aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Documentation/ABI/stable/sysfs-bus-vmbus7
-rw-r--r--Documentation/ABI/testing/debugfs-cec-error-inj40
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-chemical-vz89x2
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-proximity-as39354
-rw-r--r--Documentation/ABI/testing/sysfs-bus-thunderbolt33
-rw-r--r--Documentation/ABI/testing/sysfs-bus-usb10
-rw-r--r--Documentation/ABI/testing/sysfs-class-mei9
-rw-r--r--Documentation/ABI/testing/sysfs-class-usb_role21
-rw-r--r--Documentation/ABI/testing/sysfs-driver-fsi-master-gpio10
-rw-r--r--Documentation/ABI/testing/sysfs-kernel-irq7
-rw-r--r--Documentation/admin-guide/kernel-parameters.txt66
-rw-r--r--Documentation/admin-guide/thunderbolt.rst15
-rw-r--r--Documentation/arm64/cpu-feature-registers.txt18
-rw-r--r--Documentation/arm64/elf_hwcaps.txt16
-rw-r--r--Documentation/arm64/silicon-errata.txt1
-rw-r--r--Documentation/crypto/crypto_engine.rst48
-rw-r--r--Documentation/crypto/devel-algos.rst8
-rw-r--r--Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt23
-rw-r--r--Documentation/devicetree/bindings/ata/ahci-platform.txt1
-rw-r--r--Documentation/devicetree/bindings/ata/imx-sata.txt1
-rw-r--r--Documentation/devicetree/bindings/ata/nvidia,tegra124-ahci.txt36
-rw-r--r--Documentation/devicetree/bindings/connector/samsung,usb-connector-11pin.txt49
-rw-r--r--Documentation/devicetree/bindings/connector/usb-connector.txt75
-rw-r--r--Documentation/devicetree/bindings/crypto/arm-cryptocell.txt3
-rw-r--r--Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt6
-rw-r--r--Documentation/devicetree/bindings/fsi/fsi.txt151
-rw-r--r--Documentation/devicetree/bindings/iio/adc/axp20x_adc.txt48
-rw-r--r--Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt8
-rw-r--r--Documentation/devicetree/bindings/iio/potentiometer/ad5272.txt27
-rw-r--r--Documentation/devicetree/bindings/iio/temperature/mlx90632.txt28
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt22
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt78
-rw-r--r--Documentation/devicetree/bindings/media/coda.txt5
-rw-r--r--Documentation/devicetree/bindings/media/i2c/adv7604.txt18
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ov2685.txt41
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ov5695.txt41
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ov7670.txt16
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ov9650.txt36
-rw-r--r--Documentation/devicetree/bindings/media/i2c/tda1997x.txt178
-rw-r--r--Documentation/devicetree/bindings/media/rcar_vin.txt4
-rw-r--r--Documentation/devicetree/bindings/media/renesas,ceu.txt81
-rw-r--r--Documentation/devicetree/bindings/media/s5p-mfc.txt1
-rw-r--r--Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt14
-rw-r--r--Documentation/devicetree/bindings/media/sunxi-ir.txt3
-rw-r--r--Documentation/devicetree/bindings/mfd/aspeed-lpc.txt41
-rw-r--r--Documentation/devicetree/bindings/net/fsl-tsec-phy.txt6
-rw-r--r--Documentation/devicetree/bindings/nvmem/imx-ocotp.txt23
-rw-r--r--Documentation/devicetree/bindings/nvmem/snvs-lpgpr.txt3
-rw-r--r--Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt4
-rw-r--r--Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt31
-rw-r--r--Documentation/devicetree/bindings/phy/phy-hi3798cv200-combphy.txt59
-rw-r--r--Documentation/devicetree/bindings/phy/phy-hisi-inno-usb2.txt71
-rw-r--r--Documentation/devicetree/bindings/phy/phy-mapphone-mdm6600.txt29
-rw-r--r--Documentation/devicetree/bindings/phy/phy-mtk-tphy.txt4
-rw-r--r--Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt35
-rw-r--r--Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt73
-rw-r--r--Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt6
-rw-r--r--Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt5
-rw-r--r--Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt2
-rw-r--r--Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt2
-rw-r--r--Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt1
-rw-r--r--Documentation/devicetree/bindings/rng/imx-rng.txt (renamed from Documentation/devicetree/bindings/rng/imx-rngc.txt)11
-rw-r--r--Documentation/devicetree/bindings/rng/ks-sa-rng.txt21
-rw-r--r--Documentation/devicetree/bindings/rng/omap_rng.txt7
-rw-r--r--Documentation/devicetree/bindings/rng/st,stm32-rng.txt4
-rw-r--r--Documentation/devicetree/bindings/serial/8250.txt1
-rw-r--r--Documentation/devicetree/bindings/serial/renesas,sci-serial.txt2
-rw-r--r--Documentation/devicetree/bindings/serial/st,stm32-usart.txt2
-rw-r--r--Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-vchiq.txt16
-rw-r--r--Documentation/devicetree/bindings/usb/amlogic,dwc3.txt42
-rw-r--r--Documentation/devicetree/bindings/usb/dwc3.txt16
-rw-r--r--Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt5
-rw-r--r--Documentation/devicetree/bindings/usb/mediatek,mtu3.txt5
-rw-r--r--Documentation/devicetree/bindings/usb/usb-ehci.txt6
-rw-r--r--Documentation/devicetree/bindings/usb/usb-hcd.txt9
-rw-r--r--Documentation/devicetree/bindings/usb/usb-ohci.txt6
-rw-r--r--Documentation/devicetree/bindings/usb/usb-uhci.txt3
-rw-r--r--Documentation/devicetree/bindings/usb/usb-xhci.txt5
-rw-r--r--Documentation/driver-api/device_connection.rst43
-rw-r--r--Documentation/driver-api/firmware/fallback-mechanisms.rst2
-rw-r--r--Documentation/driver-api/firmware/request_firmware.rst14
-rw-r--r--Documentation/driver-api/uio-howto.rst5
-rw-r--r--Documentation/driver-api/usb/typec.rst73
-rw-r--r--Documentation/filesystems/cifs/README29
-rw-r--r--Documentation/filesystems/cifs/TODO25
-rw-r--r--Documentation/kbuild/kbuild.txt4
-rw-r--r--Documentation/kbuild/kconfig.txt2
-rw-r--r--Documentation/kbuild/makefiles.txt28
-rw-r--r--Documentation/media/kapi/cec-core.rst72
-rw-r--r--Documentation/media/lirc.h.rst.exceptions1
-rw-r--r--Documentation/media/uapi/cec/cec-api.rst1
-rw-r--r--Documentation/media/uapi/cec/cec-pin-error-inj.rst325
-rw-r--r--Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst19
-rw-r--r--Documentation/media/uapi/mediactl/media-ioc-enum-links.rst18
-rw-r--r--Documentation/media/uapi/mediactl/media-ioc-g-topology.rst54
-rw-r--r--Documentation/media/uapi/mediactl/media-types.rst23
-rw-r--r--Documentation/media/uapi/rc/lirc-dev-intro.rst1
-rw-r--r--Documentation/media/uapi/v4l/buffer.rst2
-rw-r--r--Documentation/media/uapi/v4l/extended-controls.rst410
-rw-r--r--Documentation/media/uapi/v4l/func-poll.rst8
-rw-r--r--Documentation/media/uapi/v4l/pixfmt-compressed.rst5
-rw-r--r--Documentation/media/uapi/v4l/pixfmt-v4l2.rst2
-rw-r--r--Documentation/media/uapi/v4l/subdev-formats.rst8
-rw-r--r--Documentation/media/uapi/v4l/vidioc-g-parm.rst7
-rw-r--r--Documentation/media/uapi/v4l/vidioc-prepare-buf.rst2
-rw-r--r--Documentation/media/v4l-drivers/imx.rst26
-rw-r--r--Documentation/networking/dpaa2/index.rst8
-rw-r--r--Documentation/networking/dpaa2/overview.rst (renamed from drivers/staging/fsl-mc/overview.rst)0
-rw-r--r--Documentation/networking/i40e.txt2
-rw-r--r--Documentation/networking/index.rst1
-rw-r--r--Documentation/networking/irda.txt10
-rw-r--r--Documentation/process/changes.rst2
-rw-r--r--Documentation/trace/ftrace.rst22
-rw-r--r--MAINTAINERS149
-rw-r--r--Makefile95
-rw-r--r--arch/Kconfig6
-rwxr-xr-xarch/arm/boot/deflate_xip_data.sh2
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi.dtsi6
-rw-r--r--arch/arm/boot/dts/ls1021a.dtsi3
-rw-r--r--arch/arm/boot/dts/stih407-b2120.dts4
-rw-r--r--arch/arm/boot/dts/stih410-b2120.dts4
-rw-r--r--arch/arm/boot/dts/stih410-b2260.dts4
-rw-r--r--arch/arm/boot/dts/stih418-b2199.dts4
-rw-r--r--arch/arm/crypto/Kconfig6
-rw-r--r--arch/arm/crypto/Makefile4
-rw-r--r--arch/arm/crypto/aes-cipher-core.S19
-rw-r--r--arch/arm/crypto/speck-neon-core.S432
-rw-r--r--arch/arm/crypto/speck-neon-glue.c288
-rw-r--r--arch/arm/include/asm/arch_gicv3.h47
-rw-r--r--arch/arm64/Kconfig51
-rw-r--r--arch/arm64/Makefile15
-rw-r--r--arch/arm64/crypto/Kconfig6
-rw-r--r--arch/arm64/crypto/Makefile8
-rw-r--r--arch/arm64/crypto/aes-ce-ccm-glue.c47
-rw-r--r--arch/arm64/crypto/aes-glue.c95
-rw-r--r--arch/arm64/crypto/aes-modes.S355
-rw-r--r--arch/arm64/crypto/aes-neonbs-glue.c48
-rw-r--r--arch/arm64/crypto/chacha20-neon-glue.c12
-rw-r--r--arch/arm64/crypto/sha256-glue.c36
-rw-r--r--arch/arm64/crypto/speck-neon-core.S352
-rw-r--r--arch/arm64/crypto/speck-neon-glue.c282
-rw-r--r--arch/arm64/include/asm/arch_gicv3.h5
-rw-r--r--arch/arm64/include/asm/assembler.h34
-rw-r--r--arch/arm64/include/asm/cache.h4
-rw-r--r--arch/arm64/include/asm/cacheflush.h3
-rw-r--r--arch/arm64/include/asm/cmpxchg.h29
-rw-r--r--arch/arm64/include/asm/cpucaps.h6
-rw-r--r--arch/arm64/include/asm/cpufeature.h262
-rw-r--r--arch/arm64/include/asm/cputype.h43
-rw-r--r--arch/arm64/include/asm/esr.h9
-rw-r--r--arch/arm64/include/asm/fpsimd.h34
-rw-r--r--arch/arm64/include/asm/lse.h3
-rw-r--r--arch/arm64/include/asm/module.h2
-rw-r--r--arch/arm64/include/asm/percpu.h29
-rw-r--r--arch/arm64/include/asm/pgtable-hwdef.h1
-rw-r--r--arch/arm64/include/asm/processor.h47
-rw-r--r--arch/arm64/include/asm/sysreg.h3
-rw-r--r--arch/arm64/include/asm/system_misc.h11
-rw-r--r--arch/arm64/include/asm/tlbflush.h25
-rw-r--r--arch/arm64/include/asm/traps.h8
-rw-r--r--arch/arm64/include/asm/virt.h6
-rw-r--r--arch/arm64/include/uapi/asm/hwcap.h4
-rw-r--r--arch/arm64/include/uapi/asm/siginfo.h21
-rw-r--r--arch/arm64/kernel/armv8_deprecated.c2
-rw-r--r--arch/arm64/kernel/cpu_errata.c316
-rw-r--r--arch/arm64/kernel/cpufeature.c438
-rw-r--r--arch/arm64/kernel/cpuinfo.c4
-rw-r--r--arch/arm64/kernel/debug-monitors.c3
-rw-r--r--arch/arm64/kernel/fpsimd.c105
-rw-r--r--arch/arm64/kernel/kaslr.c35
-rw-r--r--arch/arm64/kernel/kgdb.c21
-rw-r--r--arch/arm64/kernel/module-plts.c90
-rw-r--r--arch/arm64/kernel/module.c44
-rw-r--r--arch/arm64/kernel/process.c6
-rw-r--r--arch/arm64/kernel/ptrace.c32
-rw-r--r--arch/arm64/kernel/reloc_test_core.c4
-rw-r--r--arch/arm64/kernel/reloc_test_syms.S12
-rw-r--r--arch/arm64/kernel/signal.c9
-rw-r--r--arch/arm64/kernel/signal32.c15
-rw-r--r--arch/arm64/kernel/smp.c44
-rw-r--r--arch/arm64/kernel/sys_compat.c23
-rw-r--r--arch/arm64/kernel/traps.c76
-rw-r--r--arch/arm64/lib/Makefile3
-rw-r--r--arch/arm64/mm/cache.S21
-rw-r--r--arch/arm64/mm/fault.c236
-rw-r--r--arch/arm64/mm/proc.S22
-rw-r--r--arch/mips/Kconfig1
-rw-r--r--arch/openrisc/Kconfig4
-rw-r--r--arch/parisc/Kconfig6
-rw-r--r--arch/parisc/include/asm/io.h12
-rw-r--r--arch/parisc/include/uapi/asm/mman.h2
-rw-r--r--arch/parisc/kernel/drivers.c197
-rw-r--r--arch/parisc/kernel/hardware.c12
-rw-r--r--arch/parisc/kernel/hpmc.S6
-rw-r--r--arch/parisc/kernel/process.c6
-rw-r--r--arch/parisc/math-emu/fcnvff.c2
-rwxr-xr-xarch/powerpc/boot/wrapper2
-rw-r--r--arch/powerpc/kernel/Makefile2
-rw-r--r--arch/riscv/Kconfig13
-rw-r--r--arch/riscv/Makefile8
-rw-r--r--arch/riscv/configs/defconfig2
-rw-r--r--arch/riscv/include/asm/Kbuild1
-rw-r--r--arch/riscv/include/asm/atomic.h417
-rw-r--r--arch/riscv/include/asm/barrier.h15
-rw-r--r--arch/riscv/include/asm/cmpxchg.h391
-rw-r--r--arch/riscv/include/asm/fence.h12
-rw-r--r--arch/riscv/include/asm/ftrace.h56
-rw-r--r--arch/riscv/include/asm/module.h113
-rw-r--r--arch/riscv/include/asm/spinlock.h29
-rw-r--r--arch/riscv/include/uapi/asm/elf.h7
-rw-r--r--arch/riscv/kernel/Makefile6
-rw-r--r--arch/riscv/kernel/entry.S7
-rw-r--r--arch/riscv/kernel/ftrace.c175
-rw-r--r--arch/riscv/kernel/irq.c13
-rw-r--r--arch/riscv/kernel/mcount-dyn.S239
-rw-r--r--arch/riscv/kernel/mcount.S22
-rw-r--r--arch/riscv/kernel/module-sections.c156
-rw-r--r--arch/riscv/kernel/module.c179
-rw-r--r--arch/riscv/kernel/module.lds8
-rw-r--r--arch/riscv/kernel/stacktrace.c6
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c338
-rw-r--r--arch/sh/boards/mach-migor/setup.c225
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7722.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7724.c4
-rw-r--r--arch/x86/crypto/aesni-intel_asm.S1404
-rw-r--r--arch/x86/crypto/aesni-intel_glue.c230
-rw-r--r--arch/x86/crypto/blowfish_glue.c230
-rw-r--r--arch/x86/crypto/camellia_aesni_avx2_glue.c491
-rw-r--r--arch/x86/crypto/camellia_aesni_avx_glue.c495
-rw-r--r--arch/x86/crypto/camellia_glue.c356
-rw-r--r--arch/x86/crypto/cast5_avx_glue.c352
-rw-r--r--arch/x86/crypto/cast6_avx_glue.c489
-rw-r--r--arch/x86/crypto/des3_ede_glue.c238
-rw-r--r--arch/x86/crypto/glue_helper.c391
-rw-r--r--arch/x86/crypto/serpent_avx2_glue.c478
-rw-r--r--arch/x86/crypto/serpent_avx_glue.c518
-rw-r--r--arch/x86/crypto/serpent_sse2_glue.c519
-rw-r--r--arch/x86/crypto/sha1-mb/sha1_mb.c28
-rw-r--r--arch/x86/crypto/sha1-mb/sha1_mb_ctx.h8
-rw-r--r--arch/x86/crypto/sha256-mb/sha256_mb.c27
-rw-r--r--arch/x86/crypto/sha256-mb/sha256_mb_ctx.h8
-rw-r--r--arch/x86/crypto/sha512-mb/sha512_mb.c30
-rw-r--r--arch/x86/crypto/sha512-mb/sha512_mb_ctx.h8
-rw-r--r--arch/x86/crypto/twofish_avx_glue.c493
-rw-r--r--arch/x86/crypto/twofish_glue_3way.c339
-rw-r--r--arch/x86/entry/entry_32.S3
-rw-r--r--arch/x86/entry/entry_64.S3
-rw-r--r--arch/x86/include/asm/crypto/camellia.h16
-rw-r--r--arch/x86/include/asm/crypto/glue_helper.h75
-rw-r--r--arch/x86/include/asm/crypto/serpent-avx.h17
-rw-r--r--arch/x86/include/asm/crypto/twofish.h19
-rw-r--r--arch/x86/include/asm/hardirq.h1
-rw-r--r--arch/x86/include/asm/irq_vectors.h3
-rw-r--r--arch/x86/include/asm/mshyperv.h13
-rw-r--r--arch/x86/include/uapi/asm/hyperv.h3
-rw-r--r--arch/x86/kernel/cpu/mshyperv.c40
-rw-r--r--arch/x86/kernel/irq.c7
-rw-r--r--arch/x86/kernel/signal_compat.c2
-rw-r--r--block/genhd.c19
-rw-r--r--crypto/Kconfig129
-rw-r--r--crypto/Makefile4
-rw-r--r--crypto/ablk_helper.c150
-rw-r--r--crypto/af_alg.c8
-rw-r--r--crypto/ahash.c25
-rw-r--r--crypto/algapi.c8
-rw-r--r--crypto/api.c34
-rw-r--r--crypto/cfb.c353
-rw-r--r--crypto/crypto_engine.c301
-rw-r--r--crypto/crypto_user.c2
-rw-r--r--crypto/ecc.c23
-rw-r--r--crypto/ecdh.c23
-rw-r--r--crypto/internal.h1
-rw-r--r--crypto/lrw.c154
-rw-r--r--crypto/mcryptd.c34
-rw-r--r--crypto/md4.c17
-rw-r--r--crypto/md5.c17
-rw-r--r--crypto/rsa-pkcs1pad.c2
-rw-r--r--crypto/simd.c50
-rw-r--r--crypto/sm4_generic.c244
-rw-r--r--crypto/speck.c307
-rw-r--r--crypto/tcrypt.c3
-rw-r--r--crypto/testmgr.c45
-rw-r--r--crypto/testmgr.h1882
-rw-r--r--crypto/xts.c72
-rw-r--r--drivers/Kconfig4
-rw-r--r--drivers/acpi/arm64/iort.c12
-rw-r--r--drivers/ata/Kconfig16
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci.h1
-rw-r--r--drivers/ata/ahci_imx.c371
-rw-r--r--drivers/ata/ahci_tegra.c359
-rw-r--r--drivers/ata/libahci_platform.c24
-rw-r--r--drivers/ata/libata-core.c46
-rw-r--r--drivers/ata/libata-transport.c4
-rw-r--r--drivers/ata/libata.h2
-rw-r--r--drivers/ata/pata_arasan_cf.c6
-rw-r--r--drivers/ata/pata_bk3710.c8
-rw-r--r--drivers/ata/pata_falcon.c8
-rw-r--r--drivers/ata/pata_gayle.c219
-rw-r--r--drivers/ata/pata_it821x.c6
-rw-r--r--drivers/ata/pata_macio.c12
-rw-r--r--drivers/ata/pata_mpc52xx.c1
-rw-r--r--drivers/ata/pata_samsung_cf.c4
-rw-r--r--drivers/ata/sata_dwc_460ex.c1
-rw-r--r--drivers/base/Makefile5
-rw-r--r--drivers/base/arch_topology.c12
-rw-r--r--drivers/base/cpu.c4
-rw-r--r--drivers/base/dd.c3
-rw-r--r--drivers/base/devcon.c136
-rw-r--r--drivers/base/firmware_loader/Makefile7
-rw-r--r--drivers/base/firmware_loader/fallback.c675
-rw-r--r--drivers/base/firmware_loader/fallback.h67
-rw-r--r--drivers/base/firmware_loader/fallback_table.c55
-rw-r--r--drivers/base/firmware_loader/firmware.h115
-rw-r--r--drivers/base/firmware_loader/main.c (renamed from drivers/base/firmware_class.c)833
-rw-r--r--drivers/base/node.c4
-rw-r--r--drivers/base/platform.c4
-rw-r--r--drivers/base/soc.c2
-rw-r--r--drivers/bus/Kconfig2
-rw-r--r--drivers/bus/Makefile4
-rw-r--r--drivers/bus/fsl-mc/Kconfig16
-rw-r--r--drivers/bus/fsl-mc/Makefile18
-rw-r--r--drivers/bus/fsl-mc/dpbp.c (renamed from drivers/staging/fsl-mc/bus/dpbp.c)85
-rw-r--r--drivers/bus/fsl-mc/dpcon.c (renamed from drivers/staging/fsl-mc/bus/dpcon.c)20
-rw-r--r--drivers/bus/fsl-mc/dpmcp.c (renamed from drivers/staging/fsl-mc/bus/dpmcp.c)8
-rw-r--r--drivers/bus/fsl-mc/dprc-driver.c (renamed from drivers/staging/fsl-mc/bus/dprc-driver.c)2
-rw-r--r--drivers/bus/fsl-mc/dprc.c (renamed from drivers/staging/fsl-mc/bus/dprc.c)31
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-allocator.c (renamed from drivers/staging/fsl-mc/bus/fsl-mc-allocator.c)7
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-bus.c (renamed from drivers/staging/fsl-mc/bus/fsl-mc-bus.c)2
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-msi.c (renamed from drivers/staging/fsl-mc/bus/fsl-mc-msi.c)1
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-private.h (renamed from drivers/staging/fsl-mc/bus/fsl-mc-private.h)91
-rw-r--r--drivers/bus/fsl-mc/mc-io.c (renamed from drivers/staging/fsl-mc/bus/mc-io.c)2
-rw-r--r--drivers/bus/fsl-mc/mc-sys.c (renamed from drivers/staging/fsl-mc/bus/mc-sys.c)22
-rw-r--r--drivers/char/Kconfig2
-rw-r--r--drivers/char/hw_random/Kconfig7
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/bcm2835-rng.c2
-rw-r--r--drivers/char/hw_random/cavium-rng-vf.c2
-rw-r--r--drivers/char/hw_random/cavium-rng.c2
-rw-r--r--drivers/char/hw_random/imx-rngc.c2
-rw-r--r--drivers/char/hw_random/ks-sa-rng.c257
-rw-r--r--drivers/char/hw_random/mxc-rnga.c23
-rw-r--r--drivers/char/hw_random/omap-rng.c22
-rw-r--r--drivers/char/hw_random/stm32-rng.c44
-rw-r--r--drivers/char/mem.c6
-rw-r--r--drivers/char/random.c58
-rw-r--r--drivers/char/xillybus/xillybus_pcie.c1
-rw-r--r--drivers/crypto/Kconfig34
-rw-r--r--drivers/crypto/Makefile2
-rw-r--r--drivers/crypto/atmel-aes.c8
-rw-r--r--drivers/crypto/atmel-sha.c9
-rw-r--r--drivers/crypto/atmel-tdes.c9
-rw-r--r--drivers/crypto/bcm/cipher.c4
-rw-r--r--drivers/crypto/bcm/util.c1
-rw-r--r--drivers/crypto/bfin_crc.c743
-rw-r--r--drivers/crypto/bfin_crc.h124
-rw-r--r--drivers/crypto/caam/caamalg.c21
-rw-r--r--drivers/crypto/caam/caamalg_desc.c165
-rw-r--r--drivers/crypto/caam/caamalg_desc.h24
-rw-r--r--drivers/crypto/caam/caamalg_qi.c388
-rw-r--r--drivers/crypto/caam/ctrl.c42
-rw-r--r--drivers/crypto/caam/qi.c11
-rw-r--r--drivers/crypto/cavium/cpt/cptpf_main.c2
-rw-r--r--drivers/crypto/ccp/ccp-crypto-aes-cmac.c2
-rw-r--r--drivers/crypto/ccp/ccp-crypto-rsa.c7
-rw-r--r--drivers/crypto/ccp/ccp-crypto-sha.c2
-rw-r--r--drivers/crypto/ccp/ccp-debugfs.c7
-rw-r--r--drivers/crypto/ccp/ccp-dmaengine.c2
-rw-r--r--drivers/crypto/ccp/ccp-ops.c108
-rw-r--r--drivers/crypto/ccp/psp-dev.c15
-rw-r--r--drivers/crypto/ccp/sp-dev.c6
-rw-r--r--drivers/crypto/ccree/Makefile (renamed from drivers/staging/ccree/Makefile)0
-rw-r--r--drivers/crypto/ccree/cc_aead.c (renamed from drivers/staging/ccree/cc_aead.c)81
-rw-r--r--drivers/crypto/ccree/cc_aead.h (renamed from drivers/staging/ccree/cc_aead.h)0
-rw-r--r--drivers/crypto/ccree/cc_buffer_mgr.c (renamed from drivers/staging/ccree/cc_buffer_mgr.c)28
-rw-r--r--drivers/crypto/ccree/cc_buffer_mgr.h (renamed from drivers/staging/ccree/cc_buffer_mgr.h)15
-rw-r--r--drivers/crypto/ccree/cc_cipher.c (renamed from drivers/staging/ccree/cc_cipher.c)400
-rw-r--r--drivers/crypto/ccree/cc_cipher.h (renamed from drivers/staging/ccree/cc_cipher.h)25
-rw-r--r--drivers/crypto/ccree/cc_crypto_ctx.h (renamed from drivers/staging/ccree/cc_crypto_ctx.h)37
-rw-r--r--drivers/crypto/ccree/cc_debugfs.c (renamed from drivers/staging/ccree/cc_debugfs.c)0
-rw-r--r--drivers/crypto/ccree/cc_debugfs.h (renamed from drivers/staging/ccree/cc_debugfs.h)0
-rw-r--r--drivers/crypto/ccree/cc_driver.c (renamed from drivers/staging/ccree/cc_driver.c)96
-rw-r--r--drivers/crypto/ccree/cc_driver.h (renamed from drivers/staging/ccree/cc_driver.h)38
-rw-r--r--drivers/crypto/ccree/cc_fips.c (renamed from drivers/staging/ccree/cc_fips.c)13
-rw-r--r--drivers/crypto/ccree/cc_fips.h (renamed from drivers/staging/ccree/cc_fips.h)1
-rw-r--r--drivers/crypto/ccree/cc_hash.c (renamed from drivers/staging/ccree/cc_hash.c)205
-rw-r--r--drivers/crypto/ccree/cc_hash.h (renamed from drivers/staging/ccree/cc_hash.h)13
-rw-r--r--drivers/crypto/ccree/cc_host_regs.h (renamed from drivers/staging/ccree/cc_host_regs.h)3
-rw-r--r--drivers/crypto/ccree/cc_hw_queue_defs.h (renamed from drivers/staging/ccree/cc_hw_queue_defs.h)30
-rw-r--r--drivers/crypto/ccree/cc_ivgen.c (renamed from drivers/staging/ccree/cc_ivgen.c)7
-rw-r--r--drivers/crypto/ccree/cc_ivgen.h (renamed from drivers/staging/ccree/cc_ivgen.h)0
-rw-r--r--drivers/crypto/ccree/cc_kernel_regs.h (renamed from drivers/staging/ccree/cc_kernel_regs.h)1
-rw-r--r--drivers/crypto/ccree/cc_lli_defs.h (renamed from drivers/staging/ccree/cc_lli_defs.h)0
-rw-r--r--drivers/crypto/ccree/cc_pm.c (renamed from drivers/staging/ccree/cc_pm.c)0
-rw-r--r--drivers/crypto/ccree/cc_pm.h (renamed from drivers/staging/ccree/cc_pm.h)1
-rw-r--r--drivers/crypto/ccree/cc_request_mgr.c (renamed from drivers/staging/ccree/cc_request_mgr.c)12
-rw-r--r--drivers/crypto/ccree/cc_request_mgr.h (renamed from drivers/staging/ccree/cc_request_mgr.h)0
-rw-r--r--drivers/crypto/ccree/cc_sram_mgr.c (renamed from drivers/staging/ccree/cc_sram_mgr.c)15
-rw-r--r--drivers/crypto/ccree/cc_sram_mgr.h (renamed from drivers/staging/ccree/cc_sram_mgr.h)0
-rw-r--r--drivers/crypto/chelsio/chcr_algo.c577
-rw-r--r--drivers/crypto/chelsio/chcr_algo.h11
-rw-r--r--drivers/crypto/chelsio/chcr_core.h6
-rw-r--r--drivers/crypto/chelsio/chcr_crypto.h31
-rw-r--r--drivers/crypto/chelsio/chcr_ipsec.c5
-rw-r--r--drivers/crypto/inside-secure/safexcel.c114
-rw-r--r--drivers/crypto/inside-secure/safexcel.h22
-rw-r--r--drivers/crypto/inside-secure/safexcel_cipher.c5
-rw-r--r--drivers/crypto/inside-secure/safexcel_hash.c258
-rw-r--r--drivers/crypto/ixp4xx_crypto.c2
-rw-r--r--drivers/crypto/marvell/cesa.c1
-rw-r--r--drivers/crypto/mxs-dcp.c14
-rw-r--r--drivers/crypto/n2_core.c12
-rw-r--r--drivers/crypto/nx/nx-842-pseries.c5
-rw-r--r--drivers/crypto/omap-aes.c112
-rw-r--r--drivers/crypto/omap-aes.h3
-rw-r--r--drivers/crypto/omap-crypto.c4
-rw-r--r--drivers/crypto/omap-des.c24
-rw-r--r--drivers/crypto/omap-sham.c106
-rw-r--r--drivers/crypto/picoxcell_crypto.c2
-rw-r--r--drivers/crypto/qat/qat_common/qat_algs.c3
-rw-r--r--drivers/crypto/qat/qat_common/qat_asym_algs.c9
-rw-r--r--drivers/crypto/s5p-sss.c34
-rw-r--r--drivers/crypto/sahara.c6
-rw-r--r--drivers/crypto/stm32/stm32-cryp.c964
-rw-r--r--drivers/crypto/stm32/stm32-hash.c41
-rw-r--r--drivers/crypto/sunxi-ss/sun4i-ss-core.c1
-rw-r--r--drivers/crypto/talitos.c218
-rw-r--r--drivers/crypto/ux500/cryp/cryp_core.c14
-rw-r--r--drivers/crypto/ux500/hash/hash_core.c18
-rw-r--r--drivers/crypto/virtio/Kconfig1
-rw-r--r--drivers/crypto/virtio/virtio_crypto_algs.c16
-rw-r--r--drivers/crypto/virtio/virtio_crypto_common.h4
-rw-r--r--drivers/crypto/virtio/virtio_crypto_core.c3
-rw-r--r--drivers/extcon/Kconfig3
-rw-r--r--drivers/extcon/extcon-axp288.c176
-rw-r--r--drivers/extcon/extcon-gpio.c103
-rw-r--r--drivers/extcon/extcon-intel-cht-wc.c11
-rw-r--r--drivers/extcon/extcon-intel-int3496.c9
-rw-r--r--drivers/extcon/extcon.c44
-rw-r--r--drivers/fpga/altera-cvp.c2
-rw-r--r--drivers/fsi/Kconfig1
-rw-r--r--drivers/fsi/fsi-core.c129
-rw-r--r--drivers/fsi/fsi-master-gpio.c89
-rw-r--r--drivers/fsi/fsi-master-hub.c27
-rw-r--r--drivers/fsi/fsi-master.h17
-rw-r--r--drivers/gpu/drm/bridge/sil-sii8620.c97
-rw-r--r--drivers/hv/Kconfig2
-rw-r--r--drivers/hv/Makefile1
-rw-r--r--drivers/hv/channel_mgmt.c8
-rw-r--r--drivers/hv/hv.c64
-rw-r--r--drivers/hv/hv_balloon.c121
-rw-r--r--drivers/hv/hv_trace.c2
-rw-r--r--drivers/hv/hv_trace.h2
-rw-r--r--drivers/hv/hv_trace_balloon.h48
-rw-r--r--drivers/hv/hyperv_vmbus.h4
-rw-r--r--drivers/hwtracing/Kconfig7
-rw-r--r--drivers/hwtracing/coresight/coresight-cpu-debug.c2
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x-sysfs.c4
-rw-r--r--drivers/hwtracing/intel_th/Kconfig12
-rw-r--r--drivers/hwtracing/intel_th/Makefile3
-rw-r--r--drivers/hwtracing/intel_th/acpi.c79
-rw-r--r--drivers/hwtracing/intel_th/core.c31
-rw-r--r--drivers/hwtracing/intel_th/debug.c10
-rw-r--r--drivers/hwtracing/intel_th/debug.h10
-rw-r--r--drivers/hwtracing/intel_th/gth.c10
-rw-r--r--drivers/hwtracing/intel_th/gth.h10
-rw-r--r--drivers/hwtracing/intel_th/intel_th.h14
-rw-r--r--drivers/hwtracing/intel_th/msu.c10
-rw-r--r--drivers/hwtracing/intel_th/msu.h10
-rw-r--r--drivers/hwtracing/intel_th/pci.c10
-rw-r--r--drivers/hwtracing/intel_th/pti.c10
-rw-r--r--drivers/hwtracing/intel_th/pti.h10
-rw-r--r--drivers/hwtracing/intel_th/sth.c10
-rw-r--r--drivers/hwtracing/intel_th/sth.h10
-rw-r--r--drivers/hwtracing/stm/console.c10
-rw-r--r--drivers/hwtracing/stm/core.c10
-rw-r--r--drivers/hwtracing/stm/dummy_stm.c34
-rw-r--r--drivers/hwtracing/stm/heartbeat.c10
-rw-r--r--drivers/hwtracing/stm/policy.c10
-rw-r--r--drivers/hwtracing/stm/stm.h10
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c6
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c2
-rw-r--r--drivers/iio/accel/st_accel_i2c.c3
-rw-r--r--drivers/iio/adc/Kconfig3
-rw-r--r--drivers/iio/adc/ad7476.c26
-rw-r--r--drivers/iio/adc/axp20x_adc.c168
-rw-r--r--drivers/iio/adc/ep93xx_adc.c4
-rw-r--r--drivers/iio/adc/ti-adc161s626.c16
-rw-r--r--drivers/iio/chemical/ams-iaq-core.c17
-rw-r--r--drivers/iio/chemical/atlas-ph-sensor.c16
-rw-r--r--drivers/iio/chemical/ccs811.c10
-rw-r--r--drivers/iio/chemical/vz89x.c17
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c1
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c49
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.h2
-rw-r--r--drivers/iio/dac/ad5380.c2
-rw-r--r--drivers/iio/dac/ad5764.c2
-rw-r--r--drivers/iio/dummy/Kconfig27
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c2
-rw-r--r--drivers/iio/health/max30100.c16
-rw-r--r--drivers/iio/humidity/Kconfig2
-rw-r--r--drivers/iio/humidity/dht11.c2
-rw-r--r--drivers/iio/humidity/hdc100x.c16
-rw-r--r--drivers/iio/humidity/hts221.h21
-rw-r--r--drivers/iio/humidity/hts221_buffer.c39
-rw-r--r--drivers/iio/humidity/hts221_core.c132
-rw-r--r--drivers/iio/humidity/hts221_i2c.c64
-rw-r--r--drivers/iio/humidity/hts221_spi.c81
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h29
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c161
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c104
-rw-r--r--drivers/iio/light/Kconfig10
-rw-r--r--drivers/iio/light/Makefile1
-rw-r--r--drivers/iio/light/apds9960.c16
-rw-r--r--drivers/iio/light/cros_ec_light_prox.c1
-rw-r--r--drivers/iio/light/hid-sensor-als.c2
-rw-r--r--drivers/iio/light/lm3533-als.c2
-rw-r--r--drivers/iio/light/lv0104cs.c531
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c2
-rw-r--r--drivers/iio/potentiometer/Kconfig21
-rw-r--r--drivers/iio/potentiometer/Makefile2
-rw-r--r--drivers/iio/potentiometer/ad5272.c231
-rw-r--r--drivers/iio/potentiometer/ds1803.c2
-rw-r--r--drivers/iio/potentiometer/mcp4018.c194
-rw-r--r--drivers/iio/potentiometer/tpl0102.c16
-rw-r--r--drivers/iio/potentiostat/lmp91000.c16
-rw-r--r--drivers/iio/pressure/ms5611.h2
-rw-r--r--drivers/iio/proximity/as3935.c17
-rw-r--r--drivers/iio/proximity/pulsedlight-lidar-lite-v2.c16
-rw-r--r--drivers/iio/proximity/sx9500.c25
-rw-r--r--drivers/iio/temperature/Kconfig12
-rw-r--r--drivers/iio/temperature/Makefile1
-rw-r--r--drivers/iio/temperature/maxim_thermocouple.c16
-rw-r--r--drivers/iio/temperature/mlx90632.c752
-rw-r--r--drivers/input/evdev.c7
-rw-r--r--drivers/input/serio/gscps2.c11
-rw-r--r--drivers/input/touchscreen/sur40.c178
-rw-r--r--drivers/irqchip/Kconfig20
-rw-r--r--drivers/irqchip/Makefile3
-rw-r--r--drivers/irqchip/irq-gic-common.c9
-rw-r--r--drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c (renamed from drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c)4
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c267
-rw-r--r--drivers/irqchip/irq-gic-v3.c99
-rw-r--r--drivers/irqchip/irq-gic.c44
-rw-r--r--drivers/irqchip/irq-mscc-ocelot.c118
-rw-r--r--drivers/irqchip/irq-renesas-intc-irqpin.c40
-rw-r--r--drivers/irqchip/irq-renesas-irqc.c30
-rw-r--r--drivers/irqchip/qcom-pdc.c311
-rw-r--r--drivers/mcb/mcb-pci.c1
-rw-r--r--drivers/media/Kconfig1
-rw-r--r--drivers/media/cec/Kconfig6
-rw-r--r--drivers/media/cec/Makefile4
-rw-r--r--drivers/media/cec/cec-adap.c54
-rw-r--r--drivers/media/cec/cec-api.c14
-rw-r--r--drivers/media/cec/cec-core.c72
-rw-r--r--drivers/media/cec/cec-edid.c14
-rw-r--r--drivers/media/cec/cec-notifier.c14
-rw-r--r--drivers/media/cec/cec-pin-error-inj.c342
-rw-r--r--drivers/media/cec/cec-pin-priv.h148
-rw-r--r--drivers/media/cec/cec-pin.c678
-rw-r--r--drivers/media/cec/cec-priv.h14
-rw-r--r--drivers/media/common/siano/smscoreapi.c33
-rw-r--r--drivers/media/common/siano/smscoreapi.h2
-rw-r--r--drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c14
-rw-r--r--drivers/media/common/v4l2-tpg/v4l2-tpg-core.c18
-rw-r--r--drivers/media/common/videobuf2/videobuf2-core.c9
-rw-r--r--drivers/media/common/videobuf2/videobuf2-vmalloc.c2
-rw-r--r--drivers/media/dvb-core/dvb_ca_en50221.c4
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c4
-rw-r--r--drivers/media/dvb-core/dvbdev.c50
-rw-r--r--drivers/media/dvb-frontends/Kconfig32
-rw-r--r--drivers/media/dvb-frontends/Makefile2
-rw-r--r--drivers/media/dvb-frontends/af9013.c909
-rw-r--r--drivers/media/dvb-frontends/af9013.h48
-rw-r--r--drivers/media/dvb-frontends/af9013_priv.h1558
-rw-r--r--drivers/media/dvb-frontends/cxd2099.c (renamed from drivers/staging/media/cxd2099/cxd2099.c)209
-rw-r--r--drivers/media/dvb-frontends/cxd2099.h (renamed from drivers/staging/media/cxd2099/cxd2099.h)19
-rw-r--r--drivers/media/dvb-frontends/cxd2880/Kconfig8
-rw-r--r--drivers/media/dvb-frontends/cxd2880/Makefile18
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880.h29
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_common.c21
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_common.h19
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c129
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h23
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h29
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h74
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h385
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c72
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h27
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_io.c66
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_io.h54
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h34
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c113
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h26
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c3519
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h365
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h12
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c919
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h45
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c1217
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h65
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c1878
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h135
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c775
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h77
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c150
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h29
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_top.c1947
-rw-r--r--drivers/media/dvb-frontends/dib0090.c4
-rw-r--r--drivers/media/dvb-frontends/dib7000p.c2
-rw-r--r--drivers/media/dvb-frontends/dib8000.c2
-rw-r--r--drivers/media/dvb-frontends/dibx000_common.c2
-rw-r--r--drivers/media/dvb-frontends/dibx000_common.h2
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h139
-rw-r--r--drivers/media/dvb-frontends/lgdt3306a.c69
-rw-r--r--drivers/media/dvb-frontends/mb86a16.c8
-rw-r--r--drivers/media/dvb-frontends/mxl5xx.c34
-rw-r--r--drivers/media/dvb-frontends/rtl2832.c4
-rw-r--r--drivers/media/dvb-frontends/s5h1409.c8
-rw-r--r--drivers/media/dvb-frontends/s5h1409.h8
-rw-r--r--drivers/media/dvb-frontends/s5h1411.c8
-rw-r--r--drivers/media/dvb-frontends/s5h1411.h8
-rw-r--r--drivers/media/dvb-frontends/s5h1432.h8
-rw-r--r--drivers/media/dvb-frontends/si2168.c49
-rw-r--r--drivers/media/dvb-frontends/si2168.h4
-rw-r--r--drivers/media/dvb-frontends/si2168_priv.h1
-rw-r--r--drivers/media/dvb-frontends/sp887x.c6
-rw-r--r--drivers/media/dvb-frontends/stb0899_reg.h8
-rw-r--r--drivers/media/dvb-frontends/stv0367_priv.h1
-rw-r--r--drivers/media/dvb-frontends/stv0900_priv.h1
-rw-r--r--drivers/media/dvb-frontends/stv0900_sw.c6
-rw-r--r--drivers/media/dvb-frontends/stv0910.c19
-rw-r--r--drivers/media/dvb-frontends/ves1820.c2
-rw-r--r--drivers/media/i2c/Kconfig66
-rw-r--r--drivers/media/i2c/Makefile6
-rw-r--r--drivers/media/i2c/ad9389b.c14
-rw-r--r--drivers/media/i2c/adv748x/adv748x-core.c187
-rw-r--r--drivers/media/i2c/adv748x/adv748x-hdmi.c3
-rw-r--r--drivers/media/i2c/adv748x/adv748x.h14
-rw-r--r--drivers/media/i2c/adv7511.c14
-rw-r--r--drivers/media/i2c/adv7604.c76
-rw-r--r--drivers/media/i2c/adv7842.c15
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c28
-rw-r--r--drivers/media/i2c/ir-kbd-i2c.c20
-rw-r--r--drivers/media/i2c/max2175.c2
-rw-r--r--drivers/media/i2c/mt9t112.c1140
-rw-r--r--drivers/media/i2c/mt9v011.c29
-rw-r--r--drivers/media/i2c/ov13858.c55
-rw-r--r--drivers/media/i2c/ov2685.c846
-rw-r--r--drivers/media/i2c/ov5640.c99
-rw-r--r--drivers/media/i2c/ov5670.c42
-rw-r--r--drivers/media/i2c/ov5695.c1399
-rw-r--r--drivers/media/i2c/ov6650.c33
-rw-r--r--drivers/media/i2c/ov7670.c120
-rw-r--r--drivers/media/i2c/ov772x.c1356
-rw-r--r--drivers/media/i2c/ov7740.c31
-rw-r--r--drivers/media/i2c/ov9650.c134
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c6
-rw-r--r--drivers/media/i2c/soc_camera/Kconfig12
-rw-r--r--drivers/media/i2c/soc_camera/Makefile2
-rw-r--r--drivers/media/i2c/soc_camera/mt9t112.c2
-rw-r--r--drivers/media/i2c/sr030pc30.c7
-rw-r--r--drivers/media/i2c/tc358743.c15
-rw-r--r--drivers/media/i2c/tc358743_regs.h15
-rw-r--r--drivers/media/i2c/tda1997x.c2820
-rw-r--r--drivers/media/i2c/tda1997x_regs.h641
-rw-r--r--drivers/media/i2c/tda9840.c6
-rw-r--r--drivers/media/i2c/tvaudio.c92
-rw-r--r--drivers/media/i2c/tvp514x.c37
-rw-r--r--drivers/media/i2c/tw9910.c1027
-rw-r--r--drivers/media/i2c/vs6624.c27
-rw-r--r--drivers/media/media-device.c9
-rw-r--r--drivers/media/media-entity.c16
-rw-r--r--drivers/media/pci/bt8xx/bttv-input.c6
-rw-r--r--drivers/media/pci/cobalt/Makefile1
-rw-r--r--drivers/media/pci/cobalt/cobalt-alsa-main.c14
-rw-r--r--drivers/media/pci/cobalt/cobalt-alsa-pcm.c14
-rw-r--r--drivers/media/pci/cobalt/cobalt-alsa-pcm.h14
-rw-r--r--drivers/media/pci/cobalt/cobalt-alsa.h14
-rw-r--r--drivers/media/pci/cobalt/cobalt-cpld.c14
-rw-r--r--drivers/media/pci/cobalt/cobalt-cpld.h14
-rw-r--r--drivers/media/pci/cobalt/cobalt-driver.c14
-rw-r--r--drivers/media/pci/cobalt/cobalt-driver.h14
-rw-r--r--drivers/media/pci/cobalt/cobalt-flash.c14
-rw-r--r--drivers/media/pci/cobalt/cobalt-flash.h14
-rw-r--r--drivers/media/pci/cobalt/cobalt-i2c.c14
-rw-r--r--drivers/media/pci/cobalt/cobalt-i2c.h14
-rw-r--r--drivers/media/pci/cobalt/cobalt-irq.c14
-rw-r--r--drivers/media/pci/cobalt/cobalt-irq.h14
-rw-r--r--drivers/media/pci/cobalt/cobalt-omnitek.c14
-rw-r--r--drivers/media/pci/cobalt/cobalt-omnitek.h14
-rw-r--r--drivers/media/pci/cobalt/cobalt-v4l2.c14
-rw-r--r--drivers/media/pci/cobalt/cobalt-v4l2.h14
-rw-r--r--drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h14
-rw-r--r--drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h14
-rw-r--r--drivers/media/pci/cobalt/m00389_cvi_memmap_package.h14
-rw-r--r--drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h14
-rw-r--r--drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h14
-rw-r--r--drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h14
-rw-r--r--drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h14
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-main.c1
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-mixer.c170
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-mixer.h18
-rw-r--r--drivers/media/pci/cx18/cx18-dvb.c4
-rw-r--r--drivers/media/pci/cx23885/cx23885-alsa.c5
-rw-r--r--drivers/media/pci/cx23885/cx23885-cards.c108
-rw-r--r--drivers/media/pci/cx23885/cx23885-core.c26
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c90
-rw-r--r--drivers/media/pci/cx23885/cx23885-input.c3
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c5
-rw-r--r--drivers/media/pci/cx23885/cx23885.h4
-rw-r--r--drivers/media/pci/cx25821/cx25821-core.c7
-rw-r--r--drivers/media/pci/cx88/cx88-alsa.c8
-rw-r--r--drivers/media/pci/cx88/cx88-cards.c2
-rw-r--r--drivers/media/pci/cx88/cx88-dvb.c12
-rw-r--r--drivers/media/pci/cx88/cx88-input.c4
-rw-r--r--drivers/media/pci/ddbridge/Kconfig1
-rw-r--r--drivers/media/pci/ddbridge/Makefile3
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-ci.c53
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-core.c36
-rw-r--r--drivers/media/pci/ddbridge/ddbridge.h1
-rw-r--r--drivers/media/pci/intel/ipu3/ipu3-cio2.c16
-rw-r--r--drivers/media/pci/intel/ipu3/ipu3-cio2.h14
-rw-r--r--drivers/media/pci/ivtv/ivtv-alsa-main.c11
-rw-r--r--drivers/media/pci/ivtv/ivtv-alsa-mixer.c165
-rw-r--r--drivers/media/pci/ivtv/ivtv-alsa-mixer.h18
-rw-r--r--drivers/media/pci/ivtv/ivtvfb.c12
-rw-r--r--drivers/media/pci/mantis/mantis_vp3028.c38
-rw-r--r--drivers/media/pci/mantis/mantis_vp3028.h33
-rw-r--r--drivers/media/pci/ngene/Kconfig7
-rw-r--r--drivers/media/pci/ngene/Makefile3
-rw-r--r--drivers/media/pci/ngene/ngene-cards.c575
-rw-r--r--drivers/media/pci/ngene/ngene-core.c117
-rw-r--r--drivers/media/pci/ngene/ngene-dvb.c151
-rw-r--r--drivers/media/pci/ngene/ngene-i2c.c2
-rw-r--r--drivers/media/pci/ngene/ngene.h24
-rw-r--r--drivers/media/pci/saa7134/saa7134-alsa.c5
-rw-r--r--drivers/media/pci/saa7134/saa7134-dvb.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-input.c46
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c2
-rw-r--r--drivers/media/pci/saa7164/saa7164-dvb.c2
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-g723.c39
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-p2m.c7
-rw-r--r--drivers/media/pci/ttpci/ttpci-eeprom.c9
-rw-r--r--drivers/media/pci/zoran/zoran_driver.c4
-rw-r--r--drivers/media/platform/Kconfig11
-rw-r--r--drivers/media/platform/Makefile1
-rw-r--r--drivers/media/platform/atmel/atmel-isc.c12
-rw-r--r--drivers/media/platform/atmel/atmel-isi.c12
-rw-r--r--drivers/media/platform/cec-gpio/cec-gpio.c14
-rw-r--r--drivers/media/platform/coda/coda-bit.c46
-rw-r--r--drivers/media/platform/coda/coda-common.c44
-rw-r--r--drivers/media/platform/coda/coda.h3
-rw-r--r--drivers/media/platform/davinci/vpss.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c7
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-regs.c2
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c12
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c2
-rw-r--r--drivers/media/platform/omap/omap_vout_vrfb.c3
-rw-r--r--drivers/media/platform/qcom/venus/hfi_msgs.c4
-rw-r--r--drivers/media/platform/rcar-vin/rcar-dma.c206
-rw-r--r--drivers/media/platform/rcar-vin/rcar-vin.h10
-rw-r--r--drivers/media/platform/rcar_drif.c3
-rw-r--r--drivers/media/platform/renesas-ceu.c1677
-rw-r--r--drivers/media/platform/rockchip/rga/rga-buf.c3
-rw-r--r--drivers/media/platform/rockchip/rga/rga.c2
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c7
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc-v10.h87
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc-v8.h2
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c28
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c9
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_common.h68
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c8
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c48
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c599
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr.h14
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c397
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h15
-rw-r--r--drivers/media/platform/sh_veu.c4
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c12
-rw-r--r--drivers/media/platform/stm32/stm32-cec.c5
-rw-r--r--drivers/media/platform/stm32/stm32-dcmi.c305
-rw-r--r--drivers/media/platform/via-camera.c4
-rw-r--r--drivers/media/platform/vimc/vimc-common.c4
-rw-r--r--drivers/media/platform/vimc/vimc-debayer.c2
-rw-r--r--drivers/media/platform/vimc/vimc-scaler.c2
-rw-r--r--drivers/media/platform/vimc/vimc-sensor.c10
-rw-r--r--drivers/media/platform/vivid/vivid-cec.c33
-rw-r--r--drivers/media/platform/vivid/vivid-cec.h14
-rw-r--r--drivers/media/platform/vivid/vivid-core.c14
-rw-r--r--drivers/media/platform/vivid/vivid-core.h14
-rw-r--r--drivers/media/platform/vivid/vivid-ctrls.c16
-rw-r--r--drivers/media/platform/vivid/vivid-ctrls.h14
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-cap.c14
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-cap.h14
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-out.c14
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-out.h14
-rw-r--r--drivers/media/platform/vivid/vivid-osd.c14
-rw-r--r--drivers/media/platform/vivid/vivid-osd.h14
-rw-r--r--drivers/media/platform/vivid/vivid-radio-common.c14
-rw-r--r--drivers/media/platform/vivid/vivid-radio-common.h14
-rw-r--r--drivers/media/platform/vivid/vivid-radio-rx.c16
-rw-r--r--drivers/media/platform/vivid/vivid-radio-rx.h14
-rw-r--r--drivers/media/platform/vivid/vivid-radio-tx.c14
-rw-r--r--drivers/media/platform/vivid/vivid-radio-tx.h14
-rw-r--r--drivers/media/platform/vivid/vivid-rds-gen.c14
-rw-r--r--drivers/media/platform/vivid/vivid-rds-gen.h14
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-cap.c14
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-cap.h14
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-cap.c14
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-cap.h14
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-gen.c14
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-gen.h14
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-out.c14
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-out.h14
-rw-r--r--drivers/media/platform/vivid/vivid-vid-cap.c19
-rw-r--r--drivers/media/platform/vivid/vivid-vid-cap.h14
-rw-r--r--drivers/media/platform/vivid/vivid-vid-common.c17
-rw-r--r--drivers/media/platform/vivid/vivid-vid-common.h14
-rw-r--r--drivers/media/platform/vivid/vivid-vid-out.c14
-rw-r--r--drivers/media/platform/vivid/vivid-vid-out.h14
-rw-r--r--drivers/media/platform/vsp1/vsp1_dl.c3
-rw-r--r--drivers/media/platform/vsp1/vsp1_drm.c30
-rw-r--r--drivers/media/platform/vsp1/vsp1_lif.c12
-rw-r--r--drivers/media/platform/vsp1/vsp1_regs.h8
-rw-r--r--drivers/media/radio/radio-mr800.c2
-rw-r--r--drivers/media/radio/radio-raremono.c14
-rw-r--r--drivers/media/radio/radio-wl1273.c2
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c17
-rw-r--r--drivers/media/radio/si470x/radio-si470x-i2c.c32
-rw-r--r--drivers/media/radio/si470x/radio-si470x-usb.c2
-rw-r--r--drivers/media/radio/si470x/radio-si470x.h2
-rw-r--r--drivers/media/radio/si4713/radio-usb-si4713.c14
-rw-r--r--drivers/media/rc/Kconfig32
-rw-r--r--drivers/media/rc/Makefile2
-rw-r--r--drivers/media/rc/imon.c170
-rw-r--r--drivers/media/rc/imon_raw.c199
-rw-r--r--drivers/media/rc/ir-hix5hd2.c35
-rw-r--r--drivers/media/rc/ir-imon-decoder.c193
-rw-r--r--drivers/media/rc/ir-jvc-decoder.c14
-rw-r--r--drivers/media/rc/ir-mce_kbd-decoder.c60
-rw-r--r--drivers/media/rc/ir-nec-decoder.c20
-rw-r--r--drivers/media/rc/ir-rc5-decoder.c12
-rw-r--r--drivers/media/rc/ir-rc6-decoder.c26
-rw-r--r--drivers/media/rc/ir-sanyo-decoder.c18
-rw-r--r--drivers/media/rc/ir-sharp-decoder.c17
-rw-r--r--drivers/media/rc/ir-sony-decoder.c14
-rw-r--r--drivers/media/rc/ir-spi.c24
-rw-r--r--drivers/media/rc/ir-xmp-decoder.c29
-rw-r--r--drivers/media/rc/keymaps/Makefile1
-rw-r--r--drivers/media/rc/keymaps/rc-imon-pad.c3
-rw-r--r--drivers/media/rc/keymaps/rc-imon-rsc.c81
-rw-r--r--drivers/media/rc/lirc_dev.c20
-rw-r--r--drivers/media/rc/mceusb.c160
-rw-r--r--drivers/media/rc/meson-ir.c7
-rw-r--r--drivers/media/rc/rc-core-priv.h18
-rw-r--r--drivers/media/rc/rc-ir-raw.c60
-rw-r--r--drivers/media/rc/rc-main.c100
-rw-r--r--drivers/media/rc/sunxi-cir.c19
-rw-r--r--drivers/media/spi/Kconfig14
-rw-r--r--drivers/media/spi/Makefile5
-rw-r--r--drivers/media/spi/cxd2880-spi.c670
-rw-r--r--drivers/media/tuners/e4000.c16
-rw-r--r--drivers/media/tuners/fc2580.c16
-rw-r--r--drivers/media/tuners/msi001.c19
-rw-r--r--drivers/media/usb/au0828/Kconfig5
-rw-r--r--drivers/media/usb/au0828/au0828-video.c4
-rw-r--r--drivers/media/usb/cpia2/cpia2_usb.c3
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c87
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-dvb.c389
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx.h3
-rw-r--r--drivers/media/usb/dvb-usb-v2/Kconfig3
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.c985
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.h20
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb.h4
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c24
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.c141
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c2
-rw-r--r--drivers/media/usb/em28xx/em28xx-audio.c116
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c49
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c905
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c231
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c1015
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c173
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c172
-rw-r--r--drivers/media/usb/em28xx/em28xx-reg.h52
-rw-r--r--drivers/media/usb/em28xx/em28xx-v4l.h27
-rw-r--r--drivers/media/usb/em28xx/em28xx-vbi.c39
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c391
-rw-r--r--drivers/media/usb/em28xx/em28xx.h396
-rw-r--r--drivers/media/usb/go7007/snd-go7007.c2
-rw-r--r--drivers/media/usb/gspca/dtcs033.c6
-rw-r--r--drivers/media/usb/s2255/s2255drv.c12
-rw-r--r--drivers/media/usb/siano/smsusb.c4
-rw-r--r--drivers/media/usb/tm6000/tm6000-cards.c2
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c5
-rw-r--r--drivers/media/usb/usbtv/usbtv-core.c3
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c114
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c97
-rw-r--r--drivers/media/usb/uvc/uvc_isight.c6
-rw-r--r--drivers/media/usb/uvc/uvc_status.c4
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c141
-rw-r--r--drivers/media/usb/uvc/uvc_video.c47
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h320
-rw-r--r--drivers/media/usb/zr364xx/zr364xx.c5
-rw-r--r--drivers/media/v4l2-core/tuner-core.c15
-rw-r--r--drivers/media/v4l2-core/v4l2-common.c82
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c119
-rw-r--r--drivers/media/v4l2-core/v4l2-dv-timings.c156
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c18
-rw-r--r--drivers/media/v4l2-core/v4l2-mc.c12
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c50
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-sg.c5
-rw-r--r--drivers/misc/Kconfig1
-rw-r--r--drivers/misc/Makefile20
-rw-r--r--drivers/misc/aspeed-lpc-ctrl.c44
-rw-r--r--drivers/misc/cardreader/rts5260.c12
-rw-r--r--drivers/misc/eeprom/at24.c293
-rw-r--r--drivers/misc/eeprom/at25.c2
-rw-r--r--drivers/misc/lkdtm/Makefile20
-rw-r--r--drivers/misc/lkdtm/bugs.c (renamed from drivers/misc/lkdtm_bugs.c)0
-rw-r--r--drivers/misc/lkdtm/core.c (renamed from drivers/misc/lkdtm_core.c)0
-rw-r--r--drivers/misc/lkdtm/heap.c (renamed from drivers/misc/lkdtm_heap.c)0
-rw-r--r--drivers/misc/lkdtm/lkdtm.h (renamed from drivers/misc/lkdtm.h)0
-rw-r--r--drivers/misc/lkdtm/perms.c (renamed from drivers/misc/lkdtm_perms.c)0
-rw-r--r--drivers/misc/lkdtm/refcount.c (renamed from drivers/misc/lkdtm_refcount.c)1
-rw-r--r--drivers/misc/lkdtm/rodata.c (renamed from drivers/misc/lkdtm_rodata.c)0
-rw-r--r--drivers/misc/lkdtm/usercopy.c (renamed from drivers/misc/lkdtm_usercopy.c)0
-rw-r--r--drivers/misc/mei/bus.c83
-rw-r--r--drivers/misc/mei/client.c87
-rw-r--r--drivers/misc/mei/debugfs.c7
-rw-r--r--drivers/misc/mei/init.c1
-rw-r--r--drivers/misc/mei/main.c66
-rw-r--r--drivers/misc/mei/mei_dev.h10
-rw-r--r--drivers/misc/mic/bus/vop_bus.c6
-rw-r--r--drivers/misc/ocxl/pci.c2
-rw-r--r--drivers/net/dsa/b53/b53_mmap.c33
-rw-r--r--drivers/net/dsa/mt7530.c6
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.c11
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c11
-rw-r--r--drivers/net/ethernet/cavium/liquidio/Makefile51
-rw-r--r--drivers/net/ethernet/freescale/fsl_pq_mdio.c50
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.h2
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.c146
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.h1
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.c4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool.c4
-rw-r--r--drivers/net/ethernet/marvell/mvpp2.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c24
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c67
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net.h4
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_common.c2
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c16
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c9
-rw-r--r--drivers/net/ethernet/sfc/ef10.c2
-rw-r--r--drivers/net/ethernet/sfc/nic.h1
-rw-r--r--drivers/net/hyperv/netvsc.c60
-rw-r--r--drivers/net/netdevsim/devlink.c67
-rw-r--r--drivers/net/netdevsim/fib.c2
-rw-r--r--drivers/net/phy/marvell.c20
-rw-r--r--drivers/net/phy/marvell10g.c184
-rw-r--r--drivers/net/ppp/pptp.c1
-rw-r--r--drivers/net/usb/lan78xx.c34
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/mcu.c2
-rw-r--r--drivers/nvmem/Kconfig6
-rw-r--r--drivers/nvmem/bcm-ocotp.c15
-rw-r--r--drivers/nvmem/core.c70
-rw-r--r--drivers/nvmem/imx-iim.c18
-rw-r--r--drivers/nvmem/imx-ocotp.c18
-rw-r--r--drivers/nvmem/lpc18xx_otp.c16
-rw-r--r--drivers/nvmem/meson-efuse.c16
-rw-r--r--drivers/nvmem/meson-mx-efuse.c16
-rw-r--r--drivers/nvmem/mtk-efuse.c16
-rw-r--r--drivers/nvmem/qfprom.c16
-rw-r--r--drivers/nvmem/rockchip-efuse.c32
-rw-r--r--drivers/nvmem/snvs_lpgpr.c53
-rw-r--r--drivers/nvmem/sunxi_sid.c71
-rw-r--r--drivers/nvmem/uniphier-efuse.c16
-rw-r--r--drivers/nvmem/vf610-ocotp.c24
-rw-r--r--drivers/oprofile/oprofilefs.c3
-rw-r--r--drivers/parisc/lba_pci.c20
-rw-r--r--drivers/parisc/led.c4
-rw-r--r--drivers/parisc/power.c3
-rw-r--r--drivers/parport/parport_ax88796.c8
-rw-r--r--drivers/parport/parport_gsc.c2
-rw-r--r--drivers/parport/parport_pc.c4
-rw-r--r--drivers/parport/parport_serial.c125
-rw-r--r--drivers/perf/arm_pmu_platform.c2
-rw-r--r--drivers/perf/arm_spe_pmu.c14
-rw-r--r--drivers/phy/allwinner/phy-sun4i-usb.c22
-rw-r--r--drivers/phy/amlogic/Kconfig13
-rw-r--r--drivers/phy/amlogic/Makefile1
-rw-r--r--drivers/phy/amlogic/phy-meson-gxl-usb2.c78
-rw-r--r--drivers/phy/amlogic/phy-meson-gxl-usb3.c282
-rw-r--r--drivers/phy/hisilicon/Kconfig20
-rw-r--r--drivers/phy/hisilicon/Makefile2
-rw-r--r--drivers/phy/hisilicon/phy-hisi-inno-usb2.c197
-rw-r--r--drivers/phy/hisilicon/phy-histb-combphy.c289
-rw-r--r--drivers/phy/marvell/phy-berlin-usb.c2
-rw-r--r--drivers/phy/mediatek/phy-mtk-tphy.c23
-rw-r--r--drivers/phy/motorola/Kconfig8
-rw-r--r--drivers/phy/motorola/Makefile1
-rw-r--r--drivers/phy/motorola/phy-mapphone-mdm6600.c542
-rw-r--r--drivers/phy/phy-core.c2
-rw-r--r--drivers/phy/phy-lpc18xx-usb-otg.c8
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp.c647
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp.h280
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qusb2.c418
-rw-r--r--drivers/phy/ralink/Kconfig1
-rw-r--r--drivers/phy/renesas/phy-rcar-gen3-usb2.c4
-rw-r--r--drivers/phy/rockchip/Kconfig1
-rw-r--r--drivers/phy/rockchip/phy-rockchip-emmc.c60
-rw-r--r--drivers/phy/rockchip/phy-rockchip-typec.c160
-rw-r--r--drivers/phy/samsung/Kconfig2
-rw-r--r--drivers/phy/st/Kconfig14
-rw-r--r--drivers/phy/st/Makefile1
-rw-r--r--drivers/phy/st/phy-stm32-usbphyc.c461
-rw-r--r--drivers/phy/tegra/xusb-tegra210.c6
-rw-r--r--drivers/phy/tegra/xusb.c2
-rw-r--r--drivers/platform/x86/intel_cht_int33fe.c24
-rw-r--r--drivers/pps/clients/pps_parport.c21
-rw-r--r--drivers/pps/generators/pps_gen_parport.c12
-rw-r--r--drivers/s390/Makefile2
-rw-r--r--drivers/siox/siox-core.c2
-rw-r--r--drivers/slimbus/core.c2
-rw-r--r--drivers/staging/Kconfig18
-rw-r--r--drivers/staging/Makefile11
-rw-r--r--drivers/staging/android/ashmem.c2
-rw-r--r--drivers/staging/android/ion/Kconfig2
-rw-r--r--drivers/staging/android/ion/ion.c26
-rw-r--r--drivers/staging/android/ion/ion.h22
-rw-r--r--drivers/staging/android/ion/ion_page_pool.c33
-rw-r--r--drivers/staging/android/ion/ion_system_heap.c76
-rw-r--r--drivers/staging/ccree/Kconfig27
-rw-r--r--drivers/staging/ccree/TODO10
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c3
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c40
-rw-r--r--drivers/staging/comedi/drivers/das16.c2
-rw-r--r--drivers/staging/comedi/drivers/das16m1.c2
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c1
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio.c9
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c10
-rw-r--r--drivers/staging/comedi/drivers/ni_stc.h2
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c2
-rw-r--r--drivers/staging/comedi/drivers/s626.c10
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.c10
-rw-r--r--drivers/staging/fsl-dpaa2/Kconfig10
-rw-r--r--drivers/staging/fsl-dpaa2/Makefile1
-rw-r--r--drivers/staging/fsl-dpaa2/ethernet/README2
-rw-r--r--drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c69
-rw-r--r--drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h22
-rw-r--r--drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c26
-rw-r--r--drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h4
-rw-r--r--drivers/staging/fsl-dpaa2/ethernet/dpni.c86
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/Makefile10
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/README106
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/TODO14
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h346
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/dpsw.c1123
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/dpsw.h586
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c182
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/ethsw.c1508
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/ethsw.h67
-rw-r--r--drivers/staging/fsl-mc/TODO18
-rw-r--r--drivers/staging/fsl-mc/bus/Kconfig12
-rw-r--r--drivers/staging/fsl-mc/bus/Makefile13
-rw-r--r--drivers/staging/fsl-mc/bus/dpbp-cmd.h54
-rw-r--r--drivers/staging/fsl-mc/bus/dpcon-cmd.h53
-rw-r--r--drivers/staging/fsl-mc/bus/dpio/Makefile2
-rw-r--r--drivers/staging/fsl-mc/bus/dpio/dpio-driver.c2
-rw-r--r--drivers/staging/fsl-mc/bus/dpio/dpio-service.c6
-rw-r--r--drivers/staging/fsl-mc/bus/dpio/dpio.c14
-rw-r--r--drivers/staging/fsl-mc/bus/dpio/qbman-portal.c27
-rw-r--r--drivers/staging/fsl-mc/bus/dpio/qbman-portal.h24
-rw-r--r--drivers/staging/fsl-mc/include/dpaa2-fd.h6
-rw-r--r--drivers/staging/fsl-mc/include/dpaa2-io.h2
-rw-r--r--drivers/staging/fsl-mc/include/dpbp.h63
-rw-r--r--drivers/staging/fsl-mc/include/dpcon.h79
-rw-r--r--drivers/staging/gdm724x/gdm_endian.c24
-rw-r--r--drivers/staging/gdm724x/gdm_endian.h13
-rw-r--r--drivers/staging/gdm724x/gdm_lte.c62
-rw-r--r--drivers/staging/gdm724x/gdm_lte.h2
-rw-r--r--drivers/staging/gdm724x/gdm_mux.c6
-rw-r--r--drivers/staging/gdm724x/gdm_tty.c29
-rw-r--r--drivers/staging/gdm724x/gdm_usb.c30
-rw-r--r--drivers/staging/gdm724x/gdm_usb.h2
-rw-r--r--drivers/staging/iio/accel/adis16201.c10
-rw-r--r--drivers/staging/iio/accel/adis16209.c272
-rw-r--r--drivers/staging/iio/adc/ad7192.c6
-rw-r--r--drivers/staging/iio/adc/ad7816.c2
-rw-r--r--drivers/staging/iio/addac/adt7316.c3
-rw-r--r--drivers/staging/iio/cdc/ad7150.c5
-rw-r--r--drivers/staging/iio/cdc/ad7152.c6
-rw-r--r--drivers/staging/iio/cdc/ad7746.c12
-rw-r--r--drivers/staging/iio/light/tsl2x7x.c290
-rw-r--r--drivers/staging/iio/light/tsl2x7x.h6
-rw-r--r--drivers/staging/iio/meter/ade7753.c18
-rw-r--r--drivers/staging/iio/meter/ade7754.c6
-rw-r--r--drivers/staging/iio/meter/ade7758.h2
-rw-r--r--drivers/staging/iio/meter/ade7758_core.c52
-rw-r--r--drivers/staging/iio/meter/ade7758_trigger.c8
-rw-r--r--drivers/staging/iio/meter/ade7759.c98
-rw-r--r--drivers/staging/iio/meter/ade7854-i2c.c28
-rw-r--r--drivers/staging/iio/meter/ade7854-spi.c60
-rw-r--r--drivers/staging/iio/meter/ade7854.h28
-rw-r--r--drivers/staging/iio/meter/meter.h3
-rw-r--r--drivers/staging/iio/resolver/ad2s1210.c20
-rw-r--r--drivers/staging/irda/TODO4
-rw-r--r--drivers/staging/irda/drivers/Kconfig398
-rw-r--r--drivers/staging/irda/drivers/Makefile44
-rw-r--r--drivers/staging/irda/drivers/act200l-sir.c250
-rw-r--r--drivers/staging/irda/drivers/actisys-sir.c245
-rw-r--r--drivers/staging/irda/drivers/ali-ircc.c2217
-rw-r--r--drivers/staging/irda/drivers/ali-ircc.h227
-rw-r--r--drivers/staging/irda/drivers/au1k_ir.c985
-rw-r--r--drivers/staging/irda/drivers/bfin_sir.c819
-rw-r--r--drivers/staging/irda/drivers/bfin_sir.h93
-rw-r--r--drivers/staging/irda/drivers/donauboe.c1732
-rw-r--r--drivers/staging/irda/drivers/donauboe.h362
-rw-r--r--drivers/staging/irda/drivers/esi-sir.c157
-rw-r--r--drivers/staging/irda/drivers/girbil-sir.c252
-rw-r--r--drivers/staging/irda/drivers/irda-usb.c1906
-rw-r--r--drivers/staging/irda/drivers/irda-usb.h175
-rw-r--r--drivers/staging/irda/drivers/irtty-sir.c570
-rw-r--r--drivers/staging/irda/drivers/irtty-sir.h34
-rw-r--r--drivers/staging/irda/drivers/kingsun-sir.c634
-rw-r--r--drivers/staging/irda/drivers/ks959-sir.c912
-rw-r--r--drivers/staging/irda/drivers/ksdazzle-sir.c813
-rw-r--r--drivers/staging/irda/drivers/litelink-sir.c199
-rw-r--r--drivers/staging/irda/drivers/ma600-sir.c253
-rw-r--r--drivers/staging/irda/drivers/mcp2120-sir.c224
-rw-r--r--drivers/staging/irda/drivers/mcs7780.c990
-rw-r--r--drivers/staging/irda/drivers/mcs7780.h165
-rw-r--r--drivers/staging/irda/drivers/nsc-ircc.c2410
-rw-r--r--drivers/staging/irda/drivers/nsc-ircc.h281
-rw-r--r--drivers/staging/irda/drivers/old_belkin-sir.c146
-rw-r--r--drivers/staging/irda/drivers/pxaficp_ir.c1075
-rw-r--r--drivers/staging/irda/drivers/sa1100_ir.c1150
-rw-r--r--drivers/staging/irda/drivers/sh_sir.c810
-rw-r--r--drivers/staging/irda/drivers/sir-dev.h191
-rw-r--r--drivers/staging/irda/drivers/sir_dev.c987
-rw-r--r--drivers/staging/irda/drivers/sir_dongle.c133
-rw-r--r--drivers/staging/irda/drivers/smsc-ircc2.c3026
-rw-r--r--drivers/staging/irda/drivers/smsc-ircc2.h191
-rw-r--r--drivers/staging/irda/drivers/smsc-sio.h100
-rw-r--r--drivers/staging/irda/drivers/stir4200.c1134
-rw-r--r--drivers/staging/irda/drivers/tekram-sir.c225
-rw-r--r--drivers/staging/irda/drivers/toim3232-sir.c358
-rw-r--r--drivers/staging/irda/drivers/via-ircc.c1593
-rw-r--r--drivers/staging/irda/drivers/via-ircc.h846
-rw-r--r--drivers/staging/irda/drivers/vlsi_ir.c1872
-rw-r--r--drivers/staging/irda/drivers/vlsi_ir.h757
-rw-r--r--drivers/staging/irda/drivers/w83977af.h53
-rw-r--r--drivers/staging/irda/drivers/w83977af_ir.c1285
-rw-r--r--drivers/staging/irda/drivers/w83977af_ir.h198
-rw-r--r--drivers/staging/irda/include/net/irda/af_irda.h87
-rw-r--r--drivers/staging/irda/include/net/irda/crc.h29
-rw-r--r--drivers/staging/irda/include/net/irda/discovery.h95
-rw-r--r--drivers/staging/irda/include/net/irda/ircomm_core.h106
-rw-r--r--drivers/staging/irda/include/net/irda/ircomm_event.h83
-rw-r--r--drivers/staging/irda/include/net/irda/ircomm_lmp.h36
-rw-r--r--drivers/staging/irda/include/net/irda/ircomm_param.h147
-rw-r--r--drivers/staging/irda/include/net/irda/ircomm_ttp.h37
-rw-r--r--drivers/staging/irda/include/net/irda/ircomm_tty.h121
-rw-r--r--drivers/staging/irda/include/net/irda/ircomm_tty_attach.h92
-rw-r--r--drivers/staging/irda/include/net/irda/irda.h115
-rw-r--r--drivers/staging/irda/include/net/irda/irda_device.h285
-rw-r--r--drivers/staging/irda/include/net/irda/iriap.h108
-rw-r--r--drivers/staging/irda/include/net/irda/iriap_event.h85
-rw-r--r--drivers/staging/irda/include/net/irda/irias_object.h108
-rw-r--r--drivers/staging/irda/include/net/irda/irlan_client.h42
-rw-r--r--drivers/staging/irda/include/net/irda/irlan_common.h230
-rw-r--r--drivers/staging/irda/include/net/irda/irlan_eth.h32
-rw-r--r--drivers/staging/irda/include/net/irda/irlan_event.h81
-rw-r--r--drivers/staging/irda/include/net/irda/irlan_filter.h35
-rw-r--r--drivers/staging/irda/include/net/irda/irlan_provider.h52
-rw-r--r--drivers/staging/irda/include/net/irda/irlap.h311
-rw-r--r--drivers/staging/irda/include/net/irda/irlap_event.h129
-rw-r--r--drivers/staging/irda/include/net/irda/irlap_frame.h167
-rw-r--r--drivers/staging/irda/include/net/irda/irlmp.h295
-rw-r--r--drivers/staging/irda/include/net/irda/irlmp_event.h98
-rw-r--r--drivers/staging/irda/include/net/irda/irlmp_frame.h62
-rw-r--r--drivers/staging/irda/include/net/irda/irmod.h109
-rw-r--r--drivers/staging/irda/include/net/irda/irqueue.h96
-rw-r--r--drivers/staging/irda/include/net/irda/irttp.h210
-rw-r--r--drivers/staging/irda/include/net/irda/parameters.h100
-rw-r--r--drivers/staging/irda/include/net/irda/qos.h101
-rw-r--r--drivers/staging/irda/include/net/irda/timer.h102
-rw-r--r--drivers/staging/irda/include/net/irda/wrapper.h58
-rw-r--r--drivers/staging/irda/net/Kconfig96
-rw-r--r--drivers/staging/irda/net/Makefile17
-rw-r--r--drivers/staging/irda/net/af_irda.c2692
-rw-r--r--drivers/staging/irda/net/discovery.c417
-rw-r--r--drivers/staging/irda/net/ircomm/Kconfig12
-rw-r--r--drivers/staging/irda/net/ircomm/Makefile8
-rw-r--r--drivers/staging/irda/net/ircomm/ircomm_core.c563
-rw-r--r--drivers/staging/irda/net/ircomm/ircomm_event.c246
-rw-r--r--drivers/staging/irda/net/ircomm/ircomm_lmp.c350
-rw-r--r--drivers/staging/irda/net/ircomm/ircomm_param.c501
-rw-r--r--drivers/staging/irda/net/ircomm/ircomm_ttp.c350
-rw-r--r--drivers/staging/irda/net/ircomm/ircomm_tty.c1329
-rw-r--r--drivers/staging/irda/net/ircomm/ircomm_tty_attach.c987
-rw-r--r--drivers/staging/irda/net/ircomm/ircomm_tty_ioctl.c291
-rw-r--r--drivers/staging/irda/net/irda_device.c316
-rw-r--r--drivers/staging/irda/net/iriap.c1085
-rw-r--r--drivers/staging/irda/net/iriap_event.c496
-rw-r--r--drivers/staging/irda/net/irias_object.c555
-rw-r--r--drivers/staging/irda/net/irlan/Kconfig14
-rw-r--r--drivers/staging/irda/net/irlan/Makefile7
-rw-r--r--drivers/staging/irda/net/irlan/irlan_client.c559
-rw-r--r--drivers/staging/irda/net/irlan/irlan_client_event.c511
-rw-r--r--drivers/staging/irda/net/irlan/irlan_common.c1176
-rw-r--r--drivers/staging/irda/net/irlan/irlan_eth.c340
-rw-r--r--drivers/staging/irda/net/irlan/irlan_event.c60
-rw-r--r--drivers/staging/irda/net/irlan/irlan_filter.c240
-rw-r--r--drivers/staging/irda/net/irlan/irlan_provider.c408
-rw-r--r--drivers/staging/irda/net/irlan/irlan_provider_event.c233
-rw-r--r--drivers/staging/irda/net/irlap.c1207
-rw-r--r--drivers/staging/irda/net/irlap_event.c2316
-rw-r--r--drivers/staging/irda/net/irlap_frame.c1407
-rw-r--r--drivers/staging/irda/net/irlmp.c1996
-rw-r--r--drivers/staging/irda/net/irlmp_event.c886
-rw-r--r--drivers/staging/irda/net/irlmp_frame.c476
-rw-r--r--drivers/staging/irda/net/irmod.c199
-rw-r--r--drivers/staging/irda/net/irnet/Kconfig13
-rw-r--r--drivers/staging/irda/net/irnet/Makefile7
-rw-r--r--drivers/staging/irda/net/irnet/irnet.h522
-rw-r--r--drivers/staging/irda/net/irnet/irnet_irda.c1885
-rw-r--r--drivers/staging/irda/net/irnet/irnet_irda.h178
-rw-r--r--drivers/staging/irda/net/irnet/irnet_ppp.c1189
-rw-r--r--drivers/staging/irda/net/irnet/irnet_ppp.h116
-rw-r--r--drivers/staging/irda/net/irnetlink.c162
-rw-r--r--drivers/staging/irda/net/irproc.c96
-rw-r--r--drivers/staging/irda/net/irqueue.c912
-rw-r--r--drivers/staging/irda/net/irsysctl.c258
-rw-r--r--drivers/staging/irda/net/irttp.c1886
-rw-r--r--drivers/staging/irda/net/parameters.c584
-rw-r--r--drivers/staging/irda/net/qos.c771
-rw-r--r--drivers/staging/irda/net/timer.c231
-rw-r--r--drivers/staging/irda/net/wrapper.c492
-rw-r--r--drivers/staging/ks7010/Makefile1
-rw-r--r--drivers/staging/ks7010/eap_packet.h41
-rw-r--r--drivers/staging/ks7010/ks7010_sdio.c197
-rw-r--r--drivers/staging/ks7010/ks_hostif.c756
-rw-r--r--drivers/staging/ks7010/ks_hostif.h95
-rw-r--r--drivers/staging/ks7010/ks_wlan.h21
-rw-r--r--drivers/staging/ks7010/ks_wlan_ioctl.h1
-rw-r--r--drivers/staging/ks7010/ks_wlan_net.c117
-rw-r--r--drivers/staging/ks7010/michael_mic.c144
-rw-r--r--drivers/staging/ks7010/michael_mic.h19
-rw-r--r--drivers/staging/lustre/TODO310
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/curproc.h37
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs.h27
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h11
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h4
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_time.h2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h7
-rw-r--r--drivers/staging/lustre/include/linux/lnet/api.h1
-rw-r--r--drivers/staging/lustre/lnet/Kconfig2
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c8
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c10
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c6
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h11
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c32
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c2
-rw-r--r--drivers/staging/lustre/lnet/libcfs/Makefile4
-rw-r--r--drivers/staging/lustre/lnet/libcfs/debug.c4
-rw-r--r--drivers/staging/lustre/lnet/libcfs/fail.c2
-rw-r--r--drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c2
-rw-r--r--drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c29
-rw-r--r--drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c108
-rw-r--r--drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c51
-rw-r--r--drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c113
-rw-r--r--drivers/staging/lustre/lnet/libcfs/tracefile.c4
-rw-r--r--drivers/staging/lustre/lnet/lnet/acceptor.c6
-rw-r--r--drivers/staging/lustre/lnet/lnet/api-ni.c26
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-eq.c10
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-move.c4
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-ptl.c5
-rw-r--r--drivers/staging/lustre/lnet/lnet/net_fault.c14
-rw-r--r--drivers/staging/lustre/lnet/lnet/peer.c2
-rw-r--r--drivers/staging/lustre/lnet/lnet/router.c10
-rw-r--r--drivers/staging/lustre/lnet/selftest/conctl.c14
-rw-r--r--drivers/staging/lustre/lnet/selftest/conrpc.c4
-rw-r--r--drivers/staging/lustre/lnet/selftest/framework.c2
-rw-r--r--drivers/staging/lustre/lnet/selftest/rpc.c2
-rw-r--r--drivers/staging/lustre/lnet/selftest/selftest.h2
-rw-r--r--drivers/staging/lustre/lnet/selftest/timer.c4
-rw-r--r--drivers/staging/lustre/lustre/Kconfig1
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_request.c107
-rw-r--r--drivers/staging/lustre/lustre/fid/lproc_fid.c44
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_cache.c2
-rw-r--r--drivers/staging/lustre/lustre/include/cl_object.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lprocfs_status.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lu_object.h7
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_dlm.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_export.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_fid.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_import.h4
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_lib.h296
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_lmv.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_mdc.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_net.h22
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_sec.h3
-rw-r--r--drivers/staging/lustre/lustre/include/obd.h2
-rw-r--r--drivers/staging/lustre/lustre/include/obd_class.h8
-rw-r--r--drivers/staging/lustre/lustre/include/obd_support.h2
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_flock.c30
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lock.c14
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c24
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_pool.c104
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_request.c53
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_resource.c14
-rw-r--r--drivers/staging/lustre/lustre/llite/dcache.c16
-rw-r--r--drivers/staging/lustre/lustre/llite/dir.c10
-rw-r--r--drivers/staging/lustre/lustre/llite/file.c12
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_internal.h4
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_lib.c60
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_mmap.c8
-rw-r--r--drivers/staging/lustre/lustre/llite/namei.c60
-rw-r--r--drivers/staging/lustre/lustre/llite/statahead.c215
-rw-r--r--drivers/staging/lustre/lustre/llite/super25.c17
-rw-r--r--drivers/staging/lustre/lustre/llite/xattr.c21
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_obd.c6
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_ea.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_io.c4
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_lock.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_object.c22
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_pack.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_request.c12
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_locks.c2
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_request.c16
-rw-r--r--drivers/staging/lustre/lustre/mgc/mgc_request.c19
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_io.c23
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_lock.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_object.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/genops.c211
-rw-r--r--drivers/staging/lustre/lustre/obdclass/linkea.c16
-rw-r--r--drivers/staging/lustre/lustre/obdclass/linux/linux-module.c4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog.c22
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_obd.c5
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lprocfs_status.c4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lu_object.c89
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lustre_handles.c4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_config.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_mount.c2
-rw-r--r--drivers/staging/lustre/lustre/obdecho/echo_client.c10
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_cache.c34
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_object.c6
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_page.c8
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_request.c8
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/client.c194
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/events.c7
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/import.c85
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/layout.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/niobuf.c15
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/pack_generic.c9
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/pinger.c99
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c56
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c33
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/recover.c38
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec.c44
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c6
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_gc.c99
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_null.c8
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_plain.c8
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/service.c111
-rw-r--r--drivers/staging/media/Kconfig6
-rw-r--r--drivers/staging/media/Makefile3
-rw-r--r--drivers/staging/media/atomisp/i2c/Kconfig12
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-gc0310.c53
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-gc2235.c53
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c6
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-ov2680.c56
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-ov2722.c53
-rw-r--r--drivers/staging/media/atomisp/i2c/gc0310.h43
-rw-r--r--drivers/staging/media/atomisp/i2c/gc2235.h7
-rw-r--r--drivers/staging/media/atomisp/i2c/ov2680.h68
-rw-r--r--drivers/staging/media/atomisp/i2c/ov2722.h6
-rw-r--r--drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c56
-rw-r--r--drivers/staging/media/atomisp/i2c/ov5693/ov5693.h6
-rw-r--r--drivers/staging/media/atomisp/i2c/ov8858.c2169
-rw-r--r--drivers/staging/media/atomisp/i2c/ov8858.h1474
-rw-r--r--drivers/staging/media/atomisp/i2c/ov8858_btns.h1276
-rw-r--r--drivers/staging/media/atomisp/include/linux/vlv2_plat_clock.h30
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/Makefile10
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c11
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c2
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.c16
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c6
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c12
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.c14
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c1
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/gp_regs_defs.h22
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/sp_hrt.h24
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/gp_regs_defs.h22
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/sp_hrt.h24
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/gp_regs_defs.h22
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/sp_hrt.h24
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/css_api_version.h673
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hive_isp_css_ddr_hrt_modified.h148
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hive_isp_css_hrt_modified.h79
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/input_formatter_global.h16
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/resource_global.h35
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/xmem_global.h20
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bamem.h46
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bbb_config.h27
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/cpu_mem_support.h59
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2400_config.h24
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2500_config.h29
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2600_config.h34
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2601_config.h70
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_config.h24
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w.h844
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w_types.h54
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w.h674
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w_types.h49
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op_count.h226
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/osys_public.h20
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/pipeline_public.h18
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func.h1221
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func_types.h385
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mpmath.h329
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/osys.h47
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/stream_buffer.h47
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_func.h38
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_ops.h31
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/xmem.h46
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_shared/socket_global.h53
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_shared/stream_buffer_global.h26
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_frame_public.h29
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe.h113
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe_public.h110
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_types.h64
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/aa/aa_2/ia_css_aa2_state.h41
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_load_param.h20
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_ls_param.h42
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_store_param.h21
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bnlm/ia_css_bnlm_state.h31
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/cnr/cnr_1.0/ia_css_cnr_state.h33
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/cnr/cnr_2/ia_css_cnr_state.h33
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/dp/dp_1.0/ia_css_dp_state.h36
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/dpc2/ia_css_dpc2_state.h30
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/eed1_8/ia_css_eed1_8_state.h40
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/plane_io_ls/ia_css_plane_io_param.h22
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/plane_io_ls/ia_css_plane_io_types.h30
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/yuv420_io_ls/ia_css_yuv420_io_param.h22
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/yuv420_io_ls/ia_css_yuv420_io_types.h22
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ia_css_plane_io_param.h22
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ia_css_plane_io_types.h30
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ia_css_yuv420_io_param.h22
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ia_css_yuv420_io_types.h22
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/norm/norm_1.0/ia_css_norm_types.h21
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a/s3a_1.0/ia_css_s3a_types.h50
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a_stat_ls/ia_css_s3a_stat_ls_param.h45
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a_stat_ls/ia_css_s3a_stat_store_param.h21
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/scale/scale_1.0/ia_css_scale_param.h20
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_common_types.h31
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_param.h22
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c3
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis_param.h21
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_2/ia_css_sdis_param.h21
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_wrapper_param.h20
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_load_param.h20
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_ls_param.h39
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_store_param.h21
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/modes/interface/isp_exprs.h286
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/interface/ia_css_binary.h88
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/src/binary.c3
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/debug/src/ia_css_debug.c8
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/frame/src/frame.c2
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/isp_param/interface/ia_css_isp_param_types.h9
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/interface/ia_css_pipeline.h24
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/src/pipeline.c7
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c49
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_legacy.h11
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_metrics.h21
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo_dev.h126
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu.h72
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/mmu/isp_mmu.c2
-rw-r--r--drivers/staging/media/cxd2099/Kconfig12
-rw-r--r--drivers/staging/media/cxd2099/Makefile4
-rw-r--r--drivers/staging/media/cxd2099/TODO12
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c2
-rw-r--r--drivers/staging/media/imx/Kconfig4
-rw-r--r--drivers/staging/media/imx/imx-ic-prp.c1
-rw-r--r--drivers/staging/media/imx/imx-ic-prpencvf.c3
-rw-r--r--drivers/staging/media/imx/imx-media-capture.c3
-rw-r--r--drivers/staging/media/imx/imx-media-csi.c9
-rw-r--r--drivers/staging/media/imx/imx-media-internal-sd.c2
-rw-r--r--drivers/staging/media/imx/imx-media-utils.c118
-rw-r--r--drivers/staging/media/imx/imx-media-vdic.c3
-rw-r--r--drivers/staging/media/imx/imx-media.h2
-rw-r--r--drivers/staging/media/imx/imx6-mipi-csi2.c25
-rw-r--r--drivers/staging/media/imx074/Kconfig5
-rw-r--r--drivers/staging/media/imx074/Makefile1
-rw-r--r--drivers/staging/media/imx074/TODO5
-rw-r--r--drivers/staging/media/imx074/imx074.c (renamed from drivers/media/i2c/soc_camera/imx074.c)0
-rw-r--r--drivers/staging/media/mt9t031/Kconfig11
-rw-r--r--drivers/staging/media/mt9t031/Makefile1
-rw-r--r--drivers/staging/media/mt9t031/TODO5
-rw-r--r--drivers/staging/media/mt9t031/mt9t031.c (renamed from drivers/media/i2c/soc_camera/mt9t031.c)0
-rw-r--r--drivers/staging/most/core.c9
-rw-r--r--drivers/staging/most/core.h2
-rw-r--r--drivers/staging/mt29f_spinand/mt29f_spinand.c3
-rw-r--r--drivers/staging/mt7621-dma/Kconfig12
-rw-r--r--drivers/staging/mt7621-dma/Makefile4
-rw-r--r--drivers/staging/mt7621-dma/TODO5
-rw-r--r--drivers/staging/mt7621-dma/mtk-hsdma.c768
-rw-r--r--drivers/staging/mt7621-dma/ralink-gdma.c930
-rw-r--r--drivers/staging/mt7621-dts/Kconfig5
-rw-r--r--drivers/staging/mt7621-dts/Makefile3
-rw-r--r--drivers/staging/mt7621-dts/TODO5
-rw-r--r--drivers/staging/mt7621-dts/gbpc1.dts143
-rw-r--r--drivers/staging/mt7621-dts/mt7621.dtsi471
-rw-r--r--drivers/staging/mt7621-eth/Documentation/devicetree/bindings/net/mediatek-net-gsw.txt48
-rw-r--r--drivers/staging/mt7621-eth/Kconfig39
-rw-r--r--drivers/staging/mt7621-eth/Makefile14
-rw-r--r--drivers/staging/mt7621-eth/TODO13
-rw-r--r--drivers/staging/mt7621-eth/ethtool.c225
-rw-r--r--drivers/staging/mt7621-eth/ethtool.h22
-rw-r--r--drivers/staging/mt7621-eth/gsw_mt7620.h277
-rw-r--r--drivers/staging/mt7621-eth/gsw_mt7621.c298
-rw-r--r--drivers/staging/mt7621-eth/mdio.c271
-rw-r--r--drivers/staging/mt7621-eth/mdio.h27
-rw-r--r--drivers/staging/mt7621-eth/mdio_mt7620.c173
-rw-r--r--drivers/staging/mt7621-eth/mtk_eth_soc.c2178
-rw-r--r--drivers/staging/mt7621-eth/mtk_eth_soc.h721
-rw-r--r--drivers/staging/mt7621-eth/soc_mt7621.c160
-rw-r--r--drivers/staging/mt7621-gpio/Kconfig6
-rw-r--r--drivers/staging/mt7621-gpio/Makefile3
-rw-r--r--drivers/staging/mt7621-gpio/TODO5
-rw-r--r--drivers/staging/mt7621-gpio/gpio-mt7621.c352
-rw-r--r--drivers/staging/mt7621-mmc/Kconfig16
-rw-r--r--drivers/staging/mt7621-mmc/Makefile42
-rw-r--r--drivers/staging/mt7621-mmc/TODO8
-rw-r--r--drivers/staging/mt7621-mmc/board.h137
-rw-r--r--drivers/staging/mt7621-mmc/dbg.c347
-rw-r--r--drivers/staging/mt7621-mmc/dbg.h156
-rw-r--r--drivers/staging/mt7621-mmc/mt6575_sd.h1001
-rw-r--r--drivers/staging/mt7621-mmc/sd.c3074
-rw-r--r--drivers/staging/mt7621-pci/Makefile1
-rw-r--r--drivers/staging/mt7621-pci/TODO12
-rw-r--r--drivers/staging/mt7621-pci/pci-mt7621.c840
-rw-r--r--drivers/staging/mt7621-pinctrl/Kconfig4
-rw-r--r--drivers/staging/mt7621-pinctrl/Makefile3
-rw-r--r--drivers/staging/mt7621-pinctrl/TODO6
-rw-r--r--drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c472
-rw-r--r--drivers/staging/mt7621-spi/Kconfig6
-rw-r--r--drivers/staging/mt7621-spi/Makefile1
-rw-r--r--drivers/staging/mt7621-spi/TODO5
-rw-r--r--drivers/staging/mt7621-spi/spi-mt7621.c489
-rw-r--r--drivers/staging/netlogic/xlr_net.c3
-rw-r--r--drivers/staging/pi433/Documentation/pi433.txt28
-rw-r--r--drivers/staging/pi433/pi433_if.c87
-rw-r--r--drivers/staging/pi433/pi433_if.h12
-rw-r--r--drivers/staging/pi433/rf69.c178
-rw-r--r--drivers/staging/pi433/rf69.h28
-rw-r--r--drivers/staging/pi433/rf69_enum.h52
-rw-r--r--drivers/staging/rtl8188eu/Kconfig4
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ieee80211.c16
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ioctl_set.c14
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme.c14
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme_ext.c72
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_recv.c227
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_security.c450
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_sta_mgt.c4
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_wlan_util.c6
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_xmit.c125
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c5
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_dm.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c8
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/usb_halinit.c2
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_security.h2
-rw-r--r--drivers/staging/rtl8188eu/include/xmit_osdep.h13
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_intf.c2
-rw-r--r--drivers/staging/rtl8188eu/os_dep/xmit_linux.c37
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_wx.c51
-rw-r--r--drivers/staging/rtl8192e/rtl819x_BAProc.c2
-rw-r--r--drivers/staging/rtl8192e/rtllib_rx.c4
-rw-r--r--drivers/staging/rtl8192e/rtllib_wx.c3
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c22
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c7
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c2
-rw-r--r--drivers/staging/rtl8712/drv_types.h2
-rw-r--r--drivers/staging/rtl8712/ieee80211.c11
-rw-r--r--drivers/staging/rtl8712/ieee80211.h6
-rw-r--r--drivers/staging/rtl8712/mlme_linux.c2
-rw-r--r--drivers/staging/rtl8712/os_intfs.c3
-rw-r--r--drivers/staging/rtl8712/recv_linux.c4
-rw-r--r--drivers/staging/rtl8712/rtl8712_bitdef.h1
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmd.c8
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmd.h4
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h2
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h2
-rw-r--r--drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h1
-rw-r--r--drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h2
-rw-r--r--drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h1
-rw-r--r--drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h2
-rw-r--r--drivers/staging/rtl8712/rtl8712_gp_bitdef.h2
-rw-r--r--drivers/staging/rtl8712/rtl8712_gp_regdef.h1
-rw-r--r--drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h1
-rw-r--r--drivers/staging/rtl8712/rtl8712_led.c70
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.c3
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.c2
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_cmd.c2
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ieee80211.c4
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme.c3
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme_ext.c8
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_pwrctrl.c2
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_recv.c2
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_com.c10
-rw-r--r--drivers/staging/rtl8723bs/hal/odm.h90
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_CfoTracking.c4
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_HWConfig.c122
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_HWConfig.h4
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c3
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c2
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c205
-rw-r--r--drivers/staging/rtl8723bs/include/drv_types.h4
-rw-r--r--drivers/staging/rtl8723bs/include/ieee80211.h154
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_mlme.h2
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_recv.h10
-rw-r--r--drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c13
-rw-r--r--drivers/staging/rtl8723bs/os_dep/ioctl_linux.c99
-rw-r--r--drivers/staging/rtl8723bs/os_dep/recv_linux.c7
-rw-r--r--drivers/staging/rtl8723bs/os_dep/rtw_proc.c18
-rw-r--r--drivers/staging/rtl8723bs/os_dep/sdio_intf.c2
-rw-r--r--drivers/staging/rtl8723bs/os_dep/xmit_linux.c24
-rw-r--r--drivers/staging/rtlwifi/base.c6
-rw-r--r--drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.c8
-rw-r--r--drivers/staging/rtlwifi/phydm/phydm_features.h2
-rw-r--r--drivers/staging/rtlwifi/phydm/phydm_kfree.h2
-rw-r--r--drivers/staging/rtlwifi/phydm/phydm_rainfo.c1
-rw-r--r--drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.c2
-rw-r--r--drivers/staging/rtlwifi/rtl8822be/phy.c2
-rw-r--r--drivers/staging/rtlwifi/wifi.h29
-rw-r--r--drivers/staging/sm750fb/ddk750_chip.c4
-rw-r--r--drivers/staging/sm750fb/ddk750_chip.h14
-rw-r--r--drivers/staging/sm750fb/ddk750_display.c2
-rw-r--r--drivers/staging/sm750fb/ddk750_display.h7
-rw-r--r--drivers/staging/sm750fb/ddk750_mode.c2
-rw-r--r--drivers/staging/sm750fb/ddk750_mode.h2
-rw-r--r--drivers/staging/sm750fb/sm750_hw.c4
-rw-r--r--drivers/staging/speakup/main.c8
-rw-r--r--drivers/staging/speakup/speakup_decpc.c6
-rw-r--r--drivers/staging/speakup/speakup_dectlk.c4
-rw-r--r--drivers/staging/speakup/speakup_dtlk.c25
-rw-r--r--drivers/staging/speakup/speakup_dummy.c2
-rw-r--r--drivers/staging/speakup/speakup_keypc.c4
-rw-r--r--drivers/staging/speakup/spk_priv.h1
-rw-r--r--drivers/staging/speakup/spk_ttyio.c21
-rw-r--r--drivers/staging/speakup/spk_types.h1
-rw-r--r--drivers/staging/speakup/synth.c25
-rw-r--r--drivers/staging/typec/tcpci.c127
-rw-r--r--drivers/staging/typec/tcpci.h14
-rw-r--r--drivers/staging/unisys/visorinput/Kconfig2
-rw-r--r--drivers/staging/unisys/visorinput/Makefile1
-rw-r--r--drivers/staging/unisys/visorinput/ultrainputreport.h57
-rw-r--r--drivers/staging/unisys/visorinput/visorinput.c169
-rw-r--r--drivers/staging/vc04_services/Makefile1
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c6
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/bcm2835.c54
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/controls.c1
-rw-r--r--drivers/staging/vc04_services/interface/vchi/TODO45
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c20
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c352
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_build_info.h37
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h10
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c431
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_memdrv.h59
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_pagelist.h6
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_version.c59
-rw-r--r--drivers/staging/vme/devices/vme_user.c4
-rw-r--r--drivers/staging/vt6655/baseband.h11
-rw-r--r--drivers/staging/vt6655/card.h13
-rw-r--r--drivers/staging/vt6655/device_cfg.h11
-rw-r--r--drivers/staging/vt6655/device_main.c6
-rw-r--r--drivers/staging/vt6655/rxtx.c12
-rw-r--r--drivers/staging/vt6656/usbpipe.c3
-rw-r--r--drivers/staging/wilc1000/coreconfigurator.c32
-rw-r--r--drivers/staging/wilc1000/host_interface.c2247
-rw-r--r--drivers/staging/wilc1000/host_interface.h2
-rw-r--r--drivers/staging/wilc1000/linux_mon.c12
-rw-r--r--drivers/staging/wilc1000/linux_wlan.c22
-rw-r--r--drivers/staging/wilc1000/wilc_sdio.c145
-rw-r--r--drivers/staging/wilc1000/wilc_spi.c551
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_cfgoperations.c351
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_netdevice.h2
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.c501
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.h5
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_cfg.c21
-rw-r--r--drivers/staging/wlan-ng/prism2mgmt.c2
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c59
-rw-r--r--drivers/thunderbolt/dma_port.c28
-rw-r--r--drivers/thunderbolt/domain.c130
-rw-r--r--drivers/thunderbolt/icm.c764
-rw-r--r--drivers/thunderbolt/nhi.c5
-rw-r--r--drivers/thunderbolt/nhi.h5
-rw-r--r--drivers/thunderbolt/switch.c61
-rw-r--r--drivers/thunderbolt/tb.h14
-rw-r--r--drivers/thunderbolt/tb_msgs.h180
-rw-r--r--drivers/thunderbolt/xdomain.c47
-rw-r--r--drivers/tty/hvc/Kconfig10
-rw-r--r--drivers/tty/hvc/Makefile1
-rw-r--r--drivers/tty/hvc/hvc_riscv_sbi.c60
-rw-r--r--drivers/tty/serdev/core.c2
-rw-r--r--drivers/tty/serial/8250/8250_dw.c34
-rw-r--r--drivers/tty/serial/8250/8250_men_mcb.c125
-rw-r--r--drivers/tty/serial/8250/8250_of.c1
-rw-r--r--drivers/tty/serial/8250/8250_omap.c11
-rw-r--r--drivers/tty/serial/8250/8250_pci.c3
-rw-r--r--drivers/tty/serial/8250/8250_port.c36
-rw-r--r--drivers/tty/serial/8250/Kconfig5
-rw-r--r--drivers/tty/serial/Kconfig15
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/altera_uart.c58
-rw-r--r--drivers/tty/serial/arc_uart.c5
-rw-r--r--drivers/tty/serial/fsl_lpuart.c4
-rw-r--r--drivers/tty/serial/imx.c1209
-rw-r--r--drivers/tty/serial/max310x.c2
-rw-r--r--drivers/tty/serial/mvebu-uart.c4
-rw-r--r--drivers/tty/serial/mxs-auart.c40
-rw-r--r--drivers/tty/serial/pxa.c4
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c1158
-rw-r--r--drivers/tty/serial/samsung.c4
-rw-r--r--drivers/tty/serial/serial_core.c2
-rw-r--r--drivers/tty/serial/sh-sci.c51
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c5
-rw-r--r--drivers/tty/serial/st-asc.c4
-rw-r--r--drivers/tty/serial/stm32-usart.c134
-rw-r--r--drivers/tty/serial/stm32-usart.h3
-rw-r--r--drivers/tty/serial/xilinx_uartps.c2
-rw-r--r--drivers/tty/vt/vt.c6
-rw-r--r--drivers/uio/uio_hv_generic.c89
-rw-r--r--drivers/usb/Kconfig5
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c15
-rw-r--r--drivers/usb/chipidea/debug.c65
-rw-r--r--drivers/usb/chipidea/host.c6
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c26
-rw-r--r--drivers/usb/common/Makefile1
-rw-r--r--drivers/usb/common/roles.c305
-rw-r--r--drivers/usb/core/Makefile2
-rw-r--r--drivers/usb/core/generic.c9
-rw-r--r--drivers/usb/core/hcd.c64
-rw-r--r--drivers/usb/core/hub.c26
-rw-r--r--drivers/usb/core/hub.h1
-rw-r--r--drivers/usb/core/phy.c158
-rw-r--r--drivers/usb/core/phy.h7
-rw-r--r--drivers/usb/core/port.c10
-rw-r--r--drivers/usb/core/quirks.c186
-rw-r--r--drivers/usb/core/urb.c8
-rw-r--r--drivers/usb/core/usb-acpi.c4
-rw-r--r--drivers/usb/core/usb.c1
-rw-r--r--drivers/usb/core/usb.h1
-rw-r--r--drivers/usb/dwc2/core.c395
-rw-r--r--drivers/usb/dwc2/core.h136
-rw-r--r--drivers/usb/dwc2/core_intr.c304
-rw-r--r--drivers/usb/dwc2/debugfs.c91
-rw-r--r--drivers/usb/dwc2/gadget.c403
-rw-r--r--drivers/usb/dwc2/hcd.c445
-rw-r--r--drivers/usb/dwc2/hcd.h56
-rw-r--r--drivers/usb/dwc2/hw.h44
-rw-r--r--drivers/usb/dwc2/params.c91
-rw-r--r--drivers/usb/dwc2/pci.c27
-rw-r--r--drivers/usb/dwc2/platform.c16
-rw-r--r--drivers/usb/dwc3/Makefile2
-rw-r--r--drivers/usb/dwc3/core.c134
-rw-r--r--drivers/usb/dwc3/core.h146
-rw-r--r--drivers/usb/dwc3/debugfs.c84
-rw-r--r--drivers/usb/dwc3/drd.c489
-rw-r--r--drivers/usb/dwc3/dwc3-of-simple.c31
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c2
-rw-r--r--drivers/usb/dwc3/ep0.c2
-rw-r--r--drivers/usb/dwc3/gadget.c82
-rw-r--r--drivers/usb/gadget/composite.c126
-rw-r--r--drivers/usb/gadget/function/f_fs.c6
-rw-r--r--drivers/usb/gadget/function/f_midi.c3
-rw-r--r--drivers/usb/gadget/function/f_tcm.c2
-rw-r--r--drivers/usb/gadget/legacy/mass_storage.c2
-rw-r--r--drivers/usb/gadget/u_f.h2
-rw-r--r--drivers/usb/gadget/udc/atmel_usba_udc.c158
-rw-r--r--drivers/usb/gadget/udc/atmel_usba_udc.h4
-rw-r--r--drivers/usb/gadget/udc/bcm63xx_udc.c33
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_ep.c3
-rw-r--r--drivers/usb/gadget/udc/core.c7
-rw-r--r--drivers/usb/gadget/udc/dummy_hcd.c2
-rw-r--r--drivers/usb/gadget/udc/goku_udc.h2
-rw-r--r--drivers/usb/gadget/udc/gr_udc.c17
-rw-r--r--drivers/usb/gadget/udc/pxa25x_udc.c20
-rw-r--r--drivers/usb/gadget/udc/pxa27x_udc.c42
-rw-r--r--drivers/usb/host/Kconfig25
-rw-r--r--drivers/usb/host/Makefile2
-rw-r--r--drivers/usb/host/ehci-fsl.c2
-rw-r--r--drivers/usb/host/ehci-mem.c3
-rw-r--r--drivers/usb/host/ehci-platform.c55
-rw-r--r--drivers/usb/host/ehci-sched.c6
-rw-r--r--drivers/usb/host/ehci-tegra.c1
-rw-r--r--drivers/usb/host/fhci-dbg.c26
-rw-r--r--drivers/usb/host/imx21-dbg.c65
-rw-r--r--drivers/usb/host/isp116x-hcd.c15
-rw-r--r--drivers/usb/host/ohci-omap.c1
-rw-r--r--drivers/usb/host/ohci-platform.c56
-rw-r--r--drivers/usb/host/sl811-hcd.c17
-rw-r--r--drivers/usb/host/whci/debug.c48
-rw-r--r--drivers/usb/host/xhci-dbgtty.c5
-rw-r--r--drivers/usb/host/xhci-ext-caps.c90
-rw-r--r--drivers/usb/host/xhci-ext-caps.h7
-rw-r--r--drivers/usb/host/xhci-mem.c2
-rw-r--r--drivers/usb/host/xhci-mtk.c98
-rw-r--r--drivers/usb/host/xhci-pci.c5
-rw-r--r--drivers/usb/host/xhci-plat.c1
-rw-r--r--drivers/usb/host/xhci-ring.c27
-rw-r--r--drivers/usb/host/xhci.c139
-rw-r--r--drivers/usb/host/xhci.h4
-rw-r--r--drivers/usb/isp1760/isp1760-udc.c6
-rw-r--r--drivers/usb/misc/adutux.c4
-rw-r--r--drivers/usb/misc/chaoskey.c8
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c68
-rw-r--r--drivers/usb/misc/usbtest.c5
-rw-r--r--drivers/usb/misc/uss720.c7
-rw-r--r--drivers/usb/musb/musb_debugfs.c13
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c14
-rw-r--r--drivers/usb/phy/phy-ab8500-usb.c508
-rw-r--r--drivers/usb/phy/phy-generic.c6
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c2
-rw-r--r--drivers/usb/phy/phy-tegra-usb.c14
-rw-r--r--drivers/usb/roles/Kconfig14
-rw-r--r--drivers/usb/roles/Makefile1
-rw-r--r--drivers/usb/roles/intel-xhci-usb-role-switch.c192
-rw-r--r--drivers/usb/serial/cp210x.c1
-rw-r--r--drivers/usb/serial/ftdi_sio.c2
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h9
-rw-r--r--drivers/usb/serial/option.c457
-rw-r--r--drivers/usb/typec/Kconfig3
-rw-r--r--drivers/usb/typec/Makefile2
-rw-r--r--drivers/usb/typec/class.c (renamed from drivers/usb/typec/typec.c)168
-rw-r--r--drivers/usb/typec/fusb302/fusb302.c19
-rw-r--r--drivers/usb/typec/mux.c191
-rw-r--r--drivers/usb/typec/mux/Kconfig10
-rw-r--r--drivers/usb/typec/mux/Makefile3
-rw-r--r--drivers/usb/typec/mux/pi3usb30532.c178
-rw-r--r--drivers/usb/typec/tcpm.c96
-rw-r--r--drivers/usb/typec/tps6598x.c41
-rw-r--r--drivers/usb/typec/typec_wcove.c1
-rw-r--r--drivers/usb/typec/ucsi/ucsi.c44
-rw-r--r--drivers/usb/usb-skeleton.c2
-rw-r--r--drivers/usb/usbip/Kconfig2
-rw-r--r--drivers/usb/wusbcore/crypto.c8
-rw-r--r--drivers/usb/wusbcore/wa-nep.c1
-rw-r--r--drivers/uwb/uwb-debug.c32
-rw-r--r--drivers/video/console/dummycon.c69
-rw-r--r--drivers/video/console/newport_con.c8
-rw-r--r--drivers/video/console/vgacon.c20
-rw-r--r--drivers/video/fbdev/core/fbcon.c3
-rw-r--r--drivers/video/fbdev/stifb.c2
-rw-r--r--drivers/w1/w1.c1
-rw-r--r--fs/Makefile2
-rw-r--r--fs/aio.c21
-rw-r--r--fs/btrfs/Kconfig3
-rw-r--r--fs/btrfs/Makefile2
-rw-r--r--fs/btrfs/acl.c14
-rw-r--r--fs/btrfs/backref.c13
-rw-r--r--fs/btrfs/backref.h2
-rw-r--r--fs/btrfs/btrfs_inode.h3
-rw-r--r--fs/btrfs/check-integrity.c4
-rw-r--r--fs/btrfs/compression.c2
-rw-r--r--fs/btrfs/compression.h2
-rw-r--r--fs/btrfs/ctree.c263
-rw-r--r--fs/btrfs/ctree.h86
-rw-r--r--fs/btrfs/delayed-inode.c62
-rw-r--r--fs/btrfs/delayed-inode.h8
-rw-r--r--fs/btrfs/delayed-ref.c8
-rw-r--r--fs/btrfs/delayed-ref.h2
-rw-r--r--fs/btrfs/dev-replace.c130
-rw-r--r--fs/btrfs/dev-replace.h9
-rw-r--r--fs/btrfs/dir-item.c1
-rw-r--r--fs/btrfs/disk-io.c226
-rw-r--r--fs/btrfs/disk-io.h15
-rw-r--r--fs/btrfs/extent-tree.c317
-rw-r--r--fs/btrfs/extent_io.c82
-rw-r--r--fs/btrfs/extent_io.h19
-rw-r--r--fs/btrfs/extent_map.c6
-rw-r--r--fs/btrfs/extent_map.h2
-rw-r--r--fs/btrfs/file.c30
-rw-r--r--fs/btrfs/free-space-cache.c2
-rw-r--r--fs/btrfs/free-space-tree.c4
-rw-r--r--fs/btrfs/hash.c54
-rw-r--r--fs/btrfs/hash.h43
-rw-r--r--fs/btrfs/inode-item.c1
-rw-r--r--fs/btrfs/inode-map.c4
-rw-r--r--fs/btrfs/inode.c335
-rw-r--r--fs/btrfs/ioctl.c127
-rw-r--r--fs/btrfs/locking.c2
-rw-r--r--fs/btrfs/lzo.c2
-rw-r--r--fs/btrfs/ordered-data.c4
-rw-r--r--fs/btrfs/ordered-data.h6
-rw-r--r--fs/btrfs/print-tree.c10
-rw-r--r--fs/btrfs/props.c8
-rw-r--r--fs/btrfs/qgroup.c406
-rw-r--r--fs/btrfs/qgroup.h106
-rw-r--r--fs/btrfs/raid56.c28
-rw-r--r--fs/btrfs/reada.c10
-rw-r--r--fs/btrfs/ref-verify.c7
-rw-r--r--fs/btrfs/relocation.c34
-rw-r--r--fs/btrfs/scrub.c126
-rw-r--r--fs/btrfs/send.c35
-rw-r--r--fs/btrfs/super.c259
-rw-r--r--fs/btrfs/sysfs.c4
-rw-r--r--fs/btrfs/tests/btrfs-tests.c3
-rw-r--r--fs/btrfs/tests/extent-map-tests.c2
-rw-r--r--fs/btrfs/tests/qgroup-tests.c2
-rw-r--r--fs/btrfs/transaction.c231
-rw-r--r--fs/btrfs/transaction.h25
-rw-r--r--fs/btrfs/tree-checker.c151
-rw-r--r--fs/btrfs/tree-checker.h7
-rw-r--r--fs/btrfs/tree-defrag.c5
-rw-r--r--fs/btrfs/tree-log.c88
-rw-r--r--fs/btrfs/tree-log.h2
-rw-r--r--fs/btrfs/uuid-tree.c2
-rw-r--r--fs/btrfs/volumes.c162
-rw-r--r--fs/btrfs/volumes.h31
-rw-r--r--fs/btrfs/xattr.c12
-rw-r--r--fs/btrfs/xattr.h7
-rw-r--r--fs/char_dev.c10
-rw-r--r--fs/cifs/Kconfig8
-rw-r--r--fs/cifs/cifsencrypt.c85
-rw-r--r--fs/cifs/cifsfs.c1
-rw-r--r--fs/cifs/cifsglob.h9
-rw-r--r--fs/cifs/cifsproto.h5
-rw-r--r--fs/cifs/cifssmb.c6
-rw-r--r--fs/cifs/connect.c18
-rw-r--r--fs/cifs/inode.c38
-rw-r--r--fs/cifs/link.c27
-rw-r--r--fs/cifs/misc.c54
-rw-r--r--fs/cifs/smb1ops.c1
-rw-r--r--fs/cifs/smb2maperror.c2
-rw-r--r--fs/cifs/smb2misc.c89
-rw-r--r--fs/cifs/smb2ops.c76
-rw-r--r--fs/cifs/smb2pdu.c57
-rw-r--r--fs/cifs/smb2pdu.h3
-rw-r--r--fs/cifs/smb2proto.h5
-rw-r--r--fs/cifs/smb2transport.c97
-rw-r--r--fs/cifs/smbdirect.c23
-rw-r--r--fs/cifs/smbencrypt.c27
-rw-r--r--fs/cifs/transport.c20
-rw-r--r--fs/d_path.c470
-rw-r--r--fs/dcache.c966
-rw-r--r--fs/debugfs/inode.c5
-rw-r--r--fs/devpts/inode.c66
-rw-r--r--fs/ext4/balloc.c19
-rw-r--r--fs/ext4/dir.c8
-rw-r--r--fs/ext4/ext4.h17
-rw-r--r--fs/ext4/ext4_jbd2.c7
-rw-r--r--fs/ext4/extents.c23
-rw-r--r--fs/ext4/ialloc.c54
-rw-r--r--fs/ext4/inode.c42
-rw-r--r--fs/ext4/ioctl.c13
-rw-r--r--fs/ext4/move_extent.c4
-rw-r--r--fs/ext4/super.c65
-rw-r--r--fs/ext4/sysfs.c72
-rw-r--r--fs/ext4/xattr.c121
-rw-r--r--fs/ext4/xattr.h11
-rw-r--r--fs/gfs2/aops.c8
-rw-r--r--fs/gfs2/bmap.c38
-rw-r--r--fs/gfs2/dir.c13
-rw-r--r--fs/gfs2/file.c34
-rw-r--r--fs/gfs2/incore.h3
-rw-r--r--fs/gfs2/inode.c10
-rw-r--r--fs/gfs2/log.c2
-rw-r--r--fs/gfs2/log.h1
-rw-r--r--fs/gfs2/quota.h2
-rw-r--r--fs/gfs2/recovery.c20
-rw-r--r--fs/gfs2/trace_gfs2.h9
-rw-r--r--fs/inode.c12
-rw-r--r--fs/jbd2/journal.c30
-rw-r--r--fs/jbd2/recovery.c4
-rw-r--r--fs/namei.c41
-rw-r--r--fs/sync.c6
-rw-r--r--fs/xfs/kmem.c6
-rw-r--r--fs/xfs/kmem.h8
-rw-r--r--fs/xfs/libxfs/xfs_ag_resv.c39
-rw-r--r--fs/xfs/libxfs/xfs_ag_resv.h31
-rw-r--r--fs/xfs/libxfs/xfs_alloc.c139
-rw-r--r--fs/xfs/libxfs/xfs_alloc.h2
-rw-r--r--fs/xfs/libxfs/xfs_alloc_btree.c8
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c51
-rw-r--r--fs/xfs/libxfs/xfs_bmap.h3
-rw-r--r--fs/xfs/libxfs/xfs_bmap_btree.c4
-rw-r--r--fs/xfs/libxfs/xfs_bmap_btree.h14
-rw-r--r--fs/xfs/libxfs/xfs_btree.c125
-rw-r--r--fs/xfs/libxfs/xfs_btree.h19
-rw-r--r--fs/xfs/libxfs/xfs_dir2.h2
-rw-r--r--fs/xfs/libxfs/xfs_dir2_block.c59
-rw-r--r--fs/xfs/libxfs/xfs_dir2_data.c78
-rw-r--r--fs/xfs/libxfs/xfs_dir2_leaf.c13
-rw-r--r--fs/xfs/libxfs/xfs_dir2_node.c16
-rw-r--r--fs/xfs/libxfs/xfs_format.h13
-rw-r--r--fs/xfs/libxfs/xfs_ialloc_btree.c9
-rw-r--r--fs/xfs/libxfs/xfs_inode_buf.c124
-rw-r--r--fs/xfs/libxfs/xfs_inode_buf.h5
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.c27
-rw-r--r--fs/xfs/libxfs/xfs_refcount_btree.c5
-rw-r--r--fs/xfs/libxfs/xfs_rmap_btree.c12
-rw-r--r--fs/xfs/libxfs/xfs_sb.c1
-rw-r--r--fs/xfs/scrub/agheader.c6
-rw-r--r--fs/xfs/scrub/attr.c2
-rw-r--r--fs/xfs/scrub/bmap.c174
-rw-r--r--fs/xfs/scrub/common.c24
-rw-r--r--fs/xfs/scrub/common.h13
-rw-r--r--fs/xfs/scrub/dir.c2
-rw-r--r--fs/xfs/scrub/ialloc.c5
-rw-r--r--fs/xfs/scrub/inode.c298
-rw-r--r--fs/xfs/scrub/parent.c12
-rw-r--r--fs/xfs/scrub/quota.c2
-rw-r--r--fs/xfs/scrub/rtbitmap.c3
-rw-r--r--fs/xfs/scrub/trace.h31
-rw-r--r--fs/xfs/xfs_aops.c20
-rw-r--r--fs/xfs/xfs_bmap_util.c44
-rw-r--r--fs/xfs/xfs_buf.c2
-rw-r--r--fs/xfs/xfs_buf_item.c10
-rw-r--r--fs/xfs/xfs_dquot.c6
-rw-r--r--fs/xfs/xfs_dquot_item.c11
-rw-r--r--fs/xfs/xfs_error.c29
-rw-r--r--fs/xfs/xfs_error.h3
-rw-r--r--fs/xfs/xfs_export.c2
-rw-r--r--fs/xfs/xfs_extent_busy.c5
-rw-r--r--fs/xfs/xfs_file.c52
-rw-r--r--fs/xfs/xfs_fsops.c2
-rw-r--r--fs/xfs/xfs_icache.c23
-rw-r--r--fs/xfs/xfs_inode.c11
-rw-r--r--fs/xfs/xfs_inode.h4
-rw-r--r--fs/xfs/xfs_inode_item.c29
-rw-r--r--fs/xfs/xfs_iops.c17
-rw-r--r--fs/xfs/xfs_log.c376
-rw-r--r--fs/xfs/xfs_log.h15
-rw-r--r--fs/xfs/xfs_log_cil.c2
-rw-r--r--fs/xfs/xfs_log_recover.c100
-rw-r--r--fs/xfs/xfs_mount.c4
-rw-r--r--fs/xfs/xfs_mount.h13
-rw-r--r--fs/xfs/xfs_reflink.c25
-rw-r--r--fs/xfs/xfs_super.c71
-rw-r--r--fs/xfs/xfs_trace.h9
-rw-r--r--fs/xfs/xfs_trans.c32
-rw-r--r--fs/xfs/xfs_trans_ail.c152
-rw-r--r--fs/xfs/xfs_trans_buf.c4
-rw-r--r--fs/xfs/xfs_trans_inode.c14
-rw-r--r--fs/xfs/xfs_trans_priv.h42
-rw-r--r--include/asm-generic/vmlinux.lds.h1
-rw-r--r--include/crypto/ablk_helper.h32
-rw-r--r--include/crypto/algapi.h1
-rw-r--r--include/crypto/engine.h68
-rw-r--r--include/crypto/hash.h11
-rw-r--r--include/crypto/internal/hash.h5
-rw-r--r--include/crypto/internal/simd.h7
-rw-r--r--include/crypto/lrw.h44
-rw-r--r--include/crypto/sm4.h28
-rw-r--r--include/crypto/speck.h62
-rw-r--r--include/crypto/xts.h17
-rw-r--r--include/dt-bindings/media/tda1997x.h74
-rw-r--r--include/linux/byteorder/generic.h17
-rw-r--r--include/linux/cgroup-defs.h2
-rw-r--r--include/linux/console.h58
-rw-r--r--include/linux/crc32c.h1
-rw-r--r--include/linux/crypto.h8
-rw-r--r--include/linux/dcache.h6
-rw-r--r--include/linux/device.h23
-rw-r--r--include/linux/extcon.h6
-rw-r--r--include/linux/extcon/extcon-gpio.h47
-rw-r--r--include/linux/firmware.h3
-rw-r--r--include/linux/fsl/mc.h (renamed from drivers/staging/fsl-mc/include/mc.h)118
-rw-r--r--include/linux/hrtimer.h2
-rw-r--r--include/linux/hyperv.h2
-rw-r--r--include/linux/ipc.h2
-rw-r--r--include/linux/irq.h23
-rw-r--r--include/linux/irqchip/arm-gic-v3.h4
-rw-r--r--include/linux/kconfig.h3
-rw-r--r--include/linux/kernel.h9
-rw-r--r--include/linux/libata.h1
-rw-r--r--include/linux/lsm_hooks.h32
-rw-r--r--include/linux/mfd/axp20x.h2
-rw-r--r--include/linux/mfd/syscon/imx6q-iomuxc-gpr.h2
-rw-r--r--include/linux/msg.h18
-rw-r--r--include/linux/nvmem-provider.h42
-rw-r--r--include/linux/pci_ids.h5
-rw-r--r--include/linux/phy/phy.h31
-rw-r--r--include/linux/random.h4
-rw-r--r--include/linux/security.h67
-rw-r--r--include/linux/sem.h40
-rw-r--r--include/linux/serial_core.h2
-rw-r--r--include/linux/shm.h22
-rw-r--r--include/linux/sizes.h4
-rw-r--r--include/linux/stm.h10
-rw-r--r--include/linux/thunderbolt.h19
-rw-r--r--include/linux/time32.h1
-rw-r--r--include/linux/timekeeper_internal.h4
-rw-r--r--include/linux/timekeeping.h37
-rw-r--r--include/linux/usb/composite.h3
-rw-r--r--include/linux/usb/gadget.h1
-rw-r--r--include/linux/usb/hcd.h8
-rw-r--r--include/linux/usb/pd.h185
-rw-r--r--include/linux/usb/pd_ado.h42
-rw-r--r--include/linux/usb/pd_ext_sdb.h31
-rw-r--r--include/linux/usb/role.h53
-rw-r--r--include/linux/usb/tcpm.h15
-rw-r--r--include/linux/usb/typec.h28
-rw-r--r--include/linux/usb/typec_mux.h55
-rw-r--r--include/linux/wait.h114
-rw-r--r--include/linux/workqueue.h23
-rw-r--r--include/media/cec-notifier.h14
-rw-r--r--include/media/cec-pin.h14
-rw-r--r--include/media/cec.h26
-rw-r--r--include/media/drv-intf/renesas-ceu.h26
-rw-r--r--include/media/dvbdev.h65
-rw-r--r--include/media/i2c/ad9389b.h14
-rw-r--r--include/media/i2c/adv7511.h14
-rw-r--r--include/media/i2c/adv7604.h15
-rw-r--r--include/media/i2c/adv7842.h15
-rw-r--r--include/media/i2c/mt9t112.h17
-rw-r--r--include/media/i2c/ov772x.h6
-rw-r--r--include/media/i2c/tc358743.h18
-rw-r--r--include/media/i2c/tda1997x.h42
-rw-r--r--include/media/i2c/ths7303.h10
-rw-r--r--include/media/i2c/tw9910.h9
-rw-r--r--include/media/i2c/uda1342.h15
-rw-r--r--include/media/rc-core.h11
-rw-r--r--include/media/rc-map.h9
-rw-r--r--include/media/tpg/v4l2-tpg.h14
-rw-r--r--include/media/v4l2-common.h60
-rw-r--r--include/media/v4l2-ctrls.h4
-rw-r--r--include/media/v4l2-dev.h6
-rw-r--r--include/media/v4l2-dv-timings.h36
-rw-r--r--include/media/v4l2-fh.h1
-rw-r--r--include/media/v4l2-rect.h14
-rw-r--r--include/media/v4l2-subdev.h121
-rw-r--r--include/media/videobuf2-core.h33
-rw-r--r--include/net/bluetooth/hci_core.h2
-rw-r--r--include/net/devlink.h40
-rw-r--r--include/net/inet_timewait_sock.h1
-rw-r--r--include/net/ip6_route.h3
-rw-r--r--include/net/ipv6.h3
-rw-r--r--include/net/nexthop.h2
-rw-r--r--include/trace/events/btrfs.h108
-rw-r--r--include/trace/events/ext4.h43
-rw-r--r--include/uapi/asm-generic/siginfo.h3
-rw-r--r--include/uapi/linux/cec-funcs.h29
-rw-r--r--include/uapi/linux/cec.h29
-rw-r--r--include/uapi/linux/irda.h252
-rw-r--r--include/uapi/linux/ixjuser.h721
-rw-r--r--include/uapi/linux/lirc.h2
-rw-r--r--include/uapi/linux/media.h344
-rw-r--r--include/uapi/linux/serial_core.h3
-rw-r--r--include/uapi/linux/stm.h13
-rw-r--r--include/uapi/linux/telephony.h263
-rw-r--r--include/uapi/linux/time.h13
-rw-r--r--include/uapi/linux/v4l2-controls.h93
-rw-r--r--include/uapi/linux/v4l2-mediabus.h4
-rw-r--r--include/uapi/linux/videodev2.h1
-rw-r--r--ipc/msg.c62
-rw-r--r--ipc/sem.c81
-rw-r--r--ipc/shm.c68
-rw-r--r--ipc/util.c9
-rw-r--r--ipc/util.h12
-rw-r--r--kernel/cgroup/cgroup.c21
-rw-r--r--kernel/irq/Kconfig6
-rw-r--r--kernel/irq/autoprobe.c2
-rw-r--r--kernel/irq/chip.c10
-rw-r--r--kernel/irq/cpuhotplug.c1
-rw-r--r--kernel/irq/debugfs.c8
-rw-r--r--kernel/irq/devres.c1
-rw-r--r--kernel/irq/dummychip.c1
-rw-r--r--kernel/irq/generic-chip.c1
-rw-r--r--kernel/irq/handle.c23
-rw-r--r--kernel/irq/ipi.c3
-rw-r--r--kernel/irq/irq_sim.c14
-rw-r--r--kernel/irq/irqdesc.c23
-rw-r--r--kernel/irq/irqdomain.c2
-rw-r--r--kernel/irq/manage.c21
-rw-r--r--kernel/irq/matrix.c8
-rw-r--r--kernel/irq/msi.c3
-rw-r--r--kernel/irq/pm.c3
-rw-r--r--kernel/irq/proc.c2
-rw-r--r--kernel/irq/resend.c2
-rw-r--r--kernel/irq/spurious.c2
-rw-r--r--kernel/irq/timings.c13
-rw-r--r--kernel/pid_namespace.c67
-rw-r--r--kernel/signal.c4
-rw-r--r--kernel/softirq.c82
-rw-r--r--kernel/sysctl.c11
-rw-r--r--kernel/time/alarmtimer.c34
-rw-r--r--kernel/time/clocksource.c66
-rw-r--r--kernel/time/hrtimer.c16
-rw-r--r--kernel/time/posix-stubs.c2
-rw-r--r--kernel/time/posix-timers.c26
-rw-r--r--kernel/time/tick-common.c15
-rw-r--r--kernel/time/tick-internal.h6
-rw-r--r--kernel/time/tick-sched.c9
-rw-r--r--kernel/time/time.c12
-rw-r--r--kernel/time/timekeeping.c219
-rw-r--r--kernel/time/timekeeping.h1
-rw-r--r--kernel/trace/trace.c2
-rw-r--r--kernel/workqueue.c60
-rw-r--r--lib/Kconfig.debug4
-rw-r--r--lib/devres.c78
-rw-r--r--lib/int_sqrt.c30
-rw-r--r--lib/kobject.c39
-rw-r--r--lib/libcrc32c.c6
-rw-r--r--lib/zstd/Makefile17
-rw-r--r--net/bluetooth/hci_conn.c29
-rw-r--r--net/bluetooth/hci_event.c15
-rw-r--r--net/bluetooth/l2cap_core.c2
-rw-r--r--net/core/dev.c2
-rw-r--r--net/core/dev_addr_lists.c4
-rw-r--r--net/core/devlink.c74
-rw-r--r--net/core/skbuff.c1
-rw-r--r--net/dccp/ipv4.c1
-rw-r--r--net/dccp/ipv6.c1
-rw-r--r--net/dsa/dsa_priv.h8
-rw-r--r--net/ieee802154/6lowpan/reassembly.c2
-rw-r--r--net/ipv4/arp.c2
-rw-r--r--net/ipv4/inet_timewait_sock.c1
-rw-r--r--net/ipv4/ip_fragment.c5
-rw-r--r--net/ipv4/ip_output.c3
-rw-r--r--net/ipv4/ip_tunnel.c11
-rw-r--r--net/ipv4/route.c11
-rw-r--r--net/ipv6/datagram.c9
-rw-r--r--net/ipv6/ip6_gre.c8
-rw-r--r--net/ipv6/ip6_output.c25
-rw-r--r--net/ipv6/ip6_tunnel.c11
-rw-r--r--net/ipv6/ip6_vti.c7
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c2
-rw-r--r--net/ipv6/ping.c2
-rw-r--r--net/ipv6/reassembly.c2
-rw-r--r--net/ipv6/route.c17
-rw-r--r--net/ipv6/sit.c8
-rw-r--r--net/ipv6/udp.c31
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--net/rxrpc/input.c6
-rw-r--r--net/rxrpc/protocol.h6
-rw-r--r--net/sched/act_bpf.c12
-rw-r--r--net/sched/cls_u32.c1
-rw-r--r--net/sctp/ipv6.c4
-rw-r--r--net/sctp/socket.c13
-rw-r--r--net/tipc/diag.c2
-rw-r--r--net/tipc/socket.c7
-rw-r--r--net/tipc/socket.h4
-rw-r--r--net/tipc/subscr.c2
-rw-r--r--net/unix/af_unix.c10
-rw-r--r--scripts/Kbuild.include6
-rw-r--r--scripts/Makefile.build97
-rw-r--r--scripts/Makefile.lib47
-rwxr-xr-xscripts/adjust_autoksyms.sh9
-rw-r--r--scripts/basic/fixdep.c8
-rwxr-xr-xscripts/checkpatch.pl21
-rwxr-xr-xscripts/clang-version.sh33
-rwxr-xr-xscripts/file-size.sh4
-rwxr-xr-xscripts/gen_initramfs_list.sh2
-rwxr-xr-xscripts/headers_install.sh10
-rw-r--r--scripts/kallsyms.c1
-rw-r--r--scripts/kconfig/Makefile31
-rw-r--r--scripts/kconfig/conf.c41
-rw-r--r--scripts/kconfig/expr.c86
-rw-r--r--scripts/kconfig/expr.h4
-rw-r--r--scripts/kconfig/lkc.h1
-rw-r--r--scripts/kconfig/menu.c12
-rw-r--r--scripts/kconfig/nconf.h4
-rw-r--r--scripts/kconfig/symbol.c40
-rw-r--r--scripts/kconfig/tests/auto_submenu/Kconfig50
-rw-r--r--scripts/kconfig/tests/auto_submenu/__init__.py12
-rw-r--r--scripts/kconfig/tests/auto_submenu/expected_stdout10
-rw-r--r--scripts/kconfig/tests/choice/Kconfig54
-rw-r--r--scripts/kconfig/tests/choice/__init__.py40
-rw-r--r--scripts/kconfig/tests/choice/alldef_expected_config5
-rw-r--r--scripts/kconfig/tests/choice/allmod_expected_config9
-rw-r--r--scripts/kconfig/tests/choice/allno_expected_config5
-rw-r--r--scripts/kconfig/tests/choice/allyes_expected_config9
-rw-r--r--scripts/kconfig/tests/choice/oldask0_expected_stdout10
-rw-r--r--scripts/kconfig/tests/choice/oldask1_config2
-rw-r--r--scripts/kconfig/tests/choice/oldask1_expected_stdout15
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/Kconfig19
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/__init__.py15
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/config2
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/expected_config3
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/expected_stdout4
-rw-r--r--scripts/kconfig/tests/conftest.py291
-rw-r--r--scripts/kconfig/tests/err_recursive_inc/Kconfig1
-rw-r--r--scripts/kconfig/tests/err_recursive_inc/Kconfig.inc14
-rw-r--r--scripts/kconfig/tests/err_recursive_inc/Kconfig.inc23
-rw-r--r--scripts/kconfig/tests/err_recursive_inc/Kconfig.inc31
-rw-r--r--scripts/kconfig/tests/err_recursive_inc/__init__.py10
-rw-r--r--scripts/kconfig/tests/err_recursive_inc/expected_stderr6
-rw-r--r--scripts/kconfig/tests/inter_choice/Kconfig23
-rw-r--r--scripts/kconfig/tests/inter_choice/__init__.py14
-rw-r--r--scripts/kconfig/tests/inter_choice/defconfig1
-rw-r--r--scripts/kconfig/tests/inter_choice/expected_config4
-rw-r--r--scripts/kconfig/tests/new_choice_with_dep/Kconfig37
-rw-r--r--scripts/kconfig/tests/new_choice_with_dep/__init__.py14
-rw-r--r--scripts/kconfig/tests/new_choice_with_dep/config3
-rw-r--r--scripts/kconfig/tests/new_choice_with_dep/expected_stdout10
-rw-r--r--scripts/kconfig/tests/no_write_if_dep_unmet/Kconfig14
-rw-r--r--scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py19
-rw-r--r--scripts/kconfig/tests/no_write_if_dep_unmet/config1
-rw-r--r--scripts/kconfig/tests/no_write_if_dep_unmet/expected_config5
-rw-r--r--scripts/kconfig/tests/pytest.ini7
-rw-r--r--scripts/kconfig/tests/rand_nested_choice/Kconfig33
-rw-r--r--scripts/kconfig/tests/rand_nested_choice/__init__.py16
-rw-r--r--scripts/kconfig/tests/rand_nested_choice/expected_stdout02
-rw-r--r--scripts/kconfig/tests/rand_nested_choice/expected_stdout14
-rw-r--r--scripts/kconfig/tests/rand_nested_choice/expected_stdout25
-rw-r--r--scripts/kconfig/tests/warn_recursive_dep/Kconfig62
-rw-r--r--scripts/kconfig/tests/warn_recursive_dep/__init__.py9
-rw-r--r--scripts/kconfig/tests/warn_recursive_dep/expected_stderr30
-rw-r--r--scripts/kconfig/zconf.l41
-rwxr-xr-xscripts/link-vmlinux.sh103
-rwxr-xr-xscripts/namespace.pl2
-rwxr-xr-xscripts/recordmcount.pl5
-rw-r--r--security/security.c32
-rw-r--r--security/selinux/hooks.c92
-rw-r--r--security/smack/smack_lsm.c197
-rw-r--r--tools/hv/hv_fcopy_daemon.c4
-rw-r--r--tools/hv/hv_kvp_daemon.c138
-rw-r--r--tools/hv/hv_vss_daemon.c1
-rw-r--r--tools/testing/selftests/Makefile1
-rw-r--r--tools/testing/selftests/filesystems/.gitignore1
-rw-r--r--tools/testing/selftests/filesystems/Makefile2
-rw-r--r--tools/testing/selftests/filesystems/devpts_pts.c313
-rw-r--r--tools/testing/selftests/firmware/Makefile2
-rw-r--r--tools/testing/selftests/firmware/config4
-rwxr-xr-xtools/testing/selftests/firmware/fw_fallback.sh65
-rwxr-xr-xtools/testing/selftests/firmware/fw_filesystem.sh72
-rwxr-xr-xtools/testing/selftests/firmware/fw_lib.sh194
-rwxr-xr-xtools/testing/selftests/firmware/fw_run_tests.sh70
-rw-r--r--tools/usb/usbip/libsrc/usbip_common.c23
-rw-r--r--tools/usb/usbip/libsrc/usbip_common.h11
-rw-r--r--tools/usb/usbip/libsrc/usbip_host_common.c5
-rw-r--r--tools/usb/usbip/src/usbip_attach.c10
-rw-r--r--tools/usb/usbip/src/usbip_list.c6
-rw-r--r--tools/usb/usbip/src/usbip_network.c10
-rw-r--r--tools/usb/usbip/src/usbip_network.h6
-rw-r--r--tools/usb/usbip/src/usbipd.c34
-rw-r--r--usr/initramfs_data.S2
2347 files changed, 105953 insertions, 122247 deletions
diff --git a/.gitignore b/.gitignore
index 1be78fd8163b..85bcc2696442 100644
--- a/.gitignore
+++ b/.gitignore
@@ -87,6 +87,7 @@ modules.builtin
#
include/config
include/generated
+include/ksym
arch/*/include/generated
# stgit generated dirs
diff --git a/Documentation/ABI/stable/sysfs-bus-vmbus b/Documentation/ABI/stable/sysfs-bus-vmbus
index e46be65d0e1d..0c9d9dcd2151 100644
--- a/Documentation/ABI/stable/sysfs-bus-vmbus
+++ b/Documentation/ABI/stable/sysfs-bus-vmbus
@@ -132,3 +132,10 @@ KernelVersion: 4.16
Contact: Stephen Hemminger <sthemmin@microsoft.com>
Description: Monitor bit associated with channel
Users: Debugging tools and userspace drivers
+
+What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/ring
+Date: January. 2018
+KernelVersion: 4.16
+Contact: Stephen Hemminger <sthemmin@microsoft.com>
+Description: Binary file created by uio_hv_generic for ring buffer
+Users: Userspace drivers
diff --git a/Documentation/ABI/testing/debugfs-cec-error-inj b/Documentation/ABI/testing/debugfs-cec-error-inj
new file mode 100644
index 000000000000..122b65c5fe62
--- /dev/null
+++ b/Documentation/ABI/testing/debugfs-cec-error-inj
@@ -0,0 +1,40 @@
+What: /sys/kernel/debug/cec/*/error-inj
+Date: March 2018
+Contact: Hans Verkuil <hans.verkuil@cisco.com>
+Description:
+
+The CEC Framework allows for CEC error injection commands through
+debugfs. Drivers that support this will create an error-inj file
+through which the error injection commands can be given.
+
+The basic syntax is as follows:
+
+Leading spaces/tabs are ignored. If the next character is a '#' or the
+end of the line was reached, then the whole line is ignored. Otherwise
+a command is expected.
+
+It is up to the driver to decide what commands to implement. The only
+exception is that the command 'clear' without any arguments must be
+implemented and that it will remove all current error injection
+commands.
+
+This ensures that you can always do 'echo clear >error-inj' to clear any
+error injections without having to know the details of the driver-specific
+commands.
+
+Note that the output of 'error-inj' shall be valid as input to 'error-inj'.
+So this must work:
+
+ $ cat error-inj >einj.txt
+ $ cat einj.txt >error-inj
+
+Other than these basic rules described above this ABI is not considered
+stable and may change in the future.
+
+Drivers that implement this functionality must document the commands as
+part of the CEC documentation and must keep that documentation up to date
+when changes are made.
+
+The following CEC error injection implementations exist:
+
+- Documentation/media/uapi/cec/cec-pin-error-inj.rst
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-chemical-vz89x b/Documentation/ABI/testing/sysfs-bus-iio-chemical-vz89x
index c0c1ea924535..d512f865600e 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio-chemical-vz89x
+++ b/Documentation/ABI/testing/sysfs-bus-iio-chemical-vz89x
@@ -1,7 +1,7 @@
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_VOC_short_raw
Date: September 2015
KernelVersion: 4.3
-Contact: Matt Ranostay <mranostay@gmail.com>
+Contact: Matt Ranostay <matt.ranostay@konsulko.com>
Description:
Get the raw calibration VOC value from the sensor.
This value has little application outside of calibration.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 b/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935
index 147d4e8a1403..9a17ab5036a4 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935
+++ b/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935
@@ -1,7 +1,7 @@
What /sys/bus/iio/devices/iio:deviceX/in_proximity_input
Date: March 2014
KernelVersion: 3.15
-Contact: Matt Ranostay <mranostay@gmail.com>
+Contact: Matt Ranostay <matt.ranostay@konsulko.com>
Description:
Get the current distance in meters of storm (1km steps)
1000-40000 = distance in meters
@@ -9,7 +9,7 @@ Description:
What /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
Date: March 2014
KernelVersion: 3.15
-Contact: Matt Ranostay <mranostay@gmail.com>
+Contact: Matt Ranostay <matt.ranostay@konsulko.com>
Description:
Show or set the gain boost of the amp, from 0-31 range.
18 = indoors (default)
diff --git a/Documentation/ABI/testing/sysfs-bus-thunderbolt b/Documentation/ABI/testing/sysfs-bus-thunderbolt
index 93798c02e28b..151584a1f950 100644
--- a/Documentation/ABI/testing/sysfs-bus-thunderbolt
+++ b/Documentation/ABI/testing/sysfs-bus-thunderbolt
@@ -1,3 +1,26 @@
+What: /sys/bus/thunderbolt/devices/.../domainX/boot_acl
+Date: Jun 2018
+KernelVersion: 4.17
+Contact: thunderbolt-software@lists.01.org
+Description: Holds a comma separated list of device unique_ids that
+ are allowed to be connected automatically during system
+ startup (e.g boot devices). The list always contains
+ maximum supported number of unique_ids where unused
+ entries are empty. This allows the userspace software
+ to determine how many entries the controller supports.
+ If there are multiple controllers, each controller has
+ its own ACL list and size may be different between the
+ controllers.
+
+ System BIOS may have an option "Preboot ACL" or similar
+ that needs to be selected before this list is taken into
+ consideration.
+
+ Software always updates a full list in each write.
+
+ If a device is authorized automatically during boot its
+ boot attribute is set to 1.
+
What: /sys/bus/thunderbolt/devices/.../domainX/security
Date: Sep 2017
KernelVersion: 4.13
@@ -12,6 +35,9 @@ Description: This attribute holds current Thunderbolt security level
minimum. User needs to authorize each device.
dponly: Automatically tunnel Display port (and USB). No
PCIe tunnels are created.
+ usbonly: Automatically tunnel USB controller of the
+ connected Thunderbolt dock (and Display Port). All
+ PCIe links downstream of the dock are removed.
What: /sys/bus/thunderbolt/devices/.../authorized
Date: Sep 2017
@@ -38,6 +64,13 @@ Description: This attribute is used to authorize Thunderbolt devices
the device did not contain a key at all, and
EKEYREJECTED if the challenge response did not match.
+What: /sys/bus/thunderbolt/devices/.../boot
+Date: Jun 2018
+KernelVersion: 4.17
+Contact: thunderbolt-software@lists.01.org
+Description: This attribute contains 1 if Thunderbolt device was already
+ authorized on boot and 0 otherwise.
+
What: /sys/bus/thunderbolt/devices/.../key
Date: Sep 2017
KernelVersion: 4.13
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index 0bd731cbb50c..c702c78f24d8 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -189,6 +189,16 @@ Description:
The file will read "hotplug", "wired" and "not used" if the
information is available, and "unknown" otherwise.
+What: /sys/bus/usb/devices/.../(hub interface)/portX/over_current_count
+Date: February 2018
+Contact: Richard Leitner <richard.leitner@skidata.com>
+Description:
+ Most hubs are able to detect over-current situations on their
+ ports and report them to the kernel. This attribute is to expose
+ the number of over-current situation occurred on a specific port
+ to user space. This file will contain an unsigned 32 bit value
+ which wraps to 0 after its maximum is reached.
+
What: /sys/bus/usb/devices/.../(hub interface)/portX/usb3_lpm_permit
Date: November 2015
Contact: Lu Baolu <baolu.lu@linux.intel.com>
diff --git a/Documentation/ABI/testing/sysfs-class-mei b/Documentation/ABI/testing/sysfs-class-mei
index 5096a82f4cde..81ff6abf9673 100644
--- a/Documentation/ABI/testing/sysfs-class-mei
+++ b/Documentation/ABI/testing/sysfs-class-mei
@@ -45,3 +45,12 @@ Contact: Tomas Winkler <tomas.winkler@intel.com>
Description: Display the driver HBM protocol version.
The HBM protocol version supported by the driver.
+
+What: /sys/class/mei/meiN/tx_queue_limit
+Date: Jan 2018
+KernelVersion: 4.16
+Contact: Tomas Winkler <tomas.winkler@intel.com>
+Description: Configure tx queue limit
+
+ Set maximal number of pending writes
+ per opened session.
diff --git a/Documentation/ABI/testing/sysfs-class-usb_role b/Documentation/ABI/testing/sysfs-class-usb_role
new file mode 100644
index 000000000000..3b810a425a52
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-usb_role
@@ -0,0 +1,21 @@
+What: /sys/class/usb_role/
+Date: Jan 2018
+Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+ Place in sysfs for USB Role Switches. USB Role Switch is a
+ device that can select the data role (host or device) for USB
+ port.
+
+What: /sys/class/usb_role/<switch>/role
+Date: Jan 2018
+Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+ The current role of the switch. This attribute can be used for
+ requesting role swapping with non-USB Type-C ports. With USB
+ Type-C ports, the ABI defined for USB Type-C connector class
+ must be used.
+
+ Valid values:
+ - none
+ - host
+ - device
diff --git a/Documentation/ABI/testing/sysfs-driver-fsi-master-gpio b/Documentation/ABI/testing/sysfs-driver-fsi-master-gpio
new file mode 100644
index 000000000000..1f29c8843cfd
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-fsi-master-gpio
@@ -0,0 +1,10 @@
+What: /sys/bus/platform/devices/[..]/fsi-master-gpio/external_mode
+Date: Feb 2018
+KernelVersion: 4.17
+Contact: jk@ozlabs.org
+Description:
+ Controls access arbitration for GPIO-based FSI master. A
+ value of 0 (the default) sets normal mode, where the
+ driver performs FSI bus transactions, 1 sets external mode,
+ where the FSI bus is driven externally (for example, by
+ a debug device).
diff --git a/Documentation/ABI/testing/sysfs-kernel-irq b/Documentation/ABI/testing/sysfs-kernel-irq
index eb074b100986..8910d0c4bcd8 100644
--- a/Documentation/ABI/testing/sysfs-kernel-irq
+++ b/Documentation/ABI/testing/sysfs-kernel-irq
@@ -51,3 +51,10 @@ Date: September 2016
KernelVersion: 4.9
Contact: Craig Gallek <kraig@google.com>
Description: The type of the interrupt. Either the string 'level' or 'edge'.
+
+What: /sys/kernel/irq/<irq>/wakeup
+Date: March 2018
+KernelVersion: 4.17
+Contact: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Description: The wakeup state of the interrupt. Either the string
+ 'enabled' or 'disabled'.
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index bf03fe49f1ce..5ffe4c4121bd 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1739,6 +1739,14 @@
of a GICv2 controller even if the memory range
exposed by the device tree is too small.
+ irqchip.gicv3_nolpi=
+ [ARM, ARM64]
+ Force the kernel to ignore the availability of
+ LPIs (and by consequence ITSs). Intended for system
+ that use the kernel as a bootloader, and thus want
+ to let secondary kernels in charge of setting up
+ LPIs.
+
irqfixup [HW]
When an interrupt is not handled search all handlers
for it. Intended to get systems with badly broken
@@ -4384,6 +4392,64 @@
usbcore.nousb [USB] Disable the USB subsystem
+ usbcore.quirks=
+ [USB] A list of quirk entries to augment the built-in
+ usb core quirk list. List entries are separated by
+ commas. Each entry has the form
+ VendorID:ProductID:Flags. The IDs are 4-digit hex
+ numbers and Flags is a set of letters. Each letter
+ will change the built-in quirk; setting it if it is
+ clear and clearing it if it is set. The letters have
+ the following meanings:
+ a = USB_QUIRK_STRING_FETCH_255 (string
+ descriptors must not be fetched using
+ a 255-byte read);
+ b = USB_QUIRK_RESET_RESUME (device can't resume
+ correctly so reset it instead);
+ c = USB_QUIRK_NO_SET_INTF (device can't handle
+ Set-Interface requests);
+ d = USB_QUIRK_CONFIG_INTF_STRINGS (device can't
+ handle its Configuration or Interface
+ strings);
+ e = USB_QUIRK_RESET (device can't be reset
+ (e.g morph devices), don't use reset);
+ f = USB_QUIRK_HONOR_BNUMINTERFACES (device has
+ more interface descriptions than the
+ bNumInterfaces count, and can't handle
+ talking to these interfaces);
+ g = USB_QUIRK_DELAY_INIT (device needs a pause
+ during initialization, after we read
+ the device descriptor);
+ h = USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL (For
+ high speed and super speed interrupt
+ endpoints, the USB 2.0 and USB 3.0 spec
+ require the interval in microframes (1
+ microframe = 125 microseconds) to be
+ calculated as interval = 2 ^
+ (bInterval-1).
+ Devices with this quirk report their
+ bInterval as the result of this
+ calculation instead of the exponent
+ variable used in the calculation);
+ i = USB_QUIRK_DEVICE_QUALIFIER (device can't
+ handle device_qualifier descriptor
+ requests);
+ j = USB_QUIRK_IGNORE_REMOTE_WAKEUP (device
+ generates spurious wakeup, ignore
+ remote wakeup capability);
+ k = USB_QUIRK_NO_LPM (device can't handle Link
+ Power Management);
+ l = USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL
+ (Device reports its bInterval as linear
+ frames instead of the USB 2.0
+ calculation);
+ m = USB_QUIRK_DISCONNECT_SUSPEND (Device needs
+ to be disconnected before suspend to
+ prevent spurious wakeup);
+ n = USB_QUIRK_DELAY_CTRL_MSG (Device needs a
+ pause after every control message);
+ Example: quirks=0781:5580:bk,0a5c:5834:gij
+
usbhid.mousepoll=
[USBHID] The interval which mice are to be polled at.
diff --git a/Documentation/admin-guide/thunderbolt.rst b/Documentation/admin-guide/thunderbolt.rst
index 9948ec36a204..35fccba6a9a6 100644
--- a/Documentation/admin-guide/thunderbolt.rst
+++ b/Documentation/admin-guide/thunderbolt.rst
@@ -21,11 +21,11 @@ vulnerable to DMA attacks.
Security levels and how to use them
-----------------------------------
Starting with Intel Falcon Ridge Thunderbolt controller there are 4
-security levels available. The reason for these is the fact that the
-connected devices can be DMA masters and thus read contents of the host
-memory without CPU and OS knowing about it. There are ways to prevent
-this by setting up an IOMMU but it is not always available for various
-reasons.
+security levels available. Intel Titan Ridge added one more security level
+(usbonly). The reason for these is the fact that the connected devices can
+be DMA masters and thus read contents of the host memory without CPU and OS
+knowing about it. There are ways to prevent this by setting up an IOMMU but
+it is not always available for various reasons.
The security levels are as follows:
@@ -52,6 +52,11 @@ The security levels are as follows:
USB. No PCIe tunneling is done. In BIOS settings this is
typically called *Display Port Only*.
+ usbonly
+ The firmware automatically creates tunnels for the USB controller and
+ Display Port in a dock. All PCIe links downstream of the dock are
+ removed.
+
The current security level can be read from
``/sys/bus/thunderbolt/devices/domainX/security`` where ``domainX`` is
the Thunderbolt domain the host controller manages. There is typically
diff --git a/Documentation/arm64/cpu-feature-registers.txt b/Documentation/arm64/cpu-feature-registers.txt
index a70090b28b07..7964f03846b1 100644
--- a/Documentation/arm64/cpu-feature-registers.txt
+++ b/Documentation/arm64/cpu-feature-registers.txt
@@ -110,7 +110,7 @@ infrastructure:
x--------------------------------------------------x
| Name | bits | visible |
|--------------------------------------------------|
- | RES0 | [63-52] | n |
+ | TS | [55-52] | y |
|--------------------------------------------------|
| FHM | [51-48] | y |
|--------------------------------------------------|
@@ -124,8 +124,6 @@ infrastructure:
|--------------------------------------------------|
| RDM | [31-28] | y |
|--------------------------------------------------|
- | RES0 | [27-24] | n |
- |--------------------------------------------------|
| ATOMICS | [23-20] | y |
|--------------------------------------------------|
| CRC32 | [19-16] | y |
@@ -135,8 +133,6 @@ infrastructure:
| SHA1 | [11-8] | y |
|--------------------------------------------------|
| AES | [7-4] | y |
- |--------------------------------------------------|
- | RES0 | [3-0] | n |
x--------------------------------------------------x
@@ -144,12 +140,10 @@ infrastructure:
x--------------------------------------------------x
| Name | bits | visible |
|--------------------------------------------------|
- | RES0 | [63-36] | n |
+ | DIT | [51-48] | y |
|--------------------------------------------------|
| SVE | [35-32] | y |
|--------------------------------------------------|
- | RES0 | [31-28] | n |
- |--------------------------------------------------|
| GIC | [27-24] | n |
|--------------------------------------------------|
| AdvSIMD | [23-20] | y |
@@ -199,6 +193,14 @@ infrastructure:
| DPB | [3-0] | y |
x--------------------------------------------------x
+ 5) ID_AA64MMFR2_EL1 - Memory model feature register 2
+
+ x--------------------------------------------------x
+ | Name | bits | visible |
+ |--------------------------------------------------|
+ | AT | [35-32] | y |
+ x--------------------------------------------------x
+
Appendix I: Example
---------------------------
diff --git a/Documentation/arm64/elf_hwcaps.txt b/Documentation/arm64/elf_hwcaps.txt
index 57324ee55ecc..d6aff2c5e9e2 100644
--- a/Documentation/arm64/elf_hwcaps.txt
+++ b/Documentation/arm64/elf_hwcaps.txt
@@ -162,3 +162,19 @@ HWCAP_SVE
HWCAP_ASIMDFHM
Functionality implied by ID_AA64ISAR0_EL1.FHM == 0b0001.
+
+HWCAP_DIT
+
+ Functionality implied by ID_AA64PFR0_EL1.DIT == 0b0001.
+
+HWCAP_USCAT
+
+ Functionality implied by ID_AA64MMFR2_EL1.AT == 0b0001.
+
+HWCAP_ILRCPC
+
+ Functionality implied by ID_AA64ISR1_EL1.LRCPC == 0b0002.
+
+HWCAP_FLAGM
+
+ Functionality implied by ID_AA64ISAR0_EL1.TS == 0b0001.
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
index c1d520de6dfe..3b2f2dd82225 100644
--- a/Documentation/arm64/silicon-errata.txt
+++ b/Documentation/arm64/silicon-errata.txt
@@ -55,6 +55,7 @@ stable kernels.
| ARM | Cortex-A57 | #834220 | ARM64_ERRATUM_834220 |
| ARM | Cortex-A72 | #853709 | N/A |
| ARM | Cortex-A73 | #858921 | ARM64_ERRATUM_858921 |
+| ARM | Cortex-A55 | #1024718 | ARM64_ERRATUM_1024718 |
| ARM | MMU-500 | #841119,#826419 | N/A |
| | | | |
| Cavium | ThunderX ITS | #22375, #24313 | CAVIUM_ERRATUM_22375 |
diff --git a/Documentation/crypto/crypto_engine.rst b/Documentation/crypto/crypto_engine.rst
new file mode 100644
index 000000000000..8272ac92a14f
--- /dev/null
+++ b/Documentation/crypto/crypto_engine.rst
@@ -0,0 +1,48 @@
+=============
+CRYPTO ENGINE
+=============
+
+Overview
+--------
+The crypto engine API (CE), is a crypto queue manager.
+
+Requirement
+-----------
+You have to put at start of your tfm_ctx the struct crypto_engine_ctx
+struct your_tfm_ctx {
+ struct crypto_engine_ctx enginectx;
+ ...
+};
+Why: Since CE manage only crypto_async_request, it cannot know the underlying
+request_type and so have access only on the TFM.
+So using container_of for accessing __ctx is impossible.
+Furthermore, the crypto engine cannot know the "struct your_tfm_ctx",
+so it must assume that crypto_engine_ctx is at start of it.
+
+Order of operations
+-------------------
+You have to obtain a struct crypto_engine via crypto_engine_alloc_init().
+And start it via crypto_engine_start().
+
+Before transferring any request, you have to fill the enginectx.
+- prepare_request: (taking a function pointer) If you need to do some processing before doing the request
+- unprepare_request: (taking a function pointer) Undoing what's done in prepare_request
+- do_one_request: (taking a function pointer) Do encryption for current request
+
+Note: that those three functions get the crypto_async_request associated with the received request.
+So your need to get the original request via container_of(areq, struct yourrequesttype_request, base);
+
+When your driver receive a crypto_request, you have to transfer it to
+the cryptoengine via one of:
+- crypto_transfer_ablkcipher_request_to_engine()
+- crypto_transfer_aead_request_to_engine()
+- crypto_transfer_akcipher_request_to_engine()
+- crypto_transfer_hash_request_to_engine()
+- crypto_transfer_skcipher_request_to_engine()
+
+At the end of the request process, a call to one of the following function is needed:
+- crypto_finalize_ablkcipher_request
+- crypto_finalize_aead_request
+- crypto_finalize_akcipher_request
+- crypto_finalize_hash_request
+- crypto_finalize_skcipher_request
diff --git a/Documentation/crypto/devel-algos.rst b/Documentation/crypto/devel-algos.rst
index 66f50d32dcec..c45c6f400dbd 100644
--- a/Documentation/crypto/devel-algos.rst
+++ b/Documentation/crypto/devel-algos.rst
@@ -236,6 +236,14 @@ when used from another part of the kernel.
|
'---------------> HASH2
+Note that it is perfectly legal to "abandon" a request object:
+- call .init() and then (as many times) .update()
+- _not_ call any of .final(), .finup() or .export() at any point in future
+
+In other words implementations should mind the resource allocation and clean-up.
+No resources related to request objects should remain allocated after a call
+to .init() or .update(), since there might be no chance to free them.
+
Specifics Of Asynchronous HASH Transformation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
index 7111fbc82a4e..199cd36fe1ba 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
@@ -75,6 +75,29 @@ Example:
};
-----------------------------------------------------------------------
+Hisilicon Hi3798CV200 Peripheral Controller
+
+The Hi3798CV200 Peripheral Controller controls peripherals, queries
+their status, and configures some functions of peripherals.
+
+Required properties:
+- compatible: Should contain "hisilicon,hi3798cv200-perictrl", "syscon"
+ and "simple-mfd".
+- reg: Register address and size of Peripheral Controller.
+- #address-cells: Should be 1.
+- #size-cells: Should be 1.
+
+Examples:
+
+ perictrl: peripheral-controller@8a20000 {
+ compatible = "hisilicon,hi3798cv200-perictrl", "syscon",
+ "simple-mfd";
+ reg = <0x8a20000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+
+-----------------------------------------------------------------------
Hisilicon Hi6220 system controller
Required properties:
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index c760ecb81381..f4006d3c9fdf 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -30,6 +30,7 @@ compatible:
Optional properties:
- dma-coherent : Present if dma operations are coherent
- clocks : a list of phandle + clock specifier pairs
+- resets : a list of phandle + reset specifier pairs
- target-supply : regulator for SATA target power
- phys : reference to the SATA PHY node
- phy-names : must be "sata-phy"
diff --git a/Documentation/devicetree/bindings/ata/imx-sata.txt b/Documentation/devicetree/bindings/ata/imx-sata.txt
index a3d14719e478..781f88751762 100644
--- a/Documentation/devicetree/bindings/ata/imx-sata.txt
+++ b/Documentation/devicetree/bindings/ata/imx-sata.txt
@@ -7,6 +7,7 @@ Required properties:
- compatible : should be one of the following:
- "fsl,imx53-ahci" for i.MX53 SATA controller
- "fsl,imx6q-ahci" for i.MX6Q SATA controller
+ - "fsl,imx6qp-ahci" for i.MX6QP SATA controller
- interrupts : interrupt mapping for SATA IRQ
- reg : registers mapping
- clocks : list of clock specifiers, must contain an entry for each
diff --git a/Documentation/devicetree/bindings/ata/nvidia,tegra124-ahci.txt b/Documentation/devicetree/bindings/ata/nvidia,tegra124-ahci.txt
index 66c83c3e8915..12ab2f723eb0 100644
--- a/Documentation/devicetree/bindings/ata/nvidia,tegra124-ahci.txt
+++ b/Documentation/devicetree/bindings/ata/nvidia,tegra124-ahci.txt
@@ -1,9 +1,10 @@
-Tegra124 SoC SATA AHCI controller
+Tegra SoC SATA AHCI controller
Required properties :
-- compatible : For Tegra124, must contain "nvidia,tegra124-ahci". Otherwise,
- must contain '"nvidia,<chip>-ahci", "nvidia,tegra124-ahci"', where <chip>
- is tegra132.
+- compatible : Must be one of:
+ - Tegra124 : "nvidia,tegra124-ahci"
+ - Tegra132 : "nvidia,tegra132-ahci", "nvidia,tegra124-ahci"
+ - Tegra210 : "nvidia,tegra210-ahci"
- reg : Should contain 2 entries:
- AHCI register set (SATA BAR5)
- SATA register set
@@ -13,8 +14,6 @@ Required properties :
- clock-names : Must include the following entries:
- sata
- sata-oob
- - cml1
- - pll_e
- resets : Must contain an entry for each entry in reset-names.
See ../reset/reset.txt for details.
- reset-names : Must include the following entries:
@@ -24,9 +23,22 @@ Required properties :
- phys : Must contain an entry for each entry in phy-names.
See ../phy/phy-bindings.txt for details.
- phy-names : Must include the following entries:
- - sata-phy : XUSB PADCTL SATA PHY
-- hvdd-supply : Defines the SATA HVDD regulator
-- vddio-supply : Defines the SATA VDDIO regulator
-- avdd-supply : Defines the SATA AVDD regulator
-- target-5v-supply : Defines the SATA 5V power regulator
-- target-12v-supply : Defines the SATA 12V power regulator
+ - For Tegra124 and Tegra132:
+ - sata-phy : XUSB PADCTL SATA PHY
+- For Tegra124 and Tegra132:
+ - hvdd-supply : Defines the SATA HVDD regulator
+ - vddio-supply : Defines the SATA VDDIO regulator
+ - avdd-supply : Defines the SATA AVDD regulator
+ - target-5v-supply : Defines the SATA 5V power regulator
+ - target-12v-supply : Defines the SATA 12V power regulator
+
+Optional properties:
+- reg :
+ - AUX register set
+- clock-names :
+ - cml1 :
+ cml1 clock should be defined here if the PHY driver
+ doesn't manage them. If it does, they should not be.
+- phy-names :
+ - For T210:
+ - sata-phy
diff --git a/Documentation/devicetree/bindings/connector/samsung,usb-connector-11pin.txt b/Documentation/devicetree/bindings/connector/samsung,usb-connector-11pin.txt
new file mode 100644
index 000000000000..22256e295a7a
--- /dev/null
+++ b/Documentation/devicetree/bindings/connector/samsung,usb-connector-11pin.txt
@@ -0,0 +1,49 @@
+Samsung micro-USB 11-pin connector
+==================================
+
+Samsung micro-USB 11-pin connector is an extension of micro-USB connector.
+It is present in multiple Samsung mobile devices.
+It has additional pins to route MHL traffic simultanously with USB.
+
+The bindings are superset of usb-connector bindings for micro-USB connector[1].
+
+Required properties:
+- compatible: must be: "samsung,usb-connector-11pin", "usb-b-connector",
+- type: must be "micro".
+
+Required nodes:
+- any data bus to the connector should be modeled using the OF graph bindings
+ specified in bindings/graph.txt, unless the bus is between parent node and
+ the connector. Since single connector can have multpile data buses every bus
+ has assigned OF graph port number as follows:
+ 0: High Speed (HS),
+ 3: Mobile High-Definition Link (MHL), specific to 11-pin Samsung micro-USB.
+
+[1]: bindings/connector/usb-connector.txt
+
+Example
+-------
+
+Micro-USB connector with HS lines routed via controller (MUIC) and MHL lines
+connected to HDMI-MHL bridge (sii8620):
+
+muic-max77843@66 {
+ ...
+ usb_con: connector {
+ compatible = "samsung,usb-connector-11pin", "usb-b-connector";
+ label = "micro-USB";
+ type = "micro";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@3 {
+ reg = <3>;
+ usb_con_mhl: endpoint {
+ remote-endpoint = <&sii8620_mhl>;
+ };
+ };
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/connector/usb-connector.txt b/Documentation/devicetree/bindings/connector/usb-connector.txt
new file mode 100644
index 000000000000..e1463f14af38
--- /dev/null
+++ b/Documentation/devicetree/bindings/connector/usb-connector.txt
@@ -0,0 +1,75 @@
+USB Connector
+=============
+
+USB connector node represents physical USB connector. It should be
+a child of USB interface controller.
+
+Required properties:
+- compatible: describes type of the connector, must be one of:
+ "usb-a-connector",
+ "usb-b-connector",
+ "usb-c-connector".
+
+Optional properties:
+- label: symbolic name for the connector,
+- type: size of the connector, should be specified in case of USB-A, USB-B
+ non-fullsize connectors: "mini", "micro".
+
+Required nodes:
+- any data bus to the connector should be modeled using the OF graph bindings
+ specified in bindings/graph.txt, unless the bus is between parent node and
+ the connector. Since single connector can have multpile data buses every bus
+ has assigned OF graph port number as follows:
+ 0: High Speed (HS), present in all connectors,
+ 1: Super Speed (SS), present in SS capable connectors,
+ 2: Sideband use (SBU), present in USB-C.
+
+Examples
+--------
+
+1. Micro-USB connector with HS lines routed via controller (MUIC):
+
+muic-max77843@66 {
+ ...
+ usb_con: connector {
+ compatible = "usb-b-connector";
+ label = "micro-USB";
+ type = "micro";
+ };
+};
+
+2. USB-C connector attached to CC controller (s2mm005), HS lines routed
+to companion PMIC (max77865), SS lines to USB3 PHY and SBU to DisplayPort.
+DisplayPort video lines are routed to the connector via SS mux in USB3 PHY.
+
+ccic: s2mm005@33 {
+ ...
+ usb_con: connector {
+ compatible = "usb-c-connector";
+ label = "USB-C";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ usb_con_hs: endpoint {
+ remote-endpoint = <&max77865_usbc_hs>;
+ };
+ };
+ port@1 {
+ reg = <1>;
+ usb_con_ss: endpoint {
+ remote-endpoint = <&usbdrd_phy_ss>;
+ };
+ };
+ port@2 {
+ reg = <2>;
+ usb_con_sbu: endpoint {
+ remote-endpoint = <&dp_aux>;
+ };
+ };
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/crypto/arm-cryptocell.txt b/Documentation/devicetree/bindings/crypto/arm-cryptocell.txt
index cec8d5d74e26..c2598ab27f2e 100644
--- a/Documentation/devicetree/bindings/crypto/arm-cryptocell.txt
+++ b/Documentation/devicetree/bindings/crypto/arm-cryptocell.txt
@@ -1,7 +1,8 @@
Arm TrustZone CryptoCell cryptographic engine
Required properties:
-- compatible: Should be "arm,cryptocell-712-ree".
+- compatible: Should be one of: "arm,cryptocell-712-ree",
+ "arm,cryptocell-710-ree" or "arm,cryptocell-630p-ree".
- reg: Base physical address of the engine and length of memory mapped region.
- interrupts: Interrupt number for the device.
diff --git a/Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt b/Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt
index 30c3ce6b502e..5dba55cdfa63 100644
--- a/Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt
+++ b/Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt
@@ -8,7 +8,11 @@ Required properties:
- interrupt-names: Should be "ring0", "ring1", "ring2", "ring3", "eip", "mem".
Optional properties:
-- clocks: Reference to the crypto engine clock.
+- clocks: Reference to the crypto engine clocks, the second clock is
+ needed for the Armada 7K/8K SoCs.
+- clock-names: mandatory if there is a second clock, in this case the
+ name must be "core" for the first clock and "reg" for
+ the second one.
Example:
diff --git a/Documentation/devicetree/bindings/fsi/fsi.txt b/Documentation/devicetree/bindings/fsi/fsi.txt
new file mode 100644
index 000000000000..ab516c673a4b
--- /dev/null
+++ b/Documentation/devicetree/bindings/fsi/fsi.txt
@@ -0,0 +1,151 @@
+FSI bus & engine generic device tree bindings
+=============================================
+
+The FSI bus is probe-able, so the OS is able to enumerate FSI slaves, and
+engines within those slaves. However, we have a facility to match devicetree
+nodes to probed engines. This allows for fsi engines to expose non-probeable
+busses, which are then exposed by the device tree. For example, an FSI engine
+that is an I2C master - the I2C bus can be described by the device tree under
+the engine's device tree node.
+
+FSI masters may require their own DT nodes (to describe the master HW itself);
+that requirement is defined by the master's implementation, and is described by
+the fsi-master-* binding specifications.
+
+Under the masters' nodes, we can describe the bus topology using nodes to
+represent the FSI slaves and their slave engines. As a basic outline:
+
+ fsi-master {
+ /* top-level of FSI bus topology, bound to an FSI master driver and
+ * exposes an FSI bus */
+
+ fsi-slave@<link,id> {
+ /* this node defines the FSI slave device, and is handled
+ * entirely with FSI core code */
+
+ fsi-slave-engine@<addr> {
+ /* this node defines the engine endpoint & address range, which
+ * is bound to the relevant fsi device driver */
+ ...
+ };
+
+ fsi-slave-engine@<addr> {
+ ...
+ };
+
+ };
+ };
+
+Note that since the bus is probe-able, some (or all) of the topology may
+not be described; this binding only provides an optional facility for
+adding subordinate device tree nodes as children of FSI engines.
+
+FSI masters
+-----------
+
+FSI master nodes declare themselves as such with the "fsi-master" compatible
+value. It's likely that an implementation-specific compatible value will
+be needed as well, for example:
+
+ compatible = "fsi-master-gpio", "fsi-master";
+
+Since the master nodes describe the top-level of the FSI topology, they also
+need to declare the FSI-standard addressing scheme. This requires two cells for
+addresses (link index and slave ID), and no size:
+
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+An optional boolean property can be added to indicate that a particular master
+should not scan for connected devices at initialization time. This is
+necessary in cases where a scan could cause arbitration issues with other
+masters that may be present on the bus.
+
+ no-scan-on-init;
+
+FSI slaves
+----------
+
+Slaves are identified by a (link-index, slave-id) pair, so require two cells
+for an address identifier. Since these are not a range, no size cells are
+required. For an example, a slave on link 1, with ID 2, could be represented
+as:
+
+ cfam@1,2 {
+ reg = <1 2>;
+ [...];
+ }
+
+Each slave provides an address-space, under which the engines are accessible.
+That address space has a maximum of 23 bits, so we use one cell to represent
+addresses and sizes in the slave address space:
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+
+FSI engines (devices)
+---------------------
+
+Engines are identified by their address under the slaves' address spaces. We
+use a single cell for address and size. Engine nodes represent the endpoint
+FSI device, and are passed to those FSI device drivers' ->probe() functions.
+
+For example, for a slave using a single 0x400-byte page starting at address
+0xc00:
+
+ engine@c00 {
+ reg = <0xc00 0x400>;
+ };
+
+
+Full example
+------------
+
+Here's an example that illustrates:
+ - an FSI master
+ - connected to an FSI slave
+ - that contains an engine that is an I2C master
+ - connected to an I2C EEPROM
+
+The FSI master may be connected to additional slaves, and slaves may have
+additional engines, but they don't necessarily need to be describe in the
+device tree if no extra platform information is required.
+
+ /* The GPIO-based FSI master node, describing the top level of the
+ * FSI bus
+ */
+ gpio-fsi {
+ compatible = "fsi-master-gpio", "fsi-master";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ /* A FSI slave (aka. CFAM) at link 0, ID 0. */
+ cfam@0,0 {
+ reg = <0 0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /* FSI engine at 0xc00, using a single page. In this example,
+ * it's an I2C master controller, so subnodes describe the
+ * I2C bus.
+ */
+ i2c-controller@c00 {
+ reg = <0xc00 0x400>;
+
+ /* Engine-specific data. In this case, we're describing an
+ * I2C bus, so we're conforming to the generic I2C binding
+ */
+ compatible = "some-vendor,fsi-i2c-controller";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ /* I2C endpoint device: an Atmel EEPROM */
+ eeprom@50 {
+ compatible = "atmel,24c256";
+ reg = <0x50>;
+ pagesize = <64>;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/adc/axp20x_adc.txt b/Documentation/devicetree/bindings/iio/adc/axp20x_adc.txt
new file mode 100644
index 000000000000..7a6313913923
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/axp20x_adc.txt
@@ -0,0 +1,48 @@
+* X-Powers AXP ADC bindings
+
+Required properties:
+ - compatible: should be one of:
+ - "x-powers,axp209-adc",
+ - "x-powers,axp221-adc",
+ - "x-powers,axp813-adc",
+ - #io-channel-cells: should be 1,
+
+Example:
+
+&axp22x {
+ adc {
+ compatible = "x-powers,axp221-adc";
+ #io-channel-cells = <1>;
+ };
+};
+
+ADC channels and their indexes per variant:
+
+AXP209
+------
+ 0 | acin_v
+ 1 | acin_i
+ 2 | vbus_v
+ 3 | vbus_i
+ 4 | pmic_temp
+ 5 | gpio0_v
+ 6 | gpio1_v
+ 7 | ipsout_v
+ 8 | batt_v
+ 9 | batt_chrg_i
+10 | batt_dischrg_i
+
+AXP22x
+------
+ 0 | pmic_temp
+ 1 | batt_v
+ 2 | batt_chrg_i
+ 3 | batt_dischrg_i
+
+AXP813
+------
+ 0 | pmic_temp
+ 1 | gpio0_v
+ 2 | batt_v
+ 3 | batt_chrg_i
+ 4 | batt_dischrg_i
diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt
index 911492da48f3..ed7520d1d051 100644
--- a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt
@@ -32,6 +32,10 @@ Optional properties:
to "clock" property. Frequency must be a multiple of the rcc
clock frequency. If not, SPI CLKOUT frequency will not be
accurate.
+- pinctrl-names: Set to "default".
+- pinctrl-0: List of phandles pointing to pin configuration
+ nodes to set pins in mode of operation for dfsdm
+ on external pin.
Contents of a STM32 DFSDM child nodes:
--------------------------------------
@@ -68,8 +72,8 @@ Optional properties:
- st,adc-channel-types: Single-ended channel input type.
- "SPI_R": SPI with data on rising edge (default)
- "SPI_F": SPI with data on falling edge
- - "MANCH_R": manchester codec, rising edge = logic 0
- - "MANCH_F": manchester codec, falling edge = logic 1
+ - "MANCH_R": manchester codec, rising edge = logic 0, falling edge = logic 1
+ - "MANCH_F": manchester codec, rising edge = logic 1, falling edge = logic 0
- st,adc-channel-clk-src: Conversion clock source.
- "CLKIN": external SPI clock (CLKIN x)
- "CLKOUT": internal SPI clock (CLKOUT) (default)
diff --git a/Documentation/devicetree/bindings/iio/potentiometer/ad5272.txt b/Documentation/devicetree/bindings/iio/potentiometer/ad5272.txt
new file mode 100644
index 000000000000..f9b2eef946aa
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/potentiometer/ad5272.txt
@@ -0,0 +1,27 @@
+* Analog Devices AD5272 digital potentiometer
+
+The node for this device must be a child node of a I2C controller, hence
+all mandatory properties for your controller must be specified. See directory:
+
+ Documentation/devicetree/bindings/i2c
+
+for more details.
+
+Required properties:
+ - compatible: Must be one of the following, depending on the model:
+ adi,ad5272-020
+ adi,ad5272-050
+ adi,ad5272-100
+ adi,ad5274-020
+ adi,ad5274-100
+
+Optional properties:
+ - reset-gpios: GPIO specification for the RESET input. This is an
+ active low signal to the AD5272.
+
+Example:
+ad5272: potentiometer@2f {
+ reg = <0x2F>;
+ compatible = "adi,ad5272-020";
+ reset-gpios = <&gpio3 6 GPIO_ACTIVE_HIGH>;
+};
diff --git a/Documentation/devicetree/bindings/iio/temperature/mlx90632.txt b/Documentation/devicetree/bindings/iio/temperature/mlx90632.txt
new file mode 100644
index 000000000000..0b05812001f8
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/temperature/mlx90632.txt
@@ -0,0 +1,28 @@
+* Melexis MLX90632 contactless Infra Red temperature sensor
+
+Link to datasheet: https://www.melexis.com/en/documents/documentation/datasheets/datasheet-mlx90632
+
+There are various applications for the Infra Red contactless temperature sensor
+and MLX90632 is most suitable for consumer applications where measured object
+temperature is in range between -20 to 200 degrees Celsius with relative error
+of measurement below 1 degree Celsius in object temperature range for
+industrial applications. Since it can operate and measure ambient temperature
+in range of -20 to 85 degrees Celsius it is suitable also for outdoor use.
+
+Be aware that electronics surrounding the sensor can increase ambient
+temperature. MLX90632 can be calibrated to reduce the housing effect via
+already existing EEPROM parameters.
+
+Since measured object emissivity effects Infra Red energy emitted, emissivity
+should be set before requesting the object temperature.
+
+Required properties:
+ - compatible: should be "melexis,mlx90632"
+ - reg: the I2C address of the sensor (default 0x3a)
+
+Example:
+
+mlx90632@3a {
+ compatible = "melexis,mlx90632";
+ reg = <0x3a>;
+};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt b/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt
new file mode 100644
index 000000000000..b47a8a02b17b
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt
@@ -0,0 +1,22 @@
+Microsemi Ocelot SoC ICPU Interrupt Controller
+
+Required properties:
+
+- compatible : should be "mscc,ocelot-icpu-intr"
+- reg : Specifies base physical address and size of the registers.
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+ interrupt source. The value shall be 1.
+- interrupt-parent : phandle of the CPU interrupt controller.
+- interrupts : Specifies the CPU interrupt the controller is connected to.
+
+Example:
+
+ intc: interrupt-controller@70000070 {
+ compatible = "mscc,ocelot-icpu-intr";
+ reg = <0x70000070 0x70>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ interrupt-parent = <&cpuintc>;
+ interrupts = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt
new file mode 100644
index 000000000000..0b2c97ddb520
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt
@@ -0,0 +1,78 @@
+PDC interrupt controller
+
+Qualcomm Technologies Inc. SoCs based on the RPM Hardened architecture have a
+Power Domain Controller (PDC) that is on always-on domain. In addition to
+providing power control for the power domains, the hardware also has an
+interrupt controller that can be used to help detect edge low interrupts as
+well detect interrupts when the GIC is non-operational.
+
+GIC is parent interrupt controller at the highest level. Platform interrupt
+controller PDC is next in hierarchy, followed by others. Drivers requiring
+wakeup capabilities of their device interrupts routed through the PDC, must
+specify PDC as their interrupt controller and request the PDC port associated
+with the GIC interrupt. See example below.
+
+Properties:
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: Should contain "qcom,<soc>-pdc"
+ - "qcom,sdm845-pdc": For SDM845
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Specifies the base physical address for PDC hardware.
+
+- interrupt-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: Specifies the number of cells needed to encode an interrupt
+ source.
+ Must be 2.
+ The first element of the tuple is the PDC pin for the
+ interrupt.
+ The second element is the trigger type.
+
+- interrupt-parent:
+ Usage: required
+ Value type: <phandle>
+ Definition: Specifies the interrupt parent necessary for hierarchical
+ domain to operate.
+
+- interrupt-controller:
+ Usage: required
+ Value type: <bool>
+ Definition: Identifies the node as an interrupt controller.
+
+- qcom,pdc-ranges:
+ Usage: required
+ Value type: <u32 array>
+ Definition: Specifies the PDC pin offset and the number of PDC ports.
+ The tuples indicates the valid mapping of valid PDC ports
+ and their hwirq mapping.
+ The first element of the tuple is the starting PDC port.
+ The second element is the GIC hwirq number for the PDC port.
+ The third element is the number of interrupts in sequence.
+
+Example:
+
+ pdc: interrupt-controller@b220000 {
+ compatible = "qcom,sdm845-pdc";
+ reg = <0xb220000 0x30000>;
+ qcom,pdc-ranges = <0 512 94>, <94 641 15>, <115 662 7>;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&intc>;
+ interrupt-controller;
+ };
+
+DT binding of a device that wants to use the GIC SPI 514 as a wakeup
+interrupt, must do -
+
+ wake-device {
+ interrupts-extended = <&pdc 2 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+In this case interrupt 514 would be mapped to port 2 on the PDC as defined by
+the qcom,pdc-ranges property.
diff --git a/Documentation/devicetree/bindings/media/coda.txt b/Documentation/devicetree/bindings/media/coda.txt
index 2865d04e4030..90eb74cc1993 100644
--- a/Documentation/devicetree/bindings/media/coda.txt
+++ b/Documentation/devicetree/bindings/media/coda.txt
@@ -7,8 +7,9 @@ called VPU (Video Processing Unit).
Required properties:
- compatible : should be "fsl,<chip>-src" for i.MX SoCs:
(a) "fsl,imx27-vpu" for CodaDx6 present in i.MX27
- (b) "fsl,imx53-vpu" for CODA7541 present in i.MX53
- (c) "fsl,imx6q-vpu" for CODA960 present in i.MX6q
+ (b) "fsl,imx51-vpu" for CodaHx4 present in i.MX51
+ (c) "fsl,imx53-vpu" for CODA7541 present in i.MX53
+ (d) "fsl,imx6q-vpu" for CODA960 present in i.MX6q
- reg: should be register base and length as documented in the
SoC reference manual
- interrupts : Should contain the VPU interrupt. For CODA960,
diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.txt b/Documentation/devicetree/bindings/media/i2c/adv7604.txt
index 9cbd92eb5d05..dcf57e7c60eb 100644
--- a/Documentation/devicetree/bindings/media/i2c/adv7604.txt
+++ b/Documentation/devicetree/bindings/media/i2c/adv7604.txt
@@ -13,7 +13,11 @@ Required Properties:
- "adi,adv7611" for the ADV7611
- "adi,adv7612" for the ADV7612
- - reg: I2C slave address
+ - reg: I2C slave addresses
+ The ADV76xx has up to thirteen 256-byte maps that can be accessed via the
+ main I2C ports. Each map has it own I2C address and acts as a standard
+ slave device on the I2C bus. The main address is mandatory, others are
+ optional and revert to defaults if not specified.
- hpd-gpios: References to the GPIOs that control the HDMI hot-plug
detection pins, one per HDMI input. The active flag indicates the GPIO
@@ -35,6 +39,11 @@ Optional Properties:
- reset-gpios: Reference to the GPIO connected to the device's reset pin.
- default-input: Select which input is selected after reset.
+ - reg-names : Names of maps with programmable addresses.
+ It can contain any map needing a non-default address.
+ Possible maps names are :
+ "main", "avlink", "cec", "infoframe", "esdp", "dpp", "afe",
+ "rep", "edid", "hdmi", "test", "cp", "vdp"
Optional Endpoint Properties:
@@ -52,7 +61,12 @@ Example:
hdmi_receiver@4c {
compatible = "adi,adv7611";
- reg = <0x4c>;
+ /*
+ * The edid page will be accessible @ 0x66 on the I2C bus. All
+ * other maps will retain their default addresses.
+ */
+ reg = <0x4c>, <0x66>;
+ reg-names "main", "edid";
reset-gpios = <&ioexp 0 GPIO_ACTIVE_LOW>;
hpd-gpios = <&ioexp 2 GPIO_ACTIVE_HIGH>;
diff --git a/Documentation/devicetree/bindings/media/i2c/ov2685.txt b/Documentation/devicetree/bindings/media/i2c/ov2685.txt
new file mode 100644
index 000000000000..625c4a8c0d53
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ov2685.txt
@@ -0,0 +1,41 @@
+* Omnivision OV2685 MIPI CSI-2 sensor
+
+Required Properties:
+- compatible: shall be "ovti,ov2685"
+- clocks: reference to the xvclk input clock
+- clock-names: shall be "xvclk"
+- avdd-supply: Analog voltage supply, 2.8 volts
+- dovdd-supply: Digital I/O voltage supply, 1.8 volts
+- dvdd-supply: Digital core voltage supply, 1.8 volts
+- reset-gpios: Low active reset gpio
+
+The device node shall contain one 'port' child node with an
+'endpoint' subnode for its digital output video port,
+in accordance with the video interface bindings defined in
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+The endpoint optional property 'data-lanes' shall be "<1>".
+
+Example:
+&i2c7 {
+ ov2685: camera-sensor@3c {
+ compatible = "ovti,ov2685";
+ reg = <0x3c>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&clk_24m_cam>;
+
+ clocks = <&cru SCLK_TESTCLKOUT1>;
+ clock-names = "xvclk";
+
+ avdd-supply = <&pp2800_cam>;
+ dovdd-supply = <&pp1800>;
+ dvdd-supply = <&pp1800>;
+ reset-gpios = <&gpio2 3 GPIO_ACTIVE_LOW>;
+
+ port {
+ ucam_out: endpoint {
+ remote-endpoint = <&mipi_in_ucam>;
+ data-lanes = <1>;
+ };
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/media/i2c/ov5695.txt b/Documentation/devicetree/bindings/media/i2c/ov5695.txt
new file mode 100644
index 000000000000..640a63717d96
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ov5695.txt
@@ -0,0 +1,41 @@
+* Omnivision OV5695 MIPI CSI-2 sensor
+
+Required Properties:
+- compatible: shall be "ovti,ov5695"
+- clocks: reference to the xvclk input clock
+- clock-names: shall be "xvclk"
+- avdd-supply: Analog voltage supply, 2.8 volts
+- dovdd-supply: Digital I/O voltage supply, 1.8 volts
+- dvdd-supply: Digital core voltage supply, 1.2 volts
+- reset-gpios: Low active reset gpio
+
+The device node shall contain one 'port' child node with an
+'endpoint' subnode for its digital output video port,
+in accordance with the video interface bindings defined in
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+The endpoint optional property 'data-lanes' shall be "<1 2>".
+
+Example:
+&i2c7 {
+ ov5695: camera-sensor@36 {
+ compatible = "ovti,ov5695";
+ reg = <0x36>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&clk_24m_cam>;
+
+ clocks = <&cru SCLK_TESTCLKOUT1>;
+ clock-names = "xvclk";
+
+ avdd-supply = <&pp2800_cam>;
+ dovdd-supply = <&pp1800>;
+ dvdd-supply = <&pp1250_cam>;
+ reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
+
+ port {
+ wcam_out: endpoint {
+ remote-endpoint = <&mipi_in_wcam>;
+ data-lanes = <1 2>;
+ };
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/media/i2c/ov7670.txt b/Documentation/devicetree/bindings/media/i2c/ov7670.txt
index 826b6563b009..2c972a56f3cb 100644
--- a/Documentation/devicetree/bindings/media/i2c/ov7670.txt
+++ b/Documentation/devicetree/bindings/media/i2c/ov7670.txt
@@ -9,14 +9,21 @@ Required Properties:
- clocks: reference to the xclk input clock.
- clock-names: should be "xclk".
+Required Endpoint Properties:
+- hsync-active: active state of the HSYNC signal, 0/1 for LOW/HIGH respectively.
+- vsync-active: active state of the VSYNC signal, 0/1 for LOW/HIGH respectively.
+
Optional Properties:
- reset-gpios: reference to the GPIO connected to the resetb pin, if any.
Active is low.
- powerdown-gpios: reference to the GPIO connected to the pwdn pin, if any.
Active is high.
+- ov7670,pclk-hb-disable: a boolean property to suppress pixel clock output
+ signal during horizontal blankings.
-The device node must contain one 'port' child node for its digital output
-video port, in accordance with the video interface bindings defined in
+The device node must contain one 'port' child node with one 'endpoint' child
+sub-node for its digital output video port, in accordance with the video
+interface bindings defined in:
Documentation/devicetree/bindings/media/video-interfaces.txt.
Example:
@@ -34,8 +41,13 @@ Example:
assigned-clocks = <&pck0>;
assigned-clock-rates = <25000000>;
+ ov7670,pclk-hb-disable;
+
port {
ov7670_0: endpoint {
+ hsync-active = <0>;
+ vsync-active = <0>;
+
remote-endpoint = <&isi_0>;
};
};
diff --git a/Documentation/devicetree/bindings/media/i2c/ov9650.txt b/Documentation/devicetree/bindings/media/i2c/ov9650.txt
new file mode 100644
index 000000000000..506dfc52872a
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ov9650.txt
@@ -0,0 +1,36 @@
+* Omnivision OV9650/OV9652 CMOS sensor
+
+Required Properties:
+- compatible: shall be one of
+ "ovti,ov9650"
+ "ovti,ov9652"
+- clocks: reference to the xvclk input clock.
+
+Optional Properties:
+- reset-gpios: reference to the GPIO connected to the resetb pin, if any.
+ Active is high.
+- powerdown-gpios: reference to the GPIO connected to the pwdn pin, if any.
+ Active is high.
+
+The device node shall contain one 'port' child node with one child 'endpoint'
+subnode for its digital output video port, in accordance with the video
+interface bindings defined in Documentation/devicetree/bindings/media/
+video-interfaces.txt.
+
+Example:
+
+&i2c0 {
+ ov9650: camera@30 {
+ compatible = "ovti,ov9650";
+ reg = <0x30>;
+ reset-gpios = <&axi_gpio_0 0 GPIO_ACTIVE_HIGH>;
+ powerdown-gpios = <&axi_gpio_0 1 GPIO_ACTIVE_HIGH>;
+ clocks = <&xclk>;
+
+ port {
+ ov9650_0: endpoint {
+ remote-endpoint = <&vcap1_in0>;
+ };
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/media/i2c/tda1997x.txt b/Documentation/devicetree/bindings/media/i2c/tda1997x.txt
new file mode 100644
index 000000000000..e76167999d76
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/tda1997x.txt
@@ -0,0 +1,178 @@
+Device-Tree bindings for the NXP TDA1997x HDMI receiver
+
+The TDA19971/73 are HDMI video receivers.
+
+The TDA19971 Video port output pins can be used as follows:
+ - RGB 8bit per color (24 bits total): R[11:4] B[11:4] G[11:4]
+ - YUV444 8bit per color (24 bits total): Y[11:4] Cr[11:4] Cb[11:4]
+ - YUV422 semi-planar 8bit per component (16 bits total): Y[11:4] CbCr[11:4]
+ - YUV422 semi-planar 10bit per component (20 bits total): Y[11:2] CbCr[11:2]
+ - YUV422 semi-planar 12bit per component (24 bits total): - Y[11:0] CbCr[11:0]
+ - YUV422 BT656 8bit per component (8 bits total): YCbCr[11:4] (2-cycles)
+ - YUV422 BT656 10bit per component (10 bits total): YCbCr[11:2] (2-cycles)
+ - YUV422 BT656 12bit per component (12 bits total): YCbCr[11:0] (2-cycles)
+
+The TDA19973 Video port output pins can be used as follows:
+ - RGB 12bit per color (36 bits total): R[11:0] B[11:0] G[11:0]
+ - YUV444 12bit per color (36 bits total): Y[11:0] Cb[11:0] Cr[11:0]
+ - YUV422 semi-planar 12bit per component (24 bits total): Y[11:0] CbCr[11:0]
+ - YUV422 BT656 12bit per component (12 bits total): YCbCr[11:0] (2-cycles)
+
+The Video port output pins are mapped via 4-bit 'pin groups' allowing
+for a variety of connection possibilities including swapping pin order within
+pin groups. The video_portcfg device-tree property consists of register mapping
+pairs which map a chip-specific VP output register to a 4-bit pin group. If
+the pin group needs to be bit-swapped you can use the *_S pin-group defines.
+
+Required Properties:
+ - compatible :
+ - "nxp,tda19971" for the TDA19971
+ - "nxp,tda19973" for the TDA19973
+ - reg : I2C slave address
+ - interrupts : The interrupt number
+ - DOVDD-supply : Digital I/O supply
+ - DVDD-supply : Digital Core supply
+ - AVDD-supply : Analog supply
+ - nxp,vidout-portcfg : array of pairs mapping VP output pins to pin groups.
+
+Optional Properties:
+ - nxp,audout-format : DAI bus format: "i2s" or "spdif".
+ - nxp,audout-width : width of audio output data bus (1-4).
+ - nxp,audout-layout : data layout (0=AP0 used, 1=AP0/AP1/AP2/AP3 used).
+ - nxp,audout-mclk-fs : Multiplication factor between stream rate and codec
+ mclk.
+
+The port node shall contain one endpoint child node for its digital
+output video port, in accordance with the video interface bindings defined in
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Optional Endpoint Properties:
+ The following three properties are defined in video-interfaces.txt and
+ are valid for the output parallel bus endpoint:
+ - hsync-active: Horizontal synchronization polarity. Defaults to active high.
+ - vsync-active: Vertical synchronization polarity. Defaults to active high.
+ - data-active: Data polarity. Defaults to active high.
+
+Examples:
+ - VP[15:0] connected to IMX6 CSI_DATA[19:4] for 16bit YUV422
+ 16bit I2S layout0 with a 128*fs clock (A_WS, AP0, A_CLK pins)
+ hdmi-receiver@48 {
+ compatible = "nxp,tda19971";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_tda1997x>;
+ reg = <0x48>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+ DOVDD-supply = <&reg_3p3v>;
+ AVDD-supply = <&reg_1p8v>;
+ DVDD-supply = <&reg_1p8v>;
+ /* audio */
+ #sound-dai-cells = <0>;
+ nxp,audout-format = "i2s";
+ nxp,audout-layout = <0>;
+ nxp,audout-width = <16>;
+ nxp,audout-mclk-fs = <128>;
+ /*
+ * The 8bpp YUV422 semi-planar mode outputs CbCr[11:4]
+ * and Y[11:4] across 16bits in the same pixclk cycle.
+ */
+ nxp,vidout-portcfg =
+ /* Y[11:8]<->VP[15:12]<->CSI_DATA[19:16] */
+ < TDA1997X_VP24_V15_12 TDA1997X_G_Y_11_8 >,
+ /* Y[7:4]<->VP[11:08]<->CSI_DATA[15:12] */
+ < TDA1997X_VP24_V11_08 TDA1997X_G_Y_7_4 >,
+ /* CbCc[11:8]<->VP[07:04]<->CSI_DATA[11:8] */
+ < TDA1997X_VP24_V07_04 TDA1997X_R_CR_CBCR_11_8 >,
+ /* CbCr[7:4]<->VP[03:00]<->CSI_DATA[7:4] */
+ < TDA1997X_VP24_V03_00 TDA1997X_R_CR_CBCR_7_4 >;
+
+ port {
+ tda1997x_to_ipu1_csi0_mux: endpoint {
+ remote-endpoint = <&ipu1_csi0_mux_from_parallel_sensor>;
+ bus-width = <16>;
+ hsync-active = <1>;
+ vsync-active = <1>;
+ data-active = <1>;
+ };
+ };
+ };
+ - VP[15:8] connected to IMX6 CSI_DATA[19:12] for 8bit BT656
+ 16bit I2S layout0 with a 128*fs clock (A_WS, AP0, A_CLK pins)
+ hdmi-receiver@48 {
+ compatible = "nxp,tda19971";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_tda1997x>;
+ reg = <0x48>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+ DOVDD-supply = <&reg_3p3v>;
+ AVDD-supply = <&reg_1p8v>;
+ DVDD-supply = <&reg_1p8v>;
+ /* audio */
+ #sound-dai-cells = <0>;
+ nxp,audout-format = "i2s";
+ nxp,audout-layout = <0>;
+ nxp,audout-width = <16>;
+ nxp,audout-mclk-fs = <128>;
+ /*
+ * The 8bpp YUV422 semi-planar mode outputs CbCr[11:4]
+ * and Y[11:4] across 16bits in the same pixclk cycle.
+ */
+ nxp,vidout-portcfg =
+ /* Y[11:8]<->VP[15:12]<->CSI_DATA[19:16] */
+ < TDA1997X_VP24_V15_12 TDA1997X_G_Y_11_8 >,
+ /* Y[7:4]<->VP[11:08]<->CSI_DATA[15:12] */
+ < TDA1997X_VP24_V11_08 TDA1997X_G_Y_7_4 >,
+ /* CbCc[11:8]<->VP[07:04]<->CSI_DATA[11:8] */
+ < TDA1997X_VP24_V07_04 TDA1997X_R_CR_CBCR_11_8 >,
+ /* CbCr[7:4]<->VP[03:00]<->CSI_DATA[7:4] */
+ < TDA1997X_VP24_V03_00 TDA1997X_R_CR_CBCR_7_4 >;
+
+ port {
+ tda1997x_to_ipu1_csi0_mux: endpoint {
+ remote-endpoint = <&ipu1_csi0_mux_from_parallel_sensor>;
+ bus-width = <16>;
+ hsync-active = <1>;
+ vsync-active = <1>;
+ data-active = <1>;
+ };
+ };
+ };
+ - VP[15:8] connected to IMX6 CSI_DATA[19:12] for 8bit BT656
+ 16bit I2S layout0 with a 128*fs clock (A_WS, AP0, A_CLK pins)
+ hdmi-receiver@48 {
+ compatible = "nxp,tda19971";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_tda1997x>;
+ reg = <0x48>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+ DOVDD-supply = <&reg_3p3v>;
+ AVDD-supply = <&reg_1p8v>;
+ DVDD-supply = <&reg_1p8v>;
+ /* audio */
+ #sound-dai-cells = <0>;
+ nxp,audout-format = "i2s";
+ nxp,audout-layout = <0>;
+ nxp,audout-width = <16>;
+ nxp,audout-mclk-fs = <128>;
+ /*
+ * The 8bpp BT656 mode outputs YCbCr[11:4] across 8bits over
+ * 2 pixclk cycles.
+ */
+ nxp,vidout-portcfg =
+ /* YCbCr[11:8]<->VP[15:12]<->CSI_DATA[19:16] */
+ < TDA1997X_VP24_V15_12 TDA1997X_R_CR_CBCR_11_8 >,
+ /* YCbCr[7:4]<->VP[11:08]<->CSI_DATA[15:12] */
+ < TDA1997X_VP24_V11_08 TDA1997X_R_CR_CBCR_7_4 >,
+
+ port {
+ tda1997x_to_ipu1_csi0_mux: endpoint {
+ remote-endpoint = <&ipu1_csi0_mux_from_parallel_sensor>;
+ bus-width = <16>;
+ hsync-active = <1>;
+ vsync-active = <1>;
+ data-active = <1>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/rcar_vin.txt b/Documentation/devicetree/bindings/media/rcar_vin.txt
index 19357d0bbe65..1ce7ff9449c5 100644
--- a/Documentation/devicetree/bindings/media/rcar_vin.txt
+++ b/Documentation/devicetree/bindings/media/rcar_vin.txt
@@ -56,7 +56,7 @@ Board setup example (vin1 composite video input)
------------------------------------------------
&i2c2 {
- status = "ok";
+ status = "okay";
pinctrl-0 = <&i2c2_pins>;
pinctrl-names = "default";
@@ -79,7 +79,7 @@ Board setup example (vin1 composite video input)
pinctrl-0 = <&vin1_pins>;
pinctrl-names = "default";
- status = "ok";
+ status = "okay";
port {
#address-cells = <1>;
diff --git a/Documentation/devicetree/bindings/media/renesas,ceu.txt b/Documentation/devicetree/bindings/media/renesas,ceu.txt
new file mode 100644
index 000000000000..3fc66dfb192c
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/renesas,ceu.txt
@@ -0,0 +1,81 @@
+Renesas Capture Engine Unit (CEU)
+----------------------------------------------
+
+The Capture Engine Unit is the image capture interface found in the Renesas
+SH Mobile and RZ SoCs.
+
+The interface supports a single parallel input with data bus width of 8 or 16
+bits.
+
+Required properties:
+- compatible: Shall be "renesas,r7s72100-ceu" for CEU units found in RZ/A1H
+ and RZ/A1M SoCs.
+- reg: Registers address base and size.
+- interrupts: The interrupt specifier.
+
+The CEU supports a single parallel input and should contain a single 'port'
+subnode with a single 'endpoint'. Connection to input devices are modeled
+according to the video interfaces OF bindings specified in:
+Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Optional endpoint properties applicable to parallel input bus described in
+the above mentioned "video-interfaces.txt" file are supported.
+
+- hsync-active: Active state of the HSYNC signal, 0/1 for LOW/HIGH respectively.
+ If property is not present, default is active high.
+- vsync-active: Active state of the VSYNC signal, 0/1 for LOW/HIGH respectively.
+ If property is not present, default is active high.
+
+Example:
+
+The example describes the connection between the Capture Engine Unit and an
+OV7670 image sensor connected to i2c1 interface.
+
+ceu: ceu@e8210000 {
+ reg = <0xe8210000 0x209c>;
+ compatible = "renesas,r7s72100-ceu";
+ interrupts = <GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&vio_pins>;
+
+ status = "okay";
+
+ port {
+ ceu_in: endpoint {
+ remote-endpoint = <&ov7670_out>;
+
+ hsync-active = <1>;
+ vsync-active = <0>;
+ };
+ };
+};
+
+i2c1: i2c@fcfee400 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+
+ status = "okay";
+
+ clock-frequency = <100000>;
+
+ ov7670: camera@21 {
+ compatible = "ovti,ov7670";
+ reg = <0x21>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&vio_pins>;
+
+ reset-gpios = <&port3 11 GPIO_ACTIVE_LOW>;
+ powerdown-gpios = <&port3 12 GPIO_ACTIVE_HIGH>;
+
+ port {
+ ov7670_out: endpoint {
+ remote-endpoint = <&ceu_in>;
+
+ hsync-active = <1>;
+ vsync-active = <0>;
+ };
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/media/s5p-mfc.txt b/Documentation/devicetree/bindings/media/s5p-mfc.txt
index d3404b5d4d17..aa54c8159d9f 100644
--- a/Documentation/devicetree/bindings/media/s5p-mfc.txt
+++ b/Documentation/devicetree/bindings/media/s5p-mfc.txt
@@ -13,6 +13,7 @@ Required properties:
(c) "samsung,mfc-v7" for MFC v7 present in Exynos5420 SoC
(d) "samsung,mfc-v8" for MFC v8 present in Exynos5800 SoC
(e) "samsung,exynos5433-mfc" for MFC v8 present in Exynos5433 SoC
+ (f) "samsung,mfc-v10" for MFC v10 present in Exynos7880 SoC
- reg : Physical base address of the IP registers and length of memory
mapped region.
diff --git a/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt b/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt
new file mode 100644
index 000000000000..fc5aa263abe5
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt
@@ -0,0 +1,14 @@
+Sony CXD2880 DVB-T2/T tuner + demodulator driver SPI adapter
+
+Required properties:
+- compatible: Should be "sony,cxd2880".
+- reg: SPI chip select number for the device.
+- spi-max-frequency: Maximum bus speed, should be set to <55000000> (55MHz).
+
+Example:
+
+cxd2880@0 {
+ compatible = "sony,cxd2880";
+ reg = <0>; /* CE0 */
+ spi-max-frequency = <55000000>; /* 55MHz */
+};
diff --git a/Documentation/devicetree/bindings/media/sunxi-ir.txt b/Documentation/devicetree/bindings/media/sunxi-ir.txt
index 91648c569b1e..278098987edb 100644
--- a/Documentation/devicetree/bindings/media/sunxi-ir.txt
+++ b/Documentation/devicetree/bindings/media/sunxi-ir.txt
@@ -11,6 +11,8 @@ Required properties:
Optional properties:
- linux,rc-map-name: see rc.txt file in the same directory.
- resets : phandle + reset specifier pair
+- clock-frequency : IR Receiver clock frequency, in Hertz. Defaults to 8 MHz
+ if missing.
Example:
@@ -18,6 +20,7 @@ ir0: ir@1c21800 {
compatible = "allwinner,sun4i-a10-ir";
clocks = <&apb0_gates 6>, <&ir0_clk>;
clock-names = "apb", "ir";
+ clock-frequency = <3000000>;
resets = <&apb0_rst 1>;
interrupts = <0 5 1>;
reg = <0x01C21800 0x40>;
diff --git a/Documentation/devicetree/bindings/mfd/aspeed-lpc.txt b/Documentation/devicetree/bindings/mfd/aspeed-lpc.txt
index 514d82ced95b..69aadee00d5f 100644
--- a/Documentation/devicetree/bindings/mfd/aspeed-lpc.txt
+++ b/Documentation/devicetree/bindings/mfd/aspeed-lpc.txt
@@ -109,9 +109,50 @@ lpc: lpc@1e789000 {
};
};
+BMC Node Children
+==================
+
+
Host Node Children
==================
+LPC Host Interface Controller
+-------------------
+
+The LPC Host Interface Controller manages functions exposed to the host such as
+LPC firmware hub cycles, configuration of the LPC-to-AHB mapping, UART
+management and bus snoop configuration.
+
+Required properties:
+
+- compatible: One of:
+ "aspeed,ast2400-lpc-ctrl";
+ "aspeed,ast2500-lpc-ctrl";
+
+- reg: contains offset/length values of the host interface controller
+ memory regions
+
+- clocks: contains a phandle to the syscon node describing the clocks.
+ There should then be one cell representing the clock to use
+
+- memory-region: A phandle to a reserved_memory region to be used for the LPC
+ to AHB mapping
+
+- flash: A phandle to the SPI flash controller containing the flash to
+ be exposed over the LPC to AHB mapping
+
+Example:
+
+lpc-host@80 {
+ lpc_ctrl: lpc-ctrl@0 {
+ compatible = "aspeed,ast2500-lpc-ctrl";
+ reg = <0x0 0x80>;
+ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ memory-region = <&flash_memory>;
+ flash = <&spi>;
+ };
+};
+
LPC Host Controller
-------------------
diff --git a/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt b/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
index 594982c6b9f9..79bf352e659c 100644
--- a/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
+++ b/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
@@ -6,7 +6,11 @@ the definition of the PHY node in booting-without-of.txt for an example
of how to define a PHY.
Required properties:
- - reg : Offset and length of the register set for the device
+ - reg : Offset and length of the register set for the device, and optionally
+ the offset and length of the TBIPA register (TBI PHY address
+ register). If TBIPA register is not specified, the driver will
+ attempt to infer it from the register set specified (your mileage may
+ vary).
- compatible : Should define the compatible device type for the
mdio. Currently supported strings/devices are:
- "fsl,gianfar-tbi"
diff --git a/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt b/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt
index f162c72b4e36..729f6747813b 100644
--- a/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt
+++ b/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt
@@ -11,17 +11,32 @@ Required properties:
"fsl,imx6ul-ocotp" (i.MX6UL),
"fsl,imx7d-ocotp" (i.MX7D/S),
followed by "syscon".
+- #address-cells : Should be 1
+- #size-cells : Should be 1
- reg: Should contain the register base and length.
- clocks: Should contain a phandle pointing to the gated peripheral clock.
Optional properties:
- read-only: disable write access
-Example:
+Optional Child nodes:
+
+- Data cells of ocotp:
+ Detailed bindings are described in bindings/nvmem/nvmem.txt
+Example:
ocotp: ocotp@21bc000 {
- compatible = "fsl,imx6q-ocotp", "syscon";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,imx6sx-ocotp", "syscon";
reg = <0x021bc000 0x4000>;
- clocks = <&clks IMX6QDL_CLK_IIM>;
- read-only;
+ clocks = <&clks IMX6SX_CLK_OCOTP>;
+
+ tempmon_calib: calib@38 {
+ reg = <0x38 4>;
+ };
+
+ tempmon_temp_grade: temp-grade@20 {
+ reg = <0x20 4>;
+ };
};
diff --git a/Documentation/devicetree/bindings/nvmem/snvs-lpgpr.txt b/Documentation/devicetree/bindings/nvmem/snvs-lpgpr.txt
index 20bc49b49799..3cb170896658 100644
--- a/Documentation/devicetree/bindings/nvmem/snvs-lpgpr.txt
+++ b/Documentation/devicetree/bindings/nvmem/snvs-lpgpr.txt
@@ -1,5 +1,5 @@
Device tree bindings for Low Power General Purpose Register found in i.MX6Q/D
-Secure Non-Volatile Storage.
+and i.MX7 Secure Non-Volatile Storage.
This DT node should be represented as a sub-node of a "syscon",
"simple-mfd" node.
@@ -8,6 +8,7 @@ Required properties:
- compatible: should be one of the fallowing variants:
"fsl,imx6q-snvs-lpgpr" for Freescale i.MX6Q/D/DL/S
"fsl,imx6ul-snvs-lpgpr" for Freescale i.MX6UL
+ "fsl,imx7d-snvs-lpgpr" for Freescale i.MX7D/S
Example:
snvs: snvs@020cc000 {
diff --git a/Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt b/Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
index a105494a0fc9..b84a02ebffdf 100644
--- a/Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
+++ b/Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
@@ -6,6 +6,10 @@ Required properties:
- #phys-cells: must be 0 (see phy-bindings.txt in this directory)
Optional properties:
+- clocks: a phandle to the clock of this PHY
+- clock-names: must be "phy"
+- resets: a phandle to the reset line of this PHY
+- reset-names: must be "phy"
- phy-supply: see phy-bindings.txt in this directory
diff --git a/Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt b/Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt
new file mode 100644
index 000000000000..114947e1de3d
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt
@@ -0,0 +1,31 @@
+* Amlogic Meson GXL and GXM USB3 PHY and OTG detection binding
+
+Required properties:
+- compatible: Should be "amlogic,meson-gxl-usb3-phy"
+- #phys-cells: must be 0 (see phy-bindings.txt in this directory)
+- reg: The base address and length of the registers
+- interrupts: the interrupt specifier for the OTG detection
+- clocks: phandles to the clocks for
+ - the USB3 PHY
+ - and peripheral mode/OTG detection
+- clock-names: must contain "phy" and "peripheral"
+- resets: phandle to the reset lines for:
+ - the USB3 PHY and
+ - peripheral mode/OTG detection
+- reset-names: must contain "phy" and "peripheral"
+
+Optional properties:
+- phy-supply: see phy-bindings.txt in this directory
+
+
+Example:
+ usb3_phy0: phy@78080 {
+ compatible = "amlogic,meson-gxl-usb3-phy";
+ #phy-cells = <0>;
+ reg = <0x0 0x78080 0x0 0x20>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clkc CLKID_USB_OTG>, <&clkc_AO CLKID_AO_CEC_32K>;
+ clock-names = "phy", "peripheral";
+ resets = <&reset RESET_USB_OTG>, <&reset RESET_USB_OTG>;
+ reset-names = "phy", "peripheral";
+ };
diff --git a/Documentation/devicetree/bindings/phy/phy-hi3798cv200-combphy.txt b/Documentation/devicetree/bindings/phy/phy-hi3798cv200-combphy.txt
new file mode 100644
index 000000000000..17b0c761370a
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-hi3798cv200-combphy.txt
@@ -0,0 +1,59 @@
+HiSilicon STB PCIE/SATA/USB3 PHY
+
+Required properties:
+- compatible: Should be "hisilicon,hi3798cv200-combphy"
+- reg: Should be the address space for COMBPHY configuration and state
+ registers in peripheral controller, e.g. PERI_COMBPHY0_CFG and
+ PERI_COMBPHY0_STATE for COMBPHY0 Hi3798CV200 SoC.
+- #phy-cells: Should be 1. The cell number is used to select the phy mode
+ as defined in <dt-bindings/phy/phy.h>.
+- clocks: The phandle to clock provider and clock specifier pair.
+- resets: The phandle to reset controller and reset specifier pair.
+
+Refer to phy/phy-bindings.txt for the generic PHY binding properties.
+
+Optional properties:
+- hisilicon,fixed-mode: If the phy device doesn't support mode select
+ but a fixed mode setting, the property should be present to specify
+ the particular mode.
+- hisilicon,mode-select-bits: If the phy device support mode select,
+ this property should be present to specify the register bits in
+ peripheral controller, as a 3 integers tuple:
+ <register_offset bit_shift bit_mask>.
+
+Notes:
+- Between hisilicon,fixed-mode and hisilicon,mode-select-bits, one and only
+ one of them should be present.
+- The device node should be a child of peripheral controller that contains
+ COMBPHY configuration/state and PERI_CTRL register used to select PHY mode.
+ Refer to arm/hisilicon/hisilicon.txt for the parent peripheral controller
+ bindings.
+
+Examples:
+
+perictrl: peripheral-controller@8a20000 {
+ compatible = "hisilicon,hi3798cv200-perictrl", "syscon",
+ "simple-mfd";
+ reg = <0x8a20000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x8a20000 0x1000>;
+
+ combphy0: phy@850 {
+ compatible = "hisilicon,hi3798cv200-combphy";
+ reg = <0x850 0x8>;
+ #phy-cells = <1>;
+ clocks = <&crg HISTB_COMBPHY0_CLK>;
+ resets = <&crg 0x188 4>;
+ hisilicon,fixed-mode = <PHY_TYPE_USB3>;
+ };
+
+ combphy1: phy@858 {
+ compatible = "hisilicon,hi3798cv200-combphy";
+ reg = <0x858 0x8>;
+ #phy-cells = <1>;
+ clocks = <&crg HISTB_COMBPHY1_CLK>;
+ resets = <&crg 0x188 12>;
+ hisilicon,mode-select-bits = <0x0008 11 (0x3 << 11)>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/phy/phy-hisi-inno-usb2.txt b/Documentation/devicetree/bindings/phy/phy-hisi-inno-usb2.txt
new file mode 100644
index 000000000000..0d70c8341095
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-hisi-inno-usb2.txt
@@ -0,0 +1,71 @@
+Device tree bindings for HiSilicon INNO USB2 PHY
+
+Required properties:
+- compatible: Should be one of the following strings:
+ "hisilicon,inno-usb2-phy",
+ "hisilicon,hi3798cv200-usb2-phy".
+- reg: Should be the address space for PHY configuration register in peripheral
+ controller, e.g. PERI_USB0 for USB 2.0 PHY01 on Hi3798CV200 SoC.
+- clocks: The phandle and clock specifier pair for INNO USB2 PHY device
+ reference clock.
+- resets: The phandle and reset specifier pair for INNO USB2 PHY device reset
+ signal.
+- #address-cells: Must be 1.
+- #size-cells: Must be 0.
+
+The INNO USB2 PHY device should be a child node of peripheral controller that
+contains the PHY configuration register, and each device suppports up to 2 PHY
+ports which are represented as child nodes of INNO USB2 PHY device.
+
+Required properties for PHY port node:
+- reg: The PHY port instance number.
+- #phy-cells: Defined by generic PHY bindings. Must be 0.
+- resets: The phandle and reset specifier pair for PHY port reset signal.
+
+Refer to phy/phy-bindings.txt for the generic PHY binding properties
+
+Example:
+
+perictrl: peripheral-controller@8a20000 {
+ compatible = "hisilicon,hi3798cv200-perictrl", "simple-mfd";
+ reg = <0x8a20000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x8a20000 0x1000>;
+
+ usb2_phy1: usb2-phy@120 {
+ compatible = "hisilicon,hi3798cv200-usb2-phy";
+ reg = <0x120 0x4>;
+ clocks = <&crg HISTB_USB2_PHY1_REF_CLK>;
+ resets = <&crg 0xbc 4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ usb2_phy1_port0: phy@0 {
+ reg = <0>;
+ #phy-cells = <0>;
+ resets = <&crg 0xbc 8>;
+ };
+
+ usb2_phy1_port1: phy@1 {
+ reg = <1>;
+ #phy-cells = <0>;
+ resets = <&crg 0xbc 9>;
+ };
+ };
+
+ usb2_phy2: usb2-phy@124 {
+ compatible = "hisilicon,hi3798cv200-usb2-phy";
+ reg = <0x124 0x4>;
+ clocks = <&crg HISTB_USB2_PHY2_REF_CLK>;
+ resets = <&crg 0xbc 6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ usb2_phy2_port0: phy@0 {
+ reg = <0>;
+ #phy-cells = <0>;
+ resets = <&crg 0xbc 10>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/phy/phy-mapphone-mdm6600.txt b/Documentation/devicetree/bindings/phy/phy-mapphone-mdm6600.txt
new file mode 100644
index 000000000000..29427d4f047a
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-mapphone-mdm6600.txt
@@ -0,0 +1,29 @@
+Device tree binding documentation for Motorola Mapphone MDM6600 USB PHY
+
+Required properties:
+- compatible Must be "motorola,mapphone-mdm6600"
+- enable-gpios GPIO to enable the USB PHY
+- power-gpios GPIO to power on the device
+- reset-gpios GPIO to reset the device
+- motorola,mode-gpios Two GPIOs to configure MDM6600 USB start-up mode for
+ normal mode versus USB flashing mode
+- motorola,cmd-gpios Three GPIOs to control the power state of the MDM6600
+- motorola,status-gpios Three GPIOs to read the power state of the MDM6600
+
+Example:
+
+usb-phy {
+ compatible = "motorola,mapphone-mdm6600";
+ enable-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>;
+ power-gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>;
+ motorola,mode-gpios = <&gpio5 20 GPIO_ACTIVE_HIGH>,
+ <&gpio5 21 GPIO_ACTIVE_HIGH>;
+ motorola,cmd-gpios = <&gpio4 7 GPIO_ACTIVE_HIGH>,
+ <&gpio4 8 GPIO_ACTIVE_HIGH>,
+ <&gpio5 14 GPIO_ACTIVE_HIGH>;
+ motorola,status-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>,
+ <&gpio2 21 GPIO_ACTIVE_HIGH>,
+ <&gpio2 23 GPIO_ACTIVE_HIGH>;
+ #phy-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/phy/phy-mtk-tphy.txt b/Documentation/devicetree/bindings/phy/phy-mtk-tphy.txt
index 41e09ed2ca70..0d34b2b4a6b7 100644
--- a/Documentation/devicetree/bindings/phy/phy-mtk-tphy.txt
+++ b/Documentation/devicetree/bindings/phy/phy-mtk-tphy.txt
@@ -27,6 +27,10 @@ Optional properties (controller (parent) node):
- reg : offset and length of register shared by multiple ports,
exclude port's private register. It is needed on mt2701
and mt8173, but not on mt2712.
+ - mediatek,src-ref-clk-mhz : frequency of reference clock for slew rate
+ calibrate
+ - mediatek,src-coef : coefficient for slew rate calibrate, depends on
+ SoC process
Required properties (port (child) node):
- reg : address and length of the register set for the port.
diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
index 6ea867e3176f..960da7fcaa9e 100644
--- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
+++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
@@ -14,25 +14,9 @@ Required properties:
- resets : a list of phandle + reset specifier pairs
- reset-names : string reset name, must be:
"uphy", "uphy-pipe", "uphy-tcphy"
- - extcon : extcon specifier for the Power Delivery
-Note, there are 2 type-c phys for RK3399, and they are almost identical, except
-these registers(description below), every register node contains 3 sections:
-offset, enable bit, write mask bit.
- - rockchip,typec-conn-dir : the register of type-c connector direction,
- for type-c phy0, it must be <0xe580 0 16>;
- for type-c phy1, it must be <0xe58c 0 16>;
- - rockchip,usb3tousb2-en : the register of type-c force usb3 to usb2 enable
- control.
- for type-c phy0, it must be <0xe580 3 19>;
- for type-c phy1, it must be <0xe58c 3 19>;
- - rockchip,external-psm : the register of type-c phy external psm clock
- selection.
- for type-c phy0, it must be <0xe588 14 30>;
- for type-c phy1, it must be <0xe594 14 30>;
- - rockchip,pipe-status : the register of type-c phy pipe status.
- for type-c phy0, it must be <0xe5c0 0 0>;
- for type-c phy1, it must be <0xe5c0 16 16>;
+Optional properties:
+ - extcon : extcon specifier for the Power Delivery
Required nodes : a sub-node is required for each port the phy provides.
The sub-node name is used to identify dp or usb3 port,
@@ -43,6 +27,13 @@ Required nodes : a sub-node is required for each port the phy provides.
Required properties (port (child) node):
- #phy-cells : must be 0, See ./phy-bindings.txt for details.
+Deprecated properties, do not use in new device tree sources, these
+properties are determined by the compatible value:
+ - rockchip,typec-conn-dir
+ - rockchip,usb3tousb2-en
+ - rockchip,external-psm
+ - rockchip,pipe-status
+
Example:
tcphy0: phy@ff7c0000 {
compatible = "rockchip,rk3399-typec-phy";
@@ -58,10 +49,6 @@ Example:
<&cru SRST_UPHY0_PIPE_L00>,
<&cru SRST_P_UPHY0_TCPHY>;
reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
- rockchip,typec-conn-dir = <0xe580 0 16>;
- rockchip,usb3tousb2-en = <0xe580 3 19>;
- rockchip,external-psm = <0xe588 14 30>;
- rockchip,pipe-status = <0xe5c0 0 0>;
tcphy0_dp: dp-port {
#phy-cells = <0>;
@@ -86,10 +73,6 @@ Example:
<&cru SRST_UPHY1_PIPE_L00>,
<&cru SRST_P_UPHY1_TCPHY>;
reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
- rockchip,typec-conn-dir = <0xe58c 0 16>;
- rockchip,usb3tousb2-en = <0xe58c 3 19>;
- rockchip,external-psm = <0xe594 14 30>;
- rockchip,pipe-status = <0xe5c0 16 16>;
tcphy1_dp: dp-port {
#phy-cells = <0>;
diff --git a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt
new file mode 100644
index 000000000000..725ae71ae653
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt
@@ -0,0 +1,73 @@
+STMicroelectronics STM32 USB HS PHY controller
+
+The STM32 USBPHYC block contains a dual port High Speed UTMI+ PHY and a UTMI
+switch. It controls PHY configuration and status, and the UTMI+ switch that
+selects either OTG or HOST controller for the second PHY port. It also sets
+PLL configuration.
+
+USBPHYC
+ |_ PLL
+ |
+ |_ PHY port#1 _________________ HOST controller
+ | _ |
+ | / 1|________________|
+ |_ PHY port#2 ----| |________________
+ | \_0| |
+ |_ UTMI switch_______| OTG controller
+
+
+Phy provider node
+=================
+
+Required properties:
+- compatible: must be "st,stm32mp1-usbphyc"
+- reg: address and length of the usb phy control register set
+- clocks: phandle + clock specifier for the PLL phy clock
+- #address-cells: number of address cells for phys sub-nodes, must be <1>
+- #size-cells: number of size cells for phys sub-nodes, must be <0>
+
+Optional properties:
+- assigned-clocks: phandle + clock specifier for the PLL phy clock
+- assigned-clock-parents: the PLL phy clock parent
+- resets: phandle + reset specifier
+
+Required nodes: one sub-node per port the controller provides.
+
+Phy sub-nodes
+==============
+
+Required properties:
+- reg: phy port index
+- phy-supply: phandle to the regulator providing 3V3 power to the PHY,
+ see phy-bindings.txt in the same directory.
+- vdda1v1-supply: phandle to the regulator providing 1V1 power to the PHY
+- vdda1v8-supply: phandle to the regulator providing 1V8 power to the PHY
+- #phy-cells: see phy-bindings.txt in the same directory, must be <0> for PHY
+ port#1 and must be <1> for PHY port#2, to select USB controller
+
+
+Example:
+ usbphyc: usb-phy@5a006000 {
+ compatible = "st,stm32mp1-usbphyc";
+ reg = <0x5a006000 0x1000>;
+ clocks = <&rcc_clk USBPHY_K>;
+ resets = <&rcc_rst USBPHY_R>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ usbphyc_port0: usb-phy@0 {
+ reg = <0>;
+ phy-supply = <&vdd_usb>;
+ vdda1v1-supply = <&reg11>;
+ vdda1v8-supply = <&reg18>
+ #phy-cells = <0>;
+ };
+
+ usbphyc_port1: usb-phy@1 {
+ reg = <1>;
+ phy-supply = <&vdd_usb>;
+ vdda1v1-supply = <&reg11>;
+ vdda1v8-supply = <&reg18>
+ #phy-cells = <1>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
index b6a9f2b92bab..dcf1b8f691d5 100644
--- a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
+++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
@@ -8,7 +8,8 @@ Required properties:
- compatible: compatible list, contains:
"qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074
"qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
- "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996.
+ "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996,
+ "qcom,qmp-v3-usb3-phy" for USB3 QMP V3 phy.
- reg: offset and length of register set for PHY's common serdes block.
@@ -25,10 +26,13 @@ Required properties:
- clock-names: "cfg_ahb" for phy config clock,
"aux" for phy aux clock,
"ref" for 19.2 MHz ref clk,
+ "com_aux" for phy common block aux clock,
For "qcom,msm8996-qmp-pcie-phy" must contain:
"aux", "cfg_ahb", "ref".
For "qcom,msm8996-qmp-usb3-phy" must contain:
"aux", "cfg_ahb", "ref".
+ For "qcom,qmp-v3-usb3-phy" must contain:
+ "aux", "cfg_ahb", "ref", "com_aux".
- resets: a list of phandles and reset controller specifier pairs,
one for each entry in reset-names.
diff --git a/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
index aa0fcb05acb3..42c97426836e 100644
--- a/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
+++ b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
@@ -4,7 +4,10 @@ Qualcomm QUSB2 phy controller
QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
Required properties:
- - compatible: compatible list, contains "qcom,msm8996-qusb2-phy".
+ - compatible: compatible list, contains
+ "qcom,msm8996-qusb2-phy" for 14nm PHY on msm8996,
+ "qcom,qusb2-v2-phy" for QUSB2 V2 PHY.
+
- reg: offset and length of the PHY register set.
- #phy-cells: must be 0.
diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
index 99b651b33110..dbd137c079e2 100644
--- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
+++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
@@ -8,6 +8,8 @@ Required properties:
SoC.
"renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796
SoC.
+ "renesas,usb2-phy-r8a77965" if the device is a part of an
+ R8A77965 SoC.
"renesas,usb2-phy-r8a77995" if the device is a part of an
R8A77995 SoC.
"renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device.
diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt
index f94cea48f6b1..47dd296ecead 100644
--- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt
+++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt
@@ -11,6 +11,8 @@ Required properties:
SoC.
"renesas,r8a7796-usb3-phy" if the device is a part of an R8A7796
SoC.
+ "renesas,r8a77965-usb3-phy" if the device is a part of an
+ R8A77965 SoC.
"renesas,rcar-gen3-usb3-phy" for a generic R-Car Gen3 compatible
device.
diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
index c1ce5a0a652e..07ca4ec4a745 100644
--- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
+++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
@@ -11,6 +11,7 @@ Required properties:
* allwinner,sun8i-a33-usb-phy
* allwinner,sun8i-a83t-usb-phy
* allwinner,sun8i-h3-usb-phy
+ * allwinner,sun8i-r40-usb-phy
* allwinner,sun8i-v3s-usb-phy
* allwinner,sun50i-a64-usb-phy
- reg : a list of offset + length pairs
diff --git a/Documentation/devicetree/bindings/rng/imx-rngc.txt b/Documentation/devicetree/bindings/rng/imx-rng.txt
index 93c7174a7bed..405c2b00ccb0 100644
--- a/Documentation/devicetree/bindings/rng/imx-rngc.txt
+++ b/Documentation/devicetree/bindings/rng/imx-rng.txt
@@ -1,15 +1,14 @@
-Freescale RNGC (Random Number Generator Version C)
-
-The driver also supports version B, which is mostly compatible
-to version C.
+Freescale RNGA/RNGB/RNGC (Random Number Generator Versions A, B and C)
Required properties:
- compatible : should be one of
+ "fsl,imx21-rnga"
+ "fsl,imx31-rnga" (backward compatible with "fsl,imx21-rnga")
"fsl,imx25-rngb"
"fsl,imx35-rngc"
- reg : offset and length of the register set of this block
-- interrupts : the interrupt number for the RNGC block
-- clocks : the RNGC clk source
+- interrupts : the interrupt number for the RNG block
+- clocks : the RNG clk source
Example:
diff --git a/Documentation/devicetree/bindings/rng/ks-sa-rng.txt b/Documentation/devicetree/bindings/rng/ks-sa-rng.txt
new file mode 100644
index 000000000000..b7a65b487901
--- /dev/null
+++ b/Documentation/devicetree/bindings/rng/ks-sa-rng.txt
@@ -0,0 +1,21 @@
+Keystone SoC Hardware Random Number Generator(HWRNG) Module
+
+On Keystone SoCs HWRNG module is a submodule of the Security Accelerator.
+
+- compatible: should be "ti,keystone-rng"
+- ti,syscon-sa-cfg: phandle to syscon node of the SA configuration registers.
+ This registers are shared between hwrng and crypto drivers.
+- clocks: phandle to the reference clocks for the subsystem
+- clock-names: functional clock name. Should be set to "fck"
+- reg: HWRNG module register space
+
+Example:
+/* K2HK */
+
+rng@24000 {
+ compatible = "ti,keystone-rng";
+ ti,syscon-sa-cfg = <&sa_config>;
+ clocks = <&clksa>;
+ clock-names = "fck";
+ reg = <0x24000 0x1000>;
+};
diff --git a/Documentation/devicetree/bindings/rng/omap_rng.txt b/Documentation/devicetree/bindings/rng/omap_rng.txt
index 9cf7876ab434..ea434ce50f36 100644
--- a/Documentation/devicetree/bindings/rng/omap_rng.txt
+++ b/Documentation/devicetree/bindings/rng/omap_rng.txt
@@ -13,7 +13,12 @@ Required properties:
- interrupts : the interrupt number for the RNG module.
Used for "ti,omap4-rng" and "inside-secure,safexcel-eip76"
- clocks: the trng clock source. Only mandatory for the
- "inside-secure,safexcel-eip76" compatible.
+ "inside-secure,safexcel-eip76" compatible, the second clock is
+ needed for the Armada 7K/8K SoCs
+- clock-names: mandatory if there is a second clock, in this case the
+ name must be "core" for the first clock and "reg" for the second
+ one
+
Example:
/* AM335x */
diff --git a/Documentation/devicetree/bindings/rng/st,stm32-rng.txt b/Documentation/devicetree/bindings/rng/st,stm32-rng.txt
index 47f04176f93b..1dfa7d51e006 100644
--- a/Documentation/devicetree/bindings/rng/st,stm32-rng.txt
+++ b/Documentation/devicetree/bindings/rng/st,stm32-rng.txt
@@ -11,6 +11,10 @@ Required properties:
- interrupts : The designated IRQ line for the RNG
- clocks : The clock needed to enable the RNG
+Optional properties:
+- resets : The reset to properly start RNG
+- clock-error-detect : Enable the clock detection management
+
Example:
rng: rng@50060800 {
diff --git a/Documentation/devicetree/bindings/serial/8250.txt b/Documentation/devicetree/bindings/serial/8250.txt
index dad3b2ec66d4..aeb6db4e35c3 100644
--- a/Documentation/devicetree/bindings/serial/8250.txt
+++ b/Documentation/devicetree/bindings/serial/8250.txt
@@ -24,6 +24,7 @@ Required properties:
- "ti,da830-uart"
- "aspeed,ast2400-vuart"
- "aspeed,ast2500-vuart"
+ - "nuvoton,npcm750-uart"
- "serial" if the port type is unknown.
- reg : offset and length of the register set for the device.
- interrupts : should contain uart interrupt.
diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
index cf504d0380ae..ad962f4ec3aa 100644
--- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
+++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
@@ -43,6 +43,8 @@ Required properties:
- "renesas,hscif-r8a7796" for R8A7796 (R-Car M3-W) HSCIF compatible UART.
- "renesas,scif-r8a77970" for R8A77970 (R-Car V3M) SCIF compatible UART.
- "renesas,hscif-r8a77970" for R8A77970 (R-Car V3M) HSCIF compatible UART.
+ - "renesas,scif-r8a77980" for R8A77980 (R-Car V3H) SCIF compatible UART.
+ - "renesas,hscif-r8a77980" for R8A77980 (R-Car V3H) HSCIF compatible UART.
- "renesas,scif-r8a77995" for R8A77995 (R-Car D3) SCIF compatible UART.
- "renesas,hscif-r8a77995" for R8A77995 (R-Car D3) HSCIF compatible UART.
- "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
index d150b04a6229..9d3efed55deb 100644
--- a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
+++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt
@@ -15,6 +15,8 @@ Required properties:
Optional properties:
- pinctrl: The reference on the pins configuration
- st,hw-flow-ctrl: bool flag to enable hardware flow control.
+- rs485-rts-delay, rs485-rx-during-tx, rs485-rts-active-low,
+ linux,rs485-enabled-at-boot-time: see rs485.txt.
- dmas: phandle(s) to DMA controller node(s). Refer to stm32-dma.txt
- dma-names: "rx" and/or "tx"
diff --git a/Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-vchiq.txt b/Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-vchiq.txt
new file mode 100644
index 000000000000..8dd7b3a7de65
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-vchiq.txt
@@ -0,0 +1,16 @@
+Broadcom VCHIQ firmware services
+
+Required properties:
+
+- compatible: Should be "brcm,bcm2835-vchiq"
+- reg: Physical base address and length of the doorbell register pair
+- interrupts: The interrupt number
+ See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
+
+Example:
+
+mailbox@7e00b840 {
+ compatible = "brcm,bcm2835-vchiq";
+ reg = <0x7e00b840 0xf>;
+ interrupts = <0 2>;
+};
diff --git a/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt b/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt
new file mode 100644
index 000000000000..9a8b631904fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt
@@ -0,0 +1,42 @@
+Amlogic Meson GX DWC3 USB SoC controller
+
+Required properties:
+- compatible: depending on the SoC this should contain one of:
+ * amlogic,meson-axg-dwc3
+ * amlogic,meson-gxl-dwc3
+- clocks: a handle for the "USB general" clock
+- clock-names: must be "usb_general"
+- resets: a handle for the shared "USB OTG" reset line
+- reset-names: must be "usb_otg"
+
+Required child node:
+A child node must exist to represent the core DWC3 IP block. The name of
+the node is not important. The content of the node is defined in dwc3.txt.
+
+PHY documentation is provided in the following places:
+- Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
+- Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt
+
+Example device nodes:
+ usb0: usb@ff500000 {
+ compatible = "amlogic,meson-axg-dwc3";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ clocks = <&clkc CLKID_USB>;
+ clock-names = "usb_general";
+ resets = <&reset RESET_USB_OTG>;
+ reset-names = "usb_otg";
+
+ dwc3: dwc3@ff500000 {
+ compatible = "snps,dwc3";
+ reg = <0x0 0xff500000 0x0 0x100000>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ dr_mode = "host";
+ maximum-speed = "high-speed";
+ snps,dis_u2_susphy_quirk;
+ phys = <&usb3_phy>, <&usb2_phy0>;
+ phy-names = "usb2-phy", "usb3-phy";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index 44e8bab159ad..0dbd3083e7dd 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -57,6 +57,22 @@ Optional properties:
- snps,quirk-frame-length-adjustment: Value for GFLADJ_30MHZ field of GFLADJ
register for post-silicon frame length adjustment when the
fladj_30mhz_sdbnd signal is invalid or incorrect.
+ - snps,rx-thr-num-pkt-prd: periodic ESS RX packet threshold count - host mode
+ only. Set this and rx-max-burst-prd to a valid,
+ non-zero value 1-16 (DWC_usb31 programming guide
+ section 1.2.4) to enable periodic ESS RX threshold.
+ - snps,rx-max-burst-prd: max periodic ESS RX burst size - host mode only. Set
+ this and rx-thr-num-pkt-prd to a valid, non-zero value
+ 1-16 (DWC_usb31 programming guide section 1.2.4) to
+ enable periodic ESS RX threshold.
+ - snps,tx-thr-num-pkt-prd: periodic ESS TX packet threshold count - host mode
+ only. Set this and tx-max-burst-prd to a valid,
+ non-zero value 1-16 (DWC_usb31 programming guide
+ section 1.2.3) to enable periodic ESS TX threshold.
+ - snps,tx-max-burst-prd: max periodic ESS TX burst size - host mode only. Set
+ this and tx-thr-num-pkt-prd to a valid, non-zero value
+ 1-16 (DWC_usb31 programming guide section 1.2.3) to
+ enable periodic ESS TX threshold.
- <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to be reallocated.
diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt
index 88d9f4a4b280..266c2d917a28 100644
--- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt
+++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt
@@ -32,7 +32,7 @@ Required properties:
"mcu_ck": mcu_bus clock for register access,
"dma_ck": dma_bus clock for data transfer by DMA
- - phys : a list of phandle + phy specifier pairs
+ - phys : see usb-hcd.txt in the current directory
Optional properties:
- wakeup-source : enable USB remote wakeup;
@@ -52,6 +52,9 @@ Optional properties:
See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
- imod-interval-ns: default interrupt moderation interval is 5000ns
+additionally the properties from usb-hcd.txt (in the current directory) are
+supported.
+
Example:
usb30: usb@11270000 {
compatible = "mediatek,mt8173-xhci";
diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt b/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt
index d589a1ef96a1..3382b5cb471d 100644
--- a/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt
+++ b/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt
@@ -17,7 +17,7 @@ Required properties:
- clock-names : must contain "sys_ck" for clock of controller,
the following clocks are optional:
"ref_ck", "mcu_ck" and "dam_ck";
- - phys : a list of phandle + phy specifier pairs
+ - phys : see usb-hcd.txt in the current directory
- dr_mode : should be one of "host", "peripheral" or "otg",
refer to usb/generic.txt
@@ -53,6 +53,9 @@ Optional properties:
- mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0,
bit1 for u3port1, ... etc;
+additionally the properties from usb-hcd.txt (in the current directory) are
+supported.
+
Sub-nodes:
The xhci should be added as subnode to mtu3 as shown in the following example
if host mode is enabled. The DT binding details of xhci can be found in:
diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
index 3efde12b5d68..0f1b75386207 100644
--- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
@@ -16,10 +16,12 @@ Optional properties:
- has-transaction-translator : boolean, set this if EHCI have a Transaction
Translator built into the root hub.
- clocks : a list of phandle + clock specifier pairs
- - phys : phandle + phy specifier pair
- - phy-names : "usb"
+ - phys : see usb-hcd.txt in the current directory
- resets : phandle + reset specifier pair
+additionally the properties from usb-hcd.txt (in the current directory) are
+supported.
+
Example (Sequoia 440EPx):
ehci@e0000300 {
compatible = "ibm,usb-ehci-440epx", "usb-ehci";
diff --git a/Documentation/devicetree/bindings/usb/usb-hcd.txt b/Documentation/devicetree/bindings/usb/usb-hcd.txt
new file mode 100644
index 000000000000..50529b838c9c
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/usb-hcd.txt
@@ -0,0 +1,9 @@
+Generic USB HCD (Host Controller Device) Properties
+
+Optional properties:
+- phys: a list of all USB PHYs on this HCD
+
+Example:
+ &usb1 {
+ phys = <&usb2_phy1>, <&usb3_phy1>;
+ };
diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt
index 09e70c875bc6..a8d2103d1f3d 100644
--- a/Documentation/devicetree/bindings/usb/usb-ohci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt
@@ -13,10 +13,12 @@ Optional properties:
- remote-wakeup-connected: remote wakeup is wired on the platform
- num-ports : u32, to override the detected port count
- clocks : a list of phandle + clock specifier pairs
-- phys : phandle + phy specifier pair
-- phy-names : "usb"
+- phys : see usb-hcd.txt in the current directory
- resets : a list of phandle + reset specifier pairs
+additionally the properties from usb-hcd.txt (in the current directory) are
+supported.
+
Example:
ohci0: usb@1c14400 {
diff --git a/Documentation/devicetree/bindings/usb/usb-uhci.txt b/Documentation/devicetree/bindings/usb/usb-uhci.txt
index 298133416c97..cc2e6f7d602e 100644
--- a/Documentation/devicetree/bindings/usb/usb-uhci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-uhci.txt
@@ -6,6 +6,9 @@ Required properties:
- reg : Should contain 1 register ranges(address and length)
- interrupts : UHCI controller interrupt
+additionally the properties from usb-hcd.txt (in the current directory) are
+supported.
+
Example:
uhci@d8007b00 {
diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt
index 1651483a7048..c4c00dff4b56 100644
--- a/Documentation/devicetree/bindings/usb/usb-xhci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt
@@ -33,6 +33,11 @@ Optional properties:
- usb3-lpm-capable: determines if platform is USB3 LPM capable
- quirk-broken-port-ped: set if the controller has broken port disable mechanism
- imod-interval-ns: default interrupt moderation interval is 5000ns
+ - phys : see usb-hcd.txt in the current directory
+
+additionally the properties from usb-hcd.txt (in the current directory) are
+supported.
+
Example:
usb@f0931000 {
diff --git a/Documentation/driver-api/device_connection.rst b/Documentation/driver-api/device_connection.rst
new file mode 100644
index 000000000000..affbc5566ab0
--- /dev/null
+++ b/Documentation/driver-api/device_connection.rst
@@ -0,0 +1,43 @@
+==================
+Device connections
+==================
+
+Introduction
+------------
+
+Devices often have connections to other devices that are outside of the direct
+child/parent relationship. A serial or network communication controller, which
+could be a PCI device, may need to be able to get a reference to its PHY
+component, which could be attached for example to the I2C bus. Some device
+drivers need to be able to control the clocks or the GPIOs for their devices,
+and so on.
+
+Device connections are generic descriptions of any type of connection between
+two separate devices.
+
+Device connections alone do not create a dependency between the two devices.
+They are only descriptions which are not tied to either of the devices directly.
+A dependency between the two devices exists only if one of the two endpoint
+devices requests a reference to the other. The descriptions themselves can be
+defined in firmware (not yet supported) or they can be built-in.
+
+Usage
+-----
+
+Device connections should exist before device ``->probe`` callback is called for
+either endpoint device in the description. If the connections are defined in
+firmware, this is not a problem. It should be considered if the connection
+descriptions are "built-in", and need to be added separately.
+
+The connection description consists of the names of the two devices with the
+connection, i.e. the endpoints, and unique identifier for the connection which
+is needed if there are multiple connections between the two devices.
+
+After a description exists, the devices in it can request reference to the other
+endpoint device, or they can request the description itself.
+
+API
+---
+
+.. kernel-doc:: drivers/base/devcon.c
+ : functions: device_connection_find_match device_connection_find device_connection_add device_connection_remove
diff --git a/Documentation/driver-api/firmware/fallback-mechanisms.rst b/Documentation/driver-api/firmware/fallback-mechanisms.rst
index 4055ac76b288..f353783ae0be 100644
--- a/Documentation/driver-api/firmware/fallback-mechanisms.rst
+++ b/Documentation/driver-api/firmware/fallback-mechanisms.rst
@@ -112,7 +112,7 @@ Since a device is created for the sysfs interface to help load firmware as a
fallback mechanism userspace can be informed of the addition of the device by
relying on kobject uevents. The addition of the device into the device
hierarchy means the fallback mechanism for firmware loading has been initiated.
-For details of implementation refer to _request_firmware_load(), in particular
+For details of implementation refer to fw_load_sysfs_fallback(), in particular
on the use of dev_set_uevent_suppress() and kobject_uevent().
The kernel's kobject uevent mechanism is implemented in lib/kobject_uevent.c,
diff --git a/Documentation/driver-api/firmware/request_firmware.rst b/Documentation/driver-api/firmware/request_firmware.rst
index cc0aea880824..cf4516dfbf96 100644
--- a/Documentation/driver-api/firmware/request_firmware.rst
+++ b/Documentation/driver-api/firmware/request_firmware.rst
@@ -44,6 +44,20 @@ request_firmware_nowait
.. kernel-doc:: drivers/base/firmware_class.c
:functions: request_firmware_nowait
+Special optimizations on reboot
+===============================
+
+Some devices have an optimization in place to enable the firmware to be
+retained during system reboot. When such optimizations are used the driver
+author must ensure the firmware is still available on resume from suspend,
+this can be done with firmware_request_cache() insted of requesting for the
+firmare to be loaded.
+
+firmware_request_cache()
+-----------------------
+.. kernel-doc:: drivers/base/firmware_class.c
+ :functions: firmware_request_cache
+
request firmware API expected driver use
========================================
diff --git a/Documentation/driver-api/uio-howto.rst b/Documentation/driver-api/uio-howto.rst
index 693e3bd84e79..92056c20e070 100644
--- a/Documentation/driver-api/uio-howto.rst
+++ b/Documentation/driver-api/uio-howto.rst
@@ -709,6 +709,11 @@ The vmbus device regions are mapped into uio device resources:
3) Network receive buffer region
4) Network send buffer region
+If a subchannel is created by a request to host, then the uio_hv_generic
+device driver will create a sysfs binary file for the per-channel ring buffer.
+For example:
+ /sys/bus/vmbus/devices/3811fe4d-0fa0-4b62-981a-74fc1084c757/channels/21/ring
+
Further information
===================
diff --git a/Documentation/driver-api/usb/typec.rst b/Documentation/driver-api/usb/typec.rst
index 8a7249f2ff04..feb31946490b 100644
--- a/Documentation/driver-api/usb/typec.rst
+++ b/Documentation/driver-api/usb/typec.rst
@@ -61,7 +61,7 @@ Registering the ports
The port drivers will describe every Type-C port they control with struct
typec_capability data structure, and register them with the following API:
-.. kernel-doc:: drivers/usb/typec/typec.c
+.. kernel-doc:: drivers/usb/typec/class.c
:functions: typec_register_port typec_unregister_port
When registering the ports, the prefer_role member in struct typec_capability
@@ -80,7 +80,7 @@ typec_partner_desc. The class copies the details of the partner during
registration. The class offers the following API for registering/unregistering
partners.
-.. kernel-doc:: drivers/usb/typec/typec.c
+.. kernel-doc:: drivers/usb/typec/class.c
:functions: typec_register_partner typec_unregister_partner
The class will provide a handle to struct typec_partner if the registration was
@@ -92,7 +92,7 @@ should include handle to struct usb_pd_identity instance. The class will then
create a sysfs directory for the identity under the partner device. The result
of Discover Identity command can then be reported with the following API:
-.. kernel-doc:: drivers/usb/typec/typec.c
+.. kernel-doc:: drivers/usb/typec/class.c
:functions: typec_partner_set_identity
Registering Cables
@@ -113,7 +113,7 @@ typec_cable_desc and about a plug in struct typec_plug_desc. The class copies
the details during registration. The class offers the following API for
registering/unregistering cables and their plugs:
-.. kernel-doc:: drivers/usb/typec/typec.c
+.. kernel-doc:: drivers/usb/typec/class.c
:functions: typec_register_cable typec_unregister_cable typec_register_plug typec_unregister_plug
The class will provide a handle to struct typec_cable and struct typec_plug if
@@ -125,7 +125,7 @@ include handle to struct usb_pd_identity instance. The class will then create a
sysfs directory for the identity under the cable device. The result of Discover
Identity command can then be reported with the following API:
-.. kernel-doc:: drivers/usb/typec/typec.c
+.. kernel-doc:: drivers/usb/typec/class.c
:functions: typec_cable_set_identity
Notifications
@@ -135,7 +135,7 @@ When the partner has executed a role change, or when the default roles change
during connection of a partner or cable, the port driver must use the following
APIs to report it to the class:
-.. kernel-doc:: drivers/usb/typec/typec.c
+.. kernel-doc:: drivers/usb/typec/class.c
:functions: typec_set_data_role typec_set_pwr_role typec_set_vconn_role typec_set_pwr_opmode
Alternate Modes
@@ -150,7 +150,7 @@ and struct typec_altmode_desc which is a container for all the supported modes.
Ports that support Alternate Modes need to register each SVID they support with
the following API:
-.. kernel-doc:: drivers/usb/typec/typec.c
+.. kernel-doc:: drivers/usb/typec/class.c
:functions: typec_port_register_altmode
If a partner or cable plug provides a list of SVIDs as response to USB Power
@@ -159,12 +159,12 @@ registered.
API for the partners:
-.. kernel-doc:: drivers/usb/typec/typec.c
+.. kernel-doc:: drivers/usb/typec/class.c
:functions: typec_partner_register_altmode
API for the Cable Plugs:
-.. kernel-doc:: drivers/usb/typec/typec.c
+.. kernel-doc:: drivers/usb/typec/class.c
:functions: typec_plug_register_altmode
So ports, partners and cable plugs will register the alternate modes with their
@@ -172,11 +172,62 @@ own functions, but the registration will always return a handle to struct
typec_altmode on success, or NULL. The unregistration will happen with the same
function:
-.. kernel-doc:: drivers/usb/typec/typec.c
+.. kernel-doc:: drivers/usb/typec/class.c
:functions: typec_unregister_altmode
If a partner or cable plug enters or exits a mode, the port driver needs to
notify the class with the following API:
-.. kernel-doc:: drivers/usb/typec/typec.c
+.. kernel-doc:: drivers/usb/typec/class.c
:functions: typec_altmode_update_active
+
+Multiplexer/DeMultiplexer Switches
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+USB Type-C connectors may have one or more mux/demux switches behind them. Since
+the plugs can be inserted right-side-up or upside-down, a switch is needed to
+route the correct data pairs from the connector to the USB controllers. If
+Alternate or Accessory Modes are supported, another switch is needed that can
+route the pins on the connector to some other component besides USB. USB Type-C
+Connector Class supplies an API for registering those switches.
+
+.. kernel-doc:: drivers/usb/typec/mux.c
+ :functions: typec_switch_register typec_switch_unregister typec_mux_register typec_mux_unregister
+
+In most cases the same physical mux will handle both the orientation and mode.
+However, as the port drivers will be responsible for the orientation, and the
+alternate mode drivers for the mode, the two are always separated into their
+own logical components: "mux" for the mode and "switch" for the orientation.
+
+When a port is registered, USB Type-C Connector Class requests both the mux and
+the switch for the port. The drivers can then use the following API for
+controlling them:
+
+.. kernel-doc:: drivers/usb/typec/class.c
+ :functions: typec_set_orientation typec_set_mode
+
+If the connector is dual-role capable, there may also be a switch for the data
+role. USB Type-C Connector Class does not supply separate API for them. The
+port drivers can use USB Role Class API with those.
+
+Illustration of the muxes behind a connector that supports an alternate mode:
+
+ ------------------------
+ | Connector |
+ ------------------------
+ | |
+ ------------------------
+ \ Orientation /
+ --------------------
+ |
+ --------------------
+ / Mode \
+ ------------------------
+ / \
+ ------------------------ --------------------
+ | Alt Mode | / USB Role \
+ ------------------------ ------------------------
+ / \
+ ------------------------ ------------------------
+ | USB Host | | USB Device |
+ ------------------------ ------------------------
diff --git a/Documentation/filesystems/cifs/README b/Documentation/filesystems/cifs/README
index a9da51553ba3..99ce3d25003d 100644
--- a/Documentation/filesystems/cifs/README
+++ b/Documentation/filesystems/cifs/README
@@ -11,13 +11,14 @@ Information Foundation. CIFS and now SMB3 has now become a defacto
standard for interoperating between Macs and Windows and major NAS appliances.
Please see
+ MS-SMB2 (for detailed SMB2/SMB3/SMB3.1.1 protocol specification)
http://protocolfreedom.org/ and
http://samba.org/samba/PFIF/
for more details.
For questions or bug reports please contact:
- sfrench@samba.org (sfrench@us.ibm.com)
+ smfrench@gmail.com
See the project page at: https://wiki.samba.org/index.php/LinuxCIFS_utils
@@ -37,15 +38,15 @@ Installation instructions:
=========================
If you have built the CIFS vfs as module (successfully) simply
type "make modules_install" (or if you prefer, manually copy the file to
-the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o).
+the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.ko).
If you have built the CIFS vfs into the kernel itself, follow the instructions
for your distribution on how to install a new kernel (usually you
would simply type "make install").
-If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on
-the CIFS VFS web site) copy it to the same directory in which mount.smbfs and
-similar files reside (usually /sbin). Although the helper software is not
+If you do not have the utility mount.cifs (in the Samba 4.x source tree and on
+the CIFS VFS web site) copy it to the same directory in which mount helpers
+reside (usually /sbin). Although the helper software is not
required, mount.cifs is recommended. Most distros include a "cifs-utils"
package that includes this utility so it is recommended to install this.
@@ -118,10 +119,13 @@ this can become unwieldy when potential mount targets include many
or unpredictable UNC names.
Samba Considerations
-====================
-To get the maximum benefit from the CIFS VFS, we recommend using a server that
-supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or
-Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers.
+====================
+Most current servers support SMB2.1 and SMB3 which are more secure,
+but there are useful protocol extensions for the older less secure CIFS
+dialect, so to get the maximum benefit if mounting using the older dialect
+(CIFS/SMB1), we recommend using a server that supports the SNIA CIFS
+Unix Extensions standard (e.g. almost any version of Samba ie version
+2.2.5 or later) but the CIFS vfs works fine with a wide variety of CIFS servers.
Note that uid, gid and file permissions will display default values if you do
not have a server that supports the Unix extensions for CIFS (such as Samba
2.2.5 or later). To enable the Unix CIFS Extensions in the Samba server, add
@@ -603,11 +607,6 @@ Stats Lists summary resource usage information as well as per
in the kernel configuration.
Configuration pseudo-files:
-PacketSigningEnabled If set to one, cifs packet signing is enabled
- and will be used if the server requires
- it. If set to two, cifs packet signing is
- required even if the server considers packet
- signing optional. (default 1)
SecurityFlags Flags which control security negotiation and
also packet signing. Authentication (may/must)
flags (e.g. for NTLM and/or NTLMv2) may be combined with
@@ -666,8 +665,6 @@ traceSMB If set to one, debug information is logged to the
LookupCacheEnable If set to one, inode information is kept cached
for one second improving performance of lookups
(default 1)
-OplockEnabled If set to one, safe distributed caching enabled.
- (default 1)
LinuxExtensionsEnabled If set to one then the client will attempt to
use the CIFS "UNIX" extensions which are optional
protocol enhancements that allow CIFS servers
diff --git a/Documentation/filesystems/cifs/TODO b/Documentation/filesystems/cifs/TODO
index 396ecfd6ff4a..c5adf149b57f 100644
--- a/Documentation/filesystems/cifs/TODO
+++ b/Documentation/filesystems/cifs/TODO
@@ -1,4 +1,4 @@
-Version 2.04 September 13, 2017
+Version 2.11 September 13, 2017
A Partial List of Missing Features
==================================
@@ -8,10 +8,10 @@ for visible, important contributions to this module. Here
is a partial list of the known problems and missing features:
a) SMB3 (and SMB3.02) missing optional features:
- - RDMA (started)
- - multichannel (started)
+ - multichannel (started), integration with RDMA
- directory leases (improved metadata caching)
- - T10 copy offload (copy chunk is only mechanism supported)
+ - T10 copy offload (copy chunk, and "Duplicate Extents" ioctl
+ currently the only two server side copy mechanisms supported)
b) improved sparse file support
@@ -21,9 +21,8 @@ using Directory Leases
d) quota support (needs minor kernel change since quota calls
to make it to network filesystems or deviceless filesystems)
-e) Better optimize open to reduce redundant opens (using reference
-counts more) and to improve use of compounding in SMB3 to reduce
-number of roundtrips.
+e) Compounding (in progress) to reduce number of roundtrips, and also
+better optimize open to reduce redundant opens (using reference counts more).
f) Finish inotify support so kde and gnome file list windows
will autorefresh (partially complete by Asser). Needs minor kernel
@@ -35,7 +34,8 @@ the CIFS statistics (started)
h) implement support for security and trusted categories of xattrs
(requires minor protocol extension) to enable better support for SELINUX
-i) Implement O_DIRECT flag on open (already supported on mount)
+i) Add support for tree connect contexts (see MS-SMB2) a new SMB3.1.1 protocol
+ feature (may be especially useful for virtualization).
j) Create UID mapping facility so server UIDs can be mapped on a per
mount or a per server basis to client UIDs or nobody if no mapping
@@ -53,13 +53,16 @@ viewing them.
o) mount helper GUI (to simplify the various configuration options on mount)
-p) autonegotiation of dialects (offering more than one dialect ie SMB3.02,
-SMB3, SMB2.1 not just SMB3).
+p) Add support for witness protocol (perhaps ioctl to cifs.ko from user space
+ tool listening on witness protocol RPC) to allow for notification of share
+ move, server failover, and server adapter changes. And also improve other
+ failover scenarios, e.g. when client knows multiple DFS entries point to
+ different servers, and the server we are connected to has gone down.
q) Allow mount.cifs to be more verbose in reporting errors with dialect
or unsupported feature errors.
-r) updating cifs documentation, and user guid.
+r) updating cifs documentation, and user guide.
s) Addressing bugs found by running a broader set of xfstests in standard
file system xfstest suite.
diff --git a/Documentation/kbuild/kbuild.txt b/Documentation/kbuild/kbuild.txt
index ac2363ea05c5..6c9c69ec3986 100644
--- a/Documentation/kbuild/kbuild.txt
+++ b/Documentation/kbuild/kbuild.txt
@@ -50,10 +50,6 @@ LDFLAGS_MODULE
--------------------------------------------------
Additional options used for $(LD) when linking modules.
-LDFLAGS_vmlinux
---------------------------------------------------
-Additional options passed to final link of vmlinux.
-
KBUILD_VERBOSE
--------------------------------------------------
Set the kbuild verbosity. Can be assigned same values as "V=...".
diff --git a/Documentation/kbuild/kconfig.txt b/Documentation/kbuild/kconfig.txt
index bbc99c0c1094..7233118f3a05 100644
--- a/Documentation/kbuild/kconfig.txt
+++ b/Documentation/kbuild/kconfig.txt
@@ -119,7 +119,7 @@ Examples:
15% of tristates will be set to 'y', 15% to 'm', 70% to 'n'
______________________________________________________________________
-Environment variables for 'silentoldconfig'
+Environment variables for 'syncconfig'
KCONFIG_NOSILENTUPDATE
--------------------------------------------------
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index 71e9feefb63c..048fc39a6b91 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -153,12 +153,18 @@ more details, with real examples.
configuration.
Kbuild compiles all the $(obj-y) files. It then calls
- "$(LD) -r" to merge these files into one built-in.o file.
- built-in.o is later linked into vmlinux by the parent Makefile.
+ "$(AR) rcSTP" to merge these files into one built-in.a file.
+ This is a thin archive without a symbol table, which makes it
+ unsuitable as a linker input.
+
+ The scripts/link-vmlinux.sh script later makes an aggregate
+ built-in.a with "${AR} rcsTP", which creates the thin archive
+ with a symbol table and an index, making it a valid input for
+ the final vmlinux link passes.
The order of files in $(obj-y) is significant. Duplicates in
the lists are allowed: the first instance will be linked into
- built-in.o and succeeding instances will be ignored.
+ built-in.a and succeeding instances will be ignored.
Link order is significant, because certain functions
(module_init() / __initcall) will be called during boot in the
@@ -222,7 +228,7 @@ more details, with real examples.
Note: Of course, when you are building objects into the kernel,
the syntax above will also work. So, if you have CONFIG_EXT2_FS=y,
kbuild will build an ext2.o file for you out of the individual
- parts and then link this into built-in.o, as you would expect.
+ parts and then link this into built-in.a, as you would expect.
--- 3.4 Objects which export symbols
@@ -232,7 +238,7 @@ more details, with real examples.
--- 3.5 Library file goals - lib-y
Objects listed with obj-* are used for modules, or
- combined in a built-in.o for that specific directory.
+ combined in a built-in.a for that specific directory.
There is also the possibility to list objects that will
be included in a library, lib.a.
All objects listed with lib-y are combined in a single
@@ -244,7 +250,7 @@ more details, with real examples.
Note that the same kbuild makefile may list files to be built-in
and to be part of a library. Therefore the same directory
- may contain both a built-in.o and a lib.a file.
+ may contain both a built-in.a and a lib.a file.
Example:
#arch/x86/lib/Makefile
@@ -831,12 +837,6 @@ When kbuild executes, the following steps are followed (roughly):
Note: ldflags-y can be used to further customise
the flags used. See chapter 3.7.
- LDFLAGS_MODULE Options for $(LD) when linking modules
-
- LDFLAGS_MODULE is used to set specific flags for $(LD) when
- linking the .ko files used for modules.
- Default is "-r", for relocatable output.
-
LDFLAGS_vmlinux Options for $(LD) when linking vmlinux
LDFLAGS_vmlinux is used to specify additional flags to pass to
@@ -986,7 +986,7 @@ When kbuild executes, the following steps are followed (roughly):
$(head-y) lists objects to be linked first in vmlinux.
$(libs-y) lists directories where a lib.a archive can be located.
- The rest list directories where a built-in.o object file can be
+ The rest list directories where a built-in.a object file can be
located.
$(init-y) objects will be located after $(head-y).
@@ -1071,7 +1071,7 @@ When kbuild executes, the following steps are followed (roughly):
extra-y := head.o init_task.o
In this example, extra-y is used to list object files that
- shall be built, but shall not be linked as part of built-in.o.
+ shall be built, but shall not be linked as part of built-in.a.
--- 6.7 Commands useful for building a boot image
diff --git a/Documentation/media/kapi/cec-core.rst b/Documentation/media/kapi/cec-core.rst
index 62b9a1448177..a9f53f069a2d 100644
--- a/Documentation/media/kapi/cec-core.rst
+++ b/Documentation/media/kapi/cec-core.rst
@@ -110,11 +110,14 @@ your driver:
void (*adap_status)(struct cec_adapter *adap, struct seq_file *file);
void (*adap_free)(struct cec_adapter *adap);
+ /* Error injection callbacks */
+ ...
+
/* High-level callbacks */
...
};
-The five low-level ops deal with various aspects of controlling the CEC adapter
+The seven low-level ops deal with various aspects of controlling the CEC adapter
hardware:
@@ -286,6 +289,70 @@ handling the receive interrupt. The framework expects to see the cec_transmit_do
call before the cec_received_msg call, otherwise it can get confused if the
received message was in reply to the transmitted message.
+Optional: Implementing Error Injection Support
+----------------------------------------------
+
+If the CEC adapter supports Error Injection functionality, then that can
+be exposed through the Error Injection callbacks:
+
+.. code-block:: none
+
+ struct cec_adap_ops {
+ /* Low-level callbacks */
+ ...
+
+ /* Error injection callbacks */
+ int (*error_inj_show)(struct cec_adapter *adap, struct seq_file *sf);
+ bool (*error_inj_parse_line)(struct cec_adapter *adap, char *line);
+
+ /* High-level CEC message callback */
+ ...
+ };
+
+If both callbacks are set, then an ``error-inj`` file will appear in debugfs.
+The basic syntax is as follows:
+
+Leading spaces/tabs are ignored. If the next character is a ``#`` or the end of the
+line was reached, then the whole line is ignored. Otherwise a command is expected.
+
+This basic parsing is done in the CEC Framework. It is up to the driver to decide
+what commands to implement. The only requirement is that the command ``clear`` without
+any arguments must be implemented and that it will remove all current error injection
+commands.
+
+This ensures that you can always do ``echo clear >error-inj`` to clear any error
+injections without having to know the details of the driver-specific commands.
+
+Note that the output of ``error-inj`` shall be valid as input to ``error-inj``.
+So this must work:
+
+.. code-block:: none
+
+ $ cat error-inj >einj.txt
+ $ cat einj.txt >error-inj
+
+The first callback is called when this file is read and it should show the
+the current error injection state:
+
+.. c:function::
+ int (*error_inj_show)(struct cec_adapter *adap, struct seq_file *sf);
+
+It is recommended that it starts with a comment block with basic usage
+information. It returns 0 for success and an error otherwise.
+
+The second callback will parse commands written to the ``error-inj`` file:
+
+.. c:function::
+ bool (*error_inj_parse_line)(struct cec_adapter *adap, char *line);
+
+The ``line`` argument points to the start of the command. Any leading
+spaces or tabs have already been skipped. It is a single line only (so there
+are no embedded newlines) and it is 0-terminated. The callback is free to
+modify the contents of the buffer. It is only called for lines containing a
+command, so this callback is never called for empty lines or comment lines.
+
+Return true if the command was valid or false if there were syntax errors.
+
Implementing the High-Level CEC Adapter
---------------------------------------
@@ -298,6 +365,9 @@ CEC protocol driven. The following high-level callbacks are available:
/* Low-level callbacks */
...
+ /* Error injection callbacks */
+ ...
+
/* High-level CEC message callback */
int (*received)(struct cec_adapter *adap, struct cec_msg *msg);
};
diff --git a/Documentation/media/lirc.h.rst.exceptions b/Documentation/media/lirc.h.rst.exceptions
index c6e3a35d2c4e..984b61dc3f2e 100644
--- a/Documentation/media/lirc.h.rst.exceptions
+++ b/Documentation/media/lirc.h.rst.exceptions
@@ -57,6 +57,7 @@ ignore symbol RC_PROTO_RC6_MCE
ignore symbol RC_PROTO_SHARP
ignore symbol RC_PROTO_XMP
ignore symbol RC_PROTO_CEC
+ignore symbol RC_PROTO_IMON
# Undocumented macros
diff --git a/Documentation/media/uapi/cec/cec-api.rst b/Documentation/media/uapi/cec/cec-api.rst
index b68ca9c1d2e0..1e2cf498ba30 100644
--- a/Documentation/media/uapi/cec/cec-api.rst
+++ b/Documentation/media/uapi/cec/cec-api.rst
@@ -23,6 +23,7 @@ This part describes the CEC: Consumer Electronics Control
cec-intro
cec-funcs
+ cec-pin-error-inj
cec-header
diff --git a/Documentation/media/uapi/cec/cec-pin-error-inj.rst b/Documentation/media/uapi/cec/cec-pin-error-inj.rst
new file mode 100644
index 000000000000..464b006dbe0a
--- /dev/null
+++ b/Documentation/media/uapi/cec/cec-pin-error-inj.rst
@@ -0,0 +1,325 @@
+CEC Pin Framework Error Injection
+=================================
+
+The CEC Pin Framework is a core CEC framework for CEC hardware that only
+has low-level support for the CEC bus. Most hardware today will have
+high-level CEC support where the hardware deals with driving the CEC bus,
+but some older devices aren't that fancy. However, this framework also
+allows you to connect the CEC pin to a GPIO on e.g. a Raspberry Pi and
+you have now made a CEC adapter.
+
+What makes doing this so interesting is that since we have full control
+over the bus it is easy to support error injection. This is ideal to
+test how well CEC adapters can handle error conditions.
+
+Currently only the cec-gpio driver (when the CEC line is directly
+connected to a pull-up GPIO line) and the AllWinner A10/A20 drm driver
+support this framework.
+
+If ``CONFIG_CEC_PIN_ERROR_INJ`` is enabled, then error injection is available
+through debugfs. Specifically, in ``/sys/kernel/debug/cec/cecX/`` there is
+now an ``error-inj`` file.
+
+.. note::
+
+ The error injection commands are not a stable ABI and may change in the
+ future.
+
+With ``cat error-inj`` you can see both the possible commands and the current
+error injection status::
+
+ $ cat /sys/kernel/debug/cec/cec0/error-inj
+ # Clear error injections:
+ # clear clear all rx and tx error injections
+ # rx-clear clear all rx error injections
+ # tx-clear clear all tx error injections
+ # <op> clear clear all rx and tx error injections for <op>
+ # <op> rx-clear clear all rx error injections for <op>
+ # <op> tx-clear clear all tx error injections for <op>
+ #
+ # RX error injection:
+ # <op>[,<mode>] rx-nack NACK the message instead of sending an ACK
+ # <op>[,<mode>] rx-low-drive <bit> force a low-drive condition at this bit position
+ # <op>[,<mode>] rx-add-byte add a spurious byte to the received CEC message
+ # <op>[,<mode>] rx-remove-byte remove the last byte from the received CEC message
+ # <op>[,<mode>] rx-arb-lost <poll> generate a POLL message to trigger an arbitration lost
+ #
+ # TX error injection settings:
+ # tx-ignore-nack-until-eom ignore early NACKs until EOM
+ # tx-custom-low-usecs <usecs> define the 'low' time for the custom pulse
+ # tx-custom-high-usecs <usecs> define the 'high' time for the custom pulse
+ # tx-custom-pulse transmit the custom pulse once the bus is idle
+ #
+ # TX error injection:
+ # <op>[,<mode>] tx-no-eom don't set the EOM bit
+ # <op>[,<mode>] tx-early-eom set the EOM bit one byte too soon
+ # <op>[,<mode>] tx-add-bytes <num> append <num> (1-255) spurious bytes to the message
+ # <op>[,<mode>] tx-remove-byte drop the last byte from the message
+ # <op>[,<mode>] tx-short-bit <bit> make this bit shorter than allowed
+ # <op>[,<mode>] tx-long-bit <bit> make this bit longer than allowed
+ # <op>[,<mode>] tx-custom-bit <bit> send the custom pulse instead of this bit
+ # <op>[,<mode>] tx-short-start send a start pulse that's too short
+ # <op>[,<mode>] tx-long-start send a start pulse that's too long
+ # <op>[,<mode>] tx-custom-start send the custom pulse instead of the start pulse
+ # <op>[,<mode>] tx-last-bit <bit> stop sending after this bit
+ # <op>[,<mode>] tx-low-drive <bit> force a low-drive condition at this bit position
+ #
+ # <op> CEC message opcode (0-255) or 'any'
+ # <mode> 'once' (default), 'always', 'toggle' or 'off'
+ # <bit> CEC message bit (0-159)
+ # 10 bits per 'byte': bits 0-7: data, bit 8: EOM, bit 9: ACK
+ # <poll> CEC poll message used to test arbitration lost (0x00-0xff, default 0x0f)
+ # <usecs> microseconds (0-10000000, default 1000)
+
+ clear
+
+You can write error injection commands to ``error-inj`` using
+``echo 'cmd' >error-inj`` or ``cat cmd.txt >error-inj``. The ``cat error-inj``
+output contains the current error commands. You can save the output to a file
+and use it as an input to ``error-inj`` later.
+
+Basic Syntax
+------------
+
+Leading spaces/tabs are ignored. If the next character is a ``#`` or the end
+of the line was reached, then the whole line is ignored. Otherwise a command
+is expected.
+
+The error injection commands fall in two main groups: those relating to
+receiving CEC messages and those relating to transmitting CEC messages. In
+addition, there are commands to clear existing error injection commands and
+to create custom pulses on the CEC bus.
+
+Most error injection commands can be executed for specific CEC opcodes or for
+all opcodes (``any``). Each command also has a 'mode' which can be ``off``
+(can be used to turn off an existing error injection command), ``once``
+(the default) which will trigger the error injection only once for the next
+received or transmitted message, ``always`` to always trigger the error
+injection and ``toggle`` to toggle the error injection on or off for every
+transmit or receive.
+
+So '``any rx-nack``' will NACK the next received CEC message,
+'``any,always rx-nack``' will NACK all received CEC messages and
+'``0x82,toggle rx-nack``' will only NACK if an Active Source message was
+received and do that only for every other received message.
+
+After an error was injected with mode ``once`` the error injection command
+is cleared automatically, so ``once`` is a one-time deal.
+
+All combinations of ``<op>`` and error injection commands can co-exist. So
+this is fine::
+
+ 0x9e tx-add-bytes 1
+ 0x9e tx-early-eom
+ 0x9f tx-add-bytes 2
+ any rx-nack
+
+All four error injection commands will be active simultaneously.
+
+However, if the same ``<op>`` and command combination is specified,
+but with different arguments::
+
+ 0x9e tx-add-bytes 1
+ 0x9e tx-add-bytes 2
+
+Then the second will overwrite the first.
+
+Clear Error Injections
+----------------------
+
+``clear``
+ Clear all error injections.
+
+``rx-clear``
+ Clear all receive error injections
+
+``tx-clear``
+ Clear all transmit error injections
+
+``<op> clear``
+ Clear all error injections for the given opcode.
+
+``<op> rx-clear``
+ Clear all receive error injections for the given opcode.
+
+``<op> tx-clear``
+ Clear all transmit error injections for the given opcode.
+
+Receive Messages
+----------------
+
+``<op>[,<mode>] rx-nack``
+ NACK broadcast messages and messages directed to this CEC adapter.
+ Every byte of the message will be NACKed in case the transmitter
+ keeps transmitting after the first byte was NACKed.
+
+``<op>[,<mode>] rx-low-drive <bit>``
+ Force a Low Drive condition at this bit position. If <op> specifies
+ a specific CEC opcode then the bit position must be at least 18,
+ otherwise the opcode hasn't been received yet. This tests if the
+ transmitter can handle the Low Drive condition correctly and reports
+ the error correctly. Note that a Low Drive in the first 4 bits can also
+ be interpreted as an Arbitration Lost condition by the transmitter.
+ This is implementation dependent.
+
+``<op>[,<mode>] rx-add-byte``
+ Add a spurious 0x55 byte to the received CEC message, provided
+ the message was 15 bytes long or less. This is useful to test
+ the high-level protocol since spurious bytes should be ignored.
+
+``<op>[,<mode>] rx-remove-byte``
+ Remove the last byte from the received CEC message, provided it
+ was at least 2 bytes long. This is useful to test the high-level
+ protocol since messages that are too short should be ignored.
+
+``<op>[,<mode>] rx-arb-lost <poll>``
+ Generate a POLL message to trigger an Arbitration Lost condition.
+ This command is only allowed for ``<op>`` values of ``next`` or ``all``.
+ As soon as a start bit has been received the CEC adapter will switch
+ to transmit mode and it will transmit a POLL message. By default this is
+ 0x0f, but it can also be specified explicitly via the ``<poll>`` argument.
+
+ This command can be used to test the Arbitration Lost condition in
+ the remote CEC transmitter. Arbitration happens when two CEC adapters
+ start sending a message at the same time. In that case the initiator
+ with the most leading zeroes wins and the other transmitter has to
+ stop transmitting ('Arbitration Lost'). This is very hard to test,
+ except by using this error injection command.
+
+ This does not work if the remote CEC transmitter has logical address
+ 0 ('TV') since that will always win.
+
+Transmit Messages
+-----------------
+
+``tx-ignore-nack-until-eom``
+ This setting changes the behavior of transmitting CEC messages. Normally
+ as soon as the receiver NACKs a byte the transmit will stop, but the
+ specification also allows that the full message is transmitted and only
+ at the end will the transmitter look at the ACK bit. This is not
+ recommended behavior since there is no point in keeping the CEC bus busy
+ for longer than is strictly needed. Especially given how slow the bus is.
+
+ This setting can be used to test how well a receiver deals with
+ transmitters that ignore NACKs until the very end of the message.
+
+``<op>[,<mode>] tx-no-eom``
+ Don't set the EOM bit. Normally the last byte of the message has the EOM
+ (End-Of-Message) bit set. With this command the transmit will just stop
+ without ever sending an EOM. This can be used to test how a receiver
+ handles this case. Normally receivers have a time-out after which
+ they will go back to the Idle state.
+
+``<op>[,<mode>] tx-early-eom``
+ Set the EOM bit one byte too soon. This obviously only works for messages
+ of two bytes or more. The EOM bit will be set for the second-to-last byte
+ and not for the final byte. The receiver should ignore the last byte in
+ this case. Since the resulting message is likely to be too short for this
+ same reason the whole message is typically ignored. The receiver should be
+ in Idle state after the last byte was transmitted.
+
+``<op>[,<mode>] tx-add-bytes <num>``
+ Append ``<num>`` (1-255) spurious bytes to the message. The extra bytes
+ have the value of the byte position in the message. So if you transmit a
+ two byte message (e.g. a Get CEC Version message) and add 2 bytes, then
+ the full message received by the remote CEC adapter is
+ ``0x40 0x9f 0x02 0x03``.
+
+ This command can be used to test buffer overflows in the receiver. E.g.
+ what does it do when it receives more than the maximum message size of 16
+ bytes.
+
+``<op>[,<mode>] tx-remove-byte``
+ Drop the last byte from the message, provided the message is at least
+ two bytes long. The receiver should ignore messages that are too short.
+
+``<op>[,<mode>] tx-short-bit <bit>``
+ Make this bit period shorter than allowed. The bit position cannot be
+ an Ack bit. If <op> specifies a specific CEC opcode then the bit position
+ must be at least 18, otherwise the opcode hasn't been received yet.
+ Normally the period of a data bit is between 2.05 and 2.75 milliseconds.
+ With this command the period of this bit is 1.8 milliseconds, this is
+ done by reducing the time the CEC bus is high. This bit period is less
+ than is allowed and the receiver should respond with a Low Drive
+ condition.
+
+ This command is ignored for 0 bits in bit positions 0 to 3. This is
+ because the receiver also looks for an Arbitration Lost condition in
+ those first four bits and it is undefined what will happen if it
+ sees a too-short 0 bit.
+
+``<op>[,<mode>] tx-long-bit <bit>``
+ Make this bit period longer than is valid. The bit position cannot be
+ an Ack bit. If <op> specifies a specific CEC opcode then the bit position
+ must be at least 18, otherwise the opcode hasn't been received yet.
+ Normally the period of a data bit is between 2.05 and 2.75 milliseconds.
+ With this command the period of this bit is 2.9 milliseconds, this is
+ done by increasing the time the CEC bus is high.
+
+ Even though this bit period is longer than is valid it is undefined what
+ a receiver will do. It might just accept it, or it might time out and
+ return to Idle state. Unfortunately the CEC specification is silent about
+ this.
+
+ This command is ignored for 0 bits in bit positions 0 to 3. This is
+ because the receiver also looks for an Arbitration Lost condition in
+ those first four bits and it is undefined what will happen if it
+ sees a too-long 0 bit.
+
+``<op>[,<mode>] tx-short-start``
+ Make this start bit period shorter than allowed. Normally the period of
+ a start bit is between 4.3 and 4.7 milliseconds. With this command the
+ period of the start bit is 4.1 milliseconds, this is done by reducing
+ the time the CEC bus is high. This start bit period is less than is
+ allowed and the receiver should return to Idle state when this is detected.
+
+``<op>[,<mode>] tx-long-start``
+ Make this start bit period longer than is valid. Normally the period of
+ a start bit is between 4.3 and 4.7 milliseconds. With this command the
+ period of the start bit is 5 milliseconds, this is done by increasing
+ the time the CEC bus is high. This start bit period is more than is
+ valid and the receiver should return to Idle state when this is detected.
+
+ Even though this start bit period is longer than is valid it is undefined
+ what a receiver will do. It might just accept it, or it might time out and
+ return to Idle state. Unfortunately the CEC specification is silent about
+ this.
+
+``<op>[,<mode>] tx-last-bit <bit>``
+ Just stop transmitting after this bit. If <op> specifies a specific CEC
+ opcode then the bit position must be at least 18, otherwise the opcode
+ hasn't been received yet. This command can be used to test how the receiver
+ reacts when a message just suddenly stops. It should time out and go back
+ to Idle state.
+
+``<op>[,<mode>] tx-low-drive <bit>``
+ Force a Low Drive condition at this bit position. If <op> specifies a
+ specific CEC opcode then the bit position must be at least 18, otherwise
+ the opcode hasn't been received yet. This can be used to test how the
+ receiver handles Low Drive conditions. Note that if this happens at bit
+ positions 0-3 the receiver can interpret this as an Arbitration Lost
+ condition. This is implementation dependent.
+
+Custom Pulses
+-------------
+
+``tx-custom-low-usecs <usecs>``
+ This defines the duration in microseconds that the custom pulse pulls
+ the CEC line low. The default is 1000 microseconds.
+
+``tx-custom-high-usecs <usecs>``
+ This defines the duration in microseconds that the custom pulse keeps the
+ CEC line high (unless another CEC adapter pulls it low in that time).
+ The default is 1000 microseconds. The total period of the custom pulse is
+ ``tx-custom-low-usecs + tx-custom-high-usecs``.
+
+``<op>[,<mode>] tx-custom-bit <bit>``
+ Send the custom bit instead of a regular data bit. The bit position cannot
+ be an Ack bit. If <op> specifies a specific CEC opcode then the bit
+ position must be at least 18, otherwise the opcode hasn't been received yet.
+
+``<op>[,<mode>] tx-custom-start``
+ Send the custom bit instead of a regular start bit.
+
+``tx-custom-pulse``
+ Transmit a single custom pulse as soon as the CEC bus is idle.
diff --git a/Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst b/Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst
index b59ce149efb5..45e76e5bc1ea 100644
--- a/Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst
+++ b/Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst
@@ -144,10 +144,21 @@ id's until they get an error.
- .. row 9
- - union
+ - __u32
+
+ - ``reserved[4]``
+
+ -
+ -
+ - Reserved for future extensions. Drivers and applications must set
+ the array to zero.
- .. row 10
+ - union
+
+ - .. row 11
+
-
- struct
@@ -156,7 +167,7 @@ id's until they get an error.
-
- Valid for (sub-)devices that create a single device node.
- - .. row 11
+ - .. row 12
-
-
@@ -166,7 +177,7 @@ id's until they get an error.
- Device node major number.
- - .. row 12
+ - .. row 13
-
-
@@ -176,7 +187,7 @@ id's until they get an error.
- Device node minor number.
- - .. row 13
+ - .. row 14
-
- __u8
diff --git a/Documentation/media/uapi/mediactl/media-ioc-enum-links.rst b/Documentation/media/uapi/mediactl/media-ioc-enum-links.rst
index d05be16ffaf6..256168b3c3be 100644
--- a/Documentation/media/uapi/mediactl/media-ioc-enum-links.rst
+++ b/Documentation/media/uapi/mediactl/media-ioc-enum-links.rst
@@ -125,6 +125,15 @@ returned during the enumeration process.
- Pad flags, see :ref:`media-pad-flag` for more details.
+ - .. row 4
+
+ - __u32
+
+ - ``reserved[2]``
+
+ - Reserved for future extensions. Drivers and applications must set
+ the array to zero.
+
.. c:type:: media_link_desc
@@ -161,6 +170,15 @@ returned during the enumeration process.
- Link flags, see :ref:`media-link-flag` for more details.
+ - .. row 4
+
+ - __u32
+
+ - ``reserved[4]``
+
+ - Reserved for future extensions. Drivers and applications must set
+ the array to zero.
+
Return Value
============
diff --git a/Documentation/media/uapi/mediactl/media-ioc-g-topology.rst b/Documentation/media/uapi/mediactl/media-ioc-g-topology.rst
index 997e6b17440d..c8f9ea37db2d 100644
--- a/Documentation/media/uapi/mediactl/media-ioc-g-topology.rst
+++ b/Documentation/media/uapi/mediactl/media-ioc-g-topology.rst
@@ -68,7 +68,7 @@ desired arrays with the media graph elements.
- .. row 2
- - __u64
+ - __u32
- ``num_entities``
@@ -76,6 +76,14 @@ desired arrays with the media graph elements.
- .. row 3
+ - __u32
+
+ - ``reserved1``
+
+ - Applications and drivers shall set this to 0.
+
+ - .. row 4
+
- __u64
- ``ptr_entities``
@@ -85,15 +93,23 @@ desired arrays with the media graph elements.
the ioctl won't store the entities. It will just update
``num_entities``
- - .. row 4
+ - .. row 5
- - __u64
+ - __u32
- ``num_interfaces``
- Number of interfaces in the graph
- - .. row 5
+ - .. row 6
+
+ - __u32
+
+ - ``reserved2``
+
+ - Applications and drivers shall set this to 0.
+
+ - .. row 7
- __u64
@@ -104,15 +120,23 @@ desired arrays with the media graph elements.
the ioctl won't store the interfaces. It will just update
``num_interfaces``
- - .. row 6
+ - .. row 8
- - __u64
+ - __u32
- ``num_pads``
- Total number of pads in the graph
- - .. row 7
+ - .. row 9
+
+ - __u32
+
+ - ``reserved3``
+
+ - Applications and drivers shall set this to 0.
+
+ - .. row 10
- __u64
@@ -122,15 +146,23 @@ desired arrays with the media graph elements.
converted to a 64-bits integer. It can be zero. if zero, the ioctl
won't store the pads. It will just update ``num_pads``
- - .. row 8
+ - .. row 11
- - __u64
+ - __u32
- ``num_links``
- Total number of data and interface links in the graph
- - .. row 9
+ - .. row 12
+
+ - __u32
+
+ - ``reserved4``
+
+ - Applications and drivers shall set this to 0.
+
+ - .. row 13
- __u64
@@ -334,7 +366,7 @@ desired arrays with the media graph elements.
- On pad to pad links: unique ID for the source pad.
- On interface to entity links: unique ID for the entity.
+ On interface to entity links: unique ID for the interface.
- .. row 3
diff --git a/Documentation/media/uapi/mediactl/media-types.rst b/Documentation/media/uapi/mediactl/media-types.rst
index 8d64b0c06ebc..f92f10b7ffbd 100644
--- a/Documentation/media/uapi/mediactl/media-types.rst
+++ b/Documentation/media/uapi/mediactl/media-types.rst
@@ -26,7 +26,7 @@ Types and flags used to represent the media graph elements
``MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN``
- Unknown entity. That generally indicates that a driver didn't
- initialize properly the entity, with is a Kernel bug
+ initialize properly the entity, which is a Kernel bug
- .. row 2
@@ -293,7 +293,7 @@ Types and flags used to represent the media graph elements
- ``MEDIA_ENT_F_PROC_VIDEO_STATISTICS``
- - Video statistics computation (histogram, 3A, ...). An entity
+ - Video statistics computation (histogram, 3A, etc.). An entity
capable of statistics computation must have one sink pad and
one source pad. It computes statistics over the frames
received on its sink pad and outputs the statistics data on
@@ -318,8 +318,19 @@ Types and flags used to represent the media graph elements
- Video interface bridge. A video interface bridge entity must have at
least one sink pad and at least one source pad. It receives video
frames on its sink pad from an input video bus of one type (HDMI, eDP,
- MIPI CSI-2, ...), and outputs them on its source pad to an output
- video bus of another type (eDP, MIPI CSI-2, parallel, ...).
+ MIPI CSI-2, etc.), and outputs them on its source pad to an output
+ video bus of another type (eDP, MIPI CSI-2, parallel, etc.).
+
+ - .. row 31
+
+ .. _MEDIA-ENT-F-DTV-DECODER:
+
+ - ``MEDIA_ENT_F_DTV_DECODER``
+
+ - Digital video decoder. The basic function of the video decoder is
+ to accept digital video from a wide variety of sources
+ and output it in some digital video standard, with appropriate
+ timing signals.
.. tabularcolumns:: |p{5.5cm}|p{12.0cm}|
@@ -337,7 +348,7 @@ Types and flags used to represent the media graph elements
- ``MEDIA_ENT_FL_DEFAULT``
- Default entity for its type. Used to discover the default audio,
- VBI and video devices, the default camera sensor, ...
+ VBI and video devices, the default camera sensor, etc.
- .. row 2
@@ -345,7 +356,7 @@ Types and flags used to represent the media graph elements
- ``MEDIA_ENT_FL_CONNECTOR``
- - The entity represents a data conector
+ - The entity represents a connector.
.. tabularcolumns:: |p{6.5cm}|p{6.0cm}|p{5.0cm}|
diff --git a/Documentation/media/uapi/rc/lirc-dev-intro.rst b/Documentation/media/uapi/rc/lirc-dev-intro.rst
index 3a74fec66d69..698e4f80270e 100644
--- a/Documentation/media/uapi/rc/lirc-dev-intro.rst
+++ b/Documentation/media/uapi/rc/lirc-dev-intro.rst
@@ -18,7 +18,6 @@ Example dmesg output upon a driver registering w/LIRC:
.. code-block:: none
$ dmesg |grep lirc_dev
- lirc_dev: IR Remote Control driver registered, major 248
rc rc0: lirc_dev: driver mceusb registered at minor = 0
What you should see for a chardev:
diff --git a/Documentation/media/uapi/v4l/buffer.rst b/Documentation/media/uapi/v4l/buffer.rst
index ae6ee73f151c..e2c85ddc990b 100644
--- a/Documentation/media/uapi/v4l/buffer.rst
+++ b/Documentation/media/uapi/v4l/buffer.rst
@@ -13,7 +13,7 @@ Only pointers to buffers (planes) are exchanged, the data itself is not
copied. These pointers, together with meta-information like timestamps
or field parity, are stored in a struct :c:type:`v4l2_buffer`,
argument to the :ref:`VIDIOC_QUERYBUF`,
-:ref:`VIDIOC_QBUF` and
+:ref:`VIDIOC_QBUF <VIDIOC_QBUF>` and
:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl. In the multi-planar API,
some plane-specific members of struct :c:type:`v4l2_buffer`,
such as pointers and sizes for each plane, are stored in struct
diff --git a/Documentation/media/uapi/v4l/extended-controls.rst b/Documentation/media/uapi/v4l/extended-controls.rst
index dfe49ae57e78..d5f3eb6e674a 100644
--- a/Documentation/media/uapi/v4l/extended-controls.rst
+++ b/Documentation/media/uapi/v4l/extended-controls.rst
@@ -1960,6 +1960,416 @@ enum v4l2_vp8_golden_frame_sel -
1, 2 and 3 corresponding to encoder profiles 0, 1, 2 and 3.
+High Efficiency Video Coding (HEVC/H.265) Control Reference
+-----------------------------------------------------------
+
+The HEVC/H.265 controls include controls for encoding parameters of HEVC/H.265
+video codec.
+
+
+.. _hevc-control-id:
+
+HEVC/H.265 Control IDs
+^^^^^^^^^^^^^^^^^^^^^^
+
+``V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP (integer)``
+ Minimum quantization parameter for HEVC.
+ Valid range: from 0 to 51.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP (integer)``
+ Maximum quantization parameter for HEVC.
+ Valid range: from 0 to 51.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP (integer)``
+ Quantization parameter for an I frame for HEVC.
+ Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP].
+
+``V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP (integer)``
+ Quantization parameter for a P frame for HEVC.
+ Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP].
+
+``V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP (integer)``
+ Quantization parameter for a B frame for HEVC.
+ Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP].
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP (boolean)``
+ HIERARCHICAL_QP allows the host to specify the quantization parameter
+ values for each temporal layer through HIERARCHICAL_QP_LAYER. This is
+ valid only if HIERARCHICAL_CODING_LAYER is greater than 1. Setting the
+ control value to 1 enables setting of the QP values for the layers.
+
+.. _v4l2-hevc-hier-coding-type:
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE``
+ (enum)
+
+enum v4l2_mpeg_video_hevc_hier_coding_type -
+ Selects the hierarchical coding type for encoding. Possible values are:
+
+.. raw:: latex
+
+ \footnotesize
+
+.. tabularcolumns:: |p{9.0cm}|p{8.0cm}|
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ * - ``V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B``
+ - Use the B frame for hierarchical coding.
+ * - ``V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P``
+ - Use the P frame for hierarchical coding.
+
+.. raw:: latex
+
+ \normalsize
+
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER (integer)``
+ Selects the hierarchical coding layer. In normal encoding
+ (non-hierarchial coding), it should be zero. Possible values are [0, 6].
+ 0 indicates HIERARCHICAL CODING LAYER 0, 1 indicates HIERARCHICAL CODING
+ LAYER 1 and so on.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP (integer)``
+ Indicates quantization parameter for hierarchical coding layer 0.
+ Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP].
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP (integer)``
+ Indicates quantization parameter for hierarchical coding layer 1.
+ Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP].
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP (integer)``
+ Indicates quantization parameter for hierarchical coding layer 2.
+ Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP].
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP (integer)``
+ Indicates quantization parameter for hierarchical coding layer 3.
+ Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP].
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP (integer)``
+ Indicates quantization parameter for hierarchical coding layer 4.
+ Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP].
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP (integer)``
+ Indicates quantization parameter for hierarchical coding layer 5.
+ Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP].
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP (integer)``
+ Indicates quantization parameter for hierarchical coding layer 6.
+ Valid range: [V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP].
+
+.. _v4l2-hevc-profile:
+
+``V4L2_CID_MPEG_VIDEO_HEVC_PROFILE``
+ (enum)
+
+enum v4l2_mpeg_video_hevc_profile -
+ Select the desired profile for HEVC encoder.
+
+.. raw:: latex
+
+ \footnotesize
+
+.. tabularcolumns:: |p{9.0cm}|p{8.0cm}|
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ * - ``V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN``
+ - Main profile.
+ * - ``V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE``
+ - Main still picture profile.
+ * - ``V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10``
+ - Main 10 profile.
+
+.. raw:: latex
+
+ \normalsize
+
+
+.. _v4l2-hevc-level:
+
+``V4L2_CID_MPEG_VIDEO_HEVC_LEVEL``
+ (enum)
+
+enum v4l2_mpeg_video_hevc_level -
+ Selects the desired level for HEVC encoder.
+
+.. raw:: latex
+
+ \footnotesize
+
+.. tabularcolumns:: |p{9.0cm}|p{8.0cm}|
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_1``
+ - Level 1.0
+ * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_2``
+ - Level 2.0
+ * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1``
+ - Level 2.1
+ * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_3``
+ - Level 3.0
+ * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1``
+ - Level 3.1
+ * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_4``
+ - Level 4.0
+ * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1``
+ - Level 4.1
+ * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_5``
+ - Level 5.0
+ * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1``
+ - Level 5.1
+ * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2``
+ - Level 5.2
+ * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_6``
+ - Level 6.0
+ * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1``
+ - Level 6.1
+ * - ``V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2``
+ - Level 6.2
+
+.. raw:: latex
+
+ \normalsize
+
+
+``V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION (integer)``
+ Indicates the number of evenly spaced subintervals, called ticks, within
+ one second. This is a 16 bit unsigned integer and has a maximum value up to
+ 0xffff and a minimum value of 1.
+
+.. _v4l2-hevc-tier:
+
+``V4L2_CID_MPEG_VIDEO_HEVC_TIER``
+ (enum)
+
+enum v4l2_mpeg_video_hevc_tier -
+ TIER_FLAG specifies tiers information of the HEVC encoded picture. Tier
+ were made to deal with applications that differ in terms of maximum bit
+ rate. Setting the flag to 0 selects HEVC tier as Main tier and setting
+ this flag to 1 indicates High tier. High tier is for applications requiring
+ high bit rates.
+
+.. raw:: latex
+
+ \footnotesize
+
+.. tabularcolumns:: |p{9.0cm}|p{8.0cm}|
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ * - ``V4L2_MPEG_VIDEO_HEVC_TIER_MAIN``
+ - Main tier.
+ * - ``V4L2_MPEG_VIDEO_HEVC_TIER_HIGH``
+ - High tier.
+
+.. raw:: latex
+
+ \normalsize
+
+
+``V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH (integer)``
+ Selects HEVC maximum coding unit depth.
+
+.. _v4l2-hevc-loop-filter-mode:
+
+``V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE``
+ (enum)
+
+enum v4l2_mpeg_video_hevc_loop_filter_mode -
+ Loop filter mode for HEVC encoder. Possible values are:
+
+.. raw:: latex
+
+ \footnotesize
+
+.. tabularcolumns:: |p{10.7cm}|p{6.3cm}|
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ * - ``V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED``
+ - Loop filter is disabled.
+ * - ``V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED``
+ - Loop filter is enabled.
+ * - ``V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY``
+ - Loop filter is disabled at the slice boundary.
+
+.. raw:: latex
+
+ \normalsize
+
+
+``V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2 (integer)``
+ Selects HEVC loop filter beta offset. The valid range is [-6, +6].
+
+``V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2 (integer)``
+ Selects HEVC loop filter tc offset. The valid range is [-6, +6].
+
+.. _v4l2-hevc-refresh-type:
+
+``V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE``
+ (enum)
+
+enum v4l2_mpeg_video_hevc_hier_refresh_type -
+ Selects refresh type for HEVC encoder.
+ Host has to specify the period into
+ V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD.
+
+.. raw:: latex
+
+ \footnotesize
+
+.. tabularcolumns:: |p{8.0cm}|p{9.0cm}|
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ * - ``V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE``
+ - Use the B frame for hierarchical coding.
+ * - ``V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA``
+ - Use CRA (Clean Random Access Unit) picture encoding.
+ * - ``V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR``
+ - Use IDR (Instantaneous Decoding Refresh) picture encoding.
+
+.. raw:: latex
+
+ \normalsize
+
+
+``V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD (integer)``
+ Selects the refresh period for HEVC encoder.
+ This specifies the number of I pictures between two CRA/IDR pictures.
+ This is valid only if REFRESH_TYPE is not 0.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU (boolean)``
+ Indicates HEVC lossless encoding. Setting it to 0 disables lossless
+ encoding. Setting it to 1 enables lossless encoding.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED (boolean)``
+ Indicates constant intra prediction for HEVC encoder. Specifies the
+ constrained intra prediction in which intra largest coding unit (LCU)
+ prediction is performed by using residual data and decoded samples of
+ neighboring intra LCU only. Setting the value to 1 enables constant intra
+ prediction and setting the value to 0 disables constant intra prediction.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT (boolean)``
+ Indicates wavefront parallel processing for HEVC encoder. Setting it to 0
+ disables the feature and setting it to 1 enables the wavefront parallel
+ processing.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB (boolean)``
+ Setting the value to 1 enables combination of P and B frame for HEVC
+ encoder.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID (boolean)``
+ Indicates temporal identifier for HEVC encoder which is enabled by
+ setting the value to 1.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING (boolean)``
+ Indicates bi-linear interpolation is conditionally used in the intra
+ prediction filtering process in the CVS when set to 1. Indicates bi-linear
+ interpolation is not used in the CVS when set to 0.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1 (integer)``
+ Indicates maximum number of merge candidate motion vectors.
+ Values are from 0 to 4.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION (boolean)``
+ Indicates temporal motion vector prediction for HEVC encoder. Setting it to
+ 1 enables the prediction. Setting it to 0 disables the prediction.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE (boolean)``
+ Specifies if HEVC generates a stream with a size of the length field
+ instead of start code pattern. The size of the length field is configurable
+ through the V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD control. Setting
+ the value to 0 disables encoding without startcode pattern. Setting the
+ value to 1 will enables encoding without startcode pattern.
+
+.. _v4l2-hevc-size-of-length-field:
+
+``V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD``
+(enum)
+
+enum v4l2_mpeg_video_hevc_size_of_length_field -
+ Indicates the size of length field.
+ This is valid when encoding WITHOUT_STARTCODE_ENABLE is enabled.
+
+.. raw:: latex
+
+ \footnotesize
+
+.. tabularcolumns:: |p{6.0cm}|p{11.0cm}|
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ * - ``V4L2_MPEG_VIDEO_HEVC_SIZE_0``
+ - Generate start code pattern (Normal).
+ * - ``V4L2_MPEG_VIDEO_HEVC_SIZE_1``
+ - Generate size of length field instead of start code pattern and length is 1.
+ * - ``V4L2_MPEG_VIDEO_HEVC_SIZE_2``
+ - Generate size of length field instead of start code pattern and length is 2.
+ * - ``V4L2_MPEG_VIDEO_HEVC_SIZE_4``
+ - Generate size of length field instead of start code pattern and length is 4.
+
+.. raw:: latex
+
+ \normalsize
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR (integer)``
+ Indicates bit rate for hierarchical coding layer 0 for HEVC encoder.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR (integer)``
+ Indicates bit rate for hierarchical coding layer 1 for HEVC encoder.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR (integer)``
+ Indicates bit rate for hierarchical coding layer 2 for HEVC encoder.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR (integer)``
+ Indicates bit rate for hierarchical coding layer 3 for HEVC encoder.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR (integer)``
+ Indicates bit rate for hierarchical coding layer 4 for HEVC encoder.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR (integer)``
+ Indicates bit rate for hierarchical coding layer 5 for HEVC encoder.
+
+``V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR (integer)``
+ Indicates bit rate for hierarchical coding layer 6 for HEVC encoder.
+
+``V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES (integer)``
+ Selects number of P reference pictures required for HEVC encoder.
+ P-Frame can use 1 or 2 frames for reference.
+
+``V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR (integer)``
+ Indicates whether to generate SPS and PPS at every IDR. Setting it to 0
+ disables generating SPS and PPS at every IDR. Setting it to one enables
+ generating SPS and PPS at every IDR.
+
+
.. _camera-controls:
Camera Control Reference
diff --git a/Documentation/media/uapi/v4l/func-poll.rst b/Documentation/media/uapi/v4l/func-poll.rst
index d0432dc09b05..360bc6523ae2 100644
--- a/Documentation/media/uapi/v4l/func-poll.rst
+++ b/Documentation/media/uapi/v4l/func-poll.rst
@@ -39,7 +39,7 @@ When streaming I/O has been negotiated this function waits until a
buffer has been filled by the capture device and can be dequeued with
the :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl. For output devices this
function waits until the device is ready to accept a new buffer to be
-queued up with the :ref:`VIDIOC_QBUF` ioctl for
+queued up with the :ref:`VIDIOC_QBUF <VIDIOC_QBUF>` ioctl for
display. When buffers are already in the outgoing queue of the driver
(capture) or the incoming queue isn't full (display) the function
returns immediately.
@@ -52,11 +52,11 @@ flags in the ``revents`` field, output devices the ``POLLOUT`` and
``POLLWRNORM`` flags. When the function timed out it returns a value of
zero, on failure it returns -1 and the ``errno`` variable is set
appropriately. When the application did not call
-:ref:`VIDIOC_STREAMON` the :ref:`poll() <func-poll>`
+:ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` the :ref:`poll() <func-poll>`
function succeeds, but sets the ``POLLERR`` flag in the ``revents``
field. When the application has called
-:ref:`VIDIOC_STREAMON` for a capture device but
-hasn't yet called :ref:`VIDIOC_QBUF`, the
+:ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` for a capture device but
+hasn't yet called :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`, the
:ref:`poll() <func-poll>` function succeeds and sets the ``POLLERR`` flag in
the ``revents`` field. For output devices this same situation will cause
:ref:`poll() <func-poll>` to succeed as well, but it sets the ``POLLOUT`` and
diff --git a/Documentation/media/uapi/v4l/pixfmt-compressed.rst b/Documentation/media/uapi/v4l/pixfmt-compressed.rst
index 728d7ede10fa..abec03937bb3 100644
--- a/Documentation/media/uapi/v4l/pixfmt-compressed.rst
+++ b/Documentation/media/uapi/v4l/pixfmt-compressed.rst
@@ -90,3 +90,8 @@ Compressed Formats
- ``V4L2_PIX_FMT_VP9``
- 'VP90'
- VP9 video elementary stream.
+ * .. _V4L2-PIX-FMT-HEVC:
+
+ - ``V4L2_PIX_FMT_HEVC``
+ - 'HEVC'
+ - HEVC/H.265 video elementary stream.
diff --git a/Documentation/media/uapi/v4l/pixfmt-v4l2.rst b/Documentation/media/uapi/v4l/pixfmt-v4l2.rst
index 2ee164c25637..6622938c1b41 100644
--- a/Documentation/media/uapi/v4l/pixfmt-v4l2.rst
+++ b/Documentation/media/uapi/v4l/pixfmt-v4l2.rst
@@ -40,7 +40,7 @@ Single-planar format structure
RGB formats in :ref:`rgb-formats`, YUV formats in
:ref:`yuv-formats`, and reserved codes in
:ref:`reserved-formats`
- * - enum :c:type::`v4l2_field`
+ * - enum :c:type:`v4l2_field`
- ``field``
- Video images are typically interlaced. Applications can request to
capture or output only the top or bottom field, or both fields
diff --git a/Documentation/media/uapi/v4l/subdev-formats.rst b/Documentation/media/uapi/v4l/subdev-formats.rst
index b1eea44550e1..9fcabe7f9367 100644
--- a/Documentation/media/uapi/v4l/subdev-formats.rst
+++ b/Documentation/media/uapi/v4l/subdev-formats.rst
@@ -16,10 +16,14 @@ Media Bus Formats
* - __u32
- ``width``
- - Image width, in pixels.
+ - Image width in pixels.
* - __u32
- ``height``
- - Image height, in pixels.
+ - Image height in pixels. If ``field`` is one of ``V4L2_FIELD_TOP``,
+ ``V4L2_FIELD_BOTTOM`` or ``V4L2_FIELD_ALTERNATE`` then height
+ refers to the number of lines in the field, otherwise it refers to
+ the number of lines in the frame (which is twice the field height
+ for interlaced formats).
* - __u32
- ``code``
- Format code, from enum
diff --git a/Documentation/media/uapi/v4l/vidioc-g-parm.rst b/Documentation/media/uapi/v4l/vidioc-g-parm.rst
index 616a5ea3f8fa..e831fa5512f0 100644
--- a/Documentation/media/uapi/v4l/vidioc-g-parm.rst
+++ b/Documentation/media/uapi/v4l/vidioc-g-parm.rst
@@ -66,7 +66,7 @@ union holding separate parameters for input and output devices.
-
- The buffer (stream) type, same as struct
:c:type:`v4l2_format` ``type``, set by the
- application. See :c:type:`v4l2_buf_type`
+ application. See :c:type:`v4l2_buf_type`.
* - union
- ``parm``
-
@@ -75,12 +75,13 @@ union holding separate parameters for input and output devices.
- struct :c:type:`v4l2_captureparm`
- ``capture``
- Parameters for capture devices, used when ``type`` is
- ``V4L2_BUF_TYPE_VIDEO_CAPTURE``.
+ ``V4L2_BUF_TYPE_VIDEO_CAPTURE`` or
+ ``V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE``.
* -
- struct :c:type:`v4l2_outputparm`
- ``output``
- Parameters for output devices, used when ``type`` is
- ``V4L2_BUF_TYPE_VIDEO_OUTPUT``.
+ ``V4L2_BUF_TYPE_VIDEO_OUTPUT`` or ``V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE``.
* -
- __u8
- ``raw_data``\ [200]
diff --git a/Documentation/media/uapi/v4l/vidioc-prepare-buf.rst b/Documentation/media/uapi/v4l/vidioc-prepare-buf.rst
index 70687a86ae38..49f9f4c181de 100644
--- a/Documentation/media/uapi/v4l/vidioc-prepare-buf.rst
+++ b/Documentation/media/uapi/v4l/vidioc-prepare-buf.rst
@@ -34,7 +34,7 @@ Description
Applications can optionally call the :ref:`VIDIOC_PREPARE_BUF` ioctl to
pass ownership of the buffer to the driver before actually enqueuing it,
-using the :ref:`VIDIOC_QBUF` ioctl, and to prepare it for future I/O. Such
+using the :ref:`VIDIOC_QBUF <VIDIOC_QBUF>` ioctl, and to prepare it for future I/O. Such
preparations may include cache invalidation or cleaning. Performing them
in advance saves time during the actual I/O. In case such cache
operations are not required, the application can use one of
diff --git a/Documentation/media/v4l-drivers/imx.rst b/Documentation/media/v4l-drivers/imx.rst
index 3c4f58bda178..65d3d15eb159 100644
--- a/Documentation/media/v4l-drivers/imx.rst
+++ b/Documentation/media/v4l-drivers/imx.rst
@@ -109,7 +109,7 @@ imx6-mipi-csi2
This is the MIPI CSI-2 receiver entity. It has one sink pad to receive
the MIPI CSI-2 stream (usually from a MIPI CSI-2 camera sensor). It has
four source pads, corresponding to the four MIPI CSI-2 demuxed virtual
-channel outputs. Multpiple source pads can be enabled to independently
+channel outputs. Multiple source pads can be enabled to independently
stream from multiple virtual channels.
This entity actually consists of two sub-blocks. One is the MIPI CSI-2
@@ -213,9 +213,11 @@ To give an example of crop and /2 downscale, this will crop a
1280x960 input frame to 640x480, and then /2 downscale in both
dimensions to 320x240 (assumes ipu1_csi0 is linked to ipu1_csi0_mux):
-media-ctl -V "'ipu1_csi0_mux':2[fmt:UYVY2X8/1280x960]"
-media-ctl -V "'ipu1_csi0':0[crop:(0,0)/640x480]"
-media-ctl -V "'ipu1_csi0':0[compose:(0,0)/320x240]"
+.. code-block:: none
+
+ media-ctl -V "'ipu1_csi0_mux':2[fmt:UYVY2X8/1280x960]"
+ media-ctl -V "'ipu1_csi0':0[crop:(0,0)/640x480]"
+ media-ctl -V "'ipu1_csi0':0[compose:(0,0)/320x240]"
Frame Skipping in ipuX_csiY
---------------------------
@@ -229,8 +231,10 @@ at the source pad.
The following example reduces an assumed incoming 60 Hz frame
rate by half at the IDMAC output source pad:
-media-ctl -V "'ipu1_csi0':0[fmt:UYVY2X8/640x480@1/60]"
-media-ctl -V "'ipu1_csi0':2[fmt:UYVY2X8/640x480@1/30]"
+.. code-block:: none
+
+ media-ctl -V "'ipu1_csi0':0[fmt:UYVY2X8/640x480@1/60]"
+ media-ctl -V "'ipu1_csi0':2[fmt:UYVY2X8/640x480@1/30]"
Frame Interval Monitor in ipuX_csiY
-----------------------------------
@@ -422,8 +426,7 @@ This pipeline uses the preprocess encode entity to route frames directly
from the CSI to the IC, to carry out scaling up to 1024x1024 resolution,
CSC, flipping, and image rotation:
--> ipuX_csiY:1 -> 0:ipuX_ic_prp:1 -> 0:ipuX_ic_prpenc:1 ->
- ipuX_ic_prpenc capture
+-> ipuX_csiY:1 -> 0:ipuX_ic_prp:1 -> 0:ipuX_ic_prpenc:1 -> ipuX_ic_prpenc capture
Motion Compensated De-interlace:
--------------------------------
@@ -432,8 +435,7 @@ This pipeline routes frames from the CSI direct pad to the VDIC entity to
support motion-compensated de-interlacing (high motion mode only),
scaling up to 1024x1024, CSC, flip, and rotation:
--> ipuX_csiY:1 -> 0:ipuX_vdic:2 -> 0:ipuX_ic_prp:2 ->
- 0:ipuX_ic_prpvf:1 -> ipuX_ic_prpvf capture
+-> ipuX_csiY:1 -> 0:ipuX_vdic:2 -> 0:ipuX_ic_prp:2 -> 0:ipuX_ic_prpvf:1 -> ipuX_ic_prpvf capture
Usage Notes
@@ -458,8 +460,8 @@ This platform requires the OmniVision OV5642 module with a parallel
camera interface, and the OV5640 module with a MIPI CSI-2
interface. Both modules are available from Boundary Devices:
-https://boundarydevices.com/product/nit6x_5mp
-https://boundarydevices.com/product/nit6x_5mp_mipi
+- https://boundarydevices.com/product/nit6x_5mp
+- https://boundarydevices.com/product/nit6x_5mp_mipi
Note that if only one camera module is available, the other sensor
node can be disabled in the device tree.
diff --git a/Documentation/networking/dpaa2/index.rst b/Documentation/networking/dpaa2/index.rst
new file mode 100644
index 000000000000..4c6586c87969
--- /dev/null
+++ b/Documentation/networking/dpaa2/index.rst
@@ -0,0 +1,8 @@
+===================
+DPAA2 Documentation
+===================
+
+.. toctree::
+ :maxdepth: 1
+
+ overview
diff --git a/drivers/staging/fsl-mc/overview.rst b/Documentation/networking/dpaa2/overview.rst
index 79fede4447d6..79fede4447d6 100644
--- a/drivers/staging/fsl-mc/overview.rst
+++ b/Documentation/networking/dpaa2/overview.rst
diff --git a/Documentation/networking/i40e.txt b/Documentation/networking/i40e.txt
index 57e616ed10b0..c2d6e1824b29 100644
--- a/Documentation/networking/i40e.txt
+++ b/Documentation/networking/i40e.txt
@@ -32,7 +32,7 @@ Enabling the driver
The driver is enabled via the standard kernel configuration system,
using the make command:
- Make oldconfig/silentoldconfig/menuconfig/etc.
+ make config/oldconfig/menuconfig/etc.
The driver is located in the menu structure at:
diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst
index 90966c2692d8..f204eaff657d 100644
--- a/Documentation/networking/index.rst
+++ b/Documentation/networking/index.rst
@@ -8,6 +8,7 @@ Contents:
batman-adv
can
+ dpaa2/index
kapi
z8530book
msg_zerocopy
diff --git a/Documentation/networking/irda.txt b/Documentation/networking/irda.txt
deleted file mode 100644
index bff26c138be6..000000000000
--- a/Documentation/networking/irda.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-To use the IrDA protocols within Linux you will need to get a suitable copy
-of the IrDA Utilities. More detailed information about these and associated
-programs can be found on http://irda.sourceforge.net/
-
-For more information about how to use the IrDA protocol stack, see the
-Linux Infrared HOWTO by Werner Heuser <wehe@tuxmobil.org>:
-<http://www.tuxmobil.org/Infrared-HOWTO/Infrared-HOWTO.html>
-
-There is an active mailing list for discussing Linux-IrDA matters called
- irda-users@lists.sourceforge.net
diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst
index 5470f1b74375..ddc029734b25 100644
--- a/Documentation/process/changes.rst
+++ b/Documentation/process/changes.rst
@@ -78,7 +78,7 @@ Binutils
--------
The build system has, as of 4.13, switched to using thin archives (`ar T`)
-rather than incremental linking (`ld -r`) for built-in.o intermediate steps.
+rather than incremental linking (`ld -r`) for built-in.a intermediate steps.
This requires binutils 2.20 or newer.
Flex
diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
index 0bc33ad4a3f9..fdf5fb54a04c 100644
--- a/Documentation/trace/ftrace.rst
+++ b/Documentation/trace/ftrace.rst
@@ -461,21 +461,13 @@ of ftrace. Here is a list of some of the key files:
and ticks at the same rate as the hardware clocksource.
boot:
- This is the boot clock (CLOCK_BOOTTIME) and is based on the
- fast monotonic clock, but also accounts for time spent in
- suspend. Since the clock access is designed for use in
- tracing in the suspend path, some side effects are possible
- if clock is accessed after the suspend time is accounted before
- the fast mono clock is updated. In this case, the clock update
- appears to happen slightly sooner than it normally would have.
- Also on 32-bit systems, it's possible that the 64-bit boot offset
- sees a partial update. These effects are rare and post
- processing should be able to handle them. See comments in the
- ktime_get_boot_fast_ns() function for more information.
-
- To set a clock, simply echo the clock name into this file::
-
- echo global > trace_clock
+ Same as mono. Used to be a separate clock which accounted
+ for the time spent in suspend while CLOCK_MONOTONIC did
+ not.
+
+ To set a clock, simply echo the clock name into this file::
+
+ # echo global > trace_clock
trace_marker:
diff --git a/MAINTAINERS b/MAINTAINERS
index f830fc9abe00..89fd8040e295 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3252,12 +3252,11 @@ F: drivers/net/ieee802154/cc2520.c
F: include/linux/spi/cc2520.h
F: Documentation/devicetree/bindings/net/ieee802154/cc2520.txt
-CCREE ARM TRUSTZONE CRYPTOCELL 700 REE DRIVER
+CCREE ARM TRUSTZONE CRYPTOCELL REE DRIVER
M: Gilad Ben-Yossef <gilad@benyossef.com>
L: linux-crypto@vger.kernel.org
-L: driverdev-devel@linuxdriverproject.org
S: Supported
-F: drivers/staging/ccree/
+F: drivers/crypto/ccree/
W: https://developer.arm.com/products/system-ip/trustzone-cryptocell/cryptocell-700-family
CEC FRAMEWORK
@@ -3275,6 +3274,7 @@ F: include/media/cec-notifier.h
F: include/uapi/linux/cec.h
F: include/uapi/linux/cec-funcs.h
F: Documentation/devicetree/bindings/media/cec.txt
+F: Documentation/ABI/testing/debugfs-cec-error-inj
CEC GPIO DRIVER
M: Hans Verkuil <hans.verkuil@cisco.com>
@@ -4079,7 +4079,7 @@ S: Supported
F: drivers/mtd/nand/denali*
DESIGNWARE USB2 DRD IP DRIVER
-M: John Youn <johnyoun@synopsys.com>
+M: Minas Harutyunyan <hminas@synopsys.com>
L: linux-usb@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
S: Maintained
@@ -4370,6 +4370,12 @@ L: linux-kernel@vger.kernel.org
S: Maintained
F: drivers/staging/fsl-dpaa2/ethernet
+DPAA2 ETHERNET SWITCH DRIVER
+M: Razvan Stefanescu <razvan.stefanescu@nxp.com>
+L: linux-kernel@vger.kernel.org
+S: Maintained
+F: drivers/staging/fsl-dpaa2/ethsw
+
DPT_I2O SCSI RAID DRIVER
M: Adaptec OEM Raid Solutions <aacraid@adaptec.com>
L: linux-scsi@vger.kernel.org
@@ -5518,7 +5524,7 @@ M: Luis R. Rodriguez <mcgrof@kernel.org>
L: linux-kernel@vger.kernel.org
S: Maintained
F: Documentation/firmware_class/
-F: drivers/base/firmware*.c
+F: drivers/base/firmware_loader/
F: include/linux/firmware.h
FLASH ADAPTER DRIVER (IBM Flash Adapter 900GB Full Height PCI Flash Card)
@@ -6206,6 +6212,11 @@ F: Documentation/hw_random.txt
F: drivers/char/hw_random/
F: include/linux/hw_random.h
+HARDWARE TRACING FACILITIES
+M: Alexander Shishkin <alexander.shishkin@linux.intel.com>
+S: Maintained
+F: drivers/hwtracing/
+
HARDWARE SPINLOCK CORE
M: Ohad Ben-Cohen <ohad@wizery.com>
M: Bjorn Andersson <bjorn.andersson@linaro.org>
@@ -6865,6 +6876,13 @@ M: James Hogan <jhogan@kernel.org>
S: Maintained
F: drivers/media/rc/img-ir/
+IMON SOUNDGRAPH USB IR RECEIVER
+M: Sean Young <sean@mess.org>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: drivers/media/rc/imon_raw.c
+F: drivers/media/rc/imon.c
+
IMS TWINTURBO FRAMEBUFFER DRIVER
L: linux-fbdev@vger.kernel.org
S: Orphan
@@ -6954,7 +6972,7 @@ F: drivers/input/input-mt.c
K: \b(ABS|SYN)_MT_
INSIDE SECURE CRYPTO DRIVER
-M: Antoine Tenart <antoine.tenart@free-electrons.com>
+M: Antoine Tenart <antoine.tenart@bootlin.com>
F: drivers/crypto/inside-secure/
S: Maintained
L: linux-crypto@vger.kernel.org
@@ -7192,6 +7210,14 @@ L: linux-rdma@vger.kernel.org
S: Supported
F: drivers/infiniband/hw/i40iw/
+INTEL SHA MULTIBUFFER DRIVER
+M: Megha Dey <megha.dey@linux.intel.com>
+R: Tim Chen <tim.c.chen@linux.intel.com>
+L: linux-crypto@vger.kernel.org
+S: Supported
+F: arch/x86/crypto/sha*-mb
+F: crypto/mcryptd.c
+
INTEL TELEMETRY DRIVER
M: Souvik Kumar Chakravarty <souvik.k.chakravarty@intel.com>
L: platform-driver-x86@vger.kernel.org
@@ -8119,7 +8145,7 @@ F: drivers/*/*/*pasemi*
LINUX KERNEL DUMP TEST MODULE (LKDTM)
M: Kees Cook <keescook@chromium.org>
S: Maintained
-F: drivers/misc/lkdtm*
+F: drivers/misc/lkdtm/*
LINUX KERNEL MEMORY CONSISTENCY MODEL (LKMM)
M: Alan Stern <stern@rowland.harvard.edu>
@@ -8572,11 +8598,12 @@ W: https://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-maxiradio*
-MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVER
+MCP4018 AND MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVERS
M: Peter Rosin <peda@axentia.se>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-iio-potentiometer-mcp4531
+F: drivers/iio/potentiometer/mcp4018.c
F: drivers/iio/potentiometer/mcp4531.c
MCR20A IEEE-802.15.4 RADIO DRIVER
@@ -8604,6 +8631,14 @@ T: git git://linuxtv.org/media_tree.git
S: Supported
F: drivers/media/dvb-frontends/ascot2e*
+MEDIA DRIVERS FOR CXD2099AR CI CONTROLLERS
+M: Jasmin Jessich <jasmin@anw.at>
+L: linux-media@vger.kernel.org
+W: https://linuxtv.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/dvb-frontends/cxd2099*
+
MEDIA DRIVERS FOR CXD2841ER
M: Sergey Kozlov <serjk@netup.ru>
M: Abylay Ospan <aospan@netup.ru>
@@ -8614,6 +8649,15 @@ T: git git://linuxtv.org/media_tree.git
S: Supported
F: drivers/media/dvb-frontends/cxd2841er*
+MEDIA DRIVERS FOR CXD2880
+M: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
+L: linux-media@vger.kernel.org
+W: http://linuxtv.org/
+T: git git://linuxtv.org/media_tree.git
+S: Supported
+F: drivers/media/dvb-frontends/cxd2880/*
+F: drivers/media/spi/cxd2880*
+
MEDIA DRIVERS FOR DIGITAL DEVICES PCIE DEVICES
M: Daniel Scheller <d.scheller.oss@gmail.com>
L: linux-media@vger.kernel.org
@@ -8681,6 +8725,16 @@ T: git git://linuxtv.org/media_tree.git
S: Supported
F: drivers/media/pci/netup_unidvb/*
+MEDIA DRIVERS FOR RENESAS - CEU
+M: Jacopo Mondi <jacopo@jmondi.org>
+L: linux-media@vger.kernel.org
+L: linux-renesas-soc@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Supported
+F: Documentation/devicetree/bindings/media/renesas,ceu.txt
+F: drivers/media/platform/renesas-ceu.c
+F: include/media/drv-intf/renesas-ceu.h
+
MEDIA DRIVERS FOR RENESAS - DRIF
M: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
L: linux-media@vger.kernel.org
@@ -8873,6 +8927,13 @@ W: http://www.melexis.com
S: Supported
F: drivers/iio/temperature/mlx90614.c
+MELEXIS MLX90632 DRIVER
+M: Crt Mori <cmo@melexis.com>
+L: linux-iio@vger.kernel.org
+W: http://www.melexis.com
+S: Supported
+F: drivers/iio/temperature/mlx90632.c
+
MELFAS MIP4 TOUCHSCREEN DRIVER
M: Sangwon Jee <jeesw@melfas.com>
W: http://www.melfas.com
@@ -9365,6 +9426,14 @@ S: Maintained
F: drivers/media/i2c/mt9t001.c
F: include/media/i2c/mt9t001.h
+MT9T112 APTINA CAMERA SENSOR
+M: Jacopo Mondi <jacopo@jmondi.org>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Odd Fixes
+F: drivers/media/i2c/mt9t112.c
+F: include/media/i2c/mt9t112.h
+
MT9V032 APTINA CAMERA SENSOR
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: linux-media@vger.kernel.org
@@ -10170,6 +10239,13 @@ T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/i2c/ov13858.c
+OMNIVISION OV2685 SENSOR DRIVER
+M: Shunqian Zheng <zhengsq@rock-chips.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/i2c/ov2685.c
+
OMNIVISION OV5640 SENSOR DRIVER
M: Steve Longerbeam <slongerbeam@gmail.com>
L: linux-media@vger.kernel.org
@@ -10184,6 +10260,13 @@ T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/i2c/ov5647.c
+OMNIVISION OV5695 SENSOR DRIVER
+M: Shunqian Zheng <zhengsq@rock-chips.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/i2c/ov5695.c
+
OMNIVISION OV7670 SENSOR DRIVER
M: Jonathan Corbet <corbet@lwn.net>
L: linux-media@vger.kernel.org
@@ -10192,6 +10275,14 @@ S: Maintained
F: drivers/media/i2c/ov7670.c
F: Documentation/devicetree/bindings/media/i2c/ov7670.txt
+OMNIVISION OV772x SENSOR DRIVER
+M: Jacopo Mondi <jacopo@jmondi.org>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Odd fixes
+F: drivers/media/i2c/ov772x.c
+F: include/media/i2c/ov772x.h
+
OMNIVISION OV7740 SENSOR DRIVER
M: Wenyou Yang <wenyou.yang@microchip.com>
L: linux-media@vger.kernel.org
@@ -10200,6 +10291,16 @@ S: Maintained
F: drivers/media/i2c/ov7740.c
F: Documentation/devicetree/bindings/media/i2c/ov7740.txt
+OMNIVISION OV9650 SENSOR DRIVER
+M: Sakari Ailus <sakari.ailus@linux.intel.com>
+R: Akinobu Mita <akinobu.mita@gmail.com>
+R: Sylwester Nawrocki <s.nawrocki@samsung.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/i2c/ov9650.c
+F: Documentation/devicetree/bindings/media/i2c/ov9650.txt
+
ONENAND FLASH DRIVER
M: Kyungmin Park <kyungmin.park@samsung.com>
L: linux-mtd@lists.infradead.org
@@ -11447,8 +11548,9 @@ M: Stuart Yoder <stuyoder@gmail.com>
M: Laurentiu Tudor <laurentiu.tudor@nxp.com>
L: linux-kernel@vger.kernel.org
S: Maintained
-F: drivers/staging/fsl-mc/
+F: drivers/bus/fsl-mc/
F: Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
+F: Documentation/networking/dpaa2/overview.rst
QT1010 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
@@ -12780,10 +12882,9 @@ S: Maintained
F: drivers/net/ethernet/smsc/smsc9420.*
SOC-CAMERA V4L2 SUBSYSTEM
-M: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-S: Maintained
+S: Orphan
F: include/media/soc*
F: drivers/media/i2c/soc_camera/
F: drivers/media/platform/soc_camera/
@@ -13512,6 +13613,14 @@ T: git git://linuxtv.org/mkrufky/tuners.git
S: Maintained
F: drivers/media/tuners/tda18271*
+TDA1997x MEDIA DRIVER
+M: Tim Harvey <tharvey@gateworks.com>
+L: linux-media@vger.kernel.org
+W: https://linuxtv.org
+Q: http://patchwork.linuxtv.org/project/linux-media/list/
+S: Maintained
+F: drivers/media/i2c/tda1997x.*
+
TDA827x MEDIA DRIVER
M: Michael Krufky <mkrufky@linuxtv.org>
L: linux-media@vger.kernel.org
@@ -13593,6 +13702,12 @@ L: linux-media@vger.kernel.org
S: Maintained
F: drivers/media/rc/ttusbir.c
+TECHWELL TW9910 VIDEO DECODER
+L: linux-media@vger.kernel.org
+S: Orphan
+F: drivers/media/i2c/tw9910.c
+F: include/media/i2c/tw9910.h
+
TEE SUBSYSTEM
M: Jens Wiklander <jens.wiklander@linaro.org>
S: Maintained
@@ -14381,6 +14496,12 @@ S: Maintained
F: Documentation/hid/hiddev.txt
F: drivers/hid/usbhid/
+USB INTEL XHCI ROLE MUX DRIVER
+M: Hans de Goede <hdegoede@redhat.com>
+L: linux-usb@vger.kernel.org
+S: Maintained
+F: drivers/usb/roles/intel-xhci-usb-role-switch.c
+
USB ISP116X DRIVER
M: Olav Kongas <ok@artecdesign.ee>
L: linux-usb@vger.kernel.org
@@ -14511,6 +14632,12 @@ F: drivers/usb/
F: include/linux/usb.h
F: include/linux/usb/
+USB TYPEC PI3USB30532 MUX DRIVER
+M: Hans de Goede <hdegoede@redhat.com>
+L: linux-usb@vger.kernel.org
+S: Maintained
+F: drivers/usb/typec/mux/pi3usb30532.c
+
USB TYPEC SUBSYSTEM
M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
L: linux-usb@vger.kernel.org
diff --git a/Makefile b/Makefile
index d3300e46f925..c1a608a1bc4c 100644
--- a/Makefile
+++ b/Makefile
@@ -35,7 +35,7 @@ unexport GREP_OPTIONS
# Most importantly: sub-Makefiles should only ever modify files in
# their own directory. If in some directory we have a dependency on
# a file in another dir (which doesn't happen often, but it's often
-# unavoidable when linking the built-in.o targets which finally
+# unavoidable when linking the built-in.a targets which finally
# turn into vmlinux), we will call a sub make in that other dir, and
# after that we are sure that everything which is in that other dir
# is now up to date.
@@ -220,7 +220,8 @@ export srctree objtree VPATH
version_h := include/generated/uapi/linux/version.h
old_version_h := include/linux/version.h
-no-dot-config-targets := clean mrproper distclean \
+clean-targets := %clean mrproper cleandocs
+no-dot-config-targets := $(clean-targets) \
cscope gtags TAGS tags help% %docs check% coccicheck \
$(version_h) headers_% archheaders archscripts \
kernelversion %src-pkg
@@ -243,6 +244,14 @@ ifeq ($(KBUILD_EXTMOD),)
endif
endif
endif
+
+# For "make -j clean all", "make -j mrproper defconfig all", etc.
+ifneq ($(filter $(clean-targets),$(MAKECMDGOALS)),)
+ ifneq ($(filter-out $(clean-targets),$(MAKECMDGOALS)),)
+ mixed-targets := 1
+ endif
+endif
+
# install and modules_install need also be processed one by one
ifneq ($(filter install,$(MAKECMDGOALS)),)
ifneq ($(filter modules_install,$(MAKECMDGOALS)),)
@@ -377,6 +386,8 @@ INSTALLKERNEL := installkernel
DEPMOD = /sbin/depmod
PERL = perl
PYTHON = python
+PYTHON2 = python2
+PYTHON3 = python3
CHECK = sparse
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
@@ -418,11 +429,12 @@ KBUILD_CFLAGS_KERNEL :=
KBUILD_AFLAGS_MODULE := -DMODULE
KBUILD_CFLAGS_MODULE := -DMODULE
KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
+LDFLAGS :=
GCC_PLUGINS_CFLAGS :=
export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC
export CPP AR NM STRIP OBJCOPY OBJDUMP HOSTLDFLAGS HOST_LOADLIBES
-export MAKE LEX YACC AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE
+export MAKE LEX YACC AWK GENKSYMS INSTALLKERNEL PERL PYTHON PYTHON2 PYTHON3 UTS_MACHINE
export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
@@ -556,14 +568,6 @@ endif
export KBUILD_MODULES KBUILD_BUILTIN
ifeq ($(KBUILD_EXTMOD),)
-# Additional helpers built in scripts/
-# Carefully list dependencies so we do not try to build scripts twice
-# in parallel
-PHONY += scripts
-scripts: scripts_basic include/config/auto.conf include/config/tristate.conf \
- asm-generic gcc-plugins
- $(Q)$(MAKE) $(build)=$(@)
-
# Objects we will link into vmlinux / subdirs we need to visit
init-y := init/
drivers-y := drivers/ sound/ firmware/
@@ -589,7 +593,7 @@ $(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
# include/generated/ and include/config/. Update them if .config is newer than
# include/config/auto.conf (which mirrors .config).
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
- $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
+ $(Q)$(MAKE) -f $(srctree)/Makefile syncconfig
else
# external modules needs include/generated/autoconf.h and include/config/auto.conf
# but do not care if they are up-to-date. Use auto.conf to trigger the test
@@ -611,13 +615,6 @@ else
include/config/auto.conf: ;
endif # $(dot-config)
-# For the kernel to actually contain only the needed exported symbols,
-# we have to build modules as well to determine what those symbols are.
-# (this can be evaluated only once include/config/auto.conf has been included)
-ifdef CONFIG_TRIM_UNUSED_KSYMS
- KBUILD_MODULES := 1
-endif
-
# The all: target is the default when no target is given on the
# command line.
# This allow a user to issue only 'make' to build a kernel including modules
@@ -984,13 +981,13 @@ vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
vmlinux-alldirs := $(sort $(vmlinux-dirs) $(patsubst %/,%,$(filter %/, \
$(init-) $(core-) $(drivers-) $(net-) $(libs-) $(virt-))))
-init-y := $(patsubst %/, %/built-in.o, $(init-y))
-core-y := $(patsubst %/, %/built-in.o, $(core-y))
-drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y))
-net-y := $(patsubst %/, %/built-in.o, $(net-y))
+init-y := $(patsubst %/, %/built-in.a, $(init-y))
+core-y := $(patsubst %/, %/built-in.a, $(core-y))
+drivers-y := $(patsubst %/, %/built-in.a, $(drivers-y))
+net-y := $(patsubst %/, %/built-in.a, $(net-y))
libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
-libs-y2 := $(filter-out %.a, $(patsubst %/, %/built-in.o, $(libs-y)))
-virt-y := $(patsubst %/, %/built-in.o, $(virt-y))
+libs-y2 := $(patsubst %/, %/built-in.a, $(filter-out %.a, $(libs-y)))
+virt-y := $(patsubst %/, %/built-in.a, $(virt-y))
# Externally visible symbols (used by link-vmlinux.sh)
export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)
@@ -1003,25 +1000,26 @@ export KBUILD_ALLDIRS := $(sort $(filter-out arch/%,$(vmlinux-alldirs)) arch Doc
vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN) $(KBUILD_VMLINUX_LIBS)
-# Include targets which we want to execute sequentially if the rest of the
-# kernel build went well. If CONFIG_TRIM_UNUSED_KSYMS is set, this might be
-# evaluated more than once.
-PHONY += vmlinux_prereq
-vmlinux_prereq: $(vmlinux-deps) FORCE
-ifdef CONFIG_HEADERS_CHECK
- $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
-endif
-ifdef CONFIG_GDB_SCRIPTS
- $(Q)ln -fsn $(abspath $(srctree)/scripts/gdb/vmlinux-gdb.py)
-endif
+# Recurse until adjust_autoksyms.sh is satisfied
+PHONY += autoksyms_recursive
+autoksyms_recursive: $(vmlinux-deps)
ifdef CONFIG_TRIM_UNUSED_KSYMS
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh \
"$(MAKE) -f $(srctree)/Makefile vmlinux"
endif
-# standalone target for easier testing
-include/generated/autoksyms.h: FORCE
- $(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh true
+# For the kernel to actually contain only the needed exported symbols,
+# we have to build modules as well to determine what those symbols are.
+# (this can be evaluated only once include/config/auto.conf has been included)
+ifdef CONFIG_TRIM_UNUSED_KSYMS
+ KBUILD_MODULES := 1
+endif
+
+autoksyms_h := $(if $(CONFIG_TRIM_UNUSED_KSYMS), include/generated/autoksyms.h)
+
+$(autoksyms_h):
+ $(Q)mkdir -p $(dir $@)
+ $(Q)touch $@
ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink)
@@ -1030,7 +1028,13 @@ cmd_link-vmlinux = \
$(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) ; \
$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)
-vmlinux: scripts/link-vmlinux.sh vmlinux_prereq $(vmlinux-deps) FORCE
+vmlinux: scripts/link-vmlinux.sh autoksyms_recursive $(vmlinux-deps) FORCE
+ifdef CONFIG_HEADERS_CHECK
+ $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
+endif
+ifdef CONFIG_GDB_SCRIPTS
+ $(Q)ln -fsn $(abspath $(srctree)/scripts/gdb/vmlinux-gdb.py)
+endif
+$(call if_changed,link-vmlinux)
# Build samples along the rest of the kernel
@@ -1060,6 +1064,13 @@ endef
include/config/kernel.release: include/config/auto.conf FORCE
$(call filechk,kernel.release)
+# Additional helpers built in scripts/
+# Carefully list dependencies so we do not try to build scripts twice
+# in parallel
+PHONY += scripts
+scripts: scripts_basic include/config/auto.conf include/config/tristate.conf \
+ asm-generic gcc-plugins $(autoksyms_h)
+ $(Q)$(MAKE) $(build)=$(@)
# Things we need to do before we recursively start building the kernel
# or the modules are listed in "prepare".
@@ -1088,7 +1099,7 @@ endif
# that need to depend on updated CONFIG_* values can be checked here.
prepare2: prepare3 prepare-compiler-check outputmakefile asm-generic
-prepare1: prepare2 $(version_h) include/generated/utsrelease.h \
+prepare1: prepare2 $(version_h) $(autoksyms_h) include/generated/utsrelease.h \
include/config/auto.conf
$(cmd_crmodverdir)
@@ -1327,7 +1338,7 @@ endif # CONFIG_MODULES
# make distclean Remove editor backup files, patch leftover files and the like
# Directories & files removed with 'make clean'
-CLEAN_DIRS += $(MODVERDIR)
+CLEAN_DIRS += $(MODVERDIR) include/ksym
# Directories & files removed with 'make mrproper'
MRPROPER_DIRS += include/config usr/include include/generated \
diff --git a/arch/Kconfig b/arch/Kconfig
index 76c0b54443b1..8e0d665c8d53 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -596,12 +596,6 @@ config CC_STACKPROTECTOR_AUTO
endchoice
-config THIN_ARCHIVES
- def_bool y
- help
- Select this if the architecture wants to use thin archives
- instead of ld -r to create the built-in.o files.
-
config LD_DEAD_CODE_DATA_ELIMINATION
bool
help
diff --git a/arch/arm/boot/deflate_xip_data.sh b/arch/arm/boot/deflate_xip_data.sh
index 5e7d758ebdd6..b7fa67d2d9e3 100755
--- a/arch/arm/boot/deflate_xip_data.sh
+++ b/arch/arm/boot/deflate_xip_data.sh
@@ -45,7 +45,7 @@ data_start=$(($__data_loc - $base_offset))
data_end=$(($_edata_loc - $base_offset))
# Make sure data occupies the last part of the file.
-file_end=$(stat -c "%s" "$XIPIMAGE")
+file_end=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" "$XIPIMAGE")
if [ "$file_end" != "$data_end" ]; then
printf "end of xipImage doesn't match with _edata_loc (%#x vs %#x)\n" \
$(($file_end + $base_offset)) $_edata_loc 1>&2
diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index e36c392a2b8f..593f58d4ac0f 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -27,6 +27,12 @@
firmware = <&firmware>;
#power-domain-cells = <1>;
};
+
+ mailbox@7e00b840 {
+ compatible = "brcm,bcm2835-vchiq";
+ reg = <0x7e00b840 0xf>;
+ interrupts = <0 2>;
+ };
};
};
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index c31dad98f989..728e206009ea 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -587,7 +587,8 @@
device_type = "mdio";
#address-cells = <1>;
#size-cells = <0>;
- reg = <0x0 0x2d24000 0x0 0x4000>;
+ reg = <0x0 0x2d24000 0x0 0x4000>,
+ <0x0 0x2d10030 0x0 0x4>;
};
ptp_clock@2d10e00 {
diff --git a/arch/arm/boot/dts/stih407-b2120.dts b/arch/arm/boot/dts/stih407-b2120.dts
index c8ad905d0309..a7a0f76e9cbc 100644
--- a/arch/arm/boot/dts/stih407-b2120.dts
+++ b/arch/arm/boot/dts/stih407-b2120.dts
@@ -14,7 +14,7 @@
compatible = "st,stih407-b2120", "st,stih407";
chosen {
- bootargs = "console=ttyAS0,115200 clk_ignore_unused";
+ bootargs = "clk_ignore_unused";
linux,stdout-path = &sbc_serial0;
};
@@ -24,7 +24,7 @@
};
aliases {
- ttyAS0 = &sbc_serial0;
+ serial0 = &sbc_serial0;
ethernet0 = &ethernet0;
};
diff --git a/arch/arm/boot/dts/stih410-b2120.dts b/arch/arm/boot/dts/stih410-b2120.dts
index 9830be577433..6c6b4cc37e97 100644
--- a/arch/arm/boot/dts/stih410-b2120.dts
+++ b/arch/arm/boot/dts/stih410-b2120.dts
@@ -14,7 +14,7 @@
compatible = "st,stih410-b2120", "st,stih410";
chosen {
- bootargs = "console=ttyAS0,115200 clk_ignore_unused";
+ bootargs = "clk_ignore_unused";
linux,stdout-path = &sbc_serial0;
};
@@ -24,7 +24,7 @@
};
aliases {
- ttyAS0 = &sbc_serial0;
+ serial0 = &sbc_serial0;
ethernet0 = &ethernet0;
};
diff --git a/arch/arm/boot/dts/stih410-b2260.dts b/arch/arm/boot/dts/stih410-b2260.dts
index c663b70c43a7..50d36758391c 100644
--- a/arch/arm/boot/dts/stih410-b2260.dts
+++ b/arch/arm/boot/dts/stih410-b2260.dts
@@ -15,7 +15,7 @@
compatible = "st,stih410-b2260", "st,stih410";
chosen {
- bootargs = "console=ttyAS1,115200 clk_ignore_unused";
+ bootargs = "clk_ignore_unused";
linux,stdout-path = &uart1;
};
@@ -25,7 +25,7 @@
};
aliases {
- ttyAS1 = &uart1;
+ serial1 = &uart1;
ethernet0 = &ethernet0;
};
diff --git a/arch/arm/boot/dts/stih418-b2199.dts b/arch/arm/boot/dts/stih418-b2199.dts
index 4e6d915c85ff..7f5f3252bfc7 100644
--- a/arch/arm/boot/dts/stih418-b2199.dts
+++ b/arch/arm/boot/dts/stih418-b2199.dts
@@ -14,7 +14,7 @@
compatible = "st,stih418-b2199", "st,stih418";
chosen {
- bootargs = "console=ttyAS0,115200 clk_ignore_unused";
+ bootargs = "clk_ignore_unused";
linux,stdout-path = &sbc_serial0;
};
@@ -24,7 +24,7 @@
};
aliases {
- ttyAS0 = &sbc_serial0;
+ serial0 = &sbc_serial0;
ethernet0 = &ethernet0;
};
diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig
index b8e69fe282b8..925d1364727a 100644
--- a/arch/arm/crypto/Kconfig
+++ b/arch/arm/crypto/Kconfig
@@ -121,4 +121,10 @@ config CRYPTO_CHACHA20_NEON
select CRYPTO_BLKCIPHER
select CRYPTO_CHACHA20
+config CRYPTO_SPECK_NEON
+ tristate "NEON accelerated Speck cipher algorithms"
+ depends on KERNEL_MODE_NEON
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_SPECK
+
endif
diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile
index 30ef8e291271..3304e671918d 100644
--- a/arch/arm/crypto/Makefile
+++ b/arch/arm/crypto/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o
obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o
obj-$(CONFIG_CRYPTO_SHA512_ARM) += sha512-arm.o
obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha20-neon.o
+obj-$(CONFIG_CRYPTO_SPECK_NEON) += speck-neon.o
ce-obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o
ce-obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o
@@ -53,7 +54,9 @@ ghash-arm-ce-y := ghash-ce-core.o ghash-ce-glue.o
crct10dif-arm-ce-y := crct10dif-ce-core.o crct10dif-ce-glue.o
crc32-arm-ce-y:= crc32-ce-core.o crc32-ce-glue.o
chacha20-neon-y := chacha20-neon-core.o chacha20-neon-glue.o
+speck-neon-y := speck-neon-core.o speck-neon-glue.o
+ifdef REGENERATE_ARM_CRYPTO
quiet_cmd_perl = PERL $@
cmd_perl = $(PERL) $(<) > $(@)
@@ -62,5 +65,6 @@ $(src)/sha256-core.S_shipped: $(src)/sha256-armv4.pl
$(src)/sha512-core.S_shipped: $(src)/sha512-armv4.pl
$(call cmd,perl)
+endif
.PRECIOUS: $(obj)/sha256-core.S $(obj)/sha512-core.S
diff --git a/arch/arm/crypto/aes-cipher-core.S b/arch/arm/crypto/aes-cipher-core.S
index 54b384084637..184d6c2d15d5 100644
--- a/arch/arm/crypto/aes-cipher-core.S
+++ b/arch/arm/crypto/aes-cipher-core.S
@@ -174,6 +174,16 @@
.ltorg
.endm
+ENTRY(__aes_arm_encrypt)
+ do_crypt fround, crypto_ft_tab, crypto_ft_tab + 1, 2
+ENDPROC(__aes_arm_encrypt)
+
+ .align 5
+ENTRY(__aes_arm_decrypt)
+ do_crypt iround, crypto_it_tab, __aes_arm_inverse_sbox, 0
+ENDPROC(__aes_arm_decrypt)
+
+ .section ".rodata", "a"
.align L1_CACHE_SHIFT
.type __aes_arm_inverse_sbox, %object
__aes_arm_inverse_sbox:
@@ -210,12 +220,3 @@ __aes_arm_inverse_sbox:
.byte 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26
.byte 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
.size __aes_arm_inverse_sbox, . - __aes_arm_inverse_sbox
-
-ENTRY(__aes_arm_encrypt)
- do_crypt fround, crypto_ft_tab, crypto_ft_tab + 1, 2
-ENDPROC(__aes_arm_encrypt)
-
- .align 5
-ENTRY(__aes_arm_decrypt)
- do_crypt iround, crypto_it_tab, __aes_arm_inverse_sbox, 0
-ENDPROC(__aes_arm_decrypt)
diff --git a/arch/arm/crypto/speck-neon-core.S b/arch/arm/crypto/speck-neon-core.S
new file mode 100644
index 000000000000..3c1e203e53b9
--- /dev/null
+++ b/arch/arm/crypto/speck-neon-core.S
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS
+ *
+ * Copyright (c) 2018 Google, Inc
+ *
+ * Author: Eric Biggers <ebiggers@google.com>
+ */
+
+#include <linux/linkage.h>
+
+ .text
+ .fpu neon
+
+ // arguments
+ ROUND_KEYS .req r0 // const {u64,u32} *round_keys
+ NROUNDS .req r1 // int nrounds
+ DST .req r2 // void *dst
+ SRC .req r3 // const void *src
+ NBYTES .req r4 // unsigned int nbytes
+ TWEAK .req r5 // void *tweak
+
+ // registers which hold the data being encrypted/decrypted
+ X0 .req q0
+ X0_L .req d0
+ X0_H .req d1
+ Y0 .req q1
+ Y0_H .req d3
+ X1 .req q2
+ X1_L .req d4
+ X1_H .req d5
+ Y1 .req q3
+ Y1_H .req d7
+ X2 .req q4
+ X2_L .req d8
+ X2_H .req d9
+ Y2 .req q5
+ Y2_H .req d11
+ X3 .req q6
+ X3_L .req d12
+ X3_H .req d13
+ Y3 .req q7
+ Y3_H .req d15
+
+ // the round key, duplicated in all lanes
+ ROUND_KEY .req q8
+ ROUND_KEY_L .req d16
+ ROUND_KEY_H .req d17
+
+ // index vector for vtbl-based 8-bit rotates
+ ROTATE_TABLE .req d18
+
+ // multiplication table for updating XTS tweaks
+ GF128MUL_TABLE .req d19
+ GF64MUL_TABLE .req d19
+
+ // current XTS tweak value(s)
+ TWEAKV .req q10
+ TWEAKV_L .req d20
+ TWEAKV_H .req d21
+
+ TMP0 .req q12
+ TMP0_L .req d24
+ TMP0_H .req d25
+ TMP1 .req q13
+ TMP2 .req q14
+ TMP3 .req q15
+
+ .align 4
+.Lror64_8_table:
+ .byte 1, 2, 3, 4, 5, 6, 7, 0
+.Lror32_8_table:
+ .byte 1, 2, 3, 0, 5, 6, 7, 4
+.Lrol64_8_table:
+ .byte 7, 0, 1, 2, 3, 4, 5, 6
+.Lrol32_8_table:
+ .byte 3, 0, 1, 2, 7, 4, 5, 6
+.Lgf128mul_table:
+ .byte 0, 0x87
+ .fill 14
+.Lgf64mul_table:
+ .byte 0, 0x1b, (0x1b << 1), (0x1b << 1) ^ 0x1b
+ .fill 12
+
+/*
+ * _speck_round_128bytes() - Speck encryption round on 128 bytes at a time
+ *
+ * Do one Speck encryption round on the 128 bytes (8 blocks for Speck128, 16 for
+ * Speck64) stored in X0-X3 and Y0-Y3, using the round key stored in all lanes
+ * of ROUND_KEY. 'n' is the lane size: 64 for Speck128, or 32 for Speck64.
+ *
+ * The 8-bit rotates are implemented using vtbl instead of vshr + vsli because
+ * the vtbl approach is faster on some processors and the same speed on others.
+ */
+.macro _speck_round_128bytes n
+
+ // x = ror(x, 8)
+ vtbl.8 X0_L, {X0_L}, ROTATE_TABLE
+ vtbl.8 X0_H, {X0_H}, ROTATE_TABLE
+ vtbl.8 X1_L, {X1_L}, ROTATE_TABLE
+ vtbl.8 X1_H, {X1_H}, ROTATE_TABLE
+ vtbl.8 X2_L, {X2_L}, ROTATE_TABLE
+ vtbl.8 X2_H, {X2_H}, ROTATE_TABLE
+ vtbl.8 X3_L, {X3_L}, ROTATE_TABLE
+ vtbl.8 X3_H, {X3_H}, ROTATE_TABLE
+
+ // x += y
+ vadd.u\n X0, Y0
+ vadd.u\n X1, Y1
+ vadd.u\n X2, Y2
+ vadd.u\n X3, Y3
+
+ // x ^= k
+ veor X0, ROUND_KEY
+ veor X1, ROUND_KEY
+ veor X2, ROUND_KEY
+ veor X3, ROUND_KEY
+
+ // y = rol(y, 3)
+ vshl.u\n TMP0, Y0, #3
+ vshl.u\n TMP1, Y1, #3
+ vshl.u\n TMP2, Y2, #3
+ vshl.u\n TMP3, Y3, #3
+ vsri.u\n TMP0, Y0, #(\n - 3)
+ vsri.u\n TMP1, Y1, #(\n - 3)
+ vsri.u\n TMP2, Y2, #(\n - 3)
+ vsri.u\n TMP3, Y3, #(\n - 3)
+
+ // y ^= x
+ veor Y0, TMP0, X0
+ veor Y1, TMP1, X1
+ veor Y2, TMP2, X2
+ veor Y3, TMP3, X3
+.endm
+
+/*
+ * _speck_unround_128bytes() - Speck decryption round on 128 bytes at a time
+ *
+ * This is the inverse of _speck_round_128bytes().
+ */
+.macro _speck_unround_128bytes n
+
+ // y ^= x
+ veor TMP0, Y0, X0
+ veor TMP1, Y1, X1
+ veor TMP2, Y2, X2
+ veor TMP3, Y3, X3
+
+ // y = ror(y, 3)
+ vshr.u\n Y0, TMP0, #3
+ vshr.u\n Y1, TMP1, #3
+ vshr.u\n Y2, TMP2, #3
+ vshr.u\n Y3, TMP3, #3
+ vsli.u\n Y0, TMP0, #(\n - 3)
+ vsli.u\n Y1, TMP1, #(\n - 3)
+ vsli.u\n Y2, TMP2, #(\n - 3)
+ vsli.u\n Y3, TMP3, #(\n - 3)
+
+ // x ^= k
+ veor X0, ROUND_KEY
+ veor X1, ROUND_KEY
+ veor X2, ROUND_KEY
+ veor X3, ROUND_KEY
+
+ // x -= y
+ vsub.u\n X0, Y0
+ vsub.u\n X1, Y1
+ vsub.u\n X2, Y2
+ vsub.u\n X3, Y3
+
+ // x = rol(x, 8);
+ vtbl.8 X0_L, {X0_L}, ROTATE_TABLE
+ vtbl.8 X0_H, {X0_H}, ROTATE_TABLE
+ vtbl.8 X1_L, {X1_L}, ROTATE_TABLE
+ vtbl.8 X1_H, {X1_H}, ROTATE_TABLE
+ vtbl.8 X2_L, {X2_L}, ROTATE_TABLE
+ vtbl.8 X2_H, {X2_H}, ROTATE_TABLE
+ vtbl.8 X3_L, {X3_L}, ROTATE_TABLE
+ vtbl.8 X3_H, {X3_H}, ROTATE_TABLE
+.endm
+
+.macro _xts128_precrypt_one dst_reg, tweak_buf, tmp
+
+ // Load the next source block
+ vld1.8 {\dst_reg}, [SRC]!
+
+ // Save the current tweak in the tweak buffer
+ vst1.8 {TWEAKV}, [\tweak_buf:128]!
+
+ // XOR the next source block with the current tweak
+ veor \dst_reg, TWEAKV
+
+ /*
+ * Calculate the next tweak by multiplying the current one by x,
+ * modulo p(x) = x^128 + x^7 + x^2 + x + 1.
+ */
+ vshr.u64 \tmp, TWEAKV, #63
+ vshl.u64 TWEAKV, #1
+ veor TWEAKV_H, \tmp\()_L
+ vtbl.8 \tmp\()_H, {GF128MUL_TABLE}, \tmp\()_H
+ veor TWEAKV_L, \tmp\()_H
+.endm
+
+.macro _xts64_precrypt_two dst_reg, tweak_buf, tmp
+
+ // Load the next two source blocks
+ vld1.8 {\dst_reg}, [SRC]!
+
+ // Save the current two tweaks in the tweak buffer
+ vst1.8 {TWEAKV}, [\tweak_buf:128]!
+
+ // XOR the next two source blocks with the current two tweaks
+ veor \dst_reg, TWEAKV
+
+ /*
+ * Calculate the next two tweaks by multiplying the current ones by x^2,
+ * modulo p(x) = x^64 + x^4 + x^3 + x + 1.
+ */
+ vshr.u64 \tmp, TWEAKV, #62
+ vshl.u64 TWEAKV, #2
+ vtbl.8 \tmp\()_L, {GF64MUL_TABLE}, \tmp\()_L
+ vtbl.8 \tmp\()_H, {GF64MUL_TABLE}, \tmp\()_H
+ veor TWEAKV, \tmp
+.endm
+
+/*
+ * _speck_xts_crypt() - Speck-XTS encryption/decryption
+ *
+ * Encrypt or decrypt NBYTES bytes of data from the SRC buffer to the DST buffer
+ * using Speck-XTS, specifically the variant with a block size of '2n' and round
+ * count given by NROUNDS. The expanded round keys are given in ROUND_KEYS, and
+ * the current XTS tweak value is given in TWEAK. It's assumed that NBYTES is a
+ * nonzero multiple of 128.
+ */
+.macro _speck_xts_crypt n, decrypting
+ push {r4-r7}
+ mov r7, sp
+
+ /*
+ * The first four parameters were passed in registers r0-r3. Load the
+ * additional parameters, which were passed on the stack.
+ */
+ ldr NBYTES, [sp, #16]
+ ldr TWEAK, [sp, #20]
+
+ /*
+ * If decrypting, modify the ROUND_KEYS parameter to point to the last
+ * round key rather than the first, since for decryption the round keys
+ * are used in reverse order.
+ */
+.if \decrypting
+.if \n == 64
+ add ROUND_KEYS, ROUND_KEYS, NROUNDS, lsl #3
+ sub ROUND_KEYS, #8
+.else
+ add ROUND_KEYS, ROUND_KEYS, NROUNDS, lsl #2
+ sub ROUND_KEYS, #4
+.endif
+.endif
+
+ // Load the index vector for vtbl-based 8-bit rotates
+.if \decrypting
+ ldr r12, =.Lrol\n\()_8_table
+.else
+ ldr r12, =.Lror\n\()_8_table
+.endif
+ vld1.8 {ROTATE_TABLE}, [r12:64]
+
+ // One-time XTS preparation
+
+ /*
+ * Allocate stack space to store 128 bytes worth of tweaks. For
+ * performance, this space is aligned to a 16-byte boundary so that we
+ * can use the load/store instructions that declare 16-byte alignment.
+ */
+ sub sp, #128
+ bic sp, #0xf
+
+.if \n == 64
+ // Load first tweak
+ vld1.8 {TWEAKV}, [TWEAK]
+
+ // Load GF(2^128) multiplication table
+ ldr r12, =.Lgf128mul_table
+ vld1.8 {GF128MUL_TABLE}, [r12:64]
+.else
+ // Load first tweak
+ vld1.8 {TWEAKV_L}, [TWEAK]
+
+ // Load GF(2^64) multiplication table
+ ldr r12, =.Lgf64mul_table
+ vld1.8 {GF64MUL_TABLE}, [r12:64]
+
+ // Calculate second tweak, packing it together with the first
+ vshr.u64 TMP0_L, TWEAKV_L, #63
+ vtbl.u8 TMP0_L, {GF64MUL_TABLE}, TMP0_L
+ vshl.u64 TWEAKV_H, TWEAKV_L, #1
+ veor TWEAKV_H, TMP0_L
+.endif
+
+.Lnext_128bytes_\@:
+
+ /*
+ * Load the source blocks into {X,Y}[0-3], XOR them with their XTS tweak
+ * values, and save the tweaks on the stack for later. Then
+ * de-interleave the 'x' and 'y' elements of each block, i.e. make it so
+ * that the X[0-3] registers contain only the second halves of blocks,
+ * and the Y[0-3] registers contain only the first halves of blocks.
+ * (Speck uses the order (y, x) rather than the more intuitive (x, y).)
+ */
+ mov r12, sp
+.if \n == 64
+ _xts128_precrypt_one X0, r12, TMP0
+ _xts128_precrypt_one Y0, r12, TMP0
+ _xts128_precrypt_one X1, r12, TMP0
+ _xts128_precrypt_one Y1, r12, TMP0
+ _xts128_precrypt_one X2, r12, TMP0
+ _xts128_precrypt_one Y2, r12, TMP0
+ _xts128_precrypt_one X3, r12, TMP0
+ _xts128_precrypt_one Y3, r12, TMP0
+ vswp X0_L, Y0_H
+ vswp X1_L, Y1_H
+ vswp X2_L, Y2_H
+ vswp X3_L, Y3_H
+.else
+ _xts64_precrypt_two X0, r12, TMP0
+ _xts64_precrypt_two Y0, r12, TMP0
+ _xts64_precrypt_two X1, r12, TMP0
+ _xts64_precrypt_two Y1, r12, TMP0
+ _xts64_precrypt_two X2, r12, TMP0
+ _xts64_precrypt_two Y2, r12, TMP0
+ _xts64_precrypt_two X3, r12, TMP0
+ _xts64_precrypt_two Y3, r12, TMP0
+ vuzp.32 Y0, X0
+ vuzp.32 Y1, X1
+ vuzp.32 Y2, X2
+ vuzp.32 Y3, X3
+.endif
+
+ // Do the cipher rounds
+
+ mov r12, ROUND_KEYS
+ mov r6, NROUNDS
+
+.Lnext_round_\@:
+.if \decrypting
+.if \n == 64
+ vld1.64 ROUND_KEY_L, [r12]
+ sub r12, #8
+ vmov ROUND_KEY_H, ROUND_KEY_L
+.else
+ vld1.32 {ROUND_KEY_L[],ROUND_KEY_H[]}, [r12]
+ sub r12, #4
+.endif
+ _speck_unround_128bytes \n
+.else
+.if \n == 64
+ vld1.64 ROUND_KEY_L, [r12]!
+ vmov ROUND_KEY_H, ROUND_KEY_L
+.else
+ vld1.32 {ROUND_KEY_L[],ROUND_KEY_H[]}, [r12]!
+.endif
+ _speck_round_128bytes \n
+.endif
+ subs r6, r6, #1
+ bne .Lnext_round_\@
+
+ // Re-interleave the 'x' and 'y' elements of each block
+.if \n == 64
+ vswp X0_L, Y0_H
+ vswp X1_L, Y1_H
+ vswp X2_L, Y2_H
+ vswp X3_L, Y3_H
+.else
+ vzip.32 Y0, X0
+ vzip.32 Y1, X1
+ vzip.32 Y2, X2
+ vzip.32 Y3, X3
+.endif
+
+ // XOR the encrypted/decrypted blocks with the tweaks we saved earlier
+ mov r12, sp
+ vld1.8 {TMP0, TMP1}, [r12:128]!
+ vld1.8 {TMP2, TMP3}, [r12:128]!
+ veor X0, TMP0
+ veor Y0, TMP1
+ veor X1, TMP2
+ veor Y1, TMP3
+ vld1.8 {TMP0, TMP1}, [r12:128]!
+ vld1.8 {TMP2, TMP3}, [r12:128]!
+ veor X2, TMP0
+ veor Y2, TMP1
+ veor X3, TMP2
+ veor Y3, TMP3
+
+ // Store the ciphertext in the destination buffer
+ vst1.8 {X0, Y0}, [DST]!
+ vst1.8 {X1, Y1}, [DST]!
+ vst1.8 {X2, Y2}, [DST]!
+ vst1.8 {X3, Y3}, [DST]!
+
+ // Continue if there are more 128-byte chunks remaining, else return
+ subs NBYTES, #128
+ bne .Lnext_128bytes_\@
+
+ // Store the next tweak
+.if \n == 64
+ vst1.8 {TWEAKV}, [TWEAK]
+.else
+ vst1.8 {TWEAKV_L}, [TWEAK]
+.endif
+
+ mov sp, r7
+ pop {r4-r7}
+ bx lr
+.endm
+
+ENTRY(speck128_xts_encrypt_neon)
+ _speck_xts_crypt n=64, decrypting=0
+ENDPROC(speck128_xts_encrypt_neon)
+
+ENTRY(speck128_xts_decrypt_neon)
+ _speck_xts_crypt n=64, decrypting=1
+ENDPROC(speck128_xts_decrypt_neon)
+
+ENTRY(speck64_xts_encrypt_neon)
+ _speck_xts_crypt n=32, decrypting=0
+ENDPROC(speck64_xts_encrypt_neon)
+
+ENTRY(speck64_xts_decrypt_neon)
+ _speck_xts_crypt n=32, decrypting=1
+ENDPROC(speck64_xts_decrypt_neon)
diff --git a/arch/arm/crypto/speck-neon-glue.c b/arch/arm/crypto/speck-neon-glue.c
new file mode 100644
index 000000000000..f012c3ea998f
--- /dev/null
+++ b/arch/arm/crypto/speck-neon-glue.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS
+ *
+ * Copyright (c) 2018 Google, Inc
+ *
+ * Note: the NIST recommendation for XTS only specifies a 128-bit block size,
+ * but a 64-bit version (needed for Speck64) is fairly straightforward; the math
+ * is just done in GF(2^64) instead of GF(2^128), with the reducing polynomial
+ * x^64 + x^4 + x^3 + x + 1 from the original XEX paper (Rogaway, 2004:
+ * "Efficient Instantiations of Tweakable Blockciphers and Refinements to Modes
+ * OCB and PMAC"), represented as 0x1B.
+ */
+
+#include <asm/hwcap.h>
+#include <asm/neon.h>
+#include <asm/simd.h>
+#include <crypto/algapi.h>
+#include <crypto/gf128mul.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/speck.h>
+#include <crypto/xts.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+/* The assembly functions only handle multiples of 128 bytes */
+#define SPECK_NEON_CHUNK_SIZE 128
+
+/* Speck128 */
+
+struct speck128_xts_tfm_ctx {
+ struct speck128_tfm_ctx main_key;
+ struct speck128_tfm_ctx tweak_key;
+};
+
+asmlinkage void speck128_xts_encrypt_neon(const u64 *round_keys, int nrounds,
+ void *dst, const void *src,
+ unsigned int nbytes, void *tweak);
+
+asmlinkage void speck128_xts_decrypt_neon(const u64 *round_keys, int nrounds,
+ void *dst, const void *src,
+ unsigned int nbytes, void *tweak);
+
+typedef void (*speck128_crypt_one_t)(const struct speck128_tfm_ctx *,
+ u8 *, const u8 *);
+typedef void (*speck128_xts_crypt_many_t)(const u64 *, int, void *,
+ const void *, unsigned int, void *);
+
+static __always_inline int
+__speck128_xts_crypt(struct skcipher_request *req,
+ speck128_crypt_one_t crypt_one,
+ speck128_xts_crypt_many_t crypt_many)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ const struct speck128_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
+ le128 tweak;
+ int err;
+
+ err = skcipher_walk_virt(&walk, req, true);
+
+ crypto_speck128_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv);
+
+ while (walk.nbytes > 0) {
+ unsigned int nbytes = walk.nbytes;
+ u8 *dst = walk.dst.virt.addr;
+ const u8 *src = walk.src.virt.addr;
+
+ if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) {
+ unsigned int count;
+
+ count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE);
+ kernel_neon_begin();
+ (*crypt_many)(ctx->main_key.round_keys,
+ ctx->main_key.nrounds,
+ dst, src, count, &tweak);
+ kernel_neon_end();
+ dst += count;
+ src += count;
+ nbytes -= count;
+ }
+
+ /* Handle any remainder with generic code */
+ while (nbytes >= sizeof(tweak)) {
+ le128_xor((le128 *)dst, (const le128 *)src, &tweak);
+ (*crypt_one)(&ctx->main_key, dst, dst);
+ le128_xor((le128 *)dst, (const le128 *)dst, &tweak);
+ gf128mul_x_ble(&tweak, &tweak);
+
+ dst += sizeof(tweak);
+ src += sizeof(tweak);
+ nbytes -= sizeof(tweak);
+ }
+ err = skcipher_walk_done(&walk, nbytes);
+ }
+
+ return err;
+}
+
+static int speck128_xts_encrypt(struct skcipher_request *req)
+{
+ return __speck128_xts_crypt(req, crypto_speck128_encrypt,
+ speck128_xts_encrypt_neon);
+}
+
+static int speck128_xts_decrypt(struct skcipher_request *req)
+{
+ return __speck128_xts_crypt(req, crypto_speck128_decrypt,
+ speck128_xts_decrypt_neon);
+}
+
+static int speck128_xts_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct speck128_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
+ int err;
+
+ err = xts_verify_key(tfm, key, keylen);
+ if (err)
+ return err;
+
+ keylen /= 2;
+
+ err = crypto_speck128_setkey(&ctx->main_key, key, keylen);
+ if (err)
+ return err;
+
+ return crypto_speck128_setkey(&ctx->tweak_key, key + keylen, keylen);
+}
+
+/* Speck64 */
+
+struct speck64_xts_tfm_ctx {
+ struct speck64_tfm_ctx main_key;
+ struct speck64_tfm_ctx tweak_key;
+};
+
+asmlinkage void speck64_xts_encrypt_neon(const u32 *round_keys, int nrounds,
+ void *dst, const void *src,
+ unsigned int nbytes, void *tweak);
+
+asmlinkage void speck64_xts_decrypt_neon(const u32 *round_keys, int nrounds,
+ void *dst, const void *src,
+ unsigned int nbytes, void *tweak);
+
+typedef void (*speck64_crypt_one_t)(const struct speck64_tfm_ctx *,
+ u8 *, const u8 *);
+typedef void (*speck64_xts_crypt_many_t)(const u32 *, int, void *,
+ const void *, unsigned int, void *);
+
+static __always_inline int
+__speck64_xts_crypt(struct skcipher_request *req, speck64_crypt_one_t crypt_one,
+ speck64_xts_crypt_many_t crypt_many)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ const struct speck64_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
+ __le64 tweak;
+ int err;
+
+ err = skcipher_walk_virt(&walk, req, true);
+
+ crypto_speck64_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv);
+
+ while (walk.nbytes > 0) {
+ unsigned int nbytes = walk.nbytes;
+ u8 *dst = walk.dst.virt.addr;
+ const u8 *src = walk.src.virt.addr;
+
+ if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) {
+ unsigned int count;
+
+ count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE);
+ kernel_neon_begin();
+ (*crypt_many)(ctx->main_key.round_keys,
+ ctx->main_key.nrounds,
+ dst, src, count, &tweak);
+ kernel_neon_end();
+ dst += count;
+ src += count;
+ nbytes -= count;
+ }
+
+ /* Handle any remainder with generic code */
+ while (nbytes >= sizeof(tweak)) {
+ *(__le64 *)dst = *(__le64 *)src ^ tweak;
+ (*crypt_one)(&ctx->main_key, dst, dst);
+ *(__le64 *)dst ^= tweak;
+ tweak = cpu_to_le64((le64_to_cpu(tweak) << 1) ^
+ ((tweak & cpu_to_le64(1ULL << 63)) ?
+ 0x1B : 0));
+ dst += sizeof(tweak);
+ src += sizeof(tweak);
+ nbytes -= sizeof(tweak);
+ }
+ err = skcipher_walk_done(&walk, nbytes);
+ }
+
+ return err;
+}
+
+static int speck64_xts_encrypt(struct skcipher_request *req)
+{
+ return __speck64_xts_crypt(req, crypto_speck64_encrypt,
+ speck64_xts_encrypt_neon);
+}
+
+static int speck64_xts_decrypt(struct skcipher_request *req)
+{
+ return __speck64_xts_crypt(req, crypto_speck64_decrypt,
+ speck64_xts_decrypt_neon);
+}
+
+static int speck64_xts_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct speck64_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
+ int err;
+
+ err = xts_verify_key(tfm, key, keylen);
+ if (err)
+ return err;
+
+ keylen /= 2;
+
+ err = crypto_speck64_setkey(&ctx->main_key, key, keylen);
+ if (err)
+ return err;
+
+ return crypto_speck64_setkey(&ctx->tweak_key, key + keylen, keylen);
+}
+
+static struct skcipher_alg speck_algs[] = {
+ {
+ .base.cra_name = "xts(speck128)",
+ .base.cra_driver_name = "xts-speck128-neon",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = SPECK128_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct speck128_xts_tfm_ctx),
+ .base.cra_alignmask = 7,
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = 2 * SPECK128_128_KEY_SIZE,
+ .max_keysize = 2 * SPECK128_256_KEY_SIZE,
+ .ivsize = SPECK128_BLOCK_SIZE,
+ .walksize = SPECK_NEON_CHUNK_SIZE,
+ .setkey = speck128_xts_setkey,
+ .encrypt = speck128_xts_encrypt,
+ .decrypt = speck128_xts_decrypt,
+ }, {
+ .base.cra_name = "xts(speck64)",
+ .base.cra_driver_name = "xts-speck64-neon",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = SPECK64_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct speck64_xts_tfm_ctx),
+ .base.cra_alignmask = 7,
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = 2 * SPECK64_96_KEY_SIZE,
+ .max_keysize = 2 * SPECK64_128_KEY_SIZE,
+ .ivsize = SPECK64_BLOCK_SIZE,
+ .walksize = SPECK_NEON_CHUNK_SIZE,
+ .setkey = speck64_xts_setkey,
+ .encrypt = speck64_xts_encrypt,
+ .decrypt = speck64_xts_decrypt,
+ }
+};
+
+static int __init speck_neon_module_init(void)
+{
+ if (!(elf_hwcap & HWCAP_NEON))
+ return -ENODEV;
+ return crypto_register_skciphers(speck_algs, ARRAY_SIZE(speck_algs));
+}
+
+static void __exit speck_neon_module_exit(void)
+{
+ crypto_unregister_skciphers(speck_algs, ARRAY_SIZE(speck_algs));
+}
+
+module_init(speck_neon_module_init);
+module_exit(speck_neon_module_exit);
+
+MODULE_DESCRIPTION("Speck block cipher (NEON-accelerated)");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>");
+MODULE_ALIAS_CRYPTO("xts(speck128)");
+MODULE_ALIAS_CRYPTO("xts-speck128-neon");
+MODULE_ALIAS_CRYPTO("xts(speck64)");
+MODULE_ALIAS_CRYPTO("xts-speck64-neon");
diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h
index 1070044f5c3f..0bd530702118 100644
--- a/arch/arm/include/asm/arch_gicv3.h
+++ b/arch/arm/include/asm/arch_gicv3.h
@@ -35,6 +35,18 @@
#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7)
#define ICC_BPR1 __ACCESS_CP15(c12, 0, c12, 3)
+#define __ICC_AP0Rx(x) __ACCESS_CP15(c12, 0, c8, 4 | x)
+#define ICC_AP0R0 __ICC_AP0Rx(0)
+#define ICC_AP0R1 __ICC_AP0Rx(1)
+#define ICC_AP0R2 __ICC_AP0Rx(2)
+#define ICC_AP0R3 __ICC_AP0Rx(3)
+
+#define __ICC_AP1Rx(x) __ACCESS_CP15(c12, 0, c9, x)
+#define ICC_AP1R0 __ICC_AP1Rx(0)
+#define ICC_AP1R1 __ICC_AP1Rx(1)
+#define ICC_AP1R2 __ICC_AP1Rx(2)
+#define ICC_AP1R3 __ICC_AP1Rx(3)
+
#define ICC_HSRE __ACCESS_CP15(c12, 4, c9, 5)
#define ICH_VSEIR __ACCESS_CP15(c12, 4, c9, 4)
@@ -86,17 +98,17 @@
#define ICH_LRC14 __LRC8(6)
#define ICH_LRC15 __LRC8(7)
-#define __AP0Rx(x) __ACCESS_CP15(c12, 4, c8, x)
-#define ICH_AP0R0 __AP0Rx(0)
-#define ICH_AP0R1 __AP0Rx(1)
-#define ICH_AP0R2 __AP0Rx(2)
-#define ICH_AP0R3 __AP0Rx(3)
+#define __ICH_AP0Rx(x) __ACCESS_CP15(c12, 4, c8, x)
+#define ICH_AP0R0 __ICH_AP0Rx(0)
+#define ICH_AP0R1 __ICH_AP0Rx(1)
+#define ICH_AP0R2 __ICH_AP0Rx(2)
+#define ICH_AP0R3 __ICH_AP0Rx(3)
-#define __AP1Rx(x) __ACCESS_CP15(c12, 4, c9, x)
-#define ICH_AP1R0 __AP1Rx(0)
-#define ICH_AP1R1 __AP1Rx(1)
-#define ICH_AP1R2 __AP1Rx(2)
-#define ICH_AP1R3 __AP1Rx(3)
+#define __ICH_AP1Rx(x) __ACCESS_CP15(c12, 4, c9, x)
+#define ICH_AP1R0 __ICH_AP1Rx(0)
+#define ICH_AP1R1 __ICH_AP1Rx(1)
+#define ICH_AP1R2 __ICH_AP1Rx(2)
+#define ICH_AP1R3 __ICH_AP1Rx(3)
/* A32-to-A64 mappings used by VGIC save/restore */
@@ -125,6 +137,16 @@ static inline u64 read_ ## a64(void) \
return val; \
}
+CPUIF_MAP(ICC_PMR, ICC_PMR_EL1)
+CPUIF_MAP(ICC_AP0R0, ICC_AP0R0_EL1)
+CPUIF_MAP(ICC_AP0R1, ICC_AP0R1_EL1)
+CPUIF_MAP(ICC_AP0R2, ICC_AP0R2_EL1)
+CPUIF_MAP(ICC_AP0R3, ICC_AP0R3_EL1)
+CPUIF_MAP(ICC_AP1R0, ICC_AP1R0_EL1)
+CPUIF_MAP(ICC_AP1R1, ICC_AP1R1_EL1)
+CPUIF_MAP(ICC_AP1R2, ICC_AP1R2_EL1)
+CPUIF_MAP(ICC_AP1R3, ICC_AP1R3_EL1)
+
CPUIF_MAP(ICH_HCR, ICH_HCR_EL2)
CPUIF_MAP(ICH_VTR, ICH_VTR_EL2)
CPUIF_MAP(ICH_MISR, ICH_MISR_EL2)
@@ -185,11 +207,6 @@ static inline u32 gic_read_iar(void)
return irqstat;
}
-static inline void gic_write_pmr(u32 val)
-{
- write_sysreg(val, ICC_PMR);
-}
-
static inline void gic_write_ctlr(u32 val)
{
write_sysreg(val, ICC_CTLR);
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 7381eeb7ef8e..177be0d1d090 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -132,6 +132,7 @@ config ARM64
select IRQ_DOMAIN
select IRQ_FORCED_THREADING
select MODULES_USE_ELF_RELA
+ select MULTI_IRQ_HANDLER
select NO_BOOTMEM
select OF
select OF_EARLY_FLATTREE
@@ -275,6 +276,9 @@ config ARCH_SUPPORTS_UPROBES
config ARCH_PROC_KCORE_TEXT
def_bool y
+config MULTI_IRQ_HANDLER
+ def_bool y
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
@@ -455,12 +459,26 @@ config ARM64_ERRATUM_845719
config ARM64_ERRATUM_843419
bool "Cortex-A53: 843419: A load or store might access an incorrect address"
default y
- select ARM64_MODULE_CMODEL_LARGE if MODULES
+ select ARM64_MODULE_PLTS if MODULES
help
This option links the kernel with '--fix-cortex-a53-843419' and
- builds modules using the large memory model in order to avoid the use
- of the ADRP instruction, which can cause a subsequent memory access
- to use an incorrect address on Cortex-A53 parts up to r0p4.
+ enables PLT support to replace certain ADRP instructions, which can
+ cause subsequent memory accesses to use an incorrect address on
+ Cortex-A53 parts up to r0p4.
+
+ If unsure, say Y.
+
+config ARM64_ERRATUM_1024718
+ bool "Cortex-A55: 1024718: Update of DBM/AP bits without break before make might result in incorrect update"
+ default y
+ help
+ This option adds work around for Arm Cortex-A55 Erratum 1024718.
+
+ Affected Cortex-A55 cores (r0p0, r0p1, r1p0) could cause incorrect
+ update of the hardware dirty bit when the DBM/AP bits are updated
+ without a break-before-make. The work around is to disable the usage
+ of hardware DBM locally on the affected cores. CPUs not affected by
+ erratum will continue to use the feature.
If unsure, say Y.
@@ -1104,12 +1122,25 @@ config ARM64_SVE
To enable use of this extension on CPUs that implement it, say Y.
-config ARM64_MODULE_CMODEL_LARGE
- bool
+ Note that for architectural reasons, firmware _must_ implement SVE
+ support when running on SVE capable hardware. The required support
+ is present in:
+
+ * version 1.5 and later of the ARM Trusted Firmware
+ * the AArch64 boot wrapper since commit 5e1261e08abf
+ ("bootwrapper: SVE: Enable SVE for EL2 and below").
+
+ For other firmware implementations, consult the firmware documentation
+ or vendor.
+
+ If you need the kernel to boot on SVE-capable hardware with broken
+ firmware, you may need to say N here until you get your firmware
+ fixed. Otherwise, you may experience firmware panics or lockups when
+ booting the kernel. If unsure and you are not observing these
+ symptoms, you should assume that it is safe to say Y.
config ARM64_MODULE_PLTS
bool
- select ARM64_MODULE_CMODEL_LARGE
select HAVE_MOD_ARCH_SPECIFIC
config RELOCATABLE
@@ -1143,12 +1174,12 @@ config RANDOMIZE_BASE
If unsure, say N.
config RANDOMIZE_MODULE_REGION_FULL
- bool "Randomize the module region independently from the core kernel"
+ bool "Randomize the module region over a 4 GB range"
depends on RANDOMIZE_BASE
default y
help
- Randomizes the location of the module region without considering the
- location of the core kernel. This way, it is impossible for modules
+ Randomizes the location of the module region inside a 4 GB window
+ covering the core kernel. This way, it is less likely for modules
to leak information about the location of core kernel data structures
but it does imply that function calls between modules and the core
kernel will need to be resolved via veneers in the module PLT.
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index b481b4a7c011..15402861bb59 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -51,7 +51,6 @@ endif
KBUILD_CFLAGS += -mgeneral-regs-only $(lseinstr) $(brokengasinst)
KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
-KBUILD_CFLAGS += $(call cc-option, -mpc-relative-literal-loads)
KBUILD_AFLAGS += $(lseinstr) $(brokengasinst)
KBUILD_CFLAGS += $(call cc-option,-mabi=lp64)
@@ -77,10 +76,6 @@ endif
CHECKFLAGS += -D__aarch64__ -m64
-ifeq ($(CONFIG_ARM64_MODULE_CMODEL_LARGE), y)
-KBUILD_CFLAGS_MODULE += -mcmodel=large
-endif
-
ifeq ($(CONFIG_ARM64_MODULE_PLTS),y)
KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/arm64/kernel/module.lds
endif
@@ -97,12 +92,14 @@ else
TEXT_OFFSET := 0x00080000
endif
-# KASAN_SHADOW_OFFSET = VA_START + (1 << (VA_BITS - 3)) - (1 << 61)
+# KASAN_SHADOW_OFFSET = VA_START + (1 << (VA_BITS - KASAN_SHADOW_SCALE_SHIFT))
+# - (1 << (64 - KASAN_SHADOW_SCALE_SHIFT))
# in 32-bit arithmetic
+KASAN_SHADOW_SCALE_SHIFT := 3
KASAN_SHADOW_OFFSET := $(shell printf "0x%08x00000000\n" $$(( \
- (0xffffffff & (-1 << ($(CONFIG_ARM64_VA_BITS) - 32))) \
- + (1 << ($(CONFIG_ARM64_VA_BITS) - 32 - 3)) \
- - (1 << (64 - 32 - 3)) )) )
+ (0xffffffff & (-1 << ($(CONFIG_ARM64_VA_BITS) - 32))) \
+ + (1 << ($(CONFIG_ARM64_VA_BITS) - 32 - $(KASAN_SHADOW_SCALE_SHIFT))) \
+ - (1 << (64 - 32 - $(KASAN_SHADOW_SCALE_SHIFT))) )) )
export TEXT_OFFSET GZFLAGS
diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig
index 285c36c7b408..cb5a243110c4 100644
--- a/arch/arm64/crypto/Kconfig
+++ b/arch/arm64/crypto/Kconfig
@@ -113,4 +113,10 @@ config CRYPTO_AES_ARM64_BS
select CRYPTO_AES_ARM64
select CRYPTO_SIMD
+config CRYPTO_SPECK_NEON
+ tristate "NEON accelerated Speck cipher algorithms"
+ depends on KERNEL_MODE_NEON
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_SPECK
+
endif
diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile
index cee9b8d9830b..8df9f326f449 100644
--- a/arch/arm64/crypto/Makefile
+++ b/arch/arm64/crypto/Makefile
@@ -53,20 +53,21 @@ sha512-arm64-y := sha512-glue.o sha512-core.o
obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha20-neon.o
chacha20-neon-y := chacha20-neon-core.o chacha20-neon-glue.o
+obj-$(CONFIG_CRYPTO_SPECK_NEON) += speck-neon.o
+speck-neon-y := speck-neon-core.o speck-neon-glue.o
+
obj-$(CONFIG_CRYPTO_AES_ARM64) += aes-arm64.o
aes-arm64-y := aes-cipher-core.o aes-cipher-glue.o
obj-$(CONFIG_CRYPTO_AES_ARM64_BS) += aes-neon-bs.o
aes-neon-bs-y := aes-neonbs-core.o aes-neonbs-glue.o
-AFLAGS_aes-ce.o := -DINTERLEAVE=4
-AFLAGS_aes-neon.o := -DINTERLEAVE=4
-
CFLAGS_aes-glue-ce.o := -DUSE_V8_CRYPTO_EXTENSIONS
$(obj)/aes-glue-%.o: $(src)/aes-glue.c FORCE
$(call if_changed_rule,cc_o_c)
+ifdef REGENERATE_ARM64_CRYPTO
quiet_cmd_perlasm = PERLASM $@
cmd_perlasm = $(PERL) $(<) void $(@)
@@ -75,5 +76,6 @@ $(src)/sha256-core.S_shipped: $(src)/sha512-armv8.pl
$(src)/sha512-core.S_shipped: $(src)/sha512-armv8.pl
$(call cmd,perlasm)
+endif
.PRECIOUS: $(obj)/sha256-core.S $(obj)/sha512-core.S
diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c
index a1254036f2b1..68b11aa690e4 100644
--- a/arch/arm64/crypto/aes-ce-ccm-glue.c
+++ b/arch/arm64/crypto/aes-ce-ccm-glue.c
@@ -107,11 +107,13 @@ static int ccm_init_mac(struct aead_request *req, u8 maciv[], u32 msglen)
}
static void ccm_update_mac(struct crypto_aes_ctx *key, u8 mac[], u8 const in[],
- u32 abytes, u32 *macp, bool use_neon)
+ u32 abytes, u32 *macp)
{
- if (likely(use_neon)) {
+ if (may_use_simd()) {
+ kernel_neon_begin();
ce_aes_ccm_auth_data(mac, in, abytes, macp, key->key_enc,
num_rounds(key));
+ kernel_neon_end();
} else {
if (*macp > 0 && *macp < AES_BLOCK_SIZE) {
int added = min(abytes, AES_BLOCK_SIZE - *macp);
@@ -143,8 +145,7 @@ static void ccm_update_mac(struct crypto_aes_ctx *key, u8 mac[], u8 const in[],
}
}
-static void ccm_calculate_auth_mac(struct aead_request *req, u8 mac[],
- bool use_neon)
+static void ccm_calculate_auth_mac(struct aead_request *req, u8 mac[])
{
struct crypto_aead *aead = crypto_aead_reqtfm(req);
struct crypto_aes_ctx *ctx = crypto_aead_ctx(aead);
@@ -163,7 +164,7 @@ static void ccm_calculate_auth_mac(struct aead_request *req, u8 mac[],
ltag.len = 6;
}
- ccm_update_mac(ctx, mac, (u8 *)&ltag, ltag.len, &macp, use_neon);
+ ccm_update_mac(ctx, mac, (u8 *)&ltag, ltag.len, &macp);
scatterwalk_start(&walk, req->src);
do {
@@ -175,7 +176,7 @@ static void ccm_calculate_auth_mac(struct aead_request *req, u8 mac[],
n = scatterwalk_clamp(&walk, len);
}
p = scatterwalk_map(&walk);
- ccm_update_mac(ctx, mac, p, n, &macp, use_neon);
+ ccm_update_mac(ctx, mac, p, n, &macp);
len -= n;
scatterwalk_unmap(p);
@@ -242,43 +243,42 @@ static int ccm_encrypt(struct aead_request *req)
u8 __aligned(8) mac[AES_BLOCK_SIZE];
u8 buf[AES_BLOCK_SIZE];
u32 len = req->cryptlen;
- bool use_neon = may_use_simd();
int err;
err = ccm_init_mac(req, mac, len);
if (err)
return err;
- if (likely(use_neon))
- kernel_neon_begin();
-
if (req->assoclen)
- ccm_calculate_auth_mac(req, mac, use_neon);
+ ccm_calculate_auth_mac(req, mac);
/* preserve the original iv for the final round */
memcpy(buf, req->iv, AES_BLOCK_SIZE);
err = skcipher_walk_aead_encrypt(&walk, req, true);
- if (likely(use_neon)) {
+ if (may_use_simd()) {
while (walk.nbytes) {
u32 tail = walk.nbytes % AES_BLOCK_SIZE;
if (walk.nbytes == walk.total)
tail = 0;
+ kernel_neon_begin();
ce_aes_ccm_encrypt(walk.dst.virt.addr,
walk.src.virt.addr,
walk.nbytes - tail, ctx->key_enc,
num_rounds(ctx), mac, walk.iv);
+ kernel_neon_end();
err = skcipher_walk_done(&walk, tail);
}
- if (!err)
+ if (!err) {
+ kernel_neon_begin();
ce_aes_ccm_final(mac, buf, ctx->key_enc,
num_rounds(ctx));
-
- kernel_neon_end();
+ kernel_neon_end();
+ }
} else {
err = ccm_crypt_fallback(&walk, mac, buf, ctx, true);
}
@@ -301,43 +301,42 @@ static int ccm_decrypt(struct aead_request *req)
u8 __aligned(8) mac[AES_BLOCK_SIZE];
u8 buf[AES_BLOCK_SIZE];
u32 len = req->cryptlen - authsize;
- bool use_neon = may_use_simd();
int err;
err = ccm_init_mac(req, mac, len);
if (err)
return err;
- if (likely(use_neon))
- kernel_neon_begin();
-
if (req->assoclen)
- ccm_calculate_auth_mac(req, mac, use_neon);
+ ccm_calculate_auth_mac(req, mac);
/* preserve the original iv for the final round */
memcpy(buf, req->iv, AES_BLOCK_SIZE);
err = skcipher_walk_aead_decrypt(&walk, req, true);
- if (likely(use_neon)) {
+ if (may_use_simd()) {
while (walk.nbytes) {
u32 tail = walk.nbytes % AES_BLOCK_SIZE;
if (walk.nbytes == walk.total)
tail = 0;
+ kernel_neon_begin();
ce_aes_ccm_decrypt(walk.dst.virt.addr,
walk.src.virt.addr,
walk.nbytes - tail, ctx->key_enc,
num_rounds(ctx), mac, walk.iv);
+ kernel_neon_end();
err = skcipher_walk_done(&walk, tail);
}
- if (!err)
+ if (!err) {
+ kernel_neon_begin();
ce_aes_ccm_final(mac, buf, ctx->key_enc,
num_rounds(ctx));
-
- kernel_neon_end();
+ kernel_neon_end();
+ }
} else {
err = ccm_crypt_fallback(&walk, mac, buf, ctx, false);
}
diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c
index 2fa850e86aa8..253188fb8cb0 100644
--- a/arch/arm64/crypto/aes-glue.c
+++ b/arch/arm64/crypto/aes-glue.c
@@ -64,17 +64,17 @@ MODULE_LICENSE("GPL v2");
/* defined in aes-modes.S */
asmlinkage void aes_ecb_encrypt(u8 out[], u8 const in[], u8 const rk[],
- int rounds, int blocks, int first);
+ int rounds, int blocks);
asmlinkage void aes_ecb_decrypt(u8 out[], u8 const in[], u8 const rk[],
- int rounds, int blocks, int first);
+ int rounds, int blocks);
asmlinkage void aes_cbc_encrypt(u8 out[], u8 const in[], u8 const rk[],
- int rounds, int blocks, u8 iv[], int first);
+ int rounds, int blocks, u8 iv[]);
asmlinkage void aes_cbc_decrypt(u8 out[], u8 const in[], u8 const rk[],
- int rounds, int blocks, u8 iv[], int first);
+ int rounds, int blocks, u8 iv[]);
asmlinkage void aes_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[],
- int rounds, int blocks, u8 ctr[], int first);
+ int rounds, int blocks, u8 ctr[]);
asmlinkage void aes_xts_encrypt(u8 out[], u8 const in[], u8 const rk1[],
int rounds, int blocks, u8 const rk2[], u8 iv[],
@@ -133,19 +133,19 @@ static int ecb_encrypt(struct skcipher_request *req)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
- int err, first, rounds = 6 + ctx->key_length / 4;
+ int err, rounds = 6 + ctx->key_length / 4;
struct skcipher_walk walk;
unsigned int blocks;
- err = skcipher_walk_virt(&walk, req, true);
+ err = skcipher_walk_virt(&walk, req, false);
- kernel_neon_begin();
- for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) {
+ while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) {
+ kernel_neon_begin();
aes_ecb_encrypt(walk.dst.virt.addr, walk.src.virt.addr,
- (u8 *)ctx->key_enc, rounds, blocks, first);
+ (u8 *)ctx->key_enc, rounds, blocks);
+ kernel_neon_end();
err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE);
}
- kernel_neon_end();
return err;
}
@@ -153,19 +153,19 @@ static int ecb_decrypt(struct skcipher_request *req)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
- int err, first, rounds = 6 + ctx->key_length / 4;
+ int err, rounds = 6 + ctx->key_length / 4;
struct skcipher_walk walk;
unsigned int blocks;
- err = skcipher_walk_virt(&walk, req, true);
+ err = skcipher_walk_virt(&walk, req, false);
- kernel_neon_begin();
- for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) {
+ while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) {
+ kernel_neon_begin();
aes_ecb_decrypt(walk.dst.virt.addr, walk.src.virt.addr,
- (u8 *)ctx->key_dec, rounds, blocks, first);
+ (u8 *)ctx->key_dec, rounds, blocks);
+ kernel_neon_end();
err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE);
}
- kernel_neon_end();
return err;
}
@@ -173,20 +173,19 @@ static int cbc_encrypt(struct skcipher_request *req)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
- int err, first, rounds = 6 + ctx->key_length / 4;
+ int err, rounds = 6 + ctx->key_length / 4;
struct skcipher_walk walk;
unsigned int blocks;
- err = skcipher_walk_virt(&walk, req, true);
+ err = skcipher_walk_virt(&walk, req, false);
- kernel_neon_begin();
- for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) {
+ while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) {
+ kernel_neon_begin();
aes_cbc_encrypt(walk.dst.virt.addr, walk.src.virt.addr,
- (u8 *)ctx->key_enc, rounds, blocks, walk.iv,
- first);
+ (u8 *)ctx->key_enc, rounds, blocks, walk.iv);
+ kernel_neon_end();
err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE);
}
- kernel_neon_end();
return err;
}
@@ -194,20 +193,19 @@ static int cbc_decrypt(struct skcipher_request *req)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
- int err, first, rounds = 6 + ctx->key_length / 4;
+ int err, rounds = 6 + ctx->key_length / 4;
struct skcipher_walk walk;
unsigned int blocks;
- err = skcipher_walk_virt(&walk, req, true);
+ err = skcipher_walk_virt(&walk, req, false);
- kernel_neon_begin();
- for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) {
+ while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) {
+ kernel_neon_begin();
aes_cbc_decrypt(walk.dst.virt.addr, walk.src.virt.addr,
- (u8 *)ctx->key_dec, rounds, blocks, walk.iv,
- first);
+ (u8 *)ctx->key_dec, rounds, blocks, walk.iv);
+ kernel_neon_end();
err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE);
}
- kernel_neon_end();
return err;
}
@@ -215,20 +213,18 @@ static int ctr_encrypt(struct skcipher_request *req)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
- int err, first, rounds = 6 + ctx->key_length / 4;
+ int err, rounds = 6 + ctx->key_length / 4;
struct skcipher_walk walk;
int blocks;
- err = skcipher_walk_virt(&walk, req, true);
+ err = skcipher_walk_virt(&walk, req, false);
- first = 1;
- kernel_neon_begin();
while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) {
+ kernel_neon_begin();
aes_ctr_encrypt(walk.dst.virt.addr, walk.src.virt.addr,
- (u8 *)ctx->key_enc, rounds, blocks, walk.iv,
- first);
+ (u8 *)ctx->key_enc, rounds, blocks, walk.iv);
err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE);
- first = 0;
+ kernel_neon_end();
}
if (walk.nbytes) {
u8 __aligned(8) tail[AES_BLOCK_SIZE];
@@ -241,12 +237,13 @@ static int ctr_encrypt(struct skcipher_request *req)
*/
blocks = -1;
+ kernel_neon_begin();
aes_ctr_encrypt(tail, NULL, (u8 *)ctx->key_enc, rounds,
- blocks, walk.iv, first);
+ blocks, walk.iv);
+ kernel_neon_end();
crypto_xor_cpy(tdst, tsrc, tail, nbytes);
err = skcipher_walk_done(&walk, 0);
}
- kernel_neon_end();
return err;
}
@@ -270,16 +267,16 @@ static int xts_encrypt(struct skcipher_request *req)
struct skcipher_walk walk;
unsigned int blocks;
- err = skcipher_walk_virt(&walk, req, true);
+ err = skcipher_walk_virt(&walk, req, false);
- kernel_neon_begin();
for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) {
+ kernel_neon_begin();
aes_xts_encrypt(walk.dst.virt.addr, walk.src.virt.addr,
(u8 *)ctx->key1.key_enc, rounds, blocks,
(u8 *)ctx->key2.key_enc, walk.iv, first);
+ kernel_neon_end();
err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE);
}
- kernel_neon_end();
return err;
}
@@ -292,16 +289,16 @@ static int xts_decrypt(struct skcipher_request *req)
struct skcipher_walk walk;
unsigned int blocks;
- err = skcipher_walk_virt(&walk, req, true);
+ err = skcipher_walk_virt(&walk, req, false);
- kernel_neon_begin();
for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) {
+ kernel_neon_begin();
aes_xts_decrypt(walk.dst.virt.addr, walk.src.virt.addr,
(u8 *)ctx->key1.key_dec, rounds, blocks,
(u8 *)ctx->key2.key_enc, walk.iv, first);
+ kernel_neon_end();
err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE);
}
- kernel_neon_end();
return err;
}
@@ -425,7 +422,7 @@ static int cmac_setkey(struct crypto_shash *tfm, const u8 *in_key,
/* encrypt the zero vector */
kernel_neon_begin();
- aes_ecb_encrypt(ctx->consts, (u8[AES_BLOCK_SIZE]){}, rk, rounds, 1, 1);
+ aes_ecb_encrypt(ctx->consts, (u8[AES_BLOCK_SIZE]){}, rk, rounds, 1);
kernel_neon_end();
cmac_gf128_mul_by_x(consts, consts);
@@ -454,8 +451,8 @@ static int xcbc_setkey(struct crypto_shash *tfm, const u8 *in_key,
return err;
kernel_neon_begin();
- aes_ecb_encrypt(key, ks[0], rk, rounds, 1, 1);
- aes_ecb_encrypt(ctx->consts, ks[1], rk, rounds, 2, 0);
+ aes_ecb_encrypt(key, ks[0], rk, rounds, 1);
+ aes_ecb_encrypt(ctx->consts, ks[1], rk, rounds, 2);
kernel_neon_end();
return cbcmac_setkey(tfm, key, sizeof(key));
diff --git a/arch/arm64/crypto/aes-modes.S b/arch/arm64/crypto/aes-modes.S
index 2674d43d1384..a68412e1e3a4 100644
--- a/arch/arm64/crypto/aes-modes.S
+++ b/arch/arm64/crypto/aes-modes.S
@@ -13,127 +13,39 @@
.text
.align 4
-/*
- * There are several ways to instantiate this code:
- * - no interleave, all inline
- * - 2-way interleave, 2x calls out of line (-DINTERLEAVE=2)
- * - 2-way interleave, all inline (-DINTERLEAVE=2 -DINTERLEAVE_INLINE)
- * - 4-way interleave, 4x calls out of line (-DINTERLEAVE=4)
- * - 4-way interleave, all inline (-DINTERLEAVE=4 -DINTERLEAVE_INLINE)
- *
- * Macros imported by this code:
- * - enc_prepare - setup NEON registers for encryption
- * - dec_prepare - setup NEON registers for decryption
- * - enc_switch_key - change to new key after having prepared for encryption
- * - encrypt_block - encrypt a single block
- * - decrypt block - decrypt a single block
- * - encrypt_block2x - encrypt 2 blocks in parallel (if INTERLEAVE == 2)
- * - decrypt_block2x - decrypt 2 blocks in parallel (if INTERLEAVE == 2)
- * - encrypt_block4x - encrypt 4 blocks in parallel (if INTERLEAVE == 4)
- * - decrypt_block4x - decrypt 4 blocks in parallel (if INTERLEAVE == 4)
- */
-
-#if defined(INTERLEAVE) && !defined(INTERLEAVE_INLINE)
-#define FRAME_PUSH stp x29, x30, [sp,#-16]! ; mov x29, sp
-#define FRAME_POP ldp x29, x30, [sp],#16
-
-#if INTERLEAVE == 2
-
-aes_encrypt_block2x:
- encrypt_block2x v0, v1, w3, x2, x6, w7
- ret
-ENDPROC(aes_encrypt_block2x)
-
-aes_decrypt_block2x:
- decrypt_block2x v0, v1, w3, x2, x6, w7
- ret
-ENDPROC(aes_decrypt_block2x)
-
-#elif INTERLEAVE == 4
-
aes_encrypt_block4x:
- encrypt_block4x v0, v1, v2, v3, w3, x2, x6, w7
+ encrypt_block4x v0, v1, v2, v3, w3, x2, x8, w7
ret
ENDPROC(aes_encrypt_block4x)
aes_decrypt_block4x:
- decrypt_block4x v0, v1, v2, v3, w3, x2, x6, w7
+ decrypt_block4x v0, v1, v2, v3, w3, x2, x8, w7
ret
ENDPROC(aes_decrypt_block4x)
-#else
-#error INTERLEAVE should equal 2 or 4
-#endif
-
- .macro do_encrypt_block2x
- bl aes_encrypt_block2x
- .endm
-
- .macro do_decrypt_block2x
- bl aes_decrypt_block2x
- .endm
-
- .macro do_encrypt_block4x
- bl aes_encrypt_block4x
- .endm
-
- .macro do_decrypt_block4x
- bl aes_decrypt_block4x
- .endm
-
-#else
-#define FRAME_PUSH
-#define FRAME_POP
-
- .macro do_encrypt_block2x
- encrypt_block2x v0, v1, w3, x2, x6, w7
- .endm
-
- .macro do_decrypt_block2x
- decrypt_block2x v0, v1, w3, x2, x6, w7
- .endm
-
- .macro do_encrypt_block4x
- encrypt_block4x v0, v1, v2, v3, w3, x2, x6, w7
- .endm
-
- .macro do_decrypt_block4x
- decrypt_block4x v0, v1, v2, v3, w3, x2, x6, w7
- .endm
-
-#endif
-
/*
* aes_ecb_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds,
- * int blocks, int first)
+ * int blocks)
* aes_ecb_decrypt(u8 out[], u8 const in[], u8 const rk[], int rounds,
- * int blocks, int first)
+ * int blocks)
*/
AES_ENTRY(aes_ecb_encrypt)
- FRAME_PUSH
- cbz w5, .LecbencloopNx
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
enc_prepare w3, x2, x5
.LecbencloopNx:
-#if INTERLEAVE >= 2
- subs w4, w4, #INTERLEAVE
+ subs w4, w4, #4
bmi .Lecbenc1x
-#if INTERLEAVE == 2
- ld1 {v0.16b-v1.16b}, [x1], #32 /* get 2 pt blocks */
- do_encrypt_block2x
- st1 {v0.16b-v1.16b}, [x0], #32
-#else
ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 pt blocks */
- do_encrypt_block4x
+ bl aes_encrypt_block4x
st1 {v0.16b-v3.16b}, [x0], #64
-#endif
b .LecbencloopNx
.Lecbenc1x:
- adds w4, w4, #INTERLEAVE
+ adds w4, w4, #4
beq .Lecbencout
-#endif
.Lecbencloop:
ld1 {v0.16b}, [x1], #16 /* get next pt block */
encrypt_block v0, w3, x2, x5, w6
@@ -141,35 +53,27 @@ AES_ENTRY(aes_ecb_encrypt)
subs w4, w4, #1
bne .Lecbencloop
.Lecbencout:
- FRAME_POP
+ ldp x29, x30, [sp], #16
ret
AES_ENDPROC(aes_ecb_encrypt)
AES_ENTRY(aes_ecb_decrypt)
- FRAME_PUSH
- cbz w5, .LecbdecloopNx
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
dec_prepare w3, x2, x5
.LecbdecloopNx:
-#if INTERLEAVE >= 2
- subs w4, w4, #INTERLEAVE
+ subs w4, w4, #4
bmi .Lecbdec1x
-#if INTERLEAVE == 2
- ld1 {v0.16b-v1.16b}, [x1], #32 /* get 2 ct blocks */
- do_decrypt_block2x
- st1 {v0.16b-v1.16b}, [x0], #32
-#else
ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 ct blocks */
- do_decrypt_block4x
+ bl aes_decrypt_block4x
st1 {v0.16b-v3.16b}, [x0], #64
-#endif
b .LecbdecloopNx
.Lecbdec1x:
- adds w4, w4, #INTERLEAVE
+ adds w4, w4, #4
beq .Lecbdecout
-#endif
.Lecbdecloop:
ld1 {v0.16b}, [x1], #16 /* get next ct block */
decrypt_block v0, w3, x2, x5, w6
@@ -177,62 +81,68 @@ AES_ENTRY(aes_ecb_decrypt)
subs w4, w4, #1
bne .Lecbdecloop
.Lecbdecout:
- FRAME_POP
+ ldp x29, x30, [sp], #16
ret
AES_ENDPROC(aes_ecb_decrypt)
/*
* aes_cbc_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds,
- * int blocks, u8 iv[], int first)
+ * int blocks, u8 iv[])
* aes_cbc_decrypt(u8 out[], u8 const in[], u8 const rk[], int rounds,
- * int blocks, u8 iv[], int first)
+ * int blocks, u8 iv[])
*/
AES_ENTRY(aes_cbc_encrypt)
- cbz w6, .Lcbcencloop
-
- ld1 {v0.16b}, [x5] /* get iv */
+ ld1 {v4.16b}, [x5] /* get iv */
enc_prepare w3, x2, x6
-.Lcbcencloop:
- ld1 {v1.16b}, [x1], #16 /* get next pt block */
- eor v0.16b, v0.16b, v1.16b /* ..and xor with iv */
+.Lcbcencloop4x:
+ subs w4, w4, #4
+ bmi .Lcbcenc1x
+ ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 pt blocks */
+ eor v0.16b, v0.16b, v4.16b /* ..and xor with iv */
encrypt_block v0, w3, x2, x6, w7
- st1 {v0.16b}, [x0], #16
+ eor v1.16b, v1.16b, v0.16b
+ encrypt_block v1, w3, x2, x6, w7
+ eor v2.16b, v2.16b, v1.16b
+ encrypt_block v2, w3, x2, x6, w7
+ eor v3.16b, v3.16b, v2.16b
+ encrypt_block v3, w3, x2, x6, w7
+ st1 {v0.16b-v3.16b}, [x0], #64
+ mov v4.16b, v3.16b
+ b .Lcbcencloop4x
+.Lcbcenc1x:
+ adds w4, w4, #4
+ beq .Lcbcencout
+.Lcbcencloop:
+ ld1 {v0.16b}, [x1], #16 /* get next pt block */
+ eor v4.16b, v4.16b, v0.16b /* ..and xor with iv */
+ encrypt_block v4, w3, x2, x6, w7
+ st1 {v4.16b}, [x0], #16
subs w4, w4, #1
bne .Lcbcencloop
- st1 {v0.16b}, [x5] /* return iv */
+.Lcbcencout:
+ st1 {v4.16b}, [x5] /* return iv */
ret
AES_ENDPROC(aes_cbc_encrypt)
AES_ENTRY(aes_cbc_decrypt)
- FRAME_PUSH
- cbz w6, .LcbcdecloopNx
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
ld1 {v7.16b}, [x5] /* get iv */
dec_prepare w3, x2, x6
.LcbcdecloopNx:
-#if INTERLEAVE >= 2
- subs w4, w4, #INTERLEAVE
+ subs w4, w4, #4
bmi .Lcbcdec1x
-#if INTERLEAVE == 2
- ld1 {v0.16b-v1.16b}, [x1], #32 /* get 2 ct blocks */
- mov v2.16b, v0.16b
- mov v3.16b, v1.16b
- do_decrypt_block2x
- eor v0.16b, v0.16b, v7.16b
- eor v1.16b, v1.16b, v2.16b
- mov v7.16b, v3.16b
- st1 {v0.16b-v1.16b}, [x0], #32
-#else
ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 ct blocks */
mov v4.16b, v0.16b
mov v5.16b, v1.16b
mov v6.16b, v2.16b
- do_decrypt_block4x
+ bl aes_decrypt_block4x
sub x1, x1, #16
eor v0.16b, v0.16b, v7.16b
eor v1.16b, v1.16b, v4.16b
@@ -240,12 +150,10 @@ AES_ENTRY(aes_cbc_decrypt)
eor v2.16b, v2.16b, v5.16b
eor v3.16b, v3.16b, v6.16b
st1 {v0.16b-v3.16b}, [x0], #64
-#endif
b .LcbcdecloopNx
.Lcbcdec1x:
- adds w4, w4, #INTERLEAVE
+ adds w4, w4, #4
beq .Lcbcdecout
-#endif
.Lcbcdecloop:
ld1 {v1.16b}, [x1], #16 /* get next ct block */
mov v0.16b, v1.16b /* ...and copy to v0 */
@@ -256,49 +164,33 @@ AES_ENTRY(aes_cbc_decrypt)
subs w4, w4, #1
bne .Lcbcdecloop
.Lcbcdecout:
- FRAME_POP
st1 {v7.16b}, [x5] /* return iv */
+ ldp x29, x30, [sp], #16
ret
AES_ENDPROC(aes_cbc_decrypt)
/*
* aes_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds,
- * int blocks, u8 ctr[], int first)
+ * int blocks, u8 ctr[])
*/
AES_ENTRY(aes_ctr_encrypt)
- FRAME_PUSH
- cbz w6, .Lctrnotfirst /* 1st time around? */
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
+
enc_prepare w3, x2, x6
ld1 {v4.16b}, [x5]
-.Lctrnotfirst:
- umov x8, v4.d[1] /* keep swabbed ctr in reg */
- rev x8, x8
-#if INTERLEAVE >= 2
- cmn w8, w4 /* 32 bit overflow? */
+ umov x6, v4.d[1] /* keep swabbed ctr in reg */
+ rev x6, x6
+ cmn w6, w4 /* 32 bit overflow? */
bcs .Lctrloop
.LctrloopNx:
- subs w4, w4, #INTERLEAVE
+ subs w4, w4, #4
bmi .Lctr1x
-#if INTERLEAVE == 2
- mov v0.8b, v4.8b
- mov v1.8b, v4.8b
- rev x7, x8
- add x8, x8, #1
- ins v0.d[1], x7
- rev x7, x8
- add x8, x8, #1
- ins v1.d[1], x7
- ld1 {v2.16b-v3.16b}, [x1], #32 /* get 2 input blocks */
- do_encrypt_block2x
- eor v0.16b, v0.16b, v2.16b
- eor v1.16b, v1.16b, v3.16b
- st1 {v0.16b-v1.16b}, [x0], #32
-#else
ldr q8, =0x30000000200000001 /* addends 1,2,3[,0] */
- dup v7.4s, w8
+ dup v7.4s, w6
mov v0.16b, v4.16b
add v7.4s, v7.4s, v8.4s
mov v1.16b, v4.16b
@@ -309,29 +201,27 @@ AES_ENTRY(aes_ctr_encrypt)
mov v2.s[3], v8.s[1]
mov v3.s[3], v8.s[2]
ld1 {v5.16b-v7.16b}, [x1], #48 /* get 3 input blocks */
- do_encrypt_block4x
+ bl aes_encrypt_block4x
eor v0.16b, v5.16b, v0.16b
ld1 {v5.16b}, [x1], #16 /* get 1 input block */
eor v1.16b, v6.16b, v1.16b
eor v2.16b, v7.16b, v2.16b
eor v3.16b, v5.16b, v3.16b
st1 {v0.16b-v3.16b}, [x0], #64
- add x8, x8, #INTERLEAVE
-#endif
- rev x7, x8
+ add x6, x6, #4
+ rev x7, x6
ins v4.d[1], x7
cbz w4, .Lctrout
b .LctrloopNx
.Lctr1x:
- adds w4, w4, #INTERLEAVE
+ adds w4, w4, #4
beq .Lctrout
-#endif
.Lctrloop:
mov v0.16b, v4.16b
- encrypt_block v0, w3, x2, x6, w7
+ encrypt_block v0, w3, x2, x8, w7
- adds x8, x8, #1 /* increment BE ctr */
- rev x7, x8
+ adds x6, x6, #1 /* increment BE ctr */
+ rev x7, x6
ins v4.d[1], x7
bcs .Lctrcarry /* overflow? */
@@ -345,12 +235,12 @@ AES_ENTRY(aes_ctr_encrypt)
.Lctrout:
st1 {v4.16b}, [x5] /* return next CTR value */
- FRAME_POP
+ ldp x29, x30, [sp], #16
ret
.Lctrtailblock:
st1 {v0.16b}, [x0]
- FRAME_POP
+ ldp x29, x30, [sp], #16
ret
.Lctrcarry:
@@ -384,39 +274,26 @@ CPU_LE( .quad 1, 0x87 )
CPU_BE( .quad 0x87, 1 )
AES_ENTRY(aes_xts_encrypt)
- FRAME_PUSH
- cbz w7, .LxtsencloopNx
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
ld1 {v4.16b}, [x6]
- enc_prepare w3, x5, x6
- encrypt_block v4, w3, x5, x6, w7 /* first tweak */
- enc_switch_key w3, x2, x6
+ cbz w7, .Lxtsencnotfirst
+
+ enc_prepare w3, x5, x8
+ encrypt_block v4, w3, x5, x8, w7 /* first tweak */
+ enc_switch_key w3, x2, x8
ldr q7, .Lxts_mul_x
b .LxtsencNx
+.Lxtsencnotfirst:
+ enc_prepare w3, x2, x8
.LxtsencloopNx:
ldr q7, .Lxts_mul_x
next_tweak v4, v4, v7, v8
.LxtsencNx:
-#if INTERLEAVE >= 2
- subs w4, w4, #INTERLEAVE
+ subs w4, w4, #4
bmi .Lxtsenc1x
-#if INTERLEAVE == 2
- ld1 {v0.16b-v1.16b}, [x1], #32 /* get 2 pt blocks */
- next_tweak v5, v4, v7, v8
- eor v0.16b, v0.16b, v4.16b
- eor v1.16b, v1.16b, v5.16b
- do_encrypt_block2x
- eor v0.16b, v0.16b, v4.16b
- eor v1.16b, v1.16b, v5.16b
- st1 {v0.16b-v1.16b}, [x0], #32
- cbz w4, .LxtsencoutNx
- next_tweak v4, v5, v7, v8
- b .LxtsencNx
-.LxtsencoutNx:
- mov v4.16b, v5.16b
- b .Lxtsencout
-#else
ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 pt blocks */
next_tweak v5, v4, v7, v8
eor v0.16b, v0.16b, v4.16b
@@ -425,7 +302,7 @@ AES_ENTRY(aes_xts_encrypt)
eor v2.16b, v2.16b, v6.16b
next_tweak v7, v6, v7, v8
eor v3.16b, v3.16b, v7.16b
- do_encrypt_block4x
+ bl aes_encrypt_block4x
eor v3.16b, v3.16b, v7.16b
eor v0.16b, v0.16b, v4.16b
eor v1.16b, v1.16b, v5.16b
@@ -434,15 +311,13 @@ AES_ENTRY(aes_xts_encrypt)
mov v4.16b, v7.16b
cbz w4, .Lxtsencout
b .LxtsencloopNx
-#endif
.Lxtsenc1x:
- adds w4, w4, #INTERLEAVE
+ adds w4, w4, #4
beq .Lxtsencout
-#endif
.Lxtsencloop:
ld1 {v1.16b}, [x1], #16
eor v0.16b, v1.16b, v4.16b
- encrypt_block v0, w3, x2, x6, w7
+ encrypt_block v0, w3, x2, x8, w7
eor v0.16b, v0.16b, v4.16b
st1 {v0.16b}, [x0], #16
subs w4, w4, #1
@@ -450,45 +325,33 @@ AES_ENTRY(aes_xts_encrypt)
next_tweak v4, v4, v7, v8
b .Lxtsencloop
.Lxtsencout:
- FRAME_POP
+ st1 {v4.16b}, [x6]
+ ldp x29, x30, [sp], #16
ret
AES_ENDPROC(aes_xts_encrypt)
AES_ENTRY(aes_xts_decrypt)
- FRAME_PUSH
- cbz w7, .LxtsdecloopNx
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
ld1 {v4.16b}, [x6]
- enc_prepare w3, x5, x6
- encrypt_block v4, w3, x5, x6, w7 /* first tweak */
- dec_prepare w3, x2, x6
+ cbz w7, .Lxtsdecnotfirst
+
+ enc_prepare w3, x5, x8
+ encrypt_block v4, w3, x5, x8, w7 /* first tweak */
+ dec_prepare w3, x2, x8
ldr q7, .Lxts_mul_x
b .LxtsdecNx
+.Lxtsdecnotfirst:
+ dec_prepare w3, x2, x8
.LxtsdecloopNx:
ldr q7, .Lxts_mul_x
next_tweak v4, v4, v7, v8
.LxtsdecNx:
-#if INTERLEAVE >= 2
- subs w4, w4, #INTERLEAVE
+ subs w4, w4, #4
bmi .Lxtsdec1x
-#if INTERLEAVE == 2
- ld1 {v0.16b-v1.16b}, [x1], #32 /* get 2 ct blocks */
- next_tweak v5, v4, v7, v8
- eor v0.16b, v0.16b, v4.16b
- eor v1.16b, v1.16b, v5.16b
- do_decrypt_block2x
- eor v0.16b, v0.16b, v4.16b
- eor v1.16b, v1.16b, v5.16b
- st1 {v0.16b-v1.16b}, [x0], #32
- cbz w4, .LxtsdecoutNx
- next_tweak v4, v5, v7, v8
- b .LxtsdecNx
-.LxtsdecoutNx:
- mov v4.16b, v5.16b
- b .Lxtsdecout
-#else
ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 ct blocks */
next_tweak v5, v4, v7, v8
eor v0.16b, v0.16b, v4.16b
@@ -497,7 +360,7 @@ AES_ENTRY(aes_xts_decrypt)
eor v2.16b, v2.16b, v6.16b
next_tweak v7, v6, v7, v8
eor v3.16b, v3.16b, v7.16b
- do_decrypt_block4x
+ bl aes_decrypt_block4x
eor v3.16b, v3.16b, v7.16b
eor v0.16b, v0.16b, v4.16b
eor v1.16b, v1.16b, v5.16b
@@ -506,15 +369,13 @@ AES_ENTRY(aes_xts_decrypt)
mov v4.16b, v7.16b
cbz w4, .Lxtsdecout
b .LxtsdecloopNx
-#endif
.Lxtsdec1x:
- adds w4, w4, #INTERLEAVE
+ adds w4, w4, #4
beq .Lxtsdecout
-#endif
.Lxtsdecloop:
ld1 {v1.16b}, [x1], #16
eor v0.16b, v1.16b, v4.16b
- decrypt_block v0, w3, x2, x6, w7
+ decrypt_block v0, w3, x2, x8, w7
eor v0.16b, v0.16b, v4.16b
st1 {v0.16b}, [x0], #16
subs w4, w4, #1
@@ -522,7 +383,8 @@ AES_ENTRY(aes_xts_decrypt)
next_tweak v4, v4, v7, v8
b .Lxtsdecloop
.Lxtsdecout:
- FRAME_POP
+ st1 {v4.16b}, [x6]
+ ldp x29, x30, [sp], #16
ret
AES_ENDPROC(aes_xts_decrypt)
@@ -533,8 +395,28 @@ AES_ENDPROC(aes_xts_decrypt)
AES_ENTRY(aes_mac_update)
ld1 {v0.16b}, [x4] /* get dg */
enc_prepare w2, x1, x7
- cbnz w5, .Lmacenc
+ cbz w5, .Lmacloop4x
+
+ encrypt_block v0, w2, x1, x7, w8
+.Lmacloop4x:
+ subs w3, w3, #4
+ bmi .Lmac1x
+ ld1 {v1.16b-v4.16b}, [x0], #64 /* get next pt block */
+ eor v0.16b, v0.16b, v1.16b /* ..and xor with dg */
+ encrypt_block v0, w2, x1, x7, w8
+ eor v0.16b, v0.16b, v2.16b
+ encrypt_block v0, w2, x1, x7, w8
+ eor v0.16b, v0.16b, v3.16b
+ encrypt_block v0, w2, x1, x7, w8
+ eor v0.16b, v0.16b, v4.16b
+ cmp w3, wzr
+ csinv x5, x6, xzr, eq
+ cbz w5, .Lmacout
+ encrypt_block v0, w2, x1, x7, w8
+ b .Lmacloop4x
+.Lmac1x:
+ add w3, w3, #4
.Lmacloop:
cbz w3, .Lmacout
ld1 {v1.16b}, [x0], #16 /* get next pt block */
@@ -544,7 +426,6 @@ AES_ENTRY(aes_mac_update)
csinv x5, x6, xzr, eq
cbz w5, .Lmacout
-.Lmacenc:
encrypt_block v0, w2, x1, x7, w8
b .Lmacloop
diff --git a/arch/arm64/crypto/aes-neonbs-glue.c b/arch/arm64/crypto/aes-neonbs-glue.c
index c55d68ccb89f..e7a95a566462 100644
--- a/arch/arm64/crypto/aes-neonbs-glue.c
+++ b/arch/arm64/crypto/aes-neonbs-glue.c
@@ -46,10 +46,9 @@ asmlinkage void aesbs_xts_decrypt(u8 out[], u8 const in[], u8 const rk[],
/* borrowed from aes-neon-blk.ko */
asmlinkage void neon_aes_ecb_encrypt(u8 out[], u8 const in[], u32 const rk[],
- int rounds, int blocks, int first);
+ int rounds, int blocks);
asmlinkage void neon_aes_cbc_encrypt(u8 out[], u8 const in[], u32 const rk[],
- int rounds, int blocks, u8 iv[],
- int first);
+ int rounds, int blocks, u8 iv[]);
struct aesbs_ctx {
u8 rk[13 * (8 * AES_BLOCK_SIZE) + 32];
@@ -100,9 +99,8 @@ static int __ecb_crypt(struct skcipher_request *req,
struct skcipher_walk walk;
int err;
- err = skcipher_walk_virt(&walk, req, true);
+ err = skcipher_walk_virt(&walk, req, false);
- kernel_neon_begin();
while (walk.nbytes >= AES_BLOCK_SIZE) {
unsigned int blocks = walk.nbytes / AES_BLOCK_SIZE;
@@ -110,12 +108,13 @@ static int __ecb_crypt(struct skcipher_request *req,
blocks = round_down(blocks,
walk.stride / AES_BLOCK_SIZE);
+ kernel_neon_begin();
fn(walk.dst.virt.addr, walk.src.virt.addr, ctx->rk,
ctx->rounds, blocks);
+ kernel_neon_end();
err = skcipher_walk_done(&walk,
walk.nbytes - blocks * AES_BLOCK_SIZE);
}
- kernel_neon_end();
return err;
}
@@ -157,22 +156,21 @@ static int cbc_encrypt(struct skcipher_request *req)
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
struct aesbs_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
struct skcipher_walk walk;
- int err, first = 1;
+ int err;
- err = skcipher_walk_virt(&walk, req, true);
+ err = skcipher_walk_virt(&walk, req, false);
- kernel_neon_begin();
while (walk.nbytes >= AES_BLOCK_SIZE) {
unsigned int blocks = walk.nbytes / AES_BLOCK_SIZE;
/* fall back to the non-bitsliced NEON implementation */
+ kernel_neon_begin();
neon_aes_cbc_encrypt(walk.dst.virt.addr, walk.src.virt.addr,
- ctx->enc, ctx->key.rounds, blocks, walk.iv,
- first);
+ ctx->enc, ctx->key.rounds, blocks,
+ walk.iv);
+ kernel_neon_end();
err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE);
- first = 0;
}
- kernel_neon_end();
return err;
}
@@ -183,9 +181,8 @@ static int cbc_decrypt(struct skcipher_request *req)
struct skcipher_walk walk;
int err;
- err = skcipher_walk_virt(&walk, req, true);
+ err = skcipher_walk_virt(&walk, req, false);
- kernel_neon_begin();
while (walk.nbytes >= AES_BLOCK_SIZE) {
unsigned int blocks = walk.nbytes / AES_BLOCK_SIZE;
@@ -193,13 +190,14 @@ static int cbc_decrypt(struct skcipher_request *req)
blocks = round_down(blocks,
walk.stride / AES_BLOCK_SIZE);
+ kernel_neon_begin();
aesbs_cbc_decrypt(walk.dst.virt.addr, walk.src.virt.addr,
ctx->key.rk, ctx->key.rounds, blocks,
walk.iv);
+ kernel_neon_end();
err = skcipher_walk_done(&walk,
walk.nbytes - blocks * AES_BLOCK_SIZE);
}
- kernel_neon_end();
return err;
}
@@ -231,9 +229,8 @@ static int ctr_encrypt(struct skcipher_request *req)
u8 buf[AES_BLOCK_SIZE];
int err;
- err = skcipher_walk_virt(&walk, req, true);
+ err = skcipher_walk_virt(&walk, req, false);
- kernel_neon_begin();
while (walk.nbytes > 0) {
unsigned int blocks = walk.nbytes / AES_BLOCK_SIZE;
u8 *final = (walk.total % AES_BLOCK_SIZE) ? buf : NULL;
@@ -244,8 +241,10 @@ static int ctr_encrypt(struct skcipher_request *req)
final = NULL;
}
+ kernel_neon_begin();
aesbs_ctr_encrypt(walk.dst.virt.addr, walk.src.virt.addr,
ctx->rk, ctx->rounds, blocks, walk.iv, final);
+ kernel_neon_end();
if (final) {
u8 *dst = walk.dst.virt.addr + blocks * AES_BLOCK_SIZE;
@@ -260,8 +259,6 @@ static int ctr_encrypt(struct skcipher_request *req)
err = skcipher_walk_done(&walk,
walk.nbytes - blocks * AES_BLOCK_SIZE);
}
- kernel_neon_end();
-
return err;
}
@@ -306,12 +303,11 @@ static int __xts_crypt(struct skcipher_request *req,
struct skcipher_walk walk;
int err;
- err = skcipher_walk_virt(&walk, req, true);
+ err = skcipher_walk_virt(&walk, req, false);
kernel_neon_begin();
-
- neon_aes_ecb_encrypt(walk.iv, walk.iv, ctx->twkey,
- ctx->key.rounds, 1, 1);
+ neon_aes_ecb_encrypt(walk.iv, walk.iv, ctx->twkey, ctx->key.rounds, 1);
+ kernel_neon_end();
while (walk.nbytes >= AES_BLOCK_SIZE) {
unsigned int blocks = walk.nbytes / AES_BLOCK_SIZE;
@@ -320,13 +316,13 @@ static int __xts_crypt(struct skcipher_request *req,
blocks = round_down(blocks,
walk.stride / AES_BLOCK_SIZE);
+ kernel_neon_begin();
fn(walk.dst.virt.addr, walk.src.virt.addr, ctx->key.rk,
ctx->key.rounds, blocks, walk.iv);
+ kernel_neon_end();
err = skcipher_walk_done(&walk,
walk.nbytes - blocks * AES_BLOCK_SIZE);
}
- kernel_neon_end();
-
return err;
}
diff --git a/arch/arm64/crypto/chacha20-neon-glue.c b/arch/arm64/crypto/chacha20-neon-glue.c
index cbdb75d15cd0..727579c93ded 100644
--- a/arch/arm64/crypto/chacha20-neon-glue.c
+++ b/arch/arm64/crypto/chacha20-neon-glue.c
@@ -37,12 +37,19 @@ static void chacha20_doneon(u32 *state, u8 *dst, const u8 *src,
u8 buf[CHACHA20_BLOCK_SIZE];
while (bytes >= CHACHA20_BLOCK_SIZE * 4) {
+ kernel_neon_begin();
chacha20_4block_xor_neon(state, dst, src);
+ kernel_neon_end();
bytes -= CHACHA20_BLOCK_SIZE * 4;
src += CHACHA20_BLOCK_SIZE * 4;
dst += CHACHA20_BLOCK_SIZE * 4;
state[12] += 4;
}
+
+ if (!bytes)
+ return;
+
+ kernel_neon_begin();
while (bytes >= CHACHA20_BLOCK_SIZE) {
chacha20_block_xor_neon(state, dst, src);
bytes -= CHACHA20_BLOCK_SIZE;
@@ -55,6 +62,7 @@ static void chacha20_doneon(u32 *state, u8 *dst, const u8 *src,
chacha20_block_xor_neon(state, buf, buf);
memcpy(dst, buf, bytes);
}
+ kernel_neon_end();
}
static int chacha20_neon(struct skcipher_request *req)
@@ -68,11 +76,10 @@ static int chacha20_neon(struct skcipher_request *req)
if (!may_use_simd() || req->cryptlen <= CHACHA20_BLOCK_SIZE)
return crypto_chacha20_crypt(req);
- err = skcipher_walk_virt(&walk, req, true);
+ err = skcipher_walk_virt(&walk, req, false);
crypto_chacha20_init(state, ctx, walk.iv);
- kernel_neon_begin();
while (walk.nbytes > 0) {
unsigned int nbytes = walk.nbytes;
@@ -83,7 +90,6 @@ static int chacha20_neon(struct skcipher_request *req)
nbytes);
err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
}
- kernel_neon_end();
return err;
}
diff --git a/arch/arm64/crypto/sha256-glue.c b/arch/arm64/crypto/sha256-glue.c
index b064d925fe2a..e8880ccdc71f 100644
--- a/arch/arm64/crypto/sha256-glue.c
+++ b/arch/arm64/crypto/sha256-glue.c
@@ -89,21 +89,32 @@ static struct shash_alg algs[] = { {
static int sha256_update_neon(struct shash_desc *desc, const u8 *data,
unsigned int len)
{
- /*
- * Stacking and unstacking a substantial slice of the NEON register
- * file may significantly affect performance for small updates when
- * executing in interrupt context, so fall back to the scalar code
- * in that case.
- */
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+
if (!may_use_simd())
return sha256_base_do_update(desc, data, len,
(sha256_block_fn *)sha256_block_data_order);
- kernel_neon_begin();
- sha256_base_do_update(desc, data, len,
- (sha256_block_fn *)sha256_block_neon);
- kernel_neon_end();
+ while (len > 0) {
+ unsigned int chunk = len;
+
+ /*
+ * Don't hog the CPU for the entire time it takes to process all
+ * input when running on a preemptible kernel, but process the
+ * data block by block instead.
+ */
+ if (IS_ENABLED(CONFIG_PREEMPT) &&
+ chunk + sctx->count % SHA256_BLOCK_SIZE > SHA256_BLOCK_SIZE)
+ chunk = SHA256_BLOCK_SIZE -
+ sctx->count % SHA256_BLOCK_SIZE;
+ kernel_neon_begin();
+ sha256_base_do_update(desc, data, chunk,
+ (sha256_block_fn *)sha256_block_neon);
+ kernel_neon_end();
+ data += chunk;
+ len -= chunk;
+ }
return 0;
}
@@ -117,10 +128,9 @@ static int sha256_finup_neon(struct shash_desc *desc, const u8 *data,
sha256_base_do_finalize(desc,
(sha256_block_fn *)sha256_block_data_order);
} else {
- kernel_neon_begin();
if (len)
- sha256_base_do_update(desc, data, len,
- (sha256_block_fn *)sha256_block_neon);
+ sha256_update_neon(desc, data, len);
+ kernel_neon_begin();
sha256_base_do_finalize(desc,
(sha256_block_fn *)sha256_block_neon);
kernel_neon_end();
diff --git a/arch/arm64/crypto/speck-neon-core.S b/arch/arm64/crypto/speck-neon-core.S
new file mode 100644
index 000000000000..b14463438b09
--- /dev/null
+++ b/arch/arm64/crypto/speck-neon-core.S
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM64 NEON-accelerated implementation of Speck128-XTS and Speck64-XTS
+ *
+ * Copyright (c) 2018 Google, Inc
+ *
+ * Author: Eric Biggers <ebiggers@google.com>
+ */
+
+#include <linux/linkage.h>
+
+ .text
+
+ // arguments
+ ROUND_KEYS .req x0 // const {u64,u32} *round_keys
+ NROUNDS .req w1 // int nrounds
+ NROUNDS_X .req x1
+ DST .req x2 // void *dst
+ SRC .req x3 // const void *src
+ NBYTES .req w4 // unsigned int nbytes
+ TWEAK .req x5 // void *tweak
+
+ // registers which hold the data being encrypted/decrypted
+ // (underscores avoid a naming collision with ARM64 registers x0-x3)
+ X_0 .req v0
+ Y_0 .req v1
+ X_1 .req v2
+ Y_1 .req v3
+ X_2 .req v4
+ Y_2 .req v5
+ X_3 .req v6
+ Y_3 .req v7
+
+ // the round key, duplicated in all lanes
+ ROUND_KEY .req v8
+
+ // index vector for tbl-based 8-bit rotates
+ ROTATE_TABLE .req v9
+ ROTATE_TABLE_Q .req q9
+
+ // temporary registers
+ TMP0 .req v10
+ TMP1 .req v11
+ TMP2 .req v12
+ TMP3 .req v13
+
+ // multiplication table for updating XTS tweaks
+ GFMUL_TABLE .req v14
+ GFMUL_TABLE_Q .req q14
+
+ // next XTS tweak value(s)
+ TWEAKV_NEXT .req v15
+
+ // XTS tweaks for the blocks currently being encrypted/decrypted
+ TWEAKV0 .req v16
+ TWEAKV1 .req v17
+ TWEAKV2 .req v18
+ TWEAKV3 .req v19
+ TWEAKV4 .req v20
+ TWEAKV5 .req v21
+ TWEAKV6 .req v22
+ TWEAKV7 .req v23
+
+ .align 4
+.Lror64_8_table:
+ .octa 0x080f0e0d0c0b0a090007060504030201
+.Lror32_8_table:
+ .octa 0x0c0f0e0d080b0a090407060500030201
+.Lrol64_8_table:
+ .octa 0x0e0d0c0b0a09080f0605040302010007
+.Lrol32_8_table:
+ .octa 0x0e0d0c0f0a09080b0605040702010003
+.Lgf128mul_table:
+ .octa 0x00000000000000870000000000000001
+.Lgf64mul_table:
+ .octa 0x0000000000000000000000002d361b00
+
+/*
+ * _speck_round_128bytes() - Speck encryption round on 128 bytes at a time
+ *
+ * Do one Speck encryption round on the 128 bytes (8 blocks for Speck128, 16 for
+ * Speck64) stored in X0-X3 and Y0-Y3, using the round key stored in all lanes
+ * of ROUND_KEY. 'n' is the lane size: 64 for Speck128, or 32 for Speck64.
+ * 'lanes' is the lane specifier: "2d" for Speck128 or "4s" for Speck64.
+ */
+.macro _speck_round_128bytes n, lanes
+
+ // x = ror(x, 8)
+ tbl X_0.16b, {X_0.16b}, ROTATE_TABLE.16b
+ tbl X_1.16b, {X_1.16b}, ROTATE_TABLE.16b
+ tbl X_2.16b, {X_2.16b}, ROTATE_TABLE.16b
+ tbl X_3.16b, {X_3.16b}, ROTATE_TABLE.16b
+
+ // x += y
+ add X_0.\lanes, X_0.\lanes, Y_0.\lanes
+ add X_1.\lanes, X_1.\lanes, Y_1.\lanes
+ add X_2.\lanes, X_2.\lanes, Y_2.\lanes
+ add X_3.\lanes, X_3.\lanes, Y_3.\lanes
+
+ // x ^= k
+ eor X_0.16b, X_0.16b, ROUND_KEY.16b
+ eor X_1.16b, X_1.16b, ROUND_KEY.16b
+ eor X_2.16b, X_2.16b, ROUND_KEY.16b
+ eor X_3.16b, X_3.16b, ROUND_KEY.16b
+
+ // y = rol(y, 3)
+ shl TMP0.\lanes, Y_0.\lanes, #3
+ shl TMP1.\lanes, Y_1.\lanes, #3
+ shl TMP2.\lanes, Y_2.\lanes, #3
+ shl TMP3.\lanes, Y_3.\lanes, #3
+ sri TMP0.\lanes, Y_0.\lanes, #(\n - 3)
+ sri TMP1.\lanes, Y_1.\lanes, #(\n - 3)
+ sri TMP2.\lanes, Y_2.\lanes, #(\n - 3)
+ sri TMP3.\lanes, Y_3.\lanes, #(\n - 3)
+
+ // y ^= x
+ eor Y_0.16b, TMP0.16b, X_0.16b
+ eor Y_1.16b, TMP1.16b, X_1.16b
+ eor Y_2.16b, TMP2.16b, X_2.16b
+ eor Y_3.16b, TMP3.16b, X_3.16b
+.endm
+
+/*
+ * _speck_unround_128bytes() - Speck decryption round on 128 bytes at a time
+ *
+ * This is the inverse of _speck_round_128bytes().
+ */
+.macro _speck_unround_128bytes n, lanes
+
+ // y ^= x
+ eor TMP0.16b, Y_0.16b, X_0.16b
+ eor TMP1.16b, Y_1.16b, X_1.16b
+ eor TMP2.16b, Y_2.16b, X_2.16b
+ eor TMP3.16b, Y_3.16b, X_3.16b
+
+ // y = ror(y, 3)
+ ushr Y_0.\lanes, TMP0.\lanes, #3
+ ushr Y_1.\lanes, TMP1.\lanes, #3
+ ushr Y_2.\lanes, TMP2.\lanes, #3
+ ushr Y_3.\lanes, TMP3.\lanes, #3
+ sli Y_0.\lanes, TMP0.\lanes, #(\n - 3)
+ sli Y_1.\lanes, TMP1.\lanes, #(\n - 3)
+ sli Y_2.\lanes, TMP2.\lanes, #(\n - 3)
+ sli Y_3.\lanes, TMP3.\lanes, #(\n - 3)
+
+ // x ^= k
+ eor X_0.16b, X_0.16b, ROUND_KEY.16b
+ eor X_1.16b, X_1.16b, ROUND_KEY.16b
+ eor X_2.16b, X_2.16b, ROUND_KEY.16b
+ eor X_3.16b, X_3.16b, ROUND_KEY.16b
+
+ // x -= y
+ sub X_0.\lanes, X_0.\lanes, Y_0.\lanes
+ sub X_1.\lanes, X_1.\lanes, Y_1.\lanes
+ sub X_2.\lanes, X_2.\lanes, Y_2.\lanes
+ sub X_3.\lanes, X_3.\lanes, Y_3.\lanes
+
+ // x = rol(x, 8)
+ tbl X_0.16b, {X_0.16b}, ROTATE_TABLE.16b
+ tbl X_1.16b, {X_1.16b}, ROTATE_TABLE.16b
+ tbl X_2.16b, {X_2.16b}, ROTATE_TABLE.16b
+ tbl X_3.16b, {X_3.16b}, ROTATE_TABLE.16b
+.endm
+
+.macro _next_xts_tweak next, cur, tmp, n
+.if \n == 64
+ /*
+ * Calculate the next tweak by multiplying the current one by x,
+ * modulo p(x) = x^128 + x^7 + x^2 + x + 1.
+ */
+ sshr \tmp\().2d, \cur\().2d, #63
+ and \tmp\().16b, \tmp\().16b, GFMUL_TABLE.16b
+ shl \next\().2d, \cur\().2d, #1
+ ext \tmp\().16b, \tmp\().16b, \tmp\().16b, #8
+ eor \next\().16b, \next\().16b, \tmp\().16b
+.else
+ /*
+ * Calculate the next two tweaks by multiplying the current ones by x^2,
+ * modulo p(x) = x^64 + x^4 + x^3 + x + 1.
+ */
+ ushr \tmp\().2d, \cur\().2d, #62
+ shl \next\().2d, \cur\().2d, #2
+ tbl \tmp\().16b, {GFMUL_TABLE.16b}, \tmp\().16b
+ eor \next\().16b, \next\().16b, \tmp\().16b
+.endif
+.endm
+
+/*
+ * _speck_xts_crypt() - Speck-XTS encryption/decryption
+ *
+ * Encrypt or decrypt NBYTES bytes of data from the SRC buffer to the DST buffer
+ * using Speck-XTS, specifically the variant with a block size of '2n' and round
+ * count given by NROUNDS. The expanded round keys are given in ROUND_KEYS, and
+ * the current XTS tweak value is given in TWEAK. It's assumed that NBYTES is a
+ * nonzero multiple of 128.
+ */
+.macro _speck_xts_crypt n, lanes, decrypting
+
+ /*
+ * If decrypting, modify the ROUND_KEYS parameter to point to the last
+ * round key rather than the first, since for decryption the round keys
+ * are used in reverse order.
+ */
+.if \decrypting
+ mov NROUNDS, NROUNDS /* zero the high 32 bits */
+.if \n == 64
+ add ROUND_KEYS, ROUND_KEYS, NROUNDS_X, lsl #3
+ sub ROUND_KEYS, ROUND_KEYS, #8
+.else
+ add ROUND_KEYS, ROUND_KEYS, NROUNDS_X, lsl #2
+ sub ROUND_KEYS, ROUND_KEYS, #4
+.endif
+.endif
+
+ // Load the index vector for tbl-based 8-bit rotates
+.if \decrypting
+ ldr ROTATE_TABLE_Q, .Lrol\n\()_8_table
+.else
+ ldr ROTATE_TABLE_Q, .Lror\n\()_8_table
+.endif
+
+ // One-time XTS preparation
+.if \n == 64
+ // Load first tweak
+ ld1 {TWEAKV0.16b}, [TWEAK]
+
+ // Load GF(2^128) multiplication table
+ ldr GFMUL_TABLE_Q, .Lgf128mul_table
+.else
+ // Load first tweak
+ ld1 {TWEAKV0.8b}, [TWEAK]
+
+ // Load GF(2^64) multiplication table
+ ldr GFMUL_TABLE_Q, .Lgf64mul_table
+
+ // Calculate second tweak, packing it together with the first
+ ushr TMP0.2d, TWEAKV0.2d, #63
+ shl TMP1.2d, TWEAKV0.2d, #1
+ tbl TMP0.8b, {GFMUL_TABLE.16b}, TMP0.8b
+ eor TMP0.8b, TMP0.8b, TMP1.8b
+ mov TWEAKV0.d[1], TMP0.d[0]
+.endif
+
+.Lnext_128bytes_\@:
+
+ // Calculate XTS tweaks for next 128 bytes
+ _next_xts_tweak TWEAKV1, TWEAKV0, TMP0, \n
+ _next_xts_tweak TWEAKV2, TWEAKV1, TMP0, \n
+ _next_xts_tweak TWEAKV3, TWEAKV2, TMP0, \n
+ _next_xts_tweak TWEAKV4, TWEAKV3, TMP0, \n
+ _next_xts_tweak TWEAKV5, TWEAKV4, TMP0, \n
+ _next_xts_tweak TWEAKV6, TWEAKV5, TMP0, \n
+ _next_xts_tweak TWEAKV7, TWEAKV6, TMP0, \n
+ _next_xts_tweak TWEAKV_NEXT, TWEAKV7, TMP0, \n
+
+ // Load the next source blocks into {X,Y}[0-3]
+ ld1 {X_0.16b-Y_1.16b}, [SRC], #64
+ ld1 {X_2.16b-Y_3.16b}, [SRC], #64
+
+ // XOR the source blocks with their XTS tweaks
+ eor TMP0.16b, X_0.16b, TWEAKV0.16b
+ eor Y_0.16b, Y_0.16b, TWEAKV1.16b
+ eor TMP1.16b, X_1.16b, TWEAKV2.16b
+ eor Y_1.16b, Y_1.16b, TWEAKV3.16b
+ eor TMP2.16b, X_2.16b, TWEAKV4.16b
+ eor Y_2.16b, Y_2.16b, TWEAKV5.16b
+ eor TMP3.16b, X_3.16b, TWEAKV6.16b
+ eor Y_3.16b, Y_3.16b, TWEAKV7.16b
+
+ /*
+ * De-interleave the 'x' and 'y' elements of each block, i.e. make it so
+ * that the X[0-3] registers contain only the second halves of blocks,
+ * and the Y[0-3] registers contain only the first halves of blocks.
+ * (Speck uses the order (y, x) rather than the more intuitive (x, y).)
+ */
+ uzp2 X_0.\lanes, TMP0.\lanes, Y_0.\lanes
+ uzp1 Y_0.\lanes, TMP0.\lanes, Y_0.\lanes
+ uzp2 X_1.\lanes, TMP1.\lanes, Y_1.\lanes
+ uzp1 Y_1.\lanes, TMP1.\lanes, Y_1.\lanes
+ uzp2 X_2.\lanes, TMP2.\lanes, Y_2.\lanes
+ uzp1 Y_2.\lanes, TMP2.\lanes, Y_2.\lanes
+ uzp2 X_3.\lanes, TMP3.\lanes, Y_3.\lanes
+ uzp1 Y_3.\lanes, TMP3.\lanes, Y_3.\lanes
+
+ // Do the cipher rounds
+ mov x6, ROUND_KEYS
+ mov w7, NROUNDS
+.Lnext_round_\@:
+.if \decrypting
+ ld1r {ROUND_KEY.\lanes}, [x6]
+ sub x6, x6, #( \n / 8 )
+ _speck_unround_128bytes \n, \lanes
+.else
+ ld1r {ROUND_KEY.\lanes}, [x6], #( \n / 8 )
+ _speck_round_128bytes \n, \lanes
+.endif
+ subs w7, w7, #1
+ bne .Lnext_round_\@
+
+ // Re-interleave the 'x' and 'y' elements of each block
+ zip1 TMP0.\lanes, Y_0.\lanes, X_0.\lanes
+ zip2 Y_0.\lanes, Y_0.\lanes, X_0.\lanes
+ zip1 TMP1.\lanes, Y_1.\lanes, X_1.\lanes
+ zip2 Y_1.\lanes, Y_1.\lanes, X_1.\lanes
+ zip1 TMP2.\lanes, Y_2.\lanes, X_2.\lanes
+ zip2 Y_2.\lanes, Y_2.\lanes, X_2.\lanes
+ zip1 TMP3.\lanes, Y_3.\lanes, X_3.\lanes
+ zip2 Y_3.\lanes, Y_3.\lanes, X_3.\lanes
+
+ // XOR the encrypted/decrypted blocks with the tweaks calculated earlier
+ eor X_0.16b, TMP0.16b, TWEAKV0.16b
+ eor Y_0.16b, Y_0.16b, TWEAKV1.16b
+ eor X_1.16b, TMP1.16b, TWEAKV2.16b
+ eor Y_1.16b, Y_1.16b, TWEAKV3.16b
+ eor X_2.16b, TMP2.16b, TWEAKV4.16b
+ eor Y_2.16b, Y_2.16b, TWEAKV5.16b
+ eor X_3.16b, TMP3.16b, TWEAKV6.16b
+ eor Y_3.16b, Y_3.16b, TWEAKV7.16b
+ mov TWEAKV0.16b, TWEAKV_NEXT.16b
+
+ // Store the ciphertext in the destination buffer
+ st1 {X_0.16b-Y_1.16b}, [DST], #64
+ st1 {X_2.16b-Y_3.16b}, [DST], #64
+
+ // Continue if there are more 128-byte chunks remaining
+ subs NBYTES, NBYTES, #128
+ bne .Lnext_128bytes_\@
+
+ // Store the next tweak and return
+.if \n == 64
+ st1 {TWEAKV_NEXT.16b}, [TWEAK]
+.else
+ st1 {TWEAKV_NEXT.8b}, [TWEAK]
+.endif
+ ret
+.endm
+
+ENTRY(speck128_xts_encrypt_neon)
+ _speck_xts_crypt n=64, lanes=2d, decrypting=0
+ENDPROC(speck128_xts_encrypt_neon)
+
+ENTRY(speck128_xts_decrypt_neon)
+ _speck_xts_crypt n=64, lanes=2d, decrypting=1
+ENDPROC(speck128_xts_decrypt_neon)
+
+ENTRY(speck64_xts_encrypt_neon)
+ _speck_xts_crypt n=32, lanes=4s, decrypting=0
+ENDPROC(speck64_xts_encrypt_neon)
+
+ENTRY(speck64_xts_decrypt_neon)
+ _speck_xts_crypt n=32, lanes=4s, decrypting=1
+ENDPROC(speck64_xts_decrypt_neon)
diff --git a/arch/arm64/crypto/speck-neon-glue.c b/arch/arm64/crypto/speck-neon-glue.c
new file mode 100644
index 000000000000..6e233aeb4ff4
--- /dev/null
+++ b/arch/arm64/crypto/speck-neon-glue.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS
+ * (64-bit version; based on the 32-bit version)
+ *
+ * Copyright (c) 2018 Google, Inc
+ */
+
+#include <asm/hwcap.h>
+#include <asm/neon.h>
+#include <asm/simd.h>
+#include <crypto/algapi.h>
+#include <crypto/gf128mul.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/speck.h>
+#include <crypto/xts.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+/* The assembly functions only handle multiples of 128 bytes */
+#define SPECK_NEON_CHUNK_SIZE 128
+
+/* Speck128 */
+
+struct speck128_xts_tfm_ctx {
+ struct speck128_tfm_ctx main_key;
+ struct speck128_tfm_ctx tweak_key;
+};
+
+asmlinkage void speck128_xts_encrypt_neon(const u64 *round_keys, int nrounds,
+ void *dst, const void *src,
+ unsigned int nbytes, void *tweak);
+
+asmlinkage void speck128_xts_decrypt_neon(const u64 *round_keys, int nrounds,
+ void *dst, const void *src,
+ unsigned int nbytes, void *tweak);
+
+typedef void (*speck128_crypt_one_t)(const struct speck128_tfm_ctx *,
+ u8 *, const u8 *);
+typedef void (*speck128_xts_crypt_many_t)(const u64 *, int, void *,
+ const void *, unsigned int, void *);
+
+static __always_inline int
+__speck128_xts_crypt(struct skcipher_request *req,
+ speck128_crypt_one_t crypt_one,
+ speck128_xts_crypt_many_t crypt_many)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ const struct speck128_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
+ le128 tweak;
+ int err;
+
+ err = skcipher_walk_virt(&walk, req, true);
+
+ crypto_speck128_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv);
+
+ while (walk.nbytes > 0) {
+ unsigned int nbytes = walk.nbytes;
+ u8 *dst = walk.dst.virt.addr;
+ const u8 *src = walk.src.virt.addr;
+
+ if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) {
+ unsigned int count;
+
+ count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE);
+ kernel_neon_begin();
+ (*crypt_many)(ctx->main_key.round_keys,
+ ctx->main_key.nrounds,
+ dst, src, count, &tweak);
+ kernel_neon_end();
+ dst += count;
+ src += count;
+ nbytes -= count;
+ }
+
+ /* Handle any remainder with generic code */
+ while (nbytes >= sizeof(tweak)) {
+ le128_xor((le128 *)dst, (const le128 *)src, &tweak);
+ (*crypt_one)(&ctx->main_key, dst, dst);
+ le128_xor((le128 *)dst, (const le128 *)dst, &tweak);
+ gf128mul_x_ble(&tweak, &tweak);
+
+ dst += sizeof(tweak);
+ src += sizeof(tweak);
+ nbytes -= sizeof(tweak);
+ }
+ err = skcipher_walk_done(&walk, nbytes);
+ }
+
+ return err;
+}
+
+static int speck128_xts_encrypt(struct skcipher_request *req)
+{
+ return __speck128_xts_crypt(req, crypto_speck128_encrypt,
+ speck128_xts_encrypt_neon);
+}
+
+static int speck128_xts_decrypt(struct skcipher_request *req)
+{
+ return __speck128_xts_crypt(req, crypto_speck128_decrypt,
+ speck128_xts_decrypt_neon);
+}
+
+static int speck128_xts_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct speck128_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
+ int err;
+
+ err = xts_verify_key(tfm, key, keylen);
+ if (err)
+ return err;
+
+ keylen /= 2;
+
+ err = crypto_speck128_setkey(&ctx->main_key, key, keylen);
+ if (err)
+ return err;
+
+ return crypto_speck128_setkey(&ctx->tweak_key, key + keylen, keylen);
+}
+
+/* Speck64 */
+
+struct speck64_xts_tfm_ctx {
+ struct speck64_tfm_ctx main_key;
+ struct speck64_tfm_ctx tweak_key;
+};
+
+asmlinkage void speck64_xts_encrypt_neon(const u32 *round_keys, int nrounds,
+ void *dst, const void *src,
+ unsigned int nbytes, void *tweak);
+
+asmlinkage void speck64_xts_decrypt_neon(const u32 *round_keys, int nrounds,
+ void *dst, const void *src,
+ unsigned int nbytes, void *tweak);
+
+typedef void (*speck64_crypt_one_t)(const struct speck64_tfm_ctx *,
+ u8 *, const u8 *);
+typedef void (*speck64_xts_crypt_many_t)(const u32 *, int, void *,
+ const void *, unsigned int, void *);
+
+static __always_inline int
+__speck64_xts_crypt(struct skcipher_request *req, speck64_crypt_one_t crypt_one,
+ speck64_xts_crypt_many_t crypt_many)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ const struct speck64_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
+ __le64 tweak;
+ int err;
+
+ err = skcipher_walk_virt(&walk, req, true);
+
+ crypto_speck64_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv);
+
+ while (walk.nbytes > 0) {
+ unsigned int nbytes = walk.nbytes;
+ u8 *dst = walk.dst.virt.addr;
+ const u8 *src = walk.src.virt.addr;
+
+ if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) {
+ unsigned int count;
+
+ count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE);
+ kernel_neon_begin();
+ (*crypt_many)(ctx->main_key.round_keys,
+ ctx->main_key.nrounds,
+ dst, src, count, &tweak);
+ kernel_neon_end();
+ dst += count;
+ src += count;
+ nbytes -= count;
+ }
+
+ /* Handle any remainder with generic code */
+ while (nbytes >= sizeof(tweak)) {
+ *(__le64 *)dst = *(__le64 *)src ^ tweak;
+ (*crypt_one)(&ctx->main_key, dst, dst);
+ *(__le64 *)dst ^= tweak;
+ tweak = cpu_to_le64((le64_to_cpu(tweak) << 1) ^
+ ((tweak & cpu_to_le64(1ULL << 63)) ?
+ 0x1B : 0));
+ dst += sizeof(tweak);
+ src += sizeof(tweak);
+ nbytes -= sizeof(tweak);
+ }
+ err = skcipher_walk_done(&walk, nbytes);
+ }
+
+ return err;
+}
+
+static int speck64_xts_encrypt(struct skcipher_request *req)
+{
+ return __speck64_xts_crypt(req, crypto_speck64_encrypt,
+ speck64_xts_encrypt_neon);
+}
+
+static int speck64_xts_decrypt(struct skcipher_request *req)
+{
+ return __speck64_xts_crypt(req, crypto_speck64_decrypt,
+ speck64_xts_decrypt_neon);
+}
+
+static int speck64_xts_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct speck64_xts_tfm_ctx *ctx = crypto_skcipher_ctx(tfm);
+ int err;
+
+ err = xts_verify_key(tfm, key, keylen);
+ if (err)
+ return err;
+
+ keylen /= 2;
+
+ err = crypto_speck64_setkey(&ctx->main_key, key, keylen);
+ if (err)
+ return err;
+
+ return crypto_speck64_setkey(&ctx->tweak_key, key + keylen, keylen);
+}
+
+static struct skcipher_alg speck_algs[] = {
+ {
+ .base.cra_name = "xts(speck128)",
+ .base.cra_driver_name = "xts-speck128-neon",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = SPECK128_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct speck128_xts_tfm_ctx),
+ .base.cra_alignmask = 7,
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = 2 * SPECK128_128_KEY_SIZE,
+ .max_keysize = 2 * SPECK128_256_KEY_SIZE,
+ .ivsize = SPECK128_BLOCK_SIZE,
+ .walksize = SPECK_NEON_CHUNK_SIZE,
+ .setkey = speck128_xts_setkey,
+ .encrypt = speck128_xts_encrypt,
+ .decrypt = speck128_xts_decrypt,
+ }, {
+ .base.cra_name = "xts(speck64)",
+ .base.cra_driver_name = "xts-speck64-neon",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = SPECK64_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct speck64_xts_tfm_ctx),
+ .base.cra_alignmask = 7,
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = 2 * SPECK64_96_KEY_SIZE,
+ .max_keysize = 2 * SPECK64_128_KEY_SIZE,
+ .ivsize = SPECK64_BLOCK_SIZE,
+ .walksize = SPECK_NEON_CHUNK_SIZE,
+ .setkey = speck64_xts_setkey,
+ .encrypt = speck64_xts_encrypt,
+ .decrypt = speck64_xts_decrypt,
+ }
+};
+
+static int __init speck_neon_module_init(void)
+{
+ if (!(elf_hwcap & HWCAP_ASIMD))
+ return -ENODEV;
+ return crypto_register_skciphers(speck_algs, ARRAY_SIZE(speck_algs));
+}
+
+static void __exit speck_neon_module_exit(void)
+{
+ crypto_unregister_skciphers(speck_algs, ARRAY_SIZE(speck_algs));
+}
+
+module_init(speck_neon_module_init);
+module_exit(speck_neon_module_exit);
+
+MODULE_DESCRIPTION("Speck block cipher (NEON-accelerated)");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>");
+MODULE_ALIAS_CRYPTO("xts(speck128)");
+MODULE_ALIAS_CRYPTO("xts-speck128-neon");
+MODULE_ALIAS_CRYPTO("xts(speck64)");
+MODULE_ALIAS_CRYPTO("xts-speck64-neon");
diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h
index 9becba9ab392..e278f94df0c9 100644
--- a/arch/arm64/include/asm/arch_gicv3.h
+++ b/arch/arm64/include/asm/arch_gicv3.h
@@ -76,11 +76,6 @@ static inline u64 gic_read_iar_cavium_thunderx(void)
return irqstat;
}
-static inline void gic_write_pmr(u32 val)
-{
- write_sysreg_s(val, SYS_ICC_PMR_EL1);
-}
-
static inline void gic_write_ctlr(u32 val)
{
write_sysreg_s(val, SYS_ICC_CTLR_EL1);
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 3c78835bba94..053d83e8db6f 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -202,25 +202,15 @@ lr .req x30 // link register
/*
* Pseudo-ops for PC-relative adr/ldr/str <reg>, <symbol> where
- * <symbol> is within the range +/- 4 GB of the PC when running
- * in core kernel context. In module context, a movz/movk sequence
- * is used, since modules may be loaded far away from the kernel
- * when KASLR is in effect.
+ * <symbol> is within the range +/- 4 GB of the PC.
*/
/*
* @dst: destination register (64 bit wide)
* @sym: name of the symbol
*/
.macro adr_l, dst, sym
-#ifndef MODULE
adrp \dst, \sym
add \dst, \dst, :lo12:\sym
-#else
- movz \dst, #:abs_g3:\sym
- movk \dst, #:abs_g2_nc:\sym
- movk \dst, #:abs_g1_nc:\sym
- movk \dst, #:abs_g0_nc:\sym
-#endif
.endm
/*
@@ -231,7 +221,6 @@ lr .req x30 // link register
* the address
*/
.macro ldr_l, dst, sym, tmp=
-#ifndef MODULE
.ifb \tmp
adrp \dst, \sym
ldr \dst, [\dst, :lo12:\sym]
@@ -239,15 +228,6 @@ lr .req x30 // link register
adrp \tmp, \sym
ldr \dst, [\tmp, :lo12:\sym]
.endif
-#else
- .ifb \tmp
- adr_l \dst, \sym
- ldr \dst, [\dst]
- .else
- adr_l \tmp, \sym
- ldr \dst, [\tmp]
- .endif
-#endif
.endm
/*
@@ -257,28 +237,18 @@ lr .req x30 // link register
* while <src> needs to be preserved.
*/
.macro str_l, src, sym, tmp
-#ifndef MODULE
adrp \tmp, \sym
str \src, [\tmp, :lo12:\sym]
-#else
- adr_l \tmp, \sym
- str \src, [\tmp]
-#endif
.endm
/*
- * @dst: Result of per_cpu(sym, smp_processor_id()), can be SP for
- * non-module code
+ * @dst: Result of per_cpu(sym, smp_processor_id()) (can be SP)
* @sym: The name of the per-cpu variable
* @tmp: scratch register
*/
.macro adr_this_cpu, dst, sym, tmp
-#ifndef MODULE
adrp \tmp, \sym
add \dst, \tmp, #:lo12:\sym
-#else
- adr_l \dst, \sym
-#endif
alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
mrs \tmp, tpidr_el1
alternative_else
diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
index ea9bb4e0e9bb..9bbffc7a301f 100644
--- a/arch/arm64/include/asm/cache.h
+++ b/arch/arm64/include/asm/cache.h
@@ -20,8 +20,12 @@
#define CTR_L1IP_SHIFT 14
#define CTR_L1IP_MASK 3
+#define CTR_DMINLINE_SHIFT 16
+#define CTR_ERG_SHIFT 20
#define CTR_CWG_SHIFT 24
#define CTR_CWG_MASK 15
+#define CTR_IDC_SHIFT 28
+#define CTR_DIC_SHIFT 29
#define CTR_L1IP(ctr) (((ctr) >> CTR_L1IP_SHIFT) & CTR_L1IP_MASK)
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index bef9f418f089..7dfcec4700fe 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -133,6 +133,9 @@ extern void flush_dcache_page(struct page *);
static inline void __flush_icache_all(void)
{
+ if (cpus_have_const_cap(ARM64_HAS_CACHE_DIC))
+ return;
+
asm("ic ialluis");
dsb(ish);
}
diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h
index ae852add053d..4f5fd2a36e6e 100644
--- a/arch/arm64/include/asm/cmpxchg.h
+++ b/arch/arm64/include/asm/cmpxchg.h
@@ -18,7 +18,8 @@
#ifndef __ASM_CMPXCHG_H
#define __ASM_CMPXCHG_H
-#include <linux/bug.h>
+#include <linux/build_bug.h>
+#include <linux/compiler.h>
#include <asm/atomic.h>
#include <asm/barrier.h>
@@ -196,32 +197,6 @@ __CMPXCHG_GEN(_mb)
__ret; \
})
-/* this_cpu_cmpxchg */
-#define _protect_cmpxchg_local(pcp, o, n) \
-({ \
- typeof(*raw_cpu_ptr(&(pcp))) __ret; \
- preempt_disable(); \
- __ret = cmpxchg_local(raw_cpu_ptr(&(pcp)), o, n); \
- preempt_enable(); \
- __ret; \
-})
-
-#define this_cpu_cmpxchg_1(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
-#define this_cpu_cmpxchg_2(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
-#define this_cpu_cmpxchg_4(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
-#define this_cpu_cmpxchg_8(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
-
-#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \
-({ \
- int __ret; \
- preempt_disable(); \
- __ret = cmpxchg_double_local( raw_cpu_ptr(&(ptr1)), \
- raw_cpu_ptr(&(ptr2)), \
- o1, o2, n1, n2); \
- preempt_enable(); \
- __ret; \
-})
-
#define __CMPWAIT_CASE(w, sz, name) \
static inline void __cmpwait_case_##name(volatile void *ptr, \
unsigned long val) \
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index bb263820de13..21bb624e0a7a 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -45,7 +45,11 @@
#define ARM64_HARDEN_BRANCH_PREDICTOR 24
#define ARM64_HARDEN_BP_POST_GUEST_EXIT 25
#define ARM64_HAS_RAS_EXTN 26
+#define ARM64_WORKAROUND_843419 27
+#define ARM64_HAS_CACHE_IDC 28
+#define ARM64_HAS_CACHE_DIC 29
+#define ARM64_HW_DBM 30
-#define ARM64_NCAPS 27
+#define ARM64_NCAPS 31
#endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 060e3a4008ab..09b0f2a80c8f 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -10,6 +10,7 @@
#define __ASM_CPUFEATURE_H
#include <asm/cpucaps.h>
+#include <asm/cputype.h>
#include <asm/fpsimd.h>
#include <asm/hwcap.h>
#include <asm/sigcontext.h>
@@ -89,24 +90,231 @@ struct arm64_ftr_reg {
extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0;
-/* scope of capability check */
-enum {
- SCOPE_SYSTEM,
- SCOPE_LOCAL_CPU,
-};
+/*
+ * CPU capabilities:
+ *
+ * We use arm64_cpu_capabilities to represent system features, errata work
+ * arounds (both used internally by kernel and tracked in cpu_hwcaps) and
+ * ELF HWCAPs (which are exposed to user).
+ *
+ * To support systems with heterogeneous CPUs, we need to make sure that we
+ * detect the capabilities correctly on the system and take appropriate
+ * measures to ensure there are no incompatibilities.
+ *
+ * This comment tries to explain how we treat the capabilities.
+ * Each capability has the following list of attributes :
+ *
+ * 1) Scope of Detection : The system detects a given capability by
+ * performing some checks at runtime. This could be, e.g, checking the
+ * value of a field in CPU ID feature register or checking the cpu
+ * model. The capability provides a call back ( @matches() ) to
+ * perform the check. Scope defines how the checks should be performed.
+ * There are three cases:
+ *
+ * a) SCOPE_LOCAL_CPU: check all the CPUs and "detect" if at least one
+ * matches. This implies, we have to run the check on all the
+ * booting CPUs, until the system decides that state of the
+ * capability is finalised. (See section 2 below)
+ * Or
+ * b) SCOPE_SYSTEM: check all the CPUs and "detect" if all the CPUs
+ * matches. This implies, we run the check only once, when the
+ * system decides to finalise the state of the capability. If the
+ * capability relies on a field in one of the CPU ID feature
+ * registers, we use the sanitised value of the register from the
+ * CPU feature infrastructure to make the decision.
+ * Or
+ * c) SCOPE_BOOT_CPU: Check only on the primary boot CPU to detect the
+ * feature. This category is for features that are "finalised"
+ * (or used) by the kernel very early even before the SMP cpus
+ * are brought up.
+ *
+ * The process of detection is usually denoted by "update" capability
+ * state in the code.
+ *
+ * 2) Finalise the state : The kernel should finalise the state of a
+ * capability at some point during its execution and take necessary
+ * actions if any. Usually, this is done, after all the boot-time
+ * enabled CPUs are brought up by the kernel, so that it can make
+ * better decision based on the available set of CPUs. However, there
+ * are some special cases, where the action is taken during the early
+ * boot by the primary boot CPU. (e.g, running the kernel at EL2 with
+ * Virtualisation Host Extensions). The kernel usually disallows any
+ * changes to the state of a capability once it finalises the capability
+ * and takes any action, as it may be impossible to execute the actions
+ * safely. A CPU brought up after a capability is "finalised" is
+ * referred to as "Late CPU" w.r.t the capability. e.g, all secondary
+ * CPUs are treated "late CPUs" for capabilities determined by the boot
+ * CPU.
+ *
+ * At the moment there are two passes of finalising the capabilities.
+ * a) Boot CPU scope capabilities - Finalised by primary boot CPU via
+ * setup_boot_cpu_capabilities().
+ * b) Everything except (a) - Run via setup_system_capabilities().
+ *
+ * 3) Verification: When a CPU is brought online (e.g, by user or by the
+ * kernel), the kernel should make sure that it is safe to use the CPU,
+ * by verifying that the CPU is compliant with the state of the
+ * capabilities finalised already. This happens via :
+ *
+ * secondary_start_kernel()-> check_local_cpu_capabilities()
+ *
+ * As explained in (2) above, capabilities could be finalised at
+ * different points in the execution. Each newly booted CPU is verified
+ * against the capabilities that have been finalised by the time it
+ * boots.
+ *
+ * a) SCOPE_BOOT_CPU : All CPUs are verified against the capability
+ * except for the primary boot CPU.
+ *
+ * b) SCOPE_LOCAL_CPU, SCOPE_SYSTEM: All CPUs hotplugged on by the
+ * user after the kernel boot are verified against the capability.
+ *
+ * If there is a conflict, the kernel takes an action, based on the
+ * severity (e.g, a CPU could be prevented from booting or cause a
+ * kernel panic). The CPU is allowed to "affect" the state of the
+ * capability, if it has not been finalised already. See section 5
+ * for more details on conflicts.
+ *
+ * 4) Action: As mentioned in (2), the kernel can take an action for each
+ * detected capability, on all CPUs on the system. Appropriate actions
+ * include, turning on an architectural feature, modifying the control
+ * registers (e.g, SCTLR, TCR etc.) or patching the kernel via
+ * alternatives. The kernel patching is batched and performed at later
+ * point. The actions are always initiated only after the capability
+ * is finalised. This is usally denoted by "enabling" the capability.
+ * The actions are initiated as follows :
+ * a) Action is triggered on all online CPUs, after the capability is
+ * finalised, invoked within the stop_machine() context from
+ * enable_cpu_capabilitie().
+ *
+ * b) Any late CPU, brought up after (1), the action is triggered via:
+ *
+ * check_local_cpu_capabilities() -> verify_local_cpu_capabilities()
+ *
+ * 5) Conflicts: Based on the state of the capability on a late CPU vs.
+ * the system state, we could have the following combinations :
+ *
+ * x-----------------------------x
+ * | Type | System | Late CPU |
+ * |-----------------------------|
+ * | a | y | n |
+ * |-----------------------------|
+ * | b | n | y |
+ * x-----------------------------x
+ *
+ * Two separate flag bits are defined to indicate whether each kind of
+ * conflict can be allowed:
+ * ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU - Case(a) is allowed
+ * ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU - Case(b) is allowed
+ *
+ * Case (a) is not permitted for a capability that the system requires
+ * all CPUs to have in order for the capability to be enabled. This is
+ * typical for capabilities that represent enhanced functionality.
+ *
+ * Case (b) is not permitted for a capability that must be enabled
+ * during boot if any CPU in the system requires it in order to run
+ * safely. This is typical for erratum work arounds that cannot be
+ * enabled after the corresponding capability is finalised.
+ *
+ * In some non-typical cases either both (a) and (b), or neither,
+ * should be permitted. This can be described by including neither
+ * or both flags in the capability's type field.
+ */
+
+
+/*
+ * Decide how the capability is detected.
+ * On any local CPU vs System wide vs the primary boot CPU
+ */
+#define ARM64_CPUCAP_SCOPE_LOCAL_CPU ((u16)BIT(0))
+#define ARM64_CPUCAP_SCOPE_SYSTEM ((u16)BIT(1))
+/*
+ * The capabilitiy is detected on the Boot CPU and is used by kernel
+ * during early boot. i.e, the capability should be "detected" and
+ * "enabled" as early as possibly on all booting CPUs.
+ */
+#define ARM64_CPUCAP_SCOPE_BOOT_CPU ((u16)BIT(2))
+#define ARM64_CPUCAP_SCOPE_MASK \
+ (ARM64_CPUCAP_SCOPE_SYSTEM | \
+ ARM64_CPUCAP_SCOPE_LOCAL_CPU | \
+ ARM64_CPUCAP_SCOPE_BOOT_CPU)
+
+#define SCOPE_SYSTEM ARM64_CPUCAP_SCOPE_SYSTEM
+#define SCOPE_LOCAL_CPU ARM64_CPUCAP_SCOPE_LOCAL_CPU
+#define SCOPE_BOOT_CPU ARM64_CPUCAP_SCOPE_BOOT_CPU
+#define SCOPE_ALL ARM64_CPUCAP_SCOPE_MASK
+
+/*
+ * Is it permitted for a late CPU to have this capability when system
+ * hasn't already enabled it ?
+ */
+#define ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU ((u16)BIT(4))
+/* Is it safe for a late CPU to miss this capability when system has it */
+#define ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU ((u16)BIT(5))
+
+/*
+ * CPU errata workarounds that need to be enabled at boot time if one or
+ * more CPUs in the system requires it. When one of these capabilities
+ * has been enabled, it is safe to allow any CPU to boot that doesn't
+ * require the workaround. However, it is not safe if a "late" CPU
+ * requires a workaround and the system hasn't enabled it already.
+ */
+#define ARM64_CPUCAP_LOCAL_CPU_ERRATUM \
+ (ARM64_CPUCAP_SCOPE_LOCAL_CPU | ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU)
+/*
+ * CPU feature detected at boot time based on system-wide value of a
+ * feature. It is safe for a late CPU to have this feature even though
+ * the system hasn't enabled it, although the featuer will not be used
+ * by Linux in this case. If the system has enabled this feature already,
+ * then every late CPU must have it.
+ */
+#define ARM64_CPUCAP_SYSTEM_FEATURE \
+ (ARM64_CPUCAP_SCOPE_SYSTEM | ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU)
+/*
+ * CPU feature detected at boot time based on feature of one or more CPUs.
+ * All possible conflicts for a late CPU are ignored.
+ */
+#define ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE \
+ (ARM64_CPUCAP_SCOPE_LOCAL_CPU | \
+ ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU | \
+ ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU)
+
+/*
+ * CPU feature detected at boot time, on one or more CPUs. A late CPU
+ * is not allowed to have the capability when the system doesn't have it.
+ * It is Ok for a late CPU to miss the feature.
+ */
+#define ARM64_CPUCAP_BOOT_RESTRICTED_CPU_LOCAL_FEATURE \
+ (ARM64_CPUCAP_SCOPE_LOCAL_CPU | \
+ ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU)
+
+/*
+ * CPU feature used early in the boot based on the boot CPU. All secondary
+ * CPUs must match the state of the capability as detected by the boot CPU.
+ */
+#define ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE ARM64_CPUCAP_SCOPE_BOOT_CPU
struct arm64_cpu_capabilities {
const char *desc;
u16 capability;
- int def_scope; /* default scope */
+ u16 type;
bool (*matches)(const struct arm64_cpu_capabilities *caps, int scope);
- int (*enable)(void *); /* Called on all active CPUs */
+ /*
+ * Take the appropriate actions to enable this capability for this CPU.
+ * For each successfully booted CPU, this method is called for each
+ * globally detected capability.
+ */
+ void (*cpu_enable)(const struct arm64_cpu_capabilities *cap);
union {
struct { /* To be used for erratum handling only */
- u32 midr_model;
- u32 midr_range_min, midr_range_max;
+ struct midr_range midr_range;
+ const struct arm64_midr_revidr {
+ u32 midr_rv; /* revision/variant */
+ u32 revidr_mask;
+ } * const fixed_revs;
};
+ const struct midr_range *midr_range_list;
struct { /* Feature register checking */
u32 sys_reg;
u8 field_pos;
@@ -115,9 +323,38 @@ struct arm64_cpu_capabilities {
bool sign;
unsigned long hwcap;
};
+ /*
+ * A list of "matches/cpu_enable" pair for the same
+ * "capability" of the same "type" as described by the parent.
+ * Only matches(), cpu_enable() and fields relevant to these
+ * methods are significant in the list. The cpu_enable is
+ * invoked only if the corresponding entry "matches()".
+ * However, if a cpu_enable() method is associated
+ * with multiple matches(), care should be taken that either
+ * the match criteria are mutually exclusive, or that the
+ * method is robust against being called multiple times.
+ */
+ const struct arm64_cpu_capabilities *match_list;
};
};
+static inline int cpucap_default_scope(const struct arm64_cpu_capabilities *cap)
+{
+ return cap->type & ARM64_CPUCAP_SCOPE_MASK;
+}
+
+static inline bool
+cpucap_late_cpu_optional(const struct arm64_cpu_capabilities *cap)
+{
+ return !!(cap->type & ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU);
+}
+
+static inline bool
+cpucap_late_cpu_permitted(const struct arm64_cpu_capabilities *cap)
+{
+ return !!(cap->type & ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU);
+}
+
extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS];
extern struct static_key_false arm64_const_caps_ready;
@@ -236,15 +473,8 @@ static inline bool id_aa64pfr0_sve(u64 pfr0)
}
void __init setup_cpu_features(void);
-
-void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
- const char *info);
-void enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps);
void check_local_cpu_capabilities(void);
-void update_cpu_errata_workarounds(void);
-void __init enable_errata_workarounds(void);
-void verify_local_cpu_errata_workarounds(void);
u64 read_sanitised_ftr_reg(u32 id);
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index 350c76a1d15b..30014a9f8f2b 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -83,6 +83,8 @@
#define ARM_CPU_PART_CORTEX_A53 0xD03
#define ARM_CPU_PART_CORTEX_A73 0xD09
#define ARM_CPU_PART_CORTEX_A75 0xD0A
+#define ARM_CPU_PART_CORTEX_A35 0xD04
+#define ARM_CPU_PART_CORTEX_A55 0xD05
#define APM_CPU_PART_POTENZA 0x000
@@ -102,6 +104,8 @@
#define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72)
#define MIDR_CORTEX_A73 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73)
#define MIDR_CORTEX_A75 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A75)
+#define MIDR_CORTEX_A35 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A35)
+#define MIDR_CORTEX_A55 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A55)
#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
#define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
@@ -118,6 +122,45 @@
#define read_cpuid(reg) read_sysreg_s(SYS_ ## reg)
/*
+ * Represent a range of MIDR values for a given CPU model and a
+ * range of variant/revision values.
+ *
+ * @model - CPU model as defined by MIDR_CPU_MODEL
+ * @rv_min - Minimum value for the revision/variant as defined by
+ * MIDR_CPU_VAR_REV
+ * @rv_max - Maximum value for the variant/revision for the range.
+ */
+struct midr_range {
+ u32 model;
+ u32 rv_min;
+ u32 rv_max;
+};
+
+#define MIDR_RANGE(m, v_min, r_min, v_max, r_max) \
+ { \
+ .model = m, \
+ .rv_min = MIDR_CPU_VAR_REV(v_min, r_min), \
+ .rv_max = MIDR_CPU_VAR_REV(v_max, r_max), \
+ }
+
+#define MIDR_ALL_VERSIONS(m) MIDR_RANGE(m, 0, 0, 0xf, 0xf)
+
+static inline bool is_midr_in_range(u32 midr, struct midr_range const *range)
+{
+ return MIDR_IS_CPU_MODEL_RANGE(midr, range->model,
+ range->rv_min, range->rv_max);
+}
+
+static inline bool
+is_midr_in_range_list(u32 midr, struct midr_range const *ranges)
+{
+ while (ranges->model)
+ if (is_midr_in_range(midr, ranges++))
+ return true;
+ return false;
+}
+
+/*
* The CPU ID never changes at run time, so we might as well tell the
* compiler that it's constant. Use this function to read the CPU ID
* rather than directly reading processor_id or read_cpuid() directly.
diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index 803443d74926..ce70c3ffb993 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -240,6 +240,15 @@
(((e) & ESR_ELx_SYS64_ISS_OP2_MASK) >> \
ESR_ELx_SYS64_ISS_OP2_SHIFT))
+/*
+ * ISS field definitions for floating-point exception traps
+ * (FP_EXC_32/FP_EXC_64).
+ *
+ * (The FPEXC_* constants are used instead for common bits.)
+ */
+
+#define ESR_ELx_FP_EXC_TFV (UL(1) << 23)
+
#ifndef __ASSEMBLY__
#include <asm/types.h>
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 8857a0f0d0f7..aa7162ae93e3 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -22,33 +22,9 @@
#ifndef __ASSEMBLY__
#include <linux/cache.h>
+#include <linux/init.h>
#include <linux/stddef.h>
-/*
- * FP/SIMD storage area has:
- * - FPSR and FPCR
- * - 32 128-bit data registers
- *
- * Note that user_fpsimd forms a prefix of this structure, which is
- * relied upon in the ptrace FP/SIMD accessors.
- */
-struct fpsimd_state {
- union {
- struct user_fpsimd_state user_fpsimd;
- struct {
- __uint128_t vregs[32];
- u32 fpsr;
- u32 fpcr;
- /*
- * For ptrace compatibility, pad to next 128-bit
- * boundary here if extending this struct.
- */
- };
- };
- /* the id of the last cpu to have restored this state */
- unsigned int cpu;
-};
-
#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
/* Masks for extracting the FPSR and FPCR from the FPSCR */
#define VFP_FPSCR_STAT_MASK 0xf800009f
@@ -62,8 +38,8 @@ struct fpsimd_state {
struct task_struct;
-extern void fpsimd_save_state(struct fpsimd_state *state);
-extern void fpsimd_load_state(struct fpsimd_state *state);
+extern void fpsimd_save_state(struct user_fpsimd_state *state);
+extern void fpsimd_load_state(struct user_fpsimd_state *state);
extern void fpsimd_thread_switch(struct task_struct *next);
extern void fpsimd_flush_thread(void);
@@ -83,7 +59,9 @@ extern void sve_save_state(void *state, u32 *pfpsr);
extern void sve_load_state(void const *state, u32 const *pfpsr,
unsigned long vq_minus_1);
extern unsigned int sve_get_vl(void);
-extern int sve_kernel_enable(void *);
+
+struct arm64_cpu_capabilities;
+extern void sve_kernel_enable(const struct arm64_cpu_capabilities *__unused);
extern int __ro_after_init sve_max_vl;
diff --git a/arch/arm64/include/asm/lse.h b/arch/arm64/include/asm/lse.h
index eec95768eaad..8262325e2fc6 100644
--- a/arch/arm64/include/asm/lse.h
+++ b/arch/arm64/include/asm/lse.h
@@ -4,8 +4,11 @@
#if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS)
+#include <linux/compiler_types.h>
+#include <linux/export.h>
#include <linux/stringify.h>
#include <asm/alternative.h>
+#include <asm/cpucaps.h>
#ifdef __ASSEMBLER__
diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h
index 4f766178fa6f..b6dbbe3123a9 100644
--- a/arch/arm64/include/asm/module.h
+++ b/arch/arm64/include/asm/module.h
@@ -39,6 +39,8 @@ struct mod_arch_specific {
u64 module_emit_plt_entry(struct module *mod, void *loc, const Elf64_Rela *rela,
Elf64_Sym *sym);
+u64 module_emit_adrp_veneer(struct module *mod, void *loc, u64 val);
+
#ifdef CONFIG_RANDOMIZE_BASE
extern u64 module_alloc_base;
#else
diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h
index 43393208229e..9234013e759e 100644
--- a/arch/arm64/include/asm/percpu.h
+++ b/arch/arm64/include/asm/percpu.h
@@ -16,7 +16,10 @@
#ifndef __ASM_PERCPU_H
#define __ASM_PERCPU_H
+#include <linux/preempt.h>
+
#include <asm/alternative.h>
+#include <asm/cmpxchg.h>
#include <asm/stack_pointer.h>
static inline void set_my_cpu_offset(unsigned long off)
@@ -197,6 +200,32 @@ static inline unsigned long __percpu_xchg(void *ptr, unsigned long val,
return ret;
}
+/* this_cpu_cmpxchg */
+#define _protect_cmpxchg_local(pcp, o, n) \
+({ \
+ typeof(*raw_cpu_ptr(&(pcp))) __ret; \
+ preempt_disable(); \
+ __ret = cmpxchg_local(raw_cpu_ptr(&(pcp)), o, n); \
+ preempt_enable(); \
+ __ret; \
+})
+
+#define this_cpu_cmpxchg_1(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_2(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_4(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+#define this_cpu_cmpxchg_8(ptr, o, n) _protect_cmpxchg_local(ptr, o, n)
+
+#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \
+({ \
+ int __ret; \
+ preempt_disable(); \
+ __ret = cmpxchg_double_local( raw_cpu_ptr(&(ptr1)), \
+ raw_cpu_ptr(&(ptr2)), \
+ o1, o2, n1, n2); \
+ preempt_enable(); \
+ __ret; \
+})
+
#define _percpu_read(pcp) \
({ \
typeof(pcp) __retval; \
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index cdfe3e657a9e..fd208eac9f2a 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -291,6 +291,7 @@
#define TCR_TBI0 (UL(1) << 37)
#define TCR_HA (UL(1) << 39)
#define TCR_HD (UL(1) << 40)
+#define TCR_NFD1 (UL(1) << 54)
/*
* TTBR.
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index fce604e3e599..767598932549 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -34,10 +34,12 @@
#ifdef __KERNEL__
+#include <linux/build_bug.h>
+#include <linux/stddef.h>
#include <linux/string.h>
#include <asm/alternative.h>
-#include <asm/fpsimd.h>
+#include <asm/cpufeature.h>
#include <asm/hw_breakpoint.h>
#include <asm/lse.h>
#include <asm/pgtable-hwdef.h>
@@ -103,11 +105,19 @@ struct cpu_context {
struct thread_struct {
struct cpu_context cpu_context; /* cpu context */
- unsigned long tp_value; /* TLS register */
-#ifdef CONFIG_COMPAT
- unsigned long tp2_value;
-#endif
- struct fpsimd_state fpsimd_state;
+
+ /*
+ * Whitelisted fields for hardened usercopy:
+ * Maintainers must ensure manually that this contains no
+ * implicit padding.
+ */
+ struct {
+ unsigned long tp_value; /* TLS register */
+ unsigned long tp2_value;
+ struct user_fpsimd_state fpsimd_state;
+ } uw;
+
+ unsigned int fpsimd_cpu;
void *sve_state; /* SVE registers, if any */
unsigned int sve_vl; /* SVE vector length */
unsigned int sve_vl_onexec; /* SVE vl after next exec */
@@ -116,14 +126,17 @@ struct thread_struct {
struct debug_info debug; /* debugging */
};
-/*
- * Everything usercopied to/from thread_struct is statically-sized, so
- * no hardened usercopy whitelist is needed.
- */
static inline void arch_thread_struct_whitelist(unsigned long *offset,
unsigned long *size)
{
- *offset = *size = 0;
+ /* Verify that there is no padding among the whitelisted fields: */
+ BUILD_BUG_ON(sizeof_field(struct thread_struct, uw) !=
+ sizeof_field(struct thread_struct, uw.tp_value) +
+ sizeof_field(struct thread_struct, uw.tp2_value) +
+ sizeof_field(struct thread_struct, uw.fpsimd_state));
+
+ *offset = offsetof(struct thread_struct, uw);
+ *size = sizeof_field(struct thread_struct, uw);
}
#ifdef CONFIG_COMPAT
@@ -131,13 +144,13 @@ static inline void arch_thread_struct_whitelist(unsigned long *offset,
({ \
unsigned long *__tls; \
if (is_compat_thread(task_thread_info(t))) \
- __tls = &(t)->thread.tp2_value; \
+ __tls = &(t)->thread.uw.tp2_value; \
else \
- __tls = &(t)->thread.tp_value; \
+ __tls = &(t)->thread.uw.tp_value; \
__tls; \
})
#else
-#define task_user_tls(t) (&(t)->thread.tp_value)
+#define task_user_tls(t) (&(t)->thread.uw.tp_value)
#endif
/* Sync TPIDR_EL0 back to thread_struct for current */
@@ -227,9 +240,9 @@ static inline void spin_lock_prefetch(const void *ptr)
#endif
-int cpu_enable_pan(void *__unused);
-int cpu_enable_cache_maint_trap(void *__unused);
-int cpu_clear_disr(void *__unused);
+void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused);
+void cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused);
+void cpu_clear_disr(const struct arm64_cpu_capabilities *__unused);
/* Userspace interface for PR_SVE_{SET,GET}_VL prctl()s: */
#define SVE_SET_VL(arg) sve_set_current_vl(arg)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 0e1960c59197..e7b9f154e476 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -490,6 +490,7 @@
#define SCTLR_EL1_BUILD_BUG_ON_MISSING_BITS BUILD_BUG_ON((SCTLR_EL1_SET ^ SCTLR_EL1_CLEAR) != ~0)
/* id_aa64isar0 */
+#define ID_AA64ISAR0_TS_SHIFT 52
#define ID_AA64ISAR0_FHM_SHIFT 48
#define ID_AA64ISAR0_DP_SHIFT 44
#define ID_AA64ISAR0_SM4_SHIFT 40
@@ -511,6 +512,7 @@
/* id_aa64pfr0 */
#define ID_AA64PFR0_CSV3_SHIFT 60
#define ID_AA64PFR0_CSV2_SHIFT 56
+#define ID_AA64PFR0_DIT_SHIFT 48
#define ID_AA64PFR0_SVE_SHIFT 32
#define ID_AA64PFR0_RAS_SHIFT 28
#define ID_AA64PFR0_GIC_SHIFT 24
@@ -568,6 +570,7 @@
#define ID_AA64MMFR1_VMIDBITS_16 2
/* id_aa64mmfr2 */
+#define ID_AA64MMFR2_AT_SHIFT 32
#define ID_AA64MMFR2_LVA_SHIFT 16
#define ID_AA64MMFR2_IESB_SHIFT 12
#define ID_AA64MMFR2_LSM_SHIFT 8
diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h
index 07aa8e3c5630..28893a0b141d 100644
--- a/arch/arm64/include/asm/system_misc.h
+++ b/arch/arm64/include/asm/system_misc.h
@@ -45,17 +45,6 @@ extern void __show_regs(struct pt_regs *);
extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
-#define show_unhandled_signals_ratelimited() \
-({ \
- static DEFINE_RATELIMIT_STATE(_rs, \
- DEFAULT_RATELIMIT_INTERVAL, \
- DEFAULT_RATELIMIT_BURST); \
- bool __show_ratelimited = false; \
- if (show_unhandled_signals && __ratelimit(&_rs)) \
- __show_ratelimited = true; \
- __show_ratelimited; \
-})
-
int handle_guest_sea(phys_addr_t addr, unsigned int esr);
#endif /* __ASSEMBLY__ */
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 9e82dd79c7db..dfc61d73f740 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -60,6 +60,15 @@
__tlbi(op, (arg) | USER_ASID_FLAG); \
} while (0)
+/* This macro creates a properly formatted VA operand for the TLBI */
+#define __TLBI_VADDR(addr, asid) \
+ ({ \
+ unsigned long __ta = (addr) >> 12; \
+ __ta &= GENMASK_ULL(43, 0); \
+ __ta |= (unsigned long)(asid) << 48; \
+ __ta; \
+ })
+
/*
* TLB Management
* ==============
@@ -117,7 +126,7 @@ static inline void flush_tlb_all(void)
static inline void flush_tlb_mm(struct mm_struct *mm)
{
- unsigned long asid = ASID(mm) << 48;
+ unsigned long asid = __TLBI_VADDR(0, ASID(mm));
dsb(ishst);
__tlbi(aside1is, asid);
@@ -128,7 +137,7 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
static inline void flush_tlb_page(struct vm_area_struct *vma,
unsigned long uaddr)
{
- unsigned long addr = uaddr >> 12 | (ASID(vma->vm_mm) << 48);
+ unsigned long addr = __TLBI_VADDR(uaddr, ASID(vma->vm_mm));
dsb(ishst);
__tlbi(vale1is, addr);
@@ -146,7 +155,7 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end,
bool last_level)
{
- unsigned long asid = ASID(vma->vm_mm) << 48;
+ unsigned long asid = ASID(vma->vm_mm);
unsigned long addr;
if ((end - start) > MAX_TLB_RANGE) {
@@ -154,8 +163,8 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,
return;
}
- start = asid | (start >> 12);
- end = asid | (end >> 12);
+ start = __TLBI_VADDR(start, asid);
+ end = __TLBI_VADDR(end, asid);
dsb(ishst);
for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) {
@@ -185,8 +194,8 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
return;
}
- start >>= 12;
- end >>= 12;
+ start = __TLBI_VADDR(start, 0);
+ end = __TLBI_VADDR(end, 0);
dsb(ishst);
for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12))
@@ -202,7 +211,7 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
static inline void __flush_tlb_pgtable(struct mm_struct *mm,
unsigned long uaddr)
{
- unsigned long addr = uaddr >> 12 | (ASID(mm) << 48);
+ unsigned long addr = __TLBI_VADDR(uaddr, ASID(mm));
__tlbi(vae1is, addr);
__tlbi_user(vae1is, addr);
diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h
index 178e338d2889..c320f3bf6c57 100644
--- a/arch/arm64/include/asm/traps.h
+++ b/arch/arm64/include/asm/traps.h
@@ -35,10 +35,10 @@ struct undef_hook {
void register_undef_hook(struct undef_hook *hook);
void unregister_undef_hook(struct undef_hook *hook);
-void force_signal_inject(int signal, int code, struct pt_regs *regs,
- unsigned long address);
-
-void arm64_notify_segfault(struct pt_regs *regs, unsigned long addr);
+void force_signal_inject(int signal, int code, unsigned long address);
+void arm64_notify_segfault(unsigned long addr);
+void arm64_force_sig_info(struct siginfo *info, const char *str,
+ struct task_struct *tsk);
/*
* Move regs->pc to next instruction and do necessary setup before it
diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
index c5f89442785c..9d1e24e030b3 100644
--- a/arch/arm64/include/asm/virt.h
+++ b/arch/arm64/include/asm/virt.h
@@ -102,12 +102,6 @@ static inline bool has_vhe(void)
return false;
}
-#ifdef CONFIG_ARM64_VHE
-extern void verify_cpu_run_el(void);
-#else
-static inline void verify_cpu_run_el(void) {}
-#endif
-
#endif /* __ASSEMBLY__ */
#endif /* ! __ASM__VIRT_H */
diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
index f018c3deea3b..17c65c8f33cb 100644
--- a/arch/arm64/include/uapi/asm/hwcap.h
+++ b/arch/arm64/include/uapi/asm/hwcap.h
@@ -44,5 +44,9 @@
#define HWCAP_SHA512 (1 << 21)
#define HWCAP_SVE (1 << 22)
#define HWCAP_ASIMDFHM (1 << 23)
+#define HWCAP_DIT (1 << 24)
+#define HWCAP_USCAT (1 << 25)
+#define HWCAP_ILRCPC (1 << 26)
+#define HWCAP_FLAGM (1 << 27)
#endif /* _UAPI__ASM_HWCAP_H */
diff --git a/arch/arm64/include/uapi/asm/siginfo.h b/arch/arm64/include/uapi/asm/siginfo.h
index 9b4d91277742..574d12f86039 100644
--- a/arch/arm64/include/uapi/asm/siginfo.h
+++ b/arch/arm64/include/uapi/asm/siginfo.h
@@ -21,25 +21,4 @@
#include <asm-generic/siginfo.h>
-/*
- * SIGFPE si_codes
- */
-#ifdef __KERNEL__
-#define FPE_FIXME 0 /* Broken dup of SI_USER */
-#endif /* __KERNEL__ */
-
-/*
- * SIGBUS si_codes
- */
-#ifdef __KERNEL__
-#define BUS_FIXME 0 /* Broken dup of SI_USER */
-#endif /* __KERNEL__ */
-
-/*
- * SIGTRAP si_codes
- */
-#ifdef __KERNEL__
-#define TRAP_FIXME 0 /* Broken dup of SI_USER */
-#endif /* __KERNEL__ */
-
#endif
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index 68450e954d47..6e47fc3ab549 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -429,7 +429,7 @@ ret:
fault:
pr_debug("SWP{B} emulation: access caused memory abort!\n");
- arm64_notify_segfault(regs, address);
+ arm64_notify_segfault(address);
return 0;
}
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index b5a28336c077..2df792771053 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -24,10 +24,28 @@
static bool __maybe_unused
is_affected_midr_range(const struct arm64_cpu_capabilities *entry, int scope)
{
+ const struct arm64_midr_revidr *fix;
+ u32 midr = read_cpuid_id(), revidr;
+
+ WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
+ if (!is_midr_in_range(midr, &entry->midr_range))
+ return false;
+
+ midr &= MIDR_REVISION_MASK | MIDR_VARIANT_MASK;
+ revidr = read_cpuid(REVIDR_EL1);
+ for (fix = entry->fixed_revs; fix && fix->revidr_mask; fix++)
+ if (midr == fix->midr_rv && (revidr & fix->revidr_mask))
+ return false;
+
+ return true;
+}
+
+static bool __maybe_unused
+is_affected_midr_range_list(const struct arm64_cpu_capabilities *entry,
+ int scope)
+{
WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
- return MIDR_IS_CPU_MODEL_RANGE(read_cpuid_id(), entry->midr_model,
- entry->midr_range_min,
- entry->midr_range_max);
+ return is_midr_in_range_list(read_cpuid_id(), entry->midr_range_list);
}
static bool __maybe_unused
@@ -41,7 +59,7 @@ is_kryo_midr(const struct arm64_cpu_capabilities *entry, int scope)
model &= MIDR_IMPLEMENTOR_MASK | (0xf00 << MIDR_PARTNUM_SHIFT) |
MIDR_ARCHITECTURE_MASK;
- return model == entry->midr_model;
+ return model == entry->midr_range.model;
}
static bool
@@ -53,11 +71,11 @@ has_mismatched_cache_line_size(const struct arm64_cpu_capabilities *entry,
(arm64_ftr_reg_ctrel0.sys_val & arm64_ftr_reg_ctrel0.strict_mask);
}
-static int cpu_enable_trap_ctr_access(void *__unused)
+static void
+cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *__unused)
{
/* Clear SCTLR_EL1.UCT */
config_sctlr_el1(SCTLR_EL1_UCT, 0);
- return 0;
}
#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
@@ -161,25 +179,25 @@ static void call_hvc_arch_workaround_1(void)
arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
}
-static int enable_smccc_arch_workaround_1(void *data)
+static void
+enable_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
{
- const struct arm64_cpu_capabilities *entry = data;
bp_hardening_cb_t cb;
void *smccc_start, *smccc_end;
struct arm_smccc_res res;
if (!entry->matches(entry, SCOPE_LOCAL_CPU))
- return 0;
+ return;
if (psci_ops.smccc_version == SMCCC_VERSION_1_0)
- return 0;
+ return;
switch (psci_ops.conduit) {
case PSCI_CONDUIT_HVC:
arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
ARM_SMCCC_ARCH_WORKAROUND_1, &res);
if ((int)res.a0 < 0)
- return 0;
+ return;
cb = call_hvc_arch_workaround_1;
smccc_start = __smccc_workaround_1_hvc_start;
smccc_end = __smccc_workaround_1_hvc_end;
@@ -189,19 +207,19 @@ static int enable_smccc_arch_workaround_1(void *data)
arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
ARM_SMCCC_ARCH_WORKAROUND_1, &res);
if ((int)res.a0 < 0)
- return 0;
+ return;
cb = call_smc_arch_workaround_1;
smccc_start = __smccc_workaround_1_smc_start;
smccc_end = __smccc_workaround_1_smc_end;
break;
default:
- return 0;
+ return;
}
install_bp_hardening_cb(entry, cb, smccc_start, smccc_end);
- return 0;
+ return;
}
static void qcom_link_stack_sanitization(void)
@@ -216,31 +234,119 @@ static void qcom_link_stack_sanitization(void)
: "=&r" (tmp));
}
-static int qcom_enable_link_stack_sanitization(void *data)
+static void
+qcom_enable_link_stack_sanitization(const struct arm64_cpu_capabilities *entry)
{
- const struct arm64_cpu_capabilities *entry = data;
-
install_bp_hardening_cb(entry, qcom_link_stack_sanitization,
__qcom_hyp_sanitize_link_stack_start,
__qcom_hyp_sanitize_link_stack_end);
-
- return 0;
}
#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */
-#define MIDR_RANGE(model, min, max) \
- .def_scope = SCOPE_LOCAL_CPU, \
- .matches = is_affected_midr_range, \
- .midr_model = model, \
- .midr_range_min = min, \
- .midr_range_max = max
+#define CAP_MIDR_RANGE(model, v_min, r_min, v_max, r_max) \
+ .matches = is_affected_midr_range, \
+ .midr_range = MIDR_RANGE(model, v_min, r_min, v_max, r_max)
+
+#define CAP_MIDR_ALL_VERSIONS(model) \
+ .matches = is_affected_midr_range, \
+ .midr_range = MIDR_ALL_VERSIONS(model)
+
+#define MIDR_FIXED(rev, revidr_mask) \
+ .fixed_revs = (struct arm64_midr_revidr[]){{ (rev), (revidr_mask) }, {}}
+
+#define ERRATA_MIDR_RANGE(model, v_min, r_min, v_max, r_max) \
+ .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, \
+ CAP_MIDR_RANGE(model, v_min, r_min, v_max, r_max)
+
+#define CAP_MIDR_RANGE_LIST(list) \
+ .matches = is_affected_midr_range_list, \
+ .midr_range_list = list
+
+/* Errata affecting a range of revisions of given model variant */
+#define ERRATA_MIDR_REV_RANGE(m, var, r_min, r_max) \
+ ERRATA_MIDR_RANGE(m, var, r_min, var, r_max)
+
+/* Errata affecting a single variant/revision of a model */
+#define ERRATA_MIDR_REV(model, var, rev) \
+ ERRATA_MIDR_RANGE(model, var, rev, var, rev)
+
+/* Errata affecting all variants/revisions of a given a model */
+#define ERRATA_MIDR_ALL_VERSIONS(model) \
+ .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, \
+ CAP_MIDR_ALL_VERSIONS(model)
+
+/* Errata affecting a list of midr ranges, with same work around */
+#define ERRATA_MIDR_RANGE_LIST(midr_list) \
+ .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, \
+ CAP_MIDR_RANGE_LIST(midr_list)
+
+/*
+ * Generic helper for handling capabilties with multiple (match,enable) pairs
+ * of call backs, sharing the same capability bit.
+ * Iterate over each entry to see if at least one matches.
+ */
+static bool __maybe_unused
+multi_entry_cap_matches(const struct arm64_cpu_capabilities *entry, int scope)
+{
+ const struct arm64_cpu_capabilities *caps;
+
+ for (caps = entry->match_list; caps->matches; caps++)
+ if (caps->matches(caps, scope))
+ return true;
+
+ return false;
+}
+
+/*
+ * Take appropriate action for all matching entries in the shared capability
+ * entry.
+ */
+static void __maybe_unused
+multi_entry_cap_cpu_enable(const struct arm64_cpu_capabilities *entry)
+{
+ const struct arm64_cpu_capabilities *caps;
-#define MIDR_ALL_VERSIONS(model) \
- .def_scope = SCOPE_LOCAL_CPU, \
- .matches = is_affected_midr_range, \
- .midr_model = model, \
- .midr_range_min = 0, \
- .midr_range_max = (MIDR_VARIANT_MASK | MIDR_REVISION_MASK)
+ for (caps = entry->match_list; caps->matches; caps++)
+ if (caps->matches(caps, SCOPE_LOCAL_CPU) &&
+ caps->cpu_enable)
+ caps->cpu_enable(caps);
+}
+
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+
+/*
+ * List of CPUs where we need to issue a psci call to
+ * harden the branch predictor.
+ */
+static const struct midr_range arm64_bp_harden_smccc_cpus[] = {
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
+ MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN),
+ MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2),
+ {},
+};
+
+static const struct midr_range qcom_bp_harden_cpus[] = {
+ MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR_V1),
+ MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR),
+ {},
+};
+
+static const struct arm64_cpu_capabilities arm64_bp_harden_list[] = {
+ {
+ CAP_MIDR_RANGE_LIST(arm64_bp_harden_smccc_cpus),
+ .cpu_enable = enable_smccc_arch_workaround_1,
+ },
+ {
+ CAP_MIDR_RANGE_LIST(qcom_bp_harden_cpus),
+ .cpu_enable = qcom_enable_link_stack_sanitization,
+ },
+ {},
+};
+
+#endif
const struct arm64_cpu_capabilities arm64_errata[] = {
#if defined(CONFIG_ARM64_ERRATUM_826319) || \
@@ -250,8 +356,8 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
/* Cortex-A53 r0p[012] */
.desc = "ARM errata 826319, 827319, 824069",
.capability = ARM64_WORKAROUND_CLEAN_CACHE,
- MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x02),
- .enable = cpu_enable_cache_maint_trap,
+ ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A53, 0, 0, 2),
+ .cpu_enable = cpu_enable_cache_maint_trap,
},
#endif
#ifdef CONFIG_ARM64_ERRATUM_819472
@@ -259,8 +365,8 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
/* Cortex-A53 r0p[01] */
.desc = "ARM errata 819472",
.capability = ARM64_WORKAROUND_CLEAN_CACHE,
- MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x01),
- .enable = cpu_enable_cache_maint_trap,
+ ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A53, 0, 0, 1),
+ .cpu_enable = cpu_enable_cache_maint_trap,
},
#endif
#ifdef CONFIG_ARM64_ERRATUM_832075
@@ -268,9 +374,9 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
/* Cortex-A57 r0p0 - r1p2 */
.desc = "ARM erratum 832075",
.capability = ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE,
- MIDR_RANGE(MIDR_CORTEX_A57,
- MIDR_CPU_VAR_REV(0, 0),
- MIDR_CPU_VAR_REV(1, 2)),
+ ERRATA_MIDR_RANGE(MIDR_CORTEX_A57,
+ 0, 0,
+ 1, 2),
},
#endif
#ifdef CONFIG_ARM64_ERRATUM_834220
@@ -278,9 +384,18 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
/* Cortex-A57 r0p0 - r1p2 */
.desc = "ARM erratum 834220",
.capability = ARM64_WORKAROUND_834220,
- MIDR_RANGE(MIDR_CORTEX_A57,
- MIDR_CPU_VAR_REV(0, 0),
- MIDR_CPU_VAR_REV(1, 2)),
+ ERRATA_MIDR_RANGE(MIDR_CORTEX_A57,
+ 0, 0,
+ 1, 2),
+ },
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_843419
+ {
+ /* Cortex-A53 r0p[01234] */
+ .desc = "ARM erratum 843419",
+ .capability = ARM64_WORKAROUND_843419,
+ ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A53, 0, 0, 4),
+ MIDR_FIXED(0x4, BIT(8)),
},
#endif
#ifdef CONFIG_ARM64_ERRATUM_845719
@@ -288,7 +403,7 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
/* Cortex-A53 r0p[01234] */
.desc = "ARM erratum 845719",
.capability = ARM64_WORKAROUND_845719,
- MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x04),
+ ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A53, 0, 0, 4),
},
#endif
#ifdef CONFIG_CAVIUM_ERRATUM_23154
@@ -296,7 +411,7 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
/* Cavium ThunderX, pass 1.x */
.desc = "Cavium erratum 23154",
.capability = ARM64_WORKAROUND_CAVIUM_23154,
- MIDR_RANGE(MIDR_THUNDERX, 0x00, 0x01),
+ ERRATA_MIDR_REV_RANGE(MIDR_THUNDERX, 0, 0, 1),
},
#endif
#ifdef CONFIG_CAVIUM_ERRATUM_27456
@@ -304,15 +419,15 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
/* Cavium ThunderX, T88 pass 1.x - 2.1 */
.desc = "Cavium erratum 27456",
.capability = ARM64_WORKAROUND_CAVIUM_27456,
- MIDR_RANGE(MIDR_THUNDERX,
- MIDR_CPU_VAR_REV(0, 0),
- MIDR_CPU_VAR_REV(1, 1)),
+ ERRATA_MIDR_RANGE(MIDR_THUNDERX,
+ 0, 0,
+ 1, 1),
},
{
/* Cavium ThunderX, T81 pass 1.0 */
.desc = "Cavium erratum 27456",
.capability = ARM64_WORKAROUND_CAVIUM_27456,
- MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00),
+ ERRATA_MIDR_REV(MIDR_THUNDERX_81XX, 0, 0),
},
#endif
#ifdef CONFIG_CAVIUM_ERRATUM_30115
@@ -320,42 +435,41 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
/* Cavium ThunderX, T88 pass 1.x - 2.2 */
.desc = "Cavium erratum 30115",
.capability = ARM64_WORKAROUND_CAVIUM_30115,
- MIDR_RANGE(MIDR_THUNDERX, 0x00,
- (1 << MIDR_VARIANT_SHIFT) | 2),
+ ERRATA_MIDR_RANGE(MIDR_THUNDERX,
+ 0, 0,
+ 1, 2),
},
{
/* Cavium ThunderX, T81 pass 1.0 - 1.2 */
.desc = "Cavium erratum 30115",
.capability = ARM64_WORKAROUND_CAVIUM_30115,
- MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x02),
+ ERRATA_MIDR_REV_RANGE(MIDR_THUNDERX_81XX, 0, 0, 2),
},
{
/* Cavium ThunderX, T83 pass 1.0 */
.desc = "Cavium erratum 30115",
.capability = ARM64_WORKAROUND_CAVIUM_30115,
- MIDR_RANGE(MIDR_THUNDERX_83XX, 0x00, 0x00),
+ ERRATA_MIDR_REV(MIDR_THUNDERX_83XX, 0, 0),
},
#endif
{
.desc = "Mismatched cache line size",
.capability = ARM64_MISMATCHED_CACHE_LINE_SIZE,
.matches = has_mismatched_cache_line_size,
- .def_scope = SCOPE_LOCAL_CPU,
- .enable = cpu_enable_trap_ctr_access,
+ .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
+ .cpu_enable = cpu_enable_trap_ctr_access,
},
#ifdef CONFIG_QCOM_FALKOR_ERRATUM_1003
{
.desc = "Qualcomm Technologies Falkor erratum 1003",
.capability = ARM64_WORKAROUND_QCOM_FALKOR_E1003,
- MIDR_RANGE(MIDR_QCOM_FALKOR_V1,
- MIDR_CPU_VAR_REV(0, 0),
- MIDR_CPU_VAR_REV(0, 0)),
+ ERRATA_MIDR_REV(MIDR_QCOM_FALKOR_V1, 0, 0),
},
{
.desc = "Qualcomm Technologies Kryo erratum 1003",
.capability = ARM64_WORKAROUND_QCOM_FALKOR_E1003,
- .def_scope = SCOPE_LOCAL_CPU,
- .midr_model = MIDR_QCOM_KRYO,
+ .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
+ .midr_range.model = MIDR_QCOM_KRYO,
.matches = is_kryo_midr,
},
#endif
@@ -363,9 +477,7 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
{
.desc = "Qualcomm Technologies Falkor erratum 1009",
.capability = ARM64_WORKAROUND_REPEAT_TLBI,
- MIDR_RANGE(MIDR_QCOM_FALKOR_V1,
- MIDR_CPU_VAR_REV(0, 0),
- MIDR_CPU_VAR_REV(0, 0)),
+ ERRATA_MIDR_REV(MIDR_QCOM_FALKOR_V1, 0, 0),
},
#endif
#ifdef CONFIG_ARM64_ERRATUM_858921
@@ -373,92 +485,22 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
/* Cortex-A73 all versions */
.desc = "ARM erratum 858921",
.capability = ARM64_WORKAROUND_858921,
- MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
+ ERRATA_MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
},
#endif
#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
{
.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
- MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
- .enable = enable_smccc_arch_workaround_1,
- },
- {
- .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
- MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
- .enable = enable_smccc_arch_workaround_1,
- },
- {
- .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
- MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
- .enable = enable_smccc_arch_workaround_1,
- },
- {
- .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
- MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
- .enable = enable_smccc_arch_workaround_1,
- },
- {
- .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
- MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR_V1),
- .enable = qcom_enable_link_stack_sanitization,
+ .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
+ .matches = multi_entry_cap_matches,
+ .cpu_enable = multi_entry_cap_cpu_enable,
+ .match_list = arm64_bp_harden_list,
},
{
.capability = ARM64_HARDEN_BP_POST_GUEST_EXIT,
- MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR_V1),
- },
- {
- .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
- MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR),
- .enable = qcom_enable_link_stack_sanitization,
- },
- {
- .capability = ARM64_HARDEN_BP_POST_GUEST_EXIT,
- MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR),
- },
- {
- .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
- MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN),
- .enable = enable_smccc_arch_workaround_1,
- },
- {
- .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
- MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2),
- .enable = enable_smccc_arch_workaround_1,
+ ERRATA_MIDR_RANGE_LIST(qcom_bp_harden_cpus),
},
#endif
{
}
};
-
-/*
- * The CPU Errata work arounds are detected and applied at boot time
- * and the related information is freed soon after. If the new CPU requires
- * an errata not detected at boot, fail this CPU.
- */
-void verify_local_cpu_errata_workarounds(void)
-{
- const struct arm64_cpu_capabilities *caps = arm64_errata;
-
- for (; caps->matches; caps++) {
- if (cpus_have_cap(caps->capability)) {
- if (caps->enable)
- caps->enable((void *)caps);
- } else if (caps->matches(caps, SCOPE_LOCAL_CPU)) {
- pr_crit("CPU%d: Requires work around for %s, not detected"
- " at boot time\n",
- smp_processor_id(),
- caps->desc ? : "an erratum");
- cpu_die_early();
- }
- }
-}
-
-void update_cpu_errata_workarounds(void)
-{
- update_cpu_capabilities(arm64_errata, "enabling workaround for");
-}
-
-void __init enable_errata_workarounds(void)
-{
- enable_cpu_capabilities(arm64_errata);
-}
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 2985a067fc13..96b15d7b10a8 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -123,6 +123,7 @@ cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused)
* sync with the documentation of the CPU feature register ABI.
*/
static const struct arm64_ftr_bits ftr_id_aa64isar0[] = {
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_TS_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_FHM_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_DP_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR0_SM4_SHIFT, 4, 0),
@@ -148,6 +149,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV3_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV2_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_DIT_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SVE),
FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_SVE_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_RAS_SHIFT, 4, 0),
@@ -190,6 +192,7 @@ static const struct arm64_ftr_bits ftr_id_aa64mmfr1[] = {
};
static const struct arm64_ftr_bits ftr_id_aa64mmfr2[] = {
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR2_AT_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR2_LVA_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR2_IESB_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR2_LSM_SHIFT, 4, 0),
@@ -199,12 +202,12 @@ static const struct arm64_ftr_bits ftr_id_aa64mmfr2[] = {
};
static const struct arm64_ftr_bits ftr_ctr[] = {
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RES1 */
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 29, 1, 1), /* DIC */
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 28, 1, 1), /* IDC */
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0), /* CWG */
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, 20, 4, 0), /* ERG */
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1), /* DminLine */
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RES1 */
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_DIC_SHIFT, 1, 1),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_IDC_SHIFT, 1, 1),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, CTR_CWG_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, CTR_ERG_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_DMINLINE_SHIFT, 4, 1),
/*
* Linux can handle differing I-cache policies. Userspace JITs will
* make use of *minLine.
@@ -506,6 +509,9 @@ static void __init init_cpu_ftr_reg(u32 sys_reg, u64 new)
reg->user_mask = user_mask;
}
+extern const struct arm64_cpu_capabilities arm64_errata[];
+static void __init setup_boot_cpu_capabilities(void);
+
void __init init_cpu_features(struct cpuinfo_arm64 *info)
{
/* Before we start using the tables, make sure it is sorted */
@@ -548,6 +554,12 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
init_cpu_ftr_reg(SYS_ZCR_EL1, info->reg_zcr);
sve_init_vq_map();
}
+
+ /*
+ * Detect and enable early CPU capabilities based on the boot CPU,
+ * after we have initialised the CPU feature infrastructure.
+ */
+ setup_boot_cpu_capabilities();
}
static void update_cpu_ftr_reg(struct arm64_ftr_reg *reg, u64 new)
@@ -826,11 +838,6 @@ static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry, int _
MIDR_CPU_VAR_REV(1, MIDR_REVISION_MASK));
}
-static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused)
-{
- return is_kernel_in_hyp_mode();
-}
-
static bool hyp_offset_low(const struct arm64_cpu_capabilities *entry,
int __unused)
{
@@ -852,14 +859,30 @@ static bool has_no_fpsimd(const struct arm64_cpu_capabilities *entry, int __unus
ID_AA64PFR0_FP_SHIFT) < 0;
}
+static bool has_cache_idc(const struct arm64_cpu_capabilities *entry,
+ int __unused)
+{
+ return read_sanitised_ftr_reg(SYS_CTR_EL0) & BIT(CTR_IDC_SHIFT);
+}
+
+static bool has_cache_dic(const struct arm64_cpu_capabilities *entry,
+ int __unused)
+{
+ return read_sanitised_ftr_reg(SYS_CTR_EL0) & BIT(CTR_DIC_SHIFT);
+}
+
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */
static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
- int __unused)
+ int scope)
{
+ /* List of CPUs that are not vulnerable and don't need KPTI */
+ static const struct midr_range kpti_safe_list[] = {
+ MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2),
+ MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN),
+ };
char const *str = "command line option";
- u64 pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
/*
* For reasons that aren't entirely clear, enabling KPTI on Cavium
@@ -883,18 +906,15 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
return true;
/* Don't force KPTI for CPUs that are not vulnerable */
- switch (read_cpuid_id() & MIDR_CPU_MODEL_MASK) {
- case MIDR_CAVIUM_THUNDERX2:
- case MIDR_BRCM_VULCAN:
+ if (is_midr_in_range_list(read_cpuid_id(), kpti_safe_list))
return false;
- }
/* Defer to CPU feature registers */
- return !cpuid_feature_extract_unsigned_field(pfr0,
- ID_AA64PFR0_CSV3_SHIFT);
+ return !has_cpuid_feature(entry, scope);
}
-static int kpti_install_ng_mappings(void *__unused)
+static void
+kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
{
typedef void (kpti_remap_fn)(int, int, phys_addr_t);
extern kpti_remap_fn idmap_kpti_install_ng_mappings;
@@ -904,7 +924,7 @@ static int kpti_install_ng_mappings(void *__unused)
int cpu = smp_processor_id();
if (kpti_applied)
- return 0;
+ return;
remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings);
@@ -915,7 +935,7 @@ static int kpti_install_ng_mappings(void *__unused)
if (!cpu)
kpti_applied = true;
- return 0;
+ return;
}
static int __init parse_kpti(char *str)
@@ -932,7 +952,78 @@ static int __init parse_kpti(char *str)
__setup("kpti=", parse_kpti);
#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
-static int cpu_copy_el2regs(void *__unused)
+#ifdef CONFIG_ARM64_HW_AFDBM
+static inline void __cpu_enable_hw_dbm(void)
+{
+ u64 tcr = read_sysreg(tcr_el1) | TCR_HD;
+
+ write_sysreg(tcr, tcr_el1);
+ isb();
+}
+
+static bool cpu_has_broken_dbm(void)
+{
+ /* List of CPUs which have broken DBM support. */
+ static const struct midr_range cpus[] = {
+#ifdef CONFIG_ARM64_ERRATUM_1024718
+ MIDR_RANGE(MIDR_CORTEX_A55, 0, 0, 1, 0), // A55 r0p0 -r1p0
+#endif
+ {},
+ };
+
+ return is_midr_in_range_list(read_cpuid_id(), cpus);
+}
+
+static bool cpu_can_use_dbm(const struct arm64_cpu_capabilities *cap)
+{
+ return has_cpuid_feature(cap, SCOPE_LOCAL_CPU) &&
+ !cpu_has_broken_dbm();
+}
+
+static void cpu_enable_hw_dbm(struct arm64_cpu_capabilities const *cap)
+{
+ if (cpu_can_use_dbm(cap))
+ __cpu_enable_hw_dbm();
+}
+
+static bool has_hw_dbm(const struct arm64_cpu_capabilities *cap,
+ int __unused)
+{
+ static bool detected = false;
+ /*
+ * DBM is a non-conflicting feature. i.e, the kernel can safely
+ * run a mix of CPUs with and without the feature. So, we
+ * unconditionally enable the capability to allow any late CPU
+ * to use the feature. We only enable the control bits on the
+ * CPU, if it actually supports.
+ *
+ * We have to make sure we print the "feature" detection only
+ * when at least one CPU actually uses it. So check if this CPU
+ * can actually use it and print the message exactly once.
+ *
+ * This is safe as all CPUs (including secondary CPUs - due to the
+ * LOCAL_CPU scope - and the hotplugged CPUs - via verification)
+ * goes through the "matches" check exactly once. Also if a CPU
+ * matches the criteria, it is guaranteed that the CPU will turn
+ * the DBM on, as the capability is unconditionally enabled.
+ */
+ if (!detected && cpu_can_use_dbm(cap)) {
+ detected = true;
+ pr_info("detected: Hardware dirty bit management\n");
+ }
+
+ return true;
+}
+
+#endif
+
+#ifdef CONFIG_ARM64_VHE
+static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused)
+{
+ return is_kernel_in_hyp_mode();
+}
+
+static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused)
{
/*
* Copy register values that aren't redirected by hardware.
@@ -944,15 +1035,14 @@ static int cpu_copy_el2regs(void *__unused)
*/
if (!alternatives_applied)
write_sysreg(read_sysreg(tpidr_el1), tpidr_el2);
-
- return 0;
}
+#endif
static const struct arm64_cpu_capabilities arm64_features[] = {
{
.desc = "GIC system register CPU interface",
.capability = ARM64_HAS_SYSREG_GIC_CPUIF,
- .def_scope = SCOPE_SYSTEM,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
.matches = has_useable_gicv3_cpuif,
.sys_reg = SYS_ID_AA64PFR0_EL1,
.field_pos = ID_AA64PFR0_GIC_SHIFT,
@@ -963,20 +1053,20 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
{
.desc = "Privileged Access Never",
.capability = ARM64_HAS_PAN,
- .def_scope = SCOPE_SYSTEM,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
.matches = has_cpuid_feature,
.sys_reg = SYS_ID_AA64MMFR1_EL1,
.field_pos = ID_AA64MMFR1_PAN_SHIFT,
.sign = FTR_UNSIGNED,
.min_field_value = 1,
- .enable = cpu_enable_pan,
+ .cpu_enable = cpu_enable_pan,
},
#endif /* CONFIG_ARM64_PAN */
#if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS)
{
.desc = "LSE atomic instructions",
.capability = ARM64_HAS_LSE_ATOMICS,
- .def_scope = SCOPE_SYSTEM,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
.matches = has_cpuid_feature,
.sys_reg = SYS_ID_AA64ISAR0_EL1,
.field_pos = ID_AA64ISAR0_ATOMICS_SHIFT,
@@ -987,14 +1077,14 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
{
.desc = "Software prefetching using PRFM",
.capability = ARM64_HAS_NO_HW_PREFETCH,
- .def_scope = SCOPE_SYSTEM,
+ .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE,
.matches = has_no_hw_prefetch,
},
#ifdef CONFIG_ARM64_UAO
{
.desc = "User Access Override",
.capability = ARM64_HAS_UAO,
- .def_scope = SCOPE_SYSTEM,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
.matches = has_cpuid_feature,
.sys_reg = SYS_ID_AA64MMFR2_EL1,
.field_pos = ID_AA64MMFR2_UAO_SHIFT,
@@ -1008,21 +1098,23 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
#ifdef CONFIG_ARM64_PAN
{
.capability = ARM64_ALT_PAN_NOT_UAO,
- .def_scope = SCOPE_SYSTEM,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
.matches = cpufeature_pan_not_uao,
},
#endif /* CONFIG_ARM64_PAN */
+#ifdef CONFIG_ARM64_VHE
{
.desc = "Virtualization Host Extensions",
.capability = ARM64_HAS_VIRT_HOST_EXTN,
- .def_scope = SCOPE_SYSTEM,
+ .type = ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE,
.matches = runs_at_el2,
- .enable = cpu_copy_el2regs,
+ .cpu_enable = cpu_copy_el2regs,
},
+#endif /* CONFIG_ARM64_VHE */
{
.desc = "32-bit EL0 Support",
.capability = ARM64_HAS_32BIT_EL0,
- .def_scope = SCOPE_SYSTEM,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
.matches = has_cpuid_feature,
.sys_reg = SYS_ID_AA64PFR0_EL1,
.sign = FTR_UNSIGNED,
@@ -1032,22 +1124,30 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
{
.desc = "Reduced HYP mapping offset",
.capability = ARM64_HYP_OFFSET_LOW,
- .def_scope = SCOPE_SYSTEM,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
.matches = hyp_offset_low,
},
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
{
.desc = "Kernel page table isolation (KPTI)",
.capability = ARM64_UNMAP_KERNEL_AT_EL0,
- .def_scope = SCOPE_SYSTEM,
+ .type = ARM64_CPUCAP_BOOT_RESTRICTED_CPU_LOCAL_FEATURE,
+ /*
+ * The ID feature fields below are used to indicate that
+ * the CPU doesn't need KPTI. See unmap_kernel_at_el0 for
+ * more details.
+ */
+ .sys_reg = SYS_ID_AA64PFR0_EL1,
+ .field_pos = ID_AA64PFR0_CSV3_SHIFT,
+ .min_field_value = 1,
.matches = unmap_kernel_at_el0,
- .enable = kpti_install_ng_mappings,
+ .cpu_enable = kpti_install_ng_mappings,
},
#endif
{
/* FP/SIMD is not implemented */
.capability = ARM64_HAS_NO_FPSIMD,
- .def_scope = SCOPE_SYSTEM,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
.min_field_value = 0,
.matches = has_no_fpsimd,
},
@@ -1055,7 +1155,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
{
.desc = "Data cache clean to Point of Persistence",
.capability = ARM64_HAS_DCPOP,
- .def_scope = SCOPE_SYSTEM,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
.matches = has_cpuid_feature,
.sys_reg = SYS_ID_AA64ISAR1_EL1,
.field_pos = ID_AA64ISAR1_DPB_SHIFT,
@@ -1065,42 +1165,74 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
#ifdef CONFIG_ARM64_SVE
{
.desc = "Scalable Vector Extension",
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
.capability = ARM64_SVE,
- .def_scope = SCOPE_SYSTEM,
.sys_reg = SYS_ID_AA64PFR0_EL1,
.sign = FTR_UNSIGNED,
.field_pos = ID_AA64PFR0_SVE_SHIFT,
.min_field_value = ID_AA64PFR0_SVE,
.matches = has_cpuid_feature,
- .enable = sve_kernel_enable,
+ .cpu_enable = sve_kernel_enable,
},
#endif /* CONFIG_ARM64_SVE */
#ifdef CONFIG_ARM64_RAS_EXTN
{
.desc = "RAS Extension Support",
.capability = ARM64_HAS_RAS_EXTN,
- .def_scope = SCOPE_SYSTEM,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
.matches = has_cpuid_feature,
.sys_reg = SYS_ID_AA64PFR0_EL1,
.sign = FTR_UNSIGNED,
.field_pos = ID_AA64PFR0_RAS_SHIFT,
.min_field_value = ID_AA64PFR0_RAS_V1,
- .enable = cpu_clear_disr,
+ .cpu_enable = cpu_clear_disr,
},
#endif /* CONFIG_ARM64_RAS_EXTN */
+ {
+ .desc = "Data cache clean to the PoU not required for I/D coherence",
+ .capability = ARM64_HAS_CACHE_IDC,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+ .matches = has_cache_idc,
+ },
+ {
+ .desc = "Instruction cache invalidation not required for I/D coherence",
+ .capability = ARM64_HAS_CACHE_DIC,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+ .matches = has_cache_dic,
+ },
+#ifdef CONFIG_ARM64_HW_AFDBM
+ {
+ /*
+ * Since we turn this on always, we don't want the user to
+ * think that the feature is available when it may not be.
+ * So hide the description.
+ *
+ * .desc = "Hardware pagetable Dirty Bit Management",
+ *
+ */
+ .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE,
+ .capability = ARM64_HW_DBM,
+ .sys_reg = SYS_ID_AA64MMFR1_EL1,
+ .sign = FTR_UNSIGNED,
+ .field_pos = ID_AA64MMFR1_HADBS_SHIFT,
+ .min_field_value = 2,
+ .matches = has_hw_dbm,
+ .cpu_enable = cpu_enable_hw_dbm,
+ },
+#endif
{},
};
-#define HWCAP_CAP(reg, field, s, min_value, type, cap) \
+#define HWCAP_CAP(reg, field, s, min_value, cap_type, cap) \
{ \
.desc = #cap, \
- .def_scope = SCOPE_SYSTEM, \
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE, \
.matches = has_cpuid_feature, \
.sys_reg = reg, \
.field_pos = field, \
.sign = s, \
.min_field_value = min_value, \
- .hwcap_type = type, \
+ .hwcap_type = cap_type, \
.hwcap = cap, \
}
@@ -1118,14 +1250,18 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SM4_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SM4),
HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_DP_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_ASIMDDP),
HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_FHM_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_ASIMDFHM),
+ HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_TS_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_FLAGM),
HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_FP),
HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_FPHP),
HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_ASIMD),
HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_ASIMDHP),
+ HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_DIT_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_DIT),
HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_DPB_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_DCPOP),
HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_JSCVT_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_JSCVT),
HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_FCMA_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_FCMA),
HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_LRCPC),
+ HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_ILRCPC),
+ HWCAP_CAP(SYS_ID_AA64MMFR2_EL1, ID_AA64MMFR2_AT_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_USCAT),
#ifdef CONFIG_ARM64_SVE
HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_SVE_SHIFT, FTR_UNSIGNED, ID_AA64PFR0_SVE, CAP_HWCAP, HWCAP_SVE),
#endif
@@ -1193,7 +1329,7 @@ static void __init setup_elf_hwcaps(const struct arm64_cpu_capabilities *hwcaps)
/* We support emulation of accesses to CPU ID feature registers */
elf_hwcap |= HWCAP_CPUID;
for (; hwcaps->matches; hwcaps++)
- if (hwcaps->matches(hwcaps, hwcaps->def_scope))
+ if (hwcaps->matches(hwcaps, cpucap_default_scope(hwcaps)))
cap_set_elf_hwcap(hwcaps);
}
@@ -1210,17 +1346,19 @@ static bool __this_cpu_has_cap(const struct arm64_cpu_capabilities *cap_array,
return false;
for (caps = cap_array; caps->matches; caps++)
- if (caps->capability == cap &&
- caps->matches(caps, SCOPE_LOCAL_CPU))
- return true;
+ if (caps->capability == cap)
+ return caps->matches(caps, SCOPE_LOCAL_CPU);
+
return false;
}
-void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
- const char *info)
+static void __update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
+ u16 scope_mask, const char *info)
{
+ scope_mask &= ARM64_CPUCAP_SCOPE_MASK;
for (; caps->matches; caps++) {
- if (!caps->matches(caps, caps->def_scope))
+ if (!(caps->type & scope_mask) ||
+ !caps->matches(caps, cpucap_default_scope(caps)))
continue;
if (!cpus_have_cap(caps->capability) && caps->desc)
@@ -1229,41 +1367,145 @@ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
}
}
+static void update_cpu_capabilities(u16 scope_mask)
+{
+ __update_cpu_capabilities(arm64_features, scope_mask, "detected:");
+ __update_cpu_capabilities(arm64_errata, scope_mask,
+ "enabling workaround for");
+}
+
+static int __enable_cpu_capability(void *arg)
+{
+ const struct arm64_cpu_capabilities *cap = arg;
+
+ cap->cpu_enable(cap);
+ return 0;
+}
+
/*
* Run through the enabled capabilities and enable() it on all active
* CPUs
*/
-void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps)
+static void __init
+__enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
+ u16 scope_mask)
{
+ scope_mask &= ARM64_CPUCAP_SCOPE_MASK;
for (; caps->matches; caps++) {
unsigned int num = caps->capability;
- if (!cpus_have_cap(num))
+ if (!(caps->type & scope_mask) || !cpus_have_cap(num))
continue;
/* Ensure cpus_have_const_cap(num) works */
static_branch_enable(&cpu_hwcap_keys[num]);
- if (caps->enable) {
+ if (caps->cpu_enable) {
/*
- * Use stop_machine() as it schedules the work allowing
- * us to modify PSTATE, instead of on_each_cpu() which
- * uses an IPI, giving us a PSTATE that disappears when
- * we return.
+ * Capabilities with SCOPE_BOOT_CPU scope are finalised
+ * before any secondary CPU boots. Thus, each secondary
+ * will enable the capability as appropriate via
+ * check_local_cpu_capabilities(). The only exception is
+ * the boot CPU, for which the capability must be
+ * enabled here. This approach avoids costly
+ * stop_machine() calls for this case.
+ *
+ * Otherwise, use stop_machine() as it schedules the
+ * work allowing us to modify PSTATE, instead of
+ * on_each_cpu() which uses an IPI, giving us a PSTATE
+ * that disappears when we return.
*/
- stop_machine(caps->enable, (void *)caps, cpu_online_mask);
+ if (scope_mask & SCOPE_BOOT_CPU)
+ caps->cpu_enable(caps);
+ else
+ stop_machine(__enable_cpu_capability,
+ (void *)caps, cpu_online_mask);
}
}
}
+static void __init enable_cpu_capabilities(u16 scope_mask)
+{
+ __enable_cpu_capabilities(arm64_features, scope_mask);
+ __enable_cpu_capabilities(arm64_errata, scope_mask);
+}
+
+/*
+ * Run through the list of capabilities to check for conflicts.
+ * If the system has already detected a capability, take necessary
+ * action on this CPU.
+ *
+ * Returns "false" on conflicts.
+ */
+static bool
+__verify_local_cpu_caps(const struct arm64_cpu_capabilities *caps,
+ u16 scope_mask)
+{
+ bool cpu_has_cap, system_has_cap;
+
+ scope_mask &= ARM64_CPUCAP_SCOPE_MASK;
+
+ for (; caps->matches; caps++) {
+ if (!(caps->type & scope_mask))
+ continue;
+
+ cpu_has_cap = caps->matches(caps, SCOPE_LOCAL_CPU);
+ system_has_cap = cpus_have_cap(caps->capability);
+
+ if (system_has_cap) {
+ /*
+ * Check if the new CPU misses an advertised feature,
+ * which is not safe to miss.
+ */
+ if (!cpu_has_cap && !cpucap_late_cpu_optional(caps))
+ break;
+ /*
+ * We have to issue cpu_enable() irrespective of
+ * whether the CPU has it or not, as it is enabeld
+ * system wide. It is upto the call back to take
+ * appropriate action on this CPU.
+ */
+ if (caps->cpu_enable)
+ caps->cpu_enable(caps);
+ } else {
+ /*
+ * Check if the CPU has this capability if it isn't
+ * safe to have when the system doesn't.
+ */
+ if (cpu_has_cap && !cpucap_late_cpu_permitted(caps))
+ break;
+ }
+ }
+
+ if (caps->matches) {
+ pr_crit("CPU%d: Detected conflict for capability %d (%s), System: %d, CPU: %d\n",
+ smp_processor_id(), caps->capability,
+ caps->desc, system_has_cap, cpu_has_cap);
+ return false;
+ }
+
+ return true;
+}
+
+static bool verify_local_cpu_caps(u16 scope_mask)
+{
+ return __verify_local_cpu_caps(arm64_errata, scope_mask) &&
+ __verify_local_cpu_caps(arm64_features, scope_mask);
+}
+
/*
* Check for CPU features that are used in early boot
* based on the Boot CPU value.
*/
static void check_early_cpu_features(void)
{
- verify_cpu_run_el();
verify_cpu_asid_bits();
+ /*
+ * Early features are used by the kernel already. If there
+ * is a conflict, we cannot proceed further.
+ */
+ if (!verify_local_cpu_caps(SCOPE_BOOT_CPU))
+ cpu_panic_kernel();
}
static void
@@ -1278,27 +1520,6 @@ verify_local_elf_hwcaps(const struct arm64_cpu_capabilities *caps)
}
}
-static void
-verify_local_cpu_features(const struct arm64_cpu_capabilities *caps_list)
-{
- const struct arm64_cpu_capabilities *caps = caps_list;
- for (; caps->matches; caps++) {
- if (!cpus_have_cap(caps->capability))
- continue;
- /*
- * If the new CPU misses an advertised feature, we cannot proceed
- * further, park the cpu.
- */
- if (!__this_cpu_has_cap(caps_list, caps->capability)) {
- pr_crit("CPU%d: missing feature: %s\n",
- smp_processor_id(), caps->desc);
- cpu_die_early();
- }
- if (caps->enable)
- caps->enable((void *)caps);
- }
-}
-
static void verify_sve_features(void)
{
u64 safe_zcr = read_sanitised_ftr_reg(SYS_ZCR_EL1);
@@ -1316,6 +1537,7 @@ static void verify_sve_features(void)
/* Add checks on other ZCR bits here if necessary */
}
+
/*
* Run through the enabled system capabilities and enable() it on this CPU.
* The capabilities were decided based on the available CPUs at the boot time.
@@ -1326,8 +1548,14 @@ static void verify_sve_features(void)
*/
static void verify_local_cpu_capabilities(void)
{
- verify_local_cpu_errata_workarounds();
- verify_local_cpu_features(arm64_features);
+ /*
+ * The capabilities with SCOPE_BOOT_CPU are checked from
+ * check_early_cpu_features(), as they need to be verified
+ * on all secondary CPUs.
+ */
+ if (!verify_local_cpu_caps(SCOPE_ALL & ~SCOPE_BOOT_CPU))
+ cpu_die_early();
+
verify_local_elf_hwcaps(arm64_elf_hwcaps);
if (system_supports_32bit_el0())
@@ -1335,9 +1563,6 @@ static void verify_local_cpu_capabilities(void)
if (system_supports_sve())
verify_sve_features();
-
- if (system_uses_ttbr0_pan())
- pr_info("Emulating Privileged Access Never (PAN) using TTBR0_EL1 switching\n");
}
void check_local_cpu_capabilities(void)
@@ -1350,20 +1575,22 @@ void check_local_cpu_capabilities(void)
/*
* If we haven't finalised the system capabilities, this CPU gets
- * a chance to update the errata work arounds.
+ * a chance to update the errata work arounds and local features.
* Otherwise, this CPU should verify that it has all the system
* advertised capabilities.
*/
if (!sys_caps_initialised)
- update_cpu_errata_workarounds();
+ update_cpu_capabilities(SCOPE_LOCAL_CPU);
else
verify_local_cpu_capabilities();
}
-static void __init setup_feature_capabilities(void)
+static void __init setup_boot_cpu_capabilities(void)
{
- update_cpu_capabilities(arm64_features, "detected feature:");
- enable_cpu_capabilities(arm64_features);
+ /* Detect capabilities with either SCOPE_BOOT_CPU or SCOPE_LOCAL_CPU */
+ update_cpu_capabilities(SCOPE_BOOT_CPU | SCOPE_LOCAL_CPU);
+ /* Enable the SCOPE_BOOT_CPU capabilities alone right away */
+ enable_cpu_capabilities(SCOPE_BOOT_CPU);
}
DEFINE_STATIC_KEY_FALSE(arm64_const_caps_ready);
@@ -1382,20 +1609,33 @@ bool this_cpu_has_cap(unsigned int cap)
__this_cpu_has_cap(arm64_errata, cap));
}
+static void __init setup_system_capabilities(void)
+{
+ /*
+ * We have finalised the system-wide safe feature
+ * registers, finalise the capabilities that depend
+ * on it. Also enable all the available capabilities,
+ * that are not enabled already.
+ */
+ update_cpu_capabilities(SCOPE_SYSTEM);
+ enable_cpu_capabilities(SCOPE_ALL & ~SCOPE_BOOT_CPU);
+}
+
void __init setup_cpu_features(void)
{
u32 cwg;
int cls;
- /* Set the CPU feature capabilies */
- setup_feature_capabilities();
- enable_errata_workarounds();
+ setup_system_capabilities();
mark_const_caps_ready();
setup_elf_hwcaps(arm64_elf_hwcaps);
if (system_supports_32bit_el0())
setup_elf_hwcaps(compat_elf_hwcaps);
+ if (system_uses_ttbr0_pan())
+ pr_info("emulated: Privileged Access Never (PAN) using TTBR0_EL1 switching\n");
+
sve_setup();
/* Advertise that we have computed the system capabilities */
@@ -1518,10 +1758,8 @@ static int __init enable_mrs_emulation(void)
core_initcall(enable_mrs_emulation);
-int cpu_clear_disr(void *__unused)
+void cpu_clear_disr(const struct arm64_cpu_capabilities *__unused)
{
/* Firmware may have left a deferred SError in this register. */
write_sysreg_s(0, SYS_DISR_EL1);
-
- return 0;
}
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 7f94623df8a5..e9ab7b3ed317 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -77,6 +77,10 @@ static const char *const hwcap_str[] = {
"sha512",
"sve",
"asimdfhm",
+ "dit",
+ "uscat",
+ "ilrcpc",
+ "flagm",
NULL
};
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index 53781f5687c5..06ca574495af 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -33,6 +33,7 @@
#include <asm/daifflags.h>
#include <asm/debug-monitors.h>
#include <asm/system_misc.h>
+#include <asm/traps.h>
/* Determine debug architecture. */
u8 debug_monitors_arch(void)
@@ -223,7 +224,7 @@ static void send_user_sigtrap(int si_code)
if (interrupts_enabled(regs))
local_irq_enable();
- force_sig_info(SIGTRAP, &info, current);
+ arm64_force_sig_info(&info, "User debug trap", current);
}
static int single_step_handler(unsigned long addr, unsigned int esr,
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index e7226c4c7493..87a35364e750 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -39,7 +39,9 @@
#include <linux/slab.h>
#include <linux/sysctl.h>
+#include <asm/esr.h>
#include <asm/fpsimd.h>
+#include <asm/cpufeature.h>
#include <asm/cputype.h>
#include <asm/simd.h>
#include <asm/sigcontext.h>
@@ -64,7 +66,7 @@
* been loaded into its FPSIMD registers most recently, or whether it has
* been used to perform kernel mode NEON in the meantime.
*
- * For (a), we add a 'cpu' field to struct fpsimd_state, which gets updated to
+ * For (a), we add a fpsimd_cpu field to thread_struct, which gets updated to
* the id of the current CPU every time the state is loaded onto a CPU. For (b),
* we add the per-cpu variable 'fpsimd_last_state' (below), which contains the
* address of the userland FPSIMD state of the task that was loaded onto the CPU
@@ -73,7 +75,7 @@
* With this in place, we no longer have to restore the next FPSIMD state right
* when switching between tasks. Instead, we can defer this check to userland
* resume, at which time we verify whether the CPU's fpsimd_last_state and the
- * task's fpsimd_state.cpu are still mutually in sync. If this is the case, we
+ * task's fpsimd_cpu are still mutually in sync. If this is the case, we
* can omit the FPSIMD restore.
*
* As an optimization, we use the thread_info flag TIF_FOREIGN_FPSTATE to
@@ -90,14 +92,14 @@
* flag with local_bh_disable() unless softirqs are already masked.
*
* For a certain task, the sequence may look something like this:
- * - the task gets scheduled in; if both the task's fpsimd_state.cpu field
+ * - the task gets scheduled in; if both the task's fpsimd_cpu field
* contains the id of the current CPU, and the CPU's fpsimd_last_state per-cpu
* variable points to the task's fpsimd_state, the TIF_FOREIGN_FPSTATE flag is
* cleared, otherwise it is set;
*
* - the task returns to userland; if TIF_FOREIGN_FPSTATE is set, the task's
* userland FPSIMD state is copied from memory to the registers, the task's
- * fpsimd_state.cpu field is set to the id of the current CPU, the current
+ * fpsimd_cpu field is set to the id of the current CPU, the current
* CPU's fpsimd_last_state pointer is set to this task's fpsimd_state and the
* TIF_FOREIGN_FPSTATE flag is cleared;
*
@@ -115,7 +117,7 @@
* whatever is in the FPSIMD registers is not saved to memory, but discarded.
*/
struct fpsimd_last_state_struct {
- struct fpsimd_state *st;
+ struct user_fpsimd_state *st;
bool sve_in_use;
};
@@ -222,7 +224,7 @@ static void sve_user_enable(void)
* sets TIF_SVE.
*
* When stored, FPSIMD registers V0-V31 are encoded in
- * task->fpsimd_state; bits [max : 128] for each of Z0-Z31 are
+ * task->thread.uw.fpsimd_state; bits [max : 128] for each of Z0-Z31 are
* logically zero but not stored anywhere; P0-P15 and FFR are not
* stored and have unspecified values from userspace's point of
* view. For hygiene purposes, the kernel zeroes them on next use,
@@ -231,9 +233,9 @@ static void sve_user_enable(void)
* task->thread.sve_state does not need to be non-NULL, valid or any
* particular size: it must not be dereferenced.
*
- * * FPSR and FPCR are always stored in task->fpsimd_state irrespctive of
- * whether TIF_SVE is clear or set, since these are not vector length
- * dependent.
+ * * FPSR and FPCR are always stored in task->thread.uw.fpsimd_state
+ * irrespective of whether TIF_SVE is clear or set, since these are
+ * not vector length dependent.
*/
/*
@@ -251,10 +253,10 @@ static void task_fpsimd_load(void)
if (system_supports_sve() && test_thread_flag(TIF_SVE))
sve_load_state(sve_pffr(current),
- &current->thread.fpsimd_state.fpsr,
+ &current->thread.uw.fpsimd_state.fpsr,
sve_vq_from_vl(current->thread.sve_vl) - 1);
else
- fpsimd_load_state(&current->thread.fpsimd_state);
+ fpsimd_load_state(&current->thread.uw.fpsimd_state);
if (system_supports_sve()) {
/* Toggle SVE trapping for userspace if needed */
@@ -285,15 +287,14 @@ static void task_fpsimd_save(void)
* re-enter user with corrupt state.
* There's no way to recover, so kill it:
*/
- force_signal_inject(
- SIGKILL, 0, current_pt_regs(), 0);
+ force_signal_inject(SIGKILL, SI_KERNEL, 0);
return;
}
sve_save_state(sve_pffr(current),
- &current->thread.fpsimd_state.fpsr);
+ &current->thread.uw.fpsimd_state.fpsr);
} else
- fpsimd_save_state(&current->thread.fpsimd_state);
+ fpsimd_save_state(&current->thread.uw.fpsimd_state);
}
}
@@ -404,20 +405,21 @@ static int __init sve_sysctl_init(void) { return 0; }
(SVE_SIG_ZREG_OFFSET(vq, n) - SVE_SIG_REGS_OFFSET))
/*
- * Transfer the FPSIMD state in task->thread.fpsimd_state to
+ * Transfer the FPSIMD state in task->thread.uw.fpsimd_state to
* task->thread.sve_state.
*
* Task can be a non-runnable task, or current. In the latter case,
* softirqs (and preemption) must be disabled.
* task->thread.sve_state must point to at least sve_state_size(task)
* bytes of allocated kernel memory.
- * task->thread.fpsimd_state must be up to date before calling this function.
+ * task->thread.uw.fpsimd_state must be up to date before calling this
+ * function.
*/
static void fpsimd_to_sve(struct task_struct *task)
{
unsigned int vq;
void *sst = task->thread.sve_state;
- struct fpsimd_state const *fst = &task->thread.fpsimd_state;
+ struct user_fpsimd_state const *fst = &task->thread.uw.fpsimd_state;
unsigned int i;
if (!system_supports_sve())
@@ -431,7 +433,7 @@ static void fpsimd_to_sve(struct task_struct *task)
/*
* Transfer the SVE state in task->thread.sve_state to
- * task->thread.fpsimd_state.
+ * task->thread.uw.fpsimd_state.
*
* Task can be a non-runnable task, or current. In the latter case,
* softirqs (and preemption) must be disabled.
@@ -443,7 +445,7 @@ static void sve_to_fpsimd(struct task_struct *task)
{
unsigned int vq;
void const *sst = task->thread.sve_state;
- struct fpsimd_state *fst = &task->thread.fpsimd_state;
+ struct user_fpsimd_state *fst = &task->thread.uw.fpsimd_state;
unsigned int i;
if (!system_supports_sve())
@@ -510,7 +512,7 @@ void fpsimd_sync_to_sve(struct task_struct *task)
}
/*
- * Ensure that task->thread.fpsimd_state is up to date with respect to
+ * Ensure that task->thread.uw.fpsimd_state is up to date with respect to
* the user task, irrespective of whether SVE is in use or not.
*
* This should only be called by ptrace. task must be non-runnable.
@@ -525,21 +527,21 @@ void sve_sync_to_fpsimd(struct task_struct *task)
/*
* Ensure that task->thread.sve_state is up to date with respect to
- * the task->thread.fpsimd_state.
+ * the task->thread.uw.fpsimd_state.
*
* This should only be called by ptrace to merge new FPSIMD register
* values into a task for which SVE is currently active.
* task must be non-runnable.
* task->thread.sve_state must point to at least sve_state_size(task)
* bytes of allocated kernel memory.
- * task->thread.fpsimd_state must already have been initialised with
+ * task->thread.uw.fpsimd_state must already have been initialised with
* the new FPSIMD register values to be merged in.
*/
void sve_sync_from_fpsimd_zeropad(struct task_struct *task)
{
unsigned int vq;
void *sst = task->thread.sve_state;
- struct fpsimd_state const *fst = &task->thread.fpsimd_state;
+ struct user_fpsimd_state const *fst = &task->thread.uw.fpsimd_state;
unsigned int i;
if (!test_tsk_thread_flag(task, TIF_SVE))
@@ -757,12 +759,10 @@ fail:
* Enable SVE for EL1.
* Intended for use by the cpufeatures code during CPU boot.
*/
-int sve_kernel_enable(void *__always_unused p)
+void sve_kernel_enable(const struct arm64_cpu_capabilities *__always_unused p)
{
write_sysreg(read_sysreg(CPACR_EL1) | CPACR_EL1_ZEN_EL1EN, CPACR_EL1);
isb();
-
- return 0;
}
void __init sve_setup(void)
@@ -831,7 +831,7 @@ asmlinkage void do_sve_acc(unsigned int esr, struct pt_regs *regs)
{
/* Even if we chose not to use SVE, the hardware could still trap: */
if (unlikely(!system_supports_sve()) || WARN_ON(is_compat_task())) {
- force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
+ force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc);
return;
}
@@ -867,18 +867,20 @@ asmlinkage void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
asmlinkage void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
{
siginfo_t info;
- unsigned int si_code = FPE_FIXME;
-
- if (esr & FPEXC_IOF)
- si_code = FPE_FLTINV;
- else if (esr & FPEXC_DZF)
- si_code = FPE_FLTDIV;
- else if (esr & FPEXC_OFF)
- si_code = FPE_FLTOVF;
- else if (esr & FPEXC_UFF)
- si_code = FPE_FLTUND;
- else if (esr & FPEXC_IXF)
- si_code = FPE_FLTRES;
+ unsigned int si_code = FPE_FLTUNK;
+
+ if (esr & ESR_ELx_FP_EXC_TFV) {
+ if (esr & FPEXC_IOF)
+ si_code = FPE_FLTINV;
+ else if (esr & FPEXC_DZF)
+ si_code = FPE_FLTDIV;
+ else if (esr & FPEXC_OFF)
+ si_code = FPE_FLTOVF;
+ else if (esr & FPEXC_UFF)
+ si_code = FPE_FLTUND;
+ else if (esr & FPEXC_IXF)
+ si_code = FPE_FLTRES;
+ }
memset(&info, 0, sizeof(info));
info.si_signo = SIGFPE;
@@ -908,10 +910,9 @@ void fpsimd_thread_switch(struct task_struct *next)
* the TIF_FOREIGN_FPSTATE flag so the state will be loaded
* upon the next return to userland.
*/
- struct fpsimd_state *st = &next->thread.fpsimd_state;
-
- if (__this_cpu_read(fpsimd_last_state.st) == st
- && st->cpu == smp_processor_id())
+ if (__this_cpu_read(fpsimd_last_state.st) ==
+ &next->thread.uw.fpsimd_state
+ && next->thread.fpsimd_cpu == smp_processor_id())
clear_tsk_thread_flag(next, TIF_FOREIGN_FPSTATE);
else
set_tsk_thread_flag(next, TIF_FOREIGN_FPSTATE);
@@ -927,7 +928,8 @@ void fpsimd_flush_thread(void)
local_bh_disable();
- memset(&current->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
+ memset(&current->thread.uw.fpsimd_state, 0,
+ sizeof(current->thread.uw.fpsimd_state));
fpsimd_flush_task_state(current);
if (system_supports_sve()) {
@@ -986,7 +988,7 @@ void fpsimd_preserve_current_state(void)
/*
* Like fpsimd_preserve_current_state(), but ensure that
- * current->thread.fpsimd_state is updated so that it can be copied to
+ * current->thread.uw.fpsimd_state is updated so that it can be copied to
* the signal frame.
*/
void fpsimd_signal_preserve_current_state(void)
@@ -1004,11 +1006,10 @@ static void fpsimd_bind_to_cpu(void)
{
struct fpsimd_last_state_struct *last =
this_cpu_ptr(&fpsimd_last_state);
- struct fpsimd_state *st = &current->thread.fpsimd_state;
- last->st = st;
+ last->st = &current->thread.uw.fpsimd_state;
last->sve_in_use = test_thread_flag(TIF_SVE);
- st->cpu = smp_processor_id();
+ current->thread.fpsimd_cpu = smp_processor_id();
}
/*
@@ -1043,7 +1044,7 @@ void fpsimd_update_current_state(struct user_fpsimd_state const *state)
local_bh_disable();
- current->thread.fpsimd_state.user_fpsimd = *state;
+ current->thread.uw.fpsimd_state = *state;
if (system_supports_sve() && test_thread_flag(TIF_SVE))
fpsimd_to_sve(current);
@@ -1060,7 +1061,7 @@ void fpsimd_update_current_state(struct user_fpsimd_state const *state)
*/
void fpsimd_flush_task_state(struct task_struct *t)
{
- t->thread.fpsimd_state.cpu = NR_CPUS;
+ t->thread.fpsimd_cpu = NR_CPUS;
}
static inline void fpsimd_flush_cpu_state(void)
@@ -1159,7 +1160,7 @@ EXPORT_SYMBOL(kernel_neon_end);
#ifdef CONFIG_EFI
-static DEFINE_PER_CPU(struct fpsimd_state, efi_fpsimd_state);
+static DEFINE_PER_CPU(struct user_fpsimd_state, efi_fpsimd_state);
static DEFINE_PER_CPU(bool, efi_fpsimd_state_used);
static DEFINE_PER_CPU(bool, efi_sve_state_used);
diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c
index 47080c49cc7e..f0e6ab8abe9c 100644
--- a/arch/arm64/kernel/kaslr.c
+++ b/arch/arm64/kernel/kaslr.c
@@ -117,53 +117,42 @@ u64 __init kaslr_early_init(u64 dt_phys)
/*
* OK, so we are proceeding with KASLR enabled. Calculate a suitable
* kernel image offset from the seed. Let's place the kernel in the
- * lower half of the VMALLOC area (VA_BITS - 2).
+ * middle half of the VMALLOC area (VA_BITS - 2), and stay clear of
+ * the lower and upper quarters to avoid colliding with other
+ * allocations.
* Even if we could randomize at page granularity for 16k and 64k pages,
* let's always round to 2 MB so we don't interfere with the ability to
* map using contiguous PTEs
*/
mask = ((1UL << (VA_BITS - 2)) - 1) & ~(SZ_2M - 1);
- offset = seed & mask;
+ offset = BIT(VA_BITS - 3) + (seed & mask);
/* use the top 16 bits to randomize the linear region */
memstart_offset_seed = seed >> 48;
- /*
- * The kernel Image should not extend across a 1GB/32MB/512MB alignment
- * boundary (for 4KB/16KB/64KB granule kernels, respectively). If this
- * happens, round down the KASLR offset by (1 << SWAPPER_TABLE_SHIFT).
- *
- * NOTE: The references to _text and _end below will already take the
- * modulo offset (the physical displacement modulo 2 MB) into
- * account, given that the physical placement is controlled by
- * the loader, and will not change as a result of the virtual
- * mapping we choose.
- */
- if ((((u64)_text + offset) >> SWAPPER_TABLE_SHIFT) !=
- (((u64)_end + offset) >> SWAPPER_TABLE_SHIFT))
- offset = round_down(offset, 1 << SWAPPER_TABLE_SHIFT);
-
if (IS_ENABLED(CONFIG_KASAN))
/*
* KASAN does not expect the module region to intersect the
* vmalloc region, since shadow memory is allocated for each
* module at load time, whereas the vmalloc region is shadowed
* by KASAN zero pages. So keep modules out of the vmalloc
- * region if KASAN is enabled.
+ * region if KASAN is enabled, and put the kernel well within
+ * 4 GB of the module region.
*/
- return offset;
+ return offset % SZ_2G;
if (IS_ENABLED(CONFIG_RANDOMIZE_MODULE_REGION_FULL)) {
/*
- * Randomize the module region independently from the core
- * kernel. This prevents modules from leaking any information
+ * Randomize the module region over a 4 GB window covering the
+ * kernel. This reduces the risk of modules leaking information
* about the address of the kernel itself, but results in
* branches between modules and the core kernel that are
* resolved via PLTs. (Branches between modules will be
* resolved normally.)
*/
- module_range = VMALLOC_END - VMALLOC_START - MODULES_VSIZE;
- module_alloc_base = VMALLOC_START;
+ module_range = SZ_4G - (u64)(_end - _stext);
+ module_alloc_base = max((u64)_end + offset - SZ_4G,
+ (u64)MODULES_VADDR);
} else {
/*
* Randomize the module region by setting module_alloc_base to
diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
index 2122cd187f19..a20de58061a8 100644
--- a/arch/arm64/kernel/kgdb.c
+++ b/arch/arm64/kernel/kgdb.c
@@ -138,14 +138,25 @@ int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
void
sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
{
- struct pt_regs *thread_regs;
+ struct cpu_context *cpu_context = &task->thread.cpu_context;
/* Initialize to zero */
memset((char *)gdb_regs, 0, NUMREGBYTES);
- thread_regs = task_pt_regs(task);
- memcpy((void *)gdb_regs, (void *)thread_regs->regs, GP_REG_BYTES);
- /* Special case for PSTATE (check comments in asm/kgdb.h for details) */
- dbg_get_reg(33, gdb_regs + GP_REG_BYTES, thread_regs);
+
+ gdb_regs[19] = cpu_context->x19;
+ gdb_regs[20] = cpu_context->x20;
+ gdb_regs[21] = cpu_context->x21;
+ gdb_regs[22] = cpu_context->x22;
+ gdb_regs[23] = cpu_context->x23;
+ gdb_regs[24] = cpu_context->x24;
+ gdb_regs[25] = cpu_context->x25;
+ gdb_regs[26] = cpu_context->x26;
+ gdb_regs[27] = cpu_context->x27;
+ gdb_regs[28] = cpu_context->x28;
+ gdb_regs[29] = cpu_context->fp;
+
+ gdb_regs[31] = cpu_context->sp;
+ gdb_regs[32] = cpu_context->pc;
}
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c
index ea640f92fe5a..fa3637284a3d 100644
--- a/arch/arm64/kernel/module-plts.c
+++ b/arch/arm64/kernel/module-plts.c
@@ -36,11 +36,53 @@ u64 module_emit_plt_entry(struct module *mod, void *loc, const Elf64_Rela *rela,
return (u64)&plt[i - 1];
pltsec->plt_num_entries++;
- BUG_ON(pltsec->plt_num_entries > pltsec->plt_max_entries);
+ if (WARN_ON(pltsec->plt_num_entries > pltsec->plt_max_entries))
+ return 0;
return (u64)&plt[i];
}
+#ifdef CONFIG_ARM64_ERRATUM_843419
+u64 module_emit_adrp_veneer(struct module *mod, void *loc, u64 val)
+{
+ struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core :
+ &mod->arch.init;
+ struct plt_entry *plt = (struct plt_entry *)pltsec->plt->sh_addr;
+ int i = pltsec->plt_num_entries++;
+ u32 mov0, mov1, mov2, br;
+ int rd;
+
+ if (WARN_ON(pltsec->plt_num_entries > pltsec->plt_max_entries))
+ return 0;
+
+ /* get the destination register of the ADRP instruction */
+ rd = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RD,
+ le32_to_cpup((__le32 *)loc));
+
+ /* generate the veneer instructions */
+ mov0 = aarch64_insn_gen_movewide(rd, (u16)~val, 0,
+ AARCH64_INSN_VARIANT_64BIT,
+ AARCH64_INSN_MOVEWIDE_INVERSE);
+ mov1 = aarch64_insn_gen_movewide(rd, (u16)(val >> 16), 16,
+ AARCH64_INSN_VARIANT_64BIT,
+ AARCH64_INSN_MOVEWIDE_KEEP);
+ mov2 = aarch64_insn_gen_movewide(rd, (u16)(val >> 32), 32,
+ AARCH64_INSN_VARIANT_64BIT,
+ AARCH64_INSN_MOVEWIDE_KEEP);
+ br = aarch64_insn_gen_branch_imm((u64)&plt[i].br, (u64)loc + 4,
+ AARCH64_INSN_BRANCH_NOLINK);
+
+ plt[i] = (struct plt_entry){
+ cpu_to_le32(mov0),
+ cpu_to_le32(mov1),
+ cpu_to_le32(mov2),
+ cpu_to_le32(br)
+ };
+
+ return (u64)&plt[i];
+}
+#endif
+
#define cmp_3way(a,b) ((a) < (b) ? -1 : (a) > (b))
static int cmp_rela(const void *a, const void *b)
@@ -68,16 +110,21 @@ static bool duplicate_rel(const Elf64_Rela *rela, int num)
}
static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num,
- Elf64_Word dstidx)
+ Elf64_Word dstidx, Elf_Shdr *dstsec)
{
unsigned int ret = 0;
Elf64_Sym *s;
int i;
for (i = 0; i < num; i++) {
+ u64 min_align;
+
switch (ELF64_R_TYPE(rela[i].r_info)) {
case R_AARCH64_JUMP26:
case R_AARCH64_CALL26:
+ if (!IS_ENABLED(CONFIG_RANDOMIZE_BASE))
+ break;
+
/*
* We only have to consider branch targets that resolve
* to symbols that are defined in a different section.
@@ -109,6 +156,41 @@ static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num,
if (rela[i].r_addend != 0 || !duplicate_rel(rela, i))
ret++;
break;
+ case R_AARCH64_ADR_PREL_PG_HI21_NC:
+ case R_AARCH64_ADR_PREL_PG_HI21:
+ if (!IS_ENABLED(CONFIG_ARM64_ERRATUM_843419) ||
+ !cpus_have_const_cap(ARM64_WORKAROUND_843419))
+ break;
+
+ /*
+ * Determine the minimal safe alignment for this ADRP
+ * instruction: the section alignment at which it is
+ * guaranteed not to appear at a vulnerable offset.
+ *
+ * This comes down to finding the least significant zero
+ * bit in bits [11:3] of the section offset, and
+ * increasing the section's alignment so that the
+ * resulting address of this instruction is guaranteed
+ * to equal the offset in that particular bit (as well
+ * as all less signficant bits). This ensures that the
+ * address modulo 4 KB != 0xfff8 or 0xfffc (which would
+ * have all ones in bits [11:3])
+ */
+ min_align = 2ULL << ffz(rela[i].r_offset | 0x7);
+
+ /*
+ * Allocate veneer space for each ADRP that may appear
+ * at a vulnerable offset nonetheless. At relocation
+ * time, some of these will remain unused since some
+ * ADRP instructions can be patched to ADR instructions
+ * instead.
+ */
+ if (min_align > SZ_4K)
+ ret++;
+ else
+ dstsec->sh_addralign = max(dstsec->sh_addralign,
+ min_align);
+ break;
}
}
return ret;
@@ -166,10 +248,10 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
if (strncmp(secstrings + dstsec->sh_name, ".init", 5) != 0)
core_plts += count_plts(syms, rels, numrels,
- sechdrs[i].sh_info);
+ sechdrs[i].sh_info, dstsec);
else
init_plts += count_plts(syms, rels, numrels,
- sechdrs[i].sh_info);
+ sechdrs[i].sh_info, dstsec);
}
mod->arch.core.plt->sh_type = SHT_NOBITS;
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
index f469e0435903..719fde8dcc19 100644
--- a/arch/arm64/kernel/module.c
+++ b/arch/arm64/kernel/module.c
@@ -55,9 +55,10 @@ void *module_alloc(unsigned long size)
* less likely that the module region gets exhausted, so we
* can simply omit this fallback in that case.
*/
- p = __vmalloc_node_range(size, MODULE_ALIGN, VMALLOC_START,
- VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_EXEC, 0,
- NUMA_NO_NODE, __builtin_return_address(0));
+ p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base,
+ module_alloc_base + SZ_4G, GFP_KERNEL,
+ PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
+ __builtin_return_address(0));
if (p && (kasan_module_alloc(p, size) < 0)) {
vfree(p);
@@ -197,6 +198,34 @@ static int reloc_insn_imm(enum aarch64_reloc_op op, __le32 *place, u64 val,
return 0;
}
+static int reloc_insn_adrp(struct module *mod, __le32 *place, u64 val)
+{
+ u32 insn;
+
+ if (!IS_ENABLED(CONFIG_ARM64_ERRATUM_843419) ||
+ !cpus_have_const_cap(ARM64_WORKAROUND_843419) ||
+ ((u64)place & 0xfff) < 0xff8)
+ return reloc_insn_imm(RELOC_OP_PAGE, place, val, 12, 21,
+ AARCH64_INSN_IMM_ADR);
+
+ /* patch ADRP to ADR if it is in range */
+ if (!reloc_insn_imm(RELOC_OP_PREL, place, val & ~0xfff, 0, 21,
+ AARCH64_INSN_IMM_ADR)) {
+ insn = le32_to_cpu(*place);
+ insn &= ~BIT(31);
+ } else {
+ /* out of range for ADR -> emit a veneer */
+ val = module_emit_adrp_veneer(mod, place, val & ~0xfff);
+ if (!val)
+ return -ENOEXEC;
+ insn = aarch64_insn_gen_branch_imm((u64)place, val,
+ AARCH64_INSN_BRANCH_NOLINK);
+ }
+
+ *place = cpu_to_le32(insn);
+ return 0;
+}
+
int apply_relocate_add(Elf64_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
@@ -336,14 +365,13 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21,
AARCH64_INSN_IMM_ADR);
break;
-#ifndef CONFIG_ARM64_ERRATUM_843419
case R_AARCH64_ADR_PREL_PG_HI21_NC:
overflow_check = false;
case R_AARCH64_ADR_PREL_PG_HI21:
- ovf = reloc_insn_imm(RELOC_OP_PAGE, loc, val, 12, 21,
- AARCH64_INSN_IMM_ADR);
+ ovf = reloc_insn_adrp(me, loc, val);
+ if (ovf && ovf != -ERANGE)
+ return ovf;
break;
-#endif
case R_AARCH64_ADD_ABS_LO12_NC:
case R_AARCH64_LDST8_ABS_LO12_NC:
overflow_check = false;
@@ -386,6 +414,8 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) &&
ovf == -ERANGE) {
val = module_emit_plt_entry(me, loc, &rel[i], sym);
+ if (!val)
+ return -ENOEXEC;
ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2,
26, AARCH64_INSN_IMM_26);
}
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index c0da6efe5465..f08a2ed9db0d 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -257,7 +257,7 @@ static void tls_thread_flush(void)
write_sysreg(0, tpidr_el0);
if (is_compat_task()) {
- current->thread.tp_value = 0;
+ current->thread.uw.tp_value = 0;
/*
* We need to ensure ordering between the shadow state and the
@@ -351,7 +351,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
* for the new thread.
*/
if (clone_flags & CLONE_SETTLS)
- p->thread.tp_value = childregs->regs[3];
+ p->thread.uw.tp_value = childregs->regs[3];
} else {
memset(childregs, 0, sizeof(struct pt_regs));
childregs->pstate = PSR_MODE_EL1h;
@@ -379,7 +379,7 @@ static void tls_thread_switch(struct task_struct *next)
tls_preserve_current_state();
if (is_compat_thread(task_thread_info(next)))
- write_sysreg(next->thread.tp_value, tpidrro_el0);
+ write_sysreg(next->thread.uw.tp_value, tpidrro_el0);
else if (!arm64_kernel_unmapped_at_el0())
write_sysreg(0, tpidrro_el0);
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 9ae31f7e2243..71d99af24ef2 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -209,7 +209,7 @@ static void ptrace_hbptriggered(struct perf_event *bp,
force_sig_ptrace_errno_trap(si_errno, (void __user *)bkpt->trigger);
}
#endif
- force_sig_info(SIGTRAP, &info, current);
+ arm64_force_sig_info(&info, "Hardware breakpoint trap (ptrace)", current);
}
/*
@@ -629,7 +629,7 @@ static int __fpr_get(struct task_struct *target,
sve_sync_to_fpsimd(target);
- uregs = &target->thread.fpsimd_state.user_fpsimd;
+ uregs = &target->thread.uw.fpsimd_state;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs,
start_pos, start_pos + sizeof(*uregs));
@@ -655,19 +655,19 @@ static int __fpr_set(struct task_struct *target,
struct user_fpsimd_state newstate;
/*
- * Ensure target->thread.fpsimd_state is up to date, so that a
+ * Ensure target->thread.uw.fpsimd_state is up to date, so that a
* short copyin can't resurrect stale data.
*/
sve_sync_to_fpsimd(target);
- newstate = target->thread.fpsimd_state.user_fpsimd;
+ newstate = target->thread.uw.fpsimd_state;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate,
start_pos, start_pos + sizeof(newstate));
if (ret)
return ret;
- target->thread.fpsimd_state.user_fpsimd = newstate;
+ target->thread.uw.fpsimd_state = newstate;
return ret;
}
@@ -692,7 +692,7 @@ static int tls_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
- unsigned long *tls = &target->thread.tp_value;
+ unsigned long *tls = &target->thread.uw.tp_value;
if (target == current)
tls_preserve_current_state();
@@ -705,13 +705,13 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset,
const void *kbuf, const void __user *ubuf)
{
int ret;
- unsigned long tls = target->thread.tp_value;
+ unsigned long tls = target->thread.uw.tp_value;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
if (ret)
return ret;
- target->thread.tp_value = tls;
+ target->thread.uw.tp_value = tls;
return ret;
}
@@ -842,7 +842,7 @@ static int sve_get(struct task_struct *target,
start = end;
end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
- &target->thread.fpsimd_state.fpsr,
+ &target->thread.uw.fpsimd_state.fpsr,
start, end);
if (ret)
return ret;
@@ -941,7 +941,7 @@ static int sve_set(struct task_struct *target,
start = end;
end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &target->thread.fpsimd_state.fpsr,
+ &target->thread.uw.fpsimd_state.fpsr,
start, end);
out:
@@ -1169,7 +1169,7 @@ static int compat_vfp_get(struct task_struct *target,
compat_ulong_t fpscr;
int ret, vregs_end_pos;
- uregs = &target->thread.fpsimd_state.user_fpsimd;
+ uregs = &target->thread.uw.fpsimd_state;
if (target == current)
fpsimd_preserve_current_state();
@@ -1202,7 +1202,7 @@ static int compat_vfp_set(struct task_struct *target,
compat_ulong_t fpscr;
int ret, vregs_end_pos;
- uregs = &target->thread.fpsimd_state.user_fpsimd;
+ uregs = &target->thread.uw.fpsimd_state;
vregs_end_pos = VFP_STATE_SIZE - sizeof(compat_ulong_t);
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
@@ -1225,7 +1225,7 @@ static int compat_tls_get(struct task_struct *target,
const struct user_regset *regset, unsigned int pos,
unsigned int count, void *kbuf, void __user *ubuf)
{
- compat_ulong_t tls = (compat_ulong_t)target->thread.tp_value;
+ compat_ulong_t tls = (compat_ulong_t)target->thread.uw.tp_value;
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
}
@@ -1235,13 +1235,13 @@ static int compat_tls_set(struct task_struct *target,
const void __user *ubuf)
{
int ret;
- compat_ulong_t tls = target->thread.tp_value;
+ compat_ulong_t tls = target->thread.uw.tp_value;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
if (ret)
return ret;
- target->thread.tp_value = tls;
+ target->thread.uw.tp_value = tls;
return ret;
}
@@ -1538,7 +1538,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
break;
case COMPAT_PTRACE_GET_THREAD_AREA:
- ret = put_user((compat_ulong_t)child->thread.tp_value,
+ ret = put_user((compat_ulong_t)child->thread.uw.tp_value,
(compat_ulong_t __user *)datap);
break;
diff --git a/arch/arm64/kernel/reloc_test_core.c b/arch/arm64/kernel/reloc_test_core.c
index c124752a8bd3..5915ce5759cc 100644
--- a/arch/arm64/kernel/reloc_test_core.c
+++ b/arch/arm64/kernel/reloc_test_core.c
@@ -28,6 +28,7 @@ asmlinkage u64 absolute_data16(void);
asmlinkage u64 signed_movw(void);
asmlinkage u64 unsigned_movw(void);
asmlinkage u64 relative_adrp(void);
+asmlinkage u64 relative_adrp_far(void);
asmlinkage u64 relative_adr(void);
asmlinkage u64 relative_data64(void);
asmlinkage u64 relative_data32(void);
@@ -43,9 +44,8 @@ static struct {
{ "R_AARCH64_ABS16", absolute_data16, UL(SYM16_ABS_VAL) },
{ "R_AARCH64_MOVW_SABS_Gn", signed_movw, UL(SYM64_ABS_VAL) },
{ "R_AARCH64_MOVW_UABS_Gn", unsigned_movw, UL(SYM64_ABS_VAL) },
-#ifndef CONFIG_ARM64_ERRATUM_843419
{ "R_AARCH64_ADR_PREL_PG_HI21", relative_adrp, (u64)&sym64_rel },
-#endif
+ { "R_AARCH64_ADR_PREL_PG_HI21", relative_adrp_far, (u64)&memstart_addr },
{ "R_AARCH64_ADR_PREL_LO21", relative_adr, (u64)&sym64_rel },
{ "R_AARCH64_PREL64", relative_data64, (u64)&sym64_rel },
{ "R_AARCH64_PREL32", relative_data32, (u64)&sym64_rel },
diff --git a/arch/arm64/kernel/reloc_test_syms.S b/arch/arm64/kernel/reloc_test_syms.S
index e1edcefeb02d..2b8d9cb8b078 100644
--- a/arch/arm64/kernel/reloc_test_syms.S
+++ b/arch/arm64/kernel/reloc_test_syms.S
@@ -43,15 +43,21 @@ ENTRY(unsigned_movw)
ret
ENDPROC(unsigned_movw)
-#ifndef CONFIG_ARM64_ERRATUM_843419
-
+ .align 12
+ .space 0xff8
ENTRY(relative_adrp)
adrp x0, sym64_rel
add x0, x0, #:lo12:sym64_rel
ret
ENDPROC(relative_adrp)
-#endif
+ .align 12
+ .space 0xffc
+ENTRY(relative_adrp_far)
+ adrp x0, memstart_addr
+ add x0, x0, #:lo12:memstart_addr
+ ret
+ENDPROC(relative_adrp_far)
ENTRY(relative_adr)
adr x0, sym64_rel
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index f60c052e8d1c..154b7d30145d 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -40,6 +40,7 @@
#include <asm/fpsimd.h>
#include <asm/ptrace.h>
#include <asm/signal32.h>
+#include <asm/traps.h>
#include <asm/vdso.h>
/*
@@ -179,7 +180,7 @@ static void __user *apply_user_offset(
static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
{
struct user_fpsimd_state const *fpsimd =
- &current->thread.fpsimd_state.user_fpsimd;
+ &current->thread.uw.fpsimd_state;
int err;
/* copy the FP and status/control registers */
@@ -565,11 +566,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
return regs->regs[0];
badframe:
- if (show_unhandled_signals)
- pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n",
- current->comm, task_pid_nr(current), __func__,
- regs->pc, regs->sp);
- force_sig(SIGSEGV, current);
+ arm64_notify_segfault(regs->sp);
return 0;
}
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 79feb861929b..77b91f478995 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -26,6 +26,7 @@
#include <asm/esr.h>
#include <asm/fpsimd.h>
#include <asm/signal32.h>
+#include <asm/traps.h>
#include <linux/uaccess.h>
#include <asm/unistd.h>
@@ -149,7 +150,7 @@ union __fpsimd_vreg {
static int compat_preserve_vfp_context(struct compat_vfp_sigframe __user *frame)
{
struct user_fpsimd_state const *fpsimd =
- &current->thread.fpsimd_state.user_fpsimd;
+ &current->thread.uw.fpsimd_state;
compat_ulong_t magic = VFP_MAGIC;
compat_ulong_t size = VFP_STORAGE_SIZE;
compat_ulong_t fpscr, fpexc;
@@ -307,11 +308,7 @@ asmlinkage int compat_sys_sigreturn(struct pt_regs *regs)
return regs->regs[0];
badframe:
- if (show_unhandled_signals)
- pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n",
- current->comm, task_pid_nr(current), __func__,
- regs->pc, regs->compat_sp);
- force_sig(SIGSEGV, current);
+ arm64_notify_segfault(regs->compat_sp);
return 0;
}
@@ -344,11 +341,7 @@ asmlinkage int compat_sys_rt_sigreturn(struct pt_regs *regs)
return regs->regs[0];
badframe:
- if (show_unhandled_signals)
- pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n",
- current->comm, task_pid_nr(current), __func__,
- regs->pc, regs->compat_sp);
- force_sig(SIGSEGV, current);
+ arm64_notify_segfault(regs->compat_sp);
return 0;
}
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 3b8ad7be9c33..f3e2e3aec0b0 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -85,43 +85,6 @@ enum ipi_msg_type {
IPI_WAKEUP
};
-#ifdef CONFIG_ARM64_VHE
-
-/* Whether the boot CPU is running in HYP mode or not*/
-static bool boot_cpu_hyp_mode;
-
-static inline void save_boot_cpu_run_el(void)
-{
- boot_cpu_hyp_mode = is_kernel_in_hyp_mode();
-}
-
-static inline bool is_boot_cpu_in_hyp_mode(void)
-{
- return boot_cpu_hyp_mode;
-}
-
-/*
- * Verify that a secondary CPU is running the kernel at the same
- * EL as that of the boot CPU.
- */
-void verify_cpu_run_el(void)
-{
- bool in_el2 = is_kernel_in_hyp_mode();
- bool boot_cpu_el2 = is_boot_cpu_in_hyp_mode();
-
- if (in_el2 ^ boot_cpu_el2) {
- pr_crit("CPU%d: mismatched Exception Level(EL%d) with boot CPU(EL%d)\n",
- smp_processor_id(),
- in_el2 ? 2 : 1,
- boot_cpu_el2 ? 2 : 1);
- cpu_panic_kernel();
- }
-}
-
-#else
-static inline void save_boot_cpu_run_el(void) {}
-#endif
-
#ifdef CONFIG_HOTPLUG_CPU
static int op_cpu_kill(unsigned int cpu);
#else
@@ -447,13 +410,6 @@ void __init smp_prepare_boot_cpu(void)
*/
jump_label_init();
cpuinfo_store_boot_cpu();
- save_boot_cpu_run_el();
- /*
- * Run the errata work around checks on the boot CPU, once we have
- * initialised the cpu feature infrastructure from
- * cpuinfo_store_boot_cpu() above.
- */
- update_cpu_errata_workarounds();
}
static u64 __init of_get_cpu_mpidr(struct device_node *dn)
diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c
index a382b2a1b84e..93ab57dcfc14 100644
--- a/arch/arm64/kernel/sys_compat.c
+++ b/arch/arm64/kernel/sys_compat.c
@@ -27,6 +27,7 @@
#include <linux/uaccess.h>
#include <asm/cacheflush.h>
+#include <asm/system_misc.h>
#include <asm/unistd.h>
static long
@@ -67,6 +68,7 @@ do_compat_cache_op(unsigned long start, unsigned long end, int flags)
*/
long compat_arm_syscall(struct pt_regs *regs)
{
+ siginfo_t info;
unsigned int no = regs->regs[7];
switch (no) {
@@ -88,7 +90,7 @@ long compat_arm_syscall(struct pt_regs *regs)
return do_compat_cache_op(regs->regs[0], regs->regs[1], regs->regs[2]);
case __ARM_NR_compat_set_tls:
- current->thread.tp_value = regs->regs[0];
+ current->thread.uw.tp_value = regs->regs[0];
/*
* Protect against register corruption from context switch.
@@ -99,6 +101,23 @@ long compat_arm_syscall(struct pt_regs *regs)
return 0;
default:
- return -ENOSYS;
+ /*
+ * Calls 9f00xx..9f07ff are defined to return -ENOSYS
+ * if not implemented, rather than raising SIGILL. This
+ * way the calling program can gracefully determine whether
+ * a feature is supported.
+ */
+ if ((no & 0xffff) <= 0x7ff)
+ return -ENOSYS;
+ break;
}
+
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = ILL_ILLTRP;
+ info.si_addr = (void __user *)instruction_pointer(regs) -
+ (compat_thumb_mode(regs) ? 2 : 4);
+
+ arm64_notify_die("Oops - bad compat syscall(2)", regs, &info, no);
+ return 0;
}
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index eb2d15147e8d..ba964da31a25 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -38,6 +38,7 @@
#include <asm/atomic.h>
#include <asm/bug.h>
+#include <asm/cpufeature.h>
#include <asm/daifflags.h>
#include <asm/debug-monitors.h>
#include <asm/esr.h>
@@ -223,13 +224,46 @@ void die(const char *str, struct pt_regs *regs, int err)
do_exit(SIGSEGV);
}
+static bool show_unhandled_signals_ratelimited(void)
+{
+ static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
+ DEFAULT_RATELIMIT_BURST);
+ return show_unhandled_signals && __ratelimit(&rs);
+}
+
+void arm64_force_sig_info(struct siginfo *info, const char *str,
+ struct task_struct *tsk)
+{
+ unsigned int esr = tsk->thread.fault_code;
+ struct pt_regs *regs = task_pt_regs(tsk);
+
+ if (!unhandled_signal(tsk, info->si_signo))
+ goto send_sig;
+
+ if (!show_unhandled_signals_ratelimited())
+ goto send_sig;
+
+ pr_info("%s[%d]: unhandled exception: ", tsk->comm, task_pid_nr(tsk));
+ if (esr)
+ pr_cont("%s, ESR 0x%08x, ", esr_get_class_string(esr), esr);
+
+ pr_cont("%s", str);
+ print_vma_addr(KERN_CONT " in ", regs->pc);
+ pr_cont("\n");
+ __show_regs(regs);
+
+send_sig:
+ force_sig_info(info->si_signo, info, tsk);
+}
+
void arm64_notify_die(const char *str, struct pt_regs *regs,
struct siginfo *info, int err)
{
if (user_mode(regs)) {
+ WARN_ON(regs != current_pt_regs());
current->thread.fault_address = 0;
current->thread.fault_code = err;
- force_sig_info(info->si_signo, info, current);
+ arm64_force_sig_info(info, str, current);
} else {
die(str, regs, err);
}
@@ -311,12 +345,13 @@ exit:
return fn ? fn(regs, instr) : 1;
}
-void force_signal_inject(int signal, int code, struct pt_regs *regs,
- unsigned long address)
+void force_signal_inject(int signal, int code, unsigned long address)
{
siginfo_t info;
- void __user *pc = (void __user *)instruction_pointer(regs);
const char *desc;
+ struct pt_regs *regs = current_pt_regs();
+
+ clear_siginfo(&info);
switch (signal) {
case SIGILL:
@@ -330,17 +365,16 @@ void force_signal_inject(int signal, int code, struct pt_regs *regs,
break;
}
- if (unhandled_signal(current, signal) &&
- show_unhandled_signals_ratelimited()) {
- pr_info("%s[%d]: %s: pc=%p\n",
- current->comm, task_pid_nr(current), desc, pc);
- dump_instr(KERN_INFO, regs);
+ /* Force signals we don't understand to SIGKILL */
+ if (WARN_ON(signal != SIGKILL ||
+ siginfo_layout(signal, code) != SIL_FAULT)) {
+ signal = SIGKILL;
}
info.si_signo = signal;
info.si_errno = 0;
info.si_code = code;
- info.si_addr = pc;
+ info.si_addr = (void __user *)address;
arm64_notify_die(desc, regs, &info, 0);
}
@@ -348,7 +382,7 @@ void force_signal_inject(int signal, int code, struct pt_regs *regs,
/*
* Set up process info to signal segmentation fault - called on access error.
*/
-void arm64_notify_segfault(struct pt_regs *regs, unsigned long addr)
+void arm64_notify_segfault(unsigned long addr)
{
int code;
@@ -359,7 +393,7 @@ void arm64_notify_segfault(struct pt_regs *regs, unsigned long addr)
code = SEGV_ACCERR;
up_read(&current->mm->mmap_sem);
- force_signal_inject(SIGSEGV, code, regs, addr);
+ force_signal_inject(SIGSEGV, code, addr);
}
asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
@@ -371,13 +405,12 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
if (call_undef_hook(regs) == 0)
return;
- force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
+ force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc);
}
-int cpu_enable_cache_maint_trap(void *__unused)
+void cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused)
{
config_sctlr_el1(SCTLR_EL1_UCI, 0);
- return 0;
}
#define __user_cache_maint(insn, address, res) \
@@ -426,12 +459,12 @@ static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
__user_cache_maint("ic ivau", address, ret);
break;
default:
- force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
+ force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc);
return;
}
if (ret)
- arm64_notify_segfault(regs, address);
+ arm64_notify_segfault(address);
else
arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
}
@@ -600,11 +633,6 @@ asmlinkage void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr)
{
siginfo_t info;
void __user *pc = (void __user *)instruction_pointer(regs);
- console_verbose();
-
- pr_crit("Bad EL0 synchronous exception detected on CPU%d, code 0x%08x -- %s\n",
- smp_processor_id(), esr, esr_get_class_string(esr));
- __show_regs(regs);
info.si_signo = SIGILL;
info.si_errno = 0;
@@ -612,9 +640,9 @@ asmlinkage void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr)
info.si_addr = pc;
current->thread.fault_address = 0;
- current->thread.fault_code = 0;
+ current->thread.fault_code = esr;
- force_sig_info(info.si_signo, &info, current);
+ arm64_force_sig_info(&info, "Bad EL0 synchronous exception", current);
}
#ifdef CONFIG_VMAP_STACK
diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile
index 4e696f96451f..0ead8a1d1679 100644
--- a/arch/arm64/lib/Makefile
+++ b/arch/arm64/lib/Makefile
@@ -17,6 +17,7 @@ CFLAGS_atomic_ll_sc.o := -fcall-used-x0 -ffixed-x1 -ffixed-x2 \
-ffixed-x7 -fcall-saved-x8 -fcall-saved-x9 \
-fcall-saved-x10 -fcall-saved-x11 -fcall-saved-x12 \
-fcall-saved-x13 -fcall-saved-x14 -fcall-saved-x15 \
- -fcall-saved-x18
+ -fcall-saved-x18 -fomit-frame-pointer
+CFLAGS_REMOVE_atomic_ll_sc.o := -pg
lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 758bde7e2fa6..30334d81b021 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -50,6 +50,10 @@ ENTRY(flush_icache_range)
*/
ENTRY(__flush_cache_user_range)
uaccess_ttbr0_enable x2, x3, x4
+alternative_if ARM64_HAS_CACHE_IDC
+ dsb ishst
+ b 7f
+alternative_else_nop_endif
dcache_line_size x2, x3
sub x3, x2, #1
bic x4, x0, x3
@@ -60,8 +64,13 @@ user_alt 9f, "dc cvau, x4", "dc civac, x4", ARM64_WORKAROUND_CLEAN_CACHE
b.lo 1b
dsb ish
+7:
+alternative_if ARM64_HAS_CACHE_DIC
+ isb
+ b 8f
+alternative_else_nop_endif
invalidate_icache_by_line x0, x1, x2, x3, 9f
- mov x0, #0
+8: mov x0, #0
1:
uaccess_ttbr0_disable x1, x2
ret
@@ -80,6 +89,12 @@ ENDPROC(__flush_cache_user_range)
* - end - virtual end address of region
*/
ENTRY(invalidate_icache_range)
+alternative_if ARM64_HAS_CACHE_DIC
+ mov x0, xzr
+ isb
+ ret
+alternative_else_nop_endif
+
uaccess_ttbr0_enable x2, x3, x4
invalidate_icache_by_line x0, x1, x2, x3, 2f
@@ -116,6 +131,10 @@ ENDPIPROC(__flush_dcache_area)
* - size - size in question
*/
ENTRY(__clean_dcache_area_pou)
+alternative_if ARM64_HAS_CACHE_IDC
+ dsb ishst
+ ret
+alternative_else_nop_endif
dcache_by_line_op cvau, ish, x0, x1, x2, x3
ret
ENDPROC(__clean_dcache_area_pou)
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index bff11553eb05..4165485e8b6e 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -43,6 +43,7 @@
#include <asm/system_misc.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
+#include <asm/traps.h>
#include <acpi/ghes.h>
@@ -289,58 +290,31 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr,
do_exit(SIGKILL);
}
-static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
- unsigned int esr, unsigned int sig, int code,
- struct pt_regs *regs, int fault)
+static void __do_user_fault(struct siginfo *info, unsigned int esr)
{
- struct siginfo si;
- const struct fault_info *inf;
- unsigned int lsb = 0;
-
- if (unhandled_signal(tsk, sig) && show_unhandled_signals_ratelimited()) {
- inf = esr_to_fault_info(esr);
- pr_info("%s[%d]: unhandled %s (%d) at 0x%08lx, esr 0x%03x",
- tsk->comm, task_pid_nr(tsk), inf->name, sig,
- addr, esr);
- print_vma_addr(KERN_CONT ", in ", regs->pc);
- pr_cont("\n");
- __show_regs(regs);
- }
-
- tsk->thread.fault_address = addr;
- tsk->thread.fault_code = esr;
- si.si_signo = sig;
- si.si_errno = 0;
- si.si_code = code;
- si.si_addr = (void __user *)addr;
- /*
- * Either small page or large page may be poisoned.
- * In other words, VM_FAULT_HWPOISON_LARGE and
- * VM_FAULT_HWPOISON are mutually exclusive.
- */
- if (fault & VM_FAULT_HWPOISON_LARGE)
- lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
- else if (fault & VM_FAULT_HWPOISON)
- lsb = PAGE_SHIFT;
- si.si_addr_lsb = lsb;
-
- force_sig_info(sig, &si, tsk);
+ current->thread.fault_address = (unsigned long)info->si_addr;
+ current->thread.fault_code = esr;
+ arm64_force_sig_info(info, esr_to_fault_info(esr)->name, current);
}
static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *regs)
{
- struct task_struct *tsk = current;
- const struct fault_info *inf;
-
/*
* If we are in kernel mode at this point, we have no context to
* handle this fault with.
*/
if (user_mode(regs)) {
- inf = esr_to_fault_info(esr);
- __do_user_fault(tsk, addr, esr, inf->sig, inf->code, regs, 0);
- } else
+ const struct fault_info *inf = esr_to_fault_info(esr);
+ struct siginfo si = {
+ .si_signo = inf->sig,
+ .si_code = inf->code,
+ .si_addr = (void __user *)addr,
+ };
+
+ __do_user_fault(&si, esr);
+ } else {
__do_kernel_fault(addr, esr, regs);
+ }
}
#define VM_FAULT_BADMAP 0x010000
@@ -393,7 +367,8 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
{
struct task_struct *tsk;
struct mm_struct *mm;
- int fault, sig, code, major = 0;
+ struct siginfo si;
+ int fault, major = 0;
unsigned long vm_flags = VM_READ | VM_WRITE;
unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
@@ -525,27 +500,37 @@ retry:
return 0;
}
+ clear_siginfo(&si);
+ si.si_addr = (void __user *)addr;
+
if (fault & VM_FAULT_SIGBUS) {
/*
* We had some memory, but were unable to successfully fix up
* this page fault.
*/
- sig = SIGBUS;
- code = BUS_ADRERR;
- } else if (fault & (VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE)) {
- sig = SIGBUS;
- code = BUS_MCEERR_AR;
+ si.si_signo = SIGBUS;
+ si.si_code = BUS_ADRERR;
+ } else if (fault & VM_FAULT_HWPOISON_LARGE) {
+ unsigned int hindex = VM_FAULT_GET_HINDEX(fault);
+
+ si.si_signo = SIGBUS;
+ si.si_code = BUS_MCEERR_AR;
+ si.si_addr_lsb = hstate_index_to_shift(hindex);
+ } else if (fault & VM_FAULT_HWPOISON) {
+ si.si_signo = SIGBUS;
+ si.si_code = BUS_MCEERR_AR;
+ si.si_addr_lsb = PAGE_SHIFT;
} else {
/*
* Something tried to access memory that isn't in our memory
* map.
*/
- sig = SIGSEGV;
- code = fault == VM_FAULT_BADACCESS ?
- SEGV_ACCERR : SEGV_MAPERR;
+ si.si_signo = SIGSEGV;
+ si.si_code = fault == VM_FAULT_BADACCESS ?
+ SEGV_ACCERR : SEGV_MAPERR;
}
- __do_user_fault(tsk, addr, esr, sig, code, regs, fault);
+ __do_user_fault(&si, esr);
return 0;
no_context:
@@ -582,8 +567,6 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
const struct fault_info *inf;
inf = esr_to_fault_info(esr);
- pr_err("Synchronous External Abort: %s (0x%08x) at 0x%016lx\n",
- inf->name, esr, addr);
/*
* Synchronous aborts may interrupt code which had interrupts masked.
@@ -600,83 +583,83 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
nmi_exit();
}
- info.si_signo = SIGBUS;
+ info.si_signo = inf->sig;
info.si_errno = 0;
- info.si_code = BUS_FIXME;
+ info.si_code = inf->code;
if (esr & ESR_ELx_FnV)
info.si_addr = NULL;
else
info.si_addr = (void __user *)addr;
- arm64_notify_die("", regs, &info, esr);
+ arm64_notify_die(inf->name, regs, &info, esr);
return 0;
}
static const struct fault_info fault_info[] = {
- { do_bad, SIGBUS, BUS_FIXME, "ttbr address size fault" },
- { do_bad, SIGBUS, BUS_FIXME, "level 1 address size fault" },
- { do_bad, SIGBUS, BUS_FIXME, "level 2 address size fault" },
- { do_bad, SIGBUS, BUS_FIXME, "level 3 address size fault" },
+ { do_bad, SIGKILL, SI_KERNEL, "ttbr address size fault" },
+ { do_bad, SIGKILL, SI_KERNEL, "level 1 address size fault" },
+ { do_bad, SIGKILL, SI_KERNEL, "level 2 address size fault" },
+ { do_bad, SIGKILL, SI_KERNEL, "level 3 address size fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 0 translation fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 8" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 8" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 12" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 12" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
- { do_sea, SIGBUS, BUS_FIXME, "synchronous external abort" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 17" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 18" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 19" },
- { do_sea, SIGBUS, BUS_FIXME, "level 0 (translation table walk)" },
- { do_sea, SIGBUS, BUS_FIXME, "level 1 (translation table walk)" },
- { do_sea, SIGBUS, BUS_FIXME, "level 2 (translation table walk)" },
- { do_sea, SIGBUS, BUS_FIXME, "level 3 (translation table walk)" },
- { do_sea, SIGBUS, BUS_FIXME, "synchronous parity or ECC error" }, // Reserved when RAS is implemented
- { do_bad, SIGBUS, BUS_FIXME, "unknown 25" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 26" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 27" },
- { do_sea, SIGBUS, BUS_FIXME, "level 0 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
- { do_sea, SIGBUS, BUS_FIXME, "level 1 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
- { do_sea, SIGBUS, BUS_FIXME, "level 2 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
- { do_sea, SIGBUS, BUS_FIXME, "level 3 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
- { do_bad, SIGBUS, BUS_FIXME, "unknown 32" },
+ { do_sea, SIGBUS, BUS_OBJERR, "synchronous external abort" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 17" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 18" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 19" },
+ { do_sea, SIGKILL, SI_KERNEL, "level 0 (translation table walk)" },
+ { do_sea, SIGKILL, SI_KERNEL, "level 1 (translation table walk)" },
+ { do_sea, SIGKILL, SI_KERNEL, "level 2 (translation table walk)" },
+ { do_sea, SIGKILL, SI_KERNEL, "level 3 (translation table walk)" },
+ { do_sea, SIGBUS, BUS_OBJERR, "synchronous parity or ECC error" }, // Reserved when RAS is implemented
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 25" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 26" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 27" },
+ { do_sea, SIGKILL, SI_KERNEL, "level 0 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
+ { do_sea, SIGKILL, SI_KERNEL, "level 1 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
+ { do_sea, SIGKILL, SI_KERNEL, "level 2 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
+ { do_sea, SIGKILL, SI_KERNEL, "level 3 synchronous parity error (translation table walk)" }, // Reserved when RAS is implemented
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 32" },
{ do_alignment_fault, SIGBUS, BUS_ADRALN, "alignment fault" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 34" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 35" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 36" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 37" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 38" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 39" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 40" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 41" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 42" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 43" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 44" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 45" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 46" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 47" },
- { do_bad, SIGBUS, BUS_FIXME, "TLB conflict abort" },
- { do_bad, SIGBUS, BUS_FIXME, "Unsupported atomic hardware update fault" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 50" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 51" },
- { do_bad, SIGBUS, BUS_FIXME, "implementation fault (lockdown abort)" },
- { do_bad, SIGBUS, BUS_FIXME, "implementation fault (unsupported exclusive)" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 54" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 55" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 56" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 57" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 58" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 59" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 60" },
- { do_bad, SIGBUS, BUS_FIXME, "section domain fault" },
- { do_bad, SIGBUS, BUS_FIXME, "page domain fault" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 63" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 34" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 35" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 36" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 37" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 38" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 39" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 40" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 41" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 42" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 43" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 44" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 45" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 46" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 47" },
+ { do_bad, SIGKILL, SI_KERNEL, "TLB conflict abort" },
+ { do_bad, SIGKILL, SI_KERNEL, "Unsupported atomic hardware update fault" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 50" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 51" },
+ { do_bad, SIGKILL, SI_KERNEL, "implementation fault (lockdown abort)" },
+ { do_bad, SIGBUS, BUS_OBJERR, "implementation fault (unsupported exclusive)" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 54" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 55" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 56" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 57" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 58" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 59" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 60" },
+ { do_bad, SIGKILL, SI_KERNEL, "section domain fault" },
+ { do_bad, SIGKILL, SI_KERNEL, "page domain fault" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 63" },
};
int handle_guest_sea(phys_addr_t addr, unsigned int esr)
@@ -698,19 +681,17 @@ asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr,
if (!inf->fn(addr, esr, regs))
return;
- pr_alert("Unhandled fault: %s at 0x%016lx\n",
- inf->name, addr);
-
- mem_abort_decode(esr);
-
- if (!user_mode(regs))
+ if (!user_mode(regs)) {
+ pr_alert("Unhandled fault at 0x%016lx\n", addr);
+ mem_abort_decode(esr);
show_pte(addr);
+ }
info.si_signo = inf->sig;
info.si_errno = 0;
info.si_code = inf->code;
info.si_addr = (void __user *)addr;
- arm64_notify_die("", regs, &info, esr);
+ arm64_notify_die(inf->name, regs, &info, esr);
}
asmlinkage void __exception do_el0_irq_bp_hardening(void)
@@ -741,7 +722,6 @@ asmlinkage void __exception do_sp_pc_abort(unsigned long addr,
struct pt_regs *regs)
{
struct siginfo info;
- struct task_struct *tsk = current;
if (user_mode(regs)) {
if (instruction_pointer(regs) > TASK_SIZE)
@@ -749,17 +729,11 @@ asmlinkage void __exception do_sp_pc_abort(unsigned long addr,
local_irq_enable();
}
- if (show_unhandled_signals && unhandled_signal(tsk, SIGBUS))
- pr_info_ratelimited("%s[%d]: %s exception: pc=%p sp=%p\n",
- tsk->comm, task_pid_nr(tsk),
- esr_get_class_string(esr), (void *)regs->pc,
- (void *)regs->sp);
-
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRALN;
info.si_addr = (void __user *)addr;
- arm64_notify_die("Oops - SP/PC alignment exception", regs, &info, esr);
+ arm64_notify_die("SP/PC alignment exception", regs, &info, esr);
}
int __init early_brk64(unsigned long addr, unsigned int esr,
@@ -774,11 +748,11 @@ static struct fault_info __refdata debug_fault_info[] = {
{ do_bad, SIGTRAP, TRAP_HWBKPT, "hardware breakpoint" },
{ do_bad, SIGTRAP, TRAP_HWBKPT, "hardware single-step" },
{ do_bad, SIGTRAP, TRAP_HWBKPT, "hardware watchpoint" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 3" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 3" },
{ do_bad, SIGTRAP, TRAP_BRKPT, "aarch32 BKPT" },
- { do_bad, SIGTRAP, TRAP_FIXME, "aarch32 vector catch" },
+ { do_bad, SIGKILL, SI_KERNEL, "aarch32 vector catch" },
{ early_brk64, SIGTRAP, TRAP_BRKPT, "aarch64 BRK" },
- { do_bad, SIGBUS, BUS_FIXME, "unknown 7" },
+ { do_bad, SIGKILL, SI_KERNEL, "unknown 7" },
};
void __init hook_debug_fault_code(int nr,
@@ -814,14 +788,11 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,
if (!inf->fn(addr, esr, regs)) {
rv = 1;
} else {
- pr_alert("Unhandled debug exception: %s (0x%08x) at 0x%016lx\n",
- inf->name, esr, addr);
-
info.si_signo = inf->sig;
info.si_errno = 0;
info.si_code = inf->code;
info.si_addr = (void __user *)addr;
- arm64_notify_die("", regs, &info, 0);
+ arm64_notify_die(inf->name, regs, &info, esr);
rv = 0;
}
@@ -833,7 +804,7 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,
NOKPROBE_SYMBOL(do_debug_exception);
#ifdef CONFIG_ARM64_PAN
-int cpu_enable_pan(void *__unused)
+void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused)
{
/*
* We modify PSTATE. This won't work from irq context as the PSTATE
@@ -843,6 +814,5 @@ int cpu_enable_pan(void *__unused)
config_sctlr_el1(SCTLR_EL1_SPAN, 0);
asm(SET_PSTATE_PAN(1));
- return 0;
}
#endif /* CONFIG_ARM64_PAN */
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index c0af47617299..5f9a73a4452c 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -36,6 +36,12 @@
#define TCR_TG_FLAGS TCR_TG0_4K | TCR_TG1_4K
#endif
+#ifdef CONFIG_RANDOMIZE_BASE
+#define TCR_KASLR_FLAGS TCR_NFD1
+#else
+#define TCR_KASLR_FLAGS 0
+#endif
+
#define TCR_SMP_FLAGS TCR_SHARED
/* PTWs cacheable, inner/outer WBWA */
@@ -432,7 +438,8 @@ ENTRY(__cpu_setup)
* both user and kernel.
*/
ldr x10, =TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \
- TCR_TG_FLAGS | TCR_ASID16 | TCR_TBI0 | TCR_A1
+ TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \
+ TCR_TBI0 | TCR_A1
tcr_set_idmap_t0sz x10, x9
/*
@@ -441,16 +448,15 @@ ENTRY(__cpu_setup)
tcr_compute_pa_size x10, #TCR_IPS_SHIFT, x5, x6
#ifdef CONFIG_ARM64_HW_AFDBM
/*
- * Hardware update of the Access and Dirty bits.
+ * Enable hardware update of the Access Flags bit.
+ * Hardware dirty bit management is enabled later,
+ * via capabilities.
*/
mrs x9, ID_AA64MMFR1_EL1
and x9, x9, #0xf
- cbz x9, 2f
- cmp x9, #2
- b.lt 1f
- orr x10, x10, #TCR_HD // hardware Dirty flag update
-1: orr x10, x10, #TCR_HA // hardware Access flag update
-2:
+ cbz x9, 1f
+ orr x10, x10, #TCR_HA // hardware Access flag update
+1:
#endif /* CONFIG_ARM64_HW_AFDBM */
msr tcr_el1, x10
ret // return to head.S
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 8128c3b68d6b..61e9a24297b7 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -200,6 +200,7 @@ config ATH79
select SYS_SUPPORTS_MIPS16
select SYS_SUPPORTS_ZBOOT_UART_PROM
select USE_OF
+ select USB_EHCI_ROOT_HUB_TT if USB_EHCI_HCD_PLATFORM
help
Support for the Atheros AR71XX/AR724X/AR913X SoCs.
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index 339df7324e9c..9ecad05bfc73 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -27,6 +27,7 @@ config OPENRISC
select GENERIC_STRNLEN_USER
select GENERIC_SMP_IDLE_THREAD
select MODULES_USE_ELF_RELA
+ select MULTI_IRQ_HANDLER
select HAVE_DEBUG_STACKOVERFLOW
select OR1K_PIC
select CPU_NO_EFFICIENT_FFS if !OPENRISC_HAVE_INST_FF1
@@ -68,6 +69,9 @@ config STACKTRACE_SUPPORT
config LOCKDEP_SUPPORT
def_bool y
+config MULTI_IRQ_HANDLER
+ def_bool y
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 9792d8cf4f56..7e0bb9836b58 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -276,10 +276,8 @@ config SMP
than one CPU, say Y.
If you say N here, the kernel will run on uni- and multiprocessor
- machines, but will use only one CPU of a multiprocessor machine. If
- you say Y here, the kernel will run on many, but not all,
- uniprocessor machines. On a uniprocessor machine, the kernel
- will run faster if you say N here.
+ machines, but will use only one CPU of a multiprocessor machine.
+ On a uniprocessor machine, the kernel will run faster if you say N.
See also <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO
available at <http://www.tldp.org/docs.html#howto>.
diff --git a/arch/parisc/include/asm/io.h b/arch/parisc/include/asm/io.h
index 27c62baa9c4e..afe493b23d04 100644
--- a/arch/parisc/include/asm/io.h
+++ b/arch/parisc/include/asm/io.h
@@ -183,15 +183,15 @@ static inline unsigned char readb(const volatile void __iomem *addr)
}
static inline unsigned short readw(const volatile void __iomem *addr)
{
- return le16_to_cpu(__raw_readw(addr));
+ return le16_to_cpu((__le16 __force) __raw_readw(addr));
}
static inline unsigned int readl(const volatile void __iomem *addr)
{
- return le32_to_cpu(__raw_readl(addr));
+ return le32_to_cpu((__le32 __force) __raw_readl(addr));
}
static inline unsigned long long readq(const volatile void __iomem *addr)
{
- return le64_to_cpu(__raw_readq(addr));
+ return le64_to_cpu((__le64 __force) __raw_readq(addr));
}
static inline void writeb(unsigned char b, volatile void __iomem *addr)
@@ -200,15 +200,15 @@ static inline void writeb(unsigned char b, volatile void __iomem *addr)
}
static inline void writew(unsigned short w, volatile void __iomem *addr)
{
- __raw_writew(cpu_to_le16(w), addr);
+ __raw_writew((__u16 __force) cpu_to_le16(w), addr);
}
static inline void writel(unsigned int l, volatile void __iomem *addr)
{
- __raw_writel(cpu_to_le32(l), addr);
+ __raw_writel((__u32 __force) cpu_to_le32(l), addr);
}
static inline void writeq(unsigned long long q, volatile void __iomem *addr)
{
- __raw_writeq(cpu_to_le64(q), addr);
+ __raw_writeq((__u64 __force) cpu_to_le64(q), addr);
}
#define readb readb
diff --git a/arch/parisc/include/uapi/asm/mman.h b/arch/parisc/include/uapi/asm/mman.h
index 80510ba44c08..a056a642bb31 100644
--- a/arch/parisc/include/uapi/asm/mman.h
+++ b/arch/parisc/include/uapi/asm/mman.h
@@ -13,7 +13,7 @@
#define MAP_SHARED 0x01 /* Share changes */
#define MAP_PRIVATE 0x02 /* Changes are private */
#define MAP_SHARED_VALIDATE 0x03 /* share + validate extension flags */
-#define MAP_TYPE 0x03 /* Mask for type of mapping */
+#define MAP_TYPE 0x2b /* Mask for type of mapping, includes bits 0x08 and 0x20 */
#define MAP_FIXED 0x04 /* Interpret addr exactly */
#define MAP_ANONYMOUS 0x10 /* don't use a file */
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
index 29b99b8964aa..3b8507f71050 100644
--- a/arch/parisc/kernel/drivers.c
+++ b/arch/parisc/kernel/drivers.c
@@ -135,7 +135,7 @@ static int parisc_driver_probe(struct device *dev)
return rc;
}
-static int parisc_driver_remove(struct device *dev)
+static int __exit parisc_driver_remove(struct device *dev)
{
struct parisc_device *pa_dev = to_parisc_device(dev);
struct parisc_driver *pa_drv = to_parisc_driver(dev->driver);
@@ -205,7 +205,7 @@ static int match_and_count(struct device * dev, void * data)
* Use by IOMMU support to "guess" the right size IOPdir.
* Formula is something like memsize/(num_iommu * entry_size).
*/
-int count_parisc_driver(struct parisc_driver *driver)
+int __init count_parisc_driver(struct parisc_driver *driver)
{
struct match_count m = {
.driver = driver,
@@ -268,7 +268,7 @@ static struct parisc_device *find_device_by_addr(unsigned long hpa)
* Walks up the device tree looking for a device of the specified type.
* If it finds it, it returns it. If not, it returns NULL.
*/
-const struct parisc_device *
+const struct parisc_device * __init
find_pa_parent_type(const struct parisc_device *padev, int type)
{
const struct device *dev = &padev->dev;
@@ -397,7 +397,7 @@ static void setup_bus_id(struct parisc_device *padev)
dev_set_name(&padev->dev, name);
}
-struct parisc_device * create_tree_node(char id, struct device *parent)
+struct parisc_device * __init create_tree_node(char id, struct device *parent)
{
struct parisc_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
@@ -471,7 +471,7 @@ static struct parisc_device *create_parisc_device(struct hardware_path *modpath)
return alloc_tree_node(parent, modpath->mod);
}
-struct parisc_device *
+struct parisc_device * __init
alloc_pa_dev(unsigned long hpa, struct hardware_path *mod_path)
{
int status;
@@ -609,7 +609,7 @@ struct bus_type parisc_bus_type = {
.uevent = parisc_uevent,
.dev_groups = parisc_device_groups,
.probe = parisc_driver_probe,
- .remove = parisc_driver_remove,
+ .remove = __exit_p(parisc_driver_remove),
};
/**
@@ -619,7 +619,7 @@ struct bus_type parisc_bus_type = {
* Search the driver list for a driver that is willing to manage
* this device.
*/
-int register_parisc_device(struct parisc_device *dev)
+int __init register_parisc_device(struct parisc_device *dev)
{
if (!dev)
return 0;
@@ -651,6 +651,10 @@ static int match_pci_device(struct device *dev, int index,
(modpath->mod == PCI_FUNC(devfn)));
}
+ /* index might be out of bounds for bc[] */
+ if (index >= 6)
+ return 0;
+
id = PCI_SLOT(pdev->devfn) | (PCI_FUNC(pdev->devfn) << 5);
return (modpath->bc[index] == id);
}
@@ -791,7 +795,7 @@ EXPORT_SYMBOL(device_to_hwpath);
static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high,
struct device *parent);
-void walk_lower_bus(struct parisc_device *dev)
+static void walk_lower_bus(struct parisc_device *dev)
{
unsigned long io_io_low, io_io_high;
@@ -857,7 +861,7 @@ static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high,
* PDC doesn't tell us about all devices in the system. This routine
* finds devices connected to the central bus.
*/
-void walk_central_bus(void)
+void __init walk_central_bus(void)
{
walk_native_bus(CENTRAL_BUS_ADDR,
CENTRAL_BUS_ADDR + (MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET),
@@ -886,7 +890,7 @@ static void print_parisc_device(struct parisc_device *dev)
/**
* init_parisc_bus - Some preparation to be done before inventory
*/
-void init_parisc_bus(void)
+void __init init_parisc_bus(void)
{
if (bus_register(&parisc_bus_type))
panic("Could not register PA-RISC bus type\n");
@@ -895,6 +899,171 @@ void init_parisc_bus(void)
get_device(&root);
}
+static __init void qemu_header(void)
+{
+ int num;
+ unsigned long *p;
+
+ pr_info("--- cut here ---\n");
+ pr_info("/* AUTO-GENERATED HEADER FILE FOR SEABIOS FIRMWARE */\n");
+ pr_cont("/* generated with Linux kernel */\n");
+ pr_cont("/* search for PARISC_QEMU_MACHINE_HEADER in Linux */\n\n");
+
+ pr_info("#define PARISC_MODEL \"%s\"\n\n",
+ boot_cpu_data.pdc.sys_model_name);
+
+ pr_info("#define PARISC_PDC_MODEL 0x%lx, 0x%lx, 0x%lx, "
+ "0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx\n\n",
+ #define p ((unsigned long *)&boot_cpu_data.pdc.model)
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]);
+ #undef p
+
+ pr_info("#define PARISC_PDC_VERSION 0x%04lx\n\n",
+ boot_cpu_data.pdc.versions);
+
+ pr_info("#define PARISC_PDC_CPUID 0x%04lx\n\n",
+ boot_cpu_data.pdc.cpuid);
+
+ pr_info("#define PARISC_PDC_CAPABILITIES 0x%04lx\n\n",
+ boot_cpu_data.pdc.capabilities);
+
+ pr_info("#define PARISC_PDC_ENTRY_ORG 0x%04lx\n\n",
+#ifdef CONFIG_64BIT
+ (unsigned long)(PAGE0->mem_pdc_hi) << 32 |
+#endif
+ (unsigned long)PAGE0->mem_pdc);
+
+ pr_info("#define PARISC_PDC_CACHE_INFO");
+ p = (unsigned long *) &cache_info;
+ for (num = 0; num < sizeof(cache_info); num += sizeof(unsigned long)) {
+ if (((num % 5) == 0)) {
+ pr_cont(" \\\n");
+ pr_info("\t");
+ }
+ pr_cont("%s0x%04lx",
+ num?", ":"", *p++);
+ }
+ pr_cont("\n\n");
+}
+
+static __init int qemu_print_hpa(struct device *lin_dev, void *data)
+{
+ struct parisc_device *dev = to_parisc_device(lin_dev);
+ unsigned long hpa = dev->hpa.start;
+
+ pr_cont("\t{\t.hpa = 0x%08lx,\\\n", hpa);
+ pr_cont("\t\t.iodc = &iodc_data_hpa_%08lx,\\\n", hpa);
+ pr_cont("\t\t.mod_info = &mod_info_hpa_%08lx,\\\n", hpa);
+ pr_cont("\t\t.mod_path = &mod_path_hpa_%08lx,\\\n", hpa);
+ pr_cont("\t\t.num_addr = HPA_%08lx_num_addr,\\\n", hpa);
+ pr_cont("\t\t.add_addr = { HPA_%08lx_add_addr } },\\\n", hpa);
+ return 0;
+}
+
+
+static __init void qemu_footer(void)
+{
+ pr_info("\n\n#define PARISC_DEVICE_LIST \\\n");
+ for_each_padev(qemu_print_hpa, NULL);
+ pr_cont("\t{ 0, }\n");
+ pr_info("--- cut here ---\n");
+}
+
+/* print iodc data of the various hpa modules for qemu inclusion */
+static __init int qemu_print_iodc_data(struct device *lin_dev, void *data)
+{
+ struct parisc_device *dev = to_parisc_device(lin_dev);
+ unsigned long count;
+ unsigned long hpa = dev->hpa.start;
+ int status;
+ struct pdc_iodc iodc_data;
+
+ int mod_index;
+ struct pdc_system_map_mod_info pdc_mod_info;
+ struct pdc_module_path mod_path;
+
+ status = pdc_iodc_read(&count, hpa, 0,
+ &iodc_data, sizeof(iodc_data));
+ if (status != PDC_OK) {
+ pr_info("No IODC data for hpa 0x%08lx\n", hpa);
+ return 0;
+ }
+
+ pr_info("\n");
+
+ pr_info("#define HPA_%08lx_DESCRIPTION \"%s\"\n",
+ hpa, parisc_hardware_description(&dev->id));
+
+ mod_index = 0;
+ do {
+ status = pdc_system_map_find_mods(&pdc_mod_info,
+ &mod_path, mod_index++);
+ } while (status == PDC_OK && pdc_mod_info.mod_addr != hpa);
+
+ pr_info("static struct pdc_system_map_mod_info"
+ " mod_info_hpa_%08lx = {\n", hpa);
+ #define DO(member) \
+ pr_cont("\t." #member " = 0x%x,\n", \
+ (unsigned int)pdc_mod_info.member)
+ DO(mod_addr);
+ DO(mod_pgs);
+ DO(add_addrs);
+ pr_cont("};\n");
+ #undef DO
+ pr_info("static struct pdc_module_path "
+ "mod_path_hpa_%08lx = {\n", hpa);
+ pr_cont("\t.path = { ");
+ pr_cont(".flags = 0x%x, ", mod_path.path.flags);
+ pr_cont(".bc = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x }, ",
+ (unsigned char)mod_path.path.bc[0],
+ (unsigned char)mod_path.path.bc[1],
+ (unsigned char)mod_path.path.bc[2],
+ (unsigned char)mod_path.path.bc[3],
+ (unsigned char)mod_path.path.bc[4],
+ (unsigned char)mod_path.path.bc[5]);
+ pr_cont(".mod = 0x%x ", mod_path.path.mod);
+ pr_cont(" },\n");
+ pr_cont("\t.layers = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x }\n",
+ mod_path.layers[0], mod_path.layers[1], mod_path.layers[2],
+ mod_path.layers[3], mod_path.layers[4], mod_path.layers[5]);
+ pr_cont("};\n");
+
+ pr_info("static struct pdc_iodc iodc_data_hpa_%08lx = {\n", hpa);
+ #define DO(member) \
+ pr_cont("\t." #member " = 0x%04lx,\n", \
+ (unsigned long)iodc_data.member)
+ DO(hversion_model);
+ DO(hversion);
+ DO(spa);
+ DO(type);
+ DO(sversion_rev);
+ DO(sversion_model);
+ DO(sversion_opt);
+ DO(rev);
+ DO(dep);
+ DO(features);
+ DO(checksum);
+ DO(length);
+ #undef DO
+ pr_cont("\t/* pad: 0x%04x, 0x%04x */\n",
+ iodc_data.pad[0], iodc_data.pad[1]);
+ pr_cont("};\n");
+
+ pr_info("#define HPA_%08lx_num_addr %d\n", hpa, dev->num_addrs);
+ pr_info("#define HPA_%08lx_add_addr ", hpa);
+ count = 0;
+ if (dev->num_addrs == 0)
+ pr_cont("0");
+ while (count < dev->num_addrs) {
+ pr_cont("0x%08lx, ", dev->addr[count]);
+ count++;
+ }
+ pr_cont("\n\n");
+
+ return 0;
+}
+
+
static int print_one_device(struct device * dev, void * data)
{
@@ -908,7 +1077,13 @@ static int print_one_device(struct device * dev, void * data)
/**
* print_parisc_devices - Print out a list of devices found in this system
*/
-void print_parisc_devices(void)
+void __init print_parisc_devices(void)
{
for_each_padev(print_one_device, NULL);
+ #define PARISC_QEMU_MACHINE_HEADER 0
+ if (PARISC_QEMU_MACHINE_HEADER) {
+ qemu_header();
+ for_each_padev(qemu_print_iodc_data, NULL);
+ qemu_footer();
+ }
}
diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c
index af3bc359dc70..a2058953a53f 100644
--- a/arch/parisc/kernel/hardware.c
+++ b/arch/parisc/kernel/hardware.c
@@ -41,7 +41,7 @@
* are guessed. If you know the correct name, please let us know.
*/
-static struct hp_hardware hp_hardware_list[] = {
+static struct hp_hardware hp_hardware_list[] __initdata = {
{HPHW_NPROC,0x01,0x4,0x0,"Indigo (840, 930)"},
{HPHW_NPROC,0x8,0x4,0x01,"Firefox(825,925)"},
{HPHW_NPROC,0xA,0x4,0x01,"Top Gun (835,834,935,635)"},
@@ -1238,7 +1238,7 @@ static struct hp_cpu_type_mask {
unsigned short model;
unsigned short mask;
enum cpu_type cpu;
-} hp_cpu_type_mask_list[] = {
+} hp_cpu_type_mask_list[] __initdata = {
{ 0x0000, 0x0ff0, pcx }, /* 0x0000 - 0x000f */
{ 0x0048, 0x0ff0, pcxl }, /* 0x0040 - 0x004f */
@@ -1325,17 +1325,17 @@ const char * const cpu_name_version[][2] = {
[pcxt] = { "PA7100 (PCX-T)", "1.1b" },
[pcxt_] = { "PA7200 (PCX-T')", "1.1c" },
[pcxl] = { "PA7100LC (PCX-L)", "1.1d" },
- [pcxl2] = { "PA7300LC (PCX-L2)", "1.1e" },
+ [pcxl2] = { "PA7300LC (PCX-L2)","1.1e" },
[pcxu] = { "PA8000 (PCX-U)", "2.0" },
[pcxu_] = { "PA8200 (PCX-U+)", "2.0" },
[pcxw] = { "PA8500 (PCX-W)", "2.0" },
[pcxw_] = { "PA8600 (PCX-W+)", "2.0" },
[pcxw2] = { "PA8700 (PCX-W2)", "2.0" },
[mako] = { "PA8800 (Mako)", "2.0" },
- [mako2] = { "PA8900 (Shortfin)", "2.0" }
+ [mako2] = { "PA8900 (Shortfin)","2.0" }
};
-const char *parisc_hardware_description(struct parisc_device_id *id)
+const char * __init parisc_hardware_description(struct parisc_device_id *id)
{
struct hp_hardware *listptr;
@@ -1373,7 +1373,7 @@ const char *parisc_hardware_description(struct parisc_device_id *id)
/* Interpret hversion (ret[0]) from PDC_MODEL(4)/PDC_MODEL_INFO(0) */
-enum cpu_type
+enum cpu_type __init
parisc_get_cpu_type(unsigned long hversion)
{
struct hp_cpu_type_mask *ptr;
diff --git a/arch/parisc/kernel/hpmc.S b/arch/parisc/kernel/hpmc.S
index 8d072c44f300..781c3b9a3e46 100644
--- a/arch/parisc/kernel/hpmc.S
+++ b/arch/parisc/kernel/hpmc.S
@@ -84,6 +84,7 @@ END(hpmc_pim_data)
.text
.import intr_save, code
+ .align 16
ENTRY_CFI(os_hpmc)
.os_hpmc:
@@ -300,12 +301,15 @@ os_hpmc_6:
b .
nop
+ .align 16 /* make function length multiple of 16 bytes */
ENDPROC_CFI(os_hpmc)
.os_hpmc_end:
__INITRODATA
+.globl os_hpmc_size
.align 4
- .export os_hpmc_size
+ .type os_hpmc_size, @object
+ .size os_hpmc_size, 4
os_hpmc_size:
.word .os_hpmc_end-.os_hpmc
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index 6975a0627078..bbe46571ff96 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -138,6 +138,10 @@ void machine_power_off(void)
pdc_soft_power_button(0);
pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
+
+ /* ipmi_poweroff may have been installed. */
+ if (pm_power_off)
+ pm_power_off();
/* It seems we have no way to power the system off via
* software. The user has to press the button himself. */
@@ -151,7 +155,7 @@ void machine_power_off(void)
for (;;);
}
-void (*pm_power_off)(void) = machine_power_off;
+void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
void flush_thread(void)
diff --git a/arch/parisc/math-emu/fcnvff.c b/arch/parisc/math-emu/fcnvff.c
index 76c063f7d17c..f9357d9d4cb1 100644
--- a/arch/parisc/math-emu/fcnvff.c
+++ b/arch/parisc/math-emu/fcnvff.c
@@ -148,7 +148,7 @@ dbl_to_sgl_fcnvff(
register int src_exponent, dest_exponent, dest_mantissa;
register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
register boolean lsb_odd = FALSE;
- boolean is_tiny;
+ boolean is_tiny = FALSE;
Dbl_copyfromptr(srcptr,srcp1,srcp2);
src_exponent = Dbl_exponent(srcp1);
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index 76fe3ccfd381..f9141eaec6ff 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -355,7 +355,7 @@ vmz="$tmpdir/`basename \"$kernel\"`.$ext"
# Calculate the vmlinux.strip size
${CROSS}objcopy $objflags "$kernel" "$vmz.$$"
-strip_size=$(stat -c %s $vmz.$$)
+strip_size=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" "$vmz.$$")
if [ -z "$cacheit" -o ! -f "$vmz$compression" -o "$vmz$compression" -ot "$kernel" ]; then
# recompress the image if we need to
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 1b6bc7fba996..2358f97d62ec 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -165,7 +165,7 @@ systbl_chk: $(src)/systbl_chk.sh $(obj)/systbl_chk.i
$(call cmd,systbl_chk)
ifeq ($(CONFIG_PPC_OF_BOOT_TRAMPOLINE),y)
-$(obj)/built-in.o: prom_init_check
+$(obj)/built-in.a: prom_init_check
quiet_cmd_prom_init_check = CALL $<
cmd_prom_init_check = $(CONFIG_SHELL) $< "$(NM)" "$(obj)/prom_init.o"
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 04807c7f64cc..23d8acca5c90 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -33,6 +33,7 @@ config RISCV
select MODULES_USE_ELF_RELA if MODULES
select THREAD_INFO_IN_TASK
select RISCV_TIMER
+ select GENERIC_IRQ_MULTI_HANDLER
config MMU
def_bool y
@@ -114,6 +115,9 @@ config ARCH_RV64I
select 64BIT
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_GRAPH_TRACER
+ select HAVE_FTRACE_MCOUNT_RECORD
+ select HAVE_DYNAMIC_FTRACE
+ select HAVE_DYNAMIC_FTRACE_WITH_REGS
endchoice
@@ -131,6 +135,10 @@ choice
bool "medium any code model"
endchoice
+config MODULE_SECTIONS
+ bool
+ select HAVE_MOD_ARCH_SPECIFIC
+
choice
prompt "Maximum Physical Memory"
default MAXPHYSMEM_2GB if 32BIT
@@ -141,6 +149,7 @@ choice
bool "2GiB"
config MAXPHYSMEM_128GB
depends on 64BIT && CMODEL_MEDANY
+ select MODULE_SECTIONS if MODULES
bool "128GiB"
endchoice
@@ -281,7 +290,7 @@ config CMDLINE_BOOL
in CONFIG_CMDLINE.
The built-in options will be concatenated to the default command
- line if CMDLINE_OVERRIDE is set to 'N'. Otherwise, the default
+ line if CMDLINE_FORCE is set to 'N'. Otherwise, the default
command line will be ignored and replaced by the built-in string.
config CMDLINE
@@ -291,7 +300,7 @@ config CMDLINE
help
Supply command-line options at build time by entering them here.
-config CMDLINE_OVERRIDE
+config CMDLINE_FORCE
bool "Built-in command line overrides bootloader arguments"
depends on CMDLINE_BOOL
help
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 6719dd30ec5b..76e958a5414a 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -11,6 +11,9 @@
LDFLAGS :=
OBJCOPYFLAGS := -O binary
LDFLAGS_vmlinux :=
+ifeq ($(CONFIG_DYNAMIC_FTRACE),y)
+ LDFLAGS_vmlinux := --no-relax
+endif
KBUILD_AFLAGS_MODULE += -fPIC
KBUILD_CFLAGS_MODULE += -fPIC
@@ -56,6 +59,11 @@ endif
ifeq ($(CONFIG_CMODEL_MEDANY),y)
KBUILD_CFLAGS += -mcmodel=medany
endif
+ifeq ($(CONFIG_MODULE_SECTIONS),y)
+ KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/riscv/kernel/module.lds
+endif
+
+KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-relax)
# GCC versions that support the "-mstrict-align" option default to allowing
# unaligned accesses. While unaligned accesses are explicitly allowed in the
diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index 47dacf06c679..bca0eee733b0 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -73,3 +73,5 @@ CONFIG_NFS_V4_2=y
CONFIG_ROOT_NFS=y
# CONFIG_RCU_TRACE is not set
CONFIG_CRYPTO_USER_API_HASH=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
diff --git a/arch/riscv/include/asm/Kbuild b/arch/riscv/include/asm/Kbuild
index 4286a5f83876..1e5fd280fb4d 100644
--- a/arch/riscv/include/asm/Kbuild
+++ b/arch/riscv/include/asm/Kbuild
@@ -15,6 +15,7 @@ generic-y += fcntl.h
generic-y += futex.h
generic-y += hardirq.h
generic-y += hash.h
+generic-y += handle_irq.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ioctls.h
diff --git a/arch/riscv/include/asm/atomic.h b/arch/riscv/include/asm/atomic.h
index e65d1cd89e28..855115ace98c 100644
--- a/arch/riscv/include/asm/atomic.h
+++ b/arch/riscv/include/asm/atomic.h
@@ -24,6 +24,20 @@
#include <asm/barrier.h>
#define ATOMIC_INIT(i) { (i) }
+
+#define __atomic_op_acquire(op, args...) \
+({ \
+ typeof(op##_relaxed(args)) __ret = op##_relaxed(args); \
+ __asm__ __volatile__(RISCV_ACQUIRE_BARRIER "" ::: "memory"); \
+ __ret; \
+})
+
+#define __atomic_op_release(op, args...) \
+({ \
+ __asm__ __volatile__(RISCV_RELEASE_BARRIER "" ::: "memory"); \
+ op##_relaxed(args); \
+})
+
static __always_inline int atomic_read(const atomic_t *v)
{
return READ_ONCE(v->counter);
@@ -50,22 +64,23 @@ static __always_inline void atomic64_set(atomic64_t *v, long i)
* have the AQ or RL bits set. These don't return anything, so there's only
* one version to worry about.
*/
-#define ATOMIC_OP(op, asm_op, I, asm_type, c_type, prefix) \
-static __always_inline void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \
-{ \
- __asm__ __volatile__ ( \
- "amo" #asm_op "." #asm_type " zero, %1, %0" \
- : "+A" (v->counter) \
- : "r" (I) \
- : "memory"); \
-}
+#define ATOMIC_OP(op, asm_op, I, asm_type, c_type, prefix) \
+static __always_inline \
+void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \
+{ \
+ __asm__ __volatile__ ( \
+ " amo" #asm_op "." #asm_type " zero, %1, %0" \
+ : "+A" (v->counter) \
+ : "r" (I) \
+ : "memory"); \
+} \
#ifdef CONFIG_GENERIC_ATOMIC64
-#define ATOMIC_OPS(op, asm_op, I) \
+#define ATOMIC_OPS(op, asm_op, I) \
ATOMIC_OP (op, asm_op, I, w, int, )
#else
-#define ATOMIC_OPS(op, asm_op, I) \
- ATOMIC_OP (op, asm_op, I, w, int, ) \
+#define ATOMIC_OPS(op, asm_op, I) \
+ ATOMIC_OP (op, asm_op, I, w, int, ) \
ATOMIC_OP (op, asm_op, I, d, long, 64)
#endif
@@ -79,75 +94,115 @@ ATOMIC_OPS(xor, xor, i)
#undef ATOMIC_OPS
/*
- * Atomic ops that have ordered, relaxed, acquire, and relese variants.
+ * Atomic ops that have ordered, relaxed, acquire, and release variants.
* There's two flavors of these: the arithmatic ops have both fetch and return
* versions, while the logical ops only have fetch versions.
*/
-#define ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, asm_type, c_type, prefix) \
-static __always_inline c_type atomic##prefix##_fetch_##op##c_or(c_type i, atomic##prefix##_t *v) \
-{ \
- register c_type ret; \
- __asm__ __volatile__ ( \
- "amo" #asm_op "." #asm_type #asm_or " %1, %2, %0" \
- : "+A" (v->counter), "=r" (ret) \
- : "r" (I) \
- : "memory"); \
- return ret; \
+#define ATOMIC_FETCH_OP(op, asm_op, I, asm_type, c_type, prefix) \
+static __always_inline \
+c_type atomic##prefix##_fetch_##op##_relaxed(c_type i, \
+ atomic##prefix##_t *v) \
+{ \
+ register c_type ret; \
+ __asm__ __volatile__ ( \
+ " amo" #asm_op "." #asm_type " %1, %2, %0" \
+ : "+A" (v->counter), "=r" (ret) \
+ : "r" (I) \
+ : "memory"); \
+ return ret; \
+} \
+static __always_inline \
+c_type atomic##prefix##_fetch_##op(c_type i, atomic##prefix##_t *v) \
+{ \
+ register c_type ret; \
+ __asm__ __volatile__ ( \
+ " amo" #asm_op "." #asm_type ".aqrl %1, %2, %0" \
+ : "+A" (v->counter), "=r" (ret) \
+ : "r" (I) \
+ : "memory"); \
+ return ret; \
}
-#define ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, asm_type, c_type, prefix) \
-static __always_inline c_type atomic##prefix##_##op##_return##c_or(c_type i, atomic##prefix##_t *v) \
-{ \
- return atomic##prefix##_fetch_##op##c_or(i, v) c_op I; \
+#define ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_type, c_type, prefix) \
+static __always_inline \
+c_type atomic##prefix##_##op##_return_relaxed(c_type i, \
+ atomic##prefix##_t *v) \
+{ \
+ return atomic##prefix##_fetch_##op##_relaxed(i, v) c_op I; \
+} \
+static __always_inline \
+c_type atomic##prefix##_##op##_return(c_type i, atomic##prefix##_t *v) \
+{ \
+ return atomic##prefix##_fetch_##op(i, v) c_op I; \
}
#ifdef CONFIG_GENERIC_ATOMIC64
-#define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \
- ATOMIC_FETCH_OP (op, asm_op, I, asm_or, c_or, w, int, ) \
- ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, )
+#define ATOMIC_OPS(op, asm_op, c_op, I) \
+ ATOMIC_FETCH_OP( op, asm_op, I, w, int, ) \
+ ATOMIC_OP_RETURN(op, asm_op, c_op, I, w, int, )
#else
-#define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \
- ATOMIC_FETCH_OP (op, asm_op, I, asm_or, c_or, w, int, ) \
- ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, ) \
- ATOMIC_FETCH_OP (op, asm_op, I, asm_or, c_or, d, long, 64) \
- ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, d, long, 64)
+#define ATOMIC_OPS(op, asm_op, c_op, I) \
+ ATOMIC_FETCH_OP( op, asm_op, I, w, int, ) \
+ ATOMIC_OP_RETURN(op, asm_op, c_op, I, w, int, ) \
+ ATOMIC_FETCH_OP( op, asm_op, I, d, long, 64) \
+ ATOMIC_OP_RETURN(op, asm_op, c_op, I, d, long, 64)
#endif
-ATOMIC_OPS(add, add, +, i, , _relaxed)
-ATOMIC_OPS(add, add, +, i, .aq , _acquire)
-ATOMIC_OPS(add, add, +, i, .rl , _release)
-ATOMIC_OPS(add, add, +, i, .aqrl, )
+ATOMIC_OPS(add, add, +, i)
+ATOMIC_OPS(sub, add, +, -i)
+
+#define atomic_add_return_relaxed atomic_add_return_relaxed
+#define atomic_sub_return_relaxed atomic_sub_return_relaxed
+#define atomic_add_return atomic_add_return
+#define atomic_sub_return atomic_sub_return
-ATOMIC_OPS(sub, add, +, -i, , _relaxed)
-ATOMIC_OPS(sub, add, +, -i, .aq , _acquire)
-ATOMIC_OPS(sub, add, +, -i, .rl , _release)
-ATOMIC_OPS(sub, add, +, -i, .aqrl, )
+#define atomic_fetch_add_relaxed atomic_fetch_add_relaxed
+#define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed
+#define atomic_fetch_add atomic_fetch_add
+#define atomic_fetch_sub atomic_fetch_sub
+
+#ifndef CONFIG_GENERIC_ATOMIC64
+#define atomic64_add_return_relaxed atomic64_add_return_relaxed
+#define atomic64_sub_return_relaxed atomic64_sub_return_relaxed
+#define atomic64_add_return atomic64_add_return
+#define atomic64_sub_return atomic64_sub_return
+
+#define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed
+#define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed
+#define atomic64_fetch_add atomic64_fetch_add
+#define atomic64_fetch_sub atomic64_fetch_sub
+#endif
#undef ATOMIC_OPS
#ifdef CONFIG_GENERIC_ATOMIC64
-#define ATOMIC_OPS(op, asm_op, I, asm_or, c_or) \
- ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, w, int, )
+#define ATOMIC_OPS(op, asm_op, I) \
+ ATOMIC_FETCH_OP(op, asm_op, I, w, int, )
#else
-#define ATOMIC_OPS(op, asm_op, I, asm_or, c_or) \
- ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, w, int, ) \
- ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, d, long, 64)
+#define ATOMIC_OPS(op, asm_op, I) \
+ ATOMIC_FETCH_OP(op, asm_op, I, w, int, ) \
+ ATOMIC_FETCH_OP(op, asm_op, I, d, long, 64)
#endif
-ATOMIC_OPS(and, and, i, , _relaxed)
-ATOMIC_OPS(and, and, i, .aq , _acquire)
-ATOMIC_OPS(and, and, i, .rl , _release)
-ATOMIC_OPS(and, and, i, .aqrl, )
+ATOMIC_OPS(and, and, i)
+ATOMIC_OPS( or, or, i)
+ATOMIC_OPS(xor, xor, i)
-ATOMIC_OPS( or, or, i, , _relaxed)
-ATOMIC_OPS( or, or, i, .aq , _acquire)
-ATOMIC_OPS( or, or, i, .rl , _release)
-ATOMIC_OPS( or, or, i, .aqrl, )
+#define atomic_fetch_and_relaxed atomic_fetch_and_relaxed
+#define atomic_fetch_or_relaxed atomic_fetch_or_relaxed
+#define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed
+#define atomic_fetch_and atomic_fetch_and
+#define atomic_fetch_or atomic_fetch_or
+#define atomic_fetch_xor atomic_fetch_xor
-ATOMIC_OPS(xor, xor, i, , _relaxed)
-ATOMIC_OPS(xor, xor, i, .aq , _acquire)
-ATOMIC_OPS(xor, xor, i, .rl , _release)
-ATOMIC_OPS(xor, xor, i, .aqrl, )
+#ifndef CONFIG_GENERIC_ATOMIC64
+#define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed
+#define atomic64_fetch_or_relaxed atomic64_fetch_or_relaxed
+#define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed
+#define atomic64_fetch_and atomic64_fetch_and
+#define atomic64_fetch_or atomic64_fetch_or
+#define atomic64_fetch_xor atomic64_fetch_xor
+#endif
#undef ATOMIC_OPS
@@ -157,22 +212,24 @@ ATOMIC_OPS(xor, xor, i, .aqrl, )
/*
* The extra atomic operations that are constructed from one of the core
* AMO-based operations above (aside from sub, which is easier to fit above).
- * These are required to perform a barrier, but they're OK this way because
- * atomic_*_return is also required to perform a barrier.
+ * These are required to perform a full barrier, but they're OK this way
+ * because atomic_*_return is also required to perform a full barrier.
+ *
*/
-#define ATOMIC_OP(op, func_op, comp_op, I, c_type, prefix) \
-static __always_inline bool atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \
-{ \
- return atomic##prefix##_##func_op##_return(i, v) comp_op I; \
+#define ATOMIC_OP(op, func_op, comp_op, I, c_type, prefix) \
+static __always_inline \
+bool atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \
+{ \
+ return atomic##prefix##_##func_op##_return(i, v) comp_op I; \
}
#ifdef CONFIG_GENERIC_ATOMIC64
-#define ATOMIC_OPS(op, func_op, comp_op, I) \
- ATOMIC_OP (op, func_op, comp_op, I, int, )
+#define ATOMIC_OPS(op, func_op, comp_op, I) \
+ ATOMIC_OP(op, func_op, comp_op, I, int, )
#else
-#define ATOMIC_OPS(op, func_op, comp_op, I) \
- ATOMIC_OP (op, func_op, comp_op, I, int, ) \
- ATOMIC_OP (op, func_op, comp_op, I, long, 64)
+#define ATOMIC_OPS(op, func_op, comp_op, I) \
+ ATOMIC_OP(op, func_op, comp_op, I, int, ) \
+ ATOMIC_OP(op, func_op, comp_op, I, long, 64)
#endif
ATOMIC_OPS(add_and_test, add, ==, 0)
@@ -182,51 +239,87 @@ ATOMIC_OPS(add_negative, add, <, 0)
#undef ATOMIC_OP
#undef ATOMIC_OPS
-#define ATOMIC_OP(op, func_op, I, c_type, prefix) \
-static __always_inline void atomic##prefix##_##op(atomic##prefix##_t *v) \
-{ \
- atomic##prefix##_##func_op(I, v); \
+#define ATOMIC_OP(op, func_op, I, c_type, prefix) \
+static __always_inline \
+void atomic##prefix##_##op(atomic##prefix##_t *v) \
+{ \
+ atomic##prefix##_##func_op(I, v); \
}
-#define ATOMIC_FETCH_OP(op, func_op, I, c_type, prefix) \
-static __always_inline c_type atomic##prefix##_fetch_##op(atomic##prefix##_t *v) \
-{ \
- return atomic##prefix##_fetch_##func_op(I, v); \
+#define ATOMIC_FETCH_OP(op, func_op, I, c_type, prefix) \
+static __always_inline \
+c_type atomic##prefix##_fetch_##op##_relaxed(atomic##prefix##_t *v) \
+{ \
+ return atomic##prefix##_fetch_##func_op##_relaxed(I, v); \
+} \
+static __always_inline \
+c_type atomic##prefix##_fetch_##op(atomic##prefix##_t *v) \
+{ \
+ return atomic##prefix##_fetch_##func_op(I, v); \
}
-#define ATOMIC_OP_RETURN(op, asm_op, c_op, I, c_type, prefix) \
-static __always_inline c_type atomic##prefix##_##op##_return(atomic##prefix##_t *v) \
-{ \
- return atomic##prefix##_fetch_##op(v) c_op I; \
+#define ATOMIC_OP_RETURN(op, asm_op, c_op, I, c_type, prefix) \
+static __always_inline \
+c_type atomic##prefix##_##op##_return_relaxed(atomic##prefix##_t *v) \
+{ \
+ return atomic##prefix##_fetch_##op##_relaxed(v) c_op I; \
+} \
+static __always_inline \
+c_type atomic##prefix##_##op##_return(atomic##prefix##_t *v) \
+{ \
+ return atomic##prefix##_fetch_##op(v) c_op I; \
}
#ifdef CONFIG_GENERIC_ATOMIC64
-#define ATOMIC_OPS(op, asm_op, c_op, I) \
- ATOMIC_OP (op, asm_op, I, int, ) \
- ATOMIC_FETCH_OP (op, asm_op, I, int, ) \
+#define ATOMIC_OPS(op, asm_op, c_op, I) \
+ ATOMIC_OP( op, asm_op, I, int, ) \
+ ATOMIC_FETCH_OP( op, asm_op, I, int, ) \
ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, )
#else
-#define ATOMIC_OPS(op, asm_op, c_op, I) \
- ATOMIC_OP (op, asm_op, I, int, ) \
- ATOMIC_FETCH_OP (op, asm_op, I, int, ) \
- ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, ) \
- ATOMIC_OP (op, asm_op, I, long, 64) \
- ATOMIC_FETCH_OP (op, asm_op, I, long, 64) \
+#define ATOMIC_OPS(op, asm_op, c_op, I) \
+ ATOMIC_OP( op, asm_op, I, int, ) \
+ ATOMIC_FETCH_OP( op, asm_op, I, int, ) \
+ ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, ) \
+ ATOMIC_OP( op, asm_op, I, long, 64) \
+ ATOMIC_FETCH_OP( op, asm_op, I, long, 64) \
ATOMIC_OP_RETURN(op, asm_op, c_op, I, long, 64)
#endif
ATOMIC_OPS(inc, add, +, 1)
ATOMIC_OPS(dec, add, +, -1)
+#define atomic_inc_return_relaxed atomic_inc_return_relaxed
+#define atomic_dec_return_relaxed atomic_dec_return_relaxed
+#define atomic_inc_return atomic_inc_return
+#define atomic_dec_return atomic_dec_return
+
+#define atomic_fetch_inc_relaxed atomic_fetch_inc_relaxed
+#define atomic_fetch_dec_relaxed atomic_fetch_dec_relaxed
+#define atomic_fetch_inc atomic_fetch_inc
+#define atomic_fetch_dec atomic_fetch_dec
+
+#ifndef CONFIG_GENERIC_ATOMIC64
+#define atomic64_inc_return_relaxed atomic64_inc_return_relaxed
+#define atomic64_dec_return_relaxed atomic64_dec_return_relaxed
+#define atomic64_inc_return atomic64_inc_return
+#define atomic64_dec_return atomic64_dec_return
+
+#define atomic64_fetch_inc_relaxed atomic64_fetch_inc_relaxed
+#define atomic64_fetch_dec_relaxed atomic64_fetch_dec_relaxed
+#define atomic64_fetch_inc atomic64_fetch_inc
+#define atomic64_fetch_dec atomic64_fetch_dec
+#endif
+
#undef ATOMIC_OPS
#undef ATOMIC_OP
#undef ATOMIC_FETCH_OP
#undef ATOMIC_OP_RETURN
-#define ATOMIC_OP(op, func_op, comp_op, I, prefix) \
-static __always_inline bool atomic##prefix##_##op(atomic##prefix##_t *v) \
-{ \
- return atomic##prefix##_##func_op##_return(v) comp_op I; \
+#define ATOMIC_OP(op, func_op, comp_op, I, prefix) \
+static __always_inline \
+bool atomic##prefix##_##op(atomic##prefix##_t *v) \
+{ \
+ return atomic##prefix##_##func_op##_return(v) comp_op I; \
}
ATOMIC_OP(inc_and_test, inc, ==, 0, )
@@ -238,19 +331,19 @@ ATOMIC_OP(dec_and_test, dec, ==, 0, 64)
#undef ATOMIC_OP
-/* This is required to provide a barrier on success. */
+/* This is required to provide a full barrier on success. */
static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u)
{
int prev, rc;
__asm__ __volatile__ (
- "0:\n\t"
- "lr.w.aqrl %[p], %[c]\n\t"
- "beq %[p], %[u], 1f\n\t"
- "add %[rc], %[p], %[a]\n\t"
- "sc.w.aqrl %[rc], %[rc], %[c]\n\t"
- "bnez %[rc], 0b\n\t"
- "1:"
+ "0: lr.w %[p], %[c]\n"
+ " beq %[p], %[u], 1f\n"
+ " add %[rc], %[p], %[a]\n"
+ " sc.w.rl %[rc], %[rc], %[c]\n"
+ " bnez %[rc], 0b\n"
+ " fence rw, rw\n"
+ "1:\n"
: [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter)
: [a]"r" (a), [u]"r" (u)
: "memory");
@@ -263,13 +356,13 @@ static __always_inline long __atomic64_add_unless(atomic64_t *v, long a, long u)
long prev, rc;
__asm__ __volatile__ (
- "0:\n\t"
- "lr.d.aqrl %[p], %[c]\n\t"
- "beq %[p], %[u], 1f\n\t"
- "add %[rc], %[p], %[a]\n\t"
- "sc.d.aqrl %[rc], %[rc], %[c]\n\t"
- "bnez %[rc], 0b\n\t"
- "1:"
+ "0: lr.d %[p], %[c]\n"
+ " beq %[p], %[u], 1f\n"
+ " add %[rc], %[p], %[a]\n"
+ " sc.d.rl %[rc], %[rc], %[c]\n"
+ " bnez %[rc], 0b\n"
+ " fence rw, rw\n"
+ "1:\n"
: [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter)
: [a]"r" (a), [u]"r" (u)
: "memory");
@@ -300,37 +393,63 @@ static __always_inline long atomic64_inc_not_zero(atomic64_t *v)
/*
* atomic_{cmp,}xchg is required to have exactly the same ordering semantics as
- * {cmp,}xchg and the operations that return, so they need a barrier.
- */
-/*
- * FIXME: atomic_cmpxchg_{acquire,release,relaxed} are all implemented by
- * assigning the same barrier to both the LR and SC operations, but that might
- * not make any sense. We're waiting on a memory model specification to
- * determine exactly what the right thing to do is here.
+ * {cmp,}xchg and the operations that return, so they need a full barrier.
*/
-#define ATOMIC_OP(c_t, prefix, c_or, size, asm_or) \
-static __always_inline c_t atomic##prefix##_cmpxchg##c_or(atomic##prefix##_t *v, c_t o, c_t n) \
-{ \
- return __cmpxchg(&(v->counter), o, n, size, asm_or, asm_or); \
-} \
-static __always_inline c_t atomic##prefix##_xchg##c_or(atomic##prefix##_t *v, c_t n) \
-{ \
- return __xchg(n, &(v->counter), size, asm_or); \
+#define ATOMIC_OP(c_t, prefix, size) \
+static __always_inline \
+c_t atomic##prefix##_xchg_relaxed(atomic##prefix##_t *v, c_t n) \
+{ \
+ return __xchg_relaxed(&(v->counter), n, size); \
+} \
+static __always_inline \
+c_t atomic##prefix##_xchg_acquire(atomic##prefix##_t *v, c_t n) \
+{ \
+ return __xchg_acquire(&(v->counter), n, size); \
+} \
+static __always_inline \
+c_t atomic##prefix##_xchg_release(atomic##prefix##_t *v, c_t n) \
+{ \
+ return __xchg_release(&(v->counter), n, size); \
+} \
+static __always_inline \
+c_t atomic##prefix##_xchg(atomic##prefix##_t *v, c_t n) \
+{ \
+ return __xchg(&(v->counter), n, size); \
+} \
+static __always_inline \
+c_t atomic##prefix##_cmpxchg_relaxed(atomic##prefix##_t *v, \
+ c_t o, c_t n) \
+{ \
+ return __cmpxchg_relaxed(&(v->counter), o, n, size); \
+} \
+static __always_inline \
+c_t atomic##prefix##_cmpxchg_acquire(atomic##prefix##_t *v, \
+ c_t o, c_t n) \
+{ \
+ return __cmpxchg_acquire(&(v->counter), o, n, size); \
+} \
+static __always_inline \
+c_t atomic##prefix##_cmpxchg_release(atomic##prefix##_t *v, \
+ c_t o, c_t n) \
+{ \
+ return __cmpxchg_release(&(v->counter), o, n, size); \
+} \
+static __always_inline \
+c_t atomic##prefix##_cmpxchg(atomic##prefix##_t *v, c_t o, c_t n) \
+{ \
+ return __cmpxchg(&(v->counter), o, n, size); \
}
#ifdef CONFIG_GENERIC_ATOMIC64
-#define ATOMIC_OPS(c_or, asm_or) \
- ATOMIC_OP( int, , c_or, 4, asm_or)
+#define ATOMIC_OPS() \
+ ATOMIC_OP( int, , 4)
#else
-#define ATOMIC_OPS(c_or, asm_or) \
- ATOMIC_OP( int, , c_or, 4, asm_or) \
- ATOMIC_OP(long, 64, c_or, 8, asm_or)
+#define ATOMIC_OPS() \
+ ATOMIC_OP( int, , 4) \
+ ATOMIC_OP(long, 64, 8)
#endif
-ATOMIC_OPS( , .aqrl)
-ATOMIC_OPS(_acquire, .aq)
-ATOMIC_OPS(_release, .rl)
-ATOMIC_OPS(_relaxed, )
+ATOMIC_OPS()
#undef ATOMIC_OPS
#undef ATOMIC_OP
@@ -340,13 +459,13 @@ static __always_inline int atomic_sub_if_positive(atomic_t *v, int offset)
int prev, rc;
__asm__ __volatile__ (
- "0:\n\t"
- "lr.w.aqrl %[p], %[c]\n\t"
- "sub %[rc], %[p], %[o]\n\t"
- "bltz %[rc], 1f\n\t"
- "sc.w.aqrl %[rc], %[rc], %[c]\n\t"
- "bnez %[rc], 0b\n\t"
- "1:"
+ "0: lr.w %[p], %[c]\n"
+ " sub %[rc], %[p], %[o]\n"
+ " bltz %[rc], 1f\n"
+ " sc.w.rl %[rc], %[rc], %[c]\n"
+ " bnez %[rc], 0b\n"
+ " fence rw, rw\n"
+ "1:\n"
: [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter)
: [o]"r" (offset)
: "memory");
@@ -361,13 +480,13 @@ static __always_inline long atomic64_sub_if_positive(atomic64_t *v, int offset)
long prev, rc;
__asm__ __volatile__ (
- "0:\n\t"
- "lr.d.aqrl %[p], %[c]\n\t"
- "sub %[rc], %[p], %[o]\n\t"
- "bltz %[rc], 1f\n\t"
- "sc.d.aqrl %[rc], %[rc], %[c]\n\t"
- "bnez %[rc], 0b\n\t"
- "1:"
+ "0: lr.d %[p], %[c]\n"
+ " sub %[rc], %[p], %[o]\n"
+ " bltz %[rc], 1f\n"
+ " sc.d.rl %[rc], %[rc], %[c]\n"
+ " bnez %[rc], 0b\n"
+ " fence rw, rw\n"
+ "1:\n"
: [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter)
: [o]"r" (offset)
: "memory");
diff --git a/arch/riscv/include/asm/barrier.h b/arch/riscv/include/asm/barrier.h
index 5510366d169a..d4628e4b3a5e 100644
--- a/arch/riscv/include/asm/barrier.h
+++ b/arch/riscv/include/asm/barrier.h
@@ -38,6 +38,21 @@
#define __smp_rmb() RISCV_FENCE(r,r)
#define __smp_wmb() RISCV_FENCE(w,w)
+#define __smp_store_release(p, v) \
+do { \
+ compiletime_assert_atomic_type(*p); \
+ RISCV_FENCE(rw,w); \
+ WRITE_ONCE(*p, v); \
+} while (0)
+
+#define __smp_load_acquire(p) \
+({ \
+ typeof(*p) ___p1 = READ_ONCE(*p); \
+ compiletime_assert_atomic_type(*p); \
+ RISCV_FENCE(r,rw); \
+ ___p1; \
+})
+
/*
* This is a very specific barrier: it's currently only used in two places in
* the kernel, both in the scheduler. See include/linux/spinlock.h for the two
diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h
index db249dbc7b97..c12833f7b6bd 100644
--- a/arch/riscv/include/asm/cmpxchg.h
+++ b/arch/riscv/include/asm/cmpxchg.h
@@ -17,45 +17,153 @@
#include <linux/bug.h>
#include <asm/barrier.h>
+#include <asm/fence.h>
-#define __xchg(new, ptr, size, asm_or) \
-({ \
- __typeof__(ptr) __ptr = (ptr); \
- __typeof__(new) __new = (new); \
- __typeof__(*(ptr)) __ret; \
- switch (size) { \
- case 4: \
- __asm__ __volatile__ ( \
- "amoswap.w" #asm_or " %0, %2, %1" \
- : "=r" (__ret), "+A" (*__ptr) \
- : "r" (__new) \
- : "memory"); \
- break; \
- case 8: \
- __asm__ __volatile__ ( \
- "amoswap.d" #asm_or " %0, %2, %1" \
- : "=r" (__ret), "+A" (*__ptr) \
- : "r" (__new) \
- : "memory"); \
- break; \
- default: \
- BUILD_BUG(); \
- } \
- __ret; \
-})
-
-#define xchg(ptr, x) (__xchg((x), (ptr), sizeof(*(ptr)), .aqrl))
-
-#define xchg32(ptr, x) \
-({ \
- BUILD_BUG_ON(sizeof(*(ptr)) != 4); \
- xchg((ptr), (x)); \
-})
-
-#define xchg64(ptr, x) \
-({ \
- BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
- xchg((ptr), (x)); \
+#define __xchg_relaxed(ptr, new, size) \
+({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ __typeof__(new) __new = (new); \
+ __typeof__(*(ptr)) __ret; \
+ switch (size) { \
+ case 4: \
+ __asm__ __volatile__ ( \
+ " amoswap.w %0, %2, %1\n" \
+ : "=r" (__ret), "+A" (*__ptr) \
+ : "r" (__new) \
+ : "memory"); \
+ break; \
+ case 8: \
+ __asm__ __volatile__ ( \
+ " amoswap.d %0, %2, %1\n" \
+ : "=r" (__ret), "+A" (*__ptr) \
+ : "r" (__new) \
+ : "memory"); \
+ break; \
+ default: \
+ BUILD_BUG(); \
+ } \
+ __ret; \
+})
+
+#define xchg_relaxed(ptr, x) \
+({ \
+ __typeof__(*(ptr)) _x_ = (x); \
+ (__typeof__(*(ptr))) __xchg_relaxed((ptr), \
+ _x_, sizeof(*(ptr))); \
+})
+
+#define __xchg_acquire(ptr, new, size) \
+({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ __typeof__(new) __new = (new); \
+ __typeof__(*(ptr)) __ret; \
+ switch (size) { \
+ case 4: \
+ __asm__ __volatile__ ( \
+ " amoswap.w %0, %2, %1\n" \
+ RISCV_ACQUIRE_BARRIER \
+ : "=r" (__ret), "+A" (*__ptr) \
+ : "r" (__new) \
+ : "memory"); \
+ break; \
+ case 8: \
+ __asm__ __volatile__ ( \
+ " amoswap.d %0, %2, %1\n" \
+ RISCV_ACQUIRE_BARRIER \
+ : "=r" (__ret), "+A" (*__ptr) \
+ : "r" (__new) \
+ : "memory"); \
+ break; \
+ default: \
+ BUILD_BUG(); \
+ } \
+ __ret; \
+})
+
+#define xchg_acquire(ptr, x) \
+({ \
+ __typeof__(*(ptr)) _x_ = (x); \
+ (__typeof__(*(ptr))) __xchg_acquire((ptr), \
+ _x_, sizeof(*(ptr))); \
+})
+
+#define __xchg_release(ptr, new, size) \
+({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ __typeof__(new) __new = (new); \
+ __typeof__(*(ptr)) __ret; \
+ switch (size) { \
+ case 4: \
+ __asm__ __volatile__ ( \
+ RISCV_RELEASE_BARRIER \
+ " amoswap.w %0, %2, %1\n" \
+ : "=r" (__ret), "+A" (*__ptr) \
+ : "r" (__new) \
+ : "memory"); \
+ break; \
+ case 8: \
+ __asm__ __volatile__ ( \
+ RISCV_RELEASE_BARRIER \
+ " amoswap.d %0, %2, %1\n" \
+ : "=r" (__ret), "+A" (*__ptr) \
+ : "r" (__new) \
+ : "memory"); \
+ break; \
+ default: \
+ BUILD_BUG(); \
+ } \
+ __ret; \
+})
+
+#define xchg_release(ptr, x) \
+({ \
+ __typeof__(*(ptr)) _x_ = (x); \
+ (__typeof__(*(ptr))) __xchg_release((ptr), \
+ _x_, sizeof(*(ptr))); \
+})
+
+#define __xchg(ptr, new, size) \
+({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ __typeof__(new) __new = (new); \
+ __typeof__(*(ptr)) __ret; \
+ switch (size) { \
+ case 4: \
+ __asm__ __volatile__ ( \
+ " amoswap.w.aqrl %0, %2, %1\n" \
+ : "=r" (__ret), "+A" (*__ptr) \
+ : "r" (__new) \
+ : "memory"); \
+ break; \
+ case 8: \
+ __asm__ __volatile__ ( \
+ " amoswap.d.aqrl %0, %2, %1\n" \
+ : "=r" (__ret), "+A" (*__ptr) \
+ : "r" (__new) \
+ : "memory"); \
+ break; \
+ default: \
+ BUILD_BUG(); \
+ } \
+ __ret; \
+})
+
+#define xchg(ptr, x) \
+({ \
+ __typeof__(*(ptr)) _x_ = (x); \
+ (__typeof__(*(ptr))) __xchg((ptr), _x_, sizeof(*(ptr))); \
+})
+
+#define xchg32(ptr, x) \
+({ \
+ BUILD_BUG_ON(sizeof(*(ptr)) != 4); \
+ xchg((ptr), (x)); \
+})
+
+#define xchg64(ptr, x) \
+({ \
+ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
+ xchg((ptr), (x)); \
})
/*
@@ -63,7 +171,51 @@
* store NEW in MEM. Return the initial value in MEM. Success is
* indicated by comparing RETURN with OLD.
*/
-#define __cmpxchg(ptr, old, new, size, lrb, scb) \
+#define __cmpxchg_relaxed(ptr, old, new, size) \
+({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ __typeof__(*(ptr)) __old = (old); \
+ __typeof__(*(ptr)) __new = (new); \
+ __typeof__(*(ptr)) __ret; \
+ register unsigned int __rc; \
+ switch (size) { \
+ case 4: \
+ __asm__ __volatile__ ( \
+ "0: lr.w %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.w %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ "1:\n" \
+ : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
+ : "rJ" (__old), "rJ" (__new) \
+ : "memory"); \
+ break; \
+ case 8: \
+ __asm__ __volatile__ ( \
+ "0: lr.d %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.d %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ "1:\n" \
+ : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
+ : "rJ" (__old), "rJ" (__new) \
+ : "memory"); \
+ break; \
+ default: \
+ BUILD_BUG(); \
+ } \
+ __ret; \
+})
+
+#define cmpxchg_relaxed(ptr, o, n) \
+({ \
+ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg_relaxed((ptr), \
+ _o_, _n_, sizeof(*(ptr))); \
+})
+
+#define __cmpxchg_acquire(ptr, old, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(*(ptr)) __old = (old); \
@@ -73,24 +225,24 @@
switch (size) { \
case 4: \
__asm__ __volatile__ ( \
- "0:" \
- "lr.w" #scb " %0, %2\n" \
- "bne %0, %z3, 1f\n" \
- "sc.w" #lrb " %1, %z4, %2\n" \
- "bnez %1, 0b\n" \
- "1:" \
+ "0: lr.w %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.w %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ RISCV_ACQUIRE_BARRIER \
+ "1:\n" \
: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
: "rJ" (__old), "rJ" (__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__ ( \
- "0:" \
- "lr.d" #scb " %0, %2\n" \
- "bne %0, %z3, 1f\n" \
- "sc.d" #lrb " %1, %z4, %2\n" \
- "bnez %1, 0b\n" \
- "1:" \
+ "0: lr.d %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.d %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ RISCV_ACQUIRE_BARRIER \
+ "1:\n" \
: "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
: "rJ" (__old), "rJ" (__new) \
: "memory"); \
@@ -101,34 +253,131 @@
__ret; \
})
-#define cmpxchg(ptr, o, n) \
- (__cmpxchg((ptr), (o), (n), sizeof(*(ptr)), .aqrl, .aqrl))
+#define cmpxchg_acquire(ptr, o, n) \
+({ \
+ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg_acquire((ptr), \
+ _o_, _n_, sizeof(*(ptr))); \
+})
-#define cmpxchg_local(ptr, o, n) \
- (__cmpxchg((ptr), (o), (n), sizeof(*(ptr)), , ))
+#define __cmpxchg_release(ptr, old, new, size) \
+({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ __typeof__(*(ptr)) __old = (old); \
+ __typeof__(*(ptr)) __new = (new); \
+ __typeof__(*(ptr)) __ret; \
+ register unsigned int __rc; \
+ switch (size) { \
+ case 4: \
+ __asm__ __volatile__ ( \
+ RISCV_RELEASE_BARRIER \
+ "0: lr.w %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.w %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ "1:\n" \
+ : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
+ : "rJ" (__old), "rJ" (__new) \
+ : "memory"); \
+ break; \
+ case 8: \
+ __asm__ __volatile__ ( \
+ RISCV_RELEASE_BARRIER \
+ "0: lr.d %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.d %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ "1:\n" \
+ : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
+ : "rJ" (__old), "rJ" (__new) \
+ : "memory"); \
+ break; \
+ default: \
+ BUILD_BUG(); \
+ } \
+ __ret; \
+})
+
+#define cmpxchg_release(ptr, o, n) \
+({ \
+ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg_release((ptr), \
+ _o_, _n_, sizeof(*(ptr))); \
+})
+
+#define __cmpxchg(ptr, old, new, size) \
+({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ __typeof__(*(ptr)) __old = (old); \
+ __typeof__(*(ptr)) __new = (new); \
+ __typeof__(*(ptr)) __ret; \
+ register unsigned int __rc; \
+ switch (size) { \
+ case 4: \
+ __asm__ __volatile__ ( \
+ "0: lr.w %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.w.rl %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ " fence rw, rw\n" \
+ "1:\n" \
+ : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
+ : "rJ" (__old), "rJ" (__new) \
+ : "memory"); \
+ break; \
+ case 8: \
+ __asm__ __volatile__ ( \
+ "0: lr.d %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.d.rl %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ " fence rw, rw\n" \
+ "1:\n" \
+ : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \
+ : "rJ" (__old), "rJ" (__new) \
+ : "memory"); \
+ break; \
+ default: \
+ BUILD_BUG(); \
+ } \
+ __ret; \
+})
-#define cmpxchg32(ptr, o, n) \
-({ \
- BUILD_BUG_ON(sizeof(*(ptr)) != 4); \
- cmpxchg((ptr), (o), (n)); \
+#define cmpxchg(ptr, o, n) \
+({ \
+ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg((ptr), \
+ _o_, _n_, sizeof(*(ptr))); \
})
-#define cmpxchg32_local(ptr, o, n) \
-({ \
- BUILD_BUG_ON(sizeof(*(ptr)) != 4); \
- cmpxchg_local((ptr), (o), (n)); \
+#define cmpxchg_local(ptr, o, n) \
+ (__cmpxchg_relaxed((ptr), (o), (n), sizeof(*(ptr))))
+
+#define cmpxchg32(ptr, o, n) \
+({ \
+ BUILD_BUG_ON(sizeof(*(ptr)) != 4); \
+ cmpxchg((ptr), (o), (n)); \
})
-#define cmpxchg64(ptr, o, n) \
-({ \
- BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
- cmpxchg((ptr), (o), (n)); \
+#define cmpxchg32_local(ptr, o, n) \
+({ \
+ BUILD_BUG_ON(sizeof(*(ptr)) != 4); \
+ cmpxchg_relaxed((ptr), (o), (n)) \
})
-#define cmpxchg64_local(ptr, o, n) \
-({ \
- BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
- cmpxchg_local((ptr), (o), (n)); \
+#define cmpxchg64(ptr, o, n) \
+({ \
+ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
+ cmpxchg((ptr), (o), (n)); \
+})
+
+#define cmpxchg64_local(ptr, o, n) \
+({ \
+ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
+ cmpxchg_relaxed((ptr), (o), (n)); \
})
#endif /* _ASM_RISCV_CMPXCHG_H */
diff --git a/arch/riscv/include/asm/fence.h b/arch/riscv/include/asm/fence.h
new file mode 100644
index 000000000000..2b443a3a487f
--- /dev/null
+++ b/arch/riscv/include/asm/fence.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_RISCV_FENCE_H
+#define _ASM_RISCV_FENCE_H
+
+#ifdef CONFIG_SMP
+#define RISCV_ACQUIRE_BARRIER "\tfence r , rw\n"
+#define RISCV_RELEASE_BARRIER "\tfence rw, w\n"
+#else
+#define RISCV_ACQUIRE_BARRIER
+#define RISCV_RELEASE_BARRIER
+#endif
+
+#endif /* _ASM_RISCV_FENCE_H */
diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h
index 66d4175eb13e..c6dcc5291f97 100644
--- a/arch/riscv/include/asm/ftrace.h
+++ b/arch/riscv/include/asm/ftrace.h
@@ -8,3 +8,59 @@
#if defined(CONFIG_FUNCTION_GRAPH_TRACER) && defined(CONFIG_FRAME_POINTER)
#define HAVE_FUNCTION_GRAPH_FP_TEST
#endif
+#define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
+
+#define ARCH_SUPPORTS_FTRACE_OPS 1
+#ifndef __ASSEMBLY__
+void _mcount(void);
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+ return addr;
+}
+
+struct dyn_arch_ftrace {
+};
+#endif
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+/*
+ * A general call in RISC-V is a pair of insts:
+ * 1) auipc: setting high-20 pc-related bits to ra register
+ * 2) jalr: setting low-12 offset to ra, jump to ra, and set ra to
+ * return address (original pc + 4)
+ *
+ * Dynamic ftrace generates probes to call sites, so we must deal with
+ * both auipc and jalr at the same time.
+ */
+
+#define MCOUNT_ADDR ((unsigned long)_mcount)
+#define JALR_SIGN_MASK (0x00000800)
+#define JALR_OFFSET_MASK (0x00000fff)
+#define AUIPC_OFFSET_MASK (0xfffff000)
+#define AUIPC_PAD (0x00001000)
+#define JALR_SHIFT 20
+#define JALR_BASIC (0x000080e7)
+#define AUIPC_BASIC (0x00000097)
+#define NOP4 (0x00000013)
+
+#define make_call(caller, callee, call) \
+do { \
+ call[0] = to_auipc_insn((unsigned int)((unsigned long)callee - \
+ (unsigned long)caller)); \
+ call[1] = to_jalr_insn((unsigned int)((unsigned long)callee - \
+ (unsigned long)caller)); \
+} while (0)
+
+#define to_jalr_insn(offset) \
+ (((offset & JALR_OFFSET_MASK) << JALR_SHIFT) | JALR_BASIC)
+
+#define to_auipc_insn(offset) \
+ ((offset & JALR_SIGN_MASK) ? \
+ (((offset & AUIPC_OFFSET_MASK) + AUIPC_PAD) | AUIPC_BASIC) : \
+ ((offset & AUIPC_OFFSET_MASK) | AUIPC_BASIC))
+
+/*
+ * Let auipc+jalr be the basic *mcount unit*, so we make it 8 bytes here.
+ */
+#define MCOUNT_INSN_SIZE 8
+#endif
diff --git a/arch/riscv/include/asm/module.h b/arch/riscv/include/asm/module.h
new file mode 100644
index 000000000000..349df33808c4
--- /dev/null
+++ b/arch/riscv/include/asm/module.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2017 Andes Technology Corporation */
+
+#ifndef _ASM_RISCV_MODULE_H
+#define _ASM_RISCV_MODULE_H
+
+#include <asm-generic/module.h>
+
+#define MODULE_ARCH_VERMAGIC "riscv"
+
+u64 module_emit_got_entry(struct module *mod, u64 val);
+u64 module_emit_plt_entry(struct module *mod, u64 val);
+
+#ifdef CONFIG_MODULE_SECTIONS
+struct mod_section {
+ struct elf64_shdr *shdr;
+ int num_entries;
+ int max_entries;
+};
+
+struct mod_arch_specific {
+ struct mod_section got;
+ struct mod_section plt;
+ struct mod_section got_plt;
+};
+
+struct got_entry {
+ u64 symbol_addr; /* the real variable address */
+};
+
+static inline struct got_entry emit_got_entry(u64 val)
+{
+ return (struct got_entry) {val};
+}
+
+static inline struct got_entry *get_got_entry(u64 val,
+ const struct mod_section *sec)
+{
+ struct got_entry *got = (struct got_entry *)sec->shdr->sh_addr;
+ int i;
+ for (i = 0; i < sec->num_entries; i++) {
+ if (got[i].symbol_addr == val)
+ return &got[i];
+ }
+ return NULL;
+}
+
+struct plt_entry {
+ /*
+ * Trampoline code to real target address. The return address
+ * should be the original (pc+4) before entring plt entry.
+ */
+ u32 insn_auipc; /* auipc t0, 0x0 */
+ u32 insn_ld; /* ld t1, 0x10(t0) */
+ u32 insn_jr; /* jr t1 */
+};
+
+#define OPC_AUIPC 0x0017
+#define OPC_LD 0x3003
+#define OPC_JALR 0x0067
+#define REG_T0 0x5
+#define REG_T1 0x6
+
+static inline struct plt_entry emit_plt_entry(u64 val, u64 plt, u64 got_plt)
+{
+ /*
+ * U-Type encoding:
+ * +------------+----------+----------+
+ * | imm[31:12] | rd[11:7] | opc[6:0] |
+ * +------------+----------+----------+
+ *
+ * I-Type encoding:
+ * +------------+------------+--------+----------+----------+
+ * | imm[31:20] | rs1[19:15] | funct3 | rd[11:7] | opc[6:0] |
+ * +------------+------------+--------+----------+----------+
+ *
+ */
+ u64 offset = got_plt - plt;
+ u32 hi20 = (offset + 0x800) & 0xfffff000;
+ u32 lo12 = (offset - hi20);
+ return (struct plt_entry) {
+ OPC_AUIPC | (REG_T0 << 7) | hi20,
+ OPC_LD | (lo12 << 20) | (REG_T0 << 15) | (REG_T1 << 7),
+ OPC_JALR | (REG_T1 << 15)
+ };
+}
+
+static inline int get_got_plt_idx(u64 val, const struct mod_section *sec)
+{
+ struct got_entry *got_plt = (struct got_entry *)sec->shdr->sh_addr;
+ int i;
+ for (i = 0; i < sec->num_entries; i++) {
+ if (got_plt[i].symbol_addr == val)
+ return i;
+ }
+ return -1;
+}
+
+static inline struct plt_entry *get_plt_entry(u64 val,
+ const struct mod_section *sec_plt,
+ const struct mod_section *sec_got_plt)
+{
+ struct plt_entry *plt = (struct plt_entry *)sec_plt->shdr->sh_addr;
+ int got_plt_idx = get_got_plt_idx(val, sec_got_plt);
+ if (got_plt_idx >= 0)
+ return plt + got_plt_idx;
+ else
+ return NULL;
+}
+
+#endif /* CONFIG_MODULE_SECTIONS */
+
+#endif /* _ASM_RISCV_MODULE_H */
diff --git a/arch/riscv/include/asm/spinlock.h b/arch/riscv/include/asm/spinlock.h
index 2fd27e8ef1fd..8eb26d1ede81 100644
--- a/arch/riscv/include/asm/spinlock.h
+++ b/arch/riscv/include/asm/spinlock.h
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <asm/current.h>
+#include <asm/fence.h>
/*
* Simple spin lock operations. These provide no fairness guarantees.
@@ -28,10 +29,7 @@
static inline void arch_spin_unlock(arch_spinlock_t *lock)
{
- __asm__ __volatile__ (
- "amoswap.w.rl x0, x0, %0"
- : "=A" (lock->lock)
- :: "memory");
+ smp_store_release(&lock->lock, 0);
}
static inline int arch_spin_trylock(arch_spinlock_t *lock)
@@ -39,7 +37,8 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
int tmp = 1, busy;
__asm__ __volatile__ (
- "amoswap.w.aq %0, %2, %1"
+ " amoswap.w %0, %2, %1\n"
+ RISCV_ACQUIRE_BARRIER
: "=r" (busy), "+A" (lock->lock)
: "r" (tmp)
: "memory");
@@ -68,8 +67,9 @@ static inline void arch_read_lock(arch_rwlock_t *lock)
"1: lr.w %1, %0\n"
" bltz %1, 1b\n"
" addi %1, %1, 1\n"
- " sc.w.aq %1, %1, %0\n"
+ " sc.w %1, %1, %0\n"
" bnez %1, 1b\n"
+ RISCV_ACQUIRE_BARRIER
: "+A" (lock->lock), "=&r" (tmp)
:: "memory");
}
@@ -82,8 +82,9 @@ static inline void arch_write_lock(arch_rwlock_t *lock)
"1: lr.w %1, %0\n"
" bnez %1, 1b\n"
" li %1, -1\n"
- " sc.w.aq %1, %1, %0\n"
+ " sc.w %1, %1, %0\n"
" bnez %1, 1b\n"
+ RISCV_ACQUIRE_BARRIER
: "+A" (lock->lock), "=&r" (tmp)
:: "memory");
}
@@ -96,8 +97,9 @@ static inline int arch_read_trylock(arch_rwlock_t *lock)
"1: lr.w %1, %0\n"
" bltz %1, 1f\n"
" addi %1, %1, 1\n"
- " sc.w.aq %1, %1, %0\n"
+ " sc.w %1, %1, %0\n"
" bnez %1, 1b\n"
+ RISCV_ACQUIRE_BARRIER
"1:\n"
: "+A" (lock->lock), "=&r" (busy)
:: "memory");
@@ -113,8 +115,9 @@ static inline int arch_write_trylock(arch_rwlock_t *lock)
"1: lr.w %1, %0\n"
" bnez %1, 1f\n"
" li %1, -1\n"
- " sc.w.aq %1, %1, %0\n"
+ " sc.w %1, %1, %0\n"
" bnez %1, 1b\n"
+ RISCV_ACQUIRE_BARRIER
"1:\n"
: "+A" (lock->lock), "=&r" (busy)
:: "memory");
@@ -125,7 +128,8 @@ static inline int arch_write_trylock(arch_rwlock_t *lock)
static inline void arch_read_unlock(arch_rwlock_t *lock)
{
__asm__ __volatile__(
- "amoadd.w.rl x0, %1, %0"
+ RISCV_RELEASE_BARRIER
+ " amoadd.w x0, %1, %0\n"
: "+A" (lock->lock)
: "r" (-1)
: "memory");
@@ -133,10 +137,7 @@ static inline void arch_read_unlock(arch_rwlock_t *lock)
static inline void arch_write_unlock(arch_rwlock_t *lock)
{
- __asm__ __volatile__ (
- "amoswap.w.rl x0, x0, %0"
- : "=A" (lock->lock)
- :: "memory");
+ smp_store_release(&lock->lock, 0);
}
#endif /* _ASM_RISCV_SPINLOCK_H */
diff --git a/arch/riscv/include/uapi/asm/elf.h b/arch/riscv/include/uapi/asm/elf.h
index a510edfa8226..5cae4c30cd8e 100644
--- a/arch/riscv/include/uapi/asm/elf.h
+++ b/arch/riscv/include/uapi/asm/elf.h
@@ -79,5 +79,12 @@ typedef union __riscv_fp_state elf_fpregset_t;
#define R_RISCV_TPREL_I 49
#define R_RISCV_TPREL_S 50
#define R_RISCV_RELAX 51
+#define R_RISCV_SUB6 52
+#define R_RISCV_SET6 53
+#define R_RISCV_SET8 54
+#define R_RISCV_SET16 55
+#define R_RISCV_SET32 56
+#define R_RISCV_32_PCREL 57
+
#endif /* _UAPI_ASM_ELF_H */
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index 196f62ffc428..8586dd96c2f0 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -34,7 +34,9 @@ CFLAGS_setup.o := -mcmodel=medany
obj-$(CONFIG_SMP) += smpboot.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_MODULES) += module.o
-obj-$(CONFIG_FUNCTION_TRACER) += mcount.o
-obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
+obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o
+
+obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o
+obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o
clean:
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index 56fa592cfa34..9aaf6c986771 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -167,10 +167,9 @@ ENTRY(handle_exception)
bge s4, zero, 1f
/* Handle interrupts */
- slli a0, s4, 1
- srli a0, a0, 1
- move a1, sp /* pt_regs */
- tail do_IRQ
+ move a0, sp /* pt_regs */
+ REG_L a1, handle_arch_irq
+ jr a1
1:
/* Exceptions run with interrupts enabled */
csrs sstatus, SR_SIE
diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c
index d0de68d144cb..1157b6b52d25 100644
--- a/arch/riscv/kernel/ftrace.c
+++ b/arch/riscv/kernel/ftrace.c
@@ -6,9 +6,126 @@
*/
#include <linux/ftrace.h>
+#include <linux/uaccess.h>
+#include <asm/cacheflush.h>
+#ifdef CONFIG_DYNAMIC_FTRACE
+static int ftrace_check_current_call(unsigned long hook_pos,
+ unsigned int *expected)
+{
+ unsigned int replaced[2];
+ unsigned int nops[2] = {NOP4, NOP4};
+
+ /* we expect nops at the hook position */
+ if (!expected)
+ expected = nops;
+
+ /*
+ * Read the text we want to modify;
+ * return must be -EFAULT on read error
+ */
+ if (probe_kernel_read(replaced, (void *)hook_pos, MCOUNT_INSN_SIZE))
+ return -EFAULT;
+
+ /*
+ * Make sure it is what we expect it to be;
+ * return must be -EINVAL on failed comparison
+ */
+ if (memcmp(expected, replaced, sizeof(replaced))) {
+ pr_err("%p: expected (%08x %08x) but get (%08x %08x)",
+ (void *)hook_pos, expected[0], expected[1], replaced[0],
+ replaced[1]);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int __ftrace_modify_call(unsigned long hook_pos, unsigned long target,
+ bool enable)
+{
+ unsigned int call[2];
+ unsigned int nops[2] = {NOP4, NOP4};
+ int ret = 0;
+
+ make_call(hook_pos, target, call);
+
+ /* replace the auipc-jalr pair at once */
+ ret = probe_kernel_write((void *)hook_pos, enable ? call : nops,
+ MCOUNT_INSN_SIZE);
+ /* return must be -EPERM on write error */
+ if (ret)
+ return -EPERM;
+
+ smp_mb();
+ flush_icache_range((void *)hook_pos, (void *)hook_pos + MCOUNT_INSN_SIZE);
+
+ return 0;
+}
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+ int ret = ftrace_check_current_call(rec->ip, NULL);
+
+ if (ret)
+ return ret;
+
+ return __ftrace_modify_call(rec->ip, addr, true);
+}
+
+int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
+{
+ unsigned int call[2];
+ int ret;
+
+ make_call(rec->ip, addr, call);
+ ret = ftrace_check_current_call(rec->ip, call);
+
+ if (ret)
+ return ret;
+
+ return __ftrace_modify_call(rec->ip, addr, false);
+}
+
+int ftrace_update_ftrace_func(ftrace_func_t func)
+{
+ int ret = __ftrace_modify_call((unsigned long)&ftrace_call,
+ (unsigned long)func, true);
+ if (!ret) {
+ ret = __ftrace_modify_call((unsigned long)&ftrace_regs_call,
+ (unsigned long)func, true);
+ }
+
+ return ret;
+}
+
+int __init ftrace_dyn_arch_init(void)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
+ unsigned long addr)
+{
+ unsigned int call[2];
+ int ret;
+
+ make_call(rec->ip, old_addr, call);
+ ret = ftrace_check_current_call(rec->ip, call);
+
+ if (ret)
+ return ret;
+
+ return __ftrace_modify_call(rec->ip, addr, true);
+}
+#endif
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
/*
- * Most of this file is copied from arm64.
+ * Most of this function is copied from arm64.
*/
void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
unsigned long frame_pointer)
@@ -34,8 +151,62 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
return;
err = ftrace_push_return_trace(old, self_addr, &trace.depth,
- frame_pointer, NULL);
+ frame_pointer, parent);
if (err == -EBUSY)
return;
*parent = return_hooker;
}
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+extern void ftrace_graph_call(void);
+int ftrace_enable_ftrace_graph_caller(void)
+{
+ unsigned int call[2];
+ static int init_graph = 1;
+ int ret;
+
+ make_call(&ftrace_graph_call, &ftrace_stub, call);
+
+ /*
+ * When enabling graph tracer for the first time, ftrace_graph_call
+ * should contains a call to ftrace_stub. Once it has been disabled,
+ * the 8-bytes at the position becomes NOPs.
+ */
+ if (init_graph) {
+ ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call,
+ call);
+ init_graph = 0;
+ } else {
+ ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call,
+ NULL);
+ }
+
+ if (ret)
+ return ret;
+
+ return __ftrace_modify_call((unsigned long)&ftrace_graph_call,
+ (unsigned long)&prepare_ftrace_return, true);
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+ unsigned int call[2];
+ int ret;
+
+ make_call(&ftrace_graph_call, &prepare_ftrace_return, call);
+
+ /*
+ * This is to make sure that ftrace_enable_ftrace_graph_caller
+ * did the right thing.
+ */
+ ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call,
+ call);
+
+ if (ret)
+ return ret;
+
+ return __ftrace_modify_call((unsigned long)&ftrace_graph_call,
+ (unsigned long)&prepare_ftrace_return, false);
+}
+#endif /* CONFIG_DYNAMIC_FTRACE */
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
diff --git a/arch/riscv/kernel/irq.c b/arch/riscv/kernel/irq.c
index 328718e8026e..b74cbfbce2d0 100644
--- a/arch/riscv/kernel/irq.c
+++ b/arch/riscv/kernel/irq.c
@@ -24,16 +24,3 @@ void __init init_IRQ(void)
{
irqchip_init();
}
-
-asmlinkage void __irq_entry do_IRQ(unsigned int cause, struct pt_regs *regs)
-{
-#ifdef CONFIG_RISCV_INTC
- /*
- * FIXME: We don't want a direct call to riscv_intc_irq here. The plan
- * is to put an IRQ domain here and let the interrupt controller
- * register with that, but I poked around the arm64 code a bit and
- * there might be a better way to do it (ie, something fully generic).
- */
- riscv_intc_irq(cause, regs);
-#endif
-}
diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S
new file mode 100644
index 000000000000..35a6ed76cb8b
--- /dev/null
+++ b/arch/riscv/kernel/mcount-dyn.S
@@ -0,0 +1,239 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2017 Andes Technology Corporation */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <asm/asm.h>
+#include <asm/csr.h>
+#include <asm/unistd.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+#include <asm-generic/export.h>
+#include <asm/ftrace.h>
+
+ .text
+
+ .macro SAVE_ABI_STATE
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ addi sp, sp, -48
+ sd s0, 32(sp)
+ sd ra, 40(sp)
+ addi s0, sp, 48
+ sd t0, 24(sp)
+ sd t1, 16(sp)
+#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
+ sd t2, 8(sp)
+#endif
+#else
+ addi sp, sp, -16
+ sd s0, 0(sp)
+ sd ra, 8(sp)
+ addi s0, sp, 16
+#endif
+ .endm
+
+ .macro RESTORE_ABI_STATE
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ ld s0, 32(sp)
+ ld ra, 40(sp)
+ addi sp, sp, 48
+#else
+ ld ra, 8(sp)
+ ld s0, 0(sp)
+ addi sp, sp, 16
+#endif
+ .endm
+
+ .macro RESTORE_GRAPH_ARGS
+ ld a0, 24(sp)
+ ld a1, 16(sp)
+#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
+ ld a2, 8(sp)
+#endif
+ .endm
+
+ENTRY(ftrace_graph_caller)
+ addi sp, sp, -16
+ sd s0, 0(sp)
+ sd ra, 8(sp)
+ addi s0, sp, 16
+ftrace_graph_call:
+ .global ftrace_graph_call
+ /*
+ * Calling ftrace_enable/disable_ftrace_graph_caller would overwrite the
+ * call below. Check ftrace_modify_all_code for details.
+ */
+ call ftrace_stub
+ ld ra, 8(sp)
+ ld s0, 0(sp)
+ addi sp, sp, 16
+ ret
+ENDPROC(ftrace_graph_caller)
+
+ENTRY(ftrace_caller)
+ /*
+ * a0: the address in the caller when calling ftrace_caller
+ * a1: the caller's return address
+ * a2: the address of global variable function_trace_op
+ */
+ ld a1, -8(s0)
+ addi a0, ra, -MCOUNT_INSN_SIZE
+ la t5, function_trace_op
+ ld a2, 0(t5)
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ /*
+ * the graph tracer (specifically, prepare_ftrace_return) needs these
+ * arguments but for now the function tracer occupies the regs, so we
+ * save them in temporary regs to recover later.
+ */
+ addi t0, s0, -8
+ mv t1, a0
+#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
+ ld t2, -16(s0)
+#endif
+#endif
+
+ SAVE_ABI_STATE
+ftrace_call:
+ .global ftrace_call
+ /*
+ * For the dynamic ftrace to work, here we should reserve at least
+ * 8 bytes for a functional auipc-jalr pair. The following call
+ * serves this purpose.
+ *
+ * Calling ftrace_update_ftrace_func would overwrite the nops below.
+ * Check ftrace_modify_all_code for details.
+ */
+ call ftrace_stub
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ RESTORE_GRAPH_ARGS
+ call ftrace_graph_caller
+#endif
+
+ RESTORE_ABI_STATE
+ ret
+ENDPROC(ftrace_caller)
+
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+ .macro SAVE_ALL
+ addi sp, sp, -(PT_SIZE_ON_STACK+16)
+ sd s0, (PT_SIZE_ON_STACK)(sp)
+ sd ra, (PT_SIZE_ON_STACK+8)(sp)
+ addi s0, sp, (PT_SIZE_ON_STACK+16)
+
+ sd x1, PT_RA(sp)
+ sd x2, PT_SP(sp)
+ sd x3, PT_GP(sp)
+ sd x4, PT_TP(sp)
+ sd x5, PT_T0(sp)
+ sd x6, PT_T1(sp)
+ sd x7, PT_T2(sp)
+ sd x8, PT_S0(sp)
+ sd x9, PT_S1(sp)
+ sd x10, PT_A0(sp)
+ sd x11, PT_A1(sp)
+ sd x12, PT_A2(sp)
+ sd x13, PT_A3(sp)
+ sd x14, PT_A4(sp)
+ sd x15, PT_A5(sp)
+ sd x16, PT_A6(sp)
+ sd x17, PT_A7(sp)
+ sd x18, PT_S2(sp)
+ sd x19, PT_S3(sp)
+ sd x20, PT_S4(sp)
+ sd x21, PT_S5(sp)
+ sd x22, PT_S6(sp)
+ sd x23, PT_S7(sp)
+ sd x24, PT_S8(sp)
+ sd x25, PT_S9(sp)
+ sd x26, PT_S10(sp)
+ sd x27, PT_S11(sp)
+ sd x28, PT_T3(sp)
+ sd x29, PT_T4(sp)
+ sd x30, PT_T5(sp)
+ sd x31, PT_T6(sp)
+ .endm
+
+ .macro RESTORE_ALL
+ ld x1, PT_RA(sp)
+ ld x2, PT_SP(sp)
+ ld x3, PT_GP(sp)
+ ld x4, PT_TP(sp)
+ ld x5, PT_T0(sp)
+ ld x6, PT_T1(sp)
+ ld x7, PT_T2(sp)
+ ld x8, PT_S0(sp)
+ ld x9, PT_S1(sp)
+ ld x10, PT_A0(sp)
+ ld x11, PT_A1(sp)
+ ld x12, PT_A2(sp)
+ ld x13, PT_A3(sp)
+ ld x14, PT_A4(sp)
+ ld x15, PT_A5(sp)
+ ld x16, PT_A6(sp)
+ ld x17, PT_A7(sp)
+ ld x18, PT_S2(sp)
+ ld x19, PT_S3(sp)
+ ld x20, PT_S4(sp)
+ ld x21, PT_S5(sp)
+ ld x22, PT_S6(sp)
+ ld x23, PT_S7(sp)
+ ld x24, PT_S8(sp)
+ ld x25, PT_S9(sp)
+ ld x26, PT_S10(sp)
+ ld x27, PT_S11(sp)
+ ld x28, PT_T3(sp)
+ ld x29, PT_T4(sp)
+ ld x30, PT_T5(sp)
+ ld x31, PT_T6(sp)
+
+ ld s0, (PT_SIZE_ON_STACK)(sp)
+ ld ra, (PT_SIZE_ON_STACK+8)(sp)
+ addi sp, sp, (PT_SIZE_ON_STACK+16)
+ .endm
+
+ .macro RESTORE_GRAPH_REG_ARGS
+ ld a0, PT_T0(sp)
+ ld a1, PT_T1(sp)
+#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
+ ld a2, PT_T2(sp)
+#endif
+ .endm
+
+/*
+ * Most of the contents are the same as ftrace_caller.
+ */
+ENTRY(ftrace_regs_caller)
+ /*
+ * a3: the address of all registers in the stack
+ */
+ ld a1, -8(s0)
+ addi a0, ra, -MCOUNT_INSN_SIZE
+ la t5, function_trace_op
+ ld a2, 0(t5)
+ addi a3, sp, -(PT_SIZE_ON_STACK+16)
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ addi t0, s0, -8
+ mv t1, a0
+#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
+ ld t2, -16(s0)
+#endif
+#endif
+ SAVE_ALL
+
+ftrace_regs_call:
+ .global ftrace_regs_call
+ call ftrace_stub
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ RESTORE_GRAPH_REG_ARGS
+ call ftrace_graph_caller
+#endif
+
+ RESTORE_ALL
+ ret
+ENDPROC(ftrace_regs_caller)
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
diff --git a/arch/riscv/kernel/mcount.S b/arch/riscv/kernel/mcount.S
index c46a778627be..ce9bdc57a2a1 100644
--- a/arch/riscv/kernel/mcount.S
+++ b/arch/riscv/kernel/mcount.S
@@ -32,13 +32,13 @@
addi s0, sp, 32
.endm
- .macro STORE_ABI_STATE
+ .macro RESTORE_ABI_STATE
ld ra, 8(sp)
ld s0, 0(sp)
addi sp, sp, 16
.endm
- .macro STORE_RET_ABI_STATE
+ .macro RESTORE_RET_ABI_STATE
ld ra, 24(sp)
ld s0, 16(sp)
ld a0, 8(sp)
@@ -46,6 +46,10 @@
.endm
ENTRY(ftrace_stub)
+#ifdef CONFIG_DYNAMIC_FTRACE
+ .global _mcount
+ .set _mcount, ftrace_stub
+#endif
ret
ENDPROC(ftrace_stub)
@@ -66,15 +70,15 @@ ENTRY(return_to_handler)
#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
mv a0, t6
#endif
- la t0, ftrace_return_to_handler
- jalr t0
+ call ftrace_return_to_handler
mv a1, a0
- STORE_RET_ABI_STATE
+ RESTORE_RET_ABI_STATE
jalr a1
ENDPROC(return_to_handler)
EXPORT_SYMBOL(return_to_handler)
#endif
+#ifndef CONFIG_DYNAMIC_FTRACE
ENTRY(_mcount)
la t4, ftrace_stub
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
@@ -104,9 +108,8 @@ do_ftrace_graph_caller:
ld a2, -16(s0)
#endif
SAVE_ABI_STATE
- la t0, prepare_ftrace_return
- jalr t0
- STORE_ABI_STATE
+ call prepare_ftrace_return
+ RESTORE_ABI_STATE
ret
#endif
@@ -120,7 +123,8 @@ do_trace:
SAVE_ABI_STATE
jalr t5
- STORE_ABI_STATE
+ RESTORE_ABI_STATE
ret
ENDPROC(_mcount)
EXPORT_SYMBOL(_mcount)
+#endif
diff --git a/arch/riscv/kernel/module-sections.c b/arch/riscv/kernel/module-sections.c
new file mode 100644
index 000000000000..bbbd26e19bfd
--- /dev/null
+++ b/arch/riscv/kernel/module-sections.c
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2014-2017 Linaro Ltd. <ard.biesheuvel@linaro.org>
+ *
+ * Copyright (C) 2018 Andes Technology Corporation <zong@andestech.com>
+ */
+
+#include <linux/elf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+u64 module_emit_got_entry(struct module *mod, u64 val)
+{
+ struct mod_section *got_sec = &mod->arch.got;
+ int i = got_sec->num_entries;
+ struct got_entry *got = get_got_entry(val, got_sec);
+
+ if (got)
+ return (u64)got;
+
+ /* There is no duplicate entry, create a new one */
+ got = (struct got_entry *)got_sec->shdr->sh_addr;
+ got[i] = emit_got_entry(val);
+
+ got_sec->num_entries++;
+ BUG_ON(got_sec->num_entries > got_sec->max_entries);
+
+ return (u64)&got[i];
+}
+
+u64 module_emit_plt_entry(struct module *mod, u64 val)
+{
+ struct mod_section *got_plt_sec = &mod->arch.got_plt;
+ struct got_entry *got_plt;
+ struct mod_section *plt_sec = &mod->arch.plt;
+ struct plt_entry *plt = get_plt_entry(val, plt_sec, got_plt_sec);
+ int i = plt_sec->num_entries;
+
+ if (plt)
+ return (u64)plt;
+
+ /* There is no duplicate entry, create a new one */
+ got_plt = (struct got_entry *)got_plt_sec->shdr->sh_addr;
+ got_plt[i] = emit_got_entry(val);
+ plt = (struct plt_entry *)plt_sec->shdr->sh_addr;
+ plt[i] = emit_plt_entry(val, (u64)&plt[i], (u64)&got_plt[i]);
+
+ plt_sec->num_entries++;
+ got_plt_sec->num_entries++;
+ BUG_ON(plt_sec->num_entries > plt_sec->max_entries);
+
+ return (u64)&plt[i];
+}
+
+static int is_rela_equal(const Elf64_Rela *x, const Elf64_Rela *y)
+{
+ return x->r_info == y->r_info && x->r_addend == y->r_addend;
+}
+
+static bool duplicate_rela(const Elf64_Rela *rela, int idx)
+{
+ int i;
+ for (i = 0; i < idx; i++) {
+ if (is_rela_equal(&rela[i], &rela[idx]))
+ return true;
+ }
+ return false;
+}
+
+static void count_max_entries(Elf64_Rela *relas, int num,
+ unsigned int *plts, unsigned int *gots)
+{
+ unsigned int type, i;
+
+ for (i = 0; i < num; i++) {
+ type = ELF64_R_TYPE(relas[i].r_info);
+ if (type == R_RISCV_CALL_PLT) {
+ if (!duplicate_rela(relas, i))
+ (*plts)++;
+ } else if (type == R_RISCV_GOT_HI20) {
+ if (!duplicate_rela(relas, i))
+ (*gots)++;
+ }
+ }
+}
+
+int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
+ char *secstrings, struct module *mod)
+{
+ unsigned int num_plts = 0;
+ unsigned int num_gots = 0;
+ int i;
+
+ /*
+ * Find the empty .got and .plt sections.
+ */
+ for (i = 0; i < ehdr->e_shnum; i++) {
+ if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt"))
+ mod->arch.plt.shdr = sechdrs + i;
+ else if (!strcmp(secstrings + sechdrs[i].sh_name, ".got"))
+ mod->arch.got.shdr = sechdrs + i;
+ else if (!strcmp(secstrings + sechdrs[i].sh_name, ".got.plt"))
+ mod->arch.got_plt.shdr = sechdrs + i;
+ }
+
+ if (!mod->arch.plt.shdr) {
+ pr_err("%s: module PLT section(s) missing\n", mod->name);
+ return -ENOEXEC;
+ }
+ if (!mod->arch.got.shdr) {
+ pr_err("%s: module GOT section(s) missing\n", mod->name);
+ return -ENOEXEC;
+ }
+ if (!mod->arch.got_plt.shdr) {
+ pr_err("%s: module GOT.PLT section(s) missing\n", mod->name);
+ return -ENOEXEC;
+ }
+
+ /* Calculate the maxinum number of entries */
+ for (i = 0; i < ehdr->e_shnum; i++) {
+ Elf64_Rela *relas = (void *)ehdr + sechdrs[i].sh_offset;
+ int num_rela = sechdrs[i].sh_size / sizeof(Elf64_Rela);
+ Elf64_Shdr *dst_sec = sechdrs + sechdrs[i].sh_info;
+
+ if (sechdrs[i].sh_type != SHT_RELA)
+ continue;
+
+ /* ignore relocations that operate on non-exec sections */
+ if (!(dst_sec->sh_flags & SHF_EXECINSTR))
+ continue;
+
+ count_max_entries(relas, num_rela, &num_plts, &num_gots);
+ }
+
+ mod->arch.plt.shdr->sh_type = SHT_NOBITS;
+ mod->arch.plt.shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+ mod->arch.plt.shdr->sh_addralign = L1_CACHE_BYTES;
+ mod->arch.plt.shdr->sh_size = (num_plts + 1) * sizeof(struct plt_entry);
+ mod->arch.plt.num_entries = 0;
+ mod->arch.plt.max_entries = num_plts;
+
+ mod->arch.got.shdr->sh_type = SHT_NOBITS;
+ mod->arch.got.shdr->sh_flags = SHF_ALLOC;
+ mod->arch.got.shdr->sh_addralign = L1_CACHE_BYTES;
+ mod->arch.got.shdr->sh_size = (num_gots + 1) * sizeof(struct got_entry);
+ mod->arch.got.num_entries = 0;
+ mod->arch.got.max_entries = num_gots;
+
+ mod->arch.got_plt.shdr->sh_type = SHT_NOBITS;
+ mod->arch.got_plt.shdr->sh_flags = SHF_ALLOC;
+ mod->arch.got_plt.shdr->sh_addralign = L1_CACHE_BYTES;
+ mod->arch.got_plt.shdr->sh_size = (num_plts + 1) * sizeof(struct got_entry);
+ mod->arch.got_plt.num_entries = 0;
+ mod->arch.got_plt.max_entries = num_plts;
+ return 0;
+}
diff --git a/arch/riscv/kernel/module.c b/arch/riscv/kernel/module.c
index e0f05034fc21..5dddba301d0a 100644
--- a/arch/riscv/kernel/module.c
+++ b/arch/riscv/kernel/module.c
@@ -49,6 +49,39 @@ static int apply_r_riscv_jal_rela(struct module *me, u32 *location,
return 0;
}
+static int apply_r_riscv_rcv_branch_rela(struct module *me, u32 *location,
+ Elf_Addr v)
+{
+ s64 offset = (void *)v - (void *)location;
+ u16 imm8 = (offset & 0x100) << (12 - 8);
+ u16 imm7_6 = (offset & 0xc0) >> (6 - 5);
+ u16 imm5 = (offset & 0x20) >> (5 - 2);
+ u16 imm4_3 = (offset & 0x18) << (12 - 5);
+ u16 imm2_1 = (offset & 0x6) << (12 - 10);
+
+ *(u16 *)location = (*(u16 *)location & 0xe383) |
+ imm8 | imm7_6 | imm5 | imm4_3 | imm2_1;
+ return 0;
+}
+
+static int apply_r_riscv_rvc_jump_rela(struct module *me, u32 *location,
+ Elf_Addr v)
+{
+ s64 offset = (void *)v - (void *)location;
+ u16 imm11 = (offset & 0x800) << (12 - 11);
+ u16 imm10 = (offset & 0x400) >> (10 - 8);
+ u16 imm9_8 = (offset & 0x300) << (12 - 11);
+ u16 imm7 = (offset & 0x80) >> (7 - 6);
+ u16 imm6 = (offset & 0x40) << (12 - 11);
+ u16 imm5 = (offset & 0x20) >> (5 - 2);
+ u16 imm4 = (offset & 0x10) << (12 - 5);
+ u16 imm3_1 = (offset & 0xe) << (12 - 10);
+
+ *(u16 *)location = (*(u16 *)location & 0xe003) |
+ imm11 | imm10 | imm9_8 | imm7 | imm6 | imm5 | imm4 | imm3_1;
+ return 0;
+}
+
static int apply_r_riscv_pcrel_hi20_rela(struct module *me, u32 *location,
Elf_Addr v)
{
@@ -92,6 +125,67 @@ static int apply_r_riscv_pcrel_lo12_s_rela(struct module *me, u32 *location,
return 0;
}
+static int apply_r_riscv_hi20_rela(struct module *me, u32 *location,
+ Elf_Addr v)
+{
+ s32 hi20;
+
+ if (IS_ENABLED(CMODEL_MEDLOW)) {
+ pr_err(
+ "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
+ me->name, v, location);
+ return -EINVAL;
+ }
+
+ hi20 = ((s32)v + 0x800) & 0xfffff000;
+ *location = (*location & 0xfff) | hi20;
+ return 0;
+}
+
+static int apply_r_riscv_lo12_i_rela(struct module *me, u32 *location,
+ Elf_Addr v)
+{
+ /* Skip medlow checking because of filtering by HI20 already */
+ s32 hi20 = ((s32)v + 0x800) & 0xfffff000;
+ s32 lo12 = ((s32)v - hi20);
+ *location = (*location & 0xfffff) | ((lo12 & 0xfff) << 20);
+ return 0;
+}
+
+static int apply_r_riscv_lo12_s_rela(struct module *me, u32 *location,
+ Elf_Addr v)
+{
+ /* Skip medlow checking because of filtering by HI20 already */
+ s32 hi20 = ((s32)v + 0x800) & 0xfffff000;
+ s32 lo12 = ((s32)v - hi20);
+ u32 imm11_5 = (lo12 & 0xfe0) << (31 - 11);
+ u32 imm4_0 = (lo12 & 0x1f) << (11 - 4);
+ *location = (*location & 0x1fff07f) | imm11_5 | imm4_0;
+ return 0;
+}
+
+static int apply_r_riscv_got_hi20_rela(struct module *me, u32 *location,
+ Elf_Addr v)
+{
+ s64 offset = (void *)v - (void *)location;
+ s32 hi20;
+
+ /* Always emit the got entry */
+ if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) {
+ offset = module_emit_got_entry(me, v);
+ offset = (void *)offset - (void *)location;
+ } else {
+ pr_err(
+ "%s: can not generate the GOT entry for symbol = %016llx from PC = %p\n",
+ me->name, v, location);
+ return -EINVAL;
+ }
+
+ hi20 = (offset + 0x800) & 0xfffff000;
+ *location = (*location & 0xfff) | hi20;
+ return 0;
+}
+
static int apply_r_riscv_call_plt_rela(struct module *me, u32 *location,
Elf_Addr v)
{
@@ -100,6 +194,33 @@ static int apply_r_riscv_call_plt_rela(struct module *me, u32 *location,
u32 hi20, lo12;
if (offset != fill_v) {
+ /* Only emit the plt entry if offset over 32-bit range */
+ if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) {
+ offset = module_emit_plt_entry(me, v);
+ offset = (void *)offset - (void *)location;
+ } else {
+ pr_err(
+ "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
+ me->name, v, location);
+ return -EINVAL;
+ }
+ }
+
+ hi20 = (offset + 0x800) & 0xfffff000;
+ lo12 = (offset - hi20) & 0xfff;
+ *location = (*location & 0xfff) | hi20;
+ *(location + 1) = (*(location + 1) & 0xfffff) | (lo12 << 20);
+ return 0;
+}
+
+static int apply_r_riscv_call_rela(struct module *me, u32 *location,
+ Elf_Addr v)
+{
+ s64 offset = (void *)v - (void *)location;
+ s32 fill_v = offset;
+ u32 hi20, lo12;
+
+ if (offset != fill_v) {
pr_err(
"%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
me->name, v, location);
@@ -119,16 +240,49 @@ static int apply_r_riscv_relax_rela(struct module *me, u32 *location,
return 0;
}
+static int apply_r_riscv_align_rela(struct module *me, u32 *location,
+ Elf_Addr v)
+{
+ pr_err(
+ "%s: The unexpected relocation type 'R_RISCV_ALIGN' from PC = %p\n",
+ me->name, location);
+ return -EINVAL;
+}
+
+static int apply_r_riscv_add32_rela(struct module *me, u32 *location,
+ Elf_Addr v)
+{
+ *(u32 *)location += (*(u32 *)v);
+ return 0;
+}
+
+static int apply_r_riscv_sub32_rela(struct module *me, u32 *location,
+ Elf_Addr v)
+{
+ *(u32 *)location -= (*(u32 *)v);
+ return 0;
+}
+
static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
Elf_Addr v) = {
[R_RISCV_64] = apply_r_riscv_64_rela,
[R_RISCV_BRANCH] = apply_r_riscv_branch_rela,
[R_RISCV_JAL] = apply_r_riscv_jal_rela,
+ [R_RISCV_RVC_BRANCH] = apply_r_riscv_rcv_branch_rela,
+ [R_RISCV_RVC_JUMP] = apply_r_riscv_rvc_jump_rela,
[R_RISCV_PCREL_HI20] = apply_r_riscv_pcrel_hi20_rela,
[R_RISCV_PCREL_LO12_I] = apply_r_riscv_pcrel_lo12_i_rela,
[R_RISCV_PCREL_LO12_S] = apply_r_riscv_pcrel_lo12_s_rela,
+ [R_RISCV_HI20] = apply_r_riscv_hi20_rela,
+ [R_RISCV_LO12_I] = apply_r_riscv_lo12_i_rela,
+ [R_RISCV_LO12_S] = apply_r_riscv_lo12_s_rela,
+ [R_RISCV_GOT_HI20] = apply_r_riscv_got_hi20_rela,
[R_RISCV_CALL_PLT] = apply_r_riscv_call_plt_rela,
+ [R_RISCV_CALL] = apply_r_riscv_call_rela,
[R_RISCV_RELAX] = apply_r_riscv_relax_rela,
+ [R_RISCV_ALIGN] = apply_r_riscv_align_rela,
+ [R_RISCV_ADD32] = apply_r_riscv_add32_rela,
+ [R_RISCV_SUB32] = apply_r_riscv_sub32_rela,
};
int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
@@ -184,25 +338,38 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
u64 hi20_loc =
sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rel[j].r_offset;
- /* Find the corresponding HI20 PC-relative relocation entry */
- if (hi20_loc == sym->st_value) {
+ u32 hi20_type = ELF_RISCV_R_TYPE(rel[j].r_info);
+
+ /* Find the corresponding HI20 relocation entry */
+ if (hi20_loc == sym->st_value
+ && (hi20_type == R_RISCV_PCREL_HI20
+ || hi20_type == R_RISCV_GOT_HI20)) {
+ s32 hi20, lo12;
Elf_Sym *hi20_sym =
(Elf_Sym *)sechdrs[symindex].sh_addr
+ ELF_RISCV_R_SYM(rel[j].r_info);
u64 hi20_sym_val =
hi20_sym->st_value
+ rel[j].r_addend;
+
/* Calculate lo12 */
- s64 offset = hi20_sym_val - hi20_loc;
- s32 hi20 = (offset + 0x800) & 0xfffff000;
- s32 lo12 = offset - hi20;
+ u64 offset = hi20_sym_val - hi20_loc;
+ if (IS_ENABLED(CONFIG_MODULE_SECTIONS)
+ && hi20_type == R_RISCV_GOT_HI20) {
+ offset = module_emit_got_entry(
+ me, hi20_sym_val);
+ offset = offset - hi20_loc;
+ }
+ hi20 = (offset + 0x800) & 0xfffff000;
+ lo12 = offset - hi20;
v = lo12;
+
break;
}
}
if (j == sechdrs[relsec].sh_size / sizeof(*rel)) {
pr_err(
- "%s: Can not find HI20 PC-relative relocation information\n",
+ "%s: Can not find HI20 relocation information\n",
me->name);
return -EINVAL;
}
diff --git a/arch/riscv/kernel/module.lds b/arch/riscv/kernel/module.lds
new file mode 100644
index 000000000000..295ecfb341a2
--- /dev/null
+++ b/arch/riscv/kernel/module.lds
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2017 Andes Technology Corporation */
+
+SECTIONS {
+ .plt (NOLOAD) : { BYTE(0) }
+ .got (NOLOAD) : { BYTE(0) }
+ .got.plt (NOLOAD) : { BYTE(0) }
+}
diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c
index 559aae781154..a4b1d94371a0 100644
--- a/arch/riscv/kernel/stacktrace.c
+++ b/arch/riscv/kernel/stacktrace.c
@@ -18,6 +18,7 @@
#include <linux/sched/debug.h>
#include <linux/sched/task_stack.h>
#include <linux/stacktrace.h>
+#include <linux/ftrace.h>
#ifdef CONFIG_FRAME_POINTER
@@ -63,7 +64,12 @@ static void notrace walk_stackframe(struct task_struct *task,
frame = (struct stackframe *)fp - 1;
sp = fp;
fp = frame->fp;
+#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
+ pc = ftrace_graph_ret_addr(current, NULL, frame->ra,
+ (unsigned long *)(fp - 8));
+#else
pc = frame->ra - 0x4;
+#endif
}
}
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 6f929abe0b50..adc61d14172c 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -7,44 +7,47 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
-
-#include <linux/init.h>
+#include <asm/clock.h>
+#include <asm/heartbeat.h>
+#include <asm/suspend.h>
+#include <cpu/sh7724.h>
+#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/input/sh_keysc.h>
+#include <linux/interrupt.h>
+#include <linux/memblock.h>
+#include <linux/mfd/tmio.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sh_mmcif.h>
#include <linux/mtd/physmap.h>
-#include <linux/mfd/tmio.h>
#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/delay.h>
+#include <linux/gpio/machine.h>
+#include <linux/platform_data/gpio_backlight.h>
+#include <linux/platform_data/tsc2007.h>
+#include <linux/platform_device.h>
#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>
-#include <linux/usb/r8a66597.h>
-#include <linux/usb/renesas_usbhs.h>
-#include <linux/i2c.h>
-#include <linux/platform_data/tsc2007.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/sh_msiof.h>
-#include <linux/spi/mmc_spi.h>
-#include <linux/input.h>
-#include <linux/input/sh_keysc.h>
-#include <linux/platform_data/gpio_backlight.h>
#include <linux/sh_eth.h>
#include <linux/sh_intc.h>
+#include <linux/spi/mmc_spi.h>
+#include <linux/spi/sh_msiof.h>
+#include <linux/spi/spi.h>
+#include <linux/usb/r8a66597.h>
+#include <linux/usb/renesas_usbhs.h>
#include <linux/videodev2.h>
-#include <video/sh_mobile_lcdc.h>
+
+#include <media/drv-intf/renesas-ceu.h>
+#include <media/i2c/mt9t112.h>
+#include <media/i2c/tw9910.h>
+
#include <sound/sh_fsi.h>
#include <sound/simple_card.h>
-#include <media/drv-intf/sh_mobile_ceu.h>
-#include <media/soc_camera.h>
-#include <media/i2c/tw9910.h>
-#include <media/i2c/mt9t112.h>
-#include <asm/heartbeat.h>
-#include <asm/clock.h>
-#include <asm/suspend.h>
-#include <cpu/sh7724.h>
+
+#include <video/sh_mobile_lcdc.h>
/*
* Address Interface BusWidth
@@ -81,6 +84,10 @@
* amixer set 'Out Mixer Right DAC Right' on
*/
+#define CEU_BUFFER_MEMORY_SIZE (4 << 20)
+static phys_addr_t ceu0_dma_membase;
+static phys_addr_t ceu1_dma_membase;
+
/* Heartbeat */
static unsigned char led_pos[] = { 0, 1, 2, 3 };
@@ -382,8 +389,24 @@ static struct platform_device gpio_backlight_device = {
};
/* CEU0 */
-static struct sh_mobile_ceu_info sh_mobile_ceu0_info = {
- .flags = SH_CEU_FLAG_USE_8BIT_BUS,
+static struct ceu_platform_data ceu0_pdata = {
+ .num_subdevs = 2,
+ .subdevs = {
+ { /* [0] = mt9t112 */
+ .flags = 0,
+ .bus_width = 8,
+ .bus_shift = 0,
+ .i2c_adapter_id = 0,
+ .i2c_address = 0x3c,
+ },
+ { /* [1] = tw9910 */
+ .flags = 0,
+ .bus_width = 8,
+ .bus_shift = 0,
+ .i2c_adapter_id = 0,
+ .i2c_address = 0x45,
+ },
+ },
};
static struct resource ceu0_resources[] = {
@@ -397,24 +420,30 @@ static struct resource ceu0_resources[] = {
.start = evt2irq(0x880),
.flags = IORESOURCE_IRQ,
},
- [2] = {
- /* place holder for contiguous memory */
- },
};
static struct platform_device ceu0_device = {
- .name = "sh_mobile_ceu",
- .id = 0, /* "ceu0" clock */
+ .name = "renesas-ceu",
+ .id = 0, /* ceu.0 */
.num_resources = ARRAY_SIZE(ceu0_resources),
.resource = ceu0_resources,
.dev = {
- .platform_data = &sh_mobile_ceu0_info,
+ .platform_data = &ceu0_pdata,
},
};
/* CEU1 */
-static struct sh_mobile_ceu_info sh_mobile_ceu1_info = {
- .flags = SH_CEU_FLAG_USE_8BIT_BUS,
+static struct ceu_platform_data ceu1_pdata = {
+ .num_subdevs = 1,
+ .subdevs = {
+ { /* [0] = mt9t112 */
+ .flags = 0,
+ .bus_width = 8,
+ .bus_shift = 0,
+ .i2c_adapter_id = 1,
+ .i2c_address = 0x3c,
+ },
+ },
};
static struct resource ceu1_resources[] = {
@@ -428,26 +457,71 @@ static struct resource ceu1_resources[] = {
.start = evt2irq(0x9e0),
.flags = IORESOURCE_IRQ,
},
- [2] = {
- /* place holder for contiguous memory */
- },
};
static struct platform_device ceu1_device = {
- .name = "sh_mobile_ceu",
- .id = 1, /* "ceu1" clock */
+ .name = "renesas-ceu",
+ .id = 1, /* ceu.1 */
.num_resources = ARRAY_SIZE(ceu1_resources),
.resource = ceu1_resources,
.dev = {
- .platform_data = &sh_mobile_ceu1_info,
+ .platform_data = &ceu1_pdata,
+ },
+};
+
+/* Power up/down GPIOs for camera devices and video decoder */
+static struct gpiod_lookup_table tw9910_gpios = {
+ .dev_id = "0-0045",
+ .table = {
+ GPIO_LOOKUP("sh7724_pfc", GPIO_PTU2, "pdn", GPIO_ACTIVE_HIGH),
+ },
+};
+
+static struct gpiod_lookup_table mt9t112_0_gpios = {
+ .dev_id = "0-003c",
+ .table = {
+ GPIO_LOOKUP("sh7724_pfc", GPIO_PTA3, "standby",
+ GPIO_ACTIVE_HIGH),
+ },
+};
+
+static struct gpiod_lookup_table mt9t112_1_gpios = {
+ .dev_id = "1-003c",
+ .table = {
+ GPIO_LOOKUP("sh7724_pfc", GPIO_PTA4, "standby",
+ GPIO_ACTIVE_HIGH),
},
};
/* I2C device */
+static struct tw9910_video_info tw9910_info = {
+ .buswidth = 8,
+ .mpout = TW9910_MPO_FIELD,
+};
+
+static struct mt9t112_platform_data mt9t112_0_pdata = {
+ .flags = MT9T112_FLAG_PCLK_RISING_EDGE,
+ .divider = { 0x49, 0x6, 0, 6, 0, 9, 9, 6, 0 }, /* for 24MHz */
+};
+
+static struct mt9t112_platform_data mt9t112_1_pdata = {
+ .flags = MT9T112_FLAG_PCLK_RISING_EDGE,
+ .divider = { 0x49, 0x6, 0, 6, 0, 9, 9, 6, 0 }, /* for 24MHz */
+};
+
static struct i2c_board_info i2c0_devices[] = {
{
I2C_BOARD_INFO("da7210", 0x1a),
},
+ {
+ I2C_BOARD_INFO("tw9910", 0x45),
+ .platform_data = &tw9910_info,
+ },
+ {
+ /* 1st camera */
+ I2C_BOARD_INFO("mt9t112", 0x3c),
+ .platform_data = &mt9t112_0_pdata,
+ },
};
static struct i2c_board_info i2c1_devices[] = {
@@ -457,7 +531,12 @@ static struct i2c_board_info i2c1_devices[] = {
{
I2C_BOARD_INFO("lis3lv02d", 0x1c),
.irq = evt2irq(0x620),
- }
+ },
+ {
+ /* 2nd camera */
+ I2C_BOARD_INFO("mt9t112", 0x3c),
+ .platform_data = &mt9t112_1_pdata,
+ },
};
/* KEYSC */
@@ -724,115 +803,6 @@ static struct platform_device msiof0_device = {
#endif
-/* I2C Video/Camera */
-static struct i2c_board_info i2c_camera[] = {
- {
- I2C_BOARD_INFO("tw9910", 0x45),
- },
- {
- /* 1st camera */
- I2C_BOARD_INFO("mt9t112", 0x3c),
- },
- {
- /* 2nd camera */
- I2C_BOARD_INFO("mt9t112", 0x3c),
- },
-};
-
-/* tw9910 */
-static int tw9910_power(struct device *dev, int mode)
-{
- int val = mode ? 0 : 1;
-
- gpio_set_value(GPIO_PTU2, val);
- if (mode)
- mdelay(100);
-
- return 0;
-}
-
-static struct tw9910_video_info tw9910_info = {
- .buswidth = SOCAM_DATAWIDTH_8,
- .mpout = TW9910_MPO_FIELD,
-};
-
-static struct soc_camera_link tw9910_link = {
- .i2c_adapter_id = 0,
- .bus_id = 1,
- .power = tw9910_power,
- .board_info = &i2c_camera[0],
- .priv = &tw9910_info,
-};
-
-/* mt9t112 */
-static int mt9t112_power1(struct device *dev, int mode)
-{
- gpio_set_value(GPIO_PTA3, mode);
- if (mode)
- mdelay(100);
-
- return 0;
-}
-
-static struct mt9t112_camera_info mt9t112_info1 = {
- .flags = MT9T112_FLAG_PCLK_RISING_EDGE | MT9T112_FLAG_DATAWIDTH_8,
- .divider = { 0x49, 0x6, 0, 6, 0, 9, 9, 6, 0 }, /* for 24MHz */
-};
-
-static struct soc_camera_link mt9t112_link1 = {
- .i2c_adapter_id = 0,
- .power = mt9t112_power1,
- .bus_id = 0,
- .board_info = &i2c_camera[1],
- .priv = &mt9t112_info1,
-};
-
-static int mt9t112_power2(struct device *dev, int mode)
-{
- gpio_set_value(GPIO_PTA4, mode);
- if (mode)
- mdelay(100);
-
- return 0;
-}
-
-static struct mt9t112_camera_info mt9t112_info2 = {
- .flags = MT9T112_FLAG_PCLK_RISING_EDGE | MT9T112_FLAG_DATAWIDTH_8,
- .divider = { 0x49, 0x6, 0, 6, 0, 9, 9, 6, 0 }, /* for 24MHz */
-};
-
-static struct soc_camera_link mt9t112_link2 = {
- .i2c_adapter_id = 1,
- .power = mt9t112_power2,
- .bus_id = 1,
- .board_info = &i2c_camera[2],
- .priv = &mt9t112_info2,
-};
-
-static struct platform_device camera_devices[] = {
- {
- .name = "soc-camera-pdrv",
- .id = 0,
- .dev = {
- .platform_data = &tw9910_link,
- },
- },
- {
- .name = "soc-camera-pdrv",
- .id = 1,
- .dev = {
- .platform_data = &mt9t112_link1,
- },
- },
- {
- .name = "soc-camera-pdrv",
- .id = 2,
- .dev = {
- .platform_data = &mt9t112_link2,
- },
- },
-};
-
/* FSI */
static struct resource fsi_resources[] = {
[0] = {
@@ -979,6 +949,11 @@ static struct platform_device sh_mmcif_device = {
};
#endif
+static struct platform_device *ecovec_ceu_devices[] __initdata = {
+ &ceu0_device,
+ &ceu1_device,
+};
+
static struct platform_device *ecovec_devices[] __initdata = {
&heartbeat_device,
&nor_flash_device,
@@ -988,8 +963,6 @@ static struct platform_device *ecovec_devices[] __initdata = {
&usbhs_device,
&lcdc_device,
&gpio_backlight_device,
- &ceu0_device,
- &ceu1_device,
&keysc_device,
&cn12_power,
#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
@@ -1001,9 +974,6 @@ static struct platform_device *ecovec_devices[] __initdata = {
#else
&msiof0_device,
#endif
- &camera_devices[0],
- &camera_devices[1],
- &camera_devices[2],
&fsi_device,
&fsi_da7210_device,
&irda_device,
@@ -1240,7 +1210,6 @@ static int __init arch_setup(void)
gpio_request(GPIO_FN_VIO0_CLK, NULL);
gpio_request(GPIO_FN_VIO0_FLD, NULL);
gpio_request(GPIO_FN_VIO0_HD, NULL);
- platform_resource_setup_memory(&ceu0_device, "ceu0", 4 << 20);
/* enable CEU1 */
gpio_request(GPIO_FN_VIO1_D7, NULL);
@@ -1255,7 +1224,6 @@ static int __init arch_setup(void)
gpio_request(GPIO_FN_VIO1_HD, NULL);
gpio_request(GPIO_FN_VIO1_VD, NULL);
gpio_request(GPIO_FN_VIO1_CLK, NULL);
- platform_resource_setup_memory(&ceu1_device, "ceu1", 4 << 20);
/* enable KEYSC */
gpio_request(GPIO_FN_KEYOUT5_IN5, NULL);
@@ -1332,16 +1300,6 @@ static int __init arch_setup(void)
__raw_writew((__raw_readw(IODRIVEA) & ~0x3000) | 0x2000,
IODRIVEA);
- /* enable Video */
- gpio_request(GPIO_PTU2, NULL);
- gpio_direction_output(GPIO_PTU2, 1);
-
- /* enable Camera */
- gpio_request(GPIO_PTA3, NULL);
- gpio_request(GPIO_PTA4, NULL);
- gpio_direction_output(GPIO_PTA3, 0);
- gpio_direction_output(GPIO_PTA4, 0);
-
/* enable FSI */
gpio_request(GPIO_FN_FSIMCKB, NULL);
gpio_request(GPIO_FN_FSIIBSD, NULL);
@@ -1390,6 +1348,11 @@ static int __init arch_setup(void)
gpio_request(GPIO_PTU5, NULL);
gpio_direction_output(GPIO_PTU5, 0);
+ /* Register gpio lookup tables for cameras and video decoder */
+ gpiod_add_lookup_table(&tw9910_gpios);
+ gpiod_add_lookup_table(&mt9t112_0_gpios);
+ gpiod_add_lookup_table(&mt9t112_1_gpios);
+
/* enable I2C device */
i2c_register_board_info(0, i2c0_devices,
ARRAY_SIZE(i2c0_devices));
@@ -1431,6 +1394,25 @@ static int __init arch_setup(void)
gpio_set_value(GPIO_PTG4, 1);
#endif
+ /* Initialize CEU platform devices separately to map memory first */
+ device_initialize(&ecovec_ceu_devices[0]->dev);
+ arch_setup_pdev_archdata(ecovec_ceu_devices[0]);
+ dma_declare_coherent_memory(&ecovec_ceu_devices[0]->dev,
+ ceu0_dma_membase, ceu0_dma_membase,
+ ceu0_dma_membase +
+ CEU_BUFFER_MEMORY_SIZE - 1,
+ DMA_MEMORY_EXCLUSIVE);
+ platform_device_add(ecovec_ceu_devices[0]);
+
+ device_initialize(&ecovec_ceu_devices[1]->dev);
+ arch_setup_pdev_archdata(ecovec_ceu_devices[1]);
+ dma_declare_coherent_memory(&ecovec_ceu_devices[1]->dev,
+ ceu1_dma_membase, ceu1_dma_membase,
+ ceu1_dma_membase +
+ CEU_BUFFER_MEMORY_SIZE - 1,
+ DMA_MEMORY_EXCLUSIVE);
+ platform_device_add(ecovec_ceu_devices[1]);
+
return platform_add_devices(ecovec_devices,
ARRAY_SIZE(ecovec_devices));
}
@@ -1443,6 +1425,24 @@ static int __init devices_setup(void)
}
device_initcall(devices_setup);
+/* Reserve a portion of memory for CEU 0 and CEU 1 buffers */
+static void __init ecovec_mv_mem_reserve(void)
+{
+ phys_addr_t phys;
+ phys_addr_t size = CEU_BUFFER_MEMORY_SIZE;
+
+ phys = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_ALLOC_ANYWHERE);
+ memblock_free(phys, size);
+ memblock_remove(phys, size);
+ ceu0_dma_membase = phys;
+
+ phys = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_ALLOC_ANYWHERE);
+ memblock_free(phys, size);
+ memblock_remove(phys, size);
+ ceu1_dma_membase = phys;
+}
+
static struct sh_machine_vector mv_ecovec __initmv = {
.mv_name = "R0P7724 (EcoVec)",
+ .mv_mem_reserve = ecovec_mv_mem_reserve,
};
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 0bcbe58b11e9..271dfc260e82 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -1,17 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Renesas System Solutions Asia Pte. Ltd - Migo-R
*
* Copyright (C) 2008 Magnus Damm
- *
- * 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.
*/
+#include <linux/clkdev.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/input/sh_keysc.h>
+#include <linux/memblock.h>
#include <linux/mmc/host.h>
#include <linux/mtd/physmap.h>
#include <linux/mfd/tmio.h>
@@ -23,10 +22,11 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
#include <linux/videodev2.h>
#include <linux/sh_intc.h>
#include <video/sh_mobile_lcdc.h>
-#include <media/drv-intf/sh_mobile_ceu.h>
+#include <media/drv-intf/renesas-ceu.h>
#include <media/i2c/ov772x.h>
#include <media/soc_camera.h>
#include <media/i2c/tw9910.h>
@@ -45,6 +45,9 @@
* 0x18000000 8GB 8 NAND Flash (K9K8G08U0A)
*/
+#define CEU_BUFFER_MEMORY_SIZE (4 << 20)
+static phys_addr_t ceu_dma_membase;
+
static struct smc91x_platdata smc91x_info = {
.flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
};
@@ -301,65 +304,24 @@ static struct platform_device migor_lcdc_device = {
},
};
-static struct clk *camera_clk;
-static DEFINE_MUTEX(camera_lock);
-
-static void camera_power_on(int is_tw)
-{
- mutex_lock(&camera_lock);
-
- /* Use 10 MHz VIO_CKO instead of 24 MHz to work
- * around signal quality issues on Panel Board V2.1.
- */
- camera_clk = clk_get(NULL, "video_clk");
- clk_set_rate(camera_clk, 10000000);
- clk_enable(camera_clk); /* start VIO_CKO */
-
- /* use VIO_RST to take camera out of reset */
- mdelay(10);
- if (is_tw) {
- gpio_set_value(GPIO_PTT2, 0);
- gpio_set_value(GPIO_PTT0, 0);
- } else {
- gpio_set_value(GPIO_PTT0, 1);
- }
- gpio_set_value(GPIO_PTT3, 0);
- mdelay(10);
- gpio_set_value(GPIO_PTT3, 1);
- mdelay(10); /* wait to let chip come out of reset */
-}
-
-static void camera_power_off(void)
-{
- clk_disable(camera_clk); /* stop VIO_CKO */
- clk_put(camera_clk);
-
- gpio_set_value(GPIO_PTT3, 0);
- mutex_unlock(&camera_lock);
-}
-
-static int ov7725_power(struct device *dev, int mode)
-{
- if (mode)
- camera_power_on(0);
- else
- camera_power_off();
-
- return 0;
-}
-
-static int tw9910_power(struct device *dev, int mode)
-{
- if (mode)
- camera_power_on(1);
- else
- camera_power_off();
-
- return 0;
-}
-
-static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
- .flags = SH_CEU_FLAG_USE_8BIT_BUS,
+static struct ceu_platform_data ceu_pdata = {
+ .num_subdevs = 2,
+ .subdevs = {
+ { /* [0] = ov772x */
+ .flags = 0,
+ .bus_width = 8,
+ .bus_shift = 0,
+ .i2c_adapter_id = 0,
+ .i2c_address = 0x21,
+ },
+ { /* [1] = tw9910 */
+ .flags = 0,
+ .bus_width = 8,
+ .bus_shift = 0,
+ .i2c_adapter_id = 0,
+ .i2c_address = 0x45,
+ },
+ },
};
static struct resource migor_ceu_resources[] = {
@@ -373,18 +335,32 @@ static struct resource migor_ceu_resources[] = {
.start = evt2irq(0x880),
.flags = IORESOURCE_IRQ,
},
- [2] = {
- /* place holder for contiguous memory */
- },
};
static struct platform_device migor_ceu_device = {
- .name = "sh_mobile_ceu",
- .id = 0, /* "ceu0" clock */
+ .name = "renesas-ceu",
+ .id = 0, /* ceu.0 */
.num_resources = ARRAY_SIZE(migor_ceu_resources),
.resource = migor_ceu_resources,
.dev = {
- .platform_data = &sh_mobile_ceu_info,
+ .platform_data = &ceu_pdata,
+ },
+};
+
+/* Powerdown/reset gpios for CEU image sensors */
+static struct gpiod_lookup_table ov7725_gpios = {
+ .dev_id = "0-0021",
+ .table = {
+ GPIO_LOOKUP("sh7722_pfc", GPIO_PTT0, "pwdn", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("sh7722_pfc", GPIO_PTT3, "rstb", GPIO_ACTIVE_LOW),
+ },
+};
+
+static struct gpiod_lookup_table tw9910_gpios = {
+ .dev_id = "0-0045",
+ .table = {
+ GPIO_LOOKUP("sh7722_pfc", GPIO_PTT2, "pdn", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("sh7722_pfc", GPIO_PTT3, "rstb", GPIO_ACTIVE_LOW),
},
};
@@ -423,6 +399,15 @@ static struct platform_device sdhi_cn9_device = {
},
};
+static struct ov772x_camera_info ov7725_info = {
+ .flags = 0,
+};
+
+static struct tw9910_video_info tw9910_info = {
+ .buswidth = 8,
+ .mpout = TW9910_MPO_FIELD,
+};
+
static struct i2c_board_info migor_i2c_devices[] = {
{
I2C_BOARD_INFO("rs5c372b", 0x32),
@@ -434,51 +419,13 @@ static struct i2c_board_info migor_i2c_devices[] = {
{
I2C_BOARD_INFO("wm8978", 0x1a),
},
-};
-
-static struct i2c_board_info migor_i2c_camera[] = {
{
I2C_BOARD_INFO("ov772x", 0x21),
+ .platform_data = &ov7725_info,
},
{
I2C_BOARD_INFO("tw9910", 0x45),
- },
-};
-
-static struct ov772x_camera_info ov7725_info;
-
-static struct soc_camera_link ov7725_link = {
- .power = ov7725_power,
- .board_info = &migor_i2c_camera[0],
- .i2c_adapter_id = 0,
- .priv = &ov7725_info,
-};
-
-static struct tw9910_video_info tw9910_info = {
- .buswidth = SOCAM_DATAWIDTH_8,
- .mpout = TW9910_MPO_FIELD,
-};
-
-static struct soc_camera_link tw9910_link = {
- .power = tw9910_power,
- .board_info = &migor_i2c_camera[1],
- .i2c_adapter_id = 0,
- .priv = &tw9910_info,
-};
-
-static struct platform_device migor_camera[] = {
- {
- .name = "soc-camera-pdrv",
- .id = 0,
- .dev = {
- .platform_data = &ov7725_link,
- },
- }, {
- .name = "soc-camera-pdrv",
- .id = 1,
- .dev = {
- .platform_data = &tw9910_link,
- },
+ .platform_data = &tw9910_info,
},
};
@@ -486,12 +433,9 @@ static struct platform_device *migor_devices[] __initdata = {
&smc91x_eth_device,
&sh_keysc_device,
&migor_lcdc_device,
- &migor_ceu_device,
&migor_nor_flash_device,
&migor_nand_flash_device,
&sdhi_cn9_device,
- &migor_camera[0],
- &migor_camera[1],
};
extern char migor_sdram_enter_start;
@@ -501,6 +445,8 @@ extern char migor_sdram_leave_end;
static int __init migor_devices_setup(void)
{
+ struct clk *video_clk;
+
/* register board specific self-refresh code */
sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF,
&migor_sdram_enter_start,
@@ -620,20 +566,8 @@ static int __init migor_devices_setup(void)
gpio_request(GPIO_FN_VIO_D9, NULL);
gpio_request(GPIO_FN_VIO_D8, NULL);
- gpio_request(GPIO_PTT3, NULL); /* VIO_RST */
- gpio_direction_output(GPIO_PTT3, 0);
- gpio_request(GPIO_PTT2, NULL); /* TV_IN_EN */
- gpio_direction_output(GPIO_PTT2, 1);
- gpio_request(GPIO_PTT0, NULL); /* CAM_EN */
-#ifdef CONFIG_SH_MIGOR_RTA_WVGA
- gpio_direction_output(GPIO_PTT0, 0);
-#else
- gpio_direction_output(GPIO_PTT0, 1);
-#endif
__raw_writew(__raw_readw(PORT_MSELCRB) | 0x2000, PORT_MSELCRB); /* D15->D8 */
- platform_resource_setup_memory(&migor_ceu_device, "ceu", 4 << 20);
-
/* SIU: Port B */
gpio_request(GPIO_FN_SIUBOLR, NULL);
gpio_request(GPIO_FN_SIUBOBT, NULL);
@@ -647,9 +581,36 @@ static int __init migor_devices_setup(void)
*/
__raw_writew(__raw_readw(PORT_MSELCRA) | 1, PORT_MSELCRA);
+ /*
+ * Use 10 MHz VIO_CKO instead of 24 MHz to work around signal quality
+ * issues on Panel Board V2.1.
+ */
+ video_clk = clk_get(NULL, "video_clk");
+ if (!IS_ERR(video_clk)) {
+ clk_set_rate(video_clk, clk_round_rate(video_clk, 10000000));
+ clk_put(video_clk);
+ }
+
+ /* Add a clock alias for ov7725 xclk source. */
+ clk_add_alias("xclk", "0-0021", "video_clk", NULL);
+
+ /* Register GPIOs for video sources. */
+ gpiod_add_lookup_table(&ov7725_gpios);
+ gpiod_add_lookup_table(&tw9910_gpios);
+
i2c_register_board_info(0, migor_i2c_devices,
ARRAY_SIZE(migor_i2c_devices));
+ /* Initialize CEU platform device separately to map memory first */
+ device_initialize(&migor_ceu_device.dev);
+ arch_setup_pdev_archdata(&migor_ceu_device);
+ dma_declare_coherent_memory(&migor_ceu_device.dev,
+ ceu_dma_membase, ceu_dma_membase,
+ ceu_dma_membase + CEU_BUFFER_MEMORY_SIZE - 1,
+ DMA_MEMORY_EXCLUSIVE);
+
+ platform_device_add(&migor_ceu_device);
+
return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices));
}
arch_initcall(migor_devices_setup);
@@ -665,10 +626,24 @@ static int migor_mode_pins(void)
return MODE_PIN0 | MODE_PIN1 | MODE_PIN5;
}
+/* Reserve a portion of memory for CEU buffers */
+static void __init migor_mv_mem_reserve(void)
+{
+ phys_addr_t phys;
+ phys_addr_t size = CEU_BUFFER_MEMORY_SIZE;
+
+ phys = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_ALLOC_ANYWHERE);
+ memblock_free(phys, size);
+ memblock_remove(phys, size);
+
+ ceu_dma_membase = phys;
+}
+
/*
* The Machine Vector
*/
static struct sh_machine_vector mv_migor __initmv = {
.mv_name = "Migo-R",
.mv_mode_pins = migor_mode_pins,
+ .mv_mem_reserve = migor_mv_mem_reserve,
};
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
index 8f07a1a38692..d85091ec4b01 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
@@ -223,7 +223,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("sh-vou.0", &mstp_clks[HWBLK_VOU]),
CLKDEV_CON_ID("jpu0", &mstp_clks[HWBLK_JPU]),
CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU]),
- CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU]),
+ CLKDEV_DEV_ID("renesas-ceu.0", &mstp_clks[HWBLK_CEU]),
CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU]),
CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]),
CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]),
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
index f27c618de527..3194336a3599 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
@@ -338,14 +338,14 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[HWBLK_SDHI0]),
CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[HWBLK_SDHI1]),
CLKDEV_CON_ID("veu1", &mstp_clks[HWBLK_VEU1]),
- CLKDEV_DEV_ID("sh_mobile_ceu.1", &mstp_clks[HWBLK_CEU1]),
+ CLKDEV_DEV_ID("renesas-ceu.1", &mstp_clks[HWBLK_CEU1]),
CLKDEV_CON_ID("beu1", &mstp_clks[HWBLK_BEU1]),
CLKDEV_CON_ID("2ddmac0", &mstp_clks[HWBLK_2DDMAC]),
CLKDEV_DEV_ID("sh_fsi.0", &mstp_clks[HWBLK_SPU]),
CLKDEV_CON_ID("jpu0", &mstp_clks[HWBLK_JPU]),
CLKDEV_DEV_ID("sh-vou", &mstp_clks[HWBLK_VOU]),
CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU0]),
- CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU0]),
+ CLKDEV_DEV_ID("renesas-ceu.0", &mstp_clks[HWBLK_CEU0]),
CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU0]),
CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]),
CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]),
diff --git a/arch/x86/crypto/aesni-intel_asm.S b/arch/x86/crypto/aesni-intel_asm.S
index 12e8484a8ee7..e762ef417562 100644
--- a/arch/x86/crypto/aesni-intel_asm.S
+++ b/arch/x86/crypto/aesni-intel_asm.S
@@ -94,23 +94,30 @@ ALL_F: .octa 0xffffffffffffffffffffffffffffffff
#define STACK_OFFSET 8*3
-#define HashKey 16*0 // store HashKey <<1 mod poly here
-#define HashKey_2 16*1 // store HashKey^2 <<1 mod poly here
-#define HashKey_3 16*2 // store HashKey^3 <<1 mod poly here
-#define HashKey_4 16*3 // store HashKey^4 <<1 mod poly here
-#define HashKey_k 16*4 // store XOR of High 64 bits and Low 64
+
+#define AadHash 16*0
+#define AadLen 16*1
+#define InLen (16*1)+8
+#define PBlockEncKey 16*2
+#define OrigIV 16*3
+#define CurCount 16*4
+#define PBlockLen 16*5
+#define HashKey 16*6 // store HashKey <<1 mod poly here
+#define HashKey_2 16*7 // store HashKey^2 <<1 mod poly here
+#define HashKey_3 16*8 // store HashKey^3 <<1 mod poly here
+#define HashKey_4 16*9 // store HashKey^4 <<1 mod poly here
+#define HashKey_k 16*10 // store XOR of High 64 bits and Low 64
// bits of HashKey <<1 mod poly here
//(for Karatsuba purposes)
-#define HashKey_2_k 16*5 // store XOR of High 64 bits and Low 64
+#define HashKey_2_k 16*11 // store XOR of High 64 bits and Low 64
// bits of HashKey^2 <<1 mod poly here
// (for Karatsuba purposes)
-#define HashKey_3_k 16*6 // store XOR of High 64 bits and Low 64
+#define HashKey_3_k 16*12 // store XOR of High 64 bits and Low 64
// bits of HashKey^3 <<1 mod poly here
// (for Karatsuba purposes)
-#define HashKey_4_k 16*7 // store XOR of High 64 bits and Low 64
+#define HashKey_4_k 16*13 // store XOR of High 64 bits and Low 64
// bits of HashKey^4 <<1 mod poly here
// (for Karatsuba purposes)
-#define VARIABLE_OFFSET 16*8
#define arg1 rdi
#define arg2 rsi
@@ -118,10 +125,11 @@ ALL_F: .octa 0xffffffffffffffffffffffffffffffff
#define arg4 rcx
#define arg5 r8
#define arg6 r9
-#define arg7 STACK_OFFSET+8(%r14)
-#define arg8 STACK_OFFSET+16(%r14)
-#define arg9 STACK_OFFSET+24(%r14)
-#define arg10 STACK_OFFSET+32(%r14)
+#define arg7 STACK_OFFSET+8(%rsp)
+#define arg8 STACK_OFFSET+16(%rsp)
+#define arg9 STACK_OFFSET+24(%rsp)
+#define arg10 STACK_OFFSET+32(%rsp)
+#define arg11 STACK_OFFSET+40(%rsp)
#define keysize 2*15*16(%arg1)
#endif
@@ -171,6 +179,332 @@ ALL_F: .octa 0xffffffffffffffffffffffffffffffff
#define TKEYP T1
#endif
+.macro FUNC_SAVE
+ push %r12
+ push %r13
+ push %r14
+#
+# states of %xmm registers %xmm6:%xmm15 not saved
+# all %xmm registers are clobbered
+#
+.endm
+
+
+.macro FUNC_RESTORE
+ pop %r14
+ pop %r13
+ pop %r12
+.endm
+
+# Precompute hashkeys.
+# Input: Hash subkey.
+# Output: HashKeys stored in gcm_context_data. Only needs to be called
+# once per key.
+# clobbers r12, and tmp xmm registers.
+.macro PRECOMPUTE SUBKEY TMP1 TMP2 TMP3 TMP4 TMP5 TMP6 TMP7
+ mov \SUBKEY, %r12
+ movdqu (%r12), \TMP3
+ movdqa SHUF_MASK(%rip), \TMP2
+ PSHUFB_XMM \TMP2, \TMP3
+
+ # precompute HashKey<<1 mod poly from the HashKey (required for GHASH)
+
+ movdqa \TMP3, \TMP2
+ psllq $1, \TMP3
+ psrlq $63, \TMP2
+ movdqa \TMP2, \TMP1
+ pslldq $8, \TMP2
+ psrldq $8, \TMP1
+ por \TMP2, \TMP3
+
+ # reduce HashKey<<1
+
+ pshufd $0x24, \TMP1, \TMP2
+ pcmpeqd TWOONE(%rip), \TMP2
+ pand POLY(%rip), \TMP2
+ pxor \TMP2, \TMP3
+ movdqa \TMP3, HashKey(%arg2)
+
+ movdqa \TMP3, \TMP5
+ pshufd $78, \TMP3, \TMP1
+ pxor \TMP3, \TMP1
+ movdqa \TMP1, HashKey_k(%arg2)
+
+ GHASH_MUL \TMP5, \TMP3, \TMP1, \TMP2, \TMP4, \TMP6, \TMP7
+# TMP5 = HashKey^2<<1 (mod poly)
+ movdqa \TMP5, HashKey_2(%arg2)
+# HashKey_2 = HashKey^2<<1 (mod poly)
+ pshufd $78, \TMP5, \TMP1
+ pxor \TMP5, \TMP1
+ movdqa \TMP1, HashKey_2_k(%arg2)
+
+ GHASH_MUL \TMP5, \TMP3, \TMP1, \TMP2, \TMP4, \TMP6, \TMP7
+# TMP5 = HashKey^3<<1 (mod poly)
+ movdqa \TMP5, HashKey_3(%arg2)
+ pshufd $78, \TMP5, \TMP1
+ pxor \TMP5, \TMP1
+ movdqa \TMP1, HashKey_3_k(%arg2)
+
+ GHASH_MUL \TMP5, \TMP3, \TMP1, \TMP2, \TMP4, \TMP6, \TMP7
+# TMP5 = HashKey^3<<1 (mod poly)
+ movdqa \TMP5, HashKey_4(%arg2)
+ pshufd $78, \TMP5, \TMP1
+ pxor \TMP5, \TMP1
+ movdqa \TMP1, HashKey_4_k(%arg2)
+.endm
+
+# GCM_INIT initializes a gcm_context struct to prepare for encoding/decoding.
+# Clobbers rax, r10-r13 and xmm0-xmm6, %xmm13
+.macro GCM_INIT Iv SUBKEY AAD AADLEN
+ mov \AADLEN, %r11
+ mov %r11, AadLen(%arg2) # ctx_data.aad_length = aad_length
+ xor %r11, %r11
+ mov %r11, InLen(%arg2) # ctx_data.in_length = 0
+ mov %r11, PBlockLen(%arg2) # ctx_data.partial_block_length = 0
+ mov %r11, PBlockEncKey(%arg2) # ctx_data.partial_block_enc_key = 0
+ mov \Iv, %rax
+ movdqu (%rax), %xmm0
+ movdqu %xmm0, OrigIV(%arg2) # ctx_data.orig_IV = iv
+
+ movdqa SHUF_MASK(%rip), %xmm2
+ PSHUFB_XMM %xmm2, %xmm0
+ movdqu %xmm0, CurCount(%arg2) # ctx_data.current_counter = iv
+
+ PRECOMPUTE \SUBKEY, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7,
+ movdqa HashKey(%arg2), %xmm13
+
+ CALC_AAD_HASH %xmm13, \AAD, \AADLEN, %xmm0, %xmm1, %xmm2, %xmm3, \
+ %xmm4, %xmm5, %xmm6
+.endm
+
+# GCM_ENC_DEC Encodes/Decodes given data. Assumes that the passed gcm_context
+# struct has been initialized by GCM_INIT.
+# Requires the input data be at least 1 byte long because of READ_PARTIAL_BLOCK
+# Clobbers rax, r10-r13, and xmm0-xmm15
+.macro GCM_ENC_DEC operation
+ movdqu AadHash(%arg2), %xmm8
+ movdqu HashKey(%arg2), %xmm13
+ add %arg5, InLen(%arg2)
+
+ xor %r11, %r11 # initialise the data pointer offset as zero
+ PARTIAL_BLOCK %arg3 %arg4 %arg5 %r11 %xmm8 \operation
+
+ sub %r11, %arg5 # sub partial block data used
+ mov %arg5, %r13 # save the number of bytes
+
+ and $-16, %r13 # %r13 = %r13 - (%r13 mod 16)
+ mov %r13, %r12
+ # Encrypt/Decrypt first few blocks
+
+ and $(3<<4), %r12
+ jz _initial_num_blocks_is_0_\@
+ cmp $(2<<4), %r12
+ jb _initial_num_blocks_is_1_\@
+ je _initial_num_blocks_is_2_\@
+_initial_num_blocks_is_3_\@:
+ INITIAL_BLOCKS_ENC_DEC %xmm9, %xmm10, %xmm13, %xmm11, %xmm12, %xmm0, \
+%xmm1, %xmm2, %xmm3, %xmm4, %xmm8, %xmm5, %xmm6, 5, 678, \operation
+ sub $48, %r13
+ jmp _initial_blocks_\@
+_initial_num_blocks_is_2_\@:
+ INITIAL_BLOCKS_ENC_DEC %xmm9, %xmm10, %xmm13, %xmm11, %xmm12, %xmm0, \
+%xmm1, %xmm2, %xmm3, %xmm4, %xmm8, %xmm5, %xmm6, 6, 78, \operation
+ sub $32, %r13
+ jmp _initial_blocks_\@
+_initial_num_blocks_is_1_\@:
+ INITIAL_BLOCKS_ENC_DEC %xmm9, %xmm10, %xmm13, %xmm11, %xmm12, %xmm0, \
+%xmm1, %xmm2, %xmm3, %xmm4, %xmm8, %xmm5, %xmm6, 7, 8, \operation
+ sub $16, %r13
+ jmp _initial_blocks_\@
+_initial_num_blocks_is_0_\@:
+ INITIAL_BLOCKS_ENC_DEC %xmm9, %xmm10, %xmm13, %xmm11, %xmm12, %xmm0, \
+%xmm1, %xmm2, %xmm3, %xmm4, %xmm8, %xmm5, %xmm6, 8, 0, \operation
+_initial_blocks_\@:
+
+ # Main loop - Encrypt/Decrypt remaining blocks
+
+ cmp $0, %r13
+ je _zero_cipher_left_\@
+ sub $64, %r13
+ je _four_cipher_left_\@
+_crypt_by_4_\@:
+ GHASH_4_ENCRYPT_4_PARALLEL_\operation %xmm9, %xmm10, %xmm11, %xmm12, \
+ %xmm13, %xmm14, %xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, \
+ %xmm7, %xmm8, enc
+ add $64, %r11
+ sub $64, %r13
+ jne _crypt_by_4_\@
+_four_cipher_left_\@:
+ GHASH_LAST_4 %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, \
+%xmm15, %xmm1, %xmm2, %xmm3, %xmm4, %xmm8
+_zero_cipher_left_\@:
+ movdqu %xmm8, AadHash(%arg2)
+ movdqu %xmm0, CurCount(%arg2)
+
+ mov %arg5, %r13
+ and $15, %r13 # %r13 = arg5 (mod 16)
+ je _multiple_of_16_bytes_\@
+
+ mov %r13, PBlockLen(%arg2)
+
+ # Handle the last <16 Byte block separately
+ paddd ONE(%rip), %xmm0 # INCR CNT to get Yn
+ movdqu %xmm0, CurCount(%arg2)
+ movdqa SHUF_MASK(%rip), %xmm10
+ PSHUFB_XMM %xmm10, %xmm0
+
+ ENCRYPT_SINGLE_BLOCK %xmm0, %xmm1 # Encrypt(K, Yn)
+ movdqu %xmm0, PBlockEncKey(%arg2)
+
+ cmp $16, %arg5
+ jge _large_enough_update_\@
+
+ lea (%arg4,%r11,1), %r10
+ mov %r13, %r12
+ READ_PARTIAL_BLOCK %r10 %r12 %xmm2 %xmm1
+ jmp _data_read_\@
+
+_large_enough_update_\@:
+ sub $16, %r11
+ add %r13, %r11
+
+ # receive the last <16 Byte block
+ movdqu (%arg4, %r11, 1), %xmm1
+
+ sub %r13, %r11
+ add $16, %r11
+
+ lea SHIFT_MASK+16(%rip), %r12
+ # adjust the shuffle mask pointer to be able to shift 16-r13 bytes
+ # (r13 is the number of bytes in plaintext mod 16)
+ sub %r13, %r12
+ # get the appropriate shuffle mask
+ movdqu (%r12), %xmm2
+ # shift right 16-r13 bytes
+ PSHUFB_XMM %xmm2, %xmm1
+
+_data_read_\@:
+ lea ALL_F+16(%rip), %r12
+ sub %r13, %r12
+
+.ifc \operation, dec
+ movdqa %xmm1, %xmm2
+.endif
+ pxor %xmm1, %xmm0 # XOR Encrypt(K, Yn)
+ movdqu (%r12), %xmm1
+ # get the appropriate mask to mask out top 16-r13 bytes of xmm0
+ pand %xmm1, %xmm0 # mask out top 16-r13 bytes of xmm0
+.ifc \operation, dec
+ pand %xmm1, %xmm2
+ movdqa SHUF_MASK(%rip), %xmm10
+ PSHUFB_XMM %xmm10 ,%xmm2
+
+ pxor %xmm2, %xmm8
+.else
+ movdqa SHUF_MASK(%rip), %xmm10
+ PSHUFB_XMM %xmm10,%xmm0
+
+ pxor %xmm0, %xmm8
+.endif
+
+ movdqu %xmm8, AadHash(%arg2)
+.ifc \operation, enc
+ # GHASH computation for the last <16 byte block
+ movdqa SHUF_MASK(%rip), %xmm10
+ # shuffle xmm0 back to output as ciphertext
+ PSHUFB_XMM %xmm10, %xmm0
+.endif
+
+ # Output %r13 bytes
+ MOVQ_R64_XMM %xmm0, %rax
+ cmp $8, %r13
+ jle _less_than_8_bytes_left_\@
+ mov %rax, (%arg3 , %r11, 1)
+ add $8, %r11
+ psrldq $8, %xmm0
+ MOVQ_R64_XMM %xmm0, %rax
+ sub $8, %r13
+_less_than_8_bytes_left_\@:
+ mov %al, (%arg3, %r11, 1)
+ add $1, %r11
+ shr $8, %rax
+ sub $1, %r13
+ jne _less_than_8_bytes_left_\@
+_multiple_of_16_bytes_\@:
+.endm
+
+# GCM_COMPLETE Finishes update of tag of last partial block
+# Output: Authorization Tag (AUTH_TAG)
+# Clobbers rax, r10-r12, and xmm0, xmm1, xmm5-xmm15
+.macro GCM_COMPLETE AUTHTAG AUTHTAGLEN
+ movdqu AadHash(%arg2), %xmm8
+ movdqu HashKey(%arg2), %xmm13
+
+ mov PBlockLen(%arg2), %r12
+
+ cmp $0, %r12
+ je _partial_done\@
+
+ GHASH_MUL %xmm8, %xmm13, %xmm9, %xmm10, %xmm11, %xmm5, %xmm6
+
+_partial_done\@:
+ mov AadLen(%arg2), %r12 # %r13 = aadLen (number of bytes)
+ shl $3, %r12 # convert into number of bits
+ movd %r12d, %xmm15 # len(A) in %xmm15
+ mov InLen(%arg2), %r12
+ shl $3, %r12 # len(C) in bits (*128)
+ MOVQ_R64_XMM %r12, %xmm1
+
+ pslldq $8, %xmm15 # %xmm15 = len(A)||0x0000000000000000
+ pxor %xmm1, %xmm15 # %xmm15 = len(A)||len(C)
+ pxor %xmm15, %xmm8
+ GHASH_MUL %xmm8, %xmm13, %xmm9, %xmm10, %xmm11, %xmm5, %xmm6
+ # final GHASH computation
+ movdqa SHUF_MASK(%rip), %xmm10
+ PSHUFB_XMM %xmm10, %xmm8
+
+ movdqu OrigIV(%arg2), %xmm0 # %xmm0 = Y0
+ ENCRYPT_SINGLE_BLOCK %xmm0, %xmm1 # E(K, Y0)
+ pxor %xmm8, %xmm0
+_return_T_\@:
+ mov \AUTHTAG, %r10 # %r10 = authTag
+ mov \AUTHTAGLEN, %r11 # %r11 = auth_tag_len
+ cmp $16, %r11
+ je _T_16_\@
+ cmp $8, %r11
+ jl _T_4_\@
+_T_8_\@:
+ MOVQ_R64_XMM %xmm0, %rax
+ mov %rax, (%r10)
+ add $8, %r10
+ sub $8, %r11
+ psrldq $8, %xmm0
+ cmp $0, %r11
+ je _return_T_done_\@
+_T_4_\@:
+ movd %xmm0, %eax
+ mov %eax, (%r10)
+ add $4, %r10
+ sub $4, %r11
+ psrldq $4, %xmm0
+ cmp $0, %r11
+ je _return_T_done_\@
+_T_123_\@:
+ movd %xmm0, %eax
+ cmp $2, %r11
+ jl _T_1_\@
+ mov %ax, (%r10)
+ cmp $2, %r11
+ je _return_T_done_\@
+ add $2, %r10
+ sar $16, %eax
+_T_1_\@:
+ mov %al, (%r10)
+ jmp _return_T_done_\@
+_T_16_\@:
+ movdqu %xmm0, (%r10)
+_return_T_done_\@:
+.endm
#ifdef __x86_64__
/* GHASH_MUL MACRO to implement: Data*HashKey mod (128,127,126,121,0)
@@ -264,232 +598,188 @@ _read_next_byte_lt8_\@:
_done_read_partial_block_\@:
.endm
-/*
-* if a = number of total plaintext bytes
-* b = floor(a/16)
-* num_initial_blocks = b mod 4
-* encrypt the initial num_initial_blocks blocks and apply ghash on
-* the ciphertext
-* %r10, %r11, %r12, %rax, %xmm5, %xmm6, %xmm7, %xmm8, %xmm9 registers
-* are clobbered
-* arg1, %arg2, %arg3, %r14 are used as a pointer only, not modified
-*/
-
-
-.macro INITIAL_BLOCKS_DEC num_initial_blocks TMP1 TMP2 TMP3 TMP4 TMP5 XMM0 XMM1 \
-XMM2 XMM3 XMM4 XMMDst TMP6 TMP7 i i_seq operation
- MOVADQ SHUF_MASK(%rip), %xmm14
- mov arg7, %r10 # %r10 = AAD
- mov arg8, %r11 # %r11 = aadLen
- pxor %xmm\i, %xmm\i
- pxor \XMM2, \XMM2
+# CALC_AAD_HASH: Calculates the hash of the data which will not be encrypted.
+# clobbers r10-11, xmm14
+.macro CALC_AAD_HASH HASHKEY AAD AADLEN TMP1 TMP2 TMP3 TMP4 TMP5 \
+ TMP6 TMP7
+ MOVADQ SHUF_MASK(%rip), %xmm14
+ mov \AAD, %r10 # %r10 = AAD
+ mov \AADLEN, %r11 # %r11 = aadLen
+ pxor \TMP7, \TMP7
+ pxor \TMP6, \TMP6
cmp $16, %r11
- jl _get_AAD_rest\num_initial_blocks\operation
-_get_AAD_blocks\num_initial_blocks\operation:
- movdqu (%r10), %xmm\i
- PSHUFB_XMM %xmm14, %xmm\i # byte-reflect the AAD data
- pxor %xmm\i, \XMM2
- GHASH_MUL \XMM2, \TMP3, \TMP1, \TMP2, \TMP4, \TMP5, \XMM1
+ jl _get_AAD_rest\@
+_get_AAD_blocks\@:
+ movdqu (%r10), \TMP7
+ PSHUFB_XMM %xmm14, \TMP7 # byte-reflect the AAD data
+ pxor \TMP7, \TMP6
+ GHASH_MUL \TMP6, \HASHKEY, \TMP1, \TMP2, \TMP3, \TMP4, \TMP5
add $16, %r10
sub $16, %r11
cmp $16, %r11
- jge _get_AAD_blocks\num_initial_blocks\operation
+ jge _get_AAD_blocks\@
- movdqu \XMM2, %xmm\i
+ movdqu \TMP6, \TMP7
/* read the last <16B of AAD */
-_get_AAD_rest\num_initial_blocks\operation:
+_get_AAD_rest\@:
cmp $0, %r11
- je _get_AAD_done\num_initial_blocks\operation
-
- READ_PARTIAL_BLOCK %r10, %r11, \TMP1, %xmm\i
- PSHUFB_XMM %xmm14, %xmm\i # byte-reflect the AAD data
- pxor \XMM2, %xmm\i
- GHASH_MUL %xmm\i, \TMP3, \TMP1, \TMP2, \TMP4, \TMP5, \XMM1
+ je _get_AAD_done\@
-_get_AAD_done\num_initial_blocks\operation:
- xor %r11, %r11 # initialise the data pointer offset as zero
- # start AES for num_initial_blocks blocks
-
- mov %arg5, %rax # %rax = *Y0
- movdqu (%rax), \XMM0 # XMM0 = Y0
- PSHUFB_XMM %xmm14, \XMM0
+ READ_PARTIAL_BLOCK %r10, %r11, \TMP1, \TMP7
+ PSHUFB_XMM %xmm14, \TMP7 # byte-reflect the AAD data
+ pxor \TMP6, \TMP7
+ GHASH_MUL \TMP7, \HASHKEY, \TMP1, \TMP2, \TMP3, \TMP4, \TMP5
+ movdqu \TMP7, \TMP6
-.if (\i == 5) || (\i == 6) || (\i == 7)
- MOVADQ ONE(%RIP),\TMP1
- MOVADQ (%arg1),\TMP2
-.irpc index, \i_seq
- paddd \TMP1, \XMM0 # INCR Y0
- movdqa \XMM0, %xmm\index
- PSHUFB_XMM %xmm14, %xmm\index # perform a 16 byte swap
- pxor \TMP2, %xmm\index
-.endr
- lea 0x10(%arg1),%r10
- mov keysize,%eax
- shr $2,%eax # 128->4, 192->6, 256->8
- add $5,%eax # 128->9, 192->11, 256->13
-
-aes_loop_initial_dec\num_initial_blocks:
- MOVADQ (%r10),\TMP1
-.irpc index, \i_seq
- AESENC \TMP1, %xmm\index
-.endr
- add $16,%r10
- sub $1,%eax
- jnz aes_loop_initial_dec\num_initial_blocks
-
- MOVADQ (%r10), \TMP1
-.irpc index, \i_seq
- AESENCLAST \TMP1, %xmm\index # Last Round
-.endr
-.irpc index, \i_seq
- movdqu (%arg3 , %r11, 1), \TMP1
- pxor \TMP1, %xmm\index
- movdqu %xmm\index, (%arg2 , %r11, 1)
- # write back plaintext/ciphertext for num_initial_blocks
- add $16, %r11
-
- movdqa \TMP1, %xmm\index
- PSHUFB_XMM %xmm14, %xmm\index
- # prepare plaintext/ciphertext for GHASH computation
-.endr
-.endif
-
- # apply GHASH on num_initial_blocks blocks
+_get_AAD_done\@:
+ movdqu \TMP6, AadHash(%arg2)
+.endm
-.if \i == 5
- pxor %xmm5, %xmm6
- GHASH_MUL %xmm6, \TMP3, \TMP1, \TMP2, \TMP4, \TMP5, \XMM1
- pxor %xmm6, %xmm7
- GHASH_MUL %xmm7, \TMP3, \TMP1, \TMP2, \TMP4, \TMP5, \XMM1
- pxor %xmm7, %xmm8
- GHASH_MUL %xmm8, \TMP3, \TMP1, \TMP2, \TMP4, \TMP5, \XMM1
-.elseif \i == 6
- pxor %xmm6, %xmm7
- GHASH_MUL %xmm7, \TMP3, \TMP1, \TMP2, \TMP4, \TMP5, \XMM1
- pxor %xmm7, %xmm8
- GHASH_MUL %xmm8, \TMP3, \TMP1, \TMP2, \TMP4, \TMP5, \XMM1
-.elseif \i == 7
- pxor %xmm7, %xmm8
- GHASH_MUL %xmm8, \TMP3, \TMP1, \TMP2, \TMP4, \TMP5, \XMM1
+# PARTIAL_BLOCK: Handles encryption/decryption and the tag partial blocks
+# between update calls.
+# Requires the input data be at least 1 byte long due to READ_PARTIAL_BLOCK
+# Outputs encrypted bytes, and updates hash and partial info in gcm_data_context
+# Clobbers rax, r10, r12, r13, xmm0-6, xmm9-13
+.macro PARTIAL_BLOCK CYPH_PLAIN_OUT PLAIN_CYPH_IN PLAIN_CYPH_LEN DATA_OFFSET \
+ AAD_HASH operation
+ mov PBlockLen(%arg2), %r13
+ cmp $0, %r13
+ je _partial_block_done_\@ # Leave Macro if no partial blocks
+ # Read in input data without over reading
+ cmp $16, \PLAIN_CYPH_LEN
+ jl _fewer_than_16_bytes_\@
+ movups (\PLAIN_CYPH_IN), %xmm1 # If more than 16 bytes, just fill xmm
+ jmp _data_read_\@
+
+_fewer_than_16_bytes_\@:
+ lea (\PLAIN_CYPH_IN, \DATA_OFFSET, 1), %r10
+ mov \PLAIN_CYPH_LEN, %r12
+ READ_PARTIAL_BLOCK %r10 %r12 %xmm0 %xmm1
+
+ mov PBlockLen(%arg2), %r13
+
+_data_read_\@: # Finished reading in data
+
+ movdqu PBlockEncKey(%arg2), %xmm9
+ movdqu HashKey(%arg2), %xmm13
+
+ lea SHIFT_MASK(%rip), %r12
+
+ # adjust the shuffle mask pointer to be able to shift r13 bytes
+ # r16-r13 is the number of bytes in plaintext mod 16)
+ add %r13, %r12
+ movdqu (%r12), %xmm2 # get the appropriate shuffle mask
+ PSHUFB_XMM %xmm2, %xmm9 # shift right r13 bytes
+
+.ifc \operation, dec
+ movdqa %xmm1, %xmm3
+ pxor %xmm1, %xmm9 # Cyphertext XOR E(K, Yn)
+
+ mov \PLAIN_CYPH_LEN, %r10
+ add %r13, %r10
+ # Set r10 to be the amount of data left in CYPH_PLAIN_IN after filling
+ sub $16, %r10
+ # Determine if if partial block is not being filled and
+ # shift mask accordingly
+ jge _no_extra_mask_1_\@
+ sub %r10, %r12
+_no_extra_mask_1_\@:
+
+ movdqu ALL_F-SHIFT_MASK(%r12), %xmm1
+ # get the appropriate mask to mask out bottom r13 bytes of xmm9
+ pand %xmm1, %xmm9 # mask out bottom r13 bytes of xmm9
+
+ pand %xmm1, %xmm3
+ movdqa SHUF_MASK(%rip), %xmm10
+ PSHUFB_XMM %xmm10, %xmm3
+ PSHUFB_XMM %xmm2, %xmm3
+ pxor %xmm3, \AAD_HASH
+
+ cmp $0, %r10
+ jl _partial_incomplete_1_\@
+
+ # GHASH computation for the last <16 Byte block
+ GHASH_MUL \AAD_HASH, %xmm13, %xmm0, %xmm10, %xmm11, %xmm5, %xmm6
+ xor %rax,%rax
+
+ mov %rax, PBlockLen(%arg2)
+ jmp _dec_done_\@
+_partial_incomplete_1_\@:
+ add \PLAIN_CYPH_LEN, PBlockLen(%arg2)
+_dec_done_\@:
+ movdqu \AAD_HASH, AadHash(%arg2)
+.else
+ pxor %xmm1, %xmm9 # Plaintext XOR E(K, Yn)
+
+ mov \PLAIN_CYPH_LEN, %r10
+ add %r13, %r10
+ # Set r10 to be the amount of data left in CYPH_PLAIN_IN after filling
+ sub $16, %r10
+ # Determine if if partial block is not being filled and
+ # shift mask accordingly
+ jge _no_extra_mask_2_\@
+ sub %r10, %r12
+_no_extra_mask_2_\@:
+
+ movdqu ALL_F-SHIFT_MASK(%r12), %xmm1
+ # get the appropriate mask to mask out bottom r13 bytes of xmm9
+ pand %xmm1, %xmm9
+
+ movdqa SHUF_MASK(%rip), %xmm1
+ PSHUFB_XMM %xmm1, %xmm9
+ PSHUFB_XMM %xmm2, %xmm9
+ pxor %xmm9, \AAD_HASH
+
+ cmp $0, %r10
+ jl _partial_incomplete_2_\@
+
+ # GHASH computation for the last <16 Byte block
+ GHASH_MUL \AAD_HASH, %xmm13, %xmm0, %xmm10, %xmm11, %xmm5, %xmm6
+ xor %rax,%rax
+
+ mov %rax, PBlockLen(%arg2)
+ jmp _encode_done_\@
+_partial_incomplete_2_\@:
+ add \PLAIN_CYPH_LEN, PBlockLen(%arg2)
+_encode_done_\@:
+ movdqu \AAD_HASH, AadHash(%arg2)
+
+ movdqa SHUF_MASK(%rip), %xmm10
+ # shuffle xmm9 back to output as ciphertext
+ PSHUFB_XMM %xmm10, %xmm9
+ PSHUFB_XMM %xmm2, %xmm9
.endif
- cmp $64, %r13
- jl _initial_blocks_done\num_initial_blocks\operation
- # no need for precomputed values
-/*
-*
-* Precomputations for HashKey parallel with encryption of first 4 blocks.
-* Haskey_i_k holds XORed values of the low and high parts of the Haskey_i
-*/
- MOVADQ ONE(%rip), \TMP1
- paddd \TMP1, \XMM0 # INCR Y0
- MOVADQ \XMM0, \XMM1
- PSHUFB_XMM %xmm14, \XMM1 # perform a 16 byte swap
-
- paddd \TMP1, \XMM0 # INCR Y0
- MOVADQ \XMM0, \XMM2
- PSHUFB_XMM %xmm14, \XMM2 # perform a 16 byte swap
-
- paddd \TMP1, \XMM0 # INCR Y0
- MOVADQ \XMM0, \XMM3
- PSHUFB_XMM %xmm14, \XMM3 # perform a 16 byte swap
-
- paddd \TMP1, \XMM0 # INCR Y0
- MOVADQ \XMM0, \XMM4
- PSHUFB_XMM %xmm14, \XMM4 # perform a 16 byte swap
-
- MOVADQ 0(%arg1),\TMP1
- pxor \TMP1, \XMM1
- pxor \TMP1, \XMM2
- pxor \TMP1, \XMM3
- pxor \TMP1, \XMM4
- movdqa \TMP3, \TMP5
- pshufd $78, \TMP3, \TMP1
- pxor \TMP3, \TMP1
- movdqa \TMP1, HashKey_k(%rsp)
- GHASH_MUL \TMP5, \TMP3, \TMP1, \TMP2, \TMP4, \TMP6, \TMP7
-# TMP5 = HashKey^2<<1 (mod poly)
- movdqa \TMP5, HashKey_2(%rsp)
-# HashKey_2 = HashKey^2<<1 (mod poly)
- pshufd $78, \TMP5, \TMP1
- pxor \TMP5, \TMP1
- movdqa \TMP1, HashKey_2_k(%rsp)
-.irpc index, 1234 # do 4 rounds
- movaps 0x10*\index(%arg1), \TMP1
- AESENC \TMP1, \XMM1
- AESENC \TMP1, \XMM2
- AESENC \TMP1, \XMM3
- AESENC \TMP1, \XMM4
-.endr
- GHASH_MUL \TMP5, \TMP3, \TMP1, \TMP2, \TMP4, \TMP6, \TMP7
-# TMP5 = HashKey^3<<1 (mod poly)
- movdqa \TMP5, HashKey_3(%rsp)
- pshufd $78, \TMP5, \TMP1
- pxor \TMP5, \TMP1
- movdqa \TMP1, HashKey_3_k(%rsp)
-.irpc index, 56789 # do next 5 rounds
- movaps 0x10*\index(%arg1), \TMP1
- AESENC \TMP1, \XMM1
- AESENC \TMP1, \XMM2
- AESENC \TMP1, \XMM3
- AESENC \TMP1, \XMM4
-.endr
- GHASH_MUL \TMP5, \TMP3, \TMP1, \TMP2, \TMP4, \TMP6, \TMP7
-# TMP5 = HashKey^3<<1 (mod poly)
- movdqa \TMP5, HashKey_4(%rsp)
- pshufd $78, \TMP5, \TMP1
- pxor \TMP5, \TMP1
- movdqa \TMP1, HashKey_4_k(%rsp)
- lea 0xa0(%arg1),%r10
- mov keysize,%eax
- shr $2,%eax # 128->4, 192->6, 256->8
- sub $4,%eax # 128->0, 192->2, 256->4
- jz aes_loop_pre_dec_done\num_initial_blocks
-
-aes_loop_pre_dec\num_initial_blocks:
- MOVADQ (%r10),\TMP2
-.irpc index, 1234
- AESENC \TMP2, %xmm\index
-.endr
- add $16,%r10
- sub $1,%eax
- jnz aes_loop_pre_dec\num_initial_blocks
-
-aes_loop_pre_dec_done\num_initial_blocks:
- MOVADQ (%r10), \TMP2
- AESENCLAST \TMP2, \XMM1
- AESENCLAST \TMP2, \XMM2
- AESENCLAST \TMP2, \XMM3
- AESENCLAST \TMP2, \XMM4
- movdqu 16*0(%arg3 , %r11 , 1), \TMP1
- pxor \TMP1, \XMM1
- movdqu \XMM1, 16*0(%arg2 , %r11 , 1)
- movdqa \TMP1, \XMM1
- movdqu 16*1(%arg3 , %r11 , 1), \TMP1
- pxor \TMP1, \XMM2
- movdqu \XMM2, 16*1(%arg2 , %r11 , 1)
- movdqa \TMP1, \XMM2
- movdqu 16*2(%arg3 , %r11 , 1), \TMP1
- pxor \TMP1, \XMM3
- movdqu \XMM3, 16*2(%arg2 , %r11 , 1)
- movdqa \TMP1, \XMM3
- movdqu 16*3(%arg3 , %r11 , 1), \TMP1
- pxor \TMP1, \XMM4
- movdqu \XMM4, 16*3(%arg2 , %r11 , 1)
- movdqa \TMP1, \XMM4
- add $64, %r11
- PSHUFB_XMM %xmm14, \XMM1 # perform a 16 byte swap
- pxor \XMMDst, \XMM1
-# combine GHASHed value with the corresponding ciphertext
- PSHUFB_XMM %xmm14, \XMM2 # perform a 16 byte swap
- PSHUFB_XMM %xmm14, \XMM3 # perform a 16 byte swap
- PSHUFB_XMM %xmm14, \XMM4 # perform a 16 byte swap
-
-_initial_blocks_done\num_initial_blocks\operation:
-
-.endm
+ # output encrypted Bytes
+ cmp $0, %r10
+ jl _partial_fill_\@
+ mov %r13, %r12
+ mov $16, %r13
+ # Set r13 to be the number of bytes to write out
+ sub %r12, %r13
+ jmp _count_set_\@
+_partial_fill_\@:
+ mov \PLAIN_CYPH_LEN, %r13
+_count_set_\@:
+ movdqa %xmm9, %xmm0
+ MOVQ_R64_XMM %xmm0, %rax
+ cmp $8, %r13
+ jle _less_than_8_bytes_left_\@
+ mov %rax, (\CYPH_PLAIN_OUT, \DATA_OFFSET, 1)
+ add $8, \DATA_OFFSET
+ psrldq $8, %xmm0
+ MOVQ_R64_XMM %xmm0, %rax
+ sub $8, %r13
+_less_than_8_bytes_left_\@:
+ movb %al, (\CYPH_PLAIN_OUT, \DATA_OFFSET, 1)
+ add $1, \DATA_OFFSET
+ shr $8, %rax
+ sub $1, %r13
+ jne _less_than_8_bytes_left_\@
+_partial_block_done_\@:
+.endm # PARTIAL_BLOCK
/*
* if a = number of total plaintext bytes
@@ -499,49 +789,19 @@ _initial_blocks_done\num_initial_blocks\operation:
* the ciphertext
* %r10, %r11, %r12, %rax, %xmm5, %xmm6, %xmm7, %xmm8, %xmm9 registers
* are clobbered
-* arg1, %arg2, %arg3, %r14 are used as a pointer only, not modified
+* arg1, %arg2, %arg3 are used as a pointer only, not modified
*/
-.macro INITIAL_BLOCKS_ENC num_initial_blocks TMP1 TMP2 TMP3 TMP4 TMP5 XMM0 XMM1 \
-XMM2 XMM3 XMM4 XMMDst TMP6 TMP7 i i_seq operation
- MOVADQ SHUF_MASK(%rip), %xmm14
- mov arg7, %r10 # %r10 = AAD
- mov arg8, %r11 # %r11 = aadLen
- pxor %xmm\i, %xmm\i
- pxor \XMM2, \XMM2
+.macro INITIAL_BLOCKS_ENC_DEC TMP1 TMP2 TMP3 TMP4 TMP5 XMM0 XMM1 \
+ XMM2 XMM3 XMM4 XMMDst TMP6 TMP7 i i_seq operation
+ MOVADQ SHUF_MASK(%rip), %xmm14
- cmp $16, %r11
- jl _get_AAD_rest\num_initial_blocks\operation
-_get_AAD_blocks\num_initial_blocks\operation:
- movdqu (%r10), %xmm\i
- PSHUFB_XMM %xmm14, %xmm\i # byte-reflect the AAD data
- pxor %xmm\i, \XMM2
- GHASH_MUL \XMM2, \TMP3, \TMP1, \TMP2, \TMP4, \TMP5, \XMM1
- add $16, %r10
- sub $16, %r11
- cmp $16, %r11
- jge _get_AAD_blocks\num_initial_blocks\operation
+ movdqu AadHash(%arg2), %xmm\i # XMM0 = Y0
- movdqu \XMM2, %xmm\i
-
- /* read the last <16B of AAD */
-_get_AAD_rest\num_initial_blocks\operation:
- cmp $0, %r11
- je _get_AAD_done\num_initial_blocks\operation
-
- READ_PARTIAL_BLOCK %r10, %r11, \TMP1, %xmm\i
- PSHUFB_XMM %xmm14, %xmm\i # byte-reflect the AAD data
- pxor \XMM2, %xmm\i
- GHASH_MUL %xmm\i, \TMP3, \TMP1, \TMP2, \TMP4, \TMP5, \XMM1
-
-_get_AAD_done\num_initial_blocks\operation:
- xor %r11, %r11 # initialise the data pointer offset as zero
# start AES for num_initial_blocks blocks
- mov %arg5, %rax # %rax = *Y0
- movdqu (%rax), \XMM0 # XMM0 = Y0
- PSHUFB_XMM %xmm14, \XMM0
+ movdqu CurCount(%arg2), \XMM0 # XMM0 = Y0
.if (\i == 5) || (\i == 6) || (\i == 7)
@@ -549,7 +809,11 @@ _get_AAD_done\num_initial_blocks\operation:
MOVADQ 0(%arg1),\TMP2
.irpc index, \i_seq
paddd \TMP1, \XMM0 # INCR Y0
+.ifc \operation, dec
+ movdqa \XMM0, %xmm\index
+.else
MOVADQ \XMM0, %xmm\index
+.endif
PSHUFB_XMM %xmm14, %xmm\index # perform a 16 byte swap
pxor \TMP2, %xmm\index
.endr
@@ -558,25 +822,29 @@ _get_AAD_done\num_initial_blocks\operation:
shr $2,%eax # 128->4, 192->6, 256->8
add $5,%eax # 128->9, 192->11, 256->13
-aes_loop_initial_enc\num_initial_blocks:
+aes_loop_initial_\@:
MOVADQ (%r10),\TMP1
.irpc index, \i_seq
AESENC \TMP1, %xmm\index
.endr
add $16,%r10
sub $1,%eax
- jnz aes_loop_initial_enc\num_initial_blocks
+ jnz aes_loop_initial_\@
MOVADQ (%r10), \TMP1
.irpc index, \i_seq
AESENCLAST \TMP1, %xmm\index # Last Round
.endr
.irpc index, \i_seq
- movdqu (%arg3 , %r11, 1), \TMP1
+ movdqu (%arg4 , %r11, 1), \TMP1
pxor \TMP1, %xmm\index
- movdqu %xmm\index, (%arg2 , %r11, 1)
+ movdqu %xmm\index, (%arg3 , %r11, 1)
# write back plaintext/ciphertext for num_initial_blocks
add $16, %r11
+
+.ifc \operation, dec
+ movdqa \TMP1, %xmm\index
+.endif
PSHUFB_XMM %xmm14, %xmm\index
# prepare plaintext/ciphertext for GHASH computation
@@ -602,7 +870,7 @@ aes_loop_initial_enc\num_initial_blocks:
GHASH_MUL %xmm8, \TMP3, \TMP1, \TMP2, \TMP4, \TMP5, \XMM1
.endif
cmp $64, %r13
- jl _initial_blocks_done\num_initial_blocks\operation
+ jl _initial_blocks_done\@
# no need for precomputed values
/*
*
@@ -631,17 +899,6 @@ aes_loop_initial_enc\num_initial_blocks:
pxor \TMP1, \XMM2
pxor \TMP1, \XMM3
pxor \TMP1, \XMM4
- movdqa \TMP3, \TMP5
- pshufd $78, \TMP3, \TMP1
- pxor \TMP3, \TMP1
- movdqa \TMP1, HashKey_k(%rsp)
- GHASH_MUL \TMP5, \TMP3, \TMP1, \TMP2, \TMP4, \TMP6, \TMP7
-# TMP5 = HashKey^2<<1 (mod poly)
- movdqa \TMP5, HashKey_2(%rsp)
-# HashKey_2 = HashKey^2<<1 (mod poly)
- pshufd $78, \TMP5, \TMP1
- pxor \TMP5, \TMP1
- movdqa \TMP1, HashKey_2_k(%rsp)
.irpc index, 1234 # do 4 rounds
movaps 0x10*\index(%arg1), \TMP1
AESENC \TMP1, \XMM1
@@ -649,12 +906,6 @@ aes_loop_initial_enc\num_initial_blocks:
AESENC \TMP1, \XMM3
AESENC \TMP1, \XMM4
.endr
- GHASH_MUL \TMP5, \TMP3, \TMP1, \TMP2, \TMP4, \TMP6, \TMP7
-# TMP5 = HashKey^3<<1 (mod poly)
- movdqa \TMP5, HashKey_3(%rsp)
- pshufd $78, \TMP5, \TMP1
- pxor \TMP5, \TMP1
- movdqa \TMP1, HashKey_3_k(%rsp)
.irpc index, 56789 # do next 5 rounds
movaps 0x10*\index(%arg1), \TMP1
AESENC \TMP1, \XMM1
@@ -662,45 +913,56 @@ aes_loop_initial_enc\num_initial_blocks:
AESENC \TMP1, \XMM3
AESENC \TMP1, \XMM4
.endr
- GHASH_MUL \TMP5, \TMP3, \TMP1, \TMP2, \TMP4, \TMP6, \TMP7
-# TMP5 = HashKey^3<<1 (mod poly)
- movdqa \TMP5, HashKey_4(%rsp)
- pshufd $78, \TMP5, \TMP1
- pxor \TMP5, \TMP1
- movdqa \TMP1, HashKey_4_k(%rsp)
lea 0xa0(%arg1),%r10
mov keysize,%eax
shr $2,%eax # 128->4, 192->6, 256->8
sub $4,%eax # 128->0, 192->2, 256->4
- jz aes_loop_pre_enc_done\num_initial_blocks
+ jz aes_loop_pre_done\@
-aes_loop_pre_enc\num_initial_blocks:
+aes_loop_pre_\@:
MOVADQ (%r10),\TMP2
.irpc index, 1234
AESENC \TMP2, %xmm\index
.endr
add $16,%r10
sub $1,%eax
- jnz aes_loop_pre_enc\num_initial_blocks
+ jnz aes_loop_pre_\@
-aes_loop_pre_enc_done\num_initial_blocks:
+aes_loop_pre_done\@:
MOVADQ (%r10), \TMP2
AESENCLAST \TMP2, \XMM1
AESENCLAST \TMP2, \XMM2
AESENCLAST \TMP2, \XMM3
AESENCLAST \TMP2, \XMM4
- movdqu 16*0(%arg3 , %r11 , 1), \TMP1
+ movdqu 16*0(%arg4 , %r11 , 1), \TMP1
pxor \TMP1, \XMM1
- movdqu 16*1(%arg3 , %r11 , 1), \TMP1
+.ifc \operation, dec
+ movdqu \XMM1, 16*0(%arg3 , %r11 , 1)
+ movdqa \TMP1, \XMM1
+.endif
+ movdqu 16*1(%arg4 , %r11 , 1), \TMP1
pxor \TMP1, \XMM2
- movdqu 16*2(%arg3 , %r11 , 1), \TMP1
+.ifc \operation, dec
+ movdqu \XMM2, 16*1(%arg3 , %r11 , 1)
+ movdqa \TMP1, \XMM2
+.endif
+ movdqu 16*2(%arg4 , %r11 , 1), \TMP1
pxor \TMP1, \XMM3
- movdqu 16*3(%arg3 , %r11 , 1), \TMP1
+.ifc \operation, dec
+ movdqu \XMM3, 16*2(%arg3 , %r11 , 1)
+ movdqa \TMP1, \XMM3
+.endif
+ movdqu 16*3(%arg4 , %r11 , 1), \TMP1
pxor \TMP1, \XMM4
- movdqu \XMM1, 16*0(%arg2 , %r11 , 1)
- movdqu \XMM2, 16*1(%arg2 , %r11 , 1)
- movdqu \XMM3, 16*2(%arg2 , %r11 , 1)
- movdqu \XMM4, 16*3(%arg2 , %r11 , 1)
+.ifc \operation, dec
+ movdqu \XMM4, 16*3(%arg3 , %r11 , 1)
+ movdqa \TMP1, \XMM4
+.else
+ movdqu \XMM1, 16*0(%arg3 , %r11 , 1)
+ movdqu \XMM2, 16*1(%arg3 , %r11 , 1)
+ movdqu \XMM3, 16*2(%arg3 , %r11 , 1)
+ movdqu \XMM4, 16*3(%arg3 , %r11 , 1)
+.endif
add $64, %r11
PSHUFB_XMM %xmm14, \XMM1 # perform a 16 byte swap
@@ -710,14 +972,14 @@ aes_loop_pre_enc_done\num_initial_blocks:
PSHUFB_XMM %xmm14, \XMM3 # perform a 16 byte swap
PSHUFB_XMM %xmm14, \XMM4 # perform a 16 byte swap
-_initial_blocks_done\num_initial_blocks\operation:
+_initial_blocks_done\@:
.endm
/*
* encrypt 4 blocks at a time
* ghash the 4 previously encrypted ciphertext blocks
-* arg1, %arg2, %arg3 are used as pointers only, not modified
+* arg1, %arg3, %arg4 are used as pointers only, not modified
* %r11 is the data offset value
*/
.macro GHASH_4_ENCRYPT_4_PARALLEL_ENC TMP1 TMP2 TMP3 TMP4 TMP5 \
@@ -735,7 +997,7 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
pshufd $78, \XMM5, \TMP6
pxor \XMM5, \TMP6
paddd ONE(%rip), \XMM0 # INCR CNT
- movdqa HashKey_4(%rsp), \TMP5
+ movdqa HashKey_4(%arg2), \TMP5
PCLMULQDQ 0x11, \TMP5, \TMP4 # TMP4 = a1*b1
movdqa \XMM0, \XMM1
paddd ONE(%rip), \XMM0 # INCR CNT
@@ -754,7 +1016,7 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
pxor (%arg1), \XMM2
pxor (%arg1), \XMM3
pxor (%arg1), \XMM4
- movdqa HashKey_4_k(%rsp), \TMP5
+ movdqa HashKey_4_k(%arg2), \TMP5
PCLMULQDQ 0x00, \TMP5, \TMP6 # TMP6 = (a1+a0)*(b1+b0)
movaps 0x10(%arg1), \TMP1
AESENC \TMP1, \XMM1 # Round 1
@@ -769,7 +1031,7 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
movdqa \XMM6, \TMP1
pshufd $78, \XMM6, \TMP2
pxor \XMM6, \TMP2
- movdqa HashKey_3(%rsp), \TMP5
+ movdqa HashKey_3(%arg2), \TMP5
PCLMULQDQ 0x11, \TMP5, \TMP1 # TMP1 = a1 * b1
movaps 0x30(%arg1), \TMP3
AESENC \TMP3, \XMM1 # Round 3
@@ -782,7 +1044,7 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
AESENC \TMP3, \XMM2
AESENC \TMP3, \XMM3
AESENC \TMP3, \XMM4
- movdqa HashKey_3_k(%rsp), \TMP5
+ movdqa HashKey_3_k(%arg2), \TMP5
PCLMULQDQ 0x00, \TMP5, \TMP2 # TMP2 = (a1+a0)*(b1+b0)
movaps 0x50(%arg1), \TMP3
AESENC \TMP3, \XMM1 # Round 5
@@ -796,7 +1058,7 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
movdqa \XMM7, \TMP1
pshufd $78, \XMM7, \TMP2
pxor \XMM7, \TMP2
- movdqa HashKey_2(%rsp ), \TMP5
+ movdqa HashKey_2(%arg2), \TMP5
# Multiply TMP5 * HashKey using karatsuba
@@ -812,7 +1074,7 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
AESENC \TMP3, \XMM2
AESENC \TMP3, \XMM3
AESENC \TMP3, \XMM4
- movdqa HashKey_2_k(%rsp), \TMP5
+ movdqa HashKey_2_k(%arg2), \TMP5
PCLMULQDQ 0x00, \TMP5, \TMP2 # TMP2 = (a1+a0)*(b1+b0)
movaps 0x80(%arg1), \TMP3
AESENC \TMP3, \XMM1 # Round 8
@@ -830,7 +1092,7 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
movdqa \XMM8, \TMP1
pshufd $78, \XMM8, \TMP2
pxor \XMM8, \TMP2
- movdqa HashKey(%rsp), \TMP5
+ movdqa HashKey(%arg2), \TMP5
PCLMULQDQ 0x11, \TMP5, \TMP1 # TMP1 = a1*b1
movaps 0x90(%arg1), \TMP3
AESENC \TMP3, \XMM1 # Round 9
@@ -842,37 +1104,37 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
mov keysize,%eax
shr $2,%eax # 128->4, 192->6, 256->8
sub $4,%eax # 128->0, 192->2, 256->4
- jz aes_loop_par_enc_done
+ jz aes_loop_par_enc_done\@
-aes_loop_par_enc:
+aes_loop_par_enc\@:
MOVADQ (%r10),\TMP3
.irpc index, 1234
AESENC \TMP3, %xmm\index
.endr
add $16,%r10
sub $1,%eax
- jnz aes_loop_par_enc
+ jnz aes_loop_par_enc\@
-aes_loop_par_enc_done:
+aes_loop_par_enc_done\@:
MOVADQ (%r10), \TMP3
AESENCLAST \TMP3, \XMM1 # Round 10
AESENCLAST \TMP3, \XMM2
AESENCLAST \TMP3, \XMM3
AESENCLAST \TMP3, \XMM4
- movdqa HashKey_k(%rsp), \TMP5
+ movdqa HashKey_k(%arg2), \TMP5
PCLMULQDQ 0x00, \TMP5, \TMP2 # TMP2 = (a1+a0)*(b1+b0)
- movdqu (%arg3,%r11,1), \TMP3
+ movdqu (%arg4,%r11,1), \TMP3
pxor \TMP3, \XMM1 # Ciphertext/Plaintext XOR EK
- movdqu 16(%arg3,%r11,1), \TMP3
+ movdqu 16(%arg4,%r11,1), \TMP3
pxor \TMP3, \XMM2 # Ciphertext/Plaintext XOR EK
- movdqu 32(%arg3,%r11,1), \TMP3
+ movdqu 32(%arg4,%r11,1), \TMP3
pxor \TMP3, \XMM3 # Ciphertext/Plaintext XOR EK
- movdqu 48(%arg3,%r11,1), \TMP3
+ movdqu 48(%arg4,%r11,1), \TMP3
pxor \TMP3, \XMM4 # Ciphertext/Plaintext XOR EK
- movdqu \XMM1, (%arg2,%r11,1) # Write to the ciphertext buffer
- movdqu \XMM2, 16(%arg2,%r11,1) # Write to the ciphertext buffer
- movdqu \XMM3, 32(%arg2,%r11,1) # Write to the ciphertext buffer
- movdqu \XMM4, 48(%arg2,%r11,1) # Write to the ciphertext buffer
+ movdqu \XMM1, (%arg3,%r11,1) # Write to the ciphertext buffer
+ movdqu \XMM2, 16(%arg3,%r11,1) # Write to the ciphertext buffer
+ movdqu \XMM3, 32(%arg3,%r11,1) # Write to the ciphertext buffer
+ movdqu \XMM4, 48(%arg3,%r11,1) # Write to the ciphertext buffer
PSHUFB_XMM %xmm15, \XMM1 # perform a 16 byte swap
PSHUFB_XMM %xmm15, \XMM2 # perform a 16 byte swap
PSHUFB_XMM %xmm15, \XMM3 # perform a 16 byte swap
@@ -925,7 +1187,7 @@ aes_loop_par_enc_done:
/*
* decrypt 4 blocks at a time
* ghash the 4 previously decrypted ciphertext blocks
-* arg1, %arg2, %arg3 are used as pointers only, not modified
+* arg1, %arg3, %arg4 are used as pointers only, not modified
* %r11 is the data offset value
*/
.macro GHASH_4_ENCRYPT_4_PARALLEL_DEC TMP1 TMP2 TMP3 TMP4 TMP5 \
@@ -943,7 +1205,7 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
pshufd $78, \XMM5, \TMP6
pxor \XMM5, \TMP6
paddd ONE(%rip), \XMM0 # INCR CNT
- movdqa HashKey_4(%rsp), \TMP5
+ movdqa HashKey_4(%arg2), \TMP5
PCLMULQDQ 0x11, \TMP5, \TMP4 # TMP4 = a1*b1
movdqa \XMM0, \XMM1
paddd ONE(%rip), \XMM0 # INCR CNT
@@ -962,7 +1224,7 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
pxor (%arg1), \XMM2
pxor (%arg1), \XMM3
pxor (%arg1), \XMM4
- movdqa HashKey_4_k(%rsp), \TMP5
+ movdqa HashKey_4_k(%arg2), \TMP5
PCLMULQDQ 0x00, \TMP5, \TMP6 # TMP6 = (a1+a0)*(b1+b0)
movaps 0x10(%arg1), \TMP1
AESENC \TMP1, \XMM1 # Round 1
@@ -977,7 +1239,7 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
movdqa \XMM6, \TMP1
pshufd $78, \XMM6, \TMP2
pxor \XMM6, \TMP2
- movdqa HashKey_3(%rsp), \TMP5
+ movdqa HashKey_3(%arg2), \TMP5
PCLMULQDQ 0x11, \TMP5, \TMP1 # TMP1 = a1 * b1
movaps 0x30(%arg1), \TMP3
AESENC \TMP3, \XMM1 # Round 3
@@ -990,7 +1252,7 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
AESENC \TMP3, \XMM2
AESENC \TMP3, \XMM3
AESENC \TMP3, \XMM4
- movdqa HashKey_3_k(%rsp), \TMP5
+ movdqa HashKey_3_k(%arg2), \TMP5
PCLMULQDQ 0x00, \TMP5, \TMP2 # TMP2 = (a1+a0)*(b1+b0)
movaps 0x50(%arg1), \TMP3
AESENC \TMP3, \XMM1 # Round 5
@@ -1004,7 +1266,7 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
movdqa \XMM7, \TMP1
pshufd $78, \XMM7, \TMP2
pxor \XMM7, \TMP2
- movdqa HashKey_2(%rsp ), \TMP5
+ movdqa HashKey_2(%arg2), \TMP5
# Multiply TMP5 * HashKey using karatsuba
@@ -1020,7 +1282,7 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
AESENC \TMP3, \XMM2
AESENC \TMP3, \XMM3
AESENC \TMP3, \XMM4
- movdqa HashKey_2_k(%rsp), \TMP5
+ movdqa HashKey_2_k(%arg2), \TMP5
PCLMULQDQ 0x00, \TMP5, \TMP2 # TMP2 = (a1+a0)*(b1+b0)
movaps 0x80(%arg1), \TMP3
AESENC \TMP3, \XMM1 # Round 8
@@ -1038,7 +1300,7 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
movdqa \XMM8, \TMP1
pshufd $78, \XMM8, \TMP2
pxor \XMM8, \TMP2
- movdqa HashKey(%rsp), \TMP5
+ movdqa HashKey(%arg2), \TMP5
PCLMULQDQ 0x11, \TMP5, \TMP1 # TMP1 = a1*b1
movaps 0x90(%arg1), \TMP3
AESENC \TMP3, \XMM1 # Round 9
@@ -1050,40 +1312,40 @@ TMP6 XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 XMM8 operation
mov keysize,%eax
shr $2,%eax # 128->4, 192->6, 256->8
sub $4,%eax # 128->0, 192->2, 256->4
- jz aes_loop_par_dec_done
+ jz aes_loop_par_dec_done\@
-aes_loop_par_dec:
+aes_loop_par_dec\@:
MOVADQ (%r10),\TMP3
.irpc index, 1234
AESENC \TMP3, %xmm\index
.endr
add $16,%r10
sub $1,%eax
- jnz aes_loop_par_dec
+ jnz aes_loop_par_dec\@
-aes_loop_par_dec_done:
+aes_loop_par_dec_done\@:
MOVADQ (%r10), \TMP3
AESENCLAST \TMP3, \XMM1 # last round
AESENCLAST \TMP3, \XMM2
AESENCLAST \TMP3, \XMM3
AESENCLAST \TMP3, \XMM4
- movdqa HashKey_k(%rsp), \TMP5
+ movdqa HashKey_k(%arg2), \TMP5
PCLMULQDQ 0x00, \TMP5, \TMP2 # TMP2 = (a1+a0)*(b1+b0)
- movdqu (%arg3,%r11,1), \TMP3
+ movdqu (%arg4,%r11,1), \TMP3
pxor \TMP3, \XMM1 # Ciphertext/Plaintext XOR EK
- movdqu \XMM1, (%arg2,%r11,1) # Write to plaintext buffer
+ movdqu \XMM1, (%arg3,%r11,1) # Write to plaintext buffer
movdqa \TMP3, \XMM1
- movdqu 16(%arg3,%r11,1), \TMP3
+ movdqu 16(%arg4,%r11,1), \TMP3
pxor \TMP3, \XMM2 # Ciphertext/Plaintext XOR EK
- movdqu \XMM2, 16(%arg2,%r11,1) # Write to plaintext buffer
+ movdqu \XMM2, 16(%arg3,%r11,1) # Write to plaintext buffer
movdqa \TMP3, \XMM2
- movdqu 32(%arg3,%r11,1), \TMP3
+ movdqu 32(%arg4,%r11,1), \TMP3
pxor \TMP3, \XMM3 # Ciphertext/Plaintext XOR EK
- movdqu \XMM3, 32(%arg2,%r11,1) # Write to plaintext buffer
+ movdqu \XMM3, 32(%arg3,%r11,1) # Write to plaintext buffer
movdqa \TMP3, \XMM3
- movdqu 48(%arg3,%r11,1), \TMP3
+ movdqu 48(%arg4,%r11,1), \TMP3
pxor \TMP3, \XMM4 # Ciphertext/Plaintext XOR EK
- movdqu \XMM4, 48(%arg2,%r11,1) # Write to plaintext buffer
+ movdqu \XMM4, 48(%arg3,%r11,1) # Write to plaintext buffer
movdqa \TMP3, \XMM4
PSHUFB_XMM %xmm15, \XMM1 # perform a 16 byte swap
PSHUFB_XMM %xmm15, \XMM2 # perform a 16 byte swap
@@ -1143,10 +1405,10 @@ TMP7 XMM1 XMM2 XMM3 XMM4 XMMDst
movdqa \XMM1, \TMP6
pshufd $78, \XMM1, \TMP2
pxor \XMM1, \TMP2
- movdqa HashKey_4(%rsp), \TMP5
+ movdqa HashKey_4(%arg2), \TMP5
PCLMULQDQ 0x11, \TMP5, \TMP6 # TMP6 = a1*b1
PCLMULQDQ 0x00, \TMP5, \XMM1 # XMM1 = a0*b0
- movdqa HashKey_4_k(%rsp), \TMP4
+ movdqa HashKey_4_k(%arg2), \TMP4
PCLMULQDQ 0x00, \TMP4, \TMP2 # TMP2 = (a1+a0)*(b1+b0)
movdqa \XMM1, \XMMDst
movdqa \TMP2, \XMM1 # result in TMP6, XMMDst, XMM1
@@ -1156,10 +1418,10 @@ TMP7 XMM1 XMM2 XMM3 XMM4 XMMDst
movdqa \XMM2, \TMP1
pshufd $78, \XMM2, \TMP2
pxor \XMM2, \TMP2
- movdqa HashKey_3(%rsp), \TMP5
+ movdqa HashKey_3(%arg2), \TMP5
PCLMULQDQ 0x11, \TMP5, \TMP1 # TMP1 = a1*b1
PCLMULQDQ 0x00, \TMP5, \XMM2 # XMM2 = a0*b0
- movdqa HashKey_3_k(%rsp), \TMP4
+ movdqa HashKey_3_k(%arg2), \TMP4
PCLMULQDQ 0x00, \TMP4, \TMP2 # TMP2 = (a1+a0)*(b1+b0)
pxor \TMP1, \TMP6
pxor \XMM2, \XMMDst
@@ -1171,10 +1433,10 @@ TMP7 XMM1 XMM2 XMM3 XMM4 XMMDst
movdqa \XMM3, \TMP1
pshufd $78, \XMM3, \TMP2
pxor \XMM3, \TMP2
- movdqa HashKey_2(%rsp), \TMP5
+ movdqa HashKey_2(%arg2), \TMP5
PCLMULQDQ 0x11, \TMP5, \TMP1 # TMP1 = a1*b1
PCLMULQDQ 0x00, \TMP5, \XMM3 # XMM3 = a0*b0
- movdqa HashKey_2_k(%rsp), \TMP4
+ movdqa HashKey_2_k(%arg2), \TMP4
PCLMULQDQ 0x00, \TMP4, \TMP2 # TMP2 = (a1+a0)*(b1+b0)
pxor \TMP1, \TMP6
pxor \XMM3, \XMMDst
@@ -1184,10 +1446,10 @@ TMP7 XMM1 XMM2 XMM3 XMM4 XMMDst
movdqa \XMM4, \TMP1
pshufd $78, \XMM4, \TMP2
pxor \XMM4, \TMP2
- movdqa HashKey(%rsp), \TMP5
+ movdqa HashKey(%arg2), \TMP5
PCLMULQDQ 0x11, \TMP5, \TMP1 # TMP1 = a1*b1
PCLMULQDQ 0x00, \TMP5, \XMM4 # XMM4 = a0*b0
- movdqa HashKey_k(%rsp), \TMP4
+ movdqa HashKey_k(%arg2), \TMP4
PCLMULQDQ 0x00, \TMP4, \TMP2 # TMP2 = (a1+a0)*(b1+b0)
pxor \TMP1, \TMP6
pxor \XMM4, \XMMDst
@@ -1256,6 +1518,8 @@ _esb_loop_\@:
.endm
/*****************************************************************************
* void aesni_gcm_dec(void *aes_ctx, // AES Key schedule. Starts on a 16 byte boundary.
+* struct gcm_context_data *data
+* // Context data
* u8 *out, // Plaintext output. Encrypt in-place is allowed.
* const u8 *in, // Ciphertext input
* u64 plaintext_len, // Length of data in bytes for decryption.
@@ -1333,195 +1597,20 @@ _esb_loop_\@:
*
*****************************************************************************/
ENTRY(aesni_gcm_dec)
- push %r12
- push %r13
- push %r14
- mov %rsp, %r14
-/*
-* states of %xmm registers %xmm6:%xmm15 not saved
-* all %xmm registers are clobbered
-*/
- sub $VARIABLE_OFFSET, %rsp
- and $~63, %rsp # align rsp to 64 bytes
- mov %arg6, %r12
- movdqu (%r12), %xmm13 # %xmm13 = HashKey
- movdqa SHUF_MASK(%rip), %xmm2
- PSHUFB_XMM %xmm2, %xmm13
-
-
-# Precompute HashKey<<1 (mod poly) from the hash key (required for GHASH)
-
- movdqa %xmm13, %xmm2
- psllq $1, %xmm13
- psrlq $63, %xmm2
- movdqa %xmm2, %xmm1
- pslldq $8, %xmm2
- psrldq $8, %xmm1
- por %xmm2, %xmm13
-
- # Reduction
-
- pshufd $0x24, %xmm1, %xmm2
- pcmpeqd TWOONE(%rip), %xmm2
- pand POLY(%rip), %xmm2
- pxor %xmm2, %xmm13 # %xmm13 holds the HashKey<<1 (mod poly)
-
-
- # Decrypt first few blocks
-
- movdqa %xmm13, HashKey(%rsp) # store HashKey<<1 (mod poly)
- mov %arg4, %r13 # save the number of bytes of plaintext/ciphertext
- and $-16, %r13 # %r13 = %r13 - (%r13 mod 16)
- mov %r13, %r12
- and $(3<<4), %r12
- jz _initial_num_blocks_is_0_decrypt
- cmp $(2<<4), %r12
- jb _initial_num_blocks_is_1_decrypt
- je _initial_num_blocks_is_2_decrypt
-_initial_num_blocks_is_3_decrypt:
- INITIAL_BLOCKS_DEC 3, %xmm9, %xmm10, %xmm13, %xmm11, %xmm12, %xmm0, \
-%xmm1, %xmm2, %xmm3, %xmm4, %xmm8, %xmm5, %xmm6, 5, 678, dec
- sub $48, %r13
- jmp _initial_blocks_decrypted
-_initial_num_blocks_is_2_decrypt:
- INITIAL_BLOCKS_DEC 2, %xmm9, %xmm10, %xmm13, %xmm11, %xmm12, %xmm0, \
-%xmm1, %xmm2, %xmm3, %xmm4, %xmm8, %xmm5, %xmm6, 6, 78, dec
- sub $32, %r13
- jmp _initial_blocks_decrypted
-_initial_num_blocks_is_1_decrypt:
- INITIAL_BLOCKS_DEC 1, %xmm9, %xmm10, %xmm13, %xmm11, %xmm12, %xmm0, \
-%xmm1, %xmm2, %xmm3, %xmm4, %xmm8, %xmm5, %xmm6, 7, 8, dec
- sub $16, %r13
- jmp _initial_blocks_decrypted
-_initial_num_blocks_is_0_decrypt:
- INITIAL_BLOCKS_DEC 0, %xmm9, %xmm10, %xmm13, %xmm11, %xmm12, %xmm0, \
-%xmm1, %xmm2, %xmm3, %xmm4, %xmm8, %xmm5, %xmm6, 8, 0, dec
-_initial_blocks_decrypted:
- cmp $0, %r13
- je _zero_cipher_left_decrypt
- sub $64, %r13
- je _four_cipher_left_decrypt
-_decrypt_by_4:
- GHASH_4_ENCRYPT_4_PARALLEL_DEC %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, \
-%xmm14, %xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7, %xmm8, dec
- add $64, %r11
- sub $64, %r13
- jne _decrypt_by_4
-_four_cipher_left_decrypt:
- GHASH_LAST_4 %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, \
-%xmm15, %xmm1, %xmm2, %xmm3, %xmm4, %xmm8
-_zero_cipher_left_decrypt:
- mov %arg4, %r13
- and $15, %r13 # %r13 = arg4 (mod 16)
- je _multiple_of_16_bytes_decrypt
-
- # Handle the last <16 byte block separately
-
- paddd ONE(%rip), %xmm0 # increment CNT to get Yn
- movdqa SHUF_MASK(%rip), %xmm10
- PSHUFB_XMM %xmm10, %xmm0
-
- ENCRYPT_SINGLE_BLOCK %xmm0, %xmm1 # E(K, Yn)
-
- lea (%arg3,%r11,1), %r10
- mov %r13, %r12
- READ_PARTIAL_BLOCK %r10 %r12 %xmm2 %xmm1
-
- lea ALL_F+16(%rip), %r12
- sub %r13, %r12
- movdqa %xmm1, %xmm2
- pxor %xmm1, %xmm0 # Ciphertext XOR E(K, Yn)
- movdqu (%r12), %xmm1
- # get the appropriate mask to mask out top 16-%r13 bytes of %xmm0
- pand %xmm1, %xmm0 # mask out top 16-%r13 bytes of %xmm0
- pand %xmm1, %xmm2
- movdqa SHUF_MASK(%rip), %xmm10
- PSHUFB_XMM %xmm10 ,%xmm2
-
- pxor %xmm2, %xmm8
- GHASH_MUL %xmm8, %xmm13, %xmm9, %xmm10, %xmm11, %xmm5, %xmm6
-
- # output %r13 bytes
- MOVQ_R64_XMM %xmm0, %rax
- cmp $8, %r13
- jle _less_than_8_bytes_left_decrypt
- mov %rax, (%arg2 , %r11, 1)
- add $8, %r11
- psrldq $8, %xmm0
- MOVQ_R64_XMM %xmm0, %rax
- sub $8, %r13
-_less_than_8_bytes_left_decrypt:
- mov %al, (%arg2, %r11, 1)
- add $1, %r11
- shr $8, %rax
- sub $1, %r13
- jne _less_than_8_bytes_left_decrypt
-_multiple_of_16_bytes_decrypt:
- mov arg8, %r12 # %r13 = aadLen (number of bytes)
- shl $3, %r12 # convert into number of bits
- movd %r12d, %xmm15 # len(A) in %xmm15
- shl $3, %arg4 # len(C) in bits (*128)
- MOVQ_R64_XMM %arg4, %xmm1
- pslldq $8, %xmm15 # %xmm15 = len(A)||0x0000000000000000
- pxor %xmm1, %xmm15 # %xmm15 = len(A)||len(C)
- pxor %xmm15, %xmm8
- GHASH_MUL %xmm8, %xmm13, %xmm9, %xmm10, %xmm11, %xmm5, %xmm6
- # final GHASH computation
- movdqa SHUF_MASK(%rip), %xmm10
- PSHUFB_XMM %xmm10, %xmm8
+ FUNC_SAVE
- mov %arg5, %rax # %rax = *Y0
- movdqu (%rax), %xmm0 # %xmm0 = Y0
- ENCRYPT_SINGLE_BLOCK %xmm0, %xmm1 # E(K, Y0)
- pxor %xmm8, %xmm0
-_return_T_decrypt:
- mov arg9, %r10 # %r10 = authTag
- mov arg10, %r11 # %r11 = auth_tag_len
- cmp $16, %r11
- je _T_16_decrypt
- cmp $8, %r11
- jl _T_4_decrypt
-_T_8_decrypt:
- MOVQ_R64_XMM %xmm0, %rax
- mov %rax, (%r10)
- add $8, %r10
- sub $8, %r11
- psrldq $8, %xmm0
- cmp $0, %r11
- je _return_T_done_decrypt
-_T_4_decrypt:
- movd %xmm0, %eax
- mov %eax, (%r10)
- add $4, %r10
- sub $4, %r11
- psrldq $4, %xmm0
- cmp $0, %r11
- je _return_T_done_decrypt
-_T_123_decrypt:
- movd %xmm0, %eax
- cmp $2, %r11
- jl _T_1_decrypt
- mov %ax, (%r10)
- cmp $2, %r11
- je _return_T_done_decrypt
- add $2, %r10
- sar $16, %eax
-_T_1_decrypt:
- mov %al, (%r10)
- jmp _return_T_done_decrypt
-_T_16_decrypt:
- movdqu %xmm0, (%r10)
-_return_T_done_decrypt:
- mov %r14, %rsp
- pop %r14
- pop %r13
- pop %r12
+ GCM_INIT %arg6, arg7, arg8, arg9
+ GCM_ENC_DEC dec
+ GCM_COMPLETE arg10, arg11
+ FUNC_RESTORE
ret
ENDPROC(aesni_gcm_dec)
/*****************************************************************************
* void aesni_gcm_enc(void *aes_ctx, // AES Key schedule. Starts on a 16 byte boundary.
+* struct gcm_context_data *data
+* // Context data
* u8 *out, // Ciphertext output. Encrypt in-place is allowed.
* const u8 *in, // Plaintext input
* u64 plaintext_len, // Length of data in bytes for encryption.
@@ -1596,195 +1685,78 @@ ENDPROC(aesni_gcm_dec)
* poly = x^128 + x^127 + x^126 + x^121 + 1
***************************************************************************/
ENTRY(aesni_gcm_enc)
- push %r12
- push %r13
- push %r14
- mov %rsp, %r14
-#
-# states of %xmm registers %xmm6:%xmm15 not saved
-# all %xmm registers are clobbered
-#
- sub $VARIABLE_OFFSET, %rsp
- and $~63, %rsp
- mov %arg6, %r12
- movdqu (%r12), %xmm13
- movdqa SHUF_MASK(%rip), %xmm2
- PSHUFB_XMM %xmm2, %xmm13
-
-
-# precompute HashKey<<1 mod poly from the HashKey (required for GHASH)
-
- movdqa %xmm13, %xmm2
- psllq $1, %xmm13
- psrlq $63, %xmm2
- movdqa %xmm2, %xmm1
- pslldq $8, %xmm2
- psrldq $8, %xmm1
- por %xmm2, %xmm13
-
- # reduce HashKey<<1
-
- pshufd $0x24, %xmm1, %xmm2
- pcmpeqd TWOONE(%rip), %xmm2
- pand POLY(%rip), %xmm2
- pxor %xmm2, %xmm13
- movdqa %xmm13, HashKey(%rsp)
- mov %arg4, %r13 # %xmm13 holds HashKey<<1 (mod poly)
- and $-16, %r13
- mov %r13, %r12
+ FUNC_SAVE
- # Encrypt first few blocks
+ GCM_INIT %arg6, arg7, arg8, arg9
+ GCM_ENC_DEC enc
- and $(3<<4), %r12
- jz _initial_num_blocks_is_0_encrypt
- cmp $(2<<4), %r12
- jb _initial_num_blocks_is_1_encrypt
- je _initial_num_blocks_is_2_encrypt
-_initial_num_blocks_is_3_encrypt:
- INITIAL_BLOCKS_ENC 3, %xmm9, %xmm10, %xmm13, %xmm11, %xmm12, %xmm0, \
-%xmm1, %xmm2, %xmm3, %xmm4, %xmm8, %xmm5, %xmm6, 5, 678, enc
- sub $48, %r13
- jmp _initial_blocks_encrypted
-_initial_num_blocks_is_2_encrypt:
- INITIAL_BLOCKS_ENC 2, %xmm9, %xmm10, %xmm13, %xmm11, %xmm12, %xmm0, \
-%xmm1, %xmm2, %xmm3, %xmm4, %xmm8, %xmm5, %xmm6, 6, 78, enc
- sub $32, %r13
- jmp _initial_blocks_encrypted
-_initial_num_blocks_is_1_encrypt:
- INITIAL_BLOCKS_ENC 1, %xmm9, %xmm10, %xmm13, %xmm11, %xmm12, %xmm0, \
-%xmm1, %xmm2, %xmm3, %xmm4, %xmm8, %xmm5, %xmm6, 7, 8, enc
- sub $16, %r13
- jmp _initial_blocks_encrypted
-_initial_num_blocks_is_0_encrypt:
- INITIAL_BLOCKS_ENC 0, %xmm9, %xmm10, %xmm13, %xmm11, %xmm12, %xmm0, \
-%xmm1, %xmm2, %xmm3, %xmm4, %xmm8, %xmm5, %xmm6, 8, 0, enc
-_initial_blocks_encrypted:
-
- # Main loop - Encrypt remaining blocks
-
- cmp $0, %r13
- je _zero_cipher_left_encrypt
- sub $64, %r13
- je _four_cipher_left_encrypt
-_encrypt_by_4_encrypt:
- GHASH_4_ENCRYPT_4_PARALLEL_ENC %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, \
-%xmm14, %xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6, %xmm7, %xmm8, enc
- add $64, %r11
- sub $64, %r13
- jne _encrypt_by_4_encrypt
-_four_cipher_left_encrypt:
- GHASH_LAST_4 %xmm9, %xmm10, %xmm11, %xmm12, %xmm13, %xmm14, \
-%xmm15, %xmm1, %xmm2, %xmm3, %xmm4, %xmm8
-_zero_cipher_left_encrypt:
- mov %arg4, %r13
- and $15, %r13 # %r13 = arg4 (mod 16)
- je _multiple_of_16_bytes_encrypt
-
- # Handle the last <16 Byte block separately
- paddd ONE(%rip), %xmm0 # INCR CNT to get Yn
- movdqa SHUF_MASK(%rip), %xmm10
- PSHUFB_XMM %xmm10, %xmm0
-
- ENCRYPT_SINGLE_BLOCK %xmm0, %xmm1 # Encrypt(K, Yn)
-
- lea (%arg3,%r11,1), %r10
- mov %r13, %r12
- READ_PARTIAL_BLOCK %r10 %r12 %xmm2 %xmm1
-
- lea ALL_F+16(%rip), %r12
- sub %r13, %r12
- pxor %xmm1, %xmm0 # Plaintext XOR Encrypt(K, Yn)
- movdqu (%r12), %xmm1
- # get the appropriate mask to mask out top 16-r13 bytes of xmm0
- pand %xmm1, %xmm0 # mask out top 16-r13 bytes of xmm0
- movdqa SHUF_MASK(%rip), %xmm10
- PSHUFB_XMM %xmm10,%xmm0
+ GCM_COMPLETE arg10, arg11
+ FUNC_RESTORE
+ ret
+ENDPROC(aesni_gcm_enc)
- pxor %xmm0, %xmm8
- GHASH_MUL %xmm8, %xmm13, %xmm9, %xmm10, %xmm11, %xmm5, %xmm6
- # GHASH computation for the last <16 byte block
- movdqa SHUF_MASK(%rip), %xmm10
- PSHUFB_XMM %xmm10, %xmm0
+/*****************************************************************************
+* void aesni_gcm_init(void *aes_ctx, // AES Key schedule. Starts on a 16 byte boundary.
+* struct gcm_context_data *data,
+* // context data
+* u8 *iv, // Pre-counter block j0: 4 byte salt (from Security Association)
+* // concatenated with 8 byte Initialisation Vector (from IPSec ESP Payload)
+* // concatenated with 0x00000001. 16-byte aligned pointer.
+* u8 *hash_subkey, // H, the Hash sub key input. Data starts on a 16-byte boundary.
+* const u8 *aad, // Additional Authentication Data (AAD)
+* u64 aad_len) // Length of AAD in bytes.
+*/
+ENTRY(aesni_gcm_init)
+ FUNC_SAVE
+ GCM_INIT %arg3, %arg4,%arg5, %arg6
+ FUNC_RESTORE
+ ret
+ENDPROC(aesni_gcm_init)
- # shuffle xmm0 back to output as ciphertext
+/*****************************************************************************
+* void aesni_gcm_enc_update(void *aes_ctx, // AES Key schedule. Starts on a 16 byte boundary.
+* struct gcm_context_data *data,
+* // context data
+* u8 *out, // Ciphertext output. Encrypt in-place is allowed.
+* const u8 *in, // Plaintext input
+* u64 plaintext_len, // Length of data in bytes for encryption.
+*/
+ENTRY(aesni_gcm_enc_update)
+ FUNC_SAVE
+ GCM_ENC_DEC enc
+ FUNC_RESTORE
+ ret
+ENDPROC(aesni_gcm_enc_update)
- # Output %r13 bytes
- MOVQ_R64_XMM %xmm0, %rax
- cmp $8, %r13
- jle _less_than_8_bytes_left_encrypt
- mov %rax, (%arg2 , %r11, 1)
- add $8, %r11
- psrldq $8, %xmm0
- MOVQ_R64_XMM %xmm0, %rax
- sub $8, %r13
-_less_than_8_bytes_left_encrypt:
- mov %al, (%arg2, %r11, 1)
- add $1, %r11
- shr $8, %rax
- sub $1, %r13
- jne _less_than_8_bytes_left_encrypt
-_multiple_of_16_bytes_encrypt:
- mov arg8, %r12 # %r12 = addLen (number of bytes)
- shl $3, %r12
- movd %r12d, %xmm15 # len(A) in %xmm15
- shl $3, %arg4 # len(C) in bits (*128)
- MOVQ_R64_XMM %arg4, %xmm1
- pslldq $8, %xmm15 # %xmm15 = len(A)||0x0000000000000000
- pxor %xmm1, %xmm15 # %xmm15 = len(A)||len(C)
- pxor %xmm15, %xmm8
- GHASH_MUL %xmm8, %xmm13, %xmm9, %xmm10, %xmm11, %xmm5, %xmm6
- # final GHASH computation
- movdqa SHUF_MASK(%rip), %xmm10
- PSHUFB_XMM %xmm10, %xmm8 # perform a 16 byte swap
+/*****************************************************************************
+* void aesni_gcm_dec_update(void *aes_ctx, // AES Key schedule. Starts on a 16 byte boundary.
+* struct gcm_context_data *data,
+* // context data
+* u8 *out, // Ciphertext output. Encrypt in-place is allowed.
+* const u8 *in, // Plaintext input
+* u64 plaintext_len, // Length of data in bytes for encryption.
+*/
+ENTRY(aesni_gcm_dec_update)
+ FUNC_SAVE
+ GCM_ENC_DEC dec
+ FUNC_RESTORE
+ ret
+ENDPROC(aesni_gcm_dec_update)
- mov %arg5, %rax # %rax = *Y0
- movdqu (%rax), %xmm0 # %xmm0 = Y0
- ENCRYPT_SINGLE_BLOCK %xmm0, %xmm15 # Encrypt(K, Y0)
- pxor %xmm8, %xmm0
-_return_T_encrypt:
- mov arg9, %r10 # %r10 = authTag
- mov arg10, %r11 # %r11 = auth_tag_len
- cmp $16, %r11
- je _T_16_encrypt
- cmp $8, %r11
- jl _T_4_encrypt
-_T_8_encrypt:
- MOVQ_R64_XMM %xmm0, %rax
- mov %rax, (%r10)
- add $8, %r10
- sub $8, %r11
- psrldq $8, %xmm0
- cmp $0, %r11
- je _return_T_done_encrypt
-_T_4_encrypt:
- movd %xmm0, %eax
- mov %eax, (%r10)
- add $4, %r10
- sub $4, %r11
- psrldq $4, %xmm0
- cmp $0, %r11
- je _return_T_done_encrypt
-_T_123_encrypt:
- movd %xmm0, %eax
- cmp $2, %r11
- jl _T_1_encrypt
- mov %ax, (%r10)
- cmp $2, %r11
- je _return_T_done_encrypt
- add $2, %r10
- sar $16, %eax
-_T_1_encrypt:
- mov %al, (%r10)
- jmp _return_T_done_encrypt
-_T_16_encrypt:
- movdqu %xmm0, (%r10)
-_return_T_done_encrypt:
- mov %r14, %rsp
- pop %r14
- pop %r13
- pop %r12
+/*****************************************************************************
+* void aesni_gcm_finalize(void *aes_ctx, // AES Key schedule. Starts on a 16 byte boundary.
+* struct gcm_context_data *data,
+* // context data
+* u8 *auth_tag, // Authenticated Tag output.
+* u64 auth_tag_len); // Authenticated Tag Length in bytes. Valid values are 16 (most likely),
+* // 12 or 8.
+*/
+ENTRY(aesni_gcm_finalize)
+ FUNC_SAVE
+ GCM_COMPLETE %arg3 %arg4
+ FUNC_RESTORE
ret
-ENDPROC(aesni_gcm_enc)
+ENDPROC(aesni_gcm_finalize)
#endif
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
index 34cf1c1f8c98..acbe7e8336d8 100644
--- a/arch/x86/crypto/aesni-intel_glue.c
+++ b/arch/x86/crypto/aesni-intel_glue.c
@@ -72,6 +72,21 @@ struct aesni_xts_ctx {
u8 raw_crypt_ctx[sizeof(struct crypto_aes_ctx)] AESNI_ALIGN_ATTR;
};
+#define GCM_BLOCK_LEN 16
+
+struct gcm_context_data {
+ /* init, update and finalize context data */
+ u8 aad_hash[GCM_BLOCK_LEN];
+ u64 aad_length;
+ u64 in_length;
+ u8 partial_block_enc_key[GCM_BLOCK_LEN];
+ u8 orig_IV[GCM_BLOCK_LEN];
+ u8 current_counter[GCM_BLOCK_LEN];
+ u64 partial_block_len;
+ u64 unused;
+ u8 hash_keys[GCM_BLOCK_LEN * 8];
+};
+
asmlinkage int aesni_set_key(struct crypto_aes_ctx *ctx, const u8 *in_key,
unsigned int key_len);
asmlinkage void aesni_enc(struct crypto_aes_ctx *ctx, u8 *out,
@@ -105,6 +120,7 @@ asmlinkage void aesni_xts_crypt8(struct crypto_aes_ctx *ctx, u8 *out,
/* asmlinkage void aesni_gcm_enc()
* void *ctx, AES Key schedule. Starts on a 16 byte boundary.
+ * struct gcm_context_data. May be uninitialized.
* u8 *out, Ciphertext output. Encrypt in-place is allowed.
* const u8 *in, Plaintext input
* unsigned long plaintext_len, Length of data in bytes for encryption.
@@ -117,13 +133,15 @@ asmlinkage void aesni_xts_crypt8(struct crypto_aes_ctx *ctx, u8 *out,
* unsigned long auth_tag_len), Authenticated Tag Length in bytes.
* Valid values are 16 (most likely), 12 or 8.
*/
-asmlinkage void aesni_gcm_enc(void *ctx, u8 *out,
+asmlinkage void aesni_gcm_enc(void *ctx,
+ struct gcm_context_data *gdata, u8 *out,
const u8 *in, unsigned long plaintext_len, u8 *iv,
u8 *hash_subkey, const u8 *aad, unsigned long aad_len,
u8 *auth_tag, unsigned long auth_tag_len);
/* asmlinkage void aesni_gcm_dec()
* void *ctx, AES Key schedule. Starts on a 16 byte boundary.
+ * struct gcm_context_data. May be uninitialized.
* u8 *out, Plaintext output. Decrypt in-place is allowed.
* const u8 *in, Ciphertext input
* unsigned long ciphertext_len, Length of data in bytes for decryption.
@@ -137,11 +155,28 @@ asmlinkage void aesni_gcm_enc(void *ctx, u8 *out,
* unsigned long auth_tag_len) Authenticated Tag Length in bytes.
* Valid values are 16 (most likely), 12 or 8.
*/
-asmlinkage void aesni_gcm_dec(void *ctx, u8 *out,
+asmlinkage void aesni_gcm_dec(void *ctx,
+ struct gcm_context_data *gdata, u8 *out,
const u8 *in, unsigned long ciphertext_len, u8 *iv,
u8 *hash_subkey, const u8 *aad, unsigned long aad_len,
u8 *auth_tag, unsigned long auth_tag_len);
+/* Scatter / Gather routines, with args similar to above */
+asmlinkage void aesni_gcm_init(void *ctx,
+ struct gcm_context_data *gdata,
+ u8 *iv,
+ u8 *hash_subkey, const u8 *aad,
+ unsigned long aad_len);
+asmlinkage void aesni_gcm_enc_update(void *ctx,
+ struct gcm_context_data *gdata, u8 *out,
+ const u8 *in, unsigned long plaintext_len);
+asmlinkage void aesni_gcm_dec_update(void *ctx,
+ struct gcm_context_data *gdata, u8 *out,
+ const u8 *in,
+ unsigned long ciphertext_len);
+asmlinkage void aesni_gcm_finalize(void *ctx,
+ struct gcm_context_data *gdata,
+ u8 *auth_tag, unsigned long auth_tag_len);
#ifdef CONFIG_AS_AVX
asmlinkage void aes_ctr_enc_128_avx_by8(const u8 *in, u8 *iv,
@@ -167,15 +202,17 @@ asmlinkage void aesni_gcm_dec_avx_gen2(void *ctx, u8 *out,
const u8 *aad, unsigned long aad_len,
u8 *auth_tag, unsigned long auth_tag_len);
-static void aesni_gcm_enc_avx(void *ctx, u8 *out,
+static void aesni_gcm_enc_avx(void *ctx,
+ struct gcm_context_data *data, u8 *out,
const u8 *in, unsigned long plaintext_len, u8 *iv,
u8 *hash_subkey, const u8 *aad, unsigned long aad_len,
u8 *auth_tag, unsigned long auth_tag_len)
{
struct crypto_aes_ctx *aes_ctx = (struct crypto_aes_ctx*)ctx;
if ((plaintext_len < AVX_GEN2_OPTSIZE) || (aes_ctx-> key_length != AES_KEYSIZE_128)){
- aesni_gcm_enc(ctx, out, in, plaintext_len, iv, hash_subkey, aad,
- aad_len, auth_tag, auth_tag_len);
+ aesni_gcm_enc(ctx, data, out, in,
+ plaintext_len, iv, hash_subkey, aad,
+ aad_len, auth_tag, auth_tag_len);
} else {
aesni_gcm_precomp_avx_gen2(ctx, hash_subkey);
aesni_gcm_enc_avx_gen2(ctx, out, in, plaintext_len, iv, aad,
@@ -183,15 +220,17 @@ static void aesni_gcm_enc_avx(void *ctx, u8 *out,
}
}
-static void aesni_gcm_dec_avx(void *ctx, u8 *out,
+static void aesni_gcm_dec_avx(void *ctx,
+ struct gcm_context_data *data, u8 *out,
const u8 *in, unsigned long ciphertext_len, u8 *iv,
u8 *hash_subkey, const u8 *aad, unsigned long aad_len,
u8 *auth_tag, unsigned long auth_tag_len)
{
struct crypto_aes_ctx *aes_ctx = (struct crypto_aes_ctx*)ctx;
if ((ciphertext_len < AVX_GEN2_OPTSIZE) || (aes_ctx-> key_length != AES_KEYSIZE_128)) {
- aesni_gcm_dec(ctx, out, in, ciphertext_len, iv, hash_subkey, aad,
- aad_len, auth_tag, auth_tag_len);
+ aesni_gcm_dec(ctx, data, out, in,
+ ciphertext_len, iv, hash_subkey, aad,
+ aad_len, auth_tag, auth_tag_len);
} else {
aesni_gcm_precomp_avx_gen2(ctx, hash_subkey);
aesni_gcm_dec_avx_gen2(ctx, out, in, ciphertext_len, iv, aad,
@@ -218,15 +257,17 @@ asmlinkage void aesni_gcm_dec_avx_gen4(void *ctx, u8 *out,
const u8 *aad, unsigned long aad_len,
u8 *auth_tag, unsigned long auth_tag_len);
-static void aesni_gcm_enc_avx2(void *ctx, u8 *out,
+static void aesni_gcm_enc_avx2(void *ctx,
+ struct gcm_context_data *data, u8 *out,
const u8 *in, unsigned long plaintext_len, u8 *iv,
u8 *hash_subkey, const u8 *aad, unsigned long aad_len,
u8 *auth_tag, unsigned long auth_tag_len)
{
struct crypto_aes_ctx *aes_ctx = (struct crypto_aes_ctx*)ctx;
if ((plaintext_len < AVX_GEN2_OPTSIZE) || (aes_ctx-> key_length != AES_KEYSIZE_128)) {
- aesni_gcm_enc(ctx, out, in, plaintext_len, iv, hash_subkey, aad,
- aad_len, auth_tag, auth_tag_len);
+ aesni_gcm_enc(ctx, data, out, in,
+ plaintext_len, iv, hash_subkey, aad,
+ aad_len, auth_tag, auth_tag_len);
} else if (plaintext_len < AVX_GEN4_OPTSIZE) {
aesni_gcm_precomp_avx_gen2(ctx, hash_subkey);
aesni_gcm_enc_avx_gen2(ctx, out, in, plaintext_len, iv, aad,
@@ -238,15 +279,17 @@ static void aesni_gcm_enc_avx2(void *ctx, u8 *out,
}
}
-static void aesni_gcm_dec_avx2(void *ctx, u8 *out,
+static void aesni_gcm_dec_avx2(void *ctx,
+ struct gcm_context_data *data, u8 *out,
const u8 *in, unsigned long ciphertext_len, u8 *iv,
u8 *hash_subkey, const u8 *aad, unsigned long aad_len,
u8 *auth_tag, unsigned long auth_tag_len)
{
struct crypto_aes_ctx *aes_ctx = (struct crypto_aes_ctx*)ctx;
if ((ciphertext_len < AVX_GEN2_OPTSIZE) || (aes_ctx-> key_length != AES_KEYSIZE_128)) {
- aesni_gcm_dec(ctx, out, in, ciphertext_len, iv, hash_subkey,
- aad, aad_len, auth_tag, auth_tag_len);
+ aesni_gcm_dec(ctx, data, out, in,
+ ciphertext_len, iv, hash_subkey,
+ aad, aad_len, auth_tag, auth_tag_len);
} else if (ciphertext_len < AVX_GEN4_OPTSIZE) {
aesni_gcm_precomp_avx_gen2(ctx, hash_subkey);
aesni_gcm_dec_avx_gen2(ctx, out, in, ciphertext_len, iv, aad,
@@ -259,15 +302,19 @@ static void aesni_gcm_dec_avx2(void *ctx, u8 *out,
}
#endif
-static void (*aesni_gcm_enc_tfm)(void *ctx, u8 *out,
- const u8 *in, unsigned long plaintext_len, u8 *iv,
- u8 *hash_subkey, const u8 *aad, unsigned long aad_len,
- u8 *auth_tag, unsigned long auth_tag_len);
+static void (*aesni_gcm_enc_tfm)(void *ctx,
+ struct gcm_context_data *data, u8 *out,
+ const u8 *in, unsigned long plaintext_len,
+ u8 *iv, u8 *hash_subkey, const u8 *aad,
+ unsigned long aad_len, u8 *auth_tag,
+ unsigned long auth_tag_len);
-static void (*aesni_gcm_dec_tfm)(void *ctx, u8 *out,
- const u8 *in, unsigned long ciphertext_len, u8 *iv,
- u8 *hash_subkey, const u8 *aad, unsigned long aad_len,
- u8 *auth_tag, unsigned long auth_tag_len);
+static void (*aesni_gcm_dec_tfm)(void *ctx,
+ struct gcm_context_data *data, u8 *out,
+ const u8 *in, unsigned long ciphertext_len,
+ u8 *iv, u8 *hash_subkey, const u8 *aad,
+ unsigned long aad_len, u8 *auth_tag,
+ unsigned long auth_tag_len);
static inline struct
aesni_rfc4106_gcm_ctx *aesni_rfc4106_gcm_ctx_get(struct crypto_aead *tfm)
@@ -744,6 +791,127 @@ static int generic_gcmaes_set_authsize(struct crypto_aead *tfm,
return 0;
}
+static int gcmaes_crypt_by_sg(bool enc, struct aead_request *req,
+ unsigned int assoclen, u8 *hash_subkey,
+ u8 *iv, void *aes_ctx)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ unsigned long auth_tag_len = crypto_aead_authsize(tfm);
+ struct gcm_context_data data AESNI_ALIGN_ATTR;
+ struct scatter_walk dst_sg_walk = {};
+ unsigned long left = req->cryptlen;
+ unsigned long len, srclen, dstlen;
+ struct scatter_walk assoc_sg_walk;
+ struct scatter_walk src_sg_walk;
+ struct scatterlist src_start[2];
+ struct scatterlist dst_start[2];
+ struct scatterlist *src_sg;
+ struct scatterlist *dst_sg;
+ u8 *src, *dst, *assoc;
+ u8 *assocmem = NULL;
+ u8 authTag[16];
+
+ if (!enc)
+ left -= auth_tag_len;
+
+ /* Linearize assoc, if not already linear */
+ if (req->src->length >= assoclen && req->src->length &&
+ (!PageHighMem(sg_page(req->src)) ||
+ req->src->offset + req->src->length < PAGE_SIZE)) {
+ scatterwalk_start(&assoc_sg_walk, req->src);
+ assoc = scatterwalk_map(&assoc_sg_walk);
+ } else {
+ /* assoc can be any length, so must be on heap */
+ assocmem = kmalloc(assoclen, GFP_ATOMIC);
+ if (unlikely(!assocmem))
+ return -ENOMEM;
+ assoc = assocmem;
+
+ scatterwalk_map_and_copy(assoc, req->src, 0, assoclen, 0);
+ }
+
+ src_sg = scatterwalk_ffwd(src_start, req->src, req->assoclen);
+ scatterwalk_start(&src_sg_walk, src_sg);
+ if (req->src != req->dst) {
+ dst_sg = scatterwalk_ffwd(dst_start, req->dst, req->assoclen);
+ scatterwalk_start(&dst_sg_walk, dst_sg);
+ }
+
+ kernel_fpu_begin();
+ aesni_gcm_init(aes_ctx, &data, iv,
+ hash_subkey, assoc, assoclen);
+ if (req->src != req->dst) {
+ while (left) {
+ src = scatterwalk_map(&src_sg_walk);
+ dst = scatterwalk_map(&dst_sg_walk);
+ srclen = scatterwalk_clamp(&src_sg_walk, left);
+ dstlen = scatterwalk_clamp(&dst_sg_walk, left);
+ len = min(srclen, dstlen);
+ if (len) {
+ if (enc)
+ aesni_gcm_enc_update(aes_ctx, &data,
+ dst, src, len);
+ else
+ aesni_gcm_dec_update(aes_ctx, &data,
+ dst, src, len);
+ }
+ left -= len;
+
+ scatterwalk_unmap(src);
+ scatterwalk_unmap(dst);
+ scatterwalk_advance(&src_sg_walk, len);
+ scatterwalk_advance(&dst_sg_walk, len);
+ scatterwalk_done(&src_sg_walk, 0, left);
+ scatterwalk_done(&dst_sg_walk, 1, left);
+ }
+ } else {
+ while (left) {
+ dst = src = scatterwalk_map(&src_sg_walk);
+ len = scatterwalk_clamp(&src_sg_walk, left);
+ if (len) {
+ if (enc)
+ aesni_gcm_enc_update(aes_ctx, &data,
+ src, src, len);
+ else
+ aesni_gcm_dec_update(aes_ctx, &data,
+ src, src, len);
+ }
+ left -= len;
+ scatterwalk_unmap(src);
+ scatterwalk_advance(&src_sg_walk, len);
+ scatterwalk_done(&src_sg_walk, 1, left);
+ }
+ }
+ aesni_gcm_finalize(aes_ctx, &data, authTag, auth_tag_len);
+ kernel_fpu_end();
+
+ if (!assocmem)
+ scatterwalk_unmap(assoc);
+ else
+ kfree(assocmem);
+
+ if (!enc) {
+ u8 authTagMsg[16];
+
+ /* Copy out original authTag */
+ scatterwalk_map_and_copy(authTagMsg, req->src,
+ req->assoclen + req->cryptlen -
+ auth_tag_len,
+ auth_tag_len, 0);
+
+ /* Compare generated tag with passed in tag. */
+ return crypto_memneq(authTagMsg, authTag, auth_tag_len) ?
+ -EBADMSG : 0;
+ }
+
+ /* Copy in the authTag */
+ scatterwalk_map_and_copy(authTag, req->dst,
+ req->assoclen + req->cryptlen,
+ auth_tag_len, 1);
+
+ return 0;
+}
+
static int gcmaes_encrypt(struct aead_request *req, unsigned int assoclen,
u8 *hash_subkey, u8 *iv, void *aes_ctx)
{
@@ -753,7 +921,14 @@ static int gcmaes_encrypt(struct aead_request *req, unsigned int assoclen,
unsigned long auth_tag_len = crypto_aead_authsize(tfm);
struct scatter_walk src_sg_walk;
struct scatter_walk dst_sg_walk = {};
+ struct gcm_context_data data AESNI_ALIGN_ATTR;
+ if (((struct crypto_aes_ctx *)aes_ctx)->key_length != AES_KEYSIZE_128 ||
+ aesni_gcm_enc_tfm == aesni_gcm_enc ||
+ req->cryptlen < AVX_GEN2_OPTSIZE) {
+ return gcmaes_crypt_by_sg(true, req, assoclen, hash_subkey, iv,
+ aes_ctx);
+ }
if (sg_is_last(req->src) &&
(!PageHighMem(sg_page(req->src)) ||
req->src->offset + req->src->length <= PAGE_SIZE) &&
@@ -782,7 +957,7 @@ static int gcmaes_encrypt(struct aead_request *req, unsigned int assoclen,
}
kernel_fpu_begin();
- aesni_gcm_enc_tfm(aes_ctx, dst, src, req->cryptlen, iv,
+ aesni_gcm_enc_tfm(aes_ctx, &data, dst, src, req->cryptlen, iv,
hash_subkey, assoc, assoclen,
dst + req->cryptlen, auth_tag_len);
kernel_fpu_end();
@@ -817,8 +992,15 @@ static int gcmaes_decrypt(struct aead_request *req, unsigned int assoclen,
u8 authTag[16];
struct scatter_walk src_sg_walk;
struct scatter_walk dst_sg_walk = {};
+ struct gcm_context_data data AESNI_ALIGN_ATTR;
int retval = 0;
+ if (((struct crypto_aes_ctx *)aes_ctx)->key_length != AES_KEYSIZE_128 ||
+ aesni_gcm_enc_tfm == aesni_gcm_enc ||
+ req->cryptlen < AVX_GEN2_OPTSIZE) {
+ return gcmaes_crypt_by_sg(false, req, assoclen, hash_subkey, iv,
+ aes_ctx);
+ }
tempCipherLen = (unsigned long)(req->cryptlen - auth_tag_len);
if (sg_is_last(req->src) &&
@@ -849,7 +1031,7 @@ static int gcmaes_decrypt(struct aead_request *req, unsigned int assoclen,
kernel_fpu_begin();
- aesni_gcm_dec_tfm(aes_ctx, dst, src, tempCipherLen, iv,
+ aesni_gcm_dec_tfm(aes_ctx, &data, dst, src, tempCipherLen, iv,
hash_subkey, assoc, assoclen,
authTag, auth_tag_len);
kernel_fpu_end();
diff --git a/arch/x86/crypto/blowfish_glue.c b/arch/x86/crypto/blowfish_glue.c
index f9eca34301e2..3e0c07cc9124 100644
--- a/arch/x86/crypto/blowfish_glue.c
+++ b/arch/x86/crypto/blowfish_glue.c
@@ -25,13 +25,13 @@
*
*/
-#include <asm/processor.h>
+#include <crypto/algapi.h>
#include <crypto/blowfish.h>
+#include <crypto/internal/skcipher.h>
#include <linux/crypto.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
-#include <crypto/algapi.h>
/* regular block cipher functions */
asmlinkage void __blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src,
@@ -77,20 +77,28 @@ static void blowfish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
blowfish_dec_blk(crypto_tfm_ctx(tfm), dst, src);
}
-static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
+static int blowfish_setkey_skcipher(struct crypto_skcipher *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ return blowfish_setkey(&tfm->base, key, keylen);
+}
+
+static int ecb_crypt(struct skcipher_request *req,
void (*fn)(struct bf_ctx *, u8 *, const u8 *),
void (*fn_4way)(struct bf_ctx *, u8 *, const u8 *))
{
- struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
unsigned int bsize = BF_BLOCK_SIZE;
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct bf_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
unsigned int nbytes;
int err;
- err = blkcipher_walk_virt(desc, walk);
+ err = skcipher_walk_virt(&walk, req, false);
- while ((nbytes = walk->nbytes)) {
- u8 *wsrc = walk->src.virt.addr;
- u8 *wdst = walk->dst.virt.addr;
+ while ((nbytes = walk.nbytes)) {
+ u8 *wsrc = walk.src.virt.addr;
+ u8 *wdst = walk.dst.virt.addr;
/* Process four block batch */
if (nbytes >= bsize * 4) {
@@ -116,34 +124,25 @@ static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
} while (nbytes >= bsize);
done:
- err = blkcipher_walk_done(desc, walk, nbytes);
+ err = skcipher_walk_done(&walk, nbytes);
}
return err;
}
-static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_encrypt(struct skcipher_request *req)
{
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_crypt(desc, &walk, blowfish_enc_blk, blowfish_enc_blk_4way);
+ return ecb_crypt(req, blowfish_enc_blk, blowfish_enc_blk_4way);
}
-static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_decrypt(struct skcipher_request *req)
{
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_crypt(desc, &walk, blowfish_dec_blk, blowfish_dec_blk_4way);
+ return ecb_crypt(req, blowfish_dec_blk, blowfish_dec_blk_4way);
}
-static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
+static unsigned int __cbc_encrypt(struct bf_ctx *ctx,
+ struct skcipher_walk *walk)
{
- struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
unsigned int bsize = BF_BLOCK_SIZE;
unsigned int nbytes = walk->nbytes;
u64 *src = (u64 *)walk->src.virt.addr;
@@ -164,27 +163,27 @@ static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
return nbytes;
}
-static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_encrypt(struct skcipher_request *req)
{
- struct blkcipher_walk walk;
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct bf_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
+ unsigned int nbytes;
int err;
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt(desc, &walk);
+ err = skcipher_walk_virt(&walk, req, false);
while ((nbytes = walk.nbytes)) {
- nbytes = __cbc_encrypt(desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
+ nbytes = __cbc_encrypt(ctx, &walk);
+ err = skcipher_walk_done(&walk, nbytes);
}
return err;
}
-static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
+static unsigned int __cbc_decrypt(struct bf_ctx *ctx,
+ struct skcipher_walk *walk)
{
- struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
unsigned int bsize = BF_BLOCK_SIZE;
unsigned int nbytes = walk->nbytes;
u64 *src = (u64 *)walk->src.virt.addr;
@@ -245,24 +244,25 @@ done:
return nbytes;
}
-static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_decrypt(struct skcipher_request *req)
{
- struct blkcipher_walk walk;
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct bf_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
+ unsigned int nbytes;
int err;
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt(desc, &walk);
+ err = skcipher_walk_virt(&walk, req, false);
while ((nbytes = walk.nbytes)) {
- nbytes = __cbc_decrypt(desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
+ nbytes = __cbc_decrypt(ctx, &walk);
+ err = skcipher_walk_done(&walk, nbytes);
}
return err;
}
-static void ctr_crypt_final(struct bf_ctx *ctx, struct blkcipher_walk *walk)
+static void ctr_crypt_final(struct bf_ctx *ctx, struct skcipher_walk *walk)
{
u8 *ctrblk = walk->iv;
u8 keystream[BF_BLOCK_SIZE];
@@ -276,10 +276,8 @@ static void ctr_crypt_final(struct bf_ctx *ctx, struct blkcipher_walk *walk)
crypto_inc(ctrblk, BF_BLOCK_SIZE);
}
-static unsigned int __ctr_crypt(struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
+static unsigned int __ctr_crypt(struct bf_ctx *ctx, struct skcipher_walk *walk)
{
- struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
unsigned int bsize = BF_BLOCK_SIZE;
unsigned int nbytes = walk->nbytes;
u64 *src = (u64 *)walk->src.virt.addr;
@@ -332,29 +330,30 @@ done:
return nbytes;
}
-static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ctr_crypt(struct skcipher_request *req)
{
- struct blkcipher_walk walk;
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct bf_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
+ unsigned int nbytes;
int err;
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt_block(desc, &walk, BF_BLOCK_SIZE);
+ err = skcipher_walk_virt(&walk, req, false);
while ((nbytes = walk.nbytes) >= BF_BLOCK_SIZE) {
- nbytes = __ctr_crypt(desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
+ nbytes = __ctr_crypt(ctx, &walk);
+ err = skcipher_walk_done(&walk, nbytes);
}
- if (walk.nbytes) {
- ctr_crypt_final(crypto_blkcipher_ctx(desc->tfm), &walk);
- err = blkcipher_walk_done(desc, &walk, 0);
+ if (nbytes) {
+ ctr_crypt_final(ctx, &walk);
+ err = skcipher_walk_done(&walk, 0);
}
return err;
}
-static struct crypto_alg bf_algs[4] = { {
+static struct crypto_alg bf_cipher_alg = {
.cra_name = "blowfish",
.cra_driver_name = "blowfish-asm",
.cra_priority = 200,
@@ -372,66 +371,50 @@ static struct crypto_alg bf_algs[4] = { {
.cia_decrypt = blowfish_decrypt,
}
}
-}, {
- .cra_name = "ecb(blowfish)",
- .cra_driver_name = "ecb-blowfish-asm",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = BF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct bf_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = BF_MIN_KEY_SIZE,
- .max_keysize = BF_MAX_KEY_SIZE,
- .setkey = blowfish_setkey,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
+};
+
+static struct skcipher_alg bf_skcipher_algs[] = {
+ {
+ .base.cra_name = "ecb(blowfish)",
+ .base.cra_driver_name = "ecb-blowfish-asm",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = BF_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct bf_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = BF_MIN_KEY_SIZE,
+ .max_keysize = BF_MAX_KEY_SIZE,
+ .setkey = blowfish_setkey_skcipher,
+ .encrypt = ecb_encrypt,
+ .decrypt = ecb_decrypt,
+ }, {
+ .base.cra_name = "cbc(blowfish)",
+ .base.cra_driver_name = "cbc-blowfish-asm",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = BF_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct bf_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = BF_MIN_KEY_SIZE,
+ .max_keysize = BF_MAX_KEY_SIZE,
+ .ivsize = BF_BLOCK_SIZE,
+ .setkey = blowfish_setkey_skcipher,
+ .encrypt = cbc_encrypt,
+ .decrypt = cbc_decrypt,
+ }, {
+ .base.cra_name = "ctr(blowfish)",
+ .base.cra_driver_name = "ctr-blowfish-asm",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct bf_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = BF_MIN_KEY_SIZE,
+ .max_keysize = BF_MAX_KEY_SIZE,
+ .ivsize = BF_BLOCK_SIZE,
+ .chunksize = BF_BLOCK_SIZE,
+ .setkey = blowfish_setkey_skcipher,
+ .encrypt = ctr_crypt,
+ .decrypt = ctr_crypt,
},
-}, {
- .cra_name = "cbc(blowfish)",
- .cra_driver_name = "cbc-blowfish-asm",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = BF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct bf_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = BF_MIN_KEY_SIZE,
- .max_keysize = BF_MAX_KEY_SIZE,
- .ivsize = BF_BLOCK_SIZE,
- .setkey = blowfish_setkey,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-}, {
- .cra_name = "ctr(blowfish)",
- .cra_driver_name = "ctr-blowfish-asm",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct bf_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = BF_MIN_KEY_SIZE,
- .max_keysize = BF_MAX_KEY_SIZE,
- .ivsize = BF_BLOCK_SIZE,
- .setkey = blowfish_setkey,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-} };
+};
static bool is_blacklisted_cpu(void)
{
@@ -456,6 +439,8 @@ MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
static int __init init(void)
{
+ int err;
+
if (!force && is_blacklisted_cpu()) {
printk(KERN_INFO
"blowfish-x86_64: performance on this CPU "
@@ -464,12 +449,23 @@ static int __init init(void)
return -ENODEV;
}
- return crypto_register_algs(bf_algs, ARRAY_SIZE(bf_algs));
+ err = crypto_register_alg(&bf_cipher_alg);
+ if (err)
+ return err;
+
+ err = crypto_register_skciphers(bf_skcipher_algs,
+ ARRAY_SIZE(bf_skcipher_algs));
+ if (err)
+ crypto_unregister_alg(&bf_cipher_alg);
+
+ return err;
}
static void __exit fini(void)
{
- crypto_unregister_algs(bf_algs, ARRAY_SIZE(bf_algs));
+ crypto_unregister_alg(&bf_cipher_alg);
+ crypto_unregister_skciphers(bf_skcipher_algs,
+ ARRAY_SIZE(bf_skcipher_algs));
}
module_init(init);
diff --git a/arch/x86/crypto/camellia_aesni_avx2_glue.c b/arch/x86/crypto/camellia_aesni_avx2_glue.c
index 60907c139c4e..d4992e458f92 100644
--- a/arch/x86/crypto/camellia_aesni_avx2_glue.c
+++ b/arch/x86/crypto/camellia_aesni_avx2_glue.c
@@ -10,18 +10,15 @@
*
*/
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/crypto.h>
-#include <linux/err.h>
-#include <crypto/ablk_helper.h>
-#include <crypto/algapi.h>
-#include <crypto/ctr.h>
-#include <crypto/lrw.h>
-#include <crypto/xts.h>
-#include <asm/fpu/api.h>
#include <asm/crypto/camellia.h>
#include <asm/crypto/glue_helper.h>
+#include <crypto/algapi.h>
+#include <crypto/internal/simd.h>
+#include <crypto/xts.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/types.h>
#define CAMELLIA_AESNI_PARALLEL_BLOCKS 16
#define CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS 32
@@ -150,413 +147,120 @@ static const struct common_glue_ctx camellia_dec_xts = {
} }
};
-static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int camellia_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
{
- return glue_ecb_crypt_128bit(&camellia_enc, desc, dst, src, nbytes);
+ return __camellia_setkey(crypto_skcipher_ctx(tfm), key, keylen,
+ &tfm->base.crt_flags);
}
-static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_encrypt(struct skcipher_request *req)
{
- return glue_ecb_crypt_128bit(&camellia_dec, desc, dst, src, nbytes);
+ return glue_ecb_req_128bit(&camellia_enc, req);
}
-static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(camellia_enc_blk), desc,
- dst, src, nbytes);
-}
-
-static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_cbc_decrypt_128bit(&camellia_dec_cbc, desc, dst, src,
- nbytes);
-}
-
-static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ctr_crypt_128bit(&camellia_ctr, desc, dst, src, nbytes);
-}
-
-static inline bool camellia_fpu_begin(bool fpu_enabled, unsigned int nbytes)
-{
- return glue_fpu_begin(CAMELLIA_BLOCK_SIZE,
- CAMELLIA_AESNI_PARALLEL_BLOCKS, NULL, fpu_enabled,
- nbytes);
-}
-
-static inline void camellia_fpu_end(bool fpu_enabled)
-{
- glue_fpu_end(fpu_enabled);
-}
-
-static int camellia_setkey(struct crypto_tfm *tfm, const u8 *in_key,
- unsigned int key_len)
-{
- return __camellia_setkey(crypto_tfm_ctx(tfm), in_key, key_len,
- &tfm->crt_flags);
-}
-
-struct crypt_priv {
- struct camellia_ctx *ctx;
- bool fpu_enabled;
-};
-
-static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+static int ecb_decrypt(struct skcipher_request *req)
{
- const unsigned int bsize = CAMELLIA_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = camellia_fpu_begin(ctx->fpu_enabled, nbytes);
-
- if (nbytes >= CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS * bsize) {
- camellia_ecb_enc_32way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS;
- nbytes -= bsize * CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS;
- }
-
- if (nbytes >= CAMELLIA_AESNI_PARALLEL_BLOCKS * bsize) {
- camellia_ecb_enc_16way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * CAMELLIA_AESNI_PARALLEL_BLOCKS;
- nbytes -= bsize * CAMELLIA_AESNI_PARALLEL_BLOCKS;
- }
-
- while (nbytes >= CAMELLIA_PARALLEL_BLOCKS * bsize) {
- camellia_enc_blk_2way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * CAMELLIA_PARALLEL_BLOCKS;
- nbytes -= bsize * CAMELLIA_PARALLEL_BLOCKS;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- camellia_enc_blk(ctx->ctx, srcdst, srcdst);
+ return glue_ecb_req_128bit(&camellia_dec, req);
}
-static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+static int cbc_encrypt(struct skcipher_request *req)
{
- const unsigned int bsize = CAMELLIA_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = camellia_fpu_begin(ctx->fpu_enabled, nbytes);
-
- if (nbytes >= CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS * bsize) {
- camellia_ecb_dec_32way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS;
- nbytes -= bsize * CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS;
- }
-
- if (nbytes >= CAMELLIA_AESNI_PARALLEL_BLOCKS * bsize) {
- camellia_ecb_dec_16way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * CAMELLIA_AESNI_PARALLEL_BLOCKS;
- nbytes -= bsize * CAMELLIA_AESNI_PARALLEL_BLOCKS;
- }
-
- while (nbytes >= CAMELLIA_PARALLEL_BLOCKS * bsize) {
- camellia_dec_blk_2way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * CAMELLIA_PARALLEL_BLOCKS;
- nbytes -= bsize * CAMELLIA_PARALLEL_BLOCKS;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- camellia_dec_blk(ctx->ctx, srcdst, srcdst);
+ return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(camellia_enc_blk),
+ req);
}
-static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_decrypt(struct skcipher_request *req)
{
- struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->camellia_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = encrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- camellia_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
+ return glue_cbc_decrypt_req_128bit(&camellia_dec_cbc, req);
}
-static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ctr_crypt(struct skcipher_request *req)
{
- struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->camellia_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = decrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- camellia_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
+ return glue_ctr_req_128bit(&camellia_ctr, req);
}
-static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int xts_encrypt(struct skcipher_request *req)
{
- struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct camellia_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
- return glue_xts_crypt_128bit(&camellia_enc_xts, desc, dst, src, nbytes,
- XTS_TWEAK_CAST(camellia_enc_blk),
- &ctx->tweak_ctx, &ctx->crypt_ctx);
+ return glue_xts_req_128bit(&camellia_enc_xts, req,
+ XTS_TWEAK_CAST(camellia_enc_blk),
+ &ctx->tweak_ctx, &ctx->crypt_ctx);
}
-static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int xts_decrypt(struct skcipher_request *req)
{
- struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct camellia_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
- return glue_xts_crypt_128bit(&camellia_dec_xts, desc, dst, src, nbytes,
- XTS_TWEAK_CAST(camellia_enc_blk),
- &ctx->tweak_ctx, &ctx->crypt_ctx);
+ return glue_xts_req_128bit(&camellia_dec_xts, req,
+ XTS_TWEAK_CAST(camellia_enc_blk),
+ &ctx->tweak_ctx, &ctx->crypt_ctx);
}
-static struct crypto_alg cmll_algs[10] = { {
- .cra_name = "__ecb-camellia-aesni-avx2",
- .cra_driver_name = "__driver-ecb-camellia-aesni-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct camellia_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .setkey = camellia_setkey,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
- },
-}, {
- .cra_name = "__cbc-camellia-aesni-avx2",
- .cra_driver_name = "__driver-cbc-camellia-aesni-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct camellia_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .setkey = camellia_setkey,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-}, {
- .cra_name = "__ctr-camellia-aesni-avx2",
- .cra_driver_name = "__driver-ctr-camellia-aesni-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct camellia_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = camellia_setkey,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-}, {
- .cra_name = "__lrw-camellia-aesni-avx2",
- .cra_driver_name = "__driver-lrw-camellia-aesni-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct camellia_lrw_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_exit = lrw_camellia_exit_tfm,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE +
- CAMELLIA_BLOCK_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE +
- CAMELLIA_BLOCK_SIZE,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = lrw_camellia_setkey,
- .encrypt = lrw_encrypt,
- .decrypt = lrw_decrypt,
- },
- },
-}, {
- .cra_name = "__xts-camellia-aesni-avx2",
- .cra_driver_name = "__driver-xts-camellia-aesni-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct camellia_xts_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE * 2,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE * 2,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = xts_camellia_setkey,
- .encrypt = xts_encrypt,
- .decrypt = xts_decrypt,
- },
- },
-}, {
- .cra_name = "ecb(camellia)",
- .cra_driver_name = "ecb-camellia-aesni-avx2",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "cbc(camellia)",
- .cra_driver_name = "cbc-camellia-aesni-avx2",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = __ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "ctr(camellia)",
- .cra_driver_name = "ctr-camellia-aesni-avx2",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_encrypt,
- .geniv = "chainiv",
- },
- },
-}, {
- .cra_name = "lrw(camellia)",
- .cra_driver_name = "lrw-camellia-aesni-avx2",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE +
- CAMELLIA_BLOCK_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE +
- CAMELLIA_BLOCK_SIZE,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "xts(camellia)",
- .cra_driver_name = "xts-camellia-aesni-avx2",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE * 2,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE * 2,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
+static struct skcipher_alg camellia_algs[] = {
+ {
+ .base.cra_name = "__ecb(camellia)",
+ .base.cra_driver_name = "__ecb-camellia-aesni-avx2",
+ .base.cra_priority = 500,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = CAMELLIA_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct camellia_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAMELLIA_MIN_KEY_SIZE,
+ .max_keysize = CAMELLIA_MAX_KEY_SIZE,
+ .setkey = camellia_setkey,
+ .encrypt = ecb_encrypt,
+ .decrypt = ecb_decrypt,
+ }, {
+ .base.cra_name = "__cbc(camellia)",
+ .base.cra_driver_name = "__cbc-camellia-aesni-avx2",
+ .base.cra_priority = 500,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = CAMELLIA_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct camellia_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAMELLIA_MIN_KEY_SIZE,
+ .max_keysize = CAMELLIA_MAX_KEY_SIZE,
+ .ivsize = CAMELLIA_BLOCK_SIZE,
+ .setkey = camellia_setkey,
+ .encrypt = cbc_encrypt,
+ .decrypt = cbc_decrypt,
+ }, {
+ .base.cra_name = "__ctr(camellia)",
+ .base.cra_driver_name = "__ctr-camellia-aesni-avx2",
+ .base.cra_priority = 500,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct camellia_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAMELLIA_MIN_KEY_SIZE,
+ .max_keysize = CAMELLIA_MAX_KEY_SIZE,
+ .ivsize = CAMELLIA_BLOCK_SIZE,
+ .chunksize = CAMELLIA_BLOCK_SIZE,
+ .setkey = camellia_setkey,
+ .encrypt = ctr_crypt,
+ .decrypt = ctr_crypt,
+ }, {
+ .base.cra_name = "__xts(camellia)",
+ .base.cra_driver_name = "__xts-camellia-aesni-avx2",
+ .base.cra_priority = 500,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = CAMELLIA_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct camellia_xts_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = 2 * CAMELLIA_MIN_KEY_SIZE,
+ .max_keysize = 2 * CAMELLIA_MAX_KEY_SIZE,
+ .ivsize = CAMELLIA_BLOCK_SIZE,
+ .setkey = xts_camellia_setkey,
+ .encrypt = xts_encrypt,
+ .decrypt = xts_decrypt,
},
-} };
+};
+
+static struct simd_skcipher_alg *camellia_simd_algs[ARRAY_SIZE(camellia_algs)];
static int __init camellia_aesni_init(void)
{
@@ -576,12 +280,15 @@ static int __init camellia_aesni_init(void)
return -ENODEV;
}
- return crypto_register_algs(cmll_algs, ARRAY_SIZE(cmll_algs));
+ return simd_register_skciphers_compat(camellia_algs,
+ ARRAY_SIZE(camellia_algs),
+ camellia_simd_algs);
}
static void __exit camellia_aesni_fini(void)
{
- crypto_unregister_algs(cmll_algs, ARRAY_SIZE(cmll_algs));
+ simd_unregister_skciphers(camellia_algs, ARRAY_SIZE(camellia_algs),
+ camellia_simd_algs);
}
module_init(camellia_aesni_init);
diff --git a/arch/x86/crypto/camellia_aesni_avx_glue.c b/arch/x86/crypto/camellia_aesni_avx_glue.c
index d96429da88eb..d09f6521466a 100644
--- a/arch/x86/crypto/camellia_aesni_avx_glue.c
+++ b/arch/x86/crypto/camellia_aesni_avx_glue.c
@@ -10,18 +10,15 @@
*
*/
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/crypto.h>
-#include <linux/err.h>
-#include <crypto/ablk_helper.h>
-#include <crypto/algapi.h>
-#include <crypto/ctr.h>
-#include <crypto/lrw.h>
-#include <crypto/xts.h>
-#include <asm/fpu/api.h>
#include <asm/crypto/camellia.h>
#include <asm/crypto/glue_helper.h>
+#include <crypto/algapi.h>
+#include <crypto/internal/simd.h>
+#include <crypto/xts.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/types.h>
#define CAMELLIA_AESNI_PARALLEL_BLOCKS 16
@@ -154,401 +151,142 @@ static const struct common_glue_ctx camellia_dec_xts = {
} }
};
-static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ecb_crypt_128bit(&camellia_enc, desc, dst, src, nbytes);
-}
-
-static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int camellia_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
{
- return glue_ecb_crypt_128bit(&camellia_dec, desc, dst, src, nbytes);
+ return __camellia_setkey(crypto_skcipher_ctx(tfm), key, keylen,
+ &tfm->base.crt_flags);
}
-static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_encrypt(struct skcipher_request *req)
{
- return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(camellia_enc_blk), desc,
- dst, src, nbytes);
+ return glue_ecb_req_128bit(&camellia_enc, req);
}
-static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_decrypt(struct skcipher_request *req)
{
- return glue_cbc_decrypt_128bit(&camellia_dec_cbc, desc, dst, src,
- nbytes);
+ return glue_ecb_req_128bit(&camellia_dec, req);
}
-static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_encrypt(struct skcipher_request *req)
{
- return glue_ctr_crypt_128bit(&camellia_ctr, desc, dst, src, nbytes);
+ return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(camellia_enc_blk),
+ req);
}
-static inline bool camellia_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+static int cbc_decrypt(struct skcipher_request *req)
{
- return glue_fpu_begin(CAMELLIA_BLOCK_SIZE,
- CAMELLIA_AESNI_PARALLEL_BLOCKS, NULL, fpu_enabled,
- nbytes);
+ return glue_cbc_decrypt_req_128bit(&camellia_dec_cbc, req);
}
-static inline void camellia_fpu_end(bool fpu_enabled)
+static int ctr_crypt(struct skcipher_request *req)
{
- glue_fpu_end(fpu_enabled);
+ return glue_ctr_req_128bit(&camellia_ctr, req);
}
-static int camellia_setkey(struct crypto_tfm *tfm, const u8 *in_key,
- unsigned int key_len)
+int xts_camellia_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
{
- return __camellia_setkey(crypto_tfm_ctx(tfm), in_key, key_len,
- &tfm->crt_flags);
+ struct camellia_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
+ u32 *flags = &tfm->base.crt_flags;
+ int err;
+
+ err = xts_verify_key(tfm, key, keylen);
+ if (err)
+ return err;
+
+ /* first half of xts-key is for crypt */
+ err = __camellia_setkey(&ctx->crypt_ctx, key, keylen / 2, flags);
+ if (err)
+ return err;
+
+ /* second half of xts-key is for tweak */
+ return __camellia_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2,
+ flags);
}
+EXPORT_SYMBOL_GPL(xts_camellia_setkey);
-struct crypt_priv {
- struct camellia_ctx *ctx;
- bool fpu_enabled;
-};
-
-static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+static int xts_encrypt(struct skcipher_request *req)
{
- const unsigned int bsize = CAMELLIA_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = camellia_fpu_begin(ctx->fpu_enabled, nbytes);
-
- if (nbytes >= CAMELLIA_AESNI_PARALLEL_BLOCKS * bsize) {
- camellia_ecb_enc_16way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * CAMELLIA_AESNI_PARALLEL_BLOCKS;
- nbytes -= bsize * CAMELLIA_AESNI_PARALLEL_BLOCKS;
- }
-
- while (nbytes >= CAMELLIA_PARALLEL_BLOCKS * bsize) {
- camellia_enc_blk_2way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * CAMELLIA_PARALLEL_BLOCKS;
- nbytes -= bsize * CAMELLIA_PARALLEL_BLOCKS;
- }
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct camellia_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- camellia_enc_blk(ctx->ctx, srcdst, srcdst);
+ return glue_xts_req_128bit(&camellia_enc_xts, req,
+ XTS_TWEAK_CAST(camellia_enc_blk),
+ &ctx->tweak_ctx, &ctx->crypt_ctx);
}
-static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+static int xts_decrypt(struct skcipher_request *req)
{
- const unsigned int bsize = CAMELLIA_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = camellia_fpu_begin(ctx->fpu_enabled, nbytes);
-
- if (nbytes >= CAMELLIA_AESNI_PARALLEL_BLOCKS * bsize) {
- camellia_ecb_dec_16way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * CAMELLIA_AESNI_PARALLEL_BLOCKS;
- nbytes -= bsize * CAMELLIA_AESNI_PARALLEL_BLOCKS;
- }
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct camellia_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
- while (nbytes >= CAMELLIA_PARALLEL_BLOCKS * bsize) {
- camellia_dec_blk_2way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * CAMELLIA_PARALLEL_BLOCKS;
- nbytes -= bsize * CAMELLIA_PARALLEL_BLOCKS;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- camellia_dec_blk(ctx->ctx, srcdst, srcdst);
+ return glue_xts_req_128bit(&camellia_dec_xts, req,
+ XTS_TWEAK_CAST(camellia_enc_blk),
+ &ctx->tweak_ctx, &ctx->crypt_ctx);
}
-static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[CAMELLIA_AESNI_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->camellia_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = encrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- camellia_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[CAMELLIA_AESNI_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->camellia_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = decrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- camellia_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-
- return glue_xts_crypt_128bit(&camellia_enc_xts, desc, dst, src, nbytes,
- XTS_TWEAK_CAST(camellia_enc_blk),
- &ctx->tweak_ctx, &ctx->crypt_ctx);
-}
-
-static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-
- return glue_xts_crypt_128bit(&camellia_dec_xts, desc, dst, src, nbytes,
- XTS_TWEAK_CAST(camellia_enc_blk),
- &ctx->tweak_ctx, &ctx->crypt_ctx);
-}
-
-static struct crypto_alg cmll_algs[10] = { {
- .cra_name = "__ecb-camellia-aesni",
- .cra_driver_name = "__driver-ecb-camellia-aesni",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct camellia_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .setkey = camellia_setkey,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
- },
-}, {
- .cra_name = "__cbc-camellia-aesni",
- .cra_driver_name = "__driver-cbc-camellia-aesni",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct camellia_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .setkey = camellia_setkey,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-}, {
- .cra_name = "__ctr-camellia-aesni",
- .cra_driver_name = "__driver-ctr-camellia-aesni",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct camellia_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = camellia_setkey,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-}, {
- .cra_name = "__lrw-camellia-aesni",
- .cra_driver_name = "__driver-lrw-camellia-aesni",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct camellia_lrw_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_exit = lrw_camellia_exit_tfm,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE +
- CAMELLIA_BLOCK_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE +
- CAMELLIA_BLOCK_SIZE,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = lrw_camellia_setkey,
- .encrypt = lrw_encrypt,
- .decrypt = lrw_decrypt,
- },
- },
-}, {
- .cra_name = "__xts-camellia-aesni",
- .cra_driver_name = "__driver-xts-camellia-aesni",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct camellia_xts_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE * 2,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE * 2,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = xts_camellia_setkey,
- .encrypt = xts_encrypt,
- .decrypt = xts_decrypt,
- },
- },
-}, {
- .cra_name = "ecb(camellia)",
- .cra_driver_name = "ecb-camellia-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "cbc(camellia)",
- .cra_driver_name = "cbc-camellia-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = __ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "ctr(camellia)",
- .cra_driver_name = "ctr-camellia-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_encrypt,
- .geniv = "chainiv",
- },
- },
-}, {
- .cra_name = "lrw(camellia)",
- .cra_driver_name = "lrw-camellia-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE +
- CAMELLIA_BLOCK_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE +
- CAMELLIA_BLOCK_SIZE,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "xts(camellia)",
- .cra_driver_name = "xts-camellia-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE * 2,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE * 2,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
+static struct skcipher_alg camellia_algs[] = {
+ {
+ .base.cra_name = "__ecb(camellia)",
+ .base.cra_driver_name = "__ecb-camellia-aesni",
+ .base.cra_priority = 400,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = CAMELLIA_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct camellia_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAMELLIA_MIN_KEY_SIZE,
+ .max_keysize = CAMELLIA_MAX_KEY_SIZE,
+ .setkey = camellia_setkey,
+ .encrypt = ecb_encrypt,
+ .decrypt = ecb_decrypt,
+ }, {
+ .base.cra_name = "__cbc(camellia)",
+ .base.cra_driver_name = "__cbc-camellia-aesni",
+ .base.cra_priority = 400,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = CAMELLIA_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct camellia_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAMELLIA_MIN_KEY_SIZE,
+ .max_keysize = CAMELLIA_MAX_KEY_SIZE,
+ .ivsize = CAMELLIA_BLOCK_SIZE,
+ .setkey = camellia_setkey,
+ .encrypt = cbc_encrypt,
+ .decrypt = cbc_decrypt,
+ }, {
+ .base.cra_name = "__ctr(camellia)",
+ .base.cra_driver_name = "__ctr-camellia-aesni",
+ .base.cra_priority = 400,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct camellia_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAMELLIA_MIN_KEY_SIZE,
+ .max_keysize = CAMELLIA_MAX_KEY_SIZE,
+ .ivsize = CAMELLIA_BLOCK_SIZE,
+ .chunksize = CAMELLIA_BLOCK_SIZE,
+ .setkey = camellia_setkey,
+ .encrypt = ctr_crypt,
+ .decrypt = ctr_crypt,
+ }, {
+ .base.cra_name = "__xts(camellia)",
+ .base.cra_driver_name = "__xts-camellia-aesni",
+ .base.cra_priority = 400,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = CAMELLIA_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct camellia_xts_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = 2 * CAMELLIA_MIN_KEY_SIZE,
+ .max_keysize = 2 * CAMELLIA_MAX_KEY_SIZE,
+ .ivsize = CAMELLIA_BLOCK_SIZE,
+ .setkey = xts_camellia_setkey,
+ .encrypt = xts_encrypt,
+ .decrypt = xts_decrypt,
},
-} };
+};
+
+static struct simd_skcipher_alg *camellia_simd_algs[ARRAY_SIZE(camellia_algs)];
static int __init camellia_aesni_init(void)
{
@@ -567,12 +305,15 @@ static int __init camellia_aesni_init(void)
return -ENODEV;
}
- return crypto_register_algs(cmll_algs, ARRAY_SIZE(cmll_algs));
+ return simd_register_skciphers_compat(camellia_algs,
+ ARRAY_SIZE(camellia_algs),
+ camellia_simd_algs);
}
static void __exit camellia_aesni_fini(void)
{
- crypto_unregister_algs(cmll_algs, ARRAY_SIZE(cmll_algs));
+ simd_unregister_skciphers(camellia_algs, ARRAY_SIZE(camellia_algs),
+ camellia_simd_algs);
}
module_init(camellia_aesni_init);
diff --git a/arch/x86/crypto/camellia_glue.c b/arch/x86/crypto/camellia_glue.c
index af4840ab2a3d..dcd5e0f71b00 100644
--- a/arch/x86/crypto/camellia_glue.c
+++ b/arch/x86/crypto/camellia_glue.c
@@ -23,15 +23,12 @@
*
*/
-#include <asm/processor.h>
#include <asm/unaligned.h>
#include <linux/crypto.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <crypto/algapi.h>
-#include <crypto/lrw.h>
-#include <crypto/xts.h>
#include <asm/crypto/camellia.h>
#include <asm/crypto/glue_helper.h>
@@ -1272,13 +1269,19 @@ int __camellia_setkey(struct camellia_ctx *cctx, const unsigned char *key,
}
EXPORT_SYMBOL_GPL(__camellia_setkey);
-static int camellia_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+static int camellia_setkey(struct crypto_tfm *tfm, const u8 *key,
unsigned int key_len)
{
- return __camellia_setkey(crypto_tfm_ctx(tfm), in_key, key_len,
+ return __camellia_setkey(crypto_tfm_ctx(tfm), key, key_len,
&tfm->crt_flags);
}
+static int camellia_setkey_skcipher(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int key_len)
+{
+ return camellia_setkey(&tfm->base, key, key_len);
+}
+
void camellia_decrypt_cbc_2way(void *ctx, u128 *dst, const u128 *src)
{
u128 iv = *src;
@@ -1373,188 +1376,33 @@ static const struct common_glue_ctx camellia_dec_cbc = {
} }
};
-static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ecb_crypt_128bit(&camellia_enc, desc, dst, src, nbytes);
-}
-
-static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ecb_crypt_128bit(&camellia_dec, desc, dst, src, nbytes);
-}
-
-static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(camellia_enc_blk), desc,
- dst, src, nbytes);
-}
-
-static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_cbc_decrypt_128bit(&camellia_dec_cbc, desc, dst, src,
- nbytes);
-}
-
-static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ctr_crypt_128bit(&camellia_ctr, desc, dst, src, nbytes);
-}
-
-static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
-{
- const unsigned int bsize = CAMELLIA_BLOCK_SIZE;
- struct camellia_ctx *ctx = priv;
- int i;
-
- while (nbytes >= 2 * bsize) {
- camellia_enc_blk_2way(ctx, srcdst, srcdst);
- srcdst += bsize * 2;
- nbytes -= bsize * 2;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- camellia_enc_blk(ctx, srcdst, srcdst);
-}
-
-static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
-{
- const unsigned int bsize = CAMELLIA_BLOCK_SIZE;
- struct camellia_ctx *ctx = priv;
- int i;
-
- while (nbytes >= 2 * bsize) {
- camellia_dec_blk_2way(ctx, srcdst, srcdst);
- srcdst += bsize * 2;
- nbytes -= bsize * 2;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- camellia_dec_blk(ctx, srcdst, srcdst);
-}
-
-int lrw_camellia_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
-{
- struct camellia_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
- int err;
-
- err = __camellia_setkey(&ctx->camellia_ctx, key,
- keylen - CAMELLIA_BLOCK_SIZE,
- &tfm->crt_flags);
- if (err)
- return err;
-
- return lrw_init_table(&ctx->lrw_table,
- key + keylen - CAMELLIA_BLOCK_SIZE);
-}
-EXPORT_SYMBOL_GPL(lrw_camellia_setkey);
-
-static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[2 * 4];
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &ctx->camellia_ctx,
- .crypt_fn = encrypt_callback,
- };
-
- return lrw_crypt(desc, dst, src, nbytes, &req);
-}
-
-static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_encrypt(struct skcipher_request *req)
{
- struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[2 * 4];
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &ctx->camellia_ctx,
- .crypt_fn = decrypt_callback,
- };
-
- return lrw_crypt(desc, dst, src, nbytes, &req);
+ return glue_ecb_req_128bit(&camellia_enc, req);
}
-void lrw_camellia_exit_tfm(struct crypto_tfm *tfm)
+static int ecb_decrypt(struct skcipher_request *req)
{
- struct camellia_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
-
- lrw_free_table(&ctx->lrw_table);
+ return glue_ecb_req_128bit(&camellia_dec, req);
}
-EXPORT_SYMBOL_GPL(lrw_camellia_exit_tfm);
-int xts_camellia_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
+static int cbc_encrypt(struct skcipher_request *req)
{
- struct camellia_xts_ctx *ctx = crypto_tfm_ctx(tfm);
- u32 *flags = &tfm->crt_flags;
- int err;
-
- err = xts_check_key(tfm, key, keylen);
- if (err)
- return err;
-
- /* first half of xts-key is for crypt */
- err = __camellia_setkey(&ctx->crypt_ctx, key, keylen / 2, flags);
- if (err)
- return err;
-
- /* second half of xts-key is for tweak */
- return __camellia_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2,
- flags);
+ return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(camellia_enc_blk),
+ req);
}
-EXPORT_SYMBOL_GPL(xts_camellia_setkey);
-static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_decrypt(struct skcipher_request *req)
{
- struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- le128 buf[2 * 4];
- struct xts_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .tweak_ctx = &ctx->tweak_ctx,
- .tweak_fn = XTS_TWEAK_CAST(camellia_enc_blk),
- .crypt_ctx = &ctx->crypt_ctx,
- .crypt_fn = encrypt_callback,
- };
-
- return xts_crypt(desc, dst, src, nbytes, &req);
+ return glue_cbc_decrypt_req_128bit(&camellia_dec_cbc, req);
}
-static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ctr_crypt(struct skcipher_request *req)
{
- struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- le128 buf[2 * 4];
- struct xts_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .tweak_ctx = &ctx->tweak_ctx,
- .tweak_fn = XTS_TWEAK_CAST(camellia_enc_blk),
- .crypt_ctx = &ctx->crypt_ctx,
- .crypt_fn = decrypt_callback,
- };
-
- return xts_crypt(desc, dst, src, nbytes, &req);
+ return glue_ctr_req_128bit(&camellia_ctr, req);
}
-static struct crypto_alg camellia_algs[6] = { {
+static struct crypto_alg camellia_cipher_alg = {
.cra_name = "camellia",
.cra_driver_name = "camellia-asm",
.cra_priority = 200,
@@ -1572,109 +1420,50 @@ static struct crypto_alg camellia_algs[6] = { {
.cia_decrypt = camellia_decrypt
}
}
-}, {
- .cra_name = "ecb(camellia)",
- .cra_driver_name = "ecb-camellia-asm",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct camellia_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .setkey = camellia_setkey,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
- },
-}, {
- .cra_name = "cbc(camellia)",
- .cra_driver_name = "cbc-camellia-asm",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct camellia_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = camellia_setkey,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-}, {
- .cra_name = "ctr(camellia)",
- .cra_driver_name = "ctr-camellia-asm",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct camellia_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = camellia_setkey,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-}, {
- .cra_name = "lrw(camellia)",
- .cra_driver_name = "lrw-camellia-asm",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct camellia_lrw_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_exit = lrw_camellia_exit_tfm,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE +
- CAMELLIA_BLOCK_SIZE,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE +
- CAMELLIA_BLOCK_SIZE,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = lrw_camellia_setkey,
- .encrypt = lrw_encrypt,
- .decrypt = lrw_decrypt,
- },
- },
-}, {
- .cra_name = "xts(camellia)",
- .cra_driver_name = "xts-camellia-asm",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = CAMELLIA_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct camellia_xts_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAMELLIA_MIN_KEY_SIZE * 2,
- .max_keysize = CAMELLIA_MAX_KEY_SIZE * 2,
- .ivsize = CAMELLIA_BLOCK_SIZE,
- .setkey = xts_camellia_setkey,
- .encrypt = xts_encrypt,
- .decrypt = xts_decrypt,
- },
- },
-} };
+};
+
+static struct skcipher_alg camellia_skcipher_algs[] = {
+ {
+ .base.cra_name = "ecb(camellia)",
+ .base.cra_driver_name = "ecb-camellia-asm",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = CAMELLIA_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct camellia_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAMELLIA_MIN_KEY_SIZE,
+ .max_keysize = CAMELLIA_MAX_KEY_SIZE,
+ .setkey = camellia_setkey_skcipher,
+ .encrypt = ecb_encrypt,
+ .decrypt = ecb_decrypt,
+ }, {
+ .base.cra_name = "cbc(camellia)",
+ .base.cra_driver_name = "cbc-camellia-asm",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = CAMELLIA_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct camellia_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAMELLIA_MIN_KEY_SIZE,
+ .max_keysize = CAMELLIA_MAX_KEY_SIZE,
+ .ivsize = CAMELLIA_BLOCK_SIZE,
+ .setkey = camellia_setkey_skcipher,
+ .encrypt = cbc_encrypt,
+ .decrypt = cbc_decrypt,
+ }, {
+ .base.cra_name = "ctr(camellia)",
+ .base.cra_driver_name = "ctr-camellia-asm",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct camellia_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAMELLIA_MIN_KEY_SIZE,
+ .max_keysize = CAMELLIA_MAX_KEY_SIZE,
+ .ivsize = CAMELLIA_BLOCK_SIZE,
+ .chunksize = CAMELLIA_BLOCK_SIZE,
+ .setkey = camellia_setkey_skcipher,
+ .encrypt = ctr_crypt,
+ .decrypt = ctr_crypt,
+ }
+};
static bool is_blacklisted_cpu(void)
{
@@ -1700,6 +1489,8 @@ MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
static int __init init(void)
{
+ int err;
+
if (!force && is_blacklisted_cpu()) {
printk(KERN_INFO
"camellia-x86_64: performance on this CPU "
@@ -1708,12 +1499,23 @@ static int __init init(void)
return -ENODEV;
}
- return crypto_register_algs(camellia_algs, ARRAY_SIZE(camellia_algs));
+ err = crypto_register_alg(&camellia_cipher_alg);
+ if (err)
+ return err;
+
+ err = crypto_register_skciphers(camellia_skcipher_algs,
+ ARRAY_SIZE(camellia_skcipher_algs));
+ if (err)
+ crypto_unregister_alg(&camellia_cipher_alg);
+
+ return err;
}
static void __exit fini(void)
{
- crypto_unregister_algs(camellia_algs, ARRAY_SIZE(camellia_algs));
+ crypto_unregister_alg(&camellia_cipher_alg);
+ crypto_unregister_skciphers(camellia_skcipher_algs,
+ ARRAY_SIZE(camellia_skcipher_algs));
}
module_init(init);
diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c
index dbea6020ffe7..41034745d6a2 100644
--- a/arch/x86/crypto/cast5_avx_glue.c
+++ b/arch/x86/crypto/cast5_avx_glue.c
@@ -21,18 +21,14 @@
*
*/
-#include <linux/module.h>
-#include <linux/hardirq.h>
-#include <linux/types.h>
-#include <linux/crypto.h>
-#include <linux/err.h>
-#include <crypto/ablk_helper.h>
+#include <asm/crypto/glue_helper.h>
#include <crypto/algapi.h>
#include <crypto/cast5.h>
-#include <crypto/cryptd.h>
-#include <crypto/ctr.h>
-#include <asm/fpu/api.h>
-#include <asm/crypto/glue_helper.h>
+#include <crypto/internal/simd.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/types.h>
#define CAST5_PARALLEL_BLOCKS 16
@@ -45,10 +41,17 @@ asmlinkage void cast5_cbc_dec_16way(struct cast5_ctx *ctx, u8 *dst,
asmlinkage void cast5_ctr_16way(struct cast5_ctx *ctx, u8 *dst, const u8 *src,
__be64 *iv);
-static inline bool cast5_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+static int cast5_setkey_skcipher(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ return cast5_setkey(&tfm->base, key, keylen);
+}
+
+static inline bool cast5_fpu_begin(bool fpu_enabled, struct skcipher_walk *walk,
+ unsigned int nbytes)
{
return glue_fpu_begin(CAST5_BLOCK_SIZE, CAST5_PARALLEL_BLOCKS,
- NULL, fpu_enabled, nbytes);
+ walk, fpu_enabled, nbytes);
}
static inline void cast5_fpu_end(bool fpu_enabled)
@@ -56,29 +59,28 @@ static inline void cast5_fpu_end(bool fpu_enabled)
return glue_fpu_end(fpu_enabled);
}
-static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
- bool enc)
+static int ecb_crypt(struct skcipher_request *req, bool enc)
{
bool fpu_enabled = false;
- struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct cast5_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
const unsigned int bsize = CAST5_BLOCK_SIZE;
unsigned int nbytes;
void (*fn)(struct cast5_ctx *ctx, u8 *dst, const u8 *src);
int err;
- fn = (enc) ? cast5_ecb_enc_16way : cast5_ecb_dec_16way;
-
- err = blkcipher_walk_virt(desc, walk);
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+ err = skcipher_walk_virt(&walk, req, false);
- while ((nbytes = walk->nbytes)) {
- u8 *wsrc = walk->src.virt.addr;
- u8 *wdst = walk->dst.virt.addr;
+ while ((nbytes = walk.nbytes)) {
+ u8 *wsrc = walk.src.virt.addr;
+ u8 *wdst = walk.dst.virt.addr;
- fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes);
+ fpu_enabled = cast5_fpu_begin(fpu_enabled, &walk, nbytes);
/* Process multi-block batch */
if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) {
+ fn = (enc) ? cast5_ecb_enc_16way : cast5_ecb_dec_16way;
do {
fn(ctx, wdst, wsrc);
@@ -103,76 +105,58 @@ static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
} while (nbytes >= bsize);
done:
- err = blkcipher_walk_done(desc, walk, nbytes);
+ err = skcipher_walk_done(&walk, nbytes);
}
cast5_fpu_end(fpu_enabled);
return err;
}
-static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_encrypt(struct skcipher_request *req)
{
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_crypt(desc, &walk, true);
+ return ecb_crypt(req, true);
}
-static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_decrypt(struct skcipher_request *req)
{
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_crypt(desc, &walk, false);
+ return ecb_crypt(req, false);
}
-static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
+static int cbc_encrypt(struct skcipher_request *req)
{
- struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
const unsigned int bsize = CAST5_BLOCK_SIZE;
- unsigned int nbytes = walk->nbytes;
- u64 *src = (u64 *)walk->src.virt.addr;
- u64 *dst = (u64 *)walk->dst.virt.addr;
- u64 *iv = (u64 *)walk->iv;
-
- do {
- *dst = *src ^ *iv;
- __cast5_encrypt(ctx, (u8 *)dst, (u8 *)dst);
- iv = dst;
-
- src += 1;
- dst += 1;
- nbytes -= bsize;
- } while (nbytes >= bsize);
-
- *(u64 *)walk->iv = *iv;
- return nbytes;
-}
-
-static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct blkcipher_walk walk;
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct cast5_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
+ unsigned int nbytes;
int err;
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt(desc, &walk);
+ err = skcipher_walk_virt(&walk, req, false);
while ((nbytes = walk.nbytes)) {
- nbytes = __cbc_encrypt(desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
+ u64 *src = (u64 *)walk.src.virt.addr;
+ u64 *dst = (u64 *)walk.dst.virt.addr;
+ u64 *iv = (u64 *)walk.iv;
+
+ do {
+ *dst = *src ^ *iv;
+ __cast5_encrypt(ctx, (u8 *)dst, (u8 *)dst);
+ iv = dst;
+ src++;
+ dst++;
+ nbytes -= bsize;
+ } while (nbytes >= bsize);
+
+ *(u64 *)walk.iv = *iv;
+ err = skcipher_walk_done(&walk, nbytes);
}
return err;
}
-static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
+static unsigned int __cbc_decrypt(struct cast5_ctx *ctx,
+ struct skcipher_walk *walk)
{
- struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
const unsigned int bsize = CAST5_BLOCK_SIZE;
unsigned int nbytes = walk->nbytes;
u64 *src = (u64 *)walk->src.virt.addr;
@@ -224,31 +208,29 @@ done:
return nbytes;
}
-static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_decrypt(struct skcipher_request *req)
{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct cast5_ctx *ctx = crypto_skcipher_ctx(tfm);
bool fpu_enabled = false;
- struct blkcipher_walk walk;
+ struct skcipher_walk walk;
+ unsigned int nbytes;
int err;
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt(desc, &walk);
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+ err = skcipher_walk_virt(&walk, req, false);
while ((nbytes = walk.nbytes)) {
- fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes);
- nbytes = __cbc_decrypt(desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
+ fpu_enabled = cast5_fpu_begin(fpu_enabled, &walk, nbytes);
+ nbytes = __cbc_decrypt(ctx, &walk);
+ err = skcipher_walk_done(&walk, nbytes);
}
cast5_fpu_end(fpu_enabled);
return err;
}
-static void ctr_crypt_final(struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
+static void ctr_crypt_final(struct skcipher_walk *walk, struct cast5_ctx *ctx)
{
- struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
u8 *ctrblk = walk->iv;
u8 keystream[CAST5_BLOCK_SIZE];
u8 *src = walk->src.virt.addr;
@@ -261,10 +243,9 @@ static void ctr_crypt_final(struct blkcipher_desc *desc,
crypto_inc(ctrblk, CAST5_BLOCK_SIZE);
}
-static unsigned int __ctr_crypt(struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
+static unsigned int __ctr_crypt(struct skcipher_walk *walk,
+ struct cast5_ctx *ctx)
{
- struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
const unsigned int bsize = CAST5_BLOCK_SIZE;
unsigned int nbytes = walk->nbytes;
u64 *src = (u64 *)walk->src.virt.addr;
@@ -307,162 +288,80 @@ done:
return nbytes;
}
-static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ctr_crypt(struct skcipher_request *req)
{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct cast5_ctx *ctx = crypto_skcipher_ctx(tfm);
bool fpu_enabled = false;
- struct blkcipher_walk walk;
+ struct skcipher_walk walk;
+ unsigned int nbytes;
int err;
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt_block(desc, &walk, CAST5_BLOCK_SIZE);
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+ err = skcipher_walk_virt(&walk, req, false);
while ((nbytes = walk.nbytes) >= CAST5_BLOCK_SIZE) {
- fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes);
- nbytes = __ctr_crypt(desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
+ fpu_enabled = cast5_fpu_begin(fpu_enabled, &walk, nbytes);
+ nbytes = __ctr_crypt(&walk, ctx);
+ err = skcipher_walk_done(&walk, nbytes);
}
cast5_fpu_end(fpu_enabled);
if (walk.nbytes) {
- ctr_crypt_final(desc, &walk);
- err = blkcipher_walk_done(desc, &walk, 0);
+ ctr_crypt_final(&walk, ctx);
+ err = skcipher_walk_done(&walk, 0);
}
return err;
}
+static struct skcipher_alg cast5_algs[] = {
+ {
+ .base.cra_name = "__ecb(cast5)",
+ .base.cra_driver_name = "__ecb-cast5-avx",
+ .base.cra_priority = 200,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = CAST5_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct cast5_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAST5_MIN_KEY_SIZE,
+ .max_keysize = CAST5_MAX_KEY_SIZE,
+ .setkey = cast5_setkey_skcipher,
+ .encrypt = ecb_encrypt,
+ .decrypt = ecb_decrypt,
+ }, {
+ .base.cra_name = "__cbc(cast5)",
+ .base.cra_driver_name = "__cbc-cast5-avx",
+ .base.cra_priority = 200,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = CAST5_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct cast5_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAST5_MIN_KEY_SIZE,
+ .max_keysize = CAST5_MAX_KEY_SIZE,
+ .ivsize = CAST5_BLOCK_SIZE,
+ .setkey = cast5_setkey_skcipher,
+ .encrypt = cbc_encrypt,
+ .decrypt = cbc_decrypt,
+ }, {
+ .base.cra_name = "__ctr(cast5)",
+ .base.cra_driver_name = "__ctr-cast5-avx",
+ .base.cra_priority = 200,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct cast5_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAST5_MIN_KEY_SIZE,
+ .max_keysize = CAST5_MAX_KEY_SIZE,
+ .ivsize = CAST5_BLOCK_SIZE,
+ .chunksize = CAST5_BLOCK_SIZE,
+ .setkey = cast5_setkey_skcipher,
+ .encrypt = ctr_crypt,
+ .decrypt = ctr_crypt,
+ }
+};
-static struct crypto_alg cast5_algs[6] = { {
- .cra_name = "__ecb-cast5-avx",
- .cra_driver_name = "__driver-ecb-cast5-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = CAST5_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct cast5_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAST5_MIN_KEY_SIZE,
- .max_keysize = CAST5_MAX_KEY_SIZE,
- .setkey = cast5_setkey,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
- },
-}, {
- .cra_name = "__cbc-cast5-avx",
- .cra_driver_name = "__driver-cbc-cast5-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = CAST5_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct cast5_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAST5_MIN_KEY_SIZE,
- .max_keysize = CAST5_MAX_KEY_SIZE,
- .setkey = cast5_setkey,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-}, {
- .cra_name = "__ctr-cast5-avx",
- .cra_driver_name = "__driver-ctr-cast5-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct cast5_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAST5_MIN_KEY_SIZE,
- .max_keysize = CAST5_MAX_KEY_SIZE,
- .ivsize = CAST5_BLOCK_SIZE,
- .setkey = cast5_setkey,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-}, {
- .cra_name = "ecb(cast5)",
- .cra_driver_name = "ecb-cast5-avx",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CAST5_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAST5_MIN_KEY_SIZE,
- .max_keysize = CAST5_MAX_KEY_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "cbc(cast5)",
- .cra_driver_name = "cbc-cast5-avx",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CAST5_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAST5_MIN_KEY_SIZE,
- .max_keysize = CAST5_MAX_KEY_SIZE,
- .ivsize = CAST5_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = __ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "ctr(cast5)",
- .cra_driver_name = "ctr-cast5-avx",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAST5_MIN_KEY_SIZE,
- .max_keysize = CAST5_MAX_KEY_SIZE,
- .ivsize = CAST5_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_encrypt,
- .geniv = "chainiv",
- },
- },
-} };
+static struct simd_skcipher_alg *cast5_simd_algs[ARRAY_SIZE(cast5_algs)];
static int __init cast5_init(void)
{
@@ -474,12 +373,15 @@ static int __init cast5_init(void)
return -ENODEV;
}
- return crypto_register_algs(cast5_algs, ARRAY_SIZE(cast5_algs));
+ return simd_register_skciphers_compat(cast5_algs,
+ ARRAY_SIZE(cast5_algs),
+ cast5_simd_algs);
}
static void __exit cast5_exit(void)
{
- crypto_unregister_algs(cast5_algs, ARRAY_SIZE(cast5_algs));
+ simd_unregister_skciphers(cast5_algs, ARRAY_SIZE(cast5_algs),
+ cast5_simd_algs);
}
module_init(cast5_init);
diff --git a/arch/x86/crypto/cast6_avx_glue.c b/arch/x86/crypto/cast6_avx_glue.c
index 50e684768c55..9fb66b5e94b2 100644
--- a/arch/x86/crypto/cast6_avx_glue.c
+++ b/arch/x86/crypto/cast6_avx_glue.c
@@ -24,19 +24,13 @@
*/
#include <linux/module.h>
-#include <linux/hardirq.h>
#include <linux/types.h>
#include <linux/crypto.h>
#include <linux/err.h>
-#include <crypto/ablk_helper.h>
#include <crypto/algapi.h>
#include <crypto/cast6.h>
-#include <crypto/cryptd.h>
-#include <crypto/b128ops.h>
-#include <crypto/ctr.h>
-#include <crypto/lrw.h>
+#include <crypto/internal/simd.h>
#include <crypto/xts.h>
-#include <asm/fpu/api.h>
#include <asm/crypto/glue_helper.h>
#define CAST6_PARALLEL_BLOCKS 8
@@ -56,6 +50,12 @@ asmlinkage void cast6_xts_enc_8way(struct cast6_ctx *ctx, u8 *dst,
asmlinkage void cast6_xts_dec_8way(struct cast6_ctx *ctx, u8 *dst,
const u8 *src, le128 *iv);
+static int cast6_setkey_skcipher(struct crypto_skcipher *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ return cast6_setkey(&tfm->base, key, keylen);
+}
+
static void cast6_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv)
{
glue_xts_crypt_128bit_one(ctx, dst, src, iv,
@@ -157,164 +157,30 @@ static const struct common_glue_ctx cast6_dec_xts = {
} }
};
-static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ecb_crypt_128bit(&cast6_enc, desc, dst, src, nbytes);
-}
-
-static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ecb_crypt_128bit(&cast6_dec, desc, dst, src, nbytes);
-}
-
-static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(__cast6_encrypt), desc,
- dst, src, nbytes);
-}
-
-static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_cbc_decrypt_128bit(&cast6_dec_cbc, desc, dst, src,
- nbytes);
-}
-
-static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_encrypt(struct skcipher_request *req)
{
- return glue_ctr_crypt_128bit(&cast6_ctr, desc, dst, src, nbytes);
+ return glue_ecb_req_128bit(&cast6_enc, req);
}
-static inline bool cast6_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+static int ecb_decrypt(struct skcipher_request *req)
{
- return glue_fpu_begin(CAST6_BLOCK_SIZE, CAST6_PARALLEL_BLOCKS,
- NULL, fpu_enabled, nbytes);
+ return glue_ecb_req_128bit(&cast6_dec, req);
}
-static inline void cast6_fpu_end(bool fpu_enabled)
+static int cbc_encrypt(struct skcipher_request *req)
{
- glue_fpu_end(fpu_enabled);
+ return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(__cast6_encrypt),
+ req);
}
-struct crypt_priv {
- struct cast6_ctx *ctx;
- bool fpu_enabled;
-};
-
-static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+static int cbc_decrypt(struct skcipher_request *req)
{
- const unsigned int bsize = CAST6_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = cast6_fpu_begin(ctx->fpu_enabled, nbytes);
-
- if (nbytes == bsize * CAST6_PARALLEL_BLOCKS) {
- cast6_ecb_enc_8way(ctx->ctx, srcdst, srcdst);
- return;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- __cast6_encrypt(ctx->ctx, srcdst, srcdst);
+ return glue_cbc_decrypt_req_128bit(&cast6_dec_cbc, req);
}
-static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+static int ctr_crypt(struct skcipher_request *req)
{
- const unsigned int bsize = CAST6_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = cast6_fpu_begin(ctx->fpu_enabled, nbytes);
-
- if (nbytes == bsize * CAST6_PARALLEL_BLOCKS) {
- cast6_ecb_dec_8way(ctx->ctx, srcdst, srcdst);
- return;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- __cast6_decrypt(ctx->ctx, srcdst, srcdst);
-}
-
-struct cast6_lrw_ctx {
- struct lrw_table_ctx lrw_table;
- struct cast6_ctx cast6_ctx;
-};
-
-static int lrw_cast6_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
-{
- struct cast6_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
- int err;
-
- err = __cast6_setkey(&ctx->cast6_ctx, key, keylen - CAST6_BLOCK_SIZE,
- &tfm->crt_flags);
- if (err)
- return err;
-
- return lrw_init_table(&ctx->lrw_table, key + keylen - CAST6_BLOCK_SIZE);
-}
-
-static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct cast6_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[CAST6_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->cast6_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = encrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- cast6_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct cast6_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[CAST6_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->cast6_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = decrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- cast6_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-static void lrw_exit_tfm(struct crypto_tfm *tfm)
-{
- struct cast6_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
-
- lrw_free_table(&ctx->lrw_table);
+ return glue_ctr_req_128bit(&cast6_ctr, req);
}
struct cast6_xts_ctx {
@@ -322,14 +188,14 @@ struct cast6_xts_ctx {
struct cast6_ctx crypt_ctx;
};
-static int xts_cast6_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
+static int xts_cast6_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
{
- struct cast6_xts_ctx *ctx = crypto_tfm_ctx(tfm);
- u32 *flags = &tfm->crt_flags;
+ struct cast6_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
+ u32 *flags = &tfm->base.crt_flags;
int err;
- err = xts_check_key(tfm, key, keylen);
+ err = xts_verify_key(tfm, key, keylen);
if (err)
return err;
@@ -343,245 +209,87 @@ static int xts_cast6_setkey(struct crypto_tfm *tfm, const u8 *key,
flags);
}
-static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int xts_encrypt(struct skcipher_request *req)
{
- struct cast6_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct cast6_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
- return glue_xts_crypt_128bit(&cast6_enc_xts, desc, dst, src, nbytes,
- XTS_TWEAK_CAST(__cast6_encrypt),
- &ctx->tweak_ctx, &ctx->crypt_ctx);
+ return glue_xts_req_128bit(&cast6_enc_xts, req,
+ XTS_TWEAK_CAST(__cast6_encrypt),
+ &ctx->tweak_ctx, &ctx->crypt_ctx);
}
-static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int xts_decrypt(struct skcipher_request *req)
{
- struct cast6_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct cast6_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
- return glue_xts_crypt_128bit(&cast6_dec_xts, desc, dst, src, nbytes,
- XTS_TWEAK_CAST(__cast6_encrypt),
- &ctx->tweak_ctx, &ctx->crypt_ctx);
+ return glue_xts_req_128bit(&cast6_dec_xts, req,
+ XTS_TWEAK_CAST(__cast6_encrypt),
+ &ctx->tweak_ctx, &ctx->crypt_ctx);
}
-static struct crypto_alg cast6_algs[10] = { {
- .cra_name = "__ecb-cast6-avx",
- .cra_driver_name = "__driver-ecb-cast6-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = CAST6_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct cast6_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAST6_MIN_KEY_SIZE,
- .max_keysize = CAST6_MAX_KEY_SIZE,
- .setkey = cast6_setkey,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
- },
-}, {
- .cra_name = "__cbc-cast6-avx",
- .cra_driver_name = "__driver-cbc-cast6-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = CAST6_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct cast6_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAST6_MIN_KEY_SIZE,
- .max_keysize = CAST6_MAX_KEY_SIZE,
- .setkey = cast6_setkey,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-}, {
- .cra_name = "__ctr-cast6-avx",
- .cra_driver_name = "__driver-ctr-cast6-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct cast6_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAST6_MIN_KEY_SIZE,
- .max_keysize = CAST6_MAX_KEY_SIZE,
- .ivsize = CAST6_BLOCK_SIZE,
- .setkey = cast6_setkey,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-}, {
- .cra_name = "__lrw-cast6-avx",
- .cra_driver_name = "__driver-lrw-cast6-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = CAST6_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct cast6_lrw_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_exit = lrw_exit_tfm,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAST6_MIN_KEY_SIZE +
- CAST6_BLOCK_SIZE,
- .max_keysize = CAST6_MAX_KEY_SIZE +
- CAST6_BLOCK_SIZE,
- .ivsize = CAST6_BLOCK_SIZE,
- .setkey = lrw_cast6_setkey,
- .encrypt = lrw_encrypt,
- .decrypt = lrw_decrypt,
- },
- },
-}, {
- .cra_name = "__xts-cast6-avx",
- .cra_driver_name = "__driver-xts-cast6-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = CAST6_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct cast6_xts_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = CAST6_MIN_KEY_SIZE * 2,
- .max_keysize = CAST6_MAX_KEY_SIZE * 2,
- .ivsize = CAST6_BLOCK_SIZE,
- .setkey = xts_cast6_setkey,
- .encrypt = xts_encrypt,
- .decrypt = xts_decrypt,
- },
- },
-}, {
- .cra_name = "ecb(cast6)",
- .cra_driver_name = "ecb-cast6-avx",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CAST6_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAST6_MIN_KEY_SIZE,
- .max_keysize = CAST6_MAX_KEY_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "cbc(cast6)",
- .cra_driver_name = "cbc-cast6-avx",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CAST6_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAST6_MIN_KEY_SIZE,
- .max_keysize = CAST6_MAX_KEY_SIZE,
- .ivsize = CAST6_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = __ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "ctr(cast6)",
- .cra_driver_name = "ctr-cast6-avx",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAST6_MIN_KEY_SIZE,
- .max_keysize = CAST6_MAX_KEY_SIZE,
- .ivsize = CAST6_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_encrypt,
- .geniv = "chainiv",
- },
- },
-}, {
- .cra_name = "lrw(cast6)",
- .cra_driver_name = "lrw-cast6-avx",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CAST6_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAST6_MIN_KEY_SIZE +
- CAST6_BLOCK_SIZE,
- .max_keysize = CAST6_MAX_KEY_SIZE +
- CAST6_BLOCK_SIZE,
- .ivsize = CAST6_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "xts(cast6)",
- .cra_driver_name = "xts-cast6-avx",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CAST6_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = CAST6_MIN_KEY_SIZE * 2,
- .max_keysize = CAST6_MAX_KEY_SIZE * 2,
- .ivsize = CAST6_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
+static struct skcipher_alg cast6_algs[] = {
+ {
+ .base.cra_name = "__ecb(cast6)",
+ .base.cra_driver_name = "__ecb-cast6-avx",
+ .base.cra_priority = 200,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = CAST6_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct cast6_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAST6_MIN_KEY_SIZE,
+ .max_keysize = CAST6_MAX_KEY_SIZE,
+ .setkey = cast6_setkey_skcipher,
+ .encrypt = ecb_encrypt,
+ .decrypt = ecb_decrypt,
+ }, {
+ .base.cra_name = "__cbc(cast6)",
+ .base.cra_driver_name = "__cbc-cast6-avx",
+ .base.cra_priority = 200,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = CAST6_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct cast6_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAST6_MIN_KEY_SIZE,
+ .max_keysize = CAST6_MAX_KEY_SIZE,
+ .ivsize = CAST6_BLOCK_SIZE,
+ .setkey = cast6_setkey_skcipher,
+ .encrypt = cbc_encrypt,
+ .decrypt = cbc_decrypt,
+ }, {
+ .base.cra_name = "__ctr(cast6)",
+ .base.cra_driver_name = "__ctr-cast6-avx",
+ .base.cra_priority = 200,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct cast6_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = CAST6_MIN_KEY_SIZE,
+ .max_keysize = CAST6_MAX_KEY_SIZE,
+ .ivsize = CAST6_BLOCK_SIZE,
+ .chunksize = CAST6_BLOCK_SIZE,
+ .setkey = cast6_setkey_skcipher,
+ .encrypt = ctr_crypt,
+ .decrypt = ctr_crypt,
+ }, {
+ .base.cra_name = "__xts(cast6)",
+ .base.cra_driver_name = "__xts-cast6-avx",
+ .base.cra_priority = 200,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = CAST6_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct cast6_xts_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = 2 * CAST6_MIN_KEY_SIZE,
+ .max_keysize = 2 * CAST6_MAX_KEY_SIZE,
+ .ivsize = CAST6_BLOCK_SIZE,
+ .setkey = xts_cast6_setkey,
+ .encrypt = xts_encrypt,
+ .decrypt = xts_decrypt,
},
-} };
+};
+
+static struct simd_skcipher_alg *cast6_simd_algs[ARRAY_SIZE(cast6_algs)];
static int __init cast6_init(void)
{
@@ -593,12 +301,15 @@ static int __init cast6_init(void)
return -ENODEV;
}
- return crypto_register_algs(cast6_algs, ARRAY_SIZE(cast6_algs));
+ return simd_register_skciphers_compat(cast6_algs,
+ ARRAY_SIZE(cast6_algs),
+ cast6_simd_algs);
}
static void __exit cast6_exit(void)
{
- crypto_unregister_algs(cast6_algs, ARRAY_SIZE(cast6_algs));
+ simd_unregister_skciphers(cast6_algs, ARRAY_SIZE(cast6_algs),
+ cast6_simd_algs);
}
module_init(cast6_init);
diff --git a/arch/x86/crypto/des3_ede_glue.c b/arch/x86/crypto/des3_ede_glue.c
index 30c0a37f4882..5c610d4ef9fc 100644
--- a/arch/x86/crypto/des3_ede_glue.c
+++ b/arch/x86/crypto/des3_ede_glue.c
@@ -20,13 +20,13 @@
*
*/
-#include <asm/processor.h>
+#include <crypto/algapi.h>
#include <crypto/des.h>
+#include <crypto/internal/skcipher.h>
#include <linux/crypto.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
-#include <crypto/algapi.h>
struct des3_ede_x86_ctx {
u32 enc_expkey[DES3_EDE_EXPKEY_WORDS];
@@ -83,18 +83,18 @@ static void des3_ede_x86_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
des3_ede_dec_blk(crypto_tfm_ctx(tfm), dst, src);
}
-static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
- const u32 *expkey)
+static int ecb_crypt(struct skcipher_request *req, const u32 *expkey)
{
- unsigned int bsize = DES3_EDE_BLOCK_SIZE;
+ const unsigned int bsize = DES3_EDE_BLOCK_SIZE;
+ struct skcipher_walk walk;
unsigned int nbytes;
int err;
- err = blkcipher_walk_virt(desc, walk);
+ err = skcipher_walk_virt(&walk, req, false);
- while ((nbytes = walk->nbytes)) {
- u8 *wsrc = walk->src.virt.addr;
- u8 *wdst = walk->dst.virt.addr;
+ while ((nbytes = walk.nbytes)) {
+ u8 *wsrc = walk.src.virt.addr;
+ u8 *wdst = walk.dst.virt.addr;
/* Process four block batch */
if (nbytes >= bsize * 3) {
@@ -121,36 +121,31 @@ static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
} while (nbytes >= bsize);
done:
- err = blkcipher_walk_done(desc, walk, nbytes);
+ err = skcipher_walk_done(&walk, nbytes);
}
return err;
}
-static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_encrypt(struct skcipher_request *req)
{
- struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- struct blkcipher_walk walk;
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_crypt(desc, &walk, ctx->enc_expkey);
+ return ecb_crypt(req, ctx->enc_expkey);
}
-static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_decrypt(struct skcipher_request *req)
{
- struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- struct blkcipher_walk walk;
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_crypt(desc, &walk, ctx->dec_expkey);
+ return ecb_crypt(req, ctx->dec_expkey);
}
-static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
+static unsigned int __cbc_encrypt(struct des3_ede_x86_ctx *ctx,
+ struct skcipher_walk *walk)
{
- struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
unsigned int bsize = DES3_EDE_BLOCK_SIZE;
unsigned int nbytes = walk->nbytes;
u64 *src = (u64 *)walk->src.virt.addr;
@@ -171,27 +166,27 @@ static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
return nbytes;
}
-static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_encrypt(struct skcipher_request *req)
{
- struct blkcipher_walk walk;
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
+ unsigned int nbytes;
int err;
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt(desc, &walk);
+ err = skcipher_walk_virt(&walk, req, false);
while ((nbytes = walk.nbytes)) {
- nbytes = __cbc_encrypt(desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
+ nbytes = __cbc_encrypt(ctx, &walk);
+ err = skcipher_walk_done(&walk, nbytes);
}
return err;
}
-static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
+static unsigned int __cbc_decrypt(struct des3_ede_x86_ctx *ctx,
+ struct skcipher_walk *walk)
{
- struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
unsigned int bsize = DES3_EDE_BLOCK_SIZE;
unsigned int nbytes = walk->nbytes;
u64 *src = (u64 *)walk->src.virt.addr;
@@ -250,25 +245,26 @@ done:
return nbytes;
}
-static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_decrypt(struct skcipher_request *req)
{
- struct blkcipher_walk walk;
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
+ unsigned int nbytes;
int err;
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt(desc, &walk);
+ err = skcipher_walk_virt(&walk, req, false);
while ((nbytes = walk.nbytes)) {
- nbytes = __cbc_decrypt(desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
+ nbytes = __cbc_decrypt(ctx, &walk);
+ err = skcipher_walk_done(&walk, nbytes);
}
return err;
}
static void ctr_crypt_final(struct des3_ede_x86_ctx *ctx,
- struct blkcipher_walk *walk)
+ struct skcipher_walk *walk)
{
u8 *ctrblk = walk->iv;
u8 keystream[DES3_EDE_BLOCK_SIZE];
@@ -282,10 +278,9 @@ static void ctr_crypt_final(struct des3_ede_x86_ctx *ctx,
crypto_inc(ctrblk, DES3_EDE_BLOCK_SIZE);
}
-static unsigned int __ctr_crypt(struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
+static unsigned int __ctr_crypt(struct des3_ede_x86_ctx *ctx,
+ struct skcipher_walk *walk)
{
- struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
unsigned int bsize = DES3_EDE_BLOCK_SIZE;
unsigned int nbytes = walk->nbytes;
__be64 *src = (__be64 *)walk->src.virt.addr;
@@ -333,23 +328,24 @@ done:
return nbytes;
}
-static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ctr_crypt(struct skcipher_request *req)
{
- struct blkcipher_walk walk;
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_walk walk;
+ unsigned int nbytes;
int err;
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt_block(desc, &walk, DES3_EDE_BLOCK_SIZE);
+ err = skcipher_walk_virt(&walk, req, false);
while ((nbytes = walk.nbytes) >= DES3_EDE_BLOCK_SIZE) {
- nbytes = __ctr_crypt(desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
+ nbytes = __ctr_crypt(ctx, &walk);
+ err = skcipher_walk_done(&walk, nbytes);
}
- if (walk.nbytes) {
- ctr_crypt_final(crypto_blkcipher_ctx(desc->tfm), &walk);
- err = blkcipher_walk_done(desc, &walk, 0);
+ if (nbytes) {
+ ctr_crypt_final(ctx, &walk);
+ err = skcipher_walk_done(&walk, 0);
}
return err;
@@ -381,7 +377,14 @@ static int des3_ede_x86_setkey(struct crypto_tfm *tfm, const u8 *key,
return 0;
}
-static struct crypto_alg des3_ede_algs[4] = { {
+static int des3_ede_x86_setkey_skcipher(struct crypto_skcipher *tfm,
+ const u8 *key,
+ unsigned int keylen)
+{
+ return des3_ede_x86_setkey(&tfm->base, key, keylen);
+}
+
+static struct crypto_alg des3_ede_cipher = {
.cra_name = "des3_ede",
.cra_driver_name = "des3_ede-asm",
.cra_priority = 200,
@@ -399,66 +402,50 @@ static struct crypto_alg des3_ede_algs[4] = { {
.cia_decrypt = des3_ede_x86_decrypt,
}
}
-}, {
- .cra_name = "ecb(des3_ede)",
- .cra_driver_name = "ecb-des3_ede-asm",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = DES3_EDE_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct des3_ede_x86_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = DES3_EDE_KEY_SIZE,
- .max_keysize = DES3_EDE_KEY_SIZE,
- .setkey = des3_ede_x86_setkey,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
- },
-}, {
- .cra_name = "cbc(des3_ede)",
- .cra_driver_name = "cbc-des3_ede-asm",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = DES3_EDE_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct des3_ede_x86_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = DES3_EDE_KEY_SIZE,
- .max_keysize = DES3_EDE_KEY_SIZE,
- .ivsize = DES3_EDE_BLOCK_SIZE,
- .setkey = des3_ede_x86_setkey,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-}, {
- .cra_name = "ctr(des3_ede)",
- .cra_driver_name = "ctr-des3_ede-asm",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct des3_ede_x86_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = DES3_EDE_KEY_SIZE,
- .max_keysize = DES3_EDE_KEY_SIZE,
- .ivsize = DES3_EDE_BLOCK_SIZE,
- .setkey = des3_ede_x86_setkey,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-} };
+};
+
+static struct skcipher_alg des3_ede_skciphers[] = {
+ {
+ .base.cra_name = "ecb(des3_ede)",
+ .base.cra_driver_name = "ecb-des3_ede-asm",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct des3_ede_x86_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .setkey = des3_ede_x86_setkey_skcipher,
+ .encrypt = ecb_encrypt,
+ .decrypt = ecb_decrypt,
+ }, {
+ .base.cra_name = "cbc(des3_ede)",
+ .base.cra_driver_name = "cbc-des3_ede-asm",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct des3_ede_x86_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .setkey = des3_ede_x86_setkey_skcipher,
+ .encrypt = cbc_encrypt,
+ .decrypt = cbc_decrypt,
+ }, {
+ .base.cra_name = "ctr(des3_ede)",
+ .base.cra_driver_name = "ctr-des3_ede-asm",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct des3_ede_x86_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .chunksize = DES3_EDE_BLOCK_SIZE,
+ .setkey = des3_ede_x86_setkey_skcipher,
+ .encrypt = ctr_crypt,
+ .decrypt = ctr_crypt,
+ }
+};
static bool is_blacklisted_cpu(void)
{
@@ -483,17 +470,30 @@ MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
static int __init des3_ede_x86_init(void)
{
+ int err;
+
if (!force && is_blacklisted_cpu()) {
pr_info("des3_ede-x86_64: performance on this CPU would be suboptimal: disabling des3_ede-x86_64.\n");
return -ENODEV;
}
- return crypto_register_algs(des3_ede_algs, ARRAY_SIZE(des3_ede_algs));
+ err = crypto_register_alg(&des3_ede_cipher);
+ if (err)
+ return err;
+
+ err = crypto_register_skciphers(des3_ede_skciphers,
+ ARRAY_SIZE(des3_ede_skciphers));
+ if (err)
+ crypto_unregister_alg(&des3_ede_cipher);
+
+ return err;
}
static void __exit des3_ede_x86_fini(void)
{
- crypto_unregister_algs(des3_ede_algs, ARRAY_SIZE(des3_ede_algs));
+ crypto_unregister_alg(&des3_ede_cipher);
+ crypto_unregister_skciphers(des3_ede_skciphers,
+ ARRAY_SIZE(des3_ede_skciphers));
}
module_init(des3_ede_x86_init);
diff --git a/arch/x86/crypto/glue_helper.c b/arch/x86/crypto/glue_helper.c
index d61e57960fe0..a78ef99a9981 100644
--- a/arch/x86/crypto/glue_helper.c
+++ b/arch/x86/crypto/glue_helper.c
@@ -29,313 +29,212 @@
#include <crypto/b128ops.h>
#include <crypto/gf128mul.h>
#include <crypto/internal/skcipher.h>
-#include <crypto/lrw.h>
#include <crypto/xts.h>
#include <asm/crypto/glue_helper.h>
-static int __glue_ecb_crypt_128bit(const struct common_glue_ctx *gctx,
- struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
+int glue_ecb_req_128bit(const struct common_glue_ctx *gctx,
+ struct skcipher_request *req)
{
- void *ctx = crypto_blkcipher_ctx(desc->tfm);
+ void *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
const unsigned int bsize = 128 / 8;
- unsigned int nbytes, i, func_bytes;
+ struct skcipher_walk walk;
bool fpu_enabled = false;
+ unsigned int nbytes;
int err;
- err = blkcipher_walk_virt(desc, walk);
+ err = skcipher_walk_virt(&walk, req, false);
- while ((nbytes = walk->nbytes)) {
- u8 *wsrc = walk->src.virt.addr;
- u8 *wdst = walk->dst.virt.addr;
+ while ((nbytes = walk.nbytes)) {
+ const u8 *src = walk.src.virt.addr;
+ u8 *dst = walk.dst.virt.addr;
+ unsigned int func_bytes;
+ unsigned int i;
fpu_enabled = glue_fpu_begin(bsize, gctx->fpu_blocks_limit,
- desc, fpu_enabled, nbytes);
-
+ &walk, fpu_enabled, nbytes);
for (i = 0; i < gctx->num_funcs; i++) {
func_bytes = bsize * gctx->funcs[i].num_blocks;
- /* Process multi-block batch */
- if (nbytes >= func_bytes) {
- do {
- gctx->funcs[i].fn_u.ecb(ctx, wdst,
- wsrc);
+ if (nbytes < func_bytes)
+ continue;
- wsrc += func_bytes;
- wdst += func_bytes;
- nbytes -= func_bytes;
- } while (nbytes >= func_bytes);
+ /* Process multi-block batch */
+ do {
+ gctx->funcs[i].fn_u.ecb(ctx, dst, src);
+ src += func_bytes;
+ dst += func_bytes;
+ nbytes -= func_bytes;
+ } while (nbytes >= func_bytes);
- if (nbytes < bsize)
- goto done;
- }
+ if (nbytes < bsize)
+ break;
}
-
-done:
- err = blkcipher_walk_done(desc, walk, nbytes);
+ err = skcipher_walk_done(&walk, nbytes);
}
glue_fpu_end(fpu_enabled);
return err;
}
+EXPORT_SYMBOL_GPL(glue_ecb_req_128bit);
-int glue_ecb_crypt_128bit(const struct common_glue_ctx *gctx,
- struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+int glue_cbc_encrypt_req_128bit(const common_glue_func_t fn,
+ struct skcipher_request *req)
{
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return __glue_ecb_crypt_128bit(gctx, desc, &walk);
-}
-EXPORT_SYMBOL_GPL(glue_ecb_crypt_128bit);
-
-static unsigned int __glue_cbc_encrypt_128bit(const common_glue_func_t fn,
- struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
-{
- void *ctx = crypto_blkcipher_ctx(desc->tfm);
+ void *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
const unsigned int bsize = 128 / 8;
- unsigned int nbytes = walk->nbytes;
- u128 *src = (u128 *)walk->src.virt.addr;
- u128 *dst = (u128 *)walk->dst.virt.addr;
- u128 *iv = (u128 *)walk->iv;
-
- do {
- u128_xor(dst, src, iv);
- fn(ctx, (u8 *)dst, (u8 *)dst);
- iv = dst;
-
- src += 1;
- dst += 1;
- nbytes -= bsize;
- } while (nbytes >= bsize);
-
- *(u128 *)walk->iv = *iv;
- return nbytes;
-}
-
-int glue_cbc_encrypt_128bit(const common_glue_func_t fn,
- struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct blkcipher_walk walk;
+ struct skcipher_walk walk;
+ unsigned int nbytes;
int err;
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt(desc, &walk);
+ err = skcipher_walk_virt(&walk, req, false);
while ((nbytes = walk.nbytes)) {
- nbytes = __glue_cbc_encrypt_128bit(fn, desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
+ const u128 *src = (u128 *)walk.src.virt.addr;
+ u128 *dst = (u128 *)walk.dst.virt.addr;
+ u128 *iv = (u128 *)walk.iv;
+
+ do {
+ u128_xor(dst, src, iv);
+ fn(ctx, (u8 *)dst, (u8 *)dst);
+ iv = dst;
+ src++;
+ dst++;
+ nbytes -= bsize;
+ } while (nbytes >= bsize);
+
+ *(u128 *)walk.iv = *iv;
+ err = skcipher_walk_done(&walk, nbytes);
}
-
return err;
}
-EXPORT_SYMBOL_GPL(glue_cbc_encrypt_128bit);
+EXPORT_SYMBOL_GPL(glue_cbc_encrypt_req_128bit);
-static unsigned int
-__glue_cbc_decrypt_128bit(const struct common_glue_ctx *gctx,
- struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
+int glue_cbc_decrypt_req_128bit(const struct common_glue_ctx *gctx,
+ struct skcipher_request *req)
{
- void *ctx = crypto_blkcipher_ctx(desc->tfm);
+ void *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
const unsigned int bsize = 128 / 8;
- unsigned int nbytes = walk->nbytes;
- u128 *src = (u128 *)walk->src.virt.addr;
- u128 *dst = (u128 *)walk->dst.virt.addr;
- u128 last_iv;
- unsigned int num_blocks, func_bytes;
- unsigned int i;
+ struct skcipher_walk walk;
+ bool fpu_enabled = false;
+ unsigned int nbytes;
+ int err;
+
+ err = skcipher_walk_virt(&walk, req, false);
- /* Start of the last block. */
- src += nbytes / bsize - 1;
- dst += nbytes / bsize - 1;
+ while ((nbytes = walk.nbytes)) {
+ const u128 *src = walk.src.virt.addr;
+ u128 *dst = walk.dst.virt.addr;
+ unsigned int func_bytes, num_blocks;
+ unsigned int i;
+ u128 last_iv;
- last_iv = *src;
+ fpu_enabled = glue_fpu_begin(bsize, gctx->fpu_blocks_limit,
+ &walk, fpu_enabled, nbytes);
+ /* Start of the last block. */
+ src += nbytes / bsize - 1;
+ dst += nbytes / bsize - 1;
- for (i = 0; i < gctx->num_funcs; i++) {
- num_blocks = gctx->funcs[i].num_blocks;
- func_bytes = bsize * num_blocks;
+ last_iv = *src;
- /* Process multi-block batch */
- if (nbytes >= func_bytes) {
+ for (i = 0; i < gctx->num_funcs; i++) {
+ num_blocks = gctx->funcs[i].num_blocks;
+ func_bytes = bsize * num_blocks;
+
+ if (nbytes < func_bytes)
+ continue;
+
+ /* Process multi-block batch */
do {
- nbytes -= func_bytes - bsize;
src -= num_blocks - 1;
dst -= num_blocks - 1;
gctx->funcs[i].fn_u.cbc(ctx, dst, src);
- nbytes -= bsize;
+ nbytes -= func_bytes;
if (nbytes < bsize)
goto done;
- u128_xor(dst, dst, src - 1);
- src -= 1;
- dst -= 1;
+ u128_xor(dst, dst, --src);
+ dst--;
} while (nbytes >= func_bytes);
}
- }
-
done:
- u128_xor(dst, dst, (u128 *)walk->iv);
- *(u128 *)walk->iv = last_iv;
-
- return nbytes;
-}
-
-int glue_cbc_decrypt_128bit(const struct common_glue_ctx *gctx,
- struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- const unsigned int bsize = 128 / 8;
- bool fpu_enabled = false;
- struct blkcipher_walk walk;
- int err;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt(desc, &walk);
-
- while ((nbytes = walk.nbytes)) {
- fpu_enabled = glue_fpu_begin(bsize, gctx->fpu_blocks_limit,
- desc, fpu_enabled, nbytes);
- nbytes = __glue_cbc_decrypt_128bit(gctx, desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
+ u128_xor(dst, dst, (u128 *)walk.iv);
+ *(u128 *)walk.iv = last_iv;
+ err = skcipher_walk_done(&walk, nbytes);
}
glue_fpu_end(fpu_enabled);
return err;
}
-EXPORT_SYMBOL_GPL(glue_cbc_decrypt_128bit);
+EXPORT_SYMBOL_GPL(glue_cbc_decrypt_req_128bit);
-static void glue_ctr_crypt_final_128bit(const common_glue_ctr_func_t fn_ctr,
- struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
+int glue_ctr_req_128bit(const struct common_glue_ctx *gctx,
+ struct skcipher_request *req)
{
- void *ctx = crypto_blkcipher_ctx(desc->tfm);
- u8 *src = (u8 *)walk->src.virt.addr;
- u8 *dst = (u8 *)walk->dst.virt.addr;
- unsigned int nbytes = walk->nbytes;
- le128 ctrblk;
- u128 tmp;
+ void *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+ const unsigned int bsize = 128 / 8;
+ struct skcipher_walk walk;
+ bool fpu_enabled = false;
+ unsigned int nbytes;
+ int err;
- be128_to_le128(&ctrblk, (be128 *)walk->iv);
+ err = skcipher_walk_virt(&walk, req, false);
- memcpy(&tmp, src, nbytes);
- fn_ctr(ctx, &tmp, &tmp, &ctrblk);
- memcpy(dst, &tmp, nbytes);
+ while ((nbytes = walk.nbytes) >= bsize) {
+ const u128 *src = walk.src.virt.addr;
+ u128 *dst = walk.dst.virt.addr;
+ unsigned int func_bytes, num_blocks;
+ unsigned int i;
+ le128 ctrblk;
- le128_to_be128((be128 *)walk->iv, &ctrblk);
-}
+ fpu_enabled = glue_fpu_begin(bsize, gctx->fpu_blocks_limit,
+ &walk, fpu_enabled, nbytes);
-static unsigned int __glue_ctr_crypt_128bit(const struct common_glue_ctx *gctx,
- struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
-{
- const unsigned int bsize = 128 / 8;
- void *ctx = crypto_blkcipher_ctx(desc->tfm);
- unsigned int nbytes = walk->nbytes;
- u128 *src = (u128 *)walk->src.virt.addr;
- u128 *dst = (u128 *)walk->dst.virt.addr;
- le128 ctrblk;
- unsigned int num_blocks, func_bytes;
- unsigned int i;
+ be128_to_le128(&ctrblk, (be128 *)walk.iv);
- be128_to_le128(&ctrblk, (be128 *)walk->iv);
+ for (i = 0; i < gctx->num_funcs; i++) {
+ num_blocks = gctx->funcs[i].num_blocks;
+ func_bytes = bsize * num_blocks;
- /* Process multi-block batch */
- for (i = 0; i < gctx->num_funcs; i++) {
- num_blocks = gctx->funcs[i].num_blocks;
- func_bytes = bsize * num_blocks;
+ if (nbytes < func_bytes)
+ continue;
- if (nbytes >= func_bytes) {
+ /* Process multi-block batch */
do {
gctx->funcs[i].fn_u.ctr(ctx, dst, src, &ctrblk);
-
src += num_blocks;
dst += num_blocks;
nbytes -= func_bytes;
} while (nbytes >= func_bytes);
if (nbytes < bsize)
- goto done;
+ break;
}
- }
-
-done:
- le128_to_be128((be128 *)walk->iv, &ctrblk);
- return nbytes;
-}
-
-int glue_ctr_crypt_128bit(const struct common_glue_ctx *gctx,
- struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- const unsigned int bsize = 128 / 8;
- bool fpu_enabled = false;
- struct blkcipher_walk walk;
- int err;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt_block(desc, &walk, bsize);
- while ((nbytes = walk.nbytes) >= bsize) {
- fpu_enabled = glue_fpu_begin(bsize, gctx->fpu_blocks_limit,
- desc, fpu_enabled, nbytes);
- nbytes = __glue_ctr_crypt_128bit(gctx, desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
+ le128_to_be128((be128 *)walk.iv, &ctrblk);
+ err = skcipher_walk_done(&walk, nbytes);
}
glue_fpu_end(fpu_enabled);
- if (walk.nbytes) {
- glue_ctr_crypt_final_128bit(
- gctx->funcs[gctx->num_funcs - 1].fn_u.ctr, desc, &walk);
- err = blkcipher_walk_done(desc, &walk, 0);
- }
-
- return err;
-}
-EXPORT_SYMBOL_GPL(glue_ctr_crypt_128bit);
-
-static unsigned int __glue_xts_crypt_128bit(const struct common_glue_ctx *gctx,
- void *ctx,
- struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
-{
- const unsigned int bsize = 128 / 8;
- unsigned int nbytes = walk->nbytes;
- u128 *src = (u128 *)walk->src.virt.addr;
- u128 *dst = (u128 *)walk->dst.virt.addr;
- unsigned int num_blocks, func_bytes;
- unsigned int i;
-
- /* Process multi-block batch */
- for (i = 0; i < gctx->num_funcs; i++) {
- num_blocks = gctx->funcs[i].num_blocks;
- func_bytes = bsize * num_blocks;
-
- if (nbytes >= func_bytes) {
- do {
- gctx->funcs[i].fn_u.xts(ctx, dst, src,
- (le128 *)walk->iv);
+ if (nbytes) {
+ le128 ctrblk;
+ u128 tmp;
- src += num_blocks;
- dst += num_blocks;
- nbytes -= func_bytes;
- } while (nbytes >= func_bytes);
+ be128_to_le128(&ctrblk, (be128 *)walk.iv);
+ memcpy(&tmp, walk.src.virt.addr, nbytes);
+ gctx->funcs[gctx->num_funcs - 1].fn_u.ctr(ctx, &tmp, &tmp,
+ &ctrblk);
+ memcpy(walk.dst.virt.addr, &tmp, nbytes);
+ le128_to_be128((be128 *)walk.iv, &ctrblk);
- if (nbytes < bsize)
- goto done;
- }
+ err = skcipher_walk_done(&walk, 0);
}
-done:
- return nbytes;
+ return err;
}
+EXPORT_SYMBOL_GPL(glue_ctr_req_128bit);
static unsigned int __glue_xts_req_128bit(const struct common_glue_ctx *gctx,
void *ctx,
@@ -372,46 +271,6 @@ done:
return nbytes;
}
-/* for implementations implementing faster XTS IV generator */
-int glue_xts_crypt_128bit(const struct common_glue_ctx *gctx,
- struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes,
- void (*tweak_fn)(void *ctx, u8 *dst, const u8 *src),
- void *tweak_ctx, void *crypt_ctx)
-{
- const unsigned int bsize = 128 / 8;
- bool fpu_enabled = false;
- struct blkcipher_walk walk;
- int err;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
-
- err = blkcipher_walk_virt(desc, &walk);
- nbytes = walk.nbytes;
- if (!nbytes)
- return err;
-
- /* set minimum length to bsize, for tweak_fn */
- fpu_enabled = glue_fpu_begin(bsize, gctx->fpu_blocks_limit,
- desc, fpu_enabled,
- nbytes < bsize ? bsize : nbytes);
-
- /* calculate first value of T */
- tweak_fn(tweak_ctx, walk.iv, walk.iv);
-
- while (nbytes) {
- nbytes = __glue_xts_crypt_128bit(gctx, crypt_ctx, desc, &walk);
-
- err = blkcipher_walk_done(desc, &walk, nbytes);
- nbytes = walk.nbytes;
- }
-
- glue_fpu_end(fpu_enabled);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(glue_xts_crypt_128bit);
-
int glue_xts_req_128bit(const struct common_glue_ctx *gctx,
struct skcipher_request *req,
common_glue_func_t tweak_fn, void *tweak_ctx,
@@ -429,9 +288,9 @@ int glue_xts_req_128bit(const struct common_glue_ctx *gctx,
return err;
/* set minimum length to bsize, for tweak_fn */
- fpu_enabled = glue_skwalk_fpu_begin(bsize, gctx->fpu_blocks_limit,
- &walk, fpu_enabled,
- nbytes < bsize ? bsize : nbytes);
+ fpu_enabled = glue_fpu_begin(bsize, gctx->fpu_blocks_limit,
+ &walk, fpu_enabled,
+ nbytes < bsize ? bsize : nbytes);
/* calculate first value of T */
tweak_fn(tweak_ctx, walk.iv, walk.iv);
diff --git a/arch/x86/crypto/serpent_avx2_glue.c b/arch/x86/crypto/serpent_avx2_glue.c
index 870f6d812a2d..03347b16ac9d 100644
--- a/arch/x86/crypto/serpent_avx2_glue.c
+++ b/arch/x86/crypto/serpent_avx2_glue.c
@@ -14,15 +14,12 @@
#include <linux/types.h>
#include <linux/crypto.h>
#include <linux/err.h>
-#include <crypto/ablk_helper.h>
#include <crypto/algapi.h>
-#include <crypto/ctr.h>
-#include <crypto/lrw.h>
-#include <crypto/xts.h>
+#include <crypto/internal/simd.h>
#include <crypto/serpent.h>
-#include <asm/fpu/api.h>
-#include <asm/crypto/serpent-avx.h>
+#include <crypto/xts.h>
#include <asm/crypto/glue_helper.h>
+#include <asm/crypto/serpent-avx.h>
#define SERPENT_AVX2_PARALLEL_BLOCKS 16
@@ -40,6 +37,12 @@ asmlinkage void serpent_xts_enc_16way(struct serpent_ctx *ctx, u8 *dst,
asmlinkage void serpent_xts_dec_16way(struct serpent_ctx *ctx, u8 *dst,
const u8 *src, le128 *iv);
+static int serpent_setkey_skcipher(struct crypto_skcipher *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ return __serpent_setkey(crypto_skcipher_ctx(tfm), key, keylen);
+}
+
static const struct common_glue_ctx serpent_enc = {
.num_funcs = 3,
.fpu_blocks_limit = 8,
@@ -136,403 +139,113 @@ static const struct common_glue_ctx serpent_dec_xts = {
} }
};
-static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_encrypt(struct skcipher_request *req)
{
- return glue_ecb_crypt_128bit(&serpent_enc, desc, dst, src, nbytes);
+ return glue_ecb_req_128bit(&serpent_enc, req);
}
-static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_decrypt(struct skcipher_request *req)
{
- return glue_ecb_crypt_128bit(&serpent_dec, desc, dst, src, nbytes);
+ return glue_ecb_req_128bit(&serpent_dec, req);
}
-static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_encrypt(struct skcipher_request *req)
{
- return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(__serpent_encrypt), desc,
- dst, src, nbytes);
+ return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(__serpent_encrypt),
+ req);
}
-static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_decrypt(struct skcipher_request *req)
{
- return glue_cbc_decrypt_128bit(&serpent_dec_cbc, desc, dst, src,
- nbytes);
+ return glue_cbc_decrypt_req_128bit(&serpent_dec_cbc, req);
}
-static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ctr_crypt(struct skcipher_request *req)
{
- return glue_ctr_crypt_128bit(&serpent_ctr, desc, dst, src, nbytes);
+ return glue_ctr_req_128bit(&serpent_ctr, req);
}
-static inline bool serpent_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+static int xts_encrypt(struct skcipher_request *req)
{
- /* since reusing AVX functions, starts using FPU at 8 parallel blocks */
- return glue_fpu_begin(SERPENT_BLOCK_SIZE, 8, NULL, fpu_enabled, nbytes);
-}
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct serpent_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
-static inline void serpent_fpu_end(bool fpu_enabled)
-{
- glue_fpu_end(fpu_enabled);
+ return glue_xts_req_128bit(&serpent_enc_xts, req,
+ XTS_TWEAK_CAST(__serpent_encrypt),
+ &ctx->tweak_ctx, &ctx->crypt_ctx);
}
-struct crypt_priv {
- struct serpent_ctx *ctx;
- bool fpu_enabled;
-};
-
-static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+static int xts_decrypt(struct skcipher_request *req)
{
- const unsigned int bsize = SERPENT_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
-
- if (nbytes >= SERPENT_AVX2_PARALLEL_BLOCKS * bsize) {
- serpent_ecb_enc_16way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * SERPENT_AVX2_PARALLEL_BLOCKS;
- nbytes -= bsize * SERPENT_AVX2_PARALLEL_BLOCKS;
- }
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct serpent_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
- while (nbytes >= SERPENT_PARALLEL_BLOCKS * bsize) {
- serpent_ecb_enc_8way_avx(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * SERPENT_PARALLEL_BLOCKS;
- nbytes -= bsize * SERPENT_PARALLEL_BLOCKS;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- __serpent_encrypt(ctx->ctx, srcdst, srcdst);
+ return glue_xts_req_128bit(&serpent_dec_xts, req,
+ XTS_TWEAK_CAST(__serpent_encrypt),
+ &ctx->tweak_ctx, &ctx->crypt_ctx);
}
-static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
-{
- const unsigned int bsize = SERPENT_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
-
- if (nbytes >= SERPENT_AVX2_PARALLEL_BLOCKS * bsize) {
- serpent_ecb_dec_16way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * SERPENT_AVX2_PARALLEL_BLOCKS;
- nbytes -= bsize * SERPENT_AVX2_PARALLEL_BLOCKS;
- }
-
- while (nbytes >= SERPENT_PARALLEL_BLOCKS * bsize) {
- serpent_ecb_dec_8way_avx(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * SERPENT_PARALLEL_BLOCKS;
- nbytes -= bsize * SERPENT_PARALLEL_BLOCKS;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- __serpent_decrypt(ctx->ctx, srcdst, srcdst);
-}
-
-static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[SERPENT_AVX2_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->serpent_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = encrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- serpent_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[SERPENT_AVX2_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->serpent_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = decrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- serpent_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-
- return glue_xts_crypt_128bit(&serpent_enc_xts, desc, dst, src, nbytes,
- XTS_TWEAK_CAST(__serpent_encrypt),
- &ctx->tweak_ctx, &ctx->crypt_ctx);
-}
-
-static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-
- return glue_xts_crypt_128bit(&serpent_dec_xts, desc, dst, src, nbytes,
- XTS_TWEAK_CAST(__serpent_encrypt),
- &ctx->tweak_ctx, &ctx->crypt_ctx);
-}
-
-static struct crypto_alg srp_algs[10] = { {
- .cra_name = "__ecb-serpent-avx2",
- .cra_driver_name = "__driver-ecb-serpent-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct serpent_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(srp_algs[0].cra_list),
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .setkey = serpent_setkey,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
- },
-}, {
- .cra_name = "__cbc-serpent-avx2",
- .cra_driver_name = "__driver-cbc-serpent-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct serpent_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(srp_algs[1].cra_list),
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .setkey = serpent_setkey,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-}, {
- .cra_name = "__ctr-serpent-avx2",
- .cra_driver_name = "__driver-ctr-serpent-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct serpent_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(srp_algs[2].cra_list),
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = serpent_setkey,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-}, {
- .cra_name = "__lrw-serpent-avx2",
- .cra_driver_name = "__driver-lrw-serpent-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct serpent_lrw_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(srp_algs[3].cra_list),
- .cra_exit = lrw_serpent_exit_tfm,
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE +
- SERPENT_BLOCK_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE +
- SERPENT_BLOCK_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = lrw_serpent_setkey,
- .encrypt = lrw_encrypt,
- .decrypt = lrw_decrypt,
- },
- },
-}, {
- .cra_name = "__xts-serpent-avx2",
- .cra_driver_name = "__driver-xts-serpent-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct serpent_xts_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(srp_algs[4].cra_list),
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE * 2,
- .max_keysize = SERPENT_MAX_KEY_SIZE * 2,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = xts_serpent_setkey,
- .encrypt = xts_encrypt,
- .decrypt = xts_decrypt,
- },
- },
-}, {
- .cra_name = "ecb(serpent)",
- .cra_driver_name = "ecb-serpent-avx2",
- .cra_priority = 600,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(srp_algs[5].cra_list),
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "cbc(serpent)",
- .cra_driver_name = "cbc-serpent-avx2",
- .cra_priority = 600,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(srp_algs[6].cra_list),
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = __ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "ctr(serpent)",
- .cra_driver_name = "ctr-serpent-avx2",
- .cra_priority = 600,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(srp_algs[7].cra_list),
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_encrypt,
- .geniv = "chainiv",
- },
- },
-}, {
- .cra_name = "lrw(serpent)",
- .cra_driver_name = "lrw-serpent-avx2",
- .cra_priority = 600,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(srp_algs[8].cra_list),
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE +
- SERPENT_BLOCK_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE +
- SERPENT_BLOCK_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "xts(serpent)",
- .cra_driver_name = "xts-serpent-avx2",
- .cra_priority = 600,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(srp_algs[9].cra_list),
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE * 2,
- .max_keysize = SERPENT_MAX_KEY_SIZE * 2,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
+static struct skcipher_alg serpent_algs[] = {
+ {
+ .base.cra_name = "__ecb(serpent)",
+ .base.cra_driver_name = "__ecb-serpent-avx2",
+ .base.cra_priority = 600,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = SERPENT_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct serpent_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = SERPENT_MIN_KEY_SIZE,
+ .max_keysize = SERPENT_MAX_KEY_SIZE,
+ .setkey = serpent_setkey_skcipher,
+ .encrypt = ecb_encrypt,
+ .decrypt = ecb_decrypt,
+ }, {
+ .base.cra_name = "__cbc(serpent)",
+ .base.cra_driver_name = "__cbc-serpent-avx2",
+ .base.cra_priority = 600,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = SERPENT_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct serpent_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = SERPENT_MIN_KEY_SIZE,
+ .max_keysize = SERPENT_MAX_KEY_SIZE,
+ .ivsize = SERPENT_BLOCK_SIZE,
+ .setkey = serpent_setkey_skcipher,
+ .encrypt = cbc_encrypt,
+ .decrypt = cbc_decrypt,
+ }, {
+ .base.cra_name = "__ctr(serpent)",
+ .base.cra_driver_name = "__ctr-serpent-avx2",
+ .base.cra_priority = 600,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct serpent_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = SERPENT_MIN_KEY_SIZE,
+ .max_keysize = SERPENT_MAX_KEY_SIZE,
+ .ivsize = SERPENT_BLOCK_SIZE,
+ .chunksize = SERPENT_BLOCK_SIZE,
+ .setkey = serpent_setkey_skcipher,
+ .encrypt = ctr_crypt,
+ .decrypt = ctr_crypt,
+ }, {
+ .base.cra_name = "__xts(serpent)",
+ .base.cra_driver_name = "__xts-serpent-avx2",
+ .base.cra_priority = 600,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = SERPENT_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct serpent_xts_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = 2 * SERPENT_MIN_KEY_SIZE,
+ .max_keysize = 2 * SERPENT_MAX_KEY_SIZE,
+ .ivsize = SERPENT_BLOCK_SIZE,
+ .setkey = xts_serpent_setkey,
+ .encrypt = xts_encrypt,
+ .decrypt = xts_decrypt,
},
-} };
+};
+
+static struct simd_skcipher_alg *serpent_simd_algs[ARRAY_SIZE(serpent_algs)];
static int __init init(void)
{
@@ -548,12 +261,15 @@ static int __init init(void)
return -ENODEV;
}
- return crypto_register_algs(srp_algs, ARRAY_SIZE(srp_algs));
+ return simd_register_skciphers_compat(serpent_algs,
+ ARRAY_SIZE(serpent_algs),
+ serpent_simd_algs);
}
static void __exit fini(void)
{
- crypto_unregister_algs(srp_algs, ARRAY_SIZE(srp_algs));
+ simd_unregister_skciphers(serpent_algs, ARRAY_SIZE(serpent_algs),
+ serpent_simd_algs);
}
module_init(init);
diff --git a/arch/x86/crypto/serpent_avx_glue.c b/arch/x86/crypto/serpent_avx_glue.c
index 6f778d3daa22..458567ecf76c 100644
--- a/arch/x86/crypto/serpent_avx_glue.c
+++ b/arch/x86/crypto/serpent_avx_glue.c
@@ -24,21 +24,15 @@
*/
#include <linux/module.h>
-#include <linux/hardirq.h>
#include <linux/types.h>
#include <linux/crypto.h>
#include <linux/err.h>
-#include <crypto/ablk_helper.h>
#include <crypto/algapi.h>
+#include <crypto/internal/simd.h>
#include <crypto/serpent.h>
-#include <crypto/cryptd.h>
-#include <crypto/b128ops.h>
-#include <crypto/ctr.h>
-#include <crypto/lrw.h>
#include <crypto/xts.h>
-#include <asm/fpu/api.h>
-#include <asm/crypto/serpent-avx.h>
#include <asm/crypto/glue_helper.h>
+#include <asm/crypto/serpent-avx.h>
/* 8-way parallel cipher functions */
asmlinkage void serpent_ecb_enc_8way_avx(struct serpent_ctx *ctx, u8 *dst,
@@ -91,6 +85,31 @@ void serpent_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv)
}
EXPORT_SYMBOL_GPL(serpent_xts_dec);
+static int serpent_setkey_skcipher(struct crypto_skcipher *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ return __serpent_setkey(crypto_skcipher_ctx(tfm), key, keylen);
+}
+
+int xts_serpent_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct serpent_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
+ int err;
+
+ err = xts_verify_key(tfm, key, keylen);
+ if (err)
+ return err;
+
+ /* first half of xts-key is for crypt */
+ err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2);
+ if (err)
+ return err;
+
+ /* second half of xts-key is for tweak */
+ return __serpent_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2);
+}
+EXPORT_SYMBOL_GPL(xts_serpent_setkey);
static const struct common_glue_ctx serpent_enc = {
.num_funcs = 2,
@@ -170,423 +189,113 @@ static const struct common_glue_ctx serpent_dec_xts = {
} }
};
-static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_encrypt(struct skcipher_request *req)
{
- return glue_ecb_crypt_128bit(&serpent_enc, desc, dst, src, nbytes);
+ return glue_ecb_req_128bit(&serpent_enc, req);
}
-static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_decrypt(struct skcipher_request *req)
{
- return glue_ecb_crypt_128bit(&serpent_dec, desc, dst, src, nbytes);
+ return glue_ecb_req_128bit(&serpent_dec, req);
}
-static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_encrypt(struct skcipher_request *req)
{
- return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(__serpent_encrypt), desc,
- dst, src, nbytes);
+ return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(__serpent_encrypt),
+ req);
}
-static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_decrypt(struct skcipher_request *req)
{
- return glue_cbc_decrypt_128bit(&serpent_dec_cbc, desc, dst, src,
- nbytes);
+ return glue_cbc_decrypt_req_128bit(&serpent_dec_cbc, req);
}
-static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ctr_crypt(struct skcipher_request *req)
{
- return glue_ctr_crypt_128bit(&serpent_ctr, desc, dst, src, nbytes);
+ return glue_ctr_req_128bit(&serpent_ctr, req);
}
-static inline bool serpent_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+static int xts_encrypt(struct skcipher_request *req)
{
- return glue_fpu_begin(SERPENT_BLOCK_SIZE, SERPENT_PARALLEL_BLOCKS,
- NULL, fpu_enabled, nbytes);
-}
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct serpent_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
-static inline void serpent_fpu_end(bool fpu_enabled)
-{
- glue_fpu_end(fpu_enabled);
+ return glue_xts_req_128bit(&serpent_enc_xts, req,
+ XTS_TWEAK_CAST(__serpent_encrypt),
+ &ctx->tweak_ctx, &ctx->crypt_ctx);
}
-struct crypt_priv {
- struct serpent_ctx *ctx;
- bool fpu_enabled;
-};
-
-static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
-{
- const unsigned int bsize = SERPENT_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
-
- if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) {
- serpent_ecb_enc_8way_avx(ctx->ctx, srcdst, srcdst);
- return;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- __serpent_encrypt(ctx->ctx, srcdst, srcdst);
-}
-
-static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+static int xts_decrypt(struct skcipher_request *req)
{
- const unsigned int bsize = SERPENT_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct serpent_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
- if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) {
- serpent_ecb_dec_8way_avx(ctx->ctx, srcdst, srcdst);
- return;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- __serpent_decrypt(ctx->ctx, srcdst, srcdst);
-}
-
-int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
-{
- struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
- int err;
-
- err = __serpent_setkey(&ctx->serpent_ctx, key, keylen -
- SERPENT_BLOCK_SIZE);
- if (err)
- return err;
-
- return lrw_init_table(&ctx->lrw_table, key + keylen -
- SERPENT_BLOCK_SIZE);
-}
-EXPORT_SYMBOL_GPL(lrw_serpent_setkey);
-
-static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[SERPENT_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->serpent_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = encrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- serpent_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
+ return glue_xts_req_128bit(&serpent_dec_xts, req,
+ XTS_TWEAK_CAST(__serpent_encrypt),
+ &ctx->tweak_ctx, &ctx->crypt_ctx);
}
-static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[SERPENT_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->serpent_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = decrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- serpent_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-void lrw_serpent_exit_tfm(struct crypto_tfm *tfm)
-{
- struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
-
- lrw_free_table(&ctx->lrw_table);
-}
-EXPORT_SYMBOL_GPL(lrw_serpent_exit_tfm);
-
-int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
-{
- struct serpent_xts_ctx *ctx = crypto_tfm_ctx(tfm);
- int err;
-
- err = xts_check_key(tfm, key, keylen);
- if (err)
- return err;
-
- /* first half of xts-key is for crypt */
- err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2);
- if (err)
- return err;
-
- /* second half of xts-key is for tweak */
- return __serpent_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2);
-}
-EXPORT_SYMBOL_GPL(xts_serpent_setkey);
-
-static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-
- return glue_xts_crypt_128bit(&serpent_enc_xts, desc, dst, src, nbytes,
- XTS_TWEAK_CAST(__serpent_encrypt),
- &ctx->tweak_ctx, &ctx->crypt_ctx);
-}
-
-static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-
- return glue_xts_crypt_128bit(&serpent_dec_xts, desc, dst, src, nbytes,
- XTS_TWEAK_CAST(__serpent_encrypt),
- &ctx->tweak_ctx, &ctx->crypt_ctx);
-}
-
-static struct crypto_alg serpent_algs[10] = { {
- .cra_name = "__ecb-serpent-avx",
- .cra_driver_name = "__driver-ecb-serpent-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct serpent_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .setkey = serpent_setkey,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
- },
-}, {
- .cra_name = "__cbc-serpent-avx",
- .cra_driver_name = "__driver-cbc-serpent-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct serpent_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .setkey = serpent_setkey,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-}, {
- .cra_name = "__ctr-serpent-avx",
- .cra_driver_name = "__driver-ctr-serpent-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct serpent_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = serpent_setkey,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-}, {
- .cra_name = "__lrw-serpent-avx",
- .cra_driver_name = "__driver-lrw-serpent-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct serpent_lrw_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_exit = lrw_serpent_exit_tfm,
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE +
- SERPENT_BLOCK_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE +
- SERPENT_BLOCK_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = lrw_serpent_setkey,
- .encrypt = lrw_encrypt,
- .decrypt = lrw_decrypt,
- },
- },
-}, {
- .cra_name = "__xts-serpent-avx",
- .cra_driver_name = "__driver-xts-serpent-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct serpent_xts_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE * 2,
- .max_keysize = SERPENT_MAX_KEY_SIZE * 2,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = xts_serpent_setkey,
- .encrypt = xts_encrypt,
- .decrypt = xts_decrypt,
- },
- },
-}, {
- .cra_name = "ecb(serpent)",
- .cra_driver_name = "ecb-serpent-avx",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "cbc(serpent)",
- .cra_driver_name = "cbc-serpent-avx",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = __ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "ctr(serpent)",
- .cra_driver_name = "ctr-serpent-avx",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_encrypt,
- .geniv = "chainiv",
- },
- },
-}, {
- .cra_name = "lrw(serpent)",
- .cra_driver_name = "lrw-serpent-avx",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE +
- SERPENT_BLOCK_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE +
- SERPENT_BLOCK_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "xts(serpent)",
- .cra_driver_name = "xts-serpent-avx",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE * 2,
- .max_keysize = SERPENT_MAX_KEY_SIZE * 2,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
+static struct skcipher_alg serpent_algs[] = {
+ {
+ .base.cra_name = "__ecb(serpent)",
+ .base.cra_driver_name = "__ecb-serpent-avx",
+ .base.cra_priority = 500,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = SERPENT_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct serpent_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = SERPENT_MIN_KEY_SIZE,
+ .max_keysize = SERPENT_MAX_KEY_SIZE,
+ .setkey = serpent_setkey_skcipher,
+ .encrypt = ecb_encrypt,
+ .decrypt = ecb_decrypt,
+ }, {
+ .base.cra_name = "__cbc(serpent)",
+ .base.cra_driver_name = "__cbc-serpent-avx",
+ .base.cra_priority = 500,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = SERPENT_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct serpent_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = SERPENT_MIN_KEY_SIZE,
+ .max_keysize = SERPENT_MAX_KEY_SIZE,
+ .ivsize = SERPENT_BLOCK_SIZE,
+ .setkey = serpent_setkey_skcipher,
+ .encrypt = cbc_encrypt,
+ .decrypt = cbc_decrypt,
+ }, {
+ .base.cra_name = "__ctr(serpent)",
+ .base.cra_driver_name = "__ctr-serpent-avx",
+ .base.cra_priority = 500,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct serpent_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = SERPENT_MIN_KEY_SIZE,
+ .max_keysize = SERPENT_MAX_KEY_SIZE,
+ .ivsize = SERPENT_BLOCK_SIZE,
+ .chunksize = SERPENT_BLOCK_SIZE,
+ .setkey = serpent_setkey_skcipher,
+ .encrypt = ctr_crypt,
+ .decrypt = ctr_crypt,
+ }, {
+ .base.cra_name = "__xts(serpent)",
+ .base.cra_driver_name = "__xts-serpent-avx",
+ .base.cra_priority = 500,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = SERPENT_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct serpent_xts_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = 2 * SERPENT_MIN_KEY_SIZE,
+ .max_keysize = 2 * SERPENT_MAX_KEY_SIZE,
+ .ivsize = SERPENT_BLOCK_SIZE,
+ .setkey = xts_serpent_setkey,
+ .encrypt = xts_encrypt,
+ .decrypt = xts_decrypt,
},
-} };
+};
+
+static struct simd_skcipher_alg *serpent_simd_algs[ARRAY_SIZE(serpent_algs)];
static int __init serpent_init(void)
{
@@ -598,12 +307,15 @@ static int __init serpent_init(void)
return -ENODEV;
}
- return crypto_register_algs(serpent_algs, ARRAY_SIZE(serpent_algs));
+ return simd_register_skciphers_compat(serpent_algs,
+ ARRAY_SIZE(serpent_algs),
+ serpent_simd_algs);
}
static void __exit serpent_exit(void)
{
- crypto_unregister_algs(serpent_algs, ARRAY_SIZE(serpent_algs));
+ simd_unregister_skciphers(serpent_algs, ARRAY_SIZE(serpent_algs),
+ serpent_simd_algs);
}
module_init(serpent_init);
diff --git a/arch/x86/crypto/serpent_sse2_glue.c b/arch/x86/crypto/serpent_sse2_glue.c
index ac0e831943f5..3dafe137596a 100644
--- a/arch/x86/crypto/serpent_sse2_glue.c
+++ b/arch/x86/crypto/serpent_sse2_glue.c
@@ -30,21 +30,22 @@
*/
#include <linux/module.h>
-#include <linux/hardirq.h>
#include <linux/types.h>
#include <linux/crypto.h>
#include <linux/err.h>
-#include <crypto/ablk_helper.h>
#include <crypto/algapi.h>
-#include <crypto/serpent.h>
-#include <crypto/cryptd.h>
#include <crypto/b128ops.h>
-#include <crypto/ctr.h>
-#include <crypto/lrw.h>
-#include <crypto/xts.h>
+#include <crypto/internal/simd.h>
+#include <crypto/serpent.h>
#include <asm/crypto/serpent-sse2.h>
#include <asm/crypto/glue_helper.h>
+static int serpent_setkey_skcipher(struct crypto_skcipher *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ return __serpent_setkey(crypto_skcipher_ctx(tfm), key, keylen);
+}
+
static void serpent_decrypt_cbc_xway(void *ctx, u128 *dst, const u128 *src)
{
u128 ivs[SERPENT_PARALLEL_BLOCKS - 1];
@@ -139,464 +140,79 @@ static const struct common_glue_ctx serpent_dec_cbc = {
} }
};
-static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ecb_crypt_128bit(&serpent_enc, desc, dst, src, nbytes);
-}
-
-static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ecb_crypt_128bit(&serpent_dec, desc, dst, src, nbytes);
-}
-
-static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_encrypt(struct skcipher_request *req)
{
- return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(__serpent_encrypt), desc,
- dst, src, nbytes);
+ return glue_ecb_req_128bit(&serpent_enc, req);
}
-static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_decrypt(struct skcipher_request *req)
{
- return glue_cbc_decrypt_128bit(&serpent_dec_cbc, desc, dst, src,
- nbytes);
+ return glue_ecb_req_128bit(&serpent_dec, req);
}
-static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_encrypt(struct skcipher_request *req)
{
- return glue_ctr_crypt_128bit(&serpent_ctr, desc, dst, src, nbytes);
+ return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(__serpent_encrypt),
+ req);
}
-static inline bool serpent_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+static int cbc_decrypt(struct skcipher_request *req)
{
- return glue_fpu_begin(SERPENT_BLOCK_SIZE, SERPENT_PARALLEL_BLOCKS,
- NULL, fpu_enabled, nbytes);
+ return glue_cbc_decrypt_req_128bit(&serpent_dec_cbc, req);
}
-static inline void serpent_fpu_end(bool fpu_enabled)
+static int ctr_crypt(struct skcipher_request *req)
{
- glue_fpu_end(fpu_enabled);
+ return glue_ctr_req_128bit(&serpent_ctr, req);
}
-struct crypt_priv {
- struct serpent_ctx *ctx;
- bool fpu_enabled;
-};
-
-static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
-{
- const unsigned int bsize = SERPENT_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
-
- if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) {
- serpent_enc_blk_xway(ctx->ctx, srcdst, srcdst);
- return;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- __serpent_encrypt(ctx->ctx, srcdst, srcdst);
-}
-
-static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
-{
- const unsigned int bsize = SERPENT_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
-
- if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) {
- serpent_dec_blk_xway(ctx->ctx, srcdst, srcdst);
- return;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- __serpent_decrypt(ctx->ctx, srcdst, srcdst);
-}
-
-struct serpent_lrw_ctx {
- struct lrw_table_ctx lrw_table;
- struct serpent_ctx serpent_ctx;
-};
-
-static int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
-{
- struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
- int err;
-
- err = __serpent_setkey(&ctx->serpent_ctx, key, keylen -
- SERPENT_BLOCK_SIZE);
- if (err)
- return err;
-
- return lrw_init_table(&ctx->lrw_table, key + keylen -
- SERPENT_BLOCK_SIZE);
-}
-
-static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[SERPENT_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->serpent_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = encrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- serpent_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[SERPENT_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->serpent_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = decrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- serpent_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-static void lrw_exit_tfm(struct crypto_tfm *tfm)
-{
- struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
-
- lrw_free_table(&ctx->lrw_table);
-}
-
-struct serpent_xts_ctx {
- struct serpent_ctx tweak_ctx;
- struct serpent_ctx crypt_ctx;
+static struct skcipher_alg serpent_algs[] = {
+ {
+ .base.cra_name = "__ecb(serpent)",
+ .base.cra_driver_name = "__ecb-serpent-sse2",
+ .base.cra_priority = 400,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = SERPENT_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct serpent_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = SERPENT_MIN_KEY_SIZE,
+ .max_keysize = SERPENT_MAX_KEY_SIZE,
+ .setkey = serpent_setkey_skcipher,
+ .encrypt = ecb_encrypt,
+ .decrypt = ecb_decrypt,
+ }, {
+ .base.cra_name = "__cbc(serpent)",
+ .base.cra_driver_name = "__cbc-serpent-sse2",
+ .base.cra_priority = 400,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = SERPENT_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct serpent_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = SERPENT_MIN_KEY_SIZE,
+ .max_keysize = SERPENT_MAX_KEY_SIZE,
+ .ivsize = SERPENT_BLOCK_SIZE,
+ .setkey = serpent_setkey_skcipher,
+ .encrypt = cbc_encrypt,
+ .decrypt = cbc_decrypt,
+ }, {
+ .base.cra_name = "__ctr(serpent)",
+ .base.cra_driver_name = "__ctr-serpent-sse2",
+ .base.cra_priority = 400,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct serpent_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = SERPENT_MIN_KEY_SIZE,
+ .max_keysize = SERPENT_MAX_KEY_SIZE,
+ .ivsize = SERPENT_BLOCK_SIZE,
+ .chunksize = SERPENT_BLOCK_SIZE,
+ .setkey = serpent_setkey_skcipher,
+ .encrypt = ctr_crypt,
+ .decrypt = ctr_crypt,
+ },
};
-static int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
-{
- struct serpent_xts_ctx *ctx = crypto_tfm_ctx(tfm);
- int err;
-
- err = xts_check_key(tfm, key, keylen);
- if (err)
- return err;
-
- /* first half of xts-key is for crypt */
- err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2);
- if (err)
- return err;
-
- /* second half of xts-key is for tweak */
- return __serpent_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2);
-}
-
-static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- le128 buf[SERPENT_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->crypt_ctx,
- .fpu_enabled = false,
- };
- struct xts_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .tweak_ctx = &ctx->tweak_ctx,
- .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt),
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = encrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = xts_crypt(desc, dst, src, nbytes, &req);
- serpent_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- le128 buf[SERPENT_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->crypt_ctx,
- .fpu_enabled = false,
- };
- struct xts_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .tweak_ctx = &ctx->tweak_ctx,
- .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt),
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = decrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = xts_crypt(desc, dst, src, nbytes, &req);
- serpent_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-static struct crypto_alg serpent_algs[10] = { {
- .cra_name = "__ecb-serpent-sse2",
- .cra_driver_name = "__driver-ecb-serpent-sse2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct serpent_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .setkey = serpent_setkey,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
- },
-}, {
- .cra_name = "__cbc-serpent-sse2",
- .cra_driver_name = "__driver-cbc-serpent-sse2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct serpent_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .setkey = serpent_setkey,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-}, {
- .cra_name = "__ctr-serpent-sse2",
- .cra_driver_name = "__driver-ctr-serpent-sse2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct serpent_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = serpent_setkey,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-}, {
- .cra_name = "__lrw-serpent-sse2",
- .cra_driver_name = "__driver-lrw-serpent-sse2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct serpent_lrw_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_exit = lrw_exit_tfm,
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE +
- SERPENT_BLOCK_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE +
- SERPENT_BLOCK_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = lrw_serpent_setkey,
- .encrypt = lrw_encrypt,
- .decrypt = lrw_decrypt,
- },
- },
-}, {
- .cra_name = "__xts-serpent-sse2",
- .cra_driver_name = "__driver-xts-serpent-sse2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct serpent_xts_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE * 2,
- .max_keysize = SERPENT_MAX_KEY_SIZE * 2,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = xts_serpent_setkey,
- .encrypt = xts_encrypt,
- .decrypt = xts_decrypt,
- },
- },
-}, {
- .cra_name = "ecb(serpent)",
- .cra_driver_name = "ecb-serpent-sse2",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "cbc(serpent)",
- .cra_driver_name = "cbc-serpent-sse2",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = __ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "ctr(serpent)",
- .cra_driver_name = "ctr-serpent-sse2",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_encrypt,
- .geniv = "chainiv",
- },
- },
-}, {
- .cra_name = "lrw(serpent)",
- .cra_driver_name = "lrw-serpent-sse2",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE +
- SERPENT_BLOCK_SIZE,
- .max_keysize = SERPENT_MAX_KEY_SIZE +
- SERPENT_BLOCK_SIZE,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "xts(serpent)",
- .cra_driver_name = "xts-serpent-sse2",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = SERPENT_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = SERPENT_MIN_KEY_SIZE * 2,
- .max_keysize = SERPENT_MAX_KEY_SIZE * 2,
- .ivsize = SERPENT_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-} };
+static struct simd_skcipher_alg *serpent_simd_algs[ARRAY_SIZE(serpent_algs)];
static int __init serpent_sse2_init(void)
{
@@ -605,12 +221,15 @@ static int __init serpent_sse2_init(void)
return -ENODEV;
}
- return crypto_register_algs(serpent_algs, ARRAY_SIZE(serpent_algs));
+ return simd_register_skciphers_compat(serpent_algs,
+ ARRAY_SIZE(serpent_algs),
+ serpent_simd_algs);
}
static void __exit serpent_sse2_exit(void)
{
- crypto_unregister_algs(serpent_algs, ARRAY_SIZE(serpent_algs));
+ simd_unregister_skciphers(serpent_algs, ARRAY_SIZE(serpent_algs),
+ serpent_simd_algs);
}
module_init(serpent_sse2_init);
diff --git a/arch/x86/crypto/sha1-mb/sha1_mb.c b/arch/x86/crypto/sha1-mb/sha1_mb.c
index acf9fdf01671..e17655ffde79 100644
--- a/arch/x86/crypto/sha1-mb/sha1_mb.c
+++ b/arch/x86/crypto/sha1-mb/sha1_mb.c
@@ -106,13 +106,6 @@ static asmlinkage struct job_sha1* (*sha1_job_mgr_flush)
static asmlinkage struct job_sha1* (*sha1_job_mgr_get_comp_job)
(struct sha1_mb_mgr *state);
-static inline void sha1_init_digest(uint32_t *digest)
-{
- static const uint32_t initial_digest[SHA1_DIGEST_LENGTH] = {SHA1_H0,
- SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 };
- memcpy(digest, initial_digest, sizeof(initial_digest));
-}
-
static inline uint32_t sha1_pad(uint8_t padblock[SHA1_BLOCK_SIZE * 2],
uint64_t total_len)
{
@@ -244,11 +237,8 @@ static struct sha1_hash_ctx *sha1_ctx_mgr_submit(struct sha1_ctx_mgr *mgr,
uint32_t len,
int flags)
{
- if (flags & (~HASH_ENTIRE)) {
- /*
- * User should not pass anything other than FIRST, UPDATE, or
- * LAST
- */
+ if (flags & ~(HASH_UPDATE | HASH_LAST)) {
+ /* User should not pass anything other than UPDATE or LAST */
ctx->error = HASH_CTX_ERROR_INVALID_FLAGS;
return ctx;
}
@@ -259,24 +249,12 @@ static struct sha1_hash_ctx *sha1_ctx_mgr_submit(struct sha1_ctx_mgr *mgr,
return ctx;
}
- if ((ctx->status & HASH_CTX_STS_COMPLETE) && !(flags & HASH_FIRST)) {
+ if (ctx->status & HASH_CTX_STS_COMPLETE) {
/* Cannot update a finished job. */
ctx->error = HASH_CTX_ERROR_ALREADY_COMPLETED;
return ctx;
}
-
- if (flags & HASH_FIRST) {
- /* Init digest */
- sha1_init_digest(ctx->job.result_digest);
-
- /* Reset byte counter */
- ctx->total_length = 0;
-
- /* Clear extra blocks */
- ctx->partial_block_buffer_length = 0;
- }
-
/*
* If we made it here, there were no errors during this call to
* submit
diff --git a/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h b/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h
index 13590ccf965c..9454bd16f9f8 100644
--- a/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h
+++ b/arch/x86/crypto/sha1-mb/sha1_mb_ctx.h
@@ -57,11 +57,9 @@
#include "sha1_mb_mgr.h"
#define HASH_UPDATE 0x00
-#define HASH_FIRST 0x01
-#define HASH_LAST 0x02
-#define HASH_ENTIRE 0x03
-#define HASH_DONE 0x04
-#define HASH_FINAL 0x08
+#define HASH_LAST 0x01
+#define HASH_DONE 0x02
+#define HASH_FINAL 0x04
#define HASH_CTX_STS_IDLE 0x00
#define HASH_CTX_STS_PROCESSING 0x01
diff --git a/arch/x86/crypto/sha256-mb/sha256_mb.c b/arch/x86/crypto/sha256-mb/sha256_mb.c
index 7926a226b120..4c46ac1b6653 100644
--- a/arch/x86/crypto/sha256-mb/sha256_mb.c
+++ b/arch/x86/crypto/sha256-mb/sha256_mb.c
@@ -106,14 +106,6 @@ static asmlinkage struct job_sha256* (*sha256_job_mgr_flush)
static asmlinkage struct job_sha256* (*sha256_job_mgr_get_comp_job)
(struct sha256_mb_mgr *state);
-inline void sha256_init_digest(uint32_t *digest)
-{
- static const uint32_t initial_digest[SHA256_DIGEST_LENGTH] = {
- SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3,
- SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7};
- memcpy(digest, initial_digest, sizeof(initial_digest));
-}
-
inline uint32_t sha256_pad(uint8_t padblock[SHA256_BLOCK_SIZE * 2],
uint64_t total_len)
{
@@ -245,10 +237,8 @@ static struct sha256_hash_ctx *sha256_ctx_mgr_submit(struct sha256_ctx_mgr *mgr,
uint32_t len,
int flags)
{
- if (flags & (~HASH_ENTIRE)) {
- /* User should not pass anything other than FIRST, UPDATE
- * or LAST
- */
+ if (flags & ~(HASH_UPDATE | HASH_LAST)) {
+ /* User should not pass anything other than UPDATE or LAST */
ctx->error = HASH_CTX_ERROR_INVALID_FLAGS;
return ctx;
}
@@ -259,23 +249,12 @@ static struct sha256_hash_ctx *sha256_ctx_mgr_submit(struct sha256_ctx_mgr *mgr,
return ctx;
}
- if ((ctx->status & HASH_CTX_STS_COMPLETE) && !(flags & HASH_FIRST)) {
+ if (ctx->status & HASH_CTX_STS_COMPLETE) {
/* Cannot update a finished job. */
ctx->error = HASH_CTX_ERROR_ALREADY_COMPLETED;
return ctx;
}
- if (flags & HASH_FIRST) {
- /* Init digest */
- sha256_init_digest(ctx->job.result_digest);
-
- /* Reset byte counter */
- ctx->total_length = 0;
-
- /* Clear extra blocks */
- ctx->partial_block_buffer_length = 0;
- }
-
/* If we made it here, there was no error during this call to submit */
ctx->error = HASH_CTX_ERROR_NONE;
diff --git a/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h b/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h
index aabb30320af0..7c432543dc7f 100644
--- a/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h
+++ b/arch/x86/crypto/sha256-mb/sha256_mb_ctx.h
@@ -57,11 +57,9 @@
#include "sha256_mb_mgr.h"
#define HASH_UPDATE 0x00
-#define HASH_FIRST 0x01
-#define HASH_LAST 0x02
-#define HASH_ENTIRE 0x03
-#define HASH_DONE 0x04
-#define HASH_FINAL 0x08
+#define HASH_LAST 0x01
+#define HASH_DONE 0x02
+#define HASH_FINAL 0x04
#define HASH_CTX_STS_IDLE 0x00
#define HASH_CTX_STS_PROCESSING 0x01
diff --git a/arch/x86/crypto/sha512-mb/sha512_mb.c b/arch/x86/crypto/sha512-mb/sha512_mb.c
index 458409b7568d..39e2bbdc1836 100644
--- a/arch/x86/crypto/sha512-mb/sha512_mb.c
+++ b/arch/x86/crypto/sha512-mb/sha512_mb.c
@@ -107,15 +107,6 @@ static asmlinkage struct job_sha512* (*sha512_job_mgr_flush)
static asmlinkage struct job_sha512* (*sha512_job_mgr_get_comp_job)
(struct sha512_mb_mgr *state);
-inline void sha512_init_digest(uint64_t *digest)
-{
- static const uint64_t initial_digest[SHA512_DIGEST_LENGTH] = {
- SHA512_H0, SHA512_H1, SHA512_H2,
- SHA512_H3, SHA512_H4, SHA512_H5,
- SHA512_H6, SHA512_H7 };
- memcpy(digest, initial_digest, sizeof(initial_digest));
-}
-
inline uint32_t sha512_pad(uint8_t padblock[SHA512_BLOCK_SIZE * 2],
uint64_t total_len)
{
@@ -263,11 +254,8 @@ static struct sha512_hash_ctx
mgr = cstate->mgr;
spin_lock_irqsave(&cstate->work_lock, irqflags);
- if (flags & (~HASH_ENTIRE)) {
- /*
- * User should not pass anything other than FIRST, UPDATE, or
- * LAST
- */
+ if (flags & ~(HASH_UPDATE | HASH_LAST)) {
+ /* User should not pass anything other than UPDATE or LAST */
ctx->error = HASH_CTX_ERROR_INVALID_FLAGS;
goto unlock;
}
@@ -278,24 +266,12 @@ static struct sha512_hash_ctx
goto unlock;
}
- if ((ctx->status & HASH_CTX_STS_COMPLETE) && !(flags & HASH_FIRST)) {
+ if (ctx->status & HASH_CTX_STS_COMPLETE) {
/* Cannot update a finished job. */
ctx->error = HASH_CTX_ERROR_ALREADY_COMPLETED;
goto unlock;
}
-
- if (flags & HASH_FIRST) {
- /* Init digest */
- sha512_init_digest(ctx->job.result_digest);
-
- /* Reset byte counter */
- ctx->total_length = 0;
-
- /* Clear extra blocks */
- ctx->partial_block_buffer_length = 0;
- }
-
/*
* If we made it here, there were no errors during this call to
* submit
diff --git a/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h b/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h
index e4653f5eec3f..e5c465bd821e 100644
--- a/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h
+++ b/arch/x86/crypto/sha512-mb/sha512_mb_ctx.h
@@ -57,11 +57,9 @@
#include "sha512_mb_mgr.h"
#define HASH_UPDATE 0x00
-#define HASH_FIRST 0x01
-#define HASH_LAST 0x02
-#define HASH_ENTIRE 0x03
-#define HASH_DONE 0x04
-#define HASH_FINAL 0x08
+#define HASH_LAST 0x01
+#define HASH_DONE 0x02
+#define HASH_FINAL 0x04
#define HASH_CTX_STS_IDLE 0x00
#define HASH_CTX_STS_PROCESSING 0x01
diff --git a/arch/x86/crypto/twofish_avx_glue.c b/arch/x86/crypto/twofish_avx_glue.c
index b7a3904b953c..66d989230d10 100644
--- a/arch/x86/crypto/twofish_avx_glue.c
+++ b/arch/x86/crypto/twofish_avx_glue.c
@@ -24,24 +24,15 @@
*/
#include <linux/module.h>
-#include <linux/hardirq.h>
#include <linux/types.h>
#include <linux/crypto.h>
#include <linux/err.h>
-#include <crypto/ablk_helper.h>
#include <crypto/algapi.h>
+#include <crypto/internal/simd.h>
#include <crypto/twofish.h>
-#include <crypto/cryptd.h>
-#include <crypto/b128ops.h>
-#include <crypto/ctr.h>
-#include <crypto/lrw.h>
#include <crypto/xts.h>
-#include <asm/fpu/api.h>
-#include <asm/crypto/twofish.h>
#include <asm/crypto/glue_helper.h>
-#include <crypto/scatterwalk.h>
-#include <linux/workqueue.h>
-#include <linux/spinlock.h>
+#include <asm/crypto/twofish.h>
#define TWOFISH_PARALLEL_BLOCKS 8
@@ -61,6 +52,12 @@ asmlinkage void twofish_xts_enc_8way(struct twofish_ctx *ctx, u8 *dst,
asmlinkage void twofish_xts_dec_8way(struct twofish_ctx *ctx, u8 *dst,
const u8 *src, le128 *iv);
+static int twofish_setkey_skcipher(struct crypto_skcipher *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ return twofish_setkey(&tfm->base, key, keylen);
+}
+
static inline void twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
const u8 *src)
{
@@ -79,6 +76,31 @@ static void twofish_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv)
GLUE_FUNC_CAST(twofish_dec_blk));
}
+struct twofish_xts_ctx {
+ struct twofish_ctx tweak_ctx;
+ struct twofish_ctx crypt_ctx;
+};
+
+static int xts_twofish_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct twofish_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
+ u32 *flags = &tfm->base.crt_flags;
+ int err;
+
+ err = xts_verify_key(tfm, key, keylen);
+ if (err)
+ return err;
+
+ /* first half of xts-key is for crypt */
+ err = __twofish_setkey(&ctx->crypt_ctx, key, keylen / 2, flags);
+ if (err)
+ return err;
+
+ /* second half of xts-key is for tweak */
+ return __twofish_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2,
+ flags);
+}
static const struct common_glue_ctx twofish_enc = {
.num_funcs = 3,
@@ -170,389 +192,113 @@ static const struct common_glue_ctx twofish_dec_xts = {
} }
};
-static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ecb_crypt_128bit(&twofish_enc, desc, dst, src, nbytes);
-}
-
-static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ecb_crypt_128bit(&twofish_dec, desc, dst, src, nbytes);
-}
-
-static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_encrypt(struct skcipher_request *req)
{
- return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(twofish_enc_blk), desc,
- dst, src, nbytes);
+ return glue_ecb_req_128bit(&twofish_enc, req);
}
-static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_decrypt(struct skcipher_request *req)
{
- return glue_cbc_decrypt_128bit(&twofish_dec_cbc, desc, dst, src,
- nbytes);
+ return glue_ecb_req_128bit(&twofish_dec, req);
}
-static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_encrypt(struct skcipher_request *req)
{
- return glue_ctr_crypt_128bit(&twofish_ctr, desc, dst, src, nbytes);
+ return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(twofish_enc_blk),
+ req);
}
-static inline bool twofish_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+static int cbc_decrypt(struct skcipher_request *req)
{
- return glue_fpu_begin(TF_BLOCK_SIZE, TWOFISH_PARALLEL_BLOCKS, NULL,
- fpu_enabled, nbytes);
+ return glue_cbc_decrypt_req_128bit(&twofish_dec_cbc, req);
}
-static inline void twofish_fpu_end(bool fpu_enabled)
+static int ctr_crypt(struct skcipher_request *req)
{
- glue_fpu_end(fpu_enabled);
+ return glue_ctr_req_128bit(&twofish_ctr, req);
}
-struct crypt_priv {
- struct twofish_ctx *ctx;
- bool fpu_enabled;
-};
-
-static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+static int xts_encrypt(struct skcipher_request *req)
{
- const unsigned int bsize = TF_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = twofish_fpu_begin(ctx->fpu_enabled, nbytes);
-
- if (nbytes == bsize * TWOFISH_PARALLEL_BLOCKS) {
- twofish_ecb_enc_8way(ctx->ctx, srcdst, srcdst);
- return;
- }
-
- for (i = 0; i < nbytes / (bsize * 3); i++, srcdst += bsize * 3)
- twofish_enc_blk_3way(ctx->ctx, srcdst, srcdst);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct twofish_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
- nbytes %= bsize * 3;
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- twofish_enc_blk(ctx->ctx, srcdst, srcdst);
+ return glue_xts_req_128bit(&twofish_enc_xts, req,
+ XTS_TWEAK_CAST(twofish_enc_blk),
+ &ctx->tweak_ctx, &ctx->crypt_ctx);
}
-static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+static int xts_decrypt(struct skcipher_request *req)
{
- const unsigned int bsize = TF_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = twofish_fpu_begin(ctx->fpu_enabled, nbytes);
-
- if (nbytes == bsize * TWOFISH_PARALLEL_BLOCKS) {
- twofish_ecb_dec_8way(ctx->ctx, srcdst, srcdst);
- return;
- }
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct twofish_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
- for (i = 0; i < nbytes / (bsize * 3); i++, srcdst += bsize * 3)
- twofish_dec_blk_3way(ctx->ctx, srcdst, srcdst);
-
- nbytes %= bsize * 3;
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- twofish_dec_blk(ctx->ctx, srcdst, srcdst);
+ return glue_xts_req_128bit(&twofish_dec_xts, req,
+ XTS_TWEAK_CAST(twofish_enc_blk),
+ &ctx->tweak_ctx, &ctx->crypt_ctx);
}
-static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct twofish_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[TWOFISH_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->twofish_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = encrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- twofish_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct twofish_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[TWOFISH_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->twofish_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = decrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- twofish_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct twofish_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-
- return glue_xts_crypt_128bit(&twofish_enc_xts, desc, dst, src, nbytes,
- XTS_TWEAK_CAST(twofish_enc_blk),
- &ctx->tweak_ctx, &ctx->crypt_ctx);
-}
-
-static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct twofish_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-
- return glue_xts_crypt_128bit(&twofish_dec_xts, desc, dst, src, nbytes,
- XTS_TWEAK_CAST(twofish_enc_blk),
- &ctx->tweak_ctx, &ctx->crypt_ctx);
-}
-
-static struct crypto_alg twofish_algs[10] = { {
- .cra_name = "__ecb-twofish-avx",
- .cra_driver_name = "__driver-ecb-twofish-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct twofish_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .setkey = twofish_setkey,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
- },
-}, {
- .cra_name = "__cbc-twofish-avx",
- .cra_driver_name = "__driver-cbc-twofish-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct twofish_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .setkey = twofish_setkey,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-}, {
- .cra_name = "__ctr-twofish-avx",
- .cra_driver_name = "__driver-ctr-twofish-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct twofish_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = twofish_setkey,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-}, {
- .cra_name = "__lrw-twofish-avx",
- .cra_driver_name = "__driver-lrw-twofish-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct twofish_lrw_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_exit = lrw_twofish_exit_tfm,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE +
- TF_BLOCK_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE +
- TF_BLOCK_SIZE,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = lrw_twofish_setkey,
- .encrypt = lrw_encrypt,
- .decrypt = lrw_decrypt,
- },
- },
-}, {
- .cra_name = "__xts-twofish-avx",
- .cra_driver_name = "__driver-xts-twofish-avx",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
- CRYPTO_ALG_INTERNAL,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct twofish_xts_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE * 2,
- .max_keysize = TF_MAX_KEY_SIZE * 2,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = xts_twofish_setkey,
- .encrypt = xts_encrypt,
- .decrypt = xts_decrypt,
- },
- },
-}, {
- .cra_name = "ecb(twofish)",
- .cra_driver_name = "ecb-twofish-avx",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "cbc(twofish)",
- .cra_driver_name = "cbc-twofish-avx",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = __ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "ctr(twofish)",
- .cra_driver_name = "ctr-twofish-avx",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_encrypt,
- .geniv = "chainiv",
- },
- },
-}, {
- .cra_name = "lrw(twofish)",
- .cra_driver_name = "lrw-twofish-avx",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE +
- TF_BLOCK_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE +
- TF_BLOCK_SIZE,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "xts(twofish)",
- .cra_driver_name = "xts-twofish-avx",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE * 2,
- .max_keysize = TF_MAX_KEY_SIZE * 2,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
+static struct skcipher_alg twofish_algs[] = {
+ {
+ .base.cra_name = "__ecb(twofish)",
+ .base.cra_driver_name = "__ecb-twofish-avx",
+ .base.cra_priority = 400,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = TF_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct twofish_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = TF_MIN_KEY_SIZE,
+ .max_keysize = TF_MAX_KEY_SIZE,
+ .setkey = twofish_setkey_skcipher,
+ .encrypt = ecb_encrypt,
+ .decrypt = ecb_decrypt,
+ }, {
+ .base.cra_name = "__cbc(twofish)",
+ .base.cra_driver_name = "__cbc-twofish-avx",
+ .base.cra_priority = 400,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = TF_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct twofish_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = TF_MIN_KEY_SIZE,
+ .max_keysize = TF_MAX_KEY_SIZE,
+ .ivsize = TF_BLOCK_SIZE,
+ .setkey = twofish_setkey_skcipher,
+ .encrypt = cbc_encrypt,
+ .decrypt = cbc_decrypt,
+ }, {
+ .base.cra_name = "__ctr(twofish)",
+ .base.cra_driver_name = "__ctr-twofish-avx",
+ .base.cra_priority = 400,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct twofish_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = TF_MIN_KEY_SIZE,
+ .max_keysize = TF_MAX_KEY_SIZE,
+ .ivsize = TF_BLOCK_SIZE,
+ .chunksize = TF_BLOCK_SIZE,
+ .setkey = twofish_setkey_skcipher,
+ .encrypt = ctr_crypt,
+ .decrypt = ctr_crypt,
+ }, {
+ .base.cra_name = "__xts(twofish)",
+ .base.cra_driver_name = "__xts-twofish-avx",
+ .base.cra_priority = 400,
+ .base.cra_flags = CRYPTO_ALG_INTERNAL,
+ .base.cra_blocksize = TF_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct twofish_xts_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = 2 * TF_MIN_KEY_SIZE,
+ .max_keysize = 2 * TF_MAX_KEY_SIZE,
+ .ivsize = TF_BLOCK_SIZE,
+ .setkey = xts_twofish_setkey,
+ .encrypt = xts_encrypt,
+ .decrypt = xts_decrypt,
},
-} };
+};
+
+static struct simd_skcipher_alg *twofish_simd_algs[ARRAY_SIZE(twofish_algs)];
static int __init twofish_init(void)
{
@@ -563,12 +309,15 @@ static int __init twofish_init(void)
return -ENODEV;
}
- return crypto_register_algs(twofish_algs, ARRAY_SIZE(twofish_algs));
+ return simd_register_skciphers_compat(twofish_algs,
+ ARRAY_SIZE(twofish_algs),
+ twofish_simd_algs);
}
static void __exit twofish_exit(void)
{
- crypto_unregister_algs(twofish_algs, ARRAY_SIZE(twofish_algs));
+ simd_unregister_skciphers(twofish_algs, ARRAY_SIZE(twofish_algs),
+ twofish_simd_algs);
}
module_init(twofish_init);
diff --git a/arch/x86/crypto/twofish_glue_3way.c b/arch/x86/crypto/twofish_glue_3way.c
index 243e90a4b5d9..571485502ec8 100644
--- a/arch/x86/crypto/twofish_glue_3way.c
+++ b/arch/x86/crypto/twofish_glue_3way.c
@@ -20,22 +20,26 @@
*
*/
-#include <asm/processor.h>
+#include <asm/crypto/glue_helper.h>
+#include <asm/crypto/twofish.h>
+#include <crypto/algapi.h>
+#include <crypto/b128ops.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/twofish.h>
#include <linux/crypto.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
-#include <crypto/algapi.h>
-#include <crypto/twofish.h>
-#include <crypto/b128ops.h>
-#include <asm/crypto/twofish.h>
-#include <asm/crypto/glue_helper.h>
-#include <crypto/lrw.h>
-#include <crypto/xts.h>
EXPORT_SYMBOL_GPL(__twofish_enc_blk_3way);
EXPORT_SYMBOL_GPL(twofish_dec_blk_3way);
+static int twofish_setkey_skcipher(struct crypto_skcipher *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ return twofish_setkey(&tfm->base, key, keylen);
+}
+
static inline void twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
const u8 *src)
{
@@ -151,284 +155,74 @@ static const struct common_glue_ctx twofish_dec_cbc = {
} }
};
-static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ecb_crypt_128bit(&twofish_enc, desc, dst, src, nbytes);
-}
-
-static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ecb_crypt_128bit(&twofish_dec, desc, dst, src, nbytes);
-}
-
-static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(twofish_enc_blk), desc,
- dst, src, nbytes);
-}
-
-static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_cbc_decrypt_128bit(&twofish_dec_cbc, desc, dst, src,
- nbytes);
-}
-
-static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ctr_crypt_128bit(&twofish_ctr, desc, dst, src, nbytes);
-}
-
-static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+static int ecb_encrypt(struct skcipher_request *req)
{
- const unsigned int bsize = TF_BLOCK_SIZE;
- struct twofish_ctx *ctx = priv;
- int i;
-
- if (nbytes == 3 * bsize) {
- twofish_enc_blk_3way(ctx, srcdst, srcdst);
- return;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- twofish_enc_blk(ctx, srcdst, srcdst);
-}
-
-static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
-{
- const unsigned int bsize = TF_BLOCK_SIZE;
- struct twofish_ctx *ctx = priv;
- int i;
-
- if (nbytes == 3 * bsize) {
- twofish_dec_blk_3way(ctx, srcdst, srcdst);
- return;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- twofish_dec_blk(ctx, srcdst, srcdst);
-}
-
-int lrw_twofish_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
-{
- struct twofish_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
- int err;
-
- err = __twofish_setkey(&ctx->twofish_ctx, key, keylen - TF_BLOCK_SIZE,
- &tfm->crt_flags);
- if (err)
- return err;
-
- return lrw_init_table(&ctx->lrw_table, key + keylen - TF_BLOCK_SIZE);
+ return glue_ecb_req_128bit(&twofish_enc, req);
}
-EXPORT_SYMBOL_GPL(lrw_twofish_setkey);
-static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_decrypt(struct skcipher_request *req)
{
- struct twofish_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[3];
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &ctx->twofish_ctx,
- .crypt_fn = encrypt_callback,
- };
-
- return lrw_crypt(desc, dst, src, nbytes, &req);
+ return glue_ecb_req_128bit(&twofish_dec, req);
}
-static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_encrypt(struct skcipher_request *req)
{
- struct twofish_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[3];
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &ctx->twofish_ctx,
- .crypt_fn = decrypt_callback,
- };
-
- return lrw_crypt(desc, dst, src, nbytes, &req);
+ return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(twofish_enc_blk),
+ req);
}
-void lrw_twofish_exit_tfm(struct crypto_tfm *tfm)
+static int cbc_decrypt(struct skcipher_request *req)
{
- struct twofish_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
-
- lrw_free_table(&ctx->lrw_table);
-}
-EXPORT_SYMBOL_GPL(lrw_twofish_exit_tfm);
-
-int xts_twofish_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
-{
- struct twofish_xts_ctx *ctx = crypto_tfm_ctx(tfm);
- u32 *flags = &tfm->crt_flags;
- int err;
-
- err = xts_check_key(tfm, key, keylen);
- if (err)
- return err;
-
- /* first half of xts-key is for crypt */
- err = __twofish_setkey(&ctx->crypt_ctx, key, keylen / 2, flags);
- if (err)
- return err;
-
- /* second half of xts-key is for tweak */
- return __twofish_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2,
- flags);
-}
-EXPORT_SYMBOL_GPL(xts_twofish_setkey);
-
-static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct twofish_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- le128 buf[3];
- struct xts_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .tweak_ctx = &ctx->tweak_ctx,
- .tweak_fn = XTS_TWEAK_CAST(twofish_enc_blk),
- .crypt_ctx = &ctx->crypt_ctx,
- .crypt_fn = encrypt_callback,
- };
-
- return xts_crypt(desc, dst, src, nbytes, &req);
+ return glue_cbc_decrypt_req_128bit(&twofish_dec_cbc, req);
}
-static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ctr_crypt(struct skcipher_request *req)
{
- struct twofish_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- le128 buf[3];
- struct xts_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .tweak_ctx = &ctx->tweak_ctx,
- .tweak_fn = XTS_TWEAK_CAST(twofish_enc_blk),
- .crypt_ctx = &ctx->crypt_ctx,
- .crypt_fn = decrypt_callback,
- };
-
- return xts_crypt(desc, dst, src, nbytes, &req);
+ return glue_ctr_req_128bit(&twofish_ctr, req);
}
-static struct crypto_alg tf_algs[5] = { {
- .cra_name = "ecb(twofish)",
- .cra_driver_name = "ecb-twofish-3way",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct twofish_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .setkey = twofish_setkey,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
- },
-}, {
- .cra_name = "cbc(twofish)",
- .cra_driver_name = "cbc-twofish-3way",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct twofish_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = twofish_setkey,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-}, {
- .cra_name = "ctr(twofish)",
- .cra_driver_name = "ctr-twofish-3way",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct twofish_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = twofish_setkey,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-}, {
- .cra_name = "lrw(twofish)",
- .cra_driver_name = "lrw-twofish-3way",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct twofish_lrw_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_exit = lrw_twofish_exit_tfm,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE + TF_BLOCK_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE + TF_BLOCK_SIZE,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = lrw_twofish_setkey,
- .encrypt = lrw_encrypt,
- .decrypt = lrw_decrypt,
- },
- },
-}, {
- .cra_name = "xts(twofish)",
- .cra_driver_name = "xts-twofish-3way",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct twofish_xts_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE * 2,
- .max_keysize = TF_MAX_KEY_SIZE * 2,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = xts_twofish_setkey,
- .encrypt = xts_encrypt,
- .decrypt = xts_decrypt,
- },
+static struct skcipher_alg tf_skciphers[] = {
+ {
+ .base.cra_name = "ecb(twofish)",
+ .base.cra_driver_name = "ecb-twofish-3way",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = TF_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct twofish_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = TF_MIN_KEY_SIZE,
+ .max_keysize = TF_MAX_KEY_SIZE,
+ .setkey = twofish_setkey_skcipher,
+ .encrypt = ecb_encrypt,
+ .decrypt = ecb_decrypt,
+ }, {
+ .base.cra_name = "cbc(twofish)",
+ .base.cra_driver_name = "cbc-twofish-3way",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = TF_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct twofish_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = TF_MIN_KEY_SIZE,
+ .max_keysize = TF_MAX_KEY_SIZE,
+ .ivsize = TF_BLOCK_SIZE,
+ .setkey = twofish_setkey_skcipher,
+ .encrypt = cbc_encrypt,
+ .decrypt = cbc_decrypt,
+ }, {
+ .base.cra_name = "ctr(twofish)",
+ .base.cra_driver_name = "ctr-twofish-3way",
+ .base.cra_priority = 300,
+ .base.cra_blocksize = 1,
+ .base.cra_ctxsize = sizeof(struct twofish_ctx),
+ .base.cra_module = THIS_MODULE,
+ .min_keysize = TF_MIN_KEY_SIZE,
+ .max_keysize = TF_MAX_KEY_SIZE,
+ .ivsize = TF_BLOCK_SIZE,
+ .chunksize = TF_BLOCK_SIZE,
+ .setkey = twofish_setkey_skcipher,
+ .encrypt = ctr_crypt,
+ .decrypt = ctr_crypt,
},
-} };
+};
static bool is_blacklisted_cpu(void)
{
@@ -478,12 +272,13 @@ static int __init init(void)
return -ENODEV;
}
- return crypto_register_algs(tf_algs, ARRAY_SIZE(tf_algs));
+ return crypto_register_skciphers(tf_skciphers,
+ ARRAY_SIZE(tf_skciphers));
}
static void __exit fini(void)
{
- crypto_unregister_algs(tf_algs, ARRAY_SIZE(tf_algs));
+ crypto_unregister_skciphers(tf_skciphers, ARRAY_SIZE(tf_skciphers));
}
module_init(init);
diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S
index 6ad064c8cf35..bef8e2b202a8 100644
--- a/arch/x86/entry/entry_32.S
+++ b/arch/x86/entry/entry_32.S
@@ -902,6 +902,9 @@ BUILD_INTERRUPT3(hyperv_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
BUILD_INTERRUPT3(hyperv_reenlightenment_vector, HYPERV_REENLIGHTENMENT_VECTOR,
hyperv_reenlightenment_intr)
+BUILD_INTERRUPT3(hv_stimer0_callback_vector, HYPERV_STIMER0_VECTOR,
+ hv_stimer0_vector_handler)
+
#endif /* CONFIG_HYPERV */
ENTRY(page_fault)
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index 936e19642eab..b0a4649e55ce 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -1140,6 +1140,9 @@ apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \
apicinterrupt3 HYPERV_REENLIGHTENMENT_VECTOR \
hyperv_reenlightenment_vector hyperv_reenlightenment_intr
+
+apicinterrupt3 HYPERV_STIMER0_VECTOR \
+ hv_stimer0_callback_vector hv_stimer0_vector_handler
#endif /* CONFIG_HYPERV */
idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK
diff --git a/arch/x86/include/asm/crypto/camellia.h b/arch/x86/include/asm/crypto/camellia.h
index 10f8d590bcfe..a5d86fc0593f 100644
--- a/arch/x86/include/asm/crypto/camellia.h
+++ b/arch/x86/include/asm/crypto/camellia.h
@@ -2,8 +2,9 @@
#ifndef ASM_X86_CAMELLIA_H
#define ASM_X86_CAMELLIA_H
-#include <linux/kernel.h>
+#include <crypto/b128ops.h>
#include <linux/crypto.h>
+#include <linux/kernel.h>
#define CAMELLIA_MIN_KEY_SIZE 16
#define CAMELLIA_MAX_KEY_SIZE 32
@@ -11,16 +12,13 @@
#define CAMELLIA_TABLE_BYTE_LEN 272
#define CAMELLIA_PARALLEL_BLOCKS 2
+struct crypto_skcipher;
+
struct camellia_ctx {
u64 key_table[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)];
u32 key_length;
};
-struct camellia_lrw_ctx {
- struct lrw_table_ctx lrw_table;
- struct camellia_ctx camellia_ctx;
-};
-
struct camellia_xts_ctx {
struct camellia_ctx tweak_ctx;
struct camellia_ctx crypt_ctx;
@@ -30,11 +28,7 @@ extern int __camellia_setkey(struct camellia_ctx *cctx,
const unsigned char *key,
unsigned int key_len, u32 *flags);
-extern int lrw_camellia_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen);
-extern void lrw_camellia_exit_tfm(struct crypto_tfm *tfm);
-
-extern int xts_camellia_setkey(struct crypto_tfm *tfm, const u8 *key,
+extern int xts_camellia_setkey(struct crypto_skcipher *tfm, const u8 *key,
unsigned int keylen);
/* regular block cipher functions */
diff --git a/arch/x86/include/asm/crypto/glue_helper.h b/arch/x86/include/asm/crypto/glue_helper.h
index 553a03de55c3..d1818634ae7e 100644
--- a/arch/x86/include/asm/crypto/glue_helper.h
+++ b/arch/x86/include/asm/crypto/glue_helper.h
@@ -45,7 +45,7 @@ struct common_glue_ctx {
};
static inline bool glue_fpu_begin(unsigned int bsize, int fpu_blocks_limit,
- struct blkcipher_desc *desc,
+ struct skcipher_walk *walk,
bool fpu_enabled, unsigned int nbytes)
{
if (likely(fpu_blocks_limit < 0))
@@ -61,33 +61,6 @@ static inline bool glue_fpu_begin(unsigned int bsize, int fpu_blocks_limit,
if (nbytes < bsize * (unsigned int)fpu_blocks_limit)
return false;
- if (desc) {
- /* prevent sleeping if FPU is in use */
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- }
-
- kernel_fpu_begin();
- return true;
-}
-
-static inline bool glue_skwalk_fpu_begin(unsigned int bsize,
- int fpu_blocks_limit,
- struct skcipher_walk *walk,
- bool fpu_enabled, unsigned int nbytes)
-{
- if (likely(fpu_blocks_limit < 0))
- return false;
-
- if (fpu_enabled)
- return true;
-
- /*
- * Vector-registers are only used when chunk to be processed is large
- * enough, so do not enable FPU until it is necessary.
- */
- if (nbytes < bsize * (unsigned int)fpu_blocks_limit)
- return false;
-
/* prevent sleeping if FPU is in use */
skcipher_walk_atomise(walk);
@@ -126,41 +99,17 @@ static inline void le128_inc(le128 *i)
i->b = cpu_to_le64(b);
}
-extern int glue_ecb_crypt_128bit(const struct common_glue_ctx *gctx,
- struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes);
-
-extern int glue_cbc_encrypt_128bit(const common_glue_func_t fn,
- struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes);
-
-extern int glue_cbc_decrypt_128bit(const struct common_glue_ctx *gctx,
- struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes);
-
-extern int glue_ctr_crypt_128bit(const struct common_glue_ctx *gctx,
- struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes);
-
-extern int glue_xts_crypt_128bit(const struct common_glue_ctx *gctx,
- struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes,
- common_glue_func_t tweak_fn, void *tweak_ctx,
- void *crypt_ctx);
-
-extern int glue_xts_crypt_128bit(const struct common_glue_ctx *gctx,
- struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes,
- common_glue_func_t tweak_fn, void *tweak_ctx,
- void *crypt_ctx);
+extern int glue_ecb_req_128bit(const struct common_glue_ctx *gctx,
+ struct skcipher_request *req);
+
+extern int glue_cbc_encrypt_req_128bit(const common_glue_func_t fn,
+ struct skcipher_request *req);
+
+extern int glue_cbc_decrypt_req_128bit(const struct common_glue_ctx *gctx,
+ struct skcipher_request *req);
+
+extern int glue_ctr_req_128bit(const struct common_glue_ctx *gctx,
+ struct skcipher_request *req);
extern int glue_xts_req_128bit(const struct common_glue_ctx *gctx,
struct skcipher_request *req,
diff --git a/arch/x86/include/asm/crypto/serpent-avx.h b/arch/x86/include/asm/crypto/serpent-avx.h
index c958b7bd0fcb..db7c9cc32234 100644
--- a/arch/x86/include/asm/crypto/serpent-avx.h
+++ b/arch/x86/include/asm/crypto/serpent-avx.h
@@ -2,15 +2,13 @@
#ifndef ASM_X86_SERPENT_AVX_H
#define ASM_X86_SERPENT_AVX_H
-#include <linux/crypto.h>
+#include <crypto/b128ops.h>
#include <crypto/serpent.h>
+#include <linux/types.h>
-#define SERPENT_PARALLEL_BLOCKS 8
+struct crypto_skcipher;
-struct serpent_lrw_ctx {
- struct lrw_table_ctx lrw_table;
- struct serpent_ctx serpent_ctx;
-};
+#define SERPENT_PARALLEL_BLOCKS 8
struct serpent_xts_ctx {
struct serpent_ctx tweak_ctx;
@@ -38,12 +36,7 @@ extern void __serpent_crypt_ctr(void *ctx, u128 *dst, const u128 *src,
extern void serpent_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv);
extern void serpent_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv);
-extern int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen);
-
-extern void lrw_serpent_exit_tfm(struct crypto_tfm *tfm);
-
-extern int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
+extern int xts_serpent_setkey(struct crypto_skcipher *tfm, const u8 *key,
unsigned int keylen);
#endif
diff --git a/arch/x86/include/asm/crypto/twofish.h b/arch/x86/include/asm/crypto/twofish.h
index 65bb80adba3e..f618bf272b90 100644
--- a/arch/x86/include/asm/crypto/twofish.h
+++ b/arch/x86/include/asm/crypto/twofish.h
@@ -4,19 +4,8 @@
#include <linux/crypto.h>
#include <crypto/twofish.h>
-#include <crypto/lrw.h>
#include <crypto/b128ops.h>
-struct twofish_lrw_ctx {
- struct lrw_table_ctx lrw_table;
- struct twofish_ctx twofish_ctx;
-};
-
-struct twofish_xts_ctx {
- struct twofish_ctx tweak_ctx;
- struct twofish_ctx crypt_ctx;
-};
-
/* regular block cipher functions from twofish_x86_64 module */
asmlinkage void twofish_enc_blk(struct twofish_ctx *ctx, u8 *dst,
const u8 *src);
@@ -36,12 +25,4 @@ extern void twofish_enc_blk_ctr(void *ctx, u128 *dst, const u128 *src,
extern void twofish_enc_blk_ctr_3way(void *ctx, u128 *dst, const u128 *src,
le128 *iv);
-extern int lrw_twofish_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen);
-
-extern void lrw_twofish_exit_tfm(struct crypto_tfm *tfm);
-
-extern int xts_twofish_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen);
-
#endif /* ASM_X86_TWOFISH_H */
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index 7c341a74ec8c..5ea2afd4c871 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -40,6 +40,7 @@ typedef struct {
#endif
#if IS_ENABLED(CONFIG_HYPERV)
unsigned int irq_hv_reenlightenment_count;
+ unsigned int hyperv_stimer0_count;
#endif
} ____cacheline_aligned irq_cpustat_t;
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h
index e71c1120426b..404c5fdff859 100644
--- a/arch/x86/include/asm/irq_vectors.h
+++ b/arch/x86/include/asm/irq_vectors.h
@@ -106,9 +106,10 @@
#if IS_ENABLED(CONFIG_HYPERV)
#define HYPERV_REENLIGHTENMENT_VECTOR 0xee
+#define HYPERV_STIMER0_VECTOR 0xed
#endif
-#define LOCAL_TIMER_VECTOR 0xed
+#define LOCAL_TIMER_VECTOR 0xec
#define NR_VECTORS 256
diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
index 25283f7eb299..e73c4d0c06ad 100644
--- a/arch/x86/include/asm/mshyperv.h
+++ b/arch/x86/include/asm/mshyperv.h
@@ -173,6 +173,19 @@ void hv_remove_kexec_handler(void);
void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs));
void hv_remove_crash_handler(void);
+/*
+ * Routines for stimer0 Direct Mode handling.
+ * On x86/x64, there are no percpu actions to take.
+ */
+void hv_stimer0_vector_handler(struct pt_regs *regs);
+void hv_stimer0_callback_vector(void);
+int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void));
+void hv_remove_stimer0_irq(int irq);
+
+static inline void hv_enable_stimer0_percpu_irq(int irq) {}
+static inline void hv_disable_stimer0_percpu_irq(int irq) {}
+
+
#if IS_ENABLED(CONFIG_HYPERV)
extern struct clocksource *hyperv_cs;
extern void *hv_hypercall_pg;
diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h
index 099414345865..6c0c3a3b631c 100644
--- a/arch/x86/include/uapi/asm/hyperv.h
+++ b/arch/x86/include/uapi/asm/hyperv.h
@@ -77,6 +77,9 @@
/* Crash MSR available */
#define HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE (1 << 10)
+/* stimer Direct Mode is available */
+#define HV_X64_STIMER_DIRECT_MODE_AVAILABLE (1 << 19)
+
/*
* Feature identification: EBX indicates which flags were specified at
* partition creation. The format is the same as the partition creation
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 9340f41ce8d3..4488cf0dd499 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -37,6 +37,7 @@ EXPORT_SYMBOL_GPL(ms_hyperv);
#if IS_ENABLED(CONFIG_HYPERV)
static void (*vmbus_handler)(void);
+static void (*hv_stimer0_handler)(void);
static void (*hv_kexec_handler)(void);
static void (*hv_crash_handler)(struct pt_regs *regs);
@@ -69,6 +70,41 @@ void hv_remove_vmbus_irq(void)
EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq);
EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq);
+/*
+ * Routines to do per-architecture handling of stimer0
+ * interrupts when in Direct Mode
+ */
+
+__visible void __irq_entry hv_stimer0_vector_handler(struct pt_regs *regs)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+
+ entering_irq();
+ inc_irq_stat(hyperv_stimer0_count);
+ if (hv_stimer0_handler)
+ hv_stimer0_handler();
+ ack_APIC_irq();
+
+ exiting_irq();
+ set_irq_regs(old_regs);
+}
+
+int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void))
+{
+ *vector = HYPERV_STIMER0_VECTOR;
+ *irq = 0; /* Unused on x86/x64 */
+ hv_stimer0_handler = handler;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hv_setup_stimer0_irq);
+
+void hv_remove_stimer0_irq(int irq)
+{
+ /* We have no way to deallocate the interrupt gate */
+ hv_stimer0_handler = NULL;
+}
+EXPORT_SYMBOL_GPL(hv_remove_stimer0_irq);
+
void hv_setup_kexec_handler(void (*handler)(void))
{
hv_kexec_handler = handler;
@@ -257,6 +293,10 @@ static void __init ms_hyperv_init_platform(void)
alloc_intr_gate(HYPERV_REENLIGHTENMENT_VECTOR,
hyperv_reenlightenment_vector);
+ /* Setup the IDT for stimer0 */
+ if (ms_hyperv.misc_features & HV_X64_STIMER_DIRECT_MODE_AVAILABLE)
+ alloc_intr_gate(HYPERV_STIMER0_VECTOR,
+ hv_stimer0_callback_vector);
#endif
}
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 45fb4d2565f8..328d027d829d 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -150,6 +150,13 @@ int arch_show_interrupts(struct seq_file *p, int prec)
irq_stats(j)->irq_hv_reenlightenment_count);
seq_puts(p, " Hyper-V reenlightenment interrupts\n");
}
+ if (test_bit(HYPERV_STIMER0_VECTOR, system_vectors)) {
+ seq_printf(p, "%*s: ", prec, "HVS");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ",
+ irq_stats(j)->hyperv_stimer0_count);
+ seq_puts(p, " Hyper-V stimer0 interrupts\n");
+ }
#endif
seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
#if defined(CONFIG_X86_IO_APIC)
diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c
index 838a4dc90a6d..df92605d8724 100644
--- a/arch/x86/kernel/signal_compat.c
+++ b/arch/x86/kernel/signal_compat.c
@@ -26,7 +26,7 @@ static inline void signal_compat_build_tests(void)
* new fields are handled in copy_siginfo_to_user32()!
*/
BUILD_BUG_ON(NSIGILL != 11);
- BUILD_BUG_ON(NSIGFPE != 13);
+ BUILD_BUG_ON(NSIGFPE != 14);
BUILD_BUG_ON(NSIGSEGV != 7);
BUILD_BUG_ON(NSIGBUS != 5);
BUILD_BUG_ON(NSIGTRAP != 4);
diff --git a/block/genhd.c b/block/genhd.c
index 9656f9e9f99e..dc7e089373b9 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -308,19 +308,22 @@ void blkdev_show(struct seq_file *seqf, off_t offset)
/**
* register_blkdev - register a new block device
*
- * @major: the requested major device number [1..255]. If @major = 0, try to
- * allocate any unused major number.
+ * @major: the requested major device number [1..BLKDEV_MAJOR_MAX-1]. If
+ * @major = 0, try to allocate any unused major number.
* @name: the name of the new block device as a zero terminated string
*
* The @name must be unique within the system.
*
* The return value depends on the @major input parameter:
*
- * - if a major device number was requested in range [1..255] then the
- * function returns zero on success, or a negative error code
+ * - if a major device number was requested in range [1..BLKDEV_MAJOR_MAX-1]
+ * then the function returns zero on success, or a negative error code
* - if any unused major number was requested with @major = 0 parameter
* then the return value is the allocated major number in range
- * [1..255] or a negative error code otherwise
+ * [1..BLKDEV_MAJOR_MAX-1] or a negative error code otherwise
+ *
+ * See Documentation/admin-guide/devices.txt for the list of allocated
+ * major numbers.
*/
int register_blkdev(unsigned int major, const char *name)
{
@@ -347,8 +350,8 @@ int register_blkdev(unsigned int major, const char *name)
}
if (major >= BLKDEV_MAJOR_MAX) {
- pr_err("register_blkdev: major requested (%d) is greater than the maximum (%d) for %s\n",
- major, BLKDEV_MAJOR_MAX, name);
+ pr_err("register_blkdev: major requested (%u) is greater than the maximum (%u) for %s\n",
+ major, BLKDEV_MAJOR_MAX-1, name);
ret = -EINVAL;
goto out;
@@ -375,7 +378,7 @@ int register_blkdev(unsigned int major, const char *name)
ret = -EBUSY;
if (ret < 0) {
- printk("register_blkdev: cannot get major %d for %s\n",
+ printk("register_blkdev: cannot get major %u for %s\n",
major, name);
kfree(p);
}
diff --git a/crypto/Kconfig b/crypto/Kconfig
index b75264b09a46..c0dabed5122e 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -245,10 +245,6 @@ config CRYPTO_TEST
help
Quick & dirty crypto test module.
-config CRYPTO_ABLK_HELPER
- tristate
- select CRYPTO_CRYPTD
-
config CRYPTO_SIMD
tristate
select CRYPTO_CRYPTD
@@ -324,6 +320,14 @@ config CRYPTO_CBC
CBC: Cipher Block Chaining mode
This block cipher algorithm is required for IPSec.
+config CRYPTO_CFB
+ tristate "CFB support"
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_MANAGER
+ help
+ CFB: Cipher FeedBack mode
+ This block cipher algorithm is required for TPM2 Cryptography.
+
config CRYPTO_CTR
tristate "CTR support"
select CRYPTO_BLKCIPHER
@@ -1114,7 +1118,7 @@ config CRYPTO_BLOWFISH_COMMON
config CRYPTO_BLOWFISH_X86_64
tristate "Blowfish cipher algorithm (x86_64)"
depends on X86 && 64BIT
- select CRYPTO_ALGAPI
+ select CRYPTO_BLKCIPHER
select CRYPTO_BLOWFISH_COMMON
help
Blowfish cipher algorithm (x86_64), by Bruce Schneier.
@@ -1145,10 +1149,8 @@ config CRYPTO_CAMELLIA_X86_64
tristate "Camellia cipher algorithm (x86_64)"
depends on X86 && 64BIT
depends on CRYPTO
- select CRYPTO_ALGAPI
+ select CRYPTO_BLKCIPHER
select CRYPTO_GLUE_HELPER_X86
- select CRYPTO_LRW
- select CRYPTO_XTS
help
Camellia cipher algorithm module (x86_64).
@@ -1164,12 +1166,10 @@ config CRYPTO_CAMELLIA_AESNI_AVX_X86_64
tristate "Camellia cipher algorithm (x86_64/AES-NI/AVX)"
depends on X86 && 64BIT
depends on CRYPTO
- select CRYPTO_ALGAPI
- select CRYPTO_CRYPTD
- select CRYPTO_ABLK_HELPER
- select CRYPTO_GLUE_HELPER_X86
+ select CRYPTO_BLKCIPHER
select CRYPTO_CAMELLIA_X86_64
- select CRYPTO_LRW
+ select CRYPTO_GLUE_HELPER_X86
+ select CRYPTO_SIMD
select CRYPTO_XTS
help
Camellia cipher algorithm module (x86_64/AES-NI/AVX).
@@ -1186,14 +1186,7 @@ config CRYPTO_CAMELLIA_AESNI_AVX2_X86_64
tristate "Camellia cipher algorithm (x86_64/AES-NI/AVX2)"
depends on X86 && 64BIT
depends on CRYPTO
- select CRYPTO_ALGAPI
- select CRYPTO_CRYPTD
- select CRYPTO_ABLK_HELPER
- select CRYPTO_GLUE_HELPER_X86
- select CRYPTO_CAMELLIA_X86_64
select CRYPTO_CAMELLIA_AESNI_AVX_X86_64
- select CRYPTO_LRW
- select CRYPTO_XTS
help
Camellia cipher algorithm module (x86_64/AES-NI/AVX2).
@@ -1238,11 +1231,10 @@ config CRYPTO_CAST5
config CRYPTO_CAST5_AVX_X86_64
tristate "CAST5 (CAST-128) cipher algorithm (x86_64/AVX)"
depends on X86 && 64BIT
- select CRYPTO_ALGAPI
- select CRYPTO_CRYPTD
- select CRYPTO_ABLK_HELPER
- select CRYPTO_CAST_COMMON
+ select CRYPTO_BLKCIPHER
select CRYPTO_CAST5
+ select CRYPTO_CAST_COMMON
+ select CRYPTO_SIMD
help
The CAST5 encryption algorithm (synonymous with CAST-128) is
described in RFC2144.
@@ -1261,13 +1253,11 @@ config CRYPTO_CAST6
config CRYPTO_CAST6_AVX_X86_64
tristate "CAST6 (CAST-256) cipher algorithm (x86_64/AVX)"
depends on X86 && 64BIT
- select CRYPTO_ALGAPI
- select CRYPTO_CRYPTD
- select CRYPTO_ABLK_HELPER
- select CRYPTO_GLUE_HELPER_X86
- select CRYPTO_CAST_COMMON
+ select CRYPTO_BLKCIPHER
select CRYPTO_CAST6
- select CRYPTO_LRW
+ select CRYPTO_CAST_COMMON
+ select CRYPTO_GLUE_HELPER_X86
+ select CRYPTO_SIMD
select CRYPTO_XTS
help
The CAST6 encryption algorithm (synonymous with CAST-256) is
@@ -1294,7 +1284,7 @@ config CRYPTO_DES_SPARC64
config CRYPTO_DES3_EDE_X86_64
tristate "Triple DES EDE cipher algorithm (x86-64)"
depends on X86 && 64BIT
- select CRYPTO_ALGAPI
+ select CRYPTO_BLKCIPHER
select CRYPTO_DES
help
Triple DES EDE (FIPS 46-3) algorithm.
@@ -1422,13 +1412,10 @@ config CRYPTO_SERPENT
config CRYPTO_SERPENT_SSE2_X86_64
tristate "Serpent cipher algorithm (x86_64/SSE2)"
depends on X86 && 64BIT
- select CRYPTO_ALGAPI
- select CRYPTO_CRYPTD
- select CRYPTO_ABLK_HELPER
+ select CRYPTO_BLKCIPHER
select CRYPTO_GLUE_HELPER_X86
select CRYPTO_SERPENT
- select CRYPTO_LRW
- select CRYPTO_XTS
+ select CRYPTO_SIMD
help
Serpent cipher algorithm, by Anderson, Biham & Knudsen.
@@ -1444,13 +1431,10 @@ config CRYPTO_SERPENT_SSE2_X86_64
config CRYPTO_SERPENT_SSE2_586
tristate "Serpent cipher algorithm (i586/SSE2)"
depends on X86 && !64BIT
- select CRYPTO_ALGAPI
- select CRYPTO_CRYPTD
- select CRYPTO_ABLK_HELPER
+ select CRYPTO_BLKCIPHER
select CRYPTO_GLUE_HELPER_X86
select CRYPTO_SERPENT
- select CRYPTO_LRW
- select CRYPTO_XTS
+ select CRYPTO_SIMD
help
Serpent cipher algorithm, by Anderson, Biham & Knudsen.
@@ -1466,12 +1450,10 @@ config CRYPTO_SERPENT_SSE2_586
config CRYPTO_SERPENT_AVX_X86_64
tristate "Serpent cipher algorithm (x86_64/AVX)"
depends on X86 && 64BIT
- select CRYPTO_ALGAPI
- select CRYPTO_CRYPTD
- select CRYPTO_ABLK_HELPER
+ select CRYPTO_BLKCIPHER
select CRYPTO_GLUE_HELPER_X86
select CRYPTO_SERPENT
- select CRYPTO_LRW
+ select CRYPTO_SIMD
select CRYPTO_XTS
help
Serpent cipher algorithm, by Anderson, Biham & Knudsen.
@@ -1488,14 +1470,7 @@ config CRYPTO_SERPENT_AVX_X86_64
config CRYPTO_SERPENT_AVX2_X86_64
tristate "Serpent cipher algorithm (x86_64/AVX2)"
depends on X86 && 64BIT
- select CRYPTO_ALGAPI
- select CRYPTO_CRYPTD
- select CRYPTO_ABLK_HELPER
- select CRYPTO_GLUE_HELPER_X86
- select CRYPTO_SERPENT
select CRYPTO_SERPENT_AVX_X86_64
- select CRYPTO_LRW
- select CRYPTO_XTS
help
Serpent cipher algorithm, by Anderson, Biham & Knudsen.
@@ -1508,6 +1483,45 @@ config CRYPTO_SERPENT_AVX2_X86_64
See also:
<http://www.cl.cam.ac.uk/~rja14/serpent.html>
+config CRYPTO_SM4
+ tristate "SM4 cipher algorithm"
+ select CRYPTO_ALGAPI
+ help
+ SM4 cipher algorithms (OSCCA GB/T 32907-2016).
+
+ SM4 (GBT.32907-2016) is a cryptographic standard issued by the
+ Organization of State Commercial Administration of China (OSCCA)
+ as an authorized cryptographic algorithms for the use within China.
+
+ SMS4 was originally created for use in protecting wireless
+ networks, and is mandated in the Chinese National Standard for
+ Wireless LAN WAPI (Wired Authentication and Privacy Infrastructure)
+ (GB.15629.11-2003).
+
+ The latest SM4 standard (GBT.32907-2016) was proposed by OSCCA and
+ standardized through TC 260 of the Standardization Administration
+ of the People's Republic of China (SAC).
+
+ The input, output, and key of SMS4 are each 128 bits.
+
+ See also: <https://eprint.iacr.org/2008/329.pdf>
+
+ If unsure, say N.
+
+config CRYPTO_SPECK
+ tristate "Speck cipher algorithm"
+ select CRYPTO_ALGAPI
+ help
+ Speck is a lightweight block cipher that is tuned for optimal
+ performance in software (rather than hardware).
+
+ Speck may not be as secure as AES, and should only be used on systems
+ where AES is not fast enough.
+
+ See also: <https://eprint.iacr.org/2013/404.pdf>
+
+ If unsure, say N.
+
config CRYPTO_TEA
tristate "TEA, XTEA and XETA cipher algorithms"
select CRYPTO_ALGAPI
@@ -1581,12 +1595,10 @@ config CRYPTO_TWOFISH_X86_64
config CRYPTO_TWOFISH_X86_64_3WAY
tristate "Twofish cipher algorithm (x86_64, 3-way parallel)"
depends on X86 && 64BIT
- select CRYPTO_ALGAPI
+ select CRYPTO_BLKCIPHER
select CRYPTO_TWOFISH_COMMON
select CRYPTO_TWOFISH_X86_64
select CRYPTO_GLUE_HELPER_X86
- select CRYPTO_LRW
- select CRYPTO_XTS
help
Twofish cipher algorithm (x86_64, 3-way parallel).
@@ -1604,15 +1616,12 @@ config CRYPTO_TWOFISH_X86_64_3WAY
config CRYPTO_TWOFISH_AVX_X86_64
tristate "Twofish cipher algorithm (x86_64/AVX)"
depends on X86 && 64BIT
- select CRYPTO_ALGAPI
- select CRYPTO_CRYPTD
- select CRYPTO_ABLK_HELPER
+ select CRYPTO_BLKCIPHER
select CRYPTO_GLUE_HELPER_X86
+ select CRYPTO_SIMD
select CRYPTO_TWOFISH_COMMON
select CRYPTO_TWOFISH_X86_64
select CRYPTO_TWOFISH_X86_64_3WAY
- select CRYPTO_LRW
- select CRYPTO_XTS
help
Twofish cipher algorithm (x86_64/AVX).
diff --git a/crypto/Makefile b/crypto/Makefile
index cdbc03b35510..4fc69fe94e6a 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o
obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o
obj-$(CONFIG_CRYPTO_ECB) += ecb.o
obj-$(CONFIG_CRYPTO_CBC) += cbc.o
+obj-$(CONFIG_CRYPTO_CFB) += cfb.o
obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o
obj-$(CONFIG_CRYPTO_CTS) += cts.o
obj-$(CONFIG_CRYPTO_LRW) += lrw.o
@@ -100,6 +101,7 @@ obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o
CFLAGS_serpent_generic.o := $(call cc-option,-fsched-pressure) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79149
obj-$(CONFIG_CRYPTO_AES) += aes_generic.o
CFLAGS_aes_generic.o := $(call cc-option,-fno-code-hoisting) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83356
+obj-$(CONFIG_CRYPTO_SM4) += sm4_generic.o
obj-$(CONFIG_CRYPTO_AES_TI) += aes_ti.o
obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o
obj-$(CONFIG_CRYPTO_CAST_COMMON) += cast_common.o
@@ -110,6 +112,7 @@ obj-$(CONFIG_CRYPTO_TEA) += tea.o
obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o
obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o
obj-$(CONFIG_CRYPTO_SEED) += seed.o
+obj-$(CONFIG_CRYPTO_SPECK) += speck.o
obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o
obj-$(CONFIG_CRYPTO_CHACHA20) += chacha20_generic.o
obj-$(CONFIG_CRYPTO_POLY1305) += poly1305_generic.o
@@ -149,6 +152,5 @@ obj-$(CONFIG_XOR_BLOCKS) += xor.o
obj-$(CONFIG_ASYNC_CORE) += async_tx/
obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/
obj-$(CONFIG_CRYPTO_HASH_INFO) += hash_info.o
-obj-$(CONFIG_CRYPTO_ABLK_HELPER) += ablk_helper.o
crypto_simd-y := simd.o
obj-$(CONFIG_CRYPTO_SIMD) += crypto_simd.o
diff --git a/crypto/ablk_helper.c b/crypto/ablk_helper.c
deleted file mode 100644
index 09776bb1360e..000000000000
--- a/crypto/ablk_helper.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Shared async block cipher helpers
- *
- * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
- *
- * Based on aesni-intel_glue.c by:
- * Copyright (C) 2008, Intel Corp.
- * Author: Huang Ying <ying.huang@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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/kernel.h>
-#include <linux/crypto.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <crypto/algapi.h>
-#include <crypto/cryptd.h>
-#include <crypto/ablk_helper.h>
-#include <asm/simd.h>
-
-int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
- unsigned int key_len)
-{
- struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm);
- struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base;
- int err;
-
- crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
- crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm)
- & CRYPTO_TFM_REQ_MASK);
- err = crypto_ablkcipher_setkey(child, key, key_len);
- crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child)
- & CRYPTO_TFM_RES_MASK);
- return err;
-}
-EXPORT_SYMBOL_GPL(ablk_set_key);
-
-int __ablk_encrypt(struct ablkcipher_request *req)
-{
- struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
- struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm);
- struct blkcipher_desc desc;
-
- desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
- desc.info = req->info;
- desc.flags = 0;
-
- return crypto_blkcipher_crt(desc.tfm)->encrypt(
- &desc, req->dst, req->src, req->nbytes);
-}
-EXPORT_SYMBOL_GPL(__ablk_encrypt);
-
-int ablk_encrypt(struct ablkcipher_request *req)
-{
- struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
- struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm);
-
- if (!may_use_simd() ||
- (in_atomic() && cryptd_ablkcipher_queued(ctx->cryptd_tfm))) {
- struct ablkcipher_request *cryptd_req =
- ablkcipher_request_ctx(req);
-
- *cryptd_req = *req;
- ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
-
- return crypto_ablkcipher_encrypt(cryptd_req);
- } else {
- return __ablk_encrypt(req);
- }
-}
-EXPORT_SYMBOL_GPL(ablk_encrypt);
-
-int ablk_decrypt(struct ablkcipher_request *req)
-{
- struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
- struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm);
-
- if (!may_use_simd() ||
- (in_atomic() && cryptd_ablkcipher_queued(ctx->cryptd_tfm))) {
- struct ablkcipher_request *cryptd_req =
- ablkcipher_request_ctx(req);
-
- *cryptd_req = *req;
- ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
-
- return crypto_ablkcipher_decrypt(cryptd_req);
- } else {
- struct blkcipher_desc desc;
-
- desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
- desc.info = req->info;
- desc.flags = 0;
-
- return crypto_blkcipher_crt(desc.tfm)->decrypt(
- &desc, req->dst, req->src, req->nbytes);
- }
-}
-EXPORT_SYMBOL_GPL(ablk_decrypt);
-
-void ablk_exit(struct crypto_tfm *tfm)
-{
- struct async_helper_ctx *ctx = crypto_tfm_ctx(tfm);
-
- cryptd_free_ablkcipher(ctx->cryptd_tfm);
-}
-EXPORT_SYMBOL_GPL(ablk_exit);
-
-int ablk_init_common(struct crypto_tfm *tfm, const char *drv_name)
-{
- struct async_helper_ctx *ctx = crypto_tfm_ctx(tfm);
- struct cryptd_ablkcipher *cryptd_tfm;
-
- cryptd_tfm = cryptd_alloc_ablkcipher(drv_name, CRYPTO_ALG_INTERNAL,
- CRYPTO_ALG_INTERNAL);
- if (IS_ERR(cryptd_tfm))
- return PTR_ERR(cryptd_tfm);
-
- ctx->cryptd_tfm = cryptd_tfm;
- tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
- crypto_ablkcipher_reqsize(&cryptd_tfm->base);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ablk_init_common);
-
-int ablk_init(struct crypto_tfm *tfm)
-{
- char drv_name[CRYPTO_MAX_ALG_NAME];
-
- snprintf(drv_name, sizeof(drv_name), "__driver-%s",
- crypto_tfm_alg_driver_name(tfm));
-
- return ablk_init_common(tfm, drv_name);
-}
-EXPORT_SYMBOL_GPL(ablk_init);
-
-MODULE_LICENSE("GPL");
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index c49766b03165..7846c0c20cfe 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -158,16 +158,16 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
void *private;
int err;
- /* If caller uses non-allowed flag, return error. */
- if ((sa->salg_feat & ~allowed) || (sa->salg_mask & ~allowed))
- return -EINVAL;
-
if (sock->state == SS_CONNECTED)
return -EINVAL;
if (addr_len < sizeof(*sa))
return -EINVAL;
+ /* If caller uses non-allowed flag, return error. */
+ if ((sa->salg_feat & ~allowed) || (sa->salg_mask & ~allowed))
+ return -EINVAL;
+
sa->salg_type[sizeof(sa->salg_type) - 1] = 0;
sa->salg_name[sizeof(sa->salg_name) + addr_len - sizeof(*sa) - 1] = 0;
diff --git a/crypto/ahash.c b/crypto/ahash.c
index 266fc1d64f61..a64c143165b1 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -92,13 +92,14 @@ int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err)
if (nbytes && walk->offset & alignmask && !err) {
walk->offset = ALIGN(walk->offset, alignmask + 1);
- walk->data += walk->offset;
-
nbytes = min(nbytes,
((unsigned int)(PAGE_SIZE)) - walk->offset);
walk->entrylen -= nbytes;
- return nbytes;
+ if (nbytes) {
+ walk->data += walk->offset;
+ return nbytes;
+ }
}
if (walk->flags & CRYPTO_ALG_ASYNC)
@@ -446,24 +447,12 @@ static int ahash_def_finup(struct ahash_request *req)
return ahash_def_finup_finish1(req, err);
}
-static int ahash_no_export(struct ahash_request *req, void *out)
-{
- return -ENOSYS;
-}
-
-static int ahash_no_import(struct ahash_request *req, const void *in)
-{
- return -ENOSYS;
-}
-
static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
{
struct crypto_ahash *hash = __crypto_ahash_cast(tfm);
struct ahash_alg *alg = crypto_ahash_alg(hash);
hash->setkey = ahash_nosetkey;
- hash->export = ahash_no_export;
- hash->import = ahash_no_import;
if (tfm->__crt_alg->cra_type != &crypto_ahash_type)
return crypto_init_shash_ops_async(tfm);
@@ -473,16 +462,14 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
hash->final = alg->final;
hash->finup = alg->finup ?: ahash_def_finup;
hash->digest = alg->digest;
+ hash->export = alg->export;
+ hash->import = alg->import;
if (alg->setkey) {
hash->setkey = alg->setkey;
if (!(alg->halg.base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY))
crypto_ahash_set_flags(hash, CRYPTO_TFM_NEED_KEY);
}
- if (alg->export)
- hash->export = alg->export;
- if (alg->import)
- hash->import = alg->import;
return 0;
}
diff --git a/crypto/algapi.c b/crypto/algapi.c
index 395b082d03a9..2a0271b5f62a 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -543,9 +543,6 @@ int crypto_register_instance(struct crypto_template *tmpl,
inst->alg.cra_module = tmpl->module;
inst->alg.cra_flags |= CRYPTO_ALG_INSTANCE;
- if (unlikely(!crypto_mod_get(&inst->alg)))
- return -EAGAIN;
-
down_write(&crypto_alg_sem);
larval = __crypto_register_alg(&inst->alg);
@@ -563,14 +560,9 @@ unlock:
goto err;
crypto_wait_for_test(larval);
-
- /* Remove instance if test failed */
- if (!(inst->alg.cra_flags & CRYPTO_ALG_TESTED))
- crypto_unregister_instance(inst);
err = 0;
err:
- crypto_mod_put(&inst->alg);
return err;
}
EXPORT_SYMBOL_GPL(crypto_register_instance);
diff --git a/crypto/api.c b/crypto/api.c
index 70a894e52ff3..1d5290c67108 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -193,17 +193,24 @@ static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
return alg;
}
-struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, u32 mask)
+static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type,
+ u32 mask)
{
struct crypto_alg *alg;
+ u32 test = 0;
+
+ if (!((type | mask) & CRYPTO_ALG_TESTED))
+ test |= CRYPTO_ALG_TESTED;
down_read(&crypto_alg_sem);
- alg = __crypto_alg_lookup(name, type, mask);
+ alg = __crypto_alg_lookup(name, type | test, mask | test);
+ if (!alg && test)
+ alg = __crypto_alg_lookup(name, type, mask) ?
+ ERR_PTR(-ELIBBAD) : NULL;
up_read(&crypto_alg_sem);
return alg;
}
-EXPORT_SYMBOL_GPL(crypto_alg_lookup);
static struct crypto_alg *crypto_larval_lookup(const char *name, u32 type,
u32 mask)
@@ -227,10 +234,12 @@ static struct crypto_alg *crypto_larval_lookup(const char *name, u32 type,
alg = crypto_alg_lookup(name, type, mask);
}
- if (alg)
- return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg;
+ if (!IS_ERR_OR_NULL(alg) && crypto_is_larval(alg))
+ alg = crypto_larval_wait(alg);
+ else if (!alg)
+ alg = crypto_larval_add(name, type, mask);
- return crypto_larval_add(name, type, mask);
+ return alg;
}
int crypto_probing_notify(unsigned long val, void *v)
@@ -253,11 +262,6 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
struct crypto_alg *larval;
int ok;
- if (!((type | mask) & CRYPTO_ALG_TESTED)) {
- type |= CRYPTO_ALG_TESTED;
- mask |= CRYPTO_ALG_TESTED;
- }
-
/*
* If the internal flag is set for a cipher, require a caller to
* to invoke the cipher with the internal flag to use that cipher.
@@ -485,20 +489,14 @@ struct crypto_alg *crypto_find_alg(const char *alg_name,
const struct crypto_type *frontend,
u32 type, u32 mask)
{
- struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask) =
- crypto_alg_mod_lookup;
-
if (frontend) {
type &= frontend->maskclear;
mask &= frontend->maskclear;
type |= frontend->type;
mask |= frontend->maskset;
-
- if (frontend->lookup)
- lookup = frontend->lookup;
}
- return lookup(alg_name, type, mask);
+ return crypto_alg_mod_lookup(alg_name, type, mask);
}
EXPORT_SYMBOL_GPL(crypto_find_alg);
diff --git a/crypto/cfb.c b/crypto/cfb.c
new file mode 100644
index 000000000000..94ee39bed758
--- /dev/null
+++ b/crypto/cfb.c
@@ -0,0 +1,353 @@
+//SPDX-License-Identifier: GPL-2.0
+/*
+ * CFB: Cipher FeedBack mode
+ *
+ * Copyright (c) 2018 James.Bottomley@HansenPartnership.com
+ *
+ * CFB is a stream cipher mode which is layered on to a block
+ * encryption scheme. It works very much like a one time pad where
+ * the pad is generated initially from the encrypted IV and then
+ * subsequently from the encrypted previous block of ciphertext. The
+ * pad is XOR'd into the plain text to get the final ciphertext.
+ *
+ * The scheme of CFB is best described by wikipedia:
+ *
+ * https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CFB
+ *
+ * Note that since the pad for both encryption and decryption is
+ * generated by an encryption operation, CFB never uses the block
+ * decryption function.
+ */
+
+#include <crypto/algapi.h>
+#include <crypto/internal/skcipher.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+struct crypto_cfb_ctx {
+ struct crypto_cipher *child;
+};
+
+static unsigned int crypto_cfb_bsize(struct crypto_skcipher *tfm)
+{
+ struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct crypto_cipher *child = ctx->child;
+
+ return crypto_cipher_blocksize(child);
+}
+
+static void crypto_cfb_encrypt_one(struct crypto_skcipher *tfm,
+ const u8 *src, u8 *dst)
+{
+ struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+ crypto_cipher_encrypt_one(ctx->child, dst, src);
+}
+
+/* final encrypt and decrypt is the same */
+static void crypto_cfb_final(struct skcipher_walk *walk,
+ struct crypto_skcipher *tfm)
+{
+ const unsigned int bsize = crypto_cfb_bsize(tfm);
+ const unsigned long alignmask = crypto_skcipher_alignmask(tfm);
+ u8 tmp[bsize + alignmask];
+ u8 *stream = PTR_ALIGN(tmp + 0, alignmask + 1);
+ u8 *src = walk->src.virt.addr;
+ u8 *dst = walk->dst.virt.addr;
+ u8 *iv = walk->iv;
+ unsigned int nbytes = walk->nbytes;
+
+ crypto_cfb_encrypt_one(tfm, iv, stream);
+ crypto_xor_cpy(dst, stream, src, nbytes);
+}
+
+static int crypto_cfb_encrypt_segment(struct skcipher_walk *walk,
+ struct crypto_skcipher *tfm)
+{
+ const unsigned int bsize = crypto_cfb_bsize(tfm);
+ unsigned int nbytes = walk->nbytes;
+ u8 *src = walk->src.virt.addr;
+ u8 *dst = walk->dst.virt.addr;
+ u8 *iv = walk->iv;
+
+ do {
+ crypto_cfb_encrypt_one(tfm, iv, dst);
+ crypto_xor(dst, src, bsize);
+ memcpy(iv, dst, bsize);
+
+ src += bsize;
+ dst += bsize;
+ } while ((nbytes -= bsize) >= bsize);
+
+ return nbytes;
+}
+
+static int crypto_cfb_encrypt_inplace(struct skcipher_walk *walk,
+ struct crypto_skcipher *tfm)
+{
+ const unsigned int bsize = crypto_cfb_bsize(tfm);
+ unsigned int nbytes = walk->nbytes;
+ u8 *src = walk->src.virt.addr;
+ u8 *iv = walk->iv;
+ u8 tmp[bsize];
+
+ do {
+ crypto_cfb_encrypt_one(tfm, iv, tmp);
+ crypto_xor(src, tmp, bsize);
+ iv = src;
+
+ src += bsize;
+ } while ((nbytes -= bsize) >= bsize);
+
+ memcpy(walk->iv, iv, bsize);
+
+ return nbytes;
+}
+
+static int crypto_cfb_encrypt(struct skcipher_request *req)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct skcipher_walk walk;
+ unsigned int bsize = crypto_cfb_bsize(tfm);
+ int err;
+
+ err = skcipher_walk_virt(&walk, req, false);
+
+ while (walk.nbytes >= bsize) {
+ if (walk.src.virt.addr == walk.dst.virt.addr)
+ err = crypto_cfb_encrypt_inplace(&walk, tfm);
+ else
+ err = crypto_cfb_encrypt_segment(&walk, tfm);
+ err = skcipher_walk_done(&walk, err);
+ }
+
+ if (walk.nbytes) {
+ crypto_cfb_final(&walk, tfm);
+ err = skcipher_walk_done(&walk, 0);
+ }
+
+ return err;
+}
+
+static int crypto_cfb_decrypt_segment(struct skcipher_walk *walk,
+ struct crypto_skcipher *tfm)
+{
+ const unsigned int bsize = crypto_cfb_bsize(tfm);
+ unsigned int nbytes = walk->nbytes;
+ u8 *src = walk->src.virt.addr;
+ u8 *dst = walk->dst.virt.addr;
+ u8 *iv = walk->iv;
+
+ do {
+ crypto_cfb_encrypt_one(tfm, iv, dst);
+ crypto_xor(dst, iv, bsize);
+ iv = src;
+
+ src += bsize;
+ dst += bsize;
+ } while ((nbytes -= bsize) >= bsize);
+
+ memcpy(walk->iv, iv, bsize);
+
+ return nbytes;
+}
+
+static int crypto_cfb_decrypt_inplace(struct skcipher_walk *walk,
+ struct crypto_skcipher *tfm)
+{
+ const unsigned int bsize = crypto_cfb_bsize(tfm);
+ unsigned int nbytes = walk->nbytes;
+ u8 *src = walk->src.virt.addr;
+ u8 *iv = walk->iv;
+ u8 tmp[bsize];
+
+ do {
+ crypto_cfb_encrypt_one(tfm, iv, tmp);
+ memcpy(iv, src, bsize);
+ crypto_xor(src, tmp, bsize);
+ src += bsize;
+ } while ((nbytes -= bsize) >= bsize);
+
+ memcpy(walk->iv, iv, bsize);
+
+ return nbytes;
+}
+
+static int crypto_cfb_decrypt_blocks(struct skcipher_walk *walk,
+ struct crypto_skcipher *tfm)
+{
+ if (walk->src.virt.addr == walk->dst.virt.addr)
+ return crypto_cfb_decrypt_inplace(walk, tfm);
+ else
+ return crypto_cfb_decrypt_segment(walk, tfm);
+}
+
+static int crypto_cfb_setkey(struct crypto_skcipher *parent, const u8 *key,
+ unsigned int keylen)
+{
+ struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(parent);
+ struct crypto_cipher *child = ctx->child;
+ int err;
+
+ crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+ crypto_cipher_set_flags(child, crypto_skcipher_get_flags(parent) &
+ CRYPTO_TFM_REQ_MASK);
+ err = crypto_cipher_setkey(child, key, keylen);
+ crypto_skcipher_set_flags(parent, crypto_cipher_get_flags(child) &
+ CRYPTO_TFM_RES_MASK);
+ return err;
+}
+
+static int crypto_cfb_decrypt(struct skcipher_request *req)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct skcipher_walk walk;
+ const unsigned int bsize = crypto_cfb_bsize(tfm);
+ int err;
+
+ err = skcipher_walk_virt(&walk, req, false);
+
+ while (walk.nbytes >= bsize) {
+ err = crypto_cfb_decrypt_blocks(&walk, tfm);
+ err = skcipher_walk_done(&walk, err);
+ }
+
+ if (walk.nbytes) {
+ crypto_cfb_final(&walk, tfm);
+ err = skcipher_walk_done(&walk, 0);
+ }
+
+ return err;
+}
+
+static int crypto_cfb_init_tfm(struct crypto_skcipher *tfm)
+{
+ struct skcipher_instance *inst = skcipher_alg_instance(tfm);
+ struct crypto_spawn *spawn = skcipher_instance_ctx(inst);
+ struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct crypto_cipher *cipher;
+
+ cipher = crypto_spawn_cipher(spawn);
+ if (IS_ERR(cipher))
+ return PTR_ERR(cipher);
+
+ ctx->child = cipher;
+ return 0;
+}
+
+static void crypto_cfb_exit_tfm(struct crypto_skcipher *tfm)
+{
+ struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+ crypto_free_cipher(ctx->child);
+}
+
+static void crypto_cfb_free(struct skcipher_instance *inst)
+{
+ crypto_drop_skcipher(skcipher_instance_ctx(inst));
+ kfree(inst);
+}
+
+static int crypto_cfb_create(struct crypto_template *tmpl, struct rtattr **tb)
+{
+ struct skcipher_instance *inst;
+ struct crypto_attr_type *algt;
+ struct crypto_spawn *spawn;
+ struct crypto_alg *alg;
+ u32 mask;
+ int err;
+
+ err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SKCIPHER);
+ if (err)
+ return err;
+
+ inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+
+ algt = crypto_get_attr_type(tb);
+ err = PTR_ERR(algt);
+ if (IS_ERR(algt))
+ goto err_free_inst;
+
+ mask = CRYPTO_ALG_TYPE_MASK |
+ crypto_requires_off(algt->type, algt->mask,
+ CRYPTO_ALG_NEED_FALLBACK);
+
+ alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, mask);
+ err = PTR_ERR(alg);
+ if (IS_ERR(alg))
+ goto err_free_inst;
+
+ spawn = skcipher_instance_ctx(inst);
+ err = crypto_init_spawn(spawn, alg, skcipher_crypto_instance(inst),
+ CRYPTO_ALG_TYPE_MASK);
+ crypto_mod_put(alg);
+ if (err)
+ goto err_free_inst;
+
+ err = crypto_inst_setname(skcipher_crypto_instance(inst), "cfb", alg);
+ if (err)
+ goto err_drop_spawn;
+
+ inst->alg.base.cra_priority = alg->cra_priority;
+ /* we're a stream cipher independend of the crypto cra_blocksize */
+ inst->alg.base.cra_blocksize = 1;
+ inst->alg.base.cra_alignmask = alg->cra_alignmask;
+
+ inst->alg.ivsize = alg->cra_blocksize;
+ inst->alg.min_keysize = alg->cra_cipher.cia_min_keysize;
+ inst->alg.max_keysize = alg->cra_cipher.cia_max_keysize;
+
+ inst->alg.base.cra_ctxsize = sizeof(struct crypto_cfb_ctx);
+
+ inst->alg.init = crypto_cfb_init_tfm;
+ inst->alg.exit = crypto_cfb_exit_tfm;
+
+ inst->alg.setkey = crypto_cfb_setkey;
+ inst->alg.encrypt = crypto_cfb_encrypt;
+ inst->alg.decrypt = crypto_cfb_decrypt;
+
+ inst->free = crypto_cfb_free;
+
+ err = skcipher_register_instance(tmpl, inst);
+ if (err)
+ goto err_drop_spawn;
+
+out:
+ return err;
+
+err_drop_spawn:
+ crypto_drop_spawn(spawn);
+err_free_inst:
+ kfree(inst);
+ goto out;
+}
+
+static struct crypto_template crypto_cfb_tmpl = {
+ .name = "cfb",
+ .create = crypto_cfb_create,
+ .module = THIS_MODULE,
+};
+
+static int __init crypto_cfb_module_init(void)
+{
+ return crypto_register_template(&crypto_cfb_tmpl);
+}
+
+static void __exit crypto_cfb_module_exit(void)
+{
+ crypto_unregister_template(&crypto_cfb_tmpl);
+}
+
+module_init(crypto_cfb_module_init);
+module_exit(crypto_cfb_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CFB block cipher algorithm");
+MODULE_ALIAS_CRYPTO("cfb");
diff --git a/crypto/crypto_engine.c b/crypto/crypto_engine.c
index 61e7c4e02fd2..992e8d8dcdd9 100644
--- a/crypto/crypto_engine.c
+++ b/crypto/crypto_engine.c
@@ -15,13 +15,50 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <crypto/engine.h>
-#include <crypto/internal/hash.h>
#include <uapi/linux/sched/types.h>
#include "internal.h"
#define CRYPTO_ENGINE_MAX_QLEN 10
/**
+ * crypto_finalize_request - finalize one request if the request is done
+ * @engine: the hardware engine
+ * @req: the request need to be finalized
+ * @err: error number
+ */
+static void crypto_finalize_request(struct crypto_engine *engine,
+ struct crypto_async_request *req, int err)
+{
+ unsigned long flags;
+ bool finalize_cur_req = false;
+ int ret;
+ struct crypto_engine_ctx *enginectx;
+
+ spin_lock_irqsave(&engine->queue_lock, flags);
+ if (engine->cur_req == req)
+ finalize_cur_req = true;
+ spin_unlock_irqrestore(&engine->queue_lock, flags);
+
+ if (finalize_cur_req) {
+ enginectx = crypto_tfm_ctx(req->tfm);
+ if (engine->cur_req_prepared &&
+ enginectx->op.unprepare_request) {
+ ret = enginectx->op.unprepare_request(engine, req);
+ if (ret)
+ dev_err(engine->dev, "failed to unprepare request\n");
+ }
+ spin_lock_irqsave(&engine->queue_lock, flags);
+ engine->cur_req = NULL;
+ engine->cur_req_prepared = false;
+ spin_unlock_irqrestore(&engine->queue_lock, flags);
+ }
+
+ req->complete(req, err);
+
+ kthread_queue_work(engine->kworker, &engine->pump_requests);
+}
+
+/**
* crypto_pump_requests - dequeue one request from engine queue to process
* @engine: the hardware engine
* @in_kthread: true if we are in the context of the request pump thread
@@ -34,11 +71,10 @@ static void crypto_pump_requests(struct crypto_engine *engine,
bool in_kthread)
{
struct crypto_async_request *async_req, *backlog;
- struct ahash_request *hreq;
- struct ablkcipher_request *breq;
unsigned long flags;
bool was_busy = false;
- int ret, rtype;
+ int ret;
+ struct crypto_engine_ctx *enginectx;
spin_lock_irqsave(&engine->queue_lock, flags);
@@ -94,7 +130,6 @@ static void crypto_pump_requests(struct crypto_engine *engine,
spin_unlock_irqrestore(&engine->queue_lock, flags);
- rtype = crypto_tfm_alg_type(engine->cur_req->tfm);
/* Until here we get the request need to be encrypted successfully */
if (!was_busy && engine->prepare_crypt_hardware) {
ret = engine->prepare_crypt_hardware(engine);
@@ -104,57 +139,31 @@ static void crypto_pump_requests(struct crypto_engine *engine,
}
}
- switch (rtype) {
- case CRYPTO_ALG_TYPE_AHASH:
- hreq = ahash_request_cast(engine->cur_req);
- if (engine->prepare_hash_request) {
- ret = engine->prepare_hash_request(engine, hreq);
- if (ret) {
- dev_err(engine->dev, "failed to prepare request: %d\n",
- ret);
- goto req_err;
- }
- engine->cur_req_prepared = true;
- }
- ret = engine->hash_one_request(engine, hreq);
- if (ret) {
- dev_err(engine->dev, "failed to hash one request from queue\n");
- goto req_err;
- }
- return;
- case CRYPTO_ALG_TYPE_ABLKCIPHER:
- breq = ablkcipher_request_cast(engine->cur_req);
- if (engine->prepare_cipher_request) {
- ret = engine->prepare_cipher_request(engine, breq);
- if (ret) {
- dev_err(engine->dev, "failed to prepare request: %d\n",
- ret);
- goto req_err;
- }
- engine->cur_req_prepared = true;
- }
- ret = engine->cipher_one_request(engine, breq);
+ enginectx = crypto_tfm_ctx(async_req->tfm);
+
+ if (enginectx->op.prepare_request) {
+ ret = enginectx->op.prepare_request(engine, async_req);
if (ret) {
- dev_err(engine->dev, "failed to cipher one request from queue\n");
+ dev_err(engine->dev, "failed to prepare request: %d\n",
+ ret);
goto req_err;
}
- return;
- default:
- dev_err(engine->dev, "failed to prepare request of unknown type\n");
- return;
+ engine->cur_req_prepared = true;
+ }
+ if (!enginectx->op.do_one_request) {
+ dev_err(engine->dev, "failed to do request\n");
+ ret = -EINVAL;
+ goto req_err;
}
+ ret = enginectx->op.do_one_request(engine, async_req);
+ if (ret) {
+ dev_err(engine->dev, "Failed to do one request from queue: %d\n", ret);
+ goto req_err;
+ }
+ return;
req_err:
- switch (rtype) {
- case CRYPTO_ALG_TYPE_AHASH:
- hreq = ahash_request_cast(engine->cur_req);
- crypto_finalize_hash_request(engine, hreq, ret);
- break;
- case CRYPTO_ALG_TYPE_ABLKCIPHER:
- breq = ablkcipher_request_cast(engine->cur_req);
- crypto_finalize_cipher_request(engine, breq, ret);
- break;
- }
+ crypto_finalize_request(engine, async_req, ret);
return;
out:
@@ -170,13 +179,12 @@ static void crypto_pump_work(struct kthread_work *work)
}
/**
- * crypto_transfer_cipher_request - transfer the new request into the
- * enginequeue
+ * crypto_transfer_request - transfer the new request into the engine queue
* @engine: the hardware engine
* @req: the request need to be listed into the engine queue
*/
-int crypto_transfer_cipher_request(struct crypto_engine *engine,
- struct ablkcipher_request *req,
+static int crypto_transfer_request(struct crypto_engine *engine,
+ struct crypto_async_request *req,
bool need_pump)
{
unsigned long flags;
@@ -189,7 +197,7 @@ int crypto_transfer_cipher_request(struct crypto_engine *engine,
return -ESHUTDOWN;
}
- ret = ablkcipher_enqueue_request(&engine->queue, req);
+ ret = crypto_enqueue_request(&engine->queue, req);
if (!engine->busy && need_pump)
kthread_queue_work(engine->kworker, &engine->pump_requests);
@@ -197,102 +205,131 @@ int crypto_transfer_cipher_request(struct crypto_engine *engine,
spin_unlock_irqrestore(&engine->queue_lock, flags);
return ret;
}
-EXPORT_SYMBOL_GPL(crypto_transfer_cipher_request);
/**
- * crypto_transfer_cipher_request_to_engine - transfer one request to list
+ * crypto_transfer_request_to_engine - transfer one request to list
* into the engine queue
* @engine: the hardware engine
* @req: the request need to be listed into the engine queue
*/
-int crypto_transfer_cipher_request_to_engine(struct crypto_engine *engine,
- struct ablkcipher_request *req)
+static int crypto_transfer_request_to_engine(struct crypto_engine *engine,
+ struct crypto_async_request *req)
{
- return crypto_transfer_cipher_request(engine, req, true);
+ return crypto_transfer_request(engine, req, true);
}
-EXPORT_SYMBOL_GPL(crypto_transfer_cipher_request_to_engine);
/**
- * crypto_transfer_hash_request - transfer the new request into the
- * enginequeue
+ * crypto_transfer_ablkcipher_request_to_engine - transfer one ablkcipher_request
+ * to list into the engine queue
* @engine: the hardware engine
* @req: the request need to be listed into the engine queue
+ * TODO: Remove this function when skcipher conversion is finished
*/
-int crypto_transfer_hash_request(struct crypto_engine *engine,
- struct ahash_request *req, bool need_pump)
+int crypto_transfer_ablkcipher_request_to_engine(struct crypto_engine *engine,
+ struct ablkcipher_request *req)
{
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&engine->queue_lock, flags);
-
- if (!engine->running) {
- spin_unlock_irqrestore(&engine->queue_lock, flags);
- return -ESHUTDOWN;
- }
-
- ret = ahash_enqueue_request(&engine->queue, req);
+ return crypto_transfer_request_to_engine(engine, &req->base);
+}
+EXPORT_SYMBOL_GPL(crypto_transfer_ablkcipher_request_to_engine);
- if (!engine->busy && need_pump)
- kthread_queue_work(engine->kworker, &engine->pump_requests);
+/**
+ * crypto_transfer_aead_request_to_engine - transfer one aead_request
+ * to list into the engine queue
+ * @engine: the hardware engine
+ * @req: the request need to be listed into the engine queue
+ */
+int crypto_transfer_aead_request_to_engine(struct crypto_engine *engine,
+ struct aead_request *req)
+{
+ return crypto_transfer_request_to_engine(engine, &req->base);
+}
+EXPORT_SYMBOL_GPL(crypto_transfer_aead_request_to_engine);
- spin_unlock_irqrestore(&engine->queue_lock, flags);
- return ret;
+/**
+ * crypto_transfer_akcipher_request_to_engine - transfer one akcipher_request
+ * to list into the engine queue
+ * @engine: the hardware engine
+ * @req: the request need to be listed into the engine queue
+ */
+int crypto_transfer_akcipher_request_to_engine(struct crypto_engine *engine,
+ struct akcipher_request *req)
+{
+ return crypto_transfer_request_to_engine(engine, &req->base);
}
-EXPORT_SYMBOL_GPL(crypto_transfer_hash_request);
+EXPORT_SYMBOL_GPL(crypto_transfer_akcipher_request_to_engine);
/**
- * crypto_transfer_hash_request_to_engine - transfer one request to list
- * into the engine queue
+ * crypto_transfer_hash_request_to_engine - transfer one ahash_request
+ * to list into the engine queue
* @engine: the hardware engine
* @req: the request need to be listed into the engine queue
*/
int crypto_transfer_hash_request_to_engine(struct crypto_engine *engine,
struct ahash_request *req)
{
- return crypto_transfer_hash_request(engine, req, true);
+ return crypto_transfer_request_to_engine(engine, &req->base);
}
EXPORT_SYMBOL_GPL(crypto_transfer_hash_request_to_engine);
/**
- * crypto_finalize_cipher_request - finalize one request if the request is done
+ * crypto_transfer_skcipher_request_to_engine - transfer one skcipher_request
+ * to list into the engine queue
+ * @engine: the hardware engine
+ * @req: the request need to be listed into the engine queue
+ */
+int crypto_transfer_skcipher_request_to_engine(struct crypto_engine *engine,
+ struct skcipher_request *req)
+{
+ return crypto_transfer_request_to_engine(engine, &req->base);
+}
+EXPORT_SYMBOL_GPL(crypto_transfer_skcipher_request_to_engine);
+
+/**
+ * crypto_finalize_ablkcipher_request - finalize one ablkcipher_request if
+ * the request is done
* @engine: the hardware engine
* @req: the request need to be finalized
* @err: error number
+ * TODO: Remove this function when skcipher conversion is finished
*/
-void crypto_finalize_cipher_request(struct crypto_engine *engine,
- struct ablkcipher_request *req, int err)
+void crypto_finalize_ablkcipher_request(struct crypto_engine *engine,
+ struct ablkcipher_request *req, int err)
{
- unsigned long flags;
- bool finalize_cur_req = false;
- int ret;
-
- spin_lock_irqsave(&engine->queue_lock, flags);
- if (engine->cur_req == &req->base)
- finalize_cur_req = true;
- spin_unlock_irqrestore(&engine->queue_lock, flags);
-
- if (finalize_cur_req) {
- if (engine->cur_req_prepared &&
- engine->unprepare_cipher_request) {
- ret = engine->unprepare_cipher_request(engine, req);
- if (ret)
- dev_err(engine->dev, "failed to unprepare request\n");
- }
- spin_lock_irqsave(&engine->queue_lock, flags);
- engine->cur_req = NULL;
- engine->cur_req_prepared = false;
- spin_unlock_irqrestore(&engine->queue_lock, flags);
- }
+ return crypto_finalize_request(engine, &req->base, err);
+}
+EXPORT_SYMBOL_GPL(crypto_finalize_ablkcipher_request);
- req->base.complete(&req->base, err);
+/**
+ * crypto_finalize_aead_request - finalize one aead_request if
+ * the request is done
+ * @engine: the hardware engine
+ * @req: the request need to be finalized
+ * @err: error number
+ */
+void crypto_finalize_aead_request(struct crypto_engine *engine,
+ struct aead_request *req, int err)
+{
+ return crypto_finalize_request(engine, &req->base, err);
+}
+EXPORT_SYMBOL_GPL(crypto_finalize_aead_request);
- kthread_queue_work(engine->kworker, &engine->pump_requests);
+/**
+ * crypto_finalize_akcipher_request - finalize one akcipher_request if
+ * the request is done
+ * @engine: the hardware engine
+ * @req: the request need to be finalized
+ * @err: error number
+ */
+void crypto_finalize_akcipher_request(struct crypto_engine *engine,
+ struct akcipher_request *req, int err)
+{
+ return crypto_finalize_request(engine, &req->base, err);
}
-EXPORT_SYMBOL_GPL(crypto_finalize_cipher_request);
+EXPORT_SYMBOL_GPL(crypto_finalize_akcipher_request);
/**
- * crypto_finalize_hash_request - finalize one request if the request is done
+ * crypto_finalize_hash_request - finalize one ahash_request if
+ * the request is done
* @engine: the hardware engine
* @req: the request need to be finalized
* @err: error number
@@ -300,35 +337,25 @@ EXPORT_SYMBOL_GPL(crypto_finalize_cipher_request);
void crypto_finalize_hash_request(struct crypto_engine *engine,
struct ahash_request *req, int err)
{
- unsigned long flags;
- bool finalize_cur_req = false;
- int ret;
-
- spin_lock_irqsave(&engine->queue_lock, flags);
- if (engine->cur_req == &req->base)
- finalize_cur_req = true;
- spin_unlock_irqrestore(&engine->queue_lock, flags);
-
- if (finalize_cur_req) {
- if (engine->cur_req_prepared &&
- engine->unprepare_hash_request) {
- ret = engine->unprepare_hash_request(engine, req);
- if (ret)
- dev_err(engine->dev, "failed to unprepare request\n");
- }
- spin_lock_irqsave(&engine->queue_lock, flags);
- engine->cur_req = NULL;
- engine->cur_req_prepared = false;
- spin_unlock_irqrestore(&engine->queue_lock, flags);
- }
-
- req->base.complete(&req->base, err);
-
- kthread_queue_work(engine->kworker, &engine->pump_requests);
+ return crypto_finalize_request(engine, &req->base, err);
}
EXPORT_SYMBOL_GPL(crypto_finalize_hash_request);
/**
+ * crypto_finalize_skcipher_request - finalize one skcipher_request if
+ * the request is done
+ * @engine: the hardware engine
+ * @req: the request need to be finalized
+ * @err: error number
+ */
+void crypto_finalize_skcipher_request(struct crypto_engine *engine,
+ struct skcipher_request *req, int err)
+{
+ return crypto_finalize_request(engine, &req->base, err);
+}
+EXPORT_SYMBOL_GPL(crypto_finalize_skcipher_request);
+
+/**
* crypto_engine_start - start the hardware engine
* @engine: the hardware engine need to be started
*
diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c
index 5c291eedaa70..0e89b5457cab 100644
--- a/crypto/crypto_user.c
+++ b/crypto/crypto_user.c
@@ -271,7 +271,7 @@ static int crypto_report(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
return -ENOENT;
err = -ENOMEM;
- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+ skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!skb)
goto drop_alg;
diff --git a/crypto/ecc.c b/crypto/ecc.c
index 18f32f2a5e1c..9c066b5ac12d 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -1025,9 +1025,7 @@ int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
{
int ret = 0;
struct ecc_point *product, *pk;
- u64 priv[ndigits];
- u64 rand_z[ndigits];
- unsigned int nbytes;
+ u64 *priv, *rand_z;
const struct ecc_curve *curve = ecc_get_curve(curve_id);
if (!private_key || !public_key || !curve) {
@@ -1035,14 +1033,22 @@ int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
goto out;
}
- nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+ priv = kmalloc_array(ndigits, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto out;
+ }
- get_random_bytes(rand_z, nbytes);
+ rand_z = kmalloc_array(ndigits, sizeof(*rand_z), GFP_KERNEL);
+ if (!rand_z) {
+ ret = -ENOMEM;
+ goto kfree_out;
+ }
pk = ecc_alloc_point(ndigits);
if (!pk) {
ret = -ENOMEM;
- goto out;
+ goto kfree_out;
}
product = ecc_alloc_point(ndigits);
@@ -1051,6 +1057,8 @@ int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
goto err_alloc_product;
}
+ get_random_bytes(rand_z, ndigits << ECC_DIGITS_TO_BYTES_SHIFT);
+
ecc_swap_digits(public_key, pk->x, ndigits);
ecc_swap_digits(&public_key[ndigits], pk->y, ndigits);
ecc_swap_digits(private_key, priv, ndigits);
@@ -1065,6 +1073,9 @@ int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
ecc_free_point(product);
err_alloc_product:
ecc_free_point(pk);
+kfree_out:
+ kzfree(priv);
+ kzfree(rand_z);
out:
return ret;
}
diff --git a/crypto/ecdh.c b/crypto/ecdh.c
index 3aca0933ec44..d2ec33f0e098 100644
--- a/crypto/ecdh.c
+++ b/crypto/ecdh.c
@@ -89,12 +89,19 @@ static int ecdh_compute_value(struct kpp_request *req)
if (!shared_secret)
goto free_pubkey;
- copied = sg_copy_to_buffer(req->src, 1, public_key,
- public_key_sz);
- if (copied != public_key_sz) {
- ret = -EINVAL;
+ /* from here on it's invalid parameters */
+ ret = -EINVAL;
+
+ /* must have exactly two points to be on the curve */
+ if (public_key_sz != req->src_len)
+ goto free_all;
+
+ copied = sg_copy_to_buffer(req->src,
+ sg_nents_for_len(req->src,
+ public_key_sz),
+ public_key, public_key_sz);
+ if (copied != public_key_sz)
goto free_all;
- }
ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits,
ctx->private_key, public_key,
@@ -111,7 +118,11 @@ static int ecdh_compute_value(struct kpp_request *req)
if (ret < 0)
goto free_all;
- copied = sg_copy_from_buffer(req->dst, 1, buf, nbytes);
+ /* might want less than we've got */
+ nbytes = min_t(size_t, nbytes, req->dst_len);
+ copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,
+ nbytes),
+ buf, nbytes);
if (copied != nbytes)
ret = -EINVAL;
diff --git a/crypto/internal.h b/crypto/internal.h
index 5ac27fba10e8..9a3f39939fba 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -67,7 +67,6 @@ static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg)
}
struct crypto_alg *crypto_mod_get(struct crypto_alg *alg);
-struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, u32 mask);
struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask);
int crypto_init_cipher_ops(struct crypto_tfm *tfm);
diff --git a/crypto/lrw.c b/crypto/lrw.c
index cbbd7c50ad19..954a7064a179 100644
--- a/crypto/lrw.c
+++ b/crypto/lrw.c
@@ -28,13 +28,31 @@
#include <crypto/b128ops.h>
#include <crypto/gf128mul.h>
-#include <crypto/lrw.h>
#define LRW_BUFFER_SIZE 128u
+#define LRW_BLOCK_SIZE 16
+
struct priv {
struct crypto_skcipher *child;
- struct lrw_table_ctx table;
+
+ /*
+ * optimizes multiplying a random (non incrementing, as at the
+ * start of a new sector) value with key2, we could also have
+ * used 4k optimization tables or no optimization at all. In the
+ * latter case we would have to store key2 here
+ */
+ struct gf128mul_64k *table;
+
+ /*
+ * stores:
+ * key2*{ 0,0,...0,0,0,0,1 }, key2*{ 0,0,...0,0,0,1,1 },
+ * key2*{ 0,0,...0,0,1,1,1 }, key2*{ 0,0,...0,1,1,1,1 }
+ * key2*{ 0,0,...1,1,1,1,1 }, etc
+ * needed for optimized multiplication of incrementing values
+ * with key2
+ */
+ be128 mulinc[128];
};
struct rctx {
@@ -65,11 +83,25 @@ static inline void setbit128_bbe(void *b, int bit)
), b);
}
-int lrw_init_table(struct lrw_table_ctx *ctx, const u8 *tweak)
+static int setkey(struct crypto_skcipher *parent, const u8 *key,
+ unsigned int keylen)
{
+ struct priv *ctx = crypto_skcipher_ctx(parent);
+ struct crypto_skcipher *child = ctx->child;
+ int err, bsize = LRW_BLOCK_SIZE;
+ const u8 *tweak = key + keylen - bsize;
be128 tmp = { 0 };
int i;
+ crypto_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+ crypto_skcipher_set_flags(child, crypto_skcipher_get_flags(parent) &
+ CRYPTO_TFM_REQ_MASK);
+ err = crypto_skcipher_setkey(child, key, keylen - bsize);
+ crypto_skcipher_set_flags(parent, crypto_skcipher_get_flags(child) &
+ CRYPTO_TFM_RES_MASK);
+ if (err)
+ return err;
+
if (ctx->table)
gf128mul_free_64k(ctx->table);
@@ -87,34 +119,6 @@ int lrw_init_table(struct lrw_table_ctx *ctx, const u8 *tweak)
return 0;
}
-EXPORT_SYMBOL_GPL(lrw_init_table);
-
-void lrw_free_table(struct lrw_table_ctx *ctx)
-{
- if (ctx->table)
- gf128mul_free_64k(ctx->table);
-}
-EXPORT_SYMBOL_GPL(lrw_free_table);
-
-static int setkey(struct crypto_skcipher *parent, const u8 *key,
- unsigned int keylen)
-{
- struct priv *ctx = crypto_skcipher_ctx(parent);
- struct crypto_skcipher *child = ctx->child;
- int err, bsize = LRW_BLOCK_SIZE;
- const u8 *tweak = key + keylen - bsize;
-
- crypto_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
- crypto_skcipher_set_flags(child, crypto_skcipher_get_flags(parent) &
- CRYPTO_TFM_REQ_MASK);
- err = crypto_skcipher_setkey(child, key, keylen - bsize);
- crypto_skcipher_set_flags(parent, crypto_skcipher_get_flags(child) &
- CRYPTO_TFM_RES_MASK);
- if (err)
- return err;
-
- return lrw_init_table(&ctx->table, tweak);
-}
static inline void inc(be128 *iv)
{
@@ -238,7 +242,7 @@ static int pre_crypt(struct skcipher_request *req)
/* T <- I*Key2, using the optimization
* discussed in the specification */
be128_xor(&rctx->t, &rctx->t,
- &ctx->table.mulinc[get_index128(iv)]);
+ &ctx->mulinc[get_index128(iv)]);
inc(iv);
} while ((avail -= bs) >= bs);
@@ -301,7 +305,7 @@ static int init_crypt(struct skcipher_request *req, crypto_completion_t done)
memcpy(&rctx->t, req->iv, sizeof(rctx->t));
/* T <- I*Key2 */
- gf128mul_64k_bbe(&rctx->t, ctx->table.table);
+ gf128mul_64k_bbe(&rctx->t, ctx->table);
return 0;
}
@@ -313,7 +317,7 @@ static void exit_crypt(struct skcipher_request *req)
rctx->left = 0;
if (rctx->ext)
- kfree(rctx->ext);
+ kzfree(rctx->ext);
}
static int do_encrypt(struct skcipher_request *req, int err)
@@ -416,85 +420,6 @@ static int decrypt(struct skcipher_request *req)
return do_decrypt(req, init_crypt(req, decrypt_done));
}
-int lrw_crypt(struct blkcipher_desc *desc, struct scatterlist *sdst,
- struct scatterlist *ssrc, unsigned int nbytes,
- struct lrw_crypt_req *req)
-{
- const unsigned int bsize = LRW_BLOCK_SIZE;
- const unsigned int max_blks = req->tbuflen / bsize;
- struct lrw_table_ctx *ctx = req->table_ctx;
- struct blkcipher_walk walk;
- unsigned int nblocks;
- be128 *iv, *src, *dst, *t;
- be128 *t_buf = req->tbuf;
- int err, i;
-
- BUG_ON(max_blks < 1);
-
- blkcipher_walk_init(&walk, sdst, ssrc, nbytes);
-
- err = blkcipher_walk_virt(desc, &walk);
- nbytes = walk.nbytes;
- if (!nbytes)
- return err;
-
- nblocks = min(walk.nbytes / bsize, max_blks);
- src = (be128 *)walk.src.virt.addr;
- dst = (be128 *)walk.dst.virt.addr;
-
- /* calculate first value of T */
- iv = (be128 *)walk.iv;
- t_buf[0] = *iv;
-
- /* T <- I*Key2 */
- gf128mul_64k_bbe(&t_buf[0], ctx->table);
-
- i = 0;
- goto first;
-
- for (;;) {
- do {
- for (i = 0; i < nblocks; i++) {
- /* T <- I*Key2, using the optimization
- * discussed in the specification */
- be128_xor(&t_buf[i], t,
- &ctx->mulinc[get_index128(iv)]);
- inc(iv);
-first:
- t = &t_buf[i];
-
- /* PP <- T xor P */
- be128_xor(dst + i, t, src + i);
- }
-
- /* CC <- E(Key2,PP) */
- req->crypt_fn(req->crypt_ctx, (u8 *)dst,
- nblocks * bsize);
-
- /* C <- T xor CC */
- for (i = 0; i < nblocks; i++)
- be128_xor(dst + i, dst + i, &t_buf[i]);
-
- src += nblocks;
- dst += nblocks;
- nbytes -= nblocks * bsize;
- nblocks = min(nbytes / bsize, max_blks);
- } while (nblocks > 0);
-
- err = blkcipher_walk_done(desc, &walk, nbytes);
- nbytes = walk.nbytes;
- if (!nbytes)
- break;
-
- nblocks = min(nbytes / bsize, max_blks);
- src = (be128 *)walk.src.virt.addr;
- dst = (be128 *)walk.dst.virt.addr;
- }
-
- return err;
-}
-EXPORT_SYMBOL_GPL(lrw_crypt);
-
static int init_tfm(struct crypto_skcipher *tfm)
{
struct skcipher_instance *inst = skcipher_alg_instance(tfm);
@@ -518,7 +443,8 @@ static void exit_tfm(struct crypto_skcipher *tfm)
{
struct priv *ctx = crypto_skcipher_ctx(tfm);
- lrw_free_table(&ctx->table);
+ if (ctx->table)
+ gf128mul_free_64k(ctx->table);
crypto_free_skcipher(ctx->child);
}
diff --git a/crypto/mcryptd.c b/crypto/mcryptd.c
index fe5129d6ff4e..f14152147ce8 100644
--- a/crypto/mcryptd.c
+++ b/crypto/mcryptd.c
@@ -367,7 +367,7 @@ static void mcryptd_hash_update(struct crypto_async_request *req_async, int err)
goto out;
rctx->out = req->result;
- err = ahash_mcryptd_update(&rctx->areq);
+ err = crypto_ahash_update(&rctx->areq);
if (err) {
req->base.complete = rctx->complete;
goto out;
@@ -394,7 +394,7 @@ static void mcryptd_hash_final(struct crypto_async_request *req_async, int err)
goto out;
rctx->out = req->result;
- err = ahash_mcryptd_final(&rctx->areq);
+ err = crypto_ahash_final(&rctx->areq);
if (err) {
req->base.complete = rctx->complete;
goto out;
@@ -420,7 +420,7 @@ static void mcryptd_hash_finup(struct crypto_async_request *req_async, int err)
if (unlikely(err == -EINPROGRESS))
goto out;
rctx->out = req->result;
- err = ahash_mcryptd_finup(&rctx->areq);
+ err = crypto_ahash_finup(&rctx->areq);
if (err) {
req->base.complete = rctx->complete;
@@ -455,7 +455,7 @@ static void mcryptd_hash_digest(struct crypto_async_request *req_async, int err)
rctx->complete, req_async);
rctx->out = req->result;
- err = ahash_mcryptd_digest(desc);
+ err = crypto_ahash_init(desc) ?: crypto_ahash_finup(desc);
out:
local_bh_disable();
@@ -612,32 +612,6 @@ struct mcryptd_ahash *mcryptd_alloc_ahash(const char *alg_name,
}
EXPORT_SYMBOL_GPL(mcryptd_alloc_ahash);
-int ahash_mcryptd_digest(struct ahash_request *desc)
-{
- return crypto_ahash_init(desc) ?: ahash_mcryptd_finup(desc);
-}
-
-int ahash_mcryptd_update(struct ahash_request *desc)
-{
- /* alignment is to be done by multi-buffer crypto algorithm if needed */
-
- return crypto_ahash_update(desc);
-}
-
-int ahash_mcryptd_finup(struct ahash_request *desc)
-{
- /* alignment is to be done by multi-buffer crypto algorithm if needed */
-
- return crypto_ahash_finup(desc);
-}
-
-int ahash_mcryptd_final(struct ahash_request *desc)
-{
- /* alignment is to be done by multi-buffer crypto algorithm if needed */
-
- return crypto_ahash_final(desc);
-}
-
struct crypto_ahash *mcryptd_ahash_child(struct mcryptd_ahash *tfm)
{
struct mcryptd_hash_ctx *ctx = crypto_ahash_ctx(&tfm->base);
diff --git a/crypto/md4.c b/crypto/md4.c
index 3515af425cc9..810fefb0a007 100644
--- a/crypto/md4.c
+++ b/crypto/md4.c
@@ -64,23 +64,6 @@ static inline u32 H(u32 x, u32 y, u32 z)
#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (u32)0x5A827999,s))
#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (u32)0x6ED9EBA1,s))
-/* XXX: this stuff can be optimized */
-static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
-{
- while (words--) {
- __le32_to_cpus(buf);
- buf++;
- }
-}
-
-static inline void cpu_to_le32_array(u32 *buf, unsigned int words)
-{
- while (words--) {
- __cpu_to_le32s(buf);
- buf++;
- }
-}
-
static void md4_transform(u32 *hash, u32 const *in)
{
u32 a, b, c, d;
diff --git a/crypto/md5.c b/crypto/md5.c
index f7ae1a48225b..f776ef43d621 100644
--- a/crypto/md5.c
+++ b/crypto/md5.c
@@ -32,23 +32,6 @@ const u8 md5_zero_message_hash[MD5_DIGEST_SIZE] = {
};
EXPORT_SYMBOL_GPL(md5_zero_message_hash);
-/* XXX: this stuff can be optimized */
-static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
-{
- while (words--) {
- __le32_to_cpus(buf);
- buf++;
- }
-}
-
-static inline void cpu_to_le32_array(u32 *buf, unsigned int words)
-{
- while (words--) {
- __cpu_to_le32s(buf);
- buf++;
- }
-}
-
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c
index 2908f93c3e55..9893dbfc1af4 100644
--- a/crypto/rsa-pkcs1pad.c
+++ b/crypto/rsa-pkcs1pad.c
@@ -192,7 +192,7 @@ static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int err)
if (likely(!pad_len))
goto out;
- out_buf = kzalloc(ctx->key_size, GFP_ATOMIC);
+ out_buf = kzalloc(ctx->key_size, GFP_KERNEL);
err = -ENOMEM;
if (!out_buf)
goto out;
diff --git a/crypto/simd.c b/crypto/simd.c
index 208226d7f908..ea7240be3001 100644
--- a/crypto/simd.c
+++ b/crypto/simd.c
@@ -221,4 +221,54 @@ void simd_skcipher_free(struct simd_skcipher_alg *salg)
}
EXPORT_SYMBOL_GPL(simd_skcipher_free);
+int simd_register_skciphers_compat(struct skcipher_alg *algs, int count,
+ struct simd_skcipher_alg **simd_algs)
+{
+ int err;
+ int i;
+ const char *algname;
+ const char *drvname;
+ const char *basename;
+ struct simd_skcipher_alg *simd;
+
+ err = crypto_register_skciphers(algs, count);
+ if (err)
+ return err;
+
+ for (i = 0; i < count; i++) {
+ WARN_ON(strncmp(algs[i].base.cra_name, "__", 2));
+ WARN_ON(strncmp(algs[i].base.cra_driver_name, "__", 2));
+ algname = algs[i].base.cra_name + 2;
+ drvname = algs[i].base.cra_driver_name + 2;
+ basename = algs[i].base.cra_driver_name;
+ simd = simd_skcipher_create_compat(algname, drvname, basename);
+ err = PTR_ERR(simd);
+ if (IS_ERR(simd))
+ goto err_unregister;
+ simd_algs[i] = simd;
+ }
+ return 0;
+
+err_unregister:
+ simd_unregister_skciphers(algs, count, simd_algs);
+ return err;
+}
+EXPORT_SYMBOL_GPL(simd_register_skciphers_compat);
+
+void simd_unregister_skciphers(struct skcipher_alg *algs, int count,
+ struct simd_skcipher_alg **simd_algs)
+{
+ int i;
+
+ crypto_unregister_skciphers(algs, count);
+
+ for (i = 0; i < count; i++) {
+ if (simd_algs[i]) {
+ simd_skcipher_free(simd_algs[i]);
+ simd_algs[i] = NULL;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(simd_unregister_skciphers);
+
MODULE_LICENSE("GPL");
diff --git a/crypto/sm4_generic.c b/crypto/sm4_generic.c
new file mode 100644
index 000000000000..f537a2766c55
--- /dev/null
+++ b/crypto/sm4_generic.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * SM4 Cipher Algorithm.
+ *
+ * Copyright (C) 2018 ARM Limited or its affiliates.
+ * All rights reserved.
+ */
+
+#include <crypto/sm4.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/crypto.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+
+static const u32 fk[4] = {
+ 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc
+};
+
+static const u8 sbox[256] = {
+ 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7,
+ 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
+ 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3,
+ 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
+ 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a,
+ 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
+ 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95,
+ 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
+ 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba,
+ 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
+ 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b,
+ 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
+ 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2,
+ 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
+ 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52,
+ 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
+ 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5,
+ 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
+ 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55,
+ 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
+ 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60,
+ 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
+ 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f,
+ 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
+ 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f,
+ 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
+ 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd,
+ 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
+ 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e,
+ 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
+ 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20,
+ 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
+};
+
+static const u32 ck[] = {
+ 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
+ 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
+ 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
+ 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
+ 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
+ 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
+ 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
+ 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
+};
+
+static u32 sm4_t_non_lin_sub(u32 x)
+{
+ int i;
+ u8 *b = (u8 *)&x;
+
+ for (i = 0; i < 4; ++i)
+ b[i] = sbox[b[i]];
+
+ return x;
+}
+
+static u32 sm4_key_lin_sub(u32 x)
+{
+ return x ^ rol32(x, 13) ^ rol32(x, 23);
+
+}
+
+static u32 sm4_enc_lin_sub(u32 x)
+{
+ return x ^ rol32(x, 2) ^ rol32(x, 10) ^ rol32(x, 18) ^ rol32(x, 24);
+}
+
+static u32 sm4_key_sub(u32 x)
+{
+ return sm4_key_lin_sub(sm4_t_non_lin_sub(x));
+}
+
+static u32 sm4_enc_sub(u32 x)
+{
+ return sm4_enc_lin_sub(sm4_t_non_lin_sub(x));
+}
+
+static u32 sm4_round(const u32 *x, const u32 rk)
+{
+ return x[0] ^ sm4_enc_sub(x[1] ^ x[2] ^ x[3] ^ rk);
+}
+
+
+/**
+ * crypto_sm4_expand_key - Expands the SM4 key as described in GB/T 32907-2016
+ * @ctx: The location where the computed key will be stored.
+ * @in_key: The supplied key.
+ * @key_len: The length of the supplied key.
+ *
+ * Returns 0 on success. The function fails only if an invalid key size (or
+ * pointer) is supplied.
+ */
+int crypto_sm4_expand_key(struct crypto_sm4_ctx *ctx, const u8 *in_key,
+ unsigned int key_len)
+{
+ u32 rk[4], t;
+ const u32 *key = (u32 *)in_key;
+ int i;
+
+ if (key_len != SM4_KEY_SIZE)
+ return -EINVAL;
+
+ for (i = 0; i < 4; ++i)
+ rk[i] = get_unaligned_be32(&key[i]) ^ fk[i];
+
+ for (i = 0; i < 32; ++i) {
+ t = rk[0] ^ sm4_key_sub(rk[1] ^ rk[2] ^ rk[3] ^ ck[i]);
+ ctx->rkey_enc[i] = t;
+ rk[0] = rk[1];
+ rk[1] = rk[2];
+ rk[2] = rk[3];
+ rk[3] = t;
+ }
+
+ for (i = 0; i < 32; ++i)
+ ctx->rkey_dec[i] = ctx->rkey_enc[31 - i];
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_sm4_expand_key);
+
+/**
+ * crypto_sm4_set_key - Set the AES key.
+ * @tfm: The %crypto_tfm that is used in the context.
+ * @in_key: The input key.
+ * @key_len: The size of the key.
+ *
+ * Returns 0 on success, on failure the %CRYPTO_TFM_RES_BAD_KEY_LEN flag in tfm
+ * is set. The function uses crypto_sm4_expand_key() to expand the key.
+ * &crypto_sm4_ctx _must_ be the private data embedded in @tfm which is
+ * retrieved with crypto_tfm_ctx().
+ */
+int crypto_sm4_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+ unsigned int key_len)
+{
+ struct crypto_sm4_ctx *ctx = crypto_tfm_ctx(tfm);
+ u32 *flags = &tfm->crt_flags;
+ int ret;
+
+ ret = crypto_sm4_expand_key(ctx, in_key, key_len);
+ if (!ret)
+ return 0;
+
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(crypto_sm4_set_key);
+
+static void sm4_do_crypt(const u32 *rk, u32 *out, const u32 *in)
+{
+ u32 x[4], i, t;
+
+ for (i = 0; i < 4; ++i)
+ x[i] = get_unaligned_be32(&in[i]);
+
+ for (i = 0; i < 32; ++i) {
+ t = sm4_round(x, rk[i]);
+ x[0] = x[1];
+ x[1] = x[2];
+ x[2] = x[3];
+ x[3] = t;
+ }
+
+ for (i = 0; i < 4; ++i)
+ put_unaligned_be32(x[3 - i], &out[i]);
+}
+
+/* encrypt a block of text */
+
+static void sm4_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ const struct crypto_sm4_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ sm4_do_crypt(ctx->rkey_enc, (u32 *)out, (u32 *)in);
+}
+
+/* decrypt a block of text */
+
+static void sm4_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ const struct crypto_sm4_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ sm4_do_crypt(ctx->rkey_dec, (u32 *)out, (u32 *)in);
+}
+
+static struct crypto_alg sm4_alg = {
+ .cra_name = "sm4",
+ .cra_driver_name = "sm4-generic",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = SM4_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypto_sm4_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = SM4_KEY_SIZE,
+ .cia_max_keysize = SM4_KEY_SIZE,
+ .cia_setkey = crypto_sm4_set_key,
+ .cia_encrypt = sm4_encrypt,
+ .cia_decrypt = sm4_decrypt
+ }
+ }
+};
+
+static int __init sm4_init(void)
+{
+ return crypto_register_alg(&sm4_alg);
+}
+
+static void __exit sm4_fini(void)
+{
+ crypto_unregister_alg(&sm4_alg);
+}
+
+module_init(sm4_init);
+module_exit(sm4_fini);
+
+MODULE_DESCRIPTION("SM4 Cipher Algorithm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_CRYPTO("sm4");
+MODULE_ALIAS_CRYPTO("sm4-generic");
diff --git a/crypto/speck.c b/crypto/speck.c
new file mode 100644
index 000000000000..58aa9f7f91f7
--- /dev/null
+++ b/crypto/speck.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Speck: a lightweight block cipher
+ *
+ * Copyright (c) 2018 Google, Inc
+ *
+ * Speck has 10 variants, including 5 block sizes. For now we only implement
+ * the variants Speck128/128, Speck128/192, Speck128/256, Speck64/96, and
+ * Speck64/128. Speck${B}/${K} denotes the variant with a block size of B bits
+ * and a key size of K bits. The Speck128 variants are believed to be the most
+ * secure variants, and they use the same block size and key sizes as AES. The
+ * Speck64 variants are less secure, but on 32-bit processors are usually
+ * faster. The remaining variants (Speck32, Speck48, and Speck96) are even less
+ * secure and/or not as well suited for implementation on either 32-bit or
+ * 64-bit processors, so are omitted.
+ *
+ * Reference: "The Simon and Speck Families of Lightweight Block Ciphers"
+ * https://eprint.iacr.org/2013/404.pdf
+ *
+ * In a correspondence, the Speck designers have also clarified that the words
+ * should be interpreted in little-endian format, and the words should be
+ * ordered such that the first word of each block is 'y' rather than 'x', and
+ * the first key word (rather than the last) becomes the first round key.
+ */
+
+#include <asm/unaligned.h>
+#include <crypto/speck.h>
+#include <linux/bitops.h>
+#include <linux/crypto.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+/* Speck128 */
+
+static __always_inline void speck128_round(u64 *x, u64 *y, u64 k)
+{
+ *x = ror64(*x, 8);
+ *x += *y;
+ *x ^= k;
+ *y = rol64(*y, 3);
+ *y ^= *x;
+}
+
+static __always_inline void speck128_unround(u64 *x, u64 *y, u64 k)
+{
+ *y ^= *x;
+ *y = ror64(*y, 3);
+ *x ^= k;
+ *x -= *y;
+ *x = rol64(*x, 8);
+}
+
+void crypto_speck128_encrypt(const struct speck128_tfm_ctx *ctx,
+ u8 *out, const u8 *in)
+{
+ u64 y = get_unaligned_le64(in);
+ u64 x = get_unaligned_le64(in + 8);
+ int i;
+
+ for (i = 0; i < ctx->nrounds; i++)
+ speck128_round(&x, &y, ctx->round_keys[i]);
+
+ put_unaligned_le64(y, out);
+ put_unaligned_le64(x, out + 8);
+}
+EXPORT_SYMBOL_GPL(crypto_speck128_encrypt);
+
+static void speck128_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ crypto_speck128_encrypt(crypto_tfm_ctx(tfm), out, in);
+}
+
+void crypto_speck128_decrypt(const struct speck128_tfm_ctx *ctx,
+ u8 *out, const u8 *in)
+{
+ u64 y = get_unaligned_le64(in);
+ u64 x = get_unaligned_le64(in + 8);
+ int i;
+
+ for (i = ctx->nrounds - 1; i >= 0; i--)
+ speck128_unround(&x, &y, ctx->round_keys[i]);
+
+ put_unaligned_le64(y, out);
+ put_unaligned_le64(x, out + 8);
+}
+EXPORT_SYMBOL_GPL(crypto_speck128_decrypt);
+
+static void speck128_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ crypto_speck128_decrypt(crypto_tfm_ctx(tfm), out, in);
+}
+
+int crypto_speck128_setkey(struct speck128_tfm_ctx *ctx, const u8 *key,
+ unsigned int keylen)
+{
+ u64 l[3];
+ u64 k;
+ int i;
+
+ switch (keylen) {
+ case SPECK128_128_KEY_SIZE:
+ k = get_unaligned_le64(key);
+ l[0] = get_unaligned_le64(key + 8);
+ ctx->nrounds = SPECK128_128_NROUNDS;
+ for (i = 0; i < ctx->nrounds; i++) {
+ ctx->round_keys[i] = k;
+ speck128_round(&l[0], &k, i);
+ }
+ break;
+ case SPECK128_192_KEY_SIZE:
+ k = get_unaligned_le64(key);
+ l[0] = get_unaligned_le64(key + 8);
+ l[1] = get_unaligned_le64(key + 16);
+ ctx->nrounds = SPECK128_192_NROUNDS;
+ for (i = 0; i < ctx->nrounds; i++) {
+ ctx->round_keys[i] = k;
+ speck128_round(&l[i % 2], &k, i);
+ }
+ break;
+ case SPECK128_256_KEY_SIZE:
+ k = get_unaligned_le64(key);
+ l[0] = get_unaligned_le64(key + 8);
+ l[1] = get_unaligned_le64(key + 16);
+ l[2] = get_unaligned_le64(key + 24);
+ ctx->nrounds = SPECK128_256_NROUNDS;
+ for (i = 0; i < ctx->nrounds; i++) {
+ ctx->round_keys[i] = k;
+ speck128_round(&l[i % 3], &k, i);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_speck128_setkey);
+
+static int speck128_setkey(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ return crypto_speck128_setkey(crypto_tfm_ctx(tfm), key, keylen);
+}
+
+/* Speck64 */
+
+static __always_inline void speck64_round(u32 *x, u32 *y, u32 k)
+{
+ *x = ror32(*x, 8);
+ *x += *y;
+ *x ^= k;
+ *y = rol32(*y, 3);
+ *y ^= *x;
+}
+
+static __always_inline void speck64_unround(u32 *x, u32 *y, u32 k)
+{
+ *y ^= *x;
+ *y = ror32(*y, 3);
+ *x ^= k;
+ *x -= *y;
+ *x = rol32(*x, 8);
+}
+
+void crypto_speck64_encrypt(const struct speck64_tfm_ctx *ctx,
+ u8 *out, const u8 *in)
+{
+ u32 y = get_unaligned_le32(in);
+ u32 x = get_unaligned_le32(in + 4);
+ int i;
+
+ for (i = 0; i < ctx->nrounds; i++)
+ speck64_round(&x, &y, ctx->round_keys[i]);
+
+ put_unaligned_le32(y, out);
+ put_unaligned_le32(x, out + 4);
+}
+EXPORT_SYMBOL_GPL(crypto_speck64_encrypt);
+
+static void speck64_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ crypto_speck64_encrypt(crypto_tfm_ctx(tfm), out, in);
+}
+
+void crypto_speck64_decrypt(const struct speck64_tfm_ctx *ctx,
+ u8 *out, const u8 *in)
+{
+ u32 y = get_unaligned_le32(in);
+ u32 x = get_unaligned_le32(in + 4);
+ int i;
+
+ for (i = ctx->nrounds - 1; i >= 0; i--)
+ speck64_unround(&x, &y, ctx->round_keys[i]);
+
+ put_unaligned_le32(y, out);
+ put_unaligned_le32(x, out + 4);
+}
+EXPORT_SYMBOL_GPL(crypto_speck64_decrypt);
+
+static void speck64_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ crypto_speck64_decrypt(crypto_tfm_ctx(tfm), out, in);
+}
+
+int crypto_speck64_setkey(struct speck64_tfm_ctx *ctx, const u8 *key,
+ unsigned int keylen)
+{
+ u32 l[3];
+ u32 k;
+ int i;
+
+ switch (keylen) {
+ case SPECK64_96_KEY_SIZE:
+ k = get_unaligned_le32(key);
+ l[0] = get_unaligned_le32(key + 4);
+ l[1] = get_unaligned_le32(key + 8);
+ ctx->nrounds = SPECK64_96_NROUNDS;
+ for (i = 0; i < ctx->nrounds; i++) {
+ ctx->round_keys[i] = k;
+ speck64_round(&l[i % 2], &k, i);
+ }
+ break;
+ case SPECK64_128_KEY_SIZE:
+ k = get_unaligned_le32(key);
+ l[0] = get_unaligned_le32(key + 4);
+ l[1] = get_unaligned_le32(key + 8);
+ l[2] = get_unaligned_le32(key + 12);
+ ctx->nrounds = SPECK64_128_NROUNDS;
+ for (i = 0; i < ctx->nrounds; i++) {
+ ctx->round_keys[i] = k;
+ speck64_round(&l[i % 3], &k, i);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_speck64_setkey);
+
+static int speck64_setkey(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ return crypto_speck64_setkey(crypto_tfm_ctx(tfm), key, keylen);
+}
+
+/* Algorithm definitions */
+
+static struct crypto_alg speck_algs[] = {
+ {
+ .cra_name = "speck128",
+ .cra_driver_name = "speck128-generic",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = SPECK128_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct speck128_tfm_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = SPECK128_128_KEY_SIZE,
+ .cia_max_keysize = SPECK128_256_KEY_SIZE,
+ .cia_setkey = speck128_setkey,
+ .cia_encrypt = speck128_encrypt,
+ .cia_decrypt = speck128_decrypt
+ }
+ }
+ }, {
+ .cra_name = "speck64",
+ .cra_driver_name = "speck64-generic",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = SPECK64_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct speck64_tfm_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = SPECK64_96_KEY_SIZE,
+ .cia_max_keysize = SPECK64_128_KEY_SIZE,
+ .cia_setkey = speck64_setkey,
+ .cia_encrypt = speck64_encrypt,
+ .cia_decrypt = speck64_decrypt
+ }
+ }
+ }
+};
+
+static int __init speck_module_init(void)
+{
+ return crypto_register_algs(speck_algs, ARRAY_SIZE(speck_algs));
+}
+
+static void __exit speck_module_exit(void)
+{
+ crypto_unregister_algs(speck_algs, ARRAY_SIZE(speck_algs));
+}
+
+module_init(speck_module_init);
+module_exit(speck_module_exit);
+
+MODULE_DESCRIPTION("Speck block cipher (generic)");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>");
+MODULE_ALIAS_CRYPTO("speck128");
+MODULE_ALIAS_CRYPTO("speck128-generic");
+MODULE_ALIAS_CRYPTO("speck64");
+MODULE_ALIAS_CRYPTO("speck64-generic");
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 14213a096fd2..51fe7c8744ae 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -1983,6 +1983,9 @@ static int do_test(const char *alg, u32 type, u32 mask, int m)
case 190:
ret += tcrypt_test("authenc(hmac(sha512),cbc(des3_ede))");
break;
+ case 191:
+ ret += tcrypt_test("ecb(sm4)");
+ break;
case 200:
test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
speed_template_16_24_32);
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index d5e23a142a04..af4a01c5037b 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -3001,6 +3001,33 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}
}, {
+ .alg = "ecb(sm4)",
+ .test = alg_test_skcipher,
+ .suite = {
+ .cipher = {
+ .enc = __VECS(sm4_enc_tv_template),
+ .dec = __VECS(sm4_dec_tv_template)
+ }
+ }
+ }, {
+ .alg = "ecb(speck128)",
+ .test = alg_test_skcipher,
+ .suite = {
+ .cipher = {
+ .enc = __VECS(speck128_enc_tv_template),
+ .dec = __VECS(speck128_dec_tv_template)
+ }
+ }
+ }, {
+ .alg = "ecb(speck64)",
+ .test = alg_test_skcipher,
+ .suite = {
+ .cipher = {
+ .enc = __VECS(speck64_enc_tv_template),
+ .dec = __VECS(speck64_dec_tv_template)
+ }
+ }
+ }, {
.alg = "ecb(tea)",
.test = alg_test_skcipher,
.suite = {
@@ -3558,6 +3585,24 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}
}, {
+ .alg = "xts(speck128)",
+ .test = alg_test_skcipher,
+ .suite = {
+ .cipher = {
+ .enc = __VECS(speck128_xts_enc_tv_template),
+ .dec = __VECS(speck128_xts_dec_tv_template)
+ }
+ }
+ }, {
+ .alg = "xts(speck64)",
+ .test = alg_test_skcipher,
+ .suite = {
+ .cipher = {
+ .enc = __VECS(speck64_xts_enc_tv_template),
+ .dec = __VECS(speck64_xts_dec_tv_template)
+ }
+ }
+ }, {
.alg = "xts(twofish)",
.test = alg_test_skcipher,
.suite = {
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 6044f6906bd6..004c0a0f8004 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -548,7 +548,7 @@ static const struct akcipher_testvec rsa_tv_template[] = {
static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = {
{
.key =
- "\x30\x82\x03\x1f\x02\x01\x10\x02\x82\x01\x01\x00\xd7\x1e\x77\x82"
+ "\x30\x82\x03\x1f\x02\x01\x00\x02\x82\x01\x01\x00\xd7\x1e\x77\x82"
"\x8c\x92\x31\xe7\x69\x02\xa2\xd5\x5c\x78\xde\xa2\x0c\x8f\xfe\x28"
"\x59\x31\xdf\x40\x9c\x60\x61\x06\xb9\x2f\x62\x40\x80\x76\xcb\x67"
"\x4a\xb5\x59\x56\x69\x17\x07\xfa\xf9\x4c\xbd\x6c\x37\x7a\x46\x7d"
@@ -597,8 +597,8 @@ static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = {
"\xfe\xf8\x27\x1b\xd6\x55\x60\x5e\x48\xb7\x6d\x9a\xa8\x37\xf9\x7a"
"\xde\x1b\xcd\x5d\x1a\x30\xd4\xe9\x9e\x5b\x3c\x15\xf8\x9c\x1f\xda"
"\xd1\x86\x48\x55\xce\x83\xee\x8e\x51\xc7\xde\x32\x12\x47\x7d\x46"
- "\xb8\x35\xdf\x41\x02\x01\x30\x02\x01\x30\x02\x01\x30\x02\x01\x30"
- "\x02\x01\x30",
+ "\xb8\x35\xdf\x41\x02\x01\x00\x02\x01\x00\x02\x01\x00\x02\x01\x00"
+ "\x02\x01\x00",
.key_len = 804,
/*
* m is SHA256 hash of following message:
@@ -2044,6 +2044,265 @@ static const struct hash_testvec crct10dif_tv_template[] = {
.digest = (u8 *)(u16 []){ 0x44c6 },
.np = 4,
.tap = { 1, 255, 57, 6 },
+ }, {
+ .plaintext = "\x6e\x05\x79\x10\xa7\x1b\xb2\x49"
+ "\xe0\x54\xeb\x82\x19\x8d\x24\xbb"
+ "\x2f\xc6\x5d\xf4\x68\xff\x96\x0a"
+ "\xa1\x38\xcf\x43\xda\x71\x08\x7c"
+ "\x13\xaa\x1e\xb5\x4c\xe3\x57\xee"
+ "\x85\x1c\x90\x27\xbe\x32\xc9\x60"
+ "\xf7\x6b\x02\x99\x0d\xa4\x3b\xd2"
+ "\x46\xdd\x74\x0b\x7f\x16\xad\x21"
+ "\xb8\x4f\xe6\x5a\xf1\x88\x1f\x93"
+ "\x2a\xc1\x35\xcc\x63\xfa\x6e\x05"
+ "\x9c\x10\xa7\x3e\xd5\x49\xe0\x77"
+ "\x0e\x82\x19\xb0\x24\xbb\x52\xe9"
+ "\x5d\xf4\x8b\x22\x96\x2d\xc4\x38"
+ "\xcf\x66\xfd\x71\x08\x9f\x13\xaa"
+ "\x41\xd8\x4c\xe3\x7a\x11\x85\x1c"
+ "\xb3\x27\xbe\x55\xec\x60\xf7\x8e"
+ "\x02\x99\x30\xc7\x3b\xd2\x69\x00"
+ "\x74\x0b\xa2\x16\xad\x44\xdb\x4f"
+ "\xe6\x7d\x14\x88\x1f\xb6\x2a\xc1"
+ "\x58\xef\x63\xfa\x91\x05\x9c\x33"
+ "\xca\x3e\xd5\x6c\x03\x77\x0e\xa5"
+ "\x19\xb0\x47\xde\x52\xe9\x80\x17"
+ "\x8b\x22\xb9\x2d\xc4\x5b\xf2\x66"
+ "\xfd\x94\x08\x9f\x36\xcd\x41\xd8"
+ "\x6f\x06\x7a\x11\xa8\x1c\xb3\x4a"
+ "\xe1\x55\xec\x83\x1a\x8e\x25\xbc"
+ "\x30\xc7\x5e\xf5\x69\x00\x97\x0b"
+ "\xa2\x39\xd0\x44\xdb\x72\x09\x7d"
+ "\x14\xab\x1f\xb6\x4d\xe4\x58\xef"
+ "\x86\x1d\x91\x28\xbf\x33\xca\x61"
+ "\xf8\x6c\x03\x9a\x0e\xa5\x3c\xd3"
+ "\x47\xde\x75\x0c\x80\x17\xae\x22"
+ "\xb9\x50\xe7\x5b\xf2\x89\x20\x94"
+ "\x2b\xc2\x36\xcd\x64\xfb\x6f\x06"
+ "\x9d\x11\xa8\x3f\xd6\x4a\xe1\x78"
+ "\x0f\x83\x1a\xb1\x25\xbc\x53\xea"
+ "\x5e\xf5\x8c\x00\x97\x2e\xc5\x39"
+ "\xd0\x67\xfe\x72\x09\xa0\x14\xab"
+ "\x42\xd9\x4d\xe4\x7b\x12\x86\x1d"
+ "\xb4\x28\xbf\x56\xed\x61\xf8\x8f"
+ "\x03\x9a\x31\xc8\x3c\xd3\x6a\x01"
+ "\x75\x0c\xa3\x17\xae\x45\xdc\x50"
+ "\xe7\x7e\x15\x89\x20\xb7\x2b\xc2"
+ "\x59\xf0\x64\xfb\x92\x06\x9d\x34"
+ "\xcb\x3f\xd6\x6d\x04\x78\x0f\xa6"
+ "\x1a\xb1\x48\xdf\x53\xea\x81\x18"
+ "\x8c\x23\xba\x2e\xc5\x5c\xf3\x67"
+ "\xfe\x95\x09\xa0\x37\xce\x42\xd9"
+ "\x70\x07\x7b\x12\xa9\x1d\xb4\x4b"
+ "\xe2\x56\xed\x84\x1b\x8f\x26\xbd"
+ "\x31\xc8\x5f\xf6\x6a\x01\x98\x0c"
+ "\xa3\x3a\xd1\x45\xdc\x73\x0a\x7e"
+ "\x15\xac\x20\xb7\x4e\xe5\x59\xf0"
+ "\x87\x1e\x92\x29\xc0\x34\xcb\x62"
+ "\xf9\x6d\x04\x9b\x0f\xa6\x3d\xd4"
+ "\x48\xdf\x76\x0d\x81\x18\xaf\x23"
+ "\xba\x51\xe8\x5c\xf3\x8a\x21\x95"
+ "\x2c\xc3\x37\xce\x65\xfc\x70\x07"
+ "\x9e\x12\xa9\x40\xd7\x4b\xe2\x79"
+ "\x10\x84\x1b\xb2\x26\xbd\x54\xeb"
+ "\x5f\xf6\x8d\x01\x98\x2f\xc6\x3a"
+ "\xd1\x68\xff\x73\x0a\xa1\x15\xac"
+ "\x43\xda\x4e\xe5\x7c\x13\x87\x1e"
+ "\xb5\x29\xc0\x57\xee\x62\xf9\x90"
+ "\x04\x9b\x32\xc9\x3d\xd4\x6b\x02"
+ "\x76\x0d\xa4\x18\xaf\x46\xdd\x51"
+ "\xe8\x7f\x16\x8a\x21\xb8\x2c\xc3"
+ "\x5a\xf1\x65\xfc\x93\x07\x9e\x35"
+ "\xcc\x40\xd7\x6e\x05\x79\x10\xa7"
+ "\x1b\xb2\x49\xe0\x54\xeb\x82\x19"
+ "\x8d\x24\xbb\x2f\xc6\x5d\xf4\x68"
+ "\xff\x96\x0a\xa1\x38\xcf\x43\xda"
+ "\x71\x08\x7c\x13\xaa\x1e\xb5\x4c"
+ "\xe3\x57\xee\x85\x1c\x90\x27\xbe"
+ "\x32\xc9\x60\xf7\x6b\x02\x99\x0d"
+ "\xa4\x3b\xd2\x46\xdd\x74\x0b\x7f"
+ "\x16\xad\x21\xb8\x4f\xe6\x5a\xf1"
+ "\x88\x1f\x93\x2a\xc1\x35\xcc\x63"
+ "\xfa\x6e\x05\x9c\x10\xa7\x3e\xd5"
+ "\x49\xe0\x77\x0e\x82\x19\xb0\x24"
+ "\xbb\x52\xe9\x5d\xf4\x8b\x22\x96"
+ "\x2d\xc4\x38\xcf\x66\xfd\x71\x08"
+ "\x9f\x13\xaa\x41\xd8\x4c\xe3\x7a"
+ "\x11\x85\x1c\xb3\x27\xbe\x55\xec"
+ "\x60\xf7\x8e\x02\x99\x30\xc7\x3b"
+ "\xd2\x69\x00\x74\x0b\xa2\x16\xad"
+ "\x44\xdb\x4f\xe6\x7d\x14\x88\x1f"
+ "\xb6\x2a\xc1\x58\xef\x63\xfa\x91"
+ "\x05\x9c\x33\xca\x3e\xd5\x6c\x03"
+ "\x77\x0e\xa5\x19\xb0\x47\xde\x52"
+ "\xe9\x80\x17\x8b\x22\xb9\x2d\xc4"
+ "\x5b\xf2\x66\xfd\x94\x08\x9f\x36"
+ "\xcd\x41\xd8\x6f\x06\x7a\x11\xa8"
+ "\x1c\xb3\x4a\xe1\x55\xec\x83\x1a"
+ "\x8e\x25\xbc\x30\xc7\x5e\xf5\x69"
+ "\x00\x97\x0b\xa2\x39\xd0\x44\xdb"
+ "\x72\x09\x7d\x14\xab\x1f\xb6\x4d"
+ "\xe4\x58\xef\x86\x1d\x91\x28\xbf"
+ "\x33\xca\x61\xf8\x6c\x03\x9a\x0e"
+ "\xa5\x3c\xd3\x47\xde\x75\x0c\x80"
+ "\x17\xae\x22\xb9\x50\xe7\x5b\xf2"
+ "\x89\x20\x94\x2b\xc2\x36\xcd\x64"
+ "\xfb\x6f\x06\x9d\x11\xa8\x3f\xd6"
+ "\x4a\xe1\x78\x0f\x83\x1a\xb1\x25"
+ "\xbc\x53\xea\x5e\xf5\x8c\x00\x97"
+ "\x2e\xc5\x39\xd0\x67\xfe\x72\x09"
+ "\xa0\x14\xab\x42\xd9\x4d\xe4\x7b"
+ "\x12\x86\x1d\xb4\x28\xbf\x56\xed"
+ "\x61\xf8\x8f\x03\x9a\x31\xc8\x3c"
+ "\xd3\x6a\x01\x75\x0c\xa3\x17\xae"
+ "\x45\xdc\x50\xe7\x7e\x15\x89\x20"
+ "\xb7\x2b\xc2\x59\xf0\x64\xfb\x92"
+ "\x06\x9d\x34\xcb\x3f\xd6\x6d\x04"
+ "\x78\x0f\xa6\x1a\xb1\x48\xdf\x53"
+ "\xea\x81\x18\x8c\x23\xba\x2e\xc5"
+ "\x5c\xf3\x67\xfe\x95\x09\xa0\x37"
+ "\xce\x42\xd9\x70\x07\x7b\x12\xa9"
+ "\x1d\xb4\x4b\xe2\x56\xed\x84\x1b"
+ "\x8f\x26\xbd\x31\xc8\x5f\xf6\x6a"
+ "\x01\x98\x0c\xa3\x3a\xd1\x45\xdc"
+ "\x73\x0a\x7e\x15\xac\x20\xb7\x4e"
+ "\xe5\x59\xf0\x87\x1e\x92\x29\xc0"
+ "\x34\xcb\x62\xf9\x6d\x04\x9b\x0f"
+ "\xa6\x3d\xd4\x48\xdf\x76\x0d\x81"
+ "\x18\xaf\x23\xba\x51\xe8\x5c\xf3"
+ "\x8a\x21\x95\x2c\xc3\x37\xce\x65"
+ "\xfc\x70\x07\x9e\x12\xa9\x40\xd7"
+ "\x4b\xe2\x79\x10\x84\x1b\xb2\x26"
+ "\xbd\x54\xeb\x5f\xf6\x8d\x01\x98"
+ "\x2f\xc6\x3a\xd1\x68\xff\x73\x0a"
+ "\xa1\x15\xac\x43\xda\x4e\xe5\x7c"
+ "\x13\x87\x1e\xb5\x29\xc0\x57\xee"
+ "\x62\xf9\x90\x04\x9b\x32\xc9\x3d"
+ "\xd4\x6b\x02\x76\x0d\xa4\x18\xaf"
+ "\x46\xdd\x51\xe8\x7f\x16\x8a\x21"
+ "\xb8\x2c\xc3\x5a\xf1\x65\xfc\x93"
+ "\x07\x9e\x35\xcc\x40\xd7\x6e\x05"
+ "\x79\x10\xa7\x1b\xb2\x49\xe0\x54"
+ "\xeb\x82\x19\x8d\x24\xbb\x2f\xc6"
+ "\x5d\xf4\x68\xff\x96\x0a\xa1\x38"
+ "\xcf\x43\xda\x71\x08\x7c\x13\xaa"
+ "\x1e\xb5\x4c\xe3\x57\xee\x85\x1c"
+ "\x90\x27\xbe\x32\xc9\x60\xf7\x6b"
+ "\x02\x99\x0d\xa4\x3b\xd2\x46\xdd"
+ "\x74\x0b\x7f\x16\xad\x21\xb8\x4f"
+ "\xe6\x5a\xf1\x88\x1f\x93\x2a\xc1"
+ "\x35\xcc\x63\xfa\x6e\x05\x9c\x10"
+ "\xa7\x3e\xd5\x49\xe0\x77\x0e\x82"
+ "\x19\xb0\x24\xbb\x52\xe9\x5d\xf4"
+ "\x8b\x22\x96\x2d\xc4\x38\xcf\x66"
+ "\xfd\x71\x08\x9f\x13\xaa\x41\xd8"
+ "\x4c\xe3\x7a\x11\x85\x1c\xb3\x27"
+ "\xbe\x55\xec\x60\xf7\x8e\x02\x99"
+ "\x30\xc7\x3b\xd2\x69\x00\x74\x0b"
+ "\xa2\x16\xad\x44\xdb\x4f\xe6\x7d"
+ "\x14\x88\x1f\xb6\x2a\xc1\x58\xef"
+ "\x63\xfa\x91\x05\x9c\x33\xca\x3e"
+ "\xd5\x6c\x03\x77\x0e\xa5\x19\xb0"
+ "\x47\xde\x52\xe9\x80\x17\x8b\x22"
+ "\xb9\x2d\xc4\x5b\xf2\x66\xfd\x94"
+ "\x08\x9f\x36\xcd\x41\xd8\x6f\x06"
+ "\x7a\x11\xa8\x1c\xb3\x4a\xe1\x55"
+ "\xec\x83\x1a\x8e\x25\xbc\x30\xc7"
+ "\x5e\xf5\x69\x00\x97\x0b\xa2\x39"
+ "\xd0\x44\xdb\x72\x09\x7d\x14\xab"
+ "\x1f\xb6\x4d\xe4\x58\xef\x86\x1d"
+ "\x91\x28\xbf\x33\xca\x61\xf8\x6c"
+ "\x03\x9a\x0e\xa5\x3c\xd3\x47\xde"
+ "\x75\x0c\x80\x17\xae\x22\xb9\x50"
+ "\xe7\x5b\xf2\x89\x20\x94\x2b\xc2"
+ "\x36\xcd\x64\xfb\x6f\x06\x9d\x11"
+ "\xa8\x3f\xd6\x4a\xe1\x78\x0f\x83"
+ "\x1a\xb1\x25\xbc\x53\xea\x5e\xf5"
+ "\x8c\x00\x97\x2e\xc5\x39\xd0\x67"
+ "\xfe\x72\x09\xa0\x14\xab\x42\xd9"
+ "\x4d\xe4\x7b\x12\x86\x1d\xb4\x28"
+ "\xbf\x56\xed\x61\xf8\x8f\x03\x9a"
+ "\x31\xc8\x3c\xd3\x6a\x01\x75\x0c"
+ "\xa3\x17\xae\x45\xdc\x50\xe7\x7e"
+ "\x15\x89\x20\xb7\x2b\xc2\x59\xf0"
+ "\x64\xfb\x92\x06\x9d\x34\xcb\x3f"
+ "\xd6\x6d\x04\x78\x0f\xa6\x1a\xb1"
+ "\x48\xdf\x53\xea\x81\x18\x8c\x23"
+ "\xba\x2e\xc5\x5c\xf3\x67\xfe\x95"
+ "\x09\xa0\x37\xce\x42\xd9\x70\x07"
+ "\x7b\x12\xa9\x1d\xb4\x4b\xe2\x56"
+ "\xed\x84\x1b\x8f\x26\xbd\x31\xc8"
+ "\x5f\xf6\x6a\x01\x98\x0c\xa3\x3a"
+ "\xd1\x45\xdc\x73\x0a\x7e\x15\xac"
+ "\x20\xb7\x4e\xe5\x59\xf0\x87\x1e"
+ "\x92\x29\xc0\x34\xcb\x62\xf9\x6d"
+ "\x04\x9b\x0f\xa6\x3d\xd4\x48\xdf"
+ "\x76\x0d\x81\x18\xaf\x23\xba\x51"
+ "\xe8\x5c\xf3\x8a\x21\x95\x2c\xc3"
+ "\x37\xce\x65\xfc\x70\x07\x9e\x12"
+ "\xa9\x40\xd7\x4b\xe2\x79\x10\x84"
+ "\x1b\xb2\x26\xbd\x54\xeb\x5f\xf6"
+ "\x8d\x01\x98\x2f\xc6\x3a\xd1\x68"
+ "\xff\x73\x0a\xa1\x15\xac\x43\xda"
+ "\x4e\xe5\x7c\x13\x87\x1e\xb5\x29"
+ "\xc0\x57\xee\x62\xf9\x90\x04\x9b"
+ "\x32\xc9\x3d\xd4\x6b\x02\x76\x0d"
+ "\xa4\x18\xaf\x46\xdd\x51\xe8\x7f"
+ "\x16\x8a\x21\xb8\x2c\xc3\x5a\xf1"
+ "\x65\xfc\x93\x07\x9e\x35\xcc\x40"
+ "\xd7\x6e\x05\x79\x10\xa7\x1b\xb2"
+ "\x49\xe0\x54\xeb\x82\x19\x8d\x24"
+ "\xbb\x2f\xc6\x5d\xf4\x68\xff\x96"
+ "\x0a\xa1\x38\xcf\x43\xda\x71\x08"
+ "\x7c\x13\xaa\x1e\xb5\x4c\xe3\x57"
+ "\xee\x85\x1c\x90\x27\xbe\x32\xc9"
+ "\x60\xf7\x6b\x02\x99\x0d\xa4\x3b"
+ "\xd2\x46\xdd\x74\x0b\x7f\x16\xad"
+ "\x21\xb8\x4f\xe6\x5a\xf1\x88\x1f"
+ "\x93\x2a\xc1\x35\xcc\x63\xfa\x6e"
+ "\x05\x9c\x10\xa7\x3e\xd5\x49\xe0"
+ "\x77\x0e\x82\x19\xb0\x24\xbb\x52"
+ "\xe9\x5d\xf4\x8b\x22\x96\x2d\xc4"
+ "\x38\xcf\x66\xfd\x71\x08\x9f\x13"
+ "\xaa\x41\xd8\x4c\xe3\x7a\x11\x85"
+ "\x1c\xb3\x27\xbe\x55\xec\x60\xf7"
+ "\x8e\x02\x99\x30\xc7\x3b\xd2\x69"
+ "\x00\x74\x0b\xa2\x16\xad\x44\xdb"
+ "\x4f\xe6\x7d\x14\x88\x1f\xb6\x2a"
+ "\xc1\x58\xef\x63\xfa\x91\x05\x9c"
+ "\x33\xca\x3e\xd5\x6c\x03\x77\x0e"
+ "\xa5\x19\xb0\x47\xde\x52\xe9\x80"
+ "\x17\x8b\x22\xb9\x2d\xc4\x5b\xf2"
+ "\x66\xfd\x94\x08\x9f\x36\xcd\x41"
+ "\xd8\x6f\x06\x7a\x11\xa8\x1c\xb3"
+ "\x4a\xe1\x55\xec\x83\x1a\x8e\x25"
+ "\xbc\x30\xc7\x5e\xf5\x69\x00\x97"
+ "\x0b\xa2\x39\xd0\x44\xdb\x72\x09"
+ "\x7d\x14\xab\x1f\xb6\x4d\xe4\x58"
+ "\xef\x86\x1d\x91\x28\xbf\x33\xca"
+ "\x61\xf8\x6c\x03\x9a\x0e\xa5\x3c"
+ "\xd3\x47\xde\x75\x0c\x80\x17\xae"
+ "\x22\xb9\x50\xe7\x5b\xf2\x89\x20"
+ "\x94\x2b\xc2\x36\xcd\x64\xfb\x6f"
+ "\x06\x9d\x11\xa8\x3f\xd6\x4a\xe1"
+ "\x78\x0f\x83\x1a\xb1\x25\xbc\x53"
+ "\xea\x5e\xf5\x8c\x00\x97\x2e\xc5"
+ "\x39\xd0\x67\xfe\x72\x09\xa0\x14"
+ "\xab\x42\xd9\x4d\xe4\x7b\x12\x86"
+ "\x1d\xb4\x28\xbf\x56\xed\x61\xf8"
+ "\x8f\x03\x9a\x31\xc8\x3c\xd3\x6a"
+ "\x01\x75\x0c\xa3\x17\xae\x45\xdc"
+ "\x50\xe7\x7e\x15\x89\x20\xb7\x2b"
+ "\xc2\x59\xf0\x64\xfb\x92\x06\x9d"
+ "\x34\xcb\x3f\xd6\x6d\x04\x78\x0f"
+ "\xa6\x1a\xb1\x48\xdf\x53\xea\x81"
+ "\x18\x8c\x23\xba\x2e\xc5\x5c\xf3"
+ "\x67\xfe\x95\x09\xa0\x37\xce\x42"
+ "\xd9\x70\x07\x7b\x12\xa9\x1d\xb4"
+ "\x4b\xe2\x56\xed\x84\x1b\x8f\x26"
+ "\xbd\x31\xc8\x5f\xf6\x6a\x01\x98",
+ .psize = 2048,
+ .digest = (u8 *)(u16 []){ 0x23ca },
}
};
@@ -14323,6 +14582,1623 @@ static const struct cipher_testvec serpent_xts_dec_tv_template[] = {
},
};
+/*
+ * SM4 test vector taken from the draft RFC
+ * https://tools.ietf.org/html/draft-crypto-sm4-00#ref-GBT.32907-2016
+ */
+
+static const struct cipher_testvec sm4_enc_tv_template[] = {
+ { /* SM4 Appendix A: Example Calculations. Example 1. */
+ .key = "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
+ "\xFE\xDC\xBA\x98\x76\x54\x32\x10",
+ .klen = 16,
+ .input = "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
+ "\xFE\xDC\xBA\x98\x76\x54\x32\x10",
+ .ilen = 16,
+ .result = "\x68\x1E\xDF\x34\xD2\x06\x96\x5E"
+ "\x86\xB3\xE9\x4F\x53\x6E\x42\x46",
+ .rlen = 16,
+ }, { /*
+ * SM4 Appendix A: Example Calculations.
+ * Last 10 iterations of Example 2.
+ */
+ .key = "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
+ "\xFE\xDC\xBA\x98\x76\x54\x32\x10",
+ .klen = 16,
+ .input = "\x99\x4a\xc3\xe7\xc3\x57\x89\x6a"
+ "\x81\xfc\xa8\xe\x38\x3e\xef\x80"
+ "\xb1\x98\xf2\xde\x3f\x4b\xae\xd1"
+ "\xf0\xf1\x30\x4c\x1\x27\x5a\x8f"
+ "\x45\xe1\x39\xb7\xae\xff\x1f\x27"
+ "\xad\x57\x15\xab\x31\x5d\xc\xef"
+ "\x8c\xc8\x80\xbd\x11\x98\xf3\x7b"
+ "\xa2\xdd\x14\x20\xf9\xe8\xbb\x82"
+ "\xf7\x32\xca\x4b\xa8\xf7\xb3\x4d"
+ "\x27\xd1\xcd\xe6\xb6\x65\x5a\x23"
+ "\xc2\xf3\x54\x84\x53\xe3\xb9\x20"
+ "\xa5\x37\x0\xbe\xe7\x7b\x48\xfb"
+ "\x21\x3d\x9e\x48\x1d\x9e\xf5\xbf"
+ "\x77\xd5\xb4\x4a\x53\x71\x94\x7a"
+ "\x88\xa6\x6e\x6\x93\xca\x43\xa5"
+ "\xc4\xf6\xcd\x53\x4b\x7b\x8e\xfe"
+ "\xb4\x28\x7c\x42\x29\x32\x5d\x88"
+ "\xed\xce\x0\x19\xe\x16\x2\x6e"
+ "\x87\xff\x2c\xac\xe8\xe7\xe9\xbf"
+ "\x31\x51\xec\x47\xc3\x51\x83\xc1",
+ .ilen = 160,
+ .result = "\xb1\x98\xf2\xde\x3f\x4b\xae\xd1"
+ "\xf0\xf1\x30\x4c\x1\x27\x5a\x8f"
+ "\x45\xe1\x39\xb7\xae\xff\x1f\x27"
+ "\xad\x57\x15\xab\x31\x5d\xc\xef"
+ "\x8c\xc8\x80\xbd\x11\x98\xf3\x7b"
+ "\xa2\xdd\x14\x20\xf9\xe8\xbb\x82"
+ "\xf7\x32\xca\x4b\xa8\xf7\xb3\x4d"
+ "\x27\xd1\xcd\xe6\xb6\x65\x5a\x23"
+ "\xc2\xf3\x54\x84\x53\xe3\xb9\x20"
+ "\xa5\x37\x0\xbe\xe7\x7b\x48\xfb"
+ "\x21\x3d\x9e\x48\x1d\x9e\xf5\xbf"
+ "\x77\xd5\xb4\x4a\x53\x71\x94\x7a"
+ "\x88\xa6\x6e\x6\x93\xca\x43\xa5"
+ "\xc4\xf6\xcd\x53\x4b\x7b\x8e\xfe"
+ "\xb4\x28\x7c\x42\x29\x32\x5d\x88"
+ "\xed\xce\x0\x19\xe\x16\x2\x6e"
+ "\x87\xff\x2c\xac\xe8\xe7\xe9\xbf"
+ "\x31\x51\xec\x47\xc3\x51\x83\xc1"
+ "\x59\x52\x98\xc7\xc6\xfd\x27\x1f"
+ "\x4\x2\xf8\x4\xc3\x3d\x3f\x66",
+ .rlen = 160
+ }
+};
+
+static const struct cipher_testvec sm4_dec_tv_template[] = {
+ { /* SM4 Appendix A: Example Calculations. Example 1. */
+ .key = "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
+ "\xFE\xDC\xBA\x98\x76\x54\x32\x10",
+ .klen = 16,
+ .input = "\x68\x1E\xDF\x34\xD2\x06\x96\x5E"
+ "\x86\xB3\xE9\x4F\x53\x6E\x42\x46",
+ .ilen = 16,
+ .result = "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
+ "\xFE\xDC\xBA\x98\x76\x54\x32\x10",
+ .rlen = 16,
+ }, { /*
+ * SM4 Appendix A: Example Calculations.
+ * Last 10 iterations of Example 2.
+ */
+ .key = "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
+ "\xFE\xDC\xBA\x98\x76\x54\x32\x10",
+ .klen = 16,
+ .input = "\xb1\x98\xf2\xde\x3f\x4b\xae\xd1"
+ "\xf0\xf1\x30\x4c\x1\x27\x5a\x8f"
+ "\x45\xe1\x39\xb7\xae\xff\x1f\x27"
+ "\xad\x57\x15\xab\x31\x5d\xc\xef"
+ "\x8c\xc8\x80\xbd\x11\x98\xf3\x7b"
+ "\xa2\xdd\x14\x20\xf9\xe8\xbb\x82"
+ "\xf7\x32\xca\x4b\xa8\xf7\xb3\x4d"
+ "\x27\xd1\xcd\xe6\xb6\x65\x5a\x23"
+ "\xc2\xf3\x54\x84\x53\xe3\xb9\x20"
+ "\xa5\x37\x0\xbe\xe7\x7b\x48\xfb"
+ "\x21\x3d\x9e\x48\x1d\x9e\xf5\xbf"
+ "\x77\xd5\xb4\x4a\x53\x71\x94\x7a"
+ "\x88\xa6\x6e\x6\x93\xca\x43\xa5"
+ "\xc4\xf6\xcd\x53\x4b\x7b\x8e\xfe"
+ "\xb4\x28\x7c\x42\x29\x32\x5d\x88"
+ "\xed\xce\x0\x19\xe\x16\x2\x6e"
+ "\x87\xff\x2c\xac\xe8\xe7\xe9\xbf"
+ "\x31\x51\xec\x47\xc3\x51\x83\xc1"
+ "\x59\x52\x98\xc7\xc6\xfd\x27\x1f"
+ "\x4\x2\xf8\x4\xc3\x3d\x3f\x66",
+ .ilen = 160,
+ .result = "\x99\x4a\xc3\xe7\xc3\x57\x89\x6a"
+ "\x81\xfc\xa8\xe\x38\x3e\xef\x80"
+ "\xb1\x98\xf2\xde\x3f\x4b\xae\xd1"
+ "\xf0\xf1\x30\x4c\x1\x27\x5a\x8f"
+ "\x45\xe1\x39\xb7\xae\xff\x1f\x27"
+ "\xad\x57\x15\xab\x31\x5d\xc\xef"
+ "\x8c\xc8\x80\xbd\x11\x98\xf3\x7b"
+ "\xa2\xdd\x14\x20\xf9\xe8\xbb\x82"
+ "\xf7\x32\xca\x4b\xa8\xf7\xb3\x4d"
+ "\x27\xd1\xcd\xe6\xb6\x65\x5a\x23"
+ "\xc2\xf3\x54\x84\x53\xe3\xb9\x20"
+ "\xa5\x37\x0\xbe\xe7\x7b\x48\xfb"
+ "\x21\x3d\x9e\x48\x1d\x9e\xf5\xbf"
+ "\x77\xd5\xb4\x4a\x53\x71\x94\x7a"
+ "\x88\xa6\x6e\x6\x93\xca\x43\xa5"
+ "\xc4\xf6\xcd\x53\x4b\x7b\x8e\xfe"
+ "\xb4\x28\x7c\x42\x29\x32\x5d\x88"
+ "\xed\xce\x0\x19\xe\x16\x2\x6e"
+ "\x87\xff\x2c\xac\xe8\xe7\xe9\xbf"
+ "\x31\x51\xec\x47\xc3\x51\x83\xc1",
+ .rlen = 160
+ }
+};
+
+/*
+ * Speck test vectors taken from the original paper:
+ * "The Simon and Speck Families of Lightweight Block Ciphers"
+ * https://eprint.iacr.org/2013/404.pdf
+ *
+ * Note that the paper does not make byte and word order clear. But it was
+ * confirmed with the authors that the intended orders are little endian byte
+ * order and (y, x) word order. Equivalently, the printed test vectors, when
+ * looking at only the bytes (ignoring the whitespace that divides them into
+ * words), are backwards: the left-most byte is actually the one with the
+ * highest memory address, while the right-most byte is actually the one with
+ * the lowest memory address.
+ */
+
+static const struct cipher_testvec speck128_enc_tv_template[] = {
+ { /* Speck128/128 */
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ .klen = 16,
+ .input = "\x20\x6d\x61\x64\x65\x20\x69\x74"
+ "\x20\x65\x71\x75\x69\x76\x61\x6c",
+ .ilen = 16,
+ .result = "\x18\x0d\x57\x5c\xdf\xfe\x60\x78"
+ "\x65\x32\x78\x79\x51\x98\x5d\xa6",
+ .rlen = 16,
+ }, { /* Speck128/192 */
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ .klen = 24,
+ .input = "\x65\x6e\x74\x20\x74\x6f\x20\x43"
+ "\x68\x69\x65\x66\x20\x48\x61\x72",
+ .ilen = 16,
+ .result = "\x86\x18\x3c\xe0\x5d\x18\xbc\xf9"
+ "\x66\x55\x13\x13\x3a\xcf\xe4\x1b",
+ .rlen = 16,
+ }, { /* Speck128/256 */
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ .klen = 32,
+ .input = "\x70\x6f\x6f\x6e\x65\x72\x2e\x20"
+ "\x49\x6e\x20\x74\x68\x6f\x73\x65",
+ .ilen = 16,
+ .result = "\x43\x8f\x18\x9c\x8d\xb4\xee\x4e"
+ "\x3e\xf5\xc0\x05\x04\x01\x09\x41",
+ .rlen = 16,
+ },
+};
+
+static const struct cipher_testvec speck128_dec_tv_template[] = {
+ { /* Speck128/128 */
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ .klen = 16,
+ .input = "\x18\x0d\x57\x5c\xdf\xfe\x60\x78"
+ "\x65\x32\x78\x79\x51\x98\x5d\xa6",
+ .ilen = 16,
+ .result = "\x20\x6d\x61\x64\x65\x20\x69\x74"
+ "\x20\x65\x71\x75\x69\x76\x61\x6c",
+ .rlen = 16,
+ }, { /* Speck128/192 */
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ .klen = 24,
+ .input = "\x86\x18\x3c\xe0\x5d\x18\xbc\xf9"
+ "\x66\x55\x13\x13\x3a\xcf\xe4\x1b",
+ .ilen = 16,
+ .result = "\x65\x6e\x74\x20\x74\x6f\x20\x43"
+ "\x68\x69\x65\x66\x20\x48\x61\x72",
+ .rlen = 16,
+ }, { /* Speck128/256 */
+ .key = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ .klen = 32,
+ .input = "\x43\x8f\x18\x9c\x8d\xb4\xee\x4e"
+ "\x3e\xf5\xc0\x05\x04\x01\x09\x41",
+ .ilen = 16,
+ .result = "\x70\x6f\x6f\x6e\x65\x72\x2e\x20"
+ "\x49\x6e\x20\x74\x68\x6f\x73\x65",
+ .rlen = 16,
+ },
+};
+
+/*
+ * Speck128-XTS test vectors, taken from the AES-XTS test vectors with the
+ * result recomputed with Speck128 as the cipher
+ */
+
+static const struct cipher_testvec speck128_xts_enc_tv_template[] = {
+ {
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .klen = 32,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .ilen = 32,
+ .result = "\xbe\xa0\xe7\x03\xd7\xfe\xab\x62"
+ "\x3b\x99\x4a\x64\x74\x77\xac\xed"
+ "\xd8\xf4\xa6\xcf\xae\xb9\x07\x42"
+ "\x51\xd9\xb6\x1d\xe0\x5e\xbc\x54",
+ .rlen = 32,
+ }, {
+ .key = "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x22\x22\x22\x22\x22\x22\x22\x22"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 32,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .ilen = 32,
+ .result = "\xfb\x53\x81\x75\x6f\x9f\x34\xad"
+ "\x7e\x01\xed\x7b\xcc\xda\x4e\x4a"
+ "\xd4\x84\xa4\x53\xd5\x88\x73\x1b"
+ "\xfd\xcb\xae\x0d\xf3\x04\xee\xe6",
+ .rlen = 32,
+ }, {
+ .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+ "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+ "\x22\x22\x22\x22\x22\x22\x22\x22"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 32,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .ilen = 32,
+ .result = "\x21\x52\x84\x15\xd1\xf7\x21\x55"
+ "\xd9\x75\x4a\xd3\xc5\xdb\x9f\x7d"
+ "\xda\x63\xb2\xf1\x82\xb0\x89\x59"
+ "\x86\xd4\xaa\xaa\xdd\xff\x4f\x92",
+ .rlen = 32,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x31\x41\x59\x26\x53\x58\x97\x93"
+ "\x23\x84\x62\x64\x33\x83\x27\x95",
+ .klen = 32,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .ilen = 512,
+ .result = "\x57\xb5\xf8\x71\x6e\x6d\xdd\x82"
+ "\x53\xd0\xed\x2d\x30\xc1\x20\xef"
+ "\x70\x67\x5e\xff\x09\x70\xbb\xc1"
+ "\x3a\x7b\x48\x26\xd9\x0b\xf4\x48"
+ "\xbe\xce\xb1\xc7\xb2\x67\xc4\xa7"
+ "\x76\xf8\x36\x30\xb7\xb4\x9a\xd9"
+ "\xf5\x9d\xd0\x7b\xc1\x06\x96\x44"
+ "\x19\xc5\x58\x84\x63\xb9\x12\x68"
+ "\x68\xc7\xaa\x18\x98\xf2\x1f\x5c"
+ "\x39\xa6\xd8\x32\x2b\xc3\x51\xfd"
+ "\x74\x79\x2e\xb4\x44\xd7\x69\xc4"
+ "\xfc\x29\xe6\xed\x26\x1e\xa6\x9d"
+ "\x1c\xbe\x00\x0e\x7f\x3a\xca\xfb"
+ "\x6d\x13\x65\xa0\xf9\x31\x12\xe2"
+ "\x26\xd1\xec\x2b\x0a\x8b\x59\x99"
+ "\xa7\x49\xa0\x0e\x09\x33\x85\x50"
+ "\xc3\x23\xca\x7a\xdd\x13\x45\x5f"
+ "\xde\x4c\xa7\xcb\x00\x8a\x66\x6f"
+ "\xa2\xb6\xb1\x2e\xe1\xa0\x18\xf6"
+ "\xad\xf3\xbd\xeb\xc7\xef\x55\x4f"
+ "\x79\x91\x8d\x36\x13\x7b\xd0\x4a"
+ "\x6c\x39\xfb\x53\xb8\x6f\x02\x51"
+ "\xa5\x20\xac\x24\x1c\x73\x59\x73"
+ "\x58\x61\x3a\x87\x58\xb3\x20\x56"
+ "\x39\x06\x2b\x4d\xd3\x20\x2b\x89"
+ "\x3f\xa2\xf0\x96\xeb\x7f\xa4\xcd"
+ "\x11\xae\xbd\xcb\x3a\xb4\xd9\x91"
+ "\x09\x35\x71\x50\x65\xac\x92\xe3"
+ "\x7b\x32\xc0\x7a\xdd\xd4\xc3\x92"
+ "\x6f\xeb\x79\xde\x6f\xd3\x25\xc9"
+ "\xcd\x63\xf5\x1e\x7a\x3b\x26\x9d"
+ "\x77\x04\x80\xa9\xbf\x38\xb5\xbd"
+ "\xb8\x05\x07\xbd\xfd\xab\x7b\xf8"
+ "\x2a\x26\xcc\x49\x14\x6d\x55\x01"
+ "\x06\x94\xd8\xb2\x2d\x53\x83\x1b"
+ "\x8f\xd4\xdd\x57\x12\x7e\x18\xba"
+ "\x8e\xe2\x4d\x80\xef\x7e\x6b\x9d"
+ "\x24\xa9\x60\xa4\x97\x85\x86\x2a"
+ "\x01\x00\x09\xf1\xcb\x4a\x24\x1c"
+ "\xd8\xf6\xe6\x5b\xe7\x5d\xf2\xc4"
+ "\x97\x1c\x10\xc6\x4d\x66\x4f\x98"
+ "\x87\x30\xac\xd5\xea\x73\x49\x10"
+ "\x80\xea\xe5\x5f\x4d\x5f\x03\x33"
+ "\x66\x02\x35\x3d\x60\x06\x36\x4f"
+ "\x14\x1c\xd8\x07\x1f\x78\xd0\xf8"
+ "\x4f\x6c\x62\x7c\x15\xa5\x7c\x28"
+ "\x7c\xcc\xeb\x1f\xd1\x07\x90\x93"
+ "\x7e\xc2\xa8\x3a\x80\xc0\xf5\x30"
+ "\xcc\x75\xcf\x16\x26\xa9\x26\x3b"
+ "\xe7\x68\x2f\x15\x21\x5b\xe4\x00"
+ "\xbd\x48\x50\xcd\x75\x70\xc4\x62"
+ "\xbb\x41\xfb\x89\x4a\x88\x3b\x3b"
+ "\x51\x66\x02\x69\x04\x97\x36\xd4"
+ "\x75\xae\x0b\xa3\x42\xf8\xca\x79"
+ "\x8f\x93\xe9\xcc\x38\xbd\xd6\xd2"
+ "\xf9\x70\x4e\xc3\x6a\x8e\x25\xbd"
+ "\xea\x15\x5a\xa0\x85\x7e\x81\x0d"
+ "\x03\xe7\x05\x39\xf5\x05\x26\xee"
+ "\xec\xaa\x1f\x3d\xc9\x98\x76\x01"
+ "\x2c\xf4\xfc\xa3\x88\x77\x38\xc4"
+ "\x50\x65\x50\x6d\x04\x1f\xdf\x5a"
+ "\xaa\xf2\x01\xa9\xc1\x8d\xee\xca"
+ "\x47\x26\xef\x39\xb8\xb4\xf2\xd1"
+ "\xd6\xbb\x1b\x2a\xc1\x34\x14\xcf",
+ .rlen = 512,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x62\x49\x77\x57\x24\x70\x93\x69"
+ "\x99\x59\x57\x49\x66\x96\x76\x27"
+ "\x31\x41\x59\x26\x53\x58\x97\x93"
+ "\x23\x84\x62\x64\x33\x83\x27\x95"
+ "\x02\x88\x41\x97\x16\x93\x99\x37"
+ "\x51\x05\x82\x09\x74\x94\x45\x92",
+ .klen = 64,
+ .iv = "\xff\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .ilen = 512,
+ .result = "\xc5\x85\x2a\x4b\x73\xe4\xf6\xf1"
+ "\x7e\xf9\xf6\xe9\xa3\x73\x36\xcb"
+ "\xaa\xb6\x22\xb0\x24\x6e\x3d\x73"
+ "\x92\x99\xde\xd3\x76\xed\xcd\x63"
+ "\x64\x3a\x22\x57\xc1\x43\x49\xd4"
+ "\x79\x36\x31\x19\x62\xae\x10\x7e"
+ "\x7d\xcf\x7a\xe2\x6b\xce\x27\xfa"
+ "\xdc\x3d\xd9\x83\xd3\x42\x4c\xe0"
+ "\x1b\xd6\x1d\x1a\x6f\xd2\x03\x00"
+ "\xfc\x81\x99\x8a\x14\x62\xf5\x7e"
+ "\x0d\xe7\x12\xe8\x17\x9d\x0b\xec"
+ "\xe2\xf7\xc9\xa7\x63\xd1\x79\xb6"
+ "\x62\x62\x37\xfe\x0a\x4c\x4a\x37"
+ "\x70\xc7\x5e\x96\x5f\xbc\x8e\x9e"
+ "\x85\x3c\x4f\x26\x64\x85\xbc\x68"
+ "\xb0\xe0\x86\x5e\x26\x41\xce\x11"
+ "\x50\xda\x97\x14\xe9\x9e\xc7\x6d"
+ "\x3b\xdc\x43\xde\x2b\x27\x69\x7d"
+ "\xfc\xb0\x28\xbd\x8f\xb1\xc6\x31"
+ "\x14\x4d\xf0\x74\x37\xfd\x07\x25"
+ "\x96\x55\xe5\xfc\x9e\x27\x2a\x74"
+ "\x1b\x83\x4d\x15\x83\xac\x57\xa0"
+ "\xac\xa5\xd0\x38\xef\x19\x56\x53"
+ "\x25\x4b\xfc\xce\x04\x23\xe5\x6b"
+ "\xf6\xc6\x6c\x32\x0b\xb3\x12\xc5"
+ "\xed\x22\x34\x1c\x5d\xed\x17\x06"
+ "\x36\xa3\xe6\x77\xb9\x97\x46\xb8"
+ "\xe9\x3f\x7e\xc7\xbc\x13\x5c\xdc"
+ "\x6e\x3f\x04\x5e\xd1\x59\xa5\x82"
+ "\x35\x91\x3d\x1b\xe4\x97\x9f\x92"
+ "\x1c\x5e\x5f\x6f\x41\xd4\x62\xa1"
+ "\x8d\x39\xfc\x42\xfb\x38\x80\xb9"
+ "\x0a\xe3\xcc\x6a\x93\xd9\x7a\xb1"
+ "\xe9\x69\xaf\x0a\x6b\x75\x38\xa7"
+ "\xa1\xbf\xf7\xda\x95\x93\x4b\x78"
+ "\x19\xf5\x94\xf9\xd2\x00\x33\x37"
+ "\xcf\xf5\x9e\x9c\xf3\xcc\xa6\xee"
+ "\x42\xb2\x9e\x2c\x5f\x48\x23\x26"
+ "\x15\x25\x17\x03\x3d\xfe\x2c\xfc"
+ "\xeb\xba\xda\xe0\x00\x05\xb6\xa6"
+ "\x07\xb3\xe8\x36\x5b\xec\x5b\xbf"
+ "\xd6\x5b\x00\x74\xc6\x97\xf1\x6a"
+ "\x49\xa1\xc3\xfa\x10\x52\xb9\x14"
+ "\xad\xb7\x73\xf8\x78\x12\xc8\x59"
+ "\x17\x80\x4c\x57\x39\xf1\x6d\x80"
+ "\x25\x77\x0f\x5e\x7d\xf0\xaf\x21"
+ "\xec\xce\xb7\xc8\x02\x8a\xed\x53"
+ "\x2c\x25\x68\x2e\x1f\x85\x5e\x67"
+ "\xd1\x07\x7a\x3a\x89\x08\xe0\x34"
+ "\xdc\xdb\x26\xb4\x6b\x77\xfc\x40"
+ "\x31\x15\x72\xa0\xf0\x73\xd9\x3b"
+ "\xd5\xdb\xfe\xfc\x8f\xa9\x44\xa2"
+ "\x09\x9f\xc6\x33\xe5\xe2\x88\xe8"
+ "\xf3\xf0\x1a\xf4\xce\x12\x0f\xd6"
+ "\xf7\x36\xe6\xa4\xf4\x7a\x10\x58"
+ "\xcc\x1f\x48\x49\x65\x47\x75\xe9"
+ "\x28\xe1\x65\x7b\xf2\xc4\xb5\x07"
+ "\xf2\xec\x76\xd8\x8f\x09\xf3\x16"
+ "\xa1\x51\x89\x3b\xeb\x96\x42\xac"
+ "\x65\xe0\x67\x63\x29\xdc\xb4\x7d"
+ "\xf2\x41\x51\x6a\xcb\xde\x3c\xfb"
+ "\x66\x8d\x13\xca\xe0\x59\x2a\x00"
+ "\xc9\x53\x4c\xe6\x9e\xe2\x73\xd5"
+ "\x67\x19\xb2\xbd\x9a\x63\xd7\x5c",
+ .rlen = 512,
+ .also_non_np = 1,
+ .np = 3,
+ .tap = { 512 - 20, 4, 16 },
+ }
+};
+
+static const struct cipher_testvec speck128_xts_dec_tv_template[] = {
+ {
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .klen = 32,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\xbe\xa0\xe7\x03\xd7\xfe\xab\x62"
+ "\x3b\x99\x4a\x64\x74\x77\xac\xed"
+ "\xd8\xf4\xa6\xcf\xae\xb9\x07\x42"
+ "\x51\xd9\xb6\x1d\xe0\x5e\xbc\x54",
+ .ilen = 32,
+ .result = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .rlen = 32,
+ }, {
+ .key = "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x22\x22\x22\x22\x22\x22\x22\x22"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 32,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\xfb\x53\x81\x75\x6f\x9f\x34\xad"
+ "\x7e\x01\xed\x7b\xcc\xda\x4e\x4a"
+ "\xd4\x84\xa4\x53\xd5\x88\x73\x1b"
+ "\xfd\xcb\xae\x0d\xf3\x04\xee\xe6",
+ .ilen = 32,
+ .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .rlen = 32,
+ }, {
+ .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+ "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+ "\x22\x22\x22\x22\x22\x22\x22\x22"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 32,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x21\x52\x84\x15\xd1\xf7\x21\x55"
+ "\xd9\x75\x4a\xd3\xc5\xdb\x9f\x7d"
+ "\xda\x63\xb2\xf1\x82\xb0\x89\x59"
+ "\x86\xd4\xaa\xaa\xdd\xff\x4f\x92",
+ .ilen = 32,
+ .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .rlen = 32,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x31\x41\x59\x26\x53\x58\x97\x93"
+ "\x23\x84\x62\x64\x33\x83\x27\x95",
+ .klen = 32,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x57\xb5\xf8\x71\x6e\x6d\xdd\x82"
+ "\x53\xd0\xed\x2d\x30\xc1\x20\xef"
+ "\x70\x67\x5e\xff\x09\x70\xbb\xc1"
+ "\x3a\x7b\x48\x26\xd9\x0b\xf4\x48"
+ "\xbe\xce\xb1\xc7\xb2\x67\xc4\xa7"
+ "\x76\xf8\x36\x30\xb7\xb4\x9a\xd9"
+ "\xf5\x9d\xd0\x7b\xc1\x06\x96\x44"
+ "\x19\xc5\x58\x84\x63\xb9\x12\x68"
+ "\x68\xc7\xaa\x18\x98\xf2\x1f\x5c"
+ "\x39\xa6\xd8\x32\x2b\xc3\x51\xfd"
+ "\x74\x79\x2e\xb4\x44\xd7\x69\xc4"
+ "\xfc\x29\xe6\xed\x26\x1e\xa6\x9d"
+ "\x1c\xbe\x00\x0e\x7f\x3a\xca\xfb"
+ "\x6d\x13\x65\xa0\xf9\x31\x12\xe2"
+ "\x26\xd1\xec\x2b\x0a\x8b\x59\x99"
+ "\xa7\x49\xa0\x0e\x09\x33\x85\x50"
+ "\xc3\x23\xca\x7a\xdd\x13\x45\x5f"
+ "\xde\x4c\xa7\xcb\x00\x8a\x66\x6f"
+ "\xa2\xb6\xb1\x2e\xe1\xa0\x18\xf6"
+ "\xad\xf3\xbd\xeb\xc7\xef\x55\x4f"
+ "\x79\x91\x8d\x36\x13\x7b\xd0\x4a"
+ "\x6c\x39\xfb\x53\xb8\x6f\x02\x51"
+ "\xa5\x20\xac\x24\x1c\x73\x59\x73"
+ "\x58\x61\x3a\x87\x58\xb3\x20\x56"
+ "\x39\x06\x2b\x4d\xd3\x20\x2b\x89"
+ "\x3f\xa2\xf0\x96\xeb\x7f\xa4\xcd"
+ "\x11\xae\xbd\xcb\x3a\xb4\xd9\x91"
+ "\x09\x35\x71\x50\x65\xac\x92\xe3"
+ "\x7b\x32\xc0\x7a\xdd\xd4\xc3\x92"
+ "\x6f\xeb\x79\xde\x6f\xd3\x25\xc9"
+ "\xcd\x63\xf5\x1e\x7a\x3b\x26\x9d"
+ "\x77\x04\x80\xa9\xbf\x38\xb5\xbd"
+ "\xb8\x05\x07\xbd\xfd\xab\x7b\xf8"
+ "\x2a\x26\xcc\x49\x14\x6d\x55\x01"
+ "\x06\x94\xd8\xb2\x2d\x53\x83\x1b"
+ "\x8f\xd4\xdd\x57\x12\x7e\x18\xba"
+ "\x8e\xe2\x4d\x80\xef\x7e\x6b\x9d"
+ "\x24\xa9\x60\xa4\x97\x85\x86\x2a"
+ "\x01\x00\x09\xf1\xcb\x4a\x24\x1c"
+ "\xd8\xf6\xe6\x5b\xe7\x5d\xf2\xc4"
+ "\x97\x1c\x10\xc6\x4d\x66\x4f\x98"
+ "\x87\x30\xac\xd5\xea\x73\x49\x10"
+ "\x80\xea\xe5\x5f\x4d\x5f\x03\x33"
+ "\x66\x02\x35\x3d\x60\x06\x36\x4f"
+ "\x14\x1c\xd8\x07\x1f\x78\xd0\xf8"
+ "\x4f\x6c\x62\x7c\x15\xa5\x7c\x28"
+ "\x7c\xcc\xeb\x1f\xd1\x07\x90\x93"
+ "\x7e\xc2\xa8\x3a\x80\xc0\xf5\x30"
+ "\xcc\x75\xcf\x16\x26\xa9\x26\x3b"
+ "\xe7\x68\x2f\x15\x21\x5b\xe4\x00"
+ "\xbd\x48\x50\xcd\x75\x70\xc4\x62"
+ "\xbb\x41\xfb\x89\x4a\x88\x3b\x3b"
+ "\x51\x66\x02\x69\x04\x97\x36\xd4"
+ "\x75\xae\x0b\xa3\x42\xf8\xca\x79"
+ "\x8f\x93\xe9\xcc\x38\xbd\xd6\xd2"
+ "\xf9\x70\x4e\xc3\x6a\x8e\x25\xbd"
+ "\xea\x15\x5a\xa0\x85\x7e\x81\x0d"
+ "\x03\xe7\x05\x39\xf5\x05\x26\xee"
+ "\xec\xaa\x1f\x3d\xc9\x98\x76\x01"
+ "\x2c\xf4\xfc\xa3\x88\x77\x38\xc4"
+ "\x50\x65\x50\x6d\x04\x1f\xdf\x5a"
+ "\xaa\xf2\x01\xa9\xc1\x8d\xee\xca"
+ "\x47\x26\xef\x39\xb8\xb4\xf2\xd1"
+ "\xd6\xbb\x1b\x2a\xc1\x34\x14\xcf",
+ .ilen = 512,
+ .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .rlen = 512,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x62\x49\x77\x57\x24\x70\x93\x69"
+ "\x99\x59\x57\x49\x66\x96\x76\x27"
+ "\x31\x41\x59\x26\x53\x58\x97\x93"
+ "\x23\x84\x62\x64\x33\x83\x27\x95"
+ "\x02\x88\x41\x97\x16\x93\x99\x37"
+ "\x51\x05\x82\x09\x74\x94\x45\x92",
+ .klen = 64,
+ .iv = "\xff\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\xc5\x85\x2a\x4b\x73\xe4\xf6\xf1"
+ "\x7e\xf9\xf6\xe9\xa3\x73\x36\xcb"
+ "\xaa\xb6\x22\xb0\x24\x6e\x3d\x73"
+ "\x92\x99\xde\xd3\x76\xed\xcd\x63"
+ "\x64\x3a\x22\x57\xc1\x43\x49\xd4"
+ "\x79\x36\x31\x19\x62\xae\x10\x7e"
+ "\x7d\xcf\x7a\xe2\x6b\xce\x27\xfa"
+ "\xdc\x3d\xd9\x83\xd3\x42\x4c\xe0"
+ "\x1b\xd6\x1d\x1a\x6f\xd2\x03\x00"
+ "\xfc\x81\x99\x8a\x14\x62\xf5\x7e"
+ "\x0d\xe7\x12\xe8\x17\x9d\x0b\xec"
+ "\xe2\xf7\xc9\xa7\x63\xd1\x79\xb6"
+ "\x62\x62\x37\xfe\x0a\x4c\x4a\x37"
+ "\x70\xc7\x5e\x96\x5f\xbc\x8e\x9e"
+ "\x85\x3c\x4f\x26\x64\x85\xbc\x68"
+ "\xb0\xe0\x86\x5e\x26\x41\xce\x11"
+ "\x50\xda\x97\x14\xe9\x9e\xc7\x6d"
+ "\x3b\xdc\x43\xde\x2b\x27\x69\x7d"
+ "\xfc\xb0\x28\xbd\x8f\xb1\xc6\x31"
+ "\x14\x4d\xf0\x74\x37\xfd\x07\x25"
+ "\x96\x55\xe5\xfc\x9e\x27\x2a\x74"
+ "\x1b\x83\x4d\x15\x83\xac\x57\xa0"
+ "\xac\xa5\xd0\x38\xef\x19\x56\x53"
+ "\x25\x4b\xfc\xce\x04\x23\xe5\x6b"
+ "\xf6\xc6\x6c\x32\x0b\xb3\x12\xc5"
+ "\xed\x22\x34\x1c\x5d\xed\x17\x06"
+ "\x36\xa3\xe6\x77\xb9\x97\x46\xb8"
+ "\xe9\x3f\x7e\xc7\xbc\x13\x5c\xdc"
+ "\x6e\x3f\x04\x5e\xd1\x59\xa5\x82"
+ "\x35\x91\x3d\x1b\xe4\x97\x9f\x92"
+ "\x1c\x5e\x5f\x6f\x41\xd4\x62\xa1"
+ "\x8d\x39\xfc\x42\xfb\x38\x80\xb9"
+ "\x0a\xe3\xcc\x6a\x93\xd9\x7a\xb1"
+ "\xe9\x69\xaf\x0a\x6b\x75\x38\xa7"
+ "\xa1\xbf\xf7\xda\x95\x93\x4b\x78"
+ "\x19\xf5\x94\xf9\xd2\x00\x33\x37"
+ "\xcf\xf5\x9e\x9c\xf3\xcc\xa6\xee"
+ "\x42\xb2\x9e\x2c\x5f\x48\x23\x26"
+ "\x15\x25\x17\x03\x3d\xfe\x2c\xfc"
+ "\xeb\xba\xda\xe0\x00\x05\xb6\xa6"
+ "\x07\xb3\xe8\x36\x5b\xec\x5b\xbf"
+ "\xd6\x5b\x00\x74\xc6\x97\xf1\x6a"
+ "\x49\xa1\xc3\xfa\x10\x52\xb9\x14"
+ "\xad\xb7\x73\xf8\x78\x12\xc8\x59"
+ "\x17\x80\x4c\x57\x39\xf1\x6d\x80"
+ "\x25\x77\x0f\x5e\x7d\xf0\xaf\x21"
+ "\xec\xce\xb7\xc8\x02\x8a\xed\x53"
+ "\x2c\x25\x68\x2e\x1f\x85\x5e\x67"
+ "\xd1\x07\x7a\x3a\x89\x08\xe0\x34"
+ "\xdc\xdb\x26\xb4\x6b\x77\xfc\x40"
+ "\x31\x15\x72\xa0\xf0\x73\xd9\x3b"
+ "\xd5\xdb\xfe\xfc\x8f\xa9\x44\xa2"
+ "\x09\x9f\xc6\x33\xe5\xe2\x88\xe8"
+ "\xf3\xf0\x1a\xf4\xce\x12\x0f\xd6"
+ "\xf7\x36\xe6\xa4\xf4\x7a\x10\x58"
+ "\xcc\x1f\x48\x49\x65\x47\x75\xe9"
+ "\x28\xe1\x65\x7b\xf2\xc4\xb5\x07"
+ "\xf2\xec\x76\xd8\x8f\x09\xf3\x16"
+ "\xa1\x51\x89\x3b\xeb\x96\x42\xac"
+ "\x65\xe0\x67\x63\x29\xdc\xb4\x7d"
+ "\xf2\x41\x51\x6a\xcb\xde\x3c\xfb"
+ "\x66\x8d\x13\xca\xe0\x59\x2a\x00"
+ "\xc9\x53\x4c\xe6\x9e\xe2\x73\xd5"
+ "\x67\x19\xb2\xbd\x9a\x63\xd7\x5c",
+ .ilen = 512,
+ .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .rlen = 512,
+ .also_non_np = 1,
+ .np = 3,
+ .tap = { 512 - 20, 4, 16 },
+ }
+};
+
+static const struct cipher_testvec speck64_enc_tv_template[] = {
+ { /* Speck64/96 */
+ .key = "\x00\x01\x02\x03\x08\x09\x0a\x0b"
+ "\x10\x11\x12\x13",
+ .klen = 12,
+ .input = "\x65\x61\x6e\x73\x20\x46\x61\x74",
+ .ilen = 8,
+ .result = "\x6c\x94\x75\x41\xec\x52\x79\x9f",
+ .rlen = 8,
+ }, { /* Speck64/128 */
+ .key = "\x00\x01\x02\x03\x08\x09\x0a\x0b"
+ "\x10\x11\x12\x13\x18\x19\x1a\x1b",
+ .klen = 16,
+ .input = "\x2d\x43\x75\x74\x74\x65\x72\x3b",
+ .ilen = 8,
+ .result = "\x8b\x02\x4e\x45\x48\xa5\x6f\x8c",
+ .rlen = 8,
+ },
+};
+
+static const struct cipher_testvec speck64_dec_tv_template[] = {
+ { /* Speck64/96 */
+ .key = "\x00\x01\x02\x03\x08\x09\x0a\x0b"
+ "\x10\x11\x12\x13",
+ .klen = 12,
+ .input = "\x6c\x94\x75\x41\xec\x52\x79\x9f",
+ .ilen = 8,
+ .result = "\x65\x61\x6e\x73\x20\x46\x61\x74",
+ .rlen = 8,
+ }, { /* Speck64/128 */
+ .key = "\x00\x01\x02\x03\x08\x09\x0a\x0b"
+ "\x10\x11\x12\x13\x18\x19\x1a\x1b",
+ .klen = 16,
+ .input = "\x8b\x02\x4e\x45\x48\xa5\x6f\x8c",
+ .ilen = 8,
+ .result = "\x2d\x43\x75\x74\x74\x65\x72\x3b",
+ .rlen = 8,
+ },
+};
+
+/*
+ * Speck64-XTS test vectors, taken from the AES-XTS test vectors with the result
+ * recomputed with Speck64 as the cipher, and key lengths adjusted
+ */
+
+static const struct cipher_testvec speck64_xts_enc_tv_template[] = {
+ {
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .klen = 24,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .ilen = 32,
+ .result = "\x84\xaf\x54\x07\x19\xd4\x7c\xa6"
+ "\xe4\xfe\xdf\xc4\x1f\x34\xc3\xc2"
+ "\x80\xf5\x72\xe7\xcd\xf0\x99\x22"
+ "\x35\xa7\x2f\x06\xef\xdc\x51\xaa",
+ .rlen = 32,
+ }, {
+ .key = "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 24,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .ilen = 32,
+ .result = "\x12\x56\x73\xcd\x15\x87\xa8\x59"
+ "\xcf\x84\xae\xd9\x1c\x66\xd6\x9f"
+ "\xb3\x12\x69\x7e\x36\xeb\x52\xff"
+ "\x62\xdd\xba\x90\xb3\xe1\xee\x99",
+ .rlen = 32,
+ }, {
+ .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+ "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 24,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .ilen = 32,
+ .result = "\x15\x1b\xe4\x2c\xa2\x5a\x2d\x2c"
+ "\x27\x36\xc0\xbf\x5d\xea\x36\x37"
+ "\x2d\x1a\x88\xbc\x66\xb5\xd0\x0b"
+ "\xa1\xbc\x19\xb2\x0f\x3b\x75\x34",
+ .rlen = 32,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x31\x41\x59\x26\x53\x58\x97\x93",
+ .klen = 24,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .ilen = 512,
+ .result = "\xaf\xa1\x81\xa6\x32\xbb\x15\x8e"
+ "\xf8\x95\x2e\xd3\xe6\xee\x7e\x09"
+ "\x0c\x1a\xf5\x02\x97\x8b\xe3\xb3"
+ "\x11\xc7\x39\x96\xd0\x95\xf4\x56"
+ "\xf4\xdd\x03\x38\x01\x44\x2c\xcf"
+ "\x88\xae\x8e\x3c\xcd\xe7\xaa\x66"
+ "\xfe\x3d\xc6\xfb\x01\x23\x51\x43"
+ "\xd5\xd2\x13\x86\x94\x34\xe9\x62"
+ "\xf9\x89\xe3\xd1\x7b\xbe\xf8\xef"
+ "\x76\x35\x04\x3f\xdb\x23\x9d\x0b"
+ "\x85\x42\xb9\x02\xd6\xcc\xdb\x96"
+ "\xa7\x6b\x27\xb6\xd4\x45\x8f\x7d"
+ "\xae\xd2\x04\xd5\xda\xc1\x7e\x24"
+ "\x8c\x73\xbe\x48\x7e\xcf\x65\x28"
+ "\x29\xe5\xbe\x54\x30\xcb\x46\x95"
+ "\x4f\x2e\x8a\x36\xc8\x27\xc5\xbe"
+ "\xd0\x1a\xaf\xab\x26\xcd\x9e\x69"
+ "\xa1\x09\x95\x71\x26\xe9\xc4\xdf"
+ "\xe6\x31\xc3\x46\xda\xaf\x0b\x41"
+ "\x1f\xab\xb1\x8e\xd6\xfc\x0b\xb3"
+ "\x82\xc0\x37\x27\xfc\x91\xa7\x05"
+ "\xfb\xc5\xdc\x2b\x74\x96\x48\x43"
+ "\x5d\x9c\x19\x0f\x60\x63\x3a\x1f"
+ "\x6f\xf0\x03\xbe\x4d\xfd\xc8\x4a"
+ "\xc6\xa4\x81\x6d\xc3\x12\x2a\x5c"
+ "\x07\xff\xf3\x72\x74\x48\xb5\x40"
+ "\x50\xb5\xdd\x90\x43\x31\x18\x15"
+ "\x7b\xf2\xa6\xdb\x83\xc8\x4b\x4a"
+ "\x29\x93\x90\x8b\xda\x07\xf0\x35"
+ "\x6d\x90\x88\x09\x4e\x83\xf5\x5b"
+ "\x94\x12\xbb\x33\x27\x1d\x3f\x23"
+ "\x51\xa8\x7c\x07\xa2\xae\x77\xa6"
+ "\x50\xfd\xcc\xc0\x4f\x80\x7a\x9f"
+ "\x66\xdd\xcd\x75\x24\x8b\x33\xf7"
+ "\x20\xdb\x83\x9b\x4f\x11\x63\x6e"
+ "\xcf\x37\xef\xc9\x11\x01\x5c\x45"
+ "\x32\x99\x7c\x3c\x9e\x42\x89\xe3"
+ "\x70\x6d\x15\x9f\xb1\xe6\xb6\x05"
+ "\xfe\x0c\xb9\x49\x2d\x90\x6d\xcc"
+ "\x5d\x3f\xc1\xfe\x89\x0a\x2e\x2d"
+ "\xa0\xa8\x89\x3b\x73\x39\xa5\x94"
+ "\x4c\xa4\xa6\xbb\xa7\x14\x46\x89"
+ "\x10\xff\xaf\xef\xca\xdd\x4f\x80"
+ "\xb3\xdf\x3b\xab\xd4\xe5\x5a\xc7"
+ "\x33\xca\x00\x8b\x8b\x3f\xea\xec"
+ "\x68\x8a\xc2\x6d\xfd\xd4\x67\x0f"
+ "\x22\x31\xe1\x0e\xfe\x5a\x04\xd5"
+ "\x64\xa3\xf1\x1a\x76\x28\xcc\x35"
+ "\x36\xa7\x0a\x74\xf7\x1c\x44\x9b"
+ "\xc7\x1b\x53\x17\x02\xea\xd1\xad"
+ "\x13\x51\x73\xc0\xa0\xb2\x05\x32"
+ "\xa8\xa2\x37\x2e\xe1\x7a\x3a\x19"
+ "\x26\xb4\x6c\x62\x5d\xb3\x1a\x1d"
+ "\x59\xda\xee\x1a\x22\x18\xda\x0d"
+ "\x88\x0f\x55\x8b\x72\x62\xfd\xc1"
+ "\x69\x13\xcd\x0d\x5f\xc1\x09\x52"
+ "\xee\xd6\xe3\x84\x4d\xee\xf6\x88"
+ "\xaf\x83\xdc\x76\xf4\xc0\x93\x3f"
+ "\x4a\x75\x2f\xb0\x0b\x3e\xc4\x54"
+ "\x7d\x69\x8d\x00\x62\x77\x0d\x14"
+ "\xbe\x7c\xa6\x7d\xc5\x24\x4f\xf3"
+ "\x50\xf7\x5f\xf4\xc2\xca\x41\x97"
+ "\x37\xbe\x75\x74\xcd\xf0\x75\x6e"
+ "\x25\x23\x94\xbd\xda\x8d\xb0\xd4",
+ .rlen = 512,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x62\x49\x77\x57\x24\x70\x93\x69"
+ "\x99\x59\x57\x49\x66\x96\x76\x27",
+ .klen = 32,
+ .iv = "\xff\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .ilen = 512,
+ .result = "\x55\xed\x71\xd3\x02\x8e\x15\x3b"
+ "\xc6\x71\x29\x2d\x3e\x89\x9f\x59"
+ "\x68\x6a\xcc\x8a\x56\x97\xf3\x95"
+ "\x4e\x51\x08\xda\x2a\xf8\x6f\x3c"
+ "\x78\x16\xea\x80\xdb\x33\x75\x94"
+ "\xf9\x29\xc4\x2b\x76\x75\x97\xc7"
+ "\xf2\x98\x2c\xf9\xff\xc8\xd5\x2b"
+ "\x18\xf1\xaf\xcf\x7c\xc5\x0b\xee"
+ "\xad\x3c\x76\x7c\xe6\x27\xa2\x2a"
+ "\xe4\x66\xe1\xab\xa2\x39\xfc\x7c"
+ "\xf5\xec\x32\x74\xa3\xb8\x03\x88"
+ "\x52\xfc\x2e\x56\x3f\xa1\xf0\x9f"
+ "\x84\x5e\x46\xed\x20\x89\xb6\x44"
+ "\x8d\xd0\xed\x54\x47\x16\xbe\x95"
+ "\x8a\xb3\x6b\x72\xc4\x32\x52\x13"
+ "\x1b\xb0\x82\xbe\xac\xf9\x70\xa6"
+ "\x44\x18\xdd\x8c\x6e\xca\x6e\x45"
+ "\x8f\x1e\x10\x07\x57\x25\x98\x7b"
+ "\x17\x8c\x78\xdd\x80\xa7\xd9\xd8"
+ "\x63\xaf\xb9\x67\x57\xfd\xbc\xdb"
+ "\x44\xe9\xc5\x65\xd1\xc7\x3b\xff"
+ "\x20\xa0\x80\x1a\xc3\x9a\xad\x5e"
+ "\x5d\x3b\xd3\x07\xd9\xf5\xfd\x3d"
+ "\x4a\x8b\xa8\xd2\x6e\x7a\x51\x65"
+ "\x6c\x8e\x95\xe0\x45\xc9\x5f\x4a"
+ "\x09\x3c\x3d\x71\x7f\x0c\x84\x2a"
+ "\xc8\x48\x52\x1a\xc2\xd5\xd6\x78"
+ "\x92\x1e\xa0\x90\x2e\xea\xf0\xf3"
+ "\xdc\x0f\xb1\xaf\x0d\x9b\x06\x2e"
+ "\x35\x10\x30\x82\x0d\xe7\xc5\x9b"
+ "\xde\x44\x18\xbd\x9f\xd1\x45\xa9"
+ "\x7b\x7a\x4a\xad\x35\x65\x27\xca"
+ "\xb2\xc3\xd4\x9b\x71\x86\x70\xee"
+ "\xf1\x89\x3b\x85\x4b\x5b\xaa\xaf"
+ "\xfc\x42\xc8\x31\x59\xbe\x16\x60"
+ "\x4f\xf9\xfa\x12\xea\xd0\xa7\x14"
+ "\xf0\x7a\xf3\xd5\x8d\xbd\x81\xef"
+ "\x52\x7f\x29\x51\x94\x20\x67\x3c"
+ "\xd1\xaf\x77\x9f\x22\x5a\x4e\x63"
+ "\xe7\xff\x73\x25\xd1\xdd\x96\x8a"
+ "\x98\x52\x6d\xf3\xac\x3e\xf2\x18"
+ "\x6d\xf6\x0a\x29\xa6\x34\x3d\xed"
+ "\xe3\x27\x0d\x9d\x0a\x02\x44\x7e"
+ "\x5a\x7e\x67\x0f\x0a\x9e\xd6\xad"
+ "\x91\xe6\x4d\x81\x8c\x5c\x59\xaa"
+ "\xfb\xeb\x56\x53\xd2\x7d\x4c\x81"
+ "\x65\x53\x0f\x41\x11\xbd\x98\x99"
+ "\xf9\xc6\xfa\x51\x2e\xa3\xdd\x8d"
+ "\x84\x98\xf9\x34\xed\x33\x2a\x1f"
+ "\x82\xed\xc1\x73\x98\xd3\x02\xdc"
+ "\xe6\xc2\x33\x1d\xa2\xb4\xca\x76"
+ "\x63\x51\x34\x9d\x96\x12\xae\xce"
+ "\x83\xc9\x76\x5e\xa4\x1b\x53\x37"
+ "\x17\xd5\xc0\x80\x1d\x62\xf8\x3d"
+ "\x54\x27\x74\xbb\x10\x86\x57\x46"
+ "\x68\xe1\xed\x14\xe7\x9d\xfc\x84"
+ "\x47\xbc\xc2\xf8\x19\x4b\x99\xcf"
+ "\x7a\xe9\xc4\xb8\x8c\x82\x72\x4d"
+ "\x7b\x4f\x38\x55\x36\x71\x64\xc1"
+ "\xfc\x5c\x75\x52\x33\x02\x18\xf8"
+ "\x17\xe1\x2b\xc2\x43\x39\xbd\x76"
+ "\x9b\x63\x76\x32\x2f\x19\x72\x10"
+ "\x9f\x21\x0c\xf1\x66\x50\x7f\xa5"
+ "\x0d\x1f\x46\xe0\xba\xd3\x2f\x3c",
+ .rlen = 512,
+ .also_non_np = 1,
+ .np = 3,
+ .tap = { 512 - 20, 4, 16 },
+ }
+};
+
+static const struct cipher_testvec speck64_xts_dec_tv_template[] = {
+ {
+ .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .klen = 24,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x84\xaf\x54\x07\x19\xd4\x7c\xa6"
+ "\xe4\xfe\xdf\xc4\x1f\x34\xc3\xc2"
+ "\x80\xf5\x72\xe7\xcd\xf0\x99\x22"
+ "\x35\xa7\x2f\x06\xef\xdc\x51\xaa",
+ .ilen = 32,
+ .result = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .rlen = 32,
+ }, {
+ .key = "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x11\x11\x11\x11\x11\x11\x11\x11"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 24,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x12\x56\x73\xcd\x15\x87\xa8\x59"
+ "\xcf\x84\xae\xd9\x1c\x66\xd6\x9f"
+ "\xb3\x12\x69\x7e\x36\xeb\x52\xff"
+ "\x62\xdd\xba\x90\xb3\xe1\xee\x99",
+ .ilen = 32,
+ .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .rlen = 32,
+ }, {
+ .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+ "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+ "\x22\x22\x22\x22\x22\x22\x22\x22",
+ .klen = 24,
+ .iv = "\x33\x33\x33\x33\x33\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x15\x1b\xe4\x2c\xa2\x5a\x2d\x2c"
+ "\x27\x36\xc0\xbf\x5d\xea\x36\x37"
+ "\x2d\x1a\x88\xbc\x66\xb5\xd0\x0b"
+ "\xa1\xbc\x19\xb2\x0f\x3b\x75\x34",
+ .ilen = 32,
+ .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44"
+ "\x44\x44\x44\x44\x44\x44\x44\x44",
+ .rlen = 32,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x31\x41\x59\x26\x53\x58\x97\x93",
+ .klen = 24,
+ .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\xaf\xa1\x81\xa6\x32\xbb\x15\x8e"
+ "\xf8\x95\x2e\xd3\xe6\xee\x7e\x09"
+ "\x0c\x1a\xf5\x02\x97\x8b\xe3\xb3"
+ "\x11\xc7\x39\x96\xd0\x95\xf4\x56"
+ "\xf4\xdd\x03\x38\x01\x44\x2c\xcf"
+ "\x88\xae\x8e\x3c\xcd\xe7\xaa\x66"
+ "\xfe\x3d\xc6\xfb\x01\x23\x51\x43"
+ "\xd5\xd2\x13\x86\x94\x34\xe9\x62"
+ "\xf9\x89\xe3\xd1\x7b\xbe\xf8\xef"
+ "\x76\x35\x04\x3f\xdb\x23\x9d\x0b"
+ "\x85\x42\xb9\x02\xd6\xcc\xdb\x96"
+ "\xa7\x6b\x27\xb6\xd4\x45\x8f\x7d"
+ "\xae\xd2\x04\xd5\xda\xc1\x7e\x24"
+ "\x8c\x73\xbe\x48\x7e\xcf\x65\x28"
+ "\x29\xe5\xbe\x54\x30\xcb\x46\x95"
+ "\x4f\x2e\x8a\x36\xc8\x27\xc5\xbe"
+ "\xd0\x1a\xaf\xab\x26\xcd\x9e\x69"
+ "\xa1\x09\x95\x71\x26\xe9\xc4\xdf"
+ "\xe6\x31\xc3\x46\xda\xaf\x0b\x41"
+ "\x1f\xab\xb1\x8e\xd6\xfc\x0b\xb3"
+ "\x82\xc0\x37\x27\xfc\x91\xa7\x05"
+ "\xfb\xc5\xdc\x2b\x74\x96\x48\x43"
+ "\x5d\x9c\x19\x0f\x60\x63\x3a\x1f"
+ "\x6f\xf0\x03\xbe\x4d\xfd\xc8\x4a"
+ "\xc6\xa4\x81\x6d\xc3\x12\x2a\x5c"
+ "\x07\xff\xf3\x72\x74\x48\xb5\x40"
+ "\x50\xb5\xdd\x90\x43\x31\x18\x15"
+ "\x7b\xf2\xa6\xdb\x83\xc8\x4b\x4a"
+ "\x29\x93\x90\x8b\xda\x07\xf0\x35"
+ "\x6d\x90\x88\x09\x4e\x83\xf5\x5b"
+ "\x94\x12\xbb\x33\x27\x1d\x3f\x23"
+ "\x51\xa8\x7c\x07\xa2\xae\x77\xa6"
+ "\x50\xfd\xcc\xc0\x4f\x80\x7a\x9f"
+ "\x66\xdd\xcd\x75\x24\x8b\x33\xf7"
+ "\x20\xdb\x83\x9b\x4f\x11\x63\x6e"
+ "\xcf\x37\xef\xc9\x11\x01\x5c\x45"
+ "\x32\x99\x7c\x3c\x9e\x42\x89\xe3"
+ "\x70\x6d\x15\x9f\xb1\xe6\xb6\x05"
+ "\xfe\x0c\xb9\x49\x2d\x90\x6d\xcc"
+ "\x5d\x3f\xc1\xfe\x89\x0a\x2e\x2d"
+ "\xa0\xa8\x89\x3b\x73\x39\xa5\x94"
+ "\x4c\xa4\xa6\xbb\xa7\x14\x46\x89"
+ "\x10\xff\xaf\xef\xca\xdd\x4f\x80"
+ "\xb3\xdf\x3b\xab\xd4\xe5\x5a\xc7"
+ "\x33\xca\x00\x8b\x8b\x3f\xea\xec"
+ "\x68\x8a\xc2\x6d\xfd\xd4\x67\x0f"
+ "\x22\x31\xe1\x0e\xfe\x5a\x04\xd5"
+ "\x64\xa3\xf1\x1a\x76\x28\xcc\x35"
+ "\x36\xa7\x0a\x74\xf7\x1c\x44\x9b"
+ "\xc7\x1b\x53\x17\x02\xea\xd1\xad"
+ "\x13\x51\x73\xc0\xa0\xb2\x05\x32"
+ "\xa8\xa2\x37\x2e\xe1\x7a\x3a\x19"
+ "\x26\xb4\x6c\x62\x5d\xb3\x1a\x1d"
+ "\x59\xda\xee\x1a\x22\x18\xda\x0d"
+ "\x88\x0f\x55\x8b\x72\x62\xfd\xc1"
+ "\x69\x13\xcd\x0d\x5f\xc1\x09\x52"
+ "\xee\xd6\xe3\x84\x4d\xee\xf6\x88"
+ "\xaf\x83\xdc\x76\xf4\xc0\x93\x3f"
+ "\x4a\x75\x2f\xb0\x0b\x3e\xc4\x54"
+ "\x7d\x69\x8d\x00\x62\x77\x0d\x14"
+ "\xbe\x7c\xa6\x7d\xc5\x24\x4f\xf3"
+ "\x50\xf7\x5f\xf4\xc2\xca\x41\x97"
+ "\x37\xbe\x75\x74\xcd\xf0\x75\x6e"
+ "\x25\x23\x94\xbd\xda\x8d\xb0\xd4",
+ .ilen = 512,
+ .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .rlen = 512,
+ }, {
+ .key = "\x27\x18\x28\x18\x28\x45\x90\x45"
+ "\x23\x53\x60\x28\x74\x71\x35\x26"
+ "\x62\x49\x77\x57\x24\x70\x93\x69"
+ "\x99\x59\x57\x49\x66\x96\x76\x27",
+ .klen = 32,
+ .iv = "\xff\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ .input = "\x55\xed\x71\xd3\x02\x8e\x15\x3b"
+ "\xc6\x71\x29\x2d\x3e\x89\x9f\x59"
+ "\x68\x6a\xcc\x8a\x56\x97\xf3\x95"
+ "\x4e\x51\x08\xda\x2a\xf8\x6f\x3c"
+ "\x78\x16\xea\x80\xdb\x33\x75\x94"
+ "\xf9\x29\xc4\x2b\x76\x75\x97\xc7"
+ "\xf2\x98\x2c\xf9\xff\xc8\xd5\x2b"
+ "\x18\xf1\xaf\xcf\x7c\xc5\x0b\xee"
+ "\xad\x3c\x76\x7c\xe6\x27\xa2\x2a"
+ "\xe4\x66\xe1\xab\xa2\x39\xfc\x7c"
+ "\xf5\xec\x32\x74\xa3\xb8\x03\x88"
+ "\x52\xfc\x2e\x56\x3f\xa1\xf0\x9f"
+ "\x84\x5e\x46\xed\x20\x89\xb6\x44"
+ "\x8d\xd0\xed\x54\x47\x16\xbe\x95"
+ "\x8a\xb3\x6b\x72\xc4\x32\x52\x13"
+ "\x1b\xb0\x82\xbe\xac\xf9\x70\xa6"
+ "\x44\x18\xdd\x8c\x6e\xca\x6e\x45"
+ "\x8f\x1e\x10\x07\x57\x25\x98\x7b"
+ "\x17\x8c\x78\xdd\x80\xa7\xd9\xd8"
+ "\x63\xaf\xb9\x67\x57\xfd\xbc\xdb"
+ "\x44\xe9\xc5\x65\xd1\xc7\x3b\xff"
+ "\x20\xa0\x80\x1a\xc3\x9a\xad\x5e"
+ "\x5d\x3b\xd3\x07\xd9\xf5\xfd\x3d"
+ "\x4a\x8b\xa8\xd2\x6e\x7a\x51\x65"
+ "\x6c\x8e\x95\xe0\x45\xc9\x5f\x4a"
+ "\x09\x3c\x3d\x71\x7f\x0c\x84\x2a"
+ "\xc8\x48\x52\x1a\xc2\xd5\xd6\x78"
+ "\x92\x1e\xa0\x90\x2e\xea\xf0\xf3"
+ "\xdc\x0f\xb1\xaf\x0d\x9b\x06\x2e"
+ "\x35\x10\x30\x82\x0d\xe7\xc5\x9b"
+ "\xde\x44\x18\xbd\x9f\xd1\x45\xa9"
+ "\x7b\x7a\x4a\xad\x35\x65\x27\xca"
+ "\xb2\xc3\xd4\x9b\x71\x86\x70\xee"
+ "\xf1\x89\x3b\x85\x4b\x5b\xaa\xaf"
+ "\xfc\x42\xc8\x31\x59\xbe\x16\x60"
+ "\x4f\xf9\xfa\x12\xea\xd0\xa7\x14"
+ "\xf0\x7a\xf3\xd5\x8d\xbd\x81\xef"
+ "\x52\x7f\x29\x51\x94\x20\x67\x3c"
+ "\xd1\xaf\x77\x9f\x22\x5a\x4e\x63"
+ "\xe7\xff\x73\x25\xd1\xdd\x96\x8a"
+ "\x98\x52\x6d\xf3\xac\x3e\xf2\x18"
+ "\x6d\xf6\x0a\x29\xa6\x34\x3d\xed"
+ "\xe3\x27\x0d\x9d\x0a\x02\x44\x7e"
+ "\x5a\x7e\x67\x0f\x0a\x9e\xd6\xad"
+ "\x91\xe6\x4d\x81\x8c\x5c\x59\xaa"
+ "\xfb\xeb\x56\x53\xd2\x7d\x4c\x81"
+ "\x65\x53\x0f\x41\x11\xbd\x98\x99"
+ "\xf9\xc6\xfa\x51\x2e\xa3\xdd\x8d"
+ "\x84\x98\xf9\x34\xed\x33\x2a\x1f"
+ "\x82\xed\xc1\x73\x98\xd3\x02\xdc"
+ "\xe6\xc2\x33\x1d\xa2\xb4\xca\x76"
+ "\x63\x51\x34\x9d\x96\x12\xae\xce"
+ "\x83\xc9\x76\x5e\xa4\x1b\x53\x37"
+ "\x17\xd5\xc0\x80\x1d\x62\xf8\x3d"
+ "\x54\x27\x74\xbb\x10\x86\x57\x46"
+ "\x68\xe1\xed\x14\xe7\x9d\xfc\x84"
+ "\x47\xbc\xc2\xf8\x19\x4b\x99\xcf"
+ "\x7a\xe9\xc4\xb8\x8c\x82\x72\x4d"
+ "\x7b\x4f\x38\x55\x36\x71\x64\xc1"
+ "\xfc\x5c\x75\x52\x33\x02\x18\xf8"
+ "\x17\xe1\x2b\xc2\x43\x39\xbd\x76"
+ "\x9b\x63\x76\x32\x2f\x19\x72\x10"
+ "\x9f\x21\x0c\xf1\x66\x50\x7f\xa5"
+ "\x0d\x1f\x46\xe0\xba\xd3\x2f\x3c",
+ .ilen = 512,
+ .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+ "\x00\x01\x02\x03\x04\x05\x06\x07"
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17"
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27"
+ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47"
+ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57"
+ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67"
+ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77"
+ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ .rlen = 512,
+ .also_non_np = 1,
+ .np = 3,
+ .tap = { 512 - 20, 4, 16 },
+ }
+};
+
/* Cast6 test vectors from RFC 2612 */
static const struct cipher_testvec cast6_enc_tv_template[] = {
{
diff --git a/crypto/xts.c b/crypto/xts.c
index f317c48b5e43..12284183bd20 100644
--- a/crypto/xts.c
+++ b/crypto/xts.c
@@ -357,78 +357,6 @@ static int decrypt(struct skcipher_request *req)
return do_decrypt(req, init_crypt(req, decrypt_done));
}
-int xts_crypt(struct blkcipher_desc *desc, struct scatterlist *sdst,
- struct scatterlist *ssrc, unsigned int nbytes,
- struct xts_crypt_req *req)
-{
- const unsigned int bsize = XTS_BLOCK_SIZE;
- const unsigned int max_blks = req->tbuflen / bsize;
- struct blkcipher_walk walk;
- unsigned int nblocks;
- le128 *src, *dst, *t;
- le128 *t_buf = req->tbuf;
- int err, i;
-
- BUG_ON(max_blks < 1);
-
- blkcipher_walk_init(&walk, sdst, ssrc, nbytes);
-
- err = blkcipher_walk_virt(desc, &walk);
- nbytes = walk.nbytes;
- if (!nbytes)
- return err;
-
- nblocks = min(nbytes / bsize, max_blks);
- src = (le128 *)walk.src.virt.addr;
- dst = (le128 *)walk.dst.virt.addr;
-
- /* calculate first value of T */
- req->tweak_fn(req->tweak_ctx, (u8 *)&t_buf[0], walk.iv);
-
- i = 0;
- goto first;
-
- for (;;) {
- do {
- for (i = 0; i < nblocks; i++) {
- gf128mul_x_ble(&t_buf[i], t);
-first:
- t = &t_buf[i];
-
- /* PP <- T xor P */
- le128_xor(dst + i, t, src + i);
- }
-
- /* CC <- E(Key2,PP) */
- req->crypt_fn(req->crypt_ctx, (u8 *)dst,
- nblocks * bsize);
-
- /* C <- T xor CC */
- for (i = 0; i < nblocks; i++)
- le128_xor(dst + i, dst + i, &t_buf[i]);
-
- src += nblocks;
- dst += nblocks;
- nbytes -= nblocks * bsize;
- nblocks = min(nbytes / bsize, max_blks);
- } while (nblocks > 0);
-
- *(le128 *)walk.iv = *t;
-
- err = blkcipher_walk_done(desc, &walk, nbytes);
- nbytes = walk.nbytes;
- if (!nbytes)
- break;
-
- nblocks = min(nbytes / bsize, max_blks);
- src = (le128 *)walk.src.virt.addr;
- dst = (le128 *)walk.dst.virt.addr;
- }
-
- return err;
-}
-EXPORT_SYMBOL_GPL(xts_crypt);
-
static int init_tfm(struct crypto_skcipher *tfm)
{
struct skcipher_instance *inst = skcipher_alg_instance(tfm);
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 879dc0604cba..95b9ccc08165 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -199,9 +199,7 @@ source "drivers/dax/Kconfig"
source "drivers/nvmem/Kconfig"
-source "drivers/hwtracing/stm/Kconfig"
-
-source "drivers/hwtracing/intel_th/Kconfig"
+source "drivers/hwtracing/Kconfig"
source "drivers/fpga/Kconfig"
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 95255ecfae7c..9e702bc4960f 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -31,11 +31,6 @@
#define IORT_IOMMU_TYPE ((1 << ACPI_IORT_NODE_SMMU) | \
(1 << ACPI_IORT_NODE_SMMU_V3))
-/* Until ACPICA headers cover IORT rev. C */
-#ifndef ACPI_IORT_SMMU_V3_CAVIUM_CN99XX
-#define ACPI_IORT_SMMU_V3_CAVIUM_CN99XX 0x2
-#endif
-
struct iort_its_msi_chip {
struct list_head list;
struct fwnode_handle *fw_node;
@@ -366,7 +361,6 @@ static struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
return NULL;
}
-#if (ACPI_CA_VERSION > 0x20170929)
static int iort_get_id_mapping_index(struct acpi_iort_node *node)
{
struct acpi_iort_smmu_v3 *smmu;
@@ -400,12 +394,6 @@ static int iort_get_id_mapping_index(struct acpi_iort_node *node)
return -EINVAL;
}
}
-#else
-static inline int iort_get_id_mapping_index(struct acpi_iort_node *node)
-{
- return -EINVAL;
-}
-#endif
static struct acpi_iort_node *iort_node_map_id(struct acpi_iort_node *node,
u32 id_in, u32 *id_out,
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 4582fa27cf37..2b16e7c8fff3 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -211,10 +211,10 @@ config AHCI_SUNXI
If unsure, say N.
config AHCI_TEGRA
- tristate "NVIDIA Tegra124 AHCI SATA support"
+ tristate "NVIDIA Tegra AHCI SATA support"
depends on ARCH_TEGRA
help
- This option enables support for the NVIDIA Tegra124 SoC's
+ This option enables support for the NVIDIA Tegra SoC's
onboard AHCI SATA.
If unsure, say N.
@@ -954,6 +954,18 @@ config PATA_FALCON
If unsure, say N.
+config PATA_GAYLE
+ tristate "Amiga Gayle PATA support"
+ depends on M68K && AMIGA
+ help
+ This option enables support for the on-board IDE
+ interfaces on some Amiga models (A600, A1200,
+ A4000 and A4000T) and also for IDE interfaces on
+ the Zorro expansion bus (M-Tech E-Matrix 530
+ expansion card).
+
+ If unsure, say N.
+
config PATA_ISAPNP
tristate "ISA Plug and Play PATA support"
depends on ISAPNP
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 6dae8c985e8e..d21cdd83f7ab 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -97,6 +97,7 @@ obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o
# SFF PIO only
obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o
obj-$(CONFIG_PATA_FALCON) += pata_falcon.o
+obj-$(CONFIG_PATA_GAYLE) += pata_gayle.o
obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o
obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index a9d996e17d75..4356ef1d28a8 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -350,6 +350,7 @@ struct ahci_host_priv {
u32 em_msg_type; /* EM message type */
bool got_runtime_pm; /* Did we do pm_runtime_get? */
struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
+ struct reset_control *rsts; /* Optional */
struct regulator **target_pwrs; /* Optional */
/*
* If platform uses PHYs. There is a 1:1 relation between the port number and
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index a58bcc069c54..6822e2f33f7e 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -23,6 +23,7 @@
#include <linux/regmap.h>
#include <linux/ahci_platform.h>
#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/libata.h>
@@ -53,11 +54,49 @@ enum {
/* Clock Reset Register */
IMX_CLOCK_RESET = 0x7f3f,
IMX_CLOCK_RESET_RESET = 1 << 0,
+ /* IMX8QM HSIO AHCI definitions */
+ IMX8QM_SATA_PHY_RX_IMPED_RATIO_OFFSET = 0x03,
+ IMX8QM_SATA_PHY_TX_IMPED_RATIO_OFFSET = 0x09,
+ IMX8QM_SATA_PHY_IMPED_RATIO_85OHM = 0x6c,
+ IMX8QM_LPCG_PHYX2_OFFSET = 0x00000,
+ IMX8QM_CSR_PHYX2_OFFSET = 0x90000,
+ IMX8QM_CSR_PHYX1_OFFSET = 0xa0000,
+ IMX8QM_CSR_PHYX_STTS0_OFFSET = 0x4,
+ IMX8QM_CSR_PCIEA_OFFSET = 0xb0000,
+ IMX8QM_CSR_PCIEB_OFFSET = 0xc0000,
+ IMX8QM_CSR_SATA_OFFSET = 0xd0000,
+ IMX8QM_CSR_PCIE_CTRL2_OFFSET = 0x8,
+ IMX8QM_CSR_MISC_OFFSET = 0xe0000,
+
+ IMX8QM_LPCG_PHYX2_PCLK0_MASK = (0x3 << 16),
+ IMX8QM_LPCG_PHYX2_PCLK1_MASK = (0x3 << 20),
+ IMX8QM_PHY_APB_RSTN_0 = BIT(0),
+ IMX8QM_PHY_MODE_SATA = BIT(19),
+ IMX8QM_PHY_MODE_MASK = (0xf << 17),
+ IMX8QM_PHY_PIPE_RSTN_0 = BIT(24),
+ IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0 = BIT(25),
+ IMX8QM_PHY_PIPE_RSTN_1 = BIT(26),
+ IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1 = BIT(27),
+ IMX8QM_STTS0_LANE0_TX_PLL_LOCK = BIT(4),
+ IMX8QM_MISC_IOB_RXENA = BIT(0),
+ IMX8QM_MISC_IOB_TXENA = BIT(1),
+ IMX8QM_MISC_PHYX1_EPCS_SEL = BIT(12),
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 = BIT(24),
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 = BIT(25),
+ IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 = BIT(28),
+ IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0 = BIT(29),
+ IMX8QM_SATA_CTRL_RESET_N = BIT(12),
+ IMX8QM_SATA_CTRL_EPCS_PHYRESET_N = BIT(7),
+ IMX8QM_CTRL_BUTTON_RST_N = BIT(21),
+ IMX8QM_CTRL_POWER_UP_RST_N = BIT(23),
+ IMX8QM_CTRL_LTSSM_ENABLE = BIT(4),
};
enum ahci_imx_type {
AHCI_IMX53,
AHCI_IMX6Q,
+ AHCI_IMX6QP,
+ AHCI_IMX8QM,
};
struct imx_ahci_priv {
@@ -66,10 +105,18 @@ struct imx_ahci_priv {
struct clk *sata_clk;
struct clk *sata_ref_clk;
struct clk *ahb_clk;
+ struct clk *epcs_tx_clk;
+ struct clk *epcs_rx_clk;
+ struct clk *phy_apbclk;
+ struct clk *phy_pclk0;
+ struct clk *phy_pclk1;
+ void __iomem *phy_base;
+ int clkreq_gpio;
struct regmap *gpr;
bool no_device;
bool first_time;
u32 phy_params;
+ u32 imped_ratio;
};
static int ahci_imx_hotplug;
@@ -188,11 +235,26 @@ static int imx_phy_reg_read(u16 *val, void __iomem *mmio)
static int imx_sata_phy_reset(struct ahci_host_priv *hpriv)
{
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
void __iomem *mmio = hpriv->mmio;
int timeout = 10;
u16 val;
int ret;
+ if (imxpriv->type == AHCI_IMX6QP) {
+ /* 6qp adds the sata reset mechanism, use it for 6qp sata */
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5,
+ IMX6Q_GPR5_SATA_SW_PD, 0);
+
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5,
+ IMX6Q_GPR5_SATA_SW_RST, 0);
+ udelay(50);
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5,
+ IMX6Q_GPR5_SATA_SW_RST,
+ IMX6Q_GPR5_SATA_SW_RST);
+ return 0;
+ }
+
/* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */
ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio);
if (ret)
@@ -391,6 +453,207 @@ static struct attribute *fsl_sata_ahci_attrs[] = {
};
ATTRIBUTE_GROUPS(fsl_sata_ahci);
+static int imx8_sata_enable(struct ahci_host_priv *hpriv)
+{
+ u32 val, reg;
+ int i, ret;
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+ struct device *dev = &imxpriv->ahci_pdev->dev;
+
+ /* configure the hsio for sata */
+ ret = clk_prepare_enable(imxpriv->phy_pclk0);
+ if (ret < 0) {
+ dev_err(dev, "can't enable phy_pclk0.\n");
+ return ret;
+ }
+ ret = clk_prepare_enable(imxpriv->phy_pclk1);
+ if (ret < 0) {
+ dev_err(dev, "can't enable phy_pclk1.\n");
+ goto disable_phy_pclk0;
+ }
+ ret = clk_prepare_enable(imxpriv->epcs_tx_clk);
+ if (ret < 0) {
+ dev_err(dev, "can't enable epcs_tx_clk.\n");
+ goto disable_phy_pclk1;
+ }
+ ret = clk_prepare_enable(imxpriv->epcs_rx_clk);
+ if (ret < 0) {
+ dev_err(dev, "can't enable epcs_rx_clk.\n");
+ goto disable_epcs_tx_clk;
+ }
+ ret = clk_prepare_enable(imxpriv->phy_apbclk);
+ if (ret < 0) {
+ dev_err(dev, "can't enable phy_apbclk.\n");
+ goto disable_epcs_rx_clk;
+ }
+ /* Configure PHYx2 PIPE_RSTN */
+ regmap_read(imxpriv->gpr, IMX8QM_CSR_PCIEA_OFFSET +
+ IMX8QM_CSR_PCIE_CTRL2_OFFSET, &val);
+ if ((val & IMX8QM_CTRL_LTSSM_ENABLE) == 0) {
+ /* The link of the PCIEA of HSIO is down */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_PHYX2_OFFSET,
+ IMX8QM_PHY_PIPE_RSTN_0 |
+ IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0,
+ IMX8QM_PHY_PIPE_RSTN_0 |
+ IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0);
+ }
+ regmap_read(imxpriv->gpr, IMX8QM_CSR_PCIEB_OFFSET +
+ IMX8QM_CSR_PCIE_CTRL2_OFFSET, &reg);
+ if ((reg & IMX8QM_CTRL_LTSSM_ENABLE) == 0) {
+ /* The link of the PCIEB of HSIO is down */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_PHYX2_OFFSET,
+ IMX8QM_PHY_PIPE_RSTN_1 |
+ IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1,
+ IMX8QM_PHY_PIPE_RSTN_1 |
+ IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1);
+ }
+ if (((reg | val) & IMX8QM_CTRL_LTSSM_ENABLE) == 0) {
+ /* The links of both PCIA and PCIEB of HSIO are down */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_LPCG_PHYX2_OFFSET,
+ IMX8QM_LPCG_PHYX2_PCLK0_MASK |
+ IMX8QM_LPCG_PHYX2_PCLK1_MASK,
+ 0);
+ }
+
+ /* set PWR_RST and BT_RST of csr_pciea */
+ val = IMX8QM_CSR_PCIEA_OFFSET + IMX8QM_CSR_PCIE_CTRL2_OFFSET;
+ regmap_update_bits(imxpriv->gpr,
+ val,
+ IMX8QM_CTRL_BUTTON_RST_N,
+ IMX8QM_CTRL_BUTTON_RST_N);
+ regmap_update_bits(imxpriv->gpr,
+ val,
+ IMX8QM_CTRL_POWER_UP_RST_N,
+ IMX8QM_CTRL_POWER_UP_RST_N);
+
+ /* PHYX1_MODE to SATA */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_PHYX1_OFFSET,
+ IMX8QM_PHY_MODE_MASK,
+ IMX8QM_PHY_MODE_SATA);
+
+ /*
+ * BIT0 RXENA 1, BIT1 TXENA 0
+ * BIT12 PHY_X1_EPCS_SEL 1.
+ */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_IOB_RXENA,
+ IMX8QM_MISC_IOB_RXENA);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_IOB_TXENA,
+ 0);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_PHYX1_EPCS_SEL,
+ IMX8QM_MISC_PHYX1_EPCS_SEL);
+ /*
+ * It is possible, for PCIe and SATA are sharing
+ * the same clock source, HPLL or external oscillator.
+ * When PCIe is in low power modes (L1.X or L2 etc),
+ * the clock source can be turned off. In this case,
+ * if this clock source is required to be toggling by
+ * SATA, then SATA functions will be abnormal.
+ * Set the override here to avoid it.
+ */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 |
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 |
+ IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 |
+ IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0,
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 |
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 |
+ IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 |
+ IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0);
+
+ /* clear PHY RST, then set it */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_EPCS_PHYRESET_N,
+ 0);
+
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_EPCS_PHYRESET_N,
+ IMX8QM_SATA_CTRL_EPCS_PHYRESET_N);
+
+ /* CTRL RST: SET -> delay 1 us -> CLEAR -> SET */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_RESET_N,
+ IMX8QM_SATA_CTRL_RESET_N);
+ udelay(1);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_RESET_N,
+ 0);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_RESET_N,
+ IMX8QM_SATA_CTRL_RESET_N);
+
+ /* APB reset */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_PHYX1_OFFSET,
+ IMX8QM_PHY_APB_RSTN_0,
+ IMX8QM_PHY_APB_RSTN_0);
+
+ for (i = 0; i < 100; i++) {
+ reg = IMX8QM_CSR_PHYX1_OFFSET +
+ IMX8QM_CSR_PHYX_STTS0_OFFSET;
+ regmap_read(imxpriv->gpr, reg, &val);
+ val &= IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
+ if (val == IMX8QM_STTS0_LANE0_TX_PLL_LOCK)
+ break;
+ udelay(1);
+ }
+
+ if (val != IMX8QM_STTS0_LANE0_TX_PLL_LOCK) {
+ dev_err(dev, "TX PLL of the PHY is not locked\n");
+ ret = -ENODEV;
+ } else {
+ writeb(imxpriv->imped_ratio, imxpriv->phy_base +
+ IMX8QM_SATA_PHY_RX_IMPED_RATIO_OFFSET);
+ writeb(imxpriv->imped_ratio, imxpriv->phy_base +
+ IMX8QM_SATA_PHY_TX_IMPED_RATIO_OFFSET);
+ reg = readb(imxpriv->phy_base +
+ IMX8QM_SATA_PHY_RX_IMPED_RATIO_OFFSET);
+ if (unlikely(reg != imxpriv->imped_ratio))
+ dev_info(dev, "Can't set PHY RX impedance ratio.\n");
+ reg = readb(imxpriv->phy_base +
+ IMX8QM_SATA_PHY_TX_IMPED_RATIO_OFFSET);
+ if (unlikely(reg != imxpriv->imped_ratio))
+ dev_info(dev, "Can't set PHY TX impedance ratio.\n");
+ usleep_range(50, 100);
+
+ /*
+ * To reduce the power consumption, gate off
+ * the PHY clks
+ */
+ clk_disable_unprepare(imxpriv->phy_apbclk);
+ clk_disable_unprepare(imxpriv->phy_pclk1);
+ clk_disable_unprepare(imxpriv->phy_pclk0);
+ return ret;
+ }
+
+ clk_disable_unprepare(imxpriv->phy_apbclk);
+disable_epcs_rx_clk:
+ clk_disable_unprepare(imxpriv->epcs_rx_clk);
+disable_epcs_tx_clk:
+ clk_disable_unprepare(imxpriv->epcs_tx_clk);
+disable_phy_pclk1:
+ clk_disable_unprepare(imxpriv->phy_pclk1);
+disable_phy_pclk0:
+ clk_disable_unprepare(imxpriv->phy_pclk0);
+
+ return ret;
+}
+
static int imx_sata_enable(struct ahci_host_priv *hpriv)
{
struct imx_ahci_priv *imxpriv = hpriv->plat_data;
@@ -408,7 +671,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
if (ret < 0)
goto disable_regulator;
- if (imxpriv->type == AHCI_IMX6Q) {
+ if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) {
/*
* set PHY Paremeters, two steps to configure the GPR13,
* one write for rest of parameters, mask of first write
@@ -438,6 +701,8 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
dev_err(dev, "failed to reset phy: %d\n", ret);
goto disable_clk;
}
+ } else if (imxpriv->type == AHCI_IMX8QM) {
+ ret = imx8_sata_enable(hpriv);
}
usleep_range(1000, 2000);
@@ -459,10 +724,29 @@ static void imx_sata_disable(struct ahci_host_priv *hpriv)
if (imxpriv->no_device)
return;
- if (imxpriv->type == AHCI_IMX6Q) {
+ switch (imxpriv->type) {
+ case AHCI_IMX6QP:
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5,
+ IMX6Q_GPR5_SATA_SW_PD,
+ IMX6Q_GPR5_SATA_SW_PD);
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
IMX6Q_GPR13_SATA_MPLL_CLK_EN,
!IMX6Q_GPR13_SATA_MPLL_CLK_EN);
+ break;
+
+ case AHCI_IMX6Q:
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN,
+ !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
+ break;
+
+ case AHCI_IMX8QM:
+ clk_disable_unprepare(imxpriv->epcs_rx_clk);
+ clk_disable_unprepare(imxpriv->epcs_tx_clk);
+ break;
+
+ default:
+ break;
}
clk_disable_unprepare(imxpriv->sata_ref_clk);
@@ -513,7 +797,7 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
if (imxpriv->type == AHCI_IMX53)
ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline);
- else if (imxpriv->type == AHCI_IMX6Q)
+ else
ret = ahci_ops.softreset(link, class, deadline);
return ret;
@@ -536,6 +820,8 @@ static const struct ata_port_info ahci_imx_port_info = {
static const struct of_device_id imx_ahci_of_match[] = {
{ .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 },
{ .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q },
+ { .compatible = "fsl,imx6qp-ahci", .data = (void *)AHCI_IMX6QP },
+ { .compatible = "fsl,imx8qm-ahci", .data = (void *)AHCI_IMX8QM },
{},
};
MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
@@ -703,6 +989,79 @@ static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT(DRV_NAME),
};
+static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv)
+{
+ int ret;
+ struct resource *phy_res;
+ struct platform_device *pdev = imxpriv->ahci_pdev;
+ struct device_node *np = dev->of_node;
+
+ if (of_property_read_u32(np, "fsl,phy-imp", &imxpriv->imped_ratio))
+ imxpriv->imped_ratio = IMX8QM_SATA_PHY_IMPED_RATIO_85OHM;
+ phy_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
+ if (phy_res) {
+ imxpriv->phy_base = devm_ioremap(dev, phy_res->start,
+ resource_size(phy_res));
+ if (!imxpriv->phy_base) {
+ dev_err(dev, "error with ioremap\n");
+ return -ENOMEM;
+ }
+ } else {
+ dev_err(dev, "missing *phy* reg region.\n");
+ return -ENOMEM;
+ }
+ imxpriv->gpr =
+ syscon_regmap_lookup_by_phandle(np, "hsio");
+ if (IS_ERR(imxpriv->gpr)) {
+ dev_err(dev, "unable to find gpr registers\n");
+ return PTR_ERR(imxpriv->gpr);
+ }
+
+ imxpriv->epcs_tx_clk = devm_clk_get(dev, "epcs_tx");
+ if (IS_ERR(imxpriv->epcs_tx_clk)) {
+ dev_err(dev, "can't get epcs_tx_clk clock.\n");
+ return PTR_ERR(imxpriv->epcs_tx_clk);
+ }
+ imxpriv->epcs_rx_clk = devm_clk_get(dev, "epcs_rx");
+ if (IS_ERR(imxpriv->epcs_rx_clk)) {
+ dev_err(dev, "can't get epcs_rx_clk clock.\n");
+ return PTR_ERR(imxpriv->epcs_rx_clk);
+ }
+ imxpriv->phy_pclk0 = devm_clk_get(dev, "phy_pclk0");
+ if (IS_ERR(imxpriv->phy_pclk0)) {
+ dev_err(dev, "can't get phy_pclk0 clock.\n");
+ return PTR_ERR(imxpriv->phy_pclk0);
+ }
+ imxpriv->phy_pclk1 = devm_clk_get(dev, "phy_pclk1");
+ if (IS_ERR(imxpriv->phy_pclk1)) {
+ dev_err(dev, "can't get phy_pclk1 clock.\n");
+ return PTR_ERR(imxpriv->phy_pclk1);
+ }
+ imxpriv->phy_apbclk = devm_clk_get(dev, "phy_apbclk");
+ if (IS_ERR(imxpriv->phy_apbclk)) {
+ dev_err(dev, "can't get phy_apbclk clock.\n");
+ return PTR_ERR(imxpriv->phy_apbclk);
+ }
+
+ /* Fetch GPIO, then enable the external OSC */
+ imxpriv->clkreq_gpio = of_get_named_gpio(np, "clkreq-gpio", 0);
+ if (gpio_is_valid(imxpriv->clkreq_gpio)) {
+ ret = devm_gpio_request_one(dev, imxpriv->clkreq_gpio,
+ GPIOF_OUT_INIT_LOW,
+ "SATA CLKREQ");
+ if (ret == -EBUSY) {
+ dev_info(dev, "clkreq had been initialized.\n");
+ } else if (ret) {
+ dev_err(dev, "%d unable to get clkreq.\n", ret);
+ return ret;
+ }
+ } else if (imxpriv->clkreq_gpio == -EPROBE_DEFER) {
+ return imxpriv->clkreq_gpio;
+ }
+
+ return 0;
+}
+
static int imx_ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -743,7 +1102,7 @@ static int imx_ahci_probe(struct platform_device *pdev)
return PTR_ERR(imxpriv->ahb_clk);
}
- if (imxpriv->type == AHCI_IMX6Q) {
+ if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) {
u32 reg_value;
imxpriv->gpr = syscon_regmap_lookup_by_compatible(
@@ -762,6 +1121,10 @@ static int imx_ahci_probe(struct platform_device *pdev)
IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
reg_value;
+ } else if (imxpriv->type == AHCI_IMX8QM) {
+ ret = imx8_sata_probe(dev, imxpriv);
+ if (ret)
+ return ret;
}
hpriv = ahci_platform_get_resources(pdev);
diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c
index 3a62eb246d80..64d848409fe2 100644
--- a/drivers/ata/ahci_tegra.c
+++ b/drivers/ata/ahci_tegra.c
@@ -34,7 +34,8 @@
#define DRV_NAME "tegra-ahci"
#define SATA_CONFIGURATION_0 0x180
-#define SATA_CONFIGURATION_EN_FPCI BIT(0)
+#define SATA_CONFIGURATION_0_EN_FPCI BIT(0)
+#define SATA_CONFIGURATION_0_CLK_OVERRIDE BIT(31)
#define SCFG_OFFSET 0x1000
@@ -45,17 +46,55 @@
#define T_SATA0_CFG_1_SERR BIT(8)
#define T_SATA0_CFG_9 0x24
-#define T_SATA0_CFG_9_BASE_ADDRESS_SHIFT 13
+#define T_SATA0_CFG_9_BASE_ADDRESS 0x40020000
#define SATA_FPCI_BAR5 0x94
-#define SATA_FPCI_BAR5_START_SHIFT 4
+#define SATA_FPCI_BAR5_START_MASK (0xfffffff << 4)
+#define SATA_FPCI_BAR5_START (0x0040020 << 4)
+#define SATA_FPCI_BAR5_ACCESS_TYPE (0x1)
#define SATA_INTR_MASK 0x188
#define SATA_INTR_MASK_IP_INT_MASK BIT(16)
+#define T_SATA0_CFG_35 0x94
+#define T_SATA0_CFG_35_IDP_INDEX_MASK (0x7ff << 2)
+#define T_SATA0_CFG_35_IDP_INDEX (0x2a << 2)
+
+#define T_SATA0_AHCI_IDP1 0x98
+#define T_SATA0_AHCI_IDP1_DATA (0x400040)
+
+#define T_SATA0_CFG_PHY_1 0x12c
+#define T_SATA0_CFG_PHY_1_PADS_IDDQ_EN BIT(23)
+#define T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN BIT(22)
+
+#define T_SATA0_NVOOB 0x114
+#define T_SATA0_NVOOB_COMMA_CNT_MASK (0xff << 16)
+#define T_SATA0_NVOOB_COMMA_CNT (0x07 << 16)
+#define T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK (0x3 << 24)
+#define T_SATA0_NVOOB_SQUELCH_FILTER_MODE (0x1 << 24)
+#define T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK (0x3 << 26)
+#define T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH (0x3 << 26)
+
+#define T_SATA_CFG_PHY_0 0x120
+#define T_SATA_CFG_PHY_0_USE_7BIT_ALIGN_DET_FOR_SPD BIT(11)
+#define T_SATA_CFG_PHY_0_MASK_SQUELCH BIT(24)
+
+#define T_SATA0_CFG2NVOOB_2 0x134
+#define T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK (0x1ff << 18)
+#define T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW (0xc << 18)
+
#define T_SATA0_AHCI_HBA_CAP_BKDR 0x300
+#define T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP BIT(13)
+#define T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP BIT(14)
+#define T_SATA0_AHCI_HBA_CAP_BKDR_SALP BIT(26)
+#define T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM BIT(17)
+#define T_SATA0_AHCI_HBA_CAP_BKDR_SNCQ BIT(30)
#define T_SATA0_BKDOOR_CC 0x4a4
+#define T_SATA0_BKDOOR_CC_CLASS_CODE_MASK (0xffff << 16)
+#define T_SATA0_BKDOOR_CC_CLASS_CODE (0x0106 << 16)
+#define T_SATA0_BKDOOR_CC_PROG_IF_MASK (0xff << 8)
+#define T_SATA0_BKDOOR_CC_PROG_IF (0x01 << 8)
#define T_SATA0_CFG_SATA 0x54c
#define T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN BIT(12)
@@ -82,6 +121,27 @@
#define T_SATA0_CHX_PHY_CTRL11 0x6d0
#define T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ (0x2800 << 16)
+#define T_SATA0_CHX_PHY_CTRL17_0 0x6e8
+#define T_SATA0_CHX_PHY_CTRL17_0_RX_EQ_CTRL_L_GEN1 0x55010000
+#define T_SATA0_CHX_PHY_CTRL18_0 0x6ec
+#define T_SATA0_CHX_PHY_CTRL18_0_RX_EQ_CTRL_L_GEN2 0x55010000
+#define T_SATA0_CHX_PHY_CTRL20_0 0x6f4
+#define T_SATA0_CHX_PHY_CTRL20_0_RX_EQ_CTRL_H_GEN1 0x1
+#define T_SATA0_CHX_PHY_CTRL21_0 0x6f8
+#define T_SATA0_CHX_PHY_CTRL21_0_RX_EQ_CTRL_H_GEN2 0x1
+
+/* AUX Registers */
+#define SATA_AUX_MISC_CNTL_1_0 0x8
+#define SATA_AUX_MISC_CNTL_1_0_DEVSLP_OVERRIDE BIT(17)
+#define SATA_AUX_MISC_CNTL_1_0_SDS_SUPPORT BIT(13)
+#define SATA_AUX_MISC_CNTL_1_0_DESO_SUPPORT BIT(15)
+
+#define SATA_AUX_RX_STAT_INT_0 0xc
+#define SATA_AUX_RX_STAT_INT_0_SATA_DEVSLP BIT(7)
+
+#define SATA_AUX_SPARE_CFG0_0 0x18
+#define SATA_AUX_SPARE_CFG0_0_MDAT_TIMER_AFTER_PG_VALID BIT(14)
+
#define FUSE_SATA_CALIB 0x124
#define FUSE_SATA_CALIB_MASK 0x3
@@ -99,23 +159,92 @@ static const struct sata_pad_calibration tegra124_pad_calibration[] = {
{0x14, 0x0e, 0x1a, 0x0e},
};
+struct tegra_ahci_ops {
+ int (*init)(struct ahci_host_priv *hpriv);
+};
+
+struct tegra_ahci_soc {
+ const char *const *supply_names;
+ u32 num_supplies;
+ bool supports_devslp;
+ const struct tegra_ahci_ops *ops;
+};
+
struct tegra_ahci_priv {
struct platform_device *pdev;
void __iomem *sata_regs;
+ void __iomem *sata_aux_regs;
struct reset_control *sata_rst;
struct reset_control *sata_oob_rst;
struct reset_control *sata_cold_rst;
/* Needs special handling, cannot use ahci_platform */
struct clk *sata_clk;
- struct regulator_bulk_data supplies[5];
+ struct regulator_bulk_data *supplies;
+ const struct tegra_ahci_soc *soc;
};
+static void tegra_ahci_handle_quirks(struct ahci_host_priv *hpriv)
+{
+ struct tegra_ahci_priv *tegra = hpriv->plat_data;
+ u32 val;
+
+ if (tegra->sata_aux_regs && !tegra->soc->supports_devslp) {
+ val = readl(tegra->sata_aux_regs + SATA_AUX_MISC_CNTL_1_0);
+ val &= ~SATA_AUX_MISC_CNTL_1_0_SDS_SUPPORT;
+ writel(val, tegra->sata_aux_regs + SATA_AUX_MISC_CNTL_1_0);
+ }
+}
+
+static int tegra124_ahci_init(struct ahci_host_priv *hpriv)
+{
+ struct tegra_ahci_priv *tegra = hpriv->plat_data;
+ struct sata_pad_calibration calib;
+ int ret;
+ u32 val;
+
+ /* Pad calibration */
+ ret = tegra_fuse_readl(FUSE_SATA_CALIB, &val);
+ if (ret)
+ return ret;
+
+ calib = tegra124_pad_calibration[val & FUSE_SATA_CALIB_MASK];
+
+ writel(BIT(0), tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
+
+ val = readl(tegra->sata_regs +
+ SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1);
+ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK;
+ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK;
+ val |= calib.gen1_tx_amp << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
+ val |= calib.gen1_tx_peak << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
+ writel(val, tegra->sata_regs + SCFG_OFFSET +
+ T_SATA0_CHX_PHY_CTRL1_GEN1);
+
+ val = readl(tegra->sata_regs +
+ SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2);
+ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK;
+ val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK;
+ val |= calib.gen2_tx_amp << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
+ val |= calib.gen2_tx_peak << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
+ writel(val, tegra->sata_regs + SCFG_OFFSET +
+ T_SATA0_CHX_PHY_CTRL1_GEN2);
+
+ writel(T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ,
+ tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL11);
+ writel(T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1,
+ tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL2);
+
+ writel(0, tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
+
+ return 0;
+}
+
static int tegra_ahci_power_on(struct ahci_host_priv *hpriv)
{
struct tegra_ahci_priv *tegra = hpriv->plat_data;
int ret;
- ret = regulator_bulk_enable(ARRAY_SIZE(tegra->supplies),
+ ret = regulator_bulk_enable(tegra->soc->num_supplies,
tegra->supplies);
if (ret)
return ret;
@@ -144,7 +273,7 @@ disable_power:
tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
disable_regulators:
- regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies);
+ regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
return ret;
}
@@ -162,15 +291,14 @@ static void tegra_ahci_power_off(struct ahci_host_priv *hpriv)
clk_disable_unprepare(tegra->sata_clk);
tegra_powergate_power_off(TEGRA_POWERGATE_SATA);
- regulator_bulk_disable(ARRAY_SIZE(tegra->supplies), tegra->supplies);
+ regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies);
}
static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
{
struct tegra_ahci_priv *tegra = hpriv->plat_data;
int ret;
- unsigned int val;
- struct sata_pad_calibration calib;
+ u32 val;
ret = tegra_ahci_power_on(hpriv);
if (ret) {
@@ -179,78 +307,115 @@ static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
return ret;
}
+ /*
+ * Program the following SATA IPFS registers to allow SW accesses to
+ * SATA's MMIO register range.
+ */
+ val = readl(tegra->sata_regs + SATA_FPCI_BAR5);
+ val &= ~(SATA_FPCI_BAR5_START_MASK | SATA_FPCI_BAR5_ACCESS_TYPE);
+ val |= SATA_FPCI_BAR5_START | SATA_FPCI_BAR5_ACCESS_TYPE;
+ writel(val, tegra->sata_regs + SATA_FPCI_BAR5);
+
+ /* Program the following SATA IPFS register to enable the SATA */
val = readl(tegra->sata_regs + SATA_CONFIGURATION_0);
- val |= SATA_CONFIGURATION_EN_FPCI;
+ val |= SATA_CONFIGURATION_0_EN_FPCI;
writel(val, tegra->sata_regs + SATA_CONFIGURATION_0);
- /* Pad calibration */
-
- ret = tegra_fuse_readl(FUSE_SATA_CALIB, &val);
- if (ret) {
- dev_err(&tegra->pdev->dev,
- "failed to read calibration fuse: %d\n", ret);
- return ret;
- }
-
- calib = tegra124_pad_calibration[val & FUSE_SATA_CALIB_MASK];
-
- writel(BIT(0), tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
-
- val = readl(tegra->sata_regs +
- SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1);
- val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK;
- val &= ~T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK;
- val |= calib.gen1_tx_amp <<
- T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
- val |= calib.gen1_tx_peak <<
- T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
- writel(val, tegra->sata_regs + SCFG_OFFSET +
- T_SATA0_CHX_PHY_CTRL1_GEN1);
-
- val = readl(tegra->sata_regs +
- SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2);
- val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK;
- val &= ~T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK;
- val |= calib.gen2_tx_amp <<
- T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
- val |= calib.gen2_tx_peak <<
- T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
- writel(val, tegra->sata_regs + SCFG_OFFSET +
- T_SATA0_CHX_PHY_CTRL1_GEN2);
-
- writel(T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ,
- tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL11);
- writel(T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1,
- tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL2);
-
- writel(0, tegra->sata_regs + SCFG_OFFSET + T_SATA0_INDEX);
-
- /* Program controller device ID */
+ /* Electrical settings for better link stability */
+ val = T_SATA0_CHX_PHY_CTRL17_0_RX_EQ_CTRL_L_GEN1;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL17_0);
+ val = T_SATA0_CHX_PHY_CTRL18_0_RX_EQ_CTRL_L_GEN2;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL18_0);
+ val = T_SATA0_CHX_PHY_CTRL20_0_RX_EQ_CTRL_H_GEN1;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL20_0);
+ val = T_SATA0_CHX_PHY_CTRL21_0_RX_EQ_CTRL_H_GEN2;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL21_0);
+
+ /* For SQUELCH Filter & Gen3 drive getting detected as Gen1 drive */
+
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA_CFG_PHY_0);
+ val |= T_SATA_CFG_PHY_0_MASK_SQUELCH;
+ val &= ~T_SATA_CFG_PHY_0_USE_7BIT_ALIGN_DET_FOR_SPD;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA_CFG_PHY_0);
+
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_NVOOB);
+ val &= ~(T_SATA0_NVOOB_COMMA_CNT_MASK |
+ T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK |
+ T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK);
+ val |= (T_SATA0_NVOOB_COMMA_CNT |
+ T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH |
+ T_SATA0_NVOOB_SQUELCH_FILTER_MODE);
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_NVOOB);
+
+ /*
+ * Change CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW from 83.3 ns to 58.8ns
+ */
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG2NVOOB_2);
+ val &= ~T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK;
+ val |= T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG2NVOOB_2);
+
+ if (tegra->soc->ops && tegra->soc->ops->init)
+ tegra->soc->ops->init(hpriv);
+
+ /*
+ * Program the following SATA configuration registers to
+ * initialize SATA
+ */
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
+ val |= (T_SATA0_CFG_1_IO_SPACE | T_SATA0_CFG_1_MEMORY_SPACE |
+ T_SATA0_CFG_1_BUS_MASTER | T_SATA0_CFG_1_SERR);
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
+ val = T_SATA0_CFG_9_BASE_ADDRESS;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_9);
+ /* Program Class Code and Programming interface for SATA */
val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
val |= T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN;
writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
- writel(0x01060100, tegra->sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC);
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC);
+ val &=
+ ~(T_SATA0_BKDOOR_CC_CLASS_CODE_MASK |
+ T_SATA0_BKDOOR_CC_PROG_IF_MASK);
+ val |= T_SATA0_BKDOOR_CC_CLASS_CODE | T_SATA0_BKDOOR_CC_PROG_IF;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_BKDOOR_CC);
val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
val &= ~T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN;
writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_SATA);
- /* Enable IO & memory access, bus master mode */
-
- val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
- val |= T_SATA0_CFG_1_IO_SPACE | T_SATA0_CFG_1_MEMORY_SPACE |
- T_SATA0_CFG_1_BUS_MASTER | T_SATA0_CFG_1_SERR;
- writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_1);
-
- /* Program SATA MMIO */
-
- writel(0x10000 << SATA_FPCI_BAR5_START_SHIFT,
- tegra->sata_regs + SATA_FPCI_BAR5);
+ /* Enabling LPM capabilities through Backdoor Programming */
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR);
+ val |= (T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP |
+ T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP |
+ T_SATA0_AHCI_HBA_CAP_BKDR_SALP |
+ T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM);
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR);
+
+ /* SATA Second Level Clock Gating configuration
+ * Enabling Gating of Tx/Rx clocks and driving Pad IDDQ and Lane
+ * IDDQ Signals
+ */
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_35);
+ val &= ~T_SATA0_CFG_35_IDP_INDEX_MASK;
+ val |= T_SATA0_CFG_35_IDP_INDEX;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_35);
+
+ val = T_SATA0_AHCI_IDP1_DATA;
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_AHCI_IDP1);
+
+ val = readl(tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_PHY_1);
+ val |= (T_SATA0_CFG_PHY_1_PADS_IDDQ_EN |
+ T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN);
+ writel(val, tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_PHY_1);
+
+ /* Enabling IPFS Clock Gating */
+ val = readl(tegra->sata_regs + SATA_CONFIGURATION_0);
+ val &= ~SATA_CONFIGURATION_0_CLK_OVERRIDE;
+ writel(val, tegra->sata_regs + SATA_CONFIGURATION_0);
- writel(0x08000 << T_SATA0_CFG_9_BASE_ADDRESS_SHIFT,
- tegra->sata_regs + SCFG_OFFSET + T_SATA0_CFG_9);
+ tegra_ahci_handle_quirks(hpriv);
/* Unmask SATA interrupts */
@@ -279,14 +444,40 @@ static struct ata_port_operations ahci_tegra_port_ops = {
};
static const struct ata_port_info ahci_tegra_port_info = {
- .flags = AHCI_FLAG_COMMON,
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_tegra_port_ops,
};
+static const char *const tegra124_supply_names[] = {
+ "avdd", "hvdd", "vddio", "target-5v", "target-12v"
+};
+
+static const struct tegra_ahci_ops tegra124_ahci_ops = {
+ .init = tegra124_ahci_init,
+};
+
+static const struct tegra_ahci_soc tegra124_ahci_soc = {
+ .supply_names = tegra124_supply_names,
+ .num_supplies = ARRAY_SIZE(tegra124_supply_names),
+ .supports_devslp = false,
+ .ops = &tegra124_ahci_ops,
+};
+
+static const struct tegra_ahci_soc tegra210_ahci_soc = {
+ .supports_devslp = false,
+};
+
static const struct of_device_id tegra_ahci_of_match[] = {
- { .compatible = "nvidia,tegra124-ahci" },
+ {
+ .compatible = "nvidia,tegra124-ahci",
+ .data = &tegra124_ahci_soc
+ },
+ {
+ .compatible = "nvidia,tegra210-ahci",
+ .data = &tegra210_ahci_soc
+ },
{}
};
MODULE_DEVICE_TABLE(of, tegra_ahci_of_match);
@@ -301,6 +492,7 @@ static int tegra_ahci_probe(struct platform_device *pdev)
struct tegra_ahci_priv *tegra;
struct resource *res;
int ret;
+ unsigned int i;
hpriv = ahci_platform_get_resources(pdev);
if (IS_ERR(hpriv))
@@ -313,12 +505,23 @@ static int tegra_ahci_probe(struct platform_device *pdev)
hpriv->plat_data = tegra;
tegra->pdev = pdev;
+ tegra->soc = of_device_get_match_data(&pdev->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
tegra->sata_regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(tegra->sata_regs))
return PTR_ERR(tegra->sata_regs);
+ /*
+ * AUX registers is optional.
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (res) {
+ tegra->sata_aux_regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(tegra->sata_aux_regs))
+ return PTR_ERR(tegra->sata_aux_regs);
+ }
+
tegra->sata_rst = devm_reset_control_get(&pdev->dev, "sata");
if (IS_ERR(tegra->sata_rst)) {
dev_err(&pdev->dev, "Failed to get sata reset\n");
@@ -343,13 +546,17 @@ static int tegra_ahci_probe(struct platform_device *pdev)
return PTR_ERR(tegra->sata_clk);
}
- tegra->supplies[0].supply = "avdd";
- tegra->supplies[1].supply = "hvdd";
- tegra->supplies[2].supply = "vddio";
- tegra->supplies[3].supply = "target-5v";
- tegra->supplies[4].supply = "target-12v";
+ tegra->supplies = devm_kcalloc(&pdev->dev,
+ tegra->soc->num_supplies,
+ sizeof(*tegra->supplies), GFP_KERNEL);
+ if (!tegra->supplies)
+ return -ENOMEM;
+
+ for (i = 0; i < tegra->soc->num_supplies; i++)
+ tegra->supplies[i].supply = tegra->soc->supply_names[i];
- ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(tegra->supplies),
+ ret = devm_regulator_bulk_get(&pdev->dev,
+ tegra->soc->num_supplies,
tegra->supplies);
if (ret) {
dev_err(&pdev->dev, "Failed to get regulators\n");
@@ -385,5 +592,5 @@ static struct platform_driver tegra_ahci_driver = {
module_platform_driver(tegra_ahci_driver);
MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
-MODULE_DESCRIPTION("Tegra124 AHCI SATA driver");
+MODULE_DESCRIPTION("Tegra AHCI SATA driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 30cc8f1a31e1..46a762442dc5 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -25,6 +25,7 @@
#include <linux/phy/phy.h>
#include <linux/pm_runtime.h>
#include <linux/of_platform.h>
+#include <linux/reset.h>
#include "ahci.h"
static void ahci_host_stop(struct ata_host *host);
@@ -195,7 +196,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators);
* following order:
* 1) Regulator
* 2) Clocks (through ahci_platform_enable_clks)
- * 3) Phys
+ * 3) Resets
+ * 4) Phys
*
* If resource enabling fails at any point the previous enabled resources
* are disabled in reverse order.
@@ -215,12 +217,19 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
if (rc)
goto disable_regulator;
- rc = ahci_platform_enable_phys(hpriv);
+ rc = reset_control_deassert(hpriv->rsts);
if (rc)
goto disable_clks;
+ rc = ahci_platform_enable_phys(hpriv);
+ if (rc)
+ goto disable_resets;
+
return 0;
+disable_resets:
+ reset_control_assert(hpriv->rsts);
+
disable_clks:
ahci_platform_disable_clks(hpriv);
@@ -239,12 +248,15 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
* following order:
* 1) Phys
* 2) Clocks (through ahci_platform_disable_clks)
- * 3) Regulator
+ * 3) Resets
+ * 4) Regulator
*/
void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
{
ahci_platform_disable_phys(hpriv);
+ reset_control_assert(hpriv->rsts);
+
ahci_platform_disable_clks(hpriv);
ahci_platform_disable_regulators(hpriv);
@@ -393,6 +405,12 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
hpriv->clks[i] = clk;
}
+ hpriv->rsts = devm_reset_control_array_get_optional_shared(dev);
+ if (IS_ERR(hpriv->rsts)) {
+ rc = PTR_ERR(hpriv->rsts);
+ goto err_out;
+ }
+
hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
/*
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 728ed4764678..8bc71ca61e7f 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -6026,7 +6026,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
return ap;
}
-static void ata_host_release(struct device *gendev, void *res)
+static void ata_devres_release(struct device *gendev, void *res)
{
struct ata_host *host = dev_get_drvdata(gendev);
int i;
@@ -6040,13 +6040,36 @@ static void ata_host_release(struct device *gendev, void *res)
if (ap->scsi_host)
scsi_host_put(ap->scsi_host);
+ }
+
+ dev_set_drvdata(gendev, NULL);
+ ata_host_put(host);
+}
+
+static void ata_host_release(struct kref *kref)
+{
+ struct ata_host *host = container_of(kref, struct ata_host, kref);
+ int i;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
kfree(ap->pmp_link);
kfree(ap->slave_link);
kfree(ap);
host->ports[i] = NULL;
}
+ kfree(host);
+}
- dev_set_drvdata(gendev, NULL);
+void ata_host_get(struct ata_host *host)
+{
+ kref_get(&host->kref);
+}
+
+void ata_host_put(struct ata_host *host)
+{
+ kref_put(&host->kref, ata_host_release);
}
/**
@@ -6074,26 +6097,31 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
struct ata_host *host;
size_t sz;
int i;
+ void *dr;
DPRINTK("ENTER\n");
- if (!devres_open_group(dev, NULL, GFP_KERNEL))
- return NULL;
-
/* alloc a container for our list of ATA ports (buses) */
sz = sizeof(struct ata_host) + (max_ports + 1) * sizeof(void *);
- /* alloc a container for our list of ATA ports (buses) */
- host = devres_alloc(ata_host_release, sz, GFP_KERNEL);
+ host = kzalloc(sz, GFP_KERNEL);
if (!host)
+ return NULL;
+
+ if (!devres_open_group(dev, NULL, GFP_KERNEL))
+ goto err_free;
+
+ dr = devres_alloc(ata_devres_release, 0, GFP_KERNEL);
+ if (!dr)
goto err_out;
- devres_add(dev, host);
+ devres_add(dev, dr);
dev_set_drvdata(dev, host);
spin_lock_init(&host->lock);
mutex_init(&host->eh_mutex);
host->dev = dev;
host->n_ports = max_ports;
+ kref_init(&host->kref);
/* allocate ports bound to this host */
for (i = 0; i < max_ports; i++) {
@@ -6112,6 +6140,8 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
err_out:
devres_release_group(dev, NULL);
+ err_free:
+ kfree(host);
return NULL;
}
diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c
index 19e6e539a061..a0b0b4d986f2 100644
--- a/drivers/ata/libata-transport.c
+++ b/drivers/ata/libata-transport.c
@@ -224,6 +224,8 @@ static DECLARE_TRANSPORT_CLASS(ata_port_class,
static void ata_tport_release(struct device *dev)
{
+ struct ata_port *ap = tdev_to_port(dev);
+ ata_host_put(ap->host);
}
/**
@@ -284,6 +286,7 @@ int ata_tport_add(struct device *parent,
dev->type = &ata_port_type;
dev->parent = parent;
+ ata_host_get(ap->host);
dev->release = ata_tport_release;
dev_set_name(dev, "ata%d", ap->print_id);
transport_setup_device(dev);
@@ -314,6 +317,7 @@ int ata_tport_add(struct device *parent,
tport_err:
transport_destroy_device(dev);
put_device(dev);
+ ata_host_put(ap->host);
return error;
}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index f953cb4bb1ba..9e21c49cf6be 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -100,6 +100,8 @@ extern int ata_port_probe(struct ata_port *ap);
extern void __ata_port_probe(struct ata_port *ap);
extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
u8 page, void *buf, unsigned int sectors);
+extern void ata_host_get(struct ata_host *host);
+extern void ata_host_put(struct ata_host *host);
#define to_ata_port(d) container_of(d, struct ata_port, tdev)
diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c
index b4d54771c9fe..ebecab8c3f36 100644
--- a/drivers/ata/pata_arasan_cf.c
+++ b/drivers/ata/pata_arasan_cf.c
@@ -796,7 +796,7 @@ static int arasan_cf_probe(struct platform_device *pdev)
struct resource *res;
u32 quirk;
irq_handler_t irq_handler = NULL;
- int ret = 0;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -809,10 +809,8 @@ static int arasan_cf_probe(struct platform_device *pdev)
}
acdev = devm_kzalloc(&pdev->dev, sizeof(*acdev), GFP_KERNEL);
- if (!acdev) {
- dev_warn(&pdev->dev, "kzalloc fail\n");
+ if (!acdev)
return -ENOMEM;
- }
if (pdata)
quirk = pdata->quirk;
diff --git a/drivers/ata/pata_bk3710.c b/drivers/ata/pata_bk3710.c
index 6c3bd5fae3e4..fad95cfecced 100644
--- a/drivers/ata/pata_bk3710.c
+++ b/drivers/ata/pata_bk3710.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
/*
* Palmchip BK3710 PATA controller driver
*
@@ -8,10 +10,6 @@
*
* Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com>
- *
- * 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.
*/
#include <linux/ata.h>
@@ -379,4 +377,4 @@ static int __init pata_bk3710_init(void)
}
module_init(pata_bk3710_init);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/ata/pata_falcon.c b/drivers/ata/pata_falcon.c
index 5b0c57d1c59f..41e0d6a6cd05 100644
--- a/drivers/ata/pata_falcon.c
+++ b/drivers/ata/pata_falcon.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
/*
* Atari Falcon PATA controller driver
*
@@ -7,10 +9,6 @@
* Based on falconide.c:
*
* Created 12 Jul 1997 by Geert Uytterhoeven
- *
- * 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.
*/
#include <linux/kernel.h>
@@ -180,5 +178,5 @@ module_init(pata_falcon_init_one);
MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
MODULE_DESCRIPTION("low-level driver for Atari Falcon PATA");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_gayle.c b/drivers/ata/pata_gayle.c
new file mode 100644
index 000000000000..65bc9f3042ce
--- /dev/null
+++ b/drivers/ata/pata_gayle.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Amiga Gayle PATA controller driver
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Based on gayle.c:
+ *
+ * Created 12 Jul 1997 by Geert Uytterhoeven
+ */
+
+#include <linux/ata.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/libata.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/zorro.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/amigayle.h>
+#include <asm/ide.h>
+#include <asm/setup.h>
+
+#define DRV_NAME "pata_gayle"
+#define DRV_VERSION "0.1.0"
+
+#define GAYLE_CONTROL 0x101a
+
+static struct scsi_host_template pata_gayle_sht = {
+ ATA_PIO_SHT(DRV_NAME),
+};
+
+/* FIXME: is this needed? */
+static unsigned int pata_gayle_data_xfer(struct ata_queued_cmd *qc,
+ unsigned char *buf,
+ unsigned int buflen, int rw)
+{
+ struct ata_device *dev = qc->dev;
+ struct ata_port *ap = dev->link->ap;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned int words = buflen >> 1;
+
+ /* Transfer multiple of 2 bytes */
+ if (rw == READ)
+ raw_insw((u16 *)data_addr, (u16 *)buf, words);
+ else
+ raw_outsw((u16 *)data_addr, (u16 *)buf, words);
+
+ /* Transfer trailing byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ unsigned char pad[2] = { };
+
+ /* Point buf to the tail of buffer */
+ buf += buflen - 1;
+
+ if (rw == READ) {
+ raw_insw((u16 *)data_addr, (u16 *)pad, 1);
+ *buf = pad[0];
+ } else {
+ pad[0] = *buf;
+ raw_outsw((u16 *)data_addr, (u16 *)pad, 1);
+ }
+ words++;
+ }
+
+ return words << 1;
+}
+
+/*
+ * Provide our own set_mode() as we don't want to change anything that has
+ * already been configured..
+ */
+static int pata_gayle_set_mode(struct ata_link *link,
+ struct ata_device **unused)
+{
+ struct ata_device *dev;
+
+ ata_for_each_dev(dev, link, ENABLED) {
+ /* We don't really care */
+ dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
+ ata_dev_info(dev, "configured for PIO\n");
+ }
+ return 0;
+}
+
+static bool pata_gayle_irq_check(struct ata_port *ap)
+{
+ u8 ch;
+
+ ch = z_readb((unsigned long)ap->private_data);
+
+ return !!(ch & GAYLE_IRQ_IDE);
+}
+
+static void pata_gayle_irq_clear(struct ata_port *ap)
+{
+ (void)z_readb((unsigned long)ap->ioaddr.status_addr);
+ z_writeb(0x7c, (unsigned long)ap->private_data);
+}
+
+static struct ata_port_operations pata_gayle_a1200_ops = {
+ .inherits = &ata_sff_port_ops,
+ .sff_data_xfer = pata_gayle_data_xfer,
+ .sff_irq_check = pata_gayle_irq_check,
+ .sff_irq_clear = pata_gayle_irq_clear,
+ .cable_detect = ata_cable_unknown,
+ .set_mode = pata_gayle_set_mode,
+};
+
+static struct ata_port_operations pata_gayle_a4000_ops = {
+ .inherits = &ata_sff_port_ops,
+ .sff_data_xfer = pata_gayle_data_xfer,
+ .cable_detect = ata_cable_unknown,
+ .set_mode = pata_gayle_set_mode,
+};
+
+static int __init pata_gayle_init_one(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct gayle_ide_platform_data *pdata;
+ struct ata_host *host;
+ struct ata_port *ap;
+ void __iomem *base;
+ int ret;
+
+ pdata = dev_get_platdata(&pdev->dev);
+
+ dev_info(&pdev->dev, "Amiga Gayle IDE controller (A%u style)\n",
+ pdata->explicit_ack ? 1200 : 4000);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), DRV_NAME)) {
+ pr_err(DRV_NAME ": resources busy\n");
+ return -EBUSY;
+ }
+
+ /* allocate host */
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ return -ENOMEM;
+
+ ap = host->ports[0];
+
+ if (pdata->explicit_ack)
+ ap->ops = &pata_gayle_a1200_ops;
+ else
+ ap->ops = &pata_gayle_a4000_ops;
+
+ ap->pio_mask = ATA_PIO4;
+ ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
+
+ base = ZTWO_VADDR(pdata->base);
+ ap->ioaddr.data_addr = base;
+ ap->ioaddr.error_addr = base + 2 + 1 * 4;
+ ap->ioaddr.feature_addr = base + 2 + 1 * 4;
+ ap->ioaddr.nsect_addr = base + 2 + 2 * 4;
+ ap->ioaddr.lbal_addr = base + 2 + 3 * 4;
+ ap->ioaddr.lbam_addr = base + 2 + 4 * 4;
+ ap->ioaddr.lbah_addr = base + 2 + 5 * 4;
+ ap->ioaddr.device_addr = base + 2 + 6 * 4;
+ ap->ioaddr.status_addr = base + 2 + 7 * 4;
+ ap->ioaddr.command_addr = base + 2 + 7 * 4;
+
+ ap->ioaddr.altstatus_addr = base + GAYLE_CONTROL;
+ ap->ioaddr.ctl_addr = base + GAYLE_CONTROL;
+
+ ap->private_data = (void *)ZTWO_VADDR(pdata->irqport);
+
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", pdata->base,
+ pdata->base + GAYLE_CONTROL);
+
+ ret = ata_host_activate(host, IRQ_AMIGA_PORTS, ata_sff_interrupt,
+ IRQF_SHARED, &pata_gayle_sht);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, host);
+
+ return 0;
+}
+
+static int __exit pata_gayle_remove_one(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+
+ ata_host_detach(host);
+
+ return 0;
+}
+
+static struct platform_driver pata_gayle_driver = {
+ .remove = __exit_p(pata_gayle_remove_one),
+ .driver = {
+ .name = "amiga-gayle-ide",
+ },
+};
+
+module_platform_driver_probe(pata_gayle_driver, pata_gayle_init_one);
+
+MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
+MODULE_DESCRIPTION("low-level driver for Amiga Gayle PATA");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:amiga-gayle-ide");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 8468b300193b..9bac79edbc2c 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -658,10 +658,10 @@ static u8 *it821x_firmware_command(struct ata_port *ap, u8 cmd, int len)
u8 status;
int n = 0;
u16 *buf = kmalloc(len, GFP_KERNEL);
- if (buf == NULL) {
- printk(KERN_ERR "it821x_firmware_command: Out of memory\n");
+
+ if (!buf)
return NULL;
- }
+
/* This isn't quite a normal ATA command as we are talking to the
firmware not the drives */
ap->ctl |= ATA_NIEN;
diff --git a/drivers/ata/pata_macio.c b/drivers/ata/pata_macio.c
index 0adcb40d2794..9588e685d994 100644
--- a/drivers/ata/pata_macio.c
+++ b/drivers/ata/pata_macio.c
@@ -1131,11 +1131,9 @@ static int pata_macio_attach(struct macio_dev *mdev,
/* Allocate and init private data structure */
priv = devm_kzalloc(&mdev->ofdev.dev,
sizeof(struct pata_macio_priv), GFP_KERNEL);
- if (priv == NULL) {
- dev_err(&mdev->ofdev.dev,
- "Failed to allocate private memory\n");
+ if (!priv)
return -ENOMEM;
- }
+
priv->node = of_node_get(mdev->ofdev.dev.of_node);
priv->mdev = mdev;
priv->dev = &mdev->ofdev.dev;
@@ -1277,11 +1275,9 @@ static int pata_macio_pci_attach(struct pci_dev *pdev,
/* Allocate and init private data structure */
priv = devm_kzalloc(&pdev->dev,
sizeof(struct pata_macio_priv), GFP_KERNEL);
- if (priv == NULL) {
- dev_err(&pdev->dev,
- "Failed to allocate private memory\n");
+ if (!priv)
return -ENOMEM;
- }
+
priv->node = of_node_get(np);
priv->pdev = pdev;
priv->dev = &pdev->dev;
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 9730125530f6..f1d352d5f128 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -738,7 +738,6 @@ static int mpc52xx_ata_probe(struct platform_device *op)
/* Prepare our private structure */
priv = devm_kzalloc(&op->dev, sizeof(*priv), GFP_ATOMIC);
if (!priv) {
- dev_err(&op->dev, "error allocating private structure\n");
rv = -ENOMEM;
goto err1;
}
diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c
index 50801c40b029..bb96dc35950d 100644
--- a/drivers/ata/pata_samsung_cf.c
+++ b/drivers/ata/pata_samsung_cf.c
@@ -505,10 +505,8 @@ static int __init pata_s3c_probe(struct platform_device *pdev)
cpu_type = platform_get_device_id(pdev)->driver_data;
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
- if (!info) {
- dev_err(dev, "failed to allocate memory for device data\n");
+ if (!info)
return -ENOMEM;
- }
info->irq = platform_get_irq(pdev, 0);
diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c
index 6af4ec3c88c3..ce3d6674ef80 100644
--- a/drivers/ata/sata_dwc_460ex.c
+++ b/drivers/ata/sata_dwc_460ex.c
@@ -901,7 +901,6 @@ static int sata_dwc_port_start(struct ata_port *ap)
/* Allocate Port Struct */
hsdevp = kzalloc(sizeof(*hsdevp), GFP_KERNEL);
if (!hsdevp) {
- dev_err(ap->dev, "%s: kmalloc failed for hsdevp\n", __func__);
err = -ENOMEM;
goto CLEANUP;
}
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index e32a52490051..b074f242a435 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -5,14 +5,15 @@ obj-y := component.o core.o bus.o dd.o syscore.o \
driver.o class.o platform.o \
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o \
- topology.o container.o property.o cacheinfo.o
+ topology.o container.o property.o cacheinfo.o \
+ devcon.o
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
obj-y += power/
obj-$(CONFIG_HAS_DMA) += dma-mapping.o
obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
obj-$(CONFIG_ISA_BUS_API) += isa.o
-obj-$(CONFIG_FW_LOADER) += firmware_class.o
+obj-y += firmware_loader/
obj-$(CONFIG_NUMA) += node.o
obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o
ifeq ($(CONFIG_SYSFS),y)
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 52ec5174bcb1..e7cb0c6ade81 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -169,11 +169,11 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
}
#ifdef CONFIG_CPU_FREQ
-static cpumask_var_t cpus_to_visit __initdata;
-static void __init parsing_done_workfn(struct work_struct *work);
-static __initdata DECLARE_WORK(parsing_done_work, parsing_done_workfn);
+static cpumask_var_t cpus_to_visit;
+static void parsing_done_workfn(struct work_struct *work);
+static DECLARE_WORK(parsing_done_work, parsing_done_workfn);
-static int __init
+static int
init_cpu_capacity_callback(struct notifier_block *nb,
unsigned long val,
void *data)
@@ -209,7 +209,7 @@ init_cpu_capacity_callback(struct notifier_block *nb,
return 0;
}
-static struct notifier_block init_cpu_capacity_notifier __initdata = {
+static struct notifier_block init_cpu_capacity_notifier = {
.notifier_call = init_cpu_capacity_callback,
};
@@ -242,7 +242,7 @@ static int __init register_cpufreq_notifier(void)
}
core_initcall(register_cpufreq_notifier);
-static void __init parsing_done_workfn(struct work_struct *work)
+static void parsing_done_workfn(struct work_struct *work)
{
cpufreq_unregister_notifier(&init_cpu_capacity_notifier,
CPUFREQ_POLICY_NOTIFIER);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index d21a2d913107..2da998baa75c 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -382,8 +382,10 @@ int register_cpu(struct cpu *cpu, int num)
if (cpu->hotpluggable)
cpu->dev.groups = hotplugable_cpu_attr_groups;
error = device_register(&cpu->dev);
- if (error)
+ if (error) {
+ put_device(&cpu->dev);
return error;
+ }
per_cpu(cpu_sys_devices, num) = &cpu->dev;
register_cpu_under_node(num, cpu_to_node(num));
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index de6fd092bf2f..c9f54089429b 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -292,8 +292,7 @@ static ssize_t coredump_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
device_lock(dev);
- if (dev->driver->coredump)
- dev->driver->coredump(dev);
+ dev->driver->coredump(dev);
device_unlock(dev);
return count;
diff --git a/drivers/base/devcon.c b/drivers/base/devcon.c
new file mode 100644
index 000000000000..d427e806cd73
--- /dev/null
+++ b/drivers/base/devcon.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * Device connections
+ *
+ * Copyright (C) 2018 Intel Corporation
+ * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+ */
+
+#include <linux/device.h>
+
+static DEFINE_MUTEX(devcon_lock);
+static LIST_HEAD(devcon_list);
+
+/**
+ * device_connection_find_match - Find physical connection to a device
+ * @dev: Device with the connection
+ * @con_id: Identifier for the connection
+ * @data: Data for the match function
+ * @match: Function to check and convert the connection description
+ *
+ * Find a connection with unique identifier @con_id between @dev and another
+ * device. @match will be used to convert the connection description to data the
+ * caller is expecting to be returned.
+ */
+void *device_connection_find_match(struct device *dev, const char *con_id,
+ void *data,
+ void *(*match)(struct device_connection *con,
+ int ep, void *data))
+{
+ const char *devname = dev_name(dev);
+ struct device_connection *con;
+ void *ret = NULL;
+ int ep;
+
+ if (!match)
+ return NULL;
+
+ mutex_lock(&devcon_lock);
+
+ list_for_each_entry(con, &devcon_list, list) {
+ ep = match_string(con->endpoint, 2, devname);
+ if (ep < 0)
+ continue;
+
+ if (con_id && strcmp(con->id, con_id))
+ continue;
+
+ ret = match(con, !ep, data);
+ if (ret)
+ break;
+ }
+
+ mutex_unlock(&devcon_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(device_connection_find_match);
+
+extern struct bus_type platform_bus_type;
+extern struct bus_type pci_bus_type;
+extern struct bus_type i2c_bus_type;
+extern struct bus_type spi_bus_type;
+
+static struct bus_type *generic_match_buses[] = {
+ &platform_bus_type,
+#ifdef CONFIG_PCI
+ &pci_bus_type,
+#endif
+#ifdef CONFIG_I2C
+ &i2c_bus_type,
+#endif
+#ifdef CONFIG_SPI_MASTER
+ &spi_bus_type,
+#endif
+ NULL,
+};
+
+/* This tries to find the device from the most common bus types by name. */
+static void *generic_match(struct device_connection *con, int ep, void *data)
+{
+ struct bus_type *bus;
+ struct device *dev;
+
+ for (bus = generic_match_buses[0]; bus; bus++) {
+ dev = bus_find_device_by_name(bus, NULL, con->endpoint[ep]);
+ if (dev)
+ return dev;
+ }
+
+ /*
+ * We only get called if a connection was found, tell the caller to
+ * wait for the other device to show up.
+ */
+ return ERR_PTR(-EPROBE_DEFER);
+}
+
+/**
+ * device_connection_find - Find two devices connected together
+ * @dev: Device with the connection
+ * @con_id: Identifier for the connection
+ *
+ * Find a connection with unique identifier @con_id between @dev and
+ * another device. On success returns handle to the device that is connected
+ * to @dev, with the reference count for the found device incremented. Returns
+ * NULL if no matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a
+ * connection was found but the other device has not been enumerated yet.
+ */
+struct device *device_connection_find(struct device *dev, const char *con_id)
+{
+ return device_connection_find_match(dev, con_id, NULL, generic_match);
+}
+EXPORT_SYMBOL_GPL(device_connection_find);
+
+/**
+ * device_connection_add - Register a connection description
+ * @con: The connection description to be registered
+ */
+void device_connection_add(struct device_connection *con)
+{
+ mutex_lock(&devcon_lock);
+ list_add_tail(&con->list, &devcon_list);
+ mutex_unlock(&devcon_lock);
+}
+EXPORT_SYMBOL_GPL(device_connection_add);
+
+/**
+ * device_connections_remove - Unregister connection description
+ * @con: The connection description to be unregistered
+ */
+void device_connection_remove(struct device_connection *con)
+{
+ mutex_lock(&devcon_lock);
+ list_del(&con->list);
+ mutex_unlock(&devcon_lock);
+}
+EXPORT_SYMBOL_GPL(device_connection_remove);
diff --git a/drivers/base/firmware_loader/Makefile b/drivers/base/firmware_loader/Makefile
new file mode 100644
index 000000000000..a97eeb0be1d8
--- /dev/null
+++ b/drivers/base/firmware_loader/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for the Linux firmware loader
+
+obj-y := fallback_table.o
+obj-$(CONFIG_FW_LOADER) += firmware_class.o
+firmware_class-objs := main.o
+firmware_class-$(CONFIG_FW_LOADER_USER_HELPER) += fallback.o
diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c
new file mode 100644
index 000000000000..31b5015b59fe
--- /dev/null
+++ b/drivers/base/firmware_loader/fallback.c
@@ -0,0 +1,675 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/types.h>
+#include <linux/kconfig.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/security.h>
+#include <linux/highmem.h>
+#include <linux/umh.h>
+#include <linux/sysctl.h>
+#include <linux/vmalloc.h>
+
+#include "fallback.h"
+#include "firmware.h"
+
+/*
+ * firmware fallback mechanism
+ */
+
+extern struct firmware_fallback_config fw_fallback_config;
+
+/* These getters are vetted to use int properly */
+static inline int __firmware_loading_timeout(void)
+{
+ return fw_fallback_config.loading_timeout;
+}
+
+/* These setters are vetted to use int properly */
+static void __fw_fallback_set_timeout(int timeout)
+{
+ fw_fallback_config.loading_timeout = timeout;
+}
+
+/*
+ * use small loading timeout for caching devices' firmware because all these
+ * firmware images have been loaded successfully at lease once, also system is
+ * ready for completing firmware loading now. The maximum size of firmware in
+ * current distributions is about 2M bytes, so 10 secs should be enough.
+ */
+void fw_fallback_set_cache_timeout(void)
+{
+ fw_fallback_config.old_timeout = __firmware_loading_timeout();
+ __fw_fallback_set_timeout(10);
+}
+
+/* Restores the timeout to the value last configured during normal operation */
+void fw_fallback_set_default_timeout(void)
+{
+ __fw_fallback_set_timeout(fw_fallback_config.old_timeout);
+}
+
+static long firmware_loading_timeout(void)
+{
+ return __firmware_loading_timeout() > 0 ?
+ __firmware_loading_timeout() * HZ : MAX_JIFFY_OFFSET;
+}
+
+static inline bool fw_sysfs_done(struct fw_priv *fw_priv)
+{
+ return __fw_state_check(fw_priv, FW_STATUS_DONE);
+}
+
+static inline bool fw_sysfs_loading(struct fw_priv *fw_priv)
+{
+ return __fw_state_check(fw_priv, FW_STATUS_LOADING);
+}
+
+static inline int fw_sysfs_wait_timeout(struct fw_priv *fw_priv, long timeout)
+{
+ return __fw_state_wait_common(fw_priv, timeout);
+}
+
+struct fw_sysfs {
+ bool nowait;
+ struct device dev;
+ struct fw_priv *fw_priv;
+ struct firmware *fw;
+};
+
+static struct fw_sysfs *to_fw_sysfs(struct device *dev)
+{
+ return container_of(dev, struct fw_sysfs, dev);
+}
+
+static void __fw_load_abort(struct fw_priv *fw_priv)
+{
+ /*
+ * There is a small window in which user can write to 'loading'
+ * between loading done and disappearance of 'loading'
+ */
+ if (fw_sysfs_done(fw_priv))
+ return;
+
+ list_del_init(&fw_priv->pending_list);
+ fw_state_aborted(fw_priv);
+}
+
+static void fw_load_abort(struct fw_sysfs *fw_sysfs)
+{
+ struct fw_priv *fw_priv = fw_sysfs->fw_priv;
+
+ __fw_load_abort(fw_priv);
+}
+
+static LIST_HEAD(pending_fw_head);
+
+void kill_pending_fw_fallback_reqs(bool only_kill_custom)
+{
+ struct fw_priv *fw_priv;
+ struct fw_priv *next;
+
+ mutex_lock(&fw_lock);
+ list_for_each_entry_safe(fw_priv, next, &pending_fw_head,
+ pending_list) {
+ if (!fw_priv->need_uevent || !only_kill_custom)
+ __fw_load_abort(fw_priv);
+ }
+ mutex_unlock(&fw_lock);
+}
+
+static ssize_t timeout_show(struct class *class, struct class_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", __firmware_loading_timeout());
+}
+
+/**
+ * firmware_timeout_store - set number of seconds to wait for firmware
+ * @class: device class pointer
+ * @attr: device attribute pointer
+ * @buf: buffer to scan for timeout value
+ * @count: number of bytes in @buf
+ *
+ * Sets the number of seconds to wait for the firmware. Once
+ * this expires an error will be returned to the driver and no
+ * firmware will be provided.
+ *
+ * Note: zero means 'wait forever'.
+ **/
+static ssize_t timeout_store(struct class *class, struct class_attribute *attr,
+ const char *buf, size_t count)
+{
+ int tmp_loading_timeout = simple_strtol(buf, NULL, 10);
+
+ if (tmp_loading_timeout < 0)
+ tmp_loading_timeout = 0;
+
+ __fw_fallback_set_timeout(tmp_loading_timeout);
+
+ return count;
+}
+static CLASS_ATTR_RW(timeout);
+
+static struct attribute *firmware_class_attrs[] = {
+ &class_attr_timeout.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(firmware_class);
+
+static void fw_dev_release(struct device *dev)
+{
+ struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);
+
+ kfree(fw_sysfs);
+}
+
+static int do_firmware_uevent(struct fw_sysfs *fw_sysfs, struct kobj_uevent_env *env)
+{
+ if (add_uevent_var(env, "FIRMWARE=%s", fw_sysfs->fw_priv->fw_name))
+ return -ENOMEM;
+ if (add_uevent_var(env, "TIMEOUT=%i", __firmware_loading_timeout()))
+ return -ENOMEM;
+ if (add_uevent_var(env, "ASYNC=%d", fw_sysfs->nowait))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);
+ int err = 0;
+
+ mutex_lock(&fw_lock);
+ if (fw_sysfs->fw_priv)
+ err = do_firmware_uevent(fw_sysfs, env);
+ mutex_unlock(&fw_lock);
+ return err;
+}
+
+static struct class firmware_class = {
+ .name = "firmware",
+ .class_groups = firmware_class_groups,
+ .dev_uevent = firmware_uevent,
+ .dev_release = fw_dev_release,
+};
+
+int register_sysfs_loader(void)
+{
+ return class_register(&firmware_class);
+}
+
+void unregister_sysfs_loader(void)
+{
+ class_unregister(&firmware_class);
+}
+
+static ssize_t firmware_loading_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);
+ int loading = 0;
+
+ mutex_lock(&fw_lock);
+ if (fw_sysfs->fw_priv)
+ loading = fw_sysfs_loading(fw_sysfs->fw_priv);
+ mutex_unlock(&fw_lock);
+
+ return sprintf(buf, "%d\n", loading);
+}
+
+/* Some architectures don't have PAGE_KERNEL_RO */
+#ifndef PAGE_KERNEL_RO
+#define PAGE_KERNEL_RO PAGE_KERNEL
+#endif
+
+/* one pages buffer should be mapped/unmapped only once */
+static int map_fw_priv_pages(struct fw_priv *fw_priv)
+{
+ if (!fw_priv->is_paged_buf)
+ return 0;
+
+ vunmap(fw_priv->data);
+ fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0,
+ PAGE_KERNEL_RO);
+ if (!fw_priv->data)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * firmware_loading_store - set value in the 'loading' control file
+ * @dev: device pointer
+ * @attr: device attribute pointer
+ * @buf: buffer to scan for loading control value
+ * @count: number of bytes in @buf
+ *
+ * The relevant values are:
+ *
+ * 1: Start a load, discarding any previous partial load.
+ * 0: Conclude the load and hand the data to the driver code.
+ * -1: Conclude the load with an error and discard any written data.
+ **/
+static ssize_t firmware_loading_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);
+ struct fw_priv *fw_priv;
+ ssize_t written = count;
+ int loading = simple_strtol(buf, NULL, 10);
+ int i;
+
+ mutex_lock(&fw_lock);
+ fw_priv = fw_sysfs->fw_priv;
+ if (fw_state_is_aborted(fw_priv))
+ goto out;
+
+ switch (loading) {
+ case 1:
+ /* discarding any previous partial load */
+ if (!fw_sysfs_done(fw_priv)) {
+ for (i = 0; i < fw_priv->nr_pages; i++)
+ __free_page(fw_priv->pages[i]);
+ vfree(fw_priv->pages);
+ fw_priv->pages = NULL;
+ fw_priv->page_array_size = 0;
+ fw_priv->nr_pages = 0;
+ fw_state_start(fw_priv);
+ }
+ break;
+ case 0:
+ if (fw_sysfs_loading(fw_priv)) {
+ int rc;
+
+ /*
+ * Several loading requests may be pending on
+ * one same firmware buf, so let all requests
+ * see the mapped 'buf->data' once the loading
+ * is completed.
+ * */
+ rc = map_fw_priv_pages(fw_priv);
+ if (rc)
+ dev_err(dev, "%s: map pages failed\n",
+ __func__);
+ else
+ rc = security_kernel_post_read_file(NULL,
+ fw_priv->data, fw_priv->size,
+ READING_FIRMWARE);
+
+ /*
+ * Same logic as fw_load_abort, only the DONE bit
+ * is ignored and we set ABORT only on failure.
+ */
+ list_del_init(&fw_priv->pending_list);
+ if (rc) {
+ fw_state_aborted(fw_priv);
+ written = rc;
+ } else {
+ fw_state_done(fw_priv);
+ }
+ break;
+ }
+ /* fallthrough */
+ default:
+ dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading);
+ /* fallthrough */
+ case -1:
+ fw_load_abort(fw_sysfs);
+ break;
+ }
+out:
+ mutex_unlock(&fw_lock);
+ return written;
+}
+
+static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
+
+static void firmware_rw_data(struct fw_priv *fw_priv, char *buffer,
+ loff_t offset, size_t count, bool read)
+{
+ if (read)
+ memcpy(buffer, fw_priv->data + offset, count);
+ else
+ memcpy(fw_priv->data + offset, buffer, count);
+}
+
+static void firmware_rw(struct fw_priv *fw_priv, char *buffer,
+ loff_t offset, size_t count, bool read)
+{
+ while (count) {
+ void *page_data;
+ int page_nr = offset >> PAGE_SHIFT;
+ int page_ofs = offset & (PAGE_SIZE-1);
+ int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
+
+ page_data = kmap(fw_priv->pages[page_nr]);
+
+ if (read)
+ memcpy(buffer, page_data + page_ofs, page_cnt);
+ else
+ memcpy(page_data + page_ofs, buffer, page_cnt);
+
+ kunmap(fw_priv->pages[page_nr]);
+ buffer += page_cnt;
+ offset += page_cnt;
+ count -= page_cnt;
+ }
+}
+
+static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t offset, size_t count)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);
+ struct fw_priv *fw_priv;
+ ssize_t ret_count;
+
+ mutex_lock(&fw_lock);
+ fw_priv = fw_sysfs->fw_priv;
+ if (!fw_priv || fw_sysfs_done(fw_priv)) {
+ ret_count = -ENODEV;
+ goto out;
+ }
+ if (offset > fw_priv->size) {
+ ret_count = 0;
+ goto out;
+ }
+ if (count > fw_priv->size - offset)
+ count = fw_priv->size - offset;
+
+ ret_count = count;
+
+ if (fw_priv->data)
+ firmware_rw_data(fw_priv, buffer, offset, count, true);
+ else
+ firmware_rw(fw_priv, buffer, offset, count, true);
+
+out:
+ mutex_unlock(&fw_lock);
+ return ret_count;
+}
+
+static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size)
+{
+ struct fw_priv *fw_priv= fw_sysfs->fw_priv;
+ int pages_needed = PAGE_ALIGN(min_size) >> PAGE_SHIFT;
+
+ /* If the array of pages is too small, grow it... */
+ if (fw_priv->page_array_size < pages_needed) {
+ int new_array_size = max(pages_needed,
+ fw_priv->page_array_size * 2);
+ struct page **new_pages;
+
+ new_pages = vmalloc(new_array_size * sizeof(void *));
+ if (!new_pages) {
+ fw_load_abort(fw_sysfs);
+ return -ENOMEM;
+ }
+ memcpy(new_pages, fw_priv->pages,
+ fw_priv->page_array_size * sizeof(void *));
+ memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
+ (new_array_size - fw_priv->page_array_size));
+ vfree(fw_priv->pages);
+ fw_priv->pages = new_pages;
+ fw_priv->page_array_size = new_array_size;
+ }
+
+ while (fw_priv->nr_pages < pages_needed) {
+ fw_priv->pages[fw_priv->nr_pages] =
+ alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+
+ if (!fw_priv->pages[fw_priv->nr_pages]) {
+ fw_load_abort(fw_sysfs);
+ return -ENOMEM;
+ }
+ fw_priv->nr_pages++;
+ }
+ return 0;
+}
+
+/**
+ * firmware_data_write - write method for firmware
+ * @filp: open sysfs file
+ * @kobj: kobject for the device
+ * @bin_attr: bin_attr structure
+ * @buffer: buffer being written
+ * @offset: buffer offset for write in total data store area
+ * @count: buffer size
+ *
+ * Data written to the 'data' attribute will be later handed to
+ * the driver as a firmware image.
+ **/
+static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t offset, size_t count)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);
+ struct fw_priv *fw_priv;
+ ssize_t retval;
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ mutex_lock(&fw_lock);
+ fw_priv = fw_sysfs->fw_priv;
+ if (!fw_priv || fw_sysfs_done(fw_priv)) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ if (fw_priv->data) {
+ if (offset + count > fw_priv->allocated_size) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ firmware_rw_data(fw_priv, buffer, offset, count, false);
+ retval = count;
+ } else {
+ retval = fw_realloc_pages(fw_sysfs, offset + count);
+ if (retval)
+ goto out;
+
+ retval = count;
+ firmware_rw(fw_priv, buffer, offset, count, false);
+ }
+
+ fw_priv->size = max_t(size_t, offset + count, fw_priv->size);
+out:
+ mutex_unlock(&fw_lock);
+ return retval;
+}
+
+static struct bin_attribute firmware_attr_data = {
+ .attr = { .name = "data", .mode = 0644 },
+ .size = 0,
+ .read = firmware_data_read,
+ .write = firmware_data_write,
+};
+
+static struct attribute *fw_dev_attrs[] = {
+ &dev_attr_loading.attr,
+ NULL
+};
+
+static struct bin_attribute *fw_dev_bin_attrs[] = {
+ &firmware_attr_data,
+ NULL
+};
+
+static const struct attribute_group fw_dev_attr_group = {
+ .attrs = fw_dev_attrs,
+ .bin_attrs = fw_dev_bin_attrs,
+};
+
+static const struct attribute_group *fw_dev_attr_groups[] = {
+ &fw_dev_attr_group,
+ NULL
+};
+
+static struct fw_sysfs *
+fw_create_instance(struct firmware *firmware, const char *fw_name,
+ struct device *device, unsigned int opt_flags)
+{
+ struct fw_sysfs *fw_sysfs;
+ struct device *f_dev;
+
+ fw_sysfs = kzalloc(sizeof(*fw_sysfs), GFP_KERNEL);
+ if (!fw_sysfs) {
+ fw_sysfs = ERR_PTR(-ENOMEM);
+ goto exit;
+ }
+
+ fw_sysfs->nowait = !!(opt_flags & FW_OPT_NOWAIT);
+ fw_sysfs->fw = firmware;
+ f_dev = &fw_sysfs->dev;
+
+ device_initialize(f_dev);
+ dev_set_name(f_dev, "%s", fw_name);
+ f_dev->parent = device;
+ f_dev->class = &firmware_class;
+ f_dev->groups = fw_dev_attr_groups;
+exit:
+ return fw_sysfs;
+}
+
+/**
+ * fw_load_sysfs_fallback - load a firmware via the syfs fallback mechanism
+ * @fw_sysfs: firmware syfs information for the firmware to load
+ * @opt_flags: flags of options, FW_OPT_*
+ * @timeout: timeout to wait for the load
+ *
+ * In charge of constructing a sysfs fallback interface for firmware loading.
+ **/
+static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs,
+ unsigned int opt_flags, long timeout)
+{
+ int retval = 0;
+ struct device *f_dev = &fw_sysfs->dev;
+ struct fw_priv *fw_priv = fw_sysfs->fw_priv;
+
+ /* fall back on userspace loading */
+ if (!fw_priv->data)
+ fw_priv->is_paged_buf = true;
+
+ dev_set_uevent_suppress(f_dev, true);
+
+ retval = device_add(f_dev);
+ if (retval) {
+ dev_err(f_dev, "%s: device_register failed\n", __func__);
+ goto err_put_dev;
+ }
+
+ mutex_lock(&fw_lock);
+ list_add(&fw_priv->pending_list, &pending_fw_head);
+ mutex_unlock(&fw_lock);
+
+ if (opt_flags & FW_OPT_UEVENT) {
+ fw_priv->need_uevent = true;
+ dev_set_uevent_suppress(f_dev, false);
+ dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_name);
+ kobject_uevent(&fw_sysfs->dev.kobj, KOBJ_ADD);
+ } else {
+ timeout = MAX_JIFFY_OFFSET;
+ }
+
+ retval = fw_sysfs_wait_timeout(fw_priv, timeout);
+ if (retval < 0) {
+ mutex_lock(&fw_lock);
+ fw_load_abort(fw_sysfs);
+ mutex_unlock(&fw_lock);
+ }
+
+ if (fw_state_is_aborted(fw_priv)) {
+ if (retval == -ERESTARTSYS)
+ retval = -EINTR;
+ else
+ retval = -EAGAIN;
+ } else if (fw_priv->is_paged_buf && !fw_priv->data)
+ retval = -ENOMEM;
+
+ device_del(f_dev);
+err_put_dev:
+ put_device(f_dev);
+ return retval;
+}
+
+static int fw_load_from_user_helper(struct firmware *firmware,
+ const char *name, struct device *device,
+ unsigned int opt_flags)
+{
+ struct fw_sysfs *fw_sysfs;
+ long timeout;
+ int ret;
+
+ timeout = firmware_loading_timeout();
+ if (opt_flags & FW_OPT_NOWAIT) {
+ timeout = usermodehelper_read_lock_wait(timeout);
+ if (!timeout) {
+ dev_dbg(device, "firmware: %s loading timed out\n",
+ name);
+ return -EBUSY;
+ }
+ } else {
+ ret = usermodehelper_read_trylock();
+ if (WARN_ON(ret)) {
+ dev_err(device, "firmware: %s will not be loaded\n",
+ name);
+ return ret;
+ }
+ }
+
+ fw_sysfs = fw_create_instance(firmware, name, device, opt_flags);
+ if (IS_ERR(fw_sysfs)) {
+ ret = PTR_ERR(fw_sysfs);
+ goto out_unlock;
+ }
+
+ fw_sysfs->fw_priv = firmware->priv;
+ ret = fw_load_sysfs_fallback(fw_sysfs, opt_flags, timeout);
+
+ if (!ret)
+ ret = assign_fw(firmware, device, opt_flags);
+
+out_unlock:
+ usermodehelper_read_unlock();
+
+ return ret;
+}
+
+static bool fw_force_sysfs_fallback(unsigned int opt_flags)
+{
+ if (fw_fallback_config.force_sysfs_fallback)
+ return true;
+ if (!(opt_flags & FW_OPT_USERHELPER))
+ return false;
+ return true;
+}
+
+static bool fw_run_sysfs_fallback(unsigned int opt_flags)
+{
+ if (fw_fallback_config.ignore_sysfs_fallback) {
+ pr_info_once("Ignoring firmware sysfs fallback due to sysctl knob\n");
+ return false;
+ }
+
+ if ((opt_flags & FW_OPT_NOFALLBACK))
+ return false;
+
+ return fw_force_sysfs_fallback(opt_flags);
+}
+
+int fw_sysfs_fallback(struct firmware *fw, const char *name,
+ struct device *device,
+ unsigned int opt_flags,
+ int ret)
+{
+ if (!fw_run_sysfs_fallback(opt_flags))
+ return ret;
+
+ dev_warn(device, "Falling back to user helper\n");
+ return fw_load_from_user_helper(fw, name, device, opt_flags);
+}
diff --git a/drivers/base/firmware_loader/fallback.h b/drivers/base/firmware_loader/fallback.h
new file mode 100644
index 000000000000..dfebc644ed35
--- /dev/null
+++ b/drivers/base/firmware_loader/fallback.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __FIRMWARE_FALLBACK_H
+#define __FIRMWARE_FALLBACK_H
+
+#include <linux/firmware.h>
+#include <linux/device.h>
+
+/**
+ * struct firmware_fallback_config - firmware fallback configuratioon settings
+ *
+ * Helps describe and fine tune the fallback mechanism.
+ *
+ * @force_sysfs_fallback: force the sysfs fallback mechanism to be used
+ * as if one had enabled CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y.
+ * Useful to help debug a CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+ * functionality on a kernel where that config entry has been disabled.
+ * @ignore_sysfs_fallback: force to disable the sysfs fallback mechanism.
+ * This emulates the behaviour as if we had set the kernel
+ * config CONFIG_FW_LOADER_USER_HELPER=n.
+ * @old_timeout: for internal use
+ * @loading_timeout: the timeout to wait for the fallback mechanism before
+ * giving up, in seconds.
+ */
+struct firmware_fallback_config {
+ unsigned int force_sysfs_fallback;
+ unsigned int ignore_sysfs_fallback;
+ int old_timeout;
+ int loading_timeout;
+};
+
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+int fw_sysfs_fallback(struct firmware *fw, const char *name,
+ struct device *device,
+ unsigned int opt_flags,
+ int ret);
+void kill_pending_fw_fallback_reqs(bool only_kill_custom);
+
+void fw_fallback_set_cache_timeout(void);
+void fw_fallback_set_default_timeout(void);
+
+int register_sysfs_loader(void);
+void unregister_sysfs_loader(void);
+#else /* CONFIG_FW_LOADER_USER_HELPER */
+static inline int fw_sysfs_fallback(struct firmware *fw, const char *name,
+ struct device *device,
+ unsigned int opt_flags,
+ int ret)
+{
+ /* Keep carrying over the same error */
+ return ret;
+}
+
+static inline void kill_pending_fw_fallback_reqs(bool only_kill_custom) { }
+static inline void fw_fallback_set_cache_timeout(void) { }
+static inline void fw_fallback_set_default_timeout(void) { }
+
+static inline int register_sysfs_loader(void)
+{
+ return 0;
+}
+
+static inline void unregister_sysfs_loader(void)
+{
+}
+#endif /* CONFIG_FW_LOADER_USER_HELPER */
+
+#endif /* __FIRMWARE_FALLBACK_H */
diff --git a/drivers/base/firmware_loader/fallback_table.c b/drivers/base/firmware_loader/fallback_table.c
new file mode 100644
index 000000000000..7428659d8df9
--- /dev/null
+++ b/drivers/base/firmware_loader/fallback_table.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/types.h>
+#include <linux/kconfig.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/security.h>
+#include <linux/highmem.h>
+#include <linux/umh.h>
+#include <linux/sysctl.h>
+
+#include "fallback.h"
+#include "firmware.h"
+
+/*
+ * firmware fallback configuration table
+ */
+
+/* Module or buit-in */
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+
+static unsigned int zero;
+static unsigned int one = 1;
+
+struct firmware_fallback_config fw_fallback_config = {
+ .force_sysfs_fallback = IS_ENABLED(CONFIG_FW_LOADER_USER_HELPER_FALLBACK),
+ .loading_timeout = 60,
+ .old_timeout = 60,
+};
+EXPORT_SYMBOL_GPL(fw_fallback_config);
+
+struct ctl_table firmware_config_table[] = {
+ {
+ .procname = "force_sysfs_fallback",
+ .data = &fw_fallback_config.force_sysfs_fallback,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = proc_douintvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &one,
+ },
+ {
+ .procname = "ignore_sysfs_fallback",
+ .data = &fw_fallback_config.ignore_sysfs_fallback,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = proc_douintvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &one,
+ },
+ { }
+};
+EXPORT_SYMBOL_GPL(firmware_config_table);
+
+#endif
diff --git a/drivers/base/firmware_loader/firmware.h b/drivers/base/firmware_loader/firmware.h
new file mode 100644
index 000000000000..64acbb1a392c
--- /dev/null
+++ b/drivers/base/firmware_loader/firmware.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __FIRMWARE_LOADER_H
+#define __FIRMWARE_LOADER_H
+
+#include <linux/firmware.h>
+#include <linux/types.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/completion.h>
+
+#include <generated/utsrelease.h>
+
+/* firmware behavior options */
+#define FW_OPT_UEVENT (1U << 0)
+#define FW_OPT_NOWAIT (1U << 1)
+#define FW_OPT_USERHELPER (1U << 2)
+#define FW_OPT_NO_WARN (1U << 3)
+#define FW_OPT_NOCACHE (1U << 4)
+#define FW_OPT_NOFALLBACK (1U << 5)
+
+enum fw_status {
+ FW_STATUS_UNKNOWN,
+ FW_STATUS_LOADING,
+ FW_STATUS_DONE,
+ FW_STATUS_ABORTED,
+};
+
+/*
+ * Concurrent request_firmware() for the same firmware need to be
+ * serialized. struct fw_state is simple state machine which hold the
+ * state of the firmware loading.
+ */
+struct fw_state {
+ struct completion completion;
+ enum fw_status status;
+};
+
+struct fw_priv {
+ struct kref ref;
+ struct list_head list;
+ struct firmware_cache *fwc;
+ struct fw_state fw_st;
+ void *data;
+ size_t size;
+ size_t allocated_size;
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+ bool is_paged_buf;
+ bool need_uevent;
+ struct page **pages;
+ int nr_pages;
+ int page_array_size;
+ struct list_head pending_list;
+#endif
+ const char *fw_name;
+};
+
+extern struct mutex fw_lock;
+
+static inline bool __fw_state_check(struct fw_priv *fw_priv,
+ enum fw_status status)
+{
+ struct fw_state *fw_st = &fw_priv->fw_st;
+
+ return fw_st->status == status;
+}
+
+static inline int __fw_state_wait_common(struct fw_priv *fw_priv, long timeout)
+{
+ struct fw_state *fw_st = &fw_priv->fw_st;
+ long ret;
+
+ ret = wait_for_completion_killable_timeout(&fw_st->completion, timeout);
+ if (ret != 0 && fw_st->status == FW_STATUS_ABORTED)
+ return -ENOENT;
+ if (!ret)
+ return -ETIMEDOUT;
+
+ return ret < 0 ? ret : 0;
+}
+
+static inline void __fw_state_set(struct fw_priv *fw_priv,
+ enum fw_status status)
+{
+ struct fw_state *fw_st = &fw_priv->fw_st;
+
+ WRITE_ONCE(fw_st->status, status);
+
+ if (status == FW_STATUS_DONE || status == FW_STATUS_ABORTED)
+ complete_all(&fw_st->completion);
+}
+
+static inline void fw_state_aborted(struct fw_priv *fw_priv)
+{
+ __fw_state_set(fw_priv, FW_STATUS_ABORTED);
+}
+
+static inline bool fw_state_is_aborted(struct fw_priv *fw_priv)
+{
+ return __fw_state_check(fw_priv, FW_STATUS_ABORTED);
+}
+
+static inline void fw_state_start(struct fw_priv *fw_priv)
+{
+ __fw_state_set(fw_priv, FW_STATUS_LOADING);
+}
+
+static inline void fw_state_done(struct fw_priv *fw_priv)
+{
+ __fw_state_set(fw_priv, FW_STATUS_DONE);
+}
+
+int assign_fw(struct firmware *fw, struct device *device,
+ unsigned int opt_flags);
+
+#endif /* __FIRMWARE_LOADER_H */
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_loader/main.c
index 7dd36ace6152..eb34089e4299 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_loader/main.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * firmware_class.c - Multi purpose firmware loading support
+ * main.c - Multi purpose firmware loading support
*
* Copyright (c) 2003 Manuel Estrada Sainz
*
@@ -36,37 +36,14 @@
#include <generated/utsrelease.h>
-#include "base.h"
+#include "../base.h"
+#include "firmware.h"
+#include "fallback.h"
MODULE_AUTHOR("Manuel Estrada Sainz");
MODULE_DESCRIPTION("Multi purpose firmware loading support");
MODULE_LICENSE("GPL");
-enum fw_status {
- FW_STATUS_UNKNOWN,
- FW_STATUS_LOADING,
- FW_STATUS_DONE,
- FW_STATUS_ABORTED,
-};
-
-/*
- * Concurrent request_firmware() for the same firmware need to be
- * serialized. struct fw_state is simple state machine which hold the
- * state of the firmware loading.
- */
-struct fw_state {
- struct completion completion;
- enum fw_status status;
-};
-
-/* firmware behavior options */
-#define FW_OPT_UEVENT (1U << 0)
-#define FW_OPT_NOWAIT (1U << 1)
-#define FW_OPT_USERHELPER (1U << 2)
-#define FW_OPT_NO_WARN (1U << 3)
-#define FW_OPT_NOCACHE (1U << 4)
-#define FW_OPT_NOFALLBACK (1U << 5)
-
struct firmware_cache {
/* firmware_buf instance will be added into the below list */
spinlock_t lock;
@@ -89,25 +66,6 @@ struct firmware_cache {
#endif
};
-struct fw_priv {
- struct kref ref;
- struct list_head list;
- struct firmware_cache *fwc;
- struct fw_state fw_st;
- void *data;
- size_t size;
- size_t allocated_size;
-#ifdef CONFIG_FW_LOADER_USER_HELPER
- bool is_paged_buf;
- bool need_uevent;
- struct page **pages;
- int nr_pages;
- int page_array_size;
- struct list_head pending_list;
-#endif
- const char *fw_name;
-};
-
struct fw_cache_entry {
struct list_head list;
const char *name;
@@ -128,7 +86,7 @@ static inline struct fw_priv *to_fw_priv(struct kref *ref)
/* fw_lock could be moved to 'struct fw_sysfs' but since it is just
* guarding for corner cases a global lock should be OK */
-static DEFINE_MUTEX(fw_lock);
+DEFINE_MUTEX(fw_lock);
static struct firmware_cache fw_cache;
@@ -191,13 +149,6 @@ static inline bool fw_is_builtin_firmware(const struct firmware *fw)
}
#endif
-static int loading_timeout = 60; /* In seconds */
-
-static inline long firmware_loading_timeout(void)
-{
- return loading_timeout > 0 ? loading_timeout * HZ : MAX_JIFFY_OFFSET;
-}
-
static void fw_state_init(struct fw_priv *fw_priv)
{
struct fw_state *fw_st = &fw_priv->fw_st;
@@ -206,83 +157,11 @@ static void fw_state_init(struct fw_priv *fw_priv)
fw_st->status = FW_STATUS_UNKNOWN;
}
-static int __fw_state_wait_common(struct fw_priv *fw_priv, long timeout)
-{
- struct fw_state *fw_st = &fw_priv->fw_st;
- long ret;
-
- ret = wait_for_completion_killable_timeout(&fw_st->completion, timeout);
- if (ret != 0 && fw_st->status == FW_STATUS_ABORTED)
- return -ENOENT;
- if (!ret)
- return -ETIMEDOUT;
-
- return ret < 0 ? ret : 0;
-}
-
-static void __fw_state_set(struct fw_priv *fw_priv,
- enum fw_status status)
-{
- struct fw_state *fw_st = &fw_priv->fw_st;
-
- WRITE_ONCE(fw_st->status, status);
-
- if (status == FW_STATUS_DONE || status == FW_STATUS_ABORTED)
- complete_all(&fw_st->completion);
-}
-
-static inline void fw_state_start(struct fw_priv *fw_priv)
-{
- __fw_state_set(fw_priv, FW_STATUS_LOADING);
-}
-
-static inline void fw_state_done(struct fw_priv *fw_priv)
-{
- __fw_state_set(fw_priv, FW_STATUS_DONE);
-}
-
-static inline void fw_state_aborted(struct fw_priv *fw_priv)
-{
- __fw_state_set(fw_priv, FW_STATUS_ABORTED);
-}
-
static inline int fw_state_wait(struct fw_priv *fw_priv)
{
return __fw_state_wait_common(fw_priv, MAX_SCHEDULE_TIMEOUT);
}
-static bool __fw_state_check(struct fw_priv *fw_priv,
- enum fw_status status)
-{
- struct fw_state *fw_st = &fw_priv->fw_st;
-
- return fw_st->status == status;
-}
-
-static inline bool fw_state_is_aborted(struct fw_priv *fw_priv)
-{
- return __fw_state_check(fw_priv, FW_STATUS_ABORTED);
-}
-
-#ifdef CONFIG_FW_LOADER_USER_HELPER
-
-static inline bool fw_sysfs_done(struct fw_priv *fw_priv)
-{
- return __fw_state_check(fw_priv, FW_STATUS_DONE);
-}
-
-static inline bool fw_sysfs_loading(struct fw_priv *fw_priv)
-{
- return __fw_state_check(fw_priv, FW_STATUS_LOADING);
-}
-
-static inline int fw_sysfs_wait_timeout(struct fw_priv *fw_priv, long timeout)
-{
- return __fw_state_wait_common(fw_priv, timeout);
-}
-
-#endif /* CONFIG_FW_LOADER_USER_HELPER */
-
static int fw_cache_piggyback_on_request(const char *name);
static struct fw_priv *__allocate_fw_priv(const char *fw_name,
@@ -517,14 +396,24 @@ static struct fw_name_devm *fw_find_devm_name(struct device *dev,
return fwn;
}
-/* add firmware name into devres list */
-static int fw_add_devm_name(struct device *dev, const char *name)
+static bool fw_cache_is_setup(struct device *dev, const char *name)
{
struct fw_name_devm *fwn;
fwn = fw_find_devm_name(dev, name);
if (fwn)
- return 1;
+ return true;
+
+ return false;
+}
+
+/* add firmware name into devres list */
+static int fw_add_devm_name(struct device *dev, const char *name)
+{
+ struct fw_name_devm *fwn;
+
+ if (fw_cache_is_setup(dev, name))
+ return 0;
fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm),
GFP_KERNEL);
@@ -542,16 +431,22 @@ static int fw_add_devm_name(struct device *dev, const char *name)
return 0;
}
#else
+static bool fw_cache_is_setup(struct device *dev, const char *name)
+{
+ return false;
+}
+
static int fw_add_devm_name(struct device *dev, const char *name)
{
return 0;
}
#endif
-static int assign_fw(struct firmware *fw, struct device *device,
- unsigned int opt_flags)
+int assign_fw(struct firmware *fw, struct device *device,
+ unsigned int opt_flags)
{
struct fw_priv *fw_priv = fw->priv;
+ int ret;
mutex_lock(&fw_lock);
if (!fw_priv->size || fw_state_is_aborted(fw_priv)) {
@@ -568,8 +463,13 @@ static int assign_fw(struct firmware *fw, struct device *device,
*/
/* don't cache firmware handled without uevent */
if (device && (opt_flags & FW_OPT_UEVENT) &&
- !(opt_flags & FW_OPT_NOCACHE))
- fw_add_devm_name(device, fw_priv->fw_name);
+ !(opt_flags & FW_OPT_NOCACHE)) {
+ ret = fw_add_devm_name(device, fw_priv->fw_name);
+ if (ret) {
+ mutex_unlock(&fw_lock);
+ return ret;
+ }
+ }
/*
* After caching firmware image is started, let it piggyback
@@ -587,626 +487,6 @@ static int assign_fw(struct firmware *fw, struct device *device,
return 0;
}
-/*
- * user-mode helper code
- */
-#ifdef CONFIG_FW_LOADER_USER_HELPER
-struct fw_sysfs {
- bool nowait;
- struct device dev;
- struct fw_priv *fw_priv;
- struct firmware *fw;
-};
-
-static struct fw_sysfs *to_fw_sysfs(struct device *dev)
-{
- return container_of(dev, struct fw_sysfs, dev);
-}
-
-static void __fw_load_abort(struct fw_priv *fw_priv)
-{
- /*
- * There is a small window in which user can write to 'loading'
- * between loading done and disappearance of 'loading'
- */
- if (fw_sysfs_done(fw_priv))
- return;
-
- list_del_init(&fw_priv->pending_list);
- fw_state_aborted(fw_priv);
-}
-
-static void fw_load_abort(struct fw_sysfs *fw_sysfs)
-{
- struct fw_priv *fw_priv = fw_sysfs->fw_priv;
-
- __fw_load_abort(fw_priv);
-}
-
-static LIST_HEAD(pending_fw_head);
-
-static void kill_pending_fw_fallback_reqs(bool only_kill_custom)
-{
- struct fw_priv *fw_priv;
- struct fw_priv *next;
-
- mutex_lock(&fw_lock);
- list_for_each_entry_safe(fw_priv, next, &pending_fw_head,
- pending_list) {
- if (!fw_priv->need_uevent || !only_kill_custom)
- __fw_load_abort(fw_priv);
- }
- mutex_unlock(&fw_lock);
-}
-
-static ssize_t timeout_show(struct class *class, struct class_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%d\n", loading_timeout);
-}
-
-/**
- * firmware_timeout_store - set number of seconds to wait for firmware
- * @class: device class pointer
- * @attr: device attribute pointer
- * @buf: buffer to scan for timeout value
- * @count: number of bytes in @buf
- *
- * Sets the number of seconds to wait for the firmware. Once
- * this expires an error will be returned to the driver and no
- * firmware will be provided.
- *
- * Note: zero means 'wait forever'.
- **/
-static ssize_t timeout_store(struct class *class, struct class_attribute *attr,
- const char *buf, size_t count)
-{
- loading_timeout = simple_strtol(buf, NULL, 10);
- if (loading_timeout < 0)
- loading_timeout = 0;
-
- return count;
-}
-static CLASS_ATTR_RW(timeout);
-
-static struct attribute *firmware_class_attrs[] = {
- &class_attr_timeout.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(firmware_class);
-
-static void fw_dev_release(struct device *dev)
-{
- struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);
-
- kfree(fw_sysfs);
-}
-
-static int do_firmware_uevent(struct fw_sysfs *fw_sysfs, struct kobj_uevent_env *env)
-{
- if (add_uevent_var(env, "FIRMWARE=%s", fw_sysfs->fw_priv->fw_name))
- return -ENOMEM;
- if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
- return -ENOMEM;
- if (add_uevent_var(env, "ASYNC=%d", fw_sysfs->nowait))
- return -ENOMEM;
-
- return 0;
-}
-
-static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);
- int err = 0;
-
- mutex_lock(&fw_lock);
- if (fw_sysfs->fw_priv)
- err = do_firmware_uevent(fw_sysfs, env);
- mutex_unlock(&fw_lock);
- return err;
-}
-
-static struct class firmware_class = {
- .name = "firmware",
- .class_groups = firmware_class_groups,
- .dev_uevent = firmware_uevent,
- .dev_release = fw_dev_release,
-};
-
-static inline int register_sysfs_loader(void)
-{
- return class_register(&firmware_class);
-}
-
-static inline void unregister_sysfs_loader(void)
-{
- class_unregister(&firmware_class);
-}
-
-static ssize_t firmware_loading_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);
- int loading = 0;
-
- mutex_lock(&fw_lock);
- if (fw_sysfs->fw_priv)
- loading = fw_sysfs_loading(fw_sysfs->fw_priv);
- mutex_unlock(&fw_lock);
-
- return sprintf(buf, "%d\n", loading);
-}
-
-/* Some architectures don't have PAGE_KERNEL_RO */
-#ifndef PAGE_KERNEL_RO
-#define PAGE_KERNEL_RO PAGE_KERNEL
-#endif
-
-/* one pages buffer should be mapped/unmapped only once */
-static int map_fw_priv_pages(struct fw_priv *fw_priv)
-{
- if (!fw_priv->is_paged_buf)
- return 0;
-
- vunmap(fw_priv->data);
- fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0,
- PAGE_KERNEL_RO);
- if (!fw_priv->data)
- return -ENOMEM;
- return 0;
-}
-
-/**
- * firmware_loading_store - set value in the 'loading' control file
- * @dev: device pointer
- * @attr: device attribute pointer
- * @buf: buffer to scan for loading control value
- * @count: number of bytes in @buf
- *
- * The relevant values are:
- *
- * 1: Start a load, discarding any previous partial load.
- * 0: Conclude the load and hand the data to the driver code.
- * -1: Conclude the load with an error and discard any written data.
- **/
-static ssize_t firmware_loading_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);
- struct fw_priv *fw_priv;
- ssize_t written = count;
- int loading = simple_strtol(buf, NULL, 10);
- int i;
-
- mutex_lock(&fw_lock);
- fw_priv = fw_sysfs->fw_priv;
- if (fw_state_is_aborted(fw_priv))
- goto out;
-
- switch (loading) {
- case 1:
- /* discarding any previous partial load */
- if (!fw_sysfs_done(fw_priv)) {
- for (i = 0; i < fw_priv->nr_pages; i++)
- __free_page(fw_priv->pages[i]);
- vfree(fw_priv->pages);
- fw_priv->pages = NULL;
- fw_priv->page_array_size = 0;
- fw_priv->nr_pages = 0;
- fw_state_start(fw_priv);
- }
- break;
- case 0:
- if (fw_sysfs_loading(fw_priv)) {
- int rc;
-
- /*
- * Several loading requests may be pending on
- * one same firmware buf, so let all requests
- * see the mapped 'buf->data' once the loading
- * is completed.
- * */
- rc = map_fw_priv_pages(fw_priv);
- if (rc)
- dev_err(dev, "%s: map pages failed\n",
- __func__);
- else
- rc = security_kernel_post_read_file(NULL,
- fw_priv->data, fw_priv->size,
- READING_FIRMWARE);
-
- /*
- * Same logic as fw_load_abort, only the DONE bit
- * is ignored and we set ABORT only on failure.
- */
- list_del_init(&fw_priv->pending_list);
- if (rc) {
- fw_state_aborted(fw_priv);
- written = rc;
- } else {
- fw_state_done(fw_priv);
- }
- break;
- }
- /* fallthrough */
- default:
- dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading);
- /* fallthrough */
- case -1:
- fw_load_abort(fw_sysfs);
- break;
- }
-out:
- mutex_unlock(&fw_lock);
- return written;
-}
-
-static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
-
-static void firmware_rw_data(struct fw_priv *fw_priv, char *buffer,
- loff_t offset, size_t count, bool read)
-{
- if (read)
- memcpy(buffer, fw_priv->data + offset, count);
- else
- memcpy(fw_priv->data + offset, buffer, count);
-}
-
-static void firmware_rw(struct fw_priv *fw_priv, char *buffer,
- loff_t offset, size_t count, bool read)
-{
- while (count) {
- void *page_data;
- int page_nr = offset >> PAGE_SHIFT;
- int page_ofs = offset & (PAGE_SIZE-1);
- int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
-
- page_data = kmap(fw_priv->pages[page_nr]);
-
- if (read)
- memcpy(buffer, page_data + page_ofs, page_cnt);
- else
- memcpy(page_data + page_ofs, buffer, page_cnt);
-
- kunmap(fw_priv->pages[page_nr]);
- buffer += page_cnt;
- offset += page_cnt;
- count -= page_cnt;
- }
-}
-
-static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buffer, loff_t offset, size_t count)
-{
- struct device *dev = kobj_to_dev(kobj);
- struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);
- struct fw_priv *fw_priv;
- ssize_t ret_count;
-
- mutex_lock(&fw_lock);
- fw_priv = fw_sysfs->fw_priv;
- if (!fw_priv || fw_sysfs_done(fw_priv)) {
- ret_count = -ENODEV;
- goto out;
- }
- if (offset > fw_priv->size) {
- ret_count = 0;
- goto out;
- }
- if (count > fw_priv->size - offset)
- count = fw_priv->size - offset;
-
- ret_count = count;
-
- if (fw_priv->data)
- firmware_rw_data(fw_priv, buffer, offset, count, true);
- else
- firmware_rw(fw_priv, buffer, offset, count, true);
-
-out:
- mutex_unlock(&fw_lock);
- return ret_count;
-}
-
-static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size)
-{
- struct fw_priv *fw_priv= fw_sysfs->fw_priv;
- int pages_needed = PAGE_ALIGN(min_size) >> PAGE_SHIFT;
-
- /* If the array of pages is too small, grow it... */
- if (fw_priv->page_array_size < pages_needed) {
- int new_array_size = max(pages_needed,
- fw_priv->page_array_size * 2);
- struct page **new_pages;
-
- new_pages = vmalloc(new_array_size * sizeof(void *));
- if (!new_pages) {
- fw_load_abort(fw_sysfs);
- return -ENOMEM;
- }
- memcpy(new_pages, fw_priv->pages,
- fw_priv->page_array_size * sizeof(void *));
- memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
- (new_array_size - fw_priv->page_array_size));
- vfree(fw_priv->pages);
- fw_priv->pages = new_pages;
- fw_priv->page_array_size = new_array_size;
- }
-
- while (fw_priv->nr_pages < pages_needed) {
- fw_priv->pages[fw_priv->nr_pages] =
- alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
-
- if (!fw_priv->pages[fw_priv->nr_pages]) {
- fw_load_abort(fw_sysfs);
- return -ENOMEM;
- }
- fw_priv->nr_pages++;
- }
- return 0;
-}
-
-/**
- * firmware_data_write - write method for firmware
- * @filp: open sysfs file
- * @kobj: kobject for the device
- * @bin_attr: bin_attr structure
- * @buffer: buffer being written
- * @offset: buffer offset for write in total data store area
- * @count: buffer size
- *
- * Data written to the 'data' attribute will be later handed to
- * the driver as a firmware image.
- **/
-static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buffer, loff_t offset, size_t count)
-{
- struct device *dev = kobj_to_dev(kobj);
- struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);
- struct fw_priv *fw_priv;
- ssize_t retval;
-
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
-
- mutex_lock(&fw_lock);
- fw_priv = fw_sysfs->fw_priv;
- if (!fw_priv || fw_sysfs_done(fw_priv)) {
- retval = -ENODEV;
- goto out;
- }
-
- if (fw_priv->data) {
- if (offset + count > fw_priv->allocated_size) {
- retval = -ENOMEM;
- goto out;
- }
- firmware_rw_data(fw_priv, buffer, offset, count, false);
- retval = count;
- } else {
- retval = fw_realloc_pages(fw_sysfs, offset + count);
- if (retval)
- goto out;
-
- retval = count;
- firmware_rw(fw_priv, buffer, offset, count, false);
- }
-
- fw_priv->size = max_t(size_t, offset + count, fw_priv->size);
-out:
- mutex_unlock(&fw_lock);
- return retval;
-}
-
-static struct bin_attribute firmware_attr_data = {
- .attr = { .name = "data", .mode = 0644 },
- .size = 0,
- .read = firmware_data_read,
- .write = firmware_data_write,
-};
-
-static struct attribute *fw_dev_attrs[] = {
- &dev_attr_loading.attr,
- NULL
-};
-
-static struct bin_attribute *fw_dev_bin_attrs[] = {
- &firmware_attr_data,
- NULL
-};
-
-static const struct attribute_group fw_dev_attr_group = {
- .attrs = fw_dev_attrs,
- .bin_attrs = fw_dev_bin_attrs,
-};
-
-static const struct attribute_group *fw_dev_attr_groups[] = {
- &fw_dev_attr_group,
- NULL
-};
-
-static struct fw_sysfs *
-fw_create_instance(struct firmware *firmware, const char *fw_name,
- struct device *device, unsigned int opt_flags)
-{
- struct fw_sysfs *fw_sysfs;
- struct device *f_dev;
-
- fw_sysfs = kzalloc(sizeof(*fw_sysfs), GFP_KERNEL);
- if (!fw_sysfs) {
- fw_sysfs = ERR_PTR(-ENOMEM);
- goto exit;
- }
-
- fw_sysfs->nowait = !!(opt_flags & FW_OPT_NOWAIT);
- fw_sysfs->fw = firmware;
- f_dev = &fw_sysfs->dev;
-
- device_initialize(f_dev);
- dev_set_name(f_dev, "%s", fw_name);
- f_dev->parent = device;
- f_dev->class = &firmware_class;
- f_dev->groups = fw_dev_attr_groups;
-exit:
- return fw_sysfs;
-}
-
-/* load a firmware via user helper */
-static int _request_firmware_load(struct fw_sysfs *fw_sysfs,
- unsigned int opt_flags, long timeout)
-{
- int retval = 0;
- struct device *f_dev = &fw_sysfs->dev;
- struct fw_priv *fw_priv = fw_sysfs->fw_priv;
-
- /* fall back on userspace loading */
- if (!fw_priv->data)
- fw_priv->is_paged_buf = true;
-
- dev_set_uevent_suppress(f_dev, true);
-
- retval = device_add(f_dev);
- if (retval) {
- dev_err(f_dev, "%s: device_register failed\n", __func__);
- goto err_put_dev;
- }
-
- mutex_lock(&fw_lock);
- list_add(&fw_priv->pending_list, &pending_fw_head);
- mutex_unlock(&fw_lock);
-
- if (opt_flags & FW_OPT_UEVENT) {
- fw_priv->need_uevent = true;
- dev_set_uevent_suppress(f_dev, false);
- dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_name);
- kobject_uevent(&fw_sysfs->dev.kobj, KOBJ_ADD);
- } else {
- timeout = MAX_JIFFY_OFFSET;
- }
-
- retval = fw_sysfs_wait_timeout(fw_priv, timeout);
- if (retval < 0) {
- mutex_lock(&fw_lock);
- fw_load_abort(fw_sysfs);
- mutex_unlock(&fw_lock);
- }
-
- if (fw_state_is_aborted(fw_priv)) {
- if (retval == -ERESTARTSYS)
- retval = -EINTR;
- else
- retval = -EAGAIN;
- } else if (fw_priv->is_paged_buf && !fw_priv->data)
- retval = -ENOMEM;
-
- device_del(f_dev);
-err_put_dev:
- put_device(f_dev);
- return retval;
-}
-
-static int fw_load_from_user_helper(struct firmware *firmware,
- const char *name, struct device *device,
- unsigned int opt_flags)
-{
- struct fw_sysfs *fw_sysfs;
- long timeout;
- int ret;
-
- timeout = firmware_loading_timeout();
- if (opt_flags & FW_OPT_NOWAIT) {
- timeout = usermodehelper_read_lock_wait(timeout);
- if (!timeout) {
- dev_dbg(device, "firmware: %s loading timed out\n",
- name);
- return -EBUSY;
- }
- } else {
- ret = usermodehelper_read_trylock();
- if (WARN_ON(ret)) {
- dev_err(device, "firmware: %s will not be loaded\n",
- name);
- return ret;
- }
- }
-
- fw_sysfs = fw_create_instance(firmware, name, device, opt_flags);
- if (IS_ERR(fw_sysfs)) {
- ret = PTR_ERR(fw_sysfs);
- goto out_unlock;
- }
-
- fw_sysfs->fw_priv = firmware->priv;
- ret = _request_firmware_load(fw_sysfs, opt_flags, timeout);
-
- if (!ret)
- ret = assign_fw(firmware, device, opt_flags);
-
-out_unlock:
- usermodehelper_read_unlock();
-
- return ret;
-}
-
-#ifdef CONFIG_FW_LOADER_USER_HELPER_FALLBACK
-static bool fw_force_sysfs_fallback(unsigned int opt_flags)
-{
- return true;
-}
-#else
-static bool fw_force_sysfs_fallback(unsigned int opt_flags)
-{
- if (!(opt_flags & FW_OPT_USERHELPER))
- return false;
- return true;
-}
-#endif
-
-static bool fw_run_sysfs_fallback(unsigned int opt_flags)
-{
- if ((opt_flags & FW_OPT_NOFALLBACK))
- return false;
-
- return fw_force_sysfs_fallback(opt_flags);
-}
-
-static int fw_sysfs_fallback(struct firmware *fw, const char *name,
- struct device *device,
- unsigned int opt_flags,
- int ret)
-{
- if (!fw_run_sysfs_fallback(opt_flags))
- return ret;
-
- dev_warn(device, "Falling back to user helper\n");
- return fw_load_from_user_helper(fw, name, device, opt_flags);
-}
-#else /* CONFIG_FW_LOADER_USER_HELPER */
-static int fw_sysfs_fallback(struct firmware *fw, const char *name,
- struct device *device,
- unsigned int opt_flags,
- int ret)
-{
- /* Keep carrying over the same error */
- return ret;
-}
-
-static inline void kill_pending_fw_fallback_reqs(bool only_kill_custom) { }
-
-static inline int register_sysfs_loader(void)
-{
- return 0;
-}
-
-static inline void unregister_sysfs_loader(void)
-{
-}
-
-#endif /* CONFIG_FW_LOADER_USER_HELPER */
-
/* prepare firmware and firmware_buf structs;
* return 0 if a firmware is already assigned, 1 if need to load one,
* or a negative error code
@@ -1377,6 +657,30 @@ int request_firmware_direct(const struct firmware **firmware_p,
EXPORT_SYMBOL_GPL(request_firmware_direct);
/**
+ * firmware_request_cache: - cache firmware for suspend so resume can use it
+ * @name: name of firmware file
+ * @device: device for which firmware should be cached for
+ *
+ * There are some devices with an optimization that enables the device to not
+ * require loading firmware on system reboot. This optimization may still
+ * require the firmware present on resume from suspend. This routine can be
+ * used to ensure the firmware is present on resume from suspend in these
+ * situations. This helper is not compatible with drivers which use
+ * request_firmware_into_buf() or request_firmware_nowait() with no uevent set.
+ **/
+int firmware_request_cache(struct device *device, const char *name)
+{
+ int ret;
+
+ mutex_lock(&fw_lock);
+ ret = fw_add_devm_name(device, name);
+ mutex_unlock(&fw_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(firmware_request_cache);
+
+/**
* request_firmware_into_buf - load firmware into a previously allocated buffer
* @firmware_p: pointer to firmware image
* @name: name of firmware file
@@ -1397,6 +701,9 @@ request_firmware_into_buf(const struct firmware **firmware_p, const char *name,
{
int ret;
+ if (fw_cache_is_setup(device, name))
+ return -EOPNOTSUPP;
+
__module_get(THIS_MODULE);
ret = _request_firmware(firmware_p, name, device, buf, size,
FW_OPT_UEVENT | FW_OPT_NOCACHE);
@@ -1494,6 +801,12 @@ request_firmware_nowait(
fw_work->opt_flags = FW_OPT_NOWAIT |
(uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER);
+ if (!uevent && fw_cache_is_setup(device, name)) {
+ kfree_const(fw_work->name);
+ kfree(fw_work);
+ return -EOPNOTSUPP;
+ }
+
if (!try_module_get(module)) {
kfree_const(fw_work->name);
kfree(fw_work);
@@ -1741,7 +1054,6 @@ static void __device_uncache_fw_images(void)
static void device_cache_fw_images(void)
{
struct firmware_cache *fwc = &fw_cache;
- int old_timeout;
DEFINE_WAIT(wait);
pr_debug("%s\n", __func__);
@@ -1749,16 +1061,7 @@ static void device_cache_fw_images(void)
/* cancel uncache work */
cancel_delayed_work_sync(&fwc->work);
- /*
- * use small loading timeout for caching devices' firmware
- * because all these firmware images have been loaded
- * successfully at lease once, also system is ready for
- * completing firmware loading now. The maximum size of
- * firmware in current distributions is about 2M bytes,
- * so 10 secs should be enough.
- */
- old_timeout = loading_timeout;
- loading_timeout = 10;
+ fw_fallback_set_cache_timeout();
mutex_lock(&fw_lock);
fwc->state = FW_LOADER_START_CACHE;
@@ -1768,7 +1071,7 @@ static void device_cache_fw_images(void)
/* wait for completion of caching firmware for all devices */
async_synchronize_full_domain(&fw_cache_domain);
- loading_timeout = old_timeout;
+ fw_fallback_set_default_timeout();
}
/**
diff --git a/drivers/base/node.c b/drivers/base/node.c
index ee090ab9171c..c5f81fc621ac 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -315,7 +315,9 @@ static int register_node(struct node *node, int num)
node->dev.groups = node_dev_groups;
error = device_register(&node->dev);
- if (!error){
+ if (error)
+ put_device(&node->dev);
+ else {
hugetlb_register_node(node);
compaction_register_node(node);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index f1bf7b38d91c..8075ddc70a17 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -1153,8 +1153,10 @@ int __init platform_bus_init(void)
early_platform_cleanup();
error = device_register(&platform_bus);
- if (error)
+ if (error) {
+ put_device(&platform_bus);
return error;
+ }
error = bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
diff --git a/drivers/base/soc.c b/drivers/base/soc.c
index 4e80f48ad5d6..10b280f30217 100644
--- a/drivers/base/soc.c
+++ b/drivers/base/soc.c
@@ -150,6 +150,8 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr
out3:
ida_simple_remove(&soc_ida, soc_dev->soc_dev_num);
+ put_device(&soc_dev->dev);
+ soc_dev = NULL;
out2:
kfree(soc_dev);
out1:
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 57e011d36a79..769599bc1bab 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -199,4 +199,6 @@ config DA8XX_MSTPRI
configuration. Allows to adjust the priorities of all master
peripherals.
+source "drivers/bus/fsl-mc/Kconfig"
+
endmenu
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index 9bcd0bf3954b..b666c49f249e 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -8,6 +8,10 @@ obj-$(CONFIG_ARM_CCI) += arm-cci.o
obj-$(CONFIG_ARM_CCN) += arm-ccn.o
obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o
+
+# DPAA2 fsl-mc bus
+obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/
+
obj-$(CONFIG_IMX_WEIM) += imx-weim.o
obj-$(CONFIG_MIPS_CDMM) += mips_cdmm.o
obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o
diff --git a/drivers/bus/fsl-mc/Kconfig b/drivers/bus/fsl-mc/Kconfig
new file mode 100644
index 000000000000..c23c77c9b705
--- /dev/null
+++ b/drivers/bus/fsl-mc/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# DPAA2 fsl-mc bus
+#
+# Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
+#
+
+config FSL_MC_BUS
+ bool "QorIQ DPAA2 fsl-mc bus driver"
+ depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86_LOCAL_APIC || PPC)))
+ select GENERIC_MSI_IRQ_DOMAIN
+ help
+ Driver to enable the bus infrastructure for the QorIQ DPAA2
+ architecture. The fsl-mc bus driver handles discovery of
+ DPAA2 objects (which are represented as Linux devices) and
+ binding objects to drivers.
diff --git a/drivers/bus/fsl-mc/Makefile b/drivers/bus/fsl-mc/Makefile
new file mode 100644
index 000000000000..3c518c7e8374
--- /dev/null
+++ b/drivers/bus/fsl-mc/Makefile
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Freescale Management Complex (MC) bus drivers
+#
+# Copyright (C) 2014 Freescale Semiconductor, Inc.
+#
+obj-$(CONFIG_FSL_MC_BUS) += mc-bus-driver.o
+
+mc-bus-driver-objs := fsl-mc-bus.o \
+ mc-sys.o \
+ mc-io.o \
+ dpbp.o \
+ dpcon.o \
+ dprc.o \
+ dprc-driver.o \
+ fsl-mc-allocator.o \
+ fsl-mc-msi.o \
+ dpmcp.o
diff --git a/drivers/staging/fsl-mc/bus/dpbp.c b/drivers/bus/fsl-mc/dpbp.c
index a4df84668d5b..17e3c5d2f22e 100644
--- a/drivers/staging/fsl-mc/bus/dpbp.c
+++ b/drivers/bus/fsl-mc/dpbp.c
@@ -4,10 +4,10 @@
*
*/
#include <linux/kernel.h>
-#include "../include/mc.h"
-#include "../include/dpbp.h"
+#include <linux/fsl/mc.h>
+#include <linux/fsl/mc.h>
-#include "dpbp-cmd.h"
+#include "fsl-mc-private.h"
/**
* dpbp_open() - Open a control session for the specified object.
@@ -31,7 +31,7 @@ int dpbp_open(struct fsl_mc_io *mc_io,
int dpbp_id,
u16 *token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpbp_cmd_open *cmd_params;
int err;
@@ -68,7 +68,7 @@ int dpbp_close(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPBP_CMDID_CLOSE, cmd_flags,
@@ -91,7 +91,7 @@ int dpbp_enable(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPBP_CMDID_ENABLE, cmd_flags,
@@ -114,7 +114,7 @@ int dpbp_disable(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPBP_CMDID_DISABLE,
@@ -126,40 +126,6 @@ int dpbp_disable(struct fsl_mc_io *mc_io,
EXPORT_SYMBOL_GPL(dpbp_disable);
/**
- * dpbp_is_enabled() - Check if the DPBP is enabled.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPBP object
- * @en: Returns '1' if object is enabled; '0' otherwise
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpbp_is_enabled(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int *en)
-{
- struct mc_command cmd = { 0 };
- struct dpbp_rsp_is_enabled *rsp_params;
- int err;
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPBP_CMDID_IS_ENABLED, cmd_flags,
- token);
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dpbp_rsp_is_enabled *)cmd.params;
- *en = rsp_params->enabled & DPBP_ENABLE;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(dpbp_is_enabled);
-
-/**
* dpbp_reset() - Reset the DPBP, returns the object to initial state.
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
@@ -171,7 +137,7 @@ int dpbp_reset(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPBP_CMDID_RESET,
@@ -197,7 +163,7 @@ int dpbp_get_attributes(struct fsl_mc_io *mc_io,
u16 token,
struct dpbp_attr *attr)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpbp_rsp_get_attributes *rsp_params;
int err;
@@ -218,36 +184,3 @@ int dpbp_get_attributes(struct fsl_mc_io *mc_io,
return 0;
}
EXPORT_SYMBOL_GPL(dpbp_get_attributes);
-
-/**
- * dpbp_get_api_version - Get Data Path Buffer Pool API version
- * @mc_io: Pointer to Mc portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @major_ver: Major version of Buffer Pool API
- * @minor_ver: Minor version of Buffer Pool API
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpbp_get_api_version(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 *major_ver,
- u16 *minor_ver)
-{
- struct mc_command cmd = { 0 };
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_API_VERSION,
- cmd_flags, 0);
-
- /* send command to mc */
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- mc_cmd_read_api_version(&cmd, major_ver, minor_ver);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(dpbp_get_api_version);
diff --git a/drivers/staging/fsl-mc/bus/dpcon.c b/drivers/bus/fsl-mc/dpcon.c
index 8f84d7b5465c..760555d7946e 100644
--- a/drivers/staging/fsl-mc/bus/dpcon.c
+++ b/drivers/bus/fsl-mc/dpcon.c
@@ -4,10 +4,10 @@
*
*/
#include <linux/kernel.h>
-#include "../include/mc.h"
-#include "../include/dpcon.h"
+#include <linux/fsl/mc.h>
+#include <linux/fsl/mc.h>
-#include "dpcon-cmd.h"
+#include "fsl-mc-private.h"
/**
* dpcon_open() - Open a control session for the specified object
@@ -31,7 +31,7 @@ int dpcon_open(struct fsl_mc_io *mc_io,
int dpcon_id,
u16 *token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpcon_cmd_open *dpcon_cmd;
int err;
@@ -69,7 +69,7 @@ int dpcon_close(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPCON_CMDID_CLOSE,
@@ -93,7 +93,7 @@ int dpcon_enable(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPCON_CMDID_ENABLE,
@@ -117,7 +117,7 @@ int dpcon_disable(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPCON_CMDID_DISABLE,
@@ -141,7 +141,7 @@ int dpcon_reset(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPCON_CMDID_RESET,
@@ -166,7 +166,7 @@ int dpcon_get_attributes(struct fsl_mc_io *mc_io,
u16 token,
struct dpcon_attr *attr)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpcon_rsp_get_attr *dpcon_rsp;
int err;
@@ -204,7 +204,7 @@ int dpcon_set_notification(struct fsl_mc_io *mc_io,
u16 token,
struct dpcon_notification_cfg *cfg)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpcon_cmd_set_notification *dpcon_cmd;
/* prepare command */
diff --git a/drivers/staging/fsl-mc/bus/dpmcp.c b/drivers/bus/fsl-mc/dpmcp.c
index be07c77520af..5fbd0dbde24a 100644
--- a/drivers/staging/fsl-mc/bus/dpmcp.c
+++ b/drivers/bus/fsl-mc/dpmcp.c
@@ -4,7 +4,7 @@
*
*/
#include <linux/kernel.h>
-#include "../include/mc.h"
+#include <linux/fsl/mc.h>
#include "fsl-mc-private.h"
@@ -30,7 +30,7 @@ int dpmcp_open(struct fsl_mc_io *mc_io,
int dpmcp_id,
u16 *token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpmcp_cmd_open *cmd_params;
int err;
@@ -66,7 +66,7 @@ int dpmcp_close(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPMCP_CMDID_CLOSE,
@@ -88,7 +88,7 @@ int dpmcp_reset(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPMCP_CMDID_RESET,
diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/bus/fsl-mc/dprc-driver.c
index b09075731e62..52c7e15143d6 100644
--- a/drivers/staging/fsl-mc/bus/dprc-driver.c
+++ b/drivers/bus/fsl-mc/dprc-driver.c
@@ -11,7 +11,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/msi.h>
-#include "../include/mc.h"
+#include <linux/fsl/mc.h>
#include "fsl-mc-private.h"
diff --git a/drivers/staging/fsl-mc/bus/dprc.c b/drivers/bus/fsl-mc/dprc.c
index 97f51726fa7e..1c3f62182266 100644
--- a/drivers/staging/fsl-mc/bus/dprc.c
+++ b/drivers/bus/fsl-mc/dprc.c
@@ -4,7 +4,8 @@
*
*/
#include <linux/kernel.h>
-#include "../include/mc.h"
+#include <linux/fsl/mc.h>
+
#include "fsl-mc-private.h"
/**
@@ -23,7 +24,7 @@ int dprc_open(struct fsl_mc_io *mc_io,
int container_id,
u16 *token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dprc_cmd_open *cmd_params;
int err;
@@ -60,7 +61,7 @@ int dprc_close(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPRC_CMDID_CLOSE, cmd_flags,
@@ -87,7 +88,7 @@ int dprc_set_irq(struct fsl_mc_io *mc_io,
u8 irq_index,
struct dprc_irq_cfg *irq_cfg)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dprc_cmd_set_irq *cmd_params;
/* prepare command */
@@ -125,7 +126,7 @@ int dprc_set_irq_enable(struct fsl_mc_io *mc_io,
u8 irq_index,
u8 en)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dprc_cmd_set_irq_enable *cmd_params;
/* prepare command */
@@ -161,7 +162,7 @@ int dprc_set_irq_mask(struct fsl_mc_io *mc_io,
u8 irq_index,
u32 mask)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dprc_cmd_set_irq_mask *cmd_params;
/* prepare command */
@@ -193,7 +194,7 @@ int dprc_get_irq_status(struct fsl_mc_io *mc_io,
u8 irq_index,
u32 *status)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dprc_cmd_get_irq_status *cmd_params;
struct dprc_rsp_get_irq_status *rsp_params;
int err;
@@ -235,7 +236,7 @@ int dprc_clear_irq_status(struct fsl_mc_io *mc_io,
u8 irq_index,
u32 status)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dprc_cmd_clear_irq_status *cmd_params;
/* prepare command */
@@ -263,7 +264,7 @@ int dprc_get_attributes(struct fsl_mc_io *mc_io,
u16 token,
struct dprc_attributes *attr)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dprc_rsp_get_attributes *rsp_params;
int err;
@@ -301,7 +302,7 @@ int dprc_get_obj_count(struct fsl_mc_io *mc_io,
u16 token,
int *obj_count)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dprc_rsp_get_obj_count *rsp_params;
int err;
@@ -343,7 +344,7 @@ int dprc_get_obj(struct fsl_mc_io *mc_io,
int obj_index,
struct fsl_mc_obj_desc *obj_desc)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dprc_cmd_get_obj *cmd_params;
struct dprc_rsp_get_obj *rsp_params;
int err;
@@ -398,7 +399,7 @@ int dprc_set_obj_irq(struct fsl_mc_io *mc_io,
u8 irq_index,
struct dprc_irq_cfg *irq_cfg)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dprc_cmd_set_obj_irq *cmd_params;
/* prepare command */
@@ -439,7 +440,7 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io,
u8 region_index,
struct dprc_region_desc *region_desc)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dprc_cmd_get_obj_region *cmd_params;
struct dprc_rsp_get_obj_region *rsp_params;
int err;
@@ -481,7 +482,7 @@ int dprc_get_api_version(struct fsl_mc_io *mc_io,
u16 *major_ver,
u16 *minor_ver)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
int err;
/* prepare command */
@@ -511,7 +512,7 @@ int dprc_get_container_id(struct fsl_mc_io *mc_io,
u32 cmd_flags,
int *container_id)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
int err;
/* prepare command */
diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c b/drivers/bus/fsl-mc/fsl-mc-allocator.c
index 8f313a41240b..fb1442b08962 100644
--- a/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c
+++ b/drivers/bus/fsl-mc/fsl-mc-allocator.c
@@ -8,7 +8,7 @@
#include <linux/module.h>
#include <linux/msi.h>
-#include "../include/mc.h"
+#include <linux/fsl/mc.h>
#include "fsl-mc-private.h"
@@ -646,3 +646,8 @@ int __init fsl_mc_allocator_driver_init(void)
{
return fsl_mc_driver_register(&fsl_mc_allocator_driver);
}
+
+void fsl_mc_allocator_driver_exit(void)
+{
+ fsl_mc_driver_unregister(&fsl_mc_allocator_driver);
+}
diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index 1b333c43aae9..5d8266c6571f 100644
--- a/drivers/staging/fsl-mc/bus/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -314,7 +314,7 @@ static int mc_get_version(struct fsl_mc_io *mc_io,
u32 cmd_flags,
struct mc_version *mc_ver_info)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpmng_rsp_get_version *rsp_params;
int err;
diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-msi.c b/drivers/bus/fsl-mc/fsl-mc-msi.c
index 971ad87c584c..ec35e255b496 100644
--- a/drivers/staging/fsl-mc/bus/fsl-mc-msi.c
+++ b/drivers/bus/fsl-mc/fsl-mc-msi.c
@@ -13,6 +13,7 @@
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/msi.h>
+
#include "fsl-mc-private.h"
#ifdef GENERIC_MSI_DOMAIN_OPS
diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-private.h b/drivers/bus/fsl-mc/fsl-mc-private.h
index 83b89d6241f2..ea11b4fe59f7 100644
--- a/drivers/staging/fsl-mc/bus/fsl-mc-private.h
+++ b/drivers/bus/fsl-mc/fsl-mc-private.h
@@ -8,7 +8,7 @@
#ifndef _FSL_MC_PRIVATE_H_
#define _FSL_MC_PRIVATE_H_
-#include "../include/mc.h"
+#include <linux/fsl/mc.h>
#include <linux/mutex.h>
/*
@@ -379,6 +379,93 @@ int dprc_get_container_id(struct fsl_mc_io *mc_io,
u32 cmd_flags,
int *container_id);
+/*
+ * Data Path Buffer Pool (DPBP) API
+ */
+
+/* DPBP Version */
+#define DPBP_VER_MAJOR 3
+#define DPBP_VER_MINOR 2
+
+/* Command versioning */
+#define DPBP_CMD_BASE_VERSION 1
+#define DPBP_CMD_ID_OFFSET 4
+
+#define DPBP_CMD(id) (((id) << DPBP_CMD_ID_OFFSET) | DPBP_CMD_BASE_VERSION)
+
+/* Command IDs */
+#define DPBP_CMDID_CLOSE DPBP_CMD(0x800)
+#define DPBP_CMDID_OPEN DPBP_CMD(0x804)
+
+#define DPBP_CMDID_ENABLE DPBP_CMD(0x002)
+#define DPBP_CMDID_DISABLE DPBP_CMD(0x003)
+#define DPBP_CMDID_GET_ATTR DPBP_CMD(0x004)
+#define DPBP_CMDID_RESET DPBP_CMD(0x005)
+
+struct dpbp_cmd_open {
+ __le32 dpbp_id;
+};
+
+#define DPBP_ENABLE 0x1
+
+struct dpbp_rsp_get_attributes {
+ /* response word 0 */
+ __le16 pad;
+ __le16 bpid;
+ __le32 id;
+ /* response word 1 */
+ __le16 version_major;
+ __le16 version_minor;
+};
+
+/*
+ * Data Path Concentrator (DPCON) API
+ */
+
+/* DPCON Version */
+#define DPCON_VER_MAJOR 3
+#define DPCON_VER_MINOR 2
+
+/* Command versioning */
+#define DPCON_CMD_BASE_VERSION 1
+#define DPCON_CMD_ID_OFFSET 4
+
+#define DPCON_CMD(id) (((id) << DPCON_CMD_ID_OFFSET) | DPCON_CMD_BASE_VERSION)
+
+/* Command IDs */
+#define DPCON_CMDID_CLOSE DPCON_CMD(0x800)
+#define DPCON_CMDID_OPEN DPCON_CMD(0x808)
+
+#define DPCON_CMDID_ENABLE DPCON_CMD(0x002)
+#define DPCON_CMDID_DISABLE DPCON_CMD(0x003)
+#define DPCON_CMDID_GET_ATTR DPCON_CMD(0x004)
+#define DPCON_CMDID_RESET DPCON_CMD(0x005)
+
+#define DPCON_CMDID_SET_NOTIFICATION DPCON_CMD(0x100)
+
+struct dpcon_cmd_open {
+ __le32 dpcon_id;
+};
+
+#define DPCON_ENABLE 1
+
+struct dpcon_rsp_get_attr {
+ /* response word 0 */
+ __le32 id;
+ __le16 qbman_ch_id;
+ u8 num_priorities;
+ u8 pad;
+};
+
+struct dpcon_cmd_set_notification {
+ /* cmd word 0 */
+ __le32 dpio_id;
+ u8 priority;
+ u8 pad[3];
+ /* cmd word 1 */
+ __le64 user_ctx;
+};
+
/**
* Maximum number of total IRQs that can be pre-allocated for an MC bus'
* IRQ pool
@@ -438,6 +525,8 @@ void dprc_driver_exit(void);
int __init fsl_mc_allocator_driver_init(void);
+void fsl_mc_allocator_driver_exit(void);
+
void fsl_mc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev);
void fsl_mc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev);
diff --git a/drivers/staging/fsl-mc/bus/mc-io.c b/drivers/bus/fsl-mc/mc-io.c
index 7e6fb360ef12..7226cfc49b6f 100644
--- a/drivers/staging/fsl-mc/bus/mc-io.c
+++ b/drivers/bus/fsl-mc/mc-io.c
@@ -5,7 +5,7 @@
*/
#include <linux/io.h>
-#include "../include/mc.h"
+#include <linux/fsl/mc.h>
#include "fsl-mc-private.h"
diff --git a/drivers/staging/fsl-mc/bus/mc-sys.c b/drivers/bus/fsl-mc/mc-sys.c
index f09d75d9a976..3221a7fbaf0a 100644
--- a/drivers/staging/fsl-mc/bus/mc-sys.c
+++ b/drivers/bus/fsl-mc/mc-sys.c
@@ -12,7 +12,7 @@
#include <linux/device.h>
#include <linux/io.h>
#include <linux/io-64-nonatomic-hi-lo.h>
-#include "../include/mc.h"
+#include <linux/fsl/mc.h>
#include "fsl-mc-private.h"
@@ -28,14 +28,14 @@
#define MC_CMD_COMPLETION_POLLING_MIN_SLEEP_USECS 10
#define MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS 500
-static enum mc_cmd_status mc_cmd_hdr_read_status(struct mc_command *cmd)
+static enum mc_cmd_status mc_cmd_hdr_read_status(struct fsl_mc_command *cmd)
{
struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header;
return (enum mc_cmd_status)hdr->status;
}
-static u16 mc_cmd_hdr_read_cmdid(struct mc_command *cmd)
+static u16 mc_cmd_hdr_read_cmdid(struct fsl_mc_command *cmd)
{
struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header;
u16 cmd_id = le16_to_cpu(hdr->cmd_id);
@@ -94,8 +94,8 @@ static const char *mc_status_to_string(enum mc_cmd_status status)
* @portal: pointer to an MC portal
* @cmd: pointer to a filled command
*/
-static inline void mc_write_command(struct mc_command __iomem *portal,
- struct mc_command *cmd)
+static inline void mc_write_command(struct fsl_mc_command __iomem *portal,
+ struct fsl_mc_command *cmd)
{
int i;
@@ -121,9 +121,9 @@ static inline void mc_write_command(struct mc_command __iomem *portal,
*
* Returns MC_CMD_STATUS_OK on Success; Error code otherwise.
*/
-static inline enum mc_cmd_status mc_read_response(struct mc_command __iomem *
- portal,
- struct mc_command *resp)
+static inline enum mc_cmd_status mc_read_response(struct fsl_mc_command __iomem
+ *portal,
+ struct fsl_mc_command *resp)
{
int i;
enum mc_cmd_status status;
@@ -156,7 +156,7 @@ static inline enum mc_cmd_status mc_read_response(struct mc_command __iomem *
* @mc_status: MC command completion status
*/
static int mc_polling_wait_preemptible(struct fsl_mc_io *mc_io,
- struct mc_command *cmd,
+ struct fsl_mc_command *cmd,
enum mc_cmd_status *mc_status)
{
enum mc_cmd_status status;
@@ -202,7 +202,7 @@ static int mc_polling_wait_preemptible(struct fsl_mc_io *mc_io,
* @mc_status: MC command completion status
*/
static int mc_polling_wait_atomic(struct fsl_mc_io *mc_io,
- struct mc_command *cmd,
+ struct fsl_mc_command *cmd,
enum mc_cmd_status *mc_status)
{
enum mc_cmd_status status;
@@ -241,7 +241,7 @@ static int mc_polling_wait_atomic(struct fsl_mc_io *mc_io,
*
* Returns '0' on Success; Error code otherwise.
*/
-int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd)
+int mc_send_command(struct fsl_mc_io *mc_io, struct fsl_mc_command *cmd)
{
int error;
enum mc_cmd_status status;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 40947a796666..e538061eadcb 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -236,7 +236,7 @@ source "drivers/char/hw_random/Kconfig"
config NVRAM
tristate "/dev/nvram support"
- depends on ATARI || X86 || (ARM && RTC_DRV_CMOS) || GENERIC_NVRAM
+ depends on ATARI || X86 || GENERIC_NVRAM
---help---
If you say Y here and create a character special file /dev/nvram
with major number 10 and minor number 144 using mknod ("man mknod"),
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 4d0f571c15f9..d53541e96bee 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -452,3 +452,10 @@ config UML_RANDOM
(check your distro, or download from
http://sourceforge.net/projects/gkernel/). rngd periodically reads
/dev/hwrng and injects the entropy into /dev/random.
+
+config HW_RANDOM_KEYSTONE
+ depends on ARCH_KEYSTONE
+ default HW_RANDOM
+ tristate "TI Keystone NETCP SA Hardware random number generator"
+ help
+ This option enables Keystone's hardware random generator.
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index b780370bd4eb..533e913c93d1 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -38,3 +38,4 @@ obj-$(CONFIG_HW_RANDOM_MESON) += meson-rng.o
obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o
obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o
obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o
+obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o
diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c
index 7a84cec30c3a..6767d965c36c 100644
--- a/drivers/char/hw_random/bcm2835-rng.c
+++ b/drivers/char/hw_random/bcm2835-rng.c
@@ -163,6 +163,8 @@ static int bcm2835_rng_probe(struct platform_device *pdev)
/* Clock is optional on most platforms */
priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
priv->rng.name = pdev->name;
priv->rng.init = bcm2835_rng_init;
diff --git a/drivers/char/hw_random/cavium-rng-vf.c b/drivers/char/hw_random/cavium-rng-vf.c
index dd1007aecb10..2d1352b67168 100644
--- a/drivers/char/hw_random/cavium-rng-vf.c
+++ b/drivers/char/hw_random/cavium-rng-vf.c
@@ -77,7 +77,7 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev,
}
/* Remove the VF */
-void cavium_rng_remove_vf(struct pci_dev *pdev)
+static void cavium_rng_remove_vf(struct pci_dev *pdev)
{
struct cavium_rng *rng;
diff --git a/drivers/char/hw_random/cavium-rng.c b/drivers/char/hw_random/cavium-rng.c
index a944e0a47f42..63d6e68c24d2 100644
--- a/drivers/char/hw_random/cavium-rng.c
+++ b/drivers/char/hw_random/cavium-rng.c
@@ -62,7 +62,7 @@ static int cavium_rng_probe(struct pci_dev *pdev,
}
/* Disable VF and RNG Hardware */
-void cavium_rng_remove(struct pci_dev *pdev)
+static void cavium_rng_remove(struct pci_dev *pdev)
{
struct cavium_rng_pf *rng;
diff --git a/drivers/char/hw_random/imx-rngc.c b/drivers/char/hw_random/imx-rngc.c
index eca87249bcff..250123bc4905 100644
--- a/drivers/char/hw_random/imx-rngc.c
+++ b/drivers/char/hw_random/imx-rngc.c
@@ -300,7 +300,7 @@ static int __maybe_unused imx_rngc_resume(struct device *dev)
return 0;
}
-SIMPLE_DEV_PM_OPS(imx_rngc_pm_ops, imx_rngc_suspend, imx_rngc_resume);
+static SIMPLE_DEV_PM_OPS(imx_rngc_pm_ops, imx_rngc_suspend, imx_rngc_resume);
static const struct of_device_id imx_rngc_dt_ids[] = {
{ .compatible = "fsl,imx25-rngb", .data = NULL, },
diff --git a/drivers/char/hw_random/ks-sa-rng.c b/drivers/char/hw_random/ks-sa-rng.c
new file mode 100644
index 000000000000..62c6696c1dbd
--- /dev/null
+++ b/drivers/char/hw_random/ks-sa-rng.c
@@ -0,0 +1,257 @@
+/*
+ * Random Number Generator driver for the Keystone SOC
+ *
+ * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Sandeep Nair
+ * Vitaly Andrianov
+ *
+ * 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/hw_random.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/delay.h>
+
+#define SA_CMD_STATUS_OFS 0x8
+
+/* TRNG enable control in SA System module*/
+#define SA_CMD_STATUS_REG_TRNG_ENABLE BIT(3)
+
+/* TRNG start control in TRNG module */
+#define TRNG_CNTL_REG_TRNG_ENABLE BIT(10)
+
+/* Data ready indicator in STATUS register */
+#define TRNG_STATUS_REG_READY BIT(0)
+
+/* Data ready clear control in INTACK register */
+#define TRNG_INTACK_REG_READY BIT(0)
+
+/*
+ * Number of samples taken to gather entropy during startup.
+ * If value is 0, the number of samples is 2^24 else
+ * equals value times 2^8.
+ */
+#define TRNG_DEF_STARTUP_CYCLES 0
+#define TRNG_CNTL_REG_STARTUP_CYCLES_SHIFT 16
+
+/*
+ * Minimum number of samples taken to regenerate entropy
+ * If value is 0, the number of samples is 2^24 else
+ * equals value times 2^6.
+ */
+#define TRNG_DEF_MIN_REFILL_CYCLES 1
+#define TRNG_CFG_REG_MIN_REFILL_CYCLES_SHIFT 0
+
+/*
+ * Maximum number of samples taken to regenerate entropy
+ * If value is 0, the number of samples is 2^24 else
+ * equals value times 2^8.
+ */
+#define TRNG_DEF_MAX_REFILL_CYCLES 0
+#define TRNG_CFG_REG_MAX_REFILL_CYCLES_SHIFT 16
+
+/* Number of CLK input cycles between samples */
+#define TRNG_DEF_CLK_DIV_CYCLES 0
+#define TRNG_CFG_REG_SAMPLE_DIV_SHIFT 8
+
+/* Maximum retries to get rng data */
+#define SA_MAX_RNG_DATA_RETRIES 5
+/* Delay between retries (in usecs) */
+#define SA_RNG_DATA_RETRY_DELAY 5
+
+struct trng_regs {
+ u32 output_l;
+ u32 output_h;
+ u32 status;
+ u32 intmask;
+ u32 intack;
+ u32 control;
+ u32 config;
+};
+
+struct ks_sa_rng {
+ struct device *dev;
+ struct hwrng rng;
+ struct clk *clk;
+ struct regmap *regmap_cfg;
+ struct trng_regs *reg_rng;
+};
+
+static int ks_sa_rng_init(struct hwrng *rng)
+{
+ u32 value;
+ struct device *dev = (struct device *)rng->priv;
+ struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
+
+ /* Enable RNG module */
+ regmap_write_bits(ks_sa_rng->regmap_cfg, SA_CMD_STATUS_OFS,
+ SA_CMD_STATUS_REG_TRNG_ENABLE,
+ SA_CMD_STATUS_REG_TRNG_ENABLE);
+
+ /* Configure RNG module */
+ writel(0, &ks_sa_rng->reg_rng->control);
+ value = TRNG_DEF_STARTUP_CYCLES << TRNG_CNTL_REG_STARTUP_CYCLES_SHIFT;
+ writel(value, &ks_sa_rng->reg_rng->control);
+
+ value = (TRNG_DEF_MIN_REFILL_CYCLES <<
+ TRNG_CFG_REG_MIN_REFILL_CYCLES_SHIFT) |
+ (TRNG_DEF_MAX_REFILL_CYCLES <<
+ TRNG_CFG_REG_MAX_REFILL_CYCLES_SHIFT) |
+ (TRNG_DEF_CLK_DIV_CYCLES <<
+ TRNG_CFG_REG_SAMPLE_DIV_SHIFT);
+
+ writel(value, &ks_sa_rng->reg_rng->config);
+
+ /* Disable all interrupts from TRNG */
+ writel(0, &ks_sa_rng->reg_rng->intmask);
+
+ /* Enable RNG */
+ value = readl(&ks_sa_rng->reg_rng->control);
+ value |= TRNG_CNTL_REG_TRNG_ENABLE;
+ writel(value, &ks_sa_rng->reg_rng->control);
+
+ return 0;
+}
+
+static void ks_sa_rng_cleanup(struct hwrng *rng)
+{
+ struct device *dev = (struct device *)rng->priv;
+ struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
+
+ /* Disable RNG */
+ writel(0, &ks_sa_rng->reg_rng->control);
+ regmap_write_bits(ks_sa_rng->regmap_cfg, SA_CMD_STATUS_OFS,
+ SA_CMD_STATUS_REG_TRNG_ENABLE, 0);
+}
+
+static int ks_sa_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ struct device *dev = (struct device *)rng->priv;
+ struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
+
+ /* Read random data */
+ data[0] = readl(&ks_sa_rng->reg_rng->output_l);
+ data[1] = readl(&ks_sa_rng->reg_rng->output_h);
+
+ writel(TRNG_INTACK_REG_READY, &ks_sa_rng->reg_rng->intack);
+
+ return sizeof(u32) * 2;
+}
+
+static int ks_sa_rng_data_present(struct hwrng *rng, int wait)
+{
+ struct device *dev = (struct device *)rng->priv;
+ struct ks_sa_rng *ks_sa_rng = dev_get_drvdata(dev);
+
+ u32 ready;
+ int j;
+
+ for (j = 0; j < SA_MAX_RNG_DATA_RETRIES; j++) {
+ ready = readl(&ks_sa_rng->reg_rng->status);
+ ready &= TRNG_STATUS_REG_READY;
+
+ if (ready || !wait)
+ break;
+
+ udelay(SA_RNG_DATA_RETRY_DELAY);
+ }
+
+ return ready;
+}
+
+static int ks_sa_rng_probe(struct platform_device *pdev)
+{
+ struct ks_sa_rng *ks_sa_rng;
+ struct device *dev = &pdev->dev;
+ int ret;
+ struct resource *mem;
+
+ ks_sa_rng = devm_kzalloc(dev, sizeof(*ks_sa_rng), GFP_KERNEL);
+ if (!ks_sa_rng)
+ return -ENOMEM;
+
+ ks_sa_rng->dev = dev;
+ ks_sa_rng->rng = (struct hwrng) {
+ .name = "ks_sa_hwrng",
+ .init = ks_sa_rng_init,
+ .data_read = ks_sa_rng_data_read,
+ .data_present = ks_sa_rng_data_present,
+ .cleanup = ks_sa_rng_cleanup,
+ };
+ ks_sa_rng->rng.priv = (unsigned long)dev;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ks_sa_rng->reg_rng = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(ks_sa_rng->reg_rng))
+ return PTR_ERR(ks_sa_rng->reg_rng);
+
+ ks_sa_rng->regmap_cfg =
+ syscon_regmap_lookup_by_phandle(dev->of_node,
+ "ti,syscon-sa-cfg");
+
+ if (IS_ERR(ks_sa_rng->regmap_cfg)) {
+ dev_err(dev, "syscon_node_to_regmap failed\n");
+ return -EINVAL;
+ }
+
+ pm_runtime_enable(dev);
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable SA power-domain\n");
+ pm_runtime_disable(dev);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, ks_sa_rng);
+
+ return devm_hwrng_register(&pdev->dev, &ks_sa_rng->rng);
+}
+
+static int ks_sa_rng_remove(struct platform_device *pdev)
+{
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id ks_sa_rng_dt_match[] = {
+ {
+ .compatible = "ti,keystone-rng",
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ks_sa_rng_dt_match);
+
+static struct platform_driver ks_sa_rng_driver = {
+ .driver = {
+ .name = "ks-sa-rng",
+ .of_match_table = ks_sa_rng_dt_match,
+ },
+ .probe = ks_sa_rng_probe,
+ .remove = ks_sa_rng_remove,
+};
+
+module_platform_driver(ks_sa_rng_driver);
+
+MODULE_DESCRIPTION("Keystone NETCP SA H/W Random Number Generator driver");
+MODULE_AUTHOR("Vitaly Andrianov <vitalya@ti.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/mxc-rnga.c b/drivers/char/hw_random/mxc-rnga.c
index 467362262651..f83bee513d91 100644
--- a/drivers/char/hw_random/mxc-rnga.c
+++ b/drivers/char/hw_random/mxc-rnga.c
@@ -16,16 +16,13 @@
* This driver is based on other RNG drivers.
*/
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/hw_random.h>
#include <linux/delay.h>
+#include <linux/hw_random.h>
#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
/* RNGA Registers */
#define RNGA_CONTROL 0x00
@@ -197,10 +194,18 @@ static int __exit mxc_rnga_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id mxc_rnga_of_match[] = {
+ { .compatible = "fsl,imx21-rnga", },
+ { .compatible = "fsl,imx31-rnga", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mxc_rnga_of_match);
+
static struct platform_driver mxc_rnga_driver = {
.driver = {
- .name = "mxc_rnga",
- },
+ .name = "mxc_rnga",
+ .of_match_table = mxc_rnga_of_match,
+ },
.remove = __exit_p(mxc_rnga_remove),
};
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index 74d11ae6abe9..b65ff6962899 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -150,6 +150,7 @@ struct omap_rng_dev {
const struct omap_rng_pdata *pdata;
struct hwrng rng;
struct clk *clk;
+ struct clk *clk_reg;
};
static inline u32 omap_rng_read(struct omap_rng_dev *priv, u16 reg)
@@ -480,6 +481,19 @@ static int omap_rng_probe(struct platform_device *pdev)
}
}
+ priv->clk_reg = devm_clk_get(&pdev->dev, "reg");
+ if (IS_ERR(priv->clk_reg) && PTR_ERR(priv->clk_reg) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ if (!IS_ERR(priv->clk_reg)) {
+ ret = clk_prepare_enable(priv->clk_reg);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Unable to enable the register clk: %d\n",
+ ret);
+ goto err_register;
+ }
+ }
+
ret = (dev->of_node) ? of_get_omap_rng_device_details(priv, pdev) :
get_omap_rng_device_details(priv);
if (ret)
@@ -499,8 +513,8 @@ err_register:
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- if (!IS_ERR(priv->clk))
- clk_disable_unprepare(priv->clk);
+ clk_disable_unprepare(priv->clk_reg);
+ clk_disable_unprepare(priv->clk);
err_ioremap:
dev_err(dev, "initialization failed.\n");
return ret;
@@ -517,8 +531,8 @@ static int omap_rng_remove(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- if (!IS_ERR(priv->clk))
- clk_disable_unprepare(priv->clk);
+ clk_disable_unprepare(priv->clk);
+ clk_disable_unprepare(priv->clk_reg);
return 0;
}
diff --git a/drivers/char/hw_random/stm32-rng.c b/drivers/char/hw_random/stm32-rng.c
index 63d84e6f1891..0d2328da3b76 100644
--- a/drivers/char/hw_random/stm32-rng.c
+++ b/drivers/char/hw_random/stm32-rng.c
@@ -16,15 +16,18 @@
#include <linux/delay.h>
#include <linux/hw_random.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include <linux/slab.h>
#define RNG_CR 0x00
#define RNG_CR_RNGEN BIT(2)
+#define RNG_CR_CED BIT(5)
#define RNG_SR 0x04
#define RNG_SR_SEIS BIT(6)
@@ -33,19 +36,12 @@
#define RNG_DR 0x08
-/*
- * It takes 40 cycles @ 48MHz to generate each random number (e.g. <1us).
- * At the time of writing STM32 parts max out at ~200MHz meaning a timeout
- * of 500 leaves us a very comfortable margin for error. The loop to which
- * the timeout applies takes at least 4 instructions per iteration so the
- * timeout is enough to take us up to multi-GHz parts!
- */
-#define RNG_TIMEOUT 500
-
struct stm32_rng_private {
struct hwrng rng;
void __iomem *base;
struct clk *clk;
+ struct reset_control *rst;
+ bool ced;
};
static int stm32_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
@@ -59,13 +55,16 @@ static int stm32_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
while (max > sizeof(u32)) {
sr = readl_relaxed(priv->base + RNG_SR);
+ /* Manage timeout which is based on timer and take */
+ /* care of initial delay time when enabling rng */
if (!sr && wait) {
- unsigned int timeout = RNG_TIMEOUT;
-
- do {
- cpu_relax();
- sr = readl_relaxed(priv->base + RNG_SR);
- } while (!sr && --timeout);
+ retval = readl_relaxed_poll_timeout_atomic(priv->base
+ + RNG_SR,
+ sr, sr,
+ 10, 50000);
+ if (retval)
+ dev_err((struct device *)priv->rng.priv,
+ "%s: timeout %x!\n", __func__, sr);
}
/* If error detected or data not ready... */
@@ -99,7 +98,11 @@ static int stm32_rng_init(struct hwrng *rng)
if (err)
return err;
- writel_relaxed(RNG_CR_RNGEN, priv->base + RNG_CR);
+ if (priv->ced)
+ writel_relaxed(RNG_CR_RNGEN, priv->base + RNG_CR);
+ else
+ writel_relaxed(RNG_CR_RNGEN | RNG_CR_CED,
+ priv->base + RNG_CR);
/* clear error indicators */
writel_relaxed(0, priv->base + RNG_SR);
@@ -140,6 +143,15 @@ static int stm32_rng_probe(struct platform_device *ofdev)
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
+ priv->rst = devm_reset_control_get(&ofdev->dev, NULL);
+ if (!IS_ERR(priv->rst)) {
+ reset_control_assert(priv->rst);
+ udelay(2);
+ reset_control_deassert(priv->rst);
+ }
+
+ priv->ced = of_property_read_bool(np, "clock-error-detect");
+
dev_set_drvdata(dev, priv);
priv->rng.name = dev_driver_string(dev),
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 052011bcf100..ffeb60d3434c 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -137,7 +137,7 @@ static ssize_t read_mem(struct file *file, char __user *buf,
while (count > 0) {
unsigned long remaining;
- int allowed;
+ int allowed, probe;
sz = size_inside_page(p, count);
@@ -160,9 +160,9 @@ static ssize_t read_mem(struct file *file, char __user *buf,
if (!ptr)
goto failed;
- err = probe_kernel_read(bounce, ptr, sz);
+ probe = probe_kernel_read(bounce, ptr, sz);
unxlate_dev_mem_ptr(p, ptr);
- if (err)
+ if (probe)
goto failed;
remaining = copy_to_user(buf, bounce, sz);
diff --git a/drivers/char/random.c b/drivers/char/random.c
index e5b3d3ba4660..e027e7fa1472 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -709,7 +709,8 @@ retry:
}
/* should we wake readers? */
- if (entropy_bits >= random_read_wakeup_bits) {
+ if (entropy_bits >= random_read_wakeup_bits &&
+ wq_has_sleeper(&random_read_wait)) {
wake_up_interruptible(&random_read_wait);
kill_fasync(&fasync, SIGIO, POLL_IN);
}
@@ -732,7 +733,7 @@ retry:
static int credit_entropy_bits_safe(struct entropy_store *r, int nbits)
{
- const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1));
+ const int nbits_max = r->poolinfo->poolwords * 32;
if (nbits < 0)
return -EINVAL;
@@ -963,7 +964,6 @@ static ssize_t extract_crng_user(void __user *buf, size_t nbytes)
struct timer_rand_state {
cycles_t last_time;
long last_delta, last_delta2;
- unsigned dont_count_entropy:1;
};
#define INIT_TIMER_RAND_STATE { INITIAL_JIFFIES, };
@@ -1029,35 +1029,33 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
* We take into account the first, second and third-order deltas
* in order to make our estimate.
*/
+ delta = sample.jiffies - state->last_time;
+ state->last_time = sample.jiffies;
+
+ delta2 = delta - state->last_delta;
+ state->last_delta = delta;
+
+ delta3 = delta2 - state->last_delta2;
+ state->last_delta2 = delta2;
+
+ if (delta < 0)
+ delta = -delta;
+ if (delta2 < 0)
+ delta2 = -delta2;
+ if (delta3 < 0)
+ delta3 = -delta3;
+ if (delta > delta2)
+ delta = delta2;
+ if (delta > delta3)
+ delta = delta3;
- if (!state->dont_count_entropy) {
- delta = sample.jiffies - state->last_time;
- state->last_time = sample.jiffies;
-
- delta2 = delta - state->last_delta;
- state->last_delta = delta;
-
- delta3 = delta2 - state->last_delta2;
- state->last_delta2 = delta2;
-
- if (delta < 0)
- delta = -delta;
- if (delta2 < 0)
- delta2 = -delta2;
- if (delta3 < 0)
- delta3 = -delta3;
- if (delta > delta2)
- delta = delta2;
- if (delta > delta3)
- delta = delta3;
+ /*
+ * delta is now minimum absolute delta.
+ * Round down by 1 bit on general principles,
+ * and limit entropy entimate to 12 bits.
+ */
+ credit_entropy_bits(r, min_t(int, fls(delta>>1), 11));
- /*
- * delta is now minimum absolute delta.
- * Round down by 1 bit on general principles,
- * and limit entropy entimate to 12 bits.
- */
- credit_entropy_bits(r, min_t(int, fls(delta>>1), 11));
- }
preempt_enable();
}
diff --git a/drivers/char/xillybus/xillybus_pcie.c b/drivers/char/xillybus/xillybus_pcie.c
index dff2d1538164..05e5324f60bd 100644
--- a/drivers/char/xillybus/xillybus_pcie.c
+++ b/drivers/char/xillybus/xillybus_pcie.c
@@ -24,7 +24,6 @@ MODULE_LICENSE("GPL v2");
#define PCI_DEVICE_ID_XILLYBUS 0xebeb
-#define PCI_VENDOR_ID_ALTERA 0x1172
#define PCI_VENDOR_ID_ACTEL 0x11aa
#define PCI_VENDOR_ID_LATTICE 0x1204
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 4b741b83e23f..d1ea1a07cecb 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -464,13 +464,6 @@ if CRYPTO_DEV_UX500
source "drivers/crypto/ux500/Kconfig"
endif # if CRYPTO_DEV_UX500
-config CRYPTO_DEV_BFIN_CRC
- tristate "Support for Blackfin CRC hardware"
- depends on BF60x
- help
- Newer Blackfin processors have CRC hardware. Select this if you
- want to use the Blackfin CRC module.
-
config CRYPTO_DEV_ATMEL_AUTHENC
tristate "Support for Atmel IPSEC/SSL hw accelerator"
depends on HAS_DMA
@@ -730,4 +723,31 @@ config CRYPTO_DEV_ARTPEC6
To compile this driver as a module, choose M here.
+config CRYPTO_DEV_CCREE
+ tristate "Support for ARM TrustZone CryptoCell family of security processors"
+ depends on CRYPTO && CRYPTO_HW && OF && HAS_DMA
+ default n
+ select CRYPTO_HASH
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_DES
+ select CRYPTO_AEAD
+ select CRYPTO_AUTHENC
+ select CRYPTO_SHA1
+ select CRYPTO_MD5
+ select CRYPTO_SHA256
+ select CRYPTO_SHA512
+ select CRYPTO_HMAC
+ select CRYPTO_AES
+ select CRYPTO_CBC
+ select CRYPTO_ECB
+ select CRYPTO_CTR
+ select CRYPTO_XTS
+ help
+ Say 'Y' to enable a driver for the REE interface of the Arm
+ TrustZone CryptoCell family of processors. Currently the
+ CryptoCell 712, 710 and 630 are supported.
+ Choose this if you wish to use hardware acceleration of
+ cryptographic operations on the system REE.
+ If unsure say Y.
+
endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 2513d13ea2c4..7ae87b4f6c8d 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -3,9 +3,9 @@ obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o
obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o
obj-$(CONFIG_CRYPTO_DEV_ATMEL_ECC) += atmel-ecc.o
-obj-$(CONFIG_CRYPTO_DEV_BFIN_CRC) += bfin_crc.o
obj-$(CONFIG_CRYPTO_DEV_CAVIUM_ZIP) += cavium/
obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/
+obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/
obj-$(CONFIG_CRYPTO_DEV_CHELSIO) += chelsio/
obj-$(CONFIG_CRYPTO_DEV_CPT) += cavium/cpt/
obj-$(CONFIG_CRYPTO_DEV_NITROX) += cavium/nitrox/
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index 691c6465b71e..801aeab5ab1e 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -2155,7 +2155,7 @@ static int atmel_aes_authenc_setkey(struct crypto_aead *tfm, const u8 *key,
badkey:
crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
- memzero_explicit(&key, sizeof(keys));
+ memzero_explicit(&keys, sizeof(keys));
return -EINVAL;
}
@@ -2602,16 +2602,13 @@ static struct crypto_platform_data *atmel_aes_of_init(struct platform_device *pd
}
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(&pdev->dev, "could not allocate memory for pdata\n");
+ if (!pdata)
return ERR_PTR(-ENOMEM);
- }
pdata->dma_slave = devm_kzalloc(&pdev->dev,
sizeof(*(pdata->dma_slave)),
GFP_KERNEL);
if (!pdata->dma_slave) {
- dev_err(&pdev->dev, "could not allocate memory for dma_slave\n");
devm_kfree(&pdev->dev, pdata);
return ERR_PTR(-ENOMEM);
}
@@ -2649,7 +2646,6 @@ static int atmel_aes_probe(struct platform_device *pdev)
aes_dd = devm_kzalloc(&pdev->dev, sizeof(*aes_dd), GFP_KERNEL);
if (aes_dd == NULL) {
- dev_err(dev, "unable to alloc data struct.\n");
err = -ENOMEM;
goto aes_dd_err;
}
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index 8874aa5ca0f7..4d43081120db 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -2726,18 +2726,14 @@ static struct crypto_platform_data *atmel_sha_of_init(struct platform_device *pd
}
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(&pdev->dev, "could not allocate memory for pdata\n");
+ if (!pdata)
return ERR_PTR(-ENOMEM);
- }
pdata->dma_slave = devm_kzalloc(&pdev->dev,
sizeof(*(pdata->dma_slave)),
GFP_KERNEL);
- if (!pdata->dma_slave) {
- dev_err(&pdev->dev, "could not allocate memory for dma_slave\n");
+ if (!pdata->dma_slave)
return ERR_PTR(-ENOMEM);
- }
return pdata;
}
@@ -2758,7 +2754,6 @@ static int atmel_sha_probe(struct platform_device *pdev)
sha_dd = devm_kzalloc(&pdev->dev, sizeof(*sha_dd), GFP_KERNEL);
if (sha_dd == NULL) {
- dev_err(dev, "unable to alloc data struct.\n");
err = -ENOMEM;
goto sha_dd_err;
}
diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
index 592124f8382b..97b0423efa7f 100644
--- a/drivers/crypto/atmel-tdes.c
+++ b/drivers/crypto/atmel-tdes.c
@@ -1312,18 +1312,14 @@ static struct crypto_platform_data *atmel_tdes_of_init(struct platform_device *p
}
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(&pdev->dev, "could not allocate memory for pdata\n");
+ if (!pdata)
return ERR_PTR(-ENOMEM);
- }
pdata->dma_slave = devm_kzalloc(&pdev->dev,
sizeof(*(pdata->dma_slave)),
GFP_KERNEL);
- if (!pdata->dma_slave) {
- dev_err(&pdev->dev, "could not allocate memory for dma_slave\n");
+ if (!pdata->dma_slave)
return ERR_PTR(-ENOMEM);
- }
return pdata;
}
@@ -1344,7 +1340,6 @@ static int atmel_tdes_probe(struct platform_device *pdev)
tdes_dd = devm_kmalloc(&pdev->dev, sizeof(*tdes_dd), GFP_KERNEL);
if (tdes_dd == NULL) {
- dev_err(dev, "unable to alloc data struct.\n");
err = -ENOMEM;
goto tdes_dd_err;
}
diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c
index 2b75f95bbe1b..309c67c7012f 100644
--- a/drivers/crypto/bcm/cipher.c
+++ b/drivers/crypto/bcm/cipher.c
@@ -818,7 +818,7 @@ static int handle_ahash_req(struct iproc_reqctx_s *rctx)
/* AES hashing keeps key size in type field, so need to copy it here */
if (hash_parms.alg == HASH_ALG_AES)
- hash_parms.type = cipher_parms.type;
+ hash_parms.type = (enum hash_type)cipher_parms.type;
else
hash_parms.type = spu->spu_hash_type(rctx->total_sent);
@@ -1409,7 +1409,7 @@ static int handle_aead_req(struct iproc_reqctx_s *rctx)
rctx->iv_ctr_len);
if (ctx->auth.alg == HASH_ALG_AES)
- hash_parms.type = ctx->cipher_type;
+ hash_parms.type = (enum hash_type)ctx->cipher_type;
/* General case AAD padding (CCM and RFC4543 special cases below) */
aead_parms.aad_pad_len = spu->spu_gcm_ccm_pad_len(ctx->cipher.mode,
diff --git a/drivers/crypto/bcm/util.c b/drivers/crypto/bcm/util.c
index d543c010ccd9..a912c6ad3e85 100644
--- a/drivers/crypto/bcm/util.c
+++ b/drivers/crypto/bcm/util.c
@@ -279,7 +279,6 @@ int do_shash(unsigned char *name, unsigned char *result,
sdesc = kmalloc(size, GFP_KERNEL);
if (!sdesc) {
rc = -ENOMEM;
- pr_err("%s: Memory allocation failure\n", __func__);
goto do_shash_err;
}
sdesc->shash.tfm = hash;
diff --git a/drivers/crypto/bfin_crc.c b/drivers/crypto/bfin_crc.c
deleted file mode 100644
index bfbf8bf77f03..000000000000
--- a/drivers/crypto/bfin_crc.c
+++ /dev/null
@@ -1,743 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Support Blackfin CRC HW acceleration.
- *
- * Copyright 2012 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/crypto.h>
-#include <linux/cryptohash.h>
-#include <crypto/scatterwalk.h>
-#include <crypto/algapi.h>
-#include <crypto/hash.h>
-#include <crypto/internal/hash.h>
-#include <asm/unaligned.h>
-
-#include <asm/dma.h>
-#include <asm/portmux.h>
-#include <asm/io.h>
-
-#include "bfin_crc.h"
-
-#define CRC_CCRYPTO_QUEUE_LENGTH 5
-
-#define DRIVER_NAME "bfin-hmac-crc"
-#define CHKSUM_DIGEST_SIZE 4
-#define CHKSUM_BLOCK_SIZE 1
-
-#define CRC_MAX_DMA_DESC 100
-
-#define CRC_CRYPTO_STATE_UPDATE 1
-#define CRC_CRYPTO_STATE_FINALUPDATE 2
-#define CRC_CRYPTO_STATE_FINISH 3
-
-struct bfin_crypto_crc {
- struct list_head list;
- struct device *dev;
- spinlock_t lock;
-
- int irq;
- int dma_ch;
- u32 poly;
- struct crc_register *regs;
-
- struct ahash_request *req; /* current request in operation */
- struct dma_desc_array *sg_cpu; /* virt addr of sg dma descriptors */
- dma_addr_t sg_dma; /* phy addr of sg dma descriptors */
- u8 *sg_mid_buf;
- dma_addr_t sg_mid_dma; /* phy addr of sg mid buffer */
-
- struct tasklet_struct done_task;
- struct crypto_queue queue; /* waiting requests */
-
- u8 busy:1; /* crc device in operation flag */
-};
-
-static struct bfin_crypto_crc_list {
- struct list_head dev_list;
- spinlock_t lock;
-} crc_list;
-
-struct bfin_crypto_crc_reqctx {
- struct bfin_crypto_crc *crc;
-
- unsigned int total; /* total request bytes */
- size_t sg_buflen; /* bytes for this update */
- unsigned int sg_nents;
- struct scatterlist *sg; /* sg list head for this update*/
- struct scatterlist bufsl[2]; /* chained sg list */
-
- size_t bufnext_len;
- size_t buflast_len;
- u8 bufnext[CHKSUM_DIGEST_SIZE]; /* extra bytes for next udpate */
- u8 buflast[CHKSUM_DIGEST_SIZE]; /* extra bytes from last udpate */
-
- u8 flag;
-};
-
-struct bfin_crypto_crc_ctx {
- struct bfin_crypto_crc *crc;
- u32 key;
-};
-
-/*
- * get element in scatter list by given index
- */
-static struct scatterlist *sg_get(struct scatterlist *sg_list, unsigned int nents,
- unsigned int index)
-{
- struct scatterlist *sg = NULL;
- int i;
-
- for_each_sg(sg_list, sg, nents, i)
- if (i == index)
- break;
-
- return sg;
-}
-
-static int bfin_crypto_crc_init_hw(struct bfin_crypto_crc *crc, u32 key)
-{
- writel(0, &crc->regs->datacntrld);
- writel(MODE_CALC_CRC << OPMODE_OFFSET, &crc->regs->control);
- writel(key, &crc->regs->curresult);
-
- /* setup CRC interrupts */
- writel(CMPERRI | DCNTEXPI, &crc->regs->status);
- writel(CMPERRI | DCNTEXPI, &crc->regs->intrenset);
-
- return 0;
-}
-
-static int bfin_crypto_crc_init(struct ahash_request *req)
-{
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
- struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
- struct bfin_crypto_crc *crc;
-
- dev_dbg(ctx->crc->dev, "crc_init\n");
- spin_lock_bh(&crc_list.lock);
- list_for_each_entry(crc, &crc_list.dev_list, list) {
- crc_ctx->crc = crc;
- break;
- }
- spin_unlock_bh(&crc_list.lock);
-
- if (sg_nents(req->src) > CRC_MAX_DMA_DESC) {
- dev_dbg(ctx->crc->dev, "init: requested sg list is too big > %d\n",
- CRC_MAX_DMA_DESC);
- return -EINVAL;
- }
-
- ctx->crc = crc;
- ctx->bufnext_len = 0;
- ctx->buflast_len = 0;
- ctx->sg_buflen = 0;
- ctx->total = 0;
- ctx->flag = 0;
-
- /* init crc results */
- put_unaligned_le32(crc_ctx->key, req->result);
-
- dev_dbg(ctx->crc->dev, "init: digest size: %d\n",
- crypto_ahash_digestsize(tfm));
-
- return bfin_crypto_crc_init_hw(crc, crc_ctx->key);
-}
-
-static void bfin_crypto_crc_config_dma(struct bfin_crypto_crc *crc)
-{
- struct scatterlist *sg;
- struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(crc->req);
- int i = 0, j = 0;
- unsigned long dma_config;
- unsigned int dma_count;
- unsigned int dma_addr;
- unsigned int mid_dma_count = 0;
- int dma_mod;
-
- dma_map_sg(crc->dev, ctx->sg, ctx->sg_nents, DMA_TO_DEVICE);
-
- for_each_sg(ctx->sg, sg, ctx->sg_nents, j) {
- dma_addr = sg_dma_address(sg);
- /* deduce extra bytes in last sg */
- if (sg_is_last(sg))
- dma_count = sg_dma_len(sg) - ctx->bufnext_len;
- else
- dma_count = sg_dma_len(sg);
-
- if (mid_dma_count) {
- /* Append last middle dma buffer to 4 bytes with first
- bytes in current sg buffer. Move addr of current
- sg and deduce the length of current sg.
- */
- memcpy(crc->sg_mid_buf +(i << 2) + mid_dma_count,
- sg_virt(sg),
- CHKSUM_DIGEST_SIZE - mid_dma_count);
- dma_addr += CHKSUM_DIGEST_SIZE - mid_dma_count;
- dma_count -= CHKSUM_DIGEST_SIZE - mid_dma_count;
-
- dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 |
- DMAEN | PSIZE_32 | WDSIZE_32;
-
- /* setup new dma descriptor for next middle dma */
- crc->sg_cpu[i].start_addr = crc->sg_mid_dma + (i << 2);
- crc->sg_cpu[i].cfg = dma_config;
- crc->sg_cpu[i].x_count = 1;
- crc->sg_cpu[i].x_modify = CHKSUM_DIGEST_SIZE;
- dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, "
- "cfg:0x%x, x_count:0x%x, x_modify:0x%x\n",
- i, crc->sg_cpu[i].start_addr,
- crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count,
- crc->sg_cpu[i].x_modify);
- i++;
- }
-
- dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 | DMAEN | PSIZE_32;
- /* chop current sg dma len to multiple of 32 bits */
- mid_dma_count = dma_count % 4;
- dma_count &= ~0x3;
-
- if (dma_addr % 4 == 0) {
- dma_config |= WDSIZE_32;
- dma_count >>= 2;
- dma_mod = 4;
- } else if (dma_addr % 2 == 0) {
- dma_config |= WDSIZE_16;
- dma_count >>= 1;
- dma_mod = 2;
- } else {
- dma_config |= WDSIZE_8;
- dma_mod = 1;
- }
-
- crc->sg_cpu[i].start_addr = dma_addr;
- crc->sg_cpu[i].cfg = dma_config;
- crc->sg_cpu[i].x_count = dma_count;
- crc->sg_cpu[i].x_modify = dma_mod;
- dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, "
- "cfg:0x%x, x_count:0x%x, x_modify:0x%x\n",
- i, crc->sg_cpu[i].start_addr,
- crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count,
- crc->sg_cpu[i].x_modify);
- i++;
-
- if (mid_dma_count) {
- /* copy extra bytes to next middle dma buffer */
- memcpy(crc->sg_mid_buf + (i << 2),
- (u8*)sg_virt(sg) + (dma_count << 2),
- mid_dma_count);
- }
- }
-
- dma_config = DMAFLOW_ARRAY | RESTART | NDSIZE_3 | DMAEN | PSIZE_32 | WDSIZE_32;
- /* For final update req, append the buffer for next update as well*/
- if (ctx->bufnext_len && (ctx->flag == CRC_CRYPTO_STATE_FINALUPDATE ||
- ctx->flag == CRC_CRYPTO_STATE_FINISH)) {
- crc->sg_cpu[i].start_addr = dma_map_single(crc->dev, ctx->bufnext,
- CHKSUM_DIGEST_SIZE, DMA_TO_DEVICE);
- crc->sg_cpu[i].cfg = dma_config;
- crc->sg_cpu[i].x_count = 1;
- crc->sg_cpu[i].x_modify = CHKSUM_DIGEST_SIZE;
- dev_dbg(crc->dev, "%d: crc_dma: start_addr:0x%lx, "
- "cfg:0x%x, x_count:0x%x, x_modify:0x%x\n",
- i, crc->sg_cpu[i].start_addr,
- crc->sg_cpu[i].cfg, crc->sg_cpu[i].x_count,
- crc->sg_cpu[i].x_modify);
- i++;
- }
-
- if (i == 0)
- return;
-
- /* Set the last descriptor to stop mode */
- crc->sg_cpu[i - 1].cfg &= ~(DMAFLOW | NDSIZE);
- crc->sg_cpu[i - 1].cfg |= DI_EN;
- set_dma_curr_desc_addr(crc->dma_ch, (unsigned long *)crc->sg_dma);
- set_dma_x_count(crc->dma_ch, 0);
- set_dma_x_modify(crc->dma_ch, 0);
- set_dma_config(crc->dma_ch, dma_config);
-}
-
-static int bfin_crypto_crc_handle_queue(struct bfin_crypto_crc *crc,
- struct ahash_request *req)
-{
- struct crypto_async_request *async_req, *backlog;
- struct bfin_crypto_crc_reqctx *ctx;
- struct scatterlist *sg;
- int ret = 0;
- int nsg, i, j;
- unsigned int nextlen;
- unsigned long flags;
- u32 reg;
-
- spin_lock_irqsave(&crc->lock, flags);
- if (req)
- ret = ahash_enqueue_request(&crc->queue, req);
- if (crc->busy) {
- spin_unlock_irqrestore(&crc->lock, flags);
- return ret;
- }
- backlog = crypto_get_backlog(&crc->queue);
- async_req = crypto_dequeue_request(&crc->queue);
- if (async_req)
- crc->busy = 1;
- spin_unlock_irqrestore(&crc->lock, flags);
-
- if (!async_req)
- return ret;
-
- if (backlog)
- backlog->complete(backlog, -EINPROGRESS);
-
- req = ahash_request_cast(async_req);
- crc->req = req;
- ctx = ahash_request_ctx(req);
- ctx->sg = NULL;
- ctx->sg_buflen = 0;
- ctx->sg_nents = 0;
-
- dev_dbg(crc->dev, "handling new req, flag=%u, nbytes: %d\n",
- ctx->flag, req->nbytes);
-
- if (ctx->flag == CRC_CRYPTO_STATE_FINISH) {
- if (ctx->bufnext_len == 0) {
- crc->busy = 0;
- return 0;
- }
-
- /* Pack last crc update buffer to 32bit */
- memset(ctx->bufnext + ctx->bufnext_len, 0,
- CHKSUM_DIGEST_SIZE - ctx->bufnext_len);
- } else {
- /* Pack small data which is less than 32bit to buffer for next update. */
- if (ctx->bufnext_len + req->nbytes < CHKSUM_DIGEST_SIZE) {
- memcpy(ctx->bufnext + ctx->bufnext_len,
- sg_virt(req->src), req->nbytes);
- ctx->bufnext_len += req->nbytes;
- if (ctx->flag == CRC_CRYPTO_STATE_FINALUPDATE &&
- ctx->bufnext_len) {
- goto finish_update;
- } else {
- crc->busy = 0;
- return 0;
- }
- }
-
- if (ctx->bufnext_len) {
- /* Chain in extra bytes of last update */
- ctx->buflast_len = ctx->bufnext_len;
- memcpy(ctx->buflast, ctx->bufnext, ctx->buflast_len);
-
- nsg = ctx->sg_buflen ? 2 : 1;
- sg_init_table(ctx->bufsl, nsg);
- sg_set_buf(ctx->bufsl, ctx->buflast, ctx->buflast_len);
- if (nsg > 1)
- sg_chain(ctx->bufsl, nsg, req->src);
- ctx->sg = ctx->bufsl;
- } else
- ctx->sg = req->src;
-
- /* Chop crc buffer size to multiple of 32 bit */
- nsg = sg_nents(ctx->sg);
- ctx->sg_nents = nsg;
- ctx->sg_buflen = ctx->buflast_len + req->nbytes;
- ctx->bufnext_len = ctx->sg_buflen % 4;
- ctx->sg_buflen &= ~0x3;
-
- if (ctx->bufnext_len) {
- /* copy extra bytes to buffer for next update */
- memset(ctx->bufnext, 0, CHKSUM_DIGEST_SIZE);
- nextlen = ctx->bufnext_len;
- for (i = nsg - 1; i >= 0; i--) {
- sg = sg_get(ctx->sg, nsg, i);
- j = min(nextlen, sg_dma_len(sg));
- memcpy(ctx->bufnext + nextlen - j,
- sg_virt(sg) + sg_dma_len(sg) - j, j);
- if (j == sg_dma_len(sg))
- ctx->sg_nents--;
- nextlen -= j;
- if (nextlen == 0)
- break;
- }
- }
- }
-
-finish_update:
- if (ctx->bufnext_len && (ctx->flag == CRC_CRYPTO_STATE_FINALUPDATE ||
- ctx->flag == CRC_CRYPTO_STATE_FINISH))
- ctx->sg_buflen += CHKSUM_DIGEST_SIZE;
-
- /* set CRC data count before start DMA */
- writel(ctx->sg_buflen >> 2, &crc->regs->datacnt);
-
- /* setup and enable CRC DMA */
- bfin_crypto_crc_config_dma(crc);
-
- /* finally kick off CRC operation */
- reg = readl(&crc->regs->control);
- writel(reg | BLKEN, &crc->regs->control);
-
- return -EINPROGRESS;
-}
-
-static int bfin_crypto_crc_update(struct ahash_request *req)
-{
- struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
-
- if (!req->nbytes)
- return 0;
-
- dev_dbg(ctx->crc->dev, "crc_update\n");
- ctx->total += req->nbytes;
- ctx->flag = CRC_CRYPTO_STATE_UPDATE;
-
- return bfin_crypto_crc_handle_queue(ctx->crc, req);
-}
-
-static int bfin_crypto_crc_final(struct ahash_request *req)
-{
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
- struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
-
- dev_dbg(ctx->crc->dev, "crc_final\n");
- ctx->flag = CRC_CRYPTO_STATE_FINISH;
- crc_ctx->key = 0;
-
- return bfin_crypto_crc_handle_queue(ctx->crc, req);
-}
-
-static int bfin_crypto_crc_finup(struct ahash_request *req)
-{
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
- struct bfin_crypto_crc_reqctx *ctx = ahash_request_ctx(req);
-
- dev_dbg(ctx->crc->dev, "crc_finishupdate\n");
- ctx->total += req->nbytes;
- ctx->flag = CRC_CRYPTO_STATE_FINALUPDATE;
- crc_ctx->key = 0;
-
- return bfin_crypto_crc_handle_queue(ctx->crc, req);
-}
-
-static int bfin_crypto_crc_digest(struct ahash_request *req)
-{
- int ret;
-
- ret = bfin_crypto_crc_init(req);
- if (ret)
- return ret;
-
- return bfin_crypto_crc_finup(req);
-}
-
-static int bfin_crypto_crc_setkey(struct crypto_ahash *tfm, const u8 *key,
- unsigned int keylen)
-{
- struct bfin_crypto_crc_ctx *crc_ctx = crypto_ahash_ctx(tfm);
-
- dev_dbg(crc_ctx->crc->dev, "crc_setkey\n");
- if (keylen != CHKSUM_DIGEST_SIZE) {
- crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
- return -EINVAL;
- }
-
- crc_ctx->key = get_unaligned_le32(key);
-
- return 0;
-}
-
-static int bfin_crypto_crc_cra_init(struct crypto_tfm *tfm)
-{
- struct bfin_crypto_crc_ctx *crc_ctx = crypto_tfm_ctx(tfm);
-
- crc_ctx->key = 0;
- crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
- sizeof(struct bfin_crypto_crc_reqctx));
-
- return 0;
-}
-
-static void bfin_crypto_crc_cra_exit(struct crypto_tfm *tfm)
-{
-}
-
-static struct ahash_alg algs = {
- .init = bfin_crypto_crc_init,
- .update = bfin_crypto_crc_update,
- .final = bfin_crypto_crc_final,
- .finup = bfin_crypto_crc_finup,
- .digest = bfin_crypto_crc_digest,
- .setkey = bfin_crypto_crc_setkey,
- .halg.digestsize = CHKSUM_DIGEST_SIZE,
- .halg.base = {
- .cra_name = "hmac(crc32)",
- .cra_driver_name = DRIVER_NAME,
- .cra_priority = 100,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH |
- CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_OPTIONAL_KEY,
- .cra_blocksize = CHKSUM_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct bfin_crypto_crc_ctx),
- .cra_alignmask = 3,
- .cra_module = THIS_MODULE,
- .cra_init = bfin_crypto_crc_cra_init,
- .cra_exit = bfin_crypto_crc_cra_exit,
- }
-};
-
-static void bfin_crypto_crc_done_task(unsigned long data)
-{
- struct bfin_crypto_crc *crc = (struct bfin_crypto_crc *)data;
-
- bfin_crypto_crc_handle_queue(crc, NULL);
-}
-
-static irqreturn_t bfin_crypto_crc_handler(int irq, void *dev_id)
-{
- struct bfin_crypto_crc *crc = dev_id;
- u32 reg;
-
- if (readl(&crc->regs->status) & DCNTEXP) {
- writel(DCNTEXP, &crc->regs->status);
-
- /* prepare results */
- put_unaligned_le32(readl(&crc->regs->result),
- crc->req->result);
-
- reg = readl(&crc->regs->control);
- writel(reg & ~BLKEN, &crc->regs->control);
- crc->busy = 0;
-
- if (crc->req->base.complete)
- crc->req->base.complete(&crc->req->base, 0);
-
- tasklet_schedule(&crc->done_task);
-
- return IRQ_HANDLED;
- } else
- return IRQ_NONE;
-}
-
-#ifdef CONFIG_PM
-/**
- * bfin_crypto_crc_suspend - suspend crc device
- * @pdev: device being suspended
- * @state: requested suspend state
- */
-static int bfin_crypto_crc_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct bfin_crypto_crc *crc = platform_get_drvdata(pdev);
- int i = 100000;
-
- while ((readl(&crc->regs->control) & BLKEN) && --i)
- cpu_relax();
-
- if (i == 0)
- return -EBUSY;
-
- return 0;
-}
-#else
-# define bfin_crypto_crc_suspend NULL
-#endif
-
-#define bfin_crypto_crc_resume NULL
-
-/**
- * bfin_crypto_crc_probe - Initialize module
- *
- */
-static int bfin_crypto_crc_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct resource *res;
- struct bfin_crypto_crc *crc;
- unsigned int timeout = 100000;
- int ret;
-
- crc = devm_kzalloc(dev, sizeof(*crc), GFP_KERNEL);
- if (!crc) {
- dev_err(&pdev->dev, "fail to malloc bfin_crypto_crc\n");
- return -ENOMEM;
- }
-
- crc->dev = dev;
-
- INIT_LIST_HEAD(&crc->list);
- spin_lock_init(&crc->lock);
- tasklet_init(&crc->done_task, bfin_crypto_crc_done_task, (unsigned long)crc);
- crypto_init_queue(&crc->queue, CRC_CCRYPTO_QUEUE_LENGTH);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- crc->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR((void *)crc->regs)) {
- dev_err(&pdev->dev, "Cannot map CRC IO\n");
- return PTR_ERR((void *)crc->regs);
- }
-
- crc->irq = platform_get_irq(pdev, 0);
- if (crc->irq < 0) {
- dev_err(&pdev->dev, "No CRC DCNTEXP IRQ specified\n");
- return -ENOENT;
- }
-
- ret = devm_request_irq(dev, crc->irq, bfin_crypto_crc_handler,
- IRQF_SHARED, dev_name(dev), crc);
- if (ret) {
- dev_err(&pdev->dev, "Unable to request blackfin crc irq\n");
- return ret;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "No CRC DMA channel specified\n");
- return -ENOENT;
- }
- crc->dma_ch = res->start;
-
- ret = request_dma(crc->dma_ch, dev_name(dev));
- if (ret) {
- dev_err(&pdev->dev, "Unable to attach Blackfin CRC DMA channel\n");
- return ret;
- }
-
- crc->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &crc->sg_dma, GFP_KERNEL);
- if (crc->sg_cpu == NULL) {
- ret = -ENOMEM;
- goto out_error_dma;
- }
- /*
- * need at most CRC_MAX_DMA_DESC sg + CRC_MAX_DMA_DESC middle +
- * 1 last + 1 next dma descriptors
- */
- crc->sg_mid_buf = (u8 *)(crc->sg_cpu + ((CRC_MAX_DMA_DESC + 1) << 1));
- crc->sg_mid_dma = crc->sg_dma + sizeof(struct dma_desc_array)
- * ((CRC_MAX_DMA_DESC + 1) << 1);
-
- writel(0, &crc->regs->control);
- crc->poly = (u32)pdev->dev.platform_data;
- writel(crc->poly, &crc->regs->poly);
-
- while (!(readl(&crc->regs->status) & LUTDONE) && (--timeout) > 0)
- cpu_relax();
-
- if (timeout == 0)
- dev_info(&pdev->dev, "init crc poly timeout\n");
-
- platform_set_drvdata(pdev, crc);
-
- spin_lock(&crc_list.lock);
- list_add(&crc->list, &crc_list.dev_list);
- spin_unlock(&crc_list.lock);
-
- if (list_is_singular(&crc_list.dev_list)) {
- ret = crypto_register_ahash(&algs);
- if (ret) {
- dev_err(&pdev->dev,
- "Can't register crypto ahash device\n");
- goto out_error_dma;
- }
- }
-
- dev_info(&pdev->dev, "initialized\n");
-
- return 0;
-
-out_error_dma:
- if (crc->sg_cpu)
- dma_free_coherent(&pdev->dev, PAGE_SIZE, crc->sg_cpu, crc->sg_dma);
- free_dma(crc->dma_ch);
-
- return ret;
-}
-
-/**
- * bfin_crypto_crc_remove - Initialize module
- *
- */
-static int bfin_crypto_crc_remove(struct platform_device *pdev)
-{
- struct bfin_crypto_crc *crc = platform_get_drvdata(pdev);
-
- if (!crc)
- return -ENODEV;
-
- spin_lock(&crc_list.lock);
- list_del(&crc->list);
- spin_unlock(&crc_list.lock);
-
- crypto_unregister_ahash(&algs);
- tasklet_kill(&crc->done_task);
- free_dma(crc->dma_ch);
-
- return 0;
-}
-
-static struct platform_driver bfin_crypto_crc_driver = {
- .probe = bfin_crypto_crc_probe,
- .remove = bfin_crypto_crc_remove,
- .suspend = bfin_crypto_crc_suspend,
- .resume = bfin_crypto_crc_resume,
- .driver = {
- .name = DRIVER_NAME,
- },
-};
-
-/**
- * bfin_crypto_crc_mod_init - Initialize module
- *
- * Checks the module params and registers the platform driver.
- * Real work is in the platform probe function.
- */
-static int __init bfin_crypto_crc_mod_init(void)
-{
- int ret;
-
- pr_info("Blackfin hardware CRC crypto driver\n");
-
- INIT_LIST_HEAD(&crc_list.dev_list);
- spin_lock_init(&crc_list.lock);
-
- ret = platform_driver_register(&bfin_crypto_crc_driver);
- if (ret) {
- pr_err("unable to register driver\n");
- return ret;
- }
-
- return 0;
-}
-
-/**
- * bfin_crypto_crc_mod_exit - Deinitialize module
- */
-static void __exit bfin_crypto_crc_mod_exit(void)
-{
- platform_driver_unregister(&bfin_crypto_crc_driver);
-}
-
-module_init(bfin_crypto_crc_mod_init);
-module_exit(bfin_crypto_crc_mod_exit);
-
-MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
-MODULE_DESCRIPTION("Blackfin CRC hardware crypto driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/crypto/bfin_crc.h b/drivers/crypto/bfin_crc.h
deleted file mode 100644
index 786ef746d109..000000000000
--- a/drivers/crypto/bfin_crc.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * bfin_crc.h - interface to Blackfin CRC controllers
- *
- * Copyright 2012 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#ifndef __BFIN_CRC_H__
-#define __BFIN_CRC_H__
-
-/* Function driver which use hardware crc must initialize the structure */
-struct crc_info {
- /* Input data address */
- unsigned char *in_addr;
- /* Output data address */
- unsigned char *out_addr;
- /* Input or output bytes */
- unsigned long datasize;
- union {
- /* CRC to compare with that of input buffer */
- unsigned long crc_compare;
- /* Value to compare with input data */
- unsigned long val_verify;
- /* Value to fill */
- unsigned long val_fill;
- };
- /* Value to program the 32b CRC Polynomial */
- unsigned long crc_poly;
- union {
- /* CRC calculated from the input data */
- unsigned long crc_result;
- /* First failed position to verify input data */
- unsigned long pos_verify;
- };
- /* CRC mirror flags */
- unsigned int bitmirr:1;
- unsigned int bytmirr:1;
- unsigned int w16swp:1;
- unsigned int fdsel:1;
- unsigned int rsltmirr:1;
- unsigned int polymirr:1;
- unsigned int cmpmirr:1;
-};
-
-/* Userspace interface */
-#define CRC_IOC_MAGIC 'C'
-#define CRC_IOC_CALC_CRC _IOWR('C', 0x01, unsigned int)
-#define CRC_IOC_MEMCPY_CRC _IOWR('C', 0x02, unsigned int)
-#define CRC_IOC_VERIFY_VAL _IOWR('C', 0x03, unsigned int)
-#define CRC_IOC_FILL_VAL _IOWR('C', 0x04, unsigned int)
-
-
-#ifdef __KERNEL__
-
-#include <linux/types.h>
-#include <linux/spinlock.h>
-
-struct crc_register {
- u32 control;
- u32 datacnt;
- u32 datacntrld;
- u32 __pad_1[2];
- u32 compare;
- u32 fillval;
- u32 datafifo;
- u32 intren;
- u32 intrenset;
- u32 intrenclr;
- u32 poly;
- u32 __pad_2[4];
- u32 status;
- u32 datacntcap;
- u32 __pad_3;
- u32 result;
- u32 curresult;
- u32 __pad_4[3];
- u32 revid;
-};
-
-/* CRC_STATUS Masks */
-#define CMPERR 0x00000002 /* Compare error */
-#define DCNTEXP 0x00000010 /* datacnt register expired */
-#define IBR 0x00010000 /* Input buffer ready */
-#define OBR 0x00020000 /* Output buffer ready */
-#define IRR 0x00040000 /* Immediate result readt */
-#define LUTDONE 0x00080000 /* Look-up table generation done */
-#define FSTAT 0x00700000 /* FIFO status */
-#define MAX_FIFO 4 /* Max fifo size */
-
-/* CRC_CONTROL Masks */
-#define BLKEN 0x00000001 /* Block enable */
-#define OPMODE 0x000000F0 /* Operation mode */
-#define OPMODE_OFFSET 4 /* Operation mode mask offset*/
-#define MODE_DMACPY_CRC 1 /* MTM CRC compute and compare */
-#define MODE_DATA_FILL 2 /* MTM data fill */
-#define MODE_CALC_CRC 3 /* MSM CRC compute and compare */
-#define MODE_DATA_VERIFY 4 /* MSM data verify */
-#define AUTOCLRZ 0x00000100 /* Auto clear to zero */
-#define AUTOCLRF 0x00000200 /* Auto clear to one */
-#define OBRSTALL 0x00001000 /* Stall on output buffer ready */
-#define IRRSTALL 0x00002000 /* Stall on immediate result ready */
-#define BITMIRR 0x00010000 /* Mirror bits within each byte of 32-bit input data */
-#define BITMIRR_OFFSET 16 /* Mirror bits offset */
-#define BYTMIRR 0x00020000 /* Mirror bytes of 32-bit input data */
-#define BYTMIRR_OFFSET 17 /* Mirror bytes offset */
-#define W16SWP 0x00040000 /* Mirror uppper and lower 16-bit word of 32-bit input data */
-#define W16SWP_OFFSET 18 /* Mirror 16-bit word offset */
-#define FDSEL 0x00080000 /* FIFO is written after input data is mirrored */
-#define FDSEL_OFFSET 19 /* Mirror FIFO offset */
-#define RSLTMIRR 0x00100000 /* CRC result registers are mirrored. */
-#define RSLTMIRR_OFFSET 20 /* Mirror CRC result offset. */
-#define POLYMIRR 0x00200000 /* CRC poly register is mirrored. */
-#define POLYMIRR_OFFSET 21 /* Mirror CRC poly offset. */
-#define CMPMIRR 0x00400000 /* CRC compare register is mirrored. */
-#define CMPMIRR_OFFSET 22 /* Mirror CRC compare offset. */
-
-/* CRC_INTREN Masks */
-#define CMPERRI 0x02 /* CRC_ERROR_INTR */
-#define DCNTEXPI 0x10 /* CRC_STATUS_INTR */
-
-#endif
-
-#endif
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 2188235be02d..7207a535942d 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -328,6 +328,7 @@ static int gcm_set_sh_desc(struct crypto_aead *aead)
{
struct caam_ctx *ctx = crypto_aead_ctx(aead);
struct device *jrdev = ctx->jrdev;
+ unsigned int ivsize = crypto_aead_ivsize(aead);
u32 *desc;
int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN -
ctx->cdata.keylen;
@@ -349,7 +350,7 @@ static int gcm_set_sh_desc(struct crypto_aead *aead)
}
desc = ctx->sh_desc_enc;
- cnstr_shdsc_gcm_encap(desc, &ctx->cdata, ctx->authsize);
+ cnstr_shdsc_gcm_encap(desc, &ctx->cdata, ivsize, ctx->authsize, false);
dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
desc_bytes(desc), ctx->dir);
@@ -366,7 +367,7 @@ static int gcm_set_sh_desc(struct crypto_aead *aead)
}
desc = ctx->sh_desc_dec;
- cnstr_shdsc_gcm_decap(desc, &ctx->cdata, ctx->authsize);
+ cnstr_shdsc_gcm_decap(desc, &ctx->cdata, ivsize, ctx->authsize, false);
dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
desc_bytes(desc), ctx->dir);
@@ -387,6 +388,7 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead)
{
struct caam_ctx *ctx = crypto_aead_ctx(aead);
struct device *jrdev = ctx->jrdev;
+ unsigned int ivsize = crypto_aead_ivsize(aead);
u32 *desc;
int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN -
ctx->cdata.keylen;
@@ -408,7 +410,8 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead)
}
desc = ctx->sh_desc_enc;
- cnstr_shdsc_rfc4106_encap(desc, &ctx->cdata, ctx->authsize);
+ cnstr_shdsc_rfc4106_encap(desc, &ctx->cdata, ivsize, ctx->authsize,
+ false);
dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
desc_bytes(desc), ctx->dir);
@@ -425,7 +428,8 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead)
}
desc = ctx->sh_desc_dec;
- cnstr_shdsc_rfc4106_decap(desc, &ctx->cdata, ctx->authsize);
+ cnstr_shdsc_rfc4106_decap(desc, &ctx->cdata, ivsize, ctx->authsize,
+ false);
dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
desc_bytes(desc), ctx->dir);
@@ -447,6 +451,7 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead)
{
struct caam_ctx *ctx = crypto_aead_ctx(aead);
struct device *jrdev = ctx->jrdev;
+ unsigned int ivsize = crypto_aead_ivsize(aead);
u32 *desc;
int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN -
ctx->cdata.keylen;
@@ -468,7 +473,8 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead)
}
desc = ctx->sh_desc_enc;
- cnstr_shdsc_rfc4543_encap(desc, &ctx->cdata, ctx->authsize);
+ cnstr_shdsc_rfc4543_encap(desc, &ctx->cdata, ivsize, ctx->authsize,
+ false);
dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma,
desc_bytes(desc), ctx->dir);
@@ -485,7 +491,8 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead)
}
desc = ctx->sh_desc_dec;
- cnstr_shdsc_rfc4543_decap(desc, &ctx->cdata, ctx->authsize);
+ cnstr_shdsc_rfc4543_decap(desc, &ctx->cdata, ivsize, ctx->authsize,
+ false);
dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma,
desc_bytes(desc), ctx->dir);
@@ -563,9 +570,11 @@ static int aead_setkey(struct crypto_aead *aead,
skip_split_key:
ctx->cdata.keylen = keys.enckeylen;
+ memzero_explicit(&keys, sizeof(keys));
return aead_set_sh_desc(aead);
badkey:
crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ memzero_explicit(&keys, sizeof(keys));
return -EINVAL;
}
diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c
index ceb93fbb76e6..8ae7a1be7dfd 100644
--- a/drivers/crypto/caam/caamalg_desc.c
+++ b/drivers/crypto/caam/caamalg_desc.c
@@ -625,10 +625,13 @@ EXPORT_SYMBOL(cnstr_shdsc_aead_givencap);
* @desc: pointer to buffer used for descriptor construction
* @cdata: pointer to block cipher transform definitions
* Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
+ * @ivsize: initialization vector size
* @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_qi: true when called from caam/qi
*/
void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata,
- unsigned int icvsize)
+ unsigned int ivsize, unsigned int icvsize,
+ const bool is_qi)
{
u32 *key_jump_cmd, *zero_payload_jump_cmd, *zero_assoc_jump_cmd1,
*zero_assoc_jump_cmd2;
@@ -650,11 +653,35 @@ void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata,
append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
OP_ALG_ENCRYPT);
+ if (is_qi) {
+ u32 *wait_load_cmd;
+
+ /* REG3 = assoclen */
+ append_seq_load(desc, 4, LDST_CLASS_DECO |
+ LDST_SRCDST_WORD_DECO_MATH3 |
+ (4 << LDST_OFFSET_SHIFT));
+
+ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+ JUMP_COND_CALM | JUMP_COND_NCP |
+ JUMP_COND_NOP | JUMP_COND_NIP |
+ JUMP_COND_NIFP);
+ set_jump_tgt_here(desc, wait_load_cmd);
+
+ append_math_sub_imm_u32(desc, VARSEQOUTLEN, SEQINLEN, IMM,
+ ivsize);
+ } else {
+ append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0,
+ CAAM_CMD_SZ);
+ }
+
/* if assoclen + cryptlen is ZERO, skip to ICV write */
- append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
zero_assoc_jump_cmd2 = append_jump(desc, JUMP_TEST_ALL |
JUMP_COND_MATH_Z);
+ if (is_qi)
+ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
+ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+
/* if assoclen is ZERO, skip reading the assoc data */
append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL |
@@ -686,8 +713,11 @@ void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata,
append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1);
- /* jump the zero-payload commands */
- append_jump(desc, JUMP_TEST_ALL | 2);
+ /* jump to ICV writing */
+ if (is_qi)
+ append_jump(desc, JUMP_TEST_ALL | 4);
+ else
+ append_jump(desc, JUMP_TEST_ALL | 2);
/* zero-payload commands */
set_jump_tgt_here(desc, zero_payload_jump_cmd);
@@ -695,10 +725,18 @@ void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata,
/* read assoc data */
append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF |
FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST1);
+ if (is_qi)
+ /* jump to ICV writing */
+ append_jump(desc, JUMP_TEST_ALL | 2);
/* There is no input data */
set_jump_tgt_here(desc, zero_assoc_jump_cmd2);
+ if (is_qi)
+ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
+ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 |
+ FIFOLD_TYPE_LAST1);
+
/* write ICV */
append_seq_store(desc, icvsize, LDST_CLASS_1_CCB |
LDST_SRCDST_BYTE_CONTEXT);
@@ -715,10 +753,13 @@ EXPORT_SYMBOL(cnstr_shdsc_gcm_encap);
* @desc: pointer to buffer used for descriptor construction
* @cdata: pointer to block cipher transform definitions
* Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
+ * @ivsize: initialization vector size
* @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_qi: true when called from caam/qi
*/
void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata,
- unsigned int icvsize)
+ unsigned int ivsize, unsigned int icvsize,
+ const bool is_qi)
{
u32 *key_jump_cmd, *zero_payload_jump_cmd, *zero_assoc_jump_cmd1;
@@ -739,6 +780,24 @@ void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata,
append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
OP_ALG_DECRYPT | OP_ALG_ICV_ON);
+ if (is_qi) {
+ u32 *wait_load_cmd;
+
+ /* REG3 = assoclen */
+ append_seq_load(desc, 4, LDST_CLASS_DECO |
+ LDST_SRCDST_WORD_DECO_MATH3 |
+ (4 << LDST_OFFSET_SHIFT));
+
+ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+ JUMP_COND_CALM | JUMP_COND_NCP |
+ JUMP_COND_NOP | JUMP_COND_NIP |
+ JUMP_COND_NIFP);
+ set_jump_tgt_here(desc, wait_load_cmd);
+
+ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
+ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+ }
+
/* if assoclen is ZERO, skip reading the assoc data */
append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL |
@@ -791,10 +850,13 @@ EXPORT_SYMBOL(cnstr_shdsc_gcm_decap);
* @desc: pointer to buffer used for descriptor construction
* @cdata: pointer to block cipher transform definitions
* Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
+ * @ivsize: initialization vector size
* @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_qi: true when called from caam/qi
*/
void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata,
- unsigned int icvsize)
+ unsigned int ivsize, unsigned int icvsize,
+ const bool is_qi)
{
u32 *key_jump_cmd;
@@ -815,7 +877,29 @@ void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata,
append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
OP_ALG_ENCRYPT);
- append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8);
+ if (is_qi) {
+ u32 *wait_load_cmd;
+
+ /* REG3 = assoclen */
+ append_seq_load(desc, 4, LDST_CLASS_DECO |
+ LDST_SRCDST_WORD_DECO_MATH3 |
+ (4 << LDST_OFFSET_SHIFT));
+
+ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+ JUMP_COND_CALM | JUMP_COND_NCP |
+ JUMP_COND_NOP | JUMP_COND_NIP |
+ JUMP_COND_NIFP);
+ set_jump_tgt_here(desc, wait_load_cmd);
+
+ /* Read salt and IV */
+ append_fifo_load_as_imm(desc, (void *)(cdata->key_virt +
+ cdata->keylen), 4, FIFOLD_CLASS_CLASS1 |
+ FIFOLD_TYPE_IV);
+ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
+ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+ }
+
+ append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, ivsize);
append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
/* Read assoc data */
@@ -823,7 +907,7 @@ void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata,
FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1);
/* Skip IV */
- append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP);
+ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_SKIP);
/* Will read cryptlen bytes */
append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
@@ -862,10 +946,13 @@ EXPORT_SYMBOL(cnstr_shdsc_rfc4106_encap);
* @desc: pointer to buffer used for descriptor construction
* @cdata: pointer to block cipher transform definitions
* Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
+ * @ivsize: initialization vector size
* @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_qi: true when called from caam/qi
*/
void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata,
- unsigned int icvsize)
+ unsigned int ivsize, unsigned int icvsize,
+ const bool is_qi)
{
u32 *key_jump_cmd;
@@ -887,7 +974,29 @@ void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata,
append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
OP_ALG_DECRYPT | OP_ALG_ICV_ON);
- append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8);
+ if (is_qi) {
+ u32 *wait_load_cmd;
+
+ /* REG3 = assoclen */
+ append_seq_load(desc, 4, LDST_CLASS_DECO |
+ LDST_SRCDST_WORD_DECO_MATH3 |
+ (4 << LDST_OFFSET_SHIFT));
+
+ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+ JUMP_COND_CALM | JUMP_COND_NCP |
+ JUMP_COND_NOP | JUMP_COND_NIP |
+ JUMP_COND_NIFP);
+ set_jump_tgt_here(desc, wait_load_cmd);
+
+ /* Read salt and IV */
+ append_fifo_load_as_imm(desc, (void *)(cdata->key_virt +
+ cdata->keylen), 4, FIFOLD_CLASS_CLASS1 |
+ FIFOLD_TYPE_IV);
+ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
+ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+ }
+
+ append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, ivsize);
append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
/* Read assoc data */
@@ -895,7 +1004,7 @@ void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata,
FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1);
/* Skip IV */
- append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP);
+ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_SKIP);
/* Will read cryptlen bytes */
append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG3, CAAM_CMD_SZ);
@@ -934,10 +1043,13 @@ EXPORT_SYMBOL(cnstr_shdsc_rfc4106_decap);
* @desc: pointer to buffer used for descriptor construction
* @cdata: pointer to block cipher transform definitions
* Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
+ * @ivsize: initialization vector size
* @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_qi: true when called from caam/qi
*/
void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata,
- unsigned int icvsize)
+ unsigned int ivsize, unsigned int icvsize,
+ const bool is_qi)
{
u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd;
@@ -958,6 +1070,18 @@ void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata,
append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
OP_ALG_ENCRYPT);
+ if (is_qi) {
+ /* assoclen is not needed, skip it */
+ append_seq_fifo_load(desc, 4, FIFOLD_CLASS_SKIP);
+
+ /* Read salt and IV */
+ append_fifo_load_as_imm(desc, (void *)(cdata->key_virt +
+ cdata->keylen), 4, FIFOLD_CLASS_CLASS1 |
+ FIFOLD_TYPE_IV);
+ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
+ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+ }
+
/* assoclen + cryptlen = seqinlen */
append_math_sub(desc, REG3, SEQINLEN, REG0, CAAM_CMD_SZ);
@@ -1004,10 +1128,13 @@ EXPORT_SYMBOL(cnstr_shdsc_rfc4543_encap);
* @desc: pointer to buffer used for descriptor construction
* @cdata: pointer to block cipher transform definitions
* Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM.
+ * @ivsize: initialization vector size
* @icvsize: integrity check value (ICV) size (truncated or full)
+ * @is_qi: true when called from caam/qi
*/
void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata,
- unsigned int icvsize)
+ unsigned int ivsize, unsigned int icvsize,
+ const bool is_qi)
{
u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd;
@@ -1028,6 +1155,18 @@ void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata,
append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL |
OP_ALG_DECRYPT | OP_ALG_ICV_ON);
+ if (is_qi) {
+ /* assoclen is not needed, skip it */
+ append_seq_fifo_load(desc, 4, FIFOLD_CLASS_SKIP);
+
+ /* Read salt and IV */
+ append_fifo_load_as_imm(desc, (void *)(cdata->key_virt +
+ cdata->keylen), 4, FIFOLD_CLASS_CLASS1 |
+ FIFOLD_TYPE_IV);
+ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 |
+ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1);
+ }
+
/* assoclen + cryptlen = seqoutlen */
append_math_sub(desc, REG3, SEQOUTLEN, REG0, CAAM_CMD_SZ);
diff --git a/drivers/crypto/caam/caamalg_desc.h b/drivers/crypto/caam/caamalg_desc.h
index 5f9445ae2114..a917af5776ce 100644
--- a/drivers/crypto/caam/caamalg_desc.h
+++ b/drivers/crypto/caam/caamalg_desc.h
@@ -27,14 +27,20 @@
#define DESC_GCM_BASE (3 * CAAM_CMD_SZ)
#define DESC_GCM_ENC_LEN (DESC_GCM_BASE + 16 * CAAM_CMD_SZ)
#define DESC_GCM_DEC_LEN (DESC_GCM_BASE + 12 * CAAM_CMD_SZ)
+#define DESC_QI_GCM_ENC_LEN (DESC_GCM_ENC_LEN + 6 * CAAM_CMD_SZ)
+#define DESC_QI_GCM_DEC_LEN (DESC_GCM_DEC_LEN + 3 * CAAM_CMD_SZ)
#define DESC_RFC4106_BASE (3 * CAAM_CMD_SZ)
#define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ)
#define DESC_RFC4106_DEC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ)
+#define DESC_QI_RFC4106_ENC_LEN (DESC_RFC4106_ENC_LEN + 5 * CAAM_CMD_SZ)
+#define DESC_QI_RFC4106_DEC_LEN (DESC_RFC4106_DEC_LEN + 5 * CAAM_CMD_SZ)
#define DESC_RFC4543_BASE (3 * CAAM_CMD_SZ)
#define DESC_RFC4543_ENC_LEN (DESC_RFC4543_BASE + 11 * CAAM_CMD_SZ)
#define DESC_RFC4543_DEC_LEN (DESC_RFC4543_BASE + 12 * CAAM_CMD_SZ)
+#define DESC_QI_RFC4543_ENC_LEN (DESC_RFC4543_ENC_LEN + 4 * CAAM_CMD_SZ)
+#define DESC_QI_RFC4543_DEC_LEN (DESC_RFC4543_DEC_LEN + 4 * CAAM_CMD_SZ)
#define DESC_ABLKCIPHER_BASE (3 * CAAM_CMD_SZ)
#define DESC_ABLKCIPHER_ENC_LEN (DESC_ABLKCIPHER_BASE + \
@@ -67,22 +73,28 @@ void cnstr_shdsc_aead_givencap(u32 * const desc, struct alginfo *cdata,
const bool is_qi, int era);
void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata,
- unsigned int icvsize);
+ unsigned int ivsize, unsigned int icvsize,
+ const bool is_qi);
void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata,
- unsigned int icvsize);
+ unsigned int ivsize, unsigned int icvsize,
+ const bool is_qi);
void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata,
- unsigned int icvsize);
+ unsigned int ivsize, unsigned int icvsize,
+ const bool is_qi);
void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata,
- unsigned int icvsize);
+ unsigned int ivsize, unsigned int icvsize,
+ const bool is_qi);
void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata,
- unsigned int icvsize);
+ unsigned int ivsize, unsigned int icvsize,
+ const bool is_qi);
void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata,
- unsigned int icvsize);
+ unsigned int ivsize, unsigned int icvsize,
+ const bool is_qi);
void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata,
unsigned int ivsize, const bool is_rfc3686,
diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c
index 4aecc9435f69..cacda0831390 100644
--- a/drivers/crypto/caam/caamalg_qi.c
+++ b/drivers/crypto/caam/caamalg_qi.c
@@ -278,12 +278,317 @@ skip_split_key:
}
}
+ memzero_explicit(&keys, sizeof(keys));
return ret;
badkey:
crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ memzero_explicit(&keys, sizeof(keys));
return -EINVAL;
}
+static int gcm_set_sh_desc(struct crypto_aead *aead)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ unsigned int ivsize = crypto_aead_ivsize(aead);
+ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
+ ctx->cdata.keylen;
+
+ if (!ctx->cdata.keylen || !ctx->authsize)
+ return 0;
+
+ /*
+ * Job Descriptor and Shared Descriptor
+ * must fit into the 64-word Descriptor h/w Buffer
+ */
+ if (rem_bytes >= DESC_QI_GCM_ENC_LEN) {
+ ctx->cdata.key_inline = true;
+ ctx->cdata.key_virt = ctx->key;
+ } else {
+ ctx->cdata.key_inline = false;
+ ctx->cdata.key_dma = ctx->key_dma;
+ }
+
+ cnstr_shdsc_gcm_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize,
+ ctx->authsize, true);
+
+ /*
+ * Job Descriptor and Shared Descriptor
+ * must fit into the 64-word Descriptor h/w Buffer
+ */
+ if (rem_bytes >= DESC_QI_GCM_DEC_LEN) {
+ ctx->cdata.key_inline = true;
+ ctx->cdata.key_virt = ctx->key;
+ } else {
+ ctx->cdata.key_inline = false;
+ ctx->cdata.key_dma = ctx->key_dma;
+ }
+
+ cnstr_shdsc_gcm_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize,
+ ctx->authsize, true);
+
+ return 0;
+}
+
+static int gcm_setauthsize(struct crypto_aead *authenc, unsigned int authsize)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
+
+ ctx->authsize = authsize;
+ gcm_set_sh_desc(authenc);
+
+ return 0;
+}
+
+static int gcm_setkey(struct crypto_aead *aead,
+ const u8 *key, unsigned int keylen)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
+ int ret;
+
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+#endif
+
+ memcpy(ctx->key, key, keylen);
+ dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, ctx->dir);
+ ctx->cdata.keylen = keylen;
+
+ ret = gcm_set_sh_desc(aead);
+ if (ret)
+ return ret;
+
+ /* Now update the driver contexts with the new shared descriptor */
+ if (ctx->drv_ctx[ENCRYPT]) {
+ ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT],
+ ctx->sh_desc_enc);
+ if (ret) {
+ dev_err(jrdev, "driver enc context update failed\n");
+ return ret;
+ }
+ }
+
+ if (ctx->drv_ctx[DECRYPT]) {
+ ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT],
+ ctx->sh_desc_dec);
+ if (ret) {
+ dev_err(jrdev, "driver dec context update failed\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int rfc4106_set_sh_desc(struct crypto_aead *aead)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ unsigned int ivsize = crypto_aead_ivsize(aead);
+ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
+ ctx->cdata.keylen;
+
+ if (!ctx->cdata.keylen || !ctx->authsize)
+ return 0;
+
+ ctx->cdata.key_virt = ctx->key;
+
+ /*
+ * Job Descriptor and Shared Descriptor
+ * must fit into the 64-word Descriptor h/w Buffer
+ */
+ if (rem_bytes >= DESC_QI_RFC4106_ENC_LEN) {
+ ctx->cdata.key_inline = true;
+ } else {
+ ctx->cdata.key_inline = false;
+ ctx->cdata.key_dma = ctx->key_dma;
+ }
+
+ cnstr_shdsc_rfc4106_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize,
+ ctx->authsize, true);
+
+ /*
+ * Job Descriptor and Shared Descriptor
+ * must fit into the 64-word Descriptor h/w Buffer
+ */
+ if (rem_bytes >= DESC_QI_RFC4106_DEC_LEN) {
+ ctx->cdata.key_inline = true;
+ } else {
+ ctx->cdata.key_inline = false;
+ ctx->cdata.key_dma = ctx->key_dma;
+ }
+
+ cnstr_shdsc_rfc4106_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize,
+ ctx->authsize, true);
+
+ return 0;
+}
+
+static int rfc4106_setauthsize(struct crypto_aead *authenc,
+ unsigned int authsize)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
+
+ ctx->authsize = authsize;
+ rfc4106_set_sh_desc(authenc);
+
+ return 0;
+}
+
+static int rfc4106_setkey(struct crypto_aead *aead,
+ const u8 *key, unsigned int keylen)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
+ int ret;
+
+ if (keylen < 4)
+ return -EINVAL;
+
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+#endif
+
+ memcpy(ctx->key, key, keylen);
+ /*
+ * The last four bytes of the key material are used as the salt value
+ * in the nonce. Update the AES key length.
+ */
+ ctx->cdata.keylen = keylen - 4;
+ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen,
+ ctx->dir);
+
+ ret = rfc4106_set_sh_desc(aead);
+ if (ret)
+ return ret;
+
+ /* Now update the driver contexts with the new shared descriptor */
+ if (ctx->drv_ctx[ENCRYPT]) {
+ ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT],
+ ctx->sh_desc_enc);
+ if (ret) {
+ dev_err(jrdev, "driver enc context update failed\n");
+ return ret;
+ }
+ }
+
+ if (ctx->drv_ctx[DECRYPT]) {
+ ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT],
+ ctx->sh_desc_dec);
+ if (ret) {
+ dev_err(jrdev, "driver dec context update failed\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int rfc4543_set_sh_desc(struct crypto_aead *aead)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ unsigned int ivsize = crypto_aead_ivsize(aead);
+ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN -
+ ctx->cdata.keylen;
+
+ if (!ctx->cdata.keylen || !ctx->authsize)
+ return 0;
+
+ ctx->cdata.key_virt = ctx->key;
+
+ /*
+ * Job Descriptor and Shared Descriptor
+ * must fit into the 64-word Descriptor h/w Buffer
+ */
+ if (rem_bytes >= DESC_QI_RFC4543_ENC_LEN) {
+ ctx->cdata.key_inline = true;
+ } else {
+ ctx->cdata.key_inline = false;
+ ctx->cdata.key_dma = ctx->key_dma;
+ }
+
+ cnstr_shdsc_rfc4543_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize,
+ ctx->authsize, true);
+
+ /*
+ * Job Descriptor and Shared Descriptor
+ * must fit into the 64-word Descriptor h/w Buffer
+ */
+ if (rem_bytes >= DESC_QI_RFC4543_DEC_LEN) {
+ ctx->cdata.key_inline = true;
+ } else {
+ ctx->cdata.key_inline = false;
+ ctx->cdata.key_dma = ctx->key_dma;
+ }
+
+ cnstr_shdsc_rfc4543_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize,
+ ctx->authsize, true);
+
+ return 0;
+}
+
+static int rfc4543_setauthsize(struct crypto_aead *authenc,
+ unsigned int authsize)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
+
+ ctx->authsize = authsize;
+ rfc4543_set_sh_desc(authenc);
+
+ return 0;
+}
+
+static int rfc4543_setkey(struct crypto_aead *aead,
+ const u8 *key, unsigned int keylen)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
+ int ret;
+
+ if (keylen < 4)
+ return -EINVAL;
+
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+#endif
+
+ memcpy(ctx->key, key, keylen);
+ /*
+ * The last four bytes of the key material are used as the salt value
+ * in the nonce. Update the AES key length.
+ */
+ ctx->cdata.keylen = keylen - 4;
+ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen,
+ ctx->dir);
+
+ ret = rfc4543_set_sh_desc(aead);
+ if (ret)
+ return ret;
+
+ /* Now update the driver contexts with the new shared descriptor */
+ if (ctx->drv_ctx[ENCRYPT]) {
+ ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT],
+ ctx->sh_desc_enc);
+ if (ret) {
+ dev_err(jrdev, "driver enc context update failed\n");
+ return ret;
+ }
+ }
+
+ if (ctx->drv_ctx[DECRYPT]) {
+ ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT],
+ ctx->sh_desc_dec);
+ if (ret) {
+ dev_err(jrdev, "driver dec context update failed\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
const u8 *key, unsigned int keylen)
{
@@ -562,8 +867,18 @@ static void aead_done(struct caam_drv_req *drv_req, u32 status)
qidev = caam_ctx->qidev;
if (unlikely(status)) {
+ u32 ssrc = status & JRSTA_SSRC_MASK;
+ u8 err_id = status & JRSTA_CCBERR_ERRID_MASK;
+
caam_jr_strstatus(qidev, status);
- ecode = -EIO;
+ /*
+ * verify hw auth check passed else return -EBADMSG
+ */
+ if (ssrc == JRSTA_SSRC_CCB_ERROR &&
+ err_id == JRSTA_CCBERR_ERRID_ICVCHK)
+ ecode = -EBADMSG;
+ else
+ ecode = -EIO;
}
edesc = container_of(drv_req, typeof(*edesc), drv_req);
@@ -807,6 +1122,22 @@ static int aead_decrypt(struct aead_request *req)
return aead_crypt(req, false);
}
+static int ipsec_gcm_encrypt(struct aead_request *req)
+{
+ if (req->assoclen < 8)
+ return -EINVAL;
+
+ return aead_crypt(req, true);
+}
+
+static int ipsec_gcm_decrypt(struct aead_request *req)
+{
+ if (req->assoclen < 8)
+ return -EINVAL;
+
+ return aead_crypt(req, false);
+}
+
static void ablkcipher_done(struct caam_drv_req *drv_req, u32 status)
{
struct ablkcipher_edesc *edesc;
@@ -1327,6 +1658,61 @@ static struct caam_alg_template driver_algs[] = {
};
static struct caam_aead_alg driver_aeads[] = {
+ {
+ .aead = {
+ .base = {
+ .cra_name = "rfc4106(gcm(aes))",
+ .cra_driver_name = "rfc4106-gcm-aes-caam-qi",
+ .cra_blocksize = 1,
+ },
+ .setkey = rfc4106_setkey,
+ .setauthsize = rfc4106_setauthsize,
+ .encrypt = ipsec_gcm_encrypt,
+ .decrypt = ipsec_gcm_decrypt,
+ .ivsize = 8,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+ },
+ },
+ {
+ .aead = {
+ .base = {
+ .cra_name = "rfc4543(gcm(aes))",
+ .cra_driver_name = "rfc4543-gcm-aes-caam-qi",
+ .cra_blocksize = 1,
+ },
+ .setkey = rfc4543_setkey,
+ .setauthsize = rfc4543_setauthsize,
+ .encrypt = ipsec_gcm_encrypt,
+ .decrypt = ipsec_gcm_decrypt,
+ .ivsize = 8,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+ },
+ },
+ /* Galois Counter Mode */
+ {
+ .aead = {
+ .base = {
+ .cra_name = "gcm(aes)",
+ .cra_driver_name = "gcm-aes-caam-qi",
+ .cra_blocksize = 1,
+ },
+ .setkey = gcm_setkey,
+ .setauthsize = gcm_setauthsize,
+ .encrypt = aead_encrypt,
+ .decrypt = aead_decrypt,
+ .ivsize = 12,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .caam = {
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM,
+ }
+ },
/* single-pass ipsec_esp descriptor */
{
.aead = {
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index e843cf410373..e4cc636e1104 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -337,7 +337,8 @@ static int caam_remove(struct platform_device *pdev)
/* shut clocks off before finalizing shutdown */
clk_disable_unprepare(ctrlpriv->caam_ipg);
- clk_disable_unprepare(ctrlpriv->caam_mem);
+ if (ctrlpriv->caam_mem)
+ clk_disable_unprepare(ctrlpriv->caam_mem);
clk_disable_unprepare(ctrlpriv->caam_aclk);
if (ctrlpriv->caam_emi_slow)
clk_disable_unprepare(ctrlpriv->caam_emi_slow);
@@ -466,14 +467,17 @@ static int caam_probe(struct platform_device *pdev)
}
ctrlpriv->caam_ipg = clk;
- clk = caam_drv_identify_clk(&pdev->dev, "mem");
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- dev_err(&pdev->dev,
- "can't identify CAAM mem clk: %d\n", ret);
- return ret;
+ if (!of_machine_is_compatible("fsl,imx7d") &&
+ !of_machine_is_compatible("fsl,imx7s")) {
+ clk = caam_drv_identify_clk(&pdev->dev, "mem");
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ dev_err(&pdev->dev,
+ "can't identify CAAM mem clk: %d\n", ret);
+ return ret;
+ }
+ ctrlpriv->caam_mem = clk;
}
- ctrlpriv->caam_mem = clk;
clk = caam_drv_identify_clk(&pdev->dev, "aclk");
if (IS_ERR(clk)) {
@@ -484,7 +488,9 @@ static int caam_probe(struct platform_device *pdev)
}
ctrlpriv->caam_aclk = clk;
- if (!of_machine_is_compatible("fsl,imx6ul")) {
+ if (!of_machine_is_compatible("fsl,imx6ul") &&
+ !of_machine_is_compatible("fsl,imx7d") &&
+ !of_machine_is_compatible("fsl,imx7s")) {
clk = caam_drv_identify_clk(&pdev->dev, "emi_slow");
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
@@ -501,11 +507,13 @@ static int caam_probe(struct platform_device *pdev)
return ret;
}
- ret = clk_prepare_enable(ctrlpriv->caam_mem);
- if (ret < 0) {
- dev_err(&pdev->dev, "can't enable CAAM secure mem clock: %d\n",
- ret);
- goto disable_caam_ipg;
+ if (ctrlpriv->caam_mem) {
+ ret = clk_prepare_enable(ctrlpriv->caam_mem);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can't enable CAAM secure mem clock: %d\n",
+ ret);
+ goto disable_caam_ipg;
+ }
}
ret = clk_prepare_enable(ctrlpriv->caam_aclk);
@@ -815,9 +823,6 @@ static int caam_probe(struct platform_device *pdev)
return 0;
caam_remove:
-#ifdef CONFIG_DEBUG_FS
- debugfs_remove_recursive(ctrlpriv->dfs_root);
-#endif
caam_remove(pdev);
return ret;
@@ -829,7 +834,8 @@ disable_caam_emi_slow:
disable_caam_aclk:
clk_disable_unprepare(ctrlpriv->caam_aclk);
disable_caam_mem:
- clk_disable_unprepare(ctrlpriv->caam_mem);
+ if (ctrlpriv->caam_mem)
+ clk_disable_unprepare(ctrlpriv->caam_mem);
disable_caam_ipg:
clk_disable_unprepare(ctrlpriv->caam_ipg);
return ret;
diff --git a/drivers/crypto/caam/qi.c b/drivers/crypto/caam/qi.c
index f9a44f485aac..b9480828da38 100644
--- a/drivers/crypto/caam/qi.c
+++ b/drivers/crypto/caam/qi.c
@@ -579,8 +579,15 @@ static enum qman_cb_dqrr_result caam_rsp_fq_dqrr_cb(struct qman_portal *p,
fd = &dqrr->fd;
status = be32_to_cpu(fd->status);
- if (unlikely(status))
- dev_err(qidev, "Error: %#x in CAAM response FD\n", status);
+ if (unlikely(status)) {
+ u32 ssrc = status & JRSTA_SSRC_MASK;
+ u8 err_id = status & JRSTA_CCBERR_ERRID_MASK;
+
+ if (ssrc != JRSTA_SSRC_CCB_ERROR ||
+ err_id != JRSTA_CCBERR_ERRID_ICVCHK)
+ dev_err(qidev, "Error: %#x in CAAM response FD\n",
+ status);
+ }
if (unlikely(qm_fd_get_format(fd) != qm_fd_compound)) {
dev_err(qidev, "Non-compound FD from CAAM\n");
diff --git a/drivers/crypto/cavium/cpt/cptpf_main.c b/drivers/crypto/cavium/cpt/cptpf_main.c
index 34a6d8bf229e..06ad85ab5e86 100644
--- a/drivers/crypto/cavium/cpt/cptpf_main.c
+++ b/drivers/crypto/cavium/cpt/cptpf_main.c
@@ -436,7 +436,7 @@ static int cpt_device_init(struct cpt_device *cpt)
/* Reset the PF when probed first */
cpt_reset(cpt);
- mdelay(100);
+ msleep(100);
/*Check BIST status*/
bist = (u64)cpt_check_bist_status(cpt);
diff --git a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c
index 60fc0fa26fd3..26687f318de6 100644
--- a/drivers/crypto/ccp/ccp-crypto-aes-cmac.c
+++ b/drivers/crypto/ccp/ccp-crypto-aes-cmac.c
@@ -46,7 +46,7 @@ static int ccp_aes_cmac_complete(struct crypto_async_request *async_req,
}
/* Update result area if supplied */
- if (req->result)
+ if (req->result && rctx->final)
memcpy(req->result, rctx->iv, digest_size);
e_free:
diff --git a/drivers/crypto/ccp/ccp-crypto-rsa.c b/drivers/crypto/ccp/ccp-crypto-rsa.c
index e6db8672d89c..05850dfd7940 100644
--- a/drivers/crypto/ccp/ccp-crypto-rsa.c
+++ b/drivers/crypto/ccp/ccp-crypto-rsa.c
@@ -60,10 +60,9 @@ static int ccp_rsa_complete(struct crypto_async_request *async_req, int ret)
static unsigned int ccp_rsa_maxsize(struct crypto_akcipher *tfm)
{
- if (ccp_version() > CCP_VERSION(3, 0))
- return CCP5_RSA_MAXMOD;
- else
- return CCP_RSA_MAXMOD;
+ struct ccp_ctx *ctx = akcipher_tfm_ctx(tfm);
+
+ return ctx->u.rsa.n_len;
}
static int ccp_rsa_crypt(struct akcipher_request *req, bool encrypt)
diff --git a/drivers/crypto/ccp/ccp-crypto-sha.c b/drivers/crypto/ccp/ccp-crypto-sha.c
index 8b9b16d433f7..871c9628a2ee 100644
--- a/drivers/crypto/ccp/ccp-crypto-sha.c
+++ b/drivers/crypto/ccp/ccp-crypto-sha.c
@@ -47,7 +47,7 @@ static int ccp_sha_complete(struct crypto_async_request *async_req, int ret)
}
/* Update result area if supplied */
- if (req->result)
+ if (req->result && rctx->final)
memcpy(req->result, rctx->ctx, digest_size);
e_free:
diff --git a/drivers/crypto/ccp/ccp-debugfs.c b/drivers/crypto/ccp/ccp-debugfs.c
index 59d4ca4e72d8..1a734bd2070a 100644
--- a/drivers/crypto/ccp/ccp-debugfs.c
+++ b/drivers/crypto/ccp/ccp-debugfs.c
@@ -278,7 +278,7 @@ static const struct file_operations ccp_debugfs_stats_ops = {
};
static struct dentry *ccp_debugfs_dir;
-static DEFINE_RWLOCK(ccp_debugfs_lock);
+static DEFINE_MUTEX(ccp_debugfs_lock);
#define MAX_NAME_LEN 20
@@ -290,16 +290,15 @@ void ccp5_debugfs_setup(struct ccp_device *ccp)
struct dentry *debugfs_stats;
struct dentry *debugfs_q_instance;
struct dentry *debugfs_q_stats;
- unsigned long flags;
int i;
if (!debugfs_initialized())
return;
- write_lock_irqsave(&ccp_debugfs_lock, flags);
+ mutex_lock(&ccp_debugfs_lock);
if (!ccp_debugfs_dir)
ccp_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
- write_unlock_irqrestore(&ccp_debugfs_lock, flags);
+ mutex_unlock(&ccp_debugfs_lock);
if (!ccp_debugfs_dir)
return;
diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c
index 8b9da58459df..67155cb21636 100644
--- a/drivers/crypto/ccp/ccp-dmaengine.c
+++ b/drivers/crypto/ccp/ccp-dmaengine.c
@@ -38,7 +38,7 @@ static unsigned int dma_chan_attr = CCP_DMA_DFLT;
module_param(dma_chan_attr, uint, 0444);
MODULE_PARM_DESC(dma_chan_attr, "Set DMA channel visibility: 0 (default) = device defaults, 1 = make private, 2 = make public");
-unsigned int ccp_get_dma_chan_attr(struct ccp_device *ccp)
+static unsigned int ccp_get_dma_chan_attr(struct ccp_device *ccp)
{
switch (dma_chan_attr) {
case CCP_DMA_DFLT:
diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c
index 406b95329b3d..0ea43cdeb05f 100644
--- a/drivers/crypto/ccp/ccp-ops.c
+++ b/drivers/crypto/ccp/ccp-ops.c
@@ -178,14 +178,18 @@ static int ccp_init_dm_workarea(struct ccp_dm_workarea *wa,
return 0;
}
-static void ccp_set_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
- struct scatterlist *sg, unsigned int sg_offset,
- unsigned int len)
+static int ccp_set_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
+ struct scatterlist *sg, unsigned int sg_offset,
+ unsigned int len)
{
WARN_ON(!wa->address);
+ if (len > (wa->length - wa_offset))
+ return -EINVAL;
+
scatterwalk_map_and_copy(wa->address + wa_offset, sg, sg_offset, len,
0);
+ return 0;
}
static void ccp_get_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
@@ -205,8 +209,11 @@ static int ccp_reverse_set_dm_area(struct ccp_dm_workarea *wa,
unsigned int len)
{
u8 *p, *q;
+ int rc;
- ccp_set_dm_area(wa, wa_offset, sg, sg_offset, len);
+ rc = ccp_set_dm_area(wa, wa_offset, sg, sg_offset, len);
+ if (rc)
+ return rc;
p = wa->address + wa_offset;
q = p + len - 1;
@@ -509,7 +516,9 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
return ret;
dm_offset = CCP_SB_BYTES - aes->key_len;
- ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
+ ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
+ if (ret)
+ goto e_key;
ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
@@ -528,7 +537,9 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
goto e_key;
dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
- ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
+ ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
+ if (ret)
+ goto e_ctx;
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
@@ -556,8 +567,10 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
goto e_src;
}
- ccp_set_dm_area(&ctx, 0, aes->cmac_key, 0,
- aes->cmac_key_len);
+ ret = ccp_set_dm_area(&ctx, 0, aes->cmac_key, 0,
+ aes->cmac_key_len);
+ if (ret)
+ goto e_src;
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
@@ -666,7 +679,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
return ret;
dm_offset = CCP_SB_BYTES - aes->key_len;
- ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
+ ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
+ if (ret)
+ goto e_key;
ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
@@ -685,7 +700,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
goto e_key;
dm_offset = CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES - aes->iv_len;
- ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
+ ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
+ if (ret)
+ goto e_ctx;
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
CCP_PASSTHRU_BYTESWAP_256BIT);
@@ -777,7 +794,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
goto e_dst;
}
- ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
+ ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
+ if (ret)
+ goto e_dst;
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
CCP_PASSTHRU_BYTESWAP_256BIT);
@@ -820,7 +839,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
DMA_BIDIRECTIONAL);
if (ret)
goto e_tag;
- ccp_set_dm_area(&tag, 0, p_tag, 0, AES_BLOCK_SIZE);
+ ret = ccp_set_dm_area(&tag, 0, p_tag, 0, AES_BLOCK_SIZE);
+ if (ret)
+ goto e_tag;
ret = memcmp(tag.address, final_wa.address, AES_BLOCK_SIZE);
ccp_dm_free(&tag);
@@ -914,7 +935,9 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
return ret;
dm_offset = CCP_SB_BYTES - aes->key_len;
- ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
+ ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
+ if (ret)
+ goto e_key;
ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
@@ -935,7 +958,9 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
if (aes->mode != CCP_AES_MODE_ECB) {
/* Load the AES context - convert to LE */
dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
- ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
+ ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
+ if (ret)
+ goto e_ctx;
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) {
@@ -1113,8 +1138,12 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,
* big endian to little endian.
*/
dm_offset = CCP_SB_BYTES - AES_KEYSIZE_128;
- ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len);
- ccp_set_dm_area(&key, 0, xts->key, xts->key_len, xts->key_len);
+ ret = ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len);
+ if (ret)
+ goto e_key;
+ ret = ccp_set_dm_area(&key, 0, xts->key, xts->key_len, xts->key_len);
+ if (ret)
+ goto e_key;
} else {
/* Version 5 CCPs use a 512-bit space for the key: each portion
* occupies 256 bits, or one entire slot, and is zero-padded.
@@ -1123,9 +1152,13 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,
dm_offset = CCP_SB_BYTES;
pad = dm_offset - xts->key_len;
- ccp_set_dm_area(&key, pad, xts->key, 0, xts->key_len);
- ccp_set_dm_area(&key, dm_offset + pad, xts->key, xts->key_len,
- xts->key_len);
+ ret = ccp_set_dm_area(&key, pad, xts->key, 0, xts->key_len);
+ if (ret)
+ goto e_key;
+ ret = ccp_set_dm_area(&key, dm_offset + pad, xts->key,
+ xts->key_len, xts->key_len);
+ if (ret)
+ goto e_key;
}
ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
CCP_PASSTHRU_BYTESWAP_256BIT);
@@ -1144,7 +1177,9 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,
if (ret)
goto e_key;
- ccp_set_dm_area(&ctx, 0, xts->iv, 0, xts->iv_len);
+ ret = ccp_set_dm_area(&ctx, 0, xts->iv, 0, xts->iv_len);
+ if (ret)
+ goto e_ctx;
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
CCP_PASSTHRU_BYTESWAP_NOOP);
if (ret) {
@@ -1287,12 +1322,18 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
dm_offset = CCP_SB_BYTES - des3->key_len; /* Basic offset */
len_singlekey = des3->key_len / 3;
- ccp_set_dm_area(&key, dm_offset + 2 * len_singlekey,
- des3->key, 0, len_singlekey);
- ccp_set_dm_area(&key, dm_offset + len_singlekey,
- des3->key, len_singlekey, len_singlekey);
- ccp_set_dm_area(&key, dm_offset,
- des3->key, 2 * len_singlekey, len_singlekey);
+ ret = ccp_set_dm_area(&key, dm_offset + 2 * len_singlekey,
+ des3->key, 0, len_singlekey);
+ if (ret)
+ goto e_key;
+ ret = ccp_set_dm_area(&key, dm_offset + len_singlekey,
+ des3->key, len_singlekey, len_singlekey);
+ if (ret)
+ goto e_key;
+ ret = ccp_set_dm_area(&key, dm_offset,
+ des3->key, 2 * len_singlekey, len_singlekey);
+ if (ret)
+ goto e_key;
/* Copy the key to the SB */
ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
@@ -1320,7 +1361,10 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
/* Load the context into the LSB */
dm_offset = CCP_SB_BYTES - des3->iv_len;
- ccp_set_dm_area(&ctx, dm_offset, des3->iv, 0, des3->iv_len);
+ ret = ccp_set_dm_area(&ctx, dm_offset, des3->iv, 0,
+ des3->iv_len);
+ if (ret)
+ goto e_ctx;
if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0))
load_mode = CCP_PASSTHRU_BYTESWAP_NOOP;
@@ -1604,8 +1648,10 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
}
} else {
/* Restore the context */
- ccp_set_dm_area(&ctx, 0, sha->ctx, 0,
- sb_count * CCP_SB_BYTES);
+ ret = ccp_set_dm_area(&ctx, 0, sha->ctx, 0,
+ sb_count * CCP_SB_BYTES);
+ if (ret)
+ goto e_ctx;
}
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
@@ -1927,7 +1973,9 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q,
if (ret)
return ret;
- ccp_set_dm_area(&mask, 0, pt->mask, 0, pt->mask_len);
+ ret = ccp_set_dm_area(&mask, 0, pt->mask, 0, pt->mask_len);
+ if (ret)
+ goto e_mask;
ret = ccp_copy_to_sb(cmd_q, &mask, op.jobid, op.sb_key,
CCP_PASSTHRU_BYTESWAP_NOOP);
if (ret) {
diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c
index b3afb6cc9d72..d95ec526587a 100644
--- a/drivers/crypto/ccp/psp-dev.c
+++ b/drivers/crypto/ccp/psp-dev.c
@@ -367,8 +367,6 @@ e_free:
void *psp_copy_user_blob(u64 __user uaddr, u32 len)
{
- void *data;
-
if (!uaddr || !len)
return ERR_PTR(-EINVAL);
@@ -376,18 +374,7 @@ void *psp_copy_user_blob(u64 __user uaddr, u32 len)
if (len > SEV_FW_BLOB_MAX_SIZE)
return ERR_PTR(-EINVAL);
- data = kmalloc(len, GFP_KERNEL);
- if (!data)
- return ERR_PTR(-ENOMEM);
-
- if (copy_from_user(data, (void __user *)(uintptr_t)uaddr, len))
- goto e_free;
-
- return data;
-
-e_free:
- kfree(data);
- return ERR_PTR(-EFAULT);
+ return memdup_user((void __user *)(uintptr_t)uaddr, len);
}
EXPORT_SYMBOL_GPL(psp_copy_user_blob);
diff --git a/drivers/crypto/ccp/sp-dev.c b/drivers/crypto/ccp/sp-dev.c
index eb0da6572720..e0459002eb71 100644
--- a/drivers/crypto/ccp/sp-dev.c
+++ b/drivers/crypto/ccp/sp-dev.c
@@ -252,12 +252,12 @@ struct sp_device *sp_get_psp_master_device(void)
goto unlock;
list_for_each_entry(i, &sp_units, entry) {
- if (i->psp_data)
+ if (i->psp_data && i->get_psp_master_device) {
+ ret = i->get_psp_master_device();
break;
+ }
}
- if (i->get_psp_master_device)
- ret = i->get_psp_master_device();
unlock:
write_unlock_irqrestore(&sp_unit_lock, flags);
return ret;
diff --git a/drivers/staging/ccree/Makefile b/drivers/crypto/ccree/Makefile
index bdc27970f95f..bdc27970f95f 100644
--- a/drivers/staging/ccree/Makefile
+++ b/drivers/crypto/ccree/Makefile
diff --git a/drivers/staging/ccree/cc_aead.c b/drivers/crypto/ccree/cc_aead.c
index b58413172231..03f4b9fce556 100644
--- a/drivers/staging/ccree/cc_aead.c
+++ b/drivers/crypto/ccree/cc_aead.c
@@ -257,7 +257,8 @@ done:
aead_request_complete(areq, err);
}
-static int xcbc_setkey(struct cc_hw_desc *desc, struct cc_aead_ctx *ctx)
+static unsigned int xcbc_setkey(struct cc_hw_desc *desc,
+ struct cc_aead_ctx *ctx)
{
/* Load the AES key */
hw_desc_init(&desc[0]);
@@ -307,7 +308,7 @@ static int hmac_setkey(struct cc_hw_desc *desc, struct cc_aead_ctx *ctx)
CC_SHA1_DIGEST_SIZE : CC_SHA256_DIGEST_SIZE;
struct cc_hmac_s *hmac = &ctx->auth_state.hmac;
- int idx = 0;
+ unsigned int idx = 0;
int i;
/* calc derived HMAC key */
@@ -326,7 +327,7 @@ static int hmac_setkey(struct cc_hw_desc *desc, struct cc_aead_ctx *ctx)
/* Load the hash current length*/
hw_desc_init(&desc[idx]);
set_cipher_mode(&desc[idx], hash_mode);
- set_din_const(&desc[idx], 0, HASH_LEN_SIZE);
+ set_din_const(&desc[idx], 0, ctx->drvdata->hash_len_sz);
set_flow_mode(&desc[idx], S_DIN_to_HASH);
set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
idx++;
@@ -414,9 +415,8 @@ static int validate_keys_sizes(struct cc_aead_ctx *ctx)
/* This function prepers the user key so it can pass to the hmac processing
* (copy to intenral buffer or hash in case of key longer than block
*/
-static int
-cc_get_plain_hmac_key(struct crypto_aead *tfm, const u8 *key,
- unsigned int keylen)
+static int cc_get_plain_hmac_key(struct crypto_aead *tfm, const u8 *key,
+ unsigned int keylen)
{
dma_addr_t key_dma_addr = 0;
struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
@@ -465,7 +465,7 @@ cc_get_plain_hmac_key(struct crypto_aead *tfm, const u8 *key,
/* Load the hash current length*/
hw_desc_init(&desc[idx]);
set_cipher_mode(&desc[idx], hashmode);
- set_din_const(&desc[idx], 0, HASH_LEN_SIZE);
+ set_din_const(&desc[idx], 0, ctx->drvdata->hash_len_sz);
set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED);
set_flow_mode(&desc[idx], S_DIN_to_HASH);
set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
@@ -536,15 +536,16 @@ cc_get_plain_hmac_key(struct crypto_aead *tfm, const u8 *key,
return rc;
}
-static int
-cc_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
+static int cc_aead_setkey(struct crypto_aead *tfm, const u8 *key,
+ unsigned int keylen)
{
struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm);
struct rtattr *rta = (struct rtattr *)key;
struct cc_crypto_req cc_req = {};
struct crypto_authenc_key_param *param;
struct cc_hw_desc desc[MAX_AEAD_SETKEY_SEQ];
- int seq_len = 0, rc = -EINVAL;
+ int rc = -EINVAL;
+ unsigned int seq_len = 0;
struct device *dev = drvdata_to_dev(ctx->drvdata);
dev_dbg(dev, "Setting key in context @%p for %s. key=%p keylen=%u\n",
@@ -876,7 +877,7 @@ static void cc_proc_digest_desc(struct aead_request *req,
set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
set_dout_dlli(&desc[idx], req_ctx->icv_dma_addr, ctx->authsize,
NS_BIT, 1);
- set_queue_last_ind(&desc[idx]);
+ set_queue_last_ind(ctx->drvdata, &desc[idx]);
if (ctx->auth_mode == DRV_HASH_XCBC_MAC) {
set_aes_not_hash_mode(&desc[idx]);
set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC);
@@ -892,7 +893,7 @@ static void cc_proc_digest_desc(struct aead_request *req,
set_flow_mode(&desc[idx], S_HASH_to_DOUT);
set_dout_dlli(&desc[idx], req_ctx->mac_buf_dma_addr,
ctx->authsize, NS_BIT, 1);
- set_queue_last_ind(&desc[idx]);
+ set_queue_last_ind(ctx->drvdata, &desc[idx]);
set_cipher_config0(&desc[idx],
HASH_DIGEST_RESULT_LITTLE_ENDIAN);
set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED);
@@ -1000,7 +1001,7 @@ static void cc_set_hmac_desc(struct aead_request *req, struct cc_hw_desc desc[],
hw_desc_init(&desc[idx]);
set_cipher_mode(&desc[idx], hash_mode);
set_din_sram(&desc[idx], cc_digest_len_addr(ctx->drvdata, hash_mode),
- HASH_LEN_SIZE);
+ ctx->drvdata->hash_len_sz);
set_flow_mode(&desc[idx], S_DIN_to_HASH);
set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
idx++;
@@ -1097,7 +1098,7 @@ static void cc_proc_scheme_desc(struct aead_request *req,
hw_desc_init(&desc[idx]);
set_cipher_mode(&desc[idx], hash_mode);
set_dout_sram(&desc[idx], aead_handle->sram_workspace_addr,
- HASH_LEN_SIZE);
+ ctx->drvdata->hash_len_sz);
set_flow_mode(&desc[idx], S_HASH_to_DOUT);
set_setup_mode(&desc[idx], SETUP_WRITE_STATE1);
set_cipher_do(&desc[idx], DO_PAD);
@@ -1127,7 +1128,7 @@ static void cc_proc_scheme_desc(struct aead_request *req,
hw_desc_init(&desc[idx]);
set_cipher_mode(&desc[idx], hash_mode);
set_din_sram(&desc[idx], cc_digest_len_addr(ctx->drvdata, hash_mode),
- HASH_LEN_SIZE);
+ ctx->drvdata->hash_len_sz);
set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED);
set_flow_mode(&desc[idx], S_DIN_to_HASH);
set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
@@ -1508,7 +1509,7 @@ static int cc_ccm(struct aead_request *req, struct cc_hw_desc desc[],
set_din_type(&desc[idx], DMA_DLLI, req_ctx->mac_buf_dma_addr,
ctx->authsize, NS_BIT);
set_dout_dlli(&desc[idx], mac_result, ctx->authsize, NS_BIT, 1);
- set_queue_last_ind(&desc[idx]);
+ set_queue_last_ind(ctx->drvdata, &desc[idx]);
set_flow_mode(&desc[idx], DIN_AES_DOUT);
idx++;
@@ -1771,7 +1772,7 @@ static void cc_proc_gcm_result(struct aead_request *req,
set_din_type(&desc[idx], DMA_DLLI, req_ctx->mac_buf_dma_addr,
AES_BLOCK_SIZE, NS_BIT);
set_dout_dlli(&desc[idx], mac_result, ctx->authsize, NS_BIT, 1);
- set_queue_last_ind(&desc[idx]);
+ set_queue_last_ind(ctx->drvdata, &desc[idx]);
set_flow_mode(&desc[idx], DIN_AES_DOUT);
idx++;
@@ -1906,7 +1907,7 @@ static int cc_proc_aead(struct aead_request *req,
return -EINVAL;
}
- /* Setup DX request structure */
+ /* Setup request structure */
cc_req.user_cb = (void *)cc_aead_complete;
cc_req.user_arg = (void *)req;
@@ -2337,11 +2338,11 @@ static int cc_rfc4543_gcm_decrypt(struct aead_request *req)
return rc;
}
-/* DX Block aead alg */
+/* aead alg */
static struct cc_alg_template aead_algs[] = {
{
.name = "authenc(hmac(sha1),cbc(aes))",
- .driver_name = "authenc-hmac-sha1-cbc-aes-dx",
+ .driver_name = "authenc-hmac-sha1-cbc-aes-ccree",
.blocksize = AES_BLOCK_SIZE,
.type = CRYPTO_ALG_TYPE_AEAD,
.template_aead = {
@@ -2357,10 +2358,11 @@ static struct cc_alg_template aead_algs[] = {
.cipher_mode = DRV_CIPHER_CBC,
.flow_mode = S_DIN_to_AES,
.auth_mode = DRV_HASH_SHA1,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "authenc(hmac(sha1),cbc(des3_ede))",
- .driver_name = "authenc-hmac-sha1-cbc-des3-dx",
+ .driver_name = "authenc-hmac-sha1-cbc-des3-ccree",
.blocksize = DES3_EDE_BLOCK_SIZE,
.type = CRYPTO_ALG_TYPE_AEAD,
.template_aead = {
@@ -2376,10 +2378,11 @@ static struct cc_alg_template aead_algs[] = {
.cipher_mode = DRV_CIPHER_CBC,
.flow_mode = S_DIN_to_DES,
.auth_mode = DRV_HASH_SHA1,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "authenc(hmac(sha256),cbc(aes))",
- .driver_name = "authenc-hmac-sha256-cbc-aes-dx",
+ .driver_name = "authenc-hmac-sha256-cbc-aes-ccree",
.blocksize = AES_BLOCK_SIZE,
.type = CRYPTO_ALG_TYPE_AEAD,
.template_aead = {
@@ -2395,10 +2398,11 @@ static struct cc_alg_template aead_algs[] = {
.cipher_mode = DRV_CIPHER_CBC,
.flow_mode = S_DIN_to_AES,
.auth_mode = DRV_HASH_SHA256,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "authenc(hmac(sha256),cbc(des3_ede))",
- .driver_name = "authenc-hmac-sha256-cbc-des3-dx",
+ .driver_name = "authenc-hmac-sha256-cbc-des3-ccree",
.blocksize = DES3_EDE_BLOCK_SIZE,
.type = CRYPTO_ALG_TYPE_AEAD,
.template_aead = {
@@ -2414,10 +2418,11 @@ static struct cc_alg_template aead_algs[] = {
.cipher_mode = DRV_CIPHER_CBC,
.flow_mode = S_DIN_to_DES,
.auth_mode = DRV_HASH_SHA256,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "authenc(xcbc(aes),cbc(aes))",
- .driver_name = "authenc-xcbc-aes-cbc-aes-dx",
+ .driver_name = "authenc-xcbc-aes-cbc-aes-ccree",
.blocksize = AES_BLOCK_SIZE,
.type = CRYPTO_ALG_TYPE_AEAD,
.template_aead = {
@@ -2433,10 +2438,11 @@ static struct cc_alg_template aead_algs[] = {
.cipher_mode = DRV_CIPHER_CBC,
.flow_mode = S_DIN_to_AES,
.auth_mode = DRV_HASH_XCBC_MAC,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "authenc(hmac(sha1),rfc3686(ctr(aes)))",
- .driver_name = "authenc-hmac-sha1-rfc3686-ctr-aes-dx",
+ .driver_name = "authenc-hmac-sha1-rfc3686-ctr-aes-ccree",
.blocksize = 1,
.type = CRYPTO_ALG_TYPE_AEAD,
.template_aead = {
@@ -2452,10 +2458,11 @@ static struct cc_alg_template aead_algs[] = {
.cipher_mode = DRV_CIPHER_CTR,
.flow_mode = S_DIN_to_AES,
.auth_mode = DRV_HASH_SHA1,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "authenc(hmac(sha256),rfc3686(ctr(aes)))",
- .driver_name = "authenc-hmac-sha256-rfc3686-ctr-aes-dx",
+ .driver_name = "authenc-hmac-sha256-rfc3686-ctr-aes-ccree",
.blocksize = 1,
.type = CRYPTO_ALG_TYPE_AEAD,
.template_aead = {
@@ -2471,10 +2478,11 @@ static struct cc_alg_template aead_algs[] = {
.cipher_mode = DRV_CIPHER_CTR,
.flow_mode = S_DIN_to_AES,
.auth_mode = DRV_HASH_SHA256,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "authenc(xcbc(aes),rfc3686(ctr(aes)))",
- .driver_name = "authenc-xcbc-aes-rfc3686-ctr-aes-dx",
+ .driver_name = "authenc-xcbc-aes-rfc3686-ctr-aes-ccree",
.blocksize = 1,
.type = CRYPTO_ALG_TYPE_AEAD,
.template_aead = {
@@ -2490,10 +2498,11 @@ static struct cc_alg_template aead_algs[] = {
.cipher_mode = DRV_CIPHER_CTR,
.flow_mode = S_DIN_to_AES,
.auth_mode = DRV_HASH_XCBC_MAC,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "ccm(aes)",
- .driver_name = "ccm-aes-dx",
+ .driver_name = "ccm-aes-ccree",
.blocksize = 1,
.type = CRYPTO_ALG_TYPE_AEAD,
.template_aead = {
@@ -2509,10 +2518,11 @@ static struct cc_alg_template aead_algs[] = {
.cipher_mode = DRV_CIPHER_CCM,
.flow_mode = S_DIN_to_AES,
.auth_mode = DRV_HASH_NULL,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "rfc4309(ccm(aes))",
- .driver_name = "rfc4309-ccm-aes-dx",
+ .driver_name = "rfc4309-ccm-aes-ccree",
.blocksize = 1,
.type = CRYPTO_ALG_TYPE_AEAD,
.template_aead = {
@@ -2528,10 +2538,11 @@ static struct cc_alg_template aead_algs[] = {
.cipher_mode = DRV_CIPHER_CCM,
.flow_mode = S_DIN_to_AES,
.auth_mode = DRV_HASH_NULL,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "gcm(aes)",
- .driver_name = "gcm-aes-dx",
+ .driver_name = "gcm-aes-ccree",
.blocksize = 1,
.type = CRYPTO_ALG_TYPE_AEAD,
.template_aead = {
@@ -2547,10 +2558,11 @@ static struct cc_alg_template aead_algs[] = {
.cipher_mode = DRV_CIPHER_GCTR,
.flow_mode = S_DIN_to_AES,
.auth_mode = DRV_HASH_NULL,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "rfc4106(gcm(aes))",
- .driver_name = "rfc4106-gcm-aes-dx",
+ .driver_name = "rfc4106-gcm-aes-ccree",
.blocksize = 1,
.type = CRYPTO_ALG_TYPE_AEAD,
.template_aead = {
@@ -2566,10 +2578,11 @@ static struct cc_alg_template aead_algs[] = {
.cipher_mode = DRV_CIPHER_GCTR,
.flow_mode = S_DIN_to_AES,
.auth_mode = DRV_HASH_NULL,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "rfc4543(gcm(aes))",
- .driver_name = "rfc4543-gcm-aes-dx",
+ .driver_name = "rfc4543-gcm-aes-ccree",
.blocksize = 1,
.type = CRYPTO_ALG_TYPE_AEAD,
.template_aead = {
@@ -2585,6 +2598,7 @@ static struct cc_alg_template aead_algs[] = {
.cipher_mode = DRV_CIPHER_GCTR,
.flow_mode = S_DIN_to_AES,
.auth_mode = DRV_HASH_NULL,
+ .min_hw_rev = CC_HW_REV_630,
},
};
@@ -2670,6 +2684,9 @@ int cc_aead_alloc(struct cc_drvdata *drvdata)
/* Linux crypto */
for (alg = 0; alg < ARRAY_SIZE(aead_algs); alg++) {
+ if (aead_algs[alg].min_hw_rev > drvdata->hw_rev)
+ continue;
+
t_alg = cc_create_aead_alg(&aead_algs[alg], dev);
if (IS_ERR(t_alg)) {
rc = PTR_ERR(t_alg);
diff --git a/drivers/staging/ccree/cc_aead.h b/drivers/crypto/ccree/cc_aead.h
index 5edf3b351fa4..5edf3b351fa4 100644
--- a/drivers/staging/ccree/cc_aead.h
+++ b/drivers/crypto/ccree/cc_aead.h
diff --git a/drivers/staging/ccree/cc_buffer_mgr.c b/drivers/crypto/ccree/cc_buffer_mgr.c
index 14b2eabbf70a..b32577477b4c 100644
--- a/drivers/staging/ccree/cc_buffer_mgr.c
+++ b/drivers/crypto/ccree/cc_buffer_mgr.c
@@ -444,11 +444,11 @@ static int cc_set_hash_buf(struct device *dev, struct ahash_req_ctx *areq_ctx,
return 0;
}
-void cc_unmap_blkcipher_request(struct device *dev, void *ctx,
+void cc_unmap_cipher_request(struct device *dev, void *ctx,
unsigned int ivsize, struct scatterlist *src,
struct scatterlist *dst)
{
- struct blkcipher_req_ctx *req_ctx = (struct blkcipher_req_ctx *)ctx;
+ struct cipher_req_ctx *req_ctx = (struct cipher_req_ctx *)ctx;
if (req_ctx->gen_ctx.iv_dma_addr) {
dev_dbg(dev, "Unmapped iv: iv_dma_addr=%pad iv_size=%u\n",
@@ -475,12 +475,12 @@ void cc_unmap_blkcipher_request(struct device *dev, void *ctx,
}
}
-int cc_map_blkcipher_request(struct cc_drvdata *drvdata, void *ctx,
- unsigned int ivsize, unsigned int nbytes,
- void *info, struct scatterlist *src,
- struct scatterlist *dst, gfp_t flags)
+int cc_map_cipher_request(struct cc_drvdata *drvdata, void *ctx,
+ unsigned int ivsize, unsigned int nbytes,
+ void *info, struct scatterlist *src,
+ struct scatterlist *dst, gfp_t flags)
{
- struct blkcipher_req_ctx *req_ctx = (struct blkcipher_req_ctx *)ctx;
+ struct cipher_req_ctx *req_ctx = (struct cipher_req_ctx *)ctx;
struct mlli_params *mlli_params = &req_ctx->mlli_params;
struct buff_mgr_handle *buff_mgr = drvdata->buff_mgr_handle;
struct device *dev = drvdata_to_dev(drvdata);
@@ -517,7 +517,7 @@ int cc_map_blkcipher_request(struct cc_drvdata *drvdata, void *ctx,
LLI_MAX_NUM_OF_DATA_ENTRIES, &dummy, &mapped_nents);
if (rc) {
rc = -ENOMEM;
- goto ablkcipher_exit;
+ goto cipher_exit;
}
if (mapped_nents > 1)
req_ctx->dma_buf_type = CC_DMA_BUF_MLLI;
@@ -536,7 +536,7 @@ int cc_map_blkcipher_request(struct cc_drvdata *drvdata, void *ctx,
&req_ctx->out_nents, LLI_MAX_NUM_OF_DATA_ENTRIES,
&dummy, &mapped_nents)) {
rc = -ENOMEM;
- goto ablkcipher_exit;
+ goto cipher_exit;
}
if (mapped_nents > 1)
req_ctx->dma_buf_type = CC_DMA_BUF_MLLI;
@@ -555,7 +555,7 @@ int cc_map_blkcipher_request(struct cc_drvdata *drvdata, void *ctx,
mlli_params->curr_pool = buff_mgr->mlli_buffs_pool;
rc = cc_generate_mlli(dev, &sg_data, mlli_params, flags);
if (rc)
- goto ablkcipher_exit;
+ goto cipher_exit;
}
dev_dbg(dev, "areq_ctx->dma_buf_type = %s\n",
@@ -563,8 +563,8 @@ int cc_map_blkcipher_request(struct cc_drvdata *drvdata, void *ctx,
return 0;
-ablkcipher_exit:
- cc_unmap_blkcipher_request(dev, req_ctx, ivsize, src, dst);
+cipher_exit:
+ cc_unmap_cipher_request(dev, req_ctx, ivsize, src, dst);
return rc;
}
@@ -1018,7 +1018,7 @@ static int cc_aead_chain_data(struct cc_drvdata *drvdata,
struct device *dev = drvdata_to_dev(drvdata);
enum drv_crypto_direction direct = areq_ctx->gen_ctx.op_type;
unsigned int authsize = areq_ctx->req_authsize;
- int src_last_bytes = 0, dst_last_bytes = 0;
+ unsigned int src_last_bytes = 0, dst_last_bytes = 0;
int rc = 0;
u32 src_mapped_nents = 0, dst_mapped_nents = 0;
u32 offset = 0;
@@ -1064,7 +1064,7 @@ static int cc_aead_chain_data(struct cc_drvdata *drvdata,
if (src_mapped_nents > LLI_MAX_NUM_OF_DATA_ENTRIES) {
dev_err(dev, "Too many fragments. current %d max %d\n",
src_mapped_nents, LLI_MAX_NUM_OF_DATA_ENTRIES);
- return -ENOMEM;
+ return -ENOMEM;
}
areq_ctx->src.nents = src_mapped_nents;
diff --git a/drivers/staging/ccree/cc_buffer_mgr.h b/drivers/crypto/ccree/cc_buffer_mgr.h
index 99b752aa1077..3ec4b4db5247 100644
--- a/drivers/staging/ccree/cc_buffer_mgr.h
+++ b/drivers/crypto/ccree/cc_buffer_mgr.h
@@ -40,15 +40,13 @@ int cc_buffer_mgr_init(struct cc_drvdata *drvdata);
int cc_buffer_mgr_fini(struct cc_drvdata *drvdata);
-int cc_map_blkcipher_request(struct cc_drvdata *drvdata, void *ctx,
- unsigned int ivsize, unsigned int nbytes,
- void *info, struct scatterlist *src,
- struct scatterlist *dst, gfp_t flags);
+int cc_map_cipher_request(struct cc_drvdata *drvdata, void *ctx,
+ unsigned int ivsize, unsigned int nbytes,
+ void *info, struct scatterlist *src,
+ struct scatterlist *dst, gfp_t flags);
-void cc_unmap_blkcipher_request(struct device *dev, void *ctx,
- unsigned int ivsize,
- struct scatterlist *src,
- struct scatterlist *dst);
+void cc_unmap_cipher_request(struct device *dev, void *ctx, unsigned int ivsize,
+ struct scatterlist *src, struct scatterlist *dst);
int cc_map_aead_request(struct cc_drvdata *drvdata, struct aead_request *req);
@@ -71,4 +69,3 @@ void cc_copy_sg_portion(struct device *dev, u8 *dest, struct scatterlist *sg,
void cc_zero_sgl(struct scatterlist *sgl, u32 data_len);
#endif /*__BUFFER_MGR_H__*/
-
diff --git a/drivers/staging/ccree/cc_cipher.c b/drivers/crypto/ccree/cc_cipher.c
index d4ac0ff2ffcf..df98f7afe645 100644
--- a/drivers/staging/ccree/cc_cipher.c
+++ b/drivers/crypto/ccree/cc_cipher.c
@@ -17,12 +17,12 @@
#define MAX_ABLKCIPHER_SEQ_LEN 6
-#define template_ablkcipher template_u.ablkcipher
+#define template_skcipher template_u.skcipher
#define CC_MIN_AES_XTS_SIZE 0x10
#define CC_MAX_AES_XTS_SIZE 0x2000
struct cc_cipher_handle {
- struct list_head blkcipher_alg_list;
+ struct list_head alg_list;
};
struct cc_user_key_info {
@@ -42,7 +42,6 @@ struct cc_cipher_ctx {
int cipher_mode;
int flow_mode;
unsigned int flags;
- struct blkcipher_req_ctx *sync_ctx;
struct cc_user_key_info user;
struct cc_hw_key_info hw;
struct crypto_shash *shash_tfm;
@@ -124,37 +123,21 @@ static int validate_data_size(struct cc_cipher_ctx *ctx_p,
return -EINVAL;
}
-static unsigned int get_max_keysize(struct crypto_tfm *tfm)
-{
- struct cc_crypto_alg *cc_alg =
- container_of(tfm->__crt_alg, struct cc_crypto_alg, crypto_alg);
-
- if ((cc_alg->crypto_alg.cra_flags & CRYPTO_ALG_TYPE_MASK) ==
- CRYPTO_ALG_TYPE_ABLKCIPHER)
- return cc_alg->crypto_alg.cra_ablkcipher.max_keysize;
-
- if ((cc_alg->crypto_alg.cra_flags & CRYPTO_ALG_TYPE_MASK) ==
- CRYPTO_ALG_TYPE_BLKCIPHER)
- return cc_alg->crypto_alg.cra_blkcipher.max_keysize;
-
- return 0;
-}
-
static int cc_cipher_init(struct crypto_tfm *tfm)
{
struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
- struct crypto_alg *alg = tfm->__crt_alg;
struct cc_crypto_alg *cc_alg =
- container_of(alg, struct cc_crypto_alg, crypto_alg);
+ container_of(tfm->__crt_alg, struct cc_crypto_alg,
+ skcipher_alg.base);
struct device *dev = drvdata_to_dev(cc_alg->drvdata);
+ unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize;
int rc = 0;
- unsigned int max_key_buf_size = get_max_keysize(tfm);
- struct ablkcipher_tfm *ablktfm = &tfm->crt_ablkcipher;
dev_dbg(dev, "Initializing context @%p for %s\n", ctx_p,
crypto_tfm_alg_name(tfm));
- ablktfm->reqsize = sizeof(struct blkcipher_req_ctx);
+ crypto_skcipher_set_reqsize(__crypto_skcipher_cast(tfm),
+ sizeof(struct cipher_req_ctx));
ctx_p->cipher_mode = cc_alg->cipher_mode;
ctx_p->flow_mode = cc_alg->flow_mode;
@@ -194,9 +177,13 @@ static int cc_cipher_init(struct crypto_tfm *tfm)
static void cc_cipher_exit(struct crypto_tfm *tfm)
{
+ struct crypto_alg *alg = tfm->__crt_alg;
+ struct cc_crypto_alg *cc_alg =
+ container_of(alg, struct cc_crypto_alg,
+ skcipher_alg.base);
+ unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize;
struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
struct device *dev = drvdata_to_dev(ctx_p->drvdata);
- unsigned int max_key_buf_size = get_max_keysize(tfm);
dev_dbg(dev, "Clearing context @%p for %s\n",
crypto_tfm_ctx(tfm), crypto_tfm_alg_name(tfm));
@@ -214,7 +201,7 @@ static void cc_cipher_exit(struct crypto_tfm *tfm)
&ctx_p->user.key_dma_addr);
/* Free key buffer in context */
- kfree(ctx_p->user.key);
+ kzfree(ctx_p->user.key);
dev_dbg(dev, "Free key buffer in context. key=@%p\n", ctx_p->user.key);
}
@@ -224,27 +211,6 @@ struct tdes_keys {
u8 key3[DES_KEY_SIZE];
};
-static const u8 zero_buff[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
-
-/* The function verifies that tdes keys are not weak.*/
-static int cc_verify_3des_keys(const u8 *key, unsigned int keylen)
-{
- struct tdes_keys *tdes_key = (struct tdes_keys *)key;
-
- /* verify key1 != key2 and key3 != key2*/
- if ((memcmp((u8 *)tdes_key->key1, (u8 *)tdes_key->key2,
- sizeof(tdes_key->key1)) == 0) ||
- (memcmp((u8 *)tdes_key->key3, (u8 *)tdes_key->key2,
- sizeof(tdes_key->key3)) == 0)) {
- return -ENOEXEC;
- }
-
- return 0;
-}
-
static enum cc_hw_crypto_key hw_key_to_cc_hw_key(int slot_num)
{
switch (slot_num) {
@@ -260,14 +226,17 @@ static enum cc_hw_crypto_key hw_key_to_cc_hw_key(int slot_num)
return END_OF_KEYS;
}
-static int cc_cipher_setkey(struct crypto_ablkcipher *atfm, const u8 *key,
+static int cc_cipher_setkey(struct crypto_skcipher *sktfm, const u8 *key,
unsigned int keylen)
{
- struct crypto_tfm *tfm = crypto_ablkcipher_tfm(atfm);
+ struct crypto_tfm *tfm = crypto_skcipher_tfm(sktfm);
struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
struct device *dev = drvdata_to_dev(ctx_p->drvdata);
- u32 tmp[DES_EXPKEY_WORDS];
- unsigned int max_key_buf_size = get_max_keysize(tfm);
+ u32 tmp[DES3_EDE_EXPKEY_WORDS];
+ struct cc_crypto_alg *cc_alg =
+ container_of(tfm->__crt_alg, struct cc_crypto_alg,
+ skcipher_alg.base);
+ unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize;
dev_dbg(dev, "Setting key in context @%p for %s. keylen=%u\n",
ctx_p, crypto_tfm_alg_name(tfm), keylen);
@@ -320,26 +289,30 @@ static int cc_cipher_setkey(struct crypto_ablkcipher *atfm, const u8 *key,
return 0;
}
- // verify weak keys
+ /*
+ * Verify DES weak keys
+ * Note that we're dropping the expanded key since the
+ * HW does the expansion on its own.
+ */
if (ctx_p->flow_mode == S_DIN_to_DES) {
- if (!des_ekey(tmp, key) &&
+ if (keylen == DES3_EDE_KEY_SIZE &&
+ __des3_ede_setkey(tmp, &tfm->crt_flags, key,
+ DES3_EDE_KEY_SIZE)) {
+ dev_dbg(dev, "weak 3DES key");
+ return -EINVAL;
+ } else if (!des_ekey(tmp, key) &&
(crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_WEAK_KEY)) {
tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY;
dev_dbg(dev, "weak DES key");
return -EINVAL;
}
}
+
if (ctx_p->cipher_mode == DRV_CIPHER_XTS &&
xts_check_key(tfm, key, keylen)) {
dev_dbg(dev, "weak XTS key");
return -EINVAL;
}
- if (ctx_p->flow_mode == S_DIN_to_DES &&
- keylen == DES3_EDE_KEY_SIZE &&
- cc_verify_3des_keys(key, keylen)) {
- dev_dbg(dev, "weak 3DES key");
- return -EINVAL;
- }
/* STAT_PHASE_1: Copy key to ctx */
dma_sync_single_for_cpu(dev, ctx_p->user.key_dma_addr,
@@ -369,12 +342,12 @@ static int cc_cipher_setkey(struct crypto_ablkcipher *atfm, const u8 *key,
max_key_buf_size, DMA_TO_DEVICE);
ctx_p->keylen = keylen;
- dev_dbg(dev, "return safely");
+ dev_dbg(dev, "return safely");
return 0;
}
static void cc_setup_cipher_desc(struct crypto_tfm *tfm,
- struct blkcipher_req_ctx *req_ctx,
+ struct cipher_req_ctx *req_ctx,
unsigned int ivsize, unsigned int nbytes,
struct cc_hw_desc desc[],
unsigned int *seq_size)
@@ -390,14 +363,11 @@ static void cc_setup_cipher_desc(struct crypto_tfm *tfm,
unsigned int du_size = nbytes;
struct cc_crypto_alg *cc_alg =
- container_of(tfm->__crt_alg, struct cc_crypto_alg, crypto_alg);
+ container_of(tfm->__crt_alg, struct cc_crypto_alg,
+ skcipher_alg.base);
- if ((cc_alg->crypto_alg.cra_flags & CRYPTO_ALG_BULK_MASK) ==
- CRYPTO_ALG_BULK_DU_512)
- du_size = 512;
- if ((cc_alg->crypto_alg.cra_flags & CRYPTO_ALG_BULK_MASK) ==
- CRYPTO_ALG_BULK_DU_4096)
- du_size = 4096;
+ if (cc_alg->data_unit)
+ du_size = cc_alg->data_unit;
switch (cipher_mode) {
case DRV_CIPHER_CBC:
@@ -499,7 +469,7 @@ static void cc_setup_cipher_desc(struct crypto_tfm *tfm,
}
static void cc_setup_cipher_data(struct crypto_tfm *tfm,
- struct blkcipher_req_ctx *req_ctx,
+ struct cipher_req_ctx *req_ctx,
struct scatterlist *dst,
struct scatterlist *src, unsigned int nbytes,
void *areq, struct cc_hw_desc desc[],
@@ -532,7 +502,7 @@ static void cc_setup_cipher_data(struct crypto_tfm *tfm,
set_dout_dlli(&desc[*seq_size], sg_dma_address(dst),
nbytes, NS_BIT, (!areq ? 0 : 1));
if (areq)
- set_queue_last_ind(&desc[*seq_size]);
+ set_queue_last_ind(ctx_p->drvdata, &desc[*seq_size]);
set_flow_mode(&desc[*seq_size], flow_mode);
(*seq_size)++;
@@ -577,7 +547,7 @@ static void cc_setup_cipher_data(struct crypto_tfm *tfm,
(!areq ? 0 : 1));
}
if (areq)
- set_queue_last_ind(&desc[*seq_size]);
+ set_queue_last_ind(ctx_p->drvdata, &desc[*seq_size]);
set_flow_mode(&desc[*seq_size], flow_mode);
(*seq_size)++;
@@ -586,56 +556,57 @@ static void cc_setup_cipher_data(struct crypto_tfm *tfm,
static void cc_cipher_complete(struct device *dev, void *cc_req, int err)
{
- struct ablkcipher_request *areq = (struct ablkcipher_request *)cc_req;
- struct scatterlist *dst = areq->dst;
- struct scatterlist *src = areq->src;
- struct blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(areq);
- struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq);
- unsigned int ivsize = crypto_ablkcipher_ivsize(tfm);
- struct ablkcipher_request *req = (struct ablkcipher_request *)areq;
+ struct skcipher_request *req = (struct skcipher_request *)cc_req;
+ struct scatterlist *dst = req->dst;
+ struct scatterlist *src = req->src;
+ struct cipher_req_ctx *req_ctx = skcipher_request_ctx(req);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ unsigned int ivsize = crypto_skcipher_ivsize(tfm);
- cc_unmap_blkcipher_request(dev, req_ctx, ivsize, src, dst);
- kfree(req_ctx->iv);
+ cc_unmap_cipher_request(dev, req_ctx, ivsize, src, dst);
+ kzfree(req_ctx->iv);
/*
- * The crypto API expects us to set the req->info to the last
+ * The crypto API expects us to set the req->iv to the last
* ciphertext block. For encrypt, simply copy from the result.
* For decrypt, we must copy from a saved buffer since this
* could be an in-place decryption operation and the src is
* lost by this point.
*/
if (req_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) {
- memcpy(req->info, req_ctx->backup_info, ivsize);
- kfree(req_ctx->backup_info);
+ memcpy(req->iv, req_ctx->backup_info, ivsize);
+ kzfree(req_ctx->backup_info);
} else if (!err) {
- scatterwalk_map_and_copy(req->info, req->dst,
- (req->nbytes - ivsize), ivsize, 0);
+ scatterwalk_map_and_copy(req->iv, req->dst,
+ (req->cryptlen - ivsize),
+ ivsize, 0);
}
- ablkcipher_request_complete(areq, err);
+ skcipher_request_complete(req, err);
}
-static int cc_cipher_process(struct ablkcipher_request *req,
+static int cc_cipher_process(struct skcipher_request *req,
enum drv_crypto_direction direction)
{
- struct crypto_ablkcipher *ablk_tfm = crypto_ablkcipher_reqtfm(req);
- struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablk_tfm);
- struct blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(req);
- unsigned int ivsize = crypto_ablkcipher_ivsize(ablk_tfm);
+ struct crypto_skcipher *sk_tfm = crypto_skcipher_reqtfm(req);
+ struct crypto_tfm *tfm = crypto_skcipher_tfm(sk_tfm);
+ struct cipher_req_ctx *req_ctx = skcipher_request_ctx(req);
+ unsigned int ivsize = crypto_skcipher_ivsize(sk_tfm);
struct scatterlist *dst = req->dst;
struct scatterlist *src = req->src;
- unsigned int nbytes = req->nbytes;
- void *info = req->info;
+ unsigned int nbytes = req->cryptlen;
+ void *iv = req->iv;
struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
struct device *dev = drvdata_to_dev(ctx_p->drvdata);
struct cc_hw_desc desc[MAX_ABLKCIPHER_SEQ_LEN];
struct cc_crypto_req cc_req = {};
- int rc, seq_len = 0, cts_restore_flag = 0;
+ int rc, cts_restore_flag = 0;
+ unsigned int seq_len = 0;
gfp_t flags = cc_gfp_flags(&req->base);
- dev_dbg(dev, "%s req=%p info=%p nbytes=%d\n",
+ dev_dbg(dev, "%s req=%p iv=%p nbytes=%d\n",
((direction == DRV_CRYPTO_DIRECTION_ENCRYPT) ?
- "Encrypt" : "Decrypt"), req, info, nbytes);
+ "Encrypt" : "Decrypt"), req, iv, nbytes);
/* STAT_PHASE_0: Init and sanity checks */
@@ -655,12 +626,11 @@ static int cc_cipher_process(struct ablkcipher_request *req,
/* The IV we are handed may be allocted from the stack so
* we must copy it to a DMAable buffer before use.
*/
- req_ctx->iv = kmalloc(ivsize, flags);
+ req_ctx->iv = kmemdup(iv, ivsize, flags);
if (!req_ctx->iv) {
rc = -ENOMEM;
goto exit_process;
}
- memcpy(req_ctx->iv, info, ivsize);
/*For CTS in case of data size aligned to 16 use CBC mode*/
if (((nbytes % AES_BLOCK_SIZE) == 0) &&
@@ -669,7 +639,7 @@ static int cc_cipher_process(struct ablkcipher_request *req,
cts_restore_flag = 1;
}
- /* Setup DX request structure */
+ /* Setup request structure */
cc_req.user_cb = (void *)cc_cipher_complete;
cc_req.user_arg = (void *)req;
@@ -684,7 +654,7 @@ static int cc_cipher_process(struct ablkcipher_request *req,
/* STAT_PHASE_1: Map buffers */
- rc = cc_map_blkcipher_request(ctx_p->drvdata, req_ctx, ivsize, nbytes,
+ rc = cc_map_cipher_request(ctx_p->drvdata, req_ctx, ivsize, nbytes,
req_ctx->iv, src, dst, flags);
if (rc) {
dev_err(dev, "map_request() failed\n");
@@ -715,7 +685,7 @@ static int cc_cipher_process(struct ablkcipher_request *req,
/* Failed to send the request or request completed
* synchronously
*/
- cc_unmap_blkcipher_request(dev, req_ctx, ivsize, src, dst);
+ cc_unmap_cipher_request(dev, req_ctx, ivsize, src, dst);
}
exit_process:
@@ -723,16 +693,16 @@ exit_process:
ctx_p->cipher_mode = DRV_CIPHER_CBC_CTS;
if (rc != -EINPROGRESS && rc != -EBUSY) {
- kfree(req_ctx->backup_info);
- kfree(req_ctx->iv);
+ kzfree(req_ctx->backup_info);
+ kzfree(req_ctx->iv);
}
return rc;
}
-static int cc_cipher_encrypt(struct ablkcipher_request *req)
+static int cc_cipher_encrypt(struct skcipher_request *req)
{
- struct blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(req);
+ struct cipher_req_ctx *req_ctx = skcipher_request_ctx(req);
req_ctx->is_giv = false;
req_ctx->backup_info = NULL;
@@ -740,11 +710,11 @@ static int cc_cipher_encrypt(struct ablkcipher_request *req)
return cc_cipher_process(req, DRV_CRYPTO_DIRECTION_ENCRYPT);
}
-static int cc_cipher_decrypt(struct ablkcipher_request *req)
+static int cc_cipher_decrypt(struct skcipher_request *req)
{
- struct crypto_ablkcipher *ablk_tfm = crypto_ablkcipher_reqtfm(req);
- struct blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(req);
- unsigned int ivsize = crypto_ablkcipher_ivsize(ablk_tfm);
+ struct crypto_skcipher *sk_tfm = crypto_skcipher_reqtfm(req);
+ struct cipher_req_ctx *req_ctx = skcipher_request_ctx(req);
+ unsigned int ivsize = crypto_skcipher_ivsize(sk_tfm);
gfp_t flags = cc_gfp_flags(&req->base);
/*
@@ -756,37 +726,35 @@ static int cc_cipher_decrypt(struct ablkcipher_request *req)
return -ENOMEM;
scatterwalk_map_and_copy(req_ctx->backup_info, req->src,
- (req->nbytes - ivsize), ivsize, 0);
+ (req->cryptlen - ivsize), ivsize, 0);
req_ctx->is_giv = false;
return cc_cipher_process(req, DRV_CRYPTO_DIRECTION_DECRYPT);
}
-/* DX Block cipher alg */
-static struct cc_alg_template blkcipher_algs[] = {
+/* Block cipher alg */
+static const struct cc_alg_template skcipher_algs[] = {
{
.name = "xts(aes)",
- .driver_name = "xts-aes-dx",
+ .driver_name = "xts-aes-ccree",
.blocksize = AES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
.min_keysize = AES_MIN_KEY_SIZE * 2,
.max_keysize = AES_MAX_KEY_SIZE * 2,
.ivsize = AES_BLOCK_SIZE,
- .geniv = "eseqiv",
},
.cipher_mode = DRV_CIPHER_XTS,
.flow_mode = S_DIN_to_AES,
+ .min_hw_rev = CC_HW_REV_630,
},
{
- .name = "xts(aes)",
- .driver_name = "xts-aes-du512-dx",
+ .name = "xts512(aes)",
+ .driver_name = "xts-aes-du512-ccree",
.blocksize = AES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_512,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -796,13 +764,14 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_XTS,
.flow_mode = S_DIN_to_AES,
+ .data_unit = 512,
+ .min_hw_rev = CC_HW_REV_712,
},
{
- .name = "xts(aes)",
- .driver_name = "xts-aes-du4096-dx",
+ .name = "xts4096(aes)",
+ .driver_name = "xts-aes-du4096-ccree",
.blocksize = AES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_4096,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -812,13 +781,14 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_XTS,
.flow_mode = S_DIN_to_AES,
+ .data_unit = 4096,
+ .min_hw_rev = CC_HW_REV_712,
},
{
.name = "essiv(aes)",
- .driver_name = "essiv-aes-dx",
+ .driver_name = "essiv-aes-ccree",
.blocksize = AES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -828,13 +798,13 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_ESSIV,
.flow_mode = S_DIN_to_AES,
+ .min_hw_rev = CC_HW_REV_712,
},
{
- .name = "essiv(aes)",
- .driver_name = "essiv-aes-du512-dx",
+ .name = "essiv512(aes)",
+ .driver_name = "essiv-aes-du512-ccree",
.blocksize = AES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_512,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -844,13 +814,14 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_ESSIV,
.flow_mode = S_DIN_to_AES,
+ .data_unit = 512,
+ .min_hw_rev = CC_HW_REV_712,
},
{
- .name = "essiv(aes)",
- .driver_name = "essiv-aes-du4096-dx",
+ .name = "essiv4096(aes)",
+ .driver_name = "essiv-aes-du4096-ccree",
.blocksize = AES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_4096,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -860,13 +831,14 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_ESSIV,
.flow_mode = S_DIN_to_AES,
+ .data_unit = 4096,
+ .min_hw_rev = CC_HW_REV_712,
},
{
.name = "bitlocker(aes)",
- .driver_name = "bitlocker-aes-dx",
+ .driver_name = "bitlocker-aes-ccree",
.blocksize = AES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -876,13 +848,13 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_BITLOCKER,
.flow_mode = S_DIN_to_AES,
+ .min_hw_rev = CC_HW_REV_712,
},
{
- .name = "bitlocker(aes)",
- .driver_name = "bitlocker-aes-du512-dx",
+ .name = "bitlocker512(aes)",
+ .driver_name = "bitlocker-aes-du512-ccree",
.blocksize = AES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_512,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -892,13 +864,14 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_BITLOCKER,
.flow_mode = S_DIN_to_AES,
+ .data_unit = 512,
+ .min_hw_rev = CC_HW_REV_712,
},
{
- .name = "bitlocker(aes)",
- .driver_name = "bitlocker-aes-du4096-dx",
+ .name = "bitlocker4096(aes)",
+ .driver_name = "bitlocker-aes-du4096-ccree",
.blocksize = AES_BLOCK_SIZE,
- .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_4096,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -908,13 +881,15 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_BITLOCKER,
.flow_mode = S_DIN_to_AES,
+ .data_unit = 4096,
+ .min_hw_rev = CC_HW_REV_712,
},
{
.name = "ecb(aes)",
- .driver_name = "ecb-aes-dx",
+ .driver_name = "ecb-aes-ccree",
.blocksize = AES_BLOCK_SIZE,
.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -924,13 +899,14 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_ECB,
.flow_mode = S_DIN_to_AES,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "cbc(aes)",
- .driver_name = "cbc-aes-dx",
+ .driver_name = "cbc-aes-ccree",
.blocksize = AES_BLOCK_SIZE,
.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -940,13 +916,14 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_CBC,
.flow_mode = S_DIN_to_AES,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "ofb(aes)",
- .driver_name = "ofb-aes-dx",
+ .driver_name = "ofb-aes-ccree",
.blocksize = AES_BLOCK_SIZE,
.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -956,13 +933,14 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_OFB,
.flow_mode = S_DIN_to_AES,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "cts1(cbc(aes))",
- .driver_name = "cts1-cbc-aes-dx",
+ .driver_name = "cts1-cbc-aes-ccree",
.blocksize = AES_BLOCK_SIZE,
.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -972,13 +950,14 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_CBC_CTS,
.flow_mode = S_DIN_to_AES,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "ctr(aes)",
- .driver_name = "ctr-aes-dx",
+ .driver_name = "ctr-aes-ccree",
.blocksize = 1,
.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -988,13 +967,14 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_CTR,
.flow_mode = S_DIN_to_AES,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "cbc(des3_ede)",
- .driver_name = "cbc-3des-dx",
+ .driver_name = "cbc-3des-ccree",
.blocksize = DES3_EDE_BLOCK_SIZE,
.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -1004,13 +984,14 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_CBC,
.flow_mode = S_DIN_to_DES,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "ecb(des3_ede)",
- .driver_name = "ecb-3des-dx",
+ .driver_name = "ecb-3des-ccree",
.blocksize = DES3_EDE_BLOCK_SIZE,
.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -1020,13 +1001,14 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_ECB,
.flow_mode = S_DIN_to_DES,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "cbc(des)",
- .driver_name = "cbc-des-dx",
+ .driver_name = "cbc-des-ccree",
.blocksize = DES_BLOCK_SIZE,
.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -1036,13 +1018,14 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_CBC,
.flow_mode = S_DIN_to_DES,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "ecb(des)",
- .driver_name = "ecb-des-dx",
+ .driver_name = "ecb-des-ccree",
.blocksize = DES_BLOCK_SIZE,
.type = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .template_ablkcipher = {
+ .template_skcipher = {
.setkey = cc_cipher_setkey,
.encrypt = cc_cipher_encrypt,
.decrypt = cc_cipher_decrypt,
@@ -1052,40 +1035,41 @@ static struct cc_alg_template blkcipher_algs[] = {
},
.cipher_mode = DRV_CIPHER_ECB,
.flow_mode = S_DIN_to_DES,
+ .min_hw_rev = CC_HW_REV_630,
},
};
-static
-struct cc_crypto_alg *cc_cipher_create_alg(struct cc_alg_template *template,
+static struct cc_crypto_alg *cc_create_alg(const struct cc_alg_template *tmpl,
struct device *dev)
{
struct cc_crypto_alg *t_alg;
- struct crypto_alg *alg;
+ struct skcipher_alg *alg;
t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL);
if (!t_alg)
return ERR_PTR(-ENOMEM);
- alg = &t_alg->crypto_alg;
+ alg = &t_alg->skcipher_alg;
- snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name);
- snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
- template->driver_name);
- alg->cra_module = THIS_MODULE;
- alg->cra_priority = CC_CRA_PRIO;
- alg->cra_blocksize = template->blocksize;
- alg->cra_alignmask = 0;
- alg->cra_ctxsize = sizeof(struct cc_cipher_ctx);
+ memcpy(alg, &tmpl->template_skcipher, sizeof(*alg));
- alg->cra_init = cc_cipher_init;
- alg->cra_exit = cc_cipher_exit;
- alg->cra_type = &crypto_ablkcipher_type;
- alg->cra_ablkcipher = template->template_ablkcipher;
- alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY |
- template->type;
+ snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name);
+ snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+ tmpl->driver_name);
+ alg->base.cra_module = THIS_MODULE;
+ alg->base.cra_priority = CC_CRA_PRIO;
+ alg->base.cra_blocksize = tmpl->blocksize;
+ alg->base.cra_alignmask = 0;
+ alg->base.cra_ctxsize = sizeof(struct cc_cipher_ctx);
- t_alg->cipher_mode = template->cipher_mode;
- t_alg->flow_mode = template->flow_mode;
+ alg->base.cra_init = cc_cipher_init;
+ alg->base.cra_exit = cc_cipher_exit;
+ alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY |
+ CRYPTO_ALG_TYPE_SKCIPHER;
+
+ t_alg->cipher_mode = tmpl->cipher_mode;
+ t_alg->flow_mode = tmpl->flow_mode;
+ t_alg->data_unit = tmpl->data_unit;
return t_alg;
}
@@ -1093,67 +1077,69 @@ struct cc_crypto_alg *cc_cipher_create_alg(struct cc_alg_template *template,
int cc_cipher_free(struct cc_drvdata *drvdata)
{
struct cc_crypto_alg *t_alg, *n;
- struct cc_cipher_handle *blkcipher_handle = drvdata->blkcipher_handle;
+ struct cc_cipher_handle *cipher_handle = drvdata->cipher_handle;
- if (blkcipher_handle) {
+ if (cipher_handle) {
/* Remove registered algs */
- list_for_each_entry_safe(t_alg, n,
- &blkcipher_handle->blkcipher_alg_list,
+ list_for_each_entry_safe(t_alg, n, &cipher_handle->alg_list,
entry) {
- crypto_unregister_alg(&t_alg->crypto_alg);
+ crypto_unregister_skcipher(&t_alg->skcipher_alg);
list_del(&t_alg->entry);
kfree(t_alg);
}
- kfree(blkcipher_handle);
- drvdata->blkcipher_handle = NULL;
+ kfree(cipher_handle);
+ drvdata->cipher_handle = NULL;
}
return 0;
}
int cc_cipher_alloc(struct cc_drvdata *drvdata)
{
- struct cc_cipher_handle *ablkcipher_handle;
+ struct cc_cipher_handle *cipher_handle;
struct cc_crypto_alg *t_alg;
struct device *dev = drvdata_to_dev(drvdata);
int rc = -ENOMEM;
int alg;
- ablkcipher_handle = kmalloc(sizeof(*ablkcipher_handle), GFP_KERNEL);
- if (!ablkcipher_handle)
+ cipher_handle = kmalloc(sizeof(*cipher_handle), GFP_KERNEL);
+ if (!cipher_handle)
return -ENOMEM;
- INIT_LIST_HEAD(&ablkcipher_handle->blkcipher_alg_list);
- drvdata->blkcipher_handle = ablkcipher_handle;
+ INIT_LIST_HEAD(&cipher_handle->alg_list);
+ drvdata->cipher_handle = cipher_handle;
/* Linux crypto */
dev_dbg(dev, "Number of algorithms = %zu\n",
- ARRAY_SIZE(blkcipher_algs));
- for (alg = 0; alg < ARRAY_SIZE(blkcipher_algs); alg++) {
- dev_dbg(dev, "creating %s\n", blkcipher_algs[alg].driver_name);
- t_alg = cc_cipher_create_alg(&blkcipher_algs[alg], dev);
+ ARRAY_SIZE(skcipher_algs));
+ for (alg = 0; alg < ARRAY_SIZE(skcipher_algs); alg++) {
+ if (skcipher_algs[alg].min_hw_rev > drvdata->hw_rev)
+ continue;
+
+ dev_dbg(dev, "creating %s\n", skcipher_algs[alg].driver_name);
+ t_alg = cc_create_alg(&skcipher_algs[alg], dev);
if (IS_ERR(t_alg)) {
rc = PTR_ERR(t_alg);
dev_err(dev, "%s alg allocation failed\n",
- blkcipher_algs[alg].driver_name);
+ skcipher_algs[alg].driver_name);
goto fail0;
}
t_alg->drvdata = drvdata;
dev_dbg(dev, "registering %s\n",
- blkcipher_algs[alg].driver_name);
- rc = crypto_register_alg(&t_alg->crypto_alg);
+ skcipher_algs[alg].driver_name);
+ rc = crypto_register_skcipher(&t_alg->skcipher_alg);
dev_dbg(dev, "%s alg registration rc = %x\n",
- t_alg->crypto_alg.cra_driver_name, rc);
+ t_alg->skcipher_alg.base.cra_driver_name, rc);
if (rc) {
dev_err(dev, "%s alg registration failed\n",
- t_alg->crypto_alg.cra_driver_name);
+ t_alg->skcipher_alg.base.cra_driver_name);
kfree(t_alg);
goto fail0;
} else {
list_add_tail(&t_alg->entry,
- &ablkcipher_handle->blkcipher_alg_list);
+ &cipher_handle->alg_list);
dev_dbg(dev, "Registered %s\n",
- t_alg->crypto_alg.cra_driver_name);
+ t_alg->skcipher_alg.base.cra_driver_name);
}
}
return 0;
diff --git a/drivers/staging/ccree/cc_cipher.h b/drivers/crypto/ccree/cc_cipher.h
index 4c181c721723..2a2a6f46c515 100644
--- a/drivers/staging/ccree/cc_cipher.h
+++ b/drivers/crypto/ccree/cc_cipher.h
@@ -25,7 +25,7 @@
CC_CRYPTO_CIPHER_KEY_KFDE2 | \
CC_CRYPTO_CIPHER_KEY_KFDE3)
-struct blkcipher_req_ctx {
+struct cipher_req_ctx {
struct async_gen_req_ctx gen_ctx;
enum cc_req_dma_buf_type dma_buf_type;
u32 in_nents;
@@ -42,33 +42,18 @@ int cc_cipher_alloc(struct cc_drvdata *drvdata);
int cc_cipher_free(struct cc_drvdata *drvdata);
-#ifndef CRYPTO_ALG_BULK_MASK
-
-#define CRYPTO_ALG_BULK_DU_512 0x00002000
-#define CRYPTO_ALG_BULK_DU_4096 0x00004000
-#define CRYPTO_ALG_BULK_MASK (CRYPTO_ALG_BULK_DU_512 |\
- CRYPTO_ALG_BULK_DU_4096)
-#endif /* CRYPTO_ALG_BULK_MASK */
-
-#ifdef CRYPTO_TFM_REQ_HW_KEY
-
-static inline bool cc_is_hw_key(struct crypto_tfm *tfm)
-{
- return (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_HW_KEY);
-}
-
-#else
-
struct arm_hw_key_info {
int hw_key1;
int hw_key2;
};
+/*
+ * This is a stub function that will replaced when we
+ * implement secure keys
+ */
static inline bool cc_is_hw_key(struct crypto_tfm *tfm)
{
return false;
}
-#endif /* CRYPTO_TFM_REQ_HW_KEY */
-
#endif /*__CC_CIPHER_H__*/
diff --git a/drivers/staging/ccree/cc_crypto_ctx.h b/drivers/crypto/ccree/cc_crypto_ctx.h
index eb16842d7db9..e032544f4e31 100644
--- a/drivers/staging/ccree/cc_crypto_ctx.h
+++ b/drivers/crypto/ccree/cc_crypto_ctx.h
@@ -6,17 +6,6 @@
#include <linux/types.h>
-/* context size */
-#ifndef CC_CTX_SIZE_LOG2
-#if (CC_DEV_SHA_MAX > 256)
-#define CC_CTX_SIZE_LOG2 8
-#else
-#define CC_CTX_SIZE_LOG2 7
-#endif
-#endif
-#define CC_CTX_SIZE BIT(CC_CTX_SIZE_LOG2)
-#define CC_DRV_CTX_SIZE_WORDS (CC_CTX_SIZE >> 2)
-
#define CC_DRV_DES_IV_SIZE 8
#define CC_DRV_DES_BLOCK_SIZE 8
@@ -59,13 +48,8 @@
#define CC_SHA384_BLOCK_SIZE 128
#define CC_SHA512_BLOCK_SIZE 128
-#if (CC_DEV_SHA_MAX > 256)
#define CC_DIGEST_SIZE_MAX CC_SHA512_DIGEST_SIZE
#define CC_HASH_BLOCK_SIZE_MAX CC_SHA512_BLOCK_SIZE /*1024b*/
-#else /* Only up to SHA256 */
-#define CC_DIGEST_SIZE_MAX CC_SHA256_DIGEST_SIZE
-#define CC_HASH_BLOCK_SIZE_MAX CC_SHA256_BLOCK_SIZE /*512b*/
-#endif
#define CC_HMAC_BLOCK_SIZE_MAX CC_HASH_BLOCK_SIZE_MAX
@@ -146,25 +130,4 @@ enum drv_hash_hw_mode {
DRV_HASH_HW_RESERVE32B = S32_MAX
};
-/* drv_crypto_key_type[1:0] is mapped to cipher_do[1:0] */
-/* drv_crypto_key_type[2] is mapped to cipher_config2 */
-enum drv_crypto_key_type {
- DRV_NULL_KEY = -1,
- DRV_USER_KEY = 0, /* 0x000 */
- DRV_ROOT_KEY = 1, /* 0x001 */
- DRV_PROVISIONING_KEY = 2, /* 0x010 */
- DRV_SESSION_KEY = 3, /* 0x011 */
- DRV_APPLET_KEY = 4, /* NA */
- DRV_PLATFORM_KEY = 5, /* 0x101 */
- DRV_CUSTOMER_KEY = 6, /* 0x110 */
- DRV_END_OF_KEYS = S32_MAX,
-};
-
-enum drv_crypto_padding_type {
- DRV_PADDING_NONE = 0,
- DRV_PADDING_PKCS7 = 1,
- DRV_PADDING_RESERVE32B = S32_MAX
-};
-
#endif /* _CC_CRYPTO_CTX_H_ */
-
diff --git a/drivers/staging/ccree/cc_debugfs.c b/drivers/crypto/ccree/cc_debugfs.c
index 08f8db489cf0..08f8db489cf0 100644
--- a/drivers/staging/ccree/cc_debugfs.c
+++ b/drivers/crypto/ccree/cc_debugfs.c
diff --git a/drivers/staging/ccree/cc_debugfs.h b/drivers/crypto/ccree/cc_debugfs.h
index 5b5320eca7d2..5b5320eca7d2 100644
--- a/drivers/staging/ccree/cc_debugfs.h
+++ b/drivers/crypto/ccree/cc_debugfs.h
diff --git a/drivers/staging/ccree/cc_driver.c b/drivers/crypto/ccree/cc_driver.c
index 3a1cb0c98648..89ce013ae093 100644
--- a/drivers/staging/ccree/cc_driver.c
+++ b/drivers/crypto/ccree/cc_driver.c
@@ -35,6 +35,34 @@ bool cc_dump_bytes;
module_param_named(dump_bytes, cc_dump_bytes, bool, 0600);
MODULE_PARM_DESC(cc_dump_bytes, "Dump buffers to kernel log as debugging aid");
+struct cc_hw_data {
+ char *name;
+ enum cc_hw_rev rev;
+ u32 sig;
+};
+
+/* Hardware revisions defs. */
+
+static const struct cc_hw_data cc712_hw = {
+ .name = "712", .rev = CC_HW_REV_712, .sig = 0xDCC71200U
+};
+
+static const struct cc_hw_data cc710_hw = {
+ .name = "710", .rev = CC_HW_REV_710, .sig = 0xDCC63200U
+};
+
+static const struct cc_hw_data cc630p_hw = {
+ .name = "630P", .rev = CC_HW_REV_630, .sig = 0xDCC63000U
+};
+
+static const struct of_device_id arm_ccree_dev_of_match[] = {
+ { .compatible = "arm,cryptocell-712-ree", .data = &cc712_hw },
+ { .compatible = "arm,cryptocell-710-ree", .data = &cc710_hw },
+ { .compatible = "arm,cryptocell-630p-ree", .data = &cc630p_hw },
+ {}
+};
+MODULE_DEVICE_TABLE(of, arm_ccree_dev_of_match);
+
void __dump_byte_array(const char *name, const u8 *buf, size_t len)
{
char prefix[64];
@@ -128,9 +156,12 @@ int init_cc_regs(struct cc_drvdata *drvdata, bool is_probe)
cc_iowrite(drvdata, CC_REG(HOST_ICR), val);
/* Unmask relevant interrupt cause */
- val = (unsigned int)(~(CC_COMP_IRQ_MASK | CC_AXI_ERR_IRQ_MASK |
- CC_GPR0_IRQ_MASK));
- cc_iowrite(drvdata, CC_REG(HOST_IMR), val);
+ val = CC_COMP_IRQ_MASK | CC_AXI_ERR_IRQ_MASK;
+
+ if (drvdata->hw_rev >= CC_HW_REV_712)
+ val |= CC_GPR0_IRQ_MASK;
+
+ cc_iowrite(drvdata, CC_REG(HOST_IMR), ~val);
cache_params = (drvdata->coherent ? CC_COHERENT_CACHE_PARAMS : 0x0);
@@ -157,12 +188,30 @@ static int init_cc_resources(struct platform_device *plat_dev)
struct device_node *np = dev->of_node;
u32 signature_val;
u64 dma_mask;
+ const struct cc_hw_data *hw_rev;
+ const struct of_device_id *dev_id;
int rc = 0;
new_drvdata = devm_kzalloc(dev, sizeof(*new_drvdata), GFP_KERNEL);
if (!new_drvdata)
return -ENOMEM;
+ dev_id = of_match_node(arm_ccree_dev_of_match, np);
+ if (!dev_id)
+ return -ENODEV;
+
+ hw_rev = (struct cc_hw_data *)dev_id->data;
+ new_drvdata->hw_rev_name = hw_rev->name;
+ new_drvdata->hw_rev = hw_rev->rev;
+
+ if (hw_rev->rev >= CC_HW_REV_712) {
+ new_drvdata->hash_len_sz = HASH_LEN_SIZE_712;
+ new_drvdata->axim_mon_offset = CC_REG(AXIM_MON_COMP);
+ } else {
+ new_drvdata->hash_len_sz = HASH_LEN_SIZE_630;
+ new_drvdata->axim_mon_offset = CC_REG(AXIM_MON_COMP8);
+ }
+
platform_set_drvdata(plat_dev, new_drvdata);
new_drvdata->plat_dev = plat_dev;
@@ -174,8 +223,10 @@ static int init_cc_resources(struct platform_device *plat_dev)
req_mem_cc_regs = platform_get_resource(plat_dev, IORESOURCE_MEM, 0);
/* Map registers space */
new_drvdata->cc_base = devm_ioremap_resource(dev, req_mem_cc_regs);
- if (IS_ERR(new_drvdata->cc_base))
+ if (IS_ERR(new_drvdata->cc_base)) {
+ dev_err(dev, "Failed to ioremap registers");
return PTR_ERR(new_drvdata->cc_base);
+ }
dev_dbg(dev, "Got MEM resource (%s): %pR\n", req_mem_cc_regs->name,
req_mem_cc_regs);
@@ -190,7 +241,7 @@ static int init_cc_resources(struct platform_device *plat_dev)
}
rc = devm_request_irq(dev, new_drvdata->irq, cc_isr,
- IRQF_SHARED, "arm_cc7x", new_drvdata);
+ IRQF_SHARED, "ccree", new_drvdata);
if (rc) {
dev_err(dev, "Could not register to interrupt %d\n",
new_drvdata->irq);
@@ -214,7 +265,7 @@ static int init_cc_resources(struct platform_device *plat_dev)
}
if (rc) {
- dev_err(dev, "Failed in dma_set_mask, mask=%par\n", &dma_mask);
+ dev_err(dev, "Failed in dma_set_mask, mask=%pad\n", &dma_mask);
return rc;
}
@@ -226,9 +277,9 @@ static int init_cc_resources(struct platform_device *plat_dev)
/* Verify correct mapping */
signature_val = cc_ioread(new_drvdata, CC_REG(HOST_SIGNATURE));
- if (signature_val != CC_DEV_SIGNATURE) {
+ if (signature_val != hw_rev->sig) {
dev_err(dev, "Invalid CC signature: SIGNATURE=0x%08X != expected=0x%08X\n",
- signature_val, (u32)CC_DEV_SIGNATURE);
+ signature_val, hw_rev->sig);
rc = -EINVAL;
goto post_clk_err;
}
@@ -236,8 +287,7 @@ static int init_cc_resources(struct platform_device *plat_dev)
/* Display HW versions */
dev_info(dev, "ARM CryptoCell %s Driver: HW version 0x%08X, Driver version %s\n",
- CC_DEV_NAME_STR,
- cc_ioread(new_drvdata, CC_REG(HOST_VERSION)),
+ hw_rev->name, cc_ioread(new_drvdata, CC_REG(HOST_VERSION)),
DRV_MODULE_VERSION);
rc = init_cc_regs(new_drvdata, true);
@@ -400,7 +450,7 @@ void cc_clk_off(struct cc_drvdata *drvdata)
clk_disable_unprepare(clk);
}
-static int cc7x_probe(struct platform_device *plat_dev)
+static int ccree_probe(struct platform_device *plat_dev)
{
int rc;
struct device *dev = &plat_dev->dev;
@@ -415,11 +465,11 @@ static int cc7x_probe(struct platform_device *plat_dev)
return 0;
}
-static int cc7x_remove(struct platform_device *plat_dev)
+static int ccree_remove(struct platform_device *plat_dev)
{
struct device *dev = &plat_dev->dev;
- dev_dbg(dev, "Releasing cc7x resources...\n");
+ dev_dbg(dev, "Releasing ccree resources...\n");
cleanup_cc_resources(plat_dev);
@@ -428,22 +478,16 @@ static int cc7x_remove(struct platform_device *plat_dev)
return 0;
}
-static const struct of_device_id arm_cc7x_dev_of_match[] = {
- {.compatible = "arm,cryptocell-712-ree"},
- {}
-};
-MODULE_DEVICE_TABLE(of, arm_cc7x_dev_of_match);
-
-static struct platform_driver cc7x_driver = {
+static struct platform_driver ccree_driver = {
.driver = {
- .name = "cc7xree",
- .of_match_table = arm_cc7x_dev_of_match,
+ .name = "ccree",
+ .of_match_table = arm_ccree_dev_of_match,
#ifdef CONFIG_PM
.pm = &ccree_pm,
#endif
},
- .probe = cc7x_probe,
- .remove = cc7x_remove,
+ .probe = ccree_probe,
+ .remove = ccree_remove,
};
static int __init ccree_init(void)
@@ -456,13 +500,13 @@ static int __init ccree_init(void)
if (ret)
return ret;
- return platform_driver_register(&cc7x_driver);
+ return platform_driver_register(&ccree_driver);
}
module_init(ccree_init);
static void __exit ccree_exit(void)
{
- platform_driver_unregister(&cc7x_driver);
+ platform_driver_unregister(&ccree_driver);
cc_debugfs_global_fini();
}
module_exit(ccree_exit);
diff --git a/drivers/staging/ccree/cc_driver.h b/drivers/crypto/ccree/cc_driver.h
index 773ac591c45c..2048fdeb9579 100644
--- a/drivers/staging/ccree/cc_driver.h
+++ b/drivers/crypto/ccree/cc_driver.h
@@ -21,6 +21,7 @@
#include <crypto/aead.h>
#include <crypto/authenc.h>
#include <crypto/hash.h>
+#include <crypto/skcipher.h>
#include <linux/version.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
@@ -35,16 +36,19 @@
extern bool cc_dump_desc;
extern bool cc_dump_bytes;
-#define DRV_MODULE_VERSION "3.0"
+#define DRV_MODULE_VERSION "4.0"
+
+enum cc_hw_rev {
+ CC_HW_REV_630 = 630,
+ CC_HW_REV_710 = 710,
+ CC_HW_REV_712 = 712
+};
-#define CC_DEV_NAME_STR "cc715ree"
#define CC_COHERENT_CACHE_PARAMS 0xEEE
/* Maximum DMA mask supported by IP */
#define DMA_BIT_MASK_LEN 48
-#define CC_DEV_SIGNATURE 0xDCC71200UL
-
#define CC_AXI_IRQ_MASK ((1 << CC_AXIM_CFG_BRESPMASK_BIT_SHIFT) | \
(1 << CC_AXIM_CFG_RRESPMASK_BIT_SHIFT) | \
(1 << CC_AXIM_CFG_INFLTMASK_BIT_SHIFT) | \
@@ -64,7 +68,7 @@ extern bool cc_dump_bytes;
/* TEE FIPS status interrupt */
#define CC_GPR0_IRQ_MASK BIT(CC_HOST_IRR_GPR0_BIT_SHIFT)
-#define CC_CRA_PRIO 3000
+#define CC_CRA_PRIO 400
#define MIN_HW_QUEUE_SIZE 50 /* Minimum size required for proper function */
@@ -111,9 +115,9 @@ struct cc_drvdata {
struct platform_device *plat_dev;
cc_sram_addr_t mlli_sram_addr;
void *buff_mgr_handle;
+ void *cipher_handle;
void *hash_handle;
void *aead_handle;
- void *blkcipher_handle;
void *request_mgr_handle;
void *fips_handle;
void *ivgen_handle;
@@ -121,6 +125,10 @@ struct cc_drvdata {
void *debugfs;
struct clk *clk;
bool coherent;
+ char *hw_rev_name;
+ enum cc_hw_rev hw_rev;
+ u32 hash_len_sz;
+ u32 axim_mon_offset;
};
struct cc_crypto_alg {
@@ -128,8 +136,9 @@ struct cc_crypto_alg {
int cipher_mode;
int flow_mode; /* Note: currently, refers to the cipher mode only. */
int auth_mode;
+ unsigned int data_unit;
struct cc_drvdata *drvdata;
- struct crypto_alg crypto_alg;
+ struct skcipher_alg skcipher_alg;
struct aead_alg aead_alg;
};
@@ -139,15 +148,14 @@ struct cc_alg_template {
unsigned int blocksize;
u32 type;
union {
- struct ablkcipher_alg ablkcipher;
+ struct skcipher_alg skcipher;
struct aead_alg aead;
- struct blkcipher_alg blkcipher;
- struct cipher_alg cipher;
- struct compress_alg compress;
} template_u;
int cipher_mode;
int flow_mode; /* Note: currently, refers to the cipher mode only. */
int auth_mode;
+ u32 min_hw_rev;
+ unsigned int data_unit;
struct cc_drvdata *drvdata;
};
@@ -190,5 +198,11 @@ static inline gfp_t cc_gfp_flags(struct crypto_async_request *req)
GFP_KERNEL : GFP_ATOMIC;
}
-#endif /*__CC_DRIVER_H__*/
+static inline void set_queue_last_ind(struct cc_drvdata *drvdata,
+ struct cc_hw_desc *pdesc)
+{
+ if (drvdata->hw_rev >= CC_HW_REV_712)
+ set_queue_last_ind_bit(pdesc);
+}
+#endif /*__CC_DRIVER_H__*/
diff --git a/drivers/staging/ccree/cc_fips.c b/drivers/crypto/ccree/cc_fips.c
index de08af976b7f..b4d0a6d983e0 100644
--- a/drivers/staging/ccree/cc_fips.c
+++ b/drivers/crypto/ccree/cc_fips.c
@@ -32,6 +32,9 @@ void cc_set_ree_fips_status(struct cc_drvdata *drvdata, bool status)
{
int val = CC_FIPS_SYNC_REE_STATUS;
+ if (drvdata->hw_rev < CC_HW_REV_712)
+ return;
+
val |= (status ? CC_FIPS_SYNC_MODULE_OK : CC_FIPS_SYNC_MODULE_ERROR);
cc_iowrite(drvdata, CC_REG(HOST_GPR0), val);
@@ -41,8 +44,8 @@ void cc_fips_fini(struct cc_drvdata *drvdata)
{
struct cc_fips_handle *fips_h = drvdata->fips_handle;
- if (!fips_h)
- return; /* Not allocated */
+ if (drvdata->hw_rev < CC_HW_REV_712 || !fips_h)
+ return;
/* Kill tasklet */
tasklet_kill(&fips_h->tasklet);
@@ -55,6 +58,9 @@ void fips_handler(struct cc_drvdata *drvdata)
{
struct cc_fips_handle *fips_handle_ptr = drvdata->fips_handle;
+ if (drvdata->hw_rev < CC_HW_REV_712)
+ return;
+
tasklet_schedule(&fips_handle_ptr->tasklet);
}
@@ -95,6 +101,9 @@ int cc_fips_init(struct cc_drvdata *p_drvdata)
struct cc_fips_handle *fips_h;
struct device *dev = drvdata_to_dev(p_drvdata);
+ if (p_drvdata->hw_rev < CC_HW_REV_712)
+ return 0;
+
fips_h = kzalloc(sizeof(*fips_h), GFP_KERNEL);
if (!fips_h)
return -ENOMEM;
diff --git a/drivers/staging/ccree/cc_fips.h b/drivers/crypto/ccree/cc_fips.h
index 0d520030095b..645e096a7a82 100644
--- a/drivers/staging/ccree/cc_fips.h
+++ b/drivers/crypto/ccree/cc_fips.h
@@ -34,4 +34,3 @@ static inline void fips_handler(struct cc_drvdata *drvdata) {}
#endif /* CONFIG_CRYPTO_FIPS */
#endif /*__CC_FIPS_H__*/
-
diff --git a/drivers/staging/ccree/cc_hash.c b/drivers/crypto/ccree/cc_hash.c
index 8afc39f10bb3..96ff777474d7 100644
--- a/drivers/staging/ccree/cc_hash.c
+++ b/drivers/crypto/ccree/cc_hash.c
@@ -35,7 +35,6 @@ static const u32 sha224_init[] = {
static const u32 sha256_init[] = {
SHA256_H7, SHA256_H6, SHA256_H5, SHA256_H4,
SHA256_H3, SHA256_H2, SHA256_H1, SHA256_H0 };
-#if (CC_DEV_SHA_MAX > 256)
static const u32 digest_len_sha512_init[] = {
0x00000080, 0x00000000, 0x00000000, 0x00000000 };
static u64 sha384_init[] = {
@@ -44,7 +43,6 @@ static u64 sha384_init[] = {
static u64 sha512_init[] = {
SHA512_H7, SHA512_H6, SHA512_H5, SHA512_H4,
SHA512_H3, SHA512_H2, SHA512_H1, SHA512_H0 };
-#endif
static void cc_setup_xcbc(struct ahash_request *areq, struct cc_hw_desc desc[],
unsigned int *seq_size);
@@ -136,18 +134,14 @@ static void cc_init_req(struct device *dev, struct ahash_req_ctx *state,
memcpy(state->digest_buff, ctx->digest_buff,
ctx->inter_digestsize);
-#if (CC_DEV_SHA_MAX > 256)
if (ctx->hash_mode == DRV_HASH_SHA512 ||
ctx->hash_mode == DRV_HASH_SHA384)
memcpy(state->digest_bytes_len,
- digest_len_sha512_init, HASH_LEN_SIZE);
+ digest_len_sha512_init,
+ ctx->drvdata->hash_len_sz);
else
- memcpy(state->digest_bytes_len,
- digest_len_init, HASH_LEN_SIZE);
-#else
- memcpy(state->digest_bytes_len, digest_len_init,
- HASH_LEN_SIZE);
-#endif
+ memcpy(state->digest_bytes_len, digest_len_init,
+ ctx->drvdata->hash_len_sz);
}
if (ctx->hash_mode != DRV_HASH_NULL) {
@@ -186,14 +180,14 @@ static int cc_map_req(struct device *dev, struct ahash_req_ctx *state,
if (ctx->hw_mode != DRV_CIPHER_XCBC_MAC) {
state->digest_bytes_len_dma_addr =
dma_map_single(dev, state->digest_bytes_len,
- HASH_LEN_SIZE, DMA_BIDIRECTIONAL);
+ HASH_MAX_LEN_SIZE, DMA_BIDIRECTIONAL);
if (dma_mapping_error(dev, state->digest_bytes_len_dma_addr)) {
dev_err(dev, "Mapping digest len %u B at va=%pK for DMA failed\n",
- HASH_LEN_SIZE, state->digest_bytes_len);
+ HASH_MAX_LEN_SIZE, state->digest_bytes_len);
goto unmap_digest_buf;
}
dev_dbg(dev, "Mapped digest len %u B at va=%pK to dma=%pad\n",
- HASH_LEN_SIZE, state->digest_bytes_len,
+ HASH_MAX_LEN_SIZE, state->digest_bytes_len,
&state->digest_bytes_len_dma_addr);
}
@@ -218,7 +212,7 @@ static int cc_map_req(struct device *dev, struct ahash_req_ctx *state,
unmap_digest_len:
if (state->digest_bytes_len_dma_addr) {
dma_unmap_single(dev, state->digest_bytes_len_dma_addr,
- HASH_LEN_SIZE, DMA_BIDIRECTIONAL);
+ HASH_MAX_LEN_SIZE, DMA_BIDIRECTIONAL);
state->digest_bytes_len_dma_addr = 0;
}
unmap_digest_buf:
@@ -243,7 +237,7 @@ static void cc_unmap_req(struct device *dev, struct ahash_req_ctx *state,
}
if (state->digest_bytes_len_dma_addr) {
dma_unmap_single(dev, state->digest_bytes_len_dma_addr,
- HASH_LEN_SIZE, DMA_BIDIRECTIONAL);
+ HASH_MAX_LEN_SIZE, DMA_BIDIRECTIONAL);
dev_dbg(dev, "Unmapped digest-bytes-len buffer: digest_bytes_len_dma_addr=%pad\n",
&state->digest_bytes_len_dma_addr);
state->digest_bytes_len_dma_addr = 0;
@@ -331,7 +325,7 @@ static int cc_fin_result(struct cc_hw_desc *desc, struct ahash_request *req,
/* TODO */
set_dout_dlli(&desc[idx], state->digest_result_dma_addr, digestsize,
NS_BIT, 1);
- set_queue_last_ind(&desc[idx]);
+ set_queue_last_ind(ctx->drvdata, &desc[idx]);
set_flow_mode(&desc[idx], S_HASH_to_DOUT);
set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED);
@@ -373,7 +367,7 @@ static int cc_fin_hmac(struct cc_hw_desc *desc, struct ahash_request *req,
set_cipher_mode(&desc[idx], ctx->hw_mode);
set_din_sram(&desc[idx],
cc_digest_len_addr(ctx->drvdata, ctx->hash_mode),
- HASH_LEN_SIZE);
+ ctx->drvdata->hash_len_sz);
set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED);
set_flow_mode(&desc[idx], S_DIN_to_HASH);
set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
@@ -438,7 +432,7 @@ static int cc_hash_digest(struct ahash_request *req)
return -ENOMEM;
}
- /* Setup DX request structure */
+ /* Setup request structure */
cc_req.user_cb = cc_digest_complete;
cc_req.user_arg = req;
@@ -464,10 +458,10 @@ static int cc_hash_digest(struct ahash_request *req)
if (is_hmac) {
set_din_type(&desc[idx], DMA_DLLI,
- state->digest_bytes_len_dma_addr, HASH_LEN_SIZE,
- NS_BIT);
+ state->digest_bytes_len_dma_addr,
+ ctx->drvdata->hash_len_sz, NS_BIT);
} else {
- set_din_const(&desc[idx], 0, HASH_LEN_SIZE);
+ set_din_const(&desc[idx], 0, ctx->drvdata->hash_len_sz);
if (nbytes)
set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED);
else
@@ -484,7 +478,7 @@ static int cc_hash_digest(struct ahash_request *req)
hw_desc_init(&desc[idx]);
set_cipher_mode(&desc[idx], ctx->hw_mode);
set_dout_dlli(&desc[idx], state->digest_buff_dma_addr,
- HASH_LEN_SIZE, NS_BIT, 0);
+ ctx->drvdata->hash_len_sz, NS_BIT, 0);
set_flow_mode(&desc[idx], S_HASH_to_DOUT);
set_setup_mode(&desc[idx], SETUP_WRITE_STATE1);
set_cipher_do(&desc[idx], DO_PAD);
@@ -506,7 +500,7 @@ static int cc_hash_digest(struct ahash_request *req)
}
static int cc_restore_hash(struct cc_hw_desc *desc, struct cc_hash_ctx *ctx,
- struct ahash_req_ctx *state, int idx)
+ struct ahash_req_ctx *state, unsigned int idx)
{
/* Restore hash digest */
hw_desc_init(&desc[idx]);
@@ -522,7 +516,7 @@ static int cc_restore_hash(struct cc_hw_desc *desc, struct cc_hash_ctx *ctx,
set_cipher_mode(&desc[idx], ctx->hw_mode);
set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED);
set_din_type(&desc[idx], DMA_DLLI, state->digest_bytes_len_dma_addr,
- HASH_LEN_SIZE, NS_BIT);
+ ctx->drvdata->hash_len_sz, NS_BIT);
set_flow_mode(&desc[idx], S_DIN_to_HASH);
set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
idx++;
@@ -574,7 +568,7 @@ static int cc_hash_update(struct ahash_request *req)
return -EINVAL;
}
- /* Setup DX request structure */
+ /* Setup request structure */
cc_req.user_cb = cc_update_complete;
cc_req.user_arg = req;
@@ -593,8 +587,8 @@ static int cc_hash_update(struct ahash_request *req)
hw_desc_init(&desc[idx]);
set_cipher_mode(&desc[idx], ctx->hw_mode);
set_dout_dlli(&desc[idx], state->digest_bytes_len_dma_addr,
- HASH_LEN_SIZE, NS_BIT, 1);
- set_queue_last_ind(&desc[idx]);
+ ctx->drvdata->hash_len_sz, NS_BIT, 1);
+ set_queue_last_ind(ctx->drvdata, &desc[idx]);
set_flow_mode(&desc[idx], S_HASH_to_DOUT);
set_setup_mode(&desc[idx], SETUP_WRITE_STATE1);
idx++;
@@ -621,7 +615,7 @@ static int cc_hash_finup(struct ahash_request *req)
bool is_hmac = ctx->is_hmac;
struct cc_crypto_req cc_req = {};
struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
- int idx = 0;
+ unsigned int idx = 0;
int rc;
gfp_t flags = cc_gfp_flags(&req->base);
@@ -646,7 +640,7 @@ static int cc_hash_finup(struct ahash_request *req)
return -ENOMEM;
}
- /* Setup DX request structure */
+ /* Setup request structure */
cc_req.user_cb = cc_hash_complete;
cc_req.user_arg = req;
@@ -680,7 +674,7 @@ static int cc_hash_final(struct ahash_request *req)
bool is_hmac = ctx->is_hmac;
struct cc_crypto_req cc_req = {};
struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
- int idx = 0;
+ unsigned int idx = 0;
int rc;
gfp_t flags = cc_gfp_flags(&req->base);
@@ -706,7 +700,7 @@ static int cc_hash_final(struct ahash_request *req)
return -ENOMEM;
}
- /* Setup DX request structure */
+ /* Setup request structure */
cc_req.user_cb = cc_hash_complete;
cc_req.user_arg = req;
@@ -717,7 +711,7 @@ static int cc_hash_final(struct ahash_request *req)
set_cipher_do(&desc[idx], DO_PAD);
set_cipher_mode(&desc[idx], ctx->hw_mode);
set_dout_dlli(&desc[idx], state->digest_bytes_len_dma_addr,
- HASH_LEN_SIZE, NS_BIT, 0);
+ ctx->drvdata->hash_len_sz, NS_BIT, 0);
set_setup_mode(&desc[idx], SETUP_WRITE_STATE1);
set_flow_mode(&desc[idx], S_HASH_to_DOUT);
idx++;
@@ -804,7 +798,7 @@ static int cc_hash_setkey(struct crypto_ahash *ahash, const u8 *key,
/* Load the hash current length*/
hw_desc_init(&desc[idx]);
set_cipher_mode(&desc[idx], ctx->hw_mode);
- set_din_const(&desc[idx], 0, HASH_LEN_SIZE);
+ set_din_const(&desc[idx], 0, ctx->drvdata->hash_len_sz);
set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED);
set_flow_mode(&desc[idx], S_DIN_to_HASH);
set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
@@ -886,7 +880,7 @@ static int cc_hash_setkey(struct crypto_ahash *ahash, const u8 *key,
/* Load the hash current length*/
hw_desc_init(&desc[idx]);
set_cipher_mode(&desc[idx], ctx->hw_mode);
- set_din_const(&desc[idx], 0, HASH_LEN_SIZE);
+ set_din_const(&desc[idx], 0, ctx->drvdata->hash_len_sz);
set_flow_mode(&desc[idx], S_DIN_to_HASH);
set_setup_mode(&desc[idx], SETUP_LOAD_KEY0);
idx++;
@@ -945,7 +939,8 @@ static int cc_xcbc_setkey(struct crypto_ahash *ahash,
struct cc_crypto_req cc_req = {};
struct cc_hash_ctx *ctx = crypto_ahash_ctx(ahash);
struct device *dev = drvdata_to_dev(ctx->drvdata);
- int idx = 0, rc = 0;
+ int rc = 0;
+ unsigned int idx = 0;
struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
dev_dbg(dev, "===== setkey (%d) ====\n", keylen);
@@ -1203,12 +1198,12 @@ static int cc_mac_update(struct ahash_request *req)
set_cipher_mode(&desc[idx], ctx->hw_mode);
set_dout_dlli(&desc[idx], state->digest_buff_dma_addr,
ctx->inter_digestsize, NS_BIT, 1);
- set_queue_last_ind(&desc[idx]);
+ set_queue_last_ind(ctx->drvdata, &desc[idx]);
set_flow_mode(&desc[idx], S_AES_to_DOUT);
set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
idx++;
- /* Setup DX request structure */
+ /* Setup request structure */
cc_req.user_cb = (void *)cc_update_complete;
cc_req.user_arg = (void *)req;
@@ -1266,7 +1261,7 @@ static int cc_mac_final(struct ahash_request *req)
return -ENOMEM;
}
- /* Setup DX request structure */
+ /* Setup request structure */
cc_req.user_cb = (void *)cc_hash_complete;
cc_req.user_arg = (void *)req;
@@ -1327,7 +1322,7 @@ static int cc_mac_final(struct ahash_request *req)
/* TODO */
set_dout_dlli(&desc[idx], state->digest_result_dma_addr,
digestsize, NS_BIT, 1);
- set_queue_last_ind(&desc[idx]);
+ set_queue_last_ind(ctx->drvdata, &desc[idx]);
set_flow_mode(&desc[idx], S_AES_to_DOUT);
set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
set_cipher_mode(&desc[idx], ctx->hw_mode);
@@ -1381,7 +1376,7 @@ static int cc_mac_finup(struct ahash_request *req)
return -ENOMEM;
}
- /* Setup DX request structure */
+ /* Setup request structure */
cc_req.user_cb = (void *)cc_hash_complete;
cc_req.user_arg = (void *)req;
@@ -1409,7 +1404,7 @@ static int cc_mac_finup(struct ahash_request *req)
/* TODO */
set_dout_dlli(&desc[idx], state->digest_result_dma_addr,
digestsize, NS_BIT, 1);
- set_queue_last_ind(&desc[idx]);
+ set_queue_last_ind(ctx->drvdata, &desc[idx]);
set_flow_mode(&desc[idx], S_AES_to_DOUT);
set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
set_cipher_mode(&desc[idx], ctx->hw_mode);
@@ -1435,7 +1430,7 @@ static int cc_mac_digest(struct ahash_request *req)
struct cc_crypto_req cc_req = {};
struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN];
u32 key_len;
- int idx = 0;
+ unsigned int idx = 0;
int rc;
gfp_t flags = cc_gfp_flags(&req->base);
@@ -1460,7 +1455,7 @@ static int cc_mac_digest(struct ahash_request *req)
return -ENOMEM;
}
- /* Setup DX request structure */
+ /* Setup request structure */
cc_req.user_cb = (void *)cc_digest_complete;
cc_req.user_arg = (void *)req;
@@ -1487,7 +1482,7 @@ static int cc_mac_digest(struct ahash_request *req)
hw_desc_init(&desc[idx]);
set_dout_dlli(&desc[idx], state->digest_result_dma_addr,
CC_AES_BLOCK_SIZE, NS_BIT, 1);
- set_queue_last_ind(&desc[idx]);
+ set_queue_last_ind(ctx->drvdata, &desc[idx]);
set_flow_mode(&desc[idx], S_AES_to_DOUT);
set_setup_mode(&desc[idx], SETUP_WRITE_STATE0);
set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
@@ -1519,8 +1514,8 @@ static int cc_hash_export(struct ahash_request *req, void *out)
memcpy(out, state->digest_buff, ctx->inter_digestsize);
out += ctx->inter_digestsize;
- memcpy(out, state->digest_bytes_len, HASH_LEN_SIZE);
- out += HASH_LEN_SIZE;
+ memcpy(out, state->digest_bytes_len, ctx->drvdata->hash_len_sz);
+ out += ctx->drvdata->hash_len_sz;
memcpy(out, &curr_buff_cnt, sizeof(u32));
out += sizeof(u32);
@@ -1548,8 +1543,8 @@ static int cc_hash_import(struct ahash_request *req, const void *in)
memcpy(state->digest_buff, in, ctx->inter_digestsize);
in += ctx->inter_digestsize;
- memcpy(state->digest_bytes_len, in, HASH_LEN_SIZE);
- in += HASH_LEN_SIZE;
+ memcpy(state->digest_bytes_len, in, ctx->drvdata->hash_len_sz);
+ in += ctx->drvdata->hash_len_sz;
/* Sanity check the data as much as possible */
memcpy(&tmp, in, sizeof(u32));
@@ -1575,19 +1570,20 @@ struct cc_hash_template {
int hw_mode;
int inter_digestsize;
struct cc_drvdata *drvdata;
+ u32 min_hw_rev;
};
#define CC_STATE_SIZE(_x) \
- ((_x) + HASH_LEN_SIZE + CC_MAX_HASH_BLCK_SIZE + (2 * sizeof(u32)))
+ ((_x) + HASH_MAX_LEN_SIZE + CC_MAX_HASH_BLCK_SIZE + (2 * sizeof(u32)))
/* hash descriptors */
static struct cc_hash_template driver_hash[] = {
//Asynchronize hash template
{
.name = "sha1",
- .driver_name = "sha1-dx",
+ .driver_name = "sha1-ccree",
.mac_name = "hmac(sha1)",
- .mac_driver_name = "hmac-sha1-dx",
+ .mac_driver_name = "hmac-sha1-ccree",
.blocksize = SHA1_BLOCK_SIZE,
.synchronize = false,
.template_ahash = {
@@ -1607,12 +1603,13 @@ static struct cc_hash_template driver_hash[] = {
.hash_mode = DRV_HASH_SHA1,
.hw_mode = DRV_HASH_HW_SHA1,
.inter_digestsize = SHA1_DIGEST_SIZE,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "sha256",
- .driver_name = "sha256-dx",
+ .driver_name = "sha256-ccree",
.mac_name = "hmac(sha256)",
- .mac_driver_name = "hmac-sha256-dx",
+ .mac_driver_name = "hmac-sha256-ccree",
.blocksize = SHA256_BLOCK_SIZE,
.template_ahash = {
.init = cc_hash_init,
@@ -1631,12 +1628,13 @@ static struct cc_hash_template driver_hash[] = {
.hash_mode = DRV_HASH_SHA256,
.hw_mode = DRV_HASH_HW_SHA256,
.inter_digestsize = SHA256_DIGEST_SIZE,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.name = "sha224",
- .driver_name = "sha224-dx",
+ .driver_name = "sha224-ccree",
.mac_name = "hmac(sha224)",
- .mac_driver_name = "hmac-sha224-dx",
+ .mac_driver_name = "hmac-sha224-ccree",
.blocksize = SHA224_BLOCK_SIZE,
.template_ahash = {
.init = cc_hash_init,
@@ -1655,13 +1653,13 @@ static struct cc_hash_template driver_hash[] = {
.hash_mode = DRV_HASH_SHA224,
.hw_mode = DRV_HASH_HW_SHA256,
.inter_digestsize = SHA256_DIGEST_SIZE,
+ .min_hw_rev = CC_HW_REV_630,
},
-#if (CC_DEV_SHA_MAX > 256)
{
.name = "sha384",
- .driver_name = "sha384-dx",
+ .driver_name = "sha384-ccree",
.mac_name = "hmac(sha384)",
- .mac_driver_name = "hmac-sha384-dx",
+ .mac_driver_name = "hmac-sha384-ccree",
.blocksize = SHA384_BLOCK_SIZE,
.template_ahash = {
.init = cc_hash_init,
@@ -1680,12 +1678,13 @@ static struct cc_hash_template driver_hash[] = {
.hash_mode = DRV_HASH_SHA384,
.hw_mode = DRV_HASH_HW_SHA512,
.inter_digestsize = SHA512_DIGEST_SIZE,
+ .min_hw_rev = CC_HW_REV_712,
},
{
.name = "sha512",
- .driver_name = "sha512-dx",
+ .driver_name = "sha512-ccree",
.mac_name = "hmac(sha512)",
- .mac_driver_name = "hmac-sha512-dx",
+ .mac_driver_name = "hmac-sha512-ccree",
.blocksize = SHA512_BLOCK_SIZE,
.template_ahash = {
.init = cc_hash_init,
@@ -1704,13 +1703,13 @@ static struct cc_hash_template driver_hash[] = {
.hash_mode = DRV_HASH_SHA512,
.hw_mode = DRV_HASH_HW_SHA512,
.inter_digestsize = SHA512_DIGEST_SIZE,
+ .min_hw_rev = CC_HW_REV_712,
},
-#endif
{
.name = "md5",
- .driver_name = "md5-dx",
+ .driver_name = "md5-ccree",
.mac_name = "hmac(md5)",
- .mac_driver_name = "hmac-md5-dx",
+ .mac_driver_name = "hmac-md5-ccree",
.blocksize = MD5_HMAC_BLOCK_SIZE,
.template_ahash = {
.init = cc_hash_init,
@@ -1729,10 +1728,11 @@ static struct cc_hash_template driver_hash[] = {
.hash_mode = DRV_HASH_MD5,
.hw_mode = DRV_HASH_HW_MD5,
.inter_digestsize = MD5_DIGEST_SIZE,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.mac_name = "xcbc(aes)",
- .mac_driver_name = "xcbc-aes-dx",
+ .mac_driver_name = "xcbc-aes-ccree",
.blocksize = AES_BLOCK_SIZE,
.template_ahash = {
.init = cc_hash_init,
@@ -1751,10 +1751,11 @@ static struct cc_hash_template driver_hash[] = {
.hash_mode = DRV_HASH_NULL,
.hw_mode = DRV_CIPHER_XCBC_MAC,
.inter_digestsize = AES_BLOCK_SIZE,
+ .min_hw_rev = CC_HW_REV_630,
},
{
.mac_name = "cmac(aes)",
- .mac_driver_name = "cmac-aes-dx",
+ .mac_driver_name = "cmac-aes-ccree",
.blocksize = AES_BLOCK_SIZE,
.template_ahash = {
.init = cc_hash_init,
@@ -1773,6 +1774,7 @@ static struct cc_hash_template driver_hash[] = {
.hash_mode = DRV_HASH_NULL,
.hw_mode = DRV_CIPHER_CMAC,
.inter_digestsize = AES_BLOCK_SIZE,
+ .min_hw_rev = CC_HW_REV_630,
},
};
@@ -1828,6 +1830,7 @@ int cc_init_hash_sram(struct cc_drvdata *drvdata)
cc_sram_addr_t sram_buff_ofs = hash_handle->digest_len_sram_addr;
unsigned int larval_seq_len = 0;
struct cc_hw_desc larval_seq[CC_DIGEST_SIZE_MAX / sizeof(u32)];
+ bool large_sha_supported = (drvdata->hw_rev >= CC_HW_REV_712);
int rc = 0;
/* Copy-to-sram digest-len */
@@ -1841,18 +1844,18 @@ int cc_init_hash_sram(struct cc_drvdata *drvdata)
sram_buff_ofs += sizeof(digest_len_init);
larval_seq_len = 0;
-#if (CC_DEV_SHA_MAX > 256)
- /* Copy-to-sram digest-len for sha384/512 */
- cc_set_sram_desc(digest_len_sha512_init, sram_buff_ofs,
- ARRAY_SIZE(digest_len_sha512_init),
- larval_seq, &larval_seq_len);
- rc = send_request_init(drvdata, larval_seq, larval_seq_len);
- if (rc)
- goto init_digest_const_err;
+ if (large_sha_supported) {
+ /* Copy-to-sram digest-len for sha384/512 */
+ cc_set_sram_desc(digest_len_sha512_init, sram_buff_ofs,
+ ARRAY_SIZE(digest_len_sha512_init),
+ larval_seq, &larval_seq_len);
+ rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+ if (rc)
+ goto init_digest_const_err;
- sram_buff_ofs += sizeof(digest_len_sha512_init);
- larval_seq_len = 0;
-#endif
+ sram_buff_ofs += sizeof(digest_len_sha512_init);
+ larval_seq_len = 0;
+ }
/* The initial digests offset */
hash_handle->larval_digest_sram_addr = sram_buff_ofs;
@@ -1893,23 +1896,23 @@ int cc_init_hash_sram(struct cc_drvdata *drvdata)
sram_buff_ofs += sizeof(sha256_init);
larval_seq_len = 0;
-#if (CC_DEV_SHA_MAX > 256)
- cc_set_sram_desc((u32 *)sha384_init, sram_buff_ofs,
- (ARRAY_SIZE(sha384_init) * 2), larval_seq,
- &larval_seq_len);
- rc = send_request_init(drvdata, larval_seq, larval_seq_len);
- if (rc)
- goto init_digest_const_err;
- sram_buff_ofs += sizeof(sha384_init);
- larval_seq_len = 0;
+ if (large_sha_supported) {
+ cc_set_sram_desc((u32 *)sha384_init, sram_buff_ofs,
+ (ARRAY_SIZE(sha384_init) * 2), larval_seq,
+ &larval_seq_len);
+ rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+ if (rc)
+ goto init_digest_const_err;
+ sram_buff_ofs += sizeof(sha384_init);
+ larval_seq_len = 0;
- cc_set_sram_desc((u32 *)sha512_init, sram_buff_ofs,
- (ARRAY_SIZE(sha512_init) * 2), larval_seq,
- &larval_seq_len);
- rc = send_request_init(drvdata, larval_seq, larval_seq_len);
- if (rc)
- goto init_digest_const_err;
-#endif
+ cc_set_sram_desc((u32 *)sha512_init, sram_buff_ofs,
+ (ARRAY_SIZE(sha512_init) * 2), larval_seq,
+ &larval_seq_len);
+ rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+ if (rc)
+ goto init_digest_const_err;
+ }
init_digest_const_err:
return rc;
@@ -1954,16 +1957,15 @@ int cc_hash_alloc(struct cc_drvdata *drvdata)
drvdata->hash_handle = hash_handle;
sram_size_to_alloc = sizeof(digest_len_init) +
-#if (CC_DEV_SHA_MAX > 256)
- sizeof(digest_len_sha512_init) +
- sizeof(sha384_init) +
- sizeof(sha512_init) +
-#endif
sizeof(md5_init) +
sizeof(sha1_init) +
sizeof(sha224_init) +
sizeof(sha256_init);
+ if (drvdata->hw_rev >= CC_HW_REV_712)
+ sram_size_to_alloc += sizeof(digest_len_sha512_init) +
+ sizeof(sha384_init) + sizeof(sha512_init);
+
sram_buff = cc_sram_alloc(drvdata, sram_size_to_alloc);
if (sram_buff == NULL_SRAM_ADDR) {
dev_err(dev, "SRAM pool exhausted\n");
@@ -1986,6 +1988,10 @@ int cc_hash_alloc(struct cc_drvdata *drvdata)
struct cc_hash_alg *t_alg;
int hw_mode = driver_hash[alg].hw_mode;
+ /* We either support both HASH and MAC or none */
+ if (driver_hash[alg].min_hw_rev > drvdata->hw_rev)
+ continue;
+
/* register hmac version */
t_alg = cc_alloc_hash_alg(&driver_hash[alg], dev, true);
if (IS_ERR(t_alg)) {
@@ -2203,12 +2209,10 @@ static const void *cc_larval_digest(struct device *dev, u32 mode)
return sha224_init;
case DRV_HASH_SHA256:
return sha256_init;
-#if (CC_DEV_SHA_MAX > 256)
case DRV_HASH_SHA384:
return sha384_init;
case DRV_HASH_SHA512:
return sha512_init;
-#endif
default:
dev_err(dev, "Invalid hash mode (%d)\n", mode);
return md5_init;
@@ -2247,7 +2251,6 @@ cc_sram_addr_t cc_larval_digest_addr(void *drvdata, u32 mode)
sizeof(md5_init) +
sizeof(sha1_init) +
sizeof(sha224_init));
-#if (CC_DEV_SHA_MAX > 256)
case DRV_HASH_SHA384:
return (hash_handle->larval_digest_sram_addr +
sizeof(md5_init) +
@@ -2261,7 +2264,6 @@ cc_sram_addr_t cc_larval_digest_addr(void *drvdata, u32 mode)
sizeof(sha224_init) +
sizeof(sha256_init) +
sizeof(sha384_init));
-#endif
default:
dev_err(dev, "Invalid hash mode (%d)\n", mode);
}
@@ -2292,4 +2294,3 @@ cc_digest_len_addr(void *drvdata, u32 mode)
return digest_len_addr; /*to avoid kernel crash*/
}
}
-
diff --git a/drivers/staging/ccree/cc_hash.h b/drivers/crypto/ccree/cc_hash.h
index aa42b8f4348d..2e5bf8b0bbb6 100644
--- a/drivers/staging/ccree/cc_hash.h
+++ b/drivers/crypto/ccree/cc_hash.h
@@ -12,15 +12,11 @@
#define HMAC_IPAD_CONST 0x36363636
#define HMAC_OPAD_CONST 0x5C5C5C5C
-#if (CC_DEV_SHA_MAX > 256)
-#define HASH_LEN_SIZE 16
+#define HASH_LEN_SIZE_712 16
+#define HASH_LEN_SIZE_630 8
+#define HASH_MAX_LEN_SIZE HASH_LEN_SIZE_712
#define CC_MAX_HASH_DIGEST_SIZE SHA512_DIGEST_SIZE
#define CC_MAX_HASH_BLCK_SIZE SHA512_BLOCK_SIZE
-#else
-#define HASH_LEN_SIZE 8
-#define CC_MAX_HASH_DIGEST_SIZE SHA256_DIGEST_SIZE
-#define CC_MAX_HASH_BLCK_SIZE SHA256_BLOCK_SIZE
-#endif
#define XCBC_MAC_K1_OFFSET 0
#define XCBC_MAC_K2_OFFSET 16
@@ -43,7 +39,7 @@ struct ahash_req_ctx {
u8 digest_result_buff[CC_MAX_HASH_DIGEST_SIZE] ____cacheline_aligned;
u8 digest_buff[CC_MAX_HASH_DIGEST_SIZE] ____cacheline_aligned;
u8 opad_digest_buff[CC_MAX_HASH_DIGEST_SIZE] ____cacheline_aligned;
- u8 digest_bytes_len[HASH_LEN_SIZE] ____cacheline_aligned;
+ u8 digest_bytes_len[HASH_MAX_LEN_SIZE] ____cacheline_aligned;
struct async_gen_req_ctx gen_ctx ____cacheline_aligned;
enum cc_req_dma_buf_type data_dma_buf_type;
dma_addr_t opad_digest_dma_addr;
@@ -111,4 +107,3 @@ cc_sram_addr_t cc_larval_digest_addr(void *drvdata, u32 mode);
void cc_hash_global_init(void);
#endif /*__CC_HASH_H__*/
-
diff --git a/drivers/staging/ccree/cc_host_regs.h b/drivers/crypto/ccree/cc_host_regs.h
index 69ef2fa0cb9b..f51001898ca1 100644
--- a/drivers/staging/ccree/cc_host_regs.h
+++ b/drivers/crypto/ccree/cc_host_regs.h
@@ -18,6 +18,9 @@
#define CC_HOST_IRR_DSCRPTR_WATERMARK_INT_BIT_SIZE 0x1UL
#define CC_HOST_IRR_AXIM_COMP_INT_BIT_SHIFT 0x17UL
#define CC_HOST_IRR_AXIM_COMP_INT_BIT_SIZE 0x1UL
+#define CC_HOST_SEP_SRAM_THRESHOLD_REG_OFFSET 0xA10UL
+#define CC_HOST_SEP_SRAM_THRESHOLD_VALUE_BIT_SHIFT 0x0UL
+#define CC_HOST_SEP_SRAM_THRESHOLD_VALUE_BIT_SIZE 0xCUL
#define CC_HOST_IMR_REG_OFFSET 0xA04UL
#define CC_HOST_IMR_NOT_USED_MASK_BIT_SHIFT 0x1UL
#define CC_HOST_IMR_NOT_USED_MASK_BIT_SIZE 0x1UL
diff --git a/drivers/staging/ccree/cc_hw_queue_defs.h b/drivers/crypto/ccree/cc_hw_queue_defs.h
index a79f28cec5ae..a091ae57f902 100644
--- a/drivers/staging/ccree/cc_hw_queue_defs.h
+++ b/drivers/crypto/ccree/cc_hw_queue_defs.h
@@ -124,13 +124,6 @@ enum cc_flow_mode {
FLOW_MODE_END = S32_MAX,
};
-enum cc_tunnel_op {
- TUNNEL_OP_INVALID = -1,
- TUNNEL_OFF = 0,
- TUNNEL_ON = 1,
- TUNNEL_OP_END = S32_MAX,
-};
-
enum cc_setup_op {
SETUP_LOAD_NOP = 0,
SETUP_LOAD_STATE0 = 1,
@@ -145,6 +138,13 @@ enum cc_setup_op {
SETUP_OP_END = S32_MAX,
};
+enum cc_hash_conf_pad {
+ HASH_PADDING_DISABLED = 0,
+ HASH_PADDING_ENABLED = 1,
+ HASH_DIGEST_RESULT_LITTLE_ENDIAN = 2,
+ HASH_CONFIG1_PADDING_RESERVE32 = S32_MAX,
+};
+
enum cc_aes_mac_selector {
AES_SK = 1,
AES_CMAC_INIT = 2,
@@ -179,20 +179,6 @@ enum cc_hw_aes_key_size {
END_OF_AES_KEYS = S32_MAX,
};
-enum cc_hw_des_key_size {
- DES_ONE_KEY = 0,
- DES_TWO_KEYS = 1,
- DES_THREE_KEYS = 2,
- END_OF_DES_KEYS = S32_MAX,
-};
-
-enum cc_hash_conf_pad {
- HASH_PADDING_DISABLED = 0,
- HASH_PADDING_ENABLED = 1,
- HASH_DIGEST_RESULT_LITTLE_ENDIAN = 2,
- HASH_CONFIG1_PADDING_RESERVE32 = S32_MAX,
-};
-
enum cc_hash_cipher_pad {
DO_NOT_PAD = 0,
DO_PAD = 1,
@@ -217,7 +203,7 @@ static inline void hw_desc_init(struct cc_hw_desc *pdesc)
*
* @pdesc: pointer HW descriptor struct
*/
-static inline void set_queue_last_ind(struct cc_hw_desc *pdesc)
+static inline void set_queue_last_ind_bit(struct cc_hw_desc *pdesc)
{
pdesc->word[3] |= FIELD_PREP(WORD3_QUEUE_LAST_IND, 1);
}
diff --git a/drivers/staging/ccree/cc_ivgen.c b/drivers/crypto/ccree/cc_ivgen.c
index c47f419b277b..769458323394 100644
--- a/drivers/staging/ccree/cc_ivgen.c
+++ b/drivers/crypto/ccree/cc_ivgen.c
@@ -95,7 +95,7 @@ static int cc_gen_iv_pool(struct cc_ivgen_ctx *ivgen_ctx,
/*!
* Generates the initial pool in SRAM.
- * This function should be invoked when resuming DX driver.
+ * This function should be invoked when resuming driver.
*
* \param drvdata
*
@@ -178,8 +178,6 @@ int cc_ivgen_init(struct cc_drvdata *drvdata)
if (!ivgen_ctx)
return -ENOMEM;
- drvdata->ivgen_handle = ivgen_ctx;
-
/* Allocate pool's header for initial enc. key/IV */
ivgen_ctx->pool_meta = dma_alloc_coherent(device, CC_IVPOOL_META_SIZE,
&ivgen_ctx->pool_meta_dma,
@@ -198,6 +196,8 @@ int cc_ivgen_init(struct cc_drvdata *drvdata)
goto out;
}
+ drvdata->ivgen_handle = ivgen_ctx;
+
return cc_init_iv_sram(drvdata);
out:
@@ -277,4 +277,3 @@ int cc_get_iv(struct cc_drvdata *drvdata, dma_addr_t iv_out_dma[],
return 0;
}
-
diff --git a/drivers/staging/ccree/cc_ivgen.h b/drivers/crypto/ccree/cc_ivgen.h
index b6ac16903dda..b6ac16903dda 100644
--- a/drivers/staging/ccree/cc_ivgen.h
+++ b/drivers/crypto/ccree/cc_ivgen.h
diff --git a/drivers/staging/ccree/cc_kernel_regs.h b/drivers/crypto/ccree/cc_kernel_regs.h
index fa994406d610..8d7262a35156 100644
--- a/drivers/staging/ccree/cc_kernel_regs.h
+++ b/drivers/crypto/ccree/cc_kernel_regs.h
@@ -118,6 +118,7 @@
#define CC_AXIM_MON_INFLIGHTLAST_VALUE_BIT_SHIFT 0x0UL
#define CC_AXIM_MON_INFLIGHTLAST_VALUE_BIT_SIZE 0x8UL
#define CC_AXIM_MON_COMP_REG_OFFSET 0xB80UL
+#define CC_AXIM_MON_COMP8_REG_OFFSET 0xBA0UL
#define CC_AXIM_MON_COMP_VALUE_BIT_SHIFT 0x0UL
#define CC_AXIM_MON_COMP_VALUE_BIT_SIZE 0x10UL
#define CC_AXIM_MON_ERR_REG_OFFSET 0xBC4UL
diff --git a/drivers/staging/ccree/cc_lli_defs.h b/drivers/crypto/ccree/cc_lli_defs.h
index 64b15ac9f1d3..64b15ac9f1d3 100644
--- a/drivers/staging/ccree/cc_lli_defs.h
+++ b/drivers/crypto/ccree/cc_lli_defs.h
diff --git a/drivers/staging/ccree/cc_pm.c b/drivers/crypto/ccree/cc_pm.c
index d990f472e89f..d990f472e89f 100644
--- a/drivers/staging/ccree/cc_pm.c
+++ b/drivers/crypto/ccree/cc_pm.c
diff --git a/drivers/staging/ccree/cc_pm.h b/drivers/crypto/ccree/cc_pm.h
index aac8190fea38..020a5403c58b 100644
--- a/drivers/staging/ccree/cc_pm.h
+++ b/drivers/crypto/ccree/cc_pm.h
@@ -54,4 +54,3 @@ static inline int cc_pm_put_suspend(struct device *dev)
#endif
#endif /*__POWER_MGR_H__*/
-
diff --git a/drivers/staging/ccree/cc_request_mgr.c b/drivers/crypto/ccree/cc_request_mgr.c
index 8a7f83407410..83a8aaae61c7 100644
--- a/drivers/staging/ccree/cc_request_mgr.c
+++ b/drivers/crypto/ccree/cc_request_mgr.c
@@ -81,8 +81,7 @@ void cc_req_mgr_fini(struct cc_drvdata *drvdata)
/* Kill tasklet */
tasklet_kill(&req_mgr_h->comptask);
#endif
- memset(req_mgr_h, 0, sizeof(struct cc_req_mgr_handle));
- kfree(req_mgr_h);
+ kzfree(req_mgr_h);
drvdata->request_mgr_handle = NULL;
}
@@ -106,7 +105,7 @@ int cc_req_mgr_init(struct cc_drvdata *drvdata)
#ifdef COMP_IN_WQ
dev_dbg(dev, "Initializing completion workqueue\n");
- req_mgr_h->workq = create_singlethread_workqueue("arm_cc7x_wq");
+ req_mgr_h->workq = create_singlethread_workqueue("ccree");
if (!req_mgr_h->workq) {
dev_err(dev, "Failed creating work queue\n");
rc = -ENOMEM;
@@ -148,7 +147,7 @@ int cc_req_mgr_init(struct cc_drvdata *drvdata)
set_dout_dlli(&req_mgr_h->compl_desc, req_mgr_h->dummy_comp_buff_dma,
sizeof(u32), NS_BIT, 1);
set_flow_mode(&req_mgr_h->compl_desc, BYPASS);
- set_queue_last_ind(&req_mgr_h->compl_desc);
+ set_queue_last_ind(drvdata, &req_mgr_h->compl_desc);
return 0;
@@ -531,7 +530,7 @@ int send_request_init(struct cc_drvdata *drvdata, struct cc_hw_desc *desc,
if (rc)
return rc;
- set_queue_last_ind(&desc[(len - 1)]);
+ set_queue_last_ind(drvdata, &desc[(len - 1)]);
/*
* We are about to push command to the HW via the command registers
@@ -610,7 +609,7 @@ static void proc_completions(struct cc_drvdata *drvdata)
static inline u32 cc_axi_comp_count(struct cc_drvdata *drvdata)
{
return FIELD_GET(AXIM_MON_COMP_VALUE,
- cc_ioread(drvdata, CC_REG(AXIM_MON_COMP)));
+ cc_ioread(drvdata, drvdata->axim_mon_offset));
}
/* Deferred service handler, run as interrupt-fired tasklet */
@@ -710,4 +709,3 @@ bool cc_req_queue_suspended(struct cc_drvdata *drvdata)
}
#endif
-
diff --git a/drivers/staging/ccree/cc_request_mgr.h b/drivers/crypto/ccree/cc_request_mgr.h
index 573cb97af085..573cb97af085 100644
--- a/drivers/staging/ccree/cc_request_mgr.h
+++ b/drivers/crypto/ccree/cc_request_mgr.h
diff --git a/drivers/staging/ccree/cc_sram_mgr.c b/drivers/crypto/ccree/cc_sram_mgr.c
index d1f8a9cc1c0f..c8c276f6dee9 100644
--- a/drivers/staging/ccree/cc_sram_mgr.c
+++ b/drivers/crypto/ccree/cc_sram_mgr.c
@@ -33,6 +33,19 @@ void cc_sram_mgr_fini(struct cc_drvdata *drvdata)
int cc_sram_mgr_init(struct cc_drvdata *drvdata)
{
struct cc_sram_ctx *ctx;
+ dma_addr_t start = 0;
+ struct device *dev = drvdata_to_dev(drvdata);
+
+ if (drvdata->hw_rev < CC_HW_REV_712) {
+ /* Pool starts after ROM bytes */
+ start = (dma_addr_t)cc_ioread(drvdata,
+ CC_REG(HOST_SEP_SRAM_THRESHOLD));
+
+ if ((start & 0x3) != 0) {
+ dev_err(dev, "Invalid SRAM offset %pad\n", &start);
+ return -EINVAL;
+ }
+ }
/* Allocate "this" context */
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -40,6 +53,7 @@ int cc_sram_mgr_init(struct cc_drvdata *drvdata)
if (!ctx)
return -ENOMEM;
+ ctx->sram_free_offset = start;
drvdata->sram_mgr_handle = ctx;
return 0;
@@ -104,4 +118,3 @@ void cc_set_sram_desc(const u32 *src, cc_sram_addr_t dst,
*seq_len = idx;
}
-
diff --git a/drivers/staging/ccree/cc_sram_mgr.h b/drivers/crypto/ccree/cc_sram_mgr.h
index d48649fb3323..d48649fb3323 100644
--- a/drivers/staging/ccree/cc_sram_mgr.h
+++ b/drivers/crypto/ccree/cc_sram_mgr.h
diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c
index 34a02d690548..59fe6631e73e 100644
--- a/drivers/crypto/chelsio/chcr_algo.c
+++ b/drivers/crypto/chelsio/chcr_algo.c
@@ -131,6 +131,11 @@ static inline int is_ofld_imm(const struct sk_buff *skb)
return (skb->len <= SGE_MAX_WR_LEN);
}
+static inline void chcr_init_hctx_per_wr(struct chcr_ahash_req_ctx *reqctx)
+{
+ memset(&reqctx->hctx_wr, 0, sizeof(struct chcr_hctx_per_wr));
+}
+
static int sg_nents_xlen(struct scatterlist *sg, unsigned int reqlen,
unsigned int entlen,
unsigned int skip)
@@ -160,41 +165,6 @@ static int sg_nents_xlen(struct scatterlist *sg, unsigned int reqlen,
return nents;
}
-static inline void chcr_handle_ahash_resp(struct ahash_request *req,
- unsigned char *input,
- int err)
-{
- struct chcr_ahash_req_ctx *reqctx = ahash_request_ctx(req);
- int digestsize, updated_digestsize;
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct uld_ctx *u_ctx = ULD_CTX(h_ctx(tfm));
-
- if (input == NULL)
- goto out;
- digestsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(req));
- if (reqctx->is_sg_map)
- chcr_hash_dma_unmap(&u_ctx->lldi.pdev->dev, req);
- if (reqctx->dma_addr)
- dma_unmap_single(&u_ctx->lldi.pdev->dev, reqctx->dma_addr,
- reqctx->dma_len, DMA_TO_DEVICE);
- reqctx->dma_addr = 0;
- updated_digestsize = digestsize;
- if (digestsize == SHA224_DIGEST_SIZE)
- updated_digestsize = SHA256_DIGEST_SIZE;
- else if (digestsize == SHA384_DIGEST_SIZE)
- updated_digestsize = SHA512_DIGEST_SIZE;
- if (reqctx->result == 1) {
- reqctx->result = 0;
- memcpy(req->result, input + sizeof(struct cpl_fw6_pld),
- digestsize);
- } else {
- memcpy(reqctx->partial_hash, input + sizeof(struct cpl_fw6_pld),
- updated_digestsize);
- }
-out:
- req->base.complete(&req->base, err);
-}
-
static inline int get_aead_subtype(struct crypto_aead *aead)
{
struct aead_alg *alg = crypto_aead_alg(aead);
@@ -247,34 +217,6 @@ static inline void chcr_handle_aead_resp(struct aead_request *req,
req->base.complete(&req->base, err);
}
-/*
- * chcr_handle_resp - Unmap the DMA buffers associated with the request
- * @req: crypto request
- */
-int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input,
- int err)
-{
- struct crypto_tfm *tfm = req->tfm;
- struct chcr_context *ctx = crypto_tfm_ctx(tfm);
- struct adapter *adap = padap(ctx->dev);
-
- switch (tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
- case CRYPTO_ALG_TYPE_AEAD:
- chcr_handle_aead_resp(aead_request_cast(req), input, err);
- break;
-
- case CRYPTO_ALG_TYPE_ABLKCIPHER:
- err = chcr_handle_cipher_resp(ablkcipher_request_cast(req),
- input, err);
- break;
-
- case CRYPTO_ALG_TYPE_AHASH:
- chcr_handle_ahash_resp(ahash_request_cast(req), input, err);
- }
- atomic_inc(&adap->chcr_stats.complete);
- return err;
-}
-
static void get_aes_decrypt_key(unsigned char *dec_key,
const unsigned char *key,
unsigned int keylength)
@@ -563,7 +505,6 @@ static void ulptx_walk_add_sg(struct ulptx_walk *walk,
if (!len)
return;
-
while (sg && skip) {
if (sg_dma_len(sg) <= skip) {
skip -= sg_dma_len(sg);
@@ -653,6 +594,35 @@ static int generate_copy_rrkey(struct ablk_ctx *ablkctx,
}
return 0;
}
+
+static int chcr_hash_ent_in_wr(struct scatterlist *src,
+ unsigned int minsg,
+ unsigned int space,
+ unsigned int srcskip)
+{
+ int srclen = 0;
+ int srcsg = minsg;
+ int soffset = 0, sless;
+
+ if (sg_dma_len(src) == srcskip) {
+ src = sg_next(src);
+ srcskip = 0;
+ }
+ while (src && space > (sgl_ent_len[srcsg + 1])) {
+ sless = min_t(unsigned int, sg_dma_len(src) - soffset - srcskip,
+ CHCR_SRC_SG_SIZE);
+ srclen += sless;
+ soffset += sless;
+ srcsg++;
+ if (sg_dma_len(src) == (soffset + srcskip)) {
+ src = sg_next(src);
+ soffset = 0;
+ srcskip = 0;
+ }
+ }
+ return srclen;
+}
+
static int chcr_sg_ent_in_wr(struct scatterlist *src,
struct scatterlist *dst,
unsigned int minsg,
@@ -662,7 +632,7 @@ static int chcr_sg_ent_in_wr(struct scatterlist *src,
{
int srclen = 0, dstlen = 0;
int srcsg = minsg, dstsg = minsg;
- int offset = 0, less;
+ int offset = 0, soffset = 0, less, sless = 0;
if (sg_dma_len(src) == srcskip) {
src = sg_next(src);
@@ -676,7 +646,9 @@ static int chcr_sg_ent_in_wr(struct scatterlist *src,
while (src && dst &&
space > (sgl_ent_len[srcsg + 1] + dsgl_ent_len[dstsg])) {
- srclen += (sg_dma_len(src) - srcskip);
+ sless = min_t(unsigned int, sg_dma_len(src) - srcskip - soffset,
+ CHCR_SRC_SG_SIZE);
+ srclen += sless;
srcsg++;
offset = 0;
while (dst && ((dstsg + 1) <= MAX_DSGL_ENT) &&
@@ -687,15 +659,20 @@ static int chcr_sg_ent_in_wr(struct scatterlist *src,
dstskip, CHCR_DST_SG_SIZE);
dstlen += less;
offset += less;
- if (offset == sg_dma_len(dst)) {
+ if ((offset + dstskip) == sg_dma_len(dst)) {
dst = sg_next(dst);
offset = 0;
}
dstsg++;
dstskip = 0;
}
- src = sg_next(src);
- srcskip = 0;
+ soffset += sless;
+ if ((soffset + srcskip) == sg_dma_len(src)) {
+ src = sg_next(src);
+ srcskip = 0;
+ soffset = 0;
+ }
+
}
return min(srclen, dstlen);
}
@@ -784,14 +761,14 @@ static struct sk_buff *create_cipher_wr(struct cipher_wr_param *wrparam)
nents = sg_nents_xlen(reqctx->dstsg, wrparam->bytes, CHCR_DST_SG_SIZE,
reqctx->dst_ofst);
dst_size = get_space_for_phys_dsgl(nents + 1);
- kctx_len = (DIV_ROUND_UP(ablkctx->enckey_len, 16) * 16);
+ kctx_len = roundup(ablkctx->enckey_len, 16);
transhdr_len = CIPHER_TRANSHDR_SIZE(kctx_len, dst_size);
nents = sg_nents_xlen(reqctx->srcsg, wrparam->bytes,
CHCR_SRC_SG_SIZE, reqctx->src_ofst);
- temp = reqctx->imm ? (DIV_ROUND_UP((IV + wrparam->req->nbytes), 16)
- * 16) : (sgl_len(nents + MIN_CIPHER_SG) * 8);
+ temp = reqctx->imm ? roundup(IV + wrparam->req->nbytes, 16) :
+ (sgl_len(nents + MIN_CIPHER_SG) * 8);
transhdr_len += temp;
- transhdr_len = DIV_ROUND_UP(transhdr_len, 16) * 16;
+ transhdr_len = roundup(transhdr_len, 16);
skb = alloc_skb(SGE_MAX_WR_LEN, flags);
if (!skb) {
error = -ENOMEM;
@@ -847,6 +824,13 @@ static struct sk_buff *create_cipher_wr(struct cipher_wr_param *wrparam)
transhdr_len, temp,
ablkctx->ciph_mode == CHCR_SCMD_CIPHER_MODE_AES_CBC);
reqctx->skb = skb;
+
+ if (reqctx->op && (ablkctx->ciph_mode ==
+ CHCR_SCMD_CIPHER_MODE_AES_CBC))
+ sg_pcopy_to_buffer(wrparam->req->src,
+ sg_nents(wrparam->req->src), wrparam->req->info, 16,
+ reqctx->processed + wrparam->bytes - AES_BLOCK_SIZE);
+
return skb;
err:
return ERR_PTR(error);
@@ -1070,9 +1054,8 @@ static int chcr_update_cipher_iv(struct ablkcipher_request *req,
ret = chcr_update_tweak(req, iv, 0);
else if (subtype == CRYPTO_ALG_SUB_TYPE_CBC) {
if (reqctx->op)
- sg_pcopy_to_buffer(req->src, sg_nents(req->src), iv,
- 16,
- reqctx->processed - AES_BLOCK_SIZE);
+ /*Updated before sending last WR*/
+ memcpy(iv, req->info, AES_BLOCK_SIZE);
else
memcpy(iv, &fw6_pld->data[2], AES_BLOCK_SIZE);
}
@@ -1100,11 +1083,8 @@ static int chcr_final_cipher_iv(struct ablkcipher_request *req,
else if (subtype == CRYPTO_ALG_SUB_TYPE_XTS)
ret = chcr_update_tweak(req, iv, 1);
else if (subtype == CRYPTO_ALG_SUB_TYPE_CBC) {
- if (reqctx->op)
- sg_pcopy_to_buffer(req->src, sg_nents(req->src), iv,
- 16,
- reqctx->processed - AES_BLOCK_SIZE);
- else
+ /*Already updated for Decrypt*/
+ if (!reqctx->op)
memcpy(iv, &fw6_pld->data[2], AES_BLOCK_SIZE);
}
@@ -1143,12 +1123,12 @@ static int chcr_handle_cipher_resp(struct ablkcipher_request *req,
}
if (!reqctx->imm) {
bytes = chcr_sg_ent_in_wr(reqctx->srcsg, reqctx->dstsg, 1,
- SPACE_LEFT(ablkctx->enckey_len),
+ CIP_SPACE_LEFT(ablkctx->enckey_len),
reqctx->src_ofst, reqctx->dst_ofst);
if ((bytes + reqctx->processed) >= req->nbytes)
bytes = req->nbytes - reqctx->processed;
else
- bytes = ROUND_16(bytes);
+ bytes = rounddown(bytes, 16);
} else {
/*CTR mode counter overfloa*/
bytes = req->nbytes - reqctx->processed;
@@ -1234,7 +1214,7 @@ static int process_cipher(struct ablkcipher_request *req,
CHCR_DST_SG_SIZE, 0);
dnents += 1; // IV
phys_dsgl = get_space_for_phys_dsgl(dnents);
- kctx_len = (DIV_ROUND_UP(ablkctx->enckey_len, 16) * 16);
+ kctx_len = roundup(ablkctx->enckey_len, 16);
transhdr_len = CIPHER_TRANSHDR_SIZE(kctx_len, phys_dsgl);
reqctx->imm = (transhdr_len + IV + req->nbytes) <=
SGE_MAX_WR_LEN;
@@ -1247,12 +1227,12 @@ static int process_cipher(struct ablkcipher_request *req,
if (!reqctx->imm) {
bytes = chcr_sg_ent_in_wr(req->src, req->dst,
MIN_CIPHER_SG,
- SPACE_LEFT(ablkctx->enckey_len),
+ CIP_SPACE_LEFT(ablkctx->enckey_len),
0, 0);
if ((bytes + reqctx->processed) >= req->nbytes)
bytes = req->nbytes - reqctx->processed;
else
- bytes = ROUND_16(bytes);
+ bytes = rounddown(bytes, 16);
} else {
bytes = req->nbytes;
}
@@ -1282,7 +1262,7 @@ static int process_cipher(struct ablkcipher_request *req,
req->src,
req->dst,
req->nbytes,
- req->info,
+ reqctx->iv,
op_type);
goto error;
}
@@ -1503,35 +1483,24 @@ static struct sk_buff *create_hash_wr(struct ahash_request *req,
struct uld_ctx *u_ctx = ULD_CTX(h_ctx(tfm));
struct chcr_wr *chcr_req;
struct ulptx_sgl *ulptx;
- unsigned int nents = 0, transhdr_len, iopad_alignment = 0;
- unsigned int digestsize = crypto_ahash_digestsize(tfm);
- unsigned int kctx_len = 0, temp = 0;
- u8 hash_size_in_response = 0;
+ unsigned int nents = 0, transhdr_len;
+ unsigned int temp = 0;
gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
GFP_ATOMIC;
struct adapter *adap = padap(h_ctx(tfm)->dev);
int error = 0;
- iopad_alignment = KEYCTX_ALIGN_PAD(digestsize);
- kctx_len = param->alg_prm.result_size + iopad_alignment;
- if (param->opad_needed)
- kctx_len += param->alg_prm.result_size + iopad_alignment;
-
- if (req_ctx->result)
- hash_size_in_response = digestsize;
- else
- hash_size_in_response = param->alg_prm.result_size;
- transhdr_len = HASH_TRANSHDR_SIZE(kctx_len);
- req_ctx->imm = (transhdr_len + param->bfr_len + param->sg_len) <=
- SGE_MAX_WR_LEN;
- nents = sg_nents_xlen(req->src, param->sg_len, CHCR_SRC_SG_SIZE, 0);
+ transhdr_len = HASH_TRANSHDR_SIZE(param->kctx_len);
+ req_ctx->hctx_wr.imm = (transhdr_len + param->bfr_len +
+ param->sg_len) <= SGE_MAX_WR_LEN;
+ nents = sg_nents_xlen(req_ctx->hctx_wr.srcsg, param->sg_len,
+ CHCR_SRC_SG_SIZE, req_ctx->hctx_wr.src_ofst);
nents += param->bfr_len ? 1 : 0;
- transhdr_len += req_ctx->imm ? (DIV_ROUND_UP((param->bfr_len +
- param->sg_len), 16) * 16) :
- (sgl_len(nents) * 8);
- transhdr_len = DIV_ROUND_UP(transhdr_len, 16) * 16;
+ transhdr_len += req_ctx->hctx_wr.imm ? roundup(param->bfr_len +
+ param->sg_len, 16) : (sgl_len(nents) * 8);
+ transhdr_len = roundup(transhdr_len, 16);
- skb = alloc_skb(SGE_MAX_WR_LEN, flags);
+ skb = alloc_skb(transhdr_len, flags);
if (!skb)
return ERR_PTR(-ENOMEM);
chcr_req = __skb_put_zero(skb, transhdr_len);
@@ -1563,33 +1532,33 @@ static struct sk_buff *create_hash_wr(struct ahash_request *req,
chcr_req->key_ctx.ctx_hdr = FILL_KEY_CTX_HDR(CHCR_KEYCTX_NO_KEY,
param->alg_prm.mk_size, 0,
param->opad_needed,
- ((kctx_len +
+ ((param->kctx_len +
sizeof(chcr_req->key_ctx)) >> 4));
chcr_req->sec_cpl.scmd1 = cpu_to_be64((u64)param->scmd1);
- ulptx = (struct ulptx_sgl *)((u8 *)(chcr_req + 1) + kctx_len +
+ ulptx = (struct ulptx_sgl *)((u8 *)(chcr_req + 1) + param->kctx_len +
DUMMY_BYTES);
if (param->bfr_len != 0) {
- req_ctx->dma_addr = dma_map_single(&u_ctx->lldi.pdev->dev,
- req_ctx->reqbfr, param->bfr_len,
- DMA_TO_DEVICE);
+ req_ctx->hctx_wr.dma_addr =
+ dma_map_single(&u_ctx->lldi.pdev->dev, req_ctx->reqbfr,
+ param->bfr_len, DMA_TO_DEVICE);
if (dma_mapping_error(&u_ctx->lldi.pdev->dev,
- req_ctx->dma_addr)) {
+ req_ctx->hctx_wr. dma_addr)) {
error = -ENOMEM;
goto err;
}
- req_ctx->dma_len = param->bfr_len;
+ req_ctx->hctx_wr.dma_len = param->bfr_len;
} else {
- req_ctx->dma_addr = 0;
+ req_ctx->hctx_wr.dma_addr = 0;
}
chcr_add_hash_src_ent(req, ulptx, param);
/* Request upto max wr size */
- temp = kctx_len + DUMMY_BYTES + (req_ctx->imm ? (param->sg_len
- + param->bfr_len) : 0);
+ temp = param->kctx_len + DUMMY_BYTES + (req_ctx->hctx_wr.imm ?
+ (param->sg_len + param->bfr_len) : 0);
atomic_inc(&adap->chcr_stats.digest_rqst);
- create_wreq(h_ctx(tfm), chcr_req, &req->base, req_ctx->imm,
- hash_size_in_response, transhdr_len,
+ create_wreq(h_ctx(tfm), chcr_req, &req->base, req_ctx->hctx_wr.imm,
+ param->hash_size, transhdr_len,
temp, 0);
- req_ctx->skb = skb;
+ req_ctx->hctx_wr.skb = skb;
return skb;
err:
kfree_skb(skb);
@@ -1608,7 +1577,6 @@ static int chcr_ahash_update(struct ahash_request *req)
int error;
bs = crypto_tfm_alg_blocksize(crypto_ahash_tfm(rtfm));
-
u_ctx = ULD_CTX(h_ctx(rtfm));
if (unlikely(cxgb4_is_crypto_q_full(u_ctx->lldi.ports[0],
h_ctx(rtfm)->tx_qidx))) {
@@ -1625,17 +1593,26 @@ static int chcr_ahash_update(struct ahash_request *req)
req_ctx->reqlen += nbytes;
return 0;
}
+ chcr_init_hctx_per_wr(req_ctx);
error = chcr_hash_dma_map(&u_ctx->lldi.pdev->dev, req);
if (error)
return -ENOMEM;
+ get_alg_config(&params.alg_prm, crypto_ahash_digestsize(rtfm));
+ params.kctx_len = roundup(params.alg_prm.result_size, 16);
+ params.sg_len = chcr_hash_ent_in_wr(req->src, !!req_ctx->reqlen,
+ HASH_SPACE_LEFT(params.kctx_len), 0);
+ if (params.sg_len > req->nbytes)
+ params.sg_len = req->nbytes;
+ params.sg_len = rounddown(params.sg_len + req_ctx->reqlen, bs) -
+ req_ctx->reqlen;
params.opad_needed = 0;
params.more = 1;
params.last = 0;
- params.sg_len = nbytes - req_ctx->reqlen;
params.bfr_len = req_ctx->reqlen;
params.scmd1 = 0;
- get_alg_config(&params.alg_prm, crypto_ahash_digestsize(rtfm));
- req_ctx->result = 0;
+ req_ctx->hctx_wr.srcsg = req->src;
+
+ params.hash_size = params.alg_prm.result_size;
req_ctx->data_len += params.sg_len + params.bfr_len;
skb = create_hash_wr(req, &params);
if (IS_ERR(skb)) {
@@ -1643,6 +1620,7 @@ static int chcr_ahash_update(struct ahash_request *req)
goto unmap;
}
+ req_ctx->hctx_wr.processed += params.sg_len;
if (remainder) {
/* Swap buffers */
swap(req_ctx->reqbfr, req_ctx->skbfr);
@@ -1680,16 +1658,27 @@ static int chcr_ahash_final(struct ahash_request *req)
struct uld_ctx *u_ctx = NULL;
u8 bs = crypto_tfm_alg_blocksize(crypto_ahash_tfm(rtfm));
+ chcr_init_hctx_per_wr(req_ctx);
u_ctx = ULD_CTX(h_ctx(rtfm));
if (is_hmac(crypto_ahash_tfm(rtfm)))
params.opad_needed = 1;
else
params.opad_needed = 0;
params.sg_len = 0;
+ req_ctx->hctx_wr.isfinal = 1;
get_alg_config(&params.alg_prm, crypto_ahash_digestsize(rtfm));
- req_ctx->result = 1;
+ params.kctx_len = roundup(params.alg_prm.result_size, 16);
+ if (is_hmac(crypto_ahash_tfm(rtfm))) {
+ params.opad_needed = 1;
+ params.kctx_len *= 2;
+ } else {
+ params.opad_needed = 0;
+ }
+
+ req_ctx->hctx_wr.result = 1;
params.bfr_len = req_ctx->reqlen;
req_ctx->data_len += params.bfr_len + params.sg_len;
+ req_ctx->hctx_wr.srcsg = req->src;
if (req_ctx->reqlen == 0) {
create_last_hash_block(req_ctx->reqbfr, bs, req_ctx->data_len);
params.last = 0;
@@ -1702,10 +1691,11 @@ static int chcr_ahash_final(struct ahash_request *req)
params.last = 1;
params.more = 0;
}
+ params.hash_size = crypto_ahash_digestsize(rtfm);
skb = create_hash_wr(req, &params);
if (IS_ERR(skb))
return PTR_ERR(skb);
-
+ req_ctx->reqlen = 0;
skb->dev = u_ctx->lldi.ports[0];
set_wr_txq(skb, CPL_PRIORITY_DATA, h_ctx(rtfm)->tx_qidx);
chcr_send_wr(skb);
@@ -1730,37 +1720,59 @@ static int chcr_ahash_finup(struct ahash_request *req)
if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
return -EBUSY;
}
+ chcr_init_hctx_per_wr(req_ctx);
+ error = chcr_hash_dma_map(&u_ctx->lldi.pdev->dev, req);
+ if (error)
+ return -ENOMEM;
- if (is_hmac(crypto_ahash_tfm(rtfm)))
+ get_alg_config(&params.alg_prm, crypto_ahash_digestsize(rtfm));
+ params.kctx_len = roundup(params.alg_prm.result_size, 16);
+ if (is_hmac(crypto_ahash_tfm(rtfm))) {
+ params.kctx_len *= 2;
params.opad_needed = 1;
- else
+ } else {
params.opad_needed = 0;
+ }
- params.sg_len = req->nbytes;
+ params.sg_len = chcr_hash_ent_in_wr(req->src, !!req_ctx->reqlen,
+ HASH_SPACE_LEFT(params.kctx_len), 0);
+ if (params.sg_len < req->nbytes) {
+ if (is_hmac(crypto_ahash_tfm(rtfm))) {
+ params.kctx_len /= 2;
+ params.opad_needed = 0;
+ }
+ params.last = 0;
+ params.more = 1;
+ params.sg_len = rounddown(params.sg_len + req_ctx->reqlen, bs)
+ - req_ctx->reqlen;
+ params.hash_size = params.alg_prm.result_size;
+ params.scmd1 = 0;
+ } else {
+ params.last = 1;
+ params.more = 0;
+ params.sg_len = req->nbytes;
+ params.hash_size = crypto_ahash_digestsize(rtfm);
+ params.scmd1 = req_ctx->data_len + req_ctx->reqlen +
+ params.sg_len;
+ }
params.bfr_len = req_ctx->reqlen;
- get_alg_config(&params.alg_prm, crypto_ahash_digestsize(rtfm));
req_ctx->data_len += params.bfr_len + params.sg_len;
- req_ctx->result = 1;
+ req_ctx->hctx_wr.result = 1;
+ req_ctx->hctx_wr.srcsg = req->src;
if ((req_ctx->reqlen + req->nbytes) == 0) {
create_last_hash_block(req_ctx->reqbfr, bs, req_ctx->data_len);
params.last = 0;
params.more = 1;
params.scmd1 = 0;
params.bfr_len = bs;
- } else {
- params.scmd1 = req_ctx->data_len;
- params.last = 1;
- params.more = 0;
}
- error = chcr_hash_dma_map(&u_ctx->lldi.pdev->dev, req);
- if (error)
- return -ENOMEM;
-
skb = create_hash_wr(req, &params);
if (IS_ERR(skb)) {
error = PTR_ERR(skb);
goto unmap;
}
+ req_ctx->reqlen = 0;
+ req_ctx->hctx_wr.processed += params.sg_len;
skb->dev = u_ctx->lldi.ports[0];
set_wr_txq(skb, CPL_PRIORITY_DATA, h_ctx(rtfm)->tx_qidx);
chcr_send_wr(skb);
@@ -1791,21 +1803,42 @@ static int chcr_ahash_digest(struct ahash_request *req)
return -EBUSY;
}
- if (is_hmac(crypto_ahash_tfm(rtfm)))
- params.opad_needed = 1;
- else
- params.opad_needed = 0;
+ chcr_init_hctx_per_wr(req_ctx);
error = chcr_hash_dma_map(&u_ctx->lldi.pdev->dev, req);
if (error)
return -ENOMEM;
- params.last = 0;
- params.more = 0;
- params.sg_len = req->nbytes;
- params.bfr_len = 0;
- params.scmd1 = 0;
get_alg_config(&params.alg_prm, crypto_ahash_digestsize(rtfm));
- req_ctx->result = 1;
+ params.kctx_len = roundup(params.alg_prm.result_size, 16);
+ if (is_hmac(crypto_ahash_tfm(rtfm))) {
+ params.kctx_len *= 2;
+ params.opad_needed = 1;
+ } else {
+ params.opad_needed = 0;
+ }
+ params.sg_len = chcr_hash_ent_in_wr(req->src, !!req_ctx->reqlen,
+ HASH_SPACE_LEFT(params.kctx_len), 0);
+ if (params.sg_len < req->nbytes) {
+ if (is_hmac(crypto_ahash_tfm(rtfm))) {
+ params.kctx_len /= 2;
+ params.opad_needed = 0;
+ }
+ params.last = 0;
+ params.more = 1;
+ params.scmd1 = 0;
+ params.sg_len = rounddown(params.sg_len, bs);
+ params.hash_size = params.alg_prm.result_size;
+ } else {
+ params.sg_len = req->nbytes;
+ params.hash_size = crypto_ahash_digestsize(rtfm);
+ params.last = 1;
+ params.more = 0;
+ params.scmd1 = req->nbytes + req_ctx->data_len;
+
+ }
+ params.bfr_len = 0;
+ req_ctx->hctx_wr.result = 1;
+ req_ctx->hctx_wr.srcsg = req->src;
req_ctx->data_len += params.bfr_len + params.sg_len;
if (req->nbytes == 0) {
@@ -1819,6 +1852,7 @@ static int chcr_ahash_digest(struct ahash_request *req)
error = PTR_ERR(skb);
goto unmap;
}
+ req_ctx->hctx_wr.processed += params.sg_len;
skb->dev = u_ctx->lldi.ports[0];
set_wr_txq(skb, CPL_PRIORITY_DATA, h_ctx(rtfm)->tx_qidx);
chcr_send_wr(skb);
@@ -1828,6 +1862,151 @@ unmap:
return error;
}
+static int chcr_ahash_continue(struct ahash_request *req)
+{
+ struct chcr_ahash_req_ctx *reqctx = ahash_request_ctx(req);
+ struct chcr_hctx_per_wr *hctx_wr = &reqctx->hctx_wr;
+ struct crypto_ahash *rtfm = crypto_ahash_reqtfm(req);
+ struct uld_ctx *u_ctx = NULL;
+ struct sk_buff *skb;
+ struct hash_wr_param params;
+ u8 bs;
+ int error;
+
+ bs = crypto_tfm_alg_blocksize(crypto_ahash_tfm(rtfm));
+ u_ctx = ULD_CTX(h_ctx(rtfm));
+ if (unlikely(cxgb4_is_crypto_q_full(u_ctx->lldi.ports[0],
+ h_ctx(rtfm)->tx_qidx))) {
+ if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
+ return -EBUSY;
+ }
+ get_alg_config(&params.alg_prm, crypto_ahash_digestsize(rtfm));
+ params.kctx_len = roundup(params.alg_prm.result_size, 16);
+ if (is_hmac(crypto_ahash_tfm(rtfm))) {
+ params.kctx_len *= 2;
+ params.opad_needed = 1;
+ } else {
+ params.opad_needed = 0;
+ }
+ params.sg_len = chcr_hash_ent_in_wr(hctx_wr->srcsg, 0,
+ HASH_SPACE_LEFT(params.kctx_len),
+ hctx_wr->src_ofst);
+ if ((params.sg_len + hctx_wr->processed) > req->nbytes)
+ params.sg_len = req->nbytes - hctx_wr->processed;
+ if (!hctx_wr->result ||
+ ((params.sg_len + hctx_wr->processed) < req->nbytes)) {
+ if (is_hmac(crypto_ahash_tfm(rtfm))) {
+ params.kctx_len /= 2;
+ params.opad_needed = 0;
+ }
+ params.last = 0;
+ params.more = 1;
+ params.sg_len = rounddown(params.sg_len, bs);
+ params.hash_size = params.alg_prm.result_size;
+ params.scmd1 = 0;
+ } else {
+ params.last = 1;
+ params.more = 0;
+ params.hash_size = crypto_ahash_digestsize(rtfm);
+ params.scmd1 = reqctx->data_len + params.sg_len;
+ }
+ params.bfr_len = 0;
+ reqctx->data_len += params.sg_len;
+ skb = create_hash_wr(req, &params);
+ if (IS_ERR(skb)) {
+ error = PTR_ERR(skb);
+ goto err;
+ }
+ hctx_wr->processed += params.sg_len;
+ skb->dev = u_ctx->lldi.ports[0];
+ set_wr_txq(skb, CPL_PRIORITY_DATA, h_ctx(rtfm)->tx_qidx);
+ chcr_send_wr(skb);
+ return 0;
+err:
+ return error;
+}
+
+static inline void chcr_handle_ahash_resp(struct ahash_request *req,
+ unsigned char *input,
+ int err)
+{
+ struct chcr_ahash_req_ctx *reqctx = ahash_request_ctx(req);
+ struct chcr_hctx_per_wr *hctx_wr = &reqctx->hctx_wr;
+ int digestsize, updated_digestsize;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct uld_ctx *u_ctx = ULD_CTX(h_ctx(tfm));
+
+ if (input == NULL)
+ goto out;
+ digestsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(req));
+ updated_digestsize = digestsize;
+ if (digestsize == SHA224_DIGEST_SIZE)
+ updated_digestsize = SHA256_DIGEST_SIZE;
+ else if (digestsize == SHA384_DIGEST_SIZE)
+ updated_digestsize = SHA512_DIGEST_SIZE;
+
+ if (hctx_wr->dma_addr) {
+ dma_unmap_single(&u_ctx->lldi.pdev->dev, hctx_wr->dma_addr,
+ hctx_wr->dma_len, DMA_TO_DEVICE);
+ hctx_wr->dma_addr = 0;
+ }
+ if (hctx_wr->isfinal || ((hctx_wr->processed + reqctx->reqlen) ==
+ req->nbytes)) {
+ if (hctx_wr->result == 1) {
+ hctx_wr->result = 0;
+ memcpy(req->result, input + sizeof(struct cpl_fw6_pld),
+ digestsize);
+ } else {
+ memcpy(reqctx->partial_hash,
+ input + sizeof(struct cpl_fw6_pld),
+ updated_digestsize);
+
+ }
+ goto unmap;
+ }
+ memcpy(reqctx->partial_hash, input + sizeof(struct cpl_fw6_pld),
+ updated_digestsize);
+
+ err = chcr_ahash_continue(req);
+ if (err)
+ goto unmap;
+ return;
+unmap:
+ if (hctx_wr->is_sg_map)
+ chcr_hash_dma_unmap(&u_ctx->lldi.pdev->dev, req);
+
+
+out:
+ req->base.complete(&req->base, err);
+}
+
+/*
+ * chcr_handle_resp - Unmap the DMA buffers associated with the request
+ * @req: crypto request
+ */
+int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input,
+ int err)
+{
+ struct crypto_tfm *tfm = req->tfm;
+ struct chcr_context *ctx = crypto_tfm_ctx(tfm);
+ struct adapter *adap = padap(ctx->dev);
+
+ switch (tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
+ case CRYPTO_ALG_TYPE_AEAD:
+ chcr_handle_aead_resp(aead_request_cast(req), input, err);
+ break;
+
+ case CRYPTO_ALG_TYPE_ABLKCIPHER:
+ err = chcr_handle_cipher_resp(ablkcipher_request_cast(req),
+ input, err);
+ break;
+
+ case CRYPTO_ALG_TYPE_AHASH:
+ chcr_handle_ahash_resp(ahash_request_cast(req), input, err);
+ }
+ atomic_inc(&adap->chcr_stats.complete);
+ return err;
+}
static int chcr_ahash_export(struct ahash_request *areq, void *out)
{
struct chcr_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
@@ -1835,11 +2014,10 @@ static int chcr_ahash_export(struct ahash_request *areq, void *out)
state->reqlen = req_ctx->reqlen;
state->data_len = req_ctx->data_len;
- state->is_sg_map = 0;
- state->result = 0;
memcpy(state->bfr1, req_ctx->reqbfr, req_ctx->reqlen);
memcpy(state->partial_hash, req_ctx->partial_hash,
CHCR_HASH_MAX_DIGEST_SIZE);
+ chcr_init_hctx_per_wr(state);
return 0;
}
@@ -1852,11 +2030,10 @@ static int chcr_ahash_import(struct ahash_request *areq, const void *in)
req_ctx->data_len = state->data_len;
req_ctx->reqbfr = req_ctx->bfr1;
req_ctx->skbfr = req_ctx->bfr2;
- req_ctx->is_sg_map = 0;
- req_ctx->result = 0;
memcpy(req_ctx->bfr1, state->bfr1, CHCR_HASH_MAX_BLOCK_SIZE_128);
memcpy(req_ctx->partial_hash, state->partial_hash,
CHCR_HASH_MAX_DIGEST_SIZE);
+ chcr_init_hctx_per_wr(req_ctx);
return 0;
}
@@ -1953,10 +2130,8 @@ static int chcr_sha_init(struct ahash_request *areq)
req_ctx->reqlen = 0;
req_ctx->reqbfr = req_ctx->bfr1;
req_ctx->skbfr = req_ctx->bfr2;
- req_ctx->skb = NULL;
- req_ctx->result = 0;
- req_ctx->is_sg_map = 0;
copy_hash_init_values(req_ctx->partial_hash, digestsize);
+
return 0;
}
@@ -2124,11 +2299,11 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req,
transhdr_len = CIPHER_TRANSHDR_SIZE(kctx_len, dst_size);
reqctx->imm = (transhdr_len + assoclen + IV + req->cryptlen) <
SGE_MAX_WR_LEN;
- temp = reqctx->imm ? (DIV_ROUND_UP((assoclen + IV + req->cryptlen), 16)
- * 16) : (sgl_len(reqctx->src_nents + reqctx->aad_nents
+ temp = reqctx->imm ? roundup(assoclen + IV + req->cryptlen, 16)
+ : (sgl_len(reqctx->src_nents + reqctx->aad_nents
+ MIN_GCM_SG) * 8);
transhdr_len += temp;
- transhdr_len = DIV_ROUND_UP(transhdr_len, 16) * 16;
+ transhdr_len = roundup(transhdr_len, 16);
if (chcr_aead_need_fallback(req, dnents, T6_MAX_AAD_SIZE,
transhdr_len, op_type)) {
@@ -2187,9 +2362,8 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req,
memcpy(chcr_req->key_ctx.key, actx->dec_rrkey,
aeadctx->enckey_len);
- memcpy(chcr_req->key_ctx.key + (DIV_ROUND_UP(aeadctx->enckey_len, 16) <<
- 4), actx->h_iopad, kctx_len -
- (DIV_ROUND_UP(aeadctx->enckey_len, 16) << 4));
+ memcpy(chcr_req->key_ctx.key + roundup(aeadctx->enckey_len, 16),
+ actx->h_iopad, kctx_len - roundup(aeadctx->enckey_len, 16));
if (subtype == CRYPTO_ALG_SUB_TYPE_CTR_SHA ||
subtype == CRYPTO_ALG_SUB_TYPE_CTR_NULL) {
memcpy(reqctx->iv, aeadctx->nonce, CTR_RFC3686_NONCE_SIZE);
@@ -2398,22 +2572,26 @@ void chcr_add_hash_src_ent(struct ahash_request *req,
struct ulptx_walk ulp_walk;
struct chcr_ahash_req_ctx *reqctx = ahash_request_ctx(req);
- if (reqctx->imm) {
+ if (reqctx->hctx_wr.imm) {
u8 *buf = (u8 *)ulptx;
if (param->bfr_len) {
memcpy(buf, reqctx->reqbfr, param->bfr_len);
buf += param->bfr_len;
}
- sg_pcopy_to_buffer(req->src, sg_nents(req->src),
- buf, param->sg_len, 0);
+
+ sg_pcopy_to_buffer(reqctx->hctx_wr.srcsg,
+ sg_nents(reqctx->hctx_wr.srcsg), buf,
+ param->sg_len, 0);
} else {
ulptx_walk_init(&ulp_walk, ulptx);
if (param->bfr_len)
ulptx_walk_add_page(&ulp_walk, param->bfr_len,
- &reqctx->dma_addr);
- ulptx_walk_add_sg(&ulp_walk, req->src, param->sg_len,
- 0);
+ &reqctx->hctx_wr.dma_addr);
+ ulptx_walk_add_sg(&ulp_walk, reqctx->hctx_wr.srcsg,
+ param->sg_len, reqctx->hctx_wr.src_ofst);
+ reqctx->hctx_wr.srcsg = ulp_walk.last_sg;
+ reqctx->hctx_wr.src_ofst = ulp_walk.last_sg_len;
ulptx_walk_end(&ulp_walk);
}
}
@@ -2430,7 +2608,7 @@ int chcr_hash_dma_map(struct device *dev,
DMA_TO_DEVICE);
if (!error)
return -ENOMEM;
- req_ctx->is_sg_map = 1;
+ req_ctx->hctx_wr.is_sg_map = 1;
return 0;
}
@@ -2444,7 +2622,7 @@ void chcr_hash_dma_unmap(struct device *dev,
dma_unmap_sg(dev, req->src, sg_nents(req->src),
DMA_TO_DEVICE);
- req_ctx->is_sg_map = 0;
+ req_ctx->hctx_wr.is_sg_map = 0;
}
@@ -2636,10 +2814,10 @@ static void fill_sec_cpl_for_aead(struct cpl_tx_sec_pdu *sec_cpl,
0, dst_size);
}
-int aead_ccm_validate_input(unsigned short op_type,
- struct aead_request *req,
- struct chcr_aead_ctx *aeadctx,
- unsigned int sub_type)
+static int aead_ccm_validate_input(unsigned short op_type,
+ struct aead_request *req,
+ struct chcr_aead_ctx *aeadctx,
+ unsigned int sub_type)
{
if (sub_type != CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309) {
if (crypto_ccm_check_iv(req->iv)) {
@@ -2696,16 +2874,16 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req,
CHCR_DST_SG_SIZE, req->assoclen);
dnents += MIN_CCM_SG; // For IV and B0
dst_size = get_space_for_phys_dsgl(dnents);
- kctx_len = ((DIV_ROUND_UP(aeadctx->enckey_len, 16)) << 4) * 2;
+ kctx_len = roundup(aeadctx->enckey_len, 16) * 2;
transhdr_len = CIPHER_TRANSHDR_SIZE(kctx_len, dst_size);
reqctx->imm = (transhdr_len + assoclen + IV + req->cryptlen +
reqctx->b0_len) <= SGE_MAX_WR_LEN;
- temp = reqctx->imm ? (DIV_ROUND_UP((assoclen + IV + req->cryptlen +
- reqctx->b0_len), 16) * 16) :
+ temp = reqctx->imm ? roundup(assoclen + IV + req->cryptlen +
+ reqctx->b0_len, 16) :
(sgl_len(reqctx->src_nents + reqctx->aad_nents +
MIN_CCM_SG) * 8);
transhdr_len += temp;
- transhdr_len = DIV_ROUND_UP(transhdr_len, 16) * 16;
+ transhdr_len = roundup(transhdr_len, 16);
if (chcr_aead_need_fallback(req, dnents, T6_MAX_AAD_SIZE -
reqctx->b0_len, transhdr_len, op_type)) {
@@ -2727,8 +2905,8 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req,
chcr_req->key_ctx.ctx_hdr = aeadctx->key_ctx_hdr;
memcpy(chcr_req->key_ctx.key, aeadctx->key, aeadctx->enckey_len);
- memcpy(chcr_req->key_ctx.key + (DIV_ROUND_UP(aeadctx->enckey_len, 16) *
- 16), aeadctx->key, aeadctx->enckey_len);
+ memcpy(chcr_req->key_ctx.key + roundup(aeadctx->enckey_len, 16),
+ aeadctx->key, aeadctx->enckey_len);
phys_cpl = (struct cpl_rx_phys_dsgl *)((u8 *)(chcr_req + 1) + kctx_len);
ulptx = (struct ulptx_sgl *)((u8 *)(phys_cpl + 1) + dst_size);
@@ -2798,16 +2976,15 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req,
CHCR_DST_SG_SIZE, req->assoclen);
dnents += MIN_GCM_SG; // For IV
dst_size = get_space_for_phys_dsgl(dnents);
- kctx_len = ((DIV_ROUND_UP(aeadctx->enckey_len, 16)) << 4) +
- AEAD_H_SIZE;
+ kctx_len = roundup(aeadctx->enckey_len, 16) + AEAD_H_SIZE;
transhdr_len = CIPHER_TRANSHDR_SIZE(kctx_len, dst_size);
reqctx->imm = (transhdr_len + assoclen + IV + req->cryptlen) <=
SGE_MAX_WR_LEN;
- temp = reqctx->imm ? (DIV_ROUND_UP((assoclen + IV +
- req->cryptlen), 16) * 16) : (sgl_len(reqctx->src_nents +
- reqctx->aad_nents + MIN_GCM_SG) * 8);
+ temp = reqctx->imm ? roundup(assoclen + IV + req->cryptlen, 16) :
+ (sgl_len(reqctx->src_nents +
+ reqctx->aad_nents + MIN_GCM_SG) * 8);
transhdr_len += temp;
- transhdr_len = DIV_ROUND_UP(transhdr_len, 16) * 16;
+ transhdr_len = roundup(transhdr_len, 16);
if (chcr_aead_need_fallback(req, dnents, T6_MAX_AAD_SIZE,
transhdr_len, op_type)) {
atomic_inc(&adap->chcr_stats.fallback);
@@ -2846,8 +3023,8 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req,
0, 0, dst_size);
chcr_req->key_ctx.ctx_hdr = aeadctx->key_ctx_hdr;
memcpy(chcr_req->key_ctx.key, aeadctx->key, aeadctx->enckey_len);
- memcpy(chcr_req->key_ctx.key + (DIV_ROUND_UP(aeadctx->enckey_len, 16) *
- 16), GCM_CTX(aeadctx)->ghash_h, AEAD_H_SIZE);
+ memcpy(chcr_req->key_ctx.key + roundup(aeadctx->enckey_len, 16),
+ GCM_CTX(aeadctx)->ghash_h, AEAD_H_SIZE);
/* prepare a 16 byte iv */
/* S A L T | IV | 0x00000001 */
@@ -3067,11 +3244,10 @@ static int chcr_ccm_common_setkey(struct crypto_aead *aead,
unsigned char ck_size, mk_size;
int key_ctx_size = 0;
- key_ctx_size = sizeof(struct _key_ctx) +
- ((DIV_ROUND_UP(keylen, 16)) << 4) * 2;
+ key_ctx_size = sizeof(struct _key_ctx) + roundup(keylen, 16) * 2;
if (keylen == AES_KEYSIZE_128) {
- mk_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_128;
ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_128;
+ mk_size = CHCR_KEYCTX_MAC_KEY_SIZE_128;
} else if (keylen == AES_KEYSIZE_192) {
ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_192;
mk_size = CHCR_KEYCTX_MAC_KEY_SIZE_192;
@@ -3178,10 +3354,9 @@ static int chcr_gcm_setkey(struct crypto_aead *aead, const u8 *key,
memcpy(aeadctx->key, key, keylen);
aeadctx->enckey_len = keylen;
- key_ctx_size = sizeof(struct _key_ctx) +
- ((DIV_ROUND_UP(keylen, 16)) << 4) +
+ key_ctx_size = sizeof(struct _key_ctx) + roundup(keylen, 16) +
AEAD_H_SIZE;
- aeadctx->key_ctx_hdr = FILL_KEY_CTX_HDR(ck_size,
+ aeadctx->key_ctx_hdr = FILL_KEY_CTX_HDR(ck_size,
CHCR_KEYCTX_MAC_KEY_SIZE_128,
0, 0,
key_ctx_size >> 4);
@@ -3281,6 +3456,7 @@ static int chcr_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
if (IS_ERR(base_hash)) {
pr_err("chcr : Base driver cannot be loaded\n");
aeadctx->enckey_len = 0;
+ memzero_explicit(&keys, sizeof(keys));
return -EINVAL;
}
{
@@ -3325,17 +3501,19 @@ static int chcr_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
chcr_change_order(actx->h_iopad, param.result_size);
chcr_change_order(o_ptr, param.result_size);
key_ctx_len = sizeof(struct _key_ctx) +
- ((DIV_ROUND_UP(keys.enckeylen, 16)) << 4) +
+ roundup(keys.enckeylen, 16) +
(param.result_size + align) * 2;
aeadctx->key_ctx_hdr = FILL_KEY_CTX_HDR(ck_size, param.mk_size,
0, 1, key_ctx_len >> 4);
actx->auth_mode = param.auth_mode;
chcr_free_shash(base_hash);
+ memzero_explicit(&keys, sizeof(keys));
return 0;
}
out:
aeadctx->enckey_len = 0;
+ memzero_explicit(&keys, sizeof(keys));
if (!IS_ERR(base_hash))
chcr_free_shash(base_hash);
return -EINVAL;
@@ -3393,15 +3571,16 @@ static int chcr_aead_digest_null_setkey(struct crypto_aead *authenc,
get_aes_decrypt_key(actx->dec_rrkey, aeadctx->key,
aeadctx->enckey_len << 3);
}
- key_ctx_len = sizeof(struct _key_ctx)
- + ((DIV_ROUND_UP(keys.enckeylen, 16)) << 4);
+ key_ctx_len = sizeof(struct _key_ctx) + roundup(keys.enckeylen, 16);
aeadctx->key_ctx_hdr = FILL_KEY_CTX_HDR(ck_size, CHCR_KEYCTX_NO_KEY, 0,
0, key_ctx_len >> 4);
actx->auth_mode = CHCR_SCMD_AUTH_MODE_NOP;
+ memzero_explicit(&keys, sizeof(keys));
return 0;
out:
aeadctx->enckey_len = 0;
+ memzero_explicit(&keys, sizeof(keys));
return -EINVAL;
}
diff --git a/drivers/crypto/chelsio/chcr_algo.h b/drivers/crypto/chelsio/chcr_algo.h
index f263cd42a84f..dba3dff1e209 100644
--- a/drivers/crypto/chelsio/chcr_algo.h
+++ b/drivers/crypto/chelsio/chcr_algo.h
@@ -258,15 +258,16 @@
#define FILL_CMD_MORE(immdatalen) htonl(ULPTX_CMD_V(ULP_TX_SC_IMM) |\
ULP_TX_SC_MORE_V((immdatalen)))
#define MAX_NK 8
-#define ROUND_16(bytes) ((bytes) & 0xFFFFFFF0)
#define MAX_DSGL_ENT 32
#define MIN_CIPHER_SG 1 /* IV */
#define MIN_AUTH_SG 1 /* IV */
#define MIN_GCM_SG 1 /* IV */
#define MIN_DIGEST_SG 1 /*Partial Buffer*/
#define MIN_CCM_SG 2 /*IV+B0*/
-#define SPACE_LEFT(len) \
- ((SGE_MAX_WR_LEN - WR_MIN_LEN - (len)))
+#define CIP_SPACE_LEFT(len) \
+ ((SGE_MAX_WR_LEN - CIP_WR_MIN_LEN - (len)))
+#define HASH_SPACE_LEFT(len) \
+ ((SGE_MAX_WR_LEN - HASH_WR_MIN_LEN - (len)))
struct algo_param {
unsigned int auth_mode;
@@ -275,12 +276,14 @@ struct algo_param {
};
struct hash_wr_param {
+ struct algo_param alg_prm;
unsigned int opad_needed;
unsigned int more;
unsigned int last;
- struct algo_param alg_prm;
+ unsigned int kctx_len;
unsigned int sg_len;
unsigned int bfr_len;
+ unsigned int hash_size;
u64 scmd1;
};
diff --git a/drivers/crypto/chelsio/chcr_core.h b/drivers/crypto/chelsio/chcr_core.h
index 77056a90c8e1..1a20424e18c6 100644
--- a/drivers/crypto/chelsio/chcr_core.h
+++ b/drivers/crypto/chelsio/chcr_core.h
@@ -54,10 +54,14 @@
#define MAC_ERROR_BIT 0
#define CHK_MAC_ERR_BIT(x) (((x) >> MAC_ERROR_BIT) & 1)
#define MAX_SALT 4
-#define WR_MIN_LEN (sizeof(struct chcr_wr) + \
+#define CIP_WR_MIN_LEN (sizeof(struct chcr_wr) + \
sizeof(struct cpl_rx_phys_dsgl) + \
sizeof(struct ulptx_sgl))
+#define HASH_WR_MIN_LEN (sizeof(struct chcr_wr) + \
+ DUMMY_BYTES + \
+ sizeof(struct ulptx_sgl))
+
#define padap(dev) pci_get_drvdata(dev->u_ctx->lldi.pdev)
struct uld_ctx;
diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h
index 7daf0a17a7d2..c8e8972af283 100644
--- a/drivers/crypto/chelsio/chcr_crypto.h
+++ b/drivers/crypto/chelsio/chcr_crypto.h
@@ -258,21 +258,32 @@ struct chcr_context {
struct __crypto_ctx crypto_ctx[0];
};
-struct chcr_ahash_req_ctx {
+struct chcr_hctx_per_wr {
+ struct scatterlist *srcsg;
+ struct sk_buff *skb;
+ dma_addr_t dma_addr;
+ u32 dma_len;
+ unsigned int src_ofst;
+ unsigned int processed;
u32 result;
- u8 bfr1[CHCR_HASH_MAX_BLOCK_SIZE_128];
- u8 bfr2[CHCR_HASH_MAX_BLOCK_SIZE_128];
+ u8 is_sg_map;
+ u8 imm;
+ /*Final callback called. Driver cannot rely on nbytes to decide
+ * final call
+ */
+ u8 isfinal;
+};
+
+struct chcr_ahash_req_ctx {
+ struct chcr_hctx_per_wr hctx_wr;
u8 *reqbfr;
u8 *skbfr;
- dma_addr_t dma_addr;
- u32 dma_len;
+ /* SKB which is being sent to the hardware for processing */
+ u64 data_len; /* Data len till time */
u8 reqlen;
- u8 imm;
- u8 is_sg_map;
u8 partial_hash[CHCR_HASH_MAX_DIGEST_SIZE];
- u64 data_len; /* Data len till time */
- /* SKB which is being sent to the hardware for processing */
- struct sk_buff *skb;
+ u8 bfr1[CHCR_HASH_MAX_BLOCK_SIZE_128];
+ u8 bfr2[CHCR_HASH_MAX_BLOCK_SIZE_128];
};
struct chcr_blkcipher_req_ctx {
diff --git a/drivers/crypto/chelsio/chcr_ipsec.c b/drivers/crypto/chelsio/chcr_ipsec.c
index db1e241104ed..8e0aa3f175c9 100644
--- a/drivers/crypto/chelsio/chcr_ipsec.c
+++ b/drivers/crypto/chelsio/chcr_ipsec.c
@@ -360,8 +360,7 @@ inline void *copy_cpltx_pktxt(struct sk_buff *skb,
cpl = (struct cpl_tx_pkt_core *)pos;
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- cntrl = TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F;
+ cntrl = TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F;
ctrl0 = TXPKT_OPCODE_V(CPL_TX_PKT_XT) | TXPKT_INTF_V(pi->tx_chan) |
TXPKT_PF_V(adap->pf);
if (skb_vlan_tag_present(skb)) {
@@ -475,7 +474,7 @@ inline void *chcr_crypto_wreq(struct sk_buff *skb,
wr->req.ulptx.len = htonl(DIV_ROUND_UP(flits, 2) - 1);
/* Sub-command */
- wr->req.sc_imm.cmd_more = FILL_CMD_MORE(immdatalen);
+ wr->req.sc_imm.cmd_more = FILL_CMD_MORE(!immdatalen);
wr->req.sc_imm.len = cpu_to_be32(sizeof(struct cpl_tx_sec_pdu) +
sizeof(wr->req.key_ctx) +
kctx_len +
diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c
index 225e74a7f724..d4a81be0d7d2 100644
--- a/drivers/crypto/inside-secure/safexcel.c
+++ b/drivers/crypto/inside-secure/safexcel.c
@@ -235,7 +235,7 @@ static int safexcel_hw_setup_rdesc_rings(struct safexcel_crypto_priv *priv)
/* Configure DMA tx control */
val = EIP197_HIA_xDR_CFG_WR_CACHE(WR_CACHE_3BITS);
val |= EIP197_HIA_xDR_CFG_RD_CACHE(RD_CACHE_3BITS);
- val |= EIP197_HIA_xDR_WR_RES_BUF | EIP197_HIA_xDR_WR_CTRL_BUG;
+ val |= EIP197_HIA_xDR_WR_RES_BUF | EIP197_HIA_xDR_WR_CTRL_BUF;
writel(val,
EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_DMA_CFG);
@@ -332,7 +332,7 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv)
val = EIP197_HIA_DSE_CFG_DIS_DEBUG;
val |= EIP197_HIA_DxE_CFG_MIN_DATA_SIZE(7) | EIP197_HIA_DxE_CFG_MAX_DATA_SIZE(8);
val |= EIP197_HIA_DxE_CFG_DATA_CACHE_CTRL(WR_CACHE_3BITS);
- val |= EIP197_HIA_DSE_CFG_ALLWAYS_BUFFERABLE;
+ val |= EIP197_HIA_DSE_CFG_ALWAYS_BUFFERABLE;
/* FIXME: instability issues can occur for EIP97 but disabling it impact
* performances.
*/
@@ -354,7 +354,7 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv)
val |= EIP197_PROTOCOL_ENCRYPT_ONLY | EIP197_PROTOCOL_HASH_ONLY;
val |= EIP197_ALG_AES_ECB | EIP197_ALG_AES_CBC;
val |= EIP197_ALG_SHA1 | EIP197_ALG_HMAC_SHA1;
- val |= EIP197_ALG_SHA2;
+ val |= EIP197_ALG_SHA2 | EIP197_ALG_HMAC_SHA2;
writel(val, EIP197_PE(priv) + EIP197_PE_EIP96_FUNCTION_EN);
/* Command Descriptor Rings prepare */
@@ -432,20 +432,18 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv)
}
/* Called with ring's lock taken */
-static int safexcel_try_push_requests(struct safexcel_crypto_priv *priv,
- int ring, int reqs)
+static void safexcel_try_push_requests(struct safexcel_crypto_priv *priv,
+ int ring)
{
- int coal = min_t(int, reqs, EIP197_MAX_BATCH_SZ);
+ int coal = min_t(int, priv->ring[ring].requests, EIP197_MAX_BATCH_SZ);
if (!coal)
- return 0;
+ return;
/* Configure when we want an interrupt */
writel(EIP197_HIA_RDR_THRESH_PKT_MODE |
EIP197_HIA_RDR_THRESH_PROC_PKT(coal),
EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_THRESH);
-
- return coal;
}
void safexcel_dequeue(struct safexcel_crypto_priv *priv, int ring)
@@ -490,6 +488,15 @@ handle_req:
if (backlog)
backlog->complete(backlog, -EINPROGRESS);
+ /* In case the send() helper did not issue any command to push
+ * to the engine because the input data was cached, continue to
+ * dequeue other requests as this is valid and not an error.
+ */
+ if (!commands && !results) {
+ kfree(request);
+ continue;
+ }
+
spin_lock_bh(&priv->ring[ring].egress_lock);
list_add_tail(&request->list, &priv->ring[ring].list);
spin_unlock_bh(&priv->ring[ring].egress_lock);
@@ -512,14 +519,13 @@ finalize:
spin_lock_bh(&priv->ring[ring].egress_lock);
+ priv->ring[ring].requests += nreq;
+
if (!priv->ring[ring].busy) {
- nreq -= safexcel_try_push_requests(priv, ring, nreq);
- if (nreq)
- priv->ring[ring].busy = true;
+ safexcel_try_push_requests(priv, ring);
+ priv->ring[ring].busy = true;
}
- priv->ring[ring].requests_left += nreq;
-
spin_unlock_bh(&priv->ring[ring].egress_lock);
/* let the RDR know we have pending descriptors */
@@ -531,25 +537,6 @@ finalize:
EIP197_HIA_CDR(priv, ring) + EIP197_HIA_xDR_PREP_COUNT);
}
-void safexcel_free_context(struct safexcel_crypto_priv *priv,
- struct crypto_async_request *req,
- int result_sz)
-{
- struct safexcel_context *ctx = crypto_tfm_ctx(req->tfm);
-
- if (ctx->result_dma)
- dma_unmap_single(priv->dev, ctx->result_dma, result_sz,
- DMA_FROM_DEVICE);
-
- if (ctx->cache) {
- dma_unmap_single(priv->dev, ctx->cache_dma, ctx->cache_sz,
- DMA_TO_DEVICE);
- kfree(ctx->cache);
- ctx->cache = NULL;
- ctx->cache_sz = 0;
- }
-}
-
void safexcel_complete(struct safexcel_crypto_priv *priv, int ring)
{
struct safexcel_command_desc *cdesc;
@@ -623,7 +610,7 @@ static inline void safexcel_handle_result_descriptor(struct safexcel_crypto_priv
{
struct safexcel_request *sreq;
struct safexcel_context *ctx;
- int ret, i, nreq, ndesc, tot_descs, done;
+ int ret, i, nreq, ndesc, tot_descs, handled = 0;
bool should_complete;
handle_results:
@@ -659,6 +646,7 @@ handle_results:
kfree(sreq);
tot_descs += ndesc;
+ handled++;
}
acknowledge:
@@ -677,11 +665,10 @@ acknowledge:
requests_left:
spin_lock_bh(&priv->ring[ring].egress_lock);
- done = safexcel_try_push_requests(priv, ring,
- priv->ring[ring].requests_left);
+ priv->ring[ring].requests -= handled;
+ safexcel_try_push_requests(priv, ring);
- priv->ring[ring].requests_left -= done;
- if (!done && !priv->ring[ring].requests_left)
+ if (!priv->ring[ring].requests)
priv->ring[ring].busy = false;
spin_unlock_bh(&priv->ring[ring].egress_lock);
@@ -781,6 +768,8 @@ static struct safexcel_alg_template *safexcel_algs[] = {
&safexcel_alg_sha224,
&safexcel_alg_sha256,
&safexcel_alg_hmac_sha1,
+ &safexcel_alg_hmac_sha224,
+ &safexcel_alg_hmac_sha256,
};
static int safexcel_register_algorithms(struct safexcel_crypto_priv *priv)
@@ -894,29 +883,44 @@ static int safexcel_probe(struct platform_device *pdev)
return PTR_ERR(priv->base);
}
- priv->clk = of_clk_get(dev->of_node, 0);
- if (!IS_ERR(priv->clk)) {
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
+ ret = PTR_ERR_OR_ZERO(priv->clk);
+ /* The clock isn't mandatory */
+ if (ret != -ENOENT) {
+ if (ret)
+ return ret;
+
ret = clk_prepare_enable(priv->clk);
if (ret) {
dev_err(dev, "unable to enable clk (%d)\n", ret);
return ret;
}
- } else {
- /* The clock isn't mandatory */
- if (PTR_ERR(priv->clk) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
+ }
+
+ priv->reg_clk = devm_clk_get(&pdev->dev, "reg");
+ ret = PTR_ERR_OR_ZERO(priv->reg_clk);
+ /* The clock isn't mandatory */
+ if (ret != -ENOENT) {
+ if (ret)
+ goto err_core_clk;
+
+ ret = clk_prepare_enable(priv->reg_clk);
+ if (ret) {
+ dev_err(dev, "unable to enable reg clk (%d)\n", ret);
+ goto err_core_clk;
+ }
}
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
if (ret)
- goto err_clk;
+ goto err_reg_clk;
priv->context_pool = dmam_pool_create("safexcel-context", dev,
sizeof(struct safexcel_context_record),
1, 0);
if (!priv->context_pool) {
ret = -ENOMEM;
- goto err_clk;
+ goto err_reg_clk;
}
safexcel_configure(priv);
@@ -931,12 +935,12 @@ static int safexcel_probe(struct platform_device *pdev)
&priv->ring[i].cdr,
&priv->ring[i].rdr);
if (ret)
- goto err_clk;
+ goto err_reg_clk;
ring_irq = devm_kzalloc(dev, sizeof(*ring_irq), GFP_KERNEL);
if (!ring_irq) {
ret = -ENOMEM;
- goto err_clk;
+ goto err_reg_clk;
}
ring_irq->priv = priv;
@@ -948,7 +952,7 @@ static int safexcel_probe(struct platform_device *pdev)
ring_irq);
if (irq < 0) {
ret = irq;
- goto err_clk;
+ goto err_reg_clk;
}
priv->ring[i].work_data.priv = priv;
@@ -959,10 +963,10 @@ static int safexcel_probe(struct platform_device *pdev)
priv->ring[i].workqueue = create_singlethread_workqueue(wq_name);
if (!priv->ring[i].workqueue) {
ret = -ENOMEM;
- goto err_clk;
+ goto err_reg_clk;
}
- priv->ring[i].requests_left = 0;
+ priv->ring[i].requests = 0;
priv->ring[i].busy = false;
crypto_init_queue(&priv->ring[i].queue,
@@ -980,18 +984,20 @@ static int safexcel_probe(struct platform_device *pdev)
ret = safexcel_hw_init(priv);
if (ret) {
dev_err(dev, "EIP h/w init failed (%d)\n", ret);
- goto err_clk;
+ goto err_reg_clk;
}
ret = safexcel_register_algorithms(priv);
if (ret) {
dev_err(dev, "Failed to register algorithms (%d)\n", ret);
- goto err_clk;
+ goto err_reg_clk;
}
return 0;
-err_clk:
+err_reg_clk:
+ clk_disable_unprepare(priv->reg_clk);
+err_core_clk:
clk_disable_unprepare(priv->clk);
return ret;
}
diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h
index 4e219c21608b..b470a849721f 100644
--- a/drivers/crypto/inside-secure/safexcel.h
+++ b/drivers/crypto/inside-secure/safexcel.h
@@ -135,7 +135,7 @@
/* EIP197_HIA_xDR_DMA_CFG */
#define EIP197_HIA_xDR_WR_RES_BUF BIT(22)
-#define EIP197_HIA_xDR_WR_CTRL_BUG BIT(23)
+#define EIP197_HIA_xDR_WR_CTRL_BUF BIT(23)
#define EIP197_HIA_xDR_WR_OWN_BUF BIT(24)
#define EIP197_HIA_xDR_CFG_WR_CACHE(n) (((n) & 0x7) << 25)
#define EIP197_HIA_xDR_CFG_RD_CACHE(n) (((n) & 0x7) << 29)
@@ -179,7 +179,7 @@
#define EIP197_HIA_DxE_CFG_MIN_DATA_SIZE(n) ((n) << 0)
#define EIP197_HIA_DxE_CFG_DATA_CACHE_CTRL(n) (((n) & 0x7) << 4)
#define EIP197_HIA_DxE_CFG_MAX_DATA_SIZE(n) ((n) << 8)
-#define EIP197_HIA_DSE_CFG_ALLWAYS_BUFFERABLE GENMASK(15, 14)
+#define EIP197_HIA_DSE_CFG_ALWAYS_BUFFERABLE GENMASK(15, 14)
#define EIP197_HIA_DxE_CFG_MIN_CTRL_SIZE(n) ((n) << 16)
#define EIP197_HIA_DxE_CFG_CTRL_CACHE_CTRL(n) (((n) & 0x7) << 20)
#define EIP197_HIA_DxE_CFG_MAX_CTRL_SIZE(n) ((n) << 24)
@@ -525,6 +525,7 @@ struct safexcel_crypto_priv {
void __iomem *base;
struct device *dev;
struct clk *clk;
+ struct clk *reg_clk;
struct safexcel_config config;
enum safexcel_eip_version version;
@@ -551,10 +552,8 @@ struct safexcel_crypto_priv {
struct crypto_queue queue;
spinlock_t queue_lock;
- /* Number of requests in the engine that needs the threshold
- * interrupt to be set up.
- */
- int requests_left;
+ /* Number of requests in the engine. */
+ int requests;
/* The ring is currently handling at least one request */
bool busy;
@@ -580,12 +579,6 @@ struct safexcel_context {
int ring;
bool needs_inv;
bool exit_inv;
-
- /* Used for ahash requests */
- dma_addr_t result_dma;
- void *cache;
- dma_addr_t cache_dma;
- unsigned int cache_sz;
};
/*
@@ -609,9 +602,6 @@ struct safexcel_inv_result {
void safexcel_dequeue(struct safexcel_crypto_priv *priv, int ring);
void safexcel_complete(struct safexcel_crypto_priv *priv, int ring);
-void safexcel_free_context(struct safexcel_crypto_priv *priv,
- struct crypto_async_request *req,
- int result_sz);
int safexcel_invalidate_cache(struct crypto_async_request *async,
struct safexcel_crypto_priv *priv,
dma_addr_t ctxr_dma, int ring,
@@ -643,5 +633,7 @@ extern struct safexcel_alg_template safexcel_alg_sha1;
extern struct safexcel_alg_template safexcel_alg_sha224;
extern struct safexcel_alg_template safexcel_alg_sha256;
extern struct safexcel_alg_template safexcel_alg_hmac_sha1;
+extern struct safexcel_alg_template safexcel_alg_hmac_sha224;
+extern struct safexcel_alg_template safexcel_alg_hmac_sha256;
#endif
diff --git a/drivers/crypto/inside-secure/safexcel_cipher.c b/drivers/crypto/inside-secure/safexcel_cipher.c
index 63a8768ed2ae..bafb60505fab 100644
--- a/drivers/crypto/inside-secure/safexcel_cipher.c
+++ b/drivers/crypto/inside-secure/safexcel_cipher.c
@@ -58,7 +58,8 @@ static void safexcel_cipher_token(struct safexcel_cipher_ctx *ctx,
token[0].opcode = EIP197_TOKEN_OPCODE_DIRECTION;
token[0].packet_length = length;
- token[0].stat = EIP197_TOKEN_STAT_LAST_PACKET;
+ token[0].stat = EIP197_TOKEN_STAT_LAST_PACKET |
+ EIP197_TOKEN_STAT_LAST_HASH;
token[0].instructions = EIP197_TOKEN_INS_LAST |
EIP197_TOKEN_INS_TYPE_CRYTO |
EIP197_TOKEN_INS_TYPE_OUTPUT;
@@ -456,7 +457,7 @@ static int safexcel_cipher_exit_inv(struct crypto_tfm *tfm)
queue_work(priv->ring[ring].workqueue,
&priv->ring[ring].work_data.work);
- wait_for_completion_interruptible(&result.completion);
+ wait_for_completion(&result.completion);
if (result.error) {
dev_warn(priv->dev,
diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c
index 122a2a58e98f..317b9e480312 100644
--- a/drivers/crypto/inside-secure/safexcel_hash.c
+++ b/drivers/crypto/inside-secure/safexcel_hash.c
@@ -21,10 +21,9 @@ struct safexcel_ahash_ctx {
struct safexcel_crypto_priv *priv;
u32 alg;
- u32 digest;
- u32 ipad[SHA1_DIGEST_SIZE / sizeof(u32)];
- u32 opad[SHA1_DIGEST_SIZE / sizeof(u32)];
+ u32 ipad[SHA256_DIGEST_SIZE / sizeof(u32)];
+ u32 opad[SHA256_DIGEST_SIZE / sizeof(u32)];
};
struct safexcel_ahash_req {
@@ -34,6 +33,9 @@ struct safexcel_ahash_req {
bool needs_inv;
int nents;
+ dma_addr_t result_dma;
+
+ u32 digest;
u8 state_sz; /* expected sate size, only set once */
u32 state[SHA256_DIGEST_SIZE / sizeof(u32)] __aligned(sizeof(u32));
@@ -42,6 +44,9 @@ struct safexcel_ahash_req {
u64 processed;
u8 cache[SHA256_BLOCK_SIZE] __aligned(sizeof(u32));
+ dma_addr_t cache_dma;
+ unsigned int cache_sz;
+
u8 cache_next[SHA256_BLOCK_SIZE] __aligned(sizeof(u32));
};
@@ -49,6 +54,8 @@ struct safexcel_ahash_export_state {
u64 len;
u64 processed;
+ u32 digest;
+
u32 state[SHA256_DIGEST_SIZE / sizeof(u32)];
u8 cache[SHA256_BLOCK_SIZE];
};
@@ -82,9 +89,9 @@ static void safexcel_context_control(struct safexcel_ahash_ctx *ctx,
cdesc->control_data.control0 |= CONTEXT_CONTROL_TYPE_HASH_OUT;
cdesc->control_data.control0 |= ctx->alg;
- cdesc->control_data.control0 |= ctx->digest;
+ cdesc->control_data.control0 |= req->digest;
- if (ctx->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED) {
+ if (req->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED) {
if (req->processed) {
if (ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_SHA1)
cdesc->control_data.control0 |= CONTEXT_CONTROL_SIZE(6);
@@ -112,12 +119,12 @@ static void safexcel_context_control(struct safexcel_ahash_ctx *ctx,
if (req->finish)
ctx->base.ctxr->data[i] = cpu_to_le32(req->processed / blocksize);
}
- } else if (ctx->digest == CONTEXT_CONTROL_DIGEST_HMAC) {
- cdesc->control_data.control0 |= CONTEXT_CONTROL_SIZE(10);
+ } else if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC) {
+ cdesc->control_data.control0 |= CONTEXT_CONTROL_SIZE(2 * req->state_sz / sizeof(u32));
- memcpy(ctx->base.ctxr->data, ctx->ipad, digestsize);
- memcpy(ctx->base.ctxr->data + digestsize / sizeof(u32),
- ctx->opad, digestsize);
+ memcpy(ctx->base.ctxr->data, ctx->ipad, req->state_sz);
+ memcpy(ctx->base.ctxr->data + req->state_sz / sizeof(u32),
+ ctx->opad, req->state_sz);
}
}
@@ -149,16 +156,26 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin
safexcel_complete(priv, ring);
spin_unlock_bh(&priv->ring[ring].egress_lock);
- if (sreq->finish)
- memcpy(areq->result, sreq->state,
- crypto_ahash_digestsize(ahash));
-
if (sreq->nents) {
dma_unmap_sg(priv->dev, areq->src, sreq->nents, DMA_TO_DEVICE);
sreq->nents = 0;
}
- safexcel_free_context(priv, async, sreq->state_sz);
+ if (sreq->result_dma) {
+ dma_unmap_single(priv->dev, sreq->result_dma, sreq->state_sz,
+ DMA_FROM_DEVICE);
+ sreq->result_dma = 0;
+ }
+
+ if (sreq->cache_dma) {
+ dma_unmap_single(priv->dev, sreq->cache_dma, sreq->cache_sz,
+ DMA_TO_DEVICE);
+ sreq->cache_dma = 0;
+ }
+
+ if (sreq->finish)
+ memcpy(areq->result, sreq->state,
+ crypto_ahash_digestsize(ahash));
cache_len = sreq->len - sreq->processed;
if (cache_len)
@@ -184,7 +201,7 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring,
int i, queued, len, cache_len, extra, n_cdesc = 0, ret = 0;
queued = len = req->len - req->processed;
- if (queued < crypto_ahash_blocksize(ahash))
+ if (queued <= crypto_ahash_blocksize(ahash))
cache_len = queued;
else
cache_len = queued - areq->nbytes;
@@ -198,7 +215,7 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring,
/* If this is not the last request and the queued data
* is a multiple of a block, cache the last one for now.
*/
- extra = queued - crypto_ahash_blocksize(ahash);
+ extra = crypto_ahash_blocksize(ahash);
if (extra) {
sg_pcopy_to_buffer(areq->src, sg_nents(areq->src),
@@ -220,24 +237,17 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring,
/* Add a command descriptor for the cached data, if any */
if (cache_len) {
- ctx->base.cache = kzalloc(cache_len, EIP197_GFP_FLAGS(*async));
- if (!ctx->base.cache) {
- ret = -ENOMEM;
- goto unlock;
- }
- memcpy(ctx->base.cache, req->cache, cache_len);
- ctx->base.cache_dma = dma_map_single(priv->dev, ctx->base.cache,
- cache_len, DMA_TO_DEVICE);
- if (dma_mapping_error(priv->dev, ctx->base.cache_dma)) {
- ret = -EINVAL;
- goto free_cache;
+ req->cache_dma = dma_map_single(priv->dev, req->cache,
+ cache_len, DMA_TO_DEVICE);
+ if (dma_mapping_error(priv->dev, req->cache_dma)) {
+ spin_unlock_bh(&priv->ring[ring].egress_lock);
+ return -EINVAL;
}
- ctx->base.cache_sz = cache_len;
+ req->cache_sz = cache_len;
first_cdesc = safexcel_add_cdesc(priv, ring, 1,
(cache_len == len),
- ctx->base.cache_dma,
- cache_len, len,
+ req->cache_dma, cache_len, len,
ctx->base.ctxr_dma);
if (IS_ERR(first_cdesc)) {
ret = PTR_ERR(first_cdesc);
@@ -271,7 +281,7 @@ static int safexcel_ahash_send_req(struct crypto_async_request *async, int ring,
sglen, len, ctx->base.ctxr_dma);
if (IS_ERR(cdesc)) {
ret = PTR_ERR(cdesc);
- goto cdesc_rollback;
+ goto unmap_sg;
}
n_cdesc++;
@@ -291,19 +301,19 @@ send_command:
/* Add the token */
safexcel_hash_token(first_cdesc, len, req->state_sz);
- ctx->base.result_dma = dma_map_single(priv->dev, req->state,
- req->state_sz, DMA_FROM_DEVICE);
- if (dma_mapping_error(priv->dev, ctx->base.result_dma)) {
+ req->result_dma = dma_map_single(priv->dev, req->state, req->state_sz,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(priv->dev, req->result_dma)) {
ret = -EINVAL;
- goto cdesc_rollback;
+ goto unmap_sg;
}
/* Add a result descriptor */
- rdesc = safexcel_add_rdesc(priv, ring, 1, 1, ctx->base.result_dma,
+ rdesc = safexcel_add_rdesc(priv, ring, 1, 1, req->result_dma,
req->state_sz);
if (IS_ERR(rdesc)) {
ret = PTR_ERR(rdesc);
- goto cdesc_rollback;
+ goto unmap_result;
}
spin_unlock_bh(&priv->ring[ring].egress_lock);
@@ -315,20 +325,21 @@ send_command:
*results = 1;
return 0;
+unmap_result:
+ dma_unmap_single(priv->dev, req->result_dma, req->state_sz,
+ DMA_FROM_DEVICE);
+unmap_sg:
+ dma_unmap_sg(priv->dev, areq->src, req->nents, DMA_TO_DEVICE);
cdesc_rollback:
for (i = 0; i < n_cdesc; i++)
safexcel_ring_rollback_wptr(priv, &priv->ring[ring].cdr);
unmap_cache:
- if (ctx->base.cache_dma) {
- dma_unmap_single(priv->dev, ctx->base.cache_dma,
- ctx->base.cache_sz, DMA_TO_DEVICE);
- ctx->base.cache_sz = 0;
+ if (req->cache_dma) {
+ dma_unmap_single(priv->dev, req->cache_dma, req->cache_sz,
+ DMA_TO_DEVICE);
+ req->cache_sz = 0;
}
-free_cache:
- kfree(ctx->base.cache);
- ctx->base.cache = NULL;
-unlock:
spin_unlock_bh(&priv->ring[ring].egress_lock);
return ret;
}
@@ -493,7 +504,7 @@ static int safexcel_ahash_exit_inv(struct crypto_tfm *tfm)
queue_work(priv->ring[ring].workqueue,
&priv->ring[ring].work_data.work);
- wait_for_completion_interruptible(&result.completion);
+ wait_for_completion(&result.completion);
if (result.error) {
dev_warn(priv->dev, "hash: completion error (%d)\n",
@@ -550,7 +561,7 @@ static int safexcel_ahash_enqueue(struct ahash_request *areq)
if (ctx->base.ctxr) {
if (priv->version == EIP197 &&
!ctx->base.needs_inv && req->processed &&
- ctx->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED)
+ req->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED)
/* We're still setting needs_inv here, even though it is
* cleared right away, because the needs_inv flag can be
* set in other functions and we want to keep the same
@@ -585,7 +596,6 @@ static int safexcel_ahash_enqueue(struct ahash_request *areq)
static int safexcel_ahash_update(struct ahash_request *areq)
{
- struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
struct safexcel_ahash_req *req = ahash_request_ctx(areq);
struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq);
@@ -601,7 +611,7 @@ static int safexcel_ahash_update(struct ahash_request *areq)
* We're not doing partial updates when performing an hmac request.
* Everything will be handled by the final() call.
*/
- if (ctx->digest == CONTEXT_CONTROL_DIGEST_HMAC)
+ if (req->digest == CONTEXT_CONTROL_DIGEST_HMAC)
return 0;
if (req->hmac)
@@ -660,6 +670,8 @@ static int safexcel_ahash_export(struct ahash_request *areq, void *out)
export->len = req->len;
export->processed = req->processed;
+ export->digest = req->digest;
+
memcpy(export->state, req->state, req->state_sz);
memcpy(export->cache, req->cache, crypto_ahash_blocksize(ahash));
@@ -680,6 +692,8 @@ static int safexcel_ahash_import(struct ahash_request *areq, const void *in)
req->len = export->len;
req->processed = export->processed;
+ req->digest = export->digest;
+
memcpy(req->cache, export->cache, crypto_ahash_blocksize(ahash));
memcpy(req->state, export->state, req->state_sz);
@@ -716,7 +730,7 @@ static int safexcel_sha1_init(struct ahash_request *areq)
req->state[4] = SHA1_H4;
ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA1;
- ctx->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
req->state_sz = SHA1_DIGEST_SIZE;
return 0;
@@ -783,10 +797,10 @@ struct safexcel_alg_template safexcel_alg_sha1 = {
static int safexcel_hmac_sha1_init(struct ahash_request *areq)
{
- struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
+ struct safexcel_ahash_req *req = ahash_request_ctx(areq);
safexcel_sha1_init(areq);
- ctx->digest = CONTEXT_CONTROL_DIGEST_HMAC;
+ req->digest = CONTEXT_CONTROL_DIGEST_HMAC;
return 0;
}
@@ -839,7 +853,7 @@ static int safexcel_hmac_init_pad(struct ahash_request *areq,
init_completion(&result.completion);
ret = crypto_ahash_digest(areq);
- if (ret == -EINPROGRESS) {
+ if (ret == -EINPROGRESS || ret == -EBUSY) {
wait_for_completion_interruptible(&result.completion);
ret = result.error;
}
@@ -949,20 +963,21 @@ free_ahash:
return ret;
}
-static int safexcel_hmac_sha1_setkey(struct crypto_ahash *tfm, const u8 *key,
- unsigned int keylen)
+static int safexcel_hmac_alg_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen, const char *alg,
+ unsigned int state_sz)
{
struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
struct safexcel_crypto_priv *priv = ctx->priv;
struct safexcel_ahash_export_state istate, ostate;
int ret, i;
- ret = safexcel_hmac_setkey("safexcel-sha1", key, keylen, &istate, &ostate);
+ ret = safexcel_hmac_setkey(alg, key, keylen, &istate, &ostate);
if (ret)
return ret;
if (priv->version == EIP197 && ctx->base.ctxr) {
- for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++) {
+ for (i = 0; i < state_sz / sizeof(u32); i++) {
if (ctx->ipad[i] != le32_to_cpu(istate.state[i]) ||
ctx->opad[i] != le32_to_cpu(ostate.state[i])) {
ctx->base.needs_inv = true;
@@ -971,12 +986,19 @@ static int safexcel_hmac_sha1_setkey(struct crypto_ahash *tfm, const u8 *key,
}
}
- memcpy(ctx->ipad, &istate.state, SHA1_DIGEST_SIZE);
- memcpy(ctx->opad, &ostate.state, SHA1_DIGEST_SIZE);
+ memcpy(ctx->ipad, &istate.state, state_sz);
+ memcpy(ctx->opad, &ostate.state, state_sz);
return 0;
}
+static int safexcel_hmac_sha1_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ return safexcel_hmac_alg_setkey(tfm, key, keylen, "safexcel-sha1",
+ SHA1_DIGEST_SIZE);
+}
+
struct safexcel_alg_template safexcel_alg_hmac_sha1 = {
.type = SAFEXCEL_ALG_TYPE_AHASH,
.alg.ahash = {
@@ -1024,7 +1046,7 @@ static int safexcel_sha256_init(struct ahash_request *areq)
req->state[7] = SHA256_H7;
ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA256;
- ctx->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
req->state_sz = SHA256_DIGEST_SIZE;
return 0;
@@ -1086,7 +1108,7 @@ static int safexcel_sha224_init(struct ahash_request *areq)
req->state[7] = SHA224_H7;
ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA224;
- ctx->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
req->state_sz = SHA256_DIGEST_SIZE;
return 0;
@@ -1130,3 +1152,115 @@ struct safexcel_alg_template safexcel_alg_sha224 = {
},
},
};
+
+static int safexcel_hmac_sha224_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ return safexcel_hmac_alg_setkey(tfm, key, keylen, "safexcel-sha224",
+ SHA256_DIGEST_SIZE);
+}
+
+static int safexcel_hmac_sha224_init(struct ahash_request *areq)
+{
+ struct safexcel_ahash_req *req = ahash_request_ctx(areq);
+
+ safexcel_sha224_init(areq);
+ req->digest = CONTEXT_CONTROL_DIGEST_HMAC;
+ return 0;
+}
+
+static int safexcel_hmac_sha224_digest(struct ahash_request *areq)
+{
+ int ret = safexcel_hmac_sha224_init(areq);
+
+ if (ret)
+ return ret;
+
+ return safexcel_ahash_finup(areq);
+}
+
+struct safexcel_alg_template safexcel_alg_hmac_sha224 = {
+ .type = SAFEXCEL_ALG_TYPE_AHASH,
+ .alg.ahash = {
+ .init = safexcel_hmac_sha224_init,
+ .update = safexcel_ahash_update,
+ .final = safexcel_ahash_final,
+ .finup = safexcel_ahash_finup,
+ .digest = safexcel_hmac_sha224_digest,
+ .setkey = safexcel_hmac_sha224_setkey,
+ .export = safexcel_ahash_export,
+ .import = safexcel_ahash_import,
+ .halg = {
+ .digestsize = SHA224_DIGEST_SIZE,
+ .statesize = sizeof(struct safexcel_ahash_export_state),
+ .base = {
+ .cra_name = "hmac(sha224)",
+ .cra_driver_name = "safexcel-hmac-sha224",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA224_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
+ .cra_init = safexcel_ahash_cra_init,
+ .cra_exit = safexcel_ahash_cra_exit,
+ .cra_module = THIS_MODULE,
+ },
+ },
+ },
+};
+
+static int safexcel_hmac_sha256_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ return safexcel_hmac_alg_setkey(tfm, key, keylen, "safexcel-sha256",
+ SHA256_DIGEST_SIZE);
+}
+
+static int safexcel_hmac_sha256_init(struct ahash_request *areq)
+{
+ struct safexcel_ahash_req *req = ahash_request_ctx(areq);
+
+ safexcel_sha256_init(areq);
+ req->digest = CONTEXT_CONTROL_DIGEST_HMAC;
+ return 0;
+}
+
+static int safexcel_hmac_sha256_digest(struct ahash_request *areq)
+{
+ int ret = safexcel_hmac_sha256_init(areq);
+
+ if (ret)
+ return ret;
+
+ return safexcel_ahash_finup(areq);
+}
+
+struct safexcel_alg_template safexcel_alg_hmac_sha256 = {
+ .type = SAFEXCEL_ALG_TYPE_AHASH,
+ .alg.ahash = {
+ .init = safexcel_hmac_sha256_init,
+ .update = safexcel_ahash_update,
+ .final = safexcel_ahash_final,
+ .finup = safexcel_ahash_finup,
+ .digest = safexcel_hmac_sha256_digest,
+ .setkey = safexcel_hmac_sha256_setkey,
+ .export = safexcel_ahash_export,
+ .import = safexcel_ahash_import,
+ .halg = {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .statesize = sizeof(struct safexcel_ahash_export_state),
+ .base = {
+ .cra_name = "hmac(sha256)",
+ .cra_driver_name = "safexcel-hmac-sha256",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
+ .cra_init = safexcel_ahash_cra_init,
+ .cra_exit = safexcel_ahash_cra_exit,
+ .cra_module = THIS_MODULE,
+ },
+ },
+ },
+};
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
index 717a26607bdb..27f7dad2d45d 100644
--- a/drivers/crypto/ixp4xx_crypto.c
+++ b/drivers/crypto/ixp4xx_crypto.c
@@ -1167,9 +1167,11 @@ static int aead_setkey(struct crypto_aead *tfm, const u8 *key,
ctx->authkey_len = keys.authkeylen;
ctx->enckey_len = keys.enckeylen;
+ memzero_explicit(&keys, sizeof(keys));
return aead_setup(tfm, crypto_aead_authsize(tfm));
badkey:
crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ memzero_explicit(&keys, sizeof(keys));
return -EINVAL;
}
diff --git a/drivers/crypto/marvell/cesa.c b/drivers/crypto/marvell/cesa.c
index aca2373fa1de..f81fa4a3e66b 100644
--- a/drivers/crypto/marvell/cesa.c
+++ b/drivers/crypto/marvell/cesa.c
@@ -25,7 +25,6 @@
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/dma-direct.h> /* XXX: drivers shall never use this directly! */
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_platform.h>
diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c
index 764be3e6933c..a10c418d4e5c 100644
--- a/drivers/crypto/mxs-dcp.c
+++ b/drivers/crypto/mxs-dcp.c
@@ -759,6 +759,16 @@ static int dcp_sha_digest(struct ahash_request *req)
return dcp_sha_finup(req);
}
+static int dcp_sha_noimport(struct ahash_request *req, const void *in)
+{
+ return -ENOSYS;
+}
+
+static int dcp_sha_noexport(struct ahash_request *req, void *out)
+{
+ return -ENOSYS;
+}
+
static int dcp_sha_cra_init(struct crypto_tfm *tfm)
{
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
@@ -829,6 +839,8 @@ static struct ahash_alg dcp_sha1_alg = {
.final = dcp_sha_final,
.finup = dcp_sha_finup,
.digest = dcp_sha_digest,
+ .import = dcp_sha_noimport,
+ .export = dcp_sha_noexport,
.halg = {
.digestsize = SHA1_DIGEST_SIZE,
.base = {
@@ -853,6 +865,8 @@ static struct ahash_alg dcp_sha256_alg = {
.final = dcp_sha_final,
.finup = dcp_sha_finup,
.digest = dcp_sha_digest,
+ .import = dcp_sha_noimport,
+ .export = dcp_sha_noexport,
.halg = {
.digestsize = SHA256_DIGEST_SIZE,
.base = {
diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c
index 662e709812cc..80e9c842aad4 100644
--- a/drivers/crypto/n2_core.c
+++ b/drivers/crypto/n2_core.c
@@ -359,6 +359,16 @@ static int n2_hash_async_finup(struct ahash_request *req)
return crypto_ahash_finup(&rctx->fallback_req);
}
+static int n2_hash_async_noimport(struct ahash_request *req, const void *in)
+{
+ return -ENOSYS;
+}
+
+static int n2_hash_async_noexport(struct ahash_request *req, void *out)
+{
+ return -ENOSYS;
+}
+
static int n2_hash_cra_init(struct crypto_tfm *tfm)
{
const char *fallback_driver_name = crypto_tfm_alg_name(tfm);
@@ -1467,6 +1477,8 @@ static int __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl)
ahash->final = n2_hash_async_final;
ahash->finup = n2_hash_async_finup;
ahash->digest = n2_hash_async_digest;
+ ahash->export = n2_hash_async_noexport;
+ ahash->import = n2_hash_async_noimport;
halg = &ahash->halg;
halg->digestsize = tmpl->digest_size;
diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c
index bf52cd1d7fca..66869976cfa2 100644
--- a/drivers/crypto/nx/nx-842-pseries.c
+++ b/drivers/crypto/nx/nx-842-pseries.c
@@ -1105,10 +1105,9 @@ static int __init nx842_pseries_init(void)
RCU_INIT_POINTER(devdata, NULL);
new_devdata = kzalloc(sizeof(*new_devdata), GFP_KERNEL);
- if (!new_devdata) {
- pr_err("Could not allocate memory for device data\n");
+ if (!new_devdata)
return -ENOMEM;
- }
+
RCU_INIT_POINTER(devdata, new_devdata);
ret = vio_register_driver(&nx842_vio_driver);
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index fbec0a2e76dd..9019f6b67986 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -47,6 +47,8 @@
static LIST_HEAD(dev_list);
static DEFINE_SPINLOCK(list_lock);
+static int aes_fallback_sz = 200;
+
#ifdef DEBUG
#define omap_aes_read(dd, offset) \
({ \
@@ -388,7 +390,7 @@ static void omap_aes_finish_req(struct omap_aes_dev *dd, int err)
pr_debug("err: %d\n", err);
- crypto_finalize_cipher_request(dd->engine, req, err);
+ crypto_finalize_ablkcipher_request(dd->engine, req, err);
pm_runtime_mark_last_busy(dd->dev);
pm_runtime_put_autosuspend(dd->dev);
@@ -408,14 +410,15 @@ static int omap_aes_handle_queue(struct omap_aes_dev *dd,
struct ablkcipher_request *req)
{
if (req)
- return crypto_transfer_cipher_request_to_engine(dd->engine, req);
+ return crypto_transfer_ablkcipher_request_to_engine(dd->engine, req);
return 0;
}
static int omap_aes_prepare_req(struct crypto_engine *engine,
- struct ablkcipher_request *req)
+ void *areq)
{
+ struct ablkcipher_request *req = container_of(areq, struct ablkcipher_request, base);
struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(
crypto_ablkcipher_reqtfm(req));
struct omap_aes_reqctx *rctx = ablkcipher_request_ctx(req);
@@ -468,8 +471,9 @@ static int omap_aes_prepare_req(struct crypto_engine *engine,
}
static int omap_aes_crypt_req(struct crypto_engine *engine,
- struct ablkcipher_request *req)
+ void *areq)
{
+ struct ablkcipher_request *req = container_of(areq, struct ablkcipher_request, base);
struct omap_aes_reqctx *rctx = ablkcipher_request_ctx(req);
struct omap_aes_dev *dd = rctx->dd;
@@ -517,7 +521,7 @@ static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
!!(mode & FLAGS_ENCRYPT),
!!(mode & FLAGS_CBC));
- if (req->nbytes < 200) {
+ if (req->nbytes < aes_fallback_sz) {
SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
skcipher_request_set_tfm(subreq, ctx->fallback);
@@ -601,6 +605,11 @@ static int omap_aes_ctr_decrypt(struct ablkcipher_request *req)
return omap_aes_crypt(req, FLAGS_CTR);
}
+static int omap_aes_prepare_req(struct crypto_engine *engine,
+ void *req);
+static int omap_aes_crypt_req(struct crypto_engine *engine,
+ void *req);
+
static int omap_aes_cra_init(struct crypto_tfm *tfm)
{
const char *name = crypto_tfm_alg_name(tfm);
@@ -616,6 +625,10 @@ static int omap_aes_cra_init(struct crypto_tfm *tfm)
tfm->crt_ablkcipher.reqsize = sizeof(struct omap_aes_reqctx);
+ ctx->enginectx.op.prepare_request = omap_aes_prepare_req;
+ ctx->enginectx.op.unprepare_request = NULL;
+ ctx->enginectx.op.do_one_request = omap_aes_crypt_req;
+
return 0;
}
@@ -1029,6 +1042,87 @@ err:
return err;
}
+static ssize_t fallback_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", aes_fallback_sz);
+}
+
+static ssize_t fallback_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t status;
+ long value;
+
+ status = kstrtol(buf, 0, &value);
+ if (status)
+ return status;
+
+ /* HW accelerator only works with buffers > 9 */
+ if (value < 9) {
+ dev_err(dev, "minimum fallback size 9\n");
+ return -EINVAL;
+ }
+
+ aes_fallback_sz = value;
+
+ return size;
+}
+
+static ssize_t queue_len_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct omap_aes_dev *dd = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", dd->engine->queue.max_qlen);
+}
+
+static ssize_t queue_len_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ struct omap_aes_dev *dd;
+ ssize_t status;
+ long value;
+ unsigned long flags;
+
+ status = kstrtol(buf, 0, &value);
+ if (status)
+ return status;
+
+ if (value < 1)
+ return -EINVAL;
+
+ /*
+ * Changing the queue size in fly is safe, if size becomes smaller
+ * than current size, it will just not accept new entries until
+ * it has shrank enough.
+ */
+ spin_lock_bh(&list_lock);
+ list_for_each_entry(dd, &dev_list, list) {
+ spin_lock_irqsave(&dd->lock, flags);
+ dd->engine->queue.max_qlen = value;
+ dd->aead_queue.base.max_qlen = value;
+ spin_unlock_irqrestore(&dd->lock, flags);
+ }
+ spin_unlock_bh(&list_lock);
+
+ return size;
+}
+
+static DEVICE_ATTR_RW(queue_len);
+static DEVICE_ATTR_RW(fallback);
+
+static struct attribute *omap_aes_attrs[] = {
+ &dev_attr_queue_len.attr,
+ &dev_attr_fallback.attr,
+ NULL,
+};
+
+static struct attribute_group omap_aes_attr_group = {
+ .attrs = omap_aes_attrs,
+};
+
static int omap_aes_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1119,8 +1213,6 @@ static int omap_aes_probe(struct platform_device *pdev)
goto err_engine;
}
- dd->engine->prepare_cipher_request = omap_aes_prepare_req;
- dd->engine->cipher_one_request = omap_aes_crypt_req;
err = crypto_engine_start(dd->engine);
if (err)
goto err_engine;
@@ -1159,6 +1251,12 @@ static int omap_aes_probe(struct platform_device *pdev)
}
}
+ err = sysfs_create_group(&dev->kobj, &omap_aes_attr_group);
+ if (err) {
+ dev_err(dev, "could not create sysfs device attrs\n");
+ goto err_aead_algs;
+ }
+
return 0;
err_aead_algs:
for (i = dd->pdata->aead_algs_info->registered - 1; i >= 0; i--) {
diff --git a/drivers/crypto/omap-aes.h b/drivers/crypto/omap-aes.h
index 8906342e2b9a..fc3b46a85809 100644
--- a/drivers/crypto/omap-aes.h
+++ b/drivers/crypto/omap-aes.h
@@ -13,6 +13,8 @@
#ifndef __OMAP_AES_H__
#define __OMAP_AES_H__
+#include <crypto/engine.h>
+
#define DST_MAXBURST 4
#define DMA_MIN (DST_MAXBURST * sizeof(u32))
@@ -95,6 +97,7 @@ struct omap_aes_gcm_result {
};
struct omap_aes_ctx {
+ struct crypto_engine_ctx enginectx;
int keylen;
u32 key[AES_KEYSIZE_256 / sizeof(u32)];
u8 nonce[4];
diff --git a/drivers/crypto/omap-crypto.c b/drivers/crypto/omap-crypto.c
index 23e37779317e..2c42e4b4a6e9 100644
--- a/drivers/crypto/omap-crypto.c
+++ b/drivers/crypto/omap-crypto.c
@@ -104,6 +104,10 @@ static int omap_crypto_check_sg(struct scatterlist *sg, int total, int bs,
return OMAP_CRYPTO_NOT_ALIGNED;
if (!IS_ALIGNED(sg->length, bs))
return OMAP_CRYPTO_NOT_ALIGNED;
+#ifdef CONFIG_ZONE_DMA
+ if (page_zonenum(sg_page(sg)) != ZONE_DMA)
+ return OMAP_CRYPTO_NOT_ALIGNED;
+#endif
len += sg->length;
sg = sg_next(sg);
diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c
index ebc5c0f11f03..eb95b0d7f184 100644
--- a/drivers/crypto/omap-des.c
+++ b/drivers/crypto/omap-des.c
@@ -86,6 +86,7 @@
#define FLAGS_OUT_DATA_ST_SHIFT 10
struct omap_des_ctx {
+ struct crypto_engine_ctx enginectx;
struct omap_des_dev *dd;
int keylen;
@@ -498,7 +499,7 @@ static void omap_des_finish_req(struct omap_des_dev *dd, int err)
pr_debug("err: %d\n", err);
- crypto_finalize_cipher_request(dd->engine, req, err);
+ crypto_finalize_ablkcipher_request(dd->engine, req, err);
pm_runtime_mark_last_busy(dd->dev);
pm_runtime_put_autosuspend(dd->dev);
@@ -520,14 +521,15 @@ static int omap_des_handle_queue(struct omap_des_dev *dd,
struct ablkcipher_request *req)
{
if (req)
- return crypto_transfer_cipher_request_to_engine(dd->engine, req);
+ return crypto_transfer_ablkcipher_request_to_engine(dd->engine, req);
return 0;
}
static int omap_des_prepare_req(struct crypto_engine *engine,
- struct ablkcipher_request *req)
+ void *areq)
{
+ struct ablkcipher_request *req = container_of(areq, struct ablkcipher_request, base);
struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(
crypto_ablkcipher_reqtfm(req));
struct omap_des_dev *dd = omap_des_find_dev(ctx);
@@ -582,8 +584,9 @@ static int omap_des_prepare_req(struct crypto_engine *engine,
}
static int omap_des_crypt_req(struct crypto_engine *engine,
- struct ablkcipher_request *req)
+ void *areq)
{
+ struct ablkcipher_request *req = container_of(areq, struct ablkcipher_request, base);
struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(
crypto_ablkcipher_reqtfm(req));
struct omap_des_dev *dd = omap_des_find_dev(ctx);
@@ -695,12 +698,23 @@ static int omap_des_cbc_decrypt(struct ablkcipher_request *req)
return omap_des_crypt(req, FLAGS_CBC);
}
+static int omap_des_prepare_req(struct crypto_engine *engine,
+ void *areq);
+static int omap_des_crypt_req(struct crypto_engine *engine,
+ void *areq);
+
static int omap_des_cra_init(struct crypto_tfm *tfm)
{
+ struct omap_des_ctx *ctx = crypto_tfm_ctx(tfm);
+
pr_debug("enter\n");
tfm->crt_ablkcipher.reqsize = sizeof(struct omap_des_reqctx);
+ ctx->enginectx.op.prepare_request = omap_des_prepare_req;
+ ctx->enginectx.op.unprepare_request = NULL;
+ ctx->enginectx.op.do_one_request = omap_des_crypt_req;
+
return 0;
}
@@ -1046,8 +1060,6 @@ static int omap_des_probe(struct platform_device *pdev)
goto err_engine;
}
- dd->engine->prepare_cipher_request = omap_des_prepare_req;
- dd->engine->cipher_one_request = omap_des_crypt_req;
err = crypto_engine_start(dd->engine);
if (err)
goto err_engine;
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 86b89ace836f..ad02aa63b519 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -229,6 +229,7 @@ struct omap_sham_dev {
u8 xmit_buf[BUFLEN] OMAP_ALIGNED;
unsigned long flags;
+ int fallback_sz;
struct crypto_queue queue;
struct ahash_request *req;
@@ -759,6 +760,13 @@ static int omap_sham_align_sgs(struct scatterlist *sg,
while (nbytes > 0 && sg_tmp) {
n++;
+#ifdef CONFIG_ZONE_DMA
+ if (page_zonenum(sg_page(sg_tmp)) != ZONE_DMA) {
+ aligned = false;
+ break;
+ }
+#endif
+
if (offset < sg_tmp->length) {
if (!IS_ALIGNED(offset + sg_tmp->offset, 4)) {
aligned = false;
@@ -809,9 +817,6 @@ static int omap_sham_prepare_request(struct ahash_request *req, bool update)
bool final = rctx->flags & BIT(FLAGS_FINUP);
int xmit_len, hash_later;
- if (!req)
- return 0;
-
bs = get_block_size(rctx);
if (update)
@@ -1002,7 +1007,7 @@ static int omap_sham_update_req(struct omap_sham_dev *dd)
ctx->total, ctx->digcnt, (ctx->flags & BIT(FLAGS_FINUP)) != 0);
if (ctx->total < get_block_size(ctx) ||
- ctx->total < OMAP_SHA_DMA_THRESHOLD)
+ ctx->total < dd->fallback_sz)
ctx->flags |= BIT(FLAGS_CPU);
if (ctx->flags & BIT(FLAGS_CPU))
@@ -1258,11 +1263,11 @@ static int omap_sham_final(struct ahash_request *req)
/*
* OMAP HW accel works only with buffers >= 9.
* HMAC is always >= 9 because ipad == block size.
- * If buffersize is less than DMA_THRESHOLD, we use fallback
+ * If buffersize is less than fallback_sz, we use fallback
* SW encoding, as using DMA + HW in this case doesn't provide
* any benefit.
*/
- if (!ctx->digcnt && ctx->bufcnt < OMAP_SHA_DMA_THRESHOLD)
+ if (!ctx->digcnt && ctx->bufcnt < ctx->dd->fallback_sz)
return omap_sham_final_shash(req);
else if (ctx->bufcnt)
return omap_sham_enqueue(req, OP_FINAL);
@@ -1761,7 +1766,7 @@ static void omap_sham_done_task(unsigned long data)
if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags)) {
/* hash or semi-hash ready */
clear_bit(FLAGS_DMA_READY, &dd->flags);
- goto finish;
+ goto finish;
}
}
@@ -2013,6 +2018,85 @@ err:
return err;
}
+static ssize_t fallback_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct omap_sham_dev *dd = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", dd->fallback_sz);
+}
+
+static ssize_t fallback_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap_sham_dev *dd = dev_get_drvdata(dev);
+ ssize_t status;
+ long value;
+
+ status = kstrtol(buf, 0, &value);
+ if (status)
+ return status;
+
+ /* HW accelerator only works with buffers > 9 */
+ if (value < 9) {
+ dev_err(dev, "minimum fallback size 9\n");
+ return -EINVAL;
+ }
+
+ dd->fallback_sz = value;
+
+ return size;
+}
+
+static ssize_t queue_len_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct omap_sham_dev *dd = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", dd->queue.max_qlen);
+}
+
+static ssize_t queue_len_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ struct omap_sham_dev *dd = dev_get_drvdata(dev);
+ ssize_t status;
+ long value;
+ unsigned long flags;
+
+ status = kstrtol(buf, 0, &value);
+ if (status)
+ return status;
+
+ if (value < 1)
+ return -EINVAL;
+
+ /*
+ * Changing the queue size in fly is safe, if size becomes smaller
+ * than current size, it will just not accept new entries until
+ * it has shrank enough.
+ */
+ spin_lock_irqsave(&dd->lock, flags);
+ dd->queue.max_qlen = value;
+ spin_unlock_irqrestore(&dd->lock, flags);
+
+ return size;
+}
+
+static DEVICE_ATTR_RW(queue_len);
+static DEVICE_ATTR_RW(fallback);
+
+static struct attribute *omap_sham_attrs[] = {
+ &dev_attr_queue_len.attr,
+ &dev_attr_fallback.attr,
+ NULL,
+};
+
+static struct attribute_group omap_sham_attr_group = {
+ .attrs = omap_sham_attrs,
+};
+
static int omap_sham_probe(struct platform_device *pdev)
{
struct omap_sham_dev *dd;
@@ -2074,6 +2158,8 @@ static int omap_sham_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, DEFAULT_AUTOSUSPEND_DELAY);
+ dd->fallback_sz = OMAP_SHA_DMA_THRESHOLD;
+
pm_runtime_enable(dev);
pm_runtime_irq_safe(dev);
@@ -2111,6 +2197,12 @@ static int omap_sham_probe(struct platform_device *pdev)
}
}
+ err = sysfs_create_group(&dev->kobj, &omap_sham_attr_group);
+ if (err) {
+ dev_err(dev, "could not create sysfs device attrs\n");
+ goto err_algs;
+ }
+
return 0;
err_algs:
diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c
index 4ef52c9d72fc..a4df966adbf6 100644
--- a/drivers/crypto/picoxcell_crypto.c
+++ b/drivers/crypto/picoxcell_crypto.c
@@ -499,10 +499,12 @@ static int spacc_aead_setkey(struct crypto_aead *tfm, const u8 *key,
memcpy(ctx->hash_ctx, keys.authkey, keys.authkeylen);
ctx->hash_key_len = keys.authkeylen;
+ memzero_explicit(&keys, sizeof(keys));
return 0;
badkey:
crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ memzero_explicit(&keys, sizeof(keys));
return -EINVAL;
}
diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
index baffae817259..1138e41d6805 100644
--- a/drivers/crypto/qat/qat_common/qat_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_algs.c
@@ -546,11 +546,14 @@ static int qat_alg_aead_init_sessions(struct crypto_aead *tfm, const u8 *key,
if (qat_alg_aead_init_dec_session(tfm, alg, &keys, mode))
goto error;
+ memzero_explicit(&keys, sizeof(keys));
return 0;
bad_key:
crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ memzero_explicit(&keys, sizeof(keys));
return -EINVAL;
error:
+ memzero_explicit(&keys, sizeof(keys));
return -EFAULT;
}
diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c
index 13c52d6bf630..320e7854b4ee 100644
--- a/drivers/crypto/qat/qat_common/qat_asym_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_asym_algs.c
@@ -969,7 +969,8 @@ unmap_src:
return ret;
}
-int qat_rsa_set_n(struct qat_rsa_ctx *ctx, const char *value, size_t vlen)
+static int qat_rsa_set_n(struct qat_rsa_ctx *ctx, const char *value,
+ size_t vlen)
{
struct qat_crypto_instance *inst = ctx->inst;
struct device *dev = &GET_DEV(inst->accel_dev);
@@ -1000,7 +1001,8 @@ err:
return ret;
}
-int qat_rsa_set_e(struct qat_rsa_ctx *ctx, const char *value, size_t vlen)
+static int qat_rsa_set_e(struct qat_rsa_ctx *ctx, const char *value,
+ size_t vlen)
{
struct qat_crypto_instance *inst = ctx->inst;
struct device *dev = &GET_DEV(inst->accel_dev);
@@ -1024,7 +1026,8 @@ int qat_rsa_set_e(struct qat_rsa_ctx *ctx, const char *value, size_t vlen)
return 0;
}
-int qat_rsa_set_d(struct qat_rsa_ctx *ctx, const char *value, size_t vlen)
+static int qat_rsa_set_d(struct qat_rsa_ctx *ctx, const char *value,
+ size_t vlen)
{
struct qat_crypto_instance *inst = ctx->inst;
struct device *dev = &GET_DEV(inst->accel_dev);
diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c
index 5d64c08b7f47..bf7163042569 100644
--- a/drivers/crypto/s5p-sss.c
+++ b/drivers/crypto/s5p-sss.c
@@ -404,29 +404,31 @@ static const struct of_device_id s5p_sss_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, s5p_sss_dt_match);
-static inline struct samsung_aes_variant *find_s5p_sss_version
- (struct platform_device *pdev)
+static inline const struct samsung_aes_variant *find_s5p_sss_version
+ (const struct platform_device *pdev)
{
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;
+ return (const struct samsung_aes_variant *)match->data;
}
- return (struct samsung_aes_variant *)
+ return (const struct samsung_aes_variant *)
platform_get_device_id(pdev)->driver_data;
}
static struct s5p_aes_dev *s5p_dev;
-static void s5p_set_dma_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
+static void s5p_set_dma_indata(struct s5p_aes_dev *dev,
+ const struct scatterlist *sg)
{
SSS_WRITE(dev, FCBRDMAS, sg_dma_address(sg));
SSS_WRITE(dev, FCBRDMAL, sg_dma_len(sg));
}
-static void s5p_set_dma_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg)
+static void s5p_set_dma_outdata(struct s5p_aes_dev *dev,
+ const struct scatterlist *sg)
{
SSS_WRITE(dev, FCBTDMAS, sg_dma_address(sg));
SSS_WRITE(dev, FCBTDMAL, sg_dma_len(sg));
@@ -619,7 +621,7 @@ static inline void s5p_hash_write(struct s5p_aes_dev *dd,
* @sg: scatterlist ready to DMA transmit
*/
static void s5p_set_dma_hashdata(struct s5p_aes_dev *dev,
- struct scatterlist *sg)
+ const struct scatterlist *sg)
{
dev->hash_sg_cnt--;
SSS_WRITE(dev, FCHRDMAS, sg_dma_address(sg));
@@ -792,9 +794,9 @@ static void s5p_hash_read_msg(struct ahash_request *req)
* @ctx: request context
*/
static void s5p_hash_write_ctx_iv(struct s5p_aes_dev *dd,
- struct s5p_hash_reqctx *ctx)
+ const struct s5p_hash_reqctx *ctx)
{
- u32 *hash = (u32 *)ctx->digest;
+ const u32 *hash = (const u32 *)ctx->digest;
unsigned int i;
for (i = 0; i < ctx->nregs; i++)
@@ -818,7 +820,7 @@ static void s5p_hash_write_iv(struct ahash_request *req)
*/
static void s5p_hash_copy_result(struct ahash_request *req)
{
- struct s5p_hash_reqctx *ctx = ahash_request_ctx(req);
+ const struct s5p_hash_reqctx *ctx = ahash_request_ctx(req);
if (!req->result)
return;
@@ -1210,9 +1212,6 @@ static int s5p_hash_prepare_request(struct ahash_request *req, bool update)
int xmit_len, hash_later, nbytes;
int ret;
- if (!req)
- return 0;
-
if (update)
nbytes = req->nbytes;
else
@@ -1293,7 +1292,7 @@ static int s5p_hash_prepare_request(struct ahash_request *req, bool update)
*/
static void s5p_hash_update_dma_stop(struct s5p_aes_dev *dd)
{
- struct s5p_hash_reqctx *ctx = ahash_request_ctx(dd->hash_req);
+ const struct s5p_hash_reqctx *ctx = ahash_request_ctx(dd->hash_req);
dma_unmap_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE);
clear_bit(HASH_FLAGS_DMA_ACTIVE, &dd->hash_flags);
@@ -1720,7 +1719,7 @@ static void s5p_hash_cra_exit(struct crypto_tfm *tfm)
*/
static int s5p_hash_export(struct ahash_request *req, void *out)
{
- struct s5p_hash_reqctx *ctx = ahash_request_ctx(req);
+ const struct s5p_hash_reqctx *ctx = ahash_request_ctx(req);
memcpy(out, ctx, sizeof(*ctx) + ctx->bufcnt);
@@ -1834,7 +1833,8 @@ static struct ahash_alg algs_sha1_md5_sha256[] = {
};
static void s5p_set_aes(struct s5p_aes_dev *dev,
- uint8_t *key, uint8_t *iv, unsigned int keylen)
+ const uint8_t *key, const uint8_t *iv,
+ unsigned int keylen)
{
void __iomem *keystart;
@@ -2153,7 +2153,7 @@ static int s5p_aes_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int i, j, err = -ENODEV;
- struct samsung_aes_variant *variant;
+ const struct samsung_aes_variant *variant;
struct s5p_aes_dev *pdata;
struct resource *res;
unsigned int hash_i;
diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c
index 08e7bdcaa6e3..0f2245e1af2b 100644
--- a/drivers/crypto/sahara.c
+++ b/drivers/crypto/sahara.c
@@ -1397,11 +1397,9 @@ static int sahara_probe(struct platform_device *pdev)
int err;
int i;
- dev = devm_kzalloc(&pdev->dev, sizeof(struct sahara_dev), GFP_KERNEL);
- if (dev == NULL) {
- dev_err(&pdev->dev, "unable to alloc data struct.\n");
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
return -ENOMEM;
- }
dev->device = &pdev->dev;
platform_set_drvdata(pdev, dev);
diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c
index 4a06a7a665ee..c5d3efc54a4f 100644
--- a/drivers/crypto/stm32/stm32-cryp.c
+++ b/drivers/crypto/stm32/stm32-cryp.c
@@ -17,6 +17,7 @@
#include <crypto/des.h>
#include <crypto/engine.h>
#include <crypto/scatterwalk.h>
+#include <crypto/internal/aead.h>
#define DRIVER_NAME "stm32-cryp"
@@ -29,8 +30,12 @@
#define FLG_ECB BIT(4)
#define FLG_CBC BIT(5)
#define FLG_CTR BIT(6)
+#define FLG_GCM BIT(7)
+#define FLG_CCM BIT(8)
/* Mode mask = bits [15..0] */
#define FLG_MODE_MASK GENMASK(15, 0)
+/* Bit [31..16] status */
+#define FLG_CCM_PADDED_WA BIT(16)
/* Registers */
#define CRYP_CR 0x00000000
@@ -53,6 +58,8 @@
#define CRYP_IV0RR 0x00000044
#define CRYP_IV1LR 0x00000048
#define CRYP_IV1RR 0x0000004C
+#define CRYP_CSGCMCCM0R 0x00000050
+#define CRYP_CSGCM0R 0x00000070
/* Registers values */
#define CR_DEC_NOT_ENC 0x00000004
@@ -64,6 +71,8 @@
#define CR_AES_CBC 0x00000028
#define CR_AES_CTR 0x00000030
#define CR_AES_KP 0x00000038
+#define CR_AES_GCM 0x00080000
+#define CR_AES_CCM 0x00080008
#define CR_AES_UNKNOWN 0xFFFFFFFF
#define CR_ALGO_MASK 0x00080038
#define CR_DATA32 0x00000000
@@ -75,6 +84,12 @@
#define CR_KEY256 0x00000200
#define CR_FFLUSH 0x00004000
#define CR_CRYPEN 0x00008000
+#define CR_PH_INIT 0x00000000
+#define CR_PH_HEADER 0x00010000
+#define CR_PH_PAYLOAD 0x00020000
+#define CR_PH_FINAL 0x00030000
+#define CR_PH_MASK 0x00030000
+#define CR_NBPBL_SHIFT 20
#define SR_BUSY 0x00000010
#define SR_OFNE 0x00000004
@@ -87,10 +102,17 @@
/* Misc */
#define AES_BLOCK_32 (AES_BLOCK_SIZE / sizeof(u32))
+#define GCM_CTR_INIT 2
#define _walked_in (cryp->in_walk.offset - cryp->in_sg->offset)
#define _walked_out (cryp->out_walk.offset - cryp->out_sg->offset)
+struct stm32_cryp_caps {
+ bool swap_final;
+ bool padding_wa;
+};
+
struct stm32_cryp_ctx {
+ struct crypto_engine_ctx enginectx;
struct stm32_cryp *cryp;
int keylen;
u32 key[AES_KEYSIZE_256 / sizeof(u32)];
@@ -108,13 +130,16 @@ struct stm32_cryp {
struct clk *clk;
unsigned long flags;
u32 irq_status;
+ const struct stm32_cryp_caps *caps;
struct stm32_cryp_ctx *ctx;
struct crypto_engine *engine;
- struct mutex lock; /* protects req */
+ struct mutex lock; /* protects req / areq */
struct ablkcipher_request *req;
+ struct aead_request *areq;
+ size_t authsize;
size_t hw_blocksize;
size_t total_in;
@@ -137,6 +162,7 @@ struct stm32_cryp {
struct scatter_walk out_walk;
u32 last_ctr[4];
+ u32 gcm_ctr;
};
struct stm32_cryp_list {
@@ -179,6 +205,16 @@ static inline bool is_ctr(struct stm32_cryp *cryp)
return cryp->flags & FLG_CTR;
}
+static inline bool is_gcm(struct stm32_cryp *cryp)
+{
+ return cryp->flags & FLG_GCM;
+}
+
+static inline bool is_ccm(struct stm32_cryp *cryp)
+{
+ return cryp->flags & FLG_CCM;
+}
+
static inline bool is_encrypt(struct stm32_cryp *cryp)
{
return cryp->flags & FLG_ENCRYPT;
@@ -207,6 +243,24 @@ static inline int stm32_cryp_wait_busy(struct stm32_cryp *cryp)
!(status & SR_BUSY), 10, 100000);
}
+static inline int stm32_cryp_wait_enable(struct stm32_cryp *cryp)
+{
+ u32 status;
+
+ return readl_relaxed_poll_timeout(cryp->regs + CRYP_CR, status,
+ !(status & CR_CRYPEN), 10, 100000);
+}
+
+static inline int stm32_cryp_wait_output(struct stm32_cryp *cryp)
+{
+ u32 status;
+
+ return readl_relaxed_poll_timeout(cryp->regs + CRYP_SR, status,
+ status & SR_OFNE, 10, 100000);
+}
+
+static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp);
+
static struct stm32_cryp *stm32_cryp_find_dev(struct stm32_cryp_ctx *ctx)
{
struct stm32_cryp *tmp, *cryp = NULL;
@@ -365,6 +419,12 @@ static u32 stm32_cryp_get_hw_mode(struct stm32_cryp *cryp)
if (is_aes(cryp) && is_ctr(cryp))
return CR_AES_CTR;
+ if (is_aes(cryp) && is_gcm(cryp))
+ return CR_AES_GCM;
+
+ if (is_aes(cryp) && is_ccm(cryp))
+ return CR_AES_CCM;
+
if (is_des(cryp) && is_ecb(cryp))
return CR_DES_ECB;
@@ -381,6 +441,79 @@ static u32 stm32_cryp_get_hw_mode(struct stm32_cryp *cryp)
return CR_AES_UNKNOWN;
}
+static unsigned int stm32_cryp_get_input_text_len(struct stm32_cryp *cryp)
+{
+ return is_encrypt(cryp) ? cryp->areq->cryptlen :
+ cryp->areq->cryptlen - cryp->authsize;
+}
+
+static int stm32_cryp_gcm_init(struct stm32_cryp *cryp, u32 cfg)
+{
+ int ret;
+ u32 iv[4];
+
+ /* Phase 1 : init */
+ memcpy(iv, cryp->areq->iv, 12);
+ iv[3] = cpu_to_be32(GCM_CTR_INIT);
+ cryp->gcm_ctr = GCM_CTR_INIT;
+ stm32_cryp_hw_write_iv(cryp, iv);
+
+ stm32_cryp_write(cryp, CRYP_CR, cfg | CR_PH_INIT | CR_CRYPEN);
+
+ /* Wait for end of processing */
+ ret = stm32_cryp_wait_enable(cryp);
+ if (ret)
+ dev_err(cryp->dev, "Timeout (gcm init)\n");
+
+ return ret;
+}
+
+static int stm32_cryp_ccm_init(struct stm32_cryp *cryp, u32 cfg)
+{
+ int ret;
+ u8 iv[AES_BLOCK_SIZE], b0[AES_BLOCK_SIZE];
+ u32 *d;
+ unsigned int i, textlen;
+
+ /* Phase 1 : init. Firstly set the CTR value to 1 (not 0) */
+ memcpy(iv, cryp->areq->iv, AES_BLOCK_SIZE);
+ memset(iv + AES_BLOCK_SIZE - 1 - iv[0], 0, iv[0] + 1);
+ iv[AES_BLOCK_SIZE - 1] = 1;
+ stm32_cryp_hw_write_iv(cryp, (u32 *)iv);
+
+ /* Build B0 */
+ memcpy(b0, iv, AES_BLOCK_SIZE);
+
+ b0[0] |= (8 * ((cryp->authsize - 2) / 2));
+
+ if (cryp->areq->assoclen)
+ b0[0] |= 0x40;
+
+ textlen = stm32_cryp_get_input_text_len(cryp);
+
+ b0[AES_BLOCK_SIZE - 2] = textlen >> 8;
+ b0[AES_BLOCK_SIZE - 1] = textlen & 0xFF;
+
+ /* Enable HW */
+ stm32_cryp_write(cryp, CRYP_CR, cfg | CR_PH_INIT | CR_CRYPEN);
+
+ /* Write B0 */
+ d = (u32 *)b0;
+
+ for (i = 0; i < AES_BLOCK_32; i++) {
+ if (!cryp->caps->padding_wa)
+ *d = cpu_to_be32(*d);
+ stm32_cryp_write(cryp, CRYP_DIN, *d++);
+ }
+
+ /* Wait for end of processing */
+ ret = stm32_cryp_wait_enable(cryp);
+ if (ret)
+ dev_err(cryp->dev, "Timeout (ccm init)\n");
+
+ return ret;
+}
+
static int stm32_cryp_hw_init(struct stm32_cryp *cryp)
{
int ret;
@@ -436,6 +569,29 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp)
stm32_cryp_write(cryp, CRYP_CR, cfg);
switch (hw_mode) {
+ case CR_AES_GCM:
+ case CR_AES_CCM:
+ /* Phase 1 : init */
+ if (hw_mode == CR_AES_CCM)
+ ret = stm32_cryp_ccm_init(cryp, cfg);
+ else
+ ret = stm32_cryp_gcm_init(cryp, cfg);
+
+ if (ret)
+ return ret;
+
+ /* Phase 2 : header (authenticated data) */
+ if (cryp->areq->assoclen) {
+ cfg |= CR_PH_HEADER;
+ } else if (stm32_cryp_get_input_text_len(cryp)) {
+ cfg |= CR_PH_PAYLOAD;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+ } else {
+ cfg |= CR_PH_INIT;
+ }
+
+ break;
+
case CR_DES_CBC:
case CR_TDES_CBC:
case CR_AES_CBC:
@@ -452,12 +608,16 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp)
stm32_cryp_write(cryp, CRYP_CR, cfg);
+ cryp->flags &= ~FLG_CCM_PADDED_WA;
+
return 0;
}
-static void stm32_cryp_finish_req(struct stm32_cryp *cryp)
+static void stm32_cryp_finish_req(struct stm32_cryp *cryp, int err)
{
- int err = 0;
+ if (!err && (is_gcm(cryp) || is_ccm(cryp)))
+ /* Phase 4 : output tag */
+ err = stm32_cryp_read_auth_tag(cryp);
if (cryp->sgs_copied) {
void *buf_in, *buf_out;
@@ -478,8 +638,14 @@ static void stm32_cryp_finish_req(struct stm32_cryp *cryp)
free_pages((unsigned long)buf_out, pages);
}
- crypto_finalize_cipher_request(cryp->engine, cryp->req, err);
- cryp->req = NULL;
+ if (is_gcm(cryp) || is_ccm(cryp)) {
+ crypto_finalize_aead_request(cryp->engine, cryp->areq, err);
+ cryp->areq = NULL;
+ } else {
+ crypto_finalize_ablkcipher_request(cryp->engine, cryp->req,
+ err);
+ cryp->req = NULL;
+ }
memset(cryp->ctx->key, 0, cryp->ctx->keylen);
@@ -494,10 +660,36 @@ static int stm32_cryp_cpu_start(struct stm32_cryp *cryp)
return 0;
}
+static int stm32_cryp_cipher_one_req(struct crypto_engine *engine, void *areq);
+static int stm32_cryp_prepare_cipher_req(struct crypto_engine *engine,
+ void *areq);
+
static int stm32_cryp_cra_init(struct crypto_tfm *tfm)
{
+ struct stm32_cryp_ctx *ctx = crypto_tfm_ctx(tfm);
+
tfm->crt_ablkcipher.reqsize = sizeof(struct stm32_cryp_reqctx);
+ ctx->enginectx.op.do_one_request = stm32_cryp_cipher_one_req;
+ ctx->enginectx.op.prepare_request = stm32_cryp_prepare_cipher_req;
+ ctx->enginectx.op.unprepare_request = NULL;
+ return 0;
+}
+
+static int stm32_cryp_aead_one_req(struct crypto_engine *engine, void *areq);
+static int stm32_cryp_prepare_aead_req(struct crypto_engine *engine,
+ void *areq);
+
+static int stm32_cryp_aes_aead_init(struct crypto_aead *tfm)
+{
+ struct stm32_cryp_ctx *ctx = crypto_aead_ctx(tfm);
+
+ tfm->reqsize = sizeof(struct stm32_cryp_reqctx);
+
+ ctx->enginectx.op.do_one_request = stm32_cryp_aead_one_req;
+ ctx->enginectx.op.prepare_request = stm32_cryp_prepare_aead_req;
+ ctx->enginectx.op.unprepare_request = NULL;
+
return 0;
}
@@ -513,7 +705,21 @@ static int stm32_cryp_crypt(struct ablkcipher_request *req, unsigned long mode)
rctx->mode = mode;
- return crypto_transfer_cipher_request_to_engine(cryp->engine, req);
+ return crypto_transfer_ablkcipher_request_to_engine(cryp->engine, req);
+}
+
+static int stm32_cryp_aead_crypt(struct aead_request *req, unsigned long mode)
+{
+ struct stm32_cryp_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+ struct stm32_cryp_reqctx *rctx = aead_request_ctx(req);
+ struct stm32_cryp *cryp = stm32_cryp_find_dev(ctx);
+
+ if (!cryp)
+ return -ENODEV;
+
+ rctx->mode = mode;
+
+ return crypto_transfer_aead_request_to_engine(cryp->engine, req);
}
static int stm32_cryp_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
@@ -555,6 +761,46 @@ static int stm32_cryp_tdes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
return stm32_cryp_setkey(tfm, key, keylen);
}
+static int stm32_cryp_aes_aead_setkey(struct crypto_aead *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct stm32_cryp_ctx *ctx = crypto_aead_ctx(tfm);
+
+ if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 &&
+ keylen != AES_KEYSIZE_256)
+ return -EINVAL;
+
+ memcpy(ctx->key, key, keylen);
+ ctx->keylen = keylen;
+
+ return 0;
+}
+
+static int stm32_cryp_aes_gcm_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ return authsize == AES_BLOCK_SIZE ? 0 : -EINVAL;
+}
+
+static int stm32_cryp_aes_ccm_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ switch (authsize) {
+ case 4:
+ case 6:
+ case 8:
+ case 10:
+ case 12:
+ case 14:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int stm32_cryp_aes_ecb_encrypt(struct ablkcipher_request *req)
{
return stm32_cryp_crypt(req, FLG_AES | FLG_ECB | FLG_ENCRYPT);
@@ -585,6 +831,26 @@ static int stm32_cryp_aes_ctr_decrypt(struct ablkcipher_request *req)
return stm32_cryp_crypt(req, FLG_AES | FLG_CTR);
}
+static int stm32_cryp_aes_gcm_encrypt(struct aead_request *req)
+{
+ return stm32_cryp_aead_crypt(req, FLG_AES | FLG_GCM | FLG_ENCRYPT);
+}
+
+static int stm32_cryp_aes_gcm_decrypt(struct aead_request *req)
+{
+ return stm32_cryp_aead_crypt(req, FLG_AES | FLG_GCM);
+}
+
+static int stm32_cryp_aes_ccm_encrypt(struct aead_request *req)
+{
+ return stm32_cryp_aead_crypt(req, FLG_AES | FLG_CCM | FLG_ENCRYPT);
+}
+
+static int stm32_cryp_aes_ccm_decrypt(struct aead_request *req)
+{
+ return stm32_cryp_aead_crypt(req, FLG_AES | FLG_CCM);
+}
+
static int stm32_cryp_des_ecb_encrypt(struct ablkcipher_request *req)
{
return stm32_cryp_crypt(req, FLG_DES | FLG_ECB | FLG_ENCRYPT);
@@ -625,18 +891,19 @@ static int stm32_cryp_tdes_cbc_decrypt(struct ablkcipher_request *req)
return stm32_cryp_crypt(req, FLG_TDES | FLG_CBC);
}
-static int stm32_cryp_prepare_req(struct crypto_engine *engine,
- struct ablkcipher_request *req)
+static int stm32_cryp_prepare_req(struct ablkcipher_request *req,
+ struct aead_request *areq)
{
struct stm32_cryp_ctx *ctx;
struct stm32_cryp *cryp;
struct stm32_cryp_reqctx *rctx;
int ret;
- if (!req)
+ if (!req && !areq)
return -EINVAL;
- ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
+ ctx = req ? crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req)) :
+ crypto_aead_ctx(crypto_aead_reqtfm(areq));
cryp = ctx->cryp;
@@ -645,7 +912,7 @@ static int stm32_cryp_prepare_req(struct crypto_engine *engine,
mutex_lock(&cryp->lock);
- rctx = ablkcipher_request_ctx(req);
+ rctx = req ? ablkcipher_request_ctx(req) : aead_request_ctx(areq);
rctx->mode &= FLG_MODE_MASK;
ctx->cryp = cryp;
@@ -654,15 +921,48 @@ static int stm32_cryp_prepare_req(struct crypto_engine *engine,
cryp->hw_blocksize = is_aes(cryp) ? AES_BLOCK_SIZE : DES_BLOCK_SIZE;
cryp->ctx = ctx;
- cryp->req = req;
- cryp->total_in = req->nbytes;
- cryp->total_out = cryp->total_in;
+ if (req) {
+ cryp->req = req;
+ cryp->total_in = req->nbytes;
+ cryp->total_out = cryp->total_in;
+ } else {
+ /*
+ * Length of input and output data:
+ * Encryption case:
+ * INPUT = AssocData || PlainText
+ * <- assoclen -> <- cryptlen ->
+ * <------- total_in ----------->
+ *
+ * OUTPUT = AssocData || CipherText || AuthTag
+ * <- assoclen -> <- cryptlen -> <- authsize ->
+ * <---------------- total_out ----------------->
+ *
+ * Decryption case:
+ * INPUT = AssocData || CipherText || AuthTag
+ * <- assoclen -> <--------- cryptlen --------->
+ * <- authsize ->
+ * <---------------- total_in ------------------>
+ *
+ * OUTPUT = AssocData || PlainText
+ * <- assoclen -> <- crypten - authsize ->
+ * <---------- total_out ----------------->
+ */
+ cryp->areq = areq;
+ cryp->authsize = crypto_aead_authsize(crypto_aead_reqtfm(areq));
+ cryp->total_in = areq->assoclen + areq->cryptlen;
+ if (is_encrypt(cryp))
+ /* Append auth tag to output */
+ cryp->total_out = cryp->total_in + cryp->authsize;
+ else
+ /* No auth tag in output */
+ cryp->total_out = cryp->total_in - cryp->authsize;
+ }
cryp->total_in_save = cryp->total_in;
cryp->total_out_save = cryp->total_out;
- cryp->in_sg = req->src;
- cryp->out_sg = req->dst;
+ cryp->in_sg = req ? req->src : areq->src;
+ cryp->out_sg = req ? req->dst : areq->dst;
cryp->out_sg_save = cryp->out_sg;
cryp->in_sg_len = sg_nents_for_len(cryp->in_sg, cryp->total_in);
@@ -686,6 +986,12 @@ static int stm32_cryp_prepare_req(struct crypto_engine *engine,
scatterwalk_start(&cryp->in_walk, cryp->in_sg);
scatterwalk_start(&cryp->out_walk, cryp->out_sg);
+ if (is_gcm(cryp) || is_ccm(cryp)) {
+ /* In output, jump after assoc data */
+ scatterwalk_advance(&cryp->out_walk, cryp->areq->assoclen);
+ cryp->total_out -= cryp->areq->assoclen;
+ }
+
ret = stm32_cryp_hw_init(cryp);
out:
if (ret)
@@ -695,14 +1001,20 @@ out:
}
static int stm32_cryp_prepare_cipher_req(struct crypto_engine *engine,
- struct ablkcipher_request *req)
+ void *areq)
{
- return stm32_cryp_prepare_req(engine, req);
+ struct ablkcipher_request *req = container_of(areq,
+ struct ablkcipher_request,
+ base);
+
+ return stm32_cryp_prepare_req(req, NULL);
}
-static int stm32_cryp_cipher_one_req(struct crypto_engine *engine,
- struct ablkcipher_request *req)
+static int stm32_cryp_cipher_one_req(struct crypto_engine *engine, void *areq)
{
+ struct ablkcipher_request *req = container_of(areq,
+ struct ablkcipher_request,
+ base);
struct stm32_cryp_ctx *ctx = crypto_ablkcipher_ctx(
crypto_ablkcipher_reqtfm(req));
struct stm32_cryp *cryp = ctx->cryp;
@@ -713,6 +1025,34 @@ static int stm32_cryp_cipher_one_req(struct crypto_engine *engine,
return stm32_cryp_cpu_start(cryp);
}
+static int stm32_cryp_prepare_aead_req(struct crypto_engine *engine, void *areq)
+{
+ struct aead_request *req = container_of(areq, struct aead_request,
+ base);
+
+ return stm32_cryp_prepare_req(NULL, req);
+}
+
+static int stm32_cryp_aead_one_req(struct crypto_engine *engine, void *areq)
+{
+ struct aead_request *req = container_of(areq, struct aead_request,
+ base);
+ struct stm32_cryp_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
+ struct stm32_cryp *cryp = ctx->cryp;
+
+ if (!cryp)
+ return -ENODEV;
+
+ if (unlikely(!cryp->areq->assoclen &&
+ !stm32_cryp_get_input_text_len(cryp))) {
+ /* No input data to process: get tag and finish */
+ stm32_cryp_finish_req(cryp, 0);
+ return 0;
+ }
+
+ return stm32_cryp_cpu_start(cryp);
+}
+
static u32 *stm32_cryp_next_out(struct stm32_cryp *cryp, u32 *dst,
unsigned int n)
{
@@ -745,6 +1085,111 @@ static u32 *stm32_cryp_next_in(struct stm32_cryp *cryp, u32 *src,
return (u32 *)((u8 *)src + n);
}
+static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp)
+{
+ u32 cfg, size_bit, *dst, d32;
+ u8 *d8;
+ unsigned int i, j;
+ int ret = 0;
+
+ /* Update Config */
+ cfg = stm32_cryp_read(cryp, CRYP_CR);
+
+ cfg &= ~CR_PH_MASK;
+ cfg |= CR_PH_FINAL;
+ cfg &= ~CR_DEC_NOT_ENC;
+ cfg |= CR_CRYPEN;
+
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ if (is_gcm(cryp)) {
+ /* GCM: write aad and payload size (in bits) */
+ size_bit = cryp->areq->assoclen * 8;
+ if (cryp->caps->swap_final)
+ size_bit = cpu_to_be32(size_bit);
+
+ stm32_cryp_write(cryp, CRYP_DIN, 0);
+ stm32_cryp_write(cryp, CRYP_DIN, size_bit);
+
+ size_bit = is_encrypt(cryp) ? cryp->areq->cryptlen :
+ cryp->areq->cryptlen - AES_BLOCK_SIZE;
+ size_bit *= 8;
+ if (cryp->caps->swap_final)
+ size_bit = cpu_to_be32(size_bit);
+
+ stm32_cryp_write(cryp, CRYP_DIN, 0);
+ stm32_cryp_write(cryp, CRYP_DIN, size_bit);
+ } else {
+ /* CCM: write CTR0 */
+ u8 iv[AES_BLOCK_SIZE];
+ u32 *iv32 = (u32 *)iv;
+
+ memcpy(iv, cryp->areq->iv, AES_BLOCK_SIZE);
+ memset(iv + AES_BLOCK_SIZE - 1 - iv[0], 0, iv[0] + 1);
+
+ for (i = 0; i < AES_BLOCK_32; i++) {
+ if (!cryp->caps->padding_wa)
+ *iv32 = cpu_to_be32(*iv32);
+ stm32_cryp_write(cryp, CRYP_DIN, *iv32++);
+ }
+ }
+
+ /* Wait for output data */
+ ret = stm32_cryp_wait_output(cryp);
+ if (ret) {
+ dev_err(cryp->dev, "Timeout (read tag)\n");
+ return ret;
+ }
+
+ if (is_encrypt(cryp)) {
+ /* Get and write tag */
+ dst = sg_virt(cryp->out_sg) + _walked_out;
+
+ for (i = 0; i < AES_BLOCK_32; i++) {
+ if (cryp->total_out >= sizeof(u32)) {
+ /* Read a full u32 */
+ *dst = stm32_cryp_read(cryp, CRYP_DOUT);
+
+ dst = stm32_cryp_next_out(cryp, dst,
+ sizeof(u32));
+ cryp->total_out -= sizeof(u32);
+ } else if (!cryp->total_out) {
+ /* Empty fifo out (data from input padding) */
+ stm32_cryp_read(cryp, CRYP_DOUT);
+ } else {
+ /* Read less than an u32 */
+ d32 = stm32_cryp_read(cryp, CRYP_DOUT);
+ d8 = (u8 *)&d32;
+
+ for (j = 0; j < cryp->total_out; j++) {
+ *((u8 *)dst) = *(d8++);
+ dst = stm32_cryp_next_out(cryp, dst, 1);
+ }
+ cryp->total_out = 0;
+ }
+ }
+ } else {
+ /* Get and check tag */
+ u32 in_tag[AES_BLOCK_32], out_tag[AES_BLOCK_32];
+
+ scatterwalk_map_and_copy(in_tag, cryp->in_sg,
+ cryp->total_in_save - cryp->authsize,
+ cryp->authsize, 0);
+
+ for (i = 0; i < AES_BLOCK_32; i++)
+ out_tag[i] = stm32_cryp_read(cryp, CRYP_DOUT);
+
+ if (crypto_memneq(in_tag, out_tag, cryp->authsize))
+ ret = -EBADMSG;
+ }
+
+ /* Disable cryp */
+ cfg &= ~CR_CRYPEN;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ return ret;
+}
+
static void stm32_cryp_check_ctr_counter(struct stm32_cryp *cryp)
{
u32 cr;
@@ -777,17 +1222,24 @@ static bool stm32_cryp_irq_read_data(struct stm32_cryp *cryp)
unsigned int i, j;
u32 d32, *dst;
u8 *d8;
+ size_t tag_size;
+
+ /* Do no read tag now (if any) */
+ if (is_encrypt(cryp) && (is_gcm(cryp) || is_ccm(cryp)))
+ tag_size = cryp->authsize;
+ else
+ tag_size = 0;
dst = sg_virt(cryp->out_sg) + _walked_out;
for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) {
- if (likely(cryp->total_out >= sizeof(u32))) {
+ if (likely(cryp->total_out - tag_size >= sizeof(u32))) {
/* Read a full u32 */
*dst = stm32_cryp_read(cryp, CRYP_DOUT);
dst = stm32_cryp_next_out(cryp, dst, sizeof(u32));
cryp->total_out -= sizeof(u32);
- } else if (!cryp->total_out) {
+ } else if (cryp->total_out == tag_size) {
/* Empty fifo out (data from input padding) */
d32 = stm32_cryp_read(cryp, CRYP_DOUT);
} else {
@@ -795,15 +1247,15 @@ static bool stm32_cryp_irq_read_data(struct stm32_cryp *cryp)
d32 = stm32_cryp_read(cryp, CRYP_DOUT);
d8 = (u8 *)&d32;
- for (j = 0; j < cryp->total_out; j++) {
+ for (j = 0; j < cryp->total_out - tag_size; j++) {
*((u8 *)dst) = *(d8++);
dst = stm32_cryp_next_out(cryp, dst, 1);
}
- cryp->total_out = 0;
+ cryp->total_out = tag_size;
}
}
- return !cryp->total_out || !cryp->total_in;
+ return !(cryp->total_out - tag_size) || !cryp->total_in;
}
static void stm32_cryp_irq_write_block(struct stm32_cryp *cryp)
@@ -811,33 +1263,219 @@ static void stm32_cryp_irq_write_block(struct stm32_cryp *cryp)
unsigned int i, j;
u32 *src;
u8 d8[4];
+ size_t tag_size;
+
+ /* Do no write tag (if any) */
+ if (is_decrypt(cryp) && (is_gcm(cryp) || is_ccm(cryp)))
+ tag_size = cryp->authsize;
+ else
+ tag_size = 0;
src = sg_virt(cryp->in_sg) + _walked_in;
for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) {
- if (likely(cryp->total_in >= sizeof(u32))) {
+ if (likely(cryp->total_in - tag_size >= sizeof(u32))) {
/* Write a full u32 */
stm32_cryp_write(cryp, CRYP_DIN, *src);
src = stm32_cryp_next_in(cryp, src, sizeof(u32));
cryp->total_in -= sizeof(u32);
- } else if (!cryp->total_in) {
+ } else if (cryp->total_in == tag_size) {
/* Write padding data */
stm32_cryp_write(cryp, CRYP_DIN, 0);
} else {
/* Write less than an u32 */
memset(d8, 0, sizeof(u32));
- for (j = 0; j < cryp->total_in; j++) {
+ for (j = 0; j < cryp->total_in - tag_size; j++) {
d8[j] = *((u8 *)src);
src = stm32_cryp_next_in(cryp, src, 1);
}
stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8);
- cryp->total_in = 0;
+ cryp->total_in = tag_size;
}
}
}
+static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp)
+{
+ int err;
+ u32 cfg, tmp[AES_BLOCK_32];
+ size_t total_in_ori = cryp->total_in;
+ struct scatterlist *out_sg_ori = cryp->out_sg;
+ unsigned int i;
+
+ /* 'Special workaround' procedure described in the datasheet */
+
+ /* a) disable ip */
+ stm32_cryp_write(cryp, CRYP_IMSCR, 0);
+ cfg = stm32_cryp_read(cryp, CRYP_CR);
+ cfg &= ~CR_CRYPEN;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ /* b) Update IV1R */
+ stm32_cryp_write(cryp, CRYP_IV1RR, cryp->gcm_ctr - 2);
+
+ /* c) change mode to CTR */
+ cfg &= ~CR_ALGO_MASK;
+ cfg |= CR_AES_CTR;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ /* a) enable IP */
+ cfg |= CR_CRYPEN;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ /* b) pad and write the last block */
+ stm32_cryp_irq_write_block(cryp);
+ cryp->total_in = total_in_ori;
+ err = stm32_cryp_wait_output(cryp);
+ if (err) {
+ dev_err(cryp->dev, "Timeout (write gcm header)\n");
+ return stm32_cryp_finish_req(cryp, err);
+ }
+
+ /* c) get and store encrypted data */
+ stm32_cryp_irq_read_data(cryp);
+ scatterwalk_map_and_copy(tmp, out_sg_ori,
+ cryp->total_in_save - total_in_ori,
+ total_in_ori, 0);
+
+ /* d) change mode back to AES GCM */
+ cfg &= ~CR_ALGO_MASK;
+ cfg |= CR_AES_GCM;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ /* e) change phase to Final */
+ cfg &= ~CR_PH_MASK;
+ cfg |= CR_PH_FINAL;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ /* f) write padded data */
+ for (i = 0; i < AES_BLOCK_32; i++) {
+ if (cryp->total_in)
+ stm32_cryp_write(cryp, CRYP_DIN, tmp[i]);
+ else
+ stm32_cryp_write(cryp, CRYP_DIN, 0);
+
+ cryp->total_in -= min_t(size_t, sizeof(u32), cryp->total_in);
+ }
+
+ /* g) Empty fifo out */
+ err = stm32_cryp_wait_output(cryp);
+ if (err) {
+ dev_err(cryp->dev, "Timeout (write gcm header)\n");
+ return stm32_cryp_finish_req(cryp, err);
+ }
+
+ for (i = 0; i < AES_BLOCK_32; i++)
+ stm32_cryp_read(cryp, CRYP_DOUT);
+
+ /* h) run the he normal Final phase */
+ stm32_cryp_finish_req(cryp, 0);
+}
+
+static void stm32_cryp_irq_set_npblb(struct stm32_cryp *cryp)
+{
+ u32 cfg, payload_bytes;
+
+ /* disable ip, set NPBLB and reneable ip */
+ cfg = stm32_cryp_read(cryp, CRYP_CR);
+ cfg &= ~CR_CRYPEN;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ payload_bytes = is_decrypt(cryp) ? cryp->total_in - cryp->authsize :
+ cryp->total_in;
+ cfg |= (cryp->hw_blocksize - payload_bytes) << CR_NBPBL_SHIFT;
+ cfg |= CR_CRYPEN;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+}
+
+static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp)
+{
+ int err = 0;
+ u32 cfg, iv1tmp;
+ u32 cstmp1[AES_BLOCK_32], cstmp2[AES_BLOCK_32], tmp[AES_BLOCK_32];
+ size_t last_total_out, total_in_ori = cryp->total_in;
+ struct scatterlist *out_sg_ori = cryp->out_sg;
+ unsigned int i;
+
+ /* 'Special workaround' procedure described in the datasheet */
+ cryp->flags |= FLG_CCM_PADDED_WA;
+
+ /* a) disable ip */
+ stm32_cryp_write(cryp, CRYP_IMSCR, 0);
+
+ cfg = stm32_cryp_read(cryp, CRYP_CR);
+ cfg &= ~CR_CRYPEN;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ /* b) get IV1 from CRYP_CSGCMCCM7 */
+ iv1tmp = stm32_cryp_read(cryp, CRYP_CSGCMCCM0R + 7 * 4);
+
+ /* c) Load CRYP_CSGCMCCMxR */
+ for (i = 0; i < ARRAY_SIZE(cstmp1); i++)
+ cstmp1[i] = stm32_cryp_read(cryp, CRYP_CSGCMCCM0R + i * 4);
+
+ /* d) Write IV1R */
+ stm32_cryp_write(cryp, CRYP_IV1RR, iv1tmp);
+
+ /* e) change mode to CTR */
+ cfg &= ~CR_ALGO_MASK;
+ cfg |= CR_AES_CTR;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ /* a) enable IP */
+ cfg |= CR_CRYPEN;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ /* b) pad and write the last block */
+ stm32_cryp_irq_write_block(cryp);
+ cryp->total_in = total_in_ori;
+ err = stm32_cryp_wait_output(cryp);
+ if (err) {
+ dev_err(cryp->dev, "Timeout (wite ccm padded data)\n");
+ return stm32_cryp_finish_req(cryp, err);
+ }
+
+ /* c) get and store decrypted data */
+ last_total_out = cryp->total_out;
+ stm32_cryp_irq_read_data(cryp);
+
+ memset(tmp, 0, sizeof(tmp));
+ scatterwalk_map_and_copy(tmp, out_sg_ori,
+ cryp->total_out_save - last_total_out,
+ last_total_out, 0);
+
+ /* d) Load again CRYP_CSGCMCCMxR */
+ for (i = 0; i < ARRAY_SIZE(cstmp2); i++)
+ cstmp2[i] = stm32_cryp_read(cryp, CRYP_CSGCMCCM0R + i * 4);
+
+ /* e) change mode back to AES CCM */
+ cfg &= ~CR_ALGO_MASK;
+ cfg |= CR_AES_CCM;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ /* f) change phase to header */
+ cfg &= ~CR_PH_MASK;
+ cfg |= CR_PH_HEADER;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ /* g) XOR and write padded data */
+ for (i = 0; i < ARRAY_SIZE(tmp); i++) {
+ tmp[i] ^= cstmp1[i];
+ tmp[i] ^= cstmp2[i];
+ stm32_cryp_write(cryp, CRYP_DIN, tmp[i]);
+ }
+
+ /* h) wait for completion */
+ err = stm32_cryp_wait_busy(cryp);
+ if (err)
+ dev_err(cryp->dev, "Timeout (wite ccm padded data)\n");
+
+ /* i) run the he normal Final phase */
+ stm32_cryp_finish_req(cryp, err);
+}
+
static void stm32_cryp_irq_write_data(struct stm32_cryp *cryp)
{
if (unlikely(!cryp->total_in)) {
@@ -845,28 +1483,220 @@ static void stm32_cryp_irq_write_data(struct stm32_cryp *cryp)
return;
}
+ if (unlikely(cryp->total_in < AES_BLOCK_SIZE &&
+ (stm32_cryp_get_hw_mode(cryp) == CR_AES_GCM) &&
+ is_encrypt(cryp))) {
+ /* Padding for AES GCM encryption */
+ if (cryp->caps->padding_wa)
+ /* Special case 1 */
+ return stm32_cryp_irq_write_gcm_padded_data(cryp);
+
+ /* Setting padding bytes (NBBLB) */
+ stm32_cryp_irq_set_npblb(cryp);
+ }
+
+ if (unlikely((cryp->total_in - cryp->authsize < AES_BLOCK_SIZE) &&
+ (stm32_cryp_get_hw_mode(cryp) == CR_AES_CCM) &&
+ is_decrypt(cryp))) {
+ /* Padding for AES CCM decryption */
+ if (cryp->caps->padding_wa)
+ /* Special case 2 */
+ return stm32_cryp_irq_write_ccm_padded_data(cryp);
+
+ /* Setting padding bytes (NBBLB) */
+ stm32_cryp_irq_set_npblb(cryp);
+ }
+
if (is_aes(cryp) && is_ctr(cryp))
stm32_cryp_check_ctr_counter(cryp);
stm32_cryp_irq_write_block(cryp);
}
+static void stm32_cryp_irq_write_gcm_header(struct stm32_cryp *cryp)
+{
+ int err;
+ unsigned int i, j;
+ u32 cfg, *src;
+
+ src = sg_virt(cryp->in_sg) + _walked_in;
+
+ for (i = 0; i < AES_BLOCK_32; i++) {
+ stm32_cryp_write(cryp, CRYP_DIN, *src);
+
+ src = stm32_cryp_next_in(cryp, src, sizeof(u32));
+ cryp->total_in -= min_t(size_t, sizeof(u32), cryp->total_in);
+
+ /* Check if whole header written */
+ if ((cryp->total_in_save - cryp->total_in) ==
+ cryp->areq->assoclen) {
+ /* Write padding if needed */
+ for (j = i + 1; j < AES_BLOCK_32; j++)
+ stm32_cryp_write(cryp, CRYP_DIN, 0);
+
+ /* Wait for completion */
+ err = stm32_cryp_wait_busy(cryp);
+ if (err) {
+ dev_err(cryp->dev, "Timeout (gcm header)\n");
+ return stm32_cryp_finish_req(cryp, err);
+ }
+
+ if (stm32_cryp_get_input_text_len(cryp)) {
+ /* Phase 3 : payload */
+ cfg = stm32_cryp_read(cryp, CRYP_CR);
+ cfg &= ~CR_CRYPEN;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ cfg &= ~CR_PH_MASK;
+ cfg |= CR_PH_PAYLOAD;
+ cfg |= CR_CRYPEN;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+ } else {
+ /* Phase 4 : tag */
+ stm32_cryp_write(cryp, CRYP_IMSCR, 0);
+ stm32_cryp_finish_req(cryp, 0);
+ }
+
+ break;
+ }
+
+ if (!cryp->total_in)
+ break;
+ }
+}
+
+static void stm32_cryp_irq_write_ccm_header(struct stm32_cryp *cryp)
+{
+ int err;
+ unsigned int i = 0, j, k;
+ u32 alen, cfg, *src;
+ u8 d8[4];
+
+ src = sg_virt(cryp->in_sg) + _walked_in;
+ alen = cryp->areq->assoclen;
+
+ if (!_walked_in) {
+ if (cryp->areq->assoclen <= 65280) {
+ /* Write first u32 of B1 */
+ d8[0] = (alen >> 8) & 0xFF;
+ d8[1] = alen & 0xFF;
+ d8[2] = *((u8 *)src);
+ src = stm32_cryp_next_in(cryp, src, 1);
+ d8[3] = *((u8 *)src);
+ src = stm32_cryp_next_in(cryp, src, 1);
+
+ stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8);
+ i++;
+
+ cryp->total_in -= min_t(size_t, 2, cryp->total_in);
+ } else {
+ /* Build the two first u32 of B1 */
+ d8[0] = 0xFF;
+ d8[1] = 0xFE;
+ d8[2] = alen & 0xFF000000;
+ d8[3] = alen & 0x00FF0000;
+
+ stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8);
+ i++;
+
+ d8[0] = alen & 0x0000FF00;
+ d8[1] = alen & 0x000000FF;
+ d8[2] = *((u8 *)src);
+ src = stm32_cryp_next_in(cryp, src, 1);
+ d8[3] = *((u8 *)src);
+ src = stm32_cryp_next_in(cryp, src, 1);
+
+ stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8);
+ i++;
+
+ cryp->total_in -= min_t(size_t, 2, cryp->total_in);
+ }
+ }
+
+ /* Write next u32 */
+ for (; i < AES_BLOCK_32; i++) {
+ /* Build an u32 */
+ memset(d8, 0, sizeof(u32));
+ for (k = 0; k < sizeof(u32); k++) {
+ d8[k] = *((u8 *)src);
+ src = stm32_cryp_next_in(cryp, src, 1);
+
+ cryp->total_in -= min_t(size_t, 1, cryp->total_in);
+ if ((cryp->total_in_save - cryp->total_in) == alen)
+ break;
+ }
+
+ stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8);
+
+ if ((cryp->total_in_save - cryp->total_in) == alen) {
+ /* Write padding if needed */
+ for (j = i + 1; j < AES_BLOCK_32; j++)
+ stm32_cryp_write(cryp, CRYP_DIN, 0);
+
+ /* Wait for completion */
+ err = stm32_cryp_wait_busy(cryp);
+ if (err) {
+ dev_err(cryp->dev, "Timeout (ccm header)\n");
+ return stm32_cryp_finish_req(cryp, err);
+ }
+
+ if (stm32_cryp_get_input_text_len(cryp)) {
+ /* Phase 3 : payload */
+ cfg = stm32_cryp_read(cryp, CRYP_CR);
+ cfg &= ~CR_CRYPEN;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+
+ cfg &= ~CR_PH_MASK;
+ cfg |= CR_PH_PAYLOAD;
+ cfg |= CR_CRYPEN;
+ stm32_cryp_write(cryp, CRYP_CR, cfg);
+ } else {
+ /* Phase 4 : tag */
+ stm32_cryp_write(cryp, CRYP_IMSCR, 0);
+ stm32_cryp_finish_req(cryp, 0);
+ }
+
+ break;
+ }
+ }
+}
+
static irqreturn_t stm32_cryp_irq_thread(int irq, void *arg)
{
struct stm32_cryp *cryp = arg;
+ u32 ph;
if (cryp->irq_status & MISR_OUT)
/* Output FIFO IRQ: read data */
if (unlikely(stm32_cryp_irq_read_data(cryp))) {
/* All bytes processed, finish */
stm32_cryp_write(cryp, CRYP_IMSCR, 0);
- stm32_cryp_finish_req(cryp);
+ stm32_cryp_finish_req(cryp, 0);
return IRQ_HANDLED;
}
if (cryp->irq_status & MISR_IN) {
- /* Input FIFO IRQ: write data */
- stm32_cryp_irq_write_data(cryp);
+ if (is_gcm(cryp)) {
+ ph = stm32_cryp_read(cryp, CRYP_CR) & CR_PH_MASK;
+ if (unlikely(ph == CR_PH_HEADER))
+ /* Write Header */
+ stm32_cryp_irq_write_gcm_header(cryp);
+ else
+ /* Input FIFO IRQ: write data */
+ stm32_cryp_irq_write_data(cryp);
+ cryp->gcm_ctr++;
+ } else if (is_ccm(cryp)) {
+ ph = stm32_cryp_read(cryp, CRYP_CR) & CR_PH_MASK;
+ if (unlikely(ph == CR_PH_HEADER))
+ /* Write Header */
+ stm32_cryp_irq_write_ccm_header(cryp);
+ else
+ /* Input FIFO IRQ: write data */
+ stm32_cryp_irq_write_data(cryp);
+ } else {
+ /* Input FIFO IRQ: write data */
+ stm32_cryp_irq_write_data(cryp);
+ }
}
return IRQ_HANDLED;
@@ -1028,8 +1858,62 @@ static struct crypto_alg crypto_algs[] = {
},
};
+static struct aead_alg aead_algs[] = {
+{
+ .setkey = stm32_cryp_aes_aead_setkey,
+ .setauthsize = stm32_cryp_aes_gcm_setauthsize,
+ .encrypt = stm32_cryp_aes_gcm_encrypt,
+ .decrypt = stm32_cryp_aes_gcm_decrypt,
+ .init = stm32_cryp_aes_aead_init,
+ .ivsize = 12,
+ .maxauthsize = AES_BLOCK_SIZE,
+
+ .base = {
+ .cra_name = "gcm(aes)",
+ .cra_driver_name = "stm32-gcm-aes",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct stm32_cryp_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+},
+{
+ .setkey = stm32_cryp_aes_aead_setkey,
+ .setauthsize = stm32_cryp_aes_ccm_setauthsize,
+ .encrypt = stm32_cryp_aes_ccm_encrypt,
+ .decrypt = stm32_cryp_aes_ccm_decrypt,
+ .init = stm32_cryp_aes_aead_init,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+
+ .base = {
+ .cra_name = "ccm(aes)",
+ .cra_driver_name = "stm32-ccm-aes",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_ASYNC,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct stm32_cryp_ctx),
+ .cra_alignmask = 0xf,
+ .cra_module = THIS_MODULE,
+ },
+},
+};
+
+static const struct stm32_cryp_caps f7_data = {
+ .swap_final = true,
+ .padding_wa = true,
+};
+
+static const struct stm32_cryp_caps mp1_data = {
+ .swap_final = false,
+ .padding_wa = false,
+};
+
static const struct of_device_id stm32_dt_ids[] = {
- { .compatible = "st,stm32f756-cryp", },
+ { .compatible = "st,stm32f756-cryp", .data = &f7_data},
+ { .compatible = "st,stm32mp1-cryp", .data = &mp1_data},
{},
};
MODULE_DEVICE_TABLE(of, stm32_dt_ids);
@@ -1046,6 +1930,10 @@ static int stm32_cryp_probe(struct platform_device *pdev)
if (!cryp)
return -ENOMEM;
+ cryp->caps = of_device_get_match_data(dev);
+ if (!cryp->caps)
+ return -ENODEV;
+
cryp->dev = dev;
mutex_init(&cryp->lock);
@@ -1102,9 +1990,6 @@ static int stm32_cryp_probe(struct platform_device *pdev)
goto err_engine1;
}
- cryp->engine->prepare_cipher_request = stm32_cryp_prepare_cipher_req;
- cryp->engine->cipher_one_request = stm32_cryp_cipher_one_req;
-
ret = crypto_engine_start(cryp->engine);
if (ret) {
dev_err(dev, "Could not start crypto engine\n");
@@ -1117,10 +2002,16 @@ static int stm32_cryp_probe(struct platform_device *pdev)
goto err_algs;
}
+ ret = crypto_register_aeads(aead_algs, ARRAY_SIZE(aead_algs));
+ if (ret)
+ goto err_aead_algs;
+
dev_info(dev, "Initialized\n");
return 0;
+err_aead_algs:
+ crypto_unregister_algs(crypto_algs, ARRAY_SIZE(crypto_algs));
err_algs:
err_engine2:
crypto_engine_exit(cryp->engine);
@@ -1141,6 +2032,7 @@ static int stm32_cryp_remove(struct platform_device *pdev)
if (!cryp)
return -ENODEV;
+ crypto_unregister_aeads(aead_algs, ARRAY_SIZE(aead_algs));
crypto_unregister_algs(crypto_algs, ARRAY_SIZE(crypto_algs));
crypto_engine_exit(cryp->engine);
diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c
index 4ca4a264a833..981e45692695 100644
--- a/drivers/crypto/stm32/stm32-hash.c
+++ b/drivers/crypto/stm32/stm32-hash.c
@@ -122,6 +122,7 @@ enum stm32_hash_data_format {
#define HASH_DMA_THRESHOLD 50
struct stm32_hash_ctx {
+ struct crypto_engine_ctx enginectx;
struct stm32_hash_dev *hdev;
unsigned long flags;
@@ -626,7 +627,7 @@ static int stm32_hash_dma_send(struct stm32_hash_dev *hdev)
writesl(hdev->io_base + HASH_DIN, buffer,
DIV_ROUND_UP(ncp, sizeof(u32)));
}
- stm32_hash_set_nblw(hdev, DIV_ROUND_UP(ncp, sizeof(u32)));
+ stm32_hash_set_nblw(hdev, ncp);
reg = stm32_hash_read(hdev, HASH_STR);
reg |= HASH_STR_DCAL;
stm32_hash_write(hdev, HASH_STR, reg);
@@ -743,13 +744,15 @@ static int stm32_hash_final_req(struct stm32_hash_dev *hdev)
struct ahash_request *req = hdev->req;
struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req);
int err;
+ int buflen = rctx->bufcnt;
+
+ rctx->bufcnt = 0;
if (!(rctx->flags & HASH_FLAGS_CPU))
err = stm32_hash_dma_send(hdev);
else
- err = stm32_hash_xmit_cpu(hdev, rctx->buffer, rctx->bufcnt, 1);
+ err = stm32_hash_xmit_cpu(hdev, rctx->buffer, buflen, 1);
- rctx->bufcnt = 0;
return err;
}
@@ -828,15 +831,19 @@ static int stm32_hash_hw_init(struct stm32_hash_dev *hdev,
return 0;
}
+static int stm32_hash_one_request(struct crypto_engine *engine, void *areq);
+static int stm32_hash_prepare_req(struct crypto_engine *engine, void *areq);
+
static int stm32_hash_handle_queue(struct stm32_hash_dev *hdev,
struct ahash_request *req)
{
return crypto_transfer_hash_request_to_engine(hdev->engine, req);
}
-static int stm32_hash_prepare_req(struct crypto_engine *engine,
- struct ahash_request *req)
+static int stm32_hash_prepare_req(struct crypto_engine *engine, void *areq)
{
+ struct ahash_request *req = container_of(areq, struct ahash_request,
+ base);
struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx);
struct stm32_hash_request_ctx *rctx;
@@ -854,9 +861,10 @@ static int stm32_hash_prepare_req(struct crypto_engine *engine,
return stm32_hash_hw_init(hdev, rctx);
}
-static int stm32_hash_one_request(struct crypto_engine *engine,
- struct ahash_request *req)
+static int stm32_hash_one_request(struct crypto_engine *engine, void *areq)
{
+ struct ahash_request *req = container_of(areq, struct ahash_request,
+ base);
struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx);
struct stm32_hash_request_ctx *rctx;
@@ -1033,6 +1041,9 @@ static int stm32_hash_cra_init_algs(struct crypto_tfm *tfm,
if (algs_hmac_name)
ctx->flags |= HASH_FLAGS_HMAC;
+ ctx->enginectx.op.do_one_request = stm32_hash_one_request;
+ ctx->enginectx.op.prepare_request = stm32_hash_prepare_req;
+ ctx->enginectx.op.unprepare_request = NULL;
return 0;
}
@@ -1096,6 +1107,8 @@ static irqreturn_t stm32_hash_irq_handler(int irq, void *dev_id)
reg &= ~HASH_SR_OUTPUT_READY;
stm32_hash_write(hdev, HASH_SR, reg);
hdev->flags |= HASH_FLAGS_OUTPUT_READY;
+ /* Disable IT*/
+ stm32_hash_write(hdev, HASH_IMR, 0);
return IRQ_WAKE_THREAD;
}
@@ -1404,18 +1417,19 @@ MODULE_DEVICE_TABLE(of, stm32_hash_of_match);
static int stm32_hash_get_of_match(struct stm32_hash_dev *hdev,
struct device *dev)
{
- int err;
-
hdev->pdata = of_device_get_match_data(dev);
if (!hdev->pdata) {
dev_err(dev, "no compatible OF match\n");
return -EINVAL;
}
- err = of_property_read_u32(dev->of_node, "dma-maxburst",
- &hdev->dma_maxburst);
+ if (of_property_read_u32(dev->of_node, "dma-maxburst",
+ &hdev->dma_maxburst)) {
+ dev_info(dev, "dma-maxburst not specified, using 0\n");
+ hdev->dma_maxburst = 0;
+ }
- return err;
+ return 0;
}
static int stm32_hash_probe(struct platform_device *pdev)
@@ -1493,9 +1507,6 @@ static int stm32_hash_probe(struct platform_device *pdev)
goto err_engine;
}
- hdev->engine->prepare_hash_request = stm32_hash_prepare_req;
- hdev->engine->hash_one_request = stm32_hash_one_request;
-
ret = crypto_engine_start(hdev->engine);
if (ret)
goto err_engine_start;
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-core.c b/drivers/crypto/sunxi-ss/sun4i-ss-core.c
index 1547cbe13dc2..a81d89b3b7d8 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-core.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-core.c
@@ -451,6 +451,7 @@ static struct platform_driver sun4i_ss_driver = {
module_platform_driver(sun4i_ss_driver);
+MODULE_ALIAS("platform:sun4i-ss");
MODULE_DESCRIPTION("Allwinner Security System cryptographic accelerator");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Corentin LABBE <clabbe.montjoie@gmail.com>");
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 6882fa2f8bad..7cebf0a6ffbc 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -104,16 +104,34 @@ static void to_talitos_ptr_ext_or(struct talitos_ptr *ptr, u8 val, bool is_sec1)
/*
* map virtual single (contiguous) pointer to h/w descriptor pointer
*/
+static void __map_single_talitos_ptr(struct device *dev,
+ struct talitos_ptr *ptr,
+ unsigned int len, void *data,
+ enum dma_data_direction dir,
+ unsigned long attrs)
+{
+ dma_addr_t dma_addr = dma_map_single_attrs(dev, data, len, dir, attrs);
+ struct talitos_private *priv = dev_get_drvdata(dev);
+ bool is_sec1 = has_ftr_sec1(priv);
+
+ to_talitos_ptr(ptr, dma_addr, len, is_sec1);
+}
+
static void map_single_talitos_ptr(struct device *dev,
struct talitos_ptr *ptr,
unsigned int len, void *data,
enum dma_data_direction dir)
{
- dma_addr_t dma_addr = dma_map_single(dev, data, len, dir);
- struct talitos_private *priv = dev_get_drvdata(dev);
- bool is_sec1 = has_ftr_sec1(priv);
+ __map_single_talitos_ptr(dev, ptr, len, data, dir, 0);
+}
- to_talitos_ptr(ptr, dma_addr, len, is_sec1);
+static void map_single_talitos_ptr_nosync(struct device *dev,
+ struct talitos_ptr *ptr,
+ unsigned int len, void *data,
+ enum dma_data_direction dir)
+{
+ __map_single_talitos_ptr(dev, ptr, len, data, dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
}
/*
@@ -832,8 +850,6 @@ struct talitos_ctx {
unsigned int keylen;
unsigned int enckeylen;
unsigned int authkeylen;
- dma_addr_t dma_buf;
- dma_addr_t dma_hw_context;
};
#define HASH_MAX_BLOCK_SIZE SHA512_BLOCK_SIZE
@@ -888,10 +904,12 @@ static int aead_setkey(struct crypto_aead *authenc,
ctx->dma_key = dma_map_single(dev, ctx->key, ctx->keylen,
DMA_TO_DEVICE);
+ memzero_explicit(&keys, sizeof(keys));
return 0;
badkey:
crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ memzero_explicit(&keys, sizeof(keys));
return -EINVAL;
}
@@ -1130,10 +1148,10 @@ next:
return count;
}
-static int talitos_sg_map(struct device *dev, struct scatterlist *src,
- unsigned int len, struct talitos_edesc *edesc,
- struct talitos_ptr *ptr,
- int sg_count, unsigned int offset, int tbl_off)
+static int talitos_sg_map_ext(struct device *dev, struct scatterlist *src,
+ unsigned int len, struct talitos_edesc *edesc,
+ struct talitos_ptr *ptr, int sg_count,
+ unsigned int offset, int tbl_off, int elen)
{
struct talitos_private *priv = dev_get_drvdata(dev);
bool is_sec1 = has_ftr_sec1(priv);
@@ -1142,6 +1160,7 @@ static int talitos_sg_map(struct device *dev, struct scatterlist *src,
to_talitos_ptr(ptr, 0, 0, is_sec1);
return 1;
}
+ to_talitos_ptr_ext_set(ptr, elen, is_sec1);
if (sg_count == 1) {
to_talitos_ptr(ptr, sg_dma_address(src) + offset, len, is_sec1);
return sg_count;
@@ -1150,7 +1169,7 @@ static int talitos_sg_map(struct device *dev, struct scatterlist *src,
to_talitos_ptr(ptr, edesc->dma_link_tbl + offset, len, is_sec1);
return sg_count;
}
- sg_count = sg_to_link_tbl_offset(src, sg_count, offset, len,
+ sg_count = sg_to_link_tbl_offset(src, sg_count, offset, len + elen,
&edesc->link_tbl[tbl_off]);
if (sg_count == 1) {
/* Only one segment now, so no link tbl needed*/
@@ -1164,6 +1183,15 @@ static int talitos_sg_map(struct device *dev, struct scatterlist *src,
return sg_count;
}
+static int talitos_sg_map(struct device *dev, struct scatterlist *src,
+ unsigned int len, struct talitos_edesc *edesc,
+ struct talitos_ptr *ptr, int sg_count,
+ unsigned int offset, int tbl_off)
+{
+ return talitos_sg_map_ext(dev, src, len, edesc, ptr, sg_count, offset,
+ tbl_off, 0);
+}
+
/*
* fill in and submit ipsec_esp descriptor
*/
@@ -1181,7 +1209,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
unsigned int ivsize = crypto_aead_ivsize(aead);
int tbl_off = 0;
int sg_count, ret;
- int sg_link_tbl_len;
+ int elen = 0;
bool sync_needed = false;
struct talitos_private *priv = dev_get_drvdata(dev);
bool is_sec1 = has_ftr_sec1(priv);
@@ -1223,17 +1251,11 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
* extent is bytes of HMAC postpended to ciphertext,
* typically 12 for ipsec
*/
- sg_link_tbl_len = cryptlen;
-
- if (is_ipsec_esp) {
- to_talitos_ptr_ext_set(&desc->ptr[4], authsize, is_sec1);
+ if (is_ipsec_esp && (desc->hdr & DESC_HDR_MODE1_MDEU_CICV))
+ elen = authsize;
- if (desc->hdr & DESC_HDR_MODE1_MDEU_CICV)
- sg_link_tbl_len += authsize;
- }
-
- ret = talitos_sg_map(dev, areq->src, sg_link_tbl_len, edesc,
- &desc->ptr[4], sg_count, areq->assoclen, tbl_off);
+ ret = talitos_sg_map_ext(dev, areq->src, cryptlen, edesc, &desc->ptr[4],
+ sg_count, areq->assoclen, tbl_off, elen);
if (ret > 1) {
tbl_off += ret;
@@ -1404,7 +1426,6 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
edesc = kmalloc(alloc_len, GFP_DMA | flags);
if (!edesc) {
- dev_err(dev, "could not allocate edescriptor\n");
err = ERR_PTR(-ENOMEM);
goto error_sg;
}
@@ -1690,9 +1711,30 @@ static void common_nonsnoop_hash_unmap(struct device *dev,
struct ahash_request *areq)
{
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+ struct talitos_private *priv = dev_get_drvdata(dev);
+ bool is_sec1 = has_ftr_sec1(priv);
+ struct talitos_desc *desc = &edesc->desc;
+ struct talitos_desc *desc2 = desc + 1;
+
+ unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE);
+ if (desc->next_desc &&
+ desc->ptr[5].ptr != desc2->ptr[5].ptr)
+ unmap_single_talitos_ptr(dev, &desc2->ptr[5], DMA_FROM_DEVICE);
talitos_sg_unmap(dev, edesc, req_ctx->psrc, NULL, 0, 0);
+ /* When using hashctx-in, must unmap it. */
+ if (from_talitos_ptr_len(&edesc->desc.ptr[1], is_sec1))
+ unmap_single_talitos_ptr(dev, &edesc->desc.ptr[1],
+ DMA_TO_DEVICE);
+ else if (desc->next_desc)
+ unmap_single_talitos_ptr(dev, &desc2->ptr[1],
+ DMA_TO_DEVICE);
+
+ if (is_sec1 && req_ctx->nbuf)
+ unmap_single_talitos_ptr(dev, &desc->ptr[3],
+ DMA_TO_DEVICE);
+
if (edesc->dma_len)
dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
DMA_BIDIRECTIONAL);
@@ -1766,8 +1808,10 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
/* hash context in */
if (!req_ctx->first || req_ctx->swinit) {
- to_talitos_ptr(&desc->ptr[1], ctx->dma_hw_context,
- req_ctx->hw_context_size, is_sec1);
+ map_single_talitos_ptr_nosync(dev, &desc->ptr[1],
+ req_ctx->hw_context_size,
+ req_ctx->hw_context,
+ DMA_TO_DEVICE);
req_ctx->swinit = 0;
}
/* Indicate next op is not the first. */
@@ -1793,10 +1837,9 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
* data in
*/
if (is_sec1 && req_ctx->nbuf) {
- dma_addr_t dma_buf = ctx->dma_buf + req_ctx->buf_idx *
- HASH_MAX_BLOCK_SIZE;
-
- to_talitos_ptr(&desc->ptr[3], dma_buf, req_ctx->nbuf, is_sec1);
+ map_single_talitos_ptr(dev, &desc->ptr[3], req_ctx->nbuf,
+ req_ctx->buf[req_ctx->buf_idx],
+ DMA_TO_DEVICE);
} else {
sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc,
&desc->ptr[3], sg_count, offset, 0);
@@ -1812,8 +1855,10 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
crypto_ahash_digestsize(tfm),
areq->result, DMA_FROM_DEVICE);
else
- to_talitos_ptr(&desc->ptr[5], ctx->dma_hw_context,
- req_ctx->hw_context_size, is_sec1);
+ map_single_talitos_ptr_nosync(dev, &desc->ptr[5],
+ req_ctx->hw_context_size,
+ req_ctx->hw_context,
+ DMA_FROM_DEVICE);
/* last DWORD empty */
@@ -1832,9 +1877,14 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
desc->hdr |= DESC_HDR_MODE0_MDEU_CONT;
desc->hdr &= ~DESC_HDR_DONE_NOTIFY;
- to_talitos_ptr(&desc2->ptr[1], ctx->dma_hw_context,
- req_ctx->hw_context_size, is_sec1);
-
+ if (desc->ptr[1].ptr)
+ copy_talitos_ptr(&desc2->ptr[1], &desc->ptr[1],
+ is_sec1);
+ else
+ map_single_talitos_ptr_nosync(dev, &desc2->ptr[1],
+ req_ctx->hw_context_size,
+ req_ctx->hw_context,
+ DMA_TO_DEVICE);
copy_talitos_ptr(&desc2->ptr[2], &desc->ptr[2], is_sec1);
sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc,
&desc2->ptr[3], sg_count, offset, 0);
@@ -1842,8 +1892,10 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
sync_needed = true;
copy_talitos_ptr(&desc2->ptr[5], &desc->ptr[5], is_sec1);
if (req_ctx->last)
- to_talitos_ptr(&desc->ptr[5], ctx->dma_hw_context,
- req_ctx->hw_context_size, is_sec1);
+ map_single_talitos_ptr_nosync(dev, &desc->ptr[5],
+ req_ctx->hw_context_size,
+ req_ctx->hw_context,
+ DMA_FROM_DEVICE);
next_desc = dma_map_single(dev, &desc2->hdr1, TALITOS_DESC_SIZE,
DMA_BIDIRECTIONAL);
@@ -1885,8 +1937,7 @@ static int ahash_init(struct ahash_request *areq)
struct device *dev = ctx->dev;
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
unsigned int size;
- struct talitos_private *priv = dev_get_drvdata(dev);
- bool is_sec1 = has_ftr_sec1(priv);
+ dma_addr_t dma;
/* Initialize the context */
req_ctx->buf_idx = 0;
@@ -1898,18 +1949,10 @@ static int ahash_init(struct ahash_request *areq)
: TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
req_ctx->hw_context_size = size;
- if (ctx->dma_hw_context)
- dma_unmap_single(dev, ctx->dma_hw_context, size,
- DMA_BIDIRECTIONAL);
- ctx->dma_hw_context = dma_map_single(dev, req_ctx->hw_context, size,
- DMA_BIDIRECTIONAL);
- if (ctx->dma_buf)
- dma_unmap_single(dev, ctx->dma_buf, sizeof(req_ctx->buf),
- DMA_TO_DEVICE);
- if (is_sec1)
- ctx->dma_buf = dma_map_single(dev, req_ctx->buf,
- sizeof(req_ctx->buf),
- DMA_TO_DEVICE);
+ dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
+ DMA_TO_DEVICE);
+ dma_unmap_single(dev, dma, req_ctx->hw_context_size, DMA_TO_DEVICE);
+
return 0;
}
@@ -1920,12 +1963,6 @@ static int ahash_init(struct ahash_request *areq)
static int ahash_init_sha224_swinit(struct ahash_request *areq)
{
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
- struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
- struct device *dev = ctx->dev;
-
- ahash_init(areq);
- req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
req_ctx->hw_context[0] = SHA224_H0;
req_ctx->hw_context[1] = SHA224_H1;
@@ -1940,8 +1977,8 @@ static int ahash_init_sha224_swinit(struct ahash_request *areq)
req_ctx->hw_context[8] = 0;
req_ctx->hw_context[9] = 0;
- dma_sync_single_for_device(dev, ctx->dma_hw_context,
- req_ctx->hw_context_size, DMA_TO_DEVICE);
+ ahash_init(areq);
+ req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
return 0;
}
@@ -2046,13 +2083,6 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
/* request SEC to INIT hash. */
if (req_ctx->first && !req_ctx->swinit)
edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT;
- if (is_sec1) {
- dma_addr_t dma_buf = ctx->dma_buf + req_ctx->buf_idx *
- HASH_MAX_BLOCK_SIZE;
-
- dma_sync_single_for_device(dev, dma_buf,
- req_ctx->nbuf, DMA_TO_DEVICE);
- }
/* When the tfm context has a keylen, it's an HMAC.
* A first or last (ie. not middle) descriptor must request HMAC.
@@ -2106,12 +2136,15 @@ static int ahash_export(struct ahash_request *areq, void *out)
{
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
struct talitos_export_state *export = out;
- struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq);
- struct talitos_ctx *ctx = crypto_ahash_ctx(ahash);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
struct device *dev = ctx->dev;
+ dma_addr_t dma;
+
+ dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
+ DMA_FROM_DEVICE);
+ dma_unmap_single(dev, dma, req_ctx->hw_context_size, DMA_FROM_DEVICE);
- dma_sync_single_for_cpu(dev, ctx->dma_hw_context,
- req_ctx->hw_context_size, DMA_FROM_DEVICE);
memcpy(export->hw_context, req_ctx->hw_context,
req_ctx->hw_context_size);
memcpy(export->buf, req_ctx->buf[req_ctx->buf_idx], req_ctx->nbuf);
@@ -2128,39 +2161,29 @@ static int ahash_import(struct ahash_request *areq, const void *in)
{
struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
- const struct talitos_export_state *export = in;
- unsigned int size;
struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
struct device *dev = ctx->dev;
- struct talitos_private *priv = dev_get_drvdata(dev);
- bool is_sec1 = has_ftr_sec1(priv);
+ const struct talitos_export_state *export = in;
+ unsigned int size;
+ dma_addr_t dma;
memset(req_ctx, 0, sizeof(*req_ctx));
size = (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
: TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
req_ctx->hw_context_size = size;
- if (ctx->dma_hw_context)
- dma_unmap_single(dev, ctx->dma_hw_context, size,
- DMA_BIDIRECTIONAL);
-
memcpy(req_ctx->hw_context, export->hw_context, size);
- ctx->dma_hw_context = dma_map_single(dev, req_ctx->hw_context, size,
- DMA_BIDIRECTIONAL);
- if (ctx->dma_buf)
- dma_unmap_single(dev, ctx->dma_buf, sizeof(req_ctx->buf),
- DMA_TO_DEVICE);
memcpy(req_ctx->buf[0], export->buf, export->nbuf);
- if (is_sec1)
- ctx->dma_buf = dma_map_single(dev, req_ctx->buf,
- sizeof(req_ctx->buf),
- DMA_TO_DEVICE);
req_ctx->swinit = export->swinit;
req_ctx->first = export->first;
req_ctx->last = export->last;
req_ctx->to_hash_later = export->to_hash_later;
req_ctx->nbuf = export->nbuf;
+ dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
+ DMA_TO_DEVICE);
+ dma_unmap_single(dev, dma, req_ctx->hw_context_size, DMA_TO_DEVICE);
+
return 0;
}
@@ -3064,27 +3087,6 @@ static void talitos_cra_exit(struct crypto_tfm *tfm)
dma_unmap_single(dev, ctx->dma_key, ctx->keylen, DMA_TO_DEVICE);
}
-static void talitos_cra_exit_ahash(struct crypto_tfm *tfm)
-{
- struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
- struct device *dev = ctx->dev;
- unsigned int size;
-
- talitos_cra_exit(tfm);
-
- size = (crypto_ahash_digestsize(__crypto_ahash_cast(tfm)) <=
- SHA256_DIGEST_SIZE)
- ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
- : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
-
- if (ctx->dma_hw_context)
- dma_unmap_single(dev, ctx->dma_hw_context, size,
- DMA_BIDIRECTIONAL);
- if (ctx->dma_buf)
- dma_unmap_single(dev, ctx->dma_buf, HASH_MAX_BLOCK_SIZE * 2,
- DMA_TO_DEVICE);
-}
-
/*
* given the alg's descriptor header template, determine whether descriptor
* type and primary/secondary execution units required match the hw
@@ -3183,7 +3185,7 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
case CRYPTO_ALG_TYPE_AHASH:
alg = &t_alg->algt.alg.hash.halg.base;
alg->cra_init = talitos_cra_init_ahash;
- alg->cra_exit = talitos_cra_exit_ahash;
+ alg->cra_exit = talitos_cra_exit;
alg->cra_type = &crypto_ahash_type;
t_alg->algt.alg.hash.init = ahash_init;
t_alg->algt.alg.hash.update = ahash_update;
diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c
index 765f53e548ab..cb31b59c9d53 100644
--- a/drivers/crypto/ux500/cryp/cryp_core.c
+++ b/drivers/crypto/ux500/cryp/cryp_core.c
@@ -1404,9 +1404,8 @@ static void cryp_algs_unregister_all(void)
static int ux500_cryp_probe(struct platform_device *pdev)
{
int ret;
- int cryp_error = 0;
- struct resource *res = NULL;
- struct resource *res_irq = NULL;
+ struct resource *res;
+ struct resource *res_irq;
struct cryp_device_data *device_data;
struct cryp_protection_config prot = {
.privilege_access = CRYP_STATE_ENABLE
@@ -1416,7 +1415,6 @@ static int ux500_cryp_probe(struct platform_device *pdev)
dev_dbg(dev, "[%s]", __func__);
device_data = devm_kzalloc(dev, sizeof(*device_data), GFP_ATOMIC);
if (!device_data) {
- dev_err(dev, "[%s]: kzalloc() failed!", __func__);
ret = -ENOMEM;
goto out;
}
@@ -1479,15 +1477,13 @@ static int ux500_cryp_probe(struct platform_device *pdev)
goto out_clk_unprepare;
}
- cryp_error = cryp_check(device_data);
- if (cryp_error != 0) {
- dev_err(dev, "[%s]: cryp_init() failed!", __func__);
+ if (cryp_check(device_data)) {
+ dev_err(dev, "[%s]: cryp_check() failed!", __func__);
ret = -EINVAL;
goto out_power;
}
- cryp_error = cryp_configure_protection(device_data, &prot);
- if (cryp_error != 0) {
+ if (cryp_configure_protection(device_data, &prot)) {
dev_err(dev, "[%s]: cryp_configure_protection() failed!",
__func__);
ret = -EINVAL;
diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c
index 9acccad26928..2d0a677bcc76 100644
--- a/drivers/crypto/ux500/hash/hash_core.c
+++ b/drivers/crypto/ux500/hash/hash_core.c
@@ -1403,6 +1403,16 @@ out:
return ret1 ? ret1 : ret2;
}
+static int ahash_noimport(struct ahash_request *req, const void *in)
+{
+ return -ENOSYS;
+}
+
+static int ahash_noexport(struct ahash_request *req, void *out)
+{
+ return -ENOSYS;
+}
+
static int hmac_sha1_init(struct ahash_request *req)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
@@ -1507,6 +1517,8 @@ static struct hash_algo_template hash_algs[] = {
.update = ahash_update,
.final = ahash_final,
.digest = ahash_sha1_digest,
+ .export = ahash_noexport,
+ .import = ahash_noimport,
.halg.digestsize = SHA1_DIGEST_SIZE,
.halg.statesize = sizeof(struct hash_ctx),
.halg.base = {
@@ -1529,6 +1541,8 @@ static struct hash_algo_template hash_algs[] = {
.update = ahash_update,
.final = ahash_final,
.digest = ahash_sha256_digest,
+ .export = ahash_noexport,
+ .import = ahash_noimport,
.halg.digestsize = SHA256_DIGEST_SIZE,
.halg.statesize = sizeof(struct hash_ctx),
.halg.base = {
@@ -1553,6 +1567,8 @@ static struct hash_algo_template hash_algs[] = {
.final = ahash_final,
.digest = hmac_sha1_digest,
.setkey = hmac_sha1_setkey,
+ .export = ahash_noexport,
+ .import = ahash_noimport,
.halg.digestsize = SHA1_DIGEST_SIZE,
.halg.statesize = sizeof(struct hash_ctx),
.halg.base = {
@@ -1577,6 +1593,8 @@ static struct hash_algo_template hash_algs[] = {
.final = ahash_final,
.digest = hmac_sha256_digest,
.setkey = hmac_sha256_setkey,
+ .export = ahash_noexport,
+ .import = ahash_noimport,
.halg.digestsize = SHA256_DIGEST_SIZE,
.halg.statesize = sizeof(struct hash_ctx),
.halg.base = {
diff --git a/drivers/crypto/virtio/Kconfig b/drivers/crypto/virtio/Kconfig
index 5db07495ddc5..a4324b1383a4 100644
--- a/drivers/crypto/virtio/Kconfig
+++ b/drivers/crypto/virtio/Kconfig
@@ -2,7 +2,6 @@ config CRYPTO_DEV_VIRTIO
tristate "VirtIO crypto driver"
depends on VIRTIO
select CRYPTO_AEAD
- select CRYPTO_AUTHENC
select CRYPTO_BLKCIPHER
select CRYPTO_ENGINE
default m
diff --git a/drivers/crypto/virtio/virtio_crypto_algs.c b/drivers/crypto/virtio/virtio_crypto_algs.c
index abe8c15450df..ba190cfa7aa1 100644
--- a/drivers/crypto/virtio/virtio_crypto_algs.c
+++ b/drivers/crypto/virtio/virtio_crypto_algs.c
@@ -29,6 +29,7 @@
struct virtio_crypto_ablkcipher_ctx {
+ struct crypto_engine_ctx enginectx;
struct virtio_crypto *vcrypto;
struct crypto_tfm *tfm;
@@ -491,7 +492,7 @@ static int virtio_crypto_ablkcipher_encrypt(struct ablkcipher_request *req)
vc_sym_req->ablkcipher_req = req;
vc_sym_req->encrypt = true;
- return crypto_transfer_cipher_request_to_engine(data_vq->engine, req);
+ return crypto_transfer_ablkcipher_request_to_engine(data_vq->engine, req);
}
static int virtio_crypto_ablkcipher_decrypt(struct ablkcipher_request *req)
@@ -511,7 +512,7 @@ static int virtio_crypto_ablkcipher_decrypt(struct ablkcipher_request *req)
vc_sym_req->ablkcipher_req = req;
vc_sym_req->encrypt = false;
- return crypto_transfer_cipher_request_to_engine(data_vq->engine, req);
+ return crypto_transfer_ablkcipher_request_to_engine(data_vq->engine, req);
}
static int virtio_crypto_ablkcipher_init(struct crypto_tfm *tfm)
@@ -521,6 +522,9 @@ static int virtio_crypto_ablkcipher_init(struct crypto_tfm *tfm)
tfm->crt_ablkcipher.reqsize = sizeof(struct virtio_crypto_sym_request);
ctx->tfm = tfm;
+ ctx->enginectx.op.do_one_request = virtio_crypto_ablkcipher_crypt_req;
+ ctx->enginectx.op.prepare_request = NULL;
+ ctx->enginectx.op.unprepare_request = NULL;
return 0;
}
@@ -538,9 +542,9 @@ static void virtio_crypto_ablkcipher_exit(struct crypto_tfm *tfm)
}
int virtio_crypto_ablkcipher_crypt_req(
- struct crypto_engine *engine,
- struct ablkcipher_request *req)
+ struct crypto_engine *engine, void *vreq)
{
+ struct ablkcipher_request *req = container_of(vreq, struct ablkcipher_request, base);
struct virtio_crypto_sym_request *vc_sym_req =
ablkcipher_request_ctx(req);
struct virtio_crypto_request *vc_req = &vc_sym_req->base;
@@ -561,8 +565,8 @@ static void virtio_crypto_ablkcipher_finalize_req(
struct ablkcipher_request *req,
int err)
{
- crypto_finalize_cipher_request(vc_sym_req->base.dataq->engine,
- req, err);
+ crypto_finalize_ablkcipher_request(vc_sym_req->base.dataq->engine,
+ req, err);
kzfree(vc_sym_req->iv);
virtcrypto_clear_request(&vc_sym_req->base);
}
diff --git a/drivers/crypto/virtio/virtio_crypto_common.h b/drivers/crypto/virtio/virtio_crypto_common.h
index e976539a05d9..66501a5a2b7b 100644
--- a/drivers/crypto/virtio/virtio_crypto_common.h
+++ b/drivers/crypto/virtio/virtio_crypto_common.h
@@ -24,7 +24,6 @@
#include <linux/spinlock.h>
#include <crypto/aead.h>
#include <crypto/aes.h>
-#include <crypto/authenc.h>
#include <crypto/engine.h>
@@ -107,8 +106,7 @@ struct virtio_crypto *virtcrypto_get_dev_node(int node);
int virtcrypto_dev_start(struct virtio_crypto *vcrypto);
void virtcrypto_dev_stop(struct virtio_crypto *vcrypto);
int virtio_crypto_ablkcipher_crypt_req(
- struct crypto_engine *engine,
- struct ablkcipher_request *req);
+ struct crypto_engine *engine, void *vreq);
void
virtcrypto_clear_request(struct virtio_crypto_request *vc_req);
diff --git a/drivers/crypto/virtio/virtio_crypto_core.c b/drivers/crypto/virtio/virtio_crypto_core.c
index ff1410a32c2b..83326986c113 100644
--- a/drivers/crypto/virtio/virtio_crypto_core.c
+++ b/drivers/crypto/virtio/virtio_crypto_core.c
@@ -111,9 +111,6 @@ static int virtcrypto_find_vqs(struct virtio_crypto *vi)
ret = -ENOMEM;
goto err_engine;
}
-
- vi->data_vq[i].engine->cipher_one_request =
- virtio_crypto_ablkcipher_crypt_req;
}
kfree(names);
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index a7bca4207f44..de15bf55895b 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -30,7 +30,8 @@ config EXTCON_ARIZONA
config EXTCON_AXP288
tristate "X-Power AXP288 EXTCON support"
- depends on MFD_AXP20X && USB_PHY
+ depends on MFD_AXP20X && USB_SUPPORT && X86
+ select USB_ROLE_SWITCH
help
Say Y here to enable support for USB peripheral detection
and USB MUX switching by X-Power AXP288 PMIC.
diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c
index 3ec4c715e240..a983708b77a6 100644
--- a/drivers/extcon/extcon-axp288.c
+++ b/drivers/extcon/extcon-axp288.c
@@ -1,6 +1,7 @@
/*
* extcon-axp288.c - X-Power AXP288 PMIC extcon cable detection driver
*
+ * Copyright (c) 2017-2018 Hans de Goede <hdegoede@redhat.com>
* Copyright (C) 2015 Intel Corporation
* Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
*
@@ -14,6 +15,7 @@
* GNU General Public License for more details.
*/
+#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/io.h>
@@ -25,6 +27,11 @@
#include <linux/extcon-provider.h>
#include <linux/regmap.h>
#include <linux/mfd/axp20x.h>
+#include <linux/usb/role.h>
+#include <linux/workqueue.h>
+
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
/* Power source status register */
#define PS_STAT_VBUS_TRIGGER BIT(0)
@@ -97,9 +104,19 @@ struct axp288_extcon_info {
struct device *dev;
struct regmap *regmap;
struct regmap_irq_chip_data *regmap_irqc;
+ struct usb_role_switch *role_sw;
+ struct work_struct role_work;
int irq[EXTCON_IRQ_END];
struct extcon_dev *edev;
+ struct extcon_dev *id_extcon;
+ struct notifier_block id_nb;
unsigned int previous_cable;
+ bool vbus_attach;
+};
+
+static const struct x86_cpu_id cherry_trail_cpu_ids[] = {
+ { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT, X86_FEATURE_ANY },
+ {}
};
/* Power up/down reason string array */
@@ -137,20 +154,74 @@ static void axp288_extcon_log_rsi(struct axp288_extcon_info *info)
regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask);
}
-static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
+/*
+ * The below code to control the USB role-switch on devices with an AXP288
+ * may seem out of place, but there are 2 reasons why this is the best place
+ * to control the USB role-switch on such devices:
+ * 1) On many devices the USB role is controlled by AML code, but the AML code
+ * only switches between the host and none roles, because of Windows not
+ * really using device mode. To make device mode work we need to toggle
+ * between the none/device roles based on Vbus presence, and this driver
+ * gets interrupts on Vbus insertion / removal.
+ * 2) In order for our BC1.2 charger detection to work properly the role
+ * mux must be properly set to device mode before we do the detection.
+ */
+
+/* Returns the id-pin value, note pulled low / false == host-mode */
+static bool axp288_get_id_pin(struct axp288_extcon_info *info)
{
- int ret, stat, cfg, pwr_stat;
- u8 chrg_type;
- unsigned int cable = info->previous_cable;
- bool vbus_attach = false;
+ enum usb_role role;
+
+ if (info->id_extcon)
+ return extcon_get_state(info->id_extcon, EXTCON_USB_HOST) <= 0;
+
+ /* We cannot access the id-pin, see what mode the AML code has set */
+ role = usb_role_switch_get_role(info->role_sw);
+ return role != USB_ROLE_HOST;
+}
+
+static void axp288_usb_role_work(struct work_struct *work)
+{
+ struct axp288_extcon_info *info =
+ container_of(work, struct axp288_extcon_info, role_work);
+ enum usb_role role;
+ bool id_pin;
+ int ret;
+
+ id_pin = axp288_get_id_pin(info);
+ if (!id_pin)
+ role = USB_ROLE_HOST;
+ else if (info->vbus_attach)
+ role = USB_ROLE_DEVICE;
+ else
+ role = USB_ROLE_NONE;
+
+ ret = usb_role_switch_set_role(info->role_sw, role);
+ if (ret)
+ dev_err(info->dev, "failed to set role: %d\n", ret);
+}
+
+static bool axp288_get_vbus_attach(struct axp288_extcon_info *info)
+{
+ int ret, pwr_stat;
ret = regmap_read(info->regmap, AXP288_PS_STAT_REG, &pwr_stat);
if (ret < 0) {
dev_err(info->dev, "failed to read vbus status\n");
- return ret;
+ return false;
}
- vbus_attach = (pwr_stat & PS_STAT_VBUS_VALID);
+ return !!(pwr_stat & PS_STAT_VBUS_VALID);
+}
+
+static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
+{
+ int ret, stat, cfg;
+ u8 chrg_type;
+ unsigned int cable = info->previous_cable;
+ bool vbus_attach = false;
+
+ vbus_attach = axp288_get_vbus_attach(info);
if (!vbus_attach)
goto no_vbus;
@@ -201,6 +272,12 @@ no_vbus:
info->previous_cable = cable;
}
+ if (info->role_sw && info->vbus_attach != vbus_attach) {
+ info->vbus_attach = vbus_attach;
+ /* Setting the role can take a while */
+ queue_work(system_long_wq, &info->role_work);
+ }
+
return 0;
dev_det_ret:
@@ -210,6 +287,18 @@ dev_det_ret:
return ret;
}
+static int axp288_extcon_id_evt(struct notifier_block *nb,
+ unsigned long event, void *param)
+{
+ struct axp288_extcon_info *info =
+ container_of(nb, struct axp288_extcon_info, id_nb);
+
+ /* We may not sleep and setting the role can take a while */
+ queue_work(system_long_wq, &info->role_work);
+
+ return NOTIFY_OK;
+}
+
static irqreturn_t axp288_extcon_isr(int irq, void *data)
{
struct axp288_extcon_info *info = data;
@@ -231,10 +320,20 @@ static void axp288_extcon_enable(struct axp288_extcon_info *info)
BC_GLOBAL_RUN, BC_GLOBAL_RUN);
}
+static void axp288_put_role_sw(void *data)
+{
+ struct axp288_extcon_info *info = data;
+
+ cancel_work_sync(&info->role_work);
+ usb_role_switch_put(info->role_sw);
+}
+
static int axp288_extcon_probe(struct platform_device *pdev)
{
struct axp288_extcon_info *info;
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ const char *name;
int ret, i, pirq;
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
@@ -245,9 +344,33 @@ static int axp288_extcon_probe(struct platform_device *pdev)
info->regmap = axp20x->regmap;
info->regmap_irqc = axp20x->regmap_irqc;
info->previous_cable = EXTCON_NONE;
+ INIT_WORK(&info->role_work, axp288_usb_role_work);
+ info->id_nb.notifier_call = axp288_extcon_id_evt;
platform_set_drvdata(pdev, info);
+ info->role_sw = usb_role_switch_get(dev);
+ if (IS_ERR(info->role_sw))
+ return PTR_ERR(info->role_sw);
+ if (info->role_sw) {
+ ret = devm_add_action_or_reset(dev, axp288_put_role_sw, info);
+ if (ret)
+ return ret;
+
+ name = acpi_dev_get_first_match_name("INT3496", NULL, -1);
+ if (name) {
+ info->id_extcon = extcon_get_extcon_dev(name);
+ if (!info->id_extcon)
+ return -EPROBE_DEFER;
+
+ dev_info(dev, "controlling USB role\n");
+ } else {
+ dev_info(dev, "controlling USB role based on Vbus presence\n");
+ }
+ }
+
+ info->vbus_attach = axp288_get_vbus_attach(info);
+
axp288_extcon_log_rsi(info);
/* Initialize extcon device */
@@ -289,6 +412,19 @@ static int axp288_extcon_probe(struct platform_device *pdev)
}
}
+ if (info->id_extcon) {
+ ret = devm_extcon_register_notifier_all(dev, info->id_extcon,
+ &info->id_nb);
+ if (ret)
+ return ret;
+ }
+
+ /* Make sure the role-sw is set correctly before doing BC detection */
+ if (info->role_sw) {
+ queue_work(system_long_wq, &info->role_work);
+ flush_work(&info->role_work);
+ }
+
/* Start charger cable type detection */
axp288_extcon_enable(info);
@@ -308,8 +444,32 @@ static struct platform_driver axp288_extcon_driver = {
.name = "axp288_extcon",
},
};
-module_platform_driver(axp288_extcon_driver);
+
+static struct device_connection axp288_extcon_role_sw_conn = {
+ .endpoint[0] = "axp288_extcon",
+ .endpoint[1] = "intel_xhci_usb_sw-role-switch",
+ .id = "usb-role-switch",
+};
+
+static int __init axp288_extcon_init(void)
+{
+ if (x86_match_cpu(cherry_trail_cpu_ids))
+ device_connection_add(&axp288_extcon_role_sw_conn);
+
+ return platform_driver_register(&axp288_extcon_driver);
+}
+module_init(axp288_extcon_init);
+
+static void __exit axp288_extcon_exit(void)
+{
+ if (x86_match_cpu(cherry_trail_cpu_ids))
+ device_connection_remove(&axp288_extcon_role_sw_conn);
+
+ platform_driver_unregister(&axp288_extcon_driver);
+}
+module_exit(axp288_extcon_exit);
MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("X-Powers AXP288 extcon driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
index ab770adcca7e..13ba3a6e81d5 100644
--- a/drivers/extcon/extcon-gpio.c
+++ b/drivers/extcon/extcon-gpio.c
@@ -18,8 +18,6 @@
*/
#include <linux/extcon-provider.h>
-#include <linux/extcon/extcon-gpio.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -29,14 +27,30 @@
#include <linux/slab.h>
#include <linux/workqueue.h>
+/**
+ * struct gpio_extcon_data - A simple GPIO-controlled extcon device state container.
+ * @edev: Extcon device.
+ * @irq: Interrupt line for the external connector.
+ * @work: Work fired by the interrupt.
+ * @debounce_jiffies: Number of jiffies to wait for the GPIO to stabilize, from the debounce
+ * value.
+ * @gpiod: GPIO descriptor for this external connector.
+ * @extcon_id: The unique id of specific external connector.
+ * @debounce: Debounce time for GPIO IRQ in ms.
+ * @irq_flags: IRQ Flags (e.g., IRQF_TRIGGER_LOW).
+ * @check_on_resume: Boolean describing whether to check the state of gpio
+ * while resuming from sleep.
+ */
struct gpio_extcon_data {
struct extcon_dev *edev;
int irq;
struct delayed_work work;
unsigned long debounce_jiffies;
-
- struct gpio_desc *id_gpiod;
- struct gpio_extcon_pdata *pdata;
+ struct gpio_desc *gpiod;
+ unsigned int extcon_id;
+ unsigned long debounce;
+ unsigned long irq_flags;
+ bool check_on_resume;
};
static void gpio_extcon_work(struct work_struct *work)
@@ -46,11 +60,8 @@ static void gpio_extcon_work(struct work_struct *work)
container_of(to_delayed_work(work), struct gpio_extcon_data,
work);
- state = gpiod_get_value_cansleep(data->id_gpiod);
- if (data->pdata->gpio_active_low)
- state = !state;
-
- extcon_set_state_sync(data->edev, data->pdata->extcon_id, state);
+ state = gpiod_get_value_cansleep(data->gpiod);
+ extcon_set_state_sync(data->edev, data->extcon_id, state);
}
static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
@@ -62,65 +73,41 @@ static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int gpio_extcon_init(struct device *dev, struct gpio_extcon_data *data)
-{
- struct gpio_extcon_pdata *pdata = data->pdata;
- int ret;
-
- ret = devm_gpio_request_one(dev, pdata->gpio, GPIOF_DIR_IN,
- dev_name(dev));
- if (ret < 0)
- return ret;
-
- data->id_gpiod = gpio_to_desc(pdata->gpio);
- if (!data->id_gpiod)
- return -EINVAL;
-
- if (pdata->debounce) {
- ret = gpiod_set_debounce(data->id_gpiod,
- pdata->debounce * 1000);
- if (ret < 0)
- data->debounce_jiffies =
- msecs_to_jiffies(pdata->debounce);
- }
-
- data->irq = gpiod_to_irq(data->id_gpiod);
- if (data->irq < 0)
- return data->irq;
-
- return 0;
-}
-
static int gpio_extcon_probe(struct platform_device *pdev)
{
- struct gpio_extcon_pdata *pdata = dev_get_platdata(&pdev->dev);
struct gpio_extcon_data *data;
+ struct device *dev = &pdev->dev;
int ret;
- if (!pdata)
- return -EBUSY;
- if (!pdata->irq_flags || pdata->extcon_id > EXTCON_NONE)
- return -EINVAL;
-
- data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data),
- GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct gpio_extcon_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- data->pdata = pdata;
- /* Initialize the gpio */
- ret = gpio_extcon_init(&pdev->dev, data);
- if (ret < 0)
- return ret;
+ /*
+ * FIXME: extcon_id represents the unique identifier of external
+ * connectors such as EXTCON_USB, EXTCON_DISP_HDMI and so on. extcon_id
+ * is necessary to register the extcon device. But, it's not yet
+ * developed to get the extcon id from device-tree or others.
+ * On later, it have to be solved.
+ */
+ if (!data->irq_flags || data->extcon_id > EXTCON_NONE)
+ return -EINVAL;
+
+ data->gpiod = devm_gpiod_get(dev, "extcon", GPIOD_IN);
+ if (IS_ERR(data->gpiod))
+ return PTR_ERR(data->gpiod);
+ data->irq = gpiod_to_irq(data->gpiod);
+ if (data->irq <= 0)
+ return data->irq;
/* Allocate the memory of extcon devie and register extcon device */
- data->edev = devm_extcon_dev_allocate(&pdev->dev, &pdata->extcon_id);
+ data->edev = devm_extcon_dev_allocate(dev, &data->extcon_id);
if (IS_ERR(data->edev)) {
- dev_err(&pdev->dev, "failed to allocate extcon device\n");
+ dev_err(dev, "failed to allocate extcon device\n");
return -ENOMEM;
}
- ret = devm_extcon_dev_register(&pdev->dev, data->edev);
+ ret = devm_extcon_dev_register(dev, data->edev);
if (ret < 0)
return ret;
@@ -130,8 +117,8 @@ static int gpio_extcon_probe(struct platform_device *pdev)
* Request the interrupt of gpio to detect whether external connector
* is attached or detached.
*/
- ret = devm_request_any_context_irq(&pdev->dev, data->irq,
- gpio_irq_handler, pdata->irq_flags,
+ ret = devm_request_any_context_irq(dev, data->irq,
+ gpio_irq_handler, data->irq_flags,
pdev->name, data);
if (ret < 0)
return ret;
@@ -158,7 +145,7 @@ static int gpio_extcon_resume(struct device *dev)
struct gpio_extcon_data *data;
data = dev_get_drvdata(dev);
- if (data->pdata->check_on_resume)
+ if (data->check_on_resume)
queue_delayed_work(system_power_efficient_wq,
&data->work, data->debounce_jiffies);
diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c
index 7c4bc8c44c3f..b7e9ea377d70 100644
--- a/drivers/extcon/extcon-intel-cht-wc.c
+++ b/drivers/extcon/extcon-intel-cht-wc.c
@@ -66,6 +66,8 @@
#define CHT_WC_VBUS_GPIO_CTLO 0x6e2d
#define CHT_WC_VBUS_GPIO_CTLO_OUTPUT BIT(0)
+#define CHT_WC_VBUS_GPIO_CTLO_DRV_OD BIT(4)
+#define CHT_WC_VBUS_GPIO_CTLO_DIR_OUT BIT(5)
enum cht_wc_usb_id {
USB_ID_OTG,
@@ -183,14 +185,15 @@ static void cht_wc_extcon_set_5v_boost(struct cht_wc_extcon_data *ext,
{
int ret, val;
- val = enable ? CHT_WC_VBUS_GPIO_CTLO_OUTPUT : 0;
-
/*
* The 5V boost converter is enabled through a gpio on the PMIC, since
* there currently is no gpio driver we access the gpio reg directly.
*/
- ret = regmap_update_bits(ext->regmap, CHT_WC_VBUS_GPIO_CTLO,
- CHT_WC_VBUS_GPIO_CTLO_OUTPUT, val);
+ val = CHT_WC_VBUS_GPIO_CTLO_DRV_OD | CHT_WC_VBUS_GPIO_CTLO_DIR_OUT;
+ if (enable)
+ val |= CHT_WC_VBUS_GPIO_CTLO_OUTPUT;
+
+ ret = regmap_write(ext->regmap, CHT_WC_VBUS_GPIO_CTLO, val);
if (ret)
dev_err(ext->dev, "Error writing Vbus GPIO CTLO: %d\n", ret);
}
diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c
index 191e99f06a9a..acaccb128fc4 100644
--- a/drivers/extcon/extcon-intel-int3496.c
+++ b/drivers/extcon/extcon-intel-int3496.c
@@ -50,7 +50,11 @@ static const struct acpi_gpio_params vbus_gpios = { INT3496_GPIO_VBUS_EN, 0, fal
static const struct acpi_gpio_params mux_gpios = { INT3496_GPIO_USB_MUX, 0, false };
static const struct acpi_gpio_mapping acpi_int3496_default_gpios[] = {
- { "id-gpios", &id_gpios, 1 },
+ /*
+ * Some platforms have a bug in ACPI GPIO description making IRQ
+ * GPIO to be output only. Ask the GPIO core to ignore this limit.
+ */
+ { "id-gpios", &id_gpios, 1, ACPI_GPIO_QUIRK_NO_IO_RESTRICTION },
{ "vbus-gpios", &vbus_gpios, 1 },
{ "mux-gpios", &mux_gpios, 1 },
{ },
@@ -112,9 +116,6 @@ static int int3496_probe(struct platform_device *pdev)
ret = PTR_ERR(data->gpio_usb_id);
dev_err(dev, "can't request USB ID GPIO: %d\n", ret);
return ret;
- } else if (gpiod_get_direction(data->gpio_usb_id) != GPIOF_DIR_IN) {
- dev_warn(dev, FW_BUG "USB ID GPIO not in input mode, fixing\n");
- gpiod_direction_input(data->gpio_usb_id);
}
data->usb_id_irq = gpiod_to_irq(data->gpio_usb_id);
diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c
index cb38c2747684..8bff5fd18185 100644
--- a/drivers/extcon/extcon.c
+++ b/drivers/extcon/extcon.c
@@ -1336,6 +1336,28 @@ void extcon_dev_unregister(struct extcon_dev *edev)
EXPORT_SYMBOL_GPL(extcon_dev_unregister);
#ifdef CONFIG_OF
+
+/*
+ * extcon_find_edev_by_node - Find the extcon device from devicetree.
+ * @node : OF node identifying edev
+ *
+ * Return the pointer of extcon device if success or ERR_PTR(err) if fail.
+ */
+struct extcon_dev *extcon_find_edev_by_node(struct device_node *node)
+{
+ struct extcon_dev *edev;
+
+ mutex_lock(&extcon_dev_list_lock);
+ list_for_each_entry(edev, &extcon_dev_list, entry)
+ if (edev->dev.parent && edev->dev.parent->of_node == node)
+ goto out;
+ edev = ERR_PTR(-EPROBE_DEFER);
+out:
+ mutex_unlock(&extcon_dev_list_lock);
+
+ return edev;
+}
+
/*
* extcon_get_edev_by_phandle - Get the extcon device from devicetree.
* @dev : the instance to the given device
@@ -1363,25 +1385,27 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
return ERR_PTR(-ENODEV);
}
- mutex_lock(&extcon_dev_list_lock);
- list_for_each_entry(edev, &extcon_dev_list, entry) {
- if (edev->dev.parent && edev->dev.parent->of_node == node) {
- mutex_unlock(&extcon_dev_list_lock);
- of_node_put(node);
- return edev;
- }
- }
- mutex_unlock(&extcon_dev_list_lock);
+ edev = extcon_find_edev_by_node(node);
of_node_put(node);
- return ERR_PTR(-EPROBE_DEFER);
+ return edev;
}
+
#else
+
+struct extcon_dev *extcon_find_edev_by_node(struct device_node *node)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
{
return ERR_PTR(-ENOSYS);
}
+
#endif /* CONFIG_OF */
+
+EXPORT_SYMBOL_GPL(extcon_find_edev_by_node);
EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle);
/**
diff --git a/drivers/fpga/altera-cvp.c b/drivers/fpga/altera-cvp.c
index 00e73d28077c..77b04e4b3254 100644
--- a/drivers/fpga/altera-cvp.c
+++ b/drivers/fpga/altera-cvp.c
@@ -384,8 +384,6 @@ static int altera_cvp_probe(struct pci_dev *pdev,
const struct pci_device_id *dev_id);
static void altera_cvp_remove(struct pci_dev *pdev);
-#define PCI_VENDOR_ID_ALTERA 0x1172
-
static struct pci_device_id altera_cvp_id_tbl[] = {
{ PCI_VDEVICE(ALTERA, PCI_ANY_ID) },
{ }
diff --git a/drivers/fsi/Kconfig b/drivers/fsi/Kconfig
index 513e35173aaa..a326ed663d3c 100644
--- a/drivers/fsi/Kconfig
+++ b/drivers/fsi/Kconfig
@@ -4,6 +4,7 @@
menuconfig FSI
tristate "FSI support"
+ depends on OF
select CRC4
---help---
FSI - the FRU Support Interface - is a simple bus for low-level
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index e318bf8c623c..4c03d6933646 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -18,6 +18,7 @@
#include <linux/fsi.h>
#include <linux/idr.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include <linux/bitops.h>
@@ -142,6 +143,7 @@ static void fsi_device_release(struct device *_device)
{
struct fsi_device *device = to_fsi_dev(_device);
+ of_node_put(device->dev.of_node);
kfree(device);
}
@@ -205,7 +207,7 @@ static int fsi_slave_report_and_clear_errors(struct fsi_slave *slave)
if (rc)
return rc;
- dev_info(&slave->dev, "status: 0x%08x, sisc: 0x%08x\n",
+ dev_dbg(&slave->dev, "status: 0x%08x, sisc: 0x%08x\n",
be32_to_cpu(stat), be32_to_cpu(irq));
/* clear interrupts */
@@ -334,6 +336,57 @@ extern void fsi_slave_release_range(struct fsi_slave *slave,
}
EXPORT_SYMBOL_GPL(fsi_slave_release_range);
+static bool fsi_device_node_matches(struct device *dev, struct device_node *np,
+ uint32_t addr, uint32_t size)
+{
+ unsigned int len, na, ns;
+ const __be32 *prop;
+ uint32_t psize;
+
+ na = of_n_addr_cells(np);
+ ns = of_n_size_cells(np);
+
+ if (na != 1 || ns != 1)
+ return false;
+
+ prop = of_get_property(np, "reg", &len);
+ if (!prop || len != 8)
+ return false;
+
+ if (of_read_number(prop, 1) != addr)
+ return false;
+
+ psize = of_read_number(prop + 1, 1);
+ if (psize != size) {
+ dev_warn(dev,
+ "node %s matches probed address, but not size (got 0x%x, expected 0x%x)",
+ of_node_full_name(np), psize, size);
+ }
+
+ return true;
+}
+
+/* Find a matching node for the slave engine at @address, using @size bytes
+ * of space. Returns NULL if not found, or a matching node with refcount
+ * already incremented.
+ */
+static struct device_node *fsi_device_find_of_node(struct fsi_device *dev)
+{
+ struct device_node *parent, *np;
+
+ parent = dev_of_node(&dev->slave->dev);
+ if (!parent)
+ return NULL;
+
+ for_each_child_of_node(parent, np) {
+ if (fsi_device_node_matches(&dev->dev, np,
+ dev->addr, dev->size))
+ return np;
+ }
+
+ return NULL;
+}
+
static int fsi_slave_scan(struct fsi_slave *slave)
{
uint32_t engine_addr;
@@ -402,6 +455,7 @@ static int fsi_slave_scan(struct fsi_slave *slave)
dev_set_name(&dev->dev, "%02x:%02x:%02x:%02x",
slave->master->idx, slave->link,
slave->id, i - 2);
+ dev->dev.of_node = fsi_device_find_of_node(dev);
rc = device_register(&dev->dev);
if (rc) {
@@ -558,9 +612,53 @@ static void fsi_slave_release(struct device *dev)
{
struct fsi_slave *slave = to_fsi_slave(dev);
+ of_node_put(dev->of_node);
kfree(slave);
}
+static bool fsi_slave_node_matches(struct device_node *np,
+ int link, uint8_t id)
+{
+ unsigned int len, na, ns;
+ const __be32 *prop;
+
+ na = of_n_addr_cells(np);
+ ns = of_n_size_cells(np);
+
+ /* Ensure we have the correct format for addresses and sizes in
+ * reg properties
+ */
+ if (na != 2 || ns != 0)
+ return false;
+
+ prop = of_get_property(np, "reg", &len);
+ if (!prop || len != 8)
+ return false;
+
+ return (of_read_number(prop, 1) == link) &&
+ (of_read_number(prop + 1, 1) == id);
+}
+
+/* Find a matching node for the slave at (link, id). Returns NULL if none
+ * found, or a matching node with refcount already incremented.
+ */
+static struct device_node *fsi_slave_find_of_node(struct fsi_master *master,
+ int link, uint8_t id)
+{
+ struct device_node *parent, *np;
+
+ parent = dev_of_node(&master->dev);
+ if (!parent)
+ return NULL;
+
+ for_each_child_of_node(parent, np) {
+ if (fsi_slave_node_matches(np, link, id))
+ return np;
+ }
+
+ return NULL;
+}
+
static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
{
uint32_t chip_id, llmode;
@@ -589,7 +687,7 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
return -EIO;
}
- dev_info(&master->dev, "fsi: found chip %08x at %02x:%02x:%02x\n",
+ dev_dbg(&master->dev, "fsi: found chip %08x at %02x:%02x:%02x\n",
chip_id, master->idx, link, id);
rc = fsi_slave_set_smode(master, link, id);
@@ -623,6 +721,7 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
slave->master = master;
slave->dev.parent = &master->dev;
+ slave->dev.of_node = fsi_slave_find_of_node(master, link, id);
slave->dev.release = fsi_slave_release;
slave->link = link;
slave->id = id;
@@ -656,10 +755,13 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
/* FSI master support */
static int fsi_check_access(uint32_t addr, size_t size)
{
- if (size != 1 && size != 2 && size != 4)
- return -EINVAL;
-
- if ((addr & 0x3) != (size & 0x3))
+ if (size == 4) {
+ if (addr & 0x3)
+ return -EINVAL;
+ } else if (size == 2) {
+ if (addr & 0x1)
+ return -EINVAL;
+ } else if (size != 1)
return -EINVAL;
return 0;
@@ -762,14 +864,20 @@ static void fsi_master_unscan(struct fsi_master *master)
device_for_each_child(&master->dev, NULL, fsi_master_remove_slave);
}
+int fsi_master_rescan(struct fsi_master *master)
+{
+ fsi_master_unscan(master);
+ return fsi_master_scan(master);
+}
+EXPORT_SYMBOL_GPL(fsi_master_rescan);
+
static ssize_t master_rescan_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct fsi_master *master = to_fsi_master(dev);
int rc;
- fsi_master_unscan(master);
- rc = fsi_master_scan(master);
+ rc = fsi_master_rescan(master);
if (rc < 0)
return rc;
@@ -793,6 +901,7 @@ static DEVICE_ATTR(break, 0200, NULL, master_break_store);
int fsi_master_register(struct fsi_master *master)
{
int rc;
+ struct device_node *np;
if (!master)
return -EINVAL;
@@ -820,7 +929,9 @@ int fsi_master_register(struct fsi_master *master)
return rc;
}
- fsi_master_scan(master);
+ np = dev_of_node(&master->dev);
+ if (!of_property_read_bool(np, "no-scan-on-init"))
+ fsi_master_scan(master);
return 0;
}
diff --git a/drivers/fsi/fsi-master-gpio.c b/drivers/fsi/fsi-master-gpio.c
index ae2618768508..3f487449a277 100644
--- a/drivers/fsi/fsi-master-gpio.c
+++ b/drivers/fsi/fsi-master-gpio.c
@@ -9,6 +9,7 @@
#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -59,6 +60,7 @@ struct fsi_master_gpio {
struct gpio_desc *gpio_trans; /* Voltage translator */
struct gpio_desc *gpio_enable; /* FSI enable */
struct gpio_desc *gpio_mux; /* Mux control */
+ bool external_mode;
};
#define CREATE_TRACE_POINTS
@@ -411,6 +413,12 @@ static int fsi_master_gpio_xfer(struct fsi_master_gpio *master, uint8_t slave,
int rc;
spin_lock_irqsave(&master->cmd_lock, flags);
+
+ if (master->external_mode) {
+ spin_unlock_irqrestore(&master->cmd_lock, flags);
+ return -EBUSY;
+ }
+
serial_out(master, cmd);
echo_delay(master);
rc = poll_for_response(master, slave, resp_len, resp);
@@ -461,12 +469,18 @@ static int fsi_master_gpio_term(struct fsi_master *_master,
static int fsi_master_gpio_break(struct fsi_master *_master, int link)
{
struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
+ unsigned long flags;
if (link != 0)
return -ENODEV;
trace_fsi_master_gpio_break(master);
+ spin_lock_irqsave(&master->cmd_lock, flags);
+ if (master->external_mode) {
+ spin_unlock_irqrestore(&master->cmd_lock, flags);
+ return -EBUSY;
+ }
set_sda_output(master, 1);
sda_out(master, 1);
clock_toggle(master, FSI_PRE_BREAK_CLOCKS);
@@ -475,6 +489,7 @@ static int fsi_master_gpio_break(struct fsi_master *_master, int link)
echo_delay(master);
sda_out(master, 1);
clock_toggle(master, FSI_POST_BREAK_CLOCKS);
+ spin_unlock_irqrestore(&master->cmd_lock, flags);
/* Wait for logic reset to take effect */
udelay(200);
@@ -494,21 +509,84 @@ static void fsi_master_gpio_init(struct fsi_master_gpio *master)
clock_zeros(master, FSI_INIT_CLOCKS);
}
+static void fsi_master_gpio_init_external(struct fsi_master_gpio *master)
+{
+ gpiod_direction_output(master->gpio_mux, 0);
+ gpiod_direction_output(master->gpio_trans, 0);
+ gpiod_direction_output(master->gpio_enable, 1);
+ gpiod_direction_input(master->gpio_clk);
+ gpiod_direction_input(master->gpio_data);
+}
+
static int fsi_master_gpio_link_enable(struct fsi_master *_master, int link)
{
struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
+ unsigned long flags;
+ int rc = -EBUSY;
if (link != 0)
return -ENODEV;
- gpiod_set_value(master->gpio_enable, 1);
- return 0;
+ spin_lock_irqsave(&master->cmd_lock, flags);
+ if (!master->external_mode) {
+ gpiod_set_value(master->gpio_enable, 1);
+ rc = 0;
+ }
+ spin_unlock_irqrestore(&master->cmd_lock, flags);
+
+ return rc;
+}
+
+static ssize_t external_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fsi_master_gpio *master = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE - 1, "%u\n",
+ master->external_mode ? 1 : 0);
}
+static ssize_t external_mode_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct fsi_master_gpio *master = dev_get_drvdata(dev);
+ unsigned long flags, val;
+ bool external_mode;
+ int err;
+
+ err = kstrtoul(buf, 0, &val);
+ if (err)
+ return err;
+
+ external_mode = !!val;
+
+ spin_lock_irqsave(&master->cmd_lock, flags);
+
+ if (external_mode == master->external_mode) {
+ spin_unlock_irqrestore(&master->cmd_lock, flags);
+ return count;
+ }
+
+ master->external_mode = external_mode;
+ if (master->external_mode)
+ fsi_master_gpio_init_external(master);
+ else
+ fsi_master_gpio_init(master);
+ spin_unlock_irqrestore(&master->cmd_lock, flags);
+
+ fsi_master_rescan(&master->master);
+
+ return count;
+}
+
+static DEVICE_ATTR(external_mode, 0664,
+ external_mode_show, external_mode_store);
+
static int fsi_master_gpio_probe(struct platform_device *pdev)
{
struct fsi_master_gpio *master;
struct gpio_desc *gpio;
+ int rc;
master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
if (!master)
@@ -516,6 +594,7 @@ static int fsi_master_gpio_probe(struct platform_device *pdev)
master->dev = &pdev->dev;
master->master.dev.parent = master->dev;
+ master->master.dev.of_node = of_node_get(dev_of_node(master->dev));
gpio = devm_gpiod_get(&pdev->dev, "clock", 0);
if (IS_ERR(gpio)) {
@@ -565,6 +644,10 @@ static int fsi_master_gpio_probe(struct platform_device *pdev)
fsi_master_gpio_init(master);
+ rc = device_create_file(&pdev->dev, &dev_attr_external_mode);
+ if (rc)
+ return rc;
+
return fsi_master_register(&master->master);
}
@@ -583,6 +666,8 @@ static int fsi_master_gpio_remove(struct platform_device *pdev)
devm_gpiod_put(&pdev->dev, master->gpio_mux);
fsi_master_unregister(&master->master);
+ of_node_put(master->master.dev.of_node);
+
return 0;
}
diff --git a/drivers/fsi/fsi-master-hub.c b/drivers/fsi/fsi-master-hub.c
index 133b9bff1d65..5885fc4a1ef0 100644
--- a/drivers/fsi/fsi-master-hub.c
+++ b/drivers/fsi/fsi-master-hub.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/fsi.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include "fsi-master.h"
@@ -253,7 +254,7 @@ static int hub_master_probe(struct device *dev)
reg = be32_to_cpu(__reg);
links = (reg >> 8) & 0xff;
- dev_info(dev, "hub version %08x (%d links)\n", reg, links);
+ dev_dbg(dev, "hub version %08x (%d links)\n", reg, links);
rc = fsi_slave_claim_range(fsi_dev->slave, FSI_HUB_LINK_OFFSET,
FSI_HUB_LINK_SIZE * links);
@@ -274,6 +275,7 @@ static int hub_master_probe(struct device *dev)
hub->master.dev.parent = dev;
hub->master.dev.release = hub_master_release;
+ hub->master.dev.of_node = of_node_get(dev_of_node(dev));
hub->master.n_links = links;
hub->master.read = hub_master_read;
@@ -286,10 +288,19 @@ static int hub_master_probe(struct device *dev)
hub_master_init(hub);
rc = fsi_master_register(&hub->master);
- if (!rc)
- return 0;
+ if (rc)
+ goto err_release;
+
+ /* At this point, fsi_master_register performs the device_initialize(),
+ * and holds the sole reference on master.dev. This means the device
+ * will be freed (via ->release) during any subsequent call to
+ * fsi_master_unregister. We add our own reference to it here, so we
+ * can perform cleanup (in _remove()) without it being freed before
+ * we're ready.
+ */
+ get_device(&hub->master.dev);
+ return 0;
- kfree(hub);
err_release:
fsi_slave_release_range(fsi_dev->slave, FSI_HUB_LINK_OFFSET,
FSI_HUB_LINK_SIZE * links);
@@ -302,6 +313,14 @@ static int hub_master_remove(struct device *dev)
fsi_master_unregister(&hub->master);
fsi_slave_release_range(hub->upstream->slave, hub->addr, hub->size);
+ of_node_put(hub->master.dev.of_node);
+
+ /*
+ * master.dev will likely be ->release()ed after this, which free()s
+ * the hub
+ */
+ put_device(&hub->master.dev);
+
return 0;
}
diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h
index 12f7b119567d..ee0b46086026 100644
--- a/drivers/fsi/fsi-master.h
+++ b/drivers/fsi/fsi-master.h
@@ -37,7 +37,24 @@ struct fsi_master {
#define dev_to_fsi_master(d) container_of(d, struct fsi_master, dev)
+/**
+ * fsi_master registration & lifetime: the fsi_master_register() and
+ * fsi_master_unregister() functions will take ownership of the master, and
+ * ->dev in particular. The registration path performs a get_device(), which
+ * takes the first reference on the device. Similarly, the unregistration path
+ * performs a put_device(), which may well drop the last reference.
+ *
+ * This means that master implementations *may* need to hold their own
+ * reference (via get_device()) on master->dev. In particular, if the device's
+ * ->release callback frees the fsi_master, then fsi_master_unregister will
+ * invoke this free if no other reference is held.
+ *
+ * The same applies for the error path of fsi_master_register; if the call
+ * fails, dev->release will have been invoked.
+ */
extern int fsi_master_register(struct fsi_master *master);
extern void fsi_master_unregister(struct fsi_master *master);
+extern int fsi_master_rescan(struct fsi_master *master);
+
#endif /* DRIVERS_FSI_MASTER_H */
diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c
index 86789f8918a4..7ab36042a822 100644
--- a/drivers/gpu/drm/bridge/sil-sii8620.c
+++ b/drivers/gpu/drm/bridge/sil-sii8620.c
@@ -17,6 +17,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/extcon.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
@@ -25,6 +26,7 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -81,6 +83,10 @@ struct sii8620 {
struct edid *edid;
unsigned int gen2_write_burst:1;
enum sii8620_mt_state mt_state;
+ struct extcon_dev *extcon;
+ struct notifier_block extcon_nb;
+ struct work_struct extcon_wq;
+ int cable_state;
struct list_head mt_queue;
struct {
int r_size;
@@ -2170,6 +2176,77 @@ static void sii8620_init_rcp_input_dev(struct sii8620 *ctx)
ctx->rc_dev = rc_dev;
}
+static void sii8620_cable_out(struct sii8620 *ctx)
+{
+ disable_irq(to_i2c_client(ctx->dev)->irq);
+ sii8620_hw_off(ctx);
+}
+
+static void sii8620_extcon_work(struct work_struct *work)
+{
+ struct sii8620 *ctx =
+ container_of(work, struct sii8620, extcon_wq);
+ int state = extcon_get_state(ctx->extcon, EXTCON_DISP_MHL);
+
+ if (state == ctx->cable_state)
+ return;
+
+ ctx->cable_state = state;
+
+ if (state > 0)
+ sii8620_cable_in(ctx);
+ else
+ sii8620_cable_out(ctx);
+}
+
+static int sii8620_extcon_notifier(struct notifier_block *self,
+ unsigned long event, void *ptr)
+{
+ struct sii8620 *ctx =
+ container_of(self, struct sii8620, extcon_nb);
+
+ schedule_work(&ctx->extcon_wq);
+
+ return NOTIFY_DONE;
+}
+
+static int sii8620_extcon_init(struct sii8620 *ctx)
+{
+ struct extcon_dev *edev;
+ struct device_node *musb, *muic;
+ int ret;
+
+ /* get micro-USB connector node */
+ musb = of_graph_get_remote_node(ctx->dev->of_node, 1, -1);
+ /* next get micro-USB Interface Controller node */
+ muic = of_get_next_parent(musb);
+
+ if (!muic) {
+ dev_info(ctx->dev, "no extcon found, switching to 'always on' mode\n");
+ return 0;
+ }
+
+ edev = extcon_find_edev_by_node(muic);
+ of_node_put(muic);
+ if (IS_ERR(edev)) {
+ if (PTR_ERR(edev) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_err(ctx->dev, "Invalid or missing extcon\n");
+ return PTR_ERR(edev);
+ }
+
+ ctx->extcon = edev;
+ ctx->extcon_nb.notifier_call = sii8620_extcon_notifier;
+ INIT_WORK(&ctx->extcon_wq, sii8620_extcon_work);
+ ret = extcon_register_notifier(edev, EXTCON_DISP_MHL, &ctx->extcon_nb);
+ if (ret) {
+ dev_err(ctx->dev, "failed to register notifier for MHL\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static inline struct sii8620 *bridge_to_sii8620(struct drm_bridge *bridge)
{
return container_of(bridge, struct sii8620, bridge);
@@ -2302,13 +2379,20 @@ static int sii8620_probe(struct i2c_client *client,
if (ret)
return ret;
+ ret = sii8620_extcon_init(ctx);
+ if (ret < 0) {
+ dev_err(ctx->dev, "failed to initialize EXTCON\n");
+ return ret;
+ }
+
i2c_set_clientdata(client, ctx);
ctx->bridge.funcs = &sii8620_bridge_funcs;
ctx->bridge.of_node = dev->of_node;
drm_bridge_add(&ctx->bridge);
- sii8620_cable_in(ctx);
+ if (!ctx->extcon)
+ sii8620_cable_in(ctx);
return 0;
}
@@ -2317,8 +2401,15 @@ static int sii8620_remove(struct i2c_client *client)
{
struct sii8620 *ctx = i2c_get_clientdata(client);
- disable_irq(to_i2c_client(ctx->dev)->irq);
- sii8620_hw_off(ctx);
+ if (ctx->extcon) {
+ extcon_unregister_notifier(ctx->extcon, EXTCON_DISP_MHL,
+ &ctx->extcon_nb);
+ flush_work(&ctx->extcon_wq);
+ if (ctx->cable_state > 0)
+ sii8620_cable_out(ctx);
+ } else {
+ sii8620_cable_out(ctx);
+ }
drm_bridge_remove(&ctx->bridge);
return 0;
diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig
index 50b89ea0e60f..97954f575c3f 100644
--- a/drivers/hv/Kconfig
+++ b/drivers/hv/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
menu "Microsoft Hyper-V guest support"
config HYPERV
diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile
index 14c22786b519..a1eec7177c2d 100644
--- a/drivers/hv/Makefile
+++ b/drivers/hv/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_HYPERV_UTILS) += hv_utils.o
obj-$(CONFIG_HYPERV_BALLOON) += hv_balloon.o
CFLAGS_hv_trace.o = -I$(src)
+CFLAGS_hv_balloon.o = -I$(src)
hv_vmbus-y := vmbus_drv.o \
hv.o connection.o channel.o \
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index c21020b69114..ecc2bd275a73 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -71,7 +71,7 @@ static const struct vmbus_device vmbus_devs[] = {
/* PCIE */
{ .dev_type = HV_PCIE,
HV_PCIE_GUID,
- .perf_device = true,
+ .perf_device = false,
},
/* Synthetic Frame Buffer */
@@ -596,10 +596,8 @@ static int next_numa_node_id;
/*
* Starting with Win8, we can statically distribute the incoming
* channel interrupt load by binding a channel to VCPU.
- * We do this in a hierarchical fashion:
- * First distribute the primary channels across available NUMA nodes
- * and then distribute the subchannels amongst the CPUs in the NUMA
- * node assigned to the primary channel.
+ * We distribute the interrupt loads to one or more NUMA nodes based on
+ * the channel's affinity_policy.
*
* For pre-win8 hosts or non-performance critical channels we assign the
* first CPU in the first NUMA node.
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index fe96aab9e794..8137b3885b99 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -27,7 +27,7 @@
#include <linux/vmalloc.h>
#include <linux/hyperv.h>
#include <linux/version.h>
-#include <linux/interrupt.h>
+#include <linux/random.h>
#include <linux/clockchips.h>
#include <asm/hyperv.h>
#include <asm/mshyperv.h>
@@ -38,6 +38,17 @@ struct hv_context hv_context = {
.synic_initialized = false,
};
+/*
+ * If false, we're using the old mechanism for stimer0 interrupts
+ * where it sends a VMbus message when it expires. The old
+ * mechanism is used when running on older versions of Hyper-V
+ * that don't support Direct Mode. While Hyper-V provides
+ * four stimer's per CPU, Linux uses only stimer0.
+ */
+static bool direct_mode_enabled;
+static int stimer0_irq;
+static int stimer0_vector;
+
#define HV_TIMER_FREQUENCY (10 * 1000 * 1000) /* 100ns period */
#define HV_MAX_MAX_DELTA_TICKS 0xffffffff
#define HV_MIN_DELTA_TICKS 1
@@ -53,6 +64,8 @@ int hv_init(void)
if (!hv_context.cpu_context)
return -ENOMEM;
+ direct_mode_enabled = ms_hyperv.misc_features &
+ HV_X64_STIMER_DIRECT_MODE_AVAILABLE;
return 0;
}
@@ -91,6 +104,21 @@ int hv_post_message(union hv_connection_id connection_id,
return status & 0xFFFF;
}
+/*
+ * ISR for when stimer0 is operating in Direct Mode. Direct Mode
+ * does not use VMbus or any VMbus messages, so process here and not
+ * in the VMbus driver code.
+ */
+
+static void hv_stimer0_isr(void)
+{
+ struct hv_per_cpu_context *hv_cpu;
+
+ hv_cpu = this_cpu_ptr(hv_context.cpu_context);
+ hv_cpu->clk_evt->event_handler(hv_cpu->clk_evt);
+ add_interrupt_randomness(stimer0_vector, 0);
+}
+
static int hv_ce_set_next_event(unsigned long delta,
struct clock_event_device *evt)
{
@@ -108,6 +136,8 @@ static int hv_ce_shutdown(struct clock_event_device *evt)
{
hv_init_timer(HV_X64_MSR_STIMER0_COUNT, 0);
hv_init_timer_config(HV_X64_MSR_STIMER0_CONFIG, 0);
+ if (direct_mode_enabled)
+ hv_disable_stimer0_percpu_irq(stimer0_irq);
return 0;
}
@@ -116,11 +146,26 @@ static int hv_ce_set_oneshot(struct clock_event_device *evt)
{
union hv_timer_config timer_cfg;
+ timer_cfg.as_uint64 = 0;
timer_cfg.enable = 1;
timer_cfg.auto_enable = 1;
- timer_cfg.sintx = VMBUS_MESSAGE_SINT;
+ if (direct_mode_enabled) {
+ /*
+ * When it expires, the timer will directly interrupt
+ * on the specified hardware vector/IRQ.
+ */
+ timer_cfg.direct_mode = 1;
+ timer_cfg.apic_vector = stimer0_vector;
+ hv_enable_stimer0_percpu_irq(stimer0_irq);
+ } else {
+ /*
+ * When it expires, the timer will generate a VMbus message,
+ * to be handled by the normal VMbus interrupt handler.
+ */
+ timer_cfg.direct_mode = 0;
+ timer_cfg.sintx = VMBUS_MESSAGE_SINT;
+ }
hv_init_timer_config(HV_X64_MSR_STIMER0_CONFIG, timer_cfg.as_uint64);
-
return 0;
}
@@ -147,7 +192,7 @@ int hv_synic_alloc(void)
int cpu;
hv_context.hv_numa_map = kzalloc(sizeof(struct cpumask) * nr_node_ids,
- GFP_ATOMIC);
+ GFP_KERNEL);
if (hv_context.hv_numa_map == NULL) {
pr_err("Unable to allocate NUMA map\n");
goto err;
@@ -191,6 +236,11 @@ int hv_synic_alloc(void)
INIT_LIST_HEAD(&hv_cpu->chan_list);
}
+ if (direct_mode_enabled &&
+ hv_setup_stimer0_irq(&stimer0_irq, &stimer0_vector,
+ hv_stimer0_isr))
+ goto err;
+
return 0;
err:
return -ENOMEM;
@@ -217,7 +267,7 @@ void hv_synic_free(void)
}
/*
- * hv_synic_init - Initialize the Synthethic Interrupt Controller.
+ * hv_synic_init - Initialize the Synthetic Interrupt Controller.
*
* If it is already initialized by another entity (ie x2v shim), we need to
* retrieve the initialized message and event pages. Otherwise, we create and
@@ -252,7 +302,6 @@ int hv_synic_init(unsigned int cpu)
hv_get_synint_state(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT,
shared_sint.as_uint64);
- shared_sint.as_uint64 = 0;
shared_sint.vector = HYPERVISOR_CALLBACK_VECTOR;
shared_sint.masked = false;
if (ms_hyperv.hints & HV_X64_DEPRECATING_AEOI_RECOMMENDED)
@@ -292,6 +341,9 @@ void hv_synic_clockevents_cleanup(void)
if (!(ms_hyperv.features & HV_X64_MSR_SYNTIMER_AVAILABLE))
return;
+ if (direct_mode_enabled)
+ hv_remove_stimer0_irq(stimer0_irq);
+
for_each_present_cpu(cpu) {
struct hv_per_cpu_context *hv_cpu
= per_cpu_ptr(hv_context.cpu_context, cpu);
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index db0e6652d7ef..b3e9f13f8bc3 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -34,6 +34,9 @@
#include <linux/hyperv.h>
+#define CREATE_TRACE_POINTS
+#include "hv_trace_balloon.h"
+
/*
* We begin with definitions supporting the Dynamic Memory protocol
* with the host.
@@ -576,11 +579,65 @@ static struct hv_dynmem_device dm_device;
static void post_status(struct hv_dynmem_device *dm);
#ifdef CONFIG_MEMORY_HOTPLUG
+static inline bool has_pfn_is_backed(struct hv_hotadd_state *has,
+ unsigned long pfn)
+{
+ struct hv_hotadd_gap *gap;
+
+ /* The page is not backed. */
+ if ((pfn < has->covered_start_pfn) || (pfn >= has->covered_end_pfn))
+ return false;
+
+ /* Check for gaps. */
+ list_for_each_entry(gap, &has->gap_list, list) {
+ if ((pfn >= gap->start_pfn) && (pfn < gap->end_pfn))
+ return false;
+ }
+
+ return true;
+}
+
+static unsigned long hv_page_offline_check(unsigned long start_pfn,
+ unsigned long nr_pages)
+{
+ unsigned long pfn = start_pfn, count = 0;
+ struct hv_hotadd_state *has;
+ bool found;
+
+ while (pfn < start_pfn + nr_pages) {
+ /*
+ * Search for HAS which covers the pfn and when we find one
+ * count how many consequitive PFNs are covered.
+ */
+ found = false;
+ list_for_each_entry(has, &dm_device.ha_region_list, list) {
+ while ((pfn >= has->start_pfn) &&
+ (pfn < has->end_pfn) &&
+ (pfn < start_pfn + nr_pages)) {
+ found = true;
+ if (has_pfn_is_backed(has, pfn))
+ count++;
+ pfn++;
+ }
+ }
+
+ /*
+ * This PFN is not in any HAS (e.g. we're offlining a region
+ * which was present at boot), no need to account for it. Go
+ * to the next one.
+ */
+ if (!found)
+ pfn++;
+ }
+
+ return count;
+}
+
static int hv_memory_notifier(struct notifier_block *nb, unsigned long val,
void *v)
{
struct memory_notify *mem = (struct memory_notify *)v;
- unsigned long flags;
+ unsigned long flags, pfn_count;
switch (val) {
case MEM_ONLINE:
@@ -593,7 +650,19 @@ static int hv_memory_notifier(struct notifier_block *nb, unsigned long val,
case MEM_OFFLINE:
spin_lock_irqsave(&dm_device.ha_lock, flags);
- dm_device.num_pages_onlined -= mem->nr_pages;
+ pfn_count = hv_page_offline_check(mem->start_pfn,
+ mem->nr_pages);
+ if (pfn_count <= dm_device.num_pages_onlined) {
+ dm_device.num_pages_onlined -= pfn_count;
+ } else {
+ /*
+ * We're offlining more pages than we managed to online.
+ * This is unexpected. In any case don't let
+ * num_pages_onlined wrap around zero.
+ */
+ WARN_ON_ONCE(1);
+ dm_device.num_pages_onlined = 0;
+ }
spin_unlock_irqrestore(&dm_device.ha_lock, flags);
break;
case MEM_GOING_ONLINE:
@@ -612,30 +681,9 @@ static struct notifier_block hv_memory_nb = {
/* Check if the particular page is backed and can be onlined and online it. */
static void hv_page_online_one(struct hv_hotadd_state *has, struct page *pg)
{
- unsigned long cur_start_pgp;
- unsigned long cur_end_pgp;
- struct hv_hotadd_gap *gap;
-
- cur_start_pgp = (unsigned long)pfn_to_page(has->covered_start_pfn);
- cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn);
-
- /* The page is not backed. */
- if (((unsigned long)pg < cur_start_pgp) ||
- ((unsigned long)pg >= cur_end_pgp))
+ if (!has_pfn_is_backed(has, page_to_pfn(pg)))
return;
- /* Check for gaps. */
- list_for_each_entry(gap, &has->gap_list, list) {
- cur_start_pgp = (unsigned long)
- pfn_to_page(gap->start_pfn);
- cur_end_pgp = (unsigned long)
- pfn_to_page(gap->end_pfn);
- if (((unsigned long)pg >= cur_start_pgp) &&
- ((unsigned long)pg < cur_end_pgp)) {
- return;
- }
- }
-
/* This frame is currently backed; online the page. */
__online_page_set_limits(pg);
__online_page_increment_counters(pg);
@@ -691,7 +739,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
(HA_CHUNK << PAGE_SHIFT));
if (ret) {
- pr_warn("hot_add memory failed error is %d\n", ret);
+ pr_err("hot_add memory failed error is %d\n", ret);
if (ret == -EEXIST) {
/*
* This error indicates that the error
@@ -726,19 +774,13 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
static void hv_online_page(struct page *pg)
{
struct hv_hotadd_state *has;
- unsigned long cur_start_pgp;
- unsigned long cur_end_pgp;
unsigned long flags;
+ unsigned long pfn = page_to_pfn(pg);
spin_lock_irqsave(&dm_device.ha_lock, flags);
list_for_each_entry(has, &dm_device.ha_region_list, list) {
- cur_start_pgp = (unsigned long)
- pfn_to_page(has->start_pfn);
- cur_end_pgp = (unsigned long)pfn_to_page(has->end_pfn);
-
/* The page belongs to a different HAS. */
- if (((unsigned long)pg < cur_start_pgp) ||
- ((unsigned long)pg >= cur_end_pgp))
+ if ((pfn < has->start_pfn) || (pfn >= has->end_pfn))
continue;
hv_page_online_one(has, pg);
@@ -1014,7 +1056,7 @@ static void hot_add_req(struct work_struct *dummy)
resp.result = 0;
if (!do_hot_add || (resp.page_count == 0))
- pr_info("Memory hot add failed\n");
+ pr_err("Memory hot add failed\n");
dm->state = DM_INITIALIZED;
resp.hdr.trans_id = atomic_inc_return(&trans_id);
@@ -1041,7 +1083,7 @@ static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg)
break;
default:
- pr_info("Received Unknown type: %d\n", info_hdr->type);
+ pr_warn("Received Unknown type: %d\n", info_hdr->type);
}
}
@@ -1120,6 +1162,9 @@ static void post_status(struct hv_dynmem_device *dm)
dm->num_pages_added - dm->num_pages_onlined : 0) +
compute_balloon_floor();
+ trace_balloon_status(status.num_avail, status.num_committed,
+ vm_memory_committed(), dm->num_pages_ballooned,
+ dm->num_pages_added, dm->num_pages_onlined);
/*
* If our transaction ID is no longer current, just don't
* send the status. This can happen if we were interrupted
@@ -1290,7 +1335,7 @@ static void balloon_up(struct work_struct *dummy)
/*
* Free up the memory we allocatted.
*/
- pr_info("Balloon response failed\n");
+ pr_err("Balloon response failed\n");
for (i = 0; i < bl_resp->range_count; i++)
free_balloon_pages(&dm_device,
@@ -1421,7 +1466,7 @@ static void cap_resp(struct hv_dynmem_device *dm,
struct dm_capabilities_resp_msg *cap_resp)
{
if (!cap_resp->is_accepted) {
- pr_info("Capabilities not accepted by host\n");
+ pr_err("Capabilities not accepted by host\n");
dm->state = DM_INIT_ERROR;
}
complete(&dm->host_event);
@@ -1508,7 +1553,7 @@ static void balloon_onchannelcallback(void *context)
break;
default:
- pr_err("Unhandled message: type: %d\n", dm_hdr->type);
+ pr_warn("Unhandled message: type: %d\n", dm_hdr->type);
}
}
diff --git a/drivers/hv/hv_trace.c b/drivers/hv/hv_trace.c
index df47acd01a81..38d359cf1e70 100644
--- a/drivers/hv/hv_trace.c
+++ b/drivers/hv/hv_trace.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
#include "hyperv_vmbus.h"
#define CREATE_TRACE_POINTS
diff --git a/drivers/hv/hv_trace.h b/drivers/hv/hv_trace.h
index d635ee95b20d..999f80a63bff 100644
--- a/drivers/hv/hv_trace.h
+++ b/drivers/hv/hv_trace.h
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
#undef TRACE_SYSTEM
#define TRACE_SYSTEM hyperv
diff --git a/drivers/hv/hv_trace_balloon.h b/drivers/hv/hv_trace_balloon.h
new file mode 100644
index 000000000000..93082888aec3
--- /dev/null
+++ b/drivers/hv/hv_trace_balloon.h
@@ -0,0 +1,48 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hyperv
+
+#if !defined(_HV_TRACE_BALLOON_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _HV_TRACE_BALLOON_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(balloon_status,
+ TP_PROTO(u64 available, u64 committed,
+ unsigned long vm_memory_committed,
+ unsigned long pages_ballooned,
+ unsigned long pages_added,
+ unsigned long pages_onlined),
+ TP_ARGS(available, committed, vm_memory_committed,
+ pages_ballooned, pages_added, pages_onlined),
+ TP_STRUCT__entry(
+ __field(u64, available)
+ __field(u64, committed)
+ __field(unsigned long, vm_memory_committed)
+ __field(unsigned long, pages_ballooned)
+ __field(unsigned long, pages_added)
+ __field(unsigned long, pages_onlined)
+ ),
+ TP_fast_assign(
+ __entry->available = available;
+ __entry->committed = committed;
+ __entry->vm_memory_committed = vm_memory_committed;
+ __entry->pages_ballooned = pages_ballooned;
+ __entry->pages_added = pages_added;
+ __entry->pages_onlined = pages_onlined;
+ ),
+ TP_printk("available %lld, committed %lld; vm_memory_committed %ld;"
+ " pages_ballooned %ld, pages_added %ld, pages_onlined %ld",
+ __entry->available, __entry->committed,
+ __entry->vm_memory_committed, __entry->pages_ballooned,
+ __entry->pages_added, __entry->pages_onlined
+ )
+ );
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE hv_trace_balloon
+#endif /* _HV_TRACE_BALLOON_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 22300ec7b556..36d34fe3ccb3 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -57,7 +57,9 @@ union hv_timer_config {
u64 periodic:1;
u64 lazy:1;
u64 auto_enable:1;
- u64 reserved_z0:12;
+ u64 apic_vector:8;
+ u64 direct_mode:1;
+ u64 reserved_z0:3;
u64 sintx:4;
u64 reserved_z1:44;
};
diff --git a/drivers/hwtracing/Kconfig b/drivers/hwtracing/Kconfig
new file mode 100644
index 000000000000..f68e025c5131
--- /dev/null
+++ b/drivers/hwtracing/Kconfig
@@ -0,0 +1,7 @@
+menu "HW tracing support"
+
+source "drivers/hwtracing/stm/Kconfig"
+
+source "drivers/hwtracing/intel_th/Kconfig"
+
+endmenu
diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c
index 6ea62c62ff27..9cdb3fbc8c1f 100644
--- a/drivers/hwtracing/coresight/coresight-cpu-debug.c
+++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c
@@ -315,7 +315,7 @@ static void debug_dump_regs(struct debug_drvdata *drvdata)
}
pc = debug_adjust_pc(drvdata);
- dev_emerg(dev, " EDPCSR: [<%p>] %pS\n", (void *)pc, (void *)pc);
+ dev_emerg(dev, " EDPCSR: [<%px>] %pS\n", (void *)pc, (void *)pc);
if (drvdata->edcidsr_present)
dev_emerg(dev, " EDCIDSR: %08x\n", drvdata->edcidsr);
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index 4e6eab53e34e..d21961710713 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -1780,7 +1780,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
*/
for (j = 0; j < 8; j++) {
if (maskbyte & 1)
- config->ctxid_pid[i] &= ~(0xFF << (j * 8));
+ config->ctxid_pid[i] &= ~(0xFFUL << (j * 8));
maskbyte >>= 1;
}
/* Select the next ctxid comparator mask value */
@@ -1963,7 +1963,7 @@ static ssize_t vmid_masks_store(struct device *dev,
*/
for (j = 0; j < 8; j++) {
if (maskbyte & 1)
- config->vmid_val[i] &= ~(0xFF << (j * 8));
+ config->vmid_val[i] &= ~(0xFFUL << (j * 8));
maskbyte >>= 1;
}
/* Select the next vmid comparator mask value */
diff --git a/drivers/hwtracing/intel_th/Kconfig b/drivers/hwtracing/intel_th/Kconfig
index 1b412f8a56b5..ca0527d588e9 100644
--- a/drivers/hwtracing/intel_th/Kconfig
+++ b/drivers/hwtracing/intel_th/Kconfig
@@ -25,6 +25,18 @@ config INTEL_TH_PCI
Say Y here to enable PCI Intel TH support.
+config INTEL_TH_ACPI
+ tristate "Intel(R) Trace Hub ACPI controller"
+ depends on ACPI
+ help
+ Intel(R) Trace Hub may exist as an ACPI device. This option enables
+ support glue layer for ACPI-based Intel TH. This typically implies
+ 'host debugger' mode, that is, the trace configuration and capture
+ is handled by an external debug host and corresponding controls will
+ not be available on the target.
+
+ Say Y here to enable ACPI Intel TH support.
+
config INTEL_TH_GTH
tristate "Intel(R) Trace Hub Global Trace Hub"
help
diff --git a/drivers/hwtracing/intel_th/Makefile b/drivers/hwtracing/intel_th/Makefile
index 880c9b5e8566..d9252fa8d9ca 100644
--- a/drivers/hwtracing/intel_th/Makefile
+++ b/drivers/hwtracing/intel_th/Makefile
@@ -6,6 +6,9 @@ intel_th-$(CONFIG_INTEL_TH_DEBUG) += debug.o
obj-$(CONFIG_INTEL_TH_PCI) += intel_th_pci.o
intel_th_pci-y := pci.o
+obj-$(CONFIG_INTEL_TH_ACPI) += intel_th_acpi.o
+intel_th_acpi-y := acpi.o
+
obj-$(CONFIG_INTEL_TH_GTH) += intel_th_gth.o
intel_th_gth-y := gth.o
diff --git a/drivers/hwtracing/intel_th/acpi.c b/drivers/hwtracing/intel_th/acpi.c
new file mode 100644
index 000000000000..87bc3744755f
--- /dev/null
+++ b/drivers/hwtracing/intel_th/acpi.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel(R) Trace Hub ACPI driver
+ *
+ * Copyright (C) 2017 Intel Corporation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+
+#include "intel_th.h"
+
+#define DRIVER_NAME "intel_th_acpi"
+
+static const struct intel_th_drvdata intel_th_acpi_pch = {
+ .host_mode_only = 1,
+};
+
+static const struct intel_th_drvdata intel_th_acpi_uncore = {
+ .host_mode_only = 1,
+};
+
+static const struct acpi_device_id intel_th_acpi_ids[] = {
+ { "INTC1000", (kernel_ulong_t)&intel_th_acpi_uncore },
+ { "INTC1001", (kernel_ulong_t)&intel_th_acpi_pch },
+ { "", 0 },
+};
+
+MODULE_DEVICE_TABLE(acpi, intel_th_acpi_ids);
+
+static int intel_th_acpi_probe(struct platform_device *pdev)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
+ const struct acpi_device_id *id;
+ struct intel_th *th;
+
+ id = acpi_match_device(intel_th_acpi_ids, &pdev->dev);
+ if (!id)
+ return -ENODEV;
+
+ th = intel_th_alloc(&pdev->dev, (void *)id->driver_data,
+ pdev->resource, pdev->num_resources, -1);
+ if (IS_ERR(th))
+ return PTR_ERR(th);
+
+ adev->driver_data = th;
+
+ return 0;
+}
+
+static int intel_th_acpi_remove(struct platform_device *pdev)
+{
+ struct intel_th *th = platform_get_drvdata(pdev);
+
+ intel_th_free(th);
+
+ return 0;
+}
+
+static struct platform_driver intel_th_acpi_driver = {
+ .probe = intel_th_acpi_probe,
+ .remove = intel_th_acpi_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .acpi_match_table = intel_th_acpi_ids,
+ },
+};
+
+module_platform_driver(intel_th_acpi_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel(R) Trace Hub ACPI controller driver");
+MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@intel.com>");
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
index 1a023e30488c..da962aa2cef5 100644
--- a/drivers/hwtracing/intel_th/core.c
+++ b/drivers/hwtracing/intel_th/core.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel(R) Trace Hub driver core
*
* Copyright (C) 2014-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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -638,7 +630,8 @@ intel_th_subdevice_alloc(struct intel_th *th,
thdev->output.port = -1;
thdev->output.scratchpad = subdev->scrpd;
} else if (subdev->type == INTEL_TH_SWITCH) {
- thdev->host_mode = host_mode;
+ thdev->host_mode =
+ INTEL_TH_CAP(th, host_mode_only) ? true : host_mode;
th->hub = thdev;
}
@@ -737,7 +730,8 @@ static int intel_th_populate(struct intel_th *th)
struct intel_th_device *thdev;
/* only allow SOURCE and SWITCH devices in host mode */
- if (host_mode && subdev->type == INTEL_TH_OUTPUT)
+ if ((INTEL_TH_CAP(th, host_mode_only) || host_mode) &&
+ subdev->type == INTEL_TH_OUTPUT)
continue;
/*
@@ -813,7 +807,14 @@ intel_th_alloc(struct device *dev, struct intel_th_drvdata *drvdata,
struct resource *devres, unsigned int ndevres, int irq)
{
struct intel_th *th;
- int err;
+ int err, r;
+
+ if (irq == -1)
+ for (r = 0; r < ndevres; r++)
+ if (devres[r].flags & IORESOURCE_IRQ) {
+ irq = devres[r].start;
+ break;
+ }
th = kzalloc(sizeof(*th), GFP_KERNEL);
if (!th)
@@ -935,9 +936,13 @@ EXPORT_SYMBOL_GPL(intel_th_trace_disable);
int intel_th_set_output(struct intel_th_device *thdev,
unsigned int master)
{
- struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
+ struct intel_th_device *hub = to_intel_th_hub(thdev);
struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
+ /* In host mode, this is up to the external debugger, do nothing. */
+ if (hub->host_mode)
+ return 0;
+
if (!hubdrv->set_output)
return -ENOTSUPP;
diff --git a/drivers/hwtracing/intel_th/debug.c b/drivers/hwtracing/intel_th/debug.c
index 788a1f0a97ad..ff79063118a0 100644
--- a/drivers/hwtracing/intel_th/debug.c
+++ b/drivers/hwtracing/intel_th/debug.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel(R) Trace Hub driver debugging
*
* Copyright (C) 2014-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/types.h>
diff --git a/drivers/hwtracing/intel_th/debug.h b/drivers/hwtracing/intel_th/debug.h
index 88311bad3ba4..78bd7e4bf9ce 100644
--- a/drivers/hwtracing/intel_th/debug.h
+++ b/drivers/hwtracing/intel_th/debug.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Intel(R) Trace Hub driver debugging
*
* Copyright (C) 2014-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.
*/
#ifndef __INTEL_TH_DEBUG_H__
diff --git a/drivers/hwtracing/intel_th/gth.c b/drivers/hwtracing/intel_th/gth.c
index 018678ec3c13..8426b7970c14 100644
--- a/drivers/hwtracing/intel_th/gth.c
+++ b/drivers/hwtracing/intel_th/gth.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel(R) Trace Hub Global Trace Hub
*
* Copyright (C) 2014-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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/hwtracing/intel_th/gth.h b/drivers/hwtracing/intel_th/gth.h
index f3d234251a12..6f2b0b930875 100644
--- a/drivers/hwtracing/intel_th/gth.h
+++ b/drivers/hwtracing/intel_th/gth.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Intel(R) Trace Hub Global Trace Hub (GTH) data structures
*
* Copyright (C) 2014-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.
*/
#ifndef __INTEL_TH_GTH_H__
diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h
index 99ad563fc40d..780206dc9012 100644
--- a/drivers/hwtracing/intel_th/intel_th.h
+++ b/drivers/hwtracing/intel_th/intel_th.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Intel(R) Trace Hub data structures
*
* Copyright (C) 2014-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.
*/
#ifndef __INTEL_TH_H__
@@ -50,9 +42,11 @@ struct intel_th_output {
/**
* struct intel_th_drvdata - describes hardware capabilities and quirks
* @tscu_enable: device needs SW to enable time stamping unit
+ * @host_mode_only: device can only operate in 'host debugger' mode
*/
struct intel_th_drvdata {
- unsigned int tscu_enable : 1;
+ unsigned int tscu_enable : 1,
+ host_mode_only : 1;
};
#define INTEL_TH_CAP(_th, _cap) ((_th)->drvdata ? (_th)->drvdata->_cap : 0)
diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c
index dfb57eaa9f22..ede388309376 100644
--- a/drivers/hwtracing/intel_th/msu.c
+++ b/drivers/hwtracing/intel_th/msu.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel(R) Trace Hub Memory Storage Unit
*
* Copyright (C) 2014-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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/hwtracing/intel_th/msu.h b/drivers/hwtracing/intel_th/msu.h
index 9b710e4aa98a..9cc8aced6116 100644
--- a/drivers/hwtracing/intel_th/msu.h
+++ b/drivers/hwtracing/intel_th/msu.h
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel(R) Trace Hub Memory Storage Unit (MSU) data structures
*
* Copyright (C) 2014-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.
*/
#ifndef __INTEL_TH_MSU_H__
diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c
index c2a2ce8ee541..c2e55e5d97f6 100644
--- a/drivers/hwtracing/intel_th/pci.c
+++ b/drivers/hwtracing/intel_th/pci.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel(R) Trace Hub pci driver
*
* Copyright (C) 2014-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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/hwtracing/intel_th/pti.c b/drivers/hwtracing/intel_th/pti.c
index e96a1fcb57b2..56694339cb06 100644
--- a/drivers/hwtracing/intel_th/pti.c
+++ b/drivers/hwtracing/intel_th/pti.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel(R) Trace Hub PTI output driver
*
* Copyright (C) 2014-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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/hwtracing/intel_th/pti.h b/drivers/hwtracing/intel_th/pti.h
index 30827be67b4c..e9381babc84c 100644
--- a/drivers/hwtracing/intel_th/pti.h
+++ b/drivers/hwtracing/intel_th/pti.h
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel(R) Trace Hub PTI output data structures
*
* Copyright (C) 2014-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.
*/
#ifndef __INTEL_TH_STH_H__
diff --git a/drivers/hwtracing/intel_th/sth.c b/drivers/hwtracing/intel_th/sth.c
index b03444624648..4b7ae47789d2 100644
--- a/drivers/hwtracing/intel_th/sth.c
+++ b/drivers/hwtracing/intel_th/sth.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Intel(R) Trace Hub Software Trace Hub support
*
* Copyright (C) 2014-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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/hwtracing/intel_th/sth.h b/drivers/hwtracing/intel_th/sth.h
index f1390cd4f2ed..f97fc0c51739 100644
--- a/drivers/hwtracing/intel_th/sth.h
+++ b/drivers/hwtracing/intel_th/sth.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Intel(R) Trace Hub Software Trace Hub (STH) data structures
*
* Copyright (C) 2014-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.
*/
#ifndef __INTEL_TH_STH_H__
diff --git a/drivers/hwtracing/stm/console.c b/drivers/hwtracing/stm/console.c
index c9d9a8d2ff52..a00f65e21747 100644
--- a/drivers/hwtracing/stm/console.c
+++ b/drivers/hwtracing/stm/console.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Simple kernel console driver for STM devices
* Copyright (c) 2014, 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.
- *
* STM console will send kernel messages over STM devices to a trace host.
*/
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index f129869e05a9..05386b76465e 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* System Trace Module (STM) infrastructure
* Copyright (c) 2014, 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.
- *
* STM class implements generic infrastructure for System Trace Module devices
* as defined in MIPI STPv2 specification.
*/
diff --git a/drivers/hwtracing/stm/dummy_stm.c b/drivers/hwtracing/stm/dummy_stm.c
index c5f94ca31c4d..38528ffdc0b3 100644
--- a/drivers/hwtracing/stm/dummy_stm.c
+++ b/drivers/hwtracing/stm/dummy_stm.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* A dummy STM device for stm/stm_source class testing.
* Copyright (c) 2014, 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.
- *
* STM class implements generic infrastructure for System Trace Module devices
* as defined in MIPI STPv2 specification.
*/
@@ -20,6 +12,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/stm.h>
+#include <uapi/linux/stm.h>
static ssize_t notrace
dummy_stm_packet(struct stm_data *stm_data, unsigned int master,
@@ -52,6 +45,18 @@ static unsigned int fail_mode;
module_param(fail_mode, int, 0600);
+static unsigned int master_min;
+
+module_param(master_min, int, 0400);
+
+static unsigned int master_max = STP_MASTER_MAX;
+
+module_param(master_max, int, 0400);
+
+static unsigned int nr_channels = STP_CHANNEL_MAX;
+
+module_param(nr_channels, int, 0400);
+
static int dummy_stm_link(struct stm_data *data, unsigned int master,
unsigned int channel)
{
@@ -68,14 +73,19 @@ static int dummy_stm_init(void)
if (nr_dummies < 0 || nr_dummies > DUMMY_STM_MAX)
return -EINVAL;
+ if (master_min > master_max ||
+ master_max > STP_MASTER_MAX ||
+ nr_channels > STP_CHANNEL_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].sw_start = master_min;
+ dummy_stm[i].sw_end = master_max;
+ dummy_stm[i].sw_nchannels = nr_channels;
dummy_stm[i].packet = dummy_stm_packet;
dummy_stm[i].link = dummy_stm_link;
diff --git a/drivers/hwtracing/stm/heartbeat.c b/drivers/hwtracing/stm/heartbeat.c
index 3da7b673aab2..7db42395e131 100644
--- a/drivers/hwtracing/stm/heartbeat.c
+++ b/drivers/hwtracing/stm/heartbeat.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* 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.
*/
diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c
index 33e9a1b6ea7c..3fd07e275b34 100644
--- a/drivers/hwtracing/stm/policy.c
+++ b/drivers/hwtracing/stm/policy.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* System Trace Module (STM) master/channel allocation policy management
* Copyright (c) 2014, 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.
- *
* A master/channel allocation policy allows mapping string identifiers to
* master and channel ranges, where allocation can be done.
*/
diff --git a/drivers/hwtracing/stm/stm.h b/drivers/hwtracing/stm/stm.h
index 4e8c6926260f..923571adc6f4 100644
--- a/drivers/hwtracing/stm/stm.h
+++ b/drivers/hwtracing/stm/stm.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* System Trace Module (STM) infrastructure
* Copyright (c) 2014, 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.
- *
* STM class implements generic infrastructure for System Trace Module devices
* as defined in MIPI STPv2 specification.
*/
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 870f92ef61c2..208f2d9f0e8a 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -336,8 +336,7 @@ static int bmc150_accel_update_slope(struct bmc150_accel_data *data)
return ret;
}
- dev_dbg(dev, "%s: %x %x\n", __func__, data->slope_thres,
- data->slope_dur);
+ dev_dbg(dev, "%x %x\n", data->slope_thres, data->slope_dur);
return ret;
}
@@ -1716,7 +1715,6 @@ static int bmc150_accel_runtime_suspend(struct device *dev)
struct bmc150_accel_data *data = iio_priv(indio_dev);
int ret;
- dev_dbg(dev, __func__);
ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0);
if (ret < 0)
return -EAGAIN;
@@ -1731,8 +1729,6 @@ static int bmc150_accel_runtime_resume(struct device *dev)
int ret;
int sleep_val;
- dev_dbg(dev, __func__);
-
ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
if (ret < 0)
return ret;
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index c066a3bdbff7..41d97faf5013 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -155,7 +155,7 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev,
*val = 0;
*val2 = 0;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
hid_sensor_power_state(&accel_state->common_attributes, true);
report_id = accel_state->accel[chan->scan_index].report_id;
address = accel_3d_addresses[chan->scan_index];
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index 363429b5686c..6bdec8c451e0 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -159,9 +159,8 @@ static int st_accel_i2c_probe(struct i2c_client *client,
if ((ret < 0) || (ret >= ST_ACCEL_MAX))
return -ENODEV;
- strncpy(client->name, st_accel_id_table[ret].name,
+ strlcpy(client->name, st_accel_id_table[ret].name,
sizeof(client->name));
- client->name[sizeof(client->name) - 1] = '\0';
} else if (!id)
return -ENODEV;
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 72bc2b71765a..914b6f849a29 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -144,10 +144,9 @@ config ASPEED_ADC
config AT91_ADC
tristate "Atmel AT91 ADC"
depends on ARCH_AT91
- depends on INPUT
+ depends on INPUT && SYSFS
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
- select SYSFS
help
Say yes here to build support for Atmel AT91 ADC.
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index b7706bf10ffe..fbaae47746a8 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -1,9 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver
+ * Analog Devices AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver
+ * TI ADC081S/ADC101S/ADC121S 8/10/12-bit SPI ADC driver
*
* Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -56,6 +56,9 @@ enum ad7476_supported_device_ids {
ID_AD7468,
ID_AD7495,
ID_AD7940,
+ ID_ADC081S,
+ ID_ADC101S,
+ ID_ADC121S,
};
static irqreturn_t ad7476_trigger_handler(int irq, void *p)
@@ -147,6 +150,8 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
}, \
}
+#define ADC081S_CHAN(bits) _AD7476_CHAN((bits), 12 - (bits), \
+ BIT(IIO_CHAN_INFO_RAW))
#define AD7476_CHAN(bits) _AD7476_CHAN((bits), 13 - (bits), \
BIT(IIO_CHAN_INFO_RAW))
#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \
@@ -192,6 +197,18 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
.channel[0] = AD7940_CHAN(14),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
+ [ID_ADC081S] = {
+ .channel[0] = ADC081S_CHAN(8),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ },
+ [ID_ADC101S] = {
+ .channel[0] = ADC081S_CHAN(10),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ },
+ [ID_ADC121S] = {
+ .channel[0] = ADC081S_CHAN(12),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ },
};
static const struct iio_info ad7476_info = {
@@ -294,6 +311,9 @@ static const struct spi_device_id ad7476_id[] = {
{"ad7910", ID_AD7467},
{"ad7920", ID_AD7466},
{"ad7940", ID_AD7940},
+ {"adc081s", ID_ADC081S},
+ {"adc101s", ID_ADC101S},
+ {"adc121s", ID_ADC121S},
{}
};
MODULE_DEVICE_TABLE(spi, ad7476_id);
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
index a30a97245e91..5be789269353 100644
--- a/drivers/iio/adc/axp20x_adc.c
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -35,8 +35,13 @@
#define AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(x) (((x) & BIT(0)) << 1)
#define AXP20X_ADC_RATE_MASK GENMASK(7, 6)
+#define AXP813_V_I_ADC_RATE_MASK GENMASK(5, 4)
+#define AXP813_ADC_RATE_MASK (AXP20X_ADC_RATE_MASK | AXP813_V_I_ADC_RATE_MASK)
#define AXP20X_ADC_RATE_HZ(x) ((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK)
#define AXP22X_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK)
+#define AXP813_TS_GPIO0_ADC_RATE_HZ(x) AXP20X_ADC_RATE_HZ(x)
+#define AXP813_V_I_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 4) & AXP813_V_I_ADC_RATE_MASK)
+#define AXP813_ADC_RATE_HZ(x) (AXP20X_ADC_RATE_HZ(x) | AXP813_V_I_ADC_RATE_HZ(x))
#define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg) \
{ \
@@ -95,6 +100,12 @@ enum axp22x_adc_channel_i {
AXP22X_BATT_DISCHRG_I,
};
+enum axp813_adc_channel_v {
+ AXP813_TS_IN = 0,
+ AXP813_GPIO0_V,
+ AXP813_BATT_V,
+};
+
static struct iio_map axp20x_maps[] = {
{
.consumer_dev_name = "axp20x-usb-power-supply",
@@ -197,6 +208,25 @@ static const struct iio_chan_spec axp22x_adc_channels[] = {
AXP20X_BATT_DISCHRG_I_H),
};
+static const struct iio_chan_spec axp813_adc_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .address = AXP22X_PMIC_TEMP_H,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ .datasheet_name = "pmic_temp",
+ },
+ AXP20X_ADC_CHANNEL(AXP813_GPIO0_V, "gpio0_v", IIO_VOLTAGE,
+ AXP288_GP_ADC_H),
+ AXP20X_ADC_CHANNEL(AXP813_BATT_V, "batt_v", IIO_VOLTAGE,
+ AXP20X_BATT_V_H),
+ AXP20X_ADC_CHANNEL(AXP22X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
+ AXP20X_BATT_CHRG_I_H),
+ AXP20X_ADC_CHANNEL(AXP22X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
+ AXP20X_BATT_DISCHRG_I_H),
+};
+
static int axp20x_adc_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
@@ -243,6 +273,18 @@ static int axp22x_adc_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
}
+static int axp813_adc_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
+{
+ struct axp20x_adc_iio *info = iio_priv(indio_dev);
+
+ *val = axp20x_read_variable_width(info->regmap, chan->address, 12);
+ if (*val < 0)
+ return *val;
+
+ return IIO_VAL_INT;
+}
+
static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
{
switch (channel) {
@@ -273,6 +315,24 @@ static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
}
}
+static int axp813_adc_scale_voltage(int channel, int *val, int *val2)
+{
+ switch (channel) {
+ case AXP813_GPIO0_V:
+ *val = 0;
+ *val2 = 800000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case AXP813_BATT_V:
+ *val = 1;
+ *val2 = 100000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int axp20x_adc_scale_current(int channel, int *val, int *val2)
{
switch (channel) {
@@ -342,6 +402,26 @@ static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val,
}
}
+static int axp813_adc_scale(struct iio_chan_spec const *chan, int *val,
+ int *val2)
+{
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ return axp813_adc_scale_voltage(chan->channel, val, val2);
+
+ case IIO_CURRENT:
+ *val = 1;
+ return IIO_VAL_INT;
+
+ case IIO_TEMP:
+ *val = 100;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
int *val)
{
@@ -365,7 +445,7 @@ static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
return -EINVAL;
}
- *val = !!(*val) * 700000;
+ *val = *val ? 700000 : 0;
return IIO_VAL_INT;
}
@@ -425,6 +505,26 @@ static int axp22x_read_raw(struct iio_dev *indio_dev,
}
}
+static int axp813_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_OFFSET:
+ *val = -2667;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ return axp813_adc_scale(chan, val, val2);
+
+ case IIO_CHAN_INFO_RAW:
+ return axp813_adc_raw(indio_dev, chan, val);
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int axp20x_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2,
long mask)
@@ -442,15 +542,17 @@ static int axp20x_write_raw(struct iio_dev *indio_dev,
if (val != 0 && val != 700000)
return -EINVAL;
+ val = val ? 1 : 0;
+
switch (chan->channel) {
case AXP20X_GPIO0_V:
reg = AXP20X_GPIO10_IN_RANGE_GPIO0;
- regval = AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(!!val);
+ regval = AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(val);
break;
case AXP20X_GPIO1_V:
reg = AXP20X_GPIO10_IN_RANGE_GPIO1;
- regval = AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(!!val);
+ regval = AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(val);
break;
default:
@@ -470,14 +572,29 @@ static const struct iio_info axp22x_adc_iio_info = {
.read_raw = axp22x_read_raw,
};
-static int axp20x_adc_rate(int rate)
+static const struct iio_info axp813_adc_iio_info = {
+ .read_raw = axp813_read_raw,
+};
+
+static int axp20x_adc_rate(struct axp20x_adc_iio *info, int rate)
+{
+ return regmap_update_bits(info->regmap, AXP20X_ADC_RATE,
+ AXP20X_ADC_RATE_MASK,
+ AXP20X_ADC_RATE_HZ(rate));
+}
+
+static int axp22x_adc_rate(struct axp20x_adc_iio *info, int rate)
{
- return AXP20X_ADC_RATE_HZ(rate);
+ return regmap_update_bits(info->regmap, AXP20X_ADC_RATE,
+ AXP20X_ADC_RATE_MASK,
+ AXP22X_ADC_RATE_HZ(rate));
}
-static int axp22x_adc_rate(int rate)
+static int axp813_adc_rate(struct axp20x_adc_iio *info, int rate)
{
- return AXP22X_ADC_RATE_HZ(rate);
+ return regmap_update_bits(info->regmap, AXP813_ADC_RATE,
+ AXP813_ADC_RATE_MASK,
+ AXP813_ADC_RATE_HZ(rate));
}
struct axp_data {
@@ -485,7 +602,8 @@ struct axp_data {
int num_channels;
struct iio_chan_spec const *channels;
unsigned long adc_en1_mask;
- int (*adc_rate)(int rate);
+ int (*adc_rate)(struct axp20x_adc_iio *info,
+ int rate);
bool adc_en2;
struct iio_map *maps;
};
@@ -510,9 +628,28 @@ static const struct axp_data axp22x_data = {
.maps = axp22x_maps,
};
+static const struct axp_data axp813_data = {
+ .iio_info = &axp813_adc_iio_info,
+ .num_channels = ARRAY_SIZE(axp813_adc_channels),
+ .channels = axp813_adc_channels,
+ .adc_en1_mask = AXP22X_ADC_EN1_MASK,
+ .adc_rate = axp813_adc_rate,
+ .adc_en2 = false,
+ .maps = axp22x_maps,
+};
+
+static const struct of_device_id axp20x_adc_of_match[] = {
+ { .compatible = "x-powers,axp209-adc", .data = (void *)&axp20x_data, },
+ { .compatible = "x-powers,axp221-adc", .data = (void *)&axp22x_data, },
+ { .compatible = "x-powers,axp813-adc", .data = (void *)&axp813_data, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, axp20x_adc_of_match);
+
static const struct platform_device_id axp20x_adc_id_match[] = {
{ .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, },
{ .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, },
+ { .name = "axp813-adc", .driver_data = (kernel_ulong_t)&axp813_data, },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(platform, axp20x_adc_id_match);
@@ -538,7 +675,16 @@ static int axp20x_probe(struct platform_device *pdev)
indio_dev->dev.of_node = pdev->dev.of_node;
indio_dev->modes = INDIO_DIRECT_MODE;
- info->data = (struct axp_data *)platform_get_device_id(pdev)->driver_data;
+ if (!pdev->dev.of_node) {
+ const struct platform_device_id *id;
+
+ id = platform_get_device_id(pdev);
+ info->data = (struct axp_data *)id->driver_data;
+ } else {
+ struct device *dev = &pdev->dev;
+
+ info->data = (struct axp_data *)of_device_get_match_data(dev);
+ }
indio_dev->name = platform_get_device_id(pdev)->name;
indio_dev->info = info->data->iio_info;
@@ -554,8 +700,7 @@ static int axp20x_probe(struct platform_device *pdev)
AXP20X_ADC_EN2_MASK, AXP20X_ADC_EN2_MASK);
/* Configure ADCs rate */
- regmap_update_bits(info->regmap, AXP20X_ADC_RATE, AXP20X_ADC_RATE_MASK,
- info->data->adc_rate(100));
+ info->data->adc_rate(info, 100);
ret = iio_map_array_register(indio_dev, info->data->maps);
if (ret < 0) {
@@ -602,6 +747,7 @@ static int axp20x_remove(struct platform_device *pdev)
static struct platform_driver axp20x_adc_driver = {
.driver = {
.name = "axp20x-adc",
+ .of_match_table = of_match_ptr(axp20x_adc_of_match),
},
.id_table = axp20x_adc_id_match,
.probe = axp20x_probe,
diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
index 81c901507ad2..5036c392cb20 100644
--- a/drivers/iio/adc/ep93xx_adc.c
+++ b/drivers/iio/adc/ep93xx_adc.c
@@ -167,10 +167,6 @@ static int ep93xx_adc_probe(struct platform_device *pdev)
priv = iio_priv(iiodev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Cannot obtain memory resource\n");
- return -ENXIO;
- }
priv->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->base)) {
dev_err(&pdev->dev, "Cannot map memory resource\n");
diff --git a/drivers/iio/adc/ti-adc161s626.c b/drivers/iio/adc/ti-adc161s626.c
index 10fa7677ac4b..3bbc9b9ddbfe 100644
--- a/drivers/iio/adc/ti-adc161s626.c
+++ b/drivers/iio/adc/ti-adc161s626.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* ti-adc161s626.c - Texas Instruments ADC161S626 1-channel differential ADC
*
@@ -5,17 +6,8 @@
* adc141s626 - 14-bit ADC
* adc161s626 - 16-bit ADC
*
- * Copyright (C) 2016 Matt Ranostay <mranostay@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.
- *
- * 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) 2016-2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
*/
#include <linux/module.h>
@@ -275,6 +267,6 @@ static struct spi_driver ti_adc_driver = {
};
module_spi_driver(ti_adc_driver);
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("Texas Instruments ADC1x1S 1-channel differential ADC");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/chemical/ams-iaq-core.c b/drivers/iio/chemical/ams-iaq-core.c
index d9e5950ad24a..a0646ba2ad88 100644
--- a/drivers/iio/chemical/ams-iaq-core.c
+++ b/drivers/iio/chemical/ams-iaq-core.c
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* ams-iaq-core.c - Support for AMS iAQ-Core VOC sensors
*
- * Copyright (C) 2015 Matt Ranostay <mranostay@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.
- *
- * 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) 2015, 2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
*/
#include <linux/module.h>
@@ -194,6 +185,6 @@ static struct i2c_driver ams_iaqcore_driver = {
};
module_i2c_driver(ams_iaqcore_driver);
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("AMS iAQ-Core VOC sensors");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c
index 8c4e05580091..abfc4bbc4cfc 100644
--- a/drivers/iio/chemical/atlas-ph-sensor.c
+++ b/drivers/iio/chemical/atlas-ph-sensor.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* atlas-ph-sensor.c - Support for Atlas Scientific OEM pH-SM sensor
*
- * Copyright (C) 2015 Matt Ranostay <mranostay@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.
- *
- * 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) 2015-2018 Matt Ranostay
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
*/
#include <linux/module.h>
@@ -689,6 +681,6 @@ static struct i2c_driver atlas_driver = {
};
module_i2c_driver(atlas_driver);
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("Atlas Scientific pH-SM sensor");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c
index 1ea9f5513b02..b4a46eb45789 100644
--- a/drivers/iio/chemical/ccs811.c
+++ b/drivers/iio/chemical/ccs811.c
@@ -32,7 +32,7 @@
#define CCS811_ALG_RESULT_DATA 0x02
#define CCS811_RAW_DATA 0x03
#define CCS811_HW_ID 0x20
-#define CCS881_HW_ID_VALUE 0x81
+#define CCS811_HW_ID_VALUE 0x81
#define CCS811_HW_VERSION 0x21
#define CCS811_HW_VERSION_VALUE 0x10
#define CCS811_HW_VERSION_MASK 0xF0
@@ -69,7 +69,7 @@ struct ccs811_reading {
__be16 voc;
u8 status;
u8 error;
- __be16 resistance;
+ __be16 raw_data;
} __attribute__((__packed__));
struct ccs811_data {
@@ -213,12 +213,12 @@ static int ccs811_read_raw(struct iio_dev *indio_dev,
switch (chan->type) {
case IIO_VOLTAGE:
- *val = be16_to_cpu(data->buffer.resistance) &
+ *val = be16_to_cpu(data->buffer.raw_data) &
CCS811_VOLTAGE_MASK;
ret = IIO_VAL_INT;
break;
case IIO_CURRENT:
- *val = be16_to_cpu(data->buffer.resistance) >> 10;
+ *val = be16_to_cpu(data->buffer.raw_data) >> 10;
ret = IIO_VAL_INT;
break;
case IIO_CONCENTRATION:
@@ -356,7 +356,7 @@ static int ccs811_probe(struct i2c_client *client,
if (ret < 0)
return ret;
- if (ret != CCS881_HW_ID_VALUE) {
+ if (ret != CCS811_HW_ID_VALUE) {
dev_err(&client->dev, "hardware id doesn't match CCS81x\n");
return -ENODEV;
}
diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c
index 9c9095ba4227..415b39339d4e 100644
--- a/drivers/iio/chemical/vz89x.c
+++ b/drivers/iio/chemical/vz89x.c
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* vz89x.c - Support for SGX Sensortech MiCS VZ89X VOC sensors
*
- * Copyright (C) 2015 Matt Ranostay <mranostay@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.
- *
- * 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) 2015-2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
*/
#include <linux/module.h>
@@ -419,6 +410,6 @@ static struct i2c_driver vz89x_driver = {
};
module_i2c_driver(vz89x_driver);
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("SGX Sensortech MiCS VZ89X VOC sensors");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
index 7d30c59da3e2..705cb3e72663 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
@@ -289,6 +289,7 @@ MODULE_DEVICE_TABLE(platform, cros_ec_sensors_ids);
static struct platform_driver cros_ec_sensors_platform_driver = {
.driver = {
.name = "cros-ec-sensors",
+ .pm = &cros_ec_sensors_pm_ops,
},
.probe = cros_ec_sensors_probe,
.id_table = cros_ec_sensors_ids,
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
index 416cae5ebbd0..a620eb5ce202 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
@@ -446,5 +446,54 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st,
}
EXPORT_SYMBOL_GPL(cros_ec_sensors_core_write);
+static int __maybe_unused cros_ec_sensors_prepare(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
+
+ if (st->curr_sampl_freq == 0)
+ return 0;
+
+ /*
+ * If the sensors are sampled at high frequency, we will not be able to
+ * sleep. Set sampling to a long period if necessary.
+ */
+ if (st->curr_sampl_freq < CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY) {
+ mutex_lock(&st->cmd_lock);
+ st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
+ st->param.ec_rate.data = CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY;
+ cros_ec_motion_send_host_cmd(st, 0);
+ mutex_unlock(&st->cmd_lock);
+ }
+ return 0;
+}
+
+static void __maybe_unused cros_ec_sensors_complete(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
+
+ if (st->curr_sampl_freq == 0)
+ return;
+
+ if (st->curr_sampl_freq < CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY) {
+ mutex_lock(&st->cmd_lock);
+ st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
+ st->param.ec_rate.data = st->curr_sampl_freq;
+ cros_ec_motion_send_host_cmd(st, 0);
+ mutex_unlock(&st->cmd_lock);
+ }
+}
+
+const struct dev_pm_ops cros_ec_sensors_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+ .prepare = cros_ec_sensors_prepare,
+ .complete = cros_ec_sensors_complete
+#endif
+};
+EXPORT_SYMBOL_GPL(cros_ec_sensors_pm_ops);
+
MODULE_DESCRIPTION("ChromeOS EC sensor hub core functions");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.h b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.h
index 8bc2ca3c2e2e..2edf68dc7336 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.h
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.h
@@ -169,6 +169,8 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st,
struct iio_chan_spec const *chan,
int val, int val2, long mask);
+extern const struct dev_pm_ops cros_ec_sensors_pm_ops;
+
/* List of extended channel specification for all sensors */
extern const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[];
diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c
index 845fd1c0fd9d..873c2bf637c0 100644
--- a/drivers/iio/dac/ad5380.c
+++ b/drivers/iio/dac/ad5380.c
@@ -158,7 +158,7 @@ static unsigned int ad5380_info_to_reg(struct iio_chan_spec const *chan,
long info)
{
switch (info) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
return AD5380_REG_DATA(chan->address);
case IIO_CHAN_INFO_CALIBBIAS:
return AD5380_REG_OFFSET(chan->address);
diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c
index 033f20eca616..9333177062c0 100644
--- a/drivers/iio/dac/ad5764.c
+++ b/drivers/iio/dac/ad5764.c
@@ -168,7 +168,7 @@ static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg,
static int ad5764_chan_info_to_reg(struct iio_chan_spec const *chan, long info)
{
switch (info) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
return AD5764_REG_DATA(chan->address);
case IIO_CHAN_INFO_CALIBBIAS:
return AD5764_REG_OFFSET(chan->address);
diff --git a/drivers/iio/dummy/Kconfig b/drivers/iio/dummy/Kconfig
index 5a29fbd3c531..c4fd108e91d3 100644
--- a/drivers/iio/dummy/Kconfig
+++ b/drivers/iio/dummy/Kconfig
@@ -9,20 +9,24 @@ config IIO_DUMMY_EVGEN
tristate
config IIO_SIMPLE_DUMMY
- tristate "An example driver with no hardware requirements"
- depends on IIO_SW_DEVICE
- help
- Driver intended mainly as documentation for how to write
- a driver. May also be useful for testing userspace code
- without hardware.
+ tristate "An example driver with no hardware requirements"
+ depends on IIO_SW_DEVICE
+ help
+ Driver intended mainly as documentation for how to write
+ a driver. May also be useful for testing userspace code
+ without hardware.
if IIO_SIMPLE_DUMMY
config IIO_SIMPLE_DUMMY_EVENTS
- bool "Event generation support"
- select IIO_DUMMY_EVGEN
- help
- Add some dummy events to the simple dummy driver.
+ bool "Event generation support"
+ select IIO_DUMMY_EVGEN
+ help
+ Add some dummy events to the simple dummy driver.
+
+ The purpose of this is to generate 'fake' event interrupts thus
+ allowing that driver's code to be as close as possible to that
+ a normal driver talking to hardware.
config IIO_SIMPLE_DUMMY_BUFFER
bool "Buffered capture support"
@@ -32,6 +36,9 @@ config IIO_SIMPLE_DUMMY_BUFFER
help
Add buffered data capture to the simple dummy driver.
+ Buffer handling elements of industrial I/O reference driver.
+ Uses the kfifo buffer.
+
endif # IIO_SIMPLE_DUMMY
endmenu
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index f59995a90387..36941e69f959 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -115,7 +115,7 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev,
*val = 0;
*val2 = 0;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
hid_sensor_power_state(&gyro_state->common_attributes, true);
report_id = gyro_state->gyro[chan->scan_index].report_id;
address = gyro_3d_addresses[chan->scan_index];
diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c
index 91aef5df24a1..84010501762d 100644
--- a/drivers/iio/health/max30100.c
+++ b/drivers/iio/health/max30100.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* max30100.c - Support for MAX30100 heart rate and pulse oximeter sensor
*
- * Copyright (C) 2015 Matt Ranostay <mranostay@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.
- *
- * 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) 2015, 2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
*
* TODO: enable pulse length controls via device tree properties
*/
@@ -518,6 +510,6 @@ static struct i2c_driver max30100_driver = {
};
module_i2c_driver(max30100_driver);
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("MAX30100 heart rate and pulse oximeter sensor");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig
index 2c0fc9a400b8..1a0d458e4f4e 100644
--- a/drivers/iio/humidity/Kconfig
+++ b/drivers/iio/humidity/Kconfig
@@ -68,10 +68,12 @@ config HTS221
config HTS221_I2C
tristate
depends on HTS221
+ select REGMAP_I2C
config HTS221_SPI
tristate
depends on HTS221
+ select REGMAP_SPI
config HTU21
tristate "Measurement Specialties HTU21 humidity & temperature sensor"
diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c
index df6bab40d6fa..1a9f8f4ffb88 100644
--- a/drivers/iio/humidity/dht11.c
+++ b/drivers/iio/humidity/dht11.c
@@ -159,7 +159,7 @@ static int dht11_decode(struct dht11 *dht11, int offset)
}
dht11->timestamp = ktime_get_boot_ns();
- if (hum_int < 20) { /* DHT22 */
+ if (hum_int < 4) { /* DHT22: 100000 = (3*256+232)*100 */
dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) *
((temp_int & 0x80) ? -100 : 100);
dht11->humidity = ((hum_int << 8) + hum_dec) * 100;
diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c
index d8438310b6d4..066e05f92081 100644
--- a/drivers/iio/humidity/hdc100x.c
+++ b/drivers/iio/humidity/hdc100x.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* hdc100x.c - Support for the TI HDC100x temperature + humidity sensors
*
- * Copyright (C) 2015 Matt Ranostay <mranostay@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.
- *
- * 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) 2015, 2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
*
* Datasheets:
* http://www.ti.com/product/HDC1000/datasheet
@@ -449,6 +441,6 @@ static struct i2c_driver hdc100x_driver = {
};
module_i2c_driver(hdc100x_driver);
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("TI HDC100x humidity and temperature sensor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/humidity/hts221.h b/drivers/iio/humidity/hts221.h
index c581af8c0f5d..e41a3d83e95d 100644
--- a/drivers/iio/humidity/hts221.h
+++ b/drivers/iio/humidity/hts221.h
@@ -15,21 +15,8 @@
#include <linux/iio/iio.h>
-#define HTS221_RX_MAX_LENGTH 8
-#define HTS221_TX_MAX_LENGTH 8
-
#define HTS221_DATA_SIZE 2
-struct hts221_transfer_buffer {
- u8 rx_buf[HTS221_RX_MAX_LENGTH];
- u8 tx_buf[HTS221_TX_MAX_LENGTH] ____cacheline_aligned;
-};
-
-struct hts221_transfer_function {
- int (*read)(struct device *dev, u8 addr, int len, u8 *data);
- int (*write)(struct device *dev, u8 addr, int len, u8 *data);
-};
-
enum hts221_sensor_type {
HTS221_SENSOR_H,
HTS221_SENSOR_T,
@@ -44,8 +31,8 @@ struct hts221_sensor {
struct hts221_hw {
const char *name;
struct device *dev;
+ struct regmap *regmap;
- struct mutex lock;
struct iio_trigger *trig;
int irq;
@@ -53,16 +40,12 @@ struct hts221_hw {
bool enabled;
u8 odr;
-
- const struct hts221_transfer_function *tf;
- struct hts221_transfer_buffer tb;
};
extern const struct dev_pm_ops hts221_pm_ops;
-int hts221_write_with_mask(struct hts221_hw *hw, u8 addr, u8 mask, u8 val);
int hts221_probe(struct device *dev, int irq, const char *name,
- const struct hts221_transfer_function *tf_ops);
+ struct regmap *regmap);
int hts221_set_enable(struct hts221_hw *hw, bool enable);
int hts221_allocate_buffers(struct hts221_hw *hw);
int hts221_allocate_trigger(struct hts221_hw *hw);
diff --git a/drivers/iio/humidity/hts221_buffer.c b/drivers/iio/humidity/hts221_buffer.c
index e971ea425268..1a94b0b91721 100644
--- a/drivers/iio/humidity/hts221_buffer.c
+++ b/drivers/iio/humidity/hts221_buffer.c
@@ -12,6 +12,8 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
+#include <linux/regmap.h>
+#include <linux/bitfield.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
@@ -38,12 +40,10 @@ static int hts221_trig_set_state(struct iio_trigger *trig, bool state)
{
struct iio_dev *iio_dev = iio_trigger_get_drvdata(trig);
struct hts221_hw *hw = iio_priv(iio_dev);
- int err;
-
- err = hts221_write_with_mask(hw, HTS221_REG_DRDY_EN_ADDR,
- HTS221_REG_DRDY_EN_MASK, state);
- return err < 0 ? err : 0;
+ return regmap_update_bits(hw->regmap, HTS221_REG_DRDY_EN_ADDR,
+ HTS221_REG_DRDY_EN_MASK,
+ FIELD_PREP(HTS221_REG_DRDY_EN_MASK, state));
}
static const struct iio_trigger_ops hts221_trigger_ops = {
@@ -53,15 +53,13 @@ static const struct iio_trigger_ops hts221_trigger_ops = {
static irqreturn_t hts221_trigger_handler_thread(int irq, void *private)
{
struct hts221_hw *hw = private;
- u8 status;
- int err;
+ int err, status;
- err = hw->tf->read(hw->dev, HTS221_REG_STATUS_ADDR, sizeof(status),
- &status);
+ err = regmap_read(hw->regmap, HTS221_REG_STATUS_ADDR, &status);
if (err < 0)
return IRQ_HANDLED;
- /*
+ /*
* H_DA bit (humidity data available) is routed to DRDY line.
* Humidity sample is computed after temperature one.
* Here we can assume data channels are both available if H_DA bit
@@ -102,8 +100,10 @@ int hts221_allocate_trigger(struct hts221_hw *hw)
break;
}
- err = hts221_write_with_mask(hw, HTS221_REG_DRDY_HL_ADDR,
- HTS221_REG_DRDY_HL_MASK, irq_active_low);
+ err = regmap_update_bits(hw->regmap, HTS221_REG_DRDY_HL_ADDR,
+ HTS221_REG_DRDY_HL_MASK,
+ FIELD_PREP(HTS221_REG_DRDY_HL_MASK,
+ irq_active_low));
if (err < 0)
return err;
@@ -114,9 +114,10 @@ int hts221_allocate_trigger(struct hts221_hw *hw)
open_drain = true;
}
- err = hts221_write_with_mask(hw, HTS221_REG_DRDY_PP_OD_ADDR,
- HTS221_REG_DRDY_PP_OD_MASK,
- open_drain);
+ err = regmap_update_bits(hw->regmap, HTS221_REG_DRDY_PP_OD_ADDR,
+ HTS221_REG_DRDY_PP_OD_MASK,
+ FIELD_PREP(HTS221_REG_DRDY_PP_OD_MASK,
+ open_drain));
if (err < 0)
return err;
@@ -171,15 +172,15 @@ static irqreturn_t hts221_buffer_handler_thread(int irq, void *p)
/* humidity data */
ch = &iio_dev->channels[HTS221_SENSOR_H];
- err = hw->tf->read(hw->dev, ch->address, HTS221_DATA_SIZE,
- buffer);
+ err = regmap_bulk_read(hw->regmap, ch->address,
+ buffer, HTS221_DATA_SIZE);
if (err < 0)
goto out;
/* temperature data */
ch = &iio_dev->channels[HTS221_SENSOR_T];
- err = hw->tf->read(hw->dev, ch->address, HTS221_DATA_SIZE,
- buffer + HTS221_DATA_SIZE);
+ err = regmap_bulk_read(hw->regmap, ch->address,
+ buffer + HTS221_DATA_SIZE, HTS221_DATA_SIZE);
if (err < 0)
goto out;
diff --git a/drivers/iio/humidity/hts221_core.c b/drivers/iio/humidity/hts221_core.c
index d3f7904766bd..166946d4978d 100644
--- a/drivers/iio/humidity/hts221_core.c
+++ b/drivers/iio/humidity/hts221_core.c
@@ -14,7 +14,8 @@
#include <linux/iio/sysfs.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <asm/unaligned.h>
+#include <linux/regmap.h>
+#include <linux/bitfield.h>
#include "hts221.h"
@@ -131,38 +132,11 @@ static const struct iio_chan_spec hts221_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(2),
};
-int hts221_write_with_mask(struct hts221_hw *hw, u8 addr, u8 mask, u8 val)
-{
- u8 data;
- int err;
-
- mutex_lock(&hw->lock);
-
- err = hw->tf->read(hw->dev, addr, sizeof(data), &data);
- if (err < 0) {
- dev_err(hw->dev, "failed to read %02x register\n", addr);
- goto unlock;
- }
-
- data = (data & ~mask) | ((val << __ffs(mask)) & mask);
-
- err = hw->tf->write(hw->dev, addr, sizeof(data), &data);
- if (err < 0)
- dev_err(hw->dev, "failed to write %02x register\n", addr);
-
-unlock:
- mutex_unlock(&hw->lock);
-
- return err;
-}
-
static int hts221_check_whoami(struct hts221_hw *hw)
{
- u8 data;
- int err;
+ int err, data;
- err = hw->tf->read(hw->dev, HTS221_REG_WHOAMI_ADDR, sizeof(data),
- &data);
+ err = regmap_read(hw->regmap, HTS221_REG_WHOAMI_ADDR, &data);
if (err < 0) {
dev_err(hw->dev, "failed to read whoami register\n");
return err;
@@ -188,8 +162,10 @@ static int hts221_update_odr(struct hts221_hw *hw, u8 odr)
if (i == ARRAY_SIZE(hts221_odr_table))
return -EINVAL;
- err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
- HTS221_ODR_MASK, hts221_odr_table[i].val);
+ err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+ HTS221_ODR_MASK,
+ FIELD_PREP(HTS221_ODR_MASK,
+ hts221_odr_table[i].val));
if (err < 0)
return err;
@@ -202,8 +178,8 @@ static int hts221_update_avg(struct hts221_hw *hw,
enum hts221_sensor_type type,
u16 val)
{
- int i, err;
const struct hts221_avg *avg = &hts221_avg_list[type];
+ int i, err, data;
for (i = 0; i < HTS221_AVG_DEPTH; i++)
if (avg->avg_avl[i] == val)
@@ -212,7 +188,9 @@ static int hts221_update_avg(struct hts221_hw *hw,
if (i == HTS221_AVG_DEPTH)
return -EINVAL;
- err = hts221_write_with_mask(hw, avg->addr, avg->mask, i);
+ data = ((i << __ffs(avg->mask)) & avg->mask);
+ err = regmap_update_bits(hw->regmap, avg->addr,
+ avg->mask, data);
if (err < 0)
return err;
@@ -274,8 +252,9 @@ int hts221_set_enable(struct hts221_hw *hw, bool enable)
{
int err;
- err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
- HTS221_ENABLE_MASK, enable);
+ err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+ HTS221_ENABLE_MASK,
+ FIELD_PREP(HTS221_ENABLE_MASK, enable));
if (err < 0)
return err;
@@ -286,38 +265,35 @@ int hts221_set_enable(struct hts221_hw *hw, bool enable)
static int hts221_parse_temp_caldata(struct hts221_hw *hw)
{
- int err, *slope, *b_gen;
+ int err, *slope, *b_gen, cal0, cal1;
s16 cal_x0, cal_x1, cal_y0, cal_y1;
- u8 cal0, cal1;
+ __le16 val;
- err = hw->tf->read(hw->dev, HTS221_REG_0T_CAL_Y_H,
- sizeof(cal0), &cal0);
+ err = regmap_read(hw->regmap, HTS221_REG_0T_CAL_Y_H, &cal0);
if (err < 0)
return err;
- err = hw->tf->read(hw->dev, HTS221_REG_T1_T0_CAL_Y_H,
- sizeof(cal1), &cal1);
+ err = regmap_read(hw->regmap, HTS221_REG_T1_T0_CAL_Y_H, &cal1);
if (err < 0)
return err;
- cal_y0 = (le16_to_cpu(cal1 & 0x3) << 8) | cal0;
+ cal_y0 = ((cal1 & 0x3) << 8) | cal0;
- err = hw->tf->read(hw->dev, HTS221_REG_1T_CAL_Y_H,
- sizeof(cal0), &cal0);
+ err = regmap_read(hw->regmap, HTS221_REG_1T_CAL_Y_H, &cal0);
if (err < 0)
return err;
cal_y1 = (((cal1 & 0xc) >> 2) << 8) | cal0;
- err = hw->tf->read(hw->dev, HTS221_REG_0T_CAL_X_L, sizeof(cal_x0),
- (u8 *)&cal_x0);
+ err = regmap_bulk_read(hw->regmap, HTS221_REG_0T_CAL_X_L,
+ &val, sizeof(val));
if (err < 0)
return err;
- cal_x0 = le16_to_cpu(cal_x0);
+ cal_x0 = le16_to_cpu(val);
- err = hw->tf->read(hw->dev, HTS221_REG_1T_CAL_X_L, sizeof(cal_x1),
- (u8 *)&cal_x1);
+ err = regmap_bulk_read(hw->regmap, HTS221_REG_1T_CAL_X_L,
+ &val, sizeof(val));
if (err < 0)
return err;
- cal_x1 = le16_to_cpu(cal_x1);
+ cal_x1 = le16_to_cpu(val);
slope = &hw->sensors[HTS221_SENSOR_T].slope;
b_gen = &hw->sensors[HTS221_SENSOR_T].b_gen;
@@ -332,33 +308,31 @@ static int hts221_parse_temp_caldata(struct hts221_hw *hw)
static int hts221_parse_rh_caldata(struct hts221_hw *hw)
{
- int err, *slope, *b_gen;
+ int err, *slope, *b_gen, data;
s16 cal_x0, cal_x1, cal_y0, cal_y1;
- u8 data;
+ __le16 val;
- err = hw->tf->read(hw->dev, HTS221_REG_0RH_CAL_Y_H, sizeof(data),
- &data);
+ err = regmap_read(hw->regmap, HTS221_REG_0RH_CAL_Y_H, &data);
if (err < 0)
return err;
cal_y0 = data;
- err = hw->tf->read(hw->dev, HTS221_REG_1RH_CAL_Y_H, sizeof(data),
- &data);
+ err = regmap_read(hw->regmap, HTS221_REG_1RH_CAL_Y_H, &data);
if (err < 0)
return err;
cal_y1 = data;
- err = hw->tf->read(hw->dev, HTS221_REG_0RH_CAL_X_H, sizeof(cal_x0),
- (u8 *)&cal_x0);
+ err = regmap_bulk_read(hw->regmap, HTS221_REG_0RH_CAL_X_H,
+ &val, sizeof(val));
if (err < 0)
return err;
- cal_x0 = le16_to_cpu(cal_x0);
+ cal_x0 = le16_to_cpu(val);
- err = hw->tf->read(hw->dev, HTS221_REG_1RH_CAL_X_H, sizeof(cal_x1),
- (u8 *)&cal_x1);
+ err = regmap_bulk_read(hw->regmap, HTS221_REG_1RH_CAL_X_H,
+ &val, sizeof(val));
if (err < 0)
return err;
- cal_x1 = le16_to_cpu(cal_x1);
+ cal_x1 = le16_to_cpu(val);
slope = &hw->sensors[HTS221_SENSOR_H].slope;
b_gen = &hw->sensors[HTS221_SENSOR_H].b_gen;
@@ -431,7 +405,7 @@ static int hts221_get_sensor_offset(struct hts221_hw *hw,
static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val)
{
- u8 data[HTS221_DATA_SIZE];
+ __le16 data;
int err;
err = hts221_set_enable(hw, true);
@@ -440,13 +414,13 @@ static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val)
msleep(50);
- err = hw->tf->read(hw->dev, addr, sizeof(data), data);
+ err = regmap_bulk_read(hw->regmap, addr, &data, sizeof(data));
if (err < 0)
return err;
hts221_set_enable(hw, false);
- *val = (s16)get_unaligned_le16(data);
+ *val = (s16)le16_to_cpu(data);
return IIO_VAL_INT;
}
@@ -582,7 +556,7 @@ static const struct iio_info hts221_info = {
static const unsigned long hts221_scan_masks[] = {0x3, 0x0};
int hts221_probe(struct device *dev, int irq, const char *name,
- const struct hts221_transfer_function *tf_ops)
+ struct regmap *regmap)
{
struct iio_dev *iio_dev;
struct hts221_hw *hw;
@@ -599,9 +573,7 @@ int hts221_probe(struct device *dev, int irq, const char *name,
hw->name = name;
hw->dev = dev;
hw->irq = irq;
- hw->tf = tf_ops;
-
- mutex_init(&hw->lock);
+ hw->regmap = regmap;
err = hts221_check_whoami(hw);
if (err < 0)
@@ -616,8 +588,9 @@ int hts221_probe(struct device *dev, int irq, const char *name,
iio_dev->info = &hts221_info;
/* enable Block Data Update */
- err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
- HTS221_BDU_MASK, 1);
+ err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+ HTS221_BDU_MASK,
+ FIELD_PREP(HTS221_BDU_MASK, 1));
if (err < 0)
return err;
@@ -673,12 +646,10 @@ static int __maybe_unused hts221_suspend(struct device *dev)
{
struct iio_dev *iio_dev = dev_get_drvdata(dev);
struct hts221_hw *hw = iio_priv(iio_dev);
- int err;
- err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
- HTS221_ENABLE_MASK, false);
-
- return err < 0 ? err : 0;
+ return regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+ HTS221_ENABLE_MASK,
+ FIELD_PREP(HTS221_ENABLE_MASK, false));
}
static int __maybe_unused hts221_resume(struct device *dev)
@@ -688,9 +659,10 @@ static int __maybe_unused hts221_resume(struct device *dev)
int err = 0;
if (hw->enabled)
- err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
- HTS221_ENABLE_MASK, true);
-
+ err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,
+ HTS221_ENABLE_MASK,
+ FIELD_PREP(HTS221_ENABLE_MASK,
+ true));
return err;
}
diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c
index 2c97350a0f76..b5b3f408a658 100644
--- a/drivers/iio/humidity/hts221_i2c.c
+++ b/drivers/iio/humidity/hts221_i2c.c
@@ -13,61 +13,33 @@
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/slab.h>
-#include "hts221.h"
-
-#define I2C_AUTO_INCREMENT 0x80
-
-static int hts221_i2c_read(struct device *dev, u8 addr, int len, u8 *data)
-{
- struct i2c_msg msg[2];
- struct i2c_client *client = to_i2c_client(dev);
-
- if (len > 1)
- addr |= I2C_AUTO_INCREMENT;
-
- msg[0].addr = client->addr;
- msg[0].flags = client->flags;
- msg[0].len = 1;
- msg[0].buf = &addr;
-
- msg[1].addr = client->addr;
- msg[1].flags = client->flags | I2C_M_RD;
- msg[1].len = len;
- msg[1].buf = data;
-
- return i2c_transfer(client->adapter, msg, 2);
-}
+#include <linux/regmap.h>
-static int hts221_i2c_write(struct device *dev, u8 addr, int len, u8 *data)
-{
- u8 send[len + 1];
- struct i2c_msg msg;
- struct i2c_client *client = to_i2c_client(dev);
-
- if (len > 1)
- addr |= I2C_AUTO_INCREMENT;
-
- send[0] = addr;
- memcpy(&send[1], data, len * sizeof(u8));
-
- msg.addr = client->addr;
- msg.flags = client->flags;
- msg.len = len + 1;
- msg.buf = send;
+#include "hts221.h"
- return i2c_transfer(client->adapter, &msg, 1);
-}
+#define HTS221_I2C_AUTO_INCREMENT BIT(7)
-static const struct hts221_transfer_function hts221_transfer_fn = {
- .read = hts221_i2c_read,
- .write = hts221_i2c_write,
+static const struct regmap_config hts221_i2c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .write_flag_mask = HTS221_I2C_AUTO_INCREMENT,
+ .read_flag_mask = HTS221_I2C_AUTO_INCREMENT,
};
static int hts221_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &hts221_i2c_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "Failed to register i2c regmap %d\n",
+ (int)PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
return hts221_probe(&client->dev, client->irq,
- client->name, &hts221_transfer_fn);
+ client->name, regmap);
}
static const struct acpi_device_id hts221_acpi_match[] = {
diff --git a/drivers/iio/humidity/hts221_spi.c b/drivers/iio/humidity/hts221_spi.c
index 55b29b53b9d1..9c005f037026 100644
--- a/drivers/iio/humidity/hts221_spi.c
+++ b/drivers/iio/humidity/hts221_spi.c
@@ -12,76 +12,33 @@
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include "hts221.h"
-
-#define SENSORS_SPI_READ 0x80
-#define SPI_AUTO_INCREMENT 0x40
-
-static int hts221_spi_read(struct device *dev, u8 addr, int len, u8 *data)
-{
- int err;
- struct spi_device *spi = to_spi_device(dev);
- struct iio_dev *iio_dev = spi_get_drvdata(spi);
- struct hts221_hw *hw = iio_priv(iio_dev);
-
- struct spi_transfer xfers[] = {
- {
- .tx_buf = hw->tb.tx_buf,
- .bits_per_word = 8,
- .len = 1,
- },
- {
- .rx_buf = hw->tb.rx_buf,
- .bits_per_word = 8,
- .len = len,
- }
- };
-
- if (len > 1)
- addr |= SPI_AUTO_INCREMENT;
- hw->tb.tx_buf[0] = addr | SENSORS_SPI_READ;
-
- err = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers));
- if (err < 0)
- return err;
-
- memcpy(data, hw->tb.rx_buf, len * sizeof(u8));
-
- return len;
-}
-
-static int hts221_spi_write(struct device *dev, u8 addr, int len, u8 *data)
-{
- struct spi_device *spi = to_spi_device(dev);
- struct iio_dev *iio_dev = spi_get_drvdata(spi);
- struct hts221_hw *hw = iio_priv(iio_dev);
-
- struct spi_transfer xfers = {
- .tx_buf = hw->tb.tx_buf,
- .bits_per_word = 8,
- .len = len + 1,
- };
-
- if (len >= HTS221_TX_MAX_LENGTH)
- return -ENOMEM;
+#include <linux/regmap.h>
- if (len > 1)
- addr |= SPI_AUTO_INCREMENT;
- hw->tb.tx_buf[0] = addr;
- memcpy(&hw->tb.tx_buf[1], data, len);
+#include "hts221.h"
- return spi_sync_transfer(spi, &xfers, 1);
-}
+#define HTS221_SPI_READ BIT(7)
+#define HTS221_SPI_AUTO_INCREMENT BIT(6)
-static const struct hts221_transfer_function hts221_transfer_fn = {
- .read = hts221_spi_read,
- .write = hts221_spi_write,
+static const struct regmap_config hts221_spi_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .write_flag_mask = HTS221_SPI_AUTO_INCREMENT,
+ .read_flag_mask = HTS221_SPI_READ | HTS221_SPI_AUTO_INCREMENT,
};
static int hts221_spi_probe(struct spi_device *spi)
{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &hts221_spi_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "Failed to register spi regmap %d\n",
+ (int)PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
return hts221_probe(&spi->dev, spi->irq,
- spi->modalias, &hts221_transfer_fn);
+ spi->modalias, regmap);
}
static const struct of_device_id hts221_spi_of_match[] = {
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index 8fdd723afa05..a3cc7cd97026 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -27,7 +27,7 @@ enum st_lsm6dsx_hw_id {
ST_LSM6DSX_MAX_ID,
};
-#define ST_LSM6DSX_BUFF_SIZE 256
+#define ST_LSM6DSX_BUFF_SIZE 400
#define ST_LSM6DSX_CHAN_SIZE 2
#define ST_LSM6DSX_SAMPLE_SIZE 6
#define ST_LSM6DSX_MAX_WORD_LEN ((32 / ST_LSM6DSX_SAMPLE_SIZE) * \
@@ -58,12 +58,27 @@ struct st_lsm6dsx_fifo_ops {
};
/**
+ * struct st_lsm6dsx_hw_ts_settings - ST IMU hw timer settings
+ * @timer_en: Hw timer enable register info (addr + mask).
+ * @hr_timer: Hw timer resolution register info (addr + mask).
+ * @fifo_en: Hw timer FIFO enable register info (addr + mask).
+ * @decimator: Hw timer FIFO decimator register info (addr + mask).
+ */
+struct st_lsm6dsx_hw_ts_settings {
+ struct st_lsm6dsx_reg timer_en;
+ struct st_lsm6dsx_reg hr_timer;
+ struct st_lsm6dsx_reg fifo_en;
+ struct st_lsm6dsx_reg decimator;
+};
+
+/**
* struct st_lsm6dsx_settings - ST IMU sensor settings
* @wai: Sensor WhoAmI default value.
* @max_fifo_size: Sensor max fifo length in FIFO words.
* @id: List of hw id supported by the driver configuration.
* @decimator: List of decimator register info (addr + mask).
* @fifo_ops: Sensor hw FIFO parameters.
+ * @ts_settings: Hw timer related settings.
*/
struct st_lsm6dsx_settings {
u8 wai;
@@ -71,6 +86,7 @@ struct st_lsm6dsx_settings {
enum st_lsm6dsx_hw_id id[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_fifo_ops fifo_ops;
+ struct st_lsm6dsx_hw_ts_settings ts_settings;
};
enum st_lsm6dsx_sensor_id {
@@ -94,8 +110,7 @@ enum st_lsm6dsx_fifo_mode {
* @watermark: Sensor watermark level.
* @sip: Number of samples in a given pattern.
* @decimator: FIFO decimation factor.
- * @delta_ts: Delta time between two consecutive interrupts.
- * @ts: Latest timestamp from the interrupt handler.
+ * @ts_ref: Sensor timestamp reference for hw one.
*/
struct st_lsm6dsx_sensor {
char name[32];
@@ -108,9 +123,7 @@ struct st_lsm6dsx_sensor {
u16 watermark;
u8 sip;
u8 decimator;
-
- s64 delta_ts;
- s64 ts;
+ s64 ts_ref;
};
/**
@@ -122,7 +135,8 @@ struct st_lsm6dsx_sensor {
* @conf_lock: Mutex to prevent concurrent FIFO configuration update.
* @fifo_mode: FIFO operating mode supported by the device.
* @enable_mask: Enabled sensor bitmask.
- * @sip: Total number of samples (acc/gyro) in a given pattern.
+ * @ts_sip: Total number of timestamp samples in a given pattern.
+ * @sip: Total number of samples (acc/gyro/ts) in a given pattern.
* @buff: Device read buffer.
* @iio_devs: Pointers to acc/gyro iio_dev instances.
* @settings: Pointer to the specific sensor settings in use.
@@ -137,6 +151,7 @@ struct st_lsm6dsx_hw {
enum st_lsm6dsx_fifo_mode fifo_mode;
u8 enable_mask;
+ u8 ts_sip;
u8 sip;
u8 *buff;
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
index 1d6aa9b1a4cf..1045e025e92b 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -46,9 +46,13 @@
#define ST_LSM6DSX_FIFO_ODR_MASK GENMASK(6, 3)
#define ST_LSM6DSX_FIFO_EMPTY_MASK BIT(12)
#define ST_LSM6DSX_REG_FIFO_OUTL_ADDR 0x3e
+#define ST_LSM6DSX_REG_TS_RESET_ADDR 0x42
#define ST_LSM6DSX_MAX_FIFO_ODR_VAL 0x08
+#define ST_LSM6DSX_TS_SENSITIVITY 25000UL /* 25us */
+#define ST_LSM6DSX_TS_RESET_VAL 0xaa
+
struct st_lsm6dsx_decimator_entry {
u8 decimator;
u8 val;
@@ -98,9 +102,10 @@ static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw,
static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
{
+ u16 max_odr, min_odr, sip = 0, ts_sip = 0;
+ const struct st_lsm6dsx_reg *ts_dec_reg;
struct st_lsm6dsx_sensor *sensor;
- u16 max_odr, min_odr, sip = 0;
- int err, i;
+ int err = 0, i;
u8 data;
st_lsm6dsx_get_max_min_odr(hw, &max_odr, &min_odr);
@@ -119,6 +124,7 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
sensor->decimator = 0;
data = 0;
}
+ ts_sip = max_t(u16, ts_sip, sensor->sip);
dec_reg = &hw->settings->decimator[sensor->id];
if (dec_reg->addr) {
@@ -131,9 +137,23 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
}
sip += sensor->sip;
}
- hw->sip = sip;
+ hw->sip = sip + ts_sip;
+ hw->ts_sip = ts_sip;
- return 0;
+ /*
+ * update hw ts decimator if necessary. Decimator for hw timestamp
+ * is always 1 or 0 in order to have a ts sample for each data
+ * sample in FIFO
+ */
+ ts_dec_reg = &hw->settings->ts_settings.decimator;
+ if (ts_dec_reg->addr) {
+ int val, ts_dec = !!hw->ts_sip;
+
+ val = ST_LSM6DSX_SHIFT_VAL(ts_dec, ts_dec_reg->mask);
+ err = regmap_update_bits(hw->regmap, ts_dec_reg->addr,
+ ts_dec_reg->mask, val);
+ }
+ return err;
}
int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
@@ -208,6 +228,28 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
&wdata, sizeof(wdata));
}
+static int st_lsm6dsx_reset_hw_ts(struct st_lsm6dsx_hw *hw)
+{
+ struct st_lsm6dsx_sensor *sensor;
+ int i, err;
+
+ /* reset hw ts counter */
+ err = regmap_write(hw->regmap, ST_LSM6DSX_REG_TS_RESET_ADDR,
+ ST_LSM6DSX_TS_RESET_VAL);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ sensor = iio_priv(hw->iio_devs[i]);
+ /*
+ * store enable buffer timestamp as reference for
+ * hw timestamp
+ */
+ sensor->ts_ref = iio_get_time_ns(hw->iio_devs[i]);
+ }
+ return 0;
+}
+
/*
* Set max bulk read to ST_LSM6DSX_MAX_WORD_LEN in order to avoid
* a kmalloc for each bus access
@@ -231,6 +273,8 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 *data,
return 0;
}
+#define ST_LSM6DSX_IIO_BUFF_SIZE (ALIGN(ST_LSM6DSX_SAMPLE_SIZE, \
+ sizeof(s64)) + sizeof(s64))
/**
* st_lsm6dsx_read_fifo() - LSM6DS3-LSM6DS3H-LSM6DSL-LSM6DSM read FIFO routine
* @hw: Pointer to instance of struct st_lsm6dsx_hw.
@@ -243,11 +287,13 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
{
u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
- int err, acc_sip, gyro_sip, read_len, samples, offset;
+ int err, acc_sip, gyro_sip, ts_sip, read_len, offset;
struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor;
- s64 acc_ts, acc_delta_ts, gyro_ts, gyro_delta_ts;
- u8 iio_buff[ALIGN(ST_LSM6DSX_SAMPLE_SIZE, sizeof(s64)) + sizeof(s64)];
+ u8 gyro_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
+ u8 acc_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
+ bool reset_ts = false;
__le16 fifo_status;
+ s64 ts = 0;
err = regmap_bulk_read(hw->regmap,
hw->settings->fifo_ops.fifo_diff.addr,
@@ -260,23 +306,10 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
fifo_len = (le16_to_cpu(fifo_status) & fifo_diff_mask) *
ST_LSM6DSX_CHAN_SIZE;
- samples = fifo_len / ST_LSM6DSX_SAMPLE_SIZE;
fifo_len = (fifo_len / pattern_len) * pattern_len;
- /*
- * compute delta timestamp between two consecutive samples
- * in order to estimate queueing time of data generated
- * by the sensor
- */
acc_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
- acc_ts = acc_sensor->ts - acc_sensor->delta_ts;
- acc_delta_ts = div_s64(acc_sensor->delta_ts * acc_sensor->decimator,
- samples);
-
gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
- gyro_ts = gyro_sensor->ts - gyro_sensor->delta_ts;
- gyro_delta_ts = div_s64(gyro_sensor->delta_ts * gyro_sensor->decimator,
- samples);
for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
err = st_lsm6dsx_read_block(hw, hw->buff, pattern_len);
@@ -287,7 +320,7 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
* Data are written to the FIFO with a specific pattern
* depending on the configured ODRs. The first sequence of data
* stored in FIFO contains the data of all enabled sensors
- * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated
+ * (e.g. Gx, Gy, Gz, Ax, Ay, Az, Ts), then data are repeated
* depending on the value of the decimation factor set for each
* sensor.
*
@@ -296,35 +329,65 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
* - gyroscope ODR = 208Hz, accelerometer ODR = 104Hz
* Since the gyroscope ODR is twice the accelerometer one, the
* following pattern is repeated every 9 samples:
- * - Gx, Gy, Gz, Ax, Ay, Az, Gx, Gy, Gz
+ * - Gx, Gy, Gz, Ax, Ay, Az, Ts, Gx, Gy, Gz, Ts, Gx, ..
*/
gyro_sip = gyro_sensor->sip;
acc_sip = acc_sensor->sip;
+ ts_sip = hw->ts_sip;
offset = 0;
while (acc_sip > 0 || gyro_sip > 0) {
- if (gyro_sip-- > 0) {
- memcpy(iio_buff, &hw->buff[offset],
+ if (gyro_sip > 0) {
+ memcpy(gyro_buff, &hw->buff[offset],
ST_LSM6DSX_SAMPLE_SIZE);
- iio_push_to_buffers_with_timestamp(
- hw->iio_devs[ST_LSM6DSX_ID_GYRO],
- iio_buff, gyro_ts);
offset += ST_LSM6DSX_SAMPLE_SIZE;
- gyro_ts += gyro_delta_ts;
}
-
- if (acc_sip-- > 0) {
- memcpy(iio_buff, &hw->buff[offset],
+ if (acc_sip > 0) {
+ memcpy(acc_buff, &hw->buff[offset],
ST_LSM6DSX_SAMPLE_SIZE);
- iio_push_to_buffers_with_timestamp(
- hw->iio_devs[ST_LSM6DSX_ID_ACC],
- iio_buff, acc_ts);
offset += ST_LSM6DSX_SAMPLE_SIZE;
- acc_ts += acc_delta_ts;
}
+
+ if (ts_sip-- > 0) {
+ u8 data[ST_LSM6DSX_SAMPLE_SIZE];
+
+ memcpy(data, &hw->buff[offset], sizeof(data));
+ /*
+ * hw timestamp is 3B long and it is stored
+ * in FIFO using 6B as 4th FIFO data set
+ * according to this schema:
+ * B0 = ts[15:8], B1 = ts[23:16], B3 = ts[7:0]
+ */
+ ts = data[1] << 16 | data[0] << 8 | data[3];
+ /*
+ * check if hw timestamp engine is going to
+ * reset (the sensor generates an interrupt
+ * to signal the hw timestamp will reset in
+ * 1.638s)
+ */
+ if (!reset_ts && ts >= 0xff0000)
+ reset_ts = true;
+ ts *= ST_LSM6DSX_TS_SENSITIVITY;
+
+ offset += ST_LSM6DSX_SAMPLE_SIZE;
+ }
+
+ if (gyro_sip-- > 0)
+ iio_push_to_buffers_with_timestamp(
+ hw->iio_devs[ST_LSM6DSX_ID_GYRO],
+ gyro_buff, gyro_sensor->ts_ref + ts);
+ if (acc_sip-- > 0)
+ iio_push_to_buffers_with_timestamp(
+ hw->iio_devs[ST_LSM6DSX_ID_ACC],
+ acc_buff, acc_sensor->ts_ref + ts);
}
}
+ if (unlikely(reset_ts)) {
+ err = st_lsm6dsx_reset_hw_ts(hw);
+ if (err < 0)
+ return err;
+ }
return read_len;
}
@@ -379,15 +442,12 @@ static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
goto out;
if (hw->enable_mask) {
- err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
+ /* reset hw ts counter */
+ err = st_lsm6dsx_reset_hw_ts(hw);
if (err < 0)
goto out;
- /*
- * store enable buffer timestamp as reference to compute
- * first delta timestamp
- */
- sensor->ts = iio_get_time_ns(iio_dev);
+ err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
}
out:
@@ -399,25 +459,8 @@ out:
static irqreturn_t st_lsm6dsx_handler_irq(int irq, void *private)
{
struct st_lsm6dsx_hw *hw = private;
- struct st_lsm6dsx_sensor *sensor;
- int i;
-
- if (!hw->sip)
- return IRQ_NONE;
-
- for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
- sensor = iio_priv(hw->iio_devs[i]);
-
- if (sensor->sip > 0) {
- s64 timestamp;
-
- timestamp = iio_get_time_ns(hw->iio_devs[i]);
- sensor->delta_ts = timestamp - sensor->ts;
- sensor->ts = timestamp;
- }
- }
- return IRQ_WAKE_THREAD;
+ return hw->sip > 0 ? IRQ_WAKE_THREAD : IRQ_NONE;
}
static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index c2fa3239b9c6..8656d72ef4ee 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -181,6 +181,24 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
.th_wl = 3, /* 1LSB = 2B */
},
+ .ts_settings = {
+ .timer_en = {
+ .addr = 0x58,
+ .mask = BIT(7),
+ },
+ .hr_timer = {
+ .addr = 0x5c,
+ .mask = BIT(4),
+ },
+ .fifo_en = {
+ .addr = 0x07,
+ .mask = BIT(7),
+ },
+ .decimator = {
+ .addr = 0x09,
+ .mask = GENMASK(5, 3),
+ },
+ },
},
{
.wai = 0x69,
@@ -209,6 +227,24 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
.th_wl = 3, /* 1LSB = 2B */
},
+ .ts_settings = {
+ .timer_en = {
+ .addr = 0x58,
+ .mask = BIT(7),
+ },
+ .hr_timer = {
+ .addr = 0x5c,
+ .mask = BIT(4),
+ },
+ .fifo_en = {
+ .addr = 0x07,
+ .mask = BIT(7),
+ },
+ .decimator = {
+ .addr = 0x09,
+ .mask = GENMASK(5, 3),
+ },
+ },
},
{
.wai = 0x6a,
@@ -238,6 +274,24 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
.th_wl = 3, /* 1LSB = 2B */
},
+ .ts_settings = {
+ .timer_en = {
+ .addr = 0x19,
+ .mask = BIT(5),
+ },
+ .hr_timer = {
+ .addr = 0x5c,
+ .mask = BIT(4),
+ },
+ .fifo_en = {
+ .addr = 0x07,
+ .mask = BIT(7),
+ },
+ .decimator = {
+ .addr = 0x09,
+ .mask = GENMASK(5, 3),
+ },
+ },
},
};
@@ -630,6 +684,44 @@ static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
return err;
}
+static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw)
+{
+ const struct st_lsm6dsx_hw_ts_settings *ts_settings;
+ int err, val;
+
+ ts_settings = &hw->settings->ts_settings;
+ /* enable hw timestamp generation if necessary */
+ if (ts_settings->timer_en.addr) {
+ val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->timer_en.mask);
+ err = regmap_update_bits(hw->regmap,
+ ts_settings->timer_en.addr,
+ ts_settings->timer_en.mask, val);
+ if (err < 0)
+ return err;
+ }
+
+ /* enable high resolution for hw ts timer if necessary */
+ if (ts_settings->hr_timer.addr) {
+ val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->hr_timer.mask);
+ err = regmap_update_bits(hw->regmap,
+ ts_settings->hr_timer.addr,
+ ts_settings->hr_timer.mask, val);
+ if (err < 0)
+ return err;
+ }
+
+ /* enable ts queueing in FIFO if necessary */
+ if (ts_settings->fifo_en.addr) {
+ val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->fifo_en.mask);
+ err = regmap_update_bits(hw->regmap,
+ ts_settings->fifo_en.addr,
+ ts_settings->fifo_en.mask, val);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
{
u8 drdy_int_reg;
@@ -654,10 +746,14 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
if (err < 0)
return err;
- return regmap_update_bits(hw->regmap, drdy_int_reg,
- ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
- FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
- 1));
+ err = regmap_update_bits(hw->regmap, drdy_int_reg,
+ ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
+ FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
+ 1));
+ if (err < 0)
+ return err;
+
+ return st_lsm6dsx_init_hw_timer(hw);
}
static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 93fd421b10d7..074e50657366 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -275,6 +275,16 @@ config LTR501
This driver can also be built as a module. If so, the module
will be called ltr501.
+config LV0104CS
+ tristate "LV0104CS Ambient Light Sensor"
+ depends on I2C
+ help
+ Say Y here if you want to build support for the On Semiconductor
+ LV0104CS ambient light sensor.
+
+ To compile this driver as a module, choose M here:
+ the module will be called lv0104cs.
+
config MAX44000
tristate "MAX44000 Ambient and Infrared Proximity Sensor"
depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index f714067a7816..f1777036d4f8 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_ISL29125) += isl29125.o
obj-$(CONFIG_JSA1212) += jsa1212.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
obj-$(CONFIG_LTR501) += ltr501.o
+obj-$(CONFIG_LV0104CS) += lv0104cs.o
obj-$(CONFIG_MAX44000) += max44000.o
obj-$(CONFIG_OPT3001) += opt3001.o
obj-$(CONFIG_PA12203001) += pa12203001.o
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
index a8fa00e31c39..1f112ae15f3c 100644
--- a/drivers/iio/light/apds9960.c
+++ b/drivers/iio/light/apds9960.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* apds9960.c - Support for Avago APDS9960 gesture/RGB/ALS/proximity sensor
*
- * Copyright (C) 2015 Matt Ranostay <mranostay@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.
- *
- * 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) 2015, 2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
*
* TODO: gesture + proximity calib offsets
*/
@@ -1141,6 +1133,6 @@ static struct i2c_driver apds9960_driver = {
};
module_i2c_driver(apds9960_driver);
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("ADPS9960 Gesture/RGB/ALS/Proximity sensor");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c
index acfad4aeb27a..8e8a0e7f78d1 100644
--- a/drivers/iio/light/cros_ec_light_prox.c
+++ b/drivers/iio/light/cros_ec_light_prox.c
@@ -276,6 +276,7 @@ MODULE_DEVICE_TABLE(platform, cros_ec_light_prox_ids);
static struct platform_driver cros_ec_light_prox_platform_driver = {
.driver = {
.name = "cros-ec-light-prox",
+ .pm = &cros_ec_sensors_pm_ops,
},
.probe = cros_ec_light_prox_probe,
.id_table = cros_ec_light_prox_ids,
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index befd693a4a31..406caaee9a3c 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -97,7 +97,7 @@ static int als_read_raw(struct iio_dev *indio_dev,
*val = 0;
*val2 = 0;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
switch (chan->scan_index) {
case CHANNEL_SCAN_INDEX_INTENSITY:
case CHANNEL_SCAN_INDEX_ILLUM:
diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c
index 36208a3652e9..ff5a3324b489 100644
--- a/drivers/iio/light/lm3533-als.c
+++ b/drivers/iio/light/lm3533-als.c
@@ -199,7 +199,7 @@ static int lm3533_als_read_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_LIGHT:
ret = lm3533_als_get_adc(indio_dev, false, val);
diff --git a/drivers/iio/light/lv0104cs.c b/drivers/iio/light/lv0104cs.c
new file mode 100644
index 000000000000..55b8e2855647
--- /dev/null
+++ b/drivers/iio/light/lv0104cs.c
@@ -0,0 +1,531 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * lv0104cs.c: LV0104CS Ambient Light Sensor Driver
+ *
+ * Copyright (C) 2018
+ * Author: Jeff LaBundy <jeff@labundy.com>
+ *
+ * 7-bit I2C slave address: 0x13
+ *
+ * Link to data sheet: http://www.onsemi.com/pub/Collateral/LV0104CS-D.PDF
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define LV0104CS_REGVAL_MEASURE 0xE0
+#define LV0104CS_REGVAL_SLEEP 0x00
+
+#define LV0104CS_SCALE_0_25X 0
+#define LV0104CS_SCALE_1X 1
+#define LV0104CS_SCALE_2X 2
+#define LV0104CS_SCALE_8X 3
+#define LV0104CS_SCALE_SHIFT 3
+
+#define LV0104CS_INTEG_12_5MS 0
+#define LV0104CS_INTEG_100MS 1
+#define LV0104CS_INTEG_200MS 2
+#define LV0104CS_INTEG_SHIFT 1
+
+#define LV0104CS_CALIBSCALE_UNITY 31
+
+struct lv0104cs_private {
+ struct i2c_client *client;
+ struct mutex lock;
+ u8 calibscale;
+ u8 scale;
+ u8 int_time;
+};
+
+struct lv0104cs_mapping {
+ int val;
+ int val2;
+ u8 regval;
+};
+
+static const struct lv0104cs_mapping lv0104cs_calibscales[] = {
+ { 0, 666666, 0x81 },
+ { 0, 800000, 0x82 },
+ { 0, 857142, 0x83 },
+ { 0, 888888, 0x84 },
+ { 0, 909090, 0x85 },
+ { 0, 923076, 0x86 },
+ { 0, 933333, 0x87 },
+ { 0, 941176, 0x88 },
+ { 0, 947368, 0x89 },
+ { 0, 952380, 0x8A },
+ { 0, 956521, 0x8B },
+ { 0, 960000, 0x8C },
+ { 0, 962962, 0x8D },
+ { 0, 965517, 0x8E },
+ { 0, 967741, 0x8F },
+ { 0, 969696, 0x90 },
+ { 0, 971428, 0x91 },
+ { 0, 972972, 0x92 },
+ { 0, 974358, 0x93 },
+ { 0, 975609, 0x94 },
+ { 0, 976744, 0x95 },
+ { 0, 977777, 0x96 },
+ { 0, 978723, 0x97 },
+ { 0, 979591, 0x98 },
+ { 0, 980392, 0x99 },
+ { 0, 981132, 0x9A },
+ { 0, 981818, 0x9B },
+ { 0, 982456, 0x9C },
+ { 0, 983050, 0x9D },
+ { 0, 983606, 0x9E },
+ { 0, 984126, 0x9F },
+ { 1, 0, 0x80 },
+ { 1, 16129, 0xBF },
+ { 1, 16666, 0xBE },
+ { 1, 17241, 0xBD },
+ { 1, 17857, 0xBC },
+ { 1, 18518, 0xBB },
+ { 1, 19230, 0xBA },
+ { 1, 20000, 0xB9 },
+ { 1, 20833, 0xB8 },
+ { 1, 21739, 0xB7 },
+ { 1, 22727, 0xB6 },
+ { 1, 23809, 0xB5 },
+ { 1, 24999, 0xB4 },
+ { 1, 26315, 0xB3 },
+ { 1, 27777, 0xB2 },
+ { 1, 29411, 0xB1 },
+ { 1, 31250, 0xB0 },
+ { 1, 33333, 0xAF },
+ { 1, 35714, 0xAE },
+ { 1, 38461, 0xAD },
+ { 1, 41666, 0xAC },
+ { 1, 45454, 0xAB },
+ { 1, 50000, 0xAA },
+ { 1, 55555, 0xA9 },
+ { 1, 62500, 0xA8 },
+ { 1, 71428, 0xA7 },
+ { 1, 83333, 0xA6 },
+ { 1, 100000, 0xA5 },
+ { 1, 125000, 0xA4 },
+ { 1, 166666, 0xA3 },
+ { 1, 250000, 0xA2 },
+ { 1, 500000, 0xA1 },
+};
+
+static const struct lv0104cs_mapping lv0104cs_scales[] = {
+ { 0, 250000, LV0104CS_SCALE_0_25X << LV0104CS_SCALE_SHIFT },
+ { 1, 0, LV0104CS_SCALE_1X << LV0104CS_SCALE_SHIFT },
+ { 2, 0, LV0104CS_SCALE_2X << LV0104CS_SCALE_SHIFT },
+ { 8, 0, LV0104CS_SCALE_8X << LV0104CS_SCALE_SHIFT },
+};
+
+static const struct lv0104cs_mapping lv0104cs_int_times[] = {
+ { 0, 12500, LV0104CS_INTEG_12_5MS << LV0104CS_INTEG_SHIFT },
+ { 0, 100000, LV0104CS_INTEG_100MS << LV0104CS_INTEG_SHIFT },
+ { 0, 200000, LV0104CS_INTEG_200MS << LV0104CS_INTEG_SHIFT },
+};
+
+static int lv0104cs_write_reg(struct i2c_client *client, u8 regval)
+{
+ int ret;
+
+ ret = i2c_master_send(client, (char *)&regval, sizeof(regval));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(regval))
+ return -EIO;
+
+ return 0;
+}
+
+static int lv0104cs_read_adc(struct i2c_client *client, u16 *adc_output)
+{
+ __be16 regval;
+ int ret;
+
+ ret = i2c_master_recv(client, (char *)&regval, sizeof(regval));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(regval))
+ return -EIO;
+
+ *adc_output = be16_to_cpu(regval);
+
+ return 0;
+}
+
+static int lv0104cs_get_lux(struct lv0104cs_private *lv0104cs,
+ int *val, int *val2)
+{
+ u8 regval = LV0104CS_REGVAL_MEASURE;
+ u16 adc_output;
+ int ret;
+
+ regval |= lv0104cs_scales[lv0104cs->scale].regval;
+ regval |= lv0104cs_int_times[lv0104cs->int_time].regval;
+ ret = lv0104cs_write_reg(lv0104cs->client, regval);
+ if (ret)
+ return ret;
+
+ /* wait for integration time to pass (with margin) */
+ switch (lv0104cs->int_time) {
+ case LV0104CS_INTEG_12_5MS:
+ msleep(50);
+ break;
+
+ case LV0104CS_INTEG_100MS:
+ msleep(150);
+ break;
+
+ case LV0104CS_INTEG_200MS:
+ msleep(250);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ret = lv0104cs_read_adc(lv0104cs->client, &adc_output);
+ if (ret)
+ return ret;
+
+ ret = lv0104cs_write_reg(lv0104cs->client, LV0104CS_REGVAL_SLEEP);
+ if (ret)
+ return ret;
+
+ /* convert ADC output to lux */
+ switch (lv0104cs->scale) {
+ case LV0104CS_SCALE_0_25X:
+ *val = adc_output * 4;
+ *val2 = 0;
+ return 0;
+
+ case LV0104CS_SCALE_1X:
+ *val = adc_output;
+ *val2 = 0;
+ return 0;
+
+ case LV0104CS_SCALE_2X:
+ *val = adc_output / 2;
+ *val2 = (adc_output % 2) * 500000;
+ return 0;
+
+ case LV0104CS_SCALE_8X:
+ *val = adc_output / 8;
+ *val2 = (adc_output % 8) * 125000;
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int lv0104cs_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct lv0104cs_private *lv0104cs = iio_priv(indio_dev);
+ int ret;
+
+ if (chan->type != IIO_LIGHT)
+ return -EINVAL;
+
+ mutex_lock(&lv0104cs->lock);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ ret = lv0104cs_get_lux(lv0104cs, val, val2);
+ if (ret)
+ goto err_mutex;
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+
+ case IIO_CHAN_INFO_CALIBSCALE:
+ *val = lv0104cs_calibscales[lv0104cs->calibscale].val;
+ *val2 = lv0104cs_calibscales[lv0104cs->calibscale].val2;
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+
+ case IIO_CHAN_INFO_SCALE:
+ *val = lv0104cs_scales[lv0104cs->scale].val;
+ *val2 = lv0104cs_scales[lv0104cs->scale].val2;
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+
+ case IIO_CHAN_INFO_INT_TIME:
+ *val = lv0104cs_int_times[lv0104cs->int_time].val;
+ *val2 = lv0104cs_int_times[lv0104cs->int_time].val2;
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+err_mutex:
+ mutex_unlock(&lv0104cs->lock);
+
+ return ret;
+}
+
+static int lv0104cs_set_calibscale(struct lv0104cs_private *lv0104cs,
+ int val, int val2)
+{
+ int calibscale = val * 1000000 + val2;
+ int floor, ceil, mid;
+ int ret, i, index;
+
+ /* round to nearest quantized calibscale (sensitivity) */
+ for (i = 0; i < ARRAY_SIZE(lv0104cs_calibscales) - 1; i++) {
+ floor = lv0104cs_calibscales[i].val * 1000000
+ + lv0104cs_calibscales[i].val2;
+ ceil = lv0104cs_calibscales[i + 1].val * 1000000
+ + lv0104cs_calibscales[i + 1].val2;
+ mid = (floor + ceil) / 2;
+
+ /* round down */
+ if (calibscale >= floor && calibscale < mid) {
+ index = i;
+ break;
+ }
+
+ /* round up */
+ if (calibscale >= mid && calibscale <= ceil) {
+ index = i + 1;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(lv0104cs_calibscales) - 1)
+ return -EINVAL;
+
+ mutex_lock(&lv0104cs->lock);
+
+ /* set calibscale (sensitivity) */
+ ret = lv0104cs_write_reg(lv0104cs->client,
+ lv0104cs_calibscales[index].regval);
+ if (ret)
+ goto err_mutex;
+
+ lv0104cs->calibscale = index;
+
+err_mutex:
+ mutex_unlock(&lv0104cs->lock);
+
+ return ret;
+}
+
+static int lv0104cs_set_scale(struct lv0104cs_private *lv0104cs,
+ int val, int val2)
+{
+ int i;
+
+ /* hard matching */
+ for (i = 0; i < ARRAY_SIZE(lv0104cs_scales); i++) {
+ if (val != lv0104cs_scales[i].val)
+ continue;
+
+ if (val2 == lv0104cs_scales[i].val2)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(lv0104cs_scales))
+ return -EINVAL;
+
+ mutex_lock(&lv0104cs->lock);
+ lv0104cs->scale = i;
+ mutex_unlock(&lv0104cs->lock);
+
+ return 0;
+}
+
+static int lv0104cs_set_int_time(struct lv0104cs_private *lv0104cs,
+ int val, int val2)
+{
+ int i;
+
+ /* hard matching */
+ for (i = 0; i < ARRAY_SIZE(lv0104cs_int_times); i++) {
+ if (val != lv0104cs_int_times[i].val)
+ continue;
+
+ if (val2 == lv0104cs_int_times[i].val2)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(lv0104cs_int_times))
+ return -EINVAL;
+
+ mutex_lock(&lv0104cs->lock);
+ lv0104cs->int_time = i;
+ mutex_unlock(&lv0104cs->lock);
+
+ return 0;
+}
+
+static int lv0104cs_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct lv0104cs_private *lv0104cs = iio_priv(indio_dev);
+
+ if (chan->type != IIO_LIGHT)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_CALIBSCALE:
+ return lv0104cs_set_calibscale(lv0104cs, val, val2);
+
+ case IIO_CHAN_INFO_SCALE:
+ return lv0104cs_set_scale(lv0104cs, val, val2);
+
+ case IIO_CHAN_INFO_INT_TIME:
+ return lv0104cs_set_int_time(lv0104cs, val, val2);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static ssize_t lv0104cs_show_calibscale_avail(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t len = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lv0104cs_calibscales); i++) {
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
+ lv0104cs_calibscales[i].val,
+ lv0104cs_calibscales[i].val2);
+ }
+
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static ssize_t lv0104cs_show_scale_avail(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t len = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lv0104cs_scales); i++) {
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
+ lv0104cs_scales[i].val,
+ lv0104cs_scales[i].val2);
+ }
+
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static ssize_t lv0104cs_show_int_time_avail(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t len = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lv0104cs_int_times); i++) {
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
+ lv0104cs_int_times[i].val,
+ lv0104cs_int_times[i].val2);
+ }
+
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(calibscale_available, 0444,
+ lv0104cs_show_calibscale_avail, NULL, 0);
+static IIO_DEVICE_ATTR(scale_available, 0444,
+ lv0104cs_show_scale_avail, NULL, 0);
+static IIO_DEV_ATTR_INT_TIME_AVAIL(lv0104cs_show_int_time_avail);
+
+static struct attribute *lv0104cs_attributes[] = {
+ &iio_dev_attr_calibscale_available.dev_attr.attr,
+ &iio_dev_attr_scale_available.dev_attr.attr,
+ &iio_dev_attr_integration_time_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group lv0104cs_attribute_group = {
+ .attrs = lv0104cs_attributes,
+};
+
+static const struct iio_info lv0104cs_info = {
+ .attrs = &lv0104cs_attribute_group,
+ .read_raw = &lv0104cs_read_raw,
+ .write_raw = &lv0104cs_write_raw,
+};
+
+static const struct iio_chan_spec lv0104cs_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_INT_TIME),
+ },
+};
+
+static int lv0104cs_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct lv0104cs_private *lv0104cs;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*lv0104cs));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ lv0104cs = iio_priv(indio_dev);
+
+ i2c_set_clientdata(client, lv0104cs);
+ lv0104cs->client = client;
+
+ mutex_init(&lv0104cs->lock);
+
+ lv0104cs->calibscale = LV0104CS_CALIBSCALE_UNITY;
+ lv0104cs->scale = LV0104CS_SCALE_1X;
+ lv0104cs->int_time = LV0104CS_INTEG_200MS;
+
+ ret = lv0104cs_write_reg(lv0104cs->client,
+ lv0104cs_calibscales[LV0104CS_CALIBSCALE_UNITY].regval);
+ if (ret)
+ return ret;
+
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->channels = lv0104cs_channels;
+ indio_dev->num_channels = ARRAY_SIZE(lv0104cs_channels);
+ indio_dev->name = client->name;
+ indio_dev->info = &lv0104cs_info;
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id lv0104cs_id[] = {
+ { "lv0104cs", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lv0104cs_id);
+
+static struct i2c_driver lv0104cs_i2c_driver = {
+ .driver = {
+ .name = "lv0104cs",
+ },
+ .id_table = lv0104cs_id,
+ .probe = lv0104cs_probe,
+};
+module_i2c_driver(lv0104cs_i2c_driver);
+
+MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
+MODULE_DESCRIPTION("LV0104CS Ambient Light Sensor Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index a1fd9d591818..d55c4885211a 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -167,7 +167,7 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
*val = 0;
*val2 = 0;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
hid_sensor_power_state(&magn_state->magn_flux_attributes, true);
report_id =
magn_state->magn[chan->address].report_id;
diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig
index 8bf282510be6..79ec2eba4969 100644
--- a/drivers/iio/potentiometer/Kconfig
+++ b/drivers/iio/potentiometer/Kconfig
@@ -5,6 +5,16 @@
menu "Digital potentiometers"
+config AD5272
+ tristate "Analog Devices AD5272 and similar Digital Potentiometer driver"
+ depends on I2C
+ help
+ Say yes here to build support for the Analog Devices AD5272 and AD5274
+ digital potentiometer chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad5272.
+
config DS1803
tristate "Maxim Integrated DS1803 Digital Potentiometer driver"
depends on I2C
@@ -37,6 +47,17 @@ config MAX5487
To compile this driver as a module, choose M here: the
module will be called max5487.
+config MCP4018
+ tristate "Microchip MCP4017/18/19 Digital Potentiometer driver"
+ depends on I2C
+ help
+ Say yes here to build support for the Microchip
+ MCP4017, MCP4018, MCP4019
+ digital potentiometer chips.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mcp4018.
+
config MCP4131
tristate "Microchip MCP413X/414X/415X/416X/423X/424X/425X/426X Digital Potentiometer driver"
depends on SPI
diff --git a/drivers/iio/potentiometer/Makefile b/drivers/iio/potentiometer/Makefile
index 1afd1e70f8cc..4af657883c3f 100644
--- a/drivers/iio/potentiometer/Makefile
+++ b/drivers/iio/potentiometer/Makefile
@@ -4,9 +4,11 @@
#
# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_AD5272) += ad5272.o
obj-$(CONFIG_DS1803) += ds1803.o
obj-$(CONFIG_MAX5481) += max5481.o
obj-$(CONFIG_MAX5487) += max5487.o
+obj-$(CONFIG_MCP4018) += mcp4018.o
obj-$(CONFIG_MCP4131) += mcp4131.o
obj-$(CONFIG_MCP4531) += mcp4531.o
obj-$(CONFIG_TPL0102) += tpl0102.o
diff --git a/drivers/iio/potentiometer/ad5272.c b/drivers/iio/potentiometer/ad5272.c
new file mode 100644
index 000000000000..154f9a5da8bc
--- /dev/null
+++ b/drivers/iio/potentiometer/ad5272.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Analog Devices AD5272 digital potentiometer driver
+ * Copyright (C) 2018 Phil Reid <preid@electromag.com.au>
+ *
+ * Datasheet: http://www.analog.com/media/en/technical-documentation/data-sheets/AD5272_5274.pdf
+ *
+ * DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address
+ * ad5272 1 1024 20, 50, 100 01011xx
+ * ad5274 1 256 20, 100 01011xx
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+
+#define AD5272_RDAC_WR 1
+#define AD5272_RDAC_RD 2
+#define AD5272_RESET 4
+#define AD5272_CTL 7
+
+#define AD5272_RDAC_WR_EN BIT(1)
+
+struct ad5272_cfg {
+ int max_pos;
+ int kohms;
+ int shift;
+};
+
+enum ad5272_type {
+ AD5272_020,
+ AD5272_050,
+ AD5272_100,
+ AD5274_020,
+ AD5274_100,
+};
+
+static const struct ad5272_cfg ad5272_cfg[] = {
+ [AD5272_020] = { .max_pos = 1024, .kohms = 20 },
+ [AD5272_050] = { .max_pos = 1024, .kohms = 50 },
+ [AD5272_100] = { .max_pos = 1024, .kohms = 100 },
+ [AD5274_020] = { .max_pos = 256, .kohms = 20, .shift = 2 },
+ [AD5274_100] = { .max_pos = 256, .kohms = 100, .shift = 2 },
+};
+
+struct ad5272_data {
+ struct i2c_client *client;
+ struct mutex lock;
+ const struct ad5272_cfg *cfg;
+ u8 buf[2] ____cacheline_aligned;
+};
+
+static const struct iio_chan_spec ad5272_channel = {
+ .type = IIO_RESISTANCE,
+ .output = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+};
+
+static int ad5272_write(struct ad5272_data *data, int reg, int val)
+{
+ int ret;
+
+ data->buf[0] = (reg << 2) | ((val >> 8) & 0x3);
+ data->buf[1] = (u8)val;
+
+ mutex_lock(&data->lock);
+ ret = i2c_master_send(data->client, data->buf, sizeof(data->buf));
+ mutex_unlock(&data->lock);
+ return ret < 0 ? ret : 0;
+}
+
+static int ad5272_read(struct ad5272_data *data, int reg, int *val)
+{
+ int ret;
+
+ data->buf[0] = reg << 2;
+ data->buf[1] = 0;
+
+ mutex_lock(&data->lock);
+ ret = i2c_master_send(data->client, data->buf, sizeof(data->buf));
+ if (ret < 0)
+ goto error;
+
+ ret = i2c_master_recv(data->client, data->buf, sizeof(data->buf));
+ if (ret < 0)
+ goto error;
+
+ *val = ((data->buf[0] & 0x3) << 8) | data->buf[1];
+ ret = 0;
+error:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int ad5272_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct ad5272_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW: {
+ ret = ad5272_read(data, AD5272_RDAC_RD, val);
+ *val = *val >> data->cfg->shift;
+ return ret ? ret : IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ *val = 1000 * data->cfg->kohms;
+ *val2 = data->cfg->max_pos;
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ return -EINVAL;
+}
+
+static int ad5272_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ad5272_data *data = iio_priv(indio_dev);
+
+ if (mask != IIO_CHAN_INFO_RAW)
+ return -EINVAL;
+
+ if (val >= data->cfg->max_pos || val < 0 || val2)
+ return -EINVAL;
+
+ return ad5272_write(data, AD5272_RDAC_WR, val << data->cfg->shift);
+}
+
+static const struct iio_info ad5272_info = {
+ .read_raw = ad5272_read_raw,
+ .write_raw = ad5272_write_raw,
+};
+
+static int ad5272_reset(struct ad5272_data *data)
+{
+ struct gpio_desc *reset_gpio;
+
+ reset_gpio = devm_gpiod_get_optional(&data->client->dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(reset_gpio))
+ return PTR_ERR(reset_gpio);
+
+ if (reset_gpio) {
+ udelay(1);
+ gpiod_set_value(reset_gpio, 1);
+ } else {
+ ad5272_write(data, AD5272_RESET, 0);
+ }
+ usleep_range(1000, 2000);
+
+ return 0;
+}
+
+static int ad5272_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct iio_dev *indio_dev;
+ struct ad5272_data *data;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, indio_dev);
+
+ data = iio_priv(indio_dev);
+ data->client = client;
+ mutex_init(&data->lock);
+ data->cfg = &ad5272_cfg[id->driver_data];
+
+ ret = ad5272_reset(data);
+ if (ret)
+ return ret;
+
+ ret = ad5272_write(data, AD5272_CTL, AD5272_RDAC_WR_EN);
+ if (ret < 0)
+ return -ENODEV;
+
+ indio_dev->dev.parent = dev;
+ indio_dev->info = &ad5272_info;
+ indio_dev->channels = &ad5272_channel;
+ indio_dev->num_channels = 1;
+ indio_dev->name = client->name;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id ad5272_dt_ids[] = {
+ { .compatible = "adi,ad5272-020", .data = (void *)AD5272_020 },
+ { .compatible = "adi,ad5272-050", .data = (void *)AD5272_050 },
+ { .compatible = "adi,ad5272-100", .data = (void *)AD5272_100 },
+ { .compatible = "adi,ad5274-020", .data = (void *)AD5274_020 },
+ { .compatible = "adi,ad5274-100", .data = (void *)AD5274_100 },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ad5272_dt_ids);
+#endif /* CONFIG_OF */
+
+static const struct i2c_device_id ad5272_id[] = {
+ { "ad5272-020", AD5272_020 },
+ { "ad5272-050", AD5272_050 },
+ { "ad5272-100", AD5272_100 },
+ { "ad5274-020", AD5274_020 },
+ { "ad5274-100", AD5274_100 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ad5272_id);
+
+static struct i2c_driver ad5272_driver = {
+ .driver = {
+ .name = "ad5272",
+ .of_match_table = of_match_ptr(ad5272_dt_ids),
+ },
+ .probe = ad5272_probe,
+ .id_table = ad5272_id,
+};
+
+module_i2c_driver(ad5272_driver);
+
+MODULE_AUTHOR("Phil Reid <preid@eletromag.com.au>");
+MODULE_DESCRIPTION("AD5272 digital potentiometer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c
index 9b0ff4ab2f9c..6bf12c9eccbd 100644
--- a/drivers/iio/potentiometer/ds1803.c
+++ b/drivers/iio/potentiometer/ds1803.c
@@ -64,7 +64,7 @@ static int ds1803_read_raw(struct iio_dev *indio_dev,
struct ds1803_data *data = iio_priv(indio_dev);
int pot = chan->channel;
int ret;
- u8 result[indio_dev->num_channels];
+ u8 result[ARRAY_SIZE(ds1803_channels)];
switch (mask) {
case IIO_CHAN_INFO_RAW:
diff --git a/drivers/iio/potentiometer/mcp4018.c b/drivers/iio/potentiometer/mcp4018.c
new file mode 100644
index 000000000000..601b25d1f387
--- /dev/null
+++ b/drivers/iio/potentiometer/mcp4018.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Industrial I/O driver for Microchip digital potentiometers
+ * Copyright (c) 2018 Axentia Technologies AB
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22147a.pdf
+ *
+ * DEVID #Wipers #Positions Resistor Opts (kOhm)
+ * mcp4017 1 128 5, 10, 50, 100
+ * mcp4018 1 128 5, 10, 50, 100
+ * mcp4019 1 128 5, 10, 50, 100
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#define MCP4018_WIPER_MAX 127
+
+struct mcp4018_cfg {
+ int kohms;
+};
+
+enum mcp4018_type {
+ MCP4018_502,
+ MCP4018_103,
+ MCP4018_503,
+ MCP4018_104,
+};
+
+static const struct mcp4018_cfg mcp4018_cfg[] = {
+ [MCP4018_502] = { .kohms = 5, },
+ [MCP4018_103] = { .kohms = 10, },
+ [MCP4018_503] = { .kohms = 50, },
+ [MCP4018_104] = { .kohms = 100, },
+};
+
+struct mcp4018_data {
+ struct i2c_client *client;
+ const struct mcp4018_cfg *cfg;
+};
+
+static const struct iio_chan_spec mcp4018_channel = {
+ .type = IIO_RESISTANCE,
+ .indexed = 1,
+ .output = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+};
+
+static int mcp4018_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct mcp4018_data *data = iio_priv(indio_dev);
+ s32 ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = i2c_smbus_read_byte(data->client);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 1000 * data->cfg->kohms;
+ *val2 = MCP4018_WIPER_MAX;
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ return -EINVAL;
+}
+
+static int mcp4018_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct mcp4018_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (val > MCP4018_WIPER_MAX || val < 0)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return i2c_smbus_write_byte(data->client, val);
+}
+
+static const struct iio_info mcp4018_info = {
+ .read_raw = mcp4018_read_raw,
+ .write_raw = mcp4018_write_raw,
+};
+
+#ifdef CONFIG_OF
+
+#define MCP4018_COMPATIBLE(of_compatible, cfg) { \
+ .compatible = of_compatible, \
+ .data = &mcp4018_cfg[cfg], \
+}
+
+static const struct of_device_id mcp4018_of_match[] = {
+ MCP4018_COMPATIBLE("microchip,mcp4017-502", MCP4018_502),
+ MCP4018_COMPATIBLE("microchip,mcp4017-103", MCP4018_103),
+ MCP4018_COMPATIBLE("microchip,mcp4017-503", MCP4018_503),
+ MCP4018_COMPATIBLE("microchip,mcp4017-104", MCP4018_104),
+ MCP4018_COMPATIBLE("microchip,mcp4018-502", MCP4018_502),
+ MCP4018_COMPATIBLE("microchip,mcp4018-103", MCP4018_103),
+ MCP4018_COMPATIBLE("microchip,mcp4018-503", MCP4018_503),
+ MCP4018_COMPATIBLE("microchip,mcp4018-104", MCP4018_104),
+ MCP4018_COMPATIBLE("microchip,mcp4019-502", MCP4018_502),
+ MCP4018_COMPATIBLE("microchip,mcp4019-103", MCP4018_103),
+ MCP4018_COMPATIBLE("microchip,mcp4019-503", MCP4018_503),
+ MCP4018_COMPATIBLE("microchip,mcp4019-104", MCP4018_104),
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mcp4018_of_match);
+
+#endif
+
+static int mcp4018_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct mcp4018_data *data;
+ struct iio_dev *indio_dev;
+ const struct of_device_id *match;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE)) {
+ dev_err(dev, "SMBUS Byte transfers not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+
+ match = of_match_device(of_match_ptr(mcp4018_of_match), dev);
+ if (match)
+ data->cfg = of_device_get_match_data(dev);
+ else
+ data->cfg = &mcp4018_cfg[id->driver_data];
+
+ indio_dev->dev.parent = dev;
+ indio_dev->info = &mcp4018_info;
+ indio_dev->channels = &mcp4018_channel;
+ indio_dev->num_channels = 1;
+ indio_dev->name = client->name;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct i2c_device_id mcp4018_id[] = {
+ { "mcp4017-502", MCP4018_502 },
+ { "mcp4017-103", MCP4018_103 },
+ { "mcp4017-503", MCP4018_503 },
+ { "mcp4017-104", MCP4018_104 },
+ { "mcp4018-502", MCP4018_502 },
+ { "mcp4018-103", MCP4018_103 },
+ { "mcp4018-503", MCP4018_503 },
+ { "mcp4018-104", MCP4018_104 },
+ { "mcp4019-502", MCP4018_502 },
+ { "mcp4019-103", MCP4018_103 },
+ { "mcp4019-503", MCP4018_503 },
+ { "mcp4019-104", MCP4018_104 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, mcp4018_id);
+
+static struct i2c_driver mcp4018_driver = {
+ .driver = {
+ .name = "mcp4018",
+ .of_match_table = of_match_ptr(mcp4018_of_match),
+ },
+ .probe = mcp4018_probe,
+ .id_table = mcp4018_id,
+};
+
+module_i2c_driver(mcp4018_driver);
+
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
+MODULE_DESCRIPTION("MCP4018 digital potentiometer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/potentiometer/tpl0102.c b/drivers/iio/potentiometer/tpl0102.c
index 93f9d4a8c9aa..ca1cce58fe20 100644
--- a/drivers/iio/potentiometer/tpl0102.c
+++ b/drivers/iio/potentiometer/tpl0102.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* tpl0102.c - Support for Texas Instruments digital potentiometers
*
- * Copyright (C) 2016 Matt Ranostay <mranostay@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.
- *
- * 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) 2016, 2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
*
* TODO: enable/disable hi-z output control
*/
@@ -156,6 +148,6 @@ static struct i2c_driver tpl0102_driver = {
module_i2c_driver(tpl0102_driver);
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("TPL0102 digital potentiometer");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c
index 007710991f15..85714055cc74 100644
--- a/drivers/iio/potentiostat/lmp91000.c
+++ b/drivers/iio/potentiostat/lmp91000.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* lmp91000.c - Support for Texas Instruments digital potentiostats
*
- * Copyright (C) 2016 Matt Ranostay <mranostay@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.
- *
- * 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) 2016, 2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
*
* TODO: bias voltage + polarity control, and multiple chip support
*/
@@ -440,6 +432,6 @@ static struct i2c_driver lmp91000_driver = {
};
module_i2c_driver(lmp91000_driver);
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("LMP91000 digital potentiostat");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/pressure/ms5611.h b/drivers/iio/pressure/ms5611.h
index ccda63c5b3c3..ead9e9f85894 100644
--- a/drivers/iio/pressure/ms5611.h
+++ b/drivers/iio/pressure/ms5611.h
@@ -63,7 +63,7 @@ struct ms5611_state {
};
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
- const char* name, int type);
+ const char *name, int type);
int ms5611_remove(struct iio_dev *indio_dev);
#endif /* _MS5611_H */
diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c
index b6249af48014..f130388a16a0 100644
--- a/drivers/iio/proximity/as3935.c
+++ b/drivers/iio/proximity/as3935.c
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* as3935.c - Support for AS3935 Franklin lightning sensor
*
- * Copyright (C) 2014 Matt Ranostay <mranostay@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.
- *
- * 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) 2014, 2017-2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
*/
#include <linux/module.h>
@@ -502,6 +493,6 @@ static struct spi_driver as3935_driver = {
};
module_spi_driver(as3935_driver);
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("AS3935 lightning sensor");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
index 4d56f67b24c6..47af54f14756 100644
--- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
+++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* pulsedlight-lidar-lite-v2.c - Support for PulsedLight LIDAR sensor
*
- * Copyright (C) 2015 Matt Ranostay <mranostay@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.
- *
- * 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) 2015, 2017-2018
+ * Author: Matt Ranostay <matt.ranostay@konsulko.com>
*
* TODO: interrupt mode, and signal strength reporting
*/
@@ -377,6 +369,6 @@ static struct i2c_driver lidar_driver = {
};
module_i2c_driver(lidar_driver);
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("PulsedLight LIDAR sensor");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
index b8a2c2c8cac5..ff80409e0c44 100644
--- a/drivers/iio/proximity/sx9500.c
+++ b/drivers/iio/proximity/sx9500.c
@@ -32,9 +32,6 @@
#define SX9500_DRIVER_NAME "sx9500"
#define SX9500_IRQ_NAME "sx9500_event"
-#define SX9500_GPIO_INT "interrupt"
-#define SX9500_GPIO_RESET "reset"
-
/* Register definitions. */
#define SX9500_REG_IRQ_SRC 0x00
#define SX9500_REG_STAT 0x01
@@ -866,26 +863,44 @@ static int sx9500_init_device(struct iio_dev *indio_dev)
return sx9500_init_compensation(indio_dev);
}
+static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
+static const struct acpi_gpio_params interrupt_gpios = { 2, 0, false };
+
+static const struct acpi_gpio_mapping acpi_sx9500_gpios[] = {
+ { "reset-gpios", &reset_gpios, 1 },
+ /*
+ * Some platforms have a bug in ACPI GPIO description making IRQ
+ * GPIO to be output only. Ask the GPIO core to ignore this limit.
+ */
+ { "interrupt-gpios", &interrupt_gpios, 1, ACPI_GPIO_QUIRK_NO_IO_RESTRICTION },
+ { },
+};
+
static void sx9500_gpio_probe(struct i2c_client *client,
struct sx9500_data *data)
{
struct gpio_desc *gpiod_int;
struct device *dev;
+ int ret;
if (!client)
return;
dev = &client->dev;
+ ret = devm_acpi_dev_add_driver_gpios(dev, acpi_sx9500_gpios);
+ if (ret)
+ dev_dbg(dev, "Unable to add GPIO mapping table\n");
+
if (client->irq <= 0) {
- gpiod_int = devm_gpiod_get(dev, SX9500_GPIO_INT, GPIOD_IN);
+ gpiod_int = devm_gpiod_get(dev, "interrupt", GPIOD_IN);
if (IS_ERR(gpiod_int))
dev_err(dev, "gpio get irq failed\n");
else
client->irq = gpiod_to_irq(gpiod_int);
}
- data->gpiod_rst = devm_gpiod_get(dev, SX9500_GPIO_RESET, GPIOD_OUT_HIGH);
+ data->gpiod_rst = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(data->gpiod_rst)) {
dev_warn(dev, "gpio get reset pin failed\n");
data->gpiod_rst = NULL;
diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
index 5378976d6d27..82e4a62745e2 100644
--- a/drivers/iio/temperature/Kconfig
+++ b/drivers/iio/temperature/Kconfig
@@ -43,6 +43,18 @@ config MLX90614
This driver can also be built as a module. If so, the module will
be called mlx90614.
+config MLX90632
+ tristate "MLX90632 contact-less infrared sensor with medical accuracy"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for the Melexis
+ MLX90632 contact-less infrared sensor with medical accuracy
+ connected with I2C.
+
+ This driver can also be built as a module. If so, the module will
+ be called mlx90632.
+
config TMP006
tristate "TMP006 infrared thermopile sensor"
depends on I2C
diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
index 34bd9023727b..34a31db0bb63 100644
--- a/drivers/iio/temperature/Makefile
+++ b/drivers/iio/temperature/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o
obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o
obj-$(CONFIG_MLX90614) += mlx90614.o
+obj-$(CONFIG_MLX90632) += mlx90632.o
obj-$(CONFIG_TMP006) += tmp006.o
obj-$(CONFIG_TMP007) += tmp007.o
obj-$(CONFIG_TSYS01) += tsys01.o
diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c
index e8b7e0b6c8ad..54e383231d1e 100644
--- a/drivers/iio/temperature/maxim_thermocouple.c
+++ b/drivers/iio/temperature/maxim_thermocouple.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* maxim_thermocouple.c - Support for Maxim thermocouple chips
*
- * Copyright (C) 2016 Matt Ranostay <mranostay@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.
- *
- * 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) 2016-2018 Matt Ranostay
+ * Author: <matt.ranostay@konsulko.com>
*/
#include <linux/module.h>
@@ -281,6 +273,6 @@ static struct spi_driver maxim_thermocouple_driver = {
};
module_spi_driver(maxim_thermocouple_driver);
-MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("Maxim thermocouple sensors");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c
new file mode 100644
index 000000000000..9851311aa3fd
--- /dev/null
+++ b/drivers/iio/temperature/mlx90632.c
@@ -0,0 +1,752 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mlx90632.c - Melexis MLX90632 contactless IR temperature sensor
+ *
+ * Copyright (c) 2017 Melexis <cmo@melexis.com>
+ *
+ * Driver for the Melexis MLX90632 I2C 16-bit IR thermopile sensor
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/math64.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/* Memory sections addresses */
+#define MLX90632_ADDR_RAM 0x4000 /* Start address of ram */
+#define MLX90632_ADDR_EEPROM 0x2480 /* Start address of user eeprom */
+
+/* EEPROM addresses - used at startup */
+#define MLX90632_EE_CTRL 0x24d4 /* Control register initial value */
+#define MLX90632_EE_I2C_ADDR 0x24d5 /* I2C address register initial value */
+#define MLX90632_EE_VERSION 0x240b /* EEPROM version reg address */
+#define MLX90632_EE_P_R 0x240c /* P_R calibration register 32bit */
+#define MLX90632_EE_P_G 0x240e /* P_G calibration register 32bit */
+#define MLX90632_EE_P_T 0x2410 /* P_T calibration register 32bit */
+#define MLX90632_EE_P_O 0x2412 /* P_O calibration register 32bit */
+#define MLX90632_EE_Aa 0x2414 /* Aa calibration register 32bit */
+#define MLX90632_EE_Ab 0x2416 /* Ab calibration register 32bit */
+#define MLX90632_EE_Ba 0x2418 /* Ba calibration register 32bit */
+#define MLX90632_EE_Bb 0x241a /* Bb calibration register 32bit */
+#define MLX90632_EE_Ca 0x241c /* Ca calibration register 32bit */
+#define MLX90632_EE_Cb 0x241e /* Cb calibration register 32bit */
+#define MLX90632_EE_Da 0x2420 /* Da calibration register 32bit */
+#define MLX90632_EE_Db 0x2422 /* Db calibration register 32bit */
+#define MLX90632_EE_Ea 0x2424 /* Ea calibration register 32bit */
+#define MLX90632_EE_Eb 0x2426 /* Eb calibration register 32bit */
+#define MLX90632_EE_Fa 0x2428 /* Fa calibration register 32bit */
+#define MLX90632_EE_Fb 0x242a /* Fb calibration register 32bit */
+#define MLX90632_EE_Ga 0x242c /* Ga calibration register 32bit */
+
+#define MLX90632_EE_Gb 0x242e /* Gb calibration register 16bit */
+#define MLX90632_EE_Ka 0x242f /* Ka calibration register 16bit */
+
+#define MLX90632_EE_Ha 0x2481 /* Ha customer calib value reg 16bit */
+#define MLX90632_EE_Hb 0x2482 /* Hb customer calib value reg 16bit */
+
+/* Register addresses - volatile */
+#define MLX90632_REG_I2C_ADDR 0x3000 /* Chip I2C address register */
+
+/* Control register address - volatile */
+#define MLX90632_REG_CONTROL 0x3001 /* Control Register address */
+#define MLX90632_CFG_PWR_MASK GENMASK(2, 1) /* PowerMode Mask */
+/* PowerModes statuses */
+#define MLX90632_PWR_STATUS(ctrl_val) (ctrl_val << 1)
+#define MLX90632_PWR_STATUS_HALT MLX90632_PWR_STATUS(0) /* hold */
+#define MLX90632_PWR_STATUS_SLEEP_STEP MLX90632_PWR_STATUS(1) /* sleep step*/
+#define MLX90632_PWR_STATUS_STEP MLX90632_PWR_STATUS(2) /* step */
+#define MLX90632_PWR_STATUS_CONTINUOUS MLX90632_PWR_STATUS(3) /* continuous*/
+
+/* Device status register - volatile */
+#define MLX90632_REG_STATUS 0x3fff /* Device status register */
+#define MLX90632_STAT_BUSY BIT(10) /* Device busy indicator */
+#define MLX90632_STAT_EE_BUSY BIT(9) /* EEPROM busy indicator */
+#define MLX90632_STAT_BRST BIT(8) /* Brown out reset indicator */
+#define MLX90632_STAT_CYCLE_POS GENMASK(6, 2) /* Data position */
+#define MLX90632_STAT_DATA_RDY BIT(0) /* Data ready indicator */
+
+/* RAM_MEAS address-es for each channel */
+#define MLX90632_RAM_1(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num)
+#define MLX90632_RAM_2(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num + 1)
+#define MLX90632_RAM_3(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num + 2)
+
+/* Magic constants */
+#define MLX90632_ID_MEDICAL 0x0105 /* EEPROM DSPv5 Medical device id */
+#define MLX90632_ID_CONSUMER 0x0205 /* EEPROM DSPv5 Consumer device id */
+#define MLX90632_RESET_CMD 0x0006 /* Reset sensor (address or global) */
+#define MLX90632_REF_12 12LL /**< ResCtrlRef value of Ch 1 or Ch 2 */
+#define MLX90632_REF_3 12LL /**< ResCtrlRef value of Channel 3 */
+#define MLX90632_MAX_MEAS_NUM 31 /**< Maximum measurements in list */
+#define MLX90632_SLEEP_DELAY_MS 3000 /**< Autosleep delay */
+
+struct mlx90632_data {
+ struct i2c_client *client;
+ struct mutex lock; /* Multiple reads for single measurement */
+ struct regmap *regmap;
+ u16 emissivity;
+};
+
+static const struct regmap_range mlx90632_volatile_reg_range[] = {
+ regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL),
+ regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS),
+ regmap_reg_range(MLX90632_RAM_1(0),
+ MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
+};
+
+static const struct regmap_access_table mlx90632_volatile_regs_tbl = {
+ .yes_ranges = mlx90632_volatile_reg_range,
+ .n_yes_ranges = ARRAY_SIZE(mlx90632_volatile_reg_range),
+};
+
+static const struct regmap_range mlx90632_read_reg_range[] = {
+ regmap_reg_range(MLX90632_EE_VERSION, MLX90632_EE_Ka),
+ regmap_reg_range(MLX90632_EE_CTRL, MLX90632_EE_I2C_ADDR),
+ regmap_reg_range(MLX90632_EE_Ha, MLX90632_EE_Hb),
+ regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL),
+ regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS),
+ regmap_reg_range(MLX90632_RAM_1(0),
+ MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
+};
+
+static const struct regmap_access_table mlx90632_readable_regs_tbl = {
+ .yes_ranges = mlx90632_read_reg_range,
+ .n_yes_ranges = ARRAY_SIZE(mlx90632_read_reg_range),
+};
+
+static const struct regmap_range mlx90632_no_write_reg_range[] = {
+ regmap_reg_range(MLX90632_EE_VERSION, MLX90632_EE_Ka),
+ regmap_reg_range(MLX90632_RAM_1(0),
+ MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
+};
+
+static const struct regmap_access_table mlx90632_writeable_regs_tbl = {
+ .no_ranges = mlx90632_no_write_reg_range,
+ .n_no_ranges = ARRAY_SIZE(mlx90632_no_write_reg_range),
+};
+
+static const struct regmap_config mlx90632_regmap = {
+ .reg_bits = 16,
+ .val_bits = 16,
+
+ .volatile_table = &mlx90632_volatile_regs_tbl,
+ .rd_table = &mlx90632_readable_regs_tbl,
+ .wr_table = &mlx90632_writeable_regs_tbl,
+
+ .use_single_rw = true,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static s32 mlx90632_pwr_set_sleep_step(struct regmap *regmap)
+{
+ return regmap_update_bits(regmap, MLX90632_REG_CONTROL,
+ MLX90632_CFG_PWR_MASK,
+ MLX90632_PWR_STATUS_SLEEP_STEP);
+}
+
+static s32 mlx90632_pwr_continuous(struct regmap *regmap)
+{
+ return regmap_update_bits(regmap, MLX90632_REG_CONTROL,
+ MLX90632_CFG_PWR_MASK,
+ MLX90632_PWR_STATUS_CONTINUOUS);
+}
+
+/**
+ * mlx90632_perform_measurement - Trigger and retrieve current measurement cycle
+ * @*data: pointer to mlx90632_data object containing regmap information
+ *
+ * Perform a measurement and return latest measurement cycle position reported
+ * by sensor. This is a blocking function for 500ms, as that is default sensor
+ * refresh rate.
+ */
+static int mlx90632_perform_measurement(struct mlx90632_data *data)
+{
+ int ret, tries = 100;
+ unsigned int reg_status;
+
+ ret = regmap_update_bits(data->regmap, MLX90632_REG_STATUS,
+ MLX90632_STAT_DATA_RDY, 0);
+ if (ret < 0)
+ return ret;
+
+ while (tries-- > 0) {
+ ret = regmap_read(data->regmap, MLX90632_REG_STATUS,
+ &reg_status);
+ if (ret < 0)
+ return ret;
+ if (reg_status & MLX90632_STAT_DATA_RDY)
+ break;
+ usleep_range(10000, 11000);
+ }
+
+ if (tries < 0) {
+ dev_err(&data->client->dev, "data not ready");
+ return -ETIMEDOUT;
+ }
+
+ return (reg_status & MLX90632_STAT_CYCLE_POS) >> 2;
+}
+
+static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new,
+ uint8_t *channel_old)
+{
+ switch (perform_ret) {
+ case 1:
+ *channel_new = 1;
+ *channel_old = 2;
+ break;
+ case 2:
+ *channel_new = 2;
+ *channel_old = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mlx90632_read_ambient_raw(struct regmap *regmap,
+ s16 *ambient_new_raw, s16 *ambient_old_raw)
+{
+ int ret;
+ unsigned int read_tmp;
+
+ ret = regmap_read(regmap, MLX90632_RAM_3(1), &read_tmp);
+ if (ret < 0)
+ return ret;
+ *ambient_new_raw = (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90632_RAM_3(2), &read_tmp);
+ if (ret < 0)
+ return ret;
+ *ambient_old_raw = (s16)read_tmp;
+
+ return ret;
+}
+
+static int mlx90632_read_object_raw(struct regmap *regmap,
+ int perform_measurement_ret,
+ s16 *object_new_raw, s16 *object_old_raw)
+{
+ int ret;
+ unsigned int read_tmp;
+ s16 read;
+ u8 channel = 0;
+ u8 channel_old = 0;
+
+ ret = mlx90632_channel_new_select(perform_measurement_ret, &channel,
+ &channel_old);
+ if (ret != 0)
+ return ret;
+
+ ret = regmap_read(regmap, MLX90632_RAM_2(channel), &read_tmp);
+ if (ret < 0)
+ return ret;
+
+ read = (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90632_RAM_1(channel), &read_tmp);
+ if (ret < 0)
+ return ret;
+ *object_new_raw = (read + (s16)read_tmp) / 2;
+
+ ret = regmap_read(regmap, MLX90632_RAM_2(channel_old), &read_tmp);
+ if (ret < 0)
+ return ret;
+ read = (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90632_RAM_1(channel_old), &read_tmp);
+ if (ret < 0)
+ return ret;
+ *object_old_raw = (read + (s16)read_tmp) / 2;
+
+ return ret;
+}
+
+static int mlx90632_read_all_channel(struct mlx90632_data *data,
+ s16 *ambient_new_raw, s16 *ambient_old_raw,
+ s16 *object_new_raw, s16 *object_old_raw)
+{
+ s32 ret, measurement;
+
+ mutex_lock(&data->lock);
+ measurement = mlx90632_perform_measurement(data);
+ if (measurement < 0) {
+ ret = measurement;
+ goto read_unlock;
+ }
+ ret = mlx90632_read_ambient_raw(data->regmap, ambient_new_raw,
+ ambient_old_raw);
+ if (ret < 0)
+ goto read_unlock;
+
+ ret = mlx90632_read_object_raw(data->regmap, measurement,
+ object_new_raw, object_old_raw);
+read_unlock:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int mlx90632_read_ee_register(struct regmap *regmap, u16 reg_lsb,
+ s32 *reg_value)
+{
+ s32 ret;
+ unsigned int read;
+ u32 value;
+
+ ret = regmap_read(regmap, reg_lsb, &read);
+ if (ret < 0)
+ return ret;
+
+ value = read;
+
+ ret = regmap_read(regmap, reg_lsb + 1, &read);
+ if (ret < 0)
+ return ret;
+
+ *reg_value = (read << 16) | (value & 0xffff);
+
+ return 0;
+}
+
+static s64 mlx90632_preprocess_temp_amb(s16 ambient_new_raw,
+ s16 ambient_old_raw, s16 Gb)
+{
+ s64 VR_Ta, kGb, tmp;
+
+ kGb = ((s64)Gb * 1000LL) >> 10ULL;
+ VR_Ta = (s64)ambient_old_raw * 1000000LL +
+ kGb * div64_s64(((s64)ambient_new_raw * 1000LL),
+ (MLX90632_REF_3));
+ tmp = div64_s64(
+ div64_s64(((s64)ambient_new_raw * 1000000000000LL),
+ (MLX90632_REF_3)), VR_Ta);
+ return div64_s64(tmp << 19ULL, 1000LL);
+}
+
+static s64 mlx90632_preprocess_temp_obj(s16 object_new_raw, s16 object_old_raw,
+ s16 ambient_new_raw,
+ s16 ambient_old_raw, s16 Ka)
+{
+ s64 VR_IR, kKa, tmp;
+
+ kKa = ((s64)Ka * 1000LL) >> 10ULL;
+ VR_IR = (s64)ambient_old_raw * 1000000LL +
+ kKa * div64_s64(((s64)ambient_new_raw * 1000LL),
+ (MLX90632_REF_3));
+ tmp = div64_s64(
+ div64_s64(((s64)((object_new_raw + object_old_raw) / 2)
+ * 1000000000000LL), (MLX90632_REF_12)),
+ VR_IR);
+ return div64_s64((tmp << 19ULL), 1000LL);
+}
+
+static s32 mlx90632_calc_temp_ambient(s16 ambient_new_raw, s16 ambient_old_raw,
+ s32 P_T, s32 P_R, s32 P_G, s32 P_O,
+ s16 Gb)
+{
+ s64 Asub, Bsub, Ablock, Bblock, Cblock, AMB, sum;
+
+ AMB = mlx90632_preprocess_temp_amb(ambient_new_raw, ambient_old_raw,
+ Gb);
+ Asub = ((s64)P_T * 10000000000LL) >> 44ULL;
+ Bsub = AMB - (((s64)P_R * 1000LL) >> 8ULL);
+ Ablock = Asub * (Bsub * Bsub);
+ Bblock = (div64_s64(Bsub * 10000000LL, P_G)) << 20ULL;
+ Cblock = ((s64)P_O * 10000000000LL) >> 8ULL;
+
+ sum = div64_s64(Ablock, 1000000LL) + Bblock + Cblock;
+
+ return div64_s64(sum, 10000000LL);
+}
+
+static s32 mlx90632_calc_temp_object_iteration(s32 prev_object_temp, s64 object,
+ s64 TAdut, s32 Fa, s32 Fb,
+ s32 Ga, s16 Ha, s16 Hb,
+ u16 emissivity)
+{
+ s64 calcedKsTO, calcedKsTA, ir_Alpha, TAdut4, Alpha_corr;
+ s64 Ha_customer, Hb_customer;
+
+ Ha_customer = ((s64)Ha * 1000000LL) >> 14ULL;
+ Hb_customer = ((s64)Hb * 100) >> 10ULL;
+
+ calcedKsTO = ((s64)((s64)Ga * (prev_object_temp - 25 * 1000LL)
+ * 1000LL)) >> 36LL;
+ calcedKsTA = ((s64)(Fb * (TAdut - 25 * 1000000LL))) >> 36LL;
+ Alpha_corr = div64_s64((((s64)(Fa * 10000000000LL) >> 46LL)
+ * Ha_customer), 1000LL);
+ Alpha_corr *= ((s64)(1 * 1000000LL + calcedKsTO + calcedKsTA));
+ Alpha_corr = emissivity * div64_s64(Alpha_corr, 100000LL);
+ Alpha_corr = div64_s64(Alpha_corr, 1000LL);
+ ir_Alpha = div64_s64((s64)object * 10000000LL, Alpha_corr);
+ TAdut4 = (div64_s64(TAdut, 10000LL) + 27315) *
+ (div64_s64(TAdut, 10000LL) + 27315) *
+ (div64_s64(TAdut, 10000LL) + 27315) *
+ (div64_s64(TAdut, 10000LL) + 27315);
+
+ return (int_sqrt64(int_sqrt64(ir_Alpha * 1000000000000LL + TAdut4))
+ - 27315 - Hb_customer) * 10;
+}
+
+static s32 mlx90632_calc_temp_object(s64 object, s64 ambient, s32 Ea, s32 Eb,
+ s32 Fa, s32 Fb, s32 Ga, s16 Ha, s16 Hb,
+ u16 tmp_emi)
+{
+ s64 kTA, kTA0, TAdut;
+ s64 temp = 25000;
+ s8 i;
+
+ kTA = (Ea * 1000LL) >> 16LL;
+ kTA0 = (Eb * 1000LL) >> 8LL;
+ TAdut = div64_s64(((ambient - kTA0) * 1000000LL), kTA) + 25 * 1000000LL;
+
+ /* Iterations of calculation as described in datasheet */
+ for (i = 0; i < 5; ++i) {
+ temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut,
+ Fa, Fb, Ga, Ha, Hb,
+ tmp_emi);
+ }
+ return temp;
+}
+
+static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val)
+{
+ s32 ret;
+ s32 Ea, Eb, Fa, Fb, Ga;
+ unsigned int read_tmp;
+ s16 Ha, Hb, Gb, Ka;
+ s16 ambient_new_raw, ambient_old_raw, object_new_raw, object_old_raw;
+ s64 object, ambient;
+
+ ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Ea, &Ea);
+ if (ret < 0)
+ return ret;
+ ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Eb, &Eb);
+ if (ret < 0)
+ return ret;
+ ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Fa, &Fa);
+ if (ret < 0)
+ return ret;
+ ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Fb, &Fb);
+ if (ret < 0)
+ return ret;
+ ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Ga, &Ga);
+ if (ret < 0)
+ return ret;
+ ret = regmap_read(data->regmap, MLX90632_EE_Ha, &read_tmp);
+ if (ret < 0)
+ return ret;
+ Ha = (s16)read_tmp;
+ ret = regmap_read(data->regmap, MLX90632_EE_Hb, &read_tmp);
+ if (ret < 0)
+ return ret;
+ Hb = (s16)read_tmp;
+ ret = regmap_read(data->regmap, MLX90632_EE_Gb, &read_tmp);
+ if (ret < 0)
+ return ret;
+ Gb = (s16)read_tmp;
+ ret = regmap_read(data->regmap, MLX90632_EE_Ka, &read_tmp);
+ if (ret < 0)
+ return ret;
+ Ka = (s16)read_tmp;
+
+ ret = mlx90632_read_all_channel(data,
+ &ambient_new_raw, &ambient_old_raw,
+ &object_new_raw, &object_old_raw);
+ if (ret < 0)
+ return ret;
+
+ ambient = mlx90632_preprocess_temp_amb(ambient_new_raw,
+ ambient_old_raw, Gb);
+ object = mlx90632_preprocess_temp_obj(object_new_raw,
+ object_old_raw,
+ ambient_new_raw,
+ ambient_old_raw, Ka);
+
+ *val = mlx90632_calc_temp_object(object, ambient, Ea, Eb, Fa, Fb, Ga,
+ Ha, Hb, data->emissivity);
+ return 0;
+}
+
+static int mlx90632_calc_ambient_dsp105(struct mlx90632_data *data, int *val)
+{
+ s32 ret;
+ unsigned int read_tmp;
+ s32 PT, PR, PG, PO;
+ s16 Gb;
+ s16 ambient_new_raw, ambient_old_raw;
+
+ ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_R, &PR);
+ if (ret < 0)
+ return ret;
+ ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_G, &PG);
+ if (ret < 0)
+ return ret;
+ ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_T, &PT);
+ if (ret < 0)
+ return ret;
+ ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_O, &PO);
+ if (ret < 0)
+ return ret;
+ ret = regmap_read(data->regmap, MLX90632_EE_Gb, &read_tmp);
+ if (ret < 0)
+ return ret;
+ Gb = (s16)read_tmp;
+
+ ret = mlx90632_read_ambient_raw(data->regmap, &ambient_new_raw,
+ &ambient_old_raw);
+ if (ret < 0)
+ return ret;
+ *val = mlx90632_calc_temp_ambient(ambient_new_raw, ambient_old_raw,
+ PT, PR, PG, PO, Gb);
+ return ret;
+}
+
+static int mlx90632_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ struct mlx90632_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (channel->channel2) {
+ case IIO_MOD_TEMP_AMBIENT:
+ ret = mlx90632_calc_ambient_dsp105(data, val);
+ if (ret < 0)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_MOD_TEMP_OBJECT:
+ ret = mlx90632_calc_object_dsp105(data, val);
+ if (ret < 0)
+ return ret;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_CALIBEMISSIVITY:
+ if (data->emissivity == 1000) {
+ *val = 1;
+ *val2 = 0;
+ } else {
+ *val = 0;
+ *val2 = data->emissivity * 1000;
+ }
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mlx90632_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int val,
+ int val2, long mask)
+{
+ struct mlx90632_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_CALIBEMISSIVITY:
+ /* Confirm we are within 0 and 1.0 */
+ if (val < 0 || val2 < 0 || val > 1 ||
+ (val == 1 && val2 != 0))
+ return -EINVAL;
+ data->emissivity = val * 1000 + val2 / 1000;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec mlx90632_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .modified = 1,
+ .channel2 = IIO_MOD_TEMP_AMBIENT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ },
+ {
+ .type = IIO_TEMP,
+ .modified = 1,
+ .channel2 = IIO_MOD_TEMP_OBJECT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+ BIT(IIO_CHAN_INFO_CALIBEMISSIVITY),
+ },
+};
+
+static const struct iio_info mlx90632_info = {
+ .read_raw = mlx90632_read_raw,
+ .write_raw = mlx90632_write_raw,
+};
+
+static int mlx90632_sleep(struct mlx90632_data *data)
+{
+ regcache_mark_dirty(data->regmap);
+
+ dev_dbg(&data->client->dev, "Requesting sleep");
+ return mlx90632_pwr_set_sleep_step(data->regmap);
+}
+
+static int mlx90632_wakeup(struct mlx90632_data *data)
+{
+ int ret;
+
+ ret = regcache_sync(data->regmap);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "Failed to sync regmap registers: %d\n", ret);
+ return ret;
+ }
+
+ dev_dbg(&data->client->dev, "Requesting wake-up\n");
+ return mlx90632_pwr_continuous(data->regmap);
+}
+
+static int mlx90632_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct mlx90632_data *mlx90632;
+ struct regmap *regmap;
+ int ret;
+ unsigned int read;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*mlx90632));
+ if (!indio_dev) {
+ dev_err(&client->dev, "Failed to allocate device\n");
+ return -ENOMEM;
+ }
+
+ regmap = devm_regmap_init_i2c(client, &mlx90632_regmap);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+ dev_err(&client->dev, "Failed to allocate regmap: %d\n", ret);
+ return ret;
+ }
+
+ mlx90632 = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ mlx90632->client = client;
+ mlx90632->regmap = regmap;
+
+ mutex_init(&mlx90632->lock);
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = id->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &mlx90632_info;
+ indio_dev->channels = mlx90632_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mlx90632_channels);
+
+ ret = mlx90632_wakeup(mlx90632);
+ if (ret < 0) {
+ dev_err(&client->dev, "Wakeup failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_read(mlx90632->regmap, MLX90632_EE_VERSION, &read);
+ if (ret < 0) {
+ dev_err(&client->dev, "read of version failed: %d\n", ret);
+ return ret;
+ }
+ if (read == MLX90632_ID_MEDICAL) {
+ dev_dbg(&client->dev,
+ "Detected Medical EEPROM calibration %x\n", read);
+ } else if (read == MLX90632_ID_CONSUMER) {
+ dev_dbg(&client->dev,
+ "Detected Consumer EEPROM calibration %x\n", read);
+ } else {
+ dev_err(&client->dev,
+ "EEPROM version mismatch %x (expected %x or %x)\n",
+ read, MLX90632_ID_CONSUMER, MLX90632_ID_MEDICAL);
+ return -EPROTONOSUPPORT;
+ }
+
+ mlx90632->emissivity = 1000;
+
+ pm_runtime_disable(&client->dev);
+ ret = pm_runtime_set_active(&client->dev);
+ if (ret < 0) {
+ mlx90632_sleep(mlx90632);
+ return ret;
+ }
+ pm_runtime_enable(&client->dev);
+ pm_runtime_set_autosuspend_delay(&client->dev, MLX90632_SLEEP_DELAY_MS);
+ pm_runtime_use_autosuspend(&client->dev);
+
+ return iio_device_register(indio_dev);
+}
+
+static int mlx90632_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct mlx90632_data *data = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+ pm_runtime_put_noidle(&client->dev);
+
+ mlx90632_sleep(data);
+
+ return 0;
+}
+
+static const struct i2c_device_id mlx90632_id[] = {
+ { "mlx90632", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mlx90632_id);
+
+static const struct of_device_id mlx90632_of_match[] = {
+ { .compatible = "melexis,mlx90632" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mlx90632_of_match);
+
+static int __maybe_unused mlx90632_pm_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct mlx90632_data *data = iio_priv(indio_dev);
+
+ return mlx90632_sleep(data);
+}
+
+static int __maybe_unused mlx90632_pm_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct mlx90632_data *data = iio_priv(indio_dev);
+
+ return mlx90632_wakeup(data);
+}
+
+static UNIVERSAL_DEV_PM_OPS(mlx90632_pm_ops, mlx90632_pm_suspend,
+ mlx90632_pm_resume, NULL);
+
+static struct i2c_driver mlx90632_driver = {
+ .driver = {
+ .name = "mlx90632",
+ .of_match_table = mlx90632_of_match,
+ .pm = &mlx90632_pm_ops,
+ },
+ .probe = mlx90632_probe,
+ .remove = mlx90632_remove,
+ .id_table = mlx90632_id,
+};
+module_i2c_driver(mlx90632_driver);
+
+MODULE_AUTHOR("Crt Mori <cmo@melexis.com>");
+MODULE_DESCRIPTION("Melexis MLX90632 contactless Infra Red temperature sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index c81c79d01d93..46115a392098 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -31,7 +31,6 @@
enum evdev_clock_type {
EV_CLK_REAL = 0,
EV_CLK_MONO,
- EV_CLK_BOOT,
EV_CLK_MAX
};
@@ -198,12 +197,10 @@ static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
case CLOCK_REALTIME:
clk_type = EV_CLK_REAL;
break;
+ case CLOCK_BOOTTIME:
case CLOCK_MONOTONIC:
clk_type = EV_CLK_MONO;
break;
- case CLOCK_BOOTTIME:
- clk_type = EV_CLK_BOOT;
- break;
default:
return -EINVAL;
}
@@ -314,8 +311,6 @@ static void evdev_events(struct input_handle *handle,
ev_time[EV_CLK_MONO] = ktime_get();
ev_time[EV_CLK_REAL] = ktime_mono_to_real(ev_time[EV_CLK_MONO]);
- ev_time[EV_CLK_BOOT] = ktime_mono_to_any(ev_time[EV_CLK_MONO],
- TK_OFFS_BOOT);
rcu_read_lock();
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index aa9f29b875de..49d8d53e50b7 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -91,7 +91,7 @@ struct gscps2port {
struct parisc_device *padev;
struct serio *port;
spinlock_t lock;
- char *addr;
+ char __iomem *addr;
u8 act, append; /* position in buffer[] */
struct {
u8 data;
@@ -114,7 +114,7 @@ struct gscps2port {
* wait_TBE() - wait for Transmit Buffer Empty
*/
-static int wait_TBE(char *addr)
+static int wait_TBE(char __iomem *addr)
{
int timeout = 25000; /* device is expected to react within 250 msec */
while (gscps2_readb_status(addr) & GSC_STAT_TBNE) {
@@ -146,14 +146,14 @@ static void gscps2_flush(struct gscps2port *ps2port)
static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data)
{
unsigned long flags;
- char *addr = ps2port->addr;
+ char __iomem *addr = ps2port->addr;
if (!wait_TBE(addr)) {
printk(KERN_DEBUG PFX "timeout - could not write byte %#x\n", data);
return 0;
}
- while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE)
+ while (gscps2_readb_status(addr) & GSC_STAT_RBNE)
/* wait */;
spin_lock_irqsave(&ps2port->lock, flags);
@@ -200,13 +200,12 @@ static void gscps2_enable(struct gscps2port *ps2port, int enable)
static void gscps2_reset(struct gscps2port *ps2port)
{
- char *addr = ps2port->addr;
unsigned long flags;
/* reset the interface */
spin_lock_irqsave(&ps2port->lock, flags);
gscps2_flush(ps2port);
- writeb(0xff, addr+GSC_RESET);
+ writeb(0xff, ps2port->addr + GSC_RESET);
gscps2_flush(ps2port);
spin_unlock_irqrestore(&ps2port->lock, flags);
}
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index f16f8358c70a..894843a7ec7b 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -38,6 +38,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-dma-sg.h>
@@ -81,7 +82,10 @@ struct sur40_blob {
__le32 area; /* size in pixels/pressure (?) */
- u8 padding[32];
+ u8 padding[24];
+
+ __le32 tag_id; /* valid when type == 0x04 (SUR40_TAG) */
+ __le32 unknown;
} __packed;
@@ -146,6 +150,40 @@ struct sur40_image_header {
#define SUR40_TOUCH 0x02
#define SUR40_TAG 0x04
+/* video controls */
+#define SUR40_BRIGHTNESS_MAX 0xff
+#define SUR40_BRIGHTNESS_MIN 0x00
+#define SUR40_BRIGHTNESS_DEF 0xff
+
+#define SUR40_CONTRAST_MAX 0x0f
+#define SUR40_CONTRAST_MIN 0x00
+#define SUR40_CONTRAST_DEF 0x0a
+
+#define SUR40_GAIN_MAX 0x09
+#define SUR40_GAIN_MIN 0x00
+#define SUR40_GAIN_DEF 0x08
+
+#define SUR40_BACKLIGHT_MAX 0x01
+#define SUR40_BACKLIGHT_MIN 0x00
+#define SUR40_BACKLIGHT_DEF 0x01
+
+#define sur40_str(s) #s
+#define SUR40_PARAM_RANGE(lo, hi) " (range " sur40_str(lo) "-" sur40_str(hi) ")"
+
+/* module parameters */
+static uint brightness = SUR40_BRIGHTNESS_DEF;
+module_param(brightness, uint, 0644);
+MODULE_PARM_DESC(brightness, "set initial brightness"
+ SUR40_PARAM_RANGE(SUR40_BRIGHTNESS_MIN, SUR40_BRIGHTNESS_MAX));
+static uint contrast = SUR40_CONTRAST_DEF;
+module_param(contrast, uint, 0644);
+MODULE_PARM_DESC(contrast, "set initial contrast"
+ SUR40_PARAM_RANGE(SUR40_CONTRAST_MIN, SUR40_CONTRAST_MAX));
+static uint gain = SUR40_GAIN_DEF;
+module_param(gain, uint, 0644);
+MODULE_PARM_DESC(gain, "set initial gain"
+ SUR40_PARAM_RANGE(SUR40_GAIN_MIN, SUR40_GAIN_MAX));
+
static const struct v4l2_pix_format sur40_pix_format[] = {
{
.pixelformat = V4L2_TCH_FMT_TU08,
@@ -178,6 +216,7 @@ struct sur40_state {
struct video_device vdev;
struct mutex lock;
struct v4l2_pix_format pix_fmt;
+ struct v4l2_ctrl_handler hdl;
struct vb2_queue queue;
struct list_head buf_list;
@@ -187,6 +226,7 @@ struct sur40_state {
struct sur40_data *bulk_in_buffer;
size_t bulk_in_size;
u8 bulk_in_epaddr;
+ u8 vsvideo;
char phys[64];
};
@@ -200,6 +240,11 @@ struct sur40_buffer {
static const struct video_device sur40_video_device;
static const struct vb2_queue sur40_queue;
static void sur40_process_video(struct sur40_state *sur40);
+static int sur40_s_ctrl(struct v4l2_ctrl *ctrl);
+
+static const struct v4l2_ctrl_ops sur40_ctrl_ops = {
+ .s_ctrl = sur40_s_ctrl,
+};
/*
* Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT
@@ -220,6 +265,81 @@ static int sur40_command(struct sur40_state *dev,
0x00, index, buffer, size, 1000);
}
+/* poke a byte in the panel register space */
+static int sur40_poke(struct sur40_state *dev, u8 offset, u8 value)
+{
+ int result;
+ u8 index = 0x96; // 0xae for permanent write
+
+ result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+ SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0x32, index, NULL, 0, 1000);
+ if (result < 0)
+ goto error;
+ msleep(5);
+
+ result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+ SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0x72, offset, NULL, 0, 1000);
+ if (result < 0)
+ goto error;
+ msleep(5);
+
+ result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+ SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0xb2, value, NULL, 0, 1000);
+ if (result < 0)
+ goto error;
+ msleep(5);
+
+error:
+ return result;
+}
+
+static int sur40_set_preprocessor(struct sur40_state *dev, u8 value)
+{
+ u8 setting_07[2] = { 0x01, 0x00 };
+ u8 setting_17[2] = { 0x85, 0x80 };
+ int result;
+
+ if (value > 1)
+ return -ERANGE;
+
+ result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+ SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0x07, setting_07[value], NULL, 0, 1000);
+ if (result < 0)
+ goto error;
+ msleep(5);
+
+ result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0),
+ SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0x17, setting_17[value], NULL, 0, 1000);
+ if (result < 0)
+ goto error;
+ msleep(5);
+
+error:
+ return result;
+}
+
+static void sur40_set_vsvideo(struct sur40_state *handle, u8 value)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ sur40_poke(handle, 0x1c+i, value);
+ handle->vsvideo = value;
+}
+
+static void sur40_set_irlevel(struct sur40_state *handle, u8 value)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ sur40_poke(handle, 0x08+(2*i), value);
+}
+
/* Initialization routine, called from sur40_open */
static int sur40_init(struct sur40_state *dev)
{
@@ -631,6 +751,36 @@ static int sur40_probe(struct usb_interface *interface,
sur40->vdev.queue = &sur40->queue;
video_set_drvdata(&sur40->vdev, sur40);
+ /* initialize the control handler for 4 controls */
+ v4l2_ctrl_handler_init(&sur40->hdl, 4);
+ sur40->v4l2.ctrl_handler = &sur40->hdl;
+ sur40->vsvideo = (SUR40_CONTRAST_DEF << 4) | SUR40_GAIN_DEF;
+
+ v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_BRIGHTNESS,
+ SUR40_BRIGHTNESS_MIN, SUR40_BRIGHTNESS_MAX, 1, clamp(brightness,
+ (uint)SUR40_BRIGHTNESS_MIN, (uint)SUR40_BRIGHTNESS_MAX));
+
+ v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_CONTRAST,
+ SUR40_CONTRAST_MIN, SUR40_CONTRAST_MAX, 1, clamp(contrast,
+ (uint)SUR40_CONTRAST_MIN, (uint)SUR40_CONTRAST_MAX));
+
+ v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_GAIN,
+ SUR40_GAIN_MIN, SUR40_GAIN_MAX, 1, clamp(gain,
+ (uint)SUR40_GAIN_MIN, (uint)SUR40_GAIN_MAX));
+
+ v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops,
+ V4L2_CID_BACKLIGHT_COMPENSATION, SUR40_BACKLIGHT_MIN,
+ SUR40_BACKLIGHT_MAX, 1, SUR40_BACKLIGHT_DEF);
+
+ v4l2_ctrl_handler_setup(&sur40->hdl);
+
+ if (sur40->hdl.error) {
+ dev_err(&interface->dev,
+ "Unable to register video controls.");
+ v4l2_ctrl_handler_free(&sur40->hdl);
+ goto err_unreg_v4l2;
+ }
+
error = video_register_device(&sur40->vdev, VFL_TYPE_TOUCH, -1);
if (error) {
dev_err(&interface->dev,
@@ -663,6 +813,7 @@ static void sur40_disconnect(struct usb_interface *interface)
{
struct sur40_state *sur40 = usb_get_intfdata(interface);
+ v4l2_ctrl_handler_free(&sur40->hdl);
video_unregister_device(&sur40->vdev);
v4l2_device_unregister(&sur40->v4l2);
@@ -856,6 +1007,31 @@ static int sur40_vidioc_g_fmt(struct file *file, void *priv,
return 0;
}
+static int sur40_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct sur40_state *sur40 = container_of(ctrl->handler,
+ struct sur40_state, hdl);
+ u8 value = sur40->vsvideo;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ sur40_set_irlevel(sur40, ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ value = (value & 0x0f) | (ctrl->val << 4);
+ sur40_set_vsvideo(sur40, value);
+ break;
+ case V4L2_CID_GAIN:
+ value = (value & 0xf0) | (ctrl->val);
+ sur40_set_vsvideo(sur40, value);
+ break;
+ case V4L2_CID_BACKLIGHT_COMPENSATION:
+ sur40_set_preprocessor(sur40, ctrl->val);
+ break;
+ }
+ return 0;
+}
+
static int sur40_ioctl_parm(struct file *file, void *priv,
struct v4l2_streamparm *p)
{
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index d913aec85109..e9233db16e03 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -51,6 +51,12 @@ config ARM_GIC_V3_ITS_PCI
depends on PCI_MSI
default ARM_GIC_V3_ITS
+config ARM_GIC_V3_ITS_FSL_MC
+ bool
+ depends on ARM_GIC_V3_ITS
+ depends on FSL_MC_BUS
+ default ARM_GIC_V3_ITS
+
config ARM_NVIC
bool
select IRQ_DOMAIN
@@ -286,6 +292,11 @@ config IRQ_MXS
select IRQ_DOMAIN
select STMP_DEVICE
+config MSCC_OCELOT_IRQ
+ bool
+ select IRQ_DOMAIN
+ select GENERIC_IRQ_CHIP
+
config MVEBU_GICP
bool
@@ -351,4 +362,13 @@ config GOLDFISH_PIC
Say yes here to enable Goldfish interrupt controller driver used
for Goldfish based virtual platforms.
+config QCOM_PDC
+ bool "QCOM PDC"
+ depends on ARCH_QCOM
+ select IRQ_DOMAIN
+ select IRQ_DOMAIN_HIERARCHY
+ help
+ Power Domain Controller driver to manage and configure wakeup
+ IRQs for Qualcomm Technologies Inc (QTI) mobile chips.
+
endmenu
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 110de02bb215..5ed465ab1c76 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o
obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o
obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-platform-msi.o irq-gic-v4.o
obj-$(CONFIG_ARM_GIC_V3_ITS_PCI) += irq-gic-v3-its-pci-msi.o
+obj-$(CONFIG_ARM_GIC_V3_ITS_FSL_MC) += irq-gic-v3-its-fsl-mc-msi.o
obj-$(CONFIG_PARTITION_PERCPU) += irq-partition-percpu.o
obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
@@ -70,6 +71,7 @@ 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_MSCC_OCELOT_IRQ) += irq-mscc-ocelot.o
obj-$(CONFIG_MVEBU_GICP) += irq-mvebu-gicp.o
obj-$(CONFIG_MVEBU_ICU) += irq-mvebu-icu.o
obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o
@@ -84,3 +86,4 @@ obj-$(CONFIG_ARCH_SYNQUACER) += irq-sni-exiu.o
obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o
obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o
obj-$(CONFIG_NDS32) += irq-ativic32.o
+obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index 30017df5b54c..01e673c680cd 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -21,6 +21,8 @@
#include "irq-gic-common.h"
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
static const struct gic_kvm_info *gic_kvm_info;
const struct gic_kvm_info *gic_get_kvm_info(void)
@@ -53,11 +55,13 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
u32 confoff = (irq / 16) * 4;
u32 val, oldval;
int ret = 0;
+ unsigned long flags;
/*
* Read current configuration register, and insert the config
* for "irq", depending on "type".
*/
+ raw_spin_lock_irqsave(&irq_controller_lock, flags);
val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
if (type & IRQ_TYPE_LEVEL_MASK)
val &= ~confmask;
@@ -65,8 +69,10 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
val |= confmask;
/* If the current configuration is the same, then we are done */
- if (val == oldval)
+ if (val == oldval) {
+ raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
return 0;
+ }
/*
* Write back the new configuration, and possibly re-enable
@@ -84,6 +90,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
pr_warn("GIC: PPI%d is secure or misconfigured\n",
irq - 16);
}
+ raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
if (sync_access)
sync_access();
diff --git a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c b/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c
index fc2013aade51..4eca5c763766 100644
--- a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c
@@ -13,7 +13,7 @@
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/of_irq.h>
-#include "../include/mc.h"
+#include <linux/fsl/mc.h>
static struct irq_chip its_msi_irq_chip = {
.name = "ITS-fMSI",
@@ -43,9 +43,7 @@ static int its_fsl_mc_msi_prepare(struct irq_domain *msi_domain,
* NOTE: This device id corresponds to the IOMMU stream ID
* associated with the DPRC object (ICID).
*/
-#ifdef GENERIC_MSI_DOMAIN_OPS
info->scratchpad[0].ul = mc_bus_dev->icid;
-#endif
msi_info = msi_get_domain_info(msi_domain->parent);
return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info);
}
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 2cbb19cddbf8..2982e93d2369 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -33,6 +33,7 @@
#include <linux/of_platform.h>
#include <linux/percpu.h>
#include <linux/slab.h>
+#include <linux/syscore_ops.h>
#include <linux/irqchip.h>
#include <linux/irqchip/arm-gic-v3.h>
@@ -46,6 +47,7 @@
#define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0)
#define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1)
#define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2)
+#define ITS_FLAGS_SAVE_SUSPEND_STATE (1ULL << 3)
#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0)
@@ -101,6 +103,8 @@ struct its_node {
struct its_collection *collections;
struct fwnode_handle *fwnode_handle;
u64 (*get_msi_base)(struct its_device *its_dev);
+ u64 cbaser_save;
+ u32 ctlr_save;
struct list_head its_device_list;
u64 flags;
unsigned long list_nr;
@@ -1875,16 +1879,6 @@ static void its_cpu_init_lpis(void)
gic_data_rdist()->pend_page = pend_page;
}
- /* Disable LPIs */
- val = readl_relaxed(rbase + GICR_CTLR);
- val &= ~GICR_CTLR_ENABLE_LPIS;
- writel_relaxed(val, rbase + GICR_CTLR);
-
- /*
- * Make sure any change to the table is observable by the GIC.
- */
- dsb(sy);
-
/* set PROPBASE */
val = (page_to_phys(gic_rdists->prop_page) |
GICR_PROPBASER_InnerShareable |
@@ -1938,52 +1932,53 @@ static void its_cpu_init_lpis(void)
dsb(sy);
}
-static void its_cpu_init_collection(void)
+static void its_cpu_init_collection(struct its_node *its)
{
- struct its_node *its;
- int cpu;
-
- spin_lock(&its_lock);
- cpu = smp_processor_id();
-
- list_for_each_entry(its, &its_nodes, entry) {
- u64 target;
+ int cpu = smp_processor_id();
+ u64 target;
- /* avoid cross node collections and its mapping */
- if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) {
- struct device_node *cpu_node;
+ /* avoid cross node collections and its mapping */
+ if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) {
+ struct device_node *cpu_node;
- cpu_node = of_get_cpu_node(cpu, NULL);
- if (its->numa_node != NUMA_NO_NODE &&
- its->numa_node != of_node_to_nid(cpu_node))
- continue;
- }
+ cpu_node = of_get_cpu_node(cpu, NULL);
+ if (its->numa_node != NUMA_NO_NODE &&
+ its->numa_node != of_node_to_nid(cpu_node))
+ return;
+ }
+ /*
+ * We now have to bind each collection to its target
+ * redistributor.
+ */
+ if (gic_read_typer(its->base + GITS_TYPER) & GITS_TYPER_PTA) {
/*
- * We now have to bind each collection to its target
+ * This ITS wants the physical address of the
* redistributor.
*/
- if (gic_read_typer(its->base + GITS_TYPER) & GITS_TYPER_PTA) {
- /*
- * This ITS wants the physical address of the
- * redistributor.
- */
- target = gic_data_rdist()->phys_base;
- } else {
- /*
- * This ITS wants a linear CPU number.
- */
- target = gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER);
- target = GICR_TYPER_CPU_NUMBER(target) << 16;
- }
+ target = gic_data_rdist()->phys_base;
+ } else {
+ /* This ITS wants a linear CPU number. */
+ target = gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER);
+ target = GICR_TYPER_CPU_NUMBER(target) << 16;
+ }
- /* Perform collection mapping */
- its->collections[cpu].target_address = target;
- its->collections[cpu].col_id = cpu;
+ /* Perform collection mapping */
+ its->collections[cpu].target_address = target;
+ its->collections[cpu].col_id = cpu;
- its_send_mapc(its, &its->collections[cpu], 1);
- its_send_invall(its, &its->collections[cpu]);
- }
+ its_send_mapc(its, &its->collections[cpu], 1);
+ its_send_invall(its, &its->collections[cpu]);
+}
+
+static void its_cpu_init_collections(void)
+{
+ struct its_node *its;
+
+ spin_lock(&its_lock);
+
+ list_for_each_entry(its, &its_nodes, entry)
+ its_cpu_init_collection(its);
spin_unlock(&its_lock);
}
@@ -3041,6 +3036,113 @@ static void its_enable_quirks(struct its_node *its)
gic_enable_quirks(iidr, its_quirks, its);
}
+static int its_save_disable(void)
+{
+ struct its_node *its;
+ int err = 0;
+
+ spin_lock(&its_lock);
+ list_for_each_entry(its, &its_nodes, entry) {
+ void __iomem *base;
+
+ if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
+ continue;
+
+ base = its->base;
+ its->ctlr_save = readl_relaxed(base + GITS_CTLR);
+ err = its_force_quiescent(base);
+ if (err) {
+ pr_err("ITS@%pa: failed to quiesce: %d\n",
+ &its->phys_base, err);
+ writel_relaxed(its->ctlr_save, base + GITS_CTLR);
+ goto err;
+ }
+
+ its->cbaser_save = gits_read_cbaser(base + GITS_CBASER);
+ }
+
+err:
+ if (err) {
+ list_for_each_entry_continue_reverse(its, &its_nodes, entry) {
+ void __iomem *base;
+
+ if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
+ continue;
+
+ base = its->base;
+ writel_relaxed(its->ctlr_save, base + GITS_CTLR);
+ }
+ }
+ spin_unlock(&its_lock);
+
+ return err;
+}
+
+static void its_restore_enable(void)
+{
+ struct its_node *its;
+ int ret;
+
+ spin_lock(&its_lock);
+ list_for_each_entry(its, &its_nodes, entry) {
+ void __iomem *base;
+ int i;
+
+ if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
+ continue;
+
+ base = its->base;
+
+ /*
+ * Make sure that the ITS is disabled. If it fails to quiesce,
+ * don't restore it since writing to CBASER or BASER<n>
+ * registers is undefined according to the GIC v3 ITS
+ * Specification.
+ */
+ ret = its_force_quiescent(base);
+ if (ret) {
+ pr_err("ITS@%pa: failed to quiesce on resume: %d\n",
+ &its->phys_base, ret);
+ continue;
+ }
+
+ gits_write_cbaser(its->cbaser_save, base + GITS_CBASER);
+
+ /*
+ * Writing CBASER resets CREADR to 0, so make CWRITER and
+ * cmd_write line up with it.
+ */
+ its->cmd_write = its->cmd_base;
+ gits_write_cwriter(0, base + GITS_CWRITER);
+
+ /* Restore GITS_BASER from the value cache. */
+ for (i = 0; i < GITS_BASER_NR_REGS; i++) {
+ struct its_baser *baser = &its->tables[i];
+
+ if (!(baser->val & GITS_BASER_VALID))
+ continue;
+
+ its_write_baser(its, baser, baser->val);
+ }
+ writel_relaxed(its->ctlr_save, base + GITS_CTLR);
+
+ /*
+ * Reinit the collection if it's stored in the ITS. This is
+ * indicated by the col_id being less than the HCC field.
+ * CID < HCC as specified in the GIC v3 Documentation.
+ */
+ if (its->collections[smp_processor_id()].col_id <
+ GITS_TYPER_HCC(gic_read_typer(base + GITS_TYPER)))
+ its_cpu_init_collection(its);
+ }
+ spin_unlock(&its_lock);
+}
+
+static struct syscore_ops its_syscore_ops = {
+ .suspend = its_save_disable,
+ .resume = its_restore_enable,
+};
+
static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
{
struct irq_domain *inner_domain;
@@ -3260,6 +3362,9 @@ static int __init its_probe_one(struct resource *res,
ctlr |= GITS_CTLR_ImDe;
writel_relaxed(ctlr, its->base + GITS_CTLR);
+ if (GITS_TYPER_HCC(typer))
+ its->flags |= ITS_FLAGS_SAVE_SUSPEND_STATE;
+
err = its_init_domain(handle, its);
if (err)
goto out_free_tables;
@@ -3287,15 +3392,71 @@ static bool gic_rdists_supports_plpis(void)
return !!(gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER) & GICR_TYPER_PLPIS);
}
+static int redist_disable_lpis(void)
+{
+ void __iomem *rbase = gic_data_rdist_rd_base();
+ u64 timeout = USEC_PER_SEC;
+ u64 val;
+
+ if (!gic_rdists_supports_plpis()) {
+ pr_info("CPU%d: LPIs not supported\n", smp_processor_id());
+ return -ENXIO;
+ }
+
+ val = readl_relaxed(rbase + GICR_CTLR);
+ if (!(val & GICR_CTLR_ENABLE_LPIS))
+ return 0;
+
+ pr_warn("CPU%d: Booted with LPIs enabled, memory probably corrupted\n",
+ smp_processor_id());
+ add_taint(TAINT_CRAP, LOCKDEP_STILL_OK);
+
+ /* Disable LPIs */
+ val &= ~GICR_CTLR_ENABLE_LPIS;
+ writel_relaxed(val, rbase + GICR_CTLR);
+
+ /* Make sure any change to GICR_CTLR is observable by the GIC */
+ dsb(sy);
+
+ /*
+ * Software must observe RWP==0 after clearing GICR_CTLR.EnableLPIs
+ * from 1 to 0 before programming GICR_PEND{PROP}BASER registers.
+ * Error out if we time out waiting for RWP to clear.
+ */
+ while (readl_relaxed(rbase + GICR_CTLR) & GICR_CTLR_RWP) {
+ if (!timeout) {
+ pr_err("CPU%d: Timeout while disabling LPIs\n",
+ smp_processor_id());
+ return -ETIMEDOUT;
+ }
+ udelay(1);
+ timeout--;
+ }
+
+ /*
+ * After it has been written to 1, it is IMPLEMENTATION
+ * DEFINED whether GICR_CTLR.EnableLPI becomes RES1 or can be
+ * cleared to 0. Error out if clearing the bit failed.
+ */
+ if (readl_relaxed(rbase + GICR_CTLR) & GICR_CTLR_ENABLE_LPIS) {
+ pr_err("CPU%d: Failed to disable LPIs\n", smp_processor_id());
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
int its_cpu_init(void)
{
if (!list_empty(&its_nodes)) {
- if (!gic_rdists_supports_plpis()) {
- pr_info("CPU%d: LPIs not supported\n", smp_processor_id());
- return -ENXIO;
- }
+ int ret;
+
+ ret = redist_disable_lpis();
+ if (ret)
+ return ret;
+
its_cpu_init_lpis();
- its_cpu_init_collection();
+ its_cpu_init_collections();
}
return 0;
@@ -3516,5 +3677,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
}
}
+ register_syscore_ops(&its_syscore_ops);
+
return 0;
}
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index d99cc07903ec..e5d101418390 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -61,7 +61,7 @@ struct gic_chip_data {
};
static struct gic_chip_data gic_data __read_mostly;
-static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE;
+static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
static struct gic_kvm_info gic_v3_kvm_info;
static DEFINE_PER_CPU(bool, has_rss);
@@ -354,7 +354,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {
int err;
- if (static_key_true(&supports_deactivate))
+ if (static_branch_likely(&supports_deactivate_key))
gic_write_eoir(irqnr);
else
isb();
@@ -362,7 +362,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
err = handle_domain_irq(gic_data.domain, irqnr, regs);
if (err) {
WARN_ONCE(true, "Unexpected interrupt received!\n");
- if (static_key_true(&supports_deactivate)) {
+ if (static_branch_likely(&supports_deactivate_key)) {
if (irqnr < 8192)
gic_write_dir(irqnr);
} else {
@@ -373,7 +373,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
}
if (irqnr < 16) {
gic_write_eoir(irqnr);
- if (static_key_true(&supports_deactivate))
+ if (static_branch_likely(&supports_deactivate_key))
gic_write_dir(irqnr);
#ifdef CONFIG_SMP
/*
@@ -532,6 +532,8 @@ static void gic_cpu_sys_reg_init(void)
int i, cpu = smp_processor_id();
u64 mpidr = cpu_logical_map(cpu);
u64 need_rss = MPIDR_RS(mpidr);
+ bool group0;
+ u32 val, pribits;
/*
* Need to check that the SRE bit has actually been set. If
@@ -543,8 +545,28 @@ static void gic_cpu_sys_reg_init(void)
if (!gic_enable_sre())
pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n");
+ pribits = gic_read_ctlr();
+ pribits &= ICC_CTLR_EL1_PRI_BITS_MASK;
+ pribits >>= ICC_CTLR_EL1_PRI_BITS_SHIFT;
+ pribits++;
+
+ /*
+ * Let's find out if Group0 is under control of EL3 or not by
+ * setting the highest possible, non-zero priority in PMR.
+ *
+ * If SCR_EL3.FIQ is set, the priority gets shifted down in
+ * order for the CPU interface to set bit 7, and keep the
+ * actual priority in the non-secure range. In the process, it
+ * looses the least significant bit and the actual priority
+ * becomes 0x80. Reading it back returns 0, indicating that
+ * we're don't have access to Group0.
+ */
+ write_gicreg(BIT(8 - pribits), ICC_PMR_EL1);
+ val = read_gicreg(ICC_PMR_EL1);
+ group0 = val != 0;
+
/* Set priority mask register */
- gic_write_pmr(DEFAULT_PMR_VALUE);
+ write_gicreg(DEFAULT_PMR_VALUE, ICC_PMR_EL1);
/*
* Some firmwares hand over to the kernel with the BPR changed from
@@ -554,7 +576,7 @@ static void gic_cpu_sys_reg_init(void)
*/
gic_write_bpr1(0);
- if (static_key_true(&supports_deactivate)) {
+ if (static_branch_likely(&supports_deactivate_key)) {
/* EOI drops priority only (mode 1) */
gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop);
} else {
@@ -562,6 +584,37 @@ static void gic_cpu_sys_reg_init(void)
gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir);
}
+ /* Always whack Group0 before Group1 */
+ if (group0) {
+ switch(pribits) {
+ case 8:
+ case 7:
+ write_gicreg(0, ICC_AP0R3_EL1);
+ write_gicreg(0, ICC_AP0R2_EL1);
+ case 6:
+ write_gicreg(0, ICC_AP0R1_EL1);
+ case 5:
+ case 4:
+ write_gicreg(0, ICC_AP0R0_EL1);
+ }
+
+ isb();
+ }
+
+ switch(pribits) {
+ case 8:
+ case 7:
+ write_gicreg(0, ICC_AP1R3_EL1);
+ write_gicreg(0, ICC_AP1R2_EL1);
+ case 6:
+ write_gicreg(0, ICC_AP1R1_EL1);
+ case 5:
+ case 4:
+ write_gicreg(0, ICC_AP1R0_EL1);
+ }
+
+ isb();
+
/* ... and let's hit the road... */
gic_write_grpen1(1);
@@ -590,9 +643,17 @@ static void gic_cpu_sys_reg_init(void)
pr_crit_once("RSS is required but GICD doesn't support it\n");
}
+static bool gicv3_nolpi;
+
+static int __init gicv3_nolpi_cfg(char *buf)
+{
+ return strtobool(buf, &gicv3_nolpi);
+}
+early_param("irqchip.gicv3_nolpi", gicv3_nolpi_cfg);
+
static int gic_dist_supports_lpis(void)
{
- return !!(readl_relaxed(gic_data.dist_base + GICD_TYPER) & GICD_TYPER_LPIS);
+ return !!(readl_relaxed(gic_data.dist_base + GICD_TYPER) & GICD_TYPER_LPIS) && !gicv3_nolpi;
}
static void gic_cpu_init(void)
@@ -823,7 +884,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
{
struct irq_chip *chip = &gic_chip;
- if (static_key_true(&supports_deactivate))
+ if (static_branch_likely(&supports_deactivate_key))
chip = &gic_eoimode1_chip;
/* SGIs are private to the core kernel */
@@ -861,6 +922,8 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
return 0;
}
+#define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1)
+
static int gic_irq_domain_translate(struct irq_domain *d,
struct irq_fwspec *fwspec,
unsigned long *hwirq,
@@ -875,6 +938,7 @@ static int gic_irq_domain_translate(struct irq_domain *d,
*hwirq = fwspec->param[1] + 32;
break;
case 1: /* PPI */
+ case GIC_IRQ_TYPE_PARTITION:
*hwirq = fwspec->param[1] + 16;
break;
case GIC_IRQ_TYPE_LPI: /* LPI */
@@ -885,6 +949,13 @@ static int gic_irq_domain_translate(struct irq_domain *d,
}
*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
+
+ /*
+ * Make it clear that broken DTs are... broken.
+ * Partitionned PPIs are an unfortunate exception.
+ */
+ WARN_ON(*type == IRQ_TYPE_NONE &&
+ fwspec->param[0] != GIC_IRQ_TYPE_PARTITION);
return 0;
}
@@ -894,6 +965,8 @@ static int gic_irq_domain_translate(struct irq_domain *d,
*hwirq = fwspec->param[0];
*type = fwspec->param[1];
+
+ WARN_ON(*type == IRQ_TYPE_NONE);
return 0;
}
@@ -1002,9 +1075,9 @@ static int __init gic_init_bases(void __iomem *dist_base,
int err;
if (!is_hyp_mode_available())
- static_key_slow_dec(&supports_deactivate);
+ static_branch_disable(&supports_deactivate_key);
- if (static_key_true(&supports_deactivate))
+ if (static_branch_likely(&supports_deactivate_key))
pr_info("GIC: Using split EOI/Deactivate mode\n");
gic_data.fwnode = handle;
@@ -1140,7 +1213,7 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node)
.fwnode = gic_data.fwnode,
.param_count = 3,
.param = {
- [0] = 1,
+ [0] = GIC_IRQ_TYPE_PARTITION,
[1] = i,
[2] = IRQ_TYPE_NONE,
},
@@ -1239,7 +1312,7 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
gic_populate_ppi_partitions(node);
- if (static_key_true(&supports_deactivate))
+ if (static_branch_likely(&supports_deactivate_key))
gic_of_setup_kvm_info(node);
return 0;
@@ -1541,7 +1614,7 @@ gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end)
acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
- if (static_key_true(&supports_deactivate))
+ if (static_branch_likely(&supports_deactivate_key))
gic_acpi_setup_kvm_info();
return 0;
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 121af5cf688f..ced10c44b68a 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -121,7 +121,7 @@ static DEFINE_RAW_SPINLOCK(cpu_map_lock);
#define NR_GIC_CPU_IF 8
static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
-static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE;
+static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly;
@@ -361,7 +361,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
irqnr = irqstat & GICC_IAR_INT_ID_MASK;
if (likely(irqnr > 15 && irqnr < 1020)) {
- if (static_key_true(&supports_deactivate))
+ if (static_branch_likely(&supports_deactivate_key))
writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
isb();
handle_domain_irq(gic->domain, irqnr, regs);
@@ -369,7 +369,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
}
if (irqnr < 16) {
writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
- if (static_key_true(&supports_deactivate))
+ if (static_branch_likely(&supports_deactivate_key))
writel_relaxed(irqstat, cpu_base + GIC_CPU_DEACTIVATE);
#ifdef CONFIG_SMP
/*
@@ -453,15 +453,26 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic)
return mask;
}
+static bool gic_check_gicv2(void __iomem *base)
+{
+ u32 val = readl_relaxed(base + GIC_CPU_IDENT);
+ return (val & 0xff0fff) == 0x02043B;
+}
+
static void gic_cpu_if_up(struct gic_chip_data *gic)
{
void __iomem *cpu_base = gic_data_cpu_base(gic);
u32 bypass = 0;
u32 mode = 0;
+ int i;
- if (gic == &gic_data[0] && static_key_true(&supports_deactivate))
+ if (gic == &gic_data[0] && static_branch_likely(&supports_deactivate_key))
mode = GIC_CPU_CTRL_EOImodeNS;
+ if (gic_check_gicv2(cpu_base))
+ for (i = 0; i < 4; i++)
+ writel_relaxed(0, cpu_base + GIC_CPU_ACTIVEPRIO + i * 4);
+
/*
* Preserve bypass disable bits to be written back later
*/
@@ -1000,6 +1011,9 @@ static int gic_irq_domain_translate(struct irq_domain *d,
*hwirq += 16;
*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
+
+ /* Make it clear that broken DTs are... broken */
+ WARN_ON(*type == IRQ_TYPE_NONE);
return 0;
}
@@ -1009,6 +1023,8 @@ static int gic_irq_domain_translate(struct irq_domain *d,
*hwirq = fwspec->param[0];
*type = fwspec->param[1];
+
+ WARN_ON(*type == IRQ_TYPE_NONE);
return 0;
}
@@ -1203,11 +1219,11 @@ static int __init __gic_init_bases(struct gic_chip_data *gic,
"irqchip/arm/gic:starting",
gic_starting_cpu, NULL);
set_handle_irq(gic_handle_irq);
- if (static_key_true(&supports_deactivate))
+ if (static_branch_likely(&supports_deactivate_key))
pr_info("GIC: Using split EOI/Deactivate mode\n");
}
- if (static_key_true(&supports_deactivate) && gic == &gic_data[0]) {
+ if (static_branch_likely(&supports_deactivate_key) && gic == &gic_data[0]) {
name = kasprintf(GFP_KERNEL, "GICv2");
gic_init_chip(gic, NULL, name, true);
} else {
@@ -1234,7 +1250,7 @@ void __init gic_init(unsigned int gic_nr, int irq_start,
* Non-DT/ACPI systems won't run a hypervisor, so let's not
* bother with these...
*/
- static_key_slow_dec(&supports_deactivate);
+ static_branch_disable(&supports_deactivate_key);
gic = &gic_data[gic_nr];
gic->raw_dist_base = dist_base;
@@ -1264,12 +1280,6 @@ static int __init gicv2_force_probe_cfg(char *buf)
}
early_param("irqchip.gicv2_force_probe", gicv2_force_probe_cfg);
-static bool gic_check_gicv2(void __iomem *base)
-{
- u32 val = readl_relaxed(base + GIC_CPU_IDENT);
- return (val & 0xff0fff) == 0x02043B;
-}
-
static bool gic_check_eoimode(struct device_node *node, void __iomem **base)
{
struct resource cpuif_res;
@@ -1420,7 +1430,7 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)
if (ret)
return;
- if (static_key_true(&supports_deactivate))
+ if (static_branch_likely(&supports_deactivate_key))
gic_set_kvm_info(&gic_v2_kvm_info);
}
@@ -1447,7 +1457,7 @@ gic_of_init(struct device_node *node, struct device_node *parent)
* or the CPU interface is too small.
*/
if (gic_cnt == 0 && !gic_check_eoimode(node, &gic->raw_cpu_base))
- static_key_slow_dec(&supports_deactivate);
+ static_branch_disable(&supports_deactivate_key);
ret = __gic_init_bases(gic, -1, &node->fwnode);
if (ret) {
@@ -1628,7 +1638,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
* interface will always be the right size.
*/
if (!is_hyp_mode_available())
- static_key_slow_dec(&supports_deactivate);
+ static_branch_disable(&supports_deactivate_key);
/*
* Initialize GIC instance zero (no multi-GIC support).
@@ -1653,7 +1663,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
gicv2m_init(NULL, gic_data[0].domain);
- if (static_key_true(&supports_deactivate))
+ if (static_branch_likely(&supports_deactivate_key))
gic_acpi_setup_kvm_info();
return 0;
diff --git a/drivers/irqchip/irq-mscc-ocelot.c b/drivers/irqchip/irq-mscc-ocelot.c
new file mode 100644
index 000000000000..b63e40c00a02
--- /dev/null
+++ b/drivers/irqchip/irq-mscc-ocelot.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Microsemi Ocelot IRQ controller driver
+ *
+ * Copyright (c) 2017 Microsemi Corporation
+ */
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/interrupt.h>
+
+#define ICPU_CFG_INTR_INTR_STICKY 0x10
+#define ICPU_CFG_INTR_INTR_ENA 0x18
+#define ICPU_CFG_INTR_INTR_ENA_CLR 0x1c
+#define ICPU_CFG_INTR_INTR_ENA_SET 0x20
+#define ICPU_CFG_INTR_DST_INTR_IDENT(x) (0x38 + 0x4 * (x))
+#define ICPU_CFG_INTR_INTR_TRIGGER(x) (0x5c + 0x4 * (x))
+
+#define OCELOT_NR_IRQ 24
+
+static void ocelot_irq_unmask(struct irq_data *data)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+ struct irq_chip_type *ct = irq_data_get_chip_type(data);
+ unsigned int mask = data->mask;
+ u32 val;
+
+ irq_gc_lock(gc);
+ val = irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(0)) |
+ irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(1));
+ if (!(val & mask))
+ irq_reg_writel(gc, mask, ICPU_CFG_INTR_INTR_STICKY);
+
+ *ct->mask_cache &= ~mask;
+ irq_reg_writel(gc, mask, ICPU_CFG_INTR_INTR_ENA_SET);
+ irq_gc_unlock(gc);
+}
+
+static void ocelot_irq_handler(struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct irq_domain *d = irq_desc_get_handler_data(desc);
+ struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0);
+ u32 reg = irq_reg_readl(gc, ICPU_CFG_INTR_DST_INTR_IDENT(0));
+
+ chained_irq_enter(chip, desc);
+
+ while (reg) {
+ u32 hwirq = __fls(reg);
+
+ generic_handle_irq(irq_find_mapping(d, hwirq));
+ reg &= ~(BIT(hwirq));
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static int __init ocelot_irq_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct irq_domain *domain;
+ struct irq_chip_generic *gc;
+ int parent_irq, ret;
+
+ parent_irq = irq_of_parse_and_map(node, 0);
+ if (!parent_irq)
+ return -EINVAL;
+
+ domain = irq_domain_add_linear(node, OCELOT_NR_IRQ,
+ &irq_generic_chip_ops, NULL);
+ if (!domain) {
+ pr_err("%s: unable to add irq domain\n", node->name);
+ return -ENOMEM;
+ }
+
+ ret = irq_alloc_domain_generic_chips(domain, OCELOT_NR_IRQ, 1,
+ "icpu", handle_level_irq,
+ 0, 0, 0);
+ if (ret) {
+ pr_err("%s: unable to alloc irq domain gc\n", node->name);
+ goto err_domain_remove;
+ }
+
+ gc = irq_get_domain_generic_chip(domain, 0);
+ gc->reg_base = of_iomap(node, 0);
+ if (!gc->reg_base) {
+ pr_err("%s: unable to map resource\n", node->name);
+ ret = -ENOMEM;
+ goto err_gc_free;
+ }
+
+ gc->chip_types[0].regs.ack = ICPU_CFG_INTR_INTR_STICKY;
+ gc->chip_types[0].regs.mask = ICPU_CFG_INTR_INTR_ENA_CLR;
+ gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
+ gc->chip_types[0].chip.irq_unmask = ocelot_irq_unmask;
+
+ /* Mask and ack all interrupts */
+ irq_reg_writel(gc, 0, ICPU_CFG_INTR_INTR_ENA);
+ irq_reg_writel(gc, 0xffffffff, ICPU_CFG_INTR_INTR_STICKY);
+
+ irq_set_chained_handler_and_data(parent_irq, ocelot_irq_handler,
+ domain);
+
+ return 0;
+
+err_gc_free:
+ irq_free_generic_chip(gc);
+
+err_domain_remove:
+ irq_domain_remove(domain);
+
+ return ret;
+}
+IRQCHIP_DECLARE(ocelot_icpu, "mscc,ocelot-icpu-intr", ocelot_irq_init);
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c
index cee59fe1321c..c6e6c9e9137a 100644
--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
+++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
@@ -17,7 +17,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/clk.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -78,16 +77,14 @@ struct intc_irqpin_priv {
struct platform_device *pdev;
struct irq_chip irq_chip;
struct irq_domain *irq_domain;
- struct clk *clk;
+ atomic_t wakeup_path;
unsigned shared_irqs:1;
- unsigned needs_clk:1;
u8 shared_irq_mask;
};
struct intc_irqpin_config {
unsigned int irlm_bit;
unsigned needs_irlm:1;
- unsigned needs_clk:1;
};
static unsigned long intc_irqpin_read32(void __iomem *iomem)
@@ -287,14 +284,10 @@ static int intc_irqpin_irq_set_wake(struct irq_data *d, unsigned int on)
int hw_irq = irqd_to_hwirq(d);
irq_set_irq_wake(p->irq[hw_irq].requested_irq, on);
-
- if (!p->clk)
- return 0;
-
if (on)
- clk_enable(p->clk);
+ atomic_inc(&p->wakeup_path);
else
- clk_disable(p->clk);
+ atomic_dec(&p->wakeup_path);
return 0;
}
@@ -369,12 +362,10 @@ static const struct irq_domain_ops intc_irqpin_irq_domain_ops = {
static const struct intc_irqpin_config intc_irqpin_irlm_r8a777x = {
.irlm_bit = 23, /* ICR0.IRLM0 */
.needs_irlm = 1,
- .needs_clk = 0,
};
static const struct intc_irqpin_config intc_irqpin_rmobile = {
.needs_irlm = 0,
- .needs_clk = 1,
};
static const struct of_device_id intc_irqpin_dt_ids[] = {
@@ -426,18 +417,6 @@ static int intc_irqpin_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, p);
config = of_device_get_match_data(dev);
- if (config)
- p->needs_clk = config->needs_clk;
-
- p->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(p->clk)) {
- if (p->needs_clk) {
- dev_err(dev, "unable to get clock\n");
- ret = PTR_ERR(p->clk);
- goto err0;
- }
- p->clk = NULL;
- }
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
@@ -606,12 +585,25 @@ static int intc_irqpin_remove(struct platform_device *pdev)
return 0;
}
+static int __maybe_unused intc_irqpin_suspend(struct device *dev)
+{
+ struct intc_irqpin_priv *p = dev_get_drvdata(dev);
+
+ if (atomic_read(&p->wakeup_path))
+ device_set_wakeup_path(dev);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(intc_irqpin_pm_ops, intc_irqpin_suspend, NULL);
+
static struct platform_driver intc_irqpin_device_driver = {
.probe = intc_irqpin_probe,
.remove = intc_irqpin_remove,
.driver = {
.name = "renesas_intc_irqpin",
.of_match_table = intc_irqpin_dt_ids,
+ .pm = &intc_irqpin_pm_ops,
}
};
diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c
index 52304b139aa4..a4f11124024d 100644
--- a/drivers/irqchip/irq-renesas-irqc.c
+++ b/drivers/irqchip/irq-renesas-irqc.c
@@ -17,7 +17,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/clk.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
@@ -64,7 +63,7 @@ struct irqc_priv {
struct platform_device *pdev;
struct irq_chip_generic *gc;
struct irq_domain *irq_domain;
- struct clk *clk;
+ atomic_t wakeup_path;
};
static struct irqc_priv *irq_data_to_priv(struct irq_data *data)
@@ -111,14 +110,10 @@ static int irqc_irq_set_wake(struct irq_data *d, unsigned int on)
int hw_irq = irqd_to_hwirq(d);
irq_set_irq_wake(p->irq[hw_irq].requested_irq, on);
-
- if (!p->clk)
- return 0;
-
if (on)
- clk_enable(p->clk);
+ atomic_inc(&p->wakeup_path);
else
- clk_disable(p->clk);
+ atomic_dec(&p->wakeup_path);
return 0;
}
@@ -159,12 +154,6 @@ static int irqc_probe(struct platform_device *pdev)
p->pdev = pdev;
platform_set_drvdata(pdev, p);
- p->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(p->clk)) {
- dev_warn(&pdev->dev, "unable to get clock\n");
- p->clk = NULL;
- }
-
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
@@ -276,6 +265,18 @@ static int irqc_remove(struct platform_device *pdev)
return 0;
}
+static int __maybe_unused irqc_suspend(struct device *dev)
+{
+ struct irqc_priv *p = dev_get_drvdata(dev);
+
+ if (atomic_read(&p->wakeup_path))
+ device_set_wakeup_path(dev);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(irqc_pm_ops, irqc_suspend, NULL);
+
static const struct of_device_id irqc_dt_ids[] = {
{ .compatible = "renesas,irqc", },
{},
@@ -288,6 +289,7 @@ static struct platform_driver irqc_device_driver = {
.driver = {
.name = "renesas_irqc",
.of_match_table = irqc_dt_ids,
+ .pm = &irqc_pm_ops,
}
};
diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
new file mode 100644
index 000000000000..b1b47a40a278
--- /dev/null
+++ b/drivers/irqchip/qcom-pdc.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define PDC_MAX_IRQS 126
+
+#define CLEAR_INTR(reg, intr) (reg & ~(1 << intr))
+#define ENABLE_INTR(reg, intr) (reg | (1 << intr))
+
+#define IRQ_ENABLE_BANK 0x10
+#define IRQ_i_CFG 0x110
+
+struct pdc_pin_region {
+ u32 pin_base;
+ u32 parent_base;
+ u32 cnt;
+};
+
+static DEFINE_RAW_SPINLOCK(pdc_lock);
+static void __iomem *pdc_base;
+static struct pdc_pin_region *pdc_region;
+static int pdc_region_cnt;
+
+static void pdc_reg_write(int reg, u32 i, u32 val)
+{
+ writel_relaxed(val, pdc_base + reg + i * sizeof(u32));
+}
+
+static u32 pdc_reg_read(int reg, u32 i)
+{
+ return readl_relaxed(pdc_base + reg + i * sizeof(u32));
+}
+
+static void pdc_enable_intr(struct irq_data *d, bool on)
+{
+ int pin_out = d->hwirq;
+ u32 index, mask;
+ u32 enable;
+
+ index = pin_out / 32;
+ mask = pin_out % 32;
+
+ raw_spin_lock(&pdc_lock);
+ enable = pdc_reg_read(IRQ_ENABLE_BANK, index);
+ enable = on ? ENABLE_INTR(enable, mask) : CLEAR_INTR(enable, mask);
+ pdc_reg_write(IRQ_ENABLE_BANK, index, enable);
+ raw_spin_unlock(&pdc_lock);
+}
+
+static void qcom_pdc_gic_mask(struct irq_data *d)
+{
+ pdc_enable_intr(d, false);
+ irq_chip_mask_parent(d);
+}
+
+static void qcom_pdc_gic_unmask(struct irq_data *d)
+{
+ pdc_enable_intr(d, true);
+ irq_chip_unmask_parent(d);
+}
+
+/*
+ * GIC does not handle falling edge or active low. To allow falling edge and
+ * active low interrupts to be handled at GIC, PDC has an inverter that inverts
+ * falling edge into a rising edge and active low into an active high.
+ * For the inverter to work, the polarity bit in the IRQ_CONFIG register has to
+ * set as per the table below.
+ * Level sensitive active low LOW
+ * Rising edge sensitive NOT USED
+ * Falling edge sensitive LOW
+ * Dual Edge sensitive NOT USED
+ * Level sensitive active High HIGH
+ * Falling Edge sensitive NOT USED
+ * Rising edge sensitive HIGH
+ * Dual Edge sensitive HIGH
+ */
+enum pdc_irq_config_bits {
+ PDC_LEVEL_LOW = 0b000,
+ PDC_EDGE_FALLING = 0b010,
+ PDC_LEVEL_HIGH = 0b100,
+ PDC_EDGE_RISING = 0b110,
+ PDC_EDGE_DUAL = 0b111,
+};
+
+/**
+ * qcom_pdc_gic_set_type: Configure PDC for the interrupt
+ *
+ * @d: the interrupt data
+ * @type: the interrupt type
+ *
+ * If @type is edge triggered, forward that as Rising edge as PDC
+ * takes care of converting falling edge to rising edge signal
+ * If @type is level, then forward that as level high as PDC
+ * takes care of converting falling edge to rising edge signal
+ */
+static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
+{
+ int pin_out = d->hwirq;
+ enum pdc_irq_config_bits pdc_type;
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ pdc_type = PDC_EDGE_RISING;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ pdc_type = PDC_EDGE_FALLING;
+ type = IRQ_TYPE_EDGE_RISING;
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ pdc_type = PDC_EDGE_DUAL;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ pdc_type = PDC_LEVEL_HIGH;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ pdc_type = PDC_LEVEL_LOW;
+ type = IRQ_TYPE_LEVEL_HIGH;
+ break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ pdc_reg_write(IRQ_i_CFG, pin_out, pdc_type);
+
+ return irq_chip_set_type_parent(d, type);
+}
+
+static struct irq_chip qcom_pdc_gic_chip = {
+ .name = "PDC",
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_mask = qcom_pdc_gic_mask,
+ .irq_unmask = qcom_pdc_gic_unmask,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_set_type = qcom_pdc_gic_set_type,
+ .flags = IRQCHIP_MASK_ON_SUSPEND |
+ IRQCHIP_SET_TYPE_MASKED |
+ IRQCHIP_SKIP_SET_WAKE,
+ .irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+};
+
+static irq_hw_number_t get_parent_hwirq(int pin)
+{
+ int i;
+ struct pdc_pin_region *region;
+
+ for (i = 0; i < pdc_region_cnt; i++) {
+ region = &pdc_region[i];
+ if (pin >= region->pin_base &&
+ pin < region->pin_base + region->cnt)
+ return (region->parent_base + pin - region->pin_base);
+ }
+
+ WARN_ON(1);
+ return ~0UL;
+}
+
+static int qcom_pdc_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
+ unsigned long *hwirq, unsigned int *type)
+{
+ if (is_of_node(fwspec->fwnode)) {
+ if (fwspec->param_count != 2)
+ return -EINVAL;
+
+ *hwirq = fwspec->param[0];
+ *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int qcom_pdc_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *data)
+{
+ struct irq_fwspec *fwspec = data;
+ struct irq_fwspec parent_fwspec;
+ irq_hw_number_t hwirq, parent_hwirq;
+ unsigned int type;
+ int ret;
+
+ ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type);
+ if (ret)
+ return -EINVAL;
+
+ parent_hwirq = get_parent_hwirq(hwirq);
+ if (parent_hwirq == ~0UL)
+ return -EINVAL;
+
+ ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
+ &qcom_pdc_gic_chip, NULL);
+ if (ret)
+ return ret;
+
+ if (type & IRQ_TYPE_EDGE_BOTH)
+ type = IRQ_TYPE_EDGE_RISING;
+
+ if (type & IRQ_TYPE_LEVEL_MASK)
+ type = IRQ_TYPE_LEVEL_HIGH;
+
+ parent_fwspec.fwnode = domain->parent->fwnode;
+ parent_fwspec.param_count = 3;
+ parent_fwspec.param[0] = 0;
+ parent_fwspec.param[1] = parent_hwirq;
+ parent_fwspec.param[2] = type;
+
+ return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
+ &parent_fwspec);
+}
+
+static const struct irq_domain_ops qcom_pdc_ops = {
+ .translate = qcom_pdc_translate,
+ .alloc = qcom_pdc_alloc,
+ .free = irq_domain_free_irqs_common,
+};
+
+static int pdc_setup_pin_mapping(struct device_node *np)
+{
+ int ret, n;
+
+ n = of_property_count_elems_of_size(np, "qcom,pdc-ranges", sizeof(u32));
+ if (n <= 0 || n % 3)
+ return -EINVAL;
+
+ pdc_region_cnt = n / 3;
+ pdc_region = kcalloc(pdc_region_cnt, sizeof(*pdc_region), GFP_KERNEL);
+ if (!pdc_region) {
+ pdc_region_cnt = 0;
+ return -ENOMEM;
+ }
+
+ for (n = 0; n < pdc_region_cnt; n++) {
+ ret = of_property_read_u32_index(np, "qcom,pdc-ranges",
+ n * 3 + 0,
+ &pdc_region[n].pin_base);
+ if (ret)
+ return ret;
+ ret = of_property_read_u32_index(np, "qcom,pdc-ranges",
+ n * 3 + 1,
+ &pdc_region[n].parent_base);
+ if (ret)
+ return ret;
+ ret = of_property_read_u32_index(np, "qcom,pdc-ranges",
+ n * 3 + 2,
+ &pdc_region[n].cnt);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int qcom_pdc_init(struct device_node *node, struct device_node *parent)
+{
+ struct irq_domain *parent_domain, *pdc_domain;
+ int ret;
+
+ pdc_base = of_iomap(node, 0);
+ if (!pdc_base) {
+ pr_err("%pOF: unable to map PDC registers\n", node);
+ return -ENXIO;
+ }
+
+ parent_domain = irq_find_host(parent);
+ if (!parent_domain) {
+ pr_err("%pOF: unable to find PDC's parent domain\n", node);
+ ret = -ENXIO;
+ goto fail;
+ }
+
+ ret = pdc_setup_pin_mapping(node);
+ if (ret) {
+ pr_err("%pOF: failed to init PDC pin-hwirq mapping\n", node);
+ goto fail;
+ }
+
+ pdc_domain = irq_domain_create_hierarchy(parent_domain, 0, PDC_MAX_IRQS,
+ of_fwnode_handle(node),
+ &qcom_pdc_ops, NULL);
+ if (!pdc_domain) {
+ pr_err("%pOF: GIC domain add failed\n", node);
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ kfree(pdc_region);
+ iounmap(pdc_base);
+ return ret;
+}
+
+IRQCHIP_DECLARE(pdc_sdm845, "qcom,sdm845-pdc", qcom_pdc_init);
diff --git a/drivers/mcb/mcb-pci.c b/drivers/mcb/mcb-pci.c
index af4d2f26f1c6..c2d69e33bf2b 100644
--- a/drivers/mcb/mcb-pci.c
+++ b/drivers/mcb/mcb-pci.c
@@ -117,6 +117,7 @@ static void mcb_pci_remove(struct pci_dev *pdev)
static const struct pci_device_id mcb_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MEN, PCI_DEVICE_ID_MEN_CHAMELEON) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ALTERA, PCI_DEVICE_ID_MEN_CHAMELEON) },
{ 0 },
};
MODULE_DEVICE_TABLE(pci, mcb_pci_tbl);
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 86c1a190d946..37124c3b8c2a 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -141,6 +141,7 @@ config DVB_CORE
tristate
depends on MEDIA_SUPPORT
depends on MEDIA_DIGITAL_TV_SUPPORT
+ depends on (I2C || I2C=n)
default y
select CRC32
diff --git a/drivers/media/cec/Kconfig b/drivers/media/cec/Kconfig
index 43428cec3a01..9c2b108c613a 100644
--- a/drivers/media/cec/Kconfig
+++ b/drivers/media/cec/Kconfig
@@ -4,3 +4,9 @@ config MEDIA_CEC_RC
depends on CEC_CORE=m || RC_CORE=y
---help---
Pass on CEC remote control messages to the RC framework.
+
+config CEC_PIN_ERROR_INJ
+ bool "Enable CEC error injection support"
+ depends on CEC_PIN && DEBUG_FS
+ ---help---
+ This option enables CEC error injection using debugfs.
diff --git a/drivers/media/cec/Makefile b/drivers/media/cec/Makefile
index 41ee3325e1ea..29a2ab9e77c5 100644
--- a/drivers/media/cec/Makefile
+++ b/drivers/media/cec/Makefile
@@ -9,4 +9,8 @@ ifeq ($(CONFIG_CEC_PIN),y)
cec-objs += cec-pin.o
endif
+ifeq ($(CONFIG_CEC_PIN_ERROR_INJ),y)
+ cec-objs += cec-pin-error-inj.o
+endif
+
obj-$(CONFIG_CEC_CORE) += cec.o
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
index 2b1e540587d6..002ed4c90371 100644
--- a/drivers/media/cec/cec-adap.c
+++ b/drivers/media/cec/cec-adap.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cec-adap.c - HDMI Consumer Electronics Control framework - CEC adapter
*
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/errno.h>
@@ -85,8 +73,8 @@ static unsigned int cec_log_addr2dev(const struct cec_adapter *adap, u8 log_addr
void cec_queue_event_fh(struct cec_fh *fh,
const struct cec_event *new_ev, u64 ts)
{
- static const u8 max_events[CEC_NUM_EVENTS] = {
- 1, 1, 64, 64, 8, 8,
+ static const u16 max_events[CEC_NUM_EVENTS] = {
+ 1, 1, 800, 800, 8, 8,
};
struct cec_event_entry *entry;
unsigned int ev_idx = new_ev->event - 1;
@@ -154,11 +142,13 @@ static void cec_queue_event(struct cec_adapter *adap,
}
/* Notify userspace that the CEC pin changed state at the given time. */
-void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, ktime_t ts)
+void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high,
+ bool dropped_events, ktime_t ts)
{
struct cec_event ev = {
.event = is_high ? CEC_EVENT_PIN_CEC_HIGH :
CEC_EVENT_PIN_CEC_LOW,
+ .flags = dropped_events ? CEC_EVENT_FL_DROPPED_EVENTS : 0,
};
struct cec_fh *fh;
@@ -711,16 +701,31 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
else
msg->flags = 0;
+ if (msg->len > 1 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) {
+ msg->msg[2] = adap->phys_addr >> 8;
+ msg->msg[3] = adap->phys_addr & 0xff;
+ }
+
/* Sanity checks */
if (msg->len == 0 || msg->len > CEC_MAX_MSG_SIZE) {
dprintk(1, "%s: invalid length %d\n", __func__, msg->len);
return -EINVAL;
}
+
+ memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len);
+
+ if (msg->timeout)
+ dprintk(2, "%s: %*ph (wait for 0x%02x%s)\n",
+ __func__, msg->len, msg->msg, msg->reply,
+ !block ? ", nb" : "");
+ else
+ dprintk(2, "%s: %*ph%s\n",
+ __func__, msg->len, msg->msg, !block ? " (nb)" : "");
+
if (msg->timeout && msg->len == 1) {
- dprintk(1, "%s: can't reply for poll msg\n", __func__);
+ dprintk(1, "%s: can't reply to poll msg\n", __func__);
return -EINVAL;
}
- memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len);
if (msg->len == 1) {
if (cec_msg_destination(msg) == 0xf) {
dprintk(1, "%s: invalid poll message\n", __func__);
@@ -780,19 +785,6 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
if (!msg->sequence)
msg->sequence = ++adap->sequence;
- if (msg->len > 1 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) {
- msg->msg[2] = adap->phys_addr >> 8;
- msg->msg[3] = adap->phys_addr & 0xff;
- }
-
- if (msg->timeout)
- dprintk(2, "%s: %*ph (wait for 0x%02x%s)\n",
- __func__, msg->len, msg->msg, msg->reply,
- !block ? ", nb" : "");
- else
- dprintk(2, "%s: %*ph%s\n",
- __func__, msg->len, msg->msg, !block ? " (nb)" : "");
-
data->msg = *msg;
data->fh = fh;
data->adap = adap;
diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c
index 492db12b8c4d..10b67fc40318 100644
--- a/drivers/media/cec/cec-api.c
+++ b/drivers/media/cec/cec-api.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cec-api.c - HDMI Consumer Electronics Control framework - API
*
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/errno.h>
diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c
index a9f9525db9ae..b0c87f9ea08f 100644
--- a/drivers/media/cec/cec-core.c
+++ b/drivers/media/cec/cec-core.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cec-core.c - HDMI Consumer Electronics Control framework - Core
*
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/errno.h>
@@ -207,6 +195,55 @@ void cec_register_cec_notifier(struct cec_adapter *adap,
EXPORT_SYMBOL_GPL(cec_register_cec_notifier);
#endif
+#ifdef CONFIG_DEBUG_FS
+static ssize_t cec_error_inj_write(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ struct seq_file *sf = file->private_data;
+ struct cec_adapter *adap = sf->private;
+ char *buf;
+ char *line;
+ char *p;
+
+ buf = memdup_user_nul(ubuf, min_t(size_t, PAGE_SIZE, count));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+ p = buf;
+ while (p && *p) {
+ p = skip_spaces(p);
+ line = strsep(&p, "\n");
+ if (!*line || *line == '#')
+ continue;
+ if (!adap->ops->error_inj_parse_line(adap, line)) {
+ kfree(buf);
+ return -EINVAL;
+ }
+ }
+ kfree(buf);
+ return count;
+}
+
+static int cec_error_inj_show(struct seq_file *sf, void *unused)
+{
+ struct cec_adapter *adap = sf->private;
+
+ return adap->ops->error_inj_show(adap, sf);
+}
+
+static int cec_error_inj_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cec_error_inj_show, inode->i_private);
+}
+
+static const struct file_operations cec_error_inj_fops = {
+ .open = cec_error_inj_open,
+ .write = cec_error_inj_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#endif
+
struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
void *priv, const char *name, u32 caps,
u8 available_las)
@@ -346,7 +383,16 @@ int cec_register_adapter(struct cec_adapter *adap,
pr_warn("cec-%s: Failed to create status file\n", adap->name);
debugfs_remove_recursive(adap->cec_dir);
adap->cec_dir = NULL;
+ return 0;
}
+ if (!adap->ops->error_inj_show || !adap->ops->error_inj_parse_line)
+ return 0;
+ adap->error_inj_file = debugfs_create_file("error-inj", 0644,
+ adap->cec_dir, adap,
+ &cec_error_inj_fops);
+ if (IS_ERR_OR_NULL(adap->error_inj_file))
+ pr_warn("cec-%s: Failed to create error-inj file\n",
+ adap->name);
#endif
return 0;
}
diff --git a/drivers/media/cec/cec-edid.c b/drivers/media/cec/cec-edid.c
index 38e3fec6152b..ec72ac1c0b91 100644
--- a/drivers/media/cec/cec-edid.c
+++ b/drivers/media/cec/cec-edid.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cec-edid - HDMI Consumer Electronics Control EDID & CEC helper functions
*
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/module.h>
diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c
index 08b619d0ea1e..16dffa06c913 100644
--- a/drivers/media/cec/cec-notifier.c
+++ b/drivers/media/cec/cec-notifier.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cec-notifier.c - notify CEC drivers of physical address changes
*
* Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk>
* Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/export.h>
diff --git a/drivers/media/cec/cec-pin-error-inj.c b/drivers/media/cec/cec-pin-error-inj.c
new file mode 100644
index 000000000000..aaa899a175ce
--- /dev/null
+++ b/drivers/media/cec/cec-pin-error-inj.c
@@ -0,0 +1,342 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ */
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/sched/types.h>
+
+#include <media/cec-pin.h>
+#include "cec-pin-priv.h"
+
+struct cec_error_inj_cmd {
+ unsigned int mode_offset;
+ int arg_idx;
+ const char *cmd;
+};
+
+static const struct cec_error_inj_cmd cec_error_inj_cmds[] = {
+ { CEC_ERROR_INJ_RX_NACK_OFFSET, -1, "rx-nack" },
+ { CEC_ERROR_INJ_RX_LOW_DRIVE_OFFSET,
+ CEC_ERROR_INJ_RX_LOW_DRIVE_ARG_IDX, "rx-low-drive" },
+ { CEC_ERROR_INJ_RX_ADD_BYTE_OFFSET, -1, "rx-add-byte" },
+ { CEC_ERROR_INJ_RX_REMOVE_BYTE_OFFSET, -1, "rx-remove-byte" },
+ { CEC_ERROR_INJ_RX_ARB_LOST_OFFSET,
+ CEC_ERROR_INJ_RX_ARB_LOST_ARG_IDX, "rx-arb-lost" },
+
+ { CEC_ERROR_INJ_TX_NO_EOM_OFFSET, -1, "tx-no-eom" },
+ { CEC_ERROR_INJ_TX_EARLY_EOM_OFFSET, -1, "tx-early-eom" },
+ { CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET,
+ CEC_ERROR_INJ_TX_ADD_BYTES_ARG_IDX, "tx-add-bytes" },
+ { CEC_ERROR_INJ_TX_REMOVE_BYTE_OFFSET, -1, "tx-remove-byte" },
+ { CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET,
+ CEC_ERROR_INJ_TX_SHORT_BIT_ARG_IDX, "tx-short-bit" },
+ { CEC_ERROR_INJ_TX_LONG_BIT_OFFSET,
+ CEC_ERROR_INJ_TX_LONG_BIT_ARG_IDX, "tx-long-bit" },
+ { CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET,
+ CEC_ERROR_INJ_TX_CUSTOM_BIT_ARG_IDX, "tx-custom-bit" },
+ { CEC_ERROR_INJ_TX_SHORT_START_OFFSET, -1, "tx-short-start" },
+ { CEC_ERROR_INJ_TX_LONG_START_OFFSET, -1, "tx-long-start" },
+ { CEC_ERROR_INJ_TX_CUSTOM_START_OFFSET, -1, "tx-custom-start" },
+ { CEC_ERROR_INJ_TX_LAST_BIT_OFFSET,
+ CEC_ERROR_INJ_TX_LAST_BIT_ARG_IDX, "tx-last-bit" },
+ { CEC_ERROR_INJ_TX_LOW_DRIVE_OFFSET,
+ CEC_ERROR_INJ_TX_LOW_DRIVE_ARG_IDX, "tx-low-drive" },
+ { 0, -1, NULL }
+};
+
+u16 cec_pin_rx_error_inj(struct cec_pin *pin)
+{
+ u16 cmd = CEC_ERROR_INJ_OP_ANY;
+
+ /* Only when 18 bits have been received do we have a valid cmd */
+ if (!(pin->error_inj[cmd] & CEC_ERROR_INJ_RX_MASK) &&
+ pin->rx_bit >= 18)
+ cmd = pin->rx_msg.msg[1];
+ return (pin->error_inj[cmd] & CEC_ERROR_INJ_RX_MASK) ? cmd :
+ CEC_ERROR_INJ_OP_ANY;
+}
+
+u16 cec_pin_tx_error_inj(struct cec_pin *pin)
+{
+ u16 cmd = CEC_ERROR_INJ_OP_ANY;
+
+ if (!(pin->error_inj[cmd] & CEC_ERROR_INJ_TX_MASK) &&
+ pin->tx_msg.len > 1)
+ cmd = pin->tx_msg.msg[1];
+ return (pin->error_inj[cmd] & CEC_ERROR_INJ_TX_MASK) ? cmd :
+ CEC_ERROR_INJ_OP_ANY;
+}
+
+bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line)
+{
+ static const char *delims = " \t\r";
+ struct cec_pin *pin = adap->pin;
+ unsigned int i;
+ bool has_pos = false;
+ char *p = line;
+ char *token;
+ char *comma;
+ u64 *error;
+ u8 *args;
+ bool has_op;
+ u32 op;
+ u8 mode;
+ u8 pos;
+ u8 v;
+
+ p = skip_spaces(p);
+ token = strsep(&p, delims);
+ if (!strcmp(token, "clear")) {
+ memset(pin->error_inj, 0, sizeof(pin->error_inj));
+ pin->rx_toggle = pin->tx_toggle = false;
+ pin->tx_ignore_nack_until_eom = false;
+ pin->tx_custom_pulse = false;
+ pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT;
+ pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT;
+ return true;
+ }
+ if (!strcmp(token, "rx-clear")) {
+ for (i = 0; i <= CEC_ERROR_INJ_OP_ANY; i++)
+ pin->error_inj[i] &= ~CEC_ERROR_INJ_RX_MASK;
+ pin->rx_toggle = false;
+ return true;
+ }
+ if (!strcmp(token, "tx-clear")) {
+ for (i = 0; i <= CEC_ERROR_INJ_OP_ANY; i++)
+ pin->error_inj[i] &= ~CEC_ERROR_INJ_TX_MASK;
+ pin->tx_toggle = false;
+ pin->tx_ignore_nack_until_eom = false;
+ pin->tx_custom_pulse = false;
+ pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT;
+ pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT;
+ return true;
+ }
+ if (!strcmp(token, "tx-ignore-nack-until-eom")) {
+ pin->tx_ignore_nack_until_eom = true;
+ return true;
+ }
+ if (!strcmp(token, "tx-custom-pulse")) {
+ pin->tx_custom_pulse = true;
+ cec_pin_start_timer(pin);
+ return true;
+ }
+ if (!p)
+ return false;
+
+ p = skip_spaces(p);
+ if (!strcmp(token, "tx-custom-low-usecs")) {
+ u32 usecs;
+
+ if (kstrtou32(p, 0, &usecs) || usecs > 10000000)
+ return false;
+ pin->tx_custom_low_usecs = usecs;
+ return true;
+ }
+ if (!strcmp(token, "tx-custom-high-usecs")) {
+ u32 usecs;
+
+ if (kstrtou32(p, 0, &usecs) || usecs > 10000000)
+ return false;
+ pin->tx_custom_high_usecs = usecs;
+ return true;
+ }
+
+ comma = strchr(token, ',');
+ if (comma)
+ *comma++ = '\0';
+ if (!strcmp(token, "any"))
+ op = CEC_ERROR_INJ_OP_ANY;
+ else if (!kstrtou8(token, 0, &v))
+ op = v;
+ else
+ return false;
+ mode = CEC_ERROR_INJ_MODE_ONCE;
+ if (comma) {
+ if (!strcmp(comma, "off"))
+ mode = CEC_ERROR_INJ_MODE_OFF;
+ else if (!strcmp(comma, "once"))
+ mode = CEC_ERROR_INJ_MODE_ONCE;
+ else if (!strcmp(comma, "always"))
+ mode = CEC_ERROR_INJ_MODE_ALWAYS;
+ else if (!strcmp(comma, "toggle"))
+ mode = CEC_ERROR_INJ_MODE_TOGGLE;
+ else
+ return false;
+ }
+
+ error = pin->error_inj + op;
+ args = pin->error_inj_args[op];
+ has_op = op <= 0xff;
+
+ token = strsep(&p, delims);
+ if (p) {
+ p = skip_spaces(p);
+ has_pos = !kstrtou8(p, 0, &pos);
+ }
+
+ if (!strcmp(token, "clear")) {
+ *error = 0;
+ return true;
+ }
+ if (!strcmp(token, "rx-clear")) {
+ *error &= ~CEC_ERROR_INJ_RX_MASK;
+ return true;
+ }
+ if (!strcmp(token, "tx-clear")) {
+ *error &= ~CEC_ERROR_INJ_TX_MASK;
+ return true;
+ }
+
+ for (i = 0; cec_error_inj_cmds[i].cmd; i++) {
+ const char *cmd = cec_error_inj_cmds[i].cmd;
+ unsigned int mode_offset;
+ u64 mode_mask;
+ int arg_idx;
+ bool is_bit_pos = true;
+
+ if (strcmp(token, cmd))
+ continue;
+
+ mode_offset = cec_error_inj_cmds[i].mode_offset;
+ mode_mask = CEC_ERROR_INJ_MODE_MASK << mode_offset;
+ arg_idx = cec_error_inj_cmds[i].arg_idx;
+
+ if (mode_offset == CEC_ERROR_INJ_RX_ARB_LOST_OFFSET ||
+ mode_offset == CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET)
+ is_bit_pos = false;
+
+ if (mode_offset == CEC_ERROR_INJ_RX_ARB_LOST_OFFSET) {
+ if (has_op)
+ return false;
+ if (!has_pos)
+ pos = 0x0f;
+ }
+ if (arg_idx >= 0 && is_bit_pos) {
+ if (!has_pos || pos >= 160)
+ return false;
+ if (has_op && pos < 10 + 8)
+ return false;
+ /* Invalid bit position may not be the Ack bit */
+ if ((mode_offset == CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET ||
+ mode_offset == CEC_ERROR_INJ_TX_LONG_BIT_OFFSET ||
+ mode_offset == CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET) &&
+ (pos % 10) == 9)
+ return false;
+ }
+ *error &= ~mode_mask;
+ *error |= (u64)mode << mode_offset;
+ if (arg_idx >= 0)
+ args[arg_idx] = pos;
+ return true;
+ }
+ return false;
+}
+
+static void cec_pin_show_cmd(struct seq_file *sf, u32 cmd, u8 mode)
+{
+ if (cmd == CEC_ERROR_INJ_OP_ANY)
+ seq_puts(sf, "any,");
+ else
+ seq_printf(sf, "0x%02x,", cmd);
+ switch (mode) {
+ case CEC_ERROR_INJ_MODE_ONCE:
+ seq_puts(sf, "once ");
+ break;
+ case CEC_ERROR_INJ_MODE_ALWAYS:
+ seq_puts(sf, "always ");
+ break;
+ case CEC_ERROR_INJ_MODE_TOGGLE:
+ seq_puts(sf, "toggle ");
+ break;
+ default:
+ seq_puts(sf, "off ");
+ break;
+ }
+}
+
+int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf)
+{
+ struct cec_pin *pin = adap->pin;
+ unsigned int i, j;
+
+ seq_puts(sf, "# Clear error injections:\n");
+ seq_puts(sf, "# clear clear all rx and tx error injections\n");
+ seq_puts(sf, "# rx-clear clear all rx error injections\n");
+ seq_puts(sf, "# tx-clear clear all tx error injections\n");
+ seq_puts(sf, "# <op> clear clear all rx and tx error injections for <op>\n");
+ seq_puts(sf, "# <op> rx-clear clear all rx error injections for <op>\n");
+ seq_puts(sf, "# <op> tx-clear clear all tx error injections for <op>\n");
+ seq_puts(sf, "#\n");
+ seq_puts(sf, "# RX error injection:\n");
+ seq_puts(sf, "# <op>[,<mode>] rx-nack NACK the message instead of sending an ACK\n");
+ seq_puts(sf, "# <op>[,<mode>] rx-low-drive <bit> force a low-drive condition at this bit position\n");
+ seq_puts(sf, "# <op>[,<mode>] rx-add-byte add a spurious byte to the received CEC message\n");
+ seq_puts(sf, "# <op>[,<mode>] rx-remove-byte remove the last byte from the received CEC message\n");
+ seq_puts(sf, "# <op>[,<mode>] rx-arb-lost <poll> generate a POLL message to trigger an arbitration lost\n");
+ seq_puts(sf, "#\n");
+ seq_puts(sf, "# TX error injection settings:\n");
+ seq_puts(sf, "# tx-ignore-nack-until-eom ignore early NACKs until EOM\n");
+ seq_puts(sf, "# tx-custom-low-usecs <usecs> define the 'low' time for the custom pulse\n");
+ seq_puts(sf, "# tx-custom-high-usecs <usecs> define the 'high' time for the custom pulse\n");
+ seq_puts(sf, "# tx-custom-pulse transmit the custom pulse once the bus is idle\n");
+ seq_puts(sf, "#\n");
+ seq_puts(sf, "# TX error injection:\n");
+ seq_puts(sf, "# <op>[,<mode>] tx-no-eom don't set the EOM bit\n");
+ seq_puts(sf, "# <op>[,<mode>] tx-early-eom set the EOM bit one byte too soon\n");
+ seq_puts(sf, "# <op>[,<mode>] tx-add-bytes <num> append <num> (1-255) spurious bytes to the message\n");
+ seq_puts(sf, "# <op>[,<mode>] tx-remove-byte drop the last byte from the message\n");
+ seq_puts(sf, "# <op>[,<mode>] tx-short-bit <bit> make this bit shorter than allowed\n");
+ seq_puts(sf, "# <op>[,<mode>] tx-long-bit <bit> make this bit longer than allowed\n");
+ seq_puts(sf, "# <op>[,<mode>] tx-custom-bit <bit> send the custom pulse instead of this bit\n");
+ seq_puts(sf, "# <op>[,<mode>] tx-short-start send a start pulse that's too short\n");
+ seq_puts(sf, "# <op>[,<mode>] tx-long-start send a start pulse that's too long\n");
+ seq_puts(sf, "# <op>[,<mode>] tx-custom-start send the custom pulse instead of the start pulse\n");
+ seq_puts(sf, "# <op>[,<mode>] tx-last-bit <bit> stop sending after this bit\n");
+ seq_puts(sf, "# <op>[,<mode>] tx-low-drive <bit> force a low-drive condition at this bit position\n");
+ seq_puts(sf, "#\n");
+ seq_puts(sf, "# <op> CEC message opcode (0-255) or 'any'\n");
+ seq_puts(sf, "# <mode> 'once' (default), 'always', 'toggle' or 'off'\n");
+ seq_puts(sf, "# <bit> CEC message bit (0-159)\n");
+ seq_puts(sf, "# 10 bits per 'byte': bits 0-7: data, bit 8: EOM, bit 9: ACK\n");
+ seq_puts(sf, "# <poll> CEC poll message used to test arbitration lost (0x00-0xff, default 0x0f)\n");
+ seq_puts(sf, "# <usecs> microseconds (0-10000000, default 1000)\n");
+
+ seq_puts(sf, "\nclear\n");
+
+ for (i = 0; i < ARRAY_SIZE(pin->error_inj); i++) {
+ u64 e = pin->error_inj[i];
+
+ for (j = 0; cec_error_inj_cmds[j].cmd; j++) {
+ const char *cmd = cec_error_inj_cmds[j].cmd;
+ unsigned int mode;
+ unsigned int mode_offset;
+ int arg_idx;
+
+ mode_offset = cec_error_inj_cmds[j].mode_offset;
+ arg_idx = cec_error_inj_cmds[j].arg_idx;
+ mode = (e >> mode_offset) & CEC_ERROR_INJ_MODE_MASK;
+ if (!mode)
+ continue;
+ cec_pin_show_cmd(sf, i, mode);
+ seq_puts(sf, cmd);
+ if (arg_idx >= 0)
+ seq_printf(sf, " %u",
+ pin->error_inj_args[i][arg_idx]);
+ seq_puts(sf, "\n");
+ }
+ }
+
+ if (pin->tx_ignore_nack_until_eom)
+ seq_puts(sf, "tx-ignore-nack-until-eom\n");
+ if (pin->tx_custom_pulse)
+ seq_puts(sf, "tx-custom-pulse\n");
+ if (pin->tx_custom_low_usecs != CEC_TIM_CUSTOM_DEFAULT)
+ seq_printf(sf, "tx-custom-low-usecs %u\n",
+ pin->tx_custom_low_usecs);
+ if (pin->tx_custom_high_usecs != CEC_TIM_CUSTOM_DEFAULT)
+ seq_printf(sf, "tx-custom-high-usecs %u\n",
+ pin->tx_custom_high_usecs);
+ return 0;
+}
diff --git a/drivers/media/cec/cec-pin-priv.h b/drivers/media/cec/cec-pin-priv.h
index 7d0def199762..f423db8855d9 100644
--- a/drivers/media/cec/cec-pin-priv.h
+++ b/drivers/media/cec/cec-pin-priv.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cec-pin-priv.h - internal cec-pin header
*
* Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef LINUX_CEC_PIN_PRIV_H
@@ -40,14 +28,30 @@ enum cec_pin_state {
CEC_ST_TX_START_BIT_LOW,
/* Drive CEC high for the start bit */
CEC_ST_TX_START_BIT_HIGH,
+ /* Generate a start bit period that is too short */
+ CEC_ST_TX_START_BIT_HIGH_SHORT,
+ /* Generate a start bit period that is too long */
+ CEC_ST_TX_START_BIT_HIGH_LONG,
+ /* Drive CEC low for the start bit using the custom timing */
+ CEC_ST_TX_START_BIT_LOW_CUSTOM,
+ /* Drive CEC high for the start bit using the custom timing */
+ CEC_ST_TX_START_BIT_HIGH_CUSTOM,
/* Drive CEC low for the 0 bit */
CEC_ST_TX_DATA_BIT_0_LOW,
/* Drive CEC high for the 0 bit */
CEC_ST_TX_DATA_BIT_0_HIGH,
+ /* Generate a bit period that is too short */
+ CEC_ST_TX_DATA_BIT_0_HIGH_SHORT,
+ /* Generate a bit period that is too long */
+ CEC_ST_TX_DATA_BIT_0_HIGH_LONG,
/* Drive CEC low for the 1 bit */
CEC_ST_TX_DATA_BIT_1_LOW,
/* Drive CEC high for the 1 bit */
CEC_ST_TX_DATA_BIT_1_HIGH,
+ /* Generate a bit period that is too short */
+ CEC_ST_TX_DATA_BIT_1_HIGH_SHORT,
+ /* Generate a bit period that is too long */
+ CEC_ST_TX_DATA_BIT_1_HIGH_LONG,
/*
* Wait for start of sample time to check for Ack bit or first
* four initiator bits to check for Arbitration Lost.
@@ -55,6 +59,20 @@ enum cec_pin_state {
CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE,
/* Wait for end of bit period after sampling */
CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE,
+ /* Generate a bit period that is too short */
+ CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_SHORT,
+ /* Generate a bit period that is too long */
+ CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_LONG,
+ /* Drive CEC low for a data bit using the custom timing */
+ CEC_ST_TX_DATA_BIT_LOW_CUSTOM,
+ /* Drive CEC high for a data bit using the custom timing */
+ CEC_ST_TX_DATA_BIT_HIGH_CUSTOM,
+ /* Drive CEC low for a standalone pulse using the custom timing */
+ CEC_ST_TX_PULSE_LOW_CUSTOM,
+ /* Drive CEC high for a standalone pulse using the custom timing */
+ CEC_ST_TX_PULSE_HIGH_CUSTOM,
+ /* Start low drive */
+ CEC_ST_TX_LOW_DRIVE,
/* Rx states */
@@ -66,8 +84,8 @@ enum cec_pin_state {
CEC_ST_RX_DATA_SAMPLE,
/* Wait for earliest end of bit period after sampling */
CEC_ST_RX_DATA_POST_SAMPLE,
- /* Wait for CEC to go high (i.e. end of bit period */
- CEC_ST_RX_DATA_HIGH,
+ /* Wait for CEC to go low (i.e. end of bit period) */
+ CEC_ST_RX_DATA_WAIT_FOR_LOW,
/* Drive CEC low to send 0 Ack bit */
CEC_ST_RX_ACK_LOW,
/* End of 0 Ack time, wait for earliest end of bit period */
@@ -76,9 +94,9 @@ enum cec_pin_state {
CEC_ST_RX_ACK_HIGH_POST,
/* Wait for earliest end of bit period and end of message */
CEC_ST_RX_ACK_FINISH,
-
/* Start low drive */
- CEC_ST_LOW_DRIVE,
+ CEC_ST_RX_LOW_DRIVE,
+
/* Monitor pin using interrupts */
CEC_ST_RX_IRQ,
@@ -86,7 +104,58 @@ enum cec_pin_state {
CEC_PIN_STATES
};
-#define CEC_NUM_PIN_EVENTS 128
+/* Error Injection */
+
+/* Error injection modes */
+#define CEC_ERROR_INJ_MODE_OFF 0
+#define CEC_ERROR_INJ_MODE_ONCE 1
+#define CEC_ERROR_INJ_MODE_ALWAYS 2
+#define CEC_ERROR_INJ_MODE_TOGGLE 3
+#define CEC_ERROR_INJ_MODE_MASK 3ULL
+
+/* Receive error injection options */
+#define CEC_ERROR_INJ_RX_NACK_OFFSET 0
+#define CEC_ERROR_INJ_RX_LOW_DRIVE_OFFSET 2
+#define CEC_ERROR_INJ_RX_ADD_BYTE_OFFSET 4
+#define CEC_ERROR_INJ_RX_REMOVE_BYTE_OFFSET 6
+#define CEC_ERROR_INJ_RX_ARB_LOST_OFFSET 8
+#define CEC_ERROR_INJ_RX_MASK 0xffffULL
+
+/* Transmit error injection options */
+#define CEC_ERROR_INJ_TX_NO_EOM_OFFSET 16
+#define CEC_ERROR_INJ_TX_EARLY_EOM_OFFSET 18
+#define CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET 20
+#define CEC_ERROR_INJ_TX_LONG_BIT_OFFSET 22
+#define CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET 24
+#define CEC_ERROR_INJ_TX_SHORT_START_OFFSET 26
+#define CEC_ERROR_INJ_TX_LONG_START_OFFSET 28
+#define CEC_ERROR_INJ_TX_CUSTOM_START_OFFSET 30
+#define CEC_ERROR_INJ_TX_LAST_BIT_OFFSET 32
+#define CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET 34
+#define CEC_ERROR_INJ_TX_REMOVE_BYTE_OFFSET 36
+#define CEC_ERROR_INJ_TX_LOW_DRIVE_OFFSET 38
+#define CEC_ERROR_INJ_TX_MASK 0xffffffffffff0000ULL
+
+#define CEC_ERROR_INJ_RX_LOW_DRIVE_ARG_IDX 0
+#define CEC_ERROR_INJ_RX_ARB_LOST_ARG_IDX 1
+
+#define CEC_ERROR_INJ_TX_ADD_BYTES_ARG_IDX 2
+#define CEC_ERROR_INJ_TX_SHORT_BIT_ARG_IDX 3
+#define CEC_ERROR_INJ_TX_LONG_BIT_ARG_IDX 4
+#define CEC_ERROR_INJ_TX_CUSTOM_BIT_ARG_IDX 5
+#define CEC_ERROR_INJ_TX_LAST_BIT_ARG_IDX 6
+#define CEC_ERROR_INJ_TX_LOW_DRIVE_ARG_IDX 7
+#define CEC_ERROR_INJ_NUM_ARGS 8
+
+/* Special CEC op values */
+#define CEC_ERROR_INJ_OP_ANY 0x00000100
+
+/* The default for the low/high time of the custom pulse */
+#define CEC_TIM_CUSTOM_DEFAULT 1000
+
+#define CEC_NUM_PIN_EVENTS 128
+#define CEC_PIN_EVENT_FL_IS_HIGH (1 << 0)
+#define CEC_PIN_EVENT_FL_DROPPED (1 << 1)
#define CEC_PIN_IRQ_UNCHANGED 0
#define CEC_PIN_IRQ_DISABLE 1
@@ -110,24 +179,63 @@ struct cec_pin {
u32 tx_bit;
bool tx_nacked;
u32 tx_signal_free_time;
+ bool tx_toggle;
struct cec_msg rx_msg;
u32 rx_bit;
+ bool rx_toggle;
+ u32 rx_start_bit_low_too_short_cnt;
+ u64 rx_start_bit_low_too_short_ts;
+ u32 rx_start_bit_low_too_short_delta;
+ u32 rx_start_bit_too_short_cnt;
+ u64 rx_start_bit_too_short_ts;
+ u32 rx_start_bit_too_short_delta;
+ u32 rx_start_bit_too_long_cnt;
+ u32 rx_data_bit_too_short_cnt;
+ u64 rx_data_bit_too_short_ts;
+ u32 rx_data_bit_too_short_delta;
+ u32 rx_data_bit_too_long_cnt;
+ u32 rx_low_drive_cnt;
struct cec_msg work_rx_msg;
u8 work_tx_status;
ktime_t work_tx_ts;
atomic_t work_irq_change;
- atomic_t work_pin_events;
+ atomic_t work_pin_num_events;
unsigned int work_pin_events_wr;
unsigned int work_pin_events_rd;
ktime_t work_pin_ts[CEC_NUM_PIN_EVENTS];
- bool work_pin_is_high[CEC_NUM_PIN_EVENTS];
+ u8 work_pin_events[CEC_NUM_PIN_EVENTS];
+ bool work_pin_events_dropped;
+ u32 work_pin_events_dropped_cnt;
ktime_t timer_ts;
u32 timer_cnt;
u32 timer_100ms_overruns;
u32 timer_300ms_overruns;
u32 timer_max_overrun;
u32 timer_sum_overrun;
+
+ u32 tx_custom_low_usecs;
+ u32 tx_custom_high_usecs;
+ bool tx_ignore_nack_until_eom;
+ bool tx_custom_pulse;
+ bool tx_generated_poll;
+ bool tx_post_eom;
+ u8 tx_extra_bytes;
+ u32 tx_low_drive_cnt;
+#ifdef CONFIG_CEC_PIN_ERROR_INJ
+ u64 error_inj[CEC_ERROR_INJ_OP_ANY + 1];
+ u8 error_inj_args[CEC_ERROR_INJ_OP_ANY + 1][CEC_ERROR_INJ_NUM_ARGS];
+#endif
};
+void cec_pin_start_timer(struct cec_pin *pin);
+
+#ifdef CONFIG_CEC_PIN_ERROR_INJ
+bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line);
+int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf);
+
+u16 cec_pin_rx_error_inj(struct cec_pin *pin);
+u16 cec_pin_tx_error_inj(struct cec_pin *pin);
+#endif
+
#endif
diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c
index b48dfe844118..fafe1ebc8aff 100644
--- a/drivers/media/cec/cec-pin.c
+++ b/drivers/media/cec/cec-pin.c
@@ -1,18 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/delay.h>
@@ -51,11 +39,29 @@
#define CEC_TIM_IDLE_SAMPLE 1000
/* when processing the start bit, sample twice per millisecond */
#define CEC_TIM_START_BIT_SAMPLE 500
-/* when polling for a state change, sample once every 50 micoseconds */
+/* when polling for a state change, sample once every 50 microseconds */
#define CEC_TIM_SAMPLE 50
#define CEC_TIM_LOW_DRIVE_ERROR (1.5 * CEC_TIM_DATA_BIT_TOTAL)
+/*
+ * Total data bit time that is too short/long for a valid bit,
+ * used for error injection.
+ */
+#define CEC_TIM_DATA_BIT_TOTAL_SHORT 1800
+#define CEC_TIM_DATA_BIT_TOTAL_LONG 2900
+
+/*
+ * Total start bit time that is too short/long for a valid bit,
+ * used for error injection.
+ */
+#define CEC_TIM_START_BIT_TOTAL_SHORT 4100
+#define CEC_TIM_START_BIT_TOTAL_LONG 5000
+
+/* Data bits are 0-7, EOM is bit 8 and ACK is bit 9 */
+#define EOM_BIT 8
+#define ACK_BIT 9
+
struct cec_state {
const char * const name;
unsigned int usecs;
@@ -68,17 +74,32 @@ static const struct cec_state states[CEC_PIN_STATES] = {
{ "Tx Wait for High", CEC_TIM_IDLE_SAMPLE },
{ "Tx Start Bit Low", CEC_TIM_START_BIT_LOW },
{ "Tx Start Bit High", CEC_TIM_START_BIT_TOTAL - CEC_TIM_START_BIT_LOW },
+ { "Tx Start Bit High Short", CEC_TIM_START_BIT_TOTAL_SHORT - CEC_TIM_START_BIT_LOW },
+ { "Tx Start Bit High Long", CEC_TIM_START_BIT_TOTAL_LONG - CEC_TIM_START_BIT_LOW },
+ { "Tx Start Bit Low Custom", 0 },
+ { "Tx Start Bit High Custom", 0 },
{ "Tx Data 0 Low", CEC_TIM_DATA_BIT_0_LOW },
{ "Tx Data 0 High", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_0_LOW },
+ { "Tx Data 0 High Short", CEC_TIM_DATA_BIT_TOTAL_SHORT - CEC_TIM_DATA_BIT_0_LOW },
+ { "Tx Data 0 High Long", CEC_TIM_DATA_BIT_TOTAL_LONG - CEC_TIM_DATA_BIT_0_LOW },
{ "Tx Data 1 Low", CEC_TIM_DATA_BIT_1_LOW },
{ "Tx Data 1 High", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_1_LOW },
- { "Tx Data 1 Pre Sample", CEC_TIM_DATA_BIT_SAMPLE - CEC_TIM_DATA_BIT_1_LOW },
- { "Tx Data 1 Post Sample", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_SAMPLE },
+ { "Tx Data 1 High Short", CEC_TIM_DATA_BIT_TOTAL_SHORT - CEC_TIM_DATA_BIT_1_LOW },
+ { "Tx Data 1 High Long", CEC_TIM_DATA_BIT_TOTAL_LONG - CEC_TIM_DATA_BIT_1_LOW },
+ { "Tx Data 1 High Pre Sample", CEC_TIM_DATA_BIT_SAMPLE - CEC_TIM_DATA_BIT_1_LOW },
+ { "Tx Data 1 High Post Sample", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_SAMPLE },
+ { "Tx Data 1 High Post Sample Short", CEC_TIM_DATA_BIT_TOTAL_SHORT - CEC_TIM_DATA_BIT_SAMPLE },
+ { "Tx Data 1 High Post Sample Long", CEC_TIM_DATA_BIT_TOTAL_LONG - CEC_TIM_DATA_BIT_SAMPLE },
+ { "Tx Data Bit Low Custom", 0 },
+ { "Tx Data Bit High Custom", 0 },
+ { "Tx Pulse Low Custom", 0 },
+ { "Tx Pulse High Custom", 0 },
+ { "Tx Low Drive", CEC_TIM_LOW_DRIVE_ERROR },
{ "Rx Start Bit Low", CEC_TIM_SAMPLE },
{ "Rx Start Bit High", CEC_TIM_SAMPLE },
{ "Rx Data Sample", CEC_TIM_DATA_BIT_SAMPLE },
{ "Rx Data Post Sample", CEC_TIM_DATA_BIT_HIGH - CEC_TIM_DATA_BIT_SAMPLE },
- { "Rx Data High", CEC_TIM_SAMPLE },
+ { "Rx Data Wait for Low", CEC_TIM_SAMPLE },
{ "Rx Ack Low", CEC_TIM_DATA_BIT_0_LOW },
{ "Rx Ack Low Post", CEC_TIM_DATA_BIT_HIGH - CEC_TIM_DATA_BIT_0_LOW },
{ "Rx Ack High Post", CEC_TIM_DATA_BIT_HIGH },
@@ -93,12 +114,21 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force)
return;
pin->adap->cec_pin_is_high = v;
- if (atomic_read(&pin->work_pin_events) < CEC_NUM_PIN_EVENTS) {
- pin->work_pin_is_high[pin->work_pin_events_wr] = v;
+ if (atomic_read(&pin->work_pin_num_events) < CEC_NUM_PIN_EVENTS) {
+ u8 ev = v;
+
+ if (pin->work_pin_events_dropped) {
+ pin->work_pin_events_dropped = false;
+ v |= CEC_PIN_EVENT_FL_DROPPED;
+ }
+ pin->work_pin_events[pin->work_pin_events_wr] = ev;
pin->work_pin_ts[pin->work_pin_events_wr] = ktime_get();
pin->work_pin_events_wr =
(pin->work_pin_events_wr + 1) % CEC_NUM_PIN_EVENTS;
- atomic_inc(&pin->work_pin_events);
+ atomic_inc(&pin->work_pin_num_events);
+ } else {
+ pin->work_pin_events_dropped = true;
+ pin->work_pin_events_dropped_cnt++;
}
wake_up_interruptible(&pin->kthread_waitq);
}
@@ -123,6 +153,173 @@ static bool cec_pin_high(struct cec_pin *pin)
return cec_pin_read(pin);
}
+static bool rx_error_inj(struct cec_pin *pin, unsigned int mode_offset,
+ int arg_idx, u8 *arg)
+{
+#ifdef CONFIG_CEC_PIN_ERROR_INJ
+ u16 cmd = cec_pin_rx_error_inj(pin);
+ u64 e = pin->error_inj[cmd];
+ unsigned int mode = (e >> mode_offset) & CEC_ERROR_INJ_MODE_MASK;
+
+ if (arg_idx >= 0) {
+ u8 pos = pin->error_inj_args[cmd][arg_idx];
+
+ if (arg)
+ *arg = pos;
+ else if (pos != pin->rx_bit)
+ return false;
+ }
+
+ switch (mode) {
+ case CEC_ERROR_INJ_MODE_ONCE:
+ pin->error_inj[cmd] &=
+ ~(CEC_ERROR_INJ_MODE_MASK << mode_offset);
+ return true;
+ case CEC_ERROR_INJ_MODE_ALWAYS:
+ return true;
+ case CEC_ERROR_INJ_MODE_TOGGLE:
+ return pin->rx_toggle;
+ default:
+ return false;
+ }
+#else
+ return false;
+#endif
+}
+
+static bool rx_nack(struct cec_pin *pin)
+{
+ return rx_error_inj(pin, CEC_ERROR_INJ_RX_NACK_OFFSET, -1, NULL);
+}
+
+static bool rx_low_drive(struct cec_pin *pin)
+{
+ return rx_error_inj(pin, CEC_ERROR_INJ_RX_LOW_DRIVE_OFFSET,
+ CEC_ERROR_INJ_RX_LOW_DRIVE_ARG_IDX, NULL);
+}
+
+static bool rx_add_byte(struct cec_pin *pin)
+{
+ return rx_error_inj(pin, CEC_ERROR_INJ_RX_ADD_BYTE_OFFSET, -1, NULL);
+}
+
+static bool rx_remove_byte(struct cec_pin *pin)
+{
+ return rx_error_inj(pin, CEC_ERROR_INJ_RX_REMOVE_BYTE_OFFSET, -1, NULL);
+}
+
+static bool rx_arb_lost(struct cec_pin *pin, u8 *poll)
+{
+ return pin->tx_msg.len == 0 &&
+ rx_error_inj(pin, CEC_ERROR_INJ_RX_ARB_LOST_OFFSET,
+ CEC_ERROR_INJ_RX_ARB_LOST_ARG_IDX, poll);
+}
+
+static bool tx_error_inj(struct cec_pin *pin, unsigned int mode_offset,
+ int arg_idx, u8 *arg)
+{
+#ifdef CONFIG_CEC_PIN_ERROR_INJ
+ u16 cmd = cec_pin_tx_error_inj(pin);
+ u64 e = pin->error_inj[cmd];
+ unsigned int mode = (e >> mode_offset) & CEC_ERROR_INJ_MODE_MASK;
+
+ if (arg_idx >= 0) {
+ u8 pos = pin->error_inj_args[cmd][arg_idx];
+
+ if (arg)
+ *arg = pos;
+ else if (pos != pin->tx_bit)
+ return false;
+ }
+
+ switch (mode) {
+ case CEC_ERROR_INJ_MODE_ONCE:
+ pin->error_inj[cmd] &=
+ ~(CEC_ERROR_INJ_MODE_MASK << mode_offset);
+ return true;
+ case CEC_ERROR_INJ_MODE_ALWAYS:
+ return true;
+ case CEC_ERROR_INJ_MODE_TOGGLE:
+ return pin->tx_toggle;
+ default:
+ return false;
+ }
+#else
+ return false;
+#endif
+}
+
+static bool tx_no_eom(struct cec_pin *pin)
+{
+ return tx_error_inj(pin, CEC_ERROR_INJ_TX_NO_EOM_OFFSET, -1, NULL);
+}
+
+static bool tx_early_eom(struct cec_pin *pin)
+{
+ return tx_error_inj(pin, CEC_ERROR_INJ_TX_EARLY_EOM_OFFSET, -1, NULL);
+}
+
+static bool tx_short_bit(struct cec_pin *pin)
+{
+ return tx_error_inj(pin, CEC_ERROR_INJ_TX_SHORT_BIT_OFFSET,
+ CEC_ERROR_INJ_TX_SHORT_BIT_ARG_IDX, NULL);
+}
+
+static bool tx_long_bit(struct cec_pin *pin)
+{
+ return tx_error_inj(pin, CEC_ERROR_INJ_TX_LONG_BIT_OFFSET,
+ CEC_ERROR_INJ_TX_LONG_BIT_ARG_IDX, NULL);
+}
+
+static bool tx_custom_bit(struct cec_pin *pin)
+{
+ return tx_error_inj(pin, CEC_ERROR_INJ_TX_CUSTOM_BIT_OFFSET,
+ CEC_ERROR_INJ_TX_CUSTOM_BIT_ARG_IDX, NULL);
+}
+
+static bool tx_short_start(struct cec_pin *pin)
+{
+ return tx_error_inj(pin, CEC_ERROR_INJ_TX_SHORT_START_OFFSET, -1, NULL);
+}
+
+static bool tx_long_start(struct cec_pin *pin)
+{
+ return tx_error_inj(pin, CEC_ERROR_INJ_TX_LONG_START_OFFSET, -1, NULL);
+}
+
+static bool tx_custom_start(struct cec_pin *pin)
+{
+ return tx_error_inj(pin, CEC_ERROR_INJ_TX_CUSTOM_START_OFFSET,
+ -1, NULL);
+}
+
+static bool tx_last_bit(struct cec_pin *pin)
+{
+ return tx_error_inj(pin, CEC_ERROR_INJ_TX_LAST_BIT_OFFSET,
+ CEC_ERROR_INJ_TX_LAST_BIT_ARG_IDX, NULL);
+}
+
+static u8 tx_add_bytes(struct cec_pin *pin)
+{
+ u8 bytes;
+
+ if (tx_error_inj(pin, CEC_ERROR_INJ_TX_ADD_BYTES_OFFSET,
+ CEC_ERROR_INJ_TX_ADD_BYTES_ARG_IDX, &bytes))
+ return bytes;
+ return 0;
+}
+
+static bool tx_remove_byte(struct cec_pin *pin)
+{
+ return tx_error_inj(pin, CEC_ERROR_INJ_TX_REMOVE_BYTE_OFFSET, -1, NULL);
+}
+
+static bool tx_low_drive(struct cec_pin *pin)
+{
+ return tx_error_inj(pin, CEC_ERROR_INJ_TX_LOW_DRIVE_OFFSET,
+ CEC_ERROR_INJ_TX_LOW_DRIVE_ARG_IDX, NULL);
+}
+
static void cec_pin_to_idle(struct cec_pin *pin)
{
/*
@@ -132,8 +329,16 @@ static void cec_pin_to_idle(struct cec_pin *pin)
pin->rx_bit = pin->tx_bit = 0;
pin->rx_msg.len = 0;
memset(pin->rx_msg.msg, 0, sizeof(pin->rx_msg.msg));
- pin->state = CEC_ST_IDLE;
pin->ts = ns_to_ktime(0);
+ pin->tx_generated_poll = false;
+ pin->tx_post_eom = false;
+ if (pin->state >= CEC_ST_TX_WAIT &&
+ pin->state <= CEC_ST_TX_LOW_DRIVE)
+ pin->tx_toggle ^= 1;
+ if (pin->state >= CEC_ST_RX_START_BIT_LOW &&
+ pin->state <= CEC_ST_RX_LOW_DRIVE)
+ pin->rx_toggle ^= 1;
+ pin->state = CEC_ST_IDLE;
}
/*
@@ -174,42 +379,109 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts)
break;
case CEC_ST_TX_START_BIT_LOW:
- pin->state = CEC_ST_TX_START_BIT_HIGH;
+ if (tx_short_start(pin)) {
+ /*
+ * Error Injection: send an invalid (too short)
+ * start pulse.
+ */
+ pin->state = CEC_ST_TX_START_BIT_HIGH_SHORT;
+ } else if (tx_long_start(pin)) {
+ /*
+ * Error Injection: send an invalid (too long)
+ * start pulse.
+ */
+ pin->state = CEC_ST_TX_START_BIT_HIGH_LONG;
+ } else {
+ pin->state = CEC_ST_TX_START_BIT_HIGH;
+ }
+ /* Generate start bit */
+ cec_pin_high(pin);
+ break;
+
+ case CEC_ST_TX_START_BIT_LOW_CUSTOM:
+ pin->state = CEC_ST_TX_START_BIT_HIGH_CUSTOM;
/* Generate start bit */
cec_pin_high(pin);
break;
case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE:
- /* If the read value is 1, then all is OK */
- if (!cec_pin_read(pin)) {
+ case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_SHORT:
+ case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_LONG:
+ if (pin->tx_nacked) {
+ cec_pin_to_idle(pin);
+ pin->tx_msg.len = 0;
+ if (pin->tx_generated_poll)
+ break;
+ pin->work_tx_ts = ts;
+ pin->work_tx_status = CEC_TX_STATUS_NACK;
+ wake_up_interruptible(&pin->kthread_waitq);
+ break;
+ }
+ /* fall through */
+ case CEC_ST_TX_DATA_BIT_0_HIGH:
+ case CEC_ST_TX_DATA_BIT_0_HIGH_SHORT:
+ case CEC_ST_TX_DATA_BIT_0_HIGH_LONG:
+ case CEC_ST_TX_DATA_BIT_1_HIGH:
+ case CEC_ST_TX_DATA_BIT_1_HIGH_SHORT:
+ case CEC_ST_TX_DATA_BIT_1_HIGH_LONG:
+ /*
+ * If the read value is 1, then all is OK, otherwise we have a
+ * low drive condition.
+ *
+ * Special case: when we generate a poll message due to an
+ * Arbitration Lost error injection, then ignore this since
+ * the pin can actually be low in that case.
+ */
+ if (!cec_pin_read(pin) && !pin->tx_generated_poll) {
/*
* It's 0, so someone detected an error and pulled the
* line low for 1.5 times the nominal bit period.
*/
pin->tx_msg.len = 0;
+ pin->state = CEC_ST_TX_WAIT_FOR_HIGH;
pin->work_tx_ts = ts;
pin->work_tx_status = CEC_TX_STATUS_LOW_DRIVE;
- pin->state = CEC_ST_TX_WAIT_FOR_HIGH;
+ pin->tx_low_drive_cnt++;
wake_up_interruptible(&pin->kthread_waitq);
break;
}
- if (pin->tx_nacked) {
+ /* fall through */
+ case CEC_ST_TX_DATA_BIT_HIGH_CUSTOM:
+ if (tx_last_bit(pin)) {
+ /* Error Injection: just stop sending after this bit */
cec_pin_to_idle(pin);
pin->tx_msg.len = 0;
+ if (pin->tx_generated_poll)
+ break;
pin->work_tx_ts = ts;
- pin->work_tx_status = CEC_TX_STATUS_NACK;
+ pin->work_tx_status = CEC_TX_STATUS_OK;
wake_up_interruptible(&pin->kthread_waitq);
break;
}
- /* fall through */
- case CEC_ST_TX_DATA_BIT_0_HIGH:
- case CEC_ST_TX_DATA_BIT_1_HIGH:
pin->tx_bit++;
/* fall through */
case CEC_ST_TX_START_BIT_HIGH:
- if (pin->tx_bit / 10 >= pin->tx_msg.len) {
+ case CEC_ST_TX_START_BIT_HIGH_SHORT:
+ case CEC_ST_TX_START_BIT_HIGH_LONG:
+ case CEC_ST_TX_START_BIT_HIGH_CUSTOM:
+ if (tx_low_drive(pin)) {
+ /* Error injection: go to low drive */
+ cec_pin_low(pin);
+ pin->state = CEC_ST_TX_LOW_DRIVE;
+ pin->tx_msg.len = 0;
+ if (pin->tx_generated_poll)
+ break;
+ pin->work_tx_ts = ts;
+ pin->work_tx_status = CEC_TX_STATUS_LOW_DRIVE;
+ pin->tx_low_drive_cnt++;
+ wake_up_interruptible(&pin->kthread_waitq);
+ break;
+ }
+ if (pin->tx_bit / 10 >= pin->tx_msg.len + pin->tx_extra_bytes) {
cec_pin_to_idle(pin);
pin->tx_msg.len = 0;
+ if (pin->tx_generated_poll)
+ break;
pin->work_tx_ts = ts;
pin->work_tx_status = CEC_TX_STATUS_OK;
wake_up_interruptible(&pin->kthread_waitq);
@@ -217,39 +489,82 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts)
}
switch (pin->tx_bit % 10) {
- default:
- v = pin->tx_msg.msg[pin->tx_bit / 10] &
- (1 << (7 - (pin->tx_bit % 10)));
+ default: {
+ /*
+ * In the CEC_ERROR_INJ_TX_ADD_BYTES case we transmit
+ * extra bytes, so pin->tx_bit / 10 can become >= 16.
+ * Generate bit values for those extra bytes instead
+ * of reading them from the transmit buffer.
+ */
+ unsigned int idx = (pin->tx_bit / 10);
+ u8 val = idx;
+
+ if (idx < pin->tx_msg.len)
+ val = pin->tx_msg.msg[idx];
+ v = val & (1 << (7 - (pin->tx_bit % 10)));
+
pin->state = v ? CEC_ST_TX_DATA_BIT_1_LOW :
- CEC_ST_TX_DATA_BIT_0_LOW;
+ CEC_ST_TX_DATA_BIT_0_LOW;
break;
- case 8:
- v = pin->tx_bit / 10 == pin->tx_msg.len - 1;
+ }
+ case EOM_BIT: {
+ unsigned int tot_len = pin->tx_msg.len +
+ pin->tx_extra_bytes;
+ unsigned int tx_byte_idx = pin->tx_bit / 10;
+
+ v = !pin->tx_post_eom && tx_byte_idx == tot_len - 1;
+ if (tot_len > 1 && tx_byte_idx == tot_len - 2 &&
+ tx_early_eom(pin)) {
+ /* Error injection: set EOM one byte early */
+ v = true;
+ pin->tx_post_eom = true;
+ } else if (v && tx_no_eom(pin)) {
+ /* Error injection: no EOM */
+ v = false;
+ }
pin->state = v ? CEC_ST_TX_DATA_BIT_1_LOW :
- CEC_ST_TX_DATA_BIT_0_LOW;
+ CEC_ST_TX_DATA_BIT_0_LOW;
break;
- case 9:
+ }
+ case ACK_BIT:
pin->state = CEC_ST_TX_DATA_BIT_1_LOW;
break;
}
+ if (tx_custom_bit(pin))
+ pin->state = CEC_ST_TX_DATA_BIT_LOW_CUSTOM;
cec_pin_low(pin);
break;
case CEC_ST_TX_DATA_BIT_0_LOW:
case CEC_ST_TX_DATA_BIT_1_LOW:
v = pin->state == CEC_ST_TX_DATA_BIT_1_LOW;
- pin->state = v ? CEC_ST_TX_DATA_BIT_1_HIGH :
- CEC_ST_TX_DATA_BIT_0_HIGH;
- is_ack_bit = pin->tx_bit % 10 == 9;
- if (v && (pin->tx_bit < 4 || is_ack_bit))
+ is_ack_bit = pin->tx_bit % 10 == ACK_BIT;
+ if (v && (pin->tx_bit < 4 || is_ack_bit)) {
pin->state = CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE;
+ } else if (!is_ack_bit && tx_short_bit(pin)) {
+ /* Error Injection: send an invalid (too short) bit */
+ pin->state = v ? CEC_ST_TX_DATA_BIT_1_HIGH_SHORT :
+ CEC_ST_TX_DATA_BIT_0_HIGH_SHORT;
+ } else if (!is_ack_bit && tx_long_bit(pin)) {
+ /* Error Injection: send an invalid (too long) bit */
+ pin->state = v ? CEC_ST_TX_DATA_BIT_1_HIGH_LONG :
+ CEC_ST_TX_DATA_BIT_0_HIGH_LONG;
+ } else {
+ pin->state = v ? CEC_ST_TX_DATA_BIT_1_HIGH :
+ CEC_ST_TX_DATA_BIT_0_HIGH;
+ }
+ cec_pin_high(pin);
+ break;
+
+ case CEC_ST_TX_DATA_BIT_LOW_CUSTOM:
+ pin->state = CEC_ST_TX_DATA_BIT_HIGH_CUSTOM;
cec_pin_high(pin);
break;
case CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE:
/* Read the CEC value at the sample time */
v = cec_pin_read(pin);
- is_ack_bit = pin->tx_bit % 10 == 9;
+ is_ack_bit = pin->tx_bit % 10 == ACK_BIT;
/*
* If v == 0 and we're within the first 4 bits
* of the initiator, then someone else started
@@ -258,7 +573,7 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts)
* transmitter has more leading 0 bits in the
* initiator).
*/
- if (!v && !is_ack_bit) {
+ if (!v && !is_ack_bit && !pin->tx_generated_poll) {
pin->tx_msg.len = 0;
pin->work_tx_ts = ts;
pin->work_tx_status = CEC_TX_STATUS_ARB_LOST;
@@ -267,18 +582,27 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts)
pin->tx_bit = 0;
memset(pin->rx_msg.msg, 0, sizeof(pin->rx_msg.msg));
pin->rx_msg.msg[0] = pin->tx_msg.msg[0];
- pin->rx_msg.msg[0] &= ~(1 << (7 - pin->rx_bit));
+ pin->rx_msg.msg[0] &= (0xff << (8 - pin->rx_bit));
pin->rx_msg.len = 0;
+ pin->ts = ktime_sub_us(ts, CEC_TIM_DATA_BIT_SAMPLE);
pin->state = CEC_ST_RX_DATA_POST_SAMPLE;
pin->rx_bit++;
break;
}
pin->state = CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE;
+ if (!is_ack_bit && tx_short_bit(pin)) {
+ /* Error Injection: send an invalid (too short) bit */
+ pin->state = CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_SHORT;
+ } else if (!is_ack_bit && tx_long_bit(pin)) {
+ /* Error Injection: send an invalid (too long) bit */
+ pin->state = CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_LONG;
+ }
if (!is_ack_bit)
break;
/* Was the message ACKed? */
ack = cec_msg_is_broadcast(&pin->tx_msg) ? v : !v;
- if (!ack) {
+ if (!ack && !pin->tx_ignore_nack_until_eom &&
+ pin->tx_bit / 10 < pin->tx_msg.len && !pin->tx_post_eom) {
/*
* Note: the CEC spec is ambiguous regarding
* what action to take when a NACK appears
@@ -295,6 +619,15 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts)
}
break;
+ case CEC_ST_TX_PULSE_LOW_CUSTOM:
+ cec_pin_high(pin);
+ pin->state = CEC_ST_TX_PULSE_HIGH_CUSTOM;
+ break;
+
+ case CEC_ST_TX_PULSE_HIGH_CUSTOM:
+ cec_pin_to_idle(pin);
+ break;
+
default:
break;
}
@@ -322,6 +655,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts)
bool ack;
bool bcast, for_us;
u8 dest;
+ u8 poll;
switch (pin->state) {
/* Receive states */
@@ -331,24 +665,54 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts)
break;
pin->state = CEC_ST_RX_START_BIT_HIGH;
delta = ktime_us_delta(ts, pin->ts);
- pin->ts = ts;
/* Start bit low is too short, go back to idle */
- if (delta < CEC_TIM_START_BIT_LOW_MIN -
- CEC_TIM_IDLE_SAMPLE) {
+ if (delta < CEC_TIM_START_BIT_LOW_MIN - CEC_TIM_IDLE_SAMPLE) {
+ if (!pin->rx_start_bit_low_too_short_cnt++) {
+ pin->rx_start_bit_low_too_short_ts = pin->ts;
+ pin->rx_start_bit_low_too_short_delta = delta;
+ }
cec_pin_to_idle(pin);
+ break;
+ }
+ if (rx_arb_lost(pin, &poll)) {
+ cec_msg_init(&pin->tx_msg, poll >> 4, poll & 0xf);
+ pin->tx_generated_poll = true;
+ pin->tx_extra_bytes = 0;
+ pin->state = CEC_ST_TX_START_BIT_HIGH;
+ pin->ts = ts;
}
break;
case CEC_ST_RX_START_BIT_HIGH:
v = cec_pin_read(pin);
delta = ktime_us_delta(ts, pin->ts);
- if (v && delta > CEC_TIM_START_BIT_TOTAL_MAX -
- CEC_TIM_START_BIT_LOW_MIN) {
+ /*
+ * Unfortunately the spec does not specify when to give up
+ * and go to idle. We just pick TOTAL_LONG.
+ */
+ if (v && delta > CEC_TIM_START_BIT_TOTAL_LONG) {
+ pin->rx_start_bit_too_long_cnt++;
cec_pin_to_idle(pin);
break;
}
if (v)
break;
+ /* Start bit is too short, go back to idle */
+ if (delta < CEC_TIM_START_BIT_TOTAL_MIN - CEC_TIM_IDLE_SAMPLE) {
+ if (!pin->rx_start_bit_too_short_cnt++) {
+ pin->rx_start_bit_too_short_ts = pin->ts;
+ pin->rx_start_bit_too_short_delta = delta;
+ }
+ cec_pin_to_idle(pin);
+ break;
+ }
+ if (rx_low_drive(pin)) {
+ /* Error injection: go to low drive */
+ cec_pin_low(pin);
+ pin->state = CEC_ST_RX_LOW_DRIVE;
+ pin->rx_low_drive_cnt++;
+ break;
+ }
pin->state = CEC_ST_RX_DATA_SAMPLE;
pin->ts = ts;
pin->rx_eom = false;
@@ -363,36 +727,55 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts)
pin->rx_msg.msg[pin->rx_bit / 10] |=
v << (7 - (pin->rx_bit % 10));
break;
- case 8:
+ case EOM_BIT:
pin->rx_eom = v;
pin->rx_msg.len = pin->rx_bit / 10 + 1;
break;
- case 9:
+ case ACK_BIT:
break;
}
pin->rx_bit++;
break;
case CEC_ST_RX_DATA_POST_SAMPLE:
- pin->state = CEC_ST_RX_DATA_HIGH;
+ pin->state = CEC_ST_RX_DATA_WAIT_FOR_LOW;
break;
- case CEC_ST_RX_DATA_HIGH:
+ case CEC_ST_RX_DATA_WAIT_FOR_LOW:
v = cec_pin_read(pin);
delta = ktime_us_delta(ts, pin->ts);
- if (v && delta > CEC_TIM_DATA_BIT_TOTAL_MAX) {
+ /*
+ * Unfortunately the spec does not specify when to give up
+ * and go to idle. We just pick TOTAL_LONG.
+ */
+ if (v && delta > CEC_TIM_DATA_BIT_TOTAL_LONG) {
+ pin->rx_data_bit_too_long_cnt++;
cec_pin_to_idle(pin);
break;
}
if (v)
break;
+
+ if (rx_low_drive(pin)) {
+ /* Error injection: go to low drive */
+ cec_pin_low(pin);
+ pin->state = CEC_ST_RX_LOW_DRIVE;
+ pin->rx_low_drive_cnt++;
+ break;
+ }
+
/*
* Go to low drive state when the total bit time is
* too short.
*/
if (delta < CEC_TIM_DATA_BIT_TOTAL_MIN) {
+ if (!pin->rx_data_bit_too_short_cnt++) {
+ pin->rx_data_bit_too_short_ts = pin->ts;
+ pin->rx_data_bit_too_short_delta = delta;
+ }
cec_pin_low(pin);
- pin->state = CEC_ST_LOW_DRIVE;
+ pin->state = CEC_ST_RX_LOW_DRIVE;
+ pin->rx_low_drive_cnt++;
break;
}
pin->ts = ts;
@@ -408,6 +791,11 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts)
/* ACK bit value */
ack = bcast ? 1 : !for_us;
+ if (for_us && rx_nack(pin)) {
+ /* Error injection: toggle the ACK bit */
+ ack = !ack;
+ }
+
if (ack) {
/* No need to write to the bus, just wait */
pin->state = CEC_ST_RX_ACK_HIGH_POST;
@@ -434,7 +822,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts)
break;
}
pin->rx_bit++;
- pin->state = CEC_ST_RX_DATA_HIGH;
+ pin->state = CEC_ST_RX_DATA_WAIT_FOR_LOW;
break;
case CEC_ST_RX_ACK_FINISH:
@@ -456,6 +844,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
struct cec_adapter *adap = pin->adap;
ktime_t ts;
s32 delta;
+ u32 usecs;
ts = ktime_get();
if (ktime_to_ns(pin->timer_ts)) {
@@ -503,13 +892,27 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
/* Transmit states */
case CEC_ST_TX_WAIT_FOR_HIGH:
case CEC_ST_TX_START_BIT_LOW:
- case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE:
- case CEC_ST_TX_DATA_BIT_0_HIGH:
- case CEC_ST_TX_DATA_BIT_1_HIGH:
case CEC_ST_TX_START_BIT_HIGH:
+ case CEC_ST_TX_START_BIT_HIGH_SHORT:
+ case CEC_ST_TX_START_BIT_HIGH_LONG:
+ case CEC_ST_TX_START_BIT_LOW_CUSTOM:
+ case CEC_ST_TX_START_BIT_HIGH_CUSTOM:
case CEC_ST_TX_DATA_BIT_0_LOW:
+ case CEC_ST_TX_DATA_BIT_0_HIGH:
+ case CEC_ST_TX_DATA_BIT_0_HIGH_SHORT:
+ case CEC_ST_TX_DATA_BIT_0_HIGH_LONG:
case CEC_ST_TX_DATA_BIT_1_LOW:
+ case CEC_ST_TX_DATA_BIT_1_HIGH:
+ case CEC_ST_TX_DATA_BIT_1_HIGH_SHORT:
+ case CEC_ST_TX_DATA_BIT_1_HIGH_LONG:
case CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE:
+ case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE:
+ case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_SHORT:
+ case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE_LONG:
+ case CEC_ST_TX_DATA_BIT_LOW_CUSTOM:
+ case CEC_ST_TX_DATA_BIT_HIGH_CUSTOM:
+ case CEC_ST_TX_PULSE_LOW_CUSTOM:
+ case CEC_ST_TX_PULSE_HIGH_CUSTOM:
cec_pin_tx_states(pin, ts);
break;
@@ -518,7 +921,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
case CEC_ST_RX_START_BIT_HIGH:
case CEC_ST_RX_DATA_SAMPLE:
case CEC_ST_RX_DATA_POST_SAMPLE:
- case CEC_ST_RX_DATA_HIGH:
+ case CEC_ST_RX_DATA_WAIT_FOR_LOW:
case CEC_ST_RX_ACK_LOW:
case CEC_ST_RX_ACK_LOW_POST:
case CEC_ST_RX_ACK_HIGH_POST:
@@ -545,7 +948,10 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
if (delta / CEC_TIM_DATA_BIT_TOTAL >
pin->tx_signal_free_time) {
pin->tx_nacked = false;
- pin->state = CEC_ST_TX_START_BIT_LOW;
+ if (tx_custom_start(pin))
+ pin->state = CEC_ST_TX_START_BIT_LOW_CUSTOM;
+ else
+ pin->state = CEC_ST_TX_START_BIT_LOW;
/* Generate start bit */
cec_pin_low(pin);
break;
@@ -555,6 +961,13 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
pin->state = CEC_ST_TX_WAIT;
break;
}
+ if (pin->tx_custom_pulse && pin->state == CEC_ST_IDLE) {
+ pin->tx_custom_pulse = false;
+ /* Generate custom pulse */
+ cec_pin_low(pin);
+ pin->state = CEC_ST_TX_PULSE_LOW_CUSTOM;
+ break;
+ }
if (pin->state != CEC_ST_IDLE || pin->ops->enable_irq == NULL ||
pin->enable_irq_failed || adap->is_configuring ||
adap->is_configured || adap->monitor_all_cnt)
@@ -565,21 +978,40 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
wake_up_interruptible(&pin->kthread_waitq);
return HRTIMER_NORESTART;
- case CEC_ST_LOW_DRIVE:
+ case CEC_ST_TX_LOW_DRIVE:
+ case CEC_ST_RX_LOW_DRIVE:
+ cec_pin_high(pin);
cec_pin_to_idle(pin);
break;
default:
break;
}
- if (!adap->monitor_pin_cnt || states[pin->state].usecs <= 150) {
+
+ switch (pin->state) {
+ case CEC_ST_TX_START_BIT_LOW_CUSTOM:
+ case CEC_ST_TX_DATA_BIT_LOW_CUSTOM:
+ case CEC_ST_TX_PULSE_LOW_CUSTOM:
+ usecs = pin->tx_custom_low_usecs;
+ break;
+ case CEC_ST_TX_START_BIT_HIGH_CUSTOM:
+ case CEC_ST_TX_DATA_BIT_HIGH_CUSTOM:
+ case CEC_ST_TX_PULSE_HIGH_CUSTOM:
+ usecs = pin->tx_custom_high_usecs;
+ break;
+ default:
+ usecs = states[pin->state].usecs;
+ break;
+ }
+
+ if (!adap->monitor_pin_cnt || usecs <= 150) {
pin->wait_usecs = 0;
- pin->timer_ts = ktime_add_us(ts, states[pin->state].usecs);
+ pin->timer_ts = ktime_add_us(ts, usecs);
hrtimer_forward_now(timer,
- ns_to_ktime(states[pin->state].usecs * 1000));
+ ns_to_ktime(usecs * 1000));
return HRTIMER_RESTART;
}
- pin->wait_usecs = states[pin->state].usecs - 100;
+ pin->wait_usecs = usecs - 100;
pin->timer_ts = ktime_add_us(ts, 100);
hrtimer_forward_now(timer, ns_to_ktime(100000));
return HRTIMER_RESTART;
@@ -596,12 +1028,25 @@ static int cec_pin_thread_func(void *_adap)
pin->work_rx_msg.len ||
pin->work_tx_status ||
atomic_read(&pin->work_irq_change) ||
- atomic_read(&pin->work_pin_events));
+ atomic_read(&pin->work_pin_num_events));
if (pin->work_rx_msg.len) {
- cec_received_msg_ts(adap, &pin->work_rx_msg,
+ struct cec_msg *msg = &pin->work_rx_msg;
+
+ if (msg->len > 1 && msg->len < CEC_MAX_MSG_SIZE &&
+ rx_add_byte(pin)) {
+ /* Error injection: add byte to the message */
+ msg->msg[msg->len++] = 0x55;
+ }
+ if (msg->len > 2 && rx_remove_byte(pin)) {
+ /* Error injection: remove byte from message */
+ msg->len--;
+ }
+ if (msg->len > CEC_MAX_MSG_SIZE)
+ msg->len = CEC_MAX_MSG_SIZE;
+ cec_received_msg_ts(adap, msg,
ns_to_ktime(pin->work_rx_msg.rx_ts));
- pin->work_rx_msg.len = 0;
+ msg->len = 0;
}
if (pin->work_tx_status) {
unsigned int tx_status = pin->work_tx_status;
@@ -611,14 +1056,16 @@ static int cec_pin_thread_func(void *_adap)
pin->work_tx_ts);
}
- while (atomic_read(&pin->work_pin_events)) {
+ while (atomic_read(&pin->work_pin_num_events)) {
unsigned int idx = pin->work_pin_events_rd;
+ u8 v = pin->work_pin_events[idx];
cec_queue_pin_cec_event(adap,
- pin->work_pin_is_high[idx],
+ v & CEC_PIN_EVENT_FL_IS_HIGH,
+ v & CEC_PIN_EVENT_FL_DROPPED,
pin->work_pin_ts[idx]);
pin->work_pin_events_rd = (idx + 1) % CEC_NUM_PIN_EVENTS;
- atomic_dec(&pin->work_pin_events);
+ atomic_dec(&pin->work_pin_num_events);
}
switch (atomic_xchg(&pin->work_irq_change,
@@ -654,8 +1101,9 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable)
pin->enabled = enable;
if (enable) {
- atomic_set(&pin->work_pin_events, 0);
+ atomic_set(&pin->work_pin_num_events, 0);
pin->work_pin_events_rd = pin->work_pin_events_wr = 0;
+ pin->work_pin_events_dropped = false;
cec_pin_read(pin);
cec_pin_to_idle(pin);
pin->tx_msg.len = 0;
@@ -692,23 +1140,37 @@ static int cec_pin_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
return 0;
}
+void cec_pin_start_timer(struct cec_pin *pin)
+{
+ if (pin->state != CEC_ST_RX_IRQ)
+ return;
+
+ atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED);
+ pin->ops->disable_irq(pin->adap);
+ cec_pin_high(pin);
+ cec_pin_to_idle(pin);
+ hrtimer_start(&pin->timer, ns_to_ktime(0), HRTIMER_MODE_REL);
+}
+
static int cec_pin_adap_transmit(struct cec_adapter *adap, u8 attempts,
u32 signal_free_time, struct cec_msg *msg)
{
struct cec_pin *pin = adap->pin;
pin->tx_signal_free_time = signal_free_time;
+ pin->tx_extra_bytes = 0;
pin->tx_msg = *msg;
+ if (msg->len > 1) {
+ /* Error injection: add byte to the message */
+ pin->tx_extra_bytes = tx_add_bytes(pin);
+ }
+ if (msg->len > 2 && tx_remove_byte(pin)) {
+ /* Error injection: remove byte from the message */
+ pin->tx_msg.len--;
+ }
pin->work_tx_status = 0;
pin->tx_bit = 0;
- if (pin->state == CEC_ST_RX_IRQ) {
- atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED);
- pin->ops->disable_irq(adap);
- cec_pin_high(pin);
- cec_pin_to_idle(pin);
- hrtimer_start(&pin->timer, ns_to_ktime(0),
- HRTIMER_MODE_REL);
- }
+ cec_pin_start_timer(pin);
return 0;
}
@@ -717,10 +1179,12 @@ static void cec_pin_adap_status(struct cec_adapter *adap,
{
struct cec_pin *pin = adap->pin;
- seq_printf(file, "state: %s\n", states[pin->state].name);
- seq_printf(file, "tx_bit: %d\n", pin->tx_bit);
- seq_printf(file, "rx_bit: %d\n", pin->rx_bit);
+ seq_printf(file, "state: %s\n", states[pin->state].name);
+ seq_printf(file, "tx_bit: %d\n", pin->tx_bit);
+ seq_printf(file, "rx_bit: %d\n", pin->rx_bit);
seq_printf(file, "cec pin: %d\n", pin->ops->read(adap));
+ seq_printf(file, "cec pin events dropped: %u\n",
+ pin->work_pin_events_dropped_cnt);
seq_printf(file, "irq failed: %d\n", pin->enable_irq_failed);
if (pin->timer_100ms_overruns) {
seq_printf(file, "timer overruns > 100ms: %u of %u\n",
@@ -732,11 +1196,45 @@ static void cec_pin_adap_status(struct cec_adapter *adap,
seq_printf(file, "avg timer overrun: %u usecs\n",
pin->timer_sum_overrun / pin->timer_100ms_overruns);
}
+ if (pin->rx_start_bit_low_too_short_cnt)
+ seq_printf(file,
+ "rx start bit low too short: %u (delta %u, ts %llu)\n",
+ pin->rx_start_bit_low_too_short_cnt,
+ pin->rx_start_bit_low_too_short_delta,
+ pin->rx_start_bit_low_too_short_ts);
+ if (pin->rx_start_bit_too_short_cnt)
+ seq_printf(file,
+ "rx start bit too short: %u (delta %u, ts %llu)\n",
+ pin->rx_start_bit_too_short_cnt,
+ pin->rx_start_bit_too_short_delta,
+ pin->rx_start_bit_too_short_ts);
+ if (pin->rx_start_bit_too_long_cnt)
+ seq_printf(file, "rx start bit too long: %u\n",
+ pin->rx_start_bit_too_long_cnt);
+ if (pin->rx_data_bit_too_short_cnt)
+ seq_printf(file,
+ "rx data bit too short: %u (delta %u, ts %llu)\n",
+ pin->rx_data_bit_too_short_cnt,
+ pin->rx_data_bit_too_short_delta,
+ pin->rx_data_bit_too_short_ts);
+ if (pin->rx_data_bit_too_long_cnt)
+ seq_printf(file, "rx data bit too long: %u\n",
+ pin->rx_data_bit_too_long_cnt);
+ seq_printf(file, "rx initiated low drive: %u\n", pin->rx_low_drive_cnt);
+ seq_printf(file, "tx detected low drive: %u\n", pin->tx_low_drive_cnt);
+ pin->work_pin_events_dropped_cnt = 0;
pin->timer_cnt = 0;
pin->timer_100ms_overruns = 0;
pin->timer_300ms_overruns = 0;
pin->timer_max_overrun = 0;
pin->timer_sum_overrun = 0;
+ pin->rx_start_bit_low_too_short_cnt = 0;
+ pin->rx_start_bit_too_short_cnt = 0;
+ pin->rx_start_bit_too_long_cnt = 0;
+ pin->rx_data_bit_too_short_cnt = 0;
+ pin->rx_data_bit_too_long_cnt = 0;
+ pin->rx_low_drive_cnt = 0;
+ pin->tx_low_drive_cnt = 0;
if (pin->ops->status)
pin->ops->status(adap, file);
}
@@ -778,6 +1276,10 @@ static const struct cec_adap_ops cec_pin_adap_ops = {
.adap_transmit = cec_pin_adap_transmit,
.adap_status = cec_pin_adap_status,
.adap_free = cec_pin_adap_free,
+#ifdef CONFIG_CEC_PIN_ERROR_INJ
+ .error_inj_parse_line = cec_pin_error_inj_parse_line,
+ .error_inj_show = cec_pin_error_inj_show,
+#endif
};
struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops,
@@ -792,6 +1294,8 @@ struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops,
hrtimer_init(&pin->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
pin->timer.function = cec_pin_timer;
init_waitqueue_head(&pin->kthread_waitq);
+ pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT;
+ pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT;
adap = cec_allocate_adapter(&cec_pin_adap_ops, priv, name,
caps | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN,
diff --git a/drivers/media/cec/cec-priv.h b/drivers/media/cec/cec-priv.h
index daf597643af8..804e38f849c7 100644
--- a/drivers/media/cec/cec-priv.h
+++ b/drivers/media/cec/cec-priv.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cec-priv.h - HDMI Consumer Electronics Control internal header
*
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _CEC_PRIV_H
diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c
index c5c827e11b64..b5dcc6d1fe90 100644
--- a/drivers/media/common/siano/smscoreapi.c
+++ b/drivers/media/common/siano/smscoreapi.c
@@ -631,7 +631,8 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
cb->p = buffer;
cb->offset_in_common = buffer - (u8 *) common_buffer;
- cb->phys = common_buffer_phys + cb->offset_in_common;
+ if (common_buffer_phys)
+ cb->phys = common_buffer_phys + cb->offset_in_common;
return cb;
}
@@ -690,17 +691,21 @@ int smscore_register_device(struct smsdevice_params_t *params,
/* alloc common buffer */
dev->common_buffer_size = params->buffer_size * params->num_buffers;
- dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
- &dev->common_buffer_phys,
- GFP_KERNEL | GFP_DMA);
- if (!dev->common_buffer) {
+ if (params->usb_device)
+ buffer = kzalloc(dev->common_buffer_size, GFP_KERNEL);
+ else
+ buffer = dma_alloc_coherent(params->device,
+ dev->common_buffer_size,
+ &dev->common_buffer_phys,
+ GFP_KERNEL | GFP_DMA);
+ if (!buffer) {
smscore_unregister_device(dev);
return -ENOMEM;
}
+ dev->common_buffer = buffer;
/* prepare dma buffers */
- for (buffer = dev->common_buffer;
- dev->num_buffers < params->num_buffers;
+ for (; dev->num_buffers < params->num_buffers;
dev->num_buffers++, buffer += params->buffer_size) {
struct smscore_buffer_t *cb;
@@ -720,6 +725,7 @@ int smscore_register_device(struct smsdevice_params_t *params,
dev->board_id = SMS_BOARD_UNKNOWN;
dev->context = params->context;
dev->device = params->device;
+ dev->usb_device = params->usb_device;
dev->setmode_handler = params->setmode_handler;
dev->detectmode_handler = params->detectmode_handler;
dev->sendrequest_handler = params->sendrequest_handler;
@@ -1231,10 +1237,15 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
pr_debug("freed %d buffers\n", num_buffers);
- if (coredev->common_buffer)
- dma_free_coherent(NULL, coredev->common_buffer_size,
- coredev->common_buffer, coredev->common_buffer_phys);
-
+ if (coredev->common_buffer) {
+ if (coredev->usb_device)
+ kfree(coredev->common_buffer);
+ else
+ dma_free_coherent(coredev->device,
+ coredev->common_buffer_size,
+ coredev->common_buffer,
+ coredev->common_buffer_phys);
+ }
kfree(coredev->fw_buf);
list_del(&coredev->entry);
diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h
index 4cc39e4a8318..134c69f7ea7b 100644
--- a/drivers/media/common/siano/smscoreapi.h
+++ b/drivers/media/common/siano/smscoreapi.h
@@ -134,6 +134,7 @@ struct smscore_buffer_t {
struct smsdevice_params_t {
struct device *device;
+ struct usb_device *usb_device;
int buffer_size;
int num_buffers;
@@ -176,6 +177,7 @@ struct smscore_device_t {
void *context;
struct device *device;
+ struct usb_device *usb_device;
char devpath[32];
unsigned long device_flags;
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c
index 43180204fab2..3a3dc23c560c 100644
--- a/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c
+++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* v4l2-tpg-colors.c - A table that converts colors to various colorspaces
*
@@ -20,19 +21,6 @@
* in order to preserve precision.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/videodev2.h>
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
index 2b3d4ac4dfd4..37632bc524d4 100644
--- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
+++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* v4l2-tpg-core.c - Test Pattern Generator
*
@@ -5,19 +6,6 @@
* vivi.c source for the copyright information of those functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/module.h>
@@ -1155,13 +1143,13 @@ static void gen_twopix(struct tpg_data *tpg,
case V4L2_PIX_FMT_NV24:
buf[0][offset] = r_y_h;
buf[1][2 * offset] = g_u_s;
- buf[1][2 * offset + 1] = b_v;
+ buf[1][(2 * offset + 1) % 8] = b_v;
break;
case V4L2_PIX_FMT_NV42:
buf[0][offset] = r_y_h;
buf[1][2 * offset] = b_v;
- buf[1][2 * offset + 1] = g_u_s;
+ buf[1][(2 * offset + 1) %8] = g_u_s;
break;
case V4L2_PIX_FMT_YUYV:
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index debe35fc66b4..d3f7bb33a54d 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -1696,6 +1696,15 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
for (i = 0; i < q->num_buffers; ++i) {
struct vb2_buffer *vb = q->bufs[i];
+ if (vb->state == VB2_BUF_STATE_PREPARED ||
+ vb->state == VB2_BUF_STATE_QUEUED) {
+ unsigned int plane;
+
+ for (plane = 0; plane < vb->num_planes; ++plane)
+ call_void_memop(vb, finish,
+ vb->planes[plane].mem_priv);
+ }
+
if (vb->state != VB2_BUF_STATE_DEQUEUED) {
vb->state = VB2_BUF_STATE_PREPARED;
call_void_vb_qop(vb, buf_finish, vb);
diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c
index 3a7c80cd1a17..359fb9804d16 100644
--- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c
+++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c
@@ -106,7 +106,7 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr,
if (nums[i-1] + 1 != nums[i])
goto fail_map;
buf->vaddr = (__force void *)
- ioremap_nocache(nums[0] << PAGE_SHIFT, size);
+ ioremap_nocache(__pfn_to_phys(nums[0]), size + offset);
} else {
buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1,
PAGE_KERNEL);
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
index 204d0f6c678d..97365a863519 100644
--- a/drivers/media/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -1254,8 +1254,8 @@ static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca,
ca->pub->slot_ts_enable(ca->pub, slot);
sl->slot_state = DVB_CA_SLOTSTATE_RUNNING;
dvb_ca_en50221_thread_update_delay(ca);
- pr_err("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n",
- ca->dvbdev->adapter->num);
+ pr_info("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n",
+ ca->dvbdev->adapter->num);
break;
case DVB_CA_SLOTSTATE_RUNNING:
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index a7ed16e0841d..21a7d4b47e1a 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -2294,7 +2294,7 @@ static int dvb_frontend_handle_ioctl(struct file *file,
if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
return -EINVAL;
- tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
+ tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp));
if (IS_ERR(tvp))
return PTR_ERR(tvp);
@@ -2328,7 +2328,7 @@ static int dvb_frontend_handle_ioctl(struct file *file,
if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
return -EINVAL;
- tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
+ tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp));
if (IS_ERR(tvp))
return PTR_ERR(tvp);
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 60e9c2ba26be..787fe06df217 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -24,6 +24,7 @@
#include <linux/string.h>
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
@@ -941,6 +942,55 @@ out:
return err;
}
+#if IS_ENABLED(CONFIG_I2C)
+struct i2c_client *dvb_module_probe(const char *module_name,
+ const char *name,
+ struct i2c_adapter *adap,
+ unsigned char addr,
+ void *platform_data)
+{
+ struct i2c_client *client;
+ struct i2c_board_info *board_info;
+
+ board_info = kzalloc(sizeof(*board_info), GFP_KERNEL);
+ if (!board_info)
+ return NULL;
+
+ if (name)
+ strlcpy(board_info->type, name, I2C_NAME_SIZE);
+ else
+ strlcpy(board_info->type, module_name, I2C_NAME_SIZE);
+
+ board_info->addr = addr;
+ board_info->platform_data = platform_data;
+ request_module(module_name);
+ client = i2c_new_device(adap, board_info);
+ if (client == NULL || client->dev.driver == NULL) {
+ kfree(board_info);
+ return NULL;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ client = NULL;
+ }
+
+ kfree(board_info);
+ return client;
+}
+EXPORT_SYMBOL_GPL(dvb_module_probe);
+
+void dvb_module_release(struct i2c_client *client)
+{
+ if (!client)
+ return;
+
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+}
+EXPORT_SYMBOL_GPL(dvb_module_release);
+#endif
+
static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct dvb_device *dvbdev = dev_get_drvdata(dev);
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index d17722eb4456..0712069fd9fe 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -462,7 +462,7 @@ config DVB_TDA10048
config DVB_AF9013
tristate "Afatech AF9013 demodulator"
- depends on DVB_CORE && I2C
+ depends on DVB_CORE && I2C && I2C_MUX
select REGMAP
default m if !MEDIA_SUBDRV_AUTOSELECT
help
@@ -546,6 +546,8 @@ config DVB_GP8PSK_FE
depends on DVB_CORE
default DVB_USB_GP8PSK
+source "drivers/media/dvb-frontends/cxd2880/Kconfig"
+
comment "DVB-C (cable) frontends"
depends on DVB_CORE
@@ -822,13 +824,6 @@ config DVB_A8293
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
-config DVB_SP2
- tristate "CIMaX SP2"
- depends on DVB_CORE && I2C
- default m if !MEDIA_SUBDRV_AUTOSELECT
- help
- CIMaX SP2/SP2HF Common Interface module.
-
config DVB_LGS8GL5
tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
depends on DVB_CORE && I2C
@@ -904,6 +899,27 @@ config DVB_HELENE
help
Say Y when you want to support this frontend.
+comment "Common Interface (EN50221) controller drivers"
+ depends on DVB_CORE
+
+config DVB_CXD2099
+ tristate "CXD2099AR Common Interface driver"
+ depends on DVB_CORE && I2C
+ select REGMAP_I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A driver for the CI controller currently found mostly on
+ Digital Devices DuoFlex CI (single) addon modules.
+
+ Say Y when you want to support these devices.
+
+config DVB_SP2
+ tristate "CIMaX SP2"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ CIMaX SP2/SP2HF Common Interface module.
+
comment "Tools to develop new frontends"
config DVB_DUMMY_FE
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index 4be59fed4536..67a783fd5ed0 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -129,3 +129,5 @@ obj-$(CONFIG_DVB_HORUS3A) += horus3a.o
obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o
obj-$(CONFIG_DVB_HELENE) += helene.o
obj-$(CONFIG_DVB_ZD1301_DEMOD) += zd1301_demod.o
+obj-$(CONFIG_DVB_CXD2099) += cxd2099.o
+obj-$(CONFIG_DVB_CXD2880) += cxd2880/
diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c
index b8f3ebfc3e27..482bce49819a 100644
--- a/drivers/media/dvb-frontends/af9013.c
+++ b/drivers/media/dvb-frontends/af9013.c
@@ -23,6 +23,7 @@
struct af9013_state {
struct i2c_client *client;
struct regmap *regmap;
+ struct i2c_mux_core *muxc;
struct dvb_frontend fe;
u32 clk;
u8 tuner;
@@ -33,20 +34,20 @@ struct af9013_state {
u8 api_version[4];
u8 gpio[4];
- /* tuner/demod RF and IF AGC limits used for signal strength calc */
- u8 signal_strength_en, rf_50, rf_80, if_50, if_80;
- u16 signal_strength;
- u32 ber;
- u32 ucblocks;
- u16 snr;
u32 bandwidth_hz;
enum fe_status fe_status;
+ /* RF and IF AGC limits used for signal strength calc */
+ u8 strength_en, rf_agc_50, rf_agc_80, if_agc_50, if_agc_80;
unsigned long set_frontend_jiffies;
unsigned long read_status_jiffies;
+ unsigned long strength_jiffies;
+ unsigned long cnr_jiffies;
+ unsigned long ber_ucb_jiffies;
+ u16 dvbv3_snr;
+ u16 dvbv3_strength;
+ u32 dvbv3_ber;
+ u32 dvbv3_ucblocks;
bool first_tune;
- bool i2c_gate_state;
- unsigned int statistics_step:3;
- struct delayed_work statistics_work;
};
static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval)
@@ -101,232 +102,6 @@ err:
return ret;
}
-static int af9013_statistics_ber_unc_start(struct dvb_frontend *fe)
-{
- struct af9013_state *state = fe->demodulator_priv;
- struct i2c_client *client = state->client;
- int ret;
-
- dev_dbg(&client->dev, "\n");
-
- /* reset and start BER counter */
- ret = regmap_update_bits(state->regmap, 0xd391, 0x10, 0x10);
- if (ret)
- goto err;
-
- return 0;
-err:
- dev_dbg(&client->dev, "failed %d\n", ret);
- return ret;
-}
-
-static int af9013_statistics_ber_unc_result(struct dvb_frontend *fe)
-{
- struct af9013_state *state = fe->demodulator_priv;
- struct i2c_client *client = state->client;
- int ret;
- unsigned int utmp;
- u8 buf[5];
-
- dev_dbg(&client->dev, "\n");
-
- /* check if error bit count is ready */
- ret = regmap_read(state->regmap, 0xd391, &utmp);
- if (ret)
- goto err;
-
- if (!((utmp >> 4) & 0x01)) {
- dev_dbg(&client->dev, "not ready\n");
- return 0;
- }
-
- ret = regmap_bulk_read(state->regmap, 0xd387, buf, 5);
- if (ret)
- goto err;
-
- state->ber = (buf[2] << 16) | (buf[1] << 8) | buf[0];
- state->ucblocks += (buf[4] << 8) | buf[3];
-
- return 0;
-err:
- dev_dbg(&client->dev, "failed %d\n", ret);
- return ret;
-}
-
-static int af9013_statistics_snr_start(struct dvb_frontend *fe)
-{
- struct af9013_state *state = fe->demodulator_priv;
- struct i2c_client *client = state->client;
- int ret;
-
- dev_dbg(&client->dev, "\n");
-
- /* start SNR meas */
- ret = regmap_update_bits(state->regmap, 0xd2e1, 0x08, 0x08);
- if (ret)
- goto err;
-
- return 0;
-err:
- dev_dbg(&client->dev, "failed %d\n", ret);
- return ret;
-}
-
-static int af9013_statistics_snr_result(struct dvb_frontend *fe)
-{
- struct af9013_state *state = fe->demodulator_priv;
- struct i2c_client *client = state->client;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int ret, i, len;
- unsigned int utmp;
- u8 buf[3];
- u32 snr_val;
- const struct af9013_snr *uninitialized_var(snr_lut);
-
- dev_dbg(&client->dev, "\n");
-
- /* check if SNR ready */
- ret = regmap_read(state->regmap, 0xd2e1, &utmp);
- if (ret)
- goto err;
-
- if (!((utmp >> 3) & 0x01)) {
- dev_dbg(&client->dev, "not ready\n");
- return 0;
- }
-
- /* read value */
- ret = regmap_bulk_read(state->regmap, 0xd2e3, buf, 3);
- if (ret)
- goto err;
-
- snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0];
-
- /* read current modulation */
- ret = regmap_read(state->regmap, 0xd3c1, &utmp);
- if (ret)
- goto err;
-
- switch ((utmp >> 6) & 3) {
- case 0:
- len = ARRAY_SIZE(qpsk_snr_lut);
- snr_lut = qpsk_snr_lut;
- break;
- case 1:
- len = ARRAY_SIZE(qam16_snr_lut);
- snr_lut = qam16_snr_lut;
- break;
- case 2:
- len = ARRAY_SIZE(qam64_snr_lut);
- snr_lut = qam64_snr_lut;
- break;
- default:
- goto err;
- }
-
- for (i = 0; i < len; i++) {
- utmp = snr_lut[i].snr;
-
- if (snr_val < snr_lut[i].val)
- break;
- }
- state->snr = utmp * 10; /* dB/10 */
-
- c->cnr.stat[0].svalue = 1000 * utmp;
- c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
-
- return 0;
-err:
- dev_dbg(&client->dev, "failed %d\n", ret);
- return ret;
-}
-
-static int af9013_statistics_signal_strength(struct dvb_frontend *fe)
-{
- struct af9013_state *state = fe->demodulator_priv;
- struct i2c_client *client = state->client;
- int ret = 0;
- u8 buf[2], rf_gain, if_gain;
- int signal_strength;
-
- dev_dbg(&client->dev, "\n");
-
- if (!state->signal_strength_en)
- return 0;
-
- ret = regmap_bulk_read(state->regmap, 0xd07c, buf, 2);
- if (ret)
- goto err;
-
- rf_gain = buf[0];
- if_gain = buf[1];
-
- signal_strength = (0xffff / \
- (9 * (state->rf_50 + state->if_50) - \
- 11 * (state->rf_80 + state->if_80))) * \
- (10 * (rf_gain + if_gain) - \
- 11 * (state->rf_80 + state->if_80));
- if (signal_strength < 0)
- signal_strength = 0;
- else if (signal_strength > 0xffff)
- signal_strength = 0xffff;
-
- state->signal_strength = signal_strength;
-
- return 0;
-err:
- dev_dbg(&client->dev, "failed %d\n", ret);
- return ret;
-}
-
-static void af9013_statistics_work(struct work_struct *work)
-{
- struct af9013_state *state = container_of(work,
- struct af9013_state, statistics_work.work);
- unsigned int next_msec;
-
- /* update only signal strength when demod is not locked */
- if (!(state->fe_status & FE_HAS_LOCK)) {
- state->statistics_step = 0;
- state->ber = 0;
- state->snr = 0;
- }
-
- switch (state->statistics_step) {
- default:
- state->statistics_step = 0;
- /* fall-through */
- case 0:
- af9013_statistics_signal_strength(&state->fe);
- state->statistics_step++;
- next_msec = 300;
- break;
- case 1:
- af9013_statistics_snr_start(&state->fe);
- state->statistics_step++;
- next_msec = 200;
- break;
- case 2:
- af9013_statistics_ber_unc_start(&state->fe);
- state->statistics_step++;
- next_msec = 1000;
- break;
- case 3:
- af9013_statistics_snr_result(&state->fe);
- state->statistics_step++;
- next_msec = 400;
- break;
- case 4:
- af9013_statistics_ber_unc_result(&state->fe);
- state->statistics_step++;
- next_msec = 100;
- break;
- }
-
- schedule_delayed_work(&state->statistics_work,
- msecs_to_jiffies(next_msec));
-}
-
static int af9013_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *fesettings)
{
@@ -751,46 +526,273 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status)
{
struct af9013_state *state = fe->demodulator_priv;
struct i2c_client *client = state->client;
- int ret;
- unsigned int utmp;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret, stmp1;
+ unsigned int utmp, utmp1, utmp2, utmp3, utmp4;
+ u8 buf[7];
+
+ dev_dbg(&client->dev, "\n");
/*
* Return status from the cache if it is younger than 2000ms with the
* exception of last tune is done during 4000ms.
*/
- if (time_is_after_jiffies(
- state->read_status_jiffies + msecs_to_jiffies(2000)) &&
- time_is_before_jiffies(
- state->set_frontend_jiffies + msecs_to_jiffies(4000))
- ) {
- *status = state->fe_status;
- return 0;
+ if (time_is_after_jiffies(state->read_status_jiffies + msecs_to_jiffies(2000)) &&
+ time_is_before_jiffies(state->set_frontend_jiffies + msecs_to_jiffies(4000))) {
+ *status = state->fe_status;
} else {
- *status = 0;
+ /* MPEG2 lock */
+ ret = regmap_read(state->regmap, 0xd507, &utmp);
+ if (ret)
+ goto err;
+
+ if ((utmp >> 6) & 0x01) {
+ utmp1 = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ } else {
+ /* TPS lock */
+ ret = regmap_read(state->regmap, 0xd330, &utmp);
+ if (ret)
+ goto err;
+
+ if ((utmp >> 3) & 0x01)
+ utmp1 = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI;
+ else
+ utmp1 = 0;
+ }
+
+ dev_dbg(&client->dev, "fe_status %02x\n", utmp1);
+
+ state->read_status_jiffies = jiffies;
+
+ state->fe_status = utmp1;
+ *status = utmp1;
}
- /* MPEG2 lock */
- ret = regmap_read(state->regmap, 0xd507, &utmp);
- if (ret)
- goto err;
+ /* Signal strength */
+ switch (state->strength_en) {
+ case 0:
+ /* Check if we support signal strength */
+ ret = regmap_read(state->regmap, 0x9bee, &utmp);
+ if (ret)
+ goto err;
- if ((utmp >> 6) & 0x01)
- *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
- FE_HAS_SYNC | FE_HAS_LOCK;
+ if ((utmp >> 0) & 0x01) {
+ /* Read agc values for signal strength estimation */
+ ret = regmap_read(state->regmap, 0x9bbd, &utmp1);
+ if (ret)
+ goto err;
+ ret = regmap_read(state->regmap, 0x9bd0, &utmp2);
+ if (ret)
+ goto err;
+ ret = regmap_read(state->regmap, 0x9be2, &utmp3);
+ if (ret)
+ goto err;
+ ret = regmap_read(state->regmap, 0x9be4, &utmp4);
+ if (ret)
+ goto err;
- if (!*status) {
- /* TPS lock */
- ret = regmap_read(state->regmap, 0xd330, &utmp);
+ state->rf_agc_50 = utmp1;
+ state->rf_agc_80 = utmp2;
+ state->if_agc_50 = utmp3;
+ state->if_agc_80 = utmp4;
+ dev_dbg(&client->dev,
+ "rf_agc_50 %u, rf_agc_80 %u, if_agc_50 %u, if_agc_80 %u\n",
+ utmp1, utmp2, utmp3, utmp4);
+
+ state->strength_en = 1;
+ } else {
+ /* Signal strength is not supported */
+ state->strength_en = 2;
+ break;
+ }
+ /* Fall through */
+ case 1:
+ if (time_is_after_jiffies(state->strength_jiffies + msecs_to_jiffies(2000)))
+ break;
+
+ /* Read value */
+ ret = regmap_bulk_read(state->regmap, 0xd07c, buf, 2);
if (ret)
goto err;
- if ((utmp >> 3) & 0x01)
- *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
- FE_HAS_VITERBI;
+ /*
+ * Construct line equation from tuner dependent -80/-50 dBm agc
+ * limits and use it to map current agc value to dBm estimate
+ */
+ #define agc_gain (buf[0] + buf[1])
+ #define agc_gain_50dbm (state->rf_agc_50 + state->if_agc_50)
+ #define agc_gain_80dbm (state->rf_agc_80 + state->if_agc_80)
+ stmp1 = 30000 * (agc_gain - agc_gain_80dbm) /
+ (agc_gain_50dbm - agc_gain_80dbm) - 80000;
+
+ dev_dbg(&client->dev,
+ "strength %d, agc_gain %d, agc_gain_50dbm %d, agc_gain_80dbm %d\n",
+ stmp1, agc_gain, agc_gain_50dbm, agc_gain_80dbm);
+
+ state->strength_jiffies = jiffies;
+ /* Convert [-90, -30] dBm to [0x0000, 0xffff] for dvbv3 */
+ utmp1 = clamp(stmp1 + 90000, 0, 60000);
+ state->dvbv3_strength = div_u64((u64)utmp1 * 0xffff, 60000);
+
+ c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+ c->strength.stat[0].svalue = stmp1;
+ break;
+ default:
+ c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ break;
}
- state->fe_status = *status;
- state->read_status_jiffies = jiffies;
+ /* CNR */
+ switch (state->fe_status & FE_HAS_VITERBI) {
+ case FE_HAS_VITERBI:
+ if (time_is_after_jiffies(state->cnr_jiffies + msecs_to_jiffies(2000)))
+ break;
+
+ /* Check if cnr ready */
+ ret = regmap_read(state->regmap, 0xd2e1, &utmp);
+ if (ret)
+ goto err;
+
+ if (!((utmp >> 3) & 0x01)) {
+ dev_dbg(&client->dev, "cnr not ready\n");
+ break;
+ }
+
+ /* Read value */
+ ret = regmap_bulk_read(state->regmap, 0xd2e3, buf, 3);
+ if (ret)
+ goto err;
+
+ utmp1 = buf[2] << 16 | buf[1] << 8 | buf[0] << 0;
+
+ /* Read current modulation */
+ ret = regmap_read(state->regmap, 0xd3c1, &utmp);
+ if (ret)
+ goto err;
+
+ switch ((utmp >> 6) & 3) {
+ case 0:
+ /*
+ * QPSK
+ * CNR[dB] 13 * -log10((1690000 - value) / value) + 2.6
+ * value [653799, 1689999], 2.6 / 13 = 3355443
+ */
+ utmp1 = clamp(utmp1, 653799U, 1689999U);
+ utmp1 = ((u64)(intlog10(utmp1)
+ - intlog10(1690000 - utmp1)
+ + 3355443) * 13 * 1000) >> 24;
+ break;
+ case 1:
+ /*
+ * QAM-16
+ * CNR[dB] 6 * log10((value - 370000) / (828000 - value)) + 15.7
+ * value [371105, 827999], 15.7 / 6 = 43900382
+ */
+ utmp1 = clamp(utmp1, 371105U, 827999U);
+ utmp1 = ((u64)(intlog10(utmp1 - 370000)
+ - intlog10(828000 - utmp1)
+ + 43900382) * 6 * 1000) >> 24;
+ break;
+ case 2:
+ /*
+ * QAM-64
+ * CNR[dB] 8 * log10((value - 193000) / (425000 - value)) + 23.8
+ * value [193246, 424999], 23.8 / 8 = 49912218
+ */
+ utmp1 = clamp(utmp1, 193246U, 424999U);
+ utmp1 = ((u64)(intlog10(utmp1 - 193000)
+ - intlog10(425000 - utmp1)
+ + 49912218) * 8 * 1000) >> 24;
+ break;
+ default:
+ dev_dbg(&client->dev, "invalid modulation %u\n",
+ (utmp >> 6) & 3);
+ utmp1 = 0;
+ break;
+ }
+
+ dev_dbg(&client->dev, "cnr %u\n", utmp1);
+
+ state->cnr_jiffies = jiffies;
+ state->dvbv3_snr = utmp1 / 100;
+
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+ c->cnr.stat[0].svalue = utmp1;
+ break;
+ default:
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ break;
+ }
+
+ /* BER / PER */
+ switch (state->fe_status & FE_HAS_SYNC) {
+ case FE_HAS_SYNC:
+ if (time_is_after_jiffies(state->ber_ucb_jiffies + msecs_to_jiffies(2000)))
+ break;
+
+ /* Check if ber / ucb is ready */
+ ret = regmap_read(state->regmap, 0xd391, &utmp);
+ if (ret)
+ goto err;
+
+ if (!((utmp >> 4) & 0x01)) {
+ dev_dbg(&client->dev, "ber not ready\n");
+ break;
+ }
+
+ /* Read value */
+ ret = regmap_bulk_read(state->regmap, 0xd385, buf, 7);
+ if (ret)
+ goto err;
+
+ utmp1 = buf[4] << 16 | buf[3] << 8 | buf[2] << 0;
+ utmp2 = (buf[1] << 8 | buf[0] << 0) * 204 * 8;
+ utmp3 = buf[6] << 8 | buf[5] << 0;
+ utmp4 = buf[1] << 8 | buf[0] << 0;
+
+ /* Use 10000 TS packets for measure */
+ if (utmp4 != 10000) {
+ buf[0] = (10000 >> 0) & 0xff;
+ buf[1] = (10000 >> 8) & 0xff;
+ ret = regmap_bulk_write(state->regmap, 0xd385, buf, 2);
+ if (ret)
+ goto err;
+ }
+
+ /* Reset ber / ucb counter */
+ ret = regmap_update_bits(state->regmap, 0xd391, 0x20, 0x20);
+ if (ret)
+ goto err;
+
+ dev_dbg(&client->dev, "post_bit_error %u, post_bit_count %u\n",
+ utmp1, utmp2);
+ dev_dbg(&client->dev, "block_error %u, block_count %u\n",
+ utmp3, utmp4);
+
+ state->ber_ucb_jiffies = jiffies;
+ state->dvbv3_ber = utmp1;
+ state->dvbv3_ucblocks += utmp3;
+
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue += utmp1;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].uvalue += utmp2;
+
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[0].uvalue += utmp3;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].uvalue += utmp4;
+ break;
+ default:
+ c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+ c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ break;
+ }
return 0;
err:
@@ -801,28 +803,36 @@ err:
static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct af9013_state *state = fe->demodulator_priv;
- *snr = state->snr;
+
+ *snr = state->dvbv3_snr;
+
return 0;
}
static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
struct af9013_state *state = fe->demodulator_priv;
- *strength = state->signal_strength;
+
+ *strength = state->dvbv3_strength;
+
return 0;
}
static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct af9013_state *state = fe->demodulator_priv;
- *ber = state->ber;
+
+ *ber = state->dvbv3_ber;
+
return 0;
}
static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
struct af9013_state *state = fe->demodulator_priv;
- *ucblocks = state->ucblocks;
+
+ *ucblocks = state->dvbv3_ucblocks;
+
return 0;
}
@@ -833,7 +843,7 @@ static int af9013_init(struct dvb_frontend *fe)
int ret, i, len;
unsigned int utmp;
u8 buf[3];
- const struct af9013_reg_bit *init;
+ const struct af9013_reg_mask_val *tab;
dev_dbg(&client->dev, "\n");
@@ -888,72 +898,66 @@ static int af9013_init(struct dvb_frontend *fe)
if (ret)
goto err;
- /* load OFSM settings */
- dev_dbg(&client->dev, "load ofsm settings\n");
- len = ARRAY_SIZE(ofsm_init);
- init = ofsm_init;
+ /* Demod core settings */
+ dev_dbg(&client->dev, "load demod core settings\n");
+ len = ARRAY_SIZE(demod_init_tab);
+ tab = demod_init_tab;
for (i = 0; i < len; i++) {
- u16 reg = init[i].addr;
- u8 mask = GENMASK(init[i].pos + init[i].len - 1, init[i].pos);
- u8 val = init[i].val << init[i].pos;
-
- ret = regmap_update_bits(state->regmap, reg, mask, val);
+ ret = regmap_update_bits(state->regmap, tab[i].reg, tab[i].mask,
+ tab[i].val);
if (ret)
goto err;
}
- /* load tuner specific settings */
+ /* Demod tuner specific settings */
dev_dbg(&client->dev, "load tuner specific settings\n");
switch (state->tuner) {
case AF9013_TUNER_MXL5003D:
- len = ARRAY_SIZE(tuner_init_mxl5003d);
- init = tuner_init_mxl5003d;
+ len = ARRAY_SIZE(tuner_init_tab_mxl5003d);
+ tab = tuner_init_tab_mxl5003d;
break;
case AF9013_TUNER_MXL5005D:
case AF9013_TUNER_MXL5005R:
case AF9013_TUNER_MXL5007T:
- len = ARRAY_SIZE(tuner_init_mxl5005);
- init = tuner_init_mxl5005;
+ len = ARRAY_SIZE(tuner_init_tab_mxl5005);
+ tab = tuner_init_tab_mxl5005;
break;
case AF9013_TUNER_ENV77H11D5:
- len = ARRAY_SIZE(tuner_init_env77h11d5);
- init = tuner_init_env77h11d5;
+ len = ARRAY_SIZE(tuner_init_tab_env77h11d5);
+ tab = tuner_init_tab_env77h11d5;
break;
case AF9013_TUNER_MT2060:
- len = ARRAY_SIZE(tuner_init_mt2060);
- init = tuner_init_mt2060;
+ len = ARRAY_SIZE(tuner_init_tab_mt2060);
+ tab = tuner_init_tab_mt2060;
break;
case AF9013_TUNER_MC44S803:
- len = ARRAY_SIZE(tuner_init_mc44s803);
- init = tuner_init_mc44s803;
+ len = ARRAY_SIZE(tuner_init_tab_mc44s803);
+ tab = tuner_init_tab_mc44s803;
break;
case AF9013_TUNER_QT1010:
case AF9013_TUNER_QT1010A:
- len = ARRAY_SIZE(tuner_init_qt1010);
- init = tuner_init_qt1010;
+ len = ARRAY_SIZE(tuner_init_tab_qt1010);
+ tab = tuner_init_tab_qt1010;
break;
case AF9013_TUNER_MT2060_2:
- len = ARRAY_SIZE(tuner_init_mt2060_2);
- init = tuner_init_mt2060_2;
+ len = ARRAY_SIZE(tuner_init_tab_mt2060_2);
+ tab = tuner_init_tab_mt2060_2;
break;
case AF9013_TUNER_TDA18271:
case AF9013_TUNER_TDA18218:
- len = ARRAY_SIZE(tuner_init_tda18271);
- init = tuner_init_tda18271;
+ len = ARRAY_SIZE(tuner_init_tab_tda18271);
+ tab = tuner_init_tab_tda18271;
break;
case AF9013_TUNER_UNKNOWN:
default:
- len = ARRAY_SIZE(tuner_init_unknown);
- init = tuner_init_unknown;
+ len = ARRAY_SIZE(tuner_init_tab_unknown);
+ tab = tuner_init_tab_unknown;
break;
}
for (i = 0; i < len; i++) {
- u16 reg = init[i].addr;
- u8 mask = GENMASK(init[i].pos + init[i].len - 1, init[i].pos);
- u8 val = init[i].val << init[i].pos;
-
- ret = regmap_update_bits(state->regmap, reg, mask, val);
+ ret = regmap_update_bits(state->regmap, tab[i].reg, tab[i].mask,
+ tab[i].val);
if (ret)
goto err;
}
@@ -972,50 +976,7 @@ static int af9013_init(struct dvb_frontend *fe)
if (ret)
goto err;
- /* check if we support signal strength */
- if (!state->signal_strength_en) {
- ret = regmap_read(state->regmap, 0x9bee, &utmp);
- if (ret)
- goto err;
-
- state->signal_strength_en = (utmp >> 0) & 0x01;
- }
-
- /* read values needed for signal strength calculation */
- if (state->signal_strength_en && !state->rf_50) {
- ret = regmap_bulk_read(state->regmap, 0x9bbd, &state->rf_50, 1);
- if (ret)
- goto err;
- ret = regmap_bulk_read(state->regmap, 0x9bd0, &state->rf_80, 1);
- if (ret)
- goto err;
- ret = regmap_bulk_read(state->regmap, 0x9be2, &state->if_50, 1);
- if (ret)
- goto err;
- ret = regmap_bulk_read(state->regmap, 0x9be4, &state->if_80, 1);
- if (ret)
- goto err;
- }
-
- /* SNR */
- ret = regmap_write(state->regmap, 0xd2e2, 0x01);
- if (ret)
- goto err;
-
- /* BER / UCB */
- buf[0] = (10000 >> 0) & 0xff;
- buf[1] = (10000 >> 8) & 0xff;
- ret = regmap_bulk_write(state->regmap, 0xd385, buf, 2);
- if (ret)
- goto err;
-
- /* enable FEC monitor */
- ret = regmap_update_bits(state->regmap, 0xd392, 0x02, 0x02);
- if (ret)
- goto err;
-
state->first_tune = true;
- schedule_delayed_work(&state->statistics_work, msecs_to_jiffies(400));
return 0;
err:
@@ -1032,9 +993,6 @@ static int af9013_sleep(struct dvb_frontend *fe)
dev_dbg(&client->dev, "\n");
- /* stop statistics polling */
- cancel_delayed_work_sync(&state->statistics_work);
-
/* disable lock led */
ret = regmap_update_bits(state->regmap, 0xd730, 0x01, 0x00);
if (ret)
@@ -1072,45 +1030,6 @@ err:
return ret;
}
-static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
- int ret;
- struct af9013_state *state = fe->demodulator_priv;
- struct i2c_client *client = state->client;
-
- dev_dbg(&client->dev, "enable %d\n", enable);
-
- /* gate already open or close */
- if (state->i2c_gate_state == enable)
- return 0;
-
- if (state->ts_mode == AF9013_TS_MODE_USB)
- ret = regmap_update_bits(state->regmap, 0xd417, 0x08,
- enable << 3);
- else
- ret = regmap_update_bits(state->regmap, 0xd607, 0x04,
- enable << 2);
- if (ret)
- goto err;
-
- state->i2c_gate_state = enable;
-
- return 0;
-err:
- dev_dbg(&client->dev, "failed %d\n", ret);
- return ret;
-}
-
-static void af9013_release(struct dvb_frontend *fe)
-{
- struct af9013_state *state = fe->demodulator_priv;
- struct i2c_client *client = state->client;
-
- dev_dbg(&client->dev, "\n");
-
- i2c_unregister_device(client);
-}
-
static const struct dvb_frontend_ops af9013_ops;
static int af9013_download_firmware(struct af9013_state *state)
@@ -1213,40 +1132,6 @@ err:
return ret;
}
-/*
- * XXX: That is wrapper to af9013_probe() via driver core in order to provide
- * proper I2C client for legacy media attach binding.
- * New users must use I2C client binding directly!
- */
-struct dvb_frontend *af9013_attach(const struct af9013_config *config,
- struct i2c_adapter *i2c)
-{
- struct i2c_client *client;
- struct i2c_board_info board_info;
- struct af9013_platform_data pdata;
-
- pdata.clk = config->clock;
- pdata.tuner = config->tuner;
- pdata.if_frequency = config->if_frequency;
- pdata.ts_mode = config->ts_mode;
- pdata.ts_output_pin = 7;
- pdata.spec_inv = config->spec_inv;
- memcpy(&pdata.api_version, config->api_version, sizeof(pdata.api_version));
- memcpy(&pdata.gpio, config->gpio, sizeof(pdata.gpio));
- pdata.attach_in_use = true;
-
- memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "af9013", sizeof(board_info.type));
- board_info.addr = config->i2c_addr;
- board_info.platform_data = &pdata;
- client = i2c_new_device(i2c, &board_info);
- if (!client || !client->dev.driver)
- return NULL;
-
- return pdata.get_dvb_frontend(client);
-}
-EXPORT_SYMBOL(af9013_attach);
-
static const struct dvb_frontend_ops af9013_ops = {
.delsys = { SYS_DVBT },
.info = {
@@ -1272,8 +1157,6 @@ static const struct dvb_frontend_ops af9013_ops = {
FE_CAN_MUTE_TS
},
- .release = af9013_release,
-
.init = af9013_init,
.sleep = af9013_sleep,
@@ -1286,10 +1169,58 @@ static const struct dvb_frontend_ops af9013_ops = {
.read_signal_strength = af9013_read_signal_strength,
.read_ber = af9013_read_ber,
.read_ucblocks = af9013_read_ucblocks,
-
- .i2c_gate_ctrl = af9013_i2c_gate_ctrl,
};
+static int af9013_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
+{
+ struct af9013_state *state = fe->demodulator_priv;
+ struct i2c_client *client = state->client;
+ int ret;
+
+ dev_dbg(&client->dev, "onoff %d\n", onoff);
+
+ ret = regmap_update_bits(state->regmap, 0xd503, 0x01, onoff);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed %d\n", ret);
+ return ret;
+}
+
+static int af9013_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid,
+ int onoff)
+{
+ struct af9013_state *state = fe->demodulator_priv;
+ struct i2c_client *client = state->client;
+ int ret;
+ u8 buf[2];
+
+ dev_dbg(&client->dev, "index %d, pid %04x, onoff %d\n",
+ index, pid, onoff);
+
+ if (pid > 0x1fff) {
+ /* 0x2000 is kernel virtual pid for whole ts (all pids) */
+ ret = 0;
+ goto err;
+ }
+
+ buf[0] = (pid >> 0) & 0xff;
+ buf[1] = (pid >> 8) & 0xff;
+ ret = regmap_bulk_write(state->regmap, 0xd505, buf, 2);
+ if (ret)
+ goto err;
+ ret = regmap_write(state->regmap, 0xd504, onoff << 5 | index << 0);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed %d\n", ret);
+ return ret;
+}
+
static struct dvb_frontend *af9013_get_dvb_frontend(struct i2c_client *client)
{
struct af9013_state *state = i2c_get_clientdata(client);
@@ -1299,9 +1230,65 @@ static struct dvb_frontend *af9013_get_dvb_frontend(struct i2c_client *client)
return &state->fe;
}
+static struct i2c_adapter *af9013_get_i2c_adapter(struct i2c_client *client)
+{
+ struct af9013_state *state = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "\n");
+
+ return state->muxc->adapter[0];
+}
+
+/*
+ * XXX: Hackish solution. We use virtual register, reg bit 16, to carry info
+ * about i2c adapter locking. Own locking is needed because i2c mux call has
+ * already locked i2c adapter.
+ */
+static int af9013_select(struct i2c_mux_core *muxc, u32 chan)
+{
+ struct af9013_state *state = i2c_mux_priv(muxc);
+ struct i2c_client *client = state->client;
+ int ret;
+
+ dev_dbg(&client->dev, "\n");
+
+ if (state->ts_mode == AF9013_TS_MODE_USB)
+ ret = regmap_update_bits(state->regmap, 0x1d417, 0x08, 0x08);
+ else
+ ret = regmap_update_bits(state->regmap, 0x1d607, 0x04, 0x04);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed %d\n", ret);
+ return ret;
+}
+
+static int af9013_deselect(struct i2c_mux_core *muxc, u32 chan)
+{
+ struct af9013_state *state = i2c_mux_priv(muxc);
+ struct i2c_client *client = state->client;
+ int ret;
+
+ dev_dbg(&client->dev, "\n");
+
+ if (state->ts_mode == AF9013_TS_MODE_USB)
+ ret = regmap_update_bits(state->regmap, 0x1d417, 0x08, 0x00);
+ else
+ ret = regmap_update_bits(state->regmap, 0x1d607, 0x04, 0x00);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed %d\n", ret);
+ return ret;
+}
+
/* Own I2C access routines needed for regmap as chip uses extra command byte */
static int af9013_wregs(struct i2c_client *client, u8 cmd, u16 reg,
- const u8 *val, int len)
+ const u8 *val, int len, u8 lock)
{
int ret;
u8 buf[21];
@@ -1323,7 +1310,12 @@ static int af9013_wregs(struct i2c_client *client, u8 cmd, u16 reg,
buf[1] = (reg >> 0) & 0xff;
buf[2] = cmd;
memcpy(&buf[3], val, len);
- ret = i2c_transfer(client->adapter, msg, 1);
+
+ if (lock)
+ i2c_lock_adapter(client->adapter);
+ ret = __i2c_transfer(client->adapter, msg, 1);
+ if (lock)
+ i2c_unlock_adapter(client->adapter);
if (ret < 0) {
goto err;
} else if (ret != 1) {
@@ -1338,7 +1330,7 @@ err:
}
static int af9013_rregs(struct i2c_client *client, u8 cmd, u16 reg,
- u8 *val, int len)
+ u8 *val, int len, u8 lock)
{
int ret;
u8 buf[3];
@@ -1359,7 +1351,12 @@ static int af9013_rregs(struct i2c_client *client, u8 cmd, u16 reg,
buf[0] = (reg >> 8) & 0xff;
buf[1] = (reg >> 0) & 0xff;
buf[2] = cmd;
- ret = i2c_transfer(client->adapter, msg, 2);
+
+ if (lock)
+ i2c_lock_adapter(client->adapter);
+ ret = __i2c_transfer(client->adapter, msg, 2);
+ if (lock)
+ i2c_unlock_adapter(client->adapter);
if (ret < 0) {
goto err;
} else if (ret != 2) {
@@ -1379,25 +1376,27 @@ static int af9013_regmap_write(void *context, const void *data, size_t count)
struct af9013_state *state = i2c_get_clientdata(client);
int ret, i;
u8 cmd;
- u16 reg = ((u8 *)data)[0] << 8|((u8 *)data)[1] << 0;
- u8 *val = &((u8 *)data)[2];
- const unsigned int len = count - 2;
+ u8 lock = !((u8 *)data)[0];
+ u16 reg = ((u8 *)data)[1] << 8 | ((u8 *)data)[2] << 0;
+ u8 *val = &((u8 *)data)[3];
+ const unsigned int len = count - 3;
if (state->ts_mode == AF9013_TS_MODE_USB && (reg & 0xff00) != 0xae00) {
cmd = 0 << 7|0 << 6|(len - 1) << 2|1 << 1|1 << 0;
- ret = af9013_wregs(client, cmd, reg, val, len);
+ ret = af9013_wregs(client, cmd, reg, val, len, lock);
if (ret)
goto err;
} else if (reg >= 0x5100 && reg < 0x8fff) {
/* Firmware download */
cmd = 1 << 7|1 << 6|(len - 1) << 2|1 << 1|1 << 0;
- ret = af9013_wregs(client, cmd, reg, val, len);
+ ret = af9013_wregs(client, cmd, reg, val, len, lock);
if (ret)
goto err;
} else {
cmd = 0 << 7|0 << 6|(1 - 1) << 2|1 << 1|1 << 0;
for (i = 0; i < len; i++) {
- ret = af9013_wregs(client, cmd, reg + i, val + i, 1);
+ ret = af9013_wregs(client, cmd, reg + i, val + i, 1,
+ lock);
if (ret)
goto err;
}
@@ -1416,19 +1415,21 @@ static int af9013_regmap_read(void *context, const void *reg_buf,
struct af9013_state *state = i2c_get_clientdata(client);
int ret, i;
u8 cmd;
- u16 reg = ((u8 *)reg_buf)[0] << 8|((u8 *)reg_buf)[1] << 0;
+ u8 lock = !((u8 *)reg_buf)[0];
+ u16 reg = ((u8 *)reg_buf)[1] << 8 | ((u8 *)reg_buf)[2] << 0;
u8 *val = &((u8 *)val_buf)[0];
const unsigned int len = val_size;
if (state->ts_mode == AF9013_TS_MODE_USB && (reg & 0xff00) != 0xae00) {
cmd = 0 << 7|0 << 6|(len - 1) << 2|1 << 1|0 << 0;
- ret = af9013_rregs(client, cmd, reg, val_buf, len);
+ ret = af9013_rregs(client, cmd, reg, val_buf, len, lock);
if (ret)
goto err;
} else {
cmd = 0 << 7|0 << 6|(1 - 1) << 2|1 << 1|0 << 0;
for (i = 0; i < len; i++) {
- ret = af9013_rregs(client, cmd, reg + i, val + i, 1);
+ ret = af9013_rregs(client, cmd, reg + i, val + i, 1,
+ lock);
if (ret)
goto err;
}
@@ -1453,8 +1454,9 @@ static int af9013_probe(struct i2c_client *client,
.write = af9013_regmap_write,
};
static const struct regmap_config regmap_config = {
- .reg_bits = 16,
- .val_bits = 8,
+ /* Actual reg is 16 bits, see i2c adapter lock */
+ .reg_bits = 24,
+ .val_bits = 8,
};
state = kzalloc(sizeof(*state), GFP_KERNEL);
@@ -1463,6 +1465,8 @@ static int af9013_probe(struct i2c_client *client,
goto err;
}
+ dev_dbg(&client->dev, "\n");
+
/* Setup the state */
state->client = client;
i2c_set_clientdata(client, state);
@@ -1474,52 +1478,70 @@ static int af9013_probe(struct i2c_client *client,
state->spec_inv = pdata->spec_inv;
memcpy(&state->api_version, pdata->api_version, sizeof(state->api_version));
memcpy(&state->gpio, pdata->gpio, sizeof(state->gpio));
- INIT_DELAYED_WORK(&state->statistics_work, af9013_statistics_work);
state->regmap = regmap_init(&client->dev, &regmap_bus, client,
&regmap_config);
if (IS_ERR(state->regmap)) {
ret = PTR_ERR(state->regmap);
goto err_kfree;
}
+ /* Create mux i2c adapter */
+ state->muxc = i2c_mux_alloc(client->adapter, &client->dev, 1, 0, 0,
+ af9013_select, af9013_deselect);
+ if (!state->muxc) {
+ ret = -ENOMEM;
+ goto err_regmap_exit;
+ }
+ state->muxc->priv = state;
+ ret = i2c_mux_add_adapter(state->muxc, 0, 0, 0);
+ if (ret)
+ goto err_regmap_exit;
/* Download firmware */
if (state->ts_mode != AF9013_TS_MODE_USB) {
ret = af9013_download_firmware(state);
if (ret)
- goto err_regmap_exit;
+ goto err_i2c_mux_del_adapters;
}
/* Firmware version */
ret = regmap_bulk_read(state->regmap, 0x5103, firmware_version,
sizeof(firmware_version));
if (ret)
- goto err_regmap_exit;
+ goto err_i2c_mux_del_adapters;
/* Set GPIOs */
for (i = 0; i < sizeof(state->gpio); i++) {
ret = af9013_set_gpio(state, i, state->gpio[i]);
if (ret)
- goto err_regmap_exit;
+ goto err_i2c_mux_del_adapters;
}
/* Create dvb frontend */
memcpy(&state->fe.ops, &af9013_ops, sizeof(state->fe.ops));
- if (!pdata->attach_in_use)
- state->fe.ops.release = NULL;
state->fe.demodulator_priv = state;
/* Setup callbacks */
pdata->get_dvb_frontend = af9013_get_dvb_frontend;
+ pdata->get_i2c_adapter = af9013_get_i2c_adapter;
+ pdata->pid_filter = af9013_pid_filter;
+ pdata->pid_filter_ctrl = af9013_pid_filter_ctrl;
/* Init stats to indicate which stats are supported */
c = &state->fe.dtv_property_cache;
+ c->strength.len = 1;
c->cnr.len = 1;
+ c->post_bit_error.len = 1;
+ c->post_bit_count.len = 1;
+ c->block_error.len = 1;
+ c->block_count.len = 1;
dev_info(&client->dev, "Afatech AF9013 successfully attached\n");
dev_info(&client->dev, "firmware version: %d.%d.%d.%d\n",
firmware_version[0], firmware_version[1],
firmware_version[2], firmware_version[3]);
return 0;
+err_i2c_mux_del_adapters:
+ i2c_mux_del_adapters(state->muxc);
err_regmap_exit:
regmap_exit(state->regmap);
err_kfree:
@@ -1535,8 +1557,7 @@ static int af9013_remove(struct i2c_client *client)
dev_dbg(&client->dev, "\n");
- /* Stop statistics polling */
- cancel_delayed_work_sync(&state->statistics_work);
+ i2c_mux_del_adapters(state->muxc);
regmap_exit(state->regmap);
diff --git a/drivers/media/dvb-frontends/af9013.h b/drivers/media/dvb-frontends/af9013.h
index a290722c04fd..165ae29ccac4 100644
--- a/drivers/media/dvb-frontends/af9013.h
+++ b/drivers/media/dvb-frontends/af9013.h
@@ -38,13 +38,9 @@
* @api_version: Firmware API version.
* @gpio: GPIOs.
* @get_dvb_frontend: Get DVB frontend callback.
- *
- * AF9013/5 GPIOs (mostly guessed):
- * * demod#1-gpio#0 - set demod#2 i2c-addr for dual devices
- * * demod#1-gpio#1 - xtal setting (?)
- * * demod#1-gpio#3 - tuner#1
- * * demod#2-gpio#0 - tuner#2
- * * demod#2-gpio#1 - xtal setting (?)
+ * @get_i2c_adapter: Get I2C adapter.
+ * @pid_filter_ctrl: Control PID filter.
+ * @pid_filter: Set PID to PID filter.
*/
struct af9013_platform_data {
/*
@@ -84,36 +80,18 @@ struct af9013_platform_data {
u8 gpio[4];
struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *);
-
-/* private: For legacy media attach wrapper. Do not set value. */
- bool attach_in_use;
- u8 i2c_addr;
- u32 clock;
+ struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *);
+ int (*pid_filter_ctrl)(struct dvb_frontend *, int);
+ int (*pid_filter)(struct dvb_frontend *, u8, u16, int);
};
-#define af9013_config af9013_platform_data
-#define AF9013_TS_USB AF9013_TS_MODE_USB
-#define AF9013_TS_PARALLEL AF9013_TS_MODE_PARALLEL
-#define AF9013_TS_SERIAL AF9013_TS_MODE_SERIAL
-
-#if IS_REACHABLE(CONFIG_DVB_AF9013)
-/**
- * Attach an af9013 demod
- *
- * @config: pointer to &struct af9013_config with demod configuration.
- * @i2c: i2c adapter to use.
- *
- * return: FE pointer on success, NULL on failure.
+/*
+ * AF9013/5 GPIOs (mostly guessed)
+ * demod#1-gpio#0 - set demod#2 i2c-addr for dual devices
+ * demod#1-gpio#1 - xtal setting (?)
+ * demod#1-gpio#3 - tuner#1
+ * demod#2-gpio#0 - tuner#2
+ * demod#2-gpio#1 - xtal setting (?)
*/
-extern struct dvb_frontend *af9013_attach(const struct af9013_config *config,
- struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *af9013_attach(
-const struct af9013_config *config, struct i2c_adapter *i2c)
-{
- pr_warn("%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-#endif /* CONFIG_DVB_AF9013 */
#endif /* AF9013_H */
diff --git a/drivers/media/dvb-frontends/af9013_priv.h b/drivers/media/dvb-frontends/af9013_priv.h
index 688fc3472cf6..3e95de7dba51 100644
--- a/drivers/media/dvb-frontends/af9013_priv.h
+++ b/drivers/media/dvb-frontends/af9013_priv.h
@@ -22,25 +22,21 @@
#define AF9013_PRIV_H
#include <media/dvb_frontend.h>
+#include <media/dvb_math.h>
#include "af9013.h"
#include <linux/firmware.h>
+#include <linux/i2c-mux.h>
#include <linux/math64.h>
#include <linux/regmap.h>
#define AF9013_FIRMWARE "dvb-fe-af9013.fw"
-struct af9013_reg_bit {
- u16 addr;
- u8 pos:4;
- u8 len:4;
+struct af9013_reg_mask_val {
+ u16 reg;
+ u8 mask;
u8 val;
};
-struct af9013_snr {
- u32 val;
- u8 snr;
-};
-
struct af9013_coeff {
u32 clock;
u32 bandwidth_hz;
@@ -91,817 +87,775 @@ static const struct af9013_coeff coeff_lut[] = {
0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } },
};
-/* QPSK SNR lookup table */
-static const struct af9013_snr qpsk_snr_lut[] = {
- { 0x000000, 0 },
- { 0x0b4771, 0 },
- { 0x0c1aed, 1 },
- { 0x0d0d27, 2 },
- { 0x0e4d19, 3 },
- { 0x0e5da8, 4 },
- { 0x107097, 5 },
- { 0x116975, 6 },
- { 0x1252d9, 7 },
- { 0x131fa4, 8 },
- { 0x13d5e1, 9 },
- { 0x148e53, 10 },
- { 0x15358b, 11 },
- { 0x15dd29, 12 },
- { 0x168112, 13 },
- { 0x170b61, 14 },
- { 0xffffff, 15 },
-};
-
-/* QAM16 SNR lookup table */
-static const struct af9013_snr qam16_snr_lut[] = {
- { 0x000000, 0 },
- { 0x05eb62, 5 },
- { 0x05fecf, 6 },
- { 0x060b80, 7 },
- { 0x062501, 8 },
- { 0x064865, 9 },
- { 0x069604, 10 },
- { 0x06f356, 11 },
- { 0x07706a, 12 },
- { 0x0804d3, 13 },
- { 0x089d1a, 14 },
- { 0x093e3d, 15 },
- { 0x09e35d, 16 },
- { 0x0a7c3c, 17 },
- { 0x0afaf8, 18 },
- { 0x0b719d, 19 },
- { 0xffffff, 20 },
-};
-
-/* QAM64 SNR lookup table */
-static const struct af9013_snr qam64_snr_lut[] = {
- { 0x000000, 0 },
- { 0x03109b, 12 },
- { 0x0310d4, 13 },
- { 0x031920, 14 },
- { 0x0322d0, 15 },
- { 0x0339fc, 16 },
- { 0x0364a1, 17 },
- { 0x038bcc, 18 },
- { 0x03c7d3, 19 },
- { 0x0408cc, 20 },
- { 0x043bed, 21 },
- { 0x048061, 22 },
- { 0x04be95, 23 },
- { 0x04fa7d, 24 },
- { 0x052405, 25 },
- { 0x05570d, 26 },
- { 0xffffff, 27 },
-};
-
-static const struct af9013_reg_bit ofsm_init[] = {
- { 0xd73a, 0, 8, 0xa1 },
- { 0xd73b, 0, 8, 0x1f },
- { 0xd73c, 4, 4, 0x0a },
- { 0xd732, 3, 1, 0x00 },
- { 0xd731, 4, 2, 0x03 },
- { 0xd73d, 7, 1, 0x01 },
- { 0xd740, 0, 1, 0x00 },
- { 0xd740, 1, 1, 0x00 },
- { 0xd740, 2, 1, 0x00 },
- { 0xd740, 3, 1, 0x01 },
- { 0xd3c1, 4, 1, 0x01 },
- { 0x9124, 0, 8, 0x58 },
- { 0x9125, 0, 2, 0x02 },
- { 0xd3a2, 0, 8, 0x00 },
- { 0xd3a3, 0, 8, 0x04 },
- { 0xd305, 0, 8, 0x32 },
- { 0xd306, 0, 8, 0x10 },
- { 0xd304, 0, 8, 0x04 },
- { 0x9112, 0, 1, 0x01 },
- { 0x911d, 0, 1, 0x01 },
- { 0x911a, 0, 1, 0x01 },
- { 0x911b, 0, 1, 0x01 },
- { 0x9bce, 0, 4, 0x02 },
- { 0x9116, 0, 1, 0x01 },
- { 0x9122, 0, 8, 0xd0 },
- { 0xd2e0, 0, 8, 0xd0 },
- { 0xd2e9, 0, 4, 0x0d },
- { 0xd38c, 0, 8, 0xfc },
- { 0xd38d, 0, 8, 0x00 },
- { 0xd38e, 0, 8, 0x7e },
- { 0xd38f, 0, 8, 0x00 },
- { 0xd390, 0, 8, 0x2f },
- { 0xd145, 4, 1, 0x01 },
- { 0xd1a9, 4, 1, 0x01 },
- { 0xd158, 5, 3, 0x01 },
- { 0xd159, 0, 6, 0x06 },
- { 0xd167, 0, 8, 0x00 },
- { 0xd168, 0, 4, 0x07 },
- { 0xd1c3, 5, 3, 0x00 },
- { 0xd1c4, 0, 6, 0x00 },
- { 0xd1c5, 0, 7, 0x10 },
- { 0xd1c6, 0, 3, 0x02 },
- { 0xd080, 2, 5, 0x03 },
- { 0xd081, 4, 4, 0x09 },
- { 0xd098, 4, 4, 0x0f },
- { 0xd098, 0, 4, 0x03 },
- { 0xdbc0, 4, 1, 0x01 },
- { 0xdbc7, 0, 8, 0x08 },
- { 0xdbc8, 4, 4, 0x00 },
- { 0xdbc9, 0, 5, 0x01 },
- { 0xd280, 0, 8, 0xe0 },
- { 0xd281, 0, 8, 0xff },
- { 0xd282, 0, 8, 0xff },
- { 0xd283, 0, 8, 0xc3 },
- { 0xd284, 0, 8, 0xff },
- { 0xd285, 0, 4, 0x01 },
- { 0xd0f0, 0, 7, 0x1a },
- { 0xd0f1, 4, 1, 0x01 },
- { 0xd0f2, 0, 8, 0x0c },
- { 0xd101, 5, 3, 0x06 },
- { 0xd103, 0, 4, 0x08 },
- { 0xd0f8, 0, 7, 0x20 },
- { 0xd111, 5, 1, 0x00 },
- { 0xd111, 6, 1, 0x00 },
- { 0x910b, 0, 8, 0x0a },
- { 0x9115, 0, 8, 0x02 },
- { 0x910c, 0, 8, 0x02 },
- { 0x910d, 0, 8, 0x08 },
- { 0x910e, 0, 8, 0x0a },
- { 0x9bf6, 0, 8, 0x06 },
- { 0x9bf8, 0, 8, 0x02 },
- { 0x9bf7, 0, 8, 0x05 },
- { 0x9bf9, 0, 8, 0x0f },
- { 0x9bfc, 0, 8, 0x13 },
- { 0x9bd3, 0, 8, 0xff },
- { 0x9bbe, 0, 1, 0x01 },
- { 0x9bcc, 0, 1, 0x01 },
+/*
+ * Afatech AF9013 demod init
+ */
+static const struct af9013_reg_mask_val demod_init_tab[] = {
+ {0xd73a, 0xff, 0xa1},
+ {0xd73b, 0xff, 0x1f},
+ {0xd73c, 0xf0, 0xa0},
+ {0xd732, 0x08, 0x00},
+ {0xd731, 0x30, 0x30},
+ {0xd73d, 0x80, 0x80},
+ {0xd740, 0x01, 0x00},
+ {0xd740, 0x02, 0x00},
+ {0xd740, 0x04, 0x00},
+ {0xd740, 0x08, 0x08},
+ {0xd3c1, 0x10, 0x10},
+ {0x9124, 0xff, 0x58},
+ {0x9125, 0x03, 0x02},
+ {0xd3a2, 0xff, 0x00},
+ {0xd3a3, 0xff, 0x04},
+ {0xd305, 0xff, 0x32},
+ {0xd306, 0xff, 0x10},
+ {0xd304, 0xff, 0x04},
+ {0x9112, 0x01, 0x01},
+ {0x911d, 0x01, 0x01},
+ {0x911a, 0x01, 0x01},
+ {0x911b, 0x01, 0x01},
+ {0x9bce, 0x0f, 0x02},
+ {0x9116, 0x01, 0x01},
+ {0x9122, 0xff, 0xd0},
+ {0xd2e0, 0xff, 0xd0},
+ {0xd2e9, 0x0f, 0x0d},
+ {0xd38c, 0xff, 0xfc},
+ {0xd38d, 0xff, 0x00},
+ {0xd38e, 0xff, 0x7e},
+ {0xd38f, 0xff, 0x00},
+ {0xd390, 0xff, 0x2f},
+ {0xd145, 0x10, 0x10},
+ {0xd1a9, 0x10, 0x10},
+ {0xd158, 0xe0, 0x20},
+ {0xd159, 0x3f, 0x06},
+ {0xd167, 0xff, 0x00},
+ {0xd168, 0x0f, 0x07},
+ {0xd1c3, 0xe0, 0x00},
+ {0xd1c4, 0x3f, 0x00},
+ {0xd1c5, 0x7f, 0x10},
+ {0xd1c6, 0x07, 0x02},
+ {0xd080, 0x7c, 0x0c},
+ {0xd081, 0xf0, 0x90},
+ {0xd098, 0xf0, 0xf0},
+ {0xd098, 0x0f, 0x03},
+ {0xdbc0, 0x10, 0x10},
+ {0xdbc7, 0xff, 0x08},
+ {0xdbc8, 0xf0, 0x00},
+ {0xdbc9, 0x1f, 0x01},
+ {0xd280, 0xff, 0xe0},
+ {0xd281, 0xff, 0xff},
+ {0xd282, 0xff, 0xff},
+ {0xd283, 0xff, 0xc3},
+ {0xd284, 0xff, 0xff},
+ {0xd285, 0x0f, 0x01},
+ {0xd0f0, 0x7f, 0x1a},
+ {0xd0f1, 0x10, 0x10},
+ {0xd0f2, 0xff, 0x0c},
+ {0xd101, 0xe0, 0xc0},
+ {0xd103, 0x0f, 0x08},
+ {0xd0f8, 0x7f, 0x20},
+ {0xd111, 0x20, 0x00},
+ {0xd111, 0x40, 0x00},
+ {0x910b, 0xff, 0x0a},
+ {0x9115, 0xff, 0x02},
+ {0x910c, 0xff, 0x02},
+ {0x910d, 0xff, 0x08},
+ {0x910e, 0xff, 0x0a},
+ {0x9bf6, 0xff, 0x06},
+ {0x9bf8, 0xff, 0x02},
+ {0x9bf7, 0xff, 0x05},
+ {0x9bf9, 0xff, 0x0f},
+ {0x9bfc, 0xff, 0x13},
+ {0x9bd3, 0xff, 0xff},
+ {0x9bbe, 0x01, 0x01},
+ {0x9bcc, 0x01, 0x01},
};
-/* Panasonic ENV77H11D5 tuner init
- AF9013_TUNER_ENV77H11D5 = 129 */
-static const struct af9013_reg_bit tuner_init_env77h11d5[] = {
- { 0x9bd5, 0, 8, 0x01 },
- { 0x9bd6, 0, 8, 0x03 },
- { 0x9bbe, 0, 8, 0x01 },
- { 0xd1a0, 1, 1, 0x01 },
- { 0xd000, 0, 1, 0x01 },
- { 0xd000, 1, 1, 0x00 },
- { 0xd001, 1, 1, 0x01 },
- { 0xd001, 0, 1, 0x00 },
- { 0xd001, 5, 1, 0x00 },
- { 0xd002, 0, 5, 0x19 },
- { 0xd003, 0, 5, 0x1a },
- { 0xd004, 0, 5, 0x19 },
- { 0xd005, 0, 5, 0x1a },
- { 0xd00e, 0, 5, 0x10 },
- { 0xd00f, 0, 3, 0x04 },
- { 0xd00f, 3, 3, 0x05 },
- { 0xd010, 0, 3, 0x04 },
- { 0xd010, 3, 3, 0x05 },
- { 0xd016, 4, 4, 0x03 },
- { 0xd01f, 0, 6, 0x0a },
- { 0xd020, 0, 6, 0x0a },
- { 0x9bda, 0, 8, 0x00 },
- { 0x9be3, 0, 8, 0x00 },
- { 0xd015, 0, 8, 0x50 },
- { 0xd016, 0, 1, 0x00 },
- { 0xd044, 0, 8, 0x46 },
- { 0xd045, 0, 1, 0x00 },
- { 0xd008, 0, 8, 0xdf },
- { 0xd009, 0, 2, 0x02 },
- { 0xd006, 0, 8, 0x44 },
- { 0xd007, 0, 2, 0x01 },
- { 0xd00c, 0, 8, 0xeb },
- { 0xd00d, 0, 2, 0x02 },
- { 0xd00a, 0, 8, 0xf4 },
- { 0xd00b, 0, 2, 0x01 },
- { 0x9bba, 0, 8, 0xf9 },
- { 0x9bc3, 0, 8, 0xdf },
- { 0x9bc4, 0, 8, 0x02 },
- { 0x9bc5, 0, 8, 0xeb },
- { 0x9bc6, 0, 8, 0x02 },
- { 0x9bc9, 0, 8, 0x52 },
- { 0xd011, 0, 8, 0x3c },
- { 0xd012, 0, 2, 0x01 },
- { 0xd013, 0, 8, 0xf7 },
- { 0xd014, 0, 2, 0x02 },
- { 0xd040, 0, 8, 0x0b },
- { 0xd041, 0, 2, 0x02 },
- { 0xd042, 0, 8, 0x4d },
- { 0xd043, 0, 2, 0x00 },
- { 0xd045, 1, 1, 0x00 },
- { 0x9bcf, 0, 1, 0x01 },
- { 0xd045, 2, 1, 0x01 },
- { 0xd04f, 0, 8, 0x9a },
- { 0xd050, 0, 1, 0x01 },
- { 0xd051, 0, 8, 0x5a },
- { 0xd052, 0, 1, 0x01 },
- { 0xd053, 0, 8, 0x50 },
- { 0xd054, 0, 8, 0x46 },
- { 0x9bd7, 0, 8, 0x0a },
- { 0x9bd8, 0, 8, 0x14 },
- { 0x9bd9, 0, 8, 0x08 },
+/*
+ * Panasonic ENV77H11D5 tuner init
+ * AF9013_TUNER_ENV77H11D5 0x81
+ */
+static const struct af9013_reg_mask_val tuner_init_tab_env77h11d5[] = {
+ {0x9bd5, 0xff, 0x01},
+ {0x9bd6, 0xff, 0x03},
+ {0x9bbe, 0xff, 0x01},
+ {0xd1a0, 0x02, 0x02},
+ {0xd000, 0x01, 0x01},
+ {0xd000, 0x02, 0x00},
+ {0xd001, 0x02, 0x02},
+ {0xd001, 0x01, 0x00},
+ {0xd001, 0x20, 0x00},
+ {0xd002, 0x1f, 0x19},
+ {0xd003, 0x1f, 0x1a},
+ {0xd004, 0x1f, 0x19},
+ {0xd005, 0x1f, 0x1a},
+ {0xd00e, 0x1f, 0x10},
+ {0xd00f, 0x07, 0x04},
+ {0xd00f, 0x38, 0x28},
+ {0xd010, 0x07, 0x04},
+ {0xd010, 0x38, 0x28},
+ {0xd016, 0xf0, 0x30},
+ {0xd01f, 0x3f, 0x0a},
+ {0xd020, 0x3f, 0x0a},
+ {0x9bda, 0xff, 0x00},
+ {0x9be3, 0xff, 0x00},
+ {0xd015, 0xff, 0x50},
+ {0xd016, 0x01, 0x00},
+ {0xd044, 0xff, 0x46},
+ {0xd045, 0x01, 0x00},
+ {0xd008, 0xff, 0xdf},
+ {0xd009, 0x03, 0x02},
+ {0xd006, 0xff, 0x44},
+ {0xd007, 0x03, 0x01},
+ {0xd00c, 0xff, 0xeb},
+ {0xd00d, 0x03, 0x02},
+ {0xd00a, 0xff, 0xf4},
+ {0xd00b, 0x03, 0x01},
+ {0x9bba, 0xff, 0xf9},
+ {0x9bc3, 0xff, 0xdf},
+ {0x9bc4, 0xff, 0x02},
+ {0x9bc5, 0xff, 0xeb},
+ {0x9bc6, 0xff, 0x02},
+ {0x9bc9, 0xff, 0x52},
+ {0xd011, 0xff, 0x3c},
+ {0xd012, 0x03, 0x01},
+ {0xd013, 0xff, 0xf7},
+ {0xd014, 0x03, 0x02},
+ {0xd040, 0xff, 0x0b},
+ {0xd041, 0x03, 0x02},
+ {0xd042, 0xff, 0x4d},
+ {0xd043, 0x03, 0x00},
+ {0xd045, 0x02, 0x00},
+ {0x9bcf, 0x01, 0x01},
+ {0xd045, 0x04, 0x04},
+ {0xd04f, 0xff, 0x9a},
+ {0xd050, 0x01, 0x01},
+ {0xd051, 0xff, 0x5a},
+ {0xd052, 0x01, 0x01},
+ {0xd053, 0xff, 0x50},
+ {0xd054, 0xff, 0x46},
+ {0x9bd7, 0xff, 0x0a},
+ {0x9bd8, 0xff, 0x14},
+ {0x9bd9, 0xff, 0x08},
};
-/* Microtune MT2060 tuner init
- AF9013_TUNER_MT2060 = 130 */
-static const struct af9013_reg_bit tuner_init_mt2060[] = {
- { 0x9bd5, 0, 8, 0x01 },
- { 0x9bd6, 0, 8, 0x07 },
- { 0xd1a0, 1, 1, 0x01 },
- { 0xd000, 0, 1, 0x01 },
- { 0xd000, 1, 1, 0x00 },
- { 0xd001, 1, 1, 0x01 },
- { 0xd001, 0, 1, 0x00 },
- { 0xd001, 5, 1, 0x00 },
- { 0xd002, 0, 5, 0x19 },
- { 0xd003, 0, 5, 0x1a },
- { 0xd004, 0, 5, 0x19 },
- { 0xd005, 0, 5, 0x1a },
- { 0xd00e, 0, 5, 0x10 },
- { 0xd00f, 0, 3, 0x04 },
- { 0xd00f, 3, 3, 0x05 },
- { 0xd010, 0, 3, 0x04 },
- { 0xd010, 3, 3, 0x05 },
- { 0xd016, 4, 4, 0x03 },
- { 0xd01f, 0, 6, 0x0a },
- { 0xd020, 0, 6, 0x0a },
- { 0x9bda, 0, 8, 0x00 },
- { 0x9be3, 0, 8, 0x00 },
- { 0x9bbe, 0, 1, 0x00 },
- { 0x9bcc, 0, 1, 0x00 },
- { 0x9bb9, 0, 8, 0x75 },
- { 0x9bcd, 0, 8, 0x24 },
- { 0x9bff, 0, 8, 0x30 },
- { 0xd015, 0, 8, 0x46 },
- { 0xd016, 0, 1, 0x00 },
- { 0xd044, 0, 8, 0x46 },
- { 0xd045, 0, 1, 0x00 },
- { 0xd008, 0, 8, 0x0f },
- { 0xd009, 0, 2, 0x02 },
- { 0xd006, 0, 8, 0x32 },
- { 0xd007, 0, 2, 0x01 },
- { 0xd00c, 0, 8, 0x36 },
- { 0xd00d, 0, 2, 0x03 },
- { 0xd00a, 0, 8, 0x35 },
- { 0xd00b, 0, 2, 0x01 },
- { 0x9bc7, 0, 8, 0x07 },
- { 0x9bc8, 0, 8, 0x90 },
- { 0x9bc3, 0, 8, 0x0f },
- { 0x9bc4, 0, 8, 0x02 },
- { 0x9bc5, 0, 8, 0x36 },
- { 0x9bc6, 0, 8, 0x03 },
- { 0x9bba, 0, 8, 0xc9 },
- { 0x9bc9, 0, 8, 0x79 },
- { 0xd011, 0, 8, 0x10 },
- { 0xd012, 0, 2, 0x01 },
- { 0xd013, 0, 8, 0x45 },
- { 0xd014, 0, 2, 0x03 },
- { 0xd040, 0, 8, 0x98 },
- { 0xd041, 0, 2, 0x00 },
- { 0xd042, 0, 8, 0xcf },
- { 0xd043, 0, 2, 0x03 },
- { 0xd045, 1, 1, 0x00 },
- { 0x9bcf, 0, 1, 0x01 },
- { 0xd045, 2, 1, 0x01 },
- { 0xd04f, 0, 8, 0x9a },
- { 0xd050, 0, 1, 0x01 },
- { 0xd051, 0, 8, 0x5a },
- { 0xd052, 0, 1, 0x01 },
- { 0xd053, 0, 8, 0x50 },
- { 0xd054, 0, 8, 0x46 },
- { 0x9bd7, 0, 8, 0x0a },
- { 0x9bd8, 0, 8, 0x14 },
- { 0x9bd9, 0, 8, 0x08 },
- { 0x9bd0, 0, 8, 0xcc },
- { 0x9be4, 0, 8, 0xa0 },
- { 0x9bbd, 0, 8, 0x8e },
- { 0x9be2, 0, 8, 0x4d },
- { 0x9bee, 0, 1, 0x01 },
+/*
+ * Microtune MT2060 tuner init
+ * AF9013_TUNER_MT2060 0x82
+ */
+static const struct af9013_reg_mask_val tuner_init_tab_mt2060[] = {
+ {0x9bd5, 0xff, 0x01},
+ {0x9bd6, 0xff, 0x07},
+ {0xd1a0, 0x02, 0x02},
+ {0xd000, 0x01, 0x01},
+ {0xd000, 0x02, 0x00},
+ {0xd001, 0x02, 0x02},
+ {0xd001, 0x01, 0x00},
+ {0xd001, 0x20, 0x00},
+ {0xd002, 0x1f, 0x19},
+ {0xd003, 0x1f, 0x1a},
+ {0xd004, 0x1f, 0x19},
+ {0xd005, 0x1f, 0x1a},
+ {0xd00e, 0x1f, 0x10},
+ {0xd00f, 0x07, 0x04},
+ {0xd00f, 0x38, 0x28},
+ {0xd010, 0x07, 0x04},
+ {0xd010, 0x38, 0x28},
+ {0xd016, 0xf0, 0x30},
+ {0xd01f, 0x3f, 0x0a},
+ {0xd020, 0x3f, 0x0a},
+ {0x9bda, 0xff, 0x00},
+ {0x9be3, 0xff, 0x00},
+ {0x9bbe, 0x01, 0x00},
+ {0x9bcc, 0x01, 0x00},
+ {0x9bb9, 0xff, 0x75},
+ {0x9bcd, 0xff, 0x24},
+ {0x9bff, 0xff, 0x30},
+ {0xd015, 0xff, 0x46},
+ {0xd016, 0x01, 0x00},
+ {0xd044, 0xff, 0x46},
+ {0xd045, 0x01, 0x00},
+ {0xd008, 0xff, 0x0f},
+ {0xd009, 0x03, 0x02},
+ {0xd006, 0xff, 0x32},
+ {0xd007, 0x03, 0x01},
+ {0xd00c, 0xff, 0x36},
+ {0xd00d, 0x03, 0x03},
+ {0xd00a, 0xff, 0x35},
+ {0xd00b, 0x03, 0x01},
+ {0x9bc7, 0xff, 0x07},
+ {0x9bc8, 0xff, 0x90},
+ {0x9bc3, 0xff, 0x0f},
+ {0x9bc4, 0xff, 0x02},
+ {0x9bc5, 0xff, 0x36},
+ {0x9bc6, 0xff, 0x03},
+ {0x9bba, 0xff, 0xc9},
+ {0x9bc9, 0xff, 0x79},
+ {0xd011, 0xff, 0x10},
+ {0xd012, 0x03, 0x01},
+ {0xd013, 0xff, 0x45},
+ {0xd014, 0x03, 0x03},
+ {0xd040, 0xff, 0x98},
+ {0xd041, 0x03, 0x00},
+ {0xd042, 0xff, 0xcf},
+ {0xd043, 0x03, 0x03},
+ {0xd045, 0x02, 0x00},
+ {0x9bcf, 0x01, 0x01},
+ {0xd045, 0x04, 0x04},
+ {0xd04f, 0xff, 0x9a},
+ {0xd050, 0x01, 0x01},
+ {0xd051, 0xff, 0x5a},
+ {0xd052, 0x01, 0x01},
+ {0xd053, 0xff, 0x50},
+ {0xd054, 0xff, 0x46},
+ {0x9bd7, 0xff, 0x0a},
+ {0x9bd8, 0xff, 0x14},
+ {0x9bd9, 0xff, 0x08},
+ {0x9bd0, 0xff, 0xcc},
+ {0x9be4, 0xff, 0xa0},
+ {0x9bbd, 0xff, 0x8e},
+ {0x9be2, 0xff, 0x4d},
+ {0x9bee, 0x01, 0x01},
};
-/* Microtune MT2060 tuner init
- AF9013_TUNER_MT2060_2 = 147 */
-static const struct af9013_reg_bit tuner_init_mt2060_2[] = {
- { 0x9bd5, 0, 8, 0x01 },
- { 0x9bd6, 0, 8, 0x06 },
- { 0x9bbe, 0, 8, 0x01 },
- { 0xd1a0, 1, 1, 0x01 },
- { 0xd000, 0, 1, 0x01 },
- { 0xd000, 1, 1, 0x00 },
- { 0xd001, 1, 1, 0x01 },
- { 0xd001, 0, 1, 0x00 },
- { 0xd001, 5, 1, 0x00 },
- { 0xd002, 0, 5, 0x19 },
- { 0xd003, 0, 5, 0x1a },
- { 0xd004, 0, 5, 0x19 },
- { 0xd005, 0, 5, 0x1a },
- { 0xd00e, 0, 5, 0x10 },
- { 0xd00f, 0, 3, 0x04 },
- { 0xd00f, 3, 3, 0x05 },
- { 0xd010, 0, 3, 0x04 },
- { 0xd010, 3, 3, 0x05 },
- { 0xd016, 4, 4, 0x03 },
- { 0xd01f, 0, 6, 0x0a },
- { 0xd020, 0, 6, 0x0a },
- { 0xd015, 0, 8, 0x46 },
- { 0xd016, 0, 1, 0x00 },
- { 0xd044, 0, 8, 0x46 },
- { 0xd045, 0, 1, 0x00 },
- { 0xd008, 0, 8, 0x0f },
- { 0xd009, 0, 2, 0x02 },
- { 0xd006, 0, 8, 0x32 },
- { 0xd007, 0, 2, 0x01 },
- { 0xd00c, 0, 8, 0x36 },
- { 0xd00d, 0, 2, 0x03 },
- { 0xd00a, 0, 8, 0x35 },
- { 0xd00b, 0, 2, 0x01 },
- { 0x9bc7, 0, 8, 0x07 },
- { 0x9bc8, 0, 8, 0x90 },
- { 0x9bc3, 0, 8, 0x0f },
- { 0x9bc4, 0, 8, 0x02 },
- { 0x9bc5, 0, 8, 0x36 },
- { 0x9bc6, 0, 8, 0x03 },
- { 0x9bba, 0, 8, 0xc9 },
- { 0x9bc9, 0, 8, 0x79 },
- { 0xd011, 0, 8, 0x10 },
- { 0xd012, 0, 2, 0x01 },
- { 0xd013, 0, 8, 0x45 },
- { 0xd014, 0, 2, 0x03 },
- { 0xd040, 0, 8, 0x98 },
- { 0xd041, 0, 2, 0x00 },
- { 0xd042, 0, 8, 0xcf },
- { 0xd043, 0, 2, 0x03 },
- { 0xd045, 1, 1, 0x00 },
- { 0x9bcf, 0, 8, 0x01 },
- { 0xd045, 2, 1, 0x01 },
- { 0xd04f, 0, 8, 0x9a },
- { 0xd050, 0, 1, 0x01 },
- { 0xd051, 0, 8, 0x5a },
- { 0xd052, 0, 1, 0x01 },
- { 0xd053, 0, 8, 0x96 },
- { 0xd054, 0, 8, 0x46 },
- { 0xd045, 7, 1, 0x00 },
- { 0x9bd7, 0, 8, 0x0a },
- { 0x9bd8, 0, 8, 0x14 },
- { 0x9bd9, 0, 8, 0x08 },
+/*
+ * Microtune MT2060 tuner init
+ * AF9013_TUNER_MT2060_2 0x93
+ */
+static const struct af9013_reg_mask_val tuner_init_tab_mt2060_2[] = {
+ {0x9bd5, 0xff, 0x01},
+ {0x9bd6, 0xff, 0x06},
+ {0x9bbe, 0xff, 0x01},
+ {0xd1a0, 0x02, 0x02},
+ {0xd000, 0x01, 0x01},
+ {0xd000, 0x02, 0x00},
+ {0xd001, 0x02, 0x02},
+ {0xd001, 0x01, 0x00},
+ {0xd001, 0x20, 0x00},
+ {0xd002, 0x1f, 0x19},
+ {0xd003, 0x1f, 0x1a},
+ {0xd004, 0x1f, 0x19},
+ {0xd005, 0x1f, 0x1a},
+ {0xd00e, 0x1f, 0x10},
+ {0xd00f, 0x07, 0x04},
+ {0xd00f, 0x38, 0x28},
+ {0xd010, 0x07, 0x04},
+ {0xd010, 0x38, 0x28},
+ {0xd016, 0xf0, 0x30},
+ {0xd01f, 0x3f, 0x0a},
+ {0xd020, 0x3f, 0x0a},
+ {0xd015, 0xff, 0x46},
+ {0xd016, 0x01, 0x00},
+ {0xd044, 0xff, 0x46},
+ {0xd045, 0x01, 0x00},
+ {0xd008, 0xff, 0x0f},
+ {0xd009, 0x03, 0x02},
+ {0xd006, 0xff, 0x32},
+ {0xd007, 0x03, 0x01},
+ {0xd00c, 0xff, 0x36},
+ {0xd00d, 0x03, 0x03},
+ {0xd00a, 0xff, 0x35},
+ {0xd00b, 0x03, 0x01},
+ {0x9bc7, 0xff, 0x07},
+ {0x9bc8, 0xff, 0x90},
+ {0x9bc3, 0xff, 0x0f},
+ {0x9bc4, 0xff, 0x02},
+ {0x9bc5, 0xff, 0x36},
+ {0x9bc6, 0xff, 0x03},
+ {0x9bba, 0xff, 0xc9},
+ {0x9bc9, 0xff, 0x79},
+ {0xd011, 0xff, 0x10},
+ {0xd012, 0x03, 0x01},
+ {0xd013, 0xff, 0x45},
+ {0xd014, 0x03, 0x03},
+ {0xd040, 0xff, 0x98},
+ {0xd041, 0x03, 0x00},
+ {0xd042, 0xff, 0xcf},
+ {0xd043, 0x03, 0x03},
+ {0xd045, 0x02, 0x00},
+ {0x9bcf, 0xff, 0x01},
+ {0xd045, 0x04, 0x04},
+ {0xd04f, 0xff, 0x9a},
+ {0xd050, 0x01, 0x01},
+ {0xd051, 0xff, 0x5a},
+ {0xd052, 0x01, 0x01},
+ {0xd053, 0xff, 0x96},
+ {0xd054, 0xff, 0x46},
+ {0xd045, 0x80, 0x00},
+ {0x9bd7, 0xff, 0x0a},
+ {0x9bd8, 0xff, 0x14},
+ {0x9bd9, 0xff, 0x08},
};
-/* MaxLinear MXL5003 tuner init
- AF9013_TUNER_MXL5003D = 3 */
-static const struct af9013_reg_bit tuner_init_mxl5003d[] = {
- { 0x9bd5, 0, 8, 0x01 },
- { 0x9bd6, 0, 8, 0x09 },
- { 0xd1a0, 1, 1, 0x01 },
- { 0xd000, 0, 1, 0x01 },
- { 0xd000, 1, 1, 0x00 },
- { 0xd001, 1, 1, 0x01 },
- { 0xd001, 0, 1, 0x00 },
- { 0xd001, 5, 1, 0x00 },
- { 0xd002, 0, 5, 0x19 },
- { 0xd003, 0, 5, 0x1a },
- { 0xd004, 0, 5, 0x19 },
- { 0xd005, 0, 5, 0x1a },
- { 0xd00e, 0, 5, 0x10 },
- { 0xd00f, 0, 3, 0x04 },
- { 0xd00f, 3, 3, 0x05 },
- { 0xd010, 0, 3, 0x04 },
- { 0xd010, 3, 3, 0x05 },
- { 0xd016, 4, 4, 0x03 },
- { 0xd01f, 0, 6, 0x0a },
- { 0xd020, 0, 6, 0x0a },
- { 0x9bda, 0, 8, 0x00 },
- { 0x9be3, 0, 8, 0x00 },
- { 0x9bfc, 0, 8, 0x0f },
- { 0x9bf6, 0, 8, 0x01 },
- { 0x9bbe, 0, 1, 0x01 },
- { 0xd015, 0, 8, 0x33 },
- { 0xd016, 0, 1, 0x00 },
- { 0xd044, 0, 8, 0x40 },
- { 0xd045, 0, 1, 0x00 },
- { 0xd008, 0, 8, 0x0f },
- { 0xd009, 0, 2, 0x02 },
- { 0xd006, 0, 8, 0x6c },
- { 0xd007, 0, 2, 0x00 },
- { 0xd00c, 0, 8, 0x3d },
- { 0xd00d, 0, 2, 0x00 },
- { 0xd00a, 0, 8, 0x45 },
- { 0xd00b, 0, 2, 0x01 },
- { 0x9bc7, 0, 8, 0x07 },
- { 0x9bc8, 0, 8, 0x52 },
- { 0x9bc3, 0, 8, 0x0f },
- { 0x9bc4, 0, 8, 0x02 },
- { 0x9bc5, 0, 8, 0x3d },
- { 0x9bc6, 0, 8, 0x00 },
- { 0x9bba, 0, 8, 0xa2 },
- { 0x9bc9, 0, 8, 0xa0 },
- { 0xd011, 0, 8, 0x56 },
- { 0xd012, 0, 2, 0x00 },
- { 0xd013, 0, 8, 0x50 },
- { 0xd014, 0, 2, 0x00 },
- { 0xd040, 0, 8, 0x56 },
- { 0xd041, 0, 2, 0x00 },
- { 0xd042, 0, 8, 0x50 },
- { 0xd043, 0, 2, 0x00 },
- { 0xd045, 1, 1, 0x00 },
- { 0x9bcf, 0, 8, 0x01 },
- { 0xd045, 2, 1, 0x01 },
- { 0xd04f, 0, 8, 0x9a },
- { 0xd050, 0, 1, 0x01 },
- { 0xd051, 0, 8, 0x5a },
- { 0xd052, 0, 1, 0x01 },
- { 0xd053, 0, 8, 0x50 },
- { 0xd054, 0, 8, 0x46 },
- { 0x9bd7, 0, 8, 0x0a },
- { 0x9bd8, 0, 8, 0x14 },
- { 0x9bd9, 0, 8, 0x08 },
+/*
+ * MaxLinear MXL5003 tuner init
+ * AF9013_TUNER_MXL5003D 0x03
+ */
+static const struct af9013_reg_mask_val tuner_init_tab_mxl5003d[] = {
+ {0x9bd5, 0xff, 0x01},
+ {0x9bd6, 0xff, 0x09},
+ {0xd1a0, 0x02, 0x02},
+ {0xd000, 0x01, 0x01},
+ {0xd000, 0x02, 0x00},
+ {0xd001, 0x02, 0x02},
+ {0xd001, 0x01, 0x00},
+ {0xd001, 0x20, 0x00},
+ {0xd002, 0x1f, 0x19},
+ {0xd003, 0x1f, 0x1a},
+ {0xd004, 0x1f, 0x19},
+ {0xd005, 0x1f, 0x1a},
+ {0xd00e, 0x1f, 0x10},
+ {0xd00f, 0x07, 0x04},
+ {0xd00f, 0x38, 0x28},
+ {0xd010, 0x07, 0x04},
+ {0xd010, 0x38, 0x28},
+ {0xd016, 0xf0, 0x30},
+ {0xd01f, 0x3f, 0x0a},
+ {0xd020, 0x3f, 0x0a},
+ {0x9bda, 0xff, 0x00},
+ {0x9be3, 0xff, 0x00},
+ {0x9bfc, 0xff, 0x0f},
+ {0x9bf6, 0xff, 0x01},
+ {0x9bbe, 0x01, 0x01},
+ {0xd015, 0xff, 0x33},
+ {0xd016, 0x01, 0x00},
+ {0xd044, 0xff, 0x40},
+ {0xd045, 0x01, 0x00},
+ {0xd008, 0xff, 0x0f},
+ {0xd009, 0x03, 0x02},
+ {0xd006, 0xff, 0x6c},
+ {0xd007, 0x03, 0x00},
+ {0xd00c, 0xff, 0x3d},
+ {0xd00d, 0x03, 0x00},
+ {0xd00a, 0xff, 0x45},
+ {0xd00b, 0x03, 0x01},
+ {0x9bc7, 0xff, 0x07},
+ {0x9bc8, 0xff, 0x52},
+ {0x9bc3, 0xff, 0x0f},
+ {0x9bc4, 0xff, 0x02},
+ {0x9bc5, 0xff, 0x3d},
+ {0x9bc6, 0xff, 0x00},
+ {0x9bba, 0xff, 0xa2},
+ {0x9bc9, 0xff, 0xa0},
+ {0xd011, 0xff, 0x56},
+ {0xd012, 0x03, 0x00},
+ {0xd013, 0xff, 0x50},
+ {0xd014, 0x03, 0x00},
+ {0xd040, 0xff, 0x56},
+ {0xd041, 0x03, 0x00},
+ {0xd042, 0xff, 0x50},
+ {0xd043, 0x03, 0x00},
+ {0xd045, 0x02, 0x00},
+ {0x9bcf, 0xff, 0x01},
+ {0xd045, 0x04, 0x04},
+ {0xd04f, 0xff, 0x9a},
+ {0xd050, 0x01, 0x01},
+ {0xd051, 0xff, 0x5a},
+ {0xd052, 0x01, 0x01},
+ {0xd053, 0xff, 0x50},
+ {0xd054, 0xff, 0x46},
+ {0x9bd7, 0xff, 0x0a},
+ {0x9bd8, 0xff, 0x14},
+ {0x9bd9, 0xff, 0x08},
};
-/* MaxLinear MXL5005S & MXL5007T tuner init
- AF9013_TUNER_MXL5005D = 13
- AF9013_TUNER_MXL5005R = 30
- AF9013_TUNER_MXL5007T = 177 */
-static const struct af9013_reg_bit tuner_init_mxl5005[] = {
- { 0x9bd5, 0, 8, 0x01 },
- { 0x9bd6, 0, 8, 0x07 },
- { 0xd1a0, 1, 1, 0x01 },
- { 0xd000, 0, 1, 0x01 },
- { 0xd000, 1, 1, 0x00 },
- { 0xd001, 1, 1, 0x01 },
- { 0xd001, 0, 1, 0x00 },
- { 0xd001, 5, 1, 0x00 },
- { 0xd002, 0, 5, 0x19 },
- { 0xd003, 0, 5, 0x1a },
- { 0xd004, 0, 5, 0x19 },
- { 0xd005, 0, 5, 0x1a },
- { 0xd00e, 0, 5, 0x10 },
- { 0xd00f, 0, 3, 0x04 },
- { 0xd00f, 3, 3, 0x05 },
- { 0xd010, 0, 3, 0x04 },
- { 0xd010, 3, 3, 0x05 },
- { 0xd016, 4, 4, 0x03 },
- { 0xd01f, 0, 6, 0x0a },
- { 0xd020, 0, 6, 0x0a },
- { 0x9bda, 0, 8, 0x01 },
- { 0x9be3, 0, 8, 0x01 },
- { 0x9bbe, 0, 1, 0x01 },
- { 0x9bcc, 0, 1, 0x01 },
- { 0x9bb9, 0, 8, 0x00 },
- { 0x9bcd, 0, 8, 0x28 },
- { 0x9bff, 0, 8, 0x24 },
- { 0xd015, 0, 8, 0x40 },
- { 0xd016, 0, 1, 0x00 },
- { 0xd044, 0, 8, 0x40 },
- { 0xd045, 0, 1, 0x00 },
- { 0xd008, 0, 8, 0x0f },
- { 0xd009, 0, 2, 0x02 },
- { 0xd006, 0, 8, 0x73 },
- { 0xd007, 0, 2, 0x01 },
- { 0xd00c, 0, 8, 0xfa },
- { 0xd00d, 0, 2, 0x01 },
- { 0xd00a, 0, 8, 0xff },
- { 0xd00b, 0, 2, 0x01 },
- { 0x9bc7, 0, 8, 0x23 },
- { 0x9bc8, 0, 8, 0x55 },
- { 0x9bc3, 0, 8, 0x01 },
- { 0x9bc4, 0, 8, 0x02 },
- { 0x9bc5, 0, 8, 0xfa },
- { 0x9bc6, 0, 8, 0x01 },
- { 0x9bba, 0, 8, 0xff },
- { 0x9bc9, 0, 8, 0xff },
- { 0x9bd3, 0, 8, 0x95 },
- { 0xd011, 0, 8, 0x70 },
- { 0xd012, 0, 2, 0x01 },
- { 0xd013, 0, 8, 0xfb },
- { 0xd014, 0, 2, 0x01 },
- { 0xd040, 0, 8, 0x70 },
- { 0xd041, 0, 2, 0x01 },
- { 0xd042, 0, 8, 0xfb },
- { 0xd043, 0, 2, 0x01 },
- { 0xd045, 1, 1, 0x00 },
- { 0x9bcf, 0, 1, 0x01 },
- { 0xd045, 2, 1, 0x01 },
- { 0xd04f, 0, 8, 0x9a },
- { 0xd050, 0, 1, 0x01 },
- { 0xd051, 0, 8, 0x5a },
- { 0xd052, 0, 1, 0x01 },
- { 0xd053, 0, 8, 0x50 },
- { 0xd054, 0, 8, 0x46 },
- { 0x9bd7, 0, 8, 0x0a },
- { 0x9bd8, 0, 8, 0x14 },
- { 0x9bd9, 0, 8, 0x08 },
- { 0x9bd0, 0, 8, 0x93 },
- { 0x9be4, 0, 8, 0xfe },
- { 0x9bbd, 0, 8, 0x63 },
- { 0x9be2, 0, 8, 0xfe },
- { 0x9bee, 0, 1, 0x01 },
+/*
+ * MaxLinear MXL5005S & MXL5007T tuner init
+ * AF9013_TUNER_MXL5005D 0x0d
+ * AF9013_TUNER_MXL5005R 0x1e
+ * AF9013_TUNER_MXL5007T 0xb1
+ */
+static const struct af9013_reg_mask_val tuner_init_tab_mxl5005[] = {
+ {0x9bd5, 0xff, 0x01},
+ {0x9bd6, 0xff, 0x07},
+ {0xd1a0, 0x02, 0x02},
+ {0xd000, 0x01, 0x01},
+ {0xd000, 0x02, 0x00},
+ {0xd001, 0x02, 0x02},
+ {0xd001, 0x01, 0x00},
+ {0xd001, 0x20, 0x00},
+ {0xd002, 0x1f, 0x19},
+ {0xd003, 0x1f, 0x1a},
+ {0xd004, 0x1f, 0x19},
+ {0xd005, 0x1f, 0x1a},
+ {0xd00e, 0x1f, 0x10},
+ {0xd00f, 0x07, 0x04},
+ {0xd00f, 0x38, 0x28},
+ {0xd010, 0x07, 0x04},
+ {0xd010, 0x38, 0x28},
+ {0xd016, 0xf0, 0x30},
+ {0xd01f, 0x3f, 0x0a},
+ {0xd020, 0x3f, 0x0a},
+ {0x9bda, 0xff, 0x01},
+ {0x9be3, 0xff, 0x01},
+ {0x9bbe, 0x01, 0x01},
+ {0x9bcc, 0x01, 0x01},
+ {0x9bb9, 0xff, 0x00},
+ {0x9bcd, 0xff, 0x28},
+ {0x9bff, 0xff, 0x24},
+ {0xd015, 0xff, 0x40},
+ {0xd016, 0x01, 0x00},
+ {0xd044, 0xff, 0x40},
+ {0xd045, 0x01, 0x00},
+ {0xd008, 0xff, 0x0f},
+ {0xd009, 0x03, 0x02},
+ {0xd006, 0xff, 0x73},
+ {0xd007, 0x03, 0x01},
+ {0xd00c, 0xff, 0xfa},
+ {0xd00d, 0x03, 0x01},
+ {0xd00a, 0xff, 0xff},
+ {0xd00b, 0x03, 0x01},
+ {0x9bc7, 0xff, 0x23},
+ {0x9bc8, 0xff, 0x55},
+ {0x9bc3, 0xff, 0x01},
+ {0x9bc4, 0xff, 0x02},
+ {0x9bc5, 0xff, 0xfa},
+ {0x9bc6, 0xff, 0x01},
+ {0x9bba, 0xff, 0xff},
+ {0x9bc9, 0xff, 0xff},
+ {0x9bd3, 0xff, 0x95},
+ {0xd011, 0xff, 0x70},
+ {0xd012, 0x03, 0x01},
+ {0xd013, 0xff, 0xfb},
+ {0xd014, 0x03, 0x01},
+ {0xd040, 0xff, 0x70},
+ {0xd041, 0x03, 0x01},
+ {0xd042, 0xff, 0xfb},
+ {0xd043, 0x03, 0x01},
+ {0xd045, 0x02, 0x00},
+ {0x9bcf, 0x01, 0x01},
+ {0xd045, 0x04, 0x04},
+ {0xd04f, 0xff, 0x9a},
+ {0xd050, 0x01, 0x01},
+ {0xd051, 0xff, 0x5a},
+ {0xd052, 0x01, 0x01},
+ {0xd053, 0xff, 0x50},
+ {0xd054, 0xff, 0x46},
+ {0x9bd7, 0xff, 0x0a},
+ {0x9bd8, 0xff, 0x14},
+ {0x9bd9, 0xff, 0x08},
+ {0x9bd0, 0xff, 0x93},
+ {0x9be4, 0xff, 0xfe},
+ {0x9bbd, 0xff, 0x63},
+ {0x9be2, 0xff, 0xfe},
+ {0x9bee, 0x01, 0x01},
};
-/* Quantek QT1010 tuner init
- AF9013_TUNER_QT1010 = 134
- AF9013_TUNER_QT1010A = 162 */
-static const struct af9013_reg_bit tuner_init_qt1010[] = {
- { 0x9bd5, 0, 8, 0x01 },
- { 0x9bd6, 0, 8, 0x09 },
- { 0xd1a0, 1, 1, 0x01 },
- { 0xd000, 0, 1, 0x01 },
- { 0xd000, 1, 1, 0x00 },
- { 0xd001, 1, 1, 0x01 },
- { 0xd001, 0, 1, 0x00 },
- { 0xd001, 5, 1, 0x00 },
- { 0xd002, 0, 5, 0x19 },
- { 0xd003, 0, 5, 0x1a },
- { 0xd004, 0, 5, 0x19 },
- { 0xd005, 0, 5, 0x1a },
- { 0xd00e, 0, 5, 0x10 },
- { 0xd00f, 0, 3, 0x04 },
- { 0xd00f, 3, 3, 0x05 },
- { 0xd010, 0, 3, 0x04 },
- { 0xd010, 3, 3, 0x05 },
- { 0xd016, 4, 4, 0x03 },
- { 0xd01f, 0, 6, 0x0a },
- { 0xd020, 0, 6, 0x0a },
- { 0x9bda, 0, 8, 0x01 },
- { 0x9be3, 0, 8, 0x01 },
- { 0xd015, 0, 8, 0x46 },
- { 0xd016, 0, 1, 0x00 },
- { 0xd044, 0, 8, 0x46 },
- { 0xd045, 0, 1, 0x00 },
- { 0x9bbe, 0, 1, 0x01 },
- { 0x9bcc, 0, 1, 0x01 },
- { 0x9bb9, 0, 8, 0x00 },
- { 0x9bcd, 0, 8, 0x28 },
- { 0x9bff, 0, 8, 0x20 },
- { 0xd008, 0, 8, 0x0f },
- { 0xd009, 0, 2, 0x02 },
- { 0xd006, 0, 8, 0x99 },
- { 0xd007, 0, 2, 0x01 },
- { 0xd00c, 0, 8, 0x0f },
- { 0xd00d, 0, 2, 0x02 },
- { 0xd00a, 0, 8, 0x50 },
- { 0xd00b, 0, 2, 0x01 },
- { 0x9bc7, 0, 8, 0x00 },
- { 0x9bc8, 0, 8, 0x00 },
- { 0x9bc3, 0, 8, 0x0f },
- { 0x9bc4, 0, 8, 0x02 },
- { 0x9bc5, 0, 8, 0x0f },
- { 0x9bc6, 0, 8, 0x02 },
- { 0x9bba, 0, 8, 0xc5 },
- { 0x9bc9, 0, 8, 0xff },
- { 0xd011, 0, 8, 0x58 },
- { 0xd012, 0, 2, 0x02 },
- { 0xd013, 0, 8, 0x89 },
- { 0xd014, 0, 2, 0x01 },
- { 0xd040, 0, 8, 0x58 },
- { 0xd041, 0, 2, 0x02 },
- { 0xd042, 0, 8, 0x89 },
- { 0xd043, 0, 2, 0x01 },
- { 0xd045, 1, 1, 0x00 },
- { 0x9bcf, 0, 1, 0x01 },
- { 0xd045, 2, 1, 0x01 },
- { 0xd04f, 0, 8, 0x9a },
- { 0xd050, 0, 1, 0x01 },
- { 0xd051, 0, 8, 0x5a },
- { 0xd052, 0, 1, 0x01 },
- { 0xd053, 0, 8, 0x50 },
- { 0xd054, 0, 8, 0x46 },
- { 0x9bd7, 0, 8, 0x0a },
- { 0x9bd8, 0, 8, 0x14 },
- { 0x9bd9, 0, 8, 0x08 },
- { 0x9bd0, 0, 8, 0xcd },
- { 0x9be4, 0, 8, 0xbb },
- { 0x9bbd, 0, 8, 0x93 },
- { 0x9be2, 0, 8, 0x80 },
- { 0x9bee, 0, 1, 0x01 },
+/*
+ * Quantek QT1010 tuner init
+ * AF9013_TUNER_QT1010 0x86
+ * AF9013_TUNER_QT1010A 0xa2
+ */
+static const struct af9013_reg_mask_val tuner_init_tab_qt1010[] = {
+ {0x9bd5, 0xff, 0x01},
+ {0x9bd6, 0xff, 0x09},
+ {0xd1a0, 0x02, 0x02},
+ {0xd000, 0x01, 0x01},
+ {0xd000, 0x02, 0x00},
+ {0xd001, 0x02, 0x02},
+ {0xd001, 0x01, 0x00},
+ {0xd001, 0x20, 0x00},
+ {0xd002, 0x1f, 0x19},
+ {0xd003, 0x1f, 0x1a},
+ {0xd004, 0x1f, 0x19},
+ {0xd005, 0x1f, 0x1a},
+ {0xd00e, 0x1f, 0x10},
+ {0xd00f, 0x07, 0x04},
+ {0xd00f, 0x38, 0x28},
+ {0xd010, 0x07, 0x04},
+ {0xd010, 0x38, 0x28},
+ {0xd016, 0xf0, 0x30},
+ {0xd01f, 0x3f, 0x0a},
+ {0xd020, 0x3f, 0x0a},
+ {0x9bda, 0xff, 0x01},
+ {0x9be3, 0xff, 0x01},
+ {0xd015, 0xff, 0x46},
+ {0xd016, 0x01, 0x00},
+ {0xd044, 0xff, 0x46},
+ {0xd045, 0x01, 0x00},
+ {0x9bbe, 0x01, 0x01},
+ {0x9bcc, 0x01, 0x01},
+ {0x9bb9, 0xff, 0x00},
+ {0x9bcd, 0xff, 0x28},
+ {0x9bff, 0xff, 0x20},
+ {0xd008, 0xff, 0x0f},
+ {0xd009, 0x03, 0x02},
+ {0xd006, 0xff, 0x99},
+ {0xd007, 0x03, 0x01},
+ {0xd00c, 0xff, 0x0f},
+ {0xd00d, 0x03, 0x02},
+ {0xd00a, 0xff, 0x50},
+ {0xd00b, 0x03, 0x01},
+ {0x9bc7, 0xff, 0x00},
+ {0x9bc8, 0xff, 0x00},
+ {0x9bc3, 0xff, 0x0f},
+ {0x9bc4, 0xff, 0x02},
+ {0x9bc5, 0xff, 0x0f},
+ {0x9bc6, 0xff, 0x02},
+ {0x9bba, 0xff, 0xc5},
+ {0x9bc9, 0xff, 0xff},
+ {0xd011, 0xff, 0x58},
+ {0xd012, 0x03, 0x02},
+ {0xd013, 0xff, 0x89},
+ {0xd014, 0x03, 0x01},
+ {0xd040, 0xff, 0x58},
+ {0xd041, 0x03, 0x02},
+ {0xd042, 0xff, 0x89},
+ {0xd043, 0x03, 0x01},
+ {0xd045, 0x02, 0x00},
+ {0x9bcf, 0x01, 0x01},
+ {0xd045, 0x04, 0x04},
+ {0xd04f, 0xff, 0x9a},
+ {0xd050, 0x01, 0x01},
+ {0xd051, 0xff, 0x5a},
+ {0xd052, 0x01, 0x01},
+ {0xd053, 0xff, 0x50},
+ {0xd054, 0xff, 0x46},
+ {0x9bd7, 0xff, 0x0a},
+ {0x9bd8, 0xff, 0x14},
+ {0x9bd9, 0xff, 0x08},
+ {0x9bd0, 0xff, 0xcd},
+ {0x9be4, 0xff, 0xbb},
+ {0x9bbd, 0xff, 0x93},
+ {0x9be2, 0xff, 0x80},
+ {0x9bee, 0x01, 0x01},
};
-/* Freescale MC44S803 tuner init
- AF9013_TUNER_MC44S803 = 133 */
-static const struct af9013_reg_bit tuner_init_mc44s803[] = {
- { 0x9bd5, 0, 8, 0x01 },
- { 0x9bd6, 0, 8, 0x06 },
- { 0xd1a0, 1, 1, 0x01 },
- { 0xd000, 0, 1, 0x01 },
- { 0xd000, 1, 1, 0x00 },
- { 0xd001, 1, 1, 0x01 },
- { 0xd001, 0, 1, 0x00 },
- { 0xd001, 5, 1, 0x00 },
- { 0xd002, 0, 5, 0x19 },
- { 0xd003, 0, 5, 0x1a },
- { 0xd004, 0, 5, 0x19 },
- { 0xd005, 0, 5, 0x1a },
- { 0xd00e, 0, 5, 0x10 },
- { 0xd00f, 0, 3, 0x04 },
- { 0xd00f, 3, 3, 0x05 },
- { 0xd010, 0, 3, 0x04 },
- { 0xd010, 3, 3, 0x05 },
- { 0xd016, 4, 4, 0x03 },
- { 0xd01f, 0, 6, 0x0a },
- { 0xd020, 0, 6, 0x0a },
- { 0x9bda, 0, 8, 0x00 },
- { 0x9be3, 0, 8, 0x00 },
- { 0x9bf6, 0, 8, 0x01 },
- { 0x9bf8, 0, 8, 0x02 },
- { 0x9bf9, 0, 8, 0x02 },
- { 0x9bfc, 0, 8, 0x1f },
- { 0x9bbe, 0, 1, 0x01 },
- { 0x9bcc, 0, 1, 0x01 },
- { 0x9bb9, 0, 8, 0x00 },
- { 0x9bcd, 0, 8, 0x24 },
- { 0x9bff, 0, 8, 0x24 },
- { 0xd015, 0, 8, 0x46 },
- { 0xd016, 0, 1, 0x00 },
- { 0xd044, 0, 8, 0x46 },
- { 0xd045, 0, 1, 0x00 },
- { 0xd008, 0, 8, 0x01 },
- { 0xd009, 0, 2, 0x02 },
- { 0xd006, 0, 8, 0x7b },
- { 0xd007, 0, 2, 0x00 },
- { 0xd00c, 0, 8, 0x7c },
- { 0xd00d, 0, 2, 0x02 },
- { 0xd00a, 0, 8, 0xfe },
- { 0xd00b, 0, 2, 0x01 },
- { 0x9bc7, 0, 8, 0x08 },
- { 0x9bc8, 0, 8, 0x9a },
- { 0x9bc3, 0, 8, 0x01 },
- { 0x9bc4, 0, 8, 0x02 },
- { 0x9bc5, 0, 8, 0x7c },
- { 0x9bc6, 0, 8, 0x02 },
- { 0x9bba, 0, 8, 0xfc },
- { 0x9bc9, 0, 8, 0xaa },
- { 0xd011, 0, 8, 0x6b },
- { 0xd012, 0, 2, 0x00 },
- { 0xd013, 0, 8, 0x88 },
- { 0xd014, 0, 2, 0x02 },
- { 0xd040, 0, 8, 0x6b },
- { 0xd041, 0, 2, 0x00 },
- { 0xd042, 0, 8, 0x7c },
- { 0xd043, 0, 2, 0x02 },
- { 0xd045, 1, 1, 0x00 },
- { 0x9bcf, 0, 1, 0x01 },
- { 0xd045, 2, 1, 0x01 },
- { 0xd04f, 0, 8, 0x9a },
- { 0xd050, 0, 1, 0x01 },
- { 0xd051, 0, 8, 0x5a },
- { 0xd052, 0, 1, 0x01 },
- { 0xd053, 0, 8, 0x50 },
- { 0xd054, 0, 8, 0x46 },
- { 0x9bd7, 0, 8, 0x0a },
- { 0x9bd8, 0, 8, 0x14 },
- { 0x9bd9, 0, 8, 0x08 },
- { 0x9bd0, 0, 8, 0x9e },
- { 0x9be4, 0, 8, 0xff },
- { 0x9bbd, 0, 8, 0x9e },
- { 0x9be2, 0, 8, 0x25 },
- { 0x9bee, 0, 1, 0x01 },
- { 0xd73b, 3, 1, 0x00 },
+/*
+ * Freescale MC44S803 tuner init
+ * AF9013_TUNER_MC44S803 0x85
+ */
+static const struct af9013_reg_mask_val tuner_init_tab_mc44s803[] = {
+ {0x9bd5, 0xff, 0x01},
+ {0x9bd6, 0xff, 0x06},
+ {0xd1a0, 0x02, 0x02},
+ {0xd000, 0x01, 0x01},
+ {0xd000, 0x02, 0x00},
+ {0xd001, 0x02, 0x02},
+ {0xd001, 0x01, 0x00},
+ {0xd001, 0x20, 0x00},
+ {0xd002, 0x1f, 0x19},
+ {0xd003, 0x1f, 0x1a},
+ {0xd004, 0x1f, 0x19},
+ {0xd005, 0x1f, 0x1a},
+ {0xd00e, 0x1f, 0x10},
+ {0xd00f, 0x07, 0x04},
+ {0xd00f, 0x38, 0x28},
+ {0xd010, 0x07, 0x04},
+ {0xd010, 0x38, 0x28},
+ {0xd016, 0xf0, 0x30},
+ {0xd01f, 0x3f, 0x0a},
+ {0xd020, 0x3f, 0x0a},
+ {0x9bda, 0xff, 0x00},
+ {0x9be3, 0xff, 0x00},
+ {0x9bf6, 0xff, 0x01},
+ {0x9bf8, 0xff, 0x02},
+ {0x9bf9, 0xff, 0x02},
+ {0x9bfc, 0xff, 0x1f},
+ {0x9bbe, 0x01, 0x01},
+ {0x9bcc, 0x01, 0x01},
+ {0x9bb9, 0xff, 0x00},
+ {0x9bcd, 0xff, 0x24},
+ {0x9bff, 0xff, 0x24},
+ {0xd015, 0xff, 0x46},
+ {0xd016, 0x01, 0x00},
+ {0xd044, 0xff, 0x46},
+ {0xd045, 0x01, 0x00},
+ {0xd008, 0xff, 0x01},
+ {0xd009, 0x03, 0x02},
+ {0xd006, 0xff, 0x7b},
+ {0xd007, 0x03, 0x00},
+ {0xd00c, 0xff, 0x7c},
+ {0xd00d, 0x03, 0x02},
+ {0xd00a, 0xff, 0xfe},
+ {0xd00b, 0x03, 0x01},
+ {0x9bc7, 0xff, 0x08},
+ {0x9bc8, 0xff, 0x9a},
+ {0x9bc3, 0xff, 0x01},
+ {0x9bc4, 0xff, 0x02},
+ {0x9bc5, 0xff, 0x7c},
+ {0x9bc6, 0xff, 0x02},
+ {0x9bba, 0xff, 0xfc},
+ {0x9bc9, 0xff, 0xaa},
+ {0xd011, 0xff, 0x6b},
+ {0xd012, 0x03, 0x00},
+ {0xd013, 0xff, 0x88},
+ {0xd014, 0x03, 0x02},
+ {0xd040, 0xff, 0x6b},
+ {0xd041, 0x03, 0x00},
+ {0xd042, 0xff, 0x7c},
+ {0xd043, 0x03, 0x02},
+ {0xd045, 0x02, 0x00},
+ {0x9bcf, 0x01, 0x01},
+ {0xd045, 0x04, 0x04},
+ {0xd04f, 0xff, 0x9a},
+ {0xd050, 0x01, 0x01},
+ {0xd051, 0xff, 0x5a},
+ {0xd052, 0x01, 0x01},
+ {0xd053, 0xff, 0x50},
+ {0xd054, 0xff, 0x46},
+ {0x9bd7, 0xff, 0x0a},
+ {0x9bd8, 0xff, 0x14},
+ {0x9bd9, 0xff, 0x08},
+ {0x9bd0, 0xff, 0x9e},
+ {0x9be4, 0xff, 0xff},
+ {0x9bbd, 0xff, 0x9e},
+ {0x9be2, 0xff, 0x25},
+ {0x9bee, 0x01, 0x01},
+ {0xd73b, 0x08, 0x00},
};
-/* unknown, probably for tin can tuner, tuner init
- AF9013_TUNER_UNKNOWN = 140 */
-static const struct af9013_reg_bit tuner_init_unknown[] = {
- { 0x9bd5, 0, 8, 0x01 },
- { 0x9bd6, 0, 8, 0x02 },
- { 0xd1a0, 1, 1, 0x01 },
- { 0xd000, 0, 1, 0x01 },
- { 0xd000, 1, 1, 0x00 },
- { 0xd001, 1, 1, 0x01 },
- { 0xd001, 0, 1, 0x00 },
- { 0xd001, 5, 1, 0x00 },
- { 0xd002, 0, 5, 0x19 },
- { 0xd003, 0, 5, 0x1a },
- { 0xd004, 0, 5, 0x19 },
- { 0xd005, 0, 5, 0x1a },
- { 0xd00e, 0, 5, 0x10 },
- { 0xd00f, 0, 3, 0x04 },
- { 0xd00f, 3, 3, 0x05 },
- { 0xd010, 0, 3, 0x04 },
- { 0xd010, 3, 3, 0x05 },
- { 0xd016, 4, 4, 0x03 },
- { 0xd01f, 0, 6, 0x0a },
- { 0xd020, 0, 6, 0x0a },
- { 0x9bda, 0, 8, 0x01 },
- { 0x9be3, 0, 8, 0x01 },
- { 0xd1a0, 1, 1, 0x00 },
- { 0x9bbe, 0, 1, 0x01 },
- { 0x9bcc, 0, 1, 0x01 },
- { 0x9bb9, 0, 8, 0x00 },
- { 0x9bcd, 0, 8, 0x18 },
- { 0x9bff, 0, 8, 0x2c },
- { 0xd015, 0, 8, 0x46 },
- { 0xd016, 0, 1, 0x00 },
- { 0xd044, 0, 8, 0x46 },
- { 0xd045, 0, 1, 0x00 },
- { 0xd008, 0, 8, 0xdf },
- { 0xd009, 0, 2, 0x02 },
- { 0xd006, 0, 8, 0x44 },
- { 0xd007, 0, 2, 0x01 },
- { 0xd00c, 0, 8, 0x00 },
- { 0xd00d, 0, 2, 0x02 },
- { 0xd00a, 0, 8, 0xf6 },
- { 0xd00b, 0, 2, 0x01 },
- { 0x9bba, 0, 8, 0xf9 },
- { 0x9bc8, 0, 8, 0xaa },
- { 0x9bc3, 0, 8, 0xdf },
- { 0x9bc4, 0, 8, 0x02 },
- { 0x9bc5, 0, 8, 0x00 },
- { 0x9bc6, 0, 8, 0x02 },
- { 0x9bc9, 0, 8, 0xf0 },
- { 0xd011, 0, 8, 0x3c },
- { 0xd012, 0, 2, 0x01 },
- { 0xd013, 0, 8, 0xf7 },
- { 0xd014, 0, 2, 0x02 },
- { 0xd040, 0, 8, 0x0b },
- { 0xd041, 0, 2, 0x02 },
- { 0xd042, 0, 8, 0x4d },
- { 0xd043, 0, 2, 0x00 },
- { 0xd045, 1, 1, 0x00 },
- { 0x9bcf, 0, 1, 0x01 },
- { 0xd045, 2, 1, 0x01 },
- { 0xd04f, 0, 8, 0x9a },
- { 0xd050, 0, 1, 0x01 },
- { 0xd051, 0, 8, 0x5a },
- { 0xd052, 0, 1, 0x01 },
- { 0xd053, 0, 8, 0x50 },
- { 0xd054, 0, 8, 0x46 },
- { 0x9bd7, 0, 8, 0x0a },
- { 0x9bd8, 0, 8, 0x14 },
- { 0x9bd9, 0, 8, 0x08 },
+/*
+ * Unknown, probably for tin can tuner, tuner init
+ * AF9013_TUNER_UNKNOWN 0x8c
+ */
+static const struct af9013_reg_mask_val tuner_init_tab_unknown[] = {
+ {0x9bd5, 0xff, 0x01},
+ {0x9bd6, 0xff, 0x02},
+ {0xd1a0, 0x02, 0x02},
+ {0xd000, 0x01, 0x01},
+ {0xd000, 0x02, 0x00},
+ {0xd001, 0x02, 0x02},
+ {0xd001, 0x01, 0x00},
+ {0xd001, 0x20, 0x00},
+ {0xd002, 0x1f, 0x19},
+ {0xd003, 0x1f, 0x1a},
+ {0xd004, 0x1f, 0x19},
+ {0xd005, 0x1f, 0x1a},
+ {0xd00e, 0x1f, 0x10},
+ {0xd00f, 0x07, 0x04},
+ {0xd00f, 0x38, 0x28},
+ {0xd010, 0x07, 0x04},
+ {0xd010, 0x38, 0x28},
+ {0xd016, 0xf0, 0x30},
+ {0xd01f, 0x3f, 0x0a},
+ {0xd020, 0x3f, 0x0a},
+ {0x9bda, 0xff, 0x01},
+ {0x9be3, 0xff, 0x01},
+ {0xd1a0, 0x02, 0x00},
+ {0x9bbe, 0x01, 0x01},
+ {0x9bcc, 0x01, 0x01},
+ {0x9bb9, 0xff, 0x00},
+ {0x9bcd, 0xff, 0x18},
+ {0x9bff, 0xff, 0x2c},
+ {0xd015, 0xff, 0x46},
+ {0xd016, 0x01, 0x00},
+ {0xd044, 0xff, 0x46},
+ {0xd045, 0x01, 0x00},
+ {0xd008, 0xff, 0xdf},
+ {0xd009, 0x03, 0x02},
+ {0xd006, 0xff, 0x44},
+ {0xd007, 0x03, 0x01},
+ {0xd00c, 0xff, 0x00},
+ {0xd00d, 0x03, 0x02},
+ {0xd00a, 0xff, 0xf6},
+ {0xd00b, 0x03, 0x01},
+ {0x9bba, 0xff, 0xf9},
+ {0x9bc8, 0xff, 0xaa},
+ {0x9bc3, 0xff, 0xdf},
+ {0x9bc4, 0xff, 0x02},
+ {0x9bc5, 0xff, 0x00},
+ {0x9bc6, 0xff, 0x02},
+ {0x9bc9, 0xff, 0xf0},
+ {0xd011, 0xff, 0x3c},
+ {0xd012, 0x03, 0x01},
+ {0xd013, 0xff, 0xf7},
+ {0xd014, 0x03, 0x02},
+ {0xd040, 0xff, 0x0b},
+ {0xd041, 0x03, 0x02},
+ {0xd042, 0xff, 0x4d},
+ {0xd043, 0x03, 0x00},
+ {0xd045, 0x02, 0x00},
+ {0x9bcf, 0x01, 0x01},
+ {0xd045, 0x04, 0x04},
+ {0xd04f, 0xff, 0x9a},
+ {0xd050, 0x01, 0x01},
+ {0xd051, 0xff, 0x5a},
+ {0xd052, 0x01, 0x01},
+ {0xd053, 0xff, 0x50},
+ {0xd054, 0xff, 0x46},
+ {0x9bd7, 0xff, 0x0a},
+ {0x9bd8, 0xff, 0x14},
+ {0x9bd9, 0xff, 0x08},
};
-/* NXP TDA18271 & TDA18218 tuner init
- AF9013_TUNER_TDA18271 = 156
- AF9013_TUNER_TDA18218 = 179 */
-static const struct af9013_reg_bit tuner_init_tda18271[] = {
- { 0x9bd5, 0, 8, 0x01 },
- { 0x9bd6, 0, 8, 0x04 },
- { 0xd1a0, 1, 1, 0x01 },
- { 0xd000, 0, 1, 0x01 },
- { 0xd000, 1, 1, 0x00 },
- { 0xd001, 1, 1, 0x01 },
- { 0xd001, 0, 1, 0x00 },
- { 0xd001, 5, 1, 0x00 },
- { 0xd002, 0, 5, 0x19 },
- { 0xd003, 0, 5, 0x1a },
- { 0xd004, 0, 5, 0x19 },
- { 0xd005, 0, 5, 0x1a },
- { 0xd00e, 0, 5, 0x10 },
- { 0xd00f, 0, 3, 0x04 },
- { 0xd00f, 3, 3, 0x05 },
- { 0xd010, 0, 3, 0x04 },
- { 0xd010, 3, 3, 0x05 },
- { 0xd016, 4, 4, 0x03 },
- { 0xd01f, 0, 6, 0x0a },
- { 0xd020, 0, 6, 0x0a },
- { 0x9bda, 0, 8, 0x01 },
- { 0x9be3, 0, 8, 0x01 },
- { 0xd1a0, 1, 1, 0x00 },
- { 0x9bbe, 0, 1, 0x01 },
- { 0x9bcc, 0, 1, 0x01 },
- { 0x9bb9, 0, 8, 0x00 },
- { 0x9bcd, 0, 8, 0x18 },
- { 0x9bff, 0, 8, 0x2c },
- { 0xd015, 0, 8, 0x46 },
- { 0xd016, 0, 1, 0x00 },
- { 0xd044, 0, 8, 0x46 },
- { 0xd045, 0, 1, 0x00 },
- { 0xd008, 0, 8, 0xdf },
- { 0xd009, 0, 2, 0x02 },
- { 0xd006, 0, 8, 0x44 },
- { 0xd007, 0, 2, 0x01 },
- { 0xd00c, 0, 8, 0x00 },
- { 0xd00d, 0, 2, 0x02 },
- { 0xd00a, 0, 8, 0xf6 },
- { 0xd00b, 0, 2, 0x01 },
- { 0x9bba, 0, 8, 0xf9 },
- { 0x9bc8, 0, 8, 0xaa },
- { 0x9bc3, 0, 8, 0xdf },
- { 0x9bc4, 0, 8, 0x02 },
- { 0x9bc5, 0, 8, 0x00 },
- { 0x9bc6, 0, 8, 0x02 },
- { 0x9bc9, 0, 8, 0xf0 },
- { 0xd011, 0, 8, 0x3c },
- { 0xd012, 0, 2, 0x01 },
- { 0xd013, 0, 8, 0xf7 },
- { 0xd014, 0, 2, 0x02 },
- { 0xd040, 0, 8, 0x0b },
- { 0xd041, 0, 2, 0x02 },
- { 0xd042, 0, 8, 0x4d },
- { 0xd043, 0, 2, 0x00 },
- { 0xd045, 1, 1, 0x00 },
- { 0x9bcf, 0, 1, 0x01 },
- { 0xd045, 2, 1, 0x01 },
- { 0xd04f, 0, 8, 0x9a },
- { 0xd050, 0, 1, 0x01 },
- { 0xd051, 0, 8, 0x5a },
- { 0xd052, 0, 1, 0x01 },
- { 0xd053, 0, 8, 0x50 },
- { 0xd054, 0, 8, 0x46 },
- { 0x9bd7, 0, 8, 0x0a },
- { 0x9bd8, 0, 8, 0x14 },
- { 0x9bd9, 0, 8, 0x08 },
- { 0x9bd0, 0, 8, 0xa8 },
- { 0x9be4, 0, 8, 0x7f },
- { 0x9bbd, 0, 8, 0xa8 },
- { 0x9be2, 0, 8, 0x20 },
- { 0x9bee, 0, 1, 0x01 },
+/*
+ * NXP TDA18271 & TDA18218 tuner init
+ * AF9013_TUNER_TDA18271 0x9c
+ * AF9013_TUNER_TDA18218 0xb3
+ */
+static const struct af9013_reg_mask_val tuner_init_tab_tda18271[] = {
+ {0x9bd5, 0xff, 0x01},
+ {0x9bd6, 0xff, 0x04},
+ {0xd1a0, 0x02, 0x02},
+ {0xd000, 0x01, 0x01},
+ {0xd000, 0x02, 0x00},
+ {0xd001, 0x02, 0x02},
+ {0xd001, 0x01, 0x00},
+ {0xd001, 0x20, 0x00},
+ {0xd002, 0x1f, 0x19},
+ {0xd003, 0x1f, 0x1a},
+ {0xd004, 0x1f, 0x19},
+ {0xd005, 0x1f, 0x1a},
+ {0xd00e, 0x1f, 0x10},
+ {0xd00f, 0x07, 0x04},
+ {0xd00f, 0x38, 0x28},
+ {0xd010, 0x07, 0x04},
+ {0xd010, 0x38, 0x28},
+ {0xd016, 0xf0, 0x30},
+ {0xd01f, 0x3f, 0x0a},
+ {0xd020, 0x3f, 0x0a},
+ {0x9bda, 0xff, 0x01},
+ {0x9be3, 0xff, 0x01},
+ {0xd1a0, 0x02, 0x00},
+ {0x9bbe, 0x01, 0x01},
+ {0x9bcc, 0x01, 0x01},
+ {0x9bb9, 0xff, 0x00},
+ {0x9bcd, 0xff, 0x18},
+ {0x9bff, 0xff, 0x2c},
+ {0xd015, 0xff, 0x46},
+ {0xd016, 0x01, 0x00},
+ {0xd044, 0xff, 0x46},
+ {0xd045, 0x01, 0x00},
+ {0xd008, 0xff, 0xdf},
+ {0xd009, 0x03, 0x02},
+ {0xd006, 0xff, 0x44},
+ {0xd007, 0x03, 0x01},
+ {0xd00c, 0xff, 0x00},
+ {0xd00d, 0x03, 0x02},
+ {0xd00a, 0xff, 0xf6},
+ {0xd00b, 0x03, 0x01},
+ {0x9bba, 0xff, 0xf9},
+ {0x9bc8, 0xff, 0xaa},
+ {0x9bc3, 0xff, 0xdf},
+ {0x9bc4, 0xff, 0x02},
+ {0x9bc5, 0xff, 0x00},
+ {0x9bc6, 0xff, 0x02},
+ {0x9bc9, 0xff, 0xf0},
+ {0xd011, 0xff, 0x3c},
+ {0xd012, 0x03, 0x01},
+ {0xd013, 0xff, 0xf7},
+ {0xd014, 0x03, 0x02},
+ {0xd040, 0xff, 0x0b},
+ {0xd041, 0x03, 0x02},
+ {0xd042, 0xff, 0x4d},
+ {0xd043, 0x03, 0x00},
+ {0xd045, 0x02, 0x00},
+ {0x9bcf, 0x01, 0x01},
+ {0xd045, 0x04, 0x04},
+ {0xd04f, 0xff, 0x9a},
+ {0xd050, 0x01, 0x01},
+ {0xd051, 0xff, 0x5a},
+ {0xd052, 0x01, 0x01},
+ {0xd053, 0xff, 0x50},
+ {0xd054, 0xff, 0x46},
+ {0x9bd7, 0xff, 0x0a},
+ {0x9bd8, 0xff, 0x14},
+ {0x9bd9, 0xff, 0x08},
+ {0x9bd0, 0xff, 0xa8},
+ {0x9be4, 0xff, 0x7f},
+ {0x9bbd, 0xff, 0xa8},
+ {0x9be2, 0xff, 0x20},
+ {0x9bee, 0x01, 0x01},
};
#endif /* AF9013_PRIV_H */
diff --git a/drivers/staging/media/cxd2099/cxd2099.c b/drivers/media/dvb-frontends/cxd2099.c
index dc9cbd8f2104..c0a5849b76bb 100644
--- a/drivers/staging/media/cxd2099/cxd2099.c
+++ b/drivers/media/dvb-frontends/cxd2099.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
+#include <linux/regmap.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/mutex.h>
@@ -33,8 +34,9 @@ static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount);
struct cxd {
struct dvb_ca_en50221 en;
- struct i2c_adapter *i2c;
struct cxd2099_cfg cfg;
+ struct i2c_client *client;
+ struct regmap *regmap;
u8 regs[0x23];
u8 lastaddress;
@@ -56,69 +58,12 @@ struct cxd {
u8 wbuf[1028];
};
-static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr,
- u8 reg, u8 data)
-{
- u8 m[2] = {reg, data};
- struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = 2};
-
- if (i2c_transfer(adapter, &msg, 1) != 1) {
- dev_err(&adapter->dev,
- "Failed to write to I2C register %02x@%02x!\n",
- reg, adr);
- return -1;
- }
- return 0;
-}
-
-static int i2c_write(struct i2c_adapter *adapter, u8 adr,
- u8 *data, u16 len)
-{
- struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len};
-
- if (i2c_transfer(adapter, &msg, 1) != 1) {
- dev_err(&adapter->dev, "Failed to write to I2C!\n");
- return -1;
- }
- return 0;
-}
-
-static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr,
- u8 reg, u8 *val)
-{
- struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
- .buf = &reg, .len = 1},
- {.addr = adr, .flags = I2C_M_RD,
- .buf = val, .len = 1} };
-
- if (i2c_transfer(adapter, msgs, 2) != 2) {
- dev_err(&adapter->dev, "error in %s()\n", __func__);
- return -1;
- }
- return 0;
-}
-
-static int i2c_read(struct i2c_adapter *adapter, u8 adr,
- u8 reg, u8 *data, u16 n)
-{
- struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
- .buf = &reg, .len = 1},
- {.addr = adr, .flags = I2C_M_RD,
- .buf = data, .len = n} };
-
- if (i2c_transfer(adapter, msgs, 2) != 2) {
- dev_err(&adapter->dev, "error in %s()\n", __func__);
- return -1;
- }
- return 0;
-}
-
static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
{
int status = 0;
if (ci->lastaddress != adr)
- status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
+ status = regmap_write(ci->regmap, 0, adr);
if (!status) {
ci->lastaddress = adr;
@@ -127,7 +72,7 @@ static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
if (ci->cfg.max_i2c && len > ci->cfg.max_i2c)
len = ci->cfg.max_i2c;
- status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, len);
+ status = regmap_raw_read(ci->regmap, 1, data, len);
if (status)
return status;
data += len;
@@ -145,64 +90,66 @@ static int read_reg(struct cxd *ci, u8 reg, u8 *val)
static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
{
int status;
- u8 addr[3] = {2, address & 0xff, address >> 8};
+ u8 addr[2] = {address & 0xff, address >> 8};
- status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
+ status = regmap_raw_write(ci->regmap, 2, addr, 2);
if (!status)
- status = i2c_read(ci->i2c, ci->cfg.adr, 3, data, n);
+ status = regmap_raw_read(ci->regmap, 3, data, n);
return status;
}
static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
{
int status;
- u8 addr[3] = {2, address & 0xff, address >> 8};
+ u8 addr[2] = {address & 0xff, address >> 8};
- status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
+ status = regmap_raw_write(ci->regmap, 2, addr, 2);
if (!status) {
- u8 buf[256] = {3};
+ u8 buf[256];
- memcpy(buf + 1, data, n);
- status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
+ memcpy(buf, data, n);
+ status = regmap_raw_write(ci->regmap, 3, buf, n);
}
return status;
}
-static int read_io(struct cxd *ci, u16 address, u8 *val)
+static int read_io(struct cxd *ci, u16 address, unsigned int *val)
{
int status;
- u8 addr[3] = {2, address & 0xff, address >> 8};
+ u8 addr[2] = {address & 0xff, address >> 8};
- status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
+ status = regmap_raw_write(ci->regmap, 2, addr, 2);
if (!status)
- status = i2c_read(ci->i2c, ci->cfg.adr, 3, val, 1);
+ status = regmap_read(ci->regmap, 3, val);
return status;
}
static int write_io(struct cxd *ci, u16 address, u8 val)
{
int status;
- u8 addr[3] = {2, address & 0xff, address >> 8};
- u8 buf[2] = {3, val};
+ u8 addr[2] = {address & 0xff, address >> 8};
- status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
+ status = regmap_raw_write(ci->regmap, 2, addr, 2);
if (!status)
- status = i2c_write(ci->i2c, ci->cfg.adr, buf, 2);
+ status = regmap_write(ci->regmap, 3, val);
return status;
}
static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask)
{
int status = 0;
+ unsigned int regval;
if (ci->lastaddress != reg)
- status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, reg);
- if (!status && reg >= 6 && reg <= 8 && mask != 0xff)
- status = i2c_read_reg(ci->i2c, ci->cfg.adr, 1, &ci->regs[reg]);
+ status = regmap_write(ci->regmap, 0, reg);
+ if (!status && reg >= 6 && reg <= 8 && mask != 0xff) {
+ status = regmap_read(ci->regmap, 1, &regval);
+ ci->regs[reg] = regval;
+ }
ci->lastaddress = reg;
ci->regs[reg] = (ci->regs[reg] & (~mask)) | val;
if (!status)
- status = i2c_write_reg(ci->i2c, ci->cfg.adr, 1, ci->regs[reg]);
+ status = regmap_write(ci->regmap, 1, ci->regs[reg]);
if (reg == 0x20)
ci->regs[reg] &= 0x7f;
return status;
@@ -219,19 +166,18 @@ static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
u8 *buf = ci->wbuf;
if (ci->lastaddress != adr)
- status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
+ status = regmap_write(ci->regmap, 0, adr);
if (status)
return status;
ci->lastaddress = adr;
- buf[0] = 1;
while (n) {
int len = n;
if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c))
len = ci->cfg.max_i2c - 1;
- memcpy(buf + 1, data, len);
- status = i2c_write(ci->i2c, ci->cfg.adr, buf, len + 1);
+ memcpy(buf, data, len);
+ status = regmap_raw_write(ci->regmap, 1, buf, len);
if (status)
return status;
n -= len;
@@ -273,7 +219,7 @@ static void cam_mode(struct cxd *ci, int mode)
if (!ci->en.read_data)
return;
ci->write_busy = 0;
- dev_info(&ci->i2c->dev, "enable cam buffer mode\n");
+ dev_info(&ci->client->dev, "enable cam buffer mode\n");
write_reg(ci, 0x0d, 0x00);
write_reg(ci, 0x0e, 0x01);
write_regm(ci, 0x08, 0x40, 0x40);
@@ -464,7 +410,7 @@ static int read_cam_control(struct dvb_ca_en50221 *ca,
int slot, u8 address)
{
struct cxd *ci = ca->data;
- u8 val;
+ unsigned int val;
mutex_lock(&ci->lock);
set_mode(ci, 0);
@@ -518,7 +464,7 @@ static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
{
struct cxd *ci = ca->data;
- dev_dbg(&ci->i2c->dev, "%s\n", __func__);
+ dev_dbg(&ci->client->dev, "%s\n", __func__);
if (ci->cammode)
read_data(ca, slot, ci->rbuf, 0);
mutex_lock(&ci->lock);
@@ -577,7 +523,7 @@ static int campoll(struct cxd *ci)
if (ci->slot_stat) {
ci->slot_stat = 0;
write_regm(ci, 0x03, 0x00, 0x08);
- dev_info(&ci->i2c->dev, "NO CAM\n");
+ dev_info(&ci->client->dev, "NO CAM\n");
ci->ready = 0;
}
}
@@ -660,26 +606,41 @@ static struct dvb_ca_en50221 en_templ = {
.write_data = write_data,
};
-struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
- void *priv,
- struct i2c_adapter *i2c)
+static int cxd2099_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct cxd *ci;
- u8 val;
+ struct cxd2099_cfg *cfg = client->dev.platform_data;
+ static const struct regmap_config rm_cfg = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ };
+ unsigned int val;
+ int ret;
- if (i2c_read_reg(i2c, cfg->adr, 0, &val) < 0) {
- dev_info(&i2c->dev, "No CXD2099AR detected at 0x%02x\n",
- cfg->adr);
- return NULL;
+ ci = kzalloc(sizeof(*ci), GFP_KERNEL);
+ if (!ci) {
+ ret = -ENOMEM;
+ goto err;
}
- ci = kzalloc(sizeof(*ci), GFP_KERNEL);
- if (!ci)
- return NULL;
+ ci->client = client;
+ memcpy(&ci->cfg, cfg, sizeof(ci->cfg));
+
+ ci->regmap = regmap_init_i2c(client, &rm_cfg);
+ if (IS_ERR(ci->regmap)) {
+ ret = PTR_ERR(ci->regmap);
+ goto err_kfree;
+ }
+
+ ret = regmap_read(ci->regmap, 0x00, &val);
+ if (ret < 0) {
+ dev_info(&client->dev, "No CXD2099AR detected at 0x%02x\n",
+ client->addr);
+ goto err_rmexit;
+ }
mutex_init(&ci->lock);
- ci->cfg = *cfg;
- ci->i2c = i2c;
ci->lastaddress = 0xff;
ci->clk_reg_b = 0x4a;
ci->clk_reg_f = 0x1b;
@@ -687,18 +648,56 @@ struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
ci->en = en_templ;
ci->en.data = ci;
init(ci);
- dev_info(&i2c->dev, "Attached CXD2099AR at 0x%02x\n", ci->cfg.adr);
+ dev_info(&client->dev, "Attached CXD2099AR at 0x%02x\n", client->addr);
+
+ *cfg->en = &ci->en;
if (!buffermode) {
ci->en.read_data = NULL;
ci->en.write_data = NULL;
} else {
- dev_info(&i2c->dev, "Using CXD2099AR buffer mode");
+ dev_info(&client->dev, "Using CXD2099AR buffer mode");
}
- return &ci->en;
+ i2c_set_clientdata(client, ci);
+
+ return 0;
+
+err_rmexit:
+ regmap_exit(ci->regmap);
+err_kfree:
+ kfree(ci);
+err:
+
+ return ret;
}
-EXPORT_SYMBOL(cxd2099_attach);
+
+static int cxd2099_remove(struct i2c_client *client)
+{
+ struct cxd *ci = i2c_get_clientdata(client);
+
+ regmap_exit(ci->regmap);
+ kfree(ci);
+
+ return 0;
+}
+
+static const struct i2c_device_id cxd2099_id[] = {
+ {"cxd2099", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cxd2099_id);
+
+static struct i2c_driver cxd2099_driver = {
+ .driver = {
+ .name = "cxd2099",
+ },
+ .probe = cxd2099_probe,
+ .remove = cxd2099_remove,
+ .id_table = cxd2099_id,
+};
+
+module_i2c_driver(cxd2099_driver);
MODULE_DESCRIPTION("CXD2099AR Common Interface controller driver");
MODULE_AUTHOR("Ralph Metzler");
diff --git a/drivers/staging/media/cxd2099/cxd2099.h b/drivers/media/dvb-frontends/cxd2099.h
index 253e3155a6df..8fa45a4c615a 100644
--- a/drivers/staging/media/cxd2099/cxd2099.h
+++ b/drivers/media/dvb-frontends/cxd2099.h
@@ -20,26 +20,13 @@
struct cxd2099_cfg {
u32 bitrate;
- u8 adr;
u8 polarity;
u8 clock_mode;
u32 max_i2c;
-};
-
-#if defined(CONFIG_DVB_CXD2099) || \
- (defined(CONFIG_DVB_CXD2099_MODULE) && defined(MODULE))
-struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
- void *priv, struct i2c_adapter *i2c);
-#else
-static inline struct
-dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg, void *priv,
- struct i2c_adapter *i2c)
-{
- dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-#endif
+ /* ptr to DVB CA struct */
+ struct dvb_ca_en50221 **en;
+};
#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/Kconfig b/drivers/media/dvb-frontends/cxd2880/Kconfig
new file mode 100644
index 000000000000..9d989676e800
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/Kconfig
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config DVB_CXD2880
+ tristate "Sony CXD2880 DVB-T2/T tuner + demodulator"
+ depends on DVB_CORE && SPI
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y when you want to support this frontend. \ No newline at end of file
diff --git a/drivers/media/dvb-frontends/cxd2880/Makefile b/drivers/media/dvb-frontends/cxd2880/Makefile
new file mode 100644
index 000000000000..c6baa4caba19
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/Makefile
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0
+
+cxd2880-objs := cxd2880_common.o \
+ cxd2880_devio_spi.o \
+ cxd2880_integ.o \
+ cxd2880_io.o \
+ cxd2880_spi_device.o \
+ cxd2880_tnrdmd.o \
+ cxd2880_tnrdmd_dvbt2.o \
+ cxd2880_tnrdmd_dvbt2_mon.o \
+ cxd2880_tnrdmd_dvbt.o \
+ cxd2880_tnrdmd_dvbt_mon.o\
+ cxd2880_tnrdmd_mon.o\
+ cxd2880_top.o
+
+obj-$(CONFIG_DVB_CXD2880) += cxd2880.o
+
+ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880.h b/drivers/media/dvb-frontends/cxd2880/cxd2880.h
new file mode 100644
index 000000000000..4ea3510aab66
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver public definitions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_H
+#define CXD2880_H
+
+struct cxd2880_config {
+ struct spi_device *spi;
+ struct mutex *spi_mutex; /* For SPI access exclusive control */
+};
+
+#if IS_REACHABLE(CONFIG_DVB_CXD2880)
+extern struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
+ struct cxd2880_config *cfg);
+#else
+static inline struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
+ struct cxd2880_config *cfg)
+{
+ pr_warn("%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_CXD2880 */
+
+#endif /* CXD2880_H */
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
new file mode 100644
index 000000000000..d6f5af6609c1
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cxd2880_common.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common functions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#include "cxd2880_common.h"
+
+int cxd2880_convert2s_complement(u32 value, u32 bitlen)
+{
+ if (!bitlen || bitlen >= 32)
+ return (int)value;
+
+ if (value & (u32)(1 << (bitlen - 1)))
+ return (int)(GENMASK(31, bitlen) | value);
+ else
+ return (int)(GENMASK(bitlen - 1, 0) & value);
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
new file mode 100644
index 000000000000..b05bce71ab35
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_common.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver common definitions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_COMMON_H
+#define CXD2880_COMMON_H
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+
+int cxd2880_convert2s_complement(u32 value, u32 bitlen);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
new file mode 100644
index 000000000000..aba59400859e
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cxd2880_devio_spi.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * I/O interface via SPI
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#include "cxd2880_devio_spi.h"
+
+#define BURST_WRITE_MAX 128
+
+static int cxd2880_io_spi_read_reg(struct cxd2880_io *io,
+ enum cxd2880_io_tgt tgt,
+ u8 sub_address, u8 *data,
+ u32 size)
+{
+ int ret = 0;
+ struct cxd2880_spi *spi = NULL;
+ u8 send_data[6];
+ u8 *read_data_top = data;
+
+ if (!io || !io->if_object || !data)
+ return -EINVAL;
+
+ if (sub_address + size > 0x100)
+ return -EINVAL;
+
+ spi = io->if_object;
+
+ if (tgt == CXD2880_IO_TGT_SYS)
+ send_data[0] = 0x0b;
+ else
+ send_data[0] = 0x0a;
+
+ send_data[3] = 0;
+ send_data[4] = 0;
+ send_data[5] = 0;
+
+ while (size > 0) {
+ send_data[1] = sub_address;
+ if (size > 255)
+ send_data[2] = 255;
+ else
+ send_data[2] = size;
+
+ ret =
+ spi->write_read(spi, send_data, sizeof(send_data),
+ read_data_top, send_data[2]);
+ if (ret)
+ return ret;
+
+ sub_address += send_data[2];
+ read_data_top += send_data[2];
+ size -= send_data[2];
+ }
+
+ return ret;
+}
+
+static int cxd2880_io_spi_write_reg(struct cxd2880_io *io,
+ enum cxd2880_io_tgt tgt,
+ u8 sub_address,
+ const u8 *data, u32 size)
+{
+ int ret = 0;
+ struct cxd2880_spi *spi = NULL;
+ u8 send_data[BURST_WRITE_MAX + 4];
+ const u8 *write_data_top = data;
+
+ if (!io || !io->if_object || !data)
+ return -EINVAL;
+
+ if (size > BURST_WRITE_MAX)
+ return -EINVAL;
+
+ if (sub_address + size > 0x100)
+ return -EINVAL;
+
+ spi = io->if_object;
+
+ if (tgt == CXD2880_IO_TGT_SYS)
+ send_data[0] = 0x0f;
+ else
+ send_data[0] = 0x0e;
+
+ while (size > 0) {
+ send_data[1] = sub_address;
+ if (size > 255)
+ send_data[2] = 255;
+ else
+ send_data[2] = size;
+
+ memcpy(&send_data[3], write_data_top, send_data[2]);
+
+ if (tgt == CXD2880_IO_TGT_SYS) {
+ send_data[3 + send_data[2]] = 0x00;
+ ret = spi->write(spi, send_data, send_data[2] + 4);
+ } else {
+ ret = spi->write(spi, send_data, send_data[2] + 3);
+ }
+ if (ret)
+ return ret;
+
+ sub_address += send_data[2];
+ write_data_top += send_data[2];
+ size -= send_data[2];
+ }
+
+ return ret;
+}
+
+int cxd2880_io_spi_create(struct cxd2880_io *io,
+ struct cxd2880_spi *spi, u8 slave_select)
+{
+ if (!io || !spi)
+ return -EINVAL;
+
+ io->read_regs = cxd2880_io_spi_read_reg;
+ io->write_regs = cxd2880_io_spi_write_reg;
+ io->write_reg = cxd2880_io_common_write_one_reg;
+ io->if_object = spi;
+ io->i2c_address_sys = 0;
+ io->i2c_address_demod = 0;
+ io->slave_select = slave_select;
+
+ return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
new file mode 100644
index 000000000000..27f7cb12fad4
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_devio_spi.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * I/O interface via SPI
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_DEVIO_SPI_H
+#define CXD2880_DEVIO_SPI_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_io.h"
+#include "cxd2880_spi.h"
+
+#include "cxd2880_tnrdmd.h"
+
+int cxd2880_io_spi_create(struct cxd2880_io *io,
+ struct cxd2880_spi *spi,
+ u8 slave_select);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
new file mode 100644
index 000000000000..820f4757a520
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_dtv.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DTV related definitions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_DTV_H
+#define CXD2880_DTV_H
+
+enum cxd2880_dtv_sys {
+ CXD2880_DTV_SYS_UNKNOWN,
+ CXD2880_DTV_SYS_DVBT,
+ CXD2880_DTV_SYS_DVBT2,
+ CXD2880_DTV_SYS_ANY
+};
+
+enum cxd2880_dtv_bandwidth {
+ CXD2880_DTV_BW_UNKNOWN = 0,
+ CXD2880_DTV_BW_1_7_MHZ = 1,
+ CXD2880_DTV_BW_5_MHZ = 5,
+ CXD2880_DTV_BW_6_MHZ = 6,
+ CXD2880_DTV_BW_7_MHZ = 7,
+ CXD2880_DTV_BW_8_MHZ = 8
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
new file mode 100644
index 000000000000..76a1acc346ef
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_dvbt.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T related definitions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_DVBT_H
+#define CXD2880_DVBT_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_dvbt_constellation {
+ CXD2880_DVBT_CONSTELLATION_QPSK,
+ CXD2880_DVBT_CONSTELLATION_16QAM,
+ CXD2880_DVBT_CONSTELLATION_64QAM,
+ CXD2880_DVBT_CONSTELLATION_RESERVED_3
+};
+
+enum cxd2880_dvbt_hierarchy {
+ CXD2880_DVBT_HIERARCHY_NON,
+ CXD2880_DVBT_HIERARCHY_1,
+ CXD2880_DVBT_HIERARCHY_2,
+ CXD2880_DVBT_HIERARCHY_4
+};
+
+enum cxd2880_dvbt_coderate {
+ CXD2880_DVBT_CODERATE_1_2,
+ CXD2880_DVBT_CODERATE_2_3,
+ CXD2880_DVBT_CODERATE_3_4,
+ CXD2880_DVBT_CODERATE_5_6,
+ CXD2880_DVBT_CODERATE_7_8,
+ CXD2880_DVBT_CODERATE_RESERVED_5,
+ CXD2880_DVBT_CODERATE_RESERVED_6,
+ CXD2880_DVBT_CODERATE_RESERVED_7
+};
+
+enum cxd2880_dvbt_guard {
+ CXD2880_DVBT_GUARD_1_32,
+ CXD2880_DVBT_GUARD_1_16,
+ CXD2880_DVBT_GUARD_1_8,
+ CXD2880_DVBT_GUARD_1_4
+};
+
+enum cxd2880_dvbt_mode {
+ CXD2880_DVBT_MODE_2K,
+ CXD2880_DVBT_MODE_8K,
+ CXD2880_DVBT_MODE_RESERVED_2,
+ CXD2880_DVBT_MODE_RESERVED_3
+};
+
+enum cxd2880_dvbt_profile {
+ CXD2880_DVBT_PROFILE_HP = 0,
+ CXD2880_DVBT_PROFILE_LP
+};
+
+struct cxd2880_dvbt_tpsinfo {
+ enum cxd2880_dvbt_constellation constellation;
+ enum cxd2880_dvbt_hierarchy hierarchy;
+ enum cxd2880_dvbt_coderate rate_hp;
+ enum cxd2880_dvbt_coderate rate_lp;
+ enum cxd2880_dvbt_guard guard;
+ enum cxd2880_dvbt_mode mode;
+ u8 fnum;
+ u8 length_indicator;
+ u16 cell_id;
+ u8 cell_id_ok;
+ u8 reserved_even;
+ u8 reserved_odd;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
new file mode 100644
index 000000000000..191047b158fe
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
@@ -0,0 +1,385 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_dvbt2.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T2 related definitions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_DVBT2_H
+#define CXD2880_DVBT2_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_dvbt2_profile {
+ CXD2880_DVBT2_PROFILE_BASE,
+ CXD2880_DVBT2_PROFILE_LITE,
+ CXD2880_DVBT2_PROFILE_ANY
+};
+
+enum cxd2880_dvbt2_version {
+ CXD2880_DVBT2_V111,
+ CXD2880_DVBT2_V121,
+ CXD2880_DVBT2_V131
+};
+
+enum cxd2880_dvbt2_s1 {
+ CXD2880_DVBT2_S1_BASE_SISO = 0x00,
+ CXD2880_DVBT2_S1_BASE_MISO = 0x01,
+ CXD2880_DVBT2_S1_NON_DVBT2 = 0x02,
+ CXD2880_DVBT2_S1_LITE_SISO = 0x03,
+ CXD2880_DVBT2_S1_LITE_MISO = 0x04,
+ CXD2880_DVBT2_S1_RSVD3 = 0x05,
+ CXD2880_DVBT2_S1_RSVD4 = 0x06,
+ CXD2880_DVBT2_S1_RSVD5 = 0x07,
+ CXD2880_DVBT2_S1_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_base_s2 {
+ CXD2880_DVBT2_BASE_S2_M2K_G_ANY = 0x00,
+ CXD2880_DVBT2_BASE_S2_M8K_G_DVBT = 0x01,
+ CXD2880_DVBT2_BASE_S2_M4K_G_ANY = 0x02,
+ CXD2880_DVBT2_BASE_S2_M1K_G_ANY = 0x03,
+ CXD2880_DVBT2_BASE_S2_M16K_G_ANY = 0x04,
+ CXD2880_DVBT2_BASE_S2_M32K_G_DVBT = 0x05,
+ CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2 = 0x06,
+ CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2 = 0x07,
+ CXD2880_DVBT2_BASE_S2_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_lite_s2 {
+ CXD2880_DVBT2_LITE_S2_M2K_G_ANY = 0x00,
+ CXD2880_DVBT2_LITE_S2_M8K_G_DVBT = 0x01,
+ CXD2880_DVBT2_LITE_S2_M4K_G_ANY = 0x02,
+ CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2 = 0x03,
+ CXD2880_DVBT2_LITE_S2_M16K_G_DVBT = 0x04,
+ CXD2880_DVBT2_LITE_S2_RSVD1 = 0x05,
+ CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2 = 0x06,
+ CXD2880_DVBT2_LITE_S2_RSVD2 = 0x07,
+ CXD2880_DVBT2_LITE_S2_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_guard {
+ CXD2880_DVBT2_G1_32 = 0x00,
+ CXD2880_DVBT2_G1_16 = 0x01,
+ CXD2880_DVBT2_G1_8 = 0x02,
+ CXD2880_DVBT2_G1_4 = 0x03,
+ CXD2880_DVBT2_G1_128 = 0x04,
+ CXD2880_DVBT2_G19_128 = 0x05,
+ CXD2880_DVBT2_G19_256 = 0x06,
+ CXD2880_DVBT2_G_RSVD1 = 0x07,
+ CXD2880_DVBT2_G_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_mode {
+ CXD2880_DVBT2_M2K = 0x00,
+ CXD2880_DVBT2_M8K = 0x01,
+ CXD2880_DVBT2_M4K = 0x02,
+ CXD2880_DVBT2_M1K = 0x03,
+ CXD2880_DVBT2_M16K = 0x04,
+ CXD2880_DVBT2_M32K = 0x05,
+ CXD2880_DVBT2_M_RSVD1 = 0x06,
+ CXD2880_DVBT2_M_RSVD2 = 0x07
+};
+
+enum cxd2880_dvbt2_bw {
+ CXD2880_DVBT2_BW_8 = 0x00,
+ CXD2880_DVBT2_BW_7 = 0x01,
+ CXD2880_DVBT2_BW_6 = 0x02,
+ CXD2880_DVBT2_BW_5 = 0x03,
+ CXD2880_DVBT2_BW_10 = 0x04,
+ CXD2880_DVBT2_BW_1_7 = 0x05,
+ CXD2880_DVBT2_BW_RSVD1 = 0x06,
+ CXD2880_DVBT2_BW_RSVD2 = 0x07,
+ CXD2880_DVBT2_BW_RSVD3 = 0x08,
+ CXD2880_DVBT2_BW_RSVD4 = 0x09,
+ CXD2880_DVBT2_BW_RSVD5 = 0x0a,
+ CXD2880_DVBT2_BW_RSVD6 = 0x0b,
+ CXD2880_DVBT2_BW_RSVD7 = 0x0c,
+ CXD2880_DVBT2_BW_RSVD8 = 0x0d,
+ CXD2880_DVBT2_BW_RSVD9 = 0x0e,
+ CXD2880_DVBT2_BW_RSVD10 = 0x0f,
+ CXD2880_DVBT2_BW_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_l1pre_type {
+ CXD2880_DVBT2_L1PRE_TYPE_TS = 0x00,
+ CXD2880_DVBT2_L1PRE_TYPE_GS = 0x01,
+ CXD2880_DVBT2_L1PRE_TYPE_TS_GS = 0x02,
+ CXD2880_DVBT2_L1PRE_TYPE_RESERVED = 0x03,
+ CXD2880_DVBT2_L1PRE_TYPE_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_papr {
+ CXD2880_DVBT2_PAPR_0 = 0x00,
+ CXD2880_DVBT2_PAPR_1 = 0x01,
+ CXD2880_DVBT2_PAPR_2 = 0x02,
+ CXD2880_DVBT2_PAPR_3 = 0x03,
+ CXD2880_DVBT2_PAPR_RSVD1 = 0x04,
+ CXD2880_DVBT2_PAPR_RSVD2 = 0x05,
+ CXD2880_DVBT2_PAPR_RSVD3 = 0x06,
+ CXD2880_DVBT2_PAPR_RSVD4 = 0x07,
+ CXD2880_DVBT2_PAPR_RSVD5 = 0x08,
+ CXD2880_DVBT2_PAPR_RSVD6 = 0x09,
+ CXD2880_DVBT2_PAPR_RSVD7 = 0x0a,
+ CXD2880_DVBT2_PAPR_RSVD8 = 0x0b,
+ CXD2880_DVBT2_PAPR_RSVD9 = 0x0c,
+ CXD2880_DVBT2_PAPR_RSVD10 = 0x0d,
+ CXD2880_DVBT2_PAPR_RSVD11 = 0x0e,
+ CXD2880_DVBT2_PAPR_RSVD12 = 0x0f,
+ CXD2880_DVBT2_PAPR_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_l1post_constell {
+ CXD2880_DVBT2_L1POST_BPSK = 0x00,
+ CXD2880_DVBT2_L1POST_QPSK = 0x01,
+ CXD2880_DVBT2_L1POST_QAM16 = 0x02,
+ CXD2880_DVBT2_L1POST_QAM64 = 0x03,
+ CXD2880_DVBT2_L1POST_C_RSVD1 = 0x04,
+ CXD2880_DVBT2_L1POST_C_RSVD2 = 0x05,
+ CXD2880_DVBT2_L1POST_C_RSVD3 = 0x06,
+ CXD2880_DVBT2_L1POST_C_RSVD4 = 0x07,
+ CXD2880_DVBT2_L1POST_C_RSVD5 = 0x08,
+ CXD2880_DVBT2_L1POST_C_RSVD6 = 0x09,
+ CXD2880_DVBT2_L1POST_C_RSVD7 = 0x0a,
+ CXD2880_DVBT2_L1POST_C_RSVD8 = 0x0b,
+ CXD2880_DVBT2_L1POST_C_RSVD9 = 0x0c,
+ CXD2880_DVBT2_L1POST_C_RSVD10 = 0x0d,
+ CXD2880_DVBT2_L1POST_C_RSVD11 = 0x0e,
+ CXD2880_DVBT2_L1POST_C_RSVD12 = 0x0f,
+ CXD2880_DVBT2_L1POST_CONSTELL_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_l1post_cr {
+ CXD2880_DVBT2_L1POST_R1_2 = 0x00,
+ CXD2880_DVBT2_L1POST_R_RSVD1 = 0x01,
+ CXD2880_DVBT2_L1POST_R_RSVD2 = 0x02,
+ CXD2880_DVBT2_L1POST_R_RSVD3 = 0x03,
+ CXD2880_DVBT2_L1POST_R_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_l1post_fec_type {
+ CXD2880_DVBT2_L1POST_FEC_LDPC16K = 0x00,
+ CXD2880_DVBT2_L1POST_FEC_RSVD1 = 0x01,
+ CXD2880_DVBT2_L1POST_FEC_RSVD2 = 0x02,
+ CXD2880_DVBT2_L1POST_FEC_RSVD3 = 0x03,
+ CXD2880_DVBT2_L1POST_FEC_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_pp {
+ CXD2880_DVBT2_PP1 = 0x00,
+ CXD2880_DVBT2_PP2 = 0x01,
+ CXD2880_DVBT2_PP3 = 0x02,
+ CXD2880_DVBT2_PP4 = 0x03,
+ CXD2880_DVBT2_PP5 = 0x04,
+ CXD2880_DVBT2_PP6 = 0x05,
+ CXD2880_DVBT2_PP7 = 0x06,
+ CXD2880_DVBT2_PP8 = 0x07,
+ CXD2880_DVBT2_PP_RSVD1 = 0x08,
+ CXD2880_DVBT2_PP_RSVD2 = 0x09,
+ CXD2880_DVBT2_PP_RSVD3 = 0x0a,
+ CXD2880_DVBT2_PP_RSVD4 = 0x0b,
+ CXD2880_DVBT2_PP_RSVD5 = 0x0c,
+ CXD2880_DVBT2_PP_RSVD6 = 0x0d,
+ CXD2880_DVBT2_PP_RSVD7 = 0x0e,
+ CXD2880_DVBT2_PP_RSVD8 = 0x0f,
+ CXD2880_DVBT2_PP_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_code_rate {
+ CXD2880_DVBT2_R1_2 = 0x00,
+ CXD2880_DVBT2_R3_5 = 0x01,
+ CXD2880_DVBT2_R2_3 = 0x02,
+ CXD2880_DVBT2_R3_4 = 0x03,
+ CXD2880_DVBT2_R4_5 = 0x04,
+ CXD2880_DVBT2_R5_6 = 0x05,
+ CXD2880_DVBT2_R1_3 = 0x06,
+ CXD2880_DVBT2_R2_5 = 0x07,
+ CXD2880_DVBT2_PLP_CR_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_constell {
+ CXD2880_DVBT2_QPSK = 0x00,
+ CXD2880_DVBT2_QAM16 = 0x01,
+ CXD2880_DVBT2_QAM64 = 0x02,
+ CXD2880_DVBT2_QAM256 = 0x03,
+ CXD2880_DVBT2_CON_RSVD1 = 0x04,
+ CXD2880_DVBT2_CON_RSVD2 = 0x05,
+ CXD2880_DVBT2_CON_RSVD3 = 0x06,
+ CXD2880_DVBT2_CON_RSVD4 = 0x07,
+ CXD2880_DVBT2_CONSTELL_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_type {
+ CXD2880_DVBT2_PLP_TYPE_COMMON = 0x00,
+ CXD2880_DVBT2_PLP_TYPE_DATA1 = 0x01,
+ CXD2880_DVBT2_PLP_TYPE_DATA2 = 0x02,
+ CXD2880_DVBT2_PLP_TYPE_RSVD1 = 0x03,
+ CXD2880_DVBT2_PLP_TYPE_RSVD2 = 0x04,
+ CXD2880_DVBT2_PLP_TYPE_RSVD3 = 0x05,
+ CXD2880_DVBT2_PLP_TYPE_RSVD4 = 0x06,
+ CXD2880_DVBT2_PLP_TYPE_RSVD5 = 0x07,
+ CXD2880_DVBT2_PLP_TYPE_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_payload {
+ CXD2880_DVBT2_PLP_PAYLOAD_GFPS = 0x00,
+ CXD2880_DVBT2_PLP_PAYLOAD_GCS = 0x01,
+ CXD2880_DVBT2_PLP_PAYLOAD_GSE = 0x02,
+ CXD2880_DVBT2_PLP_PAYLOAD_TS = 0x03,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD1 = 0x04,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD2 = 0x05,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD3 = 0x06,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD4 = 0x07,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD5 = 0x08,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD6 = 0x09,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD7 = 0x0a,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD8 = 0x0b,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD9 = 0x0c,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD10 = 0x0d,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD11 = 0x0e,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD12 = 0x0f,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD13 = 0x10,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD14 = 0x11,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD15 = 0x12,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD16 = 0x13,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD17 = 0x14,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD18 = 0x15,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD19 = 0x16,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD20 = 0x17,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD21 = 0x18,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD22 = 0x19,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD23 = 0x1a,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD24 = 0x1b,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD25 = 0x1c,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD26 = 0x1d,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD27 = 0x1e,
+ CXD2880_DVBT2_PLP_PAYLOAD_RSVD28 = 0x1f,
+ CXD2880_DVBT2_PLP_PAYLOAD_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_fec {
+ CXD2880_DVBT2_FEC_LDPC_16K = 0x00,
+ CXD2880_DVBT2_FEC_LDPC_64K = 0x01,
+ CXD2880_DVBT2_FEC_RSVD1 = 0x02,
+ CXD2880_DVBT2_FEC_RSVD2 = 0x03,
+ CXD2880_DVBT2_FEC_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_mode {
+ CXD2880_DVBT2_PLP_MODE_NOTSPECIFIED = 0x00,
+ CXD2880_DVBT2_PLP_MODE_NM = 0x01,
+ CXD2880_DVBT2_PLP_MODE_HEM = 0x02,
+ CXD2880_DVBT2_PLP_MODE_RESERVED = 0x03,
+ CXD2880_DVBT2_PLP_MODE_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_btype {
+ CXD2880_DVBT2_PLP_COMMON,
+ CXD2880_DVBT2_PLP_DATA
+};
+
+enum cxd2880_dvbt2_stream {
+ CXD2880_DVBT2_STREAM_GENERIC_PACKETIZED = 0x00,
+ CXD2880_DVBT2_STREAM_GENERIC_CONTINUOUS = 0x01,
+ CXD2880_DVBT2_STREAM_GENERIC_ENCAPSULATED = 0x02,
+ CXD2880_DVBT2_STREAM_TRANSPORT = 0x03,
+ CXD2880_DVBT2_STREAM_UNKNOWN = 0xff
+};
+
+struct cxd2880_dvbt2_l1pre {
+ enum cxd2880_dvbt2_l1pre_type type;
+ u8 bw_ext;
+ enum cxd2880_dvbt2_s1 s1;
+ u8 s2;
+ u8 mixed;
+ enum cxd2880_dvbt2_mode fft_mode;
+ u8 l1_rep;
+ enum cxd2880_dvbt2_guard gi;
+ enum cxd2880_dvbt2_papr papr;
+ enum cxd2880_dvbt2_l1post_constell mod;
+ enum cxd2880_dvbt2_l1post_cr cr;
+ enum cxd2880_dvbt2_l1post_fec_type fec;
+ u32 l1_post_size;
+ u32 l1_post_info_size;
+ enum cxd2880_dvbt2_pp pp;
+ u8 tx_id_availability;
+ u16 cell_id;
+ u16 network_id;
+ u16 sys_id;
+ u8 num_frames;
+ u16 num_symbols;
+ u8 regen;
+ u8 post_ext;
+ u8 num_rf_freqs;
+ u8 rf_idx;
+ enum cxd2880_dvbt2_version t2_version;
+ u8 l1_post_scrambled;
+ u8 t2_base_lite;
+ u32 crc32;
+};
+
+struct cxd2880_dvbt2_plp {
+ u8 id;
+ enum cxd2880_dvbt2_plp_type type;
+ enum cxd2880_dvbt2_plp_payload payload;
+ u8 ff;
+ u8 first_rf_idx;
+ u8 first_frm_idx;
+ u8 group_id;
+ enum cxd2880_dvbt2_plp_constell constell;
+ enum cxd2880_dvbt2_plp_code_rate plp_cr;
+ u8 rot;
+ enum cxd2880_dvbt2_plp_fec fec;
+ u16 num_blocks_max;
+ u8 frm_int;
+ u8 til_len;
+ u8 til_type;
+ u8 in_band_a_flag;
+ u8 in_band_b_flag;
+ u16 rsvd;
+ enum cxd2880_dvbt2_plp_mode plp_mode;
+ u8 static_flag;
+ u8 static_padding_flag;
+};
+
+struct cxd2880_dvbt2_l1post {
+ u16 sub_slices_per_frame;
+ u8 num_plps;
+ u8 num_aux;
+ u8 aux_cfg_rfu;
+ u8 rf_idx;
+ u32 freq;
+ u8 fef_type;
+ u32 fef_length;
+ u8 fef_intvl;
+};
+
+struct cxd2880_dvbt2_ofdm {
+ u8 mixed;
+ u8 is_miso;
+ enum cxd2880_dvbt2_mode mode;
+ enum cxd2880_dvbt2_guard gi;
+ enum cxd2880_dvbt2_pp pp;
+ u8 bw_ext;
+ enum cxd2880_dvbt2_papr papr;
+ u16 num_symbols;
+};
+
+struct cxd2880_dvbt2_bbheader {
+ enum cxd2880_dvbt2_stream stream_input;
+ u8 is_single_input_stream;
+ u8 is_constant_coding_modulation;
+ u8 issy_indicator;
+ u8 null_packet_deletion;
+ u8 ext;
+ u8 input_stream_identifier;
+ u16 user_packet_length;
+ u16 data_field_length;
+ u8 sync_byte;
+ u32 issy;
+ enum cxd2880_dvbt2_plp_mode plp_mode;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
new file mode 100644
index 000000000000..5302ab0964c1
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cxd2880_integ.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer common functions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#include <linux/ktime.h>
+#include <linux/errno.h>
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_integ.h"
+
+int cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ int ret;
+ ktime_t start;
+ u8 cpu_task_completed = 0;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = cxd2880_tnrdmd_init1(tnr_dmd);
+ if (ret)
+ return ret;
+
+ start = ktime_get();
+
+ while (1) {
+ ret =
+ cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
+ &cpu_task_completed);
+ if (ret)
+ return ret;
+
+ if (cpu_task_completed)
+ break;
+
+ if (ktime_to_ms(ktime_sub(ktime_get(), start)) >
+ CXD2880_TNRDMD_WAIT_INIT_TIMEOUT)
+ return -ETIMEDOUT;
+
+ usleep_range(CXD2880_TNRDMD_WAIT_INIT_INTVL,
+ CXD2880_TNRDMD_WAIT_INIT_INTVL + 1000);
+ }
+
+ return cxd2880_tnrdmd_init2(tnr_dmd);
+}
+
+int cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ atomic_set(&tnr_dmd->cancel, 1);
+
+ return 0;
+}
+
+int cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (atomic_read(&tnr_dmd->cancel) != 0)
+ return -ECANCELED;
+
+ return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
new file mode 100644
index 000000000000..7160225db8b9
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_integ.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer common interface
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_INTEG_H
+#define CXD2880_INTEG_H
+
+#include "cxd2880_tnrdmd.h"
+
+#define CXD2880_TNRDMD_WAIT_INIT_TIMEOUT 500
+#define CXD2880_TNRDMD_WAIT_INIT_INTVL 10
+
+#define CXD2880_TNRDMD_WAIT_AGC_STABLE 100
+
+int cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd
+ *tnr_dmd);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
new file mode 100644
index 000000000000..9d932bccfa6c
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cxd2880_io.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * register I/O interface functions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#include "cxd2880_io.h"
+
+int cxd2880_io_common_write_one_reg(struct cxd2880_io *io,
+ enum cxd2880_io_tgt tgt,
+ u8 sub_address, u8 data)
+{
+ if (!io)
+ return -EINVAL;
+
+ return io->write_regs(io, tgt, sub_address, &data, 1);
+}
+
+int cxd2880_io_set_reg_bits(struct cxd2880_io *io,
+ enum cxd2880_io_tgt tgt,
+ u8 sub_address, u8 data, u8 mask)
+{
+ int ret;
+
+ if (!io)
+ return -EINVAL;
+
+ if (mask == 0x00)
+ return 0;
+
+ if (mask != 0xff) {
+ u8 rdata = 0x00;
+
+ ret = io->read_regs(io, tgt, sub_address, &rdata, 1);
+ if (ret)
+ return ret;
+
+ data = (data & mask) | (rdata & (mask ^ 0xff));
+ }
+
+ return io->write_reg(io, tgt, sub_address, data);
+}
+
+int cxd2880_io_write_multi_regs(struct cxd2880_io *io,
+ enum cxd2880_io_tgt tgt,
+ const struct cxd2880_reg_value reg_value[],
+ u8 size)
+{
+ int ret;
+ int i;
+
+ if (!io)
+ return -EINVAL;
+
+ for (i = 0; i < size ; i++) {
+ ret = io->write_reg(io, tgt, reg_value[i].addr,
+ reg_value[i].value);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
new file mode 100644
index 000000000000..ba550278881d
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_io.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * register I/O interface definitions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_IO_H
+#define CXD2880_IO_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_io_tgt {
+ CXD2880_IO_TGT_SYS,
+ CXD2880_IO_TGT_DMD
+};
+
+struct cxd2880_reg_value {
+ u8 addr;
+ u8 value;
+};
+
+struct cxd2880_io {
+ int (*read_regs)(struct cxd2880_io *io,
+ enum cxd2880_io_tgt tgt, u8 sub_address,
+ u8 *data, u32 size);
+ int (*write_regs)(struct cxd2880_io *io,
+ enum cxd2880_io_tgt tgt, u8 sub_address,
+ const u8 *data, u32 size);
+ int (*write_reg)(struct cxd2880_io *io,
+ enum cxd2880_io_tgt tgt, u8 sub_address,
+ u8 data);
+ void *if_object;
+ u8 i2c_address_sys;
+ u8 i2c_address_demod;
+ u8 slave_select;
+ void *user;
+};
+
+int cxd2880_io_common_write_one_reg(struct cxd2880_io *io,
+ enum cxd2880_io_tgt tgt,
+ u8 sub_address, u8 data);
+
+int cxd2880_io_set_reg_bits(struct cxd2880_io *io,
+ enum cxd2880_io_tgt tgt,
+ u8 sub_address, u8 data, u8 mask);
+
+int cxd2880_io_write_multi_regs(struct cxd2880_io *io,
+ enum cxd2880_io_tgt tgt,
+ const struct cxd2880_reg_value reg_value[],
+ u8 size);
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
new file mode 100644
index 000000000000..2be207461847
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_spi.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI access definitions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_SPI_H
+#define CXD2880_SPI_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_spi_mode {
+ CXD2880_SPI_MODE_0,
+ CXD2880_SPI_MODE_1,
+ CXD2880_SPI_MODE_2,
+ CXD2880_SPI_MODE_3
+};
+
+struct cxd2880_spi {
+ int (*read)(struct cxd2880_spi *spi, u8 *data,
+ u32 size);
+ int (*write)(struct cxd2880_spi *spi, const u8 *data,
+ u32 size);
+ int (*write_read)(struct cxd2880_spi *spi,
+ const u8 *tx_data, u32 tx_size,
+ u8 *rx_data, u32 rx_size);
+ u32 flags;
+ void *user;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
new file mode 100644
index 000000000000..b8cbaa8d7aff
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cxd2880_spi_device.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI access functions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#include <linux/spi/spi.h>
+
+#include "cxd2880_spi_device.h"
+
+static int cxd2880_spi_device_write(struct cxd2880_spi *spi,
+ const u8 *data, u32 size)
+{
+ struct cxd2880_spi_device *spi_device = NULL;
+ struct spi_message msg;
+ struct spi_transfer tx;
+ int result = 0;
+
+ if (!spi || !spi->user || !data || size == 0)
+ return -EINVAL;
+
+ spi_device = spi->user;
+
+ memset(&tx, 0, sizeof(tx));
+ tx.tx_buf = data;
+ tx.len = size;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&tx, &msg);
+ result = spi_sync(spi_device->spi, &msg);
+
+ if (result < 0)
+ return -EIO;
+
+ return 0;
+}
+
+static int cxd2880_spi_device_write_read(struct cxd2880_spi *spi,
+ const u8 *tx_data,
+ u32 tx_size,
+ u8 *rx_data,
+ u32 rx_size)
+{
+ struct cxd2880_spi_device *spi_device = NULL;
+ int result = 0;
+
+ if (!spi || !spi->user || !tx_data ||
+ !tx_size || !rx_data || !rx_size)
+ return -EINVAL;
+
+ spi_device = spi->user;
+
+ result = spi_write_then_read(spi_device->spi, tx_data,
+ tx_size, rx_data, rx_size);
+ if (result < 0)
+ return -EIO;
+
+ return 0;
+}
+
+int
+cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device,
+ enum cxd2880_spi_mode mode,
+ u32 speed_hz)
+{
+ int result = 0;
+ struct spi_device *spi = spi_device->spi;
+
+ switch (mode) {
+ case CXD2880_SPI_MODE_0:
+ spi->mode = SPI_MODE_0;
+ break;
+ case CXD2880_SPI_MODE_1:
+ spi->mode = SPI_MODE_1;
+ break;
+ case CXD2880_SPI_MODE_2:
+ spi->mode = SPI_MODE_2;
+ break;
+ case CXD2880_SPI_MODE_3:
+ spi->mode = SPI_MODE_3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spi->max_speed_hz = speed_hz;
+ spi->bits_per_word = 8;
+ result = spi_setup(spi);
+ if (result != 0) {
+ pr_err("spi_setup failed %d\n", result);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi,
+ struct cxd2880_spi_device *spi_device)
+{
+ if (!spi || !spi_device)
+ return -EINVAL;
+
+ spi->read = NULL;
+ spi->write = cxd2880_spi_device_write;
+ spi->write_read = cxd2880_spi_device_write_read;
+ spi->flags = 0;
+ spi->user = spi_device;
+
+ return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
new file mode 100644
index 000000000000..05e3a03de3a3
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_spi_device.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI access interface
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_SPI_DEVICE_H
+#define CXD2880_SPI_DEVICE_H
+
+#include "cxd2880_spi.h"
+
+struct cxd2880_spi_device {
+ struct spi_device *spi;
+};
+
+int cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device,
+ enum cxd2880_spi_mode mode,
+ u32 speedHz);
+
+int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi,
+ struct cxd2880_spi_device *spi_device);
+
+#endif /* CXD2880_SPI_DEVICE_H */
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
new file mode 100644
index 000000000000..4cf2d7cfd3f5
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
@@ -0,0 +1,3519 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cxd2880_tnrdmd.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common control functions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#include <media/dvb_frontend.h>
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_tnrdmd_dvbt2.h"
+
+static const struct cxd2880_reg_value p_init1_seq[] = {
+ {0x11, 0x16}, {0x00, 0x10},
+};
+
+static const struct cxd2880_reg_value rf_init1_seq1[] = {
+ {0x4f, 0x18}, {0x61, 0x00}, {0x71, 0x00}, {0x9d, 0x01},
+ {0x7d, 0x02}, {0x8f, 0x01}, {0x8b, 0xc6}, {0x9a, 0x03},
+ {0x1c, 0x00},
+};
+
+static const struct cxd2880_reg_value rf_init1_seq2[] = {
+ {0xb9, 0x07}, {0x33, 0x01}, {0xc1, 0x01}, {0xc4, 0x1e},
+};
+
+static const struct cxd2880_reg_value rf_init1_seq3[] = {
+ {0x00, 0x10}, {0x51, 0x01}, {0xc5, 0x07}, {0x00, 0x11},
+ {0x70, 0xe9}, {0x76, 0x0a}, {0x78, 0x32}, {0x7a, 0x46},
+ {0x7c, 0x86}, {0x7e, 0xa4}, {0x00, 0x10}, {0xe1, 0x01},
+};
+
+static const struct cxd2880_reg_value rf_init1_seq4[] = {
+ {0x15, 0x00}, {0x00, 0x16}
+};
+
+static const struct cxd2880_reg_value rf_init1_seq5[] = {
+ {0x00, 0x00}, {0x25, 0x00}
+};
+
+static const struct cxd2880_reg_value rf_init1_seq6[] = {
+ {0x02, 0x00}, {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe1},
+ {0x8f, 0x16}, {0x67, 0x60}, {0x6a, 0x0f}, {0x6c, 0x17}
+};
+
+static const struct cxd2880_reg_value rf_init1_seq7[] = {
+ {0x00, 0xe2}, {0x41, 0xa0}, {0x4b, 0x68}, {0x00, 0x00},
+ {0x21, 0x00}, {0x10, 0x01},
+};
+
+static const struct cxd2880_reg_value rf_init1_seq8[] = {
+ {0x00, 0x10}, {0x25, 0x01},
+};
+
+static const struct cxd2880_reg_value rf_init1_seq9[] = {
+ {0x00, 0x10}, {0x14, 0x01}, {0x00, 0x00}, {0x26, 0x00},
+};
+
+static const struct cxd2880_reg_value rf_init2_seq1[] = {
+ {0x00, 0x14}, {0x1b, 0x01},
+};
+
+static const struct cxd2880_reg_value rf_init2_seq2[] = {
+ {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe1}, {0xd3, 0x00},
+ {0x00, 0x00}, {0x21, 0x00},
+};
+
+static const struct cxd2880_reg_value x_tune1_seq1[] = {
+ {0x00, 0x00}, {0x10, 0x01},
+};
+
+static const struct cxd2880_reg_value x_tune1_seq2[] = {
+ {0x62, 0x00}, {0x00, 0x15},
+};
+
+static const struct cxd2880_reg_value x_tune2_seq1[] = {
+ {0x00, 0x1a}, {0x29, 0x01},
+};
+
+static const struct cxd2880_reg_value x_tune2_seq2[] = {
+ {0x62, 0x01}, {0x00, 0x11}, {0x2d, 0x00}, {0x2f, 0x00},
+};
+
+static const struct cxd2880_reg_value x_tune2_seq3[] = {
+ {0x00, 0x00}, {0x10, 0x00}, {0x21, 0x01},
+};
+
+static const struct cxd2880_reg_value x_tune2_seq4[] = {
+ {0x00, 0xe1}, {0x8a, 0x87},
+};
+
+static const struct cxd2880_reg_value x_tune2_seq5[] = {
+ {0x00, 0x00}, {0x21, 0x00},
+};
+
+static const struct cxd2880_reg_value x_tune3_seq[] = {
+ {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe2}, {0x41, 0xa0},
+ {0x00, 0x00}, {0x21, 0x00}, {0xfe, 0x01},
+};
+
+static const struct cxd2880_reg_value x_tune4_seq[] = {
+ {0x00, 0x00}, {0xfe, 0x01},
+};
+
+static const struct cxd2880_reg_value x_sleep1_seq[] = {
+ {0x00, 0x00}, {0x57, 0x03},
+};
+
+static const struct cxd2880_reg_value x_sleep2_seq1[] = {
+ {0x00, 0x2d}, {0xb1, 0x01},
+};
+
+static const struct cxd2880_reg_value x_sleep2_seq2[] = {
+ {0x00, 0x10}, {0xf4, 0x00}, {0xf3, 0x00}, {0xf2, 0x00},
+ {0xf1, 0x00}, {0xf0, 0x00}, {0xef, 0x00},
+};
+
+static const struct cxd2880_reg_value x_sleep3_seq[] = {
+ {0x00, 0x00}, {0xfd, 0x00},
+};
+
+static const struct cxd2880_reg_value x_sleep4_seq[] = {
+ {0x00, 0x00}, {0x21, 0x01}, {0x00, 0xe2}, {0x41, 0x00},
+ {0x00, 0x00}, {0x21, 0x00},
+};
+
+static const struct cxd2880_reg_value spll_reset_seq1[] = {
+ {0x00, 0x10}, {0x29, 0x01}, {0x28, 0x01}, {0x27, 0x01},
+ {0x26, 0x01},
+};
+
+static const struct cxd2880_reg_value spll_reset_seq2[] = {
+ {0x00, 0x00}, {0x10, 0x00},
+};
+
+static const struct cxd2880_reg_value spll_reset_seq3[] = {
+ {0x00, 0x00}, {0x27, 0x00}, {0x22, 0x01},
+};
+
+static const struct cxd2880_reg_value spll_reset_seq4[] = {
+ {0x00, 0x00}, {0x27, 0x01},
+};
+
+static const struct cxd2880_reg_value spll_reset_seq5[] = {
+ {0x00, 0x00}, {0x10, 0x01},
+};
+
+static const struct cxd2880_reg_value t_power_x_seq1[] = {
+ {0x00, 0x10}, {0x29, 0x01}, {0x28, 0x01}, {0x27, 0x01},
+};
+
+static const struct cxd2880_reg_value t_power_x_seq2[] = {
+ {0x00, 0x00}, {0x10, 0x00},
+};
+
+static const struct cxd2880_reg_value t_power_x_seq3[] = {
+ {0x00, 0x00}, {0x27, 0x00}, {0x25, 0x01},
+};
+
+static const struct cxd2880_reg_value t_power_x_seq4[] = {
+ {0x00, 0x00}, {0x2a, 0x00},
+};
+
+static const struct cxd2880_reg_value t_power_x_seq5[] = {
+ {0x00, 0x00}, {0x25, 0x00},
+};
+
+static const struct cxd2880_reg_value t_power_x_seq6[] = {
+ {0x00, 0x00}, {0x27, 0x01},
+};
+
+static const struct cxd2880_reg_value t_power_x_seq7[] = {
+ {0x00, 0x00}, {0x10, 0x01},
+};
+
+static const struct cxd2880_reg_value set_ts_pin_seq[] = {
+ {0x50, 0x3f}, {0x52, 0x1f},
+
+};
+
+static const struct cxd2880_reg_value set_ts_output_seq1[] = {
+ {0x00, 0x00}, {0x52, 0x00},
+};
+
+static const struct cxd2880_reg_value set_ts_output_seq2[] = {
+ {0x00, 0x00}, {0xc3, 0x00},
+
+};
+
+static const struct cxd2880_reg_value set_ts_output_seq3[] = {
+ {0x00, 0x00}, {0xc3, 0x01},
+
+};
+
+static const struct cxd2880_reg_value set_ts_output_seq4[] = {
+ {0x00, 0x00}, {0x52, 0x1f},
+
+};
+
+static int p_init1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ u8 data = 0;
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE ||
+ tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ switch (tnr_dmd->create_param.ts_output_if) {
+ case CXD2880_TNRDMD_TSOUT_IF_TS:
+ data = 0x00;
+ break;
+ case CXD2880_TNRDMD_TSOUT_IF_SPI:
+ data = 0x01;
+ break;
+ case CXD2880_TNRDMD_TSOUT_IF_SDIO:
+ data = 0x02;
+ break;
+ default:
+ return -EINVAL;
+ }
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x10, data);
+ if (ret)
+ return ret;
+ }
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ p_init1_seq,
+ ARRAY_SIZE(p_init1_seq));
+ if (ret)
+ return ret;
+
+ switch (tnr_dmd->chip_id) {
+ case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X:
+ data = 0x1a;
+ break;
+ case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11:
+ data = 0x16;
+ break;
+ default:
+ return -ENOTTY;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x10, data);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->create_param.en_internal_ldo)
+ data = 0x01;
+ else
+ data = 0x00;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x11, data);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x13, data);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x12, data);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x10);
+ if (ret)
+ return ret;
+
+ switch (tnr_dmd->chip_id) {
+ case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X:
+ data = 0x01;
+ break;
+ case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11:
+ data = 0x00;
+ break;
+ default:
+ return -ENOTTY;
+ }
+
+ return tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x69, data);
+}
+
+static int p_init2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ u8 data[6] = { 0 };
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+ data[0] = tnr_dmd->create_param.xosc_cap;
+ data[1] = tnr_dmd->create_param.xosc_i;
+ switch (tnr_dmd->create_param.xtal_share_type) {
+ case CXD2880_TNRDMD_XTAL_SHARE_NONE:
+ data[2] = 0x01;
+ data[3] = 0x00;
+ break;
+ case CXD2880_TNRDMD_XTAL_SHARE_EXTREF:
+ data[2] = 0x00;
+ data[3] = 0x00;
+ break;
+ case CXD2880_TNRDMD_XTAL_SHARE_MASTER:
+ data[2] = 0x01;
+ data[3] = 0x01;
+ break;
+ case CXD2880_TNRDMD_XTAL_SHARE_SLAVE:
+ data[2] = 0x00;
+ data[3] = 0x01;
+ break;
+ default:
+ return -EINVAL;
+ }
+ data[4] = 0x06;
+ data[5] = 0x00;
+
+ return tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x13, data, 6);
+}
+
+static int p_init3(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ u8 data[2] = { 0 };
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+
+ switch (tnr_dmd->diver_mode) {
+ case CXD2880_TNRDMD_DIVERMODE_SINGLE:
+ data[0] = 0x00;
+ break;
+ case CXD2880_TNRDMD_DIVERMODE_MAIN:
+ data[0] = 0x03;
+ break;
+ case CXD2880_TNRDMD_DIVERMODE_SUB:
+ data[0] = 0x02;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ data[1] = 0x01;
+
+ return tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x1f, data, 2);
+}
+
+static int rf_init1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ u8 data[8] = { 0 };
+ static const u8 rf_init1_cdata1[40] = {
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03,
+ 0x03, 0x04, 0x04, 0x05, 0x05, 0x05, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02,
+ 0x02, 0x03, 0x04, 0x04, 0x04
+ };
+
+ static const u8 rf_init1_cdata2[5] = {0xff, 0x00, 0x00, 0x00, 0x00};
+ static const u8 rf_init1_cdata3[80] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x02, 0x00, 0x63, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00,
+ 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x09,
+ 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0d, 0x00,
+ 0x0d, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f,
+ 0x00, 0x10, 0x00, 0x79, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01,
+ 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
+ 0x04, 0x00, 0x04, 0x00, 0x06, 0x00, 0x05,
+ 0x00, 0x07, 0x00, 0x07, 0x00, 0x08, 0x00,
+ 0x0a, 0x03, 0xe0
+ };
+
+ static const u8 rf_init1_cdata4[8] = {
+ 0x20, 0x20, 0x30, 0x41, 0x50, 0x5f, 0x6f, 0x80
+ };
+
+ static const u8 rf_init1_cdata5[50] = {
+ 0x00, 0x09, 0x00, 0x08, 0x00, 0x07, 0x00,
+ 0x06, 0x00, 0x05, 0x00, 0x03, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0c,
+ 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0f, 0x00,
+ 0x0e, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f,
+ 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f, 0x00,
+ 0x0e
+ };
+
+ u8 addr = 0;
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+ data[0] = 0x01;
+ data[1] = 0x00;
+ data[2] = 0x01;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x21, data, 3);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x10);
+ if (ret)
+ return ret;
+ data[0] = 0x01;
+ data[1] = 0x01;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x17, data, 2);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->create_param.stationary_use) {
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x1a, 0x06);
+ if (ret)
+ return ret;
+ }
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ rf_init1_seq1,
+ ARRAY_SIZE(rf_init1_seq1));
+ if (ret)
+ return ret;
+
+ data[0] = 0x00;
+ if (tnr_dmd->create_param.is_cxd2881gg &&
+ tnr_dmd->create_param.xtal_share_type ==
+ CXD2880_TNRDMD_XTAL_SHARE_SLAVE)
+ data[1] = 0x00;
+ else
+ data[1] = 0x1f;
+ data[2] = 0x0a;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0xb5, data, 3);
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ rf_init1_seq2,
+ ARRAY_SIZE(rf_init1_seq2));
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) {
+ data[0] = 0x34;
+ data[1] = 0x2c;
+ } else {
+ data[0] = 0x2f;
+ data[1] = 0x25;
+ }
+ data[2] = 0x15;
+ data[3] = 0x19;
+ data[4] = 0x1b;
+ data[5] = 0x15;
+ data[6] = 0x19;
+ data[7] = 0x1b;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0xd9, data, 8);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x11);
+ if (ret)
+ return ret;
+ data[0] = 0x6c;
+ data[1] = 0x10;
+ data[2] = 0xa6;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x44, data, 3);
+ if (ret)
+ return ret;
+ data[0] = 0x16;
+ data[1] = 0xa8;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x50, data, 2);
+ if (ret)
+ return ret;
+ data[0] = 0x00;
+ data[1] = 0x22;
+ data[2] = 0x00;
+ data[3] = 0x88;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x62, data, 4);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x74, 0x75);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x7f, rf_init1_cdata1, 40);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x16);
+ if (ret)
+ return ret;
+ data[0] = 0x00;
+ data[1] = 0x71;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x10, data, 2);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x23, 0x89);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x27, rf_init1_cdata2, 5);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x3a, rf_init1_cdata3, 80);
+ if (ret)
+ return ret;
+
+ data[0] = 0x03;
+ data[1] = 0xe0;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0xbc, data, 2);
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ rf_init1_seq3,
+ ARRAY_SIZE(rf_init1_seq3));
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->create_param.stationary_use) {
+ data[0] = 0x06;
+ data[1] = 0x07;
+ data[2] = 0x1a;
+ } else {
+ data[0] = 0x00;
+ data[1] = 0x08;
+ data[2] = 0x19;
+ }
+ data[3] = 0x0e;
+ data[4] = 0x09;
+ data[5] = 0x0e;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x12);
+ if (ret)
+ return ret;
+ for (addr = 0x10; addr < 0x9f; addr += 6) {
+ if (tnr_dmd->lna_thrs_tbl_air) {
+ u8 idx = 0;
+
+ idx = (addr - 0x10) / 6;
+ data[0] =
+ tnr_dmd->lna_thrs_tbl_air->thrs[idx].off_on;
+ data[1] =
+ tnr_dmd->lna_thrs_tbl_air->thrs[idx].on_off;
+ }
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ addr, data, 6);
+ if (ret)
+ return ret;
+ }
+
+ data[0] = 0x00;
+ data[1] = 0x08;
+ if (tnr_dmd->create_param.stationary_use)
+ data[2] = 0x1a;
+ else
+ data[2] = 0x19;
+ data[3] = 0x0e;
+ data[4] = 0x09;
+ data[5] = 0x0e;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x13);
+ if (ret)
+ return ret;
+ for (addr = 0x10; addr < 0xcf; addr += 6) {
+ if (tnr_dmd->lna_thrs_tbl_cable) {
+ u8 idx = 0;
+
+ idx = (addr - 0x10) / 6;
+ data[0] =
+ tnr_dmd->lna_thrs_tbl_cable->thrs[idx].off_on;
+ data[1] =
+ tnr_dmd->lna_thrs_tbl_cable->thrs[idx].on_off;
+ }
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ addr, data, 6);
+ if (ret)
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x11);
+ if (ret)
+ return ret;
+ data[0] = 0x08;
+ data[1] = 0x09;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0xbd, data, 2);
+ if (ret)
+ return ret;
+ data[0] = 0x08;
+ data[1] = 0x09;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0xc4, data, 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0xc9, rf_init1_cdata4, 8);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x14);
+ if (ret)
+ return ret;
+ data[0] = 0x15;
+ data[1] = 0x18;
+ data[2] = 0x00;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x10, data, 3);
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ rf_init1_seq4,
+ ARRAY_SIZE(rf_init1_seq4));
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x12, rf_init1_cdata5, 50);
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x0a);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x10, data, 1);
+ if (ret)
+ return ret;
+ if ((data[0] & 0x01) == 0x00)
+ return -EINVAL;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ rf_init1_seq5,
+ ARRAY_SIZE(rf_init1_seq5));
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x0a);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x11, data, 1);
+ if (ret)
+ return ret;
+ if ((data[0] & 0x01) == 0x00)
+ return -EINVAL;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ rf_init1_seq6,
+ ARRAY_SIZE(rf_init1_seq6));
+ if (ret)
+ return ret;
+
+ data[0] = 0x00;
+ data[1] = 0xfe;
+ data[2] = 0xee;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x6e, data, 3);
+ if (ret)
+ return ret;
+ data[0] = 0xa1;
+ data[1] = 0x8b;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x8d, data, 2);
+ if (ret)
+ return ret;
+ data[0] = 0x08;
+ data[1] = 0x09;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x77, data, 2);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->create_param.stationary_use) {
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x80, 0xaa);
+ if (ret)
+ return ret;
+ }
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ rf_init1_seq7,
+ ARRAY_SIZE(rf_init1_seq7));
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ rf_init1_seq8,
+ ARRAY_SIZE(rf_init1_seq8));
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x1a);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x10, data, 1);
+ if (ret)
+ return ret;
+ if ((data[0] & 0x01) == 0x00)
+ return -EINVAL;
+
+ return cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ rf_init1_seq9,
+ ARRAY_SIZE(rf_init1_seq9));
+}
+
+static int rf_init2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ u8 data[5] = { 0 };
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x10);
+ if (ret)
+ return ret;
+ data[0] = 0x40;
+ data[1] = 0x40;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0xea, data, 2);
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ data[0] = 0x00;
+ if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X)
+ data[1] = 0x00;
+ else
+ data[1] = 0x01;
+ data[2] = 0x01;
+ data[3] = 0x03;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x30, data, 4);
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ rf_init2_seq1,
+ ARRAY_SIZE(rf_init2_seq1));
+ if (ret)
+ return ret;
+
+ return cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ rf_init2_seq2,
+ ARRAY_SIZE(rf_init2_seq2));
+}
+
+static int x_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_dtv_sys sys, u32 freq_khz,
+ enum cxd2880_dtv_bandwidth bandwidth,
+ u8 is_cable, int shift_frequency_khz)
+{
+ u8 data[11] = { 0 };
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ x_tune1_seq1,
+ ARRAY_SIZE(x_tune1_seq1));
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x10);
+ if (ret)
+ return ret;
+
+ data[2] = 0x0e;
+ data[4] = 0x03;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0xe7, data, 5);
+ if (ret)
+ return ret;
+
+ data[0] = 0x1f;
+ data[1] = 0x80;
+ data[2] = 0x18;
+ data[3] = 0x00;
+ data[4] = 0x07;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0xe7, data, 5);
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ data[0] = 0x72;
+ data[1] = 0x81;
+ data[3] = 0x1d;
+ data[4] = 0x6f;
+ data[5] = 0x7e;
+ data[7] = 0x1c;
+ switch (sys) {
+ case CXD2880_DTV_SYS_DVBT:
+ data[2] = 0x94;
+ data[6] = 0x91;
+ break;
+ case CXD2880_DTV_SYS_DVBT2:
+ data[2] = 0x96;
+ data[6] = 0x93;
+ break;
+ default:
+ return -EINVAL;
+ }
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x44, data, 8);
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ x_tune1_seq2,
+ ARRAY_SIZE(x_tune1_seq2));
+ if (ret)
+ return ret;
+
+ data[0] = 0x03;
+ data[1] = 0xe2;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x1e, data, 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x10);
+ if (ret)
+ return ret;
+
+ data[0] = is_cable ? 0x01 : 0x00;
+ data[1] = 0x00;
+ data[2] = 0x6b;
+ data[3] = 0x4d;
+
+ switch (bandwidth) {
+ case CXD2880_DTV_BW_1_7_MHZ:
+ data[4] = 0x03;
+ break;
+ case CXD2880_DTV_BW_5_MHZ:
+ case CXD2880_DTV_BW_6_MHZ:
+ data[4] = 0x00;
+ break;
+ case CXD2880_DTV_BW_7_MHZ:
+ data[4] = 0x01;
+ break;
+ case CXD2880_DTV_BW_8_MHZ:
+ data[4] = 0x02;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ data[5] = 0x00;
+
+ freq_khz += shift_frequency_khz;
+
+ data[6] = (freq_khz >> 16) & 0x0f;
+ data[7] = (freq_khz >> 8) & 0xff;
+ data[8] = freq_khz & 0xff;
+ data[9] = 0xff;
+ data[10] = 0xfe;
+
+ return tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x52, data, 11);
+}
+
+static int x_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_dtv_bandwidth bandwidth,
+ enum cxd2880_tnrdmd_clockmode clk_mode,
+ int shift_frequency_khz)
+{
+ u8 data[3] = { 0 };
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x11);
+ if (ret)
+ return ret;
+
+ data[0] = 0x01;
+ data[1] = 0x0e;
+ data[2] = 0x01;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x2d, data, 3);
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ x_tune2_seq1,
+ ARRAY_SIZE(x_tune2_seq1));
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x2c, data, 1);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x10);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x60, data[0]);
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ x_tune2_seq2,
+ ARRAY_SIZE(x_tune2_seq2));
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ x_tune2_seq3,
+ ARRAY_SIZE(x_tune2_seq3));
+ if (ret)
+ return ret;
+
+ if (shift_frequency_khz != 0) {
+ int shift_freq = 0;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0xe1);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x60, data, 2);
+ if (ret)
+ return ret;
+
+ shift_freq = shift_frequency_khz * 1000;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ default:
+ if (shift_freq >= 0)
+ shift_freq = (shift_freq + 183 / 2) / 183;
+ else
+ shift_freq = (shift_freq - 183 / 2) / 183;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ if (shift_freq >= 0)
+ shift_freq = (shift_freq + 178 / 2) / 178;
+ else
+ shift_freq = (shift_freq - 178 / 2) / 178;
+ break;
+ }
+
+ shift_freq +=
+ cxd2880_convert2s_complement((data[0] << 8) | data[1], 16);
+
+ if (shift_freq > 32767)
+ shift_freq = 32767;
+ else if (shift_freq < -32768)
+ shift_freq = -32768;
+
+ data[0] = (shift_freq >> 8) & 0xff;
+ data[1] = shift_freq & 0xff;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x60, data, 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x69, data, 1);
+ if (ret)
+ return ret;
+
+ shift_freq = -shift_frequency_khz;
+
+ if (bandwidth == CXD2880_DTV_BW_1_7_MHZ) {
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ default:
+ if (shift_freq >= 0)
+ shift_freq =
+ (shift_freq * 1000 +
+ 17578 / 2) / 17578;
+ else
+ shift_freq =
+ (shift_freq * 1000 -
+ 17578 / 2) / 17578;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ if (shift_freq >= 0)
+ shift_freq =
+ (shift_freq * 1000 +
+ 17090 / 2) / 17090;
+ else
+ shift_freq =
+ (shift_freq * 1000 -
+ 17090 / 2) / 17090;
+ break;
+ }
+ } else {
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ default:
+ if (shift_freq >= 0)
+ shift_freq =
+ (shift_freq * 1000 +
+ 35156 / 2) / 35156;
+ else
+ shift_freq =
+ (shift_freq * 1000 -
+ 35156 / 2) / 35156;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ if (shift_freq >= 0)
+ shift_freq =
+ (shift_freq * 1000 +
+ 34180 / 2) / 34180;
+ else
+ shift_freq =
+ (shift_freq * 1000 -
+ 34180 / 2) / 34180;
+ break;
+ }
+ }
+
+ shift_freq += cxd2880_convert2s_complement(data[0], 8);
+
+ if (shift_freq > 127)
+ shift_freq = 127;
+ else if (shift_freq < -128)
+ shift_freq = -128;
+
+ data[0] = shift_freq & 0xff;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x69, data[0]);
+ if (ret)
+ return ret;
+ }
+
+ if (tnr_dmd->create_param.stationary_use) {
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ x_tune2_seq4,
+ ARRAY_SIZE(x_tune2_seq4));
+ if (ret)
+ return ret;
+ }
+
+ return cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ x_tune2_seq5,
+ ARRAY_SIZE(x_tune2_seq5));
+}
+
+static int x_tune3(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_dtv_sys sys,
+ u8 en_fef_intmtnt_ctrl)
+{
+ u8 data[6] = { 0 };
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ x_tune3_seq,
+ ARRAY_SIZE(x_tune3_seq));
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x10);
+ if (ret)
+ return ret;
+
+ if (sys == CXD2880_DTV_SYS_DVBT2 && en_fef_intmtnt_ctrl)
+ memset(data, 0x01, sizeof(data));
+ else
+ memset(data, 0x00, sizeof(data));
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0xef, data, 6);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x2d);
+ if (ret)
+ return ret;
+ if (sys == CXD2880_DTV_SYS_DVBT2 && en_fef_intmtnt_ctrl)
+ data[0] = 0x00;
+ else
+ data[0] = 0x01;
+
+ return tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xb1, data[0]);
+}
+
+static int x_tune4(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ u8 data[2] = { 0 };
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+ data[0] = 0x14;
+ data[1] = 0x00;
+ ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+ CXD2880_IO_TGT_SYS,
+ 0x55, data, 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+ data[0] = 0x0b;
+ data[1] = 0xff;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x53, data, 2);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x57, 0x01);
+ if (ret)
+ return ret;
+ data[0] = 0x0b;
+ data[1] = 0xff;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x55, data, 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+ data[0] = 0x14;
+ data[1] = 0x00;
+ ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+ CXD2880_IO_TGT_SYS,
+ 0x53, data, 2);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+ CXD2880_IO_TGT_SYS,
+ 0x57, 0x02);
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ x_tune4_seq,
+ ARRAY_SIZE(x_tune4_seq));
+ if (ret)
+ return ret;
+
+ return cxd2880_io_write_multi_regs(tnr_dmd->diver_sub->io,
+ CXD2880_IO_TGT_DMD,
+ x_tune4_seq,
+ ARRAY_SIZE(x_tune4_seq));
+}
+
+static int x_sleep1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ u8 data[3] = { 0 };
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ x_sleep1_seq,
+ ARRAY_SIZE(x_sleep1_seq));
+ if (ret)
+ return ret;
+
+ data[0] = 0x00;
+ data[1] = 0x00;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x53, data, 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+ data[0] = 0x1f;
+ data[1] = 0xff;
+ data[2] = 0x03;
+ ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+ CXD2880_IO_TGT_SYS,
+ 0x55, data, 3);
+ if (ret)
+ return ret;
+ data[0] = 0x00;
+ data[1] = 0x00;
+ ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+ CXD2880_IO_TGT_SYS,
+ 0x53, data, 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+ data[0] = 0x1f;
+ data[1] = 0xff;
+
+ return tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x55, data, 2);
+}
+
+static int x_sleep2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ u8 data = 0;
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ x_sleep2_seq1,
+ ARRAY_SIZE(x_sleep2_seq1));
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xb2, &data, 1);
+ if (ret)
+ return ret;
+
+ if ((data & 0x01) == 0x00)
+ return -EINVAL;
+
+ return cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ x_sleep2_seq2,
+ ARRAY_SIZE(x_sleep2_seq2));
+}
+
+static int x_sleep3(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ return cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ x_sleep3_seq,
+ ARRAY_SIZE(x_sleep3_seq));
+}
+
+static int x_sleep4(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ return cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ x_sleep4_seq,
+ ARRAY_SIZE(x_sleep4_seq));
+}
+
+static int spll_reset(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_tnrdmd_clockmode clockmode)
+{
+ u8 data[4] = { 0 };
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ spll_reset_seq1,
+ ARRAY_SIZE(spll_reset_seq1));
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ spll_reset_seq2,
+ ARRAY_SIZE(spll_reset_seq2));
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ spll_reset_seq3,
+ ARRAY_SIZE(spll_reset_seq3));
+ if (ret)
+ return ret;
+
+ switch (clockmode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data[0] = 0x00;
+ break;
+
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data[0] = 0x01;
+ break;
+
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data[0] = 0x02;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x30, data[0]);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x22, 0x00);
+ if (ret)
+ return ret;
+
+ usleep_range(2000, 3000);
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x0a);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x10, data, 1);
+ if (ret)
+ return ret;
+ if ((data[0] & 0x01) == 0x00)
+ return -EINVAL;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ spll_reset_seq4,
+ ARRAY_SIZE(spll_reset_seq4));
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ spll_reset_seq5,
+ ARRAY_SIZE(spll_reset_seq5));
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x10);
+ if (ret)
+ return ret;
+
+ memset(data, 0x00, sizeof(data));
+
+ return tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x26, data, 4);
+}
+
+static int t_power_x(struct cxd2880_tnrdmd *tnr_dmd, u8 on)
+{
+ u8 data[3] = { 0 };
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ t_power_x_seq1,
+ ARRAY_SIZE(t_power_x_seq1));
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ t_power_x_seq2,
+ ARRAY_SIZE(t_power_x_seq2));
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ t_power_x_seq3,
+ ARRAY_SIZE(t_power_x_seq3));
+ if (ret)
+ return ret;
+
+ if (on) {
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x2b, 0x01);
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x0a);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x12, data, 1);
+ if (ret)
+ return ret;
+ if ((data[0] & 0x01) == 0)
+ return -EINVAL;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ t_power_x_seq4,
+ ARRAY_SIZE(t_power_x_seq4));
+ if (ret)
+ return ret;
+ } else {
+ data[0] = 0x03;
+ data[1] = 0x00;
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x2a, data, 2);
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x0a);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x13, data, 1);
+ if (ret)
+ return ret;
+ if ((data[0] & 0x01) == 0)
+ return -EINVAL;
+ }
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ t_power_x_seq5,
+ ARRAY_SIZE(t_power_x_seq5));
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x0a);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x11, data, 1);
+ if (ret)
+ return ret;
+ if ((data[0] & 0x01) == 0)
+ return -EINVAL;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ t_power_x_seq6,
+ ARRAY_SIZE(t_power_x_seq6));
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ t_power_x_seq7,
+ ARRAY_SIZE(t_power_x_seq7));
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x10);
+ if (ret)
+ return ret;
+
+ memset(data, 0x00, sizeof(data));
+
+ return tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x27, data, 3);
+}
+
+struct cxd2880_tnrdmd_ts_clk_cfg {
+ u8 srl_clk_mode;
+ u8 srl_duty_mode;
+ u8 ts_clk_period;
+};
+
+static int set_ts_clk_mode_and_freq(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_dtv_sys sys)
+{
+ int ret;
+ u8 backwards_compatible = 0;
+ struct cxd2880_tnrdmd_ts_clk_cfg ts_clk_cfg;
+ u8 ts_rate_ctrl_off = 0;
+ u8 ts_in_off = 0;
+ u8 ts_clk_manaul_on = 0;
+ u8 data = 0;
+
+ static const struct cxd2880_tnrdmd_ts_clk_cfg srl_ts_clk_stgs[2][2] = {
+ {
+ {3, 1, 8,},
+ {0, 2, 16,}
+ }, {
+ {1, 1, 8,},
+ {2, 2, 16,}
+ }
+ };
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->is_ts_backwards_compatible_mode) {
+ backwards_compatible = 1;
+ ts_rate_ctrl_off = 1;
+ ts_in_off = 1;
+ } else {
+ backwards_compatible = 0;
+ ts_rate_ctrl_off = 0;
+ ts_in_off = 0;
+ }
+
+ if (tnr_dmd->ts_byte_clk_manual_setting) {
+ ts_clk_manaul_on = 1;
+ ts_rate_ctrl_off = 0;
+ }
+
+ ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xd3, ts_rate_ctrl_off, 0x01);
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xde, ts_in_off, 0x01);
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xda, ts_clk_manaul_on, 0x01);
+ if (ret)
+ return ret;
+
+ ts_clk_cfg = srl_ts_clk_stgs[tnr_dmd->srl_ts_clk_mod_cnts]
+ [tnr_dmd->srl_ts_clk_frq];
+
+ if (tnr_dmd->ts_byte_clk_manual_setting)
+ ts_clk_cfg.ts_clk_period = tnr_dmd->ts_byte_clk_manual_setting;
+
+ ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xc4, ts_clk_cfg.srl_clk_mode, 0x03);
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xd1, ts_clk_cfg.srl_duty_mode, 0x03);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD, 0xd9,
+ ts_clk_cfg.ts_clk_period);
+ if (ret)
+ return ret;
+
+ data = backwards_compatible ? 0x00 : 0x01;
+
+ if (sys == CXD2880_DTV_SYS_DVBT) {
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x10);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_io_set_reg_bits(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x66, data, 0x01);
+ }
+
+ return ret;
+}
+
+static int pid_ftr_setting(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_tnrdmd_pid_ftr_cfg
+ *pid_ftr_cfg)
+{
+ int i;
+ int ret;
+ u8 data[65];
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+
+ if (!pid_ftr_cfg)
+ return tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x50, 0x02);
+
+ data[0] = pid_ftr_cfg->is_negative ? 0x01 : 0x00;
+
+ for (i = 0; i < 32; i++) {
+ if (pid_ftr_cfg->pid_cfg[i].is_en) {
+ data[1 + (i * 2)] = (pid_ftr_cfg->pid_cfg[i].pid >> 8) | 0x20;
+ data[2 + (i * 2)] = pid_ftr_cfg->pid_cfg[i].pid & 0xff;
+ } else {
+ data[1 + (i * 2)] = 0x00;
+ data[2 + (i * 2)] = 0x00;
+ }
+ }
+
+ return tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x50, data, 65);
+}
+
+static int load_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ int ret;
+ u8 i;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) {
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ tnr_dmd->cfg_mem[i].tgt,
+ 0x00, tnr_dmd->cfg_mem[i].bank);
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+ tnr_dmd->cfg_mem[i].tgt,
+ tnr_dmd->cfg_mem[i].address,
+ tnr_dmd->cfg_mem[i].value,
+ tnr_dmd->cfg_mem[i].bit_mask);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int set_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_io_tgt tgt,
+ u8 bank, u8 address, u8 value, u8 bit_mask)
+{
+ u8 i;
+ u8 value_stored = 0;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) {
+ if (value_stored == 0 &&
+ tnr_dmd->cfg_mem[i].tgt == tgt &&
+ tnr_dmd->cfg_mem[i].bank == bank &&
+ tnr_dmd->cfg_mem[i].address == address) {
+ tnr_dmd->cfg_mem[i].value &= ~bit_mask;
+ tnr_dmd->cfg_mem[i].value |= (value & bit_mask);
+
+ tnr_dmd->cfg_mem[i].bit_mask |= bit_mask;
+
+ value_stored = 1;
+ }
+ }
+
+ if (value_stored)
+ return 0;
+
+ if (tnr_dmd->cfg_mem_last_entry < CXD2880_TNRDMD_MAX_CFG_MEM_COUNT) {
+ tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].tgt = tgt;
+ tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bank = bank;
+ tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].address = address;
+ tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].value = (value & bit_mask);
+ tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bit_mask = bit_mask;
+ tnr_dmd->cfg_mem_last_entry++;
+ } else {
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_io *io,
+ struct cxd2880_tnrdmd_create_param
+ *create_param)
+{
+ if (!tnr_dmd || !io || !create_param)
+ return -EINVAL;
+
+ memset(tnr_dmd, 0, sizeof(struct cxd2880_tnrdmd));
+
+ tnr_dmd->io = io;
+ tnr_dmd->create_param = *create_param;
+
+ tnr_dmd->diver_mode = CXD2880_TNRDMD_DIVERMODE_SINGLE;
+ tnr_dmd->diver_sub = NULL;
+
+ tnr_dmd->srl_ts_clk_mod_cnts = 1;
+ tnr_dmd->en_fef_intmtnt_base = 1;
+ tnr_dmd->en_fef_intmtnt_lite = 1;
+ tnr_dmd->rf_lvl_cmpstn = NULL;
+ tnr_dmd->lna_thrs_tbl_air = NULL;
+ tnr_dmd->lna_thrs_tbl_cable = NULL;
+ atomic_set(&tnr_dmd->cancel, 0);
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd
+ *tnr_dmd_main,
+ struct cxd2880_io *io_main,
+ struct cxd2880_tnrdmd *tnr_dmd_sub,
+ struct cxd2880_io *io_sub,
+ struct
+ cxd2880_tnrdmd_diver_create_param
+ *create_param)
+{
+ struct cxd2880_tnrdmd_create_param *main_param, *sub_param;
+
+ if (!tnr_dmd_main || !io_main || !tnr_dmd_sub || !io_sub ||
+ !create_param)
+ return -EINVAL;
+
+ memset(tnr_dmd_main, 0, sizeof(struct cxd2880_tnrdmd));
+ memset(tnr_dmd_sub, 0, sizeof(struct cxd2880_tnrdmd));
+
+ main_param = &tnr_dmd_main->create_param;
+ sub_param = &tnr_dmd_sub->create_param;
+
+ tnr_dmd_main->io = io_main;
+ tnr_dmd_main->diver_mode = CXD2880_TNRDMD_DIVERMODE_MAIN;
+ tnr_dmd_main->diver_sub = tnr_dmd_sub;
+ tnr_dmd_main->create_param.en_internal_ldo =
+ create_param->en_internal_ldo;
+
+ main_param->ts_output_if = create_param->ts_output_if;
+ main_param->xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_MASTER;
+ main_param->xosc_cap = create_param->xosc_cap_main;
+ main_param->xosc_i = create_param->xosc_i_main;
+ main_param->is_cxd2881gg = create_param->is_cxd2881gg;
+ main_param->stationary_use = create_param->stationary_use;
+
+ tnr_dmd_sub->io = io_sub;
+ tnr_dmd_sub->diver_mode = CXD2880_TNRDMD_DIVERMODE_SUB;
+ tnr_dmd_sub->diver_sub = NULL;
+
+ sub_param->en_internal_ldo = create_param->en_internal_ldo;
+ sub_param->ts_output_if = create_param->ts_output_if;
+ sub_param->xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_SLAVE;
+ sub_param->xosc_cap = 0;
+ sub_param->xosc_i = create_param->xosc_i_sub;
+ sub_param->is_cxd2881gg = create_param->is_cxd2881gg;
+ sub_param->stationary_use = create_param->stationary_use;
+
+ tnr_dmd_main->srl_ts_clk_mod_cnts = 1;
+ tnr_dmd_main->en_fef_intmtnt_base = 1;
+ tnr_dmd_main->en_fef_intmtnt_lite = 1;
+ tnr_dmd_main->rf_lvl_cmpstn = NULL;
+ tnr_dmd_main->lna_thrs_tbl_air = NULL;
+ tnr_dmd_main->lna_thrs_tbl_cable = NULL;
+
+ tnr_dmd_sub->srl_ts_clk_mod_cnts = 1;
+ tnr_dmd_sub->en_fef_intmtnt_base = 1;
+ tnr_dmd_sub->en_fef_intmtnt_lite = 1;
+ tnr_dmd_sub->rf_lvl_cmpstn = NULL;
+ tnr_dmd_sub->lna_thrs_tbl_air = NULL;
+ tnr_dmd_sub->lna_thrs_tbl_cable = NULL;
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ int ret;
+
+ if (!tnr_dmd || tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ tnr_dmd->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
+ tnr_dmd->state = CXD2880_TNRDMD_STATE_UNKNOWN;
+ tnr_dmd->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN;
+ tnr_dmd->frequency_khz = 0;
+ tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN;
+ tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+ tnr_dmd->scan_mode = 0;
+ atomic_set(&tnr_dmd->cancel, 0);
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ tnr_dmd->diver_sub->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
+ tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_UNKNOWN;
+ tnr_dmd->diver_sub->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN;
+ tnr_dmd->diver_sub->frequency_khz = 0;
+ tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN;
+ tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+ tnr_dmd->diver_sub->scan_mode = 0;
+ atomic_set(&tnr_dmd->diver_sub->cancel, 0);
+ }
+
+ ret = cxd2880_tnrdmd_chip_id(tnr_dmd, &tnr_dmd->chip_id);
+ if (ret)
+ return ret;
+
+ if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->chip_id))
+ return -ENOTTY;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret =
+ cxd2880_tnrdmd_chip_id(tnr_dmd->diver_sub,
+ &tnr_dmd->diver_sub->chip_id);
+ if (ret)
+ return ret;
+
+ if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->diver_sub->chip_id))
+ return -ENOTTY;
+ }
+
+ ret = p_init1(tnr_dmd);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = p_init1(tnr_dmd->diver_sub);
+ if (ret)
+ return ret;
+ }
+
+ usleep_range(1000, 2000);
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = p_init2(tnr_dmd->diver_sub);
+ if (ret)
+ return ret;
+ }
+
+ ret = p_init2(tnr_dmd);
+ if (ret)
+ return ret;
+
+ usleep_range(5000, 6000);
+
+ ret = p_init3(tnr_dmd);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = p_init3(tnr_dmd->diver_sub);
+ if (ret)
+ return ret;
+ }
+
+ ret = rf_init1(tnr_dmd);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+ ret = rf_init1(tnr_dmd->diver_sub);
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ u8 cpu_task_completed;
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ ret = cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
+ &cpu_task_completed);
+ if (ret)
+ return ret;
+
+ if (!cpu_task_completed)
+ return -EINVAL;
+
+ ret = rf_init2(tnr_dmd);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = rf_init2(tnr_dmd->diver_sub);
+ if (ret)
+ return ret;
+ }
+
+ ret = load_cfg_mem(tnr_dmd);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = load_cfg_mem(tnr_dmd->diver_sub);
+ if (ret)
+ return ret;
+ }
+
+ tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+ tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP;
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ u8 *task_completed)
+{
+ u16 cpu_status = 0;
+ int ret;
+
+ if (!tnr_dmd || !task_completed)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ ret = cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd, &cpu_status);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+ if (cpu_status == 0)
+ *task_completed = 1;
+ else
+ *task_completed = 0;
+
+ return ret;
+ }
+ if (cpu_status != 0) {
+ *task_completed = 0;
+ return ret;
+ }
+
+ ret = cxd2880_tnrdmd_mon_internal_cpu_status_sub(tnr_dmd, &cpu_status);
+ if (ret)
+ return ret;
+
+ if (cpu_status == 0)
+ *task_completed = 1;
+ else
+ *task_completed = 0;
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_dtv_sys sys,
+ u32 frequency_khz,
+ enum cxd2880_dtv_bandwidth
+ bandwidth, u8 one_seg_opt,
+ u8 one_seg_opt_shft_dir)
+{
+ u8 data;
+ enum cxd2880_tnrdmd_clockmode new_clk_mode =
+ CXD2880_TNRDMD_CLOCKMODE_A;
+ int shift_frequency_khz;
+ u8 cpu_task_completed;
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (frequency_khz < 4000)
+ return -EINVAL;
+
+ ret = cxd2880_tnrdmd_sleep(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00,
+ 0x00);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x2b,
+ &data,
+ 1);
+ if (ret)
+ return ret;
+
+ switch (sys) {
+ case CXD2880_DTV_SYS_DVBT:
+ if (data == 0x00) {
+ ret = t_power_x(tnr_dmd, 1);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode ==
+ CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = t_power_x(tnr_dmd->diver_sub, 1);
+ if (ret)
+ return ret;
+ }
+ }
+ break;
+
+ case CXD2880_DTV_SYS_DVBT2:
+ if (data == 0x01) {
+ ret = t_power_x(tnr_dmd, 0);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode ==
+ CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = t_power_x(tnr_dmd->diver_sub, 0);
+ if (ret)
+ return ret;
+ }
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ret = spll_reset(tnr_dmd, new_clk_mode);
+ if (ret)
+ return ret;
+
+ tnr_dmd->clk_mode = new_clk_mode;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = spll_reset(tnr_dmd->diver_sub, new_clk_mode);
+ if (ret)
+ return ret;
+
+ tnr_dmd->diver_sub->clk_mode = new_clk_mode;
+ }
+
+ ret = load_cfg_mem(tnr_dmd);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = load_cfg_mem(tnr_dmd->diver_sub);
+ if (ret)
+ return ret;
+ }
+
+ if (one_seg_opt) {
+ if (tnr_dmd->diver_mode ==
+ CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ shift_frequency_khz = 350;
+ } else {
+ if (one_seg_opt_shft_dir)
+ shift_frequency_khz = 350;
+ else
+ shift_frequency_khz = -350;
+
+ if (tnr_dmd->create_param.xtal_share_type ==
+ CXD2880_TNRDMD_XTAL_SHARE_SLAVE)
+ shift_frequency_khz *= -1;
+ }
+ } else {
+ if (tnr_dmd->diver_mode ==
+ CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ shift_frequency_khz = 150;
+ } else {
+ switch (tnr_dmd->create_param.xtal_share_type) {
+ case CXD2880_TNRDMD_XTAL_SHARE_NONE:
+ case CXD2880_TNRDMD_XTAL_SHARE_EXTREF:
+ default:
+ shift_frequency_khz = 0;
+ break;
+ case CXD2880_TNRDMD_XTAL_SHARE_MASTER:
+ shift_frequency_khz = 150;
+ break;
+ case CXD2880_TNRDMD_XTAL_SHARE_SLAVE:
+ shift_frequency_khz = -150;
+ break;
+ }
+ }
+ }
+
+ ret =
+ x_tune1(tnr_dmd, sys, frequency_khz, bandwidth,
+ tnr_dmd->is_cable_input, shift_frequency_khz);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret =
+ x_tune1(tnr_dmd->diver_sub, sys, frequency_khz,
+ bandwidth, tnr_dmd->is_cable_input,
+ -shift_frequency_khz);
+ if (ret)
+ return ret;
+ }
+
+ usleep_range(10000, 11000);
+
+ ret =
+ cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
+ &cpu_task_completed);
+ if (ret)
+ return ret;
+
+ if (!cpu_task_completed)
+ return -EINVAL;
+
+ ret =
+ x_tune2(tnr_dmd, bandwidth, tnr_dmd->clk_mode,
+ shift_frequency_khz);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret =
+ x_tune2(tnr_dmd->diver_sub, bandwidth,
+ tnr_dmd->diver_sub->clk_mode,
+ -shift_frequency_khz);
+ if (ret)
+ return ret;
+ }
+
+ if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS) {
+ ret = set_ts_clk_mode_and_freq(tnr_dmd, sys);
+ } else {
+ struct cxd2880_tnrdmd_pid_ftr_cfg *pid_ftr_cfg;
+
+ if (tnr_dmd->pid_ftr_cfg_en)
+ pid_ftr_cfg = &tnr_dmd->pid_ftr_cfg;
+ else
+ pid_ftr_cfg = NULL;
+
+ ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg);
+ }
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dtv_sys sys,
+ u8 en_fef_intmtnt_ctrl)
+{
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret = x_tune3(tnr_dmd, sys, en_fef_intmtnt_ctrl);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = x_tune3(tnr_dmd->diver_sub, sys, en_fef_intmtnt_ctrl);
+ if (ret)
+ return ret;
+ ret = x_tune4(tnr_dmd);
+ if (ret)
+ return ret;
+ }
+
+ return cxd2880_tnrdmd_set_ts_output(tnr_dmd, 1);
+}
+
+int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state == CXD2880_TNRDMD_STATE_SLEEP)
+ return 0;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 0);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = x_sleep1(tnr_dmd);
+ if (ret)
+ return ret;
+ }
+
+ ret = x_sleep2(tnr_dmd);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = x_sleep2(tnr_dmd->diver_sub);
+ if (ret)
+ return ret;
+ }
+
+ switch (tnr_dmd->sys) {
+ case CXD2880_DTV_SYS_DVBT:
+ ret = cxd2880_tnrdmd_dvbt_sleep_setting(tnr_dmd);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_DTV_SYS_DVBT2:
+ ret = cxd2880_tnrdmd_dvbt2_sleep_setting(tnr_dmd);
+ if (ret)
+ return ret;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ret = x_sleep3(tnr_dmd);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = x_sleep3(tnr_dmd->diver_sub);
+ if (ret)
+ return ret;
+ }
+
+ ret = x_sleep4(tnr_dmd);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = x_sleep4(tnr_dmd->diver_sub);
+ if (ret)
+ return ret;
+ }
+
+ tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP;
+ tnr_dmd->frequency_khz = 0;
+ tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN;
+ tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP;
+ tnr_dmd->diver_sub->frequency_khz = 0;
+ tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN;
+ tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+ }
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_tnrdmd_cfg_id id,
+ int value)
+{
+ int ret = 0;
+ u8 data[2] = { 0 };
+ u8 need_sub_setting = 0;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ switch (id) {
+ case CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0xc4,
+ value ? 0x00 : 0x10,
+ 0x10);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0xc5,
+ value ? 0x00 : 0x02,
+ 0x02);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0xc5,
+ value ? 0x00 : 0x04,
+ 0x04);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0xcb,
+ value ? 0x00 : 0x01,
+ 0x01);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0xc5,
+ value ? 0x01 : 0x00,
+ 0x01);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TSCLK_CONT:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ tnr_dmd->srl_ts_clk_mod_cnts = value ? 0x01 : 0x00;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TSCLK_MASK:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ if (value < 0 || value > 0x1f)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0xc6, value,
+ 0x1f);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TSVALID_MASK:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ if (value < 0 || value > 0x1f)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0xc8, value,
+ 0x1f);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TSERR_MASK:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ if (value < 0 || value > 0x1f)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0xc9, value,
+ 0x1f);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TSERR_VALID_DIS:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x91,
+ value ? 0x01 : 0x00,
+ 0x01);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TSPIN_CURRENT:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x51, value,
+ 0x3f);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x50,
+ value ? 0x80 : 0x00,
+ 0x80);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TSPIN_PULLUP:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x50, value,
+ 0x3f);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TSCLK_FREQ:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ if (value < 0 || value > 1)
+ return -EINVAL;
+
+ tnr_dmd->srl_ts_clk_frq =
+ (enum cxd2880_tnrdmd_serial_ts_clk)value;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ if (value < 0 || value > 0xff)
+ return -EINVAL;
+
+ tnr_dmd->ts_byte_clk_manual_setting = value;
+
+ break;
+
+ case CXD2880_TNRDMD_CFG_TS_PACKET_GAP:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ if (value < 0 || value > 7)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0xd6, value,
+ 0x07);
+ if (ret)
+ return ret;
+
+ break;
+
+ case CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE:
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ tnr_dmd->is_ts_backwards_compatible_mode = value ? 1 : 0;
+
+ break;
+
+ case CXD2880_TNRDMD_CFG_PWM_VALUE:
+ if (value < 0 || value > 0x1000)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x22,
+ value ? 0x01 : 0x00,
+ 0x01);
+ if (ret)
+ return ret;
+
+ data[0] = (value >> 8) & 0x1f;
+ data[1] = value & 0xff;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x23,
+ data[0], 0x1f);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x24,
+ data[1], 0xff);
+ if (ret)
+ return ret;
+
+ break;
+
+ case CXD2880_TNRDMD_CFG_INTERRUPT:
+ data[0] = (value >> 8) & 0xff;
+ data[1] = value & 0xff;
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x48, data[0],
+ 0xff);
+ if (ret)
+ return ret;
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x49, data[1],
+ 0xff);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL:
+ data[0] = value & 0x07;
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x4a, data[0],
+ 0x07);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL:
+ data[0] = (value & 0x07) << 3;
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x4a, data[0],
+ 0x38);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE:
+ if (value < CXD2880_TNRDMD_CLOCKMODE_UNKNOWN ||
+ value > CXD2880_TNRDMD_CLOCKMODE_C)
+ return -EINVAL;
+ tnr_dmd->fixed_clk_mode = (enum cxd2880_tnrdmd_clockmode)value;
+ break;
+
+ case CXD2880_TNRDMD_CFG_CABLE_INPUT:
+ tnr_dmd->is_cable_input = value ? 1 : 0;
+ break;
+
+ case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE:
+ tnr_dmd->en_fef_intmtnt_base = value ? 1 : 0;
+ break;
+
+ case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE:
+ tnr_dmd->en_fef_intmtnt_lite = value ? 1 : 0;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS:
+ data[0] = (value >> 8) & 0x07;
+ data[1] = value & 0xff;
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x99, data[0],
+ 0x07);
+ if (ret)
+ return ret;
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x9a, data[1],
+ 0xff);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS:
+ data[0] = (value >> 8) & 0x07;
+ data[1] = value & 0xff;
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x9b, data[0],
+ 0x07);
+ if (ret)
+ return ret;
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x9c, data[1],
+ 0xff);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS:
+ data[0] = (value >> 8) & 0x07;
+ data[1] = value & 0xff;
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x9d, data[0],
+ 0x07);
+ if (ret)
+ return ret;
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x9e, data[1],
+ 0xff);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST:
+ tnr_dmd->blind_tune_dvbt2_first = value ? 1 : 0;
+ break;
+
+ case CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD:
+ if (value < 0 || value > 31)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x10, 0x60,
+ value & 0x1f, 0x1f);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD:
+ if (value < 0 || value > 7)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x10, 0x6f,
+ value & 0x07, 0x07);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_DVBT2_BBER_MES:
+ if (value < 0 || value > 15)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x20, 0x72,
+ value & 0x0f, 0x0f);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_DVBT2_LBER_MES:
+ if (value < 0 || value > 15)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x20, 0x6f,
+ value & 0x0f, 0x0f);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_DVBT_PER_MES:
+ if (value < 0 || value > 15)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x10, 0x5c,
+ value & 0x0f, 0x0f);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_TNRDMD_CFG_DVBT2_PER_MES:
+ if (value < 0 || value > 15)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_DMD,
+ 0x24, 0xdc,
+ value & 0x0f, 0x0f);
+ if (ret)
+ return ret;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (need_sub_setting &&
+ tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+ ret = cxd2880_tnrdmd_set_cfg(tnr_dmd->diver_sub, id, value);
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 id,
+ u8 en,
+ enum cxd2880_tnrdmd_gpio_mode mode,
+ u8 open_drain, u8 invert)
+{
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (id > 2)
+ return -EINVAL;
+
+ if (mode > CXD2880_TNRDMD_GPIO_MODE_EEW)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+ 0x00, 0x40 + id, mode,
+ 0x0f);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+ 0x00, 0x43,
+ open_drain ? (1 << id) : 0,
+ 1 << id);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+ 0x00, 0x44,
+ invert ? (1 << id) : 0,
+ 1 << id);
+ if (ret)
+ return ret;
+
+ return cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x45,
+ en ? 0 : (1 << id),
+ 1 << id);
+}
+
+int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 id,
+ u8 en,
+ enum cxd2880_tnrdmd_gpio_mode
+ mode, u8 open_drain, u8 invert)
+{
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ return cxd2880_tnrdmd_gpio_set_cfg(tnr_dmd->diver_sub, id, en, mode,
+ open_drain, invert);
+}
+
+int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 id, u8 *value)
+{
+ u8 data = 0;
+ int ret;
+
+ if (!tnr_dmd || !value)
+ return -EINVAL;
+
+ if (id > 2)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x0a);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x20, &data, 1);
+ if (ret)
+ return ret;
+
+ *value = (data >> id) & 0x01;
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 id, u8 *value)
+{
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ return cxd2880_tnrdmd_gpio_read(tnr_dmd->diver_sub, id, value);
+}
+
+int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 id, u8 value)
+{
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (id > 2)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ return cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x46,
+ value ? (1 << id) : 0,
+ 1 << id);
+}
+
+int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 id, u8 value)
+{
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ return cxd2880_tnrdmd_gpio_write(tnr_dmd->diver_sub, id, value);
+}
+
+int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd,
+ u16 *value)
+{
+ int ret;
+ u8 data[2] = { 0 };
+
+ if (!tnr_dmd || !value)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x0a);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x15, data, 2);
+ if (ret)
+ return ret;
+
+ *value = (data[0] << 8) | data[1];
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd,
+ u16 value)
+{
+ int ret;
+ u8 data[2] = { 0 };
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+
+ data[0] = (value >> 8) & 0xff;
+ data[1] = value & 0xff;
+
+ return tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x3c, data, 2);
+}
+
+int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 clear_overflow_flag,
+ u8 clear_underflow_flag,
+ u8 clear_buf)
+{
+ int ret;
+ u8 data[2] = { 0 };
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+
+ data[0] = clear_overflow_flag ? 0x02 : 0x00;
+ data[0] |= clear_underflow_flag ? 0x01 : 0x00;
+ data[1] = clear_buf ? 0x01 : 0x00;
+
+ return tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x9f, data, 2);
+}
+
+int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_tnrdmd_chip_id *chip_id)
+{
+ int ret;
+ u8 data = 0;
+
+ if (!tnr_dmd || !chip_id)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0xfd, &data, 1);
+ if (ret)
+ return ret;
+
+ *chip_id = (enum cxd2880_tnrdmd_chip_id)data;
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_io_tgt tgt,
+ u8 bank, u8 address,
+ u8 value, u8 bit_mask)
+{
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io, tgt, 0x00, bank);
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+ tgt, address, value, bit_mask);
+ if (ret)
+ return ret;
+
+ return set_cfg_mem(tnr_dmd, tgt, bank, address, value, bit_mask);
+}
+
+int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_dtv_sys sys,
+ u8 scan_mode_end)
+{
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ tnr_dmd->scan_mode = scan_mode_end;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return cxd2880_tnrdmd_set_scan_mode(tnr_dmd->diver_sub, sys,
+ scan_mode_end);
+ else
+ return 0;
+}
+
+int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_tnrdmd_pid_ftr_cfg
+ *pid_ftr_cfg)
+{
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS)
+ return -ENOTTY;
+
+ if (pid_ftr_cfg) {
+ tnr_dmd->pid_ftr_cfg = *pid_ftr_cfg;
+ tnr_dmd->pid_ftr_cfg_en = 1;
+ } else {
+ tnr_dmd->pid_ftr_cfg_en = 0;
+ }
+
+ if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE)
+ return pid_ftr_setting(tnr_dmd, pid_ftr_cfg);
+ else
+ return 0;
+}
+
+int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ int (*rf_lvl_cmpstn)
+ (struct cxd2880_tnrdmd *,
+ int *))
+{
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ tnr_dmd->rf_lvl_cmpstn = rf_lvl_cmpstn;
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ int (*rf_lvl_cmpstn)
+ (struct cxd2880_tnrdmd *,
+ int *))
+{
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ return cxd2880_tnrdmd_set_rf_lvl_cmpstn(tnr_dmd->diver_sub,
+ rf_lvl_cmpstn);
+}
+
+int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_tnrdmd_lna_thrs_tbl_air
+ *tbl_air,
+ struct cxd2880_tnrdmd_lna_thrs_tbl_cable
+ *tbl_cable)
+{
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ tnr_dmd->lna_thrs_tbl_air = tbl_air;
+ tnr_dmd->lna_thrs_tbl_cable = tbl_cable;
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd,
+ struct
+ cxd2880_tnrdmd_lna_thrs_tbl_air
+ *tbl_air,
+ struct cxd2880_tnrdmd_lna_thrs_tbl_cable
+ *tbl_cable)
+{
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ return cxd2880_tnrdmd_set_lna_thrs(tnr_dmd->diver_sub,
+ tbl_air, tbl_cable);
+}
+
+int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 en, u8 value)
+{
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+ return -EINVAL;
+
+ if (tnr_dmd->create_param.ts_output_if != CXD2880_TNRDMD_TSOUT_IF_TS)
+ return -ENOTTY;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+
+ if (en) {
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x50, ((value & 0x1f) | 0x80));
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x52, (value & 0x1f));
+ } else {
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ set_ts_pin_seq,
+ ARRAY_SIZE(set_ts_pin_seq));
+ if (ret)
+ return ret;
+
+ ret = load_cfg_mem(tnr_dmd);
+ }
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 en)
+{
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ switch (tnr_dmd->create_param.ts_output_if) {
+ case CXD2880_TNRDMD_TSOUT_IF_TS:
+ if (en) {
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ set_ts_output_seq1,
+ ARRAY_SIZE(set_ts_output_seq1));
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ set_ts_output_seq2,
+ ARRAY_SIZE(set_ts_output_seq2));
+ if (ret)
+ return ret;
+ } else {
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ set_ts_output_seq3,
+ ARRAY_SIZE(set_ts_output_seq3));
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ set_ts_output_seq4,
+ ARRAY_SIZE(set_ts_output_seq4));
+ if (ret)
+ return ret;
+ }
+ break;
+
+ case CXD2880_TNRDMD_TSOUT_IF_SPI:
+ break;
+
+ case CXD2880_TNRDMD_TSOUT_IF_SDIO:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ u8 data;
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ switch (tnr_dmd->create_param.ts_output_if) {
+ case CXD2880_TNRDMD_TSOUT_IF_SPI:
+ case CXD2880_TNRDMD_TSOUT_IF_SDIO:
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, &data, 1);
+ if (ret)
+ return ret;
+
+ break;
+ case CXD2880_TNRDMD_TSOUT_IF_TS:
+ default:
+ break;
+ }
+
+ return tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x01, 0x01);
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
new file mode 100644
index 000000000000..9d809a251fc7
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
@@ -0,0 +1,365 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_tnrdmd.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common control interface
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_TNRDMD_H
+#define CXD2880_TNRDMD_H
+
+#include <linux/atomic.h>
+
+#include "cxd2880_common.h"
+#include "cxd2880_io.h"
+#include "cxd2880_dtv.h"
+#include "cxd2880_dvbt.h"
+#include "cxd2880_dvbt2.h"
+
+#define CXD2880_TNRDMD_MAX_CFG_MEM_COUNT 100
+
+#define slvt_unfreeze_reg(tnr_dmd) ((void)((tnr_dmd)->io->write_reg\
+((tnr_dmd)->io, CXD2880_IO_TGT_DMD, 0x01, 0x00)))
+
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_UNDERFLOW 0x0001
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_OVERFLOW 0x0002
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_EMPTY 0x0004
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_FULL 0x0008
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_RRDY 0x0010
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_COMMAND 0x0020
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_ACCESS 0x0040
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_CPU_ERROR 0x0100
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_LOCK 0x0200
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_INV_LOCK 0x0400
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_NOOFDM 0x0800
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_EWS 0x1000
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_EEW 0x2000
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_FEC_FAIL 0x4000
+
+#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_L1POST_OK 0x01
+#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_DMD_LOCK 0x02
+#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_TS_LOCK 0x04
+
+enum cxd2880_tnrdmd_chip_id {
+ CXD2880_TNRDMD_CHIP_ID_UNKNOWN = 0x00,
+ CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X = 0x62,
+ CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11 = 0x6a
+};
+
+#define CXD2880_TNRDMD_CHIP_ID_VALID(chip_id) \
+ (((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) || \
+ ((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11))
+
+enum cxd2880_tnrdmd_state {
+ CXD2880_TNRDMD_STATE_UNKNOWN,
+ CXD2880_TNRDMD_STATE_SLEEP,
+ CXD2880_TNRDMD_STATE_ACTIVE,
+ CXD2880_TNRDMD_STATE_INVALID
+};
+
+enum cxd2880_tnrdmd_divermode {
+ CXD2880_TNRDMD_DIVERMODE_SINGLE,
+ CXD2880_TNRDMD_DIVERMODE_MAIN,
+ CXD2880_TNRDMD_DIVERMODE_SUB
+};
+
+enum cxd2880_tnrdmd_clockmode {
+ CXD2880_TNRDMD_CLOCKMODE_UNKNOWN,
+ CXD2880_TNRDMD_CLOCKMODE_A,
+ CXD2880_TNRDMD_CLOCKMODE_B,
+ CXD2880_TNRDMD_CLOCKMODE_C
+};
+
+enum cxd2880_tnrdmd_tsout_if {
+ CXD2880_TNRDMD_TSOUT_IF_TS,
+ CXD2880_TNRDMD_TSOUT_IF_SPI,
+ CXD2880_TNRDMD_TSOUT_IF_SDIO
+};
+
+enum cxd2880_tnrdmd_xtal_share {
+ CXD2880_TNRDMD_XTAL_SHARE_NONE,
+ CXD2880_TNRDMD_XTAL_SHARE_EXTREF,
+ CXD2880_TNRDMD_XTAL_SHARE_MASTER,
+ CXD2880_TNRDMD_XTAL_SHARE_SLAVE
+};
+
+enum cxd2880_tnrdmd_spectrum_sense {
+ CXD2880_TNRDMD_SPECTRUM_NORMAL,
+ CXD2880_TNRDMD_SPECTRUM_INV
+};
+
+enum cxd2880_tnrdmd_cfg_id {
+ CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB,
+ CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI,
+ CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI,
+ CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI,
+ CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE,
+ CXD2880_TNRDMD_CFG_TSCLK_CONT,
+ CXD2880_TNRDMD_CFG_TSCLK_MASK,
+ CXD2880_TNRDMD_CFG_TSVALID_MASK,
+ CXD2880_TNRDMD_CFG_TSERR_MASK,
+ CXD2880_TNRDMD_CFG_TSERR_VALID_DIS,
+ CXD2880_TNRDMD_CFG_TSPIN_CURRENT,
+ CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL,
+ CXD2880_TNRDMD_CFG_TSPIN_PULLUP,
+ CXD2880_TNRDMD_CFG_TSCLK_FREQ,
+ CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL,
+ CXD2880_TNRDMD_CFG_TS_PACKET_GAP,
+ CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE,
+ CXD2880_TNRDMD_CFG_PWM_VALUE,
+ CXD2880_TNRDMD_CFG_INTERRUPT,
+ CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL,
+ CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL,
+ CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS,
+ CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS,
+ CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS,
+ CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE,
+ CXD2880_TNRDMD_CFG_CABLE_INPUT,
+ CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE,
+ CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE,
+ CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST,
+ CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD,
+ CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD,
+ CXD2880_TNRDMD_CFG_DVBT_PER_MES,
+ CXD2880_TNRDMD_CFG_DVBT2_BBER_MES,
+ CXD2880_TNRDMD_CFG_DVBT2_LBER_MES,
+ CXD2880_TNRDMD_CFG_DVBT2_PER_MES,
+};
+
+enum cxd2880_tnrdmd_lock_result {
+ CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT,
+ CXD2880_TNRDMD_LOCK_RESULT_LOCKED,
+ CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED
+};
+
+enum cxd2880_tnrdmd_gpio_mode {
+ CXD2880_TNRDMD_GPIO_MODE_OUTPUT = 0x00,
+ CXD2880_TNRDMD_GPIO_MODE_INPUT = 0x01,
+ CXD2880_TNRDMD_GPIO_MODE_INT = 0x02,
+ CXD2880_TNRDMD_GPIO_MODE_FEC_FAIL = 0x03,
+ CXD2880_TNRDMD_GPIO_MODE_PWM = 0x04,
+ CXD2880_TNRDMD_GPIO_MODE_EWS = 0x05,
+ CXD2880_TNRDMD_GPIO_MODE_EEW = 0x06
+};
+
+enum cxd2880_tnrdmd_serial_ts_clk {
+ CXD2880_TNRDMD_SERIAL_TS_CLK_FULL,
+ CXD2880_TNRDMD_SERIAL_TS_CLK_HALF
+};
+
+struct cxd2880_tnrdmd_cfg_mem {
+ enum cxd2880_io_tgt tgt;
+ u8 bank;
+ u8 address;
+ u8 value;
+ u8 bit_mask;
+};
+
+struct cxd2880_tnrdmd_pid_cfg {
+ u8 is_en;
+ u16 pid;
+};
+
+struct cxd2880_tnrdmd_pid_ftr_cfg {
+ u8 is_negative;
+ struct cxd2880_tnrdmd_pid_cfg pid_cfg[32];
+};
+
+struct cxd2880_tnrdmd_lna_thrs {
+ u8 off_on;
+ u8 on_off;
+};
+
+struct cxd2880_tnrdmd_lna_thrs_tbl_air {
+ struct cxd2880_tnrdmd_lna_thrs thrs[24];
+};
+
+struct cxd2880_tnrdmd_lna_thrs_tbl_cable {
+ struct cxd2880_tnrdmd_lna_thrs thrs[32];
+};
+
+struct cxd2880_tnrdmd_create_param {
+ enum cxd2880_tnrdmd_tsout_if ts_output_if;
+ u8 en_internal_ldo;
+ enum cxd2880_tnrdmd_xtal_share xtal_share_type;
+ u8 xosc_cap;
+ u8 xosc_i;
+ u8 is_cxd2881gg;
+ u8 stationary_use;
+};
+
+struct cxd2880_tnrdmd_diver_create_param {
+ enum cxd2880_tnrdmd_tsout_if ts_output_if;
+ u8 en_internal_ldo;
+ u8 xosc_cap_main;
+ u8 xosc_i_main;
+ u8 xosc_i_sub;
+ u8 is_cxd2881gg;
+ u8 stationary_use;
+};
+
+struct cxd2880_tnrdmd {
+ struct cxd2880_tnrdmd *diver_sub;
+ struct cxd2880_io *io;
+ struct cxd2880_tnrdmd_create_param create_param;
+ enum cxd2880_tnrdmd_divermode diver_mode;
+ enum cxd2880_tnrdmd_clockmode fixed_clk_mode;
+ u8 is_cable_input;
+ u8 en_fef_intmtnt_base;
+ u8 en_fef_intmtnt_lite;
+ u8 blind_tune_dvbt2_first;
+ int (*rf_lvl_cmpstn)(struct cxd2880_tnrdmd *tnr_dmd,
+ int *rf_lvl_db);
+ struct cxd2880_tnrdmd_lna_thrs_tbl_air *lna_thrs_tbl_air;
+ struct cxd2880_tnrdmd_lna_thrs_tbl_cable *lna_thrs_tbl_cable;
+ u8 srl_ts_clk_mod_cnts;
+ enum cxd2880_tnrdmd_serial_ts_clk srl_ts_clk_frq;
+ u8 ts_byte_clk_manual_setting;
+ u8 is_ts_backwards_compatible_mode;
+ struct cxd2880_tnrdmd_cfg_mem cfg_mem[CXD2880_TNRDMD_MAX_CFG_MEM_COUNT];
+ u8 cfg_mem_last_entry;
+ struct cxd2880_tnrdmd_pid_ftr_cfg pid_ftr_cfg;
+ u8 pid_ftr_cfg_en;
+ void *user;
+ enum cxd2880_tnrdmd_chip_id chip_id;
+ enum cxd2880_tnrdmd_state state;
+ enum cxd2880_tnrdmd_clockmode clk_mode;
+ u32 frequency_khz;
+ enum cxd2880_dtv_sys sys;
+ enum cxd2880_dtv_bandwidth bandwidth;
+ u8 scan_mode;
+ atomic_t cancel;
+};
+
+int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_io *io,
+ struct cxd2880_tnrdmd_create_param
+ *create_param);
+
+int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd
+ *tnr_dmd_main,
+ struct cxd2880_io *io_main,
+ struct cxd2880_tnrdmd *tnr_dmd_sub,
+ struct cxd2880_io *io_sub,
+ struct
+ cxd2880_tnrdmd_diver_create_param
+ *create_param);
+
+int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ u8 *task_completed);
+
+int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dtv_sys sys,
+ u32 frequency_khz,
+ enum cxd2880_dtv_bandwidth
+ bandwidth, u8 one_seg_opt,
+ u8 one_seg_opt_shft_dir);
+
+int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dtv_sys sys,
+ u8 en_fef_intmtnt_ctrl);
+
+int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_tnrdmd_cfg_id id,
+ int value);
+
+int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 id,
+ u8 en,
+ enum cxd2880_tnrdmd_gpio_mode mode,
+ u8 open_drain, u8 invert);
+
+int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 id,
+ u8 en,
+ enum cxd2880_tnrdmd_gpio_mode
+ mode, u8 open_drain,
+ u8 invert);
+
+int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 id, u8 *value);
+
+int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 id, u8 *value);
+
+int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 id, u8 value);
+
+int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 id, u8 value);
+
+int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd,
+ u16 *value);
+
+int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd,
+ u16 value);
+
+int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 clear_overflow_flag,
+ u8 clear_underflow_flag,
+ u8 clear_buf);
+
+int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_tnrdmd_chip_id *chip_id);
+
+int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_io_tgt tgt,
+ u8 bank, u8 address,
+ u8 value, u8 bit_mask);
+
+int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_dtv_sys sys,
+ u8 scan_mode_end);
+
+int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_tnrdmd_pid_ftr_cfg
+ *pid_ftr_cfg);
+
+int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ int (*rf_lvl_cmpstn)
+ (struct cxd2880_tnrdmd *,
+ int *));
+
+int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd *tnr_dmd,
+ int (*rf_lvl_cmpstn)
+ (struct cxd2880_tnrdmd *,
+ int *));
+
+int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd,
+ struct
+ cxd2880_tnrdmd_lna_thrs_tbl_air
+ *tbl_air,
+ struct
+ cxd2880_tnrdmd_lna_thrs_tbl_cable
+ *tbl_cable);
+
+int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd,
+ struct
+ cxd2880_tnrdmd_lna_thrs_tbl_air
+ *tbl_air,
+ struct
+ cxd2880_tnrdmd_lna_thrs_tbl_cable
+ *tbl_cable);
+
+int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 en, u8 value);
+
+int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 en);
+
+int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
new file mode 100644
index 000000000000..fab55038b37b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_tnrdmd_driver_version.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * version information
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.4"
+
+#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2018-01-17"
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
new file mode 100644
index 000000000000..fe3c6f8b1b3e
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
@@ -0,0 +1,919 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cxd2880_tnrdmd_dvbt.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control functions for DVB-T
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#include <media/dvb_frontend.h>
+
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_tnrdmd_dvbt_mon.h"
+
+static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = {
+ {0x00, 0x00}, {0x31, 0x01},
+};
+
+static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = {
+ {0x00, 0x04}, {0x5c, 0xfb}, {0x00, 0x10}, {0xa4, 0x03},
+ {0x00, 0x14}, {0xb0, 0x00}, {0x00, 0x25},
+};
+
+static const struct cxd2880_reg_value tune_dmd_setting_seq3[] = {
+ {0x00, 0x12}, {0x44, 0x00},
+};
+
+static const struct cxd2880_reg_value tune_dmd_setting_seq4[] = {
+ {0x00, 0x11}, {0x87, 0xd2},
+};
+
+static const struct cxd2880_reg_value tune_dmd_setting_seq5[] = {
+ {0x00, 0x00}, {0xfd, 0x01},
+};
+
+static const struct cxd2880_reg_value sleep_dmd_setting_seq1[] = {
+ {0x00, 0x04}, {0x5c, 0xd8}, {0x00, 0x10}, {0xa4, 0x00},
+};
+
+static const struct cxd2880_reg_value sleep_dmd_setting_seq2[] = {
+ {0x00, 0x11}, {0x87, 0x04},
+};
+
+static int x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dtv_bandwidth
+ bandwidth,
+ enum cxd2880_tnrdmd_clockmode
+ clk_mode)
+{
+ static const u8 clk_mode_ckffrq_a[2] = { 0x52, 0x49 };
+ static const u8 clk_mode_ckffrq_b[2] = { 0x5d, 0x55 };
+ static const u8 clk_mode_ckffrq_c[2] = { 0x60, 0x00 };
+ static const u8 ratectl_margin[2] = { 0x01, 0xf0 };
+ static const u8 maxclkcnt_a[3] = { 0x73, 0xca, 0x49 };
+ static const u8 maxclkcnt_b[3] = { 0xc8, 0x13, 0xaa };
+ static const u8 maxclkcnt_c[3] = { 0xdc, 0x6c, 0x00 };
+
+ static const u8 bw8_nomi_ac[5] = { 0x15, 0x00, 0x00, 0x00, 0x00};
+ static const u8 bw8_nomi_b[5] = { 0x14, 0x6a, 0xaa, 0xaa, 0xaa};
+ static const u8 bw8_gtdofst_a[2] = { 0x01, 0x28 };
+ static const u8 bw8_gtdofst_b[2] = { 0x11, 0x44 };
+ static const u8 bw8_gtdofst_c[2] = { 0x15, 0x28 };
+ static const u8 bw8_mrc_a[5] = { 0x30, 0x00, 0x00, 0x90, 0x00 };
+ static const u8 bw8_mrc_b[5] = { 0x36, 0x71, 0x00, 0xa3, 0x55 };
+ static const u8 bw8_mrc_c[5] = { 0x38, 0x00, 0x00, 0xa8, 0x00 };
+ static const u8 bw8_notch[4] = { 0xb3, 0x00, 0x01, 0x02 };
+
+ static const u8 bw7_nomi_ac[5] = { 0x18, 0x00, 0x00, 0x00, 0x00};
+ static const u8 bw7_nomi_b[5] = { 0x17, 0x55, 0x55, 0x55, 0x55};
+ static const u8 bw7_gtdofst_a[2] = { 0x12, 0x4c };
+ static const u8 bw7_gtdofst_b[2] = { 0x1f, 0x15 };
+ static const u8 bw7_gtdofst_c[2] = { 0x1f, 0xf8 };
+ static const u8 bw7_mrc_a[5] = { 0x36, 0xdb, 0x00, 0xa4, 0x92 };
+ static const u8 bw7_mrc_b[5] = { 0x3e, 0x38, 0x00, 0xba, 0xaa };
+ static const u8 bw7_mrc_c[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 };
+ static const u8 bw7_notch[4] = { 0xb8, 0x00, 0x00, 0x03 };
+
+ static const u8 bw6_nomi_ac[5] = { 0x1c, 0x00, 0x00, 0x00, 0x00};
+ static const u8 bw6_nomi_b[5] = { 0x1b, 0x38, 0xe3, 0x8e, 0x38};
+ static const u8 bw6_gtdofst_a[2] = { 0x1f, 0xf8 };
+ static const u8 bw6_gtdofst_b[2] = { 0x24, 0x43 };
+ static const u8 bw6_gtdofst_c[2] = { 0x25, 0x4c };
+ static const u8 bw6_mrc_a[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 };
+ static const u8 bw6_mrc_b[5] = { 0x48, 0x97, 0x00, 0xd9, 0xc7 };
+ static const u8 bw6_mrc_c[5] = { 0x4a, 0xaa, 0x00, 0xdf, 0xff };
+ static const u8 bw6_notch[4] = { 0xbe, 0xab, 0x00, 0x03 };
+
+ static const u8 bw5_nomi_ac[5] = { 0x21, 0x99, 0x99, 0x99, 0x99};
+ static const u8 bw5_nomi_b[5] = { 0x20, 0xaa, 0xaa, 0xaa, 0xaa};
+ static const u8 bw5_gtdofst_a[2] = { 0x26, 0x5d };
+ static const u8 bw5_gtdofst_b[2] = { 0x2b, 0x84 };
+ static const u8 bw5_gtdofst_c[2] = { 0x2c, 0xc2 };
+ static const u8 bw5_mrc_a[5] = { 0x4c, 0xcc, 0x00, 0xe6, 0x66 };
+ static const u8 bw5_mrc_b[5] = { 0x57, 0x1c, 0x01, 0x05, 0x55 };
+ static const u8 bw5_mrc_c[5] = { 0x59, 0x99, 0x01, 0x0c, 0xcc };
+ static const u8 bw5_notch[4] = { 0xc8, 0x01, 0x00, 0x03 };
+ const u8 *data = NULL;
+ u8 sst_data;
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ tune_dmd_setting_seq1,
+ ARRAY_SIZE(tune_dmd_setting_seq1));
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x04);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = clk_mode_ckffrq_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = clk_mode_ckffrq_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = clk_mode_ckffrq_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x65, data, 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x5d, 0x07);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+ u8 data[2] = { 0x01, 0x01 };
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xce, data, 2);
+ if (ret)
+ return ret;
+ }
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ tune_dmd_setting_seq2,
+ ARRAY_SIZE(tune_dmd_setting_seq2));
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xf0, ratectl_margin, 2);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN ||
+ tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ tune_dmd_setting_seq3,
+ ARRAY_SIZE(tune_dmd_setting_seq3));
+ if (ret)
+ return ret;
+ }
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ tune_dmd_setting_seq4,
+ ARRAY_SIZE(tune_dmd_setting_seq4));
+ if (ret)
+ return ret;
+ }
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x04);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = maxclkcnt_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = maxclkcnt_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = maxclkcnt_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x68, data, 3);
+ if (ret)
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x04);
+ if (ret)
+ return ret;
+
+ switch (bandwidth) {
+ case CXD2880_DTV_BW_8_MHZ:
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw8_nomi_ac;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw8_nomi_b;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x60, data, 5);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4a, 0x00);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw8_gtdofst_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw8_gtdofst_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw8_gtdofst_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x7d, data, 2);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ sst_data = 0x35;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ sst_data = 0x34;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x71, sst_data);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw8_mrc_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw8_mrc_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw8_mrc_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4b, &data[0], 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x51, &data[2], 3);
+ if (ret)
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x72, &bw8_notch[0], 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x6b, &bw8_notch[2], 2);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_DTV_BW_7_MHZ:
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw7_nomi_ac;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw7_nomi_b;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x60, data, 5);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4a, 0x02);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw7_gtdofst_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw7_gtdofst_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw7_gtdofst_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x7d, data, 2);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ sst_data = 0x2f;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ sst_data = 0x2e;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x71, sst_data);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw7_mrc_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw7_mrc_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw7_mrc_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4b, &data[0], 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x51, &data[2], 3);
+ if (ret)
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x72, &bw7_notch[0], 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x6b, &bw7_notch[2], 2);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_DTV_BW_6_MHZ:
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw6_nomi_ac;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw6_nomi_b;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x60, data, 5);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4a, 0x04);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw6_gtdofst_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw6_gtdofst_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw6_gtdofst_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x7d, data, 2);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ sst_data = 0x29;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ sst_data = 0x2a;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x71, sst_data);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw6_mrc_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw6_mrc_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw6_mrc_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4b, &data[0], 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x51, &data[2], 3);
+ if (ret)
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x72, &bw6_notch[0], 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x6b, &bw6_notch[2], 2);
+ if (ret)
+ return ret;
+ break;
+
+ case CXD2880_DTV_BW_5_MHZ:
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw5_nomi_ac;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw5_nomi_b;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x60, data, 5);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4a, 0x06);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw5_gtdofst_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw5_gtdofst_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw5_gtdofst_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x7d, data, 2);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ sst_data = 0x24;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ sst_data = 0x23;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x71, sst_data);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw5_mrc_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw5_mrc_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw5_mrc_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4b, &data[0], 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x51, &data[2], 3);
+ if (ret)
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x72, &bw5_notch[0], 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x6b, &bw5_notch[2], 2);
+ if (ret)
+ return ret;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ tune_dmd_setting_seq5,
+ ARRAY_SIZE(tune_dmd_setting_seq5));
+}
+
+static int x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd
+ *tnr_dmd)
+{
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ sleep_dmd_setting_seq1,
+ ARRAY_SIZE(sleep_dmd_setting_seq1));
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ sleep_dmd_setting_seq2,
+ ARRAY_SIZE(sleep_dmd_setting_seq2));
+
+ return ret;
+}
+
+static int dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_dvbt_profile profile)
+{
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x10);
+ if (ret)
+ return ret;
+
+ return tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x67,
+ (profile == CXD2880_DVBT_PROFILE_HP)
+ ? 0x00 : 0x01);
+}
+
+int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_dvbt_tune_param
+ *tune_param)
+{
+ int ret;
+
+ if (!tnr_dmd || !tune_param)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT,
+ tune_param->center_freq_khz,
+ tune_param->bandwidth, 0, 0);
+ if (ret)
+ return ret;
+
+ ret =
+ x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth,
+ tnr_dmd->clk_mode);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret =
+ x_tune_dvbt_demod_setting(tnr_dmd->diver_sub,
+ tune_param->bandwidth,
+ tnr_dmd->diver_sub->clk_mode);
+ if (ret)
+ return ret;
+ }
+
+ return dvbt_set_profile(tnr_dmd, tune_param->profile);
+}
+
+int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_dvbt_tune_param
+ *tune_param)
+{
+ int ret;
+
+ if (!tnr_dmd || !tune_param)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT,
+ 0);
+ if (ret)
+ return ret;
+
+ tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
+ tnr_dmd->frequency_khz = tune_param->center_freq_khz;
+ tnr_dmd->sys = CXD2880_DTV_SYS_DVBT;
+ tnr_dmd->bandwidth = tune_param->bandwidth;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
+ tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
+ tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT;
+ tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
+ }
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret = x_sleep_dvbt_demod_setting(tnr_dmd);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+ ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub);
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_tnrdmd_lock_result
+ *lock)
+{
+ int ret;
+
+ u8 sync_stat = 0;
+ u8 ts_lock = 0;
+ u8 unlock_detected = 0;
+ u8 unlock_detected_sub = 0;
+
+ if (!tnr_dmd || !lock)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+ &unlock_detected);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+ if (sync_stat == 6)
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+ else if (unlock_detected)
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+ else
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+ return ret;
+ }
+
+ if (sync_stat == 6) {
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+ return ret;
+ }
+
+ ret =
+ cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+ &unlock_detected_sub);
+ if (ret)
+ return ret;
+
+ if (sync_stat == 6)
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+ else if (unlock_detected && unlock_detected_sub)
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+ else
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_tnrdmd_lock_result
+ *lock)
+{
+ int ret;
+
+ u8 sync_stat = 0;
+ u8 ts_lock = 0;
+ u8 unlock_detected = 0;
+ u8 unlock_detected_sub = 0;
+
+ if (!tnr_dmd || !lock)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+ &unlock_detected);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+ if (ts_lock)
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+ else if (unlock_detected)
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+ else
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+ return ret;
+ }
+
+ if (ts_lock) {
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+ return ret;
+ } else if (!unlock_detected) {
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+ return ret;
+ }
+
+ ret =
+ cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+ &unlock_detected_sub);
+ if (ret)
+ return ret;
+
+ if (unlock_detected && unlock_detected_sub)
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+ else
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+ return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
new file mode 100644
index 000000000000..35d81ccc732b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_tnrdmd_dvbt.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control interface for DVB-T
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT_H
+#define CXD2880_TNRDMD_DVBT_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+
+struct cxd2880_dvbt_tune_param {
+ u32 center_freq_khz;
+ enum cxd2880_dtv_bandwidth bandwidth;
+ enum cxd2880_dvbt_profile profile;
+};
+
+int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_dvbt_tune_param
+ *tune_param);
+
+int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_dvbt_tune_param
+ *tune_param);
+
+int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd
+ *tnr_dmd);
+
+int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_tnrdmd_lock_result
+ *lock);
+
+int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_tnrdmd_lock_result
+ *lock);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
new file mode 100644
index 000000000000..dd32004a12d8
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
@@ -0,0 +1,1217 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cxd2880_tnrdmd_dvbt2.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control functions for DVB-T2
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#include <media/dvb_frontend.h>
+
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+
+static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = {
+ {0x00, 0x00}, {0x31, 0x02},
+};
+
+static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = {
+ {0x00, 0x04}, {0x5d, 0x0b},
+};
+
+static int x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dtv_bandwidth
+ bandwidth,
+ enum cxd2880_tnrdmd_clockmode
+ clk_mode)
+{
+ static const u8 tsif_settings[2] = { 0x01, 0x01 };
+ static const u8 init_settings[14] = {
+ 0x07, 0x06, 0x01, 0xf0, 0x00, 0x00, 0x04, 0xb0, 0x00, 0x00,
+ 0x09, 0x9c, 0x0e, 0x4c
+ };
+ static const u8 clk_mode_settings_a1[9] = {
+ 0x52, 0x49, 0x2c, 0x51, 0x51, 0x3d, 0x15, 0x29, 0x0c
+ };
+
+ static const u8 clk_mode_settings_b1[9] = {
+ 0x5d, 0x55, 0x32, 0x5c, 0x5c, 0x45, 0x17, 0x2e, 0x0d
+ };
+
+ static const u8 clk_mode_settings_c1[9] = {
+ 0x60, 0x00, 0x34, 0x5e, 0x5e, 0x47, 0x18, 0x2f, 0x0e
+ };
+
+ static const u8 clk_mode_settings_a2[13] = {
+ 0x04, 0xe7, 0x94, 0x92, 0x09, 0xcf, 0x7e, 0xd0, 0x49,
+ 0xcd, 0xcd, 0x1f, 0x5b
+ };
+
+ static const u8 clk_mode_settings_b2[13] = {
+ 0x05, 0x90, 0x27, 0x55, 0x0b, 0x20, 0x8f, 0xd6, 0xea,
+ 0xc8, 0xc8, 0x23, 0x91
+ };
+
+ static const u8 clk_mode_settings_c2[13] = {
+ 0x05, 0xb8, 0xd8, 0x00, 0x0b, 0x72, 0x93, 0xf3, 0x00,
+ 0xcd, 0xcd, 0x24, 0x95
+ };
+
+ static const u8 clk_mode_settings_a3[5] = {
+ 0x0b, 0x6a, 0xc9, 0x03, 0x33
+ };
+ static const u8 clk_mode_settings_b3[5] = {
+ 0x01, 0x02, 0xe4, 0x03, 0x39
+ };
+ static const u8 clk_mode_settings_c3[5] = {
+ 0x01, 0x02, 0xeb, 0x03, 0x3b
+ };
+
+ static const u8 gtdofst[2] = { 0x3f, 0xff };
+
+ static const u8 bw8_gtdofst_a[2] = { 0x19, 0xd2 };
+ static const u8 bw8_nomi_ac[6] = { 0x15, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const u8 bw8_nomi_b[6] = { 0x14, 0x6a, 0xaa, 0xaa, 0xab, 0x00 };
+ static const u8 bw8_sst_a[2] = { 0x06, 0x2a };
+ static const u8 bw8_sst_b[2] = { 0x06, 0x29 };
+ static const u8 bw8_sst_c[2] = { 0x06, 0x28 };
+ static const u8 bw8_mrc_a[9] = {
+ 0x28, 0x00, 0x50, 0x00, 0x60, 0x00, 0x00, 0x90, 0x00
+ };
+ static const u8 bw8_mrc_b[9] = {
+ 0x2d, 0x5e, 0x5a, 0xbd, 0x6c, 0xe3, 0x00, 0xa3, 0x55
+ };
+ static const u8 bw8_mrc_c[9] = {
+ 0x2e, 0xaa, 0x5d, 0x55, 0x70, 0x00, 0x00, 0xa8, 0x00
+ };
+
+ static const u8 bw7_nomi_ac[6] = { 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const u8 bw7_nomi_b[6] = { 0x17, 0x55, 0x55, 0x55, 0x55, 0x00 };
+ static const u8 bw7_sst_a[2] = { 0x06, 0x23 };
+ static const u8 bw7_sst_b[2] = { 0x06, 0x22 };
+ static const u8 bw7_sst_c[2] = { 0x06, 0x21 };
+ static const u8 bw7_mrc_a[9] = {
+ 0x2d, 0xb6, 0x5b, 0x6d, 0x6d, 0xb6, 0x00, 0xa4, 0x92
+ };
+ static const u8 bw7_mrc_b[9] = {
+ 0x33, 0xda, 0x67, 0xb4, 0x7c, 0x71, 0x00, 0xba, 0xaa
+ };
+ static const u8 bw7_mrc_c[9] = {
+ 0x35, 0x55, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xc0, 0x00
+ };
+
+ static const u8 bw6_nomi_ac[6] = { 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const u8 bw6_nomi_b[6] = { 0x1b, 0x38, 0xe3, 0x8e, 0x39, 0x00 };
+ static const u8 bw6_sst_a[2] = { 0x06, 0x1c };
+ static const u8 bw6_sst_b[2] = { 0x06, 0x1b };
+ static const u8 bw6_sst_c[2] = { 0x06, 0x1a };
+ static const u8 bw6_mrc_a[9] = {
+ 0x35, 0x55, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xc0, 0x00
+ };
+ static const u8 bw6_mrc_b[9] = {
+ 0x3c, 0x7e, 0x78, 0xfc, 0x91, 0x2f, 0x00, 0xd9, 0xc7
+ };
+ static const u8 bw6_mrc_c[9] = {
+ 0x3e, 0x38, 0x7c, 0x71, 0x95, 0x55, 0x00, 0xdf, 0xff
+ };
+
+ static const u8 bw5_nomi_ac[6] = { 0x21, 0x99, 0x99, 0x99, 0x9a, 0x00 };
+ static const u8 bw5_nomi_b[6] = { 0x20, 0xaa, 0xaa, 0xaa, 0xab, 0x00 };
+ static const u8 bw5_sst_a[2] = { 0x06, 0x15 };
+ static const u8 bw5_sst_b[2] = { 0x06, 0x15 };
+ static const u8 bw5_sst_c[2] = { 0x06, 0x14 };
+ static const u8 bw5_mrc_a[9] = {
+ 0x40, 0x00, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xe6, 0x66
+ };
+ static const u8 bw5_mrc_b[9] = {
+ 0x48, 0x97, 0x78, 0xfc, 0x91, 0x2f, 0x01, 0x05, 0x55
+ };
+ static const u8 bw5_mrc_c[9] = {
+ 0x4a, 0xaa, 0x7c, 0x71, 0x95, 0x55, 0x01, 0x0c, 0xcc
+ };
+
+ static const u8 bw1_7_nomi_a[6] = {
+ 0x68, 0x0f, 0xa2, 0x32, 0xcf, 0x03
+ };
+ static const u8 bw1_7_nomi_c[6] = {
+ 0x68, 0x0f, 0xa2, 0x32, 0xcf, 0x03
+ };
+ static const u8 bw1_7_nomi_b[6] = {
+ 0x65, 0x2b, 0xa4, 0xcd, 0xd8, 0x03
+ };
+ static const u8 bw1_7_sst_a[2] = { 0x06, 0x0c };
+ static const u8 bw1_7_sst_b[2] = { 0x06, 0x0c };
+ static const u8 bw1_7_sst_c[2] = { 0x06, 0x0b };
+ static const u8 bw1_7_mrc_a[9] = {
+ 0x40, 0x00, 0x6a, 0xaa, 0x80, 0x00, 0x02, 0xc9, 0x8f
+ };
+ static const u8 bw1_7_mrc_b[9] = {
+ 0x48, 0x97, 0x78, 0xfc, 0x91, 0x2f, 0x03, 0x29, 0x5d
+ };
+ static const u8 bw1_7_mrc_c[9] = {
+ 0x4a, 0xaa, 0x7c, 0x71, 0x95, 0x55, 0x03, 0x40, 0x7d
+ };
+
+ const u8 *data = NULL;
+ const u8 *data2 = NULL;
+ const u8 *data3 = NULL;
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ tune_dmd_setting_seq1,
+ ARRAY_SIZE(tune_dmd_setting_seq1));
+ if (ret)
+ return ret;
+
+ ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ tune_dmd_setting_seq2,
+ ARRAY_SIZE(tune_dmd_setting_seq2));
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xce, tsif_settings, 2);
+ if (ret)
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x20);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x8a, init_settings[0]);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x90, init_settings[1]);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x25);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xf0, &init_settings[2], 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x2a);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xdc, init_settings[4]);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xde, init_settings[5]);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x2d);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x73, &init_settings[6], 4);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x8f, &init_settings[10], 4);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = clk_mode_settings_a1;
+ data2 = clk_mode_settings_a2;
+ data3 = clk_mode_settings_a3;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = clk_mode_settings_b1;
+ data2 = clk_mode_settings_b2;
+ data3 = clk_mode_settings_b3;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = clk_mode_settings_c1;
+ data2 = clk_mode_settings_c2;
+ data3 = clk_mode_settings_c3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x04);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x1d, &data[0], 3);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x22, data[3]);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x24, data[4]);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x26, data[5]);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x29, &data[6], 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x2d, data[8]);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x2e, &data2[0], 6);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x35, &data2[6], 7);
+ if (ret)
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x3c, &data3[0], 2);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x56, &data3[2], 3);
+ if (ret)
+ return ret;
+
+ switch (bandwidth) {
+ case CXD2880_DTV_BW_8_MHZ:
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw8_nomi_ac;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw8_nomi_b;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x10, data, 6);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4a, 0x00);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw8_gtdofst_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = gtdofst;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x19, data, 2);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw8_sst_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw8_sst_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw8_sst_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x1b, data, 2);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw8_mrc_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw8_mrc_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw8_mrc_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4b, data, 9);
+ if (ret)
+ return ret;
+ }
+ break;
+
+ case CXD2880_DTV_BW_7_MHZ:
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw7_nomi_ac;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw7_nomi_b;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x10, data, 6);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4a, 0x02);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x19, gtdofst, 2);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw7_sst_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw7_sst_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw7_sst_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x1b, data, 2);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw7_mrc_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw7_mrc_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw7_mrc_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4b, data, 9);
+ if (ret)
+ return ret;
+ }
+ break;
+
+ case CXD2880_DTV_BW_6_MHZ:
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw6_nomi_ac;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw6_nomi_b;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x10, data, 6);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4a, 0x04);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x19, gtdofst, 2);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw6_sst_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw6_sst_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw6_sst_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x1b, data, 2);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw6_mrc_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw6_mrc_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw6_mrc_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4b, data, 9);
+ if (ret)
+ return ret;
+ }
+ break;
+
+ case CXD2880_DTV_BW_5_MHZ:
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw5_nomi_ac;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw5_nomi_b;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x10, data, 6);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4a, 0x06);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x19, gtdofst, 2);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw5_sst_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw5_sst_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw5_sst_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x1b, data, 2);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw5_mrc_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw5_mrc_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw5_mrc_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4b, data, 9);
+ if (ret)
+ return ret;
+ }
+ break;
+
+ case CXD2880_DTV_BW_1_7_MHZ:
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw1_7_nomi_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw1_7_nomi_c;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw1_7_nomi_b;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x10, data, 6);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4a, 0x03);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x19, gtdofst, 2);
+ if (ret)
+ return ret;
+
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw1_7_sst_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw1_7_sst_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw1_7_sst_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x1b, data, 2);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ switch (clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ data = bw1_7_mrc_a;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ data = bw1_7_mrc_b;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ data = bw1_7_mrc_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x4b, data, 9);
+ if (ret)
+ return ret;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+
+ return tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xfd, 0x01);
+}
+
+static int x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd
+ *tnr_dmd)
+{
+ static const u8 difint_clip[] = {
+ 0, 1, 0, 2, 0, 4, 0, 8, 0, 16, 0, 32
+ };
+ int ret = 0;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x1d);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x47, difint_clip, 12);
+ }
+
+ return ret;
+}
+
+static int dvbt2_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_dvbt2_profile profile)
+{
+ u8 t2_mode_tune_mode = 0;
+ u8 seq_not2_dtime = 0;
+ u8 dtime1 = 0;
+ u8 dtime2 = 0;
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ switch (tnr_dmd->clk_mode) {
+ case CXD2880_TNRDMD_CLOCKMODE_A:
+ dtime1 = 0x27;
+ dtime2 = 0x0c;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_B:
+ dtime1 = 0x2c;
+ dtime2 = 0x0d;
+ break;
+ case CXD2880_TNRDMD_CLOCKMODE_C:
+ dtime1 = 0x2e;
+ dtime2 = 0x0e;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (profile) {
+ case CXD2880_DVBT2_PROFILE_BASE:
+ t2_mode_tune_mode = 0x01;
+ seq_not2_dtime = dtime2;
+ break;
+
+ case CXD2880_DVBT2_PROFILE_LITE:
+ t2_mode_tune_mode = 0x05;
+ seq_not2_dtime = dtime1;
+ break;
+
+ case CXD2880_DVBT2_PROFILE_ANY:
+ t2_mode_tune_mode = 0x00;
+ seq_not2_dtime = dtime1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x2e);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x10, t2_mode_tune_mode);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x04);
+ if (ret)
+ return ret;
+
+ return tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x2c, seq_not2_dtime);
+}
+
+int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_dvbt2_tune_param
+ *tune_param)
+{
+ int ret;
+
+ if (!tnr_dmd || !tune_param)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN &&
+ tune_param->profile == CXD2880_DVBT2_PROFILE_ANY)
+ return -ENOTTY;
+
+ ret =
+ cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT2,
+ tune_param->center_freq_khz,
+ tune_param->bandwidth, 0, 0);
+ if (ret)
+ return ret;
+
+ ret =
+ x_tune_dvbt2_demod_setting(tnr_dmd, tune_param->bandwidth,
+ tnr_dmd->clk_mode);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret =
+ x_tune_dvbt2_demod_setting(tnr_dmd->diver_sub,
+ tune_param->bandwidth,
+ tnr_dmd->diver_sub->clk_mode);
+ if (ret)
+ return ret;
+ }
+
+ ret = dvbt2_set_profile(tnr_dmd, tune_param->profile);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret =
+ dvbt2_set_profile(tnr_dmd->diver_sub, tune_param->profile);
+ if (ret)
+ return ret;
+ }
+
+ if (tune_param->data_plp_id == CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO)
+ ret = cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 1, 0);
+ else
+ ret =
+ cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 0,
+ (u8)(tune_param->data_plp_id));
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_dvbt2_tune_param
+ *tune_param)
+{
+ u8 en_fef_intmtnt_ctrl = 1;
+ int ret;
+
+ if (!tnr_dmd || !tune_param)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ switch (tune_param->profile) {
+ case CXD2880_DVBT2_PROFILE_BASE:
+ en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_base;
+ break;
+ case CXD2880_DVBT2_PROFILE_LITE:
+ en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_lite;
+ break;
+ case CXD2880_DVBT2_PROFILE_ANY:
+ if (tnr_dmd->en_fef_intmtnt_base &&
+ tnr_dmd->en_fef_intmtnt_lite)
+ en_fef_intmtnt_ctrl = 1;
+ else
+ en_fef_intmtnt_ctrl = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret =
+ cxd2880_tnrdmd_common_tune_setting2(tnr_dmd,
+ CXD2880_DTV_SYS_DVBT2,
+ en_fef_intmtnt_ctrl);
+ if (ret)
+ return ret;
+
+ tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
+ tnr_dmd->frequency_khz = tune_param->center_freq_khz;
+ tnr_dmd->sys = CXD2880_DTV_SYS_DVBT2;
+ tnr_dmd->bandwidth = tune_param->bandwidth;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
+ tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
+ tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT2;
+ tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
+ }
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd
+ *tnr_dmd)
+{
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret = x_sleep_dvbt2_demod_setting(tnr_dmd);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+ ret = x_sleep_dvbt2_demod_setting(tnr_dmd->diver_sub);
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_tnrdmd_lock_result
+ *lock)
+{
+ int ret;
+
+ u8 sync_stat = 0;
+ u8 ts_lock = 0;
+ u8 unlock_detected = 0;
+ u8 unlock_detected_sub = 0;
+
+ if (!tnr_dmd || !lock)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+ &unlock_detected);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+ if (sync_stat == 6)
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+ else if (unlock_detected)
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+ else
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+ return ret;
+ }
+
+ if (sync_stat == 6) {
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+ return ret;
+ }
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+ &unlock_detected_sub);
+ if (ret)
+ return ret;
+
+ if (sync_stat == 6)
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+ else if (unlock_detected && unlock_detected_sub)
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+ else
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_tnrdmd_lock_result
+ *lock)
+{
+ int ret;
+
+ u8 sync_stat = 0;
+ u8 ts_lock = 0;
+ u8 unlock_detected = 0;
+ u8 unlock_detected_sub = 0;
+
+ if (!tnr_dmd || !lock)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+ &unlock_detected);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+ if (ts_lock)
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+ else if (unlock_detected)
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+ else
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+ return ret;
+ }
+
+ if (ts_lock) {
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+ return ret;
+ } else if (!unlock_detected) {
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+ return ret;
+ }
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+ &unlock_detected_sub);
+ if (ret)
+ return ret;
+
+ if (unlock_detected && unlock_detected_sub)
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+ else
+ *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 auto_plp,
+ u8 plp_id)
+{
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x23);
+ if (ret)
+ return ret;
+
+ if (!auto_plp) {
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xaf, plp_id);
+ if (ret)
+ return ret;
+ }
+
+ return tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xad, auto_plp ? 0x00 : 0x01);
+}
+
+int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd
+ *tnr_dmd)
+{
+ struct cxd2880_dvbt2_ofdm ofdm;
+ static const u8 data[] = { 0, 8, 0, 16, 0, 32, 0, 64, 0, 128, 1, 0};
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE)
+ return 0;
+
+ ret = cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd, &ofdm);
+ if (ret)
+ return ret;
+
+ if (!ofdm.mixed)
+ return 0;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x1d);
+ if (ret)
+ return ret;
+
+ return tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x47, data, 12);
+}
+
+int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ u8 *l1_post_valid)
+{
+ int ret;
+
+ u8 data;
+
+ if (!tnr_dmd || !l1_post_valid)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x86, &data, 1);
+ if (ret)
+ return ret;
+
+ *l1_post_valid = data & 0x01;
+
+ return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
new file mode 100644
index 000000000000..7108e3540093
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_tnrdmd_dvbt2.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control interface for DVB-T2
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT2_H
+#define CXD2880_TNRDMD_DVBT2_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+
+enum cxd2880_tnrdmd_dvbt2_tune_info {
+ CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK,
+ CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID
+};
+
+struct cxd2880_dvbt2_tune_param {
+ u32 center_freq_khz;
+ enum cxd2880_dtv_bandwidth bandwidth;
+ u16 data_plp_id;
+ enum cxd2880_dvbt2_profile profile;
+ enum cxd2880_tnrdmd_dvbt2_tune_info tune_info;
+};
+
+#define CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO 0xffff
+
+int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_dvbt2_tune_param
+ *tune_param);
+
+int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_dvbt2_tune_param
+ *tune_param);
+
+int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd
+ *tnr_dmd);
+
+int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_tnrdmd_lock_result
+ *lock);
+
+int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_tnrdmd_lock_result
+ *lock);
+
+int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 auto_plp,
+ u8 plp_id);
+
+int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd
+ *tnr_dmd);
+
+int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ u8 *l1_post_valid);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
new file mode 100644
index 000000000000..604580bf7cf7
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
@@ -0,0 +1,1878 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cxd2880_tnrdmd_dvbt2_mon.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T2 monitor functions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+
+#include <media/dvb_math.h>
+
+static const int ref_dbm_1000[4][8] = {
+ {-96000, -95000, -94000, -93000, -92000, -92000, -98000, -97000},
+ {-91000, -89000, -88000, -87000, -86000, -86000, -93000, -92000},
+ {-86000, -85000, -83000, -82000, -81000, -80000, -89000, -88000},
+ {-82000, -80000, -78000, -76000, -75000, -74000, -86000, -84000},
+};
+
+int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 *sync_stat,
+ u8 *ts_lock_stat,
+ u8 *unlock_detected)
+{
+ u8 data;
+ int ret;
+
+ if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x10, &data, sizeof(data));
+ if (ret)
+ return ret;
+
+ *sync_stat = data & 0x07;
+ *ts_lock_stat = ((data & 0x20) ? 1 : 0);
+ *unlock_detected = ((data & 0x10) ? 1 : 0);
+
+ if (*sync_stat == 0x07)
+ return -EAGAIN;
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ u8 *sync_stat,
+ u8 *unlock_detected)
+{
+ u8 ts_lock_stat = 0;
+
+ if (!tnr_dmd || !sync_stat || !unlock_detected)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ return cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub,
+ sync_stat,
+ &ts_lock_stat,
+ unlock_detected);
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
+ *tnr_dmd, int *offset)
+{
+ u8 data[4];
+ u32 ctl_val = 0;
+ u8 sync_state = 0;
+ u8 ts_lock = 0;
+ u8 unlock_detected = 0;
+ int ret;
+
+ if (!tnr_dmd || !offset)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+ &ts_lock,
+ &unlock_detected);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (sync_state != 6) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x30, data, sizeof(data));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ ctl_val =
+ ((data[0] & 0x0f) << 24) | (data[1] << 16) | (data[2] << 8)
+ | (data[3]);
+ *offset = cxd2880_convert2s_complement(ctl_val, 28);
+
+ switch (tnr_dmd->bandwidth) {
+ case CXD2880_DTV_BW_1_7_MHZ:
+ *offset = -1 * ((*offset) / 582);
+ break;
+ case CXD2880_DTV_BW_5_MHZ:
+ case CXD2880_DTV_BW_6_MHZ:
+ case CXD2880_DTV_BW_7_MHZ:
+ case CXD2880_DTV_BW_8_MHZ:
+ *offset = -1 * ((*offset) * tnr_dmd->bandwidth / 940);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
+ cxd2880_tnrdmd
+ *tnr_dmd,
+ int *offset)
+{
+ if (!tnr_dmd || !offset)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ return cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub,
+ offset);
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_dvbt2_l1pre
+ *l1_pre)
+{
+ u8 data[37];
+ u8 sync_state = 0;
+ u8 ts_lock = 0;
+ u8 unlock_detected = 0;
+ u8 version = 0;
+ enum cxd2880_dvbt2_profile profile;
+ int ret;
+
+ if (!tnr_dmd || !l1_pre)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+ &ts_lock,
+ &unlock_detected);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (sync_state < 5) {
+ if (tnr_dmd->diver_mode ==
+ CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
+ (tnr_dmd, &sync_state, &unlock_detected);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (sync_state < 5) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+ } else {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+ }
+
+ ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x61, data, sizeof(data));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+ slvt_unfreeze_reg(tnr_dmd);
+
+ l1_pre->type = (enum cxd2880_dvbt2_l1pre_type)data[0];
+ l1_pre->bw_ext = data[1] & 0x01;
+ l1_pre->s1 = (enum cxd2880_dvbt2_s1)(data[2] & 0x07);
+ l1_pre->s2 = data[3] & 0x0f;
+ l1_pre->l1_rep = data[4] & 0x01;
+ l1_pre->gi = (enum cxd2880_dvbt2_guard)(data[5] & 0x07);
+ l1_pre->papr = (enum cxd2880_dvbt2_papr)(data[6] & 0x0f);
+ l1_pre->mod =
+ (enum cxd2880_dvbt2_l1post_constell)(data[7] & 0x0f);
+ l1_pre->cr = (enum cxd2880_dvbt2_l1post_cr)(data[8] & 0x03);
+ l1_pre->fec =
+ (enum cxd2880_dvbt2_l1post_fec_type)(data[9] & 0x03);
+ l1_pre->l1_post_size = (data[10] & 0x03) << 16;
+ l1_pre->l1_post_size |= (data[11]) << 8;
+ l1_pre->l1_post_size |= (data[12]);
+ l1_pre->l1_post_info_size = (data[13] & 0x03) << 16;
+ l1_pre->l1_post_info_size |= (data[14]) << 8;
+ l1_pre->l1_post_info_size |= (data[15]);
+ l1_pre->pp = (enum cxd2880_dvbt2_pp)(data[16] & 0x0f);
+ l1_pre->tx_id_availability = data[17];
+ l1_pre->cell_id = (data[18] << 8);
+ l1_pre->cell_id |= (data[19]);
+ l1_pre->network_id = (data[20] << 8);
+ l1_pre->network_id |= (data[21]);
+ l1_pre->sys_id = (data[22] << 8);
+ l1_pre->sys_id |= (data[23]);
+ l1_pre->num_frames = data[24];
+ l1_pre->num_symbols = (data[25] & 0x0f) << 8;
+ l1_pre->num_symbols |= data[26];
+ l1_pre->regen = data[27] & 0x07;
+ l1_pre->post_ext = data[28] & 0x01;
+ l1_pre->num_rf_freqs = data[29] & 0x07;
+ l1_pre->rf_idx = data[30] & 0x07;
+ version = (data[31] & 0x03) << 2;
+ version |= (data[32] & 0xc0) >> 6;
+ l1_pre->t2_version = (enum cxd2880_dvbt2_version)version;
+ l1_pre->l1_post_scrambled = (data[32] & 0x20) >> 5;
+ l1_pre->t2_base_lite = (data[32] & 0x10) >> 4;
+ l1_pre->crc32 = (data[33] << 24);
+ l1_pre->crc32 |= (data[34] << 16);
+ l1_pre->crc32 |= (data[35] << 8);
+ l1_pre->crc32 |= data[36];
+
+ if (profile == CXD2880_DVBT2_PROFILE_BASE) {
+ switch ((l1_pre->s2 >> 1)) {
+ case CXD2880_DVBT2_BASE_S2_M1K_G_ANY:
+ l1_pre->fft_mode = CXD2880_DVBT2_M1K;
+ break;
+ case CXD2880_DVBT2_BASE_S2_M2K_G_ANY:
+ l1_pre->fft_mode = CXD2880_DVBT2_M2K;
+ break;
+ case CXD2880_DVBT2_BASE_S2_M4K_G_ANY:
+ l1_pre->fft_mode = CXD2880_DVBT2_M4K;
+ break;
+ case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT:
+ case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2:
+ l1_pre->fft_mode = CXD2880_DVBT2_M8K;
+ break;
+ case CXD2880_DVBT2_BASE_S2_M16K_G_ANY:
+ l1_pre->fft_mode = CXD2880_DVBT2_M16K;
+ break;
+ case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT:
+ case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2:
+ l1_pre->fft_mode = CXD2880_DVBT2_M32K;
+ break;
+ default:
+ return -EAGAIN;
+ }
+ } else if (profile == CXD2880_DVBT2_PROFILE_LITE) {
+ switch ((l1_pre->s2 >> 1)) {
+ case CXD2880_DVBT2_LITE_S2_M2K_G_ANY:
+ l1_pre->fft_mode = CXD2880_DVBT2_M2K;
+ break;
+ case CXD2880_DVBT2_LITE_S2_M4K_G_ANY:
+ l1_pre->fft_mode = CXD2880_DVBT2_M4K;
+ break;
+ case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT:
+ case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2:
+ l1_pre->fft_mode = CXD2880_DVBT2_M8K;
+ break;
+ case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT:
+ case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2:
+ l1_pre->fft_mode = CXD2880_DVBT2_M16K;
+ break;
+ default:
+ return -EAGAIN;
+ }
+ } else {
+ return -EAGAIN;
+ }
+
+ l1_pre->mixed = l1_pre->s2 & 0x01;
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dvbt2_version
+ *ver)
+{
+ u8 data[2];
+ u8 sync_state = 0;
+ u8 ts_lock = 0;
+ u8 unlock_detected = 0;
+ u8 version = 0;
+ int ret;
+
+ if (!tnr_dmd || !ver)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+ &ts_lock,
+ &unlock_detected);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (sync_state < 5) {
+ if (tnr_dmd->diver_mode ==
+ CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
+ (tnr_dmd, &sync_state, &unlock_detected);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (sync_state < 5) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+ } else {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x80, data, sizeof(data));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ version = ((data[0] & 0x03) << 2);
+ version |= ((data[1] & 0xc0) >> 6);
+ *ver = (enum cxd2880_dvbt2_version)version;
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_dvbt2_ofdm *ofdm)
+{
+ u8 data[5];
+ u8 sync_state = 0;
+ u8 ts_lock = 0;
+ u8 unlock_detected = 0;
+ int ret;
+
+ if (!tnr_dmd || !ofdm)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+ &ts_lock,
+ &unlock_detected);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (sync_state != 6) {
+ slvt_unfreeze_reg(tnr_dmd);
+
+ ret = -EAGAIN;
+
+ if (tnr_dmd->diver_mode ==
+ CXD2880_TNRDMD_DIVERMODE_MAIN)
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd->diver_sub,
+ ofdm);
+
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x1d, data, sizeof(data));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ ofdm->mixed = ((data[0] & 0x20) ? 1 : 0);
+ ofdm->is_miso = ((data[0] & 0x10) >> 4);
+ ofdm->mode = (enum cxd2880_dvbt2_mode)(data[0] & 0x07);
+ ofdm->gi = (enum cxd2880_dvbt2_guard)((data[1] & 0x70) >> 4);
+ ofdm->pp = (enum cxd2880_dvbt2_pp)(data[1] & 0x07);
+ ofdm->bw_ext = (data[2] & 0x10) >> 4;
+ ofdm->papr = (enum cxd2880_dvbt2_papr)(data[2] & 0x0f);
+ ofdm->num_symbols = (data[3] << 8) | data[4];
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 *plp_ids,
+ u8 *num_plps)
+{
+ u8 l1_post_ok = 0;
+ int ret;
+
+ if (!tnr_dmd || !num_plps)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret)
+ return ret;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x86, &l1_post_ok, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (!(l1_post_ok & 0x01)) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xc1, num_plps, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (*num_plps == 0) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EINVAL;
+ }
+
+ if (!plp_ids) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return 0;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xc2,
+ plp_ids,
+ ((*num_plps > 62) ?
+ 62 : *num_plps));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (*num_plps > 62) {
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0c);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x10, plp_ids + 62,
+ *num_plps - 62);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_dvbt2_plp_btype
+ type,
+ struct cxd2880_dvbt2_plp
+ *plp_info)
+{
+ u8 data[20];
+ u8 addr = 0;
+ u8 index = 0;
+ u8 l1_post_ok = 0;
+ int ret;
+
+ if (!tnr_dmd || !plp_info)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x86, &l1_post_ok, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (!l1_post_ok) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ if (type == CXD2880_DVBT2_PLP_COMMON)
+ addr = 0xa9;
+ else
+ addr = 0x96;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ addr, data, sizeof(data));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ if (type == CXD2880_DVBT2_PLP_COMMON && !data[13])
+ return -EAGAIN;
+
+ plp_info->id = data[index++];
+ plp_info->type =
+ (enum cxd2880_dvbt2_plp_type)(data[index++] & 0x07);
+ plp_info->payload =
+ (enum cxd2880_dvbt2_plp_payload)(data[index++] & 0x1f);
+ plp_info->ff = data[index++] & 0x01;
+ plp_info->first_rf_idx = data[index++] & 0x07;
+ plp_info->first_frm_idx = data[index++];
+ plp_info->group_id = data[index++];
+ plp_info->plp_cr =
+ (enum cxd2880_dvbt2_plp_code_rate)(data[index++] & 0x07);
+ plp_info->constell =
+ (enum cxd2880_dvbt2_plp_constell)(data[index++] & 0x07);
+ plp_info->rot = data[index++] & 0x01;
+ plp_info->fec =
+ (enum cxd2880_dvbt2_plp_fec)(data[index++] & 0x03);
+ plp_info->num_blocks_max = (data[index++] & 0x03) << 8;
+ plp_info->num_blocks_max |= data[index++];
+ plp_info->frm_int = data[index++];
+ plp_info->til_len = data[index++];
+ plp_info->til_type = data[index++] & 0x01;
+
+ plp_info->in_band_a_flag = data[index++] & 0x01;
+ plp_info->rsvd = data[index++] << 8;
+ plp_info->rsvd |= data[index++];
+
+ plp_info->in_band_b_flag =
+ (plp_info->rsvd & 0x8000) >> 15;
+ plp_info->plp_mode =
+ (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000c) >> 2);
+ plp_info->static_flag = (plp_info->rsvd & 0x0002) >> 1;
+ plp_info->static_padding_flag = plp_info->rsvd & 0x0001;
+ plp_info->rsvd = (plp_info->rsvd & 0x7ff0) >> 4;
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ u8 *plp_error)
+{
+ u8 data;
+ int ret;
+
+ if (!tnr_dmd || !plp_error)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x86, &data, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if ((data & 0x01) == 0x00) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xc0, &data, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ *plp_error = data & 0x01;
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 *l1_change)
+{
+ u8 data;
+ u8 sync_state = 0;
+ u8 ts_lock = 0;
+ u8 unlock_detected = 0;
+ int ret;
+
+ if (!tnr_dmd || !l1_change)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+ &ts_lock,
+ &unlock_detected);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (sync_state < 5) {
+ if (tnr_dmd->diver_mode ==
+ CXD2880_TNRDMD_DIVERMODE_MAIN) {
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
+ (tnr_dmd, &sync_state, &unlock_detected);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (sync_state < 5) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+ } else {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x5f, &data, sizeof(data));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ *l1_change = data & 0x01;
+ if (*l1_change) {
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x22);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x16, 0x01);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+ }
+ slvt_unfreeze_reg(tnr_dmd);
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ struct cxd2880_dvbt2_l1post
+ *l1_post)
+{
+ u8 data[16];
+ int ret;
+
+ if (!tnr_dmd || !l1_post)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x86, data, sizeof(data));
+ if (ret)
+ return ret;
+
+ if (!(data[0] & 0x01))
+ return -EAGAIN;
+
+ l1_post->sub_slices_per_frame = (data[1] & 0x7f) << 8;
+ l1_post->sub_slices_per_frame |= data[2];
+ l1_post->num_plps = data[3];
+ l1_post->num_aux = data[4] & 0x0f;
+ l1_post->aux_cfg_rfu = data[5];
+ l1_post->rf_idx = data[6] & 0x07;
+ l1_post->freq = data[7] << 24;
+ l1_post->freq |= data[8] << 16;
+ l1_post->freq |= data[9] << 8;
+ l1_post->freq |= data[10];
+ l1_post->fef_type = data[11] & 0x0f;
+ l1_post->fef_length = data[12] << 16;
+ l1_post->fef_length |= data[13] << 8;
+ l1_post->fef_length |= data[14];
+ l1_post->fef_intvl = data[15];
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dvbt2_plp_btype
+ type,
+ struct cxd2880_dvbt2_bbheader
+ *bbheader)
+{
+ u8 sync_state = 0;
+ u8 ts_lock = 0;
+ u8 unlock_detected = 0;
+ u8 data[14];
+ u8 addr = 0;
+ int ret;
+
+ if (!tnr_dmd || !bbheader)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+ &ts_lock,
+ &unlock_detected);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (!ts_lock) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (type == CXD2880_DVBT2_PLP_COMMON) {
+ u8 l1_post_ok;
+ u8 data;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x86, &l1_post_ok, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (!(l1_post_ok & 0x01)) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xb6, &data, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (data == 0) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+ }
+
+ if (type == CXD2880_DVBT2_PLP_COMMON)
+ addr = 0x51;
+ else
+ addr = 0x42;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ addr, data, sizeof(data));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ bbheader->stream_input =
+ (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03);
+ bbheader->is_single_input_stream = (data[0] >> 5) & 0x01;
+ bbheader->is_constant_coding_modulation =
+ (data[0] >> 4) & 0x01;
+ bbheader->issy_indicator = (data[0] >> 3) & 0x01;
+ bbheader->null_packet_deletion = (data[0] >> 2) & 0x01;
+ bbheader->ext = data[0] & 0x03;
+
+ bbheader->input_stream_identifier = data[1];
+ bbheader->plp_mode =
+ (data[3] & 0x01) ? CXD2880_DVBT2_PLP_MODE_HEM :
+ CXD2880_DVBT2_PLP_MODE_NM;
+ bbheader->data_field_length = (data[4] << 8) | data[5];
+
+ if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) {
+ bbheader->user_packet_length =
+ (data[6] << 8) | data[7];
+ bbheader->sync_byte = data[8];
+ bbheader->issy = 0;
+ } else {
+ bbheader->user_packet_length = 0;
+ bbheader->sync_byte = 0;
+ bbheader->issy =
+ (data[11] << 16) | (data[12] << 8) | data[13];
+ }
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_dvbt2_plp_btype
+ type,
+ u32 *ts_rate_bps)
+{
+ u8 sync_state = 0;
+ u8 ts_lock = 0;
+ u8 unlock_detected = 0;
+ u8 l1_post_ok = 0;
+ u8 data[4];
+ u8 addr = 0;
+
+ int ret;
+
+ if (!tnr_dmd || !ts_rate_bps)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+ &ts_lock,
+ &unlock_detected);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (!ts_lock) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x86, &l1_post_ok, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (!(l1_post_ok & 0x01)) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ if (type == CXD2880_DVBT2_PLP_COMMON)
+ addr = 0xba;
+ else
+ addr = 0xa7;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ addr, &data[0], 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if ((data[0] & 0x80) == 0x00) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x25);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (type == CXD2880_DVBT2_PLP_COMMON)
+ addr = 0xa6;
+ else
+ addr = 0xaa;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ addr, &data[0], 4);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ *ts_rate_bps = ((data[0] & 0x07) << 24) | (data[1] << 16) |
+ (data[2] << 8) | data[3];
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_tnrdmd_spectrum_sense
+ *sense)
+{
+ u8 sync_state = 0;
+ u8 ts_lock = 0;
+ u8 early_unlock = 0;
+ u8 data = 0;
+ int ret;
+
+ if (!tnr_dmd || !sense)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock,
+ &early_unlock);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (sync_state != 6) {
+ slvt_unfreeze_reg(tnr_dmd);
+
+ ret = -EAGAIN;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(tnr_dmd->diver_sub,
+ sense);
+
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x2f, &data, sizeof(data));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ *sense =
+ (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
+ CXD2880_TNRDMD_SPECTRUM_NORMAL;
+
+ return 0;
+}
+
+static int dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
+ u16 *reg_value)
+{
+ u8 sync_state = 0;
+ u8 ts_lock = 0;
+ u8 unlock_detected = 0;
+ u8 data[2];
+ int ret;
+
+ if (!tnr_dmd || !reg_value)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+ &ts_lock,
+ &unlock_detected);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (sync_state != 6) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x13, data, sizeof(data));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ *reg_value = (data[0] << 8) | data[1];
+
+ return ret;
+}
+
+static int dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
+ u32 reg_value, int *snr)
+{
+ if (!tnr_dmd || !snr)
+ return -EINVAL;
+
+ if (reg_value == 0)
+ return -EAGAIN;
+
+ if (reg_value > 10876)
+ reg_value = 10876;
+
+ *snr = intlog10(reg_value) - intlog10(12600 - reg_value);
+ *snr = (*snr + 839) / 1678 + 32000;
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+ int *snr)
+{
+ u16 reg_value = 0;
+ int ret;
+
+ if (!tnr_dmd || !snr)
+ return -EINVAL;
+
+ *snr = -1000 * 1000;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+ ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
+ if (ret)
+ return ret;
+
+ ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr);
+ } else {
+ int snr_main = 0;
+ int snr_sub = 0;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_snr_diver(tnr_dmd, snr, &snr_main,
+ &snr_sub);
+ }
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
+ *tnr_dmd, int *snr,
+ int *snr_main, int *snr_sub)
+{
+ u16 reg_value = 0;
+ u32 reg_value_sum = 0;
+ int ret;
+
+ if (!tnr_dmd || !snr || !snr_main || !snr_sub)
+ return -EINVAL;
+
+ *snr = -1000 * 1000;
+ *snr_main = -1000 * 1000;
+ *snr_sub = -1000 * 1000;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
+ if (!ret) {
+ ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr_main);
+ if (ret)
+ reg_value = 0;
+ } else if (ret == -EAGAIN) {
+ reg_value = 0;
+ } else {
+ return ret;
+ }
+
+ reg_value_sum += reg_value;
+
+ ret = dvbt2_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
+ if (!ret) {
+ ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
+ if (ret)
+ reg_value = 0;
+ } else if (ret == -EAGAIN) {
+ reg_value = 0;
+ } else {
+ return ret;
+ }
+
+ reg_value_sum += reg_value;
+
+ return dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr);
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
+ cxd2880_tnrdmd
+ *tnr_dmd,
+ u32 *pen)
+{
+ int ret;
+ u8 data[3];
+
+ if (!tnr_dmd || !pen)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x39, data, sizeof(data));
+ if (ret)
+ return ret;
+
+ if (!(data[0] & 0x01))
+ return -EAGAIN;
+
+ *pen = ((data[1] << 8) | data[2]);
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
+ *tnr_dmd, int *ppm)
+{
+ u8 ctl_val_reg[5];
+ u8 nominal_rate_reg[5];
+ u32 trl_ctl_val = 0;
+ u32 trcg_nominal_rate = 0;
+ int num;
+ int den;
+ int ret;
+ u8 sync_state = 0;
+ u8 ts_lock = 0;
+ u8 unlock_detected = 0;
+ s8 diff_upper = 0;
+
+ if (!tnr_dmd || !ppm)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+ &ts_lock,
+ &unlock_detected);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (sync_state != 6) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x34, ctl_val_reg,
+ sizeof(ctl_val_reg));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x04);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x10, nominal_rate_reg,
+ sizeof(nominal_rate_reg));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ diff_upper =
+ (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
+
+ if (diff_upper < -1 || diff_upper > 1)
+ return -EAGAIN;
+
+ trl_ctl_val = ctl_val_reg[1] << 24;
+ trl_ctl_val |= ctl_val_reg[2] << 16;
+ trl_ctl_val |= ctl_val_reg[3] << 8;
+ trl_ctl_val |= ctl_val_reg[4];
+
+ trcg_nominal_rate = nominal_rate_reg[1] << 24;
+ trcg_nominal_rate |= nominal_rate_reg[2] << 16;
+ trcg_nominal_rate |= nominal_rate_reg[3] << 8;
+ trcg_nominal_rate |= nominal_rate_reg[4];
+
+ trl_ctl_val >>= 1;
+ trcg_nominal_rate >>= 1;
+
+ if (diff_upper == 1)
+ num =
+ (int)((trl_ctl_val + 0x80000000u) -
+ trcg_nominal_rate);
+ else if (diff_upper == -1)
+ num =
+ -(int)((trcg_nominal_rate + 0x80000000u) -
+ trl_ctl_val);
+ else
+ num = (int)(trl_ctl_val - trcg_nominal_rate);
+
+ den = (nominal_rate_reg[0] & 0x7f) << 24;
+ den |= nominal_rate_reg[1] << 16;
+ den |= nominal_rate_reg[2] << 8;
+ den |= nominal_rate_reg[3];
+ den = (den + (390625 / 2)) / 390625;
+
+ den >>= 1;
+
+ if (num >= 0)
+ *ppm = (num + (den / 2)) / den;
+ else
+ *ppm = (num - (den / 2)) / den;
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
+ cxd2880_tnrdmd
+ *tnr_dmd,
+ int *ppm)
+{
+ if (!tnr_dmd || !ppm)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ return cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub,
+ ppm);
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_dvbt2_plp_btype type,
+ enum cxd2880_dvbt2_plp_constell *qam)
+{
+ u8 data;
+ u8 l1_post_ok = 0;
+ int ret;
+
+ if (!tnr_dmd || !qam)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x86, &l1_post_ok, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (!(l1_post_ok & 0x01)) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ if (type == CXD2880_DVBT2_PLP_COMMON) {
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xb6, &data, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (data == 0) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xb1, &data, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+ } else {
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x9e, &data, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ *qam = (enum cxd2880_dvbt2_plp_constell)(data & 0x07);
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dvbt2_plp_btype
+ type,
+ enum
+ cxd2880_dvbt2_plp_code_rate
+ *code_rate)
+{
+ u8 data;
+ u8 l1_post_ok = 0;
+ int ret;
+
+ if (!tnr_dmd || !code_rate)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x86, &l1_post_ok, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (!(l1_post_ok & 0x01)) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ if (type == CXD2880_DVBT2_PLP_COMMON) {
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xb6, &data, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ if (data == 0) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return -EAGAIN;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xb0, &data, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+ } else {
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x9d, &data, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ *code_rate = (enum cxd2880_dvbt2_plp_code_rate)(data & 0x07);
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dvbt2_profile
+ *profile)
+{
+ u8 data;
+ int ret;
+
+ if (!tnr_dmd || !profile)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x22, &data, sizeof(data));
+ if (ret)
+ return ret;
+
+ if (data & 0x02) {
+ if (data & 0x01)
+ *profile = CXD2880_DVBT2_PROFILE_LITE;
+ else
+ *profile = CXD2880_DVBT2_PROFILE_BASE;
+ } else {
+ ret = -EAGAIN;
+ if (tnr_dmd->diver_mode ==
+ CXD2880_TNRDMD_DIVERMODE_MAIN)
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd->diver_sub,
+ profile);
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dvbt2_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+ int rf_lvl, u8 *ssi)
+{
+ enum cxd2880_dvbt2_plp_constell qam;
+ enum cxd2880_dvbt2_plp_code_rate code_rate;
+ int prel;
+ int temp_ssi = 0;
+ int ret;
+
+ if (!tnr_dmd || !ssi)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam);
+ if (ret)
+ return ret;
+
+ ret =
+ cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA,
+ &code_rate);
+ if (ret)
+ return ret;
+
+ if (code_rate > CXD2880_DVBT2_R2_5 || qam > CXD2880_DVBT2_QAM256)
+ return -EINVAL;
+
+ prel = rf_lvl - ref_dbm_1000[qam][code_rate];
+
+ if (prel < -15000)
+ temp_ssi = 0;
+ else if (prel < 0)
+ temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
+ else if (prel < 20000)
+ temp_ssi = (((4 * prel) + 500) / 1000) + 10;
+ else if (prel < 35000)
+ temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
+ else
+ temp_ssi = 100;
+
+ *ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 *ssi)
+{
+ int rf_lvl = 0;
+ int ret;
+
+ if (!tnr_dmd || !ssi)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
+ if (ret)
+ return ret;
+
+ return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 *ssi)
+{
+ int rf_lvl = 0;
+ int ret;
+
+ if (!tnr_dmd || !ssi)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
+ if (ret)
+ return ret;
+
+ return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
new file mode 100644
index 000000000000..5b7adaceff22
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_tnrdmd_dvbt2_mon.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T2 monitor interface
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT2_MON_H
+#define CXD2880_TNRDMD_DVBT2_MON_H
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_dvbt2.h"
+
+int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 *sync_stat,
+ u8 *ts_lock_stat,
+ u8 *unlock_detected);
+
+int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ u8 *sync_stat,
+ u8 *unlock_detected);
+
+int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
+ *tnr_dmd, int *offset);
+
+int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
+ cxd2880_tnrdmd
+ *tnr_dmd,
+ int *offset);
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_dvbt2_l1pre
+ *l1_pre);
+
+int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dvbt2_version
+ *ver);
+
+int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_dvbt2_ofdm *ofdm);
+
+int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 *plp_ids,
+ u8 *num_plps);
+
+int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_dvbt2_plp_btype
+ type,
+ struct cxd2880_dvbt2_plp
+ *plp_info);
+
+int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ u8 *plp_error);
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 *l1_change);
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ struct cxd2880_dvbt2_l1post
+ *l1_post);
+
+int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dvbt2_plp_btype
+ type,
+ struct cxd2880_dvbt2_bbheader
+ *bbheader);
+
+int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_dvbt2_plp_btype
+ type,
+ u32 *ts_rate_bps);
+
+int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_tnrdmd_spectrum_sense
+ *sense);
+
+int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+ int *snr);
+
+int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
+ *tnr_dmd, int *snr,
+ int *snr_main,
+ int *snr_sub);
+
+int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
+ cxd2880_tnrdmd
+ *tnr_dmd,
+ u32 *pen);
+
+int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
+ *tnr_dmd, int *ppm);
+
+int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
+ cxd2880_tnrdmd
+ *tnr_dmd,
+ int *ppm);
+
+int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
+ enum cxd2880_dvbt2_plp_btype type,
+ enum cxd2880_dvbt2_plp_constell
+ *qam);
+
+int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dvbt2_plp_btype
+ type,
+ enum
+ cxd2880_dvbt2_plp_code_rate
+ *code_rate);
+
+int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dvbt2_profile
+ *profile);
+
+int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 *ssi);
+
+int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 *ssi);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
new file mode 100644
index 000000000000..fedc3b4a2fa0
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
@@ -0,0 +1,775 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cxd2880_tnrdmd_dvbt_mon.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T monitor functions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_tnrdmd_dvbt_mon.h"
+
+#include <media/dvb_math.h>
+
+static const int ref_dbm_1000[3][5] = {
+ {-93000, -91000, -90000, -89000, -88000},
+ {-87000, -85000, -84000, -83000, -82000},
+ {-82000, -80000, -78000, -77000, -76000},
+};
+
+static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 *sync_stat,
+ u8 *ts_lock_stat,
+ u8 *unlock_detected)
+{
+ u8 rdata = 0x00;
+ int ret;
+
+ if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0d);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x10, &rdata, 1);
+ if (ret)
+ return ret;
+
+ *unlock_detected = (rdata & 0x10) ? 1 : 0;
+ *sync_stat = rdata & 0x07;
+ *ts_lock_stat = (rdata & 0x20) ? 1 : 0;
+
+ if (*sync_stat == 0x07)
+ return -EAGAIN;
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 *sync_stat,
+ u8 *unlock_detected)
+{
+ u8 ts_lock_stat = 0;
+
+ if (!tnr_dmd || !sync_stat || !unlock_detected)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ return cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub,
+ sync_stat,
+ &ts_lock_stat,
+ unlock_detected);
+}
+
+int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dvbt_mode
+ *mode,
+ enum cxd2880_dvbt_guard
+ *guard)
+{
+ u8 rdata = 0x00;
+ int ret;
+
+ if (!tnr_dmd || !mode || !guard)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret = is_tps_locked(tnr_dmd);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+ ret =
+ cxd2880_tnrdmd_dvbt_mon_mode_guard(tnr_dmd->diver_sub,
+ mode, guard);
+
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0d);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x1b, &rdata, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ *mode = (enum cxd2880_dvbt_mode)((rdata >> 2) & 0x03);
+ *guard = (enum cxd2880_dvbt_guard)(rdata & 0x03);
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
+ *tnr_dmd, int *offset)
+{
+ u8 rdata[4];
+ u32 ctl_val = 0;
+ int ret;
+
+ if (!tnr_dmd || !offset)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret = is_tps_locked(tnr_dmd);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0d);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x1d, rdata, 4);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ ctl_val =
+ ((rdata[0] & 0x1f) << 24) | (rdata[1] << 16) | (rdata[2] << 8) |
+ (rdata[3]);
+ *offset = cxd2880_convert2s_complement(ctl_val, 29);
+ *offset = -1 * ((*offset) * tnr_dmd->bandwidth / 235);
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
+ cxd2880_tnrdmd
+ *tnr_dmd,
+ int *offset)
+{
+ if (!tnr_dmd || !offset)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ return cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub,
+ offset);
+}
+
+int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ struct cxd2880_dvbt_tpsinfo
+ *info)
+{
+ u8 rdata[7];
+ u8 cell_id_ok = 0;
+ int ret;
+
+ if (!tnr_dmd || !info)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret = is_tps_locked(tnr_dmd);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+ ret =
+ cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd->diver_sub,
+ info);
+
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0d);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x29, rdata, 7);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x11);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xd5, &cell_id_ok, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ info->constellation =
+ (enum cxd2880_dvbt_constellation)((rdata[0] >> 6) & 0x03);
+ info->hierarchy = (enum cxd2880_dvbt_hierarchy)((rdata[0] >> 3) & 0x07);
+ info->rate_hp = (enum cxd2880_dvbt_coderate)(rdata[0] & 0x07);
+ info->rate_lp = (enum cxd2880_dvbt_coderate)((rdata[1] >> 5) & 0x07);
+ info->guard = (enum cxd2880_dvbt_guard)((rdata[1] >> 3) & 0x03);
+ info->mode = (enum cxd2880_dvbt_mode)((rdata[1] >> 1) & 0x03);
+ info->fnum = (rdata[2] >> 6) & 0x03;
+ info->length_indicator = rdata[2] & 0x3f;
+ info->cell_id = (rdata[3] << 8) | rdata[4];
+ info->reserved_even = rdata[5] & 0x3f;
+ info->reserved_odd = rdata[6] & 0x3f;
+
+ info->cell_id_ok = cell_id_ok & 0x01;
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
+ cxd2880_tnrdmd
+ *tnr_dmd,
+ u32 *pen)
+{
+ u8 rdata[3];
+ int ret;
+
+ if (!tnr_dmd || !pen)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0d);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x26, rdata, 3);
+ if (ret)
+ return ret;
+
+ if (!(rdata[0] & 0x01))
+ return -EAGAIN;
+
+ *pen = (rdata[1] << 8) | rdata[2];
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_tnrdmd_spectrum_sense
+ *sense)
+{
+ u8 data = 0;
+ int ret;
+
+ if (!tnr_dmd || !sense)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret = is_tps_locked(tnr_dmd);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+ ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(tnr_dmd->diver_sub,
+ sense);
+
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0d);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x1c, &data, sizeof(data));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ *sense =
+ (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
+ CXD2880_TNRDMD_SPECTRUM_NORMAL;
+
+ return ret;
+}
+
+static int dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
+ u16 *reg_value)
+{
+ u8 rdata[2];
+ int ret;
+
+ if (!tnr_dmd || !reg_value)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret = is_tps_locked(tnr_dmd);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0d);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x13, rdata, 2);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ *reg_value = (rdata[0] << 8) | rdata[1];
+
+ return ret;
+}
+
+static int dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
+ u32 reg_value, int *snr)
+{
+ if (!tnr_dmd || !snr)
+ return -EINVAL;
+
+ if (reg_value == 0)
+ return -EAGAIN;
+
+ if (reg_value > 4996)
+ reg_value = 4996;
+
+ *snr = intlog10(reg_value) - intlog10(5350 - reg_value);
+ *snr = (*snr + 839) / 1678 + 28500;
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+ int *snr)
+{
+ u16 reg_value = 0;
+ int ret;
+
+ if (!tnr_dmd || !snr)
+ return -EINVAL;
+
+ *snr = -1000 * 1000;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+ ret = dvbt_read_snr_reg(tnr_dmd, &reg_value);
+ if (ret)
+ return ret;
+
+ ret = dvbt_calc_snr(tnr_dmd, reg_value, snr);
+ } else {
+ int snr_main = 0;
+ int snr_sub = 0;
+
+ ret =
+ cxd2880_tnrdmd_dvbt_mon_snr_diver(tnr_dmd, snr, &snr_main,
+ &snr_sub);
+ }
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
+ *tnr_dmd, int *snr,
+ int *snr_main, int *snr_sub)
+{
+ u16 reg_value = 0;
+ u32 reg_value_sum = 0;
+ int ret;
+
+ if (!tnr_dmd || !snr || !snr_main || !snr_sub)
+ return -EINVAL;
+
+ *snr = -1000 * 1000;
+ *snr_main = -1000 * 1000;
+ *snr_sub = -1000 * 1000;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+ return -EINVAL;
+
+ ret = dvbt_read_snr_reg(tnr_dmd, &reg_value);
+ if (!ret) {
+ ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main);
+ if (ret)
+ reg_value = 0;
+ } else if (ret == -EAGAIN) {
+ reg_value = 0;
+ } else {
+ return ret;
+ }
+
+ reg_value_sum += reg_value;
+
+ ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
+ if (!ret) {
+ ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
+ if (ret)
+ reg_value = 0;
+ } else if (ret == -EAGAIN) {
+ reg_value = 0;
+ } else {
+ return ret;
+ }
+
+ reg_value_sum += reg_value;
+
+ return dvbt_calc_snr(tnr_dmd, reg_value_sum, snr);
+}
+
+int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
+ *tnr_dmd, int *ppm)
+{
+ u8 ctl_val_reg[5];
+ u8 nominal_rate_reg[5];
+ u32 trl_ctl_val = 0;
+ u32 trcg_nominal_rate = 0;
+ int num;
+ int den;
+ s8 diff_upper = 0;
+ int ret;
+
+ if (!tnr_dmd || !ppm)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnr_dmd);
+ if (ret)
+ return ret;
+
+ ret = is_tps_locked(tnr_dmd);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0d);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x21, ctl_val_reg,
+ sizeof(ctl_val_reg));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x04);
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x60, nominal_rate_reg,
+ sizeof(nominal_rate_reg));
+ if (ret) {
+ slvt_unfreeze_reg(tnr_dmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnr_dmd);
+
+ diff_upper =
+ (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
+
+ if (diff_upper < -1 || diff_upper > 1)
+ return -EAGAIN;
+
+ trl_ctl_val = ctl_val_reg[1] << 24;
+ trl_ctl_val |= ctl_val_reg[2] << 16;
+ trl_ctl_val |= ctl_val_reg[3] << 8;
+ trl_ctl_val |= ctl_val_reg[4];
+
+ trcg_nominal_rate = nominal_rate_reg[1] << 24;
+ trcg_nominal_rate |= nominal_rate_reg[2] << 16;
+ trcg_nominal_rate |= nominal_rate_reg[3] << 8;
+ trcg_nominal_rate |= nominal_rate_reg[4];
+
+ trl_ctl_val >>= 1;
+ trcg_nominal_rate >>= 1;
+
+ if (diff_upper == 1)
+ num =
+ (int)((trl_ctl_val + 0x80000000u) -
+ trcg_nominal_rate);
+ else if (diff_upper == -1)
+ num =
+ -(int)((trcg_nominal_rate + 0x80000000u) -
+ trl_ctl_val);
+ else
+ num = (int)(trl_ctl_val - trcg_nominal_rate);
+
+ den = (nominal_rate_reg[0] & 0x7f) << 24;
+ den |= nominal_rate_reg[1] << 16;
+ den |= nominal_rate_reg[2] << 8;
+ den |= nominal_rate_reg[3];
+ den = (den + (390625 / 2)) / 390625;
+
+ den >>= 1;
+
+ if (num >= 0)
+ *ppm = (num + (den / 2)) / den;
+ else
+ *ppm = (num - (den / 2)) / den;
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
+ cxd2880_tnrdmd
+ *tnr_dmd, int *ppm)
+{
+ if (!tnr_dmd || !ppm)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ return cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm);
+}
+
+static int dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+ int rf_lvl, u8 *ssi)
+{
+ struct cxd2880_dvbt_tpsinfo tps;
+ int prel;
+ int temp_ssi = 0;
+ int ret;
+
+ if (!tnr_dmd || !ssi)
+ return -EINVAL;
+
+ ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps);
+ if (ret)
+ return ret;
+
+ if (tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3 ||
+ tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5)
+ return -EINVAL;
+
+ prel = rf_lvl - ref_dbm_1000[tps.constellation][tps.rate_hp];
+
+ if (prel < -15000)
+ temp_ssi = 0;
+ else if (prel < 0)
+ temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
+ else if (prel < 20000)
+ temp_ssi = (((4 * prel) + 500) / 1000) + 10;
+ else if (prel < 35000)
+ temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
+ else
+ temp_ssi = 100;
+
+ *ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 *ssi)
+{
+ int rf_lvl = 0;
+ int ret;
+
+ if (!tnr_dmd || !ssi)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+ return -EINVAL;
+
+ ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
+ if (ret)
+ return ret;
+
+ return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
+}
+
+int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 *ssi)
+{
+ int rf_lvl = 0;
+ int ret;
+
+ if (!tnr_dmd || !ssi)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+ return -EINVAL;
+
+ ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
+ if (ret)
+ return ret;
+
+ return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
+}
+
+static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd)
+{
+ u8 sync = 0;
+ u8 tslock = 0;
+ u8 early_unlock = 0;
+ int ret;
+
+ if (!tnr_dmd)
+ return -EINVAL;
+
+ ret =
+ cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock,
+ &early_unlock);
+ if (ret)
+ return ret;
+
+ if (sync != 6)
+ return -EAGAIN;
+
+ return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
new file mode 100644
index 000000000000..f4c31725fa48
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_tnrdmd_dvbt_mon.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T monitor interface
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT_MON_H
+#define CXD2880_TNRDMD_DVBT_MON_H
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_dvbt.h"
+
+int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 *sync_stat,
+ u8 *ts_lock_stat,
+ u8 *unlock_detected);
+
+int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
+ *tnr_dmd, u8 *sync_stat,
+ u8 *unlock_detected);
+
+int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum cxd2880_dvbt_mode
+ *mode,
+ enum cxd2880_dvbt_guard
+ *guard);
+
+int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
+ *tnr_dmd, int *offset);
+
+int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
+ cxd2880_tnrdmd
+ *tnr_dmd,
+ int *offset);
+
+int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ struct cxd2880_dvbt_tpsinfo
+ *info);
+
+int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
+ cxd2880_tnrdmd
+ *tnr_dmd,
+ u32 *pen);
+
+int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
+ *tnr_dmd,
+ enum
+ cxd2880_tnrdmd_spectrum_sense
+ *sense);
+
+int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+ int *snr);
+
+int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
+ *tnr_dmd, int *snr,
+ int *snr_main, int *snr_sub);
+
+int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
+ *tnr_dmd, int *ppm);
+
+int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
+ cxd2880_tnrdmd
+ *tnr_dmd,
+ int *ppm);
+
+int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 *ssi);
+
+int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
+ u8 *ssi);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
new file mode 100644
index 000000000000..3d8012c18e3f
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cxd2880_tnrdmd_mon.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common monitor functions
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd_mon.h"
+
+static const u8 rf_lvl_seq[2] = {
+ 0x80, 0x00,
+};
+
+int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
+ int *rf_lvl_db)
+{
+ u8 rdata[2];
+ int ret;
+
+ if (!tnr_dmd || !rf_lvl_db)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x10, 0x01);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x10);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x5b, rf_lvl_seq, 2);
+ if (ret)
+ return ret;
+
+ usleep_range(2000, 3000);
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x1a);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x15, rdata, 2);
+ if (ret)
+ return ret;
+
+ if (rdata[0] || rdata[1])
+ return -EINVAL;
+
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x11, rdata, 2);
+ if (ret)
+ return ret;
+
+ *rf_lvl_db =
+ cxd2880_convert2s_complement((rdata[0] << 3) |
+ ((rdata[1] & 0xe0) >> 5), 11);
+
+ *rf_lvl_db *= 125;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x00);
+ if (ret)
+ return ret;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x10, 0x00);
+ if (ret)
+ return ret;
+
+ if (tnr_dmd->rf_lvl_cmpstn)
+ ret = tnr_dmd->rf_lvl_cmpstn(tnr_dmd, rf_lvl_db);
+
+ return ret;
+}
+
+int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
+ int *rf_lvl_db)
+{
+ if (!tnr_dmd || !rf_lvl_db)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ return cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, rf_lvl_db);
+}
+
+int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
+ *tnr_dmd, u16 *status)
+{
+ u8 data[2] = { 0 };
+ int ret;
+
+ if (!tnr_dmd || !status)
+ return -EINVAL;
+
+ ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x00, 0x1a);
+ if (ret)
+ return ret;
+ ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+ CXD2880_IO_TGT_SYS,
+ 0x15, data, 2);
+ if (ret)
+ return ret;
+
+ *status = (data[0] << 8) | data[1];
+
+ return 0;
+}
+
+int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
+ cxd2880_tnrdmd
+ *tnr_dmd,
+ u16 *status)
+{
+ if (!tnr_dmd || !status)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+ return -EINVAL;
+
+ return cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd->diver_sub,
+ status);
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
new file mode 100644
index 000000000000..570360925f87
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * cxd2880_tnrdmd_mon.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common monitor interface
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#ifndef CXD2880_TNRDMD_MON_H
+#define CXD2880_TNRDMD_MON_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+
+int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
+ int *rf_lvl_db);
+
+int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
+ int *rf_lvl_db);
+
+int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
+ *tnr_dmd, u16 *status);
+
+int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
+ cxd2880_tnrdmd
+ *tnr_dmd,
+ u16 *status);
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
new file mode 100644
index 000000000000..d474dc1b05da
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
@@ -0,0 +1,1947 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cxd2880_top.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
+
+#include <linux/spi/spi.h>
+
+#include <media/dvb_frontend.h>
+#include <media/dvb_math.h>
+
+#include "cxd2880.h"
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+#include "cxd2880_tnrdmd_dvbt_mon.h"
+#include "cxd2880_integ.h"
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_devio_spi.h"
+#include "cxd2880_spi_device.h"
+#include "cxd2880_tnrdmd_driver_version.h"
+
+struct cxd2880_priv {
+ struct cxd2880_tnrdmd tnrdmd;
+ struct spi_device *spi;
+ struct cxd2880_io regio;
+ struct cxd2880_spi_device spi_device;
+ struct cxd2880_spi cxd2880_spi;
+ struct cxd2880_dvbt_tune_param dvbt_tune_param;
+ struct cxd2880_dvbt2_tune_param dvbt2_tune_param;
+ struct mutex *spi_mutex; /* For SPI access exclusive control */
+ unsigned long pre_ber_update;
+ unsigned long pre_ber_interval;
+ unsigned long post_ber_update;
+ unsigned long post_ber_interval;
+ unsigned long ucblock_update;
+ unsigned long ucblock_interval;
+ enum fe_status s;
+};
+
+static int cxd2880_pre_bit_err_t(struct cxd2880_tnrdmd *tnrdmd,
+ u32 *pre_bit_err, u32 *pre_bit_count)
+{
+ u8 rdata[2];
+ int ret;
+
+ if (!tnrdmd || !pre_bit_err || !pre_bit_count)
+ return -EINVAL;
+
+ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnrdmd);
+ if (ret)
+ return ret;
+
+ ret = tnrdmd->io->write_reg(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x10);
+ if (ret) {
+ slvt_unfreeze_reg(tnrdmd);
+ return ret;
+ }
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x39, rdata, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnrdmd);
+ return ret;
+ }
+
+ if ((rdata[0] & 0x01) == 0) {
+ slvt_unfreeze_reg(tnrdmd);
+ return -EAGAIN;
+ }
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x22, rdata, 2);
+ if (ret) {
+ slvt_unfreeze_reg(tnrdmd);
+ return ret;
+ }
+
+ *pre_bit_err = (rdata[0] << 8) | rdata[1];
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x6f, rdata, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnrdmd);
+ return ret;
+ }
+
+ slvt_unfreeze_reg(tnrdmd);
+
+ *pre_bit_count = ((rdata[0] & 0x07) == 0) ?
+ 256 : (0x1000 << (rdata[0] & 0x07));
+
+ return 0;
+}
+
+static int cxd2880_pre_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd,
+ u32 *pre_bit_err,
+ u32 *pre_bit_count)
+{
+ u32 period_exp = 0;
+ u32 n_ldpc = 0;
+ u8 data[5];
+ int ret;
+
+ if (!tnrdmd || !pre_bit_err || !pre_bit_count)
+ return -EINVAL;
+
+ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnrdmd);
+ if (ret)
+ return ret;
+
+ ret = tnrdmd->io->write_reg(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnrdmd);
+ return ret;
+ }
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x3c, data, sizeof(data));
+ if (ret) {
+ slvt_unfreeze_reg(tnrdmd);
+ return ret;
+ }
+
+ if (!(data[0] & 0x01)) {
+ slvt_unfreeze_reg(tnrdmd);
+ return -EAGAIN;
+ }
+ *pre_bit_err =
+ ((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xa0, data, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnrdmd);
+ return ret;
+ }
+
+ if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) ==
+ CXD2880_DVBT2_FEC_LDPC_16K)
+ n_ldpc = 16200;
+ else
+ n_ldpc = 64800;
+ slvt_unfreeze_reg(tnrdmd);
+
+ ret = tnrdmd->io->write_reg(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x20);
+ if (ret)
+ return ret;
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x6f, data, 1);
+ if (ret)
+ return ret;
+
+ period_exp = data[0] & 0x0f;
+
+ *pre_bit_count = (1U << period_exp) * n_ldpc;
+
+ return 0;
+}
+
+static int cxd2880_post_bit_err_t(struct cxd2880_tnrdmd *tnrdmd,
+ u32 *post_bit_err,
+ u32 *post_bit_count)
+{
+ u8 rdata[3];
+ u32 bit_error = 0;
+ u32 period_exp = 0;
+ int ret;
+
+ if (!tnrdmd || !post_bit_err || !post_bit_count)
+ return -EINVAL;
+
+ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
+ return -EINVAL;
+
+ ret = tnrdmd->io->write_reg(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0d);
+ if (ret)
+ return ret;
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x15, rdata, 3);
+ if (ret)
+ return ret;
+
+ if ((rdata[0] & 0x40) == 0)
+ return -EAGAIN;
+
+ *post_bit_err = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2];
+
+ ret = tnrdmd->io->write_reg(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x10);
+ if (ret)
+ return ret;
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x60, rdata, 1);
+ if (ret)
+ return ret;
+
+ period_exp = (rdata[0] & 0x1f);
+
+ if (period_exp <= 11 && (bit_error > (1U << period_exp) * 204 * 8))
+ return -EAGAIN;
+
+ *post_bit_count = (1U << period_exp) * 204 * 8;
+
+ return 0;
+}
+
+static int cxd2880_post_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd,
+ u32 *post_bit_err,
+ u32 *post_bit_count)
+{
+ u32 period_exp = 0;
+ u32 n_bch = 0;
+ u8 data[3];
+ enum cxd2880_dvbt2_plp_fec plp_fec_type =
+ CXD2880_DVBT2_FEC_LDPC_16K;
+ enum cxd2880_dvbt2_plp_code_rate plp_code_rate =
+ CXD2880_DVBT2_R1_2;
+ int ret;
+ static const u16 n_bch_bits_lookup[2][8] = {
+ {7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480},
+ {32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920}
+ };
+
+ if (!tnrdmd || !post_bit_err || !post_bit_count)
+ return -EINVAL;
+
+ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = slvt_freeze_reg(tnrdmd);
+ if (ret)
+ return ret;
+
+ ret = tnrdmd->io->write_reg(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret) {
+ slvt_unfreeze_reg(tnrdmd);
+ return ret;
+ }
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x15, data, 3);
+ if (ret) {
+ slvt_unfreeze_reg(tnrdmd);
+ return ret;
+ }
+
+ if (!(data[0] & 0x40)) {
+ slvt_unfreeze_reg(tnrdmd);
+ return -EAGAIN;
+ }
+
+ *post_bit_err =
+ ((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2];
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x9d, data, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnrdmd);
+ return ret;
+ }
+
+ plp_code_rate =
+ (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07);
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xa0, data, 1);
+ if (ret) {
+ slvt_unfreeze_reg(tnrdmd);
+ return ret;
+ }
+
+ plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03);
+
+ slvt_unfreeze_reg(tnrdmd);
+
+ ret = tnrdmd->io->write_reg(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x20);
+ if (ret)
+ return ret;
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x72, data, 1);
+ if (ret)
+ return ret;
+
+ period_exp = data[0] & 0x0f;
+
+ if (plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K ||
+ plp_code_rate > CXD2880_DVBT2_R2_5)
+ return -EAGAIN;
+
+ n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate];
+
+ if (*post_bit_err > ((1U << period_exp) * n_bch))
+ return -EAGAIN;
+
+ *post_bit_count = (1U << period_exp) * n_bch;
+
+ return 0;
+}
+
+static int cxd2880_read_block_err_t(struct cxd2880_tnrdmd *tnrdmd,
+ u32 *block_err,
+ u32 *block_count)
+{
+ u8 rdata[3];
+ int ret;
+
+ if (!tnrdmd || !block_err || !block_count)
+ return -EINVAL;
+
+ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
+ return -EINVAL;
+
+ ret = tnrdmd->io->write_reg(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0d);
+ if (ret)
+ return ret;
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x18, rdata, 3);
+ if (ret)
+ return ret;
+
+ if ((rdata[0] & 0x01) == 0)
+ return -EAGAIN;
+
+ *block_err = (rdata[1] << 8) | rdata[2];
+
+ ret = tnrdmd->io->write_reg(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x10);
+ if (ret)
+ return ret;
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x5c, rdata, 1);
+ if (ret)
+ return ret;
+
+ *block_count = 1U << (rdata[0] & 0x0f);
+
+ if ((*block_count == 0) || (*block_err > *block_count))
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int cxd2880_read_block_err_t2(struct cxd2880_tnrdmd *tnrdmd,
+ u32 *block_err,
+ u32 *block_count)
+{
+ u8 rdata[3];
+ int ret;
+
+ if (!tnrdmd || !block_err || !block_count)
+ return -EINVAL;
+
+ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
+ return -EINVAL;
+
+ ret = tnrdmd->io->write_reg(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x0b);
+ if (ret)
+ return ret;
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x18, rdata, 3);
+ if (ret)
+ return ret;
+
+ if ((rdata[0] & 0x01) == 0)
+ return -EAGAIN;
+
+ *block_err = (rdata[1] << 8) | rdata[2];
+
+ ret = tnrdmd->io->write_reg(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x24);
+ if (ret)
+ return ret;
+
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0xdc, rdata, 1);
+ if (ret)
+ return ret;
+
+ *block_count = 1U << (rdata[0] & 0x0f);
+
+ if ((*block_count == 0) || (*block_err > *block_count))
+ return -EAGAIN;
+
+ return 0;
+}
+
+static void cxd2880_release(struct dvb_frontend *fe)
+{
+ struct cxd2880_priv *priv = NULL;
+
+ if (!fe) {
+ pr_err("invalid arg.\n");
+ return;
+ }
+ priv = fe->demodulator_priv;
+ kfree(priv);
+}
+
+static int cxd2880_init(struct dvb_frontend *fe)
+{
+ int ret;
+ struct cxd2880_priv *priv = NULL;
+ struct cxd2880_tnrdmd_create_param create_param;
+
+ if (!fe) {
+ pr_err("invalid arg.\n");
+ return -EINVAL;
+ }
+
+ priv = fe->demodulator_priv;
+
+ create_param.ts_output_if = CXD2880_TNRDMD_TSOUT_IF_SPI;
+ create_param.xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_NONE;
+ create_param.en_internal_ldo = 1;
+ create_param.xosc_cap = 18;
+ create_param.xosc_i = 8;
+ create_param.stationary_use = 1;
+
+ mutex_lock(priv->spi_mutex);
+ if (priv->tnrdmd.io != &priv->regio) {
+ ret = cxd2880_tnrdmd_create(&priv->tnrdmd,
+ &priv->regio, &create_param);
+ if (ret) {
+ mutex_unlock(priv->spi_mutex);
+ pr_info("cxd2880 tnrdmd create failed %d\n", ret);
+ return ret;
+ }
+ }
+ ret = cxd2880_integ_init(&priv->tnrdmd);
+ if (ret) {
+ mutex_unlock(priv->spi_mutex);
+ pr_err("cxd2880 integ init failed %d\n", ret);
+ return ret;
+ }
+ mutex_unlock(priv->spi_mutex);
+
+ pr_debug("OK.\n");
+
+ return ret;
+}
+
+static int cxd2880_sleep(struct dvb_frontend *fe)
+{
+ int ret;
+ struct cxd2880_priv *priv = NULL;
+
+ if (!fe) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ priv = fe->demodulator_priv;
+
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_tnrdmd_sleep(&priv->tnrdmd);
+ mutex_unlock(priv->spi_mutex);
+
+ pr_debug("tnrdmd_sleep ret %d\n", ret);
+
+ return ret;
+}
+
+static int cxd2880_read_signal_strength(struct dvb_frontend *fe,
+ u16 *strength)
+{
+ int ret;
+ struct cxd2880_priv *priv = NULL;
+ struct dtv_frontend_properties *c = NULL;
+ int level = 0;
+
+ if (!fe || !strength) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ priv = fe->demodulator_priv;
+ c = &fe->dtv_property_cache;
+
+ mutex_lock(priv->spi_mutex);
+ if (c->delivery_system == SYS_DVBT ||
+ c->delivery_system == SYS_DVBT2) {
+ ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &level);
+ } else {
+ pr_debug("invalid system\n");
+ mutex_unlock(priv->spi_mutex);
+ return -EINVAL;
+ }
+ mutex_unlock(priv->spi_mutex);
+
+ level /= 125;
+ /*
+ * level should be between -105dBm and -30dBm.
+ * E.g. they should be between:
+ * -105000/125 = -840 and -30000/125 = -240
+ */
+ level = clamp(level, -840, -240);
+ /* scale value to 0x0000-0xffff */
+ *strength = ((level + 840) * 0xffff) / (-240 + 840);
+
+ if (ret)
+ pr_debug("ret = %d\n", ret);
+
+ return ret;
+}
+
+static int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ int ret;
+ int snrvalue = 0;
+ struct cxd2880_priv *priv = NULL;
+ struct dtv_frontend_properties *c = NULL;
+
+ if (!fe || !snr) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ priv = fe->demodulator_priv;
+ c = &fe->dtv_property_cache;
+
+ mutex_lock(priv->spi_mutex);
+ if (c->delivery_system == SYS_DVBT) {
+ ret = cxd2880_tnrdmd_dvbt_mon_snr(&priv->tnrdmd,
+ &snrvalue);
+ } else if (c->delivery_system == SYS_DVBT2) {
+ ret = cxd2880_tnrdmd_dvbt2_mon_snr(&priv->tnrdmd,
+ &snrvalue);
+ } else {
+ pr_err("invalid system\n");
+ mutex_unlock(priv->spi_mutex);
+ return -EINVAL;
+ }
+ mutex_unlock(priv->spi_mutex);
+
+ if (snrvalue < 0)
+ snrvalue = 0;
+ *snr = snrvalue;
+
+ if (ret)
+ pr_debug("ret = %d\n", ret);
+
+ return ret;
+}
+
+static int cxd2880_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ int ret;
+ struct cxd2880_priv *priv = NULL;
+ struct dtv_frontend_properties *c = NULL;
+
+ if (!fe || !ucblocks) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ priv = fe->demodulator_priv;
+ c = &fe->dtv_property_cache;
+
+ mutex_lock(priv->spi_mutex);
+ if (c->delivery_system == SYS_DVBT) {
+ ret = cxd2880_tnrdmd_dvbt_mon_packet_error_number(&priv->tnrdmd,
+ ucblocks);
+ } else if (c->delivery_system == SYS_DVBT2) {
+ ret = cxd2880_tnrdmd_dvbt2_mon_packet_error_number(&priv->tnrdmd,
+ ucblocks);
+ } else {
+ pr_err("invalid system\n");
+ mutex_unlock(priv->spi_mutex);
+ return -EINVAL;
+ }
+ mutex_unlock(priv->spi_mutex);
+
+ if (ret)
+ pr_debug("ret = %d\n", ret);
+
+ return ret;
+}
+
+static int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ *ber = 0;
+
+ return 0;
+}
+
+static int cxd2880_set_ber_per_period_t(struct dvb_frontend *fe)
+{
+ int ret;
+ struct cxd2880_priv *priv;
+ struct cxd2880_dvbt_tpsinfo info;
+ enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
+ u32 pre_ber_rate = 0;
+ u32 post_ber_rate = 0;
+ u32 ucblock_rate = 0;
+ u32 mes_exp = 0;
+ static const int cr_table[5] = {31500, 42000, 47250, 52500, 55125};
+ static const int denominator_tbl[4] = {125664, 129472, 137088, 152320};
+
+ if (!fe) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ priv = fe->demodulator_priv;
+ bw = priv->dvbt_tune_param.bandwidth;
+
+ ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd,
+ &info);
+ if (ret) {
+ pr_err("tps monitor error ret = %d\n", ret);
+ info.hierarchy = CXD2880_DVBT_HIERARCHY_NON;
+ info.constellation = CXD2880_DVBT_CONSTELLATION_QPSK;
+ info.guard = CXD2880_DVBT_GUARD_1_4;
+ info.rate_hp = CXD2880_DVBT_CODERATE_1_2;
+ info.rate_lp = CXD2880_DVBT_CODERATE_1_2;
+ }
+
+ if (info.hierarchy == CXD2880_DVBT_HIERARCHY_NON) {
+ pre_ber_rate = 63000000 * bw * (info.constellation * 2 + 2) /
+ denominator_tbl[info.guard];
+
+ post_ber_rate = 1000 * cr_table[info.rate_hp] * bw *
+ (info.constellation * 2 + 2) /
+ denominator_tbl[info.guard];
+
+ ucblock_rate = 875 * cr_table[info.rate_hp] * bw *
+ (info.constellation * 2 + 2) /
+ denominator_tbl[info.guard];
+ } else {
+ u8 data = 0;
+ struct cxd2880_tnrdmd *tnrdmd = &priv->tnrdmd;
+
+ ret = tnrdmd->io->write_reg(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x00, 0x10);
+ if (!ret) {
+ ret = tnrdmd->io->read_regs(tnrdmd->io,
+ CXD2880_IO_TGT_DMD,
+ 0x67, &data, 1);
+ if (ret)
+ data = 0x00;
+ } else {
+ data = 0x00;
+ }
+
+ if (data & 0x01) { /* Low priority */
+ pre_ber_rate =
+ 63000000 * bw * (info.constellation * 2 + 2) /
+ denominator_tbl[info.guard];
+
+ post_ber_rate = 1000 * cr_table[info.rate_lp] * bw *
+ (info.constellation * 2 + 2) /
+ denominator_tbl[info.guard];
+
+ ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_lp] *
+ bw * (info.constellation * 2 + 2) /
+ denominator_tbl[info.guard];
+ } else { /* High priority */
+ pre_ber_rate =
+ 63000000 * bw * 2 / denominator_tbl[info.guard];
+
+ post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * 2 /
+ denominator_tbl[info.guard];
+
+ ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_hp] *
+ bw * 2 / denominator_tbl[info.guard];
+ }
+ }
+
+ mes_exp = pre_ber_rate < 8192 ? 8 : intlog2(pre_ber_rate) >> 24;
+ priv->pre_ber_interval =
+ ((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) /
+ pre_ber_rate;
+ cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+ CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD,
+ mes_exp == 8 ? 0 : mes_exp - 12);
+
+ mes_exp = intlog2(post_ber_rate) >> 24;
+ priv->post_ber_interval =
+ ((1U << mes_exp) * 1000 + (post_ber_rate / 2)) /
+ post_ber_rate;
+ cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+ CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD,
+ mes_exp);
+
+ mes_exp = intlog2(ucblock_rate) >> 24;
+ priv->ucblock_interval =
+ ((1U << mes_exp) * 1000 + (ucblock_rate / 2)) /
+ ucblock_rate;
+ cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+ CXD2880_TNRDMD_CFG_DVBT_PER_MES,
+ mes_exp);
+
+ return 0;
+}
+
+static int cxd2880_set_ber_per_period_t2(struct dvb_frontend *fe)
+{
+ int ret;
+ struct cxd2880_priv *priv;
+ struct cxd2880_dvbt2_l1pre l1pre;
+ struct cxd2880_dvbt2_l1post l1post;
+ struct cxd2880_dvbt2_plp plp;
+ struct cxd2880_dvbt2_bbheader bbheader;
+ enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
+ u32 pre_ber_rate = 0;
+ u32 post_ber_rate = 0;
+ u32 ucblock_rate = 0;
+ u32 mes_exp = 0;
+ u32 term_a = 0;
+ u32 term_b = 0;
+ u32 denominator = 0;
+ static const u32 gi_tbl[7] = {32, 64, 128, 256, 8, 152, 76};
+ static const u8 n_tbl[6] = {8, 2, 4, 16, 1, 1};
+ static const u8 mode_tbl[6] = {2, 8, 4, 1, 16, 32};
+ static const u32 kbch_tbl[2][8] = {
+ {6952, 9472, 10552, 11632, 12352, 13072, 5152, 6232},
+ {32128, 38608, 42960, 48328, 51568, 53760, 0, 0}
+ };
+
+ if (!fe) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ priv = fe->demodulator_priv;
+ bw = priv->dvbt2_tune_param.bandwidth;
+
+ ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre);
+ if (ret) {
+ pr_info("l1 pre error\n");
+ goto error_ber_setting;
+ }
+
+ ret = cxd2880_tnrdmd_dvbt2_mon_active_plp(&priv->tnrdmd,
+ CXD2880_DVBT2_PLP_DATA, &plp);
+ if (ret) {
+ pr_info("plp info error\n");
+ goto error_ber_setting;
+ }
+
+ ret = cxd2880_tnrdmd_dvbt2_mon_l1_post(&priv->tnrdmd, &l1post);
+ if (ret) {
+ pr_info("l1 post error\n");
+ goto error_ber_setting;
+ }
+
+ term_a =
+ (mode_tbl[l1pre.fft_mode] * (1024 + gi_tbl[l1pre.gi])) *
+ (l1pre.num_symbols + n_tbl[l1pre.fft_mode]) + 2048;
+
+ if (l1pre.mixed && l1post.fef_intvl) {
+ term_b = (l1post.fef_length + (l1post.fef_intvl / 2)) /
+ l1post.fef_intvl;
+ } else {
+ term_b = 0;
+ }
+
+ switch (bw) {
+ case CXD2880_DTV_BW_1_7_MHZ:
+ denominator = ((term_a + term_b) * 71 + (131 / 2)) / 131;
+ break;
+ case CXD2880_DTV_BW_5_MHZ:
+ denominator = ((term_a + term_b) * 7 + 20) / 40;
+ break;
+ case CXD2880_DTV_BW_6_MHZ:
+ denominator = ((term_a + term_b) * 7 + 24) / 48;
+ break;
+ case CXD2880_DTV_BW_7_MHZ:
+ denominator = ((term_a + term_b) + 4) / 8;
+ break;
+ case CXD2880_DTV_BW_8_MHZ:
+ default:
+ denominator = ((term_a + term_b) * 7 + 32) / 64;
+ break;
+ }
+
+ if (plp.til_type && plp.til_len) {
+ pre_ber_rate =
+ (plp.num_blocks_max * 1000000 + (denominator / 2)) /
+ denominator;
+ pre_ber_rate = (pre_ber_rate + (plp.til_len / 2)) /
+ plp.til_len;
+ } else {
+ pre_ber_rate =
+ (plp.num_blocks_max * 1000000 + (denominator / 2)) /
+ denominator;
+ }
+
+ post_ber_rate = pre_ber_rate;
+
+ mes_exp = intlog2(pre_ber_rate) >> 24;
+ priv->pre_ber_interval =
+ ((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) /
+ pre_ber_rate;
+ cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+ CXD2880_TNRDMD_CFG_DVBT2_LBER_MES,
+ mes_exp);
+
+ mes_exp = intlog2(post_ber_rate) >> 24;
+ priv->post_ber_interval =
+ ((1U << mes_exp) * 1000 + (post_ber_rate / 2)) /
+ post_ber_rate;
+ cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+ CXD2880_TNRDMD_CFG_DVBT2_BBER_MES,
+ mes_exp);
+
+ ret = cxd2880_tnrdmd_dvbt2_mon_bbheader(&priv->tnrdmd,
+ CXD2880_DVBT2_PLP_DATA,
+ &bbheader);
+ if (ret) {
+ pr_info("bb header error\n");
+ goto error_ucblock_setting;
+ }
+
+ if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_NM) {
+ if (!bbheader.issy_indicator) {
+ ucblock_rate =
+ (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] +
+ 752) / 1504;
+ } else {
+ ucblock_rate =
+ (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] +
+ 764) / 1528;
+ }
+ } else if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_HEM) {
+ ucblock_rate =
+ (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + 748) /
+ 1496;
+ } else {
+ pr_info("plp mode is not Normal or HEM\n");
+ goto error_ucblock_setting;
+ }
+
+ mes_exp = intlog2(ucblock_rate) >> 24;
+ priv->ucblock_interval =
+ ((1U << mes_exp) * 1000 + (ucblock_rate / 2)) /
+ ucblock_rate;
+ cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+ CXD2880_TNRDMD_CFG_DVBT2_PER_MES,
+ mes_exp);
+
+ return 0;
+
+error_ber_setting:
+ priv->pre_ber_interval = 1000;
+ cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+ CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, 0);
+
+ priv->post_ber_interval = 1000;
+ cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+ CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, 0);
+
+error_ucblock_setting:
+ priv->ucblock_interval = 1000;
+ cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+ CXD2880_TNRDMD_CFG_DVBT2_PER_MES, 8);
+
+ return 0;
+}
+
+static int cxd2880_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_dvbt_tune_param
+ *tune_param)
+{
+ int ret;
+
+ if (!tnr_dmd || !tune_param)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ atomic_set(&tnr_dmd->cancel, 0);
+
+ if (tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ &&
+ tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ &&
+ tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ &&
+ tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ) {
+ return -ENOTTY;
+ }
+
+ ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param);
+ if (ret)
+ return ret;
+
+ usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000,
+ CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000);
+
+ return cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param);
+}
+
+static int cxd2880_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd,
+ struct cxd2880_dvbt2_tune_param
+ *tune_param)
+{
+ int ret;
+
+ if (!tnr_dmd || !tune_param)
+ return -EINVAL;
+
+ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+ return -EINVAL;
+
+ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
+ tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+ return -EINVAL;
+
+ atomic_set(&tnr_dmd->cancel, 0);
+
+ if (tune_param->bandwidth != CXD2880_DTV_BW_1_7_MHZ &&
+ tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ &&
+ tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ &&
+ tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ &&
+ tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ) {
+ return -ENOTTY;
+ }
+
+ if (tune_param->profile != CXD2880_DVBT2_PROFILE_BASE &&
+ tune_param->profile != CXD2880_DVBT2_PROFILE_LITE)
+ return -EINVAL;
+
+ ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param);
+ if (ret)
+ return ret;
+
+ usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000,
+ CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000);
+
+ return cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param);
+}
+
+static int cxd2880_set_frontend(struct dvb_frontend *fe)
+{
+ int ret;
+ struct dtv_frontend_properties *c;
+ struct cxd2880_priv *priv;
+ enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
+
+ if (!fe) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ priv = fe->demodulator_priv;
+ c = &fe->dtv_property_cache;
+
+ c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_error.stat[0].uvalue = 0;
+ c->pre_bit_error.len = 1;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_count.stat[0].uvalue = 0;
+ c->pre_bit_count.len = 1;
+ c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_error.stat[0].uvalue = 0;
+ c->post_bit_error.len = 1;
+ c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[0].uvalue = 0;
+ c->post_bit_count.len = 1;
+ c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_error.stat[0].uvalue = 0;
+ c->block_error.len = 1;
+ c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[0].uvalue = 0;
+ c->block_count.len = 1;
+
+ switch (c->bandwidth_hz) {
+ case 1712000:
+ bw = CXD2880_DTV_BW_1_7_MHZ;
+ break;
+ case 5000000:
+ bw = CXD2880_DTV_BW_5_MHZ;
+ break;
+ case 6000000:
+ bw = CXD2880_DTV_BW_6_MHZ;
+ break;
+ case 7000000:
+ bw = CXD2880_DTV_BW_7_MHZ;
+ break;
+ case 8000000:
+ bw = CXD2880_DTV_BW_8_MHZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ priv->s = 0;
+
+ pr_info("sys:%d freq:%d bw:%d\n",
+ c->delivery_system, c->frequency, bw);
+ mutex_lock(priv->spi_mutex);
+ if (c->delivery_system == SYS_DVBT) {
+ priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT;
+ priv->dvbt_tune_param.center_freq_khz = c->frequency / 1000;
+ priv->dvbt_tune_param.bandwidth = bw;
+ priv->dvbt_tune_param.profile = CXD2880_DVBT_PROFILE_HP;
+ ret = cxd2880_dvbt_tune(&priv->tnrdmd,
+ &priv->dvbt_tune_param);
+ } else if (c->delivery_system == SYS_DVBT2) {
+ priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT2;
+ priv->dvbt2_tune_param.center_freq_khz = c->frequency / 1000;
+ priv->dvbt2_tune_param.bandwidth = bw;
+ priv->dvbt2_tune_param.data_plp_id = (u16)c->stream_id;
+ priv->dvbt2_tune_param.profile = CXD2880_DVBT2_PROFILE_BASE;
+ ret = cxd2880_dvbt2_tune(&priv->tnrdmd,
+ &priv->dvbt2_tune_param);
+ } else {
+ pr_err("invalid system\n");
+ mutex_unlock(priv->spi_mutex);
+ return -EINVAL;
+ }
+ mutex_unlock(priv->spi_mutex);
+
+ pr_info("tune result %d\n", ret);
+
+ return ret;
+}
+
+static int cxd2880_get_stats(struct dvb_frontend *fe,
+ enum fe_status status)
+{
+ struct cxd2880_priv *priv = NULL;
+ struct dtv_frontend_properties *c = NULL;
+ u32 pre_bit_err = 0, pre_bit_count = 0;
+ u32 post_bit_err = 0, post_bit_count = 0;
+ u32 block_err = 0, block_count = 0;
+ int ret;
+
+ if (!fe) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ priv = fe->demodulator_priv;
+ c = &fe->dtv_property_cache;
+
+ if (!(status & FE_HAS_LOCK)) {
+ c->pre_bit_error.len = 1;
+ c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_count.len = 1;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_error.len = 1;
+ 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;
+ c->block_error.len = 1;
+ c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.len = 1;
+ c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+ return 0;
+ }
+
+ if (time_after(jiffies, priv->pre_ber_update)) {
+ priv->pre_ber_update =
+ jiffies + msecs_to_jiffies(priv->pre_ber_interval);
+ if (c->delivery_system == SYS_DVBT) {
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_pre_bit_err_t(&priv->tnrdmd,
+ &pre_bit_err,
+ &pre_bit_count);
+ mutex_unlock(priv->spi_mutex);
+ } else if (c->delivery_system == SYS_DVBT2) {
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_pre_bit_err_t2(&priv->tnrdmd,
+ &pre_bit_err,
+ &pre_bit_count);
+ mutex_unlock(priv->spi_mutex);
+ } else {
+ return -EINVAL;
+ }
+
+ if (!ret) {
+ c->pre_bit_error.len = 1;
+ c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_error.stat[0].uvalue += pre_bit_err;
+ c->pre_bit_count.len = 1;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_count.stat[0].uvalue += pre_bit_count;
+ } else {
+ c->pre_bit_error.len = 1;
+ c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_count.len = 1;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ pr_debug("pre_bit_error_t failed %d\n", ret);
+ }
+ }
+
+ if (time_after(jiffies, priv->post_ber_update)) {
+ priv->post_ber_update =
+ jiffies + msecs_to_jiffies(priv->post_ber_interval);
+ if (c->delivery_system == SYS_DVBT) {
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_post_bit_err_t(&priv->tnrdmd,
+ &post_bit_err,
+ &post_bit_count);
+ mutex_unlock(priv->spi_mutex);
+ } else if (c->delivery_system == SYS_DVBT2) {
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_post_bit_err_t2(&priv->tnrdmd,
+ &post_bit_err,
+ &post_bit_count);
+ mutex_unlock(priv->spi_mutex);
+ } else {
+ return -EINVAL;
+ }
+
+ if (!ret) {
+ c->post_bit_error.len = 1;
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue += post_bit_err;
+ c->post_bit_count.len = 1;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].uvalue += post_bit_count;
+ } else {
+ c->post_bit_error.len = 1;
+ 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;
+ pr_debug("post_bit_err_t %d\n", ret);
+ }
+ }
+
+ if (time_after(jiffies, priv->ucblock_update)) {
+ priv->ucblock_update =
+ jiffies + msecs_to_jiffies(priv->ucblock_interval);
+ if (c->delivery_system == SYS_DVBT) {
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_read_block_err_t(&priv->tnrdmd,
+ &block_err,
+ &block_count);
+ mutex_unlock(priv->spi_mutex);
+ } else if (c->delivery_system == SYS_DVBT2) {
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_read_block_err_t2(&priv->tnrdmd,
+ &block_err,
+ &block_count);
+ mutex_unlock(priv->spi_mutex);
+ } else {
+ return -EINVAL;
+ }
+ if (!ret) {
+ c->block_error.len = 1;
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[0].uvalue += block_err;
+ c->block_count.len = 1;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].uvalue += block_count;
+ } else {
+ c->block_error.len = 1;
+ c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.len = 1;
+ c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ pr_debug("read_block_err_t %d\n", ret);
+ }
+ }
+
+ return 0;
+}
+
+static int cxd2880_check_l1post_plp(struct dvb_frontend *fe)
+{
+ u8 valid = 0;
+ u8 plp_not_found;
+ int ret;
+ struct cxd2880_priv *priv = NULL;
+
+ if (!fe) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ priv = fe->demodulator_priv;
+
+ ret = cxd2880_tnrdmd_dvbt2_check_l1post_valid(&priv->tnrdmd,
+ &valid);
+ if (ret)
+ return ret;
+
+ if (!valid)
+ return -EAGAIN;
+
+ ret = cxd2880_tnrdmd_dvbt2_mon_data_plp_error(&priv->tnrdmd,
+ &plp_not_found);
+ if (ret)
+ return ret;
+
+ if (plp_not_found) {
+ priv->dvbt2_tune_param.tune_info =
+ CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID;
+ } else {
+ priv->dvbt2_tune_param.tune_info =
+ CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK;
+ }
+
+ return 0;
+}
+
+static int cxd2880_read_status(struct dvb_frontend *fe,
+ enum fe_status *status)
+{
+ int ret;
+ u8 sync = 0;
+ u8 lock = 0;
+ u8 unlock = 0;
+ struct cxd2880_priv *priv = NULL;
+ struct dtv_frontend_properties *c = NULL;
+
+ if (!fe || !status) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ priv = fe->demodulator_priv;
+ c = &fe->dtv_property_cache;
+ *status = 0;
+
+ if (priv->tnrdmd.state == CXD2880_TNRDMD_STATE_ACTIVE) {
+ mutex_lock(priv->spi_mutex);
+ if (c->delivery_system == SYS_DVBT) {
+ ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(&priv->tnrdmd,
+ &sync,
+ &lock,
+ &unlock);
+ } else if (c->delivery_system == SYS_DVBT2) {
+ ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat(&priv->tnrdmd,
+ &sync,
+ &lock,
+ &unlock);
+ } else {
+ pr_err("invalid system");
+ mutex_unlock(priv->spi_mutex);
+ return -EINVAL;
+ }
+
+ mutex_unlock(priv->spi_mutex);
+ if (ret) {
+ pr_err("failed. sys = %d\n", priv->tnrdmd.sys);
+ return ret;
+ }
+
+ if (sync == 6) {
+ *status = FE_HAS_SIGNAL |
+ FE_HAS_CARRIER;
+ }
+ if (lock)
+ *status |= FE_HAS_VITERBI |
+ FE_HAS_SYNC |
+ FE_HAS_LOCK;
+ }
+
+ pr_debug("status %d\n", *status);
+
+ if (priv->s == 0 && (*status & FE_HAS_LOCK)) {
+ mutex_lock(priv->spi_mutex);
+ if (c->delivery_system == SYS_DVBT) {
+ ret = cxd2880_set_ber_per_period_t(fe);
+ priv->s = *status;
+ } else if (c->delivery_system == SYS_DVBT2) {
+ ret = cxd2880_check_l1post_plp(fe);
+ if (!ret) {
+ ret = cxd2880_set_ber_per_period_t2(fe);
+ priv->s = *status;
+ }
+ } else {
+ pr_err("invalid system\n");
+ mutex_unlock(priv->spi_mutex);
+ return -EINVAL;
+ }
+ mutex_unlock(priv->spi_mutex);
+ }
+
+ cxd2880_get_stats(fe, *status);
+ return 0;
+}
+
+static int cxd2880_tune(struct dvb_frontend *fe,
+ bool retune,
+ unsigned int mode_flags,
+ unsigned int *delay,
+ enum fe_status *status)
+{
+ int ret;
+
+ if (!fe || !delay || !status) {
+ pr_err("invalid arg.");
+ return -EINVAL;
+ }
+
+ if (retune) {
+ ret = cxd2880_set_frontend(fe);
+ if (ret) {
+ pr_err("cxd2880_set_frontend failed %d\n", ret);
+ return ret;
+ }
+ }
+
+ *delay = HZ / 5;
+
+ return cxd2880_read_status(fe, status);
+}
+
+static int cxd2880_get_frontend_t(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
+{
+ int ret;
+ struct cxd2880_priv *priv = NULL;
+ enum cxd2880_dvbt_mode mode = CXD2880_DVBT_MODE_2K;
+ enum cxd2880_dvbt_guard guard = CXD2880_DVBT_GUARD_1_32;
+ struct cxd2880_dvbt_tpsinfo tps;
+ enum cxd2880_tnrdmd_spectrum_sense sense;
+ u16 snr = 0;
+ int strength = 0;
+
+ if (!fe || !c) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ priv = fe->demodulator_priv;
+
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_tnrdmd_dvbt_mon_mode_guard(&priv->tnrdmd,
+ &mode, &guard);
+ mutex_unlock(priv->spi_mutex);
+ if (!ret) {
+ switch (mode) {
+ case CXD2880_DVBT_MODE_2K:
+ c->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case CXD2880_DVBT_MODE_8K:
+ c->transmission_mode = TRANSMISSION_MODE_8K;
+ break;
+ default:
+ c->transmission_mode = TRANSMISSION_MODE_2K;
+ pr_debug("transmission mode is invalid %d\n", mode);
+ break;
+ }
+ switch (guard) {
+ case CXD2880_DVBT_GUARD_1_32:
+ c->guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case CXD2880_DVBT_GUARD_1_16:
+ c->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case CXD2880_DVBT_GUARD_1_8:
+ c->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case CXD2880_DVBT_GUARD_1_4:
+ c->guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ default:
+ c->guard_interval = GUARD_INTERVAL_1_32;
+ pr_debug("guard interval is invalid %d\n",
+ guard);
+ break;
+ }
+ } else {
+ c->transmission_mode = TRANSMISSION_MODE_2K;
+ c->guard_interval = GUARD_INTERVAL_1_32;
+ pr_debug("ModeGuard err %d\n", ret);
+ }
+
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, &tps);
+ mutex_unlock(priv->spi_mutex);
+ if (!ret) {
+ switch (tps.hierarchy) {
+ case CXD2880_DVBT_HIERARCHY_NON:
+ c->hierarchy = HIERARCHY_NONE;
+ break;
+ case CXD2880_DVBT_HIERARCHY_1:
+ c->hierarchy = HIERARCHY_1;
+ break;
+ case CXD2880_DVBT_HIERARCHY_2:
+ c->hierarchy = HIERARCHY_2;
+ break;
+ case CXD2880_DVBT_HIERARCHY_4:
+ c->hierarchy = HIERARCHY_4;
+ break;
+ default:
+ c->hierarchy = HIERARCHY_NONE;
+ pr_debug("TPSInfo hierarchy is invalid %d\n",
+ tps.hierarchy);
+ break;
+ }
+
+ switch (tps.rate_hp) {
+ case CXD2880_DVBT_CODERATE_1_2:
+ c->code_rate_HP = FEC_1_2;
+ break;
+ case CXD2880_DVBT_CODERATE_2_3:
+ c->code_rate_HP = FEC_2_3;
+ break;
+ case CXD2880_DVBT_CODERATE_3_4:
+ c->code_rate_HP = FEC_3_4;
+ break;
+ case CXD2880_DVBT_CODERATE_5_6:
+ c->code_rate_HP = FEC_5_6;
+ break;
+ case CXD2880_DVBT_CODERATE_7_8:
+ c->code_rate_HP = FEC_7_8;
+ break;
+ default:
+ c->code_rate_HP = FEC_NONE;
+ pr_debug("TPSInfo rateHP is invalid %d\n",
+ tps.rate_hp);
+ break;
+ }
+ switch (tps.rate_lp) {
+ case CXD2880_DVBT_CODERATE_1_2:
+ c->code_rate_LP = FEC_1_2;
+ break;
+ case CXD2880_DVBT_CODERATE_2_3:
+ c->code_rate_LP = FEC_2_3;
+ break;
+ case CXD2880_DVBT_CODERATE_3_4:
+ c->code_rate_LP = FEC_3_4;
+ break;
+ case CXD2880_DVBT_CODERATE_5_6:
+ c->code_rate_LP = FEC_5_6;
+ break;
+ case CXD2880_DVBT_CODERATE_7_8:
+ c->code_rate_LP = FEC_7_8;
+ break;
+ default:
+ c->code_rate_LP = FEC_NONE;
+ pr_debug("TPSInfo rateLP is invalid %d\n",
+ tps.rate_lp);
+ break;
+ }
+ switch (tps.constellation) {
+ case CXD2880_DVBT_CONSTELLATION_QPSK:
+ c->modulation = QPSK;
+ break;
+ case CXD2880_DVBT_CONSTELLATION_16QAM:
+ c->modulation = QAM_16;
+ break;
+ case CXD2880_DVBT_CONSTELLATION_64QAM:
+ c->modulation = QAM_64;
+ break;
+ default:
+ c->modulation = QPSK;
+ pr_debug("TPSInfo constellation is invalid %d\n",
+ tps.constellation);
+ break;
+ }
+ } else {
+ c->hierarchy = HIERARCHY_NONE;
+ c->code_rate_HP = FEC_NONE;
+ c->code_rate_LP = FEC_NONE;
+ c->modulation = QPSK;
+ pr_debug("TPS info err %d\n", ret);
+ }
+
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(&priv->tnrdmd, &sense);
+ mutex_unlock(priv->spi_mutex);
+ if (!ret) {
+ switch (sense) {
+ case CXD2880_TNRDMD_SPECTRUM_NORMAL:
+ c->inversion = INVERSION_OFF;
+ break;
+ case CXD2880_TNRDMD_SPECTRUM_INV:
+ c->inversion = INVERSION_ON;
+ break;
+ default:
+ c->inversion = INVERSION_OFF;
+ pr_debug("spectrum sense is invalid %d\n", sense);
+ break;
+ }
+ } else {
+ c->inversion = INVERSION_OFF;
+ pr_debug("spectrum_sense %d\n", ret);
+ }
+
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength);
+ mutex_unlock(priv->spi_mutex);
+ if (!ret) {
+ c->strength.len = 1;
+ c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+ c->strength.stat[0].svalue = strength;
+ } else {
+ c->strength.len = 1;
+ c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ pr_debug("mon_rf_lvl %d\n", ret);
+ }
+
+ ret = cxd2880_read_snr(fe, &snr);
+ if (!ret) {
+ c->cnr.len = 1;
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+ c->cnr.stat[0].svalue = snr;
+ } else {
+ c->cnr.len = 1;
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ pr_debug("read_snr %d\n", ret);
+ }
+
+ return 0;
+}
+
+static int cxd2880_get_frontend_t2(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c)
+{
+ int ret;
+ struct cxd2880_priv *priv = NULL;
+ struct cxd2880_dvbt2_l1pre l1pre;
+ enum cxd2880_dvbt2_plp_code_rate coderate;
+ enum cxd2880_dvbt2_plp_constell qam;
+ enum cxd2880_tnrdmd_spectrum_sense sense;
+ u16 snr = 0;
+ int strength = 0;
+
+ if (!fe || !c) {
+ pr_err("invalid arg.\n");
+ return -EINVAL;
+ }
+
+ priv = fe->demodulator_priv;
+
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre);
+ mutex_unlock(priv->spi_mutex);
+ if (!ret) {
+ switch (l1pre.fft_mode) {
+ case CXD2880_DVBT2_M2K:
+ c->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case CXD2880_DVBT2_M8K:
+ c->transmission_mode = TRANSMISSION_MODE_8K;
+ break;
+ case CXD2880_DVBT2_M4K:
+ c->transmission_mode = TRANSMISSION_MODE_4K;
+ break;
+ case CXD2880_DVBT2_M1K:
+ c->transmission_mode = TRANSMISSION_MODE_1K;
+ break;
+ case CXD2880_DVBT2_M16K:
+ c->transmission_mode = TRANSMISSION_MODE_16K;
+ break;
+ case CXD2880_DVBT2_M32K:
+ c->transmission_mode = TRANSMISSION_MODE_32K;
+ break;
+ default:
+ c->transmission_mode = TRANSMISSION_MODE_2K;
+ pr_debug("L1Pre fft_mode is invalid %d\n",
+ l1pre.fft_mode);
+ break;
+ }
+ switch (l1pre.gi) {
+ case CXD2880_DVBT2_G1_32:
+ c->guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case CXD2880_DVBT2_G1_16:
+ c->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case CXD2880_DVBT2_G1_8:
+ c->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case CXD2880_DVBT2_G1_4:
+ c->guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ case CXD2880_DVBT2_G1_128:
+ c->guard_interval = GUARD_INTERVAL_1_128;
+ break;
+ case CXD2880_DVBT2_G19_128:
+ c->guard_interval = GUARD_INTERVAL_19_128;
+ break;
+ case CXD2880_DVBT2_G19_256:
+ c->guard_interval = GUARD_INTERVAL_19_256;
+ break;
+ default:
+ c->guard_interval = GUARD_INTERVAL_1_32;
+ pr_debug("L1Pre guard interval is invalid %d\n",
+ l1pre.gi);
+ break;
+ }
+ } else {
+ c->transmission_mode = TRANSMISSION_MODE_2K;
+ c->guard_interval = GUARD_INTERVAL_1_32;
+ pr_debug("L1Pre err %d\n", ret);
+ }
+
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_tnrdmd_dvbt2_mon_code_rate(&priv->tnrdmd,
+ CXD2880_DVBT2_PLP_DATA,
+ &coderate);
+ mutex_unlock(priv->spi_mutex);
+ if (!ret) {
+ switch (coderate) {
+ case CXD2880_DVBT2_R1_2:
+ c->fec_inner = FEC_1_2;
+ break;
+ case CXD2880_DVBT2_R3_5:
+ c->fec_inner = FEC_3_5;
+ break;
+ case CXD2880_DVBT2_R2_3:
+ c->fec_inner = FEC_2_3;
+ break;
+ case CXD2880_DVBT2_R3_4:
+ c->fec_inner = FEC_3_4;
+ break;
+ case CXD2880_DVBT2_R4_5:
+ c->fec_inner = FEC_4_5;
+ break;
+ case CXD2880_DVBT2_R5_6:
+ c->fec_inner = FEC_5_6;
+ break;
+ default:
+ c->fec_inner = FEC_NONE;
+ pr_debug("CodeRate is invalid %d\n", coderate);
+ break;
+ }
+ } else {
+ c->fec_inner = FEC_NONE;
+ pr_debug("CodeRate %d\n", ret);
+ }
+
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_tnrdmd_dvbt2_mon_qam(&priv->tnrdmd,
+ CXD2880_DVBT2_PLP_DATA,
+ &qam);
+ mutex_unlock(priv->spi_mutex);
+ if (!ret) {
+ switch (qam) {
+ case CXD2880_DVBT2_QPSK:
+ c->modulation = QPSK;
+ break;
+ case CXD2880_DVBT2_QAM16:
+ c->modulation = QAM_16;
+ break;
+ case CXD2880_DVBT2_QAM64:
+ c->modulation = QAM_64;
+ break;
+ case CXD2880_DVBT2_QAM256:
+ c->modulation = QAM_256;
+ break;
+ default:
+ c->modulation = QPSK;
+ pr_debug("QAM is invalid %d\n", qam);
+ break;
+ }
+ } else {
+ c->modulation = QPSK;
+ pr_debug("QAM %d\n", ret);
+ }
+
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(&priv->tnrdmd, &sense);
+ mutex_unlock(priv->spi_mutex);
+ if (!ret) {
+ switch (sense) {
+ case CXD2880_TNRDMD_SPECTRUM_NORMAL:
+ c->inversion = INVERSION_OFF;
+ break;
+ case CXD2880_TNRDMD_SPECTRUM_INV:
+ c->inversion = INVERSION_ON;
+ break;
+ default:
+ c->inversion = INVERSION_OFF;
+ pr_debug("spectrum sense is invalid %d\n", sense);
+ break;
+ }
+ } else {
+ c->inversion = INVERSION_OFF;
+ pr_debug("SpectrumSense %d\n", ret);
+ }
+
+ mutex_lock(priv->spi_mutex);
+ ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength);
+ mutex_unlock(priv->spi_mutex);
+ if (!ret) {
+ c->strength.len = 1;
+ c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+ c->strength.stat[0].svalue = strength;
+ } else {
+ c->strength.len = 1;
+ c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ pr_debug("mon_rf_lvl %d\n", ret);
+ }
+
+ ret = cxd2880_read_snr(fe, &snr);
+ if (!ret) {
+ c->cnr.len = 1;
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+ c->cnr.stat[0].svalue = snr;
+ } else {
+ c->cnr.len = 1;
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ pr_debug("read_snr %d\n", ret);
+ }
+
+ return 0;
+}
+
+static int cxd2880_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *props)
+{
+ int ret;
+
+ if (!fe || !props) {
+ pr_err("invalid arg.");
+ return -EINVAL;
+ }
+
+ pr_debug("system=%d\n", fe->dtv_property_cache.delivery_system);
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2880_get_frontend_t(fe, props);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2880_get_frontend_t2(fe, props);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static enum dvbfe_algo cxd2880_get_frontend_algo(struct dvb_frontend *fe)
+{
+ return DVBFE_ALGO_HW;
+}
+
+static struct dvb_frontend_ops cxd2880_dvbt_t2_ops = {
+ .info = {
+ .name = "Sony CXD2880",
+ .frequency_min = 174000000,
+ .frequency_max = 862000000,
+ .frequency_stepsize = 1000,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 |
+ FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_4_5 |
+ FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK |
+ FE_CAN_QAM_16 |
+ FE_CAN_QAM_32 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 |
+ FE_CAN_QAM_256 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_2G_MODULATION |
+ FE_CAN_RECOVER |
+ FE_CAN_MUTE_TS,
+ },
+ .delsys = { SYS_DVBT, SYS_DVBT2 },
+
+ .release = cxd2880_release,
+ .init = cxd2880_init,
+ .sleep = cxd2880_sleep,
+ .tune = cxd2880_tune,
+ .set_frontend = cxd2880_set_frontend,
+ .get_frontend = cxd2880_get_frontend,
+ .read_status = cxd2880_read_status,
+ .read_ber = cxd2880_read_ber,
+ .read_signal_strength = cxd2880_read_signal_strength,
+ .read_snr = cxd2880_read_snr,
+ .read_ucblocks = cxd2880_read_ucblocks,
+ .get_frontend_algo = cxd2880_get_frontend_algo,
+};
+
+struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
+ struct cxd2880_config *cfg)
+{
+ int ret;
+ enum cxd2880_tnrdmd_chip_id chipid =
+ CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
+ static struct cxd2880_priv *priv;
+ u8 data = 0;
+
+ if (!fe) {
+ pr_err("invalid arg.\n");
+ return NULL;
+ }
+
+ priv = kzalloc(sizeof(struct cxd2880_priv), GFP_KERNEL);
+ if (!priv)
+ return NULL;
+
+ priv->spi = cfg->spi;
+ priv->spi_mutex = cfg->spi_mutex;
+ priv->spi_device.spi = cfg->spi;
+
+ memcpy(&fe->ops, &cxd2880_dvbt_t2_ops,
+ sizeof(struct dvb_frontend_ops));
+
+ ret = cxd2880_spi_device_initialize(&priv->spi_device,
+ CXD2880_SPI_MODE_0,
+ 55000000);
+ if (ret) {
+ pr_err("spi_device_initialize failed. %d\n", ret);
+ kfree(priv);
+ return NULL;
+ }
+
+ ret = cxd2880_spi_device_create_spi(&priv->cxd2880_spi,
+ &priv->spi_device);
+ if (ret) {
+ pr_err("spi_device_create_spi failed. %d\n", ret);
+ kfree(priv);
+ return NULL;
+ }
+
+ ret = cxd2880_io_spi_create(&priv->regio, &priv->cxd2880_spi, 0);
+ if (ret) {
+ pr_err("io_spi_create failed. %d\n", ret);
+ kfree(priv);
+ return NULL;
+ }
+ ret = priv->regio.write_reg(&priv->regio,
+ CXD2880_IO_TGT_SYS, 0x00, 0x00);
+ if (ret) {
+ pr_err("set bank to 0x00 failed.\n");
+ kfree(priv);
+ return NULL;
+ }
+ ret = priv->regio.read_regs(&priv->regio,
+ CXD2880_IO_TGT_SYS, 0xfd, &data, 1);
+ if (ret) {
+ pr_err("read chip id failed.\n");
+ kfree(priv);
+ return NULL;
+ }
+
+ chipid = (enum cxd2880_tnrdmd_chip_id)data;
+ if (chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X &&
+ chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11) {
+ pr_err("chip id invalid.\n");
+ kfree(priv);
+ return NULL;
+ }
+
+ fe->demodulator_priv = priv;
+ pr_info("CXD2880 driver version: Ver %s\n",
+ CXD2880_TNRDMD_DRIVER_VERSION);
+
+ return fe;
+}
+EXPORT_SYMBOL(cxd2880_attach);
+
+MODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver");
+MODULE_AUTHOR("Sony Semiconductor Solutions Corporation");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c
index 64f49c8eb1fb..ee7af34979ed 100644
--- a/drivers/media/dvb-frontends/dib0090.c
+++ b/drivers/media/dvb-frontends/dib0090.c
@@ -1285,7 +1285,7 @@ int dib0090_gain_control(struct dvb_frontend *fe)
#endif
if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */
- if (ABS(adc_error) < 50 || state->agc_step++ > 5) {
+ if (abs(adc_error) < 50 || state->agc_step++ > 5) {
#ifdef CONFIG_STANDARD_DAB
if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {
@@ -1754,7 +1754,7 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front
*tune_state = CT_TUNER_STEP_1;
} else {
/* the minimum was what we have seen in the step before */
- if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) {
+ if (abs(state->adc_diff) > abs(state->min_adc_diff)) {
dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step\n", state->adc_diff, state->min_adc_diff);
state->step--;
}
diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c
index 90ace707a80d..902af482448e 100644
--- a/drivers/media/dvb-frontends/dib7000p.c
+++ b/drivers/media/dvb-frontends/dib7000p.c
@@ -809,7 +809,7 @@ static int dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
{
u32 internal = dib7000p_get_internal_freq(state);
s32 unit_khz_dds_val;
- u32 abs_offset_khz = ABS(offset_khz);
+ u32 abs_offset_khz = abs(offset_khz);
u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
if (internal == 0) {
diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c
index e64014f338fb..6f35173d2968 100644
--- a/drivers/media/dvb-frontends/dib8000.c
+++ b/drivers/media/dvb-frontends/dib8000.c
@@ -2677,7 +2677,7 @@ static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
{
s16 unit_khz_dds_val;
- u32 abs_offset_khz = ABS(offset_khz);
+ u32 abs_offset_khz = abs(offset_khz);
u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
u8 ratio;
diff --git a/drivers/media/dvb-frontends/dibx000_common.c b/drivers/media/dvb-frontends/dibx000_common.c
index d981233e458f..70119c79ac2b 100644
--- a/drivers/media/dvb-frontends/dibx000_common.c
+++ b/drivers/media/dvb-frontends/dibx000_common.c
@@ -424,7 +424,7 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
struct i2c_algorithm *algo, const char *name,
struct dibx000_i2c_master *mst)
{
- strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
+ strlcpy(i2c_adap->name, name, sizeof(i2c_adap->name));
i2c_adap->algo = algo;
i2c_adap->algo_data = NULL;
i2c_set_adapdata(i2c_adap, mst);
diff --git a/drivers/media/dvb-frontends/dibx000_common.h b/drivers/media/dvb-frontends/dibx000_common.h
index 8784af962eba..12b58f5c677d 100644
--- a/drivers/media/dvb-frontends/dibx000_common.h
+++ b/drivers/media/dvb-frontends/dibx000_common.h
@@ -223,8 +223,6 @@ struct dvb_frontend_parametersContext {
#define FE_CALLBACK_TIME_NEVER 0xffffffff
-#define ABS(x) ((x < 0) ? (-x) : (x))
-
#define DATA_BUS_ACCESS_MODE_8BIT 0x01
#define DATA_BUS_ACCESS_MODE_16BIT 0x02
#define DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT 0x10
diff --git a/drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h b/drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h
deleted file mode 100644
index 2b3af247a1f1..000000000000
--- a/drivers/media/dvb-frontends/drx39xyj/bsp_i2c.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- I2C API, implementation depends on board specifics
-
- Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of Trident Microsystems nor Hauppauge Computer Works
- nor the names of its contributors may be used to endorse or promote
- products derived from this software without specific prior written
- permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-
- This module encapsulates I2C access.In some applications several devices
- share one I2C bus. If these devices have the same I2C address some kind
- off "switch" must be implemented to ensure error free communication with
- one device. In case such a "switch" is used, the device ID can be used
- to implement control over this "switch".
-*/
-
-#ifndef __BSPI2C_H__
-#define __BSPI2C_H__
-
-#include "bsp_types.h"
-
-/*
- * This structure contains the I2C address, the device ID and a user_data pointer.
- * The user_data pointer can be used for application specific purposes.
- */
-struct i2c_device_addr {
- u16 i2c_addr; /* The I2C address of the device. */
- u16 i2c_dev_id; /* The device identifier. */
- void *user_data; /* User data pointer */
-};
-
-
-/*
-* \def IS_I2C_10BIT( addr )
-* \brief Determine if I2C address 'addr' is a 10 bits address or not.
-* \param addr The I2C address.
-* \return int.
-* \retval 0 if address is not a 10 bits I2C address.
-* \retval 1 if address is a 10 bits I2C address.
-*/
-#define IS_I2C_10BIT(addr) \
- (((addr) & 0xF8) == 0xF0)
-
-/*------------------------------------------------------------------------------
-Exported FUNCTIONS
-------------------------------------------------------------------------------*/
-
-/*
-* \fn drxbsp_i2c_init()
-* \brief Initialize I2C communication module.
-* \return drx_status_t Return status.
-* \retval 0 Initialization successful.
-* \retval -EIO Initialization failed.
-*/
- drx_status_t drxbsp_i2c_init(void);
-
-/*
-* \fn drxbsp_i2c_term()
-* \brief Terminate I2C communication module.
-* \return drx_status_t Return status.
-* \retval 0 Termination successful.
-* \retval -EIO Termination failed.
-*/
- drx_status_t drxbsp_i2c_term(void);
-
-/*
-* \fn drx_status_t drxbsp_i2c_write_read( struct i2c_device_addr *w_dev_addr,
-* u16 w_count,
-* u8 *wData,
-* struct i2c_device_addr *r_dev_addr,
-* u16 r_count,
-* u8 *r_data)
-* \brief Read and/or write count bytes from I2C bus, store them in data[].
-* \param w_dev_addr The device i2c address and the device ID to write to
-* \param w_count The number of bytes to write
-* \param wData The array to write the data to
-* \param r_dev_addr The device i2c address and the device ID to read from
-* \param r_count The number of bytes to read
-* \param r_data The array to read the data from
-* \return drx_status_t Return status.
-* \retval 0 Succes.
-* \retval -EIO Failure.
-* \retval -EINVAL Parameter 'wcount' is not zero but parameter
-* 'wdata' contains NULL.
-* Idem for 'rcount' and 'rdata'.
-* Both w_dev_addr and r_dev_addr are NULL.
-*
-* This function must implement an atomic write and/or read action on the I2C bus
-* No other process may use the I2C bus when this function is executing.
-* The critical section of this function runs from and including the I2C
-* write, up to and including the I2C read action.
-*
-* The device ID can be useful if several devices share an I2C address.
-* It can be used to control a "switch" on the I2C bus to the correct device.
-*/
- drx_status_t drxbsp_i2c_write_read(struct i2c_device_addr *w_dev_addr,
- u16 w_count,
- u8 *w_data,
- struct i2c_device_addr *r_dev_addr,
- u16 r_count, u8 *r_data);
-
-/*
-* \fn drxbsp_i2c_error_text()
-* \brief Returns a human readable error.
-* Counter part of numerical drx_i2c_error_g.
-*
-* \return char* Pointer to human readable error text.
-*/
- char *drxbsp_i2c_error_text(void);
-
-/*
-* \var drx_i2c_error_g;
-* \brief I2C specific error codes, platform dependent.
-*/
- extern int drx_i2c_error_g;
-
-#endif /* __BSPI2C_H__ */
diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c
index 6356815cf3e1..7eb4e1469d20 100644
--- a/drivers/media/dvb-frontends/lgdt3306a.c
+++ b/drivers/media/dvb-frontends/lgdt3306a.c
@@ -30,6 +30,17 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
+/*
+ * Older drivers treated QAM64 and QAM256 the same; that is the HW always
+ * used "Auto" mode during detection. Setting "forced_manual"=1 allows
+ * the user to treat these modes as separate. For backwards compatibility,
+ * it's off by default. QAM_AUTO can now be specified to achive that
+ * effect even if "forced_manual"=1
+ */
+static int forced_manual;
+module_param(forced_manual, int, 0644);
+MODULE_PARM_DESC(forced_manual, "if set, QAM64 and QAM256 will only lock to modulation specified");
+
#define DBG_INFO 1
#define DBG_REG 2
#define DBG_DUMP 4 /* FGR - comment out to remove dump code */
@@ -566,7 +577,12 @@ static int lgdt3306a_set_qam(struct lgdt3306a_state *state, int modulation)
/* 3. : 64QAM/256QAM detection(manual, auto) */
ret = lgdt3306a_read_reg(state, 0x0009, &val);
val &= 0xfc;
- val |= 0x02; /* STDOPDETCMODE[1:0]=1=Manual 2=Auto */
+ /* Check for forced Manual modulation modes; otherwise always "auto" */
+ if(forced_manual && (modulation != QAM_AUTO)){
+ val |= 0x01; /* STDOPDETCMODE[1:0]= 1=Manual */
+ } else {
+ val |= 0x02; /* STDOPDETCMODE[1:0]= 2=Auto */
+ }
ret = lgdt3306a_write_reg(state, 0x0009, val);
if (lg_chkerr(ret))
goto fail;
@@ -598,6 +614,28 @@ static int lgdt3306a_set_qam(struct lgdt3306a_state *state, int modulation)
if (lg_chkerr(ret))
goto fail;
+ /* 5.1 V0.36 SRDCHKALWAYS : For better QAM detection */
+ ret = lgdt3306a_read_reg(state, 0x000a, &val);
+ val &= 0xfd;
+ val |= 0x02;
+ ret = lgdt3306a_write_reg(state, 0x000a, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 5.2 V0.36 Control of "no signal" detector function */
+ ret = lgdt3306a_read_reg(state, 0x2849, &val);
+ val &= 0xdf;
+ ret = lgdt3306a_write_reg(state, 0x2849, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
+ /* 5.3 Fix for Blonder Tongue HDE-2H-QAM and AQM modulators */
+ ret = lgdt3306a_read_reg(state, 0x302b, &val);
+ val &= 0x7f; /* SELFSYNCFINDEN_CQS=0; disable auto reset */
+ ret = lgdt3306a_write_reg(state, 0x302b, val);
+ if (lg_chkerr(ret))
+ goto fail;
+
/* 6. Reset */
ret = lgdt3306a_soft_reset(state);
if (lg_chkerr(ret))
@@ -620,10 +658,9 @@ static int lgdt3306a_set_modulation(struct lgdt3306a_state *state,
ret = lgdt3306a_set_vsb(state);
break;
case QAM_64:
- ret = lgdt3306a_set_qam(state, QAM_64);
- break;
case QAM_256:
- ret = lgdt3306a_set_qam(state, QAM_256);
+ case QAM_AUTO:
+ ret = lgdt3306a_set_qam(state, p->modulation);
break;
default:
return -EINVAL;
@@ -650,6 +687,7 @@ static int lgdt3306a_agc_setup(struct lgdt3306a_state *state,
break;
case QAM_64:
case QAM_256:
+ case QAM_AUTO:
break;
default:
return -EINVAL;
@@ -704,6 +742,7 @@ static int lgdt3306a_spectral_inversion(struct lgdt3306a_state *state,
break;
case QAM_64:
case QAM_256:
+ case QAM_AUTO:
/* Auto ok for QAM */
ret = lgdt3306a_set_inversion_auto(state, 1);
break;
@@ -727,6 +766,7 @@ static int lgdt3306a_set_if(struct lgdt3306a_state *state,
break;
case QAM_64:
case QAM_256:
+ case QAM_AUTO:
if_freq_khz = state->cfg->qam_if_khz;
break;
default:
@@ -1585,6 +1625,7 @@ static int lgdt3306a_read_status(struct dvb_frontend *fe,
switch (state->current_modulation) {
case QAM_256:
case QAM_64:
+ case QAM_AUTO:
if (lgdt3306a_qam_lock_poll(state) == LG3306_LOCK) {
*status |= FE_HAS_VITERBI;
*status |= FE_HAS_SYNC;
@@ -1628,6 +1669,7 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe,
* Calculate some sort of "strength" from SNR
*/
struct lgdt3306a_state *state = fe->demodulator_priv;
+ u8 val;
u16 snr; /* snr_x10 */
int ret;
u32 ref_snr; /* snr*100 */
@@ -1640,11 +1682,15 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe,
ref_snr = 1600; /* 16dB */
break;
case QAM_64:
- ref_snr = 2200; /* 22dB */
- break;
case QAM_256:
- ref_snr = 2800; /* 28dB */
- break;
+ case QAM_AUTO:
+ /* need to know actual modulation to set proper SNR baseline */
+ lgdt3306a_read_reg(state, 0x00a6, &val);
+ if(val & 0x04)
+ ref_snr = 2800; /* QAM-256 28dB */
+ else
+ ref_snr = 2200; /* QAM-64 22dB */
+ break;
default:
return -EINVAL;
}
@@ -2114,7 +2160,7 @@ static const struct dvb_frontend_ops lgdt3306a_ops = {
.frequency_min = 54000000,
.frequency_max = 858000000,
.frequency_stepsize = 62500,
- .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ .caps = FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
},
.i2c_gate_ctrl = lgdt3306a_i2c_gate_ctrl,
.init = lgdt3306a_init,
@@ -2177,6 +2223,7 @@ static int lgdt3306a_probe(struct i2c_client *client,
i2c_set_clientdata(client, fe->demodulator_priv);
state = fe->demodulator_priv;
+ state->frontend.ops.release = NULL;
/* create mux i2c adapter for tuner */
state->muxc = i2c_mux_alloc(client->adapter, &client->dev,
@@ -2196,6 +2243,8 @@ static int lgdt3306a_probe(struct i2c_client *client,
*config->i2c_adapter = state->muxc->adapter[0];
*config->fe = fe;
+ dev_info(&client->dev, "LG Electronics LGDT3306A successfully identified\n");
+
return 0;
err_kfree:
@@ -2203,7 +2252,7 @@ err_kfree:
err_fe:
kfree(config);
fail:
- dev_dbg(&client->dev, "failed=%d\n", ret);
+ dev_warn(&client->dev, "probe failed = %d\n", ret);
return ret;
}
diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c
index 2969ba6ed9e1..377cd984b069 100644
--- a/drivers/media/dvb-frontends/mb86a16.c
+++ b/drivers/media/dvb-frontends/mb86a16.c
@@ -31,8 +31,6 @@
static unsigned int verbose = 5;
module_param(verbose, int, 0644);
-#define ABS(x) ((x) < 0 ? (-x) : (x))
-
struct mb86a16_state {
struct i2c_adapter *i2c_adap;
const struct mb86a16_config *config;
@@ -1202,12 +1200,12 @@ static int mb86a16_set_fe(struct mb86a16_state *state)
signal_dupl = 0;
for (j = 0; j < prev_freq_num; j++) {
- if ((ABS(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) {
+ if ((abs(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) {
signal_dupl = 1;
dprintk(verbose, MB86A16_INFO, 1, "Probably Duplicate Signal, j = %d", j);
}
}
- if ((signal_dupl == 0) && (swp_freq > 0) && (ABS(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) {
+ if ((signal_dupl == 0) && (swp_freq > 0) && (abs(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) {
dprintk(verbose, MB86A16_DEBUG, 1, "------ Signal detect ------ [swp_freq=[%07d, srate=%05d]]", swp_freq, state->srate);
prev_swp_freq[prev_freq_num] = swp_freq;
prev_freq_num++;
@@ -1381,7 +1379,7 @@ static int mb86a16_set_fe(struct mb86a16_state *state)
dprintk(verbose, MB86A16_INFO, 1, "SWEEP Frequency = %d", swp_freq);
swp_freq += delta_freq;
dprintk(verbose, MB86A16_INFO, 1, "Adjusting .., DELTA Freq = %d, SWEEP Freq=%d", delta_freq, swp_freq);
- if (ABS(state->frequency * 1000 - swp_freq) > 3800) {
+ if (abs(state->frequency * 1000 - swp_freq) > 3800) {
dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL !");
} else {
diff --git a/drivers/media/dvb-frontends/mxl5xx.c b/drivers/media/dvb-frontends/mxl5xx.c
index e899821018a0..483ee7d6198e 100644
--- a/drivers/media/dvb-frontends/mxl5xx.c
+++ b/drivers/media/dvb-frontends/mxl5xx.c
@@ -380,6 +380,38 @@ static int get_algo(struct dvb_frontend *fe)
return DVBFE_ALGO_HW;
}
+static u32 gold2root(u32 gold)
+{
+ u32 x, g, tmp = gold;
+
+ if (tmp >= 0x3ffff)
+ tmp = 0;
+ for (g = 0, x = 1; g < tmp; g++)
+ x = (((x ^ (x >> 7)) & 1) << 17) | (x >> 1);
+ return x;
+}
+
+static int cfg_scrambler(struct mxl *state, u32 gold)
+{
+ u32 root;
+ u8 buf[26] = {
+ MXL_HYDRA_PLID_CMD_WRITE, 24,
+ 0, MXL_HYDRA_DEMOD_SCRAMBLE_CODE_CMD, 0, 0,
+ state->demod, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0,
+ };
+
+ root = gold2root(gold);
+
+ buf[25] = (root >> 24) & 0xff;
+ buf[24] = (root >> 16) & 0xff;
+ buf[23] = (root >> 8) & 0xff;
+ buf[22] = root & 0xff;
+
+ return send_command(state, sizeof(buf), buf);
+}
+
static int cfg_demod_abort_tune(struct mxl *state)
{
struct MXL_HYDRA_DEMOD_ABORT_TUNE_T abort_tune_cmd;
@@ -437,7 +469,7 @@ static int set_parameters(struct dvb_frontend *fe)
demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_AUTO;
demod_chan_cfg.modulation_scheme = MXL_HYDRA_MOD_AUTO;
demod_chan_cfg.pilots = MXL_HYDRA_PILOTS_AUTO;
- /* cfg_scrambler(state); */
+ cfg_scrambler(state, p->scrambling_sequence_index);
break;
default:
return -EINVAL;
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 94bf5b7d6f3f..fa3b8169c1a5 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -498,7 +498,7 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
* RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22)
* / ConstWithBandwidthMode)
*/
- num = dev->pdata->clk * 7;
+ num = dev->pdata->clk * 7ULL;
num *= 0x400000;
num = div_u64(num, bw_mode);
resamp_ratio = num & 0x3ffffff;
@@ -511,7 +511,7 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
* / (CrystalFreqHz * 7))
*/
num = bw_mode << 20;
- num2 = dev->pdata->clk * 7;
+ num2 = dev->pdata->clk * 7ULL;
num = div_u64(num, num2);
num = -num;
cfreq_off_ratio = num & 0xfffff;
diff --git a/drivers/media/dvb-frontends/s5h1409.c b/drivers/media/dvb-frontends/s5h1409.c
index aced6a956ec5..a23ba8727218 100644
--- a/drivers/media/dvb-frontends/s5h1409.c
+++ b/drivers/media/dvb-frontends/s5h1409.c
@@ -682,17 +682,17 @@ static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode)
val = s5h1409_readreg(state, 0xac) & 0xcfff;
switch (mode) {
- case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
+ case S5H1409_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK:
val |= 0x0000;
break;
- case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
+ case S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK:
dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
val |= 0x1000;
break;
- case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
+ case S5H1409_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK:
val |= 0x2000;
break;
- case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
+ case S5H1409_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK:
val |= 0x3000;
break;
default:
diff --git a/drivers/media/dvb-frontends/s5h1409.h b/drivers/media/dvb-frontends/s5h1409.h
index b38557c451b9..87de58ffc822 100644
--- a/drivers/media/dvb-frontends/s5h1409.h
+++ b/drivers/media/dvb-frontends/s5h1409.h
@@ -52,10 +52,10 @@ struct s5h1409_config {
u8 status_mode;
/* MPEG signal timing */
-#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0
-#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1
-#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2
-#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
+#define S5H1409_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK 0
+#define S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK 1
+#define S5H1409_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK 2
+#define S5H1409_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK 3
u16 mpeg_timing;
/* HVR-1600 optimizations (to better work with MXL5005s)
diff --git a/drivers/media/dvb-frontends/s5h1411.c b/drivers/media/dvb-frontends/s5h1411.c
index c4b1e9725f3e..af5962807f2c 100644
--- a/drivers/media/dvb-frontends/s5h1411.c
+++ b/drivers/media/dvb-frontends/s5h1411.c
@@ -433,17 +433,17 @@ static int s5h1411_set_mpeg_timing(struct dvb_frontend *fe, int mode)
val = s5h1411_readreg(state, S5H1411_I2C_TOP_ADDR, 0xbe) & 0xcfff;
switch (mode) {
- case S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
+ case S5H1411_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK:
val |= 0x0000;
break;
- case S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
+ case S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK:
dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
val |= 0x1000;
break;
- case S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
+ case S5H1411_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK:
val |= 0x2000;
break;
- case S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
+ case S5H1411_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK:
val |= 0x3000;
break;
default:
diff --git a/drivers/media/dvb-frontends/s5h1411.h b/drivers/media/dvb-frontends/s5h1411.h
index 791bab0e16e9..850ee713d64c 100644
--- a/drivers/media/dvb-frontends/s5h1411.h
+++ b/drivers/media/dvb-frontends/s5h1411.h
@@ -40,10 +40,10 @@ struct s5h1411_config {
u8 gpio;
/* MPEG signal timing */
-#define S5H1411_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0
-#define S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1
-#define S5H1411_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2
-#define S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
+#define S5H1411_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK 0
+#define S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK 1
+#define S5H1411_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK 2
+#define S5H1411_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK 3
u16 mpeg_timing;
/* IF Freq for QAM and VSB in KHz */
diff --git a/drivers/media/dvb-frontends/s5h1432.h b/drivers/media/dvb-frontends/s5h1432.h
index af3a157b5e77..646dda36262b 100644
--- a/drivers/media/dvb-frontends/s5h1432.h
+++ b/drivers/media/dvb-frontends/s5h1432.h
@@ -42,10 +42,10 @@ struct s5h1432_config {
u8 gpio;
/* MPEG signal timing */
-#define S5H1432_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0
-#define S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1
-#define S5H1432_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2
-#define S5H1432_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
+#define S5H1432_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK 0
+#define S5H1432_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK 1
+#define S5H1432_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK 2
+#define S5H1432_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK 3
u16 mpeg_timing;
/* IF Freq for QAM and VSB in KHz */
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index 539399dac551..324493e05f9f 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -82,6 +82,30 @@ err_mutex_unlock:
return ret;
}
+static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+ struct i2c_client *client = fe->demodulator_priv;
+ struct si2168_dev *dev = i2c_get_clientdata(client);
+ struct si2168_cmd cmd;
+ int ret = 0;
+
+ dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire);
+
+ /* set TS_MODE property */
+ memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
+ if (acquire)
+ cmd.args[4] |= dev->ts_mode;
+ else
+ cmd.args[4] |= SI2168_TS_TRISTATE;
+ if (dev->ts_clock_gapped)
+ cmd.args[4] |= 0x40;
+ cmd.wlen = 6;
+ cmd.rlen = 4;
+ ret = si2168_cmd_execute(client, &cmd);
+
+ return ret;
+}
+
static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status)
{
struct i2c_client *client = fe->demodulator_priv;
@@ -339,6 +363,8 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6);
cmd.args[4] = delivery_system | bandwidth;
+ if (dev->spectral_inversion)
+ cmd.args[5] |= 1;
cmd.wlen = 6;
cmd.rlen = 4;
ret = si2168_cmd_execute(client, &cmd);
@@ -403,6 +429,11 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
dev->delivery_system = c->delivery_system;
+ /* enable ts bus */
+ ret = si2168_ts_bus_ctrl(fe, 1);
+ if (ret)
+ goto err;
+
return 0;
err:
dev_dbg(&client->dev, "failed=%d\n", ret);
@@ -541,13 +572,7 @@ static int si2168_init(struct dvb_frontend *fe)
dev->version >> 8 & 0xff, dev->version >> 0 & 0xff);
/* set ts mode */
- memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
- cmd.args[4] |= dev->ts_mode;
- if (dev->ts_clock_gapped)
- cmd.args[4] |= 0x40;
- cmd.wlen = 6;
- cmd.rlen = 4;
- ret = si2168_cmd_execute(client, &cmd);
+ ret = si2168_ts_bus_ctrl(fe, 1);
if (ret)
goto err;
@@ -584,7 +609,12 @@ static int si2168_sleep(struct dvb_frontend *fe)
dev->active = false;
- /* Firmware B 4.0-11 or later loses warm state during sleep */
+ /* tri-state data bus */
+ ret = si2168_ts_bus_ctrl(fe, 0);
+ if (ret)
+ goto err;
+
+ /* Firmware later than B 4.0-11 loses warm state during sleep */
if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0))
dev->warm = false;
@@ -776,6 +806,7 @@ static int si2168_probe(struct i2c_client *client,
dev->ts_mode = config->ts_mode;
dev->ts_clock_inv = config->ts_clock_inv;
dev->ts_clock_gapped = config->ts_clock_gapped;
+ dev->spectral_inversion = config->spectral_inversion;
dev_info(&client->dev, "Silicon Labs Si2168-%c%d%d successfully identified\n",
dev->version >> 24 & 0xff, dev->version >> 16 & 0xff,
@@ -788,7 +819,7 @@ static int si2168_probe(struct i2c_client *client,
err_kfree:
kfree(dev);
err:
- dev_dbg(&client->dev, "failed=%d\n", ret);
+ dev_warn(&client->dev, "probe failed = %d\n", ret);
return ret;
}
diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h
index 3225d0cc93c7..d519edd26c21 100644
--- a/drivers/media/dvb-frontends/si2168.h
+++ b/drivers/media/dvb-frontends/si2168.h
@@ -38,6 +38,7 @@ struct si2168_config {
/* TS mode */
#define SI2168_TS_PARALLEL 0x06
#define SI2168_TS_SERIAL 0x03
+#define SI2168_TS_TRISTATE 0x00
u8 ts_mode;
/* TS clock inverted */
@@ -45,6 +46,9 @@ struct si2168_config {
/* TS clock gapped */
bool ts_clock_gapped;
+
+ /* Inverted spectrum */
+ bool spectral_inversion;
};
#endif
diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h
index 3c8746a20038..2d362e162ade 100644
--- a/drivers/media/dvb-frontends/si2168_priv.h
+++ b/drivers/media/dvb-frontends/si2168_priv.h
@@ -48,6 +48,7 @@ struct si2168_dev {
u8 ts_mode;
bool ts_clock_inv;
bool ts_clock_gapped;
+ bool spectral_inversion;
};
/* firmware command struct */
diff --git a/drivers/media/dvb-frontends/sp887x.c b/drivers/media/dvb-frontends/sp887x.c
index 572a297811fe..f39d566d7d1d 100644
--- a/drivers/media/dvb-frontends/sp887x.c
+++ b/drivers/media/dvb-frontends/sp887x.c
@@ -136,7 +136,7 @@ static void sp887x_setup_agc (struct sp887x_state* state)
static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw)
{
struct sp887x_state* state = fe->demodulator_priv;
- u8 buf [BLOCKSIZE+2];
+ u8 buf [BLOCKSIZE + 2];
int i;
int fw_size = fw->size;
const unsigned char *mem = fw->data;
@@ -144,7 +144,7 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware
dprintk("%s\n", __func__);
/* ignore the first 10 bytes, then we expect 0x4000 bytes of firmware */
- if (fw_size < FW_SIZE+10)
+ if (fw_size < FW_SIZE + 10)
return -ENODEV;
mem = fw->data + 10;
@@ -167,7 +167,7 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware
int c = BLOCKSIZE;
int err;
- if (i+c > FW_SIZE)
+ if (c > FW_SIZE - i)
c = FW_SIZE - i;
/* bit 0x8000 in address is set to enable 13bit mode */
diff --git a/drivers/media/dvb-frontends/stb0899_reg.h b/drivers/media/dvb-frontends/stb0899_reg.h
index ba1ed56304a0..f564269249a6 100644
--- a/drivers/media/dvb-frontends/stb0899_reg.h
+++ b/drivers/media/dvb-frontends/stb0899_reg.h
@@ -374,22 +374,22 @@
#define STB0899_OFF0_IF_AGC_GAIN 0xf30c
#define STB0899_BASE_IF_AGC_GAIN 0x00000000
-#define STB0899_IF_AGC_GAIN (0x3fff < 0)
+#define STB0899_IF_AGC_GAIN (0x3fff << 0)
#define STB0899_OFFST_IF_AGC_GAIN 0
#define STB0899_WIDTH_IF_AGC_GAIN 14
#define STB0899_OFF0_BB_AGC_GAIN 0xf310
#define STB0899_BASE_BB_AGC_GAIN 0x00000000
-#define STB0899_BB_AGC_GAIN (0x3fff < 0)
+#define STB0899_BB_AGC_GAIN (0x3fff << 0)
#define STB0899_OFFST_BB_AGC_GAIN 0
#define STB0899_WIDTH_BB_AGC_GAIN 14
#define STB0899_OFF0_DC_OFFSET 0xf314
#define STB0899_BASE_DC_OFFSET 0x00000000
-#define STB0899_I (0xff < 8)
+#define STB0899_I (0xff << 8)
#define STB0899_OFFST_I 8
#define STB0899_WIDTH_I 8
-#define STB0899_Q (0xff < 0)
+#define STB0899_Q (0xff << 0)
#define STB0899_OFFST_Q 8
#define STB0899_WIDTH_Q 8
diff --git a/drivers/media/dvb-frontends/stv0367_priv.h b/drivers/media/dvb-frontends/stv0367_priv.h
index 8abc451dd524..460066a391b7 100644
--- a/drivers/media/dvb-frontends/stv0367_priv.h
+++ b/drivers/media/dvb-frontends/stv0367_priv.h
@@ -35,7 +35,6 @@
#endif
/* MACRO definitions */
-#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X))
#define MAX(X, Y) ((X) >= (Y) ? (X) : (Y))
#define MIN(X, Y) ((X) <= (Y) ? (X) : (Y))
#define INRANGE(X, Y, Z) \
diff --git a/drivers/media/dvb-frontends/stv0900_priv.h b/drivers/media/dvb-frontends/stv0900_priv.h
index d1fc06ff27d3..09a46477eae4 100644
--- a/drivers/media/dvb-frontends/stv0900_priv.h
+++ b/drivers/media/dvb-frontends/stv0900_priv.h
@@ -24,7 +24,6 @@
#include <linux/i2c.h>
-#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X))
#define INRANGE(X, Y, Z) ((((X) <= (Y)) && ((Y) <= (Z))) \
|| (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0)
diff --git a/drivers/media/dvb-frontends/stv0900_sw.c b/drivers/media/dvb-frontends/stv0900_sw.c
index c97a39120ea5..d406c83e4744 100644
--- a/drivers/media/dvb-frontends/stv0900_sw.c
+++ b/drivers/media/dvb-frontends/stv0900_sw.c
@@ -1255,14 +1255,14 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
else
intp->freq[d] = stv0900_get_tuner_freq(fe);
- if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
+ if (abs(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
range = STV0900_RANGEOK;
- else if (ABS(offsetFreq) <=
+ else if (abs(offsetFreq) <=
(stv0900_carrier_width(result->symbol_rate,
result->rolloff) / 2000))
range = STV0900_RANGEOK;
- } else if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
+ } else if (abs(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
range = STV0900_RANGEOK;
dprintk("%s: range %d\n", __func__, range);
diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c
index a2f7c0c1587f..52355c14fd64 100644
--- a/drivers/media/dvb-frontends/stv0910.c
+++ b/drivers/media/dvb-frontends/stv0910.c
@@ -1673,15 +1673,15 @@ static int send_master_cmd(struct dvb_frontend *fe,
struct dvb_diseqc_master_cmd *cmd)
{
struct stv *state = fe->demodulator_priv;
- u16 offs = state->nr ? 0x40 : 0;
int i;
- write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3E);
+ SET_FIELD(DISEQC_MODE, 2);
+ SET_FIELD(DIS_PRECHARGE, 1);
for (i = 0; i < cmd->msg_len; i++) {
wait_dis(state, 0x40, 0x00);
- write_reg(state, RSTV0910_P1_DISTXFIFO + offs, cmd->msg[i]);
+ SET_REG(DISTXFIFO, cmd->msg[i]);
}
- write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A);
+ SET_FIELD(DIS_PRECHARGE, 0);
wait_dis(state, 0x20, 0x20);
return 0;
}
@@ -1689,19 +1689,20 @@ static int send_master_cmd(struct dvb_frontend *fe,
static int send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst)
{
struct stv *state = fe->demodulator_priv;
- u16 offs = state->nr ? 0x40 : 0;
u8 value;
if (burst == SEC_MINI_A) {
- write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3F);
+ SET_FIELD(DISEQC_MODE, 3);
value = 0x00;
} else {
- write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3E);
+ SET_FIELD(DISEQC_MODE, 2);
value = 0xFF;
}
+
+ SET_FIELD(DIS_PRECHARGE, 1);
wait_dis(state, 0x40, 0x00);
- write_reg(state, RSTV0910_P1_DISTXFIFO + offs, value);
- write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A);
+ SET_REG(DISTXFIFO, value);
+ SET_FIELD(DIS_PRECHARGE, 0);
wait_dis(state, 0x20, 0x20);
return 0;
diff --git a/drivers/media/dvb-frontends/ves1820.c b/drivers/media/dvb-frontends/ves1820.c
index 1d8979289915..17600989f121 100644
--- a/drivers/media/dvb-frontends/ves1820.c
+++ b/drivers/media/dvb-frontends/ves1820.c
@@ -137,7 +137,7 @@ static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
NDEC = 3;
/* yeuch! */
- fpxin = state->config->xin * 10;
+ fpxin = state->config->xin * 10ULL;
fptmp = fpxin; do_div(fptmp, 123);
if (symbolrate < fptmp)
SFIL = 1;
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 9f18cd296841..541f0d28afd8 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -56,6 +56,17 @@ config VIDEO_TDA9840
To compile this driver as a module, choose M here: the
module will be called tda9840.
+config VIDEO_TDA1997X
+ tristate "NXP TDA1997x HDMI receiver"
+ depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
+ depends on SND_SOC
+ select SND_PCM
+ ---help---
+ V4L2 subdevice driver for the NXP TDA1997x HDMI receivers.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tda1997x.
+
config VIDEO_TEA6415C
tristate "Philips TEA6415C audio processor"
depends on I2C
@@ -423,6 +434,15 @@ config VIDEO_TW9906
To compile this driver as a module, choose M here: the
module will be called tw9906.
+config VIDEO_TW9910
+ tristate "Techwell TW9910 video decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for Techwell TW9910 NTSC/PAL/SECAM video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tw9910.
+
config VIDEO_VPX3220
tristate "vpx3220a, vpx3216b & vpx3214c video decoders"
depends on VIDEO_V4L2 && I2C
@@ -586,6 +606,18 @@ config VIDEO_OV2659
To compile this driver as a module, choose M here: the
module will be called ov2659.
+config VIDEO_OV2685
+ tristate "OmniVision OV2685 sensor support"
+ depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER
+ depends on MEDIA_CAMERA_SUPPORT
+ select V4L2_FWNODE
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV2685 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ov2685.
+
config VIDEO_OV5640
tristate "OmniVision OV5640 sensor support"
depends on OF
@@ -645,6 +677,28 @@ config VIDEO_OV5670
To compile this driver as a module, choose M here: the
module will be called ov5670.
+config VIDEO_OV5695
+ tristate "OmniVision OV5695 sensor support"
+ depends on I2C && VIDEO_V4L2
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV5695 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ov5695.
+
+config VIDEO_OV772X
+ tristate "OmniVision OV772x sensor support"
+ depends on I2C && VIDEO_V4L2
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV772x camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ov772x.
+
config VIDEO_OV7640
tristate "OmniVision OV7640 sensor support"
depends on I2C && VIDEO_V4L2
@@ -660,6 +714,7 @@ config VIDEO_OV7670
tristate "OmniVision OV7670 sensor support"
depends on I2C && VIDEO_V4L2
depends on MEDIA_CAMERA_SUPPORT
+ select V4L2_FWNODE
---help---
This is a Video4Linux2 sensor-level driver for the OmniVision
OV7670 VGA camera. It currently only works with the M88ALP01
@@ -733,6 +788,17 @@ config VIDEO_MT9T001
This is a Video4Linux2 sensor-level driver for the Aptina
(Micron) mt0t001 3 Mpixel camera.
+config VIDEO_MT9T112
+ tristate "Aptina MT9T111/MT9T112 support"
+ depends on I2C && VIDEO_V4L2
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the Aptina
+ (Micron) MT9T111 and MT9T112 3 Mpixel camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mt9t112.
+
config VIDEO_MT9V011
tristate "Micron mt9v011 sensor support"
depends on I2C && VIDEO_V4L2
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index c0f94cd8d56d..ea34aee1a85a 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
+obj-$(CONFIG_VIDEO_TDA1997X) += tda1997x.o
obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o
@@ -48,6 +49,7 @@ obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o
obj-$(CONFIG_VIDEO_TW2804) += tw2804.o
obj-$(CONFIG_VIDEO_TW9903) += tw9903.o
obj-$(CONFIG_VIDEO_TW9906) += tw9906.o
+obj-$(CONFIG_VIDEO_TW9910) += tw9910.o
obj-$(CONFIG_VIDEO_CS3308) += cs3308.o
obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
@@ -61,13 +63,16 @@ obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o
obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
obj-$(CONFIG_VIDEO_OV2640) += ov2640.o
+obj-$(CONFIG_VIDEO_OV2685) += ov2685.o
obj-$(CONFIG_VIDEO_OV5640) += ov5640.o
obj-$(CONFIG_VIDEO_OV5645) += ov5645.o
obj-$(CONFIG_VIDEO_OV5647) += ov5647.o
obj-$(CONFIG_VIDEO_OV5670) += ov5670.o
+obj-$(CONFIG_VIDEO_OV5695) += ov5695.o
obj-$(CONFIG_VIDEO_OV6650) += ov6650.o
obj-$(CONFIG_VIDEO_OV7640) += ov7640.o
obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
+obj-$(CONFIG_VIDEO_OV772X) += ov772x.o
obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
@@ -75,6 +80,7 @@ obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o
obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o
+obj-$(CONFIG_VIDEO_MT9T112) += mt9t112.o
obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c
index a056d6cdaaaa..91ff06088572 100644
--- a/drivers/media/i2c/ad9389b.c
+++ b/drivers/media/i2c/ad9389b.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Analog Devices AD9389B/AD9889B video encoder driver
*
* Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
/*
diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c
index fd92c9e4b519..6ca88daa0ecd 100644
--- a/drivers/media/i2c/adv748x/adv748x-core.c
+++ b/drivers/media/i2c/adv748x/adv748x-core.c
@@ -35,96 +35,28 @@
* Register manipulation
*/
-static const struct regmap_config adv748x_regmap_cnf[] = {
- {
- .name = "io",
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = 0xff,
- .cache_type = REGCACHE_NONE,
- },
- {
- .name = "dpll",
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = 0xff,
- .cache_type = REGCACHE_NONE,
- },
- {
- .name = "cp",
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = 0xff,
- .cache_type = REGCACHE_NONE,
- },
- {
- .name = "hdmi",
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = 0xff,
- .cache_type = REGCACHE_NONE,
- },
- {
- .name = "edid",
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = 0xff,
- .cache_type = REGCACHE_NONE,
- },
- {
- .name = "repeater",
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = 0xff,
- .cache_type = REGCACHE_NONE,
- },
- {
- .name = "infoframe",
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = 0xff,
- .cache_type = REGCACHE_NONE,
- },
- {
- .name = "cec",
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = 0xff,
- .cache_type = REGCACHE_NONE,
- },
- {
- .name = "sdp",
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = 0xff,
- .cache_type = REGCACHE_NONE,
- },
-
- {
- .name = "txb",
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = 0xff,
- .cache_type = REGCACHE_NONE,
- },
- {
- .name = "txa",
- .reg_bits = 8,
- .val_bits = 8,
+#define ADV748X_REGMAP_CONF(n) \
+{ \
+ .name = n, \
+ .reg_bits = 8, \
+ .val_bits = 8, \
+ .max_register = 0xff, \
+ .cache_type = REGCACHE_NONE, \
+}
- .max_register = 0xff,
- .cache_type = REGCACHE_NONE,
- },
+static const struct regmap_config adv748x_regmap_cnf[] = {
+ ADV748X_REGMAP_CONF("io"),
+ ADV748X_REGMAP_CONF("dpll"),
+ ADV748X_REGMAP_CONF("cp"),
+ ADV748X_REGMAP_CONF("hdmi"),
+ ADV748X_REGMAP_CONF("edid"),
+ ADV748X_REGMAP_CONF("repeater"),
+ ADV748X_REGMAP_CONF("infoframe"),
+ ADV748X_REGMAP_CONF("cbus"),
+ ADV748X_REGMAP_CONF("cec"),
+ ADV748X_REGMAP_CONF("sdp"),
+ ADV748X_REGMAP_CONF("txa"),
+ ADV748X_REGMAP_CONF("txb"),
};
static int adv748x_configure_regmap(struct adv748x_state *state, int region)
@@ -148,20 +80,24 @@ static int adv748x_configure_regmap(struct adv748x_state *state, int region)
return 0;
}
+struct adv748x_register_map {
+ const char *name;
+ u8 default_addr;
+};
-/* Default addresses for the I2C pages */
-static int adv748x_i2c_addresses[ADV748X_PAGE_MAX] = {
- ADV748X_I2C_IO,
- ADV748X_I2C_DPLL,
- ADV748X_I2C_CP,
- ADV748X_I2C_HDMI,
- ADV748X_I2C_EDID,
- ADV748X_I2C_REPEATER,
- ADV748X_I2C_INFOFRAME,
- ADV748X_I2C_CEC,
- ADV748X_I2C_SDP,
- ADV748X_I2C_TXB,
- ADV748X_I2C_TXA,
+static const struct adv748x_register_map adv748x_default_addresses[] = {
+ [ADV748X_PAGE_IO] = { "main", 0x70 },
+ [ADV748X_PAGE_DPLL] = { "dpll", 0x26 },
+ [ADV748X_PAGE_CP] = { "cp", 0x22 },
+ [ADV748X_PAGE_HDMI] = { "hdmi", 0x34 },
+ [ADV748X_PAGE_EDID] = { "edid", 0x36 },
+ [ADV748X_PAGE_REPEATER] = { "repeater", 0x32 },
+ [ADV748X_PAGE_INFOFRAME] = { "infoframe", 0x31 },
+ [ADV748X_PAGE_CBUS] = { "cbus", 0x30 },
+ [ADV748X_PAGE_CEC] = { "cec", 0x41 },
+ [ADV748X_PAGE_SDP] = { "sdp", 0x79 },
+ [ADV748X_PAGE_TXB] = { "txb", 0x48 },
+ [ADV748X_PAGE_TXA] = { "txa", 0x4a },
};
static int adv748x_read_check(struct adv748x_state *state,
@@ -210,15 +146,20 @@ int adv748x_write_block(struct adv748x_state *state, int client_page,
return regmap_raw_write(regmap, init_reg, val, val_len);
}
-static struct i2c_client *adv748x_dummy_client(struct adv748x_state *state,
- u8 addr, u8 io_reg)
+static int adv748x_set_slave_addresses(struct adv748x_state *state)
{
- struct i2c_client *client = state->client;
+ struct i2c_client *client;
+ unsigned int i;
+ u8 io_reg;
- if (addr)
- io_write(state, io_reg, addr << 1);
+ for (i = ADV748X_PAGE_DPLL; i < ADV748X_PAGE_MAX; ++i) {
+ io_reg = ADV748X_IO_SLAVE_ADDR_BASE + i;
+ client = state->i2c_clients[i];
+
+ io_write(state, io_reg, client->addr << 1);
+ }
- return i2c_new_dummy(client->adapter, io_read(state, io_reg) >> 1);
+ return 0;
}
static void adv748x_unregister_clients(struct adv748x_state *state)
@@ -231,13 +172,15 @@ static void adv748x_unregister_clients(struct adv748x_state *state)
static int adv748x_initialise_clients(struct adv748x_state *state)
{
- int i;
+ unsigned int i;
int ret;
for (i = ADV748X_PAGE_DPLL; i < ADV748X_PAGE_MAX; ++i) {
- state->i2c_clients[i] =
- adv748x_dummy_client(state, adv748x_i2c_addresses[i],
- ADV748X_IO_SLAVE_ADDR_BASE + i);
+ state->i2c_clients[i] = i2c_new_secondary_device(
+ state->client,
+ adv748x_default_addresses[i].name,
+ adv748x_default_addresses[i].default_addr);
+
if (state->i2c_clients[i] == NULL) {
adv_err(state, "failed to create i2c client %u\n", i);
return -ENOMEM;
@@ -248,7 +191,7 @@ static int adv748x_initialise_clients(struct adv748x_state *state)
return ret;
}
- return 0;
+ return adv748x_set_slave_addresses(state);
}
/**
@@ -414,20 +357,6 @@ static const struct adv748x_reg_value adv748x_sw_reset[] = {
{ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */
};
-static const struct adv748x_reg_value adv748x_set_slave_address[] = {
- {ADV748X_PAGE_IO, 0xf3, ADV748X_I2C_DPLL << 1},
- {ADV748X_PAGE_IO, 0xf4, ADV748X_I2C_CP << 1},
- {ADV748X_PAGE_IO, 0xf5, ADV748X_I2C_HDMI << 1},
- {ADV748X_PAGE_IO, 0xf6, ADV748X_I2C_EDID << 1},
- {ADV748X_PAGE_IO, 0xf7, ADV748X_I2C_REPEATER << 1},
- {ADV748X_PAGE_IO, 0xf8, ADV748X_I2C_INFOFRAME << 1},
- {ADV748X_PAGE_IO, 0xfa, ADV748X_I2C_CEC << 1},
- {ADV748X_PAGE_IO, 0xfb, ADV748X_I2C_SDP << 1},
- {ADV748X_PAGE_IO, 0xfc, ADV748X_I2C_TXB << 1},
- {ADV748X_PAGE_IO, 0xfd, ADV748X_I2C_TXA << 1},
- {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */
-};
-
/* Supported Formats For Script Below */
/* - 01-29 HDMI to MIPI TxA CSI 4-Lane - RGB888: */
static const struct adv748x_reg_value adv748x_init_txa_4lane[] = {
@@ -558,7 +487,7 @@ static int adv748x_reset(struct adv748x_state *state)
if (ret < 0)
return ret;
- ret = adv748x_write_regs(state, adv748x_set_slave_address);
+ ret = adv748x_set_slave_addresses(state);
if (ret < 0)
return ret;
@@ -715,7 +644,7 @@ static int adv748x_probe(struct i2c_client *client,
ret = adv748x_identify_chip(state);
if (ret) {
adv_err(state, "Failed to identify chip");
- goto err_cleanup_clients;
+ goto err_cleanup_dt;
}
/* Configure remaining pages as I2C clients with regmap access */
diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c
index 4da4253553fc..10d229a4f088 100644
--- a/drivers/media/i2c/adv748x/adv748x-hdmi.c
+++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c
@@ -105,6 +105,9 @@ static void adv748x_hdmi_fill_format(struct adv748x_hdmi *hdmi,
fmt->width = hdmi->timings.bt.width;
fmt->height = hdmi->timings.bt.height;
+
+ if (fmt->field == V4L2_FIELD_ALTERNATE)
+ fmt->height /= 2;
}
static void adv748x_fill_optional_dv_timings(struct v4l2_dv_timings *timings)
diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h
index 6789e2f3bc8c..65f83741277e 100644
--- a/drivers/media/i2c/adv748x/adv748x.h
+++ b/drivers/media/i2c/adv748x/adv748x.h
@@ -27,19 +27,6 @@
#ifndef _ADV748X_H_
#define _ADV748X_H_
-/* I2C slave addresses */
-#define ADV748X_I2C_IO 0x70 /* IO Map */
-#define ADV748X_I2C_DPLL 0x26 /* DPLL Map */
-#define ADV748X_I2C_CP 0x22 /* CP Map */
-#define ADV748X_I2C_HDMI 0x34 /* HDMI Map */
-#define ADV748X_I2C_EDID 0x36 /* EDID Map */
-#define ADV748X_I2C_REPEATER 0x32 /* HDMI RX Repeater Map */
-#define ADV748X_I2C_INFOFRAME 0x31 /* HDMI RX InfoFrame Map */
-#define ADV748X_I2C_CEC 0x41 /* CEC Map */
-#define ADV748X_I2C_SDP 0x79 /* SDP Map */
-#define ADV748X_I2C_TXB 0x48 /* CSI-TXB Map */
-#define ADV748X_I2C_TXA 0x4a /* CSI-TXA Map */
-
enum adv748x_page {
ADV748X_PAGE_IO,
ADV748X_PAGE_DPLL,
@@ -48,6 +35,7 @@ enum adv748x_page {
ADV748X_PAGE_EDID,
ADV748X_PAGE_REPEATER,
ADV748X_PAGE_INFOFRAME,
+ ADV748X_PAGE_CBUS,
ADV748X_PAGE_CEC,
ADV748X_PAGE_SDP,
ADV748X_PAGE_TXB,
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index 2817bafc67bf..d23505a411ee 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Analog Devices ADV7511 HDMI Transmitter Device Driver
*
* Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 1544920ec52d..cac2081e876e 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* adv7604 - Analog Devices ADV7604 video decoder driver
*
* Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
*/
/*
@@ -2734,6 +2722,27 @@ static const struct v4l2_ctrl_config adv76xx_ctrl_free_run_color = {
/* ----------------------------------------------------------------------- */
+struct adv76xx_register_map {
+ const char *name;
+ u8 default_addr;
+};
+
+static const struct adv76xx_register_map adv76xx_default_addresses[] = {
+ [ADV76XX_PAGE_IO] = { "main", 0x4c },
+ [ADV7604_PAGE_AVLINK] = { "avlink", 0x42 },
+ [ADV76XX_PAGE_CEC] = { "cec", 0x40 },
+ [ADV76XX_PAGE_INFOFRAME] = { "infoframe", 0x3e },
+ [ADV7604_PAGE_ESDP] = { "esdp", 0x38 },
+ [ADV7604_PAGE_DPP] = { "dpp", 0x3c },
+ [ADV76XX_PAGE_AFE] = { "afe", 0x26 },
+ [ADV76XX_PAGE_REP] = { "rep", 0x32 },
+ [ADV76XX_PAGE_EDID] = { "edid", 0x36 },
+ [ADV76XX_PAGE_HDMI] = { "hdmi", 0x34 },
+ [ADV76XX_PAGE_TEST] = { "test", 0x30 },
+ [ADV76XX_PAGE_CP] = { "cp", 0x22 },
+ [ADV7604_PAGE_VDP] = { "vdp", 0x24 },
+};
+
static int adv76xx_core_init(struct v4l2_subdev *sd)
{
struct adv76xx_state *state = to_state(sd);
@@ -2834,13 +2843,26 @@ static void adv76xx_unregister_clients(struct adv76xx_state *state)
}
static struct i2c_client *adv76xx_dummy_client(struct v4l2_subdev *sd,
- u8 addr, u8 io_reg)
+ unsigned int page)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct adv76xx_state *state = to_state(sd);
+ struct adv76xx_platform_data *pdata = &state->pdata;
+ unsigned int io_reg = 0xf2 + page;
+ struct i2c_client *new_client;
+
+ if (pdata && pdata->i2c_addresses[page])
+ new_client = i2c_new_dummy(client->adapter,
+ pdata->i2c_addresses[page]);
+ else
+ new_client = i2c_new_secondary_device(client,
+ adv76xx_default_addresses[page].name,
+ adv76xx_default_addresses[page].default_addr);
+
+ if (new_client)
+ io_write(sd, io_reg, new_client->addr << 1);
- if (addr)
- io_write(sd, io_reg, addr << 1);
- return i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1);
+ return new_client;
}
static const struct adv76xx_reg_seq adv7604_recommended_settings_afe[] = {
@@ -3115,20 +3137,6 @@ static int adv76xx_parse_dt(struct adv76xx_state *state)
/* Disable the interrupt for now as no DT-based board uses it. */
state->pdata.int1_config = ADV76XX_INT1_CONFIG_DISABLED;
- /* Use the default I2C addresses. */
- state->pdata.i2c_addresses[ADV7604_PAGE_AVLINK] = 0x42;
- state->pdata.i2c_addresses[ADV76XX_PAGE_CEC] = 0x40;
- state->pdata.i2c_addresses[ADV76XX_PAGE_INFOFRAME] = 0x3e;
- state->pdata.i2c_addresses[ADV7604_PAGE_ESDP] = 0x38;
- state->pdata.i2c_addresses[ADV7604_PAGE_DPP] = 0x3c;
- state->pdata.i2c_addresses[ADV76XX_PAGE_AFE] = 0x26;
- state->pdata.i2c_addresses[ADV76XX_PAGE_REP] = 0x32;
- state->pdata.i2c_addresses[ADV76XX_PAGE_EDID] = 0x36;
- state->pdata.i2c_addresses[ADV76XX_PAGE_HDMI] = 0x34;
- state->pdata.i2c_addresses[ADV76XX_PAGE_TEST] = 0x30;
- state->pdata.i2c_addresses[ADV76XX_PAGE_CP] = 0x22;
- state->pdata.i2c_addresses[ADV7604_PAGE_VDP] = 0x24;
-
/* Hardcode the remaining platform data fields. */
state->pdata.disable_pwrdnb = 0;
state->pdata.disable_cable_det_rst = 0;
@@ -3478,11 +3486,9 @@ static int adv76xx_probe(struct i2c_client *client,
if (!(BIT(i) & state->info->page_mask))
continue;
- state->i2c_clients[i] =
- adv76xx_dummy_client(sd, state->pdata.i2c_addresses[i],
- 0xf2 + i);
+ state->i2c_clients[i] = adv76xx_dummy_client(sd, i);
if (!state->i2c_clients[i]) {
- err = -ENOMEM;
+ err = -EINVAL;
v4l2_err(sd, "failed to create i2c client %u\n", i);
goto err_i2c;
}
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 136aa80a834b..fddac32e5051 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* adv7842 - Analog Devices ADV7842 video decoder driver
*
* Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
*/
/*
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index 98be63ae8590..b168bf3635b6 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -463,8 +463,13 @@ static void cx23885_initialize(struct i2c_client *client)
{
DEFINE_WAIT(wait);
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+ u32 clk_freq = 0;
struct workqueue_struct *q;
+ /* cx23885 sets hostdata to clk_freq pointer */
+ if (v4l2_get_subdev_hostdata(&state->sd))
+ clk_freq = *((u32 *)v4l2_get_subdev_hostdata(&state->sd));
+
/*
* Come out of digital power down
* The CX23888, at least, needs this, otherwise registers aside from
@@ -500,8 +505,13 @@ static void cx23885_initialize(struct i2c_client *client)
* 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz
* 572.73 MHz before post divide
*/
- /* HVR1850 or 50MHz xtal */
- cx25840_write(client, 0x2, 0x71);
+ if (clk_freq == 25000000) {
+ /* 888/ImpactVCBe or 25Mhz xtal */
+ ; /* nothing to do */
+ } else {
+ /* HVR1850 or 50MHz xtal */
+ cx25840_write(client, 0x2, 0x71);
+ }
cx25840_write4(client, 0x11c, 0x01d1744c);
cx25840_write4(client, 0x118, 0x00000416);
cx25840_write4(client, 0x404, 0x0010253e);
@@ -544,9 +554,15 @@ static void cx23885_initialize(struct i2c_client *client)
/* HVR1850 */
switch (state->id) {
case CX23888_AV:
- /* 888/HVR1250 specific */
- cx25840_write4(client, 0x10c, 0x13333333);
- cx25840_write4(client, 0x108, 0x00000515);
+ if (clk_freq == 25000000) {
+ /* 888/ImpactVCBe or 25MHz xtal */
+ cx25840_write4(client, 0x10c, 0x01b6db7b);
+ cx25840_write4(client, 0x108, 0x00000512);
+ } else {
+ /* 888/HVR1250 or 50MHz xtal */
+ cx25840_write4(client, 0x10c, 0x13333333);
+ cx25840_write4(client, 0x108, 0x00000515);
+ }
break;
default:
cx25840_write4(client, 0x10c, 0x002be2c9);
@@ -576,7 +592,7 @@ static void cx23885_initialize(struct i2c_client *client)
* 368.64 MHz before post divide
* 122.88 MHz / 0xa = 12.288 MHz
*/
- /* HVR1850 or 50MHz xtal */
+ /* HVR1850 or 50MHz xtal or 25MHz xtal */
cx25840_write4(client, 0x114, 0x017dbf48);
cx25840_write4(client, 0x110, 0x000a030e);
break;
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index 193020d64e51..a7e23bcf845c 100644
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -168,11 +168,15 @@ static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_proto *protocol,
static int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
+ int rc;
unsigned char b;
/* poll IR chip */
- if (1 != i2c_master_recv(ir->c, &b, 1)) {
+ rc = i2c_master_recv(ir->c, &b, 1);
+ if (rc != 1) {
dev_dbg(&ir->rc->dev, "read error\n");
+ if (rc < 0)
+ return rc;
return -EIO;
}
@@ -185,11 +189,15 @@ static int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol,
static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
+ int rc;
unsigned char buf[4];
/* poll IR chip */
- if (4 != i2c_master_recv(ir->c, buf, 4)) {
+ rc = i2c_master_recv(ir->c, buf, 4);
+ if (rc != 4) {
dev_dbg(&ir->rc->dev, "read error\n");
+ if (rc < 0)
+ return rc;
return -EIO;
}
@@ -209,11 +217,15 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol,
static int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
+ int rc;
unsigned char b;
/* poll IR chip */
- if (1 != i2c_master_recv(ir->c, &b, 1)) {
+ rc = i2c_master_recv(ir->c, &b, 1);
+ if (rc != 1) {
dev_dbg(&ir->rc->dev, "read error\n");
+ if (rc < 0)
+ return rc;
return -EIO;
}
@@ -571,7 +583,7 @@ static int zilog_ir_format(struct rc_dev *rcdev, unsigned int *txbuf,
/* first copy any leading non-repeating */
int leading = c - rep * 3;
- if (leading + rep >= ARRAY_SIZE(code_block->codes) - 3) {
+ if (leading >= ARRAY_SIZE(code_block->codes) - 3 - rep) {
dev_warn(&rcdev->dev, "IR too long, cannot transmit\n");
return -EINVAL;
}
diff --git a/drivers/media/i2c/max2175.c b/drivers/media/i2c/max2175.c
index 2f1966bdc473..87cba15b2977 100644
--- a/drivers/media/i2c/max2175.c
+++ b/drivers/media/i2c/max2175.c
@@ -643,7 +643,7 @@ static int max2175_set_nco_freq(struct max2175 *ctx, s32 nco_freq)
if (abs_nco_freq < clock_rate / 2) {
nco_val_desired = 2 * nco_freq;
} else {
- nco_val_desired = 2 * (clock_rate - abs_nco_freq);
+ nco_val_desired = 2LL * (clock_rate - abs_nco_freq);
if (nco_freq < 0)
nco_val_desired = -nco_val_desired;
}
diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c
new file mode 100644
index 000000000000..af8cca984215
--- /dev/null
+++ b/drivers/media/i2c/mt9t112.c
@@ -0,0 +1,1140 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt9t112 Camera Driver
+ *
+ * Copyright (C) 2018 Jacopo Mondi <jacopo+renesas@jmondi.org>
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov772x driver, mt9m111 driver,
+ *
+ * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * TODO: This driver lacks support for frame rate control due to missing
+ * register level documentation and suitable hardware for testing.
+ * v4l-utils compliance tools will report errors.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/i2c/mt9t112.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-subdev.h>
+
+/* you can check PLL/clock info */
+/* #define EXT_CLOCK 24000000 */
+
+/************************************************************************
+ * macro
+ ***********************************************************************/
+/*
+ * frame size
+ */
+#define MAX_WIDTH 2048
+#define MAX_HEIGHT 1536
+
+/*
+ * macro of read/write
+ */
+#define ECHECKER(ret, x) \
+ do { \
+ (ret) = (x); \
+ if ((ret) < 0) \
+ return (ret); \
+ } while (0)
+
+#define mt9t112_reg_write(ret, client, a, b) \
+ ECHECKER(ret, __mt9t112_reg_write(client, a, b))
+#define mt9t112_mcu_write(ret, client, a, b) \
+ ECHECKER(ret, __mt9t112_mcu_write(client, a, b))
+
+#define mt9t112_reg_mask_set(ret, client, a, b, c) \
+ ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c))
+#define mt9t112_mcu_mask_set(ret, client, a, b, c) \
+ ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c))
+
+#define mt9t112_reg_read(ret, client, a) \
+ ECHECKER(ret, __mt9t112_reg_read(client, a))
+
+/*
+ * Logical address
+ */
+#define _VAR(id, offset, base) (base | (id & 0x1f) << 10 | (offset & 0x3ff))
+#define VAR(id, offset) _VAR(id, offset, 0x0000)
+#define VAR8(id, offset) _VAR(id, offset, 0x8000)
+
+/************************************************************************
+ * struct
+ ***********************************************************************/
+struct mt9t112_format {
+ u32 code;
+ enum v4l2_colorspace colorspace;
+ u16 fmt;
+ u16 order;
+};
+
+struct mt9t112_priv {
+ struct v4l2_subdev subdev;
+ struct mt9t112_platform_data *info;
+ struct i2c_client *client;
+ struct v4l2_rect frame;
+ struct clk *clk;
+ struct gpio_desc *standby_gpio;
+ const struct mt9t112_format *format;
+ int num_formats;
+ bool init_done;
+};
+
+/************************************************************************
+ * supported format
+ ***********************************************************************/
+
+static const struct mt9t112_format mt9t112_cfmts[] = {
+ {
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt = 1,
+ .order = 0,
+ }, {
+ .code = MEDIA_BUS_FMT_VYUY8_2X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt = 1,
+ .order = 1,
+ }, {
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt = 1,
+ .order = 2,
+ }, {
+ .code = MEDIA_BUS_FMT_YVYU8_2X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt = 1,
+ .order = 3,
+ }, {
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt = 8,
+ .order = 2,
+ }, {
+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt = 4,
+ .order = 2,
+ },
+};
+
+/************************************************************************
+ * general function
+ ***********************************************************************/
+static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client),
+ struct mt9t112_priv,
+ subdev);
+}
+
+static int __mt9t112_reg_read(const struct i2c_client *client, u16 command)
+{
+ struct i2c_msg msg[2];
+ u8 buf[2];
+ int ret;
+
+ command = swab16(command);
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 2;
+ msg[0].buf = (u8 *)&command;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 2;
+ msg[1].buf = buf;
+
+ /*
+ * If return value of this function is < 0, it means error, else,
+ * below 16bit is valid data.
+ */
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0)
+ return ret;
+
+ memcpy(&ret, buf, 2);
+
+ return swab16(ret);
+}
+
+static int __mt9t112_reg_write(const struct i2c_client *client,
+ u16 command, u16 data)
+{
+ struct i2c_msg msg;
+ u8 buf[4];
+ int ret;
+
+ command = swab16(command);
+ data = swab16(data);
+
+ memcpy(buf + 0, &command, 2);
+ memcpy(buf + 2, &data, 2);
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 4;
+ msg.buf = buf;
+
+ /*
+ * i2c_transfer return message length, but this function should
+ * return 0 if correct case.
+ */
+ ret = i2c_transfer(client->adapter, &msg, 1);
+
+ return ret >= 0 ? 0 : ret;
+}
+
+static int __mt9t112_reg_mask_set(const struct i2c_client *client,
+ u16 command, u16 mask, u16 set)
+{
+ int val = __mt9t112_reg_read(client, command);
+
+ if (val < 0)
+ return val;
+
+ val &= ~mask;
+ val |= set & mask;
+
+ return __mt9t112_reg_write(client, command, val);
+}
+
+/* mcu access */
+static int __mt9t112_mcu_read(const struct i2c_client *client, u16 command)
+{
+ int ret;
+
+ ret = __mt9t112_reg_write(client, 0x098E, command);
+ if (ret < 0)
+ return ret;
+
+ return __mt9t112_reg_read(client, 0x0990);
+}
+
+static int __mt9t112_mcu_write(const struct i2c_client *client,
+ u16 command, u16 data)
+{
+ int ret;
+
+ ret = __mt9t112_reg_write(client, 0x098E, command);
+ if (ret < 0)
+ return ret;
+
+ return __mt9t112_reg_write(client, 0x0990, data);
+}
+
+static int __mt9t112_mcu_mask_set(const struct i2c_client *client,
+ u16 command, u16 mask, u16 set)
+{
+ int val = __mt9t112_mcu_read(client, command);
+
+ if (val < 0)
+ return val;
+
+ val &= ~mask;
+ val |= set & mask;
+
+ return __mt9t112_mcu_write(client, command, val);
+}
+
+static int mt9t112_reset(const struct i2c_client *client)
+{
+ int ret;
+
+ mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001);
+ usleep_range(1000, 5000);
+ mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000);
+
+ return ret;
+}
+
+#ifndef EXT_CLOCK
+#define CLOCK_INFO(a, b)
+#else
+#define CLOCK_INFO(a, b) mt9t112_clock_info(a, b)
+static int mt9t112_clock_info(const struct i2c_client *client, u32 ext)
+{
+ int m, n, p1, p2, p3, p4, p5, p6, p7;
+ u32 vco, clk;
+ char *enable;
+
+ ext /= 1000; /* kbyte order */
+
+ mt9t112_reg_read(n, client, 0x0012);
+ p1 = n & 0x000f;
+ n = n >> 4;
+ p2 = n & 0x000f;
+ n = n >> 4;
+ p3 = n & 0x000f;
+
+ mt9t112_reg_read(n, client, 0x002a);
+ p4 = n & 0x000f;
+ n = n >> 4;
+ p5 = n & 0x000f;
+ n = n >> 4;
+ p6 = n & 0x000f;
+
+ mt9t112_reg_read(n, client, 0x002c);
+ p7 = n & 0x000f;
+
+ mt9t112_reg_read(n, client, 0x0010);
+ m = n & 0x00ff;
+ n = (n >> 8) & 0x003f;
+
+ enable = ((ext < 6000) || (ext > 54000)) ? "X" : "";
+ dev_dbg(&client->dev, "EXTCLK : %10u K %s\n", ext, enable);
+
+ vco = 2 * m * ext / (n + 1);
+ enable = ((vco < 384000) || (vco > 768000)) ? "X" : "";
+ dev_dbg(&client->dev, "VCO : %10u K %s\n", vco, enable);
+
+ clk = vco / (p1 + 1) / (p2 + 1);
+ enable = (clk > 96000) ? "X" : "";
+ dev_dbg(&client->dev, "PIXCLK : %10u K %s\n", clk, enable);
+
+ clk = vco / (p3 + 1);
+ enable = (clk > 768000) ? "X" : "";
+ dev_dbg(&client->dev, "MIPICLK : %10u K %s\n", clk, enable);
+
+ clk = vco / (p6 + 1);
+ enable = (clk > 96000) ? "X" : "";
+ dev_dbg(&client->dev, "MCU CLK : %10u K %s\n", clk, enable);
+
+ clk = vco / (p5 + 1);
+ enable = (clk > 54000) ? "X" : "";
+ dev_dbg(&client->dev, "SOC CLK : %10u K %s\n", clk, enable);
+
+ clk = vco / (p4 + 1);
+ enable = (clk > 70000) ? "X" : "";
+ dev_dbg(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable);
+
+ clk = vco / (p7 + 1);
+ dev_dbg(&client->dev, "External sensor : %10u K\n", clk);
+
+ clk = ext / (n + 1);
+ enable = ((clk < 2000) || (clk > 24000)) ? "X" : "";
+ dev_dbg(&client->dev, "PFD : %10u K %s\n", clk, enable);
+
+ return 0;
+}
+#endif
+
+static int mt9t112_set_a_frame_size(const struct i2c_client *client,
+ u16 width, u16 height)
+{
+ int ret;
+ u16 wstart = (MAX_WIDTH - width) / 2;
+ u16 hstart = (MAX_HEIGHT - height) / 2;
+
+ /* (Context A) Image Width/Height. */
+ mt9t112_mcu_write(ret, client, VAR(26, 0), width);
+ mt9t112_mcu_write(ret, client, VAR(26, 2), height);
+
+ /* (Context A) Output Width/Height. */
+ mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width);
+ mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height);
+
+ /* (Context A) Start Row/Column. */
+ mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart);
+ mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart);
+
+ /* (Context A) End Row/Column. */
+ mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart);
+ mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width + wstart);
+
+ mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
+
+ return ret;
+}
+
+static int mt9t112_set_pll_dividers(const struct i2c_client *client,
+ u8 m, u8 n, u8 p1, u8 p2, u8 p3, u8 p4,
+ u8 p5, u8 p6, u8 p7)
+{
+ int ret;
+ u16 val;
+
+ /* N/M */
+ val = (n << 8) | (m << 0);
+ mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val);
+
+ /* P1/P2/P3 */
+ val = ((p3 & 0x0F) << 8) | ((p2 & 0x0F) << 4) | ((p1 & 0x0F) << 0);
+ mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val);
+
+ /* P4/P5/P6 */
+ val = (0x7 << 12) | ((p6 & 0x0F) << 8) | ((p5 & 0x0F) << 4) |
+ ((p4 & 0x0F) << 0);
+ mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val);
+
+ /* P7 */
+ val = (0x1 << 12) | ((p7 & 0x0F) << 0);
+ mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val);
+
+ return ret;
+}
+
+static int mt9t112_init_pll(const struct i2c_client *client)
+{
+ struct mt9t112_priv *priv = to_mt9t112(client);
+ int data, i, ret;
+
+ mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001);
+
+ /* PLL control: BYPASS PLL = 8517. */
+ mt9t112_reg_write(ret, client, 0x0014, 0x2145);
+
+ /* Replace these registers when new timing parameters are generated. */
+ mt9t112_set_pll_dividers(client,
+ priv->info->divider.m, priv->info->divider.n,
+ priv->info->divider.p1, priv->info->divider.p2,
+ priv->info->divider.p3, priv->info->divider.p4,
+ priv->info->divider.p5, priv->info->divider.p6,
+ priv->info->divider.p7);
+
+ /*
+ * TEST_BYPASS on
+ * PLL_ENABLE on
+ * SEL_LOCK_DET on
+ * TEST_BYPASS off
+ */
+ mt9t112_reg_write(ret, client, 0x0014, 0x2525);
+ mt9t112_reg_write(ret, client, 0x0014, 0x2527);
+ mt9t112_reg_write(ret, client, 0x0014, 0x3427);
+ mt9t112_reg_write(ret, client, 0x0014, 0x3027);
+
+ mdelay(10);
+
+ /*
+ * PLL_BYPASS off
+ * Reference clock count
+ * I2C Master Clock Divider
+ */
+ mt9t112_reg_write(ret, client, 0x0014, 0x3046);
+ /* JPEG initialization workaround */
+ mt9t112_reg_write(ret, client, 0x0016, 0x0400);
+ mt9t112_reg_write(ret, client, 0x0022, 0x0190);
+ mt9t112_reg_write(ret, client, 0x3B84, 0x0212);
+
+ /* External sensor clock is PLL bypass. */
+ mt9t112_reg_write(ret, client, 0x002E, 0x0500);
+
+ mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002);
+ mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004);
+
+ /* MCU disabled. */
+ mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004);
+
+ /* Out of standby. */
+ mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0);
+
+ mdelay(50);
+
+ /*
+ * Standby Workaround
+ * Disable Secondary I2C Pads
+ */
+ mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+ mdelay(1);
+ mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+ mdelay(1);
+ mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+ mdelay(1);
+ mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+ mdelay(1);
+ mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+ mdelay(1);
+ mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+ mdelay(1);
+
+ /* Poll to verify out of standby. Must Poll this bit. */
+ for (i = 0; i < 100; i++) {
+ mt9t112_reg_read(data, client, 0x0018);
+ if (!(data & 0x4000))
+ break;
+
+ mdelay(10);
+ }
+
+ return ret;
+}
+
+static int mt9t112_init_setting(const struct i2c_client *client)
+{
+ int ret;
+
+ /* Adaptive Output Clock (A) */
+ mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000);
+
+ /* Read Mode (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024);
+
+ /* Fine Correction (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC);
+
+ /* Fine IT Min (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1);
+
+ /* Fine IT Max Margin (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF);
+
+ /* Base Frame Lines (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D);
+
+ /* Min Line Length (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a);
+
+ /* Line Length (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0);
+
+ /* Adaptive Output Clock (B) */
+ mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000);
+
+ /* Row Start (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004);
+
+ /* Column Start (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004);
+
+ /* Row End (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B);
+
+ /* Column End (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B);
+
+ /* Fine Correction (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C);
+
+ /* Fine IT Min (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1);
+
+ /* Fine IT Max Margin (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF);
+
+ /* Base Frame Lines (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668);
+
+ /* Min Line Length (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0);
+
+ /* Line Length (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0);
+
+ /*
+ * Flicker Dectection registers.
+ * This section should be replaced whenever new timing file is
+ * generated. All the following registers need to be replaced.
+ * Following registers are generated from Register Wizard but user can
+ * modify them. For detail see auto flicker detection tuning.
+ */
+
+ /* FD_FDPERIOD_SELECT */
+ mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01);
+
+ /* PRI_B_CONFIG_FD_ALGO_RUN */
+ mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003);
+
+ /* PRI_A_CONFIG_FD_ALGO_RUN */
+ mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003);
+
+ /*
+ * AFD range detection tuning registers.
+ */
+
+ /* Search_f1_50 */
+ mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25);
+
+ /* Search_f2_50 */
+ mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28);
+
+ /* Search_f1_60 */
+ mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C);
+
+ /* Search_f2_60 */
+ mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F);
+
+ /* Period_50Hz (A) */
+ mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA);
+
+ /* Secret register by Aptina. */
+ /* Period_50Hz (A MSB) */
+ mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00);
+
+ /* Period_60Hz (A) */
+ mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B);
+
+ /* Secret register by Aptina. */
+ /* Period_60Hz (A MSB) */
+ mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00);
+
+ /* Period_50Hz (B) */
+ mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82);
+
+ /* Secret register by Aptina. */
+ /* Period_50Hz (B) MSB */
+ mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00);
+
+ /* Period_60Hz (B) */
+ mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D);
+
+ /* Secret register by Aptina. */
+ /* Period_60Hz (B) MSB */
+ mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00);
+
+ /* FD Mode */
+ mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10);
+
+ /* Stat_min */
+ mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02);
+
+ /* Stat_max */
+ mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03);
+
+ /* Min_amplitude */
+ mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A);
+
+ /* RX FIFO Watermark (A) */
+ mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014);
+
+ /* RX FIFO Watermark (B) */
+ mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014);
+
+ /* MCLK: 16MHz
+ * PCLK: 73MHz
+ * CorePixCLK: 36.5 MHz
+ */
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133);
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110);
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130);
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108);
+
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27);
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30);
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32);
+ mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35);
+
+ return ret;
+}
+
+static int mt9t112_auto_focus_setting(const struct i2c_client *client)
+{
+ int ret;
+
+ mt9t112_mcu_write(ret, client, VAR(12, 13), 0x000F);
+ mt9t112_mcu_write(ret, client, VAR(12, 23), 0x0F0F);
+ mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
+
+ mt9t112_reg_write(ret, client, 0x0614, 0x0000);
+
+ mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05);
+ mt9t112_mcu_write(ret, client, VAR8(12, 2), 0x02);
+ mt9t112_mcu_write(ret, client, VAR(12, 3), 0x0002);
+ mt9t112_mcu_write(ret, client, VAR(17, 3), 0x8001);
+ mt9t112_mcu_write(ret, client, VAR(17, 11), 0x0025);
+ mt9t112_mcu_write(ret, client, VAR(17, 13), 0x0193);
+ mt9t112_mcu_write(ret, client, VAR8(17, 33), 0x18);
+ mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05);
+
+ return ret;
+}
+
+static int mt9t112_auto_focus_trigger(const struct i2c_client *client)
+{
+ int ret;
+
+ mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01);
+
+ return ret;
+}
+
+static int mt9t112_init_camera(const struct i2c_client *client)
+{
+ int ret;
+
+ ECHECKER(ret, mt9t112_reset(client));
+ ECHECKER(ret, mt9t112_init_pll(client));
+ ECHECKER(ret, mt9t112_init_setting(client));
+ ECHECKER(ret, mt9t112_auto_focus_setting(client));
+
+ mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0);
+
+ /* Analog setting B.*/
+ mt9t112_reg_write(ret, client, 0x3084, 0x2409);
+ mt9t112_reg_write(ret, client, 0x3092, 0x0A49);
+ mt9t112_reg_write(ret, client, 0x3094, 0x4949);
+ mt9t112_reg_write(ret, client, 0x3096, 0x4950);
+
+ /*
+ * Disable adaptive clock.
+ * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR
+ * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR
+ */
+ mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E);
+ mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E);
+
+ /*
+ * Configure Status in Status_before_length Format and enable header.
+ * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR
+ */
+ mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4);
+
+ /*
+ * Enable JPEG in context B.
+ * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR
+ */
+ mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01);
+
+ /* Disable Dac_TXLO. */
+ mt9t112_reg_write(ret, client, 0x316C, 0x350F);
+
+ /* Set max slew rates. */
+ mt9t112_reg_write(ret, client, 0x1E, 0x777);
+
+ return ret;
+}
+
+/************************************************************************
+ * v4l2_subdev_core_ops
+ ***********************************************************************/
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9t112_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ reg->size = 2;
+ mt9t112_reg_read(ret, client, reg->reg);
+
+ reg->val = (__u64)ret;
+
+ return 0;
+}
+
+static int mt9t112_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ mt9t112_reg_write(ret, client, reg->reg, reg->val);
+
+ return ret;
+}
+#endif
+
+static int mt9t112_power_on(struct mt9t112_priv *priv)
+{
+ int ret;
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ if (priv->standby_gpio) {
+ gpiod_set_value(priv->standby_gpio, 0);
+ msleep(100);
+ }
+
+ return 0;
+}
+
+static int mt9t112_power_off(struct mt9t112_priv *priv)
+{
+ clk_disable_unprepare(priv->clk);
+ if (priv->standby_gpio) {
+ gpiod_set_value(priv->standby_gpio, 1);
+ msleep(100);
+ }
+
+ return 0;
+}
+
+static int mt9t112_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+
+ return on ? mt9t112_power_on(priv) :
+ mt9t112_power_off(priv);
+}
+
+static const struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = mt9t112_g_register,
+ .s_register = mt9t112_s_register,
+#endif
+ .s_power = mt9t112_s_power,
+};
+
+/************************************************************************
+ * v4l2_subdev_video_ops
+ **********************************************************************/
+static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+ int ret = 0;
+
+ if (!enable) {
+ /* FIXME
+ *
+ * If user selected large output size, and used it long time,
+ * mt9t112 camera will be very warm.
+ *
+ * But current driver can not stop mt9t112 camera.
+ * So, set small size here to solve this problem.
+ */
+ mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT);
+ return ret;
+ }
+
+ if (!priv->init_done) {
+ u16 param = MT9T112_FLAG_PCLK_RISING_EDGE & priv->info->flags ?
+ 0x0001 : 0x0000;
+
+ ECHECKER(ret, mt9t112_init_camera(client));
+
+ /* Invert PCLK (Data sampled on falling edge of pixclk). */
+ mt9t112_reg_write(ret, client, 0x3C20, param);
+
+ mdelay(5);
+
+ priv->init_done = true;
+ }
+
+ mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt);
+ mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order);
+ mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
+
+ mt9t112_set_a_frame_size(client, priv->frame.width, priv->frame.height);
+
+ ECHECKER(ret, mt9t112_auto_focus_trigger(client));
+
+ dev_dbg(&client->dev, "format : %d\n", priv->format->code);
+ dev_dbg(&client->dev, "size : %d x %d\n",
+ priv->frame.width,
+ priv->frame.height);
+
+ CLOCK_INFO(client, EXT_CLOCK);
+
+ return ret;
+}
+
+static int mt9t112_set_params(struct mt9t112_priv *priv,
+ const struct v4l2_rect *rect,
+ u32 code)
+{
+ int i;
+
+ /*
+ * get color format
+ */
+ for (i = 0; i < priv->num_formats; i++)
+ if (mt9t112_cfmts[i].code == code)
+ break;
+
+ if (i == priv->num_formats)
+ return -EINVAL;
+
+ priv->frame = *rect;
+
+ /*
+ * frame size check
+ */
+ v4l_bound_align_image(&priv->frame.width, 0, MAX_WIDTH, 0,
+ &priv->frame.height, 0, MAX_HEIGHT, 0, 0);
+
+ priv->format = mt9t112_cfmts + i;
+
+ return 0;
+}
+
+static int mt9t112_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+
+ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = MAX_WIDTH;
+ sel->r.height = MAX_HEIGHT;
+ return 0;
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = VGA_WIDTH;
+ sel->r.height = VGA_HEIGHT;
+ return 0;
+ case V4L2_SEL_TGT_CROP:
+ sel->r = priv->frame;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mt9t112_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+ const struct v4l2_rect *rect = &sel->r;
+
+ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
+ sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ return mt9t112_set_params(priv, rect, priv->format->code);
+}
+
+static int mt9t112_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct v4l2_mbus_framefmt *mf = &format->format;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+
+ if (format->pad)
+ return -EINVAL;
+
+ mf->width = priv->frame.width;
+ mf->height = priv->frame.height;
+ mf->colorspace = priv->format->colorspace;
+ mf->code = priv->format->code;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int mt9t112_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+ struct v4l2_rect rect = {
+ .width = mf->width,
+ .height = mf->height,
+ .left = priv->frame.left,
+ .top = priv->frame.top,
+ };
+ int ret;
+
+ ret = mt9t112_set_params(priv, &rect, mf->code);
+
+ if (!ret)
+ mf->colorspace = priv->format->colorspace;
+
+ return ret;
+}
+
+static int mt9t112_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *mf = &format->format;
+ struct mt9t112_priv *priv = to_mt9t112(client);
+ int i;
+
+ if (format->pad)
+ return -EINVAL;
+
+ for (i = 0; i < priv->num_formats; i++)
+ if (mt9t112_cfmts[i].code == mf->code)
+ break;
+
+ if (i == priv->num_formats) {
+ mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ } else {
+ mf->colorspace = mt9t112_cfmts[i].colorspace;
+ }
+
+ v4l_bound_align_image(&mf->width, 0, MAX_WIDTH, 0,
+ &mf->height, 0, MAX_HEIGHT, 0, 0);
+
+ mf->field = V4L2_FIELD_NONE;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ return mt9t112_s_fmt(sd, mf);
+ cfg->try_fmt = *mf;
+
+ return 0;
+}
+
+static int mt9t112_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t112_priv *priv = to_mt9t112(client);
+
+ if (code->pad || code->index >= priv->num_formats)
+ return -EINVAL;
+
+ code->code = mt9t112_cfmts[code->index].code;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = {
+ .s_stream = mt9t112_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = {
+ .enum_mbus_code = mt9t112_enum_mbus_code,
+ .get_selection = mt9t112_get_selection,
+ .set_selection = mt9t112_set_selection,
+ .get_fmt = mt9t112_get_fmt,
+ .set_fmt = mt9t112_set_fmt,
+};
+
+/************************************************************************
+ * i2c driver
+ ***********************************************************************/
+static const struct v4l2_subdev_ops mt9t112_subdev_ops = {
+ .core = &mt9t112_subdev_core_ops,
+ .video = &mt9t112_subdev_video_ops,
+ .pad = &mt9t112_subdev_pad_ops,
+};
+
+static int mt9t112_camera_probe(struct i2c_client *client)
+{
+ struct mt9t112_priv *priv = to_mt9t112(client);
+ const char *devname;
+ int chipid;
+ int ret;
+
+ ret = mt9t112_s_power(&priv->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Check and show chip ID. */
+ mt9t112_reg_read(chipid, client, 0x0000);
+
+ switch (chipid) {
+ case 0x2680:
+ devname = "mt9t111";
+ priv->num_formats = 1;
+ break;
+ case 0x2682:
+ devname = "mt9t112";
+ priv->num_formats = ARRAY_SIZE(mt9t112_cfmts);
+ break;
+ default:
+ dev_err(&client->dev, "Product ID error %04x\n", chipid);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid);
+
+done:
+ mt9t112_s_power(&priv->subdev, 0);
+
+ return ret;
+}
+
+static int mt9t112_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct mt9t112_priv *priv;
+ int ret;
+
+ if (!client->dev.platform_data) {
+ dev_err(&client->dev, "mt9t112: missing platform data!\n");
+ return -EINVAL;
+ }
+
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->info = client->dev.platform_data;
+ priv->init_done = false;
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops);
+
+ priv->clk = devm_clk_get(&client->dev, "extclk");
+ if (PTR_ERR(priv->clk) == -ENOENT) {
+ priv->clk = NULL;
+ } else if (IS_ERR(priv->clk)) {
+ dev_err(&client->dev, "Unable to get clock \"extclk\"\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ priv->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->standby_gpio)) {
+ dev_err(&client->dev, "Unable to get gpio \"standby\"\n");
+ return PTR_ERR(priv->standby_gpio);
+ }
+
+ ret = mt9t112_camera_probe(client);
+ if (ret)
+ return ret;
+
+ return v4l2_async_register_subdev(&priv->subdev);
+}
+
+static int mt9t112_remove(struct i2c_client *client)
+{
+ struct mt9t112_priv *priv = to_mt9t112(client);
+
+ clk_disable_unprepare(priv->clk);
+ v4l2_async_unregister_subdev(&priv->subdev);
+
+ return 0;
+}
+
+static const struct i2c_device_id mt9t112_id[] = {
+ { "mt9t112", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9t112_id);
+
+static struct i2c_driver mt9t112_i2c_driver = {
+ .driver = {
+ .name = "mt9t112",
+ },
+ .probe = mt9t112_probe,
+ .remove = mt9t112_remove,
+ .id_table = mt9t112_id,
+};
+
+module_i2c_driver(mt9t112_i2c_driver);
+
+MODULE_DESCRIPTION("V4L2 driver for MT9T111/MT9T112 camera sensor");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
index 5e29064fae91..46ef74a2ca36 100644
--- a/drivers/media/i2c/mt9v011.c
+++ b/drivers/media/i2c/mt9v011.c
@@ -364,33 +364,22 @@ static int mt9v011_set_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int mt9v011_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+static int mt9v011_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *ival)
{
- struct v4l2_captureparm *cp = &parms->parm.capture;
-
- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- memset(cp, 0, sizeof(struct v4l2_captureparm));
- cp->capability = V4L2_CAP_TIMEPERFRAME;
calc_fps(sd,
- &cp->timeperframe.numerator,
- &cp->timeperframe.denominator);
+ &ival->interval.numerator,
+ &ival->interval.denominator);
return 0;
}
-static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+static int mt9v011_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *ival)
{
- struct v4l2_captureparm *cp = &parms->parm.capture;
- struct v4l2_fract *tpf = &cp->timeperframe;
+ struct v4l2_fract *tpf = &ival->interval;
u16 speed;
- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (cp->extendedmode != 0)
- return -EINVAL;
-
speed = calc_speed(sd, tpf->numerator, tpf->denominator);
mt9v011_write(sd, R0A_MT9V011_CLK_SPEED, speed);
@@ -469,8 +458,8 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
};
static const struct v4l2_subdev_video_ops mt9v011_video_ops = {
- .g_parm = mt9v011_g_parm,
- .s_parm = mt9v011_s_parm,
+ .g_frame_interval = mt9v011_g_frame_interval,
+ .s_frame_interval = mt9v011_s_frame_interval,
};
static const struct v4l2_subdev_pad_ops mt9v011_pad_ops = {
diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c
index bf7d06f3f21a..30ee9f71bf0d 100644
--- a/drivers/media/i2c/ov13858.c
+++ b/drivers/media/i2c/ov13858.c
@@ -194,6 +194,7 @@ static const struct ov13858_reg mode_4224x3136_regs[] = {
{0x3624, 0x1c},
{0x3640, 0x10},
{0x3641, 0x70},
+ {0x3660, 0x04},
{0x3661, 0x80},
{0x3662, 0x12},
{0x3664, 0x73},
@@ -384,6 +385,7 @@ static const struct ov13858_reg mode_2112x1568_regs[] = {
{0x3624, 0x1c},
{0x3640, 0x10},
{0x3641, 0x70},
+ {0x3660, 0x04},
{0x3661, 0x80},
{0x3662, 0x10},
{0x3664, 0x73},
@@ -574,6 +576,7 @@ static const struct ov13858_reg mode_2112x1188_regs[] = {
{0x3624, 0x1c},
{0x3640, 0x10},
{0x3641, 0x70},
+ {0x3660, 0x04},
{0x3661, 0x80},
{0x3662, 0x10},
{0x3664, 0x73},
@@ -764,6 +767,7 @@ static const struct ov13858_reg mode_1056x784_regs[] = {
{0x3624, 0x1c},
{0x3640, 0x10},
{0x3641, 0x70},
+ {0x3660, 0x04},
{0x3661, 0x80},
{0x3662, 0x08},
{0x3664, 0x73},
@@ -1057,14 +1061,15 @@ struct ov13858 {
#define to_ov13858(_sd) container_of(_sd, struct ov13858, sd)
/* Read registers up to 4 at a time */
-static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 *val)
+static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len,
+ u32 *val)
{
struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd);
struct i2c_msg msgs[2];
u8 *data_be_p;
int ret;
- u32 data_be = 0;
- u16 reg_addr_be = cpu_to_be16(reg);
+ __be32 data_be = 0;
+ __be16 reg_addr_be = cpu_to_be16(reg);
if (len > 4)
return -EINVAL;
@@ -1092,11 +1097,13 @@ static int ov13858_read_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 *val)
}
/* Write registers up to 4 at a time */
-static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 val)
+static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len,
+ u32 __val)
{
struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd);
int buf_i, val_i;
u8 buf[6], *val_p;
+ __be32 val;
if (len > 4)
return -EINVAL;
@@ -1104,7 +1111,7 @@ static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len, u32 val)
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
- val = cpu_to_be32(val);
+ val = cpu_to_be32(__val);
val_p = (u8 *)&val;
buf_i = 2;
val_i = 4 - len;
@@ -1348,39 +1355,6 @@ static int ov13858_get_pad_format(struct v4l2_subdev *sd,
return ret;
}
-/*
- * Calculate resolution distance
- */
-static int
-ov13858_get_resolution_dist(const struct ov13858_mode *mode,
- struct v4l2_mbus_framefmt *framefmt)
-{
- return abs(mode->width - framefmt->width) +
- abs(mode->height - framefmt->height);
-}
-
-/*
- * Find the closest supported resolution to the requested resolution
- */
-static const struct ov13858_mode *
-ov13858_find_best_fit(struct ov13858 *ov13858,
- struct v4l2_subdev_format *fmt)
-{
- int i, dist, cur_best_fit = 0, cur_best_fit_dist = -1;
- struct v4l2_mbus_framefmt *framefmt = &fmt->format;
-
- for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
- dist = ov13858_get_resolution_dist(&supported_modes[i],
- framefmt);
- if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
- cur_best_fit_dist = dist;
- cur_best_fit = i;
- }
- }
-
- return &supported_modes[cur_best_fit];
-}
-
static int
ov13858_set_pad_format(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
@@ -1401,7 +1375,8 @@ ov13858_set_pad_format(struct v4l2_subdev *sd,
if (fmt->format.code != MEDIA_BUS_FMT_SGRBG10_1X10)
fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
- mode = ov13858_find_best_fit(ov13858, fmt);
+ mode = v4l2_find_nearest_size(supported_modes, width, height,
+ fmt->format.width, fmt->format.height);
ov13858_update_pad_format(mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
@@ -1565,7 +1540,7 @@ static int __maybe_unused ov13858_resume(struct device *dev)
error:
ov13858_stop_streaming(ov13858);
- ov13858->streaming = 0;
+ ov13858->streaming = false;
return ret;
}
diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c
new file mode 100644
index 000000000000..83c55e8288e7
--- /dev/null
+++ b/drivers/media/i2c/ov2685.c
@@ -0,0 +1,846 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ov2685 driver
+ *
+ * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sysfs.h>
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#define CHIP_ID 0x2685
+#define OV2685_REG_CHIP_ID 0x300a
+
+#define OV2685_XVCLK_FREQ 24000000
+
+#define REG_SC_CTRL_MODE 0x0100
+#define SC_CTRL_MODE_STANDBY 0x0
+#define SC_CTRL_MODE_STREAMING BIT(0)
+
+#define OV2685_REG_EXPOSURE 0x3500
+#define OV2685_EXPOSURE_MIN 4
+#define OV2685_EXPOSURE_STEP 1
+
+#define OV2685_REG_VTS 0x380e
+#define OV2685_VTS_MAX 0x7fff
+
+#define OV2685_REG_GAIN 0x350a
+#define OV2685_GAIN_MIN 0
+#define OV2685_GAIN_MAX 0x07ff
+#define OV2685_GAIN_STEP 0x1
+#define OV2685_GAIN_DEFAULT 0x0036
+
+#define OV2685_REG_TEST_PATTERN 0x5080
+#define OV2685_TEST_PATTERN_DISABLED 0x00
+#define OV2685_TEST_PATTERN_COLOR_BAR 0x80
+#define OV2685_TEST_PATTERN_RANDOM 0x81
+#define OV2685_TEST_PATTERN_COLOR_BAR_FADE 0x88
+#define OV2685_TEST_PATTERN_BW_SQUARE 0x92
+#define OV2685_TEST_PATTERN_COLOR_SQUARE 0x82
+
+#define REG_NULL 0xFFFF
+
+#define OV2685_REG_VALUE_08BIT 1
+#define OV2685_REG_VALUE_16BIT 2
+#define OV2685_REG_VALUE_24BIT 3
+
+#define OV2685_LANES 1
+#define OV2685_BITS_PER_SAMPLE 10
+
+static const char * const ov2685_supply_names[] = {
+ "avdd", /* Analog power */
+ "dovdd", /* Digital I/O power */
+ "dvdd", /* Digital core power */
+};
+
+#define OV2685_NUM_SUPPLIES ARRAY_SIZE(ov2685_supply_names)
+
+struct regval {
+ u16 addr;
+ u8 val;
+};
+
+struct ov2685_mode {
+ u32 width;
+ u32 height;
+ u32 exp_def;
+ u32 hts_def;
+ u32 vts_def;
+ const struct regval *reg_list;
+};
+
+struct ov2685 {
+ struct i2c_client *client;
+ struct clk *xvclk;
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[OV2685_NUM_SUPPLIES];
+
+ bool streaming;
+ struct mutex mutex;
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+ struct v4l2_ctrl *anal_gain;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *test_pattern;
+ struct v4l2_ctrl_handler ctrl_handler;
+
+ const struct ov2685_mode *cur_mode;
+};
+
+#define to_ov2685(sd) container_of(sd, struct ov2685, subdev)
+
+/* PLL settings bases on 24M xvclk */
+static struct regval ov2685_1600x1200_regs[] = {
+ {0x0103, 0x01},
+ {0x0100, 0x00},
+ {0x3002, 0x00},
+ {0x3016, 0x1c},
+ {0x3018, 0x44},
+ {0x301d, 0xf0},
+ {0x3020, 0x00},
+ {0x3082, 0x37},
+ {0x3083, 0x03},
+ {0x3084, 0x09},
+ {0x3085, 0x04},
+ {0x3086, 0x00},
+ {0x3087, 0x00},
+ {0x3501, 0x4e},
+ {0x3502, 0xe0},
+ {0x3503, 0x27},
+ {0x350b, 0x36},
+ {0x3600, 0xb4},
+ {0x3603, 0x35},
+ {0x3604, 0x24},
+ {0x3605, 0x00},
+ {0x3620, 0x24},
+ {0x3621, 0x34},
+ {0x3622, 0x03},
+ {0x3628, 0x10},
+ {0x3705, 0x3c},
+ {0x370a, 0x21},
+ {0x370c, 0x50},
+ {0x370d, 0xc0},
+ {0x3717, 0x58},
+ {0x3718, 0x80},
+ {0x3720, 0x00},
+ {0x3721, 0x09},
+ {0x3722, 0x06},
+ {0x3723, 0x59},
+ {0x3738, 0x99},
+ {0x3781, 0x80},
+ {0x3784, 0x0c},
+ {0x3789, 0x60},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x06},
+ {0x3805, 0x4f},
+ {0x3806, 0x04},
+ {0x3807, 0xbf},
+ {0x3808, 0x06},
+ {0x3809, 0x40},
+ {0x380a, 0x04},
+ {0x380b, 0xb0},
+ {0x380c, 0x06},
+ {0x380d, 0xa4},
+ {0x380e, 0x05},
+ {0x380f, 0x0e},
+ {0x3810, 0x00},
+ {0x3811, 0x08},
+ {0x3812, 0x00},
+ {0x3813, 0x08},
+ {0x3814, 0x11},
+ {0x3815, 0x11},
+ {0x3819, 0x04},
+ {0x3820, 0xc0},
+ {0x3821, 0x00},
+ {0x3a06, 0x01},
+ {0x3a07, 0x84},
+ {0x3a08, 0x01},
+ {0x3a09, 0x43},
+ {0x3a0a, 0x24},
+ {0x3a0b, 0x60},
+ {0x3a0c, 0x28},
+ {0x3a0d, 0x60},
+ {0x3a0e, 0x04},
+ {0x3a0f, 0x8c},
+ {0x3a10, 0x05},
+ {0x3a11, 0x0c},
+ {0x4000, 0x81},
+ {0x4001, 0x40},
+ {0x4008, 0x02},
+ {0x4009, 0x09},
+ {0x4300, 0x00},
+ {0x430e, 0x00},
+ {0x4602, 0x02},
+ {0x481b, 0x40},
+ {0x481f, 0x40},
+ {0x4837, 0x18},
+ {0x5000, 0x1f},
+ {0x5001, 0x05},
+ {0x5002, 0x30},
+ {0x5003, 0x04},
+ {0x5004, 0x00},
+ {0x5005, 0x0c},
+ {0x5280, 0x15},
+ {0x5281, 0x06},
+ {0x5282, 0x06},
+ {0x5283, 0x08},
+ {0x5284, 0x1c},
+ {0x5285, 0x1c},
+ {0x5286, 0x20},
+ {0x5287, 0x10},
+ {REG_NULL, 0x00}
+};
+
+#define OV2685_LINK_FREQ_330MHZ 330000000
+static const s64 link_freq_menu_items[] = {
+ OV2685_LINK_FREQ_330MHZ
+};
+
+static const char * const ov2685_test_pattern_menu[] = {
+ "Disabled",
+ "Color Bar",
+ "Color Bar FADE",
+ "Random Data",
+ "Black White Square",
+ "Color Square"
+};
+
+static const int ov2685_test_pattern_val[] = {
+ OV2685_TEST_PATTERN_DISABLED,
+ OV2685_TEST_PATTERN_COLOR_BAR,
+ OV2685_TEST_PATTERN_COLOR_BAR_FADE,
+ OV2685_TEST_PATTERN_RANDOM,
+ OV2685_TEST_PATTERN_BW_SQUARE,
+ OV2685_TEST_PATTERN_COLOR_SQUARE,
+};
+
+static const struct ov2685_mode supported_modes[] = {
+ {
+ .width = 1600,
+ .height = 1200,
+ .exp_def = 0x04ee,
+ .hts_def = 0x06a4,
+ .vts_def = 0x050e,
+ .reg_list = ov2685_1600x1200_regs,
+ },
+};
+
+/* Write registers up to 4 at a time */
+static int ov2685_write_reg(struct i2c_client *client, u16 reg,
+ u32 len, u32 val)
+{
+ u32 val_i, buf_i;
+ u8 buf[6];
+ u8 *val_p;
+ __be32 val_be;
+
+ if (len > 4)
+ return -EINVAL;
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+
+ val_be = cpu_to_be32(val);
+ val_p = (u8 *)&val_be;
+ buf_i = 2;
+ val_i = 4 - len;
+
+ while (val_i < 4)
+ buf[buf_i++] = val_p[val_i++];
+
+ if (i2c_master_send(client, buf, len + 2) != len + 2)
+ return -EIO;
+
+ return 0;
+}
+
+static int ov2685_write_array(struct i2c_client *client,
+ const struct regval *regs)
+{
+ int ret = 0;
+ u32 i;
+
+ for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
+ ret = ov2685_write_reg(client, regs[i].addr,
+ OV2685_REG_VALUE_08BIT, regs[i].val);
+
+ return ret;
+}
+
+/* Read registers up to 4 at a time */
+static int ov2685_read_reg(struct i2c_client *client, u16 reg,
+ u32 len, u32 *val)
+{
+ struct i2c_msg msgs[2];
+ u8 *data_be_p;
+ __be32 data_be = 0;
+ __be16 reg_addr_be = cpu_to_be16(reg);
+ int ret;
+
+ if (len > 4)
+ return -EINVAL;
+
+ data_be_p = (u8 *)&data_be;
+ /* Write register address */
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = 2;
+ msgs[0].buf = (u8 *)&reg_addr_be;
+
+ /* Read data from register */
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = &data_be_p[4 - len];
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
+
+ *val = be32_to_cpu(data_be);
+
+ return 0;
+}
+
+static void ov2685_fill_fmt(const struct ov2685_mode *mode,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ fmt->width = mode->width;
+ fmt->height = mode->height;
+ fmt->field = V4L2_FIELD_NONE;
+}
+
+static int ov2685_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ov2685 *ov2685 = to_ov2685(sd);
+ struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
+
+ /* only one mode supported for now */
+ ov2685_fill_fmt(ov2685->cur_mode, mbus_fmt);
+
+ return 0;
+}
+
+static int ov2685_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ov2685 *ov2685 = to_ov2685(sd);
+ struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
+
+ ov2685_fill_fmt(ov2685->cur_mode, mbus_fmt);
+
+ return 0;
+}
+
+static int ov2685_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(supported_modes))
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+
+ return 0;
+}
+
+static int ov2685_enum_frame_sizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ int index = fse->index;
+
+ if (index >= ARRAY_SIZE(supported_modes))
+ return -EINVAL;
+
+ fse->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+
+ fse->min_width = supported_modes[index].width;
+ fse->max_width = supported_modes[index].width;
+ fse->max_height = supported_modes[index].height;
+ fse->min_height = supported_modes[index].height;
+
+ return 0;
+}
+
+/* Calculate the delay in us by clock rate and clock cycles */
+static inline u32 ov2685_cal_delay(u32 cycles)
+{
+ return DIV_ROUND_UP(cycles, OV2685_XVCLK_FREQ / 1000 / 1000);
+}
+
+static int __ov2685_power_on(struct ov2685 *ov2685)
+{
+ int ret;
+ u32 delay_us;
+ struct device *dev = &ov2685->client->dev;
+
+ ret = clk_prepare_enable(ov2685->xvclk);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable xvclk\n");
+ return ret;
+ }
+
+ gpiod_set_value_cansleep(ov2685->reset_gpio, 1);
+
+ ret = regulator_bulk_enable(OV2685_NUM_SUPPLIES, ov2685->supplies);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable regulators\n");
+ goto disable_clk;
+ }
+
+ /* The minimum delay between power supplies and reset rising can be 0 */
+ gpiod_set_value_cansleep(ov2685->reset_gpio, 0);
+ /* 8192 xvclk cycles prior to the first SCCB transaction */
+ delay_us = ov2685_cal_delay(8192);
+ usleep_range(delay_us, delay_us * 2);
+
+ /* HACK: ov2685 would output messy data after reset(R0103),
+ * writing register before .s_stream() as a workaround
+ */
+ ret = ov2685_write_array(ov2685->client, ov2685->cur_mode->reg_list);
+ if (ret)
+ goto disable_supplies;
+
+ return 0;
+
+disable_supplies:
+ regulator_bulk_disable(OV2685_NUM_SUPPLIES, ov2685->supplies);
+disable_clk:
+ clk_disable_unprepare(ov2685->xvclk);
+
+ return ret;
+}
+
+static void __ov2685_power_off(struct ov2685 *ov2685)
+{
+ /* 512 xvclk cycles after the last SCCB transaction or MIPI frame end */
+ u32 delay_us = ov2685_cal_delay(512);
+
+ usleep_range(delay_us, delay_us * 2);
+ clk_disable_unprepare(ov2685->xvclk);
+ gpiod_set_value_cansleep(ov2685->reset_gpio, 1);
+ regulator_bulk_disable(OV2685_NUM_SUPPLIES, ov2685->supplies);
+}
+
+static int ov2685_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct ov2685 *ov2685 = to_ov2685(sd);
+ struct i2c_client *client = ov2685->client;
+ int ret = 0;
+
+ mutex_lock(&ov2685->mutex);
+
+ on = !!on;
+ if (on == ov2685->streaming)
+ goto unlock_and_return;
+
+ if (on) {
+ ret = pm_runtime_get_sync(&ov2685->client->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(&client->dev);
+ goto unlock_and_return;
+ }
+ ret = __v4l2_ctrl_handler_setup(&ov2685->ctrl_handler);
+ if (ret) {
+ pm_runtime_put(&client->dev);
+ goto unlock_and_return;
+ }
+ ret = ov2685_write_reg(client, REG_SC_CTRL_MODE,
+ OV2685_REG_VALUE_08BIT, SC_CTRL_MODE_STREAMING);
+ if (ret) {
+ pm_runtime_put(&client->dev);
+ goto unlock_and_return;
+ }
+ } else {
+ ov2685_write_reg(client, REG_SC_CTRL_MODE,
+ OV2685_REG_VALUE_08BIT, SC_CTRL_MODE_STANDBY);
+ pm_runtime_put(&ov2685->client->dev);
+ }
+
+ ov2685->streaming = on;
+
+unlock_and_return:
+ mutex_unlock(&ov2685->mutex);
+
+ return ret;
+}
+
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct ov2685 *ov2685 = to_ov2685(sd);
+ struct v4l2_mbus_framefmt *try_fmt;
+
+ mutex_lock(&ov2685->mutex);
+
+ try_fmt = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ /* Initialize try_fmt */
+ ov2685_fill_fmt(&supported_modes[0], try_fmt);
+
+ mutex_unlock(&ov2685->mutex);
+
+ return 0;
+}
+#endif
+
+static int __maybe_unused ov2685_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov2685 *ov2685 = to_ov2685(sd);
+
+ return __ov2685_power_on(ov2685);
+}
+
+static int __maybe_unused ov2685_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov2685 *ov2685 = to_ov2685(sd);
+
+ __ov2685_power_off(ov2685);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ov2685_pm_ops = {
+ SET_RUNTIME_PM_OPS(ov2685_runtime_suspend,
+ ov2685_runtime_resume, NULL)
+};
+
+static int ov2685_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov2685 *ov2685 = container_of(ctrl->handler,
+ struct ov2685, ctrl_handler);
+ struct i2c_client *client = ov2685->client;
+ s64 max_expo;
+ int ret;
+
+ /* Propagate change of current control to all related controls */
+ switch (ctrl->id) {
+ case V4L2_CID_VBLANK:
+ /* Update max exposure while meeting expected vblanking */
+ max_expo = ov2685->cur_mode->height + ctrl->val - 4;
+ __v4l2_ctrl_modify_range(ov2685->exposure,
+ ov2685->exposure->minimum, max_expo,
+ ov2685->exposure->step,
+ ov2685->exposure->default_value);
+ break;
+ }
+
+ if (pm_runtime_get_if_in_use(&client->dev) <= 0)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ ret = ov2685_write_reg(ov2685->client, OV2685_REG_EXPOSURE,
+ OV2685_REG_VALUE_24BIT, ctrl->val << 4);
+ break;
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = ov2685_write_reg(ov2685->client, OV2685_REG_GAIN,
+ OV2685_REG_VALUE_16BIT, ctrl->val);
+ break;
+ case V4L2_CID_VBLANK:
+ ret = ov2685_write_reg(ov2685->client, OV2685_REG_VTS,
+ OV2685_REG_VALUE_16BIT,
+ ctrl->val + ov2685->cur_mode->height);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = ov2685_write_reg(ov2685->client, OV2685_REG_TEST_PATTERN,
+ OV2685_REG_VALUE_08BIT,
+ ov2685_test_pattern_val[ctrl->val]);
+ break;
+ default:
+ dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
+ __func__, ctrl->id, ctrl->val);
+ ret = -EINVAL;
+ break;
+ };
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops ov2685_video_ops = {
+ .s_stream = ov2685_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov2685_pad_ops = {
+ .enum_mbus_code = ov2685_enum_mbus_code,
+ .enum_frame_size = ov2685_enum_frame_sizes,
+ .get_fmt = ov2685_get_fmt,
+ .set_fmt = ov2685_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ov2685_subdev_ops = {
+ .video = &ov2685_video_ops,
+ .pad = &ov2685_pad_ops,
+};
+
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+static const struct v4l2_subdev_internal_ops ov2685_internal_ops = {
+ .open = ov2685_open,
+};
+#endif
+
+static const struct v4l2_ctrl_ops ov2685_ctrl_ops = {
+ .s_ctrl = ov2685_set_ctrl,
+};
+
+static int ov2685_initialize_controls(struct ov2685 *ov2685)
+{
+ const struct ov2685_mode *mode;
+ struct v4l2_ctrl_handler *handler;
+ struct v4l2_ctrl *ctrl;
+ u64 exposure_max;
+ u32 pixel_rate, h_blank;
+ int ret;
+
+ handler = &ov2685->ctrl_handler;
+ mode = ov2685->cur_mode;
+ ret = v4l2_ctrl_handler_init(handler, 8);
+ if (ret)
+ return ret;
+ handler->lock = &ov2685->mutex;
+
+ ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ,
+ 0, 0, link_freq_menu_items);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ pixel_rate = (link_freq_menu_items[0] * 2 * OV2685_LANES) /
+ OV2685_BITS_PER_SAMPLE;
+ v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE,
+ 0, pixel_rate, 1, pixel_rate);
+
+ h_blank = mode->hts_def - mode->width;
+ ov2685->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
+ h_blank, h_blank, 1, h_blank);
+ if (ov2685->hblank)
+ ov2685->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ ov2685->vblank = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops,
+ V4L2_CID_VBLANK, mode->vts_def - mode->height,
+ OV2685_VTS_MAX - mode->height, 1,
+ mode->vts_def - mode->height);
+
+ exposure_max = mode->vts_def - 4;
+ ov2685->exposure = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops,
+ V4L2_CID_EXPOSURE, OV2685_EXPOSURE_MIN,
+ exposure_max, OV2685_EXPOSURE_STEP,
+ mode->exp_def);
+
+ ov2685->anal_gain = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, OV2685_GAIN_MIN,
+ OV2685_GAIN_MAX, OV2685_GAIN_STEP,
+ OV2685_GAIN_DEFAULT);
+
+ ov2685->test_pattern = v4l2_ctrl_new_std_menu_items(handler,
+ &ov2685_ctrl_ops, V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(ov2685_test_pattern_menu) - 1,
+ 0, 0, ov2685_test_pattern_menu);
+
+ if (handler->error) {
+ ret = handler->error;
+ dev_err(&ov2685->client->dev,
+ "Failed to init controls(%d)\n", ret);
+ goto err_free_handler;
+ }
+
+ ov2685->subdev.ctrl_handler = handler;
+
+ return 0;
+
+err_free_handler:
+ v4l2_ctrl_handler_free(handler);
+
+ return ret;
+}
+
+static int ov2685_check_sensor_id(struct ov2685 *ov2685,
+ struct i2c_client *client)
+{
+ struct device *dev = &ov2685->client->dev;
+ int ret;
+ u32 id = 0;
+
+ ret = ov2685_read_reg(client, OV2685_REG_CHIP_ID,
+ OV2685_REG_VALUE_16BIT, &id);
+ if (id != CHIP_ID) {
+ dev_err(dev, "Unexpected sensor id(%04x), ret(%d)\n", id, ret);
+ return ret;
+ }
+
+ dev_info(dev, "Detected OV%04x sensor\n", CHIP_ID);
+
+ return 0;
+}
+
+static int ov2685_configure_regulators(struct ov2685 *ov2685)
+{
+ int i;
+
+ for (i = 0; i < OV2685_NUM_SUPPLIES; i++)
+ ov2685->supplies[i].supply = ov2685_supply_names[i];
+
+ return devm_regulator_bulk_get(&ov2685->client->dev,
+ OV2685_NUM_SUPPLIES,
+ ov2685->supplies);
+}
+
+static int ov2685_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct ov2685 *ov2685;
+ int ret;
+
+ ov2685 = devm_kzalloc(dev, sizeof(*ov2685), GFP_KERNEL);
+ if (!ov2685)
+ return -ENOMEM;
+
+ ov2685->client = client;
+ ov2685->cur_mode = &supported_modes[0];
+
+ ov2685->xvclk = devm_clk_get(dev, "xvclk");
+ if (IS_ERR(ov2685->xvclk)) {
+ dev_err(dev, "Failed to get xvclk\n");
+ return -EINVAL;
+ }
+ ret = clk_set_rate(ov2685->xvclk, OV2685_XVCLK_FREQ);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
+ return ret;
+ }
+ if (clk_get_rate(ov2685->xvclk) != OV2685_XVCLK_FREQ)
+ dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
+
+ ov2685->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ov2685->reset_gpio)) {
+ dev_err(dev, "Failed to get reset-gpios\n");
+ return -EINVAL;
+ }
+
+ ret = ov2685_configure_regulators(ov2685);
+ if (ret) {
+ dev_err(dev, "Failed to get power regulators\n");
+ return ret;
+ }
+
+ mutex_init(&ov2685->mutex);
+ v4l2_i2c_subdev_init(&ov2685->subdev, client, &ov2685_subdev_ops);
+ ret = ov2685_initialize_controls(ov2685);
+ if (ret)
+ goto err_destroy_mutex;
+
+ ret = __ov2685_power_on(ov2685);
+ if (ret)
+ goto err_free_handler;
+
+ ret = ov2685_check_sensor_id(ov2685, client);
+ if (ret)
+ goto err_power_off;
+
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+ ov2685->subdev.internal_ops = &ov2685_internal_ops;
+ ov2685->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+#endif
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ ov2685->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ov2685->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&ov2685->subdev.entity, 1, &ov2685->pad);
+ if (ret < 0)
+ goto err_power_off;
+#endif
+
+ ret = v4l2_async_register_subdev(&ov2685->subdev);
+ if (ret) {
+ dev_err(dev, "v4l2 async register subdev failed\n");
+ goto err_clean_entity;
+ }
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+ return 0;
+
+err_clean_entity:
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ media_entity_cleanup(&ov2685->subdev.entity);
+#endif
+err_power_off:
+ __ov2685_power_off(ov2685);
+err_free_handler:
+ v4l2_ctrl_handler_free(&ov2685->ctrl_handler);
+err_destroy_mutex:
+ mutex_destroy(&ov2685->mutex);
+
+ return ret;
+}
+
+static int ov2685_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov2685 *ov2685 = to_ov2685(sd);
+
+ v4l2_async_unregister_subdev(sd);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ media_entity_cleanup(&sd->entity);
+#endif
+ v4l2_ctrl_handler_free(&ov2685->ctrl_handler);
+ mutex_destroy(&ov2685->mutex);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ __ov2685_power_off(ov2685);
+ pm_runtime_set_suspended(&client->dev);
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id ov2685_of_match[] = {
+ { .compatible = "ovti,ov2685" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ov2685_of_match);
+#endif
+
+static struct i2c_driver ov2685_i2c_driver = {
+ .driver = {
+ .name = "ov2685",
+ .owner = THIS_MODULE,
+ .pm = &ov2685_pm_ops,
+ .of_match_table = of_match_ptr(ov2685_of_match),
+ },
+ .probe = &ov2685_probe,
+ .remove = &ov2685_remove,
+};
+
+module_i2c_driver(ov2685_i2c_driver);
+
+MODULE_DESCRIPTION("OmniVision ov2685 sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index e2dd352224c7..03940f0cdfa6 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -14,14 +14,14 @@
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/types.h>
-#include <linux/gpio/consumer.h>
-#include <linux/regulator/consumer.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
@@ -34,6 +34,8 @@
#define OV5640_DEFAULT_SLAVE_ID 0x3c
+#define OV5640_REG_SYS_RESET02 0x3002
+#define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006
#define OV5640_REG_SYS_CTRL0 0x3008
#define OV5640_REG_CHIP_ID 0x300a
#define OV5640_REG_IO_MIPI_CTRL00 0x300e
@@ -114,6 +116,7 @@ struct ov5640_pixfmt {
};
static const struct ov5640_pixfmt ov5640_formats[] = {
+ { MEDIA_BUS_FMT_JPEG_1X8, V4L2_COLORSPACE_JPEG, },
{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB, },
{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, },
{ MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, },
@@ -125,7 +128,7 @@ static const struct ov5640_pixfmt ov5640_formats[] = {
* to set the MIPI CSI-2 virtual channel.
*/
static unsigned int virtual_channel;
-module_param(virtual_channel, int, 0);
+module_param(virtual_channel, uint, 0444);
MODULE_PARM_DESC(virtual_channel,
"MIPI CSI-2 virtual channel (0..3), default 0");
@@ -136,7 +139,7 @@ static const int ov5640_framerates[] = {
/* regulator supplies */
static const char * const ov5640_supply_name[] = {
- "DOVDD", /* Digital I/O (1.8V) suppply */
+ "DOVDD", /* Digital I/O (1.8V) supply */
"DVDD", /* Digital Core (1.5V) supply */
"AVDD", /* Analog (2.8V) supply */
};
@@ -242,7 +245,6 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
*/
static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
-
{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
{0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0},
{0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0},
@@ -331,7 +333,6 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
};
static const struct reg_value ov5640_setting_30fps_VGA_640_480[] = {
-
{0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
@@ -374,7 +375,6 @@ static const struct reg_value ov5640_setting_15fps_VGA_640_480[] = {
};
static const struct reg_value ov5640_setting_30fps_XGA_1024_768[] = {
-
{0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
@@ -481,6 +481,7 @@ static const struct reg_value ov5640_setting_30fps_QCIF_176_144[] = {
{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
};
+
static const struct reg_value ov5640_setting_15fps_QCIF_176_144[] = {
{0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
@@ -836,7 +837,7 @@ static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
ret = i2c_transfer(client->adapter, &msg, 1);
if (ret < 0) {
- v4l2_err(&sensor->sd, "%s: error: reg=%x, val=%x\n",
+ dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
__func__, reg, val);
return ret;
}
@@ -865,8 +866,11 @@ static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
msg[1].len = 1;
ret = i2c_transfer(client->adapter, msg, 2);
- if (ret < 0)
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: error: reg=%x\n",
+ __func__, reg);
return ret;
+ }
*val = buf[0];
return 0;
@@ -880,7 +884,7 @@ static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
ret = ov5640_read_reg(sensor, reg, &hi);
if (ret)
return ret;
- ret = ov5640_read_reg(sensor, reg+1, &lo);
+ ret = ov5640_read_reg(sensor, reg + 1, &lo);
if (ret)
return ret;
@@ -941,7 +945,7 @@ static int ov5640_load_regs(struct ov5640_dev *sensor,
break;
if (delay_ms)
- usleep_range(1000*delay_ms, 1000*delay_ms+100);
+ usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
}
return ret;
@@ -1283,7 +1287,6 @@ static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
return ret;
prev_vts = ret;
-
/* calculate banding filter */
/* 60Hz */
band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
@@ -1355,11 +1358,16 @@ static int ov5640_binning_on(struct ov5640_dev *sensor)
static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
{
+ struct i2c_client *client = sensor->i2c_client;
u8 temp, channel = virtual_channel;
int ret;
- if (channel > 3)
+ if (channel > 3) {
+ dev_err(&client->dev,
+ "%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
+ __func__, channel);
return -EINVAL;
+ }
ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
if (ret)
@@ -1399,8 +1407,8 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
* sensor changes between scaling and subsampling, go through
* exposure calculation
*/
-static int ov5640_set_mode_exposure_calc(
- struct ov5640_dev *sensor, const struct ov5640_mode_info *mode)
+static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
+ const struct ov5640_mode_info *mode)
{
u32 prev_shutter, prev_gain16;
u32 cap_shutter, cap_gain16;
@@ -1410,7 +1418,7 @@ static int ov5640_set_mode_exposure_calc(
u8 average;
int ret;
- if (mode->reg_data == NULL)
+ if (!mode->reg_data)
return -EINVAL;
/* read preview shutter */
@@ -1564,7 +1572,7 @@ static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
{
int ret;
- if (mode->reg_data == NULL)
+ if (!mode->reg_data)
return -EINVAL;
/* Write capture setting */
@@ -1915,6 +1923,7 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor,
{
int ret = 0;
bool is_rgb = false;
+ bool is_jpeg = false;
u8 val;
switch (format->code) {
@@ -1936,6 +1945,11 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor,
val = 0x61;
is_rgb = true;
break;
+ case MEDIA_BUS_FMT_JPEG_1X8:
+ /* YUV422, YUYV */
+ val = 0x30;
+ is_jpeg = true;
+ break;
default:
return -EINVAL;
}
@@ -1946,8 +1960,40 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor,
return ret;
/* FORMAT MUX CONTROL: ISP YUV or RGB */
- return ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL,
- is_rgb ? 0x01 : 0x00);
+ ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL,
+ is_rgb ? 0x01 : 0x00);
+ if (ret)
+ return ret;
+
+ /*
+ * TIMING TC REG21:
+ * - [5]: JPEG enable
+ */
+ ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
+ BIT(5), is_jpeg ? BIT(5) : 0);
+ if (ret)
+ return ret;
+
+ /*
+ * SYSTEM RESET02:
+ * - [4]: Reset JFIFO
+ * - [3]: Reset SFIFO
+ * - [2]: Reset JPEG
+ */
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
+ BIT(4) | BIT(3) | BIT(2),
+ is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
+ if (ret)
+ return ret;
+
+ /*
+ * CLOCK ENABLE02:
+ * - [5]: Enable JPEG 2x clock
+ * - [3]: Enable JPEG clock
+ */
+ return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
+ BIT(5) | BIT(3),
+ is_jpeg ? (BIT(5) | BIT(3)) : 0);
}
/*
@@ -2073,7 +2119,8 @@ static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, int auto_gain)
if (ctrls->auto_gain->is_new) {
ret = ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
- BIT(1), ctrls->auto_gain->val ? 0 : BIT(1));
+ BIT(1),
+ ctrls->auto_gain->val ? 0 : BIT(1));
if (ret)
return ret;
}
@@ -2253,10 +2300,12 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
if (fse->index >= OV5640_NUM_MODES)
return -EINVAL;
- fse->min_width = fse->max_width =
+ fse->min_width =
ov5640_mode_data[0][fse->index].width;
- fse->min_height = fse->max_height =
+ fse->max_width = fse->min_width;
+ fse->min_height =
ov5640_mode_data[0][fse->index].height;
+ fse->max_height = fse->min_height;
return 0;
}
@@ -2325,6 +2374,8 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
sensor->current_fr = frame_rate;
sensor->frame_interval = fi->interval;
+ sensor->current_mode = ov5640_find_mode(sensor, frame_rate, mode->width,
+ mode->height, true);
sensor->pending_mode_change = true;
out:
mutex_unlock(&sensor->lock);
@@ -2332,8 +2383,8 @@ out:
}
static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_mbus_code_enum *code)
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
{
if (code->pad != 0)
return -EINVAL;
diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c
index 9f9196568eb8..d2db480da1b9 100644
--- a/drivers/media/i2c/ov5670.c
+++ b/drivers/media/i2c/ov5670.c
@@ -1853,8 +1853,8 @@ static int ov5670_read_reg(struct ov5670 *ov5670, u16 reg, unsigned int len,
struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
struct i2c_msg msgs[2];
u8 *data_be_p;
- u32 data_be = 0;
- u16 reg_addr_be = cpu_to_be16(reg);
+ __be32 data_be = 0;
+ __be16 reg_addr_be = cpu_to_be16(reg);
int ret;
if (len > 4)
@@ -1891,6 +1891,7 @@ static int ov5670_write_reg(struct ov5670 *ov5670, u16 reg, unsigned int len,
int val_i;
u8 buf[6];
u8 *val_p;
+ __be32 tmp;
if (len > 4)
return -EINVAL;
@@ -1898,8 +1899,8 @@ static int ov5670_write_reg(struct ov5670 *ov5670, u16 reg, unsigned int len,
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
- val = cpu_to_be32(val);
- val_p = (u8 *)&val;
+ tmp = cpu_to_be32(val);
+ val_p = (u8 *)&tmp;
buf_i = 2;
val_i = 4 - len;
@@ -2180,36 +2181,6 @@ static int ov5670_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
-/* Calculate resolution distance */
-static int ov5670_get_reso_dist(const struct ov5670_mode *mode,
- struct v4l2_mbus_framefmt *framefmt)
-{
- return abs(mode->width - framefmt->width) +
- abs(mode->height - framefmt->height);
-}
-
-/* Find the closest supported resolution to the requested resolution */
-static const struct ov5670_mode *ov5670_find_best_fit(
- struct ov5670 *ov5670,
- struct v4l2_subdev_format *fmt)
-{
- struct v4l2_mbus_framefmt *framefmt = &fmt->format;
- int dist;
- int cur_best_fit = 0;
- int cur_best_fit_dist = -1;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
- dist = ov5670_get_reso_dist(&supported_modes[i], framefmt);
- if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
- cur_best_fit_dist = dist;
- cur_best_fit = i;
- }
- }
-
- return &supported_modes[cur_best_fit];
-}
-
static void ov5670_update_pad_format(const struct ov5670_mode *mode,
struct v4l2_subdev_format *fmt)
{
@@ -2259,7 +2230,8 @@ static int ov5670_set_pad_format(struct v4l2_subdev *sd,
fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
- mode = ov5670_find_best_fit(ov5670, fmt);
+ mode = v4l2_find_nearest_size(supported_modes, width, height,
+ fmt->format.width, fmt->format.height);
ov5670_update_pad_format(mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
*v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c
new file mode 100644
index 000000000000..9be38a0a2046
--- /dev/null
+++ b/drivers/media/i2c/ov5695.c
@@ -0,0 +1,1399 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ov5695 driver
+ *
+ * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sysfs.h>
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#ifndef V4L2_CID_DIGITAL_GAIN
+#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
+#endif
+
+/* 45Mhz * 4 Binning */
+#define OV5695_PIXEL_RATE (45 * 1000 * 1000 * 4)
+#define OV5695_XVCLK_FREQ 24000000
+
+#define CHIP_ID 0x005695
+#define OV5695_REG_CHIP_ID 0x300a
+
+#define OV5695_REG_CTRL_MODE 0x0100
+#define OV5695_MODE_SW_STANDBY 0x0
+#define OV5695_MODE_STREAMING BIT(0)
+
+#define OV5695_REG_EXPOSURE 0x3500
+#define OV5695_EXPOSURE_MIN 4
+#define OV5695_EXPOSURE_STEP 1
+#define OV5695_VTS_MAX 0x7fff
+
+#define OV5695_REG_ANALOG_GAIN 0x3509
+#define ANALOG_GAIN_MIN 0x10
+#define ANALOG_GAIN_MAX 0xf8
+#define ANALOG_GAIN_STEP 1
+#define ANALOG_GAIN_DEFAULT 0xf8
+
+#define OV5695_REG_DIGI_GAIN_H 0x350a
+#define OV5695_REG_DIGI_GAIN_L 0x350b
+#define OV5695_DIGI_GAIN_L_MASK 0x3f
+#define OV5695_DIGI_GAIN_H_SHIFT 6
+#define OV5695_DIGI_GAIN_MIN 0
+#define OV5695_DIGI_GAIN_MAX (0x4000 - 1)
+#define OV5695_DIGI_GAIN_STEP 1
+#define OV5695_DIGI_GAIN_DEFAULT 1024
+
+#define OV5695_REG_TEST_PATTERN 0x4503
+#define OV5695_TEST_PATTERN_ENABLE 0x80
+#define OV5695_TEST_PATTERN_DISABLE 0x0
+
+#define OV5695_REG_VTS 0x380e
+
+#define REG_NULL 0xFFFF
+
+#define OV5695_REG_VALUE_08BIT 1
+#define OV5695_REG_VALUE_16BIT 2
+#define OV5695_REG_VALUE_24BIT 3
+
+#define OV5695_LANES 2
+#define OV5695_BITS_PER_SAMPLE 10
+
+static const char * const ov5695_supply_names[] = {
+ "avdd", /* Analog power */
+ "dovdd", /* Digital I/O power */
+ "dvdd", /* Digital core power */
+};
+
+#define OV5695_NUM_SUPPLIES ARRAY_SIZE(ov5695_supply_names)
+
+struct regval {
+ u16 addr;
+ u8 val;
+};
+
+struct ov5695_mode {
+ u32 width;
+ u32 height;
+ u32 max_fps;
+ u32 hts_def;
+ u32 vts_def;
+ u32 exp_def;
+ const struct regval *reg_list;
+};
+
+struct ov5695 {
+ struct i2c_client *client;
+ struct clk *xvclk;
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[OV5695_NUM_SUPPLIES];
+
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *anal_gain;
+ struct v4l2_ctrl *digi_gain;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *test_pattern;
+ struct mutex mutex;
+ bool streaming;
+ const struct ov5695_mode *cur_mode;
+};
+
+#define to_ov5695(sd) container_of(sd, struct ov5695, subdev)
+
+/*
+ * Xclk 24Mhz
+ * Pclk 45Mhz
+ * linelength 672(0x2a0)
+ * framelength 2232(0x8b8)
+ * grabwindow_width 1296
+ * grabwindow_height 972
+ * max_framerate 30fps
+ * mipi_datarate per lane 840Mbps
+ */
+static const struct regval ov5695_global_regs[] = {
+ {0x0103, 0x01},
+ {0x0100, 0x00},
+ {0x0300, 0x04},
+ {0x0301, 0x00},
+ {0x0302, 0x69},
+ {0x0303, 0x00},
+ {0x0304, 0x00},
+ {0x0305, 0x01},
+ {0x0307, 0x00},
+ {0x030b, 0x00},
+ {0x030c, 0x00},
+ {0x030d, 0x1e},
+ {0x030e, 0x04},
+ {0x030f, 0x03},
+ {0x0312, 0x01},
+ {0x3000, 0x00},
+ {0x3002, 0xa1},
+ {0x3008, 0x00},
+ {0x3010, 0x00},
+ {0x3022, 0x51},
+ {0x3106, 0x15},
+ {0x3107, 0x01},
+ {0x3108, 0x05},
+ {0x3500, 0x00},
+ {0x3501, 0x45},
+ {0x3502, 0x00},
+ {0x3503, 0x08},
+ {0x3504, 0x03},
+ {0x3505, 0x8c},
+ {0x3507, 0x03},
+ {0x3508, 0x00},
+ {0x3509, 0x10},
+ {0x350c, 0x00},
+ {0x350d, 0x80},
+ {0x3510, 0x00},
+ {0x3511, 0x02},
+ {0x3512, 0x00},
+ {0x3601, 0x55},
+ {0x3602, 0x58},
+ {0x3614, 0x30},
+ {0x3615, 0x77},
+ {0x3621, 0x08},
+ {0x3624, 0x40},
+ {0x3633, 0x0c},
+ {0x3634, 0x0c},
+ {0x3635, 0x0c},
+ {0x3636, 0x0c},
+ {0x3638, 0x00},
+ {0x3639, 0x00},
+ {0x363a, 0x00},
+ {0x363b, 0x00},
+ {0x363c, 0xff},
+ {0x363d, 0xfa},
+ {0x3650, 0x44},
+ {0x3651, 0x44},
+ {0x3652, 0x44},
+ {0x3653, 0x44},
+ {0x3654, 0x44},
+ {0x3655, 0x44},
+ {0x3656, 0x44},
+ {0x3657, 0x44},
+ {0x3660, 0x00},
+ {0x3661, 0x00},
+ {0x3662, 0x00},
+ {0x366a, 0x00},
+ {0x366e, 0x0c},
+ {0x3673, 0x04},
+ {0x3700, 0x14},
+ {0x3703, 0x0c},
+ {0x3715, 0x01},
+ {0x3733, 0x10},
+ {0x3734, 0x40},
+ {0x373f, 0xa0},
+ {0x3765, 0x20},
+ {0x37a1, 0x1d},
+ {0x37a8, 0x26},
+ {0x37ab, 0x14},
+ {0x37c2, 0x04},
+ {0x37cb, 0x09},
+ {0x37cc, 0x13},
+ {0x37cd, 0x1f},
+ {0x37ce, 0x1f},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x3f},
+ {0x3806, 0x07},
+ {0x3807, 0xaf},
+ {0x3808, 0x05},
+ {0x3809, 0x10},
+ {0x380a, 0x03},
+ {0x380b, 0xcc},
+ {0x380c, 0x02},
+ {0x380d, 0xa0},
+ {0x380e, 0x08},
+ {0x380f, 0xb8},
+ {0x3810, 0x00},
+ {0x3811, 0x06},
+ {0x3812, 0x00},
+ {0x3813, 0x06},
+ {0x3814, 0x03},
+ {0x3815, 0x01},
+ {0x3816, 0x03},
+ {0x3817, 0x01},
+ {0x3818, 0x00},
+ {0x3819, 0x00},
+ {0x381a, 0x00},
+ {0x381b, 0x01},
+ {0x3820, 0x8b},
+ {0x3821, 0x01},
+ {0x3c80, 0x08},
+ {0x3c82, 0x00},
+ {0x3c83, 0x00},
+ {0x3c88, 0x00},
+ {0x3d85, 0x14},
+ {0x3f02, 0x08},
+ {0x3f03, 0x10},
+ {0x4008, 0x02},
+ {0x4009, 0x09},
+ {0x404e, 0x20},
+ {0x4501, 0x00},
+ {0x4502, 0x10},
+ {0x4800, 0x00},
+ {0x481f, 0x2a},
+ {0x4837, 0x13},
+ {0x5000, 0x17},
+ {0x5780, 0x3e},
+ {0x5781, 0x0f},
+ {0x5782, 0x44},
+ {0x5783, 0x02},
+ {0x5784, 0x01},
+ {0x5785, 0x01},
+ {0x5786, 0x00},
+ {0x5787, 0x04},
+ {0x5788, 0x02},
+ {0x5789, 0x0f},
+ {0x578a, 0xfd},
+ {0x578b, 0xf5},
+ {0x578c, 0xf5},
+ {0x578d, 0x03},
+ {0x578e, 0x08},
+ {0x578f, 0x0c},
+ {0x5790, 0x08},
+ {0x5791, 0x06},
+ {0x5792, 0x00},
+ {0x5793, 0x52},
+ {0x5794, 0xa3},
+ {0x5b00, 0x00},
+ {0x5b01, 0x1c},
+ {0x5b02, 0x00},
+ {0x5b03, 0x7f},
+ {0x5b05, 0x6c},
+ {0x5e10, 0xfc},
+ {0x4010, 0xf1},
+ {0x3503, 0x08},
+ {0x3505, 0x8c},
+ {0x3507, 0x03},
+ {0x3508, 0x00},
+ {0x3509, 0xf8},
+ {REG_NULL, 0x00},
+};
+
+/*
+ * Xclk 24Mhz
+ * Pclk 45Mhz
+ * linelength 740(0x2e4)
+ * framelength 2024(0x7e8)
+ * grabwindow_width 2592
+ * grabwindow_height 1944
+ * max_framerate 30fps
+ * mipi_datarate per lane 840Mbps
+ */
+static const struct regval ov5695_2592x1944_regs[] = {
+ {0x3501, 0x7e},
+ {0x366e, 0x18},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x04},
+ {0x3804, 0x0a},
+ {0x3805, 0x3f},
+ {0x3806, 0x07},
+ {0x3807, 0xab},
+ {0x3808, 0x0a},
+ {0x3809, 0x20},
+ {0x380a, 0x07},
+ {0x380b, 0x98},
+ {0x380c, 0x02},
+ {0x380d, 0xe4},
+ {0x380e, 0x07},
+ {0x380f, 0xe8},
+ {0x3811, 0x06},
+ {0x3813, 0x08},
+ {0x3814, 0x01},
+ {0x3816, 0x01},
+ {0x3817, 0x01},
+ {0x3820, 0x88},
+ {0x3821, 0x00},
+ {0x4501, 0x00},
+ {0x4008, 0x04},
+ {0x4009, 0x13},
+ {REG_NULL, 0x00},
+};
+
+/*
+ * Xclk 24Mhz
+ * Pclk 45Mhz
+ * linelength 672(0x2a0)
+ * framelength 2232(0x8b8)
+ * grabwindow_width 1920
+ * grabwindow_height 1080
+ * max_framerate 30fps
+ * mipi_datarate per lane 840Mbps
+ */
+static const struct regval ov5695_1920x1080_regs[] = {
+ {0x3501, 0x45},
+ {0x366e, 0x18},
+ {0x3800, 0x01},
+ {0x3801, 0x50},
+ {0x3802, 0x01},
+ {0x3803, 0xb8},
+ {0x3804, 0x08},
+ {0x3805, 0xef},
+ {0x3806, 0x05},
+ {0x3807, 0xf7},
+ {0x3808, 0x07},
+ {0x3809, 0x80},
+ {0x380a, 0x04},
+ {0x380b, 0x38},
+ {0x380c, 0x02},
+ {0x380d, 0xa0},
+ {0x380e, 0x08},
+ {0x380f, 0xb8},
+ {0x3811, 0x06},
+ {0x3813, 0x04},
+ {0x3814, 0x01},
+ {0x3816, 0x01},
+ {0x3817, 0x01},
+ {0x3820, 0x88},
+ {0x3821, 0x00},
+ {0x4501, 0x00},
+ {0x4008, 0x04},
+ {0x4009, 0x13},
+ {REG_NULL, 0x00}
+};
+
+/*
+ * Xclk 24Mhz
+ * Pclk 45Mhz
+ * linelength 740(0x02e4)
+ * framelength 1012(0x03f4)
+ * grabwindow_width 1296
+ * grabwindow_height 972
+ * max_framerate 60fps
+ * mipi_datarate per lane 840Mbps
+ */
+static const struct regval ov5695_1296x972_regs[] = {
+ {0x0103, 0x01},
+ {0x0100, 0x00},
+ {0x0300, 0x04},
+ {0x0301, 0x00},
+ {0x0302, 0x69},
+ {0x0303, 0x00},
+ {0x0304, 0x00},
+ {0x0305, 0x01},
+ {0x0307, 0x00},
+ {0x030b, 0x00},
+ {0x030c, 0x00},
+ {0x030d, 0x1e},
+ {0x030e, 0x04},
+ {0x030f, 0x03},
+ {0x0312, 0x01},
+ {0x3000, 0x00},
+ {0x3002, 0xa1},
+ {0x3008, 0x00},
+ {0x3010, 0x00},
+ {0x3016, 0x32},
+ {0x3022, 0x51},
+ {0x3106, 0x15},
+ {0x3107, 0x01},
+ {0x3108, 0x05},
+ {0x3500, 0x00},
+ {0x3501, 0x3e},
+ {0x3502, 0x00},
+ {0x3503, 0x08},
+ {0x3504, 0x03},
+ {0x3505, 0x8c},
+ {0x3507, 0x03},
+ {0x3508, 0x00},
+ {0x3509, 0x10},
+ {0x350c, 0x00},
+ {0x350d, 0x80},
+ {0x3510, 0x00},
+ {0x3511, 0x02},
+ {0x3512, 0x00},
+ {0x3601, 0x55},
+ {0x3602, 0x58},
+ {0x3611, 0x58},
+ {0x3614, 0x30},
+ {0x3615, 0x77},
+ {0x3621, 0x08},
+ {0x3624, 0x40},
+ {0x3633, 0x0c},
+ {0x3634, 0x0c},
+ {0x3635, 0x0c},
+ {0x3636, 0x0c},
+ {0x3638, 0x00},
+ {0x3639, 0x00},
+ {0x363a, 0x00},
+ {0x363b, 0x00},
+ {0x363c, 0xff},
+ {0x363d, 0xfa},
+ {0x3650, 0x44},
+ {0x3651, 0x44},
+ {0x3652, 0x44},
+ {0x3653, 0x44},
+ {0x3654, 0x44},
+ {0x3655, 0x44},
+ {0x3656, 0x44},
+ {0x3657, 0x44},
+ {0x3660, 0x00},
+ {0x3661, 0x00},
+ {0x3662, 0x00},
+ {0x366a, 0x00},
+ {0x366e, 0x0c},
+ {0x3673, 0x04},
+ {0x3700, 0x14},
+ {0x3703, 0x0c},
+ {0x3706, 0x24},
+ {0x3714, 0x27},
+ {0x3715, 0x01},
+ {0x3716, 0x00},
+ {0x3717, 0x02},
+ {0x3733, 0x10},
+ {0x3734, 0x40},
+ {0x373f, 0xa0},
+ {0x3765, 0x20},
+ {0x37a1, 0x1d},
+ {0x37a8, 0x26},
+ {0x37ab, 0x14},
+ {0x37c2, 0x04},
+ {0x37c3, 0xf0},
+ {0x37cb, 0x09},
+ {0x37cc, 0x13},
+ {0x37cd, 0x1f},
+ {0x37ce, 0x1f},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x3f},
+ {0x3806, 0x07},
+ {0x3807, 0xaf},
+ {0x3808, 0x05},
+ {0x3809, 0x10},
+ {0x380a, 0x03},
+ {0x380b, 0xcc},
+ {0x380c, 0x02},
+ {0x380d, 0xe4},
+ {0x380e, 0x03},
+ {0x380f, 0xf4},
+ {0x3810, 0x00},
+ {0x3811, 0x00},
+ {0x3812, 0x00},
+ {0x3813, 0x06},
+ {0x3814, 0x03},
+ {0x3815, 0x01},
+ {0x3816, 0x03},
+ {0x3817, 0x01},
+ {0x3818, 0x00},
+ {0x3819, 0x00},
+ {0x381a, 0x00},
+ {0x381b, 0x01},
+ {0x3820, 0x8b},
+ {0x3821, 0x01},
+ {0x3c80, 0x08},
+ {0x3c82, 0x00},
+ {0x3c83, 0x00},
+ {0x3c88, 0x00},
+ {0x3d85, 0x14},
+ {0x3f02, 0x08},
+ {0x3f03, 0x10},
+ {0x4008, 0x02},
+ {0x4009, 0x09},
+ {0x404e, 0x20},
+ {0x4501, 0x00},
+ {0x4502, 0x10},
+ {0x4800, 0x00},
+ {0x481f, 0x2a},
+ {0x4837, 0x13},
+ {0x5000, 0x13},
+ {0x5780, 0x3e},
+ {0x5781, 0x0f},
+ {0x5782, 0x44},
+ {0x5783, 0x02},
+ {0x5784, 0x01},
+ {0x5785, 0x01},
+ {0x5786, 0x00},
+ {0x5787, 0x04},
+ {0x5788, 0x02},
+ {0x5789, 0x0f},
+ {0x578a, 0xfd},
+ {0x578b, 0xf5},
+ {0x578c, 0xf5},
+ {0x578d, 0x03},
+ {0x578e, 0x08},
+ {0x578f, 0x0c},
+ {0x5790, 0x08},
+ {0x5791, 0x06},
+ {0x5792, 0x00},
+ {0x5793, 0x52},
+ {0x5794, 0xa3},
+ {0x5b00, 0x00},
+ {0x5b01, 0x1c},
+ {0x5b02, 0x00},
+ {0x5b03, 0x7f},
+ {0x5b05, 0x6c},
+ {0x5e10, 0xfc},
+ {0x4010, 0xf1},
+ {0x3503, 0x08},
+ {0x3505, 0x8c},
+ {0x3507, 0x03},
+ {0x3508, 0x00},
+ {0x3509, 0xf8},
+ {0x0100, 0x01},
+ {REG_NULL, 0x00}
+};
+
+/*
+ * Xclk 24Mhz
+ * Pclk 45Mhz
+ * linelength 672(0x2a0)
+ * framelength 2232(0x8b8)
+ * grabwindow_width 1280
+ * grabwindow_height 720
+ * max_framerate 30fps
+ * mipi_datarate per lane 840Mbps
+ */
+static const struct regval ov5695_1280x720_regs[] = {
+ {0x3501, 0x45},
+ {0x366e, 0x0c},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x01},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x3f},
+ {0x3806, 0x06},
+ {0x3807, 0xaf},
+ {0x3808, 0x05},
+ {0x3809, 0x00},
+ {0x380a, 0x02},
+ {0x380b, 0xd0},
+ {0x380c, 0x02},
+ {0x380d, 0xa0},
+ {0x380e, 0x08},
+ {0x380f, 0xb8},
+ {0x3811, 0x06},
+ {0x3813, 0x02},
+ {0x3814, 0x03},
+ {0x3816, 0x03},
+ {0x3817, 0x01},
+ {0x3820, 0x8b},
+ {0x3821, 0x01},
+ {0x4501, 0x00},
+ {0x4008, 0x02},
+ {0x4009, 0x09},
+ {REG_NULL, 0x00}
+};
+
+/*
+ * Xclk 24Mhz
+ * Pclk 45Mhz
+ * linelength 672(0x2a0)
+ * framelength 558(0x22e)
+ * grabwindow_width 640
+ * grabwindow_height 480
+ * max_framerate 120fps
+ * mipi_datarate per lane 840Mbps
+ */
+static const struct regval ov5695_640x480_regs[] = {
+ {0x3501, 0x22},
+ {0x366e, 0x0c},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x08},
+ {0x3804, 0x0a},
+ {0x3805, 0x3f},
+ {0x3806, 0x07},
+ {0x3807, 0xa7},
+ {0x3808, 0x02},
+ {0x3809, 0x80},
+ {0x380a, 0x01},
+ {0x380b, 0xe0},
+ {0x380c, 0x02},
+ {0x380d, 0xa0},
+ {0x380e, 0x02},
+ {0x380f, 0x2e},
+ {0x3811, 0x06},
+ {0x3813, 0x04},
+ {0x3814, 0x07},
+ {0x3816, 0x05},
+ {0x3817, 0x03},
+ {0x3820, 0x8d},
+ {0x3821, 0x01},
+ {0x4501, 0x00},
+ {0x4008, 0x02},
+ {0x4009, 0x09},
+ {REG_NULL, 0x00}
+};
+
+static const struct ov5695_mode supported_modes[] = {
+ {
+ .width = 2592,
+ .height = 1944,
+ .max_fps = 30,
+ .exp_def = 0x0450,
+ .hts_def = 0x02e4 * 4,
+ .vts_def = 0x07e8,
+ .reg_list = ov5695_2592x1944_regs,
+ },
+ {
+ .width = 1920,
+ .height = 1080,
+ .max_fps = 30,
+ .exp_def = 0x0450,
+ .hts_def = 0x02a0 * 4,
+ .vts_def = 0x08b8,
+ .reg_list = ov5695_1920x1080_regs,
+ },
+ {
+ .width = 1296,
+ .height = 972,
+ .max_fps = 60,
+ .exp_def = 0x03e0,
+ .hts_def = 0x02e4 * 4,
+ .vts_def = 0x03f4,
+ .reg_list = ov5695_1296x972_regs,
+ },
+ {
+ .width = 1280,
+ .height = 720,
+ .max_fps = 30,
+ .exp_def = 0x0450,
+ .hts_def = 0x02a0 * 4,
+ .vts_def = 0x08b8,
+ .reg_list = ov5695_1280x720_regs,
+ },
+ {
+ .width = 640,
+ .height = 480,
+ .max_fps = 120,
+ .exp_def = 0x0450,
+ .hts_def = 0x02a0 * 4,
+ .vts_def = 0x022e,
+ .reg_list = ov5695_640x480_regs,
+ },
+};
+
+#define OV5695_LINK_FREQ_420MHZ 420000000
+static const s64 link_freq_menu_items[] = {
+ OV5695_LINK_FREQ_420MHZ
+};
+
+static const char * const ov5695_test_pattern_menu[] = {
+ "Disabled",
+ "Vertical Color Bar Type 1",
+ "Vertical Color Bar Type 2",
+ "Vertical Color Bar Type 3",
+ "Vertical Color Bar Type 4"
+};
+
+/* Write registers up to 4 at a time */
+static int ov5695_write_reg(struct i2c_client *client, u16 reg,
+ u32 len, u32 val)
+{
+ u32 buf_i, val_i;
+ u8 buf[6];
+ u8 *val_p;
+ __be32 val_be;
+
+ if (len > 4)
+ return -EINVAL;
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+
+ val_be = cpu_to_be32(val);
+ val_p = (u8 *)&val_be;
+ buf_i = 2;
+ val_i = 4 - len;
+
+ while (val_i < 4)
+ buf[buf_i++] = val_p[val_i++];
+
+ if (i2c_master_send(client, buf, len + 2) != len + 2)
+ return -EIO;
+
+ return 0;
+}
+
+static int ov5695_write_array(struct i2c_client *client,
+ const struct regval *regs)
+{
+ u32 i;
+ int ret = 0;
+
+ for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
+ ret = ov5695_write_reg(client, regs[i].addr,
+ OV5695_REG_VALUE_08BIT, regs[i].val);
+
+ return ret;
+}
+
+/* Read registers up to 4 at a time */
+static int ov5695_read_reg(struct i2c_client *client, u16 reg, unsigned int len,
+ u32 *val)
+{
+ struct i2c_msg msgs[2];
+ u8 *data_be_p;
+ __be32 data_be = 0;
+ __be16 reg_addr_be = cpu_to_be16(reg);
+ int ret;
+
+ if (len > 4)
+ return -EINVAL;
+
+ data_be_p = (u8 *)&data_be;
+ /* Write register address */
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = 2;
+ msgs[0].buf = (u8 *)&reg_addr_be;
+
+ /* Read data from register */
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = &data_be_p[4 - len];
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
+
+ *val = be32_to_cpu(data_be);
+
+ return 0;
+}
+
+static int ov5695_get_reso_dist(const struct ov5695_mode *mode,
+ struct v4l2_mbus_framefmt *framefmt)
+{
+ return abs(mode->width - framefmt->width) +
+ abs(mode->height - framefmt->height);
+}
+
+static const struct ov5695_mode *
+ov5695_find_best_fit(struct v4l2_subdev_format *fmt)
+{
+ struct v4l2_mbus_framefmt *framefmt = &fmt->format;
+ int dist;
+ int cur_best_fit = 0;
+ int cur_best_fit_dist = -1;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
+ dist = ov5695_get_reso_dist(&supported_modes[i], framefmt);
+ if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
+ cur_best_fit_dist = dist;
+ cur_best_fit = i;
+ }
+ }
+
+ return &supported_modes[cur_best_fit];
+}
+
+static int ov5695_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ov5695 *ov5695 = to_ov5695(sd);
+ const struct ov5695_mode *mode;
+ s64 h_blank, vblank_def;
+
+ mutex_lock(&ov5695->mutex);
+
+ mode = ov5695_find_best_fit(fmt);
+ fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ fmt->format.width = mode->width;
+ fmt->format.height = mode->height;
+ fmt->format.field = V4L2_FIELD_NONE;
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+ *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+#else
+ mutex_unlock(&ov5695->mutex);
+ return -ENOTTY;
+#endif
+ } else {
+ ov5695->cur_mode = mode;
+ h_blank = mode->hts_def - mode->width;
+ __v4l2_ctrl_modify_range(ov5695->hblank, h_blank,
+ h_blank, 1, h_blank);
+ vblank_def = mode->vts_def - mode->height;
+ __v4l2_ctrl_modify_range(ov5695->vblank, vblank_def,
+ OV5695_VTS_MAX - mode->height,
+ 1, vblank_def);
+ }
+
+ mutex_unlock(&ov5695->mutex);
+
+ return 0;
+}
+
+static int ov5695_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ov5695 *ov5695 = to_ov5695(sd);
+ const struct ov5695_mode *mode = ov5695->cur_mode;
+
+ mutex_lock(&ov5695->mutex);
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+ fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+#else
+ mutex_unlock(&ov5695->mutex);
+ return -ENOTTY;
+#endif
+ } else {
+ fmt->format.width = mode->width;
+ fmt->format.height = mode->height;
+ fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ fmt->format.field = V4L2_FIELD_NONE;
+ }
+ mutex_unlock(&ov5695->mutex);
+
+ return 0;
+}
+
+static int ov5695_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index != 0)
+ return -EINVAL;
+ code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+
+ return 0;
+}
+
+static int ov5695_enum_frame_sizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index >= ARRAY_SIZE(supported_modes))
+ return -EINVAL;
+
+ if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
+ return -EINVAL;
+
+ fse->min_width = supported_modes[fse->index].width;
+ fse->max_width = supported_modes[fse->index].width;
+ fse->max_height = supported_modes[fse->index].height;
+ fse->min_height = supported_modes[fse->index].height;
+
+ return 0;
+}
+
+static int ov5695_enable_test_pattern(struct ov5695 *ov5695, u32 pattern)
+{
+ u32 val;
+
+ if (pattern)
+ val = (pattern - 1) | OV5695_TEST_PATTERN_ENABLE;
+ else
+ val = OV5695_TEST_PATTERN_DISABLE;
+
+ return ov5695_write_reg(ov5695->client, OV5695_REG_TEST_PATTERN,
+ OV5695_REG_VALUE_08BIT, val);
+}
+
+static int __ov5695_start_stream(struct ov5695 *ov5695)
+{
+ int ret;
+
+ ret = ov5695_write_array(ov5695->client, ov5695_global_regs);
+ if (ret)
+ return ret;
+ ret = ov5695_write_array(ov5695->client, ov5695->cur_mode->reg_list);
+ if (ret)
+ return ret;
+
+ /* In case these controls are set before streaming */
+ ret = __v4l2_ctrl_handler_setup(&ov5695->ctrl_handler);
+ if (ret)
+ return ret;
+
+ return ov5695_write_reg(ov5695->client, OV5695_REG_CTRL_MODE,
+ OV5695_REG_VALUE_08BIT, OV5695_MODE_STREAMING);
+}
+
+static int __ov5695_stop_stream(struct ov5695 *ov5695)
+{
+ return ov5695_write_reg(ov5695->client, OV5695_REG_CTRL_MODE,
+ OV5695_REG_VALUE_08BIT, OV5695_MODE_SW_STANDBY);
+}
+
+static int ov5695_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct ov5695 *ov5695 = to_ov5695(sd);
+ struct i2c_client *client = ov5695->client;
+ int ret = 0;
+
+ mutex_lock(&ov5695->mutex);
+ on = !!on;
+ if (on == ov5695->streaming)
+ goto unlock_and_return;
+
+ if (on) {
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(&client->dev);
+ goto unlock_and_return;
+ }
+
+ ret = __ov5695_start_stream(ov5695);
+ if (ret) {
+ v4l2_err(sd, "start stream failed while write regs\n");
+ pm_runtime_put(&client->dev);
+ goto unlock_and_return;
+ }
+ } else {
+ __ov5695_stop_stream(ov5695);
+ pm_runtime_put(&client->dev);
+ }
+
+ ov5695->streaming = on;
+
+unlock_and_return:
+ mutex_unlock(&ov5695->mutex);
+
+ return ret;
+}
+
+/* Calculate the delay in us by clock rate and clock cycles */
+static inline u32 ov5695_cal_delay(u32 cycles)
+{
+ return DIV_ROUND_UP(cycles, OV5695_XVCLK_FREQ / 1000 / 1000);
+}
+
+static int __ov5695_power_on(struct ov5695 *ov5695)
+{
+ int ret;
+ u32 delay_us;
+ struct device *dev = &ov5695->client->dev;
+
+ ret = clk_prepare_enable(ov5695->xvclk);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable xvclk\n");
+ return ret;
+ }
+
+ gpiod_set_value_cansleep(ov5695->reset_gpio, 1);
+
+ ret = regulator_bulk_enable(OV5695_NUM_SUPPLIES, ov5695->supplies);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable regulators\n");
+ goto disable_clk;
+ }
+
+ gpiod_set_value_cansleep(ov5695->reset_gpio, 0);
+
+ /* 8192 cycles prior to first SCCB transaction */
+ delay_us = ov5695_cal_delay(8192);
+ usleep_range(delay_us, delay_us * 2);
+
+ return 0;
+
+disable_clk:
+ clk_disable_unprepare(ov5695->xvclk);
+
+ return ret;
+}
+
+static void __ov5695_power_off(struct ov5695 *ov5695)
+{
+ clk_disable_unprepare(ov5695->xvclk);
+ gpiod_set_value_cansleep(ov5695->reset_gpio, 1);
+ regulator_bulk_disable(OV5695_NUM_SUPPLIES, ov5695->supplies);
+}
+
+static int __maybe_unused ov5695_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5695 *ov5695 = to_ov5695(sd);
+
+ return __ov5695_power_on(ov5695);
+}
+
+static int __maybe_unused ov5695_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5695 *ov5695 = to_ov5695(sd);
+
+ __ov5695_power_off(ov5695);
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+static int ov5695_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct ov5695 *ov5695 = to_ov5695(sd);
+ struct v4l2_mbus_framefmt *try_fmt =
+ v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ const struct ov5695_mode *def_mode = &supported_modes[0];
+
+ mutex_lock(&ov5695->mutex);
+ /* Initialize try_fmt */
+ try_fmt->width = def_mode->width;
+ try_fmt->height = def_mode->height;
+ try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ try_fmt->field = V4L2_FIELD_NONE;
+
+ mutex_unlock(&ov5695->mutex);
+ /* No crop or compose */
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops ov5695_pm_ops = {
+ SET_RUNTIME_PM_OPS(ov5695_runtime_suspend,
+ ov5695_runtime_resume, NULL)
+};
+
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+static const struct v4l2_subdev_internal_ops ov5695_internal_ops = {
+ .open = ov5695_open,
+};
+#endif
+
+static const struct v4l2_subdev_video_ops ov5695_video_ops = {
+ .s_stream = ov5695_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov5695_pad_ops = {
+ .enum_mbus_code = ov5695_enum_mbus_code,
+ .enum_frame_size = ov5695_enum_frame_sizes,
+ .get_fmt = ov5695_get_fmt,
+ .set_fmt = ov5695_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ov5695_subdev_ops = {
+ .video = &ov5695_video_ops,
+ .pad = &ov5695_pad_ops,
+};
+
+static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov5695 *ov5695 = container_of(ctrl->handler,
+ struct ov5695, ctrl_handler);
+ struct i2c_client *client = ov5695->client;
+ s64 max;
+ int ret = 0;
+
+ /* Propagate change of current control to all related controls */
+ switch (ctrl->id) {
+ case V4L2_CID_VBLANK:
+ /* Update max exposure while meeting expected vblanking */
+ max = ov5695->cur_mode->height + ctrl->val - 4;
+ __v4l2_ctrl_modify_range(ov5695->exposure,
+ ov5695->exposure->minimum, max,
+ ov5695->exposure->step,
+ ov5695->exposure->default_value);
+ break;
+ }
+
+ if (pm_runtime_get_if_in_use(&client->dev) <= 0)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ /* 4 least significant bits of expsoure are fractional part */
+ ret = ov5695_write_reg(ov5695->client, OV5695_REG_EXPOSURE,
+ OV5695_REG_VALUE_24BIT, ctrl->val << 4);
+ break;
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = ov5695_write_reg(ov5695->client, OV5695_REG_ANALOG_GAIN,
+ OV5695_REG_VALUE_08BIT, ctrl->val);
+ break;
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = ov5695_write_reg(ov5695->client, OV5695_REG_DIGI_GAIN_L,
+ OV5695_REG_VALUE_08BIT,
+ ctrl->val & OV5695_DIGI_GAIN_L_MASK);
+ ret = ov5695_write_reg(ov5695->client, OV5695_REG_DIGI_GAIN_H,
+ OV5695_REG_VALUE_08BIT,
+ ctrl->val >> OV5695_DIGI_GAIN_H_SHIFT);
+ break;
+ case V4L2_CID_VBLANK:
+ ret = ov5695_write_reg(ov5695->client, OV5695_REG_VTS,
+ OV5695_REG_VALUE_16BIT,
+ ctrl->val + ov5695->cur_mode->height);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = ov5695_enable_test_pattern(ov5695, ctrl->val);
+ break;
+ default:
+ dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
+ __func__, ctrl->id, ctrl->val);
+ break;
+ };
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops ov5695_ctrl_ops = {
+ .s_ctrl = ov5695_set_ctrl,
+};
+
+static int ov5695_initialize_controls(struct ov5695 *ov5695)
+{
+ const struct ov5695_mode *mode;
+ struct v4l2_ctrl_handler *handler;
+ struct v4l2_ctrl *ctrl;
+ s64 exposure_max, vblank_def;
+ u32 h_blank;
+ int ret;
+
+ handler = &ov5695->ctrl_handler;
+ mode = ov5695->cur_mode;
+ ret = v4l2_ctrl_handler_init(handler, 8);
+ if (ret)
+ return ret;
+ handler->lock = &ov5695->mutex;
+
+ ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ,
+ 0, 0, link_freq_menu_items);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE,
+ 0, OV5695_PIXEL_RATE, 1, OV5695_PIXEL_RATE);
+
+ h_blank = mode->hts_def - mode->width;
+ ov5695->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
+ h_blank, h_blank, 1, h_blank);
+ if (ov5695->hblank)
+ ov5695->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ vblank_def = mode->vts_def - mode->height;
+ ov5695->vblank = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops,
+ V4L2_CID_VBLANK, vblank_def,
+ OV5695_VTS_MAX - mode->height,
+ 1, vblank_def);
+
+ exposure_max = mode->vts_def - 4;
+ ov5695->exposure = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops,
+ V4L2_CID_EXPOSURE, OV5695_EXPOSURE_MIN,
+ exposure_max, OV5695_EXPOSURE_STEP,
+ mode->exp_def);
+
+ ov5695->anal_gain = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, ANALOG_GAIN_MIN,
+ ANALOG_GAIN_MAX, ANALOG_GAIN_STEP,
+ ANALOG_GAIN_DEFAULT);
+
+ /* Digital gain */
+ ov5695->digi_gain = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops,
+ V4L2_CID_DIGITAL_GAIN, OV5695_DIGI_GAIN_MIN,
+ OV5695_DIGI_GAIN_MAX, OV5695_DIGI_GAIN_STEP,
+ OV5695_DIGI_GAIN_DEFAULT);
+
+ ov5695->test_pattern = v4l2_ctrl_new_std_menu_items(handler,
+ &ov5695_ctrl_ops, V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(ov5695_test_pattern_menu) - 1,
+ 0, 0, ov5695_test_pattern_menu);
+
+ if (handler->error) {
+ ret = handler->error;
+ dev_err(&ov5695->client->dev,
+ "Failed to init controls(%d)\n", ret);
+ goto err_free_handler;
+ }
+
+ ov5695->subdev.ctrl_handler = handler;
+
+ return 0;
+
+err_free_handler:
+ v4l2_ctrl_handler_free(handler);
+
+ return ret;
+}
+
+static int ov5695_check_sensor_id(struct ov5695 *ov5695,
+ struct i2c_client *client)
+{
+ struct device *dev = &ov5695->client->dev;
+ u32 id = 0;
+ int ret;
+
+ ret = ov5695_read_reg(client, OV5695_REG_CHIP_ID,
+ OV5695_REG_VALUE_24BIT, &id);
+ if (id != CHIP_ID) {
+ dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);
+ return ret;
+ }
+
+ dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID);
+
+ return 0;
+}
+
+static int ov5695_configure_regulators(struct ov5695 *ov5695)
+{
+ int i;
+
+ for (i = 0; i < OV5695_NUM_SUPPLIES; i++)
+ ov5695->supplies[i].supply = ov5695_supply_names[i];
+
+ return devm_regulator_bulk_get(&ov5695->client->dev,
+ OV5695_NUM_SUPPLIES,
+ ov5695->supplies);
+}
+
+static int ov5695_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct ov5695 *ov5695;
+ struct v4l2_subdev *sd;
+ int ret;
+
+ ov5695 = devm_kzalloc(dev, sizeof(*ov5695), GFP_KERNEL);
+ if (!ov5695)
+ return -ENOMEM;
+
+ ov5695->client = client;
+ ov5695->cur_mode = &supported_modes[0];
+
+ ov5695->xvclk = devm_clk_get(dev, "xvclk");
+ if (IS_ERR(ov5695->xvclk)) {
+ dev_err(dev, "Failed to get xvclk\n");
+ return -EINVAL;
+ }
+ ret = clk_set_rate(ov5695->xvclk, OV5695_XVCLK_FREQ);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
+ return ret;
+ }
+ if (clk_get_rate(ov5695->xvclk) != OV5695_XVCLK_FREQ)
+ dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
+
+ ov5695->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ov5695->reset_gpio)) {
+ dev_err(dev, "Failed to get reset-gpios\n");
+ return -EINVAL;
+ }
+
+ ret = ov5695_configure_regulators(ov5695);
+ if (ret) {
+ dev_err(dev, "Failed to get power regulators\n");
+ return ret;
+ }
+
+ mutex_init(&ov5695->mutex);
+
+ sd = &ov5695->subdev;
+ v4l2_i2c_subdev_init(sd, client, &ov5695_subdev_ops);
+ ret = ov5695_initialize_controls(ov5695);
+ if (ret)
+ goto err_destroy_mutex;
+
+ ret = __ov5695_power_on(ov5695);
+ if (ret)
+ goto err_free_handler;
+
+ ret = ov5695_check_sensor_id(ov5695, client);
+ if (ret)
+ goto err_power_off;
+
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+ sd->internal_ops = &ov5695_internal_ops;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+#endif
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ ov5695->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, 1, &ov5695->pad);
+ if (ret < 0)
+ goto err_power_off;
+#endif
+
+ ret = v4l2_async_register_subdev(sd);
+ if (ret) {
+ dev_err(dev, "v4l2 async register subdev failed\n");
+ goto err_clean_entity;
+ }
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+ return 0;
+
+err_clean_entity:
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ media_entity_cleanup(&sd->entity);
+#endif
+err_power_off:
+ __ov5695_power_off(ov5695);
+err_free_handler:
+ v4l2_ctrl_handler_free(&ov5695->ctrl_handler);
+err_destroy_mutex:
+ mutex_destroy(&ov5695->mutex);
+
+ return ret;
+}
+
+static int ov5695_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5695 *ov5695 = to_ov5695(sd);
+
+ v4l2_async_unregister_subdev(sd);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ media_entity_cleanup(&sd->entity);
+#endif
+ v4l2_ctrl_handler_free(&ov5695->ctrl_handler);
+ mutex_destroy(&ov5695->mutex);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ __ov5695_power_off(ov5695);
+ pm_runtime_set_suspended(&client->dev);
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id ov5695_of_match[] = {
+ { .compatible = "ovti,ov5695" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ov5695_of_match);
+#endif
+
+static struct i2c_driver ov5695_i2c_driver = {
+ .driver = {
+ .name = "ov5695",
+ .owner = THIS_MODULE,
+ .pm = &ov5695_pm_ops,
+ .of_match_table = of_match_ptr(ov5695_of_match),
+ },
+ .probe = &ov5695_probe,
+ .remove = &ov5695_remove,
+};
+
+module_i2c_driver(ov5695_i2c_driver);
+
+MODULE_DESCRIPTION("OmniVision ov5695 sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 8975d16b2b24..17a34b4a819d 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -201,7 +201,7 @@ struct ov6650 {
struct v4l2_rect rect; /* sensor cropping window */
unsigned long pclk_limit; /* from host */
unsigned long pclk_max; /* from resolution and format */
- struct v4l2_fract tpf; /* as requested with s_parm */
+ struct v4l2_fract tpf; /* as requested with s_frame_interval */
u32 code;
enum v4l2_colorspace colorspace;
};
@@ -723,42 +723,31 @@ static int ov6650_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
-static int ov6650_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+static int ov6650_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *ival)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov6650 *priv = to_ov6650(client);
- struct v4l2_captureparm *cp = &parms->parm.capture;
- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- memset(cp, 0, sizeof(*cp));
- cp->capability = V4L2_CAP_TIMEPERFRAME;
- cp->timeperframe.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf,
+ ival->interval.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf,
priv->pclk_limit, priv->pclk_max));
- cp->timeperframe.denominator = FRAME_RATE_MAX;
+ ival->interval.denominator = FRAME_RATE_MAX;
dev_dbg(&client->dev, "Frame interval: %u/%u s\n",
- cp->timeperframe.numerator, cp->timeperframe.denominator);
+ ival->interval.numerator, ival->interval.denominator);
return 0;
}
-static int ov6650_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+static int ov6650_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *ival)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov6650 *priv = to_ov6650(client);
- struct v4l2_captureparm *cp = &parms->parm.capture;
- struct v4l2_fract *tpf = &cp->timeperframe;
+ struct v4l2_fract *tpf = &ival->interval;
int div, ret;
u8 clkrc;
- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (cp->extendedmode != 0)
- return -EINVAL;
-
if (tpf->numerator == 0 || tpf->denominator == 0)
div = 1; /* Reset to full rate */
else
@@ -921,8 +910,8 @@ static int ov6650_s_mbus_config(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops ov6650_video_ops = {
.s_stream = ov6650_s_stream,
- .g_parm = ov6650_g_parm,
- .s_parm = ov6650_s_parm,
+ .g_frame_interval = ov6650_g_frame_interval,
+ .s_frame_interval = ov6650_s_frame_interval,
.g_mbus_config = ov6650_g_mbus_config,
.s_mbus_config = ov6650_s_mbus_config,
};
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index 28571de1c2f6..3474ef832c1e 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -21,6 +21,7 @@
#include <linux/gpio/consumer.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
#include <media/v4l2-mediabus.h>
#include <media/v4l2-image-sizes.h>
#include <media/i2c/ov7670.h>
@@ -242,6 +243,7 @@ struct ov7670_info {
struct clk *clk;
struct gpio_desc *resetb_gpio;
struct gpio_desc *pwdn_gpio;
+ unsigned int mbus_config; /* Media bus configuration flags */
int min_width; /* Filter out smaller sizes */
int min_height; /* Filter out smaller sizes */
int clock_speed; /* External clock speed (MHz) */
@@ -1014,7 +1016,7 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
struct v4l2_mbus_framefmt *mbus_fmt;
#endif
- unsigned char com7;
+ unsigned char com7, com10 = 0;
int ret;
if (format->pad)
@@ -1034,7 +1036,6 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
}
ret = ov7670_try_fmt_internal(sd, &format->format, &ovfmt, &wsize);
-
if (ret)
return ret;
/*
@@ -1045,16 +1046,41 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
*/
com7 = ovfmt->regs[0].value;
com7 |= wsize->com7_bit;
- ov7670_write(sd, REG_COM7, com7);
+ ret = ov7670_write(sd, REG_COM7, com7);
+ if (ret)
+ return ret;
+
+ /*
+ * Configure the media bus through COM10 register
+ */
+ if (info->mbus_config & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ com10 |= COM10_VS_NEG;
+ if (info->mbus_config & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ com10 |= COM10_HREF_REV;
+ if (info->pclk_hb_disable)
+ com10 |= COM10_PCLK_HB;
+ ret = ov7670_write(sd, REG_COM10, com10);
+ if (ret)
+ return ret;
+
/*
* Now write the rest of the array. Also store start/stops
*/
- ov7670_write_array(sd, ovfmt->regs + 1);
- ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart,
- wsize->vstop);
- ret = 0;
- if (wsize->regs)
+ ret = ov7670_write_array(sd, ovfmt->regs + 1);
+ if (ret)
+ return ret;
+
+ ret = ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart,
+ wsize->vstop);
+ if (ret)
+ return ret;
+
+ if (wsize->regs) {
ret = ov7670_write_array(sd, wsize->regs);
+ if (ret)
+ return ret;
+ }
+
info->fmt = ovfmt;
/*
@@ -1067,8 +1093,10 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
* to write it unconditionally, and that will make the frame
* rate persistent too.
*/
- if (ret == 0)
- ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
+ ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
+ if (ret)
+ return ret;
+
return 0;
}
@@ -1100,30 +1128,24 @@ static int ov7670_get_fmt(struct v4l2_subdev *sd,
* Implement G/S_PARM. There is a "high quality" mode we could try
* to do someday; for now, we just do the frame rate tweak.
*/
-static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+static int ov7670_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *ival)
{
- struct v4l2_captureparm *cp = &parms->parm.capture;
struct ov7670_info *info = to_state(sd);
- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- cp->capability = V4L2_CAP_TIMEPERFRAME;
- info->devtype->get_framerate(sd, &cp->timeperframe);
+ info->devtype->get_framerate(sd, &ival->interval);
return 0;
}
-static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+static int ov7670_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *ival)
{
- struct v4l2_captureparm *cp = &parms->parm.capture;
- struct v4l2_fract *tpf = &cp->timeperframe;
+ struct v4l2_fract *tpf = &ival->interval;
struct ov7670_info *info = to_state(sd);
- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- cp->capability = V4L2_CAP_TIMEPERFRAME;
return info->devtype->set_framerate(sd, tpf);
}
@@ -1636,8 +1658,8 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = {
};
static const struct v4l2_subdev_video_ops ov7670_video_ops = {
- .s_parm = ov7670_s_parm,
- .g_parm = ov7670_g_parm,
+ .s_frame_interval = ov7670_s_frame_interval,
+ .g_frame_interval = ov7670_g_frame_interval,
};
static const struct v4l2_subdev_pad_ops ov7670_pad_ops = {
@@ -1698,6 +1720,45 @@ static int ov7670_init_gpio(struct i2c_client *client, struct ov7670_info *info)
return 0;
}
+/*
+ * ov7670_parse_dt() - Parse device tree to collect mbus configuration
+ * properties
+ */
+static int ov7670_parse_dt(struct device *dev,
+ struct ov7670_info *info)
+{
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+ struct v4l2_fwnode_endpoint bus_cfg;
+ struct fwnode_handle *ep;
+ int ret;
+
+ if (!fwnode)
+ return -EINVAL;
+
+ info->pclk_hb_disable = false;
+ if (fwnode_property_present(fwnode, "ov7670,pclk-hb-disable"))
+ info->pclk_hb_disable = true;
+
+ ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
+ if (!ep)
+ return -EINVAL;
+
+ ret = v4l2_fwnode_endpoint_parse(ep, &bus_cfg);
+ if (ret) {
+ fwnode_handle_put(ep);
+ return ret;
+ }
+
+ if (bus_cfg.bus_type != V4L2_MBUS_PARALLEL) {
+ dev_err(dev, "Unsupported media bus type\n");
+ fwnode_handle_put(ep);
+ return ret;
+ }
+ info->mbus_config = bus_cfg.bus.parallel.flags;
+
+ return 0;
+}
+
static int ov7670_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1718,7 +1779,13 @@ static int ov7670_probe(struct i2c_client *client,
#endif
info->clock_speed = 30; /* default: a guess */
- if (client->dev.platform_data) {
+
+ if (dev_fwnode(&client->dev)) {
+ ret = ov7670_parse_dt(&client->dev, info);
+ if (ret)
+ return ret;
+
+ } else if (client->dev.platform_data) {
struct ov7670_config *config = client->dev.platform_data;
/*
@@ -1785,9 +1852,6 @@ static int ov7670_probe(struct i2c_client *client,
tpf.denominator = 30;
info->devtype->set_framerate(sd, &tpf);
- if (info->pclk_hb_disable)
- ov7670_write(sd, REG_COM10, COM10_PCLK_HB);
-
v4l2_ctrl_handler_init(&info->hdl, 10);
v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c
new file mode 100644
index 000000000000..b62860c89439
--- /dev/null
+++ b/drivers/media/i2c/ov772x.c
@@ -0,0 +1,1356 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ov772x Camera Driver
+ *
+ * Copyright (C) 2017 Jacopo Mondi <jacopo+renesas@jmondi.org>
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov7670 and soc_camera_platform driver,
+ *
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/i2c/ov772x.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-subdev.h>
+
+/*
+ * register offset
+ */
+#define GAIN 0x00 /* AGC - Gain control gain setting */
+#define BLUE 0x01 /* AWB - Blue channel gain setting */
+#define RED 0x02 /* AWB - Red channel gain setting */
+#define GREEN 0x03 /* AWB - Green channel gain setting */
+#define COM1 0x04 /* Common control 1 */
+#define BAVG 0x05 /* U/B Average Level */
+#define GAVG 0x06 /* Y/Gb Average Level */
+#define RAVG 0x07 /* V/R Average Level */
+#define AECH 0x08 /* Exposure Value - AEC MSBs */
+#define COM2 0x09 /* Common control 2 */
+#define PID 0x0A /* Product ID Number MSB */
+#define VER 0x0B /* Product ID Number LSB */
+#define COM3 0x0C /* Common control 3 */
+#define COM4 0x0D /* Common control 4 */
+#define COM5 0x0E /* Common control 5 */
+#define COM6 0x0F /* Common control 6 */
+#define AEC 0x10 /* Exposure Value */
+#define CLKRC 0x11 /* Internal clock */
+#define COM7 0x12 /* Common control 7 */
+#define COM8 0x13 /* Common control 8 */
+#define COM9 0x14 /* Common control 9 */
+#define COM10 0x15 /* Common control 10 */
+#define REG16 0x16 /* Register 16 */
+#define HSTART 0x17 /* Horizontal sensor size */
+#define HSIZE 0x18 /* Horizontal frame (HREF column) end high 8-bit */
+#define VSTART 0x19 /* Vertical frame (row) start high 8-bit */
+#define VSIZE 0x1A /* Vertical sensor size */
+#define PSHFT 0x1B /* Data format - pixel delay select */
+#define MIDH 0x1C /* Manufacturer ID byte - high */
+#define MIDL 0x1D /* Manufacturer ID byte - low */
+#define LAEC 0x1F /* Fine AEC value */
+#define COM11 0x20 /* Common control 11 */
+#define BDBASE 0x22 /* Banding filter Minimum AEC value */
+#define DBSTEP 0x23 /* Banding filter Maximum Setp */
+#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */
+#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */
+#define VPT 0x26 /* AGC/AEC Fast mode operating region */
+#define REG28 0x28 /* Register 28 */
+#define HOUTSIZE 0x29 /* Horizontal data output size MSBs */
+#define EXHCH 0x2A /* Dummy pixel insert MSB */
+#define EXHCL 0x2B /* Dummy pixel insert LSB */
+#define VOUTSIZE 0x2C /* Vertical data output size MSBs */
+#define ADVFL 0x2D /* LSB of insert dummy lines in Vertical direction */
+#define ADVFH 0x2E /* MSG of insert dummy lines in Vertical direction */
+#define YAVE 0x2F /* Y/G Channel Average value */
+#define LUMHTH 0x30 /* Histogram AEC/AGC Luminance high level threshold */
+#define LUMLTH 0x31 /* Histogram AEC/AGC Luminance low level threshold */
+#define HREF 0x32 /* Image start and size control */
+#define DM_LNL 0x33 /* Dummy line low 8 bits */
+#define DM_LNH 0x34 /* Dummy line high 8 bits */
+#define ADOFF_B 0x35 /* AD offset compensation value for B channel */
+#define ADOFF_R 0x36 /* AD offset compensation value for R channel */
+#define ADOFF_GB 0x37 /* AD offset compensation value for Gb channel */
+#define ADOFF_GR 0x38 /* AD offset compensation value for Gr channel */
+#define OFF_B 0x39 /* Analog process B channel offset value */
+#define OFF_R 0x3A /* Analog process R channel offset value */
+#define OFF_GB 0x3B /* Analog process Gb channel offset value */
+#define OFF_GR 0x3C /* Analog process Gr channel offset value */
+#define COM12 0x3D /* Common control 12 */
+#define COM13 0x3E /* Common control 13 */
+#define COM14 0x3F /* Common control 14 */
+#define COM15 0x40 /* Common control 15*/
+#define COM16 0x41 /* Common control 16 */
+#define TGT_B 0x42 /* BLC blue channel target value */
+#define TGT_R 0x43 /* BLC red channel target value */
+#define TGT_GB 0x44 /* BLC Gb channel target value */
+#define TGT_GR 0x45 /* BLC Gr channel target value */
+/* for ov7720 */
+#define LCC0 0x46 /* Lens correction control 0 */
+#define LCC1 0x47 /* Lens correction option 1 - X coordinate */
+#define LCC2 0x48 /* Lens correction option 2 - Y coordinate */
+#define LCC3 0x49 /* Lens correction option 3 */
+#define LCC4 0x4A /* Lens correction option 4 - radius of the circular */
+#define LCC5 0x4B /* Lens correction option 5 */
+#define LCC6 0x4C /* Lens correction option 6 */
+/* for ov7725 */
+#define LC_CTR 0x46 /* Lens correction control */
+#define LC_XC 0x47 /* X coordinate of lens correction center relative */
+#define LC_YC 0x48 /* Y coordinate of lens correction center relative */
+#define LC_COEF 0x49 /* Lens correction coefficient */
+#define LC_RADI 0x4A /* Lens correction radius */
+#define LC_COEFB 0x4B /* Lens B channel compensation coefficient */
+#define LC_COEFR 0x4C /* Lens R channel compensation coefficient */
+
+#define FIXGAIN 0x4D /* Analog fix gain amplifer */
+#define AREF0 0x4E /* Sensor reference control */
+#define AREF1 0x4F /* Sensor reference current control */
+#define AREF2 0x50 /* Analog reference control */
+#define AREF3 0x51 /* ADC reference control */
+#define AREF4 0x52 /* ADC reference control */
+#define AREF5 0x53 /* ADC reference control */
+#define AREF6 0x54 /* Analog reference control */
+#define AREF7 0x55 /* Analog reference control */
+#define UFIX 0x60 /* U channel fixed value output */
+#define VFIX 0x61 /* V channel fixed value output */
+#define AWBB_BLK 0x62 /* AWB option for advanced AWB */
+#define AWB_CTRL0 0x63 /* AWB control byte 0 */
+#define DSP_CTRL1 0x64 /* DSP control byte 1 */
+#define DSP_CTRL2 0x65 /* DSP control byte 2 */
+#define DSP_CTRL3 0x66 /* DSP control byte 3 */
+#define DSP_CTRL4 0x67 /* DSP control byte 4 */
+#define AWB_BIAS 0x68 /* AWB BLC level clip */
+#define AWB_CTRL1 0x69 /* AWB control 1 */
+#define AWB_CTRL2 0x6A /* AWB control 2 */
+#define AWB_CTRL3 0x6B /* AWB control 3 */
+#define AWB_CTRL4 0x6C /* AWB control 4 */
+#define AWB_CTRL5 0x6D /* AWB control 5 */
+#define AWB_CTRL6 0x6E /* AWB control 6 */
+#define AWB_CTRL7 0x6F /* AWB control 7 */
+#define AWB_CTRL8 0x70 /* AWB control 8 */
+#define AWB_CTRL9 0x71 /* AWB control 9 */
+#define AWB_CTRL10 0x72 /* AWB control 10 */
+#define AWB_CTRL11 0x73 /* AWB control 11 */
+#define AWB_CTRL12 0x74 /* AWB control 12 */
+#define AWB_CTRL13 0x75 /* AWB control 13 */
+#define AWB_CTRL14 0x76 /* AWB control 14 */
+#define AWB_CTRL15 0x77 /* AWB control 15 */
+#define AWB_CTRL16 0x78 /* AWB control 16 */
+#define AWB_CTRL17 0x79 /* AWB control 17 */
+#define AWB_CTRL18 0x7A /* AWB control 18 */
+#define AWB_CTRL19 0x7B /* AWB control 19 */
+#define AWB_CTRL20 0x7C /* AWB control 20 */
+#define AWB_CTRL21 0x7D /* AWB control 21 */
+#define GAM1 0x7E /* Gamma Curve 1st segment input end point */
+#define GAM2 0x7F /* Gamma Curve 2nd segment input end point */
+#define GAM3 0x80 /* Gamma Curve 3rd segment input end point */
+#define GAM4 0x81 /* Gamma Curve 4th segment input end point */
+#define GAM5 0x82 /* Gamma Curve 5th segment input end point */
+#define GAM6 0x83 /* Gamma Curve 6th segment input end point */
+#define GAM7 0x84 /* Gamma Curve 7th segment input end point */
+#define GAM8 0x85 /* Gamma Curve 8th segment input end point */
+#define GAM9 0x86 /* Gamma Curve 9th segment input end point */
+#define GAM10 0x87 /* Gamma Curve 10th segment input end point */
+#define GAM11 0x88 /* Gamma Curve 11th segment input end point */
+#define GAM12 0x89 /* Gamma Curve 12th segment input end point */
+#define GAM13 0x8A /* Gamma Curve 13th segment input end point */
+#define GAM14 0x8B /* Gamma Curve 14th segment input end point */
+#define GAM15 0x8C /* Gamma Curve 15th segment input end point */
+#define SLOP 0x8D /* Gamma curve highest segment slope */
+#define DNSTH 0x8E /* De-noise threshold */
+#define EDGE_STRNGT 0x8F /* Edge strength control when manual mode */
+#define EDGE_TRSHLD 0x90 /* Edge threshold control when manual mode */
+#define DNSOFF 0x91 /* Auto De-noise threshold control */
+#define EDGE_UPPER 0x92 /* Edge strength upper limit when Auto mode */
+#define EDGE_LOWER 0x93 /* Edge strength lower limit when Auto mode */
+#define MTX1 0x94 /* Matrix coefficient 1 */
+#define MTX2 0x95 /* Matrix coefficient 2 */
+#define MTX3 0x96 /* Matrix coefficient 3 */
+#define MTX4 0x97 /* Matrix coefficient 4 */
+#define MTX5 0x98 /* Matrix coefficient 5 */
+#define MTX6 0x99 /* Matrix coefficient 6 */
+#define MTX_CTRL 0x9A /* Matrix control */
+#define BRIGHT 0x9B /* Brightness control */
+#define CNTRST 0x9C /* Contrast contrast */
+#define CNTRST_CTRL 0x9D /* Contrast contrast center */
+#define UVAD_J0 0x9E /* Auto UV adjust contrast 0 */
+#define UVAD_J1 0x9F /* Auto UV adjust contrast 1 */
+#define SCAL0 0xA0 /* Scaling control 0 */
+#define SCAL1 0xA1 /* Scaling control 1 */
+#define SCAL2 0xA2 /* Scaling control 2 */
+#define FIFODLYM 0xA3 /* FIFO manual mode delay control */
+#define FIFODLYA 0xA4 /* FIFO auto mode delay control */
+#define SDE 0xA6 /* Special digital effect control */
+#define USAT 0xA7 /* U component saturation control */
+#define VSAT 0xA8 /* V component saturation control */
+/* for ov7720 */
+#define HUE0 0xA9 /* Hue control 0 */
+#define HUE1 0xAA /* Hue control 1 */
+/* for ov7725 */
+#define HUECOS 0xA9 /* Cosine value */
+#define HUESIN 0xAA /* Sine value */
+
+#define SIGN 0xAB /* Sign bit for Hue and contrast */
+#define DSPAUTO 0xAC /* DSP auto function ON/OFF control */
+
+/*
+ * register detail
+ */
+
+/* COM2 */
+#define SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */
+ /* Output drive capability */
+#define OCAP_1x 0x00 /* 1x */
+#define OCAP_2x 0x01 /* 2x */
+#define OCAP_3x 0x02 /* 3x */
+#define OCAP_4x 0x03 /* 4x */
+
+/* COM3 */
+#define SWAP_MASK (SWAP_RGB | SWAP_YUV | SWAP_ML)
+#define IMG_MASK (VFLIP_IMG | HFLIP_IMG)
+
+#define VFLIP_IMG 0x80 /* Vertical flip image ON/OFF selection */
+#define HFLIP_IMG 0x40 /* Horizontal mirror image ON/OFF selection */
+#define SWAP_RGB 0x20 /* Swap B/R output sequence in RGB mode */
+#define SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV mode */
+#define SWAP_ML 0x08 /* Swap output MSB/LSB */
+ /* Tri-state option for output clock */
+#define NOTRI_CLOCK 0x04 /* 0: Tri-state at this period */
+ /* 1: No tri-state at this period */
+ /* Tri-state option for output data */
+#define NOTRI_DATA 0x02 /* 0: Tri-state at this period */
+ /* 1: No tri-state at this period */
+#define SCOLOR_TEST 0x01 /* Sensor color bar test pattern */
+
+/* COM4 */
+ /* PLL frequency control */
+#define PLL_BYPASS 0x00 /* 00: Bypass PLL */
+#define PLL_4x 0x40 /* 01: PLL 4x */
+#define PLL_6x 0x80 /* 10: PLL 6x */
+#define PLL_8x 0xc0 /* 11: PLL 8x */
+ /* AEC evaluate window */
+#define AEC_FULL 0x00 /* 00: Full window */
+#define AEC_1p2 0x10 /* 01: 1/2 window */
+#define AEC_1p4 0x20 /* 10: 1/4 window */
+#define AEC_2p3 0x30 /* 11: Low 2/3 window */
+#define COM4_RESERVED 0x01 /* Reserved bit */
+
+/* COM5 */
+#define AFR_ON_OFF 0x80 /* Auto frame rate control ON/OFF selection */
+#define AFR_SPPED 0x40 /* Auto frame rate control speed selection */
+ /* Auto frame rate max rate control */
+#define AFR_NO_RATE 0x00 /* No reduction of frame rate */
+#define AFR_1p2 0x10 /* Max reduction to 1/2 frame rate */
+#define AFR_1p4 0x20 /* Max reduction to 1/4 frame rate */
+#define AFR_1p8 0x30 /* Max reduction to 1/8 frame rate */
+ /* Auto frame rate active point control */
+#define AF_2x 0x00 /* Add frame when AGC reaches 2x gain */
+#define AF_4x 0x04 /* Add frame when AGC reaches 4x gain */
+#define AF_8x 0x08 /* Add frame when AGC reaches 8x gain */
+#define AF_16x 0x0c /* Add frame when AGC reaches 16x gain */
+ /* AEC max step control */
+#define AEC_NO_LIMIT 0x01 /* 0 : AEC incease step has limit */
+ /* 1 : No limit to AEC increase step */
+/* CLKRC */
+ /* Input clock divider register */
+#define CLKRC_RESERVED 0x80 /* Reserved bit */
+#define CLKRC_DIV(n) ((n) - 1)
+
+/* COM7 */
+ /* SCCB Register Reset */
+#define SCCB_RESET 0x80 /* 0 : No change */
+ /* 1 : Resets all registers to default */
+ /* Resolution selection */
+#define SLCT_MASK 0x40 /* Mask of VGA or QVGA */
+#define SLCT_VGA 0x00 /* 0 : VGA */
+#define SLCT_QVGA 0x40 /* 1 : QVGA */
+#define ITU656_ON_OFF 0x20 /* ITU656 protocol ON/OFF selection */
+#define SENSOR_RAW 0x10 /* Sensor RAW */
+ /* RGB output format control */
+#define FMT_MASK 0x0c /* Mask of color format */
+#define FMT_GBR422 0x00 /* 00 : GBR 4:2:2 */
+#define FMT_RGB565 0x04 /* 01 : RGB 565 */
+#define FMT_RGB555 0x08 /* 10 : RGB 555 */
+#define FMT_RGB444 0x0c /* 11 : RGB 444 */
+ /* Output format control */
+#define OFMT_MASK 0x03 /* Mask of output format */
+#define OFMT_YUV 0x00 /* 00 : YUV */
+#define OFMT_P_BRAW 0x01 /* 01 : Processed Bayer RAW */
+#define OFMT_RGB 0x02 /* 10 : RGB */
+#define OFMT_BRAW 0x03 /* 11 : Bayer RAW */
+
+/* COM8 */
+#define FAST_ALGO 0x80 /* Enable fast AGC/AEC algorithm */
+ /* AEC Setp size limit */
+#define UNLMT_STEP 0x40 /* 0 : Step size is limited */
+ /* 1 : Unlimited step size */
+#define BNDF_ON_OFF 0x20 /* Banding filter ON/OFF */
+#define AEC_BND 0x10 /* Enable AEC below banding value */
+#define AEC_ON_OFF 0x08 /* Fine AEC ON/OFF control */
+#define AGC_ON 0x04 /* AGC Enable */
+#define AWB_ON 0x02 /* AWB Enable */
+#define AEC_ON 0x01 /* AEC Enable */
+
+/* COM9 */
+#define BASE_AECAGC 0x80 /* Histogram or average based AEC/AGC */
+ /* Automatic gain ceiling - maximum AGC value */
+#define GAIN_2x 0x00 /* 000 : 2x */
+#define GAIN_4x 0x10 /* 001 : 4x */
+#define GAIN_8x 0x20 /* 010 : 8x */
+#define GAIN_16x 0x30 /* 011 : 16x */
+#define GAIN_32x 0x40 /* 100 : 32x */
+#define GAIN_64x 0x50 /* 101 : 64x */
+#define GAIN_128x 0x60 /* 110 : 128x */
+#define DROP_VSYNC 0x04 /* Drop VSYNC output of corrupt frame */
+#define DROP_HREF 0x02 /* Drop HREF output of corrupt frame */
+
+/* COM11 */
+#define SGLF_ON_OFF 0x02 /* Single frame ON/OFF selection */
+#define SGLF_TRIG 0x01 /* Single frame transfer trigger */
+
+/* HREF */
+#define HREF_VSTART_SHIFT 6 /* VSTART LSB */
+#define HREF_HSTART_SHIFT 4 /* HSTART 2 LSBs */
+#define HREF_VSIZE_SHIFT 2 /* VSIZE LSB */
+#define HREF_HSIZE_SHIFT 0 /* HSIZE 2 LSBs */
+
+/* EXHCH */
+#define EXHCH_VSIZE_SHIFT 2 /* VOUTSIZE LSB */
+#define EXHCH_HSIZE_SHIFT 0 /* HOUTSIZE 2 LSBs */
+
+/* DSP_CTRL1 */
+#define FIFO_ON 0x80 /* FIFO enable/disable selection */
+#define UV_ON_OFF 0x40 /* UV adjust function ON/OFF selection */
+#define YUV444_2_422 0x20 /* YUV444 to 422 UV channel option selection */
+#define CLR_MTRX_ON_OFF 0x10 /* Color matrix ON/OFF selection */
+#define INTPLT_ON_OFF 0x08 /* Interpolation ON/OFF selection */
+#define GMM_ON_OFF 0x04 /* Gamma function ON/OFF selection */
+#define AUTO_BLK_ON_OFF 0x02 /* Black defect auto correction ON/OFF */
+#define AUTO_WHT_ON_OFF 0x01 /* White define auto correction ON/OFF */
+
+/* DSP_CTRL3 */
+#define UV_MASK 0x80 /* UV output sequence option */
+#define UV_ON 0x80 /* ON */
+#define UV_OFF 0x00 /* OFF */
+#define CBAR_MASK 0x20 /* DSP Color bar mask */
+#define CBAR_ON 0x20 /* ON */
+#define CBAR_OFF 0x00 /* OFF */
+
+/* DSP_CTRL4 */
+#define DSP_OFMT_YUV 0x00
+#define DSP_OFMT_RGB 0x00
+#define DSP_OFMT_RAW8 0x02
+#define DSP_OFMT_RAW10 0x03
+
+/* DSPAUTO (DSP Auto Function ON/OFF Control) */
+#define AWB_ACTRL 0x80 /* AWB auto threshold control */
+#define DENOISE_ACTRL 0x40 /* De-noise auto threshold control */
+#define EDGE_ACTRL 0x20 /* Edge enhancement auto strength control */
+#define UV_ACTRL 0x10 /* UV adjust auto slope control */
+#define SCAL0_ACTRL 0x08 /* Auto scaling factor control */
+#define SCAL1_2_ACTRL 0x04 /* Auto scaling factor control */
+
+#define OV772X_MAX_WIDTH VGA_WIDTH
+#define OV772X_MAX_HEIGHT VGA_HEIGHT
+
+/*
+ * ID
+ */
+#define OV7720 0x7720
+#define OV7725 0x7721
+#define VERSION(pid, ver) ((pid << 8) | (ver & 0xFF))
+
+/*
+ * PLL multipliers
+ */
+static struct {
+ unsigned int mult;
+ u8 com4;
+} ov772x_pll[] = {
+ { 1, PLL_BYPASS, },
+ { 4, PLL_4x, },
+ { 6, PLL_6x, },
+ { 8, PLL_8x, },
+};
+
+/*
+ * struct
+ */
+
+struct ov772x_color_format {
+ u32 code;
+ enum v4l2_colorspace colorspace;
+ u8 dsp3;
+ u8 dsp4;
+ u8 com3;
+ u8 com7;
+};
+
+struct ov772x_win_size {
+ char *name;
+ unsigned char com7_bit;
+ unsigned int sizeimage;
+ struct v4l2_rect rect;
+};
+
+struct ov772x_priv {
+ struct v4l2_subdev subdev;
+ struct v4l2_ctrl_handler hdl;
+ struct clk *clk;
+ struct ov772x_camera_info *info;
+ struct gpio_desc *pwdn_gpio;
+ struct gpio_desc *rstb_gpio;
+ const struct ov772x_color_format *cfmt;
+ const struct ov772x_win_size *win;
+ unsigned short flag_vflip:1;
+ unsigned short flag_hflip:1;
+ /* band_filter = COM8[5] ? 256 - BDBASE : 0 */
+ unsigned short band_filter;
+ unsigned int fps;
+};
+
+/*
+ * supported color format list
+ */
+static const struct ov772x_color_format ov772x_cfmts[] = {
+ {
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .dsp3 = 0x0,
+ .dsp4 = DSP_OFMT_YUV,
+ .com3 = SWAP_YUV,
+ .com7 = OFMT_YUV,
+ },
+ {
+ .code = MEDIA_BUS_FMT_YVYU8_2X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .dsp3 = UV_ON,
+ .dsp4 = DSP_OFMT_YUV,
+ .com3 = SWAP_YUV,
+ .com7 = OFMT_YUV,
+ },
+ {
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .dsp3 = 0x0,
+ .dsp4 = DSP_OFMT_YUV,
+ .com3 = 0x0,
+ .com7 = OFMT_YUV,
+ },
+ {
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .dsp3 = 0x0,
+ .dsp4 = DSP_OFMT_YUV,
+ .com3 = SWAP_RGB,
+ .com7 = FMT_RGB555 | OFMT_RGB,
+ },
+ {
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .dsp3 = 0x0,
+ .dsp4 = DSP_OFMT_YUV,
+ .com3 = 0x0,
+ .com7 = FMT_RGB555 | OFMT_RGB,
+ },
+ {
+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .dsp3 = 0x0,
+ .dsp4 = DSP_OFMT_YUV,
+ .com3 = SWAP_RGB,
+ .com7 = FMT_RGB565 | OFMT_RGB,
+ },
+ {
+ .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .dsp3 = 0x0,
+ .dsp4 = DSP_OFMT_YUV,
+ .com3 = 0x0,
+ .com7 = FMT_RGB565 | OFMT_RGB,
+ },
+ {
+ /* Setting DSP4 to DSP_OFMT_RAW8 still gives 10-bit output,
+ * regardless of the COM7 value. We can thus only support 10-bit
+ * Bayer until someone figures it out.
+ */
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .dsp3 = 0x0,
+ .dsp4 = DSP_OFMT_RAW10,
+ .com3 = 0x0,
+ .com7 = SENSOR_RAW | OFMT_BRAW,
+ },
+};
+
+/*
+ * window size list
+ */
+
+static const struct ov772x_win_size ov772x_win_sizes[] = {
+ {
+ .name = "VGA",
+ .com7_bit = SLCT_VGA,
+ .sizeimage = 510 * 748,
+ .rect = {
+ .left = 140,
+ .top = 14,
+ .width = VGA_WIDTH,
+ .height = VGA_HEIGHT,
+ },
+ }, {
+ .name = "QVGA",
+ .com7_bit = SLCT_QVGA,
+ .sizeimage = 278 * 576,
+ .rect = {
+ .left = 252,
+ .top = 6,
+ .width = QVGA_WIDTH,
+ .height = QVGA_HEIGHT,
+ },
+ },
+};
+
+/*
+ * frame rate settings lists
+ */
+static const unsigned int ov772x_frame_intervals[] = { 5, 10, 15, 20, 30, 60 };
+
+/*
+ * general function
+ */
+
+static struct ov772x_priv *to_ov772x(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ov772x_priv, subdev);
+}
+
+static inline int ov772x_read(struct i2c_client *client, u8 addr)
+{
+ return i2c_smbus_read_byte_data(client, addr);
+}
+
+static inline int ov772x_write(struct i2c_client *client, u8 addr, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, addr, value);
+}
+
+static int ov772x_mask_set(struct i2c_client *client, u8 command, u8 mask,
+ u8 set)
+{
+ s32 val = ov772x_read(client, command);
+
+ if (val < 0)
+ return val;
+
+ val &= ~mask;
+ val |= set & mask;
+
+ return ov772x_write(client, command, val);
+}
+
+static int ov772x_reset(struct i2c_client *client)
+{
+ int ret;
+
+ ret = ov772x_write(client, COM7, SCCB_RESET);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(1000, 5000);
+
+ return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
+}
+
+/*
+ * subdev ops
+ */
+
+static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov772x_priv *priv = to_ov772x(sd);
+
+ if (!enable) {
+ ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
+ return 0;
+ }
+
+ ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0);
+
+ dev_dbg(&client->dev, "format %d, win %s\n",
+ priv->cfmt->code, priv->win->name);
+
+ return 0;
+}
+
+static int ov772x_set_frame_rate(struct ov772x_priv *priv,
+ struct v4l2_fract *tpf,
+ const struct ov772x_color_format *cfmt,
+ const struct ov772x_win_size *win)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
+ unsigned long fin = clk_get_rate(priv->clk);
+ unsigned int fps = tpf->numerator ?
+ tpf->denominator / tpf->numerator :
+ tpf->denominator;
+ unsigned int best_diff;
+ unsigned int fsize;
+ unsigned int pclk;
+ unsigned int diff;
+ unsigned int idx;
+ unsigned int i;
+ u8 clkrc = 0;
+ u8 com4 = 0;
+ int ret;
+
+ /* Approximate to the closest supported frame interval. */
+ best_diff = ~0L;
+ for (i = 0, idx = 0; i < ARRAY_SIZE(ov772x_frame_intervals); i++) {
+ diff = abs(fps - ov772x_frame_intervals[i]);
+ if (diff < best_diff) {
+ idx = i;
+ best_diff = diff;
+ }
+ }
+ fps = ov772x_frame_intervals[idx];
+
+ /* Use image size (with blankings) to calculate desired pixel clock. */
+ switch (cfmt->com7 & OFMT_MASK) {
+ case OFMT_BRAW:
+ fsize = win->sizeimage;
+ break;
+ case OFMT_RGB:
+ case OFMT_YUV:
+ default:
+ fsize = win->sizeimage * 2;
+ break;
+ }
+
+ pclk = fps * fsize;
+
+ /*
+ * Pixel clock generation circuit is pretty simple:
+ *
+ * Fin -> [ / CLKRC_div] -> [ * PLL_mult] -> pclk
+ *
+ * Try to approximate the desired pixel clock testing all available
+ * PLL multipliers (1x, 4x, 6x, 8x) and calculate corresponding
+ * divisor with:
+ *
+ * div = PLL_mult * Fin / pclk
+ *
+ * and re-calculate the pixel clock using it:
+ *
+ * pclk = Fin * PLL_mult / CLKRC_div
+ *
+ * Choose the PLL_mult and CLKRC_div pair that gives a pixel clock
+ * closer to the desired one.
+ *
+ * The desired pixel clock is calculated using a known frame size
+ * (blanking included) and FPS.
+ */
+ best_diff = ~0L;
+ for (i = 0; i < ARRAY_SIZE(ov772x_pll); i++) {
+ unsigned int pll_mult = ov772x_pll[i].mult;
+ unsigned int pll_out = pll_mult * fin;
+ unsigned int t_pclk;
+ unsigned int div;
+
+ if (pll_out < pclk)
+ continue;
+
+ div = DIV_ROUND_CLOSEST(pll_out, pclk);
+ t_pclk = DIV_ROUND_CLOSEST(fin * pll_mult, div);
+ diff = abs(pclk - t_pclk);
+ if (diff < best_diff) {
+ best_diff = diff;
+ clkrc = CLKRC_DIV(div);
+ com4 = ov772x_pll[i].com4;
+ }
+ }
+
+ ret = ov772x_write(client, COM4, com4 | COM4_RESERVED);
+ if (ret < 0)
+ return ret;
+
+ ret = ov772x_write(client, CLKRC, clkrc | CLKRC_RESERVED);
+ if (ret < 0)
+ return ret;
+
+ tpf->numerator = 1;
+ tpf->denominator = fps;
+ priv->fps = tpf->denominator;
+
+ return 0;
+}
+
+static int ov772x_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *ival)
+{
+ struct ov772x_priv *priv = to_ov772x(sd);
+ struct v4l2_fract *tpf = &ival->interval;
+
+ tpf->numerator = 1;
+ tpf->denominator = priv->fps;
+
+ return 0;
+}
+
+static int ov772x_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *ival)
+{
+ struct ov772x_priv *priv = to_ov772x(sd);
+ struct v4l2_fract *tpf = &ival->interval;
+
+ return ov772x_set_frame_rate(priv, tpf, priv->cfmt, priv->win);
+}
+
+static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov772x_priv *priv = container_of(ctrl->handler,
+ struct ov772x_priv, hdl);
+ struct v4l2_subdev *sd = &priv->subdev;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+ u8 val;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ val = ctrl->val ? VFLIP_IMG : 0x00;
+ priv->flag_vflip = ctrl->val;
+ if (priv->info->flags & OV772X_FLAG_VFLIP)
+ val ^= VFLIP_IMG;
+ return ov772x_mask_set(client, COM3, VFLIP_IMG, val);
+ case V4L2_CID_HFLIP:
+ val = ctrl->val ? HFLIP_IMG : 0x00;
+ priv->flag_hflip = ctrl->val;
+ if (priv->info->flags & OV772X_FLAG_HFLIP)
+ val ^= HFLIP_IMG;
+ return ov772x_mask_set(client, COM3, HFLIP_IMG, val);
+ case V4L2_CID_BAND_STOP_FILTER:
+ if (!ctrl->val) {
+ /* Switch the filter off, it is on now */
+ ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff);
+ if (!ret)
+ ret = ov772x_mask_set(client, COM8,
+ BNDF_ON_OFF, 0);
+ } else {
+ /* Switch the filter on, set AEC low limit */
+ val = 256 - ctrl->val;
+ ret = ov772x_mask_set(client, COM8,
+ BNDF_ON_OFF, BNDF_ON_OFF);
+ if (!ret)
+ ret = ov772x_mask_set(client, BDBASE,
+ 0xff, val);
+ }
+ if (!ret)
+ priv->band_filter = ctrl->val;
+ return ret;
+ }
+
+ return -EINVAL;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov772x_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ reg->size = 1;
+ if (reg->reg > 0xff)
+ return -EINVAL;
+
+ ret = ov772x_read(client, reg->reg);
+ if (ret < 0)
+ return ret;
+
+ reg->val = (__u64)ret;
+
+ return 0;
+}
+
+static int ov772x_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->reg > 0xff ||
+ reg->val > 0xff)
+ return -EINVAL;
+
+ return ov772x_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov772x_power_on(struct ov772x_priv *priv)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
+ int ret;
+
+ if (priv->clk) {
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+ }
+
+ if (priv->pwdn_gpio) {
+ gpiod_set_value(priv->pwdn_gpio, 1);
+ usleep_range(500, 1000);
+ }
+
+ /*
+ * FIXME: The reset signal is connected to a shared GPIO on some
+ * platforms (namely the SuperH Migo-R). Until a framework becomes
+ * available to handle this cleanly, request the GPIO temporarily
+ * to avoid conflicts.
+ */
+ priv->rstb_gpio = gpiod_get_optional(&client->dev, "rstb",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(priv->rstb_gpio)) {
+ dev_info(&client->dev, "Unable to get GPIO \"rstb\"");
+ return PTR_ERR(priv->rstb_gpio);
+ }
+
+ if (priv->rstb_gpio) {
+ gpiod_set_value(priv->rstb_gpio, 1);
+ usleep_range(500, 1000);
+ gpiod_set_value(priv->rstb_gpio, 0);
+ usleep_range(500, 1000);
+
+ gpiod_put(priv->rstb_gpio);
+ }
+
+ return 0;
+}
+
+static int ov772x_power_off(struct ov772x_priv *priv)
+{
+ clk_disable_unprepare(priv->clk);
+
+ if (priv->pwdn_gpio) {
+ gpiod_set_value(priv->pwdn_gpio, 0);
+ usleep_range(500, 1000);
+ }
+
+ return 0;
+}
+
+static int ov772x_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct ov772x_priv *priv = to_ov772x(sd);
+
+ return on ? ov772x_power_on(priv) :
+ ov772x_power_off(priv);
+}
+
+static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
+{
+ const struct ov772x_win_size *win = &ov772x_win_sizes[0];
+ u32 best_diff = UINT_MAX;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ov772x_win_sizes); ++i) {
+ u32 diff = abs(width - ov772x_win_sizes[i].rect.width)
+ + abs(height - ov772x_win_sizes[i].rect.height);
+ if (diff < best_diff) {
+ best_diff = diff;
+ win = &ov772x_win_sizes[i];
+ }
+ }
+
+ return win;
+}
+
+static void ov772x_select_params(const struct v4l2_mbus_framefmt *mf,
+ const struct ov772x_color_format **cfmt,
+ const struct ov772x_win_size **win)
+{
+ unsigned int i;
+
+ /* Select a format. */
+ *cfmt = &ov772x_cfmts[0];
+
+ for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) {
+ if (mf->code == ov772x_cfmts[i].code) {
+ *cfmt = &ov772x_cfmts[i];
+ break;
+ }
+ }
+
+ /* Select a window size. */
+ *win = ov772x_select_win(mf->width, mf->height);
+}
+
+static int ov772x_set_params(struct ov772x_priv *priv,
+ const struct ov772x_color_format *cfmt,
+ const struct ov772x_win_size *win)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
+ struct v4l2_fract tpf;
+ int ret;
+ u8 val;
+
+ /* Reset hardware. */
+ ov772x_reset(client);
+
+ /* Edge Ctrl. */
+ if (priv->info->edgectrl.strength & OV772X_MANUAL_EDGE_CTRL) {
+ /*
+ * Manual Edge Control Mode.
+ *
+ * Edge auto strength bit is set by default.
+ * Remove it when manual mode.
+ */
+
+ ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ ret = ov772x_mask_set(client,
+ EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK,
+ priv->info->edgectrl.threshold);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ ret = ov772x_mask_set(client,
+ EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK,
+ priv->info->edgectrl.strength);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ } else if (priv->info->edgectrl.upper > priv->info->edgectrl.lower) {
+ /*
+ * Auto Edge Control Mode.
+ *
+ * Set upper and lower limit.
+ */
+ ret = ov772x_mask_set(client,
+ EDGE_UPPER, OV772X_EDGE_UPPER_MASK,
+ priv->info->edgectrl.upper);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ ret = ov772x_mask_set(client,
+ EDGE_LOWER, OV772X_EDGE_LOWER_MASK,
+ priv->info->edgectrl.lower);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ }
+
+ /* Format and window size. */
+ ret = ov772x_write(client, HSTART, win->rect.left >> 2);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ ret = ov772x_write(client, HSIZE, win->rect.width >> 2);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ ret = ov772x_write(client, VSTART, win->rect.top >> 1);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ ret = ov772x_write(client, VSIZE, win->rect.height >> 1);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ ret = ov772x_write(client, HOUTSIZE, win->rect.width >> 2);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ ret = ov772x_write(client, VOUTSIZE, win->rect.height >> 1);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ ret = ov772x_write(client, HREF,
+ ((win->rect.top & 1) << HREF_VSTART_SHIFT) |
+ ((win->rect.left & 3) << HREF_HSTART_SHIFT) |
+ ((win->rect.height & 1) << HREF_VSIZE_SHIFT) |
+ ((win->rect.width & 3) << HREF_HSIZE_SHIFT));
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ ret = ov772x_write(client, EXHCH,
+ ((win->rect.height & 1) << EXHCH_VSIZE_SHIFT) |
+ ((win->rect.width & 3) << EXHCH_HSIZE_SHIFT));
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ /* Set DSP_CTRL3. */
+ val = cfmt->dsp3;
+ if (val) {
+ ret = ov772x_mask_set(client,
+ DSP_CTRL3, UV_MASK, val);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ }
+
+ /* DSP_CTRL4: AEC reference point and DSP output format. */
+ if (cfmt->dsp4) {
+ ret = ov772x_write(client, DSP_CTRL4, cfmt->dsp4);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ }
+
+ /* Set COM3. */
+ val = cfmt->com3;
+ if (priv->info->flags & OV772X_FLAG_VFLIP)
+ val |= VFLIP_IMG;
+ if (priv->info->flags & OV772X_FLAG_HFLIP)
+ val |= HFLIP_IMG;
+ if (priv->flag_vflip)
+ val ^= VFLIP_IMG;
+ if (priv->flag_hflip)
+ val ^= HFLIP_IMG;
+
+ ret = ov772x_mask_set(client,
+ COM3, SWAP_MASK | IMG_MASK, val);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ /* COM7: Sensor resolution and output format control. */
+ ret = ov772x_write(client, COM7, win->com7_bit | cfmt->com7);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ /* COM4, CLKRC: Set pixel clock and framerate. */
+ tpf.numerator = 1;
+ tpf.denominator = priv->fps;
+ ret = ov772x_set_frame_rate(priv, &tpf, cfmt, win);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ /* Set COM8. */
+ if (priv->band_filter) {
+ ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1);
+ if (!ret)
+ ret = ov772x_mask_set(client, BDBASE,
+ 0xff, 256 - priv->band_filter);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ }
+
+ return ret;
+
+ov772x_set_fmt_error:
+
+ ov772x_reset(client);
+
+ return ret;
+}
+
+static int ov772x_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ struct ov772x_priv *priv = to_ov772x(sd);
+
+ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ sel->r.left = 0;
+ sel->r.top = 0;
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP:
+ sel->r.width = priv->win->rect.width;
+ sel->r.height = priv->win->rect.height;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ov772x_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct v4l2_mbus_framefmt *mf = &format->format;
+ struct ov772x_priv *priv = to_ov772x(sd);
+
+ if (format->pad)
+ return -EINVAL;
+
+ mf->width = priv->win->rect.width;
+ mf->height = priv->win->rect.height;
+ mf->code = priv->cfmt->code;
+ mf->colorspace = priv->cfmt->colorspace;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int ov772x_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct ov772x_priv *priv = to_ov772x(sd);
+ struct v4l2_mbus_framefmt *mf = &format->format;
+ const struct ov772x_color_format *cfmt;
+ const struct ov772x_win_size *win;
+ int ret;
+
+ if (format->pad)
+ return -EINVAL;
+
+ ov772x_select_params(mf, &cfmt, &win);
+
+ mf->code = cfmt->code;
+ mf->width = win->rect.width;
+ mf->height = win->rect.height;
+ mf->field = V4L2_FIELD_NONE;
+ mf->colorspace = cfmt->colorspace;
+ mf->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ mf->quantization = V4L2_QUANTIZATION_DEFAULT;
+ mf->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+ cfg->try_fmt = *mf;
+ return 0;
+ }
+
+ ret = ov772x_set_params(priv, cfmt, win);
+ if (ret < 0)
+ return ret;
+
+ priv->win = win;
+ priv->cfmt = cfmt;
+
+ return 0;
+}
+
+static int ov772x_video_probe(struct ov772x_priv *priv)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
+ u8 pid, ver;
+ const char *devname;
+ int ret;
+
+ ret = ov772x_s_power(&priv->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Check and show product ID and manufacturer ID. */
+ pid = ov772x_read(client, PID);
+ ver = ov772x_read(client, VER);
+
+ switch (VERSION(pid, ver)) {
+ case OV7720:
+ devname = "ov7720";
+ break;
+ case OV7725:
+ devname = "ov7725";
+ break;
+ default:
+ dev_err(&client->dev,
+ "Product ID error %x:%x\n", pid, ver);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ dev_info(&client->dev,
+ "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+ devname,
+ pid,
+ ver,
+ ov772x_read(client, MIDH),
+ ov772x_read(client, MIDL));
+ ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+ ov772x_s_power(&priv->subdev, 0);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops ov772x_ctrl_ops = {
+ .s_ctrl = ov772x_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ov772x_g_register,
+ .s_register = ov772x_s_register,
+#endif
+ .s_power = ov772x_s_power,
+};
+
+static int ov772x_enum_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ if (fie->pad || fie->index >= ARRAY_SIZE(ov772x_frame_intervals))
+ return -EINVAL;
+
+ if (fie->width != VGA_WIDTH && fie->width != QVGA_WIDTH)
+ return -EINVAL;
+ if (fie->height != VGA_HEIGHT && fie->height != QVGA_HEIGHT)
+ return -EINVAL;
+
+ fie->interval.numerator = 1;
+ fie->interval.denominator = ov772x_frame_intervals[fie->index];
+
+ return 0;
+}
+
+static int ov772x_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 >= ARRAY_SIZE(ov772x_cfmts))
+ return -EINVAL;
+
+ code->code = ov772x_cfmts[code->index].code;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
+ .s_stream = ov772x_s_stream,
+ .s_frame_interval = ov772x_s_frame_interval,
+ .g_frame_interval = ov772x_g_frame_interval,
+};
+
+static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = {
+ .enum_frame_interval = ov772x_enum_frame_interval,
+ .enum_mbus_code = ov772x_enum_mbus_code,
+ .get_selection = ov772x_get_selection,
+ .get_fmt = ov772x_get_fmt,
+ .set_fmt = ov772x_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ov772x_subdev_ops = {
+ .core = &ov772x_subdev_core_ops,
+ .video = &ov772x_subdev_video_ops,
+ .pad = &ov772x_subdev_pad_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+
+static int ov772x_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct ov772x_priv *priv;
+ struct i2c_adapter *adapter = client->adapter;
+ int ret;
+
+ if (!client->dev.platform_data) {
+ dev_err(&client->dev, "Missing ov772x platform data\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_PROTOCOL_MANGLING)) {
+ dev_err(&adapter->dev,
+ "I2C-Adapter doesn't support SMBUS_BYTE_DATA or PROTOCOL_MANGLING\n");
+ return -EIO;
+ }
+ client->flags |= I2C_CLIENT_SCCB;
+
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->info = client->dev.platform_data;
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
+ v4l2_ctrl_handler_init(&priv->hdl, 3);
+ v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
+ V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0);
+ priv->subdev.ctrl_handler = &priv->hdl;
+ if (priv->hdl.error)
+ return priv->hdl.error;
+
+ priv->clk = clk_get(&client->dev, "xclk");
+ if (IS_ERR(priv->clk)) {
+ dev_err(&client->dev, "Unable to get xclk clock\n");
+ ret = PTR_ERR(priv->clk);
+ goto error_ctrl_free;
+ }
+
+ priv->pwdn_gpio = gpiod_get_optional(&client->dev, "pwdn",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(priv->pwdn_gpio)) {
+ dev_info(&client->dev, "Unable to get GPIO \"pwdn\"");
+ ret = PTR_ERR(priv->pwdn_gpio);
+ goto error_clk_put;
+ }
+
+ ret = ov772x_video_probe(priv);
+ if (ret < 0)
+ goto error_gpio_put;
+
+ priv->cfmt = &ov772x_cfmts[0];
+ priv->win = &ov772x_win_sizes[0];
+ priv->fps = 15;
+
+ ret = v4l2_async_register_subdev(&priv->subdev);
+ if (ret)
+ goto error_gpio_put;
+
+ return 0;
+
+error_gpio_put:
+ if (priv->pwdn_gpio)
+ gpiod_put(priv->pwdn_gpio);
+error_clk_put:
+ clk_put(priv->clk);
+error_ctrl_free:
+ v4l2_ctrl_handler_free(&priv->hdl);
+
+ return ret;
+}
+
+static int ov772x_remove(struct i2c_client *client)
+{
+ struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client));
+
+ clk_put(priv->clk);
+ if (priv->pwdn_gpio)
+ gpiod_put(priv->pwdn_gpio);
+ v4l2_async_unregister_subdev(&priv->subdev);
+ v4l2_ctrl_handler_free(&priv->hdl);
+
+ return 0;
+}
+
+static const struct i2c_device_id ov772x_id[] = {
+ { "ov772x", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ov772x_id);
+
+static struct i2c_driver ov772x_i2c_driver = {
+ .driver = {
+ .name = "ov772x",
+ },
+ .probe = ov772x_probe,
+ .remove = ov772x_remove,
+ .id_table = ov772x_id,
+};
+
+module_i2c_driver(ov772x_i2c_driver);
+
+MODULE_DESCRIPTION("V4L2 driver for OV772x image sensor");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
index fc9dbbcae56e..01f578785e79 100644
--- a/drivers/media/i2c/ov7740.c
+++ b/drivers/media/i2c/ov7740.c
@@ -279,7 +279,7 @@ static int ov7740_get_register(struct v4l2_subdev *sd,
reg->val = val;
reg->size = 1;
- return 0;
+ return ret;
}
static int ov7740_set_register(struct v4l2_subdev *sd,
@@ -624,17 +624,11 @@ err_unlock:
return ret;
}
-static int ov7740_get_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *parms)
+static int ov7740_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *ival)
{
- struct v4l2_captureparm *cp = &parms->parm.capture;
- struct v4l2_fract *tpf = &cp->timeperframe;
-
- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
+ struct v4l2_fract *tpf = &ival->interval;
- memset(cp, 0, sizeof(struct v4l2_captureparm));
- cp->capability = V4L2_CAP_TIMEPERFRAME;
tpf->numerator = 1;
tpf->denominator = 60;
@@ -642,18 +636,11 @@ static int ov7740_get_parm(struct v4l2_subdev *sd,
return 0;
}
-static int ov7740_set_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *parms)
+static int ov7740_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *ival)
{
- struct v4l2_captureparm *cp = &parms->parm.capture;
- struct v4l2_fract *tpf = &cp->timeperframe;
-
- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (cp->extendedmode != 0)
- return -EINVAL;
+ struct v4l2_fract *tpf = &ival->interval;
- cp->capability = V4L2_CAP_TIMEPERFRAME;
tpf->numerator = 1;
tpf->denominator = 60;
@@ -663,8 +650,8 @@ static int ov7740_set_parm(struct v4l2_subdev *sd,
static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = {
.s_stream = ov7740_set_stream,
- .s_parm = ov7740_set_parm,
- .g_parm = ov7740_get_parm,
+ .s_frame_interval = ov7740_s_frame_interval,
+ .g_frame_interval = ov7740_g_frame_interval,
};
static const struct reg_sequence ov7740_format_yuyv[] = {
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index e519f278d5f9..5bea31cd41aa 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -11,8 +11,10 @@
* 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/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/media.h>
@@ -249,9 +251,10 @@ struct ov965x {
struct v4l2_subdev sd;
struct media_pad pad;
enum v4l2_mbus_type bus_type;
- int gpios[NUM_GPIOS];
+ struct gpio_desc *gpios[NUM_GPIOS];
/* External master clock frequency */
unsigned long mclk_frequency;
+ struct clk *clk;
/* Protects the struct fields below */
struct mutex lock;
@@ -513,24 +516,27 @@ static int ov965x_set_color_matrix(struct ov965x *ov965x)
return 0;
}
-static void ov965x_gpio_set(int gpio, int val)
-{
- if (gpio_is_valid(gpio))
- gpio_set_value(gpio, val);
-}
-
-static void __ov965x_set_power(struct ov965x *ov965x, int on)
+static int __ov965x_set_power(struct ov965x *ov965x, int on)
{
if (on) {
- ov965x_gpio_set(ov965x->gpios[GPIO_PWDN], 0);
- ov965x_gpio_set(ov965x->gpios[GPIO_RST], 0);
+ int ret = clk_prepare_enable(ov965x->clk);
+
+ if (ret)
+ return ret;
+
+ gpiod_set_value_cansleep(ov965x->gpios[GPIO_PWDN], 0);
+ gpiod_set_value_cansleep(ov965x->gpios[GPIO_RST], 0);
msleep(25);
} else {
- ov965x_gpio_set(ov965x->gpios[GPIO_RST], 1);
- ov965x_gpio_set(ov965x->gpios[GPIO_PWDN], 1);
+ gpiod_set_value_cansleep(ov965x->gpios[GPIO_RST], 1);
+ gpiod_set_value_cansleep(ov965x->gpios[GPIO_PWDN], 1);
+
+ clk_disable_unprepare(ov965x->clk);
}
ov965x->streaming = 0;
+
+ return 0;
}
static int ov965x_s_power(struct v4l2_subdev *sd, int on)
@@ -543,8 +549,8 @@ static int ov965x_s_power(struct v4l2_subdev *sd, int on)
mutex_lock(&ov965x->lock);
if (ov965x->power == !on) {
- __ov965x_set_power(ov965x, on);
- if (on) {
+ ret = __ov965x_set_power(ov965x, on);
+ if (!ret && on) {
ret = ov965x_write_array(client,
ov965x_init_regs);
ov965x->apply_frame_fmt = 1;
@@ -1130,8 +1136,8 @@ static int __ov965x_set_frame_interval(struct ov965x *ov965x,
if (fi->interval.denominator == 0)
return -EINVAL;
- req_int = (u64)(fi->interval.numerator * 10000) /
- fi->interval.denominator;
+ req_int = (u64)fi->interval.numerator * 10000;
+ do_div(req_int, fi->interval.denominator);
for (i = 0; i < ARRAY_SIZE(ov965x_intervals); i++) {
const struct ov965x_interval *iv = &ov965x_intervals[i];
@@ -1410,16 +1416,17 @@ static const struct v4l2_subdev_ops ov965x_subdev_ops = {
/*
* Reset and power down GPIOs configuration
*/
-static int ov965x_configure_gpios(struct ov965x *ov965x,
- const struct ov9650_platform_data *pdata)
+static int ov965x_configure_gpios_pdata(struct ov965x *ov965x,
+ const struct ov9650_platform_data *pdata)
{
int ret, i;
+ int gpios[NUM_GPIOS];
- ov965x->gpios[GPIO_PWDN] = pdata->gpio_pwdn;
- ov965x->gpios[GPIO_RST] = pdata->gpio_reset;
+ gpios[GPIO_PWDN] = pdata->gpio_pwdn;
+ gpios[GPIO_RST] = pdata->gpio_reset;
for (i = 0; i < ARRAY_SIZE(ov965x->gpios); i++) {
- int gpio = ov965x->gpios[i];
+ int gpio = gpios[i];
if (!gpio_is_valid(gpio))
continue;
@@ -1429,9 +1436,30 @@ static int ov965x_configure_gpios(struct ov965x *ov965x,
return ret;
v4l2_dbg(1, debug, &ov965x->sd, "set gpio %d to 1\n", gpio);
- gpio_set_value(gpio, 1);
+ gpio_set_value_cansleep(gpio, 1);
gpio_export(gpio, 0);
- ov965x->gpios[i] = gpio;
+ ov965x->gpios[i] = gpio_to_desc(gpio);
+ }
+
+ return 0;
+}
+
+static int ov965x_configure_gpios(struct ov965x *ov965x)
+{
+ struct device *dev = &ov965x->client->dev;
+
+ ov965x->gpios[GPIO_PWDN] = devm_gpiod_get_optional(dev, "powerdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ov965x->gpios[GPIO_PWDN])) {
+ dev_info(dev, "can't get %s GPIO\n", "powerdown");
+ return PTR_ERR(ov965x->gpios[GPIO_PWDN]);
+ }
+
+ ov965x->gpios[GPIO_RST] = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ov965x->gpios[GPIO_RST])) {
+ dev_info(dev, "can't get %s GPIO\n", "reset");
+ return PTR_ERR(ov965x->gpios[GPIO_RST]);
}
return 0;
@@ -1445,7 +1473,10 @@ static int ov965x_detect_sensor(struct v4l2_subdev *sd)
int ret;
mutex_lock(&ov965x->lock);
- __ov965x_set_power(ov965x, 1);
+ ret = __ov965x_set_power(ov965x, 1);
+ if (ret)
+ goto out;
+
msleep(25);
/* Check sensor revision */
@@ -1465,6 +1496,7 @@ static int ov965x_detect_sensor(struct v4l2_subdev *sd)
ret = -ENODEV;
}
}
+out:
mutex_unlock(&ov965x->lock);
return ret;
@@ -1478,23 +1510,39 @@ static int ov965x_probe(struct i2c_client *client,
struct ov965x *ov965x;
int ret;
- if (!pdata) {
- dev_err(&client->dev, "platform data not specified\n");
- return -EINVAL;
- }
-
- if (pdata->mclk_frequency == 0) {
- dev_err(&client->dev, "MCLK frequency not specified\n");
- return -EINVAL;
- }
-
ov965x = devm_kzalloc(&client->dev, sizeof(*ov965x), GFP_KERNEL);
if (!ov965x)
return -ENOMEM;
- mutex_init(&ov965x->lock);
ov965x->client = client;
- ov965x->mclk_frequency = pdata->mclk_frequency;
+
+ if (pdata) {
+ if (pdata->mclk_frequency == 0) {
+ dev_err(&client->dev, "MCLK frequency not specified\n");
+ return -EINVAL;
+ }
+ ov965x->mclk_frequency = pdata->mclk_frequency;
+
+ ret = ov965x_configure_gpios_pdata(ov965x, pdata);
+ if (ret < 0)
+ return ret;
+ } else if (dev_fwnode(&client->dev)) {
+ ov965x->clk = devm_clk_get(&ov965x->client->dev, NULL);
+ if (IS_ERR(ov965x->clk))
+ return PTR_ERR(ov965x->clk);
+ ov965x->mclk_frequency = clk_get_rate(ov965x->clk);
+
+ ret = ov965x_configure_gpios(ov965x);
+ if (ret < 0)
+ return ret;
+ } else {
+ dev_err(&client->dev,
+ "Neither platform data nor device property specified\n");
+
+ return -EINVAL;
+ }
+
+ mutex_init(&ov965x->lock);
sd = &ov965x->sd;
v4l2_i2c_subdev_init(sd, client, &ov965x_subdev_ops);
@@ -1504,10 +1552,6 @@ static int ov965x_probe(struct i2c_client *client,
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
- ret = ov965x_configure_gpios(ov965x, pdata);
- if (ret < 0)
- goto err_mutex;
-
ov965x->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&sd->entity, 1, &ov965x->pad);
@@ -1563,9 +1607,19 @@ static const struct i2c_device_id ov965x_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ov965x_id);
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id ov965x_of_match[] = {
+ { .compatible = "ovti,ov9650", },
+ { .compatible = "ovti,ov9652", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ov965x_of_match);
+#endif
+
static struct i2c_driver ov965x_i2c_driver = {
.driver = {
.name = DRIVER_NAME,
+ .of_match_table = of_match_ptr(ov965x_of_match),
},
.probe = ov965x_probe,
.remove = ov965x_remove,
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index cdc4f2392ef9..ce196b60f917 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -248,17 +248,17 @@ static int s5c73m3_check_status(struct s5c73m3 *state, unsigned int value)
{
unsigned long start = jiffies;
unsigned long end = start + msecs_to_jiffies(2000);
- int ret = 0;
+ int ret;
u16 status;
int count = 0;
- while (time_is_after_jiffies(end)) {
+ do {
ret = s5c73m3_read(state, REG_STATUS, &status);
if (ret < 0 || status == value)
break;
usleep_range(500, 1000);
++count;
- }
+ } while (time_is_after_jiffies(end));
if (count > 0)
v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd,
diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig
index 72b369895b37..7c2aabc8a3f6 100644
--- a/drivers/media/i2c/soc_camera/Kconfig
+++ b/drivers/media/i2c/soc_camera/Kconfig
@@ -1,11 +1,5 @@
comment "soc_camera sensor drivers"
-config SOC_CAMERA_IMX074
- tristate "imx074 support"
- depends on SOC_CAMERA && I2C
- help
- This driver supports IMX074 cameras from Sony
-
config SOC_CAMERA_MT9M001
tristate "mt9m001 support"
depends on SOC_CAMERA && I2C
@@ -23,12 +17,6 @@ config SOC_CAMERA_MT9M111
This is the legacy configuration which shouldn't be used anymore,
while VIDEO_MT9M111 should be used instead.
-config SOC_CAMERA_MT9T031
- tristate "mt9t031 support"
- depends on SOC_CAMERA && I2C
- help
- This driver supports MT9T031 cameras from Micron.
-
config SOC_CAMERA_MT9T112
tristate "mt9t112 support"
depends on SOC_CAMERA && I2C
diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile
index faa2df8901d2..8c7770f62997 100644
--- a/drivers/media/i2c/soc_camera/Makefile
+++ b/drivers/media/i2c/soc_camera/Makefile
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
-obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c
index 297d22ebcb18..b53c36dfa469 100644
--- a/drivers/media/i2c/soc_camera/mt9t112.c
+++ b/drivers/media/i2c/soc_camera/mt9t112.c
@@ -85,7 +85,7 @@ struct mt9t112_format {
struct mt9t112_priv {
struct v4l2_subdev subdev;
- struct mt9t112_camera_info *info;
+ struct mt9t112_platform_data *info;
struct i2c_client *client;
struct v4l2_rect frame;
struct v4l2_clk *clk;
diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c
index 0bf031b7e4fa..2a4882cddc51 100644
--- a/drivers/media/i2c/sr030pc30.c
+++ b/drivers/media/i2c/sr030pc30.c
@@ -511,13 +511,16 @@ static int sr030pc30_get_fmt(struct v4l2_subdev *sd,
static const struct sr030pc30_format *try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- int i = ARRAY_SIZE(sr030pc30_formats);
+ int i;
sr030pc30_try_frame_size(mf);
- while (i--)
+ for (i = 0; i < ARRAY_SIZE(sr030pc30_formats); i++) {
if (mf->code == sr030pc30_formats[i].code)
break;
+ }
+ if (i == ARRAY_SIZE(sr030pc30_formats))
+ i = 0;
mf->code = sr030pc30_formats[i].code;
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 2b8181469b93..393bbbbbaad7 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* tc358743 - Toshiba HDMI to CSI-2 bridge
*
* Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights
* reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
*/
/*
diff --git a/drivers/media/i2c/tc358743_regs.h b/drivers/media/i2c/tc358743_regs.h
index 227b46471793..2495878dc358 100644
--- a/drivers/media/i2c/tc358743_regs.h
+++ b/drivers/media/i2c/tc358743_regs.h
@@ -1,22 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* tc358743 - Toshiba HDMI to CSI-2 bridge - register names and bit masks
*
* Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights
* reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
*/
/*
diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c
new file mode 100644
index 000000000000..3021913c28fa
--- /dev/null
+++ b/drivers/media/i2c/tda1997x.c
@@ -0,0 +1,2820 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Gateworks Corporation
+ */
+#include <linux/delay.h>
+#include <linux/hdmi.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/v4l2-dv-timings.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/i2c/tda1997x.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <dt-bindings/media/tda1997x.h>
+
+#include "tda1997x_regs.h"
+
+#define TDA1997X_MBUS_CODES 5
+
+/* debug level */
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-2)");
+
+/* Audio formats */
+static const char * const audtype_names[] = {
+ "PCM", /* PCM Samples */
+ "HBR", /* High Bit Rate Audio */
+ "OBA", /* One-Bit Audio */
+ "DST" /* Direct Stream Transfer */
+};
+
+/* Audio output port formats */
+enum audfmt_types {
+ AUDFMT_TYPE_DISABLED = 0,
+ AUDFMT_TYPE_I2S,
+ AUDFMT_TYPE_SPDIF,
+};
+static const char * const audfmt_names[] = {
+ "Disabled",
+ "I2S",
+ "SPDIF",
+};
+
+/* Video input formats */
+static const char * const hdmi_colorspace_names[] = {
+ "RGB", "YUV422", "YUV444", "YUV420", "", "", "", "",
+};
+static const char * const hdmi_colorimetry_names[] = {
+ "", "ITU601", "ITU709", "Extended",
+};
+static const char * const v4l2_quantization_names[] = {
+ "Default",
+ "Full Range (0-255)",
+ "Limited Range (16-235)",
+};
+
+/* Video output port formats */
+static const char * const vidfmt_names[] = {
+ "RGB444/YUV444", /* RGB/YUV444 16bit data bus, 8bpp */
+ "YUV422 semi-planar", /* YUV422 16bit data base, 8bpp */
+ "YUV422 CCIR656", /* BT656 (YUV 8bpp 2 clock per pixel) */
+ "Invalid",
+};
+
+/*
+ * Colorspace conversion matrices
+ */
+struct color_matrix_coefs {
+ const char *name;
+ /* Input offsets */
+ s16 offint1;
+ s16 offint2;
+ s16 offint3;
+ /* Coeficients */
+ s16 p11coef;
+ s16 p12coef;
+ s16 p13coef;
+ s16 p21coef;
+ s16 p22coef;
+ s16 p23coef;
+ s16 p31coef;
+ s16 p32coef;
+ s16 p33coef;
+ /* Output offsets */
+ s16 offout1;
+ s16 offout2;
+ s16 offout3;
+};
+
+enum {
+ ITU709_RGBFULL,
+ ITU601_RGBFULL,
+ RGBLIMITED_RGBFULL,
+ RGBLIMITED_ITU601,
+ RGBLIMITED_ITU709,
+ RGBFULL_ITU601,
+ RGBFULL_ITU709,
+};
+
+/* NB: 4096 is 1.0 using fixed point numbers */
+static const struct color_matrix_coefs conv_matrix[] = {
+ {
+ "YUV709 -> RGB full",
+ -256, -2048, -2048,
+ 4769, -2183, -873,
+ 4769, 7343, 0,
+ 4769, 0, 8652,
+ 0, 0, 0,
+ },
+ {
+ "YUV601 -> RGB full",
+ -256, -2048, -2048,
+ 4769, -3330, -1602,
+ 4769, 6538, 0,
+ 4769, 0, 8264,
+ 256, 256, 256,
+ },
+ {
+ "RGB limited -> RGB full",
+ -256, -256, -256,
+ 0, 4769, 0,
+ 0, 0, 4769,
+ 4769, 0, 0,
+ 0, 0, 0,
+ },
+ {
+ "RGB limited -> ITU601",
+ -256, -256, -256,
+ 2404, 1225, 467,
+ -1754, 2095, -341,
+ -1388, -707, 2095,
+ 256, 2048, 2048,
+ },
+ {
+ "RGB limited -> ITU709",
+ -256, -256, -256,
+ 2918, 867, 295,
+ -1894, 2087, -190,
+ -1607, -477, 2087,
+ 256, 2048, 2048,
+ },
+ {
+ "RGB full -> ITU601",
+ 0, 0, 0,
+ 2065, 1052, 401,
+ -1506, 1799, -293,
+ -1192, -607, 1799,
+ 256, 2048, 2048,
+ },
+ {
+ "RGB full -> ITU709",
+ 0, 0, 0,
+ 2506, 745, 253,
+ -1627, 1792, -163,
+ -1380, -410, 1792,
+ 256, 2048, 2048,
+ },
+};
+
+static const struct v4l2_dv_timings_cap tda1997x_dv_timings_cap = {
+ .type = V4L2_DV_BT_656_1120,
+ /* keep this initialization for compatibility with GCC < 4.4.6 */
+ .reserved = { 0 },
+
+ V4L2_INIT_BT_TIMINGS(
+ 640, 1920, /* min/max width */
+ 350, 1200, /* min/max height */
+ 13000000, 165000000, /* min/max pixelclock */
+ /* standards */
+ V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
+ V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
+ /* capabilities */
+ V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE |
+ V4L2_DV_BT_CAP_REDUCED_BLANKING |
+ V4L2_DV_BT_CAP_CUSTOM
+ )
+};
+
+/* regulator supplies */
+static const char * const tda1997x_supply_name[] = {
+ "DOVDD", /* Digital I/O supply */
+ "DVDD", /* Digital Core supply */
+ "AVDD", /* Analog supply */
+};
+
+#define TDA1997X_NUM_SUPPLIES ARRAY_SIZE(tda1997x_supply_name)
+
+enum tda1997x_type {
+ TDA19971,
+ TDA19973,
+};
+
+enum tda1997x_hdmi_pads {
+ TDA1997X_PAD_SOURCE,
+ TDA1997X_NUM_PADS,
+};
+
+struct tda1997x_chip_info {
+ enum tda1997x_type type;
+ const char *name;
+};
+
+struct tda1997x_state {
+ const struct tda1997x_chip_info *info;
+ struct tda1997x_platform_data pdata;
+ struct i2c_client *client;
+ struct i2c_client *client_cec;
+ struct v4l2_subdev sd;
+ struct regulator_bulk_data supplies[TDA1997X_NUM_SUPPLIES];
+ struct media_pad pads[TDA1997X_NUM_PADS];
+ struct mutex lock;
+ struct mutex page_lock;
+ char page;
+
+ /* detected info from chip */
+ int chip_revision;
+ char port_30bit;
+ char output_2p5;
+ char tmdsb_clk;
+ char tmdsb_soc;
+
+ /* status info */
+ char hdmi_status;
+ char mptrw_in_progress;
+ char activity_status;
+ char input_detect[2];
+
+ /* video */
+ struct hdmi_avi_infoframe avi_infoframe;
+ struct v4l2_hdmi_colorimetry colorimetry;
+ u32 rgb_quantization_range;
+ struct v4l2_dv_timings timings;
+ int fps;
+ const struct color_matrix_coefs *conv;
+ u32 mbus_codes[TDA1997X_MBUS_CODES]; /* available modes */
+ u32 mbus_code; /* current mode */
+ u8 vid_fmt;
+
+ /* controls */
+ struct v4l2_ctrl_handler hdl;
+ struct v4l2_ctrl *detect_tx_5v_ctrl;
+ struct v4l2_ctrl *rgb_quantization_range_ctrl;
+
+ /* audio */
+ u8 audio_ch_alloc;
+ int audio_samplerate;
+ int audio_channels;
+ int audio_samplesize;
+ int audio_type;
+ struct mutex audio_lock;
+ struct snd_pcm_substream *audio_stream;
+
+ /* EDID */
+ struct {
+ u8 edid[256];
+ u32 present;
+ unsigned int blocks;
+ } edid;
+ struct delayed_work delayed_work_enable_hpd;
+};
+
+static const struct v4l2_event tda1997x_ev_fmt = {
+ .type = V4L2_EVENT_SOURCE_CHANGE,
+ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+};
+
+static const struct tda1997x_chip_info tda1997x_chip_info[] = {
+ [TDA19971] = {
+ .type = TDA19971,
+ .name = "tda19971",
+ },
+ [TDA19973] = {
+ .type = TDA19973,
+ .name = "tda19973",
+ },
+};
+
+static inline struct tda1997x_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct tda1997x_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct tda1997x_state, hdl)->sd;
+}
+
+static int tda1997x_cec_read(struct v4l2_subdev *sd, u8 reg)
+{
+ struct tda1997x_state *state = to_state(sd);
+ int val;
+
+ val = i2c_smbus_read_byte_data(state->client_cec, reg);
+ if (val < 0) {
+ v4l_err(state->client, "read reg error: reg=%2x\n", reg);
+ val = -1;
+ }
+
+ return val;
+}
+
+static int tda1997x_cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+ struct tda1997x_state *state = to_state(sd);
+ int ret = 0;
+
+ ret = i2c_smbus_write_byte_data(state->client_cec, reg, val);
+ if (ret < 0) {
+ v4l_err(state->client, "write reg error:reg=%2x,val=%2x\n",
+ reg, val);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * I2C transfer
+ */
+
+static int tda1997x_setpage(struct v4l2_subdev *sd, u8 page)
+{
+ struct tda1997x_state *state = to_state(sd);
+ int ret;
+
+ if (state->page != page) {
+ ret = i2c_smbus_write_byte_data(state->client,
+ REG_CURPAGE_00H, page);
+ if (ret < 0) {
+ v4l_err(state->client,
+ "write reg error:reg=%2x,val=%2x\n",
+ REG_CURPAGE_00H, page);
+ return ret;
+ }
+ state->page = page;
+ }
+ return 0;
+}
+
+static inline int io_read(struct v4l2_subdev *sd, u16 reg)
+{
+ struct tda1997x_state *state = to_state(sd);
+ int val;
+
+ mutex_lock(&state->page_lock);
+ if (tda1997x_setpage(sd, reg >> 8)) {
+ val = -1;
+ goto out;
+ }
+
+ val = i2c_smbus_read_byte_data(state->client, reg&0xff);
+ if (val < 0) {
+ v4l_err(state->client, "read reg error: reg=%2x\n", reg & 0xff);
+ val = -1;
+ goto out;
+ }
+
+out:
+ mutex_unlock(&state->page_lock);
+ return val;
+}
+
+static inline long io_read16(struct v4l2_subdev *sd, u16 reg)
+{
+ int val;
+ long lval = 0;
+
+ val = io_read(sd, reg);
+ if (val < 0)
+ return val;
+ lval |= (val << 8);
+ val = io_read(sd, reg + 1);
+ if (val < 0)
+ return val;
+ lval |= val;
+
+ return lval;
+}
+
+static inline long io_read24(struct v4l2_subdev *sd, u16 reg)
+{
+ int val;
+ long lval = 0;
+
+ val = io_read(sd, reg);
+ if (val < 0)
+ return val;
+ lval |= (val << 16);
+ val = io_read(sd, reg + 1);
+ if (val < 0)
+ return val;
+ lval |= (val << 8);
+ val = io_read(sd, reg + 2);
+ if (val < 0)
+ return val;
+ lval |= val;
+
+ return lval;
+}
+
+static unsigned int io_readn(struct v4l2_subdev *sd, u16 reg, u8 len, u8 *data)
+{
+ int i;
+ int sz = 0;
+ int val;
+
+ for (i = 0; i < len; i++) {
+ val = io_read(sd, reg + i);
+ if (val < 0)
+ break;
+ data[i] = val;
+ sz++;
+ }
+
+ return sz;
+}
+
+static int io_write(struct v4l2_subdev *sd, u16 reg, u8 val)
+{
+ struct tda1997x_state *state = to_state(sd);
+ s32 ret = 0;
+
+ mutex_lock(&state->page_lock);
+ if (tda1997x_setpage(sd, reg >> 8)) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = i2c_smbus_write_byte_data(state->client, reg & 0xff, val);
+ if (ret < 0) {
+ v4l_err(state->client, "write reg error:reg=%2x,val=%2x\n",
+ reg&0xff, val);
+ ret = -1;
+ goto out;
+ }
+
+out:
+ mutex_unlock(&state->page_lock);
+ return ret;
+}
+
+static int io_write16(struct v4l2_subdev *sd, u16 reg, u16 val)
+{
+ int ret;
+
+ ret = io_write(sd, reg, (val >> 8) & 0xff);
+ if (ret < 0)
+ return ret;
+ ret = io_write(sd, reg + 1, val & 0xff);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int io_write24(struct v4l2_subdev *sd, u16 reg, u32 val)
+{
+ int ret;
+
+ ret = io_write(sd, reg, (val >> 16) & 0xff);
+ if (ret < 0)
+ return ret;
+ ret = io_write(sd, reg + 1, (val >> 8) & 0xff);
+ if (ret < 0)
+ return ret;
+ ret = io_write(sd, reg + 2, val & 0xff);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Hotplug
+ */
+
+enum hpd_mode {
+ HPD_LOW_BP, /* HPD low and pulse of at least 100ms */
+ HPD_LOW_OTHER, /* HPD low and pulse of at least 100ms */
+ HPD_HIGH_BP, /* HIGH */
+ HPD_HIGH_OTHER,
+ HPD_PULSE, /* HPD low pulse */
+};
+
+/* manual HPD (Hot Plug Detect) control */
+static int tda1997x_manual_hpd(struct v4l2_subdev *sd, enum hpd_mode mode)
+{
+ u8 hpd_auto, hpd_pwr, hpd_man;
+
+ hpd_auto = io_read(sd, REG_HPD_AUTO_CTRL);
+ hpd_pwr = io_read(sd, REG_HPD_POWER);
+ hpd_man = io_read(sd, REG_HPD_MAN_CTRL);
+
+ /* mask out unused bits */
+ hpd_man &= (HPD_MAN_CTRL_HPD_PULSE |
+ HPD_MAN_CTRL_5VEN |
+ HPD_MAN_CTRL_HPD_B |
+ HPD_MAN_CTRL_HPD_A);
+
+ switch (mode) {
+ /* HPD low and pulse of at least 100ms */
+ case HPD_LOW_BP:
+ /* hpd_bp=0 */
+ hpd_pwr &= ~HPD_POWER_BP_MASK;
+ /* disable HPD_A and HPD_B */
+ hpd_man &= ~(HPD_MAN_CTRL_HPD_A | HPD_MAN_CTRL_HPD_B);
+ io_write(sd, REG_HPD_POWER, hpd_pwr);
+ io_write(sd, REG_HPD_MAN_CTRL, hpd_man);
+ break;
+ /* HPD high */
+ case HPD_HIGH_BP:
+ /* hpd_bp=1 */
+ hpd_pwr &= ~HPD_POWER_BP_MASK;
+ hpd_pwr |= 1 << HPD_POWER_BP_SHIFT;
+ io_write(sd, REG_HPD_POWER, hpd_pwr);
+ break;
+ /* HPD low and pulse of at least 100ms */
+ case HPD_LOW_OTHER:
+ /* disable HPD_A and HPD_B */
+ hpd_man &= ~(HPD_MAN_CTRL_HPD_A | HPD_MAN_CTRL_HPD_B);
+ /* hp_other=0 */
+ hpd_auto &= ~HPD_AUTO_HP_OTHER;
+ io_write(sd, REG_HPD_AUTO_CTRL, hpd_auto);
+ io_write(sd, REG_HPD_MAN_CTRL, hpd_man);
+ break;
+ /* HPD high */
+ case HPD_HIGH_OTHER:
+ hpd_auto |= HPD_AUTO_HP_OTHER;
+ io_write(sd, REG_HPD_AUTO_CTRL, hpd_auto);
+ break;
+ /* HPD low pulse */
+ case HPD_PULSE:
+ /* disable HPD_A and HPD_B */
+ hpd_man &= ~(HPD_MAN_CTRL_HPD_A | HPD_MAN_CTRL_HPD_B);
+ io_write(sd, REG_HPD_MAN_CTRL, hpd_man);
+ break;
+ }
+
+ return 0;
+}
+
+static void tda1997x_delayed_work_enable_hpd(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct tda1997x_state *state = container_of(dwork,
+ struct tda1997x_state,
+ delayed_work_enable_hpd);
+ struct v4l2_subdev *sd = &state->sd;
+
+ v4l2_dbg(2, debug, sd, "%s:\n", __func__);
+
+ /* Set HPD high */
+ tda1997x_manual_hpd(sd, HPD_HIGH_OTHER);
+ tda1997x_manual_hpd(sd, HPD_HIGH_BP);
+
+ state->edid.present = 1;
+}
+
+static void tda1997x_disable_edid(struct v4l2_subdev *sd)
+{
+ struct tda1997x_state *state = to_state(sd);
+
+ v4l2_dbg(1, debug, sd, "%s\n", __func__);
+ cancel_delayed_work_sync(&state->delayed_work_enable_hpd);
+
+ /* Set HPD low */
+ tda1997x_manual_hpd(sd, HPD_LOW_BP);
+}
+
+static void tda1997x_enable_edid(struct v4l2_subdev *sd)
+{
+ struct tda1997x_state *state = to_state(sd);
+
+ v4l2_dbg(1, debug, sd, "%s\n", __func__);
+
+ /* Enable hotplug after 100ms */
+ schedule_delayed_work(&state->delayed_work_enable_hpd, HZ / 10);
+}
+
+/* -----------------------------------------------------------------------------
+ * Signal Control
+ */
+
+/*
+ * configure vid_fmt based on mbus_code
+ */
+static int
+tda1997x_setup_format(struct tda1997x_state *state, u32 code)
+{
+ v4l_dbg(1, debug, state->client, "%s code=0x%x\n", __func__, code);
+ switch (code) {
+ case MEDIA_BUS_FMT_RGB121212_1X36:
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_YUV12_1X36:
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ state->vid_fmt = OF_FMT_444;
+ break;
+ case MEDIA_BUS_FMT_UYVY12_1X24:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ state->vid_fmt = OF_FMT_422_SMPT;
+ break;
+ case MEDIA_BUS_FMT_UYVY12_2X12:
+ case MEDIA_BUS_FMT_UYVY10_2X10:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ state->vid_fmt = OF_FMT_422_CCIR;
+ break;
+ default:
+ v4l_err(state->client, "incompatible format (0x%x)\n", code);
+ return -EINVAL;
+ }
+ v4l_dbg(1, debug, state->client, "%s code=0x%x fmt=%s\n", __func__,
+ code, vidfmt_names[state->vid_fmt]);
+ state->mbus_code = code;
+
+ return 0;
+}
+
+/*
+ * The color conversion matrix will convert between the colorimetry of the
+ * HDMI input to the desired output format RGB|YUV. RGB output is to be
+ * full-range and YUV is to be limited range.
+ *
+ * RGB full-range uses values from 0 to 255 which is recommended on a monitor
+ * and RGB Limited uses values from 16 to 236 (16=black, 235=white) which is
+ * typically recommended on a TV.
+ */
+static void
+tda1997x_configure_csc(struct v4l2_subdev *sd)
+{
+ struct tda1997x_state *state = to_state(sd);
+ struct hdmi_avi_infoframe *avi = &state->avi_infoframe;
+ struct v4l2_hdmi_colorimetry *c = &state->colorimetry;
+ /* Blanking code values depend on output colorspace (RGB or YUV) */
+ struct blanking_codes {
+ s16 code_gy;
+ s16 code_bu;
+ s16 code_rv;
+ };
+ static const struct blanking_codes rgb_blanking = { 64, 64, 64 };
+ static const struct blanking_codes yuv_blanking = { 64, 512, 512 };
+ const struct blanking_codes *blanking_codes = NULL;
+ u8 reg;
+
+ v4l_dbg(1, debug, state->client, "input:%s quant:%s output:%s\n",
+ hdmi_colorspace_names[avi->colorspace],
+ v4l2_quantization_names[c->quantization],
+ vidfmt_names[state->vid_fmt]);
+ state->conv = NULL;
+ switch (state->vid_fmt) {
+ /* RGB output */
+ case OF_FMT_444:
+ blanking_codes = &rgb_blanking;
+ if (c->colorspace == V4L2_COLORSPACE_SRGB) {
+ if (c->quantization == V4L2_QUANTIZATION_LIM_RANGE)
+ state->conv = &conv_matrix[RGBLIMITED_RGBFULL];
+ } else {
+ if (c->colorspace == V4L2_COLORSPACE_REC709)
+ state->conv = &conv_matrix[ITU709_RGBFULL];
+ else if (c->colorspace == V4L2_COLORSPACE_SMPTE170M)
+ state->conv = &conv_matrix[ITU601_RGBFULL];
+ }
+ break;
+
+ /* YUV output */
+ case OF_FMT_422_SMPT: /* semi-planar */
+ case OF_FMT_422_CCIR: /* CCIR656 */
+ blanking_codes = &yuv_blanking;
+ if ((c->colorspace == V4L2_COLORSPACE_SRGB) &&
+ (c->quantization == V4L2_QUANTIZATION_FULL_RANGE)) {
+ if (state->timings.bt.height <= 576)
+ state->conv = &conv_matrix[RGBFULL_ITU601];
+ else
+ state->conv = &conv_matrix[RGBFULL_ITU709];
+ } else if ((c->colorspace == V4L2_COLORSPACE_SRGB) &&
+ (c->quantization == V4L2_QUANTIZATION_LIM_RANGE)) {
+ if (state->timings.bt.height <= 576)
+ state->conv = &conv_matrix[RGBLIMITED_ITU601];
+ else
+ state->conv = &conv_matrix[RGBLIMITED_ITU709];
+ }
+ break;
+ }
+
+ if (state->conv) {
+ v4l_dbg(1, debug, state->client, "%s\n",
+ state->conv->name);
+ /* enable matrix conversion */
+ reg = io_read(sd, REG_VDP_CTRL);
+ reg &= ~VDP_CTRL_MATRIX_BP;
+ io_write(sd, REG_VDP_CTRL, reg);
+ /* offset inputs */
+ io_write16(sd, REG_VDP_MATRIX + 0, state->conv->offint1);
+ io_write16(sd, REG_VDP_MATRIX + 2, state->conv->offint2);
+ io_write16(sd, REG_VDP_MATRIX + 4, state->conv->offint3);
+ /* coefficients */
+ io_write16(sd, REG_VDP_MATRIX + 6, state->conv->p11coef);
+ io_write16(sd, REG_VDP_MATRIX + 8, state->conv->p12coef);
+ io_write16(sd, REG_VDP_MATRIX + 10, state->conv->p13coef);
+ io_write16(sd, REG_VDP_MATRIX + 12, state->conv->p21coef);
+ io_write16(sd, REG_VDP_MATRIX + 14, state->conv->p22coef);
+ io_write16(sd, REG_VDP_MATRIX + 16, state->conv->p23coef);
+ io_write16(sd, REG_VDP_MATRIX + 18, state->conv->p31coef);
+ io_write16(sd, REG_VDP_MATRIX + 20, state->conv->p32coef);
+ io_write16(sd, REG_VDP_MATRIX + 22, state->conv->p33coef);
+ /* offset outputs */
+ io_write16(sd, REG_VDP_MATRIX + 24, state->conv->offout1);
+ io_write16(sd, REG_VDP_MATRIX + 26, state->conv->offout2);
+ io_write16(sd, REG_VDP_MATRIX + 28, state->conv->offout3);
+ } else {
+ /* disable matrix conversion */
+ reg = io_read(sd, REG_VDP_CTRL);
+ reg |= VDP_CTRL_MATRIX_BP;
+ io_write(sd, REG_VDP_CTRL, reg);
+ }
+
+ /* SetBlankingCodes */
+ if (blanking_codes) {
+ io_write16(sd, REG_BLK_GY, blanking_codes->code_gy);
+ io_write16(sd, REG_BLK_BU, blanking_codes->code_bu);
+ io_write16(sd, REG_BLK_RV, blanking_codes->code_rv);
+ }
+}
+
+/* Configure frame detection window and VHREF timing generator */
+static void
+tda1997x_configure_vhref(struct v4l2_subdev *sd)
+{
+ struct tda1997x_state *state = to_state(sd);
+ const struct v4l2_bt_timings *bt = &state->timings.bt;
+ int width, lines;
+ u16 href_start, href_end;
+ u16 vref_f1_start, vref_f2_start;
+ u8 vref_f1_width, vref_f2_width;
+ u8 field_polarity;
+ u16 fieldref_f1_start, fieldref_f2_start;
+ u8 reg;
+
+ href_start = bt->hbackporch + bt->hsync + 1;
+ href_end = href_start + bt->width;
+ vref_f1_start = bt->height + bt->vbackporch + bt->vsync +
+ bt->il_vbackporch + bt->il_vsync +
+ bt->il_vfrontporch;
+ vref_f1_width = bt->vbackporch + bt->vsync + bt->vfrontporch;
+ vref_f2_start = 0;
+ vref_f2_width = 0;
+ fieldref_f1_start = 0;
+ fieldref_f2_start = 0;
+ if (bt->interlaced) {
+ vref_f2_start = (bt->height / 2) +
+ (bt->il_vbackporch + bt->il_vsync - 1);
+ vref_f2_width = bt->il_vbackporch + bt->il_vsync +
+ bt->il_vfrontporch;
+ fieldref_f2_start = vref_f2_start + bt->il_vfrontporch +
+ fieldref_f1_start;
+ }
+ field_polarity = 0;
+
+ width = V4L2_DV_BT_FRAME_WIDTH(bt);
+ lines = V4L2_DV_BT_FRAME_HEIGHT(bt);
+
+ /*
+ * Configure Frame Detection Window:
+ * horiz area where the VHREF module consider a VSYNC a new frame
+ */
+ io_write16(sd, REG_FDW_S, 0x2ef); /* start position */
+ io_write16(sd, REG_FDW_E, 0x141); /* end position */
+
+ /* Set Pixel And Line Counters */
+ if (state->chip_revision == 0)
+ io_write16(sd, REG_PXCNT_PR, 4);
+ else
+ io_write16(sd, REG_PXCNT_PR, 1);
+ io_write16(sd, REG_PXCNT_NPIX, width & MASK_VHREF);
+ io_write16(sd, REG_LCNT_PR, 1);
+ io_write16(sd, REG_LCNT_NLIN, lines & MASK_VHREF);
+
+ /*
+ * Configure the VHRef timing generator responsible for rebuilding all
+ * horiz and vert synch and ref signals from its input allowing auto
+ * detection algorithms and forcing predefined modes (480i & 576i)
+ */
+ reg = VHREF_STD_DET_OFF << VHREF_STD_DET_SHIFT;
+ io_write(sd, REG_VHREF_CTRL, reg);
+
+ /*
+ * Configure the VHRef timing values. In case the VHREF generator has
+ * been configured in manual mode, this will allow to manually set all
+ * horiz and vert ref values (non-active pixel areas) of the generator
+ * and allows setting the frame reference params.
+ */
+ /* horizontal reference start/end */
+ io_write16(sd, REG_HREF_S, href_start & MASK_VHREF);
+ io_write16(sd, REG_HREF_E, href_end & MASK_VHREF);
+ /* vertical reference f1 start/end */
+ io_write16(sd, REG_VREF_F1_S, vref_f1_start & MASK_VHREF);
+ io_write(sd, REG_VREF_F1_WIDTH, vref_f1_width);
+ /* vertical reference f2 start/end */
+ io_write16(sd, REG_VREF_F2_S, vref_f2_start & MASK_VHREF);
+ io_write(sd, REG_VREF_F2_WIDTH, vref_f2_width);
+
+ /* F1/F2 FREF, field polarity */
+ reg = fieldref_f1_start & MASK_VHREF;
+ reg |= field_polarity << 8;
+ io_write16(sd, REG_FREF_F1_S, reg);
+ reg = fieldref_f2_start & MASK_VHREF;
+ io_write16(sd, REG_FREF_F2_S, reg);
+}
+
+/* Configure Video Output port signals */
+static int
+tda1997x_configure_vidout(struct tda1997x_state *state)
+{
+ struct v4l2_subdev *sd = &state->sd;
+ struct tda1997x_platform_data *pdata = &state->pdata;
+ u8 prefilter;
+ u8 reg;
+
+ /* Configure pixel clock generator: delay, polarity, rate */
+ reg = (state->vid_fmt == OF_FMT_422_CCIR) ?
+ PCLK_SEL_X2 : PCLK_SEL_X1;
+ reg |= pdata->vidout_delay_pclk << PCLK_DELAY_SHIFT;
+ reg |= pdata->vidout_inv_pclk << PCLK_INV_SHIFT;
+ io_write(sd, REG_PCLK, reg);
+
+ /* Configure pre-filter */
+ prefilter = 0; /* filters off */
+ /* YUV422 mode requires conversion */
+ if ((state->vid_fmt == OF_FMT_422_SMPT) ||
+ (state->vid_fmt == OF_FMT_422_CCIR)) {
+ /* 2/7 taps for Rv and Bu */
+ prefilter = FILTERS_CTRL_2_7TAP << FILTERS_CTRL_BU_SHIFT |
+ FILTERS_CTRL_2_7TAP << FILTERS_CTRL_RV_SHIFT;
+ }
+ io_write(sd, REG_FILTERS_CTRL, prefilter);
+
+ /* Configure video port */
+ reg = state->vid_fmt & OF_FMT_MASK;
+ if (state->vid_fmt == OF_FMT_422_CCIR)
+ reg |= (OF_BLK | OF_TRC);
+ reg |= OF_VP_ENABLE;
+ io_write(sd, REG_OF, reg);
+
+ /* Configure formatter and conversions */
+ reg = io_read(sd, REG_VDP_CTRL);
+ /* pre-filter is needed unless (REG_FILTERS_CTRL == 0) */
+ if (!prefilter)
+ reg |= VDP_CTRL_PREFILTER_BP;
+ else
+ reg &= ~VDP_CTRL_PREFILTER_BP;
+ /* formatter is needed for YUV422 and for trc/blc codes */
+ if (state->vid_fmt == OF_FMT_444)
+ reg |= VDP_CTRL_FORMATTER_BP;
+ /* formatter and compdel needed for timing/blanking codes */
+ else
+ reg &= ~(VDP_CTRL_FORMATTER_BP | VDP_CTRL_COMPDEL_BP);
+ /* activate compdel for small sync delays */
+ if ((pdata->vidout_delay_vs < 4) || (pdata->vidout_delay_hs < 4))
+ reg &= ~VDP_CTRL_COMPDEL_BP;
+ io_write(sd, REG_VDP_CTRL, reg);
+
+ /* Configure DE output signal: delay, polarity, and source */
+ reg = pdata->vidout_delay_de << DE_FREF_DELAY_SHIFT |
+ pdata->vidout_inv_de << DE_FREF_INV_SHIFT |
+ pdata->vidout_sel_de << DE_FREF_SEL_SHIFT;
+ io_write(sd, REG_DE_FREF, reg);
+
+ /* Configure HS/HREF output signal: delay, polarity, and source */
+ if (state->vid_fmt != OF_FMT_422_CCIR) {
+ reg = pdata->vidout_delay_hs << HS_HREF_DELAY_SHIFT |
+ pdata->vidout_inv_hs << HS_HREF_INV_SHIFT |
+ pdata->vidout_sel_hs << HS_HREF_SEL_SHIFT;
+ } else
+ reg = HS_HREF_SEL_NONE << HS_HREF_SEL_SHIFT;
+ io_write(sd, REG_HS_HREF, reg);
+
+ /* Configure VS/VREF output signal: delay, polarity, and source */
+ if (state->vid_fmt != OF_FMT_422_CCIR) {
+ reg = pdata->vidout_delay_vs << VS_VREF_DELAY_SHIFT |
+ pdata->vidout_inv_vs << VS_VREF_INV_SHIFT |
+ pdata->vidout_sel_vs << VS_VREF_SEL_SHIFT;
+ } else
+ reg = VS_VREF_SEL_NONE << VS_VREF_SEL_SHIFT;
+ io_write(sd, REG_VS_VREF, reg);
+
+ return 0;
+}
+
+/* Configure Audio output port signals */
+static int
+tda1997x_configure_audout(struct v4l2_subdev *sd, u8 channel_assignment)
+{
+ struct tda1997x_state *state = to_state(sd);
+ struct tda1997x_platform_data *pdata = &state->pdata;
+ bool sp_used_by_fifo = 1;
+ u8 reg;
+
+ if (!pdata->audout_format)
+ return 0;
+
+ /* channel assignment (CEA-861-D Table 20) */
+ io_write(sd, REG_AUDIO_PATH, channel_assignment);
+
+ /* Audio output configuration */
+ reg = 0;
+ switch (pdata->audout_format) {
+ case AUDFMT_TYPE_I2S:
+ reg |= AUDCFG_BUS_I2S << AUDCFG_BUS_SHIFT;
+ break;
+ case AUDFMT_TYPE_SPDIF:
+ reg |= AUDCFG_BUS_SPDIF << AUDCFG_BUS_SHIFT;
+ break;
+ }
+ switch (state->audio_type) {
+ case AUDCFG_TYPE_PCM:
+ reg |= AUDCFG_TYPE_PCM << AUDCFG_TYPE_SHIFT;
+ break;
+ case AUDCFG_TYPE_OBA:
+ reg |= AUDCFG_TYPE_OBA << AUDCFG_TYPE_SHIFT;
+ break;
+ case AUDCFG_TYPE_DST:
+ reg |= AUDCFG_TYPE_DST << AUDCFG_TYPE_SHIFT;
+ sp_used_by_fifo = 0;
+ break;
+ case AUDCFG_TYPE_HBR:
+ reg |= AUDCFG_TYPE_HBR << AUDCFG_TYPE_SHIFT;
+ if (pdata->audout_layout == 1) {
+ /* demuxed via AP0:AP3 */
+ reg |= AUDCFG_HBR_DEMUX << AUDCFG_HBR_SHIFT;
+ if (pdata->audout_format == AUDFMT_TYPE_SPDIF)
+ sp_used_by_fifo = 0;
+ } else {
+ /* straight via AP0 */
+ reg |= AUDCFG_HBR_STRAIGHT << AUDCFG_HBR_SHIFT;
+ }
+ break;
+ }
+ if (pdata->audout_width == 32)
+ reg |= AUDCFG_I2SW_32 << AUDCFG_I2SW_SHIFT;
+ else
+ reg |= AUDCFG_I2SW_16 << AUDCFG_I2SW_SHIFT;
+
+ /* automatic hardware mute */
+ if (pdata->audio_auto_mute)
+ reg |= AUDCFG_AUTO_MUTE_EN;
+ /* clock polarity */
+ if (pdata->audout_invert_clk)
+ reg |= AUDCFG_CLK_INVERT;
+ io_write(sd, REG_AUDCFG, reg);
+
+ /* audio layout */
+ reg = (pdata->audout_layout) ? AUDIO_LAYOUT_LAYOUT1 : 0;
+ if (!pdata->audout_layoutauto)
+ reg |= AUDIO_LAYOUT_MANUAL;
+ if (sp_used_by_fifo)
+ reg |= AUDIO_LAYOUT_SP_FLAG;
+ io_write(sd, REG_AUDIO_LAYOUT, reg);
+
+ /* FIFO Latency value */
+ io_write(sd, REG_FIFO_LATENCY_VAL, 0x80);
+
+ /* Audio output port config */
+ if (sp_used_by_fifo) {
+ reg = AUDIO_OUT_ENABLE_AP0;
+ if (channel_assignment >= 0x01)
+ reg |= AUDIO_OUT_ENABLE_AP1;
+ if (channel_assignment >= 0x04)
+ reg |= AUDIO_OUT_ENABLE_AP2;
+ if (channel_assignment >= 0x0c)
+ reg |= AUDIO_OUT_ENABLE_AP3;
+ /* specific cases where AP1 is not used */
+ if ((channel_assignment == 0x04)
+ || (channel_assignment == 0x08)
+ || (channel_assignment == 0x0c)
+ || (channel_assignment == 0x10)
+ || (channel_assignment == 0x14)
+ || (channel_assignment == 0x18)
+ || (channel_assignment == 0x1c))
+ reg &= ~AUDIO_OUT_ENABLE_AP1;
+ /* specific cases where AP2 is not used */
+ if ((channel_assignment >= 0x14)
+ && (channel_assignment <= 0x17))
+ reg &= ~AUDIO_OUT_ENABLE_AP2;
+ } else {
+ reg = AUDIO_OUT_ENABLE_AP3 |
+ AUDIO_OUT_ENABLE_AP2 |
+ AUDIO_OUT_ENABLE_AP1 |
+ AUDIO_OUT_ENABLE_AP0;
+ }
+ if (pdata->audout_format == AUDFMT_TYPE_I2S)
+ reg |= (AUDIO_OUT_ENABLE_ACLK | AUDIO_OUT_ENABLE_WS);
+ io_write(sd, REG_AUDIO_OUT_ENABLE, reg);
+
+ /* reset test mode to normal audio freq auto selection */
+ io_write(sd, REG_TEST_MODE, 0x00);
+
+ return 0;
+}
+
+/* Soft Reset of specific hdmi info */
+static int
+tda1997x_hdmi_info_reset(struct v4l2_subdev *sd, u8 info_rst, bool reset_sus)
+{
+ u8 reg;
+
+ /* reset infoframe engine packets */
+ reg = io_read(sd, REG_HDMI_INFO_RST);
+ io_write(sd, REG_HDMI_INFO_RST, info_rst);
+
+ /* if infoframe engine has been reset clear INT_FLG_MODE */
+ if (reg & RESET_IF) {
+ reg = io_read(sd, REG_INT_FLG_CLR_MODE);
+ io_write(sd, REG_INT_FLG_CLR_MODE, reg);
+ }
+
+ /* Disable REFTIM to restart start-up-sequencer (SUS) */
+ reg = io_read(sd, REG_RATE_CTRL);
+ reg &= ~RATE_REFTIM_ENABLE;
+ if (!reset_sus)
+ reg |= RATE_REFTIM_ENABLE;
+ reg = io_write(sd, REG_RATE_CTRL, reg);
+
+ return 0;
+}
+
+static void
+tda1997x_power_mode(struct tda1997x_state *state, bool enable)
+{
+ struct v4l2_subdev *sd = &state->sd;
+ u8 reg;
+
+ if (enable) {
+ /* Automatic control of TMDS */
+ io_write(sd, REG_PON_OVR_EN, PON_DIS);
+ /* Enable current bias unit */
+ io_write(sd, REG_CFG1, PON_EN);
+ /* Enable deep color PLL */
+ io_write(sd, REG_DEEP_PLL7_BYP, PON_DIS);
+ /* Output buffers active */
+ reg = io_read(sd, REG_OF);
+ reg &= ~OF_VP_ENABLE;
+ io_write(sd, REG_OF, reg);
+ } else {
+ /* Power down EDID mode sequence */
+ /* Output buffers in HiZ */
+ reg = io_read(sd, REG_OF);
+ reg |= OF_VP_ENABLE;
+ io_write(sd, REG_OF, reg);
+ /* Disable deep color PLL */
+ io_write(sd, REG_DEEP_PLL7_BYP, PON_EN);
+ /* Disable current bias unit */
+ io_write(sd, REG_CFG1, PON_DIS);
+ /* Manual control of TMDS */
+ io_write(sd, REG_PON_OVR_EN, PON_EN);
+ }
+}
+
+static bool
+tda1997x_detect_tx_5v(struct v4l2_subdev *sd)
+{
+ u8 reg = io_read(sd, REG_DETECT_5V);
+
+ return ((reg & DETECT_5V_SEL) ? 1 : 0);
+}
+
+static bool
+tda1997x_detect_tx_hpd(struct v4l2_subdev *sd)
+{
+ u8 reg = io_read(sd, REG_DETECT_5V);
+
+ return ((reg & DETECT_HPD) ? 1 : 0);
+}
+
+static int
+tda1997x_detect_std(struct tda1997x_state *state,
+ struct v4l2_dv_timings *timings)
+{
+ struct v4l2_subdev *sd = &state->sd;
+ u32 vper;
+ u16 hper;
+ u16 hsper;
+ int i;
+
+ /*
+ * Read the FMT registers
+ * REG_V_PER: Period of a frame (or two fields) in MCLK(27MHz) cycles
+ * REG_H_PER: Period of a line in MCLK(27MHz) cycles
+ * REG_HS_WIDTH: Period of horiz sync pulse in MCLK(27MHz) cycles
+ */
+ vper = io_read24(sd, REG_V_PER) & MASK_VPER;
+ hper = io_read16(sd, REG_H_PER) & MASK_HPER;
+ hsper = io_read16(sd, REG_HS_WIDTH) & MASK_HSWIDTH;
+ v4l2_dbg(1, debug, sd, "Signal Timings: %u/%u/%u\n", vper, hper, hsper);
+ if (!vper || !hper || !hsper)
+ return -ENOLINK;
+
+ for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) {
+ const struct v4l2_bt_timings *bt;
+ u32 lines, width, _hper, _hsper;
+ u32 vmin, vmax, hmin, hmax, hsmin, hsmax;
+ bool vmatch, hmatch, hsmatch;
+
+ bt = &v4l2_dv_timings_presets[i].bt;
+ width = V4L2_DV_BT_FRAME_WIDTH(bt);
+ lines = V4L2_DV_BT_FRAME_HEIGHT(bt);
+ _hper = (u32)bt->pixelclock / width;
+ if (bt->interlaced)
+ lines /= 2;
+ /* vper +/- 0.7% */
+ vmin = ((27000000 / 1000) * 993) / _hper * lines;
+ vmax = ((27000000 / 1000) * 1007) / _hper * lines;
+ /* hper +/- 1.0% */
+ hmin = ((27000000 / 100) * 99) / _hper;
+ hmax = ((27000000 / 100) * 101) / _hper;
+ /* hsper +/- 2 (take care to avoid 32bit overflow) */
+ _hsper = 27000 * bt->hsync / ((u32)bt->pixelclock/1000);
+ hsmin = _hsper - 2;
+ hsmax = _hsper + 2;
+
+ /* vmatch matches the framerate */
+ vmatch = ((vper <= vmax) && (vper >= vmin)) ? 1 : 0;
+ /* hmatch matches the width */
+ hmatch = ((hper <= hmax) && (hper >= hmin)) ? 1 : 0;
+ /* hsmatch matches the hswidth */
+ hsmatch = ((hsper <= hsmax) && (hsper >= hsmin)) ? 1 : 0;
+ if (hmatch && vmatch && hsmatch) {
+ v4l2_print_dv_timings(sd->name, "Detected format: ",
+ &v4l2_dv_timings_presets[i],
+ false);
+ if (timings)
+ *timings = v4l2_dv_timings_presets[i];
+ return 0;
+ }
+ }
+
+ v4l_err(state->client, "no resolution match for timings: %d/%d/%d\n",
+ vper, hper, hsper);
+ return -ERANGE;
+}
+
+/* some sort of errata workaround for chip revision 0 (N1) */
+static void tda1997x_reset_n1(struct tda1997x_state *state)
+{
+ struct v4l2_subdev *sd = &state->sd;
+ u8 reg;
+
+ /* clear HDMI mode flag in BCAPS */
+ io_write(sd, REG_CLK_CFG, CLK_CFG_SEL_ACLK_EN | CLK_CFG_SEL_ACLK);
+ io_write(sd, REG_PON_OVR_EN, PON_EN);
+ io_write(sd, REG_PON_CBIAS, PON_EN);
+ io_write(sd, REG_PON_PLL, PON_EN);
+
+ reg = io_read(sd, REG_MODE_REC_CFG1);
+ reg &= ~0x06;
+ reg |= 0x02;
+ io_write(sd, REG_MODE_REC_CFG1, reg);
+ io_write(sd, REG_CLK_CFG, CLK_CFG_DIS);
+ io_write(sd, REG_PON_OVR_EN, PON_DIS);
+ reg = io_read(sd, REG_MODE_REC_CFG1);
+ reg &= ~0x06;
+ io_write(sd, REG_MODE_REC_CFG1, reg);
+}
+
+/*
+ * Activity detection must only be notified when stable_clk_x AND active_x
+ * bits are set to 1. If only stable_clk_x bit is set to 1 but not
+ * active_x, it means that the TMDS clock is not in the defined range
+ * and activity detection must not be notified.
+ */
+static u8
+tda1997x_read_activity_status_regs(struct v4l2_subdev *sd)
+{
+ u8 reg, status = 0;
+
+ /* Read CLK_A_STATUS register */
+ reg = io_read(sd, REG_CLK_A_STATUS);
+ /* ignore if not active */
+ if ((reg & MASK_CLK_STABLE) && !(reg & MASK_CLK_ACTIVE))
+ reg &= ~MASK_CLK_STABLE;
+ status |= ((reg & MASK_CLK_STABLE) >> 2);
+
+ /* Read CLK_B_STATUS register */
+ reg = io_read(sd, REG_CLK_B_STATUS);
+ /* ignore if not active */
+ if ((reg & MASK_CLK_STABLE) && !(reg & MASK_CLK_ACTIVE))
+ reg &= ~MASK_CLK_STABLE;
+ status |= ((reg & MASK_CLK_STABLE) >> 1);
+
+ /* Read the SUS_STATUS register */
+ reg = io_read(sd, REG_SUS_STATUS);
+
+ /* If state = 5 => TMDS is locked */
+ if ((reg & MASK_SUS_STATUS) == LAST_STATE_REACHED)
+ status |= MASK_SUS_STATE;
+ else
+ status &= ~MASK_SUS_STATE;
+
+ return status;
+}
+
+static void
+set_rgb_quantization_range(struct tda1997x_state *state)
+{
+ struct v4l2_hdmi_colorimetry *c = &state->colorimetry;
+
+ state->colorimetry = v4l2_hdmi_rx_colorimetry(&state->avi_infoframe,
+ NULL,
+ state->timings.bt.height);
+ /* If ycbcr_enc is V4L2_YCBCR_ENC_DEFAULT, we receive RGB */
+ if (c->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
+ switch (state->rgb_quantization_range) {
+ case V4L2_DV_RGB_RANGE_LIMITED:
+ c->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ break;
+ case V4L2_DV_RGB_RANGE_FULL:
+ c->quantization = V4L2_QUANTIZATION_LIM_RANGE;
+ break;
+ }
+ }
+ v4l_dbg(1, debug, state->client,
+ "colorspace=%d/%d colorimetry=%d range=%s content=%d\n",
+ state->avi_infoframe.colorspace, c->colorspace,
+ state->avi_infoframe.colorimetry,
+ v4l2_quantization_names[c->quantization],
+ state->avi_infoframe.content_type);
+}
+
+/* parse an infoframe and do some sanity checks on it */
+static unsigned int
+tda1997x_parse_infoframe(struct tda1997x_state *state, u16 addr)
+{
+ struct v4l2_subdev *sd = &state->sd;
+ union hdmi_infoframe frame;
+ u8 buffer[40];
+ u8 reg;
+ int len, err;
+
+ /* read data */
+ len = io_readn(sd, addr, sizeof(buffer), buffer);
+ err = hdmi_infoframe_unpack(&frame, buffer);
+ if (err) {
+ v4l_err(state->client,
+ "failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
+ len, addr, buffer[0]);
+ return err;
+ }
+ hdmi_infoframe_log(KERN_INFO, &state->client->dev, &frame);
+ switch (frame.any.type) {
+ /* Audio InfoFrame: see HDMI spec 8.2.2 */
+ case HDMI_INFOFRAME_TYPE_AUDIO:
+ /* sample rate */
+ switch (frame.audio.sample_frequency) {
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_32000:
+ state->audio_samplerate = 32000;
+ break;
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_44100:
+ state->audio_samplerate = 44100;
+ break;
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_48000:
+ state->audio_samplerate = 48000;
+ break;
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_88200:
+ state->audio_samplerate = 88200;
+ break;
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_96000:
+ state->audio_samplerate = 96000;
+ break;
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_176400:
+ state->audio_samplerate = 176400;
+ break;
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_192000:
+ state->audio_samplerate = 192000;
+ break;
+ default:
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM:
+ break;
+ }
+
+ /* sample size */
+ switch (frame.audio.sample_size) {
+ case HDMI_AUDIO_SAMPLE_SIZE_16:
+ state->audio_samplesize = 16;
+ break;
+ case HDMI_AUDIO_SAMPLE_SIZE_20:
+ state->audio_samplesize = 20;
+ break;
+ case HDMI_AUDIO_SAMPLE_SIZE_24:
+ state->audio_samplesize = 24;
+ break;
+ case HDMI_AUDIO_SAMPLE_SIZE_STREAM:
+ default:
+ break;
+ }
+
+ /* Channel Count */
+ state->audio_channels = frame.audio.channels;
+ if (frame.audio.channel_allocation &&
+ frame.audio.channel_allocation != state->audio_ch_alloc) {
+ /* use the channel assignment from the infoframe */
+ state->audio_ch_alloc = frame.audio.channel_allocation;
+ tda1997x_configure_audout(sd, state->audio_ch_alloc);
+ /* reset the audio FIFO */
+ tda1997x_hdmi_info_reset(sd, RESET_AUDIO, false);
+ }
+ break;
+
+ /* Auxiliary Video information (AVI) InfoFrame: see HDMI spec 8.2.1 */
+ case HDMI_INFOFRAME_TYPE_AVI:
+ state->avi_infoframe = frame.avi;
+ set_rgb_quantization_range(state);
+
+ /* configure upsampler: 0=bypass 1=repeatchroma 2=interpolate */
+ reg = io_read(sd, REG_PIX_REPEAT);
+ reg &= ~PIX_REPEAT_MASK_UP_SEL;
+ if (frame.avi.colorspace == HDMI_COLORSPACE_YUV422)
+ reg |= (PIX_REPEAT_CHROMA << PIX_REPEAT_SHIFT);
+ io_write(sd, REG_PIX_REPEAT, reg);
+
+ /* ConfigurePixelRepeater: repeat n-times each pixel */
+ reg = io_read(sd, REG_PIX_REPEAT);
+ reg &= ~PIX_REPEAT_MASK_REP;
+ reg |= frame.avi.pixel_repeat;
+ io_write(sd, REG_PIX_REPEAT, reg);
+
+ /* configure the receiver with the new colorspace */
+ tda1997x_configure_csc(sd);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static void tda1997x_irq_sus(struct tda1997x_state *state, u8 *flags)
+{
+ struct v4l2_subdev *sd = &state->sd;
+ u8 reg, source;
+
+ source = io_read(sd, REG_INT_FLG_CLR_SUS);
+ io_write(sd, REG_INT_FLG_CLR_SUS, source);
+
+ if (source & MASK_MPT) {
+ /* reset MTP in use flag if set */
+ if (state->mptrw_in_progress)
+ state->mptrw_in_progress = 0;
+ }
+
+ if (source & MASK_SUS_END) {
+ /* reset audio FIFO */
+ reg = io_read(sd, REG_HDMI_INFO_RST);
+ reg |= MASK_SR_FIFO_FIFO_CTRL;
+ io_write(sd, REG_HDMI_INFO_RST, reg);
+ reg &= ~MASK_SR_FIFO_FIFO_CTRL;
+ io_write(sd, REG_HDMI_INFO_RST, reg);
+
+ /* reset HDMI flags */
+ state->hdmi_status = 0;
+ }
+
+ /* filter FMT interrupt based on SUS state */
+ reg = io_read(sd, REG_SUS_STATUS);
+ if (((reg & MASK_SUS_STATUS) != LAST_STATE_REACHED)
+ || (source & MASK_MPT)) {
+ source &= ~MASK_FMT;
+ }
+
+ if (source & (MASK_FMT | MASK_SUS_END)) {
+ reg = io_read(sd, REG_SUS_STATUS);
+ if ((reg & MASK_SUS_STATUS) != LAST_STATE_REACHED) {
+ v4l_err(state->client, "BAD SUS STATUS\n");
+ return;
+ }
+ if (debug)
+ tda1997x_detect_std(state, NULL);
+ /* notify user of change in resolution */
+ v4l2_subdev_notify_event(&state->sd, &tda1997x_ev_fmt);
+ }
+}
+
+static void tda1997x_irq_ddc(struct tda1997x_state *state, u8 *flags)
+{
+ struct v4l2_subdev *sd = &state->sd;
+ u8 source;
+
+ source = io_read(sd, REG_INT_FLG_CLR_DDC);
+ io_write(sd, REG_INT_FLG_CLR_DDC, source);
+ if (source & MASK_EDID_MTP) {
+ /* reset MTP in use flag if set */
+ if (state->mptrw_in_progress)
+ state->mptrw_in_progress = 0;
+ }
+
+ /* Detection of +5V */
+ if (source & MASK_DET_5V) {
+ v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl,
+ tda1997x_detect_tx_5v(sd));
+ }
+}
+
+static void tda1997x_irq_rate(struct tda1997x_state *state, u8 *flags)
+{
+ struct v4l2_subdev *sd = &state->sd;
+ u8 reg, source;
+
+ u8 irq_status;
+
+ source = io_read(sd, REG_INT_FLG_CLR_RATE);
+ io_write(sd, REG_INT_FLG_CLR_RATE, source);
+
+ /* read status regs */
+ irq_status = tda1997x_read_activity_status_regs(sd);
+
+ /*
+ * read clock status reg until INT_FLG_CLR_RATE is still 0
+ * after the read to make sure its the last one
+ */
+ reg = source;
+ while (reg != 0) {
+ irq_status = tda1997x_read_activity_status_regs(sd);
+ reg = io_read(sd, REG_INT_FLG_CLR_RATE);
+ io_write(sd, REG_INT_FLG_CLR_RATE, reg);
+ source |= reg;
+ }
+
+ /* we only pay attention to stability change events */
+ if (source & (MASK_RATE_A_ST | MASK_RATE_B_ST)) {
+ int input = (source & MASK_RATE_A_ST)?0:1;
+ u8 mask = 1<<input;
+
+ /* state change */
+ if ((irq_status & mask) != (state->activity_status & mask)) {
+ /* activity lost */
+ if ((irq_status & mask) == 0) {
+ v4l_info(state->client,
+ "HDMI-%c: Digital Activity Lost\n",
+ input+'A');
+
+ /* bypass up/down sampler and pixel repeater */
+ reg = io_read(sd, REG_PIX_REPEAT);
+ reg &= ~PIX_REPEAT_MASK_UP_SEL;
+ reg &= ~PIX_REPEAT_MASK_REP;
+ io_write(sd, REG_PIX_REPEAT, reg);
+
+ if (state->chip_revision == 0)
+ tda1997x_reset_n1(state);
+
+ state->input_detect[input] = 0;
+ v4l2_subdev_notify_event(sd, &tda1997x_ev_fmt);
+ }
+
+ /* activity detected */
+ else {
+ v4l_info(state->client,
+ "HDMI-%c: Digital Activity Detected\n",
+ input+'A');
+ state->input_detect[input] = 1;
+ }
+
+ /* hold onto current state */
+ state->activity_status = (irq_status & mask);
+ }
+ }
+}
+
+static void tda1997x_irq_info(struct tda1997x_state *state, u8 *flags)
+{
+ struct v4l2_subdev *sd = &state->sd;
+ u8 source;
+
+ source = io_read(sd, REG_INT_FLG_CLR_INFO);
+ io_write(sd, REG_INT_FLG_CLR_INFO, source);
+
+ /* Audio infoframe */
+ if (source & MASK_AUD_IF) {
+ tda1997x_parse_infoframe(state, AUD_IF);
+ source &= ~MASK_AUD_IF;
+ }
+
+ /* Source Product Descriptor infoframe change */
+ if (source & MASK_SPD_IF) {
+ tda1997x_parse_infoframe(state, SPD_IF);
+ source &= ~MASK_SPD_IF;
+ }
+
+ /* Auxiliary Video Information infoframe */
+ if (source & MASK_AVI_IF) {
+ tda1997x_parse_infoframe(state, AVI_IF);
+ source &= ~MASK_AVI_IF;
+ }
+}
+
+static void tda1997x_irq_audio(struct tda1997x_state *state, u8 *flags)
+{
+ struct v4l2_subdev *sd = &state->sd;
+ u8 reg, source;
+
+ source = io_read(sd, REG_INT_FLG_CLR_AUDIO);
+ io_write(sd, REG_INT_FLG_CLR_AUDIO, source);
+
+ /* reset audio FIFO on FIFO pointer error or audio mute */
+ if (source & MASK_ERROR_FIFO_PT ||
+ source & MASK_MUTE_FLG) {
+ /* audio reset audio FIFO */
+ reg = io_read(sd, REG_SUS_STATUS);
+ if ((reg & MASK_SUS_STATUS) == LAST_STATE_REACHED) {
+ reg = io_read(sd, REG_HDMI_INFO_RST);
+ reg |= MASK_SR_FIFO_FIFO_CTRL;
+ io_write(sd, REG_HDMI_INFO_RST, reg);
+ reg &= ~MASK_SR_FIFO_FIFO_CTRL;
+ io_write(sd, REG_HDMI_INFO_RST, reg);
+ /* reset channel status IT if present */
+ source &= ~(MASK_CH_STATE);
+ }
+ }
+ if (source & MASK_AUDIO_FREQ_FLG) {
+ static const int freq[] = {
+ 0, 32000, 44100, 48000, 88200, 96000, 176400, 192000
+ };
+
+ reg = io_read(sd, REG_AUDIO_FREQ);
+ state->audio_samplerate = freq[reg & 7];
+ v4l_info(state->client, "Audio Frequency Change: %dHz\n",
+ state->audio_samplerate);
+ }
+ if (source & MASK_AUDIO_FLG) {
+ reg = io_read(sd, REG_AUDIO_FLAGS);
+ if (reg & BIT(AUDCFG_TYPE_DST))
+ state->audio_type = AUDCFG_TYPE_DST;
+ if (reg & BIT(AUDCFG_TYPE_OBA))
+ state->audio_type = AUDCFG_TYPE_OBA;
+ if (reg & BIT(AUDCFG_TYPE_HBR))
+ state->audio_type = AUDCFG_TYPE_HBR;
+ if (reg & BIT(AUDCFG_TYPE_PCM))
+ state->audio_type = AUDCFG_TYPE_PCM;
+ v4l_info(state->client, "Audio Type: %s\n",
+ audtype_names[state->audio_type]);
+ }
+}
+
+static void tda1997x_irq_hdcp(struct tda1997x_state *state, u8 *flags)
+{
+ struct v4l2_subdev *sd = &state->sd;
+ u8 reg, source;
+
+ source = io_read(sd, REG_INT_FLG_CLR_HDCP);
+ io_write(sd, REG_INT_FLG_CLR_HDCP, source);
+
+ /* reset MTP in use flag if set */
+ if (source & MASK_HDCP_MTP)
+ state->mptrw_in_progress = 0;
+ if (source & MASK_STATE_C5) {
+ /* REPEATER: mask AUDIO and IF irqs to avoid IF during auth */
+ reg = io_read(sd, REG_INT_MASK_TOP);
+ reg &= ~(INTERRUPT_AUDIO | INTERRUPT_INFO);
+ io_write(sd, REG_INT_MASK_TOP, reg);
+ *flags &= (INTERRUPT_AUDIO | INTERRUPT_INFO);
+ }
+}
+
+static irqreturn_t tda1997x_isr_thread(int irq, void *d)
+{
+ struct tda1997x_state *state = d;
+ struct v4l2_subdev *sd = &state->sd;
+ u8 flags;
+
+ mutex_lock(&state->lock);
+ do {
+ /* read interrupt flags */
+ flags = io_read(sd, REG_INT_FLG_CLR_TOP);
+ if (flags == 0)
+ break;
+
+ /* SUS interrupt source (Input activity events) */
+ if (flags & INTERRUPT_SUS)
+ tda1997x_irq_sus(state, &flags);
+ /* DDC interrupt source (Display Data Channel) */
+ else if (flags & INTERRUPT_DDC)
+ tda1997x_irq_ddc(state, &flags);
+ /* RATE interrupt source (Digital Input activity) */
+ else if (flags & INTERRUPT_RATE)
+ tda1997x_irq_rate(state, &flags);
+ /* Infoframe change interrupt */
+ else if (flags & INTERRUPT_INFO)
+ tda1997x_irq_info(state, &flags);
+ /* Audio interrupt source:
+ * freq change, DST,OBA,HBR,ASP flags, mute, FIFO err
+ */
+ else if (flags & INTERRUPT_AUDIO)
+ tda1997x_irq_audio(state, &flags);
+ /* HDCP interrupt source (content protection) */
+ if (flags & INTERRUPT_HDCP)
+ tda1997x_irq_hdcp(state, &flags);
+ } while (flags != 0);
+ mutex_unlock(&state->lock);
+
+ return IRQ_HANDLED;
+}
+
+/* -----------------------------------------------------------------------------
+ * v4l2_subdev_video_ops
+ */
+
+static int
+tda1997x_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+ struct tda1997x_state *state = to_state(sd);
+ u32 vper;
+ u16 hper;
+ u16 hsper;
+
+ mutex_lock(&state->lock);
+ vper = io_read24(sd, REG_V_PER) & MASK_VPER;
+ hper = io_read16(sd, REG_H_PER) & MASK_HPER;
+ hsper = io_read16(sd, REG_HS_WIDTH) & MASK_HSWIDTH;
+ /*
+ * The tda1997x supports A/B inputs but only a single output.
+ * The irq handler monitors for timing changes on both inputs and
+ * sets the input_detect array to 0|1 depending on signal presence.
+ * I believe selection of A vs B is automatic.
+ *
+ * The vper/hper/hsper registers provide the frame period, line period
+ * and horiz sync period (units of MCLK clock cycles (27MHz)) and
+ * testing shows these values to be random if no signal is present
+ * or locked.
+ */
+ v4l2_dbg(1, debug, sd, "inputs:%d/%d timings:%d/%d/%d\n",
+ state->input_detect[0], state->input_detect[1],
+ vper, hper, hsper);
+ if (!state->input_detect[0] && !state->input_detect[1])
+ *status = V4L2_IN_ST_NO_SIGNAL;
+ else if (!vper || !hper || !hsper)
+ *status = V4L2_IN_ST_NO_SYNC;
+ else
+ *status = 0;
+ mutex_unlock(&state->lock);
+
+ return 0;
+};
+
+static int tda1997x_s_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
+{
+ struct tda1997x_state *state = to_state(sd);
+
+ v4l_dbg(1, debug, state->client, "%s\n", __func__);
+
+ if (v4l2_match_dv_timings(&state->timings, timings, 0, false))
+ return 0; /* no changes */
+
+ if (!v4l2_valid_dv_timings(timings, &tda1997x_dv_timings_cap,
+ NULL, NULL))
+ return -ERANGE;
+
+ mutex_lock(&state->lock);
+ state->timings = *timings;
+ /* setup frame detection window and VHREF timing generator */
+ tda1997x_configure_vhref(sd);
+ /* configure colorspace conversion */
+ tda1997x_configure_csc(sd);
+ mutex_unlock(&state->lock);
+
+ return 0;
+}
+
+static int tda1997x_g_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
+{
+ struct tda1997x_state *state = to_state(sd);
+
+ v4l_dbg(1, debug, state->client, "%s\n", __func__);
+ mutex_lock(&state->lock);
+ *timings = state->timings;
+ mutex_unlock(&state->lock);
+
+ return 0;
+}
+
+static int tda1997x_query_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
+{
+ struct tda1997x_state *state = to_state(sd);
+
+ v4l_dbg(1, debug, state->client, "%s\n", __func__);
+ memset(timings, 0, sizeof(struct v4l2_dv_timings));
+ mutex_lock(&state->lock);
+ tda1997x_detect_std(state, timings);
+ mutex_unlock(&state->lock);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops tda1997x_video_ops = {
+ .g_input_status = tda1997x_g_input_status,
+ .s_dv_timings = tda1997x_s_dv_timings,
+ .g_dv_timings = tda1997x_g_dv_timings,
+ .query_dv_timings = tda1997x_query_dv_timings,
+};
+
+
+/* -----------------------------------------------------------------------------
+ * v4l2_subdev_pad_ops
+ */
+
+static int tda1997x_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg)
+{
+ struct tda1997x_state *state = to_state(sd);
+ struct v4l2_mbus_framefmt *mf;
+
+ mf = v4l2_subdev_get_try_format(sd, cfg, 0);
+ mf->code = state->mbus_codes[0];
+
+ return 0;
+}
+
+static int tda1997x_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct tda1997x_state *state = to_state(sd);
+
+ v4l_dbg(1, debug, state->client, "%s %d\n", __func__, code->index);
+ if (code->index >= ARRAY_SIZE(state->mbus_codes))
+ return -EINVAL;
+
+ if (!state->mbus_codes[code->index])
+ return -EINVAL;
+
+ code->code = state->mbus_codes[code->index];
+
+ return 0;
+}
+
+static void tda1997x_fill_format(struct tda1997x_state *state,
+ struct v4l2_mbus_framefmt *format)
+{
+ const struct v4l2_bt_timings *bt;
+
+ memset(format, 0, sizeof(*format));
+ bt = &state->timings.bt;
+ format->width = bt->width;
+ format->height = bt->height;
+ format->colorspace = state->colorimetry.colorspace;
+ format->field = (bt->interlaced) ?
+ V4L2_FIELD_SEQ_TB : V4L2_FIELD_NONE;
+}
+
+static int tda1997x_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct tda1997x_state *state = to_state(sd);
+
+ v4l_dbg(1, debug, state->client, "%s pad=%d which=%d\n",
+ __func__, format->pad, format->which);
+
+ tda1997x_fill_format(state, &format->format);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ format->format.code = fmt->code;
+ } else
+ format->format.code = state->mbus_code;
+
+ return 0;
+}
+
+static int tda1997x_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct tda1997x_state *state = to_state(sd);
+ u32 code = 0;
+ int i;
+
+ v4l_dbg(1, debug, state->client, "%s pad=%d which=%d fmt=0x%x\n",
+ __func__, format->pad, format->which, format->format.code);
+
+ for (i = 0; i < ARRAY_SIZE(state->mbus_codes); i++) {
+ if (format->format.code == state->mbus_codes[i]) {
+ code = state->mbus_codes[i];
+ break;
+ }
+ }
+ if (!code)
+ code = state->mbus_codes[0];
+
+ tda1997x_fill_format(state, &format->format);
+ format->format.code = code;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+ *fmt = format->format;
+ } else {
+ int ret = tda1997x_setup_format(state, format->format.code);
+
+ if (ret)
+ return ret;
+ /* mbus_code has changed - re-configure csc/vidout */
+ tda1997x_configure_csc(sd);
+ tda1997x_configure_vidout(state);
+ }
+
+ return 0;
+}
+
+static int tda1997x_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+{
+ struct tda1997x_state *state = to_state(sd);
+
+ v4l_dbg(1, debug, state->client, "%s pad=%d\n", __func__, edid->pad);
+ memset(edid->reserved, 0, sizeof(edid->reserved));
+
+ if (edid->start_block == 0 && edid->blocks == 0) {
+ edid->blocks = state->edid.blocks;
+ return 0;
+ }
+
+ if (!state->edid.present)
+ return -ENODATA;
+
+ if (edid->start_block >= state->edid.blocks)
+ return -EINVAL;
+
+ if (edid->start_block + edid->blocks > state->edid.blocks)
+ edid->blocks = state->edid.blocks - edid->start_block;
+
+ memcpy(edid->edid, state->edid.edid + edid->start_block * 128,
+ edid->blocks * 128);
+
+ return 0;
+}
+
+static int tda1997x_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+{
+ struct tda1997x_state *state = to_state(sd);
+ int i;
+
+ v4l_dbg(1, debug, state->client, "%s pad=%d\n", __func__, edid->pad);
+ memset(edid->reserved, 0, sizeof(edid->reserved));
+
+ if (edid->start_block != 0)
+ return -EINVAL;
+
+ if (edid->blocks == 0) {
+ state->edid.blocks = 0;
+ state->edid.present = 0;
+ tda1997x_disable_edid(sd);
+ return 0;
+ }
+
+ if (edid->blocks > 2) {
+ edid->blocks = 2;
+ return -E2BIG;
+ }
+
+ tda1997x_disable_edid(sd);
+
+ /* write base EDID */
+ for (i = 0; i < 128; i++)
+ io_write(sd, REG_EDID_IN_BYTE0 + i, edid->edid[i]);
+
+ /* write CEA Extension */
+ for (i = 0; i < 128; i++)
+ io_write(sd, REG_EDID_IN_BYTE128 + i, edid->edid[i+128]);
+
+ tda1997x_enable_edid(sd);
+
+ return 0;
+}
+
+static int tda1997x_get_dv_timings_cap(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings_cap *cap)
+{
+ *cap = tda1997x_dv_timings_cap;
+ return 0;
+}
+
+static int tda1997x_enum_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_enum_dv_timings *timings)
+{
+ return v4l2_enum_dv_timings_cap(timings, &tda1997x_dv_timings_cap,
+ NULL, NULL);
+}
+
+static const struct v4l2_subdev_pad_ops tda1997x_pad_ops = {
+ .init_cfg = tda1997x_init_cfg,
+ .enum_mbus_code = tda1997x_enum_mbus_code,
+ .get_fmt = tda1997x_get_format,
+ .set_fmt = tda1997x_set_format,
+ .get_edid = tda1997x_get_edid,
+ .set_edid = tda1997x_set_edid,
+ .dv_timings_cap = tda1997x_get_dv_timings_cap,
+ .enum_dv_timings = tda1997x_enum_dv_timings,
+};
+
+/* -----------------------------------------------------------------------------
+ * v4l2_subdev_core_ops
+ */
+
+static int tda1997x_log_infoframe(struct v4l2_subdev *sd, int addr)
+{
+ struct tda1997x_state *state = to_state(sd);
+ union hdmi_infoframe frame;
+ u8 buffer[40];
+ int len, err;
+
+ /* read data */
+ len = io_readn(sd, addr, sizeof(buffer), buffer);
+ v4l2_dbg(1, debug, sd, "infoframe: addr=%d len=%d\n", addr, len);
+ err = hdmi_infoframe_unpack(&frame, buffer);
+ if (err) {
+ v4l_err(state->client,
+ "failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
+ len, addr, buffer[0]);
+ return err;
+ }
+ hdmi_infoframe_log(KERN_INFO, &state->client->dev, &frame);
+
+ return 0;
+}
+
+static int tda1997x_log_status(struct v4l2_subdev *sd)
+{
+ struct tda1997x_state *state = to_state(sd);
+ struct v4l2_dv_timings timings;
+ struct hdmi_avi_infoframe *avi = &state->avi_infoframe;
+
+ v4l2_info(sd, "-----Chip status-----\n");
+ v4l2_info(sd, "Chip: %s N%d\n", state->info->name,
+ state->chip_revision + 1);
+ v4l2_info(sd, "EDID Enabled: %s\n", state->edid.present ? "yes" : "no");
+
+ v4l2_info(sd, "-----Signal status-----\n");
+ v4l2_info(sd, "Cable detected (+5V power): %s\n",
+ tda1997x_detect_tx_5v(sd) ? "yes" : "no");
+ v4l2_info(sd, "HPD detected: %s\n",
+ tda1997x_detect_tx_hpd(sd) ? "yes" : "no");
+
+ v4l2_info(sd, "-----Video Timings-----\n");
+ switch (tda1997x_detect_std(state, &timings)) {
+ case -ENOLINK:
+ v4l2_info(sd, "No video detected\n");
+ break;
+ case -ERANGE:
+ v4l2_info(sd, "Invalid signal detected\n");
+ break;
+ }
+ v4l2_print_dv_timings(sd->name, "Configured format: ",
+ &state->timings, true);
+
+ v4l2_info(sd, "-----Color space-----\n");
+ v4l2_info(sd, "Input color space: %s %s %s",
+ hdmi_colorspace_names[avi->colorspace],
+ (avi->colorspace == HDMI_COLORSPACE_RGB) ? "" :
+ hdmi_colorimetry_names[avi->colorimetry],
+ v4l2_quantization_names[state->colorimetry.quantization]);
+ v4l2_info(sd, "Output color space: %s",
+ vidfmt_names[state->vid_fmt]);
+ v4l2_info(sd, "Color space conversion: %s", state->conv ?
+ state->conv->name : "None");
+
+ v4l2_info(sd, "-----Audio-----\n");
+ if (state->audio_channels) {
+ v4l2_info(sd, "audio: %dch %dHz\n", state->audio_channels,
+ state->audio_samplerate);
+ } else {
+ v4l2_info(sd, "audio: none\n");
+ }
+
+ v4l2_info(sd, "-----Infoframes-----\n");
+ tda1997x_log_infoframe(sd, AUD_IF);
+ tda1997x_log_infoframe(sd, SPD_IF);
+ tda1997x_log_infoframe(sd, AVI_IF);
+
+ return 0;
+}
+
+static int tda1997x_subscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ switch (sub->type) {
+ case V4L2_EVENT_SOURCE_CHANGE:
+ return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
+ case V4L2_EVENT_CTRL:
+ return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct v4l2_subdev_core_ops tda1997x_core_ops = {
+ .log_status = tda1997x_log_status,
+ .subscribe_event = tda1997x_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+/* -----------------------------------------------------------------------------
+ * v4l2_subdev_ops
+ */
+
+static const struct v4l2_subdev_ops tda1997x_subdev_ops = {
+ .core = &tda1997x_core_ops,
+ .video = &tda1997x_video_ops,
+ .pad = &tda1997x_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * v4l2_controls
+ */
+
+static int tda1997x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = to_sd(ctrl);
+ struct tda1997x_state *state = to_state(sd);
+
+ switch (ctrl->id) {
+ /* allow overriding the default RGB quantization range */
+ case V4L2_CID_DV_RX_RGB_RANGE:
+ state->rgb_quantization_range = ctrl->val;
+ set_rgb_quantization_range(state);
+ tda1997x_configure_csc(sd);
+ return 0;
+ }
+
+ return -EINVAL;
+};
+
+static int tda1997x_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = to_sd(ctrl);
+ struct tda1997x_state *state = to_state(sd);
+
+ if (ctrl->id == V4L2_CID_DV_RX_IT_CONTENT_TYPE) {
+ ctrl->val = state->avi_infoframe.content_type;
+ return 0;
+ }
+ return -EINVAL;
+};
+
+static const struct v4l2_ctrl_ops tda1997x_ctrl_ops = {
+ .s_ctrl = tda1997x_s_ctrl,
+ .g_volatile_ctrl = tda1997x_g_volatile_ctrl,
+};
+
+static int tda1997x_core_init(struct v4l2_subdev *sd)
+{
+ struct tda1997x_state *state = to_state(sd);
+ struct tda1997x_platform_data *pdata = &state->pdata;
+ u8 reg;
+ int i;
+
+ /* disable HPD */
+ io_write(sd, REG_HPD_AUTO_CTRL, HPD_AUTO_HPD_UNSEL);
+ if (state->chip_revision == 0) {
+ io_write(sd, REG_MAN_SUS_HDMI_SEL, MAN_DIS_HDCP | MAN_RST_HDCP);
+ io_write(sd, REG_CGU_DBG_SEL, 1 << CGU_DBG_CLK_SEL_SHIFT);
+ }
+
+ /* reset infoframe at end of start-up-sequencer */
+ io_write(sd, REG_SUS_SET_RGB2, 0x06);
+ io_write(sd, REG_SUS_SET_RGB3, 0x06);
+
+ /* Enable TMDS pull-ups */
+ io_write(sd, REG_RT_MAN_CTRL, RT_MAN_CTRL_RT |
+ RT_MAN_CTRL_RT_B | RT_MAN_CTRL_RT_A);
+
+ /* enable sync measurement timing */
+ tda1997x_cec_write(sd, REG_PWR_CONTROL & 0xff, 0x04);
+ /* adjust CEC clock divider */
+ tda1997x_cec_write(sd, REG_OSC_DIVIDER & 0xff, 0x03);
+ tda1997x_cec_write(sd, REG_EN_OSC_PERIOD_LSB & 0xff, 0xa0);
+ io_write(sd, REG_TIMER_D, 0x54);
+ /* enable power switch */
+ reg = tda1997x_cec_read(sd, REG_CONTROL & 0xff);
+ reg |= 0x20;
+ tda1997x_cec_write(sd, REG_CONTROL & 0xff, reg);
+ mdelay(50);
+
+ /* read the chip version */
+ reg = io_read(sd, REG_VERSION);
+ /* get the chip configuration */
+ reg = io_read(sd, REG_CMTP_REG10);
+
+ /* enable interrupts we care about */
+ io_write(sd, REG_INT_MASK_TOP,
+ INTERRUPT_HDCP | INTERRUPT_AUDIO | INTERRUPT_INFO |
+ INTERRUPT_RATE | INTERRUPT_SUS);
+ /* config_mtp,fmt,sus_end,sus_st */
+ io_write(sd, REG_INT_MASK_SUS, MASK_MPT | MASK_FMT | MASK_SUS_END);
+ /* rate stability change for inputs A/B */
+ io_write(sd, REG_INT_MASK_RATE, MASK_RATE_B_ST | MASK_RATE_A_ST);
+ /* aud,spd,avi*/
+ io_write(sd, REG_INT_MASK_INFO,
+ MASK_AUD_IF | MASK_SPD_IF | MASK_AVI_IF);
+ /* audio_freq,audio_flg,mute_flg,fifo_err */
+ io_write(sd, REG_INT_MASK_AUDIO,
+ MASK_AUDIO_FREQ_FLG | MASK_AUDIO_FLG | MASK_MUTE_FLG |
+ MASK_ERROR_FIFO_PT);
+ /* HDCP C5 state reached */
+ io_write(sd, REG_INT_MASK_HDCP, MASK_STATE_C5);
+ /* 5V detect and HDP pulse end */
+ io_write(sd, REG_INT_MASK_DDC, MASK_DET_5V);
+ /* don't care about AFE/MODE */
+ io_write(sd, REG_INT_MASK_AFE, 0);
+ io_write(sd, REG_INT_MASK_MODE, 0);
+
+ /* clear all interrupts */
+ io_write(sd, REG_INT_FLG_CLR_TOP, 0xff);
+ io_write(sd, REG_INT_FLG_CLR_SUS, 0xff);
+ io_write(sd, REG_INT_FLG_CLR_DDC, 0xff);
+ io_write(sd, REG_INT_FLG_CLR_RATE, 0xff);
+ io_write(sd, REG_INT_FLG_CLR_MODE, 0xff);
+ io_write(sd, REG_INT_FLG_CLR_INFO, 0xff);
+ io_write(sd, REG_INT_FLG_CLR_AUDIO, 0xff);
+ io_write(sd, REG_INT_FLG_CLR_HDCP, 0xff);
+ io_write(sd, REG_INT_FLG_CLR_AFE, 0xff);
+
+ /* init TMDS equalizer */
+ if (state->chip_revision == 0)
+ io_write(sd, REG_CGU_DBG_SEL, 1 << CGU_DBG_CLK_SEL_SHIFT);
+ io_write24(sd, REG_CLK_MIN_RATE, CLK_MIN_RATE);
+ io_write24(sd, REG_CLK_MAX_RATE, CLK_MAX_RATE);
+ if (state->chip_revision == 0)
+ io_write(sd, REG_WDL_CFG, WDL_CFG_VAL);
+ /* DC filter */
+ io_write(sd, REG_DEEP_COLOR_CTRL, DC_FILTER_VAL);
+ /* disable test pattern */
+ io_write(sd, REG_SVC_MODE, 0x00);
+ /* update HDMI INFO CTRL */
+ io_write(sd, REG_INFO_CTRL, 0xff);
+ /* write HDMI INFO EXCEED value */
+ io_write(sd, REG_INFO_EXCEED, 3);
+
+ if (state->chip_revision == 0)
+ tda1997x_reset_n1(state);
+
+ /*
+ * No HDCP acknowledge when HDCP is disabled
+ * and reset SUS to force format detection
+ */
+ tda1997x_hdmi_info_reset(sd, NACK_HDCP, true);
+
+ /* Set HPD low */
+ tda1997x_manual_hpd(sd, HPD_LOW_BP);
+
+ /* Configure receiver capabilities */
+ io_write(sd, REG_HDCP_BCAPS, HDCP_HDMI | HDCP_FAST_REAUTH);
+
+ /* Configure HDMI: Auto HDCP mode, packet controlled mute */
+ reg = HDMI_CTRL_MUTE_AUTO << HDMI_CTRL_MUTE_SHIFT;
+ reg |= HDMI_CTRL_HDCP_AUTO << HDMI_CTRL_HDCP_SHIFT;
+ io_write(sd, REG_HDMI_CTRL, reg);
+
+ /* reset start-up-sequencer to force format detection */
+ tda1997x_hdmi_info_reset(sd, 0, true);
+
+ /* disable matrix conversion */
+ reg = io_read(sd, REG_VDP_CTRL);
+ reg |= VDP_CTRL_MATRIX_BP;
+ io_write(sd, REG_VDP_CTRL, reg);
+
+ /* set video output mode */
+ tda1997x_configure_vidout(state);
+
+ /* configure video output port */
+ for (i = 0; i < 9; i++) {
+ v4l_dbg(1, debug, state->client, "vidout_cfg[%d]=0x%02x\n", i,
+ pdata->vidout_port_cfg[i]);
+ io_write(sd, REG_VP35_32_CTRL + i, pdata->vidout_port_cfg[i]);
+ }
+
+ /* configure audio output port */
+ tda1997x_configure_audout(sd, 0);
+
+ /* configure audio clock freq */
+ switch (pdata->audout_mclk_fs) {
+ case 512:
+ reg = AUDIO_CLOCK_SEL_512FS;
+ break;
+ case 256:
+ reg = AUDIO_CLOCK_SEL_256FS;
+ break;
+ case 128:
+ reg = AUDIO_CLOCK_SEL_128FS;
+ break;
+ case 64:
+ reg = AUDIO_CLOCK_SEL_64FS;
+ break;
+ case 32:
+ reg = AUDIO_CLOCK_SEL_32FS;
+ break;
+ default:
+ reg = AUDIO_CLOCK_SEL_16FS;
+ break;
+ }
+ io_write(sd, REG_AUDIO_CLOCK, reg);
+
+ /* reset advanced infoframes (ISRC1/ISRC2/ACP) */
+ tda1997x_hdmi_info_reset(sd, RESET_AI, false);
+ /* reset infoframe */
+ tda1997x_hdmi_info_reset(sd, RESET_IF, false);
+ /* reset audio infoframes */
+ tda1997x_hdmi_info_reset(sd, RESET_AUDIO, false);
+ /* reset gamut */
+ tda1997x_hdmi_info_reset(sd, RESET_GAMUT, false);
+
+ /* get initial HDMI status */
+ state->hdmi_status = io_read(sd, REG_HDMI_FLAGS);
+
+ return 0;
+}
+
+static int tda1997x_set_power(struct tda1997x_state *state, bool on)
+{
+ int ret = 0;
+
+ if (on) {
+ ret = regulator_bulk_enable(TDA1997X_NUM_SUPPLIES,
+ state->supplies);
+ msleep(300);
+ } else {
+ ret = regulator_bulk_disable(TDA1997X_NUM_SUPPLIES,
+ state->supplies);
+ }
+
+ return ret;
+}
+
+static const struct i2c_device_id tda1997x_i2c_id[] = {
+ {"tda19971", (kernel_ulong_t)&tda1997x_chip_info[TDA19971]},
+ {"tda19973", (kernel_ulong_t)&tda1997x_chip_info[TDA19973]},
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, tda1997x_i2c_id);
+
+static const struct of_device_id tda1997x_of_id[] __maybe_unused = {
+ { .compatible = "nxp,tda19971", .data = &tda1997x_chip_info[TDA19971] },
+ { .compatible = "nxp,tda19973", .data = &tda1997x_chip_info[TDA19973] },
+ { },
+};
+MODULE_DEVICE_TABLE(of, tda1997x_of_id);
+
+static int tda1997x_parse_dt(struct tda1997x_state *state)
+{
+ struct tda1997x_platform_data *pdata = &state->pdata;
+ struct v4l2_fwnode_endpoint bus_cfg;
+ struct device_node *ep;
+ struct device_node *np;
+ unsigned int flags;
+ const char *str;
+ int ret;
+ u32 v;
+
+ /*
+ * setup default values:
+ * - HREF: active high from start to end of row
+ * - VS: Vertical Sync active high at beginning of frame
+ * - DE: Active high when data valid
+ * - A_CLK: 128*Fs
+ */
+ pdata->vidout_sel_hs = HS_HREF_SEL_HREF_VHREF;
+ pdata->vidout_sel_vs = VS_VREF_SEL_VREF_HDMI;
+ pdata->vidout_sel_de = DE_FREF_SEL_DE_VHREF;
+
+ np = state->client->dev.of_node;
+ ep = of_graph_get_next_endpoint(np, NULL);
+ if (!ep)
+ return -EINVAL;
+
+ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
+ if (ret) {
+ of_node_put(ep);
+ return ret;
+ }
+ of_node_put(ep);
+ pdata->vidout_bus_type = bus_cfg.bus_type;
+
+ /* polarity of HS/VS/DE */
+ flags = bus_cfg.bus.parallel.flags;
+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ pdata->vidout_inv_hs = 1;
+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ pdata->vidout_inv_vs = 1;
+ if (flags & V4L2_MBUS_DATA_ACTIVE_LOW)
+ pdata->vidout_inv_de = 1;
+ pdata->vidout_bus_width = bus_cfg.bus.parallel.bus_width;
+
+ /* video output port config */
+ ret = of_property_count_u32_elems(np, "nxp,vidout-portcfg");
+ if (ret > 0) {
+ u32 reg, val, i;
+
+ for (i = 0; i < ret / 2 && i < 9; i++) {
+ of_property_read_u32_index(np, "nxp,vidout-portcfg",
+ i * 2, &reg);
+ of_property_read_u32_index(np, "nxp,vidout-portcfg",
+ i * 2 + 1, &val);
+ if (reg < 9)
+ pdata->vidout_port_cfg[reg] = val;
+ }
+ } else {
+ v4l_err(state->client, "nxp,vidout-portcfg missing\n");
+ return -EINVAL;
+ }
+
+ /* default to channel layout dictated by packet header */
+ pdata->audout_layoutauto = true;
+
+ pdata->audout_format = AUDFMT_TYPE_DISABLED;
+ if (!of_property_read_string(np, "nxp,audout-format", &str)) {
+ if (strcmp(str, "i2s") == 0)
+ pdata->audout_format = AUDFMT_TYPE_I2S;
+ else if (strcmp(str, "spdif") == 0)
+ pdata->audout_format = AUDFMT_TYPE_SPDIF;
+ else {
+ v4l_err(state->client, "nxp,audout-format invalid\n");
+ return -EINVAL;
+ }
+ if (!of_property_read_u32(np, "nxp,audout-layout", &v)) {
+ switch (v) {
+ case 0:
+ case 1:
+ break;
+ default:
+ v4l_err(state->client,
+ "nxp,audout-layout invalid\n");
+ return -EINVAL;
+ }
+ pdata->audout_layout = v;
+ }
+ if (!of_property_read_u32(np, "nxp,audout-width", &v)) {
+ switch (v) {
+ case 16:
+ case 32:
+ break;
+ default:
+ v4l_err(state->client,
+ "nxp,audout-width invalid\n");
+ return -EINVAL;
+ }
+ pdata->audout_width = v;
+ }
+ if (!of_property_read_u32(np, "nxp,audout-mclk-fs", &v)) {
+ switch (v) {
+ case 512:
+ case 256:
+ case 128:
+ case 64:
+ case 32:
+ case 16:
+ break;
+ default:
+ v4l_err(state->client,
+ "nxp,audout-mclk-fs invalid\n");
+ return -EINVAL;
+ }
+ pdata->audout_mclk_fs = v;
+ }
+ }
+
+ return 0;
+}
+
+static int tda1997x_get_regulators(struct tda1997x_state *state)
+{
+ int i;
+
+ for (i = 0; i < TDA1997X_NUM_SUPPLIES; i++)
+ state->supplies[i].supply = tda1997x_supply_name[i];
+
+ return devm_regulator_bulk_get(&state->client->dev,
+ TDA1997X_NUM_SUPPLIES,
+ state->supplies);
+}
+
+static int tda1997x_identify_module(struct tda1997x_state *state)
+{
+ struct v4l2_subdev *sd = &state->sd;
+ enum tda1997x_type type;
+ u8 reg;
+
+ /* Read chip configuration*/
+ reg = io_read(sd, REG_CMTP_REG10);
+ state->tmdsb_clk = (reg >> 6) & 0x01; /* use tmds clock B_inv for B */
+ state->tmdsb_soc = (reg >> 5) & 0x01; /* tmds of input B */
+ state->port_30bit = (reg >> 2) & 0x03; /* 30bit vs 24bit */
+ state->output_2p5 = (reg >> 1) & 0x01; /* output supply 2.5v */
+ switch ((reg >> 4) & 0x03) {
+ case 0x00:
+ type = TDA19971;
+ break;
+ case 0x02:
+ case 0x03:
+ type = TDA19973;
+ break;
+ default:
+ dev_err(&state->client->dev, "unsupported chip ID\n");
+ return -EIO;
+ }
+ if (state->info->type != type) {
+ dev_err(&state->client->dev, "chip id mismatch\n");
+ return -EIO;
+ }
+
+ /* read chip revision */
+ state->chip_revision = io_read(sd, REG_CMTP_REG11);
+
+ return 0;
+}
+
+static const struct media_entity_operations tda1997x_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+
+/* -----------------------------------------------------------------------------
+ * HDMI Audio Codec
+ */
+
+/* refine sample-rate based on HDMI source */
+static int tda1997x_pcm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct tda1997x_state *state = snd_soc_dai_get_drvdata(dai);
+ struct snd_soc_codec *codec = dai->codec;
+ struct snd_pcm_runtime *rtd = substream->runtime;
+ int rate, err;
+
+ rate = state->audio_samplerate;
+ err = snd_pcm_hw_constraint_minmax(rtd, SNDRV_PCM_HW_PARAM_RATE,
+ rate, rate);
+ if (err < 0) {
+ dev_err(codec->dev, "failed to constrain samplerate to %dHz\n",
+ rate);
+ return err;
+ }
+ dev_info(codec->dev, "set samplerate constraint to %dHz\n", rate);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops tda1997x_dai_ops = {
+ .startup = tda1997x_pcm_startup,
+};
+
+static struct snd_soc_dai_driver tda1997x_audio_dai = {
+ .name = "tda1997x",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
+ },
+ .ops = &tda1997x_dai_ops,
+};
+
+static int tda1997x_codec_probe(struct snd_soc_codec *codec)
+{
+ return 0;
+}
+
+static int tda1997x_codec_remove(struct snd_soc_codec *codec)
+{
+ return 0;
+}
+
+static struct snd_soc_codec_driver tda1997x_codec_driver = {
+ .probe = tda1997x_codec_probe,
+ .remove = tda1997x_codec_remove,
+ .reg_word_size = sizeof(u16),
+};
+
+static int tda1997x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tda1997x_state *state;
+ struct tda1997x_platform_data *pdata;
+ struct v4l2_subdev *sd;
+ struct v4l2_ctrl_handler *hdl;
+ struct v4l2_ctrl *ctrl;
+ static const struct v4l2_dv_timings cea1920x1080 =
+ V4L2_DV_BT_CEA_1920X1080P60;
+ u32 *mbus_codes;
+ int i, ret;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ state = kzalloc(sizeof(struct tda1997x_state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ state->client = client;
+ pdata = &state->pdata;
+ if (IS_ENABLED(CONFIG_OF) && client->dev.of_node) {
+ const struct of_device_id *oid;
+
+ oid = of_match_node(tda1997x_of_id, client->dev.of_node);
+ state->info = oid->data;
+
+ ret = tda1997x_parse_dt(state);
+ if (ret < 0) {
+ v4l_err(client, "DT parsing error\n");
+ goto err_free_state;
+ }
+ } else if (client->dev.platform_data) {
+ struct tda1997x_platform_data *pdata =
+ client->dev.platform_data;
+ state->info =
+ (const struct tda1997x_chip_info *)id->driver_data;
+ state->pdata = *pdata;
+ } else {
+ v4l_err(client, "No platform data\n");
+ ret = -ENODEV;
+ goto err_free_state;
+ }
+
+ ret = tda1997x_get_regulators(state);
+ if (ret)
+ goto err_free_state;
+
+ ret = tda1997x_set_power(state, 1);
+ if (ret)
+ goto err_free_state;
+
+ mutex_init(&state->page_lock);
+ mutex_init(&state->lock);
+ state->page = 0xff;
+
+ INIT_DELAYED_WORK(&state->delayed_work_enable_hpd,
+ tda1997x_delayed_work_enable_hpd);
+
+ /* set video format based on chip and bus width */
+ ret = tda1997x_identify_module(state);
+ if (ret)
+ goto err_free_mutex;
+
+ /* initialize subdev */
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &tda1997x_subdev_ops);
+ snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
+ id->name, i2c_adapter_id(client->adapter),
+ client->addr);
+ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+ sd->entity.function = MEDIA_ENT_F_DTV_DECODER;
+ sd->entity.ops = &tda1997x_media_ops;
+
+ /* set allowed mbus modes based on chip, bus-type, and bus-width */
+ i = 0;
+ mbus_codes = state->mbus_codes;
+ switch (state->info->type) {
+ case TDA19973:
+ switch (pdata->vidout_bus_type) {
+ case V4L2_MBUS_PARALLEL:
+ switch (pdata->vidout_bus_width) {
+ case 36:
+ mbus_codes[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
+ mbus_codes[i++] = MEDIA_BUS_FMT_YUV12_1X36;
+ /* fall-through */
+ case 24:
+ mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
+ break;
+ }
+ break;
+ case V4L2_MBUS_BT656:
+ switch (pdata->vidout_bus_width) {
+ case 36:
+ case 24:
+ case 12:
+ mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_2X12;
+ mbus_codes[i++] = MEDIA_BUS_FMT_UYVY10_2X10;
+ mbus_codes[i++] = MEDIA_BUS_FMT_UYVY8_2X8;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case TDA19971:
+ switch (pdata->vidout_bus_type) {
+ case V4L2_MBUS_PARALLEL:
+ switch (pdata->vidout_bus_width) {
+ case 24:
+ mbus_codes[i++] = MEDIA_BUS_FMT_RGB888_1X24;
+ mbus_codes[i++] = MEDIA_BUS_FMT_YUV8_1X24;
+ mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
+ /* fall through */
+ case 20:
+ mbus_codes[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
+ /* fall through */
+ case 16:
+ mbus_codes[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
+ break;
+ }
+ break;
+ case V4L2_MBUS_BT656:
+ switch (pdata->vidout_bus_width) {
+ case 24:
+ case 20:
+ case 16:
+ case 12:
+ mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_2X12;
+ /* fall through */
+ case 10:
+ mbus_codes[i++] = MEDIA_BUS_FMT_UYVY10_2X10;
+ /* fall through */
+ case 8:
+ mbus_codes[i++] = MEDIA_BUS_FMT_UYVY8_2X8;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ if (WARN_ON(i > ARRAY_SIZE(state->mbus_codes))) {
+ ret = -EINVAL;
+ goto err_free_mutex;
+ }
+
+ /* default format */
+ tda1997x_setup_format(state, state->mbus_codes[0]);
+ state->timings = cea1920x1080;
+
+ /*
+ * default to SRGB full range quantization
+ * (in case we don't get an infoframe such as DVI signal
+ */
+ state->colorimetry.colorspace = V4L2_COLORSPACE_SRGB;
+ state->colorimetry.quantization = V4L2_QUANTIZATION_FULL_RANGE;
+
+ /* disable/reset HDCP to get correct I2C access to Rx HDMI */
+ io_write(sd, REG_MAN_SUS_HDMI_SEL, MAN_RST_HDCP | MAN_DIS_HDCP);
+
+ /*
+ * if N2 version, reset compdel_bp as it may generate some small pixel
+ * shifts in case of embedded sync/or delay lower than 4
+ */
+ if (state->chip_revision != 0) {
+ io_write(sd, REG_MAN_SUS_HDMI_SEL, 0x00);
+ io_write(sd, REG_VDP_CTRL, 0x1f);
+ }
+
+ v4l_info(client, "NXP %s N%d detected\n", state->info->name,
+ state->chip_revision + 1);
+ v4l_info(client, "video: %dbit %s %d formats available\n",
+ pdata->vidout_bus_width,
+ (pdata->vidout_bus_type == V4L2_MBUS_PARALLEL) ?
+ "parallel" : "BT656",
+ i);
+ if (pdata->audout_format) {
+ v4l_info(client, "audio: %dch %s layout%d sysclk=%d*fs\n",
+ pdata->audout_layout ? 2 : 8,
+ audfmt_names[pdata->audout_format],
+ pdata->audout_layout,
+ pdata->audout_mclk_fs);
+ }
+
+ ret = 0x34 + ((io_read(sd, REG_SLAVE_ADDR)>>4) & 0x03);
+ state->client_cec = i2c_new_dummy(client->adapter, ret);
+ v4l_info(client, "CEC slave address 0x%02x\n", ret);
+
+ ret = tda1997x_core_init(sd);
+ if (ret)
+ goto err_free_mutex;
+
+ /* control handlers */
+ hdl = &state->hdl;
+ v4l2_ctrl_handler_init(hdl, 3);
+ ctrl = v4l2_ctrl_new_std_menu(hdl, &tda1997x_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,
+ V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0);
+ state->rgb_quantization_range_ctrl = v4l2_ctrl_new_std_menu(hdl,
+ &tda1997x_ctrl_ops,
+ V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, 0,
+ V4L2_DV_RGB_RANGE_AUTO);
+ state->sd.ctrl_handler = hdl;
+ if (hdl->error) {
+ ret = hdl->error;
+ goto err_free_handler;
+ }
+ v4l2_ctrl_handler_setup(hdl);
+
+ /* initialize source pads */
+ state->pads[TDA1997X_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&sd->entity, TDA1997X_NUM_PADS,
+ state->pads);
+ if (ret) {
+ v4l_err(client, "failed entity_init: %d", ret);
+ goto err_free_mutex;
+ }
+
+ ret = v4l2_async_register_subdev(sd);
+ if (ret)
+ goto err_free_media;
+
+ /* register audio DAI */
+ if (pdata->audout_format) {
+ u64 formats;
+
+ if (pdata->audout_width == 32)
+ formats = SNDRV_PCM_FMTBIT_S32_LE;
+ else
+ formats = SNDRV_PCM_FMTBIT_S16_LE;
+ tda1997x_audio_dai.capture.formats = formats;
+ ret = snd_soc_register_codec(&state->client->dev,
+ &tda1997x_codec_driver,
+ &tda1997x_audio_dai, 1);
+ if (ret) {
+ dev_err(&client->dev, "register audio codec failed\n");
+ goto err_free_media;
+ }
+ dev_set_drvdata(&state->client->dev, state);
+ v4l_info(state->client, "registered audio codec\n");
+ }
+
+ /* request irq */
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, tda1997x_isr_thread,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ KBUILD_MODNAME, state);
+ if (ret) {
+ v4l_err(client, "irq%d reg failed: %d\n", client->irq, ret);
+ goto err_free_media;
+ }
+
+ return 0;
+
+err_free_media:
+ media_entity_cleanup(&sd->entity);
+err_free_handler:
+ v4l2_ctrl_handler_free(&state->hdl);
+err_free_mutex:
+ cancel_delayed_work(&state->delayed_work_enable_hpd);
+ mutex_destroy(&state->page_lock);
+ mutex_destroy(&state->lock);
+err_free_state:
+ kfree(state);
+ dev_err(&client->dev, "%s failed: %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int tda1997x_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct tda1997x_state *state = to_state(sd);
+ struct tda1997x_platform_data *pdata = &state->pdata;
+
+ if (pdata->audout_format) {
+ snd_soc_unregister_codec(&client->dev);
+ mutex_destroy(&state->audio_lock);
+ }
+
+ disable_irq(state->client->irq);
+ tda1997x_power_mode(state, 0);
+
+ v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(&state->hdl);
+ regulator_bulk_disable(TDA1997X_NUM_SUPPLIES, state->supplies);
+ i2c_unregister_device(state->client_cec);
+ cancel_delayed_work(&state->delayed_work_enable_hpd);
+ mutex_destroy(&state->page_lock);
+ mutex_destroy(&state->lock);
+
+ kfree(state);
+
+ return 0;
+}
+
+static struct i2c_driver tda1997x_i2c_driver = {
+ .driver = {
+ .name = "tda1997x",
+ .of_match_table = of_match_ptr(tda1997x_of_id),
+ },
+ .probe = tda1997x_probe,
+ .remove = tda1997x_remove,
+ .id_table = tda1997x_i2c_id,
+};
+
+module_i2c_driver(tda1997x_i2c_driver);
+
+MODULE_AUTHOR("Tim Harvey <tharvey@gateworks.com>");
+MODULE_DESCRIPTION("TDA1997X HDMI Receiver driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/tda1997x_regs.h b/drivers/media/i2c/tda1997x_regs.h
new file mode 100644
index 000000000000..f55dfc423a86
--- /dev/null
+++ b/drivers/media/i2c/tda1997x_regs.h
@@ -0,0 +1,641 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Gateworks Corporation
+ */
+
+/* Page 0x00 - General Control */
+#define REG_VERSION 0x0000
+#define REG_INPUT_SEL 0x0001
+#define REG_SVC_MODE 0x0002
+#define REG_HPD_MAN_CTRL 0x0003
+#define REG_RT_MAN_CTRL 0x0004
+#define REG_STANDBY_SOFT_RST 0x000A
+#define REG_HDMI_SOFT_RST 0x000B
+#define REG_HDMI_INFO_RST 0x000C
+#define REG_INT_FLG_CLR_TOP 0x000E
+#define REG_INT_FLG_CLR_SUS 0x000F
+#define REG_INT_FLG_CLR_DDC 0x0010
+#define REG_INT_FLG_CLR_RATE 0x0011
+#define REG_INT_FLG_CLR_MODE 0x0012
+#define REG_INT_FLG_CLR_INFO 0x0013
+#define REG_INT_FLG_CLR_AUDIO 0x0014
+#define REG_INT_FLG_CLR_HDCP 0x0015
+#define REG_INT_FLG_CLR_AFE 0x0016
+#define REG_INT_MASK_TOP 0x0017
+#define REG_INT_MASK_SUS 0x0018
+#define REG_INT_MASK_DDC 0x0019
+#define REG_INT_MASK_RATE 0x001A
+#define REG_INT_MASK_MODE 0x001B
+#define REG_INT_MASK_INFO 0x001C
+#define REG_INT_MASK_AUDIO 0x001D
+#define REG_INT_MASK_HDCP 0x001E
+#define REG_INT_MASK_AFE 0x001F
+#define REG_DETECT_5V 0x0020
+#define REG_SUS_STATUS 0x0021
+#define REG_V_PER 0x0022
+#define REG_H_PER 0x0025
+#define REG_HS_WIDTH 0x0027
+#define REG_FMT_H_TOT 0x0029
+#define REG_FMT_H_ACT 0x002b
+#define REG_FMT_H_FRONT 0x002d
+#define REG_FMT_H_SYNC 0x002f
+#define REG_FMT_H_BACK 0x0031
+#define REG_FMT_V_TOT 0x0033
+#define REG_FMT_V_ACT 0x0035
+#define REG_FMT_V_FRONT_F1 0x0037
+#define REG_FMT_V_FRONT_F2 0x0038
+#define REG_FMT_V_SYNC 0x0039
+#define REG_FMT_V_BACK_F1 0x003a
+#define REG_FMT_V_BACK_F2 0x003b
+#define REG_FMT_DE_ACT 0x003c
+#define REG_RATE_CTRL 0x0040
+#define REG_CLK_MIN_RATE 0x0043
+#define REG_CLK_MAX_RATE 0x0046
+#define REG_CLK_A_STATUS 0x0049
+#define REG_CLK_A_RATE 0x004A
+#define REG_DRIFT_CLK_A_REG 0x004D
+#define REG_CLK_B_STATUS 0x004E
+#define REG_CLK_B_RATE 0x004F
+#define REG_DRIFT_CLK_B_REG 0x0052
+#define REG_HDCP_CTRL 0x0060
+#define REG_HDCP_KDS 0x0061
+#define REG_HDCP_BCAPS 0x0063
+#define REG_HDCP_KEY_CTRL 0x0064
+#define REG_INFO_CTRL 0x0076
+#define REG_INFO_EXCEED 0x0077
+#define REG_PIX_REPEAT 0x007B
+#define REG_AUDIO_PATH 0x007C
+#define REG_AUDCFG 0x007D
+#define REG_AUDIO_OUT_ENABLE 0x007E
+#define REG_AUDIO_OUT_HIZ 0x007F
+#define REG_VDP_CTRL 0x0080
+#define REG_VDP_MATRIX 0x0081
+#define REG_VHREF_CTRL 0x00A0
+#define REG_PXCNT_PR 0x00A2
+#define REG_PXCNT_NPIX 0x00A4
+#define REG_LCNT_PR 0x00A6
+#define REG_LCNT_NLIN 0x00A8
+#define REG_HREF_S 0x00AA
+#define REG_HREF_E 0x00AC
+#define REG_HS_S 0x00AE
+#define REG_HS_E 0x00B0
+#define REG_VREF_F1_S 0x00B2
+#define REG_VREF_F1_WIDTH 0x00B4
+#define REG_VREF_F2_S 0x00B5
+#define REG_VREF_F2_WIDTH 0x00B7
+#define REG_VS_F1_LINE_S 0x00B8
+#define REG_VS_F1_LINE_WIDTH 0x00BA
+#define REG_VS_F2_LINE_S 0x00BB
+#define REG_VS_F2_LINE_WIDTH 0x00BD
+#define REG_VS_F1_PIX_S 0x00BE
+#define REG_VS_F1_PIX_E 0x00C0
+#define REG_VS_F2_PIX_S 0x00C2
+#define REG_VS_F2_PIX_E 0x00C4
+#define REG_FREF_F1_S 0x00C6
+#define REG_FREF_F2_S 0x00C8
+#define REG_FDW_S 0x00ca
+#define REG_FDW_E 0x00cc
+#define REG_BLK_GY 0x00da
+#define REG_BLK_BU 0x00dc
+#define REG_BLK_RV 0x00de
+#define REG_FILTERS_CTRL 0x00e0
+#define REG_DITHERING_CTRL 0x00E9
+#define REG_OF 0x00EA
+#define REG_PCLK 0x00EB
+#define REG_HS_HREF 0x00EC
+#define REG_VS_VREF 0x00ED
+#define REG_DE_FREF 0x00EE
+#define REG_VP35_32_CTRL 0x00EF
+#define REG_VP31_28_CTRL 0x00F0
+#define REG_VP27_24_CTRL 0x00F1
+#define REG_VP23_20_CTRL 0x00F2
+#define REG_VP19_16_CTRL 0x00F3
+#define REG_VP15_12_CTRL 0x00F4
+#define REG_VP11_08_CTRL 0x00F5
+#define REG_VP07_04_CTRL 0x00F6
+#define REG_VP03_00_CTRL 0x00F7
+#define REG_CURPAGE_00H 0xFF
+
+#define MASK_VPER 0x3fffff
+#define MASK_VHREF 0x3fff
+#define MASK_HPER 0x0fff
+#define MASK_HSWIDTH 0x03ff
+
+/* HPD Detection */
+#define DETECT_UTIL BIT(7) /* utility of HDMI level */
+#define DETECT_HPD BIT(6) /* HPD of HDMI level */
+#define DETECT_5V_SEL BIT(2) /* 5V present on selected input */
+#define DETECT_5V_B BIT(1) /* 5V present on input B */
+#define DETECT_5V_A BIT(0) /* 5V present on input A */
+
+/* Input Select */
+#define INPUT_SEL_RST_FMT BIT(7) /* 1=reset format measurement */
+#define INPUT_SEL_RST_VDP BIT(2) /* 1=reset video data path */
+#define INPUT_SEL_OUT_MODE BIT(1) /* 0=loop 1=bypass */
+#define INPUT_SEL_B BIT(0) /* 0=inputA 1=inputB */
+
+/* Service Mode */
+#define SVC_MODE_CLK2_MASK 0xc0
+#define SVC_MODE_CLK2_SHIFT 6
+#define SVC_MODE_CLK2_XTL 0L
+#define SVC_MODE_CLK2_XTLDIV2 1L
+#define SVC_MODE_CLK2_HDMIX2 3L
+#define SVC_MODE_CLK1_MASK 0x30
+#define SVC_MODE_CLK1_SHIFT 4
+#define SVC_MODE_CLK1_XTAL 0L
+#define SVC_MODE_CLK1_XTLDIV2 1L
+#define SVC_MODE_CLK1_HDMI 3L
+#define SVC_MODE_RAMP BIT(3) /* 0=colorbar 1=ramp */
+#define SVC_MODE_PAL BIT(2) /* 0=NTSC(480i/p) 1=PAL(576i/p) */
+#define SVC_MODE_INT_PROG BIT(1) /* 0=interlaced 1=progressive */
+#define SVC_MODE_SM_ON BIT(0) /* Enable color bars and tone gen */
+
+/* HDP Manual Control */
+#define HPD_MAN_CTRL_HPD_PULSE BIT(7) /* HPD Pulse low 110ms */
+#define HPD_MAN_CTRL_5VEN BIT(2) /* Output 5V */
+#define HPD_MAN_CTRL_HPD_B BIT(1) /* Assert HPD High for Input A */
+#define HPD_MAN_CTRL_HPD_A BIT(0) /* Assert HPD High for Input A */
+
+/* RT_MAN_CTRL */
+#define RT_MAN_CTRL_RT_AUTO BIT(7)
+#define RT_MAN_CTRL_RT BIT(6)
+#define RT_MAN_CTRL_RT_B BIT(1) /* enable TMDS pull-up on Input B */
+#define RT_MAN_CTRL_RT_A BIT(0) /* enable TMDS pull-up on Input A */
+
+/* VDP_CTRL */
+#define VDP_CTRL_COMPDEL_BP BIT(5) /* bypass compdel */
+#define VDP_CTRL_FORMATTER_BP BIT(4) /* bypass formatter */
+#define VDP_CTRL_PREFILTER_BP BIT(1) /* bypass prefilter */
+#define VDP_CTRL_MATRIX_BP BIT(0) /* bypass matrix conversion */
+
+/* REG_VHREF_CTRL */
+#define VHREF_INT_DET BIT(7) /* interlace detect: 1=alt 0=frame */
+#define VHREF_VSYNC_MASK 0x60
+#define VHREF_VSYNC_SHIFT 6
+#define VHREF_VSYNC_AUTO 0L
+#define VHREF_VSYNC_FDW 1L
+#define VHREF_VSYNC_EVEN 2L
+#define VHREF_VSYNC_ODD 3L
+#define VHREF_STD_DET_MASK 0x18
+#define VHREF_STD_DET_SHIFT 3
+#define VHREF_STD_DET_PAL 0L
+#define VHREF_STD_DET_NTSC 1L
+#define VHREF_STD_DET_AUTO 2L
+#define VHREF_STD_DET_OFF 3L
+#define VHREF_VREF_SRC_STD BIT(2) /* 1=from standard 0=manual */
+#define VHREF_HREF_SRC_STD BIT(1) /* 1=from standard 0=manual */
+#define VHREF_HSYNC_SEL_HS BIT(0) /* 1=HS 0=VS */
+
+/* AUDIO_OUT_ENABLE */
+#define AUDIO_OUT_ENABLE_ACLK BIT(5)
+#define AUDIO_OUT_ENABLE_WS BIT(4)
+#define AUDIO_OUT_ENABLE_AP3 BIT(3)
+#define AUDIO_OUT_ENABLE_AP2 BIT(2)
+#define AUDIO_OUT_ENABLE_AP1 BIT(1)
+#define AUDIO_OUT_ENABLE_AP0 BIT(0)
+
+/* Prefilter Control */
+#define FILTERS_CTRL_BU_MASK 0x0c
+#define FILTERS_CTRL_BU_SHIFT 2
+#define FILTERS_CTRL_RV_MASK 0x03
+#define FILTERS_CTRL_RV_SHIFT 0
+#define FILTERS_CTRL_OFF 0L /* off */
+#define FILTERS_CTRL_2TAP 1L /* 2 Taps */
+#define FILTERS_CTRL_7TAP 2L /* 7 Taps */
+#define FILTERS_CTRL_2_7TAP 3L /* 2/7 Taps */
+
+/* PCLK Configuration */
+#define PCLK_DELAY_MASK 0x70
+#define PCLK_DELAY_SHIFT 4 /* Pixel delay (-8..+7) */
+#define PCLK_INV_SHIFT 2
+#define PCLK_SEL_MASK 0x03 /* clock scaler */
+#define PCLK_SEL_SHIFT 0
+#define PCLK_SEL_X1 0L
+#define PCLK_SEL_X2 1L
+#define PCLK_SEL_DIV2 2L
+#define PCLK_SEL_DIV4 3L
+
+/* Pixel Repeater */
+#define PIX_REPEAT_MASK_UP_SEL 0x30
+#define PIX_REPEAT_MASK_REP 0x0f
+#define PIX_REPEAT_SHIFT 4
+#define PIX_REPEAT_CHROMA 1
+
+/* Page 0x01 - HDMI info and packets */
+#define REG_HDMI_FLAGS 0x0100
+#define REG_DEEP_COLOR_MODE 0x0101
+#define REG_AUDIO_FLAGS 0x0108
+#define REG_AUDIO_FREQ 0x0109
+#define REG_ACP_PACKET_TYPE 0x0141
+#define REG_ISRC1_PACKET_TYPE 0x0161
+#define REG_ISRC2_PACKET_TYPE 0x0181
+#define REG_GBD_PACKET_TYPE 0x01a1
+
+/* HDMI_FLAGS */
+#define HDMI_FLAGS_AUDIO BIT(7) /* Audio packet in last videoframe */
+#define HDMI_FLAGS_HDMI BIT(6) /* HDMI detected */
+#define HDMI_FLAGS_EESS BIT(5) /* EESS detected */
+#define HDMI_FLAGS_HDCP BIT(4) /* HDCP detected */
+#define HDMI_FLAGS_AVMUTE BIT(3) /* AVMUTE */
+#define HDMI_FLAGS_AUD_LAYOUT BIT(2) /* Layout status Audio sample packet */
+#define HDMI_FLAGS_AUD_FIFO_OF BIT(1) /* FIFO read/write pointers crossed */
+#define HDMI_FLAGS_AUD_FIFO_LOW BIT(0) /* FIFO read ptr within 2 of write */
+
+/* Page 0x12 - HDMI Extra control and debug */
+#define REG_CLK_CFG 0x1200
+#define REG_CLK_OUT_CFG 0x1201
+#define REG_CFG1 0x1202
+#define REG_CFG2 0x1203
+#define REG_WDL_CFG 0x1210
+#define REG_DELOCK_DELAY 0x1212
+#define REG_PON_OVR_EN 0x12A0
+#define REG_PON_CBIAS 0x12A1
+#define REG_PON_RESCAL 0x12A2
+#define REG_PON_RES 0x12A3
+#define REG_PON_CLK 0x12A4
+#define REG_PON_PLL 0x12A5
+#define REG_PON_EQ 0x12A6
+#define REG_PON_DES 0x12A7
+#define REG_PON_OUT 0x12A8
+#define REG_PON_MUX 0x12A9
+#define REG_MODE_REC_CFG1 0x12F8
+#define REG_MODE_REC_CFG2 0x12F9
+#define REG_MODE_REC_STS 0x12FA
+#define REG_AUDIO_LAYOUT 0x12D0
+
+#define PON_EN 1
+#define PON_DIS 0
+
+/* CLK CFG */
+#define CLK_CFG_INV_OUT_CLK BIT(7)
+#define CLK_CFG_INV_BUS_CLK BIT(6)
+#define CLK_CFG_SEL_ACLK_EN BIT(1)
+#define CLK_CFG_SEL_ACLK BIT(0)
+#define CLK_CFG_DIS 0
+
+/* Page 0x13 - HDMI Extra control and debug */
+#define REG_DEEP_COLOR_CTRL 0x1300
+#define REG_CGU_DBG_SEL 0x1305
+#define REG_HDCP_DDC_ADDR 0x1310
+#define REG_HDCP_KIDX 0x1316
+#define REG_DEEP_PLL7_BYP 0x1347
+#define REG_HDCP_DE_CTRL 0x1370
+#define REG_HDCP_EP_FILT_CTRL 0x1371
+#define REG_HDMI_CTRL 0x1377
+#define REG_HMTP_CTRL 0x137a
+#define REG_TIMER_D 0x13CF
+#define REG_SUS_SET_RGB0 0x13E1
+#define REG_SUS_SET_RGB1 0x13E2
+#define REG_SUS_SET_RGB2 0x13E3
+#define REG_SUS_SET_RGB3 0x13E4
+#define REG_SUS_SET_RGB4 0x13E5
+#define REG_MAN_SUS_HDMI_SEL 0x13E8
+#define REG_MAN_HDMI_SET 0x13E9
+#define REG_SUS_CLOCK_GOOD 0x13EF
+
+/* HDCP DE Control */
+#define HDCP_DE_MODE_MASK 0xc0 /* DE Measurement mode */
+#define HDCP_DE_MODE_SHIFT 6
+#define HDCP_DE_REGEN_EN BIT(5) /* enable regen mode */
+#define HDCP_DE_FILTER_MASK 0x18 /* DE filter sensitivity */
+#define HDCP_DE_FILTER_SHIFT 3
+#define HDCP_DE_COMP_MASK 0x07 /* DE Composition mode */
+#define HDCP_DE_COMP_MIXED 6L
+#define HDCP_DE_COMP_OR 5L
+#define HDCP_DE_COMP_AND 4L
+#define HDCP_DE_COMP_CH3 3L
+#define HDCP_DE_COMP_CH2 2L
+#define HDCP_DE_COMP_CH1 1L
+#define HDCP_DE_COMP_CH0 0L
+
+/* HDCP EP Filter Control */
+#define HDCP_EP_FIL_CTL_MASK 0x30
+#define HDCP_EP_FIL_CTL_SHIFT 4
+#define HDCP_EP_FIL_VS_MASK 0x0c
+#define HDCP_EP_FIL_VS_SHIFT 2
+#define HDCP_EP_FIL_HS_MASK 0x03
+#define HDCP_EP_FIL_HS_SHIFT 0
+
+/* HDMI_CTRL */
+#define HDMI_CTRL_MUTE_MASK 0x0c
+#define HDMI_CTRL_MUTE_SHIFT 2
+#define HDMI_CTRL_MUTE_AUTO 0L
+#define HDMI_CTRL_MUTE_OFF 1L
+#define HDMI_CTRL_MUTE_ON 2L
+#define HDMI_CTRL_HDCP_MASK 0x03
+#define HDMI_CTRL_HDCP_SHIFT 0
+#define HDMI_CTRL_HDCP_EESS 2L
+#define HDMI_CTRL_HDCP_OESS 1L
+#define HDMI_CTRL_HDCP_AUTO 0L
+
+/* CGU_DBG_SEL bits */
+#define CGU_DBG_CLK_SEL_MASK 0x18
+#define CGU_DBG_CLK_SEL_SHIFT 3
+#define CGU_DBG_XO_FRO_SEL BIT(2)
+#define CGU_DBG_VDP_CLK_SEL BIT(1)
+#define CGU_DBG_PIX_CLK_SEL BIT(0)
+
+/* REG_MAN_SUS_HDMI_SEL / REG_MAN_HDMI_SET bits */
+#define MAN_DIS_OUT_BUF BIT(7)
+#define MAN_DIS_ANA_PATH BIT(6)
+#define MAN_DIS_HDCP BIT(5)
+#define MAN_DIS_TMDS_ENC BIT(4)
+#define MAN_DIS_TMDS_FLOW BIT(3)
+#define MAN_RST_HDCP BIT(2)
+#define MAN_RST_TMDS_ENC BIT(1)
+#define MAN_RST_TMDS_FLOW BIT(0)
+
+/* Page 0x14 - Audio Extra control and debug */
+#define REG_FIFO_LATENCY_VAL 0x1403
+#define REG_AUDIO_CLOCK 0x1411
+#define REG_TEST_NCTS_CTRL 0x1415
+#define REG_TEST_AUDIO_FREQ 0x1426
+#define REG_TEST_MODE 0x1437
+
+/* Audio Clock Configuration */
+#define AUDIO_CLOCK_PLL_PD BIT(7) /* powerdown PLL */
+#define AUDIO_CLOCK_SEL_MASK 0x7f
+#define AUDIO_CLOCK_SEL_16FS 0L /* 16*fs */
+#define AUDIO_CLOCK_SEL_32FS 1L /* 32*fs */
+#define AUDIO_CLOCK_SEL_64FS 2L /* 64*fs */
+#define AUDIO_CLOCK_SEL_128FS 3L /* 128*fs */
+#define AUDIO_CLOCK_SEL_256FS 4L /* 256*fs */
+#define AUDIO_CLOCK_SEL_512FS 5L /* 512*fs */
+
+/* Page 0x20: EDID and Hotplug Detect */
+#define REG_EDID_IN_BYTE0 0x2000 /* EDID base */
+#define REG_EDID_IN_VERSION 0x2080
+#define REG_EDID_ENABLE 0x2081
+#define REG_HPD_POWER 0x2084
+#define REG_HPD_AUTO_CTRL 0x2085
+#define REG_HPD_DURATION 0x2086
+#define REG_RX_HPD_HEAC 0x2087
+
+/* EDID_ENABLE */
+#define EDID_ENABLE_NACK_OFF BIT(7)
+#define EDID_ENABLE_EDID_ONLY BIT(6)
+#define EDID_ENABLE_B_EN BIT(1)
+#define EDID_ENABLE_A_EN BIT(0)
+
+/* HPD Power */
+#define HPD_POWER_BP_MASK 0x0c
+#define HPD_POWER_BP_SHIFT 2
+#define HPD_POWER_BP_LOW 0L
+#define HPD_POWER_BP_HIGH 1L
+#define HPD_POWER_EDID_ONLY BIT(1)
+
+/* HPD Auto control */
+#define HPD_AUTO_READ_EDID BIT(7)
+#define HPD_AUTO_HPD_F3TECH BIT(5)
+#define HPD_AUTO_HP_OTHER BIT(4)
+#define HPD_AUTO_HPD_UNSEL BIT(3)
+#define HPD_AUTO_HPD_ALL_CH BIT(2)
+#define HPD_AUTO_HPD_PRV_CH BIT(1)
+#define HPD_AUTO_HPD_NEW_CH BIT(0)
+
+/* Page 0x21 - EDID content */
+#define REG_EDID_IN_BYTE128 0x2100 /* CEA Extension block */
+#define REG_EDID_IN_SPA_SUB 0x2180
+#define REG_EDID_IN_SPA_AB_A 0x2181
+#define REG_EDID_IN_SPA_CD_A 0x2182
+#define REG_EDID_IN_CKSUM_A 0x2183
+#define REG_EDID_IN_SPA_AB_B 0x2184
+#define REG_EDID_IN_SPA_CD_B 0x2185
+#define REG_EDID_IN_CKSUM_B 0x2186
+
+/* Page 0x30 - NV Configuration */
+#define REG_RT_AUTO_CTRL 0x3000
+#define REG_EQ_MAN_CTRL0 0x3001
+#define REG_EQ_MAN_CTRL1 0x3002
+#define REG_OUTPUT_CFG 0x3003
+#define REG_MUTE_CTRL 0x3004
+#define REG_SLAVE_ADDR 0x3005
+#define REG_CMTP_REG6 0x3006
+#define REG_CMTP_REG7 0x3007
+#define REG_CMTP_REG8 0x3008
+#define REG_CMTP_REG9 0x3009
+#define REG_CMTP_REGA 0x300A
+#define REG_CMTP_REGB 0x300B
+#define REG_CMTP_REGC 0x300C
+#define REG_CMTP_REGD 0x300D
+#define REG_CMTP_REGE 0x300E
+#define REG_CMTP_REGF 0x300F
+#define REG_CMTP_REG10 0x3010
+#define REG_CMTP_REG11 0x3011
+
+/* Page 0x80 - CEC */
+#define REG_PWR_CONTROL 0x80F4
+#define REG_OSC_DIVIDER 0x80F5
+#define REG_EN_OSC_PERIOD_LSB 0x80F8
+#define REG_CONTROL 0x80FF
+
+/* global interrupt flags (INT_FLG_CRL_TOP) */
+#define INTERRUPT_AFE BIT(7) /* AFE module */
+#define INTERRUPT_HDCP BIT(6) /* HDCP module */
+#define INTERRUPT_AUDIO BIT(5) /* Audio module */
+#define INTERRUPT_INFO BIT(4) /* Infoframe module */
+#define INTERRUPT_MODE BIT(3) /* HDMI mode module */
+#define INTERRUPT_RATE BIT(2) /* rate module */
+#define INTERRUPT_DDC BIT(1) /* DDC module */
+#define INTERRUPT_SUS BIT(0) /* SUS module */
+
+/* INT_FLG_CLR_HDCP bits */
+#define MASK_HDCP_MTP BIT(7) /* HDCP MTP busy */
+#define MASK_HDCP_DLMTP BIT(4) /* HDCP end download MTP to SRAM */
+#define MASK_HDCP_DLRAM BIT(3) /* HDCP end download keys from SRAM */
+#define MASK_HDCP_ENC BIT(2) /* HDCP ENC */
+#define MASK_STATE_C5 BIT(1) /* HDCP State C5 reached */
+#define MASK_AKSV BIT(0) /* AKSV received (start of auth) */
+
+/* INT_FLG_CLR_RATE bits */
+#define MASK_RATE_B_DRIFT BIT(7) /* Rate measurement drifted */
+#define MASK_RATE_B_ST BIT(6) /* Rate measurement stability change */
+#define MASK_RATE_B_ACT BIT(5) /* Rate measurement activity change */
+#define MASK_RATE_B_PST BIT(4) /* Rate measreument presence change */
+#define MASK_RATE_A_DRIFT BIT(3) /* Rate measurement drifted */
+#define MASK_RATE_A_ST BIT(2) /* Rate measurement stability change */
+#define MASK_RATE_A_ACT BIT(1) /* Rate measurement presence change */
+#define MASK_RATE_A_PST BIT(0) /* Rate measreument presence change */
+
+/* INT_FLG_CLR_SUS (Start Up Sequencer) bits */
+#define MASK_MPT BIT(7) /* Config MTP end of process */
+#define MASK_FMT BIT(5) /* Video format changed */
+#define MASK_RT_PULSE BIT(4) /* End of termination resistance pulse */
+#define MASK_SUS_END BIT(3) /* SUS last state reached */
+#define MASK_SUS_ACT BIT(2) /* Activity of selected input changed */
+#define MASK_SUS_CH BIT(1) /* Selected input changed */
+#define MASK_SUS_ST BIT(0) /* SUS state changed */
+
+/* INT_FLG_CLR_DDC bits */
+#define MASK_EDID_MTP BIT(7) /* EDID MTP end of process */
+#define MASK_DDC_ERR BIT(6) /* master DDC error */
+#define MASK_DDC_CMD_DONE BIT(5) /* master DDC cmd send correct */
+#define MASK_READ_DONE BIT(4) /* End of down EDID read */
+#define MASK_RX_DDC_SW BIT(3) /* Output DDC switching finished */
+#define MASK_HDCP_DDC_SW BIT(2) /* HDCP DDC switching finished */
+#define MASK_HDP_PULSE_END BIT(1) /* End of Hot Plug Detect pulse */
+#define MASK_DET_5V BIT(0) /* Detection of +5V */
+
+/* INT_FLG_CLR_MODE bits */
+#define MASK_HDMI_FLG BIT(7) /* HDMI mode/avmute/encrypt/FIFO fail */
+#define MASK_GAMUT BIT(6) /* Gamut packet */
+#define MASK_ISRC2 BIT(5) /* ISRC2 packet */
+#define MASK_ISRC1 BIT(4) /* ISRC1 packet */
+#define MASK_ACP BIT(3) /* Audio Content Protection packet */
+#define MASK_DC_NO_GCP BIT(2) /* GCP not received in 5 frames */
+#define MASK_DC_PHASE BIT(1) /* deepcolor pixel phase needs update */
+#define MASK_DC_MODE BIT(0) /* deepcolor color depth changed */
+
+/* INT_FLG_CLR_INFO bits (Infoframe Change Status) */
+#define MASK_MPS_IF BIT(6) /* MPEG Source Product */
+#define MASK_AUD_IF BIT(5) /* Audio */
+#define MASK_SPD_IF BIT(4) /* Source Product Descriptor */
+#define MASK_AVI_IF BIT(3) /* Auxiliary Video IF */
+#define MASK_VS_IF_OTHER_BK2 BIT(2) /* Vendor Specific (bank2) */
+#define MASK_VS_IF_OTHER_BK1 BIT(1) /* Vendor Specific (bank1) */
+#define MASK_VS_IF_HDMI BIT(0) /* Vendor Specific (w/ HDMI LLC code) */
+
+/* INT_FLG_CLR_AUDIO bits */
+#define MASK_AUDIO_FREQ_FLG BIT(5) /* Audio freq change */
+#define MASK_AUDIO_FLG BIT(4) /* DST, OBA, HBR, ASP change */
+#define MASK_MUTE_FLG BIT(3) /* Audio Mute */
+#define MASK_CH_STATE BIT(2) /* Channel status */
+#define MASK_UNMUTE_FIFO BIT(1) /* Audio Unmute */
+#define MASK_ERROR_FIFO_PT BIT(0) /* Audio FIFO pointer error */
+
+/* INT_FLG_CLR_AFE bits */
+#define MASK_AFE_WDL_UNLOCKED BIT(7) /* Wordlocker was unlocked */
+#define MASK_AFE_GAIN_DONE BIT(6) /* Gain calibration done */
+#define MASK_AFE_OFFSET_DONE BIT(5) /* Offset calibration done */
+#define MASK_AFE_ACTIVITY_DET BIT(4) /* Activity detected on data */
+#define MASK_AFE_PLL_LOCK BIT(3) /* TMDS PLL is locked */
+#define MASK_AFE_TRMCAL_DONE BIT(2) /* Termination calibration done */
+#define MASK_AFE_ASU_STATE BIT(1) /* ASU state is reached */
+#define MASK_AFE_ASU_READY BIT(0) /* AFE calibration done: TMDS ready */
+
+/* Audio Output */
+#define AUDCFG_CLK_INVERT BIT(7) /* invert A_CLK polarity */
+#define AUDCFG_TEST_TONE BIT(6) /* enable test tone generator */
+#define AUDCFG_BUS_SHIFT 5
+#define AUDCFG_BUS_I2S 0L
+#define AUDCFG_BUS_SPDIF 1L
+#define AUDCFG_I2SW_SHIFT 4
+#define AUDCFG_I2SW_16 0L
+#define AUDCFG_I2SW_32 1L
+#define AUDCFG_AUTO_MUTE_EN BIT(3) /* Enable Automatic audio mute */
+#define AUDCFG_HBR_SHIFT 2
+#define AUDCFG_HBR_STRAIGHT 0L /* straight via AP0 */
+#define AUDCFG_HBR_DEMUX 1L /* demuxed via AP0:AP3 */
+#define AUDCFG_TYPE_MASK 0x03
+#define AUDCFG_TYPE_SHIFT 0
+#define AUDCFG_TYPE_DST 3L /* Direct Stream Transfer (DST) */
+#define AUDCFG_TYPE_OBA 2L /* One Bit Audio (OBA) */
+#define AUDCFG_TYPE_HBR 1L /* High Bit Rate (HBR) */
+#define AUDCFG_TYPE_PCM 0L /* Audio samples */
+
+/* Video Formatter */
+#define OF_VP_ENABLE BIT(7) /* VP[35:0]/HS/VS/DE/CLK */
+#define OF_BLK BIT(4) /* blanking codes */
+#define OF_TRC BIT(3) /* timing codes (SAV/EAV) */
+#define OF_FMT_MASK 0x3
+#define OF_FMT_444 0L /* RGB444/YUV444 */
+#define OF_FMT_422_SMPT 1L /* YUV422 semi-planar */
+#define OF_FMT_422_CCIR 2L /* YUV422 CCIR656 */
+
+/* HS/HREF output control */
+#define HS_HREF_DELAY_MASK 0xf0
+#define HS_HREF_DELAY_SHIFT 4 /* Pixel delay (-8..+7) */
+#define HS_HREF_PXQ_SHIFT 3 /* Timing codes from HREF */
+#define HS_HREF_INV_SHIFT 2 /* polarity (1=invert) */
+#define HS_HREF_SEL_MASK 0x03
+#define HS_HREF_SEL_SHIFT 0
+#define HS_HREF_SEL_HS_VHREF 0L /* HS from VHREF */
+#define HS_HREF_SEL_HREF_VHREF 1L /* HREF from VHREF */
+#define HS_HREF_SEL_HREF_HDMI 2L /* HREF from HDMI */
+#define HS_HREF_SEL_NONE 3L /* not generated */
+
+/* VS output control */
+#define VS_VREF_DELAY_MASK 0xf0
+#define VS_VREF_DELAY_SHIFT 4 /* Pixel delay (-8..+7) */
+#define VS_VREF_INV_SHIFT 2 /* polarity (1=invert) */
+#define VS_VREF_SEL_MASK 0x03
+#define VS_VREF_SEL_SHIFT 0
+#define VS_VREF_SEL_VS_VHREF 0L /* VS from VHREF */
+#define VS_VREF_SEL_VREF_VHREF 1L /* VREF from VHREF */
+#define VS_VREF_SEL_VREF_HDMI 2L /* VREF from HDMI */
+#define VS_VREF_SEL_NONE 3L /* not generated */
+
+/* DE/FREF output control */
+#define DE_FREF_DELAY_MASK 0xf0
+#define DE_FREF_DELAY_SHIFT 4 /* Pixel delay (-8..+7) */
+#define DE_FREF_DE_PXQ_SHIFT 3 /* Timing codes from DE */
+#define DE_FREF_INV_SHIFT 2 /* polarity (1=invert) */
+#define DE_FREF_SEL_MASK 0x03
+#define DE_FREF_SEL_SHIFT 0
+#define DE_FREF_SEL_DE_VHREF 0L /* DE from VHREF (HREF and not(VREF) */
+#define DE_FREF_SEL_FREF_VHREF 1L /* FREF from VHREF */
+#define DE_FREF_SEL_FREF_HDMI 2L /* FREF from HDMI */
+#define DE_FREF_SEL_NONE 3L /* not generated */
+
+/* HDMI_SOFT_RST bits */
+#define RESET_DC BIT(7) /* Reset deep color module */
+#define RESET_HDCP BIT(6) /* Reset HDCP module */
+#define RESET_KSV BIT(5) /* Reset KSV-FIFO */
+#define RESET_SCFG BIT(4) /* Reset HDCP and repeater function */
+#define RESET_HCFG BIT(3) /* Reset HDCP DDC part */
+#define RESET_PA BIT(2) /* Reset polarity adjust */
+#define RESET_EP BIT(1) /* Reset Error protection */
+#define RESET_TMDS BIT(0) /* Reset TMDS (calib, encoding, flow) */
+
+/* HDMI_INFO_RST bits */
+#define NACK_HDCP BIT(7) /* No ACK on HDCP request */
+#define RESET_FIFO BIT(4) /* Reset Audio FIFO control */
+#define RESET_GAMUT BIT(3) /* Clear Gamut packet */
+#define RESET_AI BIT(2) /* Clear ACP and ISRC packets */
+#define RESET_IF BIT(1) /* Clear all Audio infoframe packets */
+#define RESET_AUDIO BIT(0) /* Reset Audio FIFO control */
+
+/* HDCP_BCAPS bits */
+#define HDCP_HDMI BIT(7) /* HDCP suports HDMI (vs DVI only) */
+#define HDCP_REPEATER BIT(6) /* HDCP supports repeater function */
+#define HDCP_READY BIT(5) /* set by repeater function */
+#define HDCP_FAST BIT(4) /* Up to 400kHz */
+#define HDCP_11 BIT(1) /* HDCP 1.1 supported */
+#define HDCP_FAST_REAUTH BIT(0) /* fast reauthentication supported */
+
+/* Audio output formatter */
+#define AUDIO_LAYOUT_SP_FLAG BIT(2) /* sp flag used by FIFO */
+#define AUDIO_LAYOUT_MANUAL BIT(1) /* manual layout (vs per pkt) */
+#define AUDIO_LAYOUT_LAYOUT1 BIT(0) /* Layout1: AP0-3 vs Layout0:AP0 */
+
+/* masks for interrupt status registers */
+#define MASK_SUS_STATUS 0x1F
+#define LAST_STATE_REACHED 0x1B
+#define MASK_CLK_STABLE 0x04
+#define MASK_CLK_ACTIVE 0x02
+#define MASK_SUS_STATE 0x10
+#define MASK_SR_FIFO_FIFO_CTRL 0x30
+#define MASK_AUDIO_FLAG 0x10
+
+/* Rate measurement */
+#define RATE_REFTIM_ENABLE 0x01
+#define CLK_MIN_RATE 0x0057e4
+#define CLK_MAX_RATE 0x0395f8
+#define WDL_CFG_VAL 0x82
+#define DC_FILTER_VAL 0x31
+
+/* Infoframe */
+#define VS_HDMI_IF_UPDATE 0x0200
+#define VS_HDMI_IF 0x0201
+#define VS_BK1_IF_UPDATE 0x0220
+#define VS_BK1_IF 0x0221
+#define VS_BK2_IF_UPDATE 0x0240
+#define VS_BK2_IF 0x0241
+#define AVI_IF_UPDATE 0x0260
+#define AVI_IF 0x0261
+#define SPD_IF_UPDATE 0x0280
+#define SPD_IF 0x0281
+#define AUD_IF_UPDATE 0x02a0
+#define AUD_IF 0x02a1
+#define MPS_IF_UPDATE 0x02c0
+#define MPS_IF 0x02c1
diff --git a/drivers/media/i2c/tda9840.c b/drivers/media/i2c/tda9840.c
index f31e659588ac..0dd6ff3e6201 100644
--- a/drivers/media/i2c/tda9840.c
+++ b/drivers/media/i2c/tda9840.c
@@ -68,11 +68,15 @@ static void tda9840_write(struct v4l2_subdev *sd, u8 reg, u8 val)
static int tda9840_status(struct v4l2_subdev *sd)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int rc;
u8 byte;
- if (1 != i2c_master_recv(client, &byte, 1)) {
+ rc = i2c_master_recv(client, &byte, 1);
+ if (rc != 1) {
v4l2_dbg(1, debug, sd,
"i2c_master_recv() failed\n");
+ if (rc < 0)
+ return rc;
return -EIO;
}
diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c
index 772164b848ef..5919214a56bf 100644
--- a/drivers/media/i2c/tvaudio.c
+++ b/drivers/media/i2c/tvaudio.c
@@ -156,14 +156,18 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
struct v4l2_subdev *sd = &chip->sd;
struct i2c_client *c = v4l2_get_subdevdata(sd);
unsigned char buffer[2];
+ int rc;
if (subaddr < 0) {
v4l2_dbg(1, debug, sd, "chip_write: 0x%x\n", val);
chip->shadow.bytes[1] = val;
buffer[0] = val;
- if (1 != i2c_master_send(c, buffer, 1)) {
+ rc = i2c_master_send(c, buffer, 1);
+ if (rc != 1) {
v4l2_warn(sd, "I/O error (write 0x%x)\n", val);
- return -1;
+ if (rc < 0)
+ return rc;
+ return -EIO;
}
} else {
if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
@@ -178,10 +182,13 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
chip->shadow.bytes[subaddr+1] = val;
buffer[0] = subaddr;
buffer[1] = val;
- if (2 != i2c_master_send(c, buffer, 2)) {
+ rc = i2c_master_send(c, buffer, 2);
+ if (rc != 2) {
v4l2_warn(sd, "I/O error (write reg%d=0x%x)\n",
subaddr, val);
- return -1;
+ if (rc < 0)
+ return rc;
+ return -EIO;
}
}
return 0;
@@ -214,10 +221,14 @@ static int chip_read(struct CHIPSTATE *chip)
struct v4l2_subdev *sd = &chip->sd;
struct i2c_client *c = v4l2_get_subdevdata(sd);
unsigned char buffer;
+ int rc;
- if (1 != i2c_master_recv(c, &buffer, 1)) {
+ rc = i2c_master_recv(c, &buffer, 1);
+ if (rc != 1) {
v4l2_warn(sd, "I/O error (read)\n");
- return -1;
+ if (rc < 0)
+ return rc;
+ return -EIO;
}
v4l2_dbg(1, debug, sd, "chip_read: 0x%x\n", buffer);
return buffer;
@@ -227,6 +238,7 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr)
{
struct v4l2_subdev *sd = &chip->sd;
struct i2c_client *c = v4l2_get_subdevdata(sd);
+ int rc;
unsigned char write[1];
unsigned char read[1];
struct i2c_msg msgs[2] = {
@@ -245,9 +257,12 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr)
write[0] = subaddr;
- if (2 != i2c_transfer(c->adapter, msgs, 2)) {
+ rc = i2c_transfer(c->adapter, msgs, 2);
+ if (rc != 2) {
v4l2_warn(sd, "I/O error (read2)\n");
- return -1;
+ if (rc < 0)
+ return rc;
+ return -EIO;
}
v4l2_dbg(1, debug, sd, "chip_read2: reg%d=0x%x\n",
subaddr, read[0]);
@@ -258,7 +273,7 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
{
struct v4l2_subdev *sd = &chip->sd;
struct i2c_client *c = v4l2_get_subdevdata(sd);
- int i;
+ int i, rc;
if (0 == cmd->count)
return 0;
@@ -284,9 +299,12 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
printk(KERN_CONT "\n");
/* send data to the chip */
- if (cmd->count != i2c_master_send(c, cmd->bytes, cmd->count)) {
+ rc = i2c_master_send(c, cmd->bytes, cmd->count);
+ if (rc != cmd->count) {
v4l2_warn(sd, "I/O error (%s)\n", name);
- return -1;
+ if (rc < 0)
+ return rc;
+ return -EIO;
}
return 0;
}
@@ -400,8 +418,12 @@ static int tda9840_getrxsubchans(struct CHIPSTATE *chip)
struct v4l2_subdev *sd = &chip->sd;
int val, mode;
- val = chip_read(chip);
mode = V4L2_TUNER_SUB_MONO;
+
+ val = chip_read(chip);
+ if (val < 0)
+ return mode;
+
if (val & TDA9840_DS_DUAL)
mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
if (val & TDA9840_ST_STEREO)
@@ -445,7 +467,12 @@ static void tda9840_setaudmode(struct CHIPSTATE *chip, int mode)
static int tda9840_checkit(struct CHIPSTATE *chip)
{
int rc;
+
rc = chip_read(chip);
+ if (rc < 0)
+ return 0;
+
+
/* lower 5 bits should be 0 */
return ((rc & 0x1f) == 0) ? 1 : 0;
}
@@ -563,6 +590,9 @@ static int tda985x_getrxsubchans(struct CHIPSTATE *chip)
/* Allows forced mono */
mode = V4L2_TUNER_SUB_MONO;
val = chip_read(chip);
+ if (val < 0)
+ return mode;
+
if (val & TDA985x_STP)
mode = V4L2_TUNER_SUB_STEREO;
if (val & TDA985x_SAPP)
@@ -720,8 +750,12 @@ static int tda9873_getrxsubchans(struct CHIPSTATE *chip)
struct v4l2_subdev *sd = &chip->sd;
int val,mode;
- val = chip_read(chip);
mode = V4L2_TUNER_SUB_MONO;
+
+ val = chip_read(chip);
+ if (val < 0)
+ return mode;
+
if (val & TDA9873_STEREO)
mode = V4L2_TUNER_SUB_STEREO;
if (val & TDA9873_DUAL)
@@ -780,7 +814,8 @@ static int tda9873_checkit(struct CHIPSTATE *chip)
{
int rc;
- if (-1 == (rc = chip_read2(chip,254)))
+ rc = chip_read2(chip, 254);
+ if (rc < 0)
return 0;
return (rc & ~0x1f) == 0x80;
}
@@ -926,11 +961,14 @@ static int tda9874a_getrxsubchans(struct CHIPSTATE *chip)
mode = V4L2_TUNER_SUB_MONO;
- if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR)))
+ dsr = chip_read2(chip, TDA9874A_DSR);
+ if (dsr < 0)
return mode;
- if(-1 == (nsr = chip_read2(chip,TDA9874A_NSR)))
+ nsr = chip_read2(chip, TDA9874A_NSR);
+ if (nsr < 0)
return mode;
- if(-1 == (necr = chip_read2(chip,TDA9874A_NECR)))
+ necr = chip_read2(chip, TDA9874A_NECR);
+ if (necr < 0)
return mode;
/* need to store dsr/nsr somewhere */
@@ -1059,9 +1097,11 @@ static int tda9874a_checkit(struct CHIPSTATE *chip)
struct v4l2_subdev *sd = &chip->sd;
int dic,sic; /* device id. and software id. codes */
- if(-1 == (dic = chip_read2(chip,TDA9874A_DIC)))
+ dic = chip_read2(chip, TDA9874A_DIC);
+ if (dic < 0)
return 0;
- if(-1 == (sic = chip_read2(chip,TDA9874A_SIC)))
+ sic = chip_read2(chip, TDA9874A_SIC);
+ if (sic < 0)
return 0;
v4l2_dbg(1, debug, sd, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
@@ -1201,7 +1241,11 @@ static int tda9875_checkit(struct CHIPSTATE *chip)
int dic, rev;
dic = chip_read2(chip, 254);
+ if (dic < 0)
+ return 0;
rev = chip_read2(chip, 255);
+ if (rev < 0)
+ return 0;
if (dic == 0 || dic == 2) { /* tda9875 and tda9875A */
v4l2_info(sd, "found tda9875%s rev. %d.\n",
@@ -1377,8 +1421,12 @@ static int ta8874z_getrxsubchans(struct CHIPSTATE *chip)
{
int val, mode;
- val = chip_read(chip);
mode = V4L2_TUNER_SUB_MONO;
+
+ val = chip_read(chip);
+ if (val < 0)
+ return mode;
+
if (val & TA8874Z_B1){
mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
}else if (!(val & TA8874Z_B0)){
@@ -1431,7 +1479,11 @@ static void ta8874z_setaudmode(struct CHIPSTATE *chip, int mode)
static int ta8874z_checkit(struct CHIPSTATE *chip)
{
int rc;
+
rc = chip_read(chip);
+ if (rc < 0)
+ return rc;
+
return ((rc & 0x1f) == 0x1f) ? 1 : 0;
}
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index 8b0aa9297bde..6a9890531d01 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -747,60 +747,47 @@ static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl)
}
/**
- * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm
+ * tvp514x_g_frame_interval() - V4L2 decoder interface handler
* @sd: pointer to standard V4L2 sub-device structure
- * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ * @ival: pointer to a v4l2_subdev_frame_interval structure
*
* Returns the decoder's video CAPTURE parameters.
*/
static int
-tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+tvp514x_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *ival)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
- struct v4l2_captureparm *cparm;
enum tvp514x_std current_std;
- if (a == NULL)
- return -EINVAL;
-
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- /* only capture is supported */
- return -EINVAL;
/* get the current standard */
current_std = decoder->current_std;
- cparm = &a->parm.capture;
- cparm->capability = V4L2_CAP_TIMEPERFRAME;
- cparm->timeperframe =
+ ival->interval =
decoder->std_list[current_std].standard.frameperiod;
return 0;
}
/**
- * tvp514x_s_parm() - V4L2 decoder interface handler for s_parm
+ * tvp514x_s_frame_interval() - V4L2 decoder interface handler
* @sd: pointer to standard V4L2 sub-device structure
- * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ * @ival: pointer to a v4l2_subdev_frame_interval structure
*
* Configures the decoder to use the input parameters, if possible. If
* not possible, returns the appropriate error code.
*/
static int
-tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+tvp514x_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *ival)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
struct v4l2_fract *timeperframe;
enum tvp514x_std current_std;
- if (a == NULL)
- return -EINVAL;
-
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- /* only capture is supported */
- return -EINVAL;
- timeperframe = &a->parm.capture.timeperframe;
+ timeperframe = &ival->interval;
/* get the current standard */
current_std = decoder->current_std;
@@ -961,8 +948,8 @@ static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
.s_std = tvp514x_s_std,
.s_routing = tvp514x_s_routing,
.querystd = tvp514x_querystd,
- .g_parm = tvp514x_g_parm,
- .s_parm = tvp514x_s_parm,
+ .g_frame_interval = tvp514x_g_frame_interval,
+ .s_frame_interval = tvp514x_s_frame_interval,
.s_stream = tvp514x_s_stream,
};
diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c
new file mode 100644
index 000000000000..a54548cc4285
--- /dev/null
+++ b/drivers/media/i2c/tw9910.c
@@ -0,0 +1,1027 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * tw9910 Video Driver
+ *
+ * Copyright (C) 2017 Jacopo Mondi <jacopo+renesas@jmondi.org>
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov772x driver,
+ *
+ * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/i2c/tw9910.h>
+#include <media/v4l2-subdev.h>
+
+#define GET_ID(val) ((val & 0xF8) >> 3)
+#define GET_REV(val) (val & 0x07)
+
+/*
+ * register offset
+ */
+#define ID 0x00 /* Product ID Code Register */
+#define STATUS1 0x01 /* Chip Status Register I */
+#define INFORM 0x02 /* Input Format */
+#define OPFORM 0x03 /* Output Format Control Register */
+#define DLYCTR 0x04 /* Hysteresis and HSYNC Delay Control */
+#define OUTCTR1 0x05 /* Output Control I */
+#define ACNTL1 0x06 /* Analog Control Register 1 */
+#define CROP_HI 0x07 /* Cropping Register, High */
+#define VDELAY_LO 0x08 /* Vertical Delay Register, Low */
+#define VACTIVE_LO 0x09 /* Vertical Active Register, Low */
+#define HDELAY_LO 0x0A /* Horizontal Delay Register, Low */
+#define HACTIVE_LO 0x0B /* Horizontal Active Register, Low */
+#define CNTRL1 0x0C /* Control Register I */
+#define VSCALE_LO 0x0D /* Vertical Scaling Register, Low */
+#define SCALE_HI 0x0E /* Scaling Register, High */
+#define HSCALE_LO 0x0F /* Horizontal Scaling Register, Low */
+#define BRIGHT 0x10 /* BRIGHTNESS Control Register */
+#define CONTRAST 0x11 /* CONTRAST Control Register */
+#define SHARPNESS 0x12 /* SHARPNESS Control Register I */
+#define SAT_U 0x13 /* Chroma (U) Gain Register */
+#define SAT_V 0x14 /* Chroma (V) Gain Register */
+#define HUE 0x15 /* Hue Control Register */
+#define CORING1 0x17
+#define CORING2 0x18 /* Coring and IF compensation */
+#define VBICNTL 0x19 /* VBI Control Register */
+#define ACNTL2 0x1A /* Analog Control 2 */
+#define OUTCTR2 0x1B /* Output Control 2 */
+#define SDT 0x1C /* Standard Selection */
+#define SDTR 0x1D /* Standard Recognition */
+#define TEST 0x1F /* Test Control Register */
+#define CLMPG 0x20 /* Clamping Gain */
+#define IAGC 0x21 /* Individual AGC Gain */
+#define AGCGAIN 0x22 /* AGC Gain */
+#define PEAKWT 0x23 /* White Peak Threshold */
+#define CLMPL 0x24 /* Clamp level */
+#define SYNCT 0x25 /* Sync Amplitude */
+#define MISSCNT 0x26 /* Sync Miss Count Register */
+#define PCLAMP 0x27 /* Clamp Position Register */
+#define VCNTL1 0x28 /* Vertical Control I */
+#define VCNTL2 0x29 /* Vertical Control II */
+#define CKILL 0x2A /* Color Killer Level Control */
+#define COMB 0x2B /* Comb Filter Control */
+#define LDLY 0x2C /* Luma Delay and H Filter Control */
+#define MISC1 0x2D /* Miscellaneous Control I */
+#define LOOP 0x2E /* LOOP Control Register */
+#define MISC2 0x2F /* Miscellaneous Control II */
+#define MVSN 0x30 /* Macrovision Detection */
+#define STATUS2 0x31 /* Chip STATUS II */
+#define HFREF 0x32 /* H monitor */
+#define CLMD 0x33 /* CLAMP MODE */
+#define IDCNTL 0x34 /* ID Detection Control */
+#define CLCNTL1 0x35 /* Clamp Control I */
+#define ANAPLLCTL 0x4C
+#define VBIMIN 0x4D
+#define HSLOWCTL 0x4E
+#define WSS3 0x4F
+#define FILLDATA 0x50
+#define SDID 0x51
+#define DID 0x52
+#define WSS1 0x53
+#define WSS2 0x54
+#define VVBI 0x55
+#define LCTL6 0x56
+#define LCTL7 0x57
+#define LCTL8 0x58
+#define LCTL9 0x59
+#define LCTL10 0x5A
+#define LCTL11 0x5B
+#define LCTL12 0x5C
+#define LCTL13 0x5D
+#define LCTL14 0x5E
+#define LCTL15 0x5F
+#define LCTL16 0x60
+#define LCTL17 0x61
+#define LCTL18 0x62
+#define LCTL19 0x63
+#define LCTL20 0x64
+#define LCTL21 0x65
+#define LCTL22 0x66
+#define LCTL23 0x67
+#define LCTL24 0x68
+#define LCTL25 0x69
+#define LCTL26 0x6A
+#define HSBEGIN 0x6B
+#define HSEND 0x6C
+#define OVSDLY 0x6D
+#define OVSEND 0x6E
+#define VBIDELAY 0x6F
+
+/*
+ * register detail
+ */
+
+/* INFORM */
+#define FC27_ON 0x40 /* 1 : Input crystal clock frequency is 27MHz */
+#define FC27_FF 0x00 /* 0 : Square pixel mode. */
+ /* Must use 24.54MHz for 60Hz field rate */
+ /* source or 29.5MHz for 50Hz field rate */
+#define IFSEL_S 0x10 /* 01 : S-video decoding */
+#define IFSEL_C 0x00 /* 00 : Composite video decoding */
+ /* Y input video selection */
+#define YSEL_M0 0x00 /* 00 : Mux0 selected */
+#define YSEL_M1 0x04 /* 01 : Mux1 selected */
+#define YSEL_M2 0x08 /* 10 : Mux2 selected */
+#define YSEL_M3 0x10 /* 11 : Mux3 selected */
+
+/* OPFORM */
+#define MODE 0x80 /* 0 : CCIR601 compatible YCrCb 4:2:2 format */
+ /* 1 : ITU-R-656 compatible data sequence format */
+#define LEN 0x40 /* 0 : 8-bit YCrCb 4:2:2 output format */
+ /* 1 : 16-bit YCrCb 4:2:2 output format.*/
+#define LLCMODE 0x20 /* 1 : LLC output mode. */
+ /* 0 : free-run output mode */
+#define AINC 0x10 /* Serial interface auto-indexing control */
+ /* 0 : auto-increment */
+ /* 1 : non-auto */
+#define VSCTL 0x08 /* 1 : Vertical out ctrl by DVALID */
+ /* 0 : Vertical out ctrl by HACTIVE and DVALID */
+#define OEN_TRI_SEL_MASK 0x07
+#define OEN_TRI_SEL_ALL_ON 0x00 /* Enable output for Rev0/Rev1 */
+#define OEN_TRI_SEL_ALL_OFF_r0 0x06 /* All tri-stated for Rev0 */
+#define OEN_TRI_SEL_ALL_OFF_r1 0x07 /* All tri-stated for Rev1 */
+
+/* OUTCTR1 */
+#define VSP_LO 0x00 /* 0 : VS pin output polarity is active low */
+#define VSP_HI 0x80 /* 1 : VS pin output polarity is active high. */
+ /* VS pin output control */
+#define VSSL_VSYNC 0x00 /* 0 : VSYNC */
+#define VSSL_VACT 0x10 /* 1 : VACT */
+#define VSSL_FIELD 0x20 /* 2 : FIELD */
+#define VSSL_VVALID 0x30 /* 3 : VVALID */
+#define VSSL_ZERO 0x70 /* 7 : 0 */
+#define HSP_LOW 0x00 /* 0 : HS pin output polarity is active low */
+#define HSP_HI 0x08 /* 1 : HS pin output polarity is active high.*/
+ /* HS pin output control */
+#define HSSL_HACT 0x00 /* 0 : HACT */
+#define HSSL_HSYNC 0x01 /* 1 : HSYNC */
+#define HSSL_DVALID 0x02 /* 2 : DVALID */
+#define HSSL_HLOCK 0x03 /* 3 : HLOCK */
+#define HSSL_ASYNCW 0x04 /* 4 : ASYNCW */
+#define HSSL_ZERO 0x07 /* 7 : 0 */
+
+/* ACNTL1 */
+#define SRESET 0x80 /* resets the device to its default state
+ * but all register content remain unchanged.
+ * This bit is self-resetting.
+ */
+#define ACNTL1_PDN_MASK 0x0e
+#define CLK_PDN 0x08 /* system clock power down */
+#define Y_PDN 0x04 /* Luma ADC power down */
+#define C_PDN 0x02 /* Chroma ADC power down */
+
+/* ACNTL2 */
+#define ACNTL2_PDN_MASK 0x40
+#define PLL_PDN 0x40 /* PLL power down */
+
+/* VBICNTL */
+
+/* RTSEL : control the real time signal output from the MPOUT pin */
+#define RTSEL_MASK 0x07
+#define RTSEL_VLOSS 0x00 /* 0000 = Video loss */
+#define RTSEL_HLOCK 0x01 /* 0001 = H-lock */
+#define RTSEL_SLOCK 0x02 /* 0010 = S-lock */
+#define RTSEL_VLOCK 0x03 /* 0011 = V-lock */
+#define RTSEL_MONO 0x04 /* 0100 = MONO */
+#define RTSEL_DET50 0x05 /* 0101 = DET50 */
+#define RTSEL_FIELD 0x06 /* 0110 = FIELD */
+#define RTSEL_RTCO 0x07 /* 0111 = RTCO ( Real Time Control ) */
+
+/* HSYNC start and end are constant for now */
+#define HSYNC_START 0x0260
+#define HSYNC_END 0x0300
+
+/*
+ * structure
+ */
+
+struct regval_list {
+ unsigned char reg_num;
+ unsigned char value;
+};
+
+struct tw9910_scale_ctrl {
+ char *name;
+ unsigned short width;
+ unsigned short height;
+ u16 hscale;
+ u16 vscale;
+};
+
+struct tw9910_priv {
+ struct v4l2_subdev subdev;
+ struct clk *clk;
+ struct tw9910_video_info *info;
+ struct gpio_desc *pdn_gpio;
+ struct gpio_desc *rstb_gpio;
+ const struct tw9910_scale_ctrl *scale;
+ v4l2_std_id norm;
+ u32 revision;
+};
+
+static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = {
+ {
+ .name = "NTSC SQ",
+ .width = 640,
+ .height = 480,
+ .hscale = 0x0100,
+ .vscale = 0x0100,
+ },
+ {
+ .name = "NTSC CCIR601",
+ .width = 720,
+ .height = 480,
+ .hscale = 0x0100,
+ .vscale = 0x0100,
+ },
+ {
+ .name = "NTSC SQ (CIF)",
+ .width = 320,
+ .height = 240,
+ .hscale = 0x0200,
+ .vscale = 0x0200,
+ },
+ {
+ .name = "NTSC CCIR601 (CIF)",
+ .width = 360,
+ .height = 240,
+ .hscale = 0x0200,
+ .vscale = 0x0200,
+ },
+ {
+ .name = "NTSC SQ (QCIF)",
+ .width = 160,
+ .height = 120,
+ .hscale = 0x0400,
+ .vscale = 0x0400,
+ },
+ {
+ .name = "NTSC CCIR601 (QCIF)",
+ .width = 180,
+ .height = 120,
+ .hscale = 0x0400,
+ .vscale = 0x0400,
+ },
+};
+
+static const struct tw9910_scale_ctrl tw9910_pal_scales[] = {
+ {
+ .name = "PAL SQ",
+ .width = 768,
+ .height = 576,
+ .hscale = 0x0100,
+ .vscale = 0x0100,
+ },
+ {
+ .name = "PAL CCIR601",
+ .width = 720,
+ .height = 576,
+ .hscale = 0x0100,
+ .vscale = 0x0100,
+ },
+ {
+ .name = "PAL SQ (CIF)",
+ .width = 384,
+ .height = 288,
+ .hscale = 0x0200,
+ .vscale = 0x0200,
+ },
+ {
+ .name = "PAL CCIR601 (CIF)",
+ .width = 360,
+ .height = 288,
+ .hscale = 0x0200,
+ .vscale = 0x0200,
+ },
+ {
+ .name = "PAL SQ (QCIF)",
+ .width = 192,
+ .height = 144,
+ .hscale = 0x0400,
+ .vscale = 0x0400,
+ },
+ {
+ .name = "PAL CCIR601 (QCIF)",
+ .width = 180,
+ .height = 144,
+ .hscale = 0x0400,
+ .vscale = 0x0400,
+ },
+};
+
+/*
+ * general function
+ */
+static struct tw9910_priv *to_tw9910(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct tw9910_priv,
+ subdev);
+}
+
+static int tw9910_mask_set(struct i2c_client *client, u8 command,
+ u8 mask, u8 set)
+{
+ s32 val = i2c_smbus_read_byte_data(client, command);
+
+ if (val < 0)
+ return val;
+
+ val &= ~mask;
+ val |= set & mask;
+
+ return i2c_smbus_write_byte_data(client, command, val);
+}
+
+static int tw9910_set_scale(struct i2c_client *client,
+ const struct tw9910_scale_ctrl *scale)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, SCALE_HI,
+ (scale->vscale & 0x0F00) >> 4 |
+ (scale->hscale & 0x0F00) >> 8);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, HSCALE_LO,
+ scale->hscale & 0x00FF);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, VSCALE_LO,
+ scale->vscale & 0x00FF);
+
+ return ret;
+}
+
+static int tw9910_set_hsync(struct i2c_client *client)
+{
+ struct tw9910_priv *priv = to_tw9910(client);
+ int ret;
+
+ /* bit 10 - 3 */
+ ret = i2c_smbus_write_byte_data(client, HSBEGIN,
+ (HSYNC_START & 0x07F8) >> 3);
+ if (ret < 0)
+ return ret;
+
+ /* bit 10 - 3 */
+ ret = i2c_smbus_write_byte_data(client, HSEND,
+ (HSYNC_END & 0x07F8) >> 3);
+ if (ret < 0)
+ return ret;
+
+ /* So far only revisions 0 and 1 have been seen. */
+ /* bit 2 - 0 */
+ if (priv->revision == 1)
+ ret = tw9910_mask_set(client, HSLOWCTL, 0x77,
+ (HSYNC_START & 0x0007) << 4 |
+ (HSYNC_END & 0x0007));
+
+ return ret;
+}
+
+static void tw9910_reset(struct i2c_client *client)
+{
+ tw9910_mask_set(client, ACNTL1, SRESET, SRESET);
+ usleep_range(1000, 5000);
+}
+
+static int tw9910_power(struct i2c_client *client, int enable)
+{
+ int ret;
+ u8 acntl1;
+ u8 acntl2;
+
+ if (enable) {
+ acntl1 = 0;
+ acntl2 = 0;
+ } else {
+ acntl1 = CLK_PDN | Y_PDN | C_PDN;
+ acntl2 = PLL_PDN;
+ }
+
+ ret = tw9910_mask_set(client, ACNTL1, ACNTL1_PDN_MASK, acntl1);
+ if (ret < 0)
+ return ret;
+
+ return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2);
+}
+
+static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm,
+ u32 width, u32 height)
+{
+ const struct tw9910_scale_ctrl *scale;
+ const struct tw9910_scale_ctrl *ret = NULL;
+ __u32 diff = 0xffffffff, tmp;
+ int size, i;
+
+ if (norm & V4L2_STD_NTSC) {
+ scale = tw9910_ntsc_scales;
+ size = ARRAY_SIZE(tw9910_ntsc_scales);
+ } else if (norm & V4L2_STD_PAL) {
+ scale = tw9910_pal_scales;
+ size = ARRAY_SIZE(tw9910_pal_scales);
+ } else {
+ return NULL;
+ }
+
+ for (i = 0; i < size; i++) {
+ tmp = abs(width - scale[i].width) +
+ abs(height - scale[i].height);
+ if (tmp < diff) {
+ diff = tmp;
+ ret = scale + i;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * subdevice operations
+ */
+static int tw9910_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+ u8 val;
+ int ret;
+
+ if (!enable) {
+ switch (priv->revision) {
+ case 0:
+ val = OEN_TRI_SEL_ALL_OFF_r0;
+ break;
+ case 1:
+ val = OEN_TRI_SEL_ALL_OFF_r1;
+ break;
+ default:
+ dev_err(&client->dev, "un-supported revision\n");
+ return -EINVAL;
+ }
+ } else {
+ val = OEN_TRI_SEL_ALL_ON;
+
+ if (!priv->scale) {
+ dev_err(&client->dev, "norm select error\n");
+ return -EPERM;
+ }
+
+ dev_dbg(&client->dev, "%s %dx%d\n",
+ priv->scale->name,
+ priv->scale->width,
+ priv->scale->height);
+ }
+
+ ret = tw9910_mask_set(client, OPFORM, OEN_TRI_SEL_MASK, val);
+ if (ret < 0)
+ return ret;
+
+ return tw9910_power(client, enable);
+}
+
+static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+
+ *norm = priv->norm;
+
+ return 0;
+}
+
+static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+ const unsigned int hact = 720;
+ const unsigned int hdelay = 15;
+ unsigned int vact;
+ unsigned int vdelay;
+ int ret;
+
+ if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL)))
+ return -EINVAL;
+
+ priv->norm = norm;
+ if (norm & V4L2_STD_525_60) {
+ vact = 240;
+ vdelay = 18;
+ ret = tw9910_mask_set(client, VVBI, 0x10, 0x10);
+ } else {
+ vact = 288;
+ vdelay = 24;
+ ret = tw9910_mask_set(client, VVBI, 0x10, 0x00);
+ }
+ if (!ret)
+ ret = i2c_smbus_write_byte_data(client, CROP_HI,
+ ((vdelay >> 2) & 0xc0) |
+ ((vact >> 4) & 0x30) |
+ ((hdelay >> 6) & 0x0c) |
+ ((hact >> 8) & 0x03));
+ if (!ret)
+ ret = i2c_smbus_write_byte_data(client, VDELAY_LO,
+ vdelay & 0xff);
+ if (!ret)
+ ret = i2c_smbus_write_byte_data(client, VACTIVE_LO,
+ vact & 0xff);
+
+ return ret;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int tw9910_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ if (reg->reg > 0xff)
+ return -EINVAL;
+
+ reg->size = 1;
+ ret = i2c_smbus_read_byte_data(client, reg->reg);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * ret = int
+ * reg->val = __u64
+ */
+ reg->val = (__u64)ret;
+
+ return 0;
+}
+
+static int tw9910_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->reg > 0xff ||
+ reg->val > 0xff)
+ return -EINVAL;
+
+ return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
+}
+#endif
+
+static int tw9910_power_on(struct tw9910_priv *priv)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
+ int ret;
+
+ if (priv->clk) {
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+ }
+
+ if (priv->pdn_gpio) {
+ gpiod_set_value(priv->pdn_gpio, 0);
+ usleep_range(500, 1000);
+ }
+
+ /*
+ * FIXME: The reset signal is connected to a shared GPIO on some
+ * platforms (namely the SuperH Migo-R). Until a framework becomes
+ * available to handle this cleanly, request the GPIO temporarily
+ * to avoid conflicts.
+ */
+ priv->rstb_gpio = gpiod_get_optional(&client->dev, "rstb",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(priv->rstb_gpio)) {
+ dev_info(&client->dev, "Unable to get GPIO \"rstb\"");
+ return PTR_ERR(priv->rstb_gpio);
+ }
+
+ if (priv->rstb_gpio) {
+ gpiod_set_value(priv->rstb_gpio, 1);
+ usleep_range(500, 1000);
+ gpiod_set_value(priv->rstb_gpio, 0);
+ usleep_range(500, 1000);
+
+ gpiod_put(priv->rstb_gpio);
+ }
+
+ return 0;
+}
+
+static int tw9910_power_off(struct tw9910_priv *priv)
+{
+ clk_disable_unprepare(priv->clk);
+
+ if (priv->pdn_gpio) {
+ gpiod_set_value(priv->pdn_gpio, 1);
+ usleep_range(500, 1000);
+ }
+
+ return 0;
+}
+
+static int tw9910_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+
+ return on ? tw9910_power_on(priv) : tw9910_power_off(priv);
+}
+
+static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+ int ret = -EINVAL;
+ u8 val;
+
+ /* Select suitable norm. */
+ priv->scale = tw9910_select_norm(priv->norm, *width, *height);
+ if (!priv->scale)
+ goto tw9910_set_fmt_error;
+
+ /* Reset hardware. */
+ tw9910_reset(client);
+
+ /* Set bus width. */
+ val = 0x00;
+ if (priv->info->buswidth == 16)
+ val = LEN;
+
+ ret = tw9910_mask_set(client, OPFORM, LEN, val);
+ if (ret < 0)
+ goto tw9910_set_fmt_error;
+
+ /* Select MPOUT behavior. */
+ switch (priv->info->mpout) {
+ case TW9910_MPO_VLOSS:
+ val = RTSEL_VLOSS; break;
+ case TW9910_MPO_HLOCK:
+ val = RTSEL_HLOCK; break;
+ case TW9910_MPO_SLOCK:
+ val = RTSEL_SLOCK; break;
+ case TW9910_MPO_VLOCK:
+ val = RTSEL_VLOCK; break;
+ case TW9910_MPO_MONO:
+ val = RTSEL_MONO; break;
+ case TW9910_MPO_DET50:
+ val = RTSEL_DET50; break;
+ case TW9910_MPO_FIELD:
+ val = RTSEL_FIELD; break;
+ case TW9910_MPO_RTCO:
+ val = RTSEL_RTCO; break;
+ default:
+ val = 0;
+ }
+
+ ret = tw9910_mask_set(client, VBICNTL, RTSEL_MASK, val);
+ if (ret < 0)
+ goto tw9910_set_fmt_error;
+
+ /* Set scale. */
+ ret = tw9910_set_scale(client, priv->scale);
+ if (ret < 0)
+ goto tw9910_set_fmt_error;
+
+ /* Set hsync. */
+ ret = tw9910_set_hsync(client);
+ if (ret < 0)
+ goto tw9910_set_fmt_error;
+
+ *width = priv->scale->width;
+ *height = priv->scale->height;
+
+ return ret;
+
+tw9910_set_fmt_error:
+
+ tw9910_reset(client);
+ priv->scale = NULL;
+
+ return ret;
+}
+
+static int tw9910_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+
+ 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;
+ if (priv->norm & V4L2_STD_NTSC) {
+ sel->r.width = 640;
+ sel->r.height = 480;
+ } else {
+ sel->r.width = 768;
+ sel->r.height = 576;
+ }
+
+ return 0;
+}
+
+static int tw9910_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct v4l2_mbus_framefmt *mf = &format->format;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+
+ if (format->pad)
+ return -EINVAL;
+
+ if (!priv->scale) {
+ priv->scale = tw9910_select_norm(priv->norm, 640, 480);
+ if (!priv->scale)
+ return -EINVAL;
+ }
+
+ mf->width = priv->scale->width;
+ mf->height = priv->scale->height;
+ mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ mf->field = V4L2_FIELD_INTERLACED_BT;
+
+ return 0;
+}
+
+static int tw9910_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ u32 width = mf->width, height = mf->height;
+ int ret;
+
+ WARN_ON(mf->field != V4L2_FIELD_ANY &&
+ mf->field != V4L2_FIELD_INTERLACED_BT);
+
+ /* Check color format. */
+ if (mf->code != MEDIA_BUS_FMT_UYVY8_2X8)
+ return -EINVAL;
+
+ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ ret = tw9910_set_frame(sd, &width, &height);
+ if (ret)
+ return ret;
+
+ mf->width = width;
+ mf->height = height;
+
+ return 0;
+}
+
+static int tw9910_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct v4l2_mbus_framefmt *mf = &format->format;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct tw9910_priv *priv = to_tw9910(client);
+ const struct tw9910_scale_ctrl *scale;
+
+ if (format->pad)
+ return -EINVAL;
+
+ if (mf->field == V4L2_FIELD_ANY) {
+ mf->field = V4L2_FIELD_INTERLACED_BT;
+ } else if (mf->field != V4L2_FIELD_INTERLACED_BT) {
+ dev_err(&client->dev, "Field type %d invalid\n", mf->field);
+ return -EINVAL;
+ }
+
+ mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ /* Select suitable norm. */
+ scale = tw9910_select_norm(priv->norm, mf->width, mf->height);
+ if (!scale)
+ return -EINVAL;
+
+ mf->width = scale->width;
+ mf->height = scale->height;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ return tw9910_s_fmt(sd, mf);
+
+ cfg->try_fmt = *mf;
+
+ return 0;
+}
+
+static int tw9910_video_probe(struct i2c_client *client)
+{
+ struct tw9910_priv *priv = to_tw9910(client);
+ s32 id;
+ int ret;
+
+ /* TW9910 only use 8 or 16 bit bus width. */
+ if (priv->info->buswidth != 16 && priv->info->buswidth != 8) {
+ dev_err(&client->dev, "bus width error\n");
+ return -ENODEV;
+ }
+
+ ret = tw9910_s_power(&priv->subdev, 1);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Check and show Product ID.
+ * So far only revisions 0 and 1 have been seen.
+ */
+ id = i2c_smbus_read_byte_data(client, ID);
+ priv->revision = GET_REV(id);
+ id = GET_ID(id);
+
+ if (id != 0x0b || priv->revision > 0x01) {
+ dev_err(&client->dev, "Product ID error %x:%x\n",
+ id, priv->revision);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ dev_info(&client->dev, "tw9910 Product ID %0x:%0x\n",
+ id, priv->revision);
+
+ priv->norm = V4L2_STD_NTSC;
+ priv->scale = &tw9910_ntsc_scales[0];
+
+done:
+ tw9910_s_power(&priv->subdev, 0);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = tw9910_g_register,
+ .s_register = tw9910_s_register,
+#endif
+ .s_power = tw9910_s_power,
+};
+
+static int tw9910_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 tw9910_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm)
+{
+ *norm = V4L2_STD_NTSC | V4L2_STD_PAL;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops tw9910_subdev_video_ops = {
+ .s_std = tw9910_s_std,
+ .g_std = tw9910_g_std,
+ .s_stream = tw9910_s_stream,
+ .g_tvnorms = tw9910_g_tvnorms,
+};
+
+static const struct v4l2_subdev_pad_ops tw9910_subdev_pad_ops = {
+ .enum_mbus_code = tw9910_enum_mbus_code,
+ .get_selection = tw9910_get_selection,
+ .get_fmt = tw9910_get_fmt,
+ .set_fmt = tw9910_set_fmt,
+};
+
+static const struct v4l2_subdev_ops tw9910_subdev_ops = {
+ .core = &tw9910_subdev_core_ops,
+ .video = &tw9910_subdev_video_ops,
+ .pad = &tw9910_subdev_pad_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+
+static int tw9910_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+
+{
+ struct tw9910_priv *priv;
+ struct tw9910_video_info *info;
+ struct i2c_adapter *adapter =
+ to_i2c_adapter(client->dev.parent);
+ int ret;
+
+ if (!client->dev.platform_data) {
+ dev_err(&client->dev, "TW9910: missing platform data!\n");
+ return -EINVAL;
+ }
+
+ info = client->dev.platform_data;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE_DATA\n");
+ return -EIO;
+ }
+
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->info = info;
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
+
+ priv->clk = clk_get(&client->dev, "xti");
+ if (PTR_ERR(priv->clk) == -ENOENT) {
+ priv->clk = NULL;
+ } else if (IS_ERR(priv->clk)) {
+ dev_err(&client->dev, "Unable to get xti clock\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ priv->pdn_gpio = gpiod_get_optional(&client->dev, "pdn",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->pdn_gpio)) {
+ dev_info(&client->dev, "Unable to get GPIO \"pdn\"");
+ ret = PTR_ERR(priv->pdn_gpio);
+ goto error_clk_put;
+ }
+
+ ret = tw9910_video_probe(client);
+ if (ret < 0)
+ goto error_gpio_put;
+
+ ret = v4l2_async_register_subdev(&priv->subdev);
+ if (ret)
+ goto error_gpio_put;
+
+ return ret;
+
+error_gpio_put:
+ if (priv->pdn_gpio)
+ gpiod_put(priv->pdn_gpio);
+error_clk_put:
+ clk_put(priv->clk);
+
+ return ret;
+}
+
+static int tw9910_remove(struct i2c_client *client)
+{
+ struct tw9910_priv *priv = to_tw9910(client);
+
+ if (priv->pdn_gpio)
+ gpiod_put(priv->pdn_gpio);
+ clk_put(priv->clk);
+ v4l2_device_unregister_subdev(&priv->subdev);
+
+ return 0;
+}
+
+static const struct i2c_device_id tw9910_id[] = {
+ { "tw9910", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tw9910_id);
+
+static struct i2c_driver tw9910_i2c_driver = {
+ .driver = {
+ .name = "tw9910",
+ },
+ .probe = tw9910_probe,
+ .remove = tw9910_remove,
+ .id_table = tw9910_id,
+};
+
+module_i2c_driver(tw9910_i2c_driver);
+
+MODULE_DESCRIPTION("V4L2 driver for TW9910 video decoder");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c
index 560738213c00..1658816a9844 100644
--- a/drivers/media/i2c/vs6624.c
+++ b/drivers/media/i2c/vs6624.c
@@ -657,31 +657,22 @@ static int vs6624_get_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int vs6624_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+static int vs6624_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *ival)
{
struct vs6624 *sensor = to_vs6624(sd);
- struct v4l2_captureparm *cp = &parms->parm.capture;
- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- memset(cp, 0, sizeof(*cp));
- cp->capability = V4L2_CAP_TIMEPERFRAME;
- cp->timeperframe.numerator = sensor->frame_rate.denominator;
- cp->timeperframe.denominator = sensor->frame_rate.numerator;
+ ival->interval.numerator = sensor->frame_rate.denominator;
+ ival->interval.denominator = sensor->frame_rate.numerator;
return 0;
}
-static int vs6624_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+static int vs6624_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *ival)
{
struct vs6624 *sensor = to_vs6624(sd);
- struct v4l2_captureparm *cp = &parms->parm.capture;
- struct v4l2_fract *tpf = &cp->timeperframe;
+ struct v4l2_fract *tpf = &ival->interval;
- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (cp->extendedmode != 0)
- return -EINVAL;
if (tpf->numerator == 0 || tpf->denominator == 0
|| (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) {
@@ -738,8 +729,8 @@ static const struct v4l2_subdev_core_ops vs6624_core_ops = {
};
static const struct v4l2_subdev_video_ops vs6624_video_ops = {
- .s_parm = vs6624_s_parm,
- .g_parm = vs6624_g_parm,
+ .s_frame_interval = vs6624_s_frame_interval,
+ .g_frame_interval = vs6624_g_frame_interval,
.s_stream = vs6624_s_stream,
};
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index e79f72b8b858..35e81f7c0d2f 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -190,6 +190,7 @@ static long media_device_enum_links(struct media_device *mdev,
ulink_desc++;
}
}
+ memset(links->reserved, 0, sizeof(links->reserved));
return 0;
}
@@ -218,6 +219,8 @@ static long media_device_setup_link(struct media_device *mdev,
if (link == NULL)
return -EINVAL;
+ memset(linkd->reserved, 0, sizeof(linkd->reserved));
+
/* Setup the link on both entities. */
return __media_entity_setup_link(link, linkd->flags);
}
@@ -255,7 +258,7 @@ static long media_device_get_topology(struct media_device *mdev,
memset(&kentity, 0, sizeof(kentity));
kentity.id = entity->graph_obj.id;
kentity.function = entity->function;
- strncpy(kentity.name, entity->name,
+ strlcpy(kentity.name, entity->name,
sizeof(kentity.name));
if (copy_to_user(uentity, &kentity, sizeof(kentity)))
@@ -263,6 +266,7 @@ static long media_device_get_topology(struct media_device *mdev,
uentity++;
}
topo->num_entities = i;
+ topo->reserved1 = 0;
/* Get interfaces and number of interfaces */
i = 0;
@@ -298,6 +302,7 @@ static long media_device_get_topology(struct media_device *mdev,
uintf++;
}
topo->num_interfaces = i;
+ topo->reserved2 = 0;
/* Get pads and number of pads */
i = 0;
@@ -324,6 +329,7 @@ static long media_device_get_topology(struct media_device *mdev,
upad++;
}
topo->num_pads = i;
+ topo->reserved3 = 0;
/* Get links and number of links */
i = 0;
@@ -355,6 +361,7 @@ static long media_device_get_topology(struct media_device *mdev,
ulink++;
}
topo->num_links = i;
+ topo->reserved4 = 0;
return ret;
}
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index f7c6d64e6031..3498551e618e 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -64,22 +64,6 @@ static inline const char *intf_type(struct media_interface *intf)
return "v4l-swradio";
case MEDIA_INTF_T_V4L_TOUCH:
return "v4l-touch";
- 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";
}
diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c
index da49c5567db5..08266b23826e 100644
--- a/drivers/media/pci/bt8xx/bttv-input.c
+++ b/drivers/media/pci/bt8xx/bttv-input.c
@@ -332,11 +332,15 @@ static void bttv_ir_stop(struct bttv *btv)
static int get_key_pv951(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
+ int rc;
unsigned char b;
/* poll IR chip */
- if (1 != i2c_master_recv(ir->c, &b, 1)) {
+ rc = i2c_master_recv(ir->c, &b, 1);
+ if (rc != 1) {
dprintk("read error\n");
+ if (rc < 0)
+ return rc;
return -EIO;
}
diff --git a/drivers/media/pci/cobalt/Makefile b/drivers/media/pci/cobalt/Makefile
index b328955abbd2..29eddff2f35f 100644
--- a/drivers/media/pci/cobalt/Makefile
+++ b/drivers/media/pci/cobalt/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
cobalt-objs := cobalt-driver.o cobalt-irq.o cobalt-v4l2.o \
cobalt-i2c.o cobalt-omnitek.o cobalt-flash.o cobalt-cpld.o \
cobalt-alsa-main.o cobalt-alsa-pcm.o
diff --git a/drivers/media/pci/cobalt/cobalt-alsa-main.c b/drivers/media/pci/cobalt/cobalt-alsa-main.c
index 720e3ad93a9e..e5022b620856 100644
--- a/drivers/media/pci/cobalt/cobalt-alsa-main.c
+++ b/drivers/media/pci/cobalt/cobalt-alsa-main.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ALSA interface to cobalt PCM capture streams
*
* Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/init.h>
diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c
index b69b258d39b9..f6a7df13cd04 100644
--- a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c
+++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ALSA PCM device for the
* ALSA interface to cobalt PCM capture streams
*
* Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/init.h>
diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.h b/drivers/media/pci/cobalt/cobalt-alsa-pcm.h
index 513fb1f71794..0e2e9c63a23e 100644
--- a/drivers/media/pci/cobalt/cobalt-alsa-pcm.h
+++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.h
@@ -1,22 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ALSA PCM device for the
* ALSA interface to cobalt PCM capture streams
*
* Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
int snd_cobalt_pcm_create(struct snd_cobalt_card *cobsc);
diff --git a/drivers/media/pci/cobalt/cobalt-alsa.h b/drivers/media/pci/cobalt/cobalt-alsa.h
index 08db699ced37..bb7f156ad3e7 100644
--- a/drivers/media/pci/cobalt/cobalt-alsa.h
+++ b/drivers/media/pci/cobalt/cobalt-alsa.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ALSA interface to cobalt PCM capture streams
*
* Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
struct snd_card;
diff --git a/drivers/media/pci/cobalt/cobalt-cpld.c b/drivers/media/pci/cobalt/cobalt-cpld.c
index bfcecef659e3..3d8026483ac3 100644
--- a/drivers/media/pci/cobalt/cobalt-cpld.c
+++ b/drivers/media/pci/cobalt/cobalt-cpld.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Cobalt CPLD functions
*
* Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/delay.h>
diff --git a/drivers/media/pci/cobalt/cobalt-cpld.h b/drivers/media/pci/cobalt/cobalt-cpld.h
index 0fc88fd5fa7b..8c880ed14cda 100644
--- a/drivers/media/pci/cobalt/cobalt-cpld.h
+++ b/drivers/media/pci/cobalt/cobalt-cpld.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Cobalt CPLD functions
*
* Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef COBALT_CPLD_H
diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c
index 3f16cf3f6d74..c8b1a6206c65 100644
--- a/drivers/media/pci/cobalt/cobalt-driver.c
+++ b/drivers/media/pci/cobalt/cobalt-driver.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cobalt driver initialization and card probing
*
@@ -5,19 +6,6 @@
*
* Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/delay.h>
diff --git a/drivers/media/pci/cobalt/cobalt-driver.h b/drivers/media/pci/cobalt/cobalt-driver.h
index 00f773ec359a..429bee4ef79c 100644
--- a/drivers/media/pci/cobalt/cobalt-driver.h
+++ b/drivers/media/pci/cobalt/cobalt-driver.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cobalt driver internal defines and structures
*
@@ -5,19 +6,6 @@
*
* Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef COBALT_DRIVER_H
diff --git a/drivers/media/pci/cobalt/cobalt-flash.c b/drivers/media/pci/cobalt/cobalt-flash.c
index 04dcaf9198d2..ef96e0f956d2 100644
--- a/drivers/media/pci/cobalt/cobalt-flash.c
+++ b/drivers/media/pci/cobalt/cobalt-flash.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Cobalt NOR flash functions
*
* Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/mtd/mtd.h>
diff --git a/drivers/media/pci/cobalt/cobalt-flash.h b/drivers/media/pci/cobalt/cobalt-flash.h
index 8077daea51cd..605ce3d37ca3 100644
--- a/drivers/media/pci/cobalt/cobalt-flash.h
+++ b/drivers/media/pci/cobalt/cobalt-flash.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Cobalt NOR flash functions
*
* Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef COBALT_FLASH_H
diff --git a/drivers/media/pci/cobalt/cobalt-i2c.c b/drivers/media/pci/cobalt/cobalt-i2c.c
index 1a5c55673ea8..c374dae78bf7 100644
--- a/drivers/media/pci/cobalt/cobalt-i2c.c
+++ b/drivers/media/pci/cobalt/cobalt-i2c.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cobalt I2C functions
*
@@ -5,19 +6,6 @@
*
* Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include "cobalt-driver.h"
diff --git a/drivers/media/pci/cobalt/cobalt-i2c.h b/drivers/media/pci/cobalt/cobalt-i2c.h
index a4c1cfaacf95..7a9057c8bff6 100644
--- a/drivers/media/pci/cobalt/cobalt-i2c.h
+++ b/drivers/media/pci/cobalt/cobalt-i2c.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cobalt I2C functions
*
@@ -5,19 +6,6 @@
*
* Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
/* init + register i2c algo-bit adapter */
diff --git a/drivers/media/pci/cobalt/cobalt-irq.c b/drivers/media/pci/cobalt/cobalt-irq.c
index b190d4f81c6e..04783e78cc12 100644
--- a/drivers/media/pci/cobalt/cobalt-irq.c
+++ b/drivers/media/pci/cobalt/cobalt-irq.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cobalt interrupt handling
*
* Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <media/i2c/adv7604.h>
diff --git a/drivers/media/pci/cobalt/cobalt-irq.h b/drivers/media/pci/cobalt/cobalt-irq.h
index 5119484a24d9..0b4078ce6555 100644
--- a/drivers/media/pci/cobalt/cobalt-irq.h
+++ b/drivers/media/pci/cobalt/cobalt-irq.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cobalt interrupt handling
*
* Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/interrupt.h>
diff --git a/drivers/media/pci/cobalt/cobalt-omnitek.c b/drivers/media/pci/cobalt/cobalt-omnitek.c
index a28a8482c1d4..4c137453e679 100644
--- a/drivers/media/pci/cobalt/cobalt-omnitek.c
+++ b/drivers/media/pci/cobalt/cobalt-omnitek.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Omnitek Scatter-Gather DMA Controller
*
* Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/string.h>
diff --git a/drivers/media/pci/cobalt/cobalt-omnitek.h b/drivers/media/pci/cobalt/cobalt-omnitek.h
index e5c6d032c6f2..129c5fccbe39 100644
--- a/drivers/media/pci/cobalt/cobalt-omnitek.h
+++ b/drivers/media/pci/cobalt/cobalt-omnitek.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Omnitek Scatter-Gather DMA Controller
*
* Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef COBALT_OMNITEK_H
diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c
index def4a3b37084..e2a4c705d353 100644
--- a/drivers/media/pci/cobalt/cobalt-v4l2.c
+++ b/drivers/media/pci/cobalt/cobalt-v4l2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* cobalt V4L2 API
*
@@ -5,19 +6,6 @@
*
* Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/dma-mapping.h>
diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.h b/drivers/media/pci/cobalt/cobalt-v4l2.h
index 62be553cd8e2..dc43974b2d86 100644
--- a/drivers/media/pci/cobalt/cobalt-v4l2.h
+++ b/drivers/media/pci/cobalt/cobalt-v4l2.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cobalt V4L2 API
*
* Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
int cobalt_nodes_register(struct cobalt *cobalt);
diff --git a/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h b/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h
index 9bc9ef1fd3a8..4c6ad1cee87e 100644
--- a/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h
+++ b/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef M00233_VIDEO_MEASURE_MEMMAP_PACKAGE_H
diff --git a/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h b/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h
index a480529f561e..6cc1ad7d98c9 100644
--- a/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h
+++ b/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef M00235_FDMA_PACKER_MEMMAP_PACKAGE_H
diff --git a/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h b/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h
index 602419e589d3..f0c6fe304247 100644
--- a/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h
+++ b/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef M00389_CVI_MEMMAP_PACKAGE_H
diff --git a/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h b/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h
index 95471c995067..27f05aca632f 100644
--- a/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h
+++ b/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef M00460_EVCNT_MEMMAP_PACKAGE_H
diff --git a/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h b/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h
index 384a3e156301..8a5bf008750a 100644
--- a/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h
+++ b/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef M00473_FREEWHEEL_MEMMAP_PACKAGE_H
diff --git a/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h b/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h
index 2a029026bf82..18bd4fcd2db8 100644
--- a/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h
+++ b/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef M00479_CLK_LOSS_DETECTOR_MEMMAP_PACKAGE_H
diff --git a/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h b/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h
index bdef2df5d689..86da49033cd8 100644
--- a/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h
+++ b/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef M00514_SYNCGEN_FLOW_EVCNT_MEMMAP_PACKAGE_H
diff --git a/drivers/media/pci/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c
index 2531e4b81b60..93443d1457c5 100644
--- a/drivers/media/pci/cx18/cx18-alsa-main.c
+++ b/drivers/media/pci/cx18/cx18-alsa-main.c
@@ -32,7 +32,6 @@
#include "cx18-driver.h"
#include "cx18-version.h"
#include "cx18-alsa.h"
-#include "cx18-alsa-mixer.h"
#include "cx18-alsa-pcm.h"
int cx18_alsa_debug;
diff --git a/drivers/media/pci/cx18/cx18-alsa-mixer.c b/drivers/media/pci/cx18/cx18-alsa-mixer.c
deleted file mode 100644
index cb04c3d820e2..000000000000
--- a/drivers/media/pci/cx18/cx18-alsa-mixer.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * ALSA mixer controls for the
- * ALSA interface to cx18 PCM capture streams
- *
- * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
- *
- * 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/kernel.h>
-#include <linux/device.h>
-#include <linux/spinlock.h>
-#include <linux/videodev2.h>
-
-#include <media/v4l2-device.h>
-
-#include <sound/core.h>
-#include <sound/control.h>
-#include <sound/tlv.h>
-
-#include "cx18-alsa.h"
-#include "cx18-driver.h"
-
-/*
- * Note the cx18-av-core volume scale is funny, due to the alignment of the
- * scale with another chip's range:
- *
- * v4l2_control value /512 indicated dB actual dB reg 0x8d4
- * 0x0000 - 0x01ff 0 -119 -96 228
- * 0x0200 - 0x02ff 1 -118 -96 228
- * ...
- * 0x2c00 - 0x2dff 22 -97 -96 228
- * 0x2e00 - 0x2fff 23 -96 -96 228
- * 0x3000 - 0x31ff 24 -95 -95 226
- * ...
- * 0xee00 - 0xefff 119 0 0 36
- * ...
- * 0xfe00 - 0xffff 127 +8 +8 20
- */
-static inline int dB_to_cx18_av_vol(int dB)
-{
- if (dB < -96)
- dB = -96;
- else if (dB > 8)
- dB = 8;
- return (dB + 119) << 9;
-}
-
-static inline int cx18_av_vol_to_dB(int v)
-{
- if (v < (23 << 9))
- v = (23 << 9);
- else if (v > (127 << 9))
- v = (127 << 9);
- return (v >> 9) - 119;
-}
-
-static int snd_cx18_mixer_tv_vol_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- /* We're already translating values, just keep this control in dB */
- uinfo->value.integer.min = -96;
- uinfo->value.integer.max = 8;
- uinfo->value.integer.step = 1;
- return 0;
-}
-
-static int snd_cx18_mixer_tv_vol_get(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *uctl)
-{
- struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl);
- struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
- struct v4l2_control vctrl;
- int ret;
-
- vctrl.id = V4L2_CID_AUDIO_VOLUME;
- vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
-
- snd_cx18_lock(cxsc);
- ret = v4l2_g_ctrl(cx->sd_av->ctrl_handler, &vctrl);
- snd_cx18_unlock(cxsc);
-
- if (!ret)
- uctl->value.integer.value[0] = cx18_av_vol_to_dB(vctrl.value);
- return ret;
-}
-
-static int snd_cx18_mixer_tv_vol_put(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *uctl)
-{
- struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl);
- struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
- struct v4l2_control vctrl;
- int ret;
-
- vctrl.id = V4L2_CID_AUDIO_VOLUME;
- vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
-
- snd_cx18_lock(cxsc);
-
- /* Fetch current state */
- ret = v4l2_g_ctrl(cx->sd_av->ctrl_handler, &vctrl);
-
- if (ret ||
- (cx18_av_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) {
-
- /* Set, if needed */
- vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
- ret = v4l2_s_ctrl(cx->sd_av->ctrl_handler, &vctrl);
- if (!ret)
- ret = 1; /* Indicate control was changed w/o error */
- }
- snd_cx18_unlock(cxsc);
-
- return ret;
-}
-
-
-/* This is a bit of overkill, the slider is already in dB internally */
-static DECLARE_TLV_DB_SCALE(snd_cx18_mixer_tv_vol_db_scale, -9600, 100, 0);
-
-static struct snd_kcontrol_new snd_cx18_mixer_tv_vol __initdata = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog TV Capture Volume",
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
- SNDRV_CTL_ELEM_ACCESS_TLV_READ,
- .info = snd_cx18_mixer_tv_volume_info,
- .get = snd_cx18_mixer_tv_volume_get,
- .put = snd_cx18_mixer_tv_volume_put,
- .tlv.p = snd_cx18_mixer_tv_vol_db_scale
-};
-
-/* FIXME - add mute switch and balance, bass, treble sliders:
- V4L2_CID_AUDIO_MUTE
-
- V4L2_CID_AUDIO_BALANCE
-
- V4L2_CID_AUDIO_BASS
- V4L2_CID_AUDIO_TREBLE
-*/
-
-/* FIXME - add stereo, lang1, lang2, mono menu */
-/* FIXME - add CS5345 I2S volume for HVR-1600 */
-
-int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc)
-{
- struct v4l2_device *v4l2_dev = cxsc->v4l2_dev;
- struct snd_card *sc = cxsc->sc;
- int ret;
-
- strlcpy(sc->mixername, "CX23418 Mixer", sizeof(sc->mixername));
-
- ret = snd_ctl_add(sc, snd_ctl_new1(&snd_cx18_mixer_tv_vol, cxsc));
- if (ret) {
- CX18_ALSA_WARN("%s: failed to add %s control, err %d\n",
- __func__, snd_cx18_mixer_tv_vol.name, ret);
- }
- return ret;
-}
diff --git a/drivers/media/pci/cx18/cx18-alsa-mixer.h b/drivers/media/pci/cx18/cx18-alsa-mixer.h
deleted file mode 100644
index 3aed123955dd..000000000000
--- a/drivers/media/pci/cx18/cx18-alsa-mixer.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * ALSA mixer controls for the
- * ALSA interface to cx18 PCM capture streams
- *
- * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
- *
- * 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.
- */
-
-int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc);
diff --git a/drivers/media/pci/cx18/cx18-dvb.c b/drivers/media/pci/cx18/cx18-dvb.c
index 53f4d6bf81fb..010f39eafce1 100644
--- a/drivers/media/pci/cx18/cx18-dvb.c
+++ b/drivers/media/pci/cx18/cx18-dvb.c
@@ -72,7 +72,7 @@ static struct s5h1409_config hauppauge_hvr1600_config = {
.qam_if = 44000,
.inversion = S5H1409_INVERSION_OFF,
.status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
.hvr1600_opt = S5H1409_HVR1600_OPTIMIZE
};
@@ -86,7 +86,7 @@ static struct s5h1411_config hcw_s5h1411_config = {
.qam_if = S5H1411_IF_4000,
.inversion = S5H1411_INVERSION_ON,
.status_mode = S5H1411_DEMODLOCKING,
- .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static struct tda18271_std_map hauppauge_tda18271_std_map = {
diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c
index d8c3637e492e..20b3cb17f97f 100644
--- a/drivers/media/pci/cx23885/cx23885-alsa.c
+++ b/drivers/media/pci/cx23885/cx23885-alsa.c
@@ -89,9 +89,8 @@ static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip, int nr_pages)
return -ENOMEM;
}
- dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n",
- (unsigned long)buf->vaddr,
- nr_pages << PAGE_SHIFT);
+ dprintk(1, "vmalloc is at addr %p, size=%d\n",
+ buf->vaddr, nr_pages << PAGE_SHIFT);
memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT);
buf->nr_pages = nr_pages;
diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c
index 3622521431f5..3a1c55187b2a 100644
--- a/drivers/media/pci/cx23885/cx23885-cards.c
+++ b/drivers/media/pci/cx23885/cx23885-cards.c
@@ -771,11 +771,46 @@ struct cx23885_board cx23885_boards[] = {
.portb = CX23885_MPEG_DVB,
.portc = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885] = {
+ .name = "Hauppauge WinTV-QuadHD-DVB(885)",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ },
[CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC] = {
.name = "Hauppauge WinTV-QuadHD-ATSC",
.portb = CX23885_MPEG_DVB,
.portc = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885] = {
+ .name = "Hauppauge WinTV-QuadHD-ATSC(885)",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1265_K4] = {
+ .name = "Hauppauge WinTV-HVR-1265(161111)",
+ .porta = CX23885_ANALOG_VIDEO,
+ .portc = CX23885_MPEG_DVB,
+ .tuner_type = TUNER_ABSENT,
+ .force_bff = 1,
+ .input = {{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN6_CH1,
+ .amux = CX25840_AUDIO7,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN8_CH1 |
+ CX25840_SVIDEO_ON,
+ .amux = CX25840_AUDIO7,
+ } },
+ },
+ [CX23885_BOARD_HAUPPAUGE_STARBURST2] = {
+ .name = "Hauppauge WinTV-Starburst2",
+ .portb = CX23885_MPEG_DVB,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -1028,6 +1063,10 @@ struct cx23885_subid cx23885_subids[] = {
.subdevice = 0x7133,
.card = CX23885_BOARD_HAUPPAUGE_IMPACTVCBE,
}, {
+ .subvendor = 0x0070,
+ .subdevice = 0x7137,
+ .card = CX23885_BOARD_HAUPPAUGE_IMPACTVCBE,
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xdb98,
.card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2,
@@ -1087,6 +1126,14 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x0070,
.subdevice = 0x6b18,
.card = CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC, /* Tuner Pair 2 */
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x2a18,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1265_K4, /* Hauppauge WinTV HVR-1265 (Model 161xx1, Hybrid ATSC/QAM-B) */
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0xf02a,
+ .card = CX23885_BOARD_HAUPPAUGE_STARBURST2,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1287,25 +1334,28 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
case 150329:
/* WinTV-HVR5525 (PCIe, DVB-S/S2, DVB-T/T2/C) */
break;
- case 166100:
+ case 161111:
+ /* WinTV-HVR-1265 K4 (PCIe, Analog/ATSC/QAM-B) */
+ break;
+ case 166100: /* 888 version, hybrid */
+ case 166200: /* 885 version, DVB only */
/* WinTV-QuadHD (DVB) Tuner Pair 1 (PCIe, IR, half height,
DVB-T/T2/C, DVB-T/T2/C */
break;
- case 166101:
+ case 166101: /* 888 version, hybrid */
+ case 166201: /* 885 version, DVB only */
/* WinTV-QuadHD (DVB) Tuner Pair 2 (PCIe, IR, half height,
DVB-T/T2/C, DVB-T/T2/C */
break;
- case 165100:
- /*
- * WinTV-QuadHD (ATSC) Tuner Pair 1 (PCIe, IR, half height,
- * ATSC, ATSC
- */
+ case 165100: /* 888 version, hybrid */
+ case 165200: /* 885 version, digital only */
+ /* WinTV-QuadHD (ATSC) Tuner Pair 1 (PCIe, IR, half height,
+ * ATSC/QAM-B, ATSC/QAM-B */
break;
- case 165101:
- /*
- * WinTV-QuadHD (DVB) Tuner Pair 2 (PCIe, IR, half height,
- * ATSC, ATSC
- */
+ case 165101: /* 888 version, hybrid */
+ case 165201: /* 885 version, digital only */
+ /* WinTV-QuadHD (ATSC) Tuner Pair 2 (PCIe, IR, half height,
+ * ATSC/QAM-B, ATSC/QAM-B */
break;
default:
pr_warn("%s: warning: unknown hauppauge model #%d\n",
@@ -1778,8 +1828,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
cx23885_gpio_set(dev, GPIO_2);
break;
case CX23885_BOARD_HAUPPAUGE_HVR5525:
- case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB:
- case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC:
+ case CX23885_BOARD_HAUPPAUGE_STARBURST2:
/*
* HVR5525 GPIO Details:
* GPIO-00 IR_WIDE
@@ -1809,6 +1858,22 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
* card does not have any GPIO's connected to subcomponents.
*/
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885:
+ /*
+ * GPIO-08 TER1_RESN
+ * GPIO-09 TER2_RESN
+ */
+ /* Put the parts into reset and back */
+ cx23885_gpio_enable(dev, GPIO_8 | GPIO_9, 1);
+ cx23885_gpio_clear(dev, GPIO_8 | GPIO_9);
+ msleep(100);
+ cx23885_gpio_set(dev, GPIO_8 | GPIO_9);
+ msleep(100);
+ break;
}
}
@@ -2054,8 +2119,12 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_STARBURST:
case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE:
case CX23885_BOARD_HAUPPAUGE_HVR5525:
+ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
+ case CX23885_BOARD_HAUPPAUGE_STARBURST2:
case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885:
case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885:
if (dev->i2c_bus[0].i2c_rc == 0)
hauppauge_eeprom(dev, eeprom+0xc0);
break;
@@ -2194,6 +2263,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
case CX23885_BOARD_HAUPPAUGE_HVR5525:
+ case CX23885_BOARD_HAUPPAUGE_STARBURST2:
ts1->gen_ctrl_val = 0x5; /* Parallel */
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
@@ -2201,8 +2271,11 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885:
case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885:
ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
@@ -2259,6 +2332,9 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
case CX23885_BOARD_HAUPPAUGE_HVR1255:
case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC:
case CX23885_BOARD_HAUPPAUGE_HVR1270:
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_MYGICA_X8506:
@@ -2286,6 +2362,10 @@ void cx23885_card_setup(struct cx23885_dev *dev)
&dev->i2c_bus[2].i2c_adap,
"cx25840", 0x88 >> 1, NULL);
if (dev->sd_cx25840) {
+ /* set host data for clk_freq configuration */
+ v4l2_set_subdev_hostdata(dev->sd_cx25840,
+ &dev->clk_freq);
+
dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE;
v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
}
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
index 8f63df1cb418..019fac49db5b 100644
--- a/drivers/media/pci/cx23885/cx23885-core.c
+++ b/drivers/media/pci/cx23885/cx23885-core.c
@@ -839,10 +839,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
/* Configure the internal memory */
if (dev->pci->device == 0x8880) {
- /* Could be 887 or 888, assume a default */
- dev->bridge = CX23885_BRIDGE_887;
+ /* Could be 887 or 888, assume an 888 default */
+ dev->bridge = CX23885_BRIDGE_888;
/* Apply a sensible clock frequency for the PCIe bridge */
- dev->clk_freq = 25000000;
+ dev->clk_freq = 50000000;
dev->sram_channels = cx23887_sram_channels;
} else
if (dev->pci->device == 0x8852) {
@@ -869,10 +869,28 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
cx23885_card_list(dev);
}
+ if (dev->pci->device == 0x8852) {
+ /* no DIF on cx23885, so no analog tuner support possible */
+ if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC)
+ dev->board = CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885;
+ else if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_DVB)
+ dev->board = CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885;
+ }
+
/* If the user specific a clk freq override, apply it */
if (cx23885_boards[dev->board].clk_freq > 0)
dev->clk_freq = cx23885_boards[dev->board].clk_freq;
+ if (dev->board == CX23885_BOARD_HAUPPAUGE_IMPACTVCBE &&
+ dev->pci->subsystem_device == 0x7137) {
+ /* Hauppauge ImpactVCBe device ID 0x7137 is populated
+ * with an 888, and a 25Mhz crystal, instead of the
+ * usual third overtone 50Mhz. The default clock rate must
+ * be overridden so the cx25840 is properly configured
+ */
+ dev->clk_freq = 25000000;
+ }
+
dev->pci_bus = dev->pci->bus->number;
dev->pci_slot = PCI_SLOT(dev->pci->devfn);
cx23885_irq_add(dev, 0x001f00);
@@ -965,7 +983,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
cx23885_i2c_register(&dev->i2c_bus[1]);
cx23885_i2c_register(&dev->i2c_bus[2]);
cx23885_card_setup(dev);
- call_all(dev, core, s_power, 0);
+ call_all(dev, tuner, standby);
cx23885_ir_init(dev);
if (dev->board == CX23885_BOARD_VIEWCAST_460E) {
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index 700422b538c0..114d9bcbe4f4 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -193,7 +193,7 @@ static struct s5h1409_config hauppauge_generic_config = {
.qam_if = 44000,
.inversion = S5H1409_INVERSION_OFF,
.status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static struct tda10048_config hauppauge_hvr1200_config = {
@@ -225,7 +225,7 @@ static struct s5h1409_config hauppauge_ezqam_config = {
.qam_if = 4000,
.inversion = S5H1409_INVERSION_ON,
.status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static struct s5h1409_config hauppauge_hvr1800lp_config = {
@@ -235,7 +235,7 @@ static struct s5h1409_config hauppauge_hvr1800lp_config = {
.qam_if = 44000,
.inversion = S5H1409_INVERSION_OFF,
.status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static struct s5h1409_config hauppauge_hvr1500_config = {
@@ -244,7 +244,7 @@ static struct s5h1409_config hauppauge_hvr1500_config = {
.gpio = S5H1409_GPIO_OFF,
.inversion = S5H1409_INVERSION_OFF,
.status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static struct mt2131_config hauppauge_generic_tunerconfig = {
@@ -264,7 +264,7 @@ static struct s5h1409_config hauppauge_hvr1500q_config = {
.qam_if = 44000,
.inversion = S5H1409_INVERSION_OFF,
.status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static struct s5h1409_config dvico_s5h1409_config = {
@@ -274,7 +274,7 @@ static struct s5h1409_config dvico_s5h1409_config = {
.qam_if = 44000,
.inversion = S5H1409_INVERSION_OFF,
.status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static struct s5h1411_config dvico_s5h1411_config = {
@@ -284,7 +284,7 @@ static struct s5h1411_config dvico_s5h1411_config = {
.vsb_if = S5H1411_IF_44000,
.inversion = S5H1411_INVERSION_OFF,
.status_mode = S5H1411_DEMODLOCKING,
- .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static struct s5h1411_config hcw_s5h1411_config = {
@@ -294,7 +294,7 @@ static struct s5h1411_config hcw_s5h1411_config = {
.qam_if = S5H1411_IF_4000,
.inversion = S5H1411_INVERSION_ON,
.status_mode = S5H1411_DEMODLOCKING,
- .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
@@ -930,6 +930,18 @@ static const struct m88ds3103_config hauppauge_hvr5525_m88ds3103_config = {
.agc = 0x99,
};
+static struct lgdt3306a_config hauppauge_hvr1265k4_config = {
+ .i2c_addr = 0x59,
+ .qam_if_khz = 4000,
+ .vsb_if_khz = 3250,
+ .deny_i2c_rptr = 1, /* Disabled */
+ .spectral_inversion = 0, /* Disabled */
+ .mpeg_mode = LGDT3306A_MPEG_SERIAL,
+ .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE,
+ .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH,
+ .xtalMHz = 25, /* 24 or 25 */
+};
+
static int netup_altera_fpga_rw(void *device, int flag, int data, int read)
{
struct cx23885_dev *dev = (struct cx23885_dev *)device;
@@ -1194,6 +1206,8 @@ static int dvb_register(struct cx23885_tsport *port)
struct si2157_config si2157_config;
struct ts2020_config ts2020_config;
struct m88ds3103_platform_data m88ds3103_pdata;
+ struct m88rs6000t_config m88rs6000t_config = {};
+ struct a8293_platform_data a8293_pdata = {};
struct i2c_board_info info;
struct i2c_adapter *adapter;
struct i2c_client *client_demod = NULL, *client_tuner = NULL;
@@ -2217,9 +2231,10 @@ static int dvb_register(struct cx23885_tsport *port)
}
port->i2c_client_tuner = client_tuner;
break;
- case CX23885_BOARD_HAUPPAUGE_HVR5525: {
- struct m88rs6000t_config m88rs6000t_config;
- struct a8293_platform_data a8293_pdata = {};
+ case CX23885_BOARD_HAUPPAUGE_STARBURST2:
+ case CX23885_BOARD_HAUPPAUGE_HVR5525:
+ i2c_bus = &dev->i2c_bus[0];
+ i2c_bus2 = &dev->i2c_bus[1];
switch (port->nr) {
@@ -2228,7 +2243,7 @@ static int dvb_register(struct cx23885_tsport *port)
/* attach frontend */
fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
&hauppauge_hvr5525_m88ds3103_config,
- &dev->i2c_bus[0].i2c_adap, &adapter);
+ &i2c_bus->i2c_adap, &adapter);
if (fe0->dvb.frontend == NULL)
break;
@@ -2239,7 +2254,7 @@ static int dvb_register(struct cx23885_tsport *port)
info.addr = 0x0b;
info.platform_data = &a8293_pdata;
request_module("a8293");
- client_sec = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info);
+ client_sec = i2c_new_device(&i2c_bus->i2c_adap, &info);
if (!client_sec || !client_sec->dev.driver)
goto frontend_detach;
if (!try_module_get(client_sec->dev.driver->owner)) {
@@ -2281,7 +2296,7 @@ static int dvb_register(struct cx23885_tsport *port)
info.addr = 0x64;
info.platform_data = &si2168_config;
request_module("%s", info.type);
- client_demod = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info);
+ client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
if (!client_demod || !client_demod->dev.driver)
goto frontend_detach;
if (!try_module_get(client_demod->dev.driver->owner)) {
@@ -2299,7 +2314,7 @@ static int dvb_register(struct cx23885_tsport *port)
info.addr = 0x60;
info.platform_data = &si2157_config;
request_module("%s", info.type);
- client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info);
+ client_tuner = i2c_new_device(&i2c_bus2->i2c_adap, &info);
if (!client_tuner || !client_tuner->dev.driver) {
module_put(client_demod->dev.driver->owner);
i2c_unregister_device(client_demod);
@@ -2317,8 +2332,10 @@ static int dvb_register(struct cx23885_tsport *port)
break;
}
break;
- }
case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885:
+ pr_info("%s(): board=%d port=%d\n", __func__,
+ dev->board, port->nr);
switch (port->nr) {
/* port b - Terrestrial/cable */
case 1:
@@ -2416,6 +2433,9 @@ static int dvb_register(struct cx23885_tsport *port)
}
break;
case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885:
+ pr_info("%s(): board=%d port=%d\n", __func__,
+ dev->board, port->nr);
switch (port->nr) {
/* port b - Terrestrial/cable */
case 1:
@@ -2490,7 +2510,41 @@ static int dvb_register(struct cx23885_tsport *port)
break;
}
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
+ switch (port->nr) {
+ /* port c - Terrestrial/cable */
+ case 2:
+ /* attach frontend */
+ i2c_bus = &dev->i2c_bus[0];
+ fe0->dvb.frontend = dvb_attach(lgdt3306a_attach,
+ &hauppauge_hvr1265k4_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend == NULL)
+ break;
+
+ /* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
+ si2157_config.fe = fe0->dvb.frontend;
+ si2157_config.if_port = 1;
+ si2157_config.inversion = 1;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &si2157_config;
+ request_module("%s", info.type);
+ client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info);
+ if (!client_tuner || !client_tuner->dev.driver)
+ goto frontend_detach;
+ if (!try_module_get(client_tuner->dev.driver->owner)) {
+ i2c_unregister_device(client_tuner);
+ client_tuner = NULL;
+ goto frontend_detach;
+ }
+ port->i2c_client_tuner = client_tuner;
+ break;
+ }
+ break;
default:
pr_info("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->name);
@@ -2514,8 +2568,8 @@ static int dvb_register(struct cx23885_tsport *port)
fe1->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl;
#endif
- /* Put the analog decoder in standby to keep it quiet */
- call_all(dev, core, s_power, 0);
+ /* Put the tuner in standby to keep it quiet */
+ call_all(dev, tuner, standby);
if (fe0->dvb.frontend->ops.analog_ops.standby)
fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
index 0f4e54294bb7..be49589a61d2 100644
--- a/drivers/media/pci/cx23885/cx23885-input.c
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -94,6 +94,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
case CX23885_BOARD_DVBSKY_S950:
case CX23885_BOARD_DVBSKY_S952:
case CX23885_BOARD_DVBSKY_T982:
+ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
/*
* The only boards we handle right now. However other boards
* using the CX2388x integrated IR controller should be similar
@@ -153,6 +154,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
case CX23885_BOARD_DVBSKY_S950:
case CX23885_BOARD_DVBSKY_S952:
case CX23885_BOARD_DVBSKY_T982:
+ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
/*
* The IR controller on this board only returns pulse widths.
* Any other mode setting will fail to set up the device.
@@ -283,6 +285,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
/* Integrated CX2388[58] IR controller */
allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER;
/* The grey Hauppauge RC-5 remote */
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index a03dcb662953..f8a3deadc77a 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -263,6 +263,7 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
(dev->board == CX23885_BOARD_HAUPPAUGE_IMPACTVCBE) ||
(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) ||
(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) ||
+ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1265_K4) ||
(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) ||
(dev->board == CX23885_BOARD_MYGICA_X8507) ||
(dev->board == CX23885_BOARD_AVERMEDIA_HC81R) ||
@@ -993,7 +994,8 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) ||
(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) ||
- (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111))
+ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) ||
+ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1265_K4))
fe = &dev->ts1.analog_fe;
if (fe && fe->ops.tuner_ops.set_analog_params) {
@@ -1022,6 +1024,7 @@ int cx23885_set_frequency(struct file *file, void *priv,
switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1255:
case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
+ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
case CX23885_BOARD_HAUPPAUGE_HVR1850:
ret = cx23885_set_freq_via_ops(dev, f);
break;
diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
index 2a17209eb4f6..d54c7ee1ab21 100644
--- a/drivers/media/pci/cx23885/cx23885.h
+++ b/drivers/media/pci/cx23885/cx23885.h
@@ -107,6 +107,10 @@
#define CX23885_BOARD_VIEWCAST_460E 55
#define CX23885_BOARD_HAUPPAUGE_QUADHD_DVB 56
#define CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC 57
+#define CX23885_BOARD_HAUPPAUGE_HVR1265_K4 58
+#define CX23885_BOARD_HAUPPAUGE_STARBURST2 59
+#define CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885 60
+#define CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885 61
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c
index 04aa4a68a0ae..040c6c251d3a 100644
--- a/drivers/media/pci/cx25821/cx25821-core.c
+++ b/drivers/media/pci/cx25821/cx25821-core.c
@@ -867,6 +867,10 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
dev->nr = ++cx25821_devcount;
sprintf(dev->name, "cx25821[%d]", dev->nr);
+ if (dev->nr >= ARRAY_SIZE(card)) {
+ CX25821_INFO("dev->nr >= %zd", ARRAY_SIZE(card));
+ return -ENODEV;
+ }
if (dev->pci->device != 0x8210) {
pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n",
__func__, dev->pci->device);
@@ -882,9 +886,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
dev->channels[i].sram_channels = &cx25821_sram_channels[i];
}
- if (dev->nr > 1)
- CX25821_INFO("dev->nr > 1!");
-
/* board config */
dev->board = 1; /* card[dev->nr]; */
dev->_max_num_decoders = MAX_DECODERS;
diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c
index 9740326bc93f..ab09bb55cf45 100644
--- a/drivers/media/pci/cx88/cx88-alsa.c
+++ b/drivers/media/pci/cx88/cx88-alsa.c
@@ -292,8 +292,8 @@ static int cx88_alsa_dma_init(struct cx88_audio_dev *chip, int nr_pages)
return -ENOMEM;
}
- dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n",
- (unsigned long)buf->vaddr, nr_pages << PAGE_SHIFT);
+ dprintk(1, "vmalloc is at addr %p, size=%d\n",
+ buf->vaddr, nr_pages << PAGE_SHIFT);
memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT);
buf->nr_pages = nr_pages;
@@ -656,8 +656,8 @@ static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol,
{
struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol);
struct cx88_core *core = chip->core;
- int left = value->value.integer.value[0];
- int right = value->value.integer.value[1];
+ u16 left = value->value.integer.value[0];
+ u16 right = value->value.integer.value[1];
int v, b;
/* Pass volume & balance onto any WM8775 */
diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c
index 6df21b29ea17..4c92d2388c26 100644
--- a/drivers/media/pci/cx88/cx88-cards.c
+++ b/drivers/media/pci/cx88/cx88-cards.c
@@ -3592,7 +3592,7 @@ static void cx88_card_setup(struct cx88_core *core)
ctl.fname);
call_all(core, tuner, s_config, &xc2028_cfg);
}
- call_all(core, core, s_power, 0);
+ call_all(core, tuner, standby);
}
/* ------------------------------------------------------------------ */
diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c
index 49a335f4603e..2f886140dd2e 100644
--- a/drivers/media/pci/cx88/cx88-dvb.c
+++ b/drivers/media/pci/cx88/cx88-dvb.c
@@ -558,7 +558,7 @@ static const struct s5h1409_config pinnacle_pctv_hd_800i_config = {
.qam_if = 44000,
.inversion = S5H1409_INVERSION_OFF,
.status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1409_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK,
};
static const struct s5h1409_config dvico_hdtv5_pci_nano_config = {
@@ -567,7 +567,7 @@ static const struct s5h1409_config dvico_hdtv5_pci_nano_config = {
.gpio = S5H1409_GPIO_OFF,
.inversion = S5H1409_INVERSION_OFF,
.status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static const struct s5h1409_config kworld_atsc_120_config = {
@@ -576,7 +576,7 @@ static const struct s5h1409_config kworld_atsc_120_config = {
.gpio = S5H1409_GPIO_OFF,
.inversion = S5H1409_INVERSION_OFF,
.status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static const struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
@@ -599,7 +599,7 @@ static const struct zl10353_config cx88_geniatech_x8000_mt = {
static const struct s5h1411_config dvico_fusionhdtv7_config = {
.output_mode = S5H1411_SERIAL_OUTPUT,
.gpio = S5H1411_GPIO_ON,
- .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
.qam_if = S5H1411_IF_44000,
.vsb_if = S5H1411_IF_44000,
.inversion = S5H1411_INVERSION_OFF,
@@ -1631,8 +1631,8 @@ static int dvb_register(struct cx8802_dev *dev)
if (fe1)
fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
- /* Put the analog decoder in standby to keep it quiet */
- call_all(core, core, s_power, 0);
+ /* Put the tuner in standby to keep it quiet */
+ call_all(core, tuner, standby);
/* register everything */
res = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index 4e9953e61a12..6f4e6923a91a 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -180,7 +180,7 @@ static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer)
struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer);
cx88_ir_handle_key(ir);
- missed = hrtimer_forward_now(&ir->timer, ir->polling * 1000000);
+ missed = hrtimer_forward_now(&ir->timer, ir->polling * 1000000LL);
if (missed > 1)
ir_dprintk("Missed ticks %ld\n", missed - 1);
@@ -200,7 +200,7 @@ static int __cx88_ir_start(void *priv)
if (ir->polling) {
hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ir->timer.function = cx88_ir_work;
- hrtimer_start(&ir->timer, ir->polling * 1000000,
+ hrtimer_start(&ir->timer, ir->polling * 1000000LL,
HRTIMER_MODE_REL);
}
if (ir->sampling) {
diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig
index f43d0b83fc0c..a422dde2f34a 100644
--- a/drivers/media/pci/ddbridge/Kconfig
+++ b/drivers/media/pci/ddbridge/Kconfig
@@ -13,6 +13,7 @@ config DVB_DDBRIDGE
select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT
select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT
---help---
Support for cards with the Digital Devices PCI express bridge:
- Octopus PCIe Bridge
diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile
index f58fdec50eab..745b37d07558 100644
--- a/drivers/media/pci/ddbridge/Makefile
+++ b/drivers/media/pci/ddbridge/Makefile
@@ -10,6 +10,3 @@ obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
ccflags-y += -Idrivers/media/dvb-frontends/
ccflags-y += -Idrivers/media/tuners/
-
-# For the staging CI driver cxd2099
-ccflags-y += -Idrivers/staging/media/cxd2099/
diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c
index 5828111487b0..a9dbc4ebf94f 100644
--- a/drivers/media/pci/ddbridge/ddbridge-ci.c
+++ b/drivers/media/pci/ddbridge/ddbridge-ci.c
@@ -172,6 +172,7 @@ static void ci_attach(struct ddb_port *port)
memcpy(&ci->en, &en_templ, sizeof(en_templ));
ci->en.data = ci;
port->en = &ci->en;
+ port->en_freedata = 1;
ci->port = port;
ci->nr = port->nr - 2;
}
@@ -304,6 +305,7 @@ static void ci_xo2_attach(struct ddb_port *port)
memcpy(&ci->en, &en_xo2_templ, sizeof(en_xo2_templ));
ci->en.data = ci;
port->en = &ci->en;
+ port->en_freedata = 1;
ci->port = port;
ci->nr = port->nr - 2;
ci->port->creg = 0;
@@ -311,38 +313,58 @@ static void ci_xo2_attach(struct ddb_port *port)
write_creg(ci, 0x08, 0x08);
}
-static struct cxd2099_cfg cxd_cfg = {
+static const struct cxd2099_cfg cxd_cfgtmpl = {
.bitrate = 72000,
- .adr = 0x40,
.polarity = 1,
.clock_mode = 1,
.max_i2c = 512,
};
+static int ci_cxd2099_attach(struct ddb_port *port, u32 bitrate)
+{
+ struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl;
+ struct i2c_client *client;
+
+ cxd_cfg.bitrate = bitrate;
+ cxd_cfg.en = &port->en;
+
+ client = dvb_module_probe("cxd2099", NULL, &port->i2c->adap,
+ 0x40, &cxd_cfg);
+ if (!client)
+ goto err;
+
+ port->dvb[0].i2c_client[0] = client;
+ port->en_freedata = 0;
+ return 0;
+
+err:
+ dev_err(port->dev->dev, "CXD2099AR attach failed\n");
+ return -ENODEV;
+}
+
int ddb_ci_attach(struct ddb_port *port, u32 bitrate)
{
+ int ret;
+
switch (port->type) {
case DDB_CI_EXTERNAL_SONY:
- cxd_cfg.bitrate = bitrate;
- port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap);
- if (!port->en)
+ ret = ci_cxd2099_attach(port, bitrate);
+ if (ret)
return -ENODEV;
break;
-
case DDB_CI_EXTERNAL_XO2:
case DDB_CI_EXTERNAL_XO2_B:
ci_xo2_attach(port);
- if (!port->en)
- return -ENODEV;
break;
-
case DDB_CI_INTERNAL:
ci_attach(port);
- if (!port->en)
- return -ENODEV;
break;
+ default:
+ return -ENODEV;
}
+ if (!port->en)
+ return -ENODEV;
dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1);
return 0;
}
@@ -353,7 +375,14 @@ void ddb_ci_detach(struct ddb_port *port)
dvb_unregister_device(port->dvb[0].dev);
if (port->en) {
dvb_ca_en50221_release(port->en);
- kfree(port->en->data);
+
+ dvb_module_release(port->dvb[0].i2c_client[0]);
+ port->dvb[0].i2c_client[0] = NULL;
+
+ /* free alloc'ed memory if needed */
+ if (port->en_freedata)
+ kfree(port->en->data);
+
port->en = NULL;
}
}
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index f9bee36f1cad..90687eff5909 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -999,37 +999,21 @@ static int tuner_attach_tda18212(struct ddb_input *input, u32 porttype)
.if_dvbt2_8 = 4000,
.if_dvbc = 5000,
};
- struct i2c_board_info board_info = {
- .type = "tda18212",
- .platform_data = &config,
- };
-
- if (input->nr & 1)
- board_info.addr = 0x63;
- else
- board_info.addr = 0x60;
+ u8 addr = (input->nr & 1) ? 0x63 : 0x60;
/* due to a hardware quirk with the I2C gate on the stv0367+tda18212
* combo, the tda18212 must be probed by reading it's id _twice_ when
* cold started, or it very likely will fail.
*/
if (porttype == DDB_TUNER_DVBCT_ST)
- tuner_tda18212_ping(input, board_info.addr);
-
- request_module(board_info.type);
-
- /* perform tuner init/attach */
- client = i2c_new_device(adapter, &board_info);
- if (!client || !client->dev.driver)
- goto err;
+ tuner_tda18212_ping(input, addr);
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
+ /* perform tuner probe/init/attach */
+ client = dvb_module_probe("tda18212", NULL, adapter, addr, &config);
+ if (!client)
goto err;
- }
dvb->i2c_client[0] = client;
-
return 0;
err:
dev_err(dev, "TDA18212 tuner not found. Device is not fully operational.\n");
@@ -1253,7 +1237,6 @@ static void dvb_input_detach(struct ddb_input *input)
{
struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
struct dvb_demux *dvbdemux = &dvb->demux;
- struct i2c_client *client;
switch (dvb->attached) {
case 0x31:
@@ -1263,13 +1246,8 @@ static void dvb_input_detach(struct ddb_input *input)
dvb_unregister_frontend(dvb->fe);
/* fallthrough */
case 0x30:
- client = dvb->i2c_client[0];
- if (client) {
- module_put(client->dev.driver->owner);
- i2c_unregister_device(client);
- dvb->i2c_client[0] = NULL;
- client = NULL;
- }
+ dvb_module_release(dvb->i2c_client[0]);
+ dvb->i2c_client[0] = NULL;
if (dvb->fe2)
dvb_frontend_detach(dvb->fe2);
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index 095457737bc1..f223dc6c9963 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -276,6 +276,7 @@ struct ddb_port {
struct ddb_input *input[2];
struct ddb_output *output;
struct dvb_ca_en50221 *en;
+ u8 en_freedata;
struct ddb_dvb dvb[2];
u32 gap;
u32 obr;
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
index 6c4444b31f4b..7d768ec0f824 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
@@ -1,14 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2017 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.
+ * Copyright (C) 2017 Intel Corporation
*
* Based partially on Intel IPU4 driver written by
* Sakari Ailus <sakari.ailus@linux.intel.com>
@@ -526,6 +518,8 @@ static void cio2_hw_exit(struct cio2_device *cio2, struct cio2_queue *q)
unsigned int i, maxloops = 1000;
/* Disable CSI receiver and MIPI backend devices */
+ writel(0, q->csi_rx_base + CIO2_REG_IRQCTRL_MASK);
+ writel(0, q->csi_rx_base + CIO2_REG_IRQCTRL_ENABLE);
writel(0, q->csi_rx_base + CIO2_REG_CSIRX_ENABLE);
writel(0, q->csi_rx_base + CIO2_REG_MIPIBE_ENABLE);
@@ -1035,6 +1029,7 @@ static void cio2_vb2_stop_streaming(struct vb2_queue *vq)
"failed to stop sensor streaming\n");
cio2_hw_exit(cio2, q);
+ synchronize_irq(cio2->pci_dev->irq);
cio2_vb2_return_all_buffers(q, VB2_BUF_STATE_ERROR);
media_pipeline_stop(&q->vdev.entity);
pm_runtime_put(&cio2->pci_dev->dev);
@@ -1976,6 +1971,7 @@ static int __maybe_unused cio2_suspend(struct device *dev)
/* Stop stream */
cio2_hw_exit(cio2, q);
+ synchronize_irq(pci_dev->irq);
pm_runtime_force_suspend(dev);
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
index 78a5799f08e7..240635be7a31 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
@@ -1,15 +1,5 @@
-/*
- * Copyright (c) 2017 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.
- */
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2017 Intel Corporation */
#ifndef __IPU3_CIO2_H
#define __IPU3_CIO2_H
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-main.c b/drivers/media/pci/ivtv/ivtv-alsa-main.c
index 029f52733f70..c1856f609d2c 100644
--- a/drivers/media/pci/ivtv/ivtv-alsa-main.c
+++ b/drivers/media/pci/ivtv/ivtv-alsa-main.c
@@ -20,7 +20,6 @@
#include "ivtv-driver.h"
#include "ivtv-version.h"
#include "ivtv-alsa.h"
-#include "ivtv-alsa-mixer.h"
#include "ivtv-alsa-pcm.h"
#include <sound/core.h>
@@ -160,15 +159,7 @@ static int snd_ivtv_init(struct v4l2_device *v4l2_dev)
/* (4) Set the driver ID and name strings */
snd_ivtv_card_set_names(itvsc);
- /* (5) Create other components: mixer, PCM, & proc files */
-#if 0
- ret = snd_ivtv_mixer_create(itvsc);
- if (ret) {
- IVTV_ALSA_WARN("%s: snd_ivtv_mixer_create() failed with err %d: proceeding anyway\n",
- __func__, ret);
- }
-#endif
-
+ /* (5) Create other components: PCM, & proc files */
ret = snd_ivtv_pcm_create(itvsc);
if (ret) {
IVTV_ALSA_ERR("%s: snd_ivtv_pcm_create() failed with err %d\n",
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-mixer.c b/drivers/media/pci/ivtv/ivtv-alsa-mixer.c
deleted file mode 100644
index aee453fcff37..000000000000
--- a/drivers/media/pci/ivtv/ivtv-alsa-mixer.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * ALSA mixer controls for the
- * ALSA interface to ivtv PCM capture streams
- *
- * Copyright (C) 2009,2012 Andy Walls <awalls@md.metrocast.net>
- *
- * 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 "ivtv-alsa.h"
-#include "ivtv-alsa-mixer.h"
-#include "ivtv-driver.h"
-
-#include <linux/videodev2.h>
-
-#include <sound/core.h>
-#include <sound/control.h>
-#include <sound/tlv.h>
-
-/*
- * Note the cx25840-core volume scale is funny, due to the alignment of the
- * scale with another chip's range:
- *
- * v4l2_control value /512 indicated dB actual dB reg 0x8d4
- * 0x0000 - 0x01ff 0 -119 -96 228
- * 0x0200 - 0x02ff 1 -118 -96 228
- * ...
- * 0x2c00 - 0x2dff 22 -97 -96 228
- * 0x2e00 - 0x2fff 23 -96 -96 228
- * 0x3000 - 0x31ff 24 -95 -95 226
- * ...
- * 0xee00 - 0xefff 119 0 0 36
- * ...
- * 0xfe00 - 0xffff 127 +8 +8 20
- */
-static inline int dB_to_cx25840_vol(int dB)
-{
- if (dB < -96)
- dB = -96;
- else if (dB > 8)
- dB = 8;
- return (dB + 119) << 9;
-}
-
-static inline int cx25840_vol_to_dB(int v)
-{
- if (v < (23 << 9))
- v = (23 << 9);
- else if (v > (127 << 9))
- v = (127 << 9);
- return (v >> 9) - 119;
-}
-
-static int snd_ivtv_mixer_tv_vol_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- /* We're already translating values, just keep this control in dB */
- uinfo->value.integer.min = -96;
- uinfo->value.integer.max = 8;
- uinfo->value.integer.step = 1;
- return 0;
-}
-
-static int snd_ivtv_mixer_tv_vol_get(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *uctl)
-{
- struct snd_ivtv_card *itvsc = snd_kcontrol_chip(kctl);
- struct ivtv *itv = to_ivtv(itvsc->v4l2_dev);
- struct v4l2_control vctrl;
- int ret;
-
- vctrl.id = V4L2_CID_AUDIO_VOLUME;
- vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]);
-
- snd_ivtv_lock(itvsc);
- ret = v4l2_g_ctrl(itv->sd_audio->ctrl_handler, &vctrl);
- snd_ivtv_unlock(itvsc);
-
- if (!ret)
- uctl->value.integer.value[0] = cx25840_vol_to_dB(vctrl.value);
- return ret;
-}
-
-static int snd_ivtv_mixer_tv_vol_put(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *uctl)
-{
- struct snd_ivtv_card *itvsc = snd_kcontrol_chip(kctl);
- struct ivtv *itv = to_ivtv(itvsc->v4l2_dev);
- struct v4l2_control vctrl;
- int ret;
-
- vctrl.id = V4L2_CID_AUDIO_VOLUME;
- vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]);
-
- snd_ivtv_lock(itvsc);
-
- /* Fetch current state */
- ret = v4l2_g_ctrl(itv->sd_audio->ctrl_handler, &vctrl);
-
- if (ret ||
- (cx25840_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) {
-
- /* Set, if needed */
- vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]);
- ret = v4l2_s_ctrl(itv->sd_audio->ctrl_handler, &vctrl);
- if (!ret)
- ret = 1; /* Indicate control was changed w/o error */
- }
- snd_ivtv_unlock(itvsc);
-
- return ret;
-}
-
-
-/* This is a bit of overkill, the slider is already in dB internally */
-static DECLARE_TLV_DB_SCALE(snd_ivtv_mixer_tv_vol_db_scale, -9600, 100, 0);
-
-static struct snd_kcontrol_new snd_ivtv_mixer_tv_vol __initdata = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog TV Capture Volume",
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
- SNDRV_CTL_ELEM_ACCESS_TLV_READ,
- .info = snd_ivtv_mixer_tv_volume_info,
- .get = snd_ivtv_mixer_tv_volume_get,
- .put = snd_ivtv_mixer_tv_volume_put,
- .tlv.p = snd_ivtv_mixer_tv_vol_db_scale
-};
-
-/* FIXME - add mute switch and balance, bass, treble sliders:
- V4L2_CID_AUDIO_MUTE
-
- V4L2_CID_AUDIO_BALANCE
-
- V4L2_CID_AUDIO_BASS
- V4L2_CID_AUDIO_TREBLE
-*/
-
-/* FIXME - add stereo, lang1, lang2, mono menu */
-/* FIXME - add I2S volume */
-
-int __init snd_ivtv_mixer_create(struct snd_ivtv_card *itvsc)
-{
- struct v4l2_device *v4l2_dev = itvsc->v4l2_dev;
- struct snd_card *sc = itvsc->sc;
- int ret;
-
- strlcpy(sc->mixername, "CX2341[56] Mixer", sizeof(sc->mixername));
-
- ret = snd_ctl_add(sc, snd_ctl_new1(&snd_ivtv_mixer_tv_vol, itvsc));
- if (ret) {
- IVTV_ALSA_WARN("%s: failed to add %s control, err %d\n",
- __func__, snd_ivtv_mixer_tv_vol.name, ret);
- }
- return ret;
-}
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-mixer.h b/drivers/media/pci/ivtv/ivtv-alsa-mixer.h
deleted file mode 100644
index 382bc36bc529..000000000000
--- a/drivers/media/pci/ivtv/ivtv-alsa-mixer.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * ALSA mixer controls for the
- * ALSA interface to ivtv PCM capture streams
- *
- * Copyright (C) 2009,2012 Andy Walls <awalls@md.metrocast.net>
- *
- * 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.
- */
-
-int __init snd_ivtv_mixer_create(struct snd_ivtv_card *itvsc);
diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c
index 621b2f613d81..8e62b8be6529 100644
--- a/drivers/media/pci/ivtv/ivtvfb.c
+++ b/drivers/media/pci/ivtv/ivtvfb.c
@@ -346,8 +346,8 @@ static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
/* Not fatal, but will have undesirable results */
if ((unsigned long)source & 3)
- IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
- (unsigned long)source);
+ IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (%p)\n",
+ source);
if (dest_offset & 3)
IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
@@ -357,12 +357,10 @@ static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
/* Check Source */
if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
- IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
- (unsigned long)source);
+ IVTVFB_WARN("Invalid userspace pointer %p\n", source);
- IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
- dest_offset, (unsigned long)source,
- count);
+ IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source %p count %d\n",
+ dest_offset, source, count);
return -EINVAL;
}
diff --git a/drivers/media/pci/mantis/mantis_vp3028.c b/drivers/media/pci/mantis/mantis_vp3028.c
deleted file mode 100644
index 4155c838a18a..000000000000
--- a/drivers/media/pci/mantis/mantis_vp3028.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- Mantis VP-3028 driver
-
- Copyright (C) Manu Abraham (abraham.manu@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.
-
- 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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "mantis_common.h"
-#include "mantis_vp3028.h"
-
-struct zl10353_config mantis_vp3028_config = {
- .demod_address = 0x0f,
-};
-
-#define MANTIS_MODEL_NAME "VP-3028"
-#define MANTIS_DEV_TYPE "DVB-T"
-
-struct mantis_hwconfig vp3028_mantis_config = {
- .model_name = MANTIS_MODEL_NAME,
- .dev_type = MANTIS_DEV_TYPE,
- .ts_size = MANTIS_TS_188,
- .baud_rate = MANTIS_BAUD_9600,
- .parity = MANTIS_PARITY_NONE,
- .bytes = 0,
-};
diff --git a/drivers/media/pci/mantis/mantis_vp3028.h b/drivers/media/pci/mantis/mantis_vp3028.h
deleted file mode 100644
index 34130d29e0aa..000000000000
--- a/drivers/media/pci/mantis/mantis_vp3028.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- Mantis VP-3028 driver
-
- Copyright (C) Manu Abraham (abraham.manu@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.
-
- 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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MANTIS_VP3028_H
-#define __MANTIS_VP3028_H
-
-#include <media/dvb_frontend.h>
-#include "mantis_common.h"
-#include "zl10353.h"
-
-#define MANTIS_VP_3028_DVB_T 0x0028
-
-extern struct zl10353_config mantis_vp3028_config;
-extern struct mantis_hwconfig vp3028_mantis_config;
-
-#endif /* __MANTIS_VP3028_H */
diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig
index 637d506b23c5..e06d019996f3 100644
--- a/drivers/media/pci/ngene/Kconfig
+++ b/drivers/media/pci/ngene/Kconfig
@@ -8,6 +8,13 @@ config DVB_NGENE
select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV0910 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_STV6111 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT
---help---
Support for Micronas PCI express cards with nGene bridge.
diff --git a/drivers/media/pci/ngene/Makefile b/drivers/media/pci/ngene/Makefile
index e4208f5ed215..ec450ad19281 100644
--- a/drivers/media/pci/ngene/Makefile
+++ b/drivers/media/pci/ngene/Makefile
@@ -9,6 +9,3 @@ obj-$(CONFIG_DVB_NGENE) += ngene.o
ccflags-y += -Idrivers/media/dvb-frontends/
ccflags-y += -Idrivers/media/tuners/
-
-# For the staging CI driver cxd2099
-ccflags-y += -Idrivers/staging/media/cxd2099/
diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c
index bb49620540c5..65fc8f23ad86 100644
--- a/drivers/media/pci/ngene/ngene-cards.c
+++ b/drivers/media/pci/ngene/ngene-cards.c
@@ -23,6 +23,8 @@
* http://www.gnu.org/copyleft/gpl.html
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
@@ -40,22 +42,101 @@
#include "drxk.h"
#include "drxd.h"
#include "dvb-pll.h"
+#include "stv0367.h"
+#include "stv0367_priv.h"
+#include "tda18212.h"
+#include "cxd2841er.h"
+#include "stv0910.h"
+#include "stv6111.h"
+#include "lnbh25.h"
+
+/****************************************************************************/
+/* I2C transfer functions used for demod/tuner probing***********************/
+/****************************************************************************/
+
+static int i2c_io(struct i2c_adapter *adapter, u8 adr,
+ u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen)
+{
+ struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+ .buf = wbuf, .len = wlen },
+ {.addr = adr, .flags = I2C_M_RD,
+ .buf = rbuf, .len = rlen } };
+ return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+}
+
+static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
+{
+ struct i2c_msg msg = {.addr = adr, .flags = 0,
+ .buf = data, .len = len};
+
+ return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1;
+}
+
+static int i2c_write_reg(struct i2c_adapter *adap, u8 adr,
+ u8 reg, u8 val)
+{
+ u8 msg[2] = {reg, val};
+
+ return i2c_write(adap, adr, msg, 2);
+}
+
+static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
+{
+ struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD,
+ .buf = val, .len = 1 } };
+ return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
+}
+
+static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
+ u16 reg, u8 *val)
+{
+ u8 msg[2] = {reg >> 8, reg & 0xff};
+ struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+ .buf = msg, .len = 2},
+ {.addr = adr, .flags = I2C_M_RD,
+ .buf = val, .len = 1} };
+ return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+}
+static int i2c_read_regs(struct i2c_adapter *adapter,
+ u8 adr, u8 reg, u8 *val, u8 len)
+{
+ struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+ .buf = &reg, .len = 1},
+ {.addr = adr, .flags = I2C_M_RD,
+ .buf = val, .len = len} };
+
+ return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+}
+
+static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val)
+{
+ return i2c_read_regs(adapter, adr, reg, val, 1);
+}
/****************************************************************************/
/* Demod/tuner attachment ***************************************************/
/****************************************************************************/
+static struct i2c_adapter *i2c_adapter_from_chan(struct ngene_channel *chan)
+{
+ /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
+ if (chan->number < 2)
+ return &chan->dev->channel[0].i2c_adapter;
+
+ return &chan->dev->channel[1].i2c_adapter;
+}
+
static int tuner_attach_stv6110(struct ngene_channel *chan)
{
- struct i2c_adapter *i2c;
+ struct device *pdev = &chan->dev->pci_dev->dev;
+ struct i2c_adapter *i2c = i2c_adapter_from_chan(chan);
struct stv090x_config *feconf = (struct stv090x_config *)
chan->dev->card_info->fe_config[chan->number];
struct stv6110x_config *tunerconf = (struct stv6110x_config *)
chan->dev->card_info->tuner_config[chan->number];
const struct stv6110x_devctl *ctl;
- /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
if (chan->number < 2)
i2c = &chan->dev->channel[0].i2c_adapter;
else
@@ -63,7 +144,7 @@ static int tuner_attach_stv6110(struct ngene_channel *chan)
ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c);
if (ctl == NULL) {
- printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n");
+ dev_err(pdev, "No STV6110X found!\n");
return -ENODEV;
}
@@ -82,6 +163,23 @@ static int tuner_attach_stv6110(struct ngene_channel *chan)
return 0;
}
+static int tuner_attach_stv6111(struct ngene_channel *chan)
+{
+ struct device *pdev = &chan->dev->pci_dev->dev;
+ struct i2c_adapter *i2c = i2c_adapter_from_chan(chan);
+ struct dvb_frontend *fe;
+ u8 adr = 4 + ((chan->number & 1) ? 0x63 : 0x60);
+
+ fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr);
+ if (!fe) {
+ fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr & ~4);
+ if (!fe) {
+ dev_err(pdev, "stv6111_attach() failed!\n");
+ return -ENODEV;
+ }
+ }
+ return 0;
+}
static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
{
@@ -100,35 +198,109 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
static int tuner_attach_tda18271(struct ngene_channel *chan)
{
- struct i2c_adapter *i2c;
+ struct device *pdev = &chan->dev->pci_dev->dev;
+ struct i2c_adapter *i2c = i2c_adapter_from_chan(chan);
struct dvb_frontend *fe;
- i2c = &chan->dev->channel[0].i2c_adapter;
if (chan->fe->ops.i2c_gate_ctrl)
chan->fe->ops.i2c_gate_ctrl(chan->fe, 1);
fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60);
if (chan->fe->ops.i2c_gate_ctrl)
chan->fe->ops.i2c_gate_ctrl(chan->fe, 0);
if (!fe) {
- printk(KERN_ERR "No TDA18271 found!\n");
+ dev_err(pdev, "No TDA18271 found!\n");
return -ENODEV;
}
return 0;
}
+static int tuner_tda18212_ping(struct ngene_channel *chan,
+ struct i2c_adapter *i2c,
+ unsigned short adr)
+{
+ struct device *pdev = &chan->dev->pci_dev->dev;
+ u8 tda_id[2];
+ u8 subaddr = 0x00;
+
+ dev_dbg(pdev, "stv0367-tda18212 tuner ping\n");
+ if (chan->fe->ops.i2c_gate_ctrl)
+ chan->fe->ops.i2c_gate_ctrl(chan->fe, 1);
+
+ if (i2c_read_regs(i2c, adr, subaddr, tda_id, sizeof(tda_id)) < 0)
+ dev_dbg(pdev, "tda18212 ping 1 fail\n");
+ if (i2c_read_regs(i2c, adr, subaddr, tda_id, sizeof(tda_id)) < 0)
+ dev_warn(pdev, "tda18212 ping failed, expect problems\n");
+
+ if (chan->fe->ops.i2c_gate_ctrl)
+ chan->fe->ops.i2c_gate_ctrl(chan->fe, 0);
+
+ return 0;
+}
+
+static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype)
+{
+ struct device *pdev = &chan->dev->pci_dev->dev;
+ struct i2c_adapter *i2c = i2c_adapter_from_chan(chan);
+ struct i2c_client *client;
+ struct tda18212_config config = {
+ .fe = chan->fe,
+ .if_dvbt_6 = 3550,
+ .if_dvbt_7 = 3700,
+ .if_dvbt_8 = 4150,
+ .if_dvbt2_6 = 3250,
+ .if_dvbt2_7 = 4000,
+ .if_dvbt2_8 = 4000,
+ .if_dvbc = 5000,
+ };
+ u8 addr = (chan->number & 1) ? 0x63 : 0x60;
+
+ /*
+ * due to a hardware quirk with the I2C gate on the stv0367+tda18212
+ * combo, the tda18212 must be probed by reading it's id _twice_ when
+ * cold started, or it very likely will fail.
+ */
+ if (dmdtype == DEMOD_TYPE_STV0367)
+ tuner_tda18212_ping(chan, i2c, addr);
+
+ /* perform tuner probe/init/attach */
+ client = dvb_module_probe("tda18212", NULL, i2c, addr, &config);
+ if (!client)
+ goto err;
+
+ chan->i2c_client[0] = client;
+ chan->i2c_client_fe = 1;
+
+ return 0;
+err:
+ dev_err(pdev, "TDA18212 tuner not found. Device is not fully operational.\n");
+ return -ENODEV;
+}
+
static int tuner_attach_probe(struct ngene_channel *chan)
{
- if (chan->demod_type == 0)
+ switch (chan->demod_type) {
+ case DEMOD_TYPE_STV090X:
return tuner_attach_stv6110(chan);
- if (chan->demod_type == 1)
+ case DEMOD_TYPE_DRXK:
return tuner_attach_tda18271(chan);
+ case DEMOD_TYPE_STV0367:
+ case DEMOD_TYPE_SONY_CT2:
+ case DEMOD_TYPE_SONY_ISDBT:
+ case DEMOD_TYPE_SONY_C2T2:
+ case DEMOD_TYPE_SONY_C2T2I:
+ return tuner_attach_tda18212(chan, chan->demod_type);
+ case DEMOD_TYPE_STV0910:
+ return tuner_attach_stv6111(chan);
+ }
+
return -EINVAL;
}
static int demod_attach_stv0900(struct ngene_channel *chan)
{
- struct i2c_adapter *i2c;
+ struct device *pdev = &chan->dev->pci_dev->dev;
+ struct i2c_adapter *i2c = i2c_adapter_from_chan(chan);
struct stv090x_config *feconf = (struct stv090x_config *)
chan->dev->card_info->fe_config[chan->number];
@@ -144,7 +316,7 @@ static int demod_attach_stv0900(struct ngene_channel *chan)
(chan->number & 1) == 0 ? STV090x_DEMODULATOR_0
: STV090x_DEMODULATOR_1);
if (chan->fe == NULL) {
- printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n");
+ dev_err(pdev, "No STV0900 found!\n");
return -ENODEV;
}
@@ -154,7 +326,7 @@ static int demod_attach_stv0900(struct ngene_channel *chan)
if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0,
0, chan->dev->card_info->lnb[chan->number])) {
- printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n");
+ dev_err(pdev, "No LNBH24 found!\n");
dvb_frontend_detach(chan->fe);
chan->fe = NULL;
return -ENODEV;
@@ -163,6 +335,119 @@ static int demod_attach_stv0900(struct ngene_channel *chan)
return 0;
}
+static struct stv0910_cfg stv0910_p = {
+ .adr = 0x68,
+ .parallel = 1,
+ .rptlvl = 4,
+ .clk = 30000000,
+};
+
+static struct lnbh25_config lnbh25_cfg = {
+ .i2c_address = 0x0c << 1,
+ .data2_config = LNBH25_TEN
+};
+
+static int demod_attach_stv0910(struct ngene_channel *chan,
+ struct i2c_adapter *i2c)
+{
+ struct device *pdev = &chan->dev->pci_dev->dev;
+ struct stv0910_cfg cfg = stv0910_p;
+ struct lnbh25_config lnbcfg = lnbh25_cfg;
+
+ chan->fe = dvb_attach(stv0910_attach, i2c, &cfg, (chan->number & 1));
+ if (!chan->fe) {
+ cfg.adr = 0x6c;
+ chan->fe = dvb_attach(stv0910_attach, i2c,
+ &cfg, (chan->number & 1));
+ }
+ if (!chan->fe) {
+ dev_err(pdev, "stv0910_attach() failed!\n");
+ return -ENODEV;
+ }
+
+ /*
+ * attach lnbh25 - leftshift by one as the lnbh25 driver expects 8bit
+ * i2c addresses
+ */
+ lnbcfg.i2c_address = (((chan->number & 1) ? 0x0d : 0x0c) << 1);
+ if (!dvb_attach(lnbh25_attach, chan->fe, &lnbcfg, i2c)) {
+ lnbcfg.i2c_address = (((chan->number & 1) ? 0x09 : 0x08) << 1);
+ if (!dvb_attach(lnbh25_attach, chan->fe, &lnbcfg, i2c)) {
+ dev_err(pdev, "lnbh25_attach() failed!\n");
+ dvb_frontend_detach(chan->fe);
+ chan->fe = NULL;
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
+static struct stv0367_config ddb_stv0367_config[] = {
+ {
+ .demod_address = 0x1f,
+ .xtal = 27000000,
+ .if_khz = 0,
+ .if_iq_mode = FE_TER_NORMAL_IF_TUNER,
+ .ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
+ .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
+ }, {
+ .demod_address = 0x1e,
+ .xtal = 27000000,
+ .if_khz = 0,
+ .if_iq_mode = FE_TER_NORMAL_IF_TUNER,
+ .ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
+ .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
+ },
+};
+
+static int demod_attach_stv0367(struct ngene_channel *chan,
+ struct i2c_adapter *i2c)
+{
+ struct device *pdev = &chan->dev->pci_dev->dev;
+
+ chan->fe = dvb_attach(stv0367ddb_attach,
+ &ddb_stv0367_config[(chan->number & 1)], i2c);
+
+ if (!chan->fe) {
+ dev_err(pdev, "stv0367ddb_attach() failed!\n");
+ return -ENODEV;
+ }
+
+ chan->fe->sec_priv = chan;
+ chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl;
+ chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+ return 0;
+}
+
+static int demod_attach_cxd28xx(struct ngene_channel *chan,
+ struct i2c_adapter *i2c, int osc24)
+{
+ struct device *pdev = &chan->dev->pci_dev->dev;
+ struct cxd2841er_config cfg;
+
+ /* the cxd2841er driver expects 8bit/shifted I2C addresses */
+ cfg.i2c_addr = ((chan->number & 1) ? 0x6d : 0x6c) << 1;
+
+ cfg.xtal = osc24 ? SONY_XTAL_24000 : SONY_XTAL_20500;
+ cfg.flags = CXD2841ER_AUTO_IFHZ | CXD2841ER_EARLY_TUNE |
+ CXD2841ER_NO_WAIT_LOCK | CXD2841ER_NO_AGCNEG |
+ CXD2841ER_TSBITS | CXD2841ER_TS_SERIAL;
+
+ /* attach frontend */
+ chan->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c);
+
+ if (!chan->fe) {
+ dev_err(pdev, "CXD28XX attach failed!\n");
+ return -ENODEV;
+ }
+
+ chan->fe->sec_priv = chan;
+ chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl;
+ chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+ return 0;
+}
+
static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock)
{
struct ngene_channel *chan = fe->analog_demod_priv;
@@ -173,44 +458,61 @@ static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock)
up(&chan->dev->pll_mutex);
}
-static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
+static int port_has_stv0900(struct i2c_adapter *i2c, int port)
{
- struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD,
- .buf = val, .len = 1 } };
- return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
+ u8 val;
+ if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0)
+ return 0;
+ return 1;
}
-static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
- u16 reg, u8 *val)
+static int port_has_drxk(struct i2c_adapter *i2c, int port)
{
- u8 msg[2] = {reg>>8, reg&0xff};
- struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
- .buf = msg, .len = 2},
- {.addr = adr, .flags = I2C_M_RD,
- .buf = val, .len = 1} };
- return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+ u8 val;
+
+ if (i2c_read(i2c, 0x29+port, &val) < 0)
+ return 0;
+ return 1;
}
-static int port_has_stv0900(struct i2c_adapter *i2c, int port)
+static int port_has_stv0367(struct i2c_adapter *i2c)
{
u8 val;
- if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0)
+
+ if (i2c_read_reg16(i2c, 0x1e, 0xf000, &val) < 0)
+ return 0;
+ if (val != 0x60)
+ return 0;
+ if (i2c_read_reg16(i2c, 0x1f, 0xf000, &val) < 0)
+ return 0;
+ if (val != 0x60)
return 0;
return 1;
}
-static int port_has_drxk(struct i2c_adapter *i2c, int port)
+int ngene_port_has_cxd2099(struct i2c_adapter *i2c, u8 *type)
{
u8 val;
-
- if (i2c_read(i2c, 0x29+port, &val) < 0)
+ u8 probe[4] = { 0xe0, 0x00, 0x00, 0x00 }, data[4];
+ struct i2c_msg msgs[2] = {{ .addr = 0x40, .flags = 0,
+ .buf = probe, .len = 4 },
+ { .addr = 0x40, .flags = I2C_M_RD,
+ .buf = data, .len = 4 } };
+ val = i2c_transfer(i2c, msgs, 2);
+ if (val != 2)
return 0;
+
+ if (data[0] == 0x02 && data[1] == 0x2b && data[3] == 0x43)
+ *type = 2;
+ else
+ *type = 1;
return 1;
}
static int demod_attach_drxk(struct ngene_channel *chan,
struct i2c_adapter *i2c)
{
+ struct device *pdev = &chan->dev->pci_dev->dev;
struct drxk_config config;
memset(&config, 0, sizeof(config));
@@ -220,7 +522,7 @@ static int demod_attach_drxk(struct ngene_channel *chan,
chan->fe = dvb_attach(drxk_attach, &config, i2c);
if (!chan->fe) {
- printk(KERN_ERR "No DRXK found!\n");
+ dev_err(pdev, "No DRXK found!\n");
return -ENODEV;
}
chan->fe->sec_priv = chan;
@@ -229,22 +531,153 @@ static int demod_attach_drxk(struct ngene_channel *chan,
return 0;
}
+/****************************************************************************/
+/* XO2 related lists and functions ******************************************/
+/****************************************************************************/
+
+static char *xo2names[] = {
+ "DUAL DVB-S2",
+ "DUAL DVB-C/T/T2",
+ "DUAL DVB-ISDBT",
+ "DUAL DVB-C/C2/T/T2",
+ "DUAL ATSC",
+ "DUAL DVB-C/C2/T/T2/I",
+};
+
+static int init_xo2(struct ngene_channel *chan, struct i2c_adapter *i2c)
+{
+ struct device *pdev = &chan->dev->pci_dev->dev;
+ u8 addr = 0x10;
+ u8 val, data[2];
+ int res;
+
+ res = i2c_read_regs(i2c, addr, 0x04, data, 2);
+ if (res < 0)
+ return res;
+
+ if (data[0] != 0x01) {
+ dev_info(pdev, "Invalid XO2 on channel %d\n", chan->number);
+ return -1;
+ }
+
+ i2c_read_reg(i2c, addr, 0x08, &val);
+ if (val != 0) {
+ i2c_write_reg(i2c, addr, 0x08, 0x00);
+ msleep(100);
+ }
+ /* Enable tuner power, disable pll, reset demods */
+ i2c_write_reg(i2c, addr, 0x08, 0x04);
+ usleep_range(2000, 3000);
+ /* Release demod resets */
+ i2c_write_reg(i2c, addr, 0x08, 0x07);
+
+ /*
+ * speed: 0=55,1=75,2=90,3=104 MBit/s
+ * Note: The ngene hardware must be run at 75 MBit/s compared
+ * to more modern ddbridge hardware which runs at 90 MBit/s,
+ * else there will be issues with the data transport and non-
+ * working secondary/slave demods/tuners.
+ */
+ i2c_write_reg(i2c, addr, 0x09, 1);
+
+ i2c_write_reg(i2c, addr, 0x0a, 0x01);
+ i2c_write_reg(i2c, addr, 0x0b, 0x01);
+
+ usleep_range(2000, 3000);
+ /* Start XO2 PLL */
+ i2c_write_reg(i2c, addr, 0x08, 0x87);
+
+ return 0;
+}
+
+static int port_has_xo2(struct i2c_adapter *i2c, u8 *type, u8 *id)
+{
+ u8 probe[1] = { 0x00 }, data[4];
+ u8 addr = 0x10;
+
+ *type = NGENE_XO2_TYPE_NONE;
+
+ if (i2c_io(i2c, addr, probe, 1, data, 4))
+ return 0;
+ if (data[0] == 'D' && data[1] == 'F') {
+ *id = data[2];
+ *type = NGENE_XO2_TYPE_DUOFLEX;
+ return 1;
+ }
+ if (data[0] == 'C' && data[1] == 'I') {
+ *id = data[2];
+ *type = NGENE_XO2_TYPE_CI;
+ return 1;
+ }
+ return 0;
+}
+
+/****************************************************************************/
+/* Probing and port/channel handling ****************************************/
+/****************************************************************************/
+
static int cineS2_probe(struct ngene_channel *chan)
{
- struct i2c_adapter *i2c;
+ struct device *pdev = &chan->dev->pci_dev->dev;
+ struct i2c_adapter *i2c = i2c_adapter_from_chan(chan);
struct stv090x_config *fe_conf;
u8 buf[3];
+ u8 xo2_type, xo2_id, xo2_demodtype;
+ u8 sony_osc24 = 0;
struct i2c_msg i2c_msg = { .flags = 0, .buf = buf };
int rc;
- /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
- if (chan->number < 2)
- i2c = &chan->dev->channel[0].i2c_adapter;
- else
- i2c = &chan->dev->channel[1].i2c_adapter;
-
- if (port_has_stv0900(i2c, chan->number)) {
- chan->demod_type = 0;
+ if (port_has_xo2(i2c, &xo2_type, &xo2_id)) {
+ xo2_id >>= 2;
+ dev_dbg(pdev, "XO2 on channel %d (type %d, id %d)\n",
+ chan->number, xo2_type, xo2_id);
+
+ switch (xo2_type) {
+ case NGENE_XO2_TYPE_DUOFLEX:
+ if (chan->number & 1)
+ dev_dbg(pdev,
+ "skipping XO2 init on odd channel %d",
+ chan->number);
+ else
+ init_xo2(chan, i2c);
+
+ xo2_demodtype = DEMOD_TYPE_XO2 + xo2_id;
+
+ switch (xo2_demodtype) {
+ case DEMOD_TYPE_SONY_CT2:
+ case DEMOD_TYPE_SONY_ISDBT:
+ case DEMOD_TYPE_SONY_C2T2:
+ case DEMOD_TYPE_SONY_C2T2I:
+ dev_info(pdev, "%s (XO2) on channel %d\n",
+ xo2names[xo2_id], chan->number);
+ chan->demod_type = xo2_demodtype;
+ if (xo2_demodtype == DEMOD_TYPE_SONY_C2T2I)
+ sony_osc24 = 1;
+
+ demod_attach_cxd28xx(chan, i2c, sony_osc24);
+ break;
+ case DEMOD_TYPE_STV0910:
+ dev_info(pdev, "%s (XO2) on channel %d\n",
+ xo2names[xo2_id], chan->number);
+ chan->demod_type = xo2_demodtype;
+ demod_attach_stv0910(chan, i2c);
+ break;
+ default:
+ dev_warn(pdev,
+ "Unsupported XO2 module on channel %d\n",
+ chan->number);
+ return -ENODEV;
+ }
+ break;
+ case NGENE_XO2_TYPE_CI:
+ dev_info(pdev, "DuoFlex CI modules not supported\n");
+ return -ENODEV;
+ default:
+ dev_info(pdev, "Unsupported XO2 module type\n");
+ return -ENODEV;
+ }
+ } else if (port_has_stv0900(i2c, chan->number)) {
+ chan->demod_type = DEMOD_TYPE_STV090X;
fe_conf = chan->dev->card_info->fe_config[chan->number];
/* demod found, attach it */
rc = demod_attach_stv0900(chan);
@@ -269,14 +702,18 @@ static int cineS2_probe(struct ngene_channel *chan)
}
rc = i2c_transfer(i2c, &i2c_msg, 1);
if (rc != 1) {
- printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n");
+ dev_err(pdev, "Could not setup DPNx\n");
return -EIO;
}
} else if (port_has_drxk(i2c, chan->number^2)) {
- chan->demod_type = 1;
+ chan->demod_type = DEMOD_TYPE_DRXK;
demod_attach_drxk(chan, i2c);
+ } else if (port_has_stv0367(i2c)) {
+ chan->demod_type = DEMOD_TYPE_STV0367;
+ dev_info(pdev, "STV0367 on channel %d\n", chan->number);
+ demod_attach_stv0367(chan, i2c);
} else {
- printk(KERN_ERR "No demod found on chan %d\n", chan->number);
+ dev_info(pdev, "No demod found on chan %d\n", chan->number);
return -ENODEV;
}
return 0;
@@ -299,9 +736,11 @@ static struct mt2131_config m780_tunerconfig = {
*/
static int demod_attach_lg330x(struct ngene_channel *chan)
{
+ struct device *pdev = &chan->dev->pci_dev->dev;
+
chan->fe = dvb_attach(lgdt330x_attach, &aver_m780, &chan->i2c_adapter);
if (chan->fe == NULL) {
- printk(KERN_ERR DEVICE_NAME ": No LGDT330x found!\n");
+ dev_err(pdev, "No LGDT330x found!\n");
return -ENODEV;
}
@@ -313,6 +752,7 @@ static int demod_attach_lg330x(struct ngene_channel *chan)
static int demod_attach_drxd(struct ngene_channel *chan)
{
+ struct device *pdev = &chan->dev->pci_dev->dev;
struct drxd_config *feconf;
feconf = chan->dev->card_info->fe_config[chan->number];
@@ -320,7 +760,7 @@ static int demod_attach_drxd(struct ngene_channel *chan)
chan->fe = dvb_attach(drxd_attach, feconf, chan,
&chan->i2c_adapter, &chan->dev->pci_dev->dev);
if (!chan->fe) {
- pr_err("No DRXD found!\n");
+ dev_err(pdev, "No DRXD found!\n");
return -ENODEV;
}
return 0;
@@ -328,6 +768,7 @@ static int demod_attach_drxd(struct ngene_channel *chan)
static int tuner_attach_dtt7520x(struct ngene_channel *chan)
{
+ struct device *pdev = &chan->dev->pci_dev->dev;
struct drxd_config *feconf;
feconf = chan->dev->card_info->fe_config[chan->number];
@@ -335,7 +776,7 @@ static int tuner_attach_dtt7520x(struct ngene_channel *chan)
if (!dvb_attach(dvb_pll_attach, chan->fe, feconf->pll_address,
&chan->i2c_adapter,
feconf->pll_type)) {
- pr_err("No pll(%d) found!\n", feconf->pll_type);
+ dev_err(pdev, "No pll(%d) found!\n", feconf->pll_type);
return -ENODEV;
}
return 0;
@@ -371,12 +812,13 @@ static int tuner_attach_dtt7520x(struct ngene_channel *chan)
static int i2c_write_eeprom(struct i2c_adapter *adapter,
u8 adr, u16 reg, u8 data)
{
+ struct device *pdev = adapter->dev.parent;
u8 m[3] = {(reg >> 8), (reg & 0xff), data};
struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m,
.len = sizeof(m)};
if (i2c_transfer(adapter, &msg, 1) != 1) {
- pr_err(DEVICE_NAME ": Error writing EEPROM!\n");
+ dev_err(pdev, "Error writing EEPROM!\n");
return -EIO;
}
return 0;
@@ -385,6 +827,7 @@ static int i2c_write_eeprom(struct i2c_adapter *adapter,
static int i2c_read_eeprom(struct i2c_adapter *adapter,
u8 adr, u16 reg, u8 *data, int len)
{
+ struct device *pdev = adapter->dev.parent;
u8 msg[2] = {(reg >> 8), (reg & 0xff)};
struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
.buf = msg, .len = 2 },
@@ -392,7 +835,7 @@ static int i2c_read_eeprom(struct i2c_adapter *adapter,
.buf = data, .len = len} };
if (i2c_transfer(adapter, msgs, 2) != 2) {
- pr_err(DEVICE_NAME ": Error reading EEPROM\n");
+ dev_err(pdev, "Error reading EEPROM\n");
return -EIO;
}
return 0;
@@ -401,6 +844,7 @@ static int i2c_read_eeprom(struct i2c_adapter *adapter,
static int ReadEEProm(struct i2c_adapter *adapter,
u16 Tag, u32 MaxLen, u8 *data, u32 *pLength)
{
+ struct device *pdev = adapter->dev.parent;
int status = 0;
u16 Addr = MICNG_EE_START, Length, tag = 0;
u8 EETag[3];
@@ -416,9 +860,8 @@ static int ReadEEProm(struct i2c_adapter *adapter,
Addr += sizeof(u16) + 1 + EETag[2];
}
if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) {
- pr_err(DEVICE_NAME
- ": Reached EOEE @ Tag = %04x Length = %3d\n",
- tag, EETag[2]);
+ dev_err(pdev, "Reached EOEE @ Tag = %04x Length = %3d\n",
+ tag, EETag[2]);
return -1;
}
Length = EETag[2];
@@ -441,6 +884,7 @@ static int ReadEEProm(struct i2c_adapter *adapter,
static int WriteEEProm(struct i2c_adapter *adapter,
u16 Tag, u32 Length, u8 *data)
{
+ struct device *pdev = adapter->dev.parent;
int status = 0;
u16 Addr = MICNG_EE_START;
u8 EETag[3];
@@ -458,9 +902,8 @@ static int WriteEEProm(struct i2c_adapter *adapter,
Addr += sizeof(u16) + 1 + EETag[2];
}
if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) {
- pr_err(DEVICE_NAME
- ": Reached EOEE @ Tag = %04x Length = %3d\n",
- tag, EETag[2]);
+ dev_err(pdev, "Reached EOEE @ Tag = %04x Length = %3d\n",
+ tag, EETag[2]);
return -1;
}
@@ -487,13 +930,11 @@ static int WriteEEProm(struct i2c_adapter *adapter,
if (status)
break;
if (Tmp != data[i])
- pr_err(DEVICE_NAME
- "eeprom write error\n");
+ dev_err(pdev, "eeprom write error\n");
retry -= 1;
}
if (status) {
- pr_err(DEVICE_NAME
- ": Timeout polling eeprom\n");
+ dev_err(pdev, "Timeout polling eeprom\n");
break;
}
}
@@ -532,19 +973,20 @@ static int eeprom_write_ushort(struct i2c_adapter *adapter, u16 tag, u16 data)
static s16 osc_deviation(void *priv, s16 deviation, int flag)
{
struct ngene_channel *chan = priv;
+ struct device *pdev = &chan->dev->pci_dev->dev;
struct i2c_adapter *adap = &chan->i2c_adapter;
u16 data = 0;
if (flag) {
data = (u16) deviation;
- pr_info(DEVICE_NAME ": write deviation %d\n",
- deviation);
+ dev_info(pdev, "write deviation %d\n",
+ deviation);
eeprom_write_ushort(adap, 0x1000 + chan->number, data);
} else {
if (eeprom_read_ushort(adap, 0x1000 + chan->number, &data))
data = 0;
- pr_info(DEVICE_NAME ": read deviation %d\n",
- (s16) data);
+ dev_info(pdev, "read deviation %d\n",
+ (s16)data);
}
return (s16) data;
@@ -749,6 +1191,8 @@ static const struct ngene_info ngene_info_terratec = {
/****************************************************************************/
static const struct pci_device_id ngene_id_tbl[] = {
+ NGENE_ID(0x18c3, 0xab04, ngene_info_cineS2),
+ NGENE_ID(0x18c3, 0xab05, ngene_info_cineS2v5),
NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2),
NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2),
NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2),
@@ -769,7 +1213,7 @@ MODULE_DEVICE_TABLE(pci, ngene_id_tbl);
static pci_ers_result_t ngene_error_detected(struct pci_dev *dev,
enum pci_channel_state state)
{
- printk(KERN_ERR DEVICE_NAME ": PCI error\n");
+ dev_err(&dev->dev, "PCI error\n");
if (state == pci_channel_io_perm_failure)
return PCI_ERS_RESULT_DISCONNECT;
if (state == pci_channel_io_frozen)
@@ -779,13 +1223,13 @@ static pci_ers_result_t ngene_error_detected(struct pci_dev *dev,
static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev)
{
- printk(KERN_INFO DEVICE_NAME ": slot reset\n");
+ dev_info(&dev->dev, "slot reset\n");
return 0;
}
static void ngene_resume(struct pci_dev *dev)
{
- printk(KERN_INFO DEVICE_NAME ": resume\n");
+ dev_info(&dev->dev, "resume\n");
}
static const struct pci_error_handlers ngene_errors = {
@@ -805,8 +1249,9 @@ static struct pci_driver ngene_pci_driver = {
static __init int module_init_ngene(void)
{
- printk(KERN_INFO
- "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n");
+ /* pr_*() since we don't have a device to use with dev_*() yet */
+ pr_info("nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n");
+
return pci_register_driver(&ngene_pci_driver);
}
diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c
index 8c92cb7f7e72..25f16833a475 100644
--- a/drivers/media/pci/ngene/ngene-core.c
+++ b/drivers/media/pci/ngene/ngene-core.c
@@ -51,8 +51,6 @@ MODULE_PARM_DESC(debug, "Print debugging information.");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-#define dprintk if (debug) printk
-
#define ngwriteb(dat, adr) writeb((dat), dev->iomem + (adr))
#define ngwritel(dat, adr) writel((dat), dev->iomem + (adr))
#define ngwriteb(dat, adr) writeb((dat), dev->iomem + (adr))
@@ -86,6 +84,7 @@ static void event_tasklet(unsigned long data)
static void demux_tasklet(unsigned long data)
{
struct ngene_channel *chan = (struct ngene_channel *)data;
+ struct device *pdev = &chan->dev->pci_dev->dev;
struct SBufferHeader *Cur = chan->nextBuffer;
spin_lock_irq(&chan->state_lock);
@@ -124,16 +123,15 @@ static void demux_tasklet(unsigned long data)
chan->HWState = HWSTATE_RUN;
}
} else {
- printk(KERN_ERR DEVICE_NAME ": OOPS\n");
+ dev_err(pdev, "OOPS\n");
if (chan->HWState == HWSTATE_RUN) {
Cur->ngeneBuffer.SR.Flags &= ~0x40;
break; /* Stop processing stream */
}
}
if (chan->AudioDTOUpdated) {
- printk(KERN_INFO DEVICE_NAME
- ": Update AudioDTO = %d\n",
- chan->AudioDTOValue);
+ dev_info(pdev, "Update AudioDTO = %d\n",
+ chan->AudioDTOValue);
Cur->ngeneBuffer.SR.DTOUpdate =
chan->AudioDTOValue;
chan->AudioDTOUpdated = 0;
@@ -173,6 +171,7 @@ static void demux_tasklet(unsigned long data)
static irqreturn_t irq_handler(int irq, void *dev_id)
{
struct ngene *dev = (struct ngene *)dev_id;
+ struct device *pdev = &dev->pci_dev->dev;
u32 icounts = 0;
irqreturn_t rc = IRQ_NONE;
u32 i = MAX_STREAM;
@@ -213,7 +212,7 @@ static irqreturn_t irq_handler(int irq, void *dev_id)
*(dev->EventBuffer);
dev->EventQueueWriteIndex = nextWriteIndex;
} else {
- printk(KERN_ERR DEVICE_NAME ": event overflow\n");
+ dev_err(pdev, "event overflow\n");
dev->EventQueueOverflowCount += 1;
dev->EventQueueOverflowFlag = 1;
}
@@ -249,23 +248,25 @@ static irqreturn_t irq_handler(int irq, void *dev_id)
static void dump_command_io(struct ngene *dev)
{
+ struct device *pdev = &dev->pci_dev->dev;
u8 buf[8], *b;
ngcpyfrom(buf, HOST_TO_NGENE, 8);
- printk(KERN_ERR "host_to_ngene (%04x): %*ph\n", HOST_TO_NGENE, 8, buf);
+ dev_err(pdev, "host_to_ngene (%04x): %*ph\n", HOST_TO_NGENE, 8, buf);
ngcpyfrom(buf, NGENE_TO_HOST, 8);
- printk(KERN_ERR "ngene_to_host (%04x): %*ph\n", NGENE_TO_HOST, 8, buf);
+ dev_err(pdev, "ngene_to_host (%04x): %*ph\n", NGENE_TO_HOST, 8, buf);
b = dev->hosttongene;
- printk(KERN_ERR "dev->hosttongene (%p): %*ph\n", b, 8, b);
+ dev_err(pdev, "dev->hosttongene (%p): %*ph\n", b, 8, b);
b = dev->ngenetohost;
- printk(KERN_ERR "dev->ngenetohost (%p): %*ph\n", b, 8, b);
+ dev_err(pdev, "dev->ngenetohost (%p): %*ph\n", b, 8, b);
}
static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com)
{
+ struct device *pdev = &dev->pci_dev->dev;
int ret;
u8 *tmpCmdDoneByte;
@@ -313,9 +314,8 @@ static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com)
if (!ret) {
/*ngwritel(0, FORCE_NMI);*/
- printk(KERN_ERR DEVICE_NAME
- ": Command timeout cmd=%02x prev=%02x\n",
- com->cmd.hdr.Opcode, dev->prev_cmd);
+ dev_err(pdev, "Command timeout cmd=%02x prev=%02x\n",
+ com->cmd.hdr.Opcode, dev->prev_cmd);
dump_command_io(dev);
return -1;
}
@@ -553,6 +553,7 @@ static void clear_buffers(struct ngene_channel *chan)
static int ngene_command_stream_control(struct ngene *dev, u8 stream,
u8 control, u8 mode, u8 flags)
{
+ struct device *pdev = &dev->pci_dev->dev;
struct ngene_channel *chan = &dev->channel[stream];
struct ngene_command com;
u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300);
@@ -572,8 +573,7 @@ static int ngene_command_stream_control(struct ngene *dev, u8 stream,
com.in_len = sizeof(struct FW_STREAM_CONTROL);
com.out_len = 0;
- dprintk(KERN_INFO DEVICE_NAME
- ": Stream=%02x, Control=%02x, Mode=%02x\n",
+ dev_dbg(pdev, "Stream=%02x, Control=%02x, Mode=%02x\n",
com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control,
com.cmd.StreamControl.Mode);
@@ -695,23 +695,24 @@ static int ngene_command_stream_control(struct ngene *dev, u8 stream,
void set_transfer(struct ngene_channel *chan, int state)
{
+ struct device *pdev = &chan->dev->pci_dev->dev;
u8 control = 0, mode = 0, flags = 0;
struct ngene *dev = chan->dev;
int ret;
/*
- printk(KERN_INFO DEVICE_NAME ": st %d\n", state);
+ dev_info(pdev, "st %d\n", state);
msleep(100);
*/
if (state) {
if (chan->running) {
- printk(KERN_INFO DEVICE_NAME ": already running\n");
+ dev_info(pdev, "already running\n");
return;
}
} else {
if (!chan->running) {
- printk(KERN_INFO DEVICE_NAME ": already stopped\n");
+ dev_info(pdev, "already stopped\n");
return;
}
}
@@ -722,7 +723,7 @@ void set_transfer(struct ngene_channel *chan, int state)
if (state) {
spin_lock_irq(&chan->state_lock);
- /* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
+ /* dev_info(pdev, "lock=%08x\n",
ngreadl(0x9310)); */
dvb_ringbuffer_flush(&dev->tsout_rbuf);
control = 0x80;
@@ -740,7 +741,7 @@ void set_transfer(struct ngene_channel *chan, int state)
chan->pBufferExchange = tsin_exchange;
spin_unlock_irq(&chan->state_lock);
}
- /* else printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
+ /* else dev_info(pdev, "lock=%08x\n",
ngreadl(0x9310)); */
mutex_lock(&dev->stream_mutex);
@@ -751,8 +752,7 @@ void set_transfer(struct ngene_channel *chan, int state)
if (!ret)
chan->running = state;
else
- printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n",
- state);
+ dev_err(pdev, "%s %d failed\n", __func__, state);
if (!state) {
spin_lock_irq(&chan->state_lock);
chan->pBufferExchange = NULL;
@@ -1195,6 +1195,7 @@ static int ngene_get_buffers(struct ngene *dev)
static void ngene_init(struct ngene *dev)
{
+ struct device *pdev = &dev->pci_dev->dev;
int i;
tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev);
@@ -1214,12 +1215,12 @@ static void ngene_init(struct ngene *dev)
dev->icounts = ngreadl(NGENE_INT_COUNTS);
dev->device_version = ngreadl(DEV_VER) & 0x0f;
- printk(KERN_INFO DEVICE_NAME ": Device version %d\n",
- dev->device_version);
+ dev_info(pdev, "Device version %d\n", dev->device_version);
}
static int ngene_load_firm(struct ngene *dev)
{
+ struct device *pdev = &dev->pci_dev->dev;
u32 size;
const struct firmware *fw = NULL;
u8 *ngene_fw;
@@ -1253,21 +1254,18 @@ static int ngene_load_firm(struct ngene *dev)
}
if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) {
- printk(KERN_ERR DEVICE_NAME
- ": Could not load firmware file %s.\n", fw_name);
- printk(KERN_INFO DEVICE_NAME
- ": Copy %s to your hotplug directory!\n", fw_name);
+ dev_err(pdev, "Could not load firmware file %s.\n", fw_name);
+ dev_info(pdev, "Copy %s to your hotplug directory!\n",
+ fw_name);
return -1;
}
if (size == 0)
size = fw->size;
if (size != fw->size) {
- printk(KERN_ERR DEVICE_NAME
- ": Firmware %s has invalid size!", fw_name);
+ dev_err(pdev, "Firmware %s has invalid size!", fw_name);
err = -1;
} else {
- printk(KERN_INFO DEVICE_NAME
- ": Loading firmware file %s.\n", fw_name);
+ dev_info(pdev, "Loading firmware file %s.\n", fw_name);
ngene_fw = (u8 *) fw->data;
err = ngene_command_load_firmware(dev, ngene_fw, size);
}
@@ -1360,14 +1358,14 @@ static int ngene_start(struct ngene *dev)
#ifdef CONFIG_PCI_MSI
/* enable MSI if kernel and card support it */
if (pci_msi_enabled() && dev->card_info->msi_supported) {
+ struct device *pdev = &dev->pci_dev->dev;
unsigned long flags;
ngwritel(0, NGENE_INT_ENABLE);
free_irq(dev->pci_dev->irq, dev);
stat = pci_enable_msi(dev->pci_dev);
if (stat) {
- printk(KERN_INFO DEVICE_NAME
- ": MSI not available\n");
+ dev_info(pdev, "MSI not available\n");
flags = IRQF_SHARED;
} else {
flags = 0;
@@ -1426,6 +1424,13 @@ static void release_channel(struct ngene_channel *chan)
if (chan->fe) {
dvb_unregister_frontend(chan->fe);
+
+ /* release I2C client (tuner) if needed */
+ if (chan->i2c_client_fe) {
+ dvb_module_release(chan->i2c_client[0]);
+ chan->i2c_client[0] = NULL;
+ }
+
dvb_frontend_detach(chan->fe);
chan->fe = NULL;
}
@@ -1461,6 +1466,7 @@ static int init_channel(struct ngene_channel *chan)
chan->users = 0;
chan->type = io;
chan->mode = chan->type; /* for now only one mode */
+ chan->i2c_client_fe = 0; /* be sure this is set to zero */
if (io & NGENE_IO_TSIN) {
chan->fe = NULL;
@@ -1562,19 +1568,46 @@ static int init_channels(struct ngene *dev)
return 0;
}
-static struct cxd2099_cfg cxd_cfg = {
+static const struct cxd2099_cfg cxd_cfgtmpl = {
.bitrate = 62000,
- .adr = 0x40,
.polarity = 0,
.clock_mode = 0,
};
static void cxd_attach(struct ngene *dev)
{
+ struct device *pdev = &dev->pci_dev->dev;
struct ngene_ci *ci = &dev->ci;
+ struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl;
+ struct i2c_client *client;
+ int ret;
+ u8 type;
+
+ /* check for CXD2099AR presence before attaching */
+ ret = ngene_port_has_cxd2099(&dev->channel[0].i2c_adapter, &type);
+ if (!ret) {
+ dev_dbg(pdev, "No CXD2099AR found\n");
+ return;
+ }
+
+ if (type != 1) {
+ dev_warn(pdev, "CXD2099AR is uninitialized!\n");
+ return;
+ }
+
+ cxd_cfg.en = &ci->en;
+ client = dvb_module_probe("cxd2099", NULL,
+ &dev->channel[0].i2c_adapter,
+ 0x40, &cxd_cfg);
+ if (!client)
+ goto err;
- ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter);
ci->dev = dev;
+ dev->channel[0].i2c_client[0] = client;
+ return;
+
+err:
+ dev_err(pdev, "CXD2099AR attach failed\n");
return;
}
@@ -1583,7 +1616,9 @@ static void cxd_detach(struct ngene *dev)
struct ngene_ci *ci = &dev->ci;
dvb_ca_en50221_release(ci->en);
- kfree(ci->en);
+
+ dvb_module_release(dev->channel[0].i2c_client[0]);
+ dev->channel[0].i2c_client[0] = NULL;
ci->en = NULL;
}
@@ -1615,7 +1650,7 @@ void ngene_shutdown(struct pci_dev *pdev)
if (!dev || !shutdown_workaround)
return;
- printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n");
+ dev_info(&pdev->dev, "shutdown workaround...\n");
ngene_unlink(dev);
pci_disable_device(pdev);
}
@@ -1655,7 +1690,7 @@ int ngene_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
dev->pci_dev = pci_dev;
dev->card_info = (struct ngene_info *)id->driver_data;
- printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name);
+ dev_info(&pci_dev->dev, "Found %s\n", dev->card_info->name);
pci_set_drvdata(pci_dev, dev);
diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c
index 03fc218a45e9..fee89b9ed9c1 100644
--- a/drivers/media/pci/ngene/ngene-dvb.c
+++ b/drivers/media/pci/ngene/ngene-dvb.c
@@ -38,6 +38,9 @@
#include "ngene.h"
+static int ci_tsfix = 1;
+module_param(ci_tsfix, int, 0444);
+MODULE_PARM_DESC(ci_tsfix, "Detect and fix TS buffer offset shifs in conjunction with CI expansions (default: 1/enabled)");
/****************************************************************************/
/* COMMAND API interface ****************************************************/
@@ -84,18 +87,41 @@ static ssize_t ts_read(struct file *file, char __user *buf,
return count;
}
+static __poll_t ts_poll(struct file *file, poll_table *wait)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct ngene_channel *chan = dvbdev->priv;
+ struct ngene *dev = chan->dev;
+ struct dvb_ringbuffer *rbuf = &dev->tsin_rbuf;
+ struct dvb_ringbuffer *wbuf = &dev->tsout_rbuf;
+ __poll_t mask = 0;
+
+ poll_wait(file, &rbuf->queue, wait);
+ poll_wait(file, &wbuf->queue, wait);
+
+ if (!dvb_ringbuffer_empty(rbuf))
+ mask |= EPOLLIN | EPOLLRDNORM;
+ if (dvb_ringbuffer_free(wbuf) >= 188)
+ mask |= EPOLLOUT | EPOLLWRNORM;
+
+ return mask;
+}
+
static const struct file_operations ci_fops = {
.owner = THIS_MODULE,
.read = ts_read,
.write = ts_write,
.open = dvb_generic_open,
.release = dvb_generic_release,
+ .poll = ts_poll,
+ .mmap = NULL,
};
struct dvb_device ngene_dvbdev_ci = {
- .readers = -1,
- .writers = -1,
- .users = -1,
+ .priv = NULL,
+ .readers = 1,
+ .writers = 1,
+ .users = 2,
.fops = &ci_fops,
};
@@ -116,47 +142,118 @@ static void swap_buffer(u32 *p, u32 len)
/* start of filler packet */
static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER };
-/* #define DEBUG_CI_XFER */
-#ifdef DEBUG_CI_XFER
-static u32 ok;
-static u32 overflow;
-static u32 stripped;
-#endif
+static int tsin_find_offset(void *buf, u32 len)
+{
+ int i, l;
+
+ l = len - sizeof(fill_ts);
+ if (l <= 0)
+ return -1;
+
+ for (i = 0; i < l; i++) {
+ if (((char *)buf)[i] == 0x47) {
+ if (!memcmp(buf + i, fill_ts, sizeof(fill_ts)))
+ return i % 188;
+ }
+ }
+
+ return -1;
+}
+
+static inline void tsin_copy_stripped(struct ngene *dev, void *buf)
+{
+ if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) {
+ if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) {
+ dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188);
+ wake_up(&dev->tsin_rbuf.queue);
+ }
+ }
+}
void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
{
struct ngene_channel *chan = priv;
struct ngene *dev = chan->dev;
-
+ int tsoff;
if (flags & DF_SWAP32)
swap_buffer(buf, len);
if (dev->ci.en && chan->number == 2) {
+ /* blindly copy buffers if ci_tsfix is disabled */
+ if (!ci_tsfix) {
+ while (len >= 188) {
+ tsin_copy_stripped(dev, buf);
+
+ buf += 188;
+ len -= 188;
+ }
+ return NULL;
+ }
+
+ /* ci_tsfix = 1 */
+
+ /*
+ * since the remainder of the TS packet which got cut off
+ * in the previous tsin_exchange() run is at the beginning
+ * of the new TS buffer, append this to the temp buffer and
+ * send it to the DVB ringbuffer afterwards.
+ */
+ if (chan->tsin_offset) {
+ memcpy(&chan->tsin_buffer[(188 - chan->tsin_offset)],
+ buf, chan->tsin_offset);
+ tsin_copy_stripped(dev, &chan->tsin_buffer);
+
+ buf += chan->tsin_offset;
+ len -= chan->tsin_offset;
+ }
+
+ /*
+ * copy TS packets to the DVB ringbuffer and detect new offset
+ * shifts by checking for a valid TS SYNC byte
+ */
while (len >= 188) {
- if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) {
- if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) {
- dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188);
- wake_up(&dev->tsin_rbuf.queue);
-#ifdef DEBUG_CI_XFER
- ok++;
-#endif
+ if (*((char *)buf) != 0x47) {
+ /*
+ * no SYNC header, find new offset shift
+ * (max. 188 bytes, tsoff will be mod 188)
+ */
+ tsoff = tsin_find_offset(buf, len);
+ if (tsoff > 0) {
+ chan->tsin_offset += tsoff;
+ chan->tsin_offset %= 188;
+
+ buf += tsoff;
+ len -= tsoff;
+
+ dev_info(&dev->pci_dev->dev,
+ "%s(): tsin_offset shift by %d on channel %d\n",
+ __func__, tsoff,
+ chan->number);
+
+ /*
+ * offset corrected. re-check remaining
+ * len for a full TS frame, break and
+ * skip to fragment handling if < 188.
+ */
+ if (len < 188)
+ break;
}
-#ifdef DEBUG_CI_XFER
- else
- overflow++;
-#endif
}
-#ifdef DEBUG_CI_XFER
- else
- stripped++;
- if (ok % 100 == 0 && overflow)
- printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped);
-#endif
+ tsin_copy_stripped(dev, buf);
+
buf += 188;
len -= 188;
}
+
+ /*
+ * if a fragment is left, copy to temp buffer. The remainder
+ * will be appended in the next tsin_exchange() iteration.
+ */
+ if (len > 0 && len < 188)
+ memcpy(&chan->tsin_buffer, buf, len);
+
return NULL;
}
diff --git a/drivers/media/pci/ngene/ngene-i2c.c b/drivers/media/pci/ngene/ngene-i2c.c
index 3004947f300b..092d46c2a3a9 100644
--- a/drivers/media/pci/ngene/ngene-i2c.c
+++ b/drivers/media/pci/ngene/ngene-i2c.c
@@ -147,7 +147,7 @@ done:
static u32 ngene_i2c_functionality(struct i2c_adapter *adap)
{
- return I2C_FUNC_SMBUS_EMUL;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm ngene_i2c_algo = {
diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h
index 02dbd18f92d0..01d9f1b58fcb 100644
--- a/drivers/media/pci/ngene/ngene.h
+++ b/drivers/media/pci/ngene/ngene.h
@@ -51,6 +51,22 @@
#define VIDEO_CAP_MPEG4 512
#endif
+#define DEMOD_TYPE_STV090X 0
+#define DEMOD_TYPE_DRXK 1
+#define DEMOD_TYPE_STV0367 2
+
+#define DEMOD_TYPE_XO2 32
+#define DEMOD_TYPE_STV0910 (DEMOD_TYPE_XO2 + 0)
+#define DEMOD_TYPE_SONY_CT2 (DEMOD_TYPE_XO2 + 1)
+#define DEMOD_TYPE_SONY_ISDBT (DEMOD_TYPE_XO2 + 2)
+#define DEMOD_TYPE_SONY_C2T2 (DEMOD_TYPE_XO2 + 3)
+#define DEMOD_TYPE_ST_ATSC (DEMOD_TYPE_XO2 + 4)
+#define DEMOD_TYPE_SONY_C2T2I (DEMOD_TYPE_XO2 + 5)
+
+#define NGENE_XO2_TYPE_NONE 0
+#define NGENE_XO2_TYPE_DUOFLEX 1
+#define NGENE_XO2_TYPE_CI 2
+
enum STREAM {
STREAM_VIDEOIN1 = 0, /* ITU656 or TS Input */
STREAM_VIDEOIN2,
@@ -630,6 +646,8 @@ struct ngene_vopen {
struct ngene_channel {
struct device device;
struct i2c_adapter i2c_adapter;
+ struct i2c_client *i2c_client[1];
+ int i2c_client_fe;
struct ngene *dev;
int number;
@@ -714,6 +732,9 @@ struct ngene_channel {
#endif
int running;
+
+ int tsin_offset;
+ u8 tsin_buffer[188];
};
@@ -891,6 +912,9 @@ int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level);
void set_transfer(struct ngene_channel *chan, int state);
void FillTSBuffer(void *Buffer, int Length, u32 Flags);
+/* Provided by ngene-cards.c */
+int ngene_port_has_cxd2099(struct i2c_adapter *i2c, u8 *type);
+
/* Provided by ngene-i2c.c */
int ngene_i2c_init(struct ngene *dev, int dev_nr);
diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c
index c59b69f1af9d..72311445d13d 100644
--- a/drivers/media/pci/saa7134/saa7134-alsa.c
+++ b/drivers/media/pci/saa7134/saa7134-alsa.c
@@ -273,9 +273,8 @@ static int saa7134_alsa_dma_init(struct saa7134_dev *dev, int nr_pages)
return -ENOMEM;
}
- pr_debug("vmalloc is at addr 0x%08lx, size=%d\n",
- (unsigned long)dma->vaddr,
- nr_pages << PAGE_SHIFT);
+ pr_debug("vmalloc is at addr %p, size=%d\n",
+ dma->vaddr, nr_pages << PAGE_SHIFT);
memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT);
dma->nr_pages = nr_pages;
diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c
index a7a63d608dde..3025d38ddb2b 100644
--- a/drivers/media/pci/saa7134/saa7134-dvb.c
+++ b/drivers/media/pci/saa7134/saa7134-dvb.c
@@ -1195,7 +1195,7 @@ static struct s5h1411_config kworld_s5h1411_config = {
.inversion = S5H1411_INVERSION_ON,
.status_mode = S5H1411_DEMODLOCKING,
.mpeg_timing =
- S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
index 33ee8322895e..0e28c5021ac4 100644
--- a/drivers/media/pci/saa7134/saa7134-input.c
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -115,7 +115,7 @@ static int build_key(struct saa7134_dev *dev)
static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
- int gpio;
+ int gpio, rc;
int attempt = 0;
unsigned char b;
@@ -153,8 +153,11 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_proto *protocol,
attempt);
return -EIO;
}
- if (1 != i2c_master_recv(ir->c, &b, 1)) {
+ rc = i2c_master_recv(ir->c, &b, 1);
+ if (rc != 1) {
ir_dbg(ir, "read error\n");
+ if (rc < 0)
+ return rc;
return -EIO;
}
@@ -169,7 +172,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir,
u32 *scancode, u8 *toggle)
{
unsigned char b;
- int gpio;
+ int gpio, rc;
/* <dev> is needed to access GPIO. Used by the saa_readl macro. */
struct saa7134_dev *dev = ir->c->adapter->algo_data;
@@ -193,8 +196,11 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir,
/* GPIO says there is a button press. Get it. */
- if (1 != i2c_master_recv(ir->c, &b, 1)) {
+ rc = i2c_master_recv(ir->c, &b, 1);
+ if (rc != 1) {
ir_dbg(ir, "read error\n");
+ if (rc < 0)
+ return rc;
return -EIO;
}
@@ -218,6 +224,7 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_proto *protocol,
{
unsigned char b;
unsigned int gpio;
+ int rc;
/* <dev> is needed to access GPIO. Used by the saa_readl macro. */
struct saa7134_dev *dev = ir->c->adapter->algo_data;
@@ -241,8 +248,11 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_proto *protocol,
/* GPIO says there is a button press. Get it. */
- if (1 != i2c_master_recv(ir->c, &b, 1)) {
+ rc = i2c_master_recv(ir->c, &b, 1);
+ if (rc != 1) {
ir_dbg(ir, "read error\n");
+ if (rc < 0)
+ return rc;
return -EIO;
}
@@ -263,11 +273,15 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_proto *protocol,
static int get_key_purpletv(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
+ int rc;
unsigned char b;
/* poll IR chip */
- if (1 != i2c_master_recv(ir->c, &b, 1)) {
+ rc = i2c_master_recv(ir->c, &b, 1);
+ if (rc != 1) {
ir_dbg(ir, "read error\n");
+ if (rc < 0)
+ return rc;
return -EIO;
}
@@ -288,11 +302,17 @@ static int get_key_purpletv(struct IR_i2c *ir, enum rc_proto *protocol,
static int get_key_hvr1110(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
+ int rc;
unsigned char buf[5];
/* poll IR chip */
- if (5 != i2c_master_recv(ir->c, buf, 5))
+ rc = i2c_master_recv(ir->c, buf, 5);
+ if (rc != 5) {
+ ir_dbg(ir, "read error\n");
+ if (rc < 0)
+ return rc;
return -EIO;
+ }
/* Check if some key were pressed */
if (!(buf[0] & 0x80))
@@ -319,6 +339,7 @@ static int get_key_hvr1110(struct IR_i2c *ir, enum rc_proto *protocol,
static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle)
{
+ int rc;
unsigned char data[12];
u32 gpio;
@@ -335,8 +356,11 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_proto *protocol,
ir->c->addr = 0x5a >> 1;
- if (12 != i2c_master_recv(ir->c, data, 12)) {
+ rc = i2c_master_recv(ir->c, data, 12);
+ if (rc != 12) {
ir_dbg(ir, "read error\n");
+ if (rc < 0)
+ return rc;
return -EIO;
}
@@ -356,12 +380,16 @@ static int get_key_pinnacle(struct IR_i2c *ir, enum rc_proto *protocol,
u32 *scancode, u8 *toggle, int parity_offset,
int marker, int code_modulo)
{
+ int rc;
unsigned char b[4];
unsigned int start = 0,parity = 0,code = 0;
/* poll IR chip */
- if (4 != i2c_master_recv(ir->c, b, 4)) {
+ rc = i2c_master_recv(ir->c, b, 4);
+ if (rc != 4) {
ir_dbg(ir, "read error\n");
+ if (rc < 0)
+ return rc;
return -EIO;
}
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 1ca6a32ad10e..4f1091a11e91 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -1200,7 +1200,7 @@ static int video_release(struct file *file)
saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0);
saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0);
- saa_call_all(dev, core, s_power, 0);
+ saa_call_all(dev, tuner, standby);
if (vdev->vfl_type == VFL_TYPE_RADIO)
saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
mutex_unlock(&dev->lock);
diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c
index e76d3bafe2ce..4f9f03c3b252 100644
--- a/drivers/media/pci/saa7164/saa7164-dvb.c
+++ b/drivers/media/pci/saa7164/saa7164-dvb.c
@@ -78,7 +78,7 @@ static struct s5h1411_config hauppauge_s5h1411_config = {
.vsb_if = S5H1411_IF_3250,
.inversion = S5H1411_INVERSION_ON,
.status_mode = S5H1411_DEMODLOCKING,
- .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static struct lgdt3306a_config hauppauge_hvr2255a_config = {
diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c
index 81be1b8df758..2ac33b5cc454 100644
--- a/drivers/media/pci/solo6x10/solo6x10-g723.c
+++ b/drivers/media/pci/solo6x10/solo6x10-g723.c
@@ -223,9 +223,9 @@ static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss)
return idx * G723_FRAMES_PER_PAGE;
}
-static int __snd_solo_pcm_copy(struct snd_pcm_substream *ss,
- unsigned long pos, void *dst,
- unsigned long count, bool in_kernel)
+static int snd_solo_pcm_copy_user(struct snd_pcm_substream *ss, int channel,
+ unsigned long pos, void __user *dst,
+ unsigned long count)
{
struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
struct solo_dev *solo_dev = solo_pcm->solo_dev;
@@ -242,10 +242,7 @@ static int __snd_solo_pcm_copy(struct snd_pcm_substream *ss,
if (err)
return err;
- if (in_kernel)
- memcpy(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES);
- else if (copy_to_user((void __user *)dst,
- solo_pcm->g723_buf, G723_PERIOD_BYTES))
+ if (copy_to_user(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES))
return -EFAULT;
dst += G723_PERIOD_BYTES;
}
@@ -253,18 +250,30 @@ static int __snd_solo_pcm_copy(struct snd_pcm_substream *ss,
return 0;
}
-static int snd_solo_pcm_copy_user(struct snd_pcm_substream *ss, int channel,
- unsigned long pos, void __user *dst,
- unsigned long count)
-{
- return __snd_solo_pcm_copy(ss, pos, (void *)dst, count, false);
-}
-
static int snd_solo_pcm_copy_kernel(struct snd_pcm_substream *ss, int channel,
unsigned long pos, void *dst,
unsigned long count)
{
- return __snd_solo_pcm_copy(ss, pos, dst, count, true);
+ struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
+ struct solo_dev *solo_dev = solo_pcm->solo_dev;
+ int err, i;
+
+ for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) {
+ int page = (pos / G723_FRAMES_PER_PAGE) + i;
+
+ err = solo_p2m_dma_t(solo_dev, 0, solo_pcm->g723_dma,
+ SOLO_G723_EXT_ADDR(solo_dev) +
+ (page * G723_PERIOD_BLOCK) +
+ (ss->number * G723_PERIOD_BYTES),
+ G723_PERIOD_BYTES, 0, 0);
+ if (err)
+ return err;
+
+ memcpy(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES);
+ dst += G723_PERIOD_BYTES;
+ }
+
+ return 0;
}
static const struct snd_pcm_ops snd_solo_pcm_ops = {
diff --git a/drivers/media/pci/solo6x10/solo6x10-p2m.c b/drivers/media/pci/solo6x10/solo6x10-p2m.c
index 8c8484674d2f..46c30430e30b 100644
--- a/drivers/media/pci/solo6x10/solo6x10-p2m.c
+++ b/drivers/media/pci/solo6x10/solo6x10-p2m.c
@@ -69,14 +69,11 @@ int solo_p2m_dma_desc(struct solo_dev *solo_dev,
unsigned int timeout;
unsigned int config = 0;
int ret = 0;
- int p2m_id = 0;
+ unsigned int p2m_id = 0;
/* Get next ID. According to Softlogic, 6110 has problems on !=0 P2M */
- if (solo_dev->type != SOLO_DEV_6110 && multi_p2m) {
+ if (solo_dev->type != SOLO_DEV_6110 && multi_p2m)
p2m_id = atomic_inc_return(&solo_dev->p2m_count) % SOLO_NR_P2M;
- if (p2m_id < 0)
- p2m_id = -p2m_id;
- }
p2m_dev = &solo_dev->p2m_dev[p2m_id];
diff --git a/drivers/media/pci/ttpci/ttpci-eeprom.c b/drivers/media/pci/ttpci/ttpci-eeprom.c
index 9534f29c1ffd..78c7a6589be5 100644
--- a/drivers/media/pci/ttpci/ttpci-eeprom.c
+++ b/drivers/media/pci/ttpci/ttpci-eeprom.c
@@ -138,7 +138,7 @@ static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encode
int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac)
{
- int ret, i;
+ int ret;
u8 encodedMAC[20];
u8 decodedMAC[6];
@@ -153,11 +153,8 @@ int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac)
ret = getmac_tt(decodedMAC, encodedMAC);
if( ret != 0 ) {
dprintk("adapter failed MAC signature check\n");
- dprintk("encoded MAC from EEPROM was " );
- for(i=0; i<19; i++) {
- dprintk( "%.2x:", encodedMAC[i]);
- }
- dprintk("%.2x\n", encodedMAC[19]);
+ dprintk("encoded MAC from EEPROM was %*phC",
+ (int)sizeof(encodedMAC), &encodedMAC);
eth_zero_addr(proposed_mac);
return ret;
}
diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c
index 8d4e7d930a66..14f9c0e26a1c 100644
--- a/drivers/media/pci/zoran/zoran_driver.c
+++ b/drivers/media/pci/zoran/zoran_driver.c
@@ -241,8 +241,8 @@ static int v4l_fbuffer_alloc(struct zoran_fh *fh)
SetPageReserved(virt_to_page(mem + off));
dprintk(4,
KERN_INFO
- "%s: %s - V4L frame %d mem 0x%lx (bus: 0x%llx)\n",
- ZR_DEVNAME(zr), __func__, i, (unsigned long) mem,
+ "%s: %s - V4L frame %d mem %p (bus: 0x%llx)\n",
+ ZR_DEVNAME(zr), __func__, i, mem,
(unsigned long long)virt_to_bus(mem));
}
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 6df9ec377482..c7a1cf8a1b01 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -122,6 +122,15 @@ config VIDEO_STM32_DCMI
To compile this driver as a module, choose M here: the module
will be called stm32-dcmi.
+config VIDEO_RENESAS_CEU
+ tristate "Renesas Capture Engine Unit (CEU) driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
+ depends on ARCH_SHMOBILE || ARCH_R7S72100 || COMPILE_TEST
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_FWNODE
+ ---help---
+ This is a v4l2 driver for the Renesas CEU Interface
+
source "drivers/media/platform/soc_camera/Kconfig"
source "drivers/media/platform/exynos4-is/Kconfig"
source "drivers/media/platform/am437x/Kconfig"
@@ -560,7 +569,7 @@ config CEC_GPIO
config VIDEO_SAMSUNG_S5P_CEC
tristate "Samsung S5P CEC driver"
- depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
+ depends on ARCH_EXYNOS || COMPILE_TEST
select CEC_CORE
select CEC_NOTIFIER
---help---
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index db96a3cb18dd..932515df4477 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o
obj-$(CONFIG_SOC_CAMERA) += soc_camera/
obj-$(CONFIG_VIDEO_RCAR_DRIF) += rcar_drif.o
+obj-$(CONFIG_VIDEO_RENESAS_CEU) += renesas-ceu.o
obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o
obj-$(CONFIG_VIDEO_RENESAS_FDP1) += rcar_fdp1.o
obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o
diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c
index 34676409ca08..d89e14524d42 100644
--- a/drivers/media/platform/atmel/atmel-isc.c
+++ b/drivers/media/platform/atmel/atmel-isc.c
@@ -335,7 +335,7 @@ static struct isc_format formats_list[] = {
},
};
-struct fmt_config fmt_configs_list[] = {
+static struct fmt_config fmt_configs_list[] = {
{
.fourcc = V4L2_PIX_FMT_SBGGR8,
.pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
@@ -1417,20 +1417,14 @@ static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
{
struct isc_device *isc = video_drvdata(file);
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- return v4l2_subdev_call(isc->current_subdev->sd, video, g_parm, a);
+ return v4l2_g_parm_cap(video_devdata(file), isc->current_subdev->sd, a);
}
static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
{
struct isc_device *isc = video_drvdata(file);
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- return v4l2_subdev_call(isc->current_subdev->sd, video, s_parm, a);
+ return v4l2_s_parm_cap(video_devdata(file), isc->current_subdev->sd, a);
}
static int isc_enum_framesizes(struct file *file, void *fh,
diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c
index 9958918e2449..e5be21a31640 100644
--- a/drivers/media/platform/atmel/atmel-isi.c
+++ b/drivers/media/platform/atmel/atmel-isi.c
@@ -689,22 +689,14 @@ static int isi_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
{
struct atmel_isi *isi = video_drvdata(file);
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- a->parm.capture.readbuffers = 2;
- return v4l2_subdev_call(isi->entity.subdev, video, g_parm, a);
+ return v4l2_g_parm_cap(video_devdata(file), isi->entity.subdev, a);
}
static int isi_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
{
struct atmel_isi *isi = video_drvdata(file);
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- a->parm.capture.readbuffers = 2;
- return v4l2_subdev_call(isi->entity.subdev, video, s_parm, a);
+ return v4l2_s_parm_cap(video_devdata(file), isi->entity.subdev, a);
}
static int isi_enum_framesizes(struct file *file, void *fh,
diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c
index 5debdf08fbe7..f1f28cf5c751 100644
--- a/drivers/media/platform/cec-gpio/cec-gpio.c
+++ b/drivers/media/platform/cec-gpio/cec-gpio.c
@@ -1,18 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/module.h>
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index 9fe113cb901f..68ed2a564ad1 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -68,8 +68,9 @@ static void coda_command_async(struct coda_ctx *ctx, int cmd)
{
struct coda_dev *dev = ctx->dev;
- if (dev->devtype->product == CODA_960 ||
- dev->devtype->product == CODA_7541) {
+ if (dev->devtype->product == CODA_HX4 ||
+ dev->devtype->product == CODA_7541 ||
+ dev->devtype->product == CODA_960) {
/* Restore context related registers to CODA */
coda_write(dev, ctx->bit_stream_param,
CODA_REG_BIT_BIT_STREAM_PARAM);
@@ -506,7 +507,8 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx,
goto err;
}
- if (!ctx->psbuf.vaddr && dev->devtype->product == CODA_7541) {
+ if (!ctx->psbuf.vaddr && (dev->devtype->product == CODA_HX4 ||
+ dev->devtype->product == CODA_7541)) {
ret = coda_alloc_context_buf(ctx, &ctx->psbuf,
CODA7_PS_BUF_SIZE, "psbuf");
if (ret < 0)
@@ -594,6 +596,7 @@ static void coda_setup_iram(struct coda_ctx *ctx)
int dbk_bits;
int bit_bits;
int ip_bits;
+ int me_bits;
memset(iram_info, 0, sizeof(*iram_info));
iram_info->next_paddr = dev->iram.paddr;
@@ -603,15 +606,23 @@ static void coda_setup_iram(struct coda_ctx *ctx)
return;
switch (dev->devtype->product) {
+ case CODA_HX4:
+ dbk_bits = CODA7_USE_HOST_DBK_ENABLE;
+ bit_bits = CODA7_USE_HOST_BIT_ENABLE;
+ ip_bits = CODA7_USE_HOST_IP_ENABLE;
+ me_bits = CODA7_USE_HOST_ME_ENABLE;
+ break;
case CODA_7541:
dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE;
bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
+ me_bits = CODA7_USE_HOST_ME_ENABLE | CODA7_USE_ME_ENABLE;
break;
case CODA_960:
dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE;
bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
+ me_bits = 0;
break;
default: /* CODA_DX6 */
return;
@@ -626,7 +637,8 @@ static void coda_setup_iram(struct coda_ctx *ctx)
w64 = mb_width * 64;
/* Prioritize in case IRAM is too small for everything */
- if (dev->devtype->product == CODA_7541) {
+ if (dev->devtype->product == CODA_HX4 ||
+ dev->devtype->product == CODA_7541) {
iram_info->search_ram_size = round_up(mb_width * 16 *
36 + 2048, 1024);
iram_info->search_ram_paddr = coda_iram_alloc(iram_info,
@@ -635,8 +647,7 @@ static void coda_setup_iram(struct coda_ctx *ctx)
pr_err("IRAM is smaller than the search ram size\n");
goto out;
}
- iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE |
- CODA7_USE_ME_ENABLE;
+ iram_info->axi_sram_use |= me_bits;
}
/* Only H.264BP and H.263P3 are considered */
@@ -688,7 +699,8 @@ out:
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"IRAM smaller than needed\n");
- if (dev->devtype->product == CODA_7541) {
+ if (dev->devtype->product == CODA_HX4 ||
+ dev->devtype->product == CODA_7541) {
/* TODO - Enabling these causes picture errors on CODA7541 */
if (ctx->inst_type == CODA_INST_DECODER) {
/* fw 1.4.50 */
@@ -706,6 +718,7 @@ out:
static u32 coda_supported_firmwares[] = {
CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
+ CODA_FIRMWARE_VERNUM(CODA_HX4, 1, 4, 50),
CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50),
CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5),
CODA_FIRMWARE_VERNUM(CODA_960, 2, 3, 10),
@@ -890,6 +903,7 @@ static int coda_start_encoding(struct coda_ctx *ctx)
case CODA_960:
coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
/* fallthrough */
+ case CODA_HX4:
case CODA_7541:
coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN |
CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
@@ -919,6 +933,7 @@ static int coda_start_encoding(struct coda_ctx *ctx)
value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK)
<< CODA_PICHEIGHT_OFFSET;
break;
+ case CODA_HX4:
case CODA_7541:
if (dst_fourcc == V4L2_PIX_FMT_H264) {
value = (round_up(q_data_src->width, 16) &
@@ -1086,6 +1101,7 @@ static int coda_start_encoding(struct coda_ctx *ctx)
value = FMO_SLICE_SAVE_BUF_SIZE << 7;
coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO);
break;
+ case CODA_HX4:
case CODA_7541:
coda_write(dev, ctx->iram_info.search_ram_paddr,
CODA7_CMD_ENC_SEQ_SEARCH_BASE);
@@ -1131,7 +1147,8 @@ static int coda_start_encoding(struct coda_ctx *ctx)
coda_write(dev, num_fb, CODA_CMD_SET_FRAME_BUF_NUM);
coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE);
- if (dev->devtype->product == CODA_7541) {
+ if (dev->devtype->product == CODA_HX4 ||
+ dev->devtype->product == CODA_7541) {
coda_write(dev, q_data_src->bytesperline,
CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
}
@@ -1570,7 +1587,8 @@ static bool coda_reorder_enable(struct coda_ctx *ctx)
struct coda_dev *dev = ctx->dev;
int profile, level;
- if (dev->devtype->product != CODA_7541 &&
+ if (dev->devtype->product != CODA_HX4 &&
+ dev->devtype->product != CODA_7541 &&
dev->devtype->product != CODA_960)
return false;
@@ -1664,7 +1682,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
CODA_CMD_DEC_SEQ_MP4_ASP_CLASS);
}
if (src_fourcc == V4L2_PIX_FMT_H264) {
- if (dev->devtype->product == CODA_7541) {
+ if (dev->devtype->product == CODA_HX4 ||
+ dev->devtype->product == CODA_7541) {
coda_write(dev, ctx->psbuf.paddr,
CODA_CMD_DEC_SEQ_PS_BB_START);
coda_write(dev, (CODA7_PS_BUF_SIZE / 1024),
@@ -1791,7 +1810,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
CODA_CMD_SET_FRAME_SLICE_BB_SIZE);
}
- if (dev->devtype->product == CODA_7541) {
+ if (dev->devtype->product == CODA_HX4 ||
+ dev->devtype->product == CODA_7541) {
int max_mb_x = 1920 / 16;
int max_mb_y = 1088 / 16;
int max_mb_num = max_mb_x * max_mb_y;
@@ -1909,6 +1929,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
switch (dev->devtype->product) {
case CODA_DX6:
/* TBD */
+ case CODA_HX4:
case CODA_7541:
coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION);
break;
@@ -2049,7 +2070,8 @@ static void coda_finish_decode(struct coda_ctx *ctx)
v4l2_err(&dev->v4l2_dev,
"errors in %d macroblocks\n", err_mb);
- if (dev->devtype->product == CODA_7541) {
+ if (dev->devtype->product == CODA_HX4 ||
+ dev->devtype->product == CODA_7541) {
val = coda_read(dev, CODA_RET_DEC_PIC_OPTION);
if (val == 0) {
/* not enough bitstream data */
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index e8a7554a61d2..04e35d70ce2e 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -128,7 +128,8 @@ void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data,
/*
* Arrays of codecs supported by each given version of Coda:
* i.MX27 -> codadx6
- * i.MX5x -> coda7
+ * i.MX51 -> codahx4
+ * i.MX53 -> coda7
* i.MX6 -> coda960
* Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants
*/
@@ -137,6 +138,13 @@ static const struct coda_codec codadx6_codecs[] = {
CODA_CODEC(CODADX6_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576),
};
+static const struct coda_codec codahx4_codecs[] = {
+ CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576),
+ CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088),
+ CODA_CODEC(CODA7_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088),
+ CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1280, 720),
+};
+
static const struct coda_codec coda7_codecs[] = {
CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720),
CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720),
@@ -234,6 +242,11 @@ static const struct coda_video_device *codadx6_video_devices[] = {
&coda_bit_encoder,
};
+static const struct coda_video_device *codahx4_video_devices[] = {
+ &coda_bit_encoder,
+ &coda_bit_decoder,
+};
+
static const struct coda_video_device *coda7_video_devices[] = {
&coda_bit_jpeg_encoder,
&coda_bit_jpeg_decoder,
@@ -332,6 +345,8 @@ const char *coda_product_name(int product)
switch (product) {
case CODA_DX6:
return "CodaDx6";
+ case CODA_HX4:
+ return "CodaHx4";
case CODA_7541:
return "CODA7541";
case CODA_960:
@@ -1775,7 +1790,8 @@ static void coda_encode_ctrls(struct coda_ctx *ctx)
V4L2_CID_MPEG_VIDEO_H264_PROFILE,
V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0,
V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE);
- if (ctx->dev->devtype->product == CODA_7541) {
+ if (ctx->dev->devtype->product == CODA_HX4 ||
+ ctx->dev->devtype->product == CODA_7541) {
v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_LEVEL,
V4L2_MPEG_VIDEO_H264_LEVEL_3_1,
@@ -1803,7 +1819,8 @@ static void coda_encode_ctrls(struct coda_ctx *ctx)
V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, 0x0,
V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE);
- if (ctx->dev->devtype->product == CODA_7541 ||
+ if (ctx->dev->devtype->product == CODA_HX4 ||
+ ctx->dev->devtype->product == CODA_7541 ||
ctx->dev->devtype->product == CODA_960) {
v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
@@ -2004,6 +2021,7 @@ static int coda_open(struct file *file)
if (enable_bwb || ctx->inst_type == CODA_INST_ENCODER)
ctx->frame_mem_ctrl = CODA9_FRAME_ENABLE_BWB;
/* fallthrough */
+ case CODA_HX4:
case CODA_7541:
ctx->reg_idx = 0;
break;
@@ -2182,7 +2200,8 @@ static int coda_hw_init(struct coda_dev *dev)
/* Tell the BIT where to find everything it needs */
if (dev->devtype->product == CODA_960 ||
- dev->devtype->product == CODA_7541) {
+ dev->devtype->product == CODA_7541 ||
+ dev->devtype->product == CODA_HX4) {
coda_write(dev, dev->tempbuf.paddr,
CODA_REG_BIT_TEMP_BUF_ADDR);
coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
@@ -2387,6 +2406,7 @@ put_pm:
enum coda_platform {
CODA_IMX27,
+ CODA_IMX51,
CODA_IMX53,
CODA_IMX6Q,
CODA_IMX6DL,
@@ -2407,6 +2427,21 @@ static const struct coda_devtype coda_devdata[] = {
.workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024,
.iram_size = 0xb000,
},
+ [CODA_IMX51] = {
+ .firmware = {
+ "vpu_fw_imx51.bin",
+ "vpu/vpu_fw_imx51.bin",
+ "v4l-codahx4-imx51.bin"
+ },
+ .product = CODA_HX4,
+ .codecs = codahx4_codecs,
+ .num_codecs = ARRAY_SIZE(codahx4_codecs),
+ .vdevs = codahx4_video_devices,
+ .num_vdevs = ARRAY_SIZE(codahx4_video_devices),
+ .workbuf_size = 128 * 1024,
+ .tempbuf_size = 304 * 1024,
+ .iram_size = 0x14000,
+ },
[CODA_IMX53] = {
.firmware = {
"vpu_fw_imx53.bin",
@@ -2463,6 +2498,7 @@ MODULE_DEVICE_TABLE(platform, coda_platform_ids);
#ifdef CONFIG_OF
static const struct of_device_id coda_dt_ids[] = {
{ .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] },
+ { .compatible = "fsl,imx51-vpu", .data = &coda_devdata[CODA_IMX51] },
{ .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] },
{ .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] },
{ .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] },
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
index c5f504d8cf67..c70cfab2433f 100644
--- a/drivers/media/platform/coda/coda.h
+++ b/drivers/media/platform/coda/coda.h
@@ -28,7 +28,7 @@
#include "coda_regs.h"
-#define CODA_MAX_FRAMEBUFFERS 17
+#define CODA_MAX_FRAMEBUFFERS 19
#define FMO_SLICE_SAVE_BUF_SIZE (32)
enum {
@@ -43,6 +43,7 @@ enum coda_inst_type {
enum coda_product {
CODA_DX6 = 0xf001,
+ CODA_HX4 = 0xf00a,
CODA_7541 = 0xf012,
CODA_960 = 0xf020,
};
diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c
index b73886519f4f..19cf6853411e 100644
--- a/drivers/media/platform/davinci/vpss.c
+++ b/drivers/media/platform/davinci/vpss.c
@@ -116,7 +116,7 @@ struct vpss_hw_ops {
struct vpss_oper_config {
__iomem void *vpss_regs_base0;
__iomem void *vpss_regs_base1;
- resource_size_t *vpss_regs_base2;
+ __iomem void *vpss_regs_base2;
enum vpss_platform_type platform;
spinlock_t vpss_lock;
struct vpss_hw_ops hw_ops;
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index ed9302caa004..a3cdac188190 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -670,10 +670,13 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx,
return;
}
if (target == V4L2_SEL_TGT_COMPOSE) {
+ u32 tmp_min_h = ffs(sink->width) - 3;
+ u32 tmp_min_v = ffs(sink->height) - 1;
+
if (ctx->rotation != 90 && ctx->rotation != 270)
align_h = 1;
- max_sc_h = min(SCALER_MAX_HRATIO, 1 << (ffs(sink->width) - 3));
- max_sc_v = min(SCALER_MAX_VRATIO, 1 << (ffs(sink->height) - 1));
+ max_sc_h = min(SCALER_MAX_HRATIO, 1 << tmp_min_h);
+ max_sc_v = min(SCALER_MAX_VRATIO, 1 << tmp_min_v);
min_sz = var->min_out_pixsize;
} else {
u32 depth = fimc_get_format_depth(sink->fmt);
diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c
index cfe4406a83ff..e0e291066037 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-regs.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c
@@ -159,7 +159,7 @@ void fimc_is_hw_load_setfile(struct fimc_is *is)
int fimc_is_hw_change_mode(struct fimc_is *is)
{
- const u8 cmd[] = {
+ static const u8 cmd[] = {
HIC_PREVIEW_STILL, HIC_PREVIEW_VIDEO,
HIC_CAPTURE_STILL, HIC_CAPTURE_VIDEO,
};
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index 7b7250b1cff8..80670eeee142 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -1443,24 +1443,24 @@ static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
* the level which controls the number of read buffers.
*/
static int mcam_vidioc_g_parm(struct file *filp, void *priv,
- struct v4l2_streamparm *parms)
+ struct v4l2_streamparm *a)
{
struct mcam_camera *cam = video_drvdata(filp);
int ret;
- ret = sensor_call(cam, video, g_parm, parms);
- parms->parm.capture.readbuffers = n_dma_bufs;
+ ret = v4l2_g_parm_cap(video_devdata(filp), cam->sensor, a);
+ a->parm.capture.readbuffers = n_dma_bufs;
return ret;
}
static int mcam_vidioc_s_parm(struct file *filp, void *priv,
- struct v4l2_streamparm *parms)
+ struct v4l2_streamparm *a)
{
struct mcam_camera *cam = video_drvdata(filp);
int ret;
- ret = sensor_call(cam, video, s_parm, parms);
- parms->parm.capture.readbuffers = n_dma_bufs;
+ ret = v4l2_s_parm_cap(video_devdata(filp), cam->sensor, a);
+ a->parm.capture.readbuffers = n_dma_bufs;
return ret;
}
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
index 843510979ad8..86f0a7134365 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
@@ -1224,6 +1224,8 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
ctx->dpb_size = dpbsize;
ctx->state = MTK_STATE_HEADER;
mtk_v4l2_debug(1, "[%d] dpbsize=%d", ctx->id, ctx->dpb_size);
+
+ mtk_vdec_queue_res_chg_event(ctx);
}
static void vb2ops_vdec_buf_finish(struct vb2_buffer *vb)
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c
index 123c2b26a933..1d8508237220 100644
--- a/drivers/media/platform/omap/omap_vout_vrfb.c
+++ b/drivers/media/platform/omap/omap_vout_vrfb.c
@@ -236,7 +236,6 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
struct dma_async_tx_descriptor *tx;
enum dma_ctrl_flags flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
struct dma_chan *chan = vout->vrfb_dma_tx.chan;
- struct dma_device *dmadev = chan->device;
struct dma_interleaved_template *xt = vout->vrfb_dma_tx.xt;
dma_cookie_t cookie;
enum dma_status status;
@@ -271,7 +270,7 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
xt->dst_sgl = true;
xt->dst_inc = true;
- tx = dmadev->device_prep_interleaved_dma(chan, xt, flags);
+ tx = dmaengine_prep_interleaved_dma(chan, xt, flags);
if (tx == NULL) {
pr_err("%s: DMA interleaved prep error\n", __func__);
return -EINVAL;
diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c
index a681ae5381d6..90c93d9603dc 100644
--- a/drivers/media/platform/qcom/venus/hfi_msgs.c
+++ b/drivers/media/platform/qcom/venus/hfi_msgs.c
@@ -659,10 +659,10 @@ static u32 init_done_read_prop(struct venus_core *core, struct venus_inst *inst,
prop->buffer_type == HFI_BUFFER_OUTPUT2) {
switch (prop->data[i]) {
case HFI_BUFFER_MODE_STATIC:
- inst->cap_bufs_mode_static = 1;
+ inst->cap_bufs_mode_static = true;
break;
case HFI_BUFFER_MODE_DYNAMIC:
- inst->cap_bufs_mode_dynamic = 1;
+ inst->cap_bufs_mode_dynamic = true;
break;
default:
break;
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index 23fdff7a7370..4a40e6ad1be7 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -168,12 +168,8 @@ static int rvin_setup(struct rvin_dev *vin)
break;
case V4L2_FIELD_ALTERNATE:
case V4L2_FIELD_NONE:
- if (vin->continuous) {
- vnmc = VNMC_IM_ODD_EVEN;
- progressive = true;
- } else {
- vnmc = VNMC_IM_ODD;
- }
+ vnmc = VNMC_IM_ODD_EVEN;
+ progressive = true;
break;
default:
vnmc = VNMC_IM_ODD;
@@ -298,14 +294,6 @@ static bool rvin_capture_active(struct rvin_dev *vin)
return rvin_read(vin, VNMS_REG) & VNMS_CA;
}
-static int rvin_get_active_slot(struct rvin_dev *vin, u32 vnms)
-{
- if (vin->continuous)
- return (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT;
-
- return 0;
-}
-
static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms)
{
if (vin->format.field == V4L2_FIELD_ALTERNATE) {
@@ -344,76 +332,47 @@ static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr)
rvin_write(vin, offset, VNMB_REG(slot));
}
-/* Moves a buffer from the queue to the HW slots */
-static bool rvin_fill_hw_slot(struct rvin_dev *vin, int slot)
+/*
+ * Moves a buffer from the queue to the HW slot. If no buffer is
+ * available use the scratch buffer. The scratch buffer is never
+ * returned to userspace, its only function is to enable the capture
+ * loop to keep running.
+ */
+static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot)
{
struct rvin_buffer *buf;
struct vb2_v4l2_buffer *vbuf;
- dma_addr_t phys_addr_top;
-
- if (vin->queue_buf[slot] != NULL)
- return true;
+ dma_addr_t phys_addr;
- if (list_empty(&vin->buf_list))
- return false;
+ /* A already populated slot shall never be overwritten. */
+ if (WARN_ON(vin->queue_buf[slot] != NULL))
+ return;
vin_dbg(vin, "Filling HW slot: %d\n", slot);
- /* Keep track of buffer we give to HW */
- buf = list_entry(vin->buf_list.next, struct rvin_buffer, list);
- vbuf = &buf->vb;
- list_del_init(to_buf_list(vbuf));
- vin->queue_buf[slot] = vbuf;
-
- /* Setup DMA */
- phys_addr_top = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
- rvin_set_slot_addr(vin, slot, phys_addr_top);
-
- return true;
-}
-
-static bool rvin_fill_hw(struct rvin_dev *vin)
-{
- int slot, limit;
-
- limit = vin->continuous ? HW_BUFFER_NUM : 1;
-
- for (slot = 0; slot < limit; slot++)
- if (!rvin_fill_hw_slot(vin, slot))
- return false;
- return true;
-}
-
-static void rvin_capture_on(struct rvin_dev *vin)
-{
- vin_dbg(vin, "Capture on in %s mode\n",
- vin->continuous ? "continuous" : "single");
+ if (list_empty(&vin->buf_list)) {
+ vin->queue_buf[slot] = NULL;
+ phys_addr = vin->scratch_phys;
+ } else {
+ /* Keep track of buffer we give to HW */
+ buf = list_entry(vin->buf_list.next, struct rvin_buffer, list);
+ vbuf = &buf->vb;
+ list_del_init(to_buf_list(vbuf));
+ vin->queue_buf[slot] = vbuf;
+
+ /* Setup DMA */
+ phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
+ }
- if (vin->continuous)
- /* Continuous Frame Capture Mode */
- rvin_write(vin, VNFC_C_FRAME, VNFC_REG);
- else
- /* Single Frame Capture Mode */
- rvin_write(vin, VNFC_S_FRAME, VNFC_REG);
+ rvin_set_slot_addr(vin, slot, phys_addr);
}
static int rvin_capture_start(struct rvin_dev *vin)
{
- struct rvin_buffer *buf, *node;
- int bufs, ret;
-
- /* Count number of free buffers */
- bufs = 0;
- list_for_each_entry_safe(buf, node, &vin->buf_list, list)
- bufs++;
+ int slot, ret;
- /* Continuous capture requires more buffers then there are HW slots */
- vin->continuous = bufs > HW_BUFFER_NUM;
-
- if (!rvin_fill_hw(vin)) {
- vin_err(vin, "HW not ready to start, not enough buffers available\n");
- return -EINVAL;
- }
+ for (slot = 0; slot < HW_BUFFER_NUM; slot++)
+ rvin_fill_hw_slot(vin, slot);
rvin_crop_scale_comp(vin);
@@ -421,7 +380,10 @@ static int rvin_capture_start(struct rvin_dev *vin)
if (ret)
return ret;
- rvin_capture_on(vin);
+ vin_dbg(vin, "Starting to capture\n");
+
+ /* Continuous Frame Capture Mode */
+ rvin_write(vin, VNFC_C_FRAME, VNFC_REG);
vin->state = RUNNING;
@@ -904,7 +866,7 @@ static irqreturn_t rvin_irq(int irq, void *data)
struct rvin_dev *vin = data;
u32 int_status, vnms;
int slot;
- unsigned int i, sequence, handled = 0;
+ unsigned int handled = 0;
unsigned long flags;
spin_lock_irqsave(&vin->qlock, flags);
@@ -930,65 +892,25 @@ static irqreturn_t rvin_irq(int irq, void *data)
/* Prepare for capture and update state */
vnms = rvin_read(vin, VNMS_REG);
- slot = rvin_get_active_slot(vin, vnms);
- sequence = vin->sequence++;
-
- vin_dbg(vin, "IRQ %02d: %d\tbuf0: %c buf1: %c buf2: %c\tmore: %d\n",
- sequence, slot,
- slot == 0 ? 'x' : vin->queue_buf[0] != NULL ? '1' : '0',
- slot == 1 ? 'x' : vin->queue_buf[1] != NULL ? '1' : '0',
- slot == 2 ? 'x' : vin->queue_buf[2] != NULL ? '1' : '0',
- !list_empty(&vin->buf_list));
-
- /* HW have written to a slot that is not prepared we are in trouble */
- if (WARN_ON((vin->queue_buf[slot] == NULL)))
- goto done;
+ slot = (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT;
/* Capture frame */
- vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms);
- vin->queue_buf[slot]->sequence = sequence;
- vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
- vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, VB2_BUF_STATE_DONE);
- vin->queue_buf[slot] = NULL;
-
- /* Prepare for next frame */
- if (!rvin_fill_hw(vin)) {
-
- /*
- * Can't supply HW with new buffers fast enough. Halt
- * capture until more buffers are available.
- */
- vin->state = STALLED;
-
- /*
- * The continuous capturing requires an explicit stop
- * operation when there is no buffer to be set into
- * the VnMBm registers.
- */
- if (vin->continuous) {
- rvin_capture_stop(vin);
- vin_dbg(vin, "IRQ %02d: hw not ready stop\n", sequence);
-
- /* Maybe we can continue in single capture mode */
- for (i = 0; i < HW_BUFFER_NUM; i++) {
- if (vin->queue_buf[i]) {
- list_add(to_buf_list(vin->queue_buf[i]),
- &vin->buf_list);
- vin->queue_buf[i] = NULL;
- }
- }
-
- if (!list_empty(&vin->buf_list))
- rvin_capture_start(vin);
- }
+ if (vin->queue_buf[slot]) {
+ vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms);
+ vin->queue_buf[slot]->sequence = vin->sequence;
+ vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
+ vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf,
+ VB2_BUF_STATE_DONE);
+ vin->queue_buf[slot] = NULL;
} else {
- /*
- * The single capturing requires an explicit capture
- * operation to fetch the next frame.
- */
- if (!vin->continuous)
- rvin_capture_on(vin);
+ /* Scratch buffer was used, dropping frame. */
+ vin_dbg(vin, "Dropping frame %u\n", vin->sequence);
}
+
+ vin->sequence++;
+
+ /* Prepare for next frame */
+ rvin_fill_hw_slot(vin, slot);
done:
spin_unlock_irqrestore(&vin->qlock, flags);
@@ -1059,13 +981,6 @@ static void rvin_buffer_queue(struct vb2_buffer *vb)
list_add_tail(to_buf_list(vbuf), &vin->buf_list);
- /*
- * If capture is stalled add buffer to HW and restart
- * capturing if HW is ready to continue.
- */
- if (vin->state == STALLED)
- rvin_capture_start(vin);
-
spin_unlock_irqrestore(&vin->qlock, flags);
}
@@ -1076,6 +991,17 @@ static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count)
unsigned long flags;
int ret;
+ /* Allocate scratch buffer. */
+ vin->scratch = dma_alloc_coherent(vin->dev, vin->format.sizeimage,
+ &vin->scratch_phys, GFP_KERNEL);
+ if (!vin->scratch) {
+ spin_lock_irqsave(&vin->qlock, flags);
+ return_all_buffers(vin, VB2_BUF_STATE_QUEUED);
+ spin_unlock_irqrestore(&vin->qlock, flags);
+ vin_err(vin, "Failed to allocate scratch buffer\n");
+ return -ENOMEM;
+ }
+
sd = vin_to_source(vin);
v4l2_subdev_call(sd, video, s_stream, 1);
@@ -1091,6 +1017,10 @@ static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count)
spin_unlock_irqrestore(&vin->qlock, flags);
+ if (ret)
+ dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch,
+ vin->scratch_phys);
+
return ret;
}
@@ -1141,6 +1071,10 @@ static void rvin_stop_streaming(struct vb2_queue *vq)
/* disable interrupts */
rvin_disable_interrupts(vin);
+
+ /* Free scratch buffer. */
+ dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch,
+ vin->scratch_phys);
}
static const struct vb2_ops rvin_qops = {
@@ -1189,7 +1123,7 @@ int rvin_dma_probe(struct rvin_dev *vin, int irq)
q->ops = &rvin_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 1;
+ q->min_buffers_needed = 4;
q->dev = vin->dev;
ret = vb2_queue_init(q);
diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h
index 5382078143fb..95897127cc41 100644
--- a/drivers/media/platform/rcar-vin/rcar-vin.h
+++ b/drivers/media/platform/rcar-vin/rcar-vin.h
@@ -38,13 +38,11 @@ enum chip_id {
/**
* STOPPED - No operation in progress
* RUNNING - Operation in progress have buffers
- * STALLED - No operation in progress have no buffers
* STOPPING - Stopping operation
*/
enum rvin_dma_state {
STOPPED = 0,
RUNNING,
- STALLED,
STOPPING,
};
@@ -102,12 +100,13 @@ struct rvin_graph_entity {
*
* @lock: protects @queue
* @queue: vb2 buffers queue
+ * @scratch: cpu address for scratch buffer
+ * @scratch_phys: physical address of the scratch buffer
*
- * @qlock: protects @queue_buf, @buf_list, @continuous, @sequence
+ * @qlock: protects @queue_buf, @buf_list, @sequence
* @state
* @queue_buf: Keeps track of buffers given to HW slot
* @buf_list: list of queued buffers
- * @continuous: tracks if active operation is continuous or single mode
* @sequence: V4L2 buffers sequence number
* @state: keeps track of operation state
*
@@ -130,11 +129,12 @@ struct rvin_dev {
struct mutex lock;
struct vb2_queue queue;
+ void *scratch;
+ dma_addr_t scratch_phys;
spinlock_t qlock;
struct vb2_v4l2_buffer *queue_buf[HW_BUFFER_NUM];
struct list_head buf_list;
- bool continuous;
unsigned int sequence;
enum rvin_dma_state state;
diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c
index b2e080ef5391..dc7e280c91b4 100644
--- a/drivers/media/platform/rcar_drif.c
+++ b/drivers/media/platform/rcar_drif.c
@@ -274,7 +274,7 @@ static int rcar_drif_alloc_dmachannels(struct rcar_drif_sdr *sdr)
{
struct dma_slave_config dma_cfg;
unsigned int i;
- int ret = -ENODEV;
+ int ret;
for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) {
struct rcar_drif *ch = sdr->ch[i];
@@ -282,6 +282,7 @@ static int rcar_drif_alloc_dmachannels(struct rcar_drif_sdr *sdr)
ch->dmach = dma_request_slave_channel(&ch->pdev->dev, "rx");
if (!ch->dmach) {
rdrif_err(sdr, "ch%u: dma channel req failed\n", i);
+ ret = -ENODEV;
goto dmach_error;
}
diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c
new file mode 100644
index 000000000000..6599dba5ab84
--- /dev/null
+++ b/drivers/media/platform/renesas-ceu.c
@@ -0,0 +1,1677 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * V4L2 Driver for Renesas Capture Engine Unit (CEU) interface
+ * Copyright (C) 2017-2018 Jacopo Mondi <jacopo+renesas@jmondi.org>
+ *
+ * Based on soc-camera driver "soc_camera/sh_mobile_ceu_camera.c"
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * Based on V4L2 Driver for PXA camera host - "pxa_camera.c",
+ * Copyright (C) 2006, Sascha Hauer, Pengutronix
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mediabus.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include <media/drv-intf/renesas-ceu.h>
+
+#define DRIVER_NAME "renesas-ceu"
+
+/* CEU registers offsets and masks. */
+#define CEU_CAPSR 0x00 /* Capture start register */
+#define CEU_CAPCR 0x04 /* Capture control register */
+#define CEU_CAMCR 0x08 /* Capture interface control register */
+#define CEU_CAMOR 0x10 /* Capture interface offset register */
+#define CEU_CAPWR 0x14 /* Capture interface width register */
+#define CEU_CAIFR 0x18 /* Capture interface input format register */
+#define CEU_CRCNTR 0x28 /* CEU register control register */
+#define CEU_CRCMPR 0x2c /* CEU register forcible control register */
+#define CEU_CFLCR 0x30 /* Capture filter control register */
+#define CEU_CFSZR 0x34 /* Capture filter size clip register */
+#define CEU_CDWDR 0x38 /* Capture destination width register */
+#define CEU_CDAYR 0x3c /* Capture data address Y register */
+#define CEU_CDACR 0x40 /* Capture data address C register */
+#define CEU_CFWCR 0x5c /* Firewall operation control register */
+#define CEU_CDOCR 0x64 /* Capture data output control register */
+#define CEU_CEIER 0x70 /* Capture event interrupt enable register */
+#define CEU_CETCR 0x74 /* Capture event flag clear register */
+#define CEU_CSTSR 0x7c /* Capture status register */
+#define CEU_CSRTR 0x80 /* Capture software reset register */
+
+/* Data synchronous fetch mode. */
+#define CEU_CAMCR_JPEG BIT(4)
+
+/* Input components ordering: CEU_CAMCR.DTARY field. */
+#define CEU_CAMCR_DTARY_8_UYVY (0x00 << 8)
+#define CEU_CAMCR_DTARY_8_VYUY (0x01 << 8)
+#define CEU_CAMCR_DTARY_8_YUYV (0x02 << 8)
+#define CEU_CAMCR_DTARY_8_YVYU (0x03 << 8)
+/* TODO: input components ordering for 16 bits input. */
+
+/* Bus transfer MTU. */
+#define CEU_CAPCR_BUS_WIDTH256 (0x3 << 20)
+
+/* Bus width configuration. */
+#define CEU_CAMCR_DTIF_16BITS BIT(12)
+
+/* No downsampling to planar YUV420 in image fetch mode. */
+#define CEU_CDOCR_NO_DOWSAMPLE BIT(4)
+
+/* Swap all input data in 8-bit, 16-bits and 32-bits units (Figure 46.45). */
+#define CEU_CDOCR_SWAP_ENDIANNESS (7)
+
+/* Capture reset and enable bits. */
+#define CEU_CAPSR_CPKIL BIT(16)
+#define CEU_CAPSR_CE BIT(0)
+
+/* CEU operating flag bit. */
+#define CEU_CAPCR_CTNCP BIT(16)
+#define CEU_CSTRST_CPTON BIT(0)
+
+/* Platform specific IRQ source flags. */
+#define CEU_CETCR_ALL_IRQS_RZ 0x397f313
+#define CEU_CETCR_ALL_IRQS_SH4 0x3d7f313
+
+/* Prohibited register access interrupt bit. */
+#define CEU_CETCR_IGRW BIT(4)
+/* One-frame capture end interrupt. */
+#define CEU_CEIER_CPE BIT(0)
+/* VBP error. */
+#define CEU_CEIER_VBP BIT(20)
+#define CEU_CEIER_MASK (CEU_CEIER_CPE | CEU_CEIER_VBP)
+
+#define CEU_MAX_WIDTH 2560
+#define CEU_MAX_HEIGHT 1920
+#define CEU_MAX_BPL 8188
+#define CEU_W_MAX(w) ((w) < CEU_MAX_WIDTH ? (w) : CEU_MAX_WIDTH)
+#define CEU_H_MAX(h) ((h) < CEU_MAX_HEIGHT ? (h) : CEU_MAX_HEIGHT)
+
+/*
+ * ceu_bus_fmt - describe a 8-bits yuyv format the sensor can produce
+ *
+ * @mbus_code: bus format code
+ * @fmt_order: CEU_CAMCR.DTARY ordering of input components (Y, Cb, Cr)
+ * @fmt_order_swap: swapped CEU_CAMCR.DTARY ordering of input components
+ * (Y, Cr, Cb)
+ * @swapped: does Cr appear before Cb?
+ * @bps: number of bits sent over bus for each sample
+ * @bpp: number of bits per pixels unit
+ */
+struct ceu_mbus_fmt {
+ u32 mbus_code;
+ u32 fmt_order;
+ u32 fmt_order_swap;
+ bool swapped;
+ u8 bps;
+ u8 bpp;
+};
+
+/*
+ * ceu_buffer - Link vb2 buffer to the list of available buffers.
+ */
+struct ceu_buffer {
+ struct vb2_v4l2_buffer vb;
+ struct list_head queue;
+};
+
+static inline struct ceu_buffer *vb2_to_ceu(struct vb2_v4l2_buffer *vbuf)
+{
+ return container_of(vbuf, struct ceu_buffer, vb);
+}
+
+/*
+ * ceu_subdev - Wraps v4l2 sub-device and provides async subdevice.
+ */
+struct ceu_subdev {
+ struct v4l2_subdev *v4l2_sd;
+ struct v4l2_async_subdev asd;
+
+ /* per-subdevice mbus configuration options */
+ unsigned int mbus_flags;
+ struct ceu_mbus_fmt mbus_fmt;
+};
+
+static struct ceu_subdev *to_ceu_subdev(struct v4l2_async_subdev *asd)
+{
+ return container_of(asd, struct ceu_subdev, asd);
+}
+
+/*
+ * ceu_device - CEU device instance
+ */
+struct ceu_device {
+ struct device *dev;
+ struct video_device vdev;
+ struct v4l2_device v4l2_dev;
+
+ /* subdevices descriptors */
+ struct ceu_subdev *subdevs;
+ /* the subdevice currently in use */
+ struct ceu_subdev *sd;
+ unsigned int sd_index;
+ unsigned int num_sd;
+
+ /* platform specific mask with all IRQ sources flagged */
+ u32 irq_mask;
+
+ /* currently configured field and pixel format */
+ enum v4l2_field field;
+ struct v4l2_pix_format_mplane v4l2_pix;
+
+ /* async subdev notification helpers */
+ struct v4l2_async_notifier notifier;
+ /* pointers to "struct ceu_subdevice -> asd" */
+ struct v4l2_async_subdev **asds;
+
+ /* vb2 queue, capture buffer list and active buffer pointer */
+ struct vb2_queue vb2_vq;
+ struct list_head capture;
+ struct vb2_v4l2_buffer *active;
+ unsigned int sequence;
+
+ /* mlock - lock access to interface reset and vb2 queue */
+ struct mutex mlock;
+
+ /* lock - lock access to capture buffer queue and active buffer */
+ spinlock_t lock;
+
+ /* base - CEU memory base address */
+ void __iomem *base;
+};
+
+static inline struct ceu_device *v4l2_to_ceu(struct v4l2_device *v4l2_dev)
+{
+ return container_of(v4l2_dev, struct ceu_device, v4l2_dev);
+}
+
+/* --- CEU memory output formats --- */
+
+/*
+ * ceu_fmt - describe a memory output format supported by CEU interface.
+ *
+ * @fourcc: memory layout fourcc format code
+ * @bpp: number of bits for each pixel stored in memory
+ */
+struct ceu_fmt {
+ u32 fourcc;
+ u32 bpp;
+};
+
+/*
+ * ceu_format_list - List of supported memory output formats
+ *
+ * If sensor provides any YUYV bus format, all the following planar memory
+ * formats are available thanks to CEU re-ordering and sub-sampling
+ * capabilities.
+ */
+static const struct ceu_fmt ceu_fmt_list[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .bpp = 16,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .bpp = 16,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .bpp = 12,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .bpp = 12,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .bpp = 16,
+ },
+};
+
+static const struct ceu_fmt *get_ceu_fmt_from_fourcc(unsigned int fourcc)
+{
+ const struct ceu_fmt *fmt = &ceu_fmt_list[0];
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ceu_fmt_list); i++, fmt++)
+ if (fmt->fourcc == fourcc)
+ return fmt;
+
+ return NULL;
+}
+
+static bool ceu_fmt_mplane(struct v4l2_pix_format_mplane *pix)
+{
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ return false;
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* --- CEU HW operations --- */
+
+static void ceu_write(struct ceu_device *priv, unsigned int reg_offs, u32 data)
+{
+ iowrite32(data, priv->base + reg_offs);
+}
+
+static u32 ceu_read(struct ceu_device *priv, unsigned int reg_offs)
+{
+ return ioread32(priv->base + reg_offs);
+}
+
+/*
+ * ceu_soft_reset() - Software reset the CEU interface.
+ * @ceu_device: CEU device.
+ *
+ * Returns 0 for success, -EIO for error.
+ */
+static int ceu_soft_reset(struct ceu_device *ceudev)
+{
+ unsigned int i;
+
+ ceu_write(ceudev, CEU_CAPSR, CEU_CAPSR_CPKIL);
+
+ for (i = 0; i < 100; i++) {
+ if (!(ceu_read(ceudev, CEU_CSTSR) & CEU_CSTRST_CPTON))
+ break;
+ udelay(1);
+ }
+
+ if (i == 100) {
+ dev_err(ceudev->dev, "soft reset time out\n");
+ return -EIO;
+ }
+
+ for (i = 0; i < 100; i++) {
+ if (!(ceu_read(ceudev, CEU_CAPSR) & CEU_CAPSR_CPKIL))
+ return 0;
+ udelay(1);
+ }
+
+ /* If we get here, CEU has not reset properly. */
+ return -EIO;
+}
+
+/* --- CEU Capture Operations --- */
+
+/*
+ * ceu_hw_config() - Configure CEU interface registers.
+ */
+static int ceu_hw_config(struct ceu_device *ceudev)
+{
+ u32 camcr, cdocr, cfzsr, cdwdr, capwr;
+ struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix;
+ struct ceu_subdev *ceu_sd = ceudev->sd;
+ struct ceu_mbus_fmt *mbus_fmt = &ceu_sd->mbus_fmt;
+ unsigned int mbus_flags = ceu_sd->mbus_flags;
+
+ /* Start configuring CEU registers */
+ ceu_write(ceudev, CEU_CAIFR, 0);
+ ceu_write(ceudev, CEU_CFWCR, 0);
+ ceu_write(ceudev, CEU_CRCNTR, 0);
+ ceu_write(ceudev, CEU_CRCMPR, 0);
+
+ /* Set the frame capture period for both image capture and data sync. */
+ capwr = (pix->height << 16) | pix->width * mbus_fmt->bpp / 8;
+
+ /*
+ * Swap input data endianness by default.
+ * In data fetch mode bytes are received in chunks of 8 bytes.
+ * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first)
+ * The data is however by default written to memory in reverse order:
+ * D7, D6, D5, D4, D3, D2, D1, D0 (D7 written to lowest byte)
+ *
+ * Use CEU_CDOCR[2:0] to swap data ordering.
+ */
+ cdocr = CEU_CDOCR_SWAP_ENDIANNESS;
+
+ /*
+ * Configure CAMCR and CDOCR:
+ * match input components ordering with memory output format and
+ * handle downsampling to YUV420.
+ *
+ * If the memory output planar format is 'swapped' (Cr before Cb) and
+ * input format is not, use the swapped version of CAMCR.DTARY.
+ *
+ * If the memory output planar format is not 'swapped' (Cb before Cr)
+ * and input format is, use the swapped version of CAMCR.DTARY.
+ *
+ * CEU by default downsample to planar YUV420 (CDCOR[4] = 0).
+ * If output is planar YUV422 set CDOCR[4] = 1
+ *
+ * No downsample for data fetch sync mode.
+ */
+ switch (pix->pixelformat) {
+ /* Data fetch sync mode */
+ case V4L2_PIX_FMT_YUYV:
+ /* TODO: handle YUYV permutations through DTARY bits. */
+ camcr = CEU_CAMCR_JPEG;
+ cdocr |= CEU_CDOCR_NO_DOWSAMPLE;
+ cfzsr = (pix->height << 16) | pix->width;
+ cdwdr = pix->plane_fmt[0].bytesperline;
+ break;
+
+ /* Non-swapped planar image capture mode. */
+ case V4L2_PIX_FMT_NV16:
+ cdocr |= CEU_CDOCR_NO_DOWSAMPLE;
+ /* fall-through */
+ case V4L2_PIX_FMT_NV12:
+ if (mbus_fmt->swapped)
+ camcr = mbus_fmt->fmt_order_swap;
+ else
+ camcr = mbus_fmt->fmt_order;
+
+ cfzsr = (pix->height << 16) | pix->width;
+ cdwdr = pix->width;
+ break;
+
+ /* Swapped planar image capture mode. */
+ case V4L2_PIX_FMT_NV61:
+ cdocr |= CEU_CDOCR_NO_DOWSAMPLE;
+ /* fall-through */
+ case V4L2_PIX_FMT_NV21:
+ if (mbus_fmt->swapped)
+ camcr = mbus_fmt->fmt_order;
+ else
+ camcr = mbus_fmt->fmt_order_swap;
+
+ cfzsr = (pix->height << 16) | pix->width;
+ cdwdr = pix->width;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ camcr |= mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
+ camcr |= mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
+
+ /* TODO: handle 16 bit bus width with DTIF bit in CAMCR */
+ ceu_write(ceudev, CEU_CAMCR, camcr);
+ ceu_write(ceudev, CEU_CDOCR, cdocr);
+ ceu_write(ceudev, CEU_CAPCR, CEU_CAPCR_BUS_WIDTH256);
+
+ /*
+ * TODO: make CAMOR offsets configurable.
+ * CAMOR wants to know the number of blanks between a VS/HS signal
+ * and valid data. This value should actually come from the sensor...
+ */
+ ceu_write(ceudev, CEU_CAMOR, 0);
+
+ /* TODO: 16 bit bus width require re-calculation of cdwdr and cfzsr */
+ ceu_write(ceudev, CEU_CAPWR, capwr);
+ ceu_write(ceudev, CEU_CFSZR, cfzsr);
+ ceu_write(ceudev, CEU_CDWDR, cdwdr);
+
+ return 0;
+}
+
+/*
+ * ceu_capture() - Trigger start of a capture sequence.
+ *
+ * Program the CEU DMA registers with addresses where to transfer image data.
+ */
+static int ceu_capture(struct ceu_device *ceudev)
+{
+ struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix;
+ dma_addr_t phys_addr_top;
+
+ phys_addr_top =
+ vb2_dma_contig_plane_dma_addr(&ceudev->active->vb2_buf, 0);
+ ceu_write(ceudev, CEU_CDAYR, phys_addr_top);
+
+ /* Ignore CbCr plane for non multi-planar image formats. */
+ if (ceu_fmt_mplane(pix)) {
+ phys_addr_top =
+ vb2_dma_contig_plane_dma_addr(&ceudev->active->vb2_buf,
+ 1);
+ ceu_write(ceudev, CEU_CDACR, phys_addr_top);
+ }
+
+ /*
+ * Trigger new capture start: once for each frame, as we work in
+ * one-frame capture mode.
+ */
+ ceu_write(ceudev, CEU_CAPSR, CEU_CAPSR_CE);
+
+ return 0;
+}
+
+static irqreturn_t ceu_irq(int irq, void *data)
+{
+ struct ceu_device *ceudev = data;
+ struct vb2_v4l2_buffer *vbuf;
+ struct ceu_buffer *buf;
+ u32 status;
+
+ /* Clean interrupt status. */
+ status = ceu_read(ceudev, CEU_CETCR);
+ ceu_write(ceudev, CEU_CETCR, ~ceudev->irq_mask);
+
+ /* Unexpected interrupt. */
+ if (!(status & CEU_CEIER_MASK))
+ return IRQ_NONE;
+
+ spin_lock(&ceudev->lock);
+
+ /* Stale interrupt from a released buffer, ignore it. */
+ vbuf = ceudev->active;
+ if (!vbuf) {
+ spin_unlock(&ceudev->lock);
+ return IRQ_HANDLED;
+ }
+
+ /*
+ * When a VBP interrupt occurs, no capture end interrupt will occur
+ * and the image of that frame is not captured correctly.
+ */
+ if (status & CEU_CEIER_VBP) {
+ dev_err(ceudev->dev, "VBP interrupt: abort capture\n");
+ goto error_irq_out;
+ }
+
+ /* Prepare to return the 'previous' buffer. */
+ vbuf->vb2_buf.timestamp = ktime_get_ns();
+ vbuf->sequence = ceudev->sequence++;
+ vbuf->field = ceudev->field;
+
+ /* Prepare a new 'active' buffer and trigger a new capture. */
+ if (!list_empty(&ceudev->capture)) {
+ buf = list_first_entry(&ceudev->capture, struct ceu_buffer,
+ queue);
+ list_del(&buf->queue);
+ ceudev->active = &buf->vb;
+
+ ceu_capture(ceudev);
+ }
+
+ /* Return the 'previous' buffer. */
+ vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
+
+ spin_unlock(&ceudev->lock);
+
+ return IRQ_HANDLED;
+
+error_irq_out:
+ /* Return the 'previous' buffer and all queued ones. */
+ vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_ERROR);
+
+ list_for_each_entry(buf, &ceudev->capture, queue)
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+
+ spin_unlock(&ceudev->lock);
+
+ return IRQ_HANDLED;
+}
+
+/* --- CEU Videobuf2 operations --- */
+
+static void ceu_update_plane_sizes(struct v4l2_plane_pix_format *plane,
+ unsigned int bpl, unsigned int szimage)
+{
+ memset(plane, 0, sizeof(*plane));
+
+ plane->sizeimage = szimage;
+ if (plane->bytesperline < bpl || plane->bytesperline > CEU_MAX_BPL)
+ plane->bytesperline = bpl;
+}
+
+/*
+ * ceu_calc_plane_sizes() - Fill per-plane 'struct v4l2_plane_pix_format'
+ * information according to the currently configured
+ * pixel format.
+ * @ceu_device: CEU device.
+ * @ceu_fmt: Active image format.
+ * @pix: Pixel format information (store line width and image sizes)
+ */
+static void ceu_calc_plane_sizes(struct ceu_device *ceudev,
+ const struct ceu_fmt *ceu_fmt,
+ struct v4l2_pix_format_mplane *pix)
+{
+ unsigned int bpl, szimage;
+
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ pix->num_planes = 1;
+ bpl = pix->width * ceu_fmt->bpp / 8;
+ szimage = pix->height * bpl;
+ ceu_update_plane_sizes(&pix->plane_fmt[0], bpl, szimage);
+ break;
+
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ pix->num_planes = 2;
+ bpl = pix->width;
+ szimage = pix->height * pix->width;
+ ceu_update_plane_sizes(&pix->plane_fmt[0], bpl, szimage);
+ ceu_update_plane_sizes(&pix->plane_fmt[1], bpl, szimage / 2);
+ break;
+
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ default:
+ pix->num_planes = 2;
+ bpl = pix->width;
+ szimage = pix->height * pix->width;
+ ceu_update_plane_sizes(&pix->plane_fmt[0], bpl, szimage);
+ ceu_update_plane_sizes(&pix->plane_fmt[1], bpl, szimage);
+ break;
+ }
+}
+
+/*
+ * ceu_vb2_setup() - is called to check whether the driver can accept the
+ * requested number of buffers and to fill in plane sizes
+ * for the current frame format, if required.
+ */
+static int ceu_vb2_setup(struct vb2_queue *vq, unsigned int *count,
+ unsigned int *num_planes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct ceu_device *ceudev = vb2_get_drv_priv(vq);
+ struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix;
+ unsigned int i;
+
+ /* num_planes is set: just check plane sizes. */
+ if (*num_planes) {
+ for (i = 0; i < pix->num_planes; i++)
+ if (sizes[i] < pix->plane_fmt[i].sizeimage)
+ return -EINVAL;
+
+ return 0;
+ }
+
+ /* num_planes not set: called from REQBUFS, just set plane sizes. */
+ *num_planes = pix->num_planes;
+ for (i = 0; i < pix->num_planes; i++)
+ sizes[i] = pix->plane_fmt[i].sizeimage;
+
+ return 0;
+}
+
+static void ceu_vb2_queue(struct vb2_buffer *vb)
+{
+ struct ceu_device *ceudev = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct ceu_buffer *buf = vb2_to_ceu(vbuf);
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&ceudev->lock, irqflags);
+ list_add_tail(&buf->queue, &ceudev->capture);
+ spin_unlock_irqrestore(&ceudev->lock, irqflags);
+}
+
+static int ceu_vb2_prepare(struct vb2_buffer *vb)
+{
+ struct ceu_device *ceudev = vb2_get_drv_priv(vb->vb2_queue);
+ struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix;
+ unsigned int i;
+
+ for (i = 0; i < pix->num_planes; i++) {
+ if (vb2_plane_size(vb, i) < pix->plane_fmt[i].sizeimage) {
+ dev_err(ceudev->dev,
+ "Plane size too small (%lu < %u)\n",
+ vb2_plane_size(vb, i),
+ pix->plane_fmt[i].sizeimage);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, i, pix->plane_fmt[i].sizeimage);
+ }
+
+ return 0;
+}
+
+static int ceu_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct ceu_device *ceudev = vb2_get_drv_priv(vq);
+ struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd;
+ struct ceu_buffer *buf;
+ unsigned long irqflags;
+ int ret;
+
+ /* Program the CEU interface according to the CEU image format. */
+ ret = ceu_hw_config(ceudev);
+ if (ret)
+ goto error_return_bufs;
+
+ ret = v4l2_subdev_call(v4l2_sd, video, s_stream, 1);
+ if (ret && ret != -ENOIOCTLCMD) {
+ dev_dbg(ceudev->dev,
+ "Subdevice failed to start streaming: %d\n", ret);
+ goto error_return_bufs;
+ }
+
+ spin_lock_irqsave(&ceudev->lock, irqflags);
+ ceudev->sequence = 0;
+
+ /* Grab the first available buffer and trigger the first capture. */
+ buf = list_first_entry(&ceudev->capture, struct ceu_buffer,
+ queue);
+ if (!buf) {
+ spin_unlock_irqrestore(&ceudev->lock, irqflags);
+ dev_dbg(ceudev->dev,
+ "No buffer available for capture.\n");
+ goto error_stop_sensor;
+ }
+
+ list_del(&buf->queue);
+ ceudev->active = &buf->vb;
+
+ /* Clean and program interrupts for first capture. */
+ ceu_write(ceudev, CEU_CETCR, ~ceudev->irq_mask);
+ ceu_write(ceudev, CEU_CEIER, CEU_CEIER_MASK);
+
+ ceu_capture(ceudev);
+
+ spin_unlock_irqrestore(&ceudev->lock, irqflags);
+
+ return 0;
+
+error_stop_sensor:
+ v4l2_subdev_call(v4l2_sd, video, s_stream, 0);
+
+error_return_bufs:
+ spin_lock_irqsave(&ceudev->lock, irqflags);
+ list_for_each_entry(buf, &ceudev->capture, queue)
+ vb2_buffer_done(&ceudev->active->vb2_buf,
+ VB2_BUF_STATE_QUEUED);
+ ceudev->active = NULL;
+ spin_unlock_irqrestore(&ceudev->lock, irqflags);
+
+ return ret;
+}
+
+static void ceu_stop_streaming(struct vb2_queue *vq)
+{
+ struct ceu_device *ceudev = vb2_get_drv_priv(vq);
+ struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd;
+ struct ceu_buffer *buf;
+ unsigned long irqflags;
+
+ /* Clean and disable interrupt sources. */
+ ceu_write(ceudev, CEU_CETCR,
+ ceu_read(ceudev, CEU_CETCR) & ceudev->irq_mask);
+ ceu_write(ceudev, CEU_CEIER, CEU_CEIER_MASK);
+
+ v4l2_subdev_call(v4l2_sd, video, s_stream, 0);
+
+ spin_lock_irqsave(&ceudev->lock, irqflags);
+ if (ceudev->active) {
+ vb2_buffer_done(&ceudev->active->vb2_buf,
+ VB2_BUF_STATE_ERROR);
+ ceudev->active = NULL;
+ }
+
+ /* Release all queued buffers. */
+ list_for_each_entry(buf, &ceudev->capture, queue)
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ INIT_LIST_HEAD(&ceudev->capture);
+
+ spin_unlock_irqrestore(&ceudev->lock, irqflags);
+
+ ceu_soft_reset(ceudev);
+}
+
+static const struct vb2_ops ceu_vb2_ops = {
+ .queue_setup = ceu_vb2_setup,
+ .buf_queue = ceu_vb2_queue,
+ .buf_prepare = ceu_vb2_prepare,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = ceu_start_streaming,
+ .stop_streaming = ceu_stop_streaming,
+};
+
+/* --- CEU image formats handling --- */
+
+/*
+ * ceu_try_fmt() - test format on CEU and sensor
+ * @ceudev: The CEU device.
+ * @v4l2_fmt: format to test.
+ *
+ * Returns 0 for success, < 0 for errors.
+ */
+static int ceu_try_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt)
+{
+ struct ceu_subdev *ceu_sd = ceudev->sd;
+ struct v4l2_pix_format_mplane *pix = &v4l2_fmt->fmt.pix_mp;
+ struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd;
+ struct v4l2_subdev_pad_config pad_cfg;
+ const struct ceu_fmt *ceu_fmt;
+ int ret;
+
+ struct v4l2_subdev_format sd_format = {
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ };
+
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ break;
+
+ default:
+ pix->pixelformat = V4L2_PIX_FMT_NV16;
+ break;
+ }
+
+ ceu_fmt = get_ceu_fmt_from_fourcc(pix->pixelformat);
+
+ /* CFSZR requires height and width to be 4-pixel aligned. */
+ v4l_bound_align_image(&pix->width, 2, CEU_MAX_WIDTH, 4,
+ &pix->height, 4, CEU_MAX_HEIGHT, 4, 0);
+
+ /*
+ * Set format on sensor sub device: bus format used to produce memory
+ * format is selected at initialization time.
+ */
+ v4l2_fill_mbus_format_mplane(&sd_format.format, pix);
+ ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, &pad_cfg, &sd_format);
+ if (ret)
+ return ret;
+
+ /* Apply size returned by sensor as the CEU can't scale. */
+ v4l2_fill_pix_format_mplane(pix, &sd_format.format);
+
+ /* Calculate per-plane sizes based on image format. */
+ ceu_calc_plane_sizes(ceudev, ceu_fmt, pix);
+
+ return 0;
+}
+
+/*
+ * ceu_set_fmt() - Apply the supplied format to both sensor and CEU
+ */
+static int ceu_set_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt)
+{
+ struct ceu_subdev *ceu_sd = ceudev->sd;
+ struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd;
+ int ret;
+
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+
+ ret = ceu_try_fmt(ceudev, v4l2_fmt);
+ if (ret)
+ return ret;
+
+ v4l2_fill_mbus_format_mplane(&format.format, &v4l2_fmt->fmt.pix_mp);
+ ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, NULL, &format);
+ if (ret)
+ return ret;
+
+ ceudev->v4l2_pix = v4l2_fmt->fmt.pix_mp;
+ ceudev->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+/*
+ * ceu_set_default_fmt() - Apply default NV16 memory output format with VGA
+ * sizes.
+ */
+static int ceu_set_default_fmt(struct ceu_device *ceudev)
+{
+ int ret;
+
+ struct v4l2_format v4l2_fmt = {
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ .fmt.pix_mp = {
+ .width = VGA_WIDTH,
+ .height = VGA_HEIGHT,
+ .field = V4L2_FIELD_NONE,
+ .pixelformat = V4L2_PIX_FMT_NV16,
+ .num_planes = 2,
+ .plane_fmt = {
+ [0] = {
+ .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2,
+ .bytesperline = VGA_WIDTH * 2,
+ },
+ [1] = {
+ .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2,
+ .bytesperline = VGA_WIDTH * 2,
+ },
+ },
+ },
+ };
+
+ ret = ceu_try_fmt(ceudev, &v4l2_fmt);
+ if (ret)
+ return ret;
+
+ ceudev->v4l2_pix = v4l2_fmt.fmt.pix_mp;
+ ceudev->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+/*
+ * ceu_init_mbus_fmt() - Query sensor for supported formats and initialize
+ * CEU media bus format used to produce memory formats.
+ *
+ * Find out if sensor can produce a permutation of 8-bits YUYV bus format.
+ * From a single 8-bits YUYV bus format the CEU can produce several memory
+ * output formats:
+ * - NV[12|21|16|61] through image fetch mode;
+ * - YUYV422 if sensor provides YUYV422
+ *
+ * TODO: Other YUYV422 permutations through data fetch sync mode and DTARY
+ * TODO: Binary data (eg. JPEG) and raw formats through data fetch sync mode
+ */
+static int ceu_init_mbus_fmt(struct ceu_device *ceudev)
+{
+ struct ceu_subdev *ceu_sd = ceudev->sd;
+ struct ceu_mbus_fmt *mbus_fmt = &ceu_sd->mbus_fmt;
+ struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd;
+ bool yuyv_bus_fmt = false;
+
+ struct v4l2_subdev_mbus_code_enum sd_mbus_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .index = 0,
+ };
+
+ /* Find out if sensor can produce any permutation of 8-bits YUYV422. */
+ while (!yuyv_bus_fmt &&
+ !v4l2_subdev_call(v4l2_sd, pad, enum_mbus_code,
+ NULL, &sd_mbus_fmt)) {
+ switch (sd_mbus_fmt.code) {
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YVYU8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_VYUY8_2X8:
+ yuyv_bus_fmt = true;
+ break;
+ default:
+ /*
+ * Only support 8-bits YUYV bus formats at the moment;
+ *
+ * TODO: add support for binary formats (data sync
+ * fetch mode).
+ */
+ break;
+ }
+
+ sd_mbus_fmt.index++;
+ }
+
+ if (!yuyv_bus_fmt)
+ return -ENXIO;
+
+ /*
+ * Save the first encountered YUYV format as "mbus_fmt" and use it
+ * to output all planar YUV422 and YUV420 (NV*) formats to memory as
+ * well as for data synch fetch mode (YUYV - YVYU etc. ).
+ */
+ mbus_fmt->mbus_code = sd_mbus_fmt.code;
+ mbus_fmt->bps = 8;
+
+ /* Annotate the selected bus format components ordering. */
+ switch (sd_mbus_fmt.code) {
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_YUYV;
+ mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_YVYU;
+ mbus_fmt->swapped = false;
+ mbus_fmt->bpp = 16;
+ break;
+
+ case MEDIA_BUS_FMT_YVYU8_2X8:
+ mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_YVYU;
+ mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_YUYV;
+ mbus_fmt->swapped = true;
+ mbus_fmt->bpp = 16;
+ break;
+
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_UYVY;
+ mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_VYUY;
+ mbus_fmt->swapped = false;
+ mbus_fmt->bpp = 16;
+ break;
+
+ case MEDIA_BUS_FMT_VYUY8_2X8:
+ mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_VYUY;
+ mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_UYVY;
+ mbus_fmt->swapped = true;
+ mbus_fmt->bpp = 16;
+ break;
+ }
+
+ return 0;
+}
+
+/* --- Runtime PM Handlers --- */
+
+/*
+ * ceu_runtime_resume() - soft-reset the interface and turn sensor power on.
+ */
+static int __maybe_unused ceu_runtime_resume(struct device *dev)
+{
+ struct ceu_device *ceudev = dev_get_drvdata(dev);
+ struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd;
+
+ v4l2_subdev_call(v4l2_sd, core, s_power, 1);
+
+ ceu_soft_reset(ceudev);
+
+ return 0;
+}
+
+/*
+ * ceu_runtime_suspend() - disable capture and interrupts and soft-reset.
+ * Turn sensor power off.
+ */
+static int __maybe_unused ceu_runtime_suspend(struct device *dev)
+{
+ struct ceu_device *ceudev = dev_get_drvdata(dev);
+ struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd;
+
+ v4l2_subdev_call(v4l2_sd, core, s_power, 0);
+
+ ceu_write(ceudev, CEU_CEIER, 0);
+ ceu_soft_reset(ceudev);
+
+ return 0;
+}
+
+/* --- File Operations --- */
+
+static int ceu_open(struct file *file)
+{
+ struct ceu_device *ceudev = video_drvdata(file);
+ int ret;
+
+ ret = v4l2_fh_open(file);
+ if (ret)
+ return ret;
+
+ mutex_lock(&ceudev->mlock);
+ /* Causes soft-reset and sensor power on on first open */
+ pm_runtime_get_sync(ceudev->dev);
+ mutex_unlock(&ceudev->mlock);
+
+ return 0;
+}
+
+static int ceu_release(struct file *file)
+{
+ struct ceu_device *ceudev = video_drvdata(file);
+
+ vb2_fop_release(file);
+
+ mutex_lock(&ceudev->mlock);
+ /* Causes soft-reset and sensor power down on last close */
+ pm_runtime_put(ceudev->dev);
+ mutex_unlock(&ceudev->mlock);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations ceu_fops = {
+ .owner = THIS_MODULE,
+ .open = ceu_open,
+ .release = ceu_release,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll,
+};
+
+/* --- Video Device IOCTLs --- */
+
+static int ceu_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct ceu_device *ceudev = video_drvdata(file);
+
+ strlcpy(cap->card, "Renesas CEU", sizeof(cap->card));
+ strlcpy(cap->driver, DRIVER_NAME, sizeof(cap->driver));
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:renesas-ceu-%s", dev_name(ceudev->dev));
+
+ return 0;
+}
+
+static int ceu_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ const struct ceu_fmt *fmt;
+
+ if (f->index >= ARRAY_SIZE(ceu_fmt_list))
+ return -EINVAL;
+
+ fmt = &ceu_fmt_list[f->index];
+ f->pixelformat = fmt->fourcc;
+
+ return 0;
+}
+
+static int ceu_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct ceu_device *ceudev = video_drvdata(file);
+
+ return ceu_try_fmt(ceudev, f);
+}
+
+static int ceu_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct ceu_device *ceudev = video_drvdata(file);
+
+ if (vb2_is_streaming(&ceudev->vb2_vq))
+ return -EBUSY;
+
+ return ceu_set_fmt(ceudev, f);
+}
+
+static int ceu_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct ceu_device *ceudev = video_drvdata(file);
+
+ f->fmt.pix_mp = ceudev->v4l2_pix;
+
+ return 0;
+}
+
+static int ceu_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct ceu_device *ceudev = video_drvdata(file);
+ struct ceu_subdev *ceusd;
+
+ if (inp->index >= ceudev->num_sd)
+ return -EINVAL;
+
+ ceusd = &ceudev->subdevs[inp->index];
+
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = 0;
+ snprintf(inp->name, sizeof(inp->name), "Camera%u: %s",
+ inp->index, ceusd->v4l2_sd->name);
+
+ return 0;
+}
+
+static int ceu_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct ceu_device *ceudev = video_drvdata(file);
+
+ *i = ceudev->sd_index;
+
+ return 0;
+}
+
+static int ceu_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct ceu_device *ceudev = video_drvdata(file);
+ struct ceu_subdev *ceu_sd_old;
+ int ret;
+
+ if (i >= ceudev->num_sd)
+ return -EINVAL;
+
+ if (vb2_is_streaming(&ceudev->vb2_vq))
+ return -EBUSY;
+
+ if (i == ceudev->sd_index)
+ return 0;
+
+ ceu_sd_old = ceudev->sd;
+ ceudev->sd = &ceudev->subdevs[i];
+
+ /*
+ * Make sure we can generate output image formats and apply
+ * default one.
+ */
+ ret = ceu_init_mbus_fmt(ceudev);
+ if (ret) {
+ ceudev->sd = ceu_sd_old;
+ return -EINVAL;
+ }
+
+ ret = ceu_set_default_fmt(ceudev);
+ if (ret) {
+ ceudev->sd = ceu_sd_old;
+ return -EINVAL;
+ }
+
+ /* Now that we're sure we can use the sensor, power off the old one. */
+ v4l2_subdev_call(ceu_sd_old->v4l2_sd, core, s_power, 0);
+ v4l2_subdev_call(ceudev->sd->v4l2_sd, core, s_power, 1);
+
+ ceudev->sd_index = i;
+
+ return 0;
+}
+
+static int ceu_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+ struct ceu_device *ceudev = video_drvdata(file);
+
+ return v4l2_g_parm_cap(video_devdata(file), ceudev->sd->v4l2_sd, a);
+}
+
+static int ceu_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+ struct ceu_device *ceudev = video_drvdata(file);
+
+ return v4l2_s_parm_cap(video_devdata(file), ceudev->sd->v4l2_sd, a);
+}
+
+static int ceu_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct ceu_device *ceudev = video_drvdata(file);
+ struct ceu_subdev *ceu_sd = ceudev->sd;
+ const struct ceu_fmt *ceu_fmt;
+ struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd;
+ int ret;
+
+ struct v4l2_subdev_frame_size_enum fse = {
+ .code = ceu_sd->mbus_fmt.mbus_code,
+ .index = fsize->index,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+
+ /* Just check if user supplied pixel format is supported. */
+ ceu_fmt = get_ceu_fmt_from_fourcc(fsize->pixel_format);
+ if (!ceu_fmt)
+ return -EINVAL;
+
+ ret = v4l2_subdev_call(v4l2_sd, pad, enum_frame_size,
+ NULL, &fse);
+ if (ret)
+ return ret;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = CEU_W_MAX(fse.max_width);
+ fsize->discrete.height = CEU_H_MAX(fse.max_height);
+
+ return 0;
+}
+
+static int ceu_enum_frameintervals(struct file *file, void *fh,
+ struct v4l2_frmivalenum *fival)
+{
+ struct ceu_device *ceudev = video_drvdata(file);
+ struct ceu_subdev *ceu_sd = ceudev->sd;
+ const struct ceu_fmt *ceu_fmt;
+ struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd;
+ int ret;
+
+ struct v4l2_subdev_frame_interval_enum fie = {
+ .code = ceu_sd->mbus_fmt.mbus_code,
+ .index = fival->index,
+ .width = fival->width,
+ .height = fival->height,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+
+ /* Just check if user supplied pixel format is supported. */
+ ceu_fmt = get_ceu_fmt_from_fourcc(fival->pixel_format);
+ if (!ceu_fmt)
+ return -EINVAL;
+
+ ret = v4l2_subdev_call(v4l2_sd, pad, enum_frame_interval, NULL,
+ &fie);
+ if (ret)
+ return ret;
+
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete = fie.interval;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops ceu_ioctl_ops = {
+ .vidioc_querycap = ceu_querycap,
+
+ .vidioc_enum_fmt_vid_cap_mplane = ceu_enum_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap_mplane = ceu_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap_mplane = ceu_s_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap_mplane = ceu_g_fmt_vid_cap,
+
+ .vidioc_enum_input = ceu_enum_input,
+ .vidioc_g_input = ceu_g_input,
+ .vidioc_s_input = ceu_s_input,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+
+ .vidioc_g_parm = ceu_g_parm,
+ .vidioc_s_parm = ceu_s_parm,
+ .vidioc_enum_framesizes = ceu_enum_framesizes,
+ .vidioc_enum_frameintervals = ceu_enum_frameintervals,
+
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/*
+ * ceu_vdev_release() - release CEU video device memory when last reference
+ * to this driver is closed
+ */
+static void ceu_vdev_release(struct video_device *vdev)
+{
+ struct ceu_device *ceudev = video_get_drvdata(vdev);
+
+ kfree(ceudev);
+}
+
+static int ceu_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *v4l2_sd,
+ struct v4l2_async_subdev *asd)
+{
+ struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
+ struct ceu_device *ceudev = v4l2_to_ceu(v4l2_dev);
+ struct ceu_subdev *ceu_sd = to_ceu_subdev(asd);
+
+ ceu_sd->v4l2_sd = v4l2_sd;
+ ceudev->num_sd++;
+
+ return 0;
+}
+
+static int ceu_notify_complete(struct v4l2_async_notifier *notifier)
+{
+ struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
+ struct ceu_device *ceudev = v4l2_to_ceu(v4l2_dev);
+ struct video_device *vdev = &ceudev->vdev;
+ struct vb2_queue *q = &ceudev->vb2_vq;
+ struct v4l2_subdev *v4l2_sd;
+ int ret;
+
+ /* Initialize vb2 queue. */
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ q->io_modes = VB2_MMAP | VB2_DMABUF;
+ q->drv_priv = ceudev;
+ q->ops = &ceu_vb2_ops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct ceu_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 2;
+ q->lock = &ceudev->mlock;
+ q->dev = ceudev->v4l2_dev.dev;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+ return ret;
+
+ /*
+ * Make sure at least one sensor is primary and use it to initialize
+ * ceu formats.
+ */
+ if (!ceudev->sd) {
+ ceudev->sd = &ceudev->subdevs[0];
+ ceudev->sd_index = 0;
+ }
+
+ v4l2_sd = ceudev->sd->v4l2_sd;
+
+ ret = ceu_init_mbus_fmt(ceudev);
+ if (ret)
+ return ret;
+
+ ret = ceu_set_default_fmt(ceudev);
+ if (ret)
+ return ret;
+
+ /* Register the video device. */
+ strncpy(vdev->name, DRIVER_NAME, strlen(DRIVER_NAME));
+ vdev->v4l2_dev = v4l2_dev;
+ vdev->lock = &ceudev->mlock;
+ vdev->queue = &ceudev->vb2_vq;
+ vdev->ctrl_handler = v4l2_sd->ctrl_handler;
+ vdev->fops = &ceu_fops;
+ vdev->ioctl_ops = &ceu_ioctl_ops;
+ vdev->release = ceu_vdev_release;
+ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_STREAMING;
+ video_set_drvdata(vdev, ceudev);
+
+ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ v4l2_err(vdev->v4l2_dev,
+ "video_register_device failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_async_notifier_operations ceu_notify_ops = {
+ .bound = ceu_notify_bound,
+ .complete = ceu_notify_complete,
+};
+
+/*
+ * ceu_init_async_subdevs() - Initialize CEU subdevices and async_subdevs in
+ * ceu device. Both DT and platform data parsing use
+ * this routine.
+ *
+ * Returns 0 for success, -ENOMEM for failure.
+ */
+static int ceu_init_async_subdevs(struct ceu_device *ceudev, unsigned int n_sd)
+{
+ /* Reserve memory for 'n_sd' ceu_subdev descriptors. */
+ ceudev->subdevs = devm_kcalloc(ceudev->dev, n_sd,
+ sizeof(*ceudev->subdevs), GFP_KERNEL);
+ if (!ceudev->subdevs)
+ return -ENOMEM;
+
+ /*
+ * Reserve memory for 'n_sd' pointers to async_subdevices.
+ * ceudev->asds members will point to &ceu_subdev.asd
+ */
+ ceudev->asds = devm_kcalloc(ceudev->dev, n_sd,
+ sizeof(*ceudev->asds), GFP_KERNEL);
+ if (!ceudev->asds)
+ return -ENOMEM;
+
+ ceudev->sd = NULL;
+ ceudev->sd_index = 0;
+ ceudev->num_sd = 0;
+
+ return 0;
+}
+
+/*
+ * ceu_parse_platform_data() - Initialize async_subdevices using platform
+ * device provided data.
+ */
+static int ceu_parse_platform_data(struct ceu_device *ceudev,
+ const struct ceu_platform_data *pdata)
+{
+ const struct ceu_async_subdev *async_sd;
+ struct ceu_subdev *ceu_sd;
+ unsigned int i;
+ int ret;
+
+ if (pdata->num_subdevs == 0)
+ return -ENODEV;
+
+ ret = ceu_init_async_subdevs(ceudev, pdata->num_subdevs);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < pdata->num_subdevs; i++) {
+ /* Setup the ceu subdevice and the async subdevice. */
+ async_sd = &pdata->subdevs[i];
+ ceu_sd = &ceudev->subdevs[i];
+
+ INIT_LIST_HEAD(&ceu_sd->asd.list);
+
+ ceu_sd->mbus_flags = async_sd->flags;
+ ceu_sd->asd.match_type = V4L2_ASYNC_MATCH_I2C;
+ ceu_sd->asd.match.i2c.adapter_id = async_sd->i2c_adapter_id;
+ ceu_sd->asd.match.i2c.address = async_sd->i2c_address;
+
+ ceudev->asds[i] = &ceu_sd->asd;
+ }
+
+ return pdata->num_subdevs;
+}
+
+/*
+ * ceu_parse_dt() - Initialize async_subdevs parsing device tree graph.
+ */
+static int ceu_parse_dt(struct ceu_device *ceudev)
+{
+ struct device_node *of = ceudev->dev->of_node;
+ struct v4l2_fwnode_endpoint fw_ep;
+ struct ceu_subdev *ceu_sd;
+ struct device_node *ep;
+ unsigned int i;
+ int num_ep;
+ int ret;
+
+ num_ep = of_graph_get_endpoint_count(of);
+ if (!num_ep)
+ return -ENODEV;
+
+ ret = ceu_init_async_subdevs(ceudev, num_ep);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < num_ep; i++) {
+ ep = of_graph_get_endpoint_by_regs(of, 0, i);
+ if (!ep) {
+ dev_err(ceudev->dev,
+ "No subdevice connected on endpoint %u.\n", i);
+ ret = -ENODEV;
+ goto error_put_node;
+ }
+
+ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &fw_ep);
+ if (ret) {
+ dev_err(ceudev->dev,
+ "Unable to parse endpoint #%u.\n", i);
+ goto error_put_node;
+ }
+
+ if (fw_ep.bus_type != V4L2_MBUS_PARALLEL) {
+ dev_err(ceudev->dev,
+ "Only parallel input supported.\n");
+ ret = -EINVAL;
+ goto error_put_node;
+ }
+
+ /* Setup the ceu subdevice and the async subdevice. */
+ ceu_sd = &ceudev->subdevs[i];
+ INIT_LIST_HEAD(&ceu_sd->asd.list);
+
+ ceu_sd->mbus_flags = fw_ep.bus.parallel.flags;
+ ceu_sd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
+ ceu_sd->asd.match.fwnode =
+ fwnode_graph_get_remote_port_parent(
+ of_fwnode_handle(ep));
+
+ ceudev->asds[i] = &ceu_sd->asd;
+ of_node_put(ep);
+ }
+
+ return num_ep;
+
+error_put_node:
+ of_node_put(ep);
+ return ret;
+}
+
+/*
+ * struct ceu_data - Platform specific CEU data
+ * @irq_mask: CETCR mask with all interrupt sources enabled. The mask differs
+ * between SH4 and RZ platforms.
+ */
+struct ceu_data {
+ u32 irq_mask;
+};
+
+static const struct ceu_data ceu_data_rz = {
+ .irq_mask = CEU_CETCR_ALL_IRQS_RZ,
+};
+
+static const struct ceu_data ceu_data_sh4 = {
+ .irq_mask = CEU_CETCR_ALL_IRQS_SH4,
+};
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id ceu_of_match[] = {
+ { .compatible = "renesas,r7s72100-ceu", .data = &ceu_data_rz },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ceu_of_match);
+#endif
+
+static int ceu_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct ceu_data *ceu_data;
+ struct ceu_device *ceudev;
+ struct resource *res;
+ unsigned int irq;
+ int num_subdevs;
+ int ret;
+
+ ceudev = kzalloc(sizeof(*ceudev), GFP_KERNEL);
+ if (!ceudev)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ceudev);
+ ceudev->dev = dev;
+
+ INIT_LIST_HEAD(&ceudev->capture);
+ spin_lock_init(&ceudev->lock);
+ mutex_init(&ceudev->mlock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ceudev->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ceudev->base)) {
+ ret = PTR_ERR(ceudev->base);
+ goto error_free_ceudev;
+ }
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(dev, "Failed to get irq: %d\n", ret);
+ goto error_free_ceudev;
+ }
+ irq = ret;
+
+ ret = devm_request_irq(dev, irq, ceu_irq,
+ 0, dev_name(dev), ceudev);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to request CEU interrupt.\n");
+ goto error_free_ceudev;
+ }
+
+ pm_runtime_enable(dev);
+
+ ret = v4l2_device_register(dev, &ceudev->v4l2_dev);
+ if (ret)
+ goto error_pm_disable;
+
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
+ ceu_data = of_match_device(ceu_of_match, dev)->data;
+ num_subdevs = ceu_parse_dt(ceudev);
+ } else if (dev->platform_data) {
+ /* Assume SH4 if booting with platform data. */
+ ceu_data = &ceu_data_sh4;
+ num_subdevs = ceu_parse_platform_data(ceudev,
+ dev->platform_data);
+ } else {
+ num_subdevs = -EINVAL;
+ }
+
+ if (num_subdevs < 0) {
+ ret = num_subdevs;
+ goto error_v4l2_unregister;
+ }
+ ceudev->irq_mask = ceu_data->irq_mask;
+
+ ceudev->notifier.v4l2_dev = &ceudev->v4l2_dev;
+ ceudev->notifier.subdevs = ceudev->asds;
+ ceudev->notifier.num_subdevs = num_subdevs;
+ ceudev->notifier.ops = &ceu_notify_ops;
+ ret = v4l2_async_notifier_register(&ceudev->v4l2_dev,
+ &ceudev->notifier);
+ if (ret)
+ goto error_v4l2_unregister;
+
+ dev_info(dev, "Renesas Capture Engine Unit %s\n", dev_name(dev));
+
+ return 0;
+
+error_v4l2_unregister:
+ v4l2_device_unregister(&ceudev->v4l2_dev);
+error_pm_disable:
+ pm_runtime_disable(dev);
+error_free_ceudev:
+ kfree(ceudev);
+
+ return ret;
+}
+
+static int ceu_remove(struct platform_device *pdev)
+{
+ struct ceu_device *ceudev = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(ceudev->dev);
+
+ v4l2_async_notifier_unregister(&ceudev->notifier);
+
+ v4l2_device_unregister(&ceudev->v4l2_dev);
+
+ video_unregister_device(&ceudev->vdev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ceu_pm_ops = {
+ SET_RUNTIME_PM_OPS(ceu_runtime_suspend,
+ ceu_runtime_resume,
+ NULL)
+};
+
+static struct platform_driver ceu_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .pm = &ceu_pm_ops,
+ .of_match_table = of_match_ptr(ceu_of_match),
+ },
+ .probe = ceu_probe,
+ .remove = ceu_remove,
+};
+
+module_platform_driver(ceu_driver);
+
+MODULE_DESCRIPTION("Renesas CEU camera driver");
+MODULE_AUTHOR("Jacopo Mondi <jacopo+renesas@jmondi.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 49cacc7a48d1..fa1ba98c96dc 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -140,7 +140,8 @@ void rga_buf_map(struct vb2_buffer *vb)
address = sg_phys(sgl);
for (p = 0; p < len; p++) {
- dma_addr_t phys = address + (p << PAGE_SHIFT);
+ dma_addr_t phys = address +
+ ((dma_addr_t)p << PAGE_SHIFT);
pages[mapped_size + p] = phys;
}
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 89296de9cf4a..d508a8ba6f89 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -207,7 +207,7 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
return 0;
}
-struct rga_fmt formats[] = {
+static struct rga_fmt formats[] = {
{
.fourcc = V4L2_PIX_FMT_ARGB32,
.color_swap = RGA_COLOR_RB_SWAP,
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index 437395a61065..9ab8e7ee2e1e 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -1256,16 +1256,17 @@ static void __camif_subdev_try_format(struct camif_dev *camif,
{
const struct s3c_camif_variant *variant = camif->variant;
const struct vp_pix_limits *pix_lim;
- int i = ARRAY_SIZE(camif_mbus_formats);
+ unsigned int i;
/* FIXME: constraints against codec or preview path ? */
pix_lim = &variant->vp_pix_limits[VP_CODEC];
- while (i-- >= 0)
+ for (i = 0; i < ARRAY_SIZE(camif_mbus_formats); i++)
if (camif_mbus_formats[i] == mf->code)
break;
- mf->code = camif_mbus_formats[i];
+ if (i == ARRAY_SIZE(camif_mbus_formats))
+ mf->code = camif_mbus_formats[0];
if (pad == CAMIF_SD_PAD_SINK) {
v4l_bound_align_image(&mf->width, 8, CAMIF_MAX_PIX_WIDTH,
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v10.h b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h
new file mode 100644
index 000000000000..fadd9139b489
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Register definition file for Samsung MFC V10.x Interface (FIMV) driver
+ *
+ */
+
+#ifndef _REGS_MFC_V10_H
+#define _REGS_MFC_V10_H
+
+#include <linux/sizes.h>
+#include "regs-mfc-v8.h"
+
+/* MFCv10 register definitions*/
+#define S5P_FIMV_MFC_CLOCK_OFF_V10 0x7120
+#define S5P_FIMV_MFC_STATE_V10 0x7124
+#define S5P_FIMV_D_STATIC_BUFFER_ADDR_V10 0xF570
+#define S5P_FIMV_D_STATIC_BUFFER_SIZE_V10 0xF574
+#define S5P_FIMV_E_NUM_T_LAYER_V10 0xFBAC
+#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER0_V10 0xFBB0
+#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER1_V10 0xFBB4
+#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER2_V10 0xFBB8
+#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER3_V10 0xFBBC
+#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER4_V10 0xFBC0
+#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER5_V10 0xFBC4
+#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER6_V10 0xFBC8
+#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0_V10 0xFD18
+#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER1_V10 0xFD1C
+#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER2_V10 0xFD20
+#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER3_V10 0xFD24
+#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER4_V10 0xFD28
+#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER5_V10 0xFD2C
+#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER6_V10 0xFD30
+#define S5P_FIMV_E_HEVC_OPTIONS_V10 0xFDD4
+#define S5P_FIMV_E_HEVC_REFRESH_PERIOD_V10 0xFDD8
+#define S5P_FIMV_E_HEVC_CHROMA_QP_OFFSET_V10 0xFDDC
+#define S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2_V10 0xFDE0
+#define S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2_V10 0xFDE4
+#define S5P_FIMV_E_HEVC_NAL_CONTROL_V10 0xFDE8
+
+/* MFCv10 Context buffer sizes */
+#define MFC_CTX_BUF_SIZE_V10 (30 * SZ_1K)
+#define MFC_H264_DEC_CTX_BUF_SIZE_V10 (2 * SZ_1M)
+#define MFC_OTHER_DEC_CTX_BUF_SIZE_V10 (20 * SZ_1K)
+#define MFC_H264_ENC_CTX_BUF_SIZE_V10 (100 * SZ_1K)
+#define MFC_HEVC_ENC_CTX_BUF_SIZE_V10 (30 * SZ_1K)
+#define MFC_OTHER_ENC_CTX_BUF_SIZE_V10 (15 * SZ_1K)
+
+/* MFCv10 variant defines */
+#define MAX_FW_SIZE_V10 (SZ_1M)
+#define MAX_CPB_SIZE_V10 (3 * SZ_1M)
+#define MFC_VERSION_V10 0xA0
+#define MFC_NUM_PORTS_V10 1
+
+/* MFCv10 codec defines*/
+#define S5P_FIMV_CODEC_HEVC_DEC 17
+#define S5P_FIMV_CODEC_VP9_DEC 18
+#define S5P_FIMV_CODEC_HEVC_ENC 26
+
+/* Decoder buffer size for MFC v10 */
+#define DEC_VP9_STATIC_BUFFER_SIZE 20480
+
+/* Encoder buffer size for MFC v10.0 */
+#define ENC_V100_BASE_SIZE(x, y) \
+ (((x + 3) * (y + 3) * 8) \
+ + ((y * 64) + 1280) * DIV_ROUND_UP(x, 8))
+
+#define ENC_V100_H264_ME_SIZE(x, y) \
+ (ENC_V100_BASE_SIZE(x, y) \
+ + (DIV_ROUND_UP(x * y, 64) * 32))
+
+#define ENC_V100_MPEG4_ME_SIZE(x, y) \
+ (ENC_V100_BASE_SIZE(x, y) \
+ + (DIV_ROUND_UP(x * y, 128) * 16))
+
+#define ENC_V100_VP8_ME_SIZE(x, y) \
+ ENC_V100_BASE_SIZE(x, y)
+
+#define ENC_V100_HEVC_ME_SIZE(x, y) \
+ (((x + 3) * (y + 3) * 32) \
+ + ((y * 128) + 1280) * DIV_ROUND_UP(x, 4))
+
+#endif /*_REGS_MFC_V10_H*/
+
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h
index 75f5f7511d72..bd639ae71023 100644
--- a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h
+++ b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h
@@ -17,6 +17,7 @@
/* Additional registers for v8 */
#define S5P_FIMV_D_MVC_NUM_VIEWS_V8 0xf104
+#define S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8 0xf108
#define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8 0xf144
#define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8 0xf148
#define S5P_FIMV_D_MV_BUFFER_SIZE_V8 0xf150
@@ -84,6 +85,7 @@
#define S5P_FIMV_E_VBV_BUFFER_SIZE_V8 0xf78c
#define S5P_FIMV_E_VBV_INIT_DELAY_V8 0xf790
+#define S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE_V8 0xf894
#define S5P_FIMV_E_ASPECT_RATIO_V8 0xfb4c
#define S5P_FIMV_E_EXTENDED_SAR_V8 0xfb50
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index d5b94fc0040e..a80251ed3143 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -526,6 +526,8 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
dev);
ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count,
dev);
+ ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops,
+ get_min_scratch_buf_size, dev);
if (ctx->img_width == 0 || ctx->img_height == 0)
ctx->state = MFCINST_ERROR;
else
@@ -1607,6 +1609,29 @@ static struct s5p_mfc_variant mfc_drvdata_v8_5433 = {
.num_clocks = 3,
};
+static struct s5p_mfc_buf_size_v6 mfc_buf_size_v10 = {
+ .dev_ctx = MFC_CTX_BUF_SIZE_V10,
+ .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V10,
+ .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V10,
+ .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V10,
+ .hevc_enc_ctx = MFC_HEVC_ENC_CTX_BUF_SIZE_V10,
+ .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V10,
+};
+
+static struct s5p_mfc_buf_size buf_size_v10 = {
+ .fw = MAX_FW_SIZE_V10,
+ .cpb = MAX_CPB_SIZE_V10,
+ .priv = &mfc_buf_size_v10,
+};
+
+static struct s5p_mfc_variant mfc_drvdata_v10 = {
+ .version = MFC_VERSION_V10,
+ .version_bit = MFC_V10_BIT,
+ .port_num = MFC_NUM_PORTS_V10,
+ .buf_size = &buf_size_v10,
+ .fw_name[0] = "s5p-mfc-v10.fw",
+};
+
static const struct of_device_id exynos_mfc_match[] = {
{
.compatible = "samsung,mfc-v5",
@@ -1623,6 +1648,9 @@ static const struct of_device_id exynos_mfc_match[] = {
}, {
.compatible = "samsung,exynos5433-mfc",
.data = &mfc_drvdata_v8_5433,
+ }, {
+ .compatible = "samsung,mfc-v10",
+ .data = &mfc_drvdata_v10,
},
{},
};
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c
index b1b149151d2d..7521fceb68f1 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c
@@ -101,6 +101,12 @@ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx)
case S5P_MFC_CODEC_VP8_DEC:
codec_type = S5P_FIMV_CODEC_VP8_DEC_V6;
break;
+ case S5P_MFC_CODEC_HEVC_DEC:
+ codec_type = S5P_FIMV_CODEC_HEVC_DEC;
+ break;
+ case S5P_MFC_CODEC_VP9_DEC:
+ codec_type = S5P_FIMV_CODEC_VP9_DEC;
+ break;
case S5P_MFC_CODEC_H264_ENC:
codec_type = S5P_FIMV_CODEC_H264_ENC_V6;
break;
@@ -116,6 +122,9 @@ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx)
case S5P_MFC_CODEC_VP8_ENC:
codec_type = S5P_FIMV_CODEC_VP8_ENC_V7;
break;
+ case S5P_MFC_CODEC_HEVC_ENC:
+ codec_type = S5P_FIMV_CODEC_HEVC_ENC;
+ break;
default:
codec_type = S5P_FIMV_CODEC_NONE_V6;
}
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
index 76119a8cc477..20442a9b9f7a 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
@@ -23,7 +23,7 @@
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-v4l2.h>
#include "regs-mfc.h"
-#include "regs-mfc-v8.h"
+#include "regs-mfc-v10.h"
#define S5P_MFC_NAME "s5p-mfc"
@@ -61,7 +61,7 @@
#define MFC_ENC_CAP_PLANE_COUNT 1
#define MFC_ENC_OUT_PLANE_COUNT 2
#define STUFF_BYTE 4
-#define MFC_MAX_CTRLS 77
+#define MFC_MAX_CTRLS 128
#define S5P_MFC_CODEC_NONE -1
#define S5P_MFC_CODEC_H264_DEC 0
@@ -72,12 +72,15 @@
#define S5P_MFC_CODEC_H263_DEC 5
#define S5P_MFC_CODEC_VC1RCV_DEC 6
#define S5P_MFC_CODEC_VP8_DEC 7
+#define S5P_MFC_CODEC_HEVC_DEC 17
+#define S5P_MFC_CODEC_VP9_DEC 18
#define S5P_MFC_CODEC_H264_ENC 20
#define S5P_MFC_CODEC_H264_MVC_ENC 21
#define S5P_MFC_CODEC_MPEG4_ENC 22
#define S5P_MFC_CODEC_H263_ENC 23
#define S5P_MFC_CODEC_VP8_ENC 24
+#define S5P_MFC_CODEC_HEVC_ENC 26
#define S5P_MFC_R2H_CMD_EMPTY 0
#define S5P_MFC_R2H_CMD_SYS_INIT_RET 1
@@ -213,6 +216,7 @@ struct s5p_mfc_buf_size_v6 {
unsigned int h264_dec_ctx;
unsigned int other_dec_ctx;
unsigned int h264_enc_ctx;
+ unsigned int hevc_enc_ctx;
unsigned int other_enc_ctx;
};
@@ -430,6 +434,55 @@ struct s5p_mfc_vp8_enc_params {
u8 profile;
};
+struct s5p_mfc_hevc_enc_params {
+ enum v4l2_mpeg_video_hevc_profile profile;
+ int level;
+ enum v4l2_mpeg_video_h264_level level_v4l2;
+ u8 tier;
+ u32 rc_framerate;
+ u8 rc_min_qp;
+ u8 rc_max_qp;
+ u8 rc_lcu_dark;
+ u8 rc_lcu_smooth;
+ u8 rc_lcu_static;
+ u8 rc_lcu_activity;
+ u8 rc_frame_qp;
+ u8 rc_p_frame_qp;
+ u8 rc_b_frame_qp;
+ u8 max_partition_depth;
+ u8 num_refs_for_p;
+ u8 refreshtype;
+ u16 refreshperiod;
+ s32 lf_beta_offset_div2;
+ s32 lf_tc_offset_div2;
+ u8 loopfilter;
+ u8 loopfilter_disable;
+ u8 loopfilter_across;
+ u8 nal_control_length_filed;
+ u8 nal_control_user_ref;
+ u8 nal_control_store_ref;
+ u8 const_intra_period_enable;
+ u8 lossless_cu_enable;
+ u8 wavefront_enable;
+ u8 enable_ltr;
+ u8 hier_qp_enable;
+ enum v4l2_mpeg_video_hevc_hier_coding_type hier_qp_type;
+ u8 num_hier_layer;
+ u8 hier_qp_layer[7];
+ u32 hier_bit_layer[7];
+ u8 sign_data_hiding;
+ u8 general_pb_enable;
+ u8 temporal_id_enable;
+ u8 strong_intra_smooth;
+ u8 intra_pu_split_disable;
+ u8 tmv_prediction_disable;
+ u8 max_num_merge_mv;
+ u8 eco_mode_enable;
+ u8 encoding_nostartcode_enable;
+ u8 size_of_length_field;
+ u8 prepend_sps_pps_to_idr;
+};
+
/**
* struct s5p_mfc_enc_params - general encoding parameters
*/
@@ -467,6 +520,7 @@ struct s5p_mfc_enc_params {
struct s5p_mfc_h264_enc_params h264;
struct s5p_mfc_mpeg4_enc_params mpeg4;
struct s5p_mfc_vp8_enc_params vp8;
+ struct s5p_mfc_hevc_enc_params hevc;
} codec;
};
@@ -714,12 +768,20 @@ void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq);
#define IS_TWOPORT(dev) (dev->variant->port_num == 2 ? 1 : 0)
#define IS_MFCV6_PLUS(dev) (dev->variant->version >= 0x60 ? 1 : 0)
#define IS_MFCV7_PLUS(dev) (dev->variant->version >= 0x70 ? 1 : 0)
-#define IS_MFCV8(dev) (dev->variant->version >= 0x80 ? 1 : 0)
+#define IS_MFCV8_PLUS(dev) (dev->variant->version >= 0x80 ? 1 : 0)
+#define IS_MFCV10(dev) (dev->variant->version >= 0xA0 ? 1 : 0)
+#define FW_HAS_E_MIN_SCRATCH_BUF(dev) (IS_MFCV10(dev))
#define MFC_V5_BIT BIT(0)
#define MFC_V6_BIT BIT(1)
#define MFC_V7_BIT BIT(2)
#define MFC_V8_BIT BIT(3)
+#define MFC_V10_BIT BIT(5)
+#define MFC_V5PLUS_BITS (MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | \
+ MFC_V8_BIT | MFC_V10_BIT)
+#define MFC_V6PLUS_BITS (MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT | \
+ MFC_V10_BIT)
+#define MFC_V7PLUS_BITS (MFC_V7_BIT | MFC_V8_BIT | MFC_V10_BIT)
#endif /* S5P_MFC_COMMON_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
index f95cd76af537..ee7b15b335e0 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
@@ -62,7 +62,7 @@ int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev)
if (!dev->variant->fw_name[i])
continue;
err = request_firmware((const struct firmware **)&fw_blob,
- dev->variant->fw_name[i], dev->v4l2_dev.dev);
+ dev->variant->fw_name[i], &dev->plat_dev->dev);
if (!err) {
dev->fw_ver = (enum s5p_mfc_fw_ver) i;
break;
@@ -239,6 +239,10 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
}
else
mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
+
+ if (IS_MFCV10(dev))
+ mfc_write(dev, 0x0, S5P_FIMV_MFC_CLOCK_OFF_V10);
+
mfc_debug(2, "Will now wait for completion of firmware transfer\n");
if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) {
mfc_err("Failed to load firmware\n");
@@ -399,7 +403,7 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
s5p_mfc_clear_cmds(dev);
s5p_mfc_clean_dev_int_flags(dev);
/* 3. Send MFC wakeup command and wait for completion*/
- if (IS_MFCV8(dev))
+ if (IS_MFCV8_PLUS(dev))
ret = s5p_mfc_v8_wait_wakeup(dev);
else
ret = s5p_mfc_wait_wakeup(dev);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index 8937b0af7cb3..5cf4d9921264 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -54,7 +54,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
- .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT,
+ .versions = MFC_V6PLUS_BITS,
},
{
.name = "4:2:0 2 Planes Y/CrCb",
@@ -62,7 +62,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
- .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT,
+ .versions = MFC_V6PLUS_BITS,
},
{
.name = "H264 Encoded Stream",
@@ -70,8 +70,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_H264_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
- .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
- MFC_V8_BIT,
+ .versions = MFC_V5PLUS_BITS,
},
{
.name = "H264/MVC Encoded Stream",
@@ -79,7 +78,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_H264_MVC_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
- .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT,
+ .versions = MFC_V6PLUS_BITS,
},
{
.name = "H263 Encoded Stream",
@@ -87,8 +86,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_H263_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
- .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
- MFC_V8_BIT,
+ .versions = MFC_V5PLUS_BITS,
},
{
.name = "MPEG1 Encoded Stream",
@@ -96,8 +94,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_MPEG2_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
- .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
- MFC_V8_BIT,
+ .versions = MFC_V5PLUS_BITS,
},
{
.name = "MPEG2 Encoded Stream",
@@ -105,8 +102,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_MPEG2_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
- .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
- MFC_V8_BIT,
+ .versions = MFC_V5PLUS_BITS,
},
{
.name = "MPEG4 Encoded Stream",
@@ -114,8 +110,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_MPEG4_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
- .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
- MFC_V8_BIT,
+ .versions = MFC_V5PLUS_BITS,
},
{
.name = "XviD Encoded Stream",
@@ -123,8 +118,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_MPEG4_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
- .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
- MFC_V8_BIT,
+ .versions = MFC_V5PLUS_BITS,
},
{
.name = "VC1 Encoded Stream",
@@ -132,8 +126,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_VC1_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
- .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
- MFC_V8_BIT,
+ .versions = MFC_V5PLUS_BITS,
},
{
.name = "VC1 RCV Encoded Stream",
@@ -141,8 +134,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_VC1RCV_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
- .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
- MFC_V8_BIT,
+ .versions = MFC_V5PLUS_BITS,
},
{
.name = "VP8 Encoded Stream",
@@ -150,7 +142,21 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_VP8_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
- .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT,
+ .versions = MFC_V6PLUS_BITS,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_HEVC,
+ .codec_mode = S5P_FIMV_CODEC_HEVC_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ .versions = MFC_V10_BIT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_VP9,
+ .codec_mode = S5P_FIMV_CODEC_VP9_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ .versions = MFC_V10_BIT,
},
};
@@ -1177,7 +1183,7 @@ void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx)
struct v4l2_format f;
f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
ctx->src_fmt = find_format(&f, MFC_FMT_DEC);
- if (IS_MFCV8(ctx->dev))
+ if (IS_MFCV8_PLUS(ctx->dev))
f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
else if (IS_MFCV6_PLUS(ctx->dev))
f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT_16X16;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index 0d5d465561be..5c0462ca9993 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -57,8 +57,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
- .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
- MFC_V8_BIT,
+ .versions = MFC_V5PLUS_BITS,
},
{
.name = "4:2:0 2 Planes Y/CrCb",
@@ -66,7 +65,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
- .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT,
+ .versions = MFC_V6PLUS_BITS,
},
{
.name = "H264 Encoded Stream",
@@ -74,8 +73,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_H264_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
- .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
- MFC_V8_BIT,
+ .versions = MFC_V5PLUS_BITS,
},
{
.name = "MPEG4 Encoded Stream",
@@ -83,8 +81,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_MPEG4_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
- .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
- MFC_V8_BIT,
+ .versions = MFC_V5PLUS_BITS,
},
{
.name = "H263 Encoded Stream",
@@ -92,8 +89,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_H263_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
- .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
- MFC_V8_BIT,
+ .versions = MFC_V5PLUS_BITS,
},
{
.name = "VP8 Encoded Stream",
@@ -101,7 +97,14 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_VP8_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
- .versions = MFC_V7_BIT | MFC_V8_BIT,
+ .versions = MFC_V7PLUS_BITS,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_HEVC,
+ .codec_mode = S5P_FIMV_CODEC_HEVC_ENC,
+ .type = MFC_FMT_ENC,
+ .num_planes = 1,
+ .versions = MFC_V10_BIT,
},
};
@@ -697,6 +700,368 @@ static struct mfc_control controls[] = {
.default_value = 0,
},
{
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC I Frame QP Value",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC P Frame QP Value",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+ .maximum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+ .maximum = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_TIER,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN,
+ .maximum = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 2,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE,
+ .maximum = V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED,
+ .maximum = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B,
+ .maximum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 6,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 4,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = -6,
+ .maximum = 6,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = -6,
+ .maximum = 6,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_HEVC_SIZE_0,
+ .maximum = V4L2_MPEG_VIDEO_HEVC_SIZE_4,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_HEVC_SIZE_0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
.id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Minimum number of output bufs",
@@ -817,6 +1182,11 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
get_enc_dpb_count, dev);
if (ctx->pb_count < enc_pb_count)
ctx->pb_count = enc_pb_count;
+ if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) {
+ ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops,
+ get_e_min_scratch_buf_size, dev);
+ ctx->bank1.size += ctx->scratch_buf_size;
+ }
ctx->state = MFCINST_HEAD_PRODUCED;
}
@@ -850,7 +1220,7 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf *mb_entry;
- unsigned long enc_y_addr, enc_c_addr;
+ unsigned long enc_y_addr = 0, enc_c_addr = 0;
unsigned long mb_y_addr, mb_c_addr;
int slice_type;
unsigned int strm_size;
@@ -1358,6 +1728,26 @@ static inline int mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl)
return t[lvl];
}
+static inline int hevc_level(enum v4l2_mpeg_video_hevc_level lvl)
+{
+ static unsigned int t[] = {
+ /* V4L2_MPEG_VIDEO_HEVC_LEVEL_1 */ 10,
+ /* V4L2_MPEG_VIDEO_HEVC_LEVEL_2 */ 20,
+ /* V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1 */ 21,
+ /* V4L2_MPEG_VIDEO_HEVC_LEVEL_3 */ 30,
+ /* V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1 */ 31,
+ /* V4L2_MPEG_VIDEO_HEVC_LEVEL_4 */ 40,
+ /* V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1 */ 41,
+ /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5 */ 50,
+ /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1 */ 51,
+ /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2 */ 52,
+ /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6 */ 60,
+ /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1 */ 61,
+ /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2 */ 62,
+ };
+ return t[lvl];
+}
+
static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar)
{
static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = {
@@ -1383,6 +1773,42 @@ static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar)
return t[sar];
}
+/*
+ * Update range of all HEVC quantization parameter controls that depend on the
+ * V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP controls.
+ */
+static void __enc_update_hevc_qp_ctrls_range(struct s5p_mfc_ctx *ctx,
+ int min, int max)
+{
+ static const int __hevc_qp_ctrls[] = {
+ V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP,
+ V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP,
+ };
+ struct v4l2_ctrl *ctrl = NULL;
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(__hevc_qp_ctrls); i++) {
+ for (j = 0; j < ARRAY_SIZE(ctx->ctrls); j++) {
+ if (ctx->ctrls[j]->id == __hevc_qp_ctrls[i]) {
+ ctrl = ctx->ctrls[j];
+ break;
+ }
+ }
+ if (WARN_ON(!ctrl))
+ break;
+
+ __v4l2_ctrl_modify_range(ctrl, min, max, ctrl->step, min);
+ }
+}
+
static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
@@ -1634,6 +2060,157 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_VPX_PROFILE:
p->codec.vp8.profile = ctrl->val;
break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP:
+ p->codec.hevc.rc_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP:
+ p->codec.hevc.rc_p_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP:
+ p->codec.hevc.rc_b_frame_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION:
+ p->codec.hevc.rc_framerate = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:
+ p->codec.hevc.rc_min_qp = ctrl->val;
+ __enc_update_hevc_qp_ctrls_range(ctx, ctrl->val,
+ p->codec.hevc.rc_max_qp);
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:
+ p->codec.hevc.rc_max_qp = ctrl->val;
+ __enc_update_hevc_qp_ctrls_range(ctx, p->codec.hevc.rc_min_qp,
+ ctrl->val);
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
+ p->codec.hevc.level_v4l2 = ctrl->val;
+ p->codec.hevc.level = hevc_level(ctrl->val);
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN:
+ p->codec.hevc.profile =
+ V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE:
+ p->codec.hevc.profile =
+ V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_TIER:
+ p->codec.hevc.tier = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH:
+ p->codec.hevc.max_partition_depth = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES:
+ p->codec.hevc.num_refs_for_p = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
+ p->codec.hevc.refreshtype = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED:
+ p->codec.hevc.const_intra_period_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU:
+ p->codec.hevc.lossless_cu_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT:
+ p->codec.hevc.wavefront_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
+ p->codec.hevc.loopfilter = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP:
+ p->codec.hevc.hier_qp_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE:
+ p->codec.hevc.hier_qp_type = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER:
+ p->codec.hevc.num_hier_layer = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP:
+ p->codec.hevc.hier_qp_layer[0] = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP:
+ p->codec.hevc.hier_qp_layer[1] = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP:
+ p->codec.hevc.hier_qp_layer[2] = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP:
+ p->codec.hevc.hier_qp_layer[3] = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP:
+ p->codec.hevc.hier_qp_layer[4] = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP:
+ p->codec.hevc.hier_qp_layer[5] = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP:
+ p->codec.hevc.hier_qp_layer[6] = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR:
+ p->codec.hevc.hier_bit_layer[0] = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR:
+ p->codec.hevc.hier_bit_layer[1] = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR:
+ p->codec.hevc.hier_bit_layer[2] = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR:
+ p->codec.hevc.hier_bit_layer[3] = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR:
+ p->codec.hevc.hier_bit_layer[4] = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR:
+ p->codec.hevc.hier_bit_layer[5] = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR:
+ p->codec.hevc.hier_bit_layer[6] = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB:
+ p->codec.hevc.general_pb_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID:
+ p->codec.hevc.temporal_id_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING:
+ p->codec.hevc.strong_intra_smooth = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT:
+ p->codec.hevc.intra_pu_split_disable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION:
+ p->codec.hevc.tmv_prediction_disable = !ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1:
+ p->codec.hevc.max_num_merge_mv = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE:
+ p->codec.hevc.encoding_nostartcode_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD:
+ p->codec.hevc.refreshperiod = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2:
+ p->codec.hevc.lf_beta_offset_div2 = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2:
+ p->codec.hevc.lf_tc_offset_div2 = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
+ p->codec.hevc.size_of_length_field = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR:
+ p->codec.hevc.prepend_sps_pps_to_idr = ctrl->val;
+ break;
default:
v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n",
ctrl->id, ctrl->val);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
index 16d553fcff08..8c295f0f9740 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
@@ -169,6 +169,9 @@ struct s5p_mfc_regs {
void __iomem *d_decoded_third_addr;/* only v7 */
void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */
void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */
+ void __iomem *d_min_scratch_buffer_size; /* v10 */
+ void __iomem *d_static_buffer_addr; /* v10 */
+ void __iomem *d_static_buffer_size; /* v10 */
/* encoder registers */
void __iomem *e_frame_width;
@@ -268,6 +271,15 @@ struct s5p_mfc_regs {
void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */
void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */
void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */
+ void __iomem *e_min_scratch_buffer_size; /* v10 */
+ void __iomem *e_num_t_layer; /* v10 */
+ void __iomem *e_hier_qp_layer0; /* v10 */
+ void __iomem *e_hier_bit_rate_layer0; /* v10 */
+ void __iomem *e_hevc_options; /* v10 */
+ void __iomem *e_hevc_refresh_period; /* v10 */
+ void __iomem *e_hevc_lf_beta_offset_div2; /* v10 */
+ void __iomem *e_hevc_lf_tc_offset_div2; /* v10 */
+ void __iomem *e_hevc_nal_control; /* v10 */
};
struct s5p_mfc_hw_ops {
@@ -311,6 +323,8 @@ struct s5p_mfc_hw_ops {
unsigned int (*get_pic_type_bot)(struct s5p_mfc_ctx *ctx);
unsigned int (*get_crop_info_h)(struct s5p_mfc_ctx *ctx);
unsigned int (*get_crop_info_v)(struct s5p_mfc_ctx *ctx);
+ int (*get_min_scratch_buf_size)(struct s5p_mfc_dev *dev);
+ int (*get_e_min_scratch_buf_size)(struct s5p_mfc_dev *dev);
};
void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
index 88dbb9c341ec..7c629be43205 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -64,6 +64,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
unsigned int mb_width, mb_height;
+ unsigned int lcu_width = 0, lcu_height = 0;
int ret;
mb_width = MB_WIDTH(ctx->img_width);
@@ -74,7 +75,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
ctx->luma_size, ctx->chroma_size, ctx->mv_size);
mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count);
} else if (ctx->type == MFCINST_ENCODER) {
- if (IS_MFCV8(dev))
+ if (IS_MFCV10(dev)) {
+ ctx->tmv_buffer_size = 0;
+ } else if (IS_MFCV8_PLUS(dev))
ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 *
ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V8(mb_width, mb_height),
S5P_FIMV_TMV_BUFFER_ALIGN_V6);
@@ -82,14 +85,37 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 *
ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V6(mb_width, mb_height),
S5P_FIMV_TMV_BUFFER_ALIGN_V6);
-
- ctx->luma_dpb_size = ALIGN((mb_width * mb_height) *
- S5P_FIMV_LUMA_MB_TO_PIXEL_V6,
- S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6);
- ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) *
- S5P_FIMV_CHROMA_MB_TO_PIXEL_V6,
- S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6);
- if (IS_MFCV8(dev))
+ if (IS_MFCV10(dev)) {
+ lcu_width = S5P_MFC_LCU_WIDTH(ctx->img_width);
+ lcu_height = S5P_MFC_LCU_HEIGHT(ctx->img_height);
+ if (ctx->codec_mode != S5P_FIMV_CODEC_HEVC_ENC) {
+ ctx->luma_dpb_size =
+ ALIGN((mb_width * 16), 64)
+ * ALIGN((mb_height * 16), 32)
+ + 64;
+ ctx->chroma_dpb_size =
+ ALIGN((mb_width * 16), 64)
+ * (mb_height * 8)
+ + 64;
+ } else {
+ ctx->luma_dpb_size =
+ ALIGN((lcu_width * 32), 64)
+ * ALIGN((lcu_height * 32), 32)
+ + 64;
+ ctx->chroma_dpb_size =
+ ALIGN((lcu_width * 32), 64)
+ * (lcu_height * 16)
+ + 64;
+ }
+ } else {
+ ctx->luma_dpb_size = ALIGN((mb_width * mb_height) *
+ S5P_FIMV_LUMA_MB_TO_PIXEL_V6,
+ S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6);
+ ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) *
+ S5P_FIMV_CHROMA_MB_TO_PIXEL_V6,
+ S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6);
+ }
+ if (IS_MFCV8_PLUS(dev))
ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V8(
ctx->img_width, ctx->img_height,
mb_width, mb_height),
@@ -110,7 +136,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
switch (ctx->codec_mode) {
case S5P_MFC_CODEC_H264_DEC:
case S5P_MFC_CODEC_H264_MVC_DEC:
- if (IS_MFCV8(dev))
+ if (IS_MFCV10(dev))
+ mfc_debug(2, "Use min scratch buffer size\n");
+ else if (IS_MFCV8_PLUS(dev))
ctx->scratch_buf_size =
S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V8(
mb_width,
@@ -127,7 +155,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
(ctx->mv_count * ctx->mv_size);
break;
case S5P_MFC_CODEC_MPEG4_DEC:
- if (IS_MFCV7_PLUS(dev)) {
+ if (IS_MFCV10(dev))
+ mfc_debug(2, "Use min scratch buffer size\n");
+ else if (IS_MFCV7_PLUS(dev)) {
ctx->scratch_buf_size =
S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V7(
mb_width,
@@ -145,10 +175,14 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
break;
case S5P_MFC_CODEC_VC1RCV_DEC:
case S5P_MFC_CODEC_VC1_DEC:
- ctx->scratch_buf_size =
- S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6(
- mb_width,
- mb_height);
+ if (IS_MFCV10(dev))
+ mfc_debug(2, "Use min scratch buffer size\n");
+ else
+ ctx->scratch_buf_size =
+ S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6(
+ mb_width,
+ mb_height);
+
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
ctx->bank1.size = ctx->scratch_buf_size;
@@ -158,16 +192,21 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
ctx->bank2.size = 0;
break;
case S5P_MFC_CODEC_H263_DEC:
- ctx->scratch_buf_size =
- S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6(
- mb_width,
- mb_height);
+ if (IS_MFCV10(dev))
+ mfc_debug(2, "Use min scratch buffer size\n");
+ else
+ ctx->scratch_buf_size =
+ S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6(
+ mb_width,
+ mb_height);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
ctx->bank1.size = ctx->scratch_buf_size;
break;
case S5P_MFC_CODEC_VP8_DEC:
- if (IS_MFCV8(dev))
+ if (IS_MFCV10(dev))
+ mfc_debug(2, "Use min scratch buffer size\n");
+ else if (IS_MFCV8_PLUS(dev))
ctx->scratch_buf_size =
S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V8(
mb_width,
@@ -181,8 +220,24 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
ctx->bank1.size = ctx->scratch_buf_size;
break;
+ case S5P_MFC_CODEC_HEVC_DEC:
+ mfc_debug(2, "Use min scratch buffer size\n");
+ ctx->bank1.size =
+ ctx->scratch_buf_size +
+ (ctx->mv_count * ctx->mv_size);
+ break;
+ case S5P_MFC_CODEC_VP9_DEC:
+ mfc_debug(2, "Use min scratch buffer size\n");
+ ctx->bank1.size =
+ ctx->scratch_buf_size +
+ DEC_VP9_STATIC_BUFFER_SIZE;
+ break;
case S5P_MFC_CODEC_H264_ENC:
- if (IS_MFCV8(dev))
+ if (IS_MFCV10(dev)) {
+ mfc_debug(2, "Use min scratch buffer size\n");
+ ctx->me_buffer_size =
+ ALIGN(ENC_V100_H264_ME_SIZE(mb_width, mb_height), 16);
+ } else if (IS_MFCV8_PLUS(dev))
ctx->scratch_buf_size =
S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V8(
mb_width,
@@ -202,10 +257,16 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
break;
case S5P_MFC_CODEC_MPEG4_ENC:
case S5P_MFC_CODEC_H263_ENC:
- ctx->scratch_buf_size =
- S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6(
- mb_width,
- mb_height);
+ if (IS_MFCV10(dev)) {
+ mfc_debug(2, "Use min scratch buffer size\n");
+ ctx->me_buffer_size =
+ ALIGN(ENC_V100_MPEG4_ME_SIZE(mb_width,
+ mb_height), 16);
+ } else
+ ctx->scratch_buf_size =
+ S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6(
+ mb_width,
+ mb_height);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
ctx->bank1.size =
@@ -215,7 +276,12 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
ctx->bank2.size = 0;
break;
case S5P_MFC_CODEC_VP8_ENC:
- if (IS_MFCV8(dev))
+ if (IS_MFCV10(dev)) {
+ mfc_debug(2, "Use min scratch buffer size\n");
+ ctx->me_buffer_size =
+ ALIGN(ENC_V100_VP8_ME_SIZE(mb_width, mb_height),
+ 16);
+ } else if (IS_MFCV8_PLUS(dev))
ctx->scratch_buf_size =
S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V8(
mb_width,
@@ -233,6 +299,17 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
ctx->chroma_dpb_size + ctx->me_buffer_size));
ctx->bank2.size = 0;
break;
+ case S5P_MFC_CODEC_HEVC_ENC:
+ mfc_debug(2, "Use min scratch buffer size\n");
+ ctx->me_buffer_size =
+ ALIGN(ENC_V100_HEVC_ME_SIZE(lcu_width, lcu_height), 16);
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->bank1.size =
+ ctx->scratch_buf_size + ctx->tmv_buffer_size +
+ (ctx->pb_count * (ctx->luma_dpb_size +
+ ctx->chroma_dpb_size + ctx->me_buffer_size));
+ ctx->bank2.size = 0;
+ break;
default:
break;
}
@@ -267,6 +344,7 @@ static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx)
switch (ctx->codec_mode) {
case S5P_MFC_CODEC_H264_DEC:
case S5P_MFC_CODEC_H264_MVC_DEC:
+ case S5P_MFC_CODEC_HEVC_DEC:
ctx->ctx.size = buf_size->h264_dec_ctx;
break;
case S5P_MFC_CODEC_MPEG4_DEC:
@@ -275,11 +353,15 @@ static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx)
case S5P_MFC_CODEC_VC1_DEC:
case S5P_MFC_CODEC_MPEG2_DEC:
case S5P_MFC_CODEC_VP8_DEC:
+ case S5P_MFC_CODEC_VP9_DEC:
ctx->ctx.size = buf_size->other_dec_ctx;
break;
case S5P_MFC_CODEC_H264_ENC:
ctx->ctx.size = buf_size->h264_enc_ctx;
break;
+ case S5P_MFC_CODEC_HEVC_ENC:
+ ctx->ctx.size = buf_size->hevc_enc_ctx;
+ break;
case S5P_MFC_CODEC_MPEG4_ENC:
case S5P_MFC_CODEC_H263_ENC:
case S5P_MFC_CODEC_VP8_ENC:
@@ -356,6 +438,7 @@ static int calc_plane(int width, int height)
static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx)
{
+ struct s5p_mfc_dev *dev = ctx->dev;
ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6);
ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6);
mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n"
@@ -364,7 +447,7 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx)
ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height);
ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1));
- if (IS_MFCV8(ctx->dev)) {
+ if (IS_MFCV8_PLUS(ctx->dev)) {
/* MFCv8 needs additional 64 bytes for luma,chroma dpb*/
ctx->luma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
ctx->chroma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
@@ -372,9 +455,17 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx)
if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) {
- ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width,
+ if (IS_MFCV10(dev)) {
+ ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V10(ctx->img_width,
+ ctx->img_height);
+ } else {
+ ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width,
+ ctx->img_height);
+ }
+ } else if (ctx->codec_mode == S5P_MFC_CODEC_HEVC_DEC) {
+ ctx->mv_size = s5p_mfc_dec_hevc_mv_size(ctx->img_width,
ctx->img_height);
- ctx->mv_size = ALIGN(ctx->mv_size, 16);
+ ctx->mv_size = ALIGN(ctx->mv_size, 32);
} else {
ctx->mv_size = 0;
}
@@ -445,7 +536,7 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
writel(buf_addr1, mfc_regs->d_scratch_buffer_addr);
writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size);
- if (IS_MFCV8(dev)) {
+ if (IS_MFCV8_PLUS(dev)) {
writel(ctx->img_width,
mfc_regs->d_first_plane_dpb_stride_size);
writel(ctx->img_width,
@@ -456,7 +547,8 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
buf_size1 -= ctx->scratch_buf_size;
if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
- ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC){
+ ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC ||
+ ctx->codec_mode == S5P_FIMV_CODEC_HEVC_DEC) {
writel(ctx->mv_size, mfc_regs->d_mv_buffer_size);
writel(ctx->mv_count, mfc_regs->d_num_mv);
}
@@ -479,7 +571,8 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
mfc_regs->d_second_plane_dpb + i * 4);
}
if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
- ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) {
+ ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC ||
+ ctx->codec_mode == S5P_MFC_CODEC_HEVC_DEC) {
for (i = 0; i < ctx->mv_count; i++) {
/* To test alignment */
align_gap = buf_addr1;
@@ -494,6 +587,13 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
buf_size1 -= frame_size_mv;
}
}
+ if (ctx->codec_mode == S5P_FIMV_CODEC_VP9_DEC) {
+ writel(buf_addr1, mfc_regs->d_static_buffer_addr);
+ writel(DEC_VP9_STATIC_BUFFER_SIZE,
+ mfc_regs->d_static_buffer_size);
+ buf_addr1 += DEC_VP9_STATIC_BUFFER_SIZE;
+ buf_size1 -= DEC_VP9_STATIC_BUFFER_SIZE;
+ }
mfc_debug(2, "Buf1: %zx, buf_size1: %d (frames %d)\n",
buf_addr1, buf_size1, ctx->total_dpb_count);
@@ -571,15 +671,34 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx)
mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1);
- for (i = 0; i < ctx->pb_count; i++) {
- writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i));
- buf_addr1 += ctx->luma_dpb_size;
- writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i));
- buf_addr1 += ctx->chroma_dpb_size;
- writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i));
- buf_addr1 += ctx->me_buffer_size;
- buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size +
- ctx->me_buffer_size);
+ if (IS_MFCV10(dev)) {
+ /* start address of per buffer is aligned */
+ for (i = 0; i < ctx->pb_count; i++) {
+ writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i));
+ buf_addr1 += ctx->luma_dpb_size;
+ buf_size1 -= ctx->luma_dpb_size;
+ }
+ for (i = 0; i < ctx->pb_count; i++) {
+ writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i));
+ buf_addr1 += ctx->chroma_dpb_size;
+ buf_size1 -= ctx->chroma_dpb_size;
+ }
+ for (i = 0; i < ctx->pb_count; i++) {
+ writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i));
+ buf_addr1 += ctx->me_buffer_size;
+ buf_size1 -= ctx->me_buffer_size;
+ }
+ } else {
+ for (i = 0; i < ctx->pb_count; i++) {
+ writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i));
+ buf_addr1 += ctx->luma_dpb_size;
+ writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i));
+ buf_addr1 += ctx->chroma_dpb_size;
+ writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i));
+ buf_addr1 += ctx->me_buffer_size;
+ buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size
+ + ctx->me_buffer_size);
+ }
}
writel(buf_addr1, mfc_regs->e_scratch_buffer_addr);
@@ -1321,6 +1440,162 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
return 0;
}
+static int s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
+ struct s5p_mfc_enc_params *p = &ctx->enc_params;
+ struct s5p_mfc_hevc_enc_params *p_hevc = &p->codec.hevc;
+ unsigned int reg = 0;
+ int i;
+
+ mfc_debug_enter();
+
+ s5p_mfc_set_enc_params(ctx);
+
+ /* pictype : number of B */
+ reg = readl(mfc_regs->e_gop_config);
+ /* num_b_frame - 0 ~ 2 */
+ reg &= ~(0x3 << 16);
+ reg |= (p->num_b_frame << 16);
+ writel(reg, mfc_regs->e_gop_config);
+
+ /* UHD encoding case */
+ if ((ctx->img_width == 3840) && (ctx->img_height == 2160)) {
+ p_hevc->level = 51;
+ p_hevc->tier = 0;
+ /* this tier can be changed */
+ }
+
+ /* tier & level */
+ reg = 0;
+ /* profile */
+ reg |= p_hevc->profile & 0x3;
+ /* level */
+ reg &= ~(0xFF << 8);
+ reg |= (p_hevc->level << 8);
+ /* tier - 0 ~ 1 */
+ reg |= (p_hevc->tier << 16);
+ writel(reg, mfc_regs->e_picture_profile);
+
+ switch (p_hevc->loopfilter) {
+ case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED:
+ p_hevc->loopfilter_disable = 1;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED:
+ p_hevc->loopfilter_disable = 0;
+ p_hevc->loopfilter_across = 1;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY:
+ p_hevc->loopfilter_disable = 0;
+ p_hevc->loopfilter_across = 0;
+ break;
+ }
+
+ /* max partition depth */
+ reg = 0;
+ reg |= (p_hevc->max_partition_depth & 0x1);
+ reg |= (p_hevc->num_refs_for_p-1) << 2;
+ reg |= (p_hevc->refreshtype & 0x3) << 3;
+ reg |= (p_hevc->const_intra_period_enable & 0x1) << 5;
+ reg |= (p_hevc->lossless_cu_enable & 0x1) << 6;
+ reg |= (p_hevc->wavefront_enable & 0x1) << 7;
+ reg |= (p_hevc->loopfilter_disable & 0x1) << 8;
+ reg |= (p_hevc->loopfilter_across & 0x1) << 9;
+ reg |= (p_hevc->enable_ltr & 0x1) << 10;
+ reg |= (p_hevc->hier_qp_enable & 0x1) << 11;
+ reg |= (p_hevc->general_pb_enable & 0x1) << 13;
+ reg |= (p_hevc->temporal_id_enable & 0x1) << 14;
+ reg |= (p_hevc->strong_intra_smooth & 0x1) << 15;
+ reg |= (p_hevc->intra_pu_split_disable & 0x1) << 16;
+ reg |= (p_hevc->tmv_prediction_disable & 0x1) << 17;
+ reg |= (p_hevc->max_num_merge_mv & 0x7) << 18;
+ reg |= (p_hevc->encoding_nostartcode_enable & 0x1) << 23;
+ reg |= (p_hevc->prepend_sps_pps_to_idr << 26);
+
+ writel(reg, mfc_regs->e_hevc_options);
+ /* refresh period */
+ if (p_hevc->refreshtype) {
+ reg = 0;
+ reg |= (p_hevc->refreshperiod & 0xFFFF);
+ writel(reg, mfc_regs->e_hevc_refresh_period);
+ }
+ /* loop filter setting */
+ if (!(p_hevc->loopfilter_disable & 0x1)) {
+ reg = 0;
+ reg |= (p_hevc->lf_beta_offset_div2);
+ writel(reg, mfc_regs->e_hevc_lf_beta_offset_div2);
+ reg = 0;
+ reg |= (p_hevc->lf_tc_offset_div2);
+ writel(reg, mfc_regs->e_hevc_lf_tc_offset_div2);
+ }
+ /* hier qp enable */
+ if (p_hevc->num_hier_layer) {
+ reg = 0;
+ reg |= (p_hevc->hier_qp_type & 0x1) << 0x3;
+ reg |= p_hevc->num_hier_layer & 0x7;
+ writel(reg, mfc_regs->e_num_t_layer);
+ /* QP value for each layer */
+ if (p_hevc->hier_qp_enable) {
+ for (i = 0; i < 7; i++)
+ writel(p_hevc->hier_qp_layer[i],
+ mfc_regs->e_hier_qp_layer0 + i * 4);
+ }
+ if (p->rc_frame) {
+ for (i = 0; i < 7; i++)
+ writel(p_hevc->hier_bit_layer[i],
+ mfc_regs->e_hier_bit_rate_layer0
+ + i * 4);
+ }
+ }
+
+ /* rate control config. */
+ reg = readl(mfc_regs->e_rc_config);
+ /* macroblock level rate control */
+ reg &= ~(0x1 << 8);
+ reg |= (p->rc_mb << 8);
+ writel(reg, mfc_regs->e_rc_config);
+ /* frame QP */
+ reg &= ~(0xFF);
+ reg |= p_hevc->rc_frame_qp;
+ writel(reg, mfc_regs->e_rc_config);
+
+ /* frame rate */
+ if (p->rc_frame) {
+ reg = 0;
+ reg &= ~(0xFFFF << 16);
+ reg |= ((p_hevc->rc_framerate) << 16);
+ reg &= ~(0xFFFF);
+ reg |= FRAME_DELTA_DEFAULT;
+ writel(reg, mfc_regs->e_rc_frame_rate);
+ }
+
+ /* max & min value of QP */
+ reg = 0;
+ /* max QP */
+ reg &= ~(0xFF << 8);
+ reg |= (p_hevc->rc_max_qp << 8);
+ /* min QP */
+ reg &= ~(0xFF);
+ reg |= p_hevc->rc_min_qp;
+ writel(reg, mfc_regs->e_rc_qp_bound);
+
+ writel(0x0, mfc_regs->e_fixed_picture_qp);
+ if (!p->rc_frame && !p->rc_mb) {
+ reg = 0;
+ reg &= ~(0xFF << 16);
+ reg |= (p_hevc->rc_b_frame_qp << 16);
+ reg &= ~(0xFF << 8);
+ reg |= (p_hevc->rc_p_frame_qp << 8);
+ reg &= ~(0xFF);
+ reg |= p_hevc->rc_frame_qp;
+ writel(reg, mfc_regs->e_fixed_picture_qp);
+ }
+ mfc_debug_leave();
+
+ return 0;
+}
+
/* Initialize decoding */
static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
{
@@ -1440,6 +1715,8 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
s5p_mfc_set_enc_params_h263(ctx);
else if (ctx->codec_mode == S5P_MFC_CODEC_VP8_ENC)
s5p_mfc_set_enc_params_vp8(ctx);
+ else if (ctx->codec_mode == S5P_FIMV_CODEC_HEVC_ENC)
+ s5p_mfc_set_enc_params_hevc(ctx);
else {
mfc_err("Unknown codec for encoding (%x).\n",
ctx->codec_mode);
@@ -1895,6 +2172,16 @@ static int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev)
return readl(dev->mfc_regs->d_min_num_mv);
}
+static int s5p_mfc_get_min_scratch_buf_size(struct s5p_mfc_dev *dev)
+{
+ return readl(dev->mfc_regs->d_min_scratch_buffer_size);
+}
+
+static int s5p_mfc_get_e_min_scratch_buf_size(struct s5p_mfc_dev *dev)
+{
+ return readl(dev->mfc_regs->e_min_scratch_buffer_size);
+}
+
static int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev)
{
return readl(dev->mfc_regs->ret_instance_id);
@@ -2109,7 +2396,7 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7);
R(e_vp8_options, S5P_FIMV_E_VP8_OPTIONS_V7);
- if (!IS_MFCV8(dev))
+ if (!IS_MFCV8_PLUS(dev))
goto done;
/* Initialize registers used in MFC v8 only.
@@ -2153,6 +2440,7 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
R(d_ret_picture_tag_bot, S5P_FIMV_D_RET_PICTURE_TAG_BOT_V8);
R(d_display_crop_info1, S5P_FIMV_D_DISPLAY_CROP_INFO1_V8);
R(d_display_crop_info2, S5P_FIMV_D_DISPLAY_CROP_INFO2_V8);
+ R(d_min_scratch_buffer_size, S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8);
/* encoder registers */
R(e_padding_ctrl, S5P_FIMV_E_PADDING_CTRL_V8);
@@ -2168,6 +2456,29 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
R(e_aspect_ratio, S5P_FIMV_E_ASPECT_RATIO_V8);
R(e_extended_sar, S5P_FIMV_E_EXTENDED_SAR_V8);
R(e_h264_options, S5P_FIMV_E_H264_OPTIONS_V8);
+ R(e_min_scratch_buffer_size, S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE_V8);
+
+ if (!IS_MFCV10(dev))
+ goto done;
+
+ /* Initialize registers used in MFC v10 only.
+ * Also, over-write the registers which have
+ * a different offset for MFC v10.
+ */
+
+ /* decoder registers */
+ R(d_static_buffer_addr, S5P_FIMV_D_STATIC_BUFFER_ADDR_V10);
+ R(d_static_buffer_size, S5P_FIMV_D_STATIC_BUFFER_SIZE_V10);
+
+ /* encoder registers */
+ R(e_num_t_layer, S5P_FIMV_E_NUM_T_LAYER_V10);
+ R(e_hier_qp_layer0, S5P_FIMV_E_HIERARCHICAL_QP_LAYER0_V10);
+ R(e_hier_bit_rate_layer0, S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0_V10);
+ R(e_hevc_options, S5P_FIMV_E_HEVC_OPTIONS_V10);
+ R(e_hevc_refresh_period, S5P_FIMV_E_HEVC_REFRESH_PERIOD_V10);
+ R(e_hevc_lf_beta_offset_div2, S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2_V10);
+ R(e_hevc_lf_tc_offset_div2, S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2_V10);
+ R(e_hevc_nal_control, S5P_FIMV_E_HEVC_NAL_CONTROL_V10);
done:
return &mfc_regs;
@@ -2216,6 +2527,8 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = {
.get_pic_type_bot = s5p_mfc_get_pic_type_bot_v6,
.get_crop_info_h = s5p_mfc_get_crop_info_h_v6,
.get_crop_info_v = s5p_mfc_get_crop_info_v_v6,
+ .get_min_scratch_buf_size = s5p_mfc_get_min_scratch_buf_size,
+ .get_e_min_scratch_buf_size = s5p_mfc_get_e_min_scratch_buf_size,
};
struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void)
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h
index 80558484bb40..f013b291ae5b 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h
@@ -24,6 +24,13 @@
#define MB_HEIGHT(y_size) DIV_ROUND_UP(y_size, 16)
#define S5P_MFC_DEC_MV_SIZE_V6(x, y) (MB_WIDTH(x) * \
(((MB_HEIGHT(y)+1)/2)*2) * 64 + 128)
+#define S5P_MFC_DEC_MV_SIZE_V10(x, y) (MB_WIDTH(x) * \
+ (((MB_HEIGHT(y)+1)/2)*2) * 64 + 512)
+#define S5P_MFC_LCU_WIDTH(x_size) DIV_ROUND_UP(x_size, 32)
+#define S5P_MFC_LCU_HEIGHT(y_size) DIV_ROUND_UP(y_size, 32)
+
+#define s5p_mfc_dec_hevc_mv_size(x, y) \
+ (DIV_ROUND_UP(x, 64) * DIV_ROUND_UP(y, 64) * 256 + 512)
/* Definition */
#define ENC_MULTI_SLICE_MB_MAX ((1 << 30) - 1)
@@ -39,6 +46,14 @@
#define ENC_MPEG4_VOP_TIME_RES_MAX ((1 << 16) - 1)
#define FRAME_DELTA_H264_H263 1
#define TIGHT_CBR_MAX 10
+#define ENC_HEVC_RC_FRAME_RATE_MAX ((1 << 16) - 1)
+#define ENC_HEVC_QP_INDEX_MIN -12
+#define ENC_HEVC_QP_INDEX_MAX 12
+#define ENC_HEVC_LOOP_FILTER_MIN -12
+#define ENC_HEVC_LOOP_FILTER_MAX 12
+#define ENC_HEVC_LEVEL_MAX 62
+
+#define FRAME_DELTA_DEFAULT 1
struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void);
const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev);
diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c
index 976ea0bb5b6c..1a0cde017fdf 100644
--- a/drivers/media/platform/sh_veu.c
+++ b/drivers/media/platform/sh_veu.c
@@ -520,8 +520,8 @@ static void sh_veu_colour_offset(struct sh_veu_dev *veu, struct sh_veu_vfmt *vfm
/* dst_left and dst_top validity will be verified in CROP / COMPOSE */
unsigned int left = vfmt->frame.left & ~0x03;
unsigned int top = vfmt->frame.top;
- dma_addr_t offset = ((left * veu->vfmt_out.fmt->depth) >> 3) +
- top * veu->vfmt_out.bytesperline;
+ dma_addr_t offset = (dma_addr_t)top * veu->vfmt_out.bytesperline +
+ (((dma_addr_t)left * veu->vfmt_out.fmt->depth) >> 3);
unsigned int y_line;
vfmt->offset_y = offset;
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index c86dd2fdab84..69f0d8e80bd8 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -787,7 +787,7 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
int err;
- dev_dbg(icd->pdev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+ dev_dbg(icd->pdev, "mmap called, vma=%p\n", vma);
if (icd->streamer != file)
return -EBUSY;
@@ -1788,17 +1788,19 @@ static int default_s_selection(struct soc_camera_device *icd,
}
static int default_g_parm(struct soc_camera_device *icd,
- struct v4l2_streamparm *parm)
+ struct v4l2_streamparm *a)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return v4l2_subdev_call(sd, video, g_parm, parm);
+
+ return v4l2_g_parm_cap(icd->vdev, sd, a);
}
static int default_s_parm(struct soc_camera_device *icd,
- struct v4l2_streamparm *parm)
+ struct v4l2_streamparm *a)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return v4l2_subdev_call(sd, video, s_parm, parm);
+
+ return v4l2_s_parm_cap(icd->vdev, sd, a);
}
static int default_enum_framesizes(struct soc_camera_device *icd,
diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c
index 0e5aa17bdd40..7c496bc1cf38 100644
--- a/drivers/media/platform/stm32/stm32-cec.c
+++ b/drivers/media/platform/stm32/stm32-cec.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* STM32 CEC driver
* Copyright (C) STMicroelectronics SA 2017
*
- * 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>
diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
index 9460b3080dca..2e1933d872ee 100644
--- a/drivers/media/platform/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/stm32/stm32-dcmi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Driver for STM32 Digital Camera Memory Interface
*
@@ -5,7 +6,6 @@
* Authors: Yannick Fertre <yannick.fertre@st.com>
* Hugues Fruchet <hugues.fruchet@st.com>
* for STMicroelectronics.
- * License terms: GNU General Public License (GPL), version 2
*
* This driver is based on atmel_isi.c
*
@@ -93,6 +93,11 @@ enum state {
#define MIN_HEIGHT 16U
#define MAX_HEIGHT 2048U
+#define MIN_JPEG_WIDTH 16U
+#define MAX_JPEG_WIDTH 2592U
+#define MIN_JPEG_HEIGHT 16U
+#define MAX_JPEG_HEIGHT 2592U
+
#define TIMEOUT_MS 1000
struct dcmi_graph_entity {
@@ -160,6 +165,7 @@ struct stm32_dcmi {
dma_cookie_t dma_cookie;
u32 misr;
int errors_count;
+ int overrun_count;
int buffers_count;
};
@@ -190,14 +196,67 @@ static inline void reg_clear(void __iomem *base, u32 reg, u32 mask)
static int dcmi_start_capture(struct stm32_dcmi *dcmi);
+static void dcmi_buffer_done(struct stm32_dcmi *dcmi,
+ struct dcmi_buf *buf,
+ size_t bytesused,
+ int err)
+{
+ struct vb2_v4l2_buffer *vbuf;
+
+ if (!buf)
+ return;
+
+ vbuf = &buf->vb;
+
+ vbuf->sequence = dcmi->sequence++;
+ vbuf->field = V4L2_FIELD_NONE;
+ vbuf->vb2_buf.timestamp = ktime_get_ns();
+ vb2_set_plane_payload(&vbuf->vb2_buf, 0, bytesused);
+ vb2_buffer_done(&vbuf->vb2_buf,
+ err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+ dev_dbg(dcmi->dev, "buffer[%d] done seq=%d, bytesused=%zu\n",
+ vbuf->vb2_buf.index, vbuf->sequence, bytesused);
+
+ dcmi->buffers_count++;
+ dcmi->active = NULL;
+}
+
+static int dcmi_restart_capture(struct stm32_dcmi *dcmi)
+{
+ spin_lock_irq(&dcmi->irqlock);
+
+ if (dcmi->state != RUNNING) {
+ spin_unlock_irq(&dcmi->irqlock);
+ return -EINVAL;
+ }
+
+ /* Restart a new DMA transfer with next buffer */
+ if (list_empty(&dcmi->buffers)) {
+ dev_err(dcmi->dev, "%s: No more buffer queued, cannot capture buffer\n",
+ __func__);
+ dcmi->errors_count++;
+ dcmi->active = NULL;
+
+ spin_unlock_irq(&dcmi->irqlock);
+ return -EINVAL;
+ }
+
+ dcmi->active = list_entry(dcmi->buffers.next,
+ struct dcmi_buf, list);
+ list_del_init(&dcmi->active->list);
+
+ spin_unlock_irq(&dcmi->irqlock);
+
+ return dcmi_start_capture(dcmi);
+}
+
static void dcmi_dma_callback(void *param)
{
struct stm32_dcmi *dcmi = (struct stm32_dcmi *)param;
struct dma_chan *chan = dcmi->dma_chan;
struct dma_tx_state state;
enum dma_status status;
-
- spin_lock(&dcmi->irqlock);
+ struct dcmi_buf *buf = dcmi->active;
/* Check DMA status */
status = dmaengine_tx_status(chan, dcmi->dma_cookie, &state);
@@ -215,58 +274,18 @@ static void dcmi_dma_callback(void *param)
case DMA_COMPLETE:
dev_dbg(dcmi->dev, "%s: Received DMA_COMPLETE\n", __func__);
- if (dcmi->active) {
- struct dcmi_buf *buf = dcmi->active;
- struct vb2_v4l2_buffer *vbuf = &dcmi->active->vb;
-
- vbuf->sequence = dcmi->sequence++;
- vbuf->field = V4L2_FIELD_NONE;
- vbuf->vb2_buf.timestamp = ktime_get_ns();
- vb2_set_plane_payload(&vbuf->vb2_buf, 0, buf->size);
- vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
- dev_dbg(dcmi->dev, "buffer[%d] done seq=%d\n",
- vbuf->vb2_buf.index, vbuf->sequence);
-
- dcmi->buffers_count++;
- dcmi->active = NULL;
- }
-
- /* Restart a new DMA transfer with next buffer */
- if (dcmi->state == RUNNING) {
- if (list_empty(&dcmi->buffers)) {
- dev_err(dcmi->dev, "%s: No more buffer queued, cannot capture buffer",
- __func__);
- dcmi->errors_count++;
- dcmi->active = NULL;
-
- spin_unlock(&dcmi->irqlock);
- return;
- }
-
- dcmi->active = list_entry(dcmi->buffers.next,
- struct dcmi_buf, list);
-
- list_del_init(&dcmi->active->list);
-
- if (dcmi_start_capture(dcmi)) {
- dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete",
- __func__);
-
- spin_unlock(&dcmi->irqlock);
- return;
- }
-
- /* Enable capture */
- reg_set(dcmi->regs, DCMI_CR, CR_CAPTURE);
- }
+ /* Return buffer to V4L2 */
+ dcmi_buffer_done(dcmi, buf, buf->size, 0);
+ /* Restart capture */
+ if (dcmi_restart_capture(dcmi))
+ dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete\n",
+ __func__);
break;
default:
dev_err(dcmi->dev, "%s: Received unknown status\n", __func__);
break;
}
-
- spin_unlock(&dcmi->irqlock);
}
static int dcmi_start_dma(struct stm32_dcmi *dcmi,
@@ -359,11 +378,57 @@ static void dcmi_set_crop(struct stm32_dcmi *dcmi)
reg_set(dcmi->regs, DCMI_CR, CR_CROP);
}
+static void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
+{
+ struct dma_tx_state state;
+ enum dma_status status;
+ struct dma_chan *chan = dcmi->dma_chan;
+ struct dcmi_buf *buf = dcmi->active;
+
+ if (!buf)
+ return;
+
+ /*
+ * Because of variable JPEG buffer size sent by sensor,
+ * DMA transfer never completes due to transfer size
+ * never reached.
+ * In order to ensure that all the JPEG data are transferred
+ * in active buffer memory, DMA is drained.
+ * Then DMA tx status gives the amount of data transferred
+ * to memory, which is then returned to V4L2 through the active
+ * buffer payload.
+ */
+
+ /* Drain DMA */
+ dmaengine_synchronize(chan);
+
+ /* Get DMA residue to get JPEG size */
+ status = dmaengine_tx_status(chan, dcmi->dma_cookie, &state);
+ if (status != DMA_ERROR && state.residue < buf->size) {
+ /* Return JPEG buffer to V4L2 with received JPEG buffer size */
+ dcmi_buffer_done(dcmi, buf, buf->size - state.residue, 0);
+ } else {
+ dcmi->errors_count++;
+ dev_err(dcmi->dev, "%s: Cannot get JPEG size from DMA\n",
+ __func__);
+ /* Return JPEG buffer to V4L2 in ERROR state */
+ dcmi_buffer_done(dcmi, buf, 0, -EIO);
+ }
+
+ /* Abort DMA operation */
+ dmaengine_terminate_all(dcmi->dma_chan);
+
+ /* Restart capture */
+ if (dcmi_restart_capture(dcmi))
+ dev_err(dcmi->dev, "%s: Cannot restart capture on JPEG received\n",
+ __func__);
+}
+
static irqreturn_t dcmi_irq_thread(int irq, void *arg)
{
struct stm32_dcmi *dcmi = arg;
- spin_lock(&dcmi->irqlock);
+ spin_lock_irq(&dcmi->irqlock);
/* Stop capture is required */
if (dcmi->state == STOPPING) {
@@ -373,50 +438,41 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg)
complete(&dcmi->complete);
- spin_unlock(&dcmi->irqlock);
+ spin_unlock_irq(&dcmi->irqlock);
return IRQ_HANDLED;
}
if ((dcmi->misr & IT_OVR) || (dcmi->misr & IT_ERR)) {
- /*
- * An overflow or an error has been detected,
- * stop current DMA transfert & restart it
- */
- dev_warn(dcmi->dev, "%s: Overflow or error detected\n",
- __func__);
-
dcmi->errors_count++;
- dmaengine_terminate_all(dcmi->dma_chan);
-
- reg_set(dcmi->regs, DCMI_ICR, IT_FRAME | IT_OVR | IT_ERR);
-
- dev_dbg(dcmi->dev, "Restarting capture after DCMI error\n");
-
- if (dcmi_start_capture(dcmi)) {
- dev_err(dcmi->dev, "%s: Cannot restart capture on overflow or error\n",
- __func__);
+ if (dcmi->misr & IT_OVR)
+ dcmi->overrun_count++;
+ }
- spin_unlock(&dcmi->irqlock);
- return IRQ_HANDLED;
- }
+ if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG &&
+ dcmi->misr & IT_FRAME) {
+ /* JPEG received */
+ spin_unlock_irq(&dcmi->irqlock);
+ dcmi_process_jpeg(dcmi);
+ return IRQ_HANDLED;
}
- spin_unlock(&dcmi->irqlock);
+ spin_unlock_irq(&dcmi->irqlock);
return IRQ_HANDLED;
}
static irqreturn_t dcmi_irq_callback(int irq, void *arg)
{
struct stm32_dcmi *dcmi = arg;
+ unsigned long flags;
- spin_lock(&dcmi->irqlock);
+ spin_lock_irqsave(&dcmi->irqlock, flags);
dcmi->misr = reg_read(dcmi->regs, DCMI_MIS);
/* Clear interrupt */
reg_set(dcmi->regs, DCMI_ICR, IT_FRAME | IT_OVR | IT_ERR);
- spin_unlock(&dcmi->irqlock);
+ spin_unlock_irqrestore(&dcmi->irqlock, flags);
return IRQ_WAKE_THREAD;
}
@@ -483,7 +539,7 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb)
vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size);
- dev_dbg(dcmi->dev, "buffer[%d] phy=0x%pad size=%zu\n",
+ dev_dbg(dcmi->dev, "buffer[%d] phy=%pad size=%zu\n",
vb->index, &buf->paddr, buf->size);
}
@@ -495,29 +551,24 @@ static void dcmi_buf_queue(struct vb2_buffer *vb)
struct stm32_dcmi *dcmi = vb2_get_drv_priv(vb->vb2_queue);
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb);
- unsigned long flags = 0;
- spin_lock_irqsave(&dcmi->irqlock, flags);
+ spin_lock_irq(&dcmi->irqlock);
- if ((dcmi->state == RUNNING) && (!dcmi->active)) {
+ if (dcmi->state == RUNNING && !dcmi->active) {
dcmi->active = buf;
dev_dbg(dcmi->dev, "Starting capture on buffer[%d] queued\n",
buf->vb.vb2_buf.index);
- if (dcmi_start_capture(dcmi)) {
+ spin_unlock_irq(&dcmi->irqlock);
+ if (dcmi_start_capture(dcmi))
dev_err(dcmi->dev, "%s: Cannot restart capture on overflow or error\n",
__func__);
-
- spin_unlock_irqrestore(&dcmi->irqlock, flags);
- return;
- }
} else {
/* Enqueue to video buffers list */
list_add_tail(&buf->list, &dcmi->buffers);
+ spin_unlock_irq(&dcmi->irqlock);
}
-
- spin_unlock_irqrestore(&dcmi->irqlock, flags);
}
static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
@@ -529,7 +580,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
ret = clk_enable(dcmi->mclk);
if (ret) {
- dev_err(dcmi->dev, "%s: Failed to start streaming, cannot enable clock",
+ dev_err(dcmi->dev, "%s: Failed to start streaming, cannot enable clock\n",
__func__);
goto err_release_buffers;
}
@@ -578,6 +629,10 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
if (dcmi->do_crop)
dcmi_set_crop(dcmi);
+ /* Enable jpeg capture */
+ if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG)
+ reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */
+
/* Enable dcmi */
reg_set(dcmi->regs, DCMI_CR, CR_ENABLE);
@@ -585,6 +640,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
dcmi->sequence = 0;
dcmi->errors_count = 0;
+ dcmi->overrun_count = 0;
dcmi->buffers_count = 0;
dcmi->active = NULL;
@@ -603,20 +659,17 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
dev_dbg(dcmi->dev, "Start streaming, starting capture\n");
+ spin_unlock_irq(&dcmi->irqlock);
ret = dcmi_start_capture(dcmi);
if (ret) {
- dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture",
+ dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture\n",
__func__);
-
- spin_unlock_irq(&dcmi->irqlock);
goto err_subdev_streamoff;
}
/* Enable interruptions */
reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR);
- spin_unlock_irq(&dcmi->irqlock);
-
return 0;
err_subdev_streamoff:
@@ -656,9 +709,12 @@ static void dcmi_stop_streaming(struct vb2_queue *vq)
/* Disable stream on the sub device */
ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0);
if (ret && ret != -ENOIOCTLCMD)
- dev_err(dcmi->dev, "stream off failed in subdev\n");
+ dev_err(dcmi->dev, "%s: Failed to stop streaming, subdev streamoff error (%d)\n",
+ __func__, ret);
+ spin_lock_irq(&dcmi->irqlock);
dcmi->state = STOPPING;
+ spin_unlock_irq(&dcmi->irqlock);
timeout = wait_for_completion_interruptible_timeout(&dcmi->complete,
time_ms);
@@ -672,7 +728,8 @@ static void dcmi_stop_streaming(struct vb2_queue *vq)
reg_clear(dcmi->regs, DCMI_CR, CR_ENABLE);
if (!timeout) {
- dev_err(dcmi->dev, "Timeout during stop streaming\n");
+ dev_err(dcmi->dev, "%s: Timeout during stop streaming\n",
+ __func__);
dcmi->state = STOPPED;
}
@@ -694,8 +751,13 @@ static void dcmi_stop_streaming(struct vb2_queue *vq)
clk_disable(dcmi->mclk);
- dev_dbg(dcmi->dev, "Stop streaming, errors=%d buffers=%d\n",
- dcmi->errors_count, dcmi->buffers_count);
+ if (dcmi->errors_count)
+ dev_warn(dcmi->dev, "Some errors found while streaming: errors=%d (overrun=%d), buffers=%d\n",
+ dcmi->errors_count, dcmi->overrun_count,
+ dcmi->buffers_count);
+ dev_dbg(dcmi->dev, "Stop streaming, errors=%d (overrun=%d), buffers=%d\n",
+ dcmi->errors_count, dcmi->overrun_count,
+ dcmi->buffers_count);
}
static const struct vb2_ops dcmi_video_qops = {
@@ -749,7 +811,7 @@ static void __find_outer_frame_size(struct stm32_dcmi *dcmi,
int h_err = (fsize->height - pix->height);
int err = w_err + h_err;
- if ((w_err >= 0) && (h_err >= 0) && (err < min_err)) {
+ if (w_err >= 0 && h_err >= 0 && err < min_err) {
min_err = err;
match = fsize;
}
@@ -771,6 +833,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f,
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
+ bool do_crop;
int ret;
sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat);
@@ -780,10 +843,19 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f,
}
/* Limit to hardware capabilities */
- pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH);
- pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT);
+ if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
+ pix->width = clamp(pix->width, MIN_JPEG_WIDTH, MAX_JPEG_WIDTH);
+ pix->height =
+ clamp(pix->height, MIN_JPEG_HEIGHT, MAX_JPEG_HEIGHT);
+ } else {
+ pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH);
+ pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT);
+ }
- if (dcmi->do_crop && dcmi->num_of_sd_framesizes) {
+ /* No crop if JPEG is requested */
+ do_crop = dcmi->do_crop && (pix->pixelformat != V4L2_PIX_FMT_JPEG);
+
+ if (do_crop && dcmi->num_of_sd_framesizes) {
struct dcmi_framesize outer_sd_fsize;
/*
* If crop is requested and sensor have discrete frame sizes,
@@ -807,7 +879,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f,
sd_fsize.width = pix->width;
sd_fsize.height = pix->height;
- if (dcmi->do_crop) {
+ if (do_crop) {
struct v4l2_rect c = dcmi->crop;
struct v4l2_rect max_rect;
@@ -862,6 +934,10 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f)
if (ret)
return ret;
+ /* Disable crop if JPEG is requested */
+ if (pix->pixelformat == V4L2_PIX_FMT_JPEG)
+ dcmi->do_crop = false;
+
/* pix to mbus format */
v4l2_fill_mbus_format(mf, pix,
sd_format->mbus_code);
@@ -1084,10 +1160,10 @@ static int dcmi_s_selection(struct file *file, void *priv,
r.top = clamp_t(s32, r.top, 0, pix.height - r.height);
r.left = clamp_t(s32, r.left, 0, pix.width - r.width);
- if (!((r.top == dcmi->sd_bounds.top) &&
- (r.left == dcmi->sd_bounds.left) &&
- (r.width == dcmi->sd_bounds.width) &&
- (r.height == dcmi->sd_bounds.height))) {
+ if (!(r.top == dcmi->sd_bounds.top &&
+ r.left == dcmi->sd_bounds.left &&
+ r.width == dcmi->sd_bounds.width &&
+ r.height == dcmi->sd_bounds.height)) {
/* Crop if request is different than sensor resolution */
dcmi->do_crop = true;
dcmi->crop = r;
@@ -1167,6 +1243,22 @@ static int dcmi_enum_framesizes(struct file *file, void *fh,
return 0;
}
+static int dcmi_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *p)
+{
+ struct stm32_dcmi *dcmi = video_drvdata(file);
+
+ return v4l2_g_parm_cap(video_devdata(file), dcmi->entity.subdev, p);
+}
+
+static int dcmi_s_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *p)
+{
+ struct stm32_dcmi *dcmi = video_drvdata(file);
+
+ return v4l2_s_parm_cap(video_devdata(file), dcmi->entity.subdev, p);
+}
+
static int dcmi_enum_frameintervals(struct file *file, void *fh,
struct v4l2_frmivalenum *fival)
{
@@ -1269,6 +1361,9 @@ static const struct v4l2_ioctl_ops dcmi_ioctl_ops = {
.vidioc_g_input = dcmi_g_input,
.vidioc_s_input = dcmi_s_input,
+ .vidioc_g_parm = dcmi_g_parm,
+ .vidioc_s_parm = dcmi_s_parm,
+
.vidioc_enum_framesizes = dcmi_enum_framesizes,
.vidioc_enum_frameintervals = dcmi_enum_frameintervals,
@@ -1334,6 +1429,10 @@ static const struct dcmi_format dcmi_formats[] = {
.fourcc = V4L2_PIX_FMT_UYVY,
.mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
.bpp = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .mbus_code = MEDIA_BUS_FMT_JPEG_1X8,
+ .bpp = 1,
},
};
diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c
index f77be9302120..e9a02639554b 100644
--- a/drivers/media/platform/via-camera.c
+++ b/drivers/media/platform/via-camera.c
@@ -1112,7 +1112,7 @@ static int viacam_g_parm(struct file *filp, void *priv,
int ret;
mutex_lock(&cam->lock);
- ret = sensor_call(cam, video, g_parm, parm);
+ ret = v4l2_g_parm_cap(video_devdata(filp), cam->sensor, parm);
mutex_unlock(&cam->lock);
parm->parm.capture.readbuffers = cam->n_cap_bufs;
return ret;
@@ -1125,7 +1125,7 @@ static int viacam_s_parm(struct file *filp, void *priv,
int ret;
mutex_lock(&cam->lock);
- ret = sensor_call(cam, video, s_parm, parm);
+ ret = v4l2_s_parm_cap(video_devdata(filp), cam->sensor, parm);
mutex_unlock(&cam->lock);
parm->parm.capture.readbuffers = cam->n_cap_bufs;
return ret;
diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c
index 9d63c84a9876..617415c224fe 100644
--- a/drivers/media/platform/vimc/vimc-common.c
+++ b/drivers/media/platform/vimc/vimc-common.c
@@ -434,7 +434,9 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
v4l2_set_subdevdata(sd, ved);
/* Expose this subdev to user space */
- sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ if (sd->ctrl_handler)
+ sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
/* Initialize the media entity */
ret = media_entity_pads_init(&sd->entity, num_pads, ved->pads);
diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c
index 4d663e89d33f..6e10b63ba9ec 100644
--- a/drivers/media/platform/vimc/vimc-debayer.c
+++ b/drivers/media/platform/vimc/vimc-debayer.c
@@ -533,7 +533,7 @@ static int vimc_deb_comp_bind(struct device *comp, struct device *master,
/* Initialize ved and sd */
ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev,
pdata->entity_name,
- MEDIA_ENT_F_ATV_DECODER, 2,
+ MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2,
(const unsigned long[2]) {MEDIA_PAD_FL_SINK,
MEDIA_PAD_FL_SOURCE},
&vimc_deb_ops);
diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c
index e1602e0bc230..e583ec7a91da 100644
--- a/drivers/media/platform/vimc/vimc-scaler.c
+++ b/drivers/media/platform/vimc/vimc-scaler.c
@@ -395,7 +395,7 @@ static int vimc_sca_comp_bind(struct device *comp, struct device *master,
/* Initialize ved and sd */
ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev,
pdata->entity_name,
- MEDIA_ENT_F_ATV_DECODER, 2,
+ MEDIA_ENT_F_PROC_VIDEO_SCALER, 2,
(const unsigned long[2]) {MEDIA_PAD_FL_SINK,
MEDIA_PAD_FL_SOURCE},
&vimc_sca_ops);
diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c
index 457e211514c6..605e2a2d5dd5 100644
--- a/drivers/media/platform/vimc/vimc-sensor.c
+++ b/drivers/media/platform/vimc/vimc-sensor.c
@@ -23,6 +23,7 @@
#include <linux/v4l2-mediabus.h>
#include <linux/vmalloc.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-subdev.h>
#include <media/tpg/v4l2-tpg.h>
@@ -284,11 +285,18 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
+static struct v4l2_subdev_core_ops vimc_sen_core_ops = {
+ .log_status = v4l2_ctrl_subdev_log_status,
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
static const struct v4l2_subdev_video_ops vimc_sen_video_ops = {
.s_stream = vimc_sen_s_stream,
};
static const struct v4l2_subdev_ops vimc_sen_ops = {
+ .core = &vimc_sen_core_ops,
.pad = &vimc_sen_pad_ops,
.video = &vimc_sen_video_ops,
};
@@ -378,7 +386,7 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master,
/* Initialize ved and sd */
ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev,
pdata->entity_name,
- MEDIA_ENT_F_ATV_DECODER, 1,
+ MEDIA_ENT_F_CAM_SENSOR, 1,
(const unsigned long[1]) {MEDIA_PAD_FL_SOURCE},
&vimc_sen_ops);
if (ret)
diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c
index b55d278d38a7..71105fa4c5f9 100644
--- a/drivers/media/platform/vivid/vivid-cec.c
+++ b/drivers/media/platform/vivid/vivid-cec.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-cec.c - A Virtual Video Test Driver, cec emulation
*
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <media/cec.h>
@@ -82,11 +70,18 @@ static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts,
if (adap == NULL)
return;
- ts = ktime_sub_us(ts, (CEC_TIM_START_BIT_TOTAL +
- len * 10 * CEC_TIM_DATA_BIT_TOTAL));
- cec_queue_pin_cec_event(adap, false, ts);
+
+ /*
+ * Suffix ULL on constant 10 makes the expression
+ * CEC_TIM_START_BIT_TOTAL + 10ULL * len * CEC_TIM_DATA_BIT_TOTAL
+ * to be evaluated using 64-bit unsigned arithmetic (u64), which
+ * is what ktime_sub_us expects as second argument.
+ */
+ ts = ktime_sub_us(ts, CEC_TIM_START_BIT_TOTAL +
+ 10ULL * len * CEC_TIM_DATA_BIT_TOTAL);
+ cec_queue_pin_cec_event(adap, false, false, ts);
ts = ktime_add_us(ts, CEC_TIM_START_BIT_LOW);
- cec_queue_pin_cec_event(adap, true, ts);
+ cec_queue_pin_cec_event(adap, true, false, ts);
ts = ktime_add_us(ts, CEC_TIM_START_BIT_HIGH);
for (i = 0; i < 10 * len; i++) {
@@ -101,12 +96,12 @@ static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts,
bit = cec_msg_is_broadcast(msg) ^ nacked;
break;
}
- cec_queue_pin_cec_event(adap, false, ts);
+ cec_queue_pin_cec_event(adap, false, false, ts);
if (bit)
ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_LOW);
else
ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_LOW);
- cec_queue_pin_cec_event(adap, true, ts);
+ cec_queue_pin_cec_event(adap, true, false, ts);
if (bit)
ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_HIGH);
else
diff --git a/drivers/media/platform/vivid/vivid-cec.h b/drivers/media/platform/vivid/vivid-cec.h
index 3926b1422777..7524ed48a914 100644
--- a/drivers/media/platform/vivid/vivid-cec.h
+++ b/drivers/media/platform/vivid/vivid-cec.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-cec.h - A Virtual Video Test Driver, cec emulation
*
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifdef CONFIG_VIDEO_VIVID_CEC
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index 9f036c5f51b0..82ec216f2ad8 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-core.c - A Virtual Video Test Driver, core initialization
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/module.h>
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index c90e4a0ab94e..477c80a4d44c 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-core.h - core datastructures
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_CORE_H_
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index 3f9d354827af..6b0bfa091592 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-ctrls.c - control support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/errno.h>
@@ -1208,6 +1196,7 @@ static int vivid_radio_rx_s_ctrl(struct v4l2_ctrl *ctrl)
v4l2_ctrl_activate(dev->radio_rx_rds_ta, dev->radio_rx_rds_controls);
v4l2_ctrl_activate(dev->radio_rx_rds_tp, dev->radio_rx_rds_controls);
v4l2_ctrl_activate(dev->radio_rx_rds_ms, dev->radio_rx_rds_controls);
+ dev->radio_rx_dev.device_caps = dev->radio_rx_caps;
break;
case V4L2_CID_RDS_RECEPTION:
dev->radio_rx_rds_enabled = ctrl->val;
@@ -1282,6 +1271,7 @@ static int vivid_radio_tx_s_ctrl(struct v4l2_ctrl *ctrl)
dev->radio_tx_caps &= ~V4L2_CAP_READWRITE;
if (!dev->radio_tx_rds_controls)
dev->radio_tx_caps |= V4L2_CAP_READWRITE;
+ dev->radio_tx_dev.device_caps = dev->radio_tx_caps;
break;
case V4L2_CID_RDS_TX_PTY:
if (dev->radio_rx_rds_controls)
diff --git a/drivers/media/platform/vivid/vivid-ctrls.h b/drivers/media/platform/vivid/vivid-ctrls.h
index 9bcca9d56359..6fad5f5d0054 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.h
+++ b/drivers/media/platform/vivid/vivid-ctrls.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-ctrls.h - control support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_CTRLS_H_
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
index 6ca71aabb576..3fdb280c36ca 100644
--- a/drivers/media/platform/vivid/vivid-kthread-cap.c
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-kthread-cap.h - video/vbi capture thread support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/module.h>
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.h b/drivers/media/platform/vivid/vivid-kthread-cap.h
index 5b92fc9a0d04..0f43015306d6 100644
--- a/drivers/media/platform/vivid/vivid-kthread-cap.h
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-kthread-cap.h - video/vbi capture thread support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_KTHREAD_CAP_H_
diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c
index 98eed5889bc1..9981e7548019 100644
--- a/drivers/media/platform/vivid/vivid-kthread-out.c
+++ b/drivers/media/platform/vivid/vivid-kthread-out.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-kthread-out.h - video/vbi output thread support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/module.h>
diff --git a/drivers/media/platform/vivid/vivid-kthread-out.h b/drivers/media/platform/vivid/vivid-kthread-out.h
index 2bf04a17b05d..d5bcf44bbaca 100644
--- a/drivers/media/platform/vivid/vivid-kthread-out.h
+++ b/drivers/media/platform/vivid/vivid-kthread-out.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-kthread-out.h - video/vbi output thread support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_KTHREAD_OUT_H_
diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c
index bdc380b14e0c..bbbc1b6938a5 100644
--- a/drivers/media/platform/vivid/vivid-osd.c
+++ b/drivers/media/platform/vivid/vivid-osd.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-osd.c - osd support for testing overlays.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/module.h>
diff --git a/drivers/media/platform/vivid/vivid-osd.h b/drivers/media/platform/vivid/vivid-osd.h
index 57c9daa5940a..f9ac1af25dd3 100644
--- a/drivers/media/platform/vivid/vivid-osd.h
+++ b/drivers/media/platform/vivid/vivid-osd.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-osd.h - output overlay support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_OSD_H_
diff --git a/drivers/media/platform/vivid/vivid-radio-common.c b/drivers/media/platform/vivid/vivid-radio-common.c
index 78c1e920670a..7c8efe38ff5b 100644
--- a/drivers/media/platform/vivid/vivid-radio-common.c
+++ b/drivers/media/platform/vivid/vivid-radio-common.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-radio-common.c - common radio rx/tx support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-radio-common.h b/drivers/media/platform/vivid/vivid-radio-common.h
index 92fe589141b7..30a9900e5b2b 100644
--- a/drivers/media/platform/vivid/vivid-radio-common.h
+++ b/drivers/media/platform/vivid/vivid-radio-common.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-radio-common.h - common radio rx/tx support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_RADIO_COMMON_H_
diff --git a/drivers/media/platform/vivid/vivid-radio-rx.c b/drivers/media/platform/vivid/vivid-radio-rx.c
index f834f7df8cf9..1f86d7d4f72f 100644
--- a/drivers/media/platform/vivid/vivid-radio-rx.c
+++ b/drivers/media/platform/vivid/vivid-radio-rx.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-radio-rx.c - radio receiver support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/errno.h>
@@ -259,7 +247,7 @@ int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
vt->rangehigh = FM_FREQ_RANGE_HIGH;
sig_qual = dev->radio_rx_sig_qual;
vt->signal = abs(sig_qual) > delta ? 0 :
- 0xffff - (abs(sig_qual) * 0xffff) / delta;
+ 0xffff - ((unsigned)abs(sig_qual) * 0xffff) / delta;
vt->afc = sig_qual > delta ? 0 : sig_qual;
if (abs(sig_qual) > delta)
vt->rxsubchans = 0;
diff --git a/drivers/media/platform/vivid/vivid-radio-rx.h b/drivers/media/platform/vivid/vivid-radio-rx.h
index 2b33edb60942..c9c7849f6f99 100644
--- a/drivers/media/platform/vivid/vivid-radio-rx.h
+++ b/drivers/media/platform/vivid/vivid-radio-rx.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-radio-rx.h - radio receiver support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_RADIO_RX_H_
diff --git a/drivers/media/platform/vivid/vivid-radio-tx.c b/drivers/media/platform/vivid/vivid-radio-tx.c
index 308b13f85dc0..1a3749ba5e7e 100644
--- a/drivers/media/platform/vivid/vivid-radio-tx.c
+++ b/drivers/media/platform/vivid/vivid-radio-tx.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-radio-tx.c - radio transmitter support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-radio-tx.h b/drivers/media/platform/vivid/vivid-radio-tx.h
index 3c3343d70cbc..c2bf1e7e634a 100644
--- a/drivers/media/platform/vivid/vivid-radio-tx.h
+++ b/drivers/media/platform/vivid/vivid-radio-tx.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-radio-tx.h - radio transmitter support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_RADIO_TX_H_
diff --git a/drivers/media/platform/vivid/vivid-rds-gen.c b/drivers/media/platform/vivid/vivid-rds-gen.c
index 996e35e28d37..39ca9a56448c 100644
--- a/drivers/media/platform/vivid/vivid-rds-gen.c
+++ b/drivers/media/platform/vivid/vivid-rds-gen.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-rds-gen.c - rds (radio data system) generator support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/kernel.h>
diff --git a/drivers/media/platform/vivid/vivid-rds-gen.h b/drivers/media/platform/vivid/vivid-rds-gen.h
index e55e3b22b7ca..35ac5742302b 100644
--- a/drivers/media/platform/vivid/vivid-rds-gen.h
+++ b/drivers/media/platform/vivid/vivid-rds-gen.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-rds-gen.h - rds (radio data system) generator support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_RDS_GEN_H_
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c
index ebd7b9c4dd83..cfb7cb4d37a8 100644
--- a/drivers/media/platform/vivid/vivid-sdr-cap.c
+++ b/drivers/media/platform/vivid/vivid-sdr-cap.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-sdr-cap.c - software defined radio support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.h b/drivers/media/platform/vivid/vivid-sdr-cap.h
index 43014b2733db..813c9248e5a7 100644
--- a/drivers/media/platform/vivid/vivid-sdr-cap.h
+++ b/drivers/media/platform/vivid/vivid-sdr-cap.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-sdr-cap.h - software defined radio support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_SDR_CAP_H_
diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c
index d66ef95dd2b5..92a852955173 100644
--- a/drivers/media/platform/vivid/vivid-vbi-cap.c
+++ b/drivers/media/platform/vivid/vivid-vbi-cap.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-vbi-cap.c - vbi capture support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.h b/drivers/media/platform/vivid/vivid-vbi-cap.h
index 2d8ea0bac743..91d2de01381c 100644
--- a/drivers/media/platform/vivid/vivid-vbi-cap.h
+++ b/drivers/media/platform/vivid/vivid-vbi-cap.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-vbi-cap.h - vbi capture support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_VBI_CAP_H_
diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.c b/drivers/media/platform/vivid/vivid-vbi-gen.c
index 02c79d7cedab..acc98445a1fa 100644
--- a/drivers/media/platform/vivid/vivid-vbi-gen.c
+++ b/drivers/media/platform/vivid/vivid-vbi-gen.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-vbi-gen.c - vbi generator support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.h b/drivers/media/platform/vivid/vivid-vbi-gen.h
index 8444abe905ea..2657a7f5571c 100644
--- a/drivers/media/platform/vivid/vivid-vbi-gen.h
+++ b/drivers/media/platform/vivid/vivid-vbi-gen.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-vbi-gen.h - vbi generator support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_VBI_GEN_H_
diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c
index d2989195cf03..69486c130a7e 100644
--- a/drivers/media/platform/vivid/vivid-vbi-out.c
+++ b/drivers/media/platform/vivid/vivid-vbi-out.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-vbi-out.c - vbi output support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-vbi-out.h b/drivers/media/platform/vivid/vivid-vbi-out.h
index 6555ba9d2860..76584940cdaf 100644
--- a/drivers/media/platform/vivid/vivid-vbi-out.h
+++ b/drivers/media/platform/vivid/vivid-vbi-out.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-vbi-out.h - vbi output support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_VBI_OUT_H_
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
index 0fbbcde19f0d..01c703683657 100644
--- a/drivers/media/platform/vivid/vivid-vid-cap.c
+++ b/drivers/media/platform/vivid/vivid-vid-cap.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-vid-cap.c - video capture support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/errno.h>
@@ -573,9 +561,8 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv,
mp->field = vivid_field_cap(dev, mp->field);
if (vivid_is_webcam(dev)) {
const struct v4l2_frmsize_discrete *sz =
- v4l2_find_nearest_format(webcam_sizes,
- VIVID_WEBCAM_SIZES,
- mp->width, mp->height);
+ v4l2_find_nearest_size(webcam_sizes, width, height,
+ mp->width, mp->height);
w = sz->width;
h = sz->height;
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.h b/drivers/media/platform/vivid/vivid-vid-cap.h
index 94079815dbc2..47d8b48820df 100644
--- a/drivers/media/platform/vivid/vivid-vid-cap.h
+++ b/drivers/media/platform/vivid/vivid-vid-cap.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-vid-cap.h - video capture support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_VID_CAP_H_
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c
index a651527d80db..e5914be0e12d 100644
--- a/drivers/media/platform/vivid/vivid-vid-common.c
+++ b/drivers/media/platform/vivid/vivid-vid-common.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-vid-common.c - common video support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/errno.h>
@@ -874,7 +862,8 @@ int vidioc_g_edid(struct file *file, void *_fh,
return -EINVAL;
if (edid->start_block + edid->blocks > dev->edid_blocks)
edid->blocks = dev->edid_blocks - edid->start_block;
- cec_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr);
+ if (adap)
+ cec_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr);
memcpy(edid->edid, dev->edid + edid->start_block * 128, edid->blocks * 128);
return 0;
}
diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h
index 4b6175eab8a2..29b6c0b40a1b 100644
--- a/drivers/media/platform/vivid/vivid-vid-common.h
+++ b/drivers/media/platform/vivid/vivid-vid-common.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-vid-common.h - common video support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_VID_COMMON_H_
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c
index 0b1b6218ede8..51fec66d8d45 100644
--- a/drivers/media/platform/vivid/vivid-vid-out.c
+++ b/drivers/media/platform/vivid/vivid-vid-out.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-vid-out.c - video output support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/errno.h>
diff --git a/drivers/media/platform/vivid/vivid-vid-out.h b/drivers/media/platform/vivid/vivid-vid-out.h
index dfa84db184ed..e87aacf843c5 100644
--- a/drivers/media/platform/vivid/vivid-vid-out.h
+++ b/drivers/media/platform/vivid/vivid-vid-out.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-vid-out.h - video output support functions.
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _VIVID_VID_OUT_H_
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 4257451f1bd8..0b86ed01e85d 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -509,7 +509,8 @@ static bool vsp1_dl_list_hw_update_pending(struct vsp1_dl_manager *dlm)
return !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE)
& VI6_DL_BODY_SIZE_UPD);
else
- return !!(vsp1_read(vsp1, VI6_CMD(dlm->index) & VI6_CMD_UPDHDR));
+ return !!(vsp1_read(vsp1, VI6_CMD(dlm->index))
+ & VI6_CMD_UPDHDR);
}
static void vsp1_dl_list_hw_enqueue(struct vsp1_dl_list *dl)
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 7ce69f23f50a..b8fee1834253 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -27,6 +27,7 @@
#include "vsp1_pipe.h"
#include "vsp1_rwpf.h"
+#define BRU_NAME(e) (e)->type == VSP1_ENTITY_BRU ? "BRU" : "BRS"
/* -----------------------------------------------------------------------------
* Interrupt Handling
@@ -88,7 +89,6 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
struct vsp1_entity *next;
struct vsp1_dl_list *dl;
struct v4l2_subdev_format format;
- const char *bru_name;
unsigned long flags;
unsigned int i;
int ret;
@@ -99,7 +99,6 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
drm_pipe = &vsp1->drm->pipe[pipe_index];
pipe = &drm_pipe->pipe;
bru = to_bru(&pipe->bru->subdev);
- bru_name = pipe->bru->type == VSP1_ENTITY_BRU ? "BRU" : "BRS";
if (!cfg) {
/*
@@ -165,7 +164,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n",
__func__, format.format.width, format.format.height,
- format.format.code, bru_name, i);
+ format.format.code, BRU_NAME(pipe->bru), i);
}
format.pad = pipe->bru->source_pad;
@@ -181,7 +180,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n",
__func__, format.format.width, format.format.height,
- format.format.code, bru_name, i);
+ format.format.code, BRU_NAME(pipe->bru), i);
format.pad = RWPF_PAD_SINK;
ret = v4l2_subdev_call(&pipe->output->entity.subdev, pad, set_fmt, NULL,
@@ -473,9 +472,9 @@ static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1,
if (ret < 0)
return ret;
- dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n",
+ dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n",
__func__, format.format.width, format.format.height,
- format.format.code, format.pad);
+ format.format.code, BRU_NAME(pipe->bru), format.pad);
sel.pad = bru_input;
sel.target = V4L2_SEL_TGT_COMPOSE;
@@ -486,10 +485,9 @@ static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1,
if (ret < 0)
return ret;
- dev_dbg(vsp1->dev,
- "%s: set selection (%u,%u)/%ux%u on BRU pad %u\n",
+ dev_dbg(vsp1->dev, "%s: set selection (%u,%u)/%ux%u on %s pad %u\n",
__func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
- sel.pad);
+ BRU_NAME(pipe->bru), sel.pad);
return 0;
}
@@ -514,12 +512,9 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index)
struct vsp1_entity *entity;
struct vsp1_entity *next;
struct vsp1_dl_list *dl;
- const char *bru_name;
unsigned int i;
int ret;
- bru_name = pipe->bru->type == VSP1_ENTITY_BRU ? "BRU" : "BRS";
-
/* Prepare the display list. */
dl = vsp1_dl_list_get(pipe->output->dlm);
@@ -530,6 +525,15 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index)
struct vsp1_rwpf *rpf = vsp1->rpf[i];
unsigned int j;
+ /*
+ * Make sure we don't accept more inputs than the hardware can
+ * handle. This is a temporary fix to avoid display stall, we
+ * need to instead allocate the BRU or BRS to display pipelines
+ * dynamically based on the number of planes they each use.
+ */
+ if (pipe->num_inputs >= pipe->bru->source_pad)
+ pipe->inputs[i] = NULL;
+
if (!pipe->inputs[i])
continue;
@@ -561,7 +565,7 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index)
rpf->entity.sink_pad = i;
dev_dbg(vsp1->dev, "%s: connecting RPF.%u to %s:%u\n",
- __func__, rpf->entity.index, bru_name, i);
+ __func__, rpf->entity.index, BRU_NAME(pipe->bru), i);
ret = vsp1_du_setup_rpf_pipe(vsp1, pipe, rpf, i);
if (ret < 0)
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index e6fa16d7fda8..704920753998 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -155,6 +155,18 @@ static void lif_configure(struct vsp1_entity *entity,
(obth << VI6_LIF_CTRL_OBTH_SHIFT) |
(format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) |
VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN);
+
+ /*
+ * On R-Car V3M the LIF0 buffer attribute register has to be set to a
+ * non-default value to guarantee proper operation (otherwise artifacts
+ * may appear on the output). The value required by the manual is not
+ * explained but is likely a buffer size or threshold.
+ */
+ if ((entity->vsp1->version & VI6_IP_VERSION_MASK) ==
+ (VI6_IP_VERSION_MODEL_VSPD_V3 | VI6_IP_VERSION_SOC_V3M))
+ vsp1_lif_write(lif, dl, VI6_LIF_LBA,
+ VI6_LIF_LBA_LBA0 |
+ (1536 << VI6_LIF_LBA_LBA1_SHIFT));
}
static const struct vsp1_entity_operations lif_entity_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h
index 26c4ffad2f46..dae0c1901297 100644
--- a/drivers/media/platform/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/vsp1/vsp1_regs.h
@@ -225,7 +225,7 @@
#define VI6_RPF_MULT_ALPHA_P_MMD_RATIO (1 << 8)
#define VI6_RPF_MULT_ALPHA_P_MMD_IMAGE (2 << 8)
#define VI6_RPF_MULT_ALPHA_P_MMD_BOTH (3 << 8)
-#define VI6_RPF_MULT_ALPHA_RATIO_MASK (0xff < 0)
+#define VI6_RPF_MULT_ALPHA_RATIO_MASK (0xff << 0)
#define VI6_RPF_MULT_ALPHA_RATIO_SHIFT 0
/* -----------------------------------------------------------------------------
@@ -693,6 +693,11 @@
#define VI6_LIF_CSBTH_LBTH_MASK (0x7ff << 0)
#define VI6_LIF_CSBTH_LBTH_SHIFT 0
+#define VI6_LIF_LBA 0x3b0c
+#define VI6_LIF_LBA_LBA0 (1 << 31)
+#define VI6_LIF_LBA_LBA1_MASK (0xfff << 16)
+#define VI6_LIF_LBA_LBA1_SHIFT 16
+
/* -----------------------------------------------------------------------------
* Security Control Registers
*/
@@ -705,6 +710,7 @@
*/
#define VI6_IP_VERSION 0x3f00
+#define VI6_IP_VERSION_MASK (0xffff << 0)
#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)
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index dc6c4f985911..0f292c6ba338 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -511,7 +511,7 @@ static int usb_amradio_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct amradio_device *radio;
- int retval = 0;
+ int retval;
radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL);
diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c
index 70a2c86774ce..9a5079d64c4a 100644
--- a/drivers/media/radio/radio-raremono.c
+++ b/drivers/media/radio/radio-raremono.c
@@ -1,18 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/kernel.h>
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index 58e944591602..8f9f8dfc3497 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -671,7 +671,7 @@ fail:
static int wl1273_fm_suspend(struct wl1273_device *radio)
{
struct wl1273_core *core = radio->core;
- int r = 0;
+ int r;
/* Cannot go from OFF to SUSPENDED */
if (core->mode == WL1273_MODE_RX)
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index e0054e0f410d..b94d66e53d4e 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -207,6 +207,15 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
unsigned long time_left;
bool timed_out = false;
+ retval = si470x_get_register(radio, POWERCFG);
+ if (retval)
+ return retval;
+
+ if ((radio->registers[POWERCFG] & (POWERCFG_ENABLE|POWERCFG_DMUTE))
+ != (POWERCFG_ENABLE|POWERCFG_DMUTE)) {
+ return 0;
+ }
+
/* start tuning */
radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
@@ -377,8 +386,12 @@ int si470x_start(struct si470x_device *radio)
goto done;
/* sysconfig 1 */
- radio->registers[SYSCONFIG1] =
- (de << 11) & SYSCONFIG1_DE; /* DE*/
+ radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN | SYSCONFIG1_STCIEN |
+ SYSCONFIG1_RDS;
+ radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2;
+ radio->registers[SYSCONFIG1] |= SYSCONFIG1_GPIO2_INT;
+ if (de)
+ radio->registers[SYSCONFIG1] |= SYSCONFIG1_DE;
retval = si470x_set_register(radio, SYSCONFIG1);
if (retval < 0)
goto done;
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
index b3034f80163f..41709b24b28f 100644
--- a/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ b/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -43,7 +43,6 @@ static const struct i2c_device_id si470x_i2c_id[] = {
MODULE_DEVICE_TABLE(i2c, si470x_i2c_id);
-
/**************************************************************************
* Module Parameters
**************************************************************************/
@@ -362,22 +361,43 @@ static int si470x_i2c_probe(struct i2c_client *client,
mutex_init(&radio->lock);
init_completion(&radio->completion);
+ retval = v4l2_device_register(&client->dev, &radio->v4l2_dev);
+ if (retval < 0) {
+ dev_err(&client->dev, "couldn't register v4l2_device\n");
+ goto err_radio;
+ }
+
+ v4l2_ctrl_handler_init(&radio->hdl, 2);
+ v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, 15, 1, 15);
+ if (radio->hdl.error) {
+ retval = radio->hdl.error;
+ dev_err(&client->dev, "couldn't register control\n");
+ goto err_dev;
+ }
+
/* video device initialization */
radio->videodev = si470x_viddev_template;
+ radio->videodev.ctrl_handler = &radio->hdl;
+ radio->videodev.lock = &radio->lock;
+ radio->videodev.v4l2_dev = &radio->v4l2_dev;
+ radio->videodev.release = video_device_release_empty;
video_set_drvdata(&radio->videodev, radio);
/* power up : need 110ms */
radio->registers[POWERCFG] = POWERCFG_ENABLE;
if (si470x_set_register(radio, POWERCFG) < 0) {
retval = -EIO;
- goto err_radio;
+ goto err_ctrl;
}
msleep(110);
/* get device and chip versions */
if (si470x_get_all_registers(radio) < 0) {
retval = -EIO;
- goto err_radio;
+ goto err_ctrl;
}
dev_info(&client->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
radio->registers[DEVICEID], radio->registers[SI_CHIPID]);
@@ -407,7 +427,7 @@ static int si470x_i2c_probe(struct i2c_client *client,
radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
if (!radio->buffer) {
retval = -EIO;
- goto err_radio;
+ goto err_ctrl;
}
/* rds buffer configuration */
@@ -437,6 +457,10 @@ err_all:
free_irq(client->irq, radio);
err_rds:
kfree(radio->buffer);
+err_ctrl:
+ v4l2_ctrl_handler_free(&radio->hdl);
+err_dev:
+ v4l2_device_unregister(&radio->v4l2_dev);
err_radio:
kfree(radio);
err_initial:
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index c311f9951d80..2277e850bb5e 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -578,7 +578,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
struct si470x_device *radio;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
- int i, int_end_size, retval = 0;
+ int i, int_end_size, retval;
unsigned char version_warning = 0;
/* private data allocation and initialization */
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h
index eb7b834a0ae5..0202f8eb90c4 100644
--- a/drivers/media/radio/si470x/radio-si470x.h
+++ b/drivers/media/radio/si470x/radio-si470x.h
@@ -79,6 +79,8 @@
#define SYSCONFIG1_BLNDADJ 0x00c0 /* bits 07..06: Stereo/Mono Blend Level Adjustment */
#define SYSCONFIG1_GPIO3 0x0030 /* bits 05..04: General Purpose I/O 3 */
#define SYSCONFIG1_GPIO2 0x000c /* bits 03..02: General Purpose I/O 2 */
+#define SYSCONFIG1_GPIO2_DIS 0x0000 /* Disable GPIO 2 interrupt */
+#define SYSCONFIG1_GPIO2_INT 0x0004 /* Enable STC/RDS interrupt */
#define SYSCONFIG1_GPIO1 0x0003 /* bits 01..00: General Purpose I/O 1 */
#define SYSCONFIG2 5 /* System Configuration 2 */
diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c
index a115db24667b..05c66701a899 100644
--- a/drivers/media/radio/si4713/radio-usb-si4713.c
+++ b/drivers/media/radio/si4713/radio-usb-si4713.c
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
* All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
/* kernel includes */
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index f14ead5954e0..eb2c3b6eca7f 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -28,14 +28,12 @@ config LIRC
menuconfig RC_DECODERS
bool "Remote controller decoders"
depends on RC_CORE
- default y
if RC_DECODERS
config IR_NEC_DECODER
tristate "Enable IR raw decoder for the NEC protocol"
depends on RC_CORE
select BITREVERSE
- default y
---help---
Enable this option if you have IR with NEC protocol, and
@@ -45,7 +43,6 @@ config IR_RC5_DECODER
tristate "Enable IR raw decoder for the RC-5 protocol"
depends on RC_CORE
select BITREVERSE
- default y
---help---
Enable this option if you have IR with RC-5 protocol, and
@@ -55,7 +52,6 @@ config IR_RC6_DECODER
tristate "Enable IR raw decoder for the RC6 protocol"
depends on RC_CORE
select BITREVERSE
- default y
---help---
Enable this option if you have an infrared remote control which
@@ -65,7 +61,6 @@ config IR_JVC_DECODER
tristate "Enable IR raw decoder for the JVC protocol"
depends on RC_CORE
select BITREVERSE
- default y
---help---
Enable this option if you have an infrared remote control which
@@ -75,7 +70,6 @@ config IR_SONY_DECODER
tristate "Enable IR raw decoder for the Sony protocol"
depends on RC_CORE
select BITREVERSE
- default y
---help---
Enable this option if you have an infrared remote control which
@@ -84,7 +78,6 @@ config IR_SONY_DECODER
config IR_SANYO_DECODER
tristate "Enable IR raw decoder for the Sanyo protocol"
depends on RC_CORE
- default y
---help---
Enable this option if you have an infrared remote control which
@@ -94,7 +87,6 @@ config IR_SANYO_DECODER
config IR_SHARP_DECODER
tristate "Enable IR raw decoder for the Sharp protocol"
depends on RC_CORE
- default y
---help---
Enable this option if you have an infrared remote control which
@@ -105,7 +97,6 @@ config IR_MCE_KBD_DECODER
tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol"
depends on RC_CORE
select BITREVERSE
- default y
---help---
Enable this option if you have a Microsoft Remote Keyboard for
@@ -116,11 +107,19 @@ config IR_XMP_DECODER
tristate "Enable IR raw decoder for the XMP protocol"
depends on RC_CORE
select BITREVERSE
- default y
---help---
Enable this option if you have IR with XMP protocol, and
if the IR is decoded in software
+
+config IR_IMON_DECODER
+ tristate "Enable IR raw decoder for the iMON protocol"
+ depends on RC_CORE
+ ---help---
+ Enable this option if you have iMON PAD or Antec Veris infrared
+ remote control and you would like to use it with a raw IR
+ receiver, or if you wish to use an encoder to transmit this IR.
+
endif #RC_DECODERS
menuconfig RC_DEVICES
@@ -185,6 +184,18 @@ config IR_IMON
To compile this driver as a module, choose M here: the
module will be called imon.
+config IR_IMON_RAW
+ tristate "SoundGraph iMON Receiver (early raw IR models)"
+ depends on USB_ARCH_HAS_HCD
+ depends on RC_CORE
+ select USB
+ ---help---
+ Say Y here if you want to use a SoundGraph iMON IR Receiver,
+ early raw models.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imon_raw.
+
config IR_MCEUSB
tristate "Windows Media Center Ed. eHome Infrared Transceiver"
depends on USB_ARCH_HAS_HCD
@@ -446,7 +457,6 @@ config IR_SERIAL
config IR_SERIAL_TRANSMITTER
bool "Serial Port Transmitter"
- default y
depends on IR_SERIAL
---help---
Serial Port Transmitter support
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 0e857816ac2d..2e1c87066f6c 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -14,11 +14,13 @@ obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o
obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o
obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o
+obj-$(CONFIG_IR_IMON_DECODER) += ir-imon-decoder.o
# stand-alone IR receivers/transmitters
obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o
obj-$(CONFIG_IR_HIX5HD2) += ir-hix5hd2.o
obj-$(CONFIG_IR_IMON) += imon.o
+obj-$(CONFIG_IR_IMON_RAW) += imon_raw.o
obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o
obj-$(CONFIG_IR_MCEUSB) += mceusb.o
obj-$(CONFIG_IR_FINTEK) += fintek-cir.o
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 950d068ba806..1041c056854d 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -92,7 +92,6 @@ struct imon_usb_dev_descr {
__u16 flags;
#define IMON_NO_FLAGS 0
#define IMON_NEED_20MS_PKT_DELAY 1
-#define IMON_IR_RAW 2
struct imon_panel_key_table key_table[];
};
@@ -123,12 +122,6 @@ struct imon_context {
unsigned char usb_tx_buf[8];
unsigned int send_packet_delay;
- struct rx_data {
- int count; /* length of 0 or 1 sequence */
- int prev_bit; /* logic level of sequence */
- int initial_space; /* initial space flag */
- } rx;
-
struct tx_t {
unsigned char data_buf[35]; /* user data buffer */
struct completion finished; /* wait for write to finish */
@@ -331,10 +324,6 @@ static const struct imon_usb_dev_descr imon_DH102 = {
}
};
-static const struct imon_usb_dev_descr imon_ir_raw = {
- .flags = IMON_IR_RAW,
-};
-
/*
* USB Device ID for iMON USB Control Boards
*
@@ -418,18 +407,6 @@ static const struct usb_device_id imon_usb_id_table[] = {
/* device specifics unknown */
{ USB_DEVICE(0x15c2, 0x0046),
.driver_info = (unsigned long)&imon_default_table},
- /* TriGem iMON (IR only) -- TG_iMON.inf */
- { USB_DEVICE(0x0aa8, 0x8001),
- .driver_info = (unsigned long)&imon_ir_raw},
- /* SoundGraph iMON (IR only) -- sg_imon.inf */
- { USB_DEVICE(0x04e8, 0xff30),
- .driver_info = (unsigned long)&imon_ir_raw},
- /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */
- { USB_DEVICE(0x0aa8, 0xffda),
- .driver_info = (unsigned long)&imon_ir_raw},
- /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */
- { USB_DEVICE(0x15c2, 0xffda),
- .driver_info = (unsigned long)&imon_ir_raw},
{}
};
@@ -1133,18 +1110,18 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_proto)
dev_dbg(dev, "Configuring IR receiver for MCE protocol\n");
ir_proto_packet[0] = 0x01;
*rc_proto = RC_PROTO_BIT_RC6_MCE;
- } else if (*rc_proto & RC_PROTO_BIT_OTHER) {
+ } else if (*rc_proto & RC_PROTO_BIT_IMON) {
dev_dbg(dev, "Configuring IR receiver for iMON protocol\n");
if (!pad_stabilize)
dev_dbg(dev, "PAD stabilize functionality disabled\n");
/* ir_proto_packet[0] = 0x00; // already the default */
- *rc_proto = RC_PROTO_BIT_OTHER;
+ *rc_proto = RC_PROTO_BIT_IMON;
} else {
dev_warn(dev, "Unsupported IR protocol specified, overriding to iMON IR protocol\n");
if (!pad_stabilize)
dev_dbg(dev, "PAD stabilize functionality disabled\n");
/* ir_proto_packet[0] = 0x00; // already the default */
- *rc_proto = RC_PROTO_BIT_OTHER;
+ *rc_proto = RC_PROTO_BIT_IMON;
}
memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet));
@@ -1411,7 +1388,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
rel_x = buf[2];
rel_y = buf[3];
- if (ictx->rc_proto == RC_PROTO_BIT_OTHER && pad_stabilize) {
+ if (ictx->rc_proto == RC_PROTO_BIT_IMON && pad_stabilize) {
if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) {
dir = stabilize((int)rel_x, (int)rel_y,
timeout, threshold);
@@ -1478,7 +1455,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
buf[0] = 0x01;
buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0;
- if (ictx->rc_proto == RC_PROTO_BIT_OTHER && pad_stabilize) {
+ if (ictx->rc_proto == RC_PROTO_BIT_IMON && pad_stabilize) {
dir = stabilize((int)rel_x, (int)rel_y,
timeout, threshold);
if (!dir) {
@@ -1572,94 +1549,11 @@ static int imon_parse_press_type(struct imon_context *ictx,
/*
* Process the incoming packet
*/
-/*
- * Convert bit count to time duration (in us) and submit
- * the value to lirc_dev.
- */
-static void submit_data(struct imon_context *context)
-{
- DEFINE_IR_RAW_EVENT(ev);
-
- ev.pulse = context->rx.prev_bit;
- ev.duration = US_TO_NS(context->rx.count * BIT_DURATION);
- ir_raw_event_store_with_filter(context->rdev, &ev);
-}
-
-/*
- * Process the incoming packet
- */
-static void imon_incoming_ir_raw(struct imon_context *context,
+static void imon_incoming_packet(struct imon_context *ictx,
struct urb *urb, int intf)
{
int len = urb->actual_length;
unsigned char *buf = urb->transfer_buffer;
- struct device *dev = context->dev;
- int octet, bit;
- unsigned char mask;
-
- if (len != 8) {
- dev_warn(dev, "imon %s: invalid incoming packet size (len = %d, intf%d)\n",
- __func__, len, intf);
- return;
- }
-
- if (debug)
- dev_info(dev, "raw packet: %*ph\n", len, buf);
- /*
- * Translate received data to pulse and space lengths.
- * Received data is active low, i.e. pulses are 0 and
- * spaces are 1.
- *
- * My original algorithm was essentially similar to
- * Changwoo Ryu's with the exception that he switched
- * the incoming bits to active high and also fed an
- * initial space to LIRC at the start of a new sequence
- * if the previous bit was a pulse.
- *
- * I've decided to adopt his algorithm.
- */
-
- if (buf[7] == 1 && context->rx.initial_space) {
- /* LIRC requires a leading space */
- context->rx.prev_bit = 0;
- context->rx.count = 4;
- submit_data(context);
- context->rx.count = 0;
- }
-
- for (octet = 0; octet < 5; ++octet) {
- mask = 0x80;
- for (bit = 0; bit < 8; ++bit) {
- int curr_bit = !(buf[octet] & mask);
-
- if (curr_bit != context->rx.prev_bit) {
- if (context->rx.count) {
- submit_data(context);
- context->rx.count = 0;
- }
- context->rx.prev_bit = curr_bit;
- }
- ++context->rx.count;
- mask >>= 1;
- }
- }
-
- if (buf[7] == 10) {
- if (context->rx.count) {
- submit_data(context);
- context->rx.count = 0;
- }
- context->rx.initial_space = context->rx.prev_bit;
- }
-
- ir_raw_event_handle(context->rdev);
-}
-
-static void imon_incoming_scancode(struct imon_context *ictx,
- struct urb *urb, int intf)
-{
- int len = urb->actual_length;
- unsigned char *buf = urb->transfer_buffer;
struct device *dev = ictx->dev;
unsigned long flags;
u32 kc;
@@ -1745,11 +1639,18 @@ static void imon_incoming_scancode(struct imon_context *ictx,
if (press_type == 0)
rc_keyup(ictx->rdev);
else {
- if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE ||
- ictx->rc_proto == RC_PROTO_BIT_OTHER)
- rc_keydown(ictx->rdev,
- ictx->rc_proto == RC_PROTO_BIT_RC6_MCE ? RC_PROTO_RC6_MCE : RC_PROTO_OTHER,
- ictx->rc_scancode, ictx->rc_toggle);
+ enum rc_proto proto;
+
+ if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE)
+ proto = RC_PROTO_RC6_MCE;
+ else if (ictx->rc_proto == RC_PROTO_BIT_IMON)
+ proto = RC_PROTO_IMON;
+ else
+ return;
+
+ rc_keydown(ictx->rdev, proto, ictx->rc_scancode,
+ ictx->rc_toggle);
+
spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->last_keycode = ictx->kc;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
@@ -1839,10 +1740,7 @@ static void usb_rx_callback_intf0(struct urb *urb)
break;
case 0:
- if (ictx->rdev->driver_type == RC_DRIVER_IR_RAW)
- imon_incoming_ir_raw(ictx, urb, intfnum);
- else
- imon_incoming_scancode(ictx, urb, intfnum);
+ imon_incoming_packet(ictx, urb, intfnum);
break;
default:
@@ -1883,10 +1781,7 @@ static void usb_rx_callback_intf1(struct urb *urb)
break;
case 0:
- if (ictx->rdev->driver_type == RC_DRIVER_IR_RAW)
- imon_incoming_ir_raw(ictx, urb, intfnum);
- else
- imon_incoming_scancode(ictx, urb, intfnum);
+ imon_incoming_packet(ictx, urb, intfnum);
break;
default:
@@ -1912,7 +1807,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
{
u8 ffdc_cfg_byte = ictx->usb_rx_buf[6];
u8 detected_display_type = IMON_DISPLAY_TYPE_NONE;
- u64 allowed_protos = RC_PROTO_BIT_OTHER;
+ u64 allowed_protos = RC_PROTO_BIT_IMON;
switch (ffdc_cfg_byte) {
/* iMON Knob, no display, iMON IR + vol knob */
@@ -1960,8 +1855,10 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
default:
dev_info(ictx->dev, "Unknown 0xffdc device, defaulting to VFD and iMON IR");
detected_display_type = IMON_DISPLAY_TYPE_VFD;
- /* We don't know which one it is, allow user to set the
- * RC6 one from userspace if OTHER wasn't correct. */
+ /*
+ * We don't know which one it is, allow user to set the
+ * RC6 one from userspace if IMON wasn't correct.
+ */
allowed_protos |= RC_PROTO_BIT_RC6_MCE;
break;
}
@@ -2000,14 +1897,11 @@ static void imon_set_display_type(struct imon_context *ictx)
case 0x0041:
case 0x0042:
case 0x0043:
- case 0x8001:
- case 0xff30:
configured_display_type = IMON_DISPLAY_TYPE_NONE;
ictx->display_supported = false;
break;
case 0x0036:
case 0x0044:
- case 0xffda:
default:
configured_display_type = IMON_DISPLAY_TYPE_VFD;
break;
@@ -2032,8 +1926,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
static const unsigned char fp_packet[] = {
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88 };
- rdev = rc_allocate_device(ictx->dev_descr->flags & IMON_IR_RAW ?
- RC_DRIVER_IR_RAW : RC_DRIVER_SCANCODE);
+ rdev = rc_allocate_device(RC_DRIVER_SCANCODE);
if (!rdev) {
dev_err(ictx->dev, "remote control dev allocation failed\n");
goto out;
@@ -2051,12 +1944,8 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
rdev->dev.parent = ictx->dev;
rdev->priv = ictx;
- if (ictx->dev_descr->flags & IMON_IR_RAW)
- rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
- else
- /* iMON PAD or MCE */
- rdev->allowed_protocols = RC_PROTO_BIT_OTHER |
- RC_PROTO_BIT_RC6_MCE;
+ /* iMON PAD or MCE */
+ rdev->allowed_protocols = RC_PROTO_BIT_IMON | RC_PROTO_BIT_RC6_MCE;
rdev->change_protocol = imon_ir_change_protocol;
rdev->driver_name = MOD_NAME;
@@ -2074,8 +1963,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
imon_set_display_type(ictx);
- if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE ||
- ictx->dev_descr->flags & IMON_IR_RAW)
+ if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE)
rdev->map_name = RC_MAP_IMON_MCE;
else
rdev->map_name = RC_MAP_IMON_PAD;
diff --git a/drivers/media/rc/imon_raw.c b/drivers/media/rc/imon_raw.c
new file mode 100644
index 000000000000..32709f96de14
--- /dev/null
+++ b/drivers/media/rc/imon_raw.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (C) 2018 Sean Young <sean@mess.org>
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
+
+/* Each bit is 250us */
+#define BIT_DURATION 250000
+
+struct imon {
+ struct device *dev;
+ struct urb *ir_urb;
+ struct rc_dev *rcdev;
+ u8 ir_buf[8];
+ char phys[64];
+};
+
+/*
+ * ffs/find_next_bit() searches in the wrong direction, so open-code our own.
+ */
+static inline int is_bit_set(const u8 *buf, int bit)
+{
+ return buf[bit / 8] & (0x80 >> (bit & 7));
+}
+
+static void imon_ir_data(struct imon *imon)
+{
+ DEFINE_IR_RAW_EVENT(rawir);
+ int offset = 0, size = 5 * 8;
+ int bit;
+
+ dev_dbg(imon->dev, "data: %*ph", 8, imon->ir_buf);
+
+ while (offset < size) {
+ bit = offset;
+ while (!is_bit_set(imon->ir_buf, bit) && bit < size)
+ bit++;
+ dev_dbg(imon->dev, "pulse: %d bits", bit - offset);
+ if (bit > offset) {
+ rawir.pulse = true;
+ rawir.duration = (bit - offset) * BIT_DURATION;
+ ir_raw_event_store_with_filter(imon->rcdev, &rawir);
+ }
+
+ if (bit >= size)
+ break;
+
+ offset = bit;
+ while (is_bit_set(imon->ir_buf, bit) && bit < size)
+ bit++;
+ dev_dbg(imon->dev, "space: %d bits", bit - offset);
+
+ rawir.pulse = false;
+ rawir.duration = (bit - offset) * BIT_DURATION;
+ ir_raw_event_store_with_filter(imon->rcdev, &rawir);
+
+ offset = bit;
+ }
+
+ if (imon->ir_buf[7] == 0x0a) {
+ ir_raw_event_set_idle(imon->rcdev, true);
+ ir_raw_event_handle(imon->rcdev);
+ }
+}
+
+static void imon_ir_rx(struct urb *urb)
+{
+ struct imon *imon = urb->context;
+ int ret;
+
+ switch (urb->status) {
+ case 0:
+ if (imon->ir_buf[7] != 0xff)
+ imon_ir_data(imon);
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ usb_unlink_urb(urb);
+ return;
+ case -EPIPE:
+ default:
+ dev_dbg(imon->dev, "error: urb status = %d", urb->status);
+ break;
+ }
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret && ret != -ENODEV)
+ dev_warn(imon->dev, "failed to resubmit urb: %d", ret);
+}
+
+static int imon_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_endpoint_descriptor *ir_ep = NULL;
+ struct usb_host_interface *idesc;
+ struct usb_device *udev;
+ struct rc_dev *rcdev;
+ struct imon *imon;
+ int i, ret;
+
+ udev = interface_to_usbdev(intf);
+ idesc = intf->cur_altsetting;
+
+ for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
+ struct usb_endpoint_descriptor *ep = &idesc->endpoint[i].desc;
+
+ if (usb_endpoint_is_int_in(ep)) {
+ ir_ep = ep;
+ break;
+ }
+ }
+
+ if (!ir_ep) {
+ dev_err(&intf->dev, "IR endpoint missing");
+ return -ENODEV;
+ }
+
+ imon = devm_kmalloc(&intf->dev, sizeof(*imon), GFP_KERNEL);
+ if (!imon)
+ return -ENOMEM;
+
+ imon->ir_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!imon->ir_urb)
+ return -ENOMEM;
+
+ imon->dev = &intf->dev;
+ usb_fill_int_urb(imon->ir_urb, udev,
+ usb_rcvintpipe(udev, ir_ep->bEndpointAddress),
+ imon->ir_buf, sizeof(imon->ir_buf),
+ imon_ir_rx, imon, ir_ep->bInterval);
+
+ rcdev = devm_rc_allocate_device(&intf->dev, RC_DRIVER_IR_RAW);
+ if (!rcdev) {
+ ret = -ENOMEM;
+ goto free_urb;
+ }
+
+ usb_make_path(udev, imon->phys, sizeof(imon->phys));
+
+ rcdev->device_name = "iMON Station";
+ rcdev->driver_name = KBUILD_MODNAME;
+ rcdev->input_phys = imon->phys;
+ usb_to_input_id(udev, &rcdev->input_id);
+ rcdev->dev.parent = &intf->dev;
+ rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
+ rcdev->map_name = RC_MAP_IMON_RSC;
+ rcdev->rx_resolution = BIT_DURATION;
+ rcdev->priv = imon;
+
+ ret = devm_rc_register_device(&intf->dev, rcdev);
+ if (ret)
+ goto free_urb;
+
+ imon->rcdev = rcdev;
+
+ ret = usb_submit_urb(imon->ir_urb, GFP_KERNEL);
+ if (ret)
+ goto free_urb;
+
+ usb_set_intfdata(intf, imon);
+
+ return 0;
+
+free_urb:
+ usb_free_urb(imon->ir_urb);
+ return ret;
+}
+
+static void imon_disconnect(struct usb_interface *intf)
+{
+ struct imon *imon = usb_get_intfdata(intf);
+
+ usb_kill_urb(imon->ir_urb);
+ usb_free_urb(imon->ir_urb);
+}
+
+static const struct usb_device_id imon_table[] = {
+ /* SoundGraph iMON (IR only) -- sg_imon.inf */
+ { USB_DEVICE(0x04e8, 0xff30) },
+ {}
+};
+
+static struct usb_driver imon_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = imon_probe,
+ .disconnect = imon_disconnect,
+ .id_table = imon_table
+};
+
+module_usb_driver(imon_driver);
+
+MODULE_DESCRIPTION("Early raw iMON IR devices");
+MODULE_AUTHOR("Sean Young <sean@mess.org>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, imon_table);
diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c
index 0ce11c41dfae..700ab4c563d0 100644
--- a/drivers/media/rc/ir-hix5hd2.c
+++ b/drivers/media/rc/ir-hix5hd2.c
@@ -71,9 +71,10 @@ struct hix5hd2_ir_priv {
unsigned long rate;
};
-static void hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on)
+static int hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on)
{
u32 val;
+ int ret = 0;
if (dev->regmap) {
regmap_read(dev->regmap, IR_CLK, &val);
@@ -87,10 +88,11 @@ static void hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on)
regmap_write(dev->regmap, IR_CLK, val);
} else {
if (on)
- clk_prepare_enable(dev->clock);
+ ret = clk_prepare_enable(dev->clock);
else
clk_disable_unprepare(dev->clock);
}
+ return ret;
}
static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv)
@@ -127,9 +129,18 @@ static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv)
static int hix5hd2_ir_open(struct rc_dev *rdev)
{
struct hix5hd2_ir_priv *priv = rdev->priv;
+ int ret;
+
+ ret = hix5hd2_ir_enable(priv, true);
+ if (ret)
+ return ret;
- hix5hd2_ir_enable(priv, true);
- return hix5hd2_ir_config(priv);
+ ret = hix5hd2_ir_config(priv);
+ if (ret) {
+ hix5hd2_ir_enable(priv, false);
+ return ret;
+ }
+ return 0;
}
static void hix5hd2_ir_close(struct rc_dev *rdev)
@@ -239,7 +250,9 @@ static int hix5hd2_ir_probe(struct platform_device *pdev)
ret = PTR_ERR(priv->clock);
goto err;
}
- clk_prepare_enable(priv->clock);
+ ret = clk_prepare_enable(priv->clock);
+ if (ret)
+ goto err;
priv->rate = clk_get_rate(priv->clock);
rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
@@ -309,9 +322,17 @@ static int hix5hd2_ir_suspend(struct device *dev)
static int hix5hd2_ir_resume(struct device *dev)
{
struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev);
+ int ret;
- hix5hd2_ir_enable(priv, true);
- clk_prepare_enable(priv->clock);
+ ret = hix5hd2_ir_enable(priv, true);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(priv->clock);
+ if (ret) {
+ hix5hd2_ir_enable(priv, false);
+ return ret;
+ }
writel_relaxed(0x01, priv->base + IR_ENABLE);
writel_relaxed(0x00, priv->base + IR_INTM);
diff --git a/drivers/media/rc/ir-imon-decoder.c b/drivers/media/rc/ir-imon-decoder.c
new file mode 100644
index 000000000000..a1ff06a26542
--- /dev/null
+++ b/drivers/media/rc/ir-imon-decoder.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0+
+// ir-imon-decoder.c - handle iMon protocol
+//
+// Copyright (C) 2018 by Sean Young <sean@mess.org>
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include "rc-core-priv.h"
+
+#define IMON_UNIT 415662 /* ns */
+#define IMON_BITS 30
+#define IMON_CHKBITS (BIT(30) | BIT(25) | BIT(24) | BIT(22) | \
+ BIT(21) | BIT(20) | BIT(19) | BIT(18) | \
+ BIT(17) | BIT(16) | BIT(14) | BIT(13) | \
+ BIT(12) | BIT(11) | BIT(10) | BIT(9))
+
+/*
+ * This protocol has 30 bits. The format is one IMON_UNIT header pulse,
+ * followed by 30 bits. Each bit is one IMON_UNIT check field, and then
+ * one IMON_UNIT field with the actual bit (1=space, 0=pulse).
+ * The check field is always space for some bits, for others it is pulse if
+ * both the preceding and current bit are zero, else space. IMON_CHKBITS
+ * defines which bits are of type check.
+ *
+ * There is no way to distinguish an incomplete message from one where
+ * the lower bits are all set, iow. the last pulse is for the lowest
+ * bit which is 0.
+ */
+enum imon_state {
+ STATE_INACTIVE,
+ STATE_BIT_CHK,
+ STATE_BIT_START,
+ STATE_FINISHED
+};
+
+/**
+ * ir_imon_decode() - Decode one iMON pulse or space
+ * @dev: the struct rc_dev descriptor of the device
+ * @ev: the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_imon_decode(struct rc_dev *dev, struct ir_raw_event ev)
+{
+ struct imon_dec *data = &dev->raw->imon;
+
+ if (!is_timing_event(ev)) {
+ if (ev.reset)
+ data->state = STATE_INACTIVE;
+ return 0;
+ }
+
+ dev_dbg(&dev->dev,
+ "iMON decode started at state %d bitno %d (%uus %s)\n",
+ data->state, data->count, TO_US(ev.duration),
+ TO_STR(ev.pulse));
+
+ for (;;) {
+ if (!geq_margin(ev.duration, IMON_UNIT, IMON_UNIT / 2))
+ return 0;
+
+ decrease_duration(&ev, IMON_UNIT);
+
+ switch (data->state) {
+ case STATE_INACTIVE:
+ if (ev.pulse) {
+ data->state = STATE_BIT_CHK;
+ data->bits = 0;
+ data->count = IMON_BITS;
+ }
+ break;
+ case STATE_BIT_CHK:
+ if (IMON_CHKBITS & BIT(data->count))
+ data->last_chk = ev.pulse;
+ else if (ev.pulse)
+ goto err_out;
+ data->state = STATE_BIT_START;
+ break;
+ case STATE_BIT_START:
+ data->bits <<= 1;
+ if (!ev.pulse)
+ data->bits |= 1;
+
+ if (IMON_CHKBITS & BIT(data->count)) {
+ if (data->last_chk != !(data->bits & 3))
+ goto err_out;
+ }
+
+ if (!data->count--)
+ data->state = STATE_FINISHED;
+ else
+ data->state = STATE_BIT_CHK;
+ break;
+ case STATE_FINISHED:
+ if (ev.pulse)
+ goto err_out;
+ rc_keydown(dev, RC_PROTO_IMON, data->bits, 0);
+ data->state = STATE_INACTIVE;
+ break;
+ }
+ }
+
+err_out:
+ dev_dbg(&dev->dev,
+ "iMON decode failed at state %d bitno %d (%uus %s)\n",
+ data->state, data->count, TO_US(ev.duration),
+ TO_STR(ev.pulse));
+
+ data->state = STATE_INACTIVE;
+
+ return -EINVAL;
+}
+
+/**
+ * ir_imon_encode() - Encode a scancode as a stream of raw events
+ *
+ * @protocol: protocol to encode
+ * @scancode: scancode to encode
+ * @events: array of raw ir events to write into
+ * @max: maximum size of @events
+ *
+ * Returns: The number of events written.
+ * -ENOBUFS if there isn't enough space in the array to fit the
+ * encoding. In this case all @max events will have been written.
+ */
+static int ir_imon_encode(enum rc_proto protocol, u32 scancode,
+ struct ir_raw_event *events, unsigned int max)
+{
+ struct ir_raw_event *e = events;
+ int i, pulse;
+
+ if (!max--)
+ return -ENOBUFS;
+ init_ir_raw_event_duration(e, 1, IMON_UNIT);
+
+ for (i = IMON_BITS; i >= 0; i--) {
+ if (BIT(i) & IMON_CHKBITS)
+ pulse = !(scancode & (BIT(i) | BIT(i + 1)));
+ else
+ pulse = 0;
+
+ if (pulse == e->pulse) {
+ e->duration += IMON_UNIT;
+ } else {
+ if (!max--)
+ return -ENOBUFS;
+ init_ir_raw_event_duration(++e, pulse, IMON_UNIT);
+ }
+
+ pulse = !(scancode & BIT(i));
+
+ if (pulse == e->pulse) {
+ e->duration += IMON_UNIT;
+ } else {
+ if (!max--)
+ return -ENOBUFS;
+ init_ir_raw_event_duration(++e, pulse, IMON_UNIT);
+ }
+ }
+
+ if (e->pulse)
+ e++;
+
+ return e - events;
+}
+
+static struct ir_raw_handler imon_handler = {
+ .protocols = RC_PROTO_BIT_IMON,
+ .decode = ir_imon_decode,
+ .encode = ir_imon_encode,
+ .carrier = 38000,
+};
+
+static int __init ir_imon_decode_init(void)
+{
+ ir_raw_handler_register(&imon_handler);
+
+ pr_info("IR iMON protocol handler initialized\n");
+ return 0;
+}
+
+static void __exit ir_imon_decode_exit(void)
+{
+ ir_raw_handler_unregister(&imon_handler);
+}
+
+module_init(ir_imon_decode_init);
+module_exit(ir_imon_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sean Young <sean@mess.org>");
+MODULE_DESCRIPTION("iMON IR protocol decoder");
diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index c03c776cfa54..8cb68ae43282 100644
--- a/drivers/media/rc/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -56,8 +56,8 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2))
goto out;
- IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "JVC decode started at state %d (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
again:
switch (data->state) {
@@ -136,15 +136,15 @@ again:
u32 scancode;
scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |
(bitrev8((data->bits >> 0) & 0xff) << 0);
- IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
+ dev_dbg(&dev->dev, "JVC scancode 0x%04x\n", scancode);
rc_keydown(dev, RC_PROTO_JVC, scancode, data->toggle);
data->first = false;
data->old_bits = data->bits;
} else if (data->bits == data->old_bits) {
- IR_dprintk(1, "JVC repeat\n");
+ dev_dbg(&dev->dev, "JVC repeat\n");
rc_repeat(dev);
} else {
- IR_dprintk(1, "JVC invalid repeat msg\n");
+ dev_dbg(&dev->dev, "JVC invalid repeat msg\n");
break;
}
@@ -164,8 +164,8 @@ again:
}
out:
- IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "JVC decode failed at state %d (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 2c3df02e05ff..c110984ca671 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -117,19 +117,19 @@ static unsigned char kbd_keycodes[256] = {
static void mce_kbd_rx_timeout(struct timer_list *t)
{
- struct mce_kbd_dec *mce_kbd = from_timer(mce_kbd, t, rx_timeout);
- int i;
+ struct ir_raw_event_ctrl *raw = from_timer(raw, t, mce_kbd.rx_timeout);
unsigned char maskcode;
+ int i;
- IR_dprintk(2, "timer callback clearing all keys\n");
+ dev_dbg(&raw->dev->dev, "timer callback clearing all keys\n");
for (i = 0; i < 7; i++) {
maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i];
- input_report_key(mce_kbd->idev, maskcode, 0);
+ input_report_key(raw->mce_kbd.idev, maskcode, 0);
}
for (i = 0; i < MCIR2_MASK_KEYS_START; i++)
- input_report_key(mce_kbd->idev, kbd_keycodes[i], 0);
+ input_report_key(raw->mce_kbd.idev, kbd_keycodes[i], 0);
}
static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data)
@@ -144,16 +144,16 @@ static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data)
}
}
-static void ir_mce_kbd_process_keyboard_data(struct input_dev *idev,
- u32 scancode)
+static void ir_mce_kbd_process_keyboard_data(struct rc_dev *dev, u32 scancode)
{
+ struct mce_kbd_dec *data = &dev->raw->mce_kbd;
u8 keydata = (scancode >> 8) & 0xff;
u8 shiftmask = scancode & 0xff;
unsigned char keycode, maskcode;
int i, keystate;
- IR_dprintk(1, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n",
- keydata, shiftmask);
+ dev_dbg(&dev->dev, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n",
+ keydata, shiftmask);
for (i = 0; i < 7; i++) {
maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i];
@@ -161,20 +161,21 @@ static void ir_mce_kbd_process_keyboard_data(struct input_dev *idev,
keystate = 1;
else
keystate = 0;
- input_report_key(idev, maskcode, keystate);
+ input_report_key(data->idev, maskcode, keystate);
}
if (keydata) {
keycode = kbd_keycodes[keydata];
- input_report_key(idev, keycode, 1);
+ input_report_key(data->idev, keycode, 1);
} else {
for (i = 0; i < MCIR2_MASK_KEYS_START; i++)
- input_report_key(idev, kbd_keycodes[i], 0);
+ input_report_key(data->idev, kbd_keycodes[i], 0);
}
}
-static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode)
+static void ir_mce_kbd_process_mouse_data(struct rc_dev *dev, u32 scancode)
{
+ struct mce_kbd_dec *data = &dev->raw->mce_kbd;
/* raw mouse coordinates */
u8 xdata = (scancode >> 7) & 0x7f;
u8 ydata = (scancode >> 14) & 0x7f;
@@ -193,14 +194,14 @@ static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode)
else
y = ydata;
- IR_dprintk(1, "mouse: x = %d, y = %d, btns = %s%s\n",
- x, y, left ? "L" : "", right ? "R" : "");
+ dev_dbg(&dev->dev, "mouse: x = %d, y = %d, btns = %s%s\n",
+ x, y, left ? "L" : "", right ? "R" : "");
- input_report_rel(idev, REL_X, x);
- input_report_rel(idev, REL_Y, y);
+ input_report_rel(data->idev, REL_X, x);
+ input_report_rel(data->idev, REL_Y, y);
- input_report_key(idev, BTN_LEFT, left);
- input_report_key(idev, BTN_RIGHT, right);
+ input_report_key(data->idev, BTN_LEFT, left);
+ input_report_key(data->idev, BTN_RIGHT, right);
}
/**
@@ -227,8 +228,8 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
goto out;
again:
- IR_dprintk(2, "started at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "started at state %i (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
return 0;
@@ -280,7 +281,7 @@ again:
data->wanted_bits = MCIR2_MOUSE_NBITS;
break;
default:
- IR_dprintk(1, "not keyboard or mouse data\n");
+ dev_dbg(&dev->dev, "not keyboard or mouse data\n");
goto out;
}
@@ -319,25 +320,26 @@ again:
switch (data->wanted_bits) {
case MCIR2_KEYBOARD_NBITS:
scancode = data->body & 0xffff;
- IR_dprintk(1, "keyboard data 0x%08x\n", data->body);
+ dev_dbg(&dev->dev, "keyboard data 0x%08x\n",
+ data->body);
if (dev->timeout)
delay = usecs_to_jiffies(dev->timeout / 1000);
else
delay = msecs_to_jiffies(100);
mod_timer(&data->rx_timeout, jiffies + delay);
/* Pass data to keyboard buffer parser */
- ir_mce_kbd_process_keyboard_data(data->idev, scancode);
+ ir_mce_kbd_process_keyboard_data(dev, scancode);
lsc.rc_proto = RC_PROTO_MCIR2_KBD;
break;
case MCIR2_MOUSE_NBITS:
scancode = data->body & 0x1fffff;
- IR_dprintk(1, "mouse data 0x%06x\n", scancode);
+ dev_dbg(&dev->dev, "mouse data 0x%06x\n", scancode);
/* Pass data to mouse buffer parser */
- ir_mce_kbd_process_mouse_data(data->idev, scancode);
+ ir_mce_kbd_process_mouse_data(dev, scancode);
lsc.rc_proto = RC_PROTO_MCIR2_MSE;
break;
default:
- IR_dprintk(1, "not keyboard or mouse data\n");
+ dev_dbg(&dev->dev, "not keyboard or mouse data\n");
goto out;
}
@@ -350,8 +352,8 @@ again:
}
out:
- IR_dprintk(1, "failed at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "failed at state %i (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
input_sync(data->idev);
return -EINVAL;
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 31d7bafe7bda..21647b809e6f 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -49,8 +49,8 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
return 0;
}
- IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "NEC decode started at state %d (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
switch (data->state) {
@@ -99,13 +99,11 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
break;
if (data->necx_repeat && data->count == NECX_REPEAT_BITS &&
- geq_margin(ev.duration,
- NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
- IR_dprintk(1, "Repeat last key\n");
- rc_repeat(dev);
- data->state = STATE_INACTIVE;
- return 0;
-
+ geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
+ dev_dbg(&dev->dev, "Repeat last key\n");
+ rc_repeat(dev);
+ data->state = STATE_INACTIVE;
+ return 0;
} else if (data->count > NECX_REPEAT_BITS)
data->necx_repeat = false;
@@ -164,8 +162,8 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
return 0;
}
- IR_dprintk(1, "NEC decode failed at count %d state %d (%uus %s)\n",
- data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "NEC decode failed at count %d state %d (%uus %s)\n",
+ data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 11a28f8772da..74d3b859c3a2 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -54,8 +54,8 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
goto out;
again:
- IR_dprintk(2, "RC5(x/sz) decode started at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "RC5(x/sz) decode started at state %i (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
return 0;
@@ -157,8 +157,8 @@ again:
} else
break;
- IR_dprintk(1, "RC5(x/sz) scancode 0x%06x (p: %u, t: %u)\n",
- scancode, protocol, toggle);
+ dev_dbg(&dev->dev, "RC5(x/sz) scancode 0x%06x (p: %u, t: %u)\n",
+ scancode, protocol, toggle);
rc_keydown(dev, protocol, scancode, toggle);
data->state = STATE_INACTIVE;
@@ -166,8 +166,8 @@ again:
}
out:
- IR_dprintk(1, "RC5(x/sz) decode failed at state %i count %d (%uus %s)\n",
- data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "RC5(x/sz) decode failed at state %i count %d (%uus %s)\n",
+ data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index 55bb19bbd4e9..8314da32453f 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -100,8 +100,8 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
goto out;
again:
- IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "RC6 decode started at state %i (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
return 0;
@@ -170,7 +170,7 @@ again:
break;
if (!(data->header & RC6_STARTBIT_MASK)) {
- IR_dprintk(1, "RC6 invalid start bit\n");
+ dev_dbg(&dev->dev, "RC6 invalid start bit\n");
break;
}
@@ -187,7 +187,7 @@ again:
data->wanted_bits = RC6_6A_NBITS;
break;
default:
- IR_dprintk(1, "RC6 unknown mode\n");
+ dev_dbg(&dev->dev, "RC6 unknown mode\n");
goto out;
}
goto again;
@@ -230,13 +230,13 @@ again:
scancode = data->body;
toggle = data->toggle;
protocol = RC_PROTO_RC6_0;
- IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
- scancode, toggle);
+ dev_dbg(&dev->dev, "RC6(0) scancode 0x%04x (toggle: %u)\n",
+ scancode, toggle);
break;
case RC6_MODE_6A:
if (data->count > CHAR_BIT * sizeof data->body) {
- IR_dprintk(1, "RC6 too many (%u) data bits\n",
+ dev_dbg(&dev->dev, "RC6 too many (%u) data bits\n",
data->count);
goto out;
}
@@ -262,15 +262,15 @@ again:
}
break;
default:
- IR_dprintk(1, "RC6(6A) unsupported length\n");
+ dev_dbg(&dev->dev, "RC6(6A) unsupported length\n");
goto out;
}
- IR_dprintk(1, "RC6(6A) proto 0x%04x, scancode 0x%08x (toggle: %u)\n",
- protocol, scancode, toggle);
+ dev_dbg(&dev->dev, "RC6(6A) proto 0x%04x, scancode 0x%08x (toggle: %u)\n",
+ protocol, scancode, toggle);
break;
default:
- IR_dprintk(1, "RC6 unknown mode\n");
+ dev_dbg(&dev->dev, "RC6 unknown mode\n");
goto out;
}
@@ -280,8 +280,8 @@ again:
}
out:
- IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "RC6 decode failed at state %i (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index ded39cdfc6ef..4efe6db5376a 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -52,14 +52,14 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
if (!is_timing_event(ev)) {
if (ev.reset) {
- IR_dprintk(1, "SANYO event reset received. reset to state 0\n");
+ dev_dbg(&dev->dev, "SANYO event reset received. reset to state 0\n");
data->state = STATE_INACTIVE;
}
return 0;
}
- IR_dprintk(2, "SANYO decode started at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "SANYO decode started at state %d (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
switch (data->state) {
@@ -102,7 +102,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
rc_repeat(dev);
- IR_dprintk(1, "SANYO repeat last key\n");
+ dev_dbg(&dev->dev, "SANYO repeat last key\n");
data->state = STATE_INACTIVE;
return 0;
}
@@ -144,21 +144,21 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
not_command = bitrev8((data->bits >> 0) & 0xff);
if ((command ^ not_command) != 0xff) {
- IR_dprintk(1, "SANYO checksum error: received 0x%08Lx\n",
- data->bits);
+ dev_dbg(&dev->dev, "SANYO checksum error: received 0x%08llx\n",
+ data->bits);
data->state = STATE_INACTIVE;
return 0;
}
scancode = address << 8 | command;
- IR_dprintk(1, "SANYO scancode: 0x%06x\n", scancode);
+ dev_dbg(&dev->dev, "SANYO scancode: 0x%06x\n", scancode);
rc_keydown(dev, RC_PROTO_SANYO, scancode, 0);
data->state = STATE_INACTIVE;
return 0;
}
- IR_dprintk(1, "SANYO decode failed at count %d state %d (%uus %s)\n",
- data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "SANYO decode failed at count %d state %d (%uus %s)\n",
+ data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c
index df296991906c..6a38c50566a4 100644
--- a/drivers/media/rc/ir-sharp-decoder.c
+++ b/drivers/media/rc/ir-sharp-decoder.c
@@ -54,8 +54,8 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
return 0;
}
- IR_dprintk(2, "Sharp decode started at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "Sharp decode started at state %d (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
switch (data->state) {
@@ -149,9 +149,9 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
msg = (data->bits >> 15) & 0x7fff;
echo = data->bits & 0x7fff;
if ((msg ^ echo) != 0x3ff) {
- IR_dprintk(1,
- "Sharp checksum error: received 0x%04x, 0x%04x\n",
- msg, echo);
+ dev_dbg(&dev->dev,
+ "Sharp checksum error: received 0x%04x, 0x%04x\n",
+ msg, echo);
break;
}
@@ -159,16 +159,15 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
command = bitrev8((msg >> 2) & 0xff);
scancode = address << 8 | command;
- IR_dprintk(1, "Sharp scancode 0x%04x\n", scancode);
+ dev_dbg(&dev->dev, "Sharp scancode 0x%04x\n", scancode);
rc_keydown(dev, RC_PROTO_SHARP, scancode, 0);
data->state = STATE_INACTIVE;
return 0;
}
- IR_dprintk(1, "Sharp decode failed at count %d state %d (%uus %s)\n",
- data->count, data->state, TO_US(ev.duration),
- TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "Sharp decode failed at count %d state %d (%uus %s)\n",
+ data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index e4bcff21c025..6764ec9de646 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -55,8 +55,8 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2))
goto out;
- IR_dprintk(2, "Sony decode started at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "Sony decode started at state %d (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
switch (data->state) {
@@ -148,19 +148,21 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
protocol = RC_PROTO_SONY20;
break;
default:
- IR_dprintk(1, "Sony invalid bitcount %u\n", data->count);
+ dev_dbg(&dev->dev, "Sony invalid bitcount %u\n",
+ data->count);
goto out;
}
scancode = device << 16 | subdevice << 8 | function;
- IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode);
+ dev_dbg(&dev->dev, "Sony(%u) scancode 0x%05x\n", data->count,
+ scancode);
rc_keydown(dev, protocol, scancode, 0);
goto finish_state_machine;
}
out:
- IR_dprintk(1, "Sony decode failed at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "Sony decode failed at state %d (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c
index a32a84ae2d0b..7163d5ce2e64 100644
--- a/drivers/media/rc/ir-spi.c
+++ b/drivers/media/rc/ir-spi.c
@@ -15,21 +15,11 @@
#define IR_SPI_DRIVER_NAME "ir-spi"
-/* pulse value for different duty cycles */
-#define IR_SPI_PULSE_DC_50 0xff00
-#define IR_SPI_PULSE_DC_60 0xfc00
-#define IR_SPI_PULSE_DC_70 0xf800
-#define IR_SPI_PULSE_DC_75 0xf000
-#define IR_SPI_PULSE_DC_80 0xc000
-#define IR_SPI_PULSE_DC_90 0x8000
-
#define IR_SPI_DEFAULT_FREQUENCY 38000
-#define IR_SPI_BIT_PER_WORD 8
#define IR_SPI_MAX_BUFSIZE 4096
struct ir_spi_data {
u32 freq;
- u8 duty_cycle;
bool negated;
u16 tx_buf[IR_SPI_MAX_BUFSIZE];
@@ -105,19 +95,9 @@ static int ir_spi_set_tx_carrier(struct rc_dev *dev, u32 carrier)
static int ir_spi_set_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
{
struct ir_spi_data *idata = dev->priv;
+ int bits = (duty_cycle * 15) / 100;
- if (duty_cycle >= 90)
- idata->pulse = IR_SPI_PULSE_DC_90;
- else if (duty_cycle >= 80)
- idata->pulse = IR_SPI_PULSE_DC_80;
- else if (duty_cycle >= 75)
- idata->pulse = IR_SPI_PULSE_DC_75;
- else if (duty_cycle >= 70)
- idata->pulse = IR_SPI_PULSE_DC_70;
- else if (duty_cycle >= 60)
- idata->pulse = IR_SPI_PULSE_DC_60;
- else
- idata->pulse = IR_SPI_PULSE_DC_50;
+ idata->pulse = GENMASK(bits, 0);
if (idata->negated) {
idata->pulse = ~idata->pulse;
diff --git a/drivers/media/rc/ir-xmp-decoder.c b/drivers/media/rc/ir-xmp-decoder.c
index 712bc6d76e92..58b47af1a763 100644
--- a/drivers/media/rc/ir-xmp-decoder.c
+++ b/drivers/media/rc/ir-xmp-decoder.c
@@ -49,8 +49,8 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
return 0;
}
- IR_dprintk(2, "XMP decode started at state %d %d (%uus %s)\n",
- data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "XMP decode started at state %d %d (%uus %s)\n",
+ data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse));
switch (data->state) {
@@ -85,7 +85,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
if (data->count != 16) {
- IR_dprintk(2, "received TRAILER period at index %d: %u\n",
+ dev_dbg(&dev->dev, "received TRAILER period at index %d: %u\n",
data->count, ev.duration);
data->state = STATE_INACTIVE;
return -EINVAL;
@@ -99,7 +99,8 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
*/
divider = (n[3] - XMP_NIBBLE_PREFIX) / 15 - 2000;
if (divider < 50) {
- IR_dprintk(2, "divider to small %d.\n", divider);
+ dev_dbg(&dev->dev, "divider to small %d.\n",
+ divider);
data->state = STATE_INACTIVE;
return -EINVAL;
}
@@ -113,7 +114,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
n[12] + n[13] + n[14] + n[15]) % 16;
if (sum1 != 15 || sum2 != 15) {
- IR_dprintk(2, "checksum errors sum1=0x%X sum2=0x%X\n",
+ dev_dbg(&dev->dev, "checksum errors sum1=0x%X sum2=0x%X\n",
sum1, sum2);
data->state = STATE_INACTIVE;
return -EINVAL;
@@ -127,24 +128,24 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
obc1 = n[12] << 4 | n[13];
obc2 = n[14] << 4 | n[15];
if (subaddr != subaddr2) {
- IR_dprintk(2, "subaddress nibbles mismatch 0x%02X != 0x%02X\n",
+ dev_dbg(&dev->dev, "subaddress nibbles mismatch 0x%02X != 0x%02X\n",
subaddr, subaddr2);
data->state = STATE_INACTIVE;
return -EINVAL;
}
if (oem != 0x44)
- IR_dprintk(1, "Warning: OEM nibbles 0x%02X. Expected 0x44\n",
+ dev_dbg(&dev->dev, "Warning: OEM nibbles 0x%02X. Expected 0x44\n",
oem);
scancode = addr << 24 | subaddr << 16 |
obc1 << 8 | obc2;
- IR_dprintk(1, "XMP scancode 0x%06x\n", scancode);
+ dev_dbg(&dev->dev, "XMP scancode 0x%06x\n", scancode);
if (toggle == 0) {
rc_keydown(dev, RC_PROTO_XMP, scancode, 0);
} else {
rc_repeat(dev);
- IR_dprintk(1, "Repeat last key\n");
+ dev_dbg(&dev->dev, "Repeat last key\n");
}
data->state = STATE_INACTIVE;
@@ -153,7 +154,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
} else if (geq_margin(ev.duration, XMP_HALFFRAME_SPACE, XMP_NIBBLE_PREFIX)) {
/* Expect 8 or 16 nibble pulses. 16 in case of 'final' frame */
if (data->count == 16) {
- IR_dprintk(2, "received half frame pulse at index %d. Probably a final frame key-up event: %u\n",
+ dev_dbg(&dev->dev, "received half frame pulse at index %d. Probably a final frame key-up event: %u\n",
data->count, ev.duration);
/*
* TODO: for now go back to half frame position
@@ -164,7 +165,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
else if (data->count != 8)
- IR_dprintk(2, "received half frame pulse at index %d: %u\n",
+ dev_dbg(&dev->dev, "received half frame pulse at index %d: %u\n",
data->count, ev.duration);
data->state = STATE_LEADER_PULSE;
@@ -173,7 +174,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
} else if (geq_margin(ev.duration, XMP_NIBBLE_PREFIX, XMP_UNIT)) {
/* store nibble raw data, decode after trailer */
if (data->count == 16) {
- IR_dprintk(2, "to many pulses (%d) ignoring: %u\n",
+ dev_dbg(&dev->dev, "to many pulses (%d) ignoring: %u\n",
data->count, ev.duration);
data->state = STATE_INACTIVE;
return -EINVAL;
@@ -189,8 +190,8 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
break;
}
- IR_dprintk(1, "XMP decode failed at count %d state %d (%uus %s)\n",
- data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "XMP decode failed at count %d state %d (%uus %s)\n",
+ data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 50b319355edf..d6b913a3032d 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-hisi-tv-demo.o \
rc-imon-mce.o \
rc-imon-pad.o \
+ rc-imon-rsc.o \
rc-iodata-bctv7e.o \
rc-it913x-v1.o \
rc-it913x-v2.o \
diff --git a/drivers/media/rc/keymaps/rc-imon-pad.c b/drivers/media/rc/keymaps/rc-imon-pad.c
index a7296ffbf218..8501cf0a3253 100644
--- a/drivers/media/rc/keymaps/rc-imon-pad.c
+++ b/drivers/media/rc/keymaps/rc-imon-pad.c
@@ -134,8 +134,7 @@ static struct rc_map_list imon_pad_map = {
.map = {
.scan = imon_pad,
.size = ARRAY_SIZE(imon_pad),
- /* actual protocol details unknown, hardware decoder */
- .rc_proto = RC_PROTO_OTHER,
+ .rc_proto = RC_PROTO_IMON,
.name = RC_MAP_IMON_PAD,
}
};
diff --git a/drivers/media/rc/keymaps/rc-imon-rsc.c b/drivers/media/rc/keymaps/rc-imon-rsc.c
new file mode 100644
index 000000000000..83e4564aaa22
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-imon-rsc.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (C) 2018 Sean Young <sean@mess.org>
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+//
+// Note that this remote has a stick which its own IR protocol,
+// with 16 directions. This is not supported yet.
+//
+static struct rc_map_table imon_rsc[] = {
+ { 0x801010, KEY_EXIT },
+ { 0x80102f, KEY_POWER },
+ { 0x80104a, KEY_SCREENSAVER }, /* Screensaver */
+ { 0x801049, KEY_TIME }, /* Timer */
+ { 0x801054, KEY_NUMERIC_1 },
+ { 0x801055, KEY_NUMERIC_2 },
+ { 0x801056, KEY_NUMERIC_3 },
+ { 0x801057, KEY_NUMERIC_4 },
+ { 0x801058, KEY_NUMERIC_5 },
+ { 0x801059, KEY_NUMERIC_6 },
+ { 0x80105a, KEY_NUMERIC_7 },
+ { 0x80105b, KEY_NUMERIC_8 },
+ { 0x80105c, KEY_NUMERIC_9 },
+ { 0x801081, KEY_SCREEN }, /* Desktop */
+ { 0x80105d, KEY_NUMERIC_0 },
+ { 0x801082, KEY_MAX },
+ { 0x801048, KEY_ESC },
+ { 0x80104b, KEY_MEDIA }, /* Windows key */
+ { 0x801083, KEY_MENU },
+ { 0x801045, KEY_APPSELECT }, /* app launcher */
+ { 0x801084, KEY_STOP },
+ { 0x801046, KEY_CYCLEWINDOWS },
+ { 0x801085, KEY_BACKSPACE },
+ { 0x801086, KEY_KEYBOARD },
+ { 0x801087, KEY_SPACE },
+ { 0x80101e, KEY_RESERVED }, /* shift tab */
+ { 0x801098, BTN_0 },
+ { 0x80101f, KEY_TAB },
+ { 0x80101b, BTN_LEFT },
+ { 0x80101d, BTN_RIGHT },
+ { 0x801016, BTN_MIDDLE }, /* drag and drop */
+ { 0x801088, KEY_MUTE },
+ { 0x80105e, KEY_VOLUMEDOWN },
+ { 0x80105f, KEY_VOLUMEUP },
+ { 0x80104c, KEY_PLAY },
+ { 0x80104d, KEY_PAUSE },
+ { 0x80104f, KEY_EJECTCD },
+ { 0x801050, KEY_PREVIOUS },
+ { 0x801051, KEY_NEXT },
+ { 0x80104e, KEY_STOP },
+ { 0x801052, KEY_REWIND },
+ { 0x801053, KEY_FASTFORWARD },
+ { 0x801089, KEY_ZOOM } /* full screen */
+};
+
+static struct rc_map_list imon_rsc_map = {
+ .map = {
+ .scan = imon_rsc,
+ .size = ARRAY_SIZE(imon_rsc),
+ .rc_proto = RC_PROTO_NEC,
+ .name = RC_MAP_IMON_RSC,
+ }
+};
+
+static int __init init_rc_map_imon_rsc(void)
+{
+ return rc_map_register(&imon_rsc_map);
+}
+
+static void __exit exit_rc_map_imon_rsc(void)
+{
+ rc_map_unregister(&imon_rsc_map);
+}
+
+module_init(init_rc_map_imon_rsc)
+module_exit(exit_rc_map_imon_rsc)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sean Young <sean@mess.org>");
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index cc863044c880..24e9fbb80e81 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -60,12 +60,12 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
* space with the maximum time value.
*/
sample = LIRC_SPACE(LIRC_VALUE_MASK);
- IR_dprintk(2, "delivering reset sync space to lirc_dev\n");
+ dev_dbg(&dev->dev, "delivering reset sync space to lirc_dev\n");
/* Carrier reports */
} else if (ev.carrier_report) {
sample = LIRC_FREQUENCY(ev.carrier);
- IR_dprintk(2, "carrier report (freq: %d)\n", sample);
+ dev_dbg(&dev->dev, "carrier report (freq: %d)\n", sample);
/* Packet end */
} else if (ev.timeout) {
@@ -77,7 +77,7 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
dev->gap_duration = ev.duration;
sample = LIRC_TIMEOUT(ev.duration / 1000);
- IR_dprintk(2, "timeout report (duration: %d)\n", sample);
+ dev_dbg(&dev->dev, "timeout report (duration: %d)\n", sample);
/* Normal sample */
} else {
@@ -100,8 +100,8 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
LIRC_SPACE(ev.duration / 1000);
- IR_dprintk(2, "delivering %uus %s to lirc_dev\n",
- TO_US(ev.duration), TO_STR(ev.pulse));
+ dev_dbg(&dev->dev, "delivering %uus %s to lirc_dev\n",
+ TO_US(ev.duration), TO_STR(ev.pulse));
}
spin_lock_irqsave(&dev->lirc_fh_lock, flags);
@@ -249,8 +249,6 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
goto out_unlock;
}
- start = ktime_get();
-
if (!dev->tx_ir) {
ret = -EINVAL;
goto out_unlock;
@@ -343,6 +341,8 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
duration += txbuf[i];
}
+ start = ktime_get();
+
ret = dev->tx_ir(dev, txbuf, count);
if (ret < 0)
goto out_kfree;
@@ -570,7 +570,7 @@ static long ir_lirc_ioctl(struct file *file, unsigned int cmd,
ret = -EINVAL;
else if (dev->s_timeout)
ret = dev->s_timeout(dev, tmp);
- else if (!ret)
+ else
dev->timeout = tmp;
}
break;
@@ -804,8 +804,8 @@ int __init lirc_dev_init(void)
return retval;
}
- pr_info("IR Remote Control driver registered, major %d\n",
- MAJOR(lirc_base_dev));
+ pr_debug("IR Remote Control driver registered, major %d\n",
+ MAJOR(lirc_base_dev));
return 0;
}
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index a9187b0b46a1..69ba57372c05 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -42,7 +42,7 @@
#include <linux/pm_wakeup.h>
#include <media/rc-core.h>
-#define DRIVER_VERSION "1.93"
+#define DRIVER_VERSION "1.94"
#define DRIVER_AUTHOR "Jarod Wilson <jarod@redhat.com>"
#define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \
"device driver"
@@ -182,6 +182,7 @@ enum mceusb_model_type {
MCE_GEN1,
MCE_GEN3,
MCE_GEN2_TX_INV,
+ MCE_GEN2_TX_INV_RX_GOOD,
POLARIS_EVK,
CX_HYBRID_TV,
MULTIFUNCTION,
@@ -198,6 +199,13 @@ struct mceusb_model {
u32 mce_gen3:1;
u32 tx_mask_normal:1;
u32 no_tx:1;
+ /*
+ * 2nd IR receiver (short-range, wideband) for learning mode:
+ * 0, absent 2nd receiver (rx2)
+ * 1, rx2 present
+ * 2, rx2 which under counts IR carrier cycles
+ */
+ u32 rx2;
int ir_intfnum;
@@ -209,9 +217,11 @@ static const struct mceusb_model mceusb_model[] = {
[MCE_GEN1] = {
.mce_gen1 = 1,
.tx_mask_normal = 1,
+ .rx2 = 2,
},
[MCE_GEN2] = {
.mce_gen2 = 1,
+ .rx2 = 2,
},
[MCE_GEN2_NO_TX] = {
.mce_gen2 = 1,
@@ -220,10 +230,17 @@ static const struct mceusb_model mceusb_model[] = {
[MCE_GEN2_TX_INV] = {
.mce_gen2 = 1,
.tx_mask_normal = 1,
+ .rx2 = 1,
+ },
+ [MCE_GEN2_TX_INV_RX_GOOD] = {
+ .mce_gen2 = 1,
+ .tx_mask_normal = 1,
+ .rx2 = 2,
},
[MCE_GEN3] = {
.mce_gen3 = 1,
.tx_mask_normal = 1,
+ .rx2 = 2,
},
[POLARIS_EVK] = {
/*
@@ -232,6 +249,7 @@ static const struct mceusb_model mceusb_model[] = {
* to allow testing it
*/
.name = "Conexant Hybrid TV (cx231xx) MCE IR",
+ .rx2 = 2,
},
[CX_HYBRID_TV] = {
.no_tx = 1, /* tx isn't wired up at all */
@@ -244,10 +262,12 @@ static const struct mceusb_model mceusb_model[] = {
[MULTIFUNCTION] = {
.mce_gen2 = 1,
.ir_intfnum = 2,
+ .rx2 = 2,
},
[TIVO_KIT] = {
.mce_gen2 = 1,
.rc_map = RC_MAP_TIVO,
+ .rx2 = 2,
},
[EVROMEDIA_FULL_HYBRID_FULLHD] = {
.name = "Evromedia USB Full Hybrid Full HD",
@@ -290,7 +310,7 @@ static const struct usb_device_id mceusb_dev_table[] = {
.driver_info = MULTIFUNCTION },
/* SMK/Toshiba G83C0004D410 */
{ USB_DEVICE(VENDOR_SMK, 0x031d),
- .driver_info = MCE_GEN2_TX_INV },
+ .driver_info = MCE_GEN2_TX_INV_RX_GOOD },
/* SMK eHome Infrared Transceiver (Sony VAIO) */
{ USB_DEVICE(VENDOR_SMK, 0x0322),
.driver_info = MCE_GEN2_TX_INV },
@@ -427,7 +447,8 @@ struct mceusb_dev {
struct rc_dev *rc;
/* optional features we can enable */
- bool learning_enabled;
+ bool carrier_report_enabled;
+ bool wideband_rx_enabled; /* aka learning mode, short-range rx */
/* core device bits */
struct device *dev;
@@ -458,6 +479,7 @@ struct mceusb_dev {
u32 tx_mask_normal:1;
u32 microsoft_gen1:1;
u32 no_tx:1;
+ u32 rx2;
} flags;
/* transmit support */
@@ -474,6 +496,11 @@ struct mceusb_dev {
u8 num_rxports; /* number of receive sensors */
u8 txports_cabled; /* bitmask of transmitters with cable */
u8 rxports_active; /* bitmask of active receive sensors */
+ bool learning_active; /* wideband rx is active */
+
+ /* receiver carrier frequency detection support */
+ u32 pulse_tunit; /* IR pulse "on" cumulative time units */
+ u32 pulse_count; /* pulse "on" count in measurement interval */
/*
* support for async error handler mceusb_deferred_kevent()
@@ -684,8 +711,8 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len,
/* aka MCE_RSP_EQIRRXCFCNT */
if (out)
dev_dbg(dev, "Get receive sensor");
- else if (ir->learning_enabled)
- dev_dbg(dev, "RX pulse count: %d",
+ else
+ dev_dbg(dev, "RX carrier cycle count: %d",
((data[0] << 8) | data[1]));
break;
case MCE_RSP_EQIRNUMPORTS:
@@ -956,14 +983,78 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
}
/*
+ * Select or deselect the 2nd receiver port.
+ * Second receiver is learning mode, wide-band, short-range receiver.
+ * Only one receiver (long or short range) may be active at a time.
+ */
+static int mceusb_set_rx_wideband(struct rc_dev *dev, int enable)
+{
+ struct mceusb_dev *ir = dev->priv;
+ unsigned char cmdbuf[3] = { MCE_CMD_PORT_IR,
+ MCE_CMD_SETIRRXPORTEN, 0x00 };
+
+ dev_dbg(ir->dev, "select %s-range receive sensor",
+ enable ? "short" : "long");
+ if (enable) {
+ ir->wideband_rx_enabled = true;
+ cmdbuf[2] = 2; /* port 2 is short range receiver */
+ } else {
+ ir->wideband_rx_enabled = false;
+ cmdbuf[2] = 1; /* port 1 is long range receiver */
+ }
+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
+ /* response from device sets ir->learning_active */
+
+ return 0;
+}
+
+/*
+ * Enable/disable receiver carrier frequency pass through reporting.
+ * Only the short-range receiver has carrier frequency measuring capability.
+ * Implicitly select this receiver when enabling carrier frequency reporting.
+ */
+static int mceusb_set_rx_carrier_report(struct rc_dev *dev, int enable)
+{
+ struct mceusb_dev *ir = dev->priv;
+ unsigned char cmdbuf[3] = { MCE_CMD_PORT_IR,
+ MCE_CMD_SETIRRXPORTEN, 0x00 };
+
+ dev_dbg(ir->dev, "%s short-range receiver carrier reporting",
+ enable ? "enable" : "disable");
+ if (enable) {
+ ir->carrier_report_enabled = true;
+ if (!ir->learning_active) {
+ cmdbuf[2] = 2; /* port 2 is short range receiver */
+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
+ }
+ } else {
+ ir->carrier_report_enabled = false;
+ /*
+ * Revert to normal (long-range) receiver only if the
+ * wideband (short-range) receiver wasn't explicitly
+ * enabled.
+ */
+ if (ir->learning_active && !ir->wideband_rx_enabled) {
+ cmdbuf[2] = 1; /* port 1 is long range receiver */
+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
+ }
+ }
+
+ return 0;
+}
+
+/*
* We don't do anything but print debug spew for many of the command bits
* we receive from the hardware, but some of them are useful information
* we want to store so that we can use them.
*/
static void mceusb_handle_command(struct mceusb_dev *ir, int index)
{
+ DEFINE_IR_RAW_EVENT(rawir);
u8 hi = ir->buf_in[index + 1] & 0xff;
u8 lo = ir->buf_in[index + 2] & 0xff;
+ u32 carrier_cycles;
+ u32 cycles_fix;
switch (ir->buf_in[index]) {
/* the one and only 5-byte return value command */
@@ -980,6 +1071,33 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
ir->num_txports = hi;
ir->num_rxports = lo;
break;
+ case MCE_RSP_EQIRRXCFCNT:
+ /*
+ * The carrier cycle counter can overflow and wrap around
+ * without notice from the device. So frequency measurement
+ * will be inaccurate with long duration IR.
+ *
+ * The long-range (non learning) receiver always reports
+ * zero count so we always ignore its report.
+ */
+ if (ir->carrier_report_enabled && ir->learning_active &&
+ ir->pulse_tunit > 0) {
+ carrier_cycles = (hi << 8 | lo);
+ /*
+ * Adjust carrier cycle count by adding
+ * 1 missed count per pulse "on"
+ */
+ cycles_fix = ir->flags.rx2 == 2 ? ir->pulse_count : 0;
+ rawir.carrier_report = 1;
+ rawir.carrier = (1000000u / MCE_TIME_UNIT) *
+ (carrier_cycles + cycles_fix) /
+ ir->pulse_tunit;
+ dev_dbg(ir->dev, "RX carrier frequency %u Hz (pulse count = %u, cycles = %u, duration = %u, rx2 = %u)",
+ rawir.carrier, ir->pulse_count, carrier_cycles,
+ ir->pulse_tunit, ir->flags.rx2);
+ ir_raw_event_store(ir->rc, &rawir);
+ }
+ break;
/* 1-byte return value commands */
case MCE_RSP_EQEMVER:
@@ -989,8 +1107,12 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
ir->tx_mask = hi;
break;
case MCE_RSP_EQIRRXPORTEN:
- ir->learning_enabled = ((hi & 0x02) == 0x02);
- ir->rxports_active = hi;
+ ir->learning_active = ((hi & 0x02) == 0x02);
+ if (ir->rxports_active != hi) {
+ dev_info(ir->dev, "%s-range (0x%x) receiver active",
+ ir->learning_active ? "short" : "long", hi);
+ ir->rxports_active = hi;
+ }
break;
case MCE_RSP_CMD_ILLEGAL:
ir->need_reset = true;
@@ -1027,12 +1149,16 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
ir->rem--;
init_ir_raw_event(&rawir);
rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
- rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
- * US_TO_NS(MCE_TIME_UNIT);
+ rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK);
+ if (rawir.pulse) {
+ ir->pulse_tunit += rawir.duration;
+ ir->pulse_count++;
+ }
+ rawir.duration *= US_TO_NS(MCE_TIME_UNIT);
- dev_dbg(ir->dev, "Storing %s with duration %u",
+ dev_dbg(ir->dev, "Storing %s %u ns (%02x)",
rawir.pulse ? "pulse" : "space",
- rawir.duration);
+ rawir.duration, ir->buf_in[i]);
if (ir_raw_event_store_with_filter(ir->rc, &rawir))
event = true;
@@ -1053,10 +1179,13 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK);
mceusb_dev_printdata(ir, ir->buf_in, buf_len,
i, ir->rem + 1, false);
- if (ir->rem)
+ if (ir->rem) {
ir->parser_state = PARSE_IRDATA;
- else
+ } else {
ir_raw_event_reset(ir->rc);
+ ir->pulse_tunit = 0;
+ ir->pulse_count = 0;
+ }
break;
}
@@ -1292,6 +1421,10 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
rc->s_tx_carrier = mceusb_set_tx_carrier;
rc->tx_ir = mceusb_tx_ir;
}
+ if (ir->flags.rx2 > 0) {
+ rc->s_learning_mode = mceusb_set_rx_wideband;
+ rc->s_carrier_report = mceusb_set_rx_carrier_report;
+ }
rc->driver_name = DRIVER_NAME;
switch (le16_to_cpu(udev->descriptor.idVendor)) {
@@ -1406,6 +1539,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
ir->flags.microsoft_gen1 = is_microsoft_gen1;
ir->flags.tx_mask_normal = tx_mask_normal;
ir->flags.no_tx = mceusb_model[model].no_tx;
+ ir->flags.rx2 = mceusb_model[model].rx2;
ir->model = model;
/* Saving usb interface data for use by the transmitter routine */
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c
index f2204eb77e2a..f449b35d25e7 100644
--- a/drivers/media/rc/meson-ir.c
+++ b/drivers/media/rc/meson-ir.c
@@ -97,8 +97,7 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id)
status = readl_relaxed(ir->reg + IR_DEC_STATUS);
rawir.pulse = !!(status & STATUS_IR_DEC_IN);
- ir_raw_event_store(ir->rc, &rawir);
- ir_raw_event_handle(ir->rc);
+ ir_raw_event_store_with_timeout(ir->rc, &rawir);
spin_unlock(&ir->lock);
@@ -145,7 +144,9 @@ static int meson_ir_probe(struct platform_device *pdev)
ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY;
ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
ir->rc->rx_resolution = US_TO_NS(MESON_TRATE);
- ir->rc->timeout = MS_TO_NS(200);
+ ir->rc->min_timeout = 1;
+ ir->rc->timeout = IR_DEFAULT_TIMEOUT;
+ ir->rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
ir->rc->driver_name = DRIVER_NAME;
spin_lock_init(&ir->lock);
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 458e9eb2d6a9..e0e6a17460f6 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -50,8 +50,9 @@ struct ir_raw_event_ctrl {
DECLARE_KFIFO(kfifo, struct ir_raw_event, MAX_IR_EVENT_SIZE);
ktime_t last_event; /* when last event occurred */
struct rc_dev *dev; /* pointer to the parent rc_dev */
- /* edge driver */
- struct timer_list edge_handle;
+ /* handle delayed ir_raw_event_store_edge processing */
+ spinlock_t edge_spinlock;
+ struct timer_list edge_handle;
/* raw decoder state follows */
struct ir_raw_event prev_ev;
@@ -117,6 +118,12 @@ struct ir_raw_event_ctrl {
unsigned count;
u32 durations[16];
} xmp;
+ struct imon_dec {
+ int state;
+ int count;
+ int last_chk;
+ unsigned int bits;
+ } imon;
};
/* macros for IR decoders */
@@ -292,11 +299,4 @@ static inline int ir_lirc_register(struct rc_dev *dev) { return 0; }
static inline void ir_lirc_unregister(struct rc_dev *dev) { }
#endif
-/*
- * Decoder initialization code
- *
- * Those load logic are called during ir-core init, and automatically
- * loads the compiled decoders for their usage with IR raw events
- */
-
#endif /* _RC_CORE_PRIV */
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 18504870b9f0..374f83105a23 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -65,8 +65,8 @@ int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
if (!dev->raw)
return -EINVAL;
- IR_dprintk(2, "sample: (%05dus %s)\n",
- TO_US(ev->duration), TO_STR(ev->pulse));
+ dev_dbg(&dev->dev, "sample: (%05dus %s)\n",
+ TO_US(ev->duration), TO_STR(ev->pulse));
if (!kfifo_put(&dev->raw->kfifo, *ev)) {
dev_err(&dev->dev, "IR event FIFO is full!\n");
@@ -92,7 +92,6 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse)
{
ktime_t now;
DEFINE_IR_RAW_EVENT(ev);
- int rc = 0;
if (!dev->raw)
return -EINVAL;
@@ -101,7 +100,33 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse)
ev.duration = ktime_to_ns(ktime_sub(now, dev->raw->last_event));
ev.pulse = !pulse;
- rc = ir_raw_event_store(dev, &ev);
+ return ir_raw_event_store_with_timeout(dev, &ev);
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
+
+/*
+ * ir_raw_event_store_with_timeout() - pass a pulse/space duration to the raw
+ * ir decoders, schedule decoding and
+ * timeout
+ * @dev: the struct rc_dev device descriptor
+ * @ev: the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This routine (which may be called from an interrupt context) stores a
+ * pulse/space duration for the raw ir decoding state machines, schedules
+ * decoding and generates a timeout.
+ */
+int ir_raw_event_store_with_timeout(struct rc_dev *dev, struct ir_raw_event *ev)
+{
+ ktime_t now;
+ int rc = 0;
+
+ if (!dev->raw)
+ return -EINVAL;
+
+ now = ktime_get();
+
+ spin_lock(&dev->raw->edge_spinlock);
+ rc = ir_raw_event_store(dev, ev);
dev->raw->last_event = now;
@@ -112,10 +137,11 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse)
mod_timer(&dev->raw->edge_handle,
jiffies + msecs_to_jiffies(15));
}
+ spin_unlock(&dev->raw->edge_spinlock);
return rc;
}
-EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
+EXPORT_SYMBOL_GPL(ir_raw_event_store_with_timeout);
/**
* ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing
@@ -168,7 +194,7 @@ void ir_raw_event_set_idle(struct rc_dev *dev, bool idle)
if (!dev->raw)
return;
- IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
+ dev_dbg(&dev->dev, "%s idle mode\n", idle ? "enter" : "leave");
if (idle) {
dev->raw->this_ev.timeout = true;
@@ -462,12 +488,26 @@ int ir_raw_encode_scancode(enum rc_proto protocol, u32 scancode,
}
EXPORT_SYMBOL(ir_raw_encode_scancode);
-static void edge_handle(struct timer_list *t)
+/**
+ * ir_raw_edge_handle() - Handle ir_raw_event_store_edge() processing
+ *
+ * @t: timer_list
+ *
+ * This callback is armed by ir_raw_event_store_edge(). It does two things:
+ * first of all, rather than calling ir_raw_event_handle() for each
+ * edge and waking up the rc thread, 15 ms after the first edge
+ * ir_raw_event_handle() is called. Secondly, generate a timeout event
+ * no more IR is received after the rc_dev timeout.
+ */
+static void ir_raw_edge_handle(struct timer_list *t)
{
struct ir_raw_event_ctrl *raw = from_timer(raw, t, edge_handle);
struct rc_dev *dev = raw->dev;
- ktime_t interval = ktime_sub(ktime_get(), dev->raw->last_event);
+ unsigned long flags;
+ ktime_t interval;
+ spin_lock_irqsave(&dev->raw->edge_spinlock, flags);
+ interval = ktime_sub(ktime_get(), dev->raw->last_event);
if (ktime_to_ns(interval) >= dev->timeout) {
DEFINE_IR_RAW_EVENT(ev);
@@ -480,6 +520,7 @@ static void edge_handle(struct timer_list *t)
jiffies + nsecs_to_jiffies(dev->timeout -
ktime_to_ns(interval)));
}
+ spin_unlock_irqrestore(&dev->raw->edge_spinlock, flags);
ir_raw_event_handle(dev);
}
@@ -528,7 +569,8 @@ int ir_raw_event_prepare(struct rc_dev *dev)
dev->raw->dev = dev;
dev->change_protocol = change_protocol;
- timer_setup(&dev->raw->edge_handle, edge_handle, 0);
+ spin_lock_init(&dev->raw->edge_spinlock);
+ timer_setup(&dev->raw->edge_handle, ir_raw_edge_handle, 0);
INIT_KFIFO(dev->raw->kfifo);
return 0;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 1db8d38fed7c..b67be33bd62f 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -68,6 +68,8 @@ static const struct {
.scancode_bits = 0x1fff, .repeat_period = 250 },
[RC_PROTO_XMP] = { .name = "xmp", .repeat_period = 250 },
[RC_PROTO_CEC] = { .name = "cec", .repeat_period = 550 },
+ [RC_PROTO_IMON] = { .name = "imon",
+ .scancode_bits = 0x7fffffff, .repeat_period = 250 },
};
/* Used to keep track of known keymaps */
@@ -156,6 +158,7 @@ static struct rc_map_list empty_map = {
/**
* ir_create_table() - initializes a scancode table
+ * @dev: the rc_dev device
* @rc_map: the rc_map to initialize
* @name: name to assign to the table
* @rc_proto: ir type to assign to the new table
@@ -166,7 +169,7 @@ static struct rc_map_list empty_map = {
*
* return: zero on success or a negative error code
*/
-static int ir_create_table(struct rc_map *rc_map,
+static int ir_create_table(struct rc_dev *dev, struct rc_map *rc_map,
const char *name, u64 rc_proto, size_t size)
{
rc_map->name = kstrdup(name, GFP_KERNEL);
@@ -182,8 +185,8 @@ static int ir_create_table(struct rc_map *rc_map,
return -ENOMEM;
}
- IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
- rc_map->size, rc_map->alloc);
+ dev_dbg(&dev->dev, "Allocated space for %u keycode entries (%u bytes)\n",
+ rc_map->size, rc_map->alloc);
return 0;
}
@@ -205,6 +208,7 @@ static void ir_free_table(struct rc_map *rc_map)
/**
* ir_resize_table() - resizes a scancode table if necessary
+ * @dev: the rc_dev device
* @rc_map: the rc_map to resize
* @gfp_flags: gfp flags to use when allocating memory
*
@@ -213,7 +217,8 @@ static void ir_free_table(struct rc_map *rc_map)
*
* return: zero on success or a negative error code
*/
-static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
+static int ir_resize_table(struct rc_dev *dev, struct rc_map *rc_map,
+ gfp_t gfp_flags)
{
unsigned int oldalloc = rc_map->alloc;
unsigned int newalloc = oldalloc;
@@ -226,23 +231,21 @@ static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
return -ENOMEM;
newalloc *= 2;
- IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
+ dev_dbg(&dev->dev, "Growing table to %u bytes\n", newalloc);
}
if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
/* Less than 1/3 of entries in use -> shrink keytable */
newalloc /= 2;
- IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
+ dev_dbg(&dev->dev, "Shrinking table to %u bytes\n", newalloc);
}
if (newalloc == oldalloc)
return 0;
newscan = kmalloc(newalloc, gfp_flags);
- if (!newscan) {
- IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
+ if (!newscan)
return -ENOMEM;
- }
memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table));
rc_map->scan = newscan;
@@ -275,16 +278,16 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
/* Did the user wish to remove the mapping? */
if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
- IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
- index, rc_map->scan[index].scancode);
+ dev_dbg(&dev->dev, "#%d: Deleting scan 0x%04x\n",
+ index, rc_map->scan[index].scancode);
rc_map->len--;
memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
(rc_map->len - index) * sizeof(struct rc_map_table));
} else {
- IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n",
- index,
- old_keycode == KEY_RESERVED ? "New" : "Replacing",
- rc_map->scan[index].scancode, new_keycode);
+ dev_dbg(&dev->dev, "#%d: %s scan 0x%04x with key 0x%04x\n",
+ index,
+ old_keycode == KEY_RESERVED ? "New" : "Replacing",
+ rc_map->scan[index].scancode, new_keycode);
rc_map->scan[index].keycode = new_keycode;
__set_bit(new_keycode, dev->input_dev->keybit);
}
@@ -301,7 +304,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
}
/* Possibly shrink the keytable, failure is not a problem */
- ir_resize_table(rc_map, GFP_ATOMIC);
+ ir_resize_table(dev, rc_map, GFP_ATOMIC);
}
return old_keycode;
@@ -352,7 +355,7 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev,
/* No previous mapping found, we might need to grow the table */
if (rc_map->size == rc_map->len) {
- if (!resize || ir_resize_table(rc_map, GFP_ATOMIC))
+ if (!resize || ir_resize_table(dev, rc_map, GFP_ATOMIC))
return -1U;
}
@@ -431,8 +434,8 @@ static int ir_setkeytable(struct rc_dev *dev,
unsigned int i, index;
int rc;
- rc = ir_create_table(rc_map, from->name,
- from->rc_proto, from->size);
+ rc = ir_create_table(dev, rc_map, from->name, from->rc_proto,
+ from->size);
if (rc)
return rc;
@@ -576,8 +579,8 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode)
spin_unlock_irqrestore(&rc_map->lock, flags);
if (keycode != KEY_RESERVED)
- IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
- dev->device_name, scancode, keycode);
+ dev_dbg(&dev->dev, "%s: scancode 0x%04x keycode 0x%02x\n",
+ dev->device_name, scancode, keycode);
return keycode;
}
@@ -596,7 +599,7 @@ static void ir_do_keyup(struct rc_dev *dev, bool sync)
if (!dev->keypressed)
return;
- IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
+ dev_dbg(&dev->dev, "keyup key 0x%04x\n", dev->last_keycode);
del_timer(&dev->timer_repeat);
input_report_key(dev->input_dev, dev->last_keycode, 0);
led_trigger_event(led_feedback, LED_OFF);
@@ -751,8 +754,8 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,
/* Register a keypress */
dev->keypressed = true;
- IR_dprintk(1, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n",
- dev->device_name, keycode, protocol, scancode);
+ dev_dbg(&dev->dev, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n",
+ dev->device_name, keycode, protocol, scancode);
input_report_key(dev->input_dev, keycode, 1);
led_trigger_event(led_feedback, LED_FULL);
@@ -1003,6 +1006,7 @@ static const struct {
RC_PROTO_BIT_MCIR2_MSE, "mce_kbd", "ir-mce_kbd-decoder" },
{ RC_PROTO_BIT_XMP, "xmp", "ir-xmp-decoder" },
{ RC_PROTO_BIT_CEC, "cec", NULL },
+ { RC_PROTO_BIT_IMON, "imon", "ir-imon-decoder" },
};
/**
@@ -1056,8 +1060,8 @@ static ssize_t show_protocols(struct device *device,
mutex_unlock(&dev->lock);
- IR_dprintk(1, "%s: allowed - 0x%llx, enabled - 0x%llx\n",
- __func__, (long long)allowed, (long long)enabled);
+ dev_dbg(&dev->dev, "%s: allowed - 0x%llx, enabled - 0x%llx\n",
+ __func__, (long long)allowed, (long long)enabled);
for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
if (allowed & enabled & proto_names[i].type)
@@ -1083,6 +1087,7 @@ static ssize_t show_protocols(struct device *device,
/**
* parse_protocol_change() - parses a protocol change request
+ * @dev: rc_dev device
* @protocols: pointer to the bitmask of current protocols
* @buf: pointer to the buffer with a list of changes
*
@@ -1092,7 +1097,8 @@ static ssize_t show_protocols(struct device *device,
* Writing "none" will disable all protocols.
* Returns the number of changes performed or a negative error code.
*/
-static int parse_protocol_change(u64 *protocols, const char *buf)
+static int parse_protocol_change(struct rc_dev *dev, u64 *protocols,
+ const char *buf)
{
const char *tmp;
unsigned count = 0;
@@ -1128,7 +1134,8 @@ static int parse_protocol_change(u64 *protocols, const char *buf)
if (!strcasecmp(tmp, "lirc"))
mask = 0;
else {
- IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
+ dev_dbg(&dev->dev, "Unknown protocol: '%s'\n",
+ tmp);
return -EINVAL;
}
}
@@ -1144,7 +1151,7 @@ static int parse_protocol_change(u64 *protocols, const char *buf)
}
if (!count) {
- IR_dprintk(1, "Protocol not specified\n");
+ dev_dbg(&dev->dev, "Protocol not specified\n");
return -EINVAL;
}
@@ -1217,12 +1224,12 @@ static ssize_t store_protocols(struct device *device,
u64 old_protocols, new_protocols;
ssize_t rc;
- IR_dprintk(1, "Normal protocol change requested\n");
+ dev_dbg(&dev->dev, "Normal protocol change requested\n");
current_protocols = &dev->enabled_protocols;
filter = &dev->scancode_filter;
if (!dev->change_protocol) {
- IR_dprintk(1, "Protocol switching not supported\n");
+ dev_dbg(&dev->dev, "Protocol switching not supported\n");
return -EINVAL;
}
@@ -1230,14 +1237,14 @@ static ssize_t store_protocols(struct device *device,
old_protocols = *current_protocols;
new_protocols = old_protocols;
- rc = parse_protocol_change(&new_protocols, buf);
+ rc = parse_protocol_change(dev, &new_protocols, buf);
if (rc < 0)
goto out;
rc = dev->change_protocol(dev, &new_protocols);
if (rc < 0) {
- IR_dprintk(1, "Error setting protocols to 0x%llx\n",
- (long long)new_protocols);
+ dev_dbg(&dev->dev, "Error setting protocols to 0x%llx\n",
+ (long long)new_protocols);
goto out;
}
@@ -1246,8 +1253,8 @@ static ssize_t store_protocols(struct device *device,
if (new_protocols != old_protocols) {
*current_protocols = new_protocols;
- IR_dprintk(1, "Protocols changed to 0x%llx\n",
- (long long)new_protocols);
+ dev_dbg(&dev->dev, "Protocols changed to 0x%llx\n",
+ (long long)new_protocols);
}
/*
@@ -1435,8 +1442,8 @@ static ssize_t show_wakeup_protocols(struct device *device,
mutex_unlock(&dev->lock);
- IR_dprintk(1, "%s: allowed - 0x%llx, enabled - %d\n",
- __func__, (long long)allowed, enabled);
+ dev_dbg(&dev->dev, "%s: allowed - 0x%llx, enabled - %d\n",
+ __func__, (long long)allowed, enabled);
for (i = 0; i < ARRAY_SIZE(protocols); i++) {
if (allowed & (1ULL << i)) {
@@ -1511,7 +1518,7 @@ static ssize_t store_wakeup_protocols(struct device *device,
if (dev->wakeup_protocol != protocol) {
dev->wakeup_protocol = protocol;
- IR_dprintk(1, "Wakeup protocol changed to %d\n", protocol);
+ dev_dbg(&dev->dev, "Wakeup protocol changed to %d\n", protocol);
if (protocol == RC_PROTO_RC6_MCE)
dev->scancode_wakeup_filter.data = 0x800f0000;
@@ -1874,9 +1881,8 @@ int rc_register_device(struct rc_dev *dev)
dev->registered = true;
- IR_dprintk(1, "Registered rc%u (driver: %s)\n",
- dev->minor,
- dev->driver_name ? dev->driver_name : "unknown");
+ dev_dbg(&dev->dev, "Registered rc%u (driver: %s)\n", dev->minor,
+ dev->driver_name ? dev->driver_name : "unknown");
return 0;
@@ -1929,12 +1935,12 @@ void rc_unregister_device(struct rc_dev *dev)
if (!dev)
return;
- del_timer_sync(&dev->timer_keyup);
- del_timer_sync(&dev->timer_repeat);
-
if (dev->driver_type == RC_DRIVER_IR_RAW)
ir_raw_event_unregister(dev);
+ del_timer_sync(&dev->timer_keyup);
+ del_timer_sync(&dev->timer_repeat);
+
rc_free_rx_device(dev);
mutex_lock(&dev->lock);
@@ -1994,9 +2000,5 @@ static void __exit rc_core_exit(void)
subsys_initcall(rc_core_init);
module_exit(rc_core_exit);
-int rc_core_debug; /* ir_debug level (0,1,2) */
-EXPORT_SYMBOL_GPL(rc_core_debug);
-module_param_named(debug, rc_core_debug, int, 0644);
-
MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index 97f367b446c4..f500cea228a9 100644
--- a/drivers/media/rc/sunxi-cir.c
+++ b/drivers/media/rc/sunxi-cir.c
@@ -72,12 +72,8 @@
/* CIR_REG register idle threshold */
#define REG_CIR_ITHR(val) (((val) << 8) & (GENMASK(15, 8)))
-/* Required frequency for IR0 or IR1 clock in CIR mode */
+/* Required frequency for IR0 or IR1 clock in CIR mode (default) */
#define SUNXI_IR_BASE_CLK 8000000
-/* Frequency after IR internal divider */
-#define SUNXI_IR_CLK (SUNXI_IR_BASE_CLK / 64)
-/* Sample period in ns */
-#define SUNXI_IR_SAMPLE (1000000000ul / SUNXI_IR_CLK)
/* Noise threshold in samples */
#define SUNXI_IR_RXNOISE 1
/* Idle Threshold in samples */
@@ -122,7 +118,8 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id)
/* for each bit in fifo */
dt = readb(ir->base + SUNXI_IR_RXFIFO_REG);
rawir.pulse = (dt & 0x80) != 0;
- rawir.duration = ((dt & 0x7f) + 1) * SUNXI_IR_SAMPLE;
+ rawir.duration = ((dt & 0x7f) + 1) *
+ ir->rc->rx_resolution;
ir_raw_event_store_with_filter(ir->rc, &rawir);
}
}
@@ -148,6 +145,7 @@ static int sunxi_ir_probe(struct platform_device *pdev)
struct device_node *dn = dev->of_node;
struct resource *res;
struct sunxi_ir *ir;
+ u32 b_clk_freq = SUNXI_IR_BASE_CLK;
ir = devm_kzalloc(dev, sizeof(struct sunxi_ir), GFP_KERNEL);
if (!ir)
@@ -172,6 +170,9 @@ static int sunxi_ir_probe(struct platform_device *pdev)
return PTR_ERR(ir->clk);
}
+ /* Base clock frequency (optional) */
+ of_property_read_u32(dn, "clock-frequency", &b_clk_freq);
+
/* Reset (optional) */
ir->rst = devm_reset_control_get_optional_exclusive(dev, NULL);
if (IS_ERR(ir->rst))
@@ -180,11 +181,12 @@ static int sunxi_ir_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = clk_set_rate(ir->clk, SUNXI_IR_BASE_CLK);
+ ret = clk_set_rate(ir->clk, b_clk_freq);
if (ret) {
dev_err(dev, "set ir base clock failed!\n");
goto exit_reset_assert;
}
+ dev_dbg(dev, "set base clock frequency to %d Hz.\n", b_clk_freq);
if (clk_prepare_enable(ir->apb_clk)) {
dev_err(dev, "try to enable apb_ir_clk failed\n");
@@ -225,7 +227,8 @@ static int sunxi_ir_probe(struct platform_device *pdev)
ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY;
ir->rc->dev.parent = dev;
ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
- ir->rc->rx_resolution = SUNXI_IR_SAMPLE;
+ /* Frequency after IR internal divider with sample period in ns */
+ ir->rc->rx_resolution = (1000000000ul / (b_clk_freq / 64));
ir->rc->timeout = MS_TO_NS(SUNXI_IR_TIMEOUT);
ir->rc->driver_name = SUNXI_IR_DEV;
diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig
index a21f5a39a440..b07ac86fc53c 100644
--- a/drivers/media/spi/Kconfig
+++ b/drivers/media/spi/Kconfig
@@ -12,3 +12,17 @@ config VIDEO_GS1662
endmenu
endif
+
+if SPI
+menu "Media SPI Adapters"
+
+config CXD2880_SPI_DRV
+ tristate "Sony CXD2880 SPI support"
+ depends on DVB_CORE && SPI
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Choose if you would like to have SPI interface support for Sony CXD2880.
+
+endmenu
+
+endif
diff --git a/drivers/media/spi/Makefile b/drivers/media/spi/Makefile
index ea64013d16cc..9e536777a330 100644
--- a/drivers/media/spi/Makefile
+++ b/drivers/media/spi/Makefile
@@ -1 +1,6 @@
obj-$(CONFIG_VIDEO_GS1662) += gs1662.o
+obj-$(CONFIG_CXD2880_SPI_DRV) += cxd2880-spi.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+ccflags-y += -Idrivers/media/dvb-frontends/cxd2880
diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c
new file mode 100644
index 000000000000..4df3bd312f48
--- /dev/null
+++ b/drivers/media/spi/cxd2880-spi.c
@@ -0,0 +1,670 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cxd2880-spi.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI adapter
+ *
+ * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
+
+#include <linux/spi/spi.h>
+#include <linux/ktime.h>
+
+#include <media/dvb_demux.h>
+#include <media/dmxdev.h>
+#include <media/dvb_frontend.h>
+#include "cxd2880.h"
+
+#define CXD2880_MAX_FILTER_SIZE 32
+#define BURST_WRITE_MAX 128
+#define MAX_TRANS_PKT 300
+
+struct cxd2880_ts_buf_info {
+ u8 read_ready:1;
+ u8 almost_full:1;
+ u8 almost_empty:1;
+ u8 overflow:1;
+ u8 underflow:1;
+ u16 pkt_num;
+};
+
+struct cxd2880_pid_config {
+ u8 is_enable;
+ u16 pid;
+};
+
+struct cxd2880_pid_filter_config {
+ u8 is_negative;
+ struct cxd2880_pid_config pid_config[CXD2880_MAX_FILTER_SIZE];
+};
+
+struct cxd2880_dvb_spi {
+ struct dvb_frontend dvb_fe;
+ struct dvb_adapter adapter;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend dmx_fe;
+ struct task_struct *cxd2880_ts_read_thread;
+ struct spi_device *spi;
+ struct mutex spi_mutex; /* For SPI access exclusive control */
+ int feed_count;
+ int all_pid_feed_count;
+ u8 *ts_buf;
+ struct cxd2880_pid_filter_config filter_config;
+};
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int cxd2880_write_spi(struct spi_device *spi, u8 *data, u32 size)
+{
+ struct spi_message msg;
+ struct spi_transfer tx;
+
+ if (!spi || !data) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ memset(&tx, 0, sizeof(tx));
+ tx.tx_buf = data;
+ tx.len = size;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&tx, &msg);
+
+ return spi_sync(spi, &msg);
+}
+
+static int cxd2880_write_reg(struct spi_device *spi,
+ u8 sub_address, const u8 *data, u32 size)
+{
+ u8 send_data[BURST_WRITE_MAX + 4];
+ const u8 *write_data_top = NULL;
+ int ret = 0;
+
+ if (!spi || !data) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+ if (size > BURST_WRITE_MAX) {
+ pr_err("data size > WRITE_MAX\n");
+ return -EINVAL;
+ }
+
+ if (sub_address + size > 0x100) {
+ pr_err("out of range\n");
+ return -EINVAL;
+ }
+
+ send_data[0] = 0x0e;
+ write_data_top = data;
+
+ while (size > 0) {
+ send_data[1] = sub_address;
+ if (size > 255)
+ send_data[2] = 255;
+ else
+ send_data[2] = (u8)size;
+
+ memcpy(&send_data[3], write_data_top, send_data[2]);
+
+ ret = cxd2880_write_spi(spi, send_data, send_data[2] + 3);
+ if (ret) {
+ pr_err("write spi failed %d\n", ret);
+ break;
+ }
+ sub_address += send_data[2];
+ write_data_top += send_data[2];
+ size -= send_data[2];
+ }
+
+ return ret;
+}
+
+static int cxd2880_spi_read_ts(struct spi_device *spi,
+ u8 *read_data,
+ u32 packet_num)
+{
+ int ret;
+ u8 data[3];
+ struct spi_message message;
+ struct spi_transfer transfer[2];
+
+ if (!spi || !read_data || !packet_num) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+ if (packet_num > 0xffff) {
+ pr_err("packet num > 0xffff\n");
+ return -EINVAL;
+ }
+
+ data[0] = 0x10;
+ data[1] = packet_num >> 8;
+ data[2] = packet_num;
+
+ spi_message_init(&message);
+ memset(transfer, 0, sizeof(transfer));
+
+ transfer[0].len = 3;
+ transfer[0].tx_buf = data;
+ spi_message_add_tail(&transfer[0], &message);
+ transfer[1].len = packet_num * 188;
+ transfer[1].rx_buf = read_data;
+ spi_message_add_tail(&transfer[1], &message);
+
+ ret = spi_sync(spi, &message);
+ if (ret)
+ pr_err("spi_write_then_read failed\n");
+
+ return ret;
+}
+
+static int cxd2880_spi_read_ts_buffer_info(struct spi_device *spi,
+ struct cxd2880_ts_buf_info *info)
+{
+ u8 send_data = 0x20;
+ u8 recv_data[2];
+ int ret;
+
+ if (!spi || !info) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ ret = spi_write_then_read(spi, &send_data, 1,
+ recv_data, sizeof(recv_data));
+ if (ret)
+ pr_err("spi_write_then_read failed\n");
+
+ info->read_ready = (recv_data[0] & 0x80) ? 1 : 0;
+ info->almost_full = (recv_data[0] & 0x40) ? 1 : 0;
+ info->almost_empty = (recv_data[0] & 0x20) ? 1 : 0;
+ info->overflow = (recv_data[0] & 0x10) ? 1 : 0;
+ info->underflow = (recv_data[0] & 0x08) ? 1 : 0;
+ info->pkt_num = ((recv_data[0] & 0x07) << 8) | recv_data[1];
+
+ return ret;
+}
+
+static int cxd2880_spi_clear_ts_buffer(struct spi_device *spi)
+{
+ u8 data = 0x03;
+ int ret;
+
+ ret = cxd2880_write_spi(spi, &data, 1);
+
+ if (ret)
+ pr_err("write spi failed\n");
+
+ return ret;
+}
+
+static int cxd2880_set_pid_filter(struct spi_device *spi,
+ struct cxd2880_pid_filter_config *cfg)
+{
+ u8 data[65];
+ int i;
+ u16 pid = 0;
+ int ret;
+
+ if (!spi) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ data[0] = 0x00;
+ ret = cxd2880_write_reg(spi, 0x00, &data[0], 1);
+ if (ret)
+ return ret;
+ if (!cfg) {
+ data[0] = 0x02;
+ ret = cxd2880_write_reg(spi, 0x50, &data[0], 1);
+ } else {
+ data[0] = cfg->is_negative ? 0x01 : 0x00;
+
+ for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
+ pid = cfg->pid_config[i].pid;
+ if (cfg->pid_config[i].is_enable) {
+ data[1 + (i * 2)] = (pid >> 8) | 0x20;
+ data[2 + (i * 2)] = pid & 0xff;
+ } else {
+ data[1 + (i * 2)] = 0x00;
+ data[2 + (i * 2)] = 0x00;
+ }
+ }
+ ret = cxd2880_write_reg(spi, 0x50, data, 65);
+ }
+
+ return ret;
+}
+
+static int cxd2880_update_pid_filter(struct cxd2880_dvb_spi *dvb_spi,
+ struct cxd2880_pid_filter_config *cfg,
+ bool is_all_pid_filter)
+{
+ int ret;
+
+ if (!dvb_spi || !cfg) {
+ pr_err("invalid arg.\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&dvb_spi->spi_mutex);
+ if (is_all_pid_filter) {
+ struct cxd2880_pid_filter_config tmpcfg;
+
+ memset(&tmpcfg, 0, sizeof(tmpcfg));
+ tmpcfg.is_negative = 1;
+ tmpcfg.pid_config[0].is_enable = 1;
+ tmpcfg.pid_config[0].pid = 0x1fff;
+
+ ret = cxd2880_set_pid_filter(dvb_spi->spi, &tmpcfg);
+ } else {
+ ret = cxd2880_set_pid_filter(dvb_spi->spi, cfg);
+ }
+ mutex_unlock(&dvb_spi->spi_mutex);
+
+ if (ret)
+ pr_err("set_pid_filter failed\n");
+
+ return ret;
+}
+
+static int cxd2880_ts_read(void *arg)
+{
+ struct cxd2880_dvb_spi *dvb_spi = NULL;
+ struct cxd2880_ts_buf_info info;
+ ktime_t start;
+ u32 i;
+ int ret;
+
+ dvb_spi = arg;
+ if (!dvb_spi) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ ret = cxd2880_spi_clear_ts_buffer(dvb_spi->spi);
+ if (ret) {
+ pr_err("set_clear_ts_buffer failed\n");
+ return ret;
+ }
+
+ start = ktime_get();
+ while (!kthread_should_stop()) {
+ ret = cxd2880_spi_read_ts_buffer_info(dvb_spi->spi,
+ &info);
+ if (ret) {
+ pr_err("spi_read_ts_buffer_info error\n");
+ return ret;
+ }
+
+ if (info.pkt_num > MAX_TRANS_PKT) {
+ for (i = 0; i < info.pkt_num / MAX_TRANS_PKT; i++) {
+ cxd2880_spi_read_ts(dvb_spi->spi,
+ dvb_spi->ts_buf,
+ MAX_TRANS_PKT);
+ dvb_dmx_swfilter(&dvb_spi->demux,
+ dvb_spi->ts_buf,
+ MAX_TRANS_PKT * 188);
+ }
+ start = ktime_get();
+ } else if ((info.pkt_num > 0) &&
+ (ktime_to_ms(ktime_sub(ktime_get(), start)) >= 500)) {
+ cxd2880_spi_read_ts(dvb_spi->spi,
+ dvb_spi->ts_buf,
+ info.pkt_num);
+ dvb_dmx_swfilter(&dvb_spi->demux,
+ dvb_spi->ts_buf,
+ info.pkt_num * 188);
+ start = ktime_get();
+ } else {
+ usleep_range(10000, 11000);
+ }
+ }
+
+ return 0;
+}
+
+static int cxd2880_start_feed(struct dvb_demux_feed *feed)
+{
+ int ret = 0;
+ int i = 0;
+ struct dvb_demux *demux = NULL;
+ struct cxd2880_dvb_spi *dvb_spi = NULL;
+
+ if (!feed) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ demux = feed->demux;
+ if (!demux) {
+ pr_err("feed->demux is NULL\n");
+ return -EINVAL;
+ }
+ dvb_spi = demux->priv;
+
+ if (dvb_spi->feed_count == CXD2880_MAX_FILTER_SIZE) {
+ pr_err("Exceeded maximum PID count (32).");
+ pr_err("Selected PID cannot be enabled.\n");
+ return -EINVAL;
+ }
+
+ if (feed->pid == 0x2000) {
+ if (dvb_spi->all_pid_feed_count == 0) {
+ ret = cxd2880_update_pid_filter(dvb_spi,
+ &dvb_spi->filter_config,
+ true);
+ if (ret) {
+ pr_err("update pid filter failed\n");
+ return ret;
+ }
+ }
+ dvb_spi->all_pid_feed_count++;
+
+ pr_debug("all PID feed (count = %d)\n",
+ dvb_spi->all_pid_feed_count);
+ } else {
+ struct cxd2880_pid_filter_config cfgtmp;
+
+ cfgtmp = dvb_spi->filter_config;
+
+ for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
+ if (cfgtmp.pid_config[i].is_enable == 0) {
+ cfgtmp.pid_config[i].is_enable = 1;
+ cfgtmp.pid_config[i].pid = feed->pid;
+ pr_debug("store PID %d to #%d\n",
+ feed->pid, i);
+ break;
+ }
+ }
+ if (i == CXD2880_MAX_FILTER_SIZE) {
+ pr_err("PID filter is full. Assumed bug.\n");
+ return -EINVAL;
+ }
+ if (!dvb_spi->all_pid_feed_count)
+ ret = cxd2880_update_pid_filter(dvb_spi,
+ &cfgtmp,
+ false);
+ if (ret)
+ return ret;
+
+ dvb_spi->filter_config = cfgtmp;
+ }
+
+ if (dvb_spi->feed_count == 0) {
+ dvb_spi->ts_buf =
+ kmalloc(MAX_TRANS_PKT * 188,
+ GFP_KERNEL | GFP_DMA);
+ if (!dvb_spi->ts_buf) {
+ pr_err("ts buffer allocate failed\n");
+ memset(&dvb_spi->filter_config, 0,
+ sizeof(dvb_spi->filter_config));
+ dvb_spi->all_pid_feed_count = 0;
+ return -ENOMEM;
+ }
+ dvb_spi->cxd2880_ts_read_thread = kthread_run(cxd2880_ts_read,
+ dvb_spi,
+ "cxd2880_ts_read");
+ if (IS_ERR(dvb_spi->cxd2880_ts_read_thread)) {
+ pr_err("kthread_run failed/\n");
+ kfree(dvb_spi->ts_buf);
+ dvb_spi->ts_buf = NULL;
+ memset(&dvb_spi->filter_config, 0,
+ sizeof(dvb_spi->filter_config));
+ dvb_spi->all_pid_feed_count = 0;
+ return PTR_ERR(dvb_spi->cxd2880_ts_read_thread);
+ }
+ }
+
+ dvb_spi->feed_count++;
+
+ pr_debug("start feed (count %d)\n", dvb_spi->feed_count);
+ return 0;
+}
+
+static int cxd2880_stop_feed(struct dvb_demux_feed *feed)
+{
+ int i = 0;
+ int ret;
+ struct dvb_demux *demux = NULL;
+ struct cxd2880_dvb_spi *dvb_spi = NULL;
+
+ if (!feed) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ demux = feed->demux;
+ if (!demux) {
+ pr_err("feed->demux is NULL\n");
+ return -EINVAL;
+ }
+ dvb_spi = demux->priv;
+
+ if (!dvb_spi->feed_count) {
+ pr_err("no feed is started\n");
+ return -EINVAL;
+ }
+
+ if (feed->pid == 0x2000) {
+ /*
+ * Special PID case.
+ * Number of 0x2000 feed request was stored
+ * in dvb_spi->all_pid_feed_count.
+ */
+ if (dvb_spi->all_pid_feed_count <= 0) {
+ pr_err("PID %d not found.\n", feed->pid);
+ return -EINVAL;
+ }
+ dvb_spi->all_pid_feed_count--;
+ } else {
+ struct cxd2880_pid_filter_config cfgtmp;
+
+ cfgtmp = dvb_spi->filter_config;
+
+ for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
+ if (feed->pid == cfgtmp.pid_config[i].pid &&
+ cfgtmp.pid_config[i].is_enable != 0) {
+ cfgtmp.pid_config[i].is_enable = 0;
+ cfgtmp.pid_config[i].pid = 0;
+ pr_debug("removed PID %d from #%d\n",
+ feed->pid, i);
+ break;
+ }
+ }
+ dvb_spi->filter_config = cfgtmp;
+
+ if (i == CXD2880_MAX_FILTER_SIZE) {
+ pr_err("PID %d not found\n", feed->pid);
+ return -EINVAL;
+ }
+ }
+
+ ret = cxd2880_update_pid_filter(dvb_spi,
+ &dvb_spi->filter_config,
+ dvb_spi->all_pid_feed_count > 0);
+ dvb_spi->feed_count--;
+
+ if (dvb_spi->feed_count == 0) {
+ int ret_stop = 0;
+
+ ret_stop = kthread_stop(dvb_spi->cxd2880_ts_read_thread);
+ if (ret_stop) {
+ pr_err("'kthread_stop failed. (%d)\n", ret_stop);
+ ret = ret_stop;
+ }
+ kfree(dvb_spi->ts_buf);
+ dvb_spi->ts_buf = NULL;
+ }
+
+ pr_debug("stop feed ok.(count %d)\n", dvb_spi->feed_count);
+
+ return ret;
+}
+
+static const struct of_device_id cxd2880_spi_of_match[] = {
+ { .compatible = "sony,cxd2880" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, cxd2880_spi_of_match);
+
+static int
+cxd2880_spi_probe(struct spi_device *spi)
+{
+ int ret;
+ struct cxd2880_dvb_spi *dvb_spi = NULL;
+ struct cxd2880_config config;
+
+ if (!spi) {
+ pr_err("invalid arg.\n");
+ return -EINVAL;
+ }
+
+ dvb_spi = kzalloc(sizeof(struct cxd2880_dvb_spi), GFP_KERNEL);
+ if (!dvb_spi)
+ return -ENOMEM;
+
+ dvb_spi->spi = spi;
+ mutex_init(&dvb_spi->spi_mutex);
+ dev_set_drvdata(&spi->dev, dvb_spi);
+ config.spi = spi;
+ config.spi_mutex = &dvb_spi->spi_mutex;
+
+ ret = dvb_register_adapter(&dvb_spi->adapter,
+ "CXD2880",
+ THIS_MODULE,
+ &spi->dev,
+ adapter_nr);
+ if (ret < 0) {
+ pr_err("dvb_register_adapter() failed\n");
+ goto fail_adapter;
+ }
+
+ if (!dvb_attach(cxd2880_attach, &dvb_spi->dvb_fe, &config)) {
+ pr_err("cxd2880_attach failed\n");
+ goto fail_attach;
+ }
+
+ ret = dvb_register_frontend(&dvb_spi->adapter,
+ &dvb_spi->dvb_fe);
+ if (ret < 0) {
+ pr_err("dvb_register_frontend() failed\n");
+ goto fail_frontend;
+ }
+
+ dvb_spi->demux.dmx.capabilities = DMX_TS_FILTERING;
+ dvb_spi->demux.priv = dvb_spi;
+ dvb_spi->demux.filternum = CXD2880_MAX_FILTER_SIZE;
+ dvb_spi->demux.feednum = CXD2880_MAX_FILTER_SIZE;
+ dvb_spi->demux.start_feed = cxd2880_start_feed;
+ dvb_spi->demux.stop_feed = cxd2880_stop_feed;
+
+ ret = dvb_dmx_init(&dvb_spi->demux);
+ if (ret < 0) {
+ pr_err("dvb_dmx_init() failed\n");
+ goto fail_dmx;
+ }
+
+ dvb_spi->dmxdev.filternum = CXD2880_MAX_FILTER_SIZE;
+ dvb_spi->dmxdev.demux = &dvb_spi->demux.dmx;
+ dvb_spi->dmxdev.capabilities = 0;
+ ret = dvb_dmxdev_init(&dvb_spi->dmxdev,
+ &dvb_spi->adapter);
+ if (ret < 0) {
+ pr_err("dvb_dmxdev_init() failed\n");
+ goto fail_dmxdev;
+ }
+
+ dvb_spi->dmx_fe.source = DMX_FRONTEND_0;
+ ret = dvb_spi->demux.dmx.add_frontend(&dvb_spi->demux.dmx,
+ &dvb_spi->dmx_fe);
+ if (ret < 0) {
+ pr_err("add_frontend() failed\n");
+ goto fail_dmx_fe;
+ }
+
+ ret = dvb_spi->demux.dmx.connect_frontend(&dvb_spi->demux.dmx,
+ &dvb_spi->dmx_fe);
+ if (ret < 0) {
+ pr_err("dvb_register_frontend() failed\n");
+ goto fail_fe_conn;
+ }
+
+ pr_info("Sony CXD2880 has successfully attached.\n");
+
+ return 0;
+
+fail_fe_conn:
+ dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx,
+ &dvb_spi->dmx_fe);
+fail_dmx_fe:
+ dvb_dmxdev_release(&dvb_spi->dmxdev);
+fail_dmxdev:
+ dvb_dmx_release(&dvb_spi->demux);
+fail_dmx:
+ dvb_unregister_frontend(&dvb_spi->dvb_fe);
+fail_frontend:
+ dvb_frontend_detach(&dvb_spi->dvb_fe);
+fail_attach:
+ dvb_unregister_adapter(&dvb_spi->adapter);
+fail_adapter:
+ kfree(dvb_spi);
+ return ret;
+}
+
+static int
+cxd2880_spi_remove(struct spi_device *spi)
+{
+ struct cxd2880_dvb_spi *dvb_spi;
+
+ if (!spi) {
+ pr_err("invalid arg\n");
+ return -EINVAL;
+ }
+
+ dvb_spi = dev_get_drvdata(&spi->dev);
+
+ if (!dvb_spi) {
+ pr_err("failed\n");
+ return -EINVAL;
+ }
+ dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx,
+ &dvb_spi->dmx_fe);
+ dvb_dmxdev_release(&dvb_spi->dmxdev);
+ dvb_dmx_release(&dvb_spi->demux);
+ dvb_unregister_frontend(&dvb_spi->dvb_fe);
+ dvb_frontend_detach(&dvb_spi->dvb_fe);
+ dvb_unregister_adapter(&dvb_spi->adapter);
+
+ kfree(dvb_spi);
+ pr_info("cxd2880_spi remove ok.\n");
+
+ return 0;
+}
+
+static const struct spi_device_id cxd2880_spi_id[] = {
+ { "cxd2880", 0 },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, cxd2880_spi_id);
+
+static struct spi_driver cxd2880_spi_driver = {
+ .driver = {
+ .name = "cxd2880",
+ .of_match_table = cxd2880_spi_of_match,
+ },
+ .id_table = cxd2880_spi_id,
+ .probe = cxd2880_spi_probe,
+ .remove = cxd2880_spi_remove,
+};
+module_spi_driver(cxd2880_spi_driver);
+
+MODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver SPI adapter");
+MODULE_AUTHOR("Sony Semiconductor Solutions Corporation");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c
index 564a000f503e..b5b9d87ba75c 100644
--- a/drivers/media/tuners/e4000.c
+++ b/drivers/media/tuners/e4000.c
@@ -293,28 +293,18 @@ static inline struct e4000_dev *e4000_subdev_to_dev(struct v4l2_subdev *sd)
return container_of(sd, struct e4000_dev, sd);
}
-static int e4000_s_power(struct v4l2_subdev *sd, int on)
+static int e4000_standby(struct v4l2_subdev *sd)
{
struct e4000_dev *dev = e4000_subdev_to_dev(sd);
- struct i2c_client *client = dev->client;
int ret;
- dev_dbg(&client->dev, "on=%d\n", on);
-
- if (on)
- ret = e4000_init(dev);
- else
- ret = e4000_sleep(dev);
+ ret = e4000_sleep(dev);
if (ret)
return ret;
return e4000_set_params(dev);
}
-static const struct v4l2_subdev_core_ops e4000_subdev_core_ops = {
- .s_power = e4000_s_power,
-};
-
static int e4000_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
{
struct e4000_dev *dev = e4000_subdev_to_dev(sd);
@@ -382,6 +372,7 @@ static int e4000_enum_freq_bands(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_tuner_ops e4000_subdev_tuner_ops = {
+ .standby = e4000_standby,
.g_tuner = e4000_g_tuner,
.s_tuner = e4000_s_tuner,
.g_frequency = e4000_g_frequency,
@@ -390,7 +381,6 @@ static const struct v4l2_subdev_tuner_ops e4000_subdev_tuner_ops = {
};
static const struct v4l2_subdev_ops e4000_subdev_ops = {
- .core = &e4000_subdev_core_ops,
.tuner = &e4000_subdev_tuner_ops,
};
diff --git a/drivers/media/tuners/fc2580.c b/drivers/media/tuners/fc2580.c
index f4d4665de168..743184ae0d26 100644
--- a/drivers/media/tuners/fc2580.c
+++ b/drivers/media/tuners/fc2580.c
@@ -386,28 +386,18 @@ static inline struct fc2580_dev *fc2580_subdev_to_dev(struct v4l2_subdev *sd)
return container_of(sd, struct fc2580_dev, subdev);
}
-static int fc2580_s_power(struct v4l2_subdev *sd, int on)
+static int fc2580_standby(struct v4l2_subdev *sd)
{
struct fc2580_dev *dev = fc2580_subdev_to_dev(sd);
- struct i2c_client *client = dev->client;
int ret;
- dev_dbg(&client->dev, "on=%d\n", on);
-
- if (on)
- ret = fc2580_init(dev);
- else
- ret = fc2580_sleep(dev);
+ ret = fc2580_sleep(dev);
if (ret)
return ret;
return fc2580_set_params(dev);
}
-static const struct v4l2_subdev_core_ops fc2580_subdev_core_ops = {
- .s_power = fc2580_s_power,
-};
-
static int fc2580_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
{
struct fc2580_dev *dev = fc2580_subdev_to_dev(sd);
@@ -475,6 +465,7 @@ static int fc2580_enum_freq_bands(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_tuner_ops fc2580_subdev_tuner_ops = {
+ .standby = fc2580_standby,
.g_tuner = fc2580_g_tuner,
.s_tuner = fc2580_s_tuner,
.g_frequency = fc2580_g_frequency,
@@ -483,7 +474,6 @@ static const struct v4l2_subdev_tuner_ops fc2580_subdev_tuner_ops = {
};
static const struct v4l2_subdev_ops fc2580_subdev_ops = {
- .core = &fc2580_subdev_core_ops,
.tuner = &fc2580_subdev_tuner_ops,
};
diff --git a/drivers/media/tuners/msi001.c b/drivers/media/tuners/msi001.c
index 3a12ef35682b..5de6ed728708 100644
--- a/drivers/media/tuners/msi001.c
+++ b/drivers/media/tuners/msi001.c
@@ -291,26 +291,13 @@ err:
return ret;
}
-static int msi001_s_power(struct v4l2_subdev *sd, int on)
+static int msi001_standby(struct v4l2_subdev *sd)
{
struct msi001_dev *dev = sd_to_msi001_dev(sd);
- struct spi_device *spi = dev->spi;
- int ret;
-
- dev_dbg(&spi->dev, "on=%d\n", on);
-
- if (on)
- ret = 0;
- else
- ret = msi001_wreg(dev, 0x000000);
- return ret;
+ return msi001_wreg(dev, 0x000000);
}
-static const struct v4l2_subdev_core_ops msi001_core_ops = {
- .s_power = msi001_s_power,
-};
-
static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
{
struct msi001_dev *dev = sd_to_msi001_dev(sd);
@@ -386,6 +373,7 @@ static int msi001_enum_freq_bands(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_tuner_ops msi001_tuner_ops = {
+ .standby = msi001_standby,
.g_tuner = msi001_g_tuner,
.s_tuner = msi001_s_tuner,
.g_frequency = msi001_g_frequency,
@@ -394,7 +382,6 @@ static const struct v4l2_subdev_tuner_ops msi001_tuner_ops = {
};
static const struct v4l2_subdev_ops msi001_ops = {
- .core = &msi001_core_ops,
.tuner = &msi001_tuner_ops,
};
diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig
index bfaa806633df..65fc067eb864 100644
--- a/drivers/media/usb/au0828/Kconfig
+++ b/drivers/media/usb/au0828/Kconfig
@@ -4,7 +4,7 @@ config VIDEO_AU0828
depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2
select I2C_ALGOBIT
select VIDEO_TVEEPROM
- select VIDEOBUF2_VMALLOC
+ select VIDEOBUF2_VMALLOC if VIDEO_V4L2
select DVB_AU8522_DTV if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
@@ -18,7 +18,8 @@ config VIDEO_AU0828
config VIDEO_AU0828_V4L2
bool "Auvitek AU0828 v4l2 analog video support"
- depends on VIDEO_AU0828 && VIDEO_V4L2
+ depends on VIDEO_AU0828
+ depends on VIDEO_V4L2=y || VIDEO_V4L2=VIDEO_AU0828
select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_TUNER
default y
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index c765d546114d..964cd7bcdd2c 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -1091,8 +1091,8 @@ static int au0828_v4l2_close(struct file *filp)
*/
ret = v4l_enable_media_source(vdev);
if (ret == 0)
- v4l2_device_call_all(&dev->v4l2_dev, 0, core,
- s_power, 0);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner,
+ standby);
dev->std_set_in_tuner_core = 0;
/* When close the device, set the usb intf0 into alt0 to free
diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c
index f3a1e5b1e57c..b51fc372ca25 100644
--- a/drivers/media/usb/cpia2/cpia2_usb.c
+++ b/drivers/media/usb/cpia2/cpia2_usb.c
@@ -910,9 +910,6 @@ static void cpia2_usb_disconnect(struct usb_interface *intf)
wake_up_interruptible(&cam->wq_stream);
}
- DBG("Releasing interface\n");
- usb_driver_release_interface(&cpia2_driver, intf);
-
LOG("CPiA2 camera disconnected.\n");
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index f9ec7fedcd5b..c76b2101193c 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -922,6 +922,85 @@ struct cx231xx_board cx231xx_boards[] = {
.gpio = NULL,
} },
},
+ [CX231XX_BOARD_HAUPPAUGE_935C] = {
+ .name = "Hauppauge WinTV-HVR-935C",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = 0x60,
+ .tuner_gpio = RDE250_XCV_TUNER,
+ .tuner_sif_gpio = 0x05,
+ .tuner_scl_gpio = 0x1a,
+ .tuner_sda_gpio = 0x1b,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x0c,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = I2C_1_MUX_3,
+ .demod_i2c_master = I2C_1_MUX_3,
+ .has_dvb = 1,
+ .demod_addr = 0x64, /* 0xc8 >> 1 */
+ .norm = V4L2_STD_PAL,
+
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ } },
+ },
+ [CX231XX_BOARD_HAUPPAUGE_975] = {
+ .name = "Hauppauge WinTV-HVR-975",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = 0x60,
+ .tuner_gpio = RDE250_XCV_TUNER,
+ .tuner_sif_gpio = 0x05,
+ .tuner_scl_gpio = 0x1a,
+ .tuner_sda_gpio = 0x1b,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x0c,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = I2C_1_MUX_3,
+ .demod_i2c_master = I2C_1_MUX_3,
+ .has_dvb = 1,
+ .demod_addr = 0x59, /* 0xb2 >> 1 */
+ .demod_addr2 = 0x64, /* 0xc8 >> 1 */
+ .norm = V4L2_STD_ALL,
+
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ } },
+ },
};
const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
@@ -953,6 +1032,10 @@ struct usb_device_id cx231xx_id_table[] = {
.driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
{USB_DEVICE(0x2040, 0xb123),
.driver_info = CX231XX_BOARD_HAUPPAUGE_955Q},
+ {USB_DEVICE(0x2040, 0xb151),
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_935C},
+ {USB_DEVICE(0x2040, 0xb150),
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_975},
{USB_DEVICE(0x2040, 0xb130),
.driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx},
{USB_DEVICE(0x2040, 0xb131),
@@ -1135,7 +1218,7 @@ static void cx231xx_config_tuner(struct cx231xx *dev)
static int read_eeprom(struct cx231xx *dev, struct i2c_client *client,
u8 *eedata, int len)
{
- int ret = 0;
+ int ret;
u8 start_offset = 0;
int len_todo = len;
u8 *eedata_cur = eedata;
@@ -1211,6 +1294,8 @@ void cx231xx_card_setup(struct cx231xx *dev)
case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
case CX231XX_BOARD_HAUPPAUGE_955Q:
+ case CX231XX_BOARD_HAUPPAUGE_935C:
+ case CX231XX_BOARD_HAUPPAUGE_975:
{
struct eeprom {
struct tveeprom tvee;
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index fb5654062b1a..713029420fcf 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -53,9 +53,10 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define CX231XX_DVB_NUM_BUFS 5
#define CX231XX_DVB_MAX_PACKETSIZE 564
#define CX231XX_DVB_MAX_PACKETS 64
+#define CX231XX_DVB_MAX_FRONTENDS 2
struct cx231xx_dvb {
- struct dvb_frontend *frontend;
+ struct dvb_frontend *frontend[CX231XX_DVB_MAX_FRONTENDS];
/* feed count management */
struct mutex lock;
@@ -68,7 +69,7 @@ struct cx231xx_dvb {
struct dmx_frontend fe_hw;
struct dmx_frontend fe_mem;
struct dvb_net net;
- struct i2c_client *i2c_client_demod;
+ struct i2c_client *i2c_client_demod[2];
struct i2c_client *i2c_client_tuner;
};
@@ -79,7 +80,7 @@ static struct s5h1432_config dvico_s5h1432_config = {
.vsb_if = S5H1432_IF_4000,
.inversion = S5H1432_INVERSION_OFF,
.status_mode = S5H1432_DEMODLOCKING,
- .mpeg_timing = S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1432_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = {
@@ -108,7 +109,7 @@ static struct s5h1411_config tda18271_s5h1411_config = {
.qam_if = S5H1411_IF_4000,
.inversion = S5H1411_INVERSION_ON,
.status_mode = S5H1411_DEMODLOCKING,
- .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static struct s5h1411_config xc5000_s5h1411_config = {
.output_mode = S5H1411_SERIAL_OUTPUT,
@@ -117,7 +118,7 @@ static struct s5h1411_config xc5000_s5h1411_config = {
.qam_if = S5H1411_IF_3250,
.inversion = S5H1411_INVERSION_OFF,
.status_mode = S5H1411_DEMODLOCKING,
- .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
};
static struct lgdt3305_config hcw_lgdt3305_config = {
@@ -386,17 +387,17 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
cfg.i2c_adap = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master);
cfg.i2c_addr = addr;
- if (!dev->dvb->frontend) {
+ if (!dev->dvb->frontend[0]) {
dev_err(dev->dev, "%s/2: dvb frontend not attached. Can't attach xc5000\n",
dev->name);
return -EINVAL;
}
- fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg);
+ fe = dvb_attach(xc5000_attach, dev->dvb->frontend[0], &cfg);
if (!fe) {
dev_err(dev->dev, "%s/2: xc5000 attach failed\n", dev->name);
- dvb_frontend_detach(dev->dvb->frontend);
- dev->dvb->frontend = NULL;
+ dvb_frontend_detach(dev->dvb->frontend[0]);
+ dev->dvb->frontend[0] = NULL;
return -EINVAL;
}
@@ -408,9 +409,9 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
{
- if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
+ if (dev->dvb && dev->dvb->frontend[0]) {
- struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
+ struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops;
if (dops->set_analog_params != NULL) {
struct analog_parameters params;
@@ -421,7 +422,7 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
/*params.audmode = ; */
/* Set the analog parameters to set the frequency */
- dops->set_analog_params(dev->dvb->frontend, &params);
+ dops->set_analog_params(dev->dvb->frontend[0], &params);
}
}
@@ -433,15 +434,15 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev)
{
int status = 0;
- if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
+ if (dev->dvb && dev->dvb->frontend[0]) {
- struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
+ struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops;
if (dops->init != NULL && !dev->xc_fw_load_done) {
dev_dbg(dev->dev,
"Reloading firmware for XC5000\n");
- status = dops->init(dev->dvb->frontend);
+ status = dops->init(dev->dvb->frontend[0]);
if (status == 0) {
dev->xc_fw_load_done = 1;
dev_dbg(dev->dev,
@@ -481,17 +482,32 @@ static int register_dvb(struct cx231xx_dvb *dvb,
dvb_register_media_controller(&dvb->adapter, dev->media_dev);
/* Ensure all frontends negotiate bus access */
- dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
+ dvb->frontend[0]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
+ if (dvb->frontend[1])
+ dvb->frontend[1]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
dvb->adapter.priv = dev;
/* register frontend */
- result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+ result = dvb_register_frontend(&dvb->adapter, dvb->frontend[0]);
if (result < 0) {
dev_warn(dev->dev,
"%s: dvb_register_frontend failed (errno = %d)\n",
dev->name, result);
- goto fail_frontend;
+ goto fail_frontend0;
+ }
+
+ if (dvb->frontend[1]) {
+ result = dvb_register_frontend(&dvb->adapter, dvb->frontend[1]);
+ if (result < 0) {
+ dev_warn(dev->dev,
+ "%s: 2nd dvb_register_frontend failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_frontend1;
+ }
+
+ /* MFE lock */
+ dvb->adapter.mfe_shared = 1;
}
/* register demux stuff */
@@ -569,9 +585,14 @@ fail_fe_hw:
fail_dmxdev:
dvb_dmx_release(&dvb->demux);
fail_dmx:
- dvb_unregister_frontend(dvb->frontend);
-fail_frontend:
- dvb_frontend_detach(dvb->frontend);
+ if (dvb->frontend[1])
+ dvb_unregister_frontend(dvb->frontend[1]);
+ dvb_unregister_frontend(dvb->frontend[0]);
+fail_frontend1:
+ if (dvb->frontend[1])
+ dvb_frontend_detach(dvb->frontend[1]);
+fail_frontend0:
+ dvb_frontend_detach(dvb->frontend[0]);
dvb_unregister_adapter(&dvb->adapter);
fail_adapter:
return result;
@@ -585,8 +606,12 @@ static void unregister_dvb(struct cx231xx_dvb *dvb)
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
dvb_dmxdev_release(&dvb->dmxdev);
dvb_dmx_release(&dvb->demux);
- dvb_unregister_frontend(dvb->frontend);
- dvb_frontend_detach(dvb->frontend);
+ if (dvb->frontend[1])
+ dvb_unregister_frontend(dvb->frontend[1]);
+ dvb_unregister_frontend(dvb->frontend[0]);
+ if (dvb->frontend[1])
+ dvb_frontend_detach(dvb->frontend[1]);
+ dvb_frontend_detach(dvb->frontend[0]);
dvb_unregister_adapter(&dvb->adapter);
/* remove I2C tuner */
client = dvb->i2c_client_tuner;
@@ -595,7 +620,12 @@ static void unregister_dvb(struct cx231xx_dvb *dvb)
i2c_unregister_device(client);
}
/* remove I2C demod */
- client = dvb->i2c_client_demod;
+ client = dvb->i2c_client_demod[1];
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+ client = dvb->i2c_client_demod[0];
if (client) {
module_put(client->dev.driver->owner);
i2c_unregister_device(client);
@@ -604,7 +634,7 @@ static void unregister_dvb(struct cx231xx_dvb *dvb)
static int dvb_init(struct cx231xx *dev)
{
- int result = 0;
+ int result;
struct cx231xx_dvb *dvb;
struct i2c_adapter *tuner_i2c;
struct i2c_adapter *demod_i2c;
@@ -635,11 +665,11 @@ static int dvb_init(struct cx231xx *dev)
case CX231XX_BOARD_CNXT_CARRAERA:
case CX231XX_BOARD_CNXT_RDE_250:
- dev->dvb->frontend = dvb_attach(s5h1432_attach,
+ dev->dvb->frontend[0] = dvb_attach(s5h1432_attach,
&dvico_s5h1432_config,
demod_i2c);
- if (dev->dvb->frontend == NULL) {
+ if (!dev->dvb->frontend[0]) {
dev_err(dev->dev,
"Failed to attach s5h1432 front end\n");
result = -EINVAL;
@@ -647,9 +677,9 @@ static int dvb_init(struct cx231xx *dev)
}
/* define general-purpose callback pointer */
- dvb->frontend->callback = cx231xx_tuner_callback;
+ dvb->frontend[0]->callback = cx231xx_tuner_callback;
- if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
+ if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0],
tuner_i2c,
&cnxt_rde250_tunerconfig)) {
result = -EINVAL;
@@ -660,11 +690,11 @@ static int dvb_init(struct cx231xx *dev)
case CX231XX_BOARD_CNXT_SHELBY:
case CX231XX_BOARD_CNXT_RDU_250:
- dev->dvb->frontend = dvb_attach(s5h1411_attach,
+ dev->dvb->frontend[0] = dvb_attach(s5h1411_attach,
&xc5000_s5h1411_config,
demod_i2c);
- if (dev->dvb->frontend == NULL) {
+ if (!dev->dvb->frontend[0]) {
dev_err(dev->dev,
"Failed to attach s5h1411 front end\n");
result = -EINVAL;
@@ -672,9 +702,9 @@ static int dvb_init(struct cx231xx *dev)
}
/* define general-purpose callback pointer */
- dvb->frontend->callback = cx231xx_tuner_callback;
+ dvb->frontend[0]->callback = cx231xx_tuner_callback;
- if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
+ if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0],
tuner_i2c,
&cnxt_rdu250_tunerconfig)) {
result = -EINVAL;
@@ -683,11 +713,11 @@ static int dvb_init(struct cx231xx *dev)
break;
case CX231XX_BOARD_CNXT_RDE_253S:
- dev->dvb->frontend = dvb_attach(s5h1432_attach,
+ dev->dvb->frontend[0] = dvb_attach(s5h1432_attach,
&dvico_s5h1432_config,
demod_i2c);
- if (dev->dvb->frontend == NULL) {
+ if (!dev->dvb->frontend[0]) {
dev_err(dev->dev,
"Failed to attach s5h1432 front end\n");
result = -EINVAL;
@@ -695,9 +725,9 @@ static int dvb_init(struct cx231xx *dev)
}
/* define general-purpose callback pointer */
- dvb->frontend->callback = cx231xx_tuner_callback;
+ dvb->frontend[0]->callback = cx231xx_tuner_callback;
- if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
+ if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0],
0x60, tuner_i2c,
&cnxt_rde253s_tunerconfig)) {
result = -EINVAL;
@@ -707,11 +737,11 @@ static int dvb_init(struct cx231xx *dev)
case CX231XX_BOARD_CNXT_RDU_253S:
case CX231XX_BOARD_KWORLD_UB445_USB_HYBRID:
- dev->dvb->frontend = dvb_attach(s5h1411_attach,
+ dev->dvb->frontend[0] = dvb_attach(s5h1411_attach,
&tda18271_s5h1411_config,
demod_i2c);
- if (dev->dvb->frontend == NULL) {
+ if (!dev->dvb->frontend[0]) {
dev_err(dev->dev,
"Failed to attach s5h1411 front end\n");
result = -EINVAL;
@@ -719,9 +749,9 @@ static int dvb_init(struct cx231xx *dev)
}
/* define general-purpose callback pointer */
- dvb->frontend->callback = cx231xx_tuner_callback;
+ dvb->frontend[0]->callback = cx231xx_tuner_callback;
- if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
+ if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0],
0x60, tuner_i2c,
&cnxt_rde253s_tunerconfig)) {
result = -EINVAL;
@@ -734,11 +764,11 @@ static int dvb_init(struct cx231xx *dev)
"%s: looking for tuner / demod on i2c bus: %d\n",
__func__, i2c_adapter_id(tuner_i2c));
- dev->dvb->frontend = dvb_attach(lgdt3305_attach,
+ dev->dvb->frontend[0] = dvb_attach(lgdt3305_attach,
&hcw_lgdt3305_config,
demod_i2c);
- if (dev->dvb->frontend == NULL) {
+ if (!dev->dvb->frontend[0]) {
dev_err(dev->dev,
"Failed to attach LG3305 front end\n");
result = -EINVAL;
@@ -746,9 +776,9 @@ static int dvb_init(struct cx231xx *dev)
}
/* define general-purpose callback pointer */
- dvb->frontend->callback = cx231xx_tuner_callback;
+ dvb->frontend[0]->callback = cx231xx_tuner_callback;
- dvb_attach(tda18271_attach, dev->dvb->frontend,
+ dvb_attach(tda18271_attach, dev->dvb->frontend[0],
0x60, tuner_i2c,
&hcw_tda18271_config);
break;
@@ -761,7 +791,7 @@ static int dvb_init(struct cx231xx *dev)
/* attach demod */
memset(&si2165_pdata, 0, sizeof(si2165_pdata));
- si2165_pdata.fe = &dev->dvb->frontend;
+ si2165_pdata.fe = &dev->dvb->frontend[0];
si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL;
si2165_pdata.ref_freq_hz = 16000000;
@@ -771,7 +801,7 @@ static int dvb_init(struct cx231xx *dev)
info.platform_data = &si2165_pdata;
request_module(info.type);
client = i2c_new_device(demod_i2c, &info);
- if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
+ if (!client || !client->dev.driver || !dev->dvb->frontend[0]) {
dev_err(dev->dev,
"Failed to attach SI2165 front end\n");
result = -EINVAL;
@@ -784,14 +814,14 @@ static int dvb_init(struct cx231xx *dev)
goto out_free;
}
- dvb->i2c_client_demod = client;
+ dvb->i2c_client_demod[0] = client;
- dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+ dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
/* define general-purpose callback pointer */
- dvb->frontend->callback = cx231xx_tuner_callback;
+ dvb->frontend[0]->callback = cx231xx_tuner_callback;
- dvb_attach(tda18271_attach, dev->dvb->frontend,
+ dvb_attach(tda18271_attach, dev->dvb->frontend[0],
0x60,
tuner_i2c,
&hcw_tda18271_config);
@@ -808,7 +838,7 @@ static int dvb_init(struct cx231xx *dev)
/* attach demod */
memset(&si2165_pdata, 0, sizeof(si2165_pdata));
- si2165_pdata.fe = &dev->dvb->frontend;
+ si2165_pdata.fe = &dev->dvb->frontend[0];
si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT;
si2165_pdata.ref_freq_hz = 24000000;
@@ -818,7 +848,7 @@ static int dvb_init(struct cx231xx *dev)
info.platform_data = &si2165_pdata;
request_module(info.type);
client = i2c_new_device(demod_i2c, &info);
- if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
+ if (!client || !client->dev.driver || !dev->dvb->frontend[0]) {
dev_err(dev->dev,
"Failed to attach SI2165 front end\n");
result = -EINVAL;
@@ -831,18 +861,18 @@ static int dvb_init(struct cx231xx *dev)
goto out_free;
}
- dvb->i2c_client_demod = client;
+ dvb->i2c_client_demod[0] = client;
memset(&info, 0, sizeof(struct i2c_board_info));
- dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+ dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
/* define general-purpose callback pointer */
- dvb->frontend->callback = cx231xx_tuner_callback;
+ dvb->frontend[0]->callback = cx231xx_tuner_callback;
/* attach tuner */
memset(&si2157_config, 0, sizeof(si2157_config));
- si2157_config.fe = dev->dvb->frontend;
+ si2157_config.fe = dev->dvb->frontend[0];
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
si2157_config.mdev = dev->media_dev;
#endif
@@ -857,14 +887,14 @@ static int dvb_init(struct cx231xx *dev)
tuner_i2c,
&info);
if (client == NULL || client->dev.driver == NULL) {
- dvb_frontend_detach(dev->dvb->frontend);
+ dvb_frontend_detach(dev->dvb->frontend[0]);
result = -ENODEV;
goto out_free;
}
if (!try_module_get(client->dev.driver->owner)) {
i2c_unregister_device(client);
- dvb_frontend_detach(dev->dvb->frontend);
+ dvb_frontend_detach(dev->dvb->frontend[0]);
result = -ENODEV;
goto out_free;
}
@@ -882,26 +912,26 @@ static int dvb_init(struct cx231xx *dev)
memset(&info, 0, sizeof(struct i2c_board_info));
- dev->dvb->frontend = dvb_attach(lgdt3306a_attach,
+ dev->dvb->frontend[0] = dvb_attach(lgdt3306a_attach,
&hauppauge_955q_lgdt3306a_config,
demod_i2c
);
- if (dev->dvb->frontend == NULL) {
+ if (!dev->dvb->frontend[0]) {
dev_err(dev->dev,
"Failed to attach LGDT3306A frontend.\n");
result = -EINVAL;
goto out_free;
}
- dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
+ dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
/* define general-purpose callback pointer */
- dvb->frontend->callback = cx231xx_tuner_callback;
+ dvb->frontend[0]->callback = cx231xx_tuner_callback;
/* attach tuner */
memset(&si2157_config, 0, sizeof(si2157_config));
- si2157_config.fe = dev->dvb->frontend;
+ si2157_config.fe = dev->dvb->frontend[0];
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
si2157_config.mdev = dev->media_dev;
#endif
@@ -916,14 +946,14 @@ static int dvb_init(struct cx231xx *dev)
tuner_i2c,
&info);
if (client == NULL || client->dev.driver == NULL) {
- dvb_frontend_detach(dev->dvb->frontend);
+ dvb_frontend_detach(dev->dvb->frontend[0]);
result = -ENODEV;
goto out_free;
}
if (!try_module_get(client->dev.driver->owner)) {
i2c_unregister_device(client);
- dvb_frontend_detach(dev->dvb->frontend);
+ dvb_frontend_detach(dev->dvb->frontend[0]);
result = -ENODEV;
goto out_free;
}
@@ -940,11 +970,11 @@ static int dvb_init(struct cx231xx *dev)
"%s: looking for demod on i2c bus: %d\n",
__func__, i2c_adapter_id(tuner_i2c));
- dev->dvb->frontend = dvb_attach(mb86a20s_attach,
+ dev->dvb->frontend[0] = dvb_attach(mb86a20s_attach,
&pv_mb86a20s_config,
demod_i2c);
- if (dev->dvb->frontend == NULL) {
+ if (!dev->dvb->frontend[0]) {
dev_err(dev->dev,
"Failed to attach mb86a20s demod\n");
result = -EINVAL;
@@ -952,9 +982,9 @@ static int dvb_init(struct cx231xx *dev)
}
/* define general-purpose callback pointer */
- dvb->frontend->callback = cx231xx_tuner_callback;
+ dvb->frontend[0]->callback = cx231xx_tuner_callback;
- dvb_attach(tda18271_attach, dev->dvb->frontend,
+ dvb_attach(tda18271_attach, dev->dvb->frontend[0],
0x60, tuner_i2c,
&pv_tda18271_config);
break;
@@ -969,7 +999,7 @@ static int dvb_init(struct cx231xx *dev)
/* attach demodulator chip */
si2168_config.ts_mode = SI2168_TS_SERIAL; /* from *.inf file */
- si2168_config.fe = &dev->dvb->frontend;
+ si2168_config.fe = &dev->dvb->frontend[0];
si2168_config.i2c_adapter = &adapter;
si2168_config.ts_clock_inv = true;
@@ -991,10 +1021,10 @@ static int dvb_init(struct cx231xx *dev)
goto out_free;
}
- dvb->i2c_client_demod = client;
+ dvb->i2c_client_demod[0] = client;
/* attach tuner chip */
- si2157_config.fe = dev->dvb->frontend;
+ si2157_config.fe = dev->dvb->frontend[0];
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
si2157_config.mdev = dev->media_dev;
#endif
@@ -1010,16 +1040,16 @@ static int dvb_init(struct cx231xx *dev)
client = i2c_new_device(tuner_i2c, &info);
if (client == NULL || client->dev.driver == NULL) {
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
+ module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod[0]);
result = -ENODEV;
goto out_free;
}
if (!try_module_get(client->dev.driver->owner)) {
i2c_unregister_device(client);
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
+ module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod[0]);
result = -ENODEV;
goto out_free;
}
@@ -1037,7 +1067,7 @@ static int dvb_init(struct cx231xx *dev)
/* attach demodulator chip */
mn88473_config.i2c_wr_max = 16;
mn88473_config.xtal = 25000000;
- mn88473_config.fe = &dev->dvb->frontend;
+ mn88473_config.fe = &dev->dvb->frontend[0];
strlcpy(info.type, "mn88473", sizeof(info.type));
info.addr = dev->board.demod_addr;
@@ -1057,24 +1087,219 @@ static int dvb_init(struct cx231xx *dev)
goto out_free;
}
- dvb->i2c_client_demod = client;
+ dvb->i2c_client_demod[0] = client;
/* define general-purpose callback pointer */
- dvb->frontend->callback = cx231xx_tuner_callback;
+ dvb->frontend[0]->callback = cx231xx_tuner_callback;
/* attach tuner chip */
- dvb_attach(r820t_attach, dev->dvb->frontend,
+ dvb_attach(r820t_attach, dev->dvb->frontend[0],
tuner_i2c,
&astrometa_t2hybrid_r820t_config);
break;
}
+ case CX231XX_BOARD_HAUPPAUGE_935C:
+ {
+ struct i2c_client *client;
+ struct i2c_adapter *adapter;
+ struct i2c_board_info info = {};
+ struct si2157_config si2157_config = {};
+ struct si2168_config si2168_config = {};
+
+ /* attach demodulator chip */
+ si2168_config.ts_mode = SI2168_TS_SERIAL;
+ si2168_config.fe = &dev->dvb->frontend[0];
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.ts_clock_inv = true;
+
+ strlcpy(info.type, "si2168", sizeof(info.type));
+ info.addr = dev->board.demod_addr;
+ info.platform_data = &si2168_config;
+
+ request_module(info.type);
+ client = i2c_new_device(demod_i2c, &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ dev_err(dev->dev,
+ "Failed to attach %s frontend.\n", info.type);
+ i2c_unregister_device(client);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dvb->i2c_client_demod[0] = client;
+ dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
+
+ /* define general-purpose callback pointer */
+ dvb->frontend[0]->callback = cx231xx_tuner_callback;
+
+ /* attach tuner */
+ si2157_config.fe = dev->dvb->frontend[0];
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ si2157_config.mdev = dev->media_dev;
+#endif
+ si2157_config.if_port = 1;
+ si2157_config.inversion = true;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ info.addr = dev->board.tuner_addr;
+ info.platform_data = &si2157_config;
+ request_module("si2157");
+
+ client = i2c_new_device(adapter, &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ dev_err(dev->dev,
+ "Failed to obtain %s tuner.\n", info.type);
+ i2c_unregister_device(client);
+ module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dev->cx231xx_reset_analog_tuner = NULL;
+ dev->dvb->i2c_client_tuner = client;
+ break;
+ }
+ case CX231XX_BOARD_HAUPPAUGE_975:
+ {
+ struct i2c_client *client;
+ struct i2c_adapter *adapter;
+ struct i2c_adapter *adapter2;
+ struct i2c_board_info info = {};
+ struct si2157_config si2157_config = {};
+ struct lgdt3306a_config lgdt3306a_config = {};
+ struct si2168_config si2168_config = {};
+
+ /* attach first demodulator chip */
+ lgdt3306a_config = hauppauge_955q_lgdt3306a_config;
+ lgdt3306a_config.fe = &dev->dvb->frontend[0];
+ lgdt3306a_config.i2c_adapter = &adapter;
+ lgdt3306a_config.deny_i2c_rptr = 0;
+
+ strlcpy(info.type, "lgdt3306a", sizeof(info.type));
+ info.addr = dev->board.demod_addr;
+ info.platform_data = &lgdt3306a_config;
+
+ request_module(info.type);
+ client = i2c_new_device(demod_i2c, &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ dev_err(dev->dev,
+ "Failed to attach %s frontend.\n", info.type);
+ i2c_unregister_device(client);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dvb->i2c_client_demod[0] = client;
+
+ /* attach second demodulator chip */
+ si2168_config.ts_mode = SI2168_TS_SERIAL;
+ si2168_config.fe = &dev->dvb->frontend[1];
+ si2168_config.i2c_adapter = &adapter2;
+ si2168_config.ts_clock_inv = true;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2168", sizeof(info.type));
+ info.addr = dev->board.demod_addr2;
+ info.platform_data = &si2168_config;
+
+ request_module(info.type);
+ client = i2c_new_device(adapter, &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ dev_err(dev->dev,
+ "Failed to attach %s frontend.\n", info.type);
+ module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dvb->i2c_client_demod[1] = client;
+ dvb->frontend[1]->id = 1;
+
+ /* define general-purpose callback pointer */
+ dvb->frontend[0]->callback = cx231xx_tuner_callback;
+ dvb->frontend[1]->callback = cx231xx_tuner_callback;
+
+ /* attach tuner */
+ si2157_config.fe = dev->dvb->frontend[0];
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ si2157_config.mdev = dev->media_dev;
+#endif
+ si2157_config.if_port = 1;
+ si2157_config.inversion = true;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ info.addr = dev->board.tuner_addr;
+ info.platform_data = &si2157_config;
+ request_module("si2157");
+
+ client = i2c_new_device(adapter, &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ module_put(dvb->i2c_client_demod[1]->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod[1]);
+ module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ dev_err(dev->dev,
+ "Failed to obtain %s tuner.\n", info.type);
+ i2c_unregister_device(client);
+ module_put(dvb->i2c_client_demod[1]->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod[1]);
+ module_put(dvb->i2c_client_demod[0]->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dev->cx231xx_reset_analog_tuner = NULL;
+ dvb->i2c_client_tuner = client;
+
+ dvb->frontend[1]->tuner_priv = dvb->frontend[0]->tuner_priv;
+
+ memcpy(&dvb->frontend[1]->ops.tuner_ops,
+ &dvb->frontend[0]->ops.tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+ break;
+ }
default:
dev_err(dev->dev,
"%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->name);
break;
}
- if (NULL == dvb->frontend) {
+ if (!dvb->frontend[0]) {
dev_err(dev->dev,
"%s/2: frontend initialization failed\n", dev->name);
result = -EINVAL;
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 5b321b8ada3a..f7fcd733a2ca 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -1941,7 +1941,7 @@ static int cx231xx_close(struct file *filp)
}
/* Save some power by putting tuner to sleep */
- call_all(dev, core, s_power, 0);
+ call_all(dev, tuner, standby);
/* do this before setting alternate! */
if (dev->USE_ISO)
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index 65b039cf80be..6ffa4bd96484 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -81,6 +81,8 @@
#define CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD 23
#define CX231XX_BOARD_ASTROMETA_T2HYBRID 24
#define CX231XX_BOARD_THE_IMAGING_SOURCE_DFG_USB2_PRO 25
+#define CX231XX_BOARD_HAUPPAUGE_935C 26
+#define CX231XX_BOARD_HAUPPAUGE_975 27
/* Limits minimum and default number of buffers */
#define CX231XX_MIN_BUF 4
@@ -343,6 +345,7 @@ struct cx231xx_board {
/* demod related */
int demod_addr;
+ int demod_addr2;
u8 demod_xfer_mode; /* 0 - Serial; 1 - parallel */
/* GPIO Pins */
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
index 0e4944b2b0f4..37053477b84d 100644
--- a/drivers/media/usb/dvb-usb-v2/Kconfig
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -15,7 +15,8 @@ config DVB_USB_V2
config DVB_USB_AF9015
tristate "Afatech AF9015 DVB-T USB2.0 support"
- depends on DVB_USB_V2
+ depends on DVB_USB_V2 && I2C_MUX
+ select REGMAP
select DVB_AF9013
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
index 8013659c41b1..39f9ffce3caa 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.c
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -29,6 +29,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
#define REQ_HDR_LEN 8 /* send header size */
#define ACK_HDR_LEN 2 /* rece header size */
struct af9015_state *state = d_to_priv(d);
+ struct usb_interface *intf = d->intf;
int ret, wlen, rlen;
u8 write = 1;
@@ -66,23 +67,24 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
case BOOT:
break;
default:
- dev_err(&d->udev->dev, "%s: unknown command=%d\n",
- KBUILD_MODNAME, req->cmd);
+ dev_err(&intf->dev, "unknown cmd %d\n", req->cmd);
ret = -EIO;
goto error;
}
- /* buffer overflow check */
+ /* Buffer overflow check */
if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) ||
- (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) {
- dev_err(&d->udev->dev, "%s: too much data; cmd=%d len=%d\n",
- KBUILD_MODNAME, req->cmd, req->data_len);
+ (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) {
+ dev_err(&intf->dev, "too much data, cmd %u, len %u\n",
+ req->cmd, req->data_len);
ret = -EINVAL;
goto error;
}
- /* write receives seq + status = 2 bytes
- read receives seq + status + data = 2 + N bytes */
+ /*
+ * Write receives seq + status = 2 bytes
+ * Read receives seq + status + data = 2 + N bytes
+ */
wlen = REQ_HDR_LEN;
rlen = ACK_HDR_LEN;
if (write) {
@@ -96,15 +98,14 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB)
rlen = 0;
- ret = dvb_usbv2_generic_rw_locked(d,
- state->buf, wlen, state->buf, rlen);
+ ret = dvb_usbv2_generic_rw_locked(d, state->buf, wlen,
+ state->buf, rlen);
if (ret)
goto error;
/* check status */
if (rlen && state->buf[1]) {
- dev_err(&d->udev->dev, "%s: command failed=%d\n",
- KBUILD_MODNAME, state->buf[1]);
+ dev_err(&intf->dev, "cmd failed %u\n", state->buf[1]);
ret = -EIO;
goto error;
}
@@ -118,121 +119,66 @@ error:
return ret;
}
-static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val,
- u8 len)
-{
- struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
- val};
- return af9015_ctrl_msg(d, &req);
-}
-
-static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len)
-{
- struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
- val};
- return af9015_ctrl_msg(d, &req);
-}
-
-static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val)
-{
- return af9015_write_regs(d, addr, &val, 1);
-}
-
-static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
-{
- return af9015_read_regs(d, addr, val, 1);
-}
-
static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
- u8 val)
+ u8 val)
{
struct af9015_state *state = d_to_priv(d);
struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val};
- if (addr == state->af9013_config[0].i2c_addr ||
- addr == state->af9013_config[1].i2c_addr)
+ if (addr == state->af9013_i2c_addr[0] ||
+ addr == state->af9013_i2c_addr[1])
req.addr_len = 3;
return af9015_ctrl_msg(d, &req);
}
static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
- u8 *val)
+ u8 *val)
{
struct af9015_state *state = d_to_priv(d);
struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val};
- if (addr == state->af9013_config[0].i2c_addr ||
- addr == state->af9013_config[1].i2c_addr)
+ if (addr == state->af9013_i2c_addr[0] ||
+ addr == state->af9013_i2c_addr[1])
req.addr_len = 3;
return af9015_ctrl_msg(d, &req);
}
-static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op)
-{
- int ret;
- u8 val, mask = 0x01;
-
- ret = af9015_read_reg(d, addr, &val);
- if (ret)
- return ret;
-
- mask <<= bit;
- if (op) {
- /* set bit */
- val |= mask;
- } else {
- /* clear bit */
- mask ^= 0xff;
- val &= mask;
- }
-
- return af9015_write_reg(d, addr, val);
-}
-
-static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
-{
- return af9015_do_reg_bit(d, addr, bit, 1);
-}
-
-static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
-{
- return af9015_do_reg_bit(d, addr, bit, 0);
-}
-
static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num)
+ int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
struct af9015_state *state = d_to_priv(d);
+ struct usb_interface *intf = d->intf;
int ret;
u16 addr;
u8 mbox, addr_len;
struct req_t req;
-/*
-The bus lock is needed because there is two tuners both using same I2C-address.
-Due to that the only way to select correct tuner is use demodulator I2C-gate.
-
-................................................
-. AF9015 includes integrated AF9013 demodulator.
-. ____________ ____________ . ____________
-.| uC | | demod | . | tuner |
-.|------------| |------------| . |------------|
-.| AF9015 | | AF9013/5 | . | MXL5003 |
-.| |--+----I2C-------|-----/ -----|-.-----I2C-------| |
-.| | | | addr 0x38 | . | addr 0xc6 |
-.|____________| | |____________| . |____________|
-.................|..............................
- | ____________ ____________
- | | demod | | tuner |
- | |------------| |------------|
- | | AF9013 | | MXL5003 |
- +----I2C-------|-----/ -----|-------I2C-------| |
- | addr 0x3a | | addr 0xc6 |
- |____________| |____________|
-*/
+ /*
+ * I2C multiplexing:
+ * There could be two tuners, both using same I2C address. Demodulator
+ * I2C-gate is only possibility to select correct tuner.
+ *
+ * ...........................................
+ * . AF9015 integrates AF9013 demodulator .
+ * . ____________ ____________ . ____________
+ * .| USB IF | | demod |. | tuner |
+ * .|------------| |------------|. |------------|
+ * .| AF9015 | | AF9013 |. | MXL5003 |
+ * .| |--+--I2C-----|-----/ -----|.----I2C-----| |
+ * .| | | | addr 0x1c |. | addr 0x63 |
+ * .|____________| | |____________|. |____________|
+ * .................|.........................
+ * | ____________ ____________
+ * | | demod | | tuner |
+ * | |------------| |------------|
+ * | | AF9013 | | MXL5003 |
+ * +--I2C-----|-----/ -----|-----I2C-----| |
+ * | addr 0x1d | | addr 0x63 |
+ * |____________| |____________|
+ */
if (msg[0].len == 0 || msg[0].flags & I2C_M_RD) {
addr = 0x0000;
@@ -243,11 +189,11 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
mbox = 0;
addr_len = 1;
} else if (msg[0].len == 2) {
- addr = msg[0].buf[0] << 8|msg[0].buf[1] << 0;
+ addr = msg[0].buf[0] << 8 | msg[0].buf[1] << 0;
mbox = 0;
addr_len = 2;
} else {
- addr = msg[0].buf[0] << 8|msg[0].buf[1] << 0;
+ addr = msg[0].buf[0] << 8 | msg[0].buf[1] << 0;
mbox = msg[0].buf[2];
addr_len = 3;
}
@@ -258,7 +204,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
ret = -EOPNOTSUPP;
goto err;
}
- if (msg[0].addr == state->af9013_config[0].i2c_addr)
+ if (msg[0].addr == state->af9013_i2c_addr[0])
req.cmd = WRITE_MEMORY;
else
req.cmd = WRITE_I2C;
@@ -266,7 +212,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
req.addr = addr;
req.mbox = mbox;
req.addr_len = addr_len;
- req.data_len = msg[0].len-addr_len;
+ req.data_len = msg[0].len - addr_len;
req.data = &msg[0].buf[addr_len];
ret = af9015_ctrl_msg(d, &req);
} else if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
@@ -276,7 +222,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
ret = -EOPNOTSUPP;
goto err;
}
- if (msg[0].addr == state->af9013_config[0].i2c_addr)
+ if (msg[0].addr == state->af9013_i2c_addr[0])
req.cmd = READ_MEMORY;
else
req.cmd = READ_I2C;
@@ -293,7 +239,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
ret = -EOPNOTSUPP;
goto err;
}
- if (msg[0].addr == state->af9013_config[0].i2c_addr) {
+ if (msg[0].addr == state->af9013_i2c_addr[0]) {
ret = -EINVAL;
goto err;
}
@@ -307,15 +253,14 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
ret = af9015_ctrl_msg(d, &req);
} else {
ret = -EOPNOTSUPP;
- dev_dbg(&d->udev->dev, "%s: unknown msg, num %u\n",
- __func__, num);
+ dev_dbg(&intf->dev, "unknown msg, num %u\n", num);
}
if (ret)
goto err;
return num;
err:
- dev_dbg(&d->udev->dev, "%s: failed %d\n", __func__, ret);
+ dev_dbg(&intf->dev, "failed %d\n", ret);
return ret;
}
@@ -331,6 +276,7 @@ static struct i2c_algorithm af9015_i2c_algo = {
static int af9015_identify_state(struct dvb_usb_device *d, const char **name)
{
+ struct usb_interface *intf = d->intf;
int ret;
u8 reply;
struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply};
@@ -339,7 +285,7 @@ static int af9015_identify_state(struct dvb_usb_device *d, const char **name)
if (ret)
return ret;
- dev_dbg(&d->udev->dev, "%s: reply=%02x\n", __func__, reply);
+ dev_dbg(&intf->dev, "reply %02x\n", reply);
if (reply == 0x02)
ret = WARM;
@@ -350,52 +296,47 @@ static int af9015_identify_state(struct dvb_usb_device *d, const char **name)
}
static int af9015_download_firmware(struct dvb_usb_device *d,
- const struct firmware *fw)
+ const struct firmware *firmware)
{
struct af9015_state *state = d_to_priv(d);
- int i, len, remaining, ret;
+ struct usb_interface *intf = d->intf;
+ int ret, i, rem;
struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL};
- u16 checksum = 0;
- dev_dbg(&d->udev->dev, "%s:\n", __func__);
+ u16 checksum;
- /* calc checksum */
- for (i = 0; i < fw->size; i++)
- checksum += fw->data[i];
+ dev_dbg(&intf->dev, "\n");
- state->firmware_size = fw->size;
- state->firmware_checksum = checksum;
+ /* Calc checksum, we need it when copy firmware to slave demod */
+ for (i = 0, checksum = 0; i < firmware->size; i++)
+ checksum += firmware->data[i];
- #define FW_ADDR 0x5100 /* firmware start address */
- #define LEN_MAX 55 /* max packet size */
- for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
- len = remaining;
- if (len > LEN_MAX)
- len = LEN_MAX;
-
- req.data_len = len;
- req.data = (u8 *) &fw->data[fw->size - remaining];
- req.addr = FW_ADDR + fw->size - remaining;
+ state->firmware_size = firmware->size;
+ state->firmware_checksum = checksum;
+ #define LEN_MAX (BUF_LEN - REQ_HDR_LEN) /* Max payload size */
+ for (rem = firmware->size; rem > 0; rem -= LEN_MAX) {
+ req.data_len = min(LEN_MAX, rem);
+ req.data = (u8 *)&firmware->data[firmware->size - rem];
+ req.addr = 0x5100 + firmware->size - rem;
ret = af9015_ctrl_msg(d, &req);
if (ret) {
- dev_err(&d->udev->dev,
- "%s: firmware download failed=%d\n",
- KBUILD_MODNAME, ret);
- goto error;
+ dev_err(&intf->dev, "firmware download failed %d\n",
+ ret);
+ goto err;
}
}
- /* firmware loaded, request boot */
req.cmd = BOOT;
req.data_len = 0;
ret = af9015_ctrl_msg(d, &req);
if (ret) {
- dev_err(&d->udev->dev, "%s: firmware boot failed=%d\n",
- KBUILD_MODNAME, ret);
- goto error;
+ dev_err(&intf->dev, "firmware boot failed %d\n", ret);
+ goto err;
}
-error:
+ return 0;
+err:
+ dev_dbg(&intf->dev, "failed %d\n", ret);
return ret;
}
@@ -407,6 +348,7 @@ error:
static int af9015_eeprom_hash(struct dvb_usb_device *d)
{
struct af9015_state *state = d_to_priv(d);
+ struct usb_interface *intf = d->intf;
int ret, i;
u8 buf[AF9015_EEPROM_SIZE];
struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, NULL};
@@ -427,24 +369,24 @@ static int af9015_eeprom_hash(struct dvb_usb_device *d)
}
for (i = 0; i < AF9015_EEPROM_SIZE; i += 16)
- dev_dbg(&d->udev->dev, "%s: %*ph\n", __func__, 16, buf + i);
+ dev_dbg(&intf->dev, "%*ph\n", 16, buf + i);
- dev_dbg(&d->udev->dev, "%s: eeprom sum=%.8x\n",
- __func__, state->eeprom_sum);
+ dev_dbg(&intf->dev, "eeprom sum %.8x\n", state->eeprom_sum);
return 0;
err:
- dev_err(&d->udev->dev, "%s: eeprom failed=%d\n", KBUILD_MODNAME, ret);
+ dev_dbg(&intf->dev, "failed %d\n", ret);
return ret;
}
static int af9015_read_config(struct dvb_usb_device *d)
{
struct af9015_state *state = d_to_priv(d);
+ struct usb_interface *intf = d->intf;
int ret;
u8 val, i, offset = 0;
struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
- dev_dbg(&d->udev->dev, "%s:\n", __func__);
+ dev_dbg(&intf->dev, "\n");
/* IR remote controller */
req.addr = AF9015_EEPROM_IR_MODE;
@@ -462,7 +404,7 @@ static int af9015_read_config(struct dvb_usb_device *d)
goto error;
state->ir_mode = val;
- dev_dbg(&d->udev->dev, "%s: IR mode=%d\n", __func__, val);
+ dev_dbg(&intf->dev, "ir mode %02x\n", val);
/* TS mode - one or two receivers */
req.addr = AF9015_EEPROM_TS_MODE;
@@ -471,13 +413,9 @@ static int af9015_read_config(struct dvb_usb_device *d)
goto error;
state->dual_mode = val;
- dev_dbg(&d->udev->dev, "%s: TS mode=%d\n", __func__, state->dual_mode);
+ dev_dbg(&intf->dev, "ts mode %02x\n", state->dual_mode);
- /* disable 2nd adapter because we don't have PID-filters */
- if (d->udev->speed == USB_SPEED_FULL)
- state->dual_mode = 0;
-
- state->af9013_config[0].i2c_addr = AF9015_I2C_DEMOD;
+ state->af9013_i2c_addr[0] = AF9015_I2C_DEMOD;
if (state->dual_mode) {
/* read 2nd demodulator I2C address */
@@ -486,7 +424,7 @@ static int af9015_read_config(struct dvb_usb_device *d)
if (ret)
goto error;
- state->af9013_config[1].i2c_addr = val >> 1;
+ state->af9013_i2c_addr[1] = val >> 1;
}
for (i = 0; i < state->dual_mode + 1; i++) {
@@ -499,21 +437,20 @@ static int af9015_read_config(struct dvb_usb_device *d)
goto error;
switch (val) {
case 0:
- state->af9013_config[i].clock = 28800000;
+ state->af9013_pdata[i].clk = 28800000;
break;
case 1:
- state->af9013_config[i].clock = 20480000;
+ state->af9013_pdata[i].clk = 20480000;
break;
case 2:
- state->af9013_config[i].clock = 28000000;
+ state->af9013_pdata[i].clk = 28000000;
break;
case 3:
- state->af9013_config[i].clock = 25000000;
+ state->af9013_pdata[i].clk = 25000000;
break;
}
- dev_dbg(&d->udev->dev, "%s: [%d] xtal=%d set clock=%d\n",
- __func__, i, val,
- state->af9013_config[i].clock);
+ dev_dbg(&intf->dev, "[%d] xtal %02x, clk %u\n",
+ i, val, state->af9013_pdata[i].clk);
/* IF frequency */
req.addr = AF9015_EEPROM_IF1H + offset;
@@ -521,17 +458,17 @@ static int af9015_read_config(struct dvb_usb_device *d)
if (ret)
goto error;
- state->af9013_config[i].if_frequency = val << 8;
+ state->af9013_pdata[i].if_frequency = val << 8;
req.addr = AF9015_EEPROM_IF1L + offset;
ret = af9015_ctrl_msg(d, &req);
if (ret)
goto error;
- state->af9013_config[i].if_frequency += val;
- state->af9013_config[i].if_frequency *= 1000;
- dev_dbg(&d->udev->dev, "%s: [%d] IF frequency=%d\n", __func__,
- i, state->af9013_config[i].if_frequency);
+ state->af9013_pdata[i].if_frequency += val;
+ state->af9013_pdata[i].if_frequency *= 1000;
+ dev_dbg(&intf->dev, "[%d] if frequency %u\n",
+ i, state->af9013_pdata[i].if_frequency);
/* MT2060 IF1 */
req.addr = AF9015_EEPROM_MT2060_IF1H + offset;
@@ -544,8 +481,8 @@ static int af9015_read_config(struct dvb_usb_device *d)
if (ret)
goto error;
state->mt2060_if1[i] += val;
- dev_dbg(&d->udev->dev, "%s: [%d] MT2060 IF1=%d\n", __func__, i,
- state->mt2060_if1[i]);
+ dev_dbg(&intf->dev, "[%d] MT2060 IF1 %u\n",
+ i, state->mt2060_if1[i]);
/* tuner */
req.addr = AF9015_EEPROM_TUNER_ID1 + offset;
@@ -561,71 +498,177 @@ static int af9015_read_config(struct dvb_usb_device *d)
case AF9013_TUNER_TDA18271:
case AF9013_TUNER_QT1010A:
case AF9013_TUNER_TDA18218:
- state->af9013_config[i].spec_inv = 1;
+ state->af9013_pdata[i].spec_inv = 1;
break;
case AF9013_TUNER_MXL5003D:
case AF9013_TUNER_MXL5005D:
case AF9013_TUNER_MXL5005R:
case AF9013_TUNER_MXL5007T:
- state->af9013_config[i].spec_inv = 0;
+ state->af9013_pdata[i].spec_inv = 0;
break;
case AF9013_TUNER_MC44S803:
- state->af9013_config[i].gpio[1] = AF9013_GPIO_LO;
- state->af9013_config[i].spec_inv = 1;
+ state->af9013_pdata[i].gpio[1] = AF9013_GPIO_LO;
+ state->af9013_pdata[i].spec_inv = 1;
break;
default:
- dev_err(&d->udev->dev, "%s: tuner id=%d not " \
- "supported, please report!\n",
- KBUILD_MODNAME, val);
+ dev_err(&intf->dev,
+ "tuner id %02x not supported, please report!\n",
+ val);
return -ENODEV;
}
- state->af9013_config[i].tuner = val;
- dev_dbg(&d->udev->dev, "%s: [%d] tuner id=%d\n",
- __func__, i, val);
+ state->af9013_pdata[i].tuner = val;
+ dev_dbg(&intf->dev, "[%d] tuner id %02x\n", i, val);
}
error:
if (ret)
- dev_err(&d->udev->dev, "%s: eeprom read failed=%d\n",
- KBUILD_MODNAME, ret);
+ dev_err(&intf->dev, "eeprom read failed %d\n", ret);
- /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM
- content :-( Override some wrong values here. Ditto for the
- AVerTV Red HD+ (A850T) device. */
+ /*
+ * AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM
+ * content :-( Override some wrong values here. Ditto for the
+ * AVerTV Red HD+ (A850T) device.
+ */
if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA &&
- ((le16_to_cpu(d->udev->descriptor.idProduct) ==
- USB_PID_AVERMEDIA_A850) ||
- (le16_to_cpu(d->udev->descriptor.idProduct) ==
- USB_PID_AVERMEDIA_A850T))) {
- dev_dbg(&d->udev->dev,
- "%s: AverMedia A850: overriding config\n",
- __func__);
+ ((le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850) ||
+ (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850T))) {
+ dev_dbg(&intf->dev, "AverMedia A850: overriding config\n");
/* disable dual mode */
state->dual_mode = 0;
/* set correct IF */
- state->af9013_config[0].if_frequency = 4570000;
+ state->af9013_pdata[0].if_frequency = 4570000;
}
return ret;
}
static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
- struct usb_data_stream_properties *stream)
+ struct usb_data_stream_properties *stream)
{
struct dvb_usb_device *d = fe_to_d(fe);
- dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, fe_to_adap(fe)->id);
+ struct usb_interface *intf = d->intf;
+
+ dev_dbg(&intf->dev, "adap %u\n", fe_to_adap(fe)->id);
if (d->udev->speed == USB_SPEED_FULL)
- stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE;
+ stream->u.bulk.buffersize = 5 * 188;
+
+ return 0;
+}
+
+static int af9015_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+ struct dvb_usb_device *d = fe_to_d(fe);
+ struct af9015_state *state = d_to_priv(d);
+ struct usb_interface *intf = d->intf;
+ int ret;
+ unsigned int utmp1, utmp2, reg1, reg2;
+ u8 buf[2];
+ const unsigned int adap_id = fe_to_adap(fe)->id;
+
+ dev_dbg(&intf->dev, "adap id %d, onoff %d\n", adap_id, onoff);
+
+ if (!state->usb_ts_if_configured[adap_id]) {
+ dev_dbg(&intf->dev, "set usb and ts interface\n");
+
+ /* USB IF stream settings */
+ utmp1 = (d->udev->speed == USB_SPEED_FULL ? 5 : 87) * 188 / 4;
+ utmp2 = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4;
+
+ buf[0] = (utmp1 >> 0) & 0xff;
+ buf[1] = (utmp1 >> 8) & 0xff;
+ if (adap_id == 0) {
+ /* 1st USB IF (EP4) stream settings */
+ reg1 = 0xdd88;
+ reg2 = 0xdd0c;
+ } else {
+ /* 2nd USB IF (EP5) stream settings */
+ reg1 = 0xdd8a;
+ reg2 = 0xdd0d;
+ }
+ ret = regmap_bulk_write(state->regmap, reg1, buf, 2);
+ if (ret)
+ goto err;
+ ret = regmap_write(state->regmap, reg2, utmp2);
+ if (ret)
+ goto err;
+
+ /* TS IF settings */
+ if (state->dual_mode) {
+ utmp1 = 0x01;
+ utmp2 = 0x10;
+ } else {
+ utmp1 = 0x00;
+ utmp2 = 0x00;
+ }
+ ret = regmap_update_bits(state->regmap, 0xd50b, 0x01, utmp1);
+ if (ret)
+ goto err;
+ ret = regmap_update_bits(state->regmap, 0xd520, 0x10, utmp2);
+ if (ret)
+ goto err;
+
+ state->usb_ts_if_configured[adap_id] = true;
+ }
+
+ if (adap_id == 0 && onoff) {
+ /* Adapter 0 stream on. EP4: clear NAK, enable, clear reset */
+ ret = regmap_update_bits(state->regmap, 0xdd13, 0x20, 0x00);
+ if (ret)
+ goto err;
+ ret = regmap_update_bits(state->regmap, 0xdd11, 0x20, 0x20);
+ if (ret)
+ goto err;
+ ret = regmap_update_bits(state->regmap, 0xd507, 0x04, 0x00);
+ if (ret)
+ goto err;
+ } else if (adap_id == 1 && onoff) {
+ /* Adapter 1 stream on. EP5: clear NAK, enable, clear reset */
+ ret = regmap_update_bits(state->regmap, 0xdd13, 0x40, 0x00);
+ if (ret)
+ goto err;
+ ret = regmap_update_bits(state->regmap, 0xdd11, 0x40, 0x40);
+ if (ret)
+ goto err;
+ ret = regmap_update_bits(state->regmap, 0xd50b, 0x02, 0x00);
+ if (ret)
+ goto err;
+ } else if (adap_id == 0 && !onoff) {
+ /* Adapter 0 stream off. EP4: set reset, disable, set NAK */
+ ret = regmap_update_bits(state->regmap, 0xd507, 0x04, 0x04);
+ if (ret)
+ goto err;
+ ret = regmap_update_bits(state->regmap, 0xdd11, 0x20, 0x00);
+ if (ret)
+ goto err;
+ ret = regmap_update_bits(state->regmap, 0xdd13, 0x20, 0x20);
+ if (ret)
+ goto err;
+ } else if (adap_id == 1 && !onoff) {
+ /* Adapter 1 stream off. EP5: set reset, disable, set NAK */
+ ret = regmap_update_bits(state->regmap, 0xd50b, 0x02, 0x02);
+ if (ret)
+ goto err;
+ ret = regmap_update_bits(state->regmap, 0xdd11, 0x40, 0x00);
+ if (ret)
+ goto err;
+ ret = regmap_update_bits(state->regmap, 0xdd13, 0x40, 0x40);
+ if (ret)
+ goto err;
+ }
return 0;
+err:
+ dev_dbg(&intf->dev, "failed %d\n", ret);
+ return ret;
}
static int af9015_get_adapter_count(struct dvb_usb_device *d)
{
struct af9015_state *state = d_to_priv(d);
+
return state->dual_mode + 1;
}
@@ -647,7 +690,7 @@ static int af9015_af9013_set_frontend(struct dvb_frontend *fe)
/* override demod callbacks for resource locking */
static int af9015_af9013_read_status(struct dvb_frontend *fe,
- enum fe_status *status)
+ enum fe_status *status)
{
int ret;
struct af9015_state *state = fe_to_priv(fe);
@@ -729,102 +772,105 @@ static int af9015_tuner_sleep(struct dvb_frontend *fe)
static int af9015_copy_firmware(struct dvb_usb_device *d)
{
struct af9015_state *state = d_to_priv(d);
+ struct usb_interface *intf = d->intf;
int ret;
- u8 fw_params[4];
- u8 val, i;
- struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params),
- fw_params };
- dev_dbg(&d->udev->dev, "%s:\n", __func__);
-
- fw_params[0] = state->firmware_size >> 8;
- fw_params[1] = state->firmware_size & 0xff;
- fw_params[2] = state->firmware_checksum >> 8;
- fw_params[3] = state->firmware_checksum & 0xff;
-
- ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr,
- 0x98be, &val);
- if (ret)
- goto error;
- else
- dev_dbg(&d->udev->dev, "%s: firmware status=%02x\n",
- __func__, val);
+ unsigned long timeout;
+ u8 val, firmware_info[4];
+ struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, 4, firmware_info};
- if (val == 0x0c) /* fw is running, no need for download */
- goto exit;
+ dev_dbg(&intf->dev, "\n");
- /* set I2C master clock to fast (to speed up firmware copy) */
- ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */
+ firmware_info[0] = (state->firmware_size >> 8) & 0xff;
+ firmware_info[1] = (state->firmware_size >> 0) & 0xff;
+ firmware_info[2] = (state->firmware_checksum >> 8) & 0xff;
+ firmware_info[3] = (state->firmware_checksum >> 0) & 0xff;
+
+ /* Check whether firmware is already running */
+ ret = af9015_read_reg_i2c(d, state->af9013_i2c_addr[1], 0x98be, &val);
if (ret)
- goto error;
+ goto err;
- msleep(50);
+ dev_dbg(&intf->dev, "firmware status %02x\n", val);
- /* copy firmware */
- ret = af9015_ctrl_msg(d, &req);
+ if (val == 0x0c)
+ return 0;
+
+ /* Set i2c clock to 625kHz to speed up firmware copy */
+ ret = regmap_write(state->regmap, 0xd416, 0x04);
if (ret)
- dev_err(&d->udev->dev, "%s: firmware copy cmd failed=%d\n",
- KBUILD_MODNAME, ret);
+ goto err;
- dev_dbg(&d->udev->dev, "%s: firmware copy done\n", __func__);
+ /* Copy firmware from master demod to slave demod */
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret) {
+ dev_err(&intf->dev, "firmware copy cmd failed %d\n", ret);
+ goto err;
+ }
- /* set I2C master clock back to normal */
- ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */
+ /* Set i2c clock to 125kHz */
+ ret = regmap_write(state->regmap, 0xd416, 0x14);
if (ret)
- goto error;
+ goto err;
- /* request boot firmware */
- ret = af9015_write_reg_i2c(d, state->af9013_config[1].i2c_addr,
- 0xe205, 1);
- dev_dbg(&d->udev->dev, "%s: firmware boot cmd status=%d\n",
- __func__, ret);
+ /* Boot firmware */
+ ret = af9015_write_reg_i2c(d, state->af9013_i2c_addr[1], 0xe205, 0x01);
if (ret)
- goto error;
+ goto err;
- for (i = 0; i < 15; i++) {
- msleep(100);
+ /* Poll firmware ready */
+ for (val = 0x00, timeout = jiffies + msecs_to_jiffies(1000);
+ !time_after(jiffies, timeout) && val != 0x0c && val != 0x04;) {
+ msleep(20);
- /* check firmware status */
- ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr,
- 0x98be, &val);
- dev_dbg(&d->udev->dev, "%s: firmware status cmd status=%d " \
- "firmware status=%02x\n", __func__, ret, val);
+ /* Check firmware status. 0c=OK, 04=fail */
+ ret = af9015_read_reg_i2c(d, state->af9013_i2c_addr[1],
+ 0x98be, &val);
if (ret)
- goto error;
+ goto err;
- if (val == 0x0c || val == 0x04) /* success or fail */
- break;
+ dev_dbg(&intf->dev, "firmware status %02x\n", val);
}
+ dev_dbg(&intf->dev, "firmware boot took %u ms\n",
+ jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - 1000));
+
if (val == 0x04) {
- dev_err(&d->udev->dev, "%s: firmware did not run\n",
- KBUILD_MODNAME);
- ret = -ETIMEDOUT;
+ ret = -ENODEV;
+ dev_err(&intf->dev, "firmware did not run\n");
+ goto err;
} else if (val != 0x0c) {
- dev_err(&d->udev->dev, "%s: firmware boot timeout\n",
- KBUILD_MODNAME);
ret = -ETIMEDOUT;
+ dev_err(&intf->dev, "firmware boot timeout\n");
+ goto err;
}
-error:
-exit:
+ return 0;
+err:
+ dev_dbg(&intf->dev, "failed %d\n", ret);
return ret;
}
static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
{
- int ret;
struct af9015_state *state = adap_to_priv(adap);
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct usb_interface *intf = d->intf;
+ struct i2c_client *client;
+ int ret;
+
+ dev_dbg(&intf->dev, "adap id %u\n", adap->id);
if (adap->id == 0) {
- state->af9013_config[0].ts_mode = AF9013_TS_USB;
- memcpy(state->af9013_config[0].api_version, "\x0\x1\x9\x0", 4);
- state->af9013_config[0].gpio[0] = AF9013_GPIO_HI;
- state->af9013_config[0].gpio[3] = AF9013_GPIO_TUNER_ON;
+ state->af9013_pdata[0].ts_mode = AF9013_TS_MODE_USB;
+ memcpy(state->af9013_pdata[0].api_version, "\x0\x1\x9\x0", 4);
+ state->af9013_pdata[0].gpio[0] = AF9013_GPIO_HI;
+ state->af9013_pdata[0].gpio[3] = AF9013_GPIO_TUNER_ON;
} else if (adap->id == 1) {
- state->af9013_config[1].ts_mode = AF9013_TS_SERIAL;
- memcpy(state->af9013_config[1].api_version, "\x0\x1\x9\x0", 4);
- state->af9013_config[1].gpio[0] = AF9013_GPIO_TUNER_ON;
- state->af9013_config[1].gpio[1] = AF9013_GPIO_LO;
+ state->af9013_pdata[1].ts_mode = AF9013_TS_MODE_SERIAL;
+ state->af9013_pdata[1].ts_output_pin = 7;
+ memcpy(state->af9013_pdata[1].api_version, "\x0\x1\x9\x0", 4);
+ state->af9013_pdata[1].gpio[0] = AF9013_GPIO_TUNER_ON;
+ state->af9013_pdata[1].gpio[1] = AF9013_GPIO_LO;
/* copy firmware to 2nd demodulator */
if (state->dual_mode) {
@@ -833,21 +879,27 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
ret = af9015_copy_firmware(adap_to_d(adap));
if (ret) {
- dev_err(&adap_to_d(adap)->udev->dev,
- "%s: firmware copy to 2nd " \
- "frontend failed, will " \
- "disable it\n", KBUILD_MODNAME);
+ dev_err(&intf->dev,
+ "firmware copy to 2nd frontend failed, will disable it\n");
state->dual_mode = 0;
- return -ENODEV;
+ goto err;
}
} else {
- return -ENODEV;
+ ret = -ENODEV;
+ goto err;
}
}
- /* attach demodulator */
- adap->fe[0] = dvb_attach(af9013_attach,
- &state->af9013_config[adap->id], &adap_to_d(adap)->i2c_adap);
+ /* Add I2C demod */
+ client = dvb_module_probe("af9013", NULL, &d->i2c_adap,
+ state->af9013_i2c_addr[adap->id],
+ &state->af9013_pdata[adap->id]);
+ if (!client) {
+ ret = -ENODEV;
+ goto err;
+ }
+ adap->fe[0] = state->af9013_pdata[adap->id].get_dvb_frontend(client);
+ state->demod_i2c_client[adap->id] = client;
/*
* AF9015 firmware does not like if it gets interrupted by I2C adapter
@@ -857,24 +909,36 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
* those "critical" paths to keep AF9015 happy.
*/
if (adap->fe[0]) {
- state->set_frontend[adap->id] =
- adap->fe[0]->ops.set_frontend;
- adap->fe[0]->ops.set_frontend =
- af9015_af9013_set_frontend;
-
- state->read_status[adap->id] =
- adap->fe[0]->ops.read_status;
- adap->fe[0]->ops.read_status =
- af9015_af9013_read_status;
-
+ state->set_frontend[adap->id] = adap->fe[0]->ops.set_frontend;
+ adap->fe[0]->ops.set_frontend = af9015_af9013_set_frontend;
+ state->read_status[adap->id] = adap->fe[0]->ops.read_status;
+ adap->fe[0]->ops.read_status = af9015_af9013_read_status;
state->init[adap->id] = adap->fe[0]->ops.init;
adap->fe[0]->ops.init = af9015_af9013_init;
-
state->sleep[adap->id] = adap->fe[0]->ops.sleep;
adap->fe[0]->ops.sleep = af9015_af9013_sleep;
}
- return adap->fe[0] == NULL ? -ENODEV : 0;
+ return 0;
+err:
+ dev_dbg(&intf->dev, "failed %d\n", ret);
+ return ret;
+}
+
+static int af9015_frontend_detach(struct dvb_usb_adapter *adap)
+{
+ struct af9015_state *state = adap_to_priv(adap);
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct usb_interface *intf = d->intf;
+ struct i2c_client *client;
+
+ dev_dbg(&intf->dev, "adap id %u\n", adap->id);
+
+ /* Remove I2C demod */
+ client = state->demod_i2c_client[adap->id];
+ dvb_module_release(client);
+
+ return 0;
}
static struct mt2060_config af9015_mt2060_config = {
@@ -944,64 +1008,61 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dvb_usb_device *d = adap_to_d(adap);
struct af9015_state *state = d_to_priv(d);
+ struct usb_interface *intf = d->intf;
+ struct i2c_client *client;
+ struct i2c_adapter *adapter;
int ret;
- dev_dbg(&d->udev->dev, "%s:\n", __func__);
- switch (state->af9013_config[adap->id].tuner) {
+ dev_dbg(&intf->dev, "adap id %u\n", adap->id);
+
+ client = state->demod_i2c_client[adap->id];
+ adapter = state->af9013_pdata[adap->id].get_i2c_adapter(client);
+
+ switch (state->af9013_pdata[adap->id].tuner) {
case AF9013_TUNER_MT2060:
case AF9013_TUNER_MT2060_2:
- ret = dvb_attach(mt2060_attach, adap->fe[0],
- &adap_to_d(adap)->i2c_adap, &af9015_mt2060_config,
- state->mt2060_if1[adap->id])
- == NULL ? -ENODEV : 0;
+ ret = dvb_attach(mt2060_attach, adap->fe[0], adapter,
+ &af9015_mt2060_config,
+ state->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_QT1010:
case AF9013_TUNER_QT1010A:
- ret = dvb_attach(qt1010_attach, adap->fe[0],
- &adap_to_d(adap)->i2c_adap,
- &af9015_qt1010_config) == NULL ? -ENODEV : 0;
+ ret = dvb_attach(qt1010_attach, adap->fe[0], adapter,
+ &af9015_qt1010_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_TDA18271:
- ret = dvb_attach(tda18271_attach, adap->fe[0], 0x60,
- &adap_to_d(adap)->i2c_adap,
- &af9015_tda18271_config) == NULL ? -ENODEV : 0;
+ ret = dvb_attach(tda18271_attach, adap->fe[0], 0x60, adapter,
+ &af9015_tda18271_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_TDA18218:
- ret = dvb_attach(tda18218_attach, adap->fe[0],
- &adap_to_d(adap)->i2c_adap,
- &af9015_tda18218_config) == NULL ? -ENODEV : 0;
+ ret = dvb_attach(tda18218_attach, adap->fe[0], adapter,
+ &af9015_tda18218_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_MXL5003D:
- ret = dvb_attach(mxl5005s_attach, adap->fe[0],
- &adap_to_d(adap)->i2c_adap,
- &af9015_mxl5003_config) == NULL ? -ENODEV : 0;
+ ret = dvb_attach(mxl5005s_attach, adap->fe[0], adapter,
+ &af9015_mxl5003_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_MXL5005D:
case AF9013_TUNER_MXL5005R:
- ret = dvb_attach(mxl5005s_attach, adap->fe[0],
- &adap_to_d(adap)->i2c_adap,
- &af9015_mxl5005_config) == NULL ? -ENODEV : 0;
+ ret = dvb_attach(mxl5005s_attach, adap->fe[0], adapter,
+ &af9015_mxl5005_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_ENV77H11D5:
- ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0x60,
- &adap_to_d(adap)->i2c_adap,
- DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
+ ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, adapter,
+ DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_MC44S803:
- ret = dvb_attach(mc44s803_attach, adap->fe[0],
- &adap_to_d(adap)->i2c_adap,
- &af9015_mc44s803_config) == NULL ? -ENODEV : 0;
+ ret = dvb_attach(mc44s803_attach, adap->fe[0], adapter,
+ &af9015_mc44s803_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_MXL5007T:
- ret = dvb_attach(mxl5007t_attach, adap->fe[0],
- &adap_to_d(adap)->i2c_adap,
- 0x60, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
+ ret = dvb_attach(mxl5007t_attach, adap->fe[0], adapter,
+ 0x60, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_UNKNOWN:
default:
- dev_err(&d->udev->dev, "%s: unknown tuner id=%d\n",
- KBUILD_MODNAME,
- state->af9013_config[adap->id].tuner);
+ dev_err(&intf->dev, "unknown tuner, tuner id %02x\n",
+ state->af9013_pdata[adap->id].tuner);
ret = -ENODEV;
}
@@ -1022,136 +1083,27 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
- struct dvb_usb_device *d = adap_to_d(adap);
- int ret;
- dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
-
- if (onoff)
- ret = af9015_set_reg_bit(d, 0xd503, 0);
- else
- ret = af9015_clear_reg_bit(d, 0xd503, 0);
-
- return ret;
-}
-
-static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
- int onoff)
-{
- struct dvb_usb_device *d = adap_to_d(adap);
+ struct af9015_state *state = adap_to_priv(adap);
+ struct af9013_platform_data *pdata = &state->af9013_pdata[adap->id];
int ret;
- u8 idx;
- dev_dbg(&d->udev->dev, "%s: index=%d pid=%04x onoff=%d\n",
- __func__, index, pid, onoff);
-
- ret = af9015_write_reg(d, 0xd505, (pid & 0xff));
- if (ret)
- goto error;
- ret = af9015_write_reg(d, 0xd506, (pid >> 8));
- if (ret)
- goto error;
-
- idx = ((index & 0x1f) | (1 << 5));
- ret = af9015_write_reg(d, 0xd504, idx);
+ mutex_lock(&state->fe_mutex);
+ ret = pdata->pid_filter_ctrl(adap->fe[0], onoff);
+ mutex_unlock(&state->fe_mutex);
-error:
return ret;
}
-static int af9015_init_endpoint(struct dvb_usb_device *d)
+static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index,
+ u16 pid, int onoff)
{
- struct af9015_state *state = d_to_priv(d);
+ struct af9015_state *state = adap_to_priv(adap);
+ struct af9013_platform_data *pdata = &state->af9013_pdata[adap->id];
int ret;
- u16 frame_size;
- u8 packet_size;
- dev_dbg(&d->udev->dev, "%s: USB speed=%d\n", __func__, d->udev->speed);
-
- if (d->udev->speed == USB_SPEED_FULL) {
- frame_size = TS_USB11_FRAME_SIZE/4;
- packet_size = TS_USB11_MAX_PACKET_SIZE/4;
- } else {
- frame_size = TS_USB20_FRAME_SIZE/4;
- packet_size = TS_USB20_MAX_PACKET_SIZE/4;
- }
-
- ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */
- if (ret)
- goto error;
- ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */
- if (ret)
- goto error;
- ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */
- if (ret)
- goto error;
- ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */
- if (ret)
- goto error;
- ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */
- if (ret)
- goto error;
- if (state->dual_mode) {
- ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */
- if (ret)
- goto error;
- }
- ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */
- if (ret)
- goto error;
- if (state->dual_mode) {
- ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */
- if (ret)
- goto error;
- }
- /* EP4 xfer length */
- ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff);
- if (ret)
- goto error;
- ret = af9015_write_reg(d, 0xdd89, frame_size >> 8);
- if (ret)
- goto error;
- /* EP5 xfer length */
- ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff);
- if (ret)
- goto error;
- ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8);
- if (ret)
- goto error;
- ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */
- if (ret)
- goto error;
- ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */
- if (ret)
- goto error;
- ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */
- if (ret)
- goto error;
- if (state->dual_mode) {
- ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */
- if (ret)
- goto error;
- }
- /* enable / disable mp2if2 */
- if (state->dual_mode) {
- ret = af9015_set_reg_bit(d, 0xd50b, 0);
- if (ret)
- goto error;
- ret = af9015_set_reg_bit(d, 0xd520, 4);
- if (ret)
- goto error;
- } else {
- ret = af9015_clear_reg_bit(d, 0xd50b, 0);
- if (ret)
- goto error;
- ret = af9015_clear_reg_bit(d, 0xd520, 4);
- if (ret)
- goto error;
- }
-
-error:
- if (ret)
- dev_err(&d->udev->dev, "%s: endpoint init failed=%d\n",
- KBUILD_MODNAME, ret);
+ mutex_lock(&state->fe_mutex);
+ ret = pdata->pid_filter(adap->fe[0], index, pid, onoff);
+ mutex_unlock(&state->fe_mutex);
return ret;
}
@@ -1159,17 +1111,15 @@ error:
static int af9015_init(struct dvb_usb_device *d)
{
struct af9015_state *state = d_to_priv(d);
+ struct usb_interface *intf = d->intf;
int ret;
- dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ dev_dbg(&intf->dev, "\n");
mutex_init(&state->fe_mutex);
/* init RC canary */
- ret = af9015_write_reg(d, 0x98e9, 0xff);
- if (ret)
- goto error;
-
- ret = af9015_init_endpoint(d);
+ ret = regmap_write(state->regmap, 0x98e9, 0xff);
if (ret)
goto error;
@@ -1184,7 +1134,7 @@ struct af9015_rc_setup {
};
static char *af9015_rc_setup_match(unsigned int id,
- const struct af9015_rc_setup *table)
+ const struct af9015_rc_setup *table)
{
for (; table->rc_codes; table++)
if (table->id == id)
@@ -1212,24 +1162,25 @@ static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
static int af9015_rc_query(struct dvb_usb_device *d)
{
struct af9015_state *state = d_to_priv(d);
+ struct usb_interface *intf = d->intf;
int ret;
u8 buf[17];
/* read registers needed to detect remote controller code */
- ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf));
+ ret = regmap_bulk_read(state->regmap, 0x98d9, buf, sizeof(buf));
if (ret)
goto error;
/* If any of these are non-zero, assume invalid data */
if (buf[1] || buf[2] || buf[3]) {
- dev_dbg(&d->udev->dev, "%s: invalid data\n", __func__);
+ dev_dbg(&intf->dev, "invalid data\n");
return ret;
}
/* Check for repeat of previous code */
if ((state->rc_repeat != buf[6] || buf[0]) &&
- !memcmp(&buf[12], state->rc_last, 4)) {
- dev_dbg(&d->udev->dev, "%s: key repeated\n", __func__);
+ !memcmp(&buf[12], state->rc_last, 4)) {
+ dev_dbg(&intf->dev, "key repeated\n");
rc_repeat(d->rc_dev);
state->rc_repeat = buf[6];
return ret;
@@ -1238,18 +1189,18 @@ static int af9015_rc_query(struct dvb_usb_device *d)
/* Only process key if canary killed */
if (buf[16] != 0xff && buf[0] != 0x01) {
enum rc_proto proto;
- dev_dbg(&d->udev->dev, "%s: key pressed %*ph\n",
- __func__, 4, buf + 12);
+
+ dev_dbg(&intf->dev, "key pressed %*ph\n", 4, buf + 12);
/* Reset the canary */
- ret = af9015_write_reg(d, 0x98e9, 0xff);
+ ret = regmap_write(state->regmap, 0x98e9, 0xff);
if (ret)
goto error;
/* Remember this key */
memcpy(state->rc_last, &buf[12], 4);
- if (buf[14] == (u8) ~buf[15]) {
- if (buf[12] == (u8) ~buf[13]) {
+ if (buf[14] == (u8)~buf[15]) {
+ if (buf[12] == (u8)~buf[13]) {
/* NEC */
state->rc_keycode = RC_SCANCODE_NEC(buf[12],
buf[14]);
@@ -1271,7 +1222,7 @@ static int af9015_rc_query(struct dvb_usb_device *d)
}
rc_keydown(d->rc_dev, proto, state->rc_keycode, 0);
} else {
- dev_dbg(&d->udev->dev, "%s: no key press\n", __func__);
+ dev_dbg(&intf->dev, "no key press\n");
/* Invalidate last keypress */
/* Not really needed, but helps with debug */
state->rc_last[2] = state->rc_last[3];
@@ -1282,8 +1233,7 @@ static int af9015_rc_query(struct dvb_usb_device *d)
error:
if (ret) {
- dev_warn(&d->udev->dev, "%s: rc query failed=%d\n",
- KBUILD_MODNAME, ret);
+ dev_warn(&intf->dev, "rc query failed %d\n", ret);
/* allow random errors as dvb-usb will stop polling on error */
if (!state->rc_failed)
@@ -1306,29 +1256,33 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
/* try to load remote based module param */
if (!rc->map_name)
rc->map_name = af9015_rc_setup_match(dvb_usb_af9015_remote,
- af9015_rc_setup_modparam);
+ af9015_rc_setup_modparam);
/* try to load remote based eeprom hash */
if (!rc->map_name)
rc->map_name = af9015_rc_setup_match(state->eeprom_sum,
- af9015_rc_setup_hashes);
+ af9015_rc_setup_hashes);
/* try to load remote based USB iManufacturer string */
if (!rc->map_name && vid == USB_VID_AFATECH) {
- /* Check USB manufacturer and product strings and try
- to determine correct remote in case of chip vendor
- reference IDs are used.
- DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */
+ /*
+ * Check USB manufacturer and product strings and try
+ * to determine correct remote in case of chip vendor
+ * reference IDs are used.
+ * DO NOT ADD ANYTHING NEW HERE. Use hashes instead.
+ */
char manufacturer[10];
+
memset(manufacturer, 0, sizeof(manufacturer));
usb_string(d->udev, d->udev->descriptor.iManufacturer,
- manufacturer, sizeof(manufacturer));
+ manufacturer, sizeof(manufacturer));
if (!strcmp("MSI", manufacturer)) {
- /* iManufacturer 1 MSI
- iProduct 2 MSI K-VOX */
- rc->map_name = af9015_rc_setup_match(
- AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
- af9015_rc_setup_modparam);
+ /*
+ * iManufacturer 1 MSI
+ * iProduct 2 MSI K-VOX
+ */
+ rc->map_name = af9015_rc_setup_match(AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+ af9015_rc_setup_modparam);
}
}
@@ -1347,15 +1301,68 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
#define af9015_get_rc_config NULL
#endif
-static int af9015_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
+static int af9015_regmap_write(void *context, const void *data, size_t count)
{
+ struct dvb_usb_device *d = context;
+ struct usb_interface *intf = d->intf;
+ int ret;
+ u16 reg = ((u8 *)data)[0] << 8 | ((u8 *)data)[1] << 0;
+ u8 *val = &((u8 *)data)[2];
+ const unsigned int len = count - 2;
+ struct req_t req = {WRITE_MEMORY, 0, reg, 0, 0, len, val};
+
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ dev_dbg(&intf->dev, "failed %d\n", ret);
+ return ret;
+}
+
+static int af9015_regmap_read(void *context, const void *reg_buf,
+ size_t reg_size, void *val_buf, size_t val_size)
+{
+ struct dvb_usb_device *d = context;
+ struct usb_interface *intf = d->intf;
+ int ret;
+ u16 reg = ((u8 *)reg_buf)[0] << 8 | ((u8 *)reg_buf)[1] << 0;
+ u8 *val = &((u8 *)val_buf)[0];
+ const unsigned int len = val_size;
+ struct req_t req = {READ_MEMORY, 0, reg, 0, 0, len, val};
+
+ ret = af9015_ctrl_msg(d, &req);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ dev_dbg(&intf->dev, "failed %d\n", ret);
+ return ret;
+}
+
+static int af9015_probe(struct dvb_usb_device *d)
+{
+ struct af9015_state *state = d_to_priv(d);
+ struct usb_interface *intf = d->intf;
struct usb_device *udev = interface_to_usbdev(intf);
+ int ret;
char manufacturer[sizeof("ITE Technologies, Inc.")];
+ static const struct regmap_config regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ };
+ static const struct regmap_bus regmap_bus = {
+ .read = af9015_regmap_read,
+ .write = af9015_regmap_write,
+ };
+
+ dev_dbg(&intf->dev, "\n");
memset(manufacturer, 0, sizeof(manufacturer));
usb_string(udev, udev->descriptor.iManufacturer,
- manufacturer, sizeof(manufacturer));
+ manufacturer, sizeof(manufacturer));
/*
* There is two devices having same ID but different chipset. One uses
* AF9015 and the other IT9135 chipset. Only difference seen on lsusb
@@ -1374,19 +1381,41 @@ static int af9015_probe(struct usb_interface *intf,
* iProduct 2 DVB-T TV Stick
*/
if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VID_TERRATEC) &&
- (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) {
+ (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) {
if (!strcmp("ITE Technologies, Inc.", manufacturer)) {
- dev_dbg(&udev->dev, "%s: rejecting device\n", __func__);
- return -ENODEV;
+ ret = -ENODEV;
+ dev_dbg(&intf->dev, "rejecting device\n");
+ goto err;
}
}
- return dvb_usbv2_probe(intf, id);
+ state->regmap = regmap_init(&intf->dev, &regmap_bus, d, &regmap_config);
+ if (IS_ERR(state->regmap)) {
+ ret = PTR_ERR(state->regmap);
+ goto err;
+ }
+
+ return 0;
+err:
+ dev_dbg(&intf->dev, "failed %d\n", ret);
+ return ret;
}
-/* interface 0 is used by DVB-T receiver and
- interface 1 is for remote controller (HID) */
-static struct dvb_usb_device_properties af9015_props = {
+static void af9015_disconnect(struct dvb_usb_device *d)
+{
+ struct af9015_state *state = d_to_priv(d);
+ struct usb_interface *intf = d->intf;
+
+ dev_dbg(&intf->dev, "\n");
+
+ regmap_exit(state->regmap);
+}
+
+/*
+ * Interface 0 is used by DVB-T receiver and
+ * interface 1 is for remote controller (HID)
+ */
+static const struct dvb_usb_device_properties af9015_props = {
.driver_name = KBUILD_MODNAME,
.owner = THIS_MODULE,
.adapter_nr = adapter_nr,
@@ -1395,6 +1424,8 @@ static struct dvb_usb_device_properties af9015_props = {
.generic_bulk_ctrl_endpoint = 0x02,
.generic_bulk_ctrl_endpoint_response = 0x81,
+ .probe = af9015_probe,
+ .disconnect = af9015_disconnect,
.identify_state = af9015_identify_state,
.firmware = AF9015_FIRMWARE,
.download_firmware = af9015_download_firmware,
@@ -1402,10 +1433,12 @@ static struct dvb_usb_device_properties af9015_props = {
.i2c_algo = &af9015_i2c_algo,
.read_config = af9015_read_config,
.frontend_attach = af9015_af9013_frontend_attach,
+ .frontend_detach = af9015_frontend_detach,
.tuner_attach = af9015_tuner_attach,
.init = af9015_init,
.get_rc_config = af9015_get_rc_config,
.get_stream_config = af9015_get_stream_config,
+ .streaming_ctrl = af9015_streaming_ctrl,
.get_adapter_count = af9015_get_adapter_count,
.adapter = {
@@ -1416,9 +1449,15 @@ static struct dvb_usb_device_properties af9015_props = {
.pid_filter = af9015_pid_filter,
.pid_filter_ctrl = af9015_pid_filter_ctrl,
- .stream = DVB_USB_STREAM_BULK(0x84, 8, TS_USB20_FRAME_SIZE),
+ .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
}, {
- .stream = DVB_USB_STREAM_BULK(0x85, 8, TS_USB20_FRAME_SIZE),
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = af9015_pid_filter,
+ .pid_filter_ctrl = af9015_pid_filter_ctrl,
+
+ .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
},
},
};
@@ -1509,7 +1548,7 @@ MODULE_DEVICE_TABLE(usb, af9015_id_table);
static struct usb_driver af9015_usb_driver = {
.name = KBUILD_MODNAME,
.id_table = af9015_id_table,
- .probe = af9015_probe,
+ .probe = dvb_usbv2_probe,
.disconnect = dvb_usbv2_disconnect,
.suspend = dvb_usbv2_suspend,
.resume = dvb_usbv2_resume,
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.h b/drivers/media/usb/dvb-usb-v2/af9015.h
index 3a9d9815ab7a..ad2b045cc39c 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.h
+++ b/drivers/media/usb/dvb-usb-v2/af9015.h
@@ -21,6 +21,7 @@
#define AF9015_H
#include <linux/hash.h>
+#include <linux/regmap.h>
#include "dvb_usb.h"
#include "af9013.h"
#include "dvb-pll.h"
@@ -34,19 +35,6 @@
#define AF9015_FIRMWARE "dvb-usb-af9015.fw"
-/* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0.
- We use smaller - about 1/4 from the original, 5 and 87. */
-#define TS_PACKET_SIZE 188
-
-#define TS_USB20_PACKET_COUNT 87
-#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT)
-
-#define TS_USB11_PACKET_COUNT 5
-#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT)
-
-#define TS_USB20_MAX_PACKET_SIZE 512
-#define TS_USB11_MAX_PACKET_SIZE 64
-
#define AF9015_I2C_EEPROM 0x50
#define AF9015_I2C_DEMOD 0x1c
#define AF9015_USB_TIMEOUT 2000
@@ -113,6 +101,7 @@ enum af9015_ir_mode {
#define BUF_LEN 63
struct af9015_state {
+ struct regmap *regmap;
u8 buf[BUF_LEN]; /* bulk USB control message */
u8 ir_mode;
u8 rc_repeat;
@@ -125,7 +114,10 @@ struct af9015_state {
u16 firmware_size;
u16 firmware_checksum;
u32 eeprom_sum;
- struct af9013_config af9013_config[2];
+ struct af9013_platform_data af9013_pdata[2];
+ struct i2c_client *demod_i2c_client[2];
+ u8 af9013_i2c_addr[2];
+ bool usb_ts_if_configured[2];
/* for demod callback override */
int (*set_frontend[2]) (struct dvb_frontend *fe);
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
index d2e80537b2f7..3fd6cc0d6340 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
@@ -203,6 +203,8 @@ struct dvb_usb_adapter_properties {
* @generic_bulk_ctrl_endpoint_response: bulk control endpoint number for
* receive
* @generic_bulk_ctrl_delay: delay between bulk control sent and receive message
+ * @probe: like probe on driver model
+ * @disconnect: like disconnect on driver model
* @identify_state: called to determine the firmware state (cold or warm) and
* return possible firmware file name to be loaded
* @firmware: name of the firmware file to be loaded
@@ -239,6 +241,8 @@ struct dvb_usb_device_properties {
u8 generic_bulk_ctrl_endpoint_response;
unsigned int generic_bulk_ctrl_delay;
+ int (*probe)(struct dvb_usb_device *);
+ void (*disconnect)(struct dvb_usb_device *);
#define WARM 0
#define COLD 1
int (*identify_state) (struct dvb_usb_device *, const char **);
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 2bf3bd81280a..afdcdbf005e9 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -854,8 +854,6 @@ static int dvb_usbv2_exit(struct dvb_usb_device *d)
dvb_usbv2_remote_exit(d);
dvb_usbv2_adapter_exit(d);
dvb_usbv2_i2c_exit(d);
- kfree(d->priv);
- kfree(d);
return 0;
}
@@ -934,7 +932,7 @@ int dvb_usbv2_probe(struct usb_interface *intf,
if (intf->cur_altsetting->desc.bInterfaceNumber !=
d->props->bInterfaceNumber) {
ret = -ENODEV;
- goto err_free_all;
+ goto err_kfree_d;
}
mutex_init(&d->usb_mutex);
@@ -946,10 +944,16 @@ int dvb_usbv2_probe(struct usb_interface *intf,
dev_err(&d->udev->dev, "%s: kzalloc() failed\n",
KBUILD_MODNAME);
ret = -ENOMEM;
- goto err_free_all;
+ goto err_kfree_d;
}
}
+ if (d->props->probe) {
+ ret = d->props->probe(d);
+ if (ret)
+ goto err_kfree_priv;
+ }
+
if (d->props->identify_state) {
const char *name = NULL;
ret = d->props->identify_state(d, &name);
@@ -1001,6 +1005,12 @@ exit:
return 0;
err_free_all:
dvb_usbv2_exit(d);
+ if (d->props->disconnect)
+ d->props->disconnect(d);
+err_kfree_priv:
+ kfree(d->priv);
+err_kfree_d:
+ kfree(d);
err:
dev_dbg(&udev->dev, "%s: failed=%d\n", __func__, ret);
return ret;
@@ -1021,6 +1031,12 @@ void dvb_usbv2_disconnect(struct usb_interface *intf)
dvb_usbv2_exit(d);
+ if (d->props->disconnect)
+ d->props->disconnect(d);
+
+ kfree(d->priv);
+ kfree(d);
+
pr_info("%s: '%s:%s' successfully deinitialized and disconnected\n",
KBUILD_MODNAME, drvname, devname);
kfree(devname);
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index 2abd15c6df81..387a074ea6ec 100644
--- a/drivers/media/usb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -1243,82 +1243,6 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static int cxusb_mygica_t230c_frontend_attach(struct dvb_usb_adapter *adap)
-{
- struct dvb_usb_device *d = adap->dev;
- struct cxusb_state *st = d->priv;
- struct i2c_adapter *adapter;
- struct i2c_client *client_demod;
- struct i2c_client *client_tuner;
- struct i2c_board_info info;
- struct si2168_config si2168_config;
- struct si2157_config si2157_config;
-
- /* Select required USB configuration */
- if (usb_set_interface(d->udev, 0, 0) < 0)
- err("set interface failed");
-
- /* Unblock all USB pipes */
- usb_clear_halt(d->udev,
- usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
- usb_clear_halt(d->udev,
- usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
- usb_clear_halt(d->udev,
- usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint));
-
- /* attach frontend */
- memset(&si2168_config, 0, sizeof(si2168_config));
- si2168_config.i2c_adapter = &adapter;
- si2168_config.fe = &adap->fe_adap[0].fe;
- si2168_config.ts_mode = SI2168_TS_PARALLEL;
- si2168_config.ts_clock_inv = 1;
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2168", I2C_NAME_SIZE);
- info.addr = 0x64;
- info.platform_data = &si2168_config;
- request_module(info.type);
- client_demod = i2c_new_device(&d->i2c_adap, &info);
- if (client_demod == NULL || client_demod->dev.driver == NULL)
- return -ENODEV;
-
- if (!try_module_get(client_demod->dev.driver->owner)) {
- i2c_unregister_device(client_demod);
- return -ENODEV;
- }
-
- /* attach tuner */
- memset(&si2157_config, 0, sizeof(si2157_config));
- si2157_config.fe = adap->fe_adap[0].fe;
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2141", I2C_NAME_SIZE);
- info.addr = 0x60;
- info.platform_data = &si2157_config;
- request_module("si2157");
- client_tuner = i2c_new_device(adapter, &info);
- if (client_tuner == NULL || client_tuner->dev.driver == NULL) {
- module_put(client_demod->dev.driver->owner);
- i2c_unregister_device(client_demod);
- return -ENODEV;
- }
- if (!try_module_get(client_tuner->dev.driver->owner)) {
- i2c_unregister_device(client_tuner);
- module_put(client_demod->dev.driver->owner);
- i2c_unregister_device(client_demod);
- return -ENODEV;
- }
-
- st->i2c_client_demod = client_demod;
- st->i2c_client_tuner = client_tuner;
-
- /* hook fe: need to resync the slave fifo when signal locks. */
- mutex_init(&st->stream_mutex);
- st->last_lock = 0;
- st->fe_read_status = adap->fe_adap[0].fe->ops.read_status;
- adap->fe_adap[0].fe->ops.read_status = cxusb_read_status;
-
- return 0;
-}
-
/*
* DViCO has shipped two devices with the same USB ID, but only one of them
* needs a firmware download. Check the device class details to see if they
@@ -1401,7 +1325,6 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
static struct dvb_usb_device_properties cxusb_mygica_d689_properties;
static struct dvb_usb_device_properties cxusb_mygica_t230_properties;
-static struct dvb_usb_device_properties cxusb_mygica_t230c_properties;
static int cxusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -1434,8 +1357,6 @@ static int cxusb_probe(struct usb_interface *intf,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &cxusb_mygica_t230_properties,
THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf, &cxusb_mygica_t230c_properties,
- THIS_MODULE, NULL, adapter_nr) ||
0)
return 0;
@@ -1487,7 +1408,6 @@ enum cxusb_table_index {
CONEXANT_D680_DMB,
MYGICA_D689,
MYGICA_T230,
- MYGICA_T230C,
NR__cxusb_table_index
};
@@ -1555,9 +1475,6 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = {
[MYGICA_T230] = {
USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230)
},
- [MYGICA_T230C] = {
- USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230+1)
- },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -2143,7 +2060,7 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
.rc.core = {
.rc_interval = 100,
- .rc_codes = RC_MAP_D680_DMB,
+ .rc_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02,
.module_name = KBUILD_MODNAME,
.rc_query = cxusb_d680_dmb_rc_query,
.allowed_protos = RC_PROTO_BIT_UNKNOWN,
@@ -2252,7 +2169,7 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = {
.rc.core = {
.rc_interval = 100,
- .rc_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02,
+ .rc_codes = RC_MAP_D680_DMB,
.module_name = KBUILD_MODNAME,
.rc_query = cxusb_d680_dmb_rc_query,
.allowed_protos = RC_PROTO_BIT_UNKNOWN,
@@ -2268,60 +2185,6 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = {
}
};
-static struct dvb_usb_device_properties cxusb_mygica_t230c_properties = {
- .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
- .usb_ctrl = CYPRESS_FX2,
-
- .size_of_priv = sizeof(struct cxusb_state),
-
- .num_adapters = 1,
- .adapter = {
- {
- .num_frontends = 1,
- .fe = {{
- .streaming_ctrl = cxusb_streaming_ctrl,
- .frontend_attach = cxusb_mygica_t230c_frontend_attach,
-
- /* parameter for the MPEG2-data transfer */
- .stream = {
- .type = USB_BULK,
- .count = 5,
- .endpoint = 0x02,
- .u = {
- .bulk = {
- .buffersize = 8192,
- }
- }
- },
- } },
- },
- },
-
- .power_ctrl = cxusb_d680_dmb_power_ctrl,
-
- .i2c_algo = &cxusb_i2c_algo,
-
- .generic_bulk_ctrl_endpoint = 0x01,
-
- .rc.core = {
- .rc_interval = 100,
- .rc_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02,
- .module_name = KBUILD_MODNAME,
- .rc_query = cxusb_d680_dmb_rc_query,
- .allowed_protos = RC_PROTO_BIT_UNKNOWN,
- },
-
- .num_device_descs = 1,
- .devices = {
- {
- "Mygica T230C DVB-T/T2/C",
- { NULL },
- { &cxusb_table[MYGICA_T230C], NULL },
- },
- }
-};
-
static struct usb_driver cxusb_driver = {
.name = "dvb_usb_cxusb",
.probe = cxusb_probe,
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 3d99e141d566..c53a969bc6be 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -3412,7 +3412,7 @@ static int novatd_frontend_attach(struct dvb_usb_adapter *adap)
static struct s5h1411_config pinnacle_801e_config = {
.output_mode = S5H1411_PARALLEL_OUTPUT,
.gpio = S5H1411_GPIO_OFF,
- .mpeg_timing = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
+ .mpeg_timing = S5H1411_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK,
.qam_if = S5H1411_IF_44000,
.vsb_if = S5H1411_IF_44000,
.inversion = S5H1411_INVERSION_OFF,
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 4628d73f46f2..8e799ae1df69 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -1,25 +1,25 @@
-/*
- * Empiatech em28x1 audio extension
- *
- * Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
- *
- * Copyright (C) 2007-2016 Mauro Carvalho Chehab
- * - Port to work with the in-kernel driver
- * - Cleanups, fixes, alsa-controls, etc.
- *
- * This driver is based on my previous au600 usb pstn audio driver
- * and inherits all the copyrights
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Empiatech em28x1 audio extension
+//
+// Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
+//
+// Copyright (C) 2007-2016 Mauro Carvalho Chehab
+// - Port to work with the in-kernel driver
+// - Cleanups, fixes, alsa-controls, etc.
+//
+// This driver is based on my previous au600 usb pstn audio driver
+// and inherits all the copyrights
+//
+// 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 "em28xx.h"
@@ -103,7 +103,7 @@ static void em28xx_audio_isocirq(struct urb *urb)
case -ESHUTDOWN:
return;
default: /* error */
- dprintk("urb completition error %d.\n", urb->status);
+ dprintk("urb completion error %d.\n", urb->status);
break;
}
@@ -165,12 +165,11 @@ static void em28xx_audio_isocirq(struct urb *urb)
dev_err(&dev->intf->dev,
"resubmit of audio urb failed (error=%i)\n",
status);
- return;
}
static int em28xx_init_audio_isoc(struct em28xx *dev)
{
- int i, errCode;
+ int i, err;
dprintk("Starting isoc transfers\n");
@@ -179,16 +178,15 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
memset(dev->adev.transfer_buffer[i], 0x80,
dev->adev.urb[i]->transfer_buffer_length);
- errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
- if (errCode) {
+ err = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
+ if (err) {
dev_err(&dev->intf->dev,
"submit of audio urb failed (error=%i)\n",
- errCode);
+ err);
em28xx_deinit_isoc_audio(dev);
atomic_set(&dev->adev.stream_started, 0);
- return errCode;
+ return err;
}
-
}
return 0;
@@ -268,14 +266,17 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
if (nonblock) {
if (!mutex_trylock(&dev->lock))
return -EAGAIN;
- } else
+ } else {
mutex_lock(&dev->lock);
+ }
runtime->hw = snd_em28xx_hw_capture;
if (dev->adev.users == 0) {
- if (dev->alt == 0 || dev->is_audio_only) {
- struct usb_device *udev = interface_to_usbdev(dev->intf);
+ if (!dev->alt || dev->is_audio_only) {
+ struct usb_device *udev;
+
+ udev = interface_to_usbdev(dev->intf);
if (dev->is_audio_only)
/* audio is on a separate interface */
@@ -367,9 +368,11 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
#if 0
- /* TODO: set up em28xx audio chip to deliver the correct audio format,
- current default is 48000hz multiplexed => 96000hz mono
- which shouldn't matter since analogue TV only supports mono */
+ /*
+ * TODO: set up em28xx audio chip to deliver the correct audio format,
+ * current default is 48000hz multiplexed => 96000hz mono
+ * which shouldn't matter since analogue TV only supports mono
+ */
unsigned int channels, rate, format;
format = params_format(hw_params);
@@ -513,8 +516,9 @@ static int em28xx_vol_put(struct snd_kcontrol *kcontrol,
if (nonblock) {
if (!mutex_trylock(&dev->lock))
return -EAGAIN;
- } else
+ } else {
mutex_lock(&dev->lock);
+ }
rc = em28xx_read_ac97(dev, kcontrol->private_value);
if (rc < 0)
goto err;
@@ -551,8 +555,9 @@ static int em28xx_vol_get(struct snd_kcontrol *kcontrol,
if (nonblock) {
if (!mutex_trylock(&dev->lock))
return -EAGAIN;
- } else
+ } else {
mutex_lock(&dev->lock);
+ }
val = em28xx_read_ac97(dev, kcontrol->private_value);
mutex_unlock(&dev->lock);
if (val < 0)
@@ -586,8 +591,9 @@ static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol,
if (nonblock) {
if (!mutex_trylock(&dev->lock))
return -EAGAIN;
- } else
+ } else {
mutex_lock(&dev->lock);
+ }
rc = em28xx_read_ac97(dev, kcontrol->private_value);
if (rc < 0)
goto err;
@@ -627,8 +633,9 @@ static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol,
if (nonblock) {
if (!mutex_trylock(&dev->lock))
return -EAGAIN;
- } else
+ } else {
mutex_lock(&dev->lock);
+ }
val = em28xx_read_ac97(dev, kcontrol->private_value);
mutex_unlock(&dev->lock);
if (val < 0)
@@ -762,7 +769,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev)
if (intf->num_altsetting <= alt) {
dev_err(&dev->intf->dev, "alt %d doesn't exist on interface %d\n",
- dev->ifnum, alt);
+ dev->ifnum, alt);
return -ENODEV;
}
@@ -836,9 +843,8 @@ static int em28xx_audio_urb_init(struct em28xx *dev)
dev->adev.transfer_buffer = kcalloc(num_urb,
sizeof(*dev->adev.transfer_buffer),
GFP_ATOMIC);
- if (!dev->adev.transfer_buffer) {
+ if (!dev->adev.transfer_buffer)
return -ENOMEM;
- }
dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_ATOMIC);
if (!dev->adev.urb) {
@@ -899,9 +905,11 @@ static int em28xx_audio_init(struct em28xx *dev)
int err;
if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) {
- /* This device does not support the extension (in this case
- the device is expecting the snd-usb-audio module or
- doesn't have analog audio support at all) */
+ /*
+ * This device does not support the extension (in this case
+ * the device is expecting the snd-usb-audio module or
+ * doesn't have analog audio support at all)
+ */
return 0;
}
@@ -977,13 +985,15 @@ card_free:
static int em28xx_audio_fini(struct em28xx *dev)
{
- if (dev == NULL)
+ if (!dev)
return 0;
if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) {
- /* This device does not support the extension (in this case
- the device is expecting the snd-usb-audio module or
- doesn't have analog audio support at all) */
+ /*
+ * This device does not support the extension (in this case
+ * the device is expecting the snd-usb-audio module or
+ * doesn't have analog audio support at all)
+ */
return 0;
}
@@ -1005,7 +1015,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
static int em28xx_audio_suspend(struct em28xx *dev)
{
- if (dev == NULL)
+ if (!dev)
return 0;
if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR)
@@ -1019,7 +1029,7 @@ static int em28xx_audio_suspend(struct em28xx *dev)
static int em28xx_audio_resume(struct em28xx *dev)
{
- if (dev == NULL)
+ if (!dev)
return 0;
if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR)
@@ -1050,7 +1060,7 @@ static void __exit em28xx_alsa_unregister(void)
em28xx_unregister_extension(&audio_ops);
}
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_DESCRIPTION(DRIVER_DESC " - audio interface");
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index ae87dd3e671f..3c2694a16ed1 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -1,23 +1,19 @@
-/*
- em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices
-
- Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@infradead.org>
- Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- 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.
-*/
+// SPDX-License-Identifier: GPL-2.0+
+//
+// em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices
+//
+// Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@infradead.org>
+// Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
#include "em28xx.h"
@@ -49,7 +45,7 @@ static int em28xx_initialize_mt9m111(struct em28xx *dev)
{ 0x0d, 0x00, 0x01, }, /* reset and use defaults */
{ 0x0d, 0x00, 0x00, },
{ 0x0a, 0x00, 0x21, },
- { 0x21, 0x04, 0x00, }, /* full readout speed, no row/col skipping */
+ { 0x21, 0x04, 0x00, }, /* full readout spd, no row/col skip */
};
for (i = 0; i < ARRAY_SIZE(regs); i++)
@@ -157,7 +153,8 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)
break;
default:
dev_info(&dev->intf->dev,
- "unknown Micron sensor detected: 0x%04x\n", id);
+ "unknown Micron sensor detected: 0x%04x\n",
+ id);
return 0;
}
@@ -186,8 +183,10 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev)
struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
dev->em28xx_sensor = EM28XX_NOSENSOR;
- /* NOTE: these devices have the register auto incrementation disabled
- * by default, so we have to use single byte reads ! */
+ /*
+ * NOTE: these devices have the register auto incrementation disabled
+ * by default, so we have to use single byte reads !
+ */
for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) {
client->addr = omnivision_sensor_addrs[i];
/* Read manufacturer ID from registers 0x1c-0x1d (BE) */
@@ -397,7 +396,7 @@ int em28xx_init_camera(struct em28xx *dev)
subdev =
v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap,
&ov2640_info, NULL);
- if (subdev == NULL)
+ if (!subdev)
return -ENODEV;
format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 34e16f6ab4ac..6e0e67d23876 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -1,27 +1,23 @@
-/*
- em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB
- video capture devices
-
- Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
- Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@infradead.org>
- Sascha Sommer <saschasommer@freenet.de>
- Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB
+// video capture devices
+//
+// Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+// Markus Rechberger <mrechberger@gmail.com>
+// Mauro Carvalho Chehab <mchehab@infradead.org>
+// Sascha Sommer <saschasommer@freenet.de>
+// Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
#include "em28xx.h"
@@ -40,7 +36,6 @@
#include <media/v4l2-common.h>
#include <sound/ac97_codec.h>
-
#define DRIVER_NAME "em28xx"
static int tuner = -1;
@@ -81,26 +76,26 @@ static void em28xx_pre_card_setup(struct em28xx *dev);
*/
/* Reset for the most [analog] boards */
-static struct em28xx_reg_seq default_analog[] = {
+static const struct em28xx_reg_seq default_analog[] = {
{EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10},
{ -1, -1, -1, -1},
};
/* Reset for the most [digital] boards */
-static struct em28xx_reg_seq default_digital[] = {
+static const struct em28xx_reg_seq default_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10},
{ -1, -1, -1, -1},
};
/* Board Hauppauge WinTV HVR 900 analog */
-static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
+static const struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
{EM2820_R08_GPIO_CTRL, 0x2d, ~EM_GPIO_4, 10},
{ 0x05, 0xff, 0x10, 10},
{ -1, -1, -1, -1},
};
/* Board Hauppauge WinTV HVR 900 digital */
-static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
+static const struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x2e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x04, 0x0f, 10},
{EM2880_R04_GPO, 0x0c, 0x0f, 10},
@@ -108,25 +103,20 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
};
/* Board Hauppauge WinTV HVR 900 (R2) digital */
-static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = {
+static const struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x2e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x0c, 0x0f, 10},
{ -1, -1, -1, -1},
};
/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
-static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
+static const struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
{EM2820_R08_GPIO_CTRL, 0x69, ~EM_GPIO_4, 10},
{ -1, -1, -1, -1},
};
-/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
-
-/* Board - EM2870 Kworld 355u
- Analog - No input analog */
-
/* Board - EM2882 Kworld 315U digital */
-static struct em28xx_reg_seq em2882_kworld_315u_digital[] = {
+static const struct em28xx_reg_seq em2882_kworld_315u_digital[] = {
{EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10},
{EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 10},
{EM2880_R04_GPO, 0x04, 0xff, 10},
@@ -135,7 +125,7 @@ static struct em28xx_reg_seq em2882_kworld_315u_digital[] = {
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
+static const struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
{EM2880_R04_GPO, 0x08, 0xff, 10},
{EM2880_R04_GPO, 0x0c, 0xff, 10},
{EM2880_R04_GPO, 0x08, 0xff, 10},
@@ -143,30 +133,31 @@ static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq kworld_330u_analog[] = {
+static const struct em28xx_reg_seq kworld_330u_analog[] = {
{EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x00, 0xff, 10},
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq kworld_330u_digital[] = {
+static const struct em28xx_reg_seq kworld_330u_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x08, 0xff, 10},
{ -1, -1, -1, -1},
};
-/* Evga inDtube
- GPIO0 - Enable digital power (s5h1409) - low to enable
- GPIO1 - Enable analog power (tvp5150/emp202) - low to enable
- GPIO4 - xc3028 reset
- GOP3 - s5h1409 reset
+/*
+ * Evga inDtube
+ * GPIO0 - Enable digital power (s5h1409) - low to enable
+ * GPIO1 - Enable analog power (tvp5150/emp202) - low to enable
+ * GPIO4 - xc3028 reset
+ * GOP3 - s5h1409 reset
*/
-static struct em28xx_reg_seq evga_indtube_analog[] = {
+static const struct em28xx_reg_seq evga_indtube_analog[] = {
{EM2820_R08_GPIO_CTRL, 0x79, 0xff, 60},
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq evga_indtube_digital[] = {
+static const struct em28xx_reg_seq evga_indtube_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x7a, 0xff, 1},
{EM2880_R04_GPO, 0x04, 0xff, 10},
{EM2880_R04_GPO, 0x0c, 0xff, 1},
@@ -184,12 +175,12 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
* EM_GPIO_6 - currently unknown
* EM_GPIO_7 - currently unknown
*/
-static struct em28xx_reg_seq kworld_a340_digital[] = {
+static const struct em28xx_reg_seq kworld_a340_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10},
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq kworld_ub435q_v3_digital[] = {
+static const struct em28xx_reg_seq kworld_ub435q_v3_digital[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xbe, 0xff, 100},
@@ -198,45 +189,49 @@ static struct em28xx_reg_seq kworld_ub435q_v3_digital[] = {
};
/* Pinnacle Hybrid Pro eb1a:2881 */
-static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
+static const struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
{EM2820_R08_GPIO_CTRL, 0xfd, ~EM_GPIO_4, 10},
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
+static const struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x04, 0xff, 100},/* zl10353 reset */
{EM2880_R04_GPO, 0x0c, 0xff, 1},
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = {
+static const struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = {
{EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x00, 0xff, 10},
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
+static const struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x08, 0xff, 10},
{ -1, -1, -1, -1},
};
-/* PCTV HD Mini (80e) GPIOs
- 0-5: not used
- 6: demod reset, active low
- 7: LED on, active high */
-static struct em28xx_reg_seq em2874_pctv_80e_digital[] = {
+/*
+ * PCTV HD Mini (80e) GPIOs
+ * 0-5: not used
+ * 6: demod reset, active low
+ * 7: LED on, active high
+ */
+static const struct em28xx_reg_seq em2874_pctv_80e_digital[] = {
{EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/
{EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 100},/*Demod reset*/
{EM2874_R80_GPIO_P0_CTRL, 0x40, 0xff, 10},
{ -1, -1, -1, -1},
};
-/* eb1a:2868 Reddo DVB-C USB TV Box
- GPIO4 - CU1216L NIM
- Other GPIOs seems to be don't care. */
-static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = {
+/*
+ * eb1a:2868 Reddo DVB-C USB TV Box
+ * GPIO4 - CU1216L NIM
+ * Other GPIOs seems to be don't care.
+ */
+static const struct em28xx_reg_seq reddo_dvb_c_usb_box[] = {
{EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 10},
{EM2820_R08_GPIO_CTRL, 0xde, 0xff, 10},
{EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 10},
@@ -248,7 +243,7 @@ static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = {
};
/* Callback for the most boards */
-static struct em28xx_reg_seq default_tuner_gpio[] = {
+static const struct em28xx_reg_seq default_tuner_gpio[] = {
{EM2820_R08_GPIO_CTRL, EM_GPIO_4, EM_GPIO_4, 10},
{EM2820_R08_GPIO_CTRL, 0, EM_GPIO_4, 10},
{EM2820_R08_GPIO_CTRL, EM_GPIO_4, EM_GPIO_4, 10},
@@ -256,69 +251,70 @@ static struct em28xx_reg_seq default_tuner_gpio[] = {
};
/* Mute/unmute */
-static struct em28xx_reg_seq compro_unmute_tv_gpio[] = {
+static const struct em28xx_reg_seq compro_unmute_tv_gpio[] = {
{EM2820_R08_GPIO_CTRL, 5, 7, 10},
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq compro_unmute_svid_gpio[] = {
+static const struct em28xx_reg_seq compro_unmute_svid_gpio[] = {
{EM2820_R08_GPIO_CTRL, 4, 7, 10},
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq compro_mute_gpio[] = {
+static const struct em28xx_reg_seq compro_mute_gpio[] = {
{EM2820_R08_GPIO_CTRL, 6, 7, 10},
{ -1, -1, -1, -1},
};
/* Terratec AV350 */
-static struct em28xx_reg_seq terratec_av350_mute_gpio[] = {
+static const struct em28xx_reg_seq terratec_av350_mute_gpio[] = {
{EM2820_R08_GPIO_CTRL, 0xff, 0x7f, 10},
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = {
+static const struct em28xx_reg_seq terratec_av350_unmute_gpio[] = {
{EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10},
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq silvercrest_reg_seq[] = {
+static const struct em28xx_reg_seq silvercrest_reg_seq[] = {
{EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10},
{EM2820_R08_GPIO_CTRL, 0x01, 0xf7, 10},
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq vc211a_enable[] = {
+static const struct em28xx_reg_seq vc211a_enable[] = {
{EM2820_R08_GPIO_CTRL, 0xff, 0x07, 10},
{EM2820_R08_GPIO_CTRL, 0xff, 0x0f, 10},
{EM2820_R08_GPIO_CTRL, 0xff, 0x0b, 10},
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq dikom_dk300_digital[] = {
+static const struct em28xx_reg_seq dikom_dk300_digital[] = {
{EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10},
{EM2880_R04_GPO, 0x08, 0xff, 10},
{ -1, -1, -1, -1},
};
/* Reset for the most [digital] boards */
-static struct em28xx_reg_seq leadership_digital[] = {
+static const struct em28xx_reg_seq leadership_digital[] = {
{EM2874_R80_GPIO_P0_CTRL, 0x70, 0xff, 10},
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq leadership_reset[] = {
+static const struct em28xx_reg_seq leadership_reset[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xf0, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0xb0, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0xf0, 0xff, 10},
{ -1, -1, -1, -1},
};
-/* 2013:024f PCTV nanoStick T2 290e
+/*
+ * 2013:024f PCTV nanoStick T2 290e
* GPIO_6 - demod reset
* GPIO_7 - LED
*/
-static struct em28xx_reg_seq pctv_290e[] = {
+static const struct em28xx_reg_seq pctv_290e[] = {
{EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 80},
{EM2874_R80_GPIO_P0_CTRL, 0x40, 0xff, 80}, /* GPIO_6 = 1 */
{EM2874_R80_GPIO_P0_CTRL, 0xc0, 0xff, 80}, /* GPIO_7 = 1 */
@@ -326,7 +322,7 @@ static struct em28xx_reg_seq pctv_290e[] = {
};
#if 0
-static struct em28xx_reg_seq terratec_h5_gpio[] = {
+static const struct em28xx_reg_seq terratec_h5_gpio[] = {
{EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xf2, 0xff, 50},
@@ -334,7 +330,7 @@ static struct em28xx_reg_seq terratec_h5_gpio[] = {
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq terratec_h5_digital[] = {
+static const struct em28xx_reg_seq terratec_h5_digital[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 10},
@@ -342,7 +338,8 @@ static struct em28xx_reg_seq terratec_h5_digital[] = {
};
#endif
-/* 2013:024f PCTV DVB-S2 Stick 460e
+/*
+ * 2013:024f PCTV DVB-S2 Stick 460e
* GPIO_0 - POWER_ON
* GPIO_1 - BOOST
* GPIO_2 - VUV_LNB (red LED)
@@ -352,7 +349,7 @@ static struct em28xx_reg_seq terratec_h5_digital[] = {
* GPIO_6 - RESET_DEM
* GPIO_7 - LED (green LED)
*/
-static struct em28xx_reg_seq pctv_460e[] = {
+static const struct em28xx_reg_seq pctv_460e[] = {
{EM2874_R80_GPIO_P0_CTRL, 0x01, 0xff, 50},
{ 0x0d, 0xff, 0xff, 50},
{EM2874_R80_GPIO_P0_CTRL, 0x41, 0xff, 50}, /* GPIO_6=1 */
@@ -361,7 +358,7 @@ static struct em28xx_reg_seq pctv_460e[] = {
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
+static const struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0xfd, 0xff, 10}, /* xc5000 reset */
{EM2874_R80_GPIO_P0_CTRL, 0xf9, 0xff, 35},
@@ -384,7 +381,7 @@ static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
* GPIO 6 = #RESET_DEM
* GPIO 7 = P07_LED (green LED)
*/
-static struct em28xx_reg_seq pctv_461e[] = {
+static const struct em28xx_reg_seq pctv_461e[] = {
{EM2874_R80_GPIO_P0_CTRL, 0x7f, 0xff, 0},
{0x0d, 0xff, 0xff, 0},
{EM2874_R80_GPIO_P0_CTRL, 0x3f, 0xff, 100}, /* reset demod */
@@ -396,7 +393,7 @@ static struct em28xx_reg_seq pctv_461e[] = {
};
#if 0
-static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
+static const struct em28xx_reg_seq hauppauge_930c_gpio[] = {
{EM2874_R80_GPIO_P0_CTRL, 0x6f, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0x4f, 0xff, 10}, /* xc5000 reset */
{EM2874_R80_GPIO_P0_CTRL, 0x6f, 0xff, 10},
@@ -404,7 +401,7 @@ static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq hauppauge_930c_digital[] = {
+static const struct em28xx_reg_seq hauppauge_930c_digital[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 10},
@@ -412,38 +409,41 @@ static struct em28xx_reg_seq hauppauge_930c_digital[] = {
};
#endif
-/* 1b80:e425 MaxMedia UB425-TC
+/*
+ * 1b80:e425 MaxMedia UB425-TC
* 1b80:e1cc Delock 61959
* GPIO_6 - demod reset, 0=active
* GPIO_7 - LED, 0=active
*/
-static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
+static const struct em28xx_reg_seq maxmedia_ub425_tc[] = {
{EM2874_R80_GPIO_P0_CTRL, 0x83, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xc3, 0xff, 100}, /* GPIO_6 = 1 */
{EM2874_R80_GPIO_P0_CTRL, 0x43, 0xff, 000}, /* GPIO_7 = 0 */
{ -1, -1, -1, -1},
};
-/* 2304:0242 PCTV QuatroStick (510e)
+/*
+ * 2304:0242 PCTV QuatroStick (510e)
* GPIO_2: decoder reset, 0=active
* GPIO_4: decoder suspend, 0=active
* GPIO_6: demod reset, 0=active
* GPIO_7: LED, 1=active
*/
-static struct em28xx_reg_seq pctv_510e[] = {
+static const struct em28xx_reg_seq pctv_510e[] = {
{EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
{EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
{ -1, -1, -1, -1},
};
-/* 2013:0251 PCTV QuatroStick nano (520e)
+/*
+ * 2013:0251 PCTV QuatroStick nano (520e)
* GPIO_2: decoder reset, 0=active
* GPIO_4: decoder suspend, 0=active
* GPIO_6: demod reset, 0=active
* GPIO_7: LED, 1=active
*/
-static struct em28xx_reg_seq pctv_520e[] = {
+static const struct em28xx_reg_seq pctv_520e[] = {
{EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
{EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
@@ -451,7 +451,8 @@ static struct em28xx_reg_seq pctv_520e[] = {
{ -1, -1, -1, -1},
};
-/* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam
+/*
+ * 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam
* reg 0x80/0x84:
* GPIO_0: capturing LED, 0=on, 1=off
* GPIO_2: AV mute button, 0=pressed, 1=unpressed
@@ -460,13 +461,13 @@ static struct em28xx_reg_seq pctv_520e[] = {
* reg 0x81/0x85:
* GPIO_7: snapshot button, 0=pressed, 1=unpressed
*/
-static struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = {
+static const struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = {
{EM2820_R08_GPIO_CTRL, 0xf7, 0xff, 10},
{EM2874_R80_GPIO_P0_CTRL, 0xff, 0xb2, 10},
{ -1, -1, -1, -1},
};
-static struct em28xx_reg_seq pctv_292e[] = {
+static const struct em28xx_reg_seq pctv_292e[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0},
{0x0d, 0xff, 0xff, 950},
{EM2874_R80_GPIO_P0_CTRL, 0xbd, 0xff, 100},
@@ -478,7 +479,7 @@ static struct em28xx_reg_seq pctv_292e[] = {
{-1, -1, -1, -1},
};
-static struct em28xx_reg_seq terratec_t2_stick_hd[] = {
+static const struct em28xx_reg_seq terratec_t2_stick_hd[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0},
{0x0d, 0xff, 0xff, 600},
{EM2874_R80_GPIO_P0_CTRL, 0xfc, 0xff, 10},
@@ -492,7 +493,7 @@ static struct em28xx_reg_seq terratec_t2_stick_hd[] = {
{-1, -1, -1, -1},
};
-static struct em28xx_reg_seq plex_px_bcud[] = {
+static const struct em28xx_reg_seq plex_px_bcud[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0},
{0x0d, 0xff, 0xff, 0},
{EM2874_R50_IR_CONFIG, 0x01, 0xff, 0},
@@ -507,8 +508,10 @@ static struct em28xx_reg_seq plex_px_bcud[] = {
};
/*
- * 2040:0265 Hauppauge WinTV-dualHD DVB
- * 2040:026d Hauppauge WinTV-dualHD ATSC/QAM
+ * 2040:0265 Hauppauge WinTV-dualHD DVB Isoc
+ * 2040:8265 Hauppauge WinTV-dualHD DVB Bulk
+ * 2040:026d Hauppauge WinTV-dualHD ATSC/QAM Isoc
+ * 2040:826d Hauppauge WinTV-dualHD ATSC/QAM Bulk
* reg 0x80/0x84:
* GPIO_0: Yellow LED tuner 1, 0=on, 1=off
* GPIO_1: Green LED tuner 1, 0=on, 1=off
@@ -517,7 +520,7 @@ static struct em28xx_reg_seq plex_px_bcud[] = {
* GPIO_5: Reset #2, 0=active
* GPIO_6: Reset #1, 0=active
*/
-static struct em28xx_reg_seq hauppauge_dualhd_dvb[] = {
+static const struct em28xx_reg_seq hauppauge_dualhd_dvb[] = {
{EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0},
{0x0d, 0xff, 0xff, 200},
{0x50, 0x04, 0xff, 300},
@@ -534,7 +537,7 @@ static struct em28xx_reg_seq hauppauge_dualhd_dvb[] = {
/*
* Button definitions
*/
-static struct em28xx_button std_snapshot_button[] = {
+static const struct em28xx_button std_snapshot_button[] = {
{
.role = EM28XX_BUTTON_SNAPSHOT,
.reg_r = EM28XX_R0C_USBSUSP,
@@ -545,7 +548,7 @@ static struct em28xx_button std_snapshot_button[] = {
{-1, 0, 0, 0, 0},
};
-static struct em28xx_button speedlink_vad_laplace_buttons[] = {
+static const struct em28xx_button speedlink_vad_laplace_buttons[] = {
{
.role = EM28XX_BUTTON_SNAPSHOT,
.reg_r = EM2874_R85_GPIO_P1_STATE,
@@ -629,7 +632,7 @@ static struct em28xx_led hauppauge_dualhd_leds[] = {
/*
* Board definitions
*/
-struct em28xx_board em28xx_boards[] = {
+const struct em28xx_board em28xx_boards[] = {
[EM2750_BOARD_UNKNOWN] = {
.name = "EM2710/EM2750/EM2751 webcam grabber",
.xclk = EM28XX_XCLK_FREQUENCY_20MHZ,
@@ -1436,9 +1439,11 @@ struct em28xx_board em28xx_boards[] = {
.gpio = default_analog,
} },
},
- /* maybe there's a reason behind it why Terratec sells the Hybrid XS
- as Prodigy XS with a different PID, let's keep it separated for now
- maybe we'll need it lateron */
+ /*
+ * maybe there's a reason behind it why Terratec sells the Hybrid XS
+ * as Prodigy XS with a different PID, let's keep it separated for now
+ * maybe we'll need it later on
+ */
[EM2880_BOARD_TERRATEC_PRODIGY_XS] = {
.name = "Terratec Prodigy XS",
.tuner_type = TUNER_XC2028,
@@ -1782,8 +1787,9 @@ struct em28xx_board em28xx_boards[] = {
.ir_codes = RC_MAP_KWORLD_315U,
.xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE,
- /* Analog mode - still not ready */
- /*.input = { {
+#if 0
+ /* FIXME: Analog mode - still not ready */
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
@@ -1801,7 +1807,8 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_LINE_IN,
.gpio = em2882_kworld_315u_analog1,
.aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
- } }, */
+ } },
+#endif
},
[EM2880_BOARD_EMPIRE_DUAL_TV] = {
.name = "Empire dual TV",
@@ -2162,17 +2169,21 @@ struct em28xx_board em28xx_boards[] = {
.gpio = evga_indtube_analog,
} },
},
- /* eb1a:2868 Empia EM2870 + Philips CU1216L NIM (Philips TDA10023 +
- Infineon TUA6034) */
+ /*
+ * eb1a:2868 Empia EM2870 + Philips CU1216L NIM
+ * (Philips TDA10023 + Infineon TUA6034)
+ */
[EM2870_BOARD_REDDO_DVB_C_USB_BOX] = {
.name = "Reddo DVB-C USB TV Box",
.tuner_type = TUNER_ABSENT,
.tuner_gpio = reddo_dvb_c_usb_box,
.has_dvb = 1,
},
- /* 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold
+ /*
+ * 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold
* initially as the KWorld PlusTV 340U, then as the UB435-Q.
- * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2 */
+ * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2
+ */
[EM2870_BOARD_KWORLD_A340] = {
.name = "KWorld PlusTV 340U or UB435-Q (ATSC)",
.tuner_type = TUNER_ABSENT, /* Digital-only TDA18271HD */
@@ -2180,30 +2191,38 @@ struct em28xx_board em28xx_boards[] = {
.dvb_gpio = kworld_a340_digital,
.tuner_gpio = default_tuner_gpio,
},
- /* 2013:024f PCTV nanoStick T2 290e.
- * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */
+ /*
+ * 2013:024f PCTV nanoStick T2 290e.
+ * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2
+ */
[EM28174_BOARD_PCTV_290E] = {
.name = "PCTV nanoStick T2 290e",
.def_i2c_bus = 1,
- .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ,
.tuner_type = TUNER_ABSENT,
.tuner_gpio = pctv_290e,
.has_dvb = 1,
.ir_codes = RC_MAP_PINNACLE_PCTV_HD,
},
- /* 2013:024f PCTV DVB-S2 Stick 460e
- * Empia EM28174, NXP TDA10071, Conexant CX24118A and Allegro A8293 */
+ /*
+ * 2013:024f PCTV DVB-S2 Stick 460e
+ * Empia EM28174, NXP TDA10071, Conexant CX24118A and Allegro A8293
+ */
[EM28174_BOARD_PCTV_460E] = {
.def_i2c_bus = 1,
- .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_400_KHZ,
.name = "PCTV DVB-S2 Stick (460e)",
.tuner_type = TUNER_ABSENT,
.tuner_gpio = pctv_460e,
.has_dvb = 1,
.ir_codes = RC_MAP_PINNACLE_PCTV_HD,
},
- /* eb1a:5006 Honestech VIDBOX NW03
- * Empia EM2860, Philips SAA7113, Empia EMP202, No Tuner */
+ /*
+ * eb1a:5006 Honestech VIDBOX NW03
+ * Empia EM2860, Philips SAA7113, Empia EMP202, No Tuner
+ */
[EM2860_BOARD_HT_VIDBOX_NW03] = {
.name = "Honestech Vidbox NW03",
.tuner_type = TUNER_ABSENT,
@@ -2214,12 +2233,14 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
- .vmux = SAA7115_SVIDEO3, /* S-VIDEO needs confirming */
+ .vmux = SAA7115_SVIDEO3, /* S-VIDEO needs check */
.amux = EM28XX_AMUX_LINE_IN,
} },
},
- /* 1b80:e425 MaxMedia UB425-TC
- * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 */
+ /*
+ * 1b80:e425 MaxMedia UB425-TC
+ * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2
+ */
[EM2874_BOARD_MAXMEDIA_UB425_TC] = {
.name = "MaxMedia UB425-TC",
.tuner_type = TUNER_ABSENT,
@@ -2230,8 +2251,10 @@ struct em28xx_board em28xx_boards[] = {
.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
- /* 2304:0242 PCTV QuatroStick (510e)
- * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */
+ /*
+ * 2304:0242 PCTV QuatroStick (510e)
+ * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2
+ */
[EM2884_BOARD_PCTV_510E] = {
.name = "PCTV QuatroStick (510e)",
.tuner_type = TUNER_ABSENT,
@@ -2242,8 +2265,10 @@ struct em28xx_board em28xx_boards[] = {
.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
- /* 2013:0251 PCTV QuatroStick nano (520e)
- * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */
+ /*
+ * 2013:0251 PCTV QuatroStick nano (520e)
+ * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2
+ */
[EM2884_BOARD_PCTV_520E] = {
.name = "PCTV QuatroStick nano (520e)",
.tuner_type = TUNER_ABSENT,
@@ -2263,9 +2288,11 @@ struct em28xx_board em28xx_boards[] = {
.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
- /* 1b80:e1cc Delock 61959
+ /*
+ * 1b80:e1cc Delock 61959
* Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2
- * mostly the same as MaxMedia UB-425-TC but different remote */
+ * mostly the same as MaxMedia UB-425-TC but different remote
+ */
[EM2874_BOARD_DELOCK_61959] = {
.name = "Delock 61959",
.tuner_type = TUNER_ABSENT,
@@ -2311,8 +2338,10 @@ struct em28xx_board em28xx_boards[] = {
.ir_codes = RC_MAP_PINNACLE_PCTV_HD,
.leds = pctv_80e_leds,
},
- /* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam
- * Empia EM2765 + OmniVision OV2640 */
+ /*
+ * 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam
+ * Empia EM2765 + OmniVision OV2640
+ */
[EM2765_BOARD_SPEEDLINK_VAD_LAPLACE] = {
.name = "SpeedLink Vicious And Devine Laplace webcam",
.xclk = EM28XX_XCLK_FREQUENCY_24MHZ,
@@ -2329,23 +2358,29 @@ struct em28xx_board em28xx_boards[] = {
.buttons = speedlink_vad_laplace_buttons,
.leds = speedlink_vad_laplace_leds,
},
- /* 2013:0258 PCTV DVB-S2 Stick (461e)
- * Empia EM28178, Montage M88DS3103, Montage M88TS2022, Allegro A8293 */
+ /*
+ * 2013:0258 PCTV DVB-S2 Stick (461e)
+ * Empia EM28178, Montage M88DS3103, Montage M88TS2022, Allegro A8293
+ */
[EM28178_BOARD_PCTV_461E] = {
.def_i2c_bus = 1,
- .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_400_KHZ,
.name = "PCTV DVB-S2 Stick (461e)",
.tuner_type = TUNER_ABSENT,
.tuner_gpio = pctv_461e,
.has_dvb = 1,
.ir_codes = RC_MAP_PINNACLE_PCTV_HD,
},
- /* 2013:025f PCTV tripleStick (292e).
- * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2157 */
+ /*
+ * 2013:025f PCTV tripleStick (292e).
+ * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2157
+ */
[EM28178_BOARD_PCTV_292E] = {
.name = "PCTV tripleStick (292e)",
.def_i2c_bus = 1,
- .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_400_KHZ,
.tuner_type = TUNER_ABSENT,
.tuner_gpio = pctv_292e,
.has_dvb = 1,
@@ -2365,12 +2400,15 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_LINE_IN,
} },
},
- /* eb1a:8179 Terratec Cinergy T2 Stick HD.
- * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2146 */
+ /*
+ * eb1a:8179 Terratec Cinergy T2 Stick HD.
+ * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2146
+ */
[EM28178_BOARD_TERRATEC_T2_STICK_HD] = {
.name = "Terratec Cinergy T2 Stick HD",
.def_i2c_bus = 1,
- .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_400_KHZ,
.tuner_type = TUNER_ABSENT,
.tuner_gpio = terratec_t2_stick_hd,
.has_dvb = 1,
@@ -2391,7 +2429,8 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
},
/*
- * 2040:0265 Hauppauge WinTV-dualHD (DVB version).
+ * 2040:0265 Hauppauge WinTV-dualHD (DVB version) Isoc.
+ * 2040:8265 Hauppauge WinTV-dualHD (DVB version) Bulk.
* Empia EM28274, 2x Silicon Labs Si2168, 2x Silicon Labs Si2157
*/
[EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB] = {
@@ -2402,11 +2441,13 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_gpio = hauppauge_dualhd_dvb,
.has_dvb = 1,
+ .has_dual_ts = 1,
.ir_codes = RC_MAP_HAUPPAUGE,
.leds = hauppauge_dualhd_leds,
},
/*
- * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM).
+ * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Isoc.
+ * 2040:826d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Bulk.
* Empia EM28274, 2x LG LGDT3306A, 2x Silicon Labs Si2157
*/
[EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595] = {
@@ -2417,6 +2458,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_gpio = hauppauge_dualhd_dvb,
.has_dvb = 1,
+ .has_dual_ts = 1,
.ir_codes = RC_MAP_HAUPPAUGE,
.leds = hauppauge_dualhd_leds,
},
@@ -2485,10 +2527,10 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2870_BOARD_KWORLD_355U },
{ USB_DEVICE(0xeb1a, 0xe359),
.driver_info = EM2870_BOARD_KWORLD_355U },
- { USB_DEVICE(0x1b80, 0xe302),
- .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */
- { USB_DEVICE(0x1b80, 0xe304),
- .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kworld DVD Maker 2 */
+ { USB_DEVICE(0x1b80, 0xe302), /* Kaiser Baas Video to DVD maker */
+ .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+ { USB_DEVICE(0x1b80, 0xe304), /* Kworld DVD Maker 2 */
+ .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
{ USB_DEVICE(0x0ccd, 0x0036),
.driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
{ USB_DEVICE(0x0ccd, 0x004c),
@@ -2547,8 +2589,12 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 },
{ USB_DEVICE(0x2040, 0x0265),
.driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB },
+ { USB_DEVICE(0x2040, 0x8265),
+ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB },
{ USB_DEVICE(0x2040, 0x026d),
.driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 },
+ { USB_DEVICE(0x2040, 0x826d),
+ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 },
{ USB_DEVICE(0x0438, 0xb002),
.driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 },
{ USB_DEVICE(0x2001, 0xf112),
@@ -2609,7 +2655,13 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM28178_BOARD_PCTV_461E },
{ USB_DEVICE(0x2013, 0x025f),
.driver_info = EM28178_BOARD_PCTV_292E },
- { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD */
+ { USB_DEVICE(0x2013, 0x0264), /* Hauppauge WinTV-soloHD 292e SE */
+ .driver_info = EM28178_BOARD_PCTV_292E },
+ { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD Isoc */
+ .driver_info = EM28178_BOARD_PCTV_292E },
+ { USB_DEVICE(0x2040, 0x8264), /* Hauppauge OEM Generic WinTV-soloHD Bulk */
+ .driver_info = EM28178_BOARD_PCTV_292E },
+ { USB_DEVICE(0x2040, 0x8268), /* Hauppauge Retail WinTV-soloHD Bulk */
.driver_info = EM28178_BOARD_PCTV_292E },
{ USB_DEVICE(0x0413, 0x6f07),
.driver_info = EM2861_BOARD_LEADTEK_VC100 },
@@ -2626,7 +2678,7 @@ MODULE_DEVICE_TABLE(usb, em28xx_id_table);
/*
* EEPROM hash table for devices with generic USB IDs
*/
-static struct em28xx_hash_table em28xx_eeprom_hash[] = {
+static const struct em28xx_hash_table em28xx_eeprom_hash[] = {
/* P/N: SA 60002070465 Tuner: TVF7533-MF */
{0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
{0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF},
@@ -2639,7 +2691,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = {
};
/* I2C devicelist hash table for devices with generic USB IDs */
-static struct em28xx_hash_table em28xx_i2c_hash[] = {
+static const struct em28xx_hash_table em28xx_i2c_hash[] = {
{0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
{0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT},
@@ -2669,26 +2721,46 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
}
EXPORT_SYMBOL_GPL(em28xx_tuner_callback);
-static inline void em28xx_set_model(struct em28xx *dev)
+static inline void em28xx_set_xclk_i2c_speed(struct em28xx *dev)
{
- dev->board = em28xx_boards[dev->model];
+ const struct em28xx_board *board = &em28xx_boards[dev->model];
+ u8 xclk = board->xclk, i2c_speed = board->i2c_speed;
- /* Those are the default values for the majority of boards
- Use those values if not specified otherwise at boards entry
+ /*
+ * Those are the default values for the majority of boards
+ * Use those values if not specified otherwise at boards entry
*/
- if (!dev->board.xclk)
- dev->board.xclk = EM28XX_XCLK_IR_RC5_MODE |
- EM28XX_XCLK_FREQUENCY_12MHZ;
+ if (!xclk)
+ xclk = EM28XX_XCLK_IR_RC5_MODE |
+ EM28XX_XCLK_FREQUENCY_12MHZ;
+
+ em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk);
- if (!dev->board.i2c_speed)
- dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
- EM28XX_I2C_FREQ_100_KHZ;
+ if (!i2c_speed)
+ i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ;
+
+ dev->i2c_speed = i2c_speed & 0x03;
+
+ if (!dev->board.is_em2800)
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, i2c_speed);
+ msleep(50);
+}
+
+static inline void em28xx_set_model(struct em28xx *dev)
+{
+ dev->board = em28xx_boards[dev->model];
+ dev->has_msp34xx = dev->board.has_msp34xx;
+ dev->is_webcam = dev->board.is_webcam;
+
+ em28xx_set_xclk_i2c_speed(dev);
/* Should be initialized early, for I2C to work */
dev->def_i2c_bus = dev->board.def_i2c_bus;
}
-/* Wait until AC97_RESET reports the expected value reliably before proceeding.
+/*
+ * 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.
@@ -2718,17 +2790,17 @@ static int em28xx_wait_until_ac97_features_equals(struct em28xx *dev,
return -ETIMEDOUT;
}
-/* Since em28xx_pre_card_setup() requires a proper dev->model,
+/*
+ * Since em28xx_pre_card_setup() requires a proper dev->model,
* this won't work for boards with generic PCI IDs
*/
static void em28xx_pre_card_setup(struct em28xx *dev)
{
- /* Set the initial XCLK and I2C clock values based on the board
- definition */
- em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f);
- if (!dev->board.is_em2800)
- em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
- msleep(50);
+ /*
+ * Set the initial XCLK and I2C clock values based on the board
+ * definition
+ */
+ em28xx_set_xclk_i2c_speed(dev);
/* request some modules */
switch (dev->model) {
@@ -2739,17 +2811,19 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
case EM2861_BOARD_KWORLD_PVRTV_300U:
case EM2880_BOARD_KWORLD_DVB_305U:
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0x6d);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0x7d);
- msleep(10);
+ usleep_range(10000, 11000);
break;
case EM2870_BOARD_COMPRO_VIDEOMATE:
- /* TODO: someone can do some cleanup here...
- not everything's needed */
+ /*
+ * TODO: someone can do some cleanup here...
+ * not everything's needed
+ */
em28xx_write_reg(dev, EM2880_R04_GPO, 0x00);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_reg(dev, EM2880_R04_GPO, 0x01);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd);
mdelay(70);
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfc);
@@ -2760,8 +2834,10 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
mdelay(70);
break;
case EM2870_BOARD_TERRATEC_XS_MT2060:
- /* this device needs some gpio writes to get the DVB-T
- demod work */
+ /*
+ * this device needs some gpio writes to get the DVB-T
+ * demod work
+ */
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
mdelay(70);
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xde);
@@ -2770,8 +2846,10 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
mdelay(70);
break;
case EM2870_BOARD_PINNACLE_PCTV_DVB:
- /* this device needs some gpio writes to get the
- DVB-T demod work */
+ /*
+ * this device needs some gpio writes to get the
+ * DVB-T demod work
+ */
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
mdelay(70);
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xde);
@@ -2787,13 +2865,13 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
case EM2882_BOARD_KWORLD_ATSC_315U:
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_reg(dev, EM2880_R04_GPO, 0x00);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_reg(dev, EM2880_R04_GPO, 0x08);
- msleep(10);
+ usleep_range(10000, 11000);
break;
case EM2860_BOARD_KAIOMY_TVNPC_U2:
@@ -2801,11 +2879,11 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
em28xx_write_regs(dev, 0x0d, "\x42", 1);
em28xx_write_regs(dev, 0x08, "\xfd", 1);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_regs(dev, 0x08, "\xff", 1);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_regs(dev, 0x08, "\x7f", 1);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_regs(dev, 0x08, "\x6b", 1);
break;
@@ -2817,7 +2895,7 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
msleep(70);
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfe);
msleep(70);
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd);
@@ -2825,7 +2903,8 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
break;
case EM2860_BOARD_TERRATEC_GRABBY:
- /* HACK?: Ensure AC97 register reading is reliable before
+ /*
+ * 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);
@@ -2843,7 +2922,7 @@ static int em28xx_hint_board(struct em28xx *dev)
{
int i;
- if (dev->board.is_webcam) {
+ if (dev->is_webcam) {
if (dev->em28xx_sensor == EM28XX_MT9V011) {
dev->model = EM2820_BOARD_SILVERCREST_WEBCAM;
} else if (dev->em28xx_sensor == EM28XX_MT9M001 ||
@@ -2855,7 +2934,8 @@ static int em28xx_hint_board(struct em28xx *dev)
return 0;
}
- /* HINT method: EEPROM
+ /*
+ * HINT method: EEPROM
*
* This method works only for boards with eeprom.
* Uses a hash of all eeprom bytes. The hash should be
@@ -2881,7 +2961,8 @@ static int em28xx_hint_board(struct em28xx *dev)
}
}
- /* HINT method: I2C attached devices
+ /*
+ * HINT method: I2C attached devices
*
* This method works for all boards.
* Uses a hash of i2c scanned devices.
@@ -2935,11 +3016,11 @@ static void em28xx_card_setup(struct em28xx *dev)
* If the device can be a webcam, seek for a sensor.
* If sensor is not found, then it isn't a webcam.
*/
- if (dev->board.is_webcam) {
+ if (dev->is_webcam) {
em28xx_detect_sensor(dev);
if (dev->em28xx_sensor == EM28XX_NOSENSOR)
/* NOTE: error/unknown sensor/no sensor */
- dev->board.is_webcam = 0;
+ dev->is_webcam = 0;
}
switch (dev->model) {
@@ -2959,9 +3040,9 @@ static void em28xx_card_setup(struct em28xx *dev)
* This solution is only valid if they do not share eeprom
* hash identities which has not been determined as yet.
*/
- if (em28xx_hint_board(dev) < 0)
+ if (em28xx_hint_board(dev) < 0) {
dev_err(&dev->intf->dev, "Board not discovered\n");
- else {
+ } else {
em28xx_set_model(dev);
em28xx_pre_card_setup(dev);
}
@@ -2971,7 +3052,7 @@ static void em28xx_card_setup(struct em28xx *dev)
}
dev_info(&dev->intf->dev, "Identified as %s (card=%d)\n",
- dev->board.name, dev->model);
+ dev->board.name, dev->model);
dev->tuner_type = em28xx_boards[dev->model].tuner_type;
@@ -2988,7 +3069,7 @@ static void em28xx_card_setup(struct em28xx *dev)
{
struct tveeprom tv;
- if (dev->eedata == NULL)
+ if (!dev->eedata)
break;
#if defined(CONFIG_MODULES) && defined(MODULE)
request_module("tveeprom");
@@ -3001,15 +3082,15 @@ static void em28xx_card_setup(struct em28xx *dev)
if (tv.audio_processor == TVEEPROM_AUDPROC_MSP) {
dev->i2s_speed = 2048000;
- dev->board.has_msp34xx = 1;
+ dev->has_msp34xx = 1;
}
break;
}
case EM2882_BOARD_KWORLD_ATSC_315U:
em28xx_write_reg(dev, 0x0d, 0x42);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xfd);
- msleep(10);
+ usleep_range(10000, 11000);
break;
case EM2820_BOARD_KWORLD_PVRTV2800RF:
/* GPIO enables sound on KWORLD PVR TV 2800RF */
@@ -3034,10 +3115,12 @@ static void em28xx_card_setup(struct em28xx *dev)
if (!em28xx_hint_board(dev))
em28xx_set_model(dev);
- /* In cases where we had to use a board hint, the call to
- em28xx_set_mode() in em28xx_pre_card_setup() was a no-op,
- so make the call now so the analog GPIOs are set properly
- before probing the i2c bus. */
+ /*
+ * In cases where we had to use a board hint, the call to
+ * em28xx_set_mode() in em28xx_pre_card_setup() was a no-op,
+ * so make the call now so the analog GPIOs are set properly
+ * before probing the i2c bus.
+ */
em28xx_gpio_set(dev, dev->board.tuner_gpio);
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
break;
@@ -3059,10 +3142,12 @@ static void em28xx_card_setup(struct em28xx *dev)
if (!em28xx_hint_board(dev))
em28xx_set_model(dev);
- /* In cases where we had to use a board hint, the call to
- em28xx_set_mode() in em28xx_pre_card_setup() was a no-op,
- so make the call now so the analog GPIOs are set properly
- before probing the i2c bus. */
+ /*
+ * In cases where we had to use a board hint, the call to
+ * em28xx_set_mode() in em28xx_pre_card_setup() was a no-op,
+ * so make the call now so the analog GPIOs are set properly
+ * before probing the i2c bus.
+ */
em28xx_gpio_set(dev, dev->board.tuner_gpio);
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
break;
@@ -3147,8 +3232,8 @@ static void request_module_async(struct work_struct *work)
*/
/*
- * Devicdes with an audio-only interface also have a V4L/DVB/RC
- * interface. Don't register extensions twice on those devices.
+ * Devices with an audio-only intf also have a V4L/DVB/RC
+ * intf. Don't register extensions twice on those devices.
*/
if (dev->is_audio_only) {
#if defined(CONFIG_MODULES) && defined(MODULE)
@@ -3209,7 +3294,6 @@ static int em28xx_media_device_init(struct em28xx *dev,
static void em28xx_unregister_media_device(struct em28xx *dev)
{
-
#ifdef CONFIG_MEDIA_CONTROLLER
if (dev->media_dev) {
media_device_unregister(dev->media_dev);
@@ -3224,7 +3308,7 @@ static void em28xx_unregister_media_device(struct em28xx *dev)
* em28xx_release_resources()
* unregisters the v4l2,i2c and usb devices
* called when the device gets disconnected or at module unload
-*/
+ */
static void em28xx_release_resources(struct em28xx *dev)
{
struct usb_device *udev = interface_to_usbdev(dev->intf);
@@ -3239,7 +3323,8 @@ static void em28xx_release_resources(struct em28xx *dev)
em28xx_i2c_unregister(dev, 1);
em28xx_i2c_unregister(dev, 0);
- usb_put_dev(udev);
+ if (dev->ts == PRIMARY_TS)
+ usb_put_dev(udev);
/* Mark device as unused */
clear_bit(dev->devno, em28xx_devused);
@@ -3273,13 +3358,13 @@ EXPORT_SYMBOL_GPL(em28xx_free_device);
* allocates and inits the device structs, registers i2c bus and v4l device
*/
static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
- struct usb_interface *interface,
+ struct usb_interface *intf,
int minor)
{
int retval;
const char *chip_name = NULL;
- dev->intf = interface;
+ dev->intf = intf;
mutex_init(&dev->ctrl_urb_lock);
spin_lock_init(&dev->slock);
@@ -3382,17 +3467,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
em28xx_pre_card_setup(dev);
- if (!dev->board.is_em2800) {
- /* Resets I2C speed */
- retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
- if (retval < 0) {
- dev_err(&dev->intf->dev,
- "%s: em28xx_write_reg failed! retval [%d]\n",
- __func__, retval);
- return retval;
- }
- }
-
rt_mutex_init(&dev->i2c_bus_lock);
/* register i2c bus 0 */
@@ -3417,8 +3491,8 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
EM28XX_I2C_ALGO_EM28XX);
if (retval < 0) {
dev_err(&dev->intf->dev,
- "%s: em28xx_i2c_register bus 1 - error [%d]!\n",
- __func__, retval);
+ "%s: em28xx_i2c_register bus 1 - error [%d]!\n",
+ __func__, retval);
em28xx_i2c_unregister(dev, 0);
@@ -3432,14 +3506,147 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
return 0;
}
+static int em28xx_duplicate_dev(struct em28xx *dev)
+{
+ int nr;
+ struct em28xx *sec_dev = kzalloc(sizeof(*sec_dev), GFP_KERNEL);
+
+ if (!sec_dev) {
+ dev->dev_next = NULL;
+ return -ENOMEM;
+ }
+ memcpy(sec_dev, dev, sizeof(*sec_dev));
+ /* Check to see next free device and mark as used */
+ do {
+ nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS);
+ if (nr >= EM28XX_MAXBOARDS) {
+ /* No free device slots */
+ dev_warn(&dev->intf->dev, ": Supports only %i em28xx boards.\n",
+ EM28XX_MAXBOARDS);
+ kfree(sec_dev);
+ dev->dev_next = NULL;
+ return -ENOMEM;
+ }
+ } while (test_and_set_bit(nr, em28xx_devused));
+ sec_dev->devno = nr;
+ snprintf(sec_dev->name, 28, "em28xx #%d", nr);
+ sec_dev->dev_next = NULL;
+ dev->dev_next = sec_dev;
+ return 0;
+}
+
/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+static void em28xx_check_usb_descriptor(struct em28xx *dev,
+ struct usb_device *udev,
+ struct usb_interface *intf,
+ int alt, int ep,
+ bool *has_vendor_audio,
+ bool *has_video,
+ bool *has_dvb)
+{
+ const struct usb_endpoint_descriptor *e;
+ int sizedescr, size;
+
+ /*
+ * NOTE:
+ *
+ * Old logic with support for isoc transfers only was:
+ * 0x82 isoc => analog
+ * 0x83 isoc => audio
+ * 0x84 isoc => digital
+ *
+ * New logic with support for bulk transfers
+ * 0x82 isoc => analog
+ * 0x82 bulk => analog
+ * 0x83 isoc* => audio
+ * 0x84 isoc => digital
+ * 0x84 bulk => analog or digital**
+ * 0x85 isoc => digital TS2
+ * 0x85 bulk => digital TS2
+ * (*: audio should always be isoc)
+ * (**: analog, if ep 0x82 is isoc, otherwise digital)
+ *
+ * The new logic preserves backwards compatibility and
+ * reflects the endpoint configurations we have seen
+ * so far. But there might be devices for which this
+ * logic is not sufficient...
+ */
+
+ e = &intf->altsetting[alt].endpoint[ep].desc;
+
+ if (!usb_endpoint_dir_in(e))
+ return;
+
+ sizedescr = le16_to_cpu(e->wMaxPacketSize);
+ size = sizedescr & 0x7ff;
+
+ if (udev->speed == USB_SPEED_HIGH)
+ size = size * hb_mult(sizedescr);
+
+ /* Only inspect input endpoints */
+
+ switch (e->bEndpointAddress) {
+ case 0x82:
+ *has_video = true;
+ if (usb_endpoint_xfer_isoc(e)) {
+ dev->analog_ep_isoc = e->bEndpointAddress;
+ dev->alt_max_pkt_size_isoc[alt] = size;
+ } else if (usb_endpoint_xfer_bulk(e)) {
+ dev->analog_ep_bulk = e->bEndpointAddress;
+ }
+ return;
+ case 0x83:
+ if (usb_endpoint_xfer_isoc(e))
+ *has_vendor_audio = true;
+ else
+ dev_err(&intf->dev,
+ "error: skipping audio endpoint 0x83, because it uses bulk transfers !\n");
+ return;
+ case 0x84:
+ if (*has_video && (usb_endpoint_xfer_bulk(e))) {
+ dev->analog_ep_bulk = e->bEndpointAddress;
+ } else {
+ if (usb_endpoint_xfer_isoc(e)) {
+ if (size > dev->dvb_max_pkt_size_isoc) {
+ /*
+ * 2) some manufacturers (e.g. Terratec)
+ * disable endpoints by setting
+ * wMaxPacketSize to 0 bytes for all
+ * alt settings. So far, we've seen
+ * this for DVB isoc endpoints only.
+ */
+ *has_dvb = true;
+ dev->dvb_ep_isoc = e->bEndpointAddress;
+ dev->dvb_max_pkt_size_isoc = size;
+ dev->dvb_alt_isoc = alt;
+ }
+ } else {
+ *has_dvb = true;
+ dev->dvb_ep_bulk = e->bEndpointAddress;
+ }
+ }
+ return;
+ case 0x85:
+ if (usb_endpoint_xfer_isoc(e)) {
+ if (size > dev->dvb_max_pkt_size_isoc_ts2) {
+ dev->dvb_ep_isoc_ts2 = e->bEndpointAddress;
+ dev->dvb_max_pkt_size_isoc_ts2 = size;
+ dev->dvb_alt_isoc = alt;
+ }
+ } else {
+ dev->dvb_ep_bulk_ts2 = e->bEndpointAddress;
+ }
+ return;
+ }
+}
+
/*
* em28xx_usb_probe()
* checks for supported devices
*/
-static int em28xx_usb_probe(struct usb_interface *interface,
+static int em28xx_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev;
@@ -3447,17 +3654,17 @@ static int em28xx_usb_probe(struct usb_interface *interface,
int retval;
bool has_vendor_audio = false, has_video = false, has_dvb = false;
int i, nr, try_bulk;
- const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+ const int ifnum = intf->altsetting[0].desc.bInterfaceNumber;
char *speed;
- udev = usb_get_dev(interface_to_usbdev(interface));
+ udev = usb_get_dev(interface_to_usbdev(intf));
/* Check to see next free device and mark as used */
do {
nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS);
if (nr >= EM28XX_MAXBOARDS) {
/* No free device slots */
- dev_err(&interface->dev,
+ dev_err(&intf->dev,
"Driver supports up to %i em28xx boards.\n",
EM28XX_MAXBOARDS);
retval = -ENOMEM;
@@ -3466,13 +3673,13 @@ static int em28xx_usb_probe(struct usb_interface *interface,
} while (test_and_set_bit(nr, em28xx_devused));
/* Don't register audio interfaces */
- if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
- dev_err(&interface->dev,
+ if (intf->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+ dev_err(&intf->dev,
"audio device (%04x:%04x): interface %i, class %i\n",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct),
ifnum,
- interface->altsetting[0].desc.bInterfaceClass);
+ intf->altsetting[0].desc.bInterfaceClass);
retval = -ENODEV;
goto err;
@@ -3480,106 +3687,33 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
+ if (!dev) {
retval = -ENOMEM;
goto err;
}
/* compute alternate max packet sizes */
- dev->alt_max_pkt_size_isoc =
- kmalloc(sizeof(dev->alt_max_pkt_size_isoc[0]) *
- interface->num_altsetting, GFP_KERNEL);
- if (dev->alt_max_pkt_size_isoc == NULL) {
+ dev->alt_max_pkt_size_isoc = kcalloc(intf->num_altsetting,
+ sizeof(dev->alt_max_pkt_size_isoc[0]),
+ GFP_KERNEL);
+ if (!dev->alt_max_pkt_size_isoc) {
kfree(dev);
retval = -ENOMEM;
goto err;
}
/* Get endpoints */
- for (i = 0; i < interface->num_altsetting; i++) {
+ for (i = 0; i < intf->num_altsetting; i++) {
int ep;
- for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
- const struct usb_endpoint_descriptor *e;
- int sizedescr, size;
-
- e = &interface->altsetting[i].endpoint[ep].desc;
-
- sizedescr = le16_to_cpu(e->wMaxPacketSize);
- size = sizedescr & 0x7ff;
-
- if (udev->speed == USB_SPEED_HIGH)
- size = size * hb_mult(sizedescr);
-
- if (usb_endpoint_dir_in(e)) {
- switch (e->bEndpointAddress) {
- case 0x82:
- has_video = true;
- if (usb_endpoint_xfer_isoc(e)) {
- dev->analog_ep_isoc =
- e->bEndpointAddress;
- dev->alt_max_pkt_size_isoc[i] = size;
- } else if (usb_endpoint_xfer_bulk(e)) {
- dev->analog_ep_bulk =
- e->bEndpointAddress;
- }
- break;
- case 0x83:
- if (usb_endpoint_xfer_isoc(e)) {
- has_vendor_audio = true;
- } else {
- dev_err(&interface->dev,
- "error: skipping audio endpoint 0x83, because it uses bulk transfers !\n");
- }
- break;
- case 0x84:
- if (has_video &&
- (usb_endpoint_xfer_bulk(e))) {
- dev->analog_ep_bulk =
- e->bEndpointAddress;
- } else {
- if (usb_endpoint_xfer_isoc(e)) {
- if (size > dev->dvb_max_pkt_size_isoc) {
- has_dvb = true; /* see NOTE (~) */
- dev->dvb_ep_isoc = e->bEndpointAddress;
- dev->dvb_max_pkt_size_isoc = size;
- dev->dvb_alt_isoc = i;
- }
- } else {
- has_dvb = true;
- dev->dvb_ep_bulk = e->bEndpointAddress;
- }
- }
- break;
- }
- }
- /* NOTE:
- * Old logic with support for isoc transfers only was:
- * 0x82 isoc => analog
- * 0x83 isoc => audio
- * 0x84 isoc => digital
- *
- * New logic with support for bulk transfers
- * 0x82 isoc => analog
- * 0x82 bulk => analog
- * 0x83 isoc* => audio
- * 0x84 isoc => digital
- * 0x84 bulk => analog or digital**
- * (*: audio should always be isoc)
- * (**: analog, if ep 0x82 is isoc, otherwise digital)
- *
- * The new logic preserves backwards compatibility and
- * reflects the endpoint configurations we have seen
- * so far. But there might be devices for which this
- * logic is not sufficient...
- */
- /*
- * NOTE (~): some manufacturers (e.g. Terratec) disable
- * endpoints by setting wMaxPacketSize to 0 bytes for
- * all alt settings. So far, we've seen this for
- * DVB isoc endpoints only.
- */
- }
+ for (ep = 0;
+ ep < intf->altsetting[i].desc.bNumEndpoints;
+ ep++)
+ em28xx_check_usb_descriptor(dev, udev, intf,
+ i, ep,
+ &has_vendor_audio,
+ &has_video,
+ &has_dvb);
}
if (!(has_vendor_audio || has_video || has_dvb)) {
@@ -3602,7 +3736,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
speed = "unknown";
}
- dev_err(&interface->dev,
+ dev_err(&intf->dev,
"New device %s %s @ %s Mbps (%04x:%04x, interface %d, class %d)\n",
udev->manufacturer ? udev->manufacturer : "",
udev->product ? udev->product : "",
@@ -3610,7 +3744,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct),
ifnum,
- interface->altsetting->desc.bInterfaceNumber);
+ intf->altsetting->desc.bInterfaceNumber);
/*
* Make sure we have 480 Mbps of bandwidth, otherwise things like
@@ -3618,8 +3752,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
* not enough even for most Digital TV streams.
*/
if (udev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
- dev_err(&interface->dev, "Device initialization failed.\n");
- dev_err(&interface->dev,
+ dev_err(&intf->dev, "Device initialization failed.\n");
+ dev_err(&intf->dev,
"Device must be connected to a high-speed USB 2.0 port.\n");
retval = -ENODEV;
goto err_free;
@@ -3632,53 +3766,56 @@ static int em28xx_usb_probe(struct usb_interface *interface,
dev->has_video = has_video;
dev->ifnum = ifnum;
+ dev->ts = PRIMARY_TS;
+ snprintf(dev->name, 28, "em28xx");
+ dev->dev_next = NULL;
+
if (has_vendor_audio) {
- dev_err(&interface->dev,
+ dev_err(&intf->dev,
"Audio interface %i found (Vendor Class)\n", ifnum);
dev->usb_audio_type = EM28XX_USB_AUDIO_VENDOR;
}
- /* Checks if audio is provided by a USB Audio Class interface */
+ /* Checks if audio is provided by a USB Audio Class intf */
for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
struct usb_interface *uif = udev->config->interface[i];
if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
if (has_vendor_audio)
- dev_err(&interface->dev,
+ dev_err(&intf->dev,
"em28xx: device seems to have vendor AND usb audio class interfaces !\n"
- "\t\tThe vendor interface will be ignored. Please contact the developers <linux-media@vger.kernel.org>\n");
+ "\t\tThe vendor interface will be ignored. Please contact the developers <linux-media@vger.kernel.org>\n");
dev->usb_audio_type = EM28XX_USB_AUDIO_CLASS;
break;
}
}
if (has_video)
- dev_err(&interface->dev, "Video interface %i found:%s%s\n",
+ dev_err(&intf->dev, "Video interface %i found:%s%s\n",
ifnum,
dev->analog_ep_bulk ? " bulk" : "",
dev->analog_ep_isoc ? " isoc" : "");
if (has_dvb)
- dev_err(&interface->dev, "DVB interface %i found:%s%s\n",
+ dev_err(&intf->dev, "DVB interface %i found:%s%s\n",
ifnum,
dev->dvb_ep_bulk ? " bulk" : "",
dev->dvb_ep_isoc ? " isoc" : "");
- dev->num_alt = interface->num_altsetting;
+ dev->num_alt = intf->num_altsetting;
- if ((unsigned)card[nr] < em28xx_bcount)
+ if ((unsigned int)card[nr] < em28xx_bcount)
dev->model = card[nr];
- /* save our data pointer in this interface device */
- usb_set_intfdata(interface, dev);
+ /* save our data pointer in this intf device */
+ usb_set_intfdata(intf, dev);
/* 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) {
+ retval = em28xx_init_dev(dev, udev, intf, nr);
+ if (retval)
goto err_free;
- }
if (usb_xfer_mode < 0) {
- if (dev->board.is_webcam)
+ if (dev->is_webcam)
try_bulk = 1;
else
try_bulk = 0;
@@ -3690,8 +3827,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
if (has_video &&
dev->board.decoder == EM28XX_NODECODER &&
dev->em28xx_sensor == EM28XX_NOSENSOR) {
-
- dev_err(&interface->dev,
+ dev_err(&intf->dev,
"Currently, V4L2 is not supported on this model\n");
has_video = false;
dev->has_video = false;
@@ -3701,16 +3837,75 @@ static int em28xx_usb_probe(struct usb_interface *interface,
if (has_video) {
if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk))
dev->analog_xfer_bulk = 1;
- dev_err(&interface->dev, "analog set to %s mode.\n",
+ dev_err(&intf->dev, "analog set to %s mode.\n",
dev->analog_xfer_bulk ? "bulk" : "isoc");
}
if (has_dvb) {
if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk))
dev->dvb_xfer_bulk = 1;
- dev_err(&interface->dev, "dvb set to %s mode.\n",
+ dev_err(&intf->dev, "dvb set to %s mode.\n",
dev->dvb_xfer_bulk ? "bulk" : "isoc");
}
+ if (dev->board.has_dual_ts && em28xx_duplicate_dev(dev) == 0) {
+ dev->dev_next->ts = SECONDARY_TS;
+ dev->dev_next->alt = -1;
+ dev->dev_next->is_audio_only = has_vendor_audio &&
+ !(has_video || has_dvb);
+ dev->dev_next->has_video = false;
+ dev->dev_next->ifnum = ifnum;
+ dev->dev_next->model = id->driver_info;
+
+ mutex_init(&dev->dev_next->lock);
+ retval = em28xx_init_dev(dev->dev_next, udev, intf,
+ dev->dev_next->devno);
+ if (retval)
+ goto err_free;
+
+ dev->dev_next->board.ir_codes = NULL; /* No IR for 2nd tuner */
+ dev->dev_next->board.has_ir_i2c = 0; /* No IR for 2nd tuner */
+
+ if (usb_xfer_mode < 0) {
+ if (dev->dev_next->is_webcam)
+ try_bulk = 1;
+ else
+ try_bulk = 0;
+ } else {
+ try_bulk = usb_xfer_mode > 0;
+ }
+
+ /* Select USB transfer types to use */
+ if (has_dvb) {
+ if (!dev->dvb_ep_isoc_ts2 ||
+ (try_bulk && dev->dvb_ep_bulk_ts2))
+ dev->dev_next->dvb_xfer_bulk = 1;
+ dev_info(&dev->intf->dev, "dvb ts2 set to %s mode.\n",
+ dev->dev_next->dvb_xfer_bulk ? "bulk" : "isoc");
+ }
+
+ dev->dev_next->dvb_ep_isoc = dev->dvb_ep_isoc_ts2;
+ dev->dev_next->dvb_ep_bulk = dev->dvb_ep_bulk_ts2;
+ dev->dev_next->dvb_max_pkt_size_isoc = dev->dvb_max_pkt_size_isoc_ts2;
+ dev->dev_next->dvb_alt_isoc = dev->dvb_alt_isoc;
+
+ /* Configuare hardware to support TS2*/
+ if (dev->dvb_xfer_bulk) {
+ /* The ep4 and ep5 are configuared for BULK */
+ em28xx_write_reg(dev, 0x0b, 0x96);
+ mdelay(100);
+ em28xx_write_reg(dev, 0x0b, 0x80);
+ mdelay(100);
+ } else {
+ /* The ep4 and ep5 are configuared for ISO */
+ em28xx_write_reg(dev, 0x0b, 0x96);
+ mdelay(100);
+ em28xx_write_reg(dev, 0x0b, 0x82);
+ mdelay(100);
+ }
+
+ kref_init(&dev->dev_next->ref);
+ }
+
kref_init(&dev->ref);
request_modules(dev);
@@ -3743,45 +3938,59 @@ err_no_slot:
* called when the device gets disconnected
* video device will be unregistered on v4l2_close in case it is still open
*/
-static void em28xx_usb_disconnect(struct usb_interface *interface)
+static void em28xx_usb_disconnect(struct usb_interface *intf)
{
struct em28xx *dev;
- dev = usb_get_intfdata(interface);
- usb_set_intfdata(interface, NULL);
+ dev = usb_get_intfdata(intf);
+ usb_set_intfdata(intf, NULL);
if (!dev)
return;
+ if (dev->dev_next) {
+ dev->dev_next->disconnected = 1;
+ dev_info(&dev->intf->dev, "Disconnecting %s\n",
+ dev->dev_next->name);
+ flush_request_modules(dev->dev_next);
+ }
+
dev->disconnected = 1;
- dev_err(&dev->intf->dev, "Disconnecting\n");
+ dev_err(&dev->intf->dev, "Disconnecting %s\n", dev->name);
flush_request_modules(dev);
em28xx_close_extension(dev);
+ if (dev->dev_next)
+ em28xx_release_resources(dev->dev_next);
em28xx_release_resources(dev);
+
+ if (dev->dev_next) {
+ kref_put(&dev->dev_next->ref, em28xx_free_device);
+ dev->dev_next = NULL;
+ }
kref_put(&dev->ref, em28xx_free_device);
}
-static int em28xx_usb_suspend(struct usb_interface *interface,
+static int em28xx_usb_suspend(struct usb_interface *intf,
pm_message_t message)
{
struct em28xx *dev;
- dev = usb_get_intfdata(interface);
+ dev = usb_get_intfdata(intf);
if (!dev)
return 0;
em28xx_suspend_extension(dev);
return 0;
}
-static int em28xx_usb_resume(struct usb_interface *interface)
+static int em28xx_usb_resume(struct usb_interface *intf)
{
struct em28xx *dev;
- dev = usb_get_intfdata(interface);
+ dev = usb_get_intfdata(intf);
if (!dev)
return 0;
em28xx_resume_extension(dev);
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 1d0d8cc06103..36d341fb65dd 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -1,26 +1,22 @@
-/*
- em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
-
- Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
- Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@infradead.org>
- Sascha Sommer <saschasommer@freenet.de>
- Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+//
+// Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+// Markus Rechberger <mrechberger@gmail.com>
+// Mauro Carvalho Chehab <mchehab@infradead.org>
+// Sascha Sommer <saschasommer@freenet.de>
+// Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
#include "em28xx.h"
@@ -41,7 +37,7 @@
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(EM28XX_VERSION);
/* #define ENABLE_DEBUG_ISOC_FRAMES */
@@ -60,7 +56,6 @@ static unsigned int reg_debug;
module_param(reg_debug, int, 0644);
MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
-
#define em28xx_regdbg(fmt, arg...) do { \
if (reg_debug) \
dev_printk(KERN_DEBUG, &dev->intf->dev, \
@@ -97,10 +92,11 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
0x0000, reg, dev->urb_buf, len, HZ);
if (ret < 0) {
em28xx_regdbg("(pipe 0x%08x): IN: %02x %02x %02x %02x %02x %02x %02x %02x failed with error %i\n",
- pipe, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- req, 0, 0,
- reg & 0xff, reg >> 8,
- len & 0xff, len >> 8, ret);
+ pipe,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ req, 0, 0,
+ reg & 0xff, reg >> 8,
+ len & 0xff, len >> 8, ret);
mutex_unlock(&dev->ctrl_urb_lock);
return usb_translate_errors(ret);
}
@@ -111,10 +107,10 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
mutex_unlock(&dev->ctrl_urb_lock);
em28xx_regdbg("(pipe 0x%08x): IN: %02x %02x %02x %02x %02x %02x %02x %02x <<< %*ph\n",
- pipe, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- req, 0, 0,
- reg & 0xff, reg >> 8,
- len & 0xff, len >> 8, len, buf);
+ pipe, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ req, 0, 0,
+ reg & 0xff, reg >> 8,
+ len & 0xff, len >> 8, len, buf);
return ret;
}
@@ -155,7 +151,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
if (dev->disconnected)
return -ENODEV;
- if ((len < 1) || (len > URB_MAX_CTRL_SIZE))
+ if (len < 1 || len > URB_MAX_CTRL_SIZE)
return -EINVAL;
mutex_lock(&dev->ctrl_urb_lock);
@@ -341,8 +337,9 @@ static int set_ac97_input(struct em28xx *dev)
int ret, i;
enum em28xx_amux amux = dev->ctl_ainput;
- /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that
- em28xx should point to LINE IN, while AC97 should use VIDEO
+ /*
+ * EM28XX_AMUX_VIDEO2 is a special case used to indicate that
+ * em28xx should point to LINE IN, while AC97 should use VIDEO
*/
if (amux == EM28XX_AMUX_VIDEO2)
amux = EM28XX_AMUX_VIDEO;
@@ -378,9 +375,9 @@ static int em28xx_set_audio_source(struct em28xx *dev)
return ret;
}
- if (dev->board.has_msp34xx)
+ if (dev->has_msp34xx) {
input = EM28XX_AUDIO_SRC_TUNER;
- else {
+ } else {
switch (dev->ctl_ainput) {
case EM28XX_AMUX_VIDEO:
input = EM28XX_AUDIO_SRC_TUNER;
@@ -399,7 +396,7 @@ static int em28xx_set_audio_source(struct em28xx *dev)
ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0);
if (ret < 0)
return ret;
- msleep(5);
+ usleep_range(10000, 11000);
switch (dev->audio_mode.ac97) {
case EM28XX_NO_AC97:
@@ -432,8 +429,9 @@ int em28xx_audio_analog_set(struct em28xx *dev)
if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE)
return 0;
- /* It is assumed that all devices use master volume for output.
- It would be possible to use also line output.
+ /*
+ * It is assumed that all devices use master volume for output.
+ * It would be possible to use also line output.
*/
if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
/* Mute all outputs */
@@ -453,7 +451,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk);
if (ret < 0)
return ret;
- msleep(10);
+ usleep_range(10000, 11000);
/* Selects the proper audio input */
ret = em28xx_set_audio_source(dev);
@@ -487,8 +485,10 @@ int em28xx_audio_analog_set(struct em28xx *dev)
if (dev->ctl_aoutput & EM28XX_AOUT_PCM_IN) {
int sel = ac97_return_record_select(dev->ctl_aoutput);
- /* Use the same input for both left and right
- channels */
+ /*
+ * Use the same input for both left and right
+ * channels
+ */
sel |= (sel << 8);
em28xx_write_ac97(dev, AC97_REC_SEL, sel);
@@ -539,7 +539,7 @@ int em28xx_audio_setup(struct em28xx *dev)
else
i2s_samplerates = 3;
dev_info(&dev->intf->dev, "I2S Audio (%d sample rate(s))\n",
- i2s_samplerates);
+ i2s_samplerates);
/* Skip the code that does AC97 vendor detection */
dev->audio_mode.ac97 = EM28XX_NO_AC97;
goto init_audio;
@@ -579,7 +579,7 @@ int em28xx_audio_setup(struct em28xx *dev)
dev_warn(&dev->intf->dev, "AC97 features = 0x%04x\n", feat);
/* Try to identify what audio processor we have */
- if (((vid == 0xffffffff) || (vid == 0x83847650)) && (feat == 0x6a90))
+ if ((vid == 0xffffffff || vid == 0x83847650) && feat == 0x6a90)
dev->audio_mode.ac97 = EM28XX_AC97_EM202;
else if ((vid >> 8) == 0x838476)
dev->audio_mode.ac97 = EM28XX_AC97_SIGMATEL;
@@ -638,10 +638,29 @@ int em28xx_capture_start(struct em28xx *dev, int start)
dev->chip_id == CHIP_ID_EM28174 ||
dev->chip_id == CHIP_ID_EM28178) {
/* The Transport Stream Enable Register moved in em2874 */
- rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
- start ?
- EM2874_TS1_CAPTURE_ENABLE : 0x00,
- EM2874_TS1_CAPTURE_ENABLE);
+ if (dev->dvb_xfer_bulk) {
+ /* Max Tx Size = 188 * 256 = 48128 - LCM(188,512) * 2 */
+ em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ?
+ EM2874_R5D_TS1_PKT_SIZE :
+ EM2874_R5E_TS2_PKT_SIZE,
+ 0xff);
+ } else {
+ /* ISOC Maximum Transfer Size = 188 * 5 */
+ em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ?
+ EM2874_R5D_TS1_PKT_SIZE :
+ EM2874_R5E_TS2_PKT_SIZE,
+ dev->dvb_max_pkt_size_isoc / 188);
+ }
+ if (dev->ts == PRIMARY_TS)
+ rc = em28xx_write_reg_bits(dev,
+ EM2874_R5F_TS_ENABLE,
+ start ? EM2874_TS1_CAPTURE_ENABLE : 0x00,
+ EM2874_TS1_CAPTURE_ENABLE);
+ else
+ rc = em28xx_write_reg_bits(dev,
+ EM2874_R5F_TS_ENABLE,
+ start ? EM2874_TS2_CAPTURE_ENABLE : 0x00,
+ EM2874_TS2_CAPTURE_ENABLE);
} else {
/* FIXME: which is the best order? */
/* video registers are sampled by VREF */
@@ -651,7 +670,7 @@ int em28xx_capture_start(struct em28xx *dev, int start)
return rc;
if (start) {
- if (dev->board.is_webcam)
+ if (dev->is_webcam)
rc = em28xx_write_reg(dev, 0x13, 0x0c);
/* Enable video capture */
@@ -670,7 +689,7 @@ int em28xx_capture_start(struct em28xx *dev, int start)
if (rc < 0)
return rc;
- msleep(6);
+ usleep_range(10000, 11000);
} else {
/* disable video capture */
rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
@@ -691,7 +710,7 @@ int em28xx_capture_start(struct em28xx *dev, int start)
return rc;
}
-int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
+int em28xx_gpio_set(struct em28xx *dev, const struct em28xx_reg_seq *gpio)
{
int rc = 0;
@@ -704,7 +723,7 @@ int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
else
em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
- msleep(6);
+ usleep_range(10000, 11000);
}
/* Send GPIO reset sequences specified at board entry */
@@ -748,9 +767,9 @@ int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
}
EXPORT_SYMBOL_GPL(em28xx_set_mode);
-/* ------------------------------------------------------------------
- URB control
- ------------------------------------------------------------------*/
+/*
+ *URB control
+ */
/*
* URB completion handler for isoc/bulk transfers
@@ -769,7 +788,7 @@ static void em28xx_irq_callback(struct urb *urb)
case -ESHUTDOWN:
return;
default: /* error */
- em28xx_isocdbg("urb completition error %d.\n", urb->status);
+ em28xx_isocdbg("urb completion error %d.\n", urb->status);
break;
}
@@ -800,11 +819,9 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode)
{
struct urb *urb;
struct em28xx_usb_bufs *usb_bufs;
- struct usb_device *udev = interface_to_usbdev(dev->intf);
int i;
- em28xx_isocdbg("em28xx: called em28xx_uninit_usb_xfer in mode %d\n",
- mode);
+ em28xx_isocdbg("called %s in mode %d\n", __func__, mode);
if (mode == EM28XX_DIGITAL_MODE)
usb_bufs = &dev->usb_ctl.digital_bufs;
@@ -819,23 +836,16 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode)
else
usb_unlink_urb(urb);
- if (usb_bufs->transfer_buffer[i]) {
- usb_free_coherent(udev,
- urb->transfer_buffer_length,
- usb_bufs->transfer_buffer[i],
- urb->transfer_dma);
- }
usb_free_urb(urb);
usb_bufs->urb[i] = NULL;
}
- usb_bufs->transfer_buffer[i] = NULL;
}
kfree(usb_bufs->urb);
- kfree(usb_bufs->transfer_buffer);
+ kfree(usb_bufs->buf);
usb_bufs->urb = NULL;
- usb_bufs->transfer_buffer = NULL;
+ usb_bufs->buf = NULL;
usb_bufs->num_bufs = 0;
em28xx_capture_start(dev, 0);
@@ -851,7 +861,7 @@ void em28xx_stop_urbs(struct em28xx *dev)
struct urb *urb;
struct em28xx_usb_bufs *isoc_bufs = &dev->usb_ctl.digital_bufs;
- em28xx_isocdbg("em28xx: called em28xx_stop_urbs\n");
+ em28xx_isocdbg("called %s\n", __func__);
for (i = 0; i < isoc_bufs->num_bufs; i++) {
urb = isoc_bufs->urb[i];
@@ -880,10 +890,12 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
int sb_size, pipe;
int j, k;
- em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode);
+ em28xx_isocdbg("em28xx: called %s in mode %d\n", __func__, mode);
- /* Check mode and if we have an endpoint for the selected
- transfer type, select buffer */
+ /*
+ * Check mode and if we have an endpoint for the selected
+ * transfer type, select buffer
+ */
if (mode == EM28XX_DIGITAL_MODE) {
if ((xfer_bulk && !dev->dvb_ep_bulk) ||
(!xfer_bulk && !dev->dvb_ep_isoc)) {
@@ -912,14 +924,13 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
usb_bufs->num_bufs = num_bufs;
- usb_bufs->urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+ usb_bufs->urb = kcalloc(num_bufs, sizeof(void *), GFP_KERNEL);
if (!usb_bufs->urb)
return -ENOMEM;
- usb_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
- GFP_KERNEL);
- if (!usb_bufs->transfer_buffer) {
- kfree(usb_bufs->urb);
+ usb_bufs->buf = kcalloc(num_bufs, sizeof(void *), GFP_KERNEL);
+ if (!usb_bufs->buf) {
+ kfree(usb_bufs->buf);
return -ENOMEM;
}
@@ -942,37 +953,36 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
}
usb_bufs->urb[i] = urb;
- usb_bufs->transfer_buffer[i] = usb_alloc_coherent(udev,
- sb_size, GFP_KERNEL, &urb->transfer_dma);
- if (!usb_bufs->transfer_buffer[i]) {
- dev_err(&dev->intf->dev,
- "unable to allocate %i bytes for transfer buffer %i%s\n",
- sb_size, i,
- in_interrupt() ? " while in int" : "");
+ usb_bufs->buf[i] = kzalloc(sb_size, GFP_KERNEL);
+ if (!usb_bufs->buf[i]) {
em28xx_uninit_usb_xfer(dev, mode);
+
+ for (i--; i >= 0; i--)
+ kfree(usb_bufs->buf[i]);
+
+ kfree(usb_bufs->buf);
+ usb_bufs->buf = NULL;
+
return -ENOMEM;
}
- memset(usb_bufs->transfer_buffer[i], 0, sb_size);
+
+ urb->transfer_flags = URB_FREE_BUFFER;
if (xfer_bulk) { /* bulk */
pipe = usb_rcvbulkpipe(udev,
mode == EM28XX_ANALOG_MODE ?
dev->analog_ep_bulk :
dev->dvb_ep_bulk);
- usb_fill_bulk_urb(urb, udev, pipe,
- usb_bufs->transfer_buffer[i], sb_size,
- em28xx_irq_callback, dev);
- urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+ usb_fill_bulk_urb(urb, udev, pipe, usb_bufs->buf[i],
+ sb_size, em28xx_irq_callback, dev);
} else { /* isoc */
pipe = usb_rcvisocpipe(udev,
mode == EM28XX_ANALOG_MODE ?
dev->analog_ep_isoc :
dev->dvb_ep_isoc);
- usb_fill_int_urb(urb, udev, pipe,
- usb_bufs->transfer_buffer[i], sb_size,
- em28xx_irq_callback, dev, 1);
- urb->transfer_flags = URB_ISO_ASAP |
- URB_NO_TRANSFER_DMA_MAP;
+ usb_fill_int_urb(urb, udev, pipe, usb_bufs->buf[i],
+ sb_size, em28xx_irq_callback, dev, 1);
+ urb->transfer_flags |= URB_ISO_ASAP;
k = 0;
for (j = 0; j < usb_bufs->num_packets; j++) {
urb->iso_frame_desc[j].offset = k;
@@ -1005,8 +1015,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
int rc;
int alloc;
- em28xx_isocdbg("em28xx: called em28xx_init_usb_xfer in mode %d\n",
- mode);
+ em28xx_isocdbg("em28xx: called %s in mode %d\n", __func__, mode);
dev->usb_ctl.urb_data_copy = urb_data_copy;
@@ -1077,7 +1086,11 @@ int em28xx_register_extension(struct em28xx_ops *ops)
mutex_lock(&em28xx_devlist_mutex);
list_add_tail(&ops->next, &em28xx_extension_devlist);
list_for_each_entry(dev, &em28xx_devlist, devlist) {
- ops->init(dev);
+ if (ops->init) {
+ ops->init(dev);
+ if (dev->dev_next)
+ ops->init(dev->dev_next);
+ }
}
mutex_unlock(&em28xx_devlist_mutex);
pr_info("em28xx: Registered (%s) extension\n", ops->name);
@@ -1091,7 +1104,11 @@ void em28xx_unregister_extension(struct em28xx_ops *ops)
mutex_lock(&em28xx_devlist_mutex);
list_for_each_entry(dev, &em28xx_devlist, devlist) {
- ops->fini(dev);
+ if (ops->fini) {
+ if (dev->dev_next)
+ ops->fini(dev->dev_next);
+ ops->fini(dev);
+ }
}
list_del(&ops->next);
mutex_unlock(&em28xx_devlist_mutex);
@@ -1106,8 +1123,11 @@ void em28xx_init_extension(struct em28xx *dev)
mutex_lock(&em28xx_devlist_mutex);
list_add_tail(&dev->devlist, &em28xx_devlist);
list_for_each_entry(ops, &em28xx_extension_devlist, next) {
- if (ops->init)
+ if (ops->init) {
ops->init(dev);
+ if (dev->dev_next)
+ ops->init(dev->dev_next);
+ }
}
mutex_unlock(&em28xx_devlist_mutex);
}
@@ -1118,8 +1138,11 @@ void em28xx_close_extension(struct em28xx *dev)
mutex_lock(&em28xx_devlist_mutex);
list_for_each_entry(ops, &em28xx_extension_devlist, next) {
- if (ops->fini)
+ if (ops->fini) {
+ if (dev->dev_next)
+ ops->fini(dev->dev_next);
ops->fini(dev);
+ }
}
list_del(&dev->devlist);
mutex_unlock(&em28xx_devlist_mutex);
@@ -1134,6 +1157,8 @@ int em28xx_suspend_extension(struct em28xx *dev)
list_for_each_entry(ops, &em28xx_extension_devlist, next) {
if (ops->suspend)
ops->suspend(dev);
+ if (dev->dev_next)
+ ops->suspend(dev->dev_next);
}
mutex_unlock(&em28xx_devlist_mutex);
return 0;
@@ -1148,6 +1173,8 @@ int em28xx_resume_extension(struct em28xx *dev)
list_for_each_entry(ops, &em28xx_extension_devlist, next) {
if (ops->resume)
ops->resume(dev);
+ if (dev->dev_next)
+ ops->resume(dev->dev_next);
}
mutex_unlock(&em28xx_devlist_mutex);
return 0;
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 8a81c94a8a27..a54cb8dc52c9 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -1,25 +1,25 @@
-/*
- DVB device driver for em28xx
-
- (c) 2008-2011 Mauro Carvalho Chehab <mchehab@infradead.org>
-
- (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
- - Fixes for the driver to properly work with HVR-950
- - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick
- - Fixes for the driver to properly work with AMD ATI TV Wonder HD 600
-
- (c) 2008 Aidan Thornton <makosoft@googlemail.com>
-
- (c) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
-
- Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by:
- (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
- (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
-
- 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// DVB device driver for em28xx
+//
+// (c) 2008-2011 Mauro Carvalho Chehab <mchehab@infradead.org>
+//
+// (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
+// - Fixes for the driver to properly work with HVR-950
+// - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick
+// - Fixes for the driver to properly work with AMD ATI TV Wonder HD 600
+//
+// (c) 2008 Aidan Thornton <makosoft@googlemail.com>
+//
+// (c) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
+//
+// Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by:
+// (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+// (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+//
+// 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 version 2 of the License.
#include "em28xx.h"
@@ -64,7 +64,7 @@
#include "qm1d1c0042.h"
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION(DRIVER_DESC " - digital TV interface");
MODULE_VERSION(EM28XX_VERSION);
@@ -96,7 +96,7 @@ struct em28xx_dvb {
struct dvb_net net;
/* Due to DRX-K - probably need changes */
- int (*gate_ctrl)(struct dvb_frontend *, int);
+ int (*gate_ctrl)(struct dvb_frontend *fe, int gate);
struct semaphore pll_mutex;
bool dont_attach_fe1;
int lna_gpio;
@@ -199,7 +199,6 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
int rc;
struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv;
struct em28xx *dev = i2c_bus->dev;
- struct usb_device *udev = interface_to_usbdev(dev->intf);
int dvb_max_packet_size, packet_multiplier, dvb_alt;
if (dev->dvb_xfer_bulk) {
@@ -218,7 +217,6 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
dvb_alt = dev->dvb_alt_isoc;
}
- usb_set_interface(udev, dev->ifnum, dvb_alt);
rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
if (rc < 0)
return rc;
@@ -278,14 +276,13 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed)
mutex_lock(&dvb->lock);
dvb->nfeeds--;
- if (0 == dvb->nfeeds)
+ if (!dvb->nfeeds)
err = em28xx_stop_streaming(dvb);
mutex_unlock(&dvb->lock);
return err;
}
-
/* ------------------------------------------------------------------ */
static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
{
@@ -358,7 +355,7 @@ static struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
.gpio = S5H1409_GPIO_OFF,
.inversion = S5H1409_INVERSION_OFF,
.status_mode = S5H1409_DEMODLOCKING,
- .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK
};
static struct tda18271_std_map kworld_a340_std_map = {
@@ -514,14 +511,15 @@ static void hauppauge_hvr930c_init(struct em28xx *dev)
em28xx_gpio_set(dev, hauppauge_hvr930c_init);
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
- msleep(10);
+ usleep_range(10000, 11000);
dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
+ regs[i].r, regs[i].len);
em28xx_gpio_set(dev, hauppauge_hvr930c_end);
msleep(100);
@@ -530,8 +528,7 @@ static void hauppauge_hvr930c_init(struct em28xx *dev)
msleep(30);
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45);
- msleep(10);
-
+ usleep_range(10000, 11000);
}
static void terratec_h5_init(struct em28xx *dev)
@@ -571,14 +568,15 @@ static void terratec_h5_init(struct em28xx *dev)
em28xx_gpio_set(dev, terratec_h5_init);
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45);
- msleep(10);
+ usleep_range(10000, 11000);
dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
+ regs[i].r, regs[i].len);
em28xx_gpio_set(dev, terratec_h5_end);
};
@@ -624,14 +622,15 @@ static void terratec_htc_stick_init(struct em28xx *dev)
em28xx_gpio_set(dev, terratec_htc_stick_init);
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
- msleep(10);
+ usleep_range(10000, 11000);
dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
+ regs[i].r, regs[i].len);
em28xx_gpio_set(dev, terratec_htc_stick_end);
};
@@ -682,14 +681,15 @@ static void terratec_htc_usb_xs_init(struct em28xx *dev)
em28xx_gpio_set(dev, terratec_htc_usb_xs_init);
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
- msleep(10);
+ usleep_range(10000, 11000);
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
- msleep(10);
+ usleep_range(10000, 11000);
dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
+ regs[i].r, regs[i].len);
em28xx_gpio_set(dev, terratec_htc_usb_xs_end);
};
@@ -718,7 +718,8 @@ static void pctv_520e_init(struct em28xx *dev)
dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; /* 0x41 */
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
+ regs[i].r, regs[i].len);
};
static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe)
@@ -780,7 +781,7 @@ static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe)
static u8 tuner_go[] = { TUNER_GO, 0x01};
mt352_write(fe, clock_config, sizeof(clock_config));
- udelay(200);
+ usleep_range(200, 250);
mt352_write(fe, reset, sizeof(reset));
mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
mt352_write(fe, agc_cfg, sizeof(agc_cfg));
@@ -840,8 +841,8 @@ static void px_bcud_init(struct em28xx *dev)
/* sleeping ISDB-T */
dev->dvb->i2c_client_demod->addr = 0x14;
for (i = 0; i < ARRAY_SIZE(regs1); i++)
- i2c_master_send(dev->dvb->i2c_client_demod, regs1[i].r,
- regs1[i].len);
+ i2c_master_send(dev->dvb->i2c_client_demod,
+ regs1[i].r, regs1[i].len);
/* sleeping ISDB-S */
dev->dvb->i2c_client_demod->addr = 0x15;
for (i = 0; i < ARRAY_SIZE(regs2); i++)
@@ -934,7 +935,7 @@ static struct lgdt3306a_config hauppauge_01595_lgdt3306a_config = {
/* ------------------------------------------------------------------ */
-static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
+static noinline_for_stack int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
{
struct dvb_frontend *fe;
struct xc2028_config cfg;
@@ -1077,7 +1078,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module,
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))
+ if (!dev->has_video || dev->tuner_type == TUNER_ABSENT)
create_rf_connector = true;
result = dvb_create_media_graph(&dvb->adapter, create_rf_connector);
@@ -1126,10 +1127,285 @@ static void em28xx_unregister_dvb(struct em28xx_dvb *dvb)
dvb_unregister_adapter(&dvb->adapter);
}
+static int em28174_dvb_init_pctv_460e(struct em28xx *dev)
+{
+ struct em28xx_dvb *dvb = dev->dvb;
+ struct tda10071_platform_data tda10071_pdata = {};
+ struct a8293_platform_data a8293_pdata = {};
+
+ /* attach demod + tuner combo */
+ tda10071_pdata.clk = 40444000; /* 40.444 MHz */
+ tda10071_pdata.i2c_wr_max = 64;
+ tda10071_pdata.ts_mode = TDA10071_TS_SERIAL;
+ tda10071_pdata.pll_multiplier = 20;
+ tda10071_pdata.tuner_i2c_addr = 0x14;
+
+ dvb->i2c_client_demod = dvb_module_probe("tda10071", "tda10071_cx24118",
+ &dev->i2c_adap[dev->def_i2c_bus],
+ 0x55, &tda10071_pdata);
+ if (!dvb->i2c_client_demod)
+ return -ENODEV;
+
+ dvb->fe[0] = tda10071_pdata.get_dvb_frontend(dvb->i2c_client_demod);
+
+ /* attach SEC */
+ a8293_pdata.dvb_frontend = dvb->fe[0];
+
+ dvb->i2c_client_sec = dvb_module_probe("a8293", NULL,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ 0x08, &a8293_pdata);
+ if (!dvb->i2c_client_sec) {
+ dvb_module_release(dvb->i2c_client_demod);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int em28178_dvb_init_pctv_461e(struct em28xx *dev)
+{
+ struct em28xx_dvb *dvb = dev->dvb;
+ struct i2c_adapter *i2c_adapter;
+ struct m88ds3103_platform_data m88ds3103_pdata = {};
+ struct ts2020_config ts2020_config = {};
+ struct a8293_platform_data a8293_pdata = {};
+
+ /* attach demod */
+ m88ds3103_pdata.clk = 27000000;
+ m88ds3103_pdata.i2c_wr_max = 33;
+ m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL;
+ m88ds3103_pdata.ts_clk = 16000;
+ m88ds3103_pdata.ts_clk_pol = 1;
+ m88ds3103_pdata.agc = 0x99;
+
+ dvb->i2c_client_demod = dvb_module_probe("m88ds3103", NULL,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ 0x68, &m88ds3103_pdata);
+ if (!dvb->i2c_client_demod)
+ return -ENODEV;
+
+ dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(dvb->i2c_client_demod);
+ i2c_adapter = m88ds3103_pdata.get_i2c_adapter(dvb->i2c_client_demod);
+
+ /* attach tuner */
+ ts2020_config.fe = dvb->fe[0];
+
+ dvb->i2c_client_tuner = dvb_module_probe("ts2020", "ts2022",
+ i2c_adapter,
+ 0x60, &ts2020_config);
+ if (!dvb->i2c_client_tuner) {
+ dvb_module_release(dvb->i2c_client_demod);
+ return -ENODEV;
+ }
+
+ /* delegate signal strength measurement to tuner */
+ dvb->fe[0]->ops.read_signal_strength =
+ dvb->fe[0]->ops.tuner_ops.get_rf_strength;
+
+ /* attach SEC */
+ a8293_pdata.dvb_frontend = dvb->fe[0];
+ dvb->i2c_client_sec = dvb_module_probe("a8293", NULL,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ 0x08, &a8293_pdata);
+ if (!dvb->i2c_client_sec) {
+ dvb_module_release(dvb->i2c_client_tuner);
+ dvb_module_release(dvb->i2c_client_demod);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int em28178_dvb_init_pctv_292e(struct em28xx *dev)
+{
+ struct em28xx_dvb *dvb = dev->dvb;
+ struct i2c_adapter *adapter;
+ struct si2168_config si2168_config = {};
+ struct si2157_config si2157_config = {};
+
+ /* attach demod */
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.fe = &dvb->fe[0];
+ si2168_config.ts_mode = SI2168_TS_PARALLEL;
+ si2168_config.spectral_inversion = true;
+
+ dvb->i2c_client_demod = dvb_module_probe("si2168", NULL,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ 0x64, &si2168_config);
+ if (!dvb->i2c_client_demod)
+ return -ENODEV;
+
+ /* attach tuner */
+ si2157_config.fe = dvb->fe[0];
+ si2157_config.if_port = 1;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ si2157_config.mdev = dev->media_dev;
+#endif
+ dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL,
+ adapter,
+ 0x60, &si2157_config);
+ if (!dvb->i2c_client_tuner) {
+ dvb_module_release(dvb->i2c_client_demod);
+ return -ENODEV;
+ }
+ dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna;
+
+ return 0;
+}
+
+static int em28178_dvb_init_terratec_t2_stick_hd(struct em28xx *dev)
+{
+ struct em28xx_dvb *dvb = dev->dvb;
+ struct i2c_adapter *adapter;
+ struct si2168_config si2168_config = {};
+ struct si2157_config si2157_config = {};
+
+ /* attach demod */
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.fe = &dvb->fe[0];
+ si2168_config.ts_mode = SI2168_TS_PARALLEL;
+
+ dvb->i2c_client_demod = dvb_module_probe("si2168", NULL,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ 0x64, &si2168_config);
+ if (!dvb->i2c_client_demod)
+ return -ENODEV;
+
+ /* attach tuner */
+ 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
+ dvb->i2c_client_tuner = dvb_module_probe("si2157", "si2146",
+ adapter,
+ 0x60, &si2157_config);
+ if (!dvb->i2c_client_tuner) {
+ dvb_module_release(dvb->i2c_client_demod);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int em28178_dvb_init_plex_px_bcud(struct em28xx *dev)
+{
+ struct em28xx_dvb *dvb = dev->dvb;
+ struct tc90522_config tc90522_config = {};
+ struct qm1d1c0042_config qm1d1c0042_config = {};
+
+ /* attach demod */
+ dvb->i2c_client_demod = dvb_module_probe("tc90522", "tc90522sat",
+ &dev->i2c_adap[dev->def_i2c_bus],
+ 0x15, &tc90522_config);
+ if (!dvb->i2c_client_demod)
+ return -ENODEV;
+
+ /* attach tuner */
+ qm1d1c0042_config.fe = tc90522_config.fe;
+ qm1d1c0042_config.lpf = 1;
+
+ dvb->i2c_client_tuner = dvb_module_probe("qm1d1c0042", NULL,
+ tc90522_config.tuner_i2c,
+ 0x61, &qm1d1c0042_config);
+ if (!dvb->i2c_client_tuner) {
+ dvb_module_release(dvb->i2c_client_demod);
+ return -ENODEV;
+ }
+
+ dvb->fe[0] = tc90522_config.fe;
+ px_bcud_init(dev);
+
+ return 0;
+}
+
+static int em28174_dvb_init_hauppauge_wintv_dualhd_dvb(struct em28xx *dev)
+{
+ struct em28xx_dvb *dvb = dev->dvb;
+ struct i2c_adapter *adapter;
+ struct si2168_config si2168_config = {};
+ struct si2157_config si2157_config = {};
+ unsigned char addr;
+
+ /* attach demod */
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.fe = &dvb->fe[0];
+ si2168_config.ts_mode = SI2168_TS_SERIAL;
+ si2168_config.spectral_inversion = true;
+ addr = (dev->ts == PRIMARY_TS) ? 0x64 : 0x67;
+
+ dvb->i2c_client_demod = dvb_module_probe("si2168", NULL,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ addr, &si2168_config);
+ if (!dvb->i2c_client_demod)
+ return -ENODEV;
+
+ /* attach tuner */
+ 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
+ addr = (dev->ts == PRIMARY_TS) ? 0x60 : 0x63;
+
+ dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL,
+ adapter,
+ addr, &si2157_config);
+ if (!dvb->i2c_client_tuner) {
+ dvb_module_release(dvb->i2c_client_demod);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int em28174_dvb_init_hauppauge_wintv_dualhd_01595(struct em28xx *dev)
+{
+ struct em28xx_dvb *dvb = dev->dvb;
+ struct i2c_adapter *adapter;
+ struct lgdt3306a_config lgdt3306a_config = {};
+ struct si2157_config si2157_config = {};
+ unsigned char addr;
+
+ /* attach demod */
+ lgdt3306a_config = hauppauge_01595_lgdt3306a_config;
+ lgdt3306a_config.fe = &dvb->fe[0];
+ lgdt3306a_config.i2c_adapter = &adapter;
+ addr = (dev->ts == PRIMARY_TS) ? 0x59 : 0x0e;
+
+ dvb->i2c_client_demod = dvb_module_probe("lgdt3306a", NULL,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ addr, &lgdt3306a_config);
+ if (!dvb->i2c_client_demod)
+ return -ENODEV;
+
+ /* attach tuner */
+ si2157_config.fe = dvb->fe[0];
+ si2157_config.if_port = 1;
+ si2157_config.inversion = 1;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ si2157_config.mdev = dev->media_dev;
+#endif
+ addr = (dev->ts == PRIMARY_TS) ? 0x60 : 0x62;
+
+ dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL,
+ adapter,
+ 0x60, &si2157_config);
+ if (!dvb->i2c_client_tuner) {
+ dvb_module_release(dvb->i2c_client_demod);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
static int em28xx_dvb_init(struct em28xx *dev)
{
- int result = 0;
+ int result = 0, dvb_alt = 0;
struct em28xx_dvb *dvb;
+ struct usb_device *udev;
if (dev->is_audio_only) {
/* Shouldn't initialize IR for this interface */
@@ -1143,12 +1419,13 @@ static int em28xx_dvb_init(struct em28xx *dev)
dev_info(&dev->intf->dev, "Binding DVB extension\n");
- dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
+ dvb = kzalloc(sizeof(*dvb), GFP_KERNEL);
if (!dvb)
return -ENOMEM;
dev->dvb = dvb;
- dvb->fe[0] = dvb->fe[1] = NULL;
+ dvb->fe[0] = NULL;
+ dvb->fe[1] = NULL;
/* pre-allocate DVB usb transfer buffers */
if (dev->dvb_xfer_bulk) {
@@ -1178,7 +1455,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
switch (dev->model) {
case EM2874_BOARD_LEADERSHIP_ISDBT:
dvb->fe[0] = dvb_attach(s921_attach,
- &sharp_isdbt, &dev->i2c_adap[dev->def_i2c_bus]);
+ &sharp_isdbt,
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
@@ -1191,8 +1469,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
dvb->fe[0] = dvb_attach(lgdt330x_attach,
- &em2880_lgdt3303_dev,
- &dev->i2c_adap[dev->def_i2c_bus]);
+ &em2880_lgdt3303_dev,
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
@@ -1200,8 +1478,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
break;
case EM2880_BOARD_KWORLD_DVB_310U:
dvb->fe[0] = dvb_attach(zl10353_attach,
- &em28xx_zl10353_with_xc3028,
- &dev->i2c_adap[dev->def_i2c_bus]);
+ &em28xx_zl10353_with_xc3028,
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
@@ -1211,8 +1489,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2882_BOARD_TERRATEC_HYBRID_XS:
case EM2880_BOARD_EMPIRE_DUAL_TV:
dvb->fe[0] = dvb_attach(zl10353_attach,
- &em28xx_zl10353_xc3028_no_i2c_gate,
- &dev->i2c_adap[dev->def_i2c_bus]);
+ &em28xx_zl10353_xc3028_no_i2c_gate,
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
@@ -1223,16 +1501,17 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2881_BOARD_PINNACLE_HYBRID_PRO:
case EM2882_BOARD_DIKOM_DK300:
case EM2882_BOARD_KWORLD_VS_DVBT:
+ /*
+ * Those boards could have either a zl10353 or a mt352.
+ * If the chip id isn't for zl10353, try mt352.
+ */
dvb->fe[0] = dvb_attach(zl10353_attach,
- &em28xx_zl10353_xc3028_no_i2c_gate,
- &dev->i2c_adap[dev->def_i2c_bus]);
- if (dvb->fe[0] == NULL) {
- /* This board could have either a zl10353 or a mt352.
- If the chip id isn't for zl10353, try mt352 */
+ &em28xx_zl10353_xc3028_no_i2c_gate,
+ &dev->i2c_adap[dev->def_i2c_bus]);
+ if (!dvb->fe[0])
dvb->fe[0] = dvb_attach(mt352_attach,
- &terratec_xs_mt352_cfg,
- &dev->i2c_adap[dev->def_i2c_bus]);
- }
+ &terratec_xs_mt352_cfg,
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
@@ -1241,27 +1520,28 @@ static int em28xx_dvb_init(struct em28xx *dev)
break;
case EM2870_BOARD_TERRATEC_XS_MT2060:
dvb->fe[0] = dvb_attach(zl10353_attach,
- &em28xx_zl10353_no_i2c_gate_dev,
- &dev->i2c_adap[dev->def_i2c_bus]);
- if (dvb->fe[0] != NULL) {
+ &em28xx_zl10353_no_i2c_gate_dev,
+ &dev->i2c_adap[dev->def_i2c_bus]);
+ if (dvb->fe[0]) {
dvb_attach(mt2060_attach, dvb->fe[0],
- &dev->i2c_adap[dev->def_i2c_bus],
- &em28xx_mt2060_config, 1220);
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &em28xx_mt2060_config, 1220);
}
break;
case EM2870_BOARD_KWORLD_355U:
dvb->fe[0] = dvb_attach(zl10353_attach,
- &em28xx_zl10353_no_i2c_gate_dev,
- &dev->i2c_adap[dev->def_i2c_bus]);
- if (dvb->fe[0] != NULL)
+ &em28xx_zl10353_no_i2c_gate_dev,
+ &dev->i2c_adap[dev->def_i2c_bus]);
+ if (dvb->fe[0])
dvb_attach(qt1010_attach, dvb->fe[0],
- &dev->i2c_adap[dev->def_i2c_bus], &em28xx_qt1010_config);
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &em28xx_qt1010_config);
break;
case EM2883_BOARD_KWORLD_HYBRID_330U:
case EM2882_BOARD_EVGA_INDTUBE:
dvb->fe[0] = dvb_attach(s5h1409_attach,
- &em28xx_s5h1409_with_xc3028,
- &dev->i2c_adap[dev->def_i2c_bus]);
+ &em28xx_s5h1409_with_xc3028,
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
@@ -1269,9 +1549,9 @@ static int em28xx_dvb_init(struct em28xx *dev)
break;
case EM2882_BOARD_KWORLD_ATSC_315U:
dvb->fe[0] = dvb_attach(lgdt330x_attach,
- &em2880_lgdt3303_dev,
- &dev->i2c_adap[dev->def_i2c_bus]);
- if (dvb->fe[0] != NULL) {
+ &em2880_lgdt3303_dev,
+ &dev->i2c_adap[dev->def_i2c_bus]);
+ if (dvb->fe[0]) {
if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
&dev->i2c_adap[dev->def_i2c_bus],
0x61, TUNER_THOMSON_DTT761X)) {
@@ -1293,8 +1573,9 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2870_BOARD_REDDO_DVB_C_USB_BOX:
/* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */
dvb->fe[0] = dvb_attach(tda10023_attach,
- &em28xx_tda10023_config,
- &dev->i2c_adap[dev->def_i2c_bus], 0x48);
+ &em28xx_tda10023_config,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ 0x48);
if (dvb->fe[0]) {
if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
&dev->i2c_adap[dev->def_i2c_bus],
@@ -1306,18 +1587,18 @@ static int em28xx_dvb_init(struct em28xx *dev)
break;
case EM2870_BOARD_KWORLD_A340:
dvb->fe[0] = dvb_attach(lgdt3305_attach,
- &em2870_lgdt3304_dev,
- &dev->i2c_adap[dev->def_i2c_bus]);
+ &em2870_lgdt3304_dev,
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
}
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
&dev->i2c_adap[dev->def_i2c_bus],
- &kworld_a340_config)) {
- dvb_frontend_detach(dvb->fe[0]);
- result = -EINVAL;
- goto out_free;
+ &kworld_a340_config)) {
+ dvb_frontend_detach(dvb->fe[0]);
+ result = -EINVAL;
+ goto out_free;
}
break;
case EM28174_BOARD_PCTV_290E:
@@ -1335,7 +1616,6 @@ static int em28xx_dvb_init(struct em28xx *dev)
0x60,
&dev->i2c_adap[dev->def_i2c_bus],
&em28xx_cxd2820r_tda18271_config)) {
-
dvb_frontend_detach(dvb->fe[0]);
result = -EINVAL;
goto out_free;
@@ -1360,12 +1640,13 @@ static int em28xx_dvb_init(struct em28xx *dev)
break;
case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C:
{
- struct xc5000_config cfg;
+ struct xc5000_config cfg = {};
hauppauge_hvr930c_init(dev);
dvb->fe[0] = dvb_attach(drxk_attach,
- &hauppauge_930c_drxk, &dev->i2c_adap[dev->def_i2c_bus]);
+ &hauppauge_930c_drxk,
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
@@ -1377,14 +1658,13 @@ static int em28xx_dvb_init(struct em28xx *dev)
dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
/* Attach xc5000 */
- memset(&cfg, 0, sizeof(cfg));
cfg.i2c_address = 0x61;
cfg.if_khz = 4000;
if (dvb->fe[0]->ops.i2c_gate_ctrl)
dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
- if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus],
- &cfg)) {
+ if (!dvb_attach(xc5000_attach, dvb->fe[0],
+ &dev->i2c_adap[dev->def_i2c_bus], &cfg)) {
result = -EINVAL;
goto out_free;
}
@@ -1396,7 +1676,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2884_BOARD_TERRATEC_H5:
terratec_h5_init(dev);
- dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap[dev->def_i2c_bus]);
+ dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk,
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
@@ -1410,7 +1691,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* Attach tda18271 to DVB-C frontend */
if (dvb->fe[0]->ops.i2c_gate_ctrl)
dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
- if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], 0x60)) {
+ if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0],
+ &dev->i2c_adap[dev->def_i2c_bus], 0x60)) {
result = -EINVAL;
goto out_free;
}
@@ -1420,72 +1702,23 @@ static int em28xx_dvb_init(struct em28xx *dev)
break;
case EM2884_BOARD_C3TECH_DIGITAL_DUO:
dvb->fe[0] = dvb_attach(mb86a20s_attach,
- &c3tech_duo_mb86a20s_config,
- &dev->i2c_adap[dev->def_i2c_bus]);
- if (dvb->fe[0] != NULL)
+ &c3tech_duo_mb86a20s_config,
+ &dev->i2c_adap[dev->def_i2c_bus]);
+ if (dvb->fe[0])
dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
&dev->i2c_adap[dev->def_i2c_bus],
&c3tech_duo_tda18271_config);
break;
- case EM28174_BOARD_PCTV_460E: {
- struct i2c_client *client;
- struct i2c_board_info board_info;
- struct tda10071_platform_data tda10071_pdata = {};
- struct a8293_platform_data a8293_pdata = {};
-
- /* attach demod + tuner combo */
- tda10071_pdata.clk = 40444000, /* 40.444 MHz */
- tda10071_pdata.i2c_wr_max = 64,
- tda10071_pdata.ts_mode = TDA10071_TS_SERIAL,
- tda10071_pdata.pll_multiplier = 20,
- tda10071_pdata.tuner_i2c_addr = 0x14,
- memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "tda10071_cx24118", I2C_NAME_SIZE);
- board_info.addr = 0x55;
- board_info.platform_data = &tda10071_pdata;
- request_module("tda10071");
- client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
- if (client == NULL || client->dev.driver == NULL) {
- result = -ENODEV;
+ case EM28174_BOARD_PCTV_460E:
+ result = em28174_dvb_init_pctv_460e(dev);
+ if (result)
goto out_free;
- }
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- result = -ENODEV;
- goto out_free;
- }
- dvb->fe[0] = tda10071_pdata.get_dvb_frontend(client);
- dvb->i2c_client_demod = client;
-
- /* attach SEC */
- a8293_pdata.dvb_frontend = dvb->fe[0];
- memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "a8293", I2C_NAME_SIZE);
- board_info.addr = 0x08;
- board_info.platform_data = &a8293_pdata;
- request_module("a8293");
- client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
- if (client == NULL || client->dev.driver == NULL) {
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
- dvb->i2c_client_sec = client;
break;
- }
case EM2874_BOARD_DELOCK_61959:
case EM2874_BOARD_MAXMEDIA_UB425_TC:
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk,
- &dev->i2c_adap[dev->def_i2c_bus]);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0]) {
/* disable I2C-gate */
@@ -1507,7 +1740,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk,
- &dev->i2c_adap[dev->def_i2c_bus]);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0]) {
/* attach tuner */
@@ -1579,13 +1812,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
break;
case EM2874_BOARD_KWORLD_UB435Q_V3:
{
- struct i2c_client *client;
struct i2c_adapter *adapter = &dev->i2c_adap[dev->def_i2c_bus];
- struct i2c_board_info board_info = {
- .type = "tda18212",
- .addr = 0x60,
- .platform_data = &kworld_ub435q_v3_config,
- };
dvb->fe[0] = dvb_attach(lgdt3305_attach,
&em2874_lgdt3305_nogate_dev,
@@ -1597,28 +1824,23 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* attach tuner */
kworld_ub435q_v3_config.fe = dvb->fe[0];
- request_module("tda18212");
- client = i2c_new_device(adapter, &board_info);
- if (client == NULL || client->dev.driver == NULL) {
- dvb_frontend_detach(dvb->fe[0]);
- result = -ENODEV;
- goto out_free;
- }
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
+ dvb->i2c_client_tuner = dvb_module_probe("tda18212", NULL,
+ adapter, 0x60,
+ &kworld_ub435q_v3_config);
+ if (!dvb->i2c_client_tuner) {
dvb_frontend_detach(dvb->fe[0]);
result = -ENODEV;
goto out_free;
}
-
- dvb->i2c_client_tuner = client;
break;
}
case EM2874_BOARD_PCTV_HD_MINI_80E:
- dvb->fe[0] = dvb_attach(drx39xxj_attach, &dev->i2c_adap[dev->def_i2c_bus]);
- if (dvb->fe[0] != NULL) {
- dvb->fe[0] = dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+ dvb->fe[0] = dvb_attach(drx39xxj_attach,
+ &dev->i2c_adap[dev->def_i2c_bus]);
+ if (dvb->fe[0]) {
+ dvb->fe[0] = dvb_attach(tda18271_attach, dvb->fe[0],
+ 0x60,
&dev->i2c_adap[dev->def_i2c_bus],
&pinnacle_80e_dvb_config);
if (!dvb->fe[0]) {
@@ -1627,410 +1849,42 @@ static int em28xx_dvb_init(struct em28xx *dev)
}
}
break;
- case EM28178_BOARD_PCTV_461E: {
- struct i2c_client *client;
- struct i2c_adapter *i2c_adapter;
- struct i2c_board_info board_info;
- struct m88ds3103_platform_data m88ds3103_pdata = {};
- struct ts2020_config ts2020_config = {};
- struct a8293_platform_data a8293_pdata = {};
-
- /* attach demod */
- m88ds3103_pdata.clk = 27000000;
- m88ds3103_pdata.i2c_wr_max = 33;
- m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL;
- m88ds3103_pdata.ts_clk = 16000;
- m88ds3103_pdata.ts_clk_pol = 1;
- m88ds3103_pdata.agc = 0x99;
- 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(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
- if (client == NULL || client->dev.driver == NULL) {
- result = -ENODEV;
- goto out_free;
- }
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- result = -ENODEV;
- goto out_free;
- }
- dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(client);
- i2c_adapter = m88ds3103_pdata.get_i2c_adapter(client);
- dvb->i2c_client_demod = client;
-
- /* attach tuner */
- ts2020_config.fe = dvb->fe[0];
- 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, &board_info);
- if (client == NULL || client->dev.driver == NULL) {
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
- dvb->i2c_client_tuner = client;
- /* delegate signal strength measurement to tuner */
- dvb->fe[0]->ops.read_signal_strength =
- dvb->fe[0]->ops.tuner_ops.get_rf_strength;
-
- /* attach SEC */
- a8293_pdata.dvb_frontend = dvb->fe[0];
- memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "a8293", I2C_NAME_SIZE);
- board_info.addr = 0x08;
- board_info.platform_data = &a8293_pdata;
- request_module("a8293");
- client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
- if (client == NULL || client->dev.driver == NULL) {
- module_put(dvb->i2c_client_tuner->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_tuner);
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- module_put(dvb->i2c_client_tuner->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_tuner);
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
+ case EM28178_BOARD_PCTV_461E:
+ result = em28178_dvb_init_pctv_461e(dev);
+ if (result)
goto out_free;
- }
- dvb->i2c_client_sec = client;
break;
- }
case EM28178_BOARD_PCTV_292E:
- {
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- struct i2c_board_info info;
- struct si2168_config si2168_config;
- struct si2157_config si2157_config;
-
- /* attach demod */
- memset(&si2168_config, 0, sizeof(si2168_config));
- si2168_config.i2c_adapter = &adapter;
- si2168_config.fe = &dvb->fe[0];
- si2168_config.ts_mode = SI2168_TS_PARALLEL;
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2168", I2C_NAME_SIZE);
- info.addr = 0x64;
- info.platform_data = &si2168_config;
- request_module(info.type);
- client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
- if (client == NULL || client->dev.driver == NULL) {
- result = -ENODEV;
- goto out_free;
- }
-
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- result = -ENODEV;
- goto out_free;
- }
-
- dvb->i2c_client_demod = client;
-
- /* attach tuner */
- 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;
- info.platform_data = &si2157_config;
- request_module(info.type);
- client = i2c_new_device(adapter, &info);
- if (client == NULL || client->dev.driver == NULL) {
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
-
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
-
- dvb->i2c_client_tuner = client;
- dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna;
- }
+ result = em28178_dvb_init_pctv_292e(dev);
+ if (result)
+ goto out_free;
break;
case EM28178_BOARD_TERRATEC_T2_STICK_HD:
- {
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- struct i2c_board_info info;
- struct si2168_config si2168_config;
- struct si2157_config si2157_config;
-
- /* attach demod */
- memset(&si2168_config, 0, sizeof(si2168_config));
- si2168_config.i2c_adapter = &adapter;
- si2168_config.fe = &dvb->fe[0];
- si2168_config.ts_mode = SI2168_TS_PARALLEL;
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2168", I2C_NAME_SIZE);
- info.addr = 0x64;
- info.platform_data = &si2168_config;
- request_module(info.type);
- client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
- if (client == NULL || client->dev.driver == NULL) {
- result = -ENODEV;
- goto out_free;
- }
-
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- result = -ENODEV;
- goto out_free;
- }
-
- dvb->i2c_client_demod = client;
-
- /* attach tuner */
- 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;
- info.platform_data = &si2157_config;
- request_module("si2157");
- client = i2c_new_device(adapter, &info);
- if (client == NULL || client->dev.driver == NULL) {
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
-
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
-
- dvb->i2c_client_tuner = client;
- }
+ result = em28178_dvb_init_terratec_t2_stick_hd(dev);
+ if (result)
+ goto out_free;
break;
-
case EM28178_BOARD_PLEX_PX_BCUD:
- {
- struct i2c_client *client;
- struct i2c_board_info info;
- struct tc90522_config tc90522_config;
- struct qm1d1c0042_config qm1d1c0042_config;
-
- /* attach demod */
- memset(&tc90522_config, 0, sizeof(tc90522_config));
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "tc90522sat", I2C_NAME_SIZE);
- info.addr = 0x15;
- info.platform_data = &tc90522_config;
- request_module("tc90522");
- client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
- if (client == NULL || client->dev.driver == NULL) {
- result = -ENODEV;
- goto out_free;
- }
- dvb->i2c_client_demod = client;
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- result = -ENODEV;
- goto out_free;
- }
-
- /* attach tuner */
- memset(&qm1d1c0042_config, 0,
- sizeof(qm1d1c0042_config));
- qm1d1c0042_config.fe = tc90522_config.fe;
- qm1d1c0042_config.lpf = 1;
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "qm1d1c0042", I2C_NAME_SIZE);
- info.addr = 0x61;
- info.platform_data = &qm1d1c0042_config;
- request_module(info.type);
- client = i2c_new_device(tc90522_config.tuner_i2c,
- &info);
- if (client == NULL || client->dev.driver == NULL) {
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
- dvb->i2c_client_tuner = client;
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
- dvb->fe[0] = tc90522_config.fe;
- px_bcud_init(dev);
- }
+ result = em28178_dvb_init_plex_px_bcud(dev);
+ if (result)
+ goto out_free;
break;
case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB:
- {
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- struct i2c_board_info info;
- struct si2168_config si2168_config;
- struct si2157_config si2157_config;
-
- /* attach demod */
- memset(&si2168_config, 0, sizeof(si2168_config));
- si2168_config.i2c_adapter = &adapter;
- si2168_config.fe = &dvb->fe[0];
- si2168_config.ts_mode = SI2168_TS_SERIAL;
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2168", I2C_NAME_SIZE);
- info.addr = 0x64;
- info.platform_data = &si2168_config;
- request_module(info.type);
- client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
- if (client == NULL || client->dev.driver == NULL) {
- result = -ENODEV;
- goto out_free;
- }
-
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- result = -ENODEV;
- goto out_free;
- }
-
- dvb->i2c_client_demod = client;
-
- /* attach tuner */
- 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;
- info.platform_data = &si2157_config;
- request_module(info.type);
- client = i2c_new_device(adapter, &info);
- if (client == NULL || client->dev.driver == NULL) {
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
-
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
-
- dvb->i2c_client_tuner = client;
-
- }
+ result = em28174_dvb_init_hauppauge_wintv_dualhd_dvb(dev);
+ if (result)
+ goto out_free;
break;
case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595:
- {
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- struct i2c_board_info info = {};
- struct lgdt3306a_config lgdt3306a_config;
- struct si2157_config si2157_config = {};
-
- /* attach demod */
- lgdt3306a_config = hauppauge_01595_lgdt3306a_config;
- lgdt3306a_config.fe = &dvb->fe[0];
- lgdt3306a_config.i2c_adapter = &adapter;
- strlcpy(info.type, "lgdt3306a", sizeof(info.type));
- info.addr = 0x59;
- info.platform_data = &lgdt3306a_config;
- request_module(info.type);
- client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus],
- &info);
- if (client == NULL || client->dev.driver == NULL) {
- result = -ENODEV;
- goto out_free;
- }
-
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- result = -ENODEV;
- goto out_free;
- }
-
- dvb->i2c_client_demod = client;
-
- /* attach tuner */
- si2157_config.fe = dvb->fe[0];
- si2157_config.if_port = 1;
- si2157_config.inversion = 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", sizeof(info.type));
- info.addr = 0x60;
- info.platform_data = &si2157_config;
- request_module(info.type);
-
- client = i2c_new_device(adapter, &info);
- if (client == NULL || client->dev.driver == NULL) {
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
- if (!try_module_get(client->dev.driver->owner)) {
- i2c_unregister_device(client);
- module_put(dvb->i2c_client_demod->dev.driver->owner);
- i2c_unregister_device(dvb->i2c_client_demod);
- result = -ENODEV;
- goto out_free;
- }
-
- dvb->i2c_client_tuner = client;
- }
+ result = em28174_dvb_init_hauppauge_wintv_dualhd_01595(dev);
+ if (result)
+ goto out_free;
break;
default:
dev_err(&dev->intf->dev,
"The frontend of your DVB/ATSC card isn't supported yet\n");
break;
}
- if (NULL == dvb->fe[0]) {
+ if (!dvb->fe[0]) {
dev_err(&dev->intf->dev, "frontend initialization failed\n");
result = -EINVAL;
goto out_free;
@@ -2046,6 +1900,14 @@ static int em28xx_dvb_init(struct em28xx *dev)
if (result < 0)
goto out_free;
+ if (dev->dvb_xfer_bulk) {
+ dvb_alt = 0;
+ } else { /* isoc */
+ dvb_alt = dev->dvb_alt_isoc;
+ }
+
+ udev = interface_to_usbdev(dev->intf);
+ usb_set_interface(udev, dev->ifnum, dvb_alt);
dev_info(&dev->intf->dev, "DVB extension successfully initialized\n");
kref_get(&dev->ref);
@@ -2071,7 +1933,6 @@ static inline void prevent_sleep(struct dvb_frontend_ops *ops)
static int em28xx_dvb_fini(struct em28xx *dev)
{
struct em28xx_dvb *dvb;
- struct i2c_client *client;
if (dev->is_audio_only) {
/* Shouldn't initialize IR for this interface */
@@ -2093,8 +1954,10 @@ static int em28xx_dvb_fini(struct em28xx *dev)
em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
if (dev->disconnected) {
- /* We cannot tell the device to sleep
- * once it has been unplugged. */
+ /*
+ * We cannot tell the device to sleep
+ * once it has been unplugged.
+ */
if (dvb->fe[0]) {
prevent_sleep(&dvb->fe[0]->ops);
dvb->fe[0]->exit = DVB_FE_DEVICE_REMOVED;
@@ -2107,26 +1970,10 @@ static int em28xx_dvb_fini(struct em28xx *dev)
em28xx_unregister_dvb(dvb);
- /* remove I2C SEC */
- client = dvb->i2c_client_sec;
- if (client) {
- module_put(client->dev.driver->owner);
- i2c_unregister_device(client);
- }
-
- /* remove I2C tuner */
- client = dvb->i2c_client_tuner;
- if (client) {
- module_put(client->dev.driver->owner);
- i2c_unregister_device(client);
- }
-
- /* remove I2C demod */
- client = dvb->i2c_client_demod;
- if (client) {
- module_put(client->dev.driver->owner);
- i2c_unregister_device(client);
- }
+ /* release I2C module bindings */
+ dvb_module_release(dvb->i2c_client_sec);
+ dvb_module_release(dvb->i2c_client_tuner);
+ dvb_module_release(dvb->i2c_client_demod);
kfree(dvb);
dev->dvb = NULL;
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index 9bf49d666e5a..9151bccd859a 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -1,26 +1,22 @@
-/*
- em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
-
- Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
- Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@infradead.org>
- Sascha Sommer <saschasommer@freenet.de>
- Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+//
+// Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+// Markus Rechberger <mrechberger@gmail.com>
+// Mauro Carvalho Chehab <mchehab@infradead.org>
+// Sascha Sommer <saschasommer@freenet.de>
+// Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
#include "em28xx.h"
@@ -50,6 +46,35 @@ MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I
"i2c: %s: " fmt, __func__, ## arg); \
} while (0)
+/*
+ * Time in msecs to wait for i2c xfers to finish.
+ * 35ms is the maximum time a SMBUS device could wait when
+ * clock stretching is used. As the transfer itself will take
+ * some time to happen, set it to 35 ms.
+ *
+ * Ok, I2C doesn't specify any limit. So, eventually, we may need
+ * to increase this timeout.
+ */
+#define EM28XX_I2C_XFER_TIMEOUT 35 /* ms */
+
+static int em28xx_i2c_timeout(struct em28xx *dev)
+{
+ int time = EM28XX_I2C_XFER_TIMEOUT;
+
+ switch (dev->i2c_speed & 0x03) {
+ case EM28XX_I2C_FREQ_25_KHZ:
+ time += 4; /* Assume 4 ms for transfers */
+ break;
+ case EM28XX_I2C_FREQ_100_KHZ:
+ case EM28XX_I2C_FREQ_400_KHZ:
+ time += 1; /* Assume 1 ms for transfers */
+ break;
+ default: /* EM28XX_I2C_FREQ_1_5_MHZ */
+ break;
+ }
+
+ return msecs_to_jiffies(time);
+}
/*
* em2800_i2c_send_bytes()
@@ -57,14 +82,13 @@ MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I
*/
static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
{
- unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
+ unsigned long timeout = jiffies + em28xx_i2c_timeout(dev);
int ret;
u8 b2[6];
if (len < 1 || len > 4)
return -EOPNOTSUPP;
- BUG_ON(len < 1 || len > 4);
b2[5] = 0x80 + len - 1;
b2[4] = addr;
b2[3] = buf[0];
@@ -98,7 +122,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
ret);
return ret;
}
- msleep(5);
+ usleep_range(5000, 6000);
}
dprintk(0, "write to i2c device at 0x%x timed out\n", addr);
return -ETIMEDOUT;
@@ -110,7 +134,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
*/
static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
{
- unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
+ unsigned long timeout = jiffies + em28xx_i2c_timeout(dev);
u8 buf2[4];
int ret;
int i;
@@ -145,14 +169,13 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
ret);
return ret;
}
- msleep(5);
+ usleep_range(5000, 6000);
}
- if (ret != 0x84 + len - 1) {
+ if (ret != 0x84 + len - 1)
dprintk(0, "read from i2c device at 0x%x timed out\n", addr);
- }
/* get the received message */
- ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
+ ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4 - len, buf2, len);
if (ret != len) {
dev_warn(&dev->intf->dev,
"reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n",
@@ -186,7 +209,7 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
u16 len, int stop)
{
- unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
+ unsigned long timeout = jiffies + em28xx_i2c_timeout(dev);
int ret;
if (len < 1 || len > 64)
@@ -204,12 +227,11 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
"writing to i2c device at 0x%x failed (error=%i)\n",
addr, ret);
return ret;
- } else {
- dev_warn(&dev->intf->dev,
- "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
- len, addr, ret);
- return -EIO;
}
+ dev_warn(&dev->intf->dev,
+ "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
+ len, addr, ret);
+ return -EIO;
}
/* wait for completion */
@@ -228,7 +250,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
ret);
return ret;
}
- msleep(5);
+ usleep_range(5000, 6000);
/*
* NOTE: do we really have to wait for success ?
* Never seen anything else than 0x00 or 0x10
@@ -351,12 +373,12 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
"writing to i2c device at 0x%x failed (error=%i)\n",
addr, ret);
return ret;
- } else {
- dev_warn(&dev->intf->dev,
- "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
- len, addr, ret);
- return -EIO;
}
+
+ dev_warn(&dev->intf->dev,
+ "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
+ len, addr, ret);
+ return -EIO;
}
/* Check success */
ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000);
@@ -366,7 +388,8 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
*/
if (!ret)
return len;
- else if (ret > 0) {
+
+ if (ret > 0) {
dprintk(1, "Bus B R08 returned 0x%02x: I2C ACK error\n", ret);
return -ENXIO;
}
@@ -420,7 +443,8 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
*/
if (!ret)
return len;
- else if (ret > 0) {
+
+ if (ret > 0) {
dprintk(1, "Bus B R08 returned 0x%02x: I2C ACK error\n", ret);
return -ENXIO;
}
@@ -508,13 +532,15 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
{
struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data;
struct em28xx *dev = i2c_bus->dev;
- unsigned bus = i2c_bus->bus;
+ unsigned int bus = i2c_bus->bus;
int addr, rc, i;
u8 reg;
- /* prevent i2c xfer attempts after device is disconnected
- some fe's try to do i2c writes/reads from their release
- interfaces when called in disconnect path */
+ /*
+ * prevent i2c xfer attempts after device is disconnected
+ * some fe's try to do i2c writes/reads from their release
+ * interfaces when called in disconnect path
+ */
if (dev->disconnected)
return -ENODEV;
@@ -597,12 +623,13 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
if (len == length) {
c = (char)len;
len = -1;
- } else
+ } else {
c = *buf++;
+ }
l = (l << 8) | c;
len++;
if ((len & (32 / 8 - 1)) == 0)
- hash = ((hash^l) * 0x9e370001UL);
+ hash = ((hash ^ l) * 0x9e370001UL);
} while (len);
return (hash >> (32 - bits)) & 0xffffffffUL;
@@ -612,7 +639,7 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
* Helper function to read data blocks from i2c clients with 8 or 16 bit
* address width, 8 bit register width and auto incrementation been activated
*/
-static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr,
+static int em28xx_i2c_read_block(struct em28xx *dev, unsigned int bus, u16 addr,
bool addr_w16, u16 len, u8 *data)
{
int remain = len, rsize, rsize_max, ret;
@@ -624,7 +651,8 @@ static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr,
/* Select address */
buf[0] = addr >> 8;
buf[1] = addr & 0xff;
- ret = i2c_master_send(&dev->i2c_client[bus], buf + !addr_w16, 1 + addr_w16);
+ ret = i2c_master_send(&dev->i2c_client[bus],
+ buf + !addr_w16, 1 + addr_w16);
if (ret < 0)
return ret;
/* Read data */
@@ -649,7 +677,7 @@ static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr,
return len;
}
-static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
+static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned int bus,
u8 **eedata, u16 *eedata_len)
{
const u16 len = 256;
@@ -677,7 +705,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
}
data = kzalloc(len, GFP_KERNEL);
- if (data == NULL)
+ if (!data)
return -ENOMEM;
/* Read EEPROM content */
@@ -710,8 +738,8 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
mc_start = (data[1] << 8) + 4; /* usually 0x0004 */
dev_info(&dev->intf->dev,
- "EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n",
- data[0], data[1], data[2], data[3], dev->hash);
+ "EEPROM ID = %4ph, EEPROM hash = 0x%08lx\n",
+ data, dev->hash);
dev_info(&dev->intf->dev,
"EEPROM info:\n");
dev_info(&dev->intf->dev,
@@ -769,15 +797,18 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
return 0;
}
- /* TODO: decrypt eeprom data for camera bridges (em25xx, em276x+) */
+ /*
+ * TODO: decrypt eeprom data for camera bridges
+ * (em25xx, em276x+)
+ */
} else if (!dev->eeprom_addrwidth_16bit &&
data[0] == 0x1a && data[1] == 0xeb &&
data[2] == 0x67 && data[3] == 0x95) {
dev->hash = em28xx_hash_mem(data, len, 32);
dev_info(&dev->intf->dev,
- "EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n",
- data[0], data[1], data[2], data[3], dev->hash);
+ "EEPROM ID = %4ph, EEPROM hash = 0x%08lx\n",
+ data, dev->hash);
dev_info(&dev->intf->dev,
"EEPROM info:\n");
} else {
@@ -859,8 +890,8 @@ static u32 functionality(struct i2c_adapter *i2c_adap)
{
struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data;
- if ((i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) ||
- (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)) {
+ if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX ||
+ i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B) {
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
} else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800) {
return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL) &
@@ -893,7 +924,7 @@ static const struct i2c_client em28xx_client_template = {
* incomplete list of known devices
*/
static char *i2c_devs[128] = {
- [0x1c >> 1] = "lgdt330x",
+ [0x1c >> 1] = "lgdt330x",
[0x3e >> 1] = "remote IR sensor",
[0x4a >> 1] = "saa7113h",
[0x52 >> 1] = "drxk",
@@ -916,7 +947,7 @@ static char *i2c_devs[128] = {
* do_i2c_scan()
* check i2c address range for devices
*/
-void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus)
+void em28xx_do_i2c_scan(struct em28xx *dev, unsigned int bus)
{
u8 i2c_devicelist[128];
unsigned char buf;
@@ -944,13 +975,14 @@ void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus)
* em28xx_i2c_register()
* register i2c bus
*/
-int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
+int em28xx_i2c_register(struct em28xx *dev, unsigned int bus,
enum em28xx_i2c_algo_type algo_type)
{
int retval;
- BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
- BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
+ if (WARN_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg ||
+ !dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req))
+ return -ENODEV;
if (bus >= NUM_I2C_BUSES)
return -ENODEV;
@@ -977,8 +1009,9 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
/* Up to now, all eeproms are at bus 0 */
if (!bus) {
- retval = em28xx_i2c_eeprom(dev, bus, &dev->eedata, &dev->eedata_len);
- if ((retval < 0) && (retval != -ENODEV)) {
+ retval = em28xx_i2c_eeprom(dev, bus,
+ &dev->eedata, &dev->eedata_len);
+ if (retval < 0 && retval != -ENODEV) {
dev_err(&dev->intf->dev,
"%s: em28xx_i2_eeprom failed! retval [%d]\n",
__func__, retval);
@@ -995,7 +1028,7 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
* em28xx_i2c_unregister()
* unregister i2c_bus
*/
-int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus)
+int em28xx_i2c_unregister(struct em28xx *dev, unsigned int bus)
{
if (bus >= NUM_I2C_BUSES)
return -ENODEV;
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 046223de1e91..2dc1be00b8b8 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -1,25 +1,21 @@
-/*
- handle em28xx IR remotes via linux kernel input layer.
-
- Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
- Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@infradead.org>
- Sascha Sommer <saschasommer@freenet.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.
-
- 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, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// handle em28xx IR remotes via linux kernel input layer.
+//
+// Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+// Markus Rechberger <mrechberger@gmail.com>
+// Mauro Carvalho Chehab <mchehab@infradead.org>
+// Sascha Sommer <saschasommer@freenet.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.
+//
+// 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 "em28xx.h"
@@ -41,15 +37,15 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
#define MODULE_NAME "em28xx"
-#define dprintk( fmt, arg...) do { \
+#define dprintk(fmt, arg...) do { \
if (ir_debug) \
dev_printk(KERN_DEBUG, &ir->dev->intf->dev, \
"input: %s: " fmt, __func__, ## arg); \
} while (0)
-/**********************************************************
- Polling structure used by em28xx IR's
- **********************************************************/
+/*
+ * Polling structure used by em28xx IR's
+ */
struct em28xx_ir_poll_result {
unsigned int toggle_bit:1;
@@ -76,24 +72,31 @@ struct em28xx_IR {
int (*get_key_i2c)(struct i2c_client *ir, enum rc_proto *protocol,
u32 *scancode);
- int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
+ int (*get_key)(struct em28xx_IR *ir, struct em28xx_ir_poll_result *r);
};
-/**********************************************************
- I2C IR based get keycodes - should be used with ir-kbd-i2c
- **********************************************************/
+/*
+ * I2C IR based get keycodes - should be used with ir-kbd-i2c
+ */
static int em28xx_get_key_terratec(struct i2c_client *i2c_dev,
enum rc_proto *protocol, u32 *scancode)
{
+ int rc;
unsigned char b;
/* poll IR chip */
- if (1 != i2c_master_recv(i2c_dev, &b, 1))
+ rc = i2c_master_recv(i2c_dev, &b, 1);
+ if (rc != 1) {
+ if (rc < 0)
+ return rc;
return -EIO;
+ }
- /* it seems that 0xFE indicates that a button is still hold
- down, while 0xff indicates that no button is hold down. */
+ /*
+ * it seems that 0xFE indicates that a button is still hold
+ * down, while 0xff indicates that no button is hold down.
+ */
if (b == 0xff)
return 0;
@@ -145,7 +148,7 @@ static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev,
/* poll IR chip */
- if (3 != i2c_master_recv(i2c_dev, buf, 3))
+ if (i2c_master_recv(i2c_dev, buf, 3) != 3)
return -EIO;
if (buf[0] != 0x00)
@@ -162,18 +165,28 @@ static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev,
{
unsigned char subaddr, keydetect, key;
- struct i2c_msg msg[] = { { .addr = i2c_dev->addr, .flags = 0, .buf = &subaddr, .len = 1},
- { .addr = i2c_dev->addr, .flags = I2C_M_RD, .buf = &keydetect, .len = 1} };
+ struct i2c_msg msg[] = {
+ {
+ .addr = i2c_dev->addr,
+ .flags = 0,
+ .buf = &subaddr, .len = 1
+ }, {
+ .addr = i2c_dev->addr,
+ .flags = I2C_M_RD,
+ .buf = &keydetect,
+ .len = 1
+ }
+ };
subaddr = 0x10;
- if (2 != i2c_transfer(i2c_dev->adapter, msg, 2))
+ if (i2c_transfer(i2c_dev->adapter, msg, 2) != 2)
return -EIO;
if (keydetect == 0x00)
return 0;
subaddr = 0x00;
msg[1].buf = &key;
- if (2 != i2c_transfer(i2c_dev->adapter, msg, 2))
+ if (i2c_transfer(i2c_dev->adapter, msg, 2) != 2)
return -EIO;
if (key == 0x00)
return 0;
@@ -183,9 +196,9 @@ static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev,
return 1;
}
-/**********************************************************
- Poll based get keycode functions
- **********************************************************/
+/*
+ * Poll based get keycode functions
+ */
/* This is for the em2860/em2880 */
static int default_polling_getkey(struct em28xx_IR *ir,
@@ -195,8 +208,9 @@ static int default_polling_getkey(struct em28xx_IR *ir,
int rc;
u8 msg[3] = { 0, 0, 0 };
- /* Read key toggle, brand, and key code
- on registers 0x45, 0x46 and 0x47
+ /*
+ * Read key toggle, brand, and key code
+ * on registers 0x45, 0x46 and 0x47
*/
rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR,
msg, sizeof(msg));
@@ -237,8 +251,9 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
int rc;
u8 msg[5] = { 0, 0, 0, 0, 0 };
- /* Read key toggle, brand, and key code
- on registers 0x51-55
+ /*
+ * Read key toggle, brand, and key code
+ * on registers 0x51-55
*/
rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR,
msg, sizeof(msg));
@@ -294,9 +309,9 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
return 0;
}
-/**********************************************************
- Polling code for em28xx
- **********************************************************/
+/*
+ * Polling code for em28xx
+ */
static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir)
{
@@ -347,11 +362,14 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
if (ir->dev->chip_id == CHIP_ID_EM2874 ||
ir->dev->chip_id == CHIP_ID_EM2884)
- /* The em2874 clears the readcount field every time the
- register is read. The em2860/2880 datasheet says that it
- is supposed to clear the readcount, but it doesn't. So with
- the em2874, we are looking for a non-zero read count as
- opposed to a readcount that is incrementing */
+ /*
+ * The em2874 clears the readcount field every time the
+ * register is read. The em2860/2880 datasheet says
+ * that it is supposed to clear the readcount, but it
+ * doesn't. So with the em2874, we are looking for a
+ * non-zero read count as opposed to a readcount
+ * that is incrementing
+ */
ir->last_readcount = 0;
else
ir->last_readcount = poll_result.read_count;
@@ -476,15 +494,18 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_proto)
static int em28xx_probe_i2c_ir(struct em28xx *dev)
{
int i = 0;
- /* Leadtek winfast tv USBII deluxe can find a non working IR-device */
- /* at address 0x18, so if that address is needed for another board in */
- /* the future, please put it after 0x1f. */
+ /*
+ * Leadtek winfast tv USBII deluxe can find a non working IR-device
+ * at address 0x18, so if that address is needed for another board in
+ * the future, please put it after 0x1f.
+ */
const unsigned short addr_list[] = {
0x1f, 0x30, 0x47, I2C_CLIENT_END
};
while (addr_list[i] != I2C_CLIENT_END) {
- if (i2c_probe_func_quick_read(&dev->i2c_adap[dev->def_i2c_bus], addr_list[i]) == 1)
+ if (i2c_probe_func_quick_read(&dev->i2c_adap[dev->def_i2c_bus],
+ addr_list[i]) == 1)
return addr_list[i];
i++;
}
@@ -492,9 +513,9 @@ static int em28xx_probe_i2c_ir(struct em28xx *dev)
return -ENODEV;
}
-/**********************************************************
- Handle buttons
- **********************************************************/
+/*
+ * Handle buttons
+ */
static void em28xx_query_buttons(struct work_struct *work)
{
@@ -515,7 +536,10 @@ static void em28xx_query_buttons(struct work_struct *work)
j = 0;
while (dev->board.buttons[j].role >= 0 &&
dev->board.buttons[j].role < EM28XX_NUM_BUTTON_ROLES) {
- struct em28xx_button *button = &dev->board.buttons[j];
+ const struct em28xx_button *button;
+
+ button = &dev->board.buttons[j];
+
/* Check if button uses the current address */
if (button->reg_r != dev->button_polling_addresses[i]) {
j++;
@@ -618,7 +642,8 @@ static void em28xx_init_buttons(struct em28xx *dev)
dev->button_polling_interval = EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL;
while (dev->board.buttons[i].role >= 0 &&
dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) {
- struct em28xx_button *button = &dev->board.buttons[i];
+ const struct em28xx_button *button = &dev->board.buttons[i];
+
/* Check if polling address is already on the list */
addr_new = true;
for (j = 0; j < dev->num_button_polling_addresses; j++) {
@@ -649,6 +674,7 @@ static void em28xx_init_buttons(struct em28xx *dev)
/* Add read address to list of polling addresses */
if (addr_new) {
unsigned int index = dev->num_button_polling_addresses;
+
dev->button_polling_addresses[index] = button->reg_r;
dev->num_button_polling_addresses++;
}
@@ -677,7 +703,7 @@ static void em28xx_shutdown_buttons(struct em28xx *dev)
/* Clear polling addresses list */
dev->num_button_polling_addresses = 0;
/* Deregister input devices */
- if (dev->sbutton_input_dev != NULL) {
+ if (dev->sbutton_input_dev) {
dev_info(&dev->intf->dev, "Deregistering snapshot button\n");
input_unregister_device(dev->sbutton_input_dev);
dev->sbutton_input_dev = NULL;
@@ -714,7 +740,7 @@ static int em28xx_ir_init(struct em28xx *dev)
}
}
- if (dev->board.ir_codes == NULL && !dev->board.has_ir_i2c) {
+ if (!dev->board.ir_codes && !dev->board.has_ir_i2c) {
/* No remote control support */
dev_warn(&dev->intf->dev,
"Remote control support is not available for this card.\n");
@@ -764,7 +790,7 @@ static int em28xx_ir_init(struct em28xx *dev)
goto error;
}
- ir->i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ ir->i2c_client = kzalloc(sizeof(*ir->i2c_client), GFP_KERNEL);
if (!ir->i2c_client)
goto error;
ir->i2c_client->adapter = &ir->dev->i2c_adap[dev->def_i2c_bus];
@@ -881,9 +907,11 @@ static int em28xx_ir_suspend(struct em28xx *dev)
if (ir)
cancel_delayed_work_sync(&ir->work);
cancel_delayed_work_sync(&dev->buttons_query_work);
- /* is canceling delayed work sufficient or does the rc event
- kthread needs stopping? kthread is stopped in
- ir_raw_event_unregister() */
+ /*
+ * is canceling delayed work sufficient or does the rc event
+ * kthread needs stopping? kthread is stopped in
+ * ir_raw_event_unregister()
+ */
return 0;
}
@@ -895,8 +923,10 @@ static int em28xx_ir_resume(struct em28xx *dev)
return 0;
dev_info(&dev->intf->dev, "Resuming input extension\n");
- /* if suspend calls ir_raw_event_unregister(), the should call
- ir_raw_event_register() */
+ /*
+ * if suspend calls ir_raw_event_unregister(), the should call
+ * ir_raw_event_register()
+ */
if (ir)
schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
if (dev->num_button_polling_addresses)
@@ -924,7 +954,7 @@ static void __exit em28xx_rc_unregister(void)
em28xx_unregister_extension(&rc_ops);
}
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Mauro Carvalho Chehab");
MODULE_DESCRIPTION(DRIVER_DESC " - input interface");
MODULE_VERSION(EM28XX_VERSION);
diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h
index 9e5cdfb25a73..f53afe18e92d 100644
--- a/drivers/media/usb/em28xx/em28xx-reg.h
+++ b/drivers/media/usb/em28xx/em28xx-reg.h
@@ -1,17 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0 */
-#define EM_GPIO_0 (1 << 0)
-#define EM_GPIO_1 (1 << 1)
-#define EM_GPIO_2 (1 << 2)
-#define EM_GPIO_3 (1 << 3)
-#define EM_GPIO_4 (1 << 4)
-#define EM_GPIO_5 (1 << 5)
-#define EM_GPIO_6 (1 << 6)
-#define EM_GPIO_7 (1 << 7)
-
-#define EM_GPO_0 (1 << 0)
-#define EM_GPO_1 (1 << 1)
-#define EM_GPO_2 (1 << 2)
-#define EM_GPO_3 (1 << 3)
+
+/*
+ * em28xx-reg.h - Register definitions for em28xx driver
+ */
+
+#define EM_GPIO_0 ((unsigned char)BIT(0))
+#define EM_GPIO_1 ((unsigned char)BIT(1))
+#define EM_GPIO_2 ((unsigned char)BIT(2))
+#define EM_GPIO_3 ((unsigned char)BIT(3))
+#define EM_GPIO_4 ((unsigned char)BIT(4))
+#define EM_GPIO_5 ((unsigned char)BIT(5))
+#define EM_GPIO_6 ((unsigned char)BIT(6))
+#define EM_GPIO_7 ((unsigned char)BIT(7))
+
+#define EM_GPO_0 ((unsigned char)BIT(0))
+#define EM_GPO_1 ((unsigned char)BIT(1))
+#define EM_GPO_2 ((unsigned char)BIT(2))
+#define EM_GPO_3 ((unsigned char)BIT(3))
/* em28xx endpoints */
/* 0x82: (always ?) analog */
@@ -203,10 +208,11 @@
#define EM28XX_R43_AC97BUSY 0x43
#define EM28XX_R45_IR 0x45
- /* 0x45 bit 7 - parity bit
- bits 6-0 - count
- 0x46 IR brand
- 0x47 IR data
+ /*
+ * 0x45 bit 7 - parity bit
+ * bits 6-0 - count
+ * 0x46 IR brand
+ * 0x47 IR data
*/
/* em2874 registers */
@@ -249,12 +255,12 @@
#define EM2874_IR_RC6_MODE_6A 0x0b
/* em2874 Transport Stream Enable Register (0x5f) */
-#define EM2874_TS1_CAPTURE_ENABLE (1 << 0)
-#define EM2874_TS1_FILTER_ENABLE (1 << 1)
-#define EM2874_TS1_NULL_DISCARD (1 << 2)
-#define EM2874_TS2_CAPTURE_ENABLE (1 << 4)
-#define EM2874_TS2_FILTER_ENABLE (1 << 5)
-#define EM2874_TS2_NULL_DISCARD (1 << 6)
+#define EM2874_TS1_CAPTURE_ENABLE ((unsigned char)BIT(0))
+#define EM2874_TS1_FILTER_ENABLE ((unsigned char)BIT(1))
+#define EM2874_TS1_NULL_DISCARD ((unsigned char)BIT(2))
+#define EM2874_TS2_CAPTURE_ENABLE ((unsigned char)BIT(4))
+#define EM2874_TS2_FILTER_ENABLE ((unsigned char)BIT(5))
+#define EM2874_TS2_NULL_DISCARD ((unsigned char)BIT(6))
/* register settings */
#define EM2800_AUDIO_SRC_TUNER 0x0d
diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
index 9c411aac3878..1788dbf9024a 100644
--- a/drivers/media/usb/em28xx/em28xx-v4l.h
+++ b/drivers/media/usb/em28xx/em28xx-v4l.h
@@ -1,17 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
- em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
- video capture devices
-
- Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.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 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.
+ * em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
+ * video capture devices
+ *
+ * Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.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 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.
*/
int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index f5123651ef30..63c48361d3f2 100644
--- a/drivers/media/usb/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -1,25 +1,20 @@
-/*
- em28xx-vbi.c - VBI driver for em28xx
-
- Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
-
- This work was sponsored by EyeMagnet 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.
-
- 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// em28xx-vbi.c - VBI driver for em28xx
+//
+// Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
+//
+// This work was sponsored by EyeMagnet 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.
+//
+// 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 "em28xx.h"
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index a2ba2d905952..d70ee13cc52e 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1,30 +1,26 @@
-/*
- em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
- video capture devices
-
- Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
- Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@infradead.org>
- Sascha Sommer <saschasommer@freenet.de>
- Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
-
- Some parts based on SN9C10x PC Camera Controllers GPL driver made
- by Luca Risolia <luca.risolia@studio.unibo.it>
-
- 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.
-
- 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
+// video capture devices
+//
+// Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+// Markus Rechberger <mrechberger@gmail.com>
+// Mauro Carvalho Chehab <mchehab@infradead.org>
+// Sascha Sommer <saschasommer@freenet.de>
+// Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
+//
+// Some parts based on SN9C10x PC Camera Controllers GPL driver made
+// by Luca Risolia <luca.risolia@studio.unibo.it>
+//
+// 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 "em28xx.h"
@@ -77,7 +73,7 @@ MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(EM28XX_VERSION);
#define EM25XX_FRMDATAHDR_BYTE1 0x02
@@ -148,7 +144,7 @@ static inline unsigned int norm_maxw(struct em28xx *dev)
{
struct em28xx_v4l2 *v4l2 = dev->v4l2;
- if (dev->board.is_webcam)
+ if (dev->is_webcam)
return v4l2->sensor_xres;
if (dev->board.max_range_640_480)
@@ -161,7 +157,7 @@ static inline unsigned int norm_maxh(struct em28xx *dev)
{
struct em28xx_v4l2 *v4l2 = dev->v4l2;
- if (dev->board.is_webcam)
+ if (dev->is_webcam)
return v4l2->sensor_yres;
if (dev->board.max_range_640_480)
@@ -176,7 +172,7 @@ static int em28xx_vbi_supported(struct em28xx *dev)
if (disable_vbi == 1)
return 0;
- if (dev->board.is_webcam)
+ if (dev->is_webcam)
return 0;
/* FIXME: check subdevices for VBI support */
@@ -250,7 +246,8 @@ static int em28xx_set_outfmt(struct em28xx *dev)
if (em28xx_vbi_supported(dev) == 1) {
vinctrl |= EM28XX_VINCTRL_VBI_RAW;
em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
- em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, v4l2->vbi_width/4);
+ em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH,
+ v4l2->vbi_width / 4);
em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, v4l2->vbi_height);
if (v4l2->norm & V4L2_STD_525_60) {
/* NTSC */
@@ -320,8 +317,10 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
buf[0] = v;
buf[1] = v >> 8;
em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
- /* it seems that both H and V scalers must be active
- to work correctly */
+ /*
+ * it seems that both H and V scalers must be active
+ * to work correctly
+ */
mode = (h || v) ? 0x30 : 0x00;
}
return em28xx_write_reg(dev, EM28XX_R26_COMPR, mode);
@@ -345,13 +344,15 @@ static int em28xx_resolution_set(struct em28xx *dev)
em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
- /* If we don't set the start position to 2 in VBI mode, we end up
- with line 20/21 being YUYV encoded instead of being in 8-bit
- greyscale. The core of the issue is that line 21 (and line 23 for
- PAL WSS) are inside of active video region, and as a result they
- get the pixelformatting associated with that area. So by cropping
- it out, we end up with the same format as the rest of the VBI
- region */
+ /*
+ * If we don't set the start position to 2 in VBI mode, we end up
+ * with line 20/21 being YUYV encoded instead of being in 8-bit
+ * greyscale. The core of the issue is that line 21 (and line 23 for
+ * PAL WSS) are inside of active video region, and as a result they
+ * get the pixelformatting associated with that area. So by cropping
+ * it out, we end up with the same format as the rest of the VBI
+ * region
+ */
if (em28xx_vbi_supported(dev) == 1)
em28xx_capture_area_set(dev, 0, 2, width, height);
else
@@ -365,14 +366,16 @@ static int em28xx_set_alternate(struct em28xx *dev)
{
struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct usb_device *udev = interface_to_usbdev(dev->intf);
- int errCode;
+ int err;
int i;
unsigned int min_pkt_size = v4l2->width * 2 + 4;
- /* NOTE: for isoc transfers, only alt settings > 0 are allowed
- bulk transfers seem to work only with alt=0 ! */
+ /*
+ * NOTE: for isoc transfers, only alt settings > 0 are allowed
+ * bulk transfers seem to work only with alt=0 !
+ */
dev->alt = 0;
- if ((alt > 0) && (alt < dev->num_alt)) {
+ if (alt > 0 && alt < dev->num_alt) {
em28xx_videodbg("alternate forced to %d\n", dev->alt);
dev->alt = alt;
goto set_alt;
@@ -380,9 +383,10 @@ static int em28xx_set_alternate(struct em28xx *dev)
if (dev->analog_xfer_bulk)
goto set_alt;
- /* When image size is bigger than a certain value,
- the frame size should be increased, otherwise, only
- green screen will be received.
+ /*
+ * When image size is bigger than a certain value,
+ * the frame size should be increased, otherwise, only
+ * green screen will be received.
*/
if (v4l2->width * 2 * v4l2->height > 720 * 240 * 2)
min_pkt_size *= 2;
@@ -392,18 +396,22 @@ static int em28xx_set_alternate(struct em28xx *dev)
if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
dev->alt = i;
break;
- /* otherwise make sure that we end up with the maximum bandwidth
- because the min_pkt_size equation might be wrong...
- */
+ /*
+ * otherwise make sure that we end up with the maximum
+ * bandwidth because the min_pkt_size equation might be wrong.
+ *
+ */
} else if (dev->alt_max_pkt_size_isoc[i] >
dev->alt_max_pkt_size_isoc[dev->alt])
dev->alt = i;
}
set_alt:
- /* NOTE: for bulk transfers, we need to call usb_set_interface()
+ /*
+ * NOTE: for bulk transfers, we need to call usb_set_interface()
* even if the previous settings were the same. Otherwise streaming
- * fails with all urbs having status = -EOVERFLOW ! */
+ * fails with all urbs having status = -EOVERFLOW !
+ */
if (dev->analog_xfer_bulk) {
dev->max_pkt_size = 512; /* USB 2.0 spec */
dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
@@ -416,19 +424,19 @@ set_alt:
}
em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n",
dev->alt, dev->max_pkt_size);
- errCode = usb_set_interface(udev, dev->ifnum, dev->alt);
- if (errCode < 0) {
+ err = usb_set_interface(udev, dev->ifnum, dev->alt);
+ if (err < 0) {
dev_err(&dev->intf->dev,
"cannot change alternate number to %d (error=%i)\n",
- dev->alt, errCode);
- return errCode;
+ dev->alt, err);
+ return err;
}
return 0;
}
-/* ------------------------------------------------------------------
- DMA and thread functions
- ------------------------------------------------------------------*/
+/*
+ * DMA and thread functions
+ */
/*
* Finish the current buffer
@@ -514,8 +522,9 @@ static void em28xx_copy_video(struct em28xx *dev,
em28xx_isocdbg("Overflow of %zu bytes past buffer end(2)\n",
((char *)startwrite + lencopy) -
((char *)buf->vb_buf + buf->length));
- lencopy = remain = (char *)buf->vb_buf + buf->length -
- (char *)startwrite;
+ remain = (char *)buf->vb_buf + buf->length -
+ (char *)startwrite;
+ lencopy = remain;
}
if (lencopy <= 0)
break;
@@ -623,11 +632,11 @@ finish_field_prepare_next(struct em28xx *dev,
struct em28xx_v4l2 *v4l2 = dev->v4l2;
if (v4l2->progressive || v4l2->top_field) { /* Brand new frame */
- if (buf != NULL)
+ if (buf)
finish_buffer(dev, buf);
buf = get_next_buf(dev, dma_q);
}
- if (buf != NULL) {
+ if (buf) {
buf->top_field = v4l2->top_field;
buf->pos = 0;
}
@@ -648,13 +657,17 @@ static inline void process_frame_data_em28xx(struct em28xx *dev,
struct em28xx_dmaqueue *dma_q = &dev->vidq;
struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
- /* capture type 0 = vbi start
- capture type 1 = vbi in progress
- capture type 2 = video start
- capture type 3 = video in progress */
+ /*
+ * capture type 0 = vbi start
+ * capture type 1 = vbi in progress
+ * capture type 2 = video start
+ * capture type 3 = video in progress
+ */
if (data_len >= 4) {
- /* NOTE: Headers are always 4 bytes and
- * never split across packets */
+ /*
+ * NOTE: Headers are always 4 bytes and
+ * never split across packets
+ */
if (data_pkt[0] == 0x88 && data_pkt[1] == 0x88 &&
data_pkt[2] == 0x88 && data_pkt[3] == 0x88) {
/* Continuation */
@@ -677,8 +690,10 @@ static inline void process_frame_data_em28xx(struct em28xx *dev,
data_len -= 4;
}
}
- /* NOTE: With bulk transfers, intermediate data packets
- * have no continuation header */
+ /*
+ * NOTE: With bulk transfers, intermediate data packets
+ * have no continuation header
+ */
if (v4l2->capture_type == 0) {
vbi_buf = finish_field_prepare_next(dev, vbi_buf, vbi_dma_q);
@@ -692,7 +707,7 @@ static inline void process_frame_data_em28xx(struct em28xx *dev,
(vbi_size - v4l2->vbi_read) : data_len;
/* Copy VBI data */
- if (vbi_buf != NULL)
+ if (vbi_buf)
em28xx_copy_vbi(dev, vbi_buf, data_pkt, vbi_data_len);
v4l2->vbi_read += vbi_data_len;
@@ -710,7 +725,7 @@ static inline void process_frame_data_em28xx(struct em28xx *dev,
v4l2->capture_type = 3;
}
- if (v4l2->capture_type == 3 && buf != NULL && data_len > 0)
+ if (v4l2->capture_type == 3 && buf && data_len > 0)
em28xx_copy_video(dev, buf, data_pkt, data_len);
}
@@ -727,8 +742,10 @@ static inline void process_frame_data_em25xx(struct em28xx *dev,
bool frame_end = false;
/* Check for header */
- /* NOTE: at least with bulk transfers, only the first packet
- * has a header and has always set the FRAME_END bit */
+ /*
+ * NOTE: at least with bulk transfers, only the first packet
+ * has a header and has always set the FRAME_END bit
+ */
if (data_len >= 2) { /* em25xx header is only 2 bytes long */
if ((data_pkt[0] == EM25XX_FRMDATAHDR_BYTE1) &&
((data_pkt[1] & ~EM25XX_FRMDATAHDR_BYTE2_MASK) == 0x00)) {
@@ -745,14 +762,15 @@ static inline void process_frame_data_em25xx(struct em28xx *dev,
buf = finish_field_prepare_next(dev, buf, dmaq);
dev->usb_ctl.vid_buf = buf;
}
- /* NOTE: in ISOC mode when a new frame starts and buf==NULL,
+ /*
+ * NOTE: in ISOC mode when a new frame starts and buf==NULL,
* we COULD already prepare a buffer here to avoid skipping the
* first frame.
*/
}
/* Copy data */
- if (buf != NULL && data_len > 0)
+ if (buf && data_len > 0)
em28xx_copy_video(dev, buf, data_pkt, data_len);
/* Finish frame (ISOC only) => avoids lag of 1 frame */
@@ -761,14 +779,17 @@ static inline void process_frame_data_em25xx(struct em28xx *dev,
dev->usb_ctl.vid_buf = buf;
}
- /* NOTE: Tested with USB bulk transfers only !
+ /*
+ * NOTES:
+ *
+ * 1) Tested with USB bulk transfers only !
* The wording in the datasheet suggests that isoc might work different.
* The current code assumes that with isoc transfers each packet has a
* header like with the other em28xx devices.
+ *
+ * 2) Support for interlaced mode is pure theory. It has not been
+ * tested and it is unknown if these devices actually support it.
*/
- /* NOTE: Support for interlaced mode is pure theory. It has not been
- * tested and it is unknown if these devices actually support it. */
- /* NOTE: No VBI support yet (these chips likely do not support VBI). */
}
/* Processes and copies the URB data content (video and VBI data) */
@@ -829,12 +850,11 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb)
else
process_frame_data_em28xx(dev,
usb_data_pkt, usb_data_len);
-
}
return 1;
}
-static int get_ressource(enum v4l2_buf_type f_type)
+static int get_resource(enum v4l2_buf_type f_type)
{
switch (f_type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -842,14 +862,15 @@ static int get_ressource(enum v4l2_buf_type f_type)
case V4L2_BUF_TYPE_VBI_CAPTURE:
return EM28XX_RESOURCE_VBI;
default:
- BUG();
+ WARN_ON(1);
+ return -1; /* Indicate that device is busy */
}
}
/* Usage lock check functions */
static int res_get(struct em28xx *dev, enum v4l2_buf_type f_type)
{
- int res_type = get_ressource(f_type);
+ int res_type = get_resource(f_type);
/* is it free? */
if (dev->resources & res_type) {
@@ -865,7 +886,7 @@ static int res_get(struct em28xx *dev, enum v4l2_buf_type f_type)
static void res_free(struct em28xx *dev, enum v4l2_buf_type f_type)
{
- int res_type = get_ressource(f_type);
+ int res_type = get_resource(f_type);
dev->resources &= ~res_type;
em28xx_videodbg("res: put %d\n", res_type);
@@ -937,10 +958,11 @@ static int em28xx_enable_analog_tuner(struct em28xx *dev)
flags ? "enabled" : "disabled",
ret);
return ret;
- } else
- em28xx_videodbg("link %s->%s was %s\n",
- source->name, sink->name,
- flags ? "ENABLED" : "disabled");
+ }
+
+ em28xx_videodbg("link %s->%s was %s\n",
+ source->name, sink->name,
+ flags ? "ENABLED" : "disabled");
}
#endif
return 0;
@@ -976,7 +998,7 @@ static void em28xx_v4l2_create_entities(struct em28xx *dev)
}
/* Webcams don't have input connectors */
- if (dev->board.is_webcam)
+ if (dev->is_webcam)
return;
/* Create entities for each input connector */
@@ -1016,10 +1038,9 @@ static void em28xx_v4l2_create_entities(struct em28xx *dev)
#endif
}
-
-/* ------------------------------------------------------------------
- Videobuf2 operations
- ------------------------------------------------------------------*/
+/*
+ * Videobuf2 operations
+ */
static int queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
@@ -1072,8 +1093,10 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
em28xx_videodbg("%s\n", __func__);
- /* Make sure streaming is not already in progress for this type
- of filehandle (e.g. video, vbi) */
+ /*
+ * Make sure streaming is not already in progress for this type
+ * of filehandle (e.g. video, vbi)
+ */
rc = res_get(dev, vq->type);
if (rc)
return rc;
@@ -1084,9 +1107,10 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
/* Allocate the USB bandwidth */
em28xx_set_alternate(dev);
- /* Needed, since GPIO might have disabled power of
- some i2c device
- */
+ /*
+ * Needed, since GPIO might have disabled power of
+ * some i2c device
+ */
em28xx_wake_i2c(dev);
v4l2->capture_type = -1;
@@ -1145,7 +1169,7 @@ static void em28xx_stop_streaming(struct vb2_queue *vq)
}
spin_lock_irqsave(&dev->slock, flags);
- if (dev->usb_ctl.vid_buf != NULL) {
+ if (dev->usb_ctl.vid_buf) {
vb2_buffer_done(&dev->usb_ctl.vid_buf->vb.vb2_buf,
VB2_BUF_STATE_ERROR);
dev->usb_ctl.vid_buf = NULL;
@@ -1180,7 +1204,7 @@ void em28xx_stop_vbi_streaming(struct vb2_queue *vq)
}
spin_lock_irqsave(&dev->slock, flags);
- if (dev->usb_ctl.vbi_buf != NULL) {
+ if (dev->usb_ctl.vbi_buf) {
vb2_buffer_done(&dev->usb_ctl.vbi_buf->vb.vb2_buf,
VB2_BUF_STATE_ERROR);
dev->usb_ctl.vbi_buf = NULL;
@@ -1261,7 +1285,9 @@ static int em28xx_vb2_setup(struct em28xx *dev)
return 0;
}
-/********************* v4l2 interface **************************************/
+/*
+ * v4l2 interface
+ */
static void video_mux(struct em28xx *dev, int index)
{
@@ -1277,7 +1303,7 @@ static void video_mux(struct em28xx *dev, int index)
v4l2_device_call_all(v4l2_dev, 0, video, s_routing,
INPUT(index)->vmux, 0, 0);
- if (dev->board.has_msp34xx) {
+ if (dev->has_msp34xx) {
if (dev->i2s_speed) {
v4l2_device_call_all(v4l2_dev, 0, audio,
s_i2s_clock_freq, dev->i2s_speed);
@@ -1394,9 +1420,9 @@ static void scale_to_size(struct em28xx *dev,
*height = 1;
}
-/* ------------------------------------------------------------------
- IOCTL vidioc handling
- ------------------------------------------------------------------*/
+/*
+ * IOCTL vidioc handling
+ */
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
@@ -1462,8 +1488,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
if (width == maxw && height == maxh)
width /= 2;
} else {
- /* width must even because of the YUYV format
- height must be even because of interlacing */
+ /*
+ * width must even because of the YUYV format
+ * height must be even because of interlacing
+ */
v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh,
1, 0);
}
@@ -1493,7 +1521,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
}
static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
- unsigned width, unsigned height)
+ unsigned int width, unsigned int height)
{
struct em28xx_fmt *fmt;
struct em28xx_v4l2 *v4l2 = dev->v4l2;
@@ -1582,17 +1610,26 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
static int vidioc_g_parm(struct file *file, void *priv,
struct v4l2_streamparm *p)
{
+ struct v4l2_subdev_frame_interval ival = { 0 };
struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
int rc = 0;
+ if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
- if (dev->board.is_webcam)
+ p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ if (dev->is_webcam) {
rc = v4l2_device_call_until_err(&v4l2->v4l2_dev, 0,
- video, g_parm, p);
- else
+ video, g_frame_interval, &ival);
+ if (!rc)
+ p->parm.capture.timeperframe = ival.interval;
+ } else {
v4l2_video_std_frame_period(v4l2->norm,
&p->parm.capture.timeperframe);
+ }
return rc;
}
@@ -1601,10 +1638,27 @@ static int vidioc_s_parm(struct file *file, void *priv,
struct v4l2_streamparm *p)
{
struct em28xx *dev = video_drvdata(file);
+ struct v4l2_subdev_frame_interval ival = {
+ 0,
+ p->parm.capture.timeperframe
+ };
+ int rc = 0;
+
+ if (!dev->is_webcam)
+ return -ENOTTY;
+
+ if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+ memset(&p->parm, 0, sizeof(p->parm));
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
- return v4l2_device_call_until_err(&dev->v4l2->v4l2_dev,
- 0, video, s_parm, p);
+ p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ rc = v4l2_device_call_until_err(&dev->v4l2->v4l2_dev, 0,
+ video, s_frame_interval, &ival);
+ if (!rc)
+ p->parm.capture.timeperframe = ival.interval;
+ return rc;
}
static int vidioc_enum_input(struct file *file, void *priv,
@@ -1616,20 +1670,19 @@ static int vidioc_enum_input(struct file *file, void *priv,
n = i->index;
if (n >= MAX_EM28XX_INPUT)
return -EINVAL;
- if (0 == INPUT(n)->type)
+ if (!INPUT(n)->type)
return -EINVAL;
- i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
strcpy(i->name, iname[INPUT(n)->type]);
- if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type))
+ if (INPUT(n)->type == EM28XX_VMUX_TELEVISION)
i->type = V4L2_INPUT_TYPE_TUNER;
i->std = dev->v4l2->vdev.tvnorms;
/* webcams do not have the STD API */
- if (dev->board.is_webcam)
+ if (dev->is_webcam)
i->capabilities = 0;
return 0;
@@ -1650,7 +1703,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
if (i >= MAX_EM28XX_INPUT)
return -EINVAL;
- if (0 == INPUT(i)->type)
+ if (!INPUT(i)->type)
return -EINVAL;
video_mux(dev, i);
@@ -1696,13 +1749,14 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
return 0;
}
-static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
+static int vidioc_s_audio(struct file *file, void *priv,
+ const struct v4l2_audio *a)
{
struct em28xx *dev = video_drvdata(file);
if (a->index >= MAX_EM28XX_INPUT)
return -EINVAL;
- if (0 == INPUT(a->index)->type)
+ if (!INPUT(a->index)->type)
return -EINVAL;
dev->ctl_ainput = INPUT(a->index)->amux;
@@ -1719,7 +1773,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
{
struct em28xx *dev = video_drvdata(file);
- if (0 != t->index)
+ if (t->index != 0)
return -EINVAL;
strcpy(t->name, "Tuner");
@@ -1733,7 +1787,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
{
struct em28xx *dev = video_drvdata(file);
- if (0 != t->index)
+ if (t->index != 0)
return -EINVAL;
v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, s_tuner, t);
@@ -1746,7 +1800,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
- if (0 != f->tuner)
+ if (f->tuner != 0)
return -EINVAL;
f->frequency = v4l2->frequency;
@@ -1760,7 +1814,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
- if (0 != f->tuner)
+ if (f->tuner != 0)
return -EINVAL;
v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_frequency, f);
@@ -1884,8 +1938,9 @@ static int vidioc_querycap(struct file *file, void *priv,
if (dev->tuner_type != TUNER_ABSENT)
cap->device_caps |= V4L2_CAP_TUNER;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
- V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps |
+ V4L2_CAP_DEVICE_CAPS | V4L2_CAP_READWRITE |
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
if (video_is_registered(&v4l2->vbi_dev))
cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
if (video_is_registered(&v4l2->radio_dev))
@@ -1978,9 +2033,9 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
return 0;
}
-/* ----------------------------------------------------------- */
-/* RADIO ESPECIFIC IOCTLS */
-/* ----------------------------------------------------------- */
+/*
+ * RADIO ESPECIFIC IOCTLS
+ */
static int radio_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
@@ -2002,7 +2057,7 @@ static int radio_s_tuner(struct file *file, void *priv,
{
struct em28xx *dev = video_drvdata(file);
- if (0 != t->index)
+ if (t->index != 0)
return -EINVAL;
v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, s_tuner, t);
@@ -2097,7 +2152,7 @@ static int em28xx_v4l2_open(struct file *filp)
* em28xx_v4l2_fini()
* unregisters the v4l2,i2c and usb devices
* called when the device gets disconected or at module unload
-*/
+ */
static int em28xx_v4l2_fini(struct em28xx *dev)
{
struct em28xx_v4l2 *v4l2 = dev->v4l2;
@@ -2112,7 +2167,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
return 0;
}
- if (v4l2 == NULL)
+ if (!v4l2)
return 0;
dev_info(&dev->intf->dev, "Closing video extension\n");
@@ -2127,17 +2182,17 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
if (video_is_registered(&v4l2->radio_dev)) {
dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n",
- video_device_node_name(&v4l2->radio_dev));
+ video_device_node_name(&v4l2->radio_dev));
video_unregister_device(&v4l2->radio_dev);
}
if (video_is_registered(&v4l2->vbi_dev)) {
dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n",
- video_device_node_name(&v4l2->vbi_dev));
+ video_device_node_name(&v4l2->vbi_dev));
video_unregister_device(&v4l2->vbi_dev);
}
if (video_is_registered(&v4l2->vdev)) {
dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n",
- video_device_node_name(&v4l2->vdev));
+ video_device_node_name(&v4l2->vdev));
video_unregister_device(&v4l2->vdev);
}
@@ -2189,7 +2244,7 @@ static int em28xx_v4l2_close(struct file *filp)
struct em28xx *dev = video_drvdata(filp);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct usb_device *udev = interface_to_usbdev(dev->intf);
- int errCode;
+ int err;
em28xx_videodbg("users=%d\n", v4l2->users);
@@ -2202,7 +2257,7 @@ static int em28xx_v4l2_close(struct file *filp)
goto exit;
/* Save some power by putting tuner to sleep */
- v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0);
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, standby);
/* do this before setting alternate! */
em28xx_set_mode(dev, EM28XX_SUSPEND);
@@ -2210,11 +2265,11 @@ static int em28xx_v4l2_close(struct file *filp)
/* set alternate 0 */
dev->alt = 0;
em28xx_videodbg("setting alternate 0\n");
- errCode = usb_set_interface(udev, 0, 0);
- if (errCode < 0) {
+ err = usb_set_interface(udev, 0, 0);
+ if (err < 0) {
dev_err(&dev->intf->dev,
"cannot change alternate number to 0 (error=%i)\n",
- errCode);
+ err);
}
}
@@ -2343,7 +2398,7 @@ static void em28xx_vdev_init(struct em28xx *dev,
*vfd = *template;
vfd->v4l2_dev = &dev->v4l2->v4l2_dev;
vfd->lock = &dev->lock;
- if (dev->board.is_webcam)
+ if (dev->is_webcam)
vfd->tvnorms = 0;
snprintf(vfd->name, sizeof(vfd->name), "%s %s",
@@ -2372,7 +2427,7 @@ static void em28xx_tuner_setup(struct em28xx *dev, unsigned short tuner_addr)
0, tuner, s_type_addr, &tun_setup);
}
- if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
+ if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type) {
tun_setup.type = dev->tuner_type;
tun_setup.addr = tuner_addr;
@@ -2435,7 +2490,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
mutex_lock(&dev->lock);
- v4l2 = kzalloc(sizeof(struct em28xx_v4l2), GFP_KERNEL);
+ v4l2 = kzalloc(sizeof(*v4l2), GFP_KERNEL);
if (!v4l2) {
mutex_unlock(&dev->lock);
return -ENOMEM;
@@ -2458,7 +2513,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
v4l2_ctrl_handler_init(hdl, 8);
v4l2->v4l2_dev.ctrl_handler = hdl;
- if (dev->board.is_webcam)
+ if (dev->is_webcam)
v4l2->progressive = true;
/*
@@ -2470,7 +2525,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
/* request some modules */
- if (dev->board.has_msp34xx)
+ if (dev->has_msp34xx)
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
&dev->i2c_adap[dev->def_i2c_bus],
"msp3400", 0, msp3400_addrs);
@@ -2559,7 +2614,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
INIT_LIST_HEAD(&dev->vidq.active);
INIT_LIST_HEAD(&dev->vbiq.active);
- if (dev->board.has_msp34xx) {
+ if (dev->has_msp34xx) {
/* Send a reset to other chips via gpio */
ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
if (ret < 0) {
@@ -2568,7 +2623,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
__func__, ret);
goto unregister_dev;
}
- msleep(3);
+ usleep_range(10000, 11000);
ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
if (ret < 0) {
@@ -2577,7 +2632,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
__func__, ret);
goto unregister_dev;
}
- msleep(3);
+ usleep_range(10000, 11000);
}
/* set default norm */
@@ -2589,8 +2644,10 @@ static int em28xx_v4l2_init(struct em28xx *dev)
v4l2->format = &format[0];
maxw = norm_maxw(dev);
- /* MaxPacketSize for em2800 is too small to capture at full resolution
- * use half of maxw as the scaler can only scale to 50% */
+ /*
+ * MaxPacketSize for em2800 is too small to capture at full resolution
+ * use half of maxw as the scaler can only scale to 50%
+ */
if (dev->board.is_em2800)
maxw /= 2;
@@ -2611,29 +2668,33 @@ static int em28xx_v4l2_init(struct em28xx *dev)
em28xx_set_outfmt(dev);
/* Add image controls */
- /* NOTE: at this point, the subdevices are already registered, so bridge
- * controls are only added/enabled when no subdevice provides them */
- if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_CONTRAST))
+
+ /*
+ * NOTE: at this point, the subdevices are already registered, so
+ * bridge controls are only added/enabled when no subdevice provides
+ * them
+ */
+ if (!v4l2_ctrl_find(hdl, V4L2_CID_CONTRAST))
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_CONTRAST,
0, 0x1f, 1, CONTRAST_DEFAULT);
- if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_BRIGHTNESS))
+ if (!v4l2_ctrl_find(hdl, V4L2_CID_BRIGHTNESS))
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_BRIGHTNESS,
-0x80, 0x7f, 1, BRIGHTNESS_DEFAULT);
- if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_SATURATION))
+ if (!v4l2_ctrl_find(hdl, V4L2_CID_SATURATION))
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_SATURATION,
0, 0x1f, 1, SATURATION_DEFAULT);
- if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_BLUE_BALANCE))
+ if (!v4l2_ctrl_find(hdl, V4L2_CID_BLUE_BALANCE))
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_BLUE_BALANCE,
-0x30, 0x30, 1, BLUE_BALANCE_DEFAULT);
- if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_RED_BALANCE))
+ if (!v4l2_ctrl_find(hdl, V4L2_CID_RED_BALANCE))
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_RED_BALANCE,
-0x30, 0x30, 1, RED_BALANCE_DEFAULT);
- if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_SHARPNESS))
+ if (!v4l2_ctrl_find(hdl, V4L2_CID_SHARPNESS))
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_SHARPNESS,
0, 0x0f, 1, SHARPNESS_DEFAULT);
@@ -2653,7 +2714,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
v4l2->vdev.queue->lock = &v4l2->vb_queue_lock;
/* disable inapplicable ioctls */
- if (dev->board.is_webcam) {
+ if (dev->is_webcam) {
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_QUERYSTD);
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_STD);
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_STD);
@@ -2683,7 +2744,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
/* Allocate and fill vbi video_device struct */
if (em28xx_vbi_supported(dev) == 1) {
em28xx_vdev_init(dev, &v4l2->vbi_dev, &em28xx_video_template,
- "vbi");
+ "vbi");
v4l2->vbi_dev.queue = &v4l2->vb_vbiq;
v4l2->vbi_dev.queue->lock = &v4l2->vb_vbi_queue_lock;
@@ -2713,7 +2774,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
em28xx_vdev_init(dev, &v4l2->radio_dev, &em28xx_radio_template,
- "radio");
+ "radio");
ret = video_register_device(&v4l2->radio_dev, VFL_TYPE_RADIO,
radio_nr[dev->devno]);
if (ret < 0) {
@@ -2749,7 +2810,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
video_device_node_name(&v4l2->vbi_dev));
/* Save some power by putting tuner to sleep */
- v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0);
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, standby);
/* initialize videobuf2 stuff */
em28xx_vb2_setup(dev);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 88084f24f033..63c7c6124707 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -1,31 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
- em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices
-
- Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
- Ludovico Cavedon <cavedon@sssup.it>
- Mauro Carvalho Chehab <mchehab@infradead.org>
- Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
-
- Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.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.
-
- 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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices
+ *
+ * Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
+ * Ludovico Cavedon <cavedon@sssup.it>
+ * Mauro Carvalho Chehab <mchehab@infradead.org>
+ * Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
+ *
+ * Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.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.
+ *
+ * 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 _EM28XX_H
#define _EM28XX_H
+#include <linux/bitfield.h>
+
#define EM28XX_VERSION "0.2.2"
#define DRIVER_DESC "Empia em28xx device driver"
@@ -166,7 +165,7 @@
#define EM28XX_STOP_AUDIO 0
/* maximum number of em28xx boards */
-#define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */
+#define EM28XX_MAXBOARDS DVB_MAX_ADAPTERS /* All adapters could be em28xx */
/* maximum number of frames that can be queued */
#define EM28XX_NUM_FRAMES 5
@@ -180,43 +179,32 @@
/* max number of I2C buses on em28xx devices */
#define NUM_I2C_BUSES 2
-/* isoc transfers: number of packets for each buffer
- windows requests only 64 packets .. so we better do the same
- this is what I found out for all alternate numbers there!
+/*
+ * isoc transfers: number of packets for each buffer
+ * windows requests only 64 packets .. so we better do the same
+ * this is what I found out for all alternate numbers there!
*/
#define EM28XX_NUM_ISOC_PACKETS 64
#define EM28XX_DVB_NUM_ISOC_PACKETS 64
-/* bulk transfers: transfer buffer size = packet size * packet multiplier
- USB 2.0 spec says bulk packet size is always 512 bytes
+/*
+ * bulk transfers: transfer buffer size = packet size * packet multiplier
+ * USB 2.0 spec says bulk packet size is always 512 bytes
*/
#define EM28XX_BULK_PACKET_MULTIPLIER 384
-#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 384
+#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 94
#define EM28XX_INTERLACED_DEFAULT 1
-/*
- * Time in msecs to wait for i2c xfers to finish.
- * 35ms is the maximum time a SMBUS device could wait when
- * clock stretching is used. As the transfer itself will take
- * some time to happen, set it to 35 ms.
- *
- * Ok, I2C doesn't specify any limit. So, eventually, we may need
- * to increase this timeout.
- *
- * FIXME: this assumes that an I2C message is not longer than 1ms.
- * This is actually dependent on the I2C bus speed, although most
- * devices use a 100kHz clock. So, this assumtion is true most of
- * the time.
- */
-#define EM28XX_I2C_XFER_TIMEOUT 36
-
/* time in msecs to wait for AC97 xfers to finish */
#define EM28XX_AC97_XFER_TIMEOUT 100
/* max. number of button state polling addresses */
#define EM28XX_NUM_BUTTON_ADDRESSES_MAX 5
+#define PRIMARY_TS 0
+#define SECONDARY_TS 1
+
enum em28xx_mode {
EM28XX_SUSPEND,
EM28XX_ANALOG_MODE,
@@ -225,64 +213,83 @@ enum em28xx_mode {
struct em28xx;
+/**
+ * struct em28xx_usb_bufs - Contains URB-related buffer data
+ *
+ * @max_pkt_size: max packet size of isoc transaction
+ * @num_packets: number of packets in each buffer
+ * @num_bufs: number of allocated urb
+ * @urb: urb for isoc/bulk transfers
+ * @buf: transfer buffers for isoc/bulk transfer
+ */
struct em28xx_usb_bufs {
- /* max packet size of isoc transaction */
int max_pkt_size;
-
- /* number of packets in each buffer */
int num_packets;
-
- /* number of allocated urbs */
int num_bufs;
-
- /* urb for isoc/bulk transfers */
struct urb **urb;
-
- /* transfer buffers for isoc/bulk transfer */
- char **transfer_buffer;
+ char **buf;
};
+/**
+ * struct em28xx_usb_ctl - Contains URB-related buffer data
+ *
+ * @analog_bufs: isoc/bulk transfer buffers for analog mode
+ * @digital_bufs: isoc/bulk transfer buffers for digital mode
+ * @vid_buf: Stores already requested video buffers
+ * @vbi_buf: Stores already requested VBI buffers
+ * @urb_data_copy: copy data from URB
+ */
struct em28xx_usb_ctl {
- /* isoc/bulk transfer buffers for analog mode */
struct em28xx_usb_bufs analog_bufs;
-
- /* isoc/bulk transfer buffers for digital mode */
struct em28xx_usb_bufs digital_bufs;
-
- /* Stores already requested buffers */
struct em28xx_buffer *vid_buf;
struct em28xx_buffer *vbi_buf;
-
- /* copy data from URB */
int (*urb_data_copy)(struct em28xx *dev, struct urb *urb);
-
};
-/* Struct to enumberate video formats */
+/**
+ * struct em28xx_fmt - Struct to enumberate video formats
+ *
+ * @name: Name for the video standard
+ * @fourcc: v4l2 format id
+ * @depth: mean number of bits to represent a pixel
+ * @reg: em28xx register value to set it
+ */
struct em28xx_fmt {
- char *name;
- u32 fourcc; /* v4l2 format id */
- int depth;
- int reg;
+ char *name;
+ u32 fourcc;
+ int depth;
+ int reg;
};
-/* buffer for one video frame */
+/**
+ * struct em28xx_buffer- buffer for storing one video frame
+ *
+ * @vb: common v4l buffer stuff
+ * @list: List to associate it with the other buffers
+ * @mem: pointer to the buffer, as returned by vb2_plane_vaddr()
+ * @length: length of the buffer, as returned by vb2_plane_size()
+ * @top_field: If non-zero, indicate that the buffer is the top field
+ * @pos: Indicate the next position of the buffer to be filled.
+ * @vb_buf: pointer to vmalloc memory address in vb
+ *
+ * .. note::
+ *
+ * in interlaced mode, @pos is reset to zero at the start of each new
+ * field (not frame !)
+ */
struct em28xx_buffer {
- /* common v4l buffer stuff -- must be first */
- struct vb2_v4l2_buffer vb;
- struct list_head list;
+ struct vb2_v4l2_buffer vb; /* must be first */
- void *mem;
- unsigned int length;
- int top_field;
+ struct list_head list;
- /* counter to control buffer fill */
- unsigned int pos;
- /* NOTE; in interlaced mode, this value is reset to zero at
- * the start of each new field (not frame !) */
+ void *mem;
+ unsigned int length;
+ int top_field;
- /* pointer to vmalloc memory address in vb */
- char *vb_buf;
+ unsigned int pos;
+
+ char *vb_buf;
};
struct em28xx_dmaqueue {
@@ -324,20 +331,48 @@ enum em28xx_usb_audio_type {
EM28XX_USB_AUDIO_VENDOR,
};
-/* em28xx has two audio inputs: tuner and line in.
- However, on most devices, an auxiliary AC97 codec device is used.
- The AC97 device may have several different inputs and outputs,
- depending on their model. So, it is possible to use AC97 mixer to
- address more than two different entries.
+/**
+ * em28xx_amux - describes the type of audio input used by em28xx
+ *
+ * @EM28XX_AMUX_VIDEO:
+ * On devices without AC97, this is the only value that it is currently
+ * allowed.
+ * On devices with AC97, it corresponds to the AC97 mixer "Video" control.
+ * @EM28XX_AMUX_LINE_IN:
+ * Only for devices with AC97. Corresponds to AC97 mixer "Line In".
+ * @EM28XX_AMUX_VIDEO2:
+ * Only for devices with AC97. It means that em28xx should use "Line In"
+ * And AC97 should use the "Video" mixer control.
+ * @EM28XX_AMUX_PHONE:
+ * Only for devices with AC97. Corresponds to AC97 mixer "Phone".
+ * @EM28XX_AMUX_MIC:
+ * Only for devices with AC97. Corresponds to AC97 mixer "Mic".
+ * @EM28XX_AMUX_CD:
+ * Only for devices with AC97. Corresponds to AC97 mixer "CD".
+ * @EM28XX_AMUX_AUX:
+ * Only for devices with AC97. Corresponds to AC97 mixer "Aux".
+ * @EM28XX_AMUX_PCM_OUT:
+ * Only for devices with AC97. Corresponds to AC97 mixer "PCM out".
+ *
+ * The em28xx chip itself has only two audio inputs: tuner and line in.
+ * On almost all devices, only the tuner input is used.
+ *
+ * However, on most devices, an auxiliary AC97 codec device is used,
+ * usually connected to the em28xx tuner input (except for
+ * @EM28XX_AMUX_LINE_IN).
+ *
+ * The AC97 device typically have several different inputs and outputs.
+ * The exact number and description depends on their model.
+ *
+ * It is possible to AC97 to mixer more than one different entries at the
+ * same time, via the alsa mux.
*/
enum em28xx_amux {
- /* This is the only entry for em28xx tuner input */
- EM28XX_AMUX_VIDEO, /* em28xx tuner, AC97 mixer Video */
-
- EM28XX_AMUX_LINE_IN, /* AC97 mixer Line In */
+ EM28XX_AMUX_VIDEO,
+ EM28XX_AMUX_LINE_IN,
/* Some less-common mixer setups */
- EM28XX_AMUX_VIDEO2, /* em28xx Line in, AC97 mixer Video */
+ EM28XX_AMUX_VIDEO2,
EM28XX_AMUX_PHONE,
EM28XX_AMUX_MIC,
EM28XX_AMUX_CD,
@@ -347,14 +382,14 @@ enum em28xx_amux {
enum em28xx_aout {
/* AC97 outputs */
- EM28XX_AOUT_MASTER = 1 << 0,
- EM28XX_AOUT_LINE = 1 << 1,
- EM28XX_AOUT_MONO = 1 << 2,
- EM28XX_AOUT_LFE = 1 << 3,
- EM28XX_AOUT_SURR = 1 << 4,
+ EM28XX_AOUT_MASTER = BIT(0),
+ EM28XX_AOUT_LINE = BIT(1),
+ EM28XX_AOUT_MONO = BIT(2),
+ EM28XX_AOUT_LFE = BIT(3),
+ EM28XX_AOUT_SURR = BIT(4),
/* PCM IN Mixer - used by AC97_RECORD_SELECT register */
- EM28XX_AOUT_PCM_IN = 1 << 7,
+ EM28XX_AOUT_PCM_IN = BIT(7),
/* Bits 10-8 are used to indicate the PCM IN record select */
EM28XX_AOUT_PCM_MIC_PCM = 0 << 8,
@@ -383,7 +418,7 @@ struct em28xx_input {
unsigned int vmux;
enum em28xx_amux amux;
enum em28xx_aout aout;
- struct em28xx_reg_seq *gpio;
+ const struct em28xx_reg_seq *gpio;
};
#define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
@@ -441,22 +476,23 @@ struct em28xx_board {
int vchannels;
int tuner_type;
int tuner_addr;
- unsigned def_i2c_bus; /* Default I2C bus */
+ unsigned int def_i2c_bus; /* Default I2C bus */
/* i2c flags */
unsigned int tda9887_conf;
/* GPIO sequences */
- struct em28xx_reg_seq *dvb_gpio;
- struct em28xx_reg_seq *suspend_gpio;
- struct em28xx_reg_seq *tuner_gpio;
- struct em28xx_reg_seq *mute_gpio;
+ const struct em28xx_reg_seq *dvb_gpio;
+ const struct em28xx_reg_seq *suspend_gpio;
+ const struct em28xx_reg_seq *tuner_gpio;
+ const struct em28xx_reg_seq *mute_gpio;
unsigned int is_em2800:1;
unsigned int has_msp34xx:1;
unsigned int mts_firmware:1;
unsigned int max_range_640_480:1;
unsigned int has_dvb:1;
+ unsigned int has_dual_ts:1;
unsigned int is_webcam:1;
unsigned int valid:1;
unsigned int has_ir_i2c:1;
@@ -476,7 +512,7 @@ struct em28xx_board {
struct em28xx_led *leds;
/* Buttons */
- struct em28xx_button *buttons;
+ const struct em28xx_button *buttons;
};
struct em28xx_eeprom {
@@ -519,8 +555,8 @@ struct em28xx_v4l2 {
/* Videobuf2 */
struct vb2_queue vb_vidq;
struct vb2_queue vb_vbiq;
- struct mutex vb_queue_lock;
- struct mutex vb_vbi_queue_lock;
+ struct mutex vb_queue_lock; /* Protects vb_vidq */
+ struct mutex vb_vbi_queue_lock; /* Protects vb_vbiq */
u8 vinmode;
u8 vinctl;
@@ -546,8 +582,8 @@ struct em28xx_v4l2 {
/* Frame properties */
int width; /* current frame width */
int height; /* current frame height */
- unsigned hscale; /* horizontal scale factor (see datasheet) */
- unsigned vscale; /* vertical scale factor (see datasheet) */
+ unsigned int hscale; /* horizontal scale factor (see datasheet) */
+ unsigned int vscale; /* vertical scale factor (see datasheet) */
unsigned int vbi_width;
unsigned int vbi_height; /* lines per field */
@@ -565,7 +601,7 @@ struct em28xx_v4l2 {
struct em28xx_audio {
char name[50];
- unsigned num_urb;
+ unsigned int num_urb;
char **transfer_buffer;
struct urb **urb;
struct usb_device *udev;
@@ -578,7 +614,7 @@ struct em28xx_audio {
size_t period;
int users;
- spinlock_t slock;
+ spinlock_t slock; /* Protects struct em28xx_audio */
/* Controls streaming */
struct work_struct wq_trigger; /* trigger to start/stop audio */
@@ -596,7 +632,7 @@ enum em28xx_i2c_algo_type {
struct em28xx_i2c_bus {
struct em28xx *dev;
- unsigned bus;
+ unsigned int bus;
enum em28xx_i2c_algo_type algo_type;
};
@@ -604,102 +640,111 @@ struct em28xx_i2c_bus {
struct em28xx {
struct kref ref;
- /* Sub-module data */
+ // Sub-module data
struct em28xx_v4l2 *v4l2;
struct em28xx_dvb *dvb;
struct em28xx_audio adev;
struct em28xx_IR *ir;
- /* generic device properties */
- int model; /* index in the device_data struct */
- int devno; /* marks the number of this device */
+ // generic device properties
+ int model; // index in the device_data struct
+ int devno; // marks the number of this device
enum em28xx_chip_id chip_id;
- unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */
- unsigned char disconnected:1; /* device has been diconnected */
+ unsigned int is_em25xx:1; // em25xx/em276x/7x/8x family bridge
+ unsigned int disconnected:1; // device has been diconnected
unsigned int has_video:1;
unsigned int is_audio_only:1;
+ unsigned int is_webcam:1;
+ unsigned int has_msp34xx:1;
+ unsigned int i2c_speed:2;
enum em28xx_int_audio_type int_audio_type;
enum em28xx_usb_audio_type usb_audio_type;
+ unsigned char name[32];
struct em28xx_board board;
- enum em28xx_sensor em28xx_sensor; /* camera specific */
+ enum em28xx_sensor em28xx_sensor; // camera specific
- /* Some older em28xx chips needs a waiting time after writing */
+ // Some older em28xx chips needs a waiting time after writing
unsigned int wait_after_write;
struct list_head devlist;
- u32 i2s_speed; /* I2S speed for audio digital stream */
+ u32 i2s_speed; // I2S speed for audio digital stream
struct em28xx_audio_mode audio_mode;
- int tuner_type; /* type of the tuner */
+ int tuner_type; // type of the tuner
- /* i2c i/o */
+ // i2c i/o
struct i2c_adapter i2c_adap[NUM_I2C_BUSES];
struct i2c_client i2c_client[NUM_I2C_BUSES];
struct em28xx_i2c_bus i2c_bus[NUM_I2C_BUSES];
unsigned char eeprom_addrwidth_16bit:1;
- unsigned def_i2c_bus; /* Default I2C bus */
- unsigned cur_i2c_bus; /* Current I2C bus */
+ unsigned int def_i2c_bus; // Default I2C bus
+ unsigned int cur_i2c_bus; // Current I2C bus
struct rt_mutex i2c_bus_lock;
- /* video for linux */
- unsigned int ctl_input; /* selected input */
- unsigned int ctl_ainput;/* selected audio input */
- unsigned int ctl_aoutput;/* selected audio output */
+ // video for linux
+ unsigned int ctl_input; // selected input
+ unsigned int ctl_ainput;// selected audio input
+ unsigned int ctl_aoutput;// selected audio output
int mute;
int volume;
- unsigned long hash; /* eeprom hash - for boards with generic ID */
- unsigned long i2c_hash; /* i2c devicelist hash -
- for boards with generic ID */
+ unsigned long hash; // eeprom hash - for boards with generic ID
+ unsigned long i2c_hash; // i2c devicelist hash -
+ // for boards with generic ID
struct work_struct request_module_wk;
- /* locks */
- struct mutex lock;
+ // locks
+ struct mutex lock; /* protects em28xx struct */
struct mutex ctrl_urb_lock; /* protects urb_buf */
- /* resources in use */
+ // resources in use
unsigned int resources;
- /* eeprom content */
+ // eeprom content
u8 *eedata;
u16 eedata_len;
- /* Isoc control struct */
+ // Isoc control struct
struct em28xx_dmaqueue vidq;
struct em28xx_dmaqueue vbiq;
struct em28xx_usb_ctl usb_ctl;
- spinlock_t slock;
-
- /* usb transfer */
- struct usb_interface *intf; /* the usb interface */
- u8 ifnum; /* number of the assigned usb interface */
- u8 analog_ep_isoc; /* address of isoc endpoint for analog */
- u8 analog_ep_bulk; /* address of bulk endpoint for analog */
- u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */
- u8 dvb_ep_bulk; /* address of bulk endpoint for DVB */
- int alt; /* alternate setting */
- int max_pkt_size; /* max packet size of the selected ep at alt */
- int packet_multiplier; /* multiplier for wMaxPacketSize, used for
- URB buffer size definition */
- int num_alt; /* number of alternative settings */
- unsigned int *alt_max_pkt_size_isoc; /* array of isoc wMaxPacketSize */
- unsigned int analog_xfer_bulk:1; /* use bulk instead of isoc
- transfers for analog */
- int dvb_alt_isoc; /* alternate setting for DVB isoc transfers */
- unsigned int dvb_max_pkt_size_isoc; /* isoc max packet size of the
- selected DVB ep at dvb_alt */
- unsigned int dvb_xfer_bulk:1; /* use bulk instead of isoc
- transfers for DVB */
- char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */
-
- /* helper funcs that call usb_control_msg */
+
+ spinlock_t slock; /* Protects em28xx video/vbi/dvb IRQ stream data */
+
+ // usb transfer
+ struct usb_interface *intf; // the usb interface
+ u8 ifnum; // number of the assigned usb interface
+ u8 analog_ep_isoc; // address of isoc endpoint for analog
+ u8 analog_ep_bulk; // address of bulk endpoint for analog
+ u8 dvb_ep_isoc_ts2; // address of isoc endpoint for DVB TS2
+ u8 dvb_ep_bulk_ts2; // address of bulk endpoint for DVB TS2
+ u8 dvb_ep_isoc; // address of isoc endpoint for DVB
+ u8 dvb_ep_bulk; // address of bulk endpoint for DVB
+ int alt; // alternate setting
+ int max_pkt_size; // max packet size of the selected ep at alt
+ int packet_multiplier; // multiplier for wMaxPacketSize, used for
+ // URB buffer size definition
+ int num_alt; // number of alternative settings
+ unsigned int *alt_max_pkt_size_isoc; // array of isoc wMaxPacketSize
+ unsigned int analog_xfer_bulk:1; // use bulk instead of isoc
+ // transfers for analog
+ int dvb_alt_isoc; // alternate setting for DVB isoc transfers
+ unsigned int dvb_max_pkt_size_isoc; // isoc max packet size of the
+ // selected DVB ep at dvb_alt
+ unsigned int dvb_max_pkt_size_isoc_ts2; // isoc max packet size of the
+ // selected DVB ep at dvb_alt
+ unsigned int dvb_xfer_bulk:1; // use bulk instead of isoc
+ // transfers for DVB
+ char urb_buf[URB_MAX_CTRL_SIZE]; // urb control msg buffer
+
+ // helper funcs that call usb_control_msg
int (*em28xx_write_regs)(struct em28xx *dev, u16 reg,
char *buf, int len);
int (*em28xx_read_reg)(struct em28xx *dev, u16 reg);
@@ -711,14 +756,14 @@ struct em28xx {
enum em28xx_mode mode;
- /* Button state polling */
+ // Button state polling
struct delayed_work buttons_query_work;
u8 button_polling_addresses[EM28XX_NUM_BUTTON_ADDRESSES_MAX];
u8 button_polling_last_values[EM28XX_NUM_BUTTON_ADDRESSES_MAX];
u8 num_button_polling_addresses;
- u16 button_polling_interval; /* [ms] */
- /* Snapshot button input device */
- char snapshot_button_path[30]; /* path of the input dev */
+ u16 button_polling_interval; // [ms]
+ // Snapshot button input device
+ char snapshot_button_path[30]; // path of the input dev
struct input_dev *sbutton_input_dev;
#ifdef CONFIG_MEDIA_CONTROLLER
@@ -726,6 +771,9 @@ struct em28xx {
struct media_entity input_ent[MAX_EM28XX_INPUT];
struct media_pad input_pad[MAX_EM28XX_INPUT];
#endif
+
+ struct em28xx *dev_next;
+ int ts;
};
#define kref_to_dev(d) container_of(d, struct em28xx, ref)
@@ -734,17 +782,17 @@ struct em28xx_ops {
struct list_head next;
char *name;
int id;
- int (*init)(struct em28xx *);
- int (*fini)(struct em28xx *);
- int (*suspend)(struct em28xx *);
- int (*resume)(struct em28xx *);
+ int (*init)(struct em28xx *dev);
+ int (*fini)(struct em28xx *dev);
+ int (*suspend)(struct em28xx *dev);
+ int (*resume)(struct em28xx *dev);
};
/* Provided by em28xx-i2c.c */
-void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus);
-int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
+void em28xx_do_i2c_scan(struct em28xx *dev, unsigned int bus);
+int em28xx_i2c_register(struct em28xx *dev, unsigned int bus,
enum em28xx_i2c_algo_type algo_type);
-int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus);
+int em28xx_i2c_unregister(struct em28xx *dev, unsigned int bus);
/* Provided by em28xx-core.c */
int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
@@ -778,7 +826,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode);
void em28xx_stop_urbs(struct em28xx *dev);
int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
-int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
+int em28xx_gpio_set(struct em28xx *dev, const struct em28xx_reg_seq *gpio);
int em28xx_register_extension(struct em28xx_ops *dev);
void em28xx_unregister_extension(struct em28xx_ops *dev);
void em28xx_init_extension(struct em28xx *dev);
@@ -787,7 +835,7 @@ int em28xx_suspend_extension(struct em28xx *dev);
int em28xx_resume_extension(struct em28xx *dev);
/* Provided by em28xx-cards.c */
-extern struct em28xx_board em28xx_boards[];
+extern const struct em28xx_board em28xx_boards[];
extern struct usb_device_id em28xx_id_table[];
int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
diff --git a/drivers/media/usb/go7007/snd-go7007.c b/drivers/media/usb/go7007/snd-go7007.c
index c618764480c6..f84a2130f033 100644
--- a/drivers/media/usb/go7007/snd-go7007.c
+++ b/drivers/media/usb/go7007/snd-go7007.c
@@ -227,7 +227,7 @@ int go7007_snd_init(struct go7007 *go)
{
static int dev;
struct go7007_snd *gosnd;
- int ret = 0;
+ int ret;
if (dev >= SNDRV_CARDS)
return -ENODEV;
diff --git a/drivers/media/usb/gspca/dtcs033.c b/drivers/media/usb/gspca/dtcs033.c
index cdf27cf0112a..7654c8c08eda 100644
--- a/drivers/media/usb/gspca/dtcs033.c
+++ b/drivers/media/usb/gspca/dtcs033.c
@@ -76,12 +76,10 @@ static int reg_reqs(struct gspca_dev *gspca_dev,
} else if (preq->bRequestType & USB_DIR_IN) {
gspca_dbg(gspca_dev, D_STREAM,
- "USB IN (%d) returned[%d] %02X %02X %02X %s\n",
+ "USB IN (%d) returned[%d] %3ph %s",
i,
preq->wLength,
- gspca_dev->usb_buf[0],
- gspca_dev->usb_buf[1],
- gspca_dev->usb_buf[2],
+ gspca_dev->usb_buf,
preq->wLength > 3 ? "...\n" : "\n");
}
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index 8c2a86d71e8a..82927eb334c4 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -648,8 +648,8 @@ static void s2255_fillbuff(struct s2255_vc *vc,
pr_err("s2255: =======no frame\n");
return;
}
- dprintk(dev, 2, "s2255fill at : Buffer 0x%08lx size= %d\n",
- (unsigned long)vbuf, pos);
+ dprintk(dev, 2, "s2255fill at : Buffer %p size= %d\n",
+ vbuf, pos);
}
@@ -803,10 +803,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
}
if (f->fmt.pix.width >= LINE_SZ_4CIFS_NTSC)
f->fmt.pix.width = LINE_SZ_4CIFS_NTSC;
- else if (f->fmt.pix.width >= LINE_SZ_2CIFS_NTSC)
- f->fmt.pix.width = LINE_SZ_2CIFS_NTSC;
- else if (f->fmt.pix.width >= LINE_SZ_1CIFS_NTSC)
- f->fmt.pix.width = LINE_SZ_1CIFS_NTSC;
else
f->fmt.pix.width = LINE_SZ_1CIFS_NTSC;
} else {
@@ -820,10 +816,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
}
if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL)
f->fmt.pix.width = LINE_SZ_4CIFS_PAL;
- else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL)
- f->fmt.pix.width = LINE_SZ_2CIFS_PAL;
- else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL)
- f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
else
f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
}
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index f13e4b01b5a5..6d436e9e454f 100644
--- a/drivers/media/usb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
@@ -179,8 +179,7 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev,
smsusb_onresponse,
surb
);
- surb->urb.transfer_dma = surb->cb->phys;
- surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ surb->urb.transfer_flags |= URB_FREE_BUFFER;
return usb_submit_urb(&surb->urb, GFP_ATOMIC);
}
@@ -446,6 +445,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
dev->in_ep, dev->out_ep);
params.device = &dev->udev->dev;
+ params.usb_device = dev->udev;
params.buffer_size = dev->buffer_size;
params.num_buffers = MAX_BUFFERS;
params.sendrequest_handler = smsusb_sendrequest;
diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c
index 4d5f4cc4887e..70939e96b856 100644
--- a/drivers/media/usb/tm6000/tm6000-cards.c
+++ b/drivers/media/usb/tm6000/tm6000-cards.c
@@ -1174,7 +1174,7 @@ static int tm6000_usb_probe(struct usb_interface *interface,
{
struct usb_device *usbdev;
struct tm6000_core *dev;
- int i, rc = 0;
+ int i, rc;
int nr = 0;
char *speed;
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c
index 8314d3fa9241..b2399d4266da 100644
--- a/drivers/media/usb/tm6000/tm6000-video.c
+++ b/drivers/media/usb/tm6000/tm6000-video.c
@@ -1346,9 +1346,8 @@ static int __tm6000_open(struct file *file)
fh->width = dev->width;
fh->height = dev->height;
- dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n",
- (unsigned long)fh, (unsigned long)dev,
- (unsigned long)&dev->vidq);
+ dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=%p, dev=%p, dev->vidq=%p\n",
+ fh, dev, &dev->vidq);
dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty queued=%d\n",
list_empty(&dev->vidq.queued));
dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty active=%d\n",
diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c
index 127f8a0c098b..5095c380b2c1 100644
--- a/drivers/media/usb/usbtv/usbtv-core.c
+++ b/drivers/media/usb/usbtv/usbtv-core.c
@@ -112,6 +112,8 @@ static int usbtv_probe(struct usb_interface *intf,
return 0;
usbtv_audio_fail:
+ /* we must not free at this point */
+ usb_get_dev(usbtv->udev);
usbtv_video_free(usbtv);
usbtv_video_fail:
@@ -145,6 +147,7 @@ static void usbtv_disconnect(struct usb_interface *intf)
static const struct usb_device_id usbtv_id_table[] = {
{ USB_DEVICE(0x1b71, 0x3002) },
{ USB_DEVICE(0x1f71, 0x3301) },
+ { USB_DEVICE(0x1f71, 0x3306) },
{}
};
MODULE_DEVICE_TABLE(usb, usbtv_id_table);
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 20397aba6849..102594ec3e97 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -366,10 +366,10 @@ static struct uvc_menu_info exposure_auto_controls[] = {
{ 8, "Aperture Priority Mode" },
};
-static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
- __u8 query, const __u8 *data)
+static s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
+ u8 query, const u8 *data)
{
- __s8 zoom = (__s8)data[0];
+ s8 zoom = (s8)data[0];
switch (query) {
case UVC_GET_CUR:
@@ -385,17 +385,17 @@ static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
}
static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
- __s32 value, __u8 *data)
+ s32 value, u8 *data)
{
data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
data[2] = min((int)abs(value), 0xff);
}
-static __s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
- __u8 query, const __u8 *data)
+static s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
+ u8 query, const u8 *data)
{
unsigned int first = mapping->offset / 8;
- __s8 rel = (__s8)data[first];
+ s8 rel = (s8)data[first];
switch (query) {
case UVC_GET_CUR:
@@ -412,7 +412,7 @@ static __s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
}
static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
- __s32 value, __u8 *data)
+ s32 value, u8 *data)
{
unsigned int first = mapping->offset / 8;
@@ -745,17 +745,17 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
* Utility functions
*/
-static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
+static inline u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
{
return ctrl->uvc_data + id * ctrl->info.size;
}
-static inline int uvc_test_bit(const __u8 *data, int bit)
+static inline int uvc_test_bit(const u8 *data, int bit)
{
return (data[bit >> 3] >> (bit & 7)) & 1;
}
-static inline void uvc_clear_bit(__u8 *data, int bit)
+static inline void uvc_clear_bit(u8 *data, int bit)
{
data[bit >> 3] &= ~(1 << (bit & 7));
}
@@ -765,20 +765,20 @@ static inline void uvc_clear_bit(__u8 *data, int bit)
* a signed 32bit integer. Sign extension will be performed if the mapping
* references a signed data type.
*/
-static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
- __u8 query, const __u8 *data)
+static s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
+ u8 query, const u8 *data)
{
int bits = mapping->size;
int offset = mapping->offset;
- __s32 value = 0;
- __u8 mask;
+ s32 value = 0;
+ u8 mask;
data += offset / 8;
offset &= 7;
mask = ((1LL << bits) - 1) << offset;
for (; bits > 0; data++) {
- __u8 byte = *data & mask;
+ u8 byte = *data & mask;
value |= offset > 0 ? (byte >> offset) : (byte << (-offset));
bits -= 8 - (offset > 0 ? offset : 0);
offset -= 8;
@@ -796,11 +796,11 @@ static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
* in the little-endian data stored at 'data' to the value 'value'.
*/
static void uvc_set_le_value(struct uvc_control_mapping *mapping,
- __s32 value, __u8 *data)
+ s32 value, u8 *data)
{
int bits = mapping->size;
int offset = mapping->offset;
- __u8 mask;
+ u8 mask;
/* According to the v4l2 spec, writing any value to a button control
* should result in the action belonging to the button control being
@@ -826,13 +826,13 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping,
* Terminal and unit management
*/
-static const __u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
-static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;
-static const __u8 uvc_media_transport_input_guid[16] =
+static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
+static const u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;
+static const u8 uvc_media_transport_input_guid[16] =
UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
static int uvc_entity_match_guid(const struct uvc_entity *entity,
- const __u8 guid[16])
+ const u8 guid[16])
{
switch (UVC_ENTITY_TYPE(entity)) {
case UVC_ITT_CAMERA:
@@ -857,7 +857,7 @@ static int uvc_entity_match_guid(const struct uvc_entity *entity,
* UVC Controls
*/
-static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
+static void __uvc_find_control(struct uvc_entity *entity, u32 v4l2_id,
struct uvc_control_mapping **mapping, struct uvc_control **control,
int next)
{
@@ -890,7 +890,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
}
static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
- __u32 v4l2_id, struct uvc_control_mapping **mapping)
+ u32 v4l2_id, struct uvc_control_mapping **mapping)
{
struct uvc_control *ctrl = NULL;
struct uvc_entity *entity;
@@ -1019,10 +1019,10 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct uvc_menu_info *menu;
unsigned int i;
- memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
+ memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
v4l2_ctrl->id = mapping->id;
v4l2_ctrl->type = mapping->v4l2_type;
- strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
+ strlcpy(v4l2_ctrl->name, mapping->name, sizeof(v4l2_ctrl->name));
v4l2_ctrl->flags = 0;
if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
@@ -1182,7 +1182,7 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
}
}
- strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
+ strlcpy(query_menu->name, menu_info->name, sizeof(query_menu->name));
done:
mutex_unlock(&chain->ctrl_mutex);
@@ -1590,6 +1590,36 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
* Dynamic controls
*/
+/*
+ * Retrieve flags for a given control
+ */
+static int uvc_ctrl_get_flags(struct uvc_device *dev,
+ const struct uvc_control *ctrl,
+ struct uvc_control_info *info)
+{
+ u8 *data;
+ int ret;
+
+ data = kmalloc(1, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
+ info->selector, data, 1);
+ if (!ret)
+ info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
+ | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
+ | (data[0] & UVC_CONTROL_CAP_GET ?
+ UVC_CTRL_FLAG_GET_CUR : 0)
+ | (data[0] & UVC_CONTROL_CAP_SET ?
+ UVC_CTRL_FLAG_SET_CUR : 0)
+ | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
+ UVC_CTRL_FLAG_AUTO_UPDATE : 0);
+
+ kfree(data);
+ return ret;
+}
+
static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
const struct uvc_control *ctrl, struct uvc_control_info *info)
{
@@ -1659,25 +1689,14 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
info->size = le16_to_cpup((__le16 *)data);
- /* Query the control information (GET_INFO) */
- ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
- info->selector, data, 1);
+ ret = uvc_ctrl_get_flags(dev, ctrl, info);
if (ret < 0) {
uvc_trace(UVC_TRACE_CONTROL,
- "GET_INFO failed on control %pUl/%u (%d).\n",
+ "Failed to get flags for control %pUl/%u (%d).\n",
info->entity, info->selector, ret);
goto done;
}
- info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
- | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
- | (data[0] & UVC_CONTROL_CAP_GET ?
- UVC_CTRL_FLAG_GET_CUR : 0)
- | (data[0] & UVC_CONTROL_CAP_SET ?
- UVC_CTRL_FLAG_SET_CUR : 0)
- | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
- UVC_CTRL_FLAG_AUTO_UPDATE : 0);
-
uvc_ctrl_fixup_xu_info(dev, ctrl, info);
uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, "
@@ -1723,9 +1742,9 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
struct uvc_entity *entity;
struct uvc_control *ctrl;
unsigned int i, found = 0;
- __u32 reqflags;
- __u16 size;
- __u8 *data = NULL;
+ u32 reqflags;
+ u16 size;
+ u8 *data = NULL;
int ret;
/* Find the extension unit. */
@@ -1902,6 +1921,13 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
goto done;
}
+ /*
+ * Retrieve control flags from the device. Ignore errors and work with
+ * default flag values from the uvc_ctrl array when the device doesn't
+ * properly implement GET_INFO on standard controls.
+ */
+ uvc_ctrl_get_flags(dev, ctrl, &ctrl->info);
+
ctrl->initialized = 1;
uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
@@ -2150,7 +2176,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
list_for_each_entry(entity, &dev->entities, list) {
struct uvc_control *ctrl;
unsigned int bControlSize = 0, ncontrols;
- __u8 *bmControls = NULL;
+ u8 *bmControls = NULL;
if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
bmControls = entity->extension.bmControls;
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index fd387bf3f02d..2469b49b2b30 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -216,7 +216,7 @@ static struct uvc_format_desc uvc_fmts[] = {
*/
struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
- __u8 epaddr)
+ u8 epaddr)
{
struct usb_host_endpoint *ep;
unsigned int i;
@@ -230,7 +230,7 @@ struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
return NULL;
}
-static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16])
+static struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16])
{
unsigned int len = ARRAY_SIZE(uvc_fmts);
unsigned int i;
@@ -243,9 +243,9 @@ static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16])
return NULL;
}
-static __u32 uvc_colorspace(const __u8 primaries)
+static u32 uvc_colorspace(const u8 primaries)
{
- static const __u8 colorprimaries[] = {
+ static const u8 colorprimaries[] = {
0,
V4L2_COLORSPACE_SRGB,
V4L2_COLORSPACE_470_SYSTEM_M,
@@ -267,14 +267,14 @@ static __u32 uvc_colorspace(const __u8 primaries)
* continued fraction decomposition. Using 8 and 333 for n_terms and threshold
* respectively seems to give nice results.
*/
-void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
+void uvc_simplify_fraction(u32 *numerator, u32 *denominator,
unsigned int n_terms, unsigned int threshold)
{
- uint32_t *an;
- uint32_t x, y, r;
+ u32 *an;
+ u32 x, y, r;
unsigned int i, n;
- an = kmalloc(n_terms * sizeof *an, GFP_KERNEL);
+ an = kmalloc_array(n_terms, sizeof(*an), GFP_KERNEL);
if (an == NULL)
return;
@@ -318,21 +318,21 @@ void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
* to compute numerator / denominator * 10000000 using 32 bit fixed point
* arithmetic only.
*/
-uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator)
+u32 uvc_fraction_to_interval(u32 numerator, u32 denominator)
{
- uint32_t multiplier;
+ u32 multiplier;
/* Saturate the result if the operation would overflow. */
if (denominator == 0 ||
- numerator/denominator >= ((uint32_t)-1)/10000000)
- return (uint32_t)-1;
+ numerator/denominator >= ((u32)-1)/10000000)
+ return (u32)-1;
/* Divide both the denominator and the multiplier by two until
* numerator * multiplier doesn't overflow. If anyone knows a better
* algorithm please let me know.
*/
multiplier = 10000000;
- while (numerator > ((uint32_t)-1)/multiplier) {
+ while (numerator > ((u32)-1)/multiplier) {
multiplier /= 2;
denominator /= 2;
}
@@ -391,7 +391,7 @@ static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id)
static int uvc_parse_format(struct uvc_device *dev,
struct uvc_streaming *streaming, struct uvc_format *format,
- __u32 **intervals, unsigned char *buffer, int buflen)
+ u32 **intervals, unsigned char *buffer, int buflen)
{
struct usb_interface *intf = streaming->intf;
struct usb_host_interface *alts = intf->cur_altsetting;
@@ -401,7 +401,7 @@ static int uvc_parse_format(struct uvc_device *dev,
unsigned int width_multiplier = 1;
unsigned int interval;
unsigned int i, n;
- __u8 ftype;
+ u8 ftype;
format->type = buffer[2];
format->index = buffer[3];
@@ -423,7 +423,7 @@ static int uvc_parse_format(struct uvc_device *dev,
if (fmtdesc != NULL) {
strlcpy(format->name, fmtdesc->name,
- sizeof format->name);
+ sizeof(format->name));
format->fcc = fmtdesc->fcc;
} else {
uvc_printk(KERN_INFO, "Unknown video format %pUl\n",
@@ -466,7 +466,7 @@ static int uvc_parse_format(struct uvc_device *dev,
return -EINVAL;
}
- strlcpy(format->name, "MJPEG", sizeof format->name);
+ strlcpy(format->name, "MJPEG", sizeof(format->name));
format->fcc = V4L2_PIX_FMT_MJPEG;
format->flags = UVC_FMT_FLAG_COMPRESSED;
format->bpp = 0;
@@ -484,13 +484,13 @@ static int uvc_parse_format(struct uvc_device *dev,
switch (buffer[8] & 0x7f) {
case 0:
- strlcpy(format->name, "SD-DV", sizeof format->name);
+ strlcpy(format->name, "SD-DV", sizeof(format->name));
break;
case 1:
- strlcpy(format->name, "SDL-DV", sizeof format->name);
+ strlcpy(format->name, "SDL-DV", sizeof(format->name));
break;
case 2:
- strlcpy(format->name, "HD-DV", sizeof format->name);
+ strlcpy(format->name, "HD-DV", sizeof(format->name));
break;
default:
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
@@ -501,7 +501,7 @@ static int uvc_parse_format(struct uvc_device *dev,
}
strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",
- sizeof format->name);
+ sizeof(format->name));
format->fcc = V4L2_PIX_FMT_DV;
format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM;
@@ -510,7 +510,7 @@ static int uvc_parse_format(struct uvc_device *dev,
/* Create a dummy frame descriptor. */
frame = &format->frame[0];
- memset(&format->frame[0], 0, sizeof format->frame[0]);
+ memset(&format->frame[0], 0, sizeof(format->frame[0]));
frame->bFrameIntervalType = 1;
frame->dwDefaultFrameInterval = 1;
frame->dwFrameInterval = *intervals;
@@ -658,8 +658,8 @@ static int uvc_parse_streaming(struct uvc_device *dev,
int _buflen, buflen = alts->extralen;
unsigned int nformats = 0, nframes = 0, nintervals = 0;
unsigned int size, i, n, p;
- __u32 *interval;
- __u16 psize;
+ u32 *interval;
+ u16 psize;
int ret = -EINVAL;
if (intf->cur_altsetting->desc.bInterfaceSubClass
@@ -677,7 +677,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
return -EINVAL;
}
- streaming = kzalloc(sizeof *streaming, GFP_KERNEL);
+ streaming = kzalloc(sizeof(*streaming), GFP_KERNEL);
if (streaming == NULL) {
usb_driver_release_interface(&uvc_driver.driver, intf);
return -EINVAL;
@@ -827,8 +827,8 @@ static int uvc_parse_streaming(struct uvc_device *dev,
goto error;
}
- size = nformats * sizeof *format + nframes * sizeof *frame
- + nintervals * sizeof *interval;
+ size = nformats * sizeof(*format) + nframes * sizeof(*frame)
+ + nintervals * sizeof(*interval);
format = kzalloc(size, GFP_KERNEL);
if (format == NULL) {
ret = -ENOMEM;
@@ -836,7 +836,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
}
frame = (struct uvc_frame *)&format[nformats];
- interval = (__u32 *)&frame[nframes];
+ interval = (u32 *)&frame[nframes];
streaming->format = format;
streaming->nformats = nformats;
@@ -930,7 +930,7 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE;
entity->bNrInPins = num_inputs;
- entity->baSourceID = (__u8 *)(&entity->pads[num_pads]);
+ entity->baSourceID = (u8 *)(&entity->pads[num_pads]);
return entity;
}
@@ -995,14 +995,14 @@ static int uvc_parse_vendor_control(struct uvc_device *dev,
unit->extension.bNumControls = buffer[20];
memcpy(unit->baSourceID, &buffer[22], p);
unit->extension.bControlSize = buffer[22+p];
- unit->extension.bmControls = (__u8 *)unit + sizeof(*unit);
- unit->extension.bmControlsType = (__u8 *)unit + sizeof(*unit)
+ unit->extension.bmControls = (u8 *)unit + sizeof(*unit);
+ unit->extension.bmControlsType = (u8 *)unit + sizeof(*unit)
+ n;
memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);
if (buffer[24+p+2*n] != 0)
usb_string(udev, buffer[24+p+2*n], unit->name,
- sizeof unit->name);
+ sizeof(unit->name));
else
sprintf(unit->name, "Extension %u", buffer[3]);
@@ -1022,7 +1022,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
struct usb_interface *intf;
struct usb_host_interface *alts = dev->intf->cur_altsetting;
unsigned int i, n, p, len;
- __u16 type;
+ u16 type;
switch (buffer[2]) {
case UVC_VC_HEADER:
@@ -1101,7 +1101,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) {
term->camera.bControlSize = n;
- term->camera.bmControls = (__u8 *)term + sizeof *term;
+ term->camera.bmControls = (u8 *)term + sizeof(*term);
term->camera.wObjectiveFocalLengthMin =
get_unaligned_le16(&buffer[8]);
term->camera.wObjectiveFocalLengthMax =
@@ -1112,17 +1112,17 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
} else if (UVC_ENTITY_TYPE(term) ==
UVC_ITT_MEDIA_TRANSPORT_INPUT) {
term->media.bControlSize = n;
- term->media.bmControls = (__u8 *)term + sizeof *term;
+ term->media.bmControls = (u8 *)term + sizeof(*term);
term->media.bTransportModeSize = p;
- term->media.bmTransportModes = (__u8 *)term
- + sizeof *term + n;
+ term->media.bmTransportModes = (u8 *)term
+ + sizeof(*term) + n;
memcpy(term->media.bmControls, &buffer[9], n);
memcpy(term->media.bmTransportModes, &buffer[10+n], p);
}
if (buffer[7] != 0)
usb_string(udev, buffer[7], term->name,
- sizeof term->name);
+ sizeof(term->name));
else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA)
sprintf(term->name, "Camera %u", buffer[3]);
else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT)
@@ -1162,7 +1162,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
if (buffer[8] != 0)
usb_string(udev, buffer[8], term->name,
- sizeof term->name);
+ sizeof(term->name));
else
sprintf(term->name, "Output %u", buffer[3]);
@@ -1187,7 +1187,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
if (buffer[5+p] != 0)
usb_string(udev, buffer[5+p], unit->name,
- sizeof unit->name);
+ sizeof(unit->name));
else
sprintf(unit->name, "Selector %u", buffer[3]);
@@ -1213,14 +1213,14 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
unit->processing.wMaxMultiplier =
get_unaligned_le16(&buffer[5]);
unit->processing.bControlSize = buffer[7];
- unit->processing.bmControls = (__u8 *)unit + sizeof *unit;
+ unit->processing.bmControls = (u8 *)unit + sizeof(*unit);
memcpy(unit->processing.bmControls, &buffer[8], n);
if (dev->uvc_version >= 0x0110)
unit->processing.bmVideoStandards = buffer[9+n];
if (buffer[8+n] != 0)
usb_string(udev, buffer[8+n], unit->name,
- sizeof unit->name);
+ sizeof(unit->name));
else
sprintf(unit->name, "Processing %u", buffer[3]);
@@ -1246,12 +1246,12 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
unit->extension.bNumControls = buffer[20];
memcpy(unit->baSourceID, &buffer[22], p);
unit->extension.bControlSize = buffer[22+p];
- unit->extension.bmControls = (__u8 *)unit + sizeof *unit;
+ unit->extension.bmControls = (u8 *)unit + sizeof(*unit);
memcpy(unit->extension.bmControls, &buffer[23+p], n);
if (buffer[23+p+n] != 0)
usb_string(udev, buffer[23+p+n], unit->name,
- sizeof unit->name);
+ sizeof(unit->name));
else
sprintf(unit->name, "Extension %u", buffer[3]);
@@ -1936,7 +1936,7 @@ int uvc_register_video_device(struct uvc_device *dev,
break;
}
- strlcpy(vdev->name, dev->name, sizeof vdev->name);
+ strlcpy(vdev->name, dev->name, sizeof(vdev->name));
/*
* Set the driver data before calling video_register_device, otherwise
@@ -2070,7 +2070,8 @@ static int uvc_probe(struct usb_interface *intf,
udev->devpath);
/* Allocate memory for the device and initialize it. */
- if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL)
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL)
return -ENOMEM;
INIT_LIST_HEAD(&dev->entities);
@@ -2089,9 +2090,9 @@ static int uvc_probe(struct usb_interface *intf,
dev->meta_format = info->meta_format;
if (udev->product != NULL)
- strlcpy(dev->name, udev->product, sizeof dev->name);
+ strlcpy(dev->name, udev->product, sizeof(dev->name));
else
- snprintf(dev->name, sizeof dev->name,
+ snprintf(dev->name, sizeof(dev->name),
"UVC Camera (%04x:%04x)",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
diff --git a/drivers/media/usb/uvc/uvc_isight.c b/drivers/media/usb/uvc/uvc_isight.c
index 5059fbf41020..81e6f2187bfb 100644
--- a/drivers/media/usb/uvc/uvc_isight.c
+++ b/drivers/media/usb/uvc/uvc_isight.c
@@ -37,16 +37,16 @@
*/
static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
- const __u8 *data, unsigned int len)
+ const u8 *data, unsigned int len)
{
- static const __u8 hdr[] = {
+ static const u8 hdr[] = {
0x11, 0x22, 0x33, 0x44,
0xde, 0xad, 0xbe, 0xef,
0xde, 0xad, 0xfa, 0xce
};
unsigned int maxlen, nbytes;
- __u8 *mem;
+ u8 *mem;
int is_header = 0;
if (buf == NULL)
diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c
index 1ef20e74b7ac..7b710410584a 100644
--- a/drivers/media/usb/uvc/uvc_status.c
+++ b/drivers/media/usb/uvc/uvc_status.c
@@ -78,7 +78,7 @@ static void uvc_input_report_key(struct uvc_device *dev, unsigned int code,
/* --------------------------------------------------------------------------
* Status interrupt endpoint
*/
-static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len)
+static void uvc_event_streaming(struct uvc_device *dev, u8 *data, int len)
{
if (len < 3) {
uvc_trace(UVC_TRACE_STATUS, "Invalid streaming status event "
@@ -99,7 +99,7 @@ static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len)
}
}
-static void uvc_event_control(struct uvc_device *dev, __u8 *data, int len)
+static void uvc_event_control(struct uvc_device *dev, u8 *data, int len)
{
char *attrs[3] = { "value", "info", "failure" };
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index a13ad4e178be..bd32914259ae 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -40,13 +40,13 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
unsigned int size;
int ret;
- map = kzalloc(sizeof *map, GFP_KERNEL);
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
if (map == NULL)
return -ENOMEM;
map->id = xmap->id;
- memcpy(map->name, xmap->name, sizeof map->name);
- memcpy(map->entity, xmap->entity, sizeof map->entity);
+ memcpy(map->name, xmap->name, sizeof(map->name));
+ memcpy(map->entity, xmap->entity, sizeof(map->entity));
map->selector = xmap->selector;
map->size = xmap->size;
map->offset = xmap->offset;
@@ -105,12 +105,12 @@ free_map:
* the Video Probe and Commit negotiation, but some hardware don't implement
* that feature.
*/
-static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval)
+static u32 uvc_try_frame_interval(struct uvc_frame *frame, u32 interval)
{
unsigned int i;
if (frame->bFrameIntervalType) {
- __u32 best = -1, dist;
+ u32 best = -1, dist;
for (i = 0; i < frame->bFrameIntervalType; ++i) {
dist = interval > frame->dwFrameInterval[i]
@@ -125,9 +125,9 @@ static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval)
interval = frame->dwFrameInterval[i-1];
} else {
- const __u32 min = frame->dwFrameInterval[0];
- const __u32 max = frame->dwFrameInterval[1];
- const __u32 step = frame->dwFrameInterval[2];
+ const u32 min = frame->dwFrameInterval[0];
+ const u32 max = frame->dwFrameInterval[1];
+ const u32 step = frame->dwFrameInterval[2];
interval = min + (interval - min + step/2) / step * step;
if (interval > max)
@@ -137,7 +137,7 @@ static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval)
return interval;
}
-static __u32 uvc_v4l2_get_bytesperline(const struct uvc_format *format,
+static u32 uvc_v4l2_get_bytesperline(const struct uvc_format *format,
const struct uvc_frame *frame)
{
switch (format->fcc) {
@@ -158,17 +158,17 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
{
struct uvc_format *format = NULL;
struct uvc_frame *frame = NULL;
- __u16 rw, rh;
+ u16 rw, rh;
unsigned int d, maxd;
unsigned int i;
- __u32 interval;
+ u32 interval;
int ret = 0;
- __u8 *fcc;
+ u8 *fcc;
if (fmt->type != stream->type)
return -EINVAL;
- fcc = (__u8 *)&fmt->fmt.pix.pixelformat;
+ fcc = (u8 *)&fmt->fmt.pix.pixelformat;
uvc_trace(UVC_TRACE_FORMAT, "Trying format 0x%08x (%c%c%c%c): %ux%u.\n",
fmt->fmt.pix.pixelformat,
fcc[0], fcc[1], fcc[2], fcc[3],
@@ -197,8 +197,8 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
maxd = (unsigned int)-1;
for (i = 0; i < format->nframes; ++i) {
- __u16 w = format->frame[i].wWidth;
- __u16 h = format->frame[i].wHeight;
+ u16 w = format->frame[i].wWidth;
+ u16 h = format->frame[i].wHeight;
d = min(w, rw) * min(h, rh);
d = w*h + rw*rh - 2*d;
@@ -224,7 +224,7 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
(100000000/interval)%10);
/* Set the format index, frame index and frame interval. */
- memset(probe, 0, sizeof *probe);
+ memset(probe, 0, sizeof(*probe));
probe->bmHint = 1; /* dwFrameInterval */
probe->bFormatIndex = format->index;
probe->bFrameIndex = frame->bFrameIndex;
@@ -336,7 +336,7 @@ done:
static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
struct v4l2_streamparm *parm)
{
- uint32_t numerator, denominator;
+ u32 numerator, denominator;
if (parm->type != stream->type)
return -EINVAL;
@@ -348,7 +348,7 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
denominator = 10000000;
uvc_simplify_fraction(&numerator, &denominator, 8, 333);
- memset(parm, 0, sizeof *parm);
+ memset(parm, 0, sizeof(*parm));
parm->type = stream->type;
if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
@@ -373,7 +373,10 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
{
struct uvc_streaming_control probe;
struct v4l2_fract timeperframe;
- uint32_t interval;
+ struct uvc_format *format;
+ struct uvc_frame *frame;
+ u32 interval, maxd;
+ unsigned int i;
int ret;
if (parm->type != stream->type)
@@ -396,9 +399,33 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
return -EBUSY;
}
+ format = stream->cur_format;
+ frame = stream->cur_frame;
probe = stream->ctrl;
- probe.dwFrameInterval =
- uvc_try_frame_interval(stream->cur_frame, interval);
+ probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
+ maxd = abs((s32)probe.dwFrameInterval - interval);
+
+ /* Try frames with matching size to find the best frame interval. */
+ for (i = 0; i < format->nframes && maxd != 0; i++) {
+ u32 d, ival;
+
+ if (&format->frame[i] == stream->cur_frame)
+ continue;
+
+ if (format->frame[i].wWidth != stream->cur_frame->wWidth ||
+ format->frame[i].wHeight != stream->cur_frame->wHeight)
+ continue;
+
+ ival = uvc_try_frame_interval(&format->frame[i], interval);
+ d = abs((s32)ival - interval);
+ if (d >= maxd)
+ continue;
+
+ frame = &format->frame[i];
+ probe.bFrameIndex = frame->bFrameIndex;
+ probe.dwFrameInterval = ival;
+ maxd = d;
+ }
/* Probe the device with the new settings. */
ret = uvc_probe_video(stream, &probe);
@@ -408,6 +435,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
}
stream->ctrl = probe;
+ stream->cur_frame = frame;
mutex_unlock(&stream->mutex);
/* Return the actual frame period. */
@@ -498,7 +526,7 @@ static int uvc_v4l2_open(struct file *file)
return ret;
/* Create the device handle. */
- handle = kzalloc(sizeof *handle, GFP_KERNEL);
+ handle = kzalloc(sizeof(*handle), GFP_KERNEL);
if (handle == NULL) {
usb_autopm_put_interface(stream->dev->intf);
return -ENOMEM;
@@ -577,7 +605,7 @@ static int uvc_ioctl_enum_fmt(struct uvc_streaming *stream,
{
struct uvc_format *format;
enum v4l2_buf_type type = fmt->type;
- __u32 index = fmt->index;
+ u32 index = fmt->index;
if (fmt->type != stream->type || fmt->index >= stream->nformats)
return -EINVAL;
@@ -1145,8 +1173,9 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh,
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
struct uvc_format *format = NULL;
- struct uvc_frame *frame;
- int i;
+ struct uvc_frame *frame = NULL;
+ unsigned int index;
+ unsigned int i;
/* Look for the given pixel format */
for (i = 0; i < stream->nformats; i++) {
@@ -1158,10 +1187,20 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh,
if (format == NULL)
return -EINVAL;
- if (fsize->index >= format->nframes)
+ /* Skip duplicate frame sizes */
+ for (i = 0, index = 0; i < format->nframes; i++) {
+ if (frame && frame->wWidth == format->frame[i].wWidth &&
+ frame->wHeight == format->frame[i].wHeight)
+ continue;
+ frame = &format->frame[i];
+ if (index == fsize->index)
+ break;
+ index++;
+ }
+
+ if (i == format->nframes)
return -EINVAL;
- frame = &format->frame[fsize->index];
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
fsize->discrete.width = frame->wWidth;
fsize->discrete.height = frame->wHeight;
@@ -1175,7 +1214,9 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
struct uvc_streaming *stream = handle->stream;
struct uvc_format *format = NULL;
struct uvc_frame *frame = NULL;
- int i;
+ unsigned int nintervals;
+ unsigned int index;
+ unsigned int i;
/* Look for the given pixel format and frame size */
for (i = 0; i < stream->nformats; i++) {
@@ -1187,30 +1228,28 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
if (format == NULL)
return -EINVAL;
+ index = fival->index;
for (i = 0; i < format->nframes; i++) {
if (format->frame[i].wWidth == fival->width &&
format->frame[i].wHeight == fival->height) {
frame = &format->frame[i];
- break;
+ nintervals = frame->bFrameIntervalType ?: 1;
+ if (index < nintervals)
+ break;
+ index -= nintervals;
}
}
- if (frame == NULL)
+ if (i == format->nframes)
return -EINVAL;
if (frame->bFrameIntervalType) {
- if (fival->index >= frame->bFrameIntervalType)
- return -EINVAL;
-
fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
fival->discrete.numerator =
- frame->dwFrameInterval[fival->index];
+ frame->dwFrameInterval[index];
fival->discrete.denominator = 10000000;
uvc_simplify_fraction(&fival->discrete.numerator,
&fival->discrete.denominator, 8, 333);
} else {
- if (fival->index)
- return -EINVAL;
-
fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
fival->stepwise.min.numerator = frame->dwFrameInterval[0];
fival->stepwise.min.denominator = 10000000;
@@ -1261,20 +1300,20 @@ static long uvc_ioctl_default(struct file *file, void *fh, bool valid_prio,
#ifdef CONFIG_COMPAT
struct uvc_xu_control_mapping32 {
- __u32 id;
- __u8 name[32];
- __u8 entity[16];
- __u8 selector;
+ u32 id;
+ u8 name[32];
+ u8 entity[16];
+ u8 selector;
- __u8 size;
- __u8 offset;
- __u32 v4l2_type;
- __u32 data_type;
+ u8 size;
+ u8 offset;
+ u32 v4l2_type;
+ u32 data_type;
compat_caddr_t menu_info;
- __u32 menu_count;
+ u32 menu_count;
- __u32 reserved[4];
+ u32 reserved[4];
};
static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp,
@@ -1310,10 +1349,10 @@ static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp,
}
struct uvc_xu_control_query32 {
- __u8 unit;
- __u8 selector;
- __u8 query;
- __u16 size;
+ u8 unit;
+ u8 selector;
+ u8 query;
+ u16 size;
compat_caddr_t data;
};
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 5441553f74e1..aa0082fe5833 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -30,11 +30,11 @@
* UVC Controls
*/
-static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
- __u8 intfnum, __u8 cs, void *data, __u16 size,
+static int __uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
+ u8 intfnum, u8 cs, void *data, u16 size,
int timeout)
{
- __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
unsigned int pipe;
pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0)
@@ -45,7 +45,7 @@ static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
unit << 8 | intfnum, data, size, timeout);
}
-static const char *uvc_query_name(__u8 query)
+static const char *uvc_query_name(u8 query)
{
switch (query) {
case UVC_SET_CUR:
@@ -69,8 +69,8 @@ static const char *uvc_query_name(__u8 query)
}
}
-int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
- __u8 intfnum, __u8 cs, void *data, __u16 size)
+int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
+ u8 intfnum, u8 cs, void *data, u16 size)
{
int ret;
@@ -164,10 +164,10 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
}
static int uvc_get_video_ctrl(struct uvc_streaming *stream,
- struct uvc_streaming_control *ctrl, int probe, __u8 query)
+ struct uvc_streaming_control *ctrl, int probe, u8 query)
{
- __u8 *data;
- __u16 size;
+ u8 *data;
+ u16 size;
int ret;
size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
@@ -191,7 +191,7 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream,
uvc_warn_once(stream->dev, UVC_WARN_MINMAX, "UVC non "
"compliance - GET_MIN/MAX(PROBE) incorrectly "
"supported. Enabling workaround.\n");
- memset(ctrl, 0, sizeof *ctrl);
+ memset(ctrl, 0, sizeof(*ctrl));
ctrl->wCompQuality = le16_to_cpup((__le16 *)data);
ret = 0;
goto out;
@@ -254,8 +254,8 @@ out:
static int uvc_set_video_ctrl(struct uvc_streaming *stream,
struct uvc_streaming_control *ctrl, int probe)
{
- __u8 *data;
- __u16 size;
+ u8 *data;
+ u16 size;
int ret;
size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
@@ -301,7 +301,7 @@ int uvc_probe_video(struct uvc_streaming *stream,
struct uvc_streaming_control *probe)
{
struct uvc_streaming_control probe_min, probe_max;
- __u16 bandwidth;
+ u16 bandwidth;
unsigned int i;
int ret;
@@ -379,7 +379,7 @@ static inline ktime_t uvc_video_get_time(void)
static void
uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
- const __u8 *data, int len)
+ const u8 *data, int len)
{
struct uvc_clock_sample *sample;
unsigned int header_size;
@@ -705,7 +705,7 @@ done:
*/
static void uvc_video_stats_decode(struct uvc_streaming *stream,
- const __u8 *data, int len)
+ const u8 *data, int len)
{
unsigned int header_size;
bool has_pts = false;
@@ -946,9 +946,9 @@ static void uvc_video_stats_stop(struct uvc_streaming *stream)
* uvc_video_decode_end will never be called with a NULL buffer.
*/
static int uvc_video_decode_start(struct uvc_streaming *stream,
- struct uvc_buffer *buf, const __u8 *data, int len)
+ struct uvc_buffer *buf, const u8 *data, int len)
{
- __u8 fid;
+ u8 fid;
/* Sanity checks:
* - packet must be at least 2 bytes long
@@ -1009,7 +1009,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
buf->buf.field = V4L2_FIELD_NONE;
buf->buf.sequence = stream->sequence;
- buf->buf.vb2_buf.timestamp = uvc_video_get_time();
+ buf->buf.vb2_buf.timestamp = ktime_to_ns(uvc_video_get_time());
/* TODO: Handle PTS and SCR. */
buf->state = UVC_BUF_STATE_ACTIVE;
@@ -1043,7 +1043,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
}
static void uvc_video_decode_data(struct uvc_streaming *stream,
- struct uvc_buffer *buf, const __u8 *data, int len)
+ struct uvc_buffer *buf, const u8 *data, int len)
{
unsigned int maxlen, nbytes;
void *mem;
@@ -1067,7 +1067,7 @@ static void uvc_video_decode_data(struct uvc_streaming *stream,
}
static void uvc_video_decode_end(struct uvc_streaming *stream,
- struct uvc_buffer *buf, const __u8 *data, int len)
+ struct uvc_buffer *buf, const u8 *data, int len)
{
/* Mark the buffer as done if the EOF marker is set. */
if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) {
@@ -1092,7 +1092,7 @@ static void uvc_video_decode_end(struct uvc_streaming *stream,
* video buffer to the transfer buffer.
*/
static int uvc_video_encode_header(struct uvc_streaming *stream,
- struct uvc_buffer *buf, __u8 *data, int len)
+ struct uvc_buffer *buf, u8 *data, int len)
{
data[0] = 2; /* Header length */
data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF
@@ -1101,7 +1101,7 @@ static int uvc_video_encode_header(struct uvc_streaming *stream,
}
static int uvc_video_encode_data(struct uvc_streaming *stream,
- struct uvc_buffer *buf, __u8 *data, int len)
+ struct uvc_buffer *buf, u8 *data, int len)
{
struct uvc_video_queue *queue = &stream->queue;
unsigned int nbytes;
@@ -1191,7 +1191,8 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream,
uvc_trace(UVC_TRACE_FRAME,
"%s(): t-sys %lluns, SOF %u, len %u, flags 0x%x, PTS %u, STC %u frame SOF %u\n",
- __func__, time, meta->sof, meta->length, meta->flags,
+ __func__, ktime_to_ns(time), meta->sof, meta->length,
+ meta->flags,
has_pts ? *(u32 *)meta->buf : 0,
has_scr ? *(u32 *)scr : 0,
has_scr ? *(u32 *)(scr + 4) & 0x7ff : 0);
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index d9e7c70788d0..be5cf179228b 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -208,60 +208,60 @@ struct uvc_device;
struct uvc_control_info {
struct list_head mappings;
- __u8 entity[16];
- __u8 index; /* Bit index in bmControls */
- __u8 selector;
+ u8 entity[16];
+ u8 index; /* Bit index in bmControls */
+ u8 selector;
- __u16 size;
- __u32 flags;
+ u16 size;
+ u32 flags;
};
struct uvc_control_mapping {
struct list_head list;
struct list_head ev_subs;
- __u32 id;
- __u8 name[32];
- __u8 entity[16];
- __u8 selector;
+ u32 id;
+ u8 name[32];
+ u8 entity[16];
+ u8 selector;
- __u8 size;
- __u8 offset;
+ u8 size;
+ u8 offset;
enum v4l2_ctrl_type v4l2_type;
- __u32 data_type;
+ u32 data_type;
struct uvc_menu_info *menu_info;
- __u32 menu_count;
+ u32 menu_count;
- __u32 master_id;
- __s32 master_manual;
- __u32 slave_ids[2];
+ u32 master_id;
+ s32 master_manual;
+ u32 slave_ids[2];
- __s32 (*get) (struct uvc_control_mapping *mapping, __u8 query,
- const __u8 *data);
- void (*set) (struct uvc_control_mapping *mapping, __s32 value,
- __u8 *data);
+ s32 (*get)(struct uvc_control_mapping *mapping, u8 query,
+ const u8 *data);
+ void (*set)(struct uvc_control_mapping *mapping, s32 value,
+ u8 *data);
};
struct uvc_control {
struct uvc_entity *entity;
struct uvc_control_info info;
- __u8 index; /* Used to match the uvc_control entry with a
+ u8 index; /* Used to match the uvc_control entry with a
uvc_control_info. */
- __u8 dirty:1,
- loaded:1,
- modified:1,
- cached:1,
- initialized:1;
+ u8 dirty:1,
+ loaded:1,
+ modified:1,
+ cached:1,
+ initialized:1;
- __u8 *uvc_data;
+ u8 *uvc_data;
};
struct uvc_format_desc {
char *name;
- __u8 guid[16];
- __u32 fcc;
+ u8 guid[16];
+ u32 fcc;
};
/* The term 'entity' refers to both UVC units and UVC terminals.
@@ -287,8 +287,8 @@ struct uvc_entity {
* chain. */
unsigned int flags;
- __u8 id;
- __u16 type;
+ u8 id;
+ u16 type;
char name[64];
/* Media controller-related fields. */
@@ -300,69 +300,69 @@ struct uvc_entity {
union {
struct {
- __u16 wObjectiveFocalLengthMin;
- __u16 wObjectiveFocalLengthMax;
- __u16 wOcularFocalLength;
- __u8 bControlSize;
- __u8 *bmControls;
+ u16 wObjectiveFocalLengthMin;
+ u16 wObjectiveFocalLengthMax;
+ u16 wOcularFocalLength;
+ u8 bControlSize;
+ u8 *bmControls;
} camera;
struct {
- __u8 bControlSize;
- __u8 *bmControls;
- __u8 bTransportModeSize;
- __u8 *bmTransportModes;
+ u8 bControlSize;
+ u8 *bmControls;
+ u8 bTransportModeSize;
+ u8 *bmTransportModes;
} media;
struct {
} output;
struct {
- __u16 wMaxMultiplier;
- __u8 bControlSize;
- __u8 *bmControls;
- __u8 bmVideoStandards;
+ u16 wMaxMultiplier;
+ u8 bControlSize;
+ u8 *bmControls;
+ u8 bmVideoStandards;
} processing;
struct {
} selector;
struct {
- __u8 guidExtensionCode[16];
- __u8 bNumControls;
- __u8 bControlSize;
- __u8 *bmControls;
- __u8 *bmControlsType;
+ u8 guidExtensionCode[16];
+ u8 bNumControls;
+ u8 bControlSize;
+ u8 *bmControls;
+ u8 *bmControlsType;
} extension;
};
- __u8 bNrInPins;
- __u8 *baSourceID;
+ u8 bNrInPins;
+ u8 *baSourceID;
unsigned int ncontrols;
struct uvc_control *controls;
};
struct uvc_frame {
- __u8 bFrameIndex;
- __u8 bmCapabilities;
- __u16 wWidth;
- __u16 wHeight;
- __u32 dwMinBitRate;
- __u32 dwMaxBitRate;
- __u32 dwMaxVideoFrameBufferSize;
- __u8 bFrameIntervalType;
- __u32 dwDefaultFrameInterval;
- __u32 *dwFrameInterval;
+ u8 bFrameIndex;
+ u8 bmCapabilities;
+ u16 wWidth;
+ u16 wHeight;
+ u32 dwMinBitRate;
+ u32 dwMaxBitRate;
+ u32 dwMaxVideoFrameBufferSize;
+ u8 bFrameIntervalType;
+ u32 dwDefaultFrameInterval;
+ u32 *dwFrameInterval;
};
struct uvc_format {
- __u8 type;
- __u8 index;
- __u8 bpp;
- __u8 colorspace;
- __u32 fcc;
- __u32 flags;
+ u8 type;
+ u8 index;
+ u8 bpp;
+ u8 colorspace;
+ u32 fcc;
+ u32 flags;
char name[32];
@@ -371,16 +371,16 @@ struct uvc_format {
};
struct uvc_streaming_header {
- __u8 bNumFormats;
- __u8 bEndpointAddress;
- __u8 bTerminalLink;
- __u8 bControlSize;
- __u8 *bmaControls;
+ u8 bNumFormats;
+ u8 bEndpointAddress;
+ u8 bTerminalLink;
+ u8 bControlSize;
+ u8 *bmaControls;
/* The following fields are used by input headers only. */
- __u8 bmInfo;
- __u8 bStillCaptureMethod;
- __u8 bTriggerSupport;
- __u8 bTriggerUsage;
+ u8 bmInfo;
+ u8 bStillCaptureMethod;
+ u8 bTriggerSupport;
+ u8 bTriggerUsage;
};
enum uvc_buffer_state {
@@ -490,7 +490,7 @@ struct uvc_streaming {
struct usb_interface *intf;
int intfnum;
- __u16 maxpsize;
+ u16 maxpsize;
struct uvc_streaming_header header;
enum v4l2_buf_type type;
@@ -517,16 +517,16 @@ struct uvc_streaming {
struct {
struct video_device vdev;
struct uvc_video_queue queue;
- __u32 format;
+ u32 format;
} meta;
/* Context data used by the bulk completion handler. */
struct {
- __u8 header[256];
+ u8 header[256];
unsigned int header_size;
int skip_payload;
- __u32 payload_size;
- __u32 max_payload_size;
+ u32 payload_size;
+ u32 max_payload_size;
} bulk;
struct urb *urb[UVC_URBS];
@@ -534,8 +534,8 @@ struct uvc_streaming {
dma_addr_t urb_dma[UVC_URBS];
unsigned int urb_size;
- __u32 sequence;
- __u8 last_fid;
+ u32 sequence;
+ u8 last_fid;
/* debugfs */
struct dentry *debugfs_dir;
@@ -570,8 +570,8 @@ struct uvc_device {
struct usb_device *udev;
struct usb_interface *intf;
unsigned long warnings;
- __u32 quirks;
- __u32 meta_format;
+ u32 quirks;
+ u32 meta_format;
int intfnum;
char name[32];
@@ -584,8 +584,8 @@ struct uvc_device {
struct media_device mdev;
#endif
struct v4l2_device vdev;
- __u16 uvc_version;
- __u32 clock_frequency;
+ u16 uvc_version;
+ u32 clock_frequency;
struct list_head entities;
struct list_head chains;
@@ -597,7 +597,7 @@ struct uvc_device {
/* Status Interrupt Endpoint */
struct usb_host_endpoint *int_ep;
struct urb *int_urb;
- __u8 *status;
+ u8 *status;
struct input_dev *input;
char input_phys[64];
};
@@ -667,40 +667,38 @@ extern unsigned int uvc_hw_timestamps_param;
/* Core driver */
extern struct uvc_driver uvc_driver;
-extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
+struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
/* Video buffers queue management. */
-extern int uvc_queue_init(struct uvc_video_queue *queue,
- enum v4l2_buf_type type, int drop_corrupted);
-extern void uvc_queue_release(struct uvc_video_queue *queue);
-extern int uvc_request_buffers(struct uvc_video_queue *queue,
- struct v4l2_requestbuffers *rb);
-extern int uvc_query_buffer(struct uvc_video_queue *queue,
- struct v4l2_buffer *v4l2_buf);
-extern int uvc_create_buffers(struct uvc_video_queue *queue,
- struct v4l2_create_buffers *v4l2_cb);
-extern int uvc_queue_buffer(struct uvc_video_queue *queue,
- struct v4l2_buffer *v4l2_buf);
-extern int uvc_export_buffer(struct uvc_video_queue *queue,
- struct v4l2_exportbuffer *exp);
-extern int uvc_dequeue_buffer(struct uvc_video_queue *queue,
- struct v4l2_buffer *v4l2_buf, int nonblocking);
-extern int uvc_queue_streamon(struct uvc_video_queue *queue,
- enum v4l2_buf_type type);
-extern int uvc_queue_streamoff(struct uvc_video_queue *queue,
- enum v4l2_buf_type type);
-extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
-extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
- struct uvc_buffer *buf);
-extern int uvc_queue_mmap(struct uvc_video_queue *queue,
- struct vm_area_struct *vma);
-extern __poll_t uvc_queue_poll(struct uvc_video_queue *queue,
- struct file *file, poll_table *wait);
+int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
+ int drop_corrupted);
+void uvc_queue_release(struct uvc_video_queue *queue);
+int uvc_request_buffers(struct uvc_video_queue *queue,
+ struct v4l2_requestbuffers *rb);
+int uvc_query_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf);
+int uvc_create_buffers(struct uvc_video_queue *queue,
+ struct v4l2_create_buffers *v4l2_cb);
+int uvc_queue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf);
+int uvc_export_buffer(struct uvc_video_queue *queue,
+ struct v4l2_exportbuffer *exp);
+int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf, int nonblocking);
+int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type);
+int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type);
+void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
+struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+ struct uvc_buffer *buf);
+int uvc_queue_mmap(struct uvc_video_queue *queue,
+ struct vm_area_struct *vma);
+__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
+ poll_table *wait);
#ifndef CONFIG_MMU
-extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
- unsigned long pgoff);
+unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+ unsigned long pgoff);
#endif
-extern int uvc_queue_allocated(struct uvc_video_queue *queue);
+int uvc_queue_allocated(struct uvc_video_queue *queue);
static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
{
return vb2_is_streaming(&queue->queue);
@@ -711,18 +709,18 @@ extern const struct v4l2_ioctl_ops uvc_ioctl_ops;
extern const struct v4l2_file_operations uvc_fops;
/* Media controller */
-extern int uvc_mc_register_entities(struct uvc_video_chain *chain);
-extern void uvc_mc_cleanup_entity(struct uvc_entity *entity);
+int uvc_mc_register_entities(struct uvc_video_chain *chain);
+void uvc_mc_cleanup_entity(struct uvc_entity *entity);
/* Video */
-extern int uvc_video_init(struct uvc_streaming *stream);
-extern int uvc_video_suspend(struct uvc_streaming *stream);
-extern int uvc_video_resume(struct uvc_streaming *stream, int reset);
-extern int uvc_video_enable(struct uvc_streaming *stream, int enable);
-extern int uvc_probe_video(struct uvc_streaming *stream,
- struct uvc_streaming_control *probe);
-extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
- __u8 intfnum, __u8 cs, void *data, __u16 size);
+int uvc_video_init(struct uvc_streaming *stream);
+int uvc_video_suspend(struct uvc_streaming *stream);
+int uvc_video_resume(struct uvc_streaming *stream, int reset);
+int uvc_video_enable(struct uvc_streaming *stream, int enable);
+int uvc_probe_video(struct uvc_streaming *stream,
+ struct uvc_streaming_control *probe);
+int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
+ u8 intfnum, u8 cs, void *data, u16 size);
void uvc_video_clock_update(struct uvc_streaming *stream,
struct vb2_v4l2_buffer *vbuf,
struct uvc_buffer *buf);
@@ -737,32 +735,32 @@ int uvc_register_video_device(struct uvc_device *dev,
const struct v4l2_ioctl_ops *ioctl_ops);
/* Status */
-extern int uvc_status_init(struct uvc_device *dev);
-extern void uvc_status_cleanup(struct uvc_device *dev);
-extern int uvc_status_start(struct uvc_device *dev, gfp_t flags);
-extern void uvc_status_stop(struct uvc_device *dev);
+int uvc_status_init(struct uvc_device *dev);
+void uvc_status_cleanup(struct uvc_device *dev);
+int uvc_status_start(struct uvc_device *dev, gfp_t flags);
+void uvc_status_stop(struct uvc_device *dev);
/* Controls */
extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
-extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
- struct v4l2_queryctrl *v4l2_ctrl);
-extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
- struct v4l2_querymenu *query_menu);
-
-extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
- const struct uvc_control_mapping *mapping);
-extern int uvc_ctrl_init_device(struct uvc_device *dev);
-extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
-extern int uvc_ctrl_restore_values(struct uvc_device *dev);
-
-extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
-extern int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
- const struct v4l2_ext_control *xctrls,
- unsigned int xctrls_count);
+int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
+ struct v4l2_queryctrl *v4l2_ctrl);
+int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
+ struct v4l2_querymenu *query_menu);
+
+int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
+ const struct uvc_control_mapping *mapping);
+int uvc_ctrl_init_device(struct uvc_device *dev);
+void uvc_ctrl_cleanup_device(struct uvc_device *dev);
+int uvc_ctrl_restore_values(struct uvc_device *dev);
+
+int uvc_ctrl_begin(struct uvc_video_chain *chain);
+int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
+ const struct v4l2_ext_control *xctrls,
+ unsigned int xctrls_count);
static inline int uvc_ctrl_commit(struct uvc_fh *handle,
- const struct v4l2_ext_control *xctrls,
- unsigned int xctrls_count)
+ const struct v4l2_ext_control *xctrls,
+ unsigned int xctrls_count)
{
return __uvc_ctrl_commit(handle, 0, xctrls, xctrls_count);
}
@@ -771,25 +769,23 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
return __uvc_ctrl_commit(handle, 1, NULL, 0);
}
-extern int uvc_ctrl_get(struct uvc_video_chain *chain,
- struct v4l2_ext_control *xctrl);
-extern int uvc_ctrl_set(struct uvc_video_chain *chain,
- struct v4l2_ext_control *xctrl);
+int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl);
+int uvc_ctrl_set(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl);
-extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
- struct uvc_xu_control_query *xqry);
+int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
+ struct uvc_xu_control_query *xqry);
/* Utility functions */
-extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
- unsigned int n_terms, unsigned int threshold);
-extern uint32_t uvc_fraction_to_interval(uint32_t numerator,
- uint32_t denominator);
-extern struct usb_host_endpoint *uvc_find_endpoint(
- struct usb_host_interface *alts, __u8 epaddr);
+void uvc_simplify_fraction(u32 *numerator, u32 *denominator,
+ unsigned int n_terms, unsigned int threshold);
+u32 uvc_fraction_to_interval(u32 numerator, u32 denominator);
+struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
+ u8 epaddr);
/* Quirks support */
void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
- struct uvc_buffer *buf, struct uvc_buffer *meta_buf);
+ struct uvc_buffer *buf,
+ struct uvc_buffer *meta_buf);
/* debugfs and statistics */
void uvc_debugfs_init(void);
diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c
index 8b7c19943d46..b8886102c5ed 100644
--- a/drivers/media/usb/zr364xx/zr364xx.c
+++ b/drivers/media/usb/zr364xx/zr364xx.c
@@ -517,8 +517,7 @@ static void zr364xx_fillbuff(struct zr364xx_camera *cam,
printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n");
return;
}
- DBG("%s: Buffer 0x%08lx size= %d\n", __func__,
- (unsigned long)vbuf, pos);
+ DBG("%s: Buffer %p size= %d\n", __func__, vbuf, pos);
/* tell v4l buffer was filled */
buf->vb.field_count = cam->frame_count * 2;
@@ -1277,7 +1276,7 @@ static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
DBG("%s: cam == NULL\n", __func__);
return -ENODEV;
}
- DBG("mmap called, vma=0x%08lx\n", (unsigned long)vma);
+ DBG("mmap called, vma=%p\n", vma);
ret = videobuf_mmap_mapper(&cam->vb_vidq, vma);
diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c
index 82852f23a3b6..7f858c39753c 100644
--- a/drivers/media/v4l2-core/tuner-core.c
+++ b/drivers/media/v4l2-core/tuner-core.c
@@ -1099,23 +1099,14 @@ static int tuner_s_radio(struct v4l2_subdev *sd)
*/
/**
- * tuner_s_power - controls the power state of the tuner
+ * tuner_standby - places the tuner in standby mode
* @sd: pointer to struct v4l2_subdev
- * @on: a zero value puts the tuner to sleep, non-zero wakes it up
*/
-static int tuner_s_power(struct v4l2_subdev *sd, int on)
+static int tuner_standby(struct v4l2_subdev *sd)
{
struct tuner *t = to_tuner(sd);
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
- if (on) {
- if (t->standby && set_mode(t, t->mode) == 0) {
- dprintk("Waking up tuner\n");
- set_freq(t, 0);
- }
- return 0;
- }
-
dprintk("Putting tuner to sleep\n");
t->standby = true;
if (analog_ops->standby)
@@ -1328,10 +1319,10 @@ static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg)
static const struct v4l2_subdev_core_ops tuner_core_ops = {
.log_status = tuner_log_status,
- .s_power = tuner_s_power,
};
static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = {
+ .standby = tuner_standby,
.s_radio = tuner_s_radio,
.g_tuner = tuner_g_tuner,
.s_tuner = tuner_s_tuner,
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 8650ad92b64d..b518b92d6d96 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -357,31 +357,35 @@ void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
}
EXPORT_SYMBOL_GPL(v4l_bound_align_image);
-const struct v4l2_frmsize_discrete *
-v4l2_find_nearest_format(const struct v4l2_frmsize_discrete *sizes,
- size_t num_sizes,
- s32 width, s32 height)
+const void *
+__v4l2_find_nearest_size(const void *array, size_t array_size,
+ size_t entry_size, size_t width_offset,
+ size_t height_offset, s32 width, s32 height)
{
- int i;
- u32 error, min_error = UINT_MAX;
- const struct v4l2_frmsize_discrete *size, *best = NULL;
+ u32 error, min_error = U32_MAX;
+ const void *best = NULL;
+ unsigned int i;
- if (!sizes)
+ if (!array)
return NULL;
- for (i = 0, size = sizes; i < num_sizes; i++, size++) {
- error = abs(size->width - width) + abs(size->height - height);
- if (error < min_error) {
- min_error = error;
- best = size;
- }
+ for (i = 0; i < array_size; i++, array += entry_size) {
+ const u32 *entry_width = array + width_offset;
+ const u32 *entry_height = array + height_offset;
+
+ error = abs(*entry_width - width) + abs(*entry_height - height);
+ if (error > min_error)
+ continue;
+
+ min_error = error;
+ best = array;
if (!error)
break;
}
return best;
}
-EXPORT_SYMBOL_GPL(v4l2_find_nearest_format);
+EXPORT_SYMBOL_GPL(__v4l2_find_nearest_size);
void v4l2_get_timestamp(struct timeval *tv)
{
@@ -392,3 +396,51 @@ void v4l2_get_timestamp(struct timeval *tv)
tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
}
EXPORT_SYMBOL_GPL(v4l2_get_timestamp);
+
+int v4l2_g_parm_cap(struct video_device *vdev,
+ struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct v4l2_subdev_frame_interval ival = { 0 };
+ int ret;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ if (vdev->device_caps & V4L2_CAP_READWRITE)
+ a->parm.capture.readbuffers = 2;
+ if (v4l2_subdev_has_op(sd, video, g_frame_interval))
+ a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ ret = v4l2_subdev_call(sd, video, g_frame_interval, &ival);
+ if (!ret)
+ a->parm.capture.timeperframe = ival.interval;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_g_parm_cap);
+
+int v4l2_s_parm_cap(struct video_device *vdev,
+ struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct v4l2_subdev_frame_interval ival = {
+ .interval = a->parm.capture.timeperframe
+ };
+ int ret;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ memset(&a->parm, 0, sizeof(a->parm));
+ if (vdev->device_caps & V4L2_CAP_READWRITE)
+ a->parm.capture.readbuffers = 2;
+ else
+ a->parm.capture.readbuffers = 0;
+
+ if (v4l2_subdev_has_op(sd, video, g_frame_interval))
+ a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ ret = v4l2_subdev_call(sd, video, s_frame_interval, &ival);
+ if (!ret)
+ a->parm.capture.timeperframe = ival.interval;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_s_parm_cap);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index ce08b50b8290..d29e45516eb7 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -480,6 +480,57 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
NULL,
};
+ static const char * const hevc_profile[] = {
+ "Main",
+ "Main Still Picture",
+ "Main 10",
+ NULL,
+ };
+ static const char * const hevc_level[] = {
+ "1",
+ "2",
+ "2.1",
+ "3",
+ "3.1",
+ "4",
+ "4.1",
+ "5",
+ "5.1",
+ "5.2",
+ "6",
+ "6.1",
+ "6.2",
+ NULL,
+ };
+ static const char * const hevc_hierarchial_coding_type[] = {
+ "B",
+ "P",
+ NULL,
+ };
+ static const char * const hevc_refresh_type[] = {
+ "None",
+ "CRA",
+ "IDR",
+ NULL,
+ };
+ static const char * const hevc_size_of_length_field[] = {
+ "0",
+ "1",
+ "2",
+ "4",
+ NULL,
+ };
+ static const char * const hevc_tier[] = {
+ "Main",
+ "High",
+ NULL,
+ };
+ static const char * const hevc_loop_filter_mode[] = {
+ "Disabled",
+ "Enabled",
+ "Disabled at slice boundary",
+ "NULL",
+ };
switch (id) {
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
@@ -575,6 +626,20 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
return dv_it_content_type;
case V4L2_CID_DETECT_MD_MODE:
return detect_md_mode;
+ case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+ return hevc_profile;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
+ return hevc_level;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE:
+ return hevc_hierarchial_coding_type;
+ case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
+ return hevc_refresh_type;
+ case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
+ return hevc_size_of_length_field;
+ case V4L2_CID_MPEG_VIDEO_HEVC_TIER:
+ return hevc_tier;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
+ return hevc_loop_filter_mode;
default:
return NULL;
@@ -776,6 +841,53 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: return "VPX P-Frame QP Value";
case V4L2_CID_MPEG_VIDEO_VPX_PROFILE: return "VPX Profile";
+ /* HEVC controls */
+ case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: return "HEVC I-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: return "HEVC P-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: return "HEVC B-Frame QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: return "HEVC Minimum QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: return "HEVC Maximum QP Value";
+ case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: return "HEVC Profile";
+ case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: return "HEVC Level";
+ case V4L2_CID_MPEG_VIDEO_HEVC_TIER: return "HEVC Tier";
+ case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION: return "HEVC Frame Rate Resolution";
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH: return "HEVC Maximum Coding Unit Depth";
+ case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: return "HEVC Refresh Type";
+ case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: return "HEVC Constant Intra Prediction";
+ case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: return "HEVC Lossless Encoding";
+ case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: return "HEVC Wavefront";
+ case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: return "HEVC Loop Filter";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP: return "HEVC QP Values";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: return "HEVC Hierarchical Coding Type";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: return "HEVC Hierarchical Coding Layer";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP: return "HEVC Hierarchical Layer 0 QP";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP: return "HEVC Hierarchical Layer 1 QP";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP: return "HEVC Hierarchical Layer 2 QP";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP: return "HEVC Hierarchical Layer 3 QP";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP: return "HEVC Hierarchical Layer 4 QP";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP: return "HEVC Hierarchical Layer 5 QP";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP: return "HEVC Hierarchical Layer 6 QP";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: return "HEVC Hierarchical Lay 0 BitRate";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: return "HEVC Hierarchical Lay 1 BitRate";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: return "HEVC Hierarchical Lay 2 BitRate";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: return "HEVC Hierarchical Lay 3 BitRate";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: return "HEVC Hierarchical Lay 4 BitRate";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: return "HEVC Hierarchical Lay 5 BitRate";
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR: return "HEVC Hierarchical Lay 6 BitRate";
+ case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB: return "HEVC General PB";
+ case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID: return "HEVC Temporal ID";
+ case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: return "HEVC Strong Intra Smoothing";
+ case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT: return "HEVC Intra PU Split";
+ case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: return "HEVC TMV Prediction";
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: return "HEVC Max Num of Candidate MVs";
+ case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE: return "HEVC ENC Without Startcode";
+ case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: return "HEVC Num of I-Frame b/w 2 IDR";
+ case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: return "HEVC Loop Filter Beta Offset";
+ case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: return "HEVC Loop Filter TC Offset";
+ case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: return "HEVC Size of Length Field";
+ case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: return "Reference Frames for a P-Frame";
+ case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: return "Prepend SPS and PPS to IDR";
+
/* CAMERA controls */
/* Keep the order of the 'case's the same as in v4l2-controls.h! */
case V4L2_CID_CAMERA_CLASS: return "Camera Controls";
@@ -1069,6 +1181,13 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_TUNE_DEEMPHASIS:
case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
case V4L2_CID_DETECT_MD_MODE:
+ case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+ case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE:
+ case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
+ case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
+ case V4L2_CID_MPEG_VIDEO_HEVC_TIER:
+ case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
*type = V4L2_CTRL_TYPE_MENU;
break;
case V4L2_CID_LINK_FREQ:
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c
index e2ee5f00c445..c81faea96fba 100644
--- a/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ b/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* v4l2-dv-timings - dv-timings helper functions
*
* Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
*/
#include <linux/module.h>
@@ -27,6 +14,7 @@
#include <linux/v4l2-dv-timings.h>
#include <media/v4l2-dv-timings.h>
#include <linux/math64.h>
+#include <linux/hdmi.h>
MODULE_AUTHOR("Hans Verkuil");
MODULE_DESCRIPTION("V4L2 DV Timings Helper Functions");
@@ -814,3 +802,143 @@ struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait)
return aspect;
}
EXPORT_SYMBOL_GPL(v4l2_calc_aspect_ratio);
+
+/** v4l2_hdmi_rx_colorimetry - determine HDMI colorimetry information
+ * based on various InfoFrames.
+ * @avi: the AVI InfoFrame
+ * @hdmi: the HDMI Vendor InfoFrame, may be NULL
+ * @height: the frame height
+ *
+ * Determines the HDMI colorimetry information, i.e. how the HDMI
+ * pixel color data should be interpreted.
+ *
+ * Note that some of the newer features (DCI-P3, HDR) are not yet
+ * implemented: the hdmi.h header needs to be updated to the HDMI 2.0
+ * and CTA-861-G standards.
+ */
+struct v4l2_hdmi_colorimetry
+v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi,
+ const struct hdmi_vendor_infoframe *hdmi,
+ unsigned int height)
+{
+ struct v4l2_hdmi_colorimetry c = {
+ V4L2_COLORSPACE_SRGB,
+ V4L2_YCBCR_ENC_DEFAULT,
+ V4L2_QUANTIZATION_FULL_RANGE,
+ V4L2_XFER_FUNC_SRGB
+ };
+ bool is_ce = avi->video_code || (hdmi && hdmi->vic);
+ bool is_sdtv = height <= 576;
+ bool default_is_lim_range_rgb = avi->video_code > 1;
+
+ switch (avi->colorspace) {
+ case HDMI_COLORSPACE_RGB:
+ /* RGB pixel encoding */
+ switch (avi->colorimetry) {
+ case HDMI_COLORIMETRY_EXTENDED:
+ switch (avi->extended_colorimetry) {
+ case HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB:
+ c.colorspace = V4L2_COLORSPACE_ADOBERGB;
+ c.xfer_func = V4L2_XFER_FUNC_ADOBERGB;
+ break;
+ case HDMI_EXTENDED_COLORIMETRY_BT2020:
+ c.colorspace = V4L2_COLORSPACE_BT2020;
+ c.xfer_func = V4L2_XFER_FUNC_709;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ switch (avi->quantization_range) {
+ case HDMI_QUANTIZATION_RANGE_LIMITED:
+ c.quantization = V4L2_QUANTIZATION_LIM_RANGE;
+ break;
+ case HDMI_QUANTIZATION_RANGE_FULL:
+ break;
+ default:
+ if (default_is_lim_range_rgb)
+ c.quantization = V4L2_QUANTIZATION_LIM_RANGE;
+ break;
+ }
+ break;
+
+ default:
+ /* YCbCr pixel encoding */
+ c.quantization = V4L2_QUANTIZATION_LIM_RANGE;
+ switch (avi->colorimetry) {
+ case HDMI_COLORIMETRY_NONE:
+ if (!is_ce)
+ break;
+ if (is_sdtv) {
+ c.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ c.ycbcr_enc = V4L2_YCBCR_ENC_601;
+ } else {
+ c.colorspace = V4L2_COLORSPACE_REC709;
+ c.ycbcr_enc = V4L2_YCBCR_ENC_709;
+ }
+ c.xfer_func = V4L2_XFER_FUNC_709;
+ break;
+ case HDMI_COLORIMETRY_ITU_601:
+ c.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ c.ycbcr_enc = V4L2_YCBCR_ENC_601;
+ c.xfer_func = V4L2_XFER_FUNC_709;
+ break;
+ case HDMI_COLORIMETRY_ITU_709:
+ c.colorspace = V4L2_COLORSPACE_REC709;
+ c.ycbcr_enc = V4L2_YCBCR_ENC_709;
+ c.xfer_func = V4L2_XFER_FUNC_709;
+ break;
+ case HDMI_COLORIMETRY_EXTENDED:
+ switch (avi->extended_colorimetry) {
+ case HDMI_EXTENDED_COLORIMETRY_XV_YCC_601:
+ c.colorspace = V4L2_COLORSPACE_REC709;
+ c.ycbcr_enc = V4L2_YCBCR_ENC_XV709;
+ c.xfer_func = V4L2_XFER_FUNC_709;
+ break;
+ case HDMI_EXTENDED_COLORIMETRY_XV_YCC_709:
+ c.colorspace = V4L2_COLORSPACE_REC709;
+ c.ycbcr_enc = V4L2_YCBCR_ENC_XV601;
+ c.xfer_func = V4L2_XFER_FUNC_709;
+ break;
+ case HDMI_EXTENDED_COLORIMETRY_S_YCC_601:
+ c.colorspace = V4L2_COLORSPACE_SRGB;
+ c.ycbcr_enc = V4L2_YCBCR_ENC_601;
+ c.xfer_func = V4L2_XFER_FUNC_SRGB;
+ break;
+ case HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601:
+ c.colorspace = V4L2_COLORSPACE_ADOBERGB;
+ c.ycbcr_enc = V4L2_YCBCR_ENC_601;
+ c.xfer_func = V4L2_XFER_FUNC_ADOBERGB;
+ break;
+ case HDMI_EXTENDED_COLORIMETRY_BT2020:
+ c.colorspace = V4L2_COLORSPACE_BT2020;
+ c.ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
+ c.xfer_func = V4L2_XFER_FUNC_709;
+ break;
+ case HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM:
+ c.colorspace = V4L2_COLORSPACE_BT2020;
+ c.ycbcr_enc = V4L2_YCBCR_ENC_BT2020_CONST_LUM;
+ c.xfer_func = V4L2_XFER_FUNC_709;
+ break;
+ default: /* fall back to ITU_709 */
+ c.colorspace = V4L2_COLORSPACE_REC709;
+ c.ycbcr_enc = V4L2_YCBCR_ENC_709;
+ c.xfer_func = V4L2_XFER_FUNC_709;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ /*
+ * YCC Quantization Range signaling is more-or-less broken,
+ * let's just ignore this.
+ */
+ break;
+ }
+ return c;
+}
+EXPORT_SYMBOL_GPL(v4l2_hdmi_rx_colorimetry);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 260288ca4f55..f48c505550e0 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1273,6 +1273,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_VC1_ANNEX_L: descr = "VC-1 (SMPTE 412M Annex L)"; break;
case V4L2_PIX_FMT_VP8: descr = "VP8"; break;
case V4L2_PIX_FMT_VP9: descr = "VP9"; break;
+ case V4L2_PIX_FMT_HEVC: descr = "HEVC"; break; /* aka H.265 */
case V4L2_PIX_FMT_CPIA1: descr = "GSPCA CPiA YUV"; break;
case V4L2_PIX_FMT_WNVA: descr = "WNVA"; break;
case V4L2_PIX_FMT_SN9C10X: descr = "GSPCA SN9C10X"; break;
@@ -2611,7 +2612,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
IOCTL_INFO_FNC(VIDIOC_PREPARE_BUF, v4l_prepare_buf, v4l_print_buffer, INFO_FL_QUEUE),
IOCTL_INFO_STD(VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings, v4l_print_enum_dv_timings, INFO_FL_CLEAR(v4l2_enum_dv_timings, pad)),
IOCTL_INFO_STD(VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings, v4l_print_dv_timings, INFO_FL_ALWAYS_COPY),
- IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, type)),
+ IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, pad)),
IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0),
IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)),
IOCTL_INFO_FNC(VIDIOC_QUERY_EXT_CTRL, v4l_query_ext_ctrl, v4l_print_query_ext_ctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_query_ext_ctrl, id)),
@@ -2832,14 +2833,15 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
size_t array_size = 0;
void __user *user_ptr = NULL;
void **kernel_ptr = NULL;
+ const size_t ioc_size = _IOC_SIZE(cmd);
/* Copy arguments into temp kernel buffer */
if (_IOC_DIR(cmd) != _IOC_NONE) {
- if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+ if (ioc_size <= sizeof(sbuf)) {
parg = sbuf;
} else {
/* too big to allocate from stack */
- mbuf = kvmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+ mbuf = kvmalloc(ioc_size, GFP_KERNEL);
if (NULL == mbuf)
return -ENOMEM;
parg = mbuf;
@@ -2847,7 +2849,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
err = -EFAULT;
if (_IOC_DIR(cmd) & _IOC_WRITE) {
- unsigned int n = _IOC_SIZE(cmd);
+ unsigned int n = ioc_size;
/*
* In some cases, only a few fields are used as input,
@@ -2868,11 +2870,11 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
goto out;
/* zero out anything we don't copy from userspace */
- if (n < _IOC_SIZE(cmd))
- memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
+ if (n < ioc_size)
+ memset((u8 *)parg + n, 0, ioc_size - n);
} else {
/* read-only ioctl */
- memset(parg, 0, _IOC_SIZE(cmd));
+ memset(parg, 0, ioc_size);
}
}
@@ -2930,7 +2932,7 @@ out_array_args:
switch (_IOC_DIR(cmd)) {
case _IOC_READ:
case (_IOC_WRITE | _IOC_READ):
- if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+ if (copy_to_user((void __user *)arg, parg, ioc_size))
err = -EFAULT;
break;
}
diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
index 1d550afeda13..0fc185a2ce90 100644
--- a/drivers/media/v4l2-core/v4l2-mc.c
+++ b/drivers/media/v4l2-core/v4l2-mc.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
/*
* Media Controller ancillary functions
*
@@ -5,16 +7,6 @@
* 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>
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index c5639817db34..f9eed938d348 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -187,27 +187,51 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
switch (cmd) {
case VIDIOC_QUERYCTRL:
+ /*
+ * TODO: this really should be folded into v4l2_queryctrl (this
+ * currently returns -EINVAL for NULL control handlers).
+ * However, v4l2_queryctrl() is still called directly by
+ * drivers as well and until that has been addressed I believe
+ * it is safer to do the check here. The same is true for the
+ * other control ioctls below.
+ */
+ if (!vfh->ctrl_handler)
+ return -ENOTTY;
return v4l2_queryctrl(vfh->ctrl_handler, arg);
case VIDIOC_QUERY_EXT_CTRL:
+ if (!vfh->ctrl_handler)
+ return -ENOTTY;
return v4l2_query_ext_ctrl(vfh->ctrl_handler, arg);
case VIDIOC_QUERYMENU:
+ if (!vfh->ctrl_handler)
+ return -ENOTTY;
return v4l2_querymenu(vfh->ctrl_handler, arg);
case VIDIOC_G_CTRL:
+ if (!vfh->ctrl_handler)
+ return -ENOTTY;
return v4l2_g_ctrl(vfh->ctrl_handler, arg);
case VIDIOC_S_CTRL:
+ if (!vfh->ctrl_handler)
+ return -ENOTTY;
return v4l2_s_ctrl(vfh, vfh->ctrl_handler, arg);
case VIDIOC_G_EXT_CTRLS:
+ if (!vfh->ctrl_handler)
+ return -ENOTTY;
return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg);
case VIDIOC_S_EXT_CTRLS:
+ if (!vfh->ctrl_handler)
+ return -ENOTTY;
return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg);
case VIDIOC_TRY_EXT_CTRLS:
+ if (!vfh->ctrl_handler)
+ return -ENOTTY;
return v4l2_try_ext_ctrls(vfh->ctrl_handler, arg);
case VIDIOC_DQEVENT:
@@ -239,6 +263,19 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return -EPERM;
return v4l2_subdev_call(sd, core, s_register, p);
}
+ case VIDIOC_DBG_G_CHIP_INFO:
+ {
+ struct v4l2_dbg_chip_info *p = arg;
+
+ if (p->match.type != V4L2_CHIP_MATCH_SUBDEV || p->match.addr)
+ return -EINVAL;
+ if (sd->ops->core && sd->ops->core->s_register)
+ p->flags |= V4L2_CHIP_FL_WRITABLE;
+ if (sd->ops->core && sd->ops->core->g_register)
+ p->flags |= V4L2_CHIP_FL_READABLE;
+ strlcpy(p->name, sd->name, sizeof(p->name));
+ return 0;
+ }
#endif
case VIDIOC_LOG_STATUS: {
@@ -260,6 +297,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (rval)
return rval;
+ memset(format->reserved, 0, sizeof(format->reserved));
+ memset(format->format.reserved, 0, sizeof(format->format.reserved));
return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format);
}
@@ -270,6 +309,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (rval)
return rval;
+ memset(format->reserved, 0, sizeof(format->reserved));
+ memset(format->format.reserved, 0, sizeof(format->format.reserved));
return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format);
}
@@ -281,6 +322,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (rval)
return rval;
+ memset(crop->reserved, 0, sizeof(crop->reserved));
memset(&sel, 0, sizeof(sel));
sel.which = crop->which;
sel.pad = crop->pad;
@@ -298,6 +340,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_subdev_crop *crop = arg;
struct v4l2_subdev_selection sel;
+ memset(crop->reserved, 0, sizeof(crop->reserved));
rval = check_crop(sd, crop);
if (rval)
return rval;
@@ -326,6 +369,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (code->pad >= sd->entity.num_pads)
return -EINVAL;
+ memset(code->reserved, 0, sizeof(code->reserved));
return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad,
code);
}
@@ -340,6 +384,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (fse->pad >= sd->entity.num_pads)
return -EINVAL;
+ memset(fse->reserved, 0, sizeof(fse->reserved));
return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad,
fse);
}
@@ -350,6 +395,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (fi->pad >= sd->entity.num_pads)
return -EINVAL;
+ memset(fi->reserved, 0, sizeof(fi->reserved));
return v4l2_subdev_call(sd, video, g_frame_interval, arg);
}
@@ -359,6 +405,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (fi->pad >= sd->entity.num_pads)
return -EINVAL;
+ memset(fi->reserved, 0, sizeof(fi->reserved));
return v4l2_subdev_call(sd, video, s_frame_interval, arg);
}
@@ -372,6 +419,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (fie->pad >= sd->entity.num_pads)
return -EINVAL;
+ memset(fie->reserved, 0, sizeof(fie->reserved));
return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad,
fie);
}
@@ -383,6 +431,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (rval)
return rval;
+ memset(sel->reserved, 0, sizeof(sel->reserved));
return v4l2_subdev_call(
sd, pad, get_selection, subdev_fh->pad, sel);
}
@@ -394,6 +443,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (rval)
return rval;
+ memset(sel->reserved, 0, sizeof(sel->reserved));
return v4l2_subdev_call(
sd, pad, set_selection, subdev_fh->pad, sel);
}
diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c
index f412429cf5ba..add2edb23eac 100644
--- a/drivers/media/v4l2-core/videobuf-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf-dma-sg.c
@@ -244,9 +244,8 @@ static int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
goto out_free_pages;
}
- dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n",
- (unsigned long)dma->vaddr,
- nr_pages << PAGE_SHIFT);
+ dprintk(1, "vmalloc is at addr %p, size=%d\n",
+ dma->vaddr, nr_pages << PAGE_SHIFT);
memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT);
dma->nr_pages = nr_pages;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 03605f8fc0dc..5d713008749b 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -75,7 +75,6 @@ config ATMEL_TCB_CLKSRC
config ATMEL_TCB_CLKSRC_BLOCK
int
depends on ATMEL_TCB_CLKSRC
- prompt "TC Block" if CPU_AT32AP700X
default 0
range 0 1
help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c3c8624f4d95..20be70c3f118 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -12,7 +12,7 @@ obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
obj-$(CONFIG_DUMMY_IRQ) += dummy-irq.o
obj-$(CONFIG_ICS932S401) += ics932s401.o
-obj-$(CONFIG_LKDTM) += lkdtm.o
+obj-$(CONFIG_LKDTM) += lkdtm/
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
obj-$(CONFIG_PHANTOM) += phantom.o
@@ -57,21 +57,3 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
obj-$(CONFIG_OCXL) += ocxl/
obj-$(CONFIG_MISC_RTSX) += cardreader/
-
-lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o
-lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o
-lkdtm-$(CONFIG_LKDTM) += lkdtm_heap.o
-lkdtm-$(CONFIG_LKDTM) += lkdtm_perms.o
-lkdtm-$(CONFIG_LKDTM) += lkdtm_refcount.o
-lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o
-lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o
-
-KCOV_INSTRUMENT_lkdtm_rodata.o := n
-
-OBJCOPYFLAGS :=
-OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \
- --set-section-flags .text=alloc,readonly \
- --rename-section .text=.rodata
-targets += lkdtm_rodata.o lkdtm_rodata_objcopy.o
-$(obj)/lkdtm_rodata_objcopy.o: $(obj)/lkdtm_rodata.o FORCE
- $(call if_changed,objcopy)
diff --git a/drivers/misc/aspeed-lpc-ctrl.c b/drivers/misc/aspeed-lpc-ctrl.c
index b5439643f54b..a024f8042259 100644
--- a/drivers/misc/aspeed-lpc-ctrl.c
+++ b/drivers/misc/aspeed-lpc-ctrl.c
@@ -7,6 +7,7 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
@@ -20,12 +21,17 @@
#define DEVICE_NAME "aspeed-lpc-ctrl"
+#define HICR5 0x0
+#define HICR5_ENL2H BIT(8)
+#define HICR5_ENFWH BIT(10)
+
#define HICR7 0x8
#define HICR8 0xc
struct aspeed_lpc_ctrl {
struct miscdevice miscdev;
struct regmap *regmap;
+ struct clk *clk;
phys_addr_t mem_base;
resource_size_t mem_size;
u32 pnor_size;
@@ -153,8 +159,18 @@ static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd,
if (rc)
return rc;
- return regmap_write(lpc_ctrl->regmap, HICR8,
- (~(map.size - 1)) | ((map.size >> 16) - 1));
+ rc = regmap_write(lpc_ctrl->regmap, HICR8,
+ (~(map.size - 1)) | ((map.size >> 16) - 1));
+ if (rc)
+ return rc;
+
+ /*
+ * Enable LPC FHW cycles. This is required for the host to
+ * access the regions specified.
+ */
+ return regmap_update_bits(lpc_ctrl->regmap, HICR5,
+ HICR5_ENFWH | HICR5_ENL2H,
+ HICR5_ENFWH | HICR5_ENL2H);
}
return -EINVAL;
@@ -221,16 +237,33 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
return -ENODEV;
}
+ lpc_ctrl->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(lpc_ctrl->clk)) {
+ dev_err(dev, "couldn't get clock\n");
+ return PTR_ERR(lpc_ctrl->clk);
+ }
+ rc = clk_prepare_enable(lpc_ctrl->clk);
+ if (rc) {
+ dev_err(dev, "couldn't enable clock\n");
+ return rc;
+ }
+
lpc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR;
lpc_ctrl->miscdev.name = DEVICE_NAME;
lpc_ctrl->miscdev.fops = &aspeed_lpc_ctrl_fops;
lpc_ctrl->miscdev.parent = dev;
rc = misc_register(&lpc_ctrl->miscdev);
- if (rc)
+ if (rc) {
dev_err(dev, "Unable to register device\n");
- else
- dev_info(dev, "Loaded at %pr\n", &resm);
+ goto err;
+ }
+
+ dev_info(dev, "Loaded at %pr\n", &resm);
+
+ return 0;
+err:
+ clk_disable_unprepare(lpc_ctrl->clk);
return rc;
}
@@ -239,6 +272,7 @@ static int aspeed_lpc_ctrl_remove(struct platform_device *pdev)
struct aspeed_lpc_ctrl *lpc_ctrl = dev_get_drvdata(&pdev->dev);
misc_deregister(&lpc_ctrl->miscdev);
+ clk_disable_unprepare(lpc_ctrl->clk);
return 0;
}
diff --git a/drivers/misc/cardreader/rts5260.c b/drivers/misc/cardreader/rts5260.c
index 07cb93abf685..a493b01c5bc6 100644
--- a/drivers/misc/cardreader/rts5260.c
+++ b/drivers/misc/cardreader/rts5260.c
@@ -388,17 +388,17 @@ static void rts5260_disable_ocp(struct rtsx_pcr *pcr)
OC_POWER_DOWN);
}
-int rts5260_get_ocpstat(struct rtsx_pcr *pcr, u8 *val)
+static int rts5260_get_ocpstat(struct rtsx_pcr *pcr, u8 *val)
{
return rtsx_pci_read_register(pcr, REG_OCPSTAT, val);
}
-int rts5260_get_ocpstat2(struct rtsx_pcr *pcr, u8 *val)
+static int rts5260_get_ocpstat2(struct rtsx_pcr *pcr, u8 *val)
{
return rtsx_pci_read_register(pcr, REG_DV3318_OCPSTAT, val);
}
-void rts5260_clear_ocpstat(struct rtsx_pcr *pcr)
+static void rts5260_clear_ocpstat(struct rtsx_pcr *pcr)
{
u8 mask = 0;
u8 val = 0;
@@ -418,7 +418,7 @@ void rts5260_clear_ocpstat(struct rtsx_pcr *pcr)
DV3318_OCP_INT_CLR | DV3318_OCP_CLR, 0);
}
-void rts5260_process_ocp(struct rtsx_pcr *pcr)
+static void rts5260_process_ocp(struct rtsx_pcr *pcr)
{
if (!pcr->option.ocp_en)
return;
@@ -449,7 +449,7 @@ void rts5260_process_ocp(struct rtsx_pcr *pcr)
}
}
-int rts5260_init_hw(struct rtsx_pcr *pcr)
+static int rts5260_init_hw(struct rtsx_pcr *pcr)
{
int err;
@@ -620,7 +620,7 @@ static int rts5260_extra_init_hw(struct rtsx_pcr *pcr)
return 0;
}
-void rts5260_set_aspm(struct rtsx_pcr *pcr, bool enable)
+static void rts5260_set_aspm(struct rtsx_pcr *pcr, bool enable)
{
struct rtsx_cr_option *option = &pcr->option;
u8 val = 0;
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 01f9c4921c50..0c125f207aea 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -1,14 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* at24.c - handle most I2C EEPROMs
*
* Copyright (C) 2005-2007 David Brownell
* Copyright (C) 2008 Wolfram Sang, Pengutronix
- *
- * 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/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -63,8 +60,6 @@ struct at24_client {
};
struct at24_data {
- struct at24_platform_data chip;
-
/*
* Lock protects against activities from other Linux tasks,
* but not from changes by other I2C masters.
@@ -75,7 +70,10 @@ struct at24_data {
unsigned int num_addresses;
unsigned int offset_adj;
- struct nvmem_config nvmem_config;
+ u32 byte_len;
+ u16 page_size;
+ u8 flags;
+
struct nvmem_device *nvmem;
struct gpio_desc *wp_gpio;
@@ -239,8 +237,6 @@ static const struct acpi_device_id at24_acpi_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, at24_acpi_ids);
-/*-------------------------------------------------------------------------*/
-
/*
* This routine supports chips which consume multiple I2C addresses. It
* computes the addressing information to be used for a given r/w request.
@@ -255,7 +251,7 @@ static struct at24_client *at24_translate_offset(struct at24_data *at24,
{
unsigned int i;
- if (at24->chip.flags & AT24_FLAG_ADDR16) {
+ if (at24->flags & AT24_FLAG_ADDR16) {
i = *offset >> 16;
*offset &= 0xffff;
} else {
@@ -266,6 +262,11 @@ static struct at24_client *at24_translate_offset(struct at24_data *at24,
return &at24->client[i];
}
+static struct device *at24_base_client_dev(struct at24_data *at24)
+{
+ return &at24->client[0].client->dev;
+}
+
static size_t at24_adjust_read_count(struct at24_data *at24,
unsigned int offset, size_t count)
{
@@ -277,8 +278,8 @@ static size_t at24_adjust_read_count(struct at24_data *at24,
* the next slave address: truncate the count to the slave boundary,
* so that the read never straddles slaves.
*/
- if (at24->chip.flags & AT24_FLAG_NO_RDROL) {
- bits = (at24->chip.flags & AT24_FLAG_ADDR16) ? 16 : 8;
+ if (at24->flags & AT24_FLAG_NO_RDROL) {
+ bits = (at24->flags & AT24_FLAG_ADDR16) ? 16 : 8;
remainder = BIT(bits) - offset;
if (count > remainder)
count = remainder;
@@ -337,7 +338,7 @@ static size_t at24_adjust_write_count(struct at24_data *at24,
count = at24->write_max;
/* Never roll over backwards, to the start of this page */
- next_page = roundup(offset + 1, at24->chip.page_size);
+ next_page = roundup(offset + 1, at24->page_size);
if (offset + count > next_page)
count = next_page - offset;
@@ -371,15 +372,18 @@ static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf,
static int at24_read(void *priv, unsigned int off, void *val, size_t count)
{
- struct at24_data *at24 = priv;
- struct device *dev = &at24->client[0].client->dev;
+ struct at24_data *at24;
+ struct device *dev;
char *buf = val;
int ret;
+ at24 = priv;
+ dev = at24_base_client_dev(at24);
+
if (unlikely(!count))
return count;
- if (off + count > at24->chip.byte_len)
+ if (off + count > at24->byte_len)
return -EINVAL;
ret = pm_runtime_get_sync(dev);
@@ -395,17 +399,15 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
mutex_lock(&at24->lock);
while (count) {
- int status;
-
- status = at24_regmap_read(at24, buf, off, count);
- if (status < 0) {
+ ret = at24_regmap_read(at24, buf, off, count);
+ if (ret < 0) {
mutex_unlock(&at24->lock);
pm_runtime_put(dev);
- return status;
+ return ret;
}
- buf += status;
- off += status;
- count -= status;
+ buf += ret;
+ off += ret;
+ count -= ret;
}
mutex_unlock(&at24->lock);
@@ -417,15 +419,18 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
static int at24_write(void *priv, unsigned int off, void *val, size_t count)
{
- struct at24_data *at24 = priv;
- struct device *dev = &at24->client[0].client->dev;
+ struct at24_data *at24;
+ struct device *dev;
char *buf = val;
int ret;
+ at24 = priv;
+ dev = at24_base_client_dev(at24);
+
if (unlikely(!count))
return -EINVAL;
- if (off + count > at24->chip.byte_len)
+ if (off + count > at24->byte_len)
return -EINVAL;
ret = pm_runtime_get_sync(dev);
@@ -442,18 +447,16 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
gpiod_set_value_cansleep(at24->wp_gpio, 0);
while (count) {
- int status;
-
- status = at24_regmap_write(at24, buf, off, count);
- if (status < 0) {
+ ret = at24_regmap_write(at24, buf, off, count);
+ if (ret < 0) {
gpiod_set_value_cansleep(at24->wp_gpio, 1);
mutex_unlock(&at24->lock);
pm_runtime_put(dev);
- return status;
+ return ret;
}
- buf += status;
- off += status;
- count -= status;
+ buf += ret;
+ off += ret;
+ count -= ret;
}
gpiod_set_value_cansleep(at24->wp_gpio, 1);
@@ -464,7 +467,8 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
return 0;
}
-static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip)
+static void at24_properties_to_pdata(struct device *dev,
+ struct at24_platform_data *chip)
{
int err;
u32 val;
@@ -491,6 +495,43 @@ static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip)
}
}
+static int at24_get_pdata(struct device *dev, struct at24_platform_data *pdata)
+{
+ struct device_node *of_node = dev->of_node;
+ const struct at24_chip_data *cdata;
+ const struct i2c_device_id *id;
+ struct at24_platform_data *pd;
+
+ pd = dev_get_platdata(dev);
+ if (pd) {
+ memcpy(pdata, pd, sizeof(*pdata));
+ return 0;
+ }
+
+ id = i2c_match_id(at24_ids, to_i2c_client(dev));
+
+ /*
+ * The I2C core allows OF nodes compatibles to match against the
+ * I2C device ID table as a fallback, so check not only if an OF
+ * node is present but also if it matches an OF device ID entry.
+ */
+ if (of_node && of_match_device(at24_of_match, dev))
+ cdata = of_device_get_match_data(dev);
+ else if (id)
+ cdata = (void *)&id->driver_data;
+ else
+ cdata = acpi_device_get_match_data(dev);
+
+ if (!cdata)
+ return -ENODEV;
+
+ pdata->byte_len = cdata->byte_len;
+ pdata->flags = cdata->flags;
+ at24_properties_to_pdata(dev, pdata);
+
+ return 0;
+}
+
static unsigned int at24_get_offset_adj(u8 flags, unsigned int byte_len)
{
if (flags & AT24_FLAG_MAC) {
@@ -514,102 +555,83 @@ static unsigned int at24_get_offset_adj(u8 flags, unsigned int byte_len)
}
}
-static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int at24_probe(struct i2c_client *client)
{
- struct at24_platform_data chip = { 0 };
- const struct at24_chip_data *cd = NULL;
- bool writable;
- struct at24_data *at24;
- int err;
- unsigned int i, num_addresses;
struct regmap_config regmap_config = { };
+ struct nvmem_config nvmem_config = { };
+ struct at24_platform_data pdata = { };
+ struct device *dev = &client->dev;
+ bool i2c_fn_i2c, i2c_fn_block;
+ unsigned int i, num_addresses;
+ struct at24_data *at24;
+ struct regmap *regmap;
+ size_t at24_size;
+ bool writable;
u8 test_byte;
+ int err;
- if (client->dev.platform_data) {
- chip = *(struct at24_platform_data *)client->dev.platform_data;
- } else {
- /*
- * The I2C core allows OF nodes compatibles to match against the
- * I2C device ID table as a fallback, so check not only if an OF
- * node is present but also if it matches an OF device ID entry.
- */
- if (client->dev.of_node &&
- of_match_device(at24_of_match, &client->dev)) {
- cd = of_device_get_match_data(&client->dev);
- } else if (id) {
- cd = (void *)id->driver_data;
- } else {
- const struct acpi_device_id *aid;
-
- aid = acpi_match_device(at24_acpi_ids, &client->dev);
- if (aid)
- cd = (void *)aid->driver_data;
- }
- if (!cd)
- return -ENODEV;
+ i2c_fn_i2c = i2c_check_functionality(client->adapter, I2C_FUNC_I2C);
+ i2c_fn_block = i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK);
- chip.byte_len = cd->byte_len;
- chip.flags = cd->flags;
- at24_get_pdata(&client->dev, &chip);
- }
+ err = at24_get_pdata(dev, &pdata);
+ if (err)
+ return err;
+
+ if (!i2c_fn_i2c && !i2c_fn_block)
+ pdata.page_size = 1;
- if (!is_power_of_2(chip.byte_len))
- dev_warn(&client->dev,
- "byte_len looks suspicious (no power of 2)!\n");
- if (!chip.page_size) {
- dev_err(&client->dev, "page_size must not be 0!\n");
+ if (!pdata.page_size) {
+ dev_err(dev, "page_size must not be 0!\n");
return -EINVAL;
}
- if (!is_power_of_2(chip.page_size))
- dev_warn(&client->dev,
- "page_size looks suspicious (no power of 2)!\n");
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C) &&
- !i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
- chip.page_size = 1;
+ if (!is_power_of_2(pdata.page_size))
+ dev_warn(dev, "page_size looks suspicious (no power of 2)!\n");
- if (chip.flags & AT24_FLAG_TAKE8ADDR)
+ if (pdata.flags & AT24_FLAG_TAKE8ADDR)
num_addresses = 8;
else
- num_addresses = DIV_ROUND_UP(chip.byte_len,
- (chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256);
+ num_addresses = DIV_ROUND_UP(pdata.byte_len,
+ (pdata.flags & AT24_FLAG_ADDR16) ? 65536 : 256);
+
+ if ((pdata.flags & AT24_FLAG_SERIAL) && (pdata.flags & AT24_FLAG_MAC)) {
+ dev_err(dev,
+ "invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC.");
+ return -EINVAL;
+ }
regmap_config.val_bits = 8;
- regmap_config.reg_bits = (chip.flags & AT24_FLAG_ADDR16) ? 16 : 8;
+ regmap_config.reg_bits = (pdata.flags & AT24_FLAG_ADDR16) ? 16 : 8;
+ regmap_config.disable_locking = true;
- at24 = devm_kzalloc(&client->dev, sizeof(struct at24_data) +
- num_addresses * sizeof(struct at24_client), GFP_KERNEL);
+ regmap = devm_regmap_init_i2c(client, &regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ at24_size = sizeof(*at24) + num_addresses * sizeof(struct at24_client);
+ at24 = devm_kzalloc(dev, at24_size, GFP_KERNEL);
if (!at24)
return -ENOMEM;
mutex_init(&at24->lock);
- at24->chip = chip;
+ at24->byte_len = pdata.byte_len;
+ at24->page_size = pdata.page_size;
+ at24->flags = pdata.flags;
at24->num_addresses = num_addresses;
- at24->offset_adj = at24_get_offset_adj(chip.flags, chip.byte_len);
+ at24->offset_adj = at24_get_offset_adj(pdata.flags, pdata.byte_len);
+ at24->client[0].client = client;
+ at24->client[0].regmap = regmap;
- at24->wp_gpio = devm_gpiod_get_optional(&client->dev,
- "wp", GPIOD_OUT_HIGH);
+ at24->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_HIGH);
if (IS_ERR(at24->wp_gpio))
return PTR_ERR(at24->wp_gpio);
- at24->client[0].client = client;
- at24->client[0].regmap = devm_regmap_init_i2c(client, &regmap_config);
- if (IS_ERR(at24->client[0].regmap))
- return PTR_ERR(at24->client[0].regmap);
-
- if ((chip.flags & AT24_FLAG_SERIAL) && (chip.flags & AT24_FLAG_MAC)) {
- dev_err(&client->dev,
- "invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC.");
- return -EINVAL;
- }
-
- writable = !(chip.flags & AT24_FLAG_READONLY);
+ writable = !(pdata.flags & AT24_FLAG_READONLY);
if (writable) {
at24->write_max = min_t(unsigned int,
- chip.page_size, at24_io_limit);
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C) &&
- at24->write_max > I2C_SMBUS_BLOCK_MAX)
+ pdata.page_size, at24_io_limit);
+ if (!i2c_fn_i2c && at24->write_max > I2C_SMBUS_BLOCK_MAX)
at24->write_max = I2C_SMBUS_BLOCK_MAX;
}
@@ -618,8 +640,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
at24->client[i].client = i2c_new_dummy(client->adapter,
client->addr + i);
if (!at24->client[i].client) {
- dev_err(&client->dev, "address 0x%02x unavailable\n",
- client->addr + i);
+ dev_err(dev, "address 0x%02x unavailable\n",
+ client->addr + i);
err = -EADDRINUSE;
goto err_clients;
}
@@ -635,48 +657,47 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
i2c_set_clientdata(client, at24);
/* enable runtime pm */
- pm_runtime_set_active(&client->dev);
- pm_runtime_enable(&client->dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
/*
* Perform a one-byte test read to verify that the
* chip is functional.
*/
err = at24_read(at24, 0, &test_byte, 1);
- pm_runtime_idle(&client->dev);
+ pm_runtime_idle(dev);
if (err) {
err = -ENODEV;
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_config.reg_read = at24_read;
- at24->nvmem_config.reg_write = at24_write;
- at24->nvmem_config.priv = at24;
- at24->nvmem_config.stride = 1;
- at24->nvmem_config.word_size = 1;
- at24->nvmem_config.size = chip.byte_len;
-
- at24->nvmem = nvmem_register(&at24->nvmem_config);
-
+ nvmem_config.name = dev_name(dev);
+ nvmem_config.dev = dev;
+ nvmem_config.read_only = !writable;
+ nvmem_config.root_only = true;
+ nvmem_config.owner = THIS_MODULE;
+ nvmem_config.compat = true;
+ nvmem_config.base_dev = dev;
+ nvmem_config.reg_read = at24_read;
+ nvmem_config.reg_write = at24_write;
+ nvmem_config.priv = at24;
+ nvmem_config.stride = 1;
+ nvmem_config.word_size = 1;
+ nvmem_config.size = pdata.byte_len;
+
+ at24->nvmem = nvmem_register(&nvmem_config);
if (IS_ERR(at24->nvmem)) {
err = PTR_ERR(at24->nvmem);
goto err_clients;
}
- 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);
+ dev_info(dev, "%u byte %s EEPROM, %s, %u bytes/write\n",
+ pdata.byte_len, client->name,
+ writable ? "writable" : "read-only", at24->write_max);
/* export data to kernel code */
- if (chip.setup)
- chip.setup(at24->nvmem, chip.context);
+ if (pdata.setup)
+ pdata.setup(at24->nvmem, pdata.context);
return 0;
@@ -685,7 +706,7 @@ err_clients:
if (at24->client[i].client)
i2c_unregister_device(at24->client[i].client);
- pm_runtime_disable(&client->dev);
+ pm_runtime_disable(dev);
return err;
}
@@ -708,15 +729,13 @@ static int at24_remove(struct i2c_client *client)
return 0;
}
-/*-------------------------------------------------------------------------*/
-
static struct i2c_driver at24_driver = {
.driver = {
.name = "at24",
.of_match_table = at24_of_match,
.acpi_match_table = ACPI_PTR(at24_acpi_ids),
},
- .probe = at24_probe,
+ .probe_new = at24_probe,
.remove = at24_remove,
.id_table = at24_ids,
};
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 9282ffd607ff..6a7d4a2ad514 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -102,7 +102,7 @@ static int at25_ee_read(void *priv, unsigned int offset,
}
spi_message_init(&m);
- memset(t, 0, sizeof t);
+ memset(t, 0, sizeof(t));
t[0].tx_buf = command;
t[0].len = at25->addrlen + 1;
diff --git a/drivers/misc/lkdtm/Makefile b/drivers/misc/lkdtm/Makefile
new file mode 100644
index 000000000000..3370a4138e94
--- /dev/null
+++ b/drivers/misc/lkdtm/Makefile
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_LKDTM) += lkdtm.o
+
+lkdtm-$(CONFIG_LKDTM) += core.o
+lkdtm-$(CONFIG_LKDTM) += bugs.o
+lkdtm-$(CONFIG_LKDTM) += heap.o
+lkdtm-$(CONFIG_LKDTM) += perms.o
+lkdtm-$(CONFIG_LKDTM) += refcount.o
+lkdtm-$(CONFIG_LKDTM) += rodata_objcopy.o
+lkdtm-$(CONFIG_LKDTM) += usercopy.o
+
+KCOV_INSTRUMENT_rodata.o := n
+
+OBJCOPYFLAGS :=
+OBJCOPYFLAGS_rodata_objcopy.o := \
+ --set-section-flags .text=alloc,readonly \
+ --rename-section .text=.rodata
+targets += rodata.o rodata_objcopy.o
+$(obj)/rodata_objcopy.o: $(obj)/rodata.o FORCE
+ $(call if_changed,objcopy)
diff --git a/drivers/misc/lkdtm_bugs.c b/drivers/misc/lkdtm/bugs.c
index 7eebbdfbcacd..7eebbdfbcacd 100644
--- a/drivers/misc/lkdtm_bugs.c
+++ b/drivers/misc/lkdtm/bugs.c
diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm/core.c
index 2154d1bfd18b..2154d1bfd18b 100644
--- a/drivers/misc/lkdtm_core.c
+++ b/drivers/misc/lkdtm/core.c
diff --git a/drivers/misc/lkdtm_heap.c b/drivers/misc/lkdtm/heap.c
index 65026d7de130..65026d7de130 100644
--- a/drivers/misc/lkdtm_heap.c
+++ b/drivers/misc/lkdtm/heap.c
diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h
index 9e513dcfd809..9e513dcfd809 100644
--- a/drivers/misc/lkdtm.h
+++ b/drivers/misc/lkdtm/lkdtm.h
diff --git a/drivers/misc/lkdtm_perms.c b/drivers/misc/lkdtm/perms.c
index 53b85c9d16b8..53b85c9d16b8 100644
--- a/drivers/misc/lkdtm_perms.c
+++ b/drivers/misc/lkdtm/perms.c
diff --git a/drivers/misc/lkdtm_refcount.c b/drivers/misc/lkdtm/refcount.c
index 2b99d448e7fd..0a146b32da13 100644
--- a/drivers/misc/lkdtm_refcount.c
+++ b/drivers/misc/lkdtm/refcount.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* This is for all the tests related to refcount bugs (e.g. overflow,
* underflow, reaching zero untested, etc).
diff --git a/drivers/misc/lkdtm_rodata.c b/drivers/misc/lkdtm/rodata.c
index 58d180af72cf..58d180af72cf 100644
--- a/drivers/misc/lkdtm_rodata.c
+++ b/drivers/misc/lkdtm/rodata.c
diff --git a/drivers/misc/lkdtm_usercopy.c b/drivers/misc/lkdtm/usercopy.c
index 9725aed305bb..9725aed305bb 100644
--- a/drivers/misc/lkdtm_usercopy.c
+++ b/drivers/misc/lkdtm/usercopy.c
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 772d02922529..b1133739fb4b 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -74,6 +74,23 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
goto out;
}
+ while (cl->tx_cb_queued >= bus->tx_queue_limit) {
+ mutex_unlock(&bus->device_lock);
+ rets = wait_event_interruptible(cl->tx_wait,
+ cl->writing_state == MEI_WRITE_COMPLETE ||
+ (!mei_cl_is_connected(cl)));
+ mutex_lock(&bus->device_lock);
+ if (rets) {
+ if (signal_pending(current))
+ rets = -EINTR;
+ goto out;
+ }
+ if (!mei_cl_is_connected(cl)) {
+ rets = -ENODEV;
+ goto out;
+ }
+ }
+
cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, NULL);
if (!cb) {
rets = -ENOMEM;
@@ -450,6 +467,29 @@ bool mei_cldev_enabled(struct mei_cl_device *cldev)
EXPORT_SYMBOL_GPL(mei_cldev_enabled);
/**
+ * mei_cl_bus_module_get - acquire module of the underlying
+ * hw driver.
+ *
+ * @cldev: mei client device
+ *
+ * Return: true on success; false if the module was removed.
+ */
+static bool mei_cl_bus_module_get(struct mei_cl_device *cldev)
+{
+ return try_module_get(cldev->bus->dev->driver->owner);
+}
+
+/**
+ * mei_cl_bus_module_put - release the underlying hw module.
+ *
+ * @cldev: mei client device
+ */
+static void mei_cl_bus_module_put(struct mei_cl_device *cldev)
+{
+ module_put(cldev->bus->dev->driver->owner);
+}
+
+/**
* mei_cldev_enable - enable me client device
* create connection with me client
*
@@ -487,9 +527,17 @@ int mei_cldev_enable(struct mei_cl_device *cldev)
goto out;
}
+ if (!mei_cl_bus_module_get(cldev)) {
+ dev_err(&cldev->dev, "get hw module failed");
+ ret = -ENODEV;
+ goto out;
+ }
+
ret = mei_cl_connect(cl, cldev->me_cl, NULL);
- if (ret < 0)
+ if (ret < 0) {
dev_err(&cldev->dev, "cannot connect\n");
+ mei_cl_bus_module_put(cldev);
+ }
out:
mutex_unlock(&bus->device_lock);
@@ -553,6 +601,8 @@ int mei_cldev_disable(struct mei_cl_device *cldev)
dev_err(bus->dev, "Could not disconnect from the ME client\n");
out:
+ mei_cl_bus_module_put(cldev);
+
/* Flush queues and remove any pending read */
mei_cl_flush_queues(cl, NULL);
mei_cl_unlink(cl);
@@ -563,37 +613,6 @@ out:
EXPORT_SYMBOL_GPL(mei_cldev_disable);
/**
- * mei_cl_bus_module_get - acquire module of the underlying
- * hw module.
- *
- * @cl: host client
- *
- * Return: true on success; false if the module was removed.
- */
-bool mei_cl_bus_module_get(struct mei_cl *cl)
-{
- struct mei_cl_device *cldev = cl->cldev;
-
- if (!cldev)
- return true;
-
- return try_module_get(cldev->bus->dev->driver->owner);
-}
-
-/**
- * mei_cl_bus_module_put - release the underlying hw module.
- *
- * @cl: host client
- */
-void mei_cl_bus_module_put(struct mei_cl *cl)
-{
- struct mei_cl_device *cldev = cl->cldev;
-
- if (cldev)
- module_put(cldev->bus->dev->driver->owner);
-}
-
-/**
* mei_cl_device_find - find matching entry in the driver id table
*
* @cldev: me client device
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 7e60c1817c31..8d6197a88b54 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -350,6 +350,36 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
}
/**
+ * mei_tx_cb_queue - queue tx callback
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * @cb: mei callback struct
+ * @head: an instance of list to queue on
+ */
+static inline void mei_tx_cb_enqueue(struct mei_cl_cb *cb,
+ struct list_head *head)
+{
+ list_add_tail(&cb->list, head);
+ cb->cl->tx_cb_queued++;
+}
+
+/**
+ * mei_tx_cb_dequeue - dequeue tx callback
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * @cb: mei callback struct to dequeue and free
+ */
+static inline void mei_tx_cb_dequeue(struct mei_cl_cb *cb)
+{
+ if (!WARN_ON(cb->cl->tx_cb_queued == 0))
+ cb->cl->tx_cb_queued--;
+
+ mei_io_cb_free(cb);
+}
+
+/**
* mei_io_cb_init - allocate and initialize io callback
*
* @cl: mei client
@@ -377,49 +407,37 @@ static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl,
}
/**
- * __mei_io_list_flush_cl - removes and frees cbs belonging to cl.
+ * mei_io_list_flush_cl - removes cbs belonging to the cl.
*
* @head: an instance of our list structure
- * @cl: host client, can be NULL for flushing the whole list
- * @free: whether to free the cbs
+ * @cl: host client
*/
-static void __mei_io_list_flush_cl(struct list_head *head,
- const struct mei_cl *cl, bool free)
+static void mei_io_list_flush_cl(struct list_head *head,
+ const struct mei_cl *cl)
{
struct mei_cl_cb *cb, *next;
- /* enable removing everything if no cl is specified */
list_for_each_entry_safe(cb, next, head, list) {
- if (!cl || mei_cl_cmp_id(cl, cb->cl)) {
+ if (mei_cl_cmp_id(cl, cb->cl))
list_del_init(&cb->list);
- if (free)
- mei_io_cb_free(cb);
- }
}
}
/**
- * mei_io_list_flush_cl - removes list entry belonging to cl.
+ * mei_io_tx_list_free_cl - removes cb belonging to the cl and free them
*
* @head: An instance of our list structure
* @cl: host client
*/
-static inline void mei_io_list_flush_cl(struct list_head *head,
- const struct mei_cl *cl)
+static void mei_io_tx_list_free_cl(struct list_head *head,
+ const struct mei_cl *cl)
{
- __mei_io_list_flush_cl(head, cl, false);
-}
+ struct mei_cl_cb *cb, *next;
-/**
- * mei_io_list_free_cl - removes cb belonging to cl and free them
- *
- * @head: An instance of our list structure
- * @cl: host client
- */
-static inline void mei_io_list_free_cl(struct list_head *head,
- const struct mei_cl *cl)
-{
- __mei_io_list_flush_cl(head, cl, true);
+ list_for_each_entry_safe(cb, next, head, list) {
+ if (mei_cl_cmp_id(cl, cb->cl))
+ mei_tx_cb_dequeue(cb);
+ }
}
/**
@@ -538,8 +556,8 @@ int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp)
dev = cl->dev;
cl_dbg(dev, cl, "remove list entry belonging to cl\n");
- mei_io_list_free_cl(&cl->dev->write_list, cl);
- mei_io_list_free_cl(&cl->dev->write_waiting_list, cl);
+ mei_io_tx_list_free_cl(&cl->dev->write_list, cl);
+ mei_io_tx_list_free_cl(&cl->dev->write_waiting_list, cl);
mei_io_list_flush_cl(&cl->dev->ctrl_wr_list, cl);
mei_io_list_flush_cl(&cl->dev->ctrl_rd_list, cl);
mei_io_list_free_fp(&cl->rd_pending, fp);
@@ -756,8 +774,8 @@ static void mei_cl_set_disconnected(struct mei_cl *cl)
return;
cl->state = MEI_FILE_DISCONNECTED;
- mei_io_list_free_cl(&dev->write_list, cl);
- mei_io_list_free_cl(&dev->write_waiting_list, cl);
+ mei_io_tx_list_free_cl(&dev->write_list, cl);
+ mei_io_tx_list_free_cl(&dev->write_waiting_list, cl);
mei_io_list_flush_cl(&dev->ctrl_rd_list, cl);
mei_io_list_flush_cl(&dev->ctrl_wr_list, cl);
mei_cl_wake_all(cl);
@@ -765,8 +783,6 @@ static void mei_cl_set_disconnected(struct mei_cl *cl)
cl->tx_flow_ctrl_creds = 0;
cl->timer_count = 0;
- mei_cl_bus_module_put(cl);
-
if (!cl->me_cl)
return;
@@ -1076,9 +1092,6 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
dev = cl->dev;
- if (!mei_cl_bus_module_get(cl))
- return -ENODEV;
-
rets = mei_cl_set_connecting(cl, me_cl);
if (rets)
goto nortpm;
@@ -1698,9 +1711,9 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
out:
if (mei_hdr.msg_complete)
- list_add_tail(&cb->list, &dev->write_waiting_list);
+ mei_tx_cb_enqueue(cb, &dev->write_waiting_list);
else
- list_add_tail(&cb->list, &dev->write_list);
+ mei_tx_cb_enqueue(cb, &dev->write_list);
cb = NULL;
if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
@@ -1746,7 +1759,7 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
switch (cb->fop_type) {
case MEI_FOP_WRITE:
- mei_io_cb_free(cb);
+ mei_tx_cb_dequeue(cb);
cl->writing_state = MEI_WRITE_COMPLETE;
if (waitqueue_active(&cl->tx_wait)) {
wake_up_interruptible(&cl->tx_wait);
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index a617aa5a3ad8..c815da91089c 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -97,7 +97,7 @@ static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
int pos = 0;
int ret;
-#define HDR " |me|host|state|rd|wr|\n"
+#define HDR " |me|host|state|rd|wr|wrq\n"
if (!dev)
return -ENODEV;
@@ -130,9 +130,10 @@ 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,
- "%3d|%2d|%4d|%5d|%2d|%2d|\n",
+ "%3d|%2d|%4d|%5d|%2d|%2d|%3u\n",
i, mei_cl_me_id(cl), cl->host_client_id, cl->state,
- !list_empty(&cl->rd_completed), cl->writing_state);
+ !list_empty(&cl->rd_completed), cl->writing_state,
+ cl->tx_cb_queued);
i++;
}
out:
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index c46f6e99a55e..4888ebc076b7 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -383,6 +383,7 @@ void mei_device_init(struct mei_device *dev,
INIT_LIST_HEAD(&dev->write_waiting_list);
INIT_LIST_HEAD(&dev->ctrl_wr_list);
INIT_LIST_HEAD(&dev->ctrl_rd_list);
+ dev->tx_queue_limit = MEI_TX_QUEUE_LIMIT_DEFAULT;
INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
INIT_WORK(&dev->reset_work, mei_reset_work);
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 758dc73602d5..7465f17e1559 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -291,6 +291,27 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
goto out;
}
+ while (cl->tx_cb_queued >= dev->tx_queue_limit) {
+ if (file->f_flags & O_NONBLOCK) {
+ rets = -EAGAIN;
+ goto out;
+ }
+ mutex_unlock(&dev->device_lock);
+ rets = wait_event_interruptible(cl->tx_wait,
+ cl->writing_state == MEI_WRITE_COMPLETE ||
+ (!mei_cl_is_connected(cl)));
+ mutex_lock(&dev->device_lock);
+ if (rets) {
+ if (signal_pending(current))
+ rets = -EINTR;
+ goto out;
+ }
+ if (!mei_cl_is_connected(cl)) {
+ rets = -ENODEV;
+ goto out;
+ }
+ }
+
*offset = 0;
cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file);
if (!cb) {
@@ -507,7 +528,6 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
break;
default:
- dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd);
rets = -ENOIOCTLCMD;
}
@@ -580,6 +600,12 @@ static __poll_t mei_poll(struct file *file, poll_table *wait)
mei_cl_read_start(cl, mei_cl_mtu(cl), file);
}
+ if (req_events & (POLLOUT | POLLWRNORM)) {
+ poll_wait(file, &cl->tx_wait, wait);
+ if (cl->tx_cb_queued < dev->tx_queue_limit)
+ mask |= POLLOUT | POLLWRNORM;
+ }
+
out:
mutex_unlock(&dev->device_lock);
return mask;
@@ -749,10 +775,48 @@ static ssize_t hbm_ver_drv_show(struct device *device,
}
static DEVICE_ATTR_RO(hbm_ver_drv);
+static ssize_t tx_queue_limit_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct mei_device *dev = dev_get_drvdata(device);
+ u8 size = 0;
+
+ mutex_lock(&dev->device_lock);
+ size = dev->tx_queue_limit;
+ mutex_unlock(&dev->device_lock);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", size);
+}
+
+static ssize_t tx_queue_limit_store(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mei_device *dev = dev_get_drvdata(device);
+ u8 limit;
+ unsigned int inp;
+ int err;
+
+ err = kstrtouint(buf, 10, &inp);
+ if (err)
+ return err;
+ if (inp > MEI_TX_QUEUE_LIMIT_MAX || inp < MEI_TX_QUEUE_LIMIT_MIN)
+ return -EINVAL;
+ limit = inp;
+
+ mutex_lock(&dev->device_lock);
+ dev->tx_queue_limit = limit;
+ mutex_unlock(&dev->device_lock);
+
+ return count;
+}
+static DEVICE_ATTR_RW(tx_queue_limit);
+
static struct attribute *mei_attrs[] = {
&dev_attr_fw_status.attr,
&dev_attr_hbm_ver.attr,
&dev_attr_hbm_ver_drv.attr,
+ &dev_attr_tx_queue_limit.attr,
NULL
};
ATTRIBUTE_GROUPS(mei);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index ebcd5132e447..be9c48415da9 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -210,6 +210,7 @@ struct mei_cl_cb {
* @timer_count: watchdog timer for operation completion
* @notify_en: notification - enabled/disabled
* @notify_ev: pending notification event
+ * @tx_cb_queued: number of tx callbacks in queue
* @writing_state: state of the tx
* @rd_pending: pending read credits
* @rd_completed: completed read
@@ -234,6 +235,7 @@ struct mei_cl {
u8 timer_count;
u8 notify_en;
u8 notify_ev;
+ u8 tx_cb_queued;
enum mei_file_transaction_states writing_state;
struct list_head rd_pending;
struct list_head rd_completed;
@@ -241,6 +243,10 @@ struct mei_cl {
struct mei_cl_device *cldev;
};
+#define MEI_TX_QUEUE_LIMIT_DEFAULT 50
+#define MEI_TX_QUEUE_LIMIT_MAX 255
+#define MEI_TX_QUEUE_LIMIT_MIN 30
+
/**
* struct mei_hw_ops - hw specific ops
*
@@ -315,8 +321,6 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length,
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);
-bool mei_cl_bus_module_get(struct mei_cl *cl);
-void mei_cl_bus_module_put(struct mei_cl *cl);
int mei_cl_bus_init(void);
void mei_cl_bus_exit(void);
@@ -361,6 +365,7 @@ const char *mei_pg_state_str(enum mei_pg_state state);
* @write_waiting_list : write completion list
* @ctrl_wr_list : pending control write list
* @ctrl_rd_list : pending control read list
+ * @tx_queue_limit: tx queues per client linit
*
* @file_list : list of opened handles
* @open_handle_count: number of opened handles
@@ -425,6 +430,7 @@ struct mei_device {
struct list_head write_waiting_list;
struct list_head ctrl_wr_list;
struct list_head ctrl_rd_list;
+ u8 tx_queue_limit;
struct list_head file_list;
long open_handle_count;
diff --git a/drivers/misc/mic/bus/vop_bus.c b/drivers/misc/mic/bus/vop_bus.c
index fd7f2a6049f8..e5bb9c749b5d 100644
--- a/drivers/misc/mic/bus/vop_bus.c
+++ b/drivers/misc/mic/bus/vop_bus.c
@@ -135,7 +135,9 @@ EXPORT_SYMBOL_GPL(vop_unregister_driver);
static void vop_release_dev(struct device *d)
{
- put_device(d);
+ struct vop_device *dev = dev_to_vop(d);
+
+ kfree(dev);
}
struct vop_device *
@@ -174,7 +176,7 @@ vop_register_device(struct device *pdev, int id,
goto free_vdev;
return vdev;
free_vdev:
- kfree(vdev);
+ put_device(&vdev->dev);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(vop_register_device);
diff --git a/drivers/misc/ocxl/pci.c b/drivers/misc/ocxl/pci.c
index 0051d9ec76cc..21f425472a82 100644
--- a/drivers/misc/ocxl/pci.c
+++ b/drivers/misc/ocxl/pci.c
@@ -519,7 +519,7 @@ static struct ocxl_fn *init_function(struct pci_dev *dev)
rc = device_register(&fn->dev);
if (rc) {
deconfigure_function(fn);
- device_unregister(&fn->dev);
+ put_device(&fn->dev);
return ERR_PTR(rc);
}
return fn;
diff --git a/drivers/net/dsa/b53/b53_mmap.c b/drivers/net/dsa/b53/b53_mmap.c
index ef63d24fef81..c628d0980c0b 100644
--- a/drivers/net/dsa/b53/b53_mmap.c
+++ b/drivers/net/dsa/b53/b53_mmap.c
@@ -30,7 +30,8 @@ struct b53_mmap_priv {
static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
{
- u8 __iomem *regs = dev->priv;
+ struct b53_mmap_priv *priv = dev->priv;
+ void __iomem *regs = priv->regs;
*val = readb(regs + (page << 8) + reg);
@@ -39,7 +40,8 @@ static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
{
- u8 __iomem *regs = dev->priv;
+ struct b53_mmap_priv *priv = dev->priv;
+ void __iomem *regs = priv->regs;
if (WARN_ON(reg % 2))
return -EINVAL;
@@ -54,7 +56,8 @@ static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
{
- u8 __iomem *regs = dev->priv;
+ struct b53_mmap_priv *priv = dev->priv;
+ void __iomem *regs = priv->regs;
if (WARN_ON(reg % 4))
return -EINVAL;
@@ -69,7 +72,8 @@ static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
{
- u8 __iomem *regs = dev->priv;
+ struct b53_mmap_priv *priv = dev->priv;
+ void __iomem *regs = priv->regs;
if (WARN_ON(reg % 2))
return -EINVAL;
@@ -107,7 +111,8 @@ static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
{
- u8 __iomem *regs = dev->priv;
+ struct b53_mmap_priv *priv = dev->priv;
+ void __iomem *regs = priv->regs;
u32 hi, lo;
if (WARN_ON(reg % 4))
@@ -128,7 +133,8 @@ static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
{
- u8 __iomem *regs = dev->priv;
+ struct b53_mmap_priv *priv = dev->priv;
+ void __iomem *regs = priv->regs;
writeb(value, regs + (page << 8) + reg);
@@ -138,7 +144,8 @@ static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg,
u16 value)
{
- u8 __iomem *regs = dev->priv;
+ struct b53_mmap_priv *priv = dev->priv;
+ void __iomem *regs = priv->regs;
if (WARN_ON(reg % 2))
return -EINVAL;
@@ -154,7 +161,8 @@ static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg,
static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg,
u32 value)
{
- u8 __iomem *regs = dev->priv;
+ struct b53_mmap_priv *priv = dev->priv;
+ void __iomem *regs = priv->regs;
if (WARN_ON(reg % 4))
return -EINVAL;
@@ -223,12 +231,19 @@ static const struct b53_io_ops b53_mmap_ops = {
static int b53_mmap_probe(struct platform_device *pdev)
{
struct b53_platform_data *pdata = pdev->dev.platform_data;
+ struct b53_mmap_priv *priv;
struct b53_device *dev;
if (!pdata)
return -EINVAL;
- dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs);
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regs = pdata->regs;
+
+ dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, priv);
if (!dev)
return -ENOMEM;
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index d244c41898dd..80a4dbc3a499 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -917,7 +917,7 @@ mt7530_port_fdb_add(struct dsa_switch *ds, int port,
mutex_lock(&priv->reg_mutex);
mt7530_fdb_write(priv, vid, port_mask, addr, -1, STATIC_ENT);
- ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0);
+ ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, NULL);
mutex_unlock(&priv->reg_mutex);
return ret;
@@ -933,7 +933,7 @@ mt7530_port_fdb_del(struct dsa_switch *ds, int port,
mutex_lock(&priv->reg_mutex);
mt7530_fdb_write(priv, vid, port_mask, addr, -1, STATIC_EMP);
- ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0);
+ ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, NULL);
mutex_unlock(&priv->reg_mutex);
return ret;
@@ -1293,7 +1293,7 @@ mt7530_setup(struct dsa_switch *ds)
}
/* Flush the FDB table */
- ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, 0);
+ ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
if (ret < 0)
return ret;
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 4a75b1de22e0..f9a3c1a76d5d 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -1192,7 +1192,7 @@ static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb,
u32 csum_info;
u8 ip_proto;
u16 csum_start;
- u16 ip_ver;
+ __be16 ip_ver;
/* Re-allocate SKB if needed */
if (unlikely(skb_headroom(skb) < sizeof(*tsb))) {
@@ -1211,12 +1211,12 @@ static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb,
memset(tsb, 0, sizeof(*tsb));
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- ip_ver = htons(skb->protocol);
+ ip_ver = skb->protocol;
switch (ip_ver) {
- case ETH_P_IP:
+ case htons(ETH_P_IP):
ip_proto = ip_hdr(skb)->protocol;
break;
- case ETH_P_IPV6:
+ case htons(ETH_P_IPV6):
ip_proto = ipv6_hdr(skb)->nexthdr;
break;
default:
@@ -1230,7 +1230,8 @@ static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb,
if (ip_proto == IPPROTO_TCP || ip_proto == IPPROTO_UDP) {
csum_info |= L4_LENGTH_VALID;
- if (ip_proto == IPPROTO_UDP && ip_ver == ETH_P_IP)
+ if (ip_proto == IPPROTO_UDP &&
+ ip_ver == htons(ETH_P_IP))
csum_info |= L4_UDP;
} else {
csum_info = 0;
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 264fb37dd341..0445f2c0c629 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1489,7 +1489,7 @@ static struct sk_buff *bcmgenet_put_tx_csum(struct net_device *dev,
struct sk_buff *new_skb;
u16 offset;
u8 ip_proto;
- u16 ip_ver;
+ __be16 ip_ver;
u32 tx_csum_info;
if (unlikely(skb_headroom(skb) < sizeof(*status))) {
@@ -1509,12 +1509,12 @@ static struct sk_buff *bcmgenet_put_tx_csum(struct net_device *dev,
status = (struct status_64 *)skb->data;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- ip_ver = htons(skb->protocol);
+ ip_ver = skb->protocol;
switch (ip_ver) {
- case ETH_P_IP:
+ case htons(ETH_P_IP):
ip_proto = ip_hdr(skb)->protocol;
break;
- case ETH_P_IPV6:
+ case htons(ETH_P_IPV6):
ip_proto = ipv6_hdr(skb)->nexthdr;
break;
default:
@@ -1530,7 +1530,8 @@ static struct sk_buff *bcmgenet_put_tx_csum(struct net_device *dev,
*/
if (ip_proto == IPPROTO_TCP || ip_proto == IPPROTO_UDP) {
tx_csum_info |= STATUS_TX_CSUM_LV;
- if (ip_proto == IPPROTO_UDP && ip_ver == ETH_P_IP)
+ if (ip_proto == IPPROTO_UDP &&
+ ip_ver == htons(ETH_P_IP))
tx_csum_info |= STATUS_TX_CSUM_PROTO_UDP;
} else {
tx_csum_info = 0;
diff --git a/drivers/net/ethernet/cavium/liquidio/Makefile b/drivers/net/ethernet/cavium/liquidio/Makefile
index e3fc4645cd8a..bc9937502043 100644
--- a/drivers/net/ethernet/cavium/liquidio/Makefile
+++ b/drivers/net/ethernet/cavium/liquidio/Makefile
@@ -2,42 +2,23 @@
#
# Cavium Liquidio ethernet device driver
#
-obj-$(CONFIG_LIQUIDIO) += liquidio.o
-liquidio-$(CONFIG_LIQUIDIO) += lio_ethtool.o \
- lio_core.o \
- request_manager.o \
- response_manager.o \
- octeon_device.o \
- cn66xx_device.o \
- cn68xx_device.o \
- cn23xx_pf_device.o \
- cn23xx_vf_device.o \
- octeon_mailbox.o \
- octeon_mem_ops.o \
- octeon_droq.o \
- octeon_nic.o
+common-objs := lio_ethtool.o \
+ lio_core.o \
+ request_manager.o \
+ response_manager.o \
+ octeon_device.o \
+ cn66xx_device.o \
+ cn68xx_device.o \
+ cn23xx_pf_device.o \
+ cn23xx_vf_device.o \
+ octeon_mailbox.o \
+ octeon_mem_ops.o \
+ octeon_droq.o \
+ octeon_nic.o
-liquidio-objs := lio_main.o octeon_console.o lio_vf_rep.o $(liquidio-y)
+obj-$(CONFIG_LIQUIDIO) += liquidio.o
+liquidio-y := lio_main.o octeon_console.o lio_vf_rep.o $(common-objs)
obj-$(CONFIG_LIQUIDIO_VF) += liquidio_vf.o
-
-ifeq ($(CONFIG_LIQUIDIO)$(CONFIG_LIQUIDIO_VF), yy)
- liquidio_vf-objs := lio_vf_main.o
-else
-liquidio_vf-$(CONFIG_LIQUIDIO_VF) += lio_ethtool.o \
- lio_core.o \
- request_manager.o \
- response_manager.o \
- octeon_device.o \
- cn66xx_device.o \
- cn68xx_device.o \
- cn23xx_pf_device.o \
- cn23xx_vf_device.o \
- octeon_mailbox.o \
- octeon_mem_ops.o \
- octeon_droq.o \
- octeon_nic.o
-
-liquidio_vf-objs := lio_vf_main.o $(liquidio_vf-y)
-endif
+liquidio_vf-y := lio_vf_main.o $(common-objs)
diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
index 80ad16acf0f1..ac2c3f6a12bc 100644
--- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c
+++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
@@ -377,6 +377,38 @@ static const struct of_device_id fsl_pq_mdio_match[] = {
};
MODULE_DEVICE_TABLE(of, fsl_pq_mdio_match);
+static void set_tbipa(const u32 tbipa_val, struct platform_device *pdev,
+ uint32_t __iomem * (*get_tbipa)(void __iomem *),
+ void __iomem *reg_map, struct resource *reg_res)
+{
+ struct device_node *np = pdev->dev.of_node;
+ uint32_t __iomem *tbipa;
+ bool tbipa_mapped;
+
+ tbipa = of_iomap(np, 1);
+ if (tbipa) {
+ tbipa_mapped = true;
+ } else {
+ tbipa_mapped = false;
+ tbipa = (*get_tbipa)(reg_map);
+
+ /*
+ * Add consistency check to make sure TBI is contained within
+ * the mapped range (not because we would get a segfault,
+ * rather to catch bugs in computing TBI address). Print error
+ * message but continue anyway.
+ */
+ if ((void *)tbipa > reg_map + resource_size(reg_res) - 4)
+ dev_err(&pdev->dev, "invalid register map (should be at least 0x%04zx to contain TBI address)\n",
+ ((void *)tbipa - reg_map) + 4);
+ }
+
+ iowrite32be(be32_to_cpu(tbipa_val), tbipa);
+
+ if (tbipa_mapped)
+ iounmap(tbipa);
+}
+
static int fsl_pq_mdio_probe(struct platform_device *pdev)
{
const struct of_device_id *id =
@@ -450,8 +482,6 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev)
if (tbi) {
const u32 *prop = of_get_property(tbi, "reg", NULL);
- uint32_t __iomem *tbipa;
-
if (!prop) {
dev_err(&pdev->dev,
"missing 'reg' property in node %pOF\n",
@@ -459,20 +489,8 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev)
err = -EBUSY;
goto error;
}
-
- tbipa = data->get_tbipa(priv->map);
-
- /*
- * Add consistency check to make sure TBI is contained
- * within the mapped range (not because we would get a
- * segfault, rather to catch bugs in computing TBI
- * address). Print error message but continue anyway.
- */
- if ((void *)tbipa > priv->map + resource_size(&res) - 4)
- dev_err(&pdev->dev, "invalid register map (should be at least 0x%04zx to contain TBI address)\n",
- ((void *)tbipa - priv->map) + 4);
-
- iowrite32be(be32_to_cpup(prop), tbipa);
+ set_tbipa(*prop, pdev,
+ data->get_tbipa, priv->map, &res);
}
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
index 9e4cfbbf8dcd..98cdbd3a1163 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
@@ -288,7 +288,7 @@ struct hns3_desc_cb {
u16 page_offset;
u16 reuse_flag;
- u16 length; /* length of the buffer */
+ u32 length; /* length of the buffer */
/* desc type, used by the ring user to mark the type of the priv data */
u16 type;
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index b492af6affc3..aad5658d79d5 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -118,6 +118,7 @@ static int init_sub_crq_irqs(struct ibmvnic_adapter *adapter);
static int ibmvnic_init(struct ibmvnic_adapter *);
static void release_crq_queue(struct ibmvnic_adapter *);
static int __ibmvnic_set_mac(struct net_device *netdev, struct sockaddr *p);
+static int init_crq_queue(struct ibmvnic_adapter *adapter);
struct ibmvnic_stat {
char name[ETH_GSTRING_LEN];
@@ -320,18 +321,16 @@ failure:
dev_info(dev, "replenish pools failure\n");
pool->free_map[pool->next_free] = index;
pool->rx_buff[index].skb = NULL;
- if (!dma_mapping_error(dev, dma_addr))
- dma_unmap_single(dev, dma_addr, pool->buff_size,
- DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
adapter->replenish_add_buff_failure++;
atomic_add(buffers_added, &pool->available);
- if (lpar_rc == H_CLOSED) {
+ if (lpar_rc == H_CLOSED || adapter->failover_pending) {
/* Disable buffer pool replenishment and report carrier off if
- * queue is closed. Firmware guarantees that a signal will
- * be sent to the driver, triggering a reset.
+ * queue is closed or pending failover.
+ * Firmware guarantees that a signal will be sent to the
+ * driver, triggering a reset.
*/
deactivate_rx_pools(adapter);
netif_carrier_off(adapter->netdev);
@@ -1071,6 +1070,14 @@ static int ibmvnic_open(struct net_device *netdev)
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
int rc;
+ /* If device failover is pending, just set device state and return.
+ * Device operation will be handled by reset routine.
+ */
+ if (adapter->failover_pending) {
+ adapter->state = VNIC_OPEN;
+ return 0;
+ }
+
mutex_lock(&adapter->reset_lock);
if (adapter->state != VNIC_CLOSED) {
@@ -1218,7 +1225,6 @@ static int __ibmvnic_close(struct net_device *netdev)
rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_DN);
if (rc)
return rc;
- ibmvnic_cleanup(netdev);
adapter->state = VNIC_CLOSED;
return 0;
}
@@ -1228,8 +1234,17 @@ static int ibmvnic_close(struct net_device *netdev)
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
int rc;
+ /* If device failover is pending, just set device state and return.
+ * Device operation will be handled by reset routine.
+ */
+ if (adapter->failover_pending) {
+ adapter->state = VNIC_CLOSED;
+ return 0;
+ }
+
mutex_lock(&adapter->reset_lock);
rc = __ibmvnic_close(netdev);
+ ibmvnic_cleanup(netdev);
mutex_unlock(&adapter->reset_lock);
return rc;
@@ -1562,8 +1577,9 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
dev_kfree_skb_any(skb);
tx_buff->skb = NULL;
- if (lpar_rc == H_CLOSED) {
- /* Disable TX and report carrier off if queue is closed.
+ if (lpar_rc == H_CLOSED || adapter->failover_pending) {
+ /* Disable TX and report carrier off if queue is closed
+ * or pending failover.
* Firmware guarantees that a signal will be sent to the
* driver, triggering a reset or some other action.
*/
@@ -1711,14 +1727,10 @@ static int do_reset(struct ibmvnic_adapter *adapter,
old_num_rx_queues = adapter->req_rx_queues;
old_num_tx_queues = adapter->req_tx_queues;
- if (rwi->reset_reason == VNIC_RESET_MOBILITY) {
- rc = ibmvnic_reenable_crq_queue(adapter);
- if (rc)
- return 0;
- ibmvnic_cleanup(netdev);
- } else if (rwi->reset_reason == VNIC_RESET_FAILOVER) {
- ibmvnic_cleanup(netdev);
- } else {
+ ibmvnic_cleanup(netdev);
+
+ if (adapter->reset_reason != VNIC_RESET_MOBILITY &&
+ adapter->reset_reason != VNIC_RESET_FAILOVER) {
rc = __ibmvnic_close(netdev);
if (rc)
return rc;
@@ -1737,6 +1749,23 @@ static int do_reset(struct ibmvnic_adapter *adapter,
*/
adapter->state = VNIC_PROBED;
+ if (adapter->wait_for_reset) {
+ rc = init_crq_queue(adapter);
+ } else if (adapter->reset_reason == VNIC_RESET_MOBILITY) {
+ rc = ibmvnic_reenable_crq_queue(adapter);
+ release_sub_crqs(adapter, 1);
+ } else {
+ rc = ibmvnic_reset_crq(adapter);
+ if (!rc)
+ rc = vio_enable_interrupts(adapter->vdev);
+ }
+
+ if (rc) {
+ netdev_err(adapter->netdev,
+ "Couldn't initialize crq. rc=%d\n", rc);
+ return rc;
+ }
+
rc = ibmvnic_init(adapter);
if (rc)
return IBMVNIC_INIT_FAILED;
@@ -1878,23 +1907,26 @@ static void __ibmvnic_reset(struct work_struct *work)
mutex_unlock(&adapter->reset_lock);
}
-static void ibmvnic_reset(struct ibmvnic_adapter *adapter,
- enum ibmvnic_reset_reason reason)
+static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
+ enum ibmvnic_reset_reason reason)
{
struct ibmvnic_rwi *rwi, *tmp;
struct net_device *netdev = adapter->netdev;
struct list_head *entry;
+ int ret;
if (adapter->state == VNIC_REMOVING ||
- adapter->state == VNIC_REMOVED) {
- netdev_dbg(netdev, "Adapter removing, skipping reset\n");
- return;
+ adapter->state == VNIC_REMOVED ||
+ adapter->failover_pending) {
+ ret = EBUSY;
+ netdev_dbg(netdev, "Adapter removing or pending failover, skipping reset\n");
+ goto err;
}
if (adapter->state == VNIC_PROBING) {
netdev_warn(netdev, "Adapter reset during probe\n");
- adapter->init_done_rc = EAGAIN;
- return;
+ ret = adapter->init_done_rc = EAGAIN;
+ goto err;
}
mutex_lock(&adapter->rwi_lock);
@@ -1904,7 +1936,8 @@ static void ibmvnic_reset(struct ibmvnic_adapter *adapter,
if (tmp->reset_reason == reason) {
netdev_dbg(netdev, "Skipping matching reset\n");
mutex_unlock(&adapter->rwi_lock);
- return;
+ ret = EBUSY;
+ goto err;
}
}
@@ -1912,7 +1945,8 @@ static void ibmvnic_reset(struct ibmvnic_adapter *adapter,
if (!rwi) {
mutex_unlock(&adapter->rwi_lock);
ibmvnic_close(netdev);
- return;
+ ret = ENOMEM;
+ goto err;
}
rwi->reset_reason = reason;
@@ -1921,6 +1955,12 @@ static void ibmvnic_reset(struct ibmvnic_adapter *adapter,
netdev_dbg(adapter->netdev, "Scheduling reset (reason %d)\n", reason);
schedule_work(&adapter->ibmvnic_reset);
+
+ return 0;
+err:
+ if (adapter->wait_for_reset)
+ adapter->wait_for_reset = false;
+ return -ret;
}
static void ibmvnic_tx_timeout(struct net_device *dev)
@@ -2055,6 +2095,8 @@ static void ibmvnic_netpoll_controller(struct net_device *dev)
static int wait_for_reset(struct ibmvnic_adapter *adapter)
{
+ int rc, ret;
+
adapter->fallback.mtu = adapter->req_mtu;
adapter->fallback.rx_queues = adapter->req_rx_queues;
adapter->fallback.tx_queues = adapter->req_tx_queues;
@@ -2062,11 +2104,15 @@ static int wait_for_reset(struct ibmvnic_adapter *adapter)
adapter->fallback.tx_entries = adapter->req_tx_entries_per_subcrq;
init_completion(&adapter->reset_done);
- ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM);
adapter->wait_for_reset = true;
+ rc = ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM);
+ if (rc)
+ return rc;
wait_for_completion(&adapter->reset_done);
+ ret = 0;
if (adapter->reset_done_rc) {
+ ret = -EIO;
adapter->desired.mtu = adapter->fallback.mtu;
adapter->desired.rx_queues = adapter->fallback.rx_queues;
adapter->desired.tx_queues = adapter->fallback.tx_queues;
@@ -2074,12 +2120,15 @@ static int wait_for_reset(struct ibmvnic_adapter *adapter)
adapter->desired.tx_entries = adapter->fallback.tx_entries;
init_completion(&adapter->reset_done);
- ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM);
+ adapter->wait_for_reset = true;
+ rc = ibmvnic_reset(adapter, VNIC_RESET_CHANGE_PARAM);
+ if (rc)
+ return ret;
wait_for_completion(&adapter->reset_done);
}
adapter->wait_for_reset = false;
- return adapter->reset_done_rc;
+ return ret;
}
static int ibmvnic_change_mtu(struct net_device *netdev, int new_mtu)
@@ -2364,6 +2413,7 @@ static int reset_one_sub_crq_queue(struct ibmvnic_adapter *adapter,
}
memset(scrq->msgs, 0, 4 * PAGE_SIZE);
+ atomic_set(&scrq->used, 0);
scrq->cur = 0;
rc = h_reg_sub_crq(adapter->vdev->unit_address, scrq->msg_token,
@@ -2574,7 +2624,7 @@ static int ibmvnic_complete_tx(struct ibmvnic_adapter *adapter,
union sub_crq *next;
int index;
int i, j;
- u8 first;
+ u8 *first;
restart_loop:
while (pending_scrq(adapter, scrq)) {
@@ -2605,11 +2655,12 @@ restart_loop:
txbuff->data_dma[j] = 0;
}
/* if sub_crq was sent indirectly */
- first = txbuff->indir_arr[0].generic.first;
- if (first == IBMVNIC_CRQ_CMD) {
+ first = &txbuff->indir_arr[0].generic.first;
+ if (*first == IBMVNIC_CRQ_CMD) {
dma_unmap_single(dev, txbuff->indir_dma,
sizeof(txbuff->indir_arr),
DMA_TO_DEVICE);
+ *first = 0;
}
if (txbuff->last_frag) {
@@ -3882,9 +3933,9 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
int i;
dma_unmap_single(dev, adapter->login_buf_token, adapter->login_buf_sz,
- DMA_BIDIRECTIONAL);
+ DMA_TO_DEVICE);
dma_unmap_single(dev, adapter->login_rsp_buf_token,
- adapter->login_rsp_buf_sz, DMA_BIDIRECTIONAL);
+ adapter->login_rsp_buf_sz, DMA_FROM_DEVICE);
/* If the number of queues requested can't be allocated by the
* server, the login response will return with code 1. We will need
@@ -4144,7 +4195,9 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
case IBMVNIC_CRQ_INIT:
dev_info(dev, "Partner initialized\n");
adapter->from_passive_init = true;
+ adapter->failover_pending = false;
complete(&adapter->init_done);
+ ibmvnic_reset(adapter, VNIC_RESET_FAILOVER);
break;
case IBMVNIC_CRQ_INIT_COMPLETE:
dev_info(dev, "Partner initialization complete\n");
@@ -4161,7 +4214,7 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
ibmvnic_reset(adapter, VNIC_RESET_MOBILITY);
} else if (gen_crq->cmd == IBMVNIC_DEVICE_FAILOVER) {
dev_info(dev, "Backing device failover detected\n");
- ibmvnic_reset(adapter, VNIC_RESET_FAILOVER);
+ adapter->failover_pending = true;
} else {
/* The adapter lost the connection */
dev_err(dev, "Virtual Adapter failed (rc=%d)\n",
@@ -4461,19 +4514,6 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter)
u64 old_num_rx_queues, old_num_tx_queues;
int rc;
- if (adapter->resetting && !adapter->wait_for_reset) {
- rc = ibmvnic_reset_crq(adapter);
- if (!rc)
- rc = vio_enable_interrupts(adapter->vdev);
- } else {
- rc = init_crq_queue(adapter);
- }
-
- if (rc) {
- dev_err(dev, "Couldn't initialize crq. rc=%d\n", rc);
- return rc;
- }
-
adapter->from_passive_init = false;
old_num_rx_queues = adapter->req_rx_queues;
@@ -4498,7 +4538,8 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter)
return -1;
}
- if (adapter->resetting && !adapter->wait_for_reset) {
+ if (adapter->resetting && !adapter->wait_for_reset &&
+ adapter->reset_reason != VNIC_RESET_MOBILITY) {
if (adapter->req_rx_queues != old_num_rx_queues ||
adapter->req_tx_queues != old_num_tx_queues) {
release_sub_crqs(adapter, 0);
@@ -4586,6 +4627,13 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
adapter->mac_change_pending = false;
do {
+ rc = init_crq_queue(adapter);
+ if (rc) {
+ dev_err(&dev->dev, "Couldn't initialize crq. rc=%d\n",
+ rc);
+ goto ibmvnic_init_fail;
+ }
+
rc = ibmvnic_init(adapter);
if (rc && rc != EAGAIN)
goto ibmvnic_init_fail;
diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
index 89efe700eafe..99c0b58c2c39 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.h
+++ b/drivers/net/ethernet/ibm/ibmvnic.h
@@ -1108,6 +1108,7 @@ struct ibmvnic_adapter {
bool napi_enabled, from_passive_init;
bool mac_change_pending;
+ bool failover_pending;
struct ibmvnic_tunables desired;
struct ibmvnic_tunables fallback;
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index 385f5d425d19..21977ec984c4 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -468,8 +468,10 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
mac_buf_len = sizeof(struct ice_aqc_manage_mac_read_resp);
mac_buf = devm_kzalloc(ice_hw_to_dev(hw), mac_buf_len, GFP_KERNEL);
- if (!mac_buf)
+ if (!mac_buf) {
+ status = ICE_ERR_NO_MEMORY;
goto err_unroll_fltr_mgmt_struct;
+ }
status = ice_aq_manage_mac_read(hw, mac_buf, mac_buf_len, NULL);
devm_kfree(ice_hw_to_dev(hw), mac_buf);
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 186764a5c263..1db304c01d10 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -156,7 +156,7 @@ ice_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
static int ice_get_regs_len(struct net_device __always_unused *netdev)
{
- return ARRAY_SIZE(ice_regs_dump_list);
+ return sizeof(ice_regs_dump_list);
}
static void
@@ -170,7 +170,7 @@ ice_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
regs->version = 1;
- for (i = 0; i < ARRAY_SIZE(ice_regs_dump_list) / sizeof(u32); ++i)
+ for (i = 0; i < ARRAY_SIZE(ice_regs_dump_list); ++i)
regs_buf[i] = rd32(hw, ice_regs_dump_list[i]);
}
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 7fc1bbf51c44..54a038943c06 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -1604,7 +1604,7 @@ static int mvpp2_prs_init_from_hw(struct mvpp2 *priv,
{
int i;
- if (pe->index > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
+ if (tid > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
return -EINVAL;
memset(pe, 0, sizeof(*pe));
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 53fffd09d133..ca38a30fbe91 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -3805,18 +3805,6 @@ static const struct mlxsw_config_profile mlxsw_sp_config_profile = {
},
};
-static u64 mlxsw_sp_resource_kvd_linear_occ_get(struct devlink *devlink)
-{
- struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
- struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
-
- return mlxsw_sp_kvdl_occ_get(mlxsw_sp);
-}
-
-static const struct devlink_resource_ops mlxsw_sp_resource_kvd_linear_ops = {
- .occ_get = mlxsw_sp_resource_kvd_linear_occ_get,
-};
-
static void
mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core,
struct devlink_resource_size_params *kvd_size_params,
@@ -3877,8 +3865,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core)
err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD,
kvd_size, MLXSW_SP_RESOURCE_KVD,
DEVLINK_RESOURCE_ID_PARENT_TOP,
- &kvd_size_params,
- NULL);
+ &kvd_size_params);
if (err)
return err;
@@ -3887,8 +3874,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core)
linear_size,
MLXSW_SP_RESOURCE_KVD_LINEAR,
MLXSW_SP_RESOURCE_KVD,
- &linear_size_params,
- &mlxsw_sp_resource_kvd_linear_ops);
+ &linear_size_params);
if (err)
return err;
@@ -3905,8 +3891,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core)
double_size,
MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
MLXSW_SP_RESOURCE_KVD,
- &hash_double_size_params,
- NULL);
+ &hash_double_size_params);
if (err)
return err;
@@ -3915,8 +3900,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core)
single_size,
MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
MLXSW_SP_RESOURCE_KVD,
- &hash_single_size_params,
- NULL);
+ &hash_single_size_params);
if (err)
return err;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 82820ba43728..804d4d2c8031 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -442,7 +442,6 @@ void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp, int entry_index);
int mlxsw_sp_kvdl_alloc_size_query(struct mlxsw_sp *mlxsw_sp,
unsigned int entry_count,
unsigned int *p_alloc_size);
-u64 mlxsw_sp_kvdl_occ_get(const struct mlxsw_sp *mlxsw_sp);
int mlxsw_sp_kvdl_resources_register(struct mlxsw_core *mlxsw_core);
struct mlxsw_sp_acl_rule_info {
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c
index 8796db44dcc3..fe4327f547d2 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_kvdl.c
@@ -315,8 +315,9 @@ static u64 mlxsw_sp_kvdl_part_occ(struct mlxsw_sp_kvdl_part *part)
return occ;
}
-u64 mlxsw_sp_kvdl_occ_get(const struct mlxsw_sp *mlxsw_sp)
+static u64 mlxsw_sp_kvdl_occ_get(void *priv)
{
+ const struct mlxsw_sp *mlxsw_sp = priv;
u64 occ = 0;
int i;
@@ -326,48 +327,33 @@ u64 mlxsw_sp_kvdl_occ_get(const struct mlxsw_sp *mlxsw_sp)
return occ;
}
-static u64 mlxsw_sp_kvdl_single_occ_get(struct devlink *devlink)
+static u64 mlxsw_sp_kvdl_single_occ_get(void *priv)
{
- struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
- struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
+ const struct mlxsw_sp *mlxsw_sp = priv;
struct mlxsw_sp_kvdl_part *part;
part = mlxsw_sp->kvdl->parts[MLXSW_SP_KVDL_PART_ID_SINGLE];
return mlxsw_sp_kvdl_part_occ(part);
}
-static u64 mlxsw_sp_kvdl_chunks_occ_get(struct devlink *devlink)
+static u64 mlxsw_sp_kvdl_chunks_occ_get(void *priv)
{
- struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
- struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
+ const struct mlxsw_sp *mlxsw_sp = priv;
struct mlxsw_sp_kvdl_part *part;
part = mlxsw_sp->kvdl->parts[MLXSW_SP_KVDL_PART_ID_CHUNKS];
return mlxsw_sp_kvdl_part_occ(part);
}
-static u64 mlxsw_sp_kvdl_large_chunks_occ_get(struct devlink *devlink)
+static u64 mlxsw_sp_kvdl_large_chunks_occ_get(void *priv)
{
- struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
- struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
+ const struct mlxsw_sp *mlxsw_sp = priv;
struct mlxsw_sp_kvdl_part *part;
part = mlxsw_sp->kvdl->parts[MLXSW_SP_KVDL_PART_ID_LARGE_CHUNKS];
return mlxsw_sp_kvdl_part_occ(part);
}
-static const struct devlink_resource_ops mlxsw_sp_kvdl_single_ops = {
- .occ_get = mlxsw_sp_kvdl_single_occ_get,
-};
-
-static const struct devlink_resource_ops mlxsw_sp_kvdl_chunks_ops = {
- .occ_get = mlxsw_sp_kvdl_chunks_occ_get,
-};
-
-static const struct devlink_resource_ops mlxsw_sp_kvdl_chunks_large_ops = {
- .occ_get = mlxsw_sp_kvdl_large_chunks_occ_get,
-};
-
int mlxsw_sp_kvdl_resources_register(struct mlxsw_core *mlxsw_core)
{
struct devlink *devlink = priv_to_devlink(mlxsw_core);
@@ -386,8 +372,7 @@ int mlxsw_sp_kvdl_resources_register(struct mlxsw_core *mlxsw_core)
MLXSW_SP_KVDL_SINGLE_SIZE,
MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE,
MLXSW_SP_RESOURCE_KVD_LINEAR,
- &size_params,
- &mlxsw_sp_kvdl_single_ops);
+ &size_params);
if (err)
return err;
@@ -398,8 +383,7 @@ int mlxsw_sp_kvdl_resources_register(struct mlxsw_core *mlxsw_core)
MLXSW_SP_KVDL_CHUNKS_SIZE,
MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS,
MLXSW_SP_RESOURCE_KVD_LINEAR,
- &size_params,
- &mlxsw_sp_kvdl_chunks_ops);
+ &size_params);
if (err)
return err;
@@ -410,13 +394,13 @@ int mlxsw_sp_kvdl_resources_register(struct mlxsw_core *mlxsw_core)
MLXSW_SP_KVDL_LARGE_CHUNKS_SIZE,
MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS,
MLXSW_SP_RESOURCE_KVD_LINEAR,
- &size_params,
- &mlxsw_sp_kvdl_chunks_large_ops);
+ &size_params);
return err;
}
int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp)
{
+ struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
struct mlxsw_sp_kvdl *kvdl;
int err;
@@ -429,6 +413,23 @@ int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp)
if (err)
goto err_kvdl_parts_init;
+ devlink_resource_occ_get_register(devlink,
+ MLXSW_SP_RESOURCE_KVD_LINEAR,
+ mlxsw_sp_kvdl_occ_get,
+ mlxsw_sp);
+ devlink_resource_occ_get_register(devlink,
+ MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE,
+ mlxsw_sp_kvdl_single_occ_get,
+ mlxsw_sp);
+ devlink_resource_occ_get_register(devlink,
+ MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS,
+ mlxsw_sp_kvdl_chunks_occ_get,
+ mlxsw_sp);
+ devlink_resource_occ_get_register(devlink,
+ MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS,
+ mlxsw_sp_kvdl_large_chunks_occ_get,
+ mlxsw_sp);
+
return 0;
err_kvdl_parts_init:
@@ -438,6 +439,16 @@ err_kvdl_parts_init:
void mlxsw_sp_kvdl_fini(struct mlxsw_sp *mlxsw_sp)
{
+ struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
+
+ devlink_resource_occ_get_unregister(devlink,
+ MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS);
+ devlink_resource_occ_get_unregister(devlink,
+ MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS);
+ devlink_resource_occ_get_unregister(devlink,
+ MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE);
+ devlink_resource_occ_get_unregister(devlink,
+ MLXSW_SP_RESOURCE_KVD_LINEAR);
mlxsw_sp_kvdl_parts_fini(mlxsw_sp);
kfree(mlxsw_sp->kvdl);
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h
index 787df47ec430..bd7d8ae31e17 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h
@@ -391,6 +391,7 @@ struct nfp_net_rx_ring {
* @rx_drops: Number of packets dropped on RX due to lack of resources
* @hw_csum_rx_ok: Counter of packets where the HW checksum was OK
* @hw_csum_rx_inner_ok: Counter of packets where the inner HW checksum was OK
+ * @hw_csum_rx_complete: Counter of packets with CHECKSUM_COMPLETE reported
* @hw_csum_rx_error: Counter of packets with bad checksums
* @tx_sync: Seqlock for atomic updates of TX stats
* @tx_pkts: Number of Transmitted packets
@@ -434,7 +435,7 @@ struct nfp_net_r_vector {
u64 rx_drops;
u64 hw_csum_rx_ok;
u64 hw_csum_rx_inner_ok;
- u64 hw_csum_rx_error;
+ u64 hw_csum_rx_complete;
struct nfp_net_tx_ring *xdp_ring;
@@ -446,6 +447,7 @@ struct nfp_net_r_vector {
u64 tx_gather;
u64 tx_lso;
+ u64 hw_csum_rx_error;
u64 rx_replace_buf_alloc_fail;
u64 tx_errors;
u64 tx_busy;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index 43a9c207a049..1eb6549f2a54 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -1406,7 +1406,7 @@ static void nfp_net_rx_csum(struct nfp_net_dp *dp,
skb->ip_summed = meta->csum_type;
skb->csum = meta->csum;
u64_stats_update_begin(&r_vec->rx_sync);
- r_vec->hw_csum_rx_ok++;
+ r_vec->hw_csum_rx_complete++;
u64_stats_update_end(&r_vec->rx_sync);
return;
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
index e1dae0616f52..c9016419bfa0 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
@@ -179,7 +179,7 @@ static const struct nfp_et_stat nfp_mac_et_stats[] = {
#define NN_ET_GLOBAL_STATS_LEN ARRAY_SIZE(nfp_net_et_stats)
#define NN_ET_SWITCH_STATS_LEN 9
-#define NN_RVEC_GATHER_STATS 8
+#define NN_RVEC_GATHER_STATS 9
#define NN_RVEC_PER_Q_STATS 3
static void nfp_net_get_nspinfo(struct nfp_app *app, char *version)
@@ -468,6 +468,7 @@ static u8 *nfp_vnic_get_sw_stats_strings(struct net_device *netdev, u8 *data)
data = nfp_pr_et(data, "hw_rx_csum_ok");
data = nfp_pr_et(data, "hw_rx_csum_inner_ok");
+ data = nfp_pr_et(data, "hw_rx_csum_complete");
data = nfp_pr_et(data, "hw_rx_csum_err");
data = nfp_pr_et(data, "rx_replace_buf_alloc_fail");
data = nfp_pr_et(data, "hw_tx_csum");
@@ -493,18 +494,19 @@ static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data)
data[0] = nn->r_vecs[i].rx_pkts;
tmp[0] = nn->r_vecs[i].hw_csum_rx_ok;
tmp[1] = nn->r_vecs[i].hw_csum_rx_inner_ok;
- tmp[2] = nn->r_vecs[i].hw_csum_rx_error;
- tmp[3] = nn->r_vecs[i].rx_replace_buf_alloc_fail;
+ tmp[2] = nn->r_vecs[i].hw_csum_rx_complete;
+ tmp[3] = nn->r_vecs[i].hw_csum_rx_error;
+ tmp[4] = nn->r_vecs[i].rx_replace_buf_alloc_fail;
} while (u64_stats_fetch_retry(&nn->r_vecs[i].rx_sync, start));
do {
start = u64_stats_fetch_begin(&nn->r_vecs[i].tx_sync);
data[1] = nn->r_vecs[i].tx_pkts;
data[2] = nn->r_vecs[i].tx_busy;
- tmp[4] = nn->r_vecs[i].hw_csum_tx;
- tmp[5] = nn->r_vecs[i].hw_csum_tx_inner;
- tmp[6] = nn->r_vecs[i].tx_gather;
- tmp[7] = nn->r_vecs[i].tx_lso;
+ tmp[5] = nn->r_vecs[i].hw_csum_tx;
+ tmp[6] = nn->r_vecs[i].hw_csum_tx_inner;
+ tmp[7] = nn->r_vecs[i].tx_gather;
+ tmp[8] = nn->r_vecs[i].tx_lso;
} while (u64_stats_fetch_retry(&nn->r_vecs[i].tx_sync, start));
data += NN_RVEC_PER_Q_STATS;
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
index 39abac678b71..99bb679a9801 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c
@@ -71,10 +71,11 @@
/* CPP address to retrieve the data from */
#define NSP_BUFFER 0x10
#define NSP_BUFFER_CPP GENMASK_ULL(63, 40)
-#define NSP_BUFFER_PCIE GENMASK_ULL(39, 38)
-#define NSP_BUFFER_ADDRESS GENMASK_ULL(37, 0)
+#define NSP_BUFFER_ADDRESS GENMASK_ULL(39, 0)
#define NSP_DFLT_BUFFER 0x18
+#define NSP_DFLT_BUFFER_CPP GENMASK_ULL(63, 40)
+#define NSP_DFLT_BUFFER_ADDRESS GENMASK_ULL(39, 0)
#define NSP_DFLT_BUFFER_CONFIG 0x20
#define NSP_DFLT_BUFFER_SIZE_MB GENMASK_ULL(7, 0)
@@ -427,8 +428,8 @@ __nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option,
if (err < 0)
return err;
- cpp_id = FIELD_GET(NSP_BUFFER_CPP, reg) << 8;
- cpp_buf = FIELD_GET(NSP_BUFFER_ADDRESS, reg);
+ cpp_id = FIELD_GET(NSP_DFLT_BUFFER_CPP, reg) << 8;
+ cpp_buf = FIELD_GET(NSP_DFLT_BUFFER_ADDRESS, reg);
if (in_buf && in_size) {
err = nfp_cpp_write(cpp, cpp_id, cpp_buf, in_buf, in_size);
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index c4c45c94da77..50daad0a1482 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -1666,7 +1666,6 @@ static const struct efx_hw_stat_desc efx_ef10_stat_desc[EF10_STAT_COUNT] = {
EF10_DMA_STAT(fec_corrected_symbols_lane1, FEC_CORRECTED_SYMBOLS_LANE1),
EF10_DMA_STAT(fec_corrected_symbols_lane2, FEC_CORRECTED_SYMBOLS_LANE2),
EF10_DMA_STAT(fec_corrected_symbols_lane3, FEC_CORRECTED_SYMBOLS_LANE3),
- EF10_DMA_STAT(ctpio_dmabuf_start, CTPIO_DMABUF_START),
EF10_DMA_STAT(ctpio_vi_busy_fallback, CTPIO_VI_BUSY_FALLBACK),
EF10_DMA_STAT(ctpio_long_write_success, CTPIO_LONG_WRITE_SUCCESS),
EF10_DMA_STAT(ctpio_missing_dbell_fail, CTPIO_MISSING_DBELL_FAIL),
@@ -1777,7 +1776,6 @@ static const struct efx_hw_stat_desc efx_ef10_stat_desc[EF10_STAT_COUNT] = {
* These bits are in the second u64 of the raw mask.
*/
#define EF10_CTPIO_STAT_MASK ( \
- (1ULL << (EF10_STAT_ctpio_dmabuf_start - 64)) | \
(1ULL << (EF10_STAT_ctpio_vi_busy_fallback - 64)) | \
(1ULL << (EF10_STAT_ctpio_long_write_success - 64)) | \
(1ULL << (EF10_STAT_ctpio_missing_dbell_fail - 64)) | \
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h
index 5640034bda10..5cca0556b47f 100644
--- a/drivers/net/ethernet/sfc/nic.h
+++ b/drivers/net/ethernet/sfc/nic.h
@@ -332,7 +332,6 @@ enum {
EF10_STAT_fec_corrected_symbols_lane1,
EF10_STAT_fec_corrected_symbols_lane2,
EF10_STAT_fec_corrected_symbols_lane3,
- EF10_STAT_ctpio_dmabuf_start,
EF10_STAT_ctpio_vi_busy_fallback,
EF10_STAT_ctpio_long_write_success,
EF10_STAT_ctpio_missing_dbell_fail,
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index c9910c33e671..04f611e6f678 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -109,11 +109,11 @@ static void free_netvsc_device_rcu(struct netvsc_device *nvdev)
call_rcu(&nvdev->rcu, free_netvsc_device);
}
-static void netvsc_revoke_buf(struct hv_device *device,
- struct netvsc_device *net_device)
+static void netvsc_revoke_recv_buf(struct hv_device *device,
+ struct netvsc_device *net_device,
+ struct net_device *ndev)
{
struct nvsp_message *revoke_packet;
- struct net_device *ndev = hv_get_drvdata(device);
int ret;
/*
@@ -157,6 +157,14 @@ static void netvsc_revoke_buf(struct hv_device *device,
}
net_device->recv_section_cnt = 0;
}
+}
+
+static void netvsc_revoke_send_buf(struct hv_device *device,
+ struct netvsc_device *net_device,
+ struct net_device *ndev)
+{
+ struct nvsp_message *revoke_packet;
+ int ret;
/* Deal with the send buffer we may have setup.
* If we got a send section size, it means we received a
@@ -202,10 +210,10 @@ static void netvsc_revoke_buf(struct hv_device *device,
}
}
-static void netvsc_teardown_gpadl(struct hv_device *device,
- struct netvsc_device *net_device)
+static void netvsc_teardown_recv_gpadl(struct hv_device *device,
+ struct netvsc_device *net_device,
+ struct net_device *ndev)
{
- struct net_device *ndev = hv_get_drvdata(device);
int ret;
if (net_device->recv_buf_gpadl_handle) {
@@ -222,6 +230,13 @@ static void netvsc_teardown_gpadl(struct hv_device *device,
}
net_device->recv_buf_gpadl_handle = 0;
}
+}
+
+static void netvsc_teardown_send_gpadl(struct hv_device *device,
+ struct netvsc_device *net_device,
+ struct net_device *ndev)
+{
+ int ret;
if (net_device->send_buf_gpadl_handle) {
ret = vmbus_teardown_gpadl(device->channel,
@@ -437,8 +452,10 @@ static int netvsc_init_buf(struct hv_device *device,
goto exit;
cleanup:
- netvsc_revoke_buf(device, net_device);
- netvsc_teardown_gpadl(device, net_device);
+ netvsc_revoke_recv_buf(device, net_device, ndev);
+ netvsc_revoke_send_buf(device, net_device, ndev);
+ netvsc_teardown_recv_gpadl(device, net_device, ndev);
+ netvsc_teardown_send_gpadl(device, net_device, ndev);
exit:
return ret;
@@ -457,7 +474,6 @@ static int negotiate_nvsp_ver(struct hv_device *device,
init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT;
init_packet->msg.init_msg.init.min_protocol_ver = nvsp_ver;
init_packet->msg.init_msg.init.max_protocol_ver = nvsp_ver;
-
trace_nvsp_send(ndev, init_packet);
/* Send the init request */
@@ -575,7 +591,17 @@ void netvsc_device_remove(struct hv_device *device)
= rtnl_dereference(net_device_ctx->nvdev);
int i;
- netvsc_revoke_buf(device, net_device);
+ /*
+ * Revoke receive buffer. If host is pre-Win2016 then tear down
+ * receive buffer GPADL. Do the same for send buffer.
+ */
+ netvsc_revoke_recv_buf(device, net_device, ndev);
+ if (vmbus_proto_version < VERSION_WIN10)
+ netvsc_teardown_recv_gpadl(device, net_device, ndev);
+
+ netvsc_revoke_send_buf(device, net_device, ndev);
+ if (vmbus_proto_version < VERSION_WIN10)
+ netvsc_teardown_send_gpadl(device, net_device, ndev);
RCU_INIT_POINTER(net_device_ctx->nvdev, NULL);
@@ -589,15 +615,17 @@ void netvsc_device_remove(struct hv_device *device)
*/
netdev_dbg(ndev, "net device safe to remove\n");
- /* older versions require that buffer be revoked before close */
- if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_4)
- netvsc_teardown_gpadl(device, net_device);
-
/* Now, we can close the channel safely */
vmbus_close(device->channel);
- if (net_device->nvsp_version >= NVSP_PROTOCOL_VERSION_4)
- netvsc_teardown_gpadl(device, net_device);
+ /*
+ * If host is Win2016 or higher then we do the GPADL tear down
+ * here after VMBus is closed.
+ */
+ if (vmbus_proto_version >= VERSION_WIN10) {
+ netvsc_teardown_recv_gpadl(device, net_device, ndev);
+ netvsc_teardown_send_gpadl(device, net_device, ndev);
+ }
/* Release all resources */
free_netvsc_device_rcu(net_device);
diff --git a/drivers/net/netdevsim/devlink.c b/drivers/net/netdevsim/devlink.c
index 27ae05c5fdaf..bef7db5d129a 100644
--- a/drivers/net/netdevsim/devlink.c
+++ b/drivers/net/netdevsim/devlink.c
@@ -30,52 +30,36 @@ static struct net *nsim_devlink_net(struct devlink *devlink)
/* IPv4
*/
-static u64 nsim_ipv4_fib_resource_occ_get(struct devlink *devlink)
+static u64 nsim_ipv4_fib_resource_occ_get(void *priv)
{
- struct net *net = nsim_devlink_net(devlink);
+ struct net *net = priv;
return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, false);
}
-static struct devlink_resource_ops nsim_ipv4_fib_res_ops = {
- .occ_get = nsim_ipv4_fib_resource_occ_get,
-};
-
-static u64 nsim_ipv4_fib_rules_res_occ_get(struct devlink *devlink)
+static u64 nsim_ipv4_fib_rules_res_occ_get(void *priv)
{
- struct net *net = nsim_devlink_net(devlink);
+ struct net *net = priv;
return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, false);
}
-static struct devlink_resource_ops nsim_ipv4_fib_rules_res_ops = {
- .occ_get = nsim_ipv4_fib_rules_res_occ_get,
-};
-
/* IPv6
*/
-static u64 nsim_ipv6_fib_resource_occ_get(struct devlink *devlink)
+static u64 nsim_ipv6_fib_resource_occ_get(void *priv)
{
- struct net *net = nsim_devlink_net(devlink);
+ struct net *net = priv;
return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, false);
}
-static struct devlink_resource_ops nsim_ipv6_fib_res_ops = {
- .occ_get = nsim_ipv6_fib_resource_occ_get,
-};
-
-static u64 nsim_ipv6_fib_rules_res_occ_get(struct devlink *devlink)
+static u64 nsim_ipv6_fib_rules_res_occ_get(void *priv)
{
- struct net *net = nsim_devlink_net(devlink);
+ struct net *net = priv;
return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, false);
}
-static struct devlink_resource_ops nsim_ipv6_fib_rules_res_ops = {
- .occ_get = nsim_ipv6_fib_rules_res_occ_get,
-};
-
static int devlink_resources_register(struct devlink *devlink)
{
struct devlink_resource_size_params params = {
@@ -91,7 +75,7 @@ static int devlink_resources_register(struct devlink *devlink)
err = devlink_resource_register(devlink, "IPv4", (u64)-1,
NSIM_RESOURCE_IPV4,
DEVLINK_RESOURCE_ID_PARENT_TOP,
- &params, NULL);
+ &params);
if (err) {
pr_err("Failed to register IPv4 top resource\n");
goto out;
@@ -100,8 +84,7 @@ static int devlink_resources_register(struct devlink *devlink)
n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, true);
err = devlink_resource_register(devlink, "fib", n,
NSIM_RESOURCE_IPV4_FIB,
- NSIM_RESOURCE_IPV4,
- &params, &nsim_ipv4_fib_res_ops);
+ NSIM_RESOURCE_IPV4, &params);
if (err) {
pr_err("Failed to register IPv4 FIB resource\n");
return err;
@@ -110,8 +93,7 @@ static int devlink_resources_register(struct devlink *devlink)
n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, true);
err = devlink_resource_register(devlink, "fib-rules", n,
NSIM_RESOURCE_IPV4_FIB_RULES,
- NSIM_RESOURCE_IPV4,
- &params, &nsim_ipv4_fib_rules_res_ops);
+ NSIM_RESOURCE_IPV4, &params);
if (err) {
pr_err("Failed to register IPv4 FIB rules resource\n");
return err;
@@ -121,7 +103,7 @@ static int devlink_resources_register(struct devlink *devlink)
err = devlink_resource_register(devlink, "IPv6", (u64)-1,
NSIM_RESOURCE_IPV6,
DEVLINK_RESOURCE_ID_PARENT_TOP,
- &params, NULL);
+ &params);
if (err) {
pr_err("Failed to register IPv6 top resource\n");
goto out;
@@ -130,8 +112,7 @@ static int devlink_resources_register(struct devlink *devlink)
n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, true);
err = devlink_resource_register(devlink, "fib", n,
NSIM_RESOURCE_IPV6_FIB,
- NSIM_RESOURCE_IPV6,
- &params, &nsim_ipv6_fib_res_ops);
+ NSIM_RESOURCE_IPV6, &params);
if (err) {
pr_err("Failed to register IPv6 FIB resource\n");
return err;
@@ -140,12 +121,28 @@ static int devlink_resources_register(struct devlink *devlink)
n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, true);
err = devlink_resource_register(devlink, "fib-rules", n,
NSIM_RESOURCE_IPV6_FIB_RULES,
- NSIM_RESOURCE_IPV6,
- &params, &nsim_ipv6_fib_rules_res_ops);
+ NSIM_RESOURCE_IPV6, &params);
if (err) {
pr_err("Failed to register IPv6 FIB rules resource\n");
return err;
}
+
+ devlink_resource_occ_get_register(devlink,
+ NSIM_RESOURCE_IPV4_FIB,
+ nsim_ipv4_fib_resource_occ_get,
+ net);
+ devlink_resource_occ_get_register(devlink,
+ NSIM_RESOURCE_IPV4_FIB_RULES,
+ nsim_ipv4_fib_rules_res_occ_get,
+ net);
+ devlink_resource_occ_get_register(devlink,
+ NSIM_RESOURCE_IPV6_FIB,
+ nsim_ipv6_fib_resource_occ_get,
+ net);
+ devlink_resource_occ_get_register(devlink,
+ NSIM_RESOURCE_IPV6_FIB_RULES,
+ nsim_ipv6_fib_rules_res_occ_get,
+ net);
out:
return err;
}
@@ -267,7 +264,7 @@ static int __net_init nsim_devlink_netns_init(struct net *net)
return 0;
}
-static struct pernet_operations nsim_devlink_net_ops __net_initdata = {
+static struct pernet_operations nsim_devlink_net_ops = {
.init = nsim_devlink_netns_init,
.id = &nsim_devlink_id,
.size = sizeof(bool),
diff --git a/drivers/net/netdevsim/fib.c b/drivers/net/netdevsim/fib.c
index 0d105bafa261..9bfe9e151e13 100644
--- a/drivers/net/netdevsim/fib.c
+++ b/drivers/net/netdevsim/fib.c
@@ -230,7 +230,7 @@ static int __net_init nsim_fib_netns_init(struct net *net)
return 0;
}
-static struct pernet_operations nsim_fib_net_ops __net_initdata = {
+static struct pernet_operations nsim_fib_net_ops = {
.init = nsim_fib_netns_init,
.id = &nsim_fib_net_id,
.size = sizeof(struct nsim_fib_data),
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index a75c511950c3..c22e8e383247 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -828,6 +828,22 @@ static int m88e1121_config_init(struct phy_device *phydev)
return marvell_config_init(phydev);
}
+static int m88e1318_config_init(struct phy_device *phydev)
+{
+ if (phy_interrupt_is_valid(phydev)) {
+ int err = phy_modify_paged(
+ phydev, MII_MARVELL_LED_PAGE,
+ MII_88E1318S_PHY_LED_TCR,
+ MII_88E1318S_PHY_LED_TCR_FORCE_INT,
+ MII_88E1318S_PHY_LED_TCR_INTn_ENABLE |
+ MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW);
+ if (err < 0)
+ return err;
+ }
+
+ return m88e1121_config_init(phydev);
+}
+
static int m88e1510_config_init(struct phy_device *phydev)
{
int err;
@@ -870,7 +886,7 @@ static int m88e1510_config_init(struct phy_device *phydev)
phydev->advertising &= ~pause;
}
- return m88e1121_config_init(phydev);
+ return m88e1318_config_init(phydev);
}
static int m88e1118_config_aneg(struct phy_device *phydev)
@@ -2086,7 +2102,7 @@ static struct phy_driver marvell_drivers[] = {
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.probe = marvell_probe,
- .config_init = &m88e1121_config_init,
+ .config_init = &m88e1318_config_init,
.config_aneg = &m88e1318_config_aneg,
.read_status = &marvell_read_status,
.ack_interrupt = &marvell_ack_interrupt,
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index 9564916d2d7b..f77a2d9e7f9d 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -21,8 +21,10 @@
* If both the fiber and copper ports are connected, the first to gain
* link takes priority and the other port is completely locked out.
*/
-#include <linux/phy.h>
+#include <linux/ctype.h>
+#include <linux/hwmon.h>
#include <linux/marvell_phy.h>
+#include <linux/phy.h>
enum {
MV_PCS_BASE_T = 0x0000,
@@ -40,6 +42,19 @@ enum {
*/
MV_AN_CTRL1000 = 0x8000, /* 1000base-T control register */
MV_AN_STAT1000 = 0x8001, /* 1000base-T status register */
+
+ /* Vendor2 MMD registers */
+ MV_V2_TEMP_CTRL = 0xf08a,
+ MV_V2_TEMP_CTRL_MASK = 0xc000,
+ MV_V2_TEMP_CTRL_SAMPLE = 0x0000,
+ MV_V2_TEMP_CTRL_DISABLE = 0xc000,
+ MV_V2_TEMP = 0xf08c,
+ MV_V2_TEMP_UNKNOWN = 0x9600, /* unknown function */
+};
+
+struct mv3310_priv {
+ struct device *hwmon_dev;
+ char *hwmon_name;
};
static int mv3310_modify(struct phy_device *phydev, int devad, u16 reg,
@@ -60,17 +75,180 @@ static int mv3310_modify(struct phy_device *phydev, int devad, u16 reg,
return ret < 0 ? ret : 1;
}
+#ifdef CONFIG_HWMON
+static umode_t mv3310_hwmon_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ if (type == hwmon_chip && attr == hwmon_chip_update_interval)
+ return 0444;
+ if (type == hwmon_temp && attr == hwmon_temp_input)
+ return 0444;
+ return 0;
+}
+
+static int mv3310_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *value)
+{
+ struct phy_device *phydev = dev_get_drvdata(dev);
+ int temp;
+
+ if (type == hwmon_chip && attr == hwmon_chip_update_interval) {
+ *value = MSEC_PER_SEC;
+ return 0;
+ }
+
+ if (type == hwmon_temp && attr == hwmon_temp_input) {
+ temp = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_TEMP);
+ if (temp < 0)
+ return temp;
+
+ *value = ((temp & 0xff) - 75) * 1000;
+
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static const struct hwmon_ops mv3310_hwmon_ops = {
+ .is_visible = mv3310_hwmon_is_visible,
+ .read = mv3310_hwmon_read,
+};
+
+static u32 mv3310_hwmon_chip_config[] = {
+ HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL,
+ 0,
+};
+
+static const struct hwmon_channel_info mv3310_hwmon_chip = {
+ .type = hwmon_chip,
+ .config = mv3310_hwmon_chip_config,
+};
+
+static u32 mv3310_hwmon_temp_config[] = {
+ HWMON_T_INPUT,
+ 0,
+};
+
+static const struct hwmon_channel_info mv3310_hwmon_temp = {
+ .type = hwmon_temp,
+ .config = mv3310_hwmon_temp_config,
+};
+
+static const struct hwmon_channel_info *mv3310_hwmon_info[] = {
+ &mv3310_hwmon_chip,
+ &mv3310_hwmon_temp,
+ NULL,
+};
+
+static const struct hwmon_chip_info mv3310_hwmon_chip_info = {
+ .ops = &mv3310_hwmon_ops,
+ .info = mv3310_hwmon_info,
+};
+
+static int mv3310_hwmon_config(struct phy_device *phydev, bool enable)
+{
+ u16 val;
+ int ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_TEMP,
+ MV_V2_TEMP_UNKNOWN);
+ if (ret < 0)
+ return ret;
+
+ val = enable ? MV_V2_TEMP_CTRL_SAMPLE : MV_V2_TEMP_CTRL_DISABLE;
+ ret = mv3310_modify(phydev, MDIO_MMD_VEND2, MV_V2_TEMP_CTRL,
+ MV_V2_TEMP_CTRL_MASK, val);
+
+ return ret < 0 ? ret : 0;
+}
+
+static void mv3310_hwmon_disable(void *data)
+{
+ struct phy_device *phydev = data;
+
+ mv3310_hwmon_config(phydev, false);
+}
+
+static int mv3310_hwmon_probe(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+ int i, j, ret;
+
+ priv->hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
+ if (!priv->hwmon_name)
+ return -ENODEV;
+
+ for (i = j = 0; priv->hwmon_name[i]; i++) {
+ if (isalnum(priv->hwmon_name[i])) {
+ if (i != j)
+ priv->hwmon_name[j] = priv->hwmon_name[i];
+ j++;
+ }
+ }
+ priv->hwmon_name[j] = '\0';
+
+ ret = mv3310_hwmon_config(phydev, true);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, mv3310_hwmon_disable, phydev);
+ if (ret)
+ return ret;
+
+ priv->hwmon_dev = devm_hwmon_device_register_with_info(dev,
+ priv->hwmon_name, phydev,
+ &mv3310_hwmon_chip_info, NULL);
+
+ return PTR_ERR_OR_ZERO(priv->hwmon_dev);
+}
+#else
+static inline int mv3310_hwmon_config(struct phy_device *phydev, bool enable)
+{
+ return 0;
+}
+
+static int mv3310_hwmon_probe(struct phy_device *phydev)
+{
+ return 0;
+}
+#endif
+
static int mv3310_probe(struct phy_device *phydev)
{
+ struct mv3310_priv *priv;
u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
+ int ret;
if (!phydev->is_c45 ||
(phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask)
return -ENODEV;
+ priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(&phydev->mdio.dev, priv);
+
+ ret = mv3310_hwmon_probe(phydev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mv3310_suspend(struct phy_device *phydev)
+{
return 0;
}
+static int mv3310_resume(struct phy_device *phydev)
+{
+ return mv3310_hwmon_config(phydev, true);
+}
+
static int mv3310_config_init(struct phy_device *phydev)
{
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };
@@ -367,9 +545,11 @@ static struct phy_driver mv3310_drivers[] = {
SUPPORTED_FIBRE |
SUPPORTED_10000baseT_Full |
SUPPORTED_Backplane,
- .probe = mv3310_probe,
.soft_reset = gen10g_no_soft_reset,
.config_init = mv3310_config_init,
+ .probe = mv3310_probe,
+ .suspend = mv3310_suspend,
+ .resume = mv3310_resume,
.config_aneg = mv3310_config_aneg,
.aneg_done = mv3310_aneg_done,
.read_status = mv3310_read_status,
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index 8249d46a7844..c4267ecefd85 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -464,7 +464,6 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
po->chan.mtu = dst_mtu(&rt->dst);
if (!po->chan.mtu)
po->chan.mtu = PPP_MRU;
- ip_rt_put(rt);
po->chan.mtu -= PPTP_HEADER_OVERHEAD;
po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header);
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index 55a78eb96961..aff105f5f58c 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -2082,10 +2082,6 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)
dev->fc_autoneg = phydev->autoneg;
- phy_start(phydev);
-
- netif_dbg(dev, ifup, dev->net, "phy initialised successfully");
-
return 0;
error:
@@ -2522,9 +2518,9 @@ static int lan78xx_open(struct net_device *net)
if (ret < 0)
goto done;
- ret = lan78xx_phy_init(dev);
- if (ret < 0)
- goto done;
+ phy_start(net->phydev);
+
+ netif_dbg(dev, ifup, dev->net, "phy initialised successfully");
/* for Link Check */
if (dev->urb_intr) {
@@ -2585,13 +2581,8 @@ static int lan78xx_stop(struct net_device *net)
if (timer_pending(&dev->stat_monitor))
del_timer_sync(&dev->stat_monitor);
- phy_unregister_fixup_for_uid(PHY_KSZ9031RNX, 0xfffffff0);
- phy_unregister_fixup_for_uid(PHY_LAN8835, 0xfffffff0);
-
- phy_stop(net->phydev);
- phy_disconnect(net->phydev);
-
- net->phydev = NULL;
+ if (net->phydev)
+ phy_stop(net->phydev);
clear_bit(EVENT_DEV_OPEN, &dev->flags);
netif_stop_queue(net);
@@ -3506,8 +3497,13 @@ static void lan78xx_disconnect(struct usb_interface *intf)
return;
udev = interface_to_usbdev(intf);
-
net = dev->net;
+
+ phy_unregister_fixup_for_uid(PHY_KSZ9031RNX, 0xfffffff0);
+ phy_unregister_fixup_for_uid(PHY_LAN8835, 0xfffffff0);
+
+ phy_disconnect(net->phydev);
+
unregister_netdev(net);
cancel_delayed_work_sync(&dev->wq);
@@ -3663,8 +3659,14 @@ static int lan78xx_probe(struct usb_interface *intf,
pm_runtime_set_autosuspend_delay(&udev->dev,
DEFAULT_AUTOSUSPEND_DELAY);
+ ret = lan78xx_phy_init(dev);
+ if (ret < 0)
+ goto out4;
+
return 0;
+out4:
+ unregister_netdev(netdev);
out3:
lan78xx_unbind(dev, intf);
out2:
@@ -4012,7 +4014,7 @@ static int lan78xx_reset_resume(struct usb_interface *intf)
lan78xx_reset(dev);
- lan78xx_phy_init(dev);
+ phy_start(dev->net->phydev);
return lan78xx_resume(intf);
}
diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.c b/drivers/net/wireless/mediatek/mt7601u/mcu.c
index d9d6fd7eff5e..61705f679856 100644
--- a/drivers/net/wireless/mediatek/mt7601u/mcu.c
+++ b/drivers/net/wireless/mediatek/mt7601u/mcu.c
@@ -420,7 +420,7 @@ static int mt7601u_load_firmware(struct mt7601u_dev *dev)
MT_USB_DMA_CFG_TX_BULK_EN));
if (firmware_running(dev))
- return 0;
+ return firmware_request_cache(dev->dev, MT7601U_FIRMWARE);
ret = request_firmware(&fw, MT7601U_FIRMWARE, dev->dev);
if (ret)
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index ff505af064ba..1090924efdb1 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -1,5 +1,5 @@
menuconfig NVMEM
- tristate "NVMEM Support"
+ bool "NVMEM Support"
help
Support for NVMEM(Non Volatile Memory) devices like EEPROM, EFUSES...
@@ -167,10 +167,10 @@ config MESON_MX_EFUSE
config NVMEM_SNVS_LPGPR
tristate "Support for Low Power General Purpose Register"
- depends on SOC_IMX6 || COMPILE_TEST
+ depends on SOC_IMX6 || SOC_IMX7D || COMPILE_TEST
help
This is a driver for Low Power General Purpose Register (LPGPR) available on
- i.MX6 SoCs in Secure Non-Volatile Storage (SNVS) of this chip.
+ i.MX6 and i.MX7 SoCs in Secure Non-Volatile Storage (SNVS) of this chip.
This driver can also be built as a module. If so, the module
will be called nvmem-snvs-lpgpr.
diff --git a/drivers/nvmem/bcm-ocotp.c b/drivers/nvmem/bcm-ocotp.c
index 5e9e324427f9..4159b3f41d79 100644
--- a/drivers/nvmem/bcm-ocotp.c
+++ b/drivers/nvmem/bcm-ocotp.c
@@ -262,8 +262,7 @@ static int bcm_otpc_probe(struct platform_device *pdev)
else if (of_device_is_compatible(dev->of_node, "brcm,ocotp-v2"))
priv->map = &otp_map_v2;
else {
- dev_err(&pdev->dev,
- "%s otpc config map not defined\n", __func__);
+ dev_err(dev, "%s otpc config map not defined\n", __func__);
return -EINVAL;
}
@@ -302,27 +301,17 @@ static int bcm_otpc_probe(struct platform_device *pdev)
priv->config = &bcm_otpc_nvmem_config;
- nvmem = nvmem_register(&bcm_otpc_nvmem_config);
+ nvmem = devm_nvmem_register(dev, &bcm_otpc_nvmem_config);
if (IS_ERR(nvmem)) {
dev_err(dev, "error registering nvmem config\n");
return PTR_ERR(nvmem);
}
- platform_set_drvdata(pdev, nvmem);
-
return 0;
}
-static int bcm_otpc_remove(struct platform_device *pdev)
-{
- struct nvmem_device *nvmem = platform_get_drvdata(pdev);
-
- return nvmem_unregister(nvmem);
-}
-
static struct platform_driver bcm_otpc_driver = {
.probe = bcm_otpc_probe,
- .remove = bcm_otpc_remove,
.driver = {
.name = "brcm-otpc",
.of_match_table = bcm_otpc_dt_ids,
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 35a3dbeea324..b05aa8e81303 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -473,9 +473,14 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
nvmem->reg_read = config->reg_read;
nvmem->reg_write = config->reg_write;
nvmem->dev.of_node = config->dev->of_node;
- dev_set_name(&nvmem->dev, "%s%d",
- config->name ? : "nvmem",
- config->name ? config->id : nvmem->id);
+
+ if (config->id == -1 && config->name) {
+ dev_set_name(&nvmem->dev, "%s", config->name);
+ } else {
+ dev_set_name(&nvmem->dev, "%s%d",
+ config->name ? : "nvmem",
+ config->name ? config->id : nvmem->id);
+ }
nvmem->read_only = device_property_present(config->dev, "read-only") |
config->read_only;
@@ -544,6 +549,65 @@ int nvmem_unregister(struct nvmem_device *nvmem)
}
EXPORT_SYMBOL_GPL(nvmem_unregister);
+static void devm_nvmem_release(struct device *dev, void *res)
+{
+ WARN_ON(nvmem_unregister(*(struct nvmem_device **)res));
+}
+
+/**
+ * devm_nvmem_register() - Register a managed nvmem device for given
+ * nvmem_config.
+ * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
+ *
+ * @config: nvmem device configuration with which nvmem device is created.
+ *
+ * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
+ * on success.
+ */
+struct nvmem_device *devm_nvmem_register(struct device *dev,
+ const struct nvmem_config *config)
+{
+ struct nvmem_device **ptr, *nvmem;
+
+ ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ nvmem = nvmem_register(config);
+
+ if (!IS_ERR(nvmem)) {
+ *ptr = nvmem;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return nvmem;
+}
+EXPORT_SYMBOL_GPL(devm_nvmem_register);
+
+static int devm_nvmem_match(struct device *dev, void *res, void *data)
+{
+ struct nvmem_device **r = res;
+
+ return *r == data;
+}
+
+/**
+ * devm_nvmem_unregister() - Unregister previously registered managed nvmem
+ * device.
+ *
+ * @nvmem: Pointer to previously registered nvmem device.
+ *
+ * Return: Will be an negative on error or a zero on success.
+ */
+int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem)
+{
+ return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem);
+}
+EXPORT_SYMBOL(devm_nvmem_unregister);
+
+
static struct nvmem_device *__nvmem_device_get(struct device_node *np,
struct nvmem_cell **cellp,
const char *cell_id)
diff --git a/drivers/nvmem/imx-iim.c b/drivers/nvmem/imx-iim.c
index 52cfe91d9762..6651e4cdc002 100644
--- a/drivers/nvmem/imx-iim.c
+++ b/drivers/nvmem/imx-iim.c
@@ -125,7 +125,7 @@ static int imx_iim_probe(struct platform_device *pdev)
drvdata = of_id->data;
- iim->clk = devm_clk_get(&pdev->dev, NULL);
+ iim->clk = devm_clk_get(dev, NULL);
if (IS_ERR(iim->clk))
return PTR_ERR(iim->clk);
@@ -138,25 +138,13 @@ static int imx_iim_probe(struct platform_device *pdev)
cfg.size = drvdata->nregs;
cfg.priv = iim;
- nvmem = nvmem_register(&cfg);
- if (IS_ERR(nvmem))
- return PTR_ERR(nvmem);
+ nvmem = devm_nvmem_register(dev, &cfg);
- platform_set_drvdata(pdev, nvmem);
-
- return 0;
-}
-
-static int imx_iim_remove(struct platform_device *pdev)
-{
- struct nvmem_device *nvmem = platform_get_drvdata(pdev);
-
- return nvmem_unregister(nvmem);
+ return PTR_ERR_OR_ZERO(nvmem);
}
static struct platform_driver imx_iim_driver = {
.probe = imx_iim_probe,
- .remove = imx_iim_remove,
.driver = {
.name = "imx-iim",
.of_match_table = imx_iim_dt_ids,
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index d7ba351a70c9..60816c856dd6 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -439,7 +439,6 @@ MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids);
static int imx_ocotp_probe(struct platform_device *pdev)
{
- const struct of_device_id *of_id;
struct device *dev = &pdev->dev;
struct resource *res;
struct ocotp_priv *priv;
@@ -460,32 +459,19 @@ static int imx_ocotp_probe(struct platform_device *pdev)
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
- of_id = of_match_device(imx_ocotp_dt_ids, dev);
priv->params = of_device_get_match_data(&pdev->dev);
imx_ocotp_nvmem_config.size = 4 * priv->params->nregs;
imx_ocotp_nvmem_config.dev = dev;
imx_ocotp_nvmem_config.priv = priv;
priv->config = &imx_ocotp_nvmem_config;
- nvmem = nvmem_register(&imx_ocotp_nvmem_config);
+ nvmem = devm_nvmem_register(dev, &imx_ocotp_nvmem_config);
- if (IS_ERR(nvmem))
- return PTR_ERR(nvmem);
- platform_set_drvdata(pdev, nvmem);
-
- return 0;
-}
-
-static int imx_ocotp_remove(struct platform_device *pdev)
-{
- struct nvmem_device *nvmem = platform_get_drvdata(pdev);
-
- return nvmem_unregister(nvmem);
+ return PTR_ERR_OR_ZERO(nvmem);
}
static struct platform_driver imx_ocotp_driver = {
.probe = imx_ocotp_probe,
- .remove = imx_ocotp_remove,
.driver = {
.name = "imx_ocotp",
.of_match_table = imx_ocotp_dt_ids,
diff --git a/drivers/nvmem/lpc18xx_otp.c b/drivers/nvmem/lpc18xx_otp.c
index 95268db155e9..549b5298ac4c 100644
--- a/drivers/nvmem/lpc18xx_otp.c
+++ b/drivers/nvmem/lpc18xx_otp.c
@@ -86,20 +86,9 @@ static int lpc18xx_otp_probe(struct platform_device *pdev)
lpc18xx_otp_nvmem_config.dev = &pdev->dev;
lpc18xx_otp_nvmem_config.priv = otp;
- nvmem = nvmem_register(&lpc18xx_otp_nvmem_config);
- if (IS_ERR(nvmem))
- return PTR_ERR(nvmem);
+ nvmem = devm_nvmem_register(&pdev->dev, &lpc18xx_otp_nvmem_config);
- platform_set_drvdata(pdev, nvmem);
-
- return 0;
-}
-
-static int lpc18xx_otp_remove(struct platform_device *pdev)
-{
- struct nvmem_device *nvmem = platform_get_drvdata(pdev);
-
- return nvmem_unregister(nvmem);
+ return PTR_ERR_OR_ZERO(nvmem);
}
static const struct of_device_id lpc18xx_otp_dt_ids[] = {
@@ -110,7 +99,6 @@ MODULE_DEVICE_TABLE(of, lpc18xx_otp_dt_ids);
static struct platform_driver lpc18xx_otp_driver = {
.probe = lpc18xx_otp_probe,
- .remove = lpc18xx_otp_remove,
.driver = {
.name = "lpc18xx_otp",
.of_match_table = lpc18xx_otp_dt_ids,
diff --git a/drivers/nvmem/meson-efuse.c b/drivers/nvmem/meson-efuse.c
index a43c68f90937..71823d1403c5 100644
--- a/drivers/nvmem/meson-efuse.c
+++ b/drivers/nvmem/meson-efuse.c
@@ -60,25 +60,13 @@ static int meson_efuse_probe(struct platform_device *pdev)
econfig.reg_read = meson_efuse_read;
econfig.size = size;
- nvmem = nvmem_register(&econfig);
- if (IS_ERR(nvmem))
- return PTR_ERR(nvmem);
+ nvmem = devm_nvmem_register(&pdev->dev, &econfig);
- platform_set_drvdata(pdev, nvmem);
-
- return 0;
-}
-
-static int meson_efuse_remove(struct platform_device *pdev)
-{
- struct nvmem_device *nvmem = platform_get_drvdata(pdev);
-
- return nvmem_unregister(nvmem);
+ return PTR_ERR_OR_ZERO(nvmem);
}
static struct platform_driver meson_efuse_driver = {
.probe = meson_efuse_probe,
- .remove = meson_efuse_remove,
.driver = {
.name = "meson-efuse",
.of_match_table = meson_efuse_match,
diff --git a/drivers/nvmem/meson-mx-efuse.c b/drivers/nvmem/meson-mx-efuse.c
index 41d3a3c1104e..a085563e39e3 100644
--- a/drivers/nvmem/meson-mx-efuse.c
+++ b/drivers/nvmem/meson-mx-efuse.c
@@ -233,25 +233,13 @@ static int meson_mx_efuse_probe(struct platform_device *pdev)
return PTR_ERR(efuse->core_clk);
}
- efuse->nvmem = nvmem_register(&efuse->config);
- if (IS_ERR(efuse->nvmem))
- return PTR_ERR(efuse->nvmem);
+ efuse->nvmem = devm_nvmem_register(&pdev->dev, &efuse->config);
- platform_set_drvdata(pdev, efuse);
-
- return 0;
-}
-
-static int meson_mx_efuse_remove(struct platform_device *pdev)
-{
- struct meson_mx_efuse *efuse = platform_get_drvdata(pdev);
-
- return nvmem_unregister(efuse->nvmem);
+ return PTR_ERR_OR_ZERO(efuse->nvmem);
}
static struct platform_driver meson_mx_efuse_driver = {
.probe = meson_mx_efuse_probe,
- .remove = meson_mx_efuse_remove,
.driver = {
.name = "meson-mx-efuse",
.of_match_table = meson_mx_efuse_match,
diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c
index 9ee3479cfc7b..e66adf17a747 100644
--- a/drivers/nvmem/mtk-efuse.c
+++ b/drivers/nvmem/mtk-efuse.c
@@ -72,20 +72,9 @@ static int mtk_efuse_probe(struct platform_device *pdev)
econfig.size = resource_size(res);
econfig.priv = priv;
econfig.dev = dev;
- nvmem = nvmem_register(&econfig);
- if (IS_ERR(nvmem))
- return PTR_ERR(nvmem);
+ nvmem = devm_nvmem_register(dev, &econfig);
- 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);
+ return PTR_ERR_OR_ZERO(nvmem);
}
static const struct of_device_id mtk_efuse_of_match[] = {
@@ -97,7 +86,6 @@ 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,
diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c
index cb3b48b47d64..4f650baad983 100644
--- a/drivers/nvmem/qfprom.c
+++ b/drivers/nvmem/qfprom.c
@@ -47,13 +47,6 @@ static int qfprom_reg_write(void *context,
return 0;
}
-static int qfprom_remove(struct platform_device *pdev)
-{
- struct nvmem_device *nvmem = platform_get_drvdata(pdev);
-
- return nvmem_unregister(nvmem);
-}
-
static struct nvmem_config econfig = {
.name = "qfprom",
.stride = 1,
@@ -82,13 +75,9 @@ static int qfprom_probe(struct platform_device *pdev)
econfig.dev = dev;
econfig.priv = priv;
- nvmem = nvmem_register(&econfig);
- if (IS_ERR(nvmem))
- return PTR_ERR(nvmem);
-
- platform_set_drvdata(pdev, nvmem);
+ nvmem = devm_nvmem_register(dev, &econfig);
- return 0;
+ return PTR_ERR_OR_ZERO(nvmem);
}
static const struct of_device_id qfprom_of_match[] = {
@@ -99,7 +88,6 @@ MODULE_DEVICE_TABLE(of, qfprom_of_match);
static struct platform_driver qfprom_driver = {
.probe = qfprom_probe,
- .remove = qfprom_remove,
.driver = {
.name = "qcom,qfprom",
.of_match_table = qfprom_of_match,
diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c
index f13a8335f364..b3b0b648be62 100644
--- a/drivers/nvmem/rockchip-efuse.c
+++ b/drivers/nvmem/rockchip-efuse.c
@@ -259,55 +259,43 @@ static int rockchip_efuse_probe(struct platform_device *pdev)
struct resource *res;
struct nvmem_device *nvmem;
struct rockchip_efuse_chip *efuse;
- const struct of_device_id *match;
+ const void *data;
struct device *dev = &pdev->dev;
- match = of_match_device(dev->driver->of_match_table, dev);
- if (!match || !match->data) {
+ data = of_device_get_match_data(dev);
+ if (!data) {
dev_err(dev, "failed to get match data\n");
return -EINVAL;
}
- efuse = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_efuse_chip),
+ efuse = devm_kzalloc(dev, sizeof(struct rockchip_efuse_chip),
GFP_KERNEL);
if (!efuse)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- efuse->base = devm_ioremap_resource(&pdev->dev, res);
+ efuse->base = devm_ioremap_resource(dev, res);
if (IS_ERR(efuse->base))
return PTR_ERR(efuse->base);
- efuse->clk = devm_clk_get(&pdev->dev, "pclk_efuse");
+ efuse->clk = devm_clk_get(dev, "pclk_efuse");
if (IS_ERR(efuse->clk))
return PTR_ERR(efuse->clk);
- efuse->dev = &pdev->dev;
+ efuse->dev = dev;
if (of_property_read_u32(dev->of_node, "rockchip,efuse-size",
&econfig.size))
econfig.size = resource_size(res);
- econfig.reg_read = match->data;
+ econfig.reg_read = data;
econfig.priv = efuse;
econfig.dev = efuse->dev;
- nvmem = nvmem_register(&econfig);
- if (IS_ERR(nvmem))
- return PTR_ERR(nvmem);
+ nvmem = devm_nvmem_register(dev, &econfig);
- platform_set_drvdata(pdev, nvmem);
-
- return 0;
-}
-
-static int rockchip_efuse_remove(struct platform_device *pdev)
-{
- struct nvmem_device *nvmem = platform_get_drvdata(pdev);
-
- return nvmem_unregister(nvmem);
+ return PTR_ERR_OR_ZERO(nvmem);
}
static struct platform_driver rockchip_efuse_driver = {
.probe = rockchip_efuse_probe,
- .remove = rockchip_efuse_remove,
.driver = {
.name = "rockchip-efuse",
.of_match_table = rockchip_efuse_match,
diff --git a/drivers/nvmem/snvs_lpgpr.c b/drivers/nvmem/snvs_lpgpr.c
index e5c2a4a17f03..c050a23a9f2b 100644
--- a/drivers/nvmem/snvs_lpgpr.c
+++ b/drivers/nvmem/snvs_lpgpr.c
@@ -14,15 +14,21 @@
#include <linux/regmap.h>
#define IMX6Q_SNVS_HPLR 0x00
-#define IMX6Q_GPR_SL BIT(5)
#define IMX6Q_SNVS_LPLR 0x34
-#define IMX6Q_GPR_HL BIT(5)
#define IMX6Q_SNVS_LPGPR 0x68
+#define IMX7D_SNVS_HPLR 0x00
+#define IMX7D_SNVS_LPLR 0x34
+#define IMX7D_SNVS_LPGPR 0x90
+
+#define IMX_GPR_SL BIT(5)
+#define IMX_GPR_HL BIT(5)
+
struct snvs_lpgpr_cfg {
int offset;
int offset_hplr;
int offset_lplr;
+ int size;
};
struct snvs_lpgpr_priv {
@@ -36,6 +42,14 @@ static const struct snvs_lpgpr_cfg snvs_lpgpr_cfg_imx6q = {
.offset = IMX6Q_SNVS_LPGPR,
.offset_hplr = IMX6Q_SNVS_HPLR,
.offset_lplr = IMX6Q_SNVS_LPLR,
+ .size = 4,
+};
+
+static const struct snvs_lpgpr_cfg snvs_lpgpr_cfg_imx7d = {
+ .offset = IMX7D_SNVS_LPGPR,
+ .offset_hplr = IMX7D_SNVS_HPLR,
+ .offset_lplr = IMX7D_SNVS_LPLR,
+ .size = 16,
};
static int snvs_lpgpr_write(void *context, unsigned int offset, void *val,
@@ -50,14 +64,14 @@ static int snvs_lpgpr_write(void *context, unsigned int offset, void *val,
if (ret < 0)
return ret;
- if (lock_reg & IMX6Q_GPR_SL)
+ if (lock_reg & IMX_GPR_SL)
return -EPERM;
ret = regmap_read(priv->regmap, dcfg->offset_lplr, &lock_reg);
if (ret < 0)
return ret;
- if (lock_reg & IMX6Q_GPR_HL)
+ if (lock_reg & IMX_GPR_HL)
return -EPERM;
return regmap_bulk_write(priv->regmap, dcfg->offset + offset, val,
@@ -110,40 +124,29 @@ static int snvs_lpgpr_probe(struct platform_device *pdev)
cfg->priv = priv;
cfg->name = dev_name(dev);
cfg->dev = dev;
- cfg->stride = 4,
- cfg->word_size = 4,
- cfg->size = 4,
- cfg->owner = THIS_MODULE,
- cfg->reg_read = snvs_lpgpr_read,
- cfg->reg_write = snvs_lpgpr_write,
-
- nvmem = nvmem_register(cfg);
- if (IS_ERR(nvmem))
- return PTR_ERR(nvmem);
+ cfg->stride = 4;
+ cfg->word_size = 4;
+ cfg->size = dcfg->size,
+ cfg->owner = THIS_MODULE;
+ cfg->reg_read = snvs_lpgpr_read;
+ cfg->reg_write = snvs_lpgpr_write;
- platform_set_drvdata(pdev, nvmem);
-
- return 0;
-}
-
-static int snvs_lpgpr_remove(struct platform_device *pdev)
-{
- struct nvmem_device *nvmem = platform_get_drvdata(pdev);
+ nvmem = devm_nvmem_register(dev, cfg);
- return nvmem_unregister(nvmem);
+ return PTR_ERR_OR_ZERO(nvmem);
}
static const struct of_device_id snvs_lpgpr_dt_ids[] = {
{ .compatible = "fsl,imx6q-snvs-lpgpr", .data = &snvs_lpgpr_cfg_imx6q },
{ .compatible = "fsl,imx6ul-snvs-lpgpr",
.data = &snvs_lpgpr_cfg_imx6q },
+ { .compatible = "fsl,imx7d-snvs-lpgpr", .data = &snvs_lpgpr_cfg_imx7d },
{ },
};
MODULE_DEVICE_TABLE(of, snvs_lpgpr_dt_ids);
static struct platform_driver snvs_lpgpr_driver = {
.probe = snvs_lpgpr_probe,
- .remove = snvs_lpgpr_remove,
.driver = {
.name = "snvs_lpgpr",
.of_match_table = snvs_lpgpr_dt_ids,
@@ -152,5 +155,5 @@ static struct platform_driver snvs_lpgpr_driver = {
module_platform_driver(snvs_lpgpr_driver);
MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>");
-MODULE_DESCRIPTION("Low Power General Purpose Register in i.MX6 Secure Non-Volatile Storage");
+MODULE_DESCRIPTION("Low Power General Purpose Register in i.MX6 and i.MX7 Secure Non-Volatile Storage");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
index 99bd54d85fcb..26bb637afe92 100644
--- a/drivers/nvmem/sunxi_sid.c
+++ b/drivers/nvmem/sunxi_sid.c
@@ -85,13 +85,14 @@ static int sunxi_sid_read(void *context, unsigned int offset,
}
static int sun8i_sid_register_readout(const struct sunxi_sid *sid,
- const unsigned int word)
+ const unsigned int offset,
+ u32 *out)
{
u32 reg_val;
int ret;
/* Set word, lock access, and set read command */
- reg_val = (word & SUN8I_SID_OFFSET_MASK)
+ reg_val = (offset & SUN8I_SID_OFFSET_MASK)
<< SUN8I_SID_OFFSET_SHIFT;
reg_val |= SUN8I_SID_OP_LOCK | SUN8I_SID_READ;
writel(reg_val, sid->base + SUN8I_SID_PRCTL);
@@ -101,7 +102,49 @@ static int sun8i_sid_register_readout(const struct sunxi_sid *sid,
if (ret)
return ret;
+ if (out)
+ *out = readl(sid->base + SUN8I_SID_RDKEY);
+
writel(0, sid->base + SUN8I_SID_PRCTL);
+
+ return 0;
+}
+
+/*
+ * On Allwinner H3, the value on the 0x200 offset of the SID controller seems
+ * to be not reliable at all.
+ * Read by the registers instead.
+ */
+static int sun8i_sid_read_byte_by_reg(const struct sunxi_sid *sid,
+ const unsigned int offset,
+ u8 *out)
+{
+ u32 word;
+ int ret;
+
+ ret = sun8i_sid_register_readout(sid, offset & ~0x03, &word);
+
+ if (ret)
+ return ret;
+
+ *out = (word >> ((offset & 0x3) * 8)) & 0xff;
+
+ return 0;
+}
+
+static int sun8i_sid_read_by_reg(void *context, unsigned int offset,
+ void *val, size_t bytes)
+{
+ struct sunxi_sid *sid = context;
+ u8 *buf = val;
+ int ret;
+
+ while (bytes--) {
+ ret = sun8i_sid_read_byte_by_reg(sid, offset++, buf++);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
@@ -131,26 +174,12 @@ static int sunxi_sid_probe(struct platform_device *pdev)
size = cfg->size;
- if (cfg->need_register_readout) {
- /*
- * H3's SID controller have a bug that the value at 0x200
- * offset is not the correct value when the hardware is reseted.
- * However, after doing a register-based read operation, the
- * value become right.
- * Do a full read operation here, but ignore its value
- * (as it's more fast to read by direct MMIO value than
- * with registers)
- */
- for (i = 0; i < (size >> 2); i++) {
- ret = sun8i_sid_register_readout(sid, i);
- if (ret)
- return ret;
- }
- }
-
econfig.size = size;
econfig.dev = dev;
- econfig.reg_read = sunxi_sid_read;
+ if (cfg->need_register_readout)
+ econfig.reg_read = sun8i_sid_read_by_reg;
+ else
+ econfig.reg_read = sunxi_sid_read;
econfig.priv = sid;
nvmem = nvmem_register(&econfig);
if (IS_ERR(nvmem))
@@ -163,7 +192,7 @@ static int sunxi_sid_probe(struct platform_device *pdev)
}
for (i = 0; i < size; i++)
- randomness[i] = sunxi_sid_read_byte(sid, i);
+ econfig.reg_read(sid, i, &randomness[i], 1);
add_device_randomness(randomness, size);
kfree(randomness);
diff --git a/drivers/nvmem/uniphier-efuse.c b/drivers/nvmem/uniphier-efuse.c
index be11880a1358..271f0b2ff86a 100644
--- a/drivers/nvmem/uniphier-efuse.c
+++ b/drivers/nvmem/uniphier-efuse.c
@@ -60,20 +60,9 @@ static int uniphier_efuse_probe(struct platform_device *pdev)
econfig.size = resource_size(res);
econfig.priv = priv;
econfig.dev = dev;
- nvmem = nvmem_register(&econfig);
- if (IS_ERR(nvmem))
- return PTR_ERR(nvmem);
+ nvmem = devm_nvmem_register(dev, &econfig);
- platform_set_drvdata(pdev, nvmem);
-
- return 0;
-}
-
-static int uniphier_efuse_remove(struct platform_device *pdev)
-{
- struct nvmem_device *nvmem = platform_get_drvdata(pdev);
-
- return nvmem_unregister(nvmem);
+ return PTR_ERR_OR_ZERO(nvmem);
}
static const struct of_device_id uniphier_efuse_of_match[] = {
@@ -84,7 +73,6 @@ MODULE_DEVICE_TABLE(of, uniphier_efuse_of_match);
static struct platform_driver uniphier_efuse_driver = {
.probe = uniphier_efuse_probe,
- .remove = uniphier_efuse_remove,
.driver = {
.name = "uniphier-efuse",
.of_match_table = uniphier_efuse_of_match,
diff --git a/drivers/nvmem/vf610-ocotp.c b/drivers/nvmem/vf610-ocotp.c
index 5ae9e002f195..4662309489db 100644
--- a/drivers/nvmem/vf610-ocotp.c
+++ b/drivers/nvmem/vf610-ocotp.c
@@ -217,21 +217,13 @@ static const struct of_device_id ocotp_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ocotp_of_match);
-static int vf610_ocotp_remove(struct platform_device *pdev)
-{
- struct vf610_ocotp *ocotp_dev = platform_get_drvdata(pdev);
-
- return nvmem_unregister(ocotp_dev->nvmem);
-}
-
static int vf610_ocotp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
struct vf610_ocotp *ocotp_dev;
- ocotp_dev = devm_kzalloc(&pdev->dev,
- sizeof(struct vf610_ocotp), GFP_KERNEL);
+ ocotp_dev = devm_kzalloc(dev, sizeof(struct vf610_ocotp), GFP_KERNEL);
if (!ocotp_dev)
return -ENOMEM;
@@ -246,26 +238,20 @@ static int vf610_ocotp_probe(struct platform_device *pdev)
PTR_ERR(ocotp_dev->clk));
return PTR_ERR(ocotp_dev->clk);
}
+ ocotp_dev->dev = dev;
+ ocotp_dev->timing = vf610_ocotp_calculate_timing(ocotp_dev);
ocotp_config.size = resource_size(res);
ocotp_config.priv = ocotp_dev;
ocotp_config.dev = dev;
- ocotp_dev->nvmem = nvmem_register(&ocotp_config);
- if (IS_ERR(ocotp_dev->nvmem))
- return PTR_ERR(ocotp_dev->nvmem);
+ ocotp_dev->nvmem = devm_nvmem_register(dev, &ocotp_config);
- ocotp_dev->dev = dev;
- platform_set_drvdata(pdev, ocotp_dev);
-
- ocotp_dev->timing = vf610_ocotp_calculate_timing(ocotp_dev);
-
- return 0;
+ return PTR_ERR_OR_ZERO(ocotp_dev->nvmem);
}
static struct platform_driver vf610_ocotp_driver = {
.probe = vf610_ocotp_probe,
- .remove = vf610_ocotp_remove,
.driver = {
.name = "vf610-ocotp",
.of_match_table = ocotp_of_match,
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index d77ebbfc67c9..4ea08979312c 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -138,6 +138,9 @@ static int __oprofilefs_create_file(struct dentry *root, char const *name,
struct dentry *dentry;
struct inode *inode;
+ if (!root)
+ return -ENOMEM;
+
inode_lock(d_inode(root));
dentry = d_alloc_name(root, name);
if (!dentry) {
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 41b740aed3a3..69bd98421eb1 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -1403,9 +1403,27 @@ lba_hw_init(struct lba_device *d)
WRITE_REG32(stat, d->hba.base_addr + LBA_ERROR_CONFIG);
}
- /* Set HF mode as the default (vs. -1 mode). */
+
+ /*
+ * Hard Fail vs. Soft Fail on PCI "Master Abort".
+ *
+ * "Master Abort" means the MMIO transaction timed out - usually due to
+ * the device not responding to an MMIO read. We would like HF to be
+ * enabled to find driver problems, though it means the system will
+ * crash with a HPMC.
+ *
+ * In SoftFail mode "~0L" is returned as a result of a timeout on the
+ * pci bus. This is like how PCI busses on x86 and most other
+ * architectures behave. In order to increase compatibility with
+ * existing (x86) PCI hardware and existing Linux drivers we enable
+ * Soft Faul mode on PA-RISC now too.
+ */
stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL);
+#if defined(ENABLE_HARDFAIL)
WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL);
+#else
+ WRITE_REG32(stat & ~HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL);
+#endif
/*
** Writing a zero to STAT_CTL.rf (bit 0) will clear reset signal
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index ff1a332d76e4..0c6e8b44b4ed 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -176,7 +176,7 @@ static int led_proc_open(struct inode *inode, struct file *file)
}
-static ssize_t led_proc_write(struct file *file, const char *buf,
+static ssize_t led_proc_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
void *data = PDE_DATA(file_inode(file));
@@ -250,7 +250,7 @@ static int __init led_create_procfs(void)
if (led_type == -1) return -1;
- proc_pdc_root = proc_mkdir("pdc", 0);
+ proc_pdc_root = proc_mkdir("pdc", NULL);
if (!proc_pdc_root) return -1;
if (!lcd_no_led_support)
diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c
index e2a3112f1c98..ebaf6867b457 100644
--- a/drivers/parisc/power.c
+++ b/drivers/parisc/power.c
@@ -95,8 +95,7 @@ static void process_shutdown(void)
/* send kill signal */
if (kill_cad_pid(SIGINT, 1)) {
/* just in case killing init process failed */
- if (pm_power_off)
- pm_power_off();
+ machine_power_off();
}
}
}
diff --git a/drivers/parport/parport_ax88796.c b/drivers/parport/parport_ax88796.c
index 2fc91edb058d..bfe97c2a8d4c 100644
--- a/drivers/parport/parport_ax88796.c
+++ b/drivers/parport/parport_ax88796.c
@@ -273,18 +273,16 @@ static int parport_ax88796_probe(struct platform_device *pdev)
{
struct device *_dev = &pdev->dev;
struct ax_drvdata *dd;
- struct parport *pp = NULL;
+ struct parport *pp;
struct resource *res;
unsigned long size;
int spacing;
int irq;
int ret;
- dd = kzalloc(sizeof(struct ax_drvdata), GFP_KERNEL);
- if (dd == NULL) {
- dev_err(_dev, "no memory for private data\n");
+ dd = kzalloc(sizeof(*dd), GFP_KERNEL);
+ if (!dd)
return -ENOMEM;
- }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
index 5f710aaaf3da..190c0a7a1c52 100644
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -256,7 +256,7 @@ struct parport *parport_gsc_probe_port(unsigned long base,
}
priv->ctr = 0xc;
priv->ctr_writable = 0xff;
- priv->dma_buf = 0;
+ priv->dma_buf = NULL;
priv->dma_handle = 0;
p->base = base;
p->base_hi = base_hi;
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 489492b608cf..380916bff9e0 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -2646,6 +2646,7 @@ enum parport_pc_pci_cards {
netmos_9901,
netmos_9865,
quatech_sppxp100,
+ wch_ch382l,
};
@@ -2708,6 +2709,7 @@ static struct parport_pc_pci {
/* netmos_9901 */ { 1, { { 0, -1 }, } },
/* netmos_9865 */ { 1, { { 0, -1 }, } },
/* quatech_sppxp100 */ { 1, { { 0, 1 }, } },
+ /* wch_ch382l */ { 1, { { 2, -1 }, } },
};
static const struct pci_device_id parport_pc_pci_tbl[] = {
@@ -2797,6 +2799,8 @@ static const struct pci_device_id parport_pc_pci_tbl[] = {
/* Quatech SPPXP-100 Parallel port PCI ExpressCard */
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 },
+ /* WCH CH382L PCI-E single parallel port card */
+ { 0x1c00, 0x3050, 0x1c00, 0x3050, 0, 0, wch_ch382l },
{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, parport_pc_pci_tbl);
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index e15b4845f7c6..ae9e01ef7599 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -1,30 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Support for common PCI multi-I/O cards (which is most of them)
*
* Copyright (C) 2001 Tim Waugh <twaugh@redhat.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.
- *
- *
* Multi-function PCI cards are supposed to present separate logical
* devices on the bus. A common thing to do seems to be to just use
* one logical device with lots of base address registers for both
* parallel ports and serial ports. This driver is for dealing with
* that.
- *
*/
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/module.h>
#include <linux/parport.h>
#include <linux/parport_pc.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
#include <linux/8250_pci.h>
enum parport_pc_pci_cards {
@@ -65,6 +59,7 @@ enum parport_pc_pci_cards {
wch_ch353_1s1p,
wch_ch353_2s1p,
wch_ch382_2s1p,
+ brainboxes_5s1p,
sunix_2s1p,
};
@@ -153,12 +148,10 @@ static struct parport_pc_pci cards[] = {
/* wch_ch353_1s1p*/ { 1, { { 1, -1}, } },
/* wch_ch353_2s1p*/ { 1, { { 2, -1}, } },
/* wch_ch382_2s1p*/ { 1, { { 2, -1}, } },
+ /* brainboxes_5s1p */ { 1, { { 3, -1 }, } },
/* sunix_2s1p */ { 1, { { 3, -1 }, } },
};
-#define PCI_VENDOR_ID_SUNIX 0x1fd4
-#define PCI_DEVICE_ID_SUNIX_1999 0x1999
-
static struct pci_device_id parport_serial_pci_tbl[] = {
/* PCI cards */
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L,
@@ -261,6 +254,10 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
{ 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p},
{ 0x1c00, 0x3250, 0x1c00, 0x3250, 0, 0, wch_ch382_2s1p},
+ /* BrainBoxes PX272/PX306 MIO card */
+ { PCI_VENDOR_ID_INTASHIELD, 0x4100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_5s1p },
+
/*
* More SUNIX variations. At least one of these has part number
* '5079A but subdevice 0x102. That board reports 0x0708 as
@@ -504,6 +501,12 @@ static struct pciserial_board pci_parport_serial_boards[] = {
.uart_offset = 8,
.first_offset = 0xC0,
},
+ [brainboxes_5s1p] = {
+ .flags = FL_BASE2,
+ .num_ports = 5,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
[sunix_2s1p] = {
.flags = FL_BASE0|FL_BASE_BARS,
.num_ports = 2,
@@ -527,12 +530,10 @@ static int serial_register(struct pci_dev *dev, const struct pci_device_id *id)
struct serial_private *serial;
board = &pci_parport_serial_boards[id->driver_data];
-
if (board->num_ports == 0)
return 0;
serial = pciserial_init_ports(dev, board);
-
if (IS_ERR(serial))
return PTR_ERR(serial);
@@ -561,10 +562,9 @@ static int parport_register(struct pci_dev *dev, const struct pci_device_id *id)
int irq;
if (priv->num_par == ARRAY_SIZE (priv->port)) {
- printk (KERN_WARNING
- "parport_serial: %s: only %zu parallel ports "
- "supported (%d reported)\n", pci_name (dev),
- ARRAY_SIZE(priv->port), card->numports);
+ dev_warn(&dev->dev,
+ "only %zu parallel ports supported (%d reported)\n",
+ ARRAY_SIZE(priv->port), card->numports);
break;
}
@@ -580,12 +580,12 @@ static int parport_register(struct pci_dev *dev, const struct pci_device_id *id)
irq = dev->irq;
if (irq == IRQ_NONE) {
dev_dbg(&dev->dev,
- "PCI parallel port detected: I/O at %#lx(%#lx)\n",
+ "PCI parallel port detected: I/O at %#lx(%#lx)\n",
io_lo, io_hi);
irq = PARPORT_IRQ_NONE;
} else {
dev_dbg(&dev->dev,
- "PCI parallel port detected: I/O at %#lx(%#lx), IRQ %d\n",
+ "PCI parallel port detected: I/O at %#lx(%#lx), IRQ %d\n",
io_lo, io_hi, irq);
}
port = parport_pc_probe_port (io_lo, io_hi, irq,
@@ -608,28 +608,26 @@ static int parport_serial_pci_probe(struct pci_dev *dev,
struct parport_serial_private *priv;
int err;
- priv = kzalloc (sizeof *priv, GFP_KERNEL);
+ priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+
pci_set_drvdata (dev, priv);
- err = pci_enable_device (dev);
- if (err) {
- kfree (priv);
+ err = pcim_enable_device(dev);
+ if (err)
return err;
- }
- if (parport_register (dev, id)) {
- kfree (priv);
- return -ENODEV;
- }
+ err = parport_register(dev, id);
+ if (err)
+ return err;
- if (serial_register (dev, id)) {
+ err = serial_register(dev, id);
+ if (err) {
int i;
for (i = 0; i < priv->num_par; i++)
parport_pc_unregister_port (priv->port[i]);
- kfree (priv);
- return -ENODEV;
+ return err;
}
return 0;
@@ -648,78 +646,47 @@ static void parport_serial_pci_remove(struct pci_dev *dev)
for (i = 0; i < priv->num_par; i++)
parport_pc_unregister_port (priv->port[i]);
- kfree (priv);
return;
}
-#ifdef CONFIG_PM
-static int parport_serial_pci_suspend(struct pci_dev *dev, pm_message_t state)
+static int __maybe_unused parport_serial_pci_suspend(struct device *dev)
{
- struct parport_serial_private *priv = pci_get_drvdata(dev);
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct parport_serial_private *priv = pci_get_drvdata(pdev);
if (priv->serial)
pciserial_suspend_ports(priv->serial);
/* FIXME: What about parport? */
-
- pci_save_state(dev);
- pci_set_power_state(dev, pci_choose_state(dev, state));
return 0;
}
-static int parport_serial_pci_resume(struct pci_dev *dev)
+static int __maybe_unused parport_serial_pci_resume(struct device *dev)
{
- struct parport_serial_private *priv = pci_get_drvdata(dev);
- int err;
-
- pci_set_power_state(dev, PCI_D0);
- pci_restore_state(dev);
-
- /*
- * The device may have been disabled. Re-enable it.
- */
- err = pci_enable_device(dev);
- if (err) {
- printk(KERN_ERR "parport_serial: %s: error enabling "
- "device for resume (%d)\n", pci_name(dev), err);
- return err;
- }
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct parport_serial_private *priv = pci_get_drvdata(pdev);
if (priv->serial)
pciserial_resume_ports(priv->serial);
/* FIXME: What about parport? */
-
return 0;
}
-#endif
+
+static SIMPLE_DEV_PM_OPS(parport_serial_pm_ops,
+ parport_serial_pci_suspend, parport_serial_pci_resume);
static struct pci_driver parport_serial_pci_driver = {
.name = "parport_serial",
.id_table = parport_serial_pci_tbl,
.probe = parport_serial_pci_probe,
.remove = parport_serial_pci_remove,
-#ifdef CONFIG_PM
- .suspend = parport_serial_pci_suspend,
- .resume = parport_serial_pci_resume,
-#endif
+ .driver = {
+ .pm = &parport_serial_pm_ops,
+ },
};
-
-
-static int __init parport_serial_init (void)
-{
- return pci_register_driver (&parport_serial_pci_driver);
-}
-
-static void __exit parport_serial_exit (void)
-{
- pci_unregister_driver (&parport_serial_pci_driver);
- return;
-}
+module_pci_driver(parport_serial_pci_driver);
MODULE_AUTHOR("Tim Waugh <twaugh@redhat.com>");
MODULE_DESCRIPTION("Driver for common parallel+serial multi-I/O PCI cards");
MODULE_LICENSE("GPL");
-
-module_init(parport_serial_init);
-module_exit(parport_serial_exit);
diff --git a/drivers/perf/arm_pmu_platform.c b/drivers/perf/arm_pmu_platform.c
index 7729eda5909d..971ff336494a 100644
--- a/drivers/perf/arm_pmu_platform.c
+++ b/drivers/perf/arm_pmu_platform.c
@@ -122,7 +122,7 @@ static int pmu_parse_irqs(struct arm_pmu *pmu)
return pmu_parse_percpu_irq(pmu, irq);
}
- if (!pmu_has_irq_affinity(pdev->dev.of_node)) {
+ if (nr_cpu_ids != 1 && !pmu_has_irq_affinity(pdev->dev.of_node)) {
pr_warn("no interrupt-affinity property for %pOF, guessing.\n",
pdev->dev.of_node);
}
diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c
index 51b40aecb776..28bb642af18b 100644
--- a/drivers/perf/arm_spe_pmu.c
+++ b/drivers/perf/arm_spe_pmu.c
@@ -23,16 +23,30 @@
#define DRVNAME PMUNAME "_pmu"
#define pr_fmt(fmt) DRVNAME ": " fmt
+#include <linux/bitops.h>
+#include <linux/bug.h>
+#include <linux/capability.h>
#include <linux/cpuhotplug.h>
+#include <linux/cpumask.h>
+#include <linux/device.h>
+#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/perf_event.h>
#include <linux/platform_device.h>
+#include <linux/printk.h>
#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/vmalloc.h>
+#include <asm/barrier.h>
+#include <asm/cpufeature.h>
+#include <asm/mmu.h>
#include <asm/sysreg.h>
#define ARM_SPE_BUF_PAD_BYTE 0
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index aa857be692cf..d4dcd39b8d76 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -112,6 +112,7 @@ enum sun4i_usb_phy_type {
sun8i_a33_phy,
sun8i_a83t_phy,
sun8i_h3_phy,
+ sun8i_r40_phy,
sun8i_v3s_phy,
sun50i_a64_phy,
};
@@ -410,11 +411,13 @@ static bool sun4i_usb_phy0_poll(struct sun4i_usb_phy_data *data)
return true;
/*
- * The A31 companion pmic (axp221) does not generate vbus change
- * interrupts when the board is driving vbus, so we must poll
+ * The A31/A23/A33 companion pmics (AXP221/AXP223) do not
+ * generate vbus change interrupts when the board is driving
+ * vbus using the N_VBUSEN pin on the pmic, so we must poll
* when using the pmic for vbus-det _and_ we're driving vbus.
*/
- if (data->cfg->type == sun6i_a31_phy &&
+ if ((data->cfg->type == sun6i_a31_phy ||
+ data->cfg->type == sun8i_a33_phy) &&
data->vbus_power_supply && data->phys[0].regulator_on)
return true;
@@ -885,7 +888,7 @@ static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
.num_phys = 2,
- .type = sun4i_a10_phy,
+ .type = sun6i_a31_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A10,
.dedicated_clocks = true,
@@ -919,6 +922,16 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
.phy0_dual_route = true,
};
+static const struct sun4i_usb_phy_cfg sun8i_r40_cfg = {
+ .num_phys = 3,
+ .type = sun8i_r40_phy,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A33,
+ .dedicated_clocks = true,
+ .enable_pmu_unk1 = true,
+ .phy0_dual_route = true,
+};
+
static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
.num_phys = 1,
.type = sun8i_v3s_phy,
@@ -948,6 +961,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = {
{ .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg },
{ .compatible = "allwinner,sun8i-a83t-usb-phy", .data = &sun8i_a83t_cfg },
{ .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg },
+ { .compatible = "allwinner,sun8i-r40-usb-phy", .data = &sun8i_r40_cfg },
{ .compatible = "allwinner,sun8i-v3s-usb-phy", .data = &sun8i_v3s_cfg },
{ .compatible = "allwinner,sun50i-a64-usb-phy",
.data = &sun50i_a64_cfg},
diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
index cb8f4501652b..23fe1cda2f70 100644
--- a/drivers/phy/amlogic/Kconfig
+++ b/drivers/phy/amlogic/Kconfig
@@ -18,10 +18,21 @@ config PHY_MESON_GXL_USB2
default ARCH_MESON
depends on OF && (ARCH_MESON || COMPILE_TEST)
depends on USB_SUPPORT
- select USB_COMMON
select GENERIC_PHY
select REGMAP_MMIO
help
Enable this to support the Meson USB2 PHYs found in Meson
GXL and GXM SoCs.
If unsure, say N.
+
+config PHY_MESON_GXL_USB3
+ tristate "Meson GXL and GXM USB3 PHY drivers"
+ default ARCH_MESON
+ depends on OF && (ARCH_MESON || COMPILE_TEST)
+ depends on USB_SUPPORT
+ select GENERIC_PHY
+ select REGMAP_MMIO
+ help
+ Enable this to support the Meson USB3 PHY and OTG detection
+ IP block found in Meson GXL and GXM SoCs.
+ If unsure, say N.
diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile
index cfdc98715c30..4fd8848c194d 100644
--- a/drivers/phy/amlogic/Makefile
+++ b/drivers/phy/amlogic/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
obj-$(CONFIG_PHY_MESON_GXL_USB2) += phy-meson-gxl-usb2.o
+obj-$(CONFIG_PHY_MESON_GXL_USB3) += phy-meson-gxl-usb3.o
diff --git a/drivers/phy/amlogic/phy-meson-gxl-usb2.c b/drivers/phy/amlogic/phy-meson-gxl-usb2.c
index e90c4ee25dfe..9f9b5414b97a 100644
--- a/drivers/phy/amlogic/phy-meson-gxl-usb2.c
+++ b/drivers/phy/amlogic/phy-meson-gxl-usb2.c
@@ -11,14 +11,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
+#include <linux/reset.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
-#include <linux/usb/of.h>
/* bits [31:27] are read-only */
#define U2P_R0 0x0
@@ -70,12 +71,11 @@
/* bits [31:14] are read-only */
#define U2P_R2 0x8
- #define U2P_R2_DATA_IN_MASK GENMASK(3, 0)
- #define U2P_R2_DATA_IN_EN_MASK GENMASK(7, 4)
- #define U2P_R2_ADDR_MASK GENMASK(11, 8)
- #define U2P_R2_DATA_OUT_SEL BIT(12)
- #define U2P_R2_CLK BIT(13)
- #define U2P_R2_DATA_OUT_MASK GENMASK(17, 14)
+ #define U2P_R2_TESTDATA_IN_MASK GENMASK(7, 0)
+ #define U2P_R2_TESTADDR_MASK GENMASK(11, 8)
+ #define U2P_R2_TESTDATA_OUT_SEL BIT(12)
+ #define U2P_R2_TESTCLK BIT(13)
+ #define U2P_R2_TESTDATA_OUT_MASK GENMASK(17, 14)
#define U2P_R2_ACA_PIN_RANGE_C BIT(18)
#define U2P_R2_ACA_PIN_RANGE_B BIT(19)
#define U2P_R2_ACA_PIN_RANGE_A BIT(20)
@@ -99,6 +99,8 @@ struct phy_meson_gxl_usb2_priv {
struct regmap *regmap;
enum phy_mode mode;
int is_enabled;
+ struct clk *clk;
+ struct reset_control *reset;
};
static const struct regmap_config phy_meson_gxl_usb2_regmap_conf = {
@@ -108,6 +110,31 @@ static const struct regmap_config phy_meson_gxl_usb2_regmap_conf = {
.max_register = U2P_R3,
};
+static int phy_meson_gxl_usb2_init(struct phy *phy)
+{
+ struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
+ int ret;
+
+ ret = reset_control_reset(priv->reset);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb2_exit(struct phy *phy)
+{
+ struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
+
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
static int phy_meson_gxl_usb2_reset(struct phy *phy)
{
struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
@@ -195,6 +222,8 @@ static int phy_meson_gxl_usb2_power_on(struct phy *phy)
}
static const struct phy_ops phy_meson_gxl_usb2_ops = {
+ .init = phy_meson_gxl_usb2_init,
+ .exit = phy_meson_gxl_usb2_exit,
.power_on = phy_meson_gxl_usb2_power_on,
.power_off = phy_meson_gxl_usb2_power_off,
.set_mode = phy_meson_gxl_usb2_set_mode,
@@ -210,6 +239,7 @@ static int phy_meson_gxl_usb2_probe(struct platform_device *pdev)
struct phy_meson_gxl_usb2_priv *priv;
struct phy *phy;
void __iomem *base;
+ int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -222,28 +252,34 @@ static int phy_meson_gxl_usb2_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
- switch (of_usb_get_dr_mode_by_phy(dev->of_node, -1)) {
- case USB_DR_MODE_PERIPHERAL:
- priv->mode = PHY_MODE_USB_DEVICE;
- break;
- case USB_DR_MODE_OTG:
- priv->mode = PHY_MODE_USB_OTG;
- break;
- case USB_DR_MODE_HOST:
- default:
- priv->mode = PHY_MODE_USB_HOST;
- break;
- }
+ /* start in host mode */
+ priv->mode = PHY_MODE_USB_HOST;
priv->regmap = devm_regmap_init_mmio(dev, base,
&phy_meson_gxl_usb2_regmap_conf);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
+ priv->clk = devm_clk_get(dev, "phy");
+ if (IS_ERR(priv->clk)) {
+ ret = PTR_ERR(priv->clk);
+ if (ret == -ENOENT)
+ priv->clk = NULL;
+ else
+ return ret;
+ }
+
+ priv->reset = devm_reset_control_get_optional_shared(dev, "phy");
+ if (IS_ERR(priv->reset))
+ return PTR_ERR(priv->reset);
+
phy = devm_phy_create(dev, NULL, &phy_meson_gxl_usb2_ops);
if (IS_ERR(phy)) {
- dev_err(dev, "failed to create PHY\n");
- return PTR_ERR(phy);
+ ret = PTR_ERR(phy);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to create PHY\n");
+
+ return ret;
}
phy_set_drvdata(phy, priv);
diff --git a/drivers/phy/amlogic/phy-meson-gxl-usb3.c b/drivers/phy/amlogic/phy-meson-gxl-usb3.c
new file mode 100644
index 000000000000..d37d94ddf9c0
--- /dev/null
+++ b/drivers/phy/amlogic/phy-meson-gxl-usb3.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Meson GXL USB3 PHY and OTG mode detection driver
+ *
+ * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/platform_device.h>
+
+#define USB_R0 0x00
+ #define USB_R0_P30_FSEL_MASK GENMASK(5, 0)
+ #define USB_R0_P30_PHY_RESET BIT(6)
+ #define USB_R0_P30_TEST_POWERDOWN_HSP BIT(7)
+ #define USB_R0_P30_TEST_POWERDOWN_SSP BIT(8)
+ #define USB_R0_P30_ACJT_LEVEL_MASK GENMASK(13, 9)
+ #define USB_R0_P30_TX_BOOST_LEVEL_MASK GENMASK(16, 14)
+ #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17)
+ #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18)
+ #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19)
+ #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29)
+ #define USB_R0_U2D_ACT BIT(31)
+
+#define USB_R1 0x04
+ #define USB_R1_U3H_BIGENDIAN_GS BIT(0)
+ #define USB_R1_U3H_PME_ENABLE BIT(1)
+ #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(6, 2)
+ #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(11, 7)
+ #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(15, 12)
+ #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16)
+ #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17)
+ #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18)
+ #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19)
+ #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25)
+
+#define USB_R2 0x08
+ #define USB_R2_P30_CR_DATA_IN_MASK GENMASK(15, 0)
+ #define USB_R2_P30_CR_READ BIT(16)
+ #define USB_R2_P30_CR_WRITE BIT(17)
+ #define USB_R2_P30_CR_CAP_ADDR BIT(18)
+ #define USB_R2_P30_CR_CAP_DATA BIT(19)
+ #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20)
+ #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26)
+
+#define USB_R3 0x0c
+ #define USB_R3_P30_SSC_ENABLE BIT(0)
+ #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1)
+ #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4)
+ #define USB_R3_P30_REF_SSP_EN BIT(13)
+ #define USB_R3_P30_LOS_BIAS_MASK GENMASK(18, 16)
+ #define USB_R3_P30_LOS_LEVEL_MASK GENMASK(23, 19)
+ #define USB_R3_P30_MPLL_MULTIPLIER_MASK GENMASK(30, 24)
+
+#define USB_R4 0x10
+ #define USB_R4_P21_PORT_RESET_0 BIT(0)
+ #define USB_R4_P21_SLEEP_M0 BIT(1)
+ #define USB_R4_MEM_PD_MASK GENMASK(3, 2)
+ #define USB_R4_P21_ONLY BIT(4)
+
+#define USB_R5 0x14
+ #define USB_R5_ID_DIG_SYNC BIT(0)
+ #define USB_R5_ID_DIG_REG BIT(1)
+ #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2)
+ #define USB_R5_ID_DIG_EN_0 BIT(4)
+ #define USB_R5_ID_DIG_EN_1 BIT(5)
+ #define USB_R5_ID_DIG_CURR BIT(6)
+ #define USB_R5_ID_DIG_IRQ BIT(7)
+ #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8)
+ #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16)
+
+/* read-only register */
+#define USB_R6 0x18
+ #define USB_R6_P30_CR_DATA_OUT_MASK GENMASK(15, 0)
+ #define USB_R6_P30_CR_ACK BIT(16)
+
+struct phy_meson_gxl_usb3_priv {
+ struct regmap *regmap;
+ enum phy_mode mode;
+ struct clk *clk_phy;
+ struct clk *clk_peripheral;
+ struct reset_control *reset;
+};
+
+static const struct regmap_config phy_meson_gxl_usb3_regmap_conf = {
+ .reg_bits = 8,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = USB_R6,
+};
+
+static int phy_meson_gxl_usb3_power_on(struct phy *phy)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0,
+ USB_R5_ID_DIG_EN_0);
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1,
+ USB_R5_ID_DIG_EN_1);
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_TH_MASK,
+ FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff));
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb3_power_off(struct phy *phy)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0, 0);
+ regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1, 0);
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb3_set_mode(struct phy *phy, enum phy_mode mode)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+
+ switch (mode) {
+ case PHY_MODE_USB_HOST:
+ regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT, 0);
+ regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
+ 0);
+ break;
+
+ case PHY_MODE_USB_DEVICE:
+ regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT,
+ USB_R0_U2D_ACT);
+ regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
+ USB_R4_P21_SLEEP_M0);
+ break;
+
+ default:
+ dev_err(&phy->dev, "unsupported PHY mode %d\n", mode);
+ return -EINVAL;
+ }
+
+ priv->mode = mode;
+
+ return 0;
+}
+
+static int phy_meson_gxl_usb3_init(struct phy *phy)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+ int ret;
+
+ ret = reset_control_reset(priv->reset);
+ if (ret)
+ goto err;
+
+ ret = clk_prepare_enable(priv->clk_phy);
+ if (ret)
+ goto err;
+
+ ret = clk_prepare_enable(priv->clk_peripheral);
+ if (ret)
+ goto err_disable_clk_phy;
+
+ ret = phy_meson_gxl_usb3_set_mode(phy, priv->mode);
+ if (ret)
+ goto err_disable_clk_peripheral;
+
+ regmap_update_bits(priv->regmap, USB_R1,
+ USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
+ FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
+
+ return 0;
+
+err_disable_clk_peripheral:
+ clk_disable_unprepare(priv->clk_peripheral);
+err_disable_clk_phy:
+ clk_disable_unprepare(priv->clk_phy);
+err:
+ return ret;
+}
+
+static int phy_meson_gxl_usb3_exit(struct phy *phy)
+{
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
+
+ clk_disable_unprepare(priv->clk_peripheral);
+ clk_disable_unprepare(priv->clk_phy);
+
+ return 0;
+}
+
+static const struct phy_ops phy_meson_gxl_usb3_ops = {
+ .power_on = phy_meson_gxl_usb3_power_on,
+ .power_off = phy_meson_gxl_usb3_power_off,
+ .set_mode = phy_meson_gxl_usb3_set_mode,
+ .init = phy_meson_gxl_usb3_init,
+ .exit = phy_meson_gxl_usb3_exit,
+ .owner = THIS_MODULE,
+};
+
+static int phy_meson_gxl_usb3_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct phy_meson_gxl_usb3_priv *priv;
+ struct resource *res;
+ struct phy *phy;
+ struct phy_provider *phy_provider;
+ void __iomem *base;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ priv->regmap = devm_regmap_init_mmio(dev, base,
+ &phy_meson_gxl_usb3_regmap_conf);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ priv->clk_phy = devm_clk_get(dev, "phy");
+ if (IS_ERR(priv->clk_phy))
+ return PTR_ERR(priv->clk_phy);
+
+ priv->clk_peripheral = devm_clk_get(dev, "peripheral");
+ if (IS_ERR(priv->clk_peripheral))
+ return PTR_ERR(priv->clk_peripheral);
+
+ priv->reset = devm_reset_control_array_get_shared(dev);
+ if (IS_ERR(priv->reset))
+ return PTR_ERR(priv->reset);
+
+ /*
+ * default to host mode as hardware defaults and/or boot-loader
+ * behavior can result in this PHY starting up in device mode. this
+ * default and the initialization in phy_meson_gxl_usb3_init ensure
+ * that we reproducibly start in a known mode on all devices.
+ */
+ priv->mode = PHY_MODE_USB_HOST;
+
+ phy = devm_phy_create(dev, np, &phy_meson_gxl_usb3_ops);
+ if (IS_ERR(phy)) {
+ ret = PTR_ERR(phy);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to create PHY\n");
+
+ return ret;
+ }
+
+ phy_set_drvdata(phy, priv);
+
+ 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 phy_meson_gxl_usb3_of_match[] = {
+ { .compatible = "amlogic,meson-gxl-usb3-phy", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb3_of_match);
+
+static struct platform_driver phy_meson_gxl_usb3_driver = {
+ .probe = phy_meson_gxl_usb3_probe,
+ .driver = {
+ .name = "phy-meson-gxl-usb3",
+ .of_match_table = phy_meson_gxl_usb3_of_match,
+ },
+};
+module_platform_driver(phy_meson_gxl_usb3_driver);
+
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
+MODULE_DESCRIPTION("Meson GXL USB3 PHY and OTG detection driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/hisilicon/Kconfig b/drivers/phy/hisilicon/Kconfig
index 6164c4cd0f65..b40ee54a1a50 100644
--- a/drivers/phy/hisilicon/Kconfig
+++ b/drivers/phy/hisilicon/Kconfig
@@ -4,6 +4,7 @@
config PHY_HI6220_USB
tristate "hi6220 USB PHY support"
depends on (ARCH_HISI && ARM64) || COMPILE_TEST
+ depends on HAS_IOMEM
select GENERIC_PHY
select MFD_SYSCON
help
@@ -11,6 +12,25 @@ config PHY_HI6220_USB
To compile this driver as a module, choose M here.
+config PHY_HISTB_COMBPHY
+ tristate "HiSilicon STB SoCs COMBPHY support"
+ depends on (ARCH_HISI && ARM64) || COMPILE_TEST
+ select GENERIC_PHY
+ select MFD_SYSCON
+ help
+ Enable this to support the HISILICON STB SoCs COMBPHY.
+ If unsure, say N.
+
+config PHY_HISI_INNO_USB2
+ tristate "HiSilicon INNO USB2 PHY support"
+ depends on (ARCH_HISI && ARM64) || COMPILE_TEST
+ select GENERIC_PHY
+ select MFD_SYSCON
+ help
+ Support for INNO USB2 PHY on HiSilicon SoCs. This Phy supports
+ USB 1.5Mb/s, USB 12Mb/s, USB 480Mb/s speeds. It supports one
+ USB host port to accept one USB device.
+
config PHY_HIX5HD2_SATA
tristate "HIX5HD2 SATA PHY Driver"
depends on ARCH_HIX5HD2 && OF && HAS_IOMEM
diff --git a/drivers/phy/hisilicon/Makefile b/drivers/phy/hisilicon/Makefile
index 541b348187a8..f662a4fe18d8 100644
--- a/drivers/phy/hisilicon/Makefile
+++ b/drivers/phy/hisilicon/Makefile
@@ -1,2 +1,4 @@
obj-$(CONFIG_PHY_HI6220_USB) += phy-hi6220-usb.o
+obj-$(CONFIG_PHY_HISTB_COMBPHY) += phy-histb-combphy.o
+obj-$(CONFIG_PHY_HISI_INNO_USB2) += phy-hisi-inno-usb2.o
obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o
diff --git a/drivers/phy/hisilicon/phy-hisi-inno-usb2.c b/drivers/phy/hisilicon/phy-hisi-inno-usb2.c
new file mode 100644
index 000000000000..524381249a2b
--- /dev/null
+++ b/drivers/phy/hisilicon/phy-hisi-inno-usb2.c
@@ -0,0 +1,197 @@
+/*
+ * HiSilicon INNO USB2 PHY Driver.
+ *
+ * Copyright (c) 2016-2017 HiSilicon Technologies Co., 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.
+ *
+ * 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/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+#include <linux/reset.h>
+
+#define INNO_PHY_PORT_NUM 2
+#define REF_CLK_STABLE_TIME 100 /* unit:us */
+#define UTMI_CLK_STABLE_TIME 200 /* unit:us */
+#define TEST_CLK_STABLE_TIME 2 /* unit:ms */
+#define PHY_CLK_STABLE_TIME 2 /* unit:ms */
+#define UTMI_RST_COMPLETE_TIME 2 /* unit:ms */
+#define POR_RST_COMPLETE_TIME 300 /* unit:us */
+#define PHY_TEST_DATA GENMASK(7, 0)
+#define PHY_TEST_ADDR GENMASK(15, 8)
+#define PHY_TEST_PORT GENMASK(18, 16)
+#define PHY_TEST_WREN BIT(21)
+#define PHY_TEST_CLK BIT(22) /* rising edge active */
+#define PHY_TEST_RST BIT(23) /* low active */
+#define PHY_CLK_ENABLE BIT(2)
+
+struct hisi_inno_phy_port {
+ struct reset_control *utmi_rst;
+ struct hisi_inno_phy_priv *priv;
+};
+
+struct hisi_inno_phy_priv {
+ void __iomem *mmio;
+ struct clk *ref_clk;
+ struct reset_control *por_rst;
+ struct hisi_inno_phy_port ports[INNO_PHY_PORT_NUM];
+};
+
+static void hisi_inno_phy_write_reg(struct hisi_inno_phy_priv *priv,
+ u8 port, u32 addr, u32 data)
+{
+ void __iomem *reg = priv->mmio;
+ u32 val;
+
+ val = (data & PHY_TEST_DATA) |
+ ((addr << 8) & PHY_TEST_ADDR) |
+ ((port << 16) & PHY_TEST_PORT) |
+ PHY_TEST_WREN | PHY_TEST_RST;
+ writel(val, reg);
+
+ val |= PHY_TEST_CLK;
+ writel(val, reg);
+
+ val &= ~PHY_TEST_CLK;
+ writel(val, reg);
+}
+
+static void hisi_inno_phy_setup(struct hisi_inno_phy_priv *priv)
+{
+ /* The phy clk is controlled by the port0 register 0x06. */
+ hisi_inno_phy_write_reg(priv, 0, 0x06, PHY_CLK_ENABLE);
+ msleep(PHY_CLK_STABLE_TIME);
+}
+
+static int hisi_inno_phy_init(struct phy *phy)
+{
+ struct hisi_inno_phy_port *port = phy_get_drvdata(phy);
+ struct hisi_inno_phy_priv *priv = port->priv;
+ int ret;
+
+ ret = clk_prepare_enable(priv->ref_clk);
+ if (ret)
+ return ret;
+ udelay(REF_CLK_STABLE_TIME);
+
+ reset_control_deassert(priv->por_rst);
+ udelay(POR_RST_COMPLETE_TIME);
+
+ /* Set up phy registers */
+ hisi_inno_phy_setup(priv);
+
+ reset_control_deassert(port->utmi_rst);
+ udelay(UTMI_RST_COMPLETE_TIME);
+
+ return 0;
+}
+
+static int hisi_inno_phy_exit(struct phy *phy)
+{
+ struct hisi_inno_phy_port *port = phy_get_drvdata(phy);
+ struct hisi_inno_phy_priv *priv = port->priv;
+
+ reset_control_assert(port->utmi_rst);
+ reset_control_assert(priv->por_rst);
+ clk_disable_unprepare(priv->ref_clk);
+
+ return 0;
+}
+
+static const struct phy_ops hisi_inno_phy_ops = {
+ .init = hisi_inno_phy_init,
+ .exit = hisi_inno_phy_exit,
+ .owner = THIS_MODULE,
+};
+
+static int hisi_inno_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct hisi_inno_phy_priv *priv;
+ struct phy_provider *provider;
+ struct device_node *child;
+ struct resource *res;
+ int i = 0;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->mmio = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->mmio)) {
+ ret = PTR_ERR(priv->mmio);
+ return ret;
+ }
+
+ priv->ref_clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->ref_clk))
+ return PTR_ERR(priv->ref_clk);
+
+ priv->por_rst = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(priv->por_rst))
+ return PTR_ERR(priv->por_rst);
+
+ for_each_child_of_node(np, child) {
+ struct reset_control *rst;
+ struct phy *phy;
+
+ rst = of_reset_control_get_exclusive(child, NULL);
+ if (IS_ERR(rst))
+ return PTR_ERR(rst);
+ priv->ports[i].utmi_rst = rst;
+ priv->ports[i].priv = priv;
+
+ phy = devm_phy_create(dev, child, &hisi_inno_phy_ops);
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+
+ phy_set_bus_width(phy, 8);
+ phy_set_drvdata(phy, &priv->ports[i]);
+ i++;
+
+ if (i > INNO_PHY_PORT_NUM) {
+ dev_warn(dev, "Support %d ports in maximum\n", i);
+ break;
+ }
+ }
+
+ provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ return PTR_ERR_OR_ZERO(provider);
+}
+
+static const struct of_device_id hisi_inno_phy_of_match[] = {
+ { .compatible = "hisilicon,inno-usb2-phy", },
+ { .compatible = "hisilicon,hi3798cv200-usb2-phy", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, hisi_inno_phy_of_match);
+
+static struct platform_driver hisi_inno_phy_driver = {
+ .probe = hisi_inno_phy_probe,
+ .driver = {
+ .name = "hisi-inno-phy",
+ .of_match_table = hisi_inno_phy_of_match,
+ }
+};
+module_platform_driver(hisi_inno_phy_driver);
+
+MODULE_DESCRIPTION("HiSilicon INNO USB2 PHY Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/hisilicon/phy-histb-combphy.c b/drivers/phy/hisilicon/phy-histb-combphy.c
new file mode 100644
index 000000000000..5777b3120017
--- /dev/null
+++ b/drivers/phy/hisilicon/phy-histb-combphy.c
@@ -0,0 +1,289 @@
+/*
+ * COMBPHY driver for HiSilicon STB SoCs
+ *
+ * Copyright (C) 2016-2017 HiSilicon Co., Ltd. http://www.hisilicon.com
+ *
+ * Authors: Jianguo Sun <sunjianguo1@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/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <dt-bindings/phy/phy.h>
+
+#define COMBPHY_MODE_PCIE 0
+#define COMBPHY_MODE_USB3 1
+#define COMBPHY_MODE_SATA 2
+
+#define COMBPHY_CFG_REG 0x0
+#define COMBPHY_BYPASS_CODEC BIT(31)
+#define COMBPHY_TEST_WRITE BIT(24)
+#define COMBPHY_TEST_DATA_SHIFT 20
+#define COMBPHY_TEST_DATA_MASK GENMASK(23, 20)
+#define COMBPHY_TEST_ADDR_SHIFT 12
+#define COMBPHY_TEST_ADDR_MASK GENMASK(16, 12)
+#define COMBPHY_CLKREF_OUT_OEN BIT(0)
+
+struct histb_combphy_mode {
+ int fixed;
+ int select;
+ u32 reg;
+ u32 shift;
+ u32 mask;
+};
+
+struct histb_combphy_priv {
+ void __iomem *mmio;
+ struct regmap *syscon;
+ struct reset_control *por_rst;
+ struct clk *ref_clk;
+ struct phy *phy;
+ struct histb_combphy_mode mode;
+};
+
+static void nano_register_write(struct histb_combphy_priv *priv,
+ u32 addr, u32 data)
+{
+ void __iomem *reg = priv->mmio + COMBPHY_CFG_REG;
+ u32 val;
+
+ /* Set up address and data for the write */
+ val = readl(reg);
+ val &= ~COMBPHY_TEST_ADDR_MASK;
+ val |= addr << COMBPHY_TEST_ADDR_SHIFT;
+ val &= ~COMBPHY_TEST_DATA_MASK;
+ val |= data << COMBPHY_TEST_DATA_SHIFT;
+ writel(val, reg);
+
+ /* Flip strobe control to trigger the write */
+ val &= ~COMBPHY_TEST_WRITE;
+ writel(val, reg);
+ val |= COMBPHY_TEST_WRITE;
+ writel(val, reg);
+}
+
+static int is_mode_fixed(struct histb_combphy_mode *mode)
+{
+ return (mode->fixed != PHY_NONE) ? true : false;
+}
+
+static int histb_combphy_set_mode(struct histb_combphy_priv *priv)
+{
+ struct histb_combphy_mode *mode = &priv->mode;
+ struct regmap *syscon = priv->syscon;
+ u32 hw_sel;
+
+ if (is_mode_fixed(mode))
+ return 0;
+
+ switch (mode->select) {
+ case PHY_TYPE_SATA:
+ hw_sel = COMBPHY_MODE_SATA;
+ break;
+ case PHY_TYPE_PCIE:
+ hw_sel = COMBPHY_MODE_PCIE;
+ break;
+ case PHY_TYPE_USB3:
+ hw_sel = COMBPHY_MODE_USB3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(syscon, mode->reg, mode->mask,
+ hw_sel << mode->shift);
+}
+
+static int histb_combphy_init(struct phy *phy)
+{
+ struct histb_combphy_priv *priv = phy_get_drvdata(phy);
+ u32 val;
+ int ret;
+
+ ret = histb_combphy_set_mode(priv);
+ if (ret)
+ return ret;
+
+ /* Clear bypass bit to enable encoding/decoding */
+ val = readl(priv->mmio + COMBPHY_CFG_REG);
+ val &= ~COMBPHY_BYPASS_CODEC;
+ writel(val, priv->mmio + COMBPHY_CFG_REG);
+
+ ret = clk_prepare_enable(priv->ref_clk);
+ if (ret)
+ return ret;
+
+ reset_control_deassert(priv->por_rst);
+
+ /* Enable EP clock */
+ val = readl(priv->mmio + COMBPHY_CFG_REG);
+ val |= COMBPHY_CLKREF_OUT_OEN;
+ writel(val, priv->mmio + COMBPHY_CFG_REG);
+
+ /* Need to wait for EP clock stable */
+ mdelay(5);
+
+ /* Configure nano phy registers as suggested by vendor */
+ nano_register_write(priv, 0x1, 0x8);
+ nano_register_write(priv, 0xc, 0x9);
+ nano_register_write(priv, 0x1a, 0x4);
+
+ return 0;
+}
+
+static int histb_combphy_exit(struct phy *phy)
+{
+ struct histb_combphy_priv *priv = phy_get_drvdata(phy);
+ u32 val;
+
+ /* Disable EP clock */
+ val = readl(priv->mmio + COMBPHY_CFG_REG);
+ val &= ~COMBPHY_CLKREF_OUT_OEN;
+ writel(val, priv->mmio + COMBPHY_CFG_REG);
+
+ reset_control_assert(priv->por_rst);
+ clk_disable_unprepare(priv->ref_clk);
+
+ return 0;
+}
+
+static const struct phy_ops histb_combphy_ops = {
+ .init = histb_combphy_init,
+ .exit = histb_combphy_exit,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *histb_combphy_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct histb_combphy_priv *priv = dev_get_drvdata(dev);
+ struct histb_combphy_mode *mode = &priv->mode;
+
+ if (args->args_count < 1) {
+ dev_err(dev, "invalid number of arguments\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ mode->select = args->args[0];
+
+ if (mode->select < PHY_TYPE_SATA || mode->select > PHY_TYPE_USB3) {
+ dev_err(dev, "invalid phy mode select argument\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (is_mode_fixed(mode) && mode->select != mode->fixed) {
+ dev_err(dev, "mode select %d mismatch fixed phy mode %d\n",
+ mode->select, mode->fixed);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return priv->phy;
+}
+
+static int histb_combphy_probe(struct platform_device *pdev)
+{
+ struct phy_provider *phy_provider;
+ struct device *dev = &pdev->dev;
+ struct histb_combphy_priv *priv;
+ struct device_node *np = dev->of_node;
+ struct histb_combphy_mode *mode;
+ struct resource *res;
+ u32 vals[3];
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->mmio = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->mmio)) {
+ ret = PTR_ERR(priv->mmio);
+ return ret;
+ }
+
+ priv->syscon = syscon_node_to_regmap(np->parent);
+ if (IS_ERR(priv->syscon)) {
+ dev_err(dev, "failed to find peri_ctrl syscon regmap\n");
+ return PTR_ERR(priv->syscon);
+ }
+
+ mode = &priv->mode;
+ mode->fixed = PHY_NONE;
+
+ ret = of_property_read_u32(np, "hisilicon,fixed-mode", &mode->fixed);
+ if (ret == 0)
+ dev_dbg(dev, "found fixed phy mode %d\n", mode->fixed);
+
+ ret = of_property_read_u32_array(np, "hisilicon,mode-select-bits",
+ vals, ARRAY_SIZE(vals));
+ if (ret == 0) {
+ if (is_mode_fixed(mode)) {
+ dev_err(dev, "found select bits for fixed mode phy\n");
+ return -EINVAL;
+ }
+
+ mode->reg = vals[0];
+ mode->shift = vals[1];
+ mode->mask = vals[2];
+ dev_dbg(dev, "found mode select bits\n");
+ } else {
+ if (!is_mode_fixed(mode)) {
+ dev_err(dev, "no valid select bits found for non-fixed phy\n");
+ return -ENODEV;
+ }
+ }
+
+ priv->ref_clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->ref_clk)) {
+ dev_err(dev, "failed to find ref clock\n");
+ return PTR_ERR(priv->ref_clk);
+ }
+
+ priv->por_rst = devm_reset_control_get(dev, NULL);
+ if (IS_ERR(priv->por_rst)) {
+ dev_err(dev, "failed to get poweron reset\n");
+ return PTR_ERR(priv->por_rst);
+ }
+
+ priv->phy = devm_phy_create(dev, NULL, &histb_combphy_ops);
+ if (IS_ERR(priv->phy)) {
+ dev_err(dev, "failed to create combphy\n");
+ return PTR_ERR(priv->phy);
+ }
+
+ dev_set_drvdata(dev, priv);
+ phy_set_drvdata(priv->phy, priv);
+
+ phy_provider = devm_of_phy_provider_register(dev, histb_combphy_xlate);
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id histb_combphy_of_match[] = {
+ { .compatible = "hisilicon,hi3798cv200-combphy" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, histb_combphy_of_match);
+
+static struct platform_driver histb_combphy_driver = {
+ .probe = histb_combphy_probe,
+ .driver = {
+ .name = "combphy",
+ .of_match_table = histb_combphy_of_match,
+ },
+};
+module_platform_driver(histb_combphy_driver);
+
+MODULE_DESCRIPTION("HiSilicon STB COMBPHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/marvell/phy-berlin-usb.c b/drivers/phy/marvell/phy-berlin-usb.c
index 2017751ede26..8f2b5cae360f 100644
--- a/drivers/phy/marvell/phy-berlin-usb.c
+++ b/drivers/phy/marvell/phy-berlin-usb.c
@@ -127,7 +127,7 @@ static int phy_berlin_usb_power_on(struct phy *phy)
writel(V2I_VCO_RATIO(0x5) | R_ROTATE_0 | ANA_TEST_DC_CTRL(0x5),
priv->base + USB_PHY_ANALOG);
writel(PHASE_FREEZE_DLY_4_CL | ACK_LENGTH_16_CL | SQ_LENGTH_12 |
- DISCON_THRESHOLD_260 | SQ_THRESHOLD(0xa) | LPF_COEF(0x2) |
+ DISCON_THRESHOLD_270 | SQ_THRESHOLD(0xa) | LPF_COEF(0x2) |
INTPL_CUR_30, priv->base + USB_PHY_RX_CTRL);
writel(TX_VDD12_13 | TX_OUT_AMP(0x3), priv->base + USB_PHY_TX_CTRL1);
diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c
index 1e96d0740ef5..38c281b5abbb 100644
--- a/drivers/phy/mediatek/phy-mtk-tphy.c
+++ b/drivers/phy/mediatek/phy-mtk-tphy.c
@@ -306,6 +306,8 @@ struct mtk_tphy {
const struct mtk_phy_pdata *pdata;
struct mtk_phy_instance **phys;
int nphys;
+ int src_ref_clk; /* MHZ, reference clock for slew rate calibrate */
+ int src_coef; /* coefficient for slew rate calibrate */
};
static void hs_slew_rate_calibrate(struct mtk_tphy *tphy,
@@ -360,16 +362,17 @@ static void hs_slew_rate_calibrate(struct mtk_tphy *tphy,
writel(tmp, fmreg + U3P_U2FREQ_FMMONR1);
if (fm_out) {
- /* ( 1024 / FM_OUT ) x reference clock frequency x 0.028 */
- tmp = U3P_FM_DET_CYCLE_CNT * U3P_REF_CLK * U3P_SLEW_RATE_COEF;
- tmp /= fm_out;
+ /* ( 1024 / FM_OUT ) x reference clock frequency x coef */
+ tmp = tphy->src_ref_clk * tphy->src_coef;
+ tmp = (tmp * U3P_FM_DET_CYCLE_CNT) / fm_out;
calibration_val = DIV_ROUND_CLOSEST(tmp, U3P_SR_COEF_DIVISOR);
} else {
/* if FM detection fail, set default value */
calibration_val = 4;
}
- dev_dbg(tphy->dev, "phy:%d, fm_out:%d, calib:%d\n",
- instance->index, fm_out, calibration_val);
+ dev_dbg(tphy->dev, "phy:%d, fm_out:%d, calib:%d (clk:%d, coef:%d)\n",
+ instance->index, fm_out, calibration_val,
+ tphy->src_ref_clk, tphy->src_coef);
/* set HS slew rate */
tmp = readl(com + U3P_USBPHYACR5);
@@ -688,8 +691,7 @@ static void pcie_phy_instance_power_on(struct mtk_tphy *tphy,
u32 tmp;
tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLD);
- tmp &= ~(P3C_FORCE_IP_SW_RST | P3C_MCU_BUS_CK_GATE_EN |
- P3C_REG_IP_SW_RST);
+ tmp &= ~(P3C_FORCE_IP_SW_RST | P3C_REG_IP_SW_RST);
writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLD);
tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLE);
@@ -1042,6 +1044,13 @@ static int mtk_tphy_probe(struct platform_device *pdev)
tphy->u3phya_ref = NULL;
}
+ tphy->src_ref_clk = U3P_REF_CLK;
+ tphy->src_coef = U3P_SLEW_RATE_COEF;
+ /* update parameters of slew rate calibrate if exist */
+ device_property_read_u32(dev, "mediatek,src-ref-clk-mhz",
+ &tphy->src_ref_clk);
+ device_property_read_u32(dev, "mediatek,src-coef", &tphy->src_coef);
+
port = 0;
for_each_child_of_node(np, child_np) {
struct mtk_phy_instance *instance;
diff --git a/drivers/phy/motorola/Kconfig b/drivers/phy/motorola/Kconfig
index 6bb7d6bdf1bf..82651524ffb9 100644
--- a/drivers/phy/motorola/Kconfig
+++ b/drivers/phy/motorola/Kconfig
@@ -10,3 +10,11 @@ config PHY_CPCAP_USB
help
Enable this for USB to work on Motorola phones and tablets
such as Droid 4.
+
+config PHY_MAPPHONE_MDM6600
+ tristate "Motorola Mapphone MDM6600 modem USB PHY driver"
+ depends on OF && USB_SUPPORT
+ select GENERIC_PHY
+ help
+ Enable this for MDM6600 USB modem to work on Motorola phones
+ and tablets such as Droid 4.
diff --git a/drivers/phy/motorola/Makefile b/drivers/phy/motorola/Makefile
index b6cd618d671a..3514f985b355 100644
--- a/drivers/phy/motorola/Makefile
+++ b/drivers/phy/motorola/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_PHY_CPCAP_USB) += phy-cpcap-usb.o
+obj-$(CONFIG_PHY_MAPPHONE_MDM6600) += phy-mapphone-mdm6600.o
diff --git a/drivers/phy/motorola/phy-mapphone-mdm6600.c b/drivers/phy/motorola/phy-mapphone-mdm6600.c
new file mode 100644
index 000000000000..5439dd90d0dd
--- /dev/null
+++ b/drivers/phy/motorola/phy-mapphone-mdm6600.c
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Motorola Mapphone MDM6600 modem GPIO controlled USB PHY driver
+ * Copyright (C) 2018 Tony Lindgren <tony@atomide.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+
+#define PHY_MDM6600_PHY_DELAY_MS 4000 /* PHY enable 2.2s to 3.5s */
+#define PHY_MDM6600_ENABLED_DELAY_MS 8000 /* 8s more total for MDM6600 */
+
+enum phy_mdm6600_ctrl_lines {
+ PHY_MDM6600_ENABLE, /* USB PHY enable */
+ PHY_MDM6600_POWER, /* Device power */
+ PHY_MDM6600_RESET, /* Device reset */
+ PHY_MDM6600_NR_CTRL_LINES,
+};
+
+enum phy_mdm6600_bootmode_lines {
+ PHY_MDM6600_MODE0, /* out USB mode0 and OOB wake */
+ PHY_MDM6600_MODE1, /* out USB mode1, in OOB wake */
+ PHY_MDM6600_NR_MODE_LINES,
+};
+
+enum phy_mdm6600_cmd_lines {
+ PHY_MDM6600_CMD0,
+ PHY_MDM6600_CMD1,
+ PHY_MDM6600_CMD2,
+ PHY_MDM6600_NR_CMD_LINES,
+};
+
+enum phy_mdm6600_status_lines {
+ PHY_MDM6600_STATUS0,
+ PHY_MDM6600_STATUS1,
+ PHY_MDM6600_STATUS2,
+ PHY_MDM6600_NR_STATUS_LINES,
+};
+
+/*
+ * MDM6600 command codes. These are based on Motorola Mapphone Linux
+ * kernel tree.
+ */
+enum phy_mdm6600_cmd {
+ PHY_MDM6600_CMD_BP_PANIC_ACK,
+ PHY_MDM6600_CMD_DATA_ONLY_BYPASS, /* Reroute USB to CPCAP PHY */
+ PHY_MDM6600_CMD_FULL_BYPASS, /* Reroute USB to CPCAP PHY */
+ PHY_MDM6600_CMD_NO_BYPASS, /* Request normal USB mode */
+ PHY_MDM6600_CMD_BP_SHUTDOWN_REQ, /* Request device power off */
+ PHY_MDM6600_CMD_BP_UNKNOWN_5,
+ PHY_MDM6600_CMD_BP_UNKNOWN_6,
+ PHY_MDM6600_CMD_UNDEFINED,
+};
+
+/*
+ * MDM6600 status codes. These are based on Motorola Mapphone Linux
+ * kernel tree.
+ */
+enum phy_mdm6600_status {
+ PHY_MDM6600_STATUS_PANIC, /* Seems to be really off */
+ PHY_MDM6600_STATUS_PANIC_BUSY_WAIT,
+ PHY_MDM6600_STATUS_QC_DLOAD,
+ PHY_MDM6600_STATUS_RAM_DOWNLOADER, /* MDM6600 USB flashing mode */
+ PHY_MDM6600_STATUS_PHONE_CODE_AWAKE, /* MDM6600 normal USB mode */
+ PHY_MDM6600_STATUS_PHONE_CODE_ASLEEP,
+ PHY_MDM6600_STATUS_SHUTDOWN_ACK,
+ PHY_MDM6600_STATUS_UNDEFINED,
+};
+
+static const char * const
+phy_mdm6600_status_name[] = {
+ "off", "busy", "qc_dl", "ram_dl", "awake",
+ "asleep", "shutdown", "undefined",
+};
+
+struct phy_mdm6600 {
+ struct device *dev;
+ struct phy *generic_phy;
+ struct phy_provider *phy_provider;
+ struct gpio_desc *ctrl_gpios[PHY_MDM6600_NR_CTRL_LINES];
+ struct gpio_descs *mode_gpios;
+ struct gpio_descs *status_gpios;
+ struct gpio_descs *cmd_gpios;
+ struct delayed_work bootup_work;
+ struct delayed_work status_work;
+ struct completion ack;
+ bool enabled; /* mdm6600 phy enabled */
+ bool running; /* mdm6600 boot done */
+ int status;
+};
+
+static int phy_mdm6600_init(struct phy *x)
+{
+ struct phy_mdm6600 *ddata = phy_get_drvdata(x);
+ struct gpio_desc *enable_gpio = ddata->ctrl_gpios[PHY_MDM6600_ENABLE];
+
+ if (!ddata->enabled)
+ return -EPROBE_DEFER;
+
+ gpiod_set_value_cansleep(enable_gpio, 0);
+
+ return 0;
+}
+
+static int phy_mdm6600_power_on(struct phy *x)
+{
+ struct phy_mdm6600 *ddata = phy_get_drvdata(x);
+ struct gpio_desc *enable_gpio = ddata->ctrl_gpios[PHY_MDM6600_ENABLE];
+
+ if (!ddata->enabled)
+ return -ENODEV;
+
+ gpiod_set_value_cansleep(enable_gpio, 1);
+
+ return 0;
+}
+
+static int phy_mdm6600_power_off(struct phy *x)
+{
+ struct phy_mdm6600 *ddata = phy_get_drvdata(x);
+ struct gpio_desc *enable_gpio = ddata->ctrl_gpios[PHY_MDM6600_ENABLE];
+
+ if (!ddata->enabled)
+ return -ENODEV;
+
+ gpiod_set_value_cansleep(enable_gpio, 0);
+
+ return 0;
+}
+
+static const struct phy_ops gpio_usb_ops = {
+ .init = phy_mdm6600_init,
+ .power_on = phy_mdm6600_power_on,
+ .power_off = phy_mdm6600_power_off,
+ .owner = THIS_MODULE,
+};
+
+/**
+ * phy_mdm6600_cmd() - send a command request to mdm6600
+ * @ddata: device driver data
+ *
+ * Configures the three command request GPIOs to the specified value.
+ */
+static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val)
+{
+ int values[PHY_MDM6600_NR_CMD_LINES];
+ int i;
+
+ val &= (1 << PHY_MDM6600_NR_CMD_LINES) - 1;
+ for (i = 0; i < PHY_MDM6600_NR_CMD_LINES; i++)
+ values[i] = (val & BIT(i)) >> i;
+
+ gpiod_set_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES,
+ ddata->cmd_gpios->desc, values);
+}
+
+/**
+ * phy_mdm6600_status() - read mdm6600 status lines
+ * @ddata: device driver data
+ */
+static void phy_mdm6600_status(struct work_struct *work)
+{
+ struct phy_mdm6600 *ddata;
+ struct device *dev;
+ int values[PHY_MDM6600_NR_STATUS_LINES];
+ int error, i, val = 0;
+
+ ddata = container_of(work, struct phy_mdm6600, status_work.work);
+ dev = ddata->dev;
+
+ error = gpiod_get_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES,
+ ddata->status_gpios->desc,
+ values);
+ if (error)
+ return;
+
+ for (i = 0; i < PHY_MDM6600_NR_CMD_LINES; i++) {
+ val |= values[i] << i;
+ dev_dbg(ddata->dev, "XXX %s: i: %i values[i]: %i val: %i\n",
+ __func__, i, values[i], val);
+ }
+ ddata->status = val;
+
+ dev_info(dev, "modem status: %i %s\n",
+ ddata->status,
+ phy_mdm6600_status_name[ddata->status & 7]);
+ complete(&ddata->ack);
+}
+
+static irqreturn_t phy_mdm6600_irq_thread(int irq, void *data)
+{
+ struct phy_mdm6600 *ddata = data;
+
+ schedule_delayed_work(&ddata->status_work, msecs_to_jiffies(10));
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * phy_mdm6600_wakeirq_thread - handle mode1 line OOB wake after booting
+ * @irq: interrupt
+ * @data: interrupt handler data
+ *
+ * GPIO mode1 is used initially as output to configure the USB boot
+ * mode for mdm6600. After booting it is used as input for OOB wake
+ * signal from mdm6600 to the SoC. Just use it for debug info only
+ * for now.
+ */
+static irqreturn_t phy_mdm6600_wakeirq_thread(int irq, void *data)
+{
+ struct phy_mdm6600 *ddata = data;
+ struct gpio_desc *mode_gpio1;
+
+ mode_gpio1 = ddata->mode_gpios->desc[PHY_MDM6600_MODE1];
+ dev_dbg(ddata->dev, "OOB wake on mode_gpio1: %i\n",
+ gpiod_get_value(mode_gpio1));
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * phy_mdm6600_init_irq() - initialize mdm6600 status IRQ lines
+ * @ddata: device driver data
+ */
+static void phy_mdm6600_init_irq(struct phy_mdm6600 *ddata)
+{
+ struct device *dev = ddata->dev;
+ int i, error, irq;
+
+ for (i = PHY_MDM6600_STATUS0;
+ i <= PHY_MDM6600_STATUS2; i++) {
+ struct gpio_desc *gpio = ddata->status_gpios->desc[i];
+
+ irq = gpiod_to_irq(gpio);
+ if (irq <= 0)
+ continue;
+
+ error = devm_request_threaded_irq(dev, irq, NULL,
+ phy_mdm6600_irq_thread,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ "mdm6600",
+ ddata);
+ if (error)
+ dev_warn(dev, "no modem status irq%i: %i\n",
+ irq, error);
+ }
+}
+
+struct phy_mdm6600_map {
+ const char *name;
+ int direction;
+};
+
+static const struct phy_mdm6600_map
+phy_mdm6600_ctrl_gpio_map[PHY_MDM6600_NR_CTRL_LINES] = {
+ { "enable", GPIOD_OUT_LOW, }, /* low = phy disabled */
+ { "power", GPIOD_OUT_LOW, }, /* low = off */
+ { "reset", GPIOD_OUT_HIGH, }, /* high = reset */
+};
+
+/**
+ * phy_mdm6600_init_lines() - initialize mdm6600 GPIO lines
+ * @ddata: device driver data
+ */
+static int phy_mdm6600_init_lines(struct phy_mdm6600 *ddata)
+{
+ struct device *dev = ddata->dev;
+ int i;
+
+ /* MDM6600 control lines */
+ for (i = 0; i < ARRAY_SIZE(phy_mdm6600_ctrl_gpio_map); i++) {
+ const struct phy_mdm6600_map *map =
+ &phy_mdm6600_ctrl_gpio_map[i];
+ struct gpio_desc **gpio = &ddata->ctrl_gpios[i];
+
+ *gpio = devm_gpiod_get(dev, map->name, map->direction);
+ if (IS_ERR(*gpio)) {
+ dev_info(dev, "gpio %s error %li\n",
+ map->name, PTR_ERR(*gpio));
+ return PTR_ERR(*gpio);
+ }
+ }
+
+ /* MDM6600 USB start-up mode output lines */
+ ddata->mode_gpios = devm_gpiod_get_array(dev, "motorola,mode",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(ddata->mode_gpios))
+ return PTR_ERR(ddata->mode_gpios);
+
+ if (ddata->mode_gpios->ndescs != PHY_MDM6600_NR_MODE_LINES)
+ return -EINVAL;
+
+ /* MDM6600 status input lines */
+ ddata->status_gpios = devm_gpiod_get_array(dev, "motorola,status",
+ GPIOD_IN);
+ if (IS_ERR(ddata->status_gpios))
+ return PTR_ERR(ddata->status_gpios);
+
+ if (ddata->status_gpios->ndescs != PHY_MDM6600_NR_STATUS_LINES)
+ return -EINVAL;
+
+ /* MDM6600 cmd output lines */
+ ddata->cmd_gpios = devm_gpiod_get_array(dev, "motorola,cmd",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(ddata->cmd_gpios))
+ return PTR_ERR(ddata->cmd_gpios);
+
+ if (ddata->cmd_gpios->ndescs != PHY_MDM6600_NR_CMD_LINES)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * phy_mdm6600_device_power_on() - power on mdm6600 device
+ * @ddata: device driver data
+ *
+ * To get the integrated USB phy in MDM6600 takes some hoops. We must ensure
+ * the shared USB bootmode GPIOs are configured, then request modem start-up,
+ * reset and power-up.. And then we need to recycle the shared USB bootmode
+ * GPIOs as they are also used for Out of Band (OOB) wake for the USB and
+ * TS 27.010 serial mux.
+ */
+static int phy_mdm6600_device_power_on(struct phy_mdm6600 *ddata)
+{
+ struct gpio_desc *mode_gpio0, *mode_gpio1, *reset_gpio, *power_gpio;
+ int error = 0, wakeirq;
+
+ mode_gpio0 = ddata->mode_gpios->desc[PHY_MDM6600_MODE0];
+ mode_gpio1 = ddata->mode_gpios->desc[PHY_MDM6600_MODE1];
+ reset_gpio = ddata->ctrl_gpios[PHY_MDM6600_RESET];
+ power_gpio = ddata->ctrl_gpios[PHY_MDM6600_POWER];
+
+ /*
+ * Shared GPIOs must be low for normal USB mode. After booting
+ * they are used for OOB wake signaling. These can be also used
+ * to configure USB flashing mode later on based on a module
+ * parameter.
+ */
+ gpiod_set_value_cansleep(mode_gpio0, 0);
+ gpiod_set_value_cansleep(mode_gpio1, 0);
+
+ /* Request start-up mode */
+ phy_mdm6600_cmd(ddata, PHY_MDM6600_CMD_NO_BYPASS);
+
+ /* Request a reset first */
+ gpiod_set_value_cansleep(reset_gpio, 0);
+ msleep(100);
+
+ /* Toggle power GPIO to request mdm6600 to start */
+ gpiod_set_value_cansleep(power_gpio, 1);
+ msleep(100);
+ gpiod_set_value_cansleep(power_gpio, 0);
+
+ /*
+ * Looks like the USB PHY needs between 2.2 to 4 seconds.
+ * If we try to use it before that, we will get L3 errors
+ * from omap-usb-host trying to access the PHY. See also
+ * phy_mdm6600_init() for -EPROBE_DEFER.
+ */
+ msleep(PHY_MDM6600_PHY_DELAY_MS);
+ ddata->enabled = true;
+
+ /* Booting up the rest of MDM6600 will take total about 8 seconds */
+ dev_info(ddata->dev, "Waiting for power up request to complete..\n");
+ if (wait_for_completion_timeout(&ddata->ack,
+ msecs_to_jiffies(PHY_MDM6600_ENABLED_DELAY_MS))) {
+ if (ddata->status > PHY_MDM6600_STATUS_PANIC &&
+ ddata->status < PHY_MDM6600_STATUS_SHUTDOWN_ACK)
+ dev_info(ddata->dev, "Powered up OK\n");
+ } else {
+ ddata->enabled = false;
+ error = -ETIMEDOUT;
+ dev_err(ddata->dev, "Timed out powering up\n");
+ }
+
+ /* Reconfigure mode1 GPIO as input for OOB wake */
+ gpiod_direction_input(mode_gpio1);
+
+ wakeirq = gpiod_to_irq(mode_gpio1);
+ if (wakeirq <= 0)
+ return wakeirq;
+
+ error = devm_request_threaded_irq(ddata->dev, wakeirq, NULL,
+ phy_mdm6600_wakeirq_thread,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ "mdm6600-wake",
+ ddata);
+ if (error)
+ dev_warn(ddata->dev, "no modem wakeirq irq%i: %i\n",
+ wakeirq, error);
+
+ ddata->running = true;
+
+ return error;
+}
+
+/**
+ * phy_mdm6600_device_power_off() - power off mdm6600 device
+ * @ddata: device driver data
+ */
+static void phy_mdm6600_device_power_off(struct phy_mdm6600 *ddata)
+{
+ struct gpio_desc *reset_gpio =
+ ddata->ctrl_gpios[PHY_MDM6600_RESET];
+
+ ddata->enabled = false;
+ phy_mdm6600_cmd(ddata, PHY_MDM6600_CMD_BP_SHUTDOWN_REQ);
+ msleep(100);
+
+ gpiod_set_value_cansleep(reset_gpio, 1);
+
+ dev_info(ddata->dev, "Waiting for power down request to complete.. ");
+ if (wait_for_completion_timeout(&ddata->ack,
+ msecs_to_jiffies(5000))) {
+ if (ddata->status == PHY_MDM6600_STATUS_PANIC)
+ dev_info(ddata->dev, "Powered down OK\n");
+ } else {
+ dev_err(ddata->dev, "Timed out powering down\n");
+ }
+}
+
+static void phy_mdm6600_deferred_power_on(struct work_struct *work)
+{
+ struct phy_mdm6600 *ddata;
+ int error;
+
+ ddata = container_of(work, struct phy_mdm6600, bootup_work.work);
+
+ error = phy_mdm6600_device_power_on(ddata);
+ if (error)
+ dev_err(ddata->dev, "Device not functional\n");
+}
+
+static const struct of_device_id phy_mdm6600_id_table[] = {
+ { .compatible = "motorola,mapphone-mdm6600", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, phy_mdm6600_id_table);
+
+static int phy_mdm6600_probe(struct platform_device *pdev)
+{
+ struct phy_mdm6600 *ddata;
+ int error;
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&ddata->bootup_work,
+ phy_mdm6600_deferred_power_on);
+ INIT_DELAYED_WORK(&ddata->status_work, phy_mdm6600_status);
+ init_completion(&ddata->ack);
+
+ ddata->dev = &pdev->dev;
+ platform_set_drvdata(pdev, ddata);
+
+ error = phy_mdm6600_init_lines(ddata);
+ if (error)
+ return error;
+
+ phy_mdm6600_init_irq(ddata);
+
+ ddata->generic_phy = devm_phy_create(ddata->dev, NULL, &gpio_usb_ops);
+ if (IS_ERR(ddata->generic_phy)) {
+ error = PTR_ERR(ddata->generic_phy);
+ goto cleanup;
+ }
+
+ phy_set_drvdata(ddata->generic_phy, ddata);
+
+ ddata->phy_provider =
+ devm_of_phy_provider_register(ddata->dev,
+ of_phy_simple_xlate);
+ if (IS_ERR(ddata->phy_provider)) {
+ error = PTR_ERR(ddata->phy_provider);
+ goto cleanup;
+ }
+
+ schedule_delayed_work(&ddata->bootup_work, 0);
+
+ /*
+ * See phy_mdm6600_device_power_on(). We should be able
+ * to remove this eventually when ohci-platform can deal
+ * with -EPROBE_DEFER.
+ */
+ msleep(PHY_MDM6600_PHY_DELAY_MS + 500);
+
+ return 0;
+
+cleanup:
+ phy_mdm6600_device_power_off(ddata);
+ return error;
+}
+
+static int phy_mdm6600_remove(struct platform_device *pdev)
+{
+ struct phy_mdm6600 *ddata = platform_get_drvdata(pdev);
+ struct gpio_desc *reset_gpio = ddata->ctrl_gpios[PHY_MDM6600_RESET];
+
+ if (!ddata->running)
+ wait_for_completion_timeout(&ddata->ack,
+ msecs_to_jiffies(PHY_MDM6600_ENABLED_DELAY_MS));
+
+ gpiod_set_value_cansleep(reset_gpio, 1);
+ phy_mdm6600_device_power_off(ddata);
+
+ cancel_delayed_work_sync(&ddata->bootup_work);
+ cancel_delayed_work_sync(&ddata->status_work);
+
+ return 0;
+}
+
+static struct platform_driver phy_mdm6600_driver = {
+ .probe = phy_mdm6600_probe,
+ .remove = phy_mdm6600_remove,
+ .driver = {
+ .name = "phy-mapphone-mdm6600",
+ .of_match_table = of_match_ptr(phy_mdm6600_id_table),
+ },
+};
+
+module_platform_driver(phy_mdm6600_driver);
+
+MODULE_ALIAS("platform:gpio_usb");
+MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
+MODULE_DESCRIPTION("mdm6600 gpio usb phy driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 8f6e8e28996d..09ac8afb97ac 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -351,6 +351,8 @@ int phy_set_mode(struct phy *phy, enum phy_mode mode)
mutex_lock(&phy->mutex);
ret = phy->ops->set_mode(phy, mode);
+ if (!ret)
+ phy->attrs.mode = mode;
mutex_unlock(&phy->mutex);
return ret;
diff --git a/drivers/phy/phy-lpc18xx-usb-otg.c b/drivers/phy/phy-lpc18xx-usb-otg.c
index 3b7a71eb5b7e..7de280a45421 100644
--- a/drivers/phy/phy-lpc18xx-usb-otg.c
+++ b/drivers/phy/phy-lpc18xx-usb-otg.c
@@ -60,8 +60,14 @@ static int lpc18xx_usb_otg_phy_power_on(struct phy *phy)
return ret;
/* The bit in CREG is cleared to enable the PHY */
- return regmap_update_bits(lpc->reg, LPC18XX_CREG_CREG0,
+ ret = regmap_update_bits(lpc->reg, LPC18XX_CREG_CREG0,
LPC18XX_CREG_CREG0_USB0PHY, 0);
+ if (ret) {
+ clk_disable(lpc->clk);
+ return ret;
+ }
+
+ return 0;
}
static int lpc18xx_usb_otg_phy_power_off(struct phy *phy)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c
index e17f0351ccc2..6470c5d61d1c 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -1,15 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/clk.h>
@@ -31,124 +22,7 @@
#include <dt-bindings/phy/phy.h>
-/* QMP PHY QSERDES COM registers */
-#define QSERDES_COM_BG_TIMER 0x00c
-#define QSERDES_COM_SSC_EN_CENTER 0x010
-#define QSERDES_COM_SSC_ADJ_PER1 0x014
-#define QSERDES_COM_SSC_ADJ_PER2 0x018
-#define QSERDES_COM_SSC_PER1 0x01c
-#define QSERDES_COM_SSC_PER2 0x020
-#define QSERDES_COM_SSC_STEP_SIZE1 0x024
-#define QSERDES_COM_SSC_STEP_SIZE2 0x028
-#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x034
-#define QSERDES_COM_CLK_ENABLE1 0x038
-#define QSERDES_COM_SYS_CLK_CTRL 0x03c
-#define QSERDES_COM_SYSCLK_BUF_ENABLE 0x040
-#define QSERDES_COM_PLL_IVCO 0x048
-#define QSERDES_COM_LOCK_CMP1_MODE0 0x04c
-#define QSERDES_COM_LOCK_CMP2_MODE0 0x050
-#define QSERDES_COM_LOCK_CMP3_MODE0 0x054
-#define QSERDES_COM_LOCK_CMP1_MODE1 0x058
-#define QSERDES_COM_LOCK_CMP2_MODE1 0x05c
-#define QSERDES_COM_LOCK_CMP3_MODE1 0x060
-#define QSERDES_COM_BG_TRIM 0x070
-#define QSERDES_COM_CLK_EP_DIV 0x074
-#define QSERDES_COM_CP_CTRL_MODE0 0x078
-#define QSERDES_COM_CP_CTRL_MODE1 0x07c
-#define QSERDES_COM_PLL_RCTRL_MODE0 0x084
-#define QSERDES_COM_PLL_RCTRL_MODE1 0x088
-#define QSERDES_COM_PLL_CCTRL_MODE0 0x090
-#define QSERDES_COM_PLL_CCTRL_MODE1 0x094
-#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM 0x0a8
-#define QSERDES_COM_SYSCLK_EN_SEL 0x0ac
-#define QSERDES_COM_RESETSM_CNTRL 0x0b4
-#define QSERDES_COM_RESTRIM_CTRL 0x0bc
-#define QSERDES_COM_RESCODE_DIV_NUM 0x0c4
-#define QSERDES_COM_LOCK_CMP_EN 0x0c8
-#define QSERDES_COM_LOCK_CMP_CFG 0x0cc
-#define QSERDES_COM_DEC_START_MODE0 0x0d0
-#define QSERDES_COM_DEC_START_MODE1 0x0d4
-#define QSERDES_COM_DIV_FRAC_START1_MODE0 0x0dc
-#define QSERDES_COM_DIV_FRAC_START2_MODE0 0x0e0
-#define QSERDES_COM_DIV_FRAC_START3_MODE0 0x0e4
-#define QSERDES_COM_DIV_FRAC_START1_MODE1 0x0e8
-#define QSERDES_COM_DIV_FRAC_START2_MODE1 0x0ec
-#define QSERDES_COM_DIV_FRAC_START3_MODE1 0x0f0
-#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x108
-#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x10c
-#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 0x110
-#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 0x114
-#define QSERDES_COM_VCO_TUNE_CTRL 0x124
-#define QSERDES_COM_VCO_TUNE_MAP 0x128
-#define QSERDES_COM_VCO_TUNE1_MODE0 0x12c
-#define QSERDES_COM_VCO_TUNE2_MODE0 0x130
-#define QSERDES_COM_VCO_TUNE1_MODE1 0x134
-#define QSERDES_COM_VCO_TUNE2_MODE1 0x138
-#define QSERDES_COM_VCO_TUNE_TIMER1 0x144
-#define QSERDES_COM_VCO_TUNE_TIMER2 0x148
-#define QSERDES_COM_BG_CTRL 0x170
-#define QSERDES_COM_CLK_SELECT 0x174
-#define QSERDES_COM_HSCLK_SEL 0x178
-#define QSERDES_COM_CORECLK_DIV 0x184
-#define QSERDES_COM_CORE_CLK_EN 0x18c
-#define QSERDES_COM_C_READY_STATUS 0x190
-#define QSERDES_COM_CMN_CONFIG 0x194
-#define QSERDES_COM_SVS_MODE_CLK_SEL 0x19c
-#define QSERDES_COM_DEBUG_BUS0 0x1a0
-#define QSERDES_COM_DEBUG_BUS1 0x1a4
-#define QSERDES_COM_DEBUG_BUS2 0x1a8
-#define QSERDES_COM_DEBUG_BUS3 0x1ac
-#define QSERDES_COM_DEBUG_BUS_SEL 0x1b0
-#define QSERDES_COM_CORECLK_DIV_MODE1 0x1bc
-
-/* QMP PHY TX registers */
-#define QSERDES_TX_RES_CODE_LANE_OFFSET 0x054
-#define QSERDES_TX_DEBUG_BUS_SEL 0x064
-#define QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN 0x068
-#define QSERDES_TX_LANE_MODE 0x094
-#define QSERDES_TX_RCV_DETECT_LVL_2 0x0ac
-
-/* QMP PHY RX registers */
-#define QSERDES_RX_UCDR_SO_GAIN_HALF 0x010
-#define QSERDES_RX_UCDR_SO_GAIN 0x01c
-#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN 0x040
-#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE 0x048
-#define QSERDES_RX_RX_TERM_BW 0x090
-#define QSERDES_RX_RX_EQ_GAIN1_LSB 0x0c4
-#define QSERDES_RX_RX_EQ_GAIN1_MSB 0x0c8
-#define QSERDES_RX_RX_EQ_GAIN2_LSB 0x0cc
-#define QSERDES_RX_RX_EQ_GAIN2_MSB 0x0d0
-#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d8
-#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 0x0dc
-#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 0x0e0
-#define QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x108
-#define QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x10c
-#define QSERDES_RX_SIGDET_ENABLES 0x110
-#define QSERDES_RX_SIGDET_CNTRL 0x114
-#define QSERDES_RX_SIGDET_LVL 0x118
-#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL 0x11c
-#define QSERDES_RX_RX_BAND 0x120
-#define QSERDES_RX_RX_INTERFACE_MODE 0x12c
-
-/* QMP PHY PCS registers */
-#define QPHY_POWER_DOWN_CONTROL 0x04
-#define QPHY_TXDEEMPH_M6DB_V0 0x24
-#define QPHY_TXDEEMPH_M3P5DB_V0 0x28
-#define QPHY_ENDPOINT_REFCLK_DRIVE 0x54
-#define QPHY_RX_IDLE_DTCT_CNTRL 0x58
-#define QPHY_POWER_STATE_CONFIG1 0x60
-#define QPHY_POWER_STATE_CONFIG2 0x64
-#define QPHY_POWER_STATE_CONFIG4 0x6c
-#define QPHY_LOCK_DETECT_CONFIG1 0x80
-#define QPHY_LOCK_DETECT_CONFIG2 0x84
-#define QPHY_LOCK_DETECT_CONFIG3 0x88
-#define QPHY_PWRUP_RESET_DLY_TIME_AUXCLK 0xa0
-#define QPHY_LP_WAKEUP_DLY_TIME_AUXCLK 0xa4
-#define QPHY_PLL_LOCK_CHK_DLY_TIME_AUXCLK_LSB 0x1A8
-#define QPHY_OSC_DTCT_ACTIONS 0x1AC
-#define QPHY_RX_SIGDET_LVL 0x1D8
-#define QPHY_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB 0x1DC
-#define QPHY_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB 0x1E0
+#include "phy-qcom-qmp.h"
/* QPHY_SW_RESET bit */
#define SW_RESET BIT(0)
@@ -164,6 +38,34 @@
/* QPHY_COM_PCS_READY_STATUS bit */
#define PCS_READY BIT(0)
+/* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */
+/* DP PHY soft reset */
+#define SW_DPPHY_RESET BIT(0)
+/* mux to select DP PHY reset control, 0:HW control, 1: software reset */
+#define SW_DPPHY_RESET_MUX BIT(1)
+/* USB3 PHY soft reset */
+#define SW_USB3PHY_RESET BIT(2)
+/* mux to select USB3 PHY reset control, 0:HW control, 1: software reset */
+#define SW_USB3PHY_RESET_MUX BIT(3)
+
+/* QPHY_V3_DP_COM_PHY_MODE_CTRL register bits */
+#define USB3_MODE BIT(0) /* enables USB3 mode */
+#define DP_MODE BIT(1) /* enables DP mode */
+
+/* QPHY_PCS_AUTONOMOUS_MODE_CTRL register bits */
+#define ARCVR_DTCT_EN BIT(0)
+#define ALFPS_DTCT_EN BIT(1)
+#define ARCVR_DTCT_EVENT_SEL BIT(4)
+
+/* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */
+#define IRQ_CLEAR BIT(0)
+
+/* QPHY_PCS_LFPS_RXTERM_IRQ_STATUS register bits */
+#define RCVR_DETECT BIT(0)
+
+/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */
+#define CLAMP_EN BIT(0) /* enables i/o clamp_n */
+
#define PHY_INIT_COMPLETE_TIMEOUT 1000
#define POWER_DOWN_DELAY_US_MIN 10
#define POWER_DOWN_DELAY_US_MAX 11
@@ -210,6 +112,9 @@ enum qphy_reg_layout {
QPHY_SW_RESET,
QPHY_START_CTRL,
QPHY_PCS_READY_STATUS,
+ QPHY_PCS_AUTONOMOUS_MODE_CTRL,
+ QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR,
+ QPHY_PCS_LFPS_RXTERM_IRQ_STATUS,
};
static const unsigned int pciephy_regs_layout[] = {
@@ -237,6 +142,18 @@ static const unsigned int usb3phy_regs_layout[] = {
[QPHY_SW_RESET] = 0x00,
[QPHY_START_CTRL] = 0x08,
[QPHY_PCS_READY_STATUS] = 0x17c,
+ [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0x0d4,
+ [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = 0x0d8,
+ [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x178,
+};
+
+static const unsigned int qmp_v3_usb3phy_regs_layout[] = {
+ [QPHY_SW_RESET] = 0x00,
+ [QPHY_START_CTRL] = 0x08,
+ [QPHY_PCS_READY_STATUS] = 0x174,
+ [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0x0d8,
+ [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = 0x0dc,
+ [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170,
};
static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = {
@@ -467,6 +384,112 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_pcs_tbl[] = {
QMP_PHY_INIT_CFG_L(QPHY_START_CTRL, 0x3),
};
+static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_BUF_ENABLE, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07),
+};
+
+static const struct qmp_phy_init_tbl qmp_v3_usb3_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x06),
+};
+
+static const struct qmp_phy_init_tbl qmp_v3_usb3_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75),
+};
+
+static const struct qmp_phy_init_tbl qmp_v3_usb3_pcs_tbl[] = {
+ /* FLL settings */
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02),
+
+ /* Lock Det settings */
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b),
+
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0xba),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V1, 0x9f),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V2, 0xb7),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V3, 0x4e),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V4, 0x65),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_LS, 0x6b),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0d),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V1, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1, 0x0d),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V2, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2, 0x0d),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V3, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3, 0x1d),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V4, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4, 0x0d),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_LS, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS, 0x0d),
+
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RATE_SLEW_CNTRL, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13),
+};
+
/* struct qmp_phy_cfg - per-PHY initialization config */
struct qmp_phy_cfg {
/* phy-type - PCIE/UFS/USB */
@@ -511,6 +534,12 @@ struct qmp_phy_cfg {
/* power_down delay in usec */
int pwrdn_delay_min;
int pwrdn_delay_max;
+
+ /* true, if PHY has a separate DP_COM control block */
+ bool has_phy_dp_com_ctrl;
+ /* Register offset of secondary tx/rx lanes for USB DP combo PHY */
+ unsigned int tx_b_lane_offset;
+ unsigned int rx_b_lane_offset;
};
/**
@@ -520,6 +549,7 @@ struct qmp_phy_cfg {
* @tx: iomapped memory space for lane's tx
* @rx: iomapped memory space for lane's rx
* @pcs: iomapped memory space for lane's pcs
+ * @pcs_misc: iomapped memory space for lane's pcs_misc
* @pipe_clk: pipe lock
* @index: lane index
* @qmp: QMP phy to which this lane belongs
@@ -530,6 +560,7 @@ struct qmp_phy {
void __iomem *tx;
void __iomem *rx;
void __iomem *pcs;
+ void __iomem *pcs_misc;
struct clk *pipe_clk;
unsigned int index;
struct qcom_qmp *qmp;
@@ -541,6 +572,7 @@ struct qmp_phy {
*
* @dev: device
* @serdes: iomapped memory space for phy's serdes
+ * @dp_com: iomapped memory space for phy's dp_com control block
*
* @clks: array of clocks required by phy
* @resets: array of resets required by phy
@@ -550,12 +582,15 @@ struct qmp_phy {
* @phys: array of per-lane phy descriptors
* @phy_mutex: mutex lock for PHY common block initialization
* @init_count: phy common block initialization count
+ * @phy_initialized: indicate if PHY has been initialized
+ * @mode: current PHY mode
*/
struct qcom_qmp {
struct device *dev;
void __iomem *serdes;
+ void __iomem *dp_com;
- struct clk **clks;
+ struct clk_bulk_data *clks;
struct reset_control **resets;
struct regulator_bulk_data *vregs;
@@ -564,6 +599,8 @@ struct qcom_qmp {
struct mutex phy_mutex;
int init_count;
+ bool phy_initialized;
+ enum phy_mode mode;
};
static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -595,6 +632,10 @@ static const char * const msm8996_phy_clk_l[] = {
"aux", "cfg_ahb", "ref",
};
+static const char * const qmp_v3_phy_clk_l[] = {
+ "aux", "cfg_ahb", "ref", "com_aux",
+};
+
/* list of resets */
static const char * const msm8996_pciephy_reset_l[] = {
"phy", "common", "cfg",
@@ -701,6 +742,38 @@ static const struct qmp_phy_cfg ipq8074_pciephy_cfg = {
.pwrdn_delay_max = 1005, /* us */
};
+static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
+ .type = PHY_TYPE_USB3,
+ .nlanes = 1,
+
+ .serdes_tbl = qmp_v3_usb3_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl),
+ .tx_tbl = qmp_v3_usb3_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_tx_tbl),
+ .rx_tbl = qmp_v3_usb3_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_rx_tbl),
+ .pcs_tbl = qmp_v3_usb3_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(qmp_v3_usb3_pcs_tbl),
+ .clk_list = qmp_v3_phy_clk_l,
+ .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l),
+ .reset_list = msm8996_usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
+ .vreg_list = msm8996_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l),
+ .regs = qmp_v3_usb3phy_regs_layout,
+
+ .start_ctrl = SERDES_START | PCS_START,
+ .pwrdn_ctrl = SW_PWRDN,
+ .mask_pcs_ready = PHYSTATUS,
+
+ .pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
+ .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
+
+ .has_phy_dp_com_ctrl = true,
+ .tx_b_lane_offset = 0x400,
+ .rx_b_lane_offset = 0x400,
+};
+
static void qcom_qmp_phy_configure(void __iomem *base,
const unsigned int *regs,
const struct qmp_phy_init_tbl tbl[],
@@ -724,44 +797,20 @@ static int qcom_qmp_phy_poweron(struct phy *phy)
{
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
- int num = qmp->cfg->num_vregs;
int ret;
- dev_vdbg(&phy->dev, "Powering on QMP phy\n");
-
- /* turn on regulator supplies */
- ret = regulator_bulk_enable(num, qmp->vregs);
- if (ret) {
- dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
- return ret;
- }
-
ret = clk_prepare_enable(qphy->pipe_clk);
- if (ret) {
+ if (ret)
dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret);
- regulator_bulk_disable(num, qmp->vregs);
- return ret;
- }
- return 0;
-}
-
-static int qcom_qmp_phy_poweroff(struct phy *phy)
-{
- struct qmp_phy *qphy = phy_get_drvdata(phy);
- struct qcom_qmp *qmp = qphy->qmp;
-
- clk_disable_unprepare(qphy->pipe_clk);
-
- regulator_bulk_disable(qmp->cfg->num_vregs, qmp->vregs);
-
- return 0;
+ return ret;
}
static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
{
const struct qmp_phy_cfg *cfg = qmp->cfg;
void __iomem *serdes = qmp->serdes;
+ void __iomem *dp_com = qmp->dp_com;
int ret, i;
mutex_lock(&qmp->phy_mutex);
@@ -770,7 +819,23 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
return 0;
}
+ /* turn on regulator supplies */
+ ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
+ if (ret) {
+ dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
+ goto err_reg_enable;
+ }
+
for (i = 0; i < cfg->num_resets; i++) {
+ ret = reset_control_assert(qmp->resets[i]);
+ if (ret) {
+ dev_err(qmp->dev, "%s reset assert failed\n",
+ cfg->reset_list[i]);
+ goto err_rst_assert;
+ }
+ }
+
+ for (i = cfg->num_resets - 1; i >= 0; i--) {
ret = reset_control_deassert(qmp->resets[i]);
if (ret) {
dev_err(qmp->dev, "%s reset deassert failed\n",
@@ -779,10 +844,33 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
}
}
+ ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
+ if (ret) {
+ dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
+ goto err_rst;
+ }
+
if (cfg->has_phy_com_ctrl)
qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL],
SW_PWRDN);
+ if (cfg->has_phy_dp_com_ctrl) {
+ qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL,
+ SW_PWRDN);
+ /* override hardware control for reset of qmp phy */
+ qphy_setbits(dp_com, QPHY_V3_DP_COM_RESET_OVRD_CTRL,
+ SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
+ SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
+
+ qphy_setbits(dp_com, QPHY_V3_DP_COM_PHY_MODE_CTRL,
+ USB3_MODE | DP_MODE);
+
+ /* bring both QMP USB and QMP DP PHYs PCS block out of reset */
+ qphy_clrbits(dp_com, QPHY_V3_DP_COM_RESET_OVRD_CTRL,
+ SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
+ SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
+ }
+
/* Serdes configuration */
qcom_qmp_phy_configure(serdes, cfg->regs, cfg->serdes_tbl,
cfg->serdes_tbl_num);
@@ -803,7 +891,7 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
if (ret) {
dev_err(qmp->dev,
"phy common block init timed-out\n");
- goto err_rst;
+ goto err_com_init;
}
}
@@ -811,9 +899,14 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
return 0;
+err_com_init:
+ clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
err_rst:
- while (--i >= 0)
+ while (++i < cfg->num_resets)
reset_control_assert(qmp->resets[i]);
+err_rst_assert:
+ regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
+err_reg_enable:
mutex_unlock(&qmp->phy_mutex);
return ret;
@@ -843,6 +936,10 @@ static int qcom_qmp_phy_com_exit(struct qcom_qmp *qmp)
while (--i >= 0)
reset_control_assert(qmp->resets[i]);
+ clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
+
+ regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
+
mutex_unlock(&qmp->phy_mutex);
return 0;
@@ -857,24 +954,16 @@ static int qcom_qmp_phy_init(struct phy *phy)
void __iomem *tx = qphy->tx;
void __iomem *rx = qphy->rx;
void __iomem *pcs = qphy->pcs;
+ void __iomem *dp_com = qmp->dp_com;
void __iomem *status;
unsigned int mask, val;
- int ret, i;
+ int ret;
dev_vdbg(qmp->dev, "Initializing QMP phy\n");
- for (i = 0; i < qmp->cfg->num_clks; i++) {
- ret = clk_prepare_enable(qmp->clks[i]);
- if (ret) {
- dev_err(qmp->dev, "failed to enable %s clk, err=%d\n",
- qmp->cfg->clk_list[i], ret);
- goto err_clk;
- }
- }
-
ret = qcom_qmp_phy_com_init(qmp);
if (ret)
- goto err_clk;
+ return ret;
if (cfg->has_lane_rst) {
ret = reset_control_deassert(qphy->lane_rst);
@@ -887,7 +976,16 @@ static int qcom_qmp_phy_init(struct phy *phy)
/* Tx, Rx, and PCS configurations */
qcom_qmp_phy_configure(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num);
+ /* Configuration for other LANE for USB-DP combo PHY */
+ if (cfg->has_phy_dp_com_ctrl)
+ qcom_qmp_phy_configure(tx + cfg->tx_b_lane_offset, cfg->regs,
+ cfg->tx_tbl, cfg->tx_tbl_num);
+
qcom_qmp_phy_configure(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num);
+ if (cfg->has_phy_dp_com_ctrl)
+ qcom_qmp_phy_configure(rx + cfg->rx_b_lane_offset, cfg->regs,
+ cfg->rx_tbl, cfg->rx_tbl_num);
+
qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num);
/*
@@ -899,11 +997,13 @@ static int qcom_qmp_phy_init(struct phy *phy)
if (cfg->has_pwrdn_delay)
usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max);
- /* start SerDes and Phy-Coding-Sublayer */
- qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
-
/* Pull PHY out of reset state */
qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
+ if (cfg->has_phy_dp_com_ctrl)
+ qphy_clrbits(dp_com, QPHY_V3_DP_COM_SW_RESET, SW_RESET);
+
+ /* start SerDes and Phy-Coding-Sublayer */
+ qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
status = pcs + cfg->regs[QPHY_PCS_READY_STATUS];
mask = cfg->mask_pcs_ready;
@@ -914,6 +1014,7 @@ static int qcom_qmp_phy_init(struct phy *phy)
dev_err(qmp->dev, "phy initialization timed-out\n");
goto err_pcs_ready;
}
+ qmp->phy_initialized = true;
return ret;
@@ -922,9 +1023,6 @@ err_pcs_ready:
reset_control_assert(qphy->lane_rst);
err_lane_rst:
qcom_qmp_phy_com_exit(qmp);
-err_clk:
- while (--i >= 0)
- clk_disable_unprepare(qmp->clks[i]);
return ret;
}
@@ -934,7 +1032,8 @@ static int qcom_qmp_phy_exit(struct phy *phy)
struct qmp_phy *qphy = phy_get_drvdata(phy);
struct qcom_qmp *qmp = qphy->qmp;
const struct qmp_phy_cfg *cfg = qmp->cfg;
- int i = cfg->num_clks;
+
+ clk_disable_unprepare(qphy->pipe_clk);
/* PHY reset */
qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
@@ -950,8 +1049,127 @@ static int qcom_qmp_phy_exit(struct phy *phy)
qcom_qmp_phy_com_exit(qmp);
- while (--i >= 0)
- clk_disable_unprepare(qmp->clks[i]);
+ qmp->phy_initialized = false;
+
+ return 0;
+}
+
+static int qcom_qmp_phy_set_mode(struct phy *phy, enum phy_mode mode)
+{
+ struct qmp_phy *qphy = phy_get_drvdata(phy);
+ struct qcom_qmp *qmp = qphy->qmp;
+
+ qmp->mode = mode;
+
+ return 0;
+}
+
+static void qcom_qmp_phy_enable_autonomous_mode(struct qmp_phy *qphy)
+{
+ struct qcom_qmp *qmp = qphy->qmp;
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ void __iomem *pcs = qphy->pcs;
+ void __iomem *pcs_misc = qphy->pcs_misc;
+ u32 intr_mask;
+
+ if (qmp->mode == PHY_MODE_USB_HOST_SS ||
+ qmp->mode == PHY_MODE_USB_DEVICE_SS)
+ intr_mask = ARCVR_DTCT_EN | ALFPS_DTCT_EN;
+ else
+ intr_mask = ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL;
+
+ /* Clear any pending interrupts status */
+ qphy_setbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR);
+ /* Writing 1 followed by 0 clears the interrupt */
+ qphy_clrbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR);
+
+ qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL],
+ ARCVR_DTCT_EN | ALFPS_DTCT_EN | ARCVR_DTCT_EVENT_SEL);
+
+ /* Enable required PHY autonomous mode interrupts */
+ qphy_setbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], intr_mask);
+
+ /* Enable i/o clamp_n for autonomous mode */
+ if (pcs_misc)
+ qphy_clrbits(pcs_misc, QPHY_V3_PCS_MISC_CLAMP_ENABLE, CLAMP_EN);
+}
+
+static void qcom_qmp_phy_disable_autonomous_mode(struct qmp_phy *qphy)
+{
+ struct qcom_qmp *qmp = qphy->qmp;
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ void __iomem *pcs = qphy->pcs;
+ void __iomem *pcs_misc = qphy->pcs_misc;
+
+ /* Disable i/o clamp_n on resume for normal mode */
+ if (pcs_misc)
+ qphy_setbits(pcs_misc, QPHY_V3_PCS_MISC_CLAMP_ENABLE, CLAMP_EN);
+
+ qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL],
+ ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL | ALFPS_DTCT_EN);
+
+ qphy_setbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR);
+ /* Writing 1 followed by 0 clears the interrupt */
+ qphy_clrbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR);
+}
+
+static int __maybe_unused qcom_qmp_phy_runtime_suspend(struct device *dev)
+{
+ struct qcom_qmp *qmp = dev_get_drvdata(dev);
+ struct qmp_phy *qphy = qmp->phys[0];
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+
+ dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode);
+
+ /* Supported only for USB3 PHY */
+ if (cfg->type != PHY_TYPE_USB3)
+ return 0;
+
+ if (!qmp->phy_initialized) {
+ dev_vdbg(dev, "PHY not initialized, bailing out\n");
+ return 0;
+ }
+
+ qcom_qmp_phy_enable_autonomous_mode(qphy);
+
+ clk_disable_unprepare(qphy->pipe_clk);
+ clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
+
+ return 0;
+}
+
+static int __maybe_unused qcom_qmp_phy_runtime_resume(struct device *dev)
+{
+ struct qcom_qmp *qmp = dev_get_drvdata(dev);
+ struct qmp_phy *qphy = qmp->phys[0];
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ int ret = 0;
+
+ dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode);
+
+ /* Supported only for USB3 PHY */
+ if (cfg->type != PHY_TYPE_USB3)
+ return 0;
+
+ if (!qmp->phy_initialized) {
+ dev_vdbg(dev, "PHY not initialized, bailing out\n");
+ return 0;
+ }
+
+ ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
+ if (ret) {
+ dev_err(qmp->dev, "failed to enable clks, err=%d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(qphy->pipe_clk);
+ if (ret) {
+ dev_err(dev, "pipe_clk enable failed, err=%d\n", ret);
+ clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks);
+ return ret;
+ }
+
+ qcom_qmp_phy_disable_autonomous_mode(qphy);
return 0;
}
@@ -1000,29 +1218,17 @@ static int qcom_qmp_phy_reset_init(struct device *dev)
static int qcom_qmp_phy_clk_init(struct device *dev)
{
struct qcom_qmp *qmp = dev_get_drvdata(dev);
- int ret, i;
+ int num = qmp->cfg->num_clks;
+ int i;
- qmp->clks = devm_kcalloc(dev, qmp->cfg->num_clks,
- sizeof(*qmp->clks), GFP_KERNEL);
+ qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL);
if (!qmp->clks)
return -ENOMEM;
- for (i = 0; i < qmp->cfg->num_clks; i++) {
- struct clk *_clk;
- const char *name = qmp->cfg->clk_list[i];
-
- _clk = devm_clk_get(dev, name);
- if (IS_ERR(_clk)) {
- ret = PTR_ERR(_clk);
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "failed to get %s clk, %d\n",
- name, ret);
- return ret;
- }
- qmp->clks[i] = _clk;
- }
+ for (i = 0; i < num; i++)
+ qmp->clks[i].id = qmp->cfg->clk_list[i];
- return 0;
+ return devm_clk_bulk_get(dev, num, qmp->clks);
}
/*
@@ -1078,7 +1284,7 @@ static const struct phy_ops qcom_qmp_phy_gen_ops = {
.init = qcom_qmp_phy_init,
.exit = qcom_qmp_phy_exit,
.power_on = qcom_qmp_phy_poweron,
- .power_off = qcom_qmp_phy_poweroff,
+ .set_mode = qcom_qmp_phy_set_mode,
.owner = THIS_MODULE,
};
@@ -1097,7 +1303,8 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id)
/*
* Get memory resources for each phy lane:
- * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2.
+ * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2; and
+ * pcs_misc (optional) -> 3.
*/
qphy->tx = of_iomap(np, 0);
if (!qphy->tx)
@@ -1111,6 +1318,10 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id)
if (!qphy->pcs)
return -ENOMEM;
+ qphy->pcs_misc = of_iomap(np, 3);
+ if (!qphy->pcs_misc)
+ dev_vdbg(dev, "PHY pcs_misc-reg not used\n");
+
/*
* Get PHY's Pipe clock, if any. USB3 and PCIe are PIPE3
* based phys, so they essentially have pipe clock. So,
@@ -1169,11 +1380,19 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
}, {
.compatible = "qcom,ipq8074-qmp-pcie-phy",
.data = &ipq8074_pciephy_cfg,
+ }, {
+ .compatible = "qcom,qmp-v3-usb3-phy",
+ .data = &qmp_v3_usb3phy_cfg,
},
{ },
};
MODULE_DEVICE_TABLE(of, qcom_qmp_phy_of_match_table);
+static const struct dev_pm_ops qcom_qmp_phy_pm_ops = {
+ SET_RUNTIME_PM_OPS(qcom_qmp_phy_runtime_suspend,
+ qcom_qmp_phy_runtime_resume, NULL)
+};
+
static int qcom_qmp_phy_probe(struct platform_device *pdev)
{
struct qcom_qmp *qmp;
@@ -1192,6 +1411,11 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev)
qmp->dev = dev;
dev_set_drvdata(dev, qmp);
+ /* Get the specific init parameters of QMP phy */
+ qmp->cfg = of_device_get_match_data(dev);
+ if (!qmp->cfg)
+ return -EINVAL;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
@@ -1200,10 +1424,18 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev)
/* per PHY serdes; usually located at base address */
qmp->serdes = base;
- mutex_init(&qmp->phy_mutex);
+ /* per PHY dp_com; if PHY has dp_com control block */
+ if (qmp->cfg->has_phy_dp_com_ctrl) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "dp_com");
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
- /* Get the specific init parameters of QMP phy */
- qmp->cfg = of_device_get_match_data(dev);
+ qmp->dp_com = base;
+ }
+
+ mutex_init(&qmp->phy_mutex);
ret = qcom_qmp_phy_clk_init(dev);
if (ret)
@@ -1229,12 +1461,21 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev)
return -ENOMEM;
id = 0;
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ /*
+ * Prevent runtime pm from being ON by default. Users can enable
+ * it using power/control in sysfs.
+ */
+ pm_runtime_forbid(dev);
+
for_each_available_child_of_node(dev->of_node, child) {
/* Create per-lane phy */
ret = qcom_qmp_phy_create(dev, child, id);
if (ret) {
dev_err(dev, "failed to create lane%d phy, %d\n",
id, ret);
+ pm_runtime_disable(dev);
return ret;
}
@@ -1246,6 +1487,7 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev)
if (ret) {
dev_err(qmp->dev,
"failed to register pipe clock source\n");
+ pm_runtime_disable(dev);
return ret;
}
id++;
@@ -1254,6 +1496,8 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev)
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (!IS_ERR(phy_provider))
dev_info(dev, "Registered Qcom-QMP phy\n");
+ else
+ pm_runtime_disable(dev);
return PTR_ERR_OR_ZERO(phy_provider);
}
@@ -1262,6 +1506,7 @@ static struct platform_driver qcom_qmp_phy_driver = {
.probe = qcom_qmp_phy_probe,
.driver = {
.name = "qcom-qmp-phy",
+ .pm = &qcom_qmp_phy_pm_ops,
.of_match_table = qcom_qmp_phy_of_match_table,
},
};
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h
new file mode 100644
index 000000000000..d1c6905d0439
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.h
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_H_
+#define QCOM_PHY_QMP_H_
+
+/* Only for QMP V2 PHY - QSERDES COM registers */
+#define QSERDES_COM_BG_TIMER 0x00c
+#define QSERDES_COM_SSC_EN_CENTER 0x010
+#define QSERDES_COM_SSC_ADJ_PER1 0x014
+#define QSERDES_COM_SSC_ADJ_PER2 0x018
+#define QSERDES_COM_SSC_PER1 0x01c
+#define QSERDES_COM_SSC_PER2 0x020
+#define QSERDES_COM_SSC_STEP_SIZE1 0x024
+#define QSERDES_COM_SSC_STEP_SIZE2 0x028
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x034
+#define QSERDES_COM_CLK_ENABLE1 0x038
+#define QSERDES_COM_SYS_CLK_CTRL 0x03c
+#define QSERDES_COM_SYSCLK_BUF_ENABLE 0x040
+#define QSERDES_COM_PLL_IVCO 0x048
+#define QSERDES_COM_LOCK_CMP1_MODE0 0x04c
+#define QSERDES_COM_LOCK_CMP2_MODE0 0x050
+#define QSERDES_COM_LOCK_CMP3_MODE0 0x054
+#define QSERDES_COM_LOCK_CMP1_MODE1 0x058
+#define QSERDES_COM_LOCK_CMP2_MODE1 0x05c
+#define QSERDES_COM_LOCK_CMP3_MODE1 0x060
+#define QSERDES_COM_BG_TRIM 0x070
+#define QSERDES_COM_CLK_EP_DIV 0x074
+#define QSERDES_COM_CP_CTRL_MODE0 0x078
+#define QSERDES_COM_CP_CTRL_MODE1 0x07c
+#define QSERDES_COM_PLL_RCTRL_MODE0 0x084
+#define QSERDES_COM_PLL_RCTRL_MODE1 0x088
+#define QSERDES_COM_PLL_CCTRL_MODE0 0x090
+#define QSERDES_COM_PLL_CCTRL_MODE1 0x094
+#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM 0x0a8
+#define QSERDES_COM_SYSCLK_EN_SEL 0x0ac
+#define QSERDES_COM_RESETSM_CNTRL 0x0b4
+#define QSERDES_COM_RESTRIM_CTRL 0x0bc
+#define QSERDES_COM_RESCODE_DIV_NUM 0x0c4
+#define QSERDES_COM_LOCK_CMP_EN 0x0c8
+#define QSERDES_COM_LOCK_CMP_CFG 0x0cc
+#define QSERDES_COM_DEC_START_MODE0 0x0d0
+#define QSERDES_COM_DEC_START_MODE1 0x0d4
+#define QSERDES_COM_DIV_FRAC_START1_MODE0 0x0dc
+#define QSERDES_COM_DIV_FRAC_START2_MODE0 0x0e0
+#define QSERDES_COM_DIV_FRAC_START3_MODE0 0x0e4
+#define QSERDES_COM_DIV_FRAC_START1_MODE1 0x0e8
+#define QSERDES_COM_DIV_FRAC_START2_MODE1 0x0ec
+#define QSERDES_COM_DIV_FRAC_START3_MODE1 0x0f0
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x108
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x10c
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 0x110
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 0x114
+#define QSERDES_COM_VCO_TUNE_CTRL 0x124
+#define QSERDES_COM_VCO_TUNE_MAP 0x128
+#define QSERDES_COM_VCO_TUNE1_MODE0 0x12c
+#define QSERDES_COM_VCO_TUNE2_MODE0 0x130
+#define QSERDES_COM_VCO_TUNE1_MODE1 0x134
+#define QSERDES_COM_VCO_TUNE2_MODE1 0x138
+#define QSERDES_COM_VCO_TUNE_TIMER1 0x144
+#define QSERDES_COM_VCO_TUNE_TIMER2 0x148
+#define QSERDES_COM_BG_CTRL 0x170
+#define QSERDES_COM_CLK_SELECT 0x174
+#define QSERDES_COM_HSCLK_SEL 0x178
+#define QSERDES_COM_CORECLK_DIV 0x184
+#define QSERDES_COM_CORE_CLK_EN 0x18c
+#define QSERDES_COM_C_READY_STATUS 0x190
+#define QSERDES_COM_CMN_CONFIG 0x194
+#define QSERDES_COM_SVS_MODE_CLK_SEL 0x19c
+#define QSERDES_COM_DEBUG_BUS0 0x1a0
+#define QSERDES_COM_DEBUG_BUS1 0x1a4
+#define QSERDES_COM_DEBUG_BUS2 0x1a8
+#define QSERDES_COM_DEBUG_BUS3 0x1ac
+#define QSERDES_COM_DEBUG_BUS_SEL 0x1b0
+#define QSERDES_COM_CORECLK_DIV_MODE1 0x1bc
+
+/* Only for QMP V2 PHY - TX registers */
+#define QSERDES_TX_RES_CODE_LANE_OFFSET 0x054
+#define QSERDES_TX_DEBUG_BUS_SEL 0x064
+#define QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN 0x068
+#define QSERDES_TX_LANE_MODE 0x094
+#define QSERDES_TX_RCV_DETECT_LVL_2 0x0ac
+
+/* Only for QMP V2 PHY - RX registers */
+#define QSERDES_RX_UCDR_SO_GAIN_HALF 0x010
+#define QSERDES_RX_UCDR_SO_GAIN 0x01c
+#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN 0x040
+#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE 0x048
+#define QSERDES_RX_RX_TERM_BW 0x090
+#define QSERDES_RX_RX_EQ_GAIN1_LSB 0x0c4
+#define QSERDES_RX_RX_EQ_GAIN1_MSB 0x0c8
+#define QSERDES_RX_RX_EQ_GAIN2_LSB 0x0cc
+#define QSERDES_RX_RX_EQ_GAIN2_MSB 0x0d0
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d8
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 0x0dc
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 0x0e0
+#define QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x108
+#define QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x10c
+#define QSERDES_RX_SIGDET_ENABLES 0x110
+#define QSERDES_RX_SIGDET_CNTRL 0x114
+#define QSERDES_RX_SIGDET_LVL 0x118
+#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL 0x11c
+#define QSERDES_RX_RX_BAND 0x120
+#define QSERDES_RX_RX_INTERFACE_MODE 0x12c
+
+/* Only for QMP V2 PHY - PCS registers */
+#define QPHY_POWER_DOWN_CONTROL 0x04
+#define QPHY_TXDEEMPH_M6DB_V0 0x24
+#define QPHY_TXDEEMPH_M3P5DB_V0 0x28
+#define QPHY_ENDPOINT_REFCLK_DRIVE 0x54
+#define QPHY_RX_IDLE_DTCT_CNTRL 0x58
+#define QPHY_POWER_STATE_CONFIG1 0x60
+#define QPHY_POWER_STATE_CONFIG2 0x64
+#define QPHY_POWER_STATE_CONFIG4 0x6c
+#define QPHY_LOCK_DETECT_CONFIG1 0x80
+#define QPHY_LOCK_DETECT_CONFIG2 0x84
+#define QPHY_LOCK_DETECT_CONFIG3 0x88
+#define QPHY_PWRUP_RESET_DLY_TIME_AUXCLK 0xa0
+#define QPHY_LP_WAKEUP_DLY_TIME_AUXCLK 0xa4
+#define QPHY_PLL_LOCK_CHK_DLY_TIME_AUXCLK_LSB 0x1A8
+#define QPHY_OSC_DTCT_ACTIONS 0x1AC
+#define QPHY_RX_SIGDET_LVL 0x1D8
+#define QPHY_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB 0x1DC
+#define QPHY_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB 0x1E0
+
+/* Only for QMP V3 PHY - DP COM registers */
+#define QPHY_V3_DP_COM_PHY_MODE_CTRL 0x00
+#define QPHY_V3_DP_COM_SW_RESET 0x04
+#define QPHY_V3_DP_COM_POWER_DOWN_CTRL 0x08
+#define QPHY_V3_DP_COM_SWI_CTRL 0x0c
+#define QPHY_V3_DP_COM_TYPEC_CTRL 0x10
+#define QPHY_V3_DP_COM_TYPEC_PWRDN_CTRL 0x14
+#define QPHY_V3_DP_COM_RESET_OVRD_CTRL 0x1c
+
+/* Only for QMP V3 PHY - QSERDES COM registers */
+#define QSERDES_V3_COM_BG_TIMER 0x00c
+#define QSERDES_V3_COM_SSC_EN_CENTER 0x010
+#define QSERDES_V3_COM_SSC_ADJ_PER1 0x014
+#define QSERDES_V3_COM_SSC_ADJ_PER2 0x018
+#define QSERDES_V3_COM_SSC_PER1 0x01c
+#define QSERDES_V3_COM_SSC_PER2 0x020
+#define QSERDES_V3_COM_SSC_STEP_SIZE1 0x024
+#define QSERDES_V3_COM_SSC_STEP_SIZE2 0x028
+#define QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN 0x034
+#define QSERDES_V3_COM_CLK_ENABLE1 0x038
+#define QSERDES_V3_COM_SYS_CLK_CTRL 0x03c
+#define QSERDES_V3_COM_SYSCLK_BUF_ENABLE 0x040
+#define QSERDES_V3_COM_PLL_IVCO 0x048
+#define QSERDES_V3_COM_LOCK_CMP1_MODE0 0x098
+#define QSERDES_V3_COM_LOCK_CMP2_MODE0 0x09c
+#define QSERDES_V3_COM_LOCK_CMP3_MODE0 0x0a0
+#define QSERDES_V3_COM_LOCK_CMP1_MODE1 0x0a4
+#define QSERDES_V3_COM_LOCK_CMP2_MODE1 0x0a8
+#define QSERDES_V3_COM_LOCK_CMP3_MODE1 0x0ac
+#define QSERDES_V3_COM_CLK_EP_DIV 0x05c
+#define QSERDES_V3_COM_CP_CTRL_MODE0 0x060
+#define QSERDES_V3_COM_CP_CTRL_MODE1 0x064
+#define QSERDES_V3_COM_PLL_RCTRL_MODE0 0x068
+#define QSERDES_V3_COM_PLL_RCTRL_MODE1 0x06c
+#define QSERDES_V3_COM_PLL_CCTRL_MODE0 0x070
+#define QSERDES_V3_COM_PLL_CCTRL_MODE1 0x074
+#define QSERDES_V3_COM_SYSCLK_EN_SEL 0x080
+#define QSERDES_V3_COM_RESETSM_CNTRL 0x088
+#define QSERDES_V3_COM_RESETSM_CNTRL2 0x08c
+#define QSERDES_V3_COM_LOCK_CMP_EN 0x090
+#define QSERDES_V3_COM_LOCK_CMP_CFG 0x094
+#define QSERDES_V3_COM_DEC_START_MODE0 0x0b0
+#define QSERDES_V3_COM_DEC_START_MODE1 0x0b4
+#define QSERDES_V3_COM_DIV_FRAC_START1_MODE0 0x0b8
+#define QSERDES_V3_COM_DIV_FRAC_START2_MODE0 0x0bc
+#define QSERDES_V3_COM_DIV_FRAC_START3_MODE0 0x0c0
+#define QSERDES_V3_COM_DIV_FRAC_START1_MODE1 0x0c4
+#define QSERDES_V3_COM_DIV_FRAC_START2_MODE1 0x0c8
+#define QSERDES_V3_COM_DIV_FRAC_START3_MODE1 0x0cc
+#define QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0 0x0d8
+#define QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0 0x0dc
+#define QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE1 0x0e0
+#define QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE1 0x0e4
+#define QSERDES_V3_COM_VCO_TUNE_CTRL 0x0ec
+#define QSERDES_V3_COM_VCO_TUNE_MAP 0x0f0
+#define QSERDES_V3_COM_VCO_TUNE1_MODE0 0x0f4
+#define QSERDES_V3_COM_VCO_TUNE2_MODE0 0x0f8
+#define QSERDES_V3_COM_VCO_TUNE1_MODE1 0x0fc
+#define QSERDES_V3_COM_VCO_TUNE2_MODE1 0x100
+#define QSERDES_V3_COM_VCO_TUNE_TIMER1 0x11c
+#define QSERDES_V3_COM_VCO_TUNE_TIMER2 0x120
+#define QSERDES_V3_COM_CLK_SELECT 0x138
+#define QSERDES_V3_COM_HSCLK_SEL 0x13c
+#define QSERDES_V3_COM_CORECLK_DIV_MODE0 0x148
+#define QSERDES_V3_COM_CORECLK_DIV_MODE1 0x14c
+#define QSERDES_V3_COM_CORE_CLK_EN 0x154
+#define QSERDES_V3_COM_C_READY_STATUS 0x158
+#define QSERDES_V3_COM_CMN_CONFIG 0x15c
+#define QSERDES_V3_COM_SVS_MODE_CLK_SEL 0x164
+#define QSERDES_V3_COM_DEBUG_BUS0 0x168
+#define QSERDES_V3_COM_DEBUG_BUS1 0x16c
+#define QSERDES_V3_COM_DEBUG_BUS2 0x170
+#define QSERDES_V3_COM_DEBUG_BUS3 0x174
+#define QSERDES_V3_COM_DEBUG_BUS_SEL 0x178
+
+/* Only for QMP V3 PHY - TX registers */
+#define QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX 0x044
+#define QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX 0x048
+#define QSERDES_V3_TX_DEBUG_BUS_SEL 0x058
+#define QSERDES_V3_TX_HIGHZ_DRVR_EN 0x060
+#define QSERDES_V3_TX_LANE_MODE_1 0x08c
+#define QSERDES_V3_TX_RCV_DETECT_LVL_2 0x0a4
+
+/* Only for QMP V3 PHY - RX registers */
+#define QSERDES_V3_RX_UCDR_SO_GAIN_HALF 0x00c
+#define QSERDES_V3_RX_UCDR_SO_GAIN 0x014
+#define QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN 0x030
+#define QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034
+#define QSERDES_V3_RX_RX_TERM_BW 0x07c
+#define QSERDES_V3_RX_RX_EQ_GAIN2_LSB 0x0c8
+#define QSERDES_V3_RX_RX_EQ_GAIN2_MSB 0x0cc
+#define QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d4
+#define QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3 0x0d8
+#define QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4 0x0dc
+#define QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x0f8
+#define QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x0fc
+#define QSERDES_V3_RX_SIGDET_ENABLES 0x100
+#define QSERDES_V3_RX_SIGDET_CNTRL 0x104
+#define QSERDES_V3_RX_SIGDET_LVL 0x108
+#define QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL 0x10c
+#define QSERDES_V3_RX_RX_BAND 0x110
+#define QSERDES_V3_RX_RX_INTERFACE_MODE 0x11c
+
+/* Only for QMP V3 PHY - PCS registers */
+#define QPHY_V3_PCS_POWER_DOWN_CONTROL 0x004
+#define QPHY_V3_PCS_TXMGN_V0 0x00c
+#define QPHY_V3_PCS_TXMGN_V1 0x010
+#define QPHY_V3_PCS_TXMGN_V2 0x014
+#define QPHY_V3_PCS_TXMGN_V3 0x018
+#define QPHY_V3_PCS_TXMGN_V4 0x01c
+#define QPHY_V3_PCS_TXMGN_LS 0x020
+#define QPHY_V3_PCS_TXDEEMPH_M6DB_V0 0x024
+#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0 0x028
+#define QPHY_V3_PCS_TXDEEMPH_M6DB_V1 0x02c
+#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1 0x030
+#define QPHY_V3_PCS_TXDEEMPH_M6DB_V2 0x034
+#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2 0x038
+#define QPHY_V3_PCS_TXDEEMPH_M6DB_V3 0x03c
+#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3 0x040
+#define QPHY_V3_PCS_TXDEEMPH_M6DB_V4 0x044
+#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4 0x048
+#define QPHY_V3_PCS_TXDEEMPH_M6DB_LS 0x04c
+#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS 0x050
+#define QPHY_V3_PCS_ENDPOINT_REFCLK_DRIVE 0x054
+#define QPHY_V3_PCS_RX_IDLE_DTCT_CNTRL 0x058
+#define QPHY_V3_PCS_RATE_SLEW_CNTRL 0x05c
+#define QPHY_V3_PCS_POWER_STATE_CONFIG1 0x060
+#define QPHY_V3_PCS_POWER_STATE_CONFIG2 0x064
+#define QPHY_V3_PCS_POWER_STATE_CONFIG4 0x06c
+#define QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L 0x070
+#define QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H 0x074
+#define QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L 0x078
+#define QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H 0x07c
+#define QPHY_V3_PCS_LOCK_DETECT_CONFIG1 0x080
+#define QPHY_V3_PCS_LOCK_DETECT_CONFIG2 0x084
+#define QPHY_V3_PCS_LOCK_DETECT_CONFIG3 0x088
+#define QPHY_V3_PCS_TSYNC_RSYNC_TIME 0x08c
+#define QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK 0x0a0
+#define QPHY_V3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK 0x0a4
+#define QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK 0x0b0
+#define QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME 0x0b8
+#define QPHY_V3_PCS_RXEQTRAINING_RUN_TIME 0x0bc
+#define QPHY_V3_PCS_FLL_CNTRL1 0x0c4
+#define QPHY_V3_PCS_FLL_CNTRL2 0x0c8
+#define QPHY_V3_PCS_FLL_CNT_VAL_L 0x0cc
+#define QPHY_V3_PCS_FLL_CNT_VAL_H_TOL 0x0d0
+#define QPHY_V3_PCS_FLL_MAN_CODE 0x0d4
+#define QPHY_V3_PCS_RX_SIGDET_LVL 0x1d8
+
+/* Only for QMP V3 PHY - PCS_MISC registers */
+#define QPHY_V3_PCS_MISC_CLAMP_ENABLE 0x0c
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 6c575244c0fb..94afeac1a19e 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -1,14 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/clk.h>
@@ -37,28 +29,57 @@
#define QUSB2PHY_PLL_AUTOPGM_CTL1 0x1c
#define QUSB2PHY_PLL_PWR_CTRL 0x18
-#define QUSB2PHY_PLL_STATUS 0x38
+/* QUSB2PHY_PLL_STATUS register bits */
#define PLL_LOCKED BIT(5)
-#define QUSB2PHY_PORT_TUNE1 0x80
-#define QUSB2PHY_PORT_TUNE2 0x84
-#define QUSB2PHY_PORT_TUNE3 0x88
-#define QUSB2PHY_PORT_TUNE4 0x8c
-#define QUSB2PHY_PORT_TUNE5 0x90
-#define QUSB2PHY_PORT_TEST2 0x9c
+/* QUSB2PHY_PLL_COMMON_STATUS_ONE register bits */
+#define CORE_READY_STATUS BIT(0)
-#define QUSB2PHY_PORT_POWERDOWN 0xb4
+/* QUSB2PHY_PORT_POWERDOWN register bits */
#define CLAMP_N_EN BIT(5)
#define FREEZIO_N BIT(1)
#define POWER_DOWN BIT(0)
+/* QUSB2PHY_PWR_CTRL1 register bits */
+#define PWR_CTRL1_VREF_SUPPLY_TRIM BIT(5)
+#define PWR_CTRL1_CLAMP_N_EN BIT(1)
+
#define QUSB2PHY_REFCLK_ENABLE BIT(0)
#define PHY_CLK_SCHEME_SEL BIT(0)
+/* QUSB2PHY_INTR_CTRL register bits */
+#define DMSE_INTR_HIGH_SEL BIT(4)
+#define DPSE_INTR_HIGH_SEL BIT(3)
+#define CHG_DET_INTR_EN BIT(2)
+#define DMSE_INTR_EN BIT(1)
+#define DPSE_INTR_EN BIT(0)
+
+/* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE register bits */
+#define CORE_PLL_EN_FROM_RESET BIT(4)
+#define CORE_RESET BIT(5)
+#define CORE_RESET_MUX BIT(6)
+
+#define QUSB2PHY_PLL_ANALOG_CONTROLS_TWO 0x04
+#define QUSB2PHY_PLL_CLOCK_INVERTERS 0x18c
+#define QUSB2PHY_PLL_CMODE 0x2c
+#define QUSB2PHY_PLL_LOCK_DELAY 0x184
+#define QUSB2PHY_PLL_DIGITAL_TIMERS_TWO 0xb4
+#define QUSB2PHY_PLL_BIAS_CONTROL_1 0x194
+#define QUSB2PHY_PLL_BIAS_CONTROL_2 0x198
+#define QUSB2PHY_PWR_CTRL2 0x214
+#define QUSB2PHY_IMP_CTRL1 0x220
+#define QUSB2PHY_IMP_CTRL2 0x224
+#define QUSB2PHY_CHG_CTRL2 0x23c
+
struct qusb2_phy_init_tbl {
unsigned int offset;
unsigned int val;
+ /*
+ * register part of layout ?
+ * if yes, then offset gives index in the reg-layout
+ */
+ int in_layout;
};
#define QUSB2_PHY_INIT_CFG(o, v) \
@@ -67,30 +88,136 @@ struct qusb2_phy_init_tbl {
.val = v, \
}
+#define QUSB2_PHY_INIT_CFG_L(o, v) \
+ { \
+ .offset = o, \
+ .val = v, \
+ .in_layout = 1, \
+ }
+
+/* set of registers with offsets different per-PHY */
+enum qusb2phy_reg_layout {
+ QUSB2PHY_PLL_CORE_INPUT_OVERRIDE,
+ QUSB2PHY_PLL_STATUS,
+ QUSB2PHY_PORT_TUNE1,
+ QUSB2PHY_PORT_TUNE2,
+ QUSB2PHY_PORT_TUNE3,
+ QUSB2PHY_PORT_TUNE4,
+ QUSB2PHY_PORT_TUNE5,
+ QUSB2PHY_PORT_TEST1,
+ QUSB2PHY_PORT_TEST2,
+ QUSB2PHY_PORT_POWERDOWN,
+ QUSB2PHY_INTR_CTRL,
+};
+
+static const unsigned int msm8996_regs_layout[] = {
+ [QUSB2PHY_PLL_STATUS] = 0x38,
+ [QUSB2PHY_PORT_TUNE1] = 0x80,
+ [QUSB2PHY_PORT_TUNE2] = 0x84,
+ [QUSB2PHY_PORT_TUNE3] = 0x88,
+ [QUSB2PHY_PORT_TUNE4] = 0x8c,
+ [QUSB2PHY_PORT_TUNE5] = 0x90,
+ [QUSB2PHY_PORT_TEST1] = 0xb8,
+ [QUSB2PHY_PORT_TEST2] = 0x9c,
+ [QUSB2PHY_PORT_POWERDOWN] = 0xb4,
+ [QUSB2PHY_INTR_CTRL] = 0xbc,
+};
+
static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
- QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE1, 0xf8),
- QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE2, 0xb3),
- QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE3, 0x83),
- QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE4, 0xc0),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xf8),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0xb3),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0x83),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0xc0),
+
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),
- QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TEST2, 0x14),
+
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TEST2, 0x14),
+
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
};
+static const unsigned int qusb2_v2_regs_layout[] = {
+ [QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8,
+ [QUSB2PHY_PLL_STATUS] = 0x1a0,
+ [QUSB2PHY_PORT_TUNE1] = 0x240,
+ [QUSB2PHY_PORT_TUNE2] = 0x244,
+ [QUSB2PHY_PORT_TUNE3] = 0x248,
+ [QUSB2PHY_PORT_TUNE4] = 0x24c,
+ [QUSB2PHY_PORT_TUNE5] = 0x250,
+ [QUSB2PHY_PORT_TEST1] = 0x254,
+ [QUSB2PHY_PORT_TEST2] = 0x258,
+ [QUSB2PHY_PORT_POWERDOWN] = 0x210,
+ [QUSB2PHY_INTR_CTRL] = 0x230,
+};
+
+static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = {
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x03),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_LOCK_DELAY, 0x0a),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_BIAS_CONTROL_1, 0x40),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_BIAS_CONTROL_2, 0x20),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PWR_CTRL2, 0x21),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_IMP_CTRL1, 0x0),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_IMP_CTRL2, 0x58),
+
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0x30),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0x29),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0xca),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0x04),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE5, 0x03),
+
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_CHG_CTRL2, 0x0),
+};
+
struct qusb2_phy_cfg {
const struct qusb2_phy_init_tbl *tbl;
/* number of entries in the table */
unsigned int tbl_num;
/* offset to PHY_CLK_SCHEME register in TCSR map */
unsigned int clk_scheme_offset;
+
+ /* array of registers with different offsets */
+ const unsigned int *regs;
+ unsigned int mask_core_ready;
+ unsigned int disable_ctrl;
+ unsigned int autoresume_en;
+
+ /* true if PHY has PLL_TEST register to select clk_scheme */
+ bool has_pll_test;
+
+ /* true if TUNE1 register must be updated by fused value, else TUNE2 */
+ bool update_tune1_with_efuse;
+
+ /* true if PHY has PLL_CORE_INPUT_OVERRIDE register to reset PLL */
+ bool has_pll_override;
};
static const struct qusb2_phy_cfg msm8996_phy_cfg = {
- .tbl = msm8996_init_tbl,
- .tbl_num = ARRAY_SIZE(msm8996_init_tbl),
+ .tbl = msm8996_init_tbl,
+ .tbl_num = ARRAY_SIZE(msm8996_init_tbl),
+ .regs = msm8996_regs_layout,
+
+ .has_pll_test = true,
+ .disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
+ .mask_core_ready = PLL_LOCKED,
+ .autoresume_en = BIT(3),
+};
+
+static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {
+ .tbl = qusb2_v2_init_tbl,
+ .tbl_num = ARRAY_SIZE(qusb2_v2_init_tbl),
+ .regs = qusb2_v2_regs_layout,
+
+ .disable_ctrl = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN |
+ POWER_DOWN),
+ .mask_core_ready = CORE_READY_STATUS,
+ .has_pll_override = true,
+ .autoresume_en = BIT(0),
};
static const char * const qusb2_phy_vreg_names[] = {
@@ -116,6 +243,8 @@ static const char * const qusb2_phy_vreg_names[] = {
*
* @cfg: phy config data
* @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme
+ * @phy_initialized: indicate if PHY has been initialized
+ * @mode: current PHY mode
*/
struct qusb2_phy {
struct phy *phy;
@@ -132,6 +261,8 @@ struct qusb2_phy {
const struct qusb2_phy_cfg *cfg;
bool has_se_clk_scheme;
+ bool phy_initialized;
+ enum phy_mode mode;
};
static inline void qusb2_setbits(void __iomem *base, u32 offset, u32 val)
@@ -160,26 +291,32 @@ static inline void qusb2_clrbits(void __iomem *base, u32 offset, u32 val)
static inline
void qcom_qusb2_phy_configure(void __iomem *base,
+ const unsigned int *regs,
const struct qusb2_phy_init_tbl tbl[], int num)
{
int i;
- for (i = 0; i < num; i++)
- writel(tbl[i].val, base + tbl[i].offset);
+ for (i = 0; i < num; i++) {
+ if (tbl[i].in_layout)
+ writel(tbl[i].val, base + regs[tbl[i].offset]);
+ else
+ writel(tbl[i].val, base + tbl[i].offset);
+ }
}
/*
* Fetches HS Tx tuning value from nvmem and sets the
- * QUSB2PHY_PORT_TUNE2 register.
+ * QUSB2PHY_PORT_TUNE1/2 register.
* For error case, skip setting the value and use the default value.
*/
static void qusb2_phy_set_tune2_param(struct qusb2_phy *qphy)
{
struct device *dev = &qphy->phy->dev;
+ const struct qusb2_phy_cfg *cfg = qphy->cfg;
u8 *val;
/*
- * Read efuse register having TUNE2 parameter's high nibble.
+ * Read efuse register having TUNE2/1 parameter's high nibble.
* If efuse register shows value as 0x0, or if we fail to find
* a valid efuse register settings, then use default value
* as 0xB for high nibble that we have already set while
@@ -191,58 +328,169 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy *qphy)
return;
}
- /* Fused TUNE2 value is the higher nibble only */
- qusb2_setbits(qphy->base, QUSB2PHY_PORT_TUNE2, val[0] << 0x4);
+ /* Fused TUNE1/2 value is the higher nibble only */
+ if (cfg->update_tune1_with_efuse)
+ qusb2_setbits(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1],
+ val[0] << 0x4);
+ else
+ qusb2_setbits(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE2],
+ val[0] << 0x4);
+
}
-static int qusb2_phy_poweron(struct phy *phy)
+static int qusb2_phy_set_mode(struct phy *phy, enum phy_mode mode)
{
struct qusb2_phy *qphy = phy_get_drvdata(phy);
- int num = ARRAY_SIZE(qphy->vregs);
+
+ qphy->mode = mode;
+
+ return 0;
+}
+
+static int __maybe_unused qusb2_phy_runtime_suspend(struct device *dev)
+{
+ struct qusb2_phy *qphy = dev_get_drvdata(dev);
+ const struct qusb2_phy_cfg *cfg = qphy->cfg;
+ u32 intr_mask;
+
+ dev_vdbg(dev, "Suspending QUSB2 Phy, mode:%d\n", qphy->mode);
+
+ if (!qphy->phy_initialized) {
+ dev_vdbg(dev, "PHY not initialized, bailing out\n");
+ return 0;
+ }
+
+ /*
+ * Enable DP/DM interrupts to detect line state changes based on current
+ * speed. In other words, enable the triggers _opposite_ of what the
+ * current D+/D- levels are e.g. if currently D+ high, D- low
+ * (HS 'J'/Suspend), configure the mask to trigger on D+ low OR D- high
+ */
+ intr_mask = DPSE_INTR_EN | DMSE_INTR_EN;
+ switch (qphy->mode) {
+ case PHY_MODE_USB_HOST_HS:
+ case PHY_MODE_USB_HOST_FS:
+ case PHY_MODE_USB_DEVICE_HS:
+ case PHY_MODE_USB_DEVICE_FS:
+ intr_mask |= DMSE_INTR_HIGH_SEL;
+ break;
+ case PHY_MODE_USB_HOST_LS:
+ case PHY_MODE_USB_DEVICE_LS:
+ intr_mask |= DPSE_INTR_HIGH_SEL;
+ break;
+ default:
+ /* No device connected, enable both DP/DM high interrupt */
+ intr_mask |= DMSE_INTR_HIGH_SEL;
+ intr_mask |= DPSE_INTR_HIGH_SEL;
+ break;
+ }
+
+ writel(intr_mask, qphy->base + cfg->regs[QUSB2PHY_INTR_CTRL]);
+
+ /* hold core PLL into reset */
+ if (cfg->has_pll_override) {
+ qusb2_setbits(qphy->base,
+ cfg->regs[QUSB2PHY_PLL_CORE_INPUT_OVERRIDE],
+ CORE_PLL_EN_FROM_RESET | CORE_RESET |
+ CORE_RESET_MUX);
+ }
+
+ /* enable phy auto-resume only if device is connected on bus */
+ if (qphy->mode != PHY_MODE_INVALID) {
+ qusb2_setbits(qphy->base, cfg->regs[QUSB2PHY_PORT_TEST1],
+ cfg->autoresume_en);
+ /* Autoresume bit has to be toggled in order to enable it */
+ qusb2_clrbits(qphy->base, cfg->regs[QUSB2PHY_PORT_TEST1],
+ cfg->autoresume_en);
+ }
+
+ if (!qphy->has_se_clk_scheme)
+ clk_disable_unprepare(qphy->ref_clk);
+
+ clk_disable_unprepare(qphy->cfg_ahb_clk);
+ clk_disable_unprepare(qphy->iface_clk);
+
+ return 0;
+}
+
+static int __maybe_unused qusb2_phy_runtime_resume(struct device *dev)
+{
+ struct qusb2_phy *qphy = dev_get_drvdata(dev);
+ const struct qusb2_phy_cfg *cfg = qphy->cfg;
int ret;
- dev_vdbg(&phy->dev, "%s(): Powering-on QUSB2 phy\n", __func__);
+ dev_vdbg(dev, "Resuming QUSB2 phy, mode:%d\n", qphy->mode);
- /* turn on regulator supplies */
- ret = regulator_bulk_enable(num, qphy->vregs);
- if (ret)
- return ret;
+ if (!qphy->phy_initialized) {
+ dev_vdbg(dev, "PHY not initialized, bailing out\n");
+ return 0;
+ }
ret = clk_prepare_enable(qphy->iface_clk);
if (ret) {
- dev_err(&phy->dev, "failed to enable iface_clk, %d\n", ret);
- regulator_bulk_disable(num, qphy->vregs);
+ dev_err(dev, "failed to enable iface_clk, %d\n", ret);
return ret;
}
- return 0;
-}
+ ret = clk_prepare_enable(qphy->cfg_ahb_clk);
+ if (ret) {
+ dev_err(dev, "failed to enable cfg ahb clock, %d\n", ret);
+ goto disable_iface_clk;
+ }
-static int qusb2_phy_poweroff(struct phy *phy)
-{
- struct qusb2_phy *qphy = phy_get_drvdata(phy);
+ if (!qphy->has_se_clk_scheme) {
+ clk_prepare_enable(qphy->ref_clk);
+ if (ret) {
+ dev_err(dev, "failed to enable ref clk, %d\n", ret);
+ goto disable_ahb_clk;
+ }
+ }
- clk_disable_unprepare(qphy->iface_clk);
+ writel(0x0, qphy->base + cfg->regs[QUSB2PHY_INTR_CTRL]);
- regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
+ /* bring core PLL out of reset */
+ if (cfg->has_pll_override) {
+ qusb2_clrbits(qphy->base,
+ cfg->regs[QUSB2PHY_PLL_CORE_INPUT_OVERRIDE],
+ CORE_RESET | CORE_RESET_MUX);
+ }
return 0;
+
+disable_ahb_clk:
+ clk_disable_unprepare(qphy->cfg_ahb_clk);
+disable_iface_clk:
+ clk_disable_unprepare(qphy->iface_clk);
+
+ return ret;
}
static int qusb2_phy_init(struct phy *phy)
{
struct qusb2_phy *qphy = phy_get_drvdata(phy);
- unsigned int val;
+ const struct qusb2_phy_cfg *cfg = qphy->cfg;
+ unsigned int val = 0;
unsigned int clk_scheme;
int ret;
dev_vdbg(&phy->dev, "%s(): Initializing QUSB2 phy\n", __func__);
+ /* turn on regulator supplies */
+ ret = regulator_bulk_enable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(qphy->iface_clk);
+ if (ret) {
+ dev_err(&phy->dev, "failed to enable iface_clk, %d\n", ret);
+ goto poweroff_phy;
+ }
+
/* enable ahb interface clock to program phy */
ret = clk_prepare_enable(qphy->cfg_ahb_clk);
if (ret) {
dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
- return ret;
+ goto disable_iface_clk;
}
/* Perform phy reset */
@@ -262,20 +510,23 @@ static int qusb2_phy_init(struct phy *phy)
}
/* Disable the PHY */
- qusb2_setbits(qphy->base, QUSB2PHY_PORT_POWERDOWN,
- CLAMP_N_EN | FREEZIO_N | POWER_DOWN);
+ qusb2_setbits(qphy->base, cfg->regs[QUSB2PHY_PORT_POWERDOWN],
+ qphy->cfg->disable_ctrl);
- /* save reset value to override reference clock scheme later */
- val = readl(qphy->base + QUSB2PHY_PLL_TEST);
+ if (cfg->has_pll_test) {
+ /* save reset value to override reference clock scheme later */
+ val = readl(qphy->base + QUSB2PHY_PLL_TEST);
+ }
- qcom_qusb2_phy_configure(qphy->base, qphy->cfg->tbl,
- qphy->cfg->tbl_num);
+ qcom_qusb2_phy_configure(qphy->base, cfg->regs, cfg->tbl,
+ cfg->tbl_num);
/* Set efuse value for tuning the PHY */
qusb2_phy_set_tune2_param(qphy);
/* Enable the PHY */
- qusb2_clrbits(qphy->base, QUSB2PHY_PORT_POWERDOWN, POWER_DOWN);
+ qusb2_clrbits(qphy->base, cfg->regs[QUSB2PHY_PORT_POWERDOWN],
+ POWER_DOWN);
/* Required to get phy pll lock successfully */
usleep_range(150, 160);
@@ -308,32 +559,37 @@ static int qusb2_phy_init(struct phy *phy)
}
if (!qphy->has_se_clk_scheme) {
- val &= ~CLK_REF_SEL;
ret = clk_prepare_enable(qphy->ref_clk);
if (ret) {
dev_err(&phy->dev, "failed to enable ref clk, %d\n",
ret);
goto assert_phy_reset;
}
- } else {
- val |= CLK_REF_SEL;
}
- writel(val, qphy->base + QUSB2PHY_PLL_TEST);
+ if (cfg->has_pll_test) {
+ if (!qphy->has_se_clk_scheme)
+ val &= ~CLK_REF_SEL;
+ else
+ val |= CLK_REF_SEL;
- /* ensure above write is through */
- readl(qphy->base + QUSB2PHY_PLL_TEST);
+ writel(val, qphy->base + QUSB2PHY_PLL_TEST);
+
+ /* ensure above write is through */
+ readl(qphy->base + QUSB2PHY_PLL_TEST);
+ }
/* Required to get phy pll lock successfully */
usleep_range(100, 110);
- val = readb(qphy->base + QUSB2PHY_PLL_STATUS);
- if (!(val & PLL_LOCKED)) {
+ val = readb(qphy->base + cfg->regs[QUSB2PHY_PLL_STATUS]);
+ if (!(val & cfg->mask_core_ready)) {
dev_err(&phy->dev,
"QUSB2PHY pll lock failed: status reg = %x\n", val);
ret = -EBUSY;
goto disable_ref_clk;
}
+ qphy->phy_initialized = true;
return 0;
@@ -344,6 +600,11 @@ assert_phy_reset:
reset_control_assert(qphy->phy_reset);
disable_ahb_clk:
clk_disable_unprepare(qphy->cfg_ahb_clk);
+disable_iface_clk:
+ clk_disable_unprepare(qphy->iface_clk);
+poweroff_phy:
+ regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
+
return ret;
}
@@ -352,8 +613,8 @@ static int qusb2_phy_exit(struct phy *phy)
struct qusb2_phy *qphy = phy_get_drvdata(phy);
/* Disable the PHY */
- qusb2_setbits(qphy->base, QUSB2PHY_PORT_POWERDOWN,
- CLAMP_N_EN | FREEZIO_N | POWER_DOWN);
+ qusb2_setbits(qphy->base, qphy->cfg->regs[QUSB2PHY_PORT_POWERDOWN],
+ qphy->cfg->disable_ctrl);
if (!qphy->has_se_clk_scheme)
clk_disable_unprepare(qphy->ref_clk);
@@ -361,6 +622,11 @@ static int qusb2_phy_exit(struct phy *phy)
reset_control_assert(qphy->phy_reset);
clk_disable_unprepare(qphy->cfg_ahb_clk);
+ clk_disable_unprepare(qphy->iface_clk);
+
+ regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
+
+ qphy->phy_initialized = false;
return 0;
}
@@ -368,8 +634,7 @@ static int qusb2_phy_exit(struct phy *phy)
static const struct phy_ops qusb2_phy_gen_ops = {
.init = qusb2_phy_init,
.exit = qusb2_phy_exit,
- .power_on = qusb2_phy_poweron,
- .power_off = qusb2_phy_poweroff,
+ .set_mode = qusb2_phy_set_mode,
.owner = THIS_MODULE,
};
@@ -377,11 +642,19 @@ static const struct of_device_id qusb2_phy_of_match_table[] = {
{
.compatible = "qcom,msm8996-qusb2-phy",
.data = &msm8996_phy_cfg,
+ }, {
+ .compatible = "qcom,qusb2-v2-phy",
+ .data = &qusb2_v2_phy_cfg,
},
{ },
};
MODULE_DEVICE_TABLE(of, qusb2_phy_of_match_table);
+static const struct dev_pm_ops qusb2_phy_pm_ops = {
+ SET_RUNTIME_PM_OPS(qusb2_phy_runtime_suspend,
+ qusb2_phy_runtime_resume, NULL)
+};
+
static int qusb2_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -459,11 +732,19 @@ static int qusb2_phy_probe(struct platform_device *pdev)
qphy->cell = NULL;
dev_dbg(dev, "failed to lookup tune2 hstx trim value\n");
}
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ /*
+ * Prevent runtime pm from being ON by default. Users can enable
+ * it using power/control in sysfs.
+ */
+ pm_runtime_forbid(dev);
generic_phy = devm_phy_create(dev, NULL, &qusb2_phy_gen_ops);
if (IS_ERR(generic_phy)) {
ret = PTR_ERR(generic_phy);
dev_err(dev, "failed to create phy, %d\n", ret);
+ pm_runtime_disable(dev);
return ret;
}
qphy->phy = generic_phy;
@@ -474,6 +755,8 @@ static int qusb2_phy_probe(struct platform_device *pdev)
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (!IS_ERR(phy_provider))
dev_info(dev, "Registered Qcom-QUSB2 phy\n");
+ else
+ pm_runtime_disable(dev);
return PTR_ERR_OR_ZERO(phy_provider);
}
@@ -482,6 +765,7 @@ static struct platform_driver qusb2_phy_driver = {
.probe = qusb2_phy_probe,
.driver = {
.name = "qcom-qusb2-phy",
+ .pm = &qusb2_phy_pm_ops,
.of_match_table = qusb2_phy_of_match_table,
},
};
diff --git a/drivers/phy/ralink/Kconfig b/drivers/phy/ralink/Kconfig
index b17635b407bc..14fd219535ef 100644
--- a/drivers/phy/ralink/Kconfig
+++ b/drivers/phy/ralink/Kconfig
@@ -4,6 +4,7 @@
config PHY_RALINK_USB
tristate "Ralink USB PHY driver"
depends on RALINK || COMPILE_TEST
+ depends on HAS_IOMEM
select GENERIC_PHY
select MFD_SYSCON
help
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
index 9c90e7d67e0a..fb8f05e39cf7 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
@@ -397,6 +397,10 @@ static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
.data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS,
},
{
+ .compatible = "renesas,usb2-phy-r8a77965",
+ .data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS,
+ },
+ {
.compatible = "renesas,rcar-gen3-usb2-phy",
},
{ }
diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index f5325b2b679e..0e15119ddfc6 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -29,6 +29,7 @@ config PHY_ROCKCHIP_INNO_USB2
config PHY_ROCKCHIP_PCIE
tristate "Rockchip PCIe PHY Driver"
depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST
+ depends on HAS_IOMEM
select GENERIC_PHY
select MFD_SYSCON
help
diff --git a/drivers/phy/rockchip/phy-rockchip-emmc.c b/drivers/phy/rockchip/phy-rockchip-emmc.c
index f1b24f18e9b2..b237360f95f6 100644
--- a/drivers/phy/rockchip/phy-rockchip-emmc.c
+++ b/drivers/phy/rockchip/phy-rockchip-emmc.c
@@ -76,6 +76,13 @@
#define PHYCTRL_OTAPDLYSEL_MASK 0xf
#define PHYCTRL_OTAPDLYSEL_SHIFT 0x7
+#define PHYCTRL_IS_CALDONE(x) \
+ ((((x) >> PHYCTRL_CALDONE_SHIFT) & \
+ PHYCTRL_CALDONE_MASK) == PHYCTRL_CALDONE_DONE)
+#define PHYCTRL_IS_DLLRDY(x) \
+ ((((x) >> PHYCTRL_DLLRDY_SHIFT) & \
+ PHYCTRL_DLLRDY_MASK) == PHYCTRL_DLLRDY_DONE)
+
struct rockchip_emmc_phy {
unsigned int reg_offset;
struct regmap *reg_base;
@@ -89,7 +96,7 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off)
unsigned int dllrdy;
unsigned int freqsel = PHYCTRL_FREQSEL_200M;
unsigned long rate;
- unsigned long timeout;
+ int ret;
/*
* Keep phyctrl_pdb and phyctrl_endll low to allow
@@ -160,17 +167,19 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off)
PHYCTRL_PDB_SHIFT));
/*
- * According to the user manual, it asks driver to
- * wait 5us for calpad busy trimming
+ * According to the user manual, it asks driver to wait 5us for
+ * calpad busy trimming. However it is documented that this value is
+ * PVT(A.K.A process,voltage and temperature) relevant, so some
+ * failure cases are found which indicates we should be more tolerant
+ * to 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;
+ ret = regmap_read_poll_timeout(rk_phy->reg_base,
+ rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
+ caldone, PHYCTRL_IS_CALDONE(caldone),
+ 0, 50);
+ if (ret) {
+ pr_err("%s: caldone failed, ret=%d\n", __func__, ret);
+ return ret;
}
/* Set the frequency of the DLL operation */
@@ -210,28 +219,15 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off)
* NOTE: There appear to be corner cases where the DLL seems to take
* extra long to lock for reasons that aren't understood. In some
* extreme cases we've seen it take up to over 10ms (!). We'll be
- * generous and give it 50ms. We still busy wait here because:
- * - In most cases it should be super fast.
- * - This is not called lots during normal operation so it shouldn't
- * be a power or performance problem to busy wait. We expect it
- * only at boot / resume. In both cases, eMMC is probably on the
- * critical path so busy waiting a little extra time should be OK.
+ * generous and give it 50ms.
*/
- timeout = jiffies + msecs_to_jiffies(50);
- do {
- udelay(1);
-
- 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)
- break;
- } while (!time_after(jiffies, timeout));
-
- if (dllrdy != PHYCTRL_DLLRDY_DONE) {
- pr_err("rockchip_emmc_phy_power: dllrdy timeout.\n");
- return -ETIMEDOUT;
+ ret = regmap_read_poll_timeout(rk_phy->reg_base,
+ rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
+ dllrdy, PHYCTRL_IS_DLLRDY(dllrdy),
+ 0, 50 * USEC_PER_MSEC);
+ if (ret) {
+ pr_err("%s: dllrdy failed. ret=%d\n", __func__, ret);
+ return ret;
}
return 0;
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index 7492c8978217..76a4b58ec771 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -355,11 +355,26 @@ struct usb3phy_reg {
u32 write_enable;
};
+/**
+ * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration.
+ * @reg: the base address for usb3-phy config.
+ * @typec_conn_dir: the register of type-c connector direction.
+ * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable.
+ * @external_psm: the register of type-c phy external psm clock.
+ * @pipe_status: the register of type-c phy pipe status.
+ * @usb3_host_disable: the register of type-c usb3 host disable.
+ * @usb3_host_port: the register of type-c usb3 host port.
+ * @uphy_dp_sel: the register of type-c phy DP select control.
+ */
struct rockchip_usb3phy_port_cfg {
+ unsigned int reg;
struct usb3phy_reg typec_conn_dir;
struct usb3phy_reg usb3tousb2_en;
struct usb3phy_reg external_psm;
struct usb3phy_reg pipe_status;
+ struct usb3phy_reg usb3_host_disable;
+ struct usb3phy_reg usb3_host_port;
+ struct usb3phy_reg uphy_dp_sel;
};
struct rockchip_typec_phy {
@@ -372,7 +387,7 @@ struct rockchip_typec_phy {
struct reset_control *uphy_rst;
struct reset_control *pipe_rst;
struct reset_control *tcphy_rst;
- struct rockchip_usb3phy_port_cfg port_cfgs;
+ const struct rockchip_usb3phy_port_cfg *port_cfgs;
/* mutex to protect access to individual PHYs */
struct mutex lock;
@@ -424,6 +439,30 @@ struct phy_reg dp_pll_cfg[] = {
{ 0x4, CMN_DIAG_PLL1_INCLK_CTRL },
};
+static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = {
+ {
+ .reg = 0xff7c0000,
+ .typec_conn_dir = { 0xe580, 0, 16 },
+ .usb3tousb2_en = { 0xe580, 3, 19 },
+ .external_psm = { 0xe588, 14, 30 },
+ .pipe_status = { 0xe5c0, 0, 0 },
+ .usb3_host_disable = { 0x2434, 0, 16 },
+ .usb3_host_port = { 0x2434, 12, 28 },
+ .uphy_dp_sel = { 0x6268, 19, 19 },
+ },
+ {
+ .reg = 0xff800000,
+ .typec_conn_dir = { 0xe58c, 0, 16 },
+ .usb3tousb2_en = { 0xe58c, 3, 19 },
+ .external_psm = { 0xe594, 14, 30 },
+ .pipe_status = { 0xe5c0, 16, 16 },
+ .usb3_host_disable = { 0x2444, 0, 16 },
+ .usb3_host_port = { 0x2444, 12, 28 },
+ .uphy_dp_sel = { 0x6268, 3, 19 },
+ },
+ { /* sentinel */ }
+};
+
static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy)
{
u32 i, rdata;
@@ -691,7 +730,7 @@ static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy)
static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode)
{
- struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs;
+ const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs;
int ret, i;
u32 val;
@@ -782,6 +821,9 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy)
u8 mode;
int ret;
+ if (!edev)
+ return MODE_DFP_USB;
+
ufp = extcon_get_state(edev, EXTCON_USB);
dp = extcon_get_state(edev, EXTCON_DISP_DP);
@@ -818,10 +860,22 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy)
return mode;
}
+static int tcphy_cfg_usb3_to_usb2_only(struct rockchip_typec_phy *tcphy,
+ bool value)
+{
+ const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs;
+
+ property_enable(tcphy, &cfg->usb3tousb2_en, value);
+ property_enable(tcphy, &cfg->usb3_host_disable, value);
+ property_enable(tcphy, &cfg->usb3_host_port, !value);
+
+ return 0;
+}
+
static int rockchip_usb3_phy_power_on(struct phy *phy)
{
struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy);
- struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs;
+ const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs;
const struct usb3phy_reg *reg = &cfg->pipe_status;
int timeout, new_mode, ret = 0;
u32 val;
@@ -835,8 +889,10 @@ static int rockchip_usb3_phy_power_on(struct phy *phy)
}
/* DP-only mode; fall back to USB2 */
- if (!(new_mode & (MODE_DFP_USB | MODE_UFP_USB)))
+ if (!(new_mode & (MODE_DFP_USB | MODE_UFP_USB))) {
+ tcphy_cfg_usb3_to_usb2_only(tcphy, true);
goto unlock_ret;
+ }
if (tcphy->mode == new_mode)
goto unlock_ret;
@@ -852,6 +908,9 @@ static int rockchip_usb3_phy_power_on(struct phy *phy)
regmap_read(tcphy->grf_regs, reg->offset, &val);
if (!(val & BIT(reg->enable_bit))) {
tcphy->mode |= new_mode & (MODE_DFP_USB | MODE_UFP_USB);
+
+ /* enable usb3 host */
+ tcphy_cfg_usb3_to_usb2_only(tcphy, false);
goto unlock_ret;
}
usleep_range(10, 20);
@@ -872,6 +931,7 @@ static int rockchip_usb3_phy_power_off(struct phy *phy)
struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy);
mutex_lock(&tcphy->lock);
+ tcphy_cfg_usb3_to_usb2_only(tcphy, false);
if (tcphy->mode == MODE_DISCONNECT)
goto unlock;
@@ -894,6 +954,7 @@ static const struct phy_ops rockchip_usb3_phy_ops = {
static int rockchip_dp_phy_power_on(struct phy *phy)
{
struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy);
+ const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs;
int new_mode, ret = 0;
u32 val;
@@ -926,6 +987,8 @@ static int rockchip_dp_phy_power_on(struct phy *phy)
if (ret)
goto unlock_ret;
+ property_enable(tcphy, &cfg->uphy_dp_sel, 1);
+
ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
val, val & DP_MODE_A2, 1000,
PHY_MODE_SET_TIMEOUT);
@@ -984,51 +1047,9 @@ static const struct phy_ops rockchip_dp_phy_ops = {
.owner = THIS_MODULE,
};
-static int tcphy_get_param(struct device *dev,
- struct usb3phy_reg *reg,
- const char *name)
-{
- u32 buffer[3];
- int ret;
-
- ret = of_property_read_u32_array(dev->of_node, name, buffer, 3);
- if (ret) {
- dev_err(dev, "Can not parse %s\n", name);
- return ret;
- }
-
- reg->offset = buffer[0];
- reg->enable_bit = buffer[1];
- reg->write_enable = buffer[2];
- return 0;
-}
-
static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy,
struct device *dev)
{
- struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs;
- int ret;
-
- ret = tcphy_get_param(dev, &cfg->typec_conn_dir,
- "rockchip,typec-conn-dir");
- if (ret)
- return ret;
-
- ret = tcphy_get_param(dev, &cfg->usb3tousb2_en,
- "rockchip,usb3tousb2-en");
- if (ret)
- return ret;
-
- ret = tcphy_get_param(dev, &cfg->external_psm,
- "rockchip,external-psm");
- if (ret)
- return ret;
-
- ret = tcphy_get_param(dev, &cfg->pipe_status,
- "rockchip,pipe-status");
- if (ret)
- return ret;
-
tcphy->grf_regs = syscon_regmap_lookup_by_phandle(dev->of_node,
"rockchip,grf");
if (IS_ERR(tcphy->grf_regs)) {
@@ -1071,7 +1092,7 @@ static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy,
static void typec_phy_pre_init(struct rockchip_typec_phy *tcphy)
{
- struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs;
+ const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs;
reset_control_assert(tcphy->tcphy_rst);
reset_control_assert(tcphy->uphy_rst);
@@ -1092,17 +1113,43 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
struct rockchip_typec_phy *tcphy;
struct phy_provider *phy_provider;
struct resource *res;
- int ret;
+ const struct rockchip_usb3phy_port_cfg *phy_cfgs;
+ const struct of_device_id *match;
+ int index, ret;
tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL);
if (!tcphy)
return -ENOMEM;
+ match = of_match_device(dev->driver->of_match_table, dev);
+ if (!match || !match->data) {
+ dev_err(dev, "phy configs are not assigned!\n");
+ return -EINVAL;
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
tcphy->base = devm_ioremap_resource(dev, res);
if (IS_ERR(tcphy->base))
return PTR_ERR(tcphy->base);
+ phy_cfgs = match->data;
+ /* find out a proper config which can be matched with dt. */
+ index = 0;
+ while (phy_cfgs[index].reg) {
+ if (phy_cfgs[index].reg == res->start) {
+ tcphy->port_cfgs = &phy_cfgs[index];
+ break;
+ }
+
+ ++index;
+ }
+
+ if (!tcphy->port_cfgs) {
+ dev_err(dev, "no phy-config can be matched with %s node\n",
+ np->name);
+ return -EINVAL;
+ }
+
ret = tcphy_parse_dt(tcphy, dev);
if (ret)
return ret;
@@ -1115,9 +1162,13 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
tcphy->extcon = extcon_get_edev_by_phandle(dev, 0);
if (IS_ERR(tcphy->extcon)) {
- if (PTR_ERR(tcphy->extcon) != -EPROBE_DEFER)
- dev_err(dev, "Invalid or missing extcon\n");
- return PTR_ERR(tcphy->extcon);
+ if (PTR_ERR(tcphy->extcon) == -ENODEV) {
+ tcphy->extcon = NULL;
+ } else {
+ if (PTR_ERR(tcphy->extcon) != -EPROBE_DEFER)
+ dev_err(dev, "Invalid or missing extcon\n");
+ return PTR_ERR(tcphy->extcon);
+ }
}
pm_runtime_enable(dev);
@@ -1162,8 +1213,11 @@ static int rockchip_typec_phy_remove(struct platform_device *pdev)
}
static const struct of_device_id rockchip_typec_phy_dt_ids[] = {
- { .compatible = "rockchip,rk3399-typec-phy" },
- {}
+ {
+ .compatible = "rockchip,rk3399-typec-phy",
+ .data = &rk3399_usb3phy_port_cfgs
+ },
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids);
diff --git a/drivers/phy/samsung/Kconfig b/drivers/phy/samsung/Kconfig
index b7e0645a7bd9..2a5d33cb0e7e 100644
--- a/drivers/phy/samsung/Kconfig
+++ b/drivers/phy/samsung/Kconfig
@@ -49,7 +49,7 @@ config PHY_EXYNOS4210_USB2
config PHY_EXYNOS4X12_USB2
bool
depends on PHY_SAMSUNG_USB2
- default SOC_EXYNOS3250 || SOC_EXYNOS4212 || SOC_EXYNOS4412
+ default SOC_EXYNOS3250 || SOC_EXYNOS4412
config PHY_EXYNOS5250_USB2
bool
diff --git a/drivers/phy/st/Kconfig b/drivers/phy/st/Kconfig
index 0814d3f87ec6..609719bdfa50 100644
--- a/drivers/phy/st/Kconfig
+++ b/drivers/phy/st/Kconfig
@@ -31,3 +31,17 @@ config PHY_STIH407_USB
help
Enable this support to enable the picoPHY device used by USB2
and USB3 controllers on STMicroelectronics STiH407 SoC families.
+
+config PHY_STM32_USBPHYC
+ tristate "STMicroelectronics STM32 USB HS PHY Controller driver"
+ depends on ARCH_STM32 || COMPILE_TEST
+ select GENERIC_PHY
+ help
+ Enable this to support the High-Speed USB transceivers that are part
+ of some STMicroelectronics STM32 SoCs.
+
+ This driver controls the entire USB PHY block: the USB PHY controller
+ (USBPHYC) and the two 8-bit wide UTMI+ interfaces. First interface is
+ used by an HS USB Host controller, and the second one is shared
+ between an HS USB OTG controller and an HS USB Host controller,
+ selected by a USB switch.
diff --git a/drivers/phy/st/Makefile b/drivers/phy/st/Makefile
index e2adfe2166d2..c0091ad1fd48 100644
--- a/drivers/phy/st/Makefile
+++ b/drivers/phy/st/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o
obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o
obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o
+obj-$(CONFIG_PHY_STM32_USBPHYC) += phy-stm32-usbphyc.o
diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c
new file mode 100644
index 000000000000..bc4e78a19c91
--- /dev/null
+++ b/drivers/phy/st/phy-stm32-usbphyc.c
@@ -0,0 +1,461 @@
+// SPDX-Licence-Identifier: GPL-2.0
+/*
+ * STMicroelectronics STM32 USB PHY Controller driver
+ *
+ * Copyright (C) 2018 STMicroelectronics
+ * Author(s): Amelie Delaunay <amelie.delaunay@st.com>.
+ */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/reset.h>
+
+#define STM32_USBPHYC_PLL 0x0
+#define STM32_USBPHYC_MISC 0x8
+#define STM32_USBPHYC_VERSION 0x3F4
+
+/* STM32_USBPHYC_PLL bit fields */
+#define PLLNDIV GENMASK(6, 0)
+#define PLLFRACIN GENMASK(25, 10)
+#define PLLEN BIT(26)
+#define PLLSTRB BIT(27)
+#define PLLSTRBYP BIT(28)
+#define PLLFRACCTL BIT(29)
+#define PLLDITHEN0 BIT(30)
+#define PLLDITHEN1 BIT(31)
+
+/* STM32_USBPHYC_MISC bit fields */
+#define SWITHOST BIT(0)
+
+/* STM32_USBPHYC_VERSION bit fields */
+#define MINREV GENMASK(3, 0)
+#define MAJREV GENMASK(7, 4)
+
+static const char * const supplies_names[] = {
+ "vdda1v1", /* 1V1 */
+ "vdda1v8", /* 1V8 */
+};
+
+#define NUM_SUPPLIES ARRAY_SIZE(supplies_names)
+
+#define PLL_LOCK_TIME_US 100
+#define PLL_PWR_DOWN_TIME_US 5
+#define PLL_FVCO_MHZ 2880
+#define PLL_INFF_MIN_RATE_HZ 19200000
+#define PLL_INFF_MAX_RATE_HZ 38400000
+#define HZ_PER_MHZ 1000000L
+
+struct pll_params {
+ u8 ndiv;
+ u16 frac;
+};
+
+struct stm32_usbphyc_phy {
+ struct phy *phy;
+ struct stm32_usbphyc *usbphyc;
+ struct regulator_bulk_data supplies[NUM_SUPPLIES];
+ u32 index;
+ bool active;
+};
+
+struct stm32_usbphyc {
+ struct device *dev;
+ void __iomem *base;
+ struct clk *clk;
+ struct reset_control *rst;
+ struct stm32_usbphyc_phy **phys;
+ int nphys;
+ int switch_setup;
+ bool pll_enabled;
+};
+
+static inline void stm32_usbphyc_set_bits(void __iomem *reg, u32 bits)
+{
+ writel_relaxed(readl_relaxed(reg) | bits, reg);
+}
+
+static inline void stm32_usbphyc_clr_bits(void __iomem *reg, u32 bits)
+{
+ writel_relaxed(readl_relaxed(reg) & ~bits, reg);
+}
+
+static void stm32_usbphyc_get_pll_params(u32 clk_rate, struct pll_params *pll_params)
+{
+ unsigned long long fvco, ndiv, frac;
+
+ /* _
+ * | FVCO = INFF*2*(NDIV + FRACT/2^16) when DITHER_DISABLE[1] = 1
+ * | FVCO = 2880MHz
+ * <
+ * | NDIV = integer part of input bits to set the LDF
+ * |_FRACT = fractional part of input bits to set the LDF
+ * => PLLNDIV = integer part of (FVCO / (INFF*2))
+ * => PLLFRACIN = fractional part of(FVCO / INFF*2) * 2^16
+ * <=> PLLFRACIN = ((FVCO / (INFF*2)) - PLLNDIV) * 2^16
+ */
+ fvco = (unsigned long long)PLL_FVCO_MHZ * HZ_PER_MHZ;
+
+ ndiv = fvco;
+ do_div(ndiv, (clk_rate * 2));
+ pll_params->ndiv = (u8)ndiv;
+
+ frac = fvco * (1 << 16);
+ do_div(frac, (clk_rate * 2));
+ frac = frac - (ndiv * (1 << 16));
+ pll_params->frac = (u16)frac;
+}
+
+static int stm32_usbphyc_pll_init(struct stm32_usbphyc *usbphyc)
+{
+ struct pll_params pll_params;
+ u32 clk_rate = clk_get_rate(usbphyc->clk);
+ u32 ndiv, frac;
+ u32 usbphyc_pll;
+
+ if ((clk_rate < PLL_INFF_MIN_RATE_HZ) ||
+ (clk_rate > PLL_INFF_MAX_RATE_HZ)) {
+ dev_err(usbphyc->dev, "input clk freq (%dHz) out of range\n",
+ clk_rate);
+ return -EINVAL;
+ }
+
+ stm32_usbphyc_get_pll_params(clk_rate, &pll_params);
+ ndiv = FIELD_PREP(PLLNDIV, pll_params.ndiv);
+ frac = FIELD_PREP(PLLFRACIN, pll_params.frac);
+
+ usbphyc_pll = PLLDITHEN1 | PLLDITHEN0 | PLLSTRBYP | ndiv;
+
+ if (pll_params.frac)
+ usbphyc_pll |= PLLFRACCTL | frac;
+
+ writel_relaxed(usbphyc_pll, usbphyc->base + STM32_USBPHYC_PLL);
+
+ dev_dbg(usbphyc->dev, "input clk freq=%dHz, ndiv=%lu, frac=%lu\n",
+ clk_rate, FIELD_GET(PLLNDIV, usbphyc_pll),
+ FIELD_GET(PLLFRACIN, usbphyc_pll));
+
+ return 0;
+}
+
+static bool stm32_usbphyc_has_one_phy_active(struct stm32_usbphyc *usbphyc)
+{
+ int i;
+
+ for (i = 0; i < usbphyc->nphys; i++)
+ if (usbphyc->phys[i]->active)
+ return true;
+
+ return false;
+}
+
+static int stm32_usbphyc_pll_enable(struct stm32_usbphyc *usbphyc)
+{
+ void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL;
+ bool pllen = (readl_relaxed(pll_reg) & PLLEN);
+ int ret;
+
+ /* Check if one phy port has already configured the pll */
+ if (pllen && stm32_usbphyc_has_one_phy_active(usbphyc))
+ return 0;
+
+ if (pllen) {
+ stm32_usbphyc_clr_bits(pll_reg, PLLEN);
+ /* Wait for minimum width of powerdown pulse (ENABLE = Low) */
+ udelay(PLL_PWR_DOWN_TIME_US);
+ }
+
+ ret = stm32_usbphyc_pll_init(usbphyc);
+ if (ret)
+ return ret;
+
+ stm32_usbphyc_set_bits(pll_reg, PLLEN);
+
+ /* Wait for maximum lock time */
+ udelay(PLL_LOCK_TIME_US);
+
+ if (!(readl_relaxed(pll_reg) & PLLEN)) {
+ dev_err(usbphyc->dev, "PLLEN not set\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc)
+{
+ void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL;
+
+ /* Check if other phy port active */
+ if (stm32_usbphyc_has_one_phy_active(usbphyc))
+ return 0;
+
+ stm32_usbphyc_clr_bits(pll_reg, PLLEN);
+ /* Wait for minimum width of powerdown pulse (ENABLE = Low) */
+ udelay(PLL_PWR_DOWN_TIME_US);
+
+ if (readl_relaxed(pll_reg) & PLLEN) {
+ dev_err(usbphyc->dev, "PLL not reset\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int stm32_usbphyc_phy_init(struct phy *phy)
+{
+ struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy);
+ struct stm32_usbphyc *usbphyc = usbphyc_phy->usbphyc;
+ int ret;
+
+ ret = stm32_usbphyc_pll_enable(usbphyc);
+ if (ret)
+ return ret;
+
+ usbphyc_phy->active = true;
+
+ return 0;
+}
+
+static int stm32_usbphyc_phy_exit(struct phy *phy)
+{
+ struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy);
+ struct stm32_usbphyc *usbphyc = usbphyc_phy->usbphyc;
+
+ usbphyc_phy->active = false;
+
+ return stm32_usbphyc_pll_disable(usbphyc);
+}
+
+static int stm32_usbphyc_phy_power_on(struct phy *phy)
+{
+ struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy);
+
+ return regulator_bulk_enable(NUM_SUPPLIES, usbphyc_phy->supplies);
+}
+
+static int stm32_usbphyc_phy_power_off(struct phy *phy)
+{
+ struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy);
+
+ return regulator_bulk_disable(NUM_SUPPLIES, usbphyc_phy->supplies);
+}
+
+static const struct phy_ops stm32_usbphyc_phy_ops = {
+ .init = stm32_usbphyc_phy_init,
+ .exit = stm32_usbphyc_phy_exit,
+ .power_on = stm32_usbphyc_phy_power_on,
+ .power_off = stm32_usbphyc_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc,
+ u32 utmi_switch)
+{
+ if (!utmi_switch)
+ stm32_usbphyc_clr_bits(usbphyc->base + STM32_USBPHYC_MISC,
+ SWITHOST);
+ else
+ stm32_usbphyc_set_bits(usbphyc->base + STM32_USBPHYC_MISC,
+ SWITHOST);
+ usbphyc->switch_setup = utmi_switch;
+}
+
+static struct phy *stm32_usbphyc_of_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct stm32_usbphyc *usbphyc = dev_get_drvdata(dev);
+ struct stm32_usbphyc_phy *usbphyc_phy = NULL;
+ struct device_node *phynode = args->np;
+
+ int port = 0;
+
+ for (port = 0; port < usbphyc->nphys; port++) {
+ if (phynode == usbphyc->phys[port]->phy->dev.of_node) {
+ usbphyc_phy = usbphyc->phys[port];
+ break;
+ }
+ }
+ if (!usbphyc_phy) {
+ dev_err(dev, "failed to find phy\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (((usbphyc_phy->index == 0) && (args->args_count != 0)) ||
+ ((usbphyc_phy->index == 1) && (args->args_count != 1))) {
+ dev_err(dev, "invalid number of cells for phy port%d\n",
+ usbphyc_phy->index);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* Configure the UTMI switch for PHY port#2 */
+ if (usbphyc_phy->index == 1) {
+ if (usbphyc->switch_setup < 0) {
+ stm32_usbphyc_switch_setup(usbphyc, args->args[0]);
+ } else {
+ if (args->args[0] != usbphyc->switch_setup) {
+ dev_err(dev, "phy port1 already used\n");
+ return ERR_PTR(-EBUSY);
+ }
+ }
+ }
+
+ return usbphyc_phy->phy;
+}
+
+static int stm32_usbphyc_probe(struct platform_device *pdev)
+{
+ struct stm32_usbphyc *usbphyc;
+ struct device *dev = &pdev->dev;
+ struct device_node *child, *np = dev->of_node;
+ struct resource *res;
+ struct phy_provider *phy_provider;
+ u32 version;
+ int ret, port = 0;
+
+ usbphyc = devm_kzalloc(dev, sizeof(*usbphyc), GFP_KERNEL);
+ if (!usbphyc)
+ return -ENOMEM;
+ usbphyc->dev = dev;
+ dev_set_drvdata(dev, usbphyc);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ usbphyc->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(usbphyc->base))
+ return PTR_ERR(usbphyc->base);
+
+ usbphyc->clk = devm_clk_get(dev, 0);
+ if (IS_ERR(usbphyc->clk)) {
+ ret = PTR_ERR(usbphyc->clk);
+ dev_err(dev, "clk get failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(usbphyc->clk);
+ if (ret) {
+ dev_err(dev, "clk enable failed: %d\n", ret);
+ return ret;
+ }
+
+ usbphyc->rst = devm_reset_control_get(dev, 0);
+ if (!IS_ERR(usbphyc->rst)) {
+ reset_control_assert(usbphyc->rst);
+ udelay(2);
+ reset_control_deassert(usbphyc->rst);
+ }
+
+ usbphyc->switch_setup = -EINVAL;
+ usbphyc->nphys = of_get_child_count(np);
+ usbphyc->phys = devm_kcalloc(dev, usbphyc->nphys,
+ sizeof(*usbphyc->phys), GFP_KERNEL);
+ if (!usbphyc->phys) {
+ ret = -ENOMEM;
+ goto clk_disable;
+ }
+
+ for_each_child_of_node(np, child) {
+ struct stm32_usbphyc_phy *usbphyc_phy;
+ struct phy *phy;
+ u32 index;
+ int i;
+
+ phy = devm_phy_create(dev, child, &stm32_usbphyc_phy_ops);
+ if (IS_ERR(phy)) {
+ ret = PTR_ERR(phy);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev,
+ "failed to create phy%d: %d\n", i, ret);
+ goto put_child;
+ }
+
+ usbphyc_phy = devm_kzalloc(dev, sizeof(*usbphyc_phy),
+ GFP_KERNEL);
+ if (!usbphyc_phy) {
+ ret = -ENOMEM;
+ goto put_child;
+ }
+
+ for (i = 0; i < NUM_SUPPLIES; i++)
+ usbphyc_phy->supplies[i].supply = supplies_names[i];
+
+ ret = devm_regulator_bulk_get(&phy->dev, NUM_SUPPLIES,
+ usbphyc_phy->supplies);
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(&phy->dev,
+ "failed to get regulators: %d\n", ret);
+ goto put_child;
+ }
+
+ ret = of_property_read_u32(child, "reg", &index);
+ if (ret || index > usbphyc->nphys) {
+ dev_err(&phy->dev, "invalid reg property: %d\n", ret);
+ goto put_child;
+ }
+
+ usbphyc->phys[port] = usbphyc_phy;
+ phy_set_bus_width(phy, 8);
+ phy_set_drvdata(phy, usbphyc_phy);
+
+ usbphyc->phys[port]->phy = phy;
+ usbphyc->phys[port]->usbphyc = usbphyc;
+ usbphyc->phys[port]->index = index;
+ usbphyc->phys[port]->active = false;
+
+ port++;
+ }
+
+ phy_provider = devm_of_phy_provider_register(dev,
+ stm32_usbphyc_of_xlate);
+ if (IS_ERR(phy_provider)) {
+ ret = PTR_ERR(phy_provider);
+ dev_err(dev, "failed to register phy provider: %d\n", ret);
+ goto clk_disable;
+ }
+
+ version = readl_relaxed(usbphyc->base + STM32_USBPHYC_VERSION);
+ dev_info(dev, "registered rev:%lu.%lu\n",
+ FIELD_GET(MAJREV, version), FIELD_GET(MINREV, version));
+
+ return 0;
+
+put_child:
+ of_node_put(child);
+clk_disable:
+ clk_disable_unprepare(usbphyc->clk);
+
+ return ret;
+}
+
+static int stm32_usbphyc_remove(struct platform_device *pdev)
+{
+ struct stm32_usbphyc *usbphyc = dev_get_drvdata(&pdev->dev);
+
+ clk_disable_unprepare(usbphyc->clk);
+
+ return 0;
+}
+
+static const struct of_device_id stm32_usbphyc_of_match[] = {
+ { .compatible = "st,stm32mp1-usbphyc", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, stm32_usbphyc_of_match);
+
+static struct platform_driver stm32_usbphyc_driver = {
+ .probe = stm32_usbphyc_probe,
+ .remove = stm32_usbphyc_remove,
+ .driver = {
+ .of_match_table = stm32_usbphyc_of_match,
+ .name = "stm32-usbphyc",
+ }
+};
+module_platform_driver(stm32_usbphyc_driver);
+
+MODULE_DESCRIPTION("STMicroelectronics STM32 USBPHYC driver");
+MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c
index 9d0689ebd28c..05bee32a3a4d 100644
--- a/drivers/phy/tegra/xusb-tegra210.c
+++ b/drivers/phy/tegra/xusb-tegra210.c
@@ -169,6 +169,7 @@
#define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN (1 << 0)
#define XUSB_PADCTL_UPHY_PLL_P0_CTL4 0x36c
+#define XUSB_PADCTL_UPHY_PLL_CTL4_XDIGCLK_EN (1 << 19)
#define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN (1 << 15)
#define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT 12
#define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK 0x3
@@ -537,11 +538,8 @@ static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl, bool usb)
value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SATA_VAL <<
XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT);
- /* XXX PLL0_XDIGCLK_EN */
- /*
- value &= ~(1 << 19);
+ value &= ~XUSB_PADCTL_UPHY_PLL_CTL4_XDIGCLK_EN;
padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL4);
- */
value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
value &= ~((XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK <<
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
index 63e916d4d069..11aa5902a9ac 100644
--- a/drivers/phy/tegra/xusb.c
+++ b/drivers/phy/tegra/xusb.c
@@ -418,7 +418,7 @@ tegra_xusb_port_find_lane(struct tegra_xusb_port *port,
{
struct tegra_xusb_lane *lane, *match = ERR_PTR(-ENODEV);
- for (map = map; map->type; map++) {
+ for (; map->type; map++) {
if (port->index != map->port)
continue;
diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c
index 380ef7ec094f..39d4100c60a2 100644
--- a/drivers/platform/x86/intel_cht_int33fe.c
+++ b/drivers/platform/x86/intel_cht_int33fe.c
@@ -33,6 +33,8 @@ struct cht_int33fe_data {
struct i2c_client *max17047;
struct i2c_client *fusb302;
struct i2c_client *pi3usb30532;
+ /* Contain a list-head must be per device */
+ struct device_connection connections[3];
};
/*
@@ -172,6 +174,20 @@ static int cht_int33fe_probe(struct i2c_client *client)
return -EPROBE_DEFER; /* Wait for i2c-adapter to load */
}
+ data->connections[0].endpoint[0] = "i2c-fusb302";
+ data->connections[0].endpoint[1] = "i2c-pi3usb30532";
+ data->connections[0].id = "typec-switch";
+ data->connections[1].endpoint[0] = "i2c-fusb302";
+ data->connections[1].endpoint[1] = "i2c-pi3usb30532";
+ data->connections[1].id = "typec-mux";
+ data->connections[2].endpoint[0] = "i2c-fusb302";
+ data->connections[2].endpoint[1] = "intel_xhci_usb_sw-role-switch";
+ data->connections[2].id = "usb-role-switch";
+
+ device_connection_add(&data->connections[0]);
+ device_connection_add(&data->connections[1]);
+ device_connection_add(&data->connections[2]);
+
memset(&board_info, 0, sizeof(board_info));
strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE);
board_info.dev_name = "fusb302";
@@ -201,6 +217,10 @@ out_unregister_max17047:
if (data->max17047)
i2c_unregister_device(data->max17047);
+ device_connection_remove(&data->connections[2]);
+ device_connection_remove(&data->connections[1]);
+ device_connection_remove(&data->connections[0]);
+
return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
}
@@ -213,6 +233,10 @@ static int cht_int33fe_remove(struct i2c_client *i2c)
if (data->max17047)
i2c_unregister_device(data->max17047);
+ device_connection_remove(&data->connections[2]);
+ device_connection_remove(&data->connections[1]);
+ device_connection_remove(&data->connections[0]);
+
return 0;
}
diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c
index 83797d89c30f..4db824f88d00 100644
--- a/drivers/pps/clients/pps_parport.c
+++ b/drivers/pps/clients/pps_parport.c
@@ -49,6 +49,7 @@ MODULE_PARM_DESC(clear_wait,
" zero turns clear edge capture off entirely");
module_param(clear_wait, uint, 0);
+static DEFINE_IDA(pps_client_index);
/* internal per port structure */
struct pps_client_pp {
@@ -56,6 +57,7 @@ struct pps_client_pp {
struct pps_device *pps; /* PPS device */
unsigned int cw; /* port clear timeout */
unsigned int cw_err; /* number of timeouts */
+ int index; /* device number */
};
static inline int signal_is_set(struct parport *port)
@@ -136,6 +138,8 @@ out_both:
static void parport_attach(struct parport *port)
{
+ struct pardev_cb pps_client_cb;
+ int index;
struct pps_client_pp *device;
struct pps_source_info info = {
.name = KBUILD_MODNAME,
@@ -154,8 +158,15 @@ static void parport_attach(struct parport *port)
return;
}
- device->pardev = parport_register_device(port, KBUILD_MODNAME,
- NULL, NULL, parport_irq, PARPORT_FLAG_EXCL, device);
+ index = ida_simple_get(&pps_client_index, 0, 0, GFP_KERNEL);
+ memset(&pps_client_cb, 0, sizeof(pps_client_cb));
+ pps_client_cb.private = device;
+ pps_client_cb.irq_func = parport_irq;
+ pps_client_cb.flags = PARPORT_FLAG_EXCL;
+ device->pardev = parport_register_dev_model(port,
+ KBUILD_MODNAME,
+ &pps_client_cb,
+ index);
if (!device->pardev) {
pr_err("couldn't register with %s\n", port->name);
goto err_free;
@@ -176,6 +187,7 @@ static void parport_attach(struct parport *port)
device->cw = clear_wait;
port->ops->enable_irq(port);
+ device->index = index;
pr_info("attached to %s\n", port->name);
@@ -186,6 +198,7 @@ err_release_dev:
err_unregister_dev:
parport_unregister_device(device->pardev);
err_free:
+ ida_simple_remove(&pps_client_index, index);
kfree(device);
}
@@ -205,13 +218,15 @@ static void parport_detach(struct parport *port)
pps_unregister_source(device->pps);
parport_release(pardev);
parport_unregister_device(pardev);
+ ida_simple_remove(&pps_client_index, device->index);
kfree(device);
}
static struct parport_driver pps_parport_driver = {
.name = KBUILD_MODNAME,
- .attach = parport_attach,
+ .match_port = parport_attach,
.detach = parport_detach,
+ .devmodel = true,
};
/* module staff */
diff --git a/drivers/pps/generators/pps_gen_parport.c b/drivers/pps/generators/pps_gen_parport.c
index 51cfde6afffd..7fd36cac063b 100644
--- a/drivers/pps/generators/pps_gen_parport.c
+++ b/drivers/pps/generators/pps_gen_parport.c
@@ -192,13 +192,18 @@ static inline ktime_t next_intr_time(struct pps_generator_pp *dev)
static void parport_attach(struct parport *port)
{
+ struct pardev_cb pps_cb;
+
if (attached) {
/* we already have a port */
return;
}
- device.pardev = parport_register_device(port, KBUILD_MODNAME,
- NULL, NULL, NULL, PARPORT_FLAG_EXCL, &device);
+ memset(&pps_cb, 0, sizeof(pps_cb));
+ pps_cb.private = &device;
+ pps_cb.flags = PARPORT_FLAG_EXCL;
+ device.pardev = parport_register_dev_model(port, KBUILD_MODNAME,
+ &pps_cb, 0);
if (!device.pardev) {
pr_err("couldn't register with %s\n", port->name);
return;
@@ -236,8 +241,9 @@ static void parport_detach(struct parport *port)
static struct parport_driver pps_gen_parport_driver = {
.name = KBUILD_MODNAME,
- .attach = parport_attach,
+ .match_port = parport_attach,
.detach = parport_detach,
+ .devmodel = true,
};
/* module staff */
diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile
index 2fdab400c1fe..a863b0462b43 100644
--- a/drivers/s390/Makefile
+++ b/drivers/s390/Makefile
@@ -5,5 +5,5 @@
obj-y += cio/ block/ char/ crypto/ net/ scsi/ virtio/
-drivers-y += drivers/s390/built-in.o
+drivers-y += drivers/s390/built-in.a
diff --git a/drivers/siox/siox-core.c b/drivers/siox/siox-core.c
index fdfcdea25867..16590dfaafa4 100644
--- a/drivers/siox/siox-core.c
+++ b/drivers/siox/siox-core.c
@@ -594,7 +594,7 @@ static ssize_t device_add_store(struct device *dev,
size_t inbytes = 0, outbytes = 0;
u8 statustype = 0;
- ret = sscanf(buf, "%20s %zu %zu %hhu", type, &inbytes,
+ ret = sscanf(buf, "%19s %zu %zu %hhu", type, &inbytes,
&outbytes, &statustype);
if (ret != 3 && ret != 4)
return -EINVAL;
diff --git a/drivers/slimbus/core.c b/drivers/slimbus/core.c
index 4988a8f4d905..7ddfc675b131 100644
--- a/drivers/slimbus/core.c
+++ b/drivers/slimbus/core.c
@@ -141,7 +141,7 @@ static struct slim_device *slim_alloc_device(struct slim_controller *ctrl,
sbdev->e_addr = *eaddr;
ret = slim_add_device(ctrl, sbdev, node);
if (ret) {
- kfree(sbdev);
+ put_device(&sbdev->dev);
return NULL;
}
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index e95ab683331e..d5926f0d3f6c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -24,8 +24,6 @@ menuconfig STAGING
if STAGING
-source "drivers/staging/irda/net/Kconfig"
-
source "drivers/staging/ipx/Kconfig"
source "drivers/staging/ncpfs/Kconfig"
@@ -114,12 +112,24 @@ source "drivers/staging/greybus/Kconfig"
source "drivers/staging/vc04_services/Kconfig"
-source "drivers/staging/ccree/Kconfig"
-
source "drivers/staging/typec/Kconfig"
source "drivers/staging/vboxvideo/Kconfig"
source "drivers/staging/pi433/Kconfig"
+source "drivers/staging/mt7621-pinctrl/Kconfig"
+
+source "drivers/staging/mt7621-gpio/Kconfig"
+
+source "drivers/staging/mt7621-spi/Kconfig"
+
+source "drivers/staging/mt7621-dma/Kconfig"
+
+source "drivers/staging/mt7621-mmc/Kconfig"
+
+source "drivers/staging/mt7621-eth/Kconfig"
+
+source "drivers/staging/mt7621-dts/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index af8cd6a3a1f6..919753c3d3f6 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -5,8 +5,6 @@ obj-y += media/
obj-y += typec/
obj-$(CONFIG_IPX) += ipx/
obj-$(CONFIG_NCP_FS) += ncpfs/
-obj-$(CONFIG_IRDA) += irda/net/
-obj-$(CONFIG_IRDA) += irda/drivers/
obj-$(CONFIG_PRISM2_USB) += wlan-ng/
obj-$(CONFIG_COMEDI) += comedi/
obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/
@@ -49,6 +47,13 @@ obj-$(CONFIG_MOST) += most/
obj-$(CONFIG_KS7010) += ks7010/
obj-$(CONFIG_GREYBUS) += greybus/
obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/
-obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/
obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo/
obj-$(CONFIG_PI433) += pi433/
+obj-$(CONFIG_SOC_MT7621) += mt7621-pci/
+obj-$(CONFIG_SOC_MT7621) += mt7621-pinctrl/
+obj-$(CONFIG_SOC_MT7621) += mt7621-gpio/
+obj-$(CONFIG_SOC_MT7621) += mt7621-spi/
+obj-$(CONFIG_SOC_MT7621) += mt7621-dma/
+obj-$(CONFIG_SOC_MT7621) += mt7621-mmc/
+obj-$(CONFIG_SOC_MT7621) += mt7621-eth/
+obj-$(CONFIG_SOC_MT7621) += mt7621-dts/
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 86580b6df33d..a1a0025b59e0 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -321,7 +321,7 @@ out_unlock:
static loff_t ashmem_llseek(struct file *file, loff_t offset, int origin)
{
struct ashmem_area *asma = file->private_data;
- int ret;
+ loff_t ret;
mutex_lock(&ashmem_mutex);
diff --git a/drivers/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig
index 8f6494158d3d..898e9a834ccc 100644
--- a/drivers/staging/android/ion/Kconfig
+++ b/drivers/staging/android/ion/Kconfig
@@ -4,7 +4,7 @@ menuconfig ION
select GENERIC_ALLOCATOR
select DMA_SHARED_BUFFER
---help---
- Chose this option to enable the ION Memory Manager,
+ Choose this option to enable the ION Memory Manager,
used by Android to efficiently allocate buffers
from userspace that can be shared between drivers.
If you're not using Android its probably safe to
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 57e0d8035b2e..e74db7902549 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -33,11 +33,6 @@
static struct ion_device *internal_dev;
static int heap_id;
-bool ion_buffer_cached(struct ion_buffer *buffer)
-{
- return !!(buffer->flags & ION_FLAG_CACHED);
-}
-
/* this function should only be called while dev->lock is held */
static void ion_buffer_add(struct ion_device *dev,
struct ion_buffer *buffer)
@@ -187,7 +182,7 @@ static struct sg_table *dup_sg_table(struct sg_table *table)
new_sg = new_table->sgl;
for_each_sg(table->sgl, sg, table->nents, i) {
memcpy(new_sg, sg, sizeof(*sg));
- sg->dma_address = 0;
+ new_sg->dma_address = 0;
new_sg = sg_next(new_sg);
}
@@ -527,7 +522,6 @@ DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get,
void ion_device_add_heap(struct ion_heap *heap)
{
- struct dentry *debug_file;
struct ion_device *dev = internal_dev;
int ret;
@@ -561,16 +555,8 @@ void ion_device_add_heap(struct ion_heap *heap)
char debug_name[64];
snprintf(debug_name, 64, "%s_shrink", heap->name);
- debug_file = debugfs_create_file(debug_name,
- 0644, dev->debug_root, heap,
- &debug_shrink_fops);
- if (!debug_file) {
- char buf[256], *path;
-
- path = dentry_path(dev->debug_root, buf, 256);
- pr_err("Failed to create heap shrinker debugfs at %s/%s\n",
- path, debug_name);
- }
+ debugfs_create_file(debug_name, 0644, dev->debug_root,
+ heap, &debug_shrink_fops);
}
dev->heap_cnt++;
@@ -599,12 +585,6 @@ static int ion_device_create(void)
}
idev->debug_root = debugfs_create_dir("ion", NULL);
- if (!idev->debug_root) {
- pr_err("ion: failed to create debugfs root directory.\n");
- goto debugfs_done;
- }
-
-debugfs_done:
idev->buffers = RB_ROOT;
mutex_init(&idev->buffer_lock);
init_rwsem(&idev->lock);
diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h
index a238f23c9116..ea0897812780 100644
--- a/drivers/staging/android/ion/ion.h
+++ b/drivers/staging/android/ion/ion.h
@@ -185,23 +185,6 @@ struct ion_heap {
};
/**
- * ion_buffer_cached - this ion buffer is cached
- * @buffer: buffer
- *
- * indicates whether this ion buffer is cached
- */
-bool ion_buffer_cached(struct ion_buffer *buffer);
-
-/**
- * ion_buffer_fault_user_mappings - fault in user mappings of this buffer
- * @buffer: buffer
- *
- * indicates whether userspace mappings of this buffer will be faulted
- * in, this can affect how buffers are allocated from the heap.
- */
-bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer);
-
-/**
* ion_device_add_heap - adds a heap to the ion device
* @heap: the heap to add
*/
@@ -311,7 +294,6 @@ size_t ion_heap_freelist_size(struct ion_heap *heap);
* @gfp_mask: gfp_mask to use from alloc
* @order: order of pages in the pool
* @list: plist node for list of pools
- * @cached: it's cached pool or not
*
* Allows you to keep a pool of pre allocated pages to use from your heap.
* Keeping a pool of pages that is ready for dma, ie any cached mapping have
@@ -321,7 +303,6 @@ size_t ion_heap_freelist_size(struct ion_heap *heap);
struct ion_page_pool {
int high_count;
int low_count;
- bool cached;
struct list_head high_items;
struct list_head low_items;
struct mutex mutex;
@@ -330,8 +311,7 @@ struct ion_page_pool {
struct plist_node list;
};
-struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
- bool cached);
+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order);
void ion_page_pool_destroy(struct ion_page_pool *pool);
struct page *ion_page_pool_alloc(struct ion_page_pool *pool);
void ion_page_pool_free(struct ion_page_pool *pool, struct page *page);
diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c
index b3017f12835f..db8f61446917 100644
--- a/drivers/staging/android/ion/ion_page_pool.c
+++ b/drivers/staging/android/ion/ion_page_pool.c
@@ -5,24 +5,15 @@
* Copyright (C) 2011 Google, Inc.
*/
-#include <linux/debugfs.h>
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/fs.h>
#include <linux/list.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/swap.h>
#include "ion.h"
-static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
+static inline struct page *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
{
- struct page *page = alloc_pages(pool->gfp_mask, pool->order);
-
- if (!page)
- return NULL;
- return page;
+ return alloc_pages(pool->gfp_mask, pool->order);
}
static void ion_page_pool_free_pages(struct ion_page_pool *pool,
@@ -31,7 +22,7 @@ static void ion_page_pool_free_pages(struct ion_page_pool *pool,
__free_pages(page, pool->order);
}
-static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
+static void ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
{
mutex_lock(&pool->mutex);
if (PageHighMem(page)) {
@@ -42,7 +33,6 @@ static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
pool->low_count++;
}
mutex_unlock(&pool->mutex);
- return 0;
}
static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high)
@@ -84,13 +74,9 @@ struct page *ion_page_pool_alloc(struct ion_page_pool *pool)
void ion_page_pool_free(struct ion_page_pool *pool, struct page *page)
{
- int ret;
-
BUG_ON(pool->order != compound_order(page));
- ret = ion_page_pool_add(pool, page);
- if (ret)
- ion_page_pool_free_pages(pool, page);
+ ion_page_pool_add(pool, page);
}
static int ion_page_pool_total(struct ion_page_pool *pool, bool high)
@@ -137,8 +123,7 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
return freed;
}
-struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
- bool cached)
+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
{
struct ion_page_pool *pool = kmalloc(sizeof(*pool), GFP_KERNEL);
@@ -152,8 +137,6 @@ struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
pool->order = order;
mutex_init(&pool->mutex);
plist_node_init(&pool->list, order);
- if (cached)
- pool->cached = true;
return pool;
}
@@ -162,9 +145,3 @@ void ion_page_pool_destroy(struct ion_page_pool *pool)
{
kfree(pool);
}
-
-static int __init ion_page_pool_init(void)
-{
- return 0;
-}
-device_initcall(ion_page_pool_init);
diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c
index bc19cdd30637..701eb9f3b0f1 100644
--- a/drivers/staging/android/ion/ion_system_heap.c
+++ b/drivers/staging/android/ion/ion_system_heap.c
@@ -41,31 +41,16 @@ static inline unsigned int order_to_size(int order)
struct ion_system_heap {
struct ion_heap heap;
- struct ion_page_pool *uncached_pools[NUM_ORDERS];
- struct ion_page_pool *cached_pools[NUM_ORDERS];
+ struct ion_page_pool *pools[NUM_ORDERS];
};
-/**
- * The page from page-pool are all zeroed before. We need do cache
- * clean for cached buffer. The uncached buffer are always non-cached
- * since it's allocated. So no need for non-cached pages.
- */
static struct page *alloc_buffer_page(struct ion_system_heap *heap,
struct ion_buffer *buffer,
unsigned long order)
{
- bool cached = ion_buffer_cached(buffer);
- struct ion_page_pool *pool;
- struct page *page;
+ struct ion_page_pool *pool = heap->pools[order_to_index(order)];
- if (!cached)
- pool = heap->uncached_pools[order_to_index(order)];
- else
- pool = heap->cached_pools[order_to_index(order)];
-
- page = ion_page_pool_alloc(pool);
-
- return page;
+ return ion_page_pool_alloc(pool);
}
static void free_buffer_page(struct ion_system_heap *heap,
@@ -73,7 +58,6 @@ static void free_buffer_page(struct ion_system_heap *heap,
{
struct ion_page_pool *pool;
unsigned int order = compound_order(page);
- bool cached = ion_buffer_cached(buffer);
/* go to system */
if (buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE) {
@@ -81,10 +65,7 @@ static void free_buffer_page(struct ion_system_heap *heap,
return;
}
- if (!cached)
- pool = heap->uncached_pools[order_to_index(order)];
- else
- pool = heap->cached_pools[order_to_index(order)];
+ pool = heap->pools[order_to_index(order)];
ion_page_pool_free(pool, page);
}
@@ -190,8 +171,7 @@ static void ion_system_heap_free(struct ion_buffer *buffer)
static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask,
int nr_to_scan)
{
- struct ion_page_pool *uncached_pool;
- struct ion_page_pool *cached_pool;
+ struct ion_page_pool *pool;
struct ion_system_heap *sys_heap;
int nr_total = 0;
int i, nr_freed;
@@ -203,26 +183,15 @@ static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask,
only_scan = 1;
for (i = 0; i < NUM_ORDERS; i++) {
- uncached_pool = sys_heap->uncached_pools[i];
- cached_pool = sys_heap->cached_pools[i];
+ pool = sys_heap->pools[i];
if (only_scan) {
- nr_total += ion_page_pool_shrink(uncached_pool,
+ nr_total += ion_page_pool_shrink(pool,
gfp_mask,
nr_to_scan);
- nr_total += ion_page_pool_shrink(cached_pool,
- gfp_mask,
- nr_to_scan);
} else {
- nr_freed = ion_page_pool_shrink(uncached_pool,
- gfp_mask,
- nr_to_scan);
- nr_to_scan -= nr_freed;
- nr_total += nr_freed;
- if (nr_to_scan <= 0)
- break;
- nr_freed = ion_page_pool_shrink(cached_pool,
+ nr_freed = ion_page_pool_shrink(pool,
gfp_mask,
nr_to_scan);
nr_to_scan -= nr_freed;
@@ -253,26 +222,16 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
struct ion_page_pool *pool;
for (i = 0; i < NUM_ORDERS; i++) {
- pool = sys_heap->uncached_pools[i];
+ pool = sys_heap->pools[i];
- seq_printf(s, "%d order %u highmem pages uncached %lu total\n",
+ seq_printf(s, "%d order %u highmem pages %lu total\n",
pool->high_count, pool->order,
(PAGE_SIZE << pool->order) * pool->high_count);
- seq_printf(s, "%d order %u lowmem pages uncached %lu total\n",
+ seq_printf(s, "%d order %u lowmem pages %lu total\n",
pool->low_count, pool->order,
(PAGE_SIZE << pool->order) * pool->low_count);
}
- for (i = 0; i < NUM_ORDERS; i++) {
- pool = sys_heap->cached_pools[i];
-
- seq_printf(s, "%d order %u highmem pages cached %lu total\n",
- pool->high_count, pool->order,
- (PAGE_SIZE << pool->order) * pool->high_count);
- seq_printf(s, "%d order %u lowmem pages cached %lu total\n",
- pool->low_count, pool->order,
- (PAGE_SIZE << pool->order) * pool->low_count);
- }
return 0;
}
@@ -285,8 +244,7 @@ static void ion_system_heap_destroy_pools(struct ion_page_pool **pools)
ion_page_pool_destroy(pools[i]);
}
-static int ion_system_heap_create_pools(struct ion_page_pool **pools,
- bool cached)
+static int ion_system_heap_create_pools(struct ion_page_pool **pools)
{
int i;
gfp_t gfp_flags = low_order_gfp_flags;
@@ -297,7 +255,7 @@ static int ion_system_heap_create_pools(struct ion_page_pool **pools,
if (orders[i] > 4)
gfp_flags = high_order_gfp_flags;
- pool = ion_page_pool_create(gfp_flags, orders[i], cached);
+ pool = ion_page_pool_create(gfp_flags, orders[i]);
if (!pool)
goto err_create_pool;
pools[i] = pool;
@@ -320,18 +278,12 @@ static struct ion_heap *__ion_system_heap_create(void)
heap->heap.type = ION_HEAP_TYPE_SYSTEM;
heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
- if (ion_system_heap_create_pools(heap->uncached_pools, false))
+ if (ion_system_heap_create_pools(heap->pools))
goto free_heap;
- if (ion_system_heap_create_pools(heap->cached_pools, true))
- goto destroy_uncached_pools;
-
heap->heap.debug_show = ion_system_heap_debug_show;
return &heap->heap;
-destroy_uncached_pools:
- ion_system_heap_destroy_pools(heap->uncached_pools);
-
free_heap:
kfree(heap);
return ERR_PTR(-ENOMEM);
diff --git a/drivers/staging/ccree/Kconfig b/drivers/staging/ccree/Kconfig
deleted file mode 100644
index c94dfe8adb63..000000000000
--- a/drivers/staging/ccree/Kconfig
+++ /dev/null
@@ -1,27 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-config CRYPTO_DEV_CCREE
- tristate "Support for ARM TrustZone CryptoCell C7XX family of Crypto accelerators"
- depends on CRYPTO && CRYPTO_HW && OF && HAS_DMA
- default n
- select CRYPTO_HASH
- select CRYPTO_BLKCIPHER
- select CRYPTO_DES
- select CRYPTO_AEAD
- select CRYPTO_AUTHENC
- select CRYPTO_SHA1
- select CRYPTO_MD5
- select CRYPTO_SHA256
- select CRYPTO_SHA512
- select CRYPTO_HMAC
- select CRYPTO_AES
- select CRYPTO_CBC
- select CRYPTO_ECB
- select CRYPTO_CTR
- select CRYPTO_XTS
- help
- Say 'Y' to enable a driver for the Arm TrustZone CryptoCell
- C7xx. Currently only the CryptoCell 712 REE is supported.
- Choose this if you wish to use hardware acceleration of
- cryptographic operations on the system REE.
- If unsure say Y.
diff --git a/drivers/staging/ccree/TODO b/drivers/staging/ccree/TODO
deleted file mode 100644
index b8e163d98f91..000000000000
--- a/drivers/staging/ccree/TODO
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-*************************************************************************
-* *
-* Arm Trust Zone CryptoCell REE Linux driver upstreaming TODO items *
-* *
-*************************************************************************
-
-1. ???
-
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index d39b4eabce8d..e21840e9002d 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -58,12 +58,11 @@ static int pci6208_ao_insn_write(struct comedi_device *dev,
unsigned int *data)
{
unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int val = s->readback[chan];
int ret;
int i;
for (i = 0; i < insn->n; i++) {
- val = data[i];
+ unsigned int val = data[i];
/* D/A transfer rate is 2.2us */
ret = comedi_timeout(dev, s, insn, pci6208_ao_eoc, 0);
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index b657beedd5ff..fdd81c3beb51 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -1488,11 +1488,10 @@ static int alloc_and_init_dma_members(struct comedi_device *dev)
for (i = 0; i < AO_DMA_RING_COUNT; i++) {
if (ao_cmd_is_supported(board)) {
devpriv->ao_buffer[i] =
- dma_alloc_coherent(&pcidev->dev,
- DMA_BUFFER_SIZE,
- &devpriv->
- ao_buffer_bus_addr[i],
- GFP_KERNEL);
+ dma_alloc_coherent(&pcidev->dev,
+ DMA_BUFFER_SIZE,
+ &devpriv->ao_buffer_bus_addr[i],
+ GFP_KERNEL);
if (!devpriv->ao_buffer[i])
return -ENOMEM;
}
@@ -1701,7 +1700,7 @@ static void i2c_write(struct comedi_device *dev, unsigned int address,
* eeprom and i2c bus
*/
- /* make sure we dont send anything to eeprom */
+ /* make sure we don't send anything to eeprom */
devpriv->plx_control_bits &= ~PLX_CNTRL_EECS;
i2c_stop(dev);
@@ -2463,20 +2462,21 @@ static int setup_channel_queue(struct comedi_device *dev,
writew(0, devpriv->main_iobase + ADC_QUEUE_CLEAR_REG);
/* load external queue */
for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chanspec = cmd->chanlist[i];
+ int use_differential;
+
bits = 0;
/* set channel */
- bits |= adc_chan_bits(CR_CHAN(cmd->
- chanlist[i]));
+ bits |= adc_chan_bits(CR_CHAN(chanspec));
/* set gain */
bits |= ai_range_bits_6xxx(dev,
- CR_RANGE(cmd->
- chanlist
- [i]));
+ CR_RANGE(chanspec));
/* set single-ended / differential */
- bits |= se_diff_bit_6xxx(dev,
- CR_AREF(cmd->
- chanlist[i]) ==
- AREF_DIFF);
+ use_differential = 0;
+ if (CR_AREF(chanspec) == AREF_DIFF)
+ use_differential = 1;
+ bits |= se_diff_bit_6xxx(dev, use_differential);
+
if (CR_AREF(cmd->chanlist[i]) == AREF_COMMON)
bits |= ADC_COMMON_BIT;
/* mark end of queue */
@@ -3248,17 +3248,15 @@ static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd)
return 0;
}
-static inline int external_ai_queue_in_use(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
+static inline int external_ai_queue_in_use(struct comedi_device *dev)
{
const struct pcidas64_board *board = dev->board_ptr;
- if (s->busy)
+ if (!dev->read_subdev->busy)
return 0;
if (board->layout == LAYOUT_4020)
return 0;
- else if (use_internal_queue_6xxx(cmd))
+ else if (use_internal_queue_6xxx(&dev->read_subdev->async->cmd))
return 0;
return 1;
}
@@ -3292,7 +3290,7 @@ static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
struct pcidas64_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
- if (external_ai_queue_in_use(dev, s, cmd)) {
+ if (external_ai_queue_in_use(dev)) {
warn_external_queue(dev);
return -EBUSY;
}
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index 74ff204b585d..81eb51b1be25 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -619,7 +619,7 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
/* Step 2b : and mutually compatible */
- /* make sure scan_begin_src and convert_src dont conflict */
+ /* make sure scan_begin_src and convert_src don't conflict */
if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
err |= -EINVAL;
if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW)
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index 72f8ed2c5008..4e36377b592a 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -407,7 +407,7 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status)
if (num_samples > cmd->stop_arg * cmd->chanlist_len)
num_samples = cmd->stop_arg * cmd->chanlist_len;
}
- /* make sure we dont try to get too many points if fifo has overrun */
+ /* make sure we don't try to get too many points if fifo has overrun */
if (num_samples > DAS16M1_AI_FIFO_SZ)
num_samples = DAS16M1_AI_FIFO_SZ;
insw(dev->iobase, devpriv->ai_buffer, num_samples);
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index 201f4f96c182..c3c88e6d298f 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -295,7 +295,6 @@ static int jr3_pci_open(struct comedi_device *dev)
struct comedi_subdevice *s;
int i;
- dev_dbg(dev->class_dev, "jr3_pci_open\n");
for (i = 0; i < dev->n_subdevices; i++) {
s = &dev->subdevices[i];
spriv = s->private;
diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c
index b9e9ab548c4b..2b7bfe0dd7f3 100644
--- a/drivers/staging/comedi/drivers/ni_atmio.c
+++ b/drivers/staging/comedi/drivers/ni_atmio.c
@@ -224,10 +224,11 @@ static int ni_isapnp_find_board(struct pnp_dev **dev)
int i;
for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
- isapnp_dev = pnp_find_dev(NULL,
- ISAPNP_VENDOR('N', 'I', 'C'),
- ISAPNP_FUNCTION(ni_boards[i].
- isapnp_id), NULL);
+ isapnp_dev =
+ pnp_find_dev(NULL,
+ ISAPNP_VENDOR('N', 'I', 'C'),
+ ISAPNP_FUNCTION(ni_boards[i].isapnp_id),
+ NULL);
if (!isapnp_dev || !isapnp_dev->card)
continue;
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index 5d610af6799f..e40a2c0a9543 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -1275,6 +1275,8 @@ static void ack_a_interrupt(struct comedi_device *dev, unsigned short a_status)
ack |= NISTC_INTA_ACK_AI_START;
if (a_status & NISTC_AI_STATUS1_STOP)
ack |= NISTC_INTA_ACK_AI_STOP;
+ if (a_status & NISTC_AI_STATUS1_OVER)
+ ack |= NISTC_INTA_ACK_AI_ERR;
if (ack)
ni_stc_writew(dev, ack, NISTC_INTA_ACK_REG);
}
@@ -1965,7 +1967,8 @@ static void ni_cmd_set_mite_transfer(struct mite_ring *ring,
if (nbytes > sdev->async->prealloc_bufsz) {
if (cmd->stop_arg > 0)
dev_err(sdev->device->class_dev,
- "ni_cmd_set_mite_transfer: tried exact data transfer limits greater than buffer size\n");
+ "%s: tried exact data transfer limits greater than buffer size\n",
+ __func__);
/*
* we can only transfer up to the size of the buffer. In this
@@ -1978,7 +1981,8 @@ static void ni_cmd_set_mite_transfer(struct mite_ring *ring,
mite_init_ring_descriptors(ring, sdev, nbytes);
#else
dev_err(sdev->device->class_dev,
- "ni_cmd_set_mite_transfer: exact data transfer limits not implemented yet without DMA\n");
+ "%s: exact data transfer limits not implemented yet without DMA\n",
+ __func__);
#endif
}
@@ -4687,7 +4691,7 @@ static int cs5529_do_conversion(struct comedi_device *dev,
retval = cs5529_wait_for_idle(dev);
if (retval) {
dev_err(dev->class_dev,
- "timeout or signal in cs5529_do_conversion()\n");
+ "timeout or signal in %s()\n", __func__);
return -ETIME;
}
status = ni_ao_win_inw(dev, NI67XX_CAL_STATUS_REG);
diff --git a/drivers/staging/comedi/drivers/ni_stc.h b/drivers/staging/comedi/drivers/ni_stc.h
index cb9d4c3a1926..831088c5cabb 100644
--- a/drivers/staging/comedi/drivers/ni_stc.h
+++ b/drivers/staging/comedi/drivers/ni_stc.h
@@ -9,7 +9,7 @@
/*
* References:
* DAQ-STC Technical Reference Manual
-*/
+ */
#ifndef _COMEDI_NI_STC_H
#define _COMEDI_NI_STC_H
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index 802f51e46405..ea194aa01a64 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -248,7 +248,7 @@ static irqreturn_t daqp_interrupt(int irq, void *dev_id)
if (loop_limit <= 0) {
dev_warn(dev->class_dev,
- "loop_limit reached in daqp_interrupt()\n");
+ "loop_limit reached in %s()\n", __func__);
s->async->events |= COMEDI_CB_ERROR;
}
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index 0b3cfe934e14..f5af6f4069dc 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -1700,7 +1700,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (devpriv->ai_cmd_running) {
dev_err(dev->class_dev,
- "s626_ai_cmd: Another ai_cmd is running\n");
+ "%s: Another ai_cmd is running\n", __func__);
return -EBUSY;
}
/* disable interrupt */
@@ -2268,10 +2268,10 @@ static int s626_initialize(struct comedi_device *dev)
*/
{
struct comedi_subdevice *s = dev->read_subdev;
- uint8_t poll_list;
- uint16_t adc_data;
- uint16_t start_val;
- uint16_t index;
+ u8 poll_list;
+ u16 adc_data;
+ u16 start_val;
+ u16 index;
unsigned int data[16];
/* Create a simple polling list for analog input channel 0 */
diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c
index 7517001fb8f0..3e51476a7045 100644
--- a/drivers/staging/emxx_udc/emxx_udc.c
+++ b/drivers/staging/emxx_udc/emxx_udc.c
@@ -1672,9 +1672,6 @@ static int std_req_set_configuration(struct nbu2ss_udc *udc)
/*-------------------------------------------------------------------------*/
static inline void _nbu2ss_read_request_data(struct nbu2ss_udc *udc, u32 *pdata)
{
- if ((!udc) && (!pdata))
- return;
-
*pdata = _nbu2ss_readl(&udc->p_regs->SETUP_DATA0);
pdata++;
*pdata = _nbu2ss_readl(&udc->p_regs->SETUP_DATA1);
@@ -2686,7 +2683,7 @@ static int nbu2ss_ep_queue(
if (req->unaligned) {
if (!ep->virt_buf)
- ep->virt_buf = (u8 *)dma_alloc_coherent(
+ ep->virt_buf = dma_alloc_coherent(
NULL, PAGE_SIZE,
&ep->phys_buf, GFP_ATOMIC | GFP_DMA);
if (ep->epnum > 0) {
@@ -2941,11 +2938,6 @@ static int nbu2ss_gad_get_frame(struct usb_gadget *pgadget)
}
udc = container_of(pgadget, struct nbu2ss_udc, gadget);
- if (!udc) {
- dev_err(&pgadget->dev, "%s, udc == NULL\n", __func__);
- return -EINVAL;
- }
-
data = gpio_get_value(VBUS_VALUE);
if (data == 0)
return -EINVAL;
diff --git a/drivers/staging/fsl-dpaa2/Kconfig b/drivers/staging/fsl-dpaa2/Kconfig
index dfff675b3055..bbb7af551696 100644
--- a/drivers/staging/fsl-dpaa2/Kconfig
+++ b/drivers/staging/fsl-dpaa2/Kconfig
@@ -4,7 +4,7 @@
config FSL_DPAA2
bool "Freescale DPAA2 devices"
- depends on FSL_MC_BUS && ARCH_LAYERSCAPE
+ depends on FSL_MC_BUS
---help---
Build drivers for Freescale DataPath Acceleration
Architecture (DPAA2) family of SoCs.
@@ -16,3 +16,11 @@ config FSL_DPAA2_ETH
---help---
Ethernet driver for Freescale DPAA2 SoCs, using the
Freescale MC bus driver
+
+config FSL_DPAA2_ETHSW
+ tristate "Freescale DPAA2 Ethernet Switch"
+ depends on FSL_DPAA2
+ depends on NET_SWITCHDEV
+ ---help---
+ Driver for Freescale DPAA2 Ethernet Switch. Select
+ BRIDGE to have support for bridge tools.
diff --git a/drivers/staging/fsl-dpaa2/Makefile b/drivers/staging/fsl-dpaa2/Makefile
index 0836ba8977b1..6cfd76b29970 100644
--- a/drivers/staging/fsl-dpaa2/Makefile
+++ b/drivers/staging/fsl-dpaa2/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_FSL_DPAA2_ETH) += ethernet/
+obj-$(CONFIG_FSL_DPAA2_ETHSW) += ethsw/
diff --git a/drivers/staging/fsl-dpaa2/ethernet/README b/drivers/staging/fsl-dpaa2/ethernet/README
index 410952ecf657..e3b5c90197e4 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/README
+++ b/drivers/staging/fsl-dpaa2/ethernet/README
@@ -36,7 +36,7 @@ are treated as internal resources of other objects.
For a more detailed description of the DPAA2 architecture and its object
abstractions see:
- drivers/staging/fsl-mc/README.txt
+ Documentation/networking/dpaa2/overview.rst
Each Linux net device is built on top of a Datapath Network Interface (DPNI)
object and uses Buffer Pools (DPBPs), I/O Portals (DPIOs) and Concentrators
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
index 2817e67df3d5..553678d8b2eb 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
+++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c
@@ -39,7 +39,7 @@
#include <linux/kthread.h>
#include <linux/iommu.h>
-#include "../../fsl-mc/include/mc.h"
+#include <linux/fsl/mc.h>
#include "dpaa2-eth.h"
/* CREATE_TRACE_POINTS only needs to be defined once. Other dpa files
@@ -324,7 +324,7 @@ static int consume_frames(struct dpaa2_eth_channel *ch)
}
fd = dpaa2_dq_fd(dq);
- fq = (struct dpaa2_eth_fq *)dpaa2_dq_fqd_ctx(dq);
+ fq = (struct dpaa2_eth_fq *)(uintptr_t)dpaa2_dq_fqd_ctx(dq);
fq->stats.frames++;
fq->consume(priv, ch, fd, &ch->napi, fq->flowid);
@@ -373,13 +373,15 @@ static int build_sg_fd(struct dpaa2_eth_priv *priv,
/* Prepare the HW SGT structure */
sgt_buf_size = priv->tx_data_offset +
- sizeof(struct dpaa2_sg_entry) * (1 + num_dma_bufs);
- sgt_buf = kzalloc(sgt_buf_size + DPAA2_ETH_TX_BUF_ALIGN, GFP_ATOMIC);
+ sizeof(struct dpaa2_sg_entry) * num_dma_bufs;
+ sgt_buf = netdev_alloc_frag(sgt_buf_size + DPAA2_ETH_TX_BUF_ALIGN);
if (unlikely(!sgt_buf)) {
err = -ENOMEM;
goto sgt_buf_alloc_failed;
}
sgt_buf = PTR_ALIGN(sgt_buf, DPAA2_ETH_TX_BUF_ALIGN);
+ memset(sgt_buf, 0, sgt_buf_size);
+
sgt = (struct dpaa2_sg_entry *)(sgt_buf + priv->tx_data_offset);
/* Fill in the HW SGT structure.
@@ -404,7 +406,7 @@ static int build_sg_fd(struct dpaa2_eth_priv *priv,
swa->skb = skb;
swa->scl = scl;
swa->num_sg = num_sg;
- swa->num_dma_bufs = num_dma_bufs;
+ swa->sgt_size = sgt_buf_size;
/* Separately map the SGT buffer */
addr = dma_map_single(dev, sgt_buf, sgt_buf_size, DMA_BIDIRECTIONAL);
@@ -421,7 +423,7 @@ static int build_sg_fd(struct dpaa2_eth_priv *priv,
return 0;
dma_map_single_failed:
- kfree(sgt_buf);
+ skb_free_frag(sgt_buf);
sgt_buf_alloc_failed:
dma_unmap_sg(dev, scl, num_sg, DMA_BIDIRECTIONAL);
dma_map_sg_failed:
@@ -487,9 +489,6 @@ static void free_tx_fd(const struct dpaa2_eth_priv *priv,
dma_addr_t fd_addr;
struct sk_buff **skbh, *skb;
unsigned char *buffer_start;
- int unmap_size;
- struct scatterlist *scl;
- int num_sg, num_dma_bufs;
struct dpaa2_eth_swa *swa;
u8 fd_format = dpaa2_fd_get_format(fd);
@@ -508,26 +507,22 @@ static void free_tx_fd(const struct dpaa2_eth_priv *priv,
} else if (fd_format == dpaa2_fd_sg) {
swa = (struct dpaa2_eth_swa *)skbh;
skb = swa->skb;
- scl = swa->scl;
- num_sg = swa->num_sg;
- num_dma_bufs = swa->num_dma_bufs;
/* Unmap the scatterlist */
- dma_unmap_sg(dev, scl, num_sg, DMA_BIDIRECTIONAL);
- kfree(scl);
+ dma_unmap_sg(dev, swa->scl, swa->num_sg, DMA_BIDIRECTIONAL);
+ kfree(swa->scl);
/* Unmap the SGT buffer */
- unmap_size = priv->tx_data_offset +
- sizeof(struct dpaa2_sg_entry) * (1 + num_dma_bufs);
- dma_unmap_single(dev, fd_addr, unmap_size, DMA_BIDIRECTIONAL);
+ dma_unmap_single(dev, fd_addr, swa->sgt_size,
+ DMA_BIDIRECTIONAL);
} else {
netdev_dbg(priv->net_dev, "Invalid FD format\n");
return;
}
- /* Free SGT buffer kmalloc'ed on tx */
+ /* Free SGT buffer allocated on tx */
if (fd_format != dpaa2_fd_single)
- kfree(skbh);
+ skb_free_frag(skbh);
/* Move on with skb release */
dev_kfree_skb(skb);
@@ -1844,6 +1839,21 @@ static int setup_dpni(struct fsl_mc_device *ls_dev)
return err;
}
+ /* Check if we can work with this DPNI object */
+ err = dpni_get_api_version(priv->mc_io, 0, &priv->dpni_ver_major,
+ &priv->dpni_ver_minor);
+ if (err) {
+ dev_err(dev, "dpni_get_api_version() failed\n");
+ goto close;
+ }
+ if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_VER_MAJOR, DPNI_VER_MINOR) < 0) {
+ dev_err(dev, "DPNI version %u.%u not supported, need >= %u.%u\n",
+ priv->dpni_ver_major, priv->dpni_ver_minor,
+ DPNI_VER_MAJOR, DPNI_VER_MINOR);
+ err = -ENOTSUPP;
+ goto close;
+ }
+
ls_dev->mc_io = priv->mc_io;
ls_dev->mc_handle = priv->mc_token;
@@ -1864,7 +1874,6 @@ static int setup_dpni(struct fsl_mc_device *ls_dev)
if (err)
goto close;
-
return 0;
close:
@@ -1906,7 +1915,7 @@ static int setup_rx_flow(struct dpaa2_eth_priv *priv,
queue.destination.id = fq->channel->dpcon_id;
queue.destination.type = DPNI_DEST_DPCON;
queue.destination.priority = 1;
- queue.user_context = (u64)fq;
+ queue.user_context = (u64)(uintptr_t)fq;
err = dpni_set_queue(priv->mc_io, 0, priv->mc_token,
DPNI_QUEUE_RX, 0, fq->flowid,
DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST,
@@ -1958,7 +1967,7 @@ static int setup_tx_flow(struct dpaa2_eth_priv *priv,
queue.destination.id = fq->channel->dpcon_id;
queue.destination.type = DPNI_DEST_DPCON;
queue.destination.priority = 0;
- queue.user_context = (u64)fq;
+ queue.user_context = (u64)(uintptr_t)fq;
err = dpni_set_queue(priv->mc_io, 0, priv->mc_token,
DPNI_QUEUE_TX_CONFIRM, 0, fq->flowid,
DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST,
@@ -2316,11 +2325,6 @@ static int poll_link_state(void *arg)
return 0;
}
-static irqreturn_t dpni_irq0_handler(int irq_num, void *arg)
-{
- return IRQ_WAKE_THREAD;
-}
-
static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg)
{
u32 status = ~0;
@@ -2355,8 +2359,7 @@ static int setup_irqs(struct fsl_mc_device *ls_dev)
irq = ls_dev->irqs[0];
err = devm_request_threaded_irq(&ls_dev->dev, irq->msi_desc->irq,
- dpni_irq0_handler,
- dpni_irq0_handler_thread,
+ NULL, dpni_irq0_handler_thread,
IRQF_NO_SUSPEND | IRQF_ONESHOT,
dev_name(&ls_dev->dev), &ls_dev->dev);
if (err < 0) {
@@ -2440,7 +2443,10 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
err = fsl_mc_portal_allocate(dpni_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
&priv->mc_io);
if (err) {
- dev_err(dev, "MC portal allocation failed\n");
+ if (err == -ENXIO)
+ err = -EPROBE_DEFER;
+ else
+ dev_err(dev, "MC portal allocation failed\n");
goto err_portal_alloc;
}
@@ -2552,7 +2558,6 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev)
priv = netdev_priv(net_dev);
unregister_netdev(net_dev);
- dev_info(net_dev->dev.parent, "Removed interface %s\n", net_dev->name);
if (priv->do_link_poll)
kthread_stop(priv->poll_thread);
@@ -2573,6 +2578,8 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev)
dev_set_drvdata(dev, NULL);
free_netdev(net_dev);
+ dev_dbg(net_dev->dev.parent, "Removed interface %s\n", net_dev->name);
+
return 0;
}
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h
index e577410fdf4f..54cea2fc6e58 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h
+++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h
@@ -35,11 +35,10 @@
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
+#include <linux/fsl/mc.h>
#include "../../fsl-mc/include/dpaa2-io.h"
#include "../../fsl-mc/include/dpaa2-fd.h"
-#include "../../fsl-mc/include/dpbp.h"
-#include "../../fsl-mc/include/dpcon.h"
#include "dpni.h"
#include "dpni-cmd.h"
@@ -109,7 +108,7 @@ struct dpaa2_eth_swa {
struct sk_buff *skb;
struct scatterlist *scl;
int num_sg;
- int num_dma_bufs;
+ int sgt_size;
};
/* Annotation valid bits in FD FRC */
@@ -143,7 +142,7 @@ struct dpaa2_fas {
u8 ppid;
__le16 ifpid;
__le32 status;
-} __packed;
+};
/* Frame annotation status word is located in the first 8 bytes
* of the buffer's hardware annoatation area
@@ -252,11 +251,11 @@ struct dpaa2_eth_ch_stats {
/* Maximum number of queues associated with a DPNI */
#define DPAA2_ETH_MAX_RX_QUEUES 16
-#define DPAA2_ETH_MAX_TX_QUEUES NR_CPUS
+#define DPAA2_ETH_MAX_TX_QUEUES 16
#define DPAA2_ETH_MAX_QUEUES (DPAA2_ETH_MAX_RX_QUEUES + \
DPAA2_ETH_MAX_TX_QUEUES)
-#define DPAA2_ETH_MAX_DPCONS NR_CPUS
+#define DPAA2_ETH_MAX_DPCONS 16
enum dpaa2_eth_fq_type {
DPAA2_RX_FQ = 0,
@@ -286,7 +285,6 @@ struct dpaa2_eth_channel {
struct fsl_mc_device *dpcon;
int dpcon_id;
int ch_id;
- int dpio_id;
struct napi_struct napi;
struct dpaa2_io *dpio;
struct dpaa2_io_store *store;
@@ -313,6 +311,8 @@ struct dpaa2_eth_priv {
struct dpaa2_eth_channel *channel[DPAA2_ETH_MAX_DPCONS];
struct dpni_attr dpni_attrs;
+ u16 dpni_ver_major;
+ u16 dpni_ver_minor;
u16 tx_data_offset;
struct fsl_mc_device *dpbp_dev;
@@ -356,6 +356,14 @@ struct dpaa2_eth_priv {
extern const struct ethtool_ops dpaa2_ethtool_ops;
extern const char dpaa2_eth_drv_version[];
+static inline int dpaa2_eth_cmp_dpni_ver(struct dpaa2_eth_priv *priv,
+ u16 ver_major, u16 ver_minor)
+{
+ if (priv->dpni_ver_major == ver_major)
+ return priv->dpni_ver_minor - ver_minor;
+ return priv->dpni_ver_major - ver_major;
+}
+
/* Hardware only sees DPAA2_ETH_RX_BUF_SIZE, but the skb built around
* the buffer also needs space for its shared info struct, and we need
* to allocate enough to accommodate hardware alignment restrictions
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c
index 070a3f2a0523..bfc8b64169ca 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c
+++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c
@@ -78,20 +78,13 @@ static void dpaa2_eth_get_drvinfo(struct net_device *net_dev,
struct ethtool_drvinfo *drvinfo)
{
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
- u16 fw_major, fw_minor;
- int err;
strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
strlcpy(drvinfo->version, dpaa2_eth_drv_version,
sizeof(drvinfo->version));
- err = dpni_get_api_version(priv->mc_io, 0, &fw_major, &fw_minor);
- if (!err)
- snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
- "%u.%u", fw_major, fw_minor);
- else
- strlcpy(drvinfo->fw_version, "N/A",
- sizeof(drvinfo->fw_version));
+ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+ "%u.%u", priv->dpni_ver_major, priv->dpni_ver_minor);
strlcpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent),
sizeof(drvinfo->bus_info));
@@ -126,6 +119,8 @@ out:
return err;
}
+#define DPNI_DYNAMIC_LINK_SET_VER_MAJOR 7
+#define DPNI_DYNAMIC_LINK_SET_VER_MINOR 1
static int
dpaa2_eth_set_link_ksettings(struct net_device *net_dev,
const struct ethtool_link_ksettings *link_settings)
@@ -134,15 +129,16 @@ dpaa2_eth_set_link_ksettings(struct net_device *net_dev,
struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
int err = 0;
- netdev_dbg(net_dev, "Setting link parameters...");
-
- /* Due to a temporary MC limitation, the DPNI must be down
+ /* If using an older MC version, the DPNI must be down
* in order to be able to change link settings. Taking steps to let
* the user know that.
*/
- if (netif_running(net_dev)) {
- netdev_info(net_dev, "Sorry, interface must be brought down first.\n");
- return -EACCES;
+ if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_DYNAMIC_LINK_SET_VER_MAJOR,
+ DPNI_DYNAMIC_LINK_SET_VER_MINOR) < 0) {
+ if (netif_running(net_dev)) {
+ netdev_info(net_dev, "Interface must be brought down first.\n");
+ return -EACCES;
+ }
}
cfg.rate = link_settings->base.speed;
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h b/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h
index 3120e22496d0..d6f96f302cc6 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h
+++ b/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h
@@ -539,8 +539,8 @@ struct dpni_rsp_get_taildrop {
};
struct dpni_rsp_get_api_version {
- u16 major;
- u16 minor;
+ __le16 major;
+ __le16 minor;
};
#endif /* _FSL_DPNI_CMD_H */
diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpni.c b/drivers/staging/fsl-dpaa2/ethernet/dpni.c
index e8be76181c36..1a721c95a67a 100644
--- a/drivers/staging/fsl-dpaa2/ethernet/dpni.c
+++ b/drivers/staging/fsl-dpaa2/ethernet/dpni.c
@@ -32,7 +32,7 @@
*/
#include <linux/kernel.h>
#include <linux/errno.h>
-#include "../../fsl-mc/include/mc.h"
+#include <linux/fsl/mc.h>
#include "dpni.h"
#include "dpni-cmd.h"
@@ -122,7 +122,7 @@ int dpni_open(struct fsl_mc_io *mc_io,
int dpni_id,
u16 *token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_open *cmd_params;
int err;
@@ -160,7 +160,7 @@ int dpni_close(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLOSE,
@@ -188,7 +188,7 @@ int dpni_set_pools(struct fsl_mc_io *mc_io,
u16 token,
const struct dpni_pools_cfg *cfg)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_set_pools *cmd_params;
int i;
@@ -222,7 +222,7 @@ int dpni_enable(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPNI_CMDID_ENABLE,
@@ -245,7 +245,7 @@ int dpni_disable(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPNI_CMDID_DISABLE,
@@ -270,7 +270,7 @@ int dpni_is_enabled(struct fsl_mc_io *mc_io,
u16 token,
int *en)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_rsp_is_enabled *rsp_params;
int err;
@@ -303,7 +303,7 @@ int dpni_reset(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPNI_CMDID_RESET,
@@ -335,7 +335,7 @@ int dpni_set_irq_enable(struct fsl_mc_io *mc_io,
u8 irq_index,
u8 en)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_set_irq_enable *cmd_params;
/* prepare command */
@@ -366,7 +366,7 @@ int dpni_get_irq_enable(struct fsl_mc_io *mc_io,
u8 irq_index,
u8 *en)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_get_irq_enable *cmd_params;
struct dpni_rsp_get_irq_enable *rsp_params;
@@ -413,7 +413,7 @@ int dpni_set_irq_mask(struct fsl_mc_io *mc_io,
u8 irq_index,
u32 mask)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_set_irq_mask *cmd_params;
/* prepare command */
@@ -447,7 +447,7 @@ int dpni_get_irq_mask(struct fsl_mc_io *mc_io,
u8 irq_index,
u32 *mask)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_get_irq_mask *cmd_params;
struct dpni_rsp_get_irq_mask *rsp_params;
int err;
@@ -489,7 +489,7 @@ int dpni_get_irq_status(struct fsl_mc_io *mc_io,
u8 irq_index,
u32 *status)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_get_irq_status *cmd_params;
struct dpni_rsp_get_irq_status *rsp_params;
int err;
@@ -532,7 +532,7 @@ int dpni_clear_irq_status(struct fsl_mc_io *mc_io,
u8 irq_index,
u32 status)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_clear_irq_status *cmd_params;
/* prepare command */
@@ -561,7 +561,7 @@ int dpni_get_attributes(struct fsl_mc_io *mc_io,
u16 token,
struct dpni_attr *attr)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_rsp_get_attr *rsp_params;
int err;
@@ -609,7 +609,7 @@ int dpni_set_errors_behavior(struct fsl_mc_io *mc_io,
u16 token,
struct dpni_error_cfg *cfg)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_set_errors_behavior *cmd_params;
/* prepare command */
@@ -641,7 +641,7 @@ int dpni_get_buffer_layout(struct fsl_mc_io *mc_io,
enum dpni_queue_type qtype,
struct dpni_buffer_layout *layout)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_get_buffer_layout *cmd_params;
struct dpni_rsp_get_buffer_layout *rsp_params;
int err;
@@ -689,7 +689,7 @@ int dpni_set_buffer_layout(struct fsl_mc_io *mc_io,
enum dpni_queue_type qtype,
const struct dpni_buffer_layout *layout)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_set_buffer_layout *cmd_params;
/* prepare command */
@@ -731,7 +731,7 @@ int dpni_set_offload(struct fsl_mc_io *mc_io,
enum dpni_offload type,
u32 config)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_set_offload *cmd_params;
cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_OFFLOAD,
@@ -750,7 +750,7 @@ int dpni_get_offload(struct fsl_mc_io *mc_io,
enum dpni_offload type,
u32 *config)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_get_offload *cmd_params;
struct dpni_rsp_get_offload *rsp_params;
int err;
@@ -792,7 +792,7 @@ int dpni_get_qdid(struct fsl_mc_io *mc_io,
enum dpni_queue_type qtype,
u16 *qdid)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_get_qdid *cmd_params;
struct dpni_rsp_get_qdid *rsp_params;
int err;
@@ -830,7 +830,7 @@ int dpni_get_tx_data_offset(struct fsl_mc_io *mc_io,
u16 token,
u16 *data_offset)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_rsp_get_tx_data_offset *rsp_params;
int err;
@@ -865,7 +865,7 @@ int dpni_set_link_cfg(struct fsl_mc_io *mc_io,
u16 token,
const struct dpni_link_cfg *cfg)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_set_link_cfg *cmd_params;
/* prepare command */
@@ -894,7 +894,7 @@ int dpni_get_link_state(struct fsl_mc_io *mc_io,
u16 token,
struct dpni_link_state *state)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_rsp_get_link_state *rsp_params;
int err;
@@ -933,7 +933,7 @@ int dpni_set_max_frame_length(struct fsl_mc_io *mc_io,
u16 token,
u16 max_frame_length)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_set_max_frame_length *cmd_params;
/* prepare command */
@@ -963,7 +963,7 @@ int dpni_get_max_frame_length(struct fsl_mc_io *mc_io,
u16 token,
u16 *max_frame_length)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_rsp_get_max_frame_length *rsp_params;
int err;
@@ -998,7 +998,7 @@ int dpni_set_multicast_promisc(struct fsl_mc_io *mc_io,
u16 token,
int en)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_set_multicast_promisc *cmd_params;
/* prepare command */
@@ -1026,7 +1026,7 @@ int dpni_get_multicast_promisc(struct fsl_mc_io *mc_io,
u16 token,
int *en)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_rsp_get_multicast_promisc *rsp_params;
int err;
@@ -1061,7 +1061,7 @@ int dpni_set_unicast_promisc(struct fsl_mc_io *mc_io,
u16 token,
int en)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_set_unicast_promisc *cmd_params;
/* prepare command */
@@ -1089,7 +1089,7 @@ int dpni_get_unicast_promisc(struct fsl_mc_io *mc_io,
u16 token,
int *en)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_rsp_get_unicast_promisc *rsp_params;
int err;
@@ -1124,7 +1124,7 @@ int dpni_set_primary_mac_addr(struct fsl_mc_io *mc_io,
u16 token,
const u8 mac_addr[6])
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_set_primary_mac_addr *cmd_params;
int i;
@@ -1154,7 +1154,7 @@ int dpni_get_primary_mac_addr(struct fsl_mc_io *mc_io,
u16 token,
u8 mac_addr[6])
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_rsp_get_primary_mac_addr *rsp_params;
int i, err;
@@ -1193,7 +1193,7 @@ int dpni_get_port_mac_addr(struct fsl_mc_io *mc_io,
u16 token,
u8 mac_addr[6])
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_rsp_get_port_mac_addr *rsp_params;
int i, err;
@@ -1229,7 +1229,7 @@ int dpni_add_mac_addr(struct fsl_mc_io *mc_io,
u16 token,
const u8 mac_addr[6])
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_add_mac_addr *cmd_params;
int i;
@@ -1259,7 +1259,7 @@ int dpni_remove_mac_addr(struct fsl_mc_io *mc_io,
u16 token,
const u8 mac_addr[6])
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_remove_mac_addr *cmd_params;
int i;
@@ -1293,7 +1293,7 @@ int dpni_clear_mac_filters(struct fsl_mc_io *mc_io,
int unicast,
int multicast)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_clear_mac_filters *cmd_params;
/* prepare command */
@@ -1327,7 +1327,7 @@ int dpni_set_rx_tc_dist(struct fsl_mc_io *mc_io,
u8 tc_id,
const struct dpni_rx_tc_dist_cfg *cfg)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_set_rx_tc_dist *cmd_params;
/* prepare command */
@@ -1371,7 +1371,7 @@ int dpni_set_queue(struct fsl_mc_io *mc_io,
u8 options,
const struct dpni_queue *queue)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_set_queue *cmd_params;
/* prepare command */
@@ -1419,7 +1419,7 @@ int dpni_get_queue(struct fsl_mc_io *mc_io,
struct dpni_queue *queue,
struct dpni_queue_id *qid)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_get_queue *cmd_params;
struct dpni_rsp_get_queue *rsp_params;
int err;
@@ -1473,7 +1473,7 @@ int dpni_get_statistics(struct fsl_mc_io *mc_io,
u8 page,
union dpni_statistics *stat)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_get_statistics *cmd_params;
struct dpni_rsp_get_statistics *rsp_params;
int i, err;
@@ -1522,7 +1522,7 @@ int dpni_set_taildrop(struct fsl_mc_io *mc_io,
u8 index,
struct dpni_taildrop *taildrop)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_set_taildrop *cmd_params;
/* prepare command */
@@ -1566,7 +1566,7 @@ int dpni_get_taildrop(struct fsl_mc_io *mc_io,
u8 index,
struct dpni_taildrop *taildrop)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpni_cmd_get_taildrop *cmd_params;
struct dpni_rsp_get_taildrop *rsp_params;
int err;
@@ -1610,7 +1610,7 @@ int dpni_get_api_version(struct fsl_mc_io *mc_io,
u16 *minor_ver)
{
struct dpni_rsp_get_api_version *rsp_params;
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
int err;
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_API_VERSION,
diff --git a/drivers/staging/fsl-dpaa2/ethsw/Makefile b/drivers/staging/fsl-dpaa2/ethsw/Makefile
new file mode 100644
index 000000000000..f6f2cf798faf
--- /dev/null
+++ b/drivers/staging/fsl-dpaa2/ethsw/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the Freescale DPAA2 Ethernet Switch
+#
+# Copyright 2014-2017 Freescale Semiconductor Inc.
+# Copyright 2017-2018 NXP
+
+obj-$(CONFIG_FSL_DPAA2_ETHSW) += dpaa2-ethsw.o
+
+dpaa2-ethsw-objs := ethsw.o ethsw-ethtool.o dpsw.o
diff --git a/drivers/staging/fsl-dpaa2/ethsw/README b/drivers/staging/fsl-dpaa2/ethsw/README
new file mode 100644
index 000000000000..f6fc07f780d1
--- /dev/null
+++ b/drivers/staging/fsl-dpaa2/ethsw/README
@@ -0,0 +1,106 @@
+DPAA2 Ethernet Switch driver
+============================
+
+This file provides documentation for the DPAA2 Ethernet Switch driver
+
+
+Contents
+========
+ Supported Platforms
+ Architecture Overview
+ Creating an Ethernet Switch
+ Features
+
+
+ Supported Platforms
+===================
+This driver provides networking support for Freescale LS2085A, LS2088A
+DPAA2 SoCs.
+
+
+Architecture Overview
+=====================
+The Ethernet Switch in the DPAA2 architecture consists of several hardware
+resources that provide the functionality. These are allocated and
+configured via the Management Complex (MC) portals. MC abstracts most of
+these resources as DPAA2 objects and exposes ABIs through which they can
+be configured and controlled.
+
+For a more detailed description of the DPAA2 architecture and its object
+abstractions see:
+ drivers/staging/fsl-mc/README.txt
+
+The Ethernet Switch is built on top of a Datapath Switch (DPSW) object.
+
+Configuration interface:
+
+ ---------------------
+ | DPAA2 Switch driver |
+ ---------------------
+ .
+ .
+ ----------
+ | DPSW API |
+ ----------
+ . software
+ ================= . ==============
+ . hardware
+ ---------------------
+ | MC hardware portals |
+ ---------------------
+ .
+ .
+ ------
+ | DPSW |
+ ------
+
+Driver uses the switch device driver model and exposes each switch port as
+a network interface, which can be included in a bridge. Traffic switched
+between ports is offloaded into the hardware. Exposed network interfaces
+are not used for I/O, they are used just for configuration. This
+limitation is going to be addressed in the future.
+
+The DPSW can have ports connected to DPNIs or to PHYs via DPMACs.
+
+
+ [ethA] [ethB] [ethC] [ethD] [ethE] [ethF]
+ : : : : : :
+ : : : : : :
+[eth drv] [eth drv] [ ethsw drv ]
+ : : : : : : kernel
+========================================================================
+ : : : : : : hardware
+ [DPNI] [DPNI] [============= DPSW =================]
+ | | | | | |
+ | ---------- | [DPMAC] [DPMAC]
+ ------------------------------- | |
+ | |
+ [PHY] [PHY]
+
+For a more detailed description of the Ethernet switch device driver model
+see:
+ Documentation/networking/switchdev.txt
+
+Creating an Ethernet Switch
+===========================
+A device is created for the switch objects probed on the MC bus. Each DPSW
+has a number of properties which determine the configuration options and
+associated hardware resources.
+
+A DPSW object (and the other DPAA2 objects needed for a DPAA2 switch) can
+be added to a container on the MC bus in one of two ways: statically,
+through a Datapath Layout Binary file (DPL) that is parsed by MC at boot
+time; or created dynamically at runtime, via the DPAA2 objects APIs.
+
+Features
+========
+Driver configures DPSW to perform hardware switching offload of
+unicast/multicast/broadcast (VLAN tagged or untagged) traffic between its
+ports.
+
+It allows configuration of hardware learning, flooding, multicast groups,
+port VLAN configuration and STP state.
+
+Static entries can be added/removed from the FDB.
+
+Hardware statistics for each port are provided through ethtool -S option.
diff --git a/drivers/staging/fsl-dpaa2/ethsw/TODO b/drivers/staging/fsl-dpaa2/ethsw/TODO
new file mode 100644
index 000000000000..24b5e95a96f8
--- /dev/null
+++ b/drivers/staging/fsl-dpaa2/ethsw/TODO
@@ -0,0 +1,14 @@
+* Add I/O capabilities on switch port netdevices. This will allow control
+traffic to reach the CPU.
+* Add ACL to redirect control traffic to CPU.
+* Add support for displaying learned FDB entries
+* Add support for multiple FDBs and switch port partitioning
+* MC firmware uprev; the DPAA2 objects used by the Ethernet Switch driver
+need to be kept in sync with binary interface changes in MC
+* refine README file
+* cleanup
+
+NOTE: At least first three of the above are required before getting the
+DPAA2 Ethernet Switch driver out of staging. Another requirement is that
+dpio driver is moved to drivers/soc (this is required for I/O).
+
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
new file mode 100644
index 000000000000..1c203e6e8035
--- /dev/null
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
@@ -0,0 +1,346 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2014-2016 Freescale Semiconductor Inc.
+ * Copyright 2017-2018 NXP
+ *
+ */
+
+#ifndef __FSL_DPSW_CMD_H
+#define __FSL_DPSW_CMD_H
+
+/* DPSW Version */
+#define DPSW_VER_MAJOR 8
+#define DPSW_VER_MINOR 0
+
+#define DPSW_CMD_BASE_VERSION 1
+#define DPSW_CMD_ID_OFFSET 4
+
+#define DPSW_CMD_ID(id) (((id) << DPSW_CMD_ID_OFFSET) | DPSW_CMD_BASE_VERSION)
+
+/* Command IDs */
+#define DPSW_CMDID_CLOSE DPSW_CMD_ID(0x800)
+#define DPSW_CMDID_OPEN DPSW_CMD_ID(0x802)
+
+#define DPSW_CMDID_GET_API_VERSION DPSW_CMD_ID(0xa02)
+
+#define DPSW_CMDID_ENABLE DPSW_CMD_ID(0x002)
+#define DPSW_CMDID_DISABLE DPSW_CMD_ID(0x003)
+#define DPSW_CMDID_GET_ATTR DPSW_CMD_ID(0x004)
+#define DPSW_CMDID_RESET DPSW_CMD_ID(0x005)
+
+#define DPSW_CMDID_SET_IRQ_ENABLE DPSW_CMD_ID(0x012)
+
+#define DPSW_CMDID_SET_IRQ_MASK DPSW_CMD_ID(0x014)
+
+#define DPSW_CMDID_GET_IRQ_STATUS DPSW_CMD_ID(0x016)
+#define DPSW_CMDID_CLEAR_IRQ_STATUS DPSW_CMD_ID(0x017)
+
+#define DPSW_CMDID_IF_SET_TCI DPSW_CMD_ID(0x030)
+#define DPSW_CMDID_IF_SET_STP DPSW_CMD_ID(0x031)
+
+#define DPSW_CMDID_IF_GET_COUNTER DPSW_CMD_ID(0x034)
+
+#define DPSW_CMDID_IF_ENABLE DPSW_CMD_ID(0x03D)
+#define DPSW_CMDID_IF_DISABLE DPSW_CMD_ID(0x03E)
+
+#define DPSW_CMDID_IF_SET_MAX_FRAME_LENGTH DPSW_CMD_ID(0x044)
+
+#define DPSW_CMDID_IF_GET_LINK_STATE DPSW_CMD_ID(0x046)
+#define DPSW_CMDID_IF_SET_FLOODING DPSW_CMD_ID(0x047)
+#define DPSW_CMDID_IF_SET_BROADCAST DPSW_CMD_ID(0x048)
+
+#define DPSW_CMDID_IF_SET_LINK_CFG DPSW_CMD_ID(0x04C)
+
+#define DPSW_CMDID_VLAN_ADD DPSW_CMD_ID(0x060)
+#define DPSW_CMDID_VLAN_ADD_IF DPSW_CMD_ID(0x061)
+#define DPSW_CMDID_VLAN_ADD_IF_UNTAGGED DPSW_CMD_ID(0x062)
+
+#define DPSW_CMDID_VLAN_REMOVE_IF DPSW_CMD_ID(0x064)
+#define DPSW_CMDID_VLAN_REMOVE_IF_UNTAGGED DPSW_CMD_ID(0x065)
+#define DPSW_CMDID_VLAN_REMOVE_IF_FLOODING DPSW_CMD_ID(0x066)
+#define DPSW_CMDID_VLAN_REMOVE DPSW_CMD_ID(0x067)
+
+#define DPSW_CMDID_FDB_ADD_UNICAST DPSW_CMD_ID(0x084)
+#define DPSW_CMDID_FDB_REMOVE_UNICAST DPSW_CMD_ID(0x085)
+#define DPSW_CMDID_FDB_ADD_MULTICAST DPSW_CMD_ID(0x086)
+#define DPSW_CMDID_FDB_REMOVE_MULTICAST DPSW_CMD_ID(0x087)
+#define DPSW_CMDID_FDB_SET_LEARNING_MODE DPSW_CMD_ID(0x088)
+
+/* Macros for accessing command fields smaller than 1byte */
+#define DPSW_MASK(field) \
+ GENMASK(DPSW_##field##_SHIFT + DPSW_##field##_SIZE - 1, \
+ DPSW_##field##_SHIFT)
+#define dpsw_set_field(var, field, val) \
+ ((var) |= (((val) << DPSW_##field##_SHIFT) & DPSW_MASK(field)))
+#define dpsw_get_field(var, field) \
+ (((var) & DPSW_MASK(field)) >> DPSW_##field##_SHIFT)
+#define dpsw_get_bit(var, bit) \
+ (((var) >> (bit)) & GENMASK(0, 0))
+
+struct dpsw_cmd_open {
+ __le32 dpsw_id;
+};
+
+#define DPSW_COMPONENT_TYPE_SHIFT 0
+#define DPSW_COMPONENT_TYPE_SIZE 4
+
+struct dpsw_cmd_create {
+ /* cmd word 0 */
+ __le16 num_ifs;
+ u8 max_fdbs;
+ u8 max_meters_per_if;
+ /* from LSB: only the first 4 bits */
+ u8 component_type;
+ u8 pad[3];
+ /* cmd word 1 */
+ __le16 max_vlans;
+ __le16 max_fdb_entries;
+ __le16 fdb_aging_time;
+ __le16 max_fdb_mc_groups;
+ /* cmd word 2 */
+ __le64 options;
+};
+
+struct dpsw_cmd_destroy {
+ __le32 dpsw_id;
+};
+
+#define DPSW_ENABLE_SHIFT 0
+#define DPSW_ENABLE_SIZE 1
+
+struct dpsw_rsp_is_enabled {
+ /* from LSB: enable:1 */
+ u8 enabled;
+};
+
+struct dpsw_cmd_set_irq_enable {
+ u8 enable_state;
+ u8 pad[3];
+ u8 irq_index;
+};
+
+struct dpsw_cmd_get_irq_enable {
+ __le32 pad;
+ u8 irq_index;
+};
+
+struct dpsw_rsp_get_irq_enable {
+ u8 enable_state;
+};
+
+struct dpsw_cmd_set_irq_mask {
+ __le32 mask;
+ u8 irq_index;
+};
+
+struct dpsw_cmd_get_irq_mask {
+ __le32 pad;
+ u8 irq_index;
+};
+
+struct dpsw_rsp_get_irq_mask {
+ __le32 mask;
+};
+
+struct dpsw_cmd_get_irq_status {
+ __le32 status;
+ u8 irq_index;
+};
+
+struct dpsw_rsp_get_irq_status {
+ __le32 status;
+};
+
+struct dpsw_cmd_clear_irq_status {
+ __le32 status;
+ u8 irq_index;
+};
+
+#define DPSW_COMPONENT_TYPE_SHIFT 0
+#define DPSW_COMPONENT_TYPE_SIZE 4
+
+struct dpsw_rsp_get_attr {
+ /* cmd word 0 */
+ __le16 num_ifs;
+ u8 max_fdbs;
+ u8 num_fdbs;
+ __le16 max_vlans;
+ __le16 num_vlans;
+ /* cmd word 1 */
+ __le16 max_fdb_entries;
+ __le16 fdb_aging_time;
+ __le32 dpsw_id;
+ /* cmd word 2 */
+ __le16 mem_size;
+ __le16 max_fdb_mc_groups;
+ u8 max_meters_per_if;
+ /* from LSB only the first 4 bits */
+ u8 component_type;
+ __le16 pad;
+ /* cmd word 3 */
+ __le64 options;
+};
+
+struct dpsw_cmd_if_set_flooding {
+ __le16 if_id;
+ /* from LSB: enable:1 */
+ u8 enable;
+};
+
+struct dpsw_cmd_if_set_broadcast {
+ __le16 if_id;
+ /* from LSB: enable:1 */
+ u8 enable;
+};
+
+#define DPSW_VLAN_ID_SHIFT 0
+#define DPSW_VLAN_ID_SIZE 12
+#define DPSW_DEI_SHIFT 12
+#define DPSW_DEI_SIZE 1
+#define DPSW_PCP_SHIFT 13
+#define DPSW_PCP_SIZE 3
+
+struct dpsw_cmd_if_set_tci {
+ __le16 if_id;
+ /* from LSB: VLAN_ID:12 DEI:1 PCP:3 */
+ __le16 conf;
+};
+
+#define DPSW_STATE_SHIFT 0
+#define DPSW_STATE_SIZE 4
+
+struct dpsw_cmd_if_set_stp {
+ __le16 if_id;
+ __le16 vlan_id;
+ /* only the first LSB 4 bits */
+ u8 state;
+};
+
+#define DPSW_COUNTER_TYPE_SHIFT 0
+#define DPSW_COUNTER_TYPE_SIZE 5
+
+struct dpsw_cmd_if_get_counter {
+ __le16 if_id;
+ /* from LSB: type:5 */
+ u8 type;
+};
+
+struct dpsw_rsp_if_get_counter {
+ __le64 pad;
+ __le64 counter;
+};
+
+struct dpsw_cmd_if {
+ __le16 if_id;
+};
+
+struct dpsw_cmd_if_set_max_frame_length {
+ __le16 if_id;
+ __le16 frame_length;
+};
+
+struct dpsw_cmd_if_set_link_cfg {
+ /* cmd word 0 */
+ __le16 if_id;
+ u8 pad[6];
+ /* cmd word 1 */
+ __le32 rate;
+ __le32 pad1;
+ /* cmd word 2 */
+ __le64 options;
+};
+
+struct dpsw_cmd_if_get_link_state {
+ __le16 if_id;
+};
+
+#define DPSW_UP_SHIFT 0
+#define DPSW_UP_SIZE 1
+
+struct dpsw_rsp_if_get_link_state {
+ /* cmd word 0 */
+ __le32 pad0;
+ u8 up;
+ u8 pad1[3];
+ /* cmd word 1 */
+ __le32 rate;
+ __le32 pad2;
+ /* cmd word 2 */
+ __le64 options;
+};
+
+struct dpsw_vlan_add {
+ __le16 fdb_id;
+ __le16 vlan_id;
+};
+
+struct dpsw_cmd_vlan_manage_if {
+ /* cmd word 0 */
+ __le16 pad0;
+ __le16 vlan_id;
+ __le32 pad1;
+ /* cmd word 1-4 */
+ __le64 if_id[4];
+};
+
+struct dpsw_cmd_vlan_remove {
+ __le16 pad;
+ __le16 vlan_id;
+};
+
+struct dpsw_cmd_fdb_add {
+ __le32 pad;
+ __le16 fdb_aging_time;
+ __le16 num_fdb_entries;
+};
+
+struct dpsw_rsp_fdb_add {
+ __le16 fdb_id;
+};
+
+struct dpsw_cmd_fdb_remove {
+ __le16 fdb_id;
+};
+
+#define DPSW_ENTRY_TYPE_SHIFT 0
+#define DPSW_ENTRY_TYPE_SIZE 4
+
+struct dpsw_cmd_fdb_unicast_op {
+ /* cmd word 0 */
+ __le16 fdb_id;
+ u8 mac_addr[6];
+ /* cmd word 1 */
+ __le16 if_egress;
+ /* only the first 4 bits from LSB */
+ u8 type;
+};
+
+struct dpsw_cmd_fdb_multicast_op {
+ /* cmd word 0 */
+ __le16 fdb_id;
+ __le16 num_ifs;
+ /* only the first 4 bits from LSB */
+ u8 type;
+ u8 pad[3];
+ /* cmd word 1 */
+ u8 mac_addr[6];
+ __le16 pad2;
+ /* cmd word 2-5 */
+ __le64 if_id[4];
+};
+
+#define DPSW_LEARNING_MODE_SHIFT 0
+#define DPSW_LEARNING_MODE_SIZE 4
+
+struct dpsw_cmd_fdb_set_learning_mode {
+ __le16 fdb_id;
+ /* only the first 4 bits from LSB */
+ u8 mode;
+};
+
+struct dpsw_rsp_get_api_version {
+ __le16 version_major;
+ __le16 version_minor;
+};
+
+#endif /* __FSL_DPSW_CMD_H */
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
new file mode 100644
index 000000000000..9b9bc604b461
--- /dev/null
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
@@ -0,0 +1,1123 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2014-2016 Freescale Semiconductor Inc.
+ * Copyright 2017-2018 NXP
+ *
+ */
+
+#include <linux/fsl/mc.h>
+#include "dpsw.h"
+#include "dpsw-cmd.h"
+
+static void build_if_id_bitmap(__le64 *bmap,
+ const u16 *id,
+ const u16 num_ifs)
+{
+ int i;
+
+ for (i = 0; (i < num_ifs) && (i < DPSW_MAX_IF); i++) {
+ if (id[i] < DPSW_MAX_IF)
+ bmap[id[i] / 64] |= cpu_to_le64(BIT_MASK(id[i] % 64));
+ }
+}
+
+/**
+ * dpsw_open() - Open a control session for the specified object
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @dpsw_id: DPSW unique ID
+ * @token: Returned token; use in subsequent API calls
+ *
+ * This function can be used to open a control session for an
+ * already created object; an object may have been declared in
+ * the DPL or by calling the dpsw_create() function.
+ * This function returns a unique authentication token,
+ * associated with the specific object ID and the specific MC
+ * portal; this token must be used in all subsequent commands for
+ * this specific object
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpsw_open(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ int dpsw_id,
+ u16 *token)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_open *cmd_params;
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_OPEN,
+ cmd_flags,
+ 0);
+ cmd_params = (struct dpsw_cmd_open *)cmd.params;
+ cmd_params->dpsw_id = cpu_to_le32(dpsw_id);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ *token = mc_cmd_hdr_read_token(&cmd);
+
+ return 0;
+}
+
+/**
+ * dpsw_close() - Close the control session of the object
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ *
+ * After this function is called, no further operations are
+ * allowed on the object without opening a new control session.
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpsw_close(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token)
+{
+ struct fsl_mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_CLOSE,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_enable() - Enable DPSW functionality
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_enable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token)
+{
+ struct fsl_mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_ENABLE,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_disable() - Disable DPSW functionality
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_disable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token)
+{
+ struct fsl_mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_DISABLE,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_reset() - Reset the DPSW, returns the object to initial state.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpsw_reset(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token)
+{
+ struct fsl_mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_RESET,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_set_irq_enable() - Set overall interrupt state.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPCI object
+ * @irq_index: The interrupt index to configure
+ * @en: Interrupt state - enable = 1, disable = 0
+ *
+ * Allows GPP software to control when interrupts are generated.
+ * Each interrupt can have up to 32 causes. The enable/disable control's the
+ * overall interrupt state. if the interrupt is disabled no causes will cause
+ * an interrupt
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpsw_set_irq_enable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u8 en)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_set_irq_enable *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_IRQ_ENABLE,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_set_irq_enable *)cmd.params;
+ dpsw_set_field(cmd_params->enable_state, ENABLE, en);
+ cmd_params->irq_index = irq_index;
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_set_irq_mask() - Set interrupt mask.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPCI object
+ * @irq_index: The interrupt index to configure
+ * @mask: Event mask to trigger interrupt;
+ * each bit:
+ * 0 = ignore event
+ * 1 = consider event for asserting IRQ
+ *
+ * Every interrupt can have up to 32 causes and the interrupt model supports
+ * masking/unmasking each cause independently
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpsw_set_irq_mask(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u32 mask)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_set_irq_mask *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_IRQ_MASK,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_set_irq_mask *)cmd.params;
+ cmd_params->mask = cpu_to_le32(mask);
+ cmd_params->irq_index = irq_index;
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_get_irq_status() - Get the current status of any pending interrupts
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @irq_index: The interrupt index to configure
+ * @status: Returned interrupts status - one bit per cause:
+ * 0 = no interrupt pending
+ * 1 = interrupt pending
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpsw_get_irq_status(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u32 *status)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_get_irq_status *cmd_params;
+ struct dpsw_rsp_get_irq_status *rsp_params;
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_IRQ_STATUS,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_get_irq_status *)cmd.params;
+ cmd_params->status = cpu_to_le32(*status);
+ cmd_params->irq_index = irq_index;
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ rsp_params = (struct dpsw_rsp_get_irq_status *)cmd.params;
+ *status = le32_to_cpu(rsp_params->status);
+
+ return 0;
+}
+
+/**
+ * dpsw_clear_irq_status() - Clear a pending interrupt's status
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPCI object
+ * @irq_index: The interrupt index to configure
+ * @status: bits to clear (W1C) - one bit per cause:
+ * 0 = don't change
+ * 1 = clear status bit
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpsw_clear_irq_status(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u32 status)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_clear_irq_status *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_CLEAR_IRQ_STATUS,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_clear_irq_status *)cmd.params;
+ cmd_params->status = cpu_to_le32(status);
+ cmd_params->irq_index = irq_index;
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_get_attributes() - Retrieve DPSW attributes
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @attr: Returned DPSW attributes
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_get_attributes(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ struct dpsw_attr *attr)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_rsp_get_attr *rsp_params;
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_ATTR,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ rsp_params = (struct dpsw_rsp_get_attr *)cmd.params;
+ attr->num_ifs = le16_to_cpu(rsp_params->num_ifs);
+ attr->max_fdbs = rsp_params->max_fdbs;
+ attr->num_fdbs = rsp_params->num_fdbs;
+ attr->max_vlans = le16_to_cpu(rsp_params->max_vlans);
+ attr->num_vlans = le16_to_cpu(rsp_params->num_vlans);
+ attr->max_fdb_entries = le16_to_cpu(rsp_params->max_fdb_entries);
+ attr->fdb_aging_time = le16_to_cpu(rsp_params->fdb_aging_time);
+ attr->id = le32_to_cpu(rsp_params->dpsw_id);
+ attr->mem_size = le16_to_cpu(rsp_params->mem_size);
+ attr->max_fdb_mc_groups = le16_to_cpu(rsp_params->max_fdb_mc_groups);
+ attr->max_meters_per_if = rsp_params->max_meters_per_if;
+ attr->options = le64_to_cpu(rsp_params->options);
+ attr->component_type = dpsw_get_field(rsp_params->component_type,
+ COMPONENT_TYPE);
+
+ return 0;
+}
+
+/**
+ * dpsw_if_set_link_cfg() - Set the link configuration.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @if_id: Interface id
+ * @cfg: Link configuration
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpsw_if_set_link_cfg(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ struct dpsw_link_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_if_set_link_cfg *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_LINK_CFG,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_if_set_link_cfg *)cmd.params;
+ cmd_params->if_id = cpu_to_le16(if_id);
+ cmd_params->rate = cpu_to_le32(cfg->rate);
+ cmd_params->options = cpu_to_le64(cfg->options);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_if_get_link_state - Return the link state
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @if_id: Interface id
+ * @state: Link state 1 - linkup, 0 - link down or disconnected
+ *
+ * @Return '0' on Success; Error code otherwise.
+ */
+int dpsw_if_get_link_state(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ struct dpsw_link_state *state)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_if_get_link_state *cmd_params;
+ struct dpsw_rsp_if_get_link_state *rsp_params;
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_LINK_STATE,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_if_get_link_state *)cmd.params;
+ cmd_params->if_id = cpu_to_le16(if_id);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ rsp_params = (struct dpsw_rsp_if_get_link_state *)cmd.params;
+ state->rate = le32_to_cpu(rsp_params->rate);
+ state->options = le64_to_cpu(rsp_params->options);
+ state->up = dpsw_get_field(rsp_params->up, UP);
+
+ return 0;
+}
+
+/**
+ * dpsw_if_set_flooding() - Enable Disable flooding for particular interface
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @if_id: Interface Identifier
+ * @en: 1 - enable, 0 - disable
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_if_set_flooding(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ u8 en)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_if_set_flooding *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_FLOODING,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_if_set_flooding *)cmd.params;
+ cmd_params->if_id = cpu_to_le16(if_id);
+ dpsw_set_field(cmd_params->enable, ENABLE, en);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_if_set_broadcast() - Enable/disable broadcast for particular interface
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @if_id: Interface Identifier
+ * @en: 1 - enable, 0 - disable
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_if_set_broadcast(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ u8 en)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_if_set_broadcast *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_BROADCAST,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_if_set_broadcast *)cmd.params;
+ cmd_params->if_id = cpu_to_le16(if_id);
+ dpsw_set_field(cmd_params->enable, ENABLE, en);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_if_set_tci() - Set default VLAN Tag Control Information (TCI)
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @if_id: Interface Identifier
+ * @cfg: Tag Control Information Configuration
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_if_set_tci(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ const struct dpsw_tci_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_if_set_tci *cmd_params;
+ u16 tmp_conf = 0;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_TCI,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_if_set_tci *)cmd.params;
+ cmd_params->if_id = cpu_to_le16(if_id);
+ dpsw_set_field(tmp_conf, VLAN_ID, cfg->vlan_id);
+ dpsw_set_field(tmp_conf, DEI, cfg->dei);
+ dpsw_set_field(tmp_conf, PCP, cfg->pcp);
+ cmd_params->conf = cpu_to_le16(tmp_conf);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_if_set_stp() - Function sets Spanning Tree Protocol (STP) state.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @if_id: Interface Identifier
+ * @cfg: STP State configuration parameters
+ *
+ * The following STP states are supported -
+ * blocking, listening, learning, forwarding and disabled.
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_if_set_stp(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ const struct dpsw_stp_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_if_set_stp *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_STP,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_if_set_stp *)cmd.params;
+ cmd_params->if_id = cpu_to_le16(if_id);
+ cmd_params->vlan_id = cpu_to_le16(cfg->vlan_id);
+ dpsw_set_field(cmd_params->state, STATE, cfg->state);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_if_get_counter() - Get specific counter of particular interface
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @if_id: Interface Identifier
+ * @type: Counter type
+ * @counter: return value
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_if_get_counter(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ enum dpsw_counter type,
+ u64 *counter)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_if_get_counter *cmd_params;
+ struct dpsw_rsp_if_get_counter *rsp_params;
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_COUNTER,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_if_get_counter *)cmd.params;
+ cmd_params->if_id = cpu_to_le16(if_id);
+ dpsw_set_field(cmd_params->type, COUNTER_TYPE, type);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ rsp_params = (struct dpsw_rsp_if_get_counter *)cmd.params;
+ *counter = le64_to_cpu(rsp_params->counter);
+
+ return 0;
+}
+
+/**
+ * dpsw_if_enable() - Enable Interface
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @if_id: Interface Identifier
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_if_enable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_if *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_ENABLE,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_if *)cmd.params;
+ cmd_params->if_id = cpu_to_le16(if_id);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_if_disable() - Disable Interface
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @if_id: Interface Identifier
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_if_disable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_if *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_DISABLE,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_if *)cmd.params;
+ cmd_params->if_id = cpu_to_le16(if_id);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_if_set_max_frame_length() - Set Maximum Receive frame length.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @if_id: Interface Identifier
+ * @frame_length: Maximum Frame Length
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_if_set_max_frame_length(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ u16 frame_length)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_if_set_max_frame_length *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_MAX_FRAME_LENGTH,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_if_set_max_frame_length *)cmd.params;
+ cmd_params->if_id = cpu_to_le16(if_id);
+ cmd_params->frame_length = cpu_to_le16(frame_length);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_vlan_add() - Adding new VLAN to DPSW.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @vlan_id: VLAN Identifier
+ * @cfg: VLAN configuration
+ *
+ * Only VLAN ID and FDB ID are required parameters here.
+ * 12 bit VLAN ID is defined in IEEE802.1Q.
+ * Adding a duplicate VLAN ID is not allowed.
+ * FDB ID can be shared across multiple VLANs. Shared learning
+ * is obtained by calling dpsw_vlan_add for multiple VLAN IDs
+ * with same fdb_id
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_vlan_add(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 vlan_id,
+ const struct dpsw_vlan_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_vlan_add *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_vlan_add *)cmd.params;
+ cmd_params->fdb_id = cpu_to_le16(cfg->fdb_id);
+ cmd_params->vlan_id = cpu_to_le16(vlan_id);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_vlan_add_if() - Adding a set of interfaces to an existing VLAN.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @vlan_id: VLAN Identifier
+ * @cfg: Set of interfaces to add
+ *
+ * It adds only interfaces not belonging to this VLAN yet,
+ * otherwise an error is generated and an entire command is
+ * ignored. This function can be called numerous times always
+ * providing required interfaces delta.
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_vlan_add_if(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 vlan_id,
+ const struct dpsw_vlan_if_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_vlan_manage_if *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD_IF,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params;
+ cmd_params->vlan_id = cpu_to_le16(vlan_id);
+ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_vlan_add_if_untagged() - Defining a set of interfaces that should be
+ * transmitted as untagged.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @vlan_id: VLAN Identifier
+ * @cfg: Set of interfaces that should be transmitted as untagged
+ *
+ * These interfaces should already belong to this VLAN.
+ * By default all interfaces are transmitted as tagged.
+ * Providing un-existing interface or untagged interface that is
+ * configured untagged already generates an error and the entire
+ * command is ignored.
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_vlan_add_if_untagged(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 vlan_id,
+ const struct dpsw_vlan_if_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_vlan_manage_if *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD_IF_UNTAGGED,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params;
+ cmd_params->vlan_id = cpu_to_le16(vlan_id);
+ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_vlan_remove_if() - Remove interfaces from an existing VLAN.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @vlan_id: VLAN Identifier
+ * @cfg: Set of interfaces that should be removed
+ *
+ * Interfaces must belong to this VLAN, otherwise an error
+ * is returned and an the command is ignored
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_vlan_remove_if(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 vlan_id,
+ const struct dpsw_vlan_if_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_vlan_manage_if *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE_IF,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params;
+ cmd_params->vlan_id = cpu_to_le16(vlan_id);
+ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_vlan_remove_if_untagged() - Define a set of interfaces that should be
+ * converted from transmitted as untagged to transmit as tagged.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @vlan_id: VLAN Identifier
+ * @cfg: Set of interfaces that should be removed
+ *
+ * Interfaces provided by API have to belong to this VLAN and
+ * configured untagged, otherwise an error is returned and the
+ * command is ignored
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_vlan_remove_if_untagged(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 vlan_id,
+ const struct dpsw_vlan_if_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_vlan_manage_if *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE_IF_UNTAGGED,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params;
+ cmd_params->vlan_id = cpu_to_le16(vlan_id);
+ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_vlan_remove() - Remove an entire VLAN
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @vlan_id: VLAN Identifier
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_vlan_remove(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 vlan_id)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_vlan_remove *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_vlan_remove *)cmd.params;
+ cmd_params->vlan_id = cpu_to_le16(vlan_id);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_fdb_add_unicast() - Function adds an unicast entry into MAC lookup table
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @fdb_id: Forwarding Database Identifier
+ * @cfg: Unicast entry configuration
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_fdb_add_unicast(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 fdb_id,
+ const struct dpsw_fdb_unicast_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_fdb_unicast_op *cmd_params;
+ int i;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_ADD_UNICAST,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_fdb_unicast_op *)cmd.params;
+ cmd_params->fdb_id = cpu_to_le16(fdb_id);
+ cmd_params->if_egress = cpu_to_le16(cfg->if_egress);
+ for (i = 0; i < 6; i++)
+ cmd_params->mac_addr[i] = cfg->mac_addr[5 - i];
+ dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_fdb_remove_unicast() - removes an entry from MAC lookup table
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @fdb_id: Forwarding Database Identifier
+ * @cfg: Unicast entry configuration
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_fdb_remove_unicast(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 fdb_id,
+ const struct dpsw_fdb_unicast_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_fdb_unicast_op *cmd_params;
+ int i;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_REMOVE_UNICAST,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_fdb_unicast_op *)cmd.params;
+ cmd_params->fdb_id = cpu_to_le16(fdb_id);
+ for (i = 0; i < 6; i++)
+ cmd_params->mac_addr[i] = cfg->mac_addr[5 - i];
+ cmd_params->if_egress = cpu_to_le16(cfg->if_egress);
+ dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_fdb_add_multicast() - Add a set of egress interfaces to multi-cast group
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @fdb_id: Forwarding Database Identifier
+ * @cfg: Multicast entry configuration
+ *
+ * If group doesn't exist, it will be created.
+ * It adds only interfaces not belonging to this multicast group
+ * yet, otherwise error will be generated and the command is
+ * ignored.
+ * This function may be called numerous times always providing
+ * required interfaces delta.
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_fdb_add_multicast(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 fdb_id,
+ const struct dpsw_fdb_multicast_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_fdb_multicast_op *cmd_params;
+ int i;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_ADD_MULTICAST,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_fdb_multicast_op *)cmd.params;
+ cmd_params->fdb_id = cpu_to_le16(fdb_id);
+ cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs);
+ dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type);
+ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs);
+ for (i = 0; i < 6; i++)
+ cmd_params->mac_addr[i] = cfg->mac_addr[5 - i];
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_fdb_remove_multicast() - Removing interfaces from an existing multicast
+ * group.
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @fdb_id: Forwarding Database Identifier
+ * @cfg: Multicast entry configuration
+ *
+ * Interfaces provided by this API have to exist in the group,
+ * otherwise an error will be returned and an entire command
+ * ignored. If there is no interface left in the group,
+ * an entire group is deleted
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_fdb_remove_multicast(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 fdb_id,
+ const struct dpsw_fdb_multicast_cfg *cfg)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_fdb_multicast_op *cmd_params;
+ int i;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_REMOVE_MULTICAST,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_fdb_multicast_op *)cmd.params;
+ cmd_params->fdb_id = cpu_to_le16(fdb_id);
+ cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs);
+ dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type);
+ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs);
+ for (i = 0; i < 6; i++)
+ cmd_params->mac_addr[i] = cfg->mac_addr[5 - i];
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_fdb_set_learning_mode() - Define FDB learning mode
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token: Token of DPSW object
+ * @fdb_id: Forwarding Database Identifier
+ * @mode: Learning mode
+ *
+ * Return: Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_fdb_set_learning_mode(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 fdb_id,
+ enum dpsw_fdb_learning_mode mode)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_cmd_fdb_set_learning_mode *cmd_params;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_SET_LEARNING_MODE,
+ cmd_flags,
+ token);
+ cmd_params = (struct dpsw_cmd_fdb_set_learning_mode *)cmd.params;
+ cmd_params->fdb_id = cpu_to_le16(fdb_id);
+ dpsw_set_field(cmd_params->mode, LEARNING_MODE, mode);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_get_api_version() - Get Data Path Switch API version
+ * @mc_io: Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @major_ver: Major version of data path switch API
+ * @minor_ver: Minor version of data path switch API
+ *
+ * Return: '0' on Success; Error code otherwise.
+ */
+int dpsw_get_api_version(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 *major_ver,
+ u16 *minor_ver)
+{
+ struct fsl_mc_command cmd = { 0 };
+ struct dpsw_rsp_get_api_version *rsp_params;
+ int err;
+
+ cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_API_VERSION,
+ cmd_flags,
+ 0);
+
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ rsp_params = (struct dpsw_rsp_get_api_version *)cmd.params;
+ *major_ver = le16_to_cpu(rsp_params->version_major);
+ *minor_ver = le16_to_cpu(rsp_params->version_minor);
+
+ return 0;
+}
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
new file mode 100644
index 000000000000..3335adde0193
--- /dev/null
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
@@ -0,0 +1,586 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2014-2016 Freescale Semiconductor Inc.
+ * Copyright 2017-2018 NXP
+ *
+ */
+
+#ifndef __FSL_DPSW_H
+#define __FSL_DPSW_H
+
+/* Data Path L2-Switch API
+ * Contains API for handling DPSW topology and functionality
+ */
+
+struct fsl_mc_io;
+
+/**
+ * DPSW general definitions
+ */
+
+/**
+ * Maximum number of traffic class priorities
+ */
+#define DPSW_MAX_PRIORITIES 8
+/**
+ * Maximum number of interfaces
+ */
+#define DPSW_MAX_IF 64
+
+int dpsw_open(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ int dpsw_id,
+ u16 *token);
+
+int dpsw_close(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
+/**
+ * DPSW options
+ */
+
+/**
+ * Disable flooding
+ */
+#define DPSW_OPT_FLOODING_DIS 0x0000000000000001ULL
+/**
+ * Disable Multicast
+ */
+#define DPSW_OPT_MULTICAST_DIS 0x0000000000000004ULL
+/**
+ * Support control interface
+ */
+#define DPSW_OPT_CTRL_IF_DIS 0x0000000000000010ULL
+/**
+ * Disable flooding metering
+ */
+#define DPSW_OPT_FLOODING_METERING_DIS 0x0000000000000020ULL
+/**
+ * Enable metering
+ */
+#define DPSW_OPT_METERING_EN 0x0000000000000040ULL
+
+/**
+ * enum dpsw_component_type - component type of a bridge
+ * @DPSW_COMPONENT_TYPE_C_VLAN: A C-VLAN component of an
+ * enterprise VLAN bridge or of a Provider Bridge used
+ * to process C-tagged frames
+ * @DPSW_COMPONENT_TYPE_S_VLAN: An S-VLAN component of a
+ * Provider Bridge
+ *
+ */
+enum dpsw_component_type {
+ DPSW_COMPONENT_TYPE_C_VLAN = 0,
+ DPSW_COMPONENT_TYPE_S_VLAN
+};
+
+/**
+ * struct dpsw_cfg - DPSW configuration
+ * @num_ifs: Number of external and internal interfaces
+ * @adv: Advanced parameters; default is all zeros;
+ * use this structure to change default settings
+ */
+struct dpsw_cfg {
+ u16 num_ifs;
+ /**
+ * struct adv - Advanced parameters
+ * @options: Enable/Disable DPSW features (bitmap)
+ * @max_vlans: Maximum Number of VLAN's; 0 - indicates default 16
+ * @max_meters_per_if: Number of meters per interface
+ * @max_fdbs: Maximum Number of FDB's; 0 - indicates default 16
+ * @max_fdb_entries: Number of FDB entries for default FDB table;
+ * 0 - indicates default 1024 entries.
+ * @fdb_aging_time: Default FDB aging time for default FDB table;
+ * 0 - indicates default 300 seconds
+ * @max_fdb_mc_groups: Number of multicast groups in each FDB table;
+ * 0 - indicates default 32
+ * @component_type: Indicates the component type of this bridge
+ */
+ struct {
+ u64 options;
+ u16 max_vlans;
+ u8 max_meters_per_if;
+ u8 max_fdbs;
+ u16 max_fdb_entries;
+ u16 fdb_aging_time;
+ u16 max_fdb_mc_groups;
+ enum dpsw_component_type component_type;
+ } adv;
+};
+
+int dpsw_enable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
+int dpsw_disable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
+int dpsw_reset(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
+/**
+ * DPSW IRQ Index and Events
+ */
+
+#define DPSW_IRQ_INDEX_IF 0x0000
+#define DPSW_IRQ_INDEX_L2SW 0x0001
+
+/**
+ * IRQ event - Indicates that the link state changed
+ */
+#define DPSW_IRQ_EVENT_LINK_CHANGED 0x0001
+
+/**
+ * struct dpsw_irq_cfg - IRQ configuration
+ * @addr: Address that must be written to signal a message-based interrupt
+ * @val: Value to write into irq_addr address
+ * @irq_num: A user defined number associated with this IRQ
+ */
+struct dpsw_irq_cfg {
+ u64 addr;
+ u32 val;
+ int irq_num;
+};
+
+int dpsw_set_irq_enable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u8 en);
+
+int dpsw_set_irq_mask(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u32 mask);
+
+int dpsw_get_irq_status(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u32 *status);
+
+int dpsw_clear_irq_status(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u8 irq_index,
+ u32 status);
+
+/**
+ * struct dpsw_attr - Structure representing DPSW attributes
+ * @id: DPSW object ID
+ * @options: Enable/Disable DPSW features
+ * @max_vlans: Maximum Number of VLANs
+ * @max_meters_per_if: Number of meters per interface
+ * @max_fdbs: Maximum Number of FDBs
+ * @max_fdb_entries: Number of FDB entries for default FDB table;
+ * 0 - indicates default 1024 entries.
+ * @fdb_aging_time: Default FDB aging time for default FDB table;
+ * 0 - indicates default 300 seconds
+ * @max_fdb_mc_groups: Number of multicast groups in each FDB table;
+ * 0 - indicates default 32
+ * @mem_size: DPSW frame storage memory size
+ * @num_ifs: Number of interfaces
+ * @num_vlans: Current number of VLANs
+ * @num_fdbs: Current number of FDBs
+ * @component_type: Component type of this bridge
+ */
+struct dpsw_attr {
+ int id;
+ u64 options;
+ u16 max_vlans;
+ u8 max_meters_per_if;
+ u8 max_fdbs;
+ u16 max_fdb_entries;
+ u16 fdb_aging_time;
+ u16 max_fdb_mc_groups;
+ u16 num_ifs;
+ u16 mem_size;
+ u16 num_vlans;
+ u8 num_fdbs;
+ enum dpsw_component_type component_type;
+};
+
+int dpsw_get_attributes(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ struct dpsw_attr *attr);
+
+/**
+ * enum dpsw_action - Action selection for special/control frames
+ * @DPSW_ACTION_DROP: Drop frame
+ * @DPSW_ACTION_REDIRECT: Redirect frame to control port
+ */
+enum dpsw_action {
+ DPSW_ACTION_DROP = 0,
+ DPSW_ACTION_REDIRECT = 1
+};
+
+/**
+ * Enable auto-negotiation
+ */
+#define DPSW_LINK_OPT_AUTONEG 0x0000000000000001ULL
+/**
+ * Enable half-duplex mode
+ */
+#define DPSW_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL
+/**
+ * Enable pause frames
+ */
+#define DPSW_LINK_OPT_PAUSE 0x0000000000000004ULL
+/**
+ * Enable a-symmetric pause frames
+ */
+#define DPSW_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL
+
+/**
+ * struct dpsw_link_cfg - Structure representing DPSW link configuration
+ * @rate: Rate
+ * @options: Mask of available options; use 'DPSW_LINK_OPT_<X>' values
+ */
+struct dpsw_link_cfg {
+ u32 rate;
+ u64 options;
+};
+
+int dpsw_if_set_link_cfg(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ struct dpsw_link_cfg *cfg);
+/**
+ * struct dpsw_link_state - Structure representing DPSW link state
+ * @rate: Rate
+ * @options: Mask of available options; use 'DPSW_LINK_OPT_<X>' values
+ * @up: 0 - covers two cases: down and disconnected, 1 - up
+ */
+struct dpsw_link_state {
+ u32 rate;
+ u64 options;
+ u8 up;
+};
+
+int dpsw_if_get_link_state(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ struct dpsw_link_state *state);
+
+int dpsw_if_set_flooding(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ u8 en);
+
+int dpsw_if_set_broadcast(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ u8 en);
+
+/**
+ * struct dpsw_tci_cfg - Tag Control Information (TCI) configuration
+ * @pcp: Priority Code Point (PCP): a 3-bit field which refers
+ * to the IEEE 802.1p priority
+ * @dei: Drop Eligible Indicator (DEI): a 1-bit field. May be used
+ * separately or in conjunction with PCP to indicate frames
+ * eligible to be dropped in the presence of congestion
+ * @vlan_id: VLAN Identifier (VID): a 12-bit field specifying the VLAN
+ * to which the frame belongs. The hexadecimal values
+ * of 0x000 and 0xFFF are reserved;
+ * all other values may be used as VLAN identifiers,
+ * allowing up to 4,094 VLANs
+ */
+struct dpsw_tci_cfg {
+ u8 pcp;
+ u8 dei;
+ u16 vlan_id;
+};
+
+int dpsw_if_set_tci(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ const struct dpsw_tci_cfg *cfg);
+
+/**
+ * enum dpsw_stp_state - Spanning Tree Protocol (STP) states
+ * @DPSW_STP_STATE_BLOCKING: Blocking state
+ * @DPSW_STP_STATE_LISTENING: Listening state
+ * @DPSW_STP_STATE_LEARNING: Learning state
+ * @DPSW_STP_STATE_FORWARDING: Forwarding state
+ *
+ */
+enum dpsw_stp_state {
+ DPSW_STP_STATE_DISABLED = 0,
+ DPSW_STP_STATE_LISTENING = 1,
+ DPSW_STP_STATE_LEARNING = 2,
+ DPSW_STP_STATE_FORWARDING = 3,
+ DPSW_STP_STATE_BLOCKING = 0
+};
+
+/**
+ * struct dpsw_stp_cfg - Spanning Tree Protocol (STP) Configuration
+ * @vlan_id: VLAN ID STP state
+ * @state: STP state
+ */
+struct dpsw_stp_cfg {
+ u16 vlan_id;
+ enum dpsw_stp_state state;
+};
+
+int dpsw_if_set_stp(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ const struct dpsw_stp_cfg *cfg);
+
+/**
+ * enum dpsw_accepted_frames - Types of frames to accept
+ * @DPSW_ADMIT_ALL: The device accepts VLAN tagged, untagged and
+ * priority tagged frames
+ * @DPSW_ADMIT_ONLY_VLAN_TAGGED: The device discards untagged frames or
+ * Priority-Tagged frames received on this interface.
+ *
+ */
+enum dpsw_accepted_frames {
+ DPSW_ADMIT_ALL = 1,
+ DPSW_ADMIT_ONLY_VLAN_TAGGED = 3
+};
+
+/**
+ * enum dpsw_counter - Counters types
+ * @DPSW_CNT_ING_FRAME: Counts ingress frames
+ * @DPSW_CNT_ING_BYTE: Counts ingress bytes
+ * @DPSW_CNT_ING_FLTR_FRAME: Counts filtered ingress frames
+ * @DPSW_CNT_ING_FRAME_DISCARD: Counts discarded ingress frame
+ * @DPSW_CNT_ING_MCAST_FRAME: Counts ingress multicast frames
+ * @DPSW_CNT_ING_MCAST_BYTE: Counts ingress multicast bytes
+ * @DPSW_CNT_ING_BCAST_FRAME: Counts ingress broadcast frames
+ * @DPSW_CNT_ING_BCAST_BYTES: Counts ingress broadcast bytes
+ * @DPSW_CNT_EGR_FRAME: Counts egress frames
+ * @DPSW_CNT_EGR_BYTE: Counts eEgress bytes
+ * @DPSW_CNT_EGR_FRAME_DISCARD: Counts discarded egress frames
+ * @DPSW_CNT_EGR_STP_FRAME_DISCARD: Counts egress STP discarded frames
+ */
+enum dpsw_counter {
+ DPSW_CNT_ING_FRAME = 0x0,
+ DPSW_CNT_ING_BYTE = 0x1,
+ DPSW_CNT_ING_FLTR_FRAME = 0x2,
+ DPSW_CNT_ING_FRAME_DISCARD = 0x3,
+ DPSW_CNT_ING_MCAST_FRAME = 0x4,
+ DPSW_CNT_ING_MCAST_BYTE = 0x5,
+ DPSW_CNT_ING_BCAST_FRAME = 0x6,
+ DPSW_CNT_ING_BCAST_BYTES = 0x7,
+ DPSW_CNT_EGR_FRAME = 0x8,
+ DPSW_CNT_EGR_BYTE = 0x9,
+ DPSW_CNT_EGR_FRAME_DISCARD = 0xa,
+ DPSW_CNT_EGR_STP_FRAME_DISCARD = 0xb
+};
+
+int dpsw_if_get_counter(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ enum dpsw_counter type,
+ u64 *counter);
+
+int dpsw_if_enable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id);
+
+int dpsw_if_disable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id);
+
+int dpsw_if_set_max_frame_length(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 if_id,
+ u16 frame_length);
+
+/**
+ * struct dpsw_vlan_cfg - VLAN Configuration
+ * @fdb_id: Forwarding Data Base
+ */
+struct dpsw_vlan_cfg {
+ u16 fdb_id;
+};
+
+int dpsw_vlan_add(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 vlan_id,
+ const struct dpsw_vlan_cfg *cfg);
+
+/**
+ * struct dpsw_vlan_if_cfg - Set of VLAN Interfaces
+ * @num_ifs: The number of interfaces that are assigned to the egress
+ * list for this VLAN
+ * @if_id: The set of interfaces that are
+ * assigned to the egress list for this VLAN
+ */
+struct dpsw_vlan_if_cfg {
+ u16 num_ifs;
+ u16 if_id[DPSW_MAX_IF];
+};
+
+int dpsw_vlan_add_if(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 vlan_id,
+ const struct dpsw_vlan_if_cfg *cfg);
+
+int dpsw_vlan_add_if_untagged(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 vlan_id,
+ const struct dpsw_vlan_if_cfg *cfg);
+
+int dpsw_vlan_remove_if(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 vlan_id,
+ const struct dpsw_vlan_if_cfg *cfg);
+
+int dpsw_vlan_remove_if_untagged(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 vlan_id,
+ const struct dpsw_vlan_if_cfg *cfg);
+
+int dpsw_vlan_remove(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 vlan_id);
+
+/**
+ * enum dpsw_fdb_entry_type - FDB Entry type - Static/Dynamic
+ * @DPSW_FDB_ENTRY_STATIC: Static entry
+ * @DPSW_FDB_ENTRY_DINAMIC: Dynamic entry
+ */
+enum dpsw_fdb_entry_type {
+ DPSW_FDB_ENTRY_STATIC = 0,
+ DPSW_FDB_ENTRY_DINAMIC = 1
+};
+
+/**
+ * struct dpsw_fdb_unicast_cfg - Unicast entry configuration
+ * @type: Select static or dynamic entry
+ * @mac_addr: MAC address
+ * @if_egress: Egress interface ID
+ */
+struct dpsw_fdb_unicast_cfg {
+ enum dpsw_fdb_entry_type type;
+ u8 mac_addr[6];
+ u16 if_egress;
+};
+
+int dpsw_fdb_add_unicast(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 fdb_id,
+ const struct dpsw_fdb_unicast_cfg *cfg);
+
+int dpsw_fdb_remove_unicast(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 fdb_id,
+ const struct dpsw_fdb_unicast_cfg *cfg);
+
+/**
+ * struct dpsw_fdb_multicast_cfg - Multi-cast entry configuration
+ * @type: Select static or dynamic entry
+ * @mac_addr: MAC address
+ * @num_ifs: Number of external and internal interfaces
+ * @if_id: Egress interface IDs
+ */
+struct dpsw_fdb_multicast_cfg {
+ enum dpsw_fdb_entry_type type;
+ u8 mac_addr[6];
+ u16 num_ifs;
+ u16 if_id[DPSW_MAX_IF];
+};
+
+int dpsw_fdb_add_multicast(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 fdb_id,
+ const struct dpsw_fdb_multicast_cfg *cfg);
+
+int dpsw_fdb_remove_multicast(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 fdb_id,
+ const struct dpsw_fdb_multicast_cfg *cfg);
+
+/**
+ * enum dpsw_fdb_learning_mode - Auto-learning modes
+ * @DPSW_FDB_LEARNING_MODE_DIS: Disable Auto-learning
+ * @DPSW_FDB_LEARNING_MODE_HW: Enable HW auto-Learning
+ * @DPSW_FDB_LEARNING_MODE_NON_SECURE: Enable None secure learning by CPU
+ * @DPSW_FDB_LEARNING_MODE_SECURE: Enable secure learning by CPU
+ *
+ * NONE - SECURE LEARNING
+ * SMAC found DMAC found CTLU Action
+ * v v Forward frame to
+ * 1. DMAC destination
+ * - v Forward frame to
+ * 1. DMAC destination
+ * 2. Control interface
+ * v - Forward frame to
+ * 1. Flooding list of interfaces
+ * - - Forward frame to
+ * 1. Flooding list of interfaces
+ * 2. Control interface
+ * SECURE LEARING
+ * SMAC found DMAC found CTLU Action
+ * v v Forward frame to
+ * 1. DMAC destination
+ * - v Forward frame to
+ * 1. Control interface
+ * v - Forward frame to
+ * 1. Flooding list of interfaces
+ * - - Forward frame to
+ * 1. Control interface
+ */
+enum dpsw_fdb_learning_mode {
+ DPSW_FDB_LEARNING_MODE_DIS = 0,
+ DPSW_FDB_LEARNING_MODE_HW = 1,
+ DPSW_FDB_LEARNING_MODE_NON_SECURE = 2,
+ DPSW_FDB_LEARNING_MODE_SECURE = 3
+};
+
+int dpsw_fdb_set_learning_mode(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ u16 fdb_id,
+ enum dpsw_fdb_learning_mode mode);
+
+/**
+ * struct dpsw_fdb_attr - FDB Attributes
+ * @max_fdb_entries: Number of FDB entries
+ * @fdb_aging_time: Aging time in seconds
+ * @learning_mode: Learning mode
+ * @num_fdb_mc_groups: Current number of multicast groups
+ * @max_fdb_mc_groups: Maximum number of multicast groups
+ */
+struct dpsw_fdb_attr {
+ u16 max_fdb_entries;
+ u16 fdb_aging_time;
+ enum dpsw_fdb_learning_mode learning_mode;
+ u16 num_fdb_mc_groups;
+ u16 max_fdb_mc_groups;
+};
+
+int dpsw_get_api_version(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 *major_ver,
+ u16 *minor_ver);
+
+#endif /* __FSL_DPSW_H */
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c
new file mode 100644
index 000000000000..926a0c053e18
--- /dev/null
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DPAA2 Ethernet Switch ethtool support
+ *
+ * Copyright 2014-2016 Freescale Semiconductor Inc.
+ * Copyright 2017-2018 NXP
+ *
+ */
+
+#include "ethsw.h"
+
+static struct {
+ enum dpsw_counter id;
+ char name[ETH_GSTRING_LEN];
+} ethsw_ethtool_counters[] = {
+ {DPSW_CNT_ING_FRAME, "rx frames"},
+ {DPSW_CNT_ING_BYTE, "rx bytes"},
+ {DPSW_CNT_ING_FLTR_FRAME, "rx filtered frames"},
+ {DPSW_CNT_ING_FRAME_DISCARD, "rx discarded frames"},
+ {DPSW_CNT_ING_BCAST_FRAME, "rx b-cast frames"},
+ {DPSW_CNT_ING_BCAST_BYTES, "rx b-cast bytes"},
+ {DPSW_CNT_ING_MCAST_FRAME, "rx m-cast frames"},
+ {DPSW_CNT_ING_MCAST_BYTE, "rx m-cast bytes"},
+ {DPSW_CNT_EGR_FRAME, "tx frames"},
+ {DPSW_CNT_EGR_BYTE, "tx bytes"},
+ {DPSW_CNT_EGR_FRAME_DISCARD, "tx discarded frames"},
+
+};
+
+#define ETHSW_NUM_COUNTERS ARRAY_SIZE(ethsw_ethtool_counters)
+
+static void ethsw_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ u16 version_major, version_minor;
+ int err;
+
+ strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
+
+ err = dpsw_get_api_version(port_priv->ethsw_data->mc_io, 0,
+ &version_major,
+ &version_minor);
+ if (err)
+ strlcpy(drvinfo->fw_version, "N/A",
+ sizeof(drvinfo->fw_version));
+ else
+ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+ "%u.%u", version_major, version_minor);
+
+ strlcpy(drvinfo->bus_info, dev_name(netdev->dev.parent->parent),
+ sizeof(drvinfo->bus_info));
+}
+
+static int
+ethsw_get_link_ksettings(struct net_device *netdev,
+ struct ethtool_link_ksettings *link_ksettings)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ struct dpsw_link_state state = {0};
+ int err = 0;
+
+ err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx,
+ &state);
+ if (err) {
+ netdev_err(netdev, "ERROR %d getting link state", err);
+ goto out;
+ }
+
+ /* At the moment, we have no way of interrogating the DPMAC
+ * from the DPSW side or there may not exist a DPMAC at all.
+ * Report only autoneg state, duplexity and speed.
+ */
+ if (state.options & DPSW_LINK_OPT_AUTONEG)
+ link_ksettings->base.autoneg = AUTONEG_ENABLE;
+ if (!(state.options & DPSW_LINK_OPT_HALF_DUPLEX))
+ link_ksettings->base.duplex = DUPLEX_FULL;
+ link_ksettings->base.speed = state.rate;
+
+out:
+ return err;
+}
+
+static int
+ethsw_set_link_ksettings(struct net_device *netdev,
+ const struct ethtool_link_ksettings *link_ksettings)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ struct dpsw_link_cfg cfg = {0};
+ int err = 0;
+
+ netdev_dbg(netdev, "Setting link parameters...");
+
+ /* Due to a temporary MC limitation, the DPSW port must be down
+ * in order to be able to change link settings. Taking steps to let
+ * the user know that.
+ */
+ if (netif_running(netdev)) {
+ netdev_info(netdev, "Sorry, interface must be brought down first.\n");
+ return -EACCES;
+ }
+
+ cfg.rate = link_ksettings->base.speed;
+ if (link_ksettings->base.autoneg == AUTONEG_ENABLE)
+ cfg.options |= DPSW_LINK_OPT_AUTONEG;
+ else
+ cfg.options &= ~DPSW_LINK_OPT_AUTONEG;
+ if (link_ksettings->base.duplex == DUPLEX_HALF)
+ cfg.options |= DPSW_LINK_OPT_HALF_DUPLEX;
+ else
+ cfg.options &= ~DPSW_LINK_OPT_HALF_DUPLEX;
+
+ err = dpsw_if_set_link_cfg(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx,
+ &cfg);
+ if (err)
+ /* ethtool will be loud enough if we return an error; no point
+ * in putting our own error message on the console by default
+ */
+ netdev_dbg(netdev, "ERROR %d setting link cfg", err);
+
+ return err;
+}
+
+static int ethsw_ethtool_get_sset_count(struct net_device *dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ETHSW_NUM_COUNTERS;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void ethsw_ethtool_get_strings(struct net_device *netdev,
+ u32 stringset, u8 *data)
+{
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < ETHSW_NUM_COUNTERS; i++)
+ memcpy(data + i * ETH_GSTRING_LEN,
+ ethsw_ethtool_counters[i].name, ETH_GSTRING_LEN);
+ break;
+ }
+}
+
+static void ethsw_ethtool_get_stats(struct net_device *netdev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ int i, err;
+
+ memset(data, 0,
+ sizeof(u64) * ETHSW_NUM_COUNTERS);
+
+ for (i = 0; i < ETHSW_NUM_COUNTERS; i++) {
+ err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx,
+ ethsw_ethtool_counters[i].id,
+ &data[i]);
+ if (err)
+ netdev_err(netdev, "dpsw_if_get_counter[%s] err %d\n",
+ ethsw_ethtool_counters[i].name, err);
+ }
+}
+
+const struct ethtool_ops ethsw_port_ethtool_ops = {
+ .get_drvinfo = ethsw_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_link_ksettings = ethsw_get_link_ksettings,
+ .set_link_ksettings = ethsw_set_link_ksettings,
+ .get_strings = ethsw_ethtool_get_strings,
+ .get_ethtool_stats = ethsw_ethtool_get_stats,
+ .get_sset_count = ethsw_ethtool_get_sset_count,
+};
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
new file mode 100644
index 000000000000..c723a04bc3d6
--- /dev/null
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -0,0 +1,1508 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DPAA2 Ethernet Switch driver
+ *
+ * Copyright 2014-2016 Freescale Semiconductor Inc.
+ * Copyright 2017-2018 NXP
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/interrupt.h>
+#include <linux/msi.h>
+#include <linux/kthread.h>
+#include <linux/workqueue.h>
+
+#include <linux/fsl/mc.h>
+
+#include "ethsw.h"
+
+static struct workqueue_struct *ethsw_owq;
+
+/* Minimal supported DPSW version */
+#define DPSW_MIN_VER_MAJOR 8
+#define DPSW_MIN_VER_MINOR 0
+
+#define DEFAULT_VLAN_ID 1
+
+static int ethsw_add_vlan(struct ethsw_core *ethsw, u16 vid)
+{
+ int err;
+
+ struct dpsw_vlan_cfg vcfg = {
+ .fdb_id = 0,
+ };
+
+ if (ethsw->vlans[vid]) {
+ dev_err(ethsw->dev, "VLAN already configured\n");
+ return -EEXIST;
+ }
+
+ err = dpsw_vlan_add(ethsw->mc_io, 0,
+ ethsw->dpsw_handle, vid, &vcfg);
+ if (err) {
+ dev_err(ethsw->dev, "dpsw_vlan_add err %d\n", err);
+ return err;
+ }
+ ethsw->vlans[vid] = ETHSW_VLAN_MEMBER;
+
+ return 0;
+}
+
+static int ethsw_port_set_tci(struct ethsw_port_priv *port_priv,
+ struct dpsw_tci_cfg *tci_cfg)
+{
+ struct ethsw_core *ethsw = port_priv->ethsw_data;
+ struct net_device *netdev = port_priv->netdev;
+ bool is_oper;
+ int err, ret;
+
+ /* Interface needs to be down to change PVID */
+ is_oper = netif_oper_up(netdev);
+ if (is_oper) {
+ err = dpsw_if_disable(ethsw->mc_io, 0,
+ ethsw->dpsw_handle,
+ port_priv->idx);
+ if (err) {
+ netdev_err(netdev, "dpsw_if_disable err %d\n", err);
+ return err;
+ }
+ }
+
+ err = dpsw_if_set_tci(ethsw->mc_io, 0, ethsw->dpsw_handle,
+ port_priv->idx, tci_cfg);
+ if (err) {
+ netdev_err(netdev, "dpsw_if_set_tci err %d\n", err);
+ goto set_tci_error;
+ }
+
+ /* Delete previous PVID info and mark the new one */
+ if (port_priv->pvid)
+ port_priv->vlans[port_priv->pvid] &= ~ETHSW_VLAN_PVID;
+ port_priv->vlans[tci_cfg->vlan_id] |= ETHSW_VLAN_PVID;
+ port_priv->pvid = tci_cfg->vlan_id;
+
+set_tci_error:
+ if (is_oper) {
+ ret = dpsw_if_enable(ethsw->mc_io, 0,
+ ethsw->dpsw_handle,
+ port_priv->idx);
+ if (ret) {
+ netdev_err(netdev, "dpsw_if_enable err %d\n", ret);
+ return ret;
+ }
+ }
+
+ return err;
+}
+
+static int ethsw_port_add_vlan(struct ethsw_port_priv *port_priv,
+ u16 vid, u16 flags)
+{
+ struct ethsw_core *ethsw = port_priv->ethsw_data;
+ struct net_device *netdev = port_priv->netdev;
+ struct dpsw_vlan_if_cfg vcfg;
+ int err;
+
+ if (port_priv->vlans[vid]) {
+ netdev_warn(netdev, "VLAN %d already configured\n", vid);
+ return -EEXIST;
+ }
+
+ vcfg.num_ifs = 1;
+ vcfg.if_id[0] = port_priv->idx;
+ err = dpsw_vlan_add_if(ethsw->mc_io, 0, ethsw->dpsw_handle, vid, &vcfg);
+ if (err) {
+ netdev_err(netdev, "dpsw_vlan_add_if err %d\n", err);
+ return err;
+ }
+
+ port_priv->vlans[vid] = ETHSW_VLAN_MEMBER;
+
+ if (flags & BRIDGE_VLAN_INFO_UNTAGGED) {
+ err = dpsw_vlan_add_if_untagged(ethsw->mc_io, 0,
+ ethsw->dpsw_handle,
+ vid, &vcfg);
+ if (err) {
+ netdev_err(netdev,
+ "dpsw_vlan_add_if_untagged err %d\n", err);
+ return err;
+ }
+ port_priv->vlans[vid] |= ETHSW_VLAN_UNTAGGED;
+ }
+
+ if (flags & BRIDGE_VLAN_INFO_PVID) {
+ struct dpsw_tci_cfg tci_cfg = {
+ .pcp = 0,
+ .dei = 0,
+ .vlan_id = vid,
+ };
+
+ err = ethsw_port_set_tci(port_priv, &tci_cfg);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int ethsw_set_learning(struct ethsw_core *ethsw, u8 flag)
+{
+ enum dpsw_fdb_learning_mode learn_mode;
+ int err;
+
+ if (flag)
+ learn_mode = DPSW_FDB_LEARNING_MODE_HW;
+ else
+ learn_mode = DPSW_FDB_LEARNING_MODE_DIS;
+
+ err = dpsw_fdb_set_learning_mode(ethsw->mc_io, 0, ethsw->dpsw_handle, 0,
+ learn_mode);
+ if (err) {
+ dev_err(ethsw->dev, "dpsw_fdb_set_learning_mode err %d\n", err);
+ return err;
+ }
+ ethsw->learning = !!flag;
+
+ return 0;
+}
+
+static int ethsw_port_set_flood(struct ethsw_port_priv *port_priv, u8 flag)
+{
+ int err;
+
+ err = dpsw_if_set_flooding(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx, flag);
+ if (err) {
+ netdev_err(port_priv->netdev,
+ "dpsw_fdb_set_learning_mode err %d\n", err);
+ return err;
+ }
+ port_priv->flood = !!flag;
+
+ return 0;
+}
+
+static int ethsw_port_set_stp_state(struct ethsw_port_priv *port_priv, u8 state)
+{
+ struct dpsw_stp_cfg stp_cfg = {
+ .vlan_id = DEFAULT_VLAN_ID,
+ .state = state,
+ };
+ int err;
+
+ if (!netif_oper_up(port_priv->netdev) || state == port_priv->stp_state)
+ return 0; /* Nothing to do */
+
+ err = dpsw_if_set_stp(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx, &stp_cfg);
+ if (err) {
+ netdev_err(port_priv->netdev,
+ "dpsw_if_set_stp err %d\n", err);
+ return err;
+ }
+
+ port_priv->stp_state = state;
+
+ return 0;
+}
+
+static int ethsw_dellink_switch(struct ethsw_core *ethsw, u16 vid)
+{
+ struct ethsw_port_priv *ppriv_local = NULL;
+ int i, err;
+
+ if (!ethsw->vlans[vid])
+ return -ENOENT;
+
+ err = dpsw_vlan_remove(ethsw->mc_io, 0, ethsw->dpsw_handle, vid);
+ if (err) {
+ dev_err(ethsw->dev, "dpsw_vlan_remove err %d\n", err);
+ return err;
+ }
+ ethsw->vlans[vid] = 0;
+
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
+ ppriv_local = ethsw->ports[i];
+ ppriv_local->vlans[vid] = 0;
+ }
+
+ return 0;
+}
+
+static int ethsw_port_fdb_add_uc(struct ethsw_port_priv *port_priv,
+ const unsigned char *addr)
+{
+ struct dpsw_fdb_unicast_cfg entry = {0};
+ int err;
+
+ entry.if_egress = port_priv->idx;
+ entry.type = DPSW_FDB_ENTRY_STATIC;
+ ether_addr_copy(entry.mac_addr, addr);
+
+ err = dpsw_fdb_add_unicast(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ 0, &entry);
+ if (err)
+ netdev_err(port_priv->netdev,
+ "dpsw_fdb_add_unicast err %d\n", err);
+ return err;
+}
+
+static int ethsw_port_fdb_del_uc(struct ethsw_port_priv *port_priv,
+ const unsigned char *addr)
+{
+ struct dpsw_fdb_unicast_cfg entry = {0};
+ int err;
+
+ entry.if_egress = port_priv->idx;
+ entry.type = DPSW_FDB_ENTRY_STATIC;
+ ether_addr_copy(entry.mac_addr, addr);
+
+ err = dpsw_fdb_remove_unicast(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ 0, &entry);
+ /* Silently discard error for calling multiple times the del command */
+ if (err && err != -ENXIO)
+ netdev_err(port_priv->netdev,
+ "dpsw_fdb_remove_unicast err %d\n", err);
+ return err;
+}
+
+static int ethsw_port_fdb_add_mc(struct ethsw_port_priv *port_priv,
+ const unsigned char *addr)
+{
+ struct dpsw_fdb_multicast_cfg entry = {0};
+ int err;
+
+ ether_addr_copy(entry.mac_addr, addr);
+ entry.type = DPSW_FDB_ENTRY_STATIC;
+ entry.num_ifs = 1;
+ entry.if_id[0] = port_priv->idx;
+
+ err = dpsw_fdb_add_multicast(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ 0, &entry);
+ /* Silently discard error for calling multiple times the add command */
+ if (err && err != -ENXIO)
+ netdev_err(port_priv->netdev, "dpsw_fdb_add_multicast err %d\n",
+ err);
+ return err;
+}
+
+static int ethsw_port_fdb_del_mc(struct ethsw_port_priv *port_priv,
+ const unsigned char *addr)
+{
+ struct dpsw_fdb_multicast_cfg entry = {0};
+ int err;
+
+ ether_addr_copy(entry.mac_addr, addr);
+ entry.type = DPSW_FDB_ENTRY_STATIC;
+ entry.num_ifs = 1;
+ entry.if_id[0] = port_priv->idx;
+
+ err = dpsw_fdb_remove_multicast(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ 0, &entry);
+ /* Silently discard error for calling multiple times the del command */
+ if (err && err != -ENAVAIL)
+ netdev_err(port_priv->netdev,
+ "dpsw_fdb_remove_multicast err %d\n", err);
+ return err;
+}
+
+static void port_get_stats(struct net_device *netdev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ u64 tmp;
+ int err;
+
+ err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx,
+ DPSW_CNT_ING_FRAME, &stats->rx_packets);
+ if (err)
+ goto error;
+
+ err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx,
+ DPSW_CNT_EGR_FRAME, &stats->tx_packets);
+ if (err)
+ goto error;
+
+ err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx,
+ DPSW_CNT_ING_BYTE, &stats->rx_bytes);
+ if (err)
+ goto error;
+
+ err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx,
+ DPSW_CNT_EGR_BYTE, &stats->tx_bytes);
+ if (err)
+ goto error;
+
+ err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx,
+ DPSW_CNT_ING_FRAME_DISCARD,
+ &stats->rx_dropped);
+ if (err)
+ goto error;
+
+ err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx,
+ DPSW_CNT_ING_FLTR_FRAME,
+ &tmp);
+ if (err)
+ goto error;
+ stats->rx_dropped += tmp;
+
+ err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx,
+ DPSW_CNT_EGR_FRAME_DISCARD,
+ &stats->tx_dropped);
+ if (err)
+ goto error;
+
+ return;
+
+error:
+ netdev_err(netdev, "dpsw_if_get_counter err %d\n", err);
+}
+
+static bool port_has_offload_stats(const struct net_device *netdev,
+ int attr_id)
+{
+ return (attr_id == IFLA_OFFLOAD_XSTATS_CPU_HIT);
+}
+
+static int port_get_offload_stats(int attr_id,
+ const struct net_device *netdev,
+ void *sp)
+{
+ switch (attr_id) {
+ case IFLA_OFFLOAD_XSTATS_CPU_HIT:
+ port_get_stats((struct net_device *)netdev, sp);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int port_change_mtu(struct net_device *netdev, int mtu)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ int err;
+
+ err = dpsw_if_set_max_frame_length(port_priv->ethsw_data->mc_io,
+ 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx,
+ (u16)ETHSW_L2_MAX_FRM(mtu));
+ if (err) {
+ netdev_err(netdev,
+ "dpsw_if_set_max_frame_length() err %d\n", err);
+ return err;
+ }
+
+ netdev->mtu = mtu;
+ return 0;
+}
+
+static int port_carrier_state_sync(struct net_device *netdev)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ struct dpsw_link_state state;
+ int err;
+
+ err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx, &state);
+ if (err) {
+ netdev_err(netdev, "dpsw_if_get_link_state() err %d\n", err);
+ return err;
+ }
+
+ WARN_ONCE(state.up > 1, "Garbage read into link_state");
+
+ if (state.up != port_priv->link_state) {
+ if (state.up)
+ netif_carrier_on(netdev);
+ else
+ netif_carrier_off(netdev);
+ port_priv->link_state = state.up;
+ }
+ return 0;
+}
+
+static int port_open(struct net_device *netdev)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ int err;
+
+ /* No need to allow Tx as control interface is disabled */
+ netif_tx_stop_all_queues(netdev);
+
+ err = dpsw_if_enable(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx);
+ if (err) {
+ netdev_err(netdev, "dpsw_if_enable err %d\n", err);
+ return err;
+ }
+
+ /* sync carrier state */
+ err = port_carrier_state_sync(netdev);
+ if (err) {
+ netdev_err(netdev,
+ "port_carrier_state_sync err %d\n", err);
+ goto err_carrier_sync;
+ }
+
+ return 0;
+
+err_carrier_sync:
+ dpsw_if_disable(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx);
+ return err;
+}
+
+static int port_stop(struct net_device *netdev)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ int err;
+
+ err = dpsw_if_disable(port_priv->ethsw_data->mc_io, 0,
+ port_priv->ethsw_data->dpsw_handle,
+ port_priv->idx);
+ if (err) {
+ netdev_err(netdev, "dpsw_if_disable err %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static netdev_tx_t port_dropframe(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ /* we don't support I/O for now, drop the frame */
+ dev_kfree_skb_any(skb);
+
+ return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops ethsw_port_ops = {
+ .ndo_open = port_open,
+ .ndo_stop = port_stop,
+
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_change_mtu = port_change_mtu,
+ .ndo_has_offload_stats = port_has_offload_stats,
+ .ndo_get_offload_stats = port_get_offload_stats,
+
+ .ndo_start_xmit = port_dropframe,
+};
+
+static void ethsw_links_state_update(struct ethsw_core *ethsw)
+{
+ int i;
+
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++)
+ port_carrier_state_sync(ethsw->ports[i]->netdev);
+}
+
+static irqreturn_t ethsw_irq0_handler_thread(int irq_num, void *arg)
+{
+ struct device *dev = (struct device *)arg;
+ struct ethsw_core *ethsw = dev_get_drvdata(dev);
+
+ /* Mask the events and the if_id reserved bits to be cleared on read */
+ u32 status = DPSW_IRQ_EVENT_LINK_CHANGED | 0xFFFF0000;
+ int err;
+
+ err = dpsw_get_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,
+ DPSW_IRQ_INDEX_IF, &status);
+ if (err) {
+ dev_err(dev, "Can't get irq status (err %d)", err);
+
+ err = dpsw_clear_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,
+ DPSW_IRQ_INDEX_IF, 0xFFFFFFFF);
+ if (err)
+ dev_err(dev, "Can't clear irq status (err %d)", err);
+ goto out;
+ }
+
+ if (status & DPSW_IRQ_EVENT_LINK_CHANGED)
+ ethsw_links_state_update(ethsw);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int ethsw_setup_irqs(struct fsl_mc_device *sw_dev)
+{
+ struct device *dev = &sw_dev->dev;
+ struct ethsw_core *ethsw = dev_get_drvdata(dev);
+ u32 mask = DPSW_IRQ_EVENT_LINK_CHANGED;
+ struct fsl_mc_device_irq *irq;
+ int err;
+
+ err = fsl_mc_allocate_irqs(sw_dev);
+ if (err) {
+ dev_err(dev, "MC irqs allocation failed\n");
+ return err;
+ }
+
+ if (WARN_ON(sw_dev->obj_desc.irq_count != DPSW_IRQ_NUM)) {
+ err = -EINVAL;
+ goto free_irq;
+ }
+
+ err = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle,
+ DPSW_IRQ_INDEX_IF, 0);
+ if (err) {
+ dev_err(dev, "dpsw_set_irq_enable err %d\n", err);
+ goto free_irq;
+ }
+
+ irq = sw_dev->irqs[DPSW_IRQ_INDEX_IF];
+
+ err = devm_request_threaded_irq(dev, irq->msi_desc->irq,
+ NULL,
+ ethsw_irq0_handler_thread,
+ IRQF_NO_SUSPEND | IRQF_ONESHOT,
+ dev_name(dev), dev);
+ if (err) {
+ dev_err(dev, "devm_request_threaded_irq(): %d", err);
+ goto free_irq;
+ }
+
+ err = dpsw_set_irq_mask(ethsw->mc_io, 0, ethsw->dpsw_handle,
+ DPSW_IRQ_INDEX_IF, mask);
+ if (err) {
+ dev_err(dev, "dpsw_set_irq_mask(): %d", err);
+ goto free_devm_irq;
+ }
+
+ err = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle,
+ DPSW_IRQ_INDEX_IF, 1);
+ if (err) {
+ dev_err(dev, "dpsw_set_irq_enable(): %d", err);
+ goto free_devm_irq;
+ }
+
+ return 0;
+
+free_devm_irq:
+ devm_free_irq(dev, irq->msi_desc->irq, dev);
+free_irq:
+ fsl_mc_free_irqs(sw_dev);
+ return err;
+}
+
+static void ethsw_teardown_irqs(struct fsl_mc_device *sw_dev)
+{
+ struct device *dev = &sw_dev->dev;
+ struct ethsw_core *ethsw = dev_get_drvdata(dev);
+ struct fsl_mc_device_irq *irq;
+ int err;
+
+ irq = sw_dev->irqs[DPSW_IRQ_INDEX_IF];
+ err = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle,
+ DPSW_IRQ_INDEX_IF, 0);
+ if (err)
+ dev_err(dev, "dpsw_set_irq_enable err %d\n", err);
+
+ fsl_mc_free_irqs(sw_dev);
+}
+
+static int swdev_port_attr_get(struct net_device *netdev,
+ struct switchdev_attr *attr)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+
+ switch (attr->id) {
+ case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
+ attr->u.ppid.id_len = 1;
+ attr->u.ppid.id[0] = port_priv->ethsw_data->dev_id;
+ break;
+ case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
+ attr->u.brport_flags =
+ (port_priv->ethsw_data->learning ? BR_LEARNING : 0) |
+ (port_priv->flood ? BR_FLOOD : 0);
+ break;
+ case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT:
+ attr->u.brport_flags_support = BR_LEARNING | BR_FLOOD;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int port_attr_stp_state_set(struct net_device *netdev,
+ struct switchdev_trans *trans,
+ u8 state)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+
+ if (switchdev_trans_ph_prepare(trans))
+ return 0;
+
+ return ethsw_port_set_stp_state(port_priv, state);
+}
+
+static int port_attr_br_flags_set(struct net_device *netdev,
+ struct switchdev_trans *trans,
+ unsigned long flags)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ int err = 0;
+
+ if (switchdev_trans_ph_prepare(trans))
+ return 0;
+
+ /* Learning is enabled per switch */
+ err = ethsw_set_learning(port_priv->ethsw_data, flags & BR_LEARNING);
+ if (err)
+ goto exit;
+
+ err = ethsw_port_set_flood(port_priv, flags & BR_FLOOD);
+
+exit:
+ return err;
+}
+
+static int swdev_port_attr_set(struct net_device *netdev,
+ const struct switchdev_attr *attr,
+ struct switchdev_trans *trans)
+{
+ int err = 0;
+
+ switch (attr->id) {
+ case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
+ err = port_attr_stp_state_set(netdev, trans,
+ attr->u.stp_state);
+ break;
+ case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
+ err = port_attr_br_flags_set(netdev, trans,
+ attr->u.brport_flags);
+ break;
+ case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
+ /* VLANs are supported by default */
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+static int port_vlans_add(struct net_device *netdev,
+ const struct switchdev_obj_port_vlan *vlan,
+ struct switchdev_trans *trans)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ int vid, err;
+
+ if (switchdev_trans_ph_prepare(trans))
+ return 0;
+
+ for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
+ if (!port_priv->ethsw_data->vlans[vid]) {
+ /* this is a new VLAN */
+ err = ethsw_add_vlan(port_priv->ethsw_data, vid);
+ if (err)
+ return err;
+
+ port_priv->ethsw_data->vlans[vid] |= ETHSW_VLAN_GLOBAL;
+ }
+ err = ethsw_port_add_vlan(port_priv, vid, vlan->flags);
+ if (err)
+ break;
+ }
+
+ return err;
+}
+
+static int port_lookup_address(struct net_device *netdev, int is_uc,
+ const unsigned char *addr)
+{
+ struct netdev_hw_addr_list *list = (is_uc) ? &netdev->uc : &netdev->mc;
+ struct netdev_hw_addr *ha;
+
+ netif_addr_lock_bh(netdev);
+ list_for_each_entry(ha, &list->list, list) {
+ if (ether_addr_equal(ha->addr, addr)) {
+ netif_addr_unlock_bh(netdev);
+ return 1;
+ }
+ }
+ netif_addr_unlock_bh(netdev);
+ return 0;
+}
+
+static int port_mdb_add(struct net_device *netdev,
+ const struct switchdev_obj_port_mdb *mdb,
+ struct switchdev_trans *trans)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ int err;
+
+ if (switchdev_trans_ph_prepare(trans))
+ return 0;
+
+ /* Check if address is already set on this port */
+ if (port_lookup_address(netdev, 0, mdb->addr))
+ return -EEXIST;
+
+ err = ethsw_port_fdb_add_mc(port_priv, mdb->addr);
+ if (err)
+ return err;
+
+ err = dev_mc_add(netdev, mdb->addr);
+ if (err) {
+ netdev_err(netdev, "dev_mc_add err %d\n", err);
+ ethsw_port_fdb_del_mc(port_priv, mdb->addr);
+ }
+
+ return err;
+}
+
+static int swdev_port_obj_add(struct net_device *netdev,
+ const struct switchdev_obj *obj,
+ struct switchdev_trans *trans)
+{
+ int err;
+
+ switch (obj->id) {
+ case SWITCHDEV_OBJ_ID_PORT_VLAN:
+ err = port_vlans_add(netdev,
+ SWITCHDEV_OBJ_PORT_VLAN(obj),
+ trans);
+ break;
+ case SWITCHDEV_OBJ_ID_PORT_MDB:
+ err = port_mdb_add(netdev,
+ SWITCHDEV_OBJ_PORT_MDB(obj),
+ trans);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+static int ethsw_port_del_vlan(struct ethsw_port_priv *port_priv, u16 vid)
+{
+ struct ethsw_core *ethsw = port_priv->ethsw_data;
+ struct net_device *netdev = port_priv->netdev;
+ struct dpsw_vlan_if_cfg vcfg;
+ int i, err;
+
+ if (!port_priv->vlans[vid])
+ return -ENOENT;
+
+ if (port_priv->vlans[vid] & ETHSW_VLAN_PVID) {
+ struct dpsw_tci_cfg tci_cfg = { 0 };
+
+ err = ethsw_port_set_tci(port_priv, &tci_cfg);
+ if (err)
+ return err;
+ }
+
+ vcfg.num_ifs = 1;
+ vcfg.if_id[0] = port_priv->idx;
+ if (port_priv->vlans[vid] & ETHSW_VLAN_UNTAGGED) {
+ err = dpsw_vlan_remove_if_untagged(ethsw->mc_io, 0,
+ ethsw->dpsw_handle,
+ vid, &vcfg);
+ if (err) {
+ netdev_err(netdev,
+ "dpsw_vlan_remove_if_untagged err %d\n",
+ err);
+ }
+ port_priv->vlans[vid] &= ~ETHSW_VLAN_UNTAGGED;
+ }
+
+ if (port_priv->vlans[vid] & ETHSW_VLAN_MEMBER) {
+ err = dpsw_vlan_remove_if(ethsw->mc_io, 0, ethsw->dpsw_handle,
+ vid, &vcfg);
+ if (err) {
+ netdev_err(netdev,
+ "dpsw_vlan_remove_if err %d\n", err);
+ return err;
+ }
+ port_priv->vlans[vid] &= ~ETHSW_VLAN_MEMBER;
+
+ /* Delete VLAN from switch if it is no longer configured on
+ * any port
+ */
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++)
+ if (ethsw->ports[i]->vlans[vid] & ETHSW_VLAN_MEMBER)
+ return 0; /* Found a port member in VID */
+
+ ethsw->vlans[vid] &= ~ETHSW_VLAN_GLOBAL;
+
+ err = ethsw_dellink_switch(ethsw, vid);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int port_vlans_del(struct net_device *netdev,
+ const struct switchdev_obj_port_vlan *vlan)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ int vid, err;
+
+ for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
+ err = ethsw_port_del_vlan(port_priv, vid);
+ if (err)
+ break;
+ }
+
+ return err;
+}
+
+static int port_mdb_del(struct net_device *netdev,
+ const struct switchdev_obj_port_mdb *mdb)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ int err;
+
+ if (!port_lookup_address(netdev, 0, mdb->addr))
+ return -ENOENT;
+
+ err = ethsw_port_fdb_del_mc(port_priv, mdb->addr);
+ if (err)
+ return err;
+
+ err = dev_mc_del(netdev, mdb->addr);
+ if (err) {
+ netdev_err(netdev, "dev_mc_del err %d\n", err);
+ return err;
+ }
+
+ return err;
+}
+
+static int swdev_port_obj_del(struct net_device *netdev,
+ const struct switchdev_obj *obj)
+{
+ int err;
+
+ switch (obj->id) {
+ case SWITCHDEV_OBJ_ID_PORT_VLAN:
+ err = port_vlans_del(netdev, SWITCHDEV_OBJ_PORT_VLAN(obj));
+ break;
+ case SWITCHDEV_OBJ_ID_PORT_MDB:
+ err = port_mdb_del(netdev, SWITCHDEV_OBJ_PORT_MDB(obj));
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+ return err;
+}
+
+static const struct switchdev_ops ethsw_port_switchdev_ops = {
+ .switchdev_port_attr_get = swdev_port_attr_get,
+ .switchdev_port_attr_set = swdev_port_attr_set,
+ .switchdev_port_obj_add = swdev_port_obj_add,
+ .switchdev_port_obj_del = swdev_port_obj_del,
+};
+
+/* For the moment, only flood setting needs to be updated */
+static int port_bridge_join(struct net_device *netdev,
+ struct net_device *upper_dev)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ struct ethsw_core *ethsw = port_priv->ethsw_data;
+ int i, err;
+
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++)
+ if (ethsw->ports[i]->bridge_dev &&
+ (ethsw->ports[i]->bridge_dev != upper_dev)) {
+ netdev_err(netdev,
+ "Another switch port is connected to %s\n",
+ ethsw->ports[i]->bridge_dev->name);
+ return -EINVAL;
+ }
+
+ /* Enable flooding */
+ err = ethsw_port_set_flood(port_priv, 1);
+ if (!err)
+ port_priv->bridge_dev = upper_dev;
+
+ return err;
+}
+
+static int port_bridge_leave(struct net_device *netdev)
+{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ int err;
+
+ /* Disable flooding */
+ err = ethsw_port_set_flood(port_priv, 0);
+ if (!err)
+ port_priv->bridge_dev = NULL;
+
+ return err;
+}
+
+static int port_netdevice_event(struct notifier_block *unused,
+ unsigned long event, void *ptr)
+{
+ struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+ struct netdev_notifier_changeupper_info *info = ptr;
+ struct net_device *upper_dev;
+ int err = 0;
+
+ if (netdev->netdev_ops != &ethsw_port_ops)
+ return NOTIFY_DONE;
+
+ /* Handle just upper dev link/unlink for the moment */
+ if (event == NETDEV_CHANGEUPPER) {
+ upper_dev = info->upper_dev;
+ if (netif_is_bridge_master(upper_dev)) {
+ if (info->linking)
+ err = port_bridge_join(netdev, upper_dev);
+ else
+ err = port_bridge_leave(netdev);
+ }
+ }
+
+ return notifier_from_errno(err);
+}
+
+static struct notifier_block port_nb __read_mostly = {
+ .notifier_call = port_netdevice_event,
+};
+
+struct ethsw_switchdev_event_work {
+ struct work_struct work;
+ struct switchdev_notifier_fdb_info fdb_info;
+ struct net_device *dev;
+ unsigned long event;
+};
+
+static void ethsw_switchdev_event_work(struct work_struct *work)
+{
+ struct ethsw_switchdev_event_work *switchdev_work =
+ container_of(work, struct ethsw_switchdev_event_work, work);
+ struct net_device *dev = switchdev_work->dev;
+ struct switchdev_notifier_fdb_info *fdb_info;
+ struct ethsw_port_priv *port_priv;
+
+ rtnl_lock();
+ port_priv = netdev_priv(dev);
+ fdb_info = &switchdev_work->fdb_info;
+
+ switch (switchdev_work->event) {
+ case SWITCHDEV_FDB_ADD_TO_DEVICE:
+ if (is_unicast_ether_addr(fdb_info->addr))
+ ethsw_port_fdb_add_uc(netdev_priv(dev), fdb_info->addr);
+ else
+ ethsw_port_fdb_add_mc(netdev_priv(dev), fdb_info->addr);
+ break;
+ case SWITCHDEV_FDB_DEL_TO_DEVICE:
+ if (is_unicast_ether_addr(fdb_info->addr))
+ ethsw_port_fdb_del_uc(netdev_priv(dev), fdb_info->addr);
+ else
+ ethsw_port_fdb_del_mc(netdev_priv(dev), fdb_info->addr);
+ break;
+ }
+
+ rtnl_unlock();
+ kfree(switchdev_work->fdb_info.addr);
+ kfree(switchdev_work);
+ dev_put(dev);
+}
+
+/* Called under rcu_read_lock() */
+static int port_switchdev_event(struct notifier_block *unused,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+ struct ethsw_switchdev_event_work *switchdev_work;
+ struct switchdev_notifier_fdb_info *fdb_info = ptr;
+
+ switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
+ if (!switchdev_work)
+ return NOTIFY_BAD;
+
+ INIT_WORK(&switchdev_work->work, ethsw_switchdev_event_work);
+ switchdev_work->dev = dev;
+ switchdev_work->event = event;
+
+ switch (event) {
+ case SWITCHDEV_FDB_ADD_TO_DEVICE:
+ case SWITCHDEV_FDB_DEL_TO_DEVICE:
+ memcpy(&switchdev_work->fdb_info, ptr,
+ sizeof(switchdev_work->fdb_info));
+ switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
+ if (!switchdev_work->fdb_info.addr)
+ goto err_addr_alloc;
+
+ ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
+ fdb_info->addr);
+
+ /* Take a reference on the device to avoid being freed. */
+ dev_hold(dev);
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ queue_work(ethsw_owq, &switchdev_work->work);
+
+ return NOTIFY_DONE;
+
+err_addr_alloc:
+ kfree(switchdev_work);
+ return NOTIFY_BAD;
+}
+
+static struct notifier_block port_switchdev_nb = {
+ .notifier_call = port_switchdev_event,
+};
+
+static int ethsw_register_notifier(struct device *dev)
+{
+ int err;
+
+ err = register_netdevice_notifier(&port_nb);
+ if (err) {
+ dev_err(dev, "Failed to register netdev notifier\n");
+ return err;
+ }
+
+ err = register_switchdev_notifier(&port_switchdev_nb);
+ if (err) {
+ dev_err(dev, "Failed to register switchdev notifier\n");
+ goto err_switchdev_nb;
+ }
+
+ return 0;
+
+err_switchdev_nb:
+ unregister_netdevice_notifier(&port_nb);
+ return err;
+}
+
+static int ethsw_open(struct ethsw_core *ethsw)
+{
+ struct ethsw_port_priv *port_priv = NULL;
+ int i, err;
+
+ err = dpsw_enable(ethsw->mc_io, 0, ethsw->dpsw_handle);
+ if (err) {
+ dev_err(ethsw->dev, "dpsw_enable err %d\n", err);
+ return err;
+ }
+
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
+ port_priv = ethsw->ports[i];
+ err = dev_open(port_priv->netdev);
+ if (err) {
+ netdev_err(port_priv->netdev, "dev_open err %d\n", err);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int ethsw_stop(struct ethsw_core *ethsw)
+{
+ struct ethsw_port_priv *port_priv = NULL;
+ int i, err;
+
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
+ port_priv = ethsw->ports[i];
+ dev_close(port_priv->netdev);
+ }
+
+ err = dpsw_disable(ethsw->mc_io, 0, ethsw->dpsw_handle);
+ if (err) {
+ dev_err(ethsw->dev, "dpsw_disable err %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int ethsw_init(struct fsl_mc_device *sw_dev)
+{
+ struct device *dev = &sw_dev->dev;
+ struct ethsw_core *ethsw = dev_get_drvdata(dev);
+ u16 version_major, version_minor, i;
+ struct dpsw_stp_cfg stp_cfg;
+ int err;
+
+ ethsw->dev_id = sw_dev->obj_desc.id;
+
+ err = dpsw_open(ethsw->mc_io, 0, ethsw->dev_id, &ethsw->dpsw_handle);
+ if (err) {
+ dev_err(dev, "dpsw_open err %d\n", err);
+ return err;
+ }
+
+ err = dpsw_get_attributes(ethsw->mc_io, 0, ethsw->dpsw_handle,
+ &ethsw->sw_attr);
+ if (err) {
+ dev_err(dev, "dpsw_get_attributes err %d\n", err);
+ goto err_close;
+ }
+
+ err = dpsw_get_api_version(ethsw->mc_io, 0,
+ &version_major,
+ &version_minor);
+ if (err) {
+ dev_err(dev, "dpsw_get_api_version err %d\n", err);
+ goto err_close;
+ }
+
+ /* Minimum supported DPSW version check */
+ if (version_major < DPSW_MIN_VER_MAJOR ||
+ (version_major == DPSW_MIN_VER_MAJOR &&
+ version_minor < DPSW_MIN_VER_MINOR)) {
+ dev_err(dev, "DPSW version %d:%d not supported. Use %d.%d or greater.\n",
+ version_major,
+ version_minor,
+ DPSW_MIN_VER_MAJOR, DPSW_MIN_VER_MINOR);
+ err = -ENOTSUPP;
+ goto err_close;
+ }
+
+ err = dpsw_reset(ethsw->mc_io, 0, ethsw->dpsw_handle);
+ if (err) {
+ dev_err(dev, "dpsw_reset err %d\n", err);
+ goto err_close;
+ }
+
+ err = dpsw_fdb_set_learning_mode(ethsw->mc_io, 0, ethsw->dpsw_handle, 0,
+ DPSW_FDB_LEARNING_MODE_HW);
+ if (err) {
+ dev_err(dev, "dpsw_fdb_set_learning_mode err %d\n", err);
+ goto err_close;
+ }
+
+ stp_cfg.vlan_id = DEFAULT_VLAN_ID;
+ stp_cfg.state = DPSW_STP_STATE_FORWARDING;
+
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
+ err = dpsw_if_set_stp(ethsw->mc_io, 0, ethsw->dpsw_handle, i,
+ &stp_cfg);
+ if (err) {
+ dev_err(dev, "dpsw_if_set_stp err %d for port %d\n",
+ err, i);
+ goto err_close;
+ }
+
+ err = dpsw_if_set_broadcast(ethsw->mc_io, 0,
+ ethsw->dpsw_handle, i, 1);
+ if (err) {
+ dev_err(dev,
+ "dpsw_if_set_broadcast err %d for port %d\n",
+ err, i);
+ goto err_close;
+ }
+ }
+
+ ethsw_owq = alloc_ordered_workqueue("%s_ordered", WQ_MEM_RECLAIM,
+ "ethsw");
+ if (!ethsw_owq) {
+ err = -ENOMEM;
+ goto err_close;
+ }
+
+ err = ethsw_register_notifier(dev);
+ if (err)
+ goto err_destroy_ordered_workqueue;
+
+ return 0;
+
+err_destroy_ordered_workqueue:
+ destroy_workqueue(ethsw_owq);
+
+err_close:
+ dpsw_close(ethsw->mc_io, 0, ethsw->dpsw_handle);
+ return err;
+}
+
+static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port)
+{
+ const char def_mcast[ETH_ALEN] = {0x01, 0x00, 0x5e, 0x00, 0x00, 0x01};
+ struct net_device *netdev = port_priv->netdev;
+ struct ethsw_core *ethsw = port_priv->ethsw_data;
+ struct dpsw_tci_cfg tci_cfg = {0};
+ struct dpsw_vlan_if_cfg vcfg;
+ int err;
+
+ /* Switch starts with all ports configured to VLAN 1. Need to
+ * remove this setting to allow configuration at bridge join
+ */
+ vcfg.num_ifs = 1;
+ vcfg.if_id[0] = port_priv->idx;
+
+ err = dpsw_vlan_remove_if_untagged(ethsw->mc_io, 0, ethsw->dpsw_handle,
+ DEFAULT_VLAN_ID, &vcfg);
+ if (err) {
+ netdev_err(netdev, "dpsw_vlan_remove_if_untagged err %d\n",
+ err);
+ return err;
+ }
+
+ err = ethsw_port_set_tci(port_priv, &tci_cfg);
+ if (err)
+ return err;
+
+ err = dpsw_vlan_remove_if(ethsw->mc_io, 0, ethsw->dpsw_handle,
+ DEFAULT_VLAN_ID, &vcfg);
+ if (err) {
+ netdev_err(netdev, "dpsw_vlan_remove_if err %d\n", err);
+ return err;
+ }
+
+ err = ethsw_port_fdb_add_mc(port_priv, def_mcast);
+
+ return err;
+}
+
+static void ethsw_unregister_notifier(struct device *dev)
+{
+ int err;
+
+ err = unregister_switchdev_notifier(&port_switchdev_nb);
+ if (err)
+ dev_err(dev,
+ "Failed to unregister switchdev notifier (%d)\n", err);
+
+ err = unregister_netdevice_notifier(&port_nb);
+ if (err)
+ dev_err(dev,
+ "Failed to unregister netdev notifier (%d)\n", err);
+}
+
+static void ethsw_takedown(struct fsl_mc_device *sw_dev)
+{
+ struct device *dev = &sw_dev->dev;
+ struct ethsw_core *ethsw = dev_get_drvdata(dev);
+ int err;
+
+ ethsw_unregister_notifier(dev);
+
+ err = dpsw_close(ethsw->mc_io, 0, ethsw->dpsw_handle);
+ if (err)
+ dev_warn(dev, "dpsw_close err %d\n", err);
+}
+
+static int ethsw_remove(struct fsl_mc_device *sw_dev)
+{
+ struct ethsw_port_priv *port_priv;
+ struct ethsw_core *ethsw;
+ struct device *dev;
+ int i;
+
+ dev = &sw_dev->dev;
+ ethsw = dev_get_drvdata(dev);
+
+ ethsw_teardown_irqs(sw_dev);
+
+ destroy_workqueue(ethsw_owq);
+
+ rtnl_lock();
+ ethsw_stop(ethsw);
+ rtnl_unlock();
+
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
+ port_priv = ethsw->ports[i];
+ unregister_netdev(port_priv->netdev);
+ free_netdev(port_priv->netdev);
+ }
+ kfree(ethsw->ports);
+
+ ethsw_takedown(sw_dev);
+ fsl_mc_portal_free(ethsw->mc_io);
+
+ kfree(ethsw);
+
+ dev_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+static int ethsw_probe_port(struct ethsw_core *ethsw, u16 port_idx)
+{
+ struct ethsw_port_priv *port_priv;
+ struct device *dev = ethsw->dev;
+ struct net_device *port_netdev;
+ int err;
+
+ port_netdev = alloc_etherdev(sizeof(struct ethsw_port_priv));
+ if (!port_netdev) {
+ dev_err(dev, "alloc_etherdev error\n");
+ return -ENOMEM;
+ }
+
+ port_priv = netdev_priv(port_netdev);
+ port_priv->netdev = port_netdev;
+ port_priv->ethsw_data = ethsw;
+
+ port_priv->idx = port_idx;
+ port_priv->stp_state = BR_STATE_FORWARDING;
+
+ /* Flooding is implicitly enabled */
+ port_priv->flood = true;
+
+ SET_NETDEV_DEV(port_netdev, dev);
+ port_netdev->netdev_ops = &ethsw_port_ops;
+ port_netdev->ethtool_ops = &ethsw_port_ethtool_ops;
+ port_netdev->switchdev_ops = &ethsw_port_switchdev_ops;
+
+ /* Set MTU limits */
+ port_netdev->min_mtu = ETH_MIN_MTU;
+ port_netdev->max_mtu = ETHSW_MAX_FRAME_LENGTH;
+
+ err = register_netdev(port_netdev);
+ if (err < 0) {
+ dev_err(dev, "register_netdev error %d\n", err);
+ free_netdev(port_netdev);
+ return err;
+ }
+
+ ethsw->ports[port_idx] = port_priv;
+
+ return ethsw_port_init(port_priv, port_idx);
+}
+
+static int ethsw_probe(struct fsl_mc_device *sw_dev)
+{
+ struct device *dev = &sw_dev->dev;
+ struct ethsw_core *ethsw;
+ int i, err;
+
+ /* Allocate switch core*/
+ ethsw = kzalloc(sizeof(*ethsw), GFP_KERNEL);
+
+ if (!ethsw)
+ return -ENOMEM;
+
+ ethsw->dev = dev;
+ dev_set_drvdata(dev, ethsw);
+
+ err = fsl_mc_portal_allocate(sw_dev, 0, &ethsw->mc_io);
+ if (err) {
+ if (err == -ENXIO)
+ err = -EPROBE_DEFER;
+ else
+ dev_err(dev, "fsl_mc_portal_allocate err %d\n", err);
+ goto err_free_drvdata;
+ }
+
+ err = ethsw_init(sw_dev);
+ if (err)
+ goto err_free_cmdport;
+
+ /* DEFAULT_VLAN_ID is implicitly configured on the switch */
+ ethsw->vlans[DEFAULT_VLAN_ID] = ETHSW_VLAN_MEMBER;
+
+ /* Learning is implicitly enabled */
+ ethsw->learning = true;
+
+ ethsw->ports = kcalloc(ethsw->sw_attr.num_ifs, sizeof(*ethsw->ports),
+ GFP_KERNEL);
+ if (!(ethsw->ports)) {
+ err = -ENOMEM;
+ goto err_takedown;
+ }
+
+ for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
+ err = ethsw_probe_port(ethsw, i);
+ if (err)
+ goto err_free_ports;
+ }
+
+ /* Switch starts up enabled */
+ rtnl_lock();
+ err = ethsw_open(ethsw);
+ rtnl_unlock();
+ if (err)
+ goto err_free_ports;
+
+ /* Setup IRQs */
+ err = ethsw_setup_irqs(sw_dev);
+ if (err)
+ goto err_stop;
+
+ dev_info(dev, "probed %d port switch\n", ethsw->sw_attr.num_ifs);
+ return 0;
+
+err_stop:
+ rtnl_lock();
+ ethsw_stop(ethsw);
+ rtnl_unlock();
+
+err_free_ports:
+ /* Cleanup registered ports only */
+ for (i--; i >= 0; i--) {
+ unregister_netdev(ethsw->ports[i]->netdev);
+ free_netdev(ethsw->ports[i]->netdev);
+ }
+ kfree(ethsw->ports);
+
+err_takedown:
+ ethsw_takedown(sw_dev);
+
+err_free_cmdport:
+ fsl_mc_portal_free(ethsw->mc_io);
+
+err_free_drvdata:
+ kfree(ethsw);
+ dev_set_drvdata(dev, NULL);
+
+ return err;
+}
+
+static const struct fsl_mc_device_id ethsw_match_id_table[] = {
+ {
+ .vendor = FSL_MC_VENDOR_FREESCALE,
+ .obj_type = "dpsw",
+ },
+ { .vendor = 0x0 }
+};
+MODULE_DEVICE_TABLE(fslmc, ethsw_match_id_table);
+
+static struct fsl_mc_driver eth_sw_drv = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ethsw_probe,
+ .remove = ethsw_remove,
+ .match_id_table = ethsw_match_id_table
+};
+
+module_fsl_mc_driver(eth_sw_drv);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DPAA2 Ethernet Switch Driver");
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
new file mode 100644
index 000000000000..069c99bfba74
--- /dev/null
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DPAA2 Ethernet Switch declarations
+ *
+ * Copyright 2014-2016 Freescale Semiconductor Inc.
+ * Copyright 2017-2018 NXP
+ *
+ */
+
+#ifndef __ETHSW_H
+#define __ETHSW_H
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_vlan.h>
+#include <uapi/linux/if_bridge.h>
+#include <net/switchdev.h>
+#include <linux/if_bridge.h>
+
+#include "dpsw.h"
+
+/* Number of IRQs supported */
+#define DPSW_IRQ_NUM 2
+
+#define ETHSW_VLAN_MEMBER 1
+#define ETHSW_VLAN_UNTAGGED 2
+#define ETHSW_VLAN_PVID 4
+#define ETHSW_VLAN_GLOBAL 8
+
+/* Maximum Frame Length supported by HW (currently 10k) */
+#define DPAA2_MFL (10 * 1024)
+#define ETHSW_MAX_FRAME_LENGTH (DPAA2_MFL - VLAN_ETH_HLEN - ETH_FCS_LEN)
+#define ETHSW_L2_MAX_FRM(mtu) ((mtu) + VLAN_ETH_HLEN + ETH_FCS_LEN)
+
+extern const struct ethtool_ops ethsw_port_ethtool_ops;
+
+struct ethsw_core;
+
+/* Per port private data */
+struct ethsw_port_priv {
+ struct net_device *netdev;
+ u16 idx;
+ struct ethsw_core *ethsw_data;
+ u8 link_state;
+ u8 stp_state;
+ bool flood;
+
+ u8 vlans[VLAN_VID_MASK + 1];
+ u16 pvid;
+ struct net_device *bridge_dev;
+};
+
+/* Switch data */
+struct ethsw_core {
+ struct device *dev;
+ struct fsl_mc_io *mc_io;
+ u16 dpsw_handle;
+ struct dpsw_attr sw_attr;
+ int dev_id;
+ struct ethsw_port_priv **ports;
+
+ u8 vlans[VLAN_VID_MASK + 1];
+ bool learning;
+};
+
+#endif /* __ETHSW_H */
diff --git a/drivers/staging/fsl-mc/TODO b/drivers/staging/fsl-mc/TODO
deleted file mode 100644
index 54a8bc69222e..000000000000
--- a/drivers/staging/fsl-mc/TODO
+++ /dev/null
@@ -1,18 +0,0 @@
-* Add at least one device driver for a DPAA2 object (child device of the
- fsl-mc bus). Most likely candidate for this is adding DPAA2 Ethernet
- driver support, which depends on drivers for several objects: DPNI,
- DPIO, DPMAC. Other pre-requisites include:
-
- * MC firmware uprev. The MC firmware upon which the fsl-mc
- bus driver and DPAA2 object drivers are based is continuing
- to evolve, so minor updates are needed to keep in sync with binary
- interface changes to the MC.
-
-* Cleanup
-
-Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
-german.rivera@freescale.com, devel@driverdev.osuosl.org,
-linux-kernel@vger.kernel.org
-
-[1] https://lkml.org/lkml/2015/7/9/93
-[2] https://lkml.org/lkml/2015/7/7/712
diff --git a/drivers/staging/fsl-mc/bus/Kconfig b/drivers/staging/fsl-mc/bus/Kconfig
index b35ef7ee6901..342453035269 100644
--- a/drivers/staging/fsl-mc/bus/Kconfig
+++ b/drivers/staging/fsl-mc/bus/Kconfig
@@ -5,19 +5,9 @@
# Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
#
-config FSL_MC_BUS
- bool "QorIQ DPAA2 fsl-mc bus driver"
- depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86_LOCAL_APIC || PPC)))
- select GENERIC_MSI_IRQ_DOMAIN
- help
- Driver to enable the bus infrastructure for the QorIQ DPAA2
- architecture. The fsl-mc bus driver handles discovery of
- DPAA2 objects (which are represented as Linux devices) and
- binding objects to drivers.
-
config FSL_MC_DPIO
tristate "QorIQ DPAA2 DPIO driver"
- depends on FSL_MC_BUS && ARCH_LAYERSCAPE
+ depends on FSL_MC_BUS
help
Driver for the DPAA2 DPIO object. A DPIO provides queue and
buffer management facilities for software to interact with
diff --git a/drivers/staging/fsl-mc/bus/Makefile b/drivers/staging/fsl-mc/bus/Makefile
index 29059db95ecc..21d8ebc8ce21 100644
--- a/drivers/staging/fsl-mc/bus/Makefile
+++ b/drivers/staging/fsl-mc/bus/Makefile
@@ -4,19 +4,6 @@
#
# Copyright (C) 2014 Freescale Semiconductor, Inc.
#
-obj-$(CONFIG_FSL_MC_BUS) += mc-bus-driver.o
-
-mc-bus-driver-objs := fsl-mc-bus.o \
- mc-sys.o \
- mc-io.o \
- dprc.o \
- dprc-driver.o \
- fsl-mc-allocator.o \
- fsl-mc-msi.o \
- irq-gic-v3-its-fsl-mc-msi.o \
- dpmcp.o \
- dpbp.o \
- dpcon.o
# MC DPIO driver
obj-$(CONFIG_FSL_MC_DPIO) += dpio/
diff --git a/drivers/staging/fsl-mc/bus/dpbp-cmd.h b/drivers/staging/fsl-mc/bus/dpbp-cmd.h
deleted file mode 100644
index 0b7f5c041f19..000000000000
--- a/drivers/staging/fsl-mc/bus/dpbp-cmd.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright 2013-2016 Freescale Semiconductor Inc.
- *
- */
-#ifndef _FSL_DPBP_CMD_H
-#define _FSL_DPBP_CMD_H
-
-/* DPBP Version */
-#define DPBP_VER_MAJOR 3
-#define DPBP_VER_MINOR 2
-
-/* Command versioning */
-#define DPBP_CMD_BASE_VERSION 1
-#define DPBP_CMD_ID_OFFSET 4
-
-#define DPBP_CMD(id) (((id) << DPBP_CMD_ID_OFFSET) | DPBP_CMD_BASE_VERSION)
-
-/* Command IDs */
-#define DPBP_CMDID_CLOSE DPBP_CMD(0x800)
-#define DPBP_CMDID_OPEN DPBP_CMD(0x804)
-#define DPBP_CMDID_GET_API_VERSION DPBP_CMD(0xa04)
-
-#define DPBP_CMDID_ENABLE DPBP_CMD(0x002)
-#define DPBP_CMDID_DISABLE DPBP_CMD(0x003)
-#define DPBP_CMDID_GET_ATTR DPBP_CMD(0x004)
-#define DPBP_CMDID_RESET DPBP_CMD(0x005)
-#define DPBP_CMDID_IS_ENABLED DPBP_CMD(0x006)
-
-struct dpbp_cmd_open {
- __le32 dpbp_id;
-};
-
-struct dpbp_cmd_destroy {
- __le32 object_id;
-};
-
-#define DPBP_ENABLE 0x1
-
-struct dpbp_rsp_is_enabled {
- u8 enabled;
-};
-
-struct dpbp_rsp_get_attributes {
- /* response word 0 */
- __le16 pad;
- __le16 bpid;
- __le32 id;
- /* response word 1 */
- __le16 version_major;
- __le16 version_minor;
-};
-
-#endif /* _FSL_DPBP_CMD_H */
diff --git a/drivers/staging/fsl-mc/bus/dpcon-cmd.h b/drivers/staging/fsl-mc/bus/dpcon-cmd.h
deleted file mode 100644
index 27fa09877970..000000000000
--- a/drivers/staging/fsl-mc/bus/dpcon-cmd.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright 2013-2016 Freescale Semiconductor Inc.
- *
- */
-#ifndef _FSL_DPCON_CMD_H
-#define _FSL_DPCON_CMD_H
-
-/* DPCON Version */
-#define DPCON_VER_MAJOR 3
-#define DPCON_VER_MINOR 2
-
-/* Command versioning */
-#define DPCON_CMD_BASE_VERSION 1
-#define DPCON_CMD_ID_OFFSET 4
-
-#define DPCON_CMD(id) (((id) << DPCON_CMD_ID_OFFSET) | DPCON_CMD_BASE_VERSION)
-
-/* Command IDs */
-#define DPCON_CMDID_CLOSE DPCON_CMD(0x800)
-#define DPCON_CMDID_OPEN DPCON_CMD(0x808)
-
-#define DPCON_CMDID_ENABLE DPCON_CMD(0x002)
-#define DPCON_CMDID_DISABLE DPCON_CMD(0x003)
-#define DPCON_CMDID_GET_ATTR DPCON_CMD(0x004)
-#define DPCON_CMDID_RESET DPCON_CMD(0x005)
-
-#define DPCON_CMDID_SET_NOTIFICATION DPCON_CMD(0x100)
-
-struct dpcon_cmd_open {
- __le32 dpcon_id;
-};
-
-#define DPCON_ENABLE 1
-
-struct dpcon_rsp_get_attr {
- /* response word 0 */
- __le32 id;
- __le16 qbman_ch_id;
- u8 num_priorities;
- u8 pad;
-};
-
-struct dpcon_cmd_set_notification {
- /* cmd word 0 */
- __le32 dpio_id;
- u8 priority;
- u8 pad[3];
- /* cmd word 1 */
- __le64 user_ctx;
-};
-
-#endif /* _FSL_DPCON_CMD_H */
diff --git a/drivers/staging/fsl-mc/bus/dpio/Makefile b/drivers/staging/fsl-mc/bus/dpio/Makefile
index 53ba84d7b884..b9ff24c76582 100644
--- a/drivers/staging/fsl-mc/bus/dpio/Makefile
+++ b/drivers/staging/fsl-mc/bus/dpio/Makefile
@@ -3,8 +3,6 @@
# QorIQ DPAA2 DPIO driver
#
-subdir-ccflags-y := -Werror
-
obj-$(CONFIG_FSL_MC_DPIO) += fsl-mc-dpio.o
fsl-mc-dpio-objs := dpio.o qbman-portal.o dpio-service.o dpio-driver.o
diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c b/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c
index b8479ef64c71..182b38412a82 100644
--- a/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c
+++ b/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c
@@ -14,7 +14,7 @@
#include <linux/dma-mapping.h>
#include <linux/delay.h>
-#include "../../include/mc.h"
+#include <linux/fsl/mc.h>
#include "../../include/dpaa2-io.h"
#include "qbman-portal.h"
diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-service.c b/drivers/staging/fsl-mc/bus/dpio/dpio-service.c
index d3c8462d43e8..14ed2beb7432 100644
--- a/drivers/staging/fsl-mc/bus/dpio/dpio-service.c
+++ b/drivers/staging/fsl-mc/bus/dpio/dpio-service.c
@@ -5,7 +5,7 @@
*
*/
#include <linux/types.h>
-#include "../../include/mc.h"
+#include <linux/fsl/mc.h>
#include "../../include/dpaa2-io.h"
#include <linux/init.h>
#include <linux/module.h>
@@ -192,7 +192,7 @@ irqreturn_t dpaa2_io_irq(struct dpaa2_io *obj)
u64 q64;
q64 = qbman_result_SCN_ctx(dq);
- ctx = (void *)q64;
+ ctx = (void *)(uintptr_t)q64;
ctx->cb(ctx);
} else {
pr_crit("fsl-mc-dpio: Unrecognised/ignored DQRR entry\n");
@@ -237,7 +237,7 @@ int dpaa2_io_service_register(struct dpaa2_io *d,
return -ENODEV;
ctx->dpio_id = d->dpio_desc.dpio_id;
- ctx->qman64 = (u64)ctx;
+ ctx->qman64 = (u64)(uintptr_t)ctx;
ctx->dpio_private = d;
spin_lock_irqsave(&d->lock_notifications, irqflags);
list_add(&ctx->node, &d->notifications);
diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio.c b/drivers/staging/fsl-mc/bus/dpio/dpio.c
index 20cdeae54a74..ff37c80e11a0 100644
--- a/drivers/staging/fsl-mc/bus/dpio/dpio.c
+++ b/drivers/staging/fsl-mc/bus/dpio/dpio.c
@@ -5,7 +5,7 @@
*
*/
#include <linux/kernel.h>
-#include "../../include/mc.h"
+#include <linux/fsl/mc.h>
#include "dpio.h"
#include "dpio-cmd.h"
@@ -37,7 +37,7 @@ int dpio_open(struct fsl_mc_io *mc_io,
int dpio_id,
u16 *token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpio_cmd_open *dpio_cmd;
int err;
@@ -70,7 +70,7 @@ int dpio_close(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPIO_CMDID_CLOSE,
@@ -92,7 +92,7 @@ int dpio_enable(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPIO_CMDID_ENABLE,
@@ -114,7 +114,7 @@ int dpio_disable(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPIO_CMDID_DISABLE,
@@ -138,7 +138,7 @@ int dpio_get_attributes(struct fsl_mc_io *mc_io,
u16 token,
struct dpio_attr *attr)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
struct dpio_rsp_get_attr *dpio_rsp;
int err;
@@ -180,7 +180,7 @@ int dpio_get_api_version(struct fsl_mc_io *mc_io,
u16 *major_ver,
u16 *minor_ver)
{
- struct mc_command cmd = { 0 };
+ struct fsl_mc_command cmd = { 0 };
int err;
/* prepare command */
diff --git a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c
index 376e9ed0297a..116fafb28640 100644
--- a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c
+++ b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c
@@ -497,7 +497,7 @@ void qbman_pull_desc_set_storage(struct qbman_pull_desc *d,
int stash)
{
/* save the virtual address */
- d->rsp_addr_virt = (u64)storage;
+ d->rsp_addr_virt = (u64)(uintptr_t)storage;
if (!storage) {
d->verb &= ~(1 << QB_VDQCR_VERB_RLS_SHIFT);
@@ -522,11 +522,6 @@ void qbman_pull_desc_set_numframes(struct qbman_pull_desc *d, u8 numframes)
d->numf = numframes - 1;
}
-void qbman_pull_desc_set_token(struct qbman_pull_desc *d, u8 token)
-{
- d->tok = token;
-}
-
/*
* Exactly one of the following descriptor "actions" should be set. (Calling any
* one of these will replace the effect of any prior call to one of these.)
@@ -590,7 +585,7 @@ int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d)
atomic_inc(&s->vdq.available);
return -EBUSY;
}
- s->vdq.storage = (void *)d->rsp_addr_virt;
+ s->vdq.storage = (void *)(uintptr_t)d->rsp_addr_virt;
p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR);
p->numf = d->numf;
p->tok = QMAN_DQ_TOKEN_VALID;
@@ -830,7 +825,7 @@ int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d,
struct qbman_acquire_desc {
u8 verb;
u8 reserved;
- u16 bpid;
+ __le16 bpid;
u8 num;
u8 reserved2[59];
};
@@ -838,10 +833,10 @@ struct qbman_acquire_desc {
struct qbman_acquire_rslt {
u8 verb;
u8 rslt;
- u16 reserved;
+ __le16 reserved;
u8 num;
u8 reserved2[3];
- u64 buf[7];
+ __le64 buf[7];
};
/**
@@ -904,7 +899,7 @@ int qbman_swp_acquire(struct qbman_swp *s, u16 bpid, u64 *buffers,
struct qbman_alt_fq_state_desc {
u8 verb;
u8 reserved[3];
- u32 fqid;
+ __le32 fqid;
u8 reserved2[56];
};
@@ -927,7 +922,7 @@ int qbman_swp_alt_fq_state(struct qbman_swp *s, u32 fqid,
if (!p)
return -EBUSY;
- p->fqid = cpu_to_le32(fqid) & ALT_FQ_FQID_MASK;
+ p->fqid = cpu_to_le32(fqid & ALT_FQ_FQID_MASK);
/* Complete the management command */
r = qbman_swp_mc_complete(s, p, alt_fq_verb);
@@ -953,11 +948,11 @@ int qbman_swp_alt_fq_state(struct qbman_swp *s, u32 fqid,
struct qbman_cdan_ctrl_desc {
u8 verb;
u8 reserved;
- u16 ch;
+ __le16 ch;
u8 we;
u8 ctrl;
- u16 reserved2;
- u64 cdan_ctx;
+ __le16 reserved2;
+ __le64 cdan_ctx;
u8 reserved3[48];
};
@@ -965,7 +960,7 @@ struct qbman_cdan_ctrl_desc {
struct qbman_cdan_ctrl_rslt {
u8 verb;
u8 rslt;
- u16 ch;
+ __le16 ch;
u8 reserved[60];
};
diff --git a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h
index fb8b9d35a3eb..4488a445b709 100644
--- a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h
+++ b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h
@@ -32,8 +32,8 @@ struct qbman_pull_desc {
u8 numf;
u8 tok;
u8 reserved;
- u32 dq_src;
- u64 rsp_addr;
+ __le32 dq_src;
+ __le64 rsp_addr;
u64 rsp_addr_virt;
u8 padding[40];
};
@@ -70,17 +70,17 @@ enum qbman_pull_type_e {
struct qbman_eq_desc {
u8 verb;
u8 dca;
- u16 seqnum;
- u16 orpid;
- u16 reserved1;
- u32 tgtid;
- u32 tag;
- u16 qdbin;
+ __le16 seqnum;
+ __le16 orpid;
+ __le16 reserved1;
+ __le32 tgtid;
+ __le32 tag;
+ __le16 qdbin;
u8 qpri;
u8 reserved[3];
u8 wae;
u8 rspid;
- u64 rsp_addr;
+ __le64 rsp_addr;
u8 fd[32];
};
@@ -88,9 +88,9 @@ struct qbman_eq_desc {
struct qbman_release_desc {
u8 verb;
u8 reserved;
- u16 bpid;
- u32 reserved2;
- u64 buf[7];
+ __le16 bpid;
+ __le32 reserved2;
+ __le64 buf[7];
};
/* Management command result codes */
diff --git a/drivers/staging/fsl-mc/include/dpaa2-fd.h b/drivers/staging/fsl-mc/include/dpaa2-fd.h
index 3e022001f0b1..b55b89ba4eda 100644
--- a/drivers/staging/fsl-mc/include/dpaa2-fd.h
+++ b/drivers/staging/fsl-mc/include/dpaa2-fd.h
@@ -287,7 +287,7 @@ enum dpaa2_sg_format {
*/
static inline dma_addr_t dpaa2_sg_get_addr(const struct dpaa2_sg_entry *sg)
{
- return le64_to_cpu((dma_addr_t)sg->addr);
+ return (dma_addr_t)le64_to_cpu(sg->addr);
}
/**
@@ -418,8 +418,8 @@ static inline bool dpaa2_sg_is_final(const struct dpaa2_sg_entry *sg)
*/
static inline void dpaa2_sg_set_final(struct dpaa2_sg_entry *sg, bool final)
{
- sg->format_offset &= cpu_to_le16(~(SG_FINAL_FLAG_MASK
- << SG_FINAL_FLAG_SHIFT));
+ sg->format_offset &= cpu_to_le16((~(SG_FINAL_FLAG_MASK
+ << SG_FINAL_FLAG_SHIFT)) & 0xFFFF);
sg->format_offset |= cpu_to_le16(final << SG_FINAL_FLAG_SHIFT);
}
diff --git a/drivers/staging/fsl-mc/include/dpaa2-io.h b/drivers/staging/fsl-mc/include/dpaa2-io.h
index 9cb1eec87a9c..f71227d3df8d 100644
--- a/drivers/staging/fsl-mc/include/dpaa2-io.h
+++ b/drivers/staging/fsl-mc/include/dpaa2-io.h
@@ -80,7 +80,7 @@ struct dpaa2_io *dpaa2_io_service_select(int cpu);
* Used when a FQDAN/CDAN registration is made by drivers.
*/
struct dpaa2_io_notification_ctx {
- void (*cb)(struct dpaa2_io_notification_ctx *);
+ void (*cb)(struct dpaa2_io_notification_ctx *ctx);
int is_cdan;
u32 id;
int desired_cpu;
diff --git a/drivers/staging/fsl-mc/include/dpbp.h b/drivers/staging/fsl-mc/include/dpbp.h
deleted file mode 100644
index 4a1809604319..000000000000
--- a/drivers/staging/fsl-mc/include/dpbp.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright 2013-2016 Freescale Semiconductor Inc.
- *
- */
-#ifndef __FSL_DPBP_H
-#define __FSL_DPBP_H
-
-/*
- * Data Path Buffer Pool API
- * Contains initialization APIs and runtime control APIs for DPBP
- */
-
-struct fsl_mc_io;
-
-int dpbp_open(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- int dpbp_id,
- u16 *token);
-
-int dpbp_close(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token);
-
-int dpbp_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token);
-
-int dpbp_disable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token);
-
-int dpbp_is_enabled(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int *en);
-
-int dpbp_reset(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token);
-
-/**
- * struct dpbp_attr - Structure representing DPBP attributes
- * @id: DPBP object ID
- * @bpid: Hardware buffer pool ID; should be used as an argument in
- * acquire/release operations on buffers
- */
-struct dpbp_attr {
- int id;
- u16 bpid;
-};
-
-int dpbp_get_attributes(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- struct dpbp_attr *attr);
-
-int dpbp_get_api_version(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 *major_ver,
- u16 *minor_ver);
-
-#endif /* __FSL_DPBP_H */
diff --git a/drivers/staging/fsl-mc/include/dpcon.h b/drivers/staging/fsl-mc/include/dpcon.h
deleted file mode 100644
index 062e90ad929b..000000000000
--- a/drivers/staging/fsl-mc/include/dpcon.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
-/*
- * Copyright 2013-2016 Freescale Semiconductor Inc.
- *
- */
-#ifndef __FSL_DPCON_H
-#define __FSL_DPCON_H
-
-/* Data Path Concentrator API
- * Contains initialization APIs and runtime control APIs for DPCON
- */
-
-struct fsl_mc_io;
-
-/** General DPCON macros */
-
-/**
- * Use it to disable notifications; see dpcon_set_notification()
- */
-#define DPCON_INVALID_DPIO_ID (int)(-1)
-
-int dpcon_open(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- int dpcon_id,
- u16 *token);
-
-int dpcon_close(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token);
-
-int dpcon_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token);
-
-int dpcon_disable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token);
-
-int dpcon_reset(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token);
-
-/**
- * struct dpcon_attr - Structure representing DPCON attributes
- * @id: DPCON object ID
- * @qbman_ch_id: Channel ID to be used by dequeue operation
- * @num_priorities: Number of priorities for the DPCON channel (1-8)
- */
-struct dpcon_attr {
- int id;
- u16 qbman_ch_id;
- u8 num_priorities;
-};
-
-int dpcon_get_attributes(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- struct dpcon_attr *attr);
-
-/**
- * struct dpcon_notification_cfg - Structure representing notification params
- * @dpio_id: DPIO object ID; must be configured with a notification channel;
- * to disable notifications set it to 'DPCON_INVALID_DPIO_ID';
- * @priority: Priority selection within the DPIO channel; valid values
- * are 0-7, depending on the number of priorities in that channel
- * @user_ctx: User context value provided with each CDAN message
- */
-struct dpcon_notification_cfg {
- int dpio_id;
- u8 priority;
- u64 user_ctx;
-};
-
-int dpcon_set_notification(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- struct dpcon_notification_cfg *cfg);
-
-#endif /* __FSL_DPCON_H */
diff --git a/drivers/staging/gdm724x/gdm_endian.c b/drivers/staging/gdm724x/gdm_endian.c
index d0b43e20ec06..4200391b1a97 100644
--- a/drivers/staging/gdm724x/gdm_endian.c
+++ b/drivers/staging/gdm724x/gdm_endian.c
@@ -14,41 +14,33 @@
#include <linux/kernel.h>
#include "gdm_endian.h"
-void gdm_set_endian(struct gdm_endian *ed, u8 dev_endian)
+__dev16 gdm_cpu_to_dev16(u8 dev_ed, u16 x)
{
- if (dev_endian == ENDIANNESS_BIG)
- ed->dev_ed = ENDIANNESS_BIG;
- else
- ed->dev_ed = ENDIANNESS_LITTLE;
-}
-
-__dev16 gdm_cpu_to_dev16(struct gdm_endian *ed, u16 x)
-{
- if (ed->dev_ed == ENDIANNESS_LITTLE)
+ if (dev_ed == ENDIANNESS_LITTLE)
return (__force __dev16)cpu_to_le16(x);
else
return (__force __dev16)cpu_to_be16(x);
}
-u16 gdm_dev16_to_cpu(struct gdm_endian *ed, __dev16 x)
+u16 gdm_dev16_to_cpu(u8 dev_ed, __dev16 x)
{
- if (ed->dev_ed == ENDIANNESS_LITTLE)
+ if (dev_ed == ENDIANNESS_LITTLE)
return le16_to_cpu((__force __le16)x);
else
return be16_to_cpu((__force __be16)x);
}
-__dev32 gdm_cpu_to_dev32(struct gdm_endian *ed, u32 x)
+__dev32 gdm_cpu_to_dev32(u8 dev_ed, u32 x)
{
- if (ed->dev_ed == ENDIANNESS_LITTLE)
+ if (dev_ed == ENDIANNESS_LITTLE)
return (__force __dev32)cpu_to_le32(x);
else
return (__force __dev32)cpu_to_be32(x);
}
-u32 gdm_dev32_to_cpu(struct gdm_endian *ed, __dev32 x)
+u32 gdm_dev32_to_cpu(u8 dev_ed, __dev32 x)
{
- if (ed->dev_ed == ENDIANNESS_LITTLE)
+ if (dev_ed == ENDIANNESS_LITTLE)
return le32_to_cpu((__force __le32)x);
else
return be32_to_cpu((__force __be32)x);
diff --git a/drivers/staging/gdm724x/gdm_endian.h b/drivers/staging/gdm724x/gdm_endian.h
index a785f30bb369..e58d29f868ba 100644
--- a/drivers/staging/gdm724x/gdm_endian.h
+++ b/drivers/staging/gdm724x/gdm_endian.h
@@ -32,14 +32,9 @@ enum {
ENDIANNESS_MAX
};
-struct gdm_endian {
- u8 dev_ed;
-};
-
-void gdm_set_endian(struct gdm_endian *ed, u8 dev_endian);
-__dev16 gdm_cpu_to_dev16(struct gdm_endian *ed, u16 x);
-u16 gdm_dev16_to_cpu(struct gdm_endian *ed, __dev16 x);
-__dev32 gdm_cpu_to_dev32(struct gdm_endian *ed, u32 x);
-u32 gdm_dev32_to_cpu(struct gdm_endian *ed, __dev32 x);
+__dev16 gdm_cpu_to_dev16(u8 dev_ed, u16 x);
+u16 gdm_dev16_to_cpu(u8 dev_ed, __dev16 x);
+__dev32 gdm_cpu_to_dev32(u8 dev_ed, u32 x);
+u32 gdm_dev32_to_cpu(u8 dev_ed, __dev32 x);
#endif /*__GDM_ENDIAN_H__*/
diff --git a/drivers/staging/gdm724x/gdm_lte.c b/drivers/staging/gdm724x/gdm_lte.c
index 0527b0d1c1d0..4f3c518304f2 100644
--- a/drivers/staging/gdm724x/gdm_lte.c
+++ b/drivers/staging/gdm724x/gdm_lte.c
@@ -185,6 +185,7 @@ static __sum16 icmp6_checksum(struct ipv6hdr *ipv6, u16 *ptr, int len)
unsigned short *w = ptr;
__wsum sum = 0;
int i;
+ u16 pa;
union {
struct {
@@ -204,9 +205,10 @@ static __sum16 icmp6_checksum(struct ipv6hdr *ipv6, u16 *ptr, int len)
pseudo_header.ph.ph_nxt = ipv6->nexthdr;
w = (u16 *)&pseudo_header;
- for (i = 0; i < ARRAY_SIZE(pseudo_header.pa); i++)
- sum = csum_add(sum, csum_unfold(
- (__force __sum16)pseudo_header.pa[i]));
+ for (i = 0; i < ARRAY_SIZE(pseudo_header.pa); i++) {
+ pa = pseudo_header.pa[i];
+ sum = csum_add(sum, csum_unfold((__force __sum16)pa));
+ }
w = ptr;
while (len > 1) {
@@ -308,7 +310,8 @@ static int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type)
sizeof(struct neighbour_advertisement));
icmp6_out.icmp6_cksum = icmp6_checksum(&ipv6_out,
- (u16 *)icmp_na, sizeof(icmp_na));
+ (u16 *)icmp_na,
+ sizeof(icmp_na));
} else {
return -EINVAL;
}
@@ -508,8 +511,9 @@ static struct net_device_stats *gdm_lte_stats(struct net_device *dev)
static int gdm_lte_event_send(struct net_device *dev, char *buf, int len)
{
- struct nic *nic = netdev_priv(dev);
+ struct phy_dev *phy_dev = ((struct nic *)netdev_priv(dev))->phy_dev;
struct hci_packet *hci = (struct hci_packet *)buf;
+ int length;
int idx;
int ret;
@@ -517,11 +521,9 @@ static int gdm_lte_event_send(struct net_device *dev, char *buf, int len)
if (ret != 1)
return -EINVAL;
- return netlink_send(lte_event.sock, idx, 0, buf,
- gdm_dev16_to_cpu(
- nic->phy_dev->get_endian(
- nic->phy_dev->priv_dev), hci->len)
- + HCI_HEADER_SIZE);
+ length = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev),
+ hci->len) + HCI_HEADER_SIZE;
+ return netlink_send(lte_event.sock, idx, 0, buf, length);
}
static void gdm_lte_event_rcv(struct net_device *dev, u16 type,
@@ -683,7 +685,7 @@ static void gdm_lte_multi_sdu_pkt(struct phy_dev *phy_dev, char *buf, int len)
struct net_device *dev;
struct multi_sdu *multi_sdu = (struct multi_sdu *)buf;
struct sdu *sdu = NULL;
- struct gdm_endian *endian = phy_dev->get_endian(phy_dev->priv_dev);
+ u8 endian = phy_dev->get_endian(phy_dev->priv_dev);
u8 *data = (u8 *)multi_sdu->data;
u16 i = 0;
u16 num_packet;
@@ -728,33 +730,30 @@ static void gdm_lte_pdn_table(struct net_device *dev, char *buf, int len)
{
struct nic *nic = netdev_priv(dev);
struct hci_pdn_table_ind *pdn_table = (struct hci_pdn_table_ind *)buf;
+ u8 ed = nic->phy_dev->get_endian(nic->phy_dev->priv_dev);
- if (pdn_table->activate) {
- nic->pdn_table.activate = pdn_table->activate;
- nic->pdn_table.dft_eps_id = gdm_dev32_to_cpu(
- nic->phy_dev->get_endian(
- nic->phy_dev->priv_dev),
- pdn_table->dft_eps_id);
- nic->pdn_table.nic_type = gdm_dev32_to_cpu(
- nic->phy_dev->get_endian(
- nic->phy_dev->priv_dev),
- pdn_table->nic_type);
-
- netdev_info(dev, "pdn activated, nic_type=0x%x\n",
- nic->pdn_table.nic_type);
- } else {
+ if (!pdn_table->activate) {
memset(&nic->pdn_table, 0x00, sizeof(struct pdn_table));
netdev_info(dev, "pdn deactivated\n");
+
+ return;
}
+
+ nic->pdn_table.activate = pdn_table->activate;
+ nic->pdn_table.dft_eps_id = gdm_dev32_to_cpu(ed, pdn_table->dft_eps_id);
+ nic->pdn_table.nic_type = gdm_dev32_to_cpu(ed, pdn_table->nic_type);
+
+ netdev_info(dev, "pdn activated, nic_type=0x%x\n",
+ nic->pdn_table.nic_type);
}
static int gdm_lte_receive_pkt(struct phy_dev *phy_dev, char *buf, int len)
{
struct hci_packet *hci = (struct hci_packet *)buf;
struct hci_pdn_table_ind *pdn_table = (struct hci_pdn_table_ind *)buf;
- struct gdm_endian *endian = phy_dev->get_endian(phy_dev->priv_dev);
struct sdu *sdu;
struct net_device *dev;
+ u8 endian = phy_dev->get_endian(phy_dev->priv_dev);
int ret = 0;
u16 cmd_evt;
u32 nic_type;
@@ -896,12 +895,11 @@ int register_lte_device(struct phy_dev *phy_dev,
nic->phy_dev = phy_dev;
nic->nic_id = index;
- form_mac_address(
- net->dev_addr,
- nic->src_mac_addr,
- nic->dest_mac_addr,
- mac_address,
- index);
+ form_mac_address(net->dev_addr,
+ nic->src_mac_addr,
+ nic->dest_mac_addr,
+ mac_address,
+ index);
SET_NETDEV_DEV(net, dev);
SET_NETDEV_DEVTYPE(net, &wwan_type);
diff --git a/drivers/staging/gdm724x/gdm_lte.h b/drivers/staging/gdm724x/gdm_lte.h
index 3ecaff1a40cb..bad0855e4721 100644
--- a/drivers/staging/gdm724x/gdm_lte.h
+++ b/drivers/staging/gdm724x/gdm_lte.h
@@ -56,7 +56,7 @@ struct phy_dev {
int (*cb)(void *cb_data, void *data, int len,
int context),
void *cb_data, int context);
- struct gdm_endian * (*get_endian)(void *priv_dev);
+ u8 (*get_endian)(void *priv_dev);
};
struct nic {
diff --git a/drivers/staging/gdm724x/gdm_mux.c b/drivers/staging/gdm724x/gdm_mux.c
index 996b1f538aae..63921bad519e 100644
--- a/drivers/staging/gdm724x/gdm_mux.c
+++ b/drivers/staging/gdm724x/gdm_mux.c
@@ -657,7 +657,11 @@ static struct usb_driver gdm_mux_driver = {
static int __init gdm_usb_mux_init(void)
{
- register_lte_tty_driver();
+ int ret;
+
+ ret = register_lte_tty_driver();
+ if (ret)
+ return ret;
return usb_register(&gdm_mux_driver);
}
diff --git a/drivers/staging/gdm724x/gdm_tty.c b/drivers/staging/gdm724x/gdm_tty.c
index fc7682c18f20..3cdebb81ba63 100644
--- a/drivers/staging/gdm724x/gdm_tty.c
+++ b/drivers/staging/gdm724x/gdm_tty.c
@@ -37,13 +37,6 @@
#define MUX_TX_MAX_SIZE 2048
-#define gdm_tty_send(n, d, l, i, c, b) (\
- n->tty_dev->send_func(n->tty_dev->priv_dev, d, l, i, c, b))
-#define gdm_tty_recv(n, c) (\
- n->tty_dev->recv_func(n->tty_dev->priv_dev, c))
-#define gdm_tty_send_control(n, r, v, d, l) (\
- n->tty_dev->send_control(n->tty_dev->priv_dev, r, v, d, l))
-
#define GDM_TTY_READY(gdm) (gdm && gdm->tty_dev && gdm->port.count)
static struct tty_driver *gdm_driver[TTY_MAX_COUNT];
@@ -146,7 +139,8 @@ static int gdm_tty_recv_complete(void *data,
if (!GDM_TTY_READY(gdm)) {
if (complete == RECV_PACKET_PROCESS_COMPLETE)
- gdm_tty_recv(gdm, gdm_tty_recv_complete);
+ gdm->tty_dev->recv_func(gdm->tty_dev->priv_dev,
+ gdm_tty_recv_complete);
return TO_HOST_PORT_CLOSE;
}
@@ -160,7 +154,8 @@ static int gdm_tty_recv_complete(void *data,
}
if (complete == RECV_PACKET_PROCESS_COMPLETE)
- gdm_tty_recv(gdm, gdm_tty_recv_complete);
+ gdm->tty_dev->recv_func(gdm->tty_dev->priv_dev,
+ gdm_tty_recv_complete);
return 0;
}
@@ -191,13 +186,12 @@ static int gdm_tty_write(struct tty_struct *tty, const unsigned char *buf,
while (1) {
sending_len = min(MUX_TX_MAX_SIZE, remain);
- gdm_tty_send(gdm,
- (void *)(buf + sent_len),
- sending_len,
- gdm->index,
- gdm_tty_send_complete,
- gdm
- );
+ gdm->tty_dev->send_func(gdm->tty_dev->priv_dev,
+ (void *)(buf + sent_len),
+ sending_len,
+ gdm->index,
+ gdm_tty_send_complete,
+ gdm);
sent_len += sending_len;
remain -= sending_len;
if (remain <= 0)
@@ -256,7 +250,8 @@ int register_lte_tty_device(struct tty_dev *tty_dev, struct device *device)
}
for (i = 0; i < MAX_ISSUE_NUM; i++)
- gdm_tty_recv(gdm, gdm_tty_recv_complete);
+ gdm->tty_dev->recv_func(gdm->tty_dev->priv_dev,
+ gdm_tty_recv_complete);
return 0;
}
diff --git a/drivers/staging/gdm724x/gdm_usb.c b/drivers/staging/gdm724x/gdm_usb.c
index 87cd1f827455..c95bad4a8615 100644
--- a/drivers/staging/gdm724x/gdm_usb.c
+++ b/drivers/staging/gdm724x/gdm_usb.c
@@ -72,8 +72,8 @@ static int request_mac_address(struct lte_udev *udev)
int actual;
int ret = -1;
- hci->cmd_evt = gdm_cpu_to_dev16(&udev->gdm_ed, LTE_GET_INFORMATION);
- hci->len = gdm_cpu_to_dev16(&udev->gdm_ed, 1);
+ hci->cmd_evt = gdm_cpu_to_dev16(udev->gdm_ed, LTE_GET_INFORMATION);
+ hci->len = gdm_cpu_to_dev16(udev->gdm_ed, 1);
hci->data[0] = MAC_ADDRESS;
ret = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 2), buf, 5,
@@ -410,7 +410,7 @@ static void do_rx(struct work_struct *work)
phy_dev = r->cb_data;
udev = phy_dev->priv_dev;
hci = (struct hci_packet *)r->buf;
- cmd_evt = gdm_dev16_to_cpu(&udev->gdm_ed, hci->cmd_evt);
+ cmd_evt = gdm_dev16_to_cpu(udev->gdm_ed, hci->cmd_evt);
switch (cmd_evt) {
case LTE_GET_INFORMATION_RESULT:
@@ -604,7 +604,7 @@ static u32 packet_aggregation(struct lte_udev *udev, u8 *send_buf)
u16 num_packet = 0;
unsigned long flags;
- multi_sdu->cmd_evt = gdm_cpu_to_dev16(&udev->gdm_ed, LTE_TX_MULTI_SDU);
+ multi_sdu->cmd_evt = gdm_cpu_to_dev16(udev->gdm_ed, LTE_TX_MULTI_SDU);
while (num_packet < MAX_PACKET_IN_MULTI_SDU) {
spin_lock_irqsave(&tx->lock, flags);
@@ -635,8 +635,8 @@ static u32 packet_aggregation(struct lte_udev *udev, u8 *send_buf)
spin_unlock_irqrestore(&tx->lock, flags);
}
- multi_sdu->len = gdm_cpu_to_dev16(&udev->gdm_ed, send_len);
- multi_sdu->num_packet = gdm_cpu_to_dev16(&udev->gdm_ed, num_packet);
+ multi_sdu->len = gdm_cpu_to_dev16(udev->gdm_ed, send_len);
+ multi_sdu->num_packet = gdm_cpu_to_dev16(udev->gdm_ed, num_packet);
return send_len + offsetof(struct multi_sdu, data);
}
@@ -735,7 +735,7 @@ static int gdm_usb_sdu_send(void *priv_dev, void *data, int len,
}
sdu = (struct sdu *)t_sdu->buf;
- sdu->cmd_evt = gdm_cpu_to_dev16(&udev->gdm_ed, LTE_TX_SDU);
+ sdu->cmd_evt = gdm_cpu_to_dev16(udev->gdm_ed, LTE_TX_SDU);
if (nic_type == NIC_TYPE_ARP) {
send_len = len + SDU_PARAM_LEN;
memcpy(sdu->data, data, len);
@@ -745,10 +745,10 @@ static int gdm_usb_sdu_send(void *priv_dev, void *data, int len,
memcpy(sdu->data, data + ETH_HLEN, len - ETH_HLEN);
}
- sdu->len = gdm_cpu_to_dev16(&udev->gdm_ed, send_len);
- sdu->dft_eps_ID = gdm_cpu_to_dev32(&udev->gdm_ed, dft_eps_ID);
- sdu->bearer_ID = gdm_cpu_to_dev32(&udev->gdm_ed, eps_ID);
- sdu->nic_type = gdm_cpu_to_dev32(&udev->gdm_ed, nic_type);
+ sdu->len = gdm_cpu_to_dev16(udev->gdm_ed, send_len);
+ sdu->dft_eps_ID = gdm_cpu_to_dev32(udev->gdm_ed, dft_eps_ID);
+ sdu->bearer_ID = gdm_cpu_to_dev32(udev->gdm_ed, eps_ID);
+ sdu->nic_type = gdm_cpu_to_dev32(udev->gdm_ed, nic_type);
t_sdu->len = send_len + HCI_HEADER_SIZE;
t_sdu->callback = cb;
@@ -799,11 +799,11 @@ static int gdm_usb_hci_send(void *priv_dev, void *data, int len,
return 0;
}
-static struct gdm_endian *gdm_usb_get_endian(void *priv_dev)
+static u8 gdm_usb_get_endian(void *priv_dev)
{
struct lte_udev *udev = priv_dev;
- return &udev->gdm_ed;
+ return udev->gdm_ed;
}
static int gdm_usb_probe(struct usb_interface *intf,
@@ -859,9 +859,9 @@ static int gdm_usb_probe(struct usb_interface *intf,
* defaults to little endian
*/
if (idProduct == PID_GDM7243)
- gdm_set_endian(&udev->gdm_ed, ENDIANNESS_BIG);
+ udev->gdm_ed = ENDIANNESS_BIG;
else
- gdm_set_endian(&udev->gdm_ed, ENDIANNESS_LITTLE);
+ udev->gdm_ed = ENDIANNESS_LITTLE;
ret = request_mac_address(udev);
if (ret < 0) {
diff --git a/drivers/staging/gdm724x/gdm_usb.h b/drivers/staging/gdm724x/gdm_usb.h
index ffb3d995097d..701038685e23 100644
--- a/drivers/staging/gdm724x/gdm_usb.h
+++ b/drivers/staging/gdm724x/gdm_usb.h
@@ -93,11 +93,11 @@ struct rx_cxt {
struct lte_udev {
struct usb_device *usbdev;
- struct gdm_endian gdm_ed;
struct tx_cxt tx;
struct rx_cxt rx;
struct delayed_work work_tx;
struct delayed_work work_rx;
+ u8 gdm_ed;
u8 send_complete;
u8 tx_stop;
struct usb_interface *intf;
diff --git a/drivers/staging/iio/accel/adis16201.c b/drivers/staging/iio/accel/adis16201.c
index 2ebd27536216..0fae8aaf1cf4 100644
--- a/drivers/staging/iio/accel/adis16201.c
+++ b/drivers/staging/iio/accel/adis16201.c
@@ -7,13 +7,13 @@
*/
#include <linux/delay.h>
-#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
-#include <linux/spi/spi.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/spi/spi.h>
#include <linux/sysfs.h>
-#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -232,6 +232,7 @@ static int adis16201_read_raw(struct iio_dev *indio_dev,
*val = val16;
return IIO_VAL_INT;
}
+
return -EINVAL;
}
@@ -262,6 +263,7 @@ static int adis16201_write_raw(struct iio_dev *indio_dev,
addr = adis16201_addresses[chan->scan_index];
return adis_write_reg_16(st, addr, val16);
}
+
return -EINVAL;
}
@@ -336,6 +338,7 @@ static int adis16201_probe(struct spi_device *spi)
ret = adis_init(st, indio_dev, spi, &adis16201_data);
if (ret)
return ret;
+
ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
if (ret)
return ret;
@@ -348,6 +351,7 @@ static int adis16201_probe(struct spi_device *spi)
ret = iio_device_register(indio_dev);
if (ret < 0)
goto error_cleanup_buffer_trigger;
+
return 0;
error_cleanup_buffer_trigger:
diff --git a/drivers/staging/iio/accel/adis16209.c b/drivers/staging/iio/accel/adis16209.c
index 7fcef9a2590a..72a18cfe81ee 100644
--- a/drivers/staging/iio/accel/adis16209.c
+++ b/drivers/staging/iio/accel/adis16209.c
@@ -9,147 +9,82 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
-#include <linux/list.h>
-#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
-#define ADIS16209_STARTUP_DELAY 220 /* ms */
-
-/* Flash memory write count */
-#define ADIS16209_FLASH_CNT 0x00
-
-/* Output, power supply */
-#define ADIS16209_SUPPLY_OUT 0x02
-
-/* Output, x-axis accelerometer */
-#define ADIS16209_XACCL_OUT 0x04
-
-/* Output, y-axis accelerometer */
-#define ADIS16209_YACCL_OUT 0x06
+#define ADIS16209_STARTUP_DELAY_MS 220
+#define ADIS16209_FLASH_CNT_REG 0x00
+/* Data Output Register Definitions */
+#define ADIS16209_SUPPLY_OUT_REG 0x02
+#define ADIS16209_XACCL_OUT_REG 0x04
+#define ADIS16209_YACCL_OUT_REG 0x06
/* Output, auxiliary ADC input */
-#define ADIS16209_AUX_ADC 0x08
-
+#define ADIS16209_AUX_ADC_REG 0x08
/* Output, temperature */
-#define ADIS16209_TEMP_OUT 0x0A
-
-/* Output, x-axis inclination */
-#define ADIS16209_XINCL_OUT 0x0C
-
-/* Output, y-axis inclination */
-#define ADIS16209_YINCL_OUT 0x0E
-
+#define ADIS16209_TEMP_OUT_REG 0x0A
+/* Output, +/- 90 degrees X-axis inclination */
+#define ADIS16209_XINCL_OUT_REG 0x0C
+#define ADIS16209_YINCL_OUT_REG 0x0E
/* Output, +/-180 vertical rotational position */
-#define ADIS16209_ROT_OUT 0x10
-
-/* Calibration, x-axis acceleration offset null */
-#define ADIS16209_XACCL_NULL 0x12
-
-/* Calibration, y-axis acceleration offset null */
-#define ADIS16209_YACCL_NULL 0x14
-
-/* Calibration, x-axis inclination offset null */
-#define ADIS16209_XINCL_NULL 0x16
-
-/* Calibration, y-axis inclination offset null */
-#define ADIS16209_YINCL_NULL 0x18
-
-/* Calibration, vertical rotation offset null */
-#define ADIS16209_ROT_NULL 0x1A
-
-/* Alarm 1 amplitude threshold */
-#define ADIS16209_ALM_MAG1 0x20
-
-/* Alarm 2 amplitude threshold */
-#define ADIS16209_ALM_MAG2 0x22
-
-/* Alarm 1, sample period */
-#define ADIS16209_ALM_SMPL1 0x24
-
-/* Alarm 2, sample period */
-#define ADIS16209_ALM_SMPL2 0x26
-
-/* Alarm control */
-#define ADIS16209_ALM_CTRL 0x28
-
-/* Auxiliary DAC data */
-#define ADIS16209_AUX_DAC 0x30
-
-/* General-purpose digital input/output control */
-#define ADIS16209_GPIO_CTRL 0x32
-
-/* Miscellaneous control */
-#define ADIS16209_MSC_CTRL 0x34
-
-/* Internal sample period (rate) control */
-#define ADIS16209_SMPL_PRD 0x36
-
-/* Operation, filter configuration */
-#define ADIS16209_AVG_CNT 0x38
-
-/* Operation, sleep mode control */
-#define ADIS16209_SLP_CNT 0x3A
-
-/* Diagnostics, system status register */
-#define ADIS16209_DIAG_STAT 0x3C
-
-/* Operation, system command register */
-#define ADIS16209_GLOB_CMD 0x3E
-
-/* MSC_CTRL */
-
-/* Self-test at power-on: 1 = disabled, 0 = enabled */
-#define ADIS16209_MSC_CTRL_PWRUP_SELF_TEST BIT(10)
-
-/* Self-test enable */
-#define ADIS16209_MSC_CTRL_SELF_TEST_EN BIT(8)
-
-/* Data-ready enable: 1 = enabled, 0 = disabled */
-#define ADIS16209_MSC_CTRL_DATA_RDY_EN BIT(2)
+#define ADIS16209_ROT_OUT_REG 0x10
+/*
+ * Calibration Register Definitions.
+ * Acceleration, inclination or rotation offset null.
+ */
+#define ADIS16209_XACCL_NULL_REG 0x12
+#define ADIS16209_YACCL_NULL_REG 0x14
+#define ADIS16209_XINCL_NULL_REG 0x16
+#define ADIS16209_YINCL_NULL_REG 0x18
+#define ADIS16209_ROT_NULL_REG 0x1A
+
+/* Alarm Register Definitions */
+#define ADIS16209_ALM_MAG1_REG 0x20
+#define ADIS16209_ALM_MAG2_REG 0x22
+#define ADIS16209_ALM_SMPL1_REG 0x24
+#define ADIS16209_ALM_SMPL2_REG 0x26
+#define ADIS16209_ALM_CTRL_REG 0x28
+
+#define ADIS16209_AUX_DAC_REG 0x30
+#define ADIS16209_GPIO_CTRL_REG 0x32
+#define ADIS16209_SMPL_PRD_REG 0x36
+#define ADIS16209_AVG_CNT_REG 0x38
+#define ADIS16209_SLP_CNT_REG 0x3A
+
+#define ADIS16209_MSC_CTRL_REG 0x34
+#define ADIS16209_MSC_CTRL_PWRUP_SELF_TEST BIT(10)
+#define ADIS16209_MSC_CTRL_SELF_TEST_EN BIT(8)
+#define ADIS16209_MSC_CTRL_DATA_RDY_EN BIT(2)
/* Data-ready polarity: 1 = active high, 0 = active low */
-#define ADIS16209_MSC_CTRL_ACTIVE_HIGH BIT(1)
-
-/* Data-ready line selection: 1 = DIO2, 0 = DIO1 */
-#define ADIS16209_MSC_CTRL_DATA_RDY_DIO2 BIT(0)
-
-/* DIAG_STAT */
-
-/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
-#define ADIS16209_DIAG_STAT_ALARM2 BIT(9)
-
-/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
-#define ADIS16209_DIAG_STAT_ALARM1 BIT(8)
-
-/* Self-test diagnostic error flag: 1 = error condition, 0 = normal operation */
-#define ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT 5
-
-/* SPI communications failure */
-#define ADIS16209_DIAG_STAT_SPI_FAIL_BIT 3
-
-/* Flash update failure */
-#define ADIS16209_DIAG_STAT_FLASH_UPT_BIT 2
-
+#define ADIS16209_MSC_CTRL_ACTIVE_HIGH BIT(1)
+#define ADIS16209_MSC_CTRL_DATA_RDY_DIO2 BIT(0)
+
+#define ADIS16209_STAT_REG 0x3C
+#define ADIS16209_STAT_ALARM2 BIT(9)
+#define ADIS16209_STAT_ALARM1 BIT(8)
+#define ADIS16209_STAT_SELFTEST_FAIL_BIT 5
+#define ADIS16209_STAT_SPI_FAIL_BIT 3
+#define ADIS16209_STAT_FLASH_UPT_FAIL_BIT 2
/* Power supply above 3.625 V */
-#define ADIS16209_DIAG_STAT_POWER_HIGH_BIT 1
-
+#define ADIS16209_STAT_POWER_HIGH_BIT 1
/* Power supply below 3.15 V */
-#define ADIS16209_DIAG_STAT_POWER_LOW_BIT 0
+#define ADIS16209_STAT_POWER_LOW_BIT 0
-/* GLOB_CMD */
+#define ADIS16209_CMD_REG 0x3E
+#define ADIS16209_CMD_SW_RESET BIT(7)
+#define ADIS16209_CMD_CLEAR_STAT BIT(4)
+#define ADIS16209_CMD_FACTORY_CAL BIT(1)
-#define ADIS16209_GLOB_CMD_SW_RESET BIT(7)
-#define ADIS16209_GLOB_CMD_CLEAR_STAT BIT(4)
-#define ADIS16209_GLOB_CMD_FACTORY_CAL BIT(1)
-
-#define ADIS16209_ERROR_ACTIVE BIT(14)
+#define ADIS16209_ERROR_ACTIVE BIT(14)
enum adis16209_scan {
ADIS16209_SCAN_SUPPLY,
@@ -165,10 +100,10 @@ enum adis16209_scan {
static const u8 adis16209_addresses[8][1] = {
[ADIS16209_SCAN_SUPPLY] = { },
[ADIS16209_SCAN_AUX_ADC] = { },
- [ADIS16209_SCAN_ACC_X] = { ADIS16209_XACCL_NULL },
- [ADIS16209_SCAN_ACC_Y] = { ADIS16209_YACCL_NULL },
- [ADIS16209_SCAN_INCLI_X] = { ADIS16209_XINCL_NULL },
- [ADIS16209_SCAN_INCLI_Y] = { ADIS16209_YINCL_NULL },
+ [ADIS16209_SCAN_ACC_X] = { ADIS16209_XACCL_NULL_REG },
+ [ADIS16209_SCAN_ACC_Y] = { ADIS16209_YACCL_NULL_REG },
+ [ADIS16209_SCAN_INCLI_X] = { ADIS16209_XINCL_NULL_REG },
+ [ADIS16209_SCAN_INCLI_Y] = { ADIS16209_YINCL_NULL_REG },
[ADIS16209_SCAN_ROT] = { },
[ADIS16209_SCAN_TEMP] = { },
};
@@ -220,30 +155,50 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
switch (chan->type) {
case IIO_VOLTAGE:
*val = 0;
- if (chan->channel == 0)
+ switch (chan->channel) {
+ case 0:
*val2 = 305180; /* 0.30518 mV */
- else
+ break;
+ case 1:
*val2 = 610500; /* 0.6105 mV */
+ break;
+ default:
+ return -EINVAL;
+ }
return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP:
- *val = -470; /* -0.47 C */
+ *val = -470;
*val2 = 0;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_ACCEL:
+ /*
+ * IIO base unit for sensitivity of accelerometer
+ * is milli g.
+ * 1 LSB represents 0.244 mg.
+ */
*val = 0;
- *val2 = IIO_G_TO_M_S_2(244140); /* 0.244140 mg */
+ *val2 = IIO_G_TO_M_S_2(244140);
return IIO_VAL_INT_PLUS_NANO;
case IIO_INCLI:
case IIO_ROT:
+ /*
+ * IIO base units for rotation are degrees.
+ * 1 LSB represents 0.025 milli degrees.
+ */
*val = 0;
- *val2 = 25000; /* 0.025 degree */
+ *val2 = 25000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
break;
case IIO_CHAN_INFO_OFFSET:
- *val = 25000 / -470 - 0x4FE; /* 25 C = 0x4FE */
+ /*
+ * The raw ADC value is 0x4FE when the temperature
+ * is 25 degrees and the scale factor per milli
+ * degree celcius is -470.
+ */
+ *val = 25000 / -470 - 0x4FE;
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS:
switch (chan->type) {
@@ -257,27 +212,27 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
ret = adis_read_reg_16(st, addr, &val16);
if (ret)
return ret;
- val16 &= (1 << bits) - 1;
- val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
- *val = val16;
+
+ *val = sign_extend32(val16, bits - 1);
return IIO_VAL_INT;
}
return -EINVAL;
}
static const struct iio_chan_spec adis16209_channels[] = {
- ADIS_SUPPLY_CHAN(ADIS16209_SUPPLY_OUT, ADIS16209_SCAN_SUPPLY, 0, 14),
- ADIS_TEMP_CHAN(ADIS16209_TEMP_OUT, ADIS16209_SCAN_TEMP, 0, 12),
- ADIS_ACCEL_CHAN(X, ADIS16209_XACCL_OUT, ADIS16209_SCAN_ACC_X,
+ ADIS_SUPPLY_CHAN(ADIS16209_SUPPLY_OUT_REG, ADIS16209_SCAN_SUPPLY,
+ 0, 14),
+ ADIS_TEMP_CHAN(ADIS16209_TEMP_OUT_REG, ADIS16209_SCAN_TEMP, 0, 12),
+ ADIS_ACCEL_CHAN(X, ADIS16209_XACCL_OUT_REG, ADIS16209_SCAN_ACC_X,
BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
- ADIS_ACCEL_CHAN(Y, ADIS16209_YACCL_OUT, ADIS16209_SCAN_ACC_Y,
+ ADIS_ACCEL_CHAN(Y, ADIS16209_YACCL_OUT_REG, ADIS16209_SCAN_ACC_Y,
BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
- ADIS_AUX_ADC_CHAN(ADIS16209_AUX_ADC, ADIS16209_SCAN_AUX_ADC, 0, 12),
- ADIS_INCLI_CHAN(X, ADIS16209_XINCL_OUT, ADIS16209_SCAN_INCLI_X,
+ ADIS_AUX_ADC_CHAN(ADIS16209_AUX_ADC_REG, ADIS16209_SCAN_AUX_ADC, 0, 12),
+ ADIS_INCLI_CHAN(X, ADIS16209_XINCL_OUT_REG, ADIS16209_SCAN_INCLI_X,
0, 0, 14),
- ADIS_INCLI_CHAN(Y, ADIS16209_YINCL_OUT, ADIS16209_SCAN_INCLI_Y,
+ ADIS_INCLI_CHAN(Y, ADIS16209_YINCL_OUT_REG, ADIS16209_SCAN_INCLI_Y,
0, 0, 14),
- ADIS_ROT_CHAN(X, ADIS16209_ROT_OUT, ADIS16209_SCAN_ROT, 0, 0, 14),
+ ADIS_ROT_CHAN(X, ADIS16209_ROT_OUT_REG, ADIS16209_SCAN_ROT, 0, 0, 14),
IIO_CHAN_SOFT_TIMESTAMP(8)
};
@@ -288,29 +243,29 @@ static const struct iio_info adis16209_info = {
};
static const char * const adis16209_status_error_msgs[] = {
- [ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT] = "Self test failure",
- [ADIS16209_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
- [ADIS16209_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
- [ADIS16209_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
- [ADIS16209_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
+ [ADIS16209_STAT_SELFTEST_FAIL_BIT] = "Self test failure",
+ [ADIS16209_STAT_SPI_FAIL_BIT] = "SPI failure",
+ [ADIS16209_STAT_FLASH_UPT_FAIL_BIT] = "Flash update failed",
+ [ADIS16209_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
+ [ADIS16209_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
};
static const struct adis_data adis16209_data = {
.read_delay = 30,
- .msc_ctrl_reg = ADIS16209_MSC_CTRL,
- .glob_cmd_reg = ADIS16209_GLOB_CMD,
- .diag_stat_reg = ADIS16209_DIAG_STAT,
+ .msc_ctrl_reg = ADIS16209_MSC_CTRL_REG,
+ .glob_cmd_reg = ADIS16209_CMD_REG,
+ .diag_stat_reg = ADIS16209_STAT_REG,
.self_test_mask = ADIS16209_MSC_CTRL_SELF_TEST_EN,
.self_test_no_autoclear = true,
- .startup_delay = ADIS16209_STARTUP_DELAY,
+ .startup_delay = ADIS16209_STARTUP_DELAY_MS,
.status_error_msgs = adis16209_status_error_msgs,
- .status_error_mask = BIT(ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT) |
- BIT(ADIS16209_DIAG_STAT_SPI_FAIL_BIT) |
- BIT(ADIS16209_DIAG_STAT_FLASH_UPT_BIT) |
- BIT(ADIS16209_DIAG_STAT_POWER_HIGH_BIT) |
- BIT(ADIS16209_DIAG_STAT_POWER_LOW_BIT),
+ .status_error_mask = BIT(ADIS16209_STAT_SELFTEST_FAIL_BIT) |
+ BIT(ADIS16209_STAT_SPI_FAIL_BIT) |
+ BIT(ADIS16209_STAT_FLASH_UPT_FAIL_BIT) |
+ BIT(ADIS16209_STAT_POWER_HIGH_BIT) |
+ BIT(ADIS16209_STAT_POWER_LOW_BIT),
};
static int adis16209_probe(struct spi_device *spi)
@@ -319,12 +274,10 @@ static int adis16209_probe(struct spi_device *spi)
struct adis *st;
struct iio_dev *indio_dev;
- /* setup the industrialio driver allocated elements */
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
- /* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
indio_dev->name = spi->dev.driver->name;
@@ -341,7 +294,6 @@ static int adis16209_probe(struct spi_device *spi)
if (ret)
return ret;
- /* Get the device into a sane initial state */
ret = adis_initial_startup(st);
if (ret)
goto error_cleanup_buffer_trigger;
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index 425e8b82533b..df0499fc4802 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -301,8 +301,12 @@ static int ad7192_setup(struct ad7192_state *st,
if (pdata->unipolar_en)
st->conf |= AD7192_CONF_UNIPOLAR;
- if (pdata->burnout_curr_en)
+ if (pdata->burnout_curr_en && pdata->buf_en && !pdata->chop_en) {
st->conf |= AD7192_CONF_BURN;
+ } else if (pdata->burnout_curr_en) {
+ dev_warn(&st->sd.spi->dev,
+ "Can't enable burnout currents: see CHOP or buffer\n");
+ }
ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
if (ret)
diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c
index bfe180a475ee..bf76a8620bdb 100644
--- a/drivers/staging/iio/adc/ad7816.c
+++ b/drivers/staging/iio/adc/ad7816.c
@@ -254,7 +254,7 @@ static const struct attribute_group ad7816_attribute_group = {
static irqreturn_t ad7816_event_handler(int irq, void *private)
{
iio_push_event(private, IIO_EVENT_CODE_AD7816_OTI,
- iio_get_time_ns((struct iio_dev *)private));
+ iio_get_time_ns(private));
return IRQ_HANDLED;
}
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index 2d33632c00e8..3f22d1088713 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -2079,9 +2079,8 @@ static int adt7316_enable(struct device *dev)
return _adt7316_store_enabled(chip, 1);
}
-
-SIMPLE_DEV_PM_OPS(adt7316_pm_ops, adt7316_disable, adt7316_enable);
EXPORT_SYMBOL_GPL(adt7316_pm_ops);
+SIMPLE_DEV_PM_OPS(adt7316_pm_ops, adt7316_disable, adt7316_enable);
#endif
static const struct iio_info adt7316_info = {
diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c
index 2fe916c48848..d16084d7068c 100644
--- a/drivers/staging/iio/cdc/ad7150.c
+++ b/drivers/staging/iio/cdc/ad7150.c
@@ -124,8 +124,9 @@ static int ad7150_read_raw(struct iio_dev *indio_dev,
}
static int ad7150_read_event_config(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, enum iio_event_type type,
- enum iio_event_direction dir)
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
{
int ret;
u8 threshtype;
diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c
index 19dc896603a1..25f51db05d2d 100644
--- a/drivers/staging/iio/cdc/ad7152.c
+++ b/drivers/staging/iio/cdc/ad7152.c
@@ -426,8 +426,8 @@ out:
}
static int ad7152_write_raw_get_fmt(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- long mask)
+ struct iio_chan_spec const *chan,
+ long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
@@ -493,7 +493,7 @@ static const struct iio_chan_spec ad7152_channels[] = {
*/
static int ad7152_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
int ret = 0;
struct ad7152_chip_info *chip;
diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c
index c4a864725376..4882dbc81c53 100644
--- a/drivers/staging/iio/cdc/ad7746.c
+++ b/drivers/staging/iio/cdc/ad7746.c
@@ -217,7 +217,7 @@ static const unsigned char ad7746_cap_filter_rate_table[][2] = {
};
static int ad7746_select_channel(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan)
+ struct iio_chan_spec const *chan)
{
struct ad7746_chip_info *chip = iio_priv(indio_dev);
int ret, delay, idx;
@@ -487,13 +487,13 @@ static int ad7746_write_raw(struct iio_dev *indio_dev,
AD7746_CAPDAC_DACP(val) | AD7746_CAPDAC_DACEN : 0;
ret = i2c_smbus_write_byte_data(chip->client,
- AD7746_REG_CAPDACA,
- chip->capdac[chan->channel][0]);
+ AD7746_REG_CAPDACA,
+ chip->capdac[chan->channel][0]);
if (ret < 0)
goto out;
ret = i2c_smbus_write_byte_data(chip->client,
- AD7746_REG_CAPDACB,
- chip->capdac[chan->channel][1]);
+ AD7746_REG_CAPDACB,
+ chip->capdac[chan->channel][1]);
if (ret < 0)
goto out;
@@ -675,7 +675,7 @@ static const struct iio_info ad7746_info = {
*/
static int ad7746_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
struct ad7746_platform_data *pdata = client->dev.platform_data;
struct ad7746_chip_info *chip;
diff --git a/drivers/staging/iio/light/tsl2x7x.c b/drivers/staging/iio/light/tsl2x7x.c
index 126e11530ce0..82681300e106 100644
--- a/drivers/staging/iio/light/tsl2x7x.c
+++ b/drivers/staging/iio/light/tsl2x7x.c
@@ -109,15 +109,15 @@
#define TSL2X7X_CNTL_INTPROXPON_ENBL 0x2F
/*Prox diode to use */
-#define TSL2X7X_DIODE0 0x10
-#define TSL2X7X_DIODE1 0x20
-#define TSL2X7X_DIODE_BOTH 0x30
+#define TSL2X7X_DIODE0 0x01
+#define TSL2X7X_DIODE1 0x02
+#define TSL2X7X_DIODE_BOTH 0x03
/* LED Power */
#define TSL2X7X_100_mA 0x00
-#define TSL2X7X_50_mA 0x40
-#define TSL2X7X_25_mA 0x80
-#define TSL2X7X_13_mA 0xD0
+#define TSL2X7X_50_mA 0x01
+#define TSL2X7X_25_mA 0x02
+#define TSL2X7X_13_mA 0x03
#define TSL2X7X_MAX_TIMER_CNT 0xFF
#define TSL2X7X_MIN_ITIME 3
@@ -228,7 +228,7 @@ static const struct tsl2x7x_settings tsl2x7x_default_settings = {
.als_time = 219, /* 101 ms */
.als_gain = 0,
.prx_time = 254, /* 5.4 ms */
- .prox_gain = 1,
+ .prox_gain = 0,
.wait_time = 245,
.prox_config = 0,
.als_gain_trim = 1000,
@@ -240,7 +240,9 @@ static const struct tsl2x7x_settings tsl2x7x_default_settings = {
.prox_thres_low = 0,
.prox_thres_high = 512,
.prox_max_samples_cal = 30,
- .prox_pulse_count = 8
+ .prox_pulse_count = 8,
+ .prox_diode = TSL2X7X_DIODE1,
+ .prox_power = TSL2X7X_100_mA
};
static const s16 tsl2x7x_als_gain[] = {
@@ -279,6 +281,49 @@ static const u8 device_channel_config[] = {
ALSPRX2
};
+static int tsl2x7x_clear_interrupts(struct tsl2X7X_chip *chip, int reg)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | reg);
+ if (ret < 0)
+ dev_err(&chip->client->dev,
+ "%s: failed to clear interrupt status %x: %d\n",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int tsl2x7x_read_status(struct tsl2X7X_chip *chip)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_STATUS);
+ if (ret < 0)
+ dev_err(&chip->client->dev,
+ "%s: failed to read STATUS register: %d\n", __func__,
+ ret);
+
+ return ret;
+}
+
+static int tsl2x7x_write_control_reg(struct tsl2X7X_chip *chip, u8 data)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CNTRL, data);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed to write to control register %x: %d\n",
+ __func__, data, ret);
+ }
+
+ return ret;
+}
+
/**
* tsl2x7x_get_lux() - Reads and calculates current lux value.
* @indio_dev: pointer to IIO device
@@ -307,8 +352,7 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
u32 ch0lux = 0;
u32 ch1lux = 0;
- if (mutex_trylock(&chip->als_mutex) == 0)
- return chip->als_cur_info.lux; /* busy, so return LAST VALUE */
+ mutex_lock(&chip->als_mutex);
if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) {
/* device is not enabled */
@@ -318,13 +362,10 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
goto out_unlock;
}
- ret = i2c_smbus_read_byte_data(chip->client,
- TSL2X7X_CMD_REG | TSL2X7X_STATUS);
- if (ret < 0) {
- dev_err(&chip->client->dev,
- "%s: Failed to read STATUS Reg\n", __func__);
+ ret = tsl2x7x_read_status(chip);
+ if (ret < 0)
goto out_unlock;
- }
+
/* is data new & valid */
if (!(ret & TSL2X7X_STA_ADC_VALID)) {
dev_err(&chip->client->dev,
@@ -346,16 +387,9 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
buf[i] = ret;
}
- /* clear any existing interrupt status */
- ret = i2c_smbus_write_byte(chip->client,
- TSL2X7X_CMD_REG |
- TSL2X7X_CMD_SPL_FN |
- TSL2X7X_CMD_ALS_INT_CLR);
- if (ret < 0) {
- dev_err(&chip->client->dev,
- "i2c_write_command failed - err = %d\n", ret);
- goto out_unlock; /* have no data, so return failure */
- }
+ ret = tsl2x7x_clear_interrupts(chip, TSL2X7X_CMD_ALS_INT_CLR);
+ if (ret < 0)
+ goto out_unlock;
/* extract ALS/lux data */
ch0 = le16_to_cpup((const __le16 *)&buf[0]);
@@ -445,18 +479,11 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
u8 chdata[2];
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
- if (mutex_trylock(&chip->prox_mutex) == 0) {
- dev_err(&chip->client->dev,
- "%s: Can't get prox mutex\n", __func__);
- return -EBUSY;
- }
+ mutex_lock(&chip->prox_mutex);
- ret = i2c_smbus_read_byte_data(chip->client,
- TSL2X7X_CMD_REG | TSL2X7X_STATUS);
- if (ret < 0) {
- dev_err(&chip->client->dev, "i2c err=%d\n", ret);
+ ret = tsl2x7x_read_status(chip);
+ if (ret < 0)
goto prox_poll_err;
- }
switch (chip->id) {
case tsl2571:
@@ -464,16 +491,20 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
case tmd2671:
case tsl2771:
case tmd2771:
- if (!(ret & TSL2X7X_STA_ADC_VALID))
+ if (!(ret & TSL2X7X_STA_ADC_VALID)) {
+ ret = -EINVAL;
goto prox_poll_err;
+ }
break;
case tsl2572:
case tsl2672:
case tmd2672:
case tsl2772:
case tmd2772:
- if (!(ret & TSL2X7X_STA_PRX_VALID))
+ if (!(ret & TSL2X7X_STA_PRX_VALID)) {
+ ret = -EINVAL;
goto prox_poll_err;
+ }
break;
}
@@ -487,14 +518,13 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
chdata[i] = ret;
}
- chip->prox_data =
- le16_to_cpup((const __le16 *)&chdata[0]);
+ chip->prox_data = le16_to_cpup((const __le16 *)&chdata[0]);
+ ret = chip->prox_data;
prox_poll_err:
-
mutex_unlock(&chip->prox_mutex);
- return chip->prox_data;
+ return ret;
}
/**
@@ -582,15 +612,11 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
int i;
int ret = 0;
u8 *dev_reg;
- u8 utmp;
int als_count;
int als_time;
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
u8 reg_val = 0;
- if (chip->pdata && chip->pdata->power_on)
- chip->pdata->power_on(indio_dev);
-
/* Non calculated parameters */
chip->tsl2x7x_config[TSL2X7X_PRX_TIME] = chip->settings.prx_time;
chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] = chip->settings.wait_time;
@@ -635,9 +661,10 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
/* Set the gain based on tsl2x7x_settings struct */
chip->tsl2x7x_config[TSL2X7X_GAIN] =
- chip->settings.als_gain |
- (TSL2X7X_100_mA | TSL2X7X_DIODE1) |
- (chip->settings.prox_gain << 2);
+ (chip->settings.als_gain & 0xFF) |
+ ((chip->settings.prox_gain & 0xFF) << 2) |
+ (chip->settings.prox_diode << 4) |
+ (chip->settings.prox_power << 6);
/* set chip struct re scaling and saturation */
chip->als_saturation = als_count * 922; /* 90% of full scale */
@@ -647,14 +674,9 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
* TSL2X7X Specific power-on / adc enable sequence
* Power on the device 1st.
*/
- utmp = TSL2X7X_CNTL_PWR_ON;
- ret = i2c_smbus_write_byte_data(chip->client,
- TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
- if (ret < 0) {
- dev_err(&chip->client->dev,
- "%s: failed on CNTRL reg.\n", __func__);
+ ret = tsl2x7x_write_control_reg(chip, TSL2X7X_CNTL_PWR_ON);
+ if (ret < 0)
return ret;
- }
/*
* Use the following shadow copy for our delay before enabling ADC.
@@ -679,16 +701,12 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
* NOW enable the ADC
* initialize the desired mode of operation
*/
- utmp = TSL2X7X_CNTL_PWR_ON |
- TSL2X7X_CNTL_ADC_ENBL |
- TSL2X7X_CNTL_PROX_DET_ENBL;
- ret = i2c_smbus_write_byte_data(chip->client,
- TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
- if (ret < 0) {
- dev_err(&chip->client->dev,
- "%s: failed on 2nd CTRL reg.\n", __func__);
+ ret = tsl2x7x_write_control_reg(chip,
+ TSL2X7X_CNTL_PWR_ON |
+ TSL2X7X_CNTL_ADC_ENBL |
+ TSL2X7X_CNTL_PROX_DET_ENBL);
+ if (ret < 0)
return ret;
- }
chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING;
@@ -701,25 +719,14 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL;
reg_val |= chip->settings.interrupts_en;
- ret = i2c_smbus_write_byte_data(chip->client,
- TSL2X7X_CMD_REG | TSL2X7X_CNTRL,
- reg_val);
+ ret = tsl2x7x_write_control_reg(chip, reg_val);
if (ret < 0)
- dev_err(&chip->client->dev,
- "%s: failed in tsl2x7x_IOCTL_INT_SET.\n",
- __func__);
+ return ret;
- /* Clear out any initial interrupts */
- ret = i2c_smbus_write_byte(chip->client,
- TSL2X7X_CMD_REG |
- TSL2X7X_CMD_SPL_FN |
- TSL2X7X_CMD_PROXALS_INT_CLR);
- if (ret < 0) {
- dev_err(&chip->client->dev,
- "%s: Failed to clear Int status\n",
- __func__);
- return ret;
- }
+ ret = tsl2x7x_clear_interrupts(chip,
+ TSL2X7X_CMD_PROXALS_INT_CLR);
+ if (ret < 0)
+ return ret;
}
return ret;
@@ -727,19 +734,11 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
static int tsl2x7x_chip_off(struct iio_dev *indio_dev)
{
- int ret;
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
/* turn device off */
chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
-
- ret = i2c_smbus_write_byte_data(chip->client,
- TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00);
-
- if (chip->pdata && chip->pdata->power_off)
- chip->pdata->power_off(chip->client);
-
- return ret;
+ return tsl2x7x_write_control_reg(chip, 0x00);
}
/**
@@ -777,7 +776,7 @@ unlock:
}
static void tsl2x7x_prox_calculate(int *data, int length,
- struct tsl2x7x_prox_stat *statP)
+ struct tsl2x7x_prox_stat *stat)
{
int i;
int sample_sum;
@@ -787,21 +786,21 @@ static void tsl2x7x_prox_calculate(int *data, int length,
length = 1;
sample_sum = 0;
- statP->min = INT_MAX;
- statP->max = INT_MIN;
+ stat->min = INT_MAX;
+ stat->max = INT_MIN;
for (i = 0; i < length; i++) {
sample_sum += data[i];
- statP->min = min(statP->min, data[i]);
- statP->max = max(statP->max, data[i]);
+ stat->min = min(stat->min, data[i]);
+ stat->max = max(stat->max, data[i]);
}
- statP->mean = sample_sum / length;
+ stat->mean = sample_sum / length;
sample_sum = 0;
for (i = 0; i < length; i++) {
- tmp = data[i] - statP->mean;
+ tmp = data[i] - stat->mean;
sample_sum += tmp * tmp;
}
- statP->stddev = int_sqrt((long)sample_sum / length);
+ stat->stddev = int_sqrt((long)sample_sum / length);
}
/**
@@ -811,12 +810,12 @@ static void tsl2x7x_prox_calculate(int *data, int length,
* Calculates a standard deviation based on the samples,
* and sets the threshold accordingly.
*/
-static void tsl2x7x_prox_cal(struct iio_dev *indio_dev)
+static int tsl2x7x_prox_cal(struct iio_dev *indio_dev)
{
int prox_history[MAX_SAMPLES_CAL + 1];
- int i;
+ int i, ret;
struct tsl2x7x_prox_stat prox_stat_data[2];
- struct tsl2x7x_prox_stat *calP;
+ struct tsl2x7x_prox_stat *cal;
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
u8 tmp_irq_settings;
u8 current_state = chip->tsl2x7x_chip_status;
@@ -829,40 +828,53 @@ static void tsl2x7x_prox_cal(struct iio_dev *indio_dev)
}
/* have to stop to change settings */
- tsl2x7x_chip_off(indio_dev);
+ ret = tsl2x7x_chip_off(indio_dev);
+ if (ret < 0)
+ return ret;
/* Enable proximity detection save just in case prox not wanted yet*/
tmp_irq_settings = chip->settings.interrupts_en;
chip->settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL;
/*turn on device if not already on*/
- tsl2x7x_chip_on(indio_dev);
+ ret = tsl2x7x_chip_on(indio_dev);
+ if (ret < 0)
+ return ret;
/*gather the samples*/
for (i = 0; i < chip->settings.prox_max_samples_cal; i++) {
usleep_range(15000, 17500);
- tsl2x7x_get_prox(indio_dev);
+ ret = tsl2x7x_get_prox(indio_dev);
+ if (ret < 0)
+ return ret;
prox_history[i] = chip->prox_data;
dev_info(&chip->client->dev, "2 i=%d prox data= %d\n",
i, chip->prox_data);
}
- tsl2x7x_chip_off(indio_dev);
- calP = &prox_stat_data[PROX_STAT_CAL];
+ ret = tsl2x7x_chip_off(indio_dev);
+ if (ret < 0)
+ return ret;
+ cal = &prox_stat_data[PROX_STAT_CAL];
tsl2x7x_prox_calculate(prox_history,
- chip->settings.prox_max_samples_cal, calP);
- chip->settings.prox_thres_high = (calP->max << 1) - calP->mean;
+ chip->settings.prox_max_samples_cal, cal);
+ chip->settings.prox_thres_high = (cal->max << 1) - cal->mean;
dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n",
- calP->min, calP->mean, calP->max);
+ cal->min, cal->mean, cal->max);
dev_info(&chip->client->dev,
"%s proximity threshold set to %d\n",
chip->client->name, chip->settings.prox_thres_high);
/* back to the way they were */
chip->settings.interrupts_en = tmp_irq_settings;
- if (current_state == TSL2X7X_CHIP_WORKING)
- tsl2x7x_chip_on(indio_dev);
+ if (current_state == TSL2X7X_CHIP_WORKING) {
+ ret = tsl2x7x_chip_on(indio_dev);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
}
static ssize_t
@@ -931,8 +943,11 @@ static ssize_t in_illuminance0_calibrate_store(struct device *dev,
if (strtobool(buf, &value))
return -EINVAL;
- if (value)
- tsl2x7x_als_calibrate(indio_dev);
+ if (value) {
+ ret = tsl2x7x_als_calibrate(indio_dev);
+ if (ret < 0)
+ return ret;
+ }
ret = tsl2x7x_invoke_change(indio_dev);
if (ret < 0)
@@ -997,8 +1012,11 @@ static ssize_t in_illuminance0_lux_table_store(struct device *dev,
return -EINVAL;
}
- if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING)
- tsl2x7x_chip_off(indio_dev);
+ if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
+ ret = tsl2x7x_chip_off(indio_dev);
+ if (ret < 0)
+ return ret;
+ }
/* Zero out the table */
memset(chip->tsl2x7x_device_lux, 0, sizeof(chip->tsl2x7x_device_lux));
@@ -1022,8 +1040,11 @@ static ssize_t in_proximity0_calibrate_store(struct device *dev,
if (strtobool(buf, &value))
return -EINVAL;
- if (value)
- tsl2x7x_prox_cal(indio_dev);
+ if (value) {
+ ret = tsl2x7x_prox_cal(indio_dev);
+ if (ret < 0)
+ return ret;
+ }
ret = tsl2x7x_invoke_change(indio_dev);
if (ret < 0)
@@ -1402,13 +1423,13 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
s64 timestamp = iio_get_time_ns(indio_dev);
int ret;
- u8 value;
- value = i2c_smbus_read_byte_data(chip->client,
- TSL2X7X_CMD_REG | TSL2X7X_STATUS);
+ ret = tsl2x7x_read_status(chip);
+ if (ret < 0)
+ return ret;
/* What type of interrupt do we need to process */
- if (value & TSL2X7X_STA_PRX_INTR) {
+ if (ret & TSL2X7X_STA_PRX_INTR) {
tsl2x7x_get_prox(indio_dev); /* freshen data for ABI */
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY,
@@ -1418,7 +1439,7 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
timestamp);
}
- if (value & TSL2X7X_STA_ALS_INTR) {
+ if (ret & TSL2X7X_STA_ALS_INTR) {
tsl2x7x_get_lux(indio_dev); /* freshen data for ABI */
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
@@ -1427,14 +1448,10 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
IIO_EV_DIR_EITHER),
timestamp);
}
- /* Clear interrupt now that we have handled it. */
- ret = i2c_smbus_write_byte(chip->client,
- TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
- TSL2X7X_CMD_PROXALS_INT_CLR);
+
+ ret = tsl2x7x_clear_interrupts(chip, TSL2X7X_CMD_PROXALS_INT_CLR);
if (ret < 0)
- dev_err(&chip->client->dev,
- "Failed to clear irq from event handler. err = %d\n",
- ret);
+ return ret;
return IRQ_HANDLED;
}
@@ -1461,7 +1478,6 @@ static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = {
&dev_attr_in_illuminance0_target_input.attr,
&dev_attr_in_illuminance0_calibrate.attr,
&dev_attr_in_illuminance0_lux_table.attr,
- &iio_const_attr_in_proximity0_calibscale_available.dev_attr.attr,
NULL
};
@@ -1792,12 +1808,6 @@ static int tsl2x7x_suspend(struct device *dev)
chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
}
- if (chip->pdata && chip->pdata->platform_power) {
- pm_message_t pmm = {PM_EVENT_SUSPEND};
-
- chip->pdata->platform_power(dev, pmm);
- }
-
return ret;
}
@@ -1807,12 +1817,6 @@ static int tsl2x7x_resume(struct device *dev)
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
int ret = 0;
- if (chip->pdata && chip->pdata->platform_power) {
- pm_message_t pmm = {PM_EVENT_RESUME};
-
- chip->pdata->platform_power(dev, pmm);
- }
-
if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED)
ret = tsl2x7x_chip_on(indio_dev);
diff --git a/drivers/staging/iio/light/tsl2x7x.h b/drivers/staging/iio/light/tsl2x7x.h
index df00f2ec1719..28b0e7fdc9b8 100644
--- a/drivers/staging/iio/light/tsl2x7x.h
+++ b/drivers/staging/iio/light/tsl2x7x.h
@@ -21,7 +21,6 @@
#ifndef __TSL2X7X_H
#define __TSL2X7X_H
-#include <linux/pm.h>
struct tsl2x7x_lux {
unsigned int ratio;
@@ -79,6 +78,8 @@ struct tsl2x7x_settings {
int prox_thres_high;
int prox_pulse_count;
int prox_max_samples_cal;
+ int prox_diode;
+ int prox_power;
};
/**
@@ -91,9 +92,6 @@ struct tsl2x7x_settings {
*
*/
struct tsl2X7X_platform_data {
- int (*platform_power)(struct device *dev, pm_message_t);
- int (*power_on)(struct iio_dev *indio_dev);
- int (*power_off)(struct i2c_client *dev);
struct tsl2x7x_lux platform_lux_table[TSL2X7X_MAX_LUX_TABLE_SIZE];
struct tsl2x7x_settings *platform_default_settings;
};
diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c
index c44eb577dc35..275e8dfff836 100644
--- a/drivers/staging/iio/meter/ade7753.c
+++ b/drivers/staging/iio/meter/ade7753.c
@@ -388,14 +388,16 @@ static IIO_DEV_ATTR_VPERIOD(0444,
ade7753_read_16bit,
NULL,
ADE7753_PERIOD);
-static IIO_DEV_ATTR_CH_OFF(1, 0644,
- ade7753_read_8bit,
- ade7753_write_8bit,
- ADE7753_CH1OS);
-static IIO_DEV_ATTR_CH_OFF(2, 0644,
- ade7753_read_8bit,
- ade7753_write_8bit,
- ADE7753_CH2OS);
+
+static IIO_DEVICE_ATTR(choff_1, 0644,
+ ade7753_read_8bit,
+ ade7753_write_8bit,
+ ADE7753_CH1OS);
+
+static IIO_DEVICE_ATTR(choff_2, 0644,
+ ade7753_read_8bit,
+ ade7753_write_8bit,
+ ADE7753_CH2OS);
static int ade7753_set_irq(struct device *dev, bool enable)
{
diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c
index 3a1e342d75fb..9aa067736715 100644
--- a/drivers/staging/iio/meter/ade7754.c
+++ b/drivers/staging/iio/meter/ade7754.c
@@ -132,7 +132,7 @@ static int ade7754_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
}
static int ade7754_spi_write_reg_16(struct device *dev,
- u8 reg_address, u16 value)
+ u8 reg_address, u16 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -140,8 +140,8 @@ static int ade7754_spi_write_reg_16(struct device *dev,
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7754_WRITE_REG(reg_address);
- st->tx[1] = (value >> 8) & 0xFF;
- st->tx[2] = value & 0xFF;
+ st->tx[1] = (val >> 8) & 0xFF;
+ st->tx[2] = val & 0xFF;
ret = spi_write(st->us, st->tx, 3);
mutex_unlock(&st->buf_lock);
diff --git a/drivers/staging/iio/meter/ade7758.h b/drivers/staging/iio/meter/ade7758.h
index 6ae78d8aa24f..2de81b53e786 100644
--- a/drivers/staging/iio/meter/ade7758.h
+++ b/drivers/staging/iio/meter/ade7758.h
@@ -111,7 +111,7 @@
* @trig: data ready trigger registered with iio
* @tx: transmit buffer
* @rx: receive buffer
- * @buf_lock: mutex to protect tx and rx
+ * @buf_lock: mutex to protect tx, rx, read and write frequency
**/
struct ade7758_state {
struct spi_device *us;
diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c
index 7b7ffe5ed186..4e0dbf5c5705 100644
--- a/drivers/staging/iio/meter/ade7758_core.c
+++ b/drivers/staging/iio/meter/ade7758_core.c
@@ -24,17 +24,25 @@
#include "meter.h"
#include "ade7758.h"
-int ade7758_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
+static int __ade7758_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
{
- int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
- mutex_lock(&st->buf_lock);
st->tx[0] = ADE7758_WRITE_REG(reg_address);
st->tx[1] = val;
- ret = spi_write(st->us, st->tx, 2);
+ return spi_write(st->us, st->tx, 2);
+}
+
+int ade7758_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
+{
+ int ret;
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ade7758_state *st = iio_priv(indio_dev);
+
+ mutex_lock(&st->buf_lock);
+ ret = __ade7758_spi_write_reg_8(dev, reg_address, val);
mutex_unlock(&st->buf_lock);
return ret;
@@ -91,7 +99,7 @@ static int ade7758_spi_write_reg_24(struct device *dev, u8 reg_address,
return ret;
}
-int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
+static int __ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
@@ -111,7 +119,6 @@ int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
},
};
- mutex_lock(&st->buf_lock);
st->tx[0] = ADE7758_READ_REG(reg_address);
st->tx[1] = 0;
@@ -124,7 +131,19 @@ int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
*val = st->rx[0];
error_ret:
+ return ret;
+}
+
+int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ade7758_state *st = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&st->buf_lock);
+ ret = __ade7758_spi_read_reg_8(dev, reg_address, val);
mutex_unlock(&st->buf_lock);
+
return ret;
}
@@ -484,6 +503,8 @@ static int ade7758_write_samp_freq(struct device *dev, int val)
{
int ret;
u8 reg, t;
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ade7758_state *st = iio_priv(indio_dev);
switch (val) {
case 26040:
@@ -499,20 +520,23 @@ static int ade7758_write_samp_freq(struct device *dev, int val)
t = 3;
break;
default:
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
- ret = ade7758_spi_read_reg_8(dev, ADE7758_WAVMODE, &reg);
+ mutex_lock(&st->buf_lock);
+
+ ret = __ade7758_spi_read_reg_8(dev, ADE7758_WAVMODE, &reg);
if (ret)
goto out;
reg &= ~(5 << 3);
reg |= t << 5;
- ret = ade7758_spi_write_reg_8(dev, ADE7758_WAVMODE, reg);
+ ret = __ade7758_spi_write_reg_8(dev, ADE7758_WAVMODE, reg);
out:
+ mutex_unlock(&st->buf_lock);
+
return ret;
}
@@ -526,9 +550,9 @@ static int ade7758_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
- mutex_lock(&indio_dev->mlock);
+
ret = ade7758_read_samp_freq(&indio_dev->dev, val);
- mutex_unlock(&indio_dev->mlock);
+
return ret;
default:
return -EINVAL;
@@ -547,9 +571,9 @@ static int ade7758_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SAMP_FREQ:
if (val2)
return -EINVAL;
- mutex_lock(&indio_dev->mlock);
+
ret = ade7758_write_samp_freq(&indio_dev->dev, val);
- mutex_unlock(&indio_dev->mlock);
+
return ret;
default:
return -EINVAL;
diff --git a/drivers/staging/iio/meter/ade7758_trigger.c b/drivers/staging/iio/meter/ade7758_trigger.c
index 1f0d1a0cf889..4f6b338cffeb 100644
--- a/drivers/staging/iio/meter/ade7758_trigger.c
+++ b/drivers/staging/iio/meter/ade7758_trigger.c
@@ -30,11 +30,11 @@ static irqreturn_t ade7758_data_rdy_trig_poll(int irq, void *private)
* ade7758_data_rdy_trigger_set_state() set datardy interrupt state
**/
static int ade7758_data_rdy_trigger_set_state(struct iio_trigger *trig,
- bool state)
+ bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
- dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
+ dev_dbg(&indio_dev->dev, "(%d)\n", state);
return ade7758_set_irq(&indio_dev->dev, state);
}
@@ -63,8 +63,8 @@ int ade7758_probe_trigger(struct iio_dev *indio_dev)
int ret;
st->trig = iio_trigger_alloc("%s-dev%d",
- spi_get_device_id(st->us)->name,
- indio_dev->id);
+ spi_get_device_id(st->us)->name,
+ indio_dev->id);
if (!st->trig) {
ret = -ENOMEM;
goto error_ret;
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c
index d99cf508d8d0..c078b770fa53 100644
--- a/drivers/staging/iio/meter/ade7759.c
+++ b/drivers/staging/iio/meter/ade7759.c
@@ -72,8 +72,8 @@ struct ade7759_state {
};
static int ade7759_spi_write_reg_8(struct device *dev,
- u8 reg_address,
- u8 val)
+ u8 reg_address,
+ u8 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -91,8 +91,8 @@ static int ade7759_spi_write_reg_8(struct device *dev,
/*Unlocked version of ade7759_spi_write_reg_16 function */
static int __ade7759_spi_write_reg_16(struct device *dev,
- u8 reg_address,
- u16 value)
+ u8 reg_address,
+ u16 value)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
@@ -104,8 +104,8 @@ static int __ade7759_spi_write_reg_16(struct device *dev,
}
static int ade7759_spi_write_reg_16(struct device *dev,
- u8 reg_address,
- u16 value)
+ u8 reg_address,
+ u16 value)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -119,8 +119,8 @@ static int ade7759_spi_write_reg_16(struct device *dev,
}
static int ade7759_spi_read_reg_8(struct device *dev,
- u8 reg_address,
- u8 *val)
+ u8 reg_address,
+ u8 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
@@ -128,8 +128,9 @@ static int ade7759_spi_read_reg_8(struct device *dev,
ret = spi_w8r8(st->us, ADE7759_READ_REG(reg_address));
if (ret < 0) {
- dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
- reg_address);
+ dev_err(&st->us->dev,
+ "problem when reading 8 bit register 0x%02X",
+ reg_address);
return ret;
}
*val = ret;
@@ -138,8 +139,8 @@ static int ade7759_spi_read_reg_8(struct device *dev,
}
static int ade7759_spi_read_reg_16(struct device *dev,
- u8 reg_address,
- u16 *val)
+ u8 reg_address,
+ u16 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
@@ -158,8 +159,8 @@ static int ade7759_spi_read_reg_16(struct device *dev,
}
static int ade7759_spi_read_reg_40(struct device *dev,
- u8 reg_address,
- u64 *val)
+ u8 reg_address,
+ u64 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
@@ -179,8 +180,9 @@ static int ade7759_spi_read_reg_40(struct device *dev,
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
if (ret) {
- dev_err(&st->us->dev, "problem when reading 40 bit register 0x%02X",
- reg_address);
+ dev_err(&st->us->dev,
+ "problem when reading 40 bit register 0x%02X",
+ reg_address);
goto error_ret;
}
*val = ((u64)st->rx[1] << 32) | ((u64)st->rx[2] << 24) |
@@ -192,8 +194,8 @@ error_ret:
}
static ssize_t ade7759_read_8bit(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
int ret;
u8 val = 0;
@@ -207,8 +209,8 @@ static ssize_t ade7759_read_8bit(struct device *dev,
}
static ssize_t ade7759_read_16bit(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
int ret;
u16 val = 0;
@@ -222,8 +224,8 @@ static ssize_t ade7759_read_16bit(struct device *dev,
}
static ssize_t ade7759_read_40bit(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
int ret;
u64 val = 0;
@@ -237,9 +239,9 @@ static ssize_t ade7759_read_40bit(struct device *dev,
}
static ssize_t ade7759_write_8bit(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
@@ -255,9 +257,9 @@ error_ret:
}
static ssize_t ade7759_write_16bit(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
@@ -277,9 +279,7 @@ static int ade7759_reset(struct device *dev)
int ret;
u16 val;
- ret = ade7759_spi_read_reg_16(dev,
- ADE7759_MODE,
- &val);
+ ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &val);
if (ret < 0)
return ret;
@@ -328,14 +328,16 @@ static IIO_DEV_ATTR_ACTIVE_POWER_GAIN(0644,
ade7759_read_16bit,
ade7759_write_16bit,
ADE7759_APGAIN);
-static IIO_DEV_ATTR_CH_OFF(1, 0644,
- ade7759_read_8bit,
- ade7759_write_8bit,
- ADE7759_CH1OS);
-static IIO_DEV_ATTR_CH_OFF(2, 0644,
- ade7759_read_8bit,
- ade7759_write_8bit,
- ADE7759_CH2OS);
+
+static IIO_DEVICE_ATTR(choff_1, 0644,
+ ade7759_read_8bit,
+ ade7759_write_8bit,
+ ADE7759_CH1OS);
+
+static IIO_DEVICE_ATTR(choff_2, 0644,
+ ade7759_read_8bit,
+ ade7759_write_8bit,
+ ADE7759_CH2OS);
static int ade7759_set_irq(struct device *dev, bool enable)
{
@@ -365,9 +367,7 @@ static int ade7759_stop_device(struct device *dev)
int ret;
u16 val;
- ret = ade7759_spi_read_reg_16(dev,
- ADE7759_MODE,
- &val);
+ ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &val);
if (ret < 0) {
dev_err(dev, "unable to power down the device, error: %d\n",
ret);
@@ -404,16 +404,14 @@ err_ret:
}
static ssize_t ade7759_read_frequency(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
int ret;
u16 t;
int sps;
- ret = ade7759_spi_read_reg_16(dev,
- ADE7759_MODE,
- &t);
+ ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &t);
if (ret)
return ret;
@@ -424,9 +422,9 @@ static ssize_t ade7759_read_frequency(struct device *dev,
}
static ssize_t ade7759_write_frequency(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c
index 8106f8cceeab..317e4f0d8176 100644
--- a/drivers/staging/iio/meter/ade7854-i2c.c
+++ b/drivers/staging/iio/meter/ade7854-i2c.c
@@ -17,7 +17,7 @@
static int ade7854_i2c_write_reg_8(struct device *dev,
u16 reg_address,
- u8 value)
+ u8 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -26,7 +26,7 @@ static int ade7854_i2c_write_reg_8(struct device *dev,
mutex_lock(&st->buf_lock);
st->tx[0] = (reg_address >> 8) & 0xFF;
st->tx[1] = reg_address & 0xFF;
- st->tx[2] = value;
+ st->tx[2] = val;
ret = i2c_master_send(st->i2c, st->tx, 3);
mutex_unlock(&st->buf_lock);
@@ -36,7 +36,7 @@ static int ade7854_i2c_write_reg_8(struct device *dev,
static int ade7854_i2c_write_reg_16(struct device *dev,
u16 reg_address,
- u16 value)
+ u16 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -45,8 +45,8 @@ static int ade7854_i2c_write_reg_16(struct device *dev,
mutex_lock(&st->buf_lock);
st->tx[0] = (reg_address >> 8) & 0xFF;
st->tx[1] = reg_address & 0xFF;
- st->tx[2] = (value >> 8) & 0xFF;
- st->tx[3] = value & 0xFF;
+ st->tx[2] = (val >> 8) & 0xFF;
+ st->tx[3] = val & 0xFF;
ret = i2c_master_send(st->i2c, st->tx, 4);
mutex_unlock(&st->buf_lock);
@@ -56,7 +56,7 @@ static int ade7854_i2c_write_reg_16(struct device *dev,
static int ade7854_i2c_write_reg_24(struct device *dev,
u16 reg_address,
- u32 value)
+ u32 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -65,9 +65,9 @@ static int ade7854_i2c_write_reg_24(struct device *dev,
mutex_lock(&st->buf_lock);
st->tx[0] = (reg_address >> 8) & 0xFF;
st->tx[1] = reg_address & 0xFF;
- st->tx[2] = (value >> 16) & 0xFF;
- st->tx[3] = (value >> 8) & 0xFF;
- st->tx[4] = value & 0xFF;
+ st->tx[2] = (val >> 16) & 0xFF;
+ st->tx[3] = (val >> 8) & 0xFF;
+ st->tx[4] = val & 0xFF;
ret = i2c_master_send(st->i2c, st->tx, 5);
mutex_unlock(&st->buf_lock);
@@ -77,7 +77,7 @@ static int ade7854_i2c_write_reg_24(struct device *dev,
static int ade7854_i2c_write_reg_32(struct device *dev,
u16 reg_address,
- u32 value)
+ u32 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -86,10 +86,10 @@ static int ade7854_i2c_write_reg_32(struct device *dev,
mutex_lock(&st->buf_lock);
st->tx[0] = (reg_address >> 8) & 0xFF;
st->tx[1] = reg_address & 0xFF;
- st->tx[2] = (value >> 24) & 0xFF;
- st->tx[3] = (value >> 16) & 0xFF;
- st->tx[4] = (value >> 8) & 0xFF;
- st->tx[5] = value & 0xFF;
+ st->tx[2] = (val >> 24) & 0xFF;
+ st->tx[3] = (val >> 16) & 0xFF;
+ st->tx[4] = (val >> 8) & 0xFF;
+ st->tx[5] = val & 0xFF;
ret = i2c_master_send(st->i2c, st->tx, 6);
mutex_unlock(&st->buf_lock);
diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c
index 63e200ffd1f2..4419b8f06197 100644
--- a/drivers/staging/iio/meter/ade7854-spi.c
+++ b/drivers/staging/iio/meter/ade7854-spi.c
@@ -16,8 +16,8 @@
#include "ade7854.h"
static int ade7854_spi_write_reg_8(struct device *dev,
- u16 reg_address,
- u8 value)
+ u16 reg_address,
+ u8 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -32,7 +32,7 @@ static int ade7854_spi_write_reg_8(struct device *dev,
st->tx[0] = ADE7854_WRITE_REG;
st->tx[1] = (reg_address >> 8) & 0xFF;
st->tx[2] = reg_address & 0xFF;
- st->tx[3] = value & 0xFF;
+ st->tx[3] = val & 0xFF;
ret = spi_sync_transfer(st->spi, &xfer, 1);
mutex_unlock(&st->buf_lock);
@@ -41,8 +41,8 @@ static int ade7854_spi_write_reg_8(struct device *dev,
}
static int ade7854_spi_write_reg_16(struct device *dev,
- u16 reg_address,
- u16 value)
+ u16 reg_address,
+ u16 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -57,8 +57,8 @@ static int ade7854_spi_write_reg_16(struct device *dev,
st->tx[0] = ADE7854_WRITE_REG;
st->tx[1] = (reg_address >> 8) & 0xFF;
st->tx[2] = reg_address & 0xFF;
- st->tx[3] = (value >> 8) & 0xFF;
- st->tx[4] = value & 0xFF;
+ st->tx[3] = (val >> 8) & 0xFF;
+ st->tx[4] = val & 0xFF;
ret = spi_sync_transfer(st->spi, &xfer, 1);
mutex_unlock(&st->buf_lock);
@@ -67,8 +67,8 @@ static int ade7854_spi_write_reg_16(struct device *dev,
}
static int ade7854_spi_write_reg_24(struct device *dev,
- u16 reg_address,
- u32 value)
+ u16 reg_address,
+ u32 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -83,9 +83,9 @@ static int ade7854_spi_write_reg_24(struct device *dev,
st->tx[0] = ADE7854_WRITE_REG;
st->tx[1] = (reg_address >> 8) & 0xFF;
st->tx[2] = reg_address & 0xFF;
- st->tx[3] = (value >> 16) & 0xFF;
- st->tx[4] = (value >> 8) & 0xFF;
- st->tx[5] = value & 0xFF;
+ st->tx[3] = (val >> 16) & 0xFF;
+ st->tx[4] = (val >> 8) & 0xFF;
+ st->tx[5] = val & 0xFF;
ret = spi_sync_transfer(st->spi, &xfer, 1);
mutex_unlock(&st->buf_lock);
@@ -94,8 +94,8 @@ static int ade7854_spi_write_reg_24(struct device *dev,
}
static int ade7854_spi_write_reg_32(struct device *dev,
- u16 reg_address,
- u32 value)
+ u16 reg_address,
+ u32 val)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -110,10 +110,10 @@ static int ade7854_spi_write_reg_32(struct device *dev,
st->tx[0] = ADE7854_WRITE_REG;
st->tx[1] = (reg_address >> 8) & 0xFF;
st->tx[2] = reg_address & 0xFF;
- st->tx[3] = (value >> 24) & 0xFF;
- st->tx[4] = (value >> 16) & 0xFF;
- st->tx[5] = (value >> 8) & 0xFF;
- st->tx[6] = value & 0xFF;
+ st->tx[3] = (val >> 24) & 0xFF;
+ st->tx[4] = (val >> 16) & 0xFF;
+ st->tx[5] = (val >> 8) & 0xFF;
+ st->tx[6] = val & 0xFF;
ret = spi_sync_transfer(st->spi, &xfer, 1);
mutex_unlock(&st->buf_lock);
@@ -122,8 +122,8 @@ static int ade7854_spi_write_reg_32(struct device *dev,
}
static int ade7854_spi_read_reg_8(struct device *dev,
- u16 reg_address,
- u8 *val)
+ u16 reg_address,
+ u8 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
@@ -149,7 +149,7 @@ static int ade7854_spi_read_reg_8(struct device *dev,
ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
if (ret) {
dev_err(&st->spi->dev, "problem when reading 8 bit register 0x%02X",
- reg_address);
+ reg_address);
goto error_ret;
}
*val = st->rx[0];
@@ -160,8 +160,8 @@ error_ret:
}
static int ade7854_spi_read_reg_16(struct device *dev,
- u16 reg_address,
- u16 *val)
+ u16 reg_address,
+ u16 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
@@ -186,7 +186,7 @@ static int ade7854_spi_read_reg_16(struct device *dev,
ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
if (ret) {
dev_err(&st->spi->dev, "problem when reading 16 bit register 0x%02X",
- reg_address);
+ reg_address);
goto error_ret;
}
*val = be16_to_cpup((const __be16 *)st->rx);
@@ -197,8 +197,8 @@ error_ret:
}
static int ade7854_spi_read_reg_24(struct device *dev,
- u16 reg_address,
- u32 *val)
+ u16 reg_address,
+ u32 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
@@ -224,7 +224,7 @@ static int ade7854_spi_read_reg_24(struct device *dev,
ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
if (ret) {
dev_err(&st->spi->dev, "problem when reading 24 bit register 0x%02X",
- reg_address);
+ reg_address);
goto error_ret;
}
*val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
@@ -235,8 +235,8 @@ error_ret:
}
static int ade7854_spi_read_reg_32(struct device *dev,
- u16 reg_address,
- u32 *val)
+ u16 reg_address,
+ u32 *val)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
@@ -262,7 +262,7 @@ static int ade7854_spi_read_reg_32(struct device *dev,
ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
if (ret) {
dev_err(&st->spi->dev, "problem when reading 32 bit register 0x%02X",
- reg_address);
+ reg_address);
goto error_ret;
}
*val = be32_to_cpup((const __be32 *)st->rx);
diff --git a/drivers/staging/iio/meter/ade7854.h b/drivers/staging/iio/meter/ade7854.h
index c27247a7891a..a82d38224cbd 100644
--- a/drivers/staging/iio/meter/ade7854.h
+++ b/drivers/staging/iio/meter/ade7854.h
@@ -152,20 +152,20 @@
* @rx: receive buffer
**/
struct ade7854_state {
- struct spi_device *spi;
- struct i2c_client *i2c;
- int (*read_reg_8)(struct device *, u16, u8 *);
- int (*read_reg_16)(struct device *, u16, u16 *);
- int (*read_reg_24)(struct device *, u16, u32 *);
- int (*read_reg_32)(struct device *, u16, u32 *);
- int (*write_reg_8)(struct device *, u16, u8);
- int (*write_reg_16)(struct device *, u16, u16);
- int (*write_reg_24)(struct device *, u16, u32);
- int (*write_reg_32)(struct device *, u16, u32);
- int irq;
- struct mutex buf_lock;
- u8 tx[ADE7854_MAX_TX] ____cacheline_aligned;
- u8 rx[ADE7854_MAX_RX];
+ struct spi_device *spi;
+ struct i2c_client *i2c;
+ int (*read_reg_8)(struct device *dev, u16 reg_address, u8 *val);
+ int (*read_reg_16)(struct device *dev, u16 reg_address, u16 *val);
+ int (*read_reg_24)(struct device *dev, u16 reg_address, u32 *val);
+ int (*read_reg_32)(struct device *dev, u16 reg_address, u32 *val);
+ int (*write_reg_8)(struct device *dev, u16 reg_address, u8 val);
+ int (*write_reg_16)(struct device *dev, u16 reg_address, u16 val);
+ int (*write_reg_24)(struct device *dev, u16 reg_address, u32 val);
+ int (*write_reg_32)(struct device *dev, u16 reg_address, u32 val);
+ int irq;
+ struct mutex buf_lock;
+ u8 tx[ADE7854_MAX_TX] ____cacheline_aligned;
+ u8 rx[ADE7854_MAX_RX];
};
diff --git a/drivers/staging/iio/meter/meter.h b/drivers/staging/iio/meter/meter.h
index edf26302fa57..5ed59bf30a25 100644
--- a/drivers/staging/iio/meter/meter.h
+++ b/drivers/staging/iio/meter/meter.h
@@ -348,9 +348,6 @@
#define IIO_DEV_ATTR_VPERIOD(_mode, _show, _store, _addr) \
IIO_DEVICE_ATTR(vperiod, _mode, _show, _store, _addr)
-#define IIO_DEV_ATTR_CH_OFF(_num, _mode, _show, _store, _addr) \
- IIO_DEVICE_ATTR(choff_##_num, _mode, _show, _store, _addr)
-
/* active energy register, AENERGY, is more than half full */
#define IIO_EVENT_ATTR_AENERGY_HALF_FULL(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(aenergy_half_full, _evlist, _show, _store, _mask)
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
index f8baab061eba..ac13b99bd9cb 100644
--- a/drivers/staging/iio/resolver/ad2s1210.c
+++ b/drivers/staging/iio/resolver/ad2s1210.c
@@ -35,8 +35,6 @@
#define AD2S1210_SET_RES1 0x02
#define AD2S1210_SET_RES0 0x01
-#define AD2S1210_SET_ENRESOLUTION (AD2S1210_SET_ENRES1 | \
- AD2S1210_SET_ENRES0)
#define AD2S1210_SET_RESOLUTION (AD2S1210_SET_RES1 | AD2S1210_SET_RES0)
#define AD2S1210_REG_POSITION 0x80
@@ -53,10 +51,6 @@
#define AD2S1210_REG_SOFT_RESET 0xF0
#define AD2S1210_REG_FAULT 0xFF
-/* pin SAMPLE, A0, A1, RES0, RES1, is controlled by driver */
-#define AD2S1210_SAA 3
-#define AD2S1210_PN (AD2S1210_SAA + AD2S1210_RES)
-
#define AD2S1210_MIN_CLKIN 6144000
#define AD2S1210_MAX_CLKIN 10240000
#define AD2S1210_MIN_EXCIT 2000
@@ -64,10 +58,6 @@
#define AD2S1210_MIN_FCW 0x4
#define AD2S1210_MAX_FCW 0x50
-/* default input clock on serial interface */
-#define AD2S1210_DEF_CLKIN 8192000
-/* clock period in nano second */
-#define AD2S1210_DEF_TCK (1000000000 / AD2S1210_DEF_CLKIN)
#define AD2S1210_DEF_EXCIT 10000
enum ad2s1210_mode {
@@ -86,7 +76,6 @@ struct ad2s1210_state {
unsigned int fclkin;
unsigned int fexcit;
bool hysteresis;
- bool old_data;
u8 resolution;
enum ad2s1210_mode mode;
u8 rx[2] ____cacheline_aligned;
@@ -117,7 +106,6 @@ static int ad2s1210_config_write(struct ad2s1210_state *st, u8 data)
ret = spi_write(st->sdev, st->tx, 1);
if (ret < 0)
return ret;
- st->old_data = true;
return 0;
}
@@ -139,7 +127,6 @@ static int ad2s1210_config_read(struct ad2s1210_state *st,
ret = spi_sync_transfer(st->sdev, &xfer, 1);
if (ret < 0)
return ret;
- st->old_data = true;
return st->rx[1];
}
@@ -165,9 +152,10 @@ int ad2s1210_update_frequency_control_word(struct ad2s1210_state *st)
static unsigned char ad2s1210_read_resolution_pin(struct ad2s1210_state *st)
{
- return ad2s1210_resolution_value[
- (gpio_get_value(st->pdata->res[0]) << 1) |
- gpio_get_value(st->pdata->res[1])];
+ int resolution = (gpio_get_value(st->pdata->res[0]) << 1) |
+ gpio_get_value(st->pdata->res[1]);
+
+ return ad2s1210_resolution_value[resolution];
}
static const int ad2s1210_res_pins[4][2] = {
diff --git a/drivers/staging/irda/TODO b/drivers/staging/irda/TODO
deleted file mode 100644
index 7d98a5cffaff..000000000000
--- a/drivers/staging/irda/TODO
+++ /dev/null
@@ -1,4 +0,0 @@
-The irda code will be removed soon from the kernel tree as it is old and
-obsolete and broken.
-
-Don't worry about fixing up anything here, it's not needed.
diff --git a/drivers/staging/irda/drivers/Kconfig b/drivers/staging/irda/drivers/Kconfig
deleted file mode 100644
index e070e1222733..000000000000
--- a/drivers/staging/irda/drivers/Kconfig
+++ /dev/null
@@ -1,398 +0,0 @@
-menu "Infrared-port device drivers"
- depends on IRDA!=n
-
-comment "SIR device drivers"
-
-config IRTTY_SIR
- tristate "IrTTY (uses Linux serial driver)"
- depends on IRDA && TTY
- help
- Say Y here if you want to build support for the IrTTY line
- discipline. To compile it as a module, choose M here: the module
- will be called irtty-sir. IrTTY makes it possible to use Linux's
- own serial driver for all IrDA ports that are 16550 compatible.
- Most IrDA chips are 16550 compatible so you should probably say Y
- to this option. Using IrTTY will however limit the speed of the
- connection to 115200 bps (IrDA SIR mode).
-
- If unsure, say Y.
-
-config BFIN_SIR
- tristate "Blackfin SIR on UART"
- depends on BLACKFIN && IRDA
- default n
- help
- Say Y here if your want to enable SIR function on Blackfin UART
- devices.
-
- To activate this driver you can start irattach like:
- "irattach irda0 -s"
-
- Saying M, it will be built as a module named bfin_sir.
-
- Note that you need to turn off one of the serial drivers for SIR
- to use that UART.
-
-config BFIN_SIR0
- bool "Blackfin SIR on UART0"
- depends on BFIN_SIR && !SERIAL_BFIN_UART0
-
-config BFIN_SIR1
- bool "Blackfin SIR on UART1"
- depends on BFIN_SIR && !SERIAL_BFIN_UART1 && (!BF531 && !BF532 && !BF533 && !BF561)
-
-config BFIN_SIR2
- bool "Blackfin SIR on UART2"
- depends on BFIN_SIR && !SERIAL_BFIN_UART2 && (BF54x || BF538 || BF539)
-
-config BFIN_SIR3
- bool "Blackfin SIR on UART3"
- depends on BFIN_SIR && !SERIAL_BFIN_UART3 && (BF54x)
-
-choice
- prompt "SIR Mode"
- depends on BFIN_SIR
- default SIR_BFIN_DMA
-
-config SIR_BFIN_DMA
- bool "DMA mode"
- depends on !DMA_UNCACHED_NONE
-
-config SIR_BFIN_PIO
- bool "PIO mode"
-endchoice
-
-config SH_SIR
- tristate "SuperH SIR on UART"
- depends on IRDA && SUPERH && \
- (CPU_SUBTYPE_SH7722 || CPU_SUBTYPE_SH7723 || \
- CPU_SUBTYPE_SH7724)
- default n
- help
- Say Y here if your want to enable SIR function on SuperH UART
- devices.
-
-comment "Dongle support"
-
-config DONGLE
- bool "Serial dongle support"
- depends on IRTTY_SIR
- help
- Say Y here if you have an infrared device that connects to your
- computer's serial port. These devices are called dongles. Then say Y
- or M to the driver for your particular dongle below.
-
- Note that the answer to this question won't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the questions about serial dongles.
-
-config ESI_DONGLE
- tristate "ESI JetEye PC dongle"
- depends on IRTTY_SIR && DONGLE && IRDA
- help
- Say Y here if you want to build support for the Extended Systems
- JetEye PC dongle. To compile it as a module, choose M here. The ESI
- dongle attaches to the normal 9-pin serial port connector, and can
- currently only be used by IrTTY. To activate support for ESI
- dongles you will have to start irattach like this:
- "irattach -d esi".
-
-config ACTISYS_DONGLE
- tristate "ACTiSYS IR-220L and IR220L+ dongle"
- depends on IRTTY_SIR && DONGLE && IRDA
- help
- Say Y here if you want to build support for the ACTiSYS IR-220L and
- IR220L+ dongles. To compile it as a module, choose M here. The
- ACTiSYS dongles attaches to the normal 9-pin serial port connector,
- and can currently only be used by IrTTY. To activate support for
- ACTiSYS dongles you will have to start irattach like this:
- "irattach -d actisys" or "irattach -d actisys+".
-
-config TEKRAM_DONGLE
- tristate "Tekram IrMate 210B dongle"
- depends on IRTTY_SIR && DONGLE && IRDA
- help
- Say Y here if you want to build support for the Tekram IrMate 210B
- dongle. To compile it as a module, choose M here. The Tekram dongle
- attaches to the normal 9-pin serial port connector, and can
- currently only be used by IrTTY. To activate support for Tekram
- dongles you will have to start irattach like this:
- "irattach -d tekram".
-
-config TOIM3232_DONGLE
- tristate "TOIM3232 IrDa dongle"
- depends on IRTTY_SIR && DONGLE && IRDA
- help
- Say Y here if you want to build support for the Vishay/Temic
- TOIM3232 and TOIM4232 based dongles.
- To compile it as a module, choose M here.
-
-config LITELINK_DONGLE
- tristate "Parallax LiteLink dongle"
- depends on IRTTY_SIR && DONGLE && IRDA
- help
- Say Y here if you want to build support for the Parallax Litelink
- dongle. To compile it as a module, choose M here. The Parallax
- dongle attaches to the normal 9-pin serial port connector, and can
- currently only be used by IrTTY. To activate support for Parallax
- dongles you will have to start irattach like this:
- "irattach -d litelink".
-
-config MA600_DONGLE
- tristate "Mobile Action MA600 dongle"
- depends on IRTTY_SIR && DONGLE && IRDA
- help
- Say Y here if you want to build support for the Mobile Action MA600
- dongle. To compile it as a module, choose M here. The MA600 dongle
- attaches to the normal 9-pin serial port connector, and can
- currently only be used by IrTTY. The driver should also support
- the MA620 USB version of the dongle, if the integrated USB-to-RS232
- converter is supported by usbserial. To activate support for
- MA600 dongle you will have to start irattach like this:
- "irattach -d ma600".
-
-config GIRBIL_DONGLE
- tristate "Greenwich GIrBIL dongle"
- depends on IRTTY_SIR && DONGLE && IRDA
- help
- Say Y here if you want to build support for the Greenwich GIrBIL
- dongle. If you want to compile it as a module, choose M here.
- The Greenwich dongle attaches to the normal 9-pin serial port
- connector, and can currently only be used by IrTTY. To activate
- support for Greenwich dongles you will have to start irattach
- like this: "irattach -d girbil".
-
-config MCP2120_DONGLE
- tristate "Microchip MCP2120"
- depends on IRTTY_SIR && DONGLE && IRDA
- help
- Say Y here if you want to build support for the Microchip MCP2120
- dongle. If you want to compile it as a module, choose M here.
- The MCP2120 dongle attaches to the normal 9-pin serial port
- connector, and can currently only be used by IrTTY. To activate
- support for MCP2120 dongles you will have to start irattach
- like this: "irattach -d mcp2120".
-
- You must build this dongle yourself. For more information see:
- <http://www.eyetap.org/~tangf/irda_sir_linux.html>
-
-config OLD_BELKIN_DONGLE
- tristate "Old Belkin dongle"
- depends on IRTTY_SIR && DONGLE && IRDA
- help
- Say Y here if you want to build support for the Adaptec Airport 1000
- and 2000 dongles. If you want to compile it as a module, choose
- M here. Some information is contained in the comments
- at the top of <file:drivers/net/irda/old_belkin-sir.c>.
-
-config ACT200L_DONGLE
- tristate "ACTiSYS IR-200L dongle"
- depends on IRTTY_SIR && DONGLE && IRDA
- help
- Say Y here if you want to build support for the ACTiSYS IR-200L
- dongle. If you want to compile it as a module, choose M here.
- The ACTiSYS IR-200L dongle attaches to the normal 9-pin serial
- port connector, and can currently only be used by IrTTY.
- To activate support for ACTiSYS IR-200L dongle you will have to
- start irattach like this: "irattach -d act200l".
-
-config KINGSUN_DONGLE
- tristate "KingSun/DonShine DS-620 IrDA-USB dongle"
- depends on IRDA && USB
- help
- Say Y or M here if you want to build support for the KingSun/DonShine
- DS-620 IrDA-USB bridge device driver.
-
- This USB bridge does not conform to the IrDA-USB device class
- specification, and therefore needs its own specific driver. This
- dongle supports SIR speed only (9600 bps).
-
- To compile it as a module, choose M here: the module will be called
- kingsun-sir.
-
-config KSDAZZLE_DONGLE
- tristate "KingSun Dazzle IrDA-USB dongle"
- depends on IRDA && USB
- help
- Say Y or M here if you want to build support for the KingSun Dazzle
- IrDA-USB bridge device driver.
-
- This USB bridge does not conform to the IrDA-USB device class
- specification, and therefore needs its own specific driver. This
- dongle supports SIR speeds only (9600 through 115200 bps).
-
- To compile it as a module, choose M here: the module will be called
- ksdazzle-sir.
-
-config KS959_DONGLE
- tristate "KingSun KS-959 IrDA-USB dongle"
- depends on IRDA && USB
- help
- Say Y or M here if you want to build support for the KingSun KS-959
- IrDA-USB bridge device driver.
-
- This USB bridge does not conform to the IrDA-USB device class
- specification, and therefore needs its own specific driver. This
- dongle supports SIR speeds only (9600 through 57600 bps).
-
- To compile it as a module, choose M here: the module will be called
- ks959-sir.
-
-comment "FIR device drivers"
-
-config USB_IRDA
- tristate "IrDA USB dongles"
- depends on IRDA && USB
- select FW_LOADER
- ---help---
- Say Y here if you want to build support for the USB IrDA FIR Dongle
- device driver. To compile it as a module, choose M here: the module
- will be called irda-usb. IrDA-USB support the various IrDA USB
- dongles available and most of their peculiarities. Those dongles
- plug in the USB port of your computer, are plug and play, and
- support SIR and FIR (4Mbps) speeds. On the other hand, those
- dongles tend to be less efficient than a FIR chipset.
-
- Please note that the driver is still experimental. And of course,
- you will need both USB and IrDA support in your kernel...
-
-config SIGMATEL_FIR
- tristate "SigmaTel STIr4200 bridge"
- depends on IRDA && USB
- select CRC32
- ---help---
- Say Y here if you want to build support for the SigmaTel STIr4200
- USB IrDA FIR bridge device driver.
-
- USB bridge based on the SigmaTel STIr4200 don't conform to the
- IrDA-USB device class specification, and therefore need their
- own specific driver. Those dongles support SIR and FIR (4Mbps)
- speeds.
-
- To compile it as a module, choose M here: the module will be called
- stir4200.
-
-config NSC_FIR
- tristate "NSC PC87108/PC87338"
- depends on IRDA && ISA_DMA_API
- help
- Say Y here if you want to build support for the NSC PC87108 and
- PC87338 IrDA chipsets. This driver supports SIR,
- MIR and FIR (4Mbps) speeds.
-
- To compile it as a module, choose M here: the module will be called
- nsc-ircc.
-
-config WINBOND_FIR
- tristate "Winbond W83977AF (IR)"
- depends on IRDA && ISA_DMA_API
- help
- Say Y here if you want to build IrDA support for the Winbond
- W83977AF super-io chipset. This driver should be used for the IrDA
- chipset in the Corel NetWinder. The driver supports SIR, MIR and
- FIR (4Mbps) speeds.
-
- To compile it as a module, choose M here: the module will be called
- w83977af_ir.
-
-config TOSHIBA_FIR
- tristate "Toshiba Type-O IR Port"
- depends on IRDA && PCI && !64BIT && VIRT_TO_BUS
- help
- Say Y here if you want to build support for the Toshiba Type-O IR
- and Donau oboe chipsets. These chipsets are used by the Toshiba
- Libretto 100/110CT, Tecra 8100, Portege 7020 and many more laptops.
- To compile it as a module, choose M here: the module will be called
- donauboe.
-
-config AU1000_FIR
- tristate "Alchemy IrDA SIR/FIR"
- depends on IRDA && MIPS_ALCHEMY
- help
- Say Y/M here to build support the IrDA peripheral on the
- Alchemy Au1000 and Au1100 SoCs.
- Say M to build a module; it will be called au1k_ir.ko
-
-config SMC_IRCC_FIR
- tristate "SMSC IrCC"
- depends on IRDA && ISA_DMA_API
- help
- Say Y here if you want to build support for the SMC Infrared
- Communications Controller. It is used in a wide variety of
- laptops (Fujitsu, Sony, Compaq and some Toshiba).
- To compile it as a module, choose M here: the module will be called
- smsc-ircc2.o.
-
-config ALI_FIR
- tristate "ALi M5123 FIR"
- depends on IRDA && ISA_DMA_API
- help
- Say Y here if you want to build support for the ALi M5123 FIR
- Controller. The ALi M5123 FIR Controller is embedded in ALi M1543C,
- M1535, M1535D, M1535+, M1535D South Bridge. This driver supports
- SIR, MIR and FIR (4Mbps) speeds.
-
- To compile it as a module, choose M here: the module will be called
- ali-ircc.
-
-config VLSI_FIR
- tristate "VLSI 82C147 SIR/MIR/FIR"
- depends on IRDA && PCI
- help
- Say Y here if you want to build support for the VLSI 82C147
- PCI-IrDA Controller. This controller is used by the HP OmniBook 800
- and 5500 notebooks. The driver provides support for SIR, MIR and
- FIR (4Mbps) speeds.
-
- To compile it as a module, choose M here: the module will be called
- vlsi_ir.
-
-config SA1100_FIR
- tristate "SA1100 Internal IR"
- depends on ARCH_SA1100 && IRDA && DMA_SA11X0
-
-config VIA_FIR
- tristate "VIA VT8231/VT1211 SIR/MIR/FIR"
- depends on IRDA && ISA_DMA_API
- help
- Say Y here if you want to build support for the VIA VT8231
- and VIA VT1211 IrDA controllers, found on the motherboards using
- those VIA chipsets. To use this controller, you will need
- to plug a specific 5 pins FIR IrDA dongle in the specific
- motherboard connector. The driver provides support for SIR, MIR
- and FIR (4Mbps) speeds.
-
- You will need to specify the 'dongle_id' module parameter to
- indicate the FIR dongle attached to the controller.
-
- To compile it as a module, choose M here: the module will be called
- via-ircc.
-
-config PXA_FICP
- tristate "Intel PXA2xx Internal FICP"
- depends on ARCH_PXA && IRDA
- help
- Say Y or M here if you want to build support for the PXA2xx
- built-in IRDA interface which can support both SIR and FIR.
- This driver relies on platform specific helper routines so
- available capabilities may vary from one PXA2xx target to
- another.
-
-config MCS_FIR
- tristate "MosChip MCS7780 IrDA-USB dongle"
- depends on IRDA && USB
- select CRC32
- help
- Say Y or M here if you want to build support for the MosChip
- MCS7780 IrDA-USB bridge device driver.
-
- USB bridge based on the MosChip MCS7780 don't conform to the
- IrDA-USB device class specification, and therefore need their
- own specific driver. Those dongles support SIR and FIR (4Mbps)
- speeds.
-
- To compile it as a module, choose M here: the module will be called
- mcs7780.
-
-endmenu
-
diff --git a/drivers/staging/irda/drivers/Makefile b/drivers/staging/irda/drivers/Makefile
deleted file mode 100644
index e2901b135528..000000000000
--- a/drivers/staging/irda/drivers/Makefile
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# Makefile for the Linux IrDA infrared port device drivers.
-#
-# 9 Aug 2000, Christoph Hellwig <hch@infradead.org>
-# Rewritten to use lists instead of if-statements.
-#
-
-subdir-ccflags-y += -I$(srctree)/drivers/staging/irda/include
-
-# FIR drivers
-obj-$(CONFIG_USB_IRDA) += irda-usb.o
-obj-$(CONFIG_SIGMATEL_FIR) += stir4200.o
-obj-$(CONFIG_NSC_FIR) += nsc-ircc.o
-obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o
-obj-$(CONFIG_SA1100_FIR) += sa1100_ir.o
-obj-$(CONFIG_TOSHIBA_FIR) += donauboe.o
-obj-$(CONFIG_SMC_IRCC_FIR) += smsc-ircc2.o
-obj-$(CONFIG_ALI_FIR) += ali-ircc.o
-obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o
-obj-$(CONFIG_VIA_FIR) += via-ircc.o
-obj-$(CONFIG_PXA_FICP) += pxaficp_ir.o
-obj-$(CONFIG_MCS_FIR) += mcs7780.o
-obj-$(CONFIG_AU1000_FIR) += au1k_ir.o
-# SIR drivers
-obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o
-obj-$(CONFIG_BFIN_SIR) += bfin_sir.o
-obj-$(CONFIG_SH_SIR) += sh_sir.o
-# dongle drivers for SIR drivers
-obj-$(CONFIG_ESI_DONGLE) += esi-sir.o
-obj-$(CONFIG_TEKRAM_DONGLE) += tekram-sir.o
-obj-$(CONFIG_ACTISYS_DONGLE) += actisys-sir.o
-obj-$(CONFIG_LITELINK_DONGLE) += litelink-sir.o
-obj-$(CONFIG_GIRBIL_DONGLE) += girbil-sir.o
-obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin-sir.o
-obj-$(CONFIG_MCP2120_DONGLE) += mcp2120-sir.o
-obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o
-obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o
-obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o
-obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o
-obj-$(CONFIG_KSDAZZLE_DONGLE) += ksdazzle-sir.o
-obj-$(CONFIG_KS959_DONGLE) += ks959-sir.o
-
-# The SIR helper module
-sir-dev-objs := sir_dev.o sir_dongle.o
diff --git a/drivers/staging/irda/drivers/act200l-sir.c b/drivers/staging/irda/drivers/act200l-sir.c
deleted file mode 100644
index e8917511e1aa..000000000000
--- a/drivers/staging/irda/drivers/act200l-sir.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*********************************************************************
- *
- * Filename: act200l.c
- * Version: 0.8
- * Description: Implementation for the ACTiSYS ACT-IR200L dongle
- * Status: Experimental.
- * Author: SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>
- * Created at: Fri Aug 3 17:35:42 2001
- * Modified at: Fri Aug 17 10:22:40 2001
- * Modified by: SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>
- *
- * Copyright (c) 2001 SHIMIZU Takuya, 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.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-
-#include "sir-dev.h"
-
-static int act200l_reset(struct sir_dev *dev);
-static int act200l_open(struct sir_dev *dev);
-static int act200l_close(struct sir_dev *dev);
-static int act200l_change_speed(struct sir_dev *dev, unsigned speed);
-
-/* Regsiter 0: Control register #1 */
-#define ACT200L_REG0 0x00
-#define ACT200L_TXEN 0x01 /* Enable transmitter */
-#define ACT200L_RXEN 0x02 /* Enable receiver */
-
-/* Register 1: Control register #2 */
-#define ACT200L_REG1 0x10
-#define ACT200L_LODB 0x01 /* Load new baud rate count value */
-#define ACT200L_WIDE 0x04 /* Expand the maximum allowable pulse */
-
-/* Register 4: Output Power register */
-#define ACT200L_REG4 0x40
-#define ACT200L_OP0 0x01 /* Enable LED1C output */
-#define ACT200L_OP1 0x02 /* Enable LED2C output */
-#define ACT200L_BLKR 0x04
-
-/* Register 5: Receive Mode register */
-#define ACT200L_REG5 0x50
-#define ACT200L_RWIDL 0x01 /* fixed 1.6us pulse mode */
-
-/* Register 6: Receive Sensitivity register #1 */
-#define ACT200L_REG6 0x60
-#define ACT200L_RS0 0x01 /* receive threshold bit 0 */
-#define ACT200L_RS1 0x02 /* receive threshold bit 1 */
-
-/* Register 7: Receive Sensitivity register #2 */
-#define ACT200L_REG7 0x70
-#define ACT200L_ENPOS 0x04 /* Ignore the falling edge */
-
-/* Register 8,9: Baud Rate Dvider register #1,#2 */
-#define ACT200L_REG8 0x80
-#define ACT200L_REG9 0x90
-
-#define ACT200L_2400 0x5f
-#define ACT200L_9600 0x17
-#define ACT200L_19200 0x0b
-#define ACT200L_38400 0x05
-#define ACT200L_57600 0x03
-#define ACT200L_115200 0x01
-
-/* Register 13: Control register #3 */
-#define ACT200L_REG13 0xd0
-#define ACT200L_SHDW 0x01 /* Enable access to shadow registers */
-
-/* Register 15: Status register */
-#define ACT200L_REG15 0xf0
-
-/* Register 21: Control register #4 */
-#define ACT200L_REG21 0x50
-#define ACT200L_EXCK 0x02 /* Disable clock output driver */
-#define ACT200L_OSCL 0x04 /* oscillator in low power, medium accuracy mode */
-
-static struct dongle_driver act200l = {
- .owner = THIS_MODULE,
- .driver_name = "ACTiSYS ACT-IR200L",
- .type = IRDA_ACT200L_DONGLE,
- .open = act200l_open,
- .close = act200l_close,
- .reset = act200l_reset,
- .set_speed = act200l_change_speed,
-};
-
-static int __init act200l_sir_init(void)
-{
- return irda_register_dongle(&act200l);
-}
-
-static void __exit act200l_sir_cleanup(void)
-{
- irda_unregister_dongle(&act200l);
-}
-
-static int act200l_open(struct sir_dev *dev)
-{
- struct qos_info *qos = &dev->qos;
-
- /* Power on the dongle */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- /* Set the speeds we can accept */
- qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
- qos->min_turn_time.bits = 0x03;
- irda_qos_bits_to_value(qos);
-
- /* irda thread waits 50 msec for power settling */
-
- return 0;
-}
-
-static int act200l_close(struct sir_dev *dev)
-{
- /* Power off the dongle */
- sirdev_set_dtr_rts(dev, FALSE, FALSE);
-
- return 0;
-}
-
-/*
- * Function act200l_change_speed (dev, speed)
- *
- * Set the speed for the ACTiSYS ACT-IR200L type dongle.
- *
- */
-static int act200l_change_speed(struct sir_dev *dev, unsigned speed)
-{
- u8 control[3];
- int ret = 0;
-
- /* Clear DTR and set RTS to enter command mode */
- sirdev_set_dtr_rts(dev, FALSE, TRUE);
-
- switch (speed) {
- default:
- ret = -EINVAL;
- /* fall through */
- case 9600:
- control[0] = ACT200L_REG8 | (ACT200L_9600 & 0x0f);
- control[1] = ACT200L_REG9 | ((ACT200L_9600 >> 4) & 0x0f);
- break;
- case 19200:
- control[0] = ACT200L_REG8 | (ACT200L_19200 & 0x0f);
- control[1] = ACT200L_REG9 | ((ACT200L_19200 >> 4) & 0x0f);
- break;
- case 38400:
- control[0] = ACT200L_REG8 | (ACT200L_38400 & 0x0f);
- control[1] = ACT200L_REG9 | ((ACT200L_38400 >> 4) & 0x0f);
- break;
- case 57600:
- control[0] = ACT200L_REG8 | (ACT200L_57600 & 0x0f);
- control[1] = ACT200L_REG9 | ((ACT200L_57600 >> 4) & 0x0f);
- break;
- case 115200:
- control[0] = ACT200L_REG8 | (ACT200L_115200 & 0x0f);
- control[1] = ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f);
- break;
- }
- control[2] = ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE;
-
- /* Write control bytes */
- sirdev_raw_write(dev, control, 3);
- msleep(5);
-
- /* Go back to normal mode */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- dev->speed = speed;
- return ret;
-}
-
-/*
- * Function act200l_reset (driver)
- *
- * Reset the ACTiSYS ACT-IR200L type dongle.
- */
-
-#define ACT200L_STATE_WAIT1_RESET (SIRDEV_STATE_DONGLE_RESET+1)
-#define ACT200L_STATE_WAIT2_RESET (SIRDEV_STATE_DONGLE_RESET+2)
-
-static int act200l_reset(struct sir_dev *dev)
-{
- unsigned state = dev->fsm.substate;
- unsigned delay = 0;
- static const u8 control[9] = {
- ACT200L_REG15,
- ACT200L_REG13 | ACT200L_SHDW,
- ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL,
- ACT200L_REG13,
- ACT200L_REG7 | ACT200L_ENPOS,
- ACT200L_REG6 | ACT200L_RS0 | ACT200L_RS1,
- ACT200L_REG5 | ACT200L_RWIDL,
- ACT200L_REG4 | ACT200L_OP0 | ACT200L_OP1 | ACT200L_BLKR,
- ACT200L_REG0 | ACT200L_TXEN | ACT200L_RXEN
- };
- int ret = 0;
-
- switch (state) {
- case SIRDEV_STATE_DONGLE_RESET:
- /* Reset the dongle : set RTS low for 25 ms */
- sirdev_set_dtr_rts(dev, TRUE, FALSE);
- state = ACT200L_STATE_WAIT1_RESET;
- delay = 50;
- break;
-
- case ACT200L_STATE_WAIT1_RESET:
- /* Clear DTR and set RTS to enter command mode */
- sirdev_set_dtr_rts(dev, FALSE, TRUE);
-
- udelay(25); /* better wait for some short while */
-
- /* Write control bytes */
- sirdev_raw_write(dev, control, sizeof(control));
- state = ACT200L_STATE_WAIT2_RESET;
- delay = 15;
- break;
-
- case ACT200L_STATE_WAIT2_RESET:
- /* Go back to normal mode */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
- dev->speed = 9600;
- break;
- default:
- net_err_ratelimited("%s(), unknown state %d\n",
- __func__, state);
- ret = -1;
- break;
- }
- dev->fsm.substate = state;
- return (delay > 0) ? delay : ret;
-}
-
-MODULE_AUTHOR("SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>");
-MODULE_DESCRIPTION("ACTiSYS ACT-IR200L dongle driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-10"); /* IRDA_ACT200L_DONGLE */
-
-module_init(act200l_sir_init);
-module_exit(act200l_sir_cleanup);
diff --git a/drivers/staging/irda/drivers/actisys-sir.c b/drivers/staging/irda/drivers/actisys-sir.c
deleted file mode 100644
index e224b8b99517..000000000000
--- a/drivers/staging/irda/drivers/actisys-sir.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/*********************************************************************
- *
- * Filename: actisys.c
- * Version: 1.1
- * Description: Implementation for the ACTiSYS IR-220L and IR-220L+
- * dongles
- * Status: Beta.
- * Authors: Dag Brattli <dagb@cs.uit.no> (initially)
- * Jean Tourrilhes <jt@hpl.hp.com> (new version)
- * Martin Diehl <mad@mdiehl.de> (new version for sir_dev)
- * Created at: Wed Oct 21 20:02:35 1998
- * Modified at: Sun Oct 27 22:02:13 2002
- * Modified by: Martin Diehl <mad@mdiehl.de>
- *
- * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
- * Copyright (c) 1999 Jean Tourrilhes
- * Copyright (c) 2002 Martin Diehl
- *
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-/*
- * Changelog
- *
- * 0.8 -> 0.9999 - Jean
- * o New initialisation procedure : much safer and correct
- * o New procedure the change speed : much faster and simpler
- * o Other cleanups & comments
- * Thanks to Lichen Wang @ Actisys for his excellent help...
- *
- * 1.0 -> 1.1 - Martin Diehl
- * modified for new sir infrastructure
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-
-#include "sir-dev.h"
-
-/*
- * Define the timing of the pulses we send to the dongle (to reset it, and
- * to toggle speeds). Basically, the limit here is the propagation speed of
- * the signals through the serial port, the dongle being much faster. Any
- * serial port support 115 kb/s, so we are sure that pulses 8.5 us wide can
- * go through cleanly . If you are on the wild side, you can try to lower
- * this value (Actisys recommended me 2 us, and 0 us work for me on a P233!)
- */
-#define MIN_DELAY 10 /* 10 us to be on the conservative side */
-
-static int actisys_open(struct sir_dev *);
-static int actisys_close(struct sir_dev *);
-static int actisys_change_speed(struct sir_dev *, unsigned);
-static int actisys_reset(struct sir_dev *);
-
-/* These are the baudrates supported, in the order available */
-/* Note : the 220L doesn't support 38400, but we will fix that below */
-static unsigned baud_rates[] = { 9600, 19200, 57600, 115200, 38400 };
-
-#define MAX_SPEEDS ARRAY_SIZE(baud_rates)
-
-static struct dongle_driver act220l = {
- .owner = THIS_MODULE,
- .driver_name = "Actisys ACT-220L",
- .type = IRDA_ACTISYS_DONGLE,
- .open = actisys_open,
- .close = actisys_close,
- .reset = actisys_reset,
- .set_speed = actisys_change_speed,
-};
-
-static struct dongle_driver act220l_plus = {
- .owner = THIS_MODULE,
- .driver_name = "Actisys ACT-220L+",
- .type = IRDA_ACTISYS_PLUS_DONGLE,
- .open = actisys_open,
- .close = actisys_close,
- .reset = actisys_reset,
- .set_speed = actisys_change_speed,
-};
-
-static int __init actisys_sir_init(void)
-{
- int ret;
-
- /* First, register an Actisys 220L dongle */
- ret = irda_register_dongle(&act220l);
- if (ret < 0)
- return ret;
-
- /* Now, register an Actisys 220L+ dongle */
- ret = irda_register_dongle(&act220l_plus);
- if (ret < 0) {
- irda_unregister_dongle(&act220l);
- return ret;
- }
- return 0;
-}
-
-static void __exit actisys_sir_cleanup(void)
-{
- /* We have to remove both dongles */
- irda_unregister_dongle(&act220l_plus);
- irda_unregister_dongle(&act220l);
-}
-
-static int actisys_open(struct sir_dev *dev)
-{
- struct qos_info *qos = &dev->qos;
-
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- /* Set the speeds we can accept */
- qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
-
- /* Remove support for 38400 if this is not a 220L+ dongle */
- if (dev->dongle_drv->type == IRDA_ACTISYS_DONGLE)
- qos->baud_rate.bits &= ~IR_38400;
-
- qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */
- irda_qos_bits_to_value(qos);
-
- /* irda thread waits 50 msec for power settling */
-
- return 0;
-}
-
-static int actisys_close(struct sir_dev *dev)
-{
- /* Power off the dongle */
- sirdev_set_dtr_rts(dev, FALSE, FALSE);
-
- return 0;
-}
-
-/*
- * Function actisys_change_speed (task)
- *
- * Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles.
- * To cycle through the available baud rates, pulse RTS low for a few us.
- *
- * First, we reset the dongle to always start from a known state.
- * Then, we cycle through the speeds by pulsing RTS low and then up.
- * The dongle allow us to pulse quite fast, se we can set speed in one go,
- * which is must faster ( < 100 us) and less complex than what is found
- * in some other dongle drivers...
- * Note that even if the new speed is the same as the current speed,
- * we reassert the speed. This make sure that things are all right,
- * and it's fast anyway...
- * By the way, this function will work for both type of dongles,
- * because the additional speed is at the end of the sequence...
- */
-static int actisys_change_speed(struct sir_dev *dev, unsigned speed)
-{
- int ret = 0;
- int i = 0;
-
- pr_debug("%s(), speed=%d (was %d)\n", __func__, speed, dev->speed);
-
- /* dongle was already resetted from irda_request state machine,
- * we are in known state (dongle default)
- */
-
- /*
- * Now, we can set the speed requested. Send RTS pulses until we
- * reach the target speed
- */
- for (i = 0; i < MAX_SPEEDS; i++) {
- if (speed == baud_rates[i]) {
- dev->speed = speed;
- break;
- }
- /* Set RTS low for 10 us */
- sirdev_set_dtr_rts(dev, TRUE, FALSE);
- udelay(MIN_DELAY);
-
- /* Set RTS high for 10 us */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
- udelay(MIN_DELAY);
- }
-
- /* Check if life is sweet... */
- if (i >= MAX_SPEEDS) {
- actisys_reset(dev);
- ret = -EINVAL; /* This should not happen */
- }
-
- /* Basta lavoro, on se casse d'ici... */
- return ret;
-}
-
-/*
- * Function actisys_reset (task)
- *
- * Reset the Actisys type dongle. Warning, this function must only be
- * called with a process context!
- *
- * We need to do two things in this function :
- * o first make sure that the dongle is in a state where it can operate
- * o second put the dongle in a know state
- *
- * The dongle is powered of the RTS and DTR lines. In the dongle, there
- * is a big capacitor to accommodate the current spikes. This capacitor
- * takes a least 50 ms to be charged. In theory, the Bios set those lines
- * up, so by the time we arrive here we should be set. It doesn't hurt
- * to be on the conservative side, so we will wait...
- * <Martin : move above comment to irda_config_fsm>
- * Then, we set the speed to 9600 b/s to get in a known state (see in
- * change_speed for details). It is needed because the IrDA stack
- * has tried to set the speed immediately after our first return,
- * so before we can be sure the dongle is up and running.
- */
-
-static int actisys_reset(struct sir_dev *dev)
-{
- /* Reset the dongle : set DTR low for 10 us */
- sirdev_set_dtr_rts(dev, FALSE, TRUE);
- udelay(MIN_DELAY);
-
- /* Go back to normal mode */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- dev->speed = 9600; /* That's the default */
-
- return 0;
-}
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no> - Jean Tourrilhes <jt@hpl.hp.com>");
-MODULE_DESCRIPTION("ACTiSYS IR-220L and IR-220L+ dongle driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-2"); /* IRDA_ACTISYS_DONGLE */
-MODULE_ALIAS("irda-dongle-3"); /* IRDA_ACTISYS_PLUS_DONGLE */
-
-module_init(actisys_sir_init);
-module_exit(actisys_sir_cleanup);
diff --git a/drivers/staging/irda/drivers/ali-ircc.c b/drivers/staging/irda/drivers/ali-ircc.c
deleted file mode 100644
index 589cd01797f4..000000000000
--- a/drivers/staging/irda/drivers/ali-ircc.c
+++ /dev/null
@@ -1,2217 +0,0 @@
-/*********************************************************************
- *
- * Filename: ali-ircc.h
- * Version: 0.5
- * Description: Driver for the ALI M1535D and M1543C FIR Controller
- * Status: Experimental.
- * Author: Benjamin Kong <benjamin_kong@ali.com.tw>
- * Created at: 2000/10/16 03:46PM
- * Modified at: 2001/1/3 02:55PM
- * Modified by: Benjamin Kong <benjamin_kong@ali.com.tw>
- * Modified at: 2003/11/6 and support for ALi south-bridge chipsets M1563
- * Modified by: Clear Zhang <clear_zhang@ali.com.tw>
- *
- * Copyright (c) 2000 Benjamin Kong <benjamin_kong@ali.com.tw>
- * 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.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/gfp.h>
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/rtnetlink.h>
-#include <linux/serial_reg.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-
-#include <net/irda/wrapper.h>
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-
-#include "ali-ircc.h"
-
-#define CHIP_IO_EXTENT 8
-#define BROKEN_DONGLE_ID
-
-#define ALI_IRCC_DRIVER_NAME "ali-ircc"
-
-/* Power Management */
-static int ali_ircc_suspend(struct platform_device *dev, pm_message_t state);
-static int ali_ircc_resume(struct platform_device *dev);
-
-static struct platform_driver ali_ircc_driver = {
- .suspend = ali_ircc_suspend,
- .resume = ali_ircc_resume,
- .driver = {
- .name = ALI_IRCC_DRIVER_NAME,
- },
-};
-
-/* Module parameters */
-static int qos_mtt_bits = 0x07; /* 1 ms or more */
-
-/* Use BIOS settions by default, but user may supply module parameters */
-static unsigned int io[] = { ~0, ~0, ~0, ~0 };
-static unsigned int irq[] = { 0, 0, 0, 0 };
-static unsigned int dma[] = { 0, 0, 0, 0 };
-
-static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info);
-static int ali_ircc_init_43(ali_chip_t *chip, chipio_t *info);
-static int ali_ircc_init_53(ali_chip_t *chip, chipio_t *info);
-
-/* These are the currently known ALi south-bridge chipsets, the only one difference
- * is that M1543C doesn't support HP HDSL-3600
- */
-static ali_chip_t chips[] =
-{
- { "M1543", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x43, ali_ircc_probe_53, ali_ircc_init_43 },
- { "M1535", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x53, ali_ircc_probe_53, ali_ircc_init_53 },
- { "M1563", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x63, ali_ircc_probe_53, ali_ircc_init_53 },
- { NULL }
-};
-
-/* Max 4 instances for now */
-static struct ali_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL };
-
-/* Dongle Types */
-static char *dongle_types[] = {
- "TFDS6000",
- "HP HSDL-3600",
- "HP HSDL-1100",
- "No dongle connected",
-};
-
-/* Some prototypes */
-static int ali_ircc_open(int i, chipio_t *info);
-
-static int ali_ircc_close(struct ali_ircc_cb *self);
-
-static int ali_ircc_setup(chipio_t *info);
-static int ali_ircc_is_receiving(struct ali_ircc_cb *self);
-static int ali_ircc_net_open(struct net_device *dev);
-static int ali_ircc_net_close(struct net_device *dev);
-static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud);
-
-/* SIR function */
-static netdev_tx_t ali_ircc_sir_hard_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static irqreturn_t ali_ircc_sir_interrupt(struct ali_ircc_cb *self);
-static void ali_ircc_sir_receive(struct ali_ircc_cb *self);
-static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self);
-static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len);
-static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed);
-
-/* FIR function */
-static netdev_tx_t ali_ircc_fir_hard_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 speed);
-static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self);
-static int ali_ircc_dma_receive(struct ali_ircc_cb *self);
-static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self);
-static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self);
-static void ali_ircc_dma_xmit(struct ali_ircc_cb *self);
-
-/* My Function */
-static int ali_ircc_read_dongle_id (int i, chipio_t *info);
-static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed);
-
-/* ALi chip function */
-static void SIR2FIR(int iobase);
-static void FIR2SIR(int iobase);
-static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable);
-
-/*
- * Function ali_ircc_init ()
- *
- * Initialize chip. Find out whay kinds of chips we are dealing with
- * and their configuration registers address
- */
-static int __init ali_ircc_init(void)
-{
- ali_chip_t *chip;
- chipio_t info;
- int ret;
- int cfg, cfg_base;
- int reg, revision;
- int i = 0;
-
- ret = platform_driver_register(&ali_ircc_driver);
- if (ret) {
- net_err_ratelimited("%s, Can't register driver!\n",
- ALI_IRCC_DRIVER_NAME);
- return ret;
- }
-
- ret = -ENODEV;
-
- /* Probe for all the ALi chipsets we know about */
- for (chip= chips; chip->name; chip++, i++)
- {
- pr_debug("%s(), Probing for %s ...\n", __func__, chip->name);
-
- /* Try all config registers for this chip */
- for (cfg=0; cfg<2; cfg++)
- {
- cfg_base = chip->cfg[cfg];
- if (!cfg_base)
- continue;
-
- memset(&info, 0, sizeof(chipio_t));
- info.cfg_base = cfg_base;
- info.fir_base = io[i];
- info.dma = dma[i];
- info.irq = irq[i];
-
-
- /* Enter Configuration */
- outb(chip->entr1, cfg_base);
- outb(chip->entr2, cfg_base);
-
- /* Select Logical Device 5 Registers (UART2) */
- outb(0x07, cfg_base);
- outb(0x05, cfg_base+1);
-
- /* Read Chip Identification Register */
- outb(chip->cid_index, cfg_base);
- reg = inb(cfg_base+1);
-
- if (reg == chip->cid_value)
- {
- pr_debug("%s(), Chip found at 0x%03x\n",
- __func__, cfg_base);
-
- outb(0x1F, cfg_base);
- revision = inb(cfg_base+1);
- pr_debug("%s(), Found %s chip, revision=%d\n",
- __func__, chip->name, revision);
-
- /*
- * If the user supplies the base address, then
- * we init the chip, if not we probe the values
- * set by the BIOS
- */
- if (io[i] < 2000)
- {
- chip->init(chip, &info);
- }
- else
- {
- chip->probe(chip, &info);
- }
-
- if (ali_ircc_open(i, &info) == 0)
- ret = 0;
- i++;
- }
- else
- {
- pr_debug("%s(), No %s chip at 0x%03x\n",
- __func__, chip->name, cfg_base);
- }
- /* Exit configuration */
- outb(0xbb, cfg_base);
- }
- }
-
- if (ret)
- platform_driver_unregister(&ali_ircc_driver);
-
- return ret;
-}
-
-/*
- * Function ali_ircc_cleanup ()
- *
- * Close all configured chips
- *
- */
-static void __exit ali_ircc_cleanup(void)
-{
- int i;
-
- for (i=0; i < ARRAY_SIZE(dev_self); i++) {
- if (dev_self[i])
- ali_ircc_close(dev_self[i]);
- }
-
- platform_driver_unregister(&ali_ircc_driver);
-
-}
-
-static const struct net_device_ops ali_ircc_sir_ops = {
- .ndo_open = ali_ircc_net_open,
- .ndo_stop = ali_ircc_net_close,
- .ndo_start_xmit = ali_ircc_sir_hard_xmit,
- .ndo_do_ioctl = ali_ircc_net_ioctl,
-};
-
-static const struct net_device_ops ali_ircc_fir_ops = {
- .ndo_open = ali_ircc_net_open,
- .ndo_stop = ali_ircc_net_close,
- .ndo_start_xmit = ali_ircc_fir_hard_xmit,
- .ndo_do_ioctl = ali_ircc_net_ioctl,
-};
-
-/*
- * Function ali_ircc_open (int i, chipio_t *inf)
- *
- * Open driver instance
- *
- */
-static int ali_ircc_open(int i, chipio_t *info)
-{
- struct net_device *dev;
- struct ali_ircc_cb *self;
- int dongle_id;
- int err;
-
- if (i >= ARRAY_SIZE(dev_self)) {
- net_err_ratelimited("%s(), maximum number of supported chips reached!\n",
- __func__);
- return -ENOMEM;
- }
-
- /* Set FIR FIFO and DMA Threshold */
- if ((ali_ircc_setup(info)) == -1)
- return -1;
-
- dev = alloc_irdadev(sizeof(*self));
- if (dev == NULL) {
- net_err_ratelimited("%s(), can't allocate memory for control block!\n",
- __func__);
- return -ENOMEM;
- }
-
- self = netdev_priv(dev);
- self->netdev = dev;
- spin_lock_init(&self->lock);
-
- /* Need to store self somewhere */
- dev_self[i] = self;
- self->index = i;
-
- /* Initialize IO */
- self->io.cfg_base = info->cfg_base; /* In ali_ircc_probe_53 assign */
- self->io.fir_base = info->fir_base; /* info->sir_base = info->fir_base */
- self->io.sir_base = info->sir_base; /* ALi SIR and FIR use the same address */
- self->io.irq = info->irq;
- self->io.fir_ext = CHIP_IO_EXTENT;
- self->io.dma = info->dma;
- self->io.fifo_size = 16; /* SIR: 16, FIR: 32 Benjamin 2000/11/1 */
-
- /* Reserve the ioports that we need */
- if (!request_region(self->io.fir_base, self->io.fir_ext,
- ALI_IRCC_DRIVER_NAME)) {
- net_warn_ratelimited("%s(), can't get iobase of 0x%03x\n",
- __func__, self->io.fir_base);
- err = -ENODEV;
- goto err_out1;
- }
-
- /* Initialize QoS for this device */
- irda_init_max_qos_capabilies(&self->qos);
-
- /* The only value we must override it the baudrate */
- self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
- IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); // benjamin 2000/11/8 05:27PM
-
- self->qos.min_turn_time.bits = qos_mtt_bits;
-
- irda_qos_bits_to_value(&self->qos);
-
- /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
- self->rx_buff.truesize = 14384;
- self->tx_buff.truesize = 14384;
-
- /* Allocate memory if needed */
- self->rx_buff.head =
- dma_zalloc_coherent(NULL, self->rx_buff.truesize,
- &self->rx_buff_dma, GFP_KERNEL);
- if (self->rx_buff.head == NULL) {
- err = -ENOMEM;
- goto err_out2;
- }
-
- self->tx_buff.head =
- dma_zalloc_coherent(NULL, self->tx_buff.truesize,
- &self->tx_buff_dma, GFP_KERNEL);
- if (self->tx_buff.head == NULL) {
- err = -ENOMEM;
- goto err_out3;
- }
-
- self->rx_buff.in_frame = FALSE;
- self->rx_buff.state = OUTSIDE_FRAME;
- self->tx_buff.data = self->tx_buff.head;
- self->rx_buff.data = self->rx_buff.head;
-
- /* Reset Tx queue info */
- self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
- self->tx_fifo.tail = self->tx_buff.head;
-
- /* Override the network functions we need to use */
- dev->netdev_ops = &ali_ircc_sir_ops;
-
- err = register_netdev(dev);
- if (err) {
- net_err_ratelimited("%s(), register_netdev() failed!\n",
- __func__);
- goto err_out4;
- }
- net_info_ratelimited("IrDA: Registered device %s\n", dev->name);
-
- /* Check dongle id */
- dongle_id = ali_ircc_read_dongle_id(i, info);
- net_info_ratelimited("%s(), %s, Found dongle: %s\n",
- __func__, ALI_IRCC_DRIVER_NAME,
- dongle_types[dongle_id]);
-
- self->io.dongle_id = dongle_id;
-
-
- return 0;
-
- err_out4:
- dma_free_coherent(NULL, self->tx_buff.truesize,
- self->tx_buff.head, self->tx_buff_dma);
- err_out3:
- dma_free_coherent(NULL, self->rx_buff.truesize,
- self->rx_buff.head, self->rx_buff_dma);
- err_out2:
- release_region(self->io.fir_base, self->io.fir_ext);
- err_out1:
- dev_self[i] = NULL;
- free_netdev(dev);
- return err;
-}
-
-
-/*
- * Function ali_ircc_close (self)
- *
- * Close driver instance
- *
- */
-static int __exit ali_ircc_close(struct ali_ircc_cb *self)
-{
- int iobase;
-
- IRDA_ASSERT(self != NULL, return -1;);
-
- iobase = self->io.fir_base;
-
- /* Remove netdevice */
- unregister_netdev(self->netdev);
-
- /* Release the PORT that this driver is using */
- pr_debug("%s(), Releasing Region %03x\n", __func__, self->io.fir_base);
- release_region(self->io.fir_base, self->io.fir_ext);
-
- if (self->tx_buff.head)
- dma_free_coherent(NULL, self->tx_buff.truesize,
- self->tx_buff.head, self->tx_buff_dma);
-
- if (self->rx_buff.head)
- dma_free_coherent(NULL, self->rx_buff.truesize,
- self->rx_buff.head, self->rx_buff_dma);
-
- dev_self[self->index] = NULL;
- free_netdev(self->netdev);
-
-
- return 0;
-}
-
-/*
- * Function ali_ircc_init_43 (chip, info)
- *
- * Initialize the ALi M1543 chip.
- */
-static int ali_ircc_init_43(ali_chip_t *chip, chipio_t *info)
-{
- /* All controller information like I/O address, DMA channel, IRQ
- * are set by BIOS
- */
-
- return 0;
-}
-
-/*
- * Function ali_ircc_init_53 (chip, info)
- *
- * Initialize the ALi M1535 chip.
- */
-static int ali_ircc_init_53(ali_chip_t *chip, chipio_t *info)
-{
- /* All controller information like I/O address, DMA channel, IRQ
- * are set by BIOS
- */
-
- return 0;
-}
-
-/*
- * Function ali_ircc_probe_53 (chip, info)
- *
- * Probes for the ALi M1535D or M1535
- */
-static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info)
-{
- int cfg_base = info->cfg_base;
- int hi, low, reg;
-
-
- /* Enter Configuration */
- outb(chip->entr1, cfg_base);
- outb(chip->entr2, cfg_base);
-
- /* Select Logical Device 5 Registers (UART2) */
- outb(0x07, cfg_base);
- outb(0x05, cfg_base+1);
-
- /* Read address control register */
- outb(0x60, cfg_base);
- hi = inb(cfg_base+1);
- outb(0x61, cfg_base);
- low = inb(cfg_base+1);
- info->fir_base = (hi<<8) + low;
-
- info->sir_base = info->fir_base;
-
- pr_debug("%s(), probing fir_base=0x%03x\n", __func__, info->fir_base);
-
- /* Read IRQ control register */
- outb(0x70, cfg_base);
- reg = inb(cfg_base+1);
- info->irq = reg & 0x0f;
- pr_debug("%s(), probing irq=%d\n", __func__, info->irq);
-
- /* Read DMA channel */
- outb(0x74, cfg_base);
- reg = inb(cfg_base+1);
- info->dma = reg & 0x07;
-
- if(info->dma == 0x04)
- net_warn_ratelimited("%s(), No DMA channel assigned !\n",
- __func__);
- else
- pr_debug("%s(), probing dma=%d\n", __func__, info->dma);
-
- /* Read Enabled Status */
- outb(0x30, cfg_base);
- reg = inb(cfg_base+1);
- info->enabled = (reg & 0x80) && (reg & 0x01);
- pr_debug("%s(), probing enabled=%d\n", __func__, info->enabled);
-
- /* Read Power Status */
- outb(0x22, cfg_base);
- reg = inb(cfg_base+1);
- info->suspended = (reg & 0x20);
- pr_debug("%s(), probing suspended=%d\n", __func__, info->suspended);
-
- /* Exit configuration */
- outb(0xbb, cfg_base);
-
-
- return 0;
-}
-
-/*
- * Function ali_ircc_setup (info)
- *
- * Set FIR FIFO and DMA Threshold
- * Returns non-negative on success.
- *
- */
-static int ali_ircc_setup(chipio_t *info)
-{
- unsigned char tmp;
- int version;
- int iobase = info->fir_base;
-
-
- /* Locking comments :
- * Most operations here need to be protected. We are called before
- * the device instance is created in ali_ircc_open(), therefore
- * nobody can bother us - Jean II */
-
- /* Switch to FIR space */
- SIR2FIR(iobase);
-
- /* Master Reset */
- outb(0x40, iobase+FIR_MCR); // benjamin 2000/11/30 11:45AM
-
- /* Read FIR ID Version Register */
- switch_bank(iobase, BANK3);
- version = inb(iobase+FIR_ID_VR);
-
- /* Should be 0x00 in the M1535/M1535D */
- if(version != 0x00)
- {
- net_err_ratelimited("%s, Wrong chip version %02x\n",
- ALI_IRCC_DRIVER_NAME, version);
- return -1;
- }
-
- /* Set FIR FIFO Threshold Register */
- switch_bank(iobase, BANK1);
- outb(RX_FIFO_Threshold, iobase+FIR_FIFO_TR);
-
- /* Set FIR DMA Threshold Register */
- outb(RX_DMA_Threshold, iobase+FIR_DMA_TR);
-
- /* CRC enable */
- switch_bank(iobase, BANK2);
- outb(inb(iobase+FIR_IRDA_CR) | IRDA_CR_CRC, iobase+FIR_IRDA_CR);
-
- /* NDIS driver set TX Length here BANK2 Alias 3, Alias4*/
-
- /* Switch to Bank 0 */
- switch_bank(iobase, BANK0);
-
- tmp = inb(iobase+FIR_LCR_B);
- tmp &=~0x20; // disable SIP
- tmp |= 0x80; // these two steps make RX mode
- tmp &= 0xbf;
- outb(tmp, iobase+FIR_LCR_B);
-
- /* Disable Interrupt */
- outb(0x00, iobase+FIR_IER);
-
-
- /* Switch to SIR space */
- FIR2SIR(iobase);
-
- net_info_ratelimited("%s, driver loaded (Benjamin Kong)\n",
- ALI_IRCC_DRIVER_NAME);
-
- /* Enable receive interrupts */
- // outb(UART_IER_RDI, iobase+UART_IER); //benjamin 2000/11/23 01:25PM
- // Turn on the interrupts in ali_ircc_net_open
-
-
- return 0;
-}
-
-/*
- * Function ali_ircc_read_dongle_id (int index, info)
- *
- * Try to read dongle identification. This procedure needs to be executed
- * once after power-on/reset. It also needs to be used whenever you suspect
- * that the user may have plugged/unplugged the IrDA Dongle.
- */
-static int ali_ircc_read_dongle_id (int i, chipio_t *info)
-{
- int dongle_id, reg;
- int cfg_base = info->cfg_base;
-
-
- /* Enter Configuration */
- outb(chips[i].entr1, cfg_base);
- outb(chips[i].entr2, cfg_base);
-
- /* Select Logical Device 5 Registers (UART2) */
- outb(0x07, cfg_base);
- outb(0x05, cfg_base+1);
-
- /* Read Dongle ID */
- outb(0xf0, cfg_base);
- reg = inb(cfg_base+1);
- dongle_id = ((reg>>6)&0x02) | ((reg>>5)&0x01);
- pr_debug("%s(), probing dongle_id=%d, dongle_types=%s\n",
- __func__, dongle_id, dongle_types[dongle_id]);
-
- /* Exit configuration */
- outb(0xbb, cfg_base);
-
-
- return dongle_id;
-}
-
-/*
- * Function ali_ircc_interrupt (irq, dev_id, regs)
- *
- * An interrupt from the chip has arrived. Time to do some work
- *
- */
-static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct ali_ircc_cb *self;
- int ret;
-
-
- self = netdev_priv(dev);
-
- spin_lock(&self->lock);
-
- /* Dispatch interrupt handler for the current speed */
- if (self->io.speed > 115200)
- ret = ali_ircc_fir_interrupt(self);
- else
- ret = ali_ircc_sir_interrupt(self);
-
- spin_unlock(&self->lock);
-
- return ret;
-}
-/*
- * Function ali_ircc_fir_interrupt(irq, struct ali_ircc_cb *self)
- *
- * Handle MIR/FIR interrupt
- *
- */
-static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self)
-{
- __u8 eir, OldMessageCount;
- int iobase, tmp;
-
-
- iobase = self->io.fir_base;
-
- switch_bank(iobase, BANK0);
- self->InterruptID = inb(iobase+FIR_IIR);
- self->BusStatus = inb(iobase+FIR_BSR);
-
- OldMessageCount = (self->LineStatus + 1) & 0x07;
- self->LineStatus = inb(iobase+FIR_LSR);
- //self->ier = inb(iobase+FIR_IER); 2000/12/1 04:32PM
- eir = self->InterruptID & self->ier; /* Mask out the interesting ones */
-
- pr_debug("%s(), self->InterruptID = %x\n", __func__, self->InterruptID);
- pr_debug("%s(), self->LineStatus = %x\n", __func__, self->LineStatus);
- pr_debug("%s(), self->ier = %x\n", __func__, self->ier);
- pr_debug("%s(), eir = %x\n", __func__, eir);
-
- /* Disable interrupts */
- SetCOMInterrupts(self, FALSE);
-
- /* Tx or Rx Interrupt */
-
- if (eir & IIR_EOM)
- {
- if (self->io.direction == IO_XMIT) /* TX */
- {
- pr_debug("%s(), ******* IIR_EOM (Tx) *******\n",
- __func__);
-
- if(ali_ircc_dma_xmit_complete(self))
- {
- if (irda_device_txqueue_empty(self->netdev))
- {
- /* Prepare for receive */
- ali_ircc_dma_receive(self);
- self->ier = IER_EOM;
- }
- }
- else
- {
- self->ier = IER_EOM;
- }
-
- }
- else /* RX */
- {
- pr_debug("%s(), ******* IIR_EOM (Rx) *******\n",
- __func__);
-
- if(OldMessageCount > ((self->LineStatus+1) & 0x07))
- {
- self->rcvFramesOverflow = TRUE;
- pr_debug("%s(), ******* self->rcvFramesOverflow = TRUE ********\n",
- __func__);
- }
-
- if (ali_ircc_dma_receive_complete(self))
- {
- pr_debug("%s(), ******* receive complete ********\n",
- __func__);
-
- self->ier = IER_EOM;
- }
- else
- {
- pr_debug("%s(), ******* Not receive complete ********\n",
- __func__);
-
- self->ier = IER_EOM | IER_TIMER;
- }
-
- }
- }
- /* Timer Interrupt */
- else if (eir & IIR_TIMER)
- {
- if(OldMessageCount > ((self->LineStatus+1) & 0x07))
- {
- self->rcvFramesOverflow = TRUE;
- pr_debug("%s(), ******* self->rcvFramesOverflow = TRUE *******\n",
- __func__);
- }
- /* Disable Timer */
- switch_bank(iobase, BANK1);
- tmp = inb(iobase+FIR_CR);
- outb( tmp& ~CR_TIMER_EN, iobase+FIR_CR);
-
- /* Check if this is a Tx timer interrupt */
- if (self->io.direction == IO_XMIT)
- {
- ali_ircc_dma_xmit(self);
-
- /* Interrupt on EOM */
- self->ier = IER_EOM;
-
- }
- else /* Rx */
- {
- if(ali_ircc_dma_receive_complete(self))
- {
- self->ier = IER_EOM;
- }
- else
- {
- self->ier = IER_EOM | IER_TIMER;
- }
- }
- }
-
- /* Restore Interrupt */
- SetCOMInterrupts(self, TRUE);
-
- return IRQ_RETVAL(eir);
-}
-
-/*
- * Function ali_ircc_sir_interrupt (irq, self, eir)
- *
- * Handle SIR interrupt
- *
- */
-static irqreturn_t ali_ircc_sir_interrupt(struct ali_ircc_cb *self)
-{
- int iobase;
- int iir, lsr;
-
-
- iobase = self->io.sir_base;
-
- iir = inb(iobase+UART_IIR) & UART_IIR_ID;
- if (iir) {
- /* Clear interrupt */
- lsr = inb(iobase+UART_LSR);
-
- pr_debug("%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
- __func__, iir, lsr, iobase);
-
- switch (iir)
- {
- case UART_IIR_RLSI:
- pr_debug("%s(), RLSI\n", __func__);
- break;
- case UART_IIR_RDI:
- /* Receive interrupt */
- ali_ircc_sir_receive(self);
- break;
- case UART_IIR_THRI:
- if (lsr & UART_LSR_THRE)
- {
- /* Transmitter ready for data */
- ali_ircc_sir_write_wakeup(self);
- }
- break;
- default:
- pr_debug("%s(), unhandled IIR=%#x\n",
- __func__, iir);
- break;
- }
-
- }
-
-
- return IRQ_RETVAL(iir);
-}
-
-
-/*
- * Function ali_ircc_sir_receive (self)
- *
- * Receive one frame from the infrared port
- *
- */
-static void ali_ircc_sir_receive(struct ali_ircc_cb *self)
-{
- int boguscount = 0;
- int iobase;
-
- IRDA_ASSERT(self != NULL, return;);
-
- iobase = self->io.sir_base;
-
- /*
- * Receive all characters in Rx FIFO, unwrap and unstuff them.
- * async_unwrap_char will deliver all found frames
- */
- do {
- async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff,
- inb(iobase+UART_RX));
-
- /* Make sure we don't stay here too long */
- if (boguscount++ > 32) {
- pr_debug("%s(), breaking!\n", __func__);
- break;
- }
- } while (inb(iobase+UART_LSR) & UART_LSR_DR);
-
-}
-
-/*
- * Function ali_ircc_sir_write_wakeup (tty)
- *
- * Called by the driver when there's room for more data. If we have
- * more packets to send, we send them here.
- *
- */
-static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self)
-{
- int actual = 0;
- int iobase;
-
- IRDA_ASSERT(self != NULL, return;);
-
-
- iobase = self->io.sir_base;
-
- /* Finished with frame? */
- if (self->tx_buff.len > 0)
- {
- /* Write data left in transmit buffer */
- actual = ali_ircc_sir_write(iobase, self->io.fifo_size,
- self->tx_buff.data, self->tx_buff.len);
- self->tx_buff.data += actual;
- self->tx_buff.len -= actual;
- }
- else
- {
- if (self->new_speed)
- {
- /* We must wait until all data are gone */
- while(!(inb(iobase+UART_LSR) & UART_LSR_TEMT))
- pr_debug("%s(), UART_LSR_THRE\n", __func__);
-
- pr_debug("%s(), Changing speed! self->new_speed = %d\n",
- __func__, self->new_speed);
- ali_ircc_change_speed(self, self->new_speed);
- self->new_speed = 0;
-
- // benjamin 2000/11/10 06:32PM
- if (self->io.speed > 115200)
- {
- pr_debug("%s(), ali_ircc_change_speed from UART_LSR_TEMT\n",
- __func__);
-
- self->ier = IER_EOM;
- // SetCOMInterrupts(self, TRUE);
- return;
- }
- }
- else
- {
- netif_wake_queue(self->netdev);
- }
-
- self->netdev->stats.tx_packets++;
-
- /* Turn on receive interrupts */
- outb(UART_IER_RDI, iobase+UART_IER);
- }
-
-}
-
-static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud)
-{
- struct net_device *dev = self->netdev;
- int iobase;
-
-
- pr_debug("%s(), setting speed = %d\n", __func__, baud);
-
- /* This function *must* be called with irq off and spin-lock.
- * - Jean II */
-
- iobase = self->io.fir_base;
-
- SetCOMInterrupts(self, FALSE); // 2000/11/24 11:43AM
-
- /* Go to MIR, FIR Speed */
- if (baud > 115200)
- {
-
-
- ali_ircc_fir_change_speed(self, baud);
-
- /* Install FIR xmit handler*/
- dev->netdev_ops = &ali_ircc_fir_ops;
-
- /* Enable Interuupt */
- self->ier = IER_EOM; // benjamin 2000/11/20 07:24PM
-
- /* Be ready for incoming frames */
- ali_ircc_dma_receive(self); // benajmin 2000/11/8 07:46PM not complete
- }
- /* Go to SIR Speed */
- else
- {
- ali_ircc_sir_change_speed(self, baud);
-
- /* Install SIR xmit handler*/
- dev->netdev_ops = &ali_ircc_sir_ops;
- }
-
-
- SetCOMInterrupts(self, TRUE); // 2000/11/24 11:43AM
-
- netif_wake_queue(self->netdev);
-
-}
-
-static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 baud)
-{
-
- int iobase;
- struct ali_ircc_cb *self = priv;
- struct net_device *dev;
-
-
- IRDA_ASSERT(self != NULL, return;);
-
- dev = self->netdev;
- iobase = self->io.fir_base;
-
- pr_debug("%s(), self->io.speed = %d, change to speed = %d\n",
- __func__, self->io.speed, baud);
-
- /* Come from SIR speed */
- if(self->io.speed <=115200)
- {
- SIR2FIR(iobase);
- }
-
- /* Update accounting for new speed */
- self->io.speed = baud;
-
- // Set Dongle Speed mode
- ali_ircc_change_dongle_speed(self, baud);
-
-}
-
-/*
- * Function ali_sir_change_speed (self, speed)
- *
- * Set speed of IrDA port to specified baudrate
- *
- */
-static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed)
-{
- struct ali_ircc_cb *self = priv;
- int iobase;
- int fcr; /* FIFO control reg */
- int lcr; /* Line control reg */
- int divisor;
-
-
- pr_debug("%s(), Setting speed to: %d\n", __func__, speed);
-
- IRDA_ASSERT(self != NULL, return;);
-
- iobase = self->io.sir_base;
-
- /* Come from MIR or FIR speed */
- if(self->io.speed >115200)
- {
- // Set Dongle Speed mode first
- ali_ircc_change_dongle_speed(self, speed);
-
- FIR2SIR(iobase);
- }
-
- // Clear Line and Auxiluary status registers 2000/11/24 11:47AM
-
- inb(iobase+UART_LSR);
- inb(iobase+UART_SCR);
-
- /* Update accounting for new speed */
- self->io.speed = speed;
-
- divisor = 115200/speed;
-
- fcr = UART_FCR_ENABLE_FIFO;
-
- /*
- * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
- * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
- * about this timeout since it will always be fast enough.
- */
- if (self->io.speed < 38400)
- fcr |= UART_FCR_TRIGGER_1;
- else
- fcr |= UART_FCR_TRIGGER_14;
-
- /* IrDA ports use 8N1 */
- lcr = UART_LCR_WLEN8;
-
- outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */
- outb(divisor & 0xff, iobase+UART_DLL); /* Set speed */
- outb(divisor >> 8, iobase+UART_DLM);
- outb(lcr, iobase+UART_LCR); /* Set 8N1 */
- outb(fcr, iobase+UART_FCR); /* Enable FIFO's */
-
- /* without this, the connection will be broken after come back from FIR speed,
- but with this, the SIR connection is harder to established */
- outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR);
-}
-
-static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed)
-{
-
- struct ali_ircc_cb *self = priv;
- int iobase,dongle_id;
- int tmp = 0;
-
-
- iobase = self->io.fir_base; /* or iobase = self->io.sir_base; */
- dongle_id = self->io.dongle_id;
-
- /* We are already locked, no need to do it again */
-
- pr_debug("%s(), Set Speed for %s , Speed = %d\n",
- __func__, dongle_types[dongle_id], speed);
-
- switch_bank(iobase, BANK2);
- tmp = inb(iobase+FIR_IRDA_CR);
-
- /* IBM type dongle */
- if(dongle_id == 0)
- {
- if(speed == 4000000)
- {
- // __ __
- // SD/MODE __| |__ __
- // __ __
- // IRTX __ __| |__
- // T1 T2 T3 T4 T5
-
- tmp &= ~IRDA_CR_HDLC; // HDLC=0
- tmp |= IRDA_CR_CRC; // CRC=1
-
- switch_bank(iobase, BANK2);
- outb(tmp, iobase+FIR_IRDA_CR);
-
- // T1 -> SD/MODE:0 IRTX:0
- tmp &= ~0x09;
- tmp |= 0x02;
- outb(tmp, iobase+FIR_IRDA_CR);
- udelay(2);
-
- // T2 -> SD/MODE:1 IRTX:0
- tmp &= ~0x01;
- tmp |= 0x0a;
- outb(tmp, iobase+FIR_IRDA_CR);
- udelay(2);
-
- // T3 -> SD/MODE:1 IRTX:1
- tmp |= 0x0b;
- outb(tmp, iobase+FIR_IRDA_CR);
- udelay(2);
-
- // T4 -> SD/MODE:0 IRTX:1
- tmp &= ~0x08;
- tmp |= 0x03;
- outb(tmp, iobase+FIR_IRDA_CR);
- udelay(2);
-
- // T5 -> SD/MODE:0 IRTX:0
- tmp &= ~0x09;
- tmp |= 0x02;
- outb(tmp, iobase+FIR_IRDA_CR);
- udelay(2);
-
- // reset -> Normal TX output Signal
- outb(tmp & ~0x02, iobase+FIR_IRDA_CR);
- }
- else /* speed <=1152000 */
- {
- // __
- // SD/MODE __| |__
- //
- // IRTX ________
- // T1 T2 T3
-
- /* MIR 115200, 57600 */
- if (speed==1152000)
- {
- tmp |= 0xA0; //HDLC=1, 1.152Mbps=1
- }
- else
- {
- tmp &=~0x80; //HDLC 0.576Mbps
- tmp |= 0x20; //HDLC=1,
- }
-
- tmp |= IRDA_CR_CRC; // CRC=1
-
- switch_bank(iobase, BANK2);
- outb(tmp, iobase+FIR_IRDA_CR);
-
- /* MIR 115200, 57600 */
-
- //switch_bank(iobase, BANK2);
- // T1 -> SD/MODE:0 IRTX:0
- tmp &= ~0x09;
- tmp |= 0x02;
- outb(tmp, iobase+FIR_IRDA_CR);
- udelay(2);
-
- // T2 -> SD/MODE:1 IRTX:0
- tmp &= ~0x01;
- tmp |= 0x0a;
- outb(tmp, iobase+FIR_IRDA_CR);
-
- // T3 -> SD/MODE:0 IRTX:0
- tmp &= ~0x09;
- tmp |= 0x02;
- outb(tmp, iobase+FIR_IRDA_CR);
- udelay(2);
-
- // reset -> Normal TX output Signal
- outb(tmp & ~0x02, iobase+FIR_IRDA_CR);
- }
- }
- else if (dongle_id == 1) /* HP HDSL-3600 */
- {
- switch(speed)
- {
- case 4000000:
- tmp &= ~IRDA_CR_HDLC; // HDLC=0
- break;
-
- case 1152000:
- tmp |= 0xA0; // HDLC=1, 1.152Mbps=1
- break;
-
- case 576000:
- tmp &=~0x80; // HDLC 0.576Mbps
- tmp |= 0x20; // HDLC=1,
- break;
- }
-
- tmp |= IRDA_CR_CRC; // CRC=1
-
- switch_bank(iobase, BANK2);
- outb(tmp, iobase+FIR_IRDA_CR);
- }
- else /* HP HDSL-1100 */
- {
- if(speed <= 115200) /* SIR */
- {
-
- tmp &= ~IRDA_CR_FIR_SIN; // HP sin select = 0
-
- switch_bank(iobase, BANK2);
- outb(tmp, iobase+FIR_IRDA_CR);
- }
- else /* MIR FIR */
- {
-
- switch(speed)
- {
- case 4000000:
- tmp &= ~IRDA_CR_HDLC; // HDLC=0
- break;
-
- case 1152000:
- tmp |= 0xA0; // HDLC=1, 1.152Mbps=1
- break;
-
- case 576000:
- tmp &=~0x80; // HDLC 0.576Mbps
- tmp |= 0x20; // HDLC=1,
- break;
- }
-
- tmp |= IRDA_CR_CRC; // CRC=1
- tmp |= IRDA_CR_FIR_SIN; // HP sin select = 1
-
- switch_bank(iobase, BANK2);
- outb(tmp, iobase+FIR_IRDA_CR);
- }
- }
-
- switch_bank(iobase, BANK0);
-
-}
-
-/*
- * Function ali_ircc_sir_write (driver)
- *
- * Fill Tx FIFO with transmit data
- *
- */
-static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len)
-{
- int actual = 0;
-
-
- /* Tx FIFO should be empty! */
- if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
- pr_debug("%s(), failed, fifo not empty!\n", __func__);
- return 0;
- }
-
- /* Fill FIFO with current frame */
- while ((fifo_size-- > 0) && (actual < len)) {
- /* Transmit next byte */
- outb(buf[actual], iobase+UART_TX);
-
- actual++;
- }
-
- return actual;
-}
-
-/*
- * Function ali_ircc_net_open (dev)
- *
- * Start the device
- *
- */
-static int ali_ircc_net_open(struct net_device *dev)
-{
- struct ali_ircc_cb *self;
- int iobase;
- char hwname[32];
-
-
- IRDA_ASSERT(dev != NULL, return -1;);
-
- self = netdev_priv(dev);
-
- IRDA_ASSERT(self != NULL, return 0;);
-
- iobase = self->io.fir_base;
-
- /* Request IRQ and install Interrupt Handler */
- if (request_irq(self->io.irq, ali_ircc_interrupt, 0, dev->name, dev))
- {
- net_warn_ratelimited("%s, unable to allocate irq=%d\n",
- ALI_IRCC_DRIVER_NAME, self->io.irq);
- return -EAGAIN;
- }
-
- /*
- * Always allocate the DMA channel after the IRQ, and clean up on
- * failure.
- */
- if (request_dma(self->io.dma, dev->name)) {
- net_warn_ratelimited("%s, unable to allocate dma=%d\n",
- ALI_IRCC_DRIVER_NAME, self->io.dma);
- free_irq(self->io.irq, dev);
- return -EAGAIN;
- }
-
- /* Turn on interrups */
- outb(UART_IER_RDI , iobase+UART_IER);
-
- /* Ready to play! */
- netif_start_queue(dev); //benjamin by irport
-
- /* Give self a hardware name */
- sprintf(hwname, "ALI-FIR @ 0x%03x", self->io.fir_base);
-
- /*
- * Open new IrLAP layer instance, now that everything should be
- * initialized properly
- */
- self->irlap = irlap_open(dev, &self->qos, hwname);
-
-
- return 0;
-}
-
-/*
- * Function ali_ircc_net_close (dev)
- *
- * Stop the device
- *
- */
-static int ali_ircc_net_close(struct net_device *dev)
-{
-
- struct ali_ircc_cb *self;
- //int iobase;
-
-
- IRDA_ASSERT(dev != NULL, return -1;);
-
- self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
-
- /* Stop device */
- netif_stop_queue(dev);
-
- /* Stop and remove instance of IrLAP */
- if (self->irlap)
- irlap_close(self->irlap);
- self->irlap = NULL;
-
- disable_dma(self->io.dma);
-
- /* Disable interrupts */
- SetCOMInterrupts(self, FALSE);
-
- free_irq(self->io.irq, dev);
- free_dma(self->io.dma);
-
-
- return 0;
-}
-
-/*
- * Function ali_ircc_fir_hard_xmit (skb, dev)
- *
- * Transmit the frame
- *
- */
-static netdev_tx_t ali_ircc_fir_hard_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct ali_ircc_cb *self;
- unsigned long flags;
- int iobase;
- __u32 speed;
- int mtt, diff;
-
-
- self = netdev_priv(dev);
- iobase = self->io.fir_base;
-
- netif_stop_queue(dev);
-
- /* Make sure tests *& speed change are atomic */
- spin_lock_irqsave(&self->lock, flags);
-
- /* Note : you should make sure that speed changes are not going
- * to corrupt any outgoing frame. Look at nsc-ircc for the gory
- * details - Jean II */
-
- /* Check if we need to change the speed */
- speed = irda_get_next_speed(skb);
- if ((speed != self->io.speed) && (speed != -1)) {
- /* Check for empty frame */
- if (!skb->len) {
- ali_ircc_change_speed(self, speed);
- netif_trans_update(dev);
- spin_unlock_irqrestore(&self->lock, flags);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- } else
- self->new_speed = speed;
- }
-
- /* Register and copy this frame to DMA memory */
- self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail;
- self->tx_fifo.queue[self->tx_fifo.free].len = skb->len;
- self->tx_fifo.tail += skb->len;
-
- dev->stats.tx_bytes += skb->len;
-
- skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start,
- skb->len);
- self->tx_fifo.len++;
- self->tx_fifo.free++;
-
- /* Start transmit only if there is currently no transmit going on */
- if (self->tx_fifo.len == 1)
- {
- /* Check if we must wait the min turn time or not */
- mtt = irda_get_mtt(skb);
-
- if (mtt)
- {
- /* Check how much time we have used already */
- diff = ktime_us_delta(ktime_get(), self->stamp);
- /* self->stamp is set from ali_ircc_dma_receive_complete() */
-
- pr_debug("%s(), ******* diff = %d *******\n",
- __func__, diff);
-
- /* Check if the mtt is larger than the time we have
- * already used by all the protocol processing
- */
- if (mtt > diff)
- {
- mtt -= diff;
-
- /*
- * Use timer if delay larger than 1000 us, and
- * use udelay for smaller values which should
- * be acceptable
- */
- if (mtt > 500)
- {
- /* Adjust for timer resolution */
- mtt = (mtt+250) / 500; /* 4 discard, 5 get advanced, Let's round off */
-
- pr_debug("%s(), ************** mtt = %d ***********\n",
- __func__, mtt);
-
- /* Setup timer */
- if (mtt == 1) /* 500 us */
- {
- switch_bank(iobase, BANK1);
- outb(TIMER_IIR_500, iobase+FIR_TIMER_IIR);
- }
- else if (mtt == 2) /* 1 ms */
- {
- switch_bank(iobase, BANK1);
- outb(TIMER_IIR_1ms, iobase+FIR_TIMER_IIR);
- }
- else /* > 2ms -> 4ms */
- {
- switch_bank(iobase, BANK1);
- outb(TIMER_IIR_2ms, iobase+FIR_TIMER_IIR);
- }
-
-
- /* Start timer */
- outb(inb(iobase+FIR_CR) | CR_TIMER_EN, iobase+FIR_CR);
- self->io.direction = IO_XMIT;
-
- /* Enable timer interrupt */
- self->ier = IER_TIMER;
- SetCOMInterrupts(self, TRUE);
-
- /* Timer will take care of the rest */
- goto out;
- }
- else
- udelay(mtt);
- } // if (if (mtt > diff)
- }// if (mtt)
-
- /* Enable EOM interrupt */
- self->ier = IER_EOM;
- SetCOMInterrupts(self, TRUE);
-
- /* Transmit frame */
- ali_ircc_dma_xmit(self);
- } // if (self->tx_fifo.len == 1)
-
- out:
-
- /* Not busy transmitting anymore if window is not full */
- if (self->tx_fifo.free < MAX_TX_WINDOW)
- netif_wake_queue(self->netdev);
-
- /* Restore bank register */
- switch_bank(iobase, BANK0);
-
- netif_trans_update(dev);
- spin_unlock_irqrestore(&self->lock, flags);
- dev_kfree_skb(skb);
-
- return NETDEV_TX_OK;
-}
-
-
-static void ali_ircc_dma_xmit(struct ali_ircc_cb *self)
-{
- int iobase, tmp;
- unsigned char FIFO_OPTI, Hi, Lo;
-
-
-
- iobase = self->io.fir_base;
-
- /* FIFO threshold , this method comes from NDIS5 code */
-
- if(self->tx_fifo.queue[self->tx_fifo.ptr].len < TX_FIFO_Threshold)
- FIFO_OPTI = self->tx_fifo.queue[self->tx_fifo.ptr].len-1;
- else
- FIFO_OPTI = TX_FIFO_Threshold;
-
- /* Disable DMA */
- switch_bank(iobase, BANK1);
- outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR);
-
- self->io.direction = IO_XMIT;
-
- irda_setup_dma(self->io.dma,
- ((u8 *)self->tx_fifo.queue[self->tx_fifo.ptr].start -
- self->tx_buff.head) + self->tx_buff_dma,
- self->tx_fifo.queue[self->tx_fifo.ptr].len,
- DMA_TX_MODE);
-
- /* Reset Tx FIFO */
- switch_bank(iobase, BANK0);
- outb(LCR_A_FIFO_RESET, iobase+FIR_LCR_A);
-
- /* Set Tx FIFO threshold */
- if (self->fifo_opti_buf!=FIFO_OPTI)
- {
- switch_bank(iobase, BANK1);
- outb(FIFO_OPTI, iobase+FIR_FIFO_TR) ;
- self->fifo_opti_buf=FIFO_OPTI;
- }
-
- /* Set Tx DMA threshold */
- switch_bank(iobase, BANK1);
- outb(TX_DMA_Threshold, iobase+FIR_DMA_TR);
-
- /* Set max Tx frame size */
- Hi = (self->tx_fifo.queue[self->tx_fifo.ptr].len >> 8) & 0x0f;
- Lo = self->tx_fifo.queue[self->tx_fifo.ptr].len & 0xff;
- switch_bank(iobase, BANK2);
- outb(Hi, iobase+FIR_TX_DSR_HI);
- outb(Lo, iobase+FIR_TX_DSR_LO);
-
- /* Disable SIP , Disable Brick Wall (we don't support in TX mode), Change to TX mode */
- switch_bank(iobase, BANK0);
- tmp = inb(iobase+FIR_LCR_B);
- tmp &= ~0x20; // Disable SIP
- outb(((unsigned char)(tmp & 0x3f) | LCR_B_TX_MODE) & ~LCR_B_BW, iobase+FIR_LCR_B);
- pr_debug("%s(), *** Change to TX mode: FIR_LCR_B = 0x%x ***\n",
- __func__, inb(iobase + FIR_LCR_B));
-
- outb(0, iobase+FIR_LSR);
-
- /* Enable DMA and Burst Mode */
- switch_bank(iobase, BANK1);
- outb(inb(iobase+FIR_CR) | CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR);
-
- switch_bank(iobase, BANK0);
-
-}
-
-static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self)
-{
- int iobase;
- int ret = TRUE;
-
-
- iobase = self->io.fir_base;
-
- /* Disable DMA */
- switch_bank(iobase, BANK1);
- outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR);
-
- /* Check for underrun! */
- switch_bank(iobase, BANK0);
- if((inb(iobase+FIR_LSR) & LSR_FRAME_ABORT) == LSR_FRAME_ABORT)
-
- {
- net_err_ratelimited("%s(), ********* LSR_FRAME_ABORT *********\n",
- __func__);
- self->netdev->stats.tx_errors++;
- self->netdev->stats.tx_fifo_errors++;
- }
- else
- {
- self->netdev->stats.tx_packets++;
- }
-
- /* Check if we need to change the speed */
- if (self->new_speed)
- {
- ali_ircc_change_speed(self, self->new_speed);
- self->new_speed = 0;
- }
-
- /* Finished with this frame, so prepare for next */
- self->tx_fifo.ptr++;
- self->tx_fifo.len--;
-
- /* Any frames to be sent back-to-back? */
- if (self->tx_fifo.len)
- {
- ali_ircc_dma_xmit(self);
-
- /* Not finished yet! */
- ret = FALSE;
- }
- else
- { /* Reset Tx FIFO info */
- self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
- self->tx_fifo.tail = self->tx_buff.head;
- }
-
- /* Make sure we have room for more frames */
- if (self->tx_fifo.free < MAX_TX_WINDOW) {
- /* Not busy transmitting anymore */
- /* Tell the network layer, that we can accept more frames */
- netif_wake_queue(self->netdev);
- }
-
- switch_bank(iobase, BANK0);
-
- return ret;
-}
-
-/*
- * Function ali_ircc_dma_receive (self)
- *
- * Get ready for receiving a frame. The device will initiate a DMA
- * if it starts to receive a frame.
- *
- */
-static int ali_ircc_dma_receive(struct ali_ircc_cb *self)
-{
- int iobase, tmp;
-
-
- iobase = self->io.fir_base;
-
- /* Reset Tx FIFO info */
- self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
- self->tx_fifo.tail = self->tx_buff.head;
-
- /* Disable DMA */
- switch_bank(iobase, BANK1);
- outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR);
-
- /* Reset Message Count */
- switch_bank(iobase, BANK0);
- outb(0x07, iobase+FIR_LSR);
-
- self->rcvFramesOverflow = FALSE;
-
- self->LineStatus = inb(iobase+FIR_LSR) ;
-
- /* Reset Rx FIFO info */
- self->io.direction = IO_RECV;
- self->rx_buff.data = self->rx_buff.head;
-
- /* Reset Rx FIFO */
- // switch_bank(iobase, BANK0);
- outb(LCR_A_FIFO_RESET, iobase+FIR_LCR_A);
-
- self->st_fifo.len = self->st_fifo.pending_bytes = 0;
- self->st_fifo.tail = self->st_fifo.head = 0;
-
- irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize,
- DMA_RX_MODE);
-
- /* Set Receive Mode,Brick Wall */
- //switch_bank(iobase, BANK0);
- tmp = inb(iobase+FIR_LCR_B);
- outb((unsigned char)(tmp &0x3f) | LCR_B_RX_MODE | LCR_B_BW , iobase + FIR_LCR_B); // 2000/12/1 05:16PM
- pr_debug("%s(), *** Change To RX mode: FIR_LCR_B = 0x%x ***\n",
- __func__, inb(iobase + FIR_LCR_B));
-
- /* Set Rx Threshold */
- switch_bank(iobase, BANK1);
- outb(RX_FIFO_Threshold, iobase+FIR_FIFO_TR);
- outb(RX_DMA_Threshold, iobase+FIR_DMA_TR);
-
- /* Enable DMA and Burst Mode */
- // switch_bank(iobase, BANK1);
- outb(CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR);
-
- switch_bank(iobase, BANK0);
- return 0;
-}
-
-static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self)
-{
- struct st_fifo *st_fifo;
- struct sk_buff *skb;
- __u8 status, MessageCount;
- int len, i, iobase, val;
-
- st_fifo = &self->st_fifo;
- iobase = self->io.fir_base;
-
- switch_bank(iobase, BANK0);
- MessageCount = inb(iobase+ FIR_LSR)&0x07;
-
- if (MessageCount > 0)
- pr_debug("%s(), Message count = %d\n", __func__, MessageCount);
-
- for (i=0; i<=MessageCount; i++)
- {
- /* Bank 0 */
- switch_bank(iobase, BANK0);
- status = inb(iobase+FIR_LSR);
-
- switch_bank(iobase, BANK2);
- len = inb(iobase+FIR_RX_DSR_HI) & 0x0f;
- len = len << 8;
- len |= inb(iobase+FIR_RX_DSR_LO);
-
- pr_debug("%s(), RX Length = 0x%.2x,\n", __func__ , len);
- pr_debug("%s(), RX Status = 0x%.2x,\n", __func__ , status);
-
- if (st_fifo->tail >= MAX_RX_WINDOW) {
- pr_debug("%s(), window is full!\n", __func__);
- continue;
- }
-
- st_fifo->entries[st_fifo->tail].status = status;
- st_fifo->entries[st_fifo->tail].len = len;
- st_fifo->pending_bytes += len;
- st_fifo->tail++;
- st_fifo->len++;
- }
-
- for (i=0; i<=MessageCount; i++)
- {
- /* Get first entry */
- status = st_fifo->entries[st_fifo->head].status;
- len = st_fifo->entries[st_fifo->head].len;
- st_fifo->pending_bytes -= len;
- st_fifo->head++;
- st_fifo->len--;
-
- /* Check for errors */
- if ((status & 0xd8) || self->rcvFramesOverflow || (len==0))
- {
- pr_debug("%s(), ************* RX Errors ************\n",
- __func__);
-
- /* Skip frame */
- self->netdev->stats.rx_errors++;
-
- self->rx_buff.data += len;
-
- if (status & LSR_FIFO_UR)
- {
- self->netdev->stats.rx_frame_errors++;
- pr_debug("%s(), ************* FIFO Errors ************\n",
- __func__);
- }
- if (status & LSR_FRAME_ERROR)
- {
- self->netdev->stats.rx_frame_errors++;
- pr_debug("%s(), ************* FRAME Errors ************\n",
- __func__);
- }
-
- if (status & LSR_CRC_ERROR)
- {
- self->netdev->stats.rx_crc_errors++;
- pr_debug("%s(), ************* CRC Errors ************\n",
- __func__);
- }
-
- if(self->rcvFramesOverflow)
- {
- self->netdev->stats.rx_frame_errors++;
- pr_debug("%s(), ************* Overran DMA buffer ************\n",
- __func__);
- }
- if(len == 0)
- {
- self->netdev->stats.rx_frame_errors++;
- pr_debug("%s(), ********** Receive Frame Size = 0 *********\n",
- __func__);
- }
- }
- else
- {
-
- if (st_fifo->pending_bytes < 32)
- {
- switch_bank(iobase, BANK0);
- val = inb(iobase+FIR_BSR);
- if ((val& BSR_FIFO_NOT_EMPTY)== 0x80)
- {
- pr_debug("%s(), ************* BSR_FIFO_NOT_EMPTY ************\n",
- __func__);
-
- /* Put this entry back in fifo */
- st_fifo->head--;
- st_fifo->len++;
- st_fifo->pending_bytes += len;
- st_fifo->entries[st_fifo->head].status = status;
- st_fifo->entries[st_fifo->head].len = len;
-
- /*
- * DMA not finished yet, so try again
- * later, set timer value, resolution
- * 500 us
- */
-
- switch_bank(iobase, BANK1);
- outb(TIMER_IIR_500, iobase+FIR_TIMER_IIR); // 2001/1/2 05:07PM
-
- /* Enable Timer */
- outb(inb(iobase+FIR_CR) | CR_TIMER_EN, iobase+FIR_CR);
-
- return FALSE; /* I'll be back! */
- }
- }
-
- /*
- * Remember the time we received this frame, so we can
- * reduce the min turn time a bit since we will know
- * how much time we have used for protocol processing
- */
- self->stamp = ktime_get();
-
- skb = dev_alloc_skb(len+1);
- if (!skb) {
- self->netdev->stats.rx_dropped++;
-
- return FALSE;
- }
-
- /* Make sure IP header gets aligned */
- skb_reserve(skb, 1);
-
- /* Copy frame without CRC, CRC is removed by hardware*/
- skb_put(skb, len);
- skb_copy_to_linear_data(skb, self->rx_buff.data, len);
-
- /* Move to next frame */
- self->rx_buff.data += len;
- self->netdev->stats.rx_bytes += len;
- self->netdev->stats.rx_packets++;
-
- skb->dev = self->netdev;
- skb_reset_mac_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- netif_rx(skb);
- }
- }
-
- switch_bank(iobase, BANK0);
-
- return TRUE;
-}
-
-
-
-/*
- * Function ali_ircc_sir_hard_xmit (skb, dev)
- *
- * Transmit the frame!
- *
- */
-static netdev_tx_t ali_ircc_sir_hard_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct ali_ircc_cb *self;
- unsigned long flags;
- int iobase;
- __u32 speed;
-
-
- IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
-
- self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
-
- iobase = self->io.sir_base;
-
- netif_stop_queue(dev);
-
- /* Make sure tests *& speed change are atomic */
- spin_lock_irqsave(&self->lock, flags);
-
- /* Note : you should make sure that speed changes are not going
- * to corrupt any outgoing frame. Look at nsc-ircc for the gory
- * details - Jean II */
-
- /* Check if we need to change the speed */
- speed = irda_get_next_speed(skb);
- if ((speed != self->io.speed) && (speed != -1)) {
- /* Check for empty frame */
- if (!skb->len) {
- ali_ircc_change_speed(self, speed);
- netif_trans_update(dev);
- spin_unlock_irqrestore(&self->lock, flags);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- } else
- self->new_speed = speed;
- }
-
- /* Init tx buffer */
- self->tx_buff.data = self->tx_buff.head;
-
- /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
- self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
- self->tx_buff.truesize);
-
- self->netdev->stats.tx_bytes += self->tx_buff.len;
-
- /* Turn on transmit finished interrupt. Will fire immediately! */
- outb(UART_IER_THRI, iobase+UART_IER);
-
- netif_trans_update(dev);
- spin_unlock_irqrestore(&self->lock, flags);
-
- dev_kfree_skb(skb);
-
-
- return NETDEV_TX_OK;
-}
-
-
-/*
- * Function ali_ircc_net_ioctl (dev, rq, cmd)
- *
- * Process IOCTL commands for this device
- *
- */
-static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct if_irda_req *irq = (struct if_irda_req *) rq;
- struct ali_ircc_cb *self;
- unsigned long flags;
- int ret = 0;
-
-
- IRDA_ASSERT(dev != NULL, return -1;);
-
- self = netdev_priv(dev);
-
- IRDA_ASSERT(self != NULL, return -1;);
-
- pr_debug("%s(), %s, (cmd=0x%X)\n", __func__ , dev->name, cmd);
-
- switch (cmd) {
- case SIOCSBANDWIDTH: /* Set bandwidth */
- pr_debug("%s(), SIOCSBANDWIDTH\n", __func__);
- /*
- * This function will also be used by IrLAP to change the
- * speed, so we still must allow for speed change within
- * interrupt context.
- */
- if (!in_interrupt() && !capable(CAP_NET_ADMIN))
- return -EPERM;
-
- spin_lock_irqsave(&self->lock, flags);
- ali_ircc_change_speed(self, irq->ifr_baudrate);
- spin_unlock_irqrestore(&self->lock, flags);
- break;
- case SIOCSMEDIABUSY: /* Set media busy */
- pr_debug("%s(), SIOCSMEDIABUSY\n", __func__);
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- irda_device_set_media_busy(self->netdev, TRUE);
- break;
- case SIOCGRECEIVING: /* Check if we are receiving right now */
- pr_debug("%s(), SIOCGRECEIVING\n", __func__);
- /* This is protected */
- irq->ifr_receiving = ali_ircc_is_receiving(self);
- break;
- default:
- ret = -EOPNOTSUPP;
- }
-
-
- return ret;
-}
-
-/*
- * Function ali_ircc_is_receiving (self)
- *
- * Return TRUE is we are currently receiving a frame
- *
- */
-static int ali_ircc_is_receiving(struct ali_ircc_cb *self)
-{
- unsigned long flags;
- int status = FALSE;
- int iobase;
-
-
- IRDA_ASSERT(self != NULL, return FALSE;);
-
- spin_lock_irqsave(&self->lock, flags);
-
- if (self->io.speed > 115200)
- {
- iobase = self->io.fir_base;
-
- switch_bank(iobase, BANK1);
- if((inb(iobase+FIR_FIFO_FR) & 0x3f) != 0)
- {
- /* We are receiving something */
- pr_debug("%s(), We are receiving something\n",
- __func__);
- status = TRUE;
- }
- switch_bank(iobase, BANK0);
- }
- else
- {
- status = (self->rx_buff.state != OUTSIDE_FRAME);
- }
-
- spin_unlock_irqrestore(&self->lock, flags);
-
-
- return status;
-}
-
-static int ali_ircc_suspend(struct platform_device *dev, pm_message_t state)
-{
- struct ali_ircc_cb *self = platform_get_drvdata(dev);
-
- net_info_ratelimited("%s, Suspending\n", ALI_IRCC_DRIVER_NAME);
-
- if (self->io.suspended)
- return 0;
-
- ali_ircc_net_close(self->netdev);
-
- self->io.suspended = 1;
-
- return 0;
-}
-
-static int ali_ircc_resume(struct platform_device *dev)
-{
- struct ali_ircc_cb *self = platform_get_drvdata(dev);
-
- if (!self->io.suspended)
- return 0;
-
- ali_ircc_net_open(self->netdev);
-
- net_info_ratelimited("%s, Waking up\n", ALI_IRCC_DRIVER_NAME);
-
- self->io.suspended = 0;
-
- return 0;
-}
-
-/* ALi Chip Function */
-
-static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable)
-{
-
- unsigned char newMask;
-
- int iobase = self->io.fir_base; /* or sir_base */
-
- pr_debug("%s(), -------- Start -------- ( Enable = %d )\n",
- __func__, enable);
-
- /* Enable the interrupt which we wish to */
- if (enable){
- if (self->io.direction == IO_XMIT)
- {
- if (self->io.speed > 115200) /* FIR, MIR */
- {
- newMask = self->ier;
- }
- else /* SIR */
- {
- newMask = UART_IER_THRI | UART_IER_RDI;
- }
- }
- else {
- if (self->io.speed > 115200) /* FIR, MIR */
- {
- newMask = self->ier;
- }
- else /* SIR */
- {
- newMask = UART_IER_RDI;
- }
- }
- }
- else /* Disable all the interrupts */
- {
- newMask = 0x00;
-
- }
-
- //SIR and FIR has different registers
- if (self->io.speed > 115200)
- {
- switch_bank(iobase, BANK0);
- outb(newMask, iobase+FIR_IER);
- }
- else
- outb(newMask, iobase+UART_IER);
-
-}
-
-static void SIR2FIR(int iobase)
-{
- //unsigned char tmp;
-
-
- /* Already protected (change_speed() or setup()), no need to lock.
- * Jean II */
-
- outb(0x28, iobase+UART_MCR);
- outb(0x68, iobase+UART_MCR);
- outb(0x88, iobase+UART_MCR);
-
- outb(0x60, iobase+FIR_MCR); /* Master Reset */
- outb(0x20, iobase+FIR_MCR); /* Master Interrupt Enable */
-
- //tmp = inb(iobase+FIR_LCR_B); /* SIP enable */
- //tmp |= 0x20;
- //outb(tmp, iobase+FIR_LCR_B);
-
-}
-
-static void FIR2SIR(int iobase)
-{
- unsigned char val;
-
-
- /* Already protected (change_speed() or setup()), no need to lock.
- * Jean II */
-
- outb(0x20, iobase+FIR_MCR); /* IRQ to low */
- outb(0x00, iobase+UART_IER);
-
- outb(0xA0, iobase+FIR_MCR); /* Don't set master reset */
- outb(0x00, iobase+UART_FCR);
- outb(0x07, iobase+UART_FCR);
-
- val = inb(iobase+UART_RX);
- val = inb(iobase+UART_LSR);
- val = inb(iobase+UART_MSR);
-
-}
-
-MODULE_AUTHOR("Benjamin Kong <benjamin_kong@ali.com.tw>");
-MODULE_DESCRIPTION("ALi FIR Controller Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" ALI_IRCC_DRIVER_NAME);
-
-
-module_param_hw_array(io, int, ioport, NULL, 0);
-MODULE_PARM_DESC(io, "Base I/O addresses");
-module_param_hw_array(irq, int, irq, NULL, 0);
-MODULE_PARM_DESC(irq, "IRQ lines");
-module_param_hw_array(dma, int, dma, NULL, 0);
-MODULE_PARM_DESC(dma, "DMA channels");
-
-module_init(ali_ircc_init);
-module_exit(ali_ircc_cleanup);
diff --git a/drivers/staging/irda/drivers/ali-ircc.h b/drivers/staging/irda/drivers/ali-ircc.h
deleted file mode 100644
index c2d9747a5108..000000000000
--- a/drivers/staging/irda/drivers/ali-ircc.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/*********************************************************************
- *
- * Filename: ali-ircc.h
- * Version: 0.5
- * Description: Driver for the ALI M1535D and M1543C FIR Controller
- * Status: Experimental.
- * Author: Benjamin Kong <benjamin_kong@ali.com.tw>
- * Created at: 2000/10/16 03:46PM
- * Modified at: 2001/1/3 02:56PM
- * Modified by: Benjamin Kong <benjamin_kong@ali.com.tw>
- *
- * Copyright (c) 2000 Benjamin Kong <benjamin_kong@ali.com.tw>
- * 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.
- *
- ********************************************************************/
-
-#ifndef ALI_IRCC_H
-#define ALI_IRCC_H
-
-#include <linux/ktime.h>
-
-#include <linux/spinlock.h>
-#include <linux/pm.h>
-#include <linux/types.h>
-#include <asm/io.h>
-
-/* SIR Register */
-/* Usr definition of linux/serial_reg.h */
-
-/* FIR Register */
-#define BANK0 0x20
-#define BANK1 0x21
-#define BANK2 0x22
-#define BANK3 0x23
-
-#define FIR_MCR 0x07 /* Master Control Register */
-
-/* Bank 0 */
-#define FIR_DR 0x00 /* Alias 0, FIR Data Register (R/W) */
-#define FIR_IER 0x01 /* Alias 1, FIR Interrupt Enable Register (R/W) */
-#define FIR_IIR 0x02 /* Alias 2, FIR Interrupt Identification Register (Read only) */
-#define FIR_LCR_A 0x03 /* Alias 3, FIR Line Control Register A (R/W) */
-#define FIR_LCR_B 0x04 /* Alias 4, FIR Line Control Register B (R/W) */
-#define FIR_LSR 0x05 /* Alias 5, FIR Line Status Register (R/W) */
-#define FIR_BSR 0x06 /* Alias 6, FIR Bus Status Register (Read only) */
-
-
- /* Alias 1 */
- #define IER_FIFO 0x10 /* FIR FIFO Interrupt Enable */
- #define IER_TIMER 0x20 /* Timer Interrupt Enable */
- #define IER_EOM 0x40 /* End of Message Interrupt Enable */
- #define IER_ACT 0x80 /* Active Frame Interrupt Enable */
-
- /* Alias 2 */
- #define IIR_FIFO 0x10 /* FIR FIFO Interrupt */
- #define IIR_TIMER 0x20 /* Timer Interrupt */
- #define IIR_EOM 0x40 /* End of Message Interrupt */
- #define IIR_ACT 0x80 /* Active Frame Interrupt */
-
- /* Alias 3 */
- #define LCR_A_FIFO_RESET 0x80 /* FIFO Reset */
-
- /* Alias 4 */
- #define LCR_B_BW 0x10 /* Brick Wall */
- #define LCR_B_SIP 0x20 /* SIP Enable */
- #define LCR_B_TX_MODE 0x40 /* Transmit Mode */
- #define LCR_B_RX_MODE 0x80 /* Receive Mode */
-
- /* Alias 5 */
- #define LSR_FIR_LSA 0x00 /* FIR Line Status Address */
- #define LSR_FRAME_ABORT 0x08 /* Frame Abort */
- #define LSR_CRC_ERROR 0x10 /* CRC Error */
- #define LSR_SIZE_ERROR 0x20 /* Size Error */
- #define LSR_FRAME_ERROR 0x40 /* Frame Error */
- #define LSR_FIFO_UR 0x80 /* FIFO Underrun */
- #define LSR_FIFO_OR 0x80 /* FIFO Overrun */
-
- /* Alias 6 */
- #define BSR_FIFO_NOT_EMPTY 0x80 /* FIFO Not Empty */
-
-/* Bank 1 */
-#define FIR_CR 0x00 /* Alias 0, FIR Configuration Register (R/W) */
-#define FIR_FIFO_TR 0x01 /* Alias 1, FIR FIFO Threshold Register (R/W) */
-#define FIR_DMA_TR 0x02 /* Alias 2, FIR DMA Threshold Register (R/W) */
-#define FIR_TIMER_IIR 0x03 /* Alias 3, FIR Timer interrupt interval register (W/O) */
-#define FIR_FIFO_FR 0x03 /* Alias 3, FIR FIFO Flag register (R/O) */
-#define FIR_FIFO_RAR 0x04 /* Alias 4, FIR FIFO Read Address register (R/O) */
-#define FIR_FIFO_WAR 0x05 /* Alias 5, FIR FIFO Write Address register (R/O) */
-#define FIR_TR 0x06 /* Alias 6, Test REgister (W/O) */
-
- /* Alias 0 */
- #define CR_DMA_EN 0x01 /* DMA Enable */
- #define CR_DMA_BURST 0x02 /* DMA Burst Mode */
- #define CR_TIMER_EN 0x08 /* Timer Enable */
-
- /* Alias 3 */
- #define TIMER_IIR_500 0x00 /* 500 us */
- #define TIMER_IIR_1ms 0x01 /* 1 ms */
- #define TIMER_IIR_2ms 0x02 /* 2 ms */
- #define TIMER_IIR_4ms 0x03 /* 4 ms */
-
-/* Bank 2 */
-#define FIR_IRDA_CR 0x00 /* Alias 0, IrDA Control Register (R/W) */
-#define FIR_BOF_CR 0x01 /* Alias 1, BOF Count Register (R/W) */
-#define FIR_BW_CR 0x02 /* Alias 2, Brick Wall Count Register (R/W) */
-#define FIR_TX_DSR_HI 0x03 /* Alias 3, TX Data Size Register (high) (R/W) */
-#define FIR_TX_DSR_LO 0x04 /* Alias 4, TX Data Size Register (low) (R/W) */
-#define FIR_RX_DSR_HI 0x05 /* Alias 5, RX Data Size Register (high) (R/W) */
-#define FIR_RX_DSR_LO 0x06 /* Alias 6, RX Data Size Register (low) (R/W) */
-
- /* Alias 0 */
- #define IRDA_CR_HDLC1152 0x80 /* 1.152Mbps HDLC Select */
- #define IRDA_CR_CRC 0X40 /* CRC Select. */
- #define IRDA_CR_HDLC 0x20 /* HDLC select. */
- #define IRDA_CR_HP_MODE 0x10 /* HP mode (read only) */
- #define IRDA_CR_SD_ST 0x08 /* SD/MODE State. */
- #define IRDA_CR_FIR_SIN 0x04 /* FIR SIN Select. */
- #define IRDA_CR_ITTX_0 0x02 /* SOUT State. IRTX force to 0 */
- #define IRDA_CR_ITTX_1 0x03 /* SOUT State. IRTX force to 1 */
-
-/* Bank 3 */
-#define FIR_ID_VR 0x00 /* Alias 0, FIR ID Version Register (R/O) */
-#define FIR_MODULE_CR 0x01 /* Alias 1, FIR Module Control Register (R/W) */
-#define FIR_IO_BASE_HI 0x02 /* Alias 2, FIR Higher I/O Base Address Register (R/O) */
-#define FIR_IO_BASE_LO 0x03 /* Alias 3, FIR Lower I/O Base Address Register (R/O) */
-#define FIR_IRQ_CR 0x04 /* Alias 4, FIR IRQ Channel Register (R/O) */
-#define FIR_DMA_CR 0x05 /* Alias 5, FIR DMA Channel Register (R/O) */
-
-struct ali_chip {
- char *name;
- int cfg[2];
- unsigned char entr1;
- unsigned char entr2;
- unsigned char cid_index;
- unsigned char cid_value;
- int (*probe)(struct ali_chip *chip, chipio_t *info);
- int (*init)(struct ali_chip *chip, chipio_t *info);
-};
-typedef struct ali_chip ali_chip_t;
-
-
-/* DMA modes needed */
-#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */
-#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */
-
-#define MAX_TX_WINDOW 7
-#define MAX_RX_WINDOW 7
-
-#define TX_FIFO_Threshold 8
-#define RX_FIFO_Threshold 1
-#define TX_DMA_Threshold 1
-#define RX_DMA_Threshold 1
-
-/* For storing entries in the status FIFO */
-
-struct st_fifo_entry {
- int status;
- int len;
-};
-
-struct st_fifo {
- struct st_fifo_entry entries[MAX_RX_WINDOW];
- int pending_bytes;
- int head;
- int tail;
- int len;
-};
-
-struct frame_cb {
- void *start; /* Start of frame in DMA mem */
- int len; /* Length of frame in DMA mem */
-};
-
-struct tx_fifo {
- struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */
- int ptr; /* Currently being sent */
- int len; /* Length of queue */
- int free; /* Next free slot */
- void *tail; /* Next free start in DMA mem */
-};
-
-/* Private data for each instance */
-struct ali_ircc_cb {
-
- struct st_fifo st_fifo; /* Info about received frames */
- struct tx_fifo tx_fifo; /* Info about frames to be transmitted */
-
- struct net_device *netdev; /* Yes! we are some kind of netdevice */
-
- struct irlap_cb *irlap; /* The link layer we are binded to */
- struct qos_info qos; /* QoS capabilities for this device */
-
- chipio_t io; /* IrDA controller information */
- iobuff_t tx_buff; /* Transmit buffer */
- iobuff_t rx_buff; /* Receive buffer */
- dma_addr_t tx_buff_dma;
- dma_addr_t rx_buff_dma;
-
- __u8 ier; /* Interrupt enable register */
-
- __u8 InterruptID; /* Interrupt ID */
- __u8 BusStatus; /* Bus Status */
- __u8 LineStatus; /* Line Status */
-
- unsigned char rcvFramesOverflow;
-
- ktime_t stamp;
-
- spinlock_t lock; /* For serializing operations */
-
- __u32 new_speed;
- int index; /* Instance index */
-
- unsigned char fifo_opti_buf;
-};
-
-static inline void switch_bank(int iobase, int bank)
-{
- outb(bank, iobase+FIR_MCR);
-}
-
-#endif /* ALI_IRCC_H */
diff --git a/drivers/staging/irda/drivers/au1k_ir.c b/drivers/staging/irda/drivers/au1k_ir.c
deleted file mode 100644
index 73e3e4b041bf..000000000000
--- a/drivers/staging/irda/drivers/au1k_ir.c
+++ /dev/null
@@ -1,985 +0,0 @@
-/*
- * Alchemy Semi Au1000 IrDA driver
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * 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.
- *
- * 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/module.h>
-#include <linux/netdevice.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irmod.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/irda_device.h>
-#include <asm/mach-au1x00/au1000.h>
-
-/* registers */
-#define IR_RING_PTR_STATUS 0x00
-#define IR_RING_BASE_ADDR_H 0x04
-#define IR_RING_BASE_ADDR_L 0x08
-#define IR_RING_SIZE 0x0C
-#define IR_RING_PROMPT 0x10
-#define IR_RING_ADDR_CMPR 0x14
-#define IR_INT_CLEAR 0x18
-#define IR_CONFIG_1 0x20
-#define IR_SIR_FLAGS 0x24
-#define IR_STATUS 0x28
-#define IR_READ_PHY_CONFIG 0x2C
-#define IR_WRITE_PHY_CONFIG 0x30
-#define IR_MAX_PKT_LEN 0x34
-#define IR_RX_BYTE_CNT 0x38
-#define IR_CONFIG_2 0x3C
-#define IR_ENABLE 0x40
-
-/* Config1 */
-#define IR_RX_INVERT_LED (1 << 0)
-#define IR_TX_INVERT_LED (1 << 1)
-#define IR_ST (1 << 2)
-#define IR_SF (1 << 3)
-#define IR_SIR (1 << 4)
-#define IR_MIR (1 << 5)
-#define IR_FIR (1 << 6)
-#define IR_16CRC (1 << 7)
-#define IR_TD (1 << 8)
-#define IR_RX_ALL (1 << 9)
-#define IR_DMA_ENABLE (1 << 10)
-#define IR_RX_ENABLE (1 << 11)
-#define IR_TX_ENABLE (1 << 12)
-#define IR_LOOPBACK (1 << 14)
-#define IR_SIR_MODE (IR_SIR | IR_DMA_ENABLE | \
- IR_RX_ALL | IR_RX_ENABLE | IR_SF | \
- IR_16CRC)
-
-/* ir_status */
-#define IR_RX_STATUS (1 << 9)
-#define IR_TX_STATUS (1 << 10)
-#define IR_PHYEN (1 << 15)
-
-/* ir_write_phy_config */
-#define IR_BR(x) (((x) & 0x3f) << 10) /* baud rate */
-#define IR_PW(x) (((x) & 0x1f) << 5) /* pulse width */
-#define IR_P(x) ((x) & 0x1f) /* preamble bits */
-
-/* Config2 */
-#define IR_MODE_INV (1 << 0)
-#define IR_ONE_PIN (1 << 1)
-#define IR_PHYCLK_40MHZ (0 << 2)
-#define IR_PHYCLK_48MHZ (1 << 2)
-#define IR_PHYCLK_56MHZ (2 << 2)
-#define IR_PHYCLK_64MHZ (3 << 2)
-#define IR_DP (1 << 4)
-#define IR_DA (1 << 5)
-#define IR_FLT_HIGH (0 << 6)
-#define IR_FLT_MEDHI (1 << 6)
-#define IR_FLT_MEDLO (2 << 6)
-#define IR_FLT_LO (3 << 6)
-#define IR_IEN (1 << 8)
-
-/* ir_enable */
-#define IR_HC (1 << 3) /* divide SBUS clock by 2 */
-#define IR_CE (1 << 2) /* clock enable */
-#define IR_C (1 << 1) /* coherency bit */
-#define IR_BE (1 << 0) /* set in big endian mode */
-
-#define NUM_IR_DESC 64
-#define RING_SIZE_4 0x0
-#define RING_SIZE_16 0x3
-#define RING_SIZE_64 0xF
-#define MAX_NUM_IR_DESC 64
-#define MAX_BUF_SIZE 2048
-
-/* Ring descriptor flags */
-#define AU_OWN (1 << 7) /* tx,rx */
-#define IR_DIS_CRC (1 << 6) /* tx */
-#define IR_BAD_CRC (1 << 5) /* tx */
-#define IR_NEED_PULSE (1 << 4) /* tx */
-#define IR_FORCE_UNDER (1 << 3) /* tx */
-#define IR_DISABLE_TX (1 << 2) /* tx */
-#define IR_HW_UNDER (1 << 0) /* tx */
-#define IR_TX_ERROR (IR_DIS_CRC | IR_BAD_CRC | IR_HW_UNDER)
-
-#define IR_PHY_ERROR (1 << 6) /* rx */
-#define IR_CRC_ERROR (1 << 5) /* rx */
-#define IR_MAX_LEN (1 << 4) /* rx */
-#define IR_FIFO_OVER (1 << 3) /* rx */
-#define IR_SIR_ERROR (1 << 2) /* rx */
-#define IR_RX_ERROR (IR_PHY_ERROR | IR_CRC_ERROR | \
- IR_MAX_LEN | IR_FIFO_OVER | IR_SIR_ERROR)
-
-struct db_dest {
- struct db_dest *pnext;
- volatile u32 *vaddr;
- dma_addr_t dma_addr;
-};
-
-struct ring_dest {
- u8 count_0; /* 7:0 */
- u8 count_1; /* 12:8 */
- u8 reserved;
- u8 flags;
- u8 addr_0; /* 7:0 */
- u8 addr_1; /* 15:8 */
- u8 addr_2; /* 23:16 */
- u8 addr_3; /* 31:24 */
-};
-
-/* Private data for each instance */
-struct au1k_private {
- void __iomem *iobase;
- int irq_rx, irq_tx;
-
- struct db_dest *pDBfree;
- struct db_dest db[2 * NUM_IR_DESC];
- volatile struct ring_dest *rx_ring[NUM_IR_DESC];
- volatile struct ring_dest *tx_ring[NUM_IR_DESC];
- struct db_dest *rx_db_inuse[NUM_IR_DESC];
- struct db_dest *tx_db_inuse[NUM_IR_DESC];
- u32 rx_head;
- u32 tx_head;
- u32 tx_tail;
- u32 tx_full;
-
- iobuff_t rx_buff;
-
- struct net_device *netdev;
- struct qos_info qos;
- struct irlap_cb *irlap;
-
- u8 open;
- u32 speed;
- u32 newspeed;
-
- struct resource *ioarea;
- struct au1k_irda_platform_data *platdata;
- struct clk *irda_clk;
-};
-
-static int qos_mtt_bits = 0x07; /* 1 ms or more */
-
-static void au1k_irda_plat_set_phy_mode(struct au1k_private *p, int mode)
-{
- if (p->platdata && p->platdata->set_phy_mode)
- p->platdata->set_phy_mode(mode);
-}
-
-static inline unsigned long irda_read(struct au1k_private *p,
- unsigned long ofs)
-{
- /*
- * IrDA peripheral bug. You have to read the register
- * twice to get the right value.
- */
- (void)__raw_readl(p->iobase + ofs);
- return __raw_readl(p->iobase + ofs);
-}
-
-static inline void irda_write(struct au1k_private *p, unsigned long ofs,
- unsigned long val)
-{
- __raw_writel(val, p->iobase + ofs);
- wmb();
-}
-
-/*
- * Buffer allocation/deallocation routines. The buffer descriptor returned
- * has the virtual and dma address of a buffer suitable for
- * both, receive and transmit operations.
- */
-static struct db_dest *GetFreeDB(struct au1k_private *aup)
-{
- struct db_dest *db;
- db = aup->pDBfree;
-
- if (db)
- aup->pDBfree = db->pnext;
- return db;
-}
-
-/*
- DMA memory allocation, derived from pci_alloc_consistent.
- However, the Au1000 data cache is coherent (when programmed
- so), therefore we return KSEG0 address, not KSEG1.
-*/
-static void *dma_alloc(size_t size, dma_addr_t *dma_handle)
-{
- void *ret;
- int gfp = GFP_ATOMIC | GFP_DMA;
-
- ret = (void *)__get_free_pages(gfp, get_order(size));
-
- if (ret != NULL) {
- memset(ret, 0, size);
- *dma_handle = virt_to_bus(ret);
- ret = (void *)KSEG0ADDR(ret);
- }
- return ret;
-}
-
-static void dma_free(void *vaddr, size_t size)
-{
- vaddr = (void *)KSEG0ADDR(vaddr);
- free_pages((unsigned long) vaddr, get_order(size));
-}
-
-
-static void setup_hw_rings(struct au1k_private *aup, u32 rx_base, u32 tx_base)
-{
- int i;
- for (i = 0; i < NUM_IR_DESC; i++) {
- aup->rx_ring[i] = (volatile struct ring_dest *)
- (rx_base + sizeof(struct ring_dest) * i);
- }
- for (i = 0; i < NUM_IR_DESC; i++) {
- aup->tx_ring[i] = (volatile struct ring_dest *)
- (tx_base + sizeof(struct ring_dest) * i);
- }
-}
-
-static int au1k_irda_init_iobuf(iobuff_t *io, int size)
-{
- io->head = kmalloc(size, GFP_KERNEL);
- if (io->head != NULL) {
- io->truesize = size;
- io->in_frame = FALSE;
- io->state = OUTSIDE_FRAME;
- io->data = io->head;
- }
- return io->head ? 0 : -ENOMEM;
-}
-
-/*
- * Set the IrDA communications speed.
- */
-static int au1k_irda_set_speed(struct net_device *dev, int speed)
-{
- struct au1k_private *aup = netdev_priv(dev);
- volatile struct ring_dest *ptxd;
- unsigned long control;
- int ret = 0, timeout = 10, i;
-
- if (speed == aup->speed)
- return ret;
-
- /* disable PHY first */
- au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF);
- irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) & ~IR_PHYEN);
-
- /* disable RX/TX */
- irda_write(aup, IR_CONFIG_1,
- irda_read(aup, IR_CONFIG_1) & ~(IR_RX_ENABLE | IR_TX_ENABLE));
- msleep(20);
- while (irda_read(aup, IR_STATUS) & (IR_RX_STATUS | IR_TX_STATUS)) {
- msleep(20);
- if (!timeout--) {
- netdev_err(dev, "rx/tx disable timeout\n");
- break;
- }
- }
-
- /* disable DMA */
- irda_write(aup, IR_CONFIG_1,
- irda_read(aup, IR_CONFIG_1) & ~IR_DMA_ENABLE);
- msleep(20);
-
- /* After we disable tx/rx. the index pointers go back to zero. */
- aup->tx_head = aup->tx_tail = aup->rx_head = 0;
- for (i = 0; i < NUM_IR_DESC; i++) {
- ptxd = aup->tx_ring[i];
- ptxd->flags = 0;
- ptxd->count_0 = 0;
- ptxd->count_1 = 0;
- }
-
- for (i = 0; i < NUM_IR_DESC; i++) {
- ptxd = aup->rx_ring[i];
- ptxd->count_0 = 0;
- ptxd->count_1 = 0;
- ptxd->flags = AU_OWN;
- }
-
- if (speed == 4000000)
- au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_FIR);
- else
- au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_SIR);
-
- switch (speed) {
- case 9600:
- irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(11) | IR_PW(12));
- irda_write(aup, IR_CONFIG_1, IR_SIR_MODE);
- break;
- case 19200:
- irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(5) | IR_PW(12));
- irda_write(aup, IR_CONFIG_1, IR_SIR_MODE);
- break;
- case 38400:
- irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(2) | IR_PW(12));
- irda_write(aup, IR_CONFIG_1, IR_SIR_MODE);
- break;
- case 57600:
- irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(1) | IR_PW(12));
- irda_write(aup, IR_CONFIG_1, IR_SIR_MODE);
- break;
- case 115200:
- irda_write(aup, IR_WRITE_PHY_CONFIG, IR_PW(12));
- irda_write(aup, IR_CONFIG_1, IR_SIR_MODE);
- break;
- case 4000000:
- irda_write(aup, IR_WRITE_PHY_CONFIG, IR_P(15));
- irda_write(aup, IR_CONFIG_1, IR_FIR | IR_DMA_ENABLE |
- IR_RX_ENABLE);
- break;
- default:
- netdev_err(dev, "unsupported speed %x\n", speed);
- ret = -EINVAL;
- break;
- }
-
- aup->speed = speed;
- irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) | IR_PHYEN);
-
- control = irda_read(aup, IR_STATUS);
- irda_write(aup, IR_RING_PROMPT, 0);
-
- if (control & (1 << 14)) {
- netdev_err(dev, "configuration error\n");
- } else {
- if (control & (1 << 11))
- netdev_debug(dev, "Valid SIR config\n");
- if (control & (1 << 12))
- netdev_debug(dev, "Valid MIR config\n");
- if (control & (1 << 13))
- netdev_debug(dev, "Valid FIR config\n");
- if (control & (1 << 10))
- netdev_debug(dev, "TX enabled\n");
- if (control & (1 << 9))
- netdev_debug(dev, "RX enabled\n");
- }
-
- return ret;
-}
-
-static void update_rx_stats(struct net_device *dev, u32 status, u32 count)
-{
- struct net_device_stats *ps = &dev->stats;
-
- ps->rx_packets++;
-
- if (status & IR_RX_ERROR) {
- ps->rx_errors++;
- if (status & (IR_PHY_ERROR | IR_FIFO_OVER))
- ps->rx_missed_errors++;
- if (status & IR_MAX_LEN)
- ps->rx_length_errors++;
- if (status & IR_CRC_ERROR)
- ps->rx_crc_errors++;
- } else
- ps->rx_bytes += count;
-}
-
-static void update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len)
-{
- struct net_device_stats *ps = &dev->stats;
-
- ps->tx_packets++;
- ps->tx_bytes += pkt_len;
-
- if (status & IR_TX_ERROR) {
- ps->tx_errors++;
- ps->tx_aborted_errors++;
- }
-}
-
-static void au1k_tx_ack(struct net_device *dev)
-{
- struct au1k_private *aup = netdev_priv(dev);
- volatile struct ring_dest *ptxd;
-
- ptxd = aup->tx_ring[aup->tx_tail];
- while (!(ptxd->flags & AU_OWN) && (aup->tx_tail != aup->tx_head)) {
- update_tx_stats(dev, ptxd->flags,
- (ptxd->count_1 << 8) | ptxd->count_0);
- ptxd->count_0 = 0;
- ptxd->count_1 = 0;
- wmb();
- aup->tx_tail = (aup->tx_tail + 1) & (NUM_IR_DESC - 1);
- ptxd = aup->tx_ring[aup->tx_tail];
-
- if (aup->tx_full) {
- aup->tx_full = 0;
- netif_wake_queue(dev);
- }
- }
-
- if (aup->tx_tail == aup->tx_head) {
- if (aup->newspeed) {
- au1k_irda_set_speed(dev, aup->newspeed);
- aup->newspeed = 0;
- } else {
- irda_write(aup, IR_CONFIG_1,
- irda_read(aup, IR_CONFIG_1) & ~IR_TX_ENABLE);
- irda_write(aup, IR_CONFIG_1,
- irda_read(aup, IR_CONFIG_1) | IR_RX_ENABLE);
- irda_write(aup, IR_RING_PROMPT, 0);
- }
- }
-}
-
-static int au1k_irda_rx(struct net_device *dev)
-{
- struct au1k_private *aup = netdev_priv(dev);
- volatile struct ring_dest *prxd;
- struct sk_buff *skb;
- struct db_dest *pDB;
- u32 flags, count;
-
- prxd = aup->rx_ring[aup->rx_head];
- flags = prxd->flags;
-
- while (!(flags & AU_OWN)) {
- pDB = aup->rx_db_inuse[aup->rx_head];
- count = (prxd->count_1 << 8) | prxd->count_0;
- if (!(flags & IR_RX_ERROR)) {
- /* good frame */
- update_rx_stats(dev, flags, count);
- skb = alloc_skb(count + 1, GFP_ATOMIC);
- if (skb == NULL) {
- dev->stats.rx_dropped++;
- continue;
- }
- skb_reserve(skb, 1);
- if (aup->speed == 4000000)
- skb_put(skb, count);
- else
- skb_put(skb, count - 2);
- skb_copy_to_linear_data(skb, (void *)pDB->vaddr,
- count - 2);
- skb->dev = dev;
- skb_reset_mac_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- netif_rx(skb);
- prxd->count_0 = 0;
- prxd->count_1 = 0;
- }
- prxd->flags |= AU_OWN;
- aup->rx_head = (aup->rx_head + 1) & (NUM_IR_DESC - 1);
- irda_write(aup, IR_RING_PROMPT, 0);
-
- /* next descriptor */
- prxd = aup->rx_ring[aup->rx_head];
- flags = prxd->flags;
-
- }
- return 0;
-}
-
-static irqreturn_t au1k_irda_interrupt(int dummy, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct au1k_private *aup = netdev_priv(dev);
-
- irda_write(aup, IR_INT_CLEAR, 0); /* ack irda interrupts */
-
- au1k_irda_rx(dev);
- au1k_tx_ack(dev);
-
- return IRQ_HANDLED;
-}
-
-static int au1k_init(struct net_device *dev)
-{
- struct au1k_private *aup = netdev_priv(dev);
- u32 enable, ring_address, phyck;
- struct clk *c;
- int i;
-
- c = clk_get(NULL, "irda_clk");
- if (IS_ERR(c))
- return PTR_ERR(c);
- i = clk_prepare_enable(c);
- if (i) {
- clk_put(c);
- return i;
- }
-
- switch (clk_get_rate(c)) {
- case 40000000:
- phyck = IR_PHYCLK_40MHZ;
- break;
- case 48000000:
- phyck = IR_PHYCLK_48MHZ;
- break;
- case 56000000:
- phyck = IR_PHYCLK_56MHZ;
- break;
- case 64000000:
- phyck = IR_PHYCLK_64MHZ;
- break;
- default:
- clk_disable_unprepare(c);
- clk_put(c);
- return -EINVAL;
- }
- aup->irda_clk = c;
-
- enable = IR_HC | IR_CE | IR_C;
-#ifndef CONFIG_CPU_LITTLE_ENDIAN
- enable |= IR_BE;
-#endif
- aup->tx_head = 0;
- aup->tx_tail = 0;
- aup->rx_head = 0;
-
- for (i = 0; i < NUM_IR_DESC; i++)
- aup->rx_ring[i]->flags = AU_OWN;
-
- irda_write(aup, IR_ENABLE, enable);
- msleep(20);
-
- /* disable PHY */
- au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF);
- irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) & ~IR_PHYEN);
- msleep(20);
-
- irda_write(aup, IR_MAX_PKT_LEN, MAX_BUF_SIZE);
-
- ring_address = (u32)virt_to_phys((void *)aup->rx_ring[0]);
- irda_write(aup, IR_RING_BASE_ADDR_H, ring_address >> 26);
- irda_write(aup, IR_RING_BASE_ADDR_L, (ring_address >> 10) & 0xffff);
-
- irda_write(aup, IR_RING_SIZE,
- (RING_SIZE_64 << 8) | (RING_SIZE_64 << 12));
-
- irda_write(aup, IR_CONFIG_2, phyck | IR_ONE_PIN);
- irda_write(aup, IR_RING_ADDR_CMPR, 0);
-
- au1k_irda_set_speed(dev, 9600);
- return 0;
-}
-
-static int au1k_irda_start(struct net_device *dev)
-{
- struct au1k_private *aup = netdev_priv(dev);
- char hwname[32];
- int retval;
-
- retval = au1k_init(dev);
- if (retval) {
- netdev_err(dev, "error in au1k_init\n");
- return retval;
- }
-
- retval = request_irq(aup->irq_tx, &au1k_irda_interrupt, 0,
- dev->name, dev);
- if (retval) {
- netdev_err(dev, "unable to get IRQ %d\n", dev->irq);
- return retval;
- }
- retval = request_irq(aup->irq_rx, &au1k_irda_interrupt, 0,
- dev->name, dev);
- if (retval) {
- free_irq(aup->irq_tx, dev);
- netdev_err(dev, "unable to get IRQ %d\n", dev->irq);
- return retval;
- }
-
- /* Give self a hardware name */
- sprintf(hwname, "Au1000 SIR/FIR");
- aup->irlap = irlap_open(dev, &aup->qos, hwname);
- netif_start_queue(dev);
-
- /* int enable */
- irda_write(aup, IR_CONFIG_2, irda_read(aup, IR_CONFIG_2) | IR_IEN);
-
- /* power up */
- au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_SIR);
-
- return 0;
-}
-
-static int au1k_irda_stop(struct net_device *dev)
-{
- struct au1k_private *aup = netdev_priv(dev);
-
- au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF);
-
- /* disable interrupts */
- irda_write(aup, IR_CONFIG_2, irda_read(aup, IR_CONFIG_2) & ~IR_IEN);
- irda_write(aup, IR_CONFIG_1, 0);
- irda_write(aup, IR_ENABLE, 0); /* disable clock */
-
- if (aup->irlap) {
- irlap_close(aup->irlap);
- aup->irlap = NULL;
- }
-
- netif_stop_queue(dev);
-
- /* disable the interrupt */
- free_irq(aup->irq_tx, dev);
- free_irq(aup->irq_rx, dev);
-
- clk_disable_unprepare(aup->irda_clk);
- clk_put(aup->irda_clk);
-
- return 0;
-}
-
-/*
- * Au1000 transmit routine.
- */
-static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct au1k_private *aup = netdev_priv(dev);
- int speed = irda_get_next_speed(skb);
- volatile struct ring_dest *ptxd;
- struct db_dest *pDB;
- u32 len, flags;
-
- if (speed != aup->speed && speed != -1)
- aup->newspeed = speed;
-
- if ((skb->len == 0) && (aup->newspeed)) {
- if (aup->tx_tail == aup->tx_head) {
- au1k_irda_set_speed(dev, speed);
- aup->newspeed = 0;
- }
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- ptxd = aup->tx_ring[aup->tx_head];
- flags = ptxd->flags;
-
- if (flags & AU_OWN) {
- netdev_debug(dev, "tx_full\n");
- netif_stop_queue(dev);
- aup->tx_full = 1;
- return 1;
- } else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) {
- netdev_debug(dev, "tx_full\n");
- netif_stop_queue(dev);
- aup->tx_full = 1;
- return 1;
- }
-
- pDB = aup->tx_db_inuse[aup->tx_head];
-
-#if 0
- if (irda_read(aup, IR_RX_BYTE_CNT) != 0) {
- netdev_debug(dev, "tx warning: rx byte cnt %x\n",
- irda_read(aup, IR_RX_BYTE_CNT));
- }
-#endif
-
- if (aup->speed == 4000000) {
- /* FIR */
- skb_copy_from_linear_data(skb, (void *)pDB->vaddr, skb->len);
- ptxd->count_0 = skb->len & 0xff;
- ptxd->count_1 = (skb->len >> 8) & 0xff;
- } else {
- /* SIR */
- len = async_wrap_skb(skb, (u8 *)pDB->vaddr, MAX_BUF_SIZE);
- ptxd->count_0 = len & 0xff;
- ptxd->count_1 = (len >> 8) & 0xff;
- ptxd->flags |= IR_DIS_CRC;
- }
- ptxd->flags |= AU_OWN;
- wmb();
-
- irda_write(aup, IR_CONFIG_1,
- irda_read(aup, IR_CONFIG_1) | IR_TX_ENABLE);
- irda_write(aup, IR_RING_PROMPT, 0);
-
- dev_kfree_skb(skb);
- aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1);
- return NETDEV_TX_OK;
-}
-
-/*
- * The Tx ring has been full longer than the watchdog timeout
- * value. The transmitter must be hung?
- */
-static void au1k_tx_timeout(struct net_device *dev)
-{
- u32 speed;
- struct au1k_private *aup = netdev_priv(dev);
-
- netdev_err(dev, "tx timeout\n");
- speed = aup->speed;
- aup->speed = 0;
- au1k_irda_set_speed(dev, speed);
- aup->tx_full = 0;
- netif_wake_queue(dev);
-}
-
-static int au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
-{
- struct if_irda_req *rq = (struct if_irda_req *)ifreq;
- struct au1k_private *aup = netdev_priv(dev);
- int ret = -EOPNOTSUPP;
-
- switch (cmd) {
- case SIOCSBANDWIDTH:
- if (capable(CAP_NET_ADMIN)) {
- /*
- * We are unable to set the speed if the
- * device is not running.
- */
- if (aup->open)
- ret = au1k_irda_set_speed(dev,
- rq->ifr_baudrate);
- else {
- netdev_err(dev, "ioctl: !netif_running\n");
- ret = 0;
- }
- }
- break;
-
- case SIOCSMEDIABUSY:
- ret = -EPERM;
- if (capable(CAP_NET_ADMIN)) {
- irda_device_set_media_busy(dev, TRUE);
- ret = 0;
- }
- break;
-
- case SIOCGRECEIVING:
- rq->ifr_receiving = 0;
- break;
- default:
- break;
- }
- return ret;
-}
-
-static const struct net_device_ops au1k_irda_netdev_ops = {
- .ndo_open = au1k_irda_start,
- .ndo_stop = au1k_irda_stop,
- .ndo_start_xmit = au1k_irda_hard_xmit,
- .ndo_tx_timeout = au1k_tx_timeout,
- .ndo_do_ioctl = au1k_irda_ioctl,
-};
-
-static int au1k_irda_net_init(struct net_device *dev)
-{
- struct au1k_private *aup = netdev_priv(dev);
- struct db_dest *pDB, *pDBfree;
- int i, err, retval = 0;
- dma_addr_t temp;
-
- err = au1k_irda_init_iobuf(&aup->rx_buff, 14384);
- if (err)
- goto out1;
-
- dev->netdev_ops = &au1k_irda_netdev_ops;
-
- irda_init_max_qos_capabilies(&aup->qos);
-
- /* The only value we must override it the baudrate */
- aup->qos.baud_rate.bits = IR_9600 | IR_19200 | IR_38400 |
- IR_57600 | IR_115200 | IR_576000 | (IR_4000000 << 8);
-
- aup->qos.min_turn_time.bits = qos_mtt_bits;
- irda_qos_bits_to_value(&aup->qos);
-
- retval = -ENOMEM;
-
- /* Tx ring follows rx ring + 512 bytes */
- /* we need a 1k aligned buffer */
- aup->rx_ring[0] = (struct ring_dest *)
- dma_alloc(2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest)),
- &temp);
- if (!aup->rx_ring[0])
- goto out2;
-
- /* allocate the data buffers */
- aup->db[0].vaddr =
- dma_alloc(MAX_BUF_SIZE * 2 * NUM_IR_DESC, &temp);
- if (!aup->db[0].vaddr)
- goto out3;
-
- setup_hw_rings(aup, (u32)aup->rx_ring[0], (u32)aup->rx_ring[0] + 512);
-
- pDBfree = NULL;
- pDB = aup->db;
- for (i = 0; i < (2 * NUM_IR_DESC); i++) {
- pDB->pnext = pDBfree;
- pDBfree = pDB;
- pDB->vaddr =
- (u32 *)((unsigned)aup->db[0].vaddr + (MAX_BUF_SIZE * i));
- pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr);
- pDB++;
- }
- aup->pDBfree = pDBfree;
-
- /* attach a data buffer to each descriptor */
- for (i = 0; i < NUM_IR_DESC; i++) {
- pDB = GetFreeDB(aup);
- if (!pDB)
- goto out3;
- aup->rx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff);
- aup->rx_ring[i]->addr_1 = (u8)((pDB->dma_addr >> 8) & 0xff);
- aup->rx_ring[i]->addr_2 = (u8)((pDB->dma_addr >> 16) & 0xff);
- aup->rx_ring[i]->addr_3 = (u8)((pDB->dma_addr >> 24) & 0xff);
- aup->rx_db_inuse[i] = pDB;
- }
- for (i = 0; i < NUM_IR_DESC; i++) {
- pDB = GetFreeDB(aup);
- if (!pDB)
- goto out3;
- aup->tx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff);
- aup->tx_ring[i]->addr_1 = (u8)((pDB->dma_addr >> 8) & 0xff);
- aup->tx_ring[i]->addr_2 = (u8)((pDB->dma_addr >> 16) & 0xff);
- aup->tx_ring[i]->addr_3 = (u8)((pDB->dma_addr >> 24) & 0xff);
- aup->tx_ring[i]->count_0 = 0;
- aup->tx_ring[i]->count_1 = 0;
- aup->tx_ring[i]->flags = 0;
- aup->tx_db_inuse[i] = pDB;
- }
-
- return 0;
-
-out3:
- dma_free((void *)aup->rx_ring[0],
- 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest)));
-out2:
- kfree(aup->rx_buff.head);
-out1:
- netdev_err(dev, "au1k_irda_net_init() failed. Returns %d\n");
- return retval;
-}
-
-static int au1k_irda_probe(struct platform_device *pdev)
-{
- struct au1k_private *aup;
- struct net_device *dev;
- struct resource *r;
- struct clk *c;
- int err;
-
- dev = alloc_irdadev(sizeof(struct au1k_private));
- if (!dev)
- return -ENOMEM;
-
- aup = netdev_priv(dev);
-
- aup->platdata = pdev->dev.platform_data;
-
- err = -EINVAL;
- r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!r)
- goto out;
-
- aup->irq_tx = r->start;
-
- r = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
- if (!r)
- goto out;
-
- aup->irq_rx = r->start;
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r)
- goto out;
-
- err = -EBUSY;
- aup->ioarea = request_mem_region(r->start, resource_size(r),
- pdev->name);
- if (!aup->ioarea)
- goto out;
-
- /* bail out early if clock doesn't exist */
- c = clk_get(NULL, "irda_clk");
- if (IS_ERR(c)) {
- err = PTR_ERR(c);
- goto out;
- }
- clk_put(c);
-
- aup->iobase = ioremap_nocache(r->start, resource_size(r));
- if (!aup->iobase)
- goto out2;
-
- dev->irq = aup->irq_rx;
-
- err = au1k_irda_net_init(dev);
- if (err)
- goto out3;
- err = register_netdev(dev);
- if (err)
- goto out4;
-
- platform_set_drvdata(pdev, dev);
-
- netdev_info(dev, "IrDA: Registered device\n");
- return 0;
-
-out4:
- dma_free((void *)aup->db[0].vaddr,
- MAX_BUF_SIZE * 2 * NUM_IR_DESC);
- dma_free((void *)aup->rx_ring[0],
- 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest)));
- kfree(aup->rx_buff.head);
-out3:
- iounmap(aup->iobase);
-out2:
- release_resource(aup->ioarea);
- kfree(aup->ioarea);
-out:
- free_netdev(dev);
- return err;
-}
-
-static int au1k_irda_remove(struct platform_device *pdev)
-{
- struct net_device *dev = platform_get_drvdata(pdev);
- struct au1k_private *aup = netdev_priv(dev);
-
- unregister_netdev(dev);
-
- dma_free((void *)aup->db[0].vaddr,
- MAX_BUF_SIZE * 2 * NUM_IR_DESC);
- dma_free((void *)aup->rx_ring[0],
- 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest)));
- kfree(aup->rx_buff.head);
-
- iounmap(aup->iobase);
- release_resource(aup->ioarea);
- kfree(aup->ioarea);
-
- free_netdev(dev);
-
- return 0;
-}
-
-static struct platform_driver au1k_irda_driver = {
- .driver = {
- .name = "au1000-irda",
- },
- .probe = au1k_irda_probe,
- .remove = au1k_irda_remove,
-};
-
-module_platform_driver(au1k_irda_driver);
-
-MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>");
-MODULE_DESCRIPTION("Au1000 IrDA Device Driver");
diff --git a/drivers/staging/irda/drivers/bfin_sir.c b/drivers/staging/irda/drivers/bfin_sir.c
deleted file mode 100644
index 59e409b68349..000000000000
--- a/drivers/staging/irda/drivers/bfin_sir.c
+++ /dev/null
@@ -1,819 +0,0 @@
-/*
- * Blackfin Infra-red Driver
- *
- * Copyright 2006-2009 Analog Devices Inc.
- *
- * Enter bugs at http://blackfin.uclinux.org/
- *
- * Licensed under the GPL-2 or later.
- *
- */
-#include "bfin_sir.h"
-
-#ifdef CONFIG_SIR_BFIN_DMA
-#define DMA_SIR_RX_XCNT 10
-#define DMA_SIR_RX_YCNT (PAGE_SIZE / DMA_SIR_RX_XCNT)
-#define DMA_SIR_RX_FLUSH_JIFS (HZ * 4 / 250)
-#endif
-
-#if ANOMALY_05000447
-static int max_rate = 57600;
-#else
-static int max_rate = 115200;
-#endif
-
-static void bfin_sir_rx_dma_timeout(struct timer_list *t);
-
-static void turnaround_delay(int mtt)
-{
- long ticks;
-
- mtt = mtt < 10000 ? 10000 : mtt;
- ticks = 1 + mtt / (USEC_PER_SEC / HZ);
- schedule_timeout_uninterruptible(ticks);
-}
-
-static void bfin_sir_init_ports(struct bfin_sir_port *sp, struct platform_device *pdev)
-{
- int i;
- struct resource *res;
-
- for (i = 0; i < pdev->num_resources; i++) {
- res = &pdev->resource[i];
- switch (res->flags) {
- case IORESOURCE_MEM:
- sp->membase = (void __iomem *)res->start;
- break;
- case IORESOURCE_IRQ:
- sp->irq = res->start;
- break;
- case IORESOURCE_DMA:
- sp->rx_dma_channel = res->start;
- sp->tx_dma_channel = res->end;
- break;
- default:
- break;
- }
- }
-
- sp->clk = get_sclk();
-#ifdef CONFIG_SIR_BFIN_DMA
- sp->tx_done = 1;
- timer_setup(&sp->rx_dma_timer, bfin_sir_rx_dma_timeout, 0);
-#endif
-}
-
-static void bfin_sir_stop_tx(struct bfin_sir_port *port)
-{
-#ifdef CONFIG_SIR_BFIN_DMA
- disable_dma(port->tx_dma_channel);
-#endif
-
- while (!(UART_GET_LSR(port) & THRE)) {
- cpu_relax();
- continue;
- }
-
- UART_CLEAR_IER(port, ETBEI);
-}
-
-static void bfin_sir_enable_tx(struct bfin_sir_port *port)
-{
- UART_SET_IER(port, ETBEI);
-}
-
-static void bfin_sir_stop_rx(struct bfin_sir_port *port)
-{
- UART_CLEAR_IER(port, ERBFI);
-}
-
-static void bfin_sir_enable_rx(struct bfin_sir_port *port)
-{
- UART_SET_IER(port, ERBFI);
-}
-
-static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
-{
- int ret = -EINVAL;
- unsigned int quot;
- unsigned short val, lsr, lcr;
- static int utime;
- int count = 10;
-
- lcr = WLS(8);
-
- switch (speed) {
- case 9600:
- case 19200:
- case 38400:
- case 57600:
- case 115200:
-
- /*
- * IRDA is not affected by anomaly 05000230, so there is no
- * need to tweak the divisor like he UART driver (which will
- * slightly speed up the baud rate on us).
- */
- quot = (port->clk + (8 * speed)) / (16 * speed);
-
- do {
- udelay(utime);
- lsr = UART_GET_LSR(port);
- } while (!(lsr & TEMT) && count--);
-
- /* The useconds for 1 bits to transmit */
- utime = 1000000 / speed + 1;
-
- /* Clear UCEN bit to reset the UART state machine
- * and control registers
- */
- val = UART_GET_GCTL(port);
- val &= ~UCEN;
- UART_PUT_GCTL(port, val);
-
- /* Set DLAB in LCR to Access THR RBR IER */
- UART_SET_DLAB(port);
- SSYNC();
-
- UART_PUT_DLL(port, quot & 0xFF);
- UART_PUT_DLH(port, (quot >> 8) & 0xFF);
- SSYNC();
-
- /* Clear DLAB in LCR */
- UART_CLEAR_DLAB(port);
- SSYNC();
-
- UART_PUT_LCR(port, lcr);
-
- val = UART_GET_GCTL(port);
- val |= UCEN;
- UART_PUT_GCTL(port, val);
-
- ret = 0;
- break;
- default:
- printk(KERN_WARNING "bfin_sir: Invalid speed %d\n", speed);
- break;
- }
-
- val = UART_GET_GCTL(port);
- /* If not add the 'RPOLC', we can't catch the receive interrupt.
- * It's related with the HW layout and the IR transiver.
- */
- val |= UMOD_IRDA | RPOLC;
- UART_PUT_GCTL(port, val);
- return ret;
-}
-
-static int bfin_sir_is_receiving(struct net_device *dev)
-{
- struct bfin_sir_self *self = netdev_priv(dev);
- struct bfin_sir_port *port = self->sir_port;
-
- if (!(UART_GET_IER(port) & ERBFI))
- return 0;
- return self->rx_buff.state != OUTSIDE_FRAME;
-}
-
-#ifdef CONFIG_SIR_BFIN_PIO
-static void bfin_sir_tx_chars(struct net_device *dev)
-{
- unsigned int chr;
- struct bfin_sir_self *self = netdev_priv(dev);
- struct bfin_sir_port *port = self->sir_port;
-
- if (self->tx_buff.len != 0) {
- chr = *(self->tx_buff.data);
- UART_PUT_CHAR(port, chr);
- self->tx_buff.data++;
- self->tx_buff.len--;
- } else {
- self->stats.tx_packets++;
- self->stats.tx_bytes += self->tx_buff.data - self->tx_buff.head;
- if (self->newspeed) {
- bfin_sir_set_speed(port, self->newspeed);
- self->speed = self->newspeed;
- self->newspeed = 0;
- }
- bfin_sir_stop_tx(port);
- bfin_sir_enable_rx(port);
- /* I'm hungry! */
- netif_wake_queue(dev);
- }
-}
-
-static void bfin_sir_rx_chars(struct net_device *dev)
-{
- struct bfin_sir_self *self = netdev_priv(dev);
- struct bfin_sir_port *port = self->sir_port;
- unsigned char ch;
-
- UART_CLEAR_LSR(port);
- ch = UART_GET_CHAR(port);
- async_unwrap_char(dev, &self->stats, &self->rx_buff, ch);
-}
-
-static irqreturn_t bfin_sir_rx_int(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct bfin_sir_self *self = netdev_priv(dev);
- struct bfin_sir_port *port = self->sir_port;
-
- spin_lock(&self->lock);
- while ((UART_GET_LSR(port) & DR))
- bfin_sir_rx_chars(dev);
- spin_unlock(&self->lock);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t bfin_sir_tx_int(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct bfin_sir_self *self = netdev_priv(dev);
- struct bfin_sir_port *port = self->sir_port;
-
- spin_lock(&self->lock);
- if (UART_GET_LSR(port) & THRE)
- bfin_sir_tx_chars(dev);
- spin_unlock(&self->lock);
-
- return IRQ_HANDLED;
-}
-#endif /* CONFIG_SIR_BFIN_PIO */
-
-#ifdef CONFIG_SIR_BFIN_DMA
-static void bfin_sir_dma_tx_chars(struct net_device *dev)
-{
- struct bfin_sir_self *self = netdev_priv(dev);
- struct bfin_sir_port *port = self->sir_port;
-
- if (!port->tx_done)
- return;
- port->tx_done = 0;
-
- if (self->tx_buff.len == 0) {
- self->stats.tx_packets++;
- if (self->newspeed) {
- bfin_sir_set_speed(port, self->newspeed);
- self->speed = self->newspeed;
- self->newspeed = 0;
- }
- bfin_sir_enable_rx(port);
- port->tx_done = 1;
- netif_wake_queue(dev);
- return;
- }
-
- blackfin_dcache_flush_range((unsigned long)(self->tx_buff.data),
- (unsigned long)(self->tx_buff.data+self->tx_buff.len));
- set_dma_config(port->tx_dma_channel,
- set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
- INTR_ON_BUF, DIMENSION_LINEAR, DATA_SIZE_8,
- DMA_SYNC_RESTART));
- set_dma_start_addr(port->tx_dma_channel,
- (unsigned long)(self->tx_buff.data));
- set_dma_x_count(port->tx_dma_channel, self->tx_buff.len);
- set_dma_x_modify(port->tx_dma_channel, 1);
- enable_dma(port->tx_dma_channel);
-}
-
-static irqreturn_t bfin_sir_dma_tx_int(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct bfin_sir_self *self = netdev_priv(dev);
- struct bfin_sir_port *port = self->sir_port;
-
- spin_lock(&self->lock);
- if (!(get_dma_curr_irqstat(port->tx_dma_channel) & DMA_RUN)) {
- clear_dma_irqstat(port->tx_dma_channel);
- bfin_sir_stop_tx(port);
-
- self->stats.tx_packets++;
- self->stats.tx_bytes += self->tx_buff.len;
- self->tx_buff.len = 0;
- if (self->newspeed) {
- bfin_sir_set_speed(port, self->newspeed);
- self->speed = self->newspeed;
- self->newspeed = 0;
- }
- bfin_sir_enable_rx(port);
- /* I'm hungry! */
- netif_wake_queue(dev);
- port->tx_done = 1;
- }
- spin_unlock(&self->lock);
-
- return IRQ_HANDLED;
-}
-
-static void bfin_sir_dma_rx_chars(struct net_device *dev)
-{
- struct bfin_sir_self *self = netdev_priv(dev);
- struct bfin_sir_port *port = self->sir_port;
- int i;
-
- UART_CLEAR_LSR(port);
-
- for (i = port->rx_dma_buf.head; i < port->rx_dma_buf.tail; i++)
- async_unwrap_char(dev, &self->stats, &self->rx_buff, port->rx_dma_buf.buf[i]);
-}
-
-static void bfin_sir_rx_dma_timeout(struct timer_list *t)
-{
- struct bfin_sir_port *port = from_timer(port, t, rx_dma_timer);
- struct net_device *dev = port->dev;
- struct bfin_sir_self *self = netdev_priv(dev);
-
- int x_pos, pos;
- unsigned long flags;
-
- spin_lock_irqsave(&self->lock, flags);
- x_pos = DMA_SIR_RX_XCNT - get_dma_curr_xcount(port->rx_dma_channel);
- if (x_pos == DMA_SIR_RX_XCNT)
- x_pos = 0;
-
- pos = port->rx_dma_nrows * DMA_SIR_RX_XCNT + x_pos;
-
- if (pos > port->rx_dma_buf.tail) {
- port->rx_dma_buf.tail = pos;
- bfin_sir_dma_rx_chars(dev);
- port->rx_dma_buf.head = port->rx_dma_buf.tail;
- }
- spin_unlock_irqrestore(&self->lock, flags);
-}
-
-static irqreturn_t bfin_sir_dma_rx_int(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct bfin_sir_self *self = netdev_priv(dev);
- struct bfin_sir_port *port = self->sir_port;
- unsigned short irqstat;
-
- spin_lock(&self->lock);
-
- port->rx_dma_nrows++;
- port->rx_dma_buf.tail = DMA_SIR_RX_XCNT * port->rx_dma_nrows;
- bfin_sir_dma_rx_chars(dev);
- if (port->rx_dma_nrows >= DMA_SIR_RX_YCNT) {
- port->rx_dma_nrows = 0;
- port->rx_dma_buf.tail = 0;
- }
- port->rx_dma_buf.head = port->rx_dma_buf.tail;
-
- irqstat = get_dma_curr_irqstat(port->rx_dma_channel);
- clear_dma_irqstat(port->rx_dma_channel);
- spin_unlock(&self->lock);
-
- mod_timer(&port->rx_dma_timer, jiffies + DMA_SIR_RX_FLUSH_JIFS);
- return IRQ_HANDLED;
-}
-#endif /* CONFIG_SIR_BFIN_DMA */
-
-static int bfin_sir_startup(struct bfin_sir_port *port, struct net_device *dev)
-{
-#ifdef CONFIG_SIR_BFIN_DMA
- dma_addr_t dma_handle;
-#endif /* CONFIG_SIR_BFIN_DMA */
-
- if (request_dma(port->rx_dma_channel, "BFIN_UART_RX") < 0) {
- dev_warn(&dev->dev, "Unable to attach SIR RX DMA channel\n");
- return -EBUSY;
- }
-
- if (request_dma(port->tx_dma_channel, "BFIN_UART_TX") < 0) {
- dev_warn(&dev->dev, "Unable to attach SIR TX DMA channel\n");
- free_dma(port->rx_dma_channel);
- return -EBUSY;
- }
-
-#ifdef CONFIG_SIR_BFIN_DMA
-
- set_dma_callback(port->rx_dma_channel, bfin_sir_dma_rx_int, dev);
- set_dma_callback(port->tx_dma_channel, bfin_sir_dma_tx_int, dev);
-
- port->rx_dma_buf.buf = dma_alloc_coherent(NULL, PAGE_SIZE,
- &dma_handle, GFP_DMA);
- port->rx_dma_buf.head = 0;
- port->rx_dma_buf.tail = 0;
- port->rx_dma_nrows = 0;
-
- set_dma_config(port->rx_dma_channel,
- set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,
- INTR_ON_ROW, DIMENSION_2D,
- DATA_SIZE_8, DMA_SYNC_RESTART));
- set_dma_x_count(port->rx_dma_channel, DMA_SIR_RX_XCNT);
- set_dma_x_modify(port->rx_dma_channel, 1);
- set_dma_y_count(port->rx_dma_channel, DMA_SIR_RX_YCNT);
- set_dma_y_modify(port->rx_dma_channel, 1);
- set_dma_start_addr(port->rx_dma_channel, (unsigned long)port->rx_dma_buf.buf);
- enable_dma(port->rx_dma_channel);
-
-
-#else
-
- if (request_irq(port->irq, bfin_sir_rx_int, 0, "BFIN_SIR_RX", dev)) {
- dev_warn(&dev->dev, "Unable to attach SIR RX interrupt\n");
- return -EBUSY;
- }
-
- if (request_irq(port->irq+1, bfin_sir_tx_int, 0, "BFIN_SIR_TX", dev)) {
- dev_warn(&dev->dev, "Unable to attach SIR TX interrupt\n");
- free_irq(port->irq, dev);
- return -EBUSY;
- }
-#endif
-
- return 0;
-}
-
-static void bfin_sir_shutdown(struct bfin_sir_port *port, struct net_device *dev)
-{
- unsigned short val;
-
- bfin_sir_stop_rx(port);
-
- val = UART_GET_GCTL(port);
- val &= ~(UCEN | UMOD_MASK | RPOLC);
- UART_PUT_GCTL(port, val);
-
-#ifdef CONFIG_SIR_BFIN_DMA
- disable_dma(port->tx_dma_channel);
- disable_dma(port->rx_dma_channel);
- del_timer(&(port->rx_dma_timer));
- dma_free_coherent(NULL, PAGE_SIZE, port->rx_dma_buf.buf, 0);
-#else
- free_irq(port->irq+1, dev);
- free_irq(port->irq, dev);
-#endif
- free_dma(port->tx_dma_channel);
- free_dma(port->rx_dma_channel);
-}
-
-#ifdef CONFIG_PM
-static int bfin_sir_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct bfin_sir_port *sir_port;
- struct net_device *dev;
- struct bfin_sir_self *self;
-
- sir_port = platform_get_drvdata(pdev);
- if (!sir_port)
- return 0;
-
- dev = sir_port->dev;
- self = netdev_priv(dev);
- if (self->open) {
- flush_work(&self->work);
- bfin_sir_shutdown(self->sir_port, dev);
- netif_device_detach(dev);
- }
-
- return 0;
-}
-static int bfin_sir_resume(struct platform_device *pdev)
-{
- struct bfin_sir_port *sir_port;
- struct net_device *dev;
- struct bfin_sir_self *self;
- struct bfin_sir_port *port;
-
- sir_port = platform_get_drvdata(pdev);
- if (!sir_port)
- return 0;
-
- dev = sir_port->dev;
- self = netdev_priv(dev);
- port = self->sir_port;
- if (self->open) {
- if (self->newspeed) {
- self->speed = self->newspeed;
- self->newspeed = 0;
- }
- bfin_sir_startup(port, dev);
- bfin_sir_set_speed(port, 9600);
- bfin_sir_enable_rx(port);
- netif_device_attach(dev);
- }
- return 0;
-}
-#else
-#define bfin_sir_suspend NULL
-#define bfin_sir_resume NULL
-#endif
-
-static void bfin_sir_send_work(struct work_struct *work)
-{
- struct bfin_sir_self *self = container_of(work, struct bfin_sir_self, work);
- struct net_device *dev = self->sir_port->dev;
- struct bfin_sir_port *port = self->sir_port;
- unsigned short val;
- int tx_cnt = 10;
-
- while (bfin_sir_is_receiving(dev) && --tx_cnt)
- turnaround_delay(self->mtt);
-
- bfin_sir_stop_rx(port);
-
- /* To avoid losting RX interrupt, we reset IR function before
- * sending data. We also can set the speed, which will
- * reset all the UART.
- */
- val = UART_GET_GCTL(port);
- val &= ~(UMOD_MASK | RPOLC);
- UART_PUT_GCTL(port, val);
- SSYNC();
- val |= UMOD_IRDA | RPOLC;
- UART_PUT_GCTL(port, val);
- SSYNC();
- /* bfin_sir_set_speed(port, self->speed); */
-
-#ifdef CONFIG_SIR_BFIN_DMA
- bfin_sir_dma_tx_chars(dev);
-#endif
- bfin_sir_enable_tx(port);
- netif_trans_update(dev);
-}
-
-static int bfin_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct bfin_sir_self *self = netdev_priv(dev);
- int speed = irda_get_next_speed(skb);
-
- netif_stop_queue(dev);
-
- self->mtt = irda_get_mtt(skb);
-
- if (speed != self->speed && speed != -1)
- self->newspeed = speed;
-
- self->tx_buff.data = self->tx_buff.head;
- if (skb->len == 0)
- self->tx_buff.len = 0;
- else
- self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize);
-
- schedule_work(&self->work);
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-static int bfin_sir_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
-{
- struct if_irda_req *rq = (struct if_irda_req *)ifreq;
- struct bfin_sir_self *self = netdev_priv(dev);
- struct bfin_sir_port *port = self->sir_port;
- int ret = 0;
-
- switch (cmd) {
- case SIOCSBANDWIDTH:
- if (capable(CAP_NET_ADMIN)) {
- if (self->open) {
- ret = bfin_sir_set_speed(port, rq->ifr_baudrate);
- bfin_sir_enable_rx(port);
- } else {
- dev_warn(&dev->dev, "SIOCSBANDWIDTH: !netif_running\n");
- ret = 0;
- }
- }
- break;
-
- case SIOCSMEDIABUSY:
- ret = -EPERM;
- if (capable(CAP_NET_ADMIN)) {
- irda_device_set_media_busy(dev, TRUE);
- ret = 0;
- }
- break;
-
- case SIOCGRECEIVING:
- rq->ifr_receiving = bfin_sir_is_receiving(dev);
- break;
-
- default:
- ret = -EOPNOTSUPP;
- break;
- }
-
- return ret;
-}
-
-static struct net_device_stats *bfin_sir_stats(struct net_device *dev)
-{
- struct bfin_sir_self *self = netdev_priv(dev);
-
- return &self->stats;
-}
-
-static int bfin_sir_open(struct net_device *dev)
-{
- struct bfin_sir_self *self = netdev_priv(dev);
- struct bfin_sir_port *port = self->sir_port;
- int err;
-
- self->newspeed = 0;
- self->speed = 9600;
-
- spin_lock_init(&self->lock);
-
- err = bfin_sir_startup(port, dev);
- if (err)
- goto err_startup;
-
- bfin_sir_set_speed(port, 9600);
-
- self->irlap = irlap_open(dev, &self->qos, DRIVER_NAME);
- if (!self->irlap) {
- err = -ENOMEM;
- goto err_irlap;
- }
-
- INIT_WORK(&self->work, bfin_sir_send_work);
-
- /*
- * Now enable the interrupt then start the queue
- */
- self->open = 1;
- bfin_sir_enable_rx(port);
-
- netif_start_queue(dev);
-
- return 0;
-
-err_irlap:
- self->open = 0;
- bfin_sir_shutdown(port, dev);
-err_startup:
- return err;
-}
-
-static int bfin_sir_stop(struct net_device *dev)
-{
- struct bfin_sir_self *self = netdev_priv(dev);
-
- flush_work(&self->work);
- bfin_sir_shutdown(self->sir_port, dev);
-
- if (self->rxskb) {
- dev_kfree_skb(self->rxskb);
- self->rxskb = NULL;
- }
-
- /* Stop IrLAP */
- if (self->irlap) {
- irlap_close(self->irlap);
- self->irlap = NULL;
- }
-
- netif_stop_queue(dev);
- self->open = 0;
-
- return 0;
-}
-
-static int bfin_sir_init_iobuf(iobuff_t *io, int size)
-{
- io->head = kmalloc(size, GFP_KERNEL);
- if (!io->head)
- return -ENOMEM;
- io->truesize = size;
- io->in_frame = FALSE;
- io->state = OUTSIDE_FRAME;
- io->data = io->head;
- return 0;
-}
-
-static const struct net_device_ops bfin_sir_ndo = {
- .ndo_open = bfin_sir_open,
- .ndo_stop = bfin_sir_stop,
- .ndo_start_xmit = bfin_sir_hard_xmit,
- .ndo_do_ioctl = bfin_sir_ioctl,
- .ndo_get_stats = bfin_sir_stats,
-};
-
-static int bfin_sir_probe(struct platform_device *pdev)
-{
- struct net_device *dev;
- struct bfin_sir_self *self;
- unsigned int baudrate_mask;
- struct bfin_sir_port *sir_port;
- int err;
-
- if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(per) && \
- per[pdev->id][3] == pdev->id) {
- err = peripheral_request_list(per[pdev->id], DRIVER_NAME);
- if (err)
- return err;
- } else {
- dev_err(&pdev->dev, "Invalid pdev id, please check board file\n");
- return -ENODEV;
- }
-
- err = -ENOMEM;
- sir_port = kmalloc(sizeof(*sir_port), GFP_KERNEL);
- if (!sir_port)
- goto err_mem_0;
-
- bfin_sir_init_ports(sir_port, pdev);
-
- dev = alloc_irdadev(sizeof(*self));
- if (!dev)
- goto err_mem_1;
-
- self = netdev_priv(dev);
- self->dev = &pdev->dev;
- self->sir_port = sir_port;
- sir_port->dev = dev;
-
- err = bfin_sir_init_iobuf(&self->rx_buff, IRDA_SKB_MAX_MTU);
- if (err)
- goto err_mem_2;
- err = bfin_sir_init_iobuf(&self->tx_buff, IRDA_SIR_MAX_FRAME);
- if (err)
- goto err_mem_3;
-
- dev->netdev_ops = &bfin_sir_ndo;
- dev->irq = sir_port->irq;
-
- irda_init_max_qos_capabilies(&self->qos);
-
- baudrate_mask = IR_9600;
-
- switch (max_rate) {
- case 115200:
- baudrate_mask |= IR_115200;
- case 57600:
- baudrate_mask |= IR_57600;
- case 38400:
- baudrate_mask |= IR_38400;
- case 19200:
- baudrate_mask |= IR_19200;
- case 9600:
- break;
- default:
- dev_warn(&pdev->dev, "Invalid maximum baud rate, using 9600\n");
- }
-
- self->qos.baud_rate.bits &= baudrate_mask;
-
- self->qos.min_turn_time.bits = 1; /* 10 ms or more */
-
- irda_qos_bits_to_value(&self->qos);
-
- err = register_netdev(dev);
-
- if (err) {
- kfree(self->tx_buff.head);
-err_mem_3:
- kfree(self->rx_buff.head);
-err_mem_2:
- free_netdev(dev);
-err_mem_1:
- kfree(sir_port);
-err_mem_0:
- peripheral_free_list(per[pdev->id]);
- } else
- platform_set_drvdata(pdev, sir_port);
-
- return err;
-}
-
-static int bfin_sir_remove(struct platform_device *pdev)
-{
- struct bfin_sir_port *sir_port;
- struct net_device *dev = NULL;
- struct bfin_sir_self *self;
-
- sir_port = platform_get_drvdata(pdev);
- if (!sir_port)
- return 0;
- dev = sir_port->dev;
- self = netdev_priv(dev);
- unregister_netdev(dev);
- kfree(self->tx_buff.head);
- kfree(self->rx_buff.head);
- free_netdev(dev);
- kfree(sir_port);
-
- return 0;
-}
-
-static struct platform_driver bfin_ir_driver = {
- .probe = bfin_sir_probe,
- .remove = bfin_sir_remove,
- .suspend = bfin_sir_suspend,
- .resume = bfin_sir_resume,
- .driver = {
- .name = DRIVER_NAME,
- },
-};
-
-module_platform_driver(bfin_ir_driver);
-
-module_param(max_rate, int, 0);
-MODULE_PARM_DESC(max_rate, "Maximum baud rate (115200, 57600, 38400, 19200, 9600)");
-
-MODULE_AUTHOR("Graf Yang <graf.yang@analog.com>");
-MODULE_DESCRIPTION("Blackfin IrDA driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/irda/drivers/bfin_sir.h b/drivers/staging/irda/drivers/bfin_sir.h
deleted file mode 100644
index d47cf14bb4a5..000000000000
--- a/drivers/staging/irda/drivers/bfin_sir.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Blackfin Infra-red Driver
- *
- * Copyright 2006-2009 Analog Devices Inc.
- *
- * Enter bugs at http://blackfin.uclinux.org/
- *
- * Licensed under the GPL-2 or later.
- *
- */
-
-#include <linux/serial.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/irda_device.h>
-
-#include <asm/irq.h>
-#include <asm/cacheflush.h>
-#include <asm/dma.h>
-#include <asm/portmux.h>
-#undef DRIVER_NAME
-
-#ifdef CONFIG_SIR_BFIN_DMA
-struct dma_rx_buf {
- char *buf;
- int head;
- int tail;
-};
-#endif
-
-struct bfin_sir_port {
- unsigned char __iomem *membase;
- unsigned int irq;
- unsigned int lsr;
- unsigned long clk;
- struct net_device *dev;
-#ifdef CONFIG_SIR_BFIN_DMA
- int tx_done;
- struct dma_rx_buf rx_dma_buf;
- struct timer_list rx_dma_timer;
- int rx_dma_nrows;
-#endif
- unsigned int tx_dma_channel;
- unsigned int rx_dma_channel;
-};
-
-struct bfin_sir_port_res {
- unsigned long base_addr;
- int irq;
- unsigned int rx_dma_channel;
- unsigned int tx_dma_channel;
-};
-
-struct bfin_sir_self {
- struct bfin_sir_port *sir_port;
- spinlock_t lock;
- unsigned int open;
- int speed;
- int newspeed;
-
- struct sk_buff *txskb;
- struct sk_buff *rxskb;
- struct net_device_stats stats;
- struct device *dev;
- struct irlap_cb *irlap;
- struct qos_info qos;
-
- iobuff_t tx_buff;
- iobuff_t rx_buff;
-
- struct work_struct work;
- int mtt;
-};
-
-#define DRIVER_NAME "bfin_sir"
-
-#include <asm/bfin_serial.h>
-
-static const unsigned short per[][4] = {
- /* rx pin tx pin NULL uart_number */
- {P_UART0_RX, P_UART0_TX, 0, 0},
- {P_UART1_RX, P_UART1_TX, 0, 1},
- {P_UART2_RX, P_UART2_TX, 0, 2},
- {P_UART3_RX, P_UART3_TX, 0, 3},
-};
diff --git a/drivers/staging/irda/drivers/donauboe.c b/drivers/staging/irda/drivers/donauboe.c
deleted file mode 100644
index b337e6d23a88..000000000000
--- a/drivers/staging/irda/drivers/donauboe.c
+++ /dev/null
@@ -1,1732 +0,0 @@
-/*****************************************************************
- *
- * Filename: donauboe.c
- * Version: 2.17
- * Description: Driver for the Toshiba OBOE (or type-O or 701)
- * FIR Chipset, also supports the DONAUOBOE (type-DO
- * or d01) FIR chipset which as far as I know is
- * register compatible.
- * Documentation: http://libxg.free.fr/irda/lib-irda.html
- * Status: Experimental.
- * Author: James McKenzie <james@fishsoup.dhs.org>
- * Created at: Sat May 8 12:35:27 1999
- * Modified: Paul Bristow <paul.bristow@technologist.com>
- * Modified: Mon Nov 11 19:10:05 1999
- * Modified: James McKenzie <james@fishsoup.dhs.org>
- * Modified: Thu Mar 16 12:49:00 2000 (Substantial rewrite)
- * Modified: Sat Apr 29 00:23:03 2000 (Added DONAUOBOE support)
- * Modified: Wed May 24 23:45:02 2000 (Fixed chipio_t structure)
- * Modified: 2.13 Christian Gennerat <christian.gennerat@polytechnique.org>
- * Modified: 2.13 dim jan 07 21:57:39 2001 (tested with kernel 2.4 & irnet/ppp)
- * Modified: 2.14 Christian Gennerat <christian.gennerat@polytechnique.org>
- * Modified: 2.14 lun fev 05 17:55:59 2001 (adapted to patch-2.4.1-pre8-irda1)
- * Modified: 2.15 Martin Lucina <mato@kotelna.sk>
- * Modified: 2.15 Fri Jun 21 20:40:59 2002 (sync with 2.4.18, substantial fixes)
- * Modified: 2.16 Martin Lucina <mato@kotelna.sk>
- * Modified: 2.16 Sat Jun 22 18:54:29 2002 (fix freeregion, default to verbose)
- * Modified: 2.17 Christian Gennerat <christian.gennerat@polytechnique.org>
- * Modified: 2.17 jeu sep 12 08:50:20 2002 (save_flags();cli(); replaced by spinlocks)
- * Modified: 2.18 Christian Gennerat <christian.gennerat@polytechnique.org>
- * Modified: 2.18 ven jan 10 03:14:16 2003 Change probe default options
- *
- * Copyright (c) 1999 James McKenzie, 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.
- *
- * Neither James McKenzie nor Cambridge University admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- * Applicable Models : Libretto 100/110CT and many more.
- * Toshiba refers to this chip as the type-O IR port,
- * or the type-DO IR port.
- *
- ********************************************************************/
-
-/* Look at toshoboe.h (currently in include/net/irda) for details of */
-/* Where to get documentation on the chip */
-
-/* See below for a description of the logic in this driver */
-
-/* User servicable parts */
-/* USE_PROBE Create the code which probes the chip and does a few tests */
-/* do_probe module parameter Enable this code */
-/* Probe code is very useful for understanding how the hardware works */
-/* Use it with various combinations of TT_LEN, RX_LEN */
-/* Strongly recommended, disable if the probe fails on your machine */
-/* and send me <james@fishsoup.dhs.org> the output of dmesg */
-#define USE_PROBE 1
-#undef USE_PROBE
-
-/* Trace Transmit ring, interrupts, Receive ring or not ? */
-#define PROBE_VERBOSE 1
-
-/* Debug option, examine sent and received raw data */
-/* Irdadump is better, but does not see all packets. enable it if you want. */
-#undef DUMP_PACKETS
-
-/* MIR mode has not been tested. Some behaviour is different */
-/* Seems to work against an Ericsson R520 for me. -Martin */
-#define USE_MIR
-
-/* Schedule back to back hardware transmits wherever possible, otherwise */
-/* we need an interrupt for every frame, unset if oboe works for a bit and */
-/* then hangs */
-#define OPTIMIZE_TX
-
-/* Set the number of slots in the rings */
-/* If you get rx/tx fifo overflows at high bitrates, you can try increasing */
-/* these */
-
-#define RING_SIZE (OBOE_RING_SIZE_RX8 | OBOE_RING_SIZE_TX8)
-#define TX_SLOTS 8
-#define RX_SLOTS 8
-
-
-/* Less user servicable parts below here */
-
-/* Test, Transmit and receive buffer sizes, adjust at your peril */
-/* remarks: nfs usually needs 1k blocks */
-/* remarks: in SIR mode, CRC is received, -> RX_LEN=TX_LEN+2 */
-/* remarks: test accepts large blocks. Standard is 0x80 */
-/* When TT_LEN > RX_LEN (SIR mode) data is stored in successive slots. */
-/* When 3 or more slots are needed for each test packet, */
-/* data received in the first slots is overwritten, even */
-/* if OBOE_CTL_RX_HW_OWNS is not set, without any error! */
-#define TT_LEN 0x80
-#define TX_LEN 0xc00
-#define RX_LEN 0xc04
-/* Real transmitted length (SIR mode) is about 14+(2%*TX_LEN) more */
-/* long than user-defined length (see async_wrap_skb) and is less then 4K */
-/* Real received length is (max RX_LEN) differs from user-defined */
-/* length only b the CRC (2 or 4 bytes) */
-#define BUF_SAFETY 0x7a
-#define RX_BUF_SZ (RX_LEN)
-#define TX_BUF_SZ (TX_LEN+BUF_SAFETY)
-
-
-/* Logic of the netdev part of this driver */
-
-/* The RX ring is filled with buffers, when a packet arrives */
-/* it is DMA'd into the buffer which is marked used and RxDone called */
-/* RxDone forms an skb (and checks the CRC if in SIR mode) and ships */
-/* the packet off upstairs */
-
-/* The transmitter on the oboe chip can work in one of two modes */
-/* for each ring->tx[] the transmitter can either */
-/* a) transmit the packet, leave the trasmitter enabled and proceed to */
-/* the next ring */
-/* OR */
-/* b) transmit the packet, switch off the transmitter and issue TxDone */
-
-/* All packets are entered into the ring in mode b), if the ring was */
-/* empty the transmitter is started. */
-
-/* If OPTIMIZE_TX is defined then in TxDone if the ring contains */
-/* more than one packet, all but the last are set to mode a) [HOWEVER */
-/* the hardware may not notice this, this is why we start in mode b) ] */
-/* then restart the transmitter */
-
-/* If OPTIMIZE_TX is not defined then we just restart the transmitter */
-/* if the ring isn't empty */
-
-/* Speed changes are delayed until the TxRing is empty */
-/* mtt is handled by generating packets with bad CRCs, before the data */
-
-/* TODO: */
-/* check the mtt works ok */
-/* finish the watchdog */
-
-/* No user servicable parts below here */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/rtnetlink.h>
-
-#include <asm/io.h>
-
-#include <net/irda/wrapper.h>
-#include <net/irda/irda.h>
-//#include <net/irda/irmod.h>
-//#include <net/irda/irlap_frame.h>
-#include <net/irda/irda_device.h>
-#include <net/irda/crc.h>
-
-#include "donauboe.h"
-
-#define INB(port) inb_p(port)
-#define OUTB(val,port) outb_p(val,port)
-#define OUTBP(val,port) outb_p(val,port)
-
-#define PROMPT OUTB(OBOE_PROMPT_BIT,OBOE_PROMPT);
-
-#if PROBE_VERBOSE
-#define PROBE_DEBUG(args...) (printk (args))
-#else
-#define PROBE_DEBUG(args...) ;
-#endif
-
-/* Set the DMA to be byte at a time */
-#define CONFIG0H_DMA_OFF OBOE_CONFIG0H_RCVANY
-#define CONFIG0H_DMA_ON_NORX CONFIG0H_DMA_OFF| OBOE_CONFIG0H_ENDMAC
-#define CONFIG0H_DMA_ON CONFIG0H_DMA_ON_NORX | OBOE_CONFIG0H_ENRX
-
-static const struct pci_device_id toshoboe_pci_tbl[] = {
- { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIRD01, PCI_ANY_ID, PCI_ANY_ID, },
- { } /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, toshoboe_pci_tbl);
-
-#define DRIVER_NAME "toshoboe"
-static char *driver_name = DRIVER_NAME;
-
-static int max_baud = 4000000;
-#ifdef USE_PROBE
-static bool do_probe = false;
-#endif
-
-
-/**********************************************************************/
-static int
-toshoboe_checkfcs (unsigned char *buf, int len)
-{
- int i;
- union
- {
- __u16 value;
- __u8 bytes[2];
- }
- fcs;
-
- fcs.value = INIT_FCS;
-
- for (i = 0; i < len; ++i)
- fcs.value = irda_fcs (fcs.value, *(buf++));
-
- return fcs.value == GOOD_FCS;
-}
-
-/***********************************************************************/
-/* Generic chip handling code */
-#ifdef DUMP_PACKETS
-static unsigned char dump[50];
-static void
-_dumpbufs (unsigned char *data, int len, char tete)
-{
-int i,j;
-char head=tete;
-for (i=0;i<len;i+=16) {
- for (j=0;j<16 && i+j<len;j++) { sprintf(&dump[3*j],"%02x.",data[i+j]); }
- dump [3*j]=0;
- pr_debug("%c%s\n", head, dump);
- head='+';
- }
-}
-#endif
-
-#ifdef USE_PROBE
-/* Dump the registers */
-static void
-toshoboe_dumpregs (struct toshoboe_cb *self)
-{
- __u32 ringbase;
-
- ringbase = INB (OBOE_RING_BASE0) << 10;
- ringbase |= INB (OBOE_RING_BASE1) << 18;
- ringbase |= INB (OBOE_RING_BASE2) << 26;
-
- printk (KERN_ERR DRIVER_NAME ": Register dump:\n");
- printk (KERN_ERR "Interrupts: Tx:%d Rx:%d TxUnder:%d RxOver:%d Sip:%d\n",
- self->int_tx, self->int_rx, self->int_txunder, self->int_rxover,
- self->int_sip);
- printk (KERN_ERR "RX %02x TX %02x RingBase %08x\n",
- INB (OBOE_RXSLOT), INB (OBOE_TXSLOT), ringbase);
- printk (KERN_ERR "RING_SIZE %02x IER %02x ISR %02x\n",
- INB (OBOE_RING_SIZE), INB (OBOE_IER), INB (OBOE_ISR));
- printk (KERN_ERR "CONFIG1 %02x STATUS %02x\n",
- INB (OBOE_CONFIG1), INB (OBOE_STATUS));
- printk (KERN_ERR "CONFIG0 %02x%02x ENABLE %02x%02x\n",
- INB (OBOE_CONFIG0H), INB (OBOE_CONFIG0L),
- INB (OBOE_ENABLEH), INB (OBOE_ENABLEL));
- printk (KERN_ERR "NEW_PCONFIG %02x%02x CURR_PCONFIG %02x%02x\n",
- INB (OBOE_NEW_PCONFIGH), INB (OBOE_NEW_PCONFIGL),
- INB (OBOE_CURR_PCONFIGH), INB (OBOE_CURR_PCONFIGL));
- printk (KERN_ERR "MAXLEN %02x%02x RXCOUNT %02x%02x\n",
- INB (OBOE_MAXLENH), INB (OBOE_MAXLENL),
- INB (OBOE_RXCOUNTL), INB (OBOE_RXCOUNTH));
-
- if (self->ring)
- {
- int i;
- ringbase = virt_to_bus (self->ring);
- printk (KERN_ERR "Ring at %08x:\n", ringbase);
- printk (KERN_ERR "RX:");
- for (i = 0; i < RX_SLOTS; ++i)
- printk (" (%d,%02x)",self->ring->rx[i].len,self->ring->rx[i].control);
- printk ("\n");
- printk (KERN_ERR "TX:");
- for (i = 0; i < RX_SLOTS; ++i)
- printk (" (%d,%02x)",self->ring->tx[i].len,self->ring->tx[i].control);
- printk ("\n");
- }
-}
-#endif
-
-/*Don't let the chip look at memory */
-static void
-toshoboe_disablebm (struct toshoboe_cb *self)
-{
- __u8 command;
- pci_read_config_byte (self->pdev, PCI_COMMAND, &command);
- command &= ~PCI_COMMAND_MASTER;
- pci_write_config_byte (self->pdev, PCI_COMMAND, command);
-
-}
-
-/* Shutdown the chip and point the taskfile reg somewhere else */
-static void
-toshoboe_stopchip (struct toshoboe_cb *self)
-{
- /*Disable interrupts */
- OUTB (0x0, OBOE_IER);
- /*Disable DMA, Disable Rx, Disable Tx */
- OUTB (CONFIG0H_DMA_OFF, OBOE_CONFIG0H);
- /*Disable SIR MIR FIR, Tx and Rx */
- OUTB (0x00, OBOE_ENABLEH);
- /*Point the ring somewhere safe */
- OUTB (0x3f, OBOE_RING_BASE2);
- OUTB (0xff, OBOE_RING_BASE1);
- OUTB (0xff, OBOE_RING_BASE0);
-
- OUTB (RX_LEN >> 8, OBOE_MAXLENH);
- OUTB (RX_LEN & 0xff, OBOE_MAXLENL);
-
- /*Acknoledge any pending interrupts */
- OUTB (0xff, OBOE_ISR);
-
- /*Why */
- OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
-
- /*switch it off */
- OUTB (OBOE_CONFIG1_OFF, OBOE_CONFIG1);
-
- toshoboe_disablebm (self);
-}
-
-/* Transmitter initialization */
-static void
-toshoboe_start_DMA (struct toshoboe_cb *self, int opts)
-{
- OUTB (0x0, OBOE_ENABLEH);
- OUTB (CONFIG0H_DMA_ON | opts, OBOE_CONFIG0H);
- OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
- PROMPT;
-}
-
-/*Set the baud rate */
-static void
-toshoboe_setbaud (struct toshoboe_cb *self)
-{
- __u16 pconfig = 0;
- __u8 config0l = 0;
-
- pr_debug("%s(%d/%d)\n", __func__, self->speed, self->io.speed);
-
- switch (self->speed)
- {
- case 2400:
- case 4800:
- case 9600:
- case 19200:
- case 38400:
- case 57600:
- case 115200:
-#ifdef USE_MIR
- case 1152000:
-#endif
- case 4000000:
- break;
- default:
-
- printk (KERN_ERR DRIVER_NAME ": switch to unsupported baudrate %d\n",
- self->speed);
- return;
- }
-
- switch (self->speed)
- {
- /* For SIR the preamble is done by adding XBOFs */
- /* to the packet */
- /* set to filtered SIR mode, filter looks for BOF and EOF */
- case 2400:
- pconfig |= 47 << OBOE_PCONFIG_BAUDSHIFT;
- pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
- break;
- case 4800:
- pconfig |= 23 << OBOE_PCONFIG_BAUDSHIFT;
- pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
- break;
- case 9600:
- pconfig |= 11 << OBOE_PCONFIG_BAUDSHIFT;
- pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
- break;
- case 19200:
- pconfig |= 5 << OBOE_PCONFIG_BAUDSHIFT;
- pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
- break;
- case 38400:
- pconfig |= 2 << OBOE_PCONFIG_BAUDSHIFT;
- pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
- break;
- case 57600:
- pconfig |= 1 << OBOE_PCONFIG_BAUDSHIFT;
- pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
- break;
- case 115200:
- pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT;
- pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
- break;
- default:
- /*Set to packet based reception */
- OUTB (RX_LEN >> 8, OBOE_MAXLENH);
- OUTB (RX_LEN & 0xff, OBOE_MAXLENL);
- break;
- }
-
- switch (self->speed)
- {
- case 2400:
- case 4800:
- case 9600:
- case 19200:
- case 38400:
- case 57600:
- case 115200:
- config0l = OBOE_CONFIG0L_ENSIR;
- if (self->async)
- {
- /*Set to character based reception */
- /*System will lock if MAXLEN=0 */
- /*so have to be careful */
- OUTB (0x01, OBOE_MAXLENH);
- OUTB (0x01, OBOE_MAXLENL);
- OUTB (0x00, OBOE_MAXLENH);
- }
- else
- {
- /*Set to packet based reception */
- config0l |= OBOE_CONFIG0L_ENSIRF;
- OUTB (RX_LEN >> 8, OBOE_MAXLENH);
- OUTB (RX_LEN & 0xff, OBOE_MAXLENL);
- }
- break;
-
-#ifdef USE_MIR
- /* MIR mode */
- /* Set for 16 bit CRC and enable MIR */
- /* Preamble now handled by the chip */
- case 1152000:
- pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT;
- pconfig |= 8 << OBOE_PCONFIG_WIDTHSHIFT;
- pconfig |= 1 << OBOE_PCONFIG_PREAMBLESHIFT;
- config0l = OBOE_CONFIG0L_CRC16 | OBOE_CONFIG0L_ENMIR;
- break;
-#endif
- /* FIR mode */
- /* Set for 32 bit CRC and enable FIR */
- /* Preamble handled by the chip */
- case 4000000:
- pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT;
- /* Documentation says 14, but toshiba use 15 in their drivers */
- pconfig |= 15 << OBOE_PCONFIG_PREAMBLESHIFT;
- config0l = OBOE_CONFIG0L_ENFIR;
- break;
- }
-
- /* Copy into new PHY config buffer */
- OUTBP (pconfig >> 8, OBOE_NEW_PCONFIGH);
- OUTB (pconfig & 0xff, OBOE_NEW_PCONFIGL);
- OUTB (config0l, OBOE_CONFIG0L);
-
- /* Now make OBOE copy from new PHY to current PHY */
- OUTB (0x0, OBOE_ENABLEH);
- OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
- PROMPT;
-
- /* speed change executed */
- self->new_speed = 0;
- self->io.speed = self->speed;
-}
-
-/*Let the chip look at memory */
-static void
-toshoboe_enablebm (struct toshoboe_cb *self)
-{
- pci_set_master (self->pdev);
-}
-
-/*setup the ring */
-static void
-toshoboe_initring (struct toshoboe_cb *self)
-{
- int i;
-
- for (i = 0; i < TX_SLOTS; ++i)
- {
- self->ring->tx[i].len = 0;
- self->ring->tx[i].control = 0x00;
- self->ring->tx[i].address = virt_to_bus (self->tx_bufs[i]);
- }
-
- for (i = 0; i < RX_SLOTS; ++i)
- {
- self->ring->rx[i].len = RX_LEN;
- self->ring->rx[i].len = 0;
- self->ring->rx[i].address = virt_to_bus (self->rx_bufs[i]);
- self->ring->rx[i].control = OBOE_CTL_RX_HW_OWNS;
- }
-}
-
-static void
-toshoboe_resetptrs (struct toshoboe_cb *self)
-{
- /* Can reset pointers by twidling DMA */
- OUTB (0x0, OBOE_ENABLEH);
- OUTBP (CONFIG0H_DMA_OFF, OBOE_CONFIG0H);
- OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
-
- self->rxs = inb_p (OBOE_RXSLOT) & OBOE_SLOT_MASK;
- self->txs = inb_p (OBOE_TXSLOT) & OBOE_SLOT_MASK;
-}
-
-/* Called in locked state */
-static void
-toshoboe_initptrs (struct toshoboe_cb *self)
-{
-
- /* spin_lock_irqsave(self->spinlock, flags); */
- /* save_flags (flags); */
-
- /* Can reset pointers by twidling DMA */
- toshoboe_resetptrs (self);
-
- OUTB (0x0, OBOE_ENABLEH);
- OUTB (CONFIG0H_DMA_ON, OBOE_CONFIG0H);
- OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
-
- self->txpending = 0;
-
- /* spin_unlock_irqrestore(self->spinlock, flags); */
- /* restore_flags (flags); */
-}
-
-/* Wake the chip up and get it looking at the rings */
-/* Called in locked state */
-static void
-toshoboe_startchip (struct toshoboe_cb *self)
-{
- __u32 physaddr;
-
- toshoboe_initring (self);
- toshoboe_enablebm (self);
- OUTBP (OBOE_CONFIG1_RESET, OBOE_CONFIG1);
- OUTBP (OBOE_CONFIG1_ON, OBOE_CONFIG1);
-
- /* Stop the clocks */
- OUTB (0, OBOE_ENABLEH);
-
- /*Set size of rings */
- OUTB (RING_SIZE, OBOE_RING_SIZE);
-
- /*Acknoledge any pending interrupts */
- OUTB (0xff, OBOE_ISR);
-
- /*Enable ints */
- OUTB (OBOE_INT_TXDONE | OBOE_INT_RXDONE |
- OBOE_INT_TXUNDER | OBOE_INT_RXOVER | OBOE_INT_SIP , OBOE_IER);
-
- /*Acknoledge any pending interrupts */
- OUTB (0xff, OBOE_ISR);
-
- /*Set the maximum packet length to 0xfff (4095) */
- OUTB (RX_LEN >> 8, OBOE_MAXLENH);
- OUTB (RX_LEN & 0xff, OBOE_MAXLENL);
-
- /*Shutdown DMA */
- OUTB (CONFIG0H_DMA_OFF, OBOE_CONFIG0H);
-
- /*Find out where the rings live */
- physaddr = virt_to_bus (self->ring);
-
- IRDA_ASSERT ((physaddr & 0x3ff) == 0,
- printk (KERN_ERR DRIVER_NAME "ring not correctly aligned\n");
- return;);
-
- OUTB ((physaddr >> 10) & 0xff, OBOE_RING_BASE0);
- OUTB ((physaddr >> 18) & 0xff, OBOE_RING_BASE1);
- OUTB ((physaddr >> 26) & 0x3f, OBOE_RING_BASE2);
-
- /*Enable DMA controller in byte mode and RX */
- OUTB (CONFIG0H_DMA_ON, OBOE_CONFIG0H);
-
- /* Start up the clocks */
- OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
-
- /*set to sensible speed */
- self->speed = 9600;
- toshoboe_setbaud (self);
- toshoboe_initptrs (self);
-}
-
-static void
-toshoboe_isntstuck (struct toshoboe_cb *self)
-{
-}
-
-static void
-toshoboe_checkstuck (struct toshoboe_cb *self)
-{
- unsigned long flags;
-
- if (0)
- {
- spin_lock_irqsave(&self->spinlock, flags);
-
- /* This will reset the chip completely */
- printk (KERN_ERR DRIVER_NAME ": Resetting chip\n");
-
- toshoboe_stopchip (self);
- toshoboe_startchip (self);
- spin_unlock_irqrestore(&self->spinlock, flags);
- }
-}
-
-/*Generate packet of about mtt us long */
-static int
-toshoboe_makemttpacket (struct toshoboe_cb *self, void *buf, int mtt)
-{
- int xbofs;
-
- xbofs = ((int) (mtt/100)) * (int) (self->speed);
- xbofs=xbofs/80000; /*Eight bits per byte, and mtt is in us*/
- xbofs++;
-
- pr_debug(DRIVER_NAME ": generated mtt of %d bytes for %d us at %d baud\n",
- xbofs, mtt, self->speed);
-
- if (xbofs > TX_LEN)
- {
- printk (KERN_ERR DRIVER_NAME ": wanted %d bytes MTT but TX_LEN is %d\n",
- xbofs, TX_LEN);
- xbofs = TX_LEN;
- }
-
- /*xbofs will do for SIR, MIR and FIR,SIR mode doesn't generate a checksum anyway */
- memset (buf, XBOF, xbofs);
-
- return xbofs;
-}
-
-#ifdef USE_PROBE
-/***********************************************************************/
-/* Probe code */
-
-static void
-toshoboe_dumptx (struct toshoboe_cb *self)
-{
- int i;
- PROBE_DEBUG(KERN_WARNING "TX:");
- for (i = 0; i < RX_SLOTS; ++i)
- PROBE_DEBUG(" (%d,%02x)",self->ring->tx[i].len,self->ring->tx[i].control);
- PROBE_DEBUG(" [%d]\n",self->speed);
-}
-
-static void
-toshoboe_dumprx (struct toshoboe_cb *self, int score)
-{
- int i;
- PROBE_DEBUG(" %d\nRX:",score);
- for (i = 0; i < RX_SLOTS; ++i)
- PROBE_DEBUG(" (%d,%02x)",self->ring->rx[i].len,self->ring->rx[i].control);
- PROBE_DEBUG("\n");
-}
-
-static inline int
-stuff_byte (__u8 byte, __u8 * buf)
-{
- switch (byte)
- {
- case BOF: /* FALLTHROUGH */
- case EOF: /* FALLTHROUGH */
- case CE:
- /* Insert transparently coded */
- buf[0] = CE; /* Send link escape */
- buf[1] = byte ^ IRDA_TRANS; /* Complement bit 5 */
- return 2;
- /* break; */
- default:
- /* Non-special value, no transparency required */
- buf[0] = byte;
- return 1;
- /* break; */
- }
-}
-
-static irqreturn_t
-toshoboe_probeinterrupt (int irq, void *dev_id)
-{
- struct toshoboe_cb *self = dev_id;
- __u8 irqstat;
-
- irqstat = INB (OBOE_ISR);
-
-/* was it us */
- if (!(irqstat & OBOE_INT_MASK))
- return IRQ_NONE;
-
-/* Ack all the interrupts */
- OUTB (irqstat, OBOE_ISR);
-
- if (irqstat & OBOE_INT_TXDONE)
- {
- int txp;
-
- self->int_tx++;
- PROBE_DEBUG("T");
-
- txp = INB (OBOE_TXSLOT) & OBOE_SLOT_MASK;
- if (self->ring->tx[txp].control & OBOE_CTL_TX_HW_OWNS)
- {
- self->int_tx+=100;
- PROBE_DEBUG("S");
- toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP);
- }
- }
-
- if (irqstat & OBOE_INT_RXDONE) {
- self->int_rx++;
- PROBE_DEBUG("R"); }
- if (irqstat & OBOE_INT_TXUNDER) {
- self->int_txunder++;
- PROBE_DEBUG("U"); }
- if (irqstat & OBOE_INT_RXOVER) {
- self->int_rxover++;
- PROBE_DEBUG("O"); }
- if (irqstat & OBOE_INT_SIP) {
- self->int_sip++;
- PROBE_DEBUG("I"); }
- return IRQ_HANDLED;
-}
-
-static int
-toshoboe_maketestpacket (unsigned char *buf, int badcrc, int fir)
-{
- int i;
- int len = 0;
- union
- {
- __u16 value;
- __u8 bytes[2];
- }
- fcs;
-
- if (fir)
- {
- memset (buf, 0, TT_LEN);
- return TT_LEN;
- }
-
- fcs.value = INIT_FCS;
-
- memset (buf, XBOF, 10);
- len += 10;
- buf[len++] = BOF;
-
- for (i = 0; i < TT_LEN; ++i)
- {
- len += stuff_byte (i, buf + len);
- fcs.value = irda_fcs (fcs.value, i);
- }
-
- len += stuff_byte (fcs.bytes[0] ^ badcrc, buf + len);
- len += stuff_byte (fcs.bytes[1] ^ badcrc, buf + len);
- buf[len++] = EOF;
- len++;
- return len;
-}
-
-static int
-toshoboe_probefail (struct toshoboe_cb *self, char *msg)
-{
- printk (KERN_ERR DRIVER_NAME "probe(%d) failed %s\n",self-> speed, msg);
- toshoboe_dumpregs (self);
- toshoboe_stopchip (self);
- free_irq (self->io.irq, (void *) self);
- return 0;
-}
-
-static int
-toshoboe_numvalidrcvs (struct toshoboe_cb *self)
-{
- int i, ret = 0;
- for (i = 0; i < RX_SLOTS; ++i)
- if ((self->ring->rx[i].control & 0xe0) == 0)
- ret++;
-
- return ret;
-}
-
-static int
-toshoboe_numrcvs (struct toshoboe_cb *self)
-{
- int i, ret = 0;
- for (i = 0; i < RX_SLOTS; ++i)
- if (!(self->ring->rx[i].control & OBOE_CTL_RX_HW_OWNS))
- ret++;
-
- return ret;
-}
-
-static int
-toshoboe_probe (struct toshoboe_cb *self)
-{
- int i, j, n;
-#ifdef USE_MIR
- static const int bauds[] = { 9600, 115200, 4000000, 1152000 };
-#else
- static const int bauds[] = { 9600, 115200, 4000000 };
-#endif
- unsigned long flags;
-
- if (request_irq (self->io.irq, toshoboe_probeinterrupt,
- self->io.irqflags, "toshoboe", (void *) self))
- {
- printk (KERN_ERR DRIVER_NAME ": probe failed to allocate irq %d\n",
- self->io.irq);
- return 0;
- }
-
- /* test 1: SIR filter and back to back */
-
- for (j = 0; j < ARRAY_SIZE(bauds); ++j)
- {
- int fir = (j > 1);
- toshoboe_stopchip (self);
-
-
- spin_lock_irqsave(&self->spinlock, flags);
- /*Address is already setup */
- toshoboe_startchip (self);
- self->int_rx = self->int_tx = 0;
- self->speed = bauds[j];
- toshoboe_setbaud (self);
- toshoboe_initptrs (self);
- spin_unlock_irqrestore(&self->spinlock, flags);
-
- self->ring->tx[self->txs].control =
-/* (FIR only) OBOE_CTL_TX_SIP needed for switching to next slot */
-/* MIR: all received data is stored in one slot */
- (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX
- : OBOE_CTL_TX_HW_OWNS ;
- self->ring->tx[self->txs].len =
- toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir);
- self->txs++;
- self->txs %= TX_SLOTS;
-
- self->ring->tx[self->txs].control =
- (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_SIP
- : OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX ;
- self->ring->tx[self->txs].len =
- toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir);
- self->txs++;
- self->txs %= TX_SLOTS;
-
- self->ring->tx[self->txs].control =
- (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX
- : OBOE_CTL_TX_HW_OWNS ;
- self->ring->tx[self->txs].len =
- toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir);
- self->txs++;
- self->txs %= TX_SLOTS;
-
- self->ring->tx[self->txs].control =
- (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX
- | OBOE_CTL_TX_SIP | OBOE_CTL_TX_BAD_CRC
- : OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX ;
- self->ring->tx[self->txs].len =
- toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir);
- self->txs++;
- self->txs %= TX_SLOTS;
-
- toshoboe_dumptx (self);
- /* Turn on TX and RX and loopback */
- toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP);
-
- i = 0;
- n = fir ? 1 : 4;
- while (toshoboe_numvalidrcvs (self) != n)
- {
- if (i > 4800)
- return toshoboe_probefail (self, "filter test");
- udelay ((9600*(TT_LEN+16))/self->speed);
- i++;
- }
-
- n = fir ? 203 : 102;
- while ((toshoboe_numrcvs(self) != self->int_rx) || (self->int_tx != n))
- {
- if (i > 4800)
- return toshoboe_probefail (self, "interrupt test");
- udelay ((9600*(TT_LEN+16))/self->speed);
- i++;
- }
- toshoboe_dumprx (self,i);
-
- }
-
- /* test 2: SIR in char at a time */
-
- toshoboe_stopchip (self);
- self->int_rx = self->int_tx = 0;
-
- spin_lock_irqsave(&self->spinlock, flags);
- toshoboe_startchip (self);
- spin_unlock_irqrestore(&self->spinlock, flags);
-
- self->async = 1;
- self->speed = 115200;
- toshoboe_setbaud (self);
- self->ring->tx[self->txs].control =
- OBOE_CTL_TX_RTCENTX | OBOE_CTL_TX_HW_OWNS;
- self->ring->tx[self->txs].len = 4;
-
- ((unsigned char *) self->tx_bufs[self->txs])[0] = 'f';
- ((unsigned char *) self->tx_bufs[self->txs])[1] = 'i';
- ((unsigned char *) self->tx_bufs[self->txs])[2] = 's';
- ((unsigned char *) self->tx_bufs[self->txs])[3] = 'h';
- toshoboe_dumptx (self);
- toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP);
-
- i = 0;
- while (toshoboe_numvalidrcvs (self) != 4)
- {
- if (i > 100)
- return toshoboe_probefail (self, "Async test");
- udelay (100);
- i++;
- }
-
- while ((toshoboe_numrcvs (self) != self->int_rx) || (self->int_tx != 1))
- {
- if (i > 100)
- return toshoboe_probefail (self, "Async interrupt test");
- udelay (100);
- i++;
- }
- toshoboe_dumprx (self,i);
-
- self->async = 0;
- self->speed = 9600;
- toshoboe_setbaud (self);
- toshoboe_stopchip (self);
-
- free_irq (self->io.irq, (void *) self);
-
- printk (KERN_WARNING DRIVER_NAME ": Self test passed ok\n");
-
- return 1;
-}
-#endif
-
-/******************************************************************/
-/* Netdev style code */
-
-/* Transmit something */
-static netdev_tx_t
-toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
-{
- struct toshoboe_cb *self;
- __s32 speed;
- int mtt, len, ctl;
- unsigned long flags;
- struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb;
-
- self = netdev_priv(dev);
-
- IRDA_ASSERT (self != NULL, return NETDEV_TX_OK; );
-
- pr_debug("%s.tx:%x(%x)%x\n",
- __func__, skb->len, self->txpending, INB(OBOE_ENABLEH));
- if (!cb->magic) {
- pr_debug("%s.Not IrLAP:%x\n", __func__, cb->magic);
-#ifdef DUMP_PACKETS
- _dumpbufs(skb->data,skb->len,'>');
-#endif
- }
-
- /* change speed pending, wait for its execution */
- if (self->new_speed)
- return NETDEV_TX_BUSY;
-
- /* device stopped (apm) wait for restart */
- if (self->stopped)
- return NETDEV_TX_BUSY;
-
- toshoboe_checkstuck (self);
-
- /* Check if we need to change the speed */
- /* But not now. Wait after transmission if mtt not required */
- speed=irda_get_next_speed(skb);
- if ((speed != self->io.speed) && (speed != -1))
- {
- spin_lock_irqsave(&self->spinlock, flags);
-
- if (self->txpending || skb->len)
- {
- self->new_speed = speed;
- pr_debug("%s: Queued TxDone scheduled speed change %d\n" ,
- __func__, speed);
- /* if no data, that's all! */
- if (!skb->len)
- {
- spin_unlock_irqrestore(&self->spinlock, flags);
- dev_kfree_skb (skb);
- return NETDEV_TX_OK;
- }
- /* True packet, go on, but */
- /* do not accept anything before change speed execution */
- netif_stop_queue(dev);
- /* ready to process TxDone interrupt */
- spin_unlock_irqrestore(&self->spinlock, flags);
- }
- else
- {
- /* idle and no data, change speed now */
- self->speed = speed;
- toshoboe_setbaud (self);
- spin_unlock_irqrestore(&self->spinlock, flags);
- dev_kfree_skb (skb);
- return NETDEV_TX_OK;
- }
-
- }
-
- if ((mtt = irda_get_mtt(skb)))
- {
- /* This is fair since the queue should be empty anyway */
- spin_lock_irqsave(&self->spinlock, flags);
-
- if (self->txpending)
- {
- spin_unlock_irqrestore(&self->spinlock, flags);
- return NETDEV_TX_BUSY;
- }
-
- /* If in SIR mode we need to generate a string of XBOFs */
- /* In MIR and FIR we need to generate a string of data */
- /* which we will add a wrong checksum to */
-
- mtt = toshoboe_makemttpacket (self, self->tx_bufs[self->txs], mtt);
- pr_debug("%s.mtt:%x(%x)%d\n", __func__, skb->len, mtt, self->txpending);
- if (mtt)
- {
- self->ring->tx[self->txs].len = mtt & 0xfff;
-
- ctl = OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX;
- if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_FIRON)
- {
- ctl |= OBOE_CTL_TX_BAD_CRC | OBOE_CTL_TX_SIP ;
- }
-#ifdef USE_MIR
- else if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_MIRON)
- {
- ctl |= OBOE_CTL_TX_BAD_CRC;
- }
-#endif
- self->ring->tx[self->txs].control = ctl;
-
- OUTB (0x0, OBOE_ENABLEH);
- /* It is only a timer. Do not send mtt packet outside! */
- toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP);
-
- self->txpending++;
-
- self->txs++;
- self->txs %= TX_SLOTS;
-
- }
- else
- {
- printk(KERN_ERR DRIVER_NAME ": problem with mtt packet - ignored\n");
- }
- spin_unlock_irqrestore(&self->spinlock, flags);
- }
-
-#ifdef DUMP_PACKETS
-dumpbufs(skb->data,skb->len,'>');
-#endif
-
- spin_lock_irqsave(&self->spinlock, flags);
-
- if (self->ring->tx[self->txs].control & OBOE_CTL_TX_HW_OWNS)
- {
- pr_debug("%s.ful:%x(%x)%x\n",
- __func__, skb->len, self->ring->tx[self->txs].control,
- self->txpending);
- toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX);
- spin_unlock_irqrestore(&self->spinlock, flags);
- return NETDEV_TX_BUSY;
- }
-
- if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_SIRON)
- {
- len = async_wrap_skb (skb, self->tx_bufs[self->txs], TX_BUF_SZ);
- }
- else
- {
- len = skb->len;
- skb_copy_from_linear_data(skb, self->tx_bufs[self->txs], len);
- }
- self->ring->tx[self->txs].len = len & 0x0fff;
-
- /*Sometimes the HW doesn't see us assert RTCENTX in the interrupt code */
- /*later this plays safe, we garuntee the last packet to be transmitted */
- /*has RTCENTX set */
-
- ctl = OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX;
- if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_FIRON)
- {
- ctl |= OBOE_CTL_TX_SIP ;
- }
- self->ring->tx[self->txs].control = ctl;
-
- /* If transmitter is idle start in one-shot mode */
-
- if (!self->txpending)
- toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX);
-
- self->txpending++;
-
- self->txs++;
- self->txs %= TX_SLOTS;
-
- spin_unlock_irqrestore(&self->spinlock, flags);
- dev_kfree_skb (skb);
-
- return NETDEV_TX_OK;
-}
-
-/*interrupt handler */
-static irqreturn_t
-toshoboe_interrupt (int irq, void *dev_id)
-{
- struct toshoboe_cb *self = dev_id;
- __u8 irqstat;
- struct sk_buff *skb = NULL;
-
- irqstat = INB (OBOE_ISR);
-
-/* was it us */
- if (!(irqstat & OBOE_INT_MASK))
- return IRQ_NONE;
-
-/* Ack all the interrupts */
- OUTB (irqstat, OBOE_ISR);
-
- toshoboe_isntstuck (self);
-
-/* Txdone */
- if (irqstat & OBOE_INT_TXDONE)
- {
- int txp, txpc;
- int i;
-
- txp = self->txpending;
- self->txpending = 0;
-
- for (i = 0; i < TX_SLOTS; ++i)
- {
- if (self->ring->tx[i].control & OBOE_CTL_TX_HW_OWNS)
- self->txpending++;
- }
- pr_debug("%s.txd(%x)%x/%x\n", __func__, irqstat, txp, self->txpending);
-
- txp = INB (OBOE_TXSLOT) & OBOE_SLOT_MASK;
-
- /* Got anything queued ? start it together */
- if (self->ring->tx[txp].control & OBOE_CTL_TX_HW_OWNS)
- {
- txpc = txp;
-#ifdef OPTIMIZE_TX
- while (self->ring->tx[txpc].control & OBOE_CTL_TX_HW_OWNS)
- {
- txp = txpc;
- txpc++;
- txpc %= TX_SLOTS;
- self->netdev->stats.tx_packets++;
- if (self->ring->tx[txpc].control & OBOE_CTL_TX_HW_OWNS)
- self->ring->tx[txp].control &= ~OBOE_CTL_TX_RTCENTX;
- }
- self->netdev->stats.tx_packets--;
-#else
- self->netdev->stats.tx_packets++;
-#endif
- toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX);
- }
-
- if ((!self->txpending) && (self->new_speed))
- {
- self->speed = self->new_speed;
- pr_debug("%s: Executed TxDone scheduled speed change %d\n",
- __func__, self->speed);
- toshoboe_setbaud (self);
- }
-
- /* Tell network layer that we want more frames */
- if (!self->new_speed)
- netif_wake_queue(self->netdev);
- }
-
- if (irqstat & OBOE_INT_RXDONE)
- {
- while (!(self->ring->rx[self->rxs].control & OBOE_CTL_RX_HW_OWNS))
- {
- int len = self->ring->rx[self->rxs].len;
- skb = NULL;
- pr_debug("%s.rcv:%x(%x)\n", __func__
- , len, self->ring->rx[self->rxs].control);
-
-#ifdef DUMP_PACKETS
-dumpbufs(self->rx_bufs[self->rxs],len,'<');
-#endif
-
- if (self->ring->rx[self->rxs].control == 0)
- {
- __u8 enable = INB (OBOE_ENABLEH);
-
- /* In SIR mode we need to check the CRC as this */
- /* hasn't been done by the hardware */
- if (enable & OBOE_ENABLEH_SIRON)
- {
- if (!toshoboe_checkfcs (self->rx_bufs[self->rxs], len))
- len = 0;
- /*Trim off the CRC */
- if (len > 1)
- len -= 2;
- else
- len = 0;
- pr_debug("%s.SIR:%x(%x)\n", __func__, len, enable);
- }
-
-#ifdef USE_MIR
- else if (enable & OBOE_ENABLEH_MIRON)
- {
- if (len > 1)
- len -= 2;
- else
- len = 0;
- pr_debug("%s.MIR:%x(%x)\n", __func__, len, enable);
- }
-#endif
- else if (enable & OBOE_ENABLEH_FIRON)
- {
- if (len > 3)
- len -= 4; /*FIXME: check this */
- else
- len = 0;
- pr_debug("%s.FIR:%x(%x)\n", __func__, len, enable);
- }
- else
- pr_debug("%s.?IR:%x(%x)\n", __func__, len, enable);
-
- if (len)
- {
- skb = dev_alloc_skb (len + 1);
- if (skb)
- {
- skb_reserve (skb, 1);
-
- skb_put (skb, len);
- skb_copy_to_linear_data(skb, self->rx_bufs[self->rxs],
- len);
- self->netdev->stats.rx_packets++;
- skb->dev = self->netdev;
- skb_reset_mac_header(skb);
- skb->protocol = htons (ETH_P_IRDA);
- }
- else
- {
- printk (KERN_INFO
- "%s(), memory squeeze, dropping frame.\n",
- __func__);
- }
- }
- }
- else
- {
- /* TODO: =========================================== */
- /* if OBOE_CTL_RX_LENGTH, our buffers are too small */
- /* (MIR or FIR) data is lost. */
- /* (SIR) data is splitted in several slots. */
- /* we have to join all the received buffers received */
- /*in a large buffer before checking CRC. */
- pr_debug("%s.err:%x(%x)\n", __func__
- , len, self->ring->rx[self->rxs].control);
- }
-
- self->ring->rx[self->rxs].len = 0x0;
- self->ring->rx[self->rxs].control = OBOE_CTL_RX_HW_OWNS;
-
- self->rxs++;
- self->rxs %= RX_SLOTS;
-
- if (skb)
- netif_rx (skb);
-
- }
- }
-
- if (irqstat & OBOE_INT_TXUNDER)
- {
- printk (KERN_WARNING DRIVER_NAME ": tx fifo underflow\n");
- }
- if (irqstat & OBOE_INT_RXOVER)
- {
- printk (KERN_WARNING DRIVER_NAME ": rx fifo overflow\n");
- }
-/* This must be useful for something... */
- if (irqstat & OBOE_INT_SIP)
- {
- self->int_sip++;
- pr_debug("%s.sip:%x(%x)%x\n",
- __func__, self->int_sip, irqstat, self->txpending);
- }
- return IRQ_HANDLED;
-}
-
-
-static int
-toshoboe_net_open (struct net_device *dev)
-{
- struct toshoboe_cb *self;
- unsigned long flags;
- int rc;
-
- self = netdev_priv(dev);
-
- if (self->async)
- return -EBUSY;
-
- if (self->stopped)
- return 0;
-
- rc = request_irq (self->io.irq, toshoboe_interrupt,
- IRQF_SHARED, dev->name, self);
- if (rc)
- return rc;
-
- spin_lock_irqsave(&self->spinlock, flags);
- toshoboe_startchip (self);
- spin_unlock_irqrestore(&self->spinlock, flags);
-
- /* Ready to play! */
- netif_start_queue(dev);
-
- /*
- * Open new IrLAP layer instance, now that everything should be
- * initialized properly
- */
- self->irlap = irlap_open (dev, &self->qos, driver_name);
-
- self->irdad = 1;
-
- return 0;
-}
-
-static int
-toshoboe_net_close (struct net_device *dev)
-{
- struct toshoboe_cb *self;
-
- IRDA_ASSERT (dev != NULL, return -1; );
- self = netdev_priv(dev);
-
- /* Stop device */
- netif_stop_queue(dev);
-
- /* Stop and remove instance of IrLAP */
- if (self->irlap)
- irlap_close (self->irlap);
- self->irlap = NULL;
-
- self->irdad = 0;
-
- free_irq (self->io.irq, (void *) self);
-
- if (!self->stopped)
- {
- toshoboe_stopchip (self);
- }
-
- return 0;
-}
-
-/*
- * Function toshoboe_net_ioctl (dev, rq, cmd)
- *
- * Process IOCTL commands for this device
- *
- */
-static int
-toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct if_irda_req *irq = (struct if_irda_req *) rq;
- struct toshoboe_cb *self;
- unsigned long flags;
- int ret = 0;
-
- IRDA_ASSERT (dev != NULL, return -1; );
-
- self = netdev_priv(dev);
-
- IRDA_ASSERT (self != NULL, return -1; );
-
- pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
-
- /* Disable interrupts & save flags */
- spin_lock_irqsave(&self->spinlock, flags);
-
- switch (cmd)
- {
- case SIOCSBANDWIDTH: /* Set bandwidth */
- /* This function will also be used by IrLAP to change the
- * speed, so we still must allow for speed change within
- * interrupt context.
- */
- pr_debug("%s(BANDWIDTH), %s, (%X/%ld\n",
- __func__, dev->name, INB(OBOE_STATUS), irq->ifr_baudrate);
- if (!in_interrupt () && !capable (CAP_NET_ADMIN)) {
- ret = -EPERM;
- goto out;
- }
-
- /* self->speed=irq->ifr_baudrate; */
- /* toshoboe_setbaud(self); */
- /* Just change speed once - inserted by Paul Bristow */
- self->new_speed = irq->ifr_baudrate;
- break;
- case SIOCSMEDIABUSY: /* Set media busy */
- pr_debug("%s(MEDIABUSY), %s, (%X/%x)\n",
- __func__, dev->name,
- INB(OBOE_STATUS), capable(CAP_NET_ADMIN));
- if (!capable (CAP_NET_ADMIN)) {
- ret = -EPERM;
- goto out;
- }
- irda_device_set_media_busy (self->netdev, TRUE);
- break;
- case SIOCGRECEIVING: /* Check if we are receiving right now */
- irq->ifr_receiving = (INB (OBOE_STATUS) & OBOE_STATUS_RXBUSY) ? 1 : 0;
- pr_debug("%s(RECEIVING), %s, (%X/%x)\n",
- __func__, dev->name, INB(OBOE_STATUS), irq->ifr_receiving);
- break;
- default:
- pr_debug("%s(?), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
- ret = -EOPNOTSUPP;
- }
-out:
- spin_unlock_irqrestore(&self->spinlock, flags);
- return ret;
-
-}
-
-MODULE_DESCRIPTION("Toshiba OBOE IrDA Device Driver");
-MODULE_AUTHOR("James McKenzie <james@fishsoup.dhs.org>");
-MODULE_LICENSE("GPL");
-
-module_param (max_baud, int, 0);
-MODULE_PARM_DESC(max_baud, "Maximum baud rate");
-
-#ifdef USE_PROBE
-module_param (do_probe, bool, 0);
-MODULE_PARM_DESC(do_probe, "Enable/disable chip probing and self-test");
-#endif
-
-static void
-toshoboe_close (struct pci_dev *pci_dev)
-{
- int i;
- struct toshoboe_cb *self = pci_get_drvdata(pci_dev);
-
- IRDA_ASSERT (self != NULL, return; );
-
- if (!self->stopped)
- {
- toshoboe_stopchip (self);
- }
-
- release_region (self->io.fir_base, self->io.fir_ext);
-
- for (i = 0; i < TX_SLOTS; ++i)
- {
- kfree (self->tx_bufs[i]);
- self->tx_bufs[i] = NULL;
- }
-
- for (i = 0; i < RX_SLOTS; ++i)
- {
- kfree (self->rx_bufs[i]);
- self->rx_bufs[i] = NULL;
- }
-
- unregister_netdev(self->netdev);
-
- kfree (self->ringbuf);
- self->ringbuf = NULL;
- self->ring = NULL;
-
- free_netdev(self->netdev);
-}
-
-static const struct net_device_ops toshoboe_netdev_ops = {
- .ndo_open = toshoboe_net_open,
- .ndo_stop = toshoboe_net_close,
- .ndo_start_xmit = toshoboe_hard_xmit,
- .ndo_do_ioctl = toshoboe_net_ioctl,
-};
-
-static int
-toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid)
-{
- struct toshoboe_cb *self;
- struct net_device *dev;
- int i = 0;
- int ok = 0;
- int err;
-
- if ((err=pci_enable_device(pci_dev)))
- return err;
-
- dev = alloc_irdadev(sizeof (struct toshoboe_cb));
- if (dev == NULL)
- {
- printk (KERN_ERR DRIVER_NAME ": can't allocate memory for "
- "IrDA control block\n");
- return -ENOMEM;
- }
-
- self = netdev_priv(dev);
- self->netdev = dev;
- self->pdev = pci_dev;
- self->base = pci_resource_start(pci_dev,0);
-
- self->io.fir_base = self->base;
- self->io.fir_ext = OBOE_IO_EXTENT;
- self->io.irq = pci_dev->irq;
- self->io.irqflags = IRQF_SHARED;
-
- self->speed = self->io.speed = 9600;
- self->async = 0;
-
- /* Lock the port that we need */
- if (NULL==request_region (self->io.fir_base, self->io.fir_ext, driver_name))
- {
- printk (KERN_ERR DRIVER_NAME ": can't get iobase of 0x%03x\n"
- ,self->io.fir_base);
- err = -EBUSY;
- goto freeself;
- }
-
- spin_lock_init(&self->spinlock);
-
- irda_init_max_qos_capabilies (&self->qos);
- self->qos.baud_rate.bits = 0;
-
- if (max_baud >= 2400)
- self->qos.baud_rate.bits |= IR_2400;
- /*if (max_baud>=4800) idev->qos.baud_rate.bits|=IR_4800; */
- if (max_baud >= 9600)
- self->qos.baud_rate.bits |= IR_9600;
- if (max_baud >= 19200)
- self->qos.baud_rate.bits |= IR_19200;
- if (max_baud >= 115200)
- self->qos.baud_rate.bits |= IR_115200;
-#ifdef USE_MIR
- if (max_baud >= 1152000)
- {
- self->qos.baud_rate.bits |= IR_1152000;
- }
-#endif
- if (max_baud >= 4000000)
- {
- self->qos.baud_rate.bits |= (IR_4000000 << 8);
- }
-
- /*FIXME: work this out... */
- self->qos.min_turn_time.bits = 0xff;
-
- irda_qos_bits_to_value (&self->qos);
-
- /* Allocate twice the size to guarantee alignment */
- self->ringbuf = kmalloc(OBOE_RING_LEN << 1, GFP_KERNEL);
- if (!self->ringbuf)
- {
- err = -ENOMEM;
- goto freeregion;
- }
-
-#if (BITS_PER_LONG == 64)
-#error broken on 64-bit: casts pointer to 32-bit, and then back to pointer.
-#endif
-
- /*We need to align the taskfile on a taskfile size boundary */
- {
- unsigned long addr;
-
- addr = (__u32) self->ringbuf;
- addr &= ~(OBOE_RING_LEN - 1);
- addr += OBOE_RING_LEN;
- self->ring = (struct OboeRing *) addr;
- }
-
- memset (self->ring, 0, OBOE_RING_LEN);
- self->io.mem_base = (__u32) self->ring;
-
- ok = 1;
- for (i = 0; i < TX_SLOTS; ++i)
- {
- self->tx_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL);
- if (!self->tx_bufs[i])
- ok = 0;
- }
-
- for (i = 0; i < RX_SLOTS; ++i)
- {
- self->rx_bufs[i] = kmalloc (RX_BUF_SZ, GFP_KERNEL);
- if (!self->rx_bufs[i])
- ok = 0;
- }
-
- if (!ok)
- {
- err = -ENOMEM;
- goto freebufs;
- }
-
-
-#ifdef USE_PROBE
- if (do_probe)
- if (!toshoboe_probe (self))
- {
- err = -ENODEV;
- goto freebufs;
- }
-#endif
-
- SET_NETDEV_DEV(dev, &pci_dev->dev);
- dev->netdev_ops = &toshoboe_netdev_ops;
-
- err = register_netdev(dev);
- if (err)
- {
- printk (KERN_ERR DRIVER_NAME ": register_netdev() failed\n");
- err = -ENOMEM;
- goto freebufs;
- }
- printk (KERN_INFO "IrDA: Registered device %s\n", dev->name);
-
- pci_set_drvdata(pci_dev,self);
-
- printk (KERN_INFO DRIVER_NAME ": Using multiple tasks\n");
-
- return 0;
-
-freebufs:
- for (i = 0; i < TX_SLOTS; ++i)
- kfree (self->tx_bufs[i]);
- for (i = 0; i < RX_SLOTS; ++i)
- kfree (self->rx_bufs[i]);
- kfree(self->ringbuf);
-
-freeregion:
- release_region (self->io.fir_base, self->io.fir_ext);
-
-freeself:
- free_netdev(dev);
-
- return err;
-}
-
-static int
-toshoboe_gotosleep (struct pci_dev *pci_dev, pm_message_t crap)
-{
- struct toshoboe_cb *self = pci_get_drvdata(pci_dev);
- unsigned long flags;
- int i = 10;
-
- if (!self || self->stopped)
- return 0;
-
- if ((!self->irdad) && (!self->async))
- return 0;
-
-/* Flush all packets */
- while ((i--) && (self->txpending))
- msleep(10);
-
- spin_lock_irqsave(&self->spinlock, flags);
-
- toshoboe_stopchip (self);
- self->stopped = 1;
- self->txpending = 0;
-
- spin_unlock_irqrestore(&self->spinlock, flags);
- return 0;
-}
-
-static int
-toshoboe_wakeup (struct pci_dev *pci_dev)
-{
- struct toshoboe_cb *self = pci_get_drvdata(pci_dev);
- unsigned long flags;
-
- if (!self || !self->stopped)
- return 0;
-
- if ((!self->irdad) && (!self->async))
- return 0;
-
- spin_lock_irqsave(&self->spinlock, flags);
-
- toshoboe_startchip (self);
- self->stopped = 0;
-
- netif_wake_queue(self->netdev);
- spin_unlock_irqrestore(&self->spinlock, flags);
- return 0;
-}
-
-static struct pci_driver donauboe_pci_driver = {
- .name = "donauboe",
- .id_table = toshoboe_pci_tbl,
- .probe = toshoboe_open,
- .remove = toshoboe_close,
- .suspend = toshoboe_gotosleep,
- .resume = toshoboe_wakeup
-};
-
-module_pci_driver(donauboe_pci_driver);
diff --git a/drivers/staging/irda/drivers/donauboe.h b/drivers/staging/irda/drivers/donauboe.h
deleted file mode 100644
index d92d54e839b9..000000000000
--- a/drivers/staging/irda/drivers/donauboe.h
+++ /dev/null
@@ -1,362 +0,0 @@
-/*********************************************************************
- *
- * Filename: toshoboe.h
- * Version: 2.16
- * Description: Driver for the Toshiba OBOE (or type-O or 701)
- * FIR Chipset, also supports the DONAUOBOE (type-DO
- * or d01) FIR chipset which as far as I know is
- * register compatible.
- * Status: Experimental.
- * Author: James McKenzie <james@fishsoup.dhs.org>
- * Created at: Sat May 8 12:35:27 1999
- * Modified: 2.16 Martin Lucina <mato@kotelna.sk>
- * Modified: 2.16 Sat Jun 22 18:54:29 2002 (sync headers)
- * Modified: 2.17 Christian Gennerat <christian.gennerat@polytechnique.org>
- * Modified: 2.17 jeu sep 12 08:50:20 2002 (add lock to be used by spinlocks)
- *
- * Copyright (c) 1999 James McKenzie, 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.
- *
- * Neither James McKenzie nor Cambridge University admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- * Applicable Models : Libretto 100/110CT and many more.
- * Toshiba refers to this chip as the type-O IR port,
- * or the type-DO IR port.
- *
- * IrDA chip set list from Toshiba Computer Engineering Corp.
- * model method maker controller Version
- * Portege 320CT FIR,SIR Toshiba Oboe(Triangle)
- * Portege 3010CT FIR,SIR Toshiba Oboe(Sydney)
- * Portege 3015CT FIR,SIR Toshiba Oboe(Sydney)
- * Portege 3020CT FIR,SIR Toshiba Oboe(Sydney)
- * Portege 7020CT FIR,SIR ? ?
- *
- * Satell. 4090XCDT FIR,SIR ? ?
- *
- * Libretto 100CT FIR,SIR Toshiba Oboe
- * Libretto 1000CT FIR,SIR Toshiba Oboe
- *
- * TECRA750DVD FIR,SIR Toshiba Oboe(Triangle) REV ID=14h
- * TECRA780 FIR,SIR Toshiba Oboe(Sandlot) REV ID=32h,33h
- * TECRA750CDT FIR,SIR Toshiba Oboe(Triangle) REV ID=13h,14h
- * TECRA8000 FIR,SIR Toshiba Oboe(ISKUR) REV ID=23h
- *
- ********************************************************************/
-
-/* The documentation for this chip is allegedly released */
-/* However I have not seen it, not have I managed to contact */
-/* anyone who has. HOWEVER the chip bears a striking resemblance */
-/* to the IrDA controller in the Toshiba RISC TMPR3922 chip */
-/* the documentation for this is freely available at */
-/* http://www.madingley.org/james/resources/toshoboe/TMPR3922.pdf */
-/* The mapping between the registers in that document and the */
-/* Registers in the 701 oboe chip are as follows */
-
-
-/* 3922 reg 701 regs, by bit numbers */
-/* 7- 0 15- 8 24-16 31-25 */
-/* $28 0x0 0x1 */
-/* $2c SEE NOTE 1 */
-/* $30 0x6 0x7 */
-/* $34 0x8 0x9 SEE NOTE 2 */
-/* $38 0x10 0x11 */
-/* $3C 0xe SEE NOTE 3 */
-/* $40 0x12 0x13 */
-/* $44 0x14 0x15 */
-/* $48 0x16 0x17 */
-/* $4c 0x18 0x19 */
-/* $50 0x1a 0x1b */
-
-/* FIXME: could be 0x1b 0x1a here */
-
-/* $54 0x1d 0x1c */
-/* $5C 0xf SEE NOTE 4 */
-/* $130 SEE NOTE 5 */
-/* $134 SEE NOTE 6 */
-/* */
-/* NOTES: */
-/* 1. The pointer to ring is packed in most unceremoniusly */
-/* 701 Register Address bits (A9-A0 must be zero) */
-/* 0x4: A17 A16 A15 A14 A13 A12 A11 A10 */
-/* 0x5: A25 A24 A23 A22 A21 A20 A19 A18 */
-/* 0x2: 0 0 A31 A30 A29 A28 A27 A26 */
-/* */
-/* 2. The M$ drivers do a write 0x1 to 0x9, however the 3922 */
-/* documentation would suggest that a write of 0x1 to 0x8 */
-/* would be more appropriate. */
-/* */
-/* 3. This assignment is tenuous at best, register 0xe seems to */
-/* have bits arranged 0 0 0 R/W R/W R/W R/W R/W */
-/* if either of the lower two bits are set the chip seems to */
-/* switch off */
-/* */
-/* 4. Bits 7-4 seem to be different 4 seems just to be generic */
-/* receiver busy flag */
-/* */
-/* 5. and 6. The IER and ISR have a different bit assignment */
-/* The lower three bits of both read back as ones */
-/* ISR is register 0xc, IER is register 0xd */
-/* 7 6 5 4 3 2 1 0 */
-/* 0xc: TxDone RxDone TxUndr RxOver SipRcv 1 1 1 */
-/* 0xd: TxDone RxDone TxUndr RxOver SipRcv 1 1 1 */
-/* TxDone xmitt done (generated only if generate interrupt bit */
-/* is set in the ring) */
-/* RxDone recv completed (or other recv condition if you set it */
-/* up */
-/* TxUnder underflow in Transmit FIFO */
-/* RxOver overflow in Recv FIFO */
-/* SipRcv received serial gap (or other condition you set) */
-/* Interrupts are enabled by writing a one to the IER register */
-/* Interrupts are cleared by writing a one to the ISR register */
-/* */
-/* 6. The remaining registers: 0x6 and 0x3 appear to be */
-/* reserved parts of 16 or 32 bit registersthe remainder */
-/* 0xa 0xb 0x1e 0x1f could possibly be (by their behaviour) */
-/* the Unicast Filter register at $58. */
-/* */
-/* 7. While the core obviously expects 32 bit accesses all the */
-/* M$ drivers do 8 bit accesses, infact the Miniport ones */
-/* write and read back the byte serveral times (why?) */
-
-
-#ifndef TOSHOBOE_H
-#define TOSHOBOE_H
-
-/* Registers */
-
-#define OBOE_IO_EXTENT 0x1f
-
-/*Receive and transmit slot pointers */
-#define OBOE_REG(i) (i+(self->base))
-#define OBOE_RXSLOT OBOE_REG(0x0)
-#define OBOE_TXSLOT OBOE_REG(0x1)
-#define OBOE_SLOT_MASK 0x3f
-
-#define OBOE_TXRING_OFFSET 0x200
-#define OBOE_TXRING_OFFSET_IN_SLOTS 0x40
-
-/*pointer to the ring */
-#define OBOE_RING_BASE0 OBOE_REG(0x4)
-#define OBOE_RING_BASE1 OBOE_REG(0x5)
-#define OBOE_RING_BASE2 OBOE_REG(0x2)
-#define OBOE_RING_BASE3 OBOE_REG(0x3)
-
-/*Number of slots in the ring */
-#define OBOE_RING_SIZE OBOE_REG(0x7)
-#define OBOE_RING_SIZE_RX4 0x00
-#define OBOE_RING_SIZE_RX8 0x01
-#define OBOE_RING_SIZE_RX16 0x03
-#define OBOE_RING_SIZE_RX32 0x07
-#define OBOE_RING_SIZE_RX64 0x0f
-#define OBOE_RING_SIZE_TX4 0x00
-#define OBOE_RING_SIZE_TX8 0x10
-#define OBOE_RING_SIZE_TX16 0x30
-#define OBOE_RING_SIZE_TX32 0x70
-#define OBOE_RING_SIZE_TX64 0xf0
-
-#define OBOE_RING_MAX_SIZE 64
-
-/*Causes the gubbins to re-examine the ring */
-#define OBOE_PROMPT OBOE_REG(0x9)
-#define OBOE_PROMPT_BIT 0x1
-
-/* Interrupt Status Register */
-#define OBOE_ISR OBOE_REG(0xc)
-/* Interrupt Enable Register */
-#define OBOE_IER OBOE_REG(0xd)
-/* Interrupt bits for IER and ISR */
-#define OBOE_INT_TXDONE 0x80
-#define OBOE_INT_RXDONE 0x40
-#define OBOE_INT_TXUNDER 0x20
-#define OBOE_INT_RXOVER 0x10
-#define OBOE_INT_SIP 0x08
-#define OBOE_INT_MASK 0xf8
-
-/*Reset Register */
-#define OBOE_CONFIG1 OBOE_REG(0xe)
-#define OBOE_CONFIG1_RST 0x01
-#define OBOE_CONFIG1_DISABLE 0x02
-#define OBOE_CONFIG1_4 0x08
-#define OBOE_CONFIG1_8 0x08
-
-#define OBOE_CONFIG1_ON 0x8
-#define OBOE_CONFIG1_RESET 0xf
-#define OBOE_CONFIG1_OFF 0xe
-
-#define OBOE_STATUS OBOE_REG(0xf)
-#define OBOE_STATUS_RXBUSY 0x10
-#define OBOE_STATUS_FIRRX 0x04
-#define OBOE_STATUS_MIRRX 0x02
-#define OBOE_STATUS_SIRRX 0x01
-
-
-/*Speed control registers */
-#define OBOE_CONFIG0L OBOE_REG(0x10)
-#define OBOE_CONFIG0H OBOE_REG(0x11)
-
-#define OBOE_CONFIG0H_TXONLOOP 0x80 /*Transmit when looping (dangerous) */
-#define OBOE_CONFIG0H_LOOP 0x40 /*Loopback Tx->Rx */
-#define OBOE_CONFIG0H_ENTX 0x10 /*Enable Tx */
-#define OBOE_CONFIG0H_ENRX 0x08 /*Enable Rx */
-#define OBOE_CONFIG0H_ENDMAC 0x04 /*Enable/reset* the DMA controller */
-#define OBOE_CONFIG0H_RCVANY 0x02 /*DMA mode 1=bytes, 0=dwords */
-
-#define OBOE_CONFIG0L_CRC16 0x80 /*CRC 1=16 bit 0=32 bit */
-#define OBOE_CONFIG0L_ENFIR 0x40 /*Enable FIR */
-#define OBOE_CONFIG0L_ENMIR 0x20 /*Enable MIR */
-#define OBOE_CONFIG0L_ENSIR 0x10 /*Enable SIR */
-#define OBOE_CONFIG0L_ENSIRF 0x08 /*Enable SIR framer */
-#define OBOE_CONFIG0L_SIRTEST 0x04 /*Enable SIR framer in MIR and FIR */
-#define OBOE_CONFIG0L_INVERTTX 0x02 /*Invert Tx Line */
-#define OBOE_CONFIG0L_INVERTRX 0x01 /*Invert Rx Line */
-
-#define OBOE_BOF OBOE_REG(0x12)
-#define OBOE_EOF OBOE_REG(0x13)
-
-#define OBOE_ENABLEL OBOE_REG(0x14)
-#define OBOE_ENABLEH OBOE_REG(0x15)
-
-#define OBOE_ENABLEH_PHYANDCLOCK 0x80 /*Toggle low to copy config in */
-#define OBOE_ENABLEH_CONFIGERR 0x40
-#define OBOE_ENABLEH_FIRON 0x20
-#define OBOE_ENABLEH_MIRON 0x10
-#define OBOE_ENABLEH_SIRON 0x08
-#define OBOE_ENABLEH_ENTX 0x04
-#define OBOE_ENABLEH_ENRX 0x02
-#define OBOE_ENABLEH_CRC16 0x01
-
-#define OBOE_ENABLEL_BROADCAST 0x01
-
-#define OBOE_CURR_PCONFIGL OBOE_REG(0x16) /*Current config */
-#define OBOE_CURR_PCONFIGH OBOE_REG(0x17)
-
-#define OBOE_NEW_PCONFIGL OBOE_REG(0x18)
-#define OBOE_NEW_PCONFIGH OBOE_REG(0x19)
-
-#define OBOE_PCONFIGH_BAUDMASK 0xfc
-#define OBOE_PCONFIGH_WIDTHMASK 0x04
-#define OBOE_PCONFIGL_WIDTHMASK 0xe0
-#define OBOE_PCONFIGL_PREAMBLEMASK 0x1f
-
-#define OBOE_PCONFIG_BAUDMASK 0xfc00
-#define OBOE_PCONFIG_BAUDSHIFT 10
-#define OBOE_PCONFIG_WIDTHMASK 0x04e0
-#define OBOE_PCONFIG_WIDTHSHIFT 5
-#define OBOE_PCONFIG_PREAMBLEMASK 0x001f
-#define OBOE_PCONFIG_PREAMBLESHIFT 0
-
-#define OBOE_MAXLENL OBOE_REG(0x1a)
-#define OBOE_MAXLENH OBOE_REG(0x1b)
-
-#define OBOE_RXCOUNTH OBOE_REG(0x1c) /*Reset on recipt */
-#define OBOE_RXCOUNTL OBOE_REG(0x1d) /*of whole packet */
-
-/* The PCI ID of the OBOE chip */
-#ifndef PCI_DEVICE_ID_FIR701
-#define PCI_DEVICE_ID_FIR701 0x0701
-#endif
-
-#ifndef PCI_DEVICE_ID_FIRD01
-#define PCI_DEVICE_ID_FIRD01 0x0d01
-#endif
-
-struct OboeSlot
-{
- __u16 len; /*Tweleve bits of packet length */
- __u8 unused;
- __u8 control; /*Slot control/status see below */
- __u32 address; /*Slot buffer address */
-}
-__packed;
-
-#define OBOE_NTASKS OBOE_TXRING_OFFSET_IN_SLOTS
-
-struct OboeRing
-{
- struct OboeSlot rx[OBOE_NTASKS];
- struct OboeSlot tx[OBOE_NTASKS];
-};
-
-#define OBOE_RING_LEN (sizeof(struct OboeRing))
-
-
-#define OBOE_CTL_TX_HW_OWNS 0x80 /*W/R This slot owned by the hardware */
-#define OBOE_CTL_TX_DISTX_CRC 0x40 /*W Disable CRC generation for [FM]IR */
-#define OBOE_CTL_TX_BAD_CRC 0x20 /*W Generate bad CRC */
-#define OBOE_CTL_TX_SIP 0x10 /*W Generate an SIP after xmittion */
-#define OBOE_CTL_TX_MKUNDER 0x08 /*W Generate an underrun error */
-#define OBOE_CTL_TX_RTCENTX 0x04 /*W Enable receiver and generate TXdone */
- /* After this slot is processed */
-#define OBOE_CTL_TX_UNDER 0x01 /*R Set by hardware to indicate underrun */
-
-
-#define OBOE_CTL_RX_HW_OWNS 0x80 /*W/R This slot owned by hardware */
-#define OBOE_CTL_RX_PHYERR 0x40 /*R Decoder error on receiption */
-#define OBOE_CTL_RX_CRCERR 0x20 /*R CRC error only set for [FM]IR */
-#define OBOE_CTL_RX_LENGTH 0x10 /*R Packet > max Rx length */
-#define OBOE_CTL_RX_OVER 0x08 /*R set to indicate an overflow */
-#define OBOE_CTL_RX_SIRBAD 0x04 /*R SIR had BOF in packet or ABORT sequence */
-#define OBOE_CTL_RX_RXEOF 0x02 /*R Finished receiving on this slot */
-
-
-struct toshoboe_cb
-{
- struct net_device *netdev; /* Yes! we are some kind of netdevice */
- struct tty_driver ttydev;
-
- struct irlap_cb *irlap; /* The link layer we are binded to */
-
- chipio_t io; /* IrDA controller information */
- struct qos_info qos; /* QoS capabilities for this device */
-
- __u32 flags; /* Interface flags */
-
- struct pci_dev *pdev; /*PCI device */
- int base; /*IO base */
-
-
- int txpending; /*how many tx's are pending */
- int txs, rxs; /*Which slots are we at */
-
- int irdad; /*Driver under control of netdev end */
- int async; /*Driver under control of async end */
-
-
- int stopped; /*Stopped by some or other APM stuff */
-
- int filter; /*In SIR mode do we want to receive
- frames or byte ranges */
-
- void *ringbuf; /*The ring buffer */
- struct OboeRing *ring; /*The ring */
-
- void *tx_bufs[OBOE_RING_MAX_SIZE]; /*The buffers */
- void *rx_bufs[OBOE_RING_MAX_SIZE];
-
-
- int speed; /*Current setting of the speed */
- int new_speed; /*Set to request a speed change */
-
-/* The spinlock protect critical parts of the driver.
- * Locking is done like this :
- * spin_lock_irqsave(&self->spinlock, flags);
- * Releasing the lock :
- * spin_unlock_irqrestore(&self->spinlock, flags);
- */
- spinlock_t spinlock;
- /* Used for the probe and diagnostics code */
- int int_rx;
- int int_tx;
- int int_txunder;
- int int_rxover;
- int int_sip;
-};
-
-
-#endif
diff --git a/drivers/staging/irda/drivers/esi-sir.c b/drivers/staging/irda/drivers/esi-sir.c
deleted file mode 100644
index eb7aa6430bea..000000000000
--- a/drivers/staging/irda/drivers/esi-sir.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*********************************************************************
- *
- * Filename: esi.c
- * Version: 1.6
- * Description: Driver for the Extended Systems JetEye PC dongle
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sat Feb 21 18:54:38 1998
- * Modified at: Sun Oct 27 22:01:04 2002
- * Modified by: Martin Diehl <mad@mdiehl.de>
- *
- * Copyright (c) 1999 Dag Brattli, <dagb@cs.uit.no>,
- * Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>,
- * Copyright (c) 2002 Martin Diehl, <mad@mdiehl.de>,
- * 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.
- *
- * 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/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-
-#include "sir-dev.h"
-
-static int esi_open(struct sir_dev *);
-static int esi_close(struct sir_dev *);
-static int esi_change_speed(struct sir_dev *, unsigned);
-static int esi_reset(struct sir_dev *);
-
-static struct dongle_driver esi = {
- .owner = THIS_MODULE,
- .driver_name = "JetEye PC ESI-9680 PC",
- .type = IRDA_ESI_DONGLE,
- .open = esi_open,
- .close = esi_close,
- .reset = esi_reset,
- .set_speed = esi_change_speed,
-};
-
-static int __init esi_sir_init(void)
-{
- return irda_register_dongle(&esi);
-}
-
-static void __exit esi_sir_cleanup(void)
-{
- irda_unregister_dongle(&esi);
-}
-
-static int esi_open(struct sir_dev *dev)
-{
- struct qos_info *qos = &dev->qos;
-
- /* Power up and set dongle to 9600 baud */
- sirdev_set_dtr_rts(dev, FALSE, TRUE);
-
- qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200;
- qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */
- irda_qos_bits_to_value(qos);
-
- /* irda thread waits 50 msec for power settling */
-
- return 0;
-}
-
-static int esi_close(struct sir_dev *dev)
-{
- /* Power off dongle */
- sirdev_set_dtr_rts(dev, FALSE, FALSE);
-
- return 0;
-}
-
-/*
- * Function esi_change_speed (task)
- *
- * Set the speed for the Extended Systems JetEye PC ESI-9680 type dongle
- * Apparently (see old esi-driver) no delays are needed here...
- *
- */
-static int esi_change_speed(struct sir_dev *dev, unsigned speed)
-{
- int ret = 0;
- int dtr, rts;
-
- switch (speed) {
- case 19200:
- dtr = TRUE;
- rts = FALSE;
- break;
- case 115200:
- dtr = rts = TRUE;
- break;
- default:
- ret = -EINVAL;
- speed = 9600;
- /* fall through */
- case 9600:
- dtr = FALSE;
- rts = TRUE;
- break;
- }
-
- /* Change speed of dongle */
- sirdev_set_dtr_rts(dev, dtr, rts);
- dev->speed = speed;
-
- return ret;
-}
-
-/*
- * Function esi_reset (task)
- *
- * Reset dongle;
- *
- */
-static int esi_reset(struct sir_dev *dev)
-{
- sirdev_set_dtr_rts(dev, FALSE, FALSE);
-
- /* Hm, the old esi-driver left the dongle unpowered relying on
- * the following speed change to repower. This might work for
- * the esi because we only need the modem lines. However, now the
- * general rule is reset must bring the dongle to some working
- * well-known state because speed change might write to registers.
- * The old esi-driver didn't any delay here - let's hope it' fine.
- */
-
- sirdev_set_dtr_rts(dev, FALSE, TRUE);
- dev->speed = 9600;
-
- return 0;
-}
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("Extended Systems JetEye PC dongle driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-1"); /* IRDA_ESI_DONGLE */
-
-module_init(esi_sir_init);
-module_exit(esi_sir_cleanup);
-
diff --git a/drivers/staging/irda/drivers/girbil-sir.c b/drivers/staging/irda/drivers/girbil-sir.c
deleted file mode 100644
index 7e0a5b8c6d53..000000000000
--- a/drivers/staging/irda/drivers/girbil-sir.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/*********************************************************************
- *
- * Filename: girbil.c
- * Version: 1.2
- * Description: Implementation for the Greenwich GIrBIL dongle
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sat Feb 6 21:02:33 1999
- * Modified at: Fri Dec 17 09:13:20 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Dag Brattli, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-
-#include "sir-dev.h"
-
-static int girbil_reset(struct sir_dev *dev);
-static int girbil_open(struct sir_dev *dev);
-static int girbil_close(struct sir_dev *dev);
-static int girbil_change_speed(struct sir_dev *dev, unsigned speed);
-
-/* Control register 1 */
-#define GIRBIL_TXEN 0x01 /* Enable transmitter */
-#define GIRBIL_RXEN 0x02 /* Enable receiver */
-#define GIRBIL_ECAN 0x04 /* Cancel self emitted data */
-#define GIRBIL_ECHO 0x08 /* Echo control characters */
-
-/* LED Current Register (0x2) */
-#define GIRBIL_HIGH 0x20
-#define GIRBIL_MEDIUM 0x21
-#define GIRBIL_LOW 0x22
-
-/* Baud register (0x3) */
-#define GIRBIL_2400 0x30
-#define GIRBIL_4800 0x31
-#define GIRBIL_9600 0x32
-#define GIRBIL_19200 0x33
-#define GIRBIL_38400 0x34
-#define GIRBIL_57600 0x35
-#define GIRBIL_115200 0x36
-
-/* Mode register (0x4) */
-#define GIRBIL_IRDA 0x40
-#define GIRBIL_ASK 0x41
-
-/* Control register 2 (0x5) */
-#define GIRBIL_LOAD 0x51 /* Load the new baud rate value */
-
-static struct dongle_driver girbil = {
- .owner = THIS_MODULE,
- .driver_name = "Greenwich GIrBIL",
- .type = IRDA_GIRBIL_DONGLE,
- .open = girbil_open,
- .close = girbil_close,
- .reset = girbil_reset,
- .set_speed = girbil_change_speed,
-};
-
-static int __init girbil_sir_init(void)
-{
- return irda_register_dongle(&girbil);
-}
-
-static void __exit girbil_sir_cleanup(void)
-{
- irda_unregister_dongle(&girbil);
-}
-
-static int girbil_open(struct sir_dev *dev)
-{
- struct qos_info *qos = &dev->qos;
-
- /* Power on dongle */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
- qos->min_turn_time.bits = 0x03;
- irda_qos_bits_to_value(qos);
-
- /* irda thread waits 50 msec for power settling */
-
- return 0;
-}
-
-static int girbil_close(struct sir_dev *dev)
-{
- /* Power off dongle */
- sirdev_set_dtr_rts(dev, FALSE, FALSE);
-
- return 0;
-}
-
-/*
- * Function girbil_change_speed (dev, speed)
- *
- * Set the speed for the Girbil type dongle.
- *
- */
-
-#define GIRBIL_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1)
-
-static int girbil_change_speed(struct sir_dev *dev, unsigned speed)
-{
- unsigned state = dev->fsm.substate;
- unsigned delay = 0;
- u8 control[2];
- static int ret = 0;
-
- /* dongle alread reset - port and dongle at default speed */
-
- switch(state) {
-
- case SIRDEV_STATE_DONGLE_SPEED:
-
- /* Set DTR and Clear RTS to enter command mode */
- sirdev_set_dtr_rts(dev, FALSE, TRUE);
-
- udelay(25); /* better wait a little while */
-
- ret = 0;
- switch (speed) {
- default:
- ret = -EINVAL;
- /* fall through */
- case 9600:
- control[0] = GIRBIL_9600;
- break;
- case 19200:
- control[0] = GIRBIL_19200;
- break;
- case 34800:
- control[0] = GIRBIL_38400;
- break;
- case 57600:
- control[0] = GIRBIL_57600;
- break;
- case 115200:
- control[0] = GIRBIL_115200;
- break;
- }
- control[1] = GIRBIL_LOAD;
-
- /* Write control bytes */
- sirdev_raw_write(dev, control, 2);
-
- dev->speed = speed;
-
- state = GIRBIL_STATE_WAIT_SPEED;
- delay = 100;
- break;
-
- case GIRBIL_STATE_WAIT_SPEED:
- /* Go back to normal mode */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- udelay(25); /* better wait a little while */
- break;
-
- default:
- net_err_ratelimited("%s - undefined state %d\n",
- __func__, state);
- ret = -EINVAL;
- break;
- }
- dev->fsm.substate = state;
- return (delay > 0) ? delay : ret;
-}
-
-/*
- * Function girbil_reset (driver)
- *
- * This function resets the girbil dongle.
- *
- * Algorithm:
- * 0. set RTS, and wait at least 5 ms
- * 1. clear RTS
- */
-
-
-#define GIRBIL_STATE_WAIT1_RESET (SIRDEV_STATE_DONGLE_RESET + 1)
-#define GIRBIL_STATE_WAIT2_RESET (SIRDEV_STATE_DONGLE_RESET + 2)
-#define GIRBIL_STATE_WAIT3_RESET (SIRDEV_STATE_DONGLE_RESET + 3)
-
-static int girbil_reset(struct sir_dev *dev)
-{
- unsigned state = dev->fsm.substate;
- unsigned delay = 0;
- u8 control = GIRBIL_TXEN | GIRBIL_RXEN;
- int ret = 0;
-
- switch (state) {
- case SIRDEV_STATE_DONGLE_RESET:
- /* Reset dongle */
- sirdev_set_dtr_rts(dev, TRUE, FALSE);
- /* Sleep at least 5 ms */
- delay = 20;
- state = GIRBIL_STATE_WAIT1_RESET;
- break;
-
- case GIRBIL_STATE_WAIT1_RESET:
- /* Set DTR and clear RTS to enter command mode */
- sirdev_set_dtr_rts(dev, FALSE, TRUE);
- delay = 20;
- state = GIRBIL_STATE_WAIT2_RESET;
- break;
-
- case GIRBIL_STATE_WAIT2_RESET:
- /* Write control byte */
- sirdev_raw_write(dev, &control, 1);
- delay = 20;
- state = GIRBIL_STATE_WAIT3_RESET;
- break;
-
- case GIRBIL_STATE_WAIT3_RESET:
- /* Go back to normal mode */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
- dev->speed = 9600;
- break;
-
- default:
- net_err_ratelimited("%s(), undefined state %d\n",
- __func__, state);
- ret = -1;
- break;
- }
- dev->fsm.substate = state;
- return (delay > 0) ? delay : ret;
-}
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("Greenwich GIrBIL dongle driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-4"); /* IRDA_GIRBIL_DONGLE */
-
-module_init(girbil_sir_init);
-module_exit(girbil_sir_cleanup);
diff --git a/drivers/staging/irda/drivers/irda-usb.c b/drivers/staging/irda/drivers/irda-usb.c
deleted file mode 100644
index bda6bdc6c70b..000000000000
--- a/drivers/staging/irda/drivers/irda-usb.c
+++ /dev/null
@@ -1,1906 +0,0 @@
-/*****************************************************************************
- *
- * Filename: irda-usb.c
- * Version: 0.10
- * Description: IrDA-USB Driver
- * Status: Experimental
- * Author: Dag Brattli <dag@brattli.net>
- *
- * Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at>
- * Copyright (C) 2001, Dag Brattli <dag@brattli.net>
- * Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com>
- * Copyright (C) 2004, SigmaTel, Inc. <irquality@sigmatel.com>
- * Copyright (C) 2005, Milan Beno <beno@pobox.sk>
- * Copyright (C) 2006, Nick Fedchik <nick@fedchik.org.ua>
- *
- * 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.
- *
- * 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.
- *
- *****************************************************************************/
-
-/*
- * IMPORTANT NOTE
- * --------------
- *
- * As of kernel 2.5.20, this is the state of compliance and testing of
- * this driver (irda-usb) with regards to the USB low level drivers...
- *
- * This driver has been tested SUCCESSFULLY with the following drivers :
- * o usb-uhci-hcd (For Intel/Via USB controllers)
- * o uhci-hcd (Alternate/JE driver for Intel/Via USB controllers)
- * o ohci-hcd (For other USB controllers)
- *
- * This driver has NOT been tested with the following drivers :
- * o ehci-hcd (USB 2.0 controllers)
- *
- * Note that all HCD drivers do URB_ZERO_PACKET and timeout properly,
- * so we don't have to worry about that anymore.
- * One common problem is the failure to set the address on the dongle,
- * but this happens before the driver gets loaded...
- *
- * Jean II
- */
-
-/*------------------------------------------------------------------*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/slab.h>
-#include <linux/rtnetlink.h>
-#include <linux/usb.h>
-#include <linux/firmware.h>
-
-#include "irda-usb.h"
-
-/*------------------------------------------------------------------*/
-
-static int qos_mtt_bits = 0;
-
-/* These are the currently known IrDA USB dongles. Add new dongles here */
-static const struct usb_device_id dongles[] = {
- /* ACTiSYS Corp., ACT-IR2000U FIR-USB Adapter */
- { USB_DEVICE(0x9c4, 0x011), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW },
- /* Look like ACTiSYS, Report : IBM Corp., IBM UltraPort IrDA */
- { USB_DEVICE(0x4428, 0x012), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW },
- /* KC Technology Inc., KC-180 USB IrDA Device */
- { USB_DEVICE(0x50f, 0x180), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW },
- /* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */
- { USB_DEVICE(0x8e9, 0x100), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW },
- /* SigmaTel STIR4210/4220/4116 USB IrDA (VFIR) Bridge */
- { USB_DEVICE(0x66f, 0x4210), .driver_info = IUC_STIR421X | IUC_SPEED_BUG },
- { USB_DEVICE(0x66f, 0x4220), .driver_info = IUC_STIR421X | IUC_SPEED_BUG },
- { USB_DEVICE(0x66f, 0x4116), .driver_info = IUC_STIR421X | IUC_SPEED_BUG },
- { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
- USB_DEVICE_ID_MATCH_INT_SUBCLASS,
- .bInterfaceClass = USB_CLASS_APP_SPEC,
- .bInterfaceSubClass = USB_CLASS_IRDA,
- .driver_info = IUC_DEFAULT, },
- { }, /* The end */
-};
-
-/*
- * Important note :
- * Devices based on the SigmaTel chipset (0x66f, 0x4200) are not designed
- * using the "USB-IrDA specification" (yes, there exist such a thing), and
- * therefore not supported by this driver (don't add them above).
- * There is a Linux driver, stir4200, that support those USB devices.
- * Jean II
- */
-
-MODULE_DEVICE_TABLE(usb, dongles);
-
-/*------------------------------------------------------------------*/
-
-static void irda_usb_init_qos(struct irda_usb_cb *self) ;
-static struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf);
-static void irda_usb_disconnect(struct usb_interface *intf);
-static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self);
-static netdev_tx_t irda_usb_hard_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static int irda_usb_open(struct irda_usb_cb *self);
-static void irda_usb_close(struct irda_usb_cb *self);
-static void speed_bulk_callback(struct urb *urb);
-static void write_bulk_callback(struct urb *urb);
-static void irda_usb_receive(struct urb *urb);
-static void irda_usb_rx_defer_expired(struct timer_list *t);
-static int irda_usb_net_open(struct net_device *dev);
-static int irda_usb_net_close(struct net_device *dev);
-static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void irda_usb_net_timeout(struct net_device *dev);
-
-/************************ TRANSMIT ROUTINES ************************/
-/*
- * Receive packets from the IrDA stack and send them on the USB pipe.
- * Handle speed change, timeout and lot's of ugliness...
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Function irda_usb_build_header(self, skb, header)
- *
- * Builds USB-IrDA outbound header
- *
- * When we send an IrDA frame over an USB pipe, we add to it a 1 byte
- * header. This function create this header with the proper values.
- *
- * Important note : the USB-IrDA spec 1.0 say very clearly in chapter 5.4.2.2
- * that the setting of the link speed and xbof number in this outbound header
- * should be applied *AFTER* the frame has been sent.
- * Unfortunately, some devices are not compliant with that... It seems that
- * reading the spec is far too difficult...
- * Jean II
- */
-static void irda_usb_build_header(struct irda_usb_cb *self,
- __u8 *header,
- int force)
-{
- /* Here we check if we have an STIR421x chip,
- * and if either speed or xbofs (or both) needs
- * to be changed.
- */
- if (self->capability & IUC_STIR421X &&
- ((self->new_speed != -1) || (self->new_xbofs != -1))) {
-
- /* With STIR421x, speed and xBOFs must be set at the same
- * time, even if only one of them changes.
- */
- if (self->new_speed == -1)
- self->new_speed = self->speed ;
-
- if (self->new_xbofs == -1)
- self->new_xbofs = self->xbofs ;
- }
-
- /* Set the link speed */
- if (self->new_speed != -1) {
- /* Hum... Ugly hack :-(
- * Some device are not compliant with the spec and change
- * parameters *before* sending the frame. - Jean II
- */
- if ((self->capability & IUC_SPEED_BUG) &&
- (!force) && (self->speed != -1)) {
- /* No speed and xbofs change here
- * (we'll do it later in the write callback) */
- pr_debug("%s(), not changing speed yet\n", __func__);
- *header = 0;
- return;
- }
-
- pr_debug("%s(), changing speed to %d\n",
- __func__, self->new_speed);
- self->speed = self->new_speed;
- /* We will do ` self->new_speed = -1; ' in the completion
- * handler just in case the current URB fail - Jean II */
-
- switch (self->speed) {
- case 2400:
- *header = SPEED_2400;
- break;
- default:
- case 9600:
- *header = SPEED_9600;
- break;
- case 19200:
- *header = SPEED_19200;
- break;
- case 38400:
- *header = SPEED_38400;
- break;
- case 57600:
- *header = SPEED_57600;
- break;
- case 115200:
- *header = SPEED_115200;
- break;
- case 576000:
- *header = SPEED_576000;
- break;
- case 1152000:
- *header = SPEED_1152000;
- break;
- case 4000000:
- *header = SPEED_4000000;
- self->new_xbofs = 0;
- break;
- case 16000000:
- *header = SPEED_16000000;
- self->new_xbofs = 0;
- break;
- }
- } else
- /* No change */
- *header = 0;
-
- /* Set the negotiated additional XBOFS */
- if (self->new_xbofs != -1) {
- pr_debug("%s(), changing xbofs to %d\n",
- __func__, self->new_xbofs);
- self->xbofs = self->new_xbofs;
- /* We will do ` self->new_xbofs = -1; ' in the completion
- * handler just in case the current URB fail - Jean II */
-
- switch (self->xbofs) {
- case 48:
- *header |= 0x10;
- break;
- case 28:
- case 24: /* USB spec 1.0 says 24 */
- *header |= 0x20;
- break;
- default:
- case 12:
- *header |= 0x30;
- break;
- case 5: /* Bug in IrLAP spec? (should be 6) */
- case 6:
- *header |= 0x40;
- break;
- case 3:
- *header |= 0x50;
- break;
- case 2:
- *header |= 0x60;
- break;
- case 1:
- *header |= 0x70;
- break;
- case 0:
- *header |= 0x80;
- break;
- }
- }
-}
-
-/*
-* calculate turnaround time for SigmaTel header
-*/
-static __u8 get_turnaround_time(struct sk_buff *skb)
-{
- int turnaround_time = irda_get_mtt(skb);
-
- if ( turnaround_time == 0 )
- return 0;
- else if ( turnaround_time <= 10 )
- return 1;
- else if ( turnaround_time <= 50 )
- return 2;
- else if ( turnaround_time <= 100 )
- return 3;
- else if ( turnaround_time <= 500 )
- return 4;
- else if ( turnaround_time <= 1000 )
- return 5;
- else if ( turnaround_time <= 5000 )
- return 6;
- else
- return 7;
-}
-
-
-/*------------------------------------------------------------------*/
-/*
- * Send a command to change the speed of the dongle
- * Need to be called with spinlock on.
- */
-static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
-{
- __u8 *frame;
- struct urb *urb;
- int ret;
-
- pr_debug("%s(), speed=%d, xbofs=%d\n", __func__,
- self->new_speed, self->new_xbofs);
-
- /* Grab the speed URB */
- urb = self->speed_urb;
- if (urb->status != 0) {
- net_warn_ratelimited("%s(), URB still in use!\n", __func__);
- return;
- }
-
- /* Allocate the fake frame */
- frame = self->speed_buff;
-
- /* Set the new speed and xbofs in this fake frame */
- irda_usb_build_header(self, frame, 1);
-
- if (self->capability & IUC_STIR421X) {
- if (frame[0] == 0) return ; // do nothing if no change
- frame[1] = 0; // other parameters don't change here
- frame[2] = 0;
- }
-
- /* Submit the 0 length IrDA frame to trigger new speed settings */
- usb_fill_bulk_urb(urb, self->usbdev,
- usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
- frame, IRDA_USB_SPEED_MTU,
- speed_bulk_callback, self);
- urb->transfer_buffer_length = self->header_length;
- urb->transfer_flags = 0;
-
- /* Irq disabled -> GFP_ATOMIC */
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret)
- net_warn_ratelimited("%s(), failed Speed URB\n", __func__);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Speed URB callback
- * Now, we can only get called for the speed URB.
- */
-static void speed_bulk_callback(struct urb *urb)
-{
- struct irda_usb_cb *self = urb->context;
-
- /* We should always have a context */
- IRDA_ASSERT(self != NULL, return;);
- /* We should always be called for the speed URB */
- IRDA_ASSERT(urb == self->speed_urb, return;);
-
- /* Check for timeout and other USB nasties */
- if (urb->status != 0) {
- /* I get a lot of -ECONNABORTED = -103 here - Jean II */
- pr_debug("%s(), URB complete status %d, transfer_flags 0x%04X\n",
- __func__, urb->status, urb->transfer_flags);
-
- /* Don't do anything here, that might confuse the USB layer.
- * Instead, we will wait for irda_usb_net_timeout(), the
- * network layer watchdog, to fix the situation.
- * Jean II */
- /* A reset of the dongle might be welcomed here - Jean II */
- return;
- }
-
- /* urb is now available */
- //urb->status = 0; -> tested above
-
- /* New speed and xbof is now committed in hardware */
- self->new_speed = -1;
- self->new_xbofs = -1;
-
- /* Allow the stack to send more packets */
- netif_wake_queue(self->netdev);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Send an IrDA frame to the USB dongle (for transmission)
- */
-static netdev_tx_t irda_usb_hard_xmit(struct sk_buff *skb,
- struct net_device *netdev)
-{
- struct irda_usb_cb *self = netdev_priv(netdev);
- struct urb *urb = self->tx_urb;
- unsigned long flags;
- s32 speed;
- s16 xbofs;
- int res, mtt;
-
- pr_debug("%s() on %s\n", __func__, netdev->name);
-
- netif_stop_queue(netdev);
-
- /* Protect us from USB callbacks, net watchdog and else. */
- spin_lock_irqsave(&self->lock, flags);
-
- /* Check if the device is still there.
- * We need to check self->present under the spinlock because
- * of irda_usb_disconnect() is synchronous - Jean II */
- if (!self->present) {
- pr_debug("%s(), Device is gone...\n", __func__);
- goto drop;
- }
-
- /* Check if we need to change the number of xbofs */
- xbofs = irda_get_next_xbofs(skb);
- if ((xbofs != self->xbofs) && (xbofs != -1)) {
- self->new_xbofs = xbofs;
- }
-
- /* Check if we need to change the speed */
- speed = irda_get_next_speed(skb);
- if ((speed != self->speed) && (speed != -1)) {
- /* Set the desired speed */
- self->new_speed = speed;
-
- /* Check for empty frame */
- if (!skb->len) {
- /* IrLAP send us an empty frame to make us change the
- * speed. Changing speed with the USB adapter is in
- * fact sending an empty frame to the adapter, so we
- * could just let the present function do its job.
- * However, we would wait for min turn time,
- * do an extra memcpy and increment packet counters...
- * Jean II */
- irda_usb_change_speed_xbofs(self);
- netif_trans_update(netdev);
- /* Will netif_wake_queue() in callback */
- goto drop;
- }
- }
-
- if (urb->status != 0) {
- net_warn_ratelimited("%s(), URB still in use!\n", __func__);
- goto drop;
- }
-
- skb_copy_from_linear_data(skb, self->tx_buff + self->header_length, skb->len);
-
- /* Change setting for next frame */
- if (self->capability & IUC_STIR421X) {
- __u8 turnaround_time;
- __u8* frame = self->tx_buff;
- turnaround_time = get_turnaround_time( skb );
- irda_usb_build_header(self, frame, 0);
- frame[2] = turnaround_time;
- if ((skb->len != 0) &&
- ((skb->len % 128) == 0) &&
- ((skb->len % 512) != 0)) {
- /* add extra byte for special SigmaTel feature */
- frame[1] = 1;
- skb_put(skb, 1);
- } else {
- frame[1] = 0;
- }
- } else {
- irda_usb_build_header(self, self->tx_buff, 0);
- }
-
- /* FIXME: Make macro out of this one */
- ((struct irda_skb_cb *)skb->cb)->context = self;
-
- usb_fill_bulk_urb(urb, self->usbdev,
- usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
- self->tx_buff, skb->len + self->header_length,
- write_bulk_callback, skb);
-
- /* This flag (URB_ZERO_PACKET) indicates that what we send is not
- * a continuous stream of data but separate packets.
- * In this case, the USB layer will insert an empty USB frame (TD)
- * after each of our packets that is exact multiple of the frame size.
- * This is how the dongle will detect the end of packet - Jean II */
- urb->transfer_flags = URB_ZERO_PACKET;
-
- /* Generate min turn time. FIXME: can we do better than this? */
- /* Trying to a turnaround time at this level is trying to measure
- * processor clock cycle with a wrist-watch, approximate at best...
- *
- * What we know is the last time we received a frame over USB.
- * Due to latency over USB that depend on the USB load, we don't
- * know when this frame was received over IrDA (a few ms before ?)
- * Then, same story for our outgoing frame...
- *
- * In theory, the USB dongle is supposed to handle the turnaround
- * by itself (spec 1.0, chater 4, page 6). Who knows ??? That's
- * why this code is enabled only for dongles that doesn't meet
- * the spec.
- * Jean II */
- if (self->capability & IUC_NO_TURN) {
- mtt = irda_get_mtt(skb);
- if (mtt) {
- int diff;
- diff = ktime_us_delta(ktime_get(), self->stamp);
-#ifdef IU_USB_MIN_RTT
- /* Factor in USB delays -> Get rid of udelay() that
- * would be lost in the noise - Jean II */
- diff += IU_USB_MIN_RTT;
-#endif /* IU_USB_MIN_RTT */
-
- /* Check if the mtt is larger than the time we have
- * already used by all the protocol processing
- */
- if (mtt > diff) {
- mtt -= diff;
- if (mtt > 1000)
- mdelay(mtt/1000);
- else
- udelay(mtt);
- }
- }
- }
-
- /* Ask USB to send the packet - Irq disabled -> GFP_ATOMIC */
- if ((res = usb_submit_urb(urb, GFP_ATOMIC))) {
- net_warn_ratelimited("%s(), failed Tx URB\n", __func__);
- netdev->stats.tx_errors++;
- /* Let USB recover : We will catch that in the watchdog */
- /*netif_start_queue(netdev);*/
- } else {
- /* Increment packet stats */
- netdev->stats.tx_packets++;
- netdev->stats.tx_bytes += skb->len;
-
- netif_trans_update(netdev);
- }
- spin_unlock_irqrestore(&self->lock, flags);
-
- return NETDEV_TX_OK;
-
-drop:
- /* Drop silently the skb and exit */
- dev_kfree_skb(skb);
- spin_unlock_irqrestore(&self->lock, flags);
- return NETDEV_TX_OK;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Note : this function will be called only for tx_urb...
- */
-static void write_bulk_callback(struct urb *urb)
-{
- unsigned long flags;
- struct sk_buff *skb = urb->context;
- struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;
-
- /* We should always have a context */
- IRDA_ASSERT(self != NULL, return;);
- /* We should always be called for the speed URB */
- IRDA_ASSERT(urb == self->tx_urb, return;);
-
- /* Free up the skb */
- dev_kfree_skb_any(skb);
- urb->context = NULL;
-
- /* Check for timeout and other USB nasties */
- if (urb->status != 0) {
- /* I get a lot of -ECONNABORTED = -103 here - Jean II */
- pr_debug("%s(), URB complete status %d, transfer_flags 0x%04X\n",
- __func__, urb->status, urb->transfer_flags);
-
- /* Don't do anything here, that might confuse the USB layer,
- * and we could go in recursion and blow the kernel stack...
- * Instead, we will wait for irda_usb_net_timeout(), the
- * network layer watchdog, to fix the situation.
- * Jean II */
- /* A reset of the dongle might be welcomed here - Jean II */
- return;
- }
-
- /* urb is now available */
- //urb->status = 0; -> tested above
-
- /* Make sure we read self->present properly */
- spin_lock_irqsave(&self->lock, flags);
-
- /* If the network is closed, stop everything */
- if ((!self->netopen) || (!self->present)) {
- pr_debug("%s(), Network is gone...\n", __func__);
- spin_unlock_irqrestore(&self->lock, flags);
- return;
- }
-
- /* If changes to speed or xbofs is pending... */
- if ((self->new_speed != -1) || (self->new_xbofs != -1)) {
- if ((self->new_speed != self->speed) ||
- (self->new_xbofs != self->xbofs)) {
- /* We haven't changed speed yet (because of
- * IUC_SPEED_BUG), so do it now - Jean II */
- pr_debug("%s(), Changing speed now...\n", __func__);
- irda_usb_change_speed_xbofs(self);
- } else {
- /* New speed and xbof is now committed in hardware */
- self->new_speed = -1;
- self->new_xbofs = -1;
- /* Done, waiting for next packet */
- netif_wake_queue(self->netdev);
- }
- } else {
- /* Otherwise, allow the stack to send more packets */
- netif_wake_queue(self->netdev);
- }
- spin_unlock_irqrestore(&self->lock, flags);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Watchdog timer from the network layer.
- * After a predetermined timeout, if we don't give confirmation that
- * the packet has been sent (i.e. no call to netif_wake_queue()),
- * the network layer will call this function.
- * Note that URB that we submit have also a timeout. When the URB timeout
- * expire, the normal URB callback is called (write_bulk_callback()).
- */
-static void irda_usb_net_timeout(struct net_device *netdev)
-{
- unsigned long flags;
- struct irda_usb_cb *self = netdev_priv(netdev);
- struct urb *urb;
- int done = 0; /* If we have made any progress */
-
- pr_debug("%s(), Network layer thinks we timed out!\n", __func__);
- IRDA_ASSERT(self != NULL, return;);
-
- /* Protect us from USB callbacks, net Tx and else. */
- spin_lock_irqsave(&self->lock, flags);
-
- /* self->present *MUST* be read under spinlock */
- if (!self->present) {
- net_warn_ratelimited("%s(), device not present!\n", __func__);
- netif_stop_queue(netdev);
- spin_unlock_irqrestore(&self->lock, flags);
- return;
- }
-
- /* Check speed URB */
- urb = self->speed_urb;
- if (urb->status != 0) {
- pr_debug("%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n",
- netdev->name, urb->status, urb->transfer_flags);
-
- switch (urb->status) {
- case -EINPROGRESS:
- usb_unlink_urb(urb);
- /* Note : above will *NOT* call netif_wake_queue()
- * in completion handler, we will come back here.
- * Jean II */
- done = 1;
- break;
- case -ECONNRESET:
- case -ENOENT: /* urb unlinked by us */
- default: /* ??? - Play safe */
- urb->status = 0;
- netif_wake_queue(self->netdev);
- done = 1;
- break;
- }
- }
-
- /* Check Tx URB */
- urb = self->tx_urb;
- if (urb->status != 0) {
- struct sk_buff *skb = urb->context;
-
- pr_debug("%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n",
- netdev->name, urb->status, urb->transfer_flags);
-
- /* Increase error count */
- netdev->stats.tx_errors++;
-
-#ifdef IU_BUG_KICK_TIMEOUT
- /* Can't be a bad idea to reset the speed ;-) - Jean II */
- if(self->new_speed == -1)
- self->new_speed = self->speed;
- if(self->new_xbofs == -1)
- self->new_xbofs = self->xbofs;
- irda_usb_change_speed_xbofs(self);
-#endif /* IU_BUG_KICK_TIMEOUT */
-
- switch (urb->status) {
- case -EINPROGRESS:
- usb_unlink_urb(urb);
- /* Note : above will *NOT* call netif_wake_queue()
- * in completion handler, because urb->status will
- * be -ENOENT. We will fix that at the next watchdog,
- * leaving more time to USB to recover...
- * Jean II */
- done = 1;
- break;
- case -ECONNRESET:
- case -ENOENT: /* urb unlinked by us */
- default: /* ??? - Play safe */
- if(skb != NULL) {
- dev_kfree_skb_any(skb);
- urb->context = NULL;
- }
- urb->status = 0;
- netif_wake_queue(self->netdev);
- done = 1;
- break;
- }
- }
- spin_unlock_irqrestore(&self->lock, flags);
-
- /* Maybe we need a reset */
- /* Note : Some drivers seem to use a usb_set_interface() when they
- * need to reset the hardware. Hum...
- */
-
- /* if(done == 0) */
-}
-
-/************************* RECEIVE ROUTINES *************************/
-/*
- * Receive packets from the USB layer stack and pass them to the IrDA stack.
- * Try to work around USB failures...
- */
-
-/*
- * Note :
- * Some of you may have noticed that most dongle have an interrupt in pipe
- * that we don't use. Here is the little secret...
- * When we hang a Rx URB on the bulk in pipe, it generates some USB traffic
- * in every USB frame. This is unnecessary overhead.
- * The interrupt in pipe will generate an event every time a packet is
- * received. Reading an interrupt pipe adds minimal overhead, but has some
- * latency (~1ms).
- * If we are connected (speed != 9600), we want to minimise latency, so
- * we just always hang the Rx URB and ignore the interrupt.
- * If we are not connected (speed == 9600), there is usually no Rx traffic,
- * and we want to minimise the USB overhead. In this case we should wait
- * on the interrupt pipe and hang the Rx URB only when an interrupt is
- * received.
- * Jean II
- *
- * Note : don't read the above as what we are currently doing, but as
- * something we could do with KC dongle. Also don't forget that the
- * interrupt pipe is not part of the original standard, so this would
- * need to be optional...
- * Jean II
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Submit a Rx URB to the USB layer to handle reception of a frame
- * Mostly called by the completion callback of the previous URB.
- *
- * Jean II
- */
-static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struct urb *urb)
-{
- struct irda_skb_cb *cb;
- int ret;
-
- /* This should never happen */
- IRDA_ASSERT(skb != NULL, return;);
- IRDA_ASSERT(urb != NULL, return;);
-
- /* Save ourselves in the skb */
- cb = (struct irda_skb_cb *) skb->cb;
- cb->context = self;
-
- /* Reinitialize URB */
- usb_fill_bulk_urb(urb, self->usbdev,
- usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep),
- skb->data, IRDA_SKB_MAX_MTU,
- irda_usb_receive, skb);
- urb->status = 0;
-
- /* Can be called from irda_usb_receive (irq handler) -> GFP_ATOMIC */
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret) {
- /* If this ever happen, we are in deep s***.
- * Basically, the Rx path will stop... */
- net_warn_ratelimited("%s(), Failed to submit Rx URB %d\n",
- __func__, ret);
- }
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irda_usb_receive(urb)
- *
- * Called by the USB subsystem when a frame has been received
- *
- */
-static void irda_usb_receive(struct urb *urb)
-{
- struct sk_buff *skb = (struct sk_buff *) urb->context;
- struct irda_usb_cb *self;
- struct irda_skb_cb *cb;
- struct sk_buff *newskb;
- struct sk_buff *dataskb;
- struct urb *next_urb;
- unsigned int len, docopy;
-
- pr_debug("%s(), len=%d\n", __func__, urb->actual_length);
-
- /* Find ourselves */
- cb = (struct irda_skb_cb *) skb->cb;
- IRDA_ASSERT(cb != NULL, return;);
- self = (struct irda_usb_cb *) cb->context;
- IRDA_ASSERT(self != NULL, return;);
-
- /* If the network is closed or the device gone, stop everything */
- if ((!self->netopen) || (!self->present)) {
- pr_debug("%s(), Network is gone!\n", __func__);
- /* Don't re-submit the URB : will stall the Rx path */
- return;
- }
-
- /* Check the status */
- if (urb->status != 0) {
- switch (urb->status) {
- case -EILSEQ:
- self->netdev->stats.rx_crc_errors++;
- /* Also precursor to a hot-unplug on UHCI. */
- /* Fallthrough... */
- case -ECONNRESET:
- /* Random error, if I remember correctly */
- /* uhci_cleanup_unlink() is going to kill the Rx
- * URB just after we return. No problem, at this
- * point the URB will be idle ;-) - Jean II */
- case -ESHUTDOWN:
- /* That's usually a hot-unplug. Submit will fail... */
- case -ETIME:
- /* Usually precursor to a hot-unplug on OHCI. */
- default:
- self->netdev->stats.rx_errors++;
- pr_debug("%s(), RX status %d, transfer_flags 0x%04X\n",
- __func__, urb->status, urb->transfer_flags);
- break;
- }
- /* If we received an error, we don't want to resubmit the
- * Rx URB straight away but to give the USB layer a little
- * bit of breathing room.
- * We are in the USB thread context, therefore there is a
- * danger of recursion (new URB we submit fails, we come
- * back here).
- * With recent USB stack (2.6.15+), I'm seeing that on
- * hot unplug of the dongle...
- * Lowest effective timer is 10ms...
- * Jean II */
- self->rx_defer_timer_urb = urb;
- mod_timer(&self->rx_defer_timer,
- jiffies + msecs_to_jiffies(10));
-
- return;
- }
-
- /* Check for empty frames */
- if (urb->actual_length <= self->header_length) {
- net_warn_ratelimited("%s(), empty frame!\n", __func__);
- goto done;
- }
-
- /*
- * Remember the time we received this frame, so we can
- * reduce the min turn time a bit since we will know
- * how much time we have used for protocol processing
- */
- self->stamp = ktime_get();
-
- /* Check if we need to copy the data to a new skb or not.
- * For most frames, we use ZeroCopy and pass the already
- * allocated skb up the stack.
- * If the frame is small, it is more efficient to copy it
- * to save memory (copy will be fast anyway - that's
- * called Rx-copy-break). Jean II */
- docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD);
-
- /* Allocate a new skb */
- if (self->capability & IUC_STIR421X)
- newskb = dev_alloc_skb(docopy ? urb->actual_length :
- IRDA_SKB_MAX_MTU +
- USB_IRDA_STIR421X_HEADER);
- else
- newskb = dev_alloc_skb(docopy ? urb->actual_length :
- IRDA_SKB_MAX_MTU);
-
- if (!newskb) {
- self->netdev->stats.rx_dropped++;
- /* We could deliver the current skb, but this would stall
- * the Rx path. Better drop the packet... Jean II */
- goto done;
- }
-
- /* Make sure IP header get aligned (IrDA header is 5 bytes) */
- /* But IrDA-USB header is 1 byte. Jean II */
- //skb_reserve(newskb, USB_IRDA_HEADER - 1);
-
- if(docopy) {
- /* Copy packet, so we can recycle the original */
- skb_copy_from_linear_data(skb, newskb->data, urb->actual_length);
- /* Deliver this new skb */
- dataskb = newskb;
- /* And hook the old skb to the URB
- * Note : we don't need to "clean up" the old skb,
- * as we never touched it. Jean II */
- } else {
- /* We are using ZeroCopy. Deliver old skb */
- dataskb = skb;
- /* And hook the new skb to the URB */
- skb = newskb;
- }
-
- /* Set proper length on skb & remove USB-IrDA header */
- skb_put(dataskb, urb->actual_length);
- skb_pull(dataskb, self->header_length);
-
- /* Ask the networking layer to queue the packet for the IrDA stack */
- dataskb->dev = self->netdev;
- skb_reset_mac_header(dataskb);
- dataskb->protocol = htons(ETH_P_IRDA);
- len = dataskb->len;
- netif_rx(dataskb);
-
- /* Keep stats up to date */
- self->netdev->stats.rx_bytes += len;
- self->netdev->stats.rx_packets++;
-
-done:
- /* Note : at this point, the URB we've just received (urb)
- * is still referenced by the USB layer. For example, if we
- * have received a -ECONNRESET, uhci_cleanup_unlink() will
- * continue to process it (in fact, cleaning it up).
- * If we were to submit this URB, disaster would ensue.
- * Therefore, we submit our idle URB, and put this URB in our
- * idle slot....
- * Jean II */
- /* Note : with this scheme, we could submit the idle URB before
- * processing the Rx URB. I don't think it would buy us anything as
- * we are running in the USB thread context. Jean II */
- next_urb = self->idle_rx_urb;
-
- /* Recycle Rx URB : Now, the idle URB is the present one */
- urb->context = NULL;
- self->idle_rx_urb = urb;
-
- /* Submit the idle URB to replace the URB we've just received.
- * Do it last to avoid race conditions... Jean II */
- irda_usb_submit(self, skb, next_urb);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * In case of errors, we want the USB layer to have time to recover.
- * Now, it is time to resubmit ouur Rx URB...
- */
-static void irda_usb_rx_defer_expired(struct timer_list *t)
-{
- struct irda_usb_cb *self = from_timer(self, t, rx_defer_timer);
- struct urb *urb = self->rx_defer_timer_urb;
- struct sk_buff *skb = (struct sk_buff *) urb->context;
- struct urb *next_urb;
-
- /* Same stuff as when Rx is done, see above... */
- next_urb = self->idle_rx_urb;
- urb->context = NULL;
- self->idle_rx_urb = urb;
- irda_usb_submit(self, skb, next_urb);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Callbak from IrDA layer. IrDA wants to know if we have
- * started receiving anything.
- */
-static int irda_usb_is_receiving(struct irda_usb_cb *self)
-{
- /* Note : because of the way UHCI works, it's almost impossible
- * to get this info. The Controller DMA directly to memory and
- * signal only when the whole frame is finished. To know if the
- * first TD of the URB has been filled or not seems hard work...
- *
- * The other solution would be to use the "receiving" command
- * on the default decriptor with a usb_control_msg(), but that
- * would add USB traffic and would return result only in the
- * next USB frame (~1ms).
- *
- * I've been told that current dongles send status info on their
- * interrupt endpoint, and that's what the Windows driver uses
- * to know this info. Unfortunately, this is not yet in the spec...
- *
- * Jean II
- */
-
- return 0; /* For now */
-}
-
-#define STIR421X_PATCH_PRODUCT_VER "Product Version: "
-#define STIR421X_PATCH_STMP_TAG "STMP"
-#define STIR421X_PATCH_CODE_OFFSET 512 /* patch image starts before here */
-/* marks end of patch file header (PC DOS text file EOF character) */
-#define STIR421X_PATCH_END_OF_HDR_TAG 0x1A
-#define STIR421X_PATCH_BLOCK_SIZE 1023
-
-/*
- * Function stir421x_fwupload (struct irda_usb_cb *self,
- * unsigned char *patch,
- * const unsigned int patch_len)
- *
- * Upload firmware code to SigmaTel 421X IRDA-USB dongle
- */
-static int stir421x_fw_upload(struct irda_usb_cb *self,
- const unsigned char *patch,
- const unsigned int patch_len)
-{
- int ret = -ENOMEM;
- int actual_len = 0;
- unsigned int i;
- unsigned int block_size = 0;
- unsigned char *patch_block;
-
- patch_block = kzalloc(STIR421X_PATCH_BLOCK_SIZE, GFP_KERNEL);
- if (patch_block == NULL)
- return -ENOMEM;
-
- /* break up patch into 1023-byte sections */
- for (i = 0; i < patch_len; i += block_size) {
- block_size = patch_len - i;
-
- if (block_size > STIR421X_PATCH_BLOCK_SIZE)
- block_size = STIR421X_PATCH_BLOCK_SIZE;
-
- /* upload the patch section */
- memcpy(patch_block, patch + i, block_size);
-
- ret = usb_bulk_msg(self->usbdev,
- usb_sndbulkpipe(self->usbdev,
- self->bulk_out_ep),
- patch_block, block_size,
- &actual_len, msecs_to_jiffies(500));
- pr_debug("%s(): Bulk send %u bytes, ret=%d\n",
- __func__, actual_len, ret);
-
- if (ret < 0)
- break;
-
- mdelay(10);
- }
-
- kfree(patch_block);
-
- return ret;
- }
-
-/*
- * Function stir421x_patch_device(struct irda_usb_cb *self)
- *
- * Get a firmware code from userspase using hotplug request_firmware() call
- */
-static int stir421x_patch_device(struct irda_usb_cb *self)
-{
- unsigned int i;
- int ret;
- char stir421x_fw_name[12];
- const struct firmware *fw;
- const unsigned char *fw_version_ptr; /* pointer to version string */
- unsigned long fw_version = 0;
-
- /*
- * Known firmware patch file names for STIR421x dongles
- * are "42101001.sb" or "42101002.sb"
- */
- sprintf(stir421x_fw_name, "4210%4X.sb",
- le16_to_cpu(self->usbdev->descriptor.bcdDevice));
- ret = request_firmware(&fw, stir421x_fw_name, &self->usbdev->dev);
- if (ret < 0)
- return ret;
-
- /* We get a patch from userspace */
- net_info_ratelimited("%s(): Received firmware %s (%zu bytes)\n",
- __func__, stir421x_fw_name, fw->size);
-
- ret = -EINVAL;
-
- /* Get the bcd product version */
- if (!memcmp(fw->data, STIR421X_PATCH_PRODUCT_VER,
- sizeof(STIR421X_PATCH_PRODUCT_VER) - 1)) {
- fw_version_ptr = fw->data +
- sizeof(STIR421X_PATCH_PRODUCT_VER) - 1;
-
- /* Let's check if the product version is dotted */
- if (fw_version_ptr[3] == '.' &&
- fw_version_ptr[7] == '.') {
- unsigned long major, minor, build;
- major = simple_strtoul(fw_version_ptr, NULL, 10);
- minor = simple_strtoul(fw_version_ptr + 4, NULL, 10);
- build = simple_strtoul(fw_version_ptr + 8, NULL, 10);
-
- fw_version = (major << 12)
- + (minor << 8)
- + ((build / 10) << 4)
- + (build % 10);
-
- pr_debug("%s(): Firmware Product version %ld\n",
- __func__, fw_version);
- }
- }
-
- if (self->usbdev->descriptor.bcdDevice == cpu_to_le16(fw_version)) {
- /*
- * If we're here, we've found a correct patch
- * The actual image starts after the "STMP" keyword
- * so forward to the firmware header tag
- */
- for (i = 0; i < fw->size && fw->data[i] !=
- STIR421X_PATCH_END_OF_HDR_TAG; i++) ;
- /* here we check for the out of buffer case */
- if (i < STIR421X_PATCH_CODE_OFFSET && i < fw->size &&
- STIR421X_PATCH_END_OF_HDR_TAG == fw->data[i]) {
- if (!memcmp(fw->data + i + 1, STIR421X_PATCH_STMP_TAG,
- sizeof(STIR421X_PATCH_STMP_TAG) - 1)) {
-
- /* We can upload the patch to the target */
- i += sizeof(STIR421X_PATCH_STMP_TAG);
- ret = stir421x_fw_upload(self, &fw->data[i],
- fw->size - i);
- }
- }
- }
-
- release_firmware(fw);
-
- return ret;
-}
-
-
-/********************** IRDA DEVICE CALLBACKS **********************/
-/*
- * Main calls from the IrDA/Network subsystem.
- * Mostly registering a new irda-usb device and removing it....
- * We only deal with the IrDA side of the business, the USB side will
- * be dealt with below...
- */
-
-
-/*------------------------------------------------------------------*/
-/*
- * Function irda_usb_net_open (dev)
- *
- * Network device is taken up. Usually this is done by "ifconfig irda0 up"
- *
- * Note : don't mess with self->netopen - Jean II
- */
-static int irda_usb_net_open(struct net_device *netdev)
-{
- struct irda_usb_cb *self;
- unsigned long flags;
- char hwname[16];
- int i;
-
- IRDA_ASSERT(netdev != NULL, return -1;);
- self = netdev_priv(netdev);
- IRDA_ASSERT(self != NULL, return -1;);
-
- spin_lock_irqsave(&self->lock, flags);
- /* Can only open the device if it's there */
- if(!self->present) {
- spin_unlock_irqrestore(&self->lock, flags);
- net_warn_ratelimited("%s(), device not present!\n", __func__);
- return -1;
- }
-
- if(self->needspatch) {
- spin_unlock_irqrestore(&self->lock, flags);
- net_warn_ratelimited("%s(), device needs patch\n", __func__);
- return -EIO ;
- }
-
- /* Initialise default speed and xbofs value
- * (IrLAP will change that soon) */
- self->speed = -1;
- self->xbofs = -1;
- self->new_speed = -1;
- self->new_xbofs = -1;
-
- /* To do *before* submitting Rx urbs and starting net Tx queue
- * Jean II */
- self->netopen = 1;
- spin_unlock_irqrestore(&self->lock, flags);
-
- /*
- * Now that everything should be initialized properly,
- * Open new IrLAP layer instance to take care of us...
- * Note : will send immediately a speed change...
- */
- sprintf(hwname, "usb#%d", self->usbdev->devnum);
- self->irlap = irlap_open(netdev, &self->qos, hwname);
- IRDA_ASSERT(self->irlap != NULL, return -1;);
-
- /* Allow IrLAP to send data to us */
- netif_start_queue(netdev);
-
- /* We submit all the Rx URB except for one that we keep idle.
- * Need to be initialised before submitting other USBs, because
- * in some cases as soon as we submit the URBs the USB layer
- * will trigger a dummy receive - Jean II */
- self->idle_rx_urb = self->rx_urb[IU_MAX_ACTIVE_RX_URBS];
- self->idle_rx_urb->context = NULL;
-
- /* Now that we can pass data to IrLAP, allow the USB layer
- * to send us some data... */
- for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++) {
- struct sk_buff *skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
- if (!skb) {
- /* If this ever happen, we are in deep s***.
- * Basically, we can't start the Rx path... */
- return -1;
- }
- //skb_reserve(newskb, USB_IRDA_HEADER - 1);
- irda_usb_submit(self, skb, self->rx_urb[i]);
- }
-
- /* Ready to play !!! */
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irda_usb_net_close (self)
- *
- * Network device is taken down. Usually this is done by
- * "ifconfig irda0 down"
- */
-static int irda_usb_net_close(struct net_device *netdev)
-{
- struct irda_usb_cb *self;
- int i;
-
- IRDA_ASSERT(netdev != NULL, return -1;);
- self = netdev_priv(netdev);
- IRDA_ASSERT(self != NULL, return -1;);
-
- /* Clear this flag *before* unlinking the urbs and *before*
- * stopping the network Tx queue - Jean II */
- self->netopen = 0;
-
- /* Stop network Tx queue */
- netif_stop_queue(netdev);
-
- /* Kill defered Rx URB */
- del_timer(&self->rx_defer_timer);
-
- /* Deallocate all the Rx path buffers (URBs and skb) */
- for (i = 0; i < self->max_rx_urb; i++) {
- struct urb *urb = self->rx_urb[i];
- struct sk_buff *skb = (struct sk_buff *) urb->context;
- /* Cancel the receive command */
- usb_kill_urb(urb);
- /* The skb is ours, free it */
- if(skb) {
- dev_kfree_skb(skb);
- urb->context = NULL;
- }
- }
- /* Cancel Tx and speed URB - need to be synchronous to avoid races */
- usb_kill_urb(self->tx_urb);
- usb_kill_urb(self->speed_urb);
-
- /* Stop and remove instance of IrLAP */
- if (self->irlap)
- irlap_close(self->irlap);
- self->irlap = NULL;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * IOCTLs : Extra out-of-band network commands...
- */
-static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- unsigned long flags;
- struct if_irda_req *irq = (struct if_irda_req *) rq;
- struct irda_usb_cb *self;
- int ret = 0;
-
- IRDA_ASSERT(dev != NULL, return -1;);
- self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return -1;);
-
- pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
-
- switch (cmd) {
- case SIOCSBANDWIDTH: /* Set bandwidth */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- /* Protect us from USB callbacks, net watchdog and else. */
- spin_lock_irqsave(&self->lock, flags);
- /* Check if the device is still there */
- if(self->present) {
- /* Set the desired speed */
- self->new_speed = irq->ifr_baudrate;
- irda_usb_change_speed_xbofs(self);
- }
- spin_unlock_irqrestore(&self->lock, flags);
- break;
- case SIOCSMEDIABUSY: /* Set media busy */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- /* Check if the IrDA stack is still there */
- if(self->netopen)
- irda_device_set_media_busy(self->netdev, TRUE);
- break;
- case SIOCGRECEIVING: /* Check if we are receiving right now */
- irq->ifr_receiving = irda_usb_is_receiving(self);
- break;
- default:
- ret = -EOPNOTSUPP;
- }
-
- return ret;
-}
-
-/*------------------------------------------------------------------*/
-
-/********************* IRDA CONFIG SUBROUTINES *********************/
-/*
- * Various subroutines dealing with IrDA and network stuff we use to
- * configure and initialise each irda-usb instance.
- * These functions are used below in the main calls of the driver...
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Set proper values in the IrDA QOS structure
- */
-static inline void irda_usb_init_qos(struct irda_usb_cb *self)
-{
- struct irda_class_desc *desc;
-
-
- desc = self->irda_desc;
-
- /* Initialize QoS for this device */
- irda_init_max_qos_capabilies(&self->qos);
-
- /* See spec section 7.2 for meaning.
- * Values are little endian (as most USB stuff), the IrDA stack
- * use it in native order (see parameters.c). - Jean II */
- self->qos.baud_rate.bits = le16_to_cpu(desc->wBaudRate);
- self->qos.min_turn_time.bits = desc->bmMinTurnaroundTime;
- self->qos.additional_bofs.bits = desc->bmAdditionalBOFs;
- self->qos.window_size.bits = desc->bmWindowSize;
- self->qos.data_size.bits = desc->bmDataSize;
-
- pr_debug("%s(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n",
- __func__, self->qos.baud_rate.bits, self->qos.data_size.bits,
- self->qos.window_size.bits, self->qos.additional_bofs.bits,
- self->qos.min_turn_time.bits);
-
- /* Don't always trust what the dongle tell us */
- if(self->capability & IUC_SIR_ONLY)
- self->qos.baud_rate.bits &= 0x00ff;
- if(self->capability & IUC_SMALL_PKT)
- self->qos.data_size.bits = 0x07;
- if(self->capability & IUC_NO_WINDOW)
- self->qos.window_size.bits = 0x01;
- if(self->capability & IUC_MAX_WINDOW)
- self->qos.window_size.bits = 0x7f;
- if(self->capability & IUC_MAX_XBOFS)
- self->qos.additional_bofs.bits = 0x01;
-
-#if 1
- /* Module parameter can override the rx window size */
- if (qos_mtt_bits)
- self->qos.min_turn_time.bits = qos_mtt_bits;
-#endif
- /*
- * Note : most of those values apply only for the receive path,
- * the transmit path will be set differently - Jean II
- */
- irda_qos_bits_to_value(&self->qos);
-}
-
-/*------------------------------------------------------------------*/
-static const struct net_device_ops irda_usb_netdev_ops = {
- .ndo_open = irda_usb_net_open,
- .ndo_stop = irda_usb_net_close,
- .ndo_do_ioctl = irda_usb_net_ioctl,
- .ndo_start_xmit = irda_usb_hard_xmit,
- .ndo_tx_timeout = irda_usb_net_timeout,
-};
-
-/*
- * Initialise the network side of the irda-usb instance
- * Called when a new USB instance is registered in irda_usb_probe()
- */
-static inline int irda_usb_open(struct irda_usb_cb *self)
-{
- struct net_device *netdev = self->netdev;
-
- netdev->netdev_ops = &irda_usb_netdev_ops;
-
- irda_usb_init_qos(self);
-
- return register_netdev(netdev);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Cleanup the network side of the irda-usb instance
- * Called when a USB instance is removed in irda_usb_disconnect()
- */
-static inline void irda_usb_close(struct irda_usb_cb *self)
-{
- /* Remove netdevice */
- unregister_netdev(self->netdev);
-
- /* Remove the speed buffer */
- kfree(self->speed_buff);
- self->speed_buff = NULL;
-
- kfree(self->tx_buff);
- self->tx_buff = NULL;
-}
-
-/********************** USB CONFIG SUBROUTINES **********************/
-/*
- * Various subroutines dealing with USB stuff we use to configure and
- * initialise each irda-usb instance.
- * These functions are used below in the main calls of the driver...
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Function irda_usb_parse_endpoints(dev, ifnum)
- *
- * Parse the various endpoints and find the one we need.
- *
- * The endpoint are the pipes used to communicate with the USB device.
- * The spec defines 2 endpoints of type bulk transfer, one in, and one out.
- * These are used to pass frames back and forth with the dongle.
- * Most dongle have also an interrupt endpoint, that will be probably
- * documented in the next spec...
- */
-static inline int irda_usb_parse_endpoints(struct irda_usb_cb *self, struct usb_host_endpoint *endpoint, int ennum)
-{
- int i; /* Endpoint index in table */
-
- /* Init : no endpoints */
- self->bulk_in_ep = 0;
- self->bulk_out_ep = 0;
- self->bulk_int_ep = 0;
-
- /* Let's look at all those endpoints */
- for(i = 0; i < ennum; i++) {
- /* All those variables will get optimised by the compiler,
- * so let's aim for clarity... - Jean II */
- __u8 ep; /* Endpoint address */
- __u8 dir; /* Endpoint direction */
- __u8 attr; /* Endpoint attribute */
- __u16 psize; /* Endpoint max packet size in bytes */
-
- /* Get endpoint address, direction and attribute */
- ep = endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
- dir = endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK;
- attr = endpoint[i].desc.bmAttributes;
- psize = le16_to_cpu(endpoint[i].desc.wMaxPacketSize);
-
- /* Is it a bulk endpoint ??? */
- if(attr == USB_ENDPOINT_XFER_BULK) {
- /* We need to find an IN and an OUT */
- if(dir == USB_DIR_IN) {
- /* This is our Rx endpoint */
- self->bulk_in_ep = ep;
- } else {
- /* This is our Tx endpoint */
- self->bulk_out_ep = ep;
- self->bulk_out_mtu = psize;
- }
- } else {
- if((attr == USB_ENDPOINT_XFER_INT) &&
- (dir == USB_DIR_IN)) {
- /* This is our interrupt endpoint */
- self->bulk_int_ep = ep;
- } else {
- net_err_ratelimited("%s(), Unrecognised endpoint %02X\n",
- __func__, ep);
- }
- }
- }
-
- pr_debug("%s(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n",
- __func__, self->bulk_in_ep, self->bulk_out_ep,
- self->bulk_out_mtu, self->bulk_int_ep);
-
- return (self->bulk_in_ep != 0) && (self->bulk_out_ep != 0);
-}
-
-#ifdef IU_DUMP_CLASS_DESC
-/*------------------------------------------------------------------*/
-/*
- * Function usb_irda_dump_class_desc(desc)
- *
- * Prints out the contents of the IrDA class descriptor
- *
- */
-static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc)
-{
- /* Values are little endian */
- printk("bLength=%x\n", desc->bLength);
- printk("bDescriptorType=%x\n", desc->bDescriptorType);
- printk("bcdSpecRevision=%x\n", le16_to_cpu(desc->bcdSpecRevision));
- printk("bmDataSize=%x\n", desc->bmDataSize);
- printk("bmWindowSize=%x\n", desc->bmWindowSize);
- printk("bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime);
- printk("wBaudRate=%x\n", le16_to_cpu(desc->wBaudRate));
- printk("bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs);
- printk("bIrdaRateSniff=%x\n", desc->bIrdaRateSniff);
- printk("bMaxUnicastList=%x\n", desc->bMaxUnicastList);
-}
-#endif /* IU_DUMP_CLASS_DESC */
-
-/*------------------------------------------------------------------*/
-/*
- * Function irda_usb_find_class_desc(intf)
- *
- * Returns instance of IrDA class descriptor, or NULL if not found
- *
- * The class descriptor is some extra info that IrDA USB devices will
- * offer to us, describing their IrDA characteristics. We will use that in
- * irda_usb_init_qos()
- */
-static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf)
-{
- struct usb_device *dev = interface_to_usbdev (intf);
- struct irda_class_desc *desc;
- int ret;
-
- desc = kzalloc(sizeof(*desc), GFP_KERNEL);
- if (!desc)
- return NULL;
-
- /* USB-IrDA class spec 1.0:
- * 6.1.3: Standard "Get Descriptor" Device Request is not
- * appropriate to retrieve class-specific descriptor
- * 6.2.5: Class Specific "Get Class Descriptor" Interface Request
- * is mandatory and returns the USB-IrDA class descriptor
- */
-
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
- IU_REQ_GET_CLASS_DESC,
- USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, intf->altsetting->desc.bInterfaceNumber, desc,
- sizeof(*desc), 500);
-
- pr_debug("%s(), ret=%d\n", __func__, ret);
- if (ret < sizeof(*desc)) {
- net_warn_ratelimited("usb-irda: class_descriptor read %s (%d)\n",
- ret < 0 ? "failed" : "too short", ret);
- }
- else if (desc->bDescriptorType != USB_DT_IRDA) {
- net_warn_ratelimited("usb-irda: bad class_descriptor type\n");
- }
- else {
-#ifdef IU_DUMP_CLASS_DESC
- irda_usb_dump_class_desc(desc);
-#endif /* IU_DUMP_CLASS_DESC */
-
- return desc;
- }
- kfree(desc);
- return NULL;
-}
-
-/*********************** USB DEVICE CALLBACKS ***********************/
-/*
- * Main calls from the USB subsystem.
- * Mostly registering a new irda-usb device and removing it....
- */
-
-/*------------------------------------------------------------------*/
-/*
- * This routine is called by the USB subsystem for each new device
- * in the system. We need to check if the device is ours, and in
- * this case start handling it.
- * The USB layer protect us from reentrancy (via BKL), so we don't need
- * to spinlock in there... Jean II
- */
-static int irda_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct net_device *net;
- struct usb_device *dev = interface_to_usbdev(intf);
- struct irda_usb_cb *self;
- struct usb_host_interface *interface;
- struct irda_class_desc *irda_desc;
- int ret = -ENOMEM;
- int i; /* Driver instance index / Rx URB index */
-
- /* Note : the probe make sure to call us only for devices that
- * matches the list of dongle (top of the file). So, we
- * don't need to check if the dongle is really ours.
- * Jean II */
-
- net_info_ratelimited("IRDA-USB found at address %d, Vendor: %x, Product: %x\n",
- dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct));
-
- net = alloc_irdadev(sizeof(*self));
- if (!net)
- goto err_out;
-
- SET_NETDEV_DEV(net, &intf->dev);
- self = netdev_priv(net);
- self->netdev = net;
- spin_lock_init(&self->lock);
- timer_setup(&self->rx_defer_timer, irda_usb_rx_defer_expired, 0);
-
- self->capability = id->driver_info;
- self->needspatch = ((self->capability & IUC_STIR421X) != 0);
-
- /* Create all of the needed urbs */
- if (self->capability & IUC_STIR421X) {
- self->max_rx_urb = IU_SIGMATEL_MAX_RX_URBS;
- self->header_length = USB_IRDA_STIR421X_HEADER;
- } else {
- self->max_rx_urb = IU_MAX_RX_URBS;
- self->header_length = USB_IRDA_HEADER;
- }
-
- self->rx_urb = kcalloc(self->max_rx_urb, sizeof(struct urb *),
- GFP_KERNEL);
- if (!self->rx_urb)
- goto err_free_net;
-
- for (i = 0; i < self->max_rx_urb; i++) {
- self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
- if (!self->rx_urb[i]) {
- goto err_out_1;
- }
- }
- self->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!self->tx_urb) {
- goto err_out_1;
- }
- self->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!self->speed_urb) {
- goto err_out_2;
- }
-
- /* Is this really necessary? (no, except maybe for broken devices) */
- if (usb_reset_configuration (dev) < 0) {
- dev_err(&intf->dev, "reset_configuration failed\n");
- ret = -EIO;
- goto err_out_3;
- }
-
- /* Is this really necessary? */
- /* Note : some driver do hardcode the interface number, some others
- * specify an alternate, but very few driver do like this.
- * Jean II */
- ret = usb_set_interface(dev, intf->altsetting->desc.bInterfaceNumber, 0);
- pr_debug("usb-irda: set interface %d result %d\n",
- intf->altsetting->desc.bInterfaceNumber, ret);
- switch (ret) {
- case 0:
- break;
- case -EPIPE: /* -EPIPE = -32 */
- /* Martin Diehl says if we get a -EPIPE we should
- * be fine and we don't need to do a usb_clear_halt().
- * - Jean II */
- pr_debug("%s(), Received -EPIPE, ignoring...\n",
- __func__);
- break;
- default:
- pr_debug("%s(), Unknown error %d\n", __func__, ret);
- ret = -EIO;
- goto err_out_3;
- }
-
- /* Find our endpoints */
- interface = intf->cur_altsetting;
- if(!irda_usb_parse_endpoints(self, interface->endpoint,
- interface->desc.bNumEndpoints)) {
- net_err_ratelimited("%s(), Bogus endpoints...\n", __func__);
- ret = -EIO;
- goto err_out_3;
- }
-
- self->usbdev = dev;
-
- /* Find IrDA class descriptor */
- irda_desc = irda_usb_find_class_desc(intf);
- ret = -ENODEV;
- if (!irda_desc)
- goto err_out_3;
-
- if (self->needspatch) {
- ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0),
- 0x02, 0x40, 0, 0, NULL, 0, 500);
- if (ret < 0) {
- pr_debug("usb_control_msg failed %d\n", ret);
- goto err_out_3;
- } else {
- mdelay(10);
- }
- }
-
- self->irda_desc = irda_desc;
- self->present = 1;
- self->netopen = 0;
- self->usbintf = intf;
-
- /* Allocate the buffer for speed changes */
- /* Don't change this buffer size and allocation without doing
- * some heavy and complete testing. Don't ask why :-(
- * Jean II */
- ret = -ENOMEM;
- self->speed_buff = kzalloc(IRDA_USB_SPEED_MTU, GFP_KERNEL);
- if (!self->speed_buff)
- goto err_out_3;
-
- self->tx_buff = kzalloc(IRDA_SKB_MAX_MTU + self->header_length,
- GFP_KERNEL);
- if (!self->tx_buff)
- goto err_out_4;
-
- ret = irda_usb_open(self);
- if (ret)
- goto err_out_5;
-
- net_info_ratelimited("IrDA: Registered device %s\n", net->name);
- usb_set_intfdata(intf, self);
-
- if (self->needspatch) {
- /* Now we fetch and upload the firmware patch */
- ret = stir421x_patch_device(self);
- self->needspatch = (ret < 0);
- if (self->needspatch) {
- net_err_ratelimited("STIR421X: Couldn't upload patch\n");
- goto err_out_6;
- }
-
- /* replace IrDA class descriptor with what patched device is now reporting */
- irda_desc = irda_usb_find_class_desc (self->usbintf);
- if (!irda_desc) {
- ret = -ENODEV;
- goto err_out_6;
- }
- kfree(self->irda_desc);
- self->irda_desc = irda_desc;
- irda_usb_init_qos(self);
- }
-
- return 0;
-err_out_6:
- unregister_netdev(self->netdev);
-err_out_5:
- kfree(self->tx_buff);
-err_out_4:
- kfree(self->speed_buff);
-err_out_3:
- /* Free all urbs that we may have created */
- usb_free_urb(self->speed_urb);
-err_out_2:
- usb_free_urb(self->tx_urb);
-err_out_1:
- for (i = 0; i < self->max_rx_urb; i++)
- usb_free_urb(self->rx_urb[i]);
- kfree(self->rx_urb);
-err_free_net:
- free_netdev(net);
-err_out:
- return ret;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * The current irda-usb device is removed, the USB layer tell us
- * to shut it down...
- * One of the constraints is that when we exit this function,
- * we cannot use the usb_device no more. Gone. Destroyed. kfree().
- * Most other subsystem allow you to destroy the instance at a time
- * when it's convenient to you, to postpone it to a later date, but
- * not the USB subsystem.
- * So, we must make bloody sure that everything gets deactivated.
- * Jean II
- */
-static void irda_usb_disconnect(struct usb_interface *intf)
-{
- unsigned long flags;
- struct irda_usb_cb *self = usb_get_intfdata(intf);
- int i;
-
- usb_set_intfdata(intf, NULL);
- if (!self)
- return;
-
- /* Make sure that the Tx path is not executing. - Jean II */
- spin_lock_irqsave(&self->lock, flags);
-
- /* Oups ! We are not there any more.
- * This will stop/desactivate the Tx path. - Jean II */
- self->present = 0;
-
- /* Kill defered Rx URB */
- del_timer(&self->rx_defer_timer);
-
- /* We need to have irq enabled to unlink the URBs. That's OK,
- * at this point the Tx path is gone - Jean II */
- spin_unlock_irqrestore(&self->lock, flags);
-
- /* Hum... Check if networking is still active (avoid races) */
- if((self->netopen) || (self->irlap)) {
- /* Accept no more transmissions */
- /*netif_device_detach(self->netdev);*/
- netif_stop_queue(self->netdev);
- /* Stop all the receive URBs. Must be synchronous. */
- for (i = 0; i < self->max_rx_urb; i++)
- usb_kill_urb(self->rx_urb[i]);
- /* Cancel Tx and speed URB.
- * Make sure it's synchronous to avoid races. */
- usb_kill_urb(self->tx_urb);
- usb_kill_urb(self->speed_urb);
- }
-
- /* Cleanup the device stuff */
- irda_usb_close(self);
- /* No longer attached to USB bus */
- self->usbdev = NULL;
- self->usbintf = NULL;
-
- /* Clean up our urbs */
- for (i = 0; i < self->max_rx_urb; i++)
- usb_free_urb(self->rx_urb[i]);
- kfree(self->rx_urb);
- /* Clean up Tx and speed URB */
- usb_free_urb(self->tx_urb);
- usb_free_urb(self->speed_urb);
-
- /* Free self and network device */
- free_netdev(self->netdev);
- pr_debug("%s(), USB IrDA Disconnected\n", __func__);
-}
-
-#ifdef CONFIG_PM
-/* USB suspend, so power off the transmitter/receiver */
-static int irda_usb_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct irda_usb_cb *self = usb_get_intfdata(intf);
- int i;
-
- netif_device_detach(self->netdev);
-
- if (self->tx_urb != NULL)
- usb_kill_urb(self->tx_urb);
- if (self->speed_urb != NULL)
- usb_kill_urb(self->speed_urb);
- for (i = 0; i < self->max_rx_urb; i++) {
- if (self->rx_urb[i] != NULL)
- usb_kill_urb(self->rx_urb[i]);
- }
- return 0;
-}
-
-/* Coming out of suspend, so reset hardware */
-static int irda_usb_resume(struct usb_interface *intf)
-{
- struct irda_usb_cb *self = usb_get_intfdata(intf);
- int i;
-
- for (i = 0; i < self->max_rx_urb; i++) {
- if (self->rx_urb[i] != NULL)
- usb_submit_urb(self->rx_urb[i], GFP_KERNEL);
- }
-
- netif_device_attach(self->netdev);
- return 0;
-}
-#endif
-
-/*------------------------------------------------------------------*/
-/*
- * USB device callbacks
- */
-static struct usb_driver irda_driver = {
- .name = "irda-usb",
- .probe = irda_usb_probe,
- .disconnect = irda_usb_disconnect,
- .id_table = dongles,
-#ifdef CONFIG_PM
- .suspend = irda_usb_suspend,
- .resume = irda_usb_resume,
-#endif
-};
-
-module_usb_driver(irda_driver);
-
-/*
- * Module parameters
- */
-module_param(qos_mtt_bits, int, 0);
-MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
-MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net>, Jean Tourrilhes <jt@hpl.hp.com> and Nick Fedchik <nick@fedchik.org.ua>");
-MODULE_DESCRIPTION("IrDA-USB Dongle Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/irda/drivers/irda-usb.h b/drivers/staging/irda/drivers/irda-usb.h
deleted file mode 100644
index 56ee8c16c5e2..000000000000
--- a/drivers/staging/irda/drivers/irda-usb.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*****************************************************************************
- *
- * Filename: irda-usb.h
- * Version: 0.10
- * Description: IrDA-USB Driver
- * Status: Experimental
- * Author: Dag Brattli <dag@brattli.net>
- *
- * Copyright (C) 2001, Roman Weissgaerber <weissg@vienna.at>
- * Copyright (C) 2000, Dag Brattli <dag@brattli.net>
- * Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com>
- * Copyright (C) 2004, SigmaTel, Inc. <irquality@sigmatel.com>
- * Copyright (C) 2005, Milan Beno <beno@pobox.sk>
- * Copyright (C) 2006, Nick FEdchik <nick@fedchik.org.ua>
- *
- * 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.
- *
- * 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.
- *
- *****************************************************************************/
-
-#include <linux/ktime.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h> /* struct irlap_cb */
-
-#define RX_COPY_THRESHOLD 200
-#define IRDA_USB_MAX_MTU 2051
-#define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */
-
-/* Maximum number of active URB on the Rx path
- * This is the amount of buffers the we keep between the USB harware and the
- * IrDA stack.
- *
- * Note : the network layer does also queue the packets between us and the
- * IrDA stack, and is actually pretty fast and efficient in doing that.
- * Therefore, we don't need to have a large number of URBs, and we can
- * perfectly live happy with only one. We certainly don't need to keep the
- * full IrTTP window around here...
- * I repeat for those who have trouble to understand : 1 URB is plenty
- * good enough to handle back-to-back (brickwalled) frames. I tried it,
- * it works (it's the hardware that has trouble doing it).
- *
- * Having 2 URBs would allow the USB stack to process one URB while we take
- * care of the other and then swap the URBs...
- * On the other hand, increasing the number of URB will have penalities
- * in term of latency and will interact with the link management in IrLAP...
- * Jean II */
-#define IU_MAX_ACTIVE_RX_URBS 1 /* Don't touch !!! */
-
-/* When a Rx URB is passed back to us, we can't reuse it immediately,
- * because it may still be referenced by the USB layer. Therefore we
- * need to keep one extra URB in the Rx path.
- * Jean II */
-#define IU_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + 1)
-
-/* Various ugly stuff to try to workaround generic problems */
-/* Send speed command in case of timeout, just for trying to get things sane */
-#define IU_BUG_KICK_TIMEOUT
-/* Show the USB class descriptor */
-#undef IU_DUMP_CLASS_DESC
-/* Assume a minimum round trip latency for USB transfer (in us)...
- * USB transfer are done in the next USB slot if there is no traffic
- * (1/19 msec) and is done at 12 Mb/s :
- * Waiting for slot + tx = (53us + 16us) * 2 = 137us minimum.
- * Rx notification will only be done at the end of the USB frame period :
- * OHCI : frame period = 1ms
- * UHCI : frame period = 1ms, but notification can take 2 or 3 ms :-(
- * EHCI : frame period = 125us */
-#define IU_USB_MIN_RTT 500 /* This should be safe in most cases */
-
-/* Inbound header */
-#define MEDIA_BUSY 0x80
-
-#define SPEED_2400 0x01
-#define SPEED_9600 0x02
-#define SPEED_19200 0x03
-#define SPEED_38400 0x04
-#define SPEED_57600 0x05
-#define SPEED_115200 0x06
-#define SPEED_576000 0x07
-#define SPEED_1152000 0x08
-#define SPEED_4000000 0x09
-#define SPEED_16000000 0x0a
-
-/* Basic capabilities */
-#define IUC_DEFAULT 0x00 /* Basic device compliant with 1.0 spec */
-/* Main bugs */
-#define IUC_SPEED_BUG 0x01 /* Device doesn't set speed after the frame */
-#define IUC_NO_WINDOW 0x02 /* Device doesn't behave with big Rx window */
-#define IUC_NO_TURN 0x04 /* Device doesn't do turnaround by itself */
-/* Not currently used */
-#define IUC_SIR_ONLY 0x08 /* Device doesn't behave at FIR speeds */
-#define IUC_SMALL_PKT 0x10 /* Device doesn't behave with big Rx packets */
-#define IUC_MAX_WINDOW 0x20 /* Device underestimate the Rx window */
-#define IUC_MAX_XBOFS 0x40 /* Device need more xbofs than advertised */
-#define IUC_STIR421X 0x80 /* SigmaTel 4210/4220/4116 VFIR */
-
-/* USB class definitions */
-#define USB_IRDA_HEADER 0x01
-#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */
-#define USB_DT_IRDA 0x21
-#define USB_IRDA_STIR421X_HEADER 0x03
-#define IU_SIGMATEL_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + \
- USB_IRDA_STIR421X_HEADER)
-
-struct irda_class_desc {
- __u8 bLength;
- __u8 bDescriptorType;
- __le16 bcdSpecRevision;
- __u8 bmDataSize;
- __u8 bmWindowSize;
- __u8 bmMinTurnaroundTime;
- __le16 wBaudRate;
- __u8 bmAdditionalBOFs;
- __u8 bIrdaRateSniff;
- __u8 bMaxUnicastList;
-} __packed;
-
-/* class specific interface request to get the IrDA-USB class descriptor
- * (6.2.5, USB-IrDA class spec 1.0) */
-
-#define IU_REQ_GET_CLASS_DESC 0x06
-#define STIR421X_MAX_PATCH_DOWNLOAD_SIZE 1023
-
-struct irda_usb_cb {
- struct irda_class_desc *irda_desc;
- struct usb_device *usbdev; /* init: probe_irda */
- struct usb_interface *usbintf; /* init: probe_irda */
- int netopen; /* Device is active for network */
- int present; /* Device is present on the bus */
- __u32 capability; /* Capability of the hardware */
- __u8 bulk_in_ep; /* Rx Endpoint assignments */
- __u8 bulk_out_ep; /* Tx Endpoint assignments */
- __u16 bulk_out_mtu; /* Max Tx packet size in bytes */
- __u8 bulk_int_ep; /* Interrupt Endpoint assignments */
-
- __u8 max_rx_urb;
- struct urb **rx_urb; /* URBs used to receive data frames */
- struct urb *idle_rx_urb; /* Pointer to idle URB in Rx path */
- struct urb *tx_urb; /* URB used to send data frames */
- struct urb *speed_urb; /* URB used to send speed commands */
-
- struct net_device *netdev; /* Yes! we are some kind of netdev. */
- struct irlap_cb *irlap; /* The link layer we are binded to */
- struct qos_info qos;
- char *speed_buff; /* Buffer for speed changes */
- char *tx_buff;
-
- ktime_t stamp;
-
- spinlock_t lock; /* For serializing Tx operations */
-
- __u16 xbofs; /* Current xbofs setting */
- __s16 new_xbofs; /* xbofs we need to set */
- __u32 speed; /* Current speed */
- __s32 new_speed; /* speed we need to set */
-
- __u8 header_length; /* USB-IrDA frame header size */
- int needspatch; /* device needs firmware patch */
-
- struct timer_list rx_defer_timer; /* Wait for Rx error to clear */
- struct urb *rx_defer_timer_urb; /* URB attached to rx_defer_timer */
-};
-
diff --git a/drivers/staging/irda/drivers/irtty-sir.c b/drivers/staging/irda/drivers/irtty-sir.c
deleted file mode 100644
index 7a20a9a4663a..000000000000
--- a/drivers/staging/irda/drivers/irtty-sir.c
+++ /dev/null
@@ -1,570 +0,0 @@
-/*********************************************************************
- *
- * Filename: irtty-sir.c
- * Version: 2.0
- * Description: IrDA line discipline implementation
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Tue Dec 9 21:18:38 1997
- * Modified at: Sun Oct 27 22:13:30 2002
- * Modified by: Martin Diehl <mad@mdiehl.de>
- * Sources: slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
- * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- *
- * Copyright (c) 1998-2000 Dag Brattli,
- * Copyright (c) 2002 Martin Diehl,
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-#include <linux/uaccess.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-
-#include "sir-dev.h"
-#include "irtty-sir.h"
-
-static int qos_mtt_bits = 0x03; /* 5 ms or more */
-
-module_param(qos_mtt_bits, int, 0);
-MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
-
-/* ------------------------------------------------------- */
-
-/* device configuration callbacks always invoked with irda-thread context */
-
-/* find out, how many chars we have in buffers below us
- * this is allowed to lie, i.e. return less chars than we
- * actually have. The returned value is used to determine
- * how long the irdathread should wait before doing the
- * real blocking wait_until_sent()
- */
-
-static int irtty_chars_in_buffer(struct sir_dev *dev)
-{
- struct sirtty_cb *priv = dev->priv;
-
- IRDA_ASSERT(priv != NULL, return -1;);
- IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
-
- return tty_chars_in_buffer(priv->tty);
-}
-
-/* Wait (sleep) until underlaying hardware finished transmission
- * i.e. hardware buffers are drained
- * this must block and not return before all characters are really sent
- *
- * If the tty sits on top of a 16550A-like uart, there are typically
- * up to 16 bytes in the fifo - f.e. 9600 bps 8N1 needs 16.7 msec
- *
- * With usbserial the uart-fifo is basically replaced by the converter's
- * outgoing endpoint buffer, which can usually hold 64 bytes (at least).
- * With pl2303 it appears we are safe with 60msec here.
- *
- * I really wish all serial drivers would provide
- * correct implementation of wait_until_sent()
- */
-
-#define USBSERIAL_TX_DONE_DELAY 60
-
-static void irtty_wait_until_sent(struct sir_dev *dev)
-{
- struct sirtty_cb *priv = dev->priv;
- struct tty_struct *tty;
-
- IRDA_ASSERT(priv != NULL, return;);
- IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
-
- tty = priv->tty;
- if (tty->ops->wait_until_sent) {
- tty->ops->wait_until_sent(tty, msecs_to_jiffies(100));
- }
- else {
- msleep(USBSERIAL_TX_DONE_DELAY);
- }
-}
-
-/*
- * Function irtty_change_speed (dev, speed)
- *
- * Change the speed of the serial port.
- *
- * This may sleep in set_termios (usbserial driver f.e.) and must
- * not be called from interrupt/timer/tasklet therefore.
- * All such invocations are deferred to kIrDAd now so we can sleep there.
- */
-
-static int irtty_change_speed(struct sir_dev *dev, unsigned speed)
-{
- struct sirtty_cb *priv = dev->priv;
- struct tty_struct *tty;
- struct ktermios old_termios;
- int cflag;
-
- IRDA_ASSERT(priv != NULL, return -1;);
- IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
-
- tty = priv->tty;
-
- down_write(&tty->termios_rwsem);
- old_termios = tty->termios;
- cflag = tty->termios.c_cflag;
- tty_encode_baud_rate(tty, speed, speed);
- if (tty->ops->set_termios)
- tty->ops->set_termios(tty, &old_termios);
- priv->io.speed = speed;
- up_write(&tty->termios_rwsem);
-
- return 0;
-}
-
-/*
- * Function irtty_set_dtr_rts (dev, dtr, rts)
- *
- * This function can be used by dongles etc. to set or reset the status
- * of the dtr and rts lines
- */
-
-static int irtty_set_dtr_rts(struct sir_dev *dev, int dtr, int rts)
-{
- struct sirtty_cb *priv = dev->priv;
- int set = 0;
- int clear = 0;
-
- IRDA_ASSERT(priv != NULL, return -1;);
- IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
-
- if (rts)
- set |= TIOCM_RTS;
- else
- clear |= TIOCM_RTS;
- if (dtr)
- set |= TIOCM_DTR;
- else
- clear |= TIOCM_DTR;
-
- /*
- * We can't use ioctl() because it expects a non-null file structure,
- * and we don't have that here.
- * This function is not yet defined for all tty driver, so
- * let's be careful... Jean II
- */
- IRDA_ASSERT(priv->tty->ops->tiocmset != NULL, return -1;);
- priv->tty->ops->tiocmset(priv->tty, set, clear);
-
- return 0;
-}
-
-/* ------------------------------------------------------- */
-
-/* called from sir_dev when there is more data to send
- * context is either netdev->hard_xmit or some transmit-completion bh
- * i.e. we are under spinlock here and must not sleep.
- */
-
-static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t len)
-{
- struct sirtty_cb *priv = dev->priv;
- struct tty_struct *tty;
- int writelen;
-
- IRDA_ASSERT(priv != NULL, return -1;);
- IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
-
- tty = priv->tty;
- if (!tty->ops->write)
- return 0;
- set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- writelen = tty_write_room(tty);
- if (writelen > len)
- writelen = len;
- return tty->ops->write(tty, ptr, writelen);
-}
-
-/* ------------------------------------------------------- */
-
-/* irda line discipline callbacks */
-
-/*
- * Function irtty_receive_buf( tty, cp, count)
- *
- * Handle the 'receiver data ready' interrupt. This function is called
- * by the 'tty_io' module in the kernel when a block of IrDA data has
- * been received, which can now be decapsulated and delivered for
- * further processing
- *
- * calling context depends on underlying driver and tty->port->low_latency!
- * for example (low_latency: 1 / 0):
- * serial.c: uart-interrupt / softint
- * usbserial: urb-complete-interrupt / softint
- */
-
-static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
-{
- struct sir_dev *dev;
- struct sirtty_cb *priv = tty->disc_data;
- int i;
-
- IRDA_ASSERT(priv != NULL, return;);
- IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
-
- if (unlikely(count==0)) /* yes, this happens */
- return;
-
- dev = priv->dev;
- if (!dev) {
- net_warn_ratelimited("%s(), not ready yet!\n", __func__);
- return;
- }
-
- for (i = 0; i < count; i++) {
- /*
- * Characters received with a parity error, etc?
- */
- if (fp && *fp++) {
- pr_debug("Framing or parity error!\n");
- sirdev_receive(dev, NULL, 0); /* notify sir_dev (updating stats) */
- return;
- }
- }
-
- sirdev_receive(dev, cp, count);
-}
-
-/*
- * Function irtty_write_wakeup (tty)
- *
- * Called by the driver when there's room for more data. If we have
- * more packets to send, we send them here.
- *
- */
-static void irtty_write_wakeup(struct tty_struct *tty)
-{
- struct sirtty_cb *priv = tty->disc_data;
-
- IRDA_ASSERT(priv != NULL, return;);
- IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
-
- clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- if (priv->dev)
- sirdev_write_complete(priv->dev);
-}
-
-/* ------------------------------------------------------- */
-
-/*
- * Function irtty_stop_receiver (tty, stop)
- *
- */
-
-static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
-{
- struct ktermios old_termios;
- int cflag;
-
- down_write(&tty->termios_rwsem);
- old_termios = tty->termios;
- cflag = tty->termios.c_cflag;
-
- if (stop)
- cflag &= ~CREAD;
- else
- cflag |= CREAD;
-
- tty->termios.c_cflag = cflag;
- if (tty->ops->set_termios)
- tty->ops->set_termios(tty, &old_termios);
- up_write(&tty->termios_rwsem);
-}
-
-/*****************************************************************/
-
-/* serialize ldisc open/close with sir_dev */
-static DEFINE_MUTEX(irtty_mutex);
-
-/* notifier from sir_dev when irda% device gets opened (ifup) */
-
-static int irtty_start_dev(struct sir_dev *dev)
-{
- struct sirtty_cb *priv;
- struct tty_struct *tty;
-
- /* serialize with ldisc open/close */
- mutex_lock(&irtty_mutex);
-
- priv = dev->priv;
- if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {
- mutex_unlock(&irtty_mutex);
- return -ESTALE;
- }
-
- tty = priv->tty;
-
- if (tty->ops->start)
- tty->ops->start(tty);
- /* Make sure we can receive more data */
- irtty_stop_receiver(tty, FALSE);
-
- mutex_unlock(&irtty_mutex);
- return 0;
-}
-
-/* notifier from sir_dev when irda% device gets closed (ifdown) */
-
-static int irtty_stop_dev(struct sir_dev *dev)
-{
- struct sirtty_cb *priv;
- struct tty_struct *tty;
-
- /* serialize with ldisc open/close */
- mutex_lock(&irtty_mutex);
-
- priv = dev->priv;
- if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {
- mutex_unlock(&irtty_mutex);
- return -ESTALE;
- }
-
- tty = priv->tty;
-
- /* Make sure we don't receive more data */
- irtty_stop_receiver(tty, TRUE);
- if (tty->ops->stop)
- tty->ops->stop(tty);
-
- mutex_unlock(&irtty_mutex);
-
- return 0;
-}
-
-/* ------------------------------------------------------- */
-
-static struct sir_driver sir_tty_drv = {
- .owner = THIS_MODULE,
- .driver_name = "sir_tty",
- .start_dev = irtty_start_dev,
- .stop_dev = irtty_stop_dev,
- .do_write = irtty_do_write,
- .chars_in_buffer = irtty_chars_in_buffer,
- .wait_until_sent = irtty_wait_until_sent,
- .set_speed = irtty_change_speed,
- .set_dtr_rts = irtty_set_dtr_rts,
-};
-
-/* ------------------------------------------------------- */
-
-/*
- * Function irtty_ioctl (tty, file, cmd, arg)
- *
- * The Swiss army knife of system calls :-)
- *
- */
-static int irtty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct irtty_info { char name[6]; } info;
- struct sir_dev *dev;
- struct sirtty_cb *priv = tty->disc_data;
- int err = 0;
-
- IRDA_ASSERT(priv != NULL, return -ENODEV;);
- IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -EBADR;);
-
- pr_debug("%s(cmd=0x%X)\n", __func__, cmd);
-
- dev = priv->dev;
- IRDA_ASSERT(dev != NULL, return -1;);
-
- switch (cmd) {
- case IRTTY_IOCTDONGLE:
- /* this call blocks for completion */
- err = sirdev_set_dongle(dev, (IRDA_DONGLE) arg);
- break;
-
- case IRTTY_IOCGET:
- IRDA_ASSERT(dev->netdev != NULL, return -1;);
-
- memset(&info, 0, sizeof(info));
- strncpy(info.name, dev->netdev->name, sizeof(info.name)-1);
-
- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
- err = -EFAULT;
- break;
- default:
- err = tty_mode_ioctl(tty, file, cmd, arg);
- break;
- }
- return err;
-}
-
-
-/*
- * Function irtty_open(tty)
- *
- * This function is called by the TTY module when the IrDA line
- * discipline is called for. Because we are sure the tty line exists,
- * we only have to link it to a free IrDA channel.
- */
-static int irtty_open(struct tty_struct *tty)
-{
- struct sir_dev *dev;
- struct sirtty_cb *priv;
- int ret = 0;
-
- /* Module stuff handled via irda_ldisc.owner - Jean II */
-
- /* stop the underlying driver */
- irtty_stop_receiver(tty, TRUE);
- if (tty->ops->stop)
- tty->ops->stop(tty);
-
- tty_driver_flush_buffer(tty);
-
- /* apply mtt override */
- sir_tty_drv.qos_mtt_bits = qos_mtt_bits;
-
- /* get a sir device instance for this driver */
- dev = sirdev_get_instance(&sir_tty_drv, tty->name);
- if (!dev) {
- ret = -ENODEV;
- goto out;
- }
-
- /* allocate private device info block */
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- ret = -ENOMEM;
- goto out_put;
- }
-
- priv->magic = IRTTY_MAGIC;
- priv->tty = tty;
- priv->dev = dev;
-
- /* serialize with start_dev - in case we were racing with ifup */
- mutex_lock(&irtty_mutex);
-
- dev->priv = priv;
- tty->disc_data = priv;
- tty->receive_room = 65536;
-
- mutex_unlock(&irtty_mutex);
-
- pr_debug("%s - %s: irda line discipline opened\n", __func__, tty->name);
-
- return 0;
-
-out_put:
- sirdev_put_instance(dev);
-out:
- return ret;
-}
-
-/*
- * Function irtty_close (tty)
- *
- * Close down a IrDA channel. This means flushing out any pending queues,
- * and then restoring the TTY line discipline to what it was before it got
- * hooked to IrDA (which usually is TTY again).
- */
-static void irtty_close(struct tty_struct *tty)
-{
- struct sirtty_cb *priv = tty->disc_data;
-
- IRDA_ASSERT(priv != NULL, return;);
- IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
-
- /* Hm, with a dongle attached the dongle driver wants
- * to close the dongle - which requires the use of
- * some tty write and/or termios or ioctl operations.
- * Are we allowed to call those when already requested
- * to shutdown the ldisc?
- * If not, we should somehow mark the dev being staled.
- * Question remains, how to close the dongle in this case...
- * For now let's assume we are granted to issue tty driver calls
- * until we return here from the ldisc close. I'm just wondering
- * how this behaves with hotpluggable serial hardware like
- * rs232-pcmcia card or usb-serial...
- *
- * priv->tty = NULL?;
- */
-
- /* we are dead now */
- tty->disc_data = NULL;
-
- sirdev_put_instance(priv->dev);
-
- /* Stop tty */
- clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- if (tty->ops->stop)
- tty->ops->stop(tty);
-
- kfree(priv);
-
- pr_debug("%s - %s: irda line discipline closed\n", __func__, tty->name);
-}
-
-/* ------------------------------------------------------- */
-
-static struct tty_ldisc_ops irda_ldisc = {
- .magic = TTY_LDISC_MAGIC,
- .name = "irda",
- .flags = 0,
- .open = irtty_open,
- .close = irtty_close,
- .read = NULL,
- .write = NULL,
- .ioctl = irtty_ioctl,
- .poll = NULL,
- .receive_buf = irtty_receive_buf,
- .write_wakeup = irtty_write_wakeup,
- .owner = THIS_MODULE,
-};
-
-/* ------------------------------------------------------- */
-
-static int __init irtty_sir_init(void)
-{
- int err;
-
- if ((err = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0)
- net_err_ratelimited("IrDA: can't register line discipline (err = %d)\n",
- err);
- return err;
-}
-
-static void __exit irtty_sir_cleanup(void)
-{
- int err;
-
- if ((err = tty_unregister_ldisc(N_IRDA))) {
- net_err_ratelimited("%s(), can't unregister line discipline (err = %d)\n",
- __func__, err);
- }
-}
-
-module_init(irtty_sir_init);
-module_exit(irtty_sir_cleanup);
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("IrDA TTY device driver");
-MODULE_ALIAS_LDISC(N_IRDA);
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/staging/irda/drivers/irtty-sir.h b/drivers/staging/irda/drivers/irtty-sir.h
deleted file mode 100644
index b132d8f6eb13..000000000000
--- a/drivers/staging/irda/drivers/irtty-sir.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*********************************************************************
- *
- * sir_tty.h: definitions for the irtty_sir client driver (former irtty)
- *
- * Copyright (c) 2002 Martin Diehl
- *
- * 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 IRTTYSIR_H
-#define IRTTYSIR_H
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h> // chipio_t
-
-#define IRTTY_IOC_MAGIC 'e'
-#define IRTTY_IOCTDONGLE _IO(IRTTY_IOC_MAGIC, 1)
-#define IRTTY_IOCGET _IOR(IRTTY_IOC_MAGIC, 2, struct irtty_info)
-#define IRTTY_IOC_MAXNR 2
-
-struct sirtty_cb {
- magic_t magic;
-
- struct sir_dev *dev;
- struct tty_struct *tty;
-
- chipio_t io; /* IrDA controller information */
-};
-
-#endif
diff --git a/drivers/staging/irda/drivers/kingsun-sir.c b/drivers/staging/irda/drivers/kingsun-sir.c
deleted file mode 100644
index 4fd4ac2fe09f..000000000000
--- a/drivers/staging/irda/drivers/kingsun-sir.c
+++ /dev/null
@@ -1,634 +0,0 @@
-/*****************************************************************************
-*
-* Filename: kingsun-sir.c
-* Version: 0.1.1
-* Description: Irda KingSun/DonShine USB Dongle
-* Status: Experimental
-* Author: Alex Villacís Lasso <a_villacis@palosanto.com>
-*
-* Based on stir4200 and mcs7780 drivers, with (strange?) differences
-*
-* 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.
-*
-* 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 is my current (2007-04-25) understanding of how this dongle is supposed
- * to work. This is based on reverse-engineering and examination of the packet
- * data sent and received by the WinXP driver using USBSnoopy. Feel free to
- * update here as more of this dongle is known:
- *
- * General: Unlike the other USB IrDA dongles, this particular dongle exposes,
- * not two bulk (in and out) endpoints, but two *interrupt* ones. This dongle,
- * like the bulk based ones (stir4200.c and mcs7780.c), requires polling in
- * order to receive data.
- * Transmission: Just like stir4200, this dongle uses a raw stream of data,
- * which needs to be wrapped and escaped in a similar way as in stir4200.c.
- * Reception: Poll-based, as in stir4200. Each read returns the contents of a
- * 8-byte buffer, of which the first byte (LSB) indicates the number of bytes
- * (1-7) of valid data contained within the remaining 7 bytes. For example, if
- * the buffer had the following contents:
- * 06 ff ff ff c0 01 04 aa
- * This means that (06) there are 6 bytes of valid data. The byte 0xaa at the
- * end is garbage (left over from a previous reception) and is discarded.
- * If a read returns an "impossible" value as the length of valid data (such as
- * 0x36) in the first byte, then the buffer is uninitialized (as is the case of
- * first plug-in) and its contents should be discarded. There is currently no
- * evidence that the top 5 bits of the 1st byte of the buffer can have values
- * other than 0 once reception begins.
- * Once valid bytes are collected, the assembled stream is a sequence of
- * wrapped IrDA frames that is unwrapped and unescaped as in stir4200.c.
- * BIG FAT WARNING: the dongle does *not* reset the RX buffer in any way after
- * a successful read from the host, which means that in absence of further
- * reception, repeated reads from the dongle will return the exact same
- * contents repeatedly. Attempts to be smart and cache a previous read seem
- * to result in corrupted packets, so this driver depends on the unwrap logic
- * to sort out any repeated reads.
- * Speed change: no commands observed so far to change speed, assumed fixed
- * 9600bps (SIR).
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/device.h>
-#include <linux/crc32.h>
-
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/crc.h>
-
-/*
- * According to lsusb, 0x07c0 is assigned to
- * "Code Mercenaries Hard- und Software GmbH"
- */
-#define KING_VENDOR_ID 0x07c0
-#define KING_PRODUCT_ID 0x4200
-
-/* These are the currently known USB ids */
-static const struct usb_device_id dongles[] = {
- /* KingSun Co,Ltd IrDA/USB Bridge */
- { USB_DEVICE(KING_VENDOR_ID, KING_PRODUCT_ID) },
- { }
-};
-
-MODULE_DEVICE_TABLE(usb, dongles);
-
-#define KINGSUN_MTT 0x07
-
-#define KINGSUN_FIFO_SIZE 4096
-#define KINGSUN_EP_IN 0
-#define KINGSUN_EP_OUT 1
-
-struct kingsun_cb {
- struct usb_device *usbdev; /* init: probe_irda */
- struct net_device *netdev; /* network layer */
- struct irlap_cb *irlap; /* The link layer we are binded to */
-
- struct qos_info qos;
-
- __u8 *in_buf; /* receive buffer */
- __u8 *out_buf; /* transmit buffer */
- __u8 max_rx; /* max. atomic read from dongle
- (usually 8), also size of in_buf */
- __u8 max_tx; /* max. atomic write to dongle
- (usually 8) */
-
- iobuff_t rx_buff; /* receive unwrap state machine */
- spinlock_t lock;
- int receiving;
-
- __u8 ep_in;
- __u8 ep_out;
-
- struct urb *tx_urb;
- struct urb *rx_urb;
-};
-
-/* Callback transmission routine */
-static void kingsun_send_irq(struct urb *urb)
-{
- struct kingsun_cb *kingsun = urb->context;
- struct net_device *netdev = kingsun->netdev;
-
- /* in process of stopping, just drop data */
- if (!netif_running(kingsun->netdev)) {
- dev_err(&kingsun->usbdev->dev,
- "kingsun_send_irq: Network not running!\n");
- return;
- }
-
- /* unlink, shutdown, unplug, other nasties */
- if (urb->status != 0) {
- dev_err(&kingsun->usbdev->dev,
- "kingsun_send_irq: urb asynchronously failed - %d\n",
- urb->status);
- }
- netif_wake_queue(netdev);
-}
-
-/*
- * Called from net/core when new frame is available.
- */
-static netdev_tx_t kingsun_hard_xmit(struct sk_buff *skb,
- struct net_device *netdev)
-{
- struct kingsun_cb *kingsun;
- int wraplen;
- int ret = 0;
-
- netif_stop_queue(netdev);
-
- /* the IRDA wrapping routines don't deal with non linear skb */
- SKB_LINEAR_ASSERT(skb);
-
- kingsun = netdev_priv(netdev);
-
- spin_lock(&kingsun->lock);
-
- /* Append data to the end of whatever data remains to be transmitted */
- wraplen = async_wrap_skb(skb,
- kingsun->out_buf,
- KINGSUN_FIFO_SIZE);
-
- /* Calculate how much data can be transmitted in this urb */
- usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
- usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
- kingsun->out_buf, wraplen, kingsun_send_irq,
- kingsun, 1);
-
- if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) {
- dev_err(&kingsun->usbdev->dev,
- "kingsun_hard_xmit: failed tx_urb submit: %d\n", ret);
- switch (ret) {
- case -ENODEV:
- case -EPIPE:
- break;
- default:
- netdev->stats.tx_errors++;
- netif_start_queue(netdev);
- }
- } else {
- netdev->stats.tx_packets++;
- netdev->stats.tx_bytes += skb->len;
- }
-
- dev_kfree_skb(skb);
- spin_unlock(&kingsun->lock);
-
- return NETDEV_TX_OK;
-}
-
-/* Receive callback function */
-static void kingsun_rcv_irq(struct urb *urb)
-{
- struct kingsun_cb *kingsun = urb->context;
- int ret;
-
- /* in process of stopping, just drop data */
- if (!netif_running(kingsun->netdev)) {
- kingsun->receiving = 0;
- return;
- }
-
- /* unlink, shutdown, unplug, other nasties */
- if (urb->status != 0) {
- dev_err(&kingsun->usbdev->dev,
- "kingsun_rcv_irq: urb asynchronously failed - %d\n",
- urb->status);
- kingsun->receiving = 0;
- return;
- }
-
- if (urb->actual_length == kingsun->max_rx) {
- __u8 *bytes = urb->transfer_buffer;
- int i;
-
- /* The very first byte in the buffer indicates the length of
- valid data in the read. This byte must be in the range
- 1..kingsun->max_rx -1 . Values outside this range indicate
- an uninitialized Rx buffer when the dongle has just been
- plugged in. */
- if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) {
- for (i = 1; i <= bytes[0]; i++) {
- async_unwrap_char(kingsun->netdev,
- &kingsun->netdev->stats,
- &kingsun->rx_buff, bytes[i]);
- }
- kingsun->receiving =
- (kingsun->rx_buff.state != OUTSIDE_FRAME)
- ? 1 : 0;
- }
- } else if (urb->actual_length > 0) {
- dev_err(&kingsun->usbdev->dev,
- "%s(): Unexpected response length, expected %d got %d\n",
- __func__, kingsun->max_rx, urb->actual_length);
- }
- /* This urb has already been filled in kingsun_net_open */
- ret = usb_submit_urb(urb, GFP_ATOMIC);
-}
-
-/*
- * Function kingsun_net_open (dev)
- *
- * Network device is taken up. Usually this is done by "ifconfig irda0 up"
- */
-static int kingsun_net_open(struct net_device *netdev)
-{
- struct kingsun_cb *kingsun = netdev_priv(netdev);
- int err = -ENOMEM;
- char hwname[16];
-
- /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
- kingsun->receiving = 0;
-
- /* Initialize for SIR to copy data directly into skb. */
- kingsun->rx_buff.in_frame = FALSE;
- kingsun->rx_buff.state = OUTSIDE_FRAME;
- kingsun->rx_buff.truesize = IRDA_SKB_MAX_MTU;
- kingsun->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
- if (!kingsun->rx_buff.skb)
- goto free_mem;
-
- skb_reserve(kingsun->rx_buff.skb, 1);
- kingsun->rx_buff.head = kingsun->rx_buff.skb->data;
-
- kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!kingsun->rx_urb)
- goto free_mem;
-
- kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!kingsun->tx_urb)
- goto free_mem;
-
- /*
- * Now that everything should be initialized properly,
- * Open new IrLAP layer instance to take care of us...
- */
- sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
- kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
- if (!kingsun->irlap) {
- dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
- goto free_mem;
- }
-
- /* Start first reception */
- usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
- usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
- kingsun->in_buf, kingsun->max_rx,
- kingsun_rcv_irq, kingsun, 1);
- kingsun->rx_urb->status = 0;
- err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
- if (err) {
- dev_err(&kingsun->usbdev->dev,
- "first urb-submit failed: %d\n", err);
- goto close_irlap;
- }
-
- netif_start_queue(netdev);
-
- /* Situation at this point:
- - all work buffers allocated
- - urbs allocated and ready to fill
- - max rx packet known (in max_rx)
- - unwrap state machine initialized, in state outside of any frame
- - receive request in progress
- - IrLAP layer started, about to hand over packets to send
- */
-
- return 0;
-
- close_irlap:
- irlap_close(kingsun->irlap);
- free_mem:
- if (kingsun->tx_urb) {
- usb_free_urb(kingsun->tx_urb);
- kingsun->tx_urb = NULL;
- }
- if (kingsun->rx_urb) {
- usb_free_urb(kingsun->rx_urb);
- kingsun->rx_urb = NULL;
- }
- if (kingsun->rx_buff.skb) {
- kfree_skb(kingsun->rx_buff.skb);
- kingsun->rx_buff.skb = NULL;
- kingsun->rx_buff.head = NULL;
- }
- return err;
-}
-
-/*
- * Function kingsun_net_close (kingsun)
- *
- * Network device is taken down. Usually this is done by
- * "ifconfig irda0 down"
- */
-static int kingsun_net_close(struct net_device *netdev)
-{
- struct kingsun_cb *kingsun = netdev_priv(netdev);
-
- /* Stop transmit processing */
- netif_stop_queue(netdev);
-
- /* Mop up receive && transmit urb's */
- usb_kill_urb(kingsun->tx_urb);
- usb_kill_urb(kingsun->rx_urb);
-
- usb_free_urb(kingsun->tx_urb);
- usb_free_urb(kingsun->rx_urb);
-
- kingsun->tx_urb = NULL;
- kingsun->rx_urb = NULL;
-
- kfree_skb(kingsun->rx_buff.skb);
- kingsun->rx_buff.skb = NULL;
- kingsun->rx_buff.head = NULL;
- kingsun->rx_buff.in_frame = FALSE;
- kingsun->rx_buff.state = OUTSIDE_FRAME;
- kingsun->receiving = 0;
-
- /* Stop and remove instance of IrLAP */
- if (kingsun->irlap)
- irlap_close(kingsun->irlap);
-
- kingsun->irlap = NULL;
-
- return 0;
-}
-
-/*
- * IOCTLs : Extra out-of-band network commands...
- */
-static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq,
- int cmd)
-{
- struct if_irda_req *irq = (struct if_irda_req *) rq;
- struct kingsun_cb *kingsun = netdev_priv(netdev);
- int ret = 0;
-
- switch (cmd) {
- case SIOCSBANDWIDTH: /* Set bandwidth */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- /* Check if the device is still there */
- if (netif_device_present(kingsun->netdev))
- /* No observed commands for speed change */
- ret = -EOPNOTSUPP;
- break;
-
- case SIOCSMEDIABUSY: /* Set media busy */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- /* Check if the IrDA stack is still there */
- if (netif_running(kingsun->netdev))
- irda_device_set_media_busy(kingsun->netdev, TRUE);
- break;
-
- case SIOCGRECEIVING:
- /* Only approximately true */
- irq->ifr_receiving = kingsun->receiving;
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- return ret;
-}
-
-static const struct net_device_ops kingsun_ops = {
- .ndo_start_xmit = kingsun_hard_xmit,
- .ndo_open = kingsun_net_open,
- .ndo_stop = kingsun_net_close,
- .ndo_do_ioctl = kingsun_net_ioctl,
-};
-
-/*
- * This routine is called by the USB subsystem for each new device
- * in the system. We need to check if the device is ours, and in
- * this case start handling it.
- */
-static int kingsun_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_host_interface *interface;
- struct usb_endpoint_descriptor *endpoint;
-
- struct usb_device *dev = interface_to_usbdev(intf);
- struct kingsun_cb *kingsun = NULL;
- struct net_device *net = NULL;
- int ret = -ENOMEM;
- int pipe, maxp_in, maxp_out;
- __u8 ep_in;
- __u8 ep_out;
-
- /* Check that there really are two interrupt endpoints.
- Check based on the one in drivers/usb/input/usbmouse.c
- */
- interface = intf->cur_altsetting;
- if (interface->desc.bNumEndpoints != 2) {
- dev_err(&intf->dev,
- "kingsun-sir: expected 2 endpoints, found %d\n",
- interface->desc.bNumEndpoints);
- return -ENODEV;
- }
- endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
- if (!usb_endpoint_is_int_in(endpoint)) {
- dev_err(&intf->dev,
- "kingsun-sir: endpoint 0 is not interrupt IN\n");
- return -ENODEV;
- }
-
- ep_in = endpoint->bEndpointAddress;
- pipe = usb_rcvintpipe(dev, ep_in);
- maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
- if (maxp_in > 255 || maxp_in <= 1) {
- dev_err(&intf->dev,
- "endpoint 0 has max packet size %d not in range\n",
- maxp_in);
- return -ENODEV;
- }
-
- endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
- if (!usb_endpoint_is_int_out(endpoint)) {
- dev_err(&intf->dev,
- "kingsun-sir: endpoint 1 is not interrupt OUT\n");
- return -ENODEV;
- }
-
- ep_out = endpoint->bEndpointAddress;
- pipe = usb_sndintpipe(dev, ep_out);
- maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
-
- /* Allocate network device container. */
- net = alloc_irdadev(sizeof(*kingsun));
- if(!net)
- goto err_out1;
-
- SET_NETDEV_DEV(net, &intf->dev);
- kingsun = netdev_priv(net);
- kingsun->irlap = NULL;
- kingsun->tx_urb = NULL;
- kingsun->rx_urb = NULL;
- kingsun->ep_in = ep_in;
- kingsun->ep_out = ep_out;
- kingsun->in_buf = NULL;
- kingsun->out_buf = NULL;
- kingsun->max_rx = (__u8)maxp_in;
- kingsun->max_tx = (__u8)maxp_out;
- kingsun->netdev = net;
- kingsun->usbdev = dev;
- kingsun->rx_buff.in_frame = FALSE;
- kingsun->rx_buff.state = OUTSIDE_FRAME;
- kingsun->rx_buff.skb = NULL;
- kingsun->receiving = 0;
- spin_lock_init(&kingsun->lock);
-
- /* Allocate input buffer */
- kingsun->in_buf = kmalloc(kingsun->max_rx, GFP_KERNEL);
- if (!kingsun->in_buf)
- goto free_mem;
-
- /* Allocate output buffer */
- kingsun->out_buf = kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL);
- if (!kingsun->out_buf)
- goto free_mem;
-
- printk(KERN_INFO "KingSun/DonShine IRDA/USB found at address %d, "
- "Vendor: %x, Product: %x\n",
- dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct));
-
- /* Initialize QoS for this device */
- irda_init_max_qos_capabilies(&kingsun->qos);
-
- /* That's the Rx capability. */
- kingsun->qos.baud_rate.bits &= IR_9600;
- kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
- irda_qos_bits_to_value(&kingsun->qos);
-
- /* Override the network functions we need to use */
- net->netdev_ops = &kingsun_ops;
-
- ret = register_netdev(net);
- if (ret != 0)
- goto free_mem;
-
- dev_info(&net->dev, "IrDA: Registered KingSun/DonShine device %s\n",
- net->name);
-
- usb_set_intfdata(intf, kingsun);
-
- /* Situation at this point:
- - all work buffers allocated
- - urbs not allocated, set to NULL
- - max rx packet known (in max_rx)
- - unwrap state machine (partially) initialized, but skb == NULL
- */
-
- return 0;
-
-free_mem:
- kfree(kingsun->out_buf);
- kfree(kingsun->in_buf);
- free_netdev(net);
-err_out1:
- return ret;
-}
-
-/*
- * The current device is removed, the USB layer tell us to shut it down...
- */
-static void kingsun_disconnect(struct usb_interface *intf)
-{
- struct kingsun_cb *kingsun = usb_get_intfdata(intf);
-
- if (!kingsun)
- return;
-
- unregister_netdev(kingsun->netdev);
-
- /* Mop up receive && transmit urb's */
- if (kingsun->tx_urb != NULL) {
- usb_kill_urb(kingsun->tx_urb);
- usb_free_urb(kingsun->tx_urb);
- kingsun->tx_urb = NULL;
- }
- if (kingsun->rx_urb != NULL) {
- usb_kill_urb(kingsun->rx_urb);
- usb_free_urb(kingsun->rx_urb);
- kingsun->rx_urb = NULL;
- }
-
- kfree(kingsun->out_buf);
- kfree(kingsun->in_buf);
- free_netdev(kingsun->netdev);
-
- usb_set_intfdata(intf, NULL);
-}
-
-#ifdef CONFIG_PM
-/* USB suspend, so power off the transmitter/receiver */
-static int kingsun_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct kingsun_cb *kingsun = usb_get_intfdata(intf);
-
- netif_device_detach(kingsun->netdev);
- if (kingsun->tx_urb != NULL) usb_kill_urb(kingsun->tx_urb);
- if (kingsun->rx_urb != NULL) usb_kill_urb(kingsun->rx_urb);
- return 0;
-}
-
-/* Coming out of suspend, so reset hardware */
-static int kingsun_resume(struct usb_interface *intf)
-{
- struct kingsun_cb *kingsun = usb_get_intfdata(intf);
-
- if (kingsun->rx_urb != NULL)
- usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
- netif_device_attach(kingsun->netdev);
-
- return 0;
-}
-#endif
-
-/*
- * USB device callbacks
- */
-static struct usb_driver irda_driver = {
- .name = "kingsun-sir",
- .probe = kingsun_probe,
- .disconnect = kingsun_disconnect,
- .id_table = dongles,
-#ifdef CONFIG_PM
- .suspend = kingsun_suspend,
- .resume = kingsun_resume,
-#endif
-};
-
-module_usb_driver(irda_driver);
-
-MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
-MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun/DonShine");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/irda/drivers/ks959-sir.c b/drivers/staging/irda/drivers/ks959-sir.c
deleted file mode 100644
index 8025741e7586..000000000000
--- a/drivers/staging/irda/drivers/ks959-sir.c
+++ /dev/null
@@ -1,912 +0,0 @@
-/*****************************************************************************
-*
-* Filename: ks959-sir.c
-* Version: 0.1.2
-* Description: Irda KingSun KS-959 USB Dongle
-* Status: Experimental
-* Author: Alex Villacís Lasso <a_villacis@palosanto.com>
-* with help from Domen Puncer <domen@coderock.org>
-*
-* Based on stir4200, mcs7780, kingsun-sir drivers.
-*
-* 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.
-*
-* 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.
-*
-*****************************************************************************/
-
-/*
- * Following is my most current (2007-07-17) understanding of how the Kingsun
- * KS-959 dongle is supposed to work. This information was deduced by
- * reverse-engineering and examining the USB traffic captured with USBSnoopy
- * from the WinXP driver. Feel free to update here as more of the dongle is
- * known.
- *
- * My most sincere thanks must go to Domen Puncer <domen@coderock.org> for
- * invaluable help in cracking the obfuscation and padding required for this
- * dongle.
- *
- * General: This dongle exposes one interface with one interrupt IN endpoint.
- * However, the interrupt endpoint is NOT used at all for this dongle. Instead,
- * this dongle uses control transfers for everything, including sending and
- * receiving the IrDA frame data. Apparently the interrupt endpoint is just a
- * dummy to ensure the dongle has a valid interface to present to the PC.And I
- * thought the DonShine dongle was weird... In addition, this dongle uses
- * obfuscation (?!?!), applied at the USB level, to hide the traffic, both sent
- * and received, from the dongle. I call it obfuscation because the XOR keying
- * and padding required to produce an USB traffic acceptable for the dongle can
- * not be explained by any other technical requirement.
- *
- * Transmission: To transmit an IrDA frame, the driver must prepare a control
- * URB with the following as a setup packet:
- * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
- * bRequest 0x09
- * wValue <length of valid data before padding, little endian>
- * wIndex 0x0000
- * wLength <length of padded data>
- * The payload packet must be manually wrapped and escaped (as in stir4200.c),
- * then padded and obfuscated before being sent. Both padding and obfuscation
- * are implemented in the procedure obfuscate_tx_buffer(). Suffice to say, the
- * designer/programmer of the dongle used his name as a source for the
- * obfuscation. WTF?!
- * Apparently the dongle cannot handle payloads larger than 256 bytes. The
- * driver has to perform fragmentation in order to send anything larger than
- * this limit.
- *
- * Reception: To receive data, the driver must poll the dongle regularly (like
- * kingsun-sir.c) with control URBs and the following as a setup packet:
- * bRequestType USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE
- * bRequest 0x01
- * wValue 0x0200
- * wIndex 0x0000
- * wLength 0x0800 (size of available buffer)
- * If there is data to be read, it will be returned as the response payload.
- * This data is (apparently) not padded, but it is obfuscated. To de-obfuscate
- * it, the driver must XOR every byte, in sequence, with a value that starts at
- * 1 and is incremented with each byte processed, and then with 0x55. The value
- * incremented with each byte processed overflows as an unsigned char. The
- * resulting bytes form a wrapped SIR frame that is unwrapped and unescaped
- * as in stir4200.c The incremented value is NOT reset with each frame, but is
- * kept across the entire session with the dongle. Also, the dongle inserts an
- * extra garbage byte with value 0x95 (after decoding) every 0xff bytes, which
- * must be skipped.
- *
- * Speed change: To change the speed of the dongle, the driver prepares a
- * control URB with the following as a setup packet:
- * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
- * bRequest 0x09
- * wValue 0x0200
- * wIndex 0x0001
- * wLength 0x0008 (length of the payload)
- * The payload is a 8-byte record, apparently identical to the one used in
- * drivers/usb/serial/cypress_m8.c to change speed:
- * __u32 baudSpeed;
- * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits
- * unsigned int : 1;
- * unsigned int stopBits : 1;
- * unsigned int parityEnable : 1;
- * unsigned int parityType : 1;
- * unsigned int : 1;
- * unsigned int reset : 1;
- * unsigned char reserved[3]; // set to 0
- *
- * For now only SIR speeds have been observed with this dongle. Therefore,
- * nothing is known on what changes (if any) must be done to frame wrapping /
- * unwrapping for higher than SIR speeds. This driver assumes no change is
- * necessary and announces support for all the way to 57600 bps. Although the
- * package announces support for up to 4MBps, tests with a Sony Ericcson K300
- * phone show corruption when receiving large frames at 115200 bps, the highest
- * speed announced by the phone. However, transmission at 115200 bps is OK. Go
- * figure. Since I don't know whether the phone or the dongle is at fault, max
- * announced speed is 57600 bps until someone produces a device that can run
- * at higher speeds with this dongle.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/device.h>
-#include <linux/crc32.h>
-
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/crc.h>
-
-#define KS959_VENDOR_ID 0x07d0
-#define KS959_PRODUCT_ID 0x4959
-
-/* These are the currently known USB ids */
-static const struct usb_device_id dongles[] = {
- /* KingSun Co,Ltd IrDA/USB Bridge */
- {USB_DEVICE(KS959_VENDOR_ID, KS959_PRODUCT_ID)},
- {}
-};
-
-MODULE_DEVICE_TABLE(usb, dongles);
-
-#define KINGSUN_MTT 0x07
-#define KINGSUN_REQ_RECV 0x01
-#define KINGSUN_REQ_SEND 0x09
-
-#define KINGSUN_RCV_FIFO_SIZE 2048 /* Max length we can receive */
-#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */
-#define KINGSUN_SND_PACKET_SIZE 256 /* Max packet dongle can handle */
-
-struct ks959_speedparams {
- __le32 baudrate; /* baud rate, little endian */
- __u8 flags;
- __u8 reserved[3];
-} __packed;
-
-#define KS_DATA_5_BITS 0x00
-#define KS_DATA_6_BITS 0x01
-#define KS_DATA_7_BITS 0x02
-#define KS_DATA_8_BITS 0x03
-
-#define KS_STOP_BITS_1 0x00
-#define KS_STOP_BITS_2 0x08
-
-#define KS_PAR_DISABLE 0x00
-#define KS_PAR_EVEN 0x10
-#define KS_PAR_ODD 0x30
-#define KS_RESET 0x80
-
-struct ks959_cb {
- struct usb_device *usbdev; /* init: probe_irda */
- struct net_device *netdev; /* network layer */
- struct irlap_cb *irlap; /* The link layer we are binded to */
-
- struct qos_info qos;
-
- struct usb_ctrlrequest *tx_setuprequest;
- struct urb *tx_urb;
- __u8 *tx_buf_clear;
- unsigned int tx_buf_clear_used;
- unsigned int tx_buf_clear_sent;
- __u8 *tx_buf_xored;
-
- struct usb_ctrlrequest *rx_setuprequest;
- struct urb *rx_urb;
- __u8 *rx_buf;
- __u8 rx_variable_xormask;
- iobuff_t rx_unwrap_buff;
-
- struct usb_ctrlrequest *speed_setuprequest;
- struct urb *speed_urb;
- struct ks959_speedparams speedparams;
- unsigned int new_speed;
-
- spinlock_t lock;
- int receiving;
-};
-
-/* Procedure to perform the obfuscation/padding expected by the dongle
- *
- * buf_cleartext (IN) Cleartext version of the IrDA frame to transmit
- * len_cleartext (IN) Length of the cleartext version of IrDA frame
- * buf_xoredtext (OUT) Obfuscated version of frame built by proc
- * len_maxbuf (OUT) Maximum space available at buf_xoredtext
- *
- * (return) length of obfuscated frame with padding
- *
- * If not enough space (as indicated by len_maxbuf vs. required padding),
- * zero is returned
- *
- * The value of lookup_string is actually a required portion of the algorithm.
- * Seems the designer of the dongle wanted to state who exactly is responsible
- * for implementing obfuscation. Send your best (or other) wishes to him ]:-)
- */
-static unsigned int obfuscate_tx_buffer(const __u8 * buf_cleartext,
- unsigned int len_cleartext,
- __u8 * buf_xoredtext,
- unsigned int len_maxbuf)
-{
- unsigned int len_xoredtext;
-
- /* Calculate required length with padding, check for necessary space */
- len_xoredtext = ((len_cleartext + 7) & ~0x7) + 0x10;
- if (len_xoredtext <= len_maxbuf) {
- static const __u8 lookup_string[] = "wangshuofei19710";
- __u8 xor_mask;
-
- /* Unlike the WinXP driver, we *do* clear out the padding */
- memset(buf_xoredtext, 0, len_xoredtext);
-
- xor_mask = lookup_string[(len_cleartext & 0x0f) ^ 0x06] ^ 0x55;
-
- while (len_cleartext-- > 0) {
- *buf_xoredtext++ = *buf_cleartext++ ^ xor_mask;
- }
- } else {
- len_xoredtext = 0;
- }
- return len_xoredtext;
-}
-
-/* Callback transmission routine */
-static void ks959_speed_irq(struct urb *urb)
-{
- /* unlink, shutdown, unplug, other nasties */
- if (urb->status != 0) {
- dev_err(&urb->dev->dev,
- "ks959_speed_irq: urb asynchronously failed - %d\n",
- urb->status);
- }
-}
-
-/* Send a control request to change speed of the dongle */
-static int ks959_change_speed(struct ks959_cb *kingsun, unsigned speed)
-{
- static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400,
- 57600, 115200, 576000, 1152000, 4000000, 0
- };
- int err;
- unsigned int i;
-
- if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL)
- return -ENOMEM;
-
- /* Check that requested speed is among the supported ones */
- for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ;
- if (supported_speeds[i] == 0)
- return -EOPNOTSUPP;
-
- memset(&(kingsun->speedparams), 0, sizeof(struct ks959_speedparams));
- kingsun->speedparams.baudrate = cpu_to_le32(speed);
- kingsun->speedparams.flags = KS_DATA_8_BITS;
-
- /* speed_setuprequest pre-filled in ks959_probe */
- usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev,
- usb_sndctrlpipe(kingsun->usbdev, 0),
- (unsigned char *)kingsun->speed_setuprequest,
- &(kingsun->speedparams),
- sizeof(struct ks959_speedparams), ks959_speed_irq,
- kingsun);
- kingsun->speed_urb->status = 0;
- err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC);
-
- return err;
-}
-
-/* Submit one fragment of an IrDA frame to the dongle */
-static void ks959_send_irq(struct urb *urb);
-static int ks959_submit_tx_fragment(struct ks959_cb *kingsun)
-{
- unsigned int padlen;
- unsigned int wraplen;
- int ret;
-
- /* Check whether current plaintext can produce a padded buffer that fits
- within the range handled by the dongle */
- wraplen = (KINGSUN_SND_PACKET_SIZE & ~0x7) - 0x10;
- if (wraplen > kingsun->tx_buf_clear_used)
- wraplen = kingsun->tx_buf_clear_used;
-
- /* Perform dongle obfuscation. Also remove the portion of the frame that
- was just obfuscated and will now be sent to the dongle. */
- padlen = obfuscate_tx_buffer(kingsun->tx_buf_clear, wraplen,
- kingsun->tx_buf_xored,
- KINGSUN_SND_PACKET_SIZE);
-
- /* Calculate how much data can be transmitted in this urb */
- kingsun->tx_setuprequest->wValue = cpu_to_le16(wraplen);
- kingsun->tx_setuprequest->wLength = cpu_to_le16(padlen);
- /* Rest of the fields were filled in ks959_probe */
- usb_fill_control_urb(kingsun->tx_urb, kingsun->usbdev,
- usb_sndctrlpipe(kingsun->usbdev, 0),
- (unsigned char *)kingsun->tx_setuprequest,
- kingsun->tx_buf_xored, padlen,
- ks959_send_irq, kingsun);
- kingsun->tx_urb->status = 0;
- ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC);
-
- /* Remember how much data was sent, in order to update at callback */
- kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0;
- return ret;
-}
-
-/* Callback transmission routine */
-static void ks959_send_irq(struct urb *urb)
-{
- struct ks959_cb *kingsun = urb->context;
- struct net_device *netdev = kingsun->netdev;
- int ret = 0;
-
- /* in process of stopping, just drop data */
- if (!netif_running(kingsun->netdev)) {
- dev_err(&kingsun->usbdev->dev,
- "ks959_send_irq: Network not running!\n");
- return;
- }
-
- /* unlink, shutdown, unplug, other nasties */
- if (urb->status != 0) {
- dev_err(&kingsun->usbdev->dev,
- "ks959_send_irq: urb asynchronously failed - %d\n",
- urb->status);
- return;
- }
-
- if (kingsun->tx_buf_clear_used > 0) {
- /* Update data remaining to be sent */
- if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) {
- memmove(kingsun->tx_buf_clear,
- kingsun->tx_buf_clear +
- kingsun->tx_buf_clear_sent,
- kingsun->tx_buf_clear_used -
- kingsun->tx_buf_clear_sent);
- }
- kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent;
- kingsun->tx_buf_clear_sent = 0;
-
- if (kingsun->tx_buf_clear_used > 0) {
- /* There is more data to be sent */
- if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
- dev_err(&kingsun->usbdev->dev,
- "ks959_send_irq: failed tx_urb submit: %d\n",
- ret);
- switch (ret) {
- case -ENODEV:
- case -EPIPE:
- break;
- default:
- netdev->stats.tx_errors++;
- netif_start_queue(netdev);
- }
- }
- } else {
- /* All data sent, send next speed && wake network queue */
- if (kingsun->new_speed != -1 &&
- cpu_to_le32(kingsun->new_speed) !=
- kingsun->speedparams.baudrate)
- ks959_change_speed(kingsun, kingsun->new_speed);
-
- netif_wake_queue(netdev);
- }
- }
-}
-
-/*
- * Called from net/core when new frame is available.
- */
-static netdev_tx_t ks959_hard_xmit(struct sk_buff *skb,
- struct net_device *netdev)
-{
- struct ks959_cb *kingsun;
- unsigned int wraplen;
- int ret = 0;
-
- netif_stop_queue(netdev);
-
- /* the IRDA wrapping routines don't deal with non linear skb */
- SKB_LINEAR_ASSERT(skb);
-
- kingsun = netdev_priv(netdev);
-
- spin_lock(&kingsun->lock);
- kingsun->new_speed = irda_get_next_speed(skb);
-
- /* Append data to the end of whatever data remains to be transmitted */
- wraplen =
- async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE);
- kingsun->tx_buf_clear_used = wraplen;
-
- if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
- dev_err(&kingsun->usbdev->dev,
- "ks959_hard_xmit: failed tx_urb submit: %d\n", ret);
- switch (ret) {
- case -ENODEV:
- case -EPIPE:
- break;
- default:
- netdev->stats.tx_errors++;
- netif_start_queue(netdev);
- }
- } else {
- netdev->stats.tx_packets++;
- netdev->stats.tx_bytes += skb->len;
-
- }
-
- dev_kfree_skb(skb);
- spin_unlock(&kingsun->lock);
-
- return NETDEV_TX_OK;
-}
-
-/* Receive callback function */
-static void ks959_rcv_irq(struct urb *urb)
-{
- struct ks959_cb *kingsun = urb->context;
- int ret;
-
- /* in process of stopping, just drop data */
- if (!netif_running(kingsun->netdev)) {
- kingsun->receiving = 0;
- return;
- }
-
- /* unlink, shutdown, unplug, other nasties */
- if (urb->status != 0) {
- dev_err(&kingsun->usbdev->dev,
- "kingsun_rcv_irq: urb asynchronously failed - %d\n",
- urb->status);
- kingsun->receiving = 0;
- return;
- }
-
- if (urb->actual_length > 0) {
- __u8 *bytes = urb->transfer_buffer;
- unsigned int i;
-
- for (i = 0; i < urb->actual_length; i++) {
- /* De-obfuscation implemented here: variable portion of
- xormask is incremented, and then used with the encoded
- byte for the XOR. The result of the operation is used
- to unwrap the SIR frame. */
- kingsun->rx_variable_xormask++;
- bytes[i] =
- bytes[i] ^ kingsun->rx_variable_xormask ^ 0x55u;
-
- /* rx_variable_xormask doubles as an index counter so we
- can skip the byte at 0xff (wrapped around to 0).
- */
- if (kingsun->rx_variable_xormask != 0) {
- async_unwrap_char(kingsun->netdev,
- &kingsun->netdev->stats,
- &kingsun->rx_unwrap_buff,
- bytes[i]);
- }
- }
- kingsun->receiving =
- (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
- }
-
- /* This urb has already been filled in kingsun_net_open. Setup
- packet must be re-filled, but it is assumed that urb keeps the
- pointer to the initial setup packet, as well as the payload buffer.
- Setup packet is already pre-filled at ks959_probe.
- */
- urb->status = 0;
- ret = usb_submit_urb(urb, GFP_ATOMIC);
-}
-
-/*
- * Function kingsun_net_open (dev)
- *
- * Network device is taken up. Usually this is done by "ifconfig irda0 up"
- */
-static int ks959_net_open(struct net_device *netdev)
-{
- struct ks959_cb *kingsun = netdev_priv(netdev);
- int err = -ENOMEM;
- char hwname[16];
-
- /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
- kingsun->receiving = 0;
-
- /* Initialize for SIR to copy data directly into skb. */
- kingsun->rx_unwrap_buff.in_frame = FALSE;
- kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
- kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU;
- kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
- if (!kingsun->rx_unwrap_buff.skb)
- goto free_mem;
-
- skb_reserve(kingsun->rx_unwrap_buff.skb, 1);
- kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data;
-
- kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!kingsun->rx_urb)
- goto free_mem;
-
- kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!kingsun->tx_urb)
- goto free_mem;
-
- kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!kingsun->speed_urb)
- goto free_mem;
-
- /* Initialize speed for dongle */
- kingsun->new_speed = 9600;
- err = ks959_change_speed(kingsun, 9600);
- if (err < 0)
- goto free_mem;
-
- /*
- * Now that everything should be initialized properly,
- * Open new IrLAP layer instance to take care of us...
- */
- sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
- kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
- if (!kingsun->irlap) {
- err = -ENOMEM;
- dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
- goto free_mem;
- }
-
- /* Start reception. Setup request already pre-filled in ks959_probe */
- usb_fill_control_urb(kingsun->rx_urb, kingsun->usbdev,
- usb_rcvctrlpipe(kingsun->usbdev, 0),
- (unsigned char *)kingsun->rx_setuprequest,
- kingsun->rx_buf, KINGSUN_RCV_FIFO_SIZE,
- ks959_rcv_irq, kingsun);
- kingsun->rx_urb->status = 0;
- err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
- if (err) {
- dev_err(&kingsun->usbdev->dev,
- "first urb-submit failed: %d\n", err);
- goto close_irlap;
- }
-
- netif_start_queue(netdev);
-
- /* Situation at this point:
- - all work buffers allocated
- - urbs allocated and ready to fill
- - max rx packet known (in max_rx)
- - unwrap state machine initialized, in state outside of any frame
- - receive request in progress
- - IrLAP layer started, about to hand over packets to send
- */
-
- return 0;
-
- close_irlap:
- irlap_close(kingsun->irlap);
- free_mem:
- usb_free_urb(kingsun->speed_urb);
- kingsun->speed_urb = NULL;
- usb_free_urb(kingsun->tx_urb);
- kingsun->tx_urb = NULL;
- usb_free_urb(kingsun->rx_urb);
- kingsun->rx_urb = NULL;
- if (kingsun->rx_unwrap_buff.skb) {
- kfree_skb(kingsun->rx_unwrap_buff.skb);
- kingsun->rx_unwrap_buff.skb = NULL;
- kingsun->rx_unwrap_buff.head = NULL;
- }
- return err;
-}
-
-/*
- * Function kingsun_net_close (kingsun)
- *
- * Network device is taken down. Usually this is done by
- * "ifconfig irda0 down"
- */
-static int ks959_net_close(struct net_device *netdev)
-{
- struct ks959_cb *kingsun = netdev_priv(netdev);
-
- /* Stop transmit processing */
- netif_stop_queue(netdev);
-
- /* Mop up receive && transmit urb's */
- usb_kill_urb(kingsun->tx_urb);
- usb_free_urb(kingsun->tx_urb);
- kingsun->tx_urb = NULL;
-
- usb_kill_urb(kingsun->speed_urb);
- usb_free_urb(kingsun->speed_urb);
- kingsun->speed_urb = NULL;
-
- usb_kill_urb(kingsun->rx_urb);
- usb_free_urb(kingsun->rx_urb);
- kingsun->rx_urb = NULL;
-
- kfree_skb(kingsun->rx_unwrap_buff.skb);
- kingsun->rx_unwrap_buff.skb = NULL;
- kingsun->rx_unwrap_buff.head = NULL;
- kingsun->rx_unwrap_buff.in_frame = FALSE;
- kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
- kingsun->receiving = 0;
-
- /* Stop and remove instance of IrLAP */
- if (kingsun->irlap)
- irlap_close(kingsun->irlap);
-
- kingsun->irlap = NULL;
-
- return 0;
-}
-
-/*
- * IOCTLs : Extra out-of-band network commands...
- */
-static int ks959_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
-{
- struct if_irda_req *irq = (struct if_irda_req *)rq;
- struct ks959_cb *kingsun = netdev_priv(netdev);
- int ret = 0;
-
- switch (cmd) {
- case SIOCSBANDWIDTH: /* Set bandwidth */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- /* Check if the device is still there */
- if (netif_device_present(kingsun->netdev))
- return ks959_change_speed(kingsun, irq->ifr_baudrate);
- break;
-
- case SIOCSMEDIABUSY: /* Set media busy */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- /* Check if the IrDA stack is still there */
- if (netif_running(kingsun->netdev))
- irda_device_set_media_busy(kingsun->netdev, TRUE);
- break;
-
- case SIOCGRECEIVING:
- /* Only approximately true */
- irq->ifr_receiving = kingsun->receiving;
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- return ret;
-}
-
-static const struct net_device_ops ks959_ops = {
- .ndo_start_xmit = ks959_hard_xmit,
- .ndo_open = ks959_net_open,
- .ndo_stop = ks959_net_close,
- .ndo_do_ioctl = ks959_net_ioctl,
-};
-/*
- * This routine is called by the USB subsystem for each new device
- * in the system. We need to check if the device is ours, and in
- * this case start handling it.
- */
-static int ks959_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct ks959_cb *kingsun = NULL;
- struct net_device *net = NULL;
- int ret = -ENOMEM;
-
- /* Allocate network device container. */
- net = alloc_irdadev(sizeof(*kingsun));
- if (!net)
- goto err_out1;
-
- SET_NETDEV_DEV(net, &intf->dev);
- kingsun = netdev_priv(net);
- kingsun->netdev = net;
- kingsun->usbdev = dev;
- kingsun->irlap = NULL;
- kingsun->tx_setuprequest = NULL;
- kingsun->tx_urb = NULL;
- kingsun->tx_buf_clear = NULL;
- kingsun->tx_buf_xored = NULL;
- kingsun->tx_buf_clear_used = 0;
- kingsun->tx_buf_clear_sent = 0;
-
- kingsun->rx_setuprequest = NULL;
- kingsun->rx_urb = NULL;
- kingsun->rx_buf = NULL;
- kingsun->rx_variable_xormask = 0;
- kingsun->rx_unwrap_buff.in_frame = FALSE;
- kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
- kingsun->rx_unwrap_buff.skb = NULL;
- kingsun->receiving = 0;
- spin_lock_init(&kingsun->lock);
-
- kingsun->speed_setuprequest = NULL;
- kingsun->speed_urb = NULL;
- kingsun->speedparams.baudrate = 0;
-
- /* Allocate input buffer */
- kingsun->rx_buf = kmalloc(KINGSUN_RCV_FIFO_SIZE, GFP_KERNEL);
- if (!kingsun->rx_buf)
- goto free_mem;
-
- /* Allocate input setup packet */
- kingsun->rx_setuprequest =
- kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
- if (!kingsun->rx_setuprequest)
- goto free_mem;
- kingsun->rx_setuprequest->bRequestType =
- USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
- kingsun->rx_setuprequest->bRequest = KINGSUN_REQ_RECV;
- kingsun->rx_setuprequest->wValue = cpu_to_le16(0x0200);
- kingsun->rx_setuprequest->wIndex = 0;
- kingsun->rx_setuprequest->wLength = cpu_to_le16(KINGSUN_RCV_FIFO_SIZE);
-
- /* Allocate output buffer */
- kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL);
- if (!kingsun->tx_buf_clear)
- goto free_mem;
- kingsun->tx_buf_xored = kmalloc(KINGSUN_SND_PACKET_SIZE, GFP_KERNEL);
- if (!kingsun->tx_buf_xored)
- goto free_mem;
-
- /* Allocate and initialize output setup packet */
- kingsun->tx_setuprequest =
- kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
- if (!kingsun->tx_setuprequest)
- goto free_mem;
- kingsun->tx_setuprequest->bRequestType =
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
- kingsun->tx_setuprequest->bRequest = KINGSUN_REQ_SEND;
- kingsun->tx_setuprequest->wValue = 0;
- kingsun->tx_setuprequest->wIndex = 0;
- kingsun->tx_setuprequest->wLength = 0;
-
- /* Allocate and initialize speed setup packet */
- kingsun->speed_setuprequest =
- kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
- if (!kingsun->speed_setuprequest)
- goto free_mem;
- kingsun->speed_setuprequest->bRequestType =
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
- kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND;
- kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200);
- kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001);
- kingsun->speed_setuprequest->wLength =
- cpu_to_le16(sizeof(struct ks959_speedparams));
-
- printk(KERN_INFO "KingSun KS-959 IRDA/USB found at address %d, "
- "Vendor: %x, Product: %x\n",
- dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct));
-
- /* Initialize QoS for this device */
- irda_init_max_qos_capabilies(&kingsun->qos);
-
- /* Baud rates known to be supported. Please uncomment if devices (other
- than a SonyEriccson K300 phone) can be shown to support higher speed
- with this dongle.
- */
- kingsun->qos.baud_rate.bits =
- IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600;
- kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
- irda_qos_bits_to_value(&kingsun->qos);
-
- /* Override the network functions we need to use */
- net->netdev_ops = &ks959_ops;
-
- ret = register_netdev(net);
- if (ret != 0)
- goto free_mem;
-
- dev_info(&net->dev, "IrDA: Registered KingSun KS-959 device %s\n",
- net->name);
-
- usb_set_intfdata(intf, kingsun);
-
- /* Situation at this point:
- - all work buffers allocated
- - setup requests pre-filled
- - urbs not allocated, set to NULL
- - max rx packet known (is KINGSUN_FIFO_SIZE)
- - unwrap state machine (partially) initialized, but skb == NULL
- */
-
- return 0;
-
- free_mem:
- kfree(kingsun->speed_setuprequest);
- kfree(kingsun->tx_setuprequest);
- kfree(kingsun->tx_buf_xored);
- kfree(kingsun->tx_buf_clear);
- kfree(kingsun->rx_setuprequest);
- kfree(kingsun->rx_buf);
- free_netdev(net);
- err_out1:
- return ret;
-}
-
-/*
- * The current device is removed, the USB layer tell us to shut it down...
- */
-static void ks959_disconnect(struct usb_interface *intf)
-{
- struct ks959_cb *kingsun = usb_get_intfdata(intf);
-
- if (!kingsun)
- return;
-
- unregister_netdev(kingsun->netdev);
-
- /* Mop up receive && transmit urb's */
- if (kingsun->speed_urb != NULL) {
- usb_kill_urb(kingsun->speed_urb);
- usb_free_urb(kingsun->speed_urb);
- kingsun->speed_urb = NULL;
- }
- if (kingsun->tx_urb != NULL) {
- usb_kill_urb(kingsun->tx_urb);
- usb_free_urb(kingsun->tx_urb);
- kingsun->tx_urb = NULL;
- }
- if (kingsun->rx_urb != NULL) {
- usb_kill_urb(kingsun->rx_urb);
- usb_free_urb(kingsun->rx_urb);
- kingsun->rx_urb = NULL;
- }
-
- kfree(kingsun->speed_setuprequest);
- kfree(kingsun->tx_setuprequest);
- kfree(kingsun->tx_buf_xored);
- kfree(kingsun->tx_buf_clear);
- kfree(kingsun->rx_setuprequest);
- kfree(kingsun->rx_buf);
- free_netdev(kingsun->netdev);
-
- usb_set_intfdata(intf, NULL);
-}
-
-#ifdef CONFIG_PM
-/* USB suspend, so power off the transmitter/receiver */
-static int ks959_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct ks959_cb *kingsun = usb_get_intfdata(intf);
-
- netif_device_detach(kingsun->netdev);
- if (kingsun->speed_urb != NULL)
- usb_kill_urb(kingsun->speed_urb);
- if (kingsun->tx_urb != NULL)
- usb_kill_urb(kingsun->tx_urb);
- if (kingsun->rx_urb != NULL)
- usb_kill_urb(kingsun->rx_urb);
- return 0;
-}
-
-/* Coming out of suspend, so reset hardware */
-static int ks959_resume(struct usb_interface *intf)
-{
- struct ks959_cb *kingsun = usb_get_intfdata(intf);
-
- if (kingsun->rx_urb != NULL) {
- /* Setup request already filled in ks959_probe */
- usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
- }
- netif_device_attach(kingsun->netdev);
-
- return 0;
-}
-#endif
-
-/*
- * USB device callbacks
- */
-static struct usb_driver irda_driver = {
- .name = "ks959-sir",
- .probe = ks959_probe,
- .disconnect = ks959_disconnect,
- .id_table = dongles,
-#ifdef CONFIG_PM
- .suspend = ks959_suspend,
- .resume = ks959_resume,
-#endif
-};
-
-module_usb_driver(irda_driver);
-
-MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
-MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun KS-959");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/irda/drivers/ksdazzle-sir.c b/drivers/staging/irda/drivers/ksdazzle-sir.c
deleted file mode 100644
index d2a0755df596..000000000000
--- a/drivers/staging/irda/drivers/ksdazzle-sir.c
+++ /dev/null
@@ -1,813 +0,0 @@
-/*****************************************************************************
-*
-* Filename: ksdazzle.c
-* Version: 0.1.2
-* Description: Irda KingSun Dazzle USB Dongle
-* Status: Experimental
-* Author: Alex Villacís Lasso <a_villacis@palosanto.com>
-*
-* Based on stir4200, mcs7780, kingsun-sir drivers.
-*
-* 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.
-*
-* 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.
-*
-*****************************************************************************/
-
-/*
- * Following is my most current (2007-07-26) understanding of how the Kingsun
- * 07D0:4100 dongle (sometimes known as the MA-660) is supposed to work. This
- * information was deduced by examining the USB traffic captured with USBSnoopy
- * from the WinXP driver. Feel free to update here as more of the dongle is
- * known.
- *
- * General: This dongle exposes one interface with two interrupt endpoints, one
- * IN and one OUT. In this regard, it is similar to what the Kingsun/Donshine
- * dongle (07c0:4200) exposes. Traffic is raw and needs to be wrapped and
- * unwrapped manually as in stir4200, kingsun-sir, and ks959-sir.
- *
- * Transmission: To transmit an IrDA frame, it is necessary to wrap it, then
- * split it into multiple segments of up to 7 bytes each, and transmit each in
- * sequence. It seems that sending a single big block (like kingsun-sir does)
- * won't work with this dongle. Each segment needs to be prefixed with a value
- * equal to (unsigned char)0xF8 + <number of bytes in segment>, inside a payload
- * of exactly 8 bytes. For example, a segment of 1 byte gets prefixed by 0xF9,
- * and one of 7 bytes gets prefixed by 0xFF. The bytes at the end of the
- * payload, not considered by the prefix, are ignored (set to 0 by this
- * implementation).
- *
- * Reception: To receive data, the driver must poll the dongle regularly (like
- * kingsun-sir.c) with interrupt URBs. If data is available, it will be returned
- * in payloads from 0 to 8 bytes long. When concatenated, these payloads form
- * a raw IrDA stream that needs to be unwrapped as in stir4200 and kingsun-sir
- *
- * Speed change: To change the speed of the dongle, the driver prepares a
- * control URB with the following as a setup packet:
- * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
- * bRequest 0x09
- * wValue 0x0200
- * wIndex 0x0001
- * wLength 0x0008 (length of the payload)
- * The payload is a 8-byte record, apparently identical to the one used in
- * drivers/usb/serial/cypress_m8.c to change speed:
- * __u32 baudSpeed;
- * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits
- * unsigned int : 1;
- * unsigned int stopBits : 1;
- * unsigned int parityEnable : 1;
- * unsigned int parityType : 1;
- * unsigned int : 1;
- * unsigned int reset : 1;
- * unsigned char reserved[3]; // set to 0
- *
- * For now only SIR speeds have been observed with this dongle. Therefore,
- * nothing is known on what changes (if any) must be done to frame wrapping /
- * unwrapping for higher than SIR speeds. This driver assumes no change is
- * necessary and announces support for all the way to 115200 bps.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/device.h>
-#include <linux/crc32.h>
-
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/crc.h>
-
-#define KSDAZZLE_VENDOR_ID 0x07d0
-#define KSDAZZLE_PRODUCT_ID 0x4100
-
-/* These are the currently known USB ids */
-static const struct usb_device_id dongles[] = {
- /* KingSun Co,Ltd IrDA/USB Bridge */
- {USB_DEVICE(KSDAZZLE_VENDOR_ID, KSDAZZLE_PRODUCT_ID)},
- {}
-};
-
-MODULE_DEVICE_TABLE(usb, dongles);
-
-#define KINGSUN_MTT 0x07
-#define KINGSUN_REQ_RECV 0x01
-#define KINGSUN_REQ_SEND 0x09
-
-#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */
-#define KINGSUN_RCV_MAX 2048 /* Max transfer we can receive */
-
-struct ksdazzle_speedparams {
- __le32 baudrate; /* baud rate, little endian */
- __u8 flags;
- __u8 reserved[3];
-} __packed;
-
-#define KS_DATA_5_BITS 0x00
-#define KS_DATA_6_BITS 0x01
-#define KS_DATA_7_BITS 0x02
-#define KS_DATA_8_BITS 0x03
-
-#define KS_STOP_BITS_1 0x00
-#define KS_STOP_BITS_2 0x08
-
-#define KS_PAR_DISABLE 0x00
-#define KS_PAR_EVEN 0x10
-#define KS_PAR_ODD 0x30
-#define KS_RESET 0x80
-
-#define KINGSUN_EP_IN 0
-#define KINGSUN_EP_OUT 1
-
-struct ksdazzle_cb {
- struct usb_device *usbdev; /* init: probe_irda */
- struct net_device *netdev; /* network layer */
- struct irlap_cb *irlap; /* The link layer we are binded to */
-
- struct qos_info qos;
-
- struct urb *tx_urb;
- __u8 *tx_buf_clear;
- unsigned int tx_buf_clear_used;
- unsigned int tx_buf_clear_sent;
- __u8 tx_payload[8];
-
- struct urb *rx_urb;
- __u8 *rx_buf;
- iobuff_t rx_unwrap_buff;
-
- struct usb_ctrlrequest *speed_setuprequest;
- struct urb *speed_urb;
- struct ksdazzle_speedparams speedparams;
- unsigned int new_speed;
-
- __u8 ep_in;
- __u8 ep_out;
-
- spinlock_t lock;
- int receiving;
-};
-
-/* Callback transmission routine */
-static void ksdazzle_speed_irq(struct urb *urb)
-{
- /* unlink, shutdown, unplug, other nasties */
- if (urb->status != 0)
- dev_err(&urb->dev->dev,
- "ksdazzle_speed_irq: urb asynchronously failed - %d\n",
- urb->status);
-}
-
-/* Send a control request to change speed of the dongle */
-static int ksdazzle_change_speed(struct ksdazzle_cb *kingsun, unsigned speed)
-{
- static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400,
- 57600, 115200, 576000, 1152000, 4000000, 0
- };
- int err;
- unsigned int i;
-
- if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL)
- return -ENOMEM;
-
- /* Check that requested speed is among the supported ones */
- for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ;
- if (supported_speeds[i] == 0)
- return -EOPNOTSUPP;
-
- memset(&(kingsun->speedparams), 0, sizeof(struct ksdazzle_speedparams));
- kingsun->speedparams.baudrate = cpu_to_le32(speed);
- kingsun->speedparams.flags = KS_DATA_8_BITS;
-
- /* speed_setuprequest pre-filled in ksdazzle_probe */
- usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev,
- usb_sndctrlpipe(kingsun->usbdev, 0),
- (unsigned char *)kingsun->speed_setuprequest,
- &(kingsun->speedparams),
- sizeof(struct ksdazzle_speedparams),
- ksdazzle_speed_irq, kingsun);
- kingsun->speed_urb->status = 0;
- err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC);
-
- return err;
-}
-
-/* Submit one fragment of an IrDA frame to the dongle */
-static void ksdazzle_send_irq(struct urb *urb);
-static int ksdazzle_submit_tx_fragment(struct ksdazzle_cb *kingsun)
-{
- unsigned int wraplen;
- int ret;
-
- /* We can send at most 7 bytes of payload at a time */
- wraplen = 7;
- if (wraplen > kingsun->tx_buf_clear_used)
- wraplen = kingsun->tx_buf_clear_used;
-
- /* Prepare payload prefix with used length */
- memset(kingsun->tx_payload, 0, 8);
- kingsun->tx_payload[0] = (unsigned char)0xf8 + wraplen;
- memcpy(kingsun->tx_payload + 1, kingsun->tx_buf_clear, wraplen);
-
- usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
- usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
- kingsun->tx_payload, 8, ksdazzle_send_irq, kingsun, 1);
- kingsun->tx_urb->status = 0;
- ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC);
-
- /* Remember how much data was sent, in order to update at callback */
- kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0;
- return ret;
-}
-
-/* Callback transmission routine */
-static void ksdazzle_send_irq(struct urb *urb)
-{
- struct ksdazzle_cb *kingsun = urb->context;
- struct net_device *netdev = kingsun->netdev;
- int ret = 0;
-
- /* in process of stopping, just drop data */
- if (!netif_running(kingsun->netdev)) {
- dev_err(&kingsun->usbdev->dev,
- "ksdazzle_send_irq: Network not running!\n");
- return;
- }
-
- /* unlink, shutdown, unplug, other nasties */
- if (urb->status != 0) {
- dev_err(&kingsun->usbdev->dev,
- "ksdazzle_send_irq: urb asynchronously failed - %d\n",
- urb->status);
- return;
- }
-
- if (kingsun->tx_buf_clear_used > 0) {
- /* Update data remaining to be sent */
- if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) {
- memmove(kingsun->tx_buf_clear,
- kingsun->tx_buf_clear +
- kingsun->tx_buf_clear_sent,
- kingsun->tx_buf_clear_used -
- kingsun->tx_buf_clear_sent);
- }
- kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent;
- kingsun->tx_buf_clear_sent = 0;
-
- if (kingsun->tx_buf_clear_used > 0) {
- /* There is more data to be sent */
- if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
- dev_err(&kingsun->usbdev->dev,
- "ksdazzle_send_irq: failed tx_urb submit: %d\n",
- ret);
- switch (ret) {
- case -ENODEV:
- case -EPIPE:
- break;
- default:
- netdev->stats.tx_errors++;
- netif_start_queue(netdev);
- }
- }
- } else {
- /* All data sent, send next speed && wake network queue */
- if (kingsun->new_speed != -1 &&
- cpu_to_le32(kingsun->new_speed) !=
- kingsun->speedparams.baudrate)
- ksdazzle_change_speed(kingsun,
- kingsun->new_speed);
-
- netif_wake_queue(netdev);
- }
- }
-}
-
-/*
- * Called from net/core when new frame is available.
- */
-static netdev_tx_t ksdazzle_hard_xmit(struct sk_buff *skb,
- struct net_device *netdev)
-{
- struct ksdazzle_cb *kingsun;
- unsigned int wraplen;
- int ret = 0;
-
- netif_stop_queue(netdev);
-
- /* the IRDA wrapping routines don't deal with non linear skb */
- SKB_LINEAR_ASSERT(skb);
-
- kingsun = netdev_priv(netdev);
-
- spin_lock(&kingsun->lock);
- kingsun->new_speed = irda_get_next_speed(skb);
-
- /* Append data to the end of whatever data remains to be transmitted */
- wraplen =
- async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE);
- kingsun->tx_buf_clear_used = wraplen;
-
- if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
- dev_err(&kingsun->usbdev->dev,
- "ksdazzle_hard_xmit: failed tx_urb submit: %d\n", ret);
- switch (ret) {
- case -ENODEV:
- case -EPIPE:
- break;
- default:
- netdev->stats.tx_errors++;
- netif_start_queue(netdev);
- }
- } else {
- netdev->stats.tx_packets++;
- netdev->stats.tx_bytes += skb->len;
-
- }
-
- dev_kfree_skb(skb);
- spin_unlock(&kingsun->lock);
-
- return NETDEV_TX_OK;
-}
-
-/* Receive callback function */
-static void ksdazzle_rcv_irq(struct urb *urb)
-{
- struct ksdazzle_cb *kingsun = urb->context;
- struct net_device *netdev = kingsun->netdev;
-
- /* in process of stopping, just drop data */
- if (!netif_running(netdev)) {
- kingsun->receiving = 0;
- return;
- }
-
- /* unlink, shutdown, unplug, other nasties */
- if (urb->status != 0) {
- dev_err(&kingsun->usbdev->dev,
- "ksdazzle_rcv_irq: urb asynchronously failed - %d\n",
- urb->status);
- kingsun->receiving = 0;
- return;
- }
-
- if (urb->actual_length > 0) {
- __u8 *bytes = urb->transfer_buffer;
- unsigned int i;
-
- for (i = 0; i < urb->actual_length; i++) {
- async_unwrap_char(netdev, &netdev->stats,
- &kingsun->rx_unwrap_buff, bytes[i]);
- }
- kingsun->receiving =
- (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
- }
-
- /* This urb has already been filled in ksdazzle_net_open. It is assumed that
- urb keeps the pointer to the payload buffer.
- */
- urb->status = 0;
- usb_submit_urb(urb, GFP_ATOMIC);
-}
-
-/*
- * Function ksdazzle_net_open (dev)
- *
- * Network device is taken up. Usually this is done by "ifconfig irda0 up"
- */
-static int ksdazzle_net_open(struct net_device *netdev)
-{
- struct ksdazzle_cb *kingsun = netdev_priv(netdev);
- int err = -ENOMEM;
- char hwname[16];
-
- /* At this point, urbs are NULL, and skb is NULL (see ksdazzle_probe) */
- kingsun->receiving = 0;
-
- /* Initialize for SIR to copy data directly into skb. */
- kingsun->rx_unwrap_buff.in_frame = FALSE;
- kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
- kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU;
- kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
- if (!kingsun->rx_unwrap_buff.skb)
- goto free_mem;
-
- skb_reserve(kingsun->rx_unwrap_buff.skb, 1);
- kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data;
-
- kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!kingsun->rx_urb)
- goto free_mem;
-
- kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!kingsun->tx_urb)
- goto free_mem;
-
- kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!kingsun->speed_urb)
- goto free_mem;
-
- /* Initialize speed for dongle */
- kingsun->new_speed = 9600;
- err = ksdazzle_change_speed(kingsun, 9600);
- if (err < 0)
- goto free_mem;
-
- /*
- * Now that everything should be initialized properly,
- * Open new IrLAP layer instance to take care of us...
- */
- sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
- kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
- if (!kingsun->irlap) {
- err = -ENOMEM;
- dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
- goto free_mem;
- }
-
- /* Start reception. */
- usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
- usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
- kingsun->rx_buf, KINGSUN_RCV_MAX, ksdazzle_rcv_irq,
- kingsun, 1);
- kingsun->rx_urb->status = 0;
- err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
- if (err) {
- dev_err(&kingsun->usbdev->dev, "first urb-submit failed: %d\n", err);
- goto close_irlap;
- }
-
- netif_start_queue(netdev);
-
- /* Situation at this point:
- - all work buffers allocated
- - urbs allocated and ready to fill
- - max rx packet known (in max_rx)
- - unwrap state machine initialized, in state outside of any frame
- - receive request in progress
- - IrLAP layer started, about to hand over packets to send
- */
-
- return 0;
-
- close_irlap:
- irlap_close(kingsun->irlap);
- free_mem:
- usb_free_urb(kingsun->speed_urb);
- kingsun->speed_urb = NULL;
- usb_free_urb(kingsun->tx_urb);
- kingsun->tx_urb = NULL;
- usb_free_urb(kingsun->rx_urb);
- kingsun->rx_urb = NULL;
- if (kingsun->rx_unwrap_buff.skb) {
- kfree_skb(kingsun->rx_unwrap_buff.skb);
- kingsun->rx_unwrap_buff.skb = NULL;
- kingsun->rx_unwrap_buff.head = NULL;
- }
- return err;
-}
-
-/*
- * Function ksdazzle_net_close (dev)
- *
- * Network device is taken down. Usually this is done by
- * "ifconfig irda0 down"
- */
-static int ksdazzle_net_close(struct net_device *netdev)
-{
- struct ksdazzle_cb *kingsun = netdev_priv(netdev);
-
- /* Stop transmit processing */
- netif_stop_queue(netdev);
-
- /* Mop up receive && transmit urb's */
- usb_kill_urb(kingsun->tx_urb);
- usb_free_urb(kingsun->tx_urb);
- kingsun->tx_urb = NULL;
-
- usb_kill_urb(kingsun->speed_urb);
- usb_free_urb(kingsun->speed_urb);
- kingsun->speed_urb = NULL;
-
- usb_kill_urb(kingsun->rx_urb);
- usb_free_urb(kingsun->rx_urb);
- kingsun->rx_urb = NULL;
-
- kfree_skb(kingsun->rx_unwrap_buff.skb);
- kingsun->rx_unwrap_buff.skb = NULL;
- kingsun->rx_unwrap_buff.head = NULL;
- kingsun->rx_unwrap_buff.in_frame = FALSE;
- kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
- kingsun->receiving = 0;
-
- /* Stop and remove instance of IrLAP */
- irlap_close(kingsun->irlap);
-
- kingsun->irlap = NULL;
-
- return 0;
-}
-
-/*
- * IOCTLs : Extra out-of-band network commands...
- */
-static int ksdazzle_net_ioctl(struct net_device *netdev, struct ifreq *rq,
- int cmd)
-{
- struct if_irda_req *irq = (struct if_irda_req *)rq;
- struct ksdazzle_cb *kingsun = netdev_priv(netdev);
- int ret = 0;
-
- switch (cmd) {
- case SIOCSBANDWIDTH: /* Set bandwidth */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- /* Check if the device is still there */
- if (netif_device_present(kingsun->netdev))
- return ksdazzle_change_speed(kingsun,
- irq->ifr_baudrate);
- break;
-
- case SIOCSMEDIABUSY: /* Set media busy */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- /* Check if the IrDA stack is still there */
- if (netif_running(kingsun->netdev))
- irda_device_set_media_busy(kingsun->netdev, TRUE);
- break;
-
- case SIOCGRECEIVING:
- /* Only approximately true */
- irq->ifr_receiving = kingsun->receiving;
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- return ret;
-}
-
-static const struct net_device_ops ksdazzle_ops = {
- .ndo_start_xmit = ksdazzle_hard_xmit,
- .ndo_open = ksdazzle_net_open,
- .ndo_stop = ksdazzle_net_close,
- .ndo_do_ioctl = ksdazzle_net_ioctl,
-};
-
-/*
- * This routine is called by the USB subsystem for each new device
- * in the system. We need to check if the device is ours, and in
- * this case start handling it.
- */
-static int ksdazzle_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_host_interface *interface;
- struct usb_endpoint_descriptor *endpoint;
-
- struct usb_device *dev = interface_to_usbdev(intf);
- struct ksdazzle_cb *kingsun = NULL;
- struct net_device *net = NULL;
- int ret = -ENOMEM;
- int pipe, maxp_in, maxp_out;
- __u8 ep_in;
- __u8 ep_out;
-
- /* Check that there really are two interrupt endpoints. Check based on the
- one in drivers/usb/input/usbmouse.c
- */
- interface = intf->cur_altsetting;
- if (interface->desc.bNumEndpoints != 2) {
- dev_err(&intf->dev, "ksdazzle: expected 2 endpoints, found %d\n",
- interface->desc.bNumEndpoints);
- return -ENODEV;
- }
- endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
- if (!usb_endpoint_is_int_in(endpoint)) {
- dev_err(&intf->dev,
- "ksdazzle: endpoint 0 is not interrupt IN\n");
- return -ENODEV;
- }
-
- ep_in = endpoint->bEndpointAddress;
- pipe = usb_rcvintpipe(dev, ep_in);
- maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
- if (maxp_in > 255 || maxp_in <= 1) {
- dev_err(&intf->dev,
- "ksdazzle: endpoint 0 has max packet size %d not in range [2..255]\n",
- maxp_in);
- return -ENODEV;
- }
-
- endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
- if (!usb_endpoint_is_int_out(endpoint)) {
- dev_err(&intf->dev,
- "ksdazzle: endpoint 1 is not interrupt OUT\n");
- return -ENODEV;
- }
-
- ep_out = endpoint->bEndpointAddress;
- pipe = usb_sndintpipe(dev, ep_out);
- maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
-
- /* Allocate network device container. */
- net = alloc_irdadev(sizeof(*kingsun));
- if (!net)
- goto err_out1;
-
- SET_NETDEV_DEV(net, &intf->dev);
- kingsun = netdev_priv(net);
- kingsun->netdev = net;
- kingsun->usbdev = dev;
- kingsun->ep_in = ep_in;
- kingsun->ep_out = ep_out;
- kingsun->irlap = NULL;
- kingsun->tx_urb = NULL;
- kingsun->tx_buf_clear = NULL;
- kingsun->tx_buf_clear_used = 0;
- kingsun->tx_buf_clear_sent = 0;
-
- kingsun->rx_urb = NULL;
- kingsun->rx_buf = NULL;
- kingsun->rx_unwrap_buff.in_frame = FALSE;
- kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
- kingsun->rx_unwrap_buff.skb = NULL;
- kingsun->receiving = 0;
- spin_lock_init(&kingsun->lock);
-
- kingsun->speed_setuprequest = NULL;
- kingsun->speed_urb = NULL;
- kingsun->speedparams.baudrate = 0;
-
- /* Allocate input buffer */
- kingsun->rx_buf = kmalloc(KINGSUN_RCV_MAX, GFP_KERNEL);
- if (!kingsun->rx_buf)
- goto free_mem;
-
- /* Allocate output buffer */
- kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL);
- if (!kingsun->tx_buf_clear)
- goto free_mem;
-
- /* Allocate and initialize speed setup packet */
- kingsun->speed_setuprequest =
- kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
- if (!kingsun->speed_setuprequest)
- goto free_mem;
- kingsun->speed_setuprequest->bRequestType =
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
- kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND;
- kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200);
- kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001);
- kingsun->speed_setuprequest->wLength =
- cpu_to_le16(sizeof(struct ksdazzle_speedparams));
-
- printk(KERN_INFO "KingSun/Dazzle IRDA/USB found at address %d, "
- "Vendor: %x, Product: %x\n",
- dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct));
-
- /* Initialize QoS for this device */
- irda_init_max_qos_capabilies(&kingsun->qos);
-
- /* Baud rates known to be supported. Please uncomment if devices (other
- than a SonyEriccson K300 phone) can be shown to support higher speeds
- with this dongle.
- */
- kingsun->qos.baud_rate.bits =
- IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200;
- kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
- irda_qos_bits_to_value(&kingsun->qos);
-
- /* Override the network functions we need to use */
- net->netdev_ops = &ksdazzle_ops;
-
- ret = register_netdev(net);
- if (ret != 0)
- goto free_mem;
-
- dev_info(&net->dev, "IrDA: Registered KingSun/Dazzle device %s\n",
- net->name);
-
- usb_set_intfdata(intf, kingsun);
-
- /* Situation at this point:
- - all work buffers allocated
- - setup requests pre-filled
- - urbs not allocated, set to NULL
- - max rx packet known (is KINGSUN_FIFO_SIZE)
- - unwrap state machine (partially) initialized, but skb == NULL
- */
-
- return 0;
-
- free_mem:
- kfree(kingsun->speed_setuprequest);
- kfree(kingsun->tx_buf_clear);
- kfree(kingsun->rx_buf);
- free_netdev(net);
- err_out1:
- return ret;
-}
-
-/*
- * The current device is removed, the USB layer tell us to shut it down...
- */
-static void ksdazzle_disconnect(struct usb_interface *intf)
-{
- struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
-
- if (!kingsun)
- return;
-
- unregister_netdev(kingsun->netdev);
-
- /* Mop up receive && transmit urb's */
- usb_kill_urb(kingsun->speed_urb);
- usb_free_urb(kingsun->speed_urb);
- kingsun->speed_urb = NULL;
-
- usb_kill_urb(kingsun->tx_urb);
- usb_free_urb(kingsun->tx_urb);
- kingsun->tx_urb = NULL;
-
- usb_kill_urb(kingsun->rx_urb);
- usb_free_urb(kingsun->rx_urb);
- kingsun->rx_urb = NULL;
-
- kfree(kingsun->speed_setuprequest);
- kfree(kingsun->tx_buf_clear);
- kfree(kingsun->rx_buf);
- free_netdev(kingsun->netdev);
-
- usb_set_intfdata(intf, NULL);
-}
-
-#ifdef CONFIG_PM
-/* USB suspend, so power off the transmitter/receiver */
-static int ksdazzle_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
-
- netif_device_detach(kingsun->netdev);
- if (kingsun->speed_urb != NULL)
- usb_kill_urb(kingsun->speed_urb);
- if (kingsun->tx_urb != NULL)
- usb_kill_urb(kingsun->tx_urb);
- if (kingsun->rx_urb != NULL)
- usb_kill_urb(kingsun->rx_urb);
- return 0;
-}
-
-/* Coming out of suspend, so reset hardware */
-static int ksdazzle_resume(struct usb_interface *intf)
-{
- struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
-
- if (kingsun->rx_urb != NULL) {
- /* Setup request already filled in ksdazzle_probe */
- usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
- }
- netif_device_attach(kingsun->netdev);
-
- return 0;
-}
-#endif
-
-/*
- * USB device callbacks
- */
-static struct usb_driver irda_driver = {
- .name = "ksdazzle-sir",
- .probe = ksdazzle_probe,
- .disconnect = ksdazzle_disconnect,
- .id_table = dongles,
-#ifdef CONFIG_PM
- .suspend = ksdazzle_suspend,
- .resume = ksdazzle_resume,
-#endif
-};
-
-module_usb_driver(irda_driver);
-
-MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
-MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun Dazzle");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/irda/drivers/litelink-sir.c b/drivers/staging/irda/drivers/litelink-sir.c
deleted file mode 100644
index 8eefcb44bac3..000000000000
--- a/drivers/staging/irda/drivers/litelink-sir.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*********************************************************************
- *
- * Filename: litelink.c
- * Version: 1.1
- * Description: Driver for the Parallax LiteLink dongle
- * Status: Stable
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Fri May 7 12:50:33 1999
- * Modified at: Fri Dec 17 09:14:23 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Dag Brattli, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- ********************************************************************/
-
-/*
- * Modified at: Thu Jan 15 2003
- * Modified by: Eugene Crosser <crosser@average.org>
- *
- * Convert to "new" IRDA infrastructure for kernel 2.6
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-
-#include "sir-dev.h"
-
-#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */
-#define MAX_DELAY 10000 /* 1 ms */
-
-static int litelink_open(struct sir_dev *dev);
-static int litelink_close(struct sir_dev *dev);
-static int litelink_change_speed(struct sir_dev *dev, unsigned speed);
-static int litelink_reset(struct sir_dev *dev);
-
-/* These are the baudrates supported - 9600 must be last one! */
-static unsigned baud_rates[] = { 115200, 57600, 38400, 19200, 9600 };
-
-static struct dongle_driver litelink = {
- .owner = THIS_MODULE,
- .driver_name = "Parallax LiteLink",
- .type = IRDA_LITELINK_DONGLE,
- .open = litelink_open,
- .close = litelink_close,
- .reset = litelink_reset,
- .set_speed = litelink_change_speed,
-};
-
-static int __init litelink_sir_init(void)
-{
- return irda_register_dongle(&litelink);
-}
-
-static void __exit litelink_sir_cleanup(void)
-{
- irda_unregister_dongle(&litelink);
-}
-
-static int litelink_open(struct sir_dev *dev)
-{
- struct qos_info *qos = &dev->qos;
-
- /* Power up dongle */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- /* Set the speeds we can accept */
- qos->baud_rate.bits &= IR_115200|IR_57600|IR_38400|IR_19200|IR_9600;
- qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */
- irda_qos_bits_to_value(qos);
-
- /* irda thread waits 50 msec for power settling */
-
- return 0;
-}
-
-static int litelink_close(struct sir_dev *dev)
-{
- /* Power off dongle */
- sirdev_set_dtr_rts(dev, FALSE, FALSE);
-
- return 0;
-}
-
-/*
- * Function litelink_change_speed (task)
- *
- * Change speed of the Litelink dongle. To cycle through the available
- * baud rates, pulse RTS low for a few ms.
- */
-static int litelink_change_speed(struct sir_dev *dev, unsigned speed)
-{
- int i;
-
- /* dongle already reset by irda-thread - current speed (dongle and
- * port) is the default speed (115200 for litelink!)
- */
-
- /* Cycle through avaiable baudrates until we reach the correct one */
- for (i = 0; baud_rates[i] != speed; i++) {
-
- /* end-of-list reached due to invalid speed request */
- if (baud_rates[i] == 9600)
- break;
-
- /* Set DTR, clear RTS */
- sirdev_set_dtr_rts(dev, FALSE, TRUE);
-
- /* Sleep a minimum of 15 us */
- udelay(MIN_DELAY);
-
- /* Set DTR, Set RTS */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- /* Sleep a minimum of 15 us */
- udelay(MIN_DELAY);
- }
-
- dev->speed = baud_rates[i];
-
- /* invalid baudrate should not happen - but if, we return -EINVAL and
- * the dongle configured for 9600 so the stack has a chance to recover
- */
-
- return (dev->speed == speed) ? 0 : -EINVAL;
-}
-
-/*
- * Function litelink_reset (task)
- *
- * Reset the Litelink type dongle.
- *
- */
-static int litelink_reset(struct sir_dev *dev)
-{
- /* probably the power-up can be dropped here, but with only
- * 15 usec delay it's not worth the risk unless somebody with
- * the hardware confirms it doesn't break anything...
- */
-
- /* Power on dongle */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- /* Sleep a minimum of 15 us */
- udelay(MIN_DELAY);
-
- /* Clear RTS to reset dongle */
- sirdev_set_dtr_rts(dev, TRUE, FALSE);
-
- /* Sleep a minimum of 15 us */
- udelay(MIN_DELAY);
-
- /* Go back to normal mode */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- /* Sleep a minimum of 15 us */
- udelay(MIN_DELAY);
-
- /* This dongles speed defaults to 115200 bps */
- dev->speed = 115200;
-
- return 0;
-}
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("Parallax Litelink dongle driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-5"); /* IRDA_LITELINK_DONGLE */
-
-/*
- * Function init_module (void)
- *
- * Initialize Litelink module
- *
- */
-module_init(litelink_sir_init);
-
-/*
- * Function cleanup_module (void)
- *
- * Cleanup Litelink module
- *
- */
-module_exit(litelink_sir_cleanup);
diff --git a/drivers/staging/irda/drivers/ma600-sir.c b/drivers/staging/irda/drivers/ma600-sir.c
deleted file mode 100644
index a764817b47f1..000000000000
--- a/drivers/staging/irda/drivers/ma600-sir.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/*********************************************************************
- *
- * Filename: ma600.c
- * Version: 0.1
- * Description: Implementation of the MA600 dongle
- * Status: Experimental.
- * Author: Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95
- * Created at: Sat Jun 10 20:02:35 2000
- * Modified at: Sat Aug 16 09:34:13 2003
- * Modified by: Martin Diehl <mad@mdiehl.de> (modified for new sir_dev)
- *
- * Note: very thanks to Mr. Maru Wang <maru@mobileaction.com.tw> for providing
- * information on the MA600 dongle
- *
- * Copyright (c) 2000 Leung, 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.
- *
- * 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/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-
-#include "sir-dev.h"
-
-static int ma600_open(struct sir_dev *);
-static int ma600_close(struct sir_dev *);
-static int ma600_change_speed(struct sir_dev *, unsigned);
-static int ma600_reset(struct sir_dev *);
-
-/* control byte for MA600 */
-#define MA600_9600 0x00
-#define MA600_19200 0x01
-#define MA600_38400 0x02
-#define MA600_57600 0x03
-#define MA600_115200 0x04
-#define MA600_DEV_ID1 0x05
-#define MA600_DEV_ID2 0x06
-#define MA600_2400 0x08
-
-static struct dongle_driver ma600 = {
- .owner = THIS_MODULE,
- .driver_name = "MA600",
- .type = IRDA_MA600_DONGLE,
- .open = ma600_open,
- .close = ma600_close,
- .reset = ma600_reset,
- .set_speed = ma600_change_speed,
-};
-
-
-static int __init ma600_sir_init(void)
-{
- return irda_register_dongle(&ma600);
-}
-
-static void __exit ma600_sir_cleanup(void)
-{
- irda_unregister_dongle(&ma600);
-}
-
-/*
- Power on:
- (0) Clear RTS and DTR for 1 second
- (1) Set RTS and DTR for 1 second
- (2) 9600 bps now
- Note: assume RTS, DTR are clear before
-*/
-static int ma600_open(struct sir_dev *dev)
-{
- struct qos_info *qos = &dev->qos;
-
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- /* Explicitly set the speeds we can accept */
- qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400
- |IR_57600|IR_115200;
- /* Hm, 0x01 means 10ms - for >= 1ms we would need 0x07 */
- qos->min_turn_time.bits = 0x01; /* Needs at least 1 ms */
- irda_qos_bits_to_value(qos);
-
- /* irda thread waits 50 msec for power settling */
-
- return 0;
-}
-
-static int ma600_close(struct sir_dev *dev)
-{
- /* Power off dongle */
- sirdev_set_dtr_rts(dev, FALSE, FALSE);
-
- return 0;
-}
-
-static __u8 get_control_byte(__u32 speed)
-{
- __u8 byte;
-
- switch (speed) {
- default:
- case 115200:
- byte = MA600_115200;
- break;
- case 57600:
- byte = MA600_57600;
- break;
- case 38400:
- byte = MA600_38400;
- break;
- case 19200:
- byte = MA600_19200;
- break;
- case 9600:
- byte = MA600_9600;
- break;
- case 2400:
- byte = MA600_2400;
- break;
- }
-
- return byte;
-}
-
-/*
- * Function ma600_change_speed (dev, speed)
- *
- * Set the speed for the MA600 type dongle.
- *
- * The dongle has already been reset to a known state (dongle default)
- * We cycle through speeds by pulsing RTS low and then high.
- */
-
-/*
- * Function ma600_change_speed (dev, speed)
- *
- * Set the speed for the MA600 type dongle.
- *
- * Algorithm
- * 1. Reset (already done by irda thread state machine)
- * 2. clear RTS, set DTR and wait for 1ms
- * 3. send Control Byte to the MA600 through TXD to set new baud rate
- * wait until the stop bit of Control Byte is sent (for 9600 baud rate,
- * it takes about 10 msec)
- * 4. set RTS, set DTR (return to NORMAL Operation)
- * 5. wait at least 10 ms, new setting (baud rate, etc) takes effect here
- * after
- */
-
-/* total delays are only about 20ms - let's just sleep for now to
- * avoid the state machine complexity before we get things working
- */
-
-static int ma600_change_speed(struct sir_dev *dev, unsigned speed)
-{
- u8 byte;
-
- pr_debug("%s(), speed=%d (was %d)\n", __func__,
- speed, dev->speed);
-
- /* dongle already reset, dongle and port at default speed (9600) */
-
- /* Set RTS low for 1 ms */
- sirdev_set_dtr_rts(dev, TRUE, FALSE);
- mdelay(1);
-
- /* Write control byte */
- byte = get_control_byte(speed);
- sirdev_raw_write(dev, &byte, sizeof(byte));
-
- /* Wait at least 10ms: fake wait_until_sent - 10 bits at 9600 baud*/
- msleep(15); /* old ma600 uses 15ms */
-
-#if 1
- /* read-back of the control byte. ma600 is the first dongle driver
- * which uses this so there might be some unidentified issues.
- * Disable this in case of problems with readback.
- */
-
- sirdev_raw_read(dev, &byte, sizeof(byte));
- if (byte != get_control_byte(speed)) {
- net_warn_ratelimited("%s(): bad control byte read-back %02x != %02x\n",
- __func__, (unsigned)byte,
- (unsigned)get_control_byte(speed));
- return -1;
- }
- else
- pr_debug("%s() control byte write read OK\n", __func__);
-#endif
-
- /* Set DTR, Set RTS */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- /* Wait at least 10ms */
- msleep(10);
-
- /* dongle is now switched to the new speed */
- dev->speed = speed;
-
- return 0;
-}
-
-/*
- * Function ma600_reset (dev)
- *
- * This function resets the ma600 dongle.
- *
- * Algorithm:
- * 0. DTR=0, RTS=1 and wait 10 ms
- * 1. DTR=1, RTS=1 and wait 10 ms
- * 2. 9600 bps now
- */
-
-/* total delays are only about 20ms - let's just sleep for now to
- * avoid the state machine complexity before we get things working
- */
-
-static int ma600_reset(struct sir_dev *dev)
-{
- /* Reset the dongle : set DTR low for 10 ms */
- sirdev_set_dtr_rts(dev, FALSE, TRUE);
- msleep(10);
-
- /* Go back to normal mode */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
- msleep(10);
-
- dev->speed = 9600; /* That's the dongle-default */
-
- return 0;
-}
-
-MODULE_AUTHOR("Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95");
-MODULE_DESCRIPTION("MA600 dongle driver version 0.1");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-11"); /* IRDA_MA600_DONGLE */
-
-module_init(ma600_sir_init);
-module_exit(ma600_sir_cleanup);
-
diff --git a/drivers/staging/irda/drivers/mcp2120-sir.c b/drivers/staging/irda/drivers/mcp2120-sir.c
deleted file mode 100644
index 2e33f91bfe8f..000000000000
--- a/drivers/staging/irda/drivers/mcp2120-sir.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*********************************************************************
- *
- *
- * Filename: mcp2120.c
- * Version: 1.0
- * Description: Implementation for the MCP2120 (Microchip)
- * Status: Experimental.
- * Author: Felix Tang (tangf@eyetap.org)
- * Created at: Sun Mar 31 19:32:12 EST 2002
- * Based on code by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 2002 Felix Tang, 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.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-
-#include "sir-dev.h"
-
-static int mcp2120_reset(struct sir_dev *dev);
-static int mcp2120_open(struct sir_dev *dev);
-static int mcp2120_close(struct sir_dev *dev);
-static int mcp2120_change_speed(struct sir_dev *dev, unsigned speed);
-
-#define MCP2120_9600 0x87
-#define MCP2120_19200 0x8B
-#define MCP2120_38400 0x85
-#define MCP2120_57600 0x83
-#define MCP2120_115200 0x81
-
-#define MCP2120_COMMIT 0x11
-
-static struct dongle_driver mcp2120 = {
- .owner = THIS_MODULE,
- .driver_name = "Microchip MCP2120",
- .type = IRDA_MCP2120_DONGLE,
- .open = mcp2120_open,
- .close = mcp2120_close,
- .reset = mcp2120_reset,
- .set_speed = mcp2120_change_speed,
-};
-
-static int __init mcp2120_sir_init(void)
-{
- return irda_register_dongle(&mcp2120);
-}
-
-static void __exit mcp2120_sir_cleanup(void)
-{
- irda_unregister_dongle(&mcp2120);
-}
-
-static int mcp2120_open(struct sir_dev *dev)
-{
- struct qos_info *qos = &dev->qos;
-
- /* seems no explicit power-on required here and reset switching it on anyway */
-
- qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
- qos->min_turn_time.bits = 0x01;
- irda_qos_bits_to_value(qos);
-
- return 0;
-}
-
-static int mcp2120_close(struct sir_dev *dev)
-{
- /* Power off dongle */
- /* reset and inhibit mcp2120 */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
- // sirdev_set_dtr_rts(dev, FALSE, FALSE);
-
- return 0;
-}
-
-/*
- * Function mcp2120_change_speed (dev, speed)
- *
- * Set the speed for the MCP2120.
- *
- */
-
-#define MCP2120_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED+1)
-
-static int mcp2120_change_speed(struct sir_dev *dev, unsigned speed)
-{
- unsigned state = dev->fsm.substate;
- unsigned delay = 0;
- u8 control[2];
- static int ret = 0;
-
- switch (state) {
- case SIRDEV_STATE_DONGLE_SPEED:
- /* Set DTR to enter command mode */
- sirdev_set_dtr_rts(dev, TRUE, FALSE);
- udelay(500);
-
- ret = 0;
- switch (speed) {
- default:
- speed = 9600;
- ret = -EINVAL;
- /* fall through */
- case 9600:
- control[0] = MCP2120_9600;
- //printk("mcp2120 9600\n");
- break;
- case 19200:
- control[0] = MCP2120_19200;
- //printk("mcp2120 19200\n");
- break;
- case 34800:
- control[0] = MCP2120_38400;
- //printk("mcp2120 38400\n");
- break;
- case 57600:
- control[0] = MCP2120_57600;
- //printk("mcp2120 57600\n");
- break;
- case 115200:
- control[0] = MCP2120_115200;
- //printk("mcp2120 115200\n");
- break;
- }
- control[1] = MCP2120_COMMIT;
-
- /* Write control bytes */
- sirdev_raw_write(dev, control, 2);
- dev->speed = speed;
-
- state = MCP2120_STATE_WAIT_SPEED;
- delay = 100;
- //printk("mcp2120_change_speed: dongle_speed\n");
- break;
-
- case MCP2120_STATE_WAIT_SPEED:
- /* Go back to normal mode */
- sirdev_set_dtr_rts(dev, FALSE, FALSE);
- //printk("mcp2120_change_speed: mcp_wait\n");
- break;
-
- default:
- net_err_ratelimited("%s(), undefine state %d\n",
- __func__, state);
- ret = -EINVAL;
- break;
- }
- dev->fsm.substate = state;
- return (delay > 0) ? delay : ret;
-}
-
-/*
- * Function mcp2120_reset (driver)
- *
- * This function resets the mcp2120 dongle.
- *
- * Info: -set RTS to reset mcp2120
- * -set DTR to set mcp2120 software command mode
- * -mcp2120 defaults to 9600 baud after reset
- *
- * Algorithm:
- * 0. Set RTS to reset mcp2120.
- * 1. Clear RTS and wait for device reset timer of 30 ms (max).
- *
- */
-
-#define MCP2120_STATE_WAIT1_RESET (SIRDEV_STATE_DONGLE_RESET+1)
-#define MCP2120_STATE_WAIT2_RESET (SIRDEV_STATE_DONGLE_RESET+2)
-
-static int mcp2120_reset(struct sir_dev *dev)
-{
- unsigned state = dev->fsm.substate;
- unsigned delay = 0;
- int ret = 0;
-
- switch (state) {
- case SIRDEV_STATE_DONGLE_RESET:
- //printk("mcp2120_reset: dongle_reset\n");
- /* Reset dongle by setting RTS*/
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
- state = MCP2120_STATE_WAIT1_RESET;
- delay = 50;
- break;
-
- case MCP2120_STATE_WAIT1_RESET:
- //printk("mcp2120_reset: mcp2120_wait1\n");
- /* clear RTS and wait for at least 30 ms. */
- sirdev_set_dtr_rts(dev, FALSE, FALSE);
- state = MCP2120_STATE_WAIT2_RESET;
- delay = 50;
- break;
-
- case MCP2120_STATE_WAIT2_RESET:
- //printk("mcp2120_reset mcp2120_wait2\n");
- /* Go back to normal mode */
- sirdev_set_dtr_rts(dev, FALSE, FALSE);
- break;
-
- default:
- net_err_ratelimited("%s(), undefined state %d\n",
- __func__, state);
- ret = -EINVAL;
- break;
- }
- dev->fsm.substate = state;
- return (delay > 0) ? delay : ret;
-}
-
-MODULE_AUTHOR("Felix Tang <tangf@eyetap.org>");
-MODULE_DESCRIPTION("Microchip MCP2120");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-9"); /* IRDA_MCP2120_DONGLE */
-
-module_init(mcp2120_sir_init);
-module_exit(mcp2120_sir_cleanup);
diff --git a/drivers/staging/irda/drivers/mcs7780.c b/drivers/staging/irda/drivers/mcs7780.c
deleted file mode 100644
index d52e9f4b9770..000000000000
--- a/drivers/staging/irda/drivers/mcs7780.c
+++ /dev/null
@@ -1,990 +0,0 @@
-/*****************************************************************************
-*
-* Filename: mcs7780.c
-* Version: 0.4-alpha
-* Description: Irda MosChip USB Dongle Driver
-* Authors: Lukasz Stelmach <stlman@poczta.fm>
-* Brian Pugh <bpugh@cs.pdx.edu>
-* Judy Fischbach <jfisch@cs.pdx.edu>
-*
-* Based on stir4200 driver, but some things done differently.
-* Based on earlier driver by Paul Stewart <stewart@parc.com>
-*
-* Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at>
-* Copyright (C) 2001, Dag Brattli <dag@brattli.net>
-* Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com>
-* Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org>
-* Copyright (C) 2005, Lukasz Stelmach <stlman@poczta.fm>
-* Copyright (C) 2005, Brian Pugh <bpugh@cs.pdx.edu>
-* Copyright (C) 2005, Judy Fischbach <jfisch@cs.pdx.edu>
-*
-* 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.
-*
-* 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.
-*
-*****************************************************************************/
-
-/*
- * MCS7780 is a simple USB to IrDA bridge by MosChip. It is neither
- * compatibile with irda-usb nor with stir4200. Although it is quite
- * similar to the later as far as general idea of operation is concerned.
- * That is it requires the software to do all the framing job at SIR speeds.
- * The hardware does take care of the framing at MIR and FIR speeds.
- * It supports all speeds from 2400 through 4Mbps
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/device.h>
-#include <linux/crc32.h>
-
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/crc.h>
-
-#include "mcs7780.h"
-
-#define MCS_VENDOR_ID 0x9710
-#define MCS_PRODUCT_ID 0x7780
-
-static const struct usb_device_id mcs_table[] = {
- /* MosChip Corp., MCS7780 FIR-USB Adapter */
- {USB_DEVICE(MCS_VENDOR_ID, MCS_PRODUCT_ID)},
- {},
-};
-
-MODULE_AUTHOR("Brian Pugh <bpugh@cs.pdx.edu>");
-MODULE_DESCRIPTION("IrDA-USB Dongle Driver for MosChip MCS7780");
-MODULE_VERSION("0.3alpha");
-MODULE_LICENSE("GPL");
-
-MODULE_DEVICE_TABLE(usb, mcs_table);
-
-static int qos_mtt_bits = 0x07 /* > 1ms */ ;
-module_param(qos_mtt_bits, int, 0);
-MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
-
-static int receive_mode = 0x1;
-module_param(receive_mode, int, 0);
-MODULE_PARM_DESC(receive_mode,
- "Receive mode of the device (1:fast, 0:slow, default:1)");
-
-static int sir_tweak = 1;
-module_param(sir_tweak, int, 0444);
-MODULE_PARM_DESC(sir_tweak,
- "Default pulse width (1:1.6us, 0:3/16 bit, default:1).");
-
-static int transceiver_type = MCS_TSC_VISHAY;
-module_param(transceiver_type, int, 0444);
-MODULE_PARM_DESC(transceiver_type, "IR transceiver type, see mcs7780.h.");
-
-static struct usb_driver mcs_driver = {
- .name = "mcs7780",
- .probe = mcs_probe,
- .disconnect = mcs_disconnect,
- .id_table = mcs_table,
-};
-
-/* speed flag selection by direct addressing.
-addr = (speed >> 8) & 0x0f
-
-0x1 57600 0x2 115200 0x4 1152000 0x5 9600
-0x6 38400 0x9 2400 0xa 576000 0xb 19200
-
-4Mbps (or 2400) must be checked separately. Since it also has
-to be programmed in a different manner that is not a big problem.
-*/
-static __u16 mcs_speed_set[16] = { 0,
- MCS_SPEED_57600,
- MCS_SPEED_115200,
- 0,
- MCS_SPEED_1152000,
- MCS_SPEED_9600,
- MCS_SPEED_38400,
- 0, 0,
- MCS_SPEED_2400,
- MCS_SPEED_576000,
- MCS_SPEED_19200,
- 0, 0, 0,
-};
-
-/* Set given 16 bit register with a 16 bit value. Send control message
- * to set dongle register. */
-static int mcs_set_reg(struct mcs_cb *mcs, __u16 reg, __u16 val)
-{
- struct usb_device *dev = mcs->usbdev;
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
- MCS_WR_RTYPE, val, reg, NULL, 0,
- msecs_to_jiffies(MCS_CTRL_TIMEOUT));
-}
-
-/* Get 16 bit register value. Send contol message to read dongle register. */
-static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val)
-{
- struct usb_device *dev = mcs->usbdev;
- void *dmabuf;
- int ret;
-
- dmabuf = kmalloc(sizeof(__u16), GFP_KERNEL);
- if (!dmabuf)
- return -ENOMEM;
-
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
- MCS_RD_RTYPE, 0, reg, dmabuf, 2,
- msecs_to_jiffies(MCS_CTRL_TIMEOUT));
-
- memcpy(val, dmabuf, sizeof(__u16));
- kfree(dmabuf);
-
- return ret;
-}
-
-/* Setup a communication between mcs7780 and TFDU chips. It is described
- * in more detail in the data sheet. The setup sequence puts the the
- * vishay tranceiver into high speed mode. It will also receive SIR speed
- * packets but at reduced sensitivity.
- */
-
-/* 0: OK 1:ERROR */
-static inline int mcs_setup_transceiver_vishay(struct mcs_cb *mcs)
-{
- int ret = 0;
- __u16 rval;
-
- /* mcs_get_reg should read exactly two bytes from the dongle */
- ret = mcs_get_reg(mcs, MCS_XCVR_REG, &rval);
- if (unlikely(ret != 2)) {
- ret = -EIO;
- goto error;
- }
-
- /* The MCS_XCVR_CONF bit puts the transceiver into configuration
- * mode. The MCS_MODE0 bit must start out high (1) and then
- * transition to low and the MCS_STFIR and MCS_MODE1 bits must
- * be low.
- */
- rval |= (MCS_MODE0 | MCS_XCVR_CONF);
- rval &= ~MCS_STFIR;
- rval &= ~MCS_MODE1;
- ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval);
- if (unlikely(ret))
- goto error;
-
- rval &= ~MCS_MODE0;
- ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval);
- if (unlikely(ret))
- goto error;
-
- rval &= ~MCS_XCVR_CONF;
- ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval);
- if (unlikely(ret))
- goto error;
-
- ret = 0;
-error:
- return ret;
-}
-
-/* Setup a communication between mcs7780 and agilent chip. */
-static inline int mcs_setup_transceiver_agilent(struct mcs_cb *mcs)
-{
- net_warn_ratelimited("This transceiver type is not supported yet\n");
- return 1;
-}
-
-/* Setup a communication between mcs7780 and sharp chip. */
-static inline int mcs_setup_transceiver_sharp(struct mcs_cb *mcs)
-{
- net_warn_ratelimited("This transceiver type is not supported yet\n");
- return 1;
-}
-
-/* Common setup for all transceivers */
-static inline int mcs_setup_transceiver(struct mcs_cb *mcs)
-{
- int ret = 0;
- __u16 rval;
- const char *msg;
-
- msg = "Basic transceiver setup error";
-
- /* read value of MODE Register, set the DRIVER and RESET bits
- * and write value back out to MODE Register
- */
- ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval);
- if(unlikely(ret != 2))
- goto error;
- rval |= MCS_DRIVER; /* put the mcs7780 into configuration mode. */
- ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
- if(unlikely(ret))
- goto error;
-
- rval = 0; /* set min pulse width to 0 initially. */
- ret = mcs_set_reg(mcs, MCS_MINRXPW_REG, rval);
- if(unlikely(ret))
- goto error;
-
- ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval);
- if(unlikely(ret != 2))
- goto error;
-
- rval &= ~MCS_FIR; /* turn off fir mode. */
- if(mcs->sir_tweak)
- rval |= MCS_SIR16US; /* 1.6us pulse width */
- else
- rval &= ~MCS_SIR16US; /* 3/16 bit time pulse width */
-
- /* make sure ask mode and back to back packets are off. */
- rval &= ~(MCS_BBTG | MCS_ASK);
-
- rval &= ~MCS_SPEED_MASK;
- rval |= MCS_SPEED_9600; /* make sure initial speed is 9600. */
- mcs->speed = 9600;
- mcs->new_speed = 0; /* new_speed is set to 0 */
- rval &= ~MCS_PLLPWDN; /* disable power down. */
-
- /* make sure device determines direction and that the auto send sip
- * pulse are on.
- */
- rval |= MCS_DTD | MCS_SIPEN;
-
- ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
- if(unlikely(ret))
- goto error;
-
- msg = "transceiver model specific setup error";
- switch (mcs->transceiver_type) {
- case MCS_TSC_VISHAY:
- ret = mcs_setup_transceiver_vishay(mcs);
- break;
-
- case MCS_TSC_SHARP:
- ret = mcs_setup_transceiver_sharp(mcs);
- break;
-
- case MCS_TSC_AGILENT:
- ret = mcs_setup_transceiver_agilent(mcs);
- break;
-
- default:
- net_warn_ratelimited("Unknown transceiver type: %d\n",
- mcs->transceiver_type);
- ret = 1;
- }
- if (unlikely(ret))
- goto error;
-
- /* If transceiver is not SHARP, then if receive mode set
- * on the RXFAST bit in the XCVR Register otherwise unset it
- */
- if (mcs->transceiver_type != MCS_TSC_SHARP) {
-
- ret = mcs_get_reg(mcs, MCS_XCVR_REG, &rval);
- if (unlikely(ret != 2))
- goto error;
- if (mcs->receive_mode)
- rval |= MCS_RXFAST;
- else
- rval &= ~MCS_RXFAST;
- ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval);
- if (unlikely(ret))
- goto error;
- }
-
- msg = "transceiver reset";
-
- ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval);
- if (unlikely(ret != 2))
- goto error;
-
- /* reset the mcs7780 so all changes take effect. */
- rval &= ~MCS_RESET;
- ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
- if (unlikely(ret))
- goto error;
- else
- return ret;
-
-error:
- net_err_ratelimited("%s\n", msg);
- return ret;
-}
-
-/* Wraps the data in format for SIR */
-static inline int mcs_wrap_sir_skb(struct sk_buff *skb, __u8 * buf)
-{
- int wraplen;
-
- /* 2: full frame length, including "the length" */
- wraplen = async_wrap_skb(skb, buf + 2, 4094);
-
- wraplen += 2;
- buf[0] = wraplen & 0xff;
- buf[1] = (wraplen >> 8) & 0xff;
-
- return wraplen;
-}
-
-/* Wraps the data in format for FIR */
-static unsigned mcs_wrap_fir_skb(const struct sk_buff *skb, __u8 *buf)
-{
- unsigned int len = 0;
- __u32 fcs = ~(crc32_le(~0, skb->data, skb->len));
-
- /* add 2 bytes for length value and 4 bytes for fcs. */
- len = skb->len + 6;
-
- /* The mcs7780 requires that the first two bytes are the packet
- * length in little endian order. Note: the length value includes
- * the two bytes for the length value itself.
- */
- buf[0] = len & 0xff;
- buf[1] = (len >> 8) & 0xff;
- /* copy the data into the tx buffer. */
- skb_copy_from_linear_data(skb, buf + 2, skb->len);
- /* put the fcs in the last four bytes in little endian order. */
- buf[len - 4] = fcs & 0xff;
- buf[len - 3] = (fcs >> 8) & 0xff;
- buf[len - 2] = (fcs >> 16) & 0xff;
- buf[len - 1] = (fcs >> 24) & 0xff;
-
- return len;
-}
-
-/* Wraps the data in format for MIR */
-static unsigned mcs_wrap_mir_skb(const struct sk_buff *skb, __u8 *buf)
-{
- __u16 fcs = 0;
- int len = skb->len + 4;
-
- fcs = ~(irda_calc_crc16(~fcs, skb->data, skb->len));
- /* put the total packet length in first. Note: packet length
- * value includes the two bytes that hold the packet length
- * itself.
- */
- buf[0] = len & 0xff;
- buf[1] = (len >> 8) & 0xff;
- /* copy the data */
- skb_copy_from_linear_data(skb, buf + 2, skb->len);
- /* put the fcs in last two bytes in little endian order. */
- buf[len - 2] = fcs & 0xff;
- buf[len - 1] = (fcs >> 8) & 0xff;
-
- return len;
-}
-
-/* Unwrap received packets at MIR speed. A 16 bit crc_ccitt checksum is
- * used for the fcs. When performed over the entire packet the result
- * should be GOOD_FCS = 0xf0b8. Hands the unwrapped data off to the IrDA
- * layer via a sk_buff.
- */
-static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len)
-{
- __u16 fcs;
- int new_len;
- struct sk_buff *skb;
-
- /* Assume that the frames are going to fill a single packet
- * rather than span multiple packets.
- */
-
- new_len = len - 2;
- if(unlikely(new_len <= 0)) {
- net_err_ratelimited("%s short frame length %d\n",
- mcs->netdev->name, new_len);
- ++mcs->netdev->stats.rx_errors;
- ++mcs->netdev->stats.rx_length_errors;
- return;
- }
- fcs = 0;
- fcs = irda_calc_crc16(~fcs, buf, len);
-
- if(fcs != GOOD_FCS) {
- net_err_ratelimited("crc error calc 0x%x len %d\n",
- fcs, new_len);
- mcs->netdev->stats.rx_errors++;
- mcs->netdev->stats.rx_crc_errors++;
- return;
- }
-
- skb = dev_alloc_skb(new_len + 1);
- if(unlikely(!skb)) {
- ++mcs->netdev->stats.rx_dropped;
- return;
- }
-
- skb_reserve(skb, 1);
- skb_copy_to_linear_data(skb, buf, new_len);
- skb_put(skb, new_len);
- skb_reset_mac_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- skb->dev = mcs->netdev;
-
- netif_rx(skb);
-
- mcs->netdev->stats.rx_packets++;
- mcs->netdev->stats.rx_bytes += new_len;
-}
-
-/* Unwrap received packets at FIR speed. A 32 bit crc_ccitt checksum is
- * used for the fcs. Hands the unwrapped data off to the IrDA
- * layer via a sk_buff.
- */
-static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len)
-{
- __u32 fcs;
- int new_len;
- struct sk_buff *skb;
-
- /* Assume that the frames are going to fill a single packet
- * rather than span multiple packets. This is most likely a false
- * assumption.
- */
-
- new_len = len - 4;
- if(unlikely(new_len <= 0)) {
- net_err_ratelimited("%s short frame length %d\n",
- mcs->netdev->name, new_len);
- ++mcs->netdev->stats.rx_errors;
- ++mcs->netdev->stats.rx_length_errors;
- return;
- }
-
- fcs = ~(crc32_le(~0, buf, new_len));
- if(fcs != get_unaligned_le32(buf + new_len)) {
- net_err_ratelimited("crc error calc 0x%x len %d\n",
- fcs, new_len);
- mcs->netdev->stats.rx_errors++;
- mcs->netdev->stats.rx_crc_errors++;
- return;
- }
-
- skb = dev_alloc_skb(new_len + 1);
- if(unlikely(!skb)) {
- ++mcs->netdev->stats.rx_dropped;
- return;
- }
-
- skb_reserve(skb, 1);
- skb_copy_to_linear_data(skb, buf, new_len);
- skb_put(skb, new_len);
- skb_reset_mac_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- skb->dev = mcs->netdev;
-
- netif_rx(skb);
-
- mcs->netdev->stats.rx_packets++;
- mcs->netdev->stats.rx_bytes += new_len;
-}
-
-
-/* Allocates urbs for both receive and transmit.
- * If alloc fails return error code 0 (fail) otherwise
- * return error code 1 (success).
- */
-static inline int mcs_setup_urbs(struct mcs_cb *mcs)
-{
- mcs->rx_urb = NULL;
-
- mcs->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!mcs->tx_urb)
- return 0;
-
- mcs->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!mcs->rx_urb) {
- usb_free_urb(mcs->tx_urb);
- mcs->tx_urb = NULL;
- return 0;
- }
-
- return 1;
-}
-
-/* Sets up state to be initially outside frame, gets receive urb,
- * sets status to successful and then submits the urb to start
- * receiving the data.
- */
-static inline int mcs_receive_start(struct mcs_cb *mcs)
-{
- mcs->rx_buff.in_frame = FALSE;
- mcs->rx_buff.state = OUTSIDE_FRAME;
-
- usb_fill_bulk_urb(mcs->rx_urb, mcs->usbdev,
- usb_rcvbulkpipe(mcs->usbdev, mcs->ep_in),
- mcs->in_buf, 4096, mcs_receive_irq, mcs);
-
- mcs->rx_urb->status = 0;
- return usb_submit_urb(mcs->rx_urb, GFP_KERNEL);
-}
-
-/* Finds the in and out endpoints for the mcs control block */
-static inline int mcs_find_endpoints(struct mcs_cb *mcs,
- struct usb_host_endpoint *ep, int epnum)
-{
- int i;
- int ret = 0;
-
- /* If no place to store the endpoints just return */
- if (!ep)
- return ret;
-
- /* cycle through all endpoints, find the first two that are DIR_IN */
- for (i = 0; i < epnum; i++) {
- if (ep[i].desc.bEndpointAddress & USB_DIR_IN)
- mcs->ep_in = ep[i].desc.bEndpointAddress;
- else
- mcs->ep_out = ep[i].desc.bEndpointAddress;
-
- /* MosChip says that the chip has only two bulk
- * endpoints. Find one for each direction and move on.
- */
- if ((mcs->ep_in != 0) && (mcs->ep_out != 0)) {
- ret = 1;
- break;
- }
- }
-
- return ret;
-}
-
-static void mcs_speed_work(struct work_struct *work)
-{
- struct mcs_cb *mcs = container_of(work, struct mcs_cb, work);
- struct net_device *netdev = mcs->netdev;
-
- mcs_speed_change(mcs);
- netif_wake_queue(netdev);
-}
-
-/* Function to change the speed of the mcs7780. Fully supports SIR,
- * MIR, and FIR speeds.
- */
-static int mcs_speed_change(struct mcs_cb *mcs)
-{
- int ret = 0;
- int rst = 0;
- int cnt = 0;
- __u16 nspeed;
- __u16 rval;
-
- nspeed = mcs_speed_set[(mcs->new_speed >> 8) & 0x0f];
-
- do {
- mcs_get_reg(mcs, MCS_RESV_REG, &rval);
- } while(cnt++ < 100 && (rval & MCS_IRINTX));
-
- if (cnt > 100) {
- net_err_ratelimited("unable to change speed\n");
- ret = -EIO;
- goto error;
- }
-
- mcs_get_reg(mcs, MCS_MODE_REG, &rval);
-
- /* MINRXPW values recommended by MosChip */
- if (mcs->new_speed <= 115200) {
- rval &= ~MCS_FIR;
-
- rst = mcs->speed > 115200;
- if (rst)
- mcs_set_reg(mcs, MCS_MINRXPW_REG, 0);
-
- } else if (mcs->new_speed <= 1152000) {
- rval &= ~MCS_FIR;
-
- rst = !(mcs->speed == 576000 || mcs->speed == 1152000);
- if (rst)
- mcs_set_reg(mcs, MCS_MINRXPW_REG, 5);
-
- } else {
- rval |= MCS_FIR;
-
- rst = mcs->speed != 4000000;
- if (rst)
- mcs_set_reg(mcs, MCS_MINRXPW_REG, 5);
-
- }
-
- rval &= ~MCS_SPEED_MASK;
- rval |= nspeed;
-
- ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
- if (unlikely(ret))
- goto error;
-
- if (rst)
- switch (mcs->transceiver_type) {
- case MCS_TSC_VISHAY:
- ret = mcs_setup_transceiver_vishay(mcs);
- break;
-
- case MCS_TSC_SHARP:
- ret = mcs_setup_transceiver_sharp(mcs);
- break;
-
- case MCS_TSC_AGILENT:
- ret = mcs_setup_transceiver_agilent(mcs);
- break;
-
- default:
- ret = 1;
- net_warn_ratelimited("Unknown transceiver type: %d\n",
- mcs->transceiver_type);
- }
- if (unlikely(ret))
- goto error;
-
- mcs_get_reg(mcs, MCS_MODE_REG, &rval);
- rval &= ~MCS_RESET;
- ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
-
- mcs->speed = mcs->new_speed;
-error:
- mcs->new_speed = 0;
- return ret;
-}
-
-/* Ioctl calls not supported at this time. Can be an area of future work. */
-static int mcs_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
-{
- /* struct if_irda_req *irq = (struct if_irda_req *)rq; */
- /* struct mcs_cb *mcs = netdev_priv(netdev); */
- int ret = 0;
-
- switch (cmd) {
- default:
- ret = -EOPNOTSUPP;
- }
-
- return ret;
-}
-
-/* Network device is taken down, done by "ifconfig irda0 down" */
-static int mcs_net_close(struct net_device *netdev)
-{
- int ret = 0;
- struct mcs_cb *mcs = netdev_priv(netdev);
-
- /* Stop transmit processing */
- netif_stop_queue(netdev);
-
- kfree_skb(mcs->rx_buff.skb);
-
- /* kill and free the receive and transmit URBs */
- usb_kill_urb(mcs->rx_urb);
- usb_free_urb(mcs->rx_urb);
- usb_kill_urb(mcs->tx_urb);
- usb_free_urb(mcs->tx_urb);
-
- /* Stop and remove instance of IrLAP */
- if (mcs->irlap)
- irlap_close(mcs->irlap);
-
- mcs->irlap = NULL;
- return ret;
-}
-
-/* Network device is taken up, done by "ifconfig irda0 up" */
-static int mcs_net_open(struct net_device *netdev)
-{
- struct mcs_cb *mcs = netdev_priv(netdev);
- char hwname[16];
- int ret = 0;
-
- ret = usb_clear_halt(mcs->usbdev,
- usb_sndbulkpipe(mcs->usbdev, mcs->ep_in));
- if (ret)
- goto error1;
- ret = usb_clear_halt(mcs->usbdev,
- usb_rcvbulkpipe(mcs->usbdev, mcs->ep_out));
- if (ret)
- goto error1;
-
- ret = mcs_setup_transceiver(mcs);
- if (ret)
- goto error1;
-
- ret = -ENOMEM;
-
- /* Initialize for SIR/FIR to copy data directly into skb. */
- mcs->receiving = 0;
- mcs->rx_buff.truesize = IRDA_SKB_MAX_MTU;
- mcs->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
- if (!mcs->rx_buff.skb)
- goto error1;
-
- skb_reserve(mcs->rx_buff.skb, 1);
- mcs->rx_buff.head = mcs->rx_buff.skb->data;
-
- /*
- * Now that everything should be initialized properly,
- * Open new IrLAP layer instance to take care of us...
- * Note : will send immediately a speed change...
- */
- sprintf(hwname, "usb#%d", mcs->usbdev->devnum);
- mcs->irlap = irlap_open(netdev, &mcs->qos, hwname);
- if (!mcs->irlap) {
- net_err_ratelimited("mcs7780: irlap_open failed\n");
- goto error2;
- }
-
- if (!mcs_setup_urbs(mcs))
- goto error3;
-
- ret = mcs_receive_start(mcs);
- if (ret)
- goto error4;
-
- netif_start_queue(netdev);
- return 0;
-
-error4:
- usb_free_urb(mcs->rx_urb);
- usb_free_urb(mcs->tx_urb);
-error3:
- irlap_close(mcs->irlap);
-error2:
- kfree_skb(mcs->rx_buff.skb);
-error1:
- return ret;
-}
-
-/* Receive callback function. */
-static void mcs_receive_irq(struct urb *urb)
-{
- __u8 *bytes;
- struct mcs_cb *mcs = urb->context;
- int i;
- int ret;
-
- if (!netif_running(mcs->netdev))
- return;
-
- if (urb->status)
- return;
-
- if (urb->actual_length > 0) {
- bytes = urb->transfer_buffer;
-
- /* MCS returns frames without BOF and EOF
- * I assume it returns whole frames.
- */
- /* SIR speed */
- if(mcs->speed < 576000) {
- async_unwrap_char(mcs->netdev, &mcs->netdev->stats,
- &mcs->rx_buff, 0xc0);
-
- for (i = 0; i < urb->actual_length; i++)
- async_unwrap_char(mcs->netdev, &mcs->netdev->stats,
- &mcs->rx_buff, bytes[i]);
-
- async_unwrap_char(mcs->netdev, &mcs->netdev->stats,
- &mcs->rx_buff, 0xc1);
- }
- /* MIR speed */
- else if(mcs->speed == 576000 || mcs->speed == 1152000) {
- mcs_unwrap_mir(mcs, urb->transfer_buffer,
- urb->actual_length);
- }
- /* FIR speed */
- else {
- mcs_unwrap_fir(mcs, urb->transfer_buffer,
- urb->actual_length);
- }
- }
-
- ret = usb_submit_urb(urb, GFP_ATOMIC);
-}
-
-/* Transmit callback function. */
-static void mcs_send_irq(struct urb *urb)
-{
- struct mcs_cb *mcs = urb->context;
- struct net_device *ndev = mcs->netdev;
-
- if (unlikely(mcs->new_speed))
- schedule_work(&mcs->work);
- else
- netif_wake_queue(ndev);
-}
-
-/* Transmit callback function. */
-static netdev_tx_t mcs_hard_xmit(struct sk_buff *skb,
- struct net_device *ndev)
-{
- unsigned long flags;
- struct mcs_cb *mcs;
- int wraplen;
- int ret = 0;
-
- netif_stop_queue(ndev);
- mcs = netdev_priv(ndev);
-
- spin_lock_irqsave(&mcs->lock, flags);
-
- mcs->new_speed = irda_get_next_speed(skb);
- if (likely(mcs->new_speed == mcs->speed))
- mcs->new_speed = 0;
-
- /* SIR speed */
- if(mcs->speed < 576000) {
- wraplen = mcs_wrap_sir_skb(skb, mcs->out_buf);
- }
- /* MIR speed */
- else if(mcs->speed == 576000 || mcs->speed == 1152000) {
- wraplen = mcs_wrap_mir_skb(skb, mcs->out_buf);
- }
- /* FIR speed */
- else {
- wraplen = mcs_wrap_fir_skb(skb, mcs->out_buf);
- }
- usb_fill_bulk_urb(mcs->tx_urb, mcs->usbdev,
- usb_sndbulkpipe(mcs->usbdev, mcs->ep_out),
- mcs->out_buf, wraplen, mcs_send_irq, mcs);
-
- if ((ret = usb_submit_urb(mcs->tx_urb, GFP_ATOMIC))) {
- net_err_ratelimited("failed tx_urb: %d\n", ret);
- switch (ret) {
- case -ENODEV:
- case -EPIPE:
- break;
- default:
- mcs->netdev->stats.tx_errors++;
- netif_start_queue(ndev);
- }
- } else {
- mcs->netdev->stats.tx_packets++;
- mcs->netdev->stats.tx_bytes += skb->len;
- }
-
- dev_kfree_skb(skb);
- spin_unlock_irqrestore(&mcs->lock, flags);
- return NETDEV_TX_OK;
-}
-
-static const struct net_device_ops mcs_netdev_ops = {
- .ndo_open = mcs_net_open,
- .ndo_stop = mcs_net_close,
- .ndo_start_xmit = mcs_hard_xmit,
- .ndo_do_ioctl = mcs_net_ioctl,
-};
-
-/*
- * This function is called by the USB subsystem for each new device in the
- * system. Need to verify the device and if it is, then start handling it.
- */
-static int mcs_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct net_device *ndev = NULL;
- struct mcs_cb *mcs;
- int ret = -ENOMEM;
-
- ndev = alloc_irdadev(sizeof(*mcs));
- if (!ndev)
- goto error1;
-
- pr_debug("MCS7780 USB-IrDA bridge found at %d.\n", udev->devnum);
-
- SET_NETDEV_DEV(ndev, &intf->dev);
-
- ret = usb_reset_configuration(udev);
- if (ret != 0) {
- net_err_ratelimited("mcs7780: usb reset configuration failed\n");
- goto error2;
- }
-
- mcs = netdev_priv(ndev);
- mcs->usbdev = udev;
- mcs->netdev = ndev;
- spin_lock_init(&mcs->lock);
-
- /* Initialize QoS for this device */
- irda_init_max_qos_capabilies(&mcs->qos);
-
- /* That's the Rx capability. */
- mcs->qos.baud_rate.bits &=
- IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200
- | IR_576000 | IR_1152000 | (IR_4000000 << 8);
-
-
- mcs->qos.min_turn_time.bits &= qos_mtt_bits;
- irda_qos_bits_to_value(&mcs->qos);
-
- /* Speed change work initialisation*/
- INIT_WORK(&mcs->work, mcs_speed_work);
-
- ndev->netdev_ops = &mcs_netdev_ops;
-
- if (!intf->cur_altsetting) {
- ret = -ENOMEM;
- goto error2;
- }
-
- ret = mcs_find_endpoints(mcs, intf->cur_altsetting->endpoint,
- intf->cur_altsetting->desc.bNumEndpoints);
- if (!ret) {
- ret = -ENODEV;
- goto error2;
- }
-
- ret = register_netdev(ndev);
- if (ret != 0)
- goto error2;
-
- pr_debug("IrDA: Registered MosChip MCS7780 device as %s\n",
- ndev->name);
-
- mcs->transceiver_type = transceiver_type;
- mcs->sir_tweak = sir_tweak;
- mcs->receive_mode = receive_mode;
-
- usb_set_intfdata(intf, mcs);
- return 0;
-
-error2:
- free_netdev(ndev);
-
-error1:
- return ret;
-}
-
-/* The current device is removed, the USB layer tells us to shut down. */
-static void mcs_disconnect(struct usb_interface *intf)
-{
- struct mcs_cb *mcs = usb_get_intfdata(intf);
-
- if (!mcs)
- return;
-
- cancel_work_sync(&mcs->work);
-
- unregister_netdev(mcs->netdev);
- free_netdev(mcs->netdev);
-
- usb_set_intfdata(intf, NULL);
- pr_debug("MCS7780 now disconnected.\n");
-}
-
-module_usb_driver(mcs_driver);
diff --git a/drivers/staging/irda/drivers/mcs7780.h b/drivers/staging/irda/drivers/mcs7780.h
deleted file mode 100644
index a6e8f7dbafc9..000000000000
--- a/drivers/staging/irda/drivers/mcs7780.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*****************************************************************************
-*
-* Filename: mcs7780.h
-* Version: 0.2-alpha
-* Description: Irda MosChip USB Dongle
-* Status: Experimental
-* Authors: Lukasz Stelmach <stlman@poczta.fm>
-* Brian Pugh <bpugh@cs.pdx.edu>
-*
-* Copyright (C) 2005, Lukasz Stelmach <stlman@poczta.fm>
-* Copyright (C) 2005, Brian Pugh <bpugh@cs.pdx.edu>
-*
-* 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.
-*
-* 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.
-*
-*****************************************************************************/
-#ifndef _MCS7780_H
-#define _MCS7780_H
-
-#define MCS_MODE_SIR 0
-#define MCS_MODE_MIR 1
-#define MCS_MODE_FIR 2
-
-#define MCS_CTRL_TIMEOUT 500
-#define MCS_XMIT_TIMEOUT 500
-/* Possible transceiver types */
-#define MCS_TSC_VISHAY 0 /* Vishay TFD, default choice */
-#define MCS_TSC_AGILENT 1 /* Agilent 3602/3600 */
-#define MCS_TSC_SHARP 2 /* Sharp GP2W1000YP */
-
-/* Requests */
-#define MCS_RD_RTYPE 0xC0
-#define MCS_WR_RTYPE 0x40
-#define MCS_RDREQ 0x0F
-#define MCS_WRREQ 0x0E
-
-/* Register 0x00 */
-#define MCS_MODE_REG 0
-#define MCS_FIR ((__u16)0x0001)
-#define MCS_SIR16US ((__u16)0x0002)
-#define MCS_BBTG ((__u16)0x0004)
-#define MCS_ASK ((__u16)0x0008)
-#define MCS_PARITY ((__u16)0x0010)
-
-/* SIR/MIR speed constants */
-#define MCS_SPEED_SHIFT 5
-#define MCS_SPEED_MASK ((__u16)0x00E0)
-#define MCS_SPEED(x) ((x & MCS_SPEED_MASK) >> MCS_SPEED_SHIFT)
-#define MCS_SPEED_2400 ((0 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
-#define MCS_SPEED_9600 ((1 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
-#define MCS_SPEED_19200 ((2 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
-#define MCS_SPEED_38400 ((3 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
-#define MCS_SPEED_57600 ((4 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
-#define MCS_SPEED_115200 ((5 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
-#define MCS_SPEED_576000 ((6 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
-#define MCS_SPEED_1152000 ((7 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
-
-#define MCS_PLLPWDN ((__u16)0x0100)
-#define MCS_DRIVER ((__u16)0x0200)
-#define MCS_DTD ((__u16)0x0400)
-#define MCS_DIR ((__u16)0x0800)
-#define MCS_SIPEN ((__u16)0x1000)
-#define MCS_SENDSIP ((__u16)0x2000)
-#define MCS_CHGDIR ((__u16)0x4000)
-#define MCS_RESET ((__u16)0x8000)
-
-/* Register 0x02 */
-#define MCS_XCVR_REG 2
-#define MCS_MODE0 ((__u16)0x0001)
-#define MCS_STFIR ((__u16)0x0002)
-#define MCS_XCVR_CONF ((__u16)0x0004)
-#define MCS_RXFAST ((__u16)0x0008)
-/* TXCUR [6:4] */
-#define MCS_TXCUR_SHIFT 4
-#define MCS_TXCUR_MASK ((__u16)0x0070)
-#define MCS_TXCUR(x) ((x & MCS_TXCUR_MASK) >> MCS_TXCUR_SHIFT)
-#define MCS_SETTXCUR(x,y) \
- ((x & ~MCS_TXCUR_MASK) | (y << MCS_TXCUR_SHIFT) & MCS_TXCUR_MASK)
-
-#define MCS_MODE1 ((__u16)0x0080)
-#define MCS_SMODE0 ((__u16)0x0100)
-#define MCS_SMODE1 ((__u16)0x0200)
-#define MCS_INVTX ((__u16)0x0400)
-#define MCS_INVRX ((__u16)0x0800)
-
-#define MCS_MINRXPW_REG 4
-
-#define MCS_RESV_REG 7
-#define MCS_IRINTX ((__u16)0x0001)
-#define MCS_IRINRX ((__u16)0x0002)
-
-struct mcs_cb {
- struct usb_device *usbdev; /* init: probe_irda */
- struct net_device *netdev; /* network layer */
- struct irlap_cb *irlap; /* The link layer we are binded to */
- struct qos_info qos;
- unsigned int speed; /* Current speed */
- unsigned int new_speed; /* new speed */
-
- struct work_struct work; /* Change speed work */
-
- struct sk_buff *tx_pending;
- char in_buf[4096]; /* transmit/receive buffer */
- char out_buf[4096]; /* transmit/receive buffer */
- __u8 *fifo_status;
-
- iobuff_t rx_buff; /* receive unwrap state machine */
- spinlock_t lock;
- int receiving;
-
- __u8 ep_in;
- __u8 ep_out;
-
- struct urb *rx_urb;
- struct urb *tx_urb;
-
- int transceiver_type;
- int sir_tweak;
- int receive_mode;
-};
-
-static int mcs_set_reg(struct mcs_cb *mcs, __u16 reg, __u16 val);
-static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val);
-
-static inline int mcs_setup_transceiver_vishay(struct mcs_cb *mcs);
-static inline int mcs_setup_transceiver_agilent(struct mcs_cb *mcs);
-static inline int mcs_setup_transceiver_sharp(struct mcs_cb *mcs);
-static inline int mcs_setup_transceiver(struct mcs_cb *mcs);
-static inline int mcs_wrap_sir_skb(struct sk_buff *skb, __u8 * buf);
-static unsigned mcs_wrap_fir_skb(const struct sk_buff *skb, __u8 *buf);
-static unsigned mcs_wrap_mir_skb(const struct sk_buff *skb, __u8 *buf);
-static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len);
-static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len);
-static inline int mcs_setup_urbs(struct mcs_cb *mcs);
-static inline int mcs_receive_start(struct mcs_cb *mcs);
-static inline int mcs_find_endpoints(struct mcs_cb *mcs,
- struct usb_host_endpoint *ep, int epnum);
-
-static int mcs_speed_change(struct mcs_cb *mcs);
-
-static int mcs_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd);
-static int mcs_net_close(struct net_device *netdev);
-static int mcs_net_open(struct net_device *netdev);
-
-static void mcs_receive_irq(struct urb *urb);
-static void mcs_send_irq(struct urb *urb);
-static netdev_tx_t mcs_hard_xmit(struct sk_buff *skb,
- struct net_device *netdev);
-
-static int mcs_probe(struct usb_interface *intf,
- const struct usb_device_id *id);
-static void mcs_disconnect(struct usb_interface *intf);
-
-#endif /* _MCS7780_H */
diff --git a/drivers/staging/irda/drivers/nsc-ircc.c b/drivers/staging/irda/drivers/nsc-ircc.c
deleted file mode 100644
index 7beae147be11..000000000000
--- a/drivers/staging/irda/drivers/nsc-ircc.c
+++ /dev/null
@@ -1,2410 +0,0 @@
-/*********************************************************************
- *
- * Filename: nsc-ircc.c
- * Version: 1.0
- * Description: Driver for the NSC PC'108 and PC'338 IrDA chipsets
- * Status: Stable.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sat Nov 7 21:43:15 1998
- * Modified at: Wed Mar 1 11:29:34 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
- * Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
- * Copyright (c) 1998 Actisys Corp., www.actisys.com
- * Copyright (c) 2000-2004 Jean Tourrilhes <jt@hpl.hp.com>
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- * Notice that all functions that needs to access the chip in _any_
- * way, must save BSR register on entry, and restore it on exit.
- * It is _very_ important to follow this policy!
- *
- * __u8 bank;
- *
- * bank = inb(iobase+BSR);
- *
- * do_your_stuff_here();
- *
- * outb(bank, iobase+BSR);
- *
- * If you find bugs in this file, its very likely that the same bug
- * will also be in w83977af_ir.c since the implementations are quite
- * similar.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/gfp.h>
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/rtnetlink.h>
-#include <linux/dma-mapping.h>
-#include <linux/pnp.h>
-#include <linux/platform_device.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-
-#include <net/irda/wrapper.h>
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-
-#include "nsc-ircc.h"
-
-#define CHIP_IO_EXTENT 8
-#define BROKEN_DONGLE_ID
-
-static char *driver_name = "nsc-ircc";
-
-/* Power Management */
-#define NSC_IRCC_DRIVER_NAME "nsc-ircc"
-static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state);
-static int nsc_ircc_resume(struct platform_device *dev);
-
-static struct platform_driver nsc_ircc_driver = {
- .suspend = nsc_ircc_suspend,
- .resume = nsc_ircc_resume,
- .driver = {
- .name = NSC_IRCC_DRIVER_NAME,
- },
-};
-
-/* Module parameters */
-static int qos_mtt_bits = 0x07; /* 1 ms or more */
-static int dongle_id;
-
-/* Use BIOS settions by default, but user may supply module parameters */
-static unsigned int io[] = { ~0, ~0, ~0, ~0, ~0 };
-static unsigned int irq[] = { 0, 0, 0, 0, 0 };
-static unsigned int dma[] = { 0, 0, 0, 0, 0 };
-
-static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info);
-static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info);
-static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info);
-static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info);
-static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info);
-static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info);
-#ifdef CONFIG_PNP
-static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id);
-#endif
-
-/* These are the known NSC chips */
-static nsc_chip_t chips[] = {
-/* Name, {cfg registers}, chip id index reg, chip id expected value, revision mask */
- { "PC87108", { 0x150, 0x398, 0xea }, 0x05, 0x10, 0xf0,
- nsc_ircc_probe_108, nsc_ircc_init_108 },
- { "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf8,
- nsc_ircc_probe_338, nsc_ircc_init_338 },
- /* Contributed by Steffen Pingel - IBM X40 */
- { "PC8738x", { 0x164e, 0x4e, 0x2e }, 0x20, 0xf4, 0xff,
- nsc_ircc_probe_39x, nsc_ircc_init_39x },
- /* Contributed by Jan Frey - IBM A30/A31 */
- { "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff,
- nsc_ircc_probe_39x, nsc_ircc_init_39x },
- /* IBM ThinkPads using PC8738x (T60/X60/Z60) */
- { "IBM-PC8738x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
- nsc_ircc_probe_39x, nsc_ircc_init_39x },
- /* IBM ThinkPads using PC8394T (T43/R52/?) */
- { "IBM-PC8394T", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf9, 0xff,
- nsc_ircc_probe_39x, nsc_ircc_init_39x },
- { NULL }
-};
-
-static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL };
-
-static char *dongle_types[] = {
- "Differential serial interface",
- "Differential serial interface",
- "Reserved",
- "Reserved",
- "Sharp RY5HD01",
- "Reserved",
- "Single-ended serial interface",
- "Consumer-IR only",
- "HP HSDL-2300, HP HSDL-3600/HSDL-3610",
- "IBM31T1100 or Temic TFDS6000/TFDS6500",
- "Reserved",
- "Reserved",
- "HP HSDL-1100/HSDL-2100",
- "HP HSDL-1100/HSDL-2100",
- "Supports SIR Mode only",
- "No dongle connected",
-};
-
-/* PNP probing */
-static chipio_t pnp_info;
-static const struct pnp_device_id nsc_ircc_pnp_table[] = {
- { .id = "NSC6001", .driver_data = 0 },
- { .id = "HWPC224", .driver_data = 0 },
- { .id = "IBM0071", .driver_data = NSC_FORCE_DONGLE_TYPE9 },
- { }
-};
-
-MODULE_DEVICE_TABLE(pnp, nsc_ircc_pnp_table);
-
-static struct pnp_driver nsc_ircc_pnp_driver = {
-#ifdef CONFIG_PNP
- .name = "nsc-ircc",
- .id_table = nsc_ircc_pnp_table,
- .probe = nsc_ircc_pnp_probe,
-#endif
-};
-
-/* Some prototypes */
-static int nsc_ircc_open(chipio_t *info);
-static int nsc_ircc_close(struct nsc_ircc_cb *self);
-static int nsc_ircc_setup(chipio_t *info);
-static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self);
-static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self);
-static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase);
-static netdev_tx_t nsc_ircc_hard_xmit_sir(struct sk_buff *skb,
- struct net_device *dev);
-static netdev_tx_t nsc_ircc_hard_xmit_fir(struct sk_buff *skb,
- struct net_device *dev);
-static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
-static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase);
-static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 baud);
-static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self);
-static int nsc_ircc_read_dongle_id (int iobase);
-static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id);
-
-static int nsc_ircc_net_open(struct net_device *dev);
-static int nsc_ircc_net_close(struct net_device *dev);
-static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-
-/* Globals */
-static int pnp_registered;
-static int pnp_succeeded;
-
-/*
- * Function nsc_ircc_init ()
- *
- * Initialize chip. Just try to find out how many chips we are dealing with
- * and where they are
- */
-static int __init nsc_ircc_init(void)
-{
- chipio_t info;
- nsc_chip_t *chip;
- int ret;
- int cfg_base;
- int cfg, id;
- int reg;
- int i = 0;
-
- ret = platform_driver_register(&nsc_ircc_driver);
- if (ret) {
- net_err_ratelimited("%s, Can't register driver!\n",
- driver_name);
- return ret;
- }
-
- /* Register with PnP subsystem to detect disable ports */
- ret = pnp_register_driver(&nsc_ircc_pnp_driver);
-
- if (!ret)
- pnp_registered = 1;
-
- ret = -ENODEV;
-
- /* Probe for all the NSC chipsets we know about */
- for (chip = chips; chip->name ; chip++) {
- pr_debug("%s(), Probing for %s ...\n", __func__,
- chip->name);
-
- /* Try all config registers for this chip */
- for (cfg = 0; cfg < ARRAY_SIZE(chip->cfg); cfg++) {
- cfg_base = chip->cfg[cfg];
- if (!cfg_base)
- continue;
-
- /* Read index register */
- reg = inb(cfg_base);
- if (reg == 0xff) {
- pr_debug("%s() no chip at 0x%03x\n",
- __func__, cfg_base);
- continue;
- }
-
- /* Read chip identification register */
- outb(chip->cid_index, cfg_base);
- id = inb(cfg_base+1);
- if ((id & chip->cid_mask) == chip->cid_value) {
- pr_debug("%s() Found %s chip, revision=%d\n",
- __func__, chip->name,
- id & ~chip->cid_mask);
-
- /*
- * If we found a correct PnP setting,
- * we first try it.
- */
- if (pnp_succeeded) {
- memset(&info, 0, sizeof(chipio_t));
- info.cfg_base = cfg_base;
- info.fir_base = pnp_info.fir_base;
- info.dma = pnp_info.dma;
- info.irq = pnp_info.irq;
-
- if (info.fir_base < 0x2000) {
- net_info_ratelimited("%s, chip->init\n",
- driver_name);
- chip->init(chip, &info);
- } else
- chip->probe(chip, &info);
-
- if (nsc_ircc_open(&info) >= 0)
- ret = 0;
- }
-
- /*
- * Opening based on PnP values failed.
- * Let's fallback to user values, or probe
- * the chip.
- */
- if (ret) {
- pr_debug("%s, PnP init failed\n",
- driver_name);
- memset(&info, 0, sizeof(chipio_t));
- info.cfg_base = cfg_base;
- info.fir_base = io[i];
- info.dma = dma[i];
- info.irq = irq[i];
-
- /*
- * If the user supplies the base address, then
- * we init the chip, if not we probe the values
- * set by the BIOS
- */
- if (io[i] < 0x2000) {
- chip->init(chip, &info);
- } else
- chip->probe(chip, &info);
-
- if (nsc_ircc_open(&info) >= 0)
- ret = 0;
- }
- i++;
- } else {
- pr_debug("%s(), Wrong chip id=0x%02x\n",
- __func__, id);
- }
- }
- }
-
- if (ret) {
- platform_driver_unregister(&nsc_ircc_driver);
- pnp_unregister_driver(&nsc_ircc_pnp_driver);
- pnp_registered = 0;
- }
-
- return ret;
-}
-
-/*
- * Function nsc_ircc_cleanup ()
- *
- * Close all configured chips
- *
- */
-static void __exit nsc_ircc_cleanup(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dev_self); i++) {
- if (dev_self[i])
- nsc_ircc_close(dev_self[i]);
- }
-
- platform_driver_unregister(&nsc_ircc_driver);
-
- if (pnp_registered)
- pnp_unregister_driver(&nsc_ircc_pnp_driver);
-
- pnp_registered = 0;
-}
-
-static const struct net_device_ops nsc_ircc_sir_ops = {
- .ndo_open = nsc_ircc_net_open,
- .ndo_stop = nsc_ircc_net_close,
- .ndo_start_xmit = nsc_ircc_hard_xmit_sir,
- .ndo_do_ioctl = nsc_ircc_net_ioctl,
-};
-
-static const struct net_device_ops nsc_ircc_fir_ops = {
- .ndo_open = nsc_ircc_net_open,
- .ndo_stop = nsc_ircc_net_close,
- .ndo_start_xmit = nsc_ircc_hard_xmit_fir,
- .ndo_do_ioctl = nsc_ircc_net_ioctl,
-};
-
-/*
- * Function nsc_ircc_open (iobase, irq)
- *
- * Open driver instance
- *
- */
-static int __init nsc_ircc_open(chipio_t *info)
-{
- struct net_device *dev;
- struct nsc_ircc_cb *self;
- void *ret;
- int err, chip_index;
-
- for (chip_index = 0; chip_index < ARRAY_SIZE(dev_self); chip_index++) {
- if (!dev_self[chip_index])
- break;
- }
-
- if (chip_index == ARRAY_SIZE(dev_self)) {
- net_err_ratelimited("%s(), maximum number of supported chips reached!\n",
- __func__);
- return -ENOMEM;
- }
-
- net_info_ratelimited("%s, Found chip at base=0x%03x\n",
- driver_name, info->cfg_base);
-
- if ((nsc_ircc_setup(info)) == -1)
- return -1;
-
- net_info_ratelimited("%s, driver loaded (Dag Brattli)\n", driver_name);
-
- dev = alloc_irdadev(sizeof(struct nsc_ircc_cb));
- if (dev == NULL) {
- net_err_ratelimited("%s(), can't allocate memory for control block!\n",
- __func__);
- return -ENOMEM;
- }
-
- self = netdev_priv(dev);
- self->netdev = dev;
- spin_lock_init(&self->lock);
-
- /* Need to store self somewhere */
- dev_self[chip_index] = self;
- self->index = chip_index;
-
- /* Initialize IO */
- self->io.cfg_base = info->cfg_base;
- self->io.fir_base = info->fir_base;
- self->io.irq = info->irq;
- self->io.fir_ext = CHIP_IO_EXTENT;
- self->io.dma = info->dma;
- self->io.fifo_size = 32;
-
- /* Reserve the ioports that we need */
- ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name);
- if (!ret) {
- net_warn_ratelimited("%s(), can't get iobase of 0x%03x\n",
- __func__, self->io.fir_base);
- err = -ENODEV;
- goto out1;
- }
-
- /* Initialize QoS for this device */
- irda_init_max_qos_capabilies(&self->qos);
-
- /* The only value we must override it the baudrate */
- self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
- IR_115200|IR_576000|IR_1152000 |(IR_4000000 << 8);
-
- self->qos.min_turn_time.bits = qos_mtt_bits;
- irda_qos_bits_to_value(&self->qos);
-
- /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
- self->rx_buff.truesize = 14384;
- self->tx_buff.truesize = 14384;
-
- /* Allocate memory if needed */
- self->rx_buff.head =
- dma_zalloc_coherent(NULL, self->rx_buff.truesize,
- &self->rx_buff_dma, GFP_KERNEL);
- if (self->rx_buff.head == NULL) {
- err = -ENOMEM;
- goto out2;
-
- }
-
- self->tx_buff.head =
- dma_zalloc_coherent(NULL, self->tx_buff.truesize,
- &self->tx_buff_dma, GFP_KERNEL);
- if (self->tx_buff.head == NULL) {
- err = -ENOMEM;
- goto out3;
- }
-
- self->rx_buff.in_frame = FALSE;
- self->rx_buff.state = OUTSIDE_FRAME;
- self->tx_buff.data = self->tx_buff.head;
- self->rx_buff.data = self->rx_buff.head;
-
- /* Reset Tx queue info */
- self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
- self->tx_fifo.tail = self->tx_buff.head;
-
- /* Override the network functions we need to use */
- dev->netdev_ops = &nsc_ircc_sir_ops;
-
- err = register_netdev(dev);
- if (err) {
- net_err_ratelimited("%s(), register_netdev() failed!\n",
- __func__);
- goto out4;
- }
- net_info_ratelimited("IrDA: Registered device %s\n", dev->name);
-
- /* Check if user has supplied a valid dongle id or not */
- if ((dongle_id <= 0) ||
- (dongle_id >= ARRAY_SIZE(dongle_types))) {
- dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base);
-
- net_info_ratelimited("%s, Found dongle: %s\n",
- driver_name, dongle_types[dongle_id]);
- } else {
- net_info_ratelimited("%s, Using dongle: %s\n",
- driver_name, dongle_types[dongle_id]);
- }
-
- self->io.dongle_id = dongle_id;
- nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id);
-
- self->pldev = platform_device_register_simple(NSC_IRCC_DRIVER_NAME,
- self->index, NULL, 0);
- if (IS_ERR(self->pldev)) {
- err = PTR_ERR(self->pldev);
- goto out5;
- }
- platform_set_drvdata(self->pldev, self);
-
- return chip_index;
-
- out5:
- unregister_netdev(dev);
- out4:
- dma_free_coherent(NULL, self->tx_buff.truesize,
- self->tx_buff.head, self->tx_buff_dma);
- out3:
- dma_free_coherent(NULL, self->rx_buff.truesize,
- self->rx_buff.head, self->rx_buff_dma);
- out2:
- release_region(self->io.fir_base, self->io.fir_ext);
- out1:
- free_netdev(dev);
- dev_self[chip_index] = NULL;
- return err;
-}
-
-/*
- * Function nsc_ircc_close (self)
- *
- * Close driver instance
- *
- */
-static int __exit nsc_ircc_close(struct nsc_ircc_cb *self)
-{
- int iobase;
-
- IRDA_ASSERT(self != NULL, return -1;);
-
- iobase = self->io.fir_base;
-
- platform_device_unregister(self->pldev);
-
- /* Remove netdevice */
- unregister_netdev(self->netdev);
-
- /* Release the PORT that this driver is using */
- pr_debug("%s(), Releasing Region %03x\n",
- __func__, self->io.fir_base);
- release_region(self->io.fir_base, self->io.fir_ext);
-
- if (self->tx_buff.head)
- dma_free_coherent(NULL, self->tx_buff.truesize,
- self->tx_buff.head, self->tx_buff_dma);
-
- if (self->rx_buff.head)
- dma_free_coherent(NULL, self->rx_buff.truesize,
- self->rx_buff.head, self->rx_buff_dma);
-
- dev_self[self->index] = NULL;
- free_netdev(self->netdev);
-
- return 0;
-}
-
-/*
- * Function nsc_ircc_init_108 (iobase, cfg_base, irq, dma)
- *
- * Initialize the NSC '108 chip
- *
- */
-static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info)
-{
- int cfg_base = info->cfg_base;
- __u8 temp=0;
-
- outb(2, cfg_base); /* Mode Control Register (MCTL) */
- outb(0x00, cfg_base+1); /* Disable device */
-
- /* Base Address and Interrupt Control Register (BAIC) */
- outb(CFG_108_BAIC, cfg_base);
- switch (info->fir_base) {
- case 0x3e8: outb(0x14, cfg_base+1); break;
- case 0x2e8: outb(0x15, cfg_base+1); break;
- case 0x3f8: outb(0x16, cfg_base+1); break;
- case 0x2f8: outb(0x17, cfg_base+1); break;
- default: net_err_ratelimited("%s(), invalid base_address\n", __func__);
- }
-
- /* Control Signal Routing Register (CSRT) */
- switch (info->irq) {
- case 3: temp = 0x01; break;
- case 4: temp = 0x02; break;
- case 5: temp = 0x03; break;
- case 7: temp = 0x04; break;
- case 9: temp = 0x05; break;
- case 11: temp = 0x06; break;
- case 15: temp = 0x07; break;
- default: net_err_ratelimited("%s(), invalid irq\n", __func__);
- }
- outb(CFG_108_CSRT, cfg_base);
-
- switch (info->dma) {
- case 0: outb(0x08+temp, cfg_base+1); break;
- case 1: outb(0x10+temp, cfg_base+1); break;
- case 3: outb(0x18+temp, cfg_base+1); break;
- default: net_err_ratelimited("%s(), invalid dma\n", __func__);
- }
-
- outb(CFG_108_MCTL, cfg_base); /* Mode Control Register (MCTL) */
- outb(0x03, cfg_base+1); /* Enable device */
-
- return 0;
-}
-
-/*
- * Function nsc_ircc_probe_108 (chip, info)
- *
- *
- *
- */
-static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info)
-{
- int cfg_base = info->cfg_base;
- int reg;
-
- /* Read address and interrupt control register (BAIC) */
- outb(CFG_108_BAIC, cfg_base);
- reg = inb(cfg_base+1);
-
- switch (reg & 0x03) {
- case 0:
- info->fir_base = 0x3e8;
- break;
- case 1:
- info->fir_base = 0x2e8;
- break;
- case 2:
- info->fir_base = 0x3f8;
- break;
- case 3:
- info->fir_base = 0x2f8;
- break;
- }
- info->sir_base = info->fir_base;
- pr_debug("%s(), probing fir_base=0x%03x\n", __func__,
- info->fir_base);
-
- /* Read control signals routing register (CSRT) */
- outb(CFG_108_CSRT, cfg_base);
- reg = inb(cfg_base+1);
-
- switch (reg & 0x07) {
- case 0:
- info->irq = -1;
- break;
- case 1:
- info->irq = 3;
- break;
- case 2:
- info->irq = 4;
- break;
- case 3:
- info->irq = 5;
- break;
- case 4:
- info->irq = 7;
- break;
- case 5:
- info->irq = 9;
- break;
- case 6:
- info->irq = 11;
- break;
- case 7:
- info->irq = 15;
- break;
- }
- pr_debug("%s(), probing irq=%d\n", __func__, info->irq);
-
- /* Currently we only read Rx DMA but it will also be used for Tx */
- switch ((reg >> 3) & 0x03) {
- case 0:
- info->dma = -1;
- break;
- case 1:
- info->dma = 0;
- break;
- case 2:
- info->dma = 1;
- break;
- case 3:
- info->dma = 3;
- break;
- }
- pr_debug("%s(), probing dma=%d\n", __func__, info->dma);
-
- /* Read mode control register (MCTL) */
- outb(CFG_108_MCTL, cfg_base);
- reg = inb(cfg_base+1);
-
- info->enabled = reg & 0x01;
- info->suspended = !((reg >> 1) & 0x01);
-
- return 0;
-}
-
-/*
- * Function nsc_ircc_init_338 (chip, info)
- *
- * Initialize the NSC '338 chip. Remember that the 87338 needs two
- * consecutive writes to the data registers while CPU interrupts are
- * disabled. The 97338 does not require this, but shouldn't be any
- * harm if we do it anyway.
- */
-static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info)
-{
- /* No init yet */
-
- return 0;
-}
-
-/*
- * Function nsc_ircc_probe_338 (chip, info)
- *
- *
- *
- */
-static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info)
-{
- int cfg_base = info->cfg_base;
- int reg, com = 0;
- int pnp;
-
- /* Read function enable register (FER) */
- outb(CFG_338_FER, cfg_base);
- reg = inb(cfg_base+1);
-
- info->enabled = (reg >> 2) & 0x01;
-
- /* Check if we are in Legacy or PnP mode */
- outb(CFG_338_PNP0, cfg_base);
- reg = inb(cfg_base+1);
-
- pnp = (reg >> 3) & 0x01;
- if (pnp) {
- pr_debug("(), Chip is in PnP mode\n");
- outb(0x46, cfg_base);
- reg = (inb(cfg_base+1) & 0xfe) << 2;
-
- outb(0x47, cfg_base);
- reg |= ((inb(cfg_base+1) & 0xfc) << 8);
-
- info->fir_base = reg;
- } else {
- /* Read function address register (FAR) */
- outb(CFG_338_FAR, cfg_base);
- reg = inb(cfg_base+1);
-
- switch ((reg >> 4) & 0x03) {
- case 0:
- info->fir_base = 0x3f8;
- break;
- case 1:
- info->fir_base = 0x2f8;
- break;
- case 2:
- com = 3;
- break;
- case 3:
- com = 4;
- break;
- }
-
- if (com) {
- switch ((reg >> 6) & 0x03) {
- case 0:
- if (com == 3)
- info->fir_base = 0x3e8;
- else
- info->fir_base = 0x2e8;
- break;
- case 1:
- if (com == 3)
- info->fir_base = 0x338;
- else
- info->fir_base = 0x238;
- break;
- case 2:
- if (com == 3)
- info->fir_base = 0x2e8;
- else
- info->fir_base = 0x2e0;
- break;
- case 3:
- if (com == 3)
- info->fir_base = 0x220;
- else
- info->fir_base = 0x228;
- break;
- }
- }
- }
- info->sir_base = info->fir_base;
-
- /* Read PnP register 1 (PNP1) */
- outb(CFG_338_PNP1, cfg_base);
- reg = inb(cfg_base+1);
-
- info->irq = reg >> 4;
-
- /* Read PnP register 3 (PNP3) */
- outb(CFG_338_PNP3, cfg_base);
- reg = inb(cfg_base+1);
-
- info->dma = (reg & 0x07) - 1;
-
- /* Read power and test register (PTR) */
- outb(CFG_338_PTR, cfg_base);
- reg = inb(cfg_base+1);
-
- info->suspended = reg & 0x01;
-
- return 0;
-}
-
-
-/*
- * Function nsc_ircc_init_39x (chip, info)
- *
- * Now that we know it's a '39x (see probe below), we need to
- * configure it so we can use it.
- *
- * The NSC '338 chip is a Super I/O chip with a "bank" architecture,
- * the configuration of the different functionality (serial, parallel,
- * floppy...) are each in a different bank (Logical Device Number).
- * The base address, irq and dma configuration registers are common
- * to all functionalities (index 0x30 to 0x7F).
- * There is only one configuration register specific to the
- * serial port, CFG_39X_SPC.
- * JeanII
- *
- * Note : this code was written by Jan Frey <janfrey@web.de>
- */
-static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info)
-{
- int cfg_base = info->cfg_base;
- int enabled;
-
- /* User is sure about his config... accept it. */
- pr_debug("%s(): nsc_ircc_init_39x (user settings): io=0x%04x, irq=%d, dma=%d\n",
- __func__, info->fir_base, info->irq, info->dma);
-
- /* Access bank for SP2 */
- outb(CFG_39X_LDN, cfg_base);
- outb(0x02, cfg_base+1);
-
- /* Configure SP2 */
-
- /* We want to enable the device if not enabled */
- outb(CFG_39X_ACT, cfg_base);
- enabled = inb(cfg_base+1) & 0x01;
-
- if (!enabled) {
- /* Enable the device */
- outb(CFG_39X_SIOCF1, cfg_base);
- outb(0x01, cfg_base+1);
- /* May want to update info->enabled. Jean II */
- }
-
- /* Enable UART bank switching (bit 7) ; Sets the chip to normal
- * power mode (wake up from sleep mode) (bit 1) */
- outb(CFG_39X_SPC, cfg_base);
- outb(0x82, cfg_base+1);
-
- return 0;
-}
-
-/*
- * Function nsc_ircc_probe_39x (chip, info)
- *
- * Test if we really have a '39x chip at the given address
- *
- * Note : this code was written by Jan Frey <janfrey@web.de>
- */
-static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info)
-{
- int cfg_base = info->cfg_base;
- int reg1, reg2, irq, irqt, dma1, dma2;
- int enabled, susp;
-
- pr_debug("%s(), nsc_ircc_probe_39x, base=%d\n",
- __func__, cfg_base);
-
- /* This function should be executed with irq off to avoid
- * another driver messing with the Super I/O bank - Jean II */
-
- /* Access bank for SP2 */
- outb(CFG_39X_LDN, cfg_base);
- outb(0x02, cfg_base+1);
-
- /* Read infos about SP2 ; store in info struct */
- outb(CFG_39X_BASEH, cfg_base);
- reg1 = inb(cfg_base+1);
- outb(CFG_39X_BASEL, cfg_base);
- reg2 = inb(cfg_base+1);
- info->fir_base = (reg1 << 8) | reg2;
-
- outb(CFG_39X_IRQNUM, cfg_base);
- irq = inb(cfg_base+1);
- outb(CFG_39X_IRQSEL, cfg_base);
- irqt = inb(cfg_base+1);
- info->irq = irq;
-
- outb(CFG_39X_DMA0, cfg_base);
- dma1 = inb(cfg_base+1);
- outb(CFG_39X_DMA1, cfg_base);
- dma2 = inb(cfg_base+1);
- info->dma = dma1 -1;
-
- outb(CFG_39X_ACT, cfg_base);
- info->enabled = enabled = inb(cfg_base+1) & 0x01;
-
- outb(CFG_39X_SPC, cfg_base);
- susp = 1 - ((inb(cfg_base+1) & 0x02) >> 1);
-
- pr_debug("%s(): io=0x%02x%02x, irq=%d (type %d), rxdma=%d, txdma=%d, enabled=%d (suspended=%d)\n",
- __func__, reg1, reg2, irq, irqt, dma1, dma2, enabled, susp);
-
- /* Configure SP2 */
-
- /* We want to enable the device if not enabled */
- outb(CFG_39X_ACT, cfg_base);
- enabled = inb(cfg_base+1) & 0x01;
-
- if (!enabled) {
- /* Enable the device */
- outb(CFG_39X_SIOCF1, cfg_base);
- outb(0x01, cfg_base+1);
- /* May want to update info->enabled. Jean II */
- }
-
- /* Enable UART bank switching (bit 7) ; Sets the chip to normal
- * power mode (wake up from sleep mode) (bit 1) */
- outb(CFG_39X_SPC, cfg_base);
- outb(0x82, cfg_base+1);
-
- return 0;
-}
-
-#ifdef CONFIG_PNP
-/* PNP probing */
-static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id)
-{
- memset(&pnp_info, 0, sizeof(chipio_t));
- pnp_info.irq = -1;
- pnp_info.dma = -1;
- pnp_succeeded = 1;
-
- if (id->driver_data & NSC_FORCE_DONGLE_TYPE9)
- dongle_id = 0x9;
-
- /* There doesn't seem to be any way of getting the cfg_base.
- * On my box, cfg_base is in the PnP descriptor of the
- * motherboard. Oh well... Jean II */
-
- if (pnp_port_valid(dev, 0) &&
- !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED))
- pnp_info.fir_base = pnp_port_start(dev, 0);
-
- if (pnp_irq_valid(dev, 0) &&
- !(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED))
- pnp_info.irq = pnp_irq(dev, 0);
-
- if (pnp_dma_valid(dev, 0) &&
- !(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED))
- pnp_info.dma = pnp_dma(dev, 0);
-
- pr_debug("%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n",
- __func__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma);
-
- if((pnp_info.fir_base == 0) ||
- (pnp_info.irq == -1) || (pnp_info.dma == -1)) {
- /* Returning an error will disable the device. Yuck ! */
- //return -EINVAL;
- pnp_succeeded = 0;
- }
-
- return 0;
-}
-#endif
-
-/*
- * Function nsc_ircc_setup (info)
- *
- * Returns non-negative on success.
- *
- */
-static int nsc_ircc_setup(chipio_t *info)
-{
- int version;
- int iobase = info->fir_base;
-
- /* Read the Module ID */
- switch_bank(iobase, BANK3);
- version = inb(iobase+MID);
-
- pr_debug("%s() Driver %s Found chip version %02x\n",
- __func__, driver_name, version);
-
- /* Should be 0x2? */
- if (0x20 != (version & 0xf0)) {
- net_err_ratelimited("%s, Wrong chip version %02x\n",
- driver_name, version);
- return -1;
- }
-
- /* Switch to advanced mode */
- switch_bank(iobase, BANK2);
- outb(ECR1_EXT_SL, iobase+ECR1);
- switch_bank(iobase, BANK0);
-
- /* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */
- switch_bank(iobase, BANK0);
- outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
-
- outb(0x03, iobase+LCR); /* 8 bit word length */
- outb(MCR_SIR, iobase+MCR); /* Start at SIR-mode, also clears LSR*/
-
- /* Set FIFO size to 32 */
- switch_bank(iobase, BANK2);
- outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
-
- /* IRCR2: FEND_MD is not set */
- switch_bank(iobase, BANK5);
- outb(0x02, iobase+4);
-
- /* Make sure that some defaults are OK */
- switch_bank(iobase, BANK6);
- outb(0x20, iobase+0); /* Set 32 bits FIR CRC */
- outb(0x0a, iobase+1); /* Set MIR pulse width */
- outb(0x0d, iobase+2); /* Set SIR pulse width to 1.6us */
- outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */
-
- /* Enable receive interrupts */
- switch_bank(iobase, BANK0);
- outb(IER_RXHDL_IE, iobase+IER);
-
- return 0;
-}
-
-/*
- * Function nsc_ircc_read_dongle_id (void)
- *
- * Try to read dongle identification. This procedure needs to be executed
- * once after power-on/reset. It also needs to be used whenever you suspect
- * that the user may have plugged/unplugged the IrDA Dongle.
- */
-static int nsc_ircc_read_dongle_id (int iobase)
-{
- int dongle_id;
- __u8 bank;
-
- bank = inb(iobase+BSR);
-
- /* Select Bank 7 */
- switch_bank(iobase, BANK7);
-
- /* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */
- outb(0x00, iobase+7);
-
- /* ID0, 1, and 2 are pulled up/down very slowly */
- udelay(50);
-
- /* IRCFG1: read the ID bits */
- dongle_id = inb(iobase+4) & 0x0f;
-
-#ifdef BROKEN_DONGLE_ID
- if (dongle_id == 0x0a)
- dongle_id = 0x09;
-#endif
- /* Go back to bank 0 before returning */
- switch_bank(iobase, BANK0);
-
- outb(bank, iobase+BSR);
-
- return dongle_id;
-}
-
-/*
- * Function nsc_ircc_init_dongle_interface (iobase, dongle_id)
- *
- * This function initializes the dongle for the transceiver that is
- * used. This procedure needs to be executed once after
- * power-on/reset. It also needs to be used whenever you suspect that
- * the dongle is changed.
- */
-static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id)
-{
- int bank;
-
- /* Save current bank */
- bank = inb(iobase+BSR);
-
- /* Select Bank 7 */
- switch_bank(iobase, BANK7);
-
- /* IRCFG4: set according to dongle_id */
- switch (dongle_id) {
- case 0x00: /* same as */
- case 0x01: /* Differential serial interface */
- pr_debug("%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
- break;
- case 0x02: /* same as */
- case 0x03: /* Reserved */
- pr_debug("%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
- break;
- case 0x04: /* Sharp RY5HD01 */
- break;
- case 0x05: /* Reserved, but this is what the Thinkpad reports */
- pr_debug("%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
- break;
- case 0x06: /* Single-ended serial interface */
- pr_debug("%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
- break;
- case 0x07: /* Consumer-IR only */
- pr_debug("%s(), %s is not for IrDA mode\n",
- __func__, dongle_types[dongle_id]);
- break;
- case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
- pr_debug("%s(), %s\n",
- __func__, dongle_types[dongle_id]);
- break;
- case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
- outb(0x28, iobase+7); /* Set irsl[0-2] as output */
- break;
- case 0x0A: /* same as */
- case 0x0B: /* Reserved */
- pr_debug("%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
- break;
- case 0x0C: /* same as */
- case 0x0D: /* HP HSDL-1100/HSDL-2100 */
- /*
- * Set irsl0 as input, irsl[1-2] as output, and separate
- * inputs are used for SIR and MIR/FIR
- */
- outb(0x48, iobase+7);
- break;
- case 0x0E: /* Supports SIR Mode only */
- outb(0x28, iobase+7); /* Set irsl[0-2] as output */
- break;
- case 0x0F: /* No dongle connected */
- pr_debug("%s(), %s\n",
- __func__, dongle_types[dongle_id]);
-
- switch_bank(iobase, BANK0);
- outb(0x62, iobase+MCR);
- break;
- default:
- pr_debug("%s(), invalid dongle_id %#x",
- __func__, dongle_id);
- }
-
- /* IRCFG1: IRSL1 and 2 are set to IrDA mode */
- outb(0x00, iobase+4);
-
- /* Restore bank register */
- outb(bank, iobase+BSR);
-
-} /* set_up_dongle_interface */
-
-/*
- * Function nsc_ircc_change_dongle_speed (iobase, speed, dongle_id)
- *
- * Change speed of the attach dongle
- *
- */
-static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id)
-{
- __u8 bank;
-
- /* Save current bank */
- bank = inb(iobase+BSR);
-
- /* Select Bank 7 */
- switch_bank(iobase, BANK7);
-
- /* IRCFG1: set according to dongle_id */
- switch (dongle_id) {
- case 0x00: /* same as */
- case 0x01: /* Differential serial interface */
- pr_debug("%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
- break;
- case 0x02: /* same as */
- case 0x03: /* Reserved */
- pr_debug("%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
- break;
- case 0x04: /* Sharp RY5HD01 */
- break;
- case 0x05: /* Reserved */
- pr_debug("%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
- break;
- case 0x06: /* Single-ended serial interface */
- pr_debug("%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
- break;
- case 0x07: /* Consumer-IR only */
- pr_debug("%s(), %s is not for IrDA mode\n",
- __func__, dongle_types[dongle_id]);
- break;
- case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
- pr_debug("%s(), %s\n",
- __func__, dongle_types[dongle_id]);
- outb(0x00, iobase+4);
- if (speed > 115200)
- outb(0x01, iobase+4);
- break;
- case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
- outb(0x01, iobase+4);
-
- if (speed == 4000000) {
- /* There was a cli() there, but we now are already
- * under spin_lock_irqsave() - JeanII */
- outb(0x81, iobase+4);
- outb(0x80, iobase+4);
- } else
- outb(0x00, iobase+4);
- break;
- case 0x0A: /* same as */
- case 0x0B: /* Reserved */
- pr_debug("%s(), %s not defined by irda yet\n",
- __func__, dongle_types[dongle_id]);
- break;
- case 0x0C: /* same as */
- case 0x0D: /* HP HSDL-1100/HSDL-2100 */
- break;
- case 0x0E: /* Supports SIR Mode only */
- break;
- case 0x0F: /* No dongle connected */
- pr_debug("%s(), %s is not for IrDA mode\n",
- __func__, dongle_types[dongle_id]);
-
- switch_bank(iobase, BANK0);
- outb(0x62, iobase+MCR);
- break;
- default:
- pr_debug("%s(), invalid data_rate\n", __func__);
- }
- /* Restore bank register */
- outb(bank, iobase+BSR);
-}
-
-/*
- * Function nsc_ircc_change_speed (self, baud)
- *
- * Change the speed of the device
- *
- * This function *must* be called with irq off and spin-lock.
- */
-static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed)
-{
- struct net_device *dev;
- __u8 mcr = MCR_SIR;
- int iobase;
- __u8 bank;
- __u8 ier; /* Interrupt enable register */
-
- pr_debug("%s(), speed=%d\n", __func__, speed);
-
- IRDA_ASSERT(self != NULL, return 0;);
-
- dev = self->netdev;
- iobase = self->io.fir_base;
-
- /* Update accounting for new speed */
- self->io.speed = speed;
-
- /* Save current bank */
- bank = inb(iobase+BSR);
-
- /* Disable interrupts */
- switch_bank(iobase, BANK0);
- outb(0, iobase+IER);
-
- /* Select Bank 2 */
- switch_bank(iobase, BANK2);
-
- outb(0x00, iobase+BGDH);
- switch (speed) {
- case 9600: outb(0x0c, iobase+BGDL); break;
- case 19200: outb(0x06, iobase+BGDL); break;
- case 38400: outb(0x03, iobase+BGDL); break;
- case 57600: outb(0x02, iobase+BGDL); break;
- case 115200: outb(0x01, iobase+BGDL); break;
- case 576000:
- switch_bank(iobase, BANK5);
-
- /* IRCR2: MDRS is set */
- outb(inb(iobase+4) | 0x04, iobase+4);
-
- mcr = MCR_MIR;
- pr_debug("%s(), handling baud of 576000\n", __func__);
- break;
- case 1152000:
- mcr = MCR_MIR;
- pr_debug("%s(), handling baud of 1152000\n", __func__);
- break;
- case 4000000:
- mcr = MCR_FIR;
- pr_debug("%s(), handling baud of 4000000\n", __func__);
- break;
- default:
- mcr = MCR_FIR;
- pr_debug("%s(), unknown baud rate of %d\n",
- __func__, speed);
- break;
- }
-
- /* Set appropriate speed mode */
- switch_bank(iobase, BANK0);
- outb(mcr | MCR_TX_DFR, iobase+MCR);
-
- /* Give some hits to the transceiver */
- nsc_ircc_change_dongle_speed(iobase, speed, self->io.dongle_id);
-
- /* Set FIFO threshold to TX17, RX16 */
- switch_bank(iobase, BANK0);
- outb(0x00, iobase+FCR);
- outb(FCR_FIFO_EN, iobase+FCR);
- outb(FCR_RXTH| /* Set Rx FIFO threshold */
- FCR_TXTH| /* Set Tx FIFO threshold */
- FCR_TXSR| /* Reset Tx FIFO */
- FCR_RXSR| /* Reset Rx FIFO */
- FCR_FIFO_EN, /* Enable FIFOs */
- iobase+FCR);
-
- /* Set FIFO size to 32 */
- switch_bank(iobase, BANK2);
- outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
-
- /* Enable some interrupts so we can receive frames */
- switch_bank(iobase, BANK0);
- if (speed > 115200) {
- /* Install FIR xmit handler */
- dev->netdev_ops = &nsc_ircc_fir_ops;
- ier = IER_SFIF_IE;
- nsc_ircc_dma_receive(self);
- } else {
- /* Install SIR xmit handler */
- dev->netdev_ops = &nsc_ircc_sir_ops;
- ier = IER_RXHDL_IE;
- }
- /* Set our current interrupt mask */
- outb(ier, iobase+IER);
-
- /* Restore BSR */
- outb(bank, iobase+BSR);
-
- /* Make sure interrupt handlers keep the proper interrupt mask */
- return ier;
-}
-
-/*
- * Function nsc_ircc_hard_xmit (skb, dev)
- *
- * Transmit the frame!
- *
- */
-static netdev_tx_t nsc_ircc_hard_xmit_sir(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct nsc_ircc_cb *self;
- unsigned long flags;
- int iobase;
- __s32 speed;
- __u8 bank;
-
- self = netdev_priv(dev);
-
- IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
-
- iobase = self->io.fir_base;
-
- netif_stop_queue(dev);
-
- /* Make sure tests *& speed change are atomic */
- spin_lock_irqsave(&self->lock, flags);
-
- /* Check if we need to change the speed */
- speed = irda_get_next_speed(skb);
- if ((speed != self->io.speed) && (speed != -1)) {
- /* Check for empty frame. */
- if (!skb->len) {
- /* If we just sent a frame, we get called before
- * the last bytes get out (because of the SIR FIFO).
- * If this is the case, let interrupt handler change
- * the speed itself... Jean II */
- if (self->io.direction == IO_RECV) {
- nsc_ircc_change_speed(self, speed);
- /* TODO : For SIR->SIR, the next packet
- * may get corrupted - Jean II */
- netif_wake_queue(dev);
- } else {
- self->new_speed = speed;
- /* Queue will be restarted after speed change
- * to make sure packets gets through the
- * proper xmit handler - Jean II */
- }
- netif_trans_update(dev);
- spin_unlock_irqrestore(&self->lock, flags);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- } else
- self->new_speed = speed;
- }
-
- /* Save current bank */
- bank = inb(iobase+BSR);
-
- self->tx_buff.data = self->tx_buff.head;
-
- self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
- self->tx_buff.truesize);
-
- dev->stats.tx_bytes += self->tx_buff.len;
-
- /* Add interrupt on tx low level (will fire immediately) */
- switch_bank(iobase, BANK0);
- outb(IER_TXLDL_IE, iobase+IER);
-
- /* Restore bank register */
- outb(bank, iobase+BSR);
-
- netif_trans_update(dev);
- spin_unlock_irqrestore(&self->lock, flags);
-
- dev_kfree_skb(skb);
-
- return NETDEV_TX_OK;
-}
-
-static netdev_tx_t nsc_ircc_hard_xmit_fir(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct nsc_ircc_cb *self;
- unsigned long flags;
- int iobase;
- __s32 speed;
- __u8 bank;
- int mtt, diff;
-
- self = netdev_priv(dev);
- iobase = self->io.fir_base;
-
- netif_stop_queue(dev);
-
- /* Make sure tests *& speed change are atomic */
- spin_lock_irqsave(&self->lock, flags);
-
- /* Check if we need to change the speed */
- speed = irda_get_next_speed(skb);
- if ((speed != self->io.speed) && (speed != -1)) {
- /* Check for empty frame. */
- if (!skb->len) {
- /* If we are currently transmitting, defer to
- * interrupt handler. - Jean II */
- if(self->tx_fifo.len == 0) {
- nsc_ircc_change_speed(self, speed);
- netif_wake_queue(dev);
- } else {
- self->new_speed = speed;
- /* Keep queue stopped :
- * the speed change operation may change the
- * xmit handler, and we want to make sure
- * the next packet get through the proper
- * Tx path, so block the Tx queue until
- * the speed change has been done.
- * Jean II */
- }
- netif_trans_update(dev);
- spin_unlock_irqrestore(&self->lock, flags);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- } else {
- /* Change speed after current frame */
- self->new_speed = speed;
- }
- }
-
- /* Save current bank */
- bank = inb(iobase+BSR);
-
- /* Register and copy this frame to DMA memory */
- self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail;
- self->tx_fifo.queue[self->tx_fifo.free].len = skb->len;
- self->tx_fifo.tail += skb->len;
-
- dev->stats.tx_bytes += skb->len;
-
- skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start,
- skb->len);
- self->tx_fifo.len++;
- self->tx_fifo.free++;
-
- /* Start transmit only if there is currently no transmit going on */
- if (self->tx_fifo.len == 1) {
- /* Check if we must wait the min turn time or not */
- mtt = irda_get_mtt(skb);
- if (mtt) {
- /* Check how much time we have used already */
- diff = ktime_us_delta(ktime_get(), self->stamp);
-
- /* Check if the mtt is larger than the time we have
- * already used by all the protocol processing
- */
- if (mtt > diff) {
- mtt -= diff;
-
- /*
- * Use timer if delay larger than 125 us, and
- * use udelay for smaller values which should
- * be acceptable
- */
- if (mtt > 125) {
- /* Adjust for timer resolution */
- mtt = mtt / 125;
-
- /* Setup timer */
- switch_bank(iobase, BANK4);
- outb(mtt & 0xff, iobase+TMRL);
- outb((mtt >> 8) & 0x0f, iobase+TMRH);
-
- /* Start timer */
- outb(IRCR1_TMR_EN, iobase+IRCR1);
- self->io.direction = IO_XMIT;
-
- /* Enable timer interrupt */
- switch_bank(iobase, BANK0);
- outb(IER_TMR_IE, iobase+IER);
-
- /* Timer will take care of the rest */
- goto out;
- } else
- udelay(mtt);
- }
- }
- /* Enable DMA interrupt */
- switch_bank(iobase, BANK0);
- outb(IER_DMA_IE, iobase+IER);
-
- /* Transmit frame */
- nsc_ircc_dma_xmit(self, iobase);
- }
- out:
- /* Not busy transmitting anymore if window is not full,
- * and if we don't need to change speed */
- if ((self->tx_fifo.free < MAX_TX_WINDOW) && (self->new_speed == 0))
- netif_wake_queue(self->netdev);
-
- /* Restore bank register */
- outb(bank, iobase+BSR);
-
- netif_trans_update(dev);
- spin_unlock_irqrestore(&self->lock, flags);
- dev_kfree_skb(skb);
-
- return NETDEV_TX_OK;
-}
-
-/*
- * Function nsc_ircc_dma_xmit (self, iobase)
- *
- * Transmit data using DMA
- *
- */
-static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase)
-{
- int bsr;
-
- /* Save current bank */
- bsr = inb(iobase+BSR);
-
- /* Disable DMA */
- switch_bank(iobase, BANK0);
- outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
-
- self->io.direction = IO_XMIT;
-
- /* Choose transmit DMA channel */
- switch_bank(iobase, BANK2);
- outb(ECR1_DMASWP|ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1);
-
- irda_setup_dma(self->io.dma,
- ((u8 *)self->tx_fifo.queue[self->tx_fifo.ptr].start -
- self->tx_buff.head) + self->tx_buff_dma,
- self->tx_fifo.queue[self->tx_fifo.ptr].len,
- DMA_TX_MODE);
-
- /* Enable DMA and SIR interaction pulse */
- switch_bank(iobase, BANK0);
- outb(inb(iobase+MCR)|MCR_TX_DFR|MCR_DMA_EN|MCR_IR_PLS, iobase+MCR);
-
- /* Restore bank register */
- outb(bsr, iobase+BSR);
-}
-
-/*
- * Function nsc_ircc_pio_xmit (self, iobase)
- *
- * Transmit data using PIO. Returns the number of bytes that actually
- * got transferred
- *
- */
-static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
-{
- int actual = 0;
- __u8 bank;
-
- /* Save current bank */
- bank = inb(iobase+BSR);
-
- switch_bank(iobase, BANK0);
- if (!(inb_p(iobase+LSR) & LSR_TXEMP)) {
- pr_debug("%s(), warning, FIFO not empty yet!\n",
- __func__);
-
- /* FIFO may still be filled to the Tx interrupt threshold */
- fifo_size -= 17;
- }
-
- /* Fill FIFO with current frame */
- while ((fifo_size-- > 0) && (actual < len)) {
- /* Transmit next byte */
- outb(buf[actual++], iobase+TXD);
- }
-
- pr_debug("%s(), fifo_size %d ; %d sent of %d\n",
- __func__, fifo_size, actual, len);
-
- /* Restore bank */
- outb(bank, iobase+BSR);
-
- return actual;
-}
-
-/*
- * Function nsc_ircc_dma_xmit_complete (self)
- *
- * The transfer of a frame in finished. This function will only be called
- * by the interrupt handler
- *
- */
-static int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self)
-{
- int iobase;
- __u8 bank;
- int ret = TRUE;
-
- iobase = self->io.fir_base;
-
- /* Save current bank */
- bank = inb(iobase+BSR);
-
- /* Disable DMA */
- switch_bank(iobase, BANK0);
- outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
-
- /* Check for underrun! */
- if (inb(iobase+ASCR) & ASCR_TXUR) {
- self->netdev->stats.tx_errors++;
- self->netdev->stats.tx_fifo_errors++;
-
- /* Clear bit, by writing 1 into it */
- outb(ASCR_TXUR, iobase+ASCR);
- } else {
- self->netdev->stats.tx_packets++;
- }
-
- /* Finished with this frame, so prepare for next */
- self->tx_fifo.ptr++;
- self->tx_fifo.len--;
-
- /* Any frames to be sent back-to-back? */
- if (self->tx_fifo.len) {
- nsc_ircc_dma_xmit(self, iobase);
-
- /* Not finished yet! */
- ret = FALSE;
- } else {
- /* Reset Tx FIFO info */
- self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
- self->tx_fifo.tail = self->tx_buff.head;
- }
-
- /* Make sure we have room for more frames and
- * that we don't need to change speed */
- if ((self->tx_fifo.free < MAX_TX_WINDOW) && (self->new_speed == 0)) {
- /* Not busy transmitting anymore */
- /* Tell the network layer, that we can accept more frames */
- netif_wake_queue(self->netdev);
- }
-
- /* Restore bank */
- outb(bank, iobase+BSR);
-
- return ret;
-}
-
-/*
- * Function nsc_ircc_dma_receive (self)
- *
- * Get ready for receiving a frame. The device will initiate a DMA
- * if it starts to receive a frame.
- *
- */
-static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self)
-{
- int iobase;
- __u8 bsr;
-
- iobase = self->io.fir_base;
-
- /* Reset Tx FIFO info */
- self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
- self->tx_fifo.tail = self->tx_buff.head;
-
- /* Save current bank */
- bsr = inb(iobase+BSR);
-
- /* Disable DMA */
- switch_bank(iobase, BANK0);
- outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
-
- /* Choose DMA Rx, DMA Fairness, and Advanced mode */
- switch_bank(iobase, BANK2);
- outb(ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1);
-
- self->io.direction = IO_RECV;
- self->rx_buff.data = self->rx_buff.head;
-
- /* Reset Rx FIFO. This will also flush the ST_FIFO */
- switch_bank(iobase, BANK0);
- outb(FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
-
- self->st_fifo.len = self->st_fifo.pending_bytes = 0;
- self->st_fifo.tail = self->st_fifo.head = 0;
-
- irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize,
- DMA_RX_MODE);
-
- /* Enable DMA */
- switch_bank(iobase, BANK0);
- outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR);
-
- /* Restore bank register */
- outb(bsr, iobase+BSR);
-
- return 0;
-}
-
-/*
- * Function nsc_ircc_dma_receive_complete (self)
- *
- * Finished with receiving frames
- *
- *
- */
-static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase)
-{
- struct st_fifo *st_fifo;
- struct sk_buff *skb;
- __u8 status;
- __u8 bank;
- int len;
-
- st_fifo = &self->st_fifo;
-
- /* Save current bank */
- bank = inb(iobase+BSR);
-
- /* Read all entries in status FIFO */
- switch_bank(iobase, BANK5);
- while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) {
- /* We must empty the status FIFO no matter what */
- len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8);
-
- if (st_fifo->tail >= MAX_RX_WINDOW) {
- pr_debug("%s(), window is full!\n", __func__);
- continue;
- }
-
- st_fifo->entries[st_fifo->tail].status = status;
- st_fifo->entries[st_fifo->tail].len = len;
- st_fifo->pending_bytes += len;
- st_fifo->tail++;
- st_fifo->len++;
- }
- /* Try to process all entries in status FIFO */
- while (st_fifo->len > 0) {
- /* Get first entry */
- status = st_fifo->entries[st_fifo->head].status;
- len = st_fifo->entries[st_fifo->head].len;
- st_fifo->pending_bytes -= len;
- st_fifo->head++;
- st_fifo->len--;
-
- /* Check for errors */
- if (status & FRM_ST_ERR_MSK) {
- if (status & FRM_ST_LOST_FR) {
- /* Add number of lost frames to stats */
- self->netdev->stats.rx_errors += len;
- } else {
- /* Skip frame */
- self->netdev->stats.rx_errors++;
-
- self->rx_buff.data += len;
-
- if (status & FRM_ST_MAX_LEN)
- self->netdev->stats.rx_length_errors++;
-
- if (status & FRM_ST_PHY_ERR)
- self->netdev->stats.rx_frame_errors++;
-
- if (status & FRM_ST_BAD_CRC)
- self->netdev->stats.rx_crc_errors++;
- }
- /* The errors below can be reported in both cases */
- if (status & FRM_ST_OVR1)
- self->netdev->stats.rx_fifo_errors++;
-
- if (status & FRM_ST_OVR2)
- self->netdev->stats.rx_fifo_errors++;
- } else {
- /*
- * First we must make sure that the frame we
- * want to deliver is all in main memory. If we
- * cannot tell, then we check if the Rx FIFO is
- * empty. If not then we will have to take a nap
- * and try again later.
- */
- if (st_fifo->pending_bytes < self->io.fifo_size) {
- switch_bank(iobase, BANK0);
- if (inb(iobase+LSR) & LSR_RXDA) {
- /* Put this entry back in fifo */
- st_fifo->head--;
- st_fifo->len++;
- st_fifo->pending_bytes += len;
- st_fifo->entries[st_fifo->head].status = status;
- st_fifo->entries[st_fifo->head].len = len;
- /*
- * DMA not finished yet, so try again
- * later, set timer value, resolution
- * 125 us
- */
- switch_bank(iobase, BANK4);
- outb(0x02, iobase+TMRL); /* x 125 us */
- outb(0x00, iobase+TMRH);
-
- /* Start timer */
- outb(IRCR1_TMR_EN, iobase+IRCR1);
-
- /* Restore bank register */
- outb(bank, iobase+BSR);
-
- return FALSE; /* I'll be back! */
- }
- }
-
- /*
- * Remember the time we received this frame, so we can
- * reduce the min turn time a bit since we will know
- * how much time we have used for protocol processing
- */
- self->stamp = ktime_get();
-
- skb = dev_alloc_skb(len+1);
- if (skb == NULL) {
- self->netdev->stats.rx_dropped++;
-
- /* Restore bank register */
- outb(bank, iobase+BSR);
-
- return FALSE;
- }
-
- /* Make sure IP header gets aligned */
- skb_reserve(skb, 1);
-
- /* Copy frame without CRC */
- if (self->io.speed < 4000000) {
- skb_put(skb, len-2);
- skb_copy_to_linear_data(skb,
- self->rx_buff.data,
- len - 2);
- } else {
- skb_put(skb, len-4);
- skb_copy_to_linear_data(skb,
- self->rx_buff.data,
- len - 4);
- }
-
- /* Move to next frame */
- self->rx_buff.data += len;
- self->netdev->stats.rx_bytes += len;
- self->netdev->stats.rx_packets++;
-
- skb->dev = self->netdev;
- skb_reset_mac_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- netif_rx(skb);
- }
- }
- /* Restore bank register */
- outb(bank, iobase+BSR);
-
- return TRUE;
-}
-
-/*
- * Function nsc_ircc_pio_receive (self)
- *
- * Receive all data in receiver FIFO
- *
- */
-static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self)
-{
- __u8 byte;
- int iobase;
-
- iobase = self->io.fir_base;
-
- /* Receive all characters in Rx FIFO */
- do {
- byte = inb(iobase+RXD);
- async_unwrap_char(self->netdev, &self->netdev->stats,
- &self->rx_buff, byte);
- } while (inb(iobase+LSR) & LSR_RXDA); /* Data available */
-}
-
-/*
- * Function nsc_ircc_sir_interrupt (self, eir)
- *
- * Handle SIR interrupt
- *
- */
-static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir)
-{
- int actual;
-
- /* Check if transmit FIFO is low on data */
- if (eir & EIR_TXLDL_EV) {
- /* Write data left in transmit buffer */
- actual = nsc_ircc_pio_write(self->io.fir_base,
- self->tx_buff.data,
- self->tx_buff.len,
- self->io.fifo_size);
- self->tx_buff.data += actual;
- self->tx_buff.len -= actual;
-
- self->io.direction = IO_XMIT;
-
- /* Check if finished */
- if (self->tx_buff.len > 0)
- self->ier = IER_TXLDL_IE;
- else {
-
- self->netdev->stats.tx_packets++;
- netif_wake_queue(self->netdev);
- self->ier = IER_TXEMP_IE;
- }
-
- }
- /* Check if transmission has completed */
- if (eir & EIR_TXEMP_EV) {
- /* Turn around and get ready to receive some data */
- self->io.direction = IO_RECV;
- self->ier = IER_RXHDL_IE;
- /* Check if we need to change the speed?
- * Need to be after self->io.direction to avoid race with
- * nsc_ircc_hard_xmit_sir() - Jean II */
- if (self->new_speed) {
- pr_debug("%s(), Changing speed!\n", __func__);
- self->ier = nsc_ircc_change_speed(self,
- self->new_speed);
- self->new_speed = 0;
- netif_wake_queue(self->netdev);
-
- /* Check if we are going to FIR */
- if (self->io.speed > 115200) {
- /* No need to do anymore SIR stuff */
- return;
- }
- }
- }
-
- /* Rx FIFO threshold or timeout */
- if (eir & EIR_RXHDL_EV) {
- nsc_ircc_pio_receive(self);
-
- /* Keep receiving */
- self->ier = IER_RXHDL_IE;
- }
-}
-
-/*
- * Function nsc_ircc_fir_interrupt (self, eir)
- *
- * Handle MIR/FIR interrupt
- *
- */
-static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase,
- int eir)
-{
- __u8 bank;
-
- bank = inb(iobase+BSR);
-
- /* Status FIFO event*/
- if (eir & EIR_SFIF_EV) {
- /* Check if DMA has finished */
- if (nsc_ircc_dma_receive_complete(self, iobase)) {
- /* Wait for next status FIFO interrupt */
- self->ier = IER_SFIF_IE;
- } else {
- self->ier = IER_SFIF_IE | IER_TMR_IE;
- }
- } else if (eir & EIR_TMR_EV) { /* Timer finished */
- /* Disable timer */
- switch_bank(iobase, BANK4);
- outb(0, iobase+IRCR1);
-
- /* Clear timer event */
- switch_bank(iobase, BANK0);
- outb(ASCR_CTE, iobase+ASCR);
-
- /* Check if this is a Tx timer interrupt */
- if (self->io.direction == IO_XMIT) {
- nsc_ircc_dma_xmit(self, iobase);
-
- /* Interrupt on DMA */
- self->ier = IER_DMA_IE;
- } else {
- /* Check (again) if DMA has finished */
- if (nsc_ircc_dma_receive_complete(self, iobase)) {
- self->ier = IER_SFIF_IE;
- } else {
- self->ier = IER_SFIF_IE | IER_TMR_IE;
- }
- }
- } else if (eir & EIR_DMA_EV) {
- /* Finished with all transmissions? */
- if (nsc_ircc_dma_xmit_complete(self)) {
- if(self->new_speed != 0) {
- /* As we stop the Tx queue, the speed change
- * need to be done when the Tx fifo is
- * empty. Ask for a Tx done interrupt */
- self->ier = IER_TXEMP_IE;
- } else {
- /* Check if there are more frames to be
- * transmitted */
- if (irda_device_txqueue_empty(self->netdev)) {
- /* Prepare for receive */
- nsc_ircc_dma_receive(self);
- self->ier = IER_SFIF_IE;
- } else
- net_warn_ratelimited("%s(), potential Tx queue lockup !\n",
- __func__);
- }
- } else {
- /* Not finished yet, so interrupt on DMA again */
- self->ier = IER_DMA_IE;
- }
- } else if (eir & EIR_TXEMP_EV) {
- /* The Tx FIFO has totally drained out, so now we can change
- * the speed... - Jean II */
- self->ier = nsc_ircc_change_speed(self, self->new_speed);
- self->new_speed = 0;
- netif_wake_queue(self->netdev);
- /* Note : nsc_ircc_change_speed() restarted Rx fifo */
- }
-
- outb(bank, iobase+BSR);
-}
-
-/*
- * Function nsc_ircc_interrupt (irq, dev_id, regs)
- *
- * An interrupt from the chip has arrived. Time to do some work
- *
- */
-static irqreturn_t nsc_ircc_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct nsc_ircc_cb *self;
- __u8 bsr, eir;
- int iobase;
-
- self = netdev_priv(dev);
-
- spin_lock(&self->lock);
-
- iobase = self->io.fir_base;
-
- bsr = inb(iobase+BSR); /* Save current bank */
-
- switch_bank(iobase, BANK0);
- self->ier = inb(iobase+IER);
- eir = inb(iobase+EIR) & self->ier; /* Mask out the interesting ones */
-
- outb(0, iobase+IER); /* Disable interrupts */
-
- if (eir) {
- /* Dispatch interrupt handler for the current speed */
- if (self->io.speed > 115200)
- nsc_ircc_fir_interrupt(self, iobase, eir);
- else
- nsc_ircc_sir_interrupt(self, eir);
- }
-
- outb(self->ier, iobase+IER); /* Restore interrupts */
- outb(bsr, iobase+BSR); /* Restore bank register */
-
- spin_unlock(&self->lock);
- return IRQ_RETVAL(eir);
-}
-
-/*
- * Function nsc_ircc_is_receiving (self)
- *
- * Return TRUE is we are currently receiving a frame
- *
- */
-static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self)
-{
- unsigned long flags;
- int status = FALSE;
- int iobase;
- __u8 bank;
-
- IRDA_ASSERT(self != NULL, return FALSE;);
-
- spin_lock_irqsave(&self->lock, flags);
-
- if (self->io.speed > 115200) {
- iobase = self->io.fir_base;
-
- /* Check if rx FIFO is not empty */
- bank = inb(iobase+BSR);
- switch_bank(iobase, BANK2);
- if ((inb(iobase+RXFLV) & 0x3f) != 0) {
- /* We are receiving something */
- status = TRUE;
- }
- outb(bank, iobase+BSR);
- } else
- status = (self->rx_buff.state != OUTSIDE_FRAME);
-
- spin_unlock_irqrestore(&self->lock, flags);
-
- return status;
-}
-
-/*
- * Function nsc_ircc_net_open (dev)
- *
- * Start the device
- *
- */
-static int nsc_ircc_net_open(struct net_device *dev)
-{
- struct nsc_ircc_cb *self;
- int iobase;
- char hwname[32];
- __u8 bank;
-
-
- IRDA_ASSERT(dev != NULL, return -1;);
- self = netdev_priv(dev);
-
- IRDA_ASSERT(self != NULL, return 0;);
-
- iobase = self->io.fir_base;
-
- if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, dev->name, dev)) {
- net_warn_ratelimited("%s, unable to allocate irq=%d\n",
- driver_name, self->io.irq);
- return -EAGAIN;
- }
- /*
- * Always allocate the DMA channel after the IRQ, and clean up on
- * failure.
- */
- if (request_dma(self->io.dma, dev->name)) {
- net_warn_ratelimited("%s, unable to allocate dma=%d\n",
- driver_name, self->io.dma);
- free_irq(self->io.irq, dev);
- return -EAGAIN;
- }
-
- /* Save current bank */
- bank = inb(iobase+BSR);
-
- /* turn on interrupts */
- switch_bank(iobase, BANK0);
- outb(IER_LS_IE | IER_RXHDL_IE, iobase+IER);
-
- /* Restore bank register */
- outb(bank, iobase+BSR);
-
- /* Ready to play! */
- netif_start_queue(dev);
-
- /* Give self a hardware name */
- sprintf(hwname, "NSC-FIR @ 0x%03x", self->io.fir_base);
-
- /*
- * Open new IrLAP layer instance, now that everything should be
- * initialized properly
- */
- self->irlap = irlap_open(dev, &self->qos, hwname);
-
- return 0;
-}
-
-/*
- * Function nsc_ircc_net_close (dev)
- *
- * Stop the device
- *
- */
-static int nsc_ircc_net_close(struct net_device *dev)
-{
- struct nsc_ircc_cb *self;
- int iobase;
- __u8 bank;
-
-
- IRDA_ASSERT(dev != NULL, return -1;);
-
- self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
-
- /* Stop device */
- netif_stop_queue(dev);
-
- /* Stop and remove instance of IrLAP */
- if (self->irlap)
- irlap_close(self->irlap);
- self->irlap = NULL;
-
- iobase = self->io.fir_base;
-
- disable_dma(self->io.dma);
-
- /* Save current bank */
- bank = inb(iobase+BSR);
-
- /* Disable interrupts */
- switch_bank(iobase, BANK0);
- outb(0, iobase+IER);
-
- free_irq(self->io.irq, dev);
- free_dma(self->io.dma);
-
- /* Restore bank register */
- outb(bank, iobase+BSR);
-
- return 0;
-}
-
-/*
- * Function nsc_ircc_net_ioctl (dev, rq, cmd)
- *
- * Process IOCTL commands for this device
- *
- */
-static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct if_irda_req *irq = (struct if_irda_req *) rq;
- struct nsc_ircc_cb *self;
- unsigned long flags;
- int ret = 0;
-
- IRDA_ASSERT(dev != NULL, return -1;);
-
- self = netdev_priv(dev);
-
- IRDA_ASSERT(self != NULL, return -1;);
-
- pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
-
- switch (cmd) {
- case SIOCSBANDWIDTH: /* Set bandwidth */
- if (!capable(CAP_NET_ADMIN)) {
- ret = -EPERM;
- break;
- }
- spin_lock_irqsave(&self->lock, flags);
- nsc_ircc_change_speed(self, irq->ifr_baudrate);
- spin_unlock_irqrestore(&self->lock, flags);
- break;
- case SIOCSMEDIABUSY: /* Set media busy */
- if (!capable(CAP_NET_ADMIN)) {
- ret = -EPERM;
- break;
- }
- irda_device_set_media_busy(self->netdev, TRUE);
- break;
- case SIOCGRECEIVING: /* Check if we are receiving right now */
- /* This is already protected */
- irq->ifr_receiving = nsc_ircc_is_receiving(self);
- break;
- default:
- ret = -EOPNOTSUPP;
- }
- return ret;
-}
-
-static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state)
-{
- struct nsc_ircc_cb *self = platform_get_drvdata(dev);
- int bank;
- unsigned long flags;
- int iobase = self->io.fir_base;
-
- if (self->io.suspended)
- return 0;
-
- pr_debug("%s, Suspending\n", driver_name);
-
- rtnl_lock();
- if (netif_running(self->netdev)) {
- netif_device_detach(self->netdev);
- spin_lock_irqsave(&self->lock, flags);
- /* Save current bank */
- bank = inb(iobase+BSR);
-
- /* Disable interrupts */
- switch_bank(iobase, BANK0);
- outb(0, iobase+IER);
-
- /* Restore bank register */
- outb(bank, iobase+BSR);
-
- spin_unlock_irqrestore(&self->lock, flags);
- free_irq(self->io.irq, self->netdev);
- disable_dma(self->io.dma);
- }
- self->io.suspended = 1;
- rtnl_unlock();
-
- return 0;
-}
-
-static int nsc_ircc_resume(struct platform_device *dev)
-{
- struct nsc_ircc_cb *self = platform_get_drvdata(dev);
- unsigned long flags;
-
- if (!self->io.suspended)
- return 0;
-
- pr_debug("%s, Waking up\n", driver_name);
-
- rtnl_lock();
- nsc_ircc_setup(&self->io);
- nsc_ircc_init_dongle_interface(self->io.fir_base, self->io.dongle_id);
-
- if (netif_running(self->netdev)) {
- if (request_irq(self->io.irq, nsc_ircc_interrupt, 0,
- self->netdev->name, self->netdev)) {
- net_warn_ratelimited("%s, unable to allocate irq=%d\n",
- driver_name, self->io.irq);
-
- /*
- * Don't fail resume process, just kill this
- * network interface
- */
- unregister_netdevice(self->netdev);
- } else {
- spin_lock_irqsave(&self->lock, flags);
- nsc_ircc_change_speed(self, self->io.speed);
- spin_unlock_irqrestore(&self->lock, flags);
- netif_device_attach(self->netdev);
- }
-
- } else {
- spin_lock_irqsave(&self->lock, flags);
- nsc_ircc_change_speed(self, 9600);
- spin_unlock_irqrestore(&self->lock, flags);
- }
- self->io.suspended = 0;
- rtnl_unlock();
-
- return 0;
-}
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("NSC IrDA Device Driver");
-MODULE_LICENSE("GPL");
-
-
-module_param(qos_mtt_bits, int, 0);
-MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
-module_param_hw_array(io, int, ioport, NULL, 0);
-MODULE_PARM_DESC(io, "Base I/O addresses");
-module_param_hw_array(irq, int, irq, NULL, 0);
-MODULE_PARM_DESC(irq, "IRQ lines");
-module_param_hw_array(dma, int, dma, NULL, 0);
-MODULE_PARM_DESC(dma, "DMA channels");
-module_param(dongle_id, int, 0);
-MODULE_PARM_DESC(dongle_id, "Type-id of used dongle");
-
-module_init(nsc_ircc_init);
-module_exit(nsc_ircc_cleanup);
-
diff --git a/drivers/staging/irda/drivers/nsc-ircc.h b/drivers/staging/irda/drivers/nsc-ircc.h
deleted file mode 100644
index 7be5acb56532..000000000000
--- a/drivers/staging/irda/drivers/nsc-ircc.h
+++ /dev/null
@@ -1,281 +0,0 @@
-/*********************************************************************
- *
- * Filename: nsc-ircc.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Fri Nov 13 14:37:40 1998
- * Modified at: Sun Jan 23 17:47:00 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
- * Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
- * Copyright (c) 1998 Actisys Corp., www.actisys.com
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef NSC_IRCC_H
-#define NSC_IRCC_H
-
-#include <linux/ktime.h>
-
-#include <linux/spinlock.h>
-#include <linux/pm.h>
-#include <linux/types.h>
-#include <asm/io.h>
-
-/* Features for chips (set in driver_data) */
-#define NSC_FORCE_DONGLE_TYPE9 0x00000001
-
-/* DMA modes needed */
-#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */
-#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */
-
-/* Config registers for the '108 */
-#define CFG_108_BAIC 0x00
-#define CFG_108_CSRT 0x01
-#define CFG_108_MCTL 0x02
-
-/* Config registers for the '338 */
-#define CFG_338_FER 0x00
-#define CFG_338_FAR 0x01
-#define CFG_338_PTR 0x02
-#define CFG_338_PNP0 0x1b
-#define CFG_338_PNP1 0x1c
-#define CFG_338_PNP3 0x4f
-
-/* Config registers for the '39x (in the logical device bank) */
-#define CFG_39X_LDN 0x07 /* Logical device number (Super I/O bank) */
-#define CFG_39X_SIOCF1 0x21 /* SuperI/O Config */
-#define CFG_39X_ACT 0x30 /* Device activation */
-#define CFG_39X_BASEH 0x60 /* Device base address (high bits) */
-#define CFG_39X_BASEL 0x61 /* Device base address (low bits) */
-#define CFG_39X_IRQNUM 0x70 /* Interrupt number & wake up enable */
-#define CFG_39X_IRQSEL 0x71 /* Interrupt select (edge/level + polarity) */
-#define CFG_39X_DMA0 0x74 /* DMA 0 configuration */
-#define CFG_39X_DMA1 0x75 /* DMA 1 configuration */
-#define CFG_39X_SPC 0xF0 /* Serial port configuration register */
-
-/* Flags for configuration register CRF0 */
-#define APEDCRC 0x02
-#define ENBNKSEL 0x01
-
-/* Set 0 */
-#define TXD 0x00 /* Transmit data port */
-#define RXD 0x00 /* Receive data port */
-
-/* Register 1 */
-#define IER 0x01 /* Interrupt Enable Register*/
-#define IER_RXHDL_IE 0x01 /* Receiver high data level interrupt */
-#define IER_TXLDL_IE 0x02 /* Transeiver low data level interrupt */
-#define IER_LS_IE 0x04//* Link Status Interrupt */
-#define IER_ETXURI 0x04 /* Tx underrun */
-#define IER_DMA_IE 0x10 /* DMA finished interrupt */
-#define IER_TXEMP_IE 0x20
-#define IER_SFIF_IE 0x40 /* Frame status FIFO intr */
-#define IER_TMR_IE 0x80 /* Timer event */
-
-#define FCR 0x02 /* (write only) */
-#define FCR_FIFO_EN 0x01 /* Enable FIFO's */
-#define FCR_RXSR 0x02 /* Rx FIFO soft reset */
-#define FCR_TXSR 0x04 /* Tx FIFO soft reset */
-#define FCR_RXTH 0x40 /* Rx FIFO threshold (set to 16) */
-#define FCR_TXTH 0x20 /* Tx FIFO threshold (set to 17) */
-
-#define EIR 0x02 /* (read only) */
-#define EIR_RXHDL_EV 0x01
-#define EIR_TXLDL_EV 0x02
-#define EIR_LS_EV 0x04
-#define EIR_DMA_EV 0x10
-#define EIR_TXEMP_EV 0x20
-#define EIR_SFIF_EV 0x40
-#define EIR_TMR_EV 0x80
-
-#define LCR 0x03 /* Link control register */
-#define LCR_WLS_8 0x03 /* 8 bits */
-
-#define BSR 0x03 /* Bank select register */
-#define BSR_BKSE 0x80
-#define BANK0 LCR_WLS_8 /* Must make sure that we set 8N1 */
-#define BANK1 0x80
-#define BANK2 0xe0
-#define BANK3 0xe4
-#define BANK4 0xe8
-#define BANK5 0xec
-#define BANK6 0xf0
-#define BANK7 0xf4
-
-#define MCR 0x04 /* Mode Control Register */
-#define MCR_MODE_MASK ~(0xd0)
-#define MCR_UART 0x00
-#define MCR_RESERVED 0x20
-#define MCR_SHARP_IR 0x40
-#define MCR_SIR 0x60
-#define MCR_MIR 0x80
-#define MCR_FIR 0xa0
-#define MCR_CEIR 0xb0
-#define MCR_IR_PLS 0x10
-#define MCR_DMA_EN 0x04
-#define MCR_EN_IRQ 0x08
-#define MCR_TX_DFR 0x08
-
-#define LSR 0x05 /* Link status register */
-#define LSR_RXDA 0x01 /* Receiver data available */
-#define LSR_TXRDY 0x20 /* Transmitter ready */
-#define LSR_TXEMP 0x40 /* Transmitter empty */
-
-#define ASCR 0x07 /* Auxiliary Status and Control Register */
-#define ASCR_RXF_TOUT 0x01 /* Rx FIFO timeout */
-#define ASCR_FEND_INF 0x02 /* Frame end bytes in rx FIFO */
-#define ASCR_S_EOT 0x04 /* Set end of transmission */
-#define ASCT_RXBSY 0x20 /* Rx busy */
-#define ASCR_TXUR 0x40 /* Transeiver underrun */
-#define ASCR_CTE 0x80 /* Clear timer event */
-
-/* Bank 2 */
-#define BGDL 0x00 /* Baud Generator Divisor Port (Low Byte) */
-#define BGDH 0x01 /* Baud Generator Divisor Port (High Byte) */
-
-#define ECR1 0x02 /* Extended Control Register 1 */
-#define ECR1_EXT_SL 0x01 /* Extended Mode Select */
-#define ECR1_DMANF 0x02 /* DMA Fairness */
-#define ECR1_DMATH 0x04 /* DMA Threshold */
-#define ECR1_DMASWP 0x08 /* DMA Swap */
-
-#define EXCR2 0x04
-#define EXCR2_TFSIZ 0x01 /* Rx FIFO size = 32 */
-#define EXCR2_RFSIZ 0x04 /* Tx FIFO size = 32 */
-
-#define TXFLV 0x06 /* Tx FIFO level */
-#define RXFLV 0x07 /* Rx FIFO level */
-
-/* Bank 3 */
-#define MID 0x00
-
-/* Bank 4 */
-#define TMRL 0x00 /* Timer low byte */
-#define TMRH 0x01 /* Timer high byte */
-#define IRCR1 0x02 /* Infrared control register 1 */
-#define IRCR1_TMR_EN 0x01 /* Timer enable */
-
-#define TFRLL 0x04
-#define TFRLH 0x05
-#define RFRLL 0x06
-#define RFRLH 0x07
-
-/* Bank 5 */
-#define IRCR2 0x04 /* Infrared control register 2 */
-#define IRCR2_MDRS 0x04 /* MIR data rate select */
-#define IRCR2_FEND_MD 0x20 /* */
-
-#define FRM_ST 0x05 /* Frame status FIFO */
-#define FRM_ST_VLD 0x80 /* Frame status FIFO data valid */
-#define FRM_ST_ERR_MSK 0x5f
-#define FRM_ST_LOST_FR 0x40 /* Frame lost */
-#define FRM_ST_MAX_LEN 0x10 /* Max frame len exceeded */
-#define FRM_ST_PHY_ERR 0x08 /* Physical layer error */
-#define FRM_ST_BAD_CRC 0x04
-#define FRM_ST_OVR1 0x02 /* Rx FIFO overrun */
-#define FRM_ST_OVR2 0x01 /* Frame status FIFO overrun */
-
-#define RFLFL 0x06
-#define RFLFH 0x07
-
-/* Bank 6 */
-#define IR_CFG2 0x00
-#define IR_CFG2_DIS_CRC 0x02
-
-/* Bank 7 */
-#define IRM_CR 0x07 /* Infrared module control register */
-#define IRM_CR_IRX_MSL 0x40
-#define IRM_CR_AF_MNT 0x80 /* Automatic format */
-
-/* NSC chip information */
-struct nsc_chip {
- char *name; /* Name of chipset */
- int cfg[3]; /* Config registers */
- u_int8_t cid_index; /* Chip identification index reg */
- u_int8_t cid_value; /* Chip identification expected value */
- u_int8_t cid_mask; /* Chip identification revision mask */
-
- /* Functions for probing and initializing the specific chip */
- int (*probe)(struct nsc_chip *chip, chipio_t *info);
- int (*init)(struct nsc_chip *chip, chipio_t *info);
-};
-typedef struct nsc_chip nsc_chip_t;
-
-/* For storing entries in the status FIFO */
-struct st_fifo_entry {
- int status;
- int len;
-};
-
-#define MAX_TX_WINDOW 7
-#define MAX_RX_WINDOW 7
-
-struct st_fifo {
- struct st_fifo_entry entries[MAX_RX_WINDOW];
- int pending_bytes;
- int head;
- int tail;
- int len;
-};
-
-struct frame_cb {
- void *start; /* Start of frame in DMA mem */
- int len; /* Length of frame in DMA mem */
-};
-
-struct tx_fifo {
- struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */
- int ptr; /* Currently being sent */
- int len; /* Length of queue */
- int free; /* Next free slot */
- void *tail; /* Next free start in DMA mem */
-};
-
-/* Private data for each instance */
-struct nsc_ircc_cb {
- struct st_fifo st_fifo; /* Info about received frames */
- struct tx_fifo tx_fifo; /* Info about frames to be transmitted */
-
- struct net_device *netdev; /* Yes! we are some kind of netdevice */
-
- struct irlap_cb *irlap; /* The link layer we are binded to */
- struct qos_info qos; /* QoS capabilities for this device */
-
- chipio_t io; /* IrDA controller information */
- iobuff_t tx_buff; /* Transmit buffer */
- iobuff_t rx_buff; /* Receive buffer */
- dma_addr_t tx_buff_dma;
- dma_addr_t rx_buff_dma;
-
- __u8 ier; /* Interrupt enable register */
-
- ktime_t stamp;
-
- spinlock_t lock; /* For serializing operations */
-
- __u32 new_speed;
- int index; /* Instance index */
-
- struct platform_device *pldev;
-};
-
-static inline void switch_bank(int iobase, int bank)
-{
- outb(bank, iobase+BSR);
-}
-
-#endif /* NSC_IRCC_H */
diff --git a/drivers/staging/irda/drivers/old_belkin-sir.c b/drivers/staging/irda/drivers/old_belkin-sir.c
deleted file mode 100644
index a7c2e990ae69..000000000000
--- a/drivers/staging/irda/drivers/old_belkin-sir.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*********************************************************************
- *
- * Filename: old_belkin.c
- * Version: 1.1
- * Description: Driver for the Belkin (old) SmartBeam dongle
- * Status: Experimental...
- * Author: Jean Tourrilhes <jt@hpl.hp.com>
- * Created at: 22/11/99
- * Modified at: Fri Dec 17 09:13:32 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Jean Tourrilhes, 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.
- *
- * 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/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-// #include <net/irda/irda_device.h>
-
-#include "sir-dev.h"
-
-/*
- * Belkin is selling a dongle called the SmartBeam.
- * In fact, there is two hardware version of this dongle, of course with
- * the same name and looking the exactly same (grrr...).
- * I guess that I've got the old one, because inside I don't have
- * a jumper for IrDA/ASK...
- *
- * As far as I can make it from info on their web site, the old dongle
- * support only 9600 b/s, which make our life much simpler as far as
- * the driver is concerned, but you might not like it very much ;-)
- * The new SmartBeam does 115 kb/s, and I've not tested it...
- *
- * Belkin claim that the correct driver for the old dongle (in Windows)
- * is the generic Parallax 9500a driver, but the Linux LiteLink driver
- * fails for me (probably because Linux-IrDA doesn't rate fallback),
- * so I created this really dumb driver...
- *
- * In fact, this driver doesn't do much. The only thing it does is to
- * prevent Linux-IrDA to use any other speed than 9600 b/s ;-) This
- * driver is called "old_belkin" so that when the new SmartBeam is supported
- * its driver can be called "belkin" instead of "new_belkin".
- *
- * Note : this driver was written without any info/help from Belkin,
- * so a lot of info here might be totally wrong. Blame me ;-)
- */
-
-static int old_belkin_open(struct sir_dev *dev);
-static int old_belkin_close(struct sir_dev *dev);
-static int old_belkin_change_speed(struct sir_dev *dev, unsigned speed);
-static int old_belkin_reset(struct sir_dev *dev);
-
-static struct dongle_driver old_belkin = {
- .owner = THIS_MODULE,
- .driver_name = "Old Belkin SmartBeam",
- .type = IRDA_OLD_BELKIN_DONGLE,
- .open = old_belkin_open,
- .close = old_belkin_close,
- .reset = old_belkin_reset,
- .set_speed = old_belkin_change_speed,
-};
-
-static int __init old_belkin_sir_init(void)
-{
- return irda_register_dongle(&old_belkin);
-}
-
-static void __exit old_belkin_sir_cleanup(void)
-{
- irda_unregister_dongle(&old_belkin);
-}
-
-static int old_belkin_open(struct sir_dev *dev)
-{
- struct qos_info *qos = &dev->qos;
-
- /* Power on dongle */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- /* Not too fast, please... */
- qos->baud_rate.bits &= IR_9600;
- /* Needs at least 10 ms (totally wild guess, can do probably better) */
- qos->min_turn_time.bits = 0x01;
- irda_qos_bits_to_value(qos);
-
- /* irda thread waits 50 msec for power settling */
-
- return 0;
-}
-
-static int old_belkin_close(struct sir_dev *dev)
-{
- /* Power off dongle */
- sirdev_set_dtr_rts(dev, FALSE, FALSE);
-
- return 0;
-}
-
-/*
- * Function old_belkin_change_speed (task)
- *
- * With only one speed available, not much to do...
- */
-static int old_belkin_change_speed(struct sir_dev *dev, unsigned speed)
-{
- dev->speed = 9600;
- return (speed==dev->speed) ? 0 : -EINVAL;
-}
-
-/*
- * Function old_belkin_reset (task)
- *
- * Reset the Old-Belkin type dongle.
- *
- */
-static int old_belkin_reset(struct sir_dev *dev)
-{
- /* This dongles speed "defaults" to 9600 bps ;-) */
- dev->speed = 9600;
-
- return 0;
-}
-
-MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>");
-MODULE_DESCRIPTION("Belkin (old) SmartBeam dongle driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-7"); /* IRDA_OLD_BELKIN_DONGLE */
-
-module_init(old_belkin_sir_init);
-module_exit(old_belkin_sir_cleanup);
diff --git a/drivers/staging/irda/drivers/pxaficp_ir.c b/drivers/staging/irda/drivers/pxaficp_ir.c
deleted file mode 100644
index 2ea00a6531f9..000000000000
--- a/drivers/staging/irda/drivers/pxaficp_ir.c
+++ /dev/null
@@ -1,1075 +0,0 @@
-/*
- * linux/drivers/net/irda/pxaficp_ir.c
- *
- * Based on sa1100_ir.c by Russell King
- *
- * Changes copyright (C) 2003-2005 MontaVista Software, Inc.
- *
- * 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.
- *
- * Infra-red driver (SIR/FIR) for the PXA2xx embedded microprocessor
- *
- */
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/dma/pxa-dma.h>
-#include <linux/gpio.h>
-#include <linux/slab.h>
-#include <linux/sched/clock.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irmod.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/irda_device.h>
-
-#include <linux/platform_data/irda-pxaficp.h>
-#undef __REG
-#define __REG(x) ((x) & 0xffff)
-#include <mach/regs-uart.h>
-
-#define ICCR0 0x0000 /* ICP Control Register 0 */
-#define ICCR1 0x0004 /* ICP Control Register 1 */
-#define ICCR2 0x0008 /* ICP Control Register 2 */
-#define ICDR 0x000c /* ICP Data Register */
-#define ICSR0 0x0014 /* ICP Status Register 0 */
-#define ICSR1 0x0018 /* ICP Status Register 1 */
-
-#define ICCR0_AME (1 << 7) /* Address match enable */
-#define ICCR0_TIE (1 << 6) /* Transmit FIFO interrupt enable */
-#define ICCR0_RIE (1 << 5) /* Receive FIFO interrupt enable */
-#define ICCR0_RXE (1 << 4) /* Receive enable */
-#define ICCR0_TXE (1 << 3) /* Transmit enable */
-#define ICCR0_TUS (1 << 2) /* Transmit FIFO underrun select */
-#define ICCR0_LBM (1 << 1) /* Loopback mode */
-#define ICCR0_ITR (1 << 0) /* IrDA transmission */
-
-#define ICCR2_RXP (1 << 3) /* Receive Pin Polarity select */
-#define ICCR2_TXP (1 << 2) /* Transmit Pin Polarity select */
-#define ICCR2_TRIG (3 << 0) /* Receive FIFO Trigger threshold */
-#define ICCR2_TRIG_8 (0 << 0) /* >= 8 bytes */
-#define ICCR2_TRIG_16 (1 << 0) /* >= 16 bytes */
-#define ICCR2_TRIG_32 (2 << 0) /* >= 32 bytes */
-
-#define ICSR0_EOC (1 << 6) /* DMA End of Descriptor Chain */
-#define ICSR0_FRE (1 << 5) /* Framing error */
-#define ICSR0_RFS (1 << 4) /* Receive FIFO service request */
-#define ICSR0_TFS (1 << 3) /* Transnit FIFO service request */
-#define ICSR0_RAB (1 << 2) /* Receiver abort */
-#define ICSR0_TUR (1 << 1) /* Trunsmit FIFO underun */
-#define ICSR0_EIF (1 << 0) /* End/Error in FIFO */
-
-#define ICSR1_ROR (1 << 6) /* Receiver FIFO underrun */
-#define ICSR1_CRE (1 << 5) /* CRC error */
-#define ICSR1_EOF (1 << 4) /* End of frame */
-#define ICSR1_TNF (1 << 3) /* Transmit FIFO not full */
-#define ICSR1_RNE (1 << 2) /* Receive FIFO not empty */
-#define ICSR1_TBY (1 << 1) /* Tramsmiter busy flag */
-#define ICSR1_RSY (1 << 0) /* Recevier synchronized flag */
-
-#define IrSR_RXPL_NEG_IS_ZERO (1<<4)
-#define IrSR_RXPL_POS_IS_ZERO 0x0
-#define IrSR_TXPL_NEG_IS_ZERO (1<<3)
-#define IrSR_TXPL_POS_IS_ZERO 0x0
-#define IrSR_XMODE_PULSE_1_6 (1<<2)
-#define IrSR_XMODE_PULSE_3_16 0x0
-#define IrSR_RCVEIR_IR_MODE (1<<1)
-#define IrSR_RCVEIR_UART_MODE 0x0
-#define IrSR_XMITIR_IR_MODE (1<<0)
-#define IrSR_XMITIR_UART_MODE 0x0
-
-#define IrSR_IR_RECEIVE_ON (\
- IrSR_RXPL_NEG_IS_ZERO | \
- IrSR_TXPL_POS_IS_ZERO | \
- IrSR_XMODE_PULSE_3_16 | \
- IrSR_RCVEIR_IR_MODE | \
- IrSR_XMITIR_UART_MODE)
-
-#define IrSR_IR_TRANSMIT_ON (\
- IrSR_RXPL_NEG_IS_ZERO | \
- IrSR_TXPL_POS_IS_ZERO | \
- IrSR_XMODE_PULSE_3_16 | \
- IrSR_RCVEIR_UART_MODE | \
- IrSR_XMITIR_IR_MODE)
-
-/* macros for registers read/write */
-#define ficp_writel(irda, val, off) \
- do { \
- dev_vdbg(irda->dev, \
- "%s():%d ficp_writel(0x%x, %s)\n", \
- __func__, __LINE__, (val), #off); \
- writel_relaxed((val), (irda)->irda_base + (off)); \
- } while (0)
-
-#define ficp_readl(irda, off) \
- ({ \
- unsigned int _v; \
- _v = readl_relaxed((irda)->irda_base + (off)); \
- dev_vdbg(irda->dev, \
- "%s():%d ficp_readl(%s): 0x%x\n", \
- __func__, __LINE__, #off, _v); \
- _v; \
- })
-
-#define stuart_writel(irda, val, off) \
- do { \
- dev_vdbg(irda->dev, \
- "%s():%d stuart_writel(0x%x, %s)\n", \
- __func__, __LINE__, (val), #off); \
- writel_relaxed((val), (irda)->stuart_base + (off)); \
- } while (0)
-
-#define stuart_readl(irda, off) \
- ({ \
- unsigned int _v; \
- _v = readl_relaxed((irda)->stuart_base + (off)); \
- dev_vdbg(irda->dev, \
- "%s():%d stuart_readl(%s): 0x%x\n", \
- __func__, __LINE__, #off, _v); \
- _v; \
- })
-
-struct pxa_irda {
- int speed;
- int newspeed;
- unsigned long long last_clk;
-
- void __iomem *stuart_base;
- void __iomem *irda_base;
- unsigned char *dma_rx_buff;
- unsigned char *dma_tx_buff;
- dma_addr_t dma_rx_buff_phy;
- dma_addr_t dma_tx_buff_phy;
- unsigned int dma_tx_buff_len;
- struct dma_chan *txdma;
- struct dma_chan *rxdma;
- dma_cookie_t rx_cookie;
- dma_cookie_t tx_cookie;
- int drcmr_rx;
- int drcmr_tx;
-
- int uart_irq;
- int icp_irq;
-
- struct irlap_cb *irlap;
- struct qos_info qos;
-
- iobuff_t tx_buff;
- iobuff_t rx_buff;
-
- struct device *dev;
- struct pxaficp_platform_data *pdata;
- struct clk *fir_clk;
- struct clk *sir_clk;
- struct clk *cur_clk;
-};
-
-static int pxa_irda_set_speed(struct pxa_irda *si, int speed);
-
-static inline void pxa_irda_disable_clk(struct pxa_irda *si)
-{
- if (si->cur_clk)
- clk_disable_unprepare(si->cur_clk);
- si->cur_clk = NULL;
-}
-
-static inline void pxa_irda_enable_firclk(struct pxa_irda *si)
-{
- si->cur_clk = si->fir_clk;
- clk_prepare_enable(si->fir_clk);
-}
-
-static inline void pxa_irda_enable_sirclk(struct pxa_irda *si)
-{
- si->cur_clk = si->sir_clk;
- clk_prepare_enable(si->sir_clk);
-}
-
-
-#define IS_FIR(si) ((si)->speed >= 4000000)
-#define IRDA_FRAME_SIZE_LIMIT 2047
-
-static void pxa_irda_fir_dma_rx_irq(void *data);
-static void pxa_irda_fir_dma_tx_irq(void *data);
-
-inline static void pxa_irda_fir_dma_rx_start(struct pxa_irda *si)
-{
- struct dma_async_tx_descriptor *tx;
-
- tx = dmaengine_prep_slave_single(si->rxdma, si->dma_rx_buff_phy,
- IRDA_FRAME_SIZE_LIMIT, DMA_FROM_DEVICE,
- DMA_PREP_INTERRUPT);
- if (!tx) {
- dev_err(si->dev, "prep_slave_sg() failed\n");
- return;
- }
- tx->callback = pxa_irda_fir_dma_rx_irq;
- tx->callback_param = si;
- si->rx_cookie = dmaengine_submit(tx);
- dma_async_issue_pending(si->rxdma);
-}
-
-inline static void pxa_irda_fir_dma_tx_start(struct pxa_irda *si)
-{
- struct dma_async_tx_descriptor *tx;
-
- tx = dmaengine_prep_slave_single(si->txdma, si->dma_tx_buff_phy,
- si->dma_tx_buff_len, DMA_TO_DEVICE,
- DMA_PREP_INTERRUPT);
- if (!tx) {
- dev_err(si->dev, "prep_slave_sg() failed\n");
- return;
- }
- tx->callback = pxa_irda_fir_dma_tx_irq;
- tx->callback_param = si;
- si->tx_cookie = dmaengine_submit(tx);
- dma_async_issue_pending(si->rxdma);
-}
-
-/*
- * Set the IrDA communications mode.
- */
-static void pxa_irda_set_mode(struct pxa_irda *si, int mode)
-{
- if (si->pdata->transceiver_mode)
- si->pdata->transceiver_mode(si->dev, mode);
- else {
- if (gpio_is_valid(si->pdata->gpio_pwdown))
- gpio_set_value(si->pdata->gpio_pwdown,
- !(mode & IR_OFF) ^
- !si->pdata->gpio_pwdown_inverted);
- pxa2xx_transceiver_mode(si->dev, mode);
- }
-}
-
-/*
- * Set the IrDA communications speed.
- */
-static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
-{
- unsigned long flags;
- unsigned int divisor;
-
- switch (speed) {
- case 9600: case 19200: case 38400:
- case 57600: case 115200:
-
- /* refer to PXA250/210 Developer's Manual 10-7 */
- /* BaudRate = 14.7456 MHz / (16*Divisor) */
- divisor = 14745600 / (16 * speed);
-
- local_irq_save(flags);
-
- if (IS_FIR(si)) {
- /* stop RX DMA */
- dmaengine_terminate_all(si->rxdma);
- /* disable FICP */
- ficp_writel(si, 0, ICCR0);
- pxa_irda_disable_clk(si);
-
- /* set board transceiver to SIR mode */
- pxa_irda_set_mode(si, IR_SIRMODE);
-
- /* enable the STUART clock */
- pxa_irda_enable_sirclk(si);
- }
-
- /* disable STUART first */
- stuart_writel(si, 0, STIER);
-
- /* access DLL & DLH */
- stuart_writel(si, stuart_readl(si, STLCR) | LCR_DLAB, STLCR);
- stuart_writel(si, divisor & 0xff, STDLL);
- stuart_writel(si, divisor >> 8, STDLH);
- stuart_writel(si, stuart_readl(si, STLCR) & ~LCR_DLAB, STLCR);
-
- si->speed = speed;
- stuart_writel(si, IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6,
- STISR);
- stuart_writel(si, IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE,
- STIER);
-
- local_irq_restore(flags);
- break;
-
- case 4000000:
- local_irq_save(flags);
-
- /* disable STUART */
- stuart_writel(si, 0, STIER);
- stuart_writel(si, 0, STISR);
- pxa_irda_disable_clk(si);
-
- /* disable FICP first */
- ficp_writel(si, 0, ICCR0);
-
- /* set board transceiver to FIR mode */
- pxa_irda_set_mode(si, IR_FIRMODE);
-
- /* enable the FICP clock */
- pxa_irda_enable_firclk(si);
-
- si->speed = speed;
- pxa_irda_fir_dma_rx_start(si);
- ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0);
-
- local_irq_restore(flags);
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* SIR interrupt service routine. */
-static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct pxa_irda *si = netdev_priv(dev);
- int iir, lsr, data;
-
- iir = stuart_readl(si, STIIR);
-
- switch (iir & 0x0F) {
- case 0x06: /* Receiver Line Status */
- lsr = stuart_readl(si, STLSR);
- while (lsr & LSR_FIFOE) {
- data = stuart_readl(si, STRBR);
- if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) {
- printk(KERN_DEBUG "pxa_ir: sir receiving error\n");
- dev->stats.rx_errors++;
- if (lsr & LSR_FE)
- dev->stats.rx_frame_errors++;
- if (lsr & LSR_OE)
- dev->stats.rx_fifo_errors++;
- } else {
- dev->stats.rx_bytes++;
- async_unwrap_char(dev, &dev->stats,
- &si->rx_buff, data);
- }
- lsr = stuart_readl(si, STLSR);
- }
- si->last_clk = sched_clock();
- break;
-
- case 0x04: /* Received Data Available */
- /* forth through */
-
- case 0x0C: /* Character Timeout Indication */
- do {
- dev->stats.rx_bytes++;
- async_unwrap_char(dev, &dev->stats, &si->rx_buff,
- stuart_readl(si, STRBR));
- } while (stuart_readl(si, STLSR) & LSR_DR);
- si->last_clk = sched_clock();
- break;
-
- case 0x02: /* Transmit FIFO Data Request */
- while ((si->tx_buff.len) &&
- (stuart_readl(si, STLSR) & LSR_TDRQ)) {
- stuart_writel(si, *si->tx_buff.data++, STTHR);
- si->tx_buff.len -= 1;
- }
-
- if (si->tx_buff.len == 0) {
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += si->tx_buff.data - si->tx_buff.head;
-
- /* We need to ensure that the transmitter has finished. */
- while ((stuart_readl(si, STLSR) & LSR_TEMT) == 0)
- cpu_relax();
- si->last_clk = sched_clock();
-
- /*
- * Ok, we've finished transmitting. Now enable
- * the receiver. Sometimes we get a receive IRQ
- * immediately after a transmit...
- */
- if (si->newspeed) {
- pxa_irda_set_speed(si, si->newspeed);
- si->newspeed = 0;
- } else {
- /* enable IR Receiver, disable IR Transmitter */
- stuart_writel(si, IrSR_IR_RECEIVE_ON |
- IrSR_XMODE_PULSE_1_6, STISR);
- /* enable STUART and receive interrupts */
- stuart_writel(si, IER_UUE | IER_RLSE |
- IER_RAVIE | IER_RTIOE, STIER);
- }
- /* I'm hungry! */
- netif_wake_queue(dev);
- }
- break;
- }
-
- return IRQ_HANDLED;
-}
-
-/* FIR Receive DMA interrupt handler */
-static void pxa_irda_fir_dma_rx_irq(void *data)
-{
- struct net_device *dev = data;
- struct pxa_irda *si = netdev_priv(dev);
-
- dmaengine_terminate_all(si->rxdma);
- netdev_dbg(dev, "pxa_ir: fir rx dma bus error\n");
-}
-
-/* FIR Transmit DMA interrupt handler */
-static void pxa_irda_fir_dma_tx_irq(void *data)
-{
- struct net_device *dev = data;
- struct pxa_irda *si = netdev_priv(dev);
-
- dmaengine_terminate_all(si->txdma);
- if (dmaengine_tx_status(si->txdma, si->tx_cookie, NULL) == DMA_ERROR) {
- dev->stats.tx_errors++;
- } else {
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += si->dma_tx_buff_len;
- }
-
- while (ficp_readl(si, ICSR1) & ICSR1_TBY)
- cpu_relax();
- si->last_clk = sched_clock();
-
- /*
- * HACK: It looks like the TBY bit is dropped too soon.
- * Without this delay things break.
- */
- udelay(120);
-
- if (si->newspeed) {
- pxa_irda_set_speed(si, si->newspeed);
- si->newspeed = 0;
- } else {
- int i = 64;
-
- ficp_writel(si, 0, ICCR0);
- pxa_irda_fir_dma_rx_start(si);
- while ((ficp_readl(si, ICSR1) & ICSR1_RNE) && i--)
- ficp_readl(si, ICDR);
- ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0);
-
- if (i < 0)
- printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n");
- }
- netif_wake_queue(dev);
-}
-
-/* EIF(Error in FIFO/End in Frame) handler for FIR */
-static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, int icsr0)
-{
- unsigned int len, stat, data;
- struct dma_tx_state state;
-
- /* Get the current data position. */
-
- dmaengine_tx_status(si->rxdma, si->rx_cookie, &state);
- len = IRDA_FRAME_SIZE_LIMIT - state.residue;
-
- do {
- /* Read Status, and then Data. */
- stat = ficp_readl(si, ICSR1);
- rmb();
- data = ficp_readl(si, ICDR);
-
- if (stat & (ICSR1_CRE | ICSR1_ROR)) {
- dev->stats.rx_errors++;
- if (stat & ICSR1_CRE) {
- printk(KERN_DEBUG "pxa_ir: fir receive CRC error\n");
- dev->stats.rx_crc_errors++;
- }
- if (stat & ICSR1_ROR) {
- printk(KERN_DEBUG "pxa_ir: fir receive overrun\n");
- dev->stats.rx_over_errors++;
- }
- } else {
- si->dma_rx_buff[len++] = data;
- }
- /* If we hit the end of frame, there's no point in continuing. */
- if (stat & ICSR1_EOF)
- break;
- } while (ficp_readl(si, ICSR0) & ICSR0_EIF);
-
- if (stat & ICSR1_EOF) {
- /* end of frame. */
- struct sk_buff *skb;
-
- if (icsr0 & ICSR0_FRE) {
- printk(KERN_ERR "pxa_ir: dropping erroneous frame\n");
- dev->stats.rx_dropped++;
- return;
- }
-
- skb = alloc_skb(len+1,GFP_ATOMIC);
- if (!skb) {
- printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n");
- dev->stats.rx_dropped++;
- return;
- }
-
- /* Align IP header to 20 bytes */
- skb_reserve(skb, 1);
- skb_copy_to_linear_data(skb, si->dma_rx_buff, len);
- skb_put(skb, len);
-
- /* Feed it to IrLAP */
- skb->dev = dev;
- skb_reset_mac_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- netif_rx(skb);
-
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += len;
- }
-}
-
-/* FIR interrupt handler */
-static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct pxa_irda *si = netdev_priv(dev);
- int icsr0, i = 64;
-
- /* stop RX DMA */
- dmaengine_terminate_all(si->rxdma);
- si->last_clk = sched_clock();
- icsr0 = ficp_readl(si, ICSR0);
-
- if (icsr0 & (ICSR0_FRE | ICSR0_RAB)) {
- if (icsr0 & ICSR0_FRE) {
- printk(KERN_DEBUG "pxa_ir: fir receive frame error\n");
- dev->stats.rx_frame_errors++;
- } else {
- printk(KERN_DEBUG "pxa_ir: fir receive abort\n");
- dev->stats.rx_errors++;
- }
- ficp_writel(si, icsr0 & (ICSR0_FRE | ICSR0_RAB), ICSR0);
- }
-
- if (icsr0 & ICSR0_EIF) {
- /* An error in FIFO occurred, or there is a end of frame */
- pxa_irda_fir_irq_eif(si, dev, icsr0);
- }
-
- ficp_writel(si, 0, ICCR0);
- pxa_irda_fir_dma_rx_start(si);
- while ((ficp_readl(si, ICSR1) & ICSR1_RNE) && i--)
- ficp_readl(si, ICDR);
- ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0);
-
- if (i < 0)
- printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n");
-
- return IRQ_HANDLED;
-}
-
-/* hard_xmit interface of irda device */
-static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct pxa_irda *si = netdev_priv(dev);
- int speed = irda_get_next_speed(skb);
-
- /*
- * Does this packet contain a request to change the interface
- * speed? If so, remember it until we complete the transmission
- * of this frame.
- */
- if (speed != si->speed && speed != -1)
- si->newspeed = speed;
-
- /*
- * If this is an empty frame, we can bypass a lot.
- */
- if (skb->len == 0) {
- if (si->newspeed) {
- si->newspeed = 0;
- pxa_irda_set_speed(si, speed);
- }
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- netif_stop_queue(dev);
-
- if (!IS_FIR(si)) {
- si->tx_buff.data = si->tx_buff.head;
- si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize);
-
- /* Disable STUART interrupts and switch to transmit mode. */
- stuart_writel(si, 0, STIER);
- stuart_writel(si, IrSR_IR_TRANSMIT_ON | IrSR_XMODE_PULSE_1_6,
- STISR);
-
- /* enable STUART and transmit interrupts */
- stuart_writel(si, IER_UUE | IER_TIE, STIER);
- } else {
- unsigned long mtt = irda_get_mtt(skb);
-
- si->dma_tx_buff_len = skb->len;
- skb_copy_from_linear_data(skb, si->dma_tx_buff, skb->len);
-
- if (mtt)
- while ((sched_clock() - si->last_clk) * 1000 < mtt)
- cpu_relax();
-
- /* stop RX DMA, disable FICP */
- dmaengine_terminate_all(si->rxdma);
- ficp_writel(si, 0, ICCR0);
-
- pxa_irda_fir_dma_tx_start(si);
- ficp_writel(si, ICCR0_ITR | ICCR0_TXE, ICCR0);
- }
-
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
-{
- struct if_irda_req *rq = (struct if_irda_req *)ifreq;
- struct pxa_irda *si = netdev_priv(dev);
- int ret;
-
- switch (cmd) {
- case SIOCSBANDWIDTH:
- ret = -EPERM;
- if (capable(CAP_NET_ADMIN)) {
- /*
- * We are unable to set the speed if the
- * device is not running.
- */
- if (netif_running(dev)) {
- ret = pxa_irda_set_speed(si,
- rq->ifr_baudrate);
- } else {
- printk(KERN_INFO "pxa_ir: SIOCSBANDWIDTH: !netif_running\n");
- ret = 0;
- }
- }
- break;
-
- case SIOCSMEDIABUSY:
- ret = -EPERM;
- if (capable(CAP_NET_ADMIN)) {
- irda_device_set_media_busy(dev, TRUE);
- ret = 0;
- }
- break;
-
- case SIOCGRECEIVING:
- ret = 0;
- rq->ifr_receiving = IS_FIR(si) ? 0
- : si->rx_buff.state != OUTSIDE_FRAME;
- break;
-
- default:
- ret = -EOPNOTSUPP;
- break;
- }
-
- return ret;
-}
-
-static void pxa_irda_startup(struct pxa_irda *si)
-{
- /* Disable STUART interrupts */
- stuart_writel(si, 0, STIER);
- /* enable STUART interrupt to the processor */
- stuart_writel(si, MCR_OUT2, STMCR);
- /* configure SIR frame format: StartBit - Data 7 ... Data 0 - Stop Bit */
- stuart_writel(si, LCR_WLS0 | LCR_WLS1, STLCR);
- /* enable FIFO, we use FIFO to improve performance */
- stuart_writel(si, FCR_TRFIFOE | FCR_ITL_32, STFCR);
-
- /* disable FICP */
- ficp_writel(si, 0, ICCR0);
- /* configure FICP ICCR2 */
- ficp_writel(si, ICCR2_TXP | ICCR2_TRIG_32, ICCR2);
-
- /* force SIR reinitialization */
- si->speed = 4000000;
- pxa_irda_set_speed(si, 9600);
-
- printk(KERN_DEBUG "pxa_ir: irda startup\n");
-}
-
-static void pxa_irda_shutdown(struct pxa_irda *si)
-{
- unsigned long flags;
-
- local_irq_save(flags);
-
- /* disable STUART and interrupt */
- stuart_writel(si, 0, STIER);
- /* disable STUART SIR mode */
- stuart_writel(si, 0, STISR);
-
- /* disable DMA */
- dmaengine_terminate_all(si->rxdma);
- dmaengine_terminate_all(si->txdma);
- /* disable FICP */
- ficp_writel(si, 0, ICCR0);
-
- /* disable the STUART or FICP clocks */
- pxa_irda_disable_clk(si);
-
- local_irq_restore(flags);
-
- /* power off board transceiver */
- pxa_irda_set_mode(si, IR_OFF);
-
- printk(KERN_DEBUG "pxa_ir: irda shutdown\n");
-}
-
-static int pxa_irda_start(struct net_device *dev)
-{
- struct pxa_irda *si = netdev_priv(dev);
- dma_cap_mask_t mask;
- struct dma_slave_config config;
- struct pxad_param param;
- int err;
-
- si->speed = 9600;
-
- err = request_irq(si->uart_irq, pxa_irda_sir_irq, 0, dev->name, dev);
- if (err)
- goto err_irq1;
-
- err = request_irq(si->icp_irq, pxa_irda_fir_irq, 0, dev->name, dev);
- if (err)
- goto err_irq2;
-
- /*
- * The interrupt must remain disabled for now.
- */
- disable_irq(si->uart_irq);
- disable_irq(si->icp_irq);
-
- err = -EBUSY;
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- param.prio = PXAD_PRIO_LOWEST;
-
- memset(&config, 0, sizeof(config));
- config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- config.src_addr = (dma_addr_t)si->irda_base + ICDR;
- config.dst_addr = (dma_addr_t)si->irda_base + ICDR;
- config.src_maxburst = 32;
- config.dst_maxburst = 32;
-
- param.drcmr = si->drcmr_rx;
- si->rxdma = dma_request_slave_channel_compat(mask, pxad_filter_fn,
- &param, &dev->dev, "rx");
- if (!si->rxdma)
- goto err_rx_dma;
-
- param.drcmr = si->drcmr_tx;
- si->txdma = dma_request_slave_channel_compat(mask, pxad_filter_fn,
- &param, &dev->dev, "tx");
- if (!si->txdma)
- goto err_tx_dma;
-
- err = dmaengine_slave_config(si->rxdma, &config);
- if (err)
- goto err_dma_rx_buff;
- err = dmaengine_slave_config(si->txdma, &config);
- if (err)
- goto err_dma_rx_buff;
-
- err = -ENOMEM;
- si->dma_rx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT,
- &si->dma_rx_buff_phy, GFP_KERNEL);
- if (!si->dma_rx_buff)
- goto err_dma_rx_buff;
-
- si->dma_tx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT,
- &si->dma_tx_buff_phy, GFP_KERNEL);
- if (!si->dma_tx_buff)
- goto err_dma_tx_buff;
-
- /* Setup the serial port for the initial speed. */
- pxa_irda_startup(si);
-
- /*
- * Open a new IrLAP layer instance.
- */
- si->irlap = irlap_open(dev, &si->qos, "pxa");
- err = -ENOMEM;
- if (!si->irlap)
- goto err_irlap;
-
- /*
- * Now enable the interrupt and start the queue
- */
- enable_irq(si->uart_irq);
- enable_irq(si->icp_irq);
- netif_start_queue(dev);
-
- printk(KERN_DEBUG "pxa_ir: irda driver opened\n");
-
- return 0;
-
-err_irlap:
- pxa_irda_shutdown(si);
- dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy);
-err_dma_tx_buff:
- dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy);
-err_dma_rx_buff:
- dma_release_channel(si->txdma);
-err_tx_dma:
- dma_release_channel(si->rxdma);
-err_rx_dma:
- free_irq(si->icp_irq, dev);
-err_irq2:
- free_irq(si->uart_irq, dev);
-err_irq1:
-
- return err;
-}
-
-static int pxa_irda_stop(struct net_device *dev)
-{
- struct pxa_irda *si = netdev_priv(dev);
-
- netif_stop_queue(dev);
-
- pxa_irda_shutdown(si);
-
- /* Stop IrLAP */
- if (si->irlap) {
- irlap_close(si->irlap);
- si->irlap = NULL;
- }
-
- free_irq(si->uart_irq, dev);
- free_irq(si->icp_irq, dev);
-
- dmaengine_terminate_all(si->rxdma);
- dmaengine_terminate_all(si->txdma);
- dma_release_channel(si->rxdma);
- dma_release_channel(si->txdma);
-
- if (si->dma_rx_buff)
- dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy);
- if (si->dma_tx_buff)
- dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy);
-
- printk(KERN_DEBUG "pxa_ir: irda driver closed\n");
- return 0;
-}
-
-static int pxa_irda_suspend(struct platform_device *_dev, pm_message_t state)
-{
- struct net_device *dev = platform_get_drvdata(_dev);
- struct pxa_irda *si;
-
- if (dev && netif_running(dev)) {
- si = netdev_priv(dev);
- netif_device_detach(dev);
- pxa_irda_shutdown(si);
- }
-
- return 0;
-}
-
-static int pxa_irda_resume(struct platform_device *_dev)
-{
- struct net_device *dev = platform_get_drvdata(_dev);
- struct pxa_irda *si;
-
- if (dev && netif_running(dev)) {
- si = netdev_priv(dev);
- pxa_irda_startup(si);
- netif_device_attach(dev);
- netif_wake_queue(dev);
- }
-
- return 0;
-}
-
-
-static int pxa_irda_init_iobuf(iobuff_t *io, int size)
-{
- io->head = kmalloc(size, GFP_KERNEL | GFP_DMA);
- if (io->head != NULL) {
- io->truesize = size;
- io->in_frame = FALSE;
- io->state = OUTSIDE_FRAME;
- io->data = io->head;
- }
- return io->head ? 0 : -ENOMEM;
-}
-
-static const struct net_device_ops pxa_irda_netdev_ops = {
- .ndo_open = pxa_irda_start,
- .ndo_stop = pxa_irda_stop,
- .ndo_start_xmit = pxa_irda_hard_xmit,
- .ndo_do_ioctl = pxa_irda_ioctl,
-};
-
-static int pxa_irda_probe(struct platform_device *pdev)
-{
- struct net_device *dev;
- struct resource *res;
- struct pxa_irda *si;
- void __iomem *ficp, *stuart;
- unsigned int baudrate_mask;
- int err;
-
- if (!pdev->dev.platform_data)
- return -ENODEV;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ficp = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ficp)) {
- dev_err(&pdev->dev, "resource ficp not defined\n");
- return PTR_ERR(ficp);
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- stuart = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(stuart)) {
- dev_err(&pdev->dev, "resource stuart not defined\n");
- return PTR_ERR(stuart);
- }
-
- dev = alloc_irdadev(sizeof(struct pxa_irda));
- if (!dev) {
- err = -ENOMEM;
- goto err_mem_1;
- }
-
- SET_NETDEV_DEV(dev, &pdev->dev);
- si = netdev_priv(dev);
- si->dev = &pdev->dev;
- si->pdata = pdev->dev.platform_data;
-
- si->irda_base = ficp;
- si->stuart_base = stuart;
- si->uart_irq = platform_get_irq(pdev, 0);
- si->icp_irq = platform_get_irq(pdev, 1);
-
- si->sir_clk = devm_clk_get(&pdev->dev, "UARTCLK");
- si->fir_clk = devm_clk_get(&pdev->dev, "FICPCLK");
- if (IS_ERR(si->sir_clk) || IS_ERR(si->fir_clk)) {
- err = PTR_ERR(IS_ERR(si->sir_clk) ? si->sir_clk : si->fir_clk);
- goto err_mem_4;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (res)
- si->drcmr_rx = res->start;
- res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (res)
- si->drcmr_tx = res->start;
-
- /*
- * Initialise the SIR buffers
- */
- err = pxa_irda_init_iobuf(&si->rx_buff, 14384);
- if (err)
- goto err_mem_4;
- err = pxa_irda_init_iobuf(&si->tx_buff, 4000);
- if (err)
- goto err_mem_5;
-
- if (gpio_is_valid(si->pdata->gpio_pwdown)) {
- err = gpio_request(si->pdata->gpio_pwdown, "IrDA switch");
- if (err)
- goto err_startup;
- err = gpio_direction_output(si->pdata->gpio_pwdown,
- !si->pdata->gpio_pwdown_inverted);
- if (err) {
- gpio_free(si->pdata->gpio_pwdown);
- goto err_startup;
- }
- }
-
- if (si->pdata->startup) {
- err = si->pdata->startup(si->dev);
- if (err)
- goto err_startup;
- }
-
- if (gpio_is_valid(si->pdata->gpio_pwdown) && si->pdata->startup)
- dev_warn(si->dev, "gpio_pwdown and startup() both defined!\n");
-
- dev->netdev_ops = &pxa_irda_netdev_ops;
-
- irda_init_max_qos_capabilies(&si->qos);
-
- baudrate_mask = 0;
- if (si->pdata->transceiver_cap & IR_SIRMODE)
- baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
- if (si->pdata->transceiver_cap & IR_FIRMODE)
- baudrate_mask |= IR_4000000 << 8;
-
- si->qos.baud_rate.bits &= baudrate_mask;
- si->qos.min_turn_time.bits = 7; /* 1ms or more */
-
- irda_qos_bits_to_value(&si->qos);
-
- err = register_netdev(dev);
-
- if (err == 0)
- platform_set_drvdata(pdev, dev);
-
- if (err) {
- if (si->pdata->shutdown)
- si->pdata->shutdown(si->dev);
-err_startup:
- kfree(si->tx_buff.head);
-err_mem_5:
- kfree(si->rx_buff.head);
-err_mem_4:
- free_netdev(dev);
- }
-err_mem_1:
- return err;
-}
-
-static int pxa_irda_remove(struct platform_device *_dev)
-{
- struct net_device *dev = platform_get_drvdata(_dev);
-
- if (dev) {
- struct pxa_irda *si = netdev_priv(dev);
- unregister_netdev(dev);
- if (gpio_is_valid(si->pdata->gpio_pwdown))
- gpio_free(si->pdata->gpio_pwdown);
- if (si->pdata->shutdown)
- si->pdata->shutdown(si->dev);
- kfree(si->tx_buff.head);
- kfree(si->rx_buff.head);
- free_netdev(dev);
- }
-
- return 0;
-}
-
-static struct platform_driver pxa_ir_driver = {
- .driver = {
- .name = "pxa2xx-ir",
- },
- .probe = pxa_irda_probe,
- .remove = pxa_irda_remove,
- .suspend = pxa_irda_suspend,
- .resume = pxa_irda_resume,
-};
-
-module_platform_driver(pxa_ir_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pxa2xx-ir");
diff --git a/drivers/staging/irda/drivers/sa1100_ir.c b/drivers/staging/irda/drivers/sa1100_ir.c
deleted file mode 100644
index b6e44ff4e373..000000000000
--- a/drivers/staging/irda/drivers/sa1100_ir.c
+++ /dev/null
@@ -1,1150 +0,0 @@
-/*
- * linux/drivers/net/irda/sa1100_ir.c
- *
- * Copyright (C) 2000-2001 Russell King
- *
- * 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.
- *
- * Infra-red driver for the StrongARM SA1100 embedded microprocessor
- *
- * Note that we don't have to worry about the SA1111's DMA bugs in here,
- * so we use the straight forward dma_map_* functions with a null pointer.
- *
- * This driver takes one kernel command line parameter, sa1100ir=, with
- * the following options:
- * max_rate:baudrate - set the maximum baud rate
- * power_level:level - set the transmitter power level
- * tx_lpm:0|1 - set transmit low power mode
- */
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/slab.h>
-#include <linux/rtnetlink.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-#include <linux/sa11x0-dma.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/irda_device.h>
-
-#include <mach/hardware.h>
-#include <linux/platform_data/irda-sa11x0.h>
-
-static int power_level = 3;
-static int tx_lpm;
-static int max_rate = 4000000;
-
-struct sa1100_buf {
- struct device *dev;
- struct sk_buff *skb;
- struct scatterlist sg;
- struct dma_chan *chan;
- dma_cookie_t cookie;
-};
-
-struct sa1100_irda {
- unsigned char utcr4;
- unsigned char power;
- unsigned char open;
-
- int speed;
- int newspeed;
-
- struct sa1100_buf dma_rx;
- struct sa1100_buf dma_tx;
-
- struct device *dev;
- struct irda_platform_data *pdata;
- struct irlap_cb *irlap;
- struct qos_info qos;
-
- iobuff_t tx_buff;
- iobuff_t rx_buff;
-
- int (*tx_start)(struct sk_buff *, struct net_device *, struct sa1100_irda *);
- irqreturn_t (*irq)(struct net_device *, struct sa1100_irda *);
-};
-
-static int sa1100_irda_set_speed(struct sa1100_irda *, int);
-
-#define IS_FIR(si) ((si)->speed >= 4000000)
-
-#define HPSIR_MAX_RXLEN 2047
-
-static struct dma_slave_config sa1100_irda_sir_tx = {
- .direction = DMA_TO_DEVICE,
- .dst_addr = __PREG(Ser2UTDR),
- .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
- .dst_maxburst = 4,
-};
-
-static struct dma_slave_config sa1100_irda_fir_rx = {
- .direction = DMA_FROM_DEVICE,
- .src_addr = __PREG(Ser2HSDR),
- .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
- .src_maxburst = 8,
-};
-
-static struct dma_slave_config sa1100_irda_fir_tx = {
- .direction = DMA_TO_DEVICE,
- .dst_addr = __PREG(Ser2HSDR),
- .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
- .dst_maxburst = 8,
-};
-
-static unsigned sa1100_irda_dma_xferred(struct sa1100_buf *buf)
-{
- struct dma_chan *chan = buf->chan;
- struct dma_tx_state state;
- enum dma_status status;
-
- status = chan->device->device_tx_status(chan, buf->cookie, &state);
- if (status != DMA_PAUSED)
- return 0;
-
- return sg_dma_len(&buf->sg) - state.residue;
-}
-
-static int sa1100_irda_dma_request(struct device *dev, struct sa1100_buf *buf,
- const char *name, struct dma_slave_config *cfg)
-{
- dma_cap_mask_t m;
- int ret;
-
- dma_cap_zero(m);
- dma_cap_set(DMA_SLAVE, m);
-
- buf->chan = dma_request_channel(m, sa11x0_dma_filter_fn, (void *)name);
- if (!buf->chan) {
- dev_err(dev, "unable to request DMA channel for %s\n",
- name);
- return -ENOENT;
- }
-
- ret = dmaengine_slave_config(buf->chan, cfg);
- if (ret)
- dev_warn(dev, "DMA slave_config for %s returned %d\n",
- name, ret);
-
- buf->dev = buf->chan->device->dev;
-
- return 0;
-}
-
-static void sa1100_irda_dma_start(struct sa1100_buf *buf,
- enum dma_transfer_direction dir, dma_async_tx_callback cb, void *cb_p)
-{
- struct dma_async_tx_descriptor *desc;
- struct dma_chan *chan = buf->chan;
-
- desc = dmaengine_prep_slave_sg(chan, &buf->sg, 1, dir,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (desc) {
- desc->callback = cb;
- desc->callback_param = cb_p;
- buf->cookie = dmaengine_submit(desc);
- dma_async_issue_pending(chan);
- }
-}
-
-/*
- * Allocate and map the receive buffer, unless it is already allocated.
- */
-static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
-{
- if (si->dma_rx.skb)
- return 0;
-
- si->dma_rx.skb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
- if (!si->dma_rx.skb) {
- printk(KERN_ERR "sa1100_ir: out of memory for RX SKB\n");
- return -ENOMEM;
- }
-
- /*
- * Align any IP headers that may be contained
- * within the frame.
- */
- skb_reserve(si->dma_rx.skb, 1);
-
- sg_set_buf(&si->dma_rx.sg, si->dma_rx.skb->data, HPSIR_MAX_RXLEN);
- if (dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE) == 0) {
- dev_kfree_skb_any(si->dma_rx.skb);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-/*
- * We want to get here as soon as possible, and get the receiver setup.
- * We use the existing buffer.
- */
-static void sa1100_irda_rx_dma_start(struct sa1100_irda *si)
-{
- if (!si->dma_rx.skb) {
- printk(KERN_ERR "sa1100_ir: rx buffer went missing\n");
- return;
- }
-
- /*
- * First empty receive FIFO
- */
- Ser2HSCR0 = HSCR0_HSSP;
-
- /*
- * Enable the DMA, receiver and receive interrupt.
- */
- dmaengine_terminate_all(si->dma_rx.chan);
- sa1100_irda_dma_start(&si->dma_rx, DMA_DEV_TO_MEM, NULL, NULL);
-
- Ser2HSCR0 = HSCR0_HSSP | HSCR0_RXE;
-}
-
-static void sa1100_irda_check_speed(struct sa1100_irda *si)
-{
- if (si->newspeed) {
- sa1100_irda_set_speed(si, si->newspeed);
- si->newspeed = 0;
- }
-}
-
-/*
- * HP-SIR format support.
- */
-static void sa1100_irda_sirtxdma_irq(void *id)
-{
- struct net_device *dev = id;
- struct sa1100_irda *si = netdev_priv(dev);
-
- dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE);
- dev_kfree_skb(si->dma_tx.skb);
- si->dma_tx.skb = NULL;
-
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += sg_dma_len(&si->dma_tx.sg);
-
- /* We need to ensure that the transmitter has finished. */
- do
- rmb();
- while (Ser2UTSR1 & UTSR1_TBY);
-
- /*
- * Ok, we've finished transmitting. Now enable the receiver.
- * Sometimes we get a receive IRQ immediately after a transmit...
- */
- Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
- Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
-
- sa1100_irda_check_speed(si);
-
- /* I'm hungry! */
- netif_wake_queue(dev);
-}
-
-static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev,
- struct sa1100_irda *si)
-{
- si->tx_buff.data = si->tx_buff.head;
- si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data,
- si->tx_buff.truesize);
-
- si->dma_tx.skb = skb;
- sg_set_buf(&si->dma_tx.sg, si->tx_buff.data, si->tx_buff.len);
- if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) {
- si->dma_tx.skb = NULL;
- netif_wake_queue(dev);
- dev->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
-
- sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_sirtxdma_irq, dev);
-
- /*
- * The mean turn-around time is enforced by XBOF padding,
- * so we don't have to do anything special here.
- */
- Ser2UTCR3 = UTCR3_TXE;
-
- return NETDEV_TX_OK;
-}
-
-static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_irda *si)
-{
- int status;
-
- status = Ser2UTSR0;
-
- /*
- * Deal with any receive errors first. The bytes in error may be
- * the only bytes in the receive FIFO, so we do this first.
- */
- while (status & UTSR0_EIF) {
- int stat, data;
-
- stat = Ser2UTSR1;
- data = Ser2UTDR;
-
- if (stat & (UTSR1_FRE | UTSR1_ROR)) {
- dev->stats.rx_errors++;
- if (stat & UTSR1_FRE)
- dev->stats.rx_frame_errors++;
- if (stat & UTSR1_ROR)
- dev->stats.rx_fifo_errors++;
- } else
- async_unwrap_char(dev, &dev->stats, &si->rx_buff, data);
-
- status = Ser2UTSR0;
- }
-
- /*
- * We must clear certain bits.
- */
- Ser2UTSR0 = status & (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
-
- if (status & UTSR0_RFS) {
- /*
- * There are at least 4 bytes in the FIFO. Read 3 bytes
- * and leave the rest to the block below.
- */
- async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
- async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
- async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
- }
-
- if (status & (UTSR0_RFS | UTSR0_RID)) {
- /*
- * Fifo contains more than 1 character.
- */
- do {
- async_unwrap_char(dev, &dev->stats, &si->rx_buff,
- Ser2UTDR);
- } while (Ser2UTSR1 & UTSR1_RNE);
-
- }
-
- return IRQ_HANDLED;
-}
-
-/*
- * FIR format support.
- */
-static void sa1100_irda_firtxdma_irq(void *id)
-{
- struct net_device *dev = id;
- struct sa1100_irda *si = netdev_priv(dev);
- struct sk_buff *skb;
-
- /*
- * Wait for the transmission to complete. Unfortunately,
- * the hardware doesn't give us an interrupt to indicate
- * "end of frame".
- */
- do
- rmb();
- while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY);
-
- /*
- * Clear the transmit underrun bit.
- */
- Ser2HSSR0 = HSSR0_TUR;
-
- /*
- * Do we need to change speed? Note that we're lazy
- * here - we don't free the old dma_rx.skb. We don't need
- * to allocate a buffer either.
- */
- sa1100_irda_check_speed(si);
-
- /*
- * Start reception. This disables the transmitter for
- * us. This will be using the existing RX buffer.
- */
- sa1100_irda_rx_dma_start(si);
-
- /* Account and free the packet. */
- skb = si->dma_tx.skb;
- if (skb) {
- dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1,
- DMA_TO_DEVICE);
- dev->stats.tx_packets ++;
- dev->stats.tx_bytes += skb->len;
- dev_kfree_skb_irq(skb);
- si->dma_tx.skb = NULL;
- }
-
- /*
- * Make sure that the TX queue is available for sending
- * (for retries). TX has priority over RX at all times.
- */
- netif_wake_queue(dev);
-}
-
-static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev,
- struct sa1100_irda *si)
-{
- int mtt = irda_get_mtt(skb);
-
- si->dma_tx.skb = skb;
- sg_set_buf(&si->dma_tx.sg, skb->data, skb->len);
- if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) {
- si->dma_tx.skb = NULL;
- netif_wake_queue(dev);
- dev->stats.tx_dropped++;
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_firtxdma_irq, dev);
-
- /*
- * If we have a mean turn-around time, impose the specified
- * specified delay. We could shorten this by timing from
- * the point we received the packet.
- */
- if (mtt)
- udelay(mtt);
-
- Ser2HSCR0 = HSCR0_HSSP | HSCR0_TXE;
-
- return NETDEV_TX_OK;
-}
-
-static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev)
-{
- struct sk_buff *skb = si->dma_rx.skb;
- unsigned int len, stat, data;
-
- if (!skb) {
- printk(KERN_ERR "sa1100_ir: SKB is NULL!\n");
- return;
- }
-
- /*
- * Get the current data position.
- */
- len = sa1100_irda_dma_xferred(&si->dma_rx);
- if (len > HPSIR_MAX_RXLEN)
- len = HPSIR_MAX_RXLEN;
- dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
-
- do {
- /*
- * Read Status, and then Data.
- */
- stat = Ser2HSSR1;
- rmb();
- data = Ser2HSDR;
-
- if (stat & (HSSR1_CRE | HSSR1_ROR)) {
- dev->stats.rx_errors++;
- if (stat & HSSR1_CRE)
- dev->stats.rx_crc_errors++;
- if (stat & HSSR1_ROR)
- dev->stats.rx_frame_errors++;
- } else
- skb->data[len++] = data;
-
- /*
- * If we hit the end of frame, there's
- * no point in continuing.
- */
- if (stat & HSSR1_EOF)
- break;
- } while (Ser2HSSR0 & HSSR0_EIF);
-
- if (stat & HSSR1_EOF) {
- si->dma_rx.skb = NULL;
-
- skb_put(skb, len);
- skb->dev = dev;
- skb_reset_mac_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += len;
-
- /*
- * Before we pass the buffer up, allocate a new one.
- */
- sa1100_irda_rx_alloc(si);
-
- netif_rx(skb);
- } else {
- /*
- * Remap the buffer - it was previously mapped, and we
- * hope that this succeeds.
- */
- dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
- }
-}
-
-/*
- * We only have to handle RX events here; transmit events go via the TX
- * DMA handler. We disable RX, process, and the restart RX.
- */
-static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_irda *si)
-{
- /*
- * Stop RX DMA
- */
- dmaengine_pause(si->dma_rx.chan);
-
- /*
- * Framing error - we throw away the packet completely.
- * Clearing RXE flushes the error conditions and data
- * from the fifo.
- */
- if (Ser2HSSR0 & (HSSR0_FRE | HSSR0_RAB)) {
- dev->stats.rx_errors++;
-
- if (Ser2HSSR0 & HSSR0_FRE)
- dev->stats.rx_frame_errors++;
-
- /*
- * Clear out the DMA...
- */
- Ser2HSCR0 = HSCR0_HSSP;
-
- /*
- * Clear selected status bits now, so we
- * don't miss them next time around.
- */
- Ser2HSSR0 = HSSR0_FRE | HSSR0_RAB;
- }
-
- /*
- * Deal with any receive errors. The any of the lowest
- * 8 bytes in the FIFO may contain an error. We must read
- * them one by one. The "error" could even be the end of
- * packet!
- */
- if (Ser2HSSR0 & HSSR0_EIF)
- sa1100_irda_fir_error(si, dev);
-
- /*
- * No matter what happens, we must restart reception.
- */
- sa1100_irda_rx_dma_start(si);
-
- return IRQ_HANDLED;
-}
-
-/*
- * Set the IrDA communications speed.
- */
-static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
-{
- unsigned long flags;
- int brd, ret = -EINVAL;
-
- switch (speed) {
- case 9600: case 19200: case 38400:
- case 57600: case 115200:
- brd = 3686400 / (16 * speed) - 1;
-
- /* Stop the receive DMA, and configure transmit. */
- if (IS_FIR(si)) {
- dmaengine_terminate_all(si->dma_rx.chan);
- dmaengine_slave_config(si->dma_tx.chan,
- &sa1100_irda_sir_tx);
- }
-
- local_irq_save(flags);
-
- Ser2UTCR3 = 0;
- Ser2HSCR0 = HSCR0_UART;
-
- Ser2UTCR1 = brd >> 8;
- Ser2UTCR2 = brd;
-
- /*
- * Clear status register
- */
- Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
- Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
-
- if (si->pdata->set_speed)
- si->pdata->set_speed(si->dev, speed);
-
- si->speed = speed;
- si->tx_start = sa1100_irda_sir_tx_start;
- si->irq = sa1100_irda_sir_irq;
-
- local_irq_restore(flags);
- ret = 0;
- break;
-
- case 4000000:
- if (!IS_FIR(si))
- dmaengine_slave_config(si->dma_tx.chan,
- &sa1100_irda_fir_tx);
-
- local_irq_save(flags);
-
- Ser2HSSR0 = 0xff;
- Ser2HSCR0 = HSCR0_HSSP;
- Ser2UTCR3 = 0;
-
- si->speed = speed;
- si->tx_start = sa1100_irda_fir_tx_start;
- si->irq = sa1100_irda_fir_irq;
-
- if (si->pdata->set_speed)
- si->pdata->set_speed(si->dev, speed);
-
- sa1100_irda_rx_alloc(si);
- sa1100_irda_rx_dma_start(si);
-
- local_irq_restore(flags);
-
- break;
-
- default:
- break;
- }
-
- return ret;
-}
-
-/*
- * Control the power state of the IrDA transmitter.
- * State:
- * 0 - off
- * 1 - short range, lowest power
- * 2 - medium range, medium power
- * 3 - maximum range, high power
- *
- * Currently, only assabet is known to support this.
- */
-static int
-__sa1100_irda_set_power(struct sa1100_irda *si, unsigned int state)
-{
- int ret = 0;
- if (si->pdata->set_power)
- ret = si->pdata->set_power(si->dev, state);
- return ret;
-}
-
-static inline int
-sa1100_set_power(struct sa1100_irda *si, unsigned int state)
-{
- int ret;
-
- ret = __sa1100_irda_set_power(si, state);
- if (ret == 0)
- si->power = state;
-
- return ret;
-}
-
-static irqreturn_t sa1100_irda_irq(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct sa1100_irda *si = netdev_priv(dev);
-
- return si->irq(dev, si);
-}
-
-static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct sa1100_irda *si = netdev_priv(dev);
- int speed = irda_get_next_speed(skb);
-
- /*
- * Does this packet contain a request to change the interface
- * speed? If so, remember it until we complete the transmission
- * of this frame.
- */
- if (speed != si->speed && speed != -1)
- si->newspeed = speed;
-
- /* If this is an empty frame, we can bypass a lot. */
- if (skb->len == 0) {
- sa1100_irda_check_speed(si);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- netif_stop_queue(dev);
-
- /* We must not already have a skb to transmit... */
- BUG_ON(si->dma_tx.skb);
-
- return si->tx_start(skb, dev, si);
-}
-
-static int
-sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
-{
- struct if_irda_req *rq = (struct if_irda_req *)ifreq;
- struct sa1100_irda *si = netdev_priv(dev);
- int ret = -EOPNOTSUPP;
-
- switch (cmd) {
- case SIOCSBANDWIDTH:
- if (capable(CAP_NET_ADMIN)) {
- /*
- * We are unable to set the speed if the
- * device is not running.
- */
- if (si->open) {
- ret = sa1100_irda_set_speed(si,
- rq->ifr_baudrate);
- } else {
- printk("sa1100_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n");
- ret = 0;
- }
- }
- break;
-
- case SIOCSMEDIABUSY:
- ret = -EPERM;
- if (capable(CAP_NET_ADMIN)) {
- irda_device_set_media_busy(dev, TRUE);
- ret = 0;
- }
- break;
-
- case SIOCGRECEIVING:
- rq->ifr_receiving = IS_FIR(si) ? 0
- : si->rx_buff.state != OUTSIDE_FRAME;
- break;
-
- default:
- break;
- }
-
- return ret;
-}
-
-static int sa1100_irda_startup(struct sa1100_irda *si)
-{
- int ret;
-
- /*
- * Ensure that the ports for this device are setup correctly.
- */
- if (si->pdata->startup) {
- ret = si->pdata->startup(si->dev);
- if (ret)
- return ret;
- }
-
- /*
- * Configure PPC for IRDA - we want to drive TXD2 low.
- * We also want to drive this pin low during sleep.
- */
- PPSR &= ~PPC_TXD2;
- PSDR &= ~PPC_TXD2;
- PPDR |= PPC_TXD2;
-
- /*
- * Enable HP-SIR modulation, and ensure that the port is disabled.
- */
- Ser2UTCR3 = 0;
- Ser2HSCR0 = HSCR0_UART;
- Ser2UTCR4 = si->utcr4;
- Ser2UTCR0 = UTCR0_8BitData;
- Ser2HSCR2 = HSCR2_TrDataH | HSCR2_RcDataL;
-
- /*
- * Clear status register
- */
- Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
-
- ret = sa1100_irda_set_speed(si, si->speed = 9600);
- if (ret) {
- Ser2UTCR3 = 0;
- Ser2HSCR0 = 0;
-
- if (si->pdata->shutdown)
- si->pdata->shutdown(si->dev);
- }
-
- return ret;
-}
-
-static void sa1100_irda_shutdown(struct sa1100_irda *si)
-{
- /*
- * Stop all DMA activity.
- */
- dmaengine_terminate_all(si->dma_rx.chan);
- dmaengine_terminate_all(si->dma_tx.chan);
-
- /* Disable the port. */
- Ser2UTCR3 = 0;
- Ser2HSCR0 = 0;
-
- if (si->pdata->shutdown)
- si->pdata->shutdown(si->dev);
-}
-
-static int sa1100_irda_start(struct net_device *dev)
-{
- struct sa1100_irda *si = netdev_priv(dev);
- int err;
-
- si->speed = 9600;
-
- err = sa1100_irda_dma_request(si->dev, &si->dma_rx, "Ser2ICPRc",
- &sa1100_irda_fir_rx);
- if (err)
- goto err_rx_dma;
-
- err = sa1100_irda_dma_request(si->dev, &si->dma_tx, "Ser2ICPTr",
- &sa1100_irda_sir_tx);
- if (err)
- goto err_tx_dma;
-
- /*
- * Setup the serial port for the specified speed.
- */
- err = sa1100_irda_startup(si);
- if (err)
- goto err_startup;
-
- /*
- * Open a new IrLAP layer instance.
- */
- si->irlap = irlap_open(dev, &si->qos, "sa1100");
- err = -ENOMEM;
- if (!si->irlap)
- goto err_irlap;
-
- err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev);
- if (err)
- goto err_irq;
-
- /*
- * Now enable the interrupt and start the queue
- */
- si->open = 1;
- sa1100_set_power(si, power_level); /* low power mode */
-
- netif_start_queue(dev);
- return 0;
-
-err_irq:
- irlap_close(si->irlap);
-err_irlap:
- si->open = 0;
- sa1100_irda_shutdown(si);
-err_startup:
- dma_release_channel(si->dma_tx.chan);
-err_tx_dma:
- dma_release_channel(si->dma_rx.chan);
-err_rx_dma:
- return err;
-}
-
-static int sa1100_irda_stop(struct net_device *dev)
-{
- struct sa1100_irda *si = netdev_priv(dev);
- struct sk_buff *skb;
-
- netif_stop_queue(dev);
-
- si->open = 0;
- sa1100_irda_shutdown(si);
-
- /*
- * If we have been doing any DMA activity, make sure we
- * tidy that up cleanly.
- */
- skb = si->dma_rx.skb;
- if (skb) {
- dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1,
- DMA_FROM_DEVICE);
- dev_kfree_skb(skb);
- si->dma_rx.skb = NULL;
- }
-
- skb = si->dma_tx.skb;
- if (skb) {
- dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1,
- DMA_TO_DEVICE);
- dev_kfree_skb(skb);
- si->dma_tx.skb = NULL;
- }
-
- /* Stop IrLAP */
- if (si->irlap) {
- irlap_close(si->irlap);
- si->irlap = NULL;
- }
-
- /*
- * Free resources
- */
- dma_release_channel(si->dma_tx.chan);
- dma_release_channel(si->dma_rx.chan);
- free_irq(dev->irq, dev);
-
- sa1100_set_power(si, 0);
-
- return 0;
-}
-
-static int sa1100_irda_init_iobuf(iobuff_t *io, int size)
-{
- io->head = kmalloc(size, GFP_KERNEL | GFP_DMA);
- if (io->head != NULL) {
- io->truesize = size;
- io->in_frame = FALSE;
- io->state = OUTSIDE_FRAME;
- io->data = io->head;
- }
- return io->head ? 0 : -ENOMEM;
-}
-
-static const struct net_device_ops sa1100_irda_netdev_ops = {
- .ndo_open = sa1100_irda_start,
- .ndo_stop = sa1100_irda_stop,
- .ndo_start_xmit = sa1100_irda_hard_xmit,
- .ndo_do_ioctl = sa1100_irda_ioctl,
-};
-
-static int sa1100_irda_probe(struct platform_device *pdev)
-{
- struct net_device *dev;
- struct sa1100_irda *si;
- unsigned int baudrate_mask;
- int err, irq;
-
- if (!pdev->dev.platform_data)
- return -EINVAL;
-
- irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return irq < 0 ? irq : -ENXIO;
-
- err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY;
- if (err)
- goto err_mem_1;
- err = request_mem_region(__PREG(Ser2HSCR0), 0x1c, "IrDA") ? 0 : -EBUSY;
- if (err)
- goto err_mem_2;
- err = request_mem_region(__PREG(Ser2HSCR2), 0x04, "IrDA") ? 0 : -EBUSY;
- if (err)
- goto err_mem_3;
-
- dev = alloc_irdadev(sizeof(struct sa1100_irda));
- if (!dev) {
- err = -ENOMEM;
- goto err_mem_4;
- }
-
- SET_NETDEV_DEV(dev, &pdev->dev);
-
- si = netdev_priv(dev);
- si->dev = &pdev->dev;
- si->pdata = pdev->dev.platform_data;
-
- sg_init_table(&si->dma_rx.sg, 1);
- sg_init_table(&si->dma_tx.sg, 1);
-
- /*
- * Initialise the HP-SIR buffers
- */
- err = sa1100_irda_init_iobuf(&si->rx_buff, 14384);
- if (err)
- goto err_mem_5;
- err = sa1100_irda_init_iobuf(&si->tx_buff, IRDA_SIR_MAX_FRAME);
- if (err)
- goto err_mem_5;
-
- dev->netdev_ops = &sa1100_irda_netdev_ops;
- dev->irq = irq;
-
- irda_init_max_qos_capabilies(&si->qos);
-
- /*
- * We support original IRDA up to 115k2. (we don't currently
- * support 4Mbps). Min Turn Time set to 1ms or greater.
- */
- baudrate_mask = IR_9600;
-
- switch (max_rate) {
- case 4000000: baudrate_mask |= IR_4000000 << 8;
- case 115200: baudrate_mask |= IR_115200;
- case 57600: baudrate_mask |= IR_57600;
- case 38400: baudrate_mask |= IR_38400;
- case 19200: baudrate_mask |= IR_19200;
- }
-
- si->qos.baud_rate.bits &= baudrate_mask;
- si->qos.min_turn_time.bits = 7;
-
- irda_qos_bits_to_value(&si->qos);
-
- si->utcr4 = UTCR4_HPSIR;
- if (tx_lpm)
- si->utcr4 |= UTCR4_Z1_6us;
-
- /*
- * Initially enable HP-SIR modulation, and ensure that the port
- * is disabled.
- */
- Ser2UTCR3 = 0;
- Ser2UTCR4 = si->utcr4;
- Ser2HSCR0 = HSCR0_UART;
-
- err = register_netdev(dev);
- if (err == 0)
- platform_set_drvdata(pdev, dev);
-
- if (err) {
- err_mem_5:
- kfree(si->tx_buff.head);
- kfree(si->rx_buff.head);
- free_netdev(dev);
- err_mem_4:
- release_mem_region(__PREG(Ser2HSCR2), 0x04);
- err_mem_3:
- release_mem_region(__PREG(Ser2HSCR0), 0x1c);
- err_mem_2:
- release_mem_region(__PREG(Ser2UTCR0), 0x24);
- }
- err_mem_1:
- return err;
-}
-
-static int sa1100_irda_remove(struct platform_device *pdev)
-{
- struct net_device *dev = platform_get_drvdata(pdev);
-
- if (dev) {
- struct sa1100_irda *si = netdev_priv(dev);
- unregister_netdev(dev);
- kfree(si->tx_buff.head);
- kfree(si->rx_buff.head);
- free_netdev(dev);
- }
-
- release_mem_region(__PREG(Ser2HSCR2), 0x04);
- release_mem_region(__PREG(Ser2HSCR0), 0x1c);
- release_mem_region(__PREG(Ser2UTCR0), 0x24);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-/*
- * Suspend the IrDA interface.
- */
-static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct net_device *dev = platform_get_drvdata(pdev);
- struct sa1100_irda *si;
-
- if (!dev)
- return 0;
-
- si = netdev_priv(dev);
- if (si->open) {
- /*
- * Stop the transmit queue
- */
- netif_device_detach(dev);
- disable_irq(dev->irq);
- sa1100_irda_shutdown(si);
- __sa1100_irda_set_power(si, 0);
- }
-
- return 0;
-}
-
-/*
- * Resume the IrDA interface.
- */
-static int sa1100_irda_resume(struct platform_device *pdev)
-{
- struct net_device *dev = platform_get_drvdata(pdev);
- struct sa1100_irda *si;
-
- if (!dev)
- return 0;
-
- si = netdev_priv(dev);
- if (si->open) {
- /*
- * If we missed a speed change, initialise at the new speed
- * directly. It is debatable whether this is actually
- * required, but in the interests of continuing from where
- * we left off it is desirable. The converse argument is
- * that we should re-negotiate at 9600 baud again.
- */
- if (si->newspeed) {
- si->speed = si->newspeed;
- si->newspeed = 0;
- }
-
- sa1100_irda_startup(si);
- __sa1100_irda_set_power(si, si->power);
- enable_irq(dev->irq);
-
- /*
- * This automatically wakes up the queue
- */
- netif_device_attach(dev);
- }
-
- return 0;
-}
-#else
-#define sa1100_irda_suspend NULL
-#define sa1100_irda_resume NULL
-#endif
-
-static struct platform_driver sa1100ir_driver = {
- .probe = sa1100_irda_probe,
- .remove = sa1100_irda_remove,
- .suspend = sa1100_irda_suspend,
- .resume = sa1100_irda_resume,
- .driver = {
- .name = "sa11x0-ir",
- },
-};
-
-static int __init sa1100_irda_init(void)
-{
- /*
- * Limit power level a sensible range.
- */
- if (power_level < 1)
- power_level = 1;
- if (power_level > 3)
- power_level = 3;
-
- return platform_driver_register(&sa1100ir_driver);
-}
-
-static void __exit sa1100_irda_exit(void)
-{
- platform_driver_unregister(&sa1100ir_driver);
-}
-
-module_init(sa1100_irda_init);
-module_exit(sa1100_irda_exit);
-module_param(power_level, int, 0);
-module_param(tx_lpm, int, 0);
-module_param(max_rate, int, 0);
-
-MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
-MODULE_DESCRIPTION("StrongARM SA1100 IrDA driver");
-MODULE_LICENSE("GPL");
-MODULE_PARM_DESC(power_level, "IrDA power level, 1 (low) to 3 (high)");
-MODULE_PARM_DESC(tx_lpm, "Enable transmitter low power (1.6us) mode");
-MODULE_PARM_DESC(max_rate, "Maximum baud rate (4000000, 115200, 57600, 38400, 19200, 9600)");
-MODULE_ALIAS("platform:sa11x0-ir");
diff --git a/drivers/staging/irda/drivers/sh_sir.c b/drivers/staging/irda/drivers/sh_sir.c
deleted file mode 100644
index 0d0687cc454a..000000000000
--- a/drivers/staging/irda/drivers/sh_sir.c
+++ /dev/null
@@ -1,810 +0,0 @@
-/*
- * SuperH IrDA Driver
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on bfin_sir.c
- * Copyright 2006-2009 Analog Devices Inc.
- *
- * 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 <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/irda_device.h>
-#include <asm/clock.h>
-
-#define DRIVER_NAME "sh_sir"
-
-#define RX_PHASE (1 << 0)
-#define TX_PHASE (1 << 1)
-#define TX_COMP_PHASE (1 << 2) /* tx complete */
-#define NONE_PHASE (1 << 31)
-
-#define IRIF_RINTCLR 0x0016 /* DMA rx interrupt source clear */
-#define IRIF_TINTCLR 0x0018 /* DMA tx interrupt source clear */
-#define IRIF_SIR0 0x0020 /* IrDA-SIR10 control */
-#define IRIF_SIR1 0x0022 /* IrDA-SIR10 baudrate error correction */
-#define IRIF_SIR2 0x0024 /* IrDA-SIR10 baudrate count */
-#define IRIF_SIR3 0x0026 /* IrDA-SIR10 status */
-#define IRIF_SIR_FRM 0x0028 /* Hardware frame processing set */
-#define IRIF_SIR_EOF 0x002A /* EOF value */
-#define IRIF_SIR_FLG 0x002C /* Flag clear */
-#define IRIF_UART_STS2 0x002E /* UART status 2 */
-#define IRIF_UART0 0x0030 /* UART control */
-#define IRIF_UART1 0x0032 /* UART status */
-#define IRIF_UART2 0x0034 /* UART mode */
-#define IRIF_UART3 0x0036 /* UART transmit data */
-#define IRIF_UART4 0x0038 /* UART receive data */
-#define IRIF_UART5 0x003A /* UART interrupt mask */
-#define IRIF_UART6 0x003C /* UART baud rate error correction */
-#define IRIF_UART7 0x003E /* UART baud rate count set */
-#define IRIF_CRC0 0x0040 /* CRC engine control */
-#define IRIF_CRC1 0x0042 /* CRC engine input data */
-#define IRIF_CRC2 0x0044 /* CRC engine calculation */
-#define IRIF_CRC3 0x0046 /* CRC engine output data 1 */
-#define IRIF_CRC4 0x0048 /* CRC engine output data 2 */
-
-/* IRIF_SIR0 */
-#define IRTPW (1 << 1) /* transmit pulse width select */
-#define IRERRC (1 << 0) /* Clear receive pulse width error */
-
-/* IRIF_SIR3 */
-#define IRERR (1 << 0) /* received pulse width Error */
-
-/* IRIF_SIR_FRM */
-#define EOFD (1 << 9) /* EOF detection flag */
-#define FRER (1 << 8) /* Frame Error bit */
-#define FRP (1 << 0) /* Frame processing set */
-
-/* IRIF_UART_STS2 */
-#define IRSME (1 << 6) /* Receive Sum Error flag */
-#define IROVE (1 << 5) /* Receive Overrun Error flag */
-#define IRFRE (1 << 4) /* Receive Framing Error flag */
-#define IRPRE (1 << 3) /* Receive Parity Error flag */
-
-/* IRIF_UART0_*/
-#define TBEC (1 << 2) /* Transmit Data Clear */
-#define RIE (1 << 1) /* Receive Enable */
-#define TIE (1 << 0) /* Transmit Enable */
-
-/* IRIF_UART1 */
-#define URSME (1 << 6) /* Receive Sum Error Flag */
-#define UROVE (1 << 5) /* Receive Overrun Error Flag */
-#define URFRE (1 << 4) /* Receive Framing Error Flag */
-#define URPRE (1 << 3) /* Receive Parity Error Flag */
-#define RBF (1 << 2) /* Receive Buffer Full Flag */
-#define TSBE (1 << 1) /* Transmit Shift Buffer Empty Flag */
-#define TBE (1 << 0) /* Transmit Buffer Empty flag */
-#define TBCOMP (TSBE | TBE)
-
-/* IRIF_UART5 */
-#define RSEIM (1 << 6) /* Receive Sum Error Flag IRQ Mask */
-#define RBFIM (1 << 2) /* Receive Buffer Full Flag IRQ Mask */
-#define TSBEIM (1 << 1) /* Transmit Shift Buffer Empty Flag IRQ Mask */
-#define TBEIM (1 << 0) /* Transmit Buffer Empty Flag IRQ Mask */
-#define RX_MASK (RSEIM | RBFIM)
-
-/* IRIF_CRC0 */
-#define CRC_RST (1 << 15) /* CRC Engine Reset */
-#define CRC_CT_MASK 0x0FFF
-
-/************************************************************************
-
-
- structure
-
-
-************************************************************************/
-struct sh_sir_self {
- void __iomem *membase;
- unsigned int irq;
- struct clk *clk;
-
- struct net_device *ndev;
-
- struct irlap_cb *irlap;
- struct qos_info qos;
-
- iobuff_t tx_buff;
- iobuff_t rx_buff;
-};
-
-/************************************************************************
-
-
- common function
-
-
-************************************************************************/
-static void sh_sir_write(struct sh_sir_self *self, u32 offset, u16 data)
-{
- iowrite16(data, self->membase + offset);
-}
-
-static u16 sh_sir_read(struct sh_sir_self *self, u32 offset)
-{
- return ioread16(self->membase + offset);
-}
-
-static void sh_sir_update_bits(struct sh_sir_self *self, u32 offset,
- u16 mask, u16 data)
-{
- u16 old, new;
-
- old = sh_sir_read(self, offset);
- new = (old & ~mask) | data;
- if (old != new)
- sh_sir_write(self, offset, new);
-}
-
-/************************************************************************
-
-
- CRC function
-
-
-************************************************************************/
-static void sh_sir_crc_reset(struct sh_sir_self *self)
-{
- sh_sir_write(self, IRIF_CRC0, CRC_RST);
-}
-
-static void sh_sir_crc_add(struct sh_sir_self *self, u8 data)
-{
- sh_sir_write(self, IRIF_CRC1, (u16)data);
-}
-
-static u16 sh_sir_crc_cnt(struct sh_sir_self *self)
-{
- return CRC_CT_MASK & sh_sir_read(self, IRIF_CRC0);
-}
-
-static u16 sh_sir_crc_out(struct sh_sir_self *self)
-{
- return sh_sir_read(self, IRIF_CRC4);
-}
-
-static int sh_sir_crc_init(struct sh_sir_self *self)
-{
- struct device *dev = &self->ndev->dev;
- int ret = -EIO;
- u16 val;
-
- sh_sir_crc_reset(self);
-
- sh_sir_crc_add(self, 0xCC);
- sh_sir_crc_add(self, 0xF5);
- sh_sir_crc_add(self, 0xF1);
- sh_sir_crc_add(self, 0xA7);
-
- val = sh_sir_crc_cnt(self);
- if (4 != val) {
- dev_err(dev, "CRC count error %x\n", val);
- goto crc_init_out;
- }
-
- val = sh_sir_crc_out(self);
- if (0x51DF != val) {
- dev_err(dev, "CRC result error%x\n", val);
- goto crc_init_out;
- }
-
- ret = 0;
-
-crc_init_out:
-
- sh_sir_crc_reset(self);
- return ret;
-}
-
-/************************************************************************
-
-
- baud rate functions
-
-
-************************************************************************/
-#define SCLK_BASE 1843200 /* 1.8432MHz */
-
-static u32 sh_sir_find_sclk(struct clk *irda_clk)
-{
- struct cpufreq_frequency_table *freq_table = irda_clk->freq_table;
- struct cpufreq_frequency_table *pos;
- struct clk *pclk = clk_get(NULL, "peripheral_clk");
- u32 limit, min = 0xffffffff, tmp;
- int index = 0;
-
- limit = clk_get_rate(pclk);
- clk_put(pclk);
-
- /* IrDA can not set over peripheral_clk */
- cpufreq_for_each_valid_entry_idx(pos, freq_table, index) {
- u32 freq = pos->frequency;
-
- /* IrDA should not over peripheral_clk */
- if (freq > limit)
- continue;
-
- tmp = freq % SCLK_BASE;
- if (tmp < min) {
- min = tmp;
- break;
- }
- }
-
- return freq_table[index].frequency;
-}
-
-#define ERR_ROUNDING(a) ((a + 5000) / 10000)
-static int sh_sir_set_baudrate(struct sh_sir_self *self, u32 baudrate)
-{
- struct clk *clk;
- struct device *dev = &self->ndev->dev;
- u32 rate;
- u16 uabca, uabc;
- u16 irbca, irbc;
- u32 min, rerr, tmp;
- int i;
-
- /* Baud Rate Error Correction x 10000 */
- u32 rate_err_array[] = {
- 0, 625, 1250, 1875,
- 2500, 3125, 3750, 4375,
- 5000, 5625, 6250, 6875,
- 7500, 8125, 8750, 9375,
- };
-
- /*
- * FIXME
- *
- * it support 9600 only now
- */
- switch (baudrate) {
- case 9600:
- break;
- default:
- dev_err(dev, "un-supported baudrate %d\n", baudrate);
- return -EIO;
- }
-
- clk = clk_get(NULL, "irda_clk");
- if (IS_ERR(clk)) {
- dev_err(dev, "can not get irda_clk\n");
- return -EIO;
- }
-
- clk_set_rate(clk, sh_sir_find_sclk(clk));
- rate = clk_get_rate(clk);
- clk_put(clk);
-
- dev_dbg(dev, "selected sclk = %d\n", rate);
-
- /*
- * CALCULATION
- *
- * 1843200 = system rate / (irbca + (irbc + 1))
- */
-
- irbc = rate / SCLK_BASE;
-
- tmp = rate - (SCLK_BASE * irbc);
- tmp *= 10000;
-
- rerr = tmp / SCLK_BASE;
-
- min = 0xffffffff;
- irbca = 0;
- for (i = 0; i < ARRAY_SIZE(rate_err_array); i++) {
- tmp = abs(rate_err_array[i] - rerr);
- if (min > tmp) {
- min = tmp;
- irbca = i;
- }
- }
-
- tmp = rate / (irbc + ERR_ROUNDING(rate_err_array[irbca]));
- if ((SCLK_BASE / 100) < abs(tmp - SCLK_BASE))
- dev_warn(dev, "IrDA freq error margin over %d\n", tmp);
-
- dev_dbg(dev, "target = %d, result = %d, infrared = %d.%d\n",
- SCLK_BASE, tmp, irbc, rate_err_array[irbca]);
-
- irbca = (irbca & 0xF) << 4;
- irbc = (irbc - 1) & 0xF;
-
- if (!irbc) {
- dev_err(dev, "sh_sir can not set 0 in IRIF_SIR2\n");
- return -EIO;
- }
-
- sh_sir_write(self, IRIF_SIR0, IRTPW | IRERRC);
- sh_sir_write(self, IRIF_SIR1, irbca);
- sh_sir_write(self, IRIF_SIR2, irbc);
-
- /*
- * CALCULATION
- *
- * BaudRate[bps] = system rate / (uabca + (uabc + 1) x 16)
- */
-
- uabc = rate / baudrate;
- uabc = (uabc / 16) - 1;
- uabc = (uabc + 1) * 16;
-
- tmp = rate - (uabc * baudrate);
- tmp *= 10000;
-
- rerr = tmp / baudrate;
-
- min = 0xffffffff;
- uabca = 0;
- for (i = 0; i < ARRAY_SIZE(rate_err_array); i++) {
- tmp = abs(rate_err_array[i] - rerr);
- if (min > tmp) {
- min = tmp;
- uabca = i;
- }
- }
-
- tmp = rate / (uabc + ERR_ROUNDING(rate_err_array[uabca]));
- if ((baudrate / 100) < abs(tmp - baudrate))
- dev_warn(dev, "UART freq error margin over %d\n", tmp);
-
- dev_dbg(dev, "target = %d, result = %d, uart = %d.%d\n",
- baudrate, tmp,
- uabc, rate_err_array[uabca]);
-
- uabca = (uabca & 0xF) << 4;
- uabc = (uabc / 16) - 1;
-
- sh_sir_write(self, IRIF_UART6, uabca);
- sh_sir_write(self, IRIF_UART7, uabc);
-
- return 0;
-}
-
-/************************************************************************
-
-
- iobuf function
-
-
-************************************************************************/
-static int __sh_sir_init_iobuf(iobuff_t *io, int size)
-{
- io->head = kmalloc(size, GFP_KERNEL);
- if (!io->head)
- return -ENOMEM;
-
- io->truesize = size;
- io->in_frame = FALSE;
- io->state = OUTSIDE_FRAME;
- io->data = io->head;
-
- return 0;
-}
-
-static void sh_sir_remove_iobuf(struct sh_sir_self *self)
-{
- kfree(self->rx_buff.head);
- kfree(self->tx_buff.head);
-
- self->rx_buff.head = NULL;
- self->tx_buff.head = NULL;
-}
-
-static int sh_sir_init_iobuf(struct sh_sir_self *self, int rxsize, int txsize)
-{
- int err = -ENOMEM;
-
- if (self->rx_buff.head ||
- self->tx_buff.head) {
- dev_err(&self->ndev->dev, "iobuff has already existed.");
- return err;
- }
-
- err = __sh_sir_init_iobuf(&self->rx_buff, rxsize);
- if (err)
- goto iobuf_err;
-
- err = __sh_sir_init_iobuf(&self->tx_buff, txsize);
-
-iobuf_err:
- if (err)
- sh_sir_remove_iobuf(self);
-
- return err;
-}
-
-/************************************************************************
-
-
- status function
-
-
-************************************************************************/
-static void sh_sir_clear_all_err(struct sh_sir_self *self)
-{
- /* Clear error flag for receive pulse width */
- sh_sir_update_bits(self, IRIF_SIR0, IRERRC, IRERRC);
-
- /* Clear frame / EOF error flag */
- sh_sir_write(self, IRIF_SIR_FLG, 0xffff);
-
- /* Clear all status error */
- sh_sir_write(self, IRIF_UART_STS2, 0);
-}
-
-static void sh_sir_set_phase(struct sh_sir_self *self, int phase)
-{
- u16 uart5 = 0;
- u16 uart0 = 0;
-
- switch (phase) {
- case TX_PHASE:
- uart5 = TBEIM;
- uart0 = TBEC | TIE;
- break;
- case TX_COMP_PHASE:
- uart5 = TSBEIM;
- uart0 = TIE;
- break;
- case RX_PHASE:
- uart5 = RX_MASK;
- uart0 = RIE;
- break;
- default:
- break;
- }
-
- sh_sir_write(self, IRIF_UART5, uart5);
- sh_sir_write(self, IRIF_UART0, uart0);
-}
-
-static int sh_sir_is_which_phase(struct sh_sir_self *self)
-{
- u16 val = sh_sir_read(self, IRIF_UART5);
-
- if (val & TBEIM)
- return TX_PHASE;
-
- if (val & TSBEIM)
- return TX_COMP_PHASE;
-
- if (val & RX_MASK)
- return RX_PHASE;
-
- return NONE_PHASE;
-}
-
-static void sh_sir_tx(struct sh_sir_self *self, int phase)
-{
- switch (phase) {
- case TX_PHASE:
- if (0 >= self->tx_buff.len) {
- sh_sir_set_phase(self, TX_COMP_PHASE);
- } else {
- sh_sir_write(self, IRIF_UART3, self->tx_buff.data[0]);
- self->tx_buff.len--;
- self->tx_buff.data++;
- }
- break;
- case TX_COMP_PHASE:
- sh_sir_set_phase(self, RX_PHASE);
- netif_wake_queue(self->ndev);
- break;
- default:
- dev_err(&self->ndev->dev, "should not happen\n");
- break;
- }
-}
-
-static int sh_sir_read_data(struct sh_sir_self *self)
-{
- u16 val = 0;
- int timeout = 1024;
-
- while (timeout--) {
- val = sh_sir_read(self, IRIF_UART1);
-
- /* data get */
- if (val & RBF) {
- if (val & (URSME | UROVE | URFRE | URPRE))
- break;
-
- return (int)sh_sir_read(self, IRIF_UART4);
- }
-
- udelay(1);
- }
-
- dev_err(&self->ndev->dev, "UART1 %04x : STATUS %04x\n",
- val, sh_sir_read(self, IRIF_UART_STS2));
-
- /* read data register for clear error */
- sh_sir_read(self, IRIF_UART4);
-
- return -1;
-}
-
-static void sh_sir_rx(struct sh_sir_self *self)
-{
- int timeout = 1024;
- int data;
-
- while (timeout--) {
- data = sh_sir_read_data(self);
- if (data < 0)
- break;
-
- async_unwrap_char(self->ndev, &self->ndev->stats,
- &self->rx_buff, (u8)data);
-
- if (EOFD & sh_sir_read(self, IRIF_SIR_FRM))
- continue;
-
- break;
- }
-}
-
-static irqreturn_t sh_sir_irq(int irq, void *dev_id)
-{
- struct sh_sir_self *self = dev_id;
- struct device *dev = &self->ndev->dev;
- int phase = sh_sir_is_which_phase(self);
-
- switch (phase) {
- case TX_COMP_PHASE:
- case TX_PHASE:
- sh_sir_tx(self, phase);
- break;
- case RX_PHASE:
- if (sh_sir_read(self, IRIF_SIR3))
- dev_err(dev, "rcv pulse width error occurred\n");
-
- sh_sir_rx(self);
- sh_sir_clear_all_err(self);
- break;
- default:
- dev_err(dev, "unknown interrupt\n");
- }
-
- return IRQ_HANDLED;
-}
-
-/************************************************************************
-
-
- net_device_ops function
-
-
-************************************************************************/
-static int sh_sir_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
-{
- struct sh_sir_self *self = netdev_priv(ndev);
- int speed = irda_get_next_speed(skb);
-
- if ((0 < speed) &&
- (9600 != speed)) {
- dev_err(&ndev->dev, "support 9600 only (%d)\n", speed);
- return -EIO;
- }
-
- netif_stop_queue(ndev);
-
- self->tx_buff.data = self->tx_buff.head;
- self->tx_buff.len = 0;
- if (skb->len)
- self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
- self->tx_buff.truesize);
-
- sh_sir_set_phase(self, TX_PHASE);
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-static int sh_sir_ioctl(struct net_device *ndev, struct ifreq *ifreq, int cmd)
-{
- /*
- * FIXME
- *
- * This function is needed for irda framework.
- * But nothing to do now
- */
- return 0;
-}
-
-static struct net_device_stats *sh_sir_stats(struct net_device *ndev)
-{
- struct sh_sir_self *self = netdev_priv(ndev);
-
- return &self->ndev->stats;
-}
-
-static int sh_sir_open(struct net_device *ndev)
-{
- struct sh_sir_self *self = netdev_priv(ndev);
- int err;
-
- clk_enable(self->clk);
- err = sh_sir_crc_init(self);
- if (err)
- goto open_err;
-
- sh_sir_set_baudrate(self, 9600);
-
- self->irlap = irlap_open(ndev, &self->qos, DRIVER_NAME);
- if (!self->irlap) {
- err = -ENODEV;
- goto open_err;
- }
-
- /*
- * Now enable the interrupt then start the queue
- */
- sh_sir_update_bits(self, IRIF_SIR_FRM, FRP, FRP);
- sh_sir_read(self, IRIF_UART1); /* flag clear */
- sh_sir_read(self, IRIF_UART4); /* flag clear */
- sh_sir_set_phase(self, RX_PHASE);
-
- netif_start_queue(ndev);
-
- dev_info(&self->ndev->dev, "opened\n");
-
- return 0;
-
-open_err:
- clk_disable(self->clk);
-
- return err;
-}
-
-static int sh_sir_stop(struct net_device *ndev)
-{
- struct sh_sir_self *self = netdev_priv(ndev);
-
- /* Stop IrLAP */
- if (self->irlap) {
- irlap_close(self->irlap);
- self->irlap = NULL;
- }
-
- netif_stop_queue(ndev);
-
- dev_info(&ndev->dev, "stopped\n");
-
- return 0;
-}
-
-static const struct net_device_ops sh_sir_ndo = {
- .ndo_open = sh_sir_open,
- .ndo_stop = sh_sir_stop,
- .ndo_start_xmit = sh_sir_hard_xmit,
- .ndo_do_ioctl = sh_sir_ioctl,
- .ndo_get_stats = sh_sir_stats,
-};
-
-/************************************************************************
-
-
- platform_driver function
-
-
-************************************************************************/
-static int sh_sir_probe(struct platform_device *pdev)
-{
- struct net_device *ndev;
- struct sh_sir_self *self;
- struct resource *res;
- char clk_name[8];
- int irq;
- int err = -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!res || irq < 0) {
- dev_err(&pdev->dev, "Not enough platform resources.\n");
- goto exit;
- }
-
- ndev = alloc_irdadev(sizeof(*self));
- if (!ndev)
- goto exit;
-
- self = netdev_priv(ndev);
- self->membase = ioremap_nocache(res->start, resource_size(res));
- if (!self->membase) {
- err = -ENXIO;
- dev_err(&pdev->dev, "Unable to ioremap.\n");
- goto err_mem_1;
- }
-
- err = sh_sir_init_iobuf(self, IRDA_SKB_MAX_MTU, IRDA_SIR_MAX_FRAME);
- if (err)
- goto err_mem_2;
-
- snprintf(clk_name, sizeof(clk_name), "irda%d", pdev->id);
- self->clk = clk_get(&pdev->dev, clk_name);
- if (IS_ERR(self->clk)) {
- dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
- err = -ENODEV;
- goto err_mem_3;
- }
-
- irda_init_max_qos_capabilies(&self->qos);
-
- ndev->netdev_ops = &sh_sir_ndo;
- ndev->irq = irq;
-
- self->ndev = ndev;
- self->qos.baud_rate.bits &= IR_9600; /* FIXME */
- self->qos.min_turn_time.bits = 1; /* 10 ms or more */
-
- irda_qos_bits_to_value(&self->qos);
-
- err = register_netdev(ndev);
- if (err)
- goto err_mem_4;
-
- platform_set_drvdata(pdev, ndev);
- err = devm_request_irq(&pdev->dev, irq, sh_sir_irq, 0, "sh_sir", self);
- if (err) {
- dev_warn(&pdev->dev, "Unable to attach sh_sir interrupt\n");
- goto err_mem_4;
- }
-
- dev_info(&pdev->dev, "SuperH IrDA probed\n");
-
- goto exit;
-
-err_mem_4:
- clk_put(self->clk);
-err_mem_3:
- sh_sir_remove_iobuf(self);
-err_mem_2:
- iounmap(self->membase);
-err_mem_1:
- free_netdev(ndev);
-exit:
- return err;
-}
-
-static int sh_sir_remove(struct platform_device *pdev)
-{
- struct net_device *ndev = platform_get_drvdata(pdev);
- struct sh_sir_self *self = netdev_priv(ndev);
-
- if (!self)
- return 0;
-
- unregister_netdev(ndev);
- clk_put(self->clk);
- sh_sir_remove_iobuf(self);
- iounmap(self->membase);
- free_netdev(ndev);
-
- return 0;
-}
-
-static struct platform_driver sh_sir_driver = {
- .probe = sh_sir_probe,
- .remove = sh_sir_remove,
- .driver = {
- .name = DRIVER_NAME,
- },
-};
-
-module_platform_driver(sh_sir_driver);
-
-MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
-MODULE_DESCRIPTION("SuperH IrDA driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/irda/drivers/sir-dev.h b/drivers/staging/irda/drivers/sir-dev.h
deleted file mode 100644
index f50b9c1c0639..000000000000
--- a/drivers/staging/irda/drivers/sir-dev.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*********************************************************************
- *
- * sir.h: include file for irda-sir device abstraction layer
- *
- * Copyright (c) 2002 Martin Diehl
- *
- * 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 IRDA_SIR_H
-#define IRDA_SIR_H
-
-#include <linux/netdevice.h>
-#include <linux/workqueue.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h> // iobuff_t
-
-struct sir_fsm {
- struct semaphore sem;
- struct delayed_work work;
- unsigned state, substate;
- int param;
- int result;
-};
-
-#define SIRDEV_STATE_WAIT_TX_COMPLETE 0x0100
-
-/* substates for wait_tx_complete */
-#define SIRDEV_STATE_WAIT_XMIT 0x0101
-#define SIRDEV_STATE_WAIT_UNTIL_SENT 0x0102
-#define SIRDEV_STATE_TX_DONE 0x0103
-
-#define SIRDEV_STATE_DONGLE_OPEN 0x0300
-
-/* 0x0301-0x03ff reserved for individual dongle substates */
-
-#define SIRDEV_STATE_DONGLE_CLOSE 0x0400
-
-/* 0x0401-0x04ff reserved for individual dongle substates */
-
-#define SIRDEV_STATE_SET_DTR_RTS 0x0500
-
-#define SIRDEV_STATE_SET_SPEED 0x0700
-#define SIRDEV_STATE_DONGLE_CHECK 0x0800
-#define SIRDEV_STATE_DONGLE_RESET 0x0900
-
-/* 0x0901-0x09ff reserved for individual dongle substates */
-
-#define SIRDEV_STATE_DONGLE_SPEED 0x0a00
-/* 0x0a01-0x0aff reserved for individual dongle substates */
-
-#define SIRDEV_STATE_PORT_SPEED 0x0b00
-#define SIRDEV_STATE_DONE 0x0c00
-#define SIRDEV_STATE_ERROR 0x0d00
-#define SIRDEV_STATE_COMPLETE 0x0e00
-
-#define SIRDEV_STATE_DEAD 0xffff
-
-
-struct sir_dev;
-
-struct dongle_driver {
-
- struct module *owner;
-
- const char *driver_name;
-
- IRDA_DONGLE type;
-
- int (*open)(struct sir_dev *dev);
- int (*close)(struct sir_dev *dev);
- int (*reset)(struct sir_dev *dev);
- int (*set_speed)(struct sir_dev *dev, unsigned speed);
-
- struct list_head dongle_list;
-};
-
-struct sir_driver {
-
- struct module *owner;
-
- const char *driver_name;
-
- int qos_mtt_bits;
-
- int (*chars_in_buffer)(struct sir_dev *dev);
- void (*wait_until_sent)(struct sir_dev *dev);
- int (*set_speed)(struct sir_dev *dev, unsigned speed);
- int (*set_dtr_rts)(struct sir_dev *dev, int dtr, int rts);
-
- int (*do_write)(struct sir_dev *dev, const unsigned char *ptr, size_t len);
-
- int (*start_dev)(struct sir_dev *dev);
- int (*stop_dev)(struct sir_dev *dev);
-};
-
-
-/* exported */
-
-int irda_register_dongle(struct dongle_driver *new);
-int irda_unregister_dongle(struct dongle_driver *drv);
-
-struct sir_dev *sirdev_get_instance(const struct sir_driver *drv,
- const char *name);
-int sirdev_put_instance(struct sir_dev *self);
-
-int sirdev_set_dongle(struct sir_dev *dev, IRDA_DONGLE type);
-void sirdev_write_complete(struct sir_dev *dev);
-int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count);
-
-/* low level helpers for SIR device/dongle setup */
-int sirdev_raw_write(struct sir_dev *dev, const char *buf, int len);
-int sirdev_raw_read(struct sir_dev *dev, char *buf, int len);
-int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts);
-
-/* not exported */
-
-int sirdev_get_dongle(struct sir_dev *self, IRDA_DONGLE type);
-int sirdev_put_dongle(struct sir_dev *self);
-
-void sirdev_enable_rx(struct sir_dev *dev);
-int sirdev_schedule_request(struct sir_dev *dev, int state, unsigned param);
-
-/* inline helpers */
-
-static inline int sirdev_schedule_speed(struct sir_dev *dev, unsigned speed)
-{
- return sirdev_schedule_request(dev, SIRDEV_STATE_SET_SPEED, speed);
-}
-
-static inline int sirdev_schedule_dongle_open(struct sir_dev *dev, int dongle_id)
-{
- return sirdev_schedule_request(dev, SIRDEV_STATE_DONGLE_OPEN, dongle_id);
-}
-
-static inline int sirdev_schedule_dongle_close(struct sir_dev *dev)
-{
- return sirdev_schedule_request(dev, SIRDEV_STATE_DONGLE_CLOSE, 0);
-}
-
-static inline int sirdev_schedule_dtr_rts(struct sir_dev *dev, int dtr, int rts)
-{
- int dtrrts;
-
- dtrrts = ((dtr) ? 0x02 : 0x00) | ((rts) ? 0x01 : 0x00);
- return sirdev_schedule_request(dev, SIRDEV_STATE_SET_DTR_RTS, dtrrts);
-}
-
-#if 0
-static inline int sirdev_schedule_mode(struct sir_dev *dev, int mode)
-{
- return sirdev_schedule_request(dev, SIRDEV_STATE_SET_MODE, mode);
-}
-#endif
-
-
-struct sir_dev {
- struct net_device *netdev;
-
- struct irlap_cb *irlap;
-
- struct qos_info qos;
-
- char hwname[32];
-
- struct sir_fsm fsm;
- atomic_t enable_rx;
- int raw_tx;
- spinlock_t tx_lock;
-
- u32 new_speed;
- u32 flags;
-
- unsigned speed;
-
- iobuff_t tx_buff; /* Transmit buffer */
- iobuff_t rx_buff; /* Receive buffer */
- struct sk_buff *tx_skb;
-
- const struct dongle_driver * dongle_drv;
- const struct sir_driver * drv;
- void *priv;
-
-};
-
-#endif /* IRDA_SIR_H */
diff --git a/drivers/staging/irda/drivers/sir_dev.c b/drivers/staging/irda/drivers/sir_dev.c
deleted file mode 100644
index 6af26a7d787c..000000000000
--- a/drivers/staging/irda/drivers/sir_dev.c
+++ /dev/null
@@ -1,987 +0,0 @@
-/*********************************************************************
- *
- * sir_dev.c: irda sir network device
- *
- * Copyright (c) 2002 Martin Diehl
- *
- * 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/hardirq.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/irda_device.h>
-
-#include "sir-dev.h"
-
-
-static struct workqueue_struct *irda_sir_wq;
-
-/* STATE MACHINE */
-
-/* substate handler of the config-fsm to handle the cases where we want
- * to wait for transmit completion before changing the port configuration
- */
-
-static int sirdev_tx_complete_fsm(struct sir_dev *dev)
-{
- struct sir_fsm *fsm = &dev->fsm;
- unsigned next_state, delay;
- unsigned bytes_left;
-
- do {
- next_state = fsm->substate; /* default: stay in current substate */
- delay = 0;
-
- switch(fsm->substate) {
-
- case SIRDEV_STATE_WAIT_XMIT:
- if (dev->drv->chars_in_buffer)
- bytes_left = dev->drv->chars_in_buffer(dev);
- else
- bytes_left = 0;
- if (!bytes_left) {
- next_state = SIRDEV_STATE_WAIT_UNTIL_SENT;
- break;
- }
-
- if (dev->speed > 115200)
- delay = (bytes_left*8*10000) / (dev->speed/100);
- else if (dev->speed > 0)
- delay = (bytes_left*10*10000) / (dev->speed/100);
- else
- delay = 0;
- /* expected delay (usec) until remaining bytes are sent */
- if (delay < 100) {
- udelay(delay);
- delay = 0;
- break;
- }
- /* sleep some longer delay (msec) */
- delay = (delay+999) / 1000;
- break;
-
- case SIRDEV_STATE_WAIT_UNTIL_SENT:
- /* block until underlaying hardware buffer are empty */
- if (dev->drv->wait_until_sent)
- dev->drv->wait_until_sent(dev);
- next_state = SIRDEV_STATE_TX_DONE;
- break;
-
- case SIRDEV_STATE_TX_DONE:
- return 0;
-
- default:
- net_err_ratelimited("%s - undefined state\n", __func__);
- return -EINVAL;
- }
- fsm->substate = next_state;
- } while (delay == 0);
- return delay;
-}
-
-/*
- * Function sirdev_config_fsm
- *
- * State machine to handle the configuration of the device (and attached dongle, if any).
- * This handler is scheduled for execution in kIrDAd context, so we can sleep.
- * however, kIrDAd is shared by all sir_dev devices so we better don't sleep there too
- * long. Instead, for longer delays we start a timer to reschedule us later.
- * On entry, fsm->sem is always locked and the netdev xmit queue stopped.
- * Both must be unlocked/restarted on completion - but only on final exit.
- */
-
-static void sirdev_config_fsm(struct work_struct *work)
-{
- struct sir_dev *dev = container_of(work, struct sir_dev, fsm.work.work);
- struct sir_fsm *fsm = &dev->fsm;
- int next_state;
- int ret = -1;
- unsigned delay;
-
- pr_debug("%s(), <%ld>\n", __func__, jiffies);
-
- do {
- pr_debug("%s - state=0x%04x / substate=0x%04x\n",
- __func__, fsm->state, fsm->substate);
-
- next_state = fsm->state;
- delay = 0;
-
- switch(fsm->state) {
-
- case SIRDEV_STATE_DONGLE_OPEN:
- if (dev->dongle_drv != NULL) {
- ret = sirdev_put_dongle(dev);
- if (ret) {
- fsm->result = -EINVAL;
- next_state = SIRDEV_STATE_ERROR;
- break;
- }
- }
-
- /* Initialize dongle */
- ret = sirdev_get_dongle(dev, fsm->param);
- if (ret) {
- fsm->result = ret;
- next_state = SIRDEV_STATE_ERROR;
- break;
- }
-
- /* Dongles are powered through the modem control lines which
- * were just set during open. Before resetting, let's wait for
- * the power to stabilize. This is what some dongle drivers did
- * in open before, while others didn't - should be safe anyway.
- */
-
- delay = 50;
- fsm->substate = SIRDEV_STATE_DONGLE_RESET;
- next_state = SIRDEV_STATE_DONGLE_RESET;
-
- fsm->param = 9600;
-
- break;
-
- case SIRDEV_STATE_DONGLE_CLOSE:
- /* shouldn't we just treat this as success=? */
- if (dev->dongle_drv == NULL) {
- fsm->result = -EINVAL;
- next_state = SIRDEV_STATE_ERROR;
- break;
- }
-
- ret = sirdev_put_dongle(dev);
- if (ret) {
- fsm->result = ret;
- next_state = SIRDEV_STATE_ERROR;
- break;
- }
- next_state = SIRDEV_STATE_DONE;
- break;
-
- case SIRDEV_STATE_SET_DTR_RTS:
- ret = sirdev_set_dtr_rts(dev,
- (fsm->param&0x02) ? TRUE : FALSE,
- (fsm->param&0x01) ? TRUE : FALSE);
- next_state = SIRDEV_STATE_DONE;
- break;
-
- case SIRDEV_STATE_SET_SPEED:
- fsm->substate = SIRDEV_STATE_WAIT_XMIT;
- next_state = SIRDEV_STATE_DONGLE_CHECK;
- break;
-
- case SIRDEV_STATE_DONGLE_CHECK:
- ret = sirdev_tx_complete_fsm(dev);
- if (ret < 0) {
- fsm->result = ret;
- next_state = SIRDEV_STATE_ERROR;
- break;
- }
- if ((delay=ret) != 0)
- break;
-
- if (dev->dongle_drv) {
- fsm->substate = SIRDEV_STATE_DONGLE_RESET;
- next_state = SIRDEV_STATE_DONGLE_RESET;
- }
- else {
- dev->speed = fsm->param;
- next_state = SIRDEV_STATE_PORT_SPEED;
- }
- break;
-
- case SIRDEV_STATE_DONGLE_RESET:
- if (dev->dongle_drv->reset) {
- ret = dev->dongle_drv->reset(dev);
- if (ret < 0) {
- fsm->result = ret;
- next_state = SIRDEV_STATE_ERROR;
- break;
- }
- }
- else
- ret = 0;
- if ((delay=ret) == 0) {
- /* set serial port according to dongle default speed */
- if (dev->drv->set_speed)
- dev->drv->set_speed(dev, dev->speed);
- fsm->substate = SIRDEV_STATE_DONGLE_SPEED;
- next_state = SIRDEV_STATE_DONGLE_SPEED;
- }
- break;
-
- case SIRDEV_STATE_DONGLE_SPEED:
- if (dev->dongle_drv->set_speed) {
- ret = dev->dongle_drv->set_speed(dev, fsm->param);
- if (ret < 0) {
- fsm->result = ret;
- next_state = SIRDEV_STATE_ERROR;
- break;
- }
- }
- else
- ret = 0;
- if ((delay=ret) == 0)
- next_state = SIRDEV_STATE_PORT_SPEED;
- break;
-
- case SIRDEV_STATE_PORT_SPEED:
- /* Finally we are ready to change the serial port speed */
- if (dev->drv->set_speed)
- dev->drv->set_speed(dev, dev->speed);
- dev->new_speed = 0;
- next_state = SIRDEV_STATE_DONE;
- break;
-
- case SIRDEV_STATE_DONE:
- /* Signal network layer so it can send more frames */
- netif_wake_queue(dev->netdev);
- next_state = SIRDEV_STATE_COMPLETE;
- break;
-
- default:
- net_err_ratelimited("%s - undefined state\n", __func__);
- fsm->result = -EINVAL;
- /* fall thru */
-
- case SIRDEV_STATE_ERROR:
- net_err_ratelimited("%s - error: %d\n",
- __func__, fsm->result);
-
-#if 0 /* don't enable this before we have netdev->tx_timeout to recover */
- netif_stop_queue(dev->netdev);
-#else
- netif_wake_queue(dev->netdev);
-#endif
- /* fall thru */
-
- case SIRDEV_STATE_COMPLETE:
- /* config change finished, so we are not busy any longer */
- sirdev_enable_rx(dev);
- up(&fsm->sem);
- return;
- }
- fsm->state = next_state;
- } while(!delay);
-
- queue_delayed_work(irda_sir_wq, &fsm->work, msecs_to_jiffies(delay));
-}
-
-/* schedule some device configuration task for execution by kIrDAd
- * on behalf of the above state machine.
- * can be called from process or interrupt/tasklet context.
- */
-
-int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned param)
-{
- struct sir_fsm *fsm = &dev->fsm;
-
- pr_debug("%s - state=0x%04x / param=%u\n", __func__,
- initial_state, param);
-
- if (down_trylock(&fsm->sem)) {
- if (in_interrupt() || in_atomic() || irqs_disabled()) {
- pr_debug("%s(), state machine busy!\n", __func__);
- return -EWOULDBLOCK;
- } else
- down(&fsm->sem);
- }
-
- if (fsm->state == SIRDEV_STATE_DEAD) {
- /* race with sirdev_close should never happen */
- net_err_ratelimited("%s(), instance staled!\n", __func__);
- up(&fsm->sem);
- return -ESTALE; /* or better EPIPE? */
- }
-
- netif_stop_queue(dev->netdev);
- atomic_set(&dev->enable_rx, 0);
-
- fsm->state = initial_state;
- fsm->param = param;
- fsm->result = 0;
-
- INIT_DELAYED_WORK(&fsm->work, sirdev_config_fsm);
- queue_delayed_work(irda_sir_wq, &fsm->work, 0);
- return 0;
-}
-
-
-/***************************************************************************/
-
-void sirdev_enable_rx(struct sir_dev *dev)
-{
- if (unlikely(atomic_read(&dev->enable_rx)))
- return;
-
- /* flush rx-buffer - should also help in case of problems with echo cancelation */
- dev->rx_buff.data = dev->rx_buff.head;
- dev->rx_buff.len = 0;
- dev->rx_buff.in_frame = FALSE;
- dev->rx_buff.state = OUTSIDE_FRAME;
- atomic_set(&dev->enable_rx, 1);
-}
-
-static int sirdev_is_receiving(struct sir_dev *dev)
-{
- if (!atomic_read(&dev->enable_rx))
- return 0;
-
- return dev->rx_buff.state != OUTSIDE_FRAME;
-}
-
-int sirdev_set_dongle(struct sir_dev *dev, IRDA_DONGLE type)
-{
- int err;
-
- pr_debug("%s : requesting dongle %d.\n", __func__, type);
-
- err = sirdev_schedule_dongle_open(dev, type);
- if (unlikely(err))
- return err;
- down(&dev->fsm.sem); /* block until config change completed */
- err = dev->fsm.result;
- up(&dev->fsm.sem);
- return err;
-}
-EXPORT_SYMBOL(sirdev_set_dongle);
-
-/* used by dongle drivers for dongle programming */
-
-int sirdev_raw_write(struct sir_dev *dev, const char *buf, int len)
-{
- unsigned long flags;
- int ret;
-
- if (unlikely(len > dev->tx_buff.truesize))
- return -ENOSPC;
-
- spin_lock_irqsave(&dev->tx_lock, flags); /* serialize with other tx operations */
- while (dev->tx_buff.len > 0) { /* wait until tx idle */
- spin_unlock_irqrestore(&dev->tx_lock, flags);
- msleep(10);
- spin_lock_irqsave(&dev->tx_lock, flags);
- }
-
- dev->tx_buff.data = dev->tx_buff.head;
- memcpy(dev->tx_buff.data, buf, len);
- dev->tx_buff.len = len;
-
- ret = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len);
- if (ret > 0) {
- pr_debug("%s(), raw-tx started\n", __func__);
-
- dev->tx_buff.data += ret;
- dev->tx_buff.len -= ret;
- dev->raw_tx = 1;
- ret = len; /* all data is going to be sent */
- }
- spin_unlock_irqrestore(&dev->tx_lock, flags);
- return ret;
-}
-EXPORT_SYMBOL(sirdev_raw_write);
-
-/* seems some dongle drivers may need this */
-
-int sirdev_raw_read(struct sir_dev *dev, char *buf, int len)
-{
- int count;
-
- if (atomic_read(&dev->enable_rx))
- return -EIO; /* fail if we expect irda-frames */
-
- count = (len < dev->rx_buff.len) ? len : dev->rx_buff.len;
-
- if (count > 0) {
- memcpy(buf, dev->rx_buff.data, count);
- dev->rx_buff.data += count;
- dev->rx_buff.len -= count;
- }
-
- /* remaining stuff gets flushed when re-enabling normal rx */
-
- return count;
-}
-EXPORT_SYMBOL(sirdev_raw_read);
-
-int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts)
-{
- int ret = -ENXIO;
- if (dev->drv->set_dtr_rts)
- ret = dev->drv->set_dtr_rts(dev, dtr, rts);
- return ret;
-}
-EXPORT_SYMBOL(sirdev_set_dtr_rts);
-
-/**********************************************************************/
-
-/* called from client driver - likely with bh-context - to indicate
- * it made some progress with transmission. Hence we send the next
- * chunk, if any, or complete the skb otherwise
- */
-
-void sirdev_write_complete(struct sir_dev *dev)
-{
- unsigned long flags;
- struct sk_buff *skb;
- int actual = 0;
- int err;
-
- spin_lock_irqsave(&dev->tx_lock, flags);
-
- pr_debug("%s() - dev->tx_buff.len = %d\n",
- __func__, dev->tx_buff.len);
-
- if (likely(dev->tx_buff.len > 0)) {
- /* Write data left in transmit buffer */
- actual = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len);
-
- if (likely(actual>0)) {
- dev->tx_buff.data += actual;
- dev->tx_buff.len -= actual;
- }
- else if (unlikely(actual<0)) {
- /* could be dropped later when we have tx_timeout to recover */
- net_err_ratelimited("%s: drv->do_write failed (%d)\n",
- __func__, actual);
- if ((skb=dev->tx_skb) != NULL) {
- dev->tx_skb = NULL;
- dev_kfree_skb_any(skb);
- dev->netdev->stats.tx_errors++;
- dev->netdev->stats.tx_dropped++;
- }
- dev->tx_buff.len = 0;
- }
- if (dev->tx_buff.len > 0)
- goto done; /* more data to send later */
- }
-
- if (unlikely(dev->raw_tx != 0)) {
- /* in raw mode we are just done now after the buffer was sent
- * completely. Since this was requested by some dongle driver
- * running under the control of the irda-thread we must take
- * care here not to re-enable the queue. The queue will be
- * restarted when the irda-thread has completed the request.
- */
-
- pr_debug("%s(), raw-tx done\n", __func__);
- dev->raw_tx = 0;
- goto done; /* no post-frame handling in raw mode */
- }
-
- /* we have finished now sending this skb.
- * update statistics and free the skb.
- * finally we check and trigger a pending speed change, if any.
- * if not we switch to rx mode and wake the queue for further
- * packets.
- * note the scheduled speed request blocks until the lower
- * client driver and the corresponding hardware has really
- * finished sending all data (xmit fifo drained f.e.)
- * before the speed change gets finally done and the queue
- * re-activated.
- */
-
- pr_debug("%s(), finished with frame!\n", __func__);
-
- if ((skb=dev->tx_skb) != NULL) {
- dev->tx_skb = NULL;
- dev->netdev->stats.tx_packets++;
- dev->netdev->stats.tx_bytes += skb->len;
- dev_kfree_skb_any(skb);
- }
-
- if (unlikely(dev->new_speed > 0)) {
- pr_debug("%s(), Changing speed!\n", __func__);
- err = sirdev_schedule_speed(dev, dev->new_speed);
- if (unlikely(err)) {
- /* should never happen
- * forget the speed change and hope the stack recovers
- */
- net_err_ratelimited("%s - schedule speed change failed: %d\n",
- __func__, err);
- netif_wake_queue(dev->netdev);
- }
- /* else: success
- * speed change in progress now
- * on completion dev->new_speed gets cleared,
- * rx-reenabled and the queue restarted
- */
- }
- else {
- sirdev_enable_rx(dev);
- netif_wake_queue(dev->netdev);
- }
-
-done:
- spin_unlock_irqrestore(&dev->tx_lock, flags);
-}
-EXPORT_SYMBOL(sirdev_write_complete);
-
-/* called from client driver - likely with bh-context - to give us
- * some more received bytes. We put them into the rx-buffer,
- * normally unwrapping and building LAP-skb's (unless rx disabled)
- */
-
-int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count)
-{
- if (!dev || !dev->netdev) {
- net_warn_ratelimited("%s(), not ready yet!\n", __func__);
- return -1;
- }
-
- if (!dev->irlap) {
- net_warn_ratelimited("%s - too early: %p / %zd!\n",
- __func__, cp, count);
- return -1;
- }
-
- if (cp==NULL) {
- /* error already at lower level receive
- * just update stats and set media busy
- */
- irda_device_set_media_busy(dev->netdev, TRUE);
- dev->netdev->stats.rx_dropped++;
- pr_debug("%s; rx-drop: %zd\n", __func__, count);
- return 0;
- }
-
- /* Read the characters into the buffer */
- if (likely(atomic_read(&dev->enable_rx))) {
- while (count--)
- /* Unwrap and destuff one byte */
- async_unwrap_char(dev->netdev, &dev->netdev->stats,
- &dev->rx_buff, *cp++);
- } else {
- while (count--) {
- /* rx not enabled: save the raw bytes and never
- * trigger any netif_rx. The received bytes are flushed
- * later when we re-enable rx but might be read meanwhile
- * by the dongle driver.
- */
- dev->rx_buff.data[dev->rx_buff.len++] = *cp++;
-
- /* What should we do when the buffer is full? */
- if (unlikely(dev->rx_buff.len == dev->rx_buff.truesize))
- dev->rx_buff.len = 0;
- }
- }
-
- return 0;
-}
-EXPORT_SYMBOL(sirdev_receive);
-
-/**********************************************************************/
-
-/* callbacks from network layer */
-
-static netdev_tx_t sirdev_hard_xmit(struct sk_buff *skb,
- struct net_device *ndev)
-{
- struct sir_dev *dev = netdev_priv(ndev);
- unsigned long flags;
- int actual = 0;
- int err;
- s32 speed;
-
- IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
-
- netif_stop_queue(ndev);
-
- pr_debug("%s(), skb->len = %d\n", __func__, skb->len);
-
- speed = irda_get_next_speed(skb);
- if ((speed != dev->speed) && (speed != -1)) {
- if (!skb->len) {
- err = sirdev_schedule_speed(dev, speed);
- if (unlikely(err == -EWOULDBLOCK)) {
- /* Failed to initiate the speed change, likely the fsm
- * is still busy (pretty unlikely, but...)
- * We refuse to accept the skb and return with the queue
- * stopped so the network layer will retry after the
- * fsm completes and wakes the queue.
- */
- return NETDEV_TX_BUSY;
- }
- else if (unlikely(err)) {
- /* other fatal error - forget the speed change and
- * hope the stack will recover somehow
- */
- netif_start_queue(ndev);
- }
- /* else: success
- * speed change in progress now
- * on completion the queue gets restarted
- */
-
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
- } else
- dev->new_speed = speed;
- }
-
- /* Init tx buffer*/
- dev->tx_buff.data = dev->tx_buff.head;
-
- /* Check problems */
- if(spin_is_locked(&dev->tx_lock)) {
- pr_debug("%s(), write not completed\n", __func__);
- }
-
- /* serialize with write completion */
- spin_lock_irqsave(&dev->tx_lock, flags);
-
- /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
- dev->tx_buff.len = async_wrap_skb(skb, dev->tx_buff.data, dev->tx_buff.truesize);
-
- /* transmission will start now - disable receive.
- * if we are just in the middle of an incoming frame,
- * treat it as collision. probably it's a good idea to
- * reset the rx_buf OUTSIDE_FRAME in this case too?
- */
- atomic_set(&dev->enable_rx, 0);
- if (unlikely(sirdev_is_receiving(dev)))
- dev->netdev->stats.collisions++;
-
- actual = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len);
-
- if (likely(actual > 0)) {
- dev->tx_skb = skb;
- dev->tx_buff.data += actual;
- dev->tx_buff.len -= actual;
- }
- else if (unlikely(actual < 0)) {
- /* could be dropped later when we have tx_timeout to recover */
- net_err_ratelimited("%s: drv->do_write failed (%d)\n",
- __func__, actual);
- dev_kfree_skb_any(skb);
- dev->netdev->stats.tx_errors++;
- dev->netdev->stats.tx_dropped++;
- netif_wake_queue(ndev);
- }
- spin_unlock_irqrestore(&dev->tx_lock, flags);
-
- return NETDEV_TX_OK;
-}
-
-/* called from network layer with rtnl hold */
-
-static int sirdev_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
-{
- struct if_irda_req *irq = (struct if_irda_req *) rq;
- struct sir_dev *dev = netdev_priv(ndev);
- int ret = 0;
-
- IRDA_ASSERT(dev != NULL, return -1;);
-
- pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, ndev->name, cmd);
-
- switch (cmd) {
- case SIOCSBANDWIDTH: /* Set bandwidth */
- if (!capable(CAP_NET_ADMIN))
- ret = -EPERM;
- else
- ret = sirdev_schedule_speed(dev, irq->ifr_baudrate);
- /* cannot sleep here for completion
- * we are called from network layer with rtnl hold
- */
- break;
-
- case SIOCSDONGLE: /* Set dongle */
- if (!capable(CAP_NET_ADMIN))
- ret = -EPERM;
- else
- ret = sirdev_schedule_dongle_open(dev, irq->ifr_dongle);
- /* cannot sleep here for completion
- * we are called from network layer with rtnl hold
- */
- break;
-
- case SIOCSMEDIABUSY: /* Set media busy */
- if (!capable(CAP_NET_ADMIN))
- ret = -EPERM;
- else
- irda_device_set_media_busy(dev->netdev, TRUE);
- break;
-
- case SIOCGRECEIVING: /* Check if we are receiving right now */
- irq->ifr_receiving = sirdev_is_receiving(dev);
- break;
-
- case SIOCSDTRRTS:
- if (!capable(CAP_NET_ADMIN))
- ret = -EPERM;
- else
- ret = sirdev_schedule_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
- /* cannot sleep here for completion
- * we are called from network layer with rtnl hold
- */
- break;
-
- case SIOCSMODE:
-#if 0
- if (!capable(CAP_NET_ADMIN))
- ret = -EPERM;
- else
- ret = sirdev_schedule_mode(dev, irq->ifr_mode);
- /* cannot sleep here for completion
- * we are called from network layer with rtnl hold
- */
- break;
-#endif
- default:
- ret = -EOPNOTSUPP;
- }
-
- return ret;
-}
-
-/* ----------------------------------------------------------------------------- */
-
-#define SIRBUF_ALLOCSIZE 4269 /* worst case size of a wrapped IrLAP frame */
-
-static int sirdev_alloc_buffers(struct sir_dev *dev)
-{
- dev->tx_buff.truesize = SIRBUF_ALLOCSIZE;
- dev->rx_buff.truesize = IRDA_SKB_MAX_MTU;
-
- /* Bootstrap ZeroCopy Rx */
- dev->rx_buff.skb = __netdev_alloc_skb(dev->netdev, dev->rx_buff.truesize,
- GFP_KERNEL);
- if (dev->rx_buff.skb == NULL)
- return -ENOMEM;
- skb_reserve(dev->rx_buff.skb, 1);
- dev->rx_buff.head = dev->rx_buff.skb->data;
-
- dev->tx_buff.head = kmalloc(dev->tx_buff.truesize, GFP_KERNEL);
- if (dev->tx_buff.head == NULL) {
- kfree_skb(dev->rx_buff.skb);
- dev->rx_buff.skb = NULL;
- dev->rx_buff.head = NULL;
- return -ENOMEM;
- }
-
- dev->tx_buff.data = dev->tx_buff.head;
- dev->rx_buff.data = dev->rx_buff.head;
- dev->tx_buff.len = 0;
- dev->rx_buff.len = 0;
-
- dev->rx_buff.in_frame = FALSE;
- dev->rx_buff.state = OUTSIDE_FRAME;
- return 0;
-};
-
-static void sirdev_free_buffers(struct sir_dev *dev)
-{
- kfree_skb(dev->rx_buff.skb);
- kfree(dev->tx_buff.head);
- dev->rx_buff.head = dev->tx_buff.head = NULL;
- dev->rx_buff.skb = NULL;
-}
-
-static int sirdev_open(struct net_device *ndev)
-{
- struct sir_dev *dev = netdev_priv(ndev);
- const struct sir_driver *drv = dev->drv;
-
- if (!drv)
- return -ENODEV;
-
- /* increase the reference count of the driver module before doing serious stuff */
- if (!try_module_get(drv->owner))
- return -ESTALE;
-
- if (sirdev_alloc_buffers(dev))
- goto errout_dec;
-
- if (!dev->drv->start_dev || dev->drv->start_dev(dev))
- goto errout_free;
-
- sirdev_enable_rx(dev);
- dev->raw_tx = 0;
-
- netif_start_queue(ndev);
- dev->irlap = irlap_open(ndev, &dev->qos, dev->hwname);
- if (!dev->irlap)
- goto errout_stop;
-
- netif_wake_queue(ndev);
-
- pr_debug("%s - done, speed = %d\n", __func__, dev->speed);
-
- return 0;
-
-errout_stop:
- atomic_set(&dev->enable_rx, 0);
- if (dev->drv->stop_dev)
- dev->drv->stop_dev(dev);
-errout_free:
- sirdev_free_buffers(dev);
-errout_dec:
- module_put(drv->owner);
- return -EAGAIN;
-}
-
-static int sirdev_close(struct net_device *ndev)
-{
- struct sir_dev *dev = netdev_priv(ndev);
- const struct sir_driver *drv;
-
-/* pr_debug("%s\n", __func__); */
-
- netif_stop_queue(ndev);
-
- down(&dev->fsm.sem); /* block on pending config completion */
-
- atomic_set(&dev->enable_rx, 0);
-
- if (unlikely(!dev->irlap))
- goto out;
- irlap_close(dev->irlap);
- dev->irlap = NULL;
-
- drv = dev->drv;
- if (unlikely(!drv || !dev->priv))
- goto out;
-
- if (drv->stop_dev)
- drv->stop_dev(dev);
-
- sirdev_free_buffers(dev);
- module_put(drv->owner);
-
-out:
- dev->speed = 0;
- up(&dev->fsm.sem);
- return 0;
-}
-
-static const struct net_device_ops sirdev_ops = {
- .ndo_start_xmit = sirdev_hard_xmit,
- .ndo_open = sirdev_open,
- .ndo_stop = sirdev_close,
- .ndo_do_ioctl = sirdev_ioctl,
-};
-/* ----------------------------------------------------------------------------- */
-
-struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *name)
-{
- struct net_device *ndev;
- struct sir_dev *dev;
-
- pr_debug("%s - %s\n", __func__, name);
-
- /* instead of adding tests to protect against drv->do_write==NULL
- * at several places we refuse to create a sir_dev instance for
- * drivers which don't implement do_write.
- */
- if (!drv || !drv->do_write)
- return NULL;
-
- /*
- * Allocate new instance of the device
- */
- ndev = alloc_irdadev(sizeof(*dev));
- if (ndev == NULL) {
- net_err_ratelimited("%s - Can't allocate memory for IrDA control block!\n",
- __func__);
- goto out;
- }
- dev = netdev_priv(ndev);
-
- irda_init_max_qos_capabilies(&dev->qos);
- dev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
- dev->qos.min_turn_time.bits = drv->qos_mtt_bits;
- irda_qos_bits_to_value(&dev->qos);
-
- strncpy(dev->hwname, name, sizeof(dev->hwname)-1);
-
- atomic_set(&dev->enable_rx, 0);
- dev->tx_skb = NULL;
-
- spin_lock_init(&dev->tx_lock);
- sema_init(&dev->fsm.sem, 1);
-
- dev->drv = drv;
- dev->netdev = ndev;
-
- /* Override the network functions we need to use */
- ndev->netdev_ops = &sirdev_ops;
-
- if (register_netdev(ndev)) {
- net_err_ratelimited("%s(), register_netdev() failed!\n",
- __func__);
- goto out_freenetdev;
- }
-
- return dev;
-
-out_freenetdev:
- free_netdev(ndev);
-out:
- return NULL;
-}
-EXPORT_SYMBOL(sirdev_get_instance);
-
-int sirdev_put_instance(struct sir_dev *dev)
-{
- int err = 0;
-
- pr_debug("%s\n", __func__);
-
- atomic_set(&dev->enable_rx, 0);
-
- netif_carrier_off(dev->netdev);
- netif_device_detach(dev->netdev);
-
- if (dev->dongle_drv)
- err = sirdev_schedule_dongle_close(dev);
- if (err)
- net_err_ratelimited("%s - error %d\n", __func__, err);
-
- sirdev_close(dev->netdev);
-
- down(&dev->fsm.sem);
- dev->fsm.state = SIRDEV_STATE_DEAD; /* mark staled */
- dev->dongle_drv = NULL;
- dev->priv = NULL;
- up(&dev->fsm.sem);
-
- /* Remove netdevice */
- unregister_netdev(dev->netdev);
-
- free_netdev(dev->netdev);
-
- return 0;
-}
-EXPORT_SYMBOL(sirdev_put_instance);
-
-static int __init sir_wq_init(void)
-{
- irda_sir_wq = create_singlethread_workqueue("irda_sir_wq");
- if (!irda_sir_wq)
- return -ENOMEM;
- return 0;
-}
-
-static void __exit sir_wq_exit(void)
-{
- destroy_workqueue(irda_sir_wq);
-}
-
-module_init(sir_wq_init);
-module_exit(sir_wq_exit);
-
-MODULE_AUTHOR("Martin Diehl <info@mdiehl.de>");
-MODULE_DESCRIPTION("IrDA SIR core");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/irda/drivers/sir_dongle.c b/drivers/staging/irda/drivers/sir_dongle.c
deleted file mode 100644
index 7436f73ff1bb..000000000000
--- a/drivers/staging/irda/drivers/sir_dongle.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*********************************************************************
- *
- * sir_dongle.c: manager for serial dongle protocol drivers
- *
- * Copyright (c) 2002 Martin Diehl
- *
- * 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/kernel.h>
-#include <linux/kmod.h>
-#include <linux/mutex.h>
-
-#include <net/irda/irda.h>
-
-#include "sir-dev.h"
-
-/**************************************************************************
- *
- * dongle registration and attachment
- *
- */
-
-static LIST_HEAD(dongle_list); /* list of registered dongle drivers */
-static DEFINE_MUTEX(dongle_list_lock); /* protects the list */
-
-int irda_register_dongle(struct dongle_driver *new)
-{
- struct list_head *entry;
- struct dongle_driver *drv;
-
- pr_debug("%s : registering dongle \"%s\" (%d).\n",
- __func__, new->driver_name, new->type);
-
- mutex_lock(&dongle_list_lock);
- list_for_each(entry, &dongle_list) {
- drv = list_entry(entry, struct dongle_driver, dongle_list);
- if (new->type == drv->type) {
- mutex_unlock(&dongle_list_lock);
- return -EEXIST;
- }
- }
- list_add(&new->dongle_list, &dongle_list);
- mutex_unlock(&dongle_list_lock);
- return 0;
-}
-EXPORT_SYMBOL(irda_register_dongle);
-
-int irda_unregister_dongle(struct dongle_driver *drv)
-{
- mutex_lock(&dongle_list_lock);
- list_del(&drv->dongle_list);
- mutex_unlock(&dongle_list_lock);
- return 0;
-}
-EXPORT_SYMBOL(irda_unregister_dongle);
-
-int sirdev_get_dongle(struct sir_dev *dev, IRDA_DONGLE type)
-{
- struct list_head *entry;
- const struct dongle_driver *drv = NULL;
- int err = -EINVAL;
-
- request_module("irda-dongle-%d", type);
-
- if (dev->dongle_drv != NULL)
- return -EBUSY;
-
- /* serialize access to the list of registered dongles */
- mutex_lock(&dongle_list_lock);
-
- list_for_each(entry, &dongle_list) {
- drv = list_entry(entry, struct dongle_driver, dongle_list);
- if (drv->type == type)
- break;
- else
- drv = NULL;
- }
-
- if (!drv) {
- err = -ENODEV;
- goto out_unlock; /* no such dongle */
- }
-
- /* handling of SMP races with dongle module removal - three cases:
- * 1) dongle driver was already unregistered - then we haven't found the
- * requested dongle above and are already out here
- * 2) the module is already marked deleted but the driver is still
- * registered - then the try_module_get() below will fail
- * 3) the try_module_get() below succeeds before the module is marked
- * deleted - then sys_delete_module() fails and prevents the removal
- * because the module is in use.
- */
-
- if (!try_module_get(drv->owner)) {
- err = -ESTALE;
- goto out_unlock; /* rmmod already pending */
- }
- dev->dongle_drv = drv;
-
- if (!drv->open || (err=drv->open(dev))!=0)
- goto out_reject; /* failed to open driver */
-
- mutex_unlock(&dongle_list_lock);
- return 0;
-
-out_reject:
- dev->dongle_drv = NULL;
- module_put(drv->owner);
-out_unlock:
- mutex_unlock(&dongle_list_lock);
- return err;
-}
-
-int sirdev_put_dongle(struct sir_dev *dev)
-{
- const struct dongle_driver *drv = dev->dongle_drv;
-
- if (drv) {
- if (drv->close)
- drv->close(dev); /* close this dongle instance */
-
- dev->dongle_drv = NULL; /* unlink the dongle driver */
- module_put(drv->owner);/* decrement driver's module refcount */
- }
-
- return 0;
-}
diff --git a/drivers/staging/irda/drivers/smsc-ircc2.c b/drivers/staging/irda/drivers/smsc-ircc2.c
deleted file mode 100644
index 19a55cba6beb..000000000000
--- a/drivers/staging/irda/drivers/smsc-ircc2.c
+++ /dev/null
@@ -1,3026 +0,0 @@
-/*********************************************************************
- *
- * Description: Driver for the SMC Infrared Communications Controller
- * Author: Daniele Peri (peri@csai.unipa.it)
- * Created at:
- * Modified at:
- * Modified by:
- *
- * Copyright (c) 2002 Daniele Peri
- * All Rights Reserved.
- * Copyright (c) 2002 Jean Tourrilhes
- * Copyright (c) 2006 Linus Walleij
- *
- *
- * Based on smc-ircc.c:
- *
- * Copyright (c) 2001 Stefani Seibold
- * Copyright (c) 1999-2001 Dag Brattli
- * Copyright (c) 1998-1999 Thomas Davis,
- *
- * and irport.c:
- *
- * Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, 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.
- *
- * 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/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/rtnetlink.h>
-#include <linux/serial_reg.h>
-#include <linux/dma-mapping.h>
-#include <linux/pnp.h>
-#include <linux/platform_device.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-
-#include <linux/spinlock.h>
-#include <linux/pm.h>
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif
-
-#include <net/irda/wrapper.h>
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-
-#include "smsc-ircc2.h"
-#include "smsc-sio.h"
-
-
-MODULE_AUTHOR("Daniele Peri <peri@csai.unipa.it>");
-MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver");
-MODULE_LICENSE("GPL");
-
-static bool smsc_nopnp = true;
-module_param_named(nopnp, smsc_nopnp, bool, 0);
-MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings, defaults to true");
-
-#define DMA_INVAL 255
-static int ircc_dma = DMA_INVAL;
-module_param_hw(ircc_dma, int, dma, 0);
-MODULE_PARM_DESC(ircc_dma, "DMA channel");
-
-#define IRQ_INVAL 255
-static int ircc_irq = IRQ_INVAL;
-module_param_hw(ircc_irq, int, irq, 0);
-MODULE_PARM_DESC(ircc_irq, "IRQ line");
-
-static int ircc_fir;
-module_param_hw(ircc_fir, int, ioport, 0);
-MODULE_PARM_DESC(ircc_fir, "FIR Base Address");
-
-static int ircc_sir;
-module_param_hw(ircc_sir, int, ioport, 0);
-MODULE_PARM_DESC(ircc_sir, "SIR Base Address");
-
-static int ircc_cfg;
-module_param_hw(ircc_cfg, int, ioport, 0);
-MODULE_PARM_DESC(ircc_cfg, "Configuration register base address");
-
-static int ircc_transceiver;
-module_param(ircc_transceiver, int, 0);
-MODULE_PARM_DESC(ircc_transceiver, "Transceiver type");
-
-/* Types */
-
-#ifdef CONFIG_PCI
-struct smsc_ircc_subsystem_configuration {
- unsigned short vendor; /* PCI vendor ID */
- unsigned short device; /* PCI vendor ID */
- unsigned short subvendor; /* PCI subsystem vendor ID */
- unsigned short subdevice; /* PCI subsystem device ID */
- unsigned short sir_io; /* I/O port for SIR */
- unsigned short fir_io; /* I/O port for FIR */
- unsigned char fir_irq; /* FIR IRQ */
- unsigned char fir_dma; /* FIR DMA */
- unsigned short cfg_base; /* I/O port for chip configuration */
- int (*preconfigure)(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); /* Preconfig function */
- const char *name; /* name shown as info */
-};
-#endif
-
-struct smsc_transceiver {
- char *name;
- void (*set_for_speed)(int fir_base, u32 speed);
- int (*probe)(int fir_base);
-};
-
-struct smsc_chip {
- char *name;
- #if 0
- u8 type;
- #endif
- u16 flags;
- u8 devid;
- u8 rev;
-};
-
-struct smsc_chip_address {
- unsigned int cfg_base;
- unsigned int type;
-};
-
-/* Private data for each instance */
-struct smsc_ircc_cb {
- struct net_device *netdev; /* Yes! we are some kind of netdevice */
- struct irlap_cb *irlap; /* The link layer we are binded to */
-
- chipio_t io; /* IrDA controller information */
- iobuff_t tx_buff; /* Transmit buffer */
- iobuff_t rx_buff; /* Receive buffer */
- dma_addr_t tx_buff_dma;
- dma_addr_t rx_buff_dma;
-
- struct qos_info qos; /* QoS capabilities for this device */
-
- spinlock_t lock; /* For serializing operations */
-
- __u32 new_speed;
- __u32 flags; /* Interface flags */
-
- int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */
- int tx_len; /* Number of frames in tx_buff */
-
- int transceiver;
- struct platform_device *pldev;
-};
-
-/* Constants */
-
-#define SMSC_IRCC2_DRIVER_NAME "smsc-ircc2"
-
-#define SMSC_IRCC2_C_IRDA_FALLBACK_SPEED 9600
-#define SMSC_IRCC2_C_DEFAULT_TRANSCEIVER 1
-#define SMSC_IRCC2_C_NET_TIMEOUT 0
-#define SMSC_IRCC2_C_SIR_STOP 0
-
-static const char *driver_name = SMSC_IRCC2_DRIVER_NAME;
-
-/* Prototypes */
-
-static int smsc_ircc_open(unsigned int firbase, unsigned int sirbase, u8 dma, u8 irq);
-static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base);
-static void smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq);
-static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self);
-static void smsc_ircc_init_chip(struct smsc_ircc_cb *self);
-static int __exit smsc_ircc_close(struct smsc_ircc_cb *self);
-static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self);
-static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self);
-static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self);
-static netdev_tx_t smsc_ircc_hard_xmit_sir(struct sk_buff *skb,
- struct net_device *dev);
-static netdev_tx_t smsc_ircc_hard_xmit_fir(struct sk_buff *skb,
- struct net_device *dev);
-static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs);
-static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self);
-static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed);
-static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, u32 speed);
-static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id);
-static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev);
-static void smsc_ircc_sir_start(struct smsc_ircc_cb *self);
-#if SMSC_IRCC2_C_SIR_STOP
-static void smsc_ircc_sir_stop(struct smsc_ircc_cb *self);
-#endif
-static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self);
-static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len);
-static int smsc_ircc_net_open(struct net_device *dev);
-static int smsc_ircc_net_close(struct net_device *dev);
-static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-#if SMSC_IRCC2_C_NET_TIMEOUT
-static void smsc_ircc_timeout(struct net_device *dev);
-#endif
-static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self);
-static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self);
-static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed);
-static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self);
-
-/* Probing */
-static int __init smsc_ircc_look_for_chips(void);
-static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type);
-static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
-static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
-static int __init smsc_superio_fdc(unsigned short cfg_base);
-static int __init smsc_superio_lpc(unsigned short cfg_base);
-#ifdef CONFIG_PCI
-static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf);
-static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
-static void __init preconfigure_ali_port(struct pci_dev *dev,
- unsigned short port);
-static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
-static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
- unsigned short ircc_fir,
- unsigned short ircc_sir,
- unsigned char ircc_dma,
- unsigned char ircc_irq);
-#endif
-
-/* Transceivers specific functions */
-
-static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed);
-static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base);
-static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed);
-static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base);
-static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed);
-static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base);
-
-/* Power Management */
-
-static int smsc_ircc_suspend(struct platform_device *dev, pm_message_t state);
-static int smsc_ircc_resume(struct platform_device *dev);
-
-static struct platform_driver smsc_ircc_driver = {
- .suspend = smsc_ircc_suspend,
- .resume = smsc_ircc_resume,
- .driver = {
- .name = SMSC_IRCC2_DRIVER_NAME,
- },
-};
-
-/* Transceivers for SMSC-ircc */
-
-static struct smsc_transceiver smsc_transceivers[] =
-{
- { "Toshiba Satellite 1800 (GP data pin select)", smsc_ircc_set_transceiver_toshiba_sat1800, smsc_ircc_probe_transceiver_toshiba_sat1800 },
- { "Fast pin select", smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select, smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select },
- { "ATC IRMode", smsc_ircc_set_transceiver_smsc_ircc_atc, smsc_ircc_probe_transceiver_smsc_ircc_atc },
- { NULL, NULL }
-};
-#define SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS (ARRAY_SIZE(smsc_transceivers) - 1)
-
-/* SMC SuperIO chipsets definitions */
-
-#define KEY55_1 0 /* SuperIO Configuration mode with Key <0x55> */
-#define KEY55_2 1 /* SuperIO Configuration mode with Key <0x55,0x55> */
-#define NoIRDA 2 /* SuperIO Chip has no IRDA Port */
-#define SIR 0 /* SuperIO Chip has only slow IRDA */
-#define FIR 4 /* SuperIO Chip has fast IRDA */
-#define SERx4 8 /* SuperIO Chip supports 115,2 KBaud * 4=460,8 KBaud */
-
-static struct smsc_chip __initdata fdc_chips_flat[] =
-{
- /* Base address 0x3f0 or 0x370 */
- { "37C44", KEY55_1|NoIRDA, 0x00, 0x00 }, /* This chip cannot be detected */
- { "37C665GT", KEY55_2|NoIRDA, 0x65, 0x01 },
- { "37C665GT", KEY55_2|NoIRDA, 0x66, 0x01 },
- { "37C669", KEY55_2|SIR|SERx4, 0x03, 0x02 },
- { "37C669", KEY55_2|SIR|SERx4, 0x04, 0x02 }, /* ID? */
- { "37C78", KEY55_2|NoIRDA, 0x78, 0x00 },
- { "37N769", KEY55_1|FIR|SERx4, 0x28, 0x00 },
- { "37N869", KEY55_1|FIR|SERx4, 0x29, 0x00 },
- { NULL }
-};
-
-static struct smsc_chip __initdata fdc_chips_paged[] =
-{
- /* Base address 0x3f0 or 0x370 */
- { "37B72X", KEY55_1|SIR|SERx4, 0x4c, 0x00 },
- { "37B77X", KEY55_1|SIR|SERx4, 0x43, 0x00 },
- { "37B78X", KEY55_1|SIR|SERx4, 0x44, 0x00 },
- { "37B80X", KEY55_1|SIR|SERx4, 0x42, 0x00 },
- { "37C67X", KEY55_1|FIR|SERx4, 0x40, 0x00 },
- { "37C93X", KEY55_2|SIR|SERx4, 0x02, 0x01 },
- { "37C93XAPM", KEY55_1|SIR|SERx4, 0x30, 0x01 },
- { "37C93XFR", KEY55_2|FIR|SERx4, 0x03, 0x01 },
- { "37M707", KEY55_1|SIR|SERx4, 0x42, 0x00 },
- { "37M81X", KEY55_1|SIR|SERx4, 0x4d, 0x00 },
- { "37N958FR", KEY55_1|FIR|SERx4, 0x09, 0x04 },
- { "37N971", KEY55_1|FIR|SERx4, 0x0a, 0x00 },
- { "37N972", KEY55_1|FIR|SERx4, 0x0b, 0x00 },
- { NULL }
-};
-
-static struct smsc_chip __initdata lpc_chips_flat[] =
-{
- /* Base address 0x2E or 0x4E */
- { "47N227", KEY55_1|FIR|SERx4, 0x5a, 0x00 },
- { "47N227", KEY55_1|FIR|SERx4, 0x7a, 0x00 },
- { "47N267", KEY55_1|FIR|SERx4, 0x5e, 0x00 },
- { NULL }
-};
-
-static struct smsc_chip __initdata lpc_chips_paged[] =
-{
- /* Base address 0x2E or 0x4E */
- { "47B27X", KEY55_1|SIR|SERx4, 0x51, 0x00 },
- { "47B37X", KEY55_1|SIR|SERx4, 0x52, 0x00 },
- { "47M10X", KEY55_1|SIR|SERx4, 0x59, 0x00 },
- { "47M120", KEY55_1|NoIRDA|SERx4, 0x5c, 0x00 },
- { "47M13X", KEY55_1|SIR|SERx4, 0x59, 0x00 },
- { "47M14X", KEY55_1|SIR|SERx4, 0x5f, 0x00 },
- { "47N252", KEY55_1|FIR|SERx4, 0x0e, 0x00 },
- { "47S42X", KEY55_1|SIR|SERx4, 0x57, 0x00 },
- { NULL }
-};
-
-#define SMSCSIO_TYPE_FDC 1
-#define SMSCSIO_TYPE_LPC 2
-#define SMSCSIO_TYPE_FLAT 4
-#define SMSCSIO_TYPE_PAGED 8
-
-static struct smsc_chip_address __initdata possible_addresses[] =
-{
- { 0x3f0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
- { 0x370, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
- { 0xe0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
- { 0x2e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
- { 0x4e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED },
- { 0, 0 }
-};
-
-/* Globals */
-
-static struct smsc_ircc_cb *dev_self[] = { NULL, NULL };
-static unsigned short dev_count;
-
-static inline void register_bank(int iobase, int bank)
-{
- outb(((inb(iobase + IRCC_MASTER) & 0xf0) | (bank & 0x07)),
- iobase + IRCC_MASTER);
-}
-
-/* PNP hotplug support */
-static const struct pnp_device_id smsc_ircc_pnp_table[] = {
- { .id = "SMCf010", .driver_data = 0 },
- /* and presumably others */
- { }
-};
-MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table);
-
-static int pnp_driver_registered;
-
-#ifdef CONFIG_PNP
-static int smsc_ircc_pnp_probe(struct pnp_dev *dev,
- const struct pnp_device_id *dev_id)
-{
- unsigned int firbase, sirbase;
- u8 dma, irq;
-
- if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
- pnp_dma_valid(dev, 0) && pnp_irq_valid(dev, 0)))
- return -EINVAL;
-
- sirbase = pnp_port_start(dev, 0);
- firbase = pnp_port_start(dev, 1);
- dma = pnp_dma(dev, 0);
- irq = pnp_irq(dev, 0);
-
- if (smsc_ircc_open(firbase, sirbase, dma, irq))
- return -ENODEV;
-
- return 0;
-}
-
-static struct pnp_driver smsc_ircc_pnp_driver = {
- .name = "smsc-ircc2",
- .id_table = smsc_ircc_pnp_table,
- .probe = smsc_ircc_pnp_probe,
-};
-#else /* CONFIG_PNP */
-static struct pnp_driver smsc_ircc_pnp_driver;
-#endif
-
-/*******************************************************************************
- *
- *
- * SMSC-ircc stuff
- *
- *
- *******************************************************************************/
-
-static int __init smsc_ircc_legacy_probe(void)
-{
- int ret = 0;
-
-#ifdef CONFIG_PCI
- if (smsc_ircc_preconfigure_subsystems(ircc_cfg, ircc_fir, ircc_sir, ircc_dma, ircc_irq) < 0) {
- /* Ignore errors from preconfiguration */
- net_err_ratelimited("%s, Preconfiguration failed !\n",
- driver_name);
- }
-#endif
-
- if (ircc_fir > 0 && ircc_sir > 0) {
- net_info_ratelimited(" Overriding FIR address 0x%04x\n",
- ircc_fir);
- net_info_ratelimited(" Overriding SIR address 0x%04x\n",
- ircc_sir);
-
- if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq))
- ret = -ENODEV;
- } else {
- ret = -ENODEV;
-
- /* try user provided configuration register base address */
- if (ircc_cfg > 0) {
- net_info_ratelimited(" Overriding configuration address 0x%04x\n",
- ircc_cfg);
- if (!smsc_superio_fdc(ircc_cfg))
- ret = 0;
- if (!smsc_superio_lpc(ircc_cfg))
- ret = 0;
- }
-
- if (smsc_ircc_look_for_chips() > 0)
- ret = 0;
- }
- return ret;
-}
-
-/*
- * Function smsc_ircc_init ()
- *
- * Initialize chip. Just try to find out how many chips we are dealing with
- * and where they are
- */
-static int __init smsc_ircc_init(void)
-{
- int ret;
-
- pr_debug("%s\n", __func__);
-
- ret = platform_driver_register(&smsc_ircc_driver);
- if (ret) {
- net_err_ratelimited("%s, Can't register driver!\n",
- driver_name);
- return ret;
- }
-
- dev_count = 0;
-
- if (smsc_nopnp || !pnp_platform_devices ||
- ircc_cfg || ircc_fir || ircc_sir ||
- ircc_dma != DMA_INVAL || ircc_irq != IRQ_INVAL) {
- ret = smsc_ircc_legacy_probe();
- } else {
- if (pnp_register_driver(&smsc_ircc_pnp_driver) == 0)
- pnp_driver_registered = 1;
- }
-
- if (ret) {
- if (pnp_driver_registered)
- pnp_unregister_driver(&smsc_ircc_pnp_driver);
- platform_driver_unregister(&smsc_ircc_driver);
- }
-
- return ret;
-}
-
-static netdev_tx_t smsc_ircc_net_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct smsc_ircc_cb *self = netdev_priv(dev);
-
- if (self->io.speed > 115200)
- return smsc_ircc_hard_xmit_fir(skb, dev);
- else
- return smsc_ircc_hard_xmit_sir(skb, dev);
-}
-
-static const struct net_device_ops smsc_ircc_netdev_ops = {
- .ndo_open = smsc_ircc_net_open,
- .ndo_stop = smsc_ircc_net_close,
- .ndo_do_ioctl = smsc_ircc_net_ioctl,
- .ndo_start_xmit = smsc_ircc_net_xmit,
-#if SMSC_IRCC2_C_NET_TIMEOUT
- .ndo_tx_timeout = smsc_ircc_timeout,
-#endif
-};
-
-/*
- * Function smsc_ircc_open (firbase, sirbase, dma, irq)
- *
- * Try to open driver instance
- *
- */
-static int smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
-{
- struct smsc_ircc_cb *self;
- struct net_device *dev;
- int err;
-
- pr_debug("%s\n", __func__);
-
- err = smsc_ircc_present(fir_base, sir_base);
- if (err)
- goto err_out;
-
- err = -ENOMEM;
- if (dev_count >= ARRAY_SIZE(dev_self)) {
- net_warn_ratelimited("%s(), too many devices!\n", __func__);
- goto err_out1;
- }
-
- /*
- * Allocate new instance of the driver
- */
- dev = alloc_irdadev(sizeof(struct smsc_ircc_cb));
- if (!dev) {
- net_warn_ratelimited("%s() can't allocate net device\n",
- __func__);
- goto err_out1;
- }
-
-#if SMSC_IRCC2_C_NET_TIMEOUT
- dev->watchdog_timeo = HZ * 2; /* Allow enough time for speed change */
-#endif
- dev->netdev_ops = &smsc_ircc_netdev_ops;
-
- self = netdev_priv(dev);
- self->netdev = dev;
-
- /* Make ifconfig display some details */
- dev->base_addr = self->io.fir_base = fir_base;
- dev->irq = self->io.irq = irq;
-
- /* Need to store self somewhere */
- dev_self[dev_count] = self;
- spin_lock_init(&self->lock);
-
- self->rx_buff.truesize = SMSC_IRCC2_RX_BUFF_TRUESIZE;
- self->tx_buff.truesize = SMSC_IRCC2_TX_BUFF_TRUESIZE;
-
- self->rx_buff.head =
- dma_zalloc_coherent(NULL, self->rx_buff.truesize,
- &self->rx_buff_dma, GFP_KERNEL);
- if (self->rx_buff.head == NULL)
- goto err_out2;
-
- self->tx_buff.head =
- dma_zalloc_coherent(NULL, self->tx_buff.truesize,
- &self->tx_buff_dma, GFP_KERNEL);
- if (self->tx_buff.head == NULL)
- goto err_out3;
-
- self->rx_buff.in_frame = FALSE;
- self->rx_buff.state = OUTSIDE_FRAME;
- self->tx_buff.data = self->tx_buff.head;
- self->rx_buff.data = self->rx_buff.head;
-
- smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq);
- smsc_ircc_setup_qos(self);
- smsc_ircc_init_chip(self);
-
- if (ircc_transceiver > 0 &&
- ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS)
- self->transceiver = ircc_transceiver;
- else
- smsc_ircc_probe_transceiver(self);
-
- err = register_netdev(self->netdev);
- if (err) {
- net_err_ratelimited("%s, Network device registration failed!\n",
- driver_name);
- goto err_out4;
- }
-
- self->pldev = platform_device_register_simple(SMSC_IRCC2_DRIVER_NAME,
- dev_count, NULL, 0);
- if (IS_ERR(self->pldev)) {
- err = PTR_ERR(self->pldev);
- goto err_out5;
- }
- platform_set_drvdata(self->pldev, self);
-
- net_info_ratelimited("IrDA: Registered device %s\n", dev->name);
- dev_count++;
-
- return 0;
-
- err_out5:
- unregister_netdev(self->netdev);
-
- err_out4:
- dma_free_coherent(NULL, self->tx_buff.truesize,
- self->tx_buff.head, self->tx_buff_dma);
- err_out3:
- dma_free_coherent(NULL, self->rx_buff.truesize,
- self->rx_buff.head, self->rx_buff_dma);
- err_out2:
- free_netdev(self->netdev);
- dev_self[dev_count] = NULL;
- err_out1:
- release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT);
- release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT);
- err_out:
- return err;
-}
-
-/*
- * Function smsc_ircc_present(fir_base, sir_base)
- *
- * Check the smsc-ircc chip presence
- *
- */
-static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base)
-{
- unsigned char low, high, chip, config, dma, irq, version;
-
- if (!request_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT,
- driver_name)) {
- net_warn_ratelimited("%s: can't get fir_base of 0x%03x\n",
- __func__, fir_base);
- goto out1;
- }
-
- if (!request_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT,
- driver_name)) {
- net_warn_ratelimited("%s: can't get sir_base of 0x%03x\n",
- __func__, sir_base);
- goto out2;
- }
-
- register_bank(fir_base, 3);
-
- high = inb(fir_base + IRCC_ID_HIGH);
- low = inb(fir_base + IRCC_ID_LOW);
- chip = inb(fir_base + IRCC_CHIP_ID);
- version = inb(fir_base + IRCC_VERSION);
- config = inb(fir_base + IRCC_INTERFACE);
- dma = config & IRCC_INTERFACE_DMA_MASK;
- irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
-
- if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) {
- net_warn_ratelimited("%s(), addr 0x%04x - no device found!\n",
- __func__, fir_base);
- goto out3;
- }
- net_info_ratelimited("SMsC IrDA Controller found\n IrCC version %d.%d, firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n",
- chip & 0x0f, version,
- fir_base, sir_base, dma, irq);
-
- return 0;
-
- out3:
- release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT);
- out2:
- release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT);
- out1:
- return -ENODEV;
-}
-
-/*
- * Function smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq)
- *
- * Setup I/O
- *
- */
-static void smsc_ircc_setup_io(struct smsc_ircc_cb *self,
- unsigned int fir_base, unsigned int sir_base,
- u8 dma, u8 irq)
-{
- unsigned char config, chip_dma, chip_irq;
-
- register_bank(fir_base, 3);
- config = inb(fir_base + IRCC_INTERFACE);
- chip_dma = config & IRCC_INTERFACE_DMA_MASK;
- chip_irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
-
- self->io.fir_base = fir_base;
- self->io.sir_base = sir_base;
- self->io.fir_ext = SMSC_IRCC2_FIR_CHIP_IO_EXTENT;
- self->io.sir_ext = SMSC_IRCC2_SIR_CHIP_IO_EXTENT;
- self->io.fifo_size = SMSC_IRCC2_FIFO_SIZE;
- self->io.speed = SMSC_IRCC2_C_IRDA_FALLBACK_SPEED;
-
- if (irq != IRQ_INVAL) {
- if (irq != chip_irq)
- net_info_ratelimited("%s, Overriding IRQ - chip says %d, using %d\n",
- driver_name, chip_irq, irq);
- self->io.irq = irq;
- } else
- self->io.irq = chip_irq;
-
- if (dma != DMA_INVAL) {
- if (dma != chip_dma)
- net_info_ratelimited("%s, Overriding DMA - chip says %d, using %d\n",
- driver_name, chip_dma, dma);
- self->io.dma = dma;
- } else
- self->io.dma = chip_dma;
-
-}
-
-/*
- * Function smsc_ircc_setup_qos(self)
- *
- * Setup qos
- *
- */
-static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self)
-{
- /* Initialize QoS for this device */
- irda_init_max_qos_capabilies(&self->qos);
-
- self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
- IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
-
- self->qos.min_turn_time.bits = SMSC_IRCC2_MIN_TURN_TIME;
- self->qos.window_size.bits = SMSC_IRCC2_WINDOW_SIZE;
- irda_qos_bits_to_value(&self->qos);
-}
-
-/*
- * Function smsc_ircc_init_chip(self)
- *
- * Init chip
- *
- */
-static void smsc_ircc_init_chip(struct smsc_ircc_cb *self)
-{
- int iobase = self->io.fir_base;
-
- register_bank(iobase, 0);
- outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER);
- outb(0x00, iobase + IRCC_MASTER);
-
- register_bank(iobase, 1);
- outb(((inb(iobase + IRCC_SCE_CFGA) & 0x87) | IRCC_CFGA_IRDA_SIR_A),
- iobase + IRCC_SCE_CFGA);
-
-#ifdef smsc_669 /* Uses pin 88/89 for Rx/Tx */
- outb(((inb(iobase + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
- iobase + IRCC_SCE_CFGB);
-#else
- outb(((inb(iobase + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
- iobase + IRCC_SCE_CFGB);
-#endif
- (void) inb(iobase + IRCC_FIFO_THRESHOLD);
- outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase + IRCC_FIFO_THRESHOLD);
-
- register_bank(iobase, 4);
- outb((inb(iobase + IRCC_CONTROL) & 0x30), iobase + IRCC_CONTROL);
-
- register_bank(iobase, 0);
- outb(0, iobase + IRCC_LCR_A);
-
- smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
-
- /* Power on device */
- outb(0x00, iobase + IRCC_MASTER);
-}
-
-/*
- * Function smsc_ircc_net_ioctl (dev, rq, cmd)
- *
- * Process IOCTL commands for this device
- *
- */
-static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct if_irda_req *irq = (struct if_irda_req *) rq;
- struct smsc_ircc_cb *self;
- unsigned long flags;
- int ret = 0;
-
- IRDA_ASSERT(dev != NULL, return -1;);
-
- self = netdev_priv(dev);
-
- IRDA_ASSERT(self != NULL, return -1;);
-
- pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
-
- switch (cmd) {
- case SIOCSBANDWIDTH: /* Set bandwidth */
- if (!capable(CAP_NET_ADMIN))
- ret = -EPERM;
- else {
- /* Make sure we are the only one touching
- * self->io.speed and the hardware - Jean II */
- spin_lock_irqsave(&self->lock, flags);
- smsc_ircc_change_speed(self, irq->ifr_baudrate);
- spin_unlock_irqrestore(&self->lock, flags);
- }
- break;
- case SIOCSMEDIABUSY: /* Set media busy */
- if (!capable(CAP_NET_ADMIN)) {
- ret = -EPERM;
- break;
- }
-
- irda_device_set_media_busy(self->netdev, TRUE);
- break;
- case SIOCGRECEIVING: /* Check if we are receiving right now */
- irq->ifr_receiving = smsc_ircc_is_receiving(self);
- break;
- #if 0
- case SIOCSDTRRTS:
- if (!capable(CAP_NET_ADMIN)) {
- ret = -EPERM;
- break;
- }
- smsc_ircc_sir_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
- break;
- #endif
- default:
- ret = -EOPNOTSUPP;
- }
-
- return ret;
-}
-
-#if SMSC_IRCC2_C_NET_TIMEOUT
-/*
- * Function smsc_ircc_timeout (struct net_device *dev)
- *
- * The networking timeout management.
- *
- */
-
-static void smsc_ircc_timeout(struct net_device *dev)
-{
- struct smsc_ircc_cb *self = netdev_priv(dev);
- unsigned long flags;
-
- net_warn_ratelimited("%s: transmit timed out, changing speed to: %d\n",
- dev->name, self->io.speed);
- spin_lock_irqsave(&self->lock, flags);
- smsc_ircc_sir_start(self);
- smsc_ircc_change_speed(self, self->io.speed);
- netif_trans_update(dev); /* prevent tx timeout */
- netif_wake_queue(dev);
- spin_unlock_irqrestore(&self->lock, flags);
-}
-#endif
-
-/*
- * Function smsc_ircc_hard_xmit_sir (struct sk_buff *skb, struct net_device *dev)
- *
- * Transmits the current frame until FIFO is full, then
- * waits until the next transmit interrupt, and continues until the
- * frame is transmitted.
- */
-static netdev_tx_t smsc_ircc_hard_xmit_sir(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct smsc_ircc_cb *self;
- unsigned long flags;
- s32 speed;
-
- pr_debug("%s\n", __func__);
-
- IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
-
- self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
-
- netif_stop_queue(dev);
-
- /* Make sure test of self->io.speed & speed change are atomic */
- spin_lock_irqsave(&self->lock, flags);
-
- /* Check if we need to change the speed */
- speed = irda_get_next_speed(skb);
- if (speed != self->io.speed && speed != -1) {
- /* Check for empty frame */
- if (!skb->len) {
- /*
- * We send frames one by one in SIR mode (no
- * pipelining), so at this point, if we were sending
- * a previous frame, we just received the interrupt
- * telling us it is finished (UART_IIR_THRI).
- * Therefore, waiting for the transmitter to really
- * finish draining the fifo won't take too long.
- * And the interrupt handler is not expected to run.
- * - Jean II */
- smsc_ircc_sir_wait_hw_transmitter_finish(self);
- smsc_ircc_change_speed(self, speed);
- spin_unlock_irqrestore(&self->lock, flags);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- self->new_speed = speed;
- }
-
- /* Init tx buffer */
- self->tx_buff.data = self->tx_buff.head;
-
- /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
- self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
- self->tx_buff.truesize);
-
- dev->stats.tx_bytes += self->tx_buff.len;
-
- /* Turn on transmit finished interrupt. Will fire immediately! */
- outb(UART_IER_THRI, self->io.sir_base + UART_IER);
-
- spin_unlock_irqrestore(&self->lock, flags);
-
- dev_kfree_skb(skb);
-
- return NETDEV_TX_OK;
-}
-
-/*
- * Function smsc_ircc_set_fir_speed (self, baud)
- *
- * Change the speed of the device
- *
- */
-static void smsc_ircc_set_fir_speed(struct smsc_ircc_cb *self, u32 speed)
-{
- int fir_base, ir_mode, ctrl, fast;
-
- IRDA_ASSERT(self != NULL, return;);
- fir_base = self->io.fir_base;
-
- self->io.speed = speed;
-
- switch (speed) {
- default:
- case 576000:
- ir_mode = IRCC_CFGA_IRDA_HDLC;
- ctrl = IRCC_CRC;
- fast = 0;
- pr_debug("%s(), handling baud of 576000\n", __func__);
- break;
- case 1152000:
- ir_mode = IRCC_CFGA_IRDA_HDLC;
- ctrl = IRCC_1152 | IRCC_CRC;
- fast = IRCC_LCR_A_FAST | IRCC_LCR_A_GP_DATA;
- pr_debug("%s(), handling baud of 1152000\n",
- __func__);
- break;
- case 4000000:
- ir_mode = IRCC_CFGA_IRDA_4PPM;
- ctrl = IRCC_CRC;
- fast = IRCC_LCR_A_FAST;
- pr_debug("%s(), handling baud of 4000000\n",
- __func__);
- break;
- }
- #if 0
- Now in tranceiver!
- /* This causes an interrupt */
- register_bank(fir_base, 0);
- outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast, fir_base + IRCC_LCR_A);
- #endif
-
- register_bank(fir_base, 1);
- outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | ir_mode), fir_base + IRCC_SCE_CFGA);
-
- register_bank(fir_base, 4);
- outb((inb(fir_base + IRCC_CONTROL) & 0x30) | ctrl, fir_base + IRCC_CONTROL);
-}
-
-/*
- * Function smsc_ircc_fir_start(self)
- *
- * Change the speed of the device
- *
- */
-static void smsc_ircc_fir_start(struct smsc_ircc_cb *self)
-{
- struct net_device *dev;
- int fir_base;
-
- pr_debug("%s\n", __func__);
-
- IRDA_ASSERT(self != NULL, return;);
- dev = self->netdev;
- IRDA_ASSERT(dev != NULL, return;);
-
- fir_base = self->io.fir_base;
-
- /* Reset everything */
-
- /* Clear FIFO */
- outb(inb(fir_base + IRCC_LCR_A) | IRCC_LCR_A_FIFO_RESET, fir_base + IRCC_LCR_A);
-
- /* Enable interrupt */
- /*outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base + IRCC_IER);*/
-
- register_bank(fir_base, 1);
-
- /* Select the TX/RX interface */
-#ifdef SMSC_669 /* Uses pin 88/89 for Rx/Tx */
- outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
- fir_base + IRCC_SCE_CFGB);
-#else
- outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
- fir_base + IRCC_SCE_CFGB);
-#endif
- (void) inb(fir_base + IRCC_FIFO_THRESHOLD);
-
- /* Enable SCE interrupts */
- outb(0, fir_base + IRCC_MASTER);
- register_bank(fir_base, 0);
- outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, fir_base + IRCC_IER);
- outb(IRCC_MASTER_INT_EN, fir_base + IRCC_MASTER);
-}
-
-/*
- * Function smsc_ircc_fir_stop(self, baud)
- *
- * Change the speed of the device
- *
- */
-static void smsc_ircc_fir_stop(struct smsc_ircc_cb *self)
-{
- int fir_base;
-
- pr_debug("%s\n", __func__);
-
- IRDA_ASSERT(self != NULL, return;);
-
- fir_base = self->io.fir_base;
- register_bank(fir_base, 0);
- /*outb(IRCC_MASTER_RESET, fir_base + IRCC_MASTER);*/
- outb(inb(fir_base + IRCC_LCR_B) & IRCC_LCR_B_SIP_ENABLE, fir_base + IRCC_LCR_B);
-}
-
-
-/*
- * Function smsc_ircc_change_speed(self, baud)
- *
- * Change the speed of the device
- *
- * This function *must* be called with spinlock held, because it may
- * be called from the irq handler. - Jean II
- */
-static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed)
-{
- struct net_device *dev;
- int last_speed_was_sir;
-
- pr_debug("%s() changing speed to: %d\n", __func__, speed);
-
- IRDA_ASSERT(self != NULL, return;);
- dev = self->netdev;
-
- last_speed_was_sir = self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED;
-
- #if 0
- /* Temp Hack */
- speed= 1152000;
- self->io.speed = speed;
- last_speed_was_sir = 0;
- smsc_ircc_fir_start(self);
- #endif
-
- if (self->io.speed == 0)
- smsc_ircc_sir_start(self);
-
- #if 0
- if (!last_speed_was_sir) speed = self->io.speed;
- #endif
-
- if (self->io.speed != speed)
- smsc_ircc_set_transceiver_for_speed(self, speed);
-
- self->io.speed = speed;
-
- if (speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
- if (!last_speed_was_sir) {
- smsc_ircc_fir_stop(self);
- smsc_ircc_sir_start(self);
- }
- smsc_ircc_set_sir_speed(self, speed);
- } else {
- if (last_speed_was_sir) {
- #if SMSC_IRCC2_C_SIR_STOP
- smsc_ircc_sir_stop(self);
- #endif
- smsc_ircc_fir_start(self);
- }
- smsc_ircc_set_fir_speed(self, speed);
-
- #if 0
- self->tx_buff.len = 10;
- self->tx_buff.data = self->tx_buff.head;
-
- smsc_ircc_dma_xmit(self, 4000);
- #endif
- /* Be ready for incoming frames */
- smsc_ircc_dma_receive(self);
- }
-
- netif_wake_queue(dev);
-}
-
-/*
- * Function smsc_ircc_set_sir_speed (self, speed)
- *
- * Set speed of IrDA port to specified baudrate
- *
- */
-static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed)
-{
- int iobase;
- int fcr; /* FIFO control reg */
- int lcr; /* Line control reg */
- int divisor;
-
- pr_debug("%s(), Setting speed to: %d\n", __func__, speed);
-
- IRDA_ASSERT(self != NULL, return;);
- iobase = self->io.sir_base;
-
- /* Update accounting for new speed */
- self->io.speed = speed;
-
- /* Turn off interrupts */
- outb(0, iobase + UART_IER);
-
- divisor = SMSC_IRCC2_MAX_SIR_SPEED / speed;
-
- fcr = UART_FCR_ENABLE_FIFO;
-
- /*
- * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
- * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
- * about this timeout since it will always be fast enough.
- */
- fcr |= self->io.speed < 38400 ?
- UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14;
-
- /* IrDA ports use 8N1 */
- lcr = UART_LCR_WLEN8;
-
- outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */
- outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */
- outb(divisor >> 8, iobase + UART_DLM);
- outb(lcr, iobase + UART_LCR); /* Set 8N1 */
- outb(fcr, iobase + UART_FCR); /* Enable FIFO's */
-
- /* Turn on interrups */
- outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
-
- pr_debug("%s() speed changed to: %d\n", __func__, speed);
-}
-
-
-/*
- * Function smsc_ircc_hard_xmit_fir (skb, dev)
- *
- * Transmit the frame!
- *
- */
-static netdev_tx_t smsc_ircc_hard_xmit_fir(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct smsc_ircc_cb *self;
- unsigned long flags;
- s32 speed;
- int mtt;
-
- IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
- self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
-
- netif_stop_queue(dev);
-
- /* Make sure test of self->io.speed & speed change are atomic */
- spin_lock_irqsave(&self->lock, flags);
-
- /* Check if we need to change the speed after this frame */
- speed = irda_get_next_speed(skb);
- if (speed != self->io.speed && speed != -1) {
- /* Check for empty frame */
- if (!skb->len) {
- /* Note : you should make sure that speed changes
- * are not going to corrupt any outgoing frame.
- * Look at nsc-ircc for the gory details - Jean II */
- smsc_ircc_change_speed(self, speed);
- spin_unlock_irqrestore(&self->lock, flags);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- self->new_speed = speed;
- }
-
- skb_copy_from_linear_data(skb, self->tx_buff.head, skb->len);
-
- self->tx_buff.len = skb->len;
- self->tx_buff.data = self->tx_buff.head;
-
- mtt = irda_get_mtt(skb);
- if (mtt) {
- int bofs;
-
- /*
- * Compute how many BOFs (STA or PA's) we need to waste the
- * min turn time given the speed of the link.
- */
- bofs = mtt * (self->io.speed / 1000) / 8000;
- if (bofs > 4095)
- bofs = 4095;
-
- smsc_ircc_dma_xmit(self, bofs);
- } else {
- /* Transmit frame */
- smsc_ircc_dma_xmit(self, 0);
- }
-
- spin_unlock_irqrestore(&self->lock, flags);
- dev_kfree_skb(skb);
-
- return NETDEV_TX_OK;
-}
-
-/*
- * Function smsc_ircc_dma_xmit (self, bofs)
- *
- * Transmit data using DMA
- *
- */
-static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs)
-{
- int iobase = self->io.fir_base;
- u8 ctrl;
-
- pr_debug("%s\n", __func__);
-#if 1
- /* Disable Rx */
- register_bank(iobase, 0);
- outb(0x00, iobase + IRCC_LCR_B);
-#endif
- register_bank(iobase, 1);
- outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
- iobase + IRCC_SCE_CFGB);
-
- self->io.direction = IO_XMIT;
-
- /* Set BOF additional count for generating the min turn time */
- register_bank(iobase, 4);
- outb(bofs & 0xff, iobase + IRCC_BOF_COUNT_LO);
- ctrl = inb(iobase + IRCC_CONTROL) & 0xf0;
- outb(ctrl | ((bofs >> 8) & 0x0f), iobase + IRCC_BOF_COUNT_HI);
-
- /* Set max Tx frame size */
- outb(self->tx_buff.len >> 8, iobase + IRCC_TX_SIZE_HI);
- outb(self->tx_buff.len & 0xff, iobase + IRCC_TX_SIZE_LO);
-
- /*outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR);*/
-
- /* Enable burst mode chip Tx DMA */
- register_bank(iobase, 1);
- outb(inb(iobase + IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
- IRCC_CFGB_DMA_BURST, iobase + IRCC_SCE_CFGB);
-
- /* Setup DMA controller (must be done after enabling chip DMA) */
- irda_setup_dma(self->io.dma, self->tx_buff_dma, self->tx_buff.len,
- DMA_TX_MODE);
-
- /* Enable interrupt */
-
- register_bank(iobase, 0);
- outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER);
- outb(IRCC_MASTER_INT_EN, iobase + IRCC_MASTER);
-
- /* Enable transmit */
- outb(IRCC_LCR_B_SCE_TRANSMIT | IRCC_LCR_B_SIP_ENABLE, iobase + IRCC_LCR_B);
-}
-
-/*
- * Function smsc_ircc_dma_xmit_complete (self)
- *
- * The transfer of a frame in finished. This function will only be called
- * by the interrupt handler
- *
- */
-static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self)
-{
- int iobase = self->io.fir_base;
-
- pr_debug("%s\n", __func__);
-#if 0
- /* Disable Tx */
- register_bank(iobase, 0);
- outb(0x00, iobase + IRCC_LCR_B);
-#endif
- register_bank(iobase, 1);
- outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
- iobase + IRCC_SCE_CFGB);
-
- /* Check for underrun! */
- register_bank(iobase, 0);
- if (inb(iobase + IRCC_LSR) & IRCC_LSR_UNDERRUN) {
- self->netdev->stats.tx_errors++;
- self->netdev->stats.tx_fifo_errors++;
-
- /* Reset error condition */
- register_bank(iobase, 0);
- outb(IRCC_MASTER_ERROR_RESET, iobase + IRCC_MASTER);
- outb(0x00, iobase + IRCC_MASTER);
- } else {
- self->netdev->stats.tx_packets++;
- self->netdev->stats.tx_bytes += self->tx_buff.len;
- }
-
- /* Check if it's time to change the speed */
- if (self->new_speed) {
- smsc_ircc_change_speed(self, self->new_speed);
- self->new_speed = 0;
- }
-
- netif_wake_queue(self->netdev);
-}
-
-/*
- * Function smsc_ircc_dma_receive(self)
- *
- * Get ready for receiving a frame. The device will initiate a DMA
- * if it starts to receive a frame.
- *
- */
-static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self)
-{
- int iobase = self->io.fir_base;
-#if 0
- /* Turn off chip DMA */
- register_bank(iobase, 1);
- outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
- iobase + IRCC_SCE_CFGB);
-#endif
-
- /* Disable Tx */
- register_bank(iobase, 0);
- outb(0x00, iobase + IRCC_LCR_B);
-
- /* Turn off chip DMA */
- register_bank(iobase, 1);
- outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
- iobase + IRCC_SCE_CFGB);
-
- self->io.direction = IO_RECV;
- self->rx_buff.data = self->rx_buff.head;
-
- /* Set max Rx frame size */
- register_bank(iobase, 4);
- outb((2050 >> 8) & 0x0f, iobase + IRCC_RX_SIZE_HI);
- outb(2050 & 0xff, iobase + IRCC_RX_SIZE_LO);
-
- /* Setup DMA controller */
- irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize,
- DMA_RX_MODE);
-
- /* Enable burst mode chip Rx DMA */
- register_bank(iobase, 1);
- outb(inb(iobase + IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
- IRCC_CFGB_DMA_BURST, iobase + IRCC_SCE_CFGB);
-
- /* Enable interrupt */
- register_bank(iobase, 0);
- outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER);
- outb(IRCC_MASTER_INT_EN, iobase + IRCC_MASTER);
-
- /* Enable receiver */
- register_bank(iobase, 0);
- outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE,
- iobase + IRCC_LCR_B);
-
- return 0;
-}
-
-/*
- * Function smsc_ircc_dma_receive_complete(self)
- *
- * Finished with receiving frames
- *
- */
-static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self)
-{
- struct sk_buff *skb;
- int len, msgcnt, lsr;
- int iobase = self->io.fir_base;
-
- register_bank(iobase, 0);
-
- pr_debug("%s\n", __func__);
-#if 0
- /* Disable Rx */
- register_bank(iobase, 0);
- outb(0x00, iobase + IRCC_LCR_B);
-#endif
- register_bank(iobase, 0);
- outb(inb(iobase + IRCC_LSAR) & ~IRCC_LSAR_ADDRESS_MASK, iobase + IRCC_LSAR);
- lsr= inb(iobase + IRCC_LSR);
- msgcnt = inb(iobase + IRCC_LCR_B) & 0x08;
-
- pr_debug("%s: dma count = %d\n", __func__,
- get_dma_residue(self->io.dma));
-
- len = self->rx_buff.truesize - get_dma_residue(self->io.dma);
-
- /* Look for errors */
- if (lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) {
- self->netdev->stats.rx_errors++;
- if (lsr & IRCC_LSR_FRAME_ERROR)
- self->netdev->stats.rx_frame_errors++;
- if (lsr & IRCC_LSR_CRC_ERROR)
- self->netdev->stats.rx_crc_errors++;
- if (lsr & IRCC_LSR_SIZE_ERROR)
- self->netdev->stats.rx_length_errors++;
- if (lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN))
- self->netdev->stats.rx_length_errors++;
- return;
- }
-
- /* Remove CRC */
- len -= self->io.speed < 4000000 ? 2 : 4;
-
- if (len < 2 || len > 2050) {
- net_warn_ratelimited("%s(), bogus len=%d\n", __func__, len);
- return;
- }
- pr_debug("%s: msgcnt = %d, len=%d\n", __func__, msgcnt, len);
-
- skb = dev_alloc_skb(len + 1);
- if (!skb)
- return;
-
- /* Make sure IP header gets aligned */
- skb_reserve(skb, 1);
-
- skb_put_data(skb, self->rx_buff.data, len);
- self->netdev->stats.rx_packets++;
- self->netdev->stats.rx_bytes += len;
-
- skb->dev = self->netdev;
- skb_reset_mac_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- netif_rx(skb);
-}
-
-/*
- * Function smsc_ircc_sir_receive (self)
- *
- * Receive one frame from the infrared port
- *
- */
-static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self)
-{
- int boguscount = 0;
- int iobase;
-
- IRDA_ASSERT(self != NULL, return;);
-
- iobase = self->io.sir_base;
-
- /*
- * Receive all characters in Rx FIFO, unwrap and unstuff them.
- * async_unwrap_char will deliver all found frames
- */
- do {
- async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff,
- inb(iobase + UART_RX));
-
- /* Make sure we don't stay here to long */
- if (boguscount++ > 32) {
- pr_debug("%s(), breaking!\n", __func__);
- break;
- }
- } while (inb(iobase + UART_LSR) & UART_LSR_DR);
-}
-
-
-/*
- * Function smsc_ircc_interrupt (irq, dev_id, regs)
- *
- * An interrupt from the chip has arrived. Time to do some work
- *
- */
-static irqreturn_t smsc_ircc_interrupt(int dummy, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct smsc_ircc_cb *self = netdev_priv(dev);
- int iobase, iir, lcra, lsr;
- irqreturn_t ret = IRQ_NONE;
-
- /* Serialise the interrupt handler in various CPUs, stop Tx path */
- spin_lock(&self->lock);
-
- /* Check if we should use the SIR interrupt handler */
- if (self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
- ret = smsc_ircc_interrupt_sir(dev);
- goto irq_ret_unlock;
- }
-
- iobase = self->io.fir_base;
-
- register_bank(iobase, 0);
- iir = inb(iobase + IRCC_IIR);
- if (iir == 0)
- goto irq_ret_unlock;
- ret = IRQ_HANDLED;
-
- /* Disable interrupts */
- outb(0, iobase + IRCC_IER);
- lcra = inb(iobase + IRCC_LCR_A);
- lsr = inb(iobase + IRCC_LSR);
-
- pr_debug("%s(), iir = 0x%02x\n", __func__, iir);
-
- if (iir & IRCC_IIR_EOM) {
- if (self->io.direction == IO_RECV)
- smsc_ircc_dma_receive_complete(self);
- else
- smsc_ircc_dma_xmit_complete(self);
-
- smsc_ircc_dma_receive(self);
- }
-
- if (iir & IRCC_IIR_ACTIVE_FRAME) {
- /*printk(KERN_WARNING "%s(): Active Frame\n", __func__);*/
- }
-
- /* Enable interrupts again */
-
- register_bank(iobase, 0);
- outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER);
-
- irq_ret_unlock:
- spin_unlock(&self->lock);
-
- return ret;
-}
-
-/*
- * Function irport_interrupt_sir (irq, dev_id)
- *
- * Interrupt handler for SIR modes
- */
-static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev)
-{
- struct smsc_ircc_cb *self = netdev_priv(dev);
- int boguscount = 0;
- int iobase;
- int iir, lsr;
-
- /* Already locked coming here in smsc_ircc_interrupt() */
- /*spin_lock(&self->lock);*/
-
- iobase = self->io.sir_base;
-
- iir = inb(iobase + UART_IIR) & UART_IIR_ID;
- if (iir == 0)
- return IRQ_NONE;
- while (iir) {
- /* Clear interrupt */
- lsr = inb(iobase + UART_LSR);
-
- pr_debug("%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
- __func__, iir, lsr, iobase);
-
- switch (iir) {
- case UART_IIR_RLSI:
- pr_debug("%s(), RLSI\n", __func__);
- break;
- case UART_IIR_RDI:
- /* Receive interrupt */
- smsc_ircc_sir_receive(self);
- break;
- case UART_IIR_THRI:
- if (lsr & UART_LSR_THRE)
- /* Transmitter ready for data */
- smsc_ircc_sir_write_wakeup(self);
- break;
- default:
- pr_debug("%s(), unhandled IIR=%#x\n",
- __func__, iir);
- break;
- }
-
- /* Make sure we don't stay here to long */
- if (boguscount++ > 100)
- break;
-
- iir = inb(iobase + UART_IIR) & UART_IIR_ID;
- }
- /*spin_unlock(&self->lock);*/
- return IRQ_HANDLED;
-}
-
-
-#if 0 /* unused */
-/*
- * Function ircc_is_receiving (self)
- *
- * Return TRUE is we are currently receiving a frame
- *
- */
-static int ircc_is_receiving(struct smsc_ircc_cb *self)
-{
- int status = FALSE;
- /* int iobase; */
-
- pr_debug("%s\n", __func__);
-
- IRDA_ASSERT(self != NULL, return FALSE;);
-
- pr_debug("%s: dma count = %d\n", __func__,
- get_dma_residue(self->io.dma));
-
- status = (self->rx_buff.state != OUTSIDE_FRAME);
-
- return status;
-}
-#endif /* unused */
-
-static int smsc_ircc_request_irq(struct smsc_ircc_cb *self)
-{
- int error;
-
- error = request_irq(self->io.irq, smsc_ircc_interrupt, 0,
- self->netdev->name, self->netdev);
- if (error)
- pr_debug("%s(), unable to allocate irq=%d, err=%d\n",
- __func__, self->io.irq, error);
-
- return error;
-}
-
-static void smsc_ircc_start_interrupts(struct smsc_ircc_cb *self)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&self->lock, flags);
-
- self->io.speed = 0;
- smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
-
- spin_unlock_irqrestore(&self->lock, flags);
-}
-
-static void smsc_ircc_stop_interrupts(struct smsc_ircc_cb *self)
-{
- int iobase = self->io.fir_base;
- unsigned long flags;
-
- spin_lock_irqsave(&self->lock, flags);
-
- register_bank(iobase, 0);
- outb(0, iobase + IRCC_IER);
- outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER);
- outb(0x00, iobase + IRCC_MASTER);
-
- spin_unlock_irqrestore(&self->lock, flags);
-}
-
-
-/*
- * Function smsc_ircc_net_open (dev)
- *
- * Start the device
- *
- */
-static int smsc_ircc_net_open(struct net_device *dev)
-{
- struct smsc_ircc_cb *self;
- char hwname[16];
-
- pr_debug("%s\n", __func__);
-
- IRDA_ASSERT(dev != NULL, return -1;);
- self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
-
- if (self->io.suspended) {
- pr_debug("%s(), device is suspended\n", __func__);
- return -EAGAIN;
- }
-
- if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name,
- (void *) dev)) {
- pr_debug("%s(), unable to allocate irq=%d\n",
- __func__, self->io.irq);
- return -EAGAIN;
- }
-
- smsc_ircc_start_interrupts(self);
-
- /* Give self a hardware name */
- /* It would be cool to offer the chip revision here - Jean II */
- sprintf(hwname, "SMSC @ 0x%03x", self->io.fir_base);
-
- /*
- * Open new IrLAP layer instance, now that everything should be
- * initialized properly
- */
- self->irlap = irlap_open(dev, &self->qos, hwname);
-
- /*
- * Always allocate the DMA channel after the IRQ,
- * and clean up on failure.
- */
- if (request_dma(self->io.dma, dev->name)) {
- smsc_ircc_net_close(dev);
-
- net_warn_ratelimited("%s(), unable to allocate DMA=%d\n",
- __func__, self->io.dma);
- return -EAGAIN;
- }
-
- netif_start_queue(dev);
-
- return 0;
-}
-
-/*
- * Function smsc_ircc_net_close (dev)
- *
- * Stop the device
- *
- */
-static int smsc_ircc_net_close(struct net_device *dev)
-{
- struct smsc_ircc_cb *self;
-
- pr_debug("%s\n", __func__);
-
- IRDA_ASSERT(dev != NULL, return -1;);
- self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
-
- /* Stop device */
- netif_stop_queue(dev);
-
- /* Stop and remove instance of IrLAP */
- if (self->irlap)
- irlap_close(self->irlap);
- self->irlap = NULL;
-
- smsc_ircc_stop_interrupts(self);
-
- /* if we are called from smsc_ircc_resume we don't have IRQ reserved */
- if (!self->io.suspended)
- free_irq(self->io.irq, dev);
-
- disable_dma(self->io.dma);
- free_dma(self->io.dma);
-
- return 0;
-}
-
-static int smsc_ircc_suspend(struct platform_device *dev, pm_message_t state)
-{
- struct smsc_ircc_cb *self = platform_get_drvdata(dev);
-
- if (!self->io.suspended) {
- pr_debug("%s, Suspending\n", driver_name);
-
- rtnl_lock();
- if (netif_running(self->netdev)) {
- netif_device_detach(self->netdev);
- smsc_ircc_stop_interrupts(self);
- free_irq(self->io.irq, self->netdev);
- disable_dma(self->io.dma);
- }
- self->io.suspended = 1;
- rtnl_unlock();
- }
-
- return 0;
-}
-
-static int smsc_ircc_resume(struct platform_device *dev)
-{
- struct smsc_ircc_cb *self = platform_get_drvdata(dev);
-
- if (self->io.suspended) {
- pr_debug("%s, Waking up\n", driver_name);
-
- rtnl_lock();
- smsc_ircc_init_chip(self);
- if (netif_running(self->netdev)) {
- if (smsc_ircc_request_irq(self)) {
- /*
- * Don't fail resume process, just kill this
- * network interface
- */
- unregister_netdevice(self->netdev);
- } else {
- enable_dma(self->io.dma);
- smsc_ircc_start_interrupts(self);
- netif_device_attach(self->netdev);
- }
- }
- self->io.suspended = 0;
- rtnl_unlock();
- }
- return 0;
-}
-
-/*
- * Function smsc_ircc_close (self)
- *
- * Close driver instance
- *
- */
-static int __exit smsc_ircc_close(struct smsc_ircc_cb *self)
-{
- pr_debug("%s\n", __func__);
-
- IRDA_ASSERT(self != NULL, return -1;);
-
- platform_device_unregister(self->pldev);
-
- /* Remove netdevice */
- unregister_netdev(self->netdev);
-
- smsc_ircc_stop_interrupts(self);
-
- /* Release the PORTS that this driver is using */
- pr_debug("%s(), releasing 0x%03x\n", __func__,
- self->io.fir_base);
-
- release_region(self->io.fir_base, self->io.fir_ext);
-
- pr_debug("%s(), releasing 0x%03x\n", __func__,
- self->io.sir_base);
-
- release_region(self->io.sir_base, self->io.sir_ext);
-
- if (self->tx_buff.head)
- dma_free_coherent(NULL, self->tx_buff.truesize,
- self->tx_buff.head, self->tx_buff_dma);
-
- if (self->rx_buff.head)
- dma_free_coherent(NULL, self->rx_buff.truesize,
- self->rx_buff.head, self->rx_buff_dma);
-
- free_netdev(self->netdev);
-
- return 0;
-}
-
-static void __exit smsc_ircc_cleanup(void)
-{
- int i;
-
- pr_debug("%s\n", __func__);
-
- for (i = 0; i < 2; i++) {
- if (dev_self[i])
- smsc_ircc_close(dev_self[i]);
- }
-
- if (pnp_driver_registered)
- pnp_unregister_driver(&smsc_ircc_pnp_driver);
-
- platform_driver_unregister(&smsc_ircc_driver);
-}
-
-/*
- * Start SIR operations
- *
- * This function *must* be called with spinlock held, because it may
- * be called from the irq handler (via smsc_ircc_change_speed()). - Jean II
- */
-static void smsc_ircc_sir_start(struct smsc_ircc_cb *self)
-{
- struct net_device *dev;
- int fir_base, sir_base;
-
- pr_debug("%s\n", __func__);
-
- IRDA_ASSERT(self != NULL, return;);
- dev = self->netdev;
- IRDA_ASSERT(dev != NULL, return;);
-
- fir_base = self->io.fir_base;
- sir_base = self->io.sir_base;
-
- /* Reset everything */
- outb(IRCC_MASTER_RESET, fir_base + IRCC_MASTER);
-
- #if SMSC_IRCC2_C_SIR_STOP
- /*smsc_ircc_sir_stop(self);*/
- #endif
-
- register_bank(fir_base, 1);
- outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | IRCC_CFGA_IRDA_SIR_A), fir_base + IRCC_SCE_CFGA);
-
- /* Initialize UART */
- outb(UART_LCR_WLEN8, sir_base + UART_LCR); /* Reset DLAB */
- outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), sir_base + UART_MCR);
-
- /* Turn on interrups */
- outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base + UART_IER);
-
- pr_debug("%s() - exit\n", __func__);
-
- outb(0x00, fir_base + IRCC_MASTER);
-}
-
-#if SMSC_IRCC2_C_SIR_STOP
-void smsc_ircc_sir_stop(struct smsc_ircc_cb *self)
-{
- int iobase;
-
- pr_debug("%s\n", __func__);
- iobase = self->io.sir_base;
-
- /* Reset UART */
- outb(0, iobase + UART_MCR);
-
- /* Turn off interrupts */
- outb(0, iobase + UART_IER);
-}
-#endif
-
-/*
- * Function smsc_sir_write_wakeup (self)
- *
- * Called by the SIR interrupt handler when there's room for more data.
- * If we have more packets to send, we send them here.
- *
- */
-static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self)
-{
- int actual = 0;
- int iobase;
- int fcr;
-
- IRDA_ASSERT(self != NULL, return;);
-
- pr_debug("%s\n", __func__);
-
- iobase = self->io.sir_base;
-
- /* Finished with frame? */
- if (self->tx_buff.len > 0) {
- /* Write data left in transmit buffer */
- actual = smsc_ircc_sir_write(iobase, self->io.fifo_size,
- self->tx_buff.data, self->tx_buff.len);
- self->tx_buff.data += actual;
- self->tx_buff.len -= actual;
- } else {
-
- /*if (self->tx_buff.len ==0) {*/
-
- /*
- * Now serial buffer is almost free & we can start
- * transmission of another packet. But first we must check
- * if we need to change the speed of the hardware
- */
- if (self->new_speed) {
- pr_debug("%s(), Changing speed to %d.\n",
- __func__, self->new_speed);
- smsc_ircc_sir_wait_hw_transmitter_finish(self);
- smsc_ircc_change_speed(self, self->new_speed);
- self->new_speed = 0;
- } else {
- /* Tell network layer that we want more frames */
- netif_wake_queue(self->netdev);
- }
- self->netdev->stats.tx_packets++;
-
- if (self->io.speed <= 115200) {
- /*
- * Reset Rx FIFO to make sure that all reflected transmit data
- * is discarded. This is needed for half duplex operation
- */
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;
- fcr |= self->io.speed < 38400 ?
- UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14;
-
- outb(fcr, iobase + UART_FCR);
-
- /* Turn on receive interrupts */
- outb(UART_IER_RDI, iobase + UART_IER);
- }
- }
-}
-
-/*
- * Function smsc_ircc_sir_write (iobase, fifo_size, buf, len)
- *
- * Fill Tx FIFO with transmit data
- *
- */
-static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len)
-{
- int actual = 0;
-
- /* Tx FIFO should be empty! */
- if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) {
- net_warn_ratelimited("%s(), failed, fifo not empty!\n",
- __func__);
- return 0;
- }
-
- /* Fill FIFO with current frame */
- while (fifo_size-- > 0 && actual < len) {
- /* Transmit next byte */
- outb(buf[actual], iobase + UART_TX);
- actual++;
- }
- return actual;
-}
-
-/*
- * Function smsc_ircc_is_receiving (self)
- *
- * Returns true is we are currently receiving data
- *
- */
-static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self)
-{
- return self->rx_buff.state != OUTSIDE_FRAME;
-}
-
-
-/*
- * Function smsc_ircc_probe_transceiver(self)
- *
- * Tries to find the used Transceiver
- *
- */
-static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self)
-{
- unsigned int i;
-
- IRDA_ASSERT(self != NULL, return;);
-
- for (i = 0; smsc_transceivers[i].name != NULL; i++)
- if (smsc_transceivers[i].probe(self->io.fir_base)) {
- net_info_ratelimited(" %s transceiver found\n",
- smsc_transceivers[i].name);
- self->transceiver= i + 1;
- return;
- }
-
- net_info_ratelimited("No transceiver found. Defaulting to %s\n",
- smsc_transceivers[SMSC_IRCC2_C_DEFAULT_TRANSCEIVER].name);
-
- self->transceiver = SMSC_IRCC2_C_DEFAULT_TRANSCEIVER;
-}
-
-
-/*
- * Function smsc_ircc_set_transceiver_for_speed(self, speed)
- *
- * Set the transceiver according to the speed
- *
- */
-static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed)
-{
- unsigned int trx;
-
- trx = self->transceiver;
- if (trx > 0)
- smsc_transceivers[trx - 1].set_for_speed(self->io.fir_base, speed);
-}
-
-/*
- * Function smsc_ircc_wait_hw_transmitter_finish ()
- *
- * Wait for the real end of HW transmission
- *
- * The UART is a strict FIFO, and we get called only when we have finished
- * pushing data to the FIFO, so the maximum amount of time we must wait
- * is only for the FIFO to drain out.
- *
- * We use a simple calibrated loop. We may need to adjust the loop
- * delay (udelay) to balance I/O traffic and latency. And we also need to
- * adjust the maximum timeout.
- * It would probably be better to wait for the proper interrupt,
- * but it doesn't seem to be available.
- *
- * We can't use jiffies or kernel timers because :
- * 1) We are called from the interrupt handler, which disable softirqs,
- * so jiffies won't be increased
- * 2) Jiffies granularity is usually very coarse (10ms), and we don't
- * want to wait that long to detect stuck hardware.
- * Jean II
- */
-
-static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self)
-{
- int iobase = self->io.sir_base;
- int count = SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US;
-
- /* Calibrated busy loop */
- while (count-- > 0 && !(inb(iobase + UART_LSR) & UART_LSR_TEMT))
- udelay(1);
-
- if (count < 0)
- pr_debug("%s(): stuck transmitter\n", __func__);
-}
-
-
-/* PROBING
- *
- * REVISIT we can be told about the device by PNP, and should use that info
- * instead of probing hardware and creating a platform_device ...
- */
-
-static int __init smsc_ircc_look_for_chips(void)
-{
- struct smsc_chip_address *address;
- char *type;
- unsigned int cfg_base, found;
-
- found = 0;
- address = possible_addresses;
-
- while (address->cfg_base) {
- cfg_base = address->cfg_base;
-
- /*printk(KERN_WARNING "%s(): probing: 0x%02x for: 0x%02x\n", __func__, cfg_base, address->type);*/
-
- if (address->type & SMSCSIO_TYPE_FDC) {
- type = "FDC";
- if (address->type & SMSCSIO_TYPE_FLAT)
- if (!smsc_superio_flat(fdc_chips_flat, cfg_base, type))
- found++;
-
- if (address->type & SMSCSIO_TYPE_PAGED)
- if (!smsc_superio_paged(fdc_chips_paged, cfg_base, type))
- found++;
- }
- if (address->type & SMSCSIO_TYPE_LPC) {
- type = "LPC";
- if (address->type & SMSCSIO_TYPE_FLAT)
- if (!smsc_superio_flat(lpc_chips_flat, cfg_base, type))
- found++;
-
- if (address->type & SMSCSIO_TYPE_PAGED)
- if (!smsc_superio_paged(lpc_chips_paged, cfg_base, type))
- found++;
- }
- address++;
- }
- return found;
-}
-
-/*
- * Function smsc_superio_flat (chip, base, type)
- *
- * Try to get configuration of a smc SuperIO chip with flat register model
- *
- */
-static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfgbase, char *type)
-{
- unsigned short firbase, sirbase;
- u8 mode, dma, irq;
- int ret = -ENODEV;
-
- pr_debug("%s\n", __func__);
-
- if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type) == NULL)
- return ret;
-
- outb(SMSCSIOFLAT_UARTMODE0C_REG, cfgbase);
- mode = inb(cfgbase + 1);
-
- /*printk(KERN_WARNING "%s(): mode: 0x%02x\n", __func__, mode);*/
-
- if (!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA))
- net_warn_ratelimited("%s(): IrDA not enabled\n", __func__);
-
- outb(SMSCSIOFLAT_UART2BASEADDR_REG, cfgbase);
- sirbase = inb(cfgbase + 1) << 2;
-
- /* FIR iobase */
- outb(SMSCSIOFLAT_FIRBASEADDR_REG, cfgbase);
- firbase = inb(cfgbase + 1) << 3;
-
- /* DMA */
- outb(SMSCSIOFLAT_FIRDMASELECT_REG, cfgbase);
- dma = inb(cfgbase + 1) & SMSCSIOFLAT_FIRDMASELECT_MASK;
-
- /* IRQ */
- outb(SMSCSIOFLAT_UARTIRQSELECT_REG, cfgbase);
- irq = inb(cfgbase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
-
- net_info_ratelimited("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n",
- __func__, firbase, sirbase, dma, irq, mode);
-
- if (firbase && smsc_ircc_open(firbase, sirbase, dma, irq) == 0)
- ret = 0;
-
- /* Exit configuration */
- outb(SMSCSIO_CFGEXITKEY, cfgbase);
-
- return ret;
-}
-
-/*
- * Function smsc_superio_paged (chip, base, type)
- *
- * Try to get configuration of a smc SuperIO chip with paged register model
- *
- */
-static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type)
-{
- unsigned short fir_io, sir_io;
- int ret = -ENODEV;
-
- pr_debug("%s\n", __func__);
-
- if (smsc_ircc_probe(cfg_base, 0x20, chips, type) == NULL)
- return ret;
-
- /* Select logical device (UART2) */
- outb(0x07, cfg_base);
- outb(0x05, cfg_base + 1);
-
- /* SIR iobase */
- outb(0x60, cfg_base);
- sir_io = inb(cfg_base + 1) << 8;
- outb(0x61, cfg_base);
- sir_io |= inb(cfg_base + 1);
-
- /* Read FIR base */
- outb(0x62, cfg_base);
- fir_io = inb(cfg_base + 1) << 8;
- outb(0x63, cfg_base);
- fir_io |= inb(cfg_base + 1);
- outb(0x2b, cfg_base); /* ??? */
-
- if (fir_io && smsc_ircc_open(fir_io, sir_io, ircc_dma, ircc_irq) == 0)
- ret = 0;
-
- /* Exit configuration */
- outb(SMSCSIO_CFGEXITKEY, cfg_base);
-
- return ret;
-}
-
-
-static int __init smsc_access(unsigned short cfg_base, unsigned char reg)
-{
- pr_debug("%s\n", __func__);
-
- outb(reg, cfg_base);
- return inb(cfg_base) != reg ? -1 : 0;
-}
-
-static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type)
-{
- u8 devid, xdevid, rev;
-
- pr_debug("%s\n", __func__);
-
- /* Leave configuration */
-
- outb(SMSCSIO_CFGEXITKEY, cfg_base);
-
- if (inb(cfg_base) == SMSCSIO_CFGEXITKEY) /* not a smc superio chip */
- return NULL;
-
- outb(reg, cfg_base);
-
- xdevid = inb(cfg_base + 1);
-
- /* Enter configuration */
-
- outb(SMSCSIO_CFGACCESSKEY, cfg_base);
-
- #if 0
- if (smsc_access(cfg_base,0x55)) /* send second key and check */
- return NULL;
- #endif
-
- /* probe device ID */
-
- if (smsc_access(cfg_base, reg))
- return NULL;
-
- devid = inb(cfg_base + 1);
-
- if (devid == 0 || devid == 0xff) /* typical values for unused port */
- return NULL;
-
- /* probe revision ID */
-
- if (smsc_access(cfg_base, reg + 1))
- return NULL;
-
- rev = inb(cfg_base + 1);
-
- if (rev >= 128) /* i think this will make no sense */
- return NULL;
-
- if (devid == xdevid) /* protection against false positives */
- return NULL;
-
- /* Check for expected device ID; are there others? */
-
- while (chip->devid != devid) {
-
- chip++;
-
- if (chip->name == NULL)
- return NULL;
- }
-
- net_info_ratelimited("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",
- devid, rev, cfg_base, type, chip->name);
-
- if (chip->rev > rev) {
- net_info_ratelimited("Revision higher than expected\n");
- return NULL;
- }
-
- if (chip->flags & NoIRDA)
- net_info_ratelimited("chipset does not support IRDA\n");
-
- return chip;
-}
-
-static int __init smsc_superio_fdc(unsigned short cfg_base)
-{
- int ret = -1;
-
- if (!request_region(cfg_base, 2, driver_name)) {
- net_warn_ratelimited("%s: can't get cfg_base of 0x%03x\n",
- __func__, cfg_base);
- } else {
- if (!smsc_superio_flat(fdc_chips_flat, cfg_base, "FDC") ||
- !smsc_superio_paged(fdc_chips_paged, cfg_base, "FDC"))
- ret = 0;
-
- release_region(cfg_base, 2);
- }
-
- return ret;
-}
-
-static int __init smsc_superio_lpc(unsigned short cfg_base)
-{
- int ret = -1;
-
- if (!request_region(cfg_base, 2, driver_name)) {
- net_warn_ratelimited("%s: can't get cfg_base of 0x%03x\n",
- __func__, cfg_base);
- } else {
- if (!smsc_superio_flat(lpc_chips_flat, cfg_base, "LPC") ||
- !smsc_superio_paged(lpc_chips_paged, cfg_base, "LPC"))
- ret = 0;
-
- release_region(cfg_base, 2);
- }
- return ret;
-}
-
-/*
- * Look for some specific subsystem setups that need
- * pre-configuration not properly done by the BIOS (especially laptops)
- * This code is based in part on smcinit.c, tosh1800-smcinit.c
- * and tosh2450-smcinit.c. The table lists the device entries
- * for ISA bridges with an LPC (Low Pin Count) controller which
- * handles the communication with the SMSC device. After the LPC
- * controller is initialized through PCI, the SMSC device is initialized
- * through a dedicated port in the ISA port-mapped I/O area, this latter
- * area is used to configure the SMSC device with default
- * SIR and FIR I/O ports, DMA and IRQ. Different vendors have
- * used different sets of parameters and different control port
- * addresses making a subsystem device table necessary.
- */
-#ifdef CONFIG_PCI
-static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = {
- /*
- * Subsystems needing entries:
- * 0x10b9:0x1533 0x103c:0x0850 HP nx9010 family
- * 0x10b9:0x1533 0x0e11:0x005a Compaq nc4000 family
- * 0x8086:0x24cc 0x0e11:0x002a HP nx9000 family
- */
- {
- /* Guessed entry */
- .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */
- .device = 0x24cc,
- .subvendor = 0x103c,
- .subdevice = 0x08bc,
- .sir_io = 0x02f8,
- .fir_io = 0x0130,
- .fir_irq = 0x05,
- .fir_dma = 0x03,
- .cfg_base = 0x004e,
- .preconfigure = preconfigure_through_82801,
- .name = "HP nx5000 family",
- },
- {
- .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */
- .device = 0x24cc,
- .subvendor = 0x103c,
- .subdevice = 0x088c,
- /* Quite certain these are the same for nc8000 as for nc6000 */
- .sir_io = 0x02f8,
- .fir_io = 0x0130,
- .fir_irq = 0x05,
- .fir_dma = 0x03,
- .cfg_base = 0x004e,
- .preconfigure = preconfigure_through_82801,
- .name = "HP nc8000 family",
- },
- {
- .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */
- .device = 0x24cc,
- .subvendor = 0x103c,
- .subdevice = 0x0890,
- .sir_io = 0x02f8,
- .fir_io = 0x0130,
- .fir_irq = 0x05,
- .fir_dma = 0x03,
- .cfg_base = 0x004e,
- .preconfigure = preconfigure_through_82801,
- .name = "HP nc6000 family",
- },
- {
- .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */
- .device = 0x24cc,
- .subvendor = 0x0e11,
- .subdevice = 0x0860,
- /* I assume these are the same for x1000 as for the others */
- .sir_io = 0x02e8,
- .fir_io = 0x02f8,
- .fir_irq = 0x07,
- .fir_dma = 0x03,
- .cfg_base = 0x002e,
- .preconfigure = preconfigure_through_82801,
- .name = "Compaq x1000 family",
- },
- {
- /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = 0x24c0,
- .subvendor = 0x1179,
- .subdevice = 0xffff, /* 0xffff is "any" */
- .sir_io = 0x03f8,
- .fir_io = 0x0130,
- .fir_irq = 0x07,
- .fir_dma = 0x01,
- .cfg_base = 0x002e,
- .preconfigure = preconfigure_through_82801,
- .name = "Toshiba laptop with Intel 82801DB/DBL LPC bridge",
- },
- {
- .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801CAM ISA bridge */
- .device = 0x248c,
- .subvendor = 0x1179,
- .subdevice = 0xffff, /* 0xffff is "any" */
- .sir_io = 0x03f8,
- .fir_io = 0x0130,
- .fir_irq = 0x03,
- .fir_dma = 0x03,
- .cfg_base = 0x002e,
- .preconfigure = preconfigure_through_82801,
- .name = "Toshiba laptop with Intel 82801CAM ISA bridge",
- },
- {
- /* 82801DBM (ICH4-M) LPC Interface Bridge */
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = 0x24cc,
- .subvendor = 0x1179,
- .subdevice = 0xffff, /* 0xffff is "any" */
- .sir_io = 0x03f8,
- .fir_io = 0x0130,
- .fir_irq = 0x03,
- .fir_dma = 0x03,
- .cfg_base = 0x002e,
- .preconfigure = preconfigure_through_82801,
- .name = "Toshiba laptop with Intel 8281DBM LPC bridge",
- },
- {
- /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */
- .vendor = PCI_VENDOR_ID_AL,
- .device = 0x1533,
- .subvendor = 0x1179,
- .subdevice = 0xffff, /* 0xffff is "any" */
- .sir_io = 0x02e8,
- .fir_io = 0x02f8,
- .fir_irq = 0x07,
- .fir_dma = 0x03,
- .cfg_base = 0x002e,
- .preconfigure = preconfigure_through_ali,
- .name = "Toshiba laptop with ALi ISA bridge",
- },
- { } // Terminator
-};
-
-
-/*
- * This sets up the basic SMSC parameters
- * (FIR port, SIR port, FIR DMA, FIR IRQ)
- * through the chip configuration port.
- */
-static int __init preconfigure_smsc_chip(struct
- smsc_ircc_subsystem_configuration
- *conf)
-{
- unsigned short iobase = conf->cfg_base;
- unsigned char tmpbyte;
-
- outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state
- outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID
- tmpbyte = inb(iobase +1); // Read device ID
- pr_debug("Detected Chip id: 0x%02x, setting up registers...\n",
- tmpbyte);
-
- /* Disable UART1 and set up SIR I/O port */
- outb(0x24, iobase); // select CR24 - UART1 base addr
- outb(0x00, iobase + 1); // disable UART1
- outb(SMSCSIOFLAT_UART2BASEADDR_REG, iobase); // select CR25 - UART2 base addr
- outb( (conf->sir_io >> 2), iobase + 1); // bits 2-9 of 0x3f8
- tmpbyte = inb(iobase + 1);
- if (tmpbyte != (conf->sir_io >> 2) ) {
- net_warn_ratelimited("ERROR: could not configure SIR ioport\n");
- net_warn_ratelimited("Try to supply ircc_cfg argument\n");
- return -ENXIO;
- }
-
- /* Set up FIR IRQ channel for UART2 */
- outb(SMSCSIOFLAT_UARTIRQSELECT_REG, iobase); // select CR28 - UART1,2 IRQ select
- tmpbyte = inb(iobase + 1);
- tmpbyte &= SMSCSIOFLAT_UART1IRQSELECT_MASK; // Do not touch the UART1 portion
- tmpbyte |= (conf->fir_irq & SMSCSIOFLAT_UART2IRQSELECT_MASK);
- outb(tmpbyte, iobase + 1);
- tmpbyte = inb(iobase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
- if (tmpbyte != conf->fir_irq) {
- net_warn_ratelimited("ERROR: could not configure FIR IRQ channel\n");
- return -ENXIO;
- }
-
- /* Set up FIR I/O port */
- outb(SMSCSIOFLAT_FIRBASEADDR_REG, iobase); // CR2B - SCE (FIR) base addr
- outb((conf->fir_io >> 3), iobase + 1);
- tmpbyte = inb(iobase + 1);
- if (tmpbyte != (conf->fir_io >> 3) ) {
- net_warn_ratelimited("ERROR: could not configure FIR I/O port\n");
- return -ENXIO;
- }
-
- /* Set up FIR DMA channel */
- outb(SMSCSIOFLAT_FIRDMASELECT_REG, iobase); // CR2C - SCE (FIR) DMA select
- outb((conf->fir_dma & LPC47N227_FIRDMASELECT_MASK), iobase + 1); // DMA
- tmpbyte = inb(iobase + 1) & LPC47N227_FIRDMASELECT_MASK;
- if (tmpbyte != (conf->fir_dma & LPC47N227_FIRDMASELECT_MASK)) {
- net_warn_ratelimited("ERROR: could not configure FIR DMA channel\n");
- return -ENXIO;
- }
-
- outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode
- tmpbyte = inb(iobase + 1);
- tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK |
- SMSCSIOFLAT_UART2MODE_VAL_IRDA;
- outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed
-
- outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel
- tmpbyte = inb(iobase + 1);
- outb(tmpbyte | LPC47N227_UART2AUTOPWRDOWN_MASK, iobase + 1); // enable UART2 autopower down
-
- /* This one was not part of tosh1800 */
- outb(0x0a, iobase); // CR0a - ecp fifo / ir mux
- tmpbyte = inb(iobase + 1);
- outb(tmpbyte | 0x40, iobase + 1); // send active device to ir port
-
- outb(LPC47N227_UART12POWER_REG, iobase); // CR02 - UART 1,2 power
- tmpbyte = inb(iobase + 1);
- outb(tmpbyte | LPC47N227_UART2POWERDOWN_MASK, iobase + 1); // UART2 power up mode, UART1 power down
-
- outb(LPC47N227_FDCPOWERVALIDCONF_REG, iobase); // CR00 - FDC Power/valid config cycle
- tmpbyte = inb(iobase + 1);
- outb(tmpbyte | LPC47N227_VALID_MASK, iobase + 1); // valid config cycle done
-
- outb(LPC47N227_CFGEXITKEY, iobase); // Exit configuration
-
- return 0;
-}
-
-/* 82801CAM generic registers */
-#define VID 0x00
-#define DID 0x02
-#define PIRQ_A_D_ROUT 0x60
-#define SIRQ_CNTL 0x64
-#define PIRQ_E_H_ROUT 0x68
-#define PCI_DMA_C 0x90
-/* LPC-specific registers */
-#define COM_DEC 0xe0
-#define GEN1_DEC 0xe4
-#define LPC_EN 0xe6
-#define GEN2_DEC 0xec
-/*
- * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge
- * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge.
- * They all work the same way!
- */
-static int __init preconfigure_through_82801(struct pci_dev *dev,
- struct
- smsc_ircc_subsystem_configuration
- *conf)
-{
- unsigned short tmpword;
- unsigned char tmpbyte;
-
- net_info_ratelimited("Setting up Intel 82801 controller and SMSC device\n");
- /*
- * Select the range for the COMA COM port (SIR)
- * Register COM_DEC:
- * Bit 7: reserved
- * Bit 6-4, COMB decode range
- * Bit 3: reserved
- * Bit 2-0, COMA decode range
- *
- * Decode ranges:
- * 000 = 0x3f8-0x3ff (COM1)
- * 001 = 0x2f8-0x2ff (COM2)
- * 010 = 0x220-0x227
- * 011 = 0x228-0x22f
- * 100 = 0x238-0x23f
- * 101 = 0x2e8-0x2ef (COM4)
- * 110 = 0x338-0x33f
- * 111 = 0x3e8-0x3ef (COM3)
- */
- pci_read_config_byte(dev, COM_DEC, &tmpbyte);
- tmpbyte &= 0xf8; /* mask COMA bits */
- switch(conf->sir_io) {
- case 0x3f8:
- tmpbyte |= 0x00;
- break;
- case 0x2f8:
- tmpbyte |= 0x01;
- break;
- case 0x220:
- tmpbyte |= 0x02;
- break;
- case 0x228:
- tmpbyte |= 0x03;
- break;
- case 0x238:
- tmpbyte |= 0x04;
- break;
- case 0x2e8:
- tmpbyte |= 0x05;
- break;
- case 0x338:
- tmpbyte |= 0x06;
- break;
- case 0x3e8:
- tmpbyte |= 0x07;
- break;
- default:
- tmpbyte |= 0x01; /* COM2 default */
- }
- pr_debug("COM_DEC (write): 0x%02x\n", tmpbyte);
- pci_write_config_byte(dev, COM_DEC, tmpbyte);
-
- /* Enable Low Pin Count interface */
- pci_read_config_word(dev, LPC_EN, &tmpword);
- /* These seem to be set up at all times,
- * just make sure it is properly set.
- */
- switch(conf->cfg_base) {
- case 0x04e:
- tmpword |= 0x2000;
- break;
- case 0x02e:
- tmpword |= 0x1000;
- break;
- case 0x062:
- tmpword |= 0x0800;
- break;
- case 0x060:
- tmpword |= 0x0400;
- break;
- default:
- net_warn_ratelimited("Uncommon I/O base address: 0x%04x\n",
- conf->cfg_base);
- break;
- }
- tmpword &= 0xfffd; /* disable LPC COMB */
- tmpword |= 0x0001; /* set bit 0 : enable LPC COMA addr range (GEN2) */
- pr_debug("LPC_EN (write): 0x%04x\n", tmpword);
- pci_write_config_word(dev, LPC_EN, tmpword);
-
- /*
- * Configure LPC DMA channel
- * PCI_DMA_C bits:
- * Bit 15-14: DMA channel 7 select
- * Bit 13-12: DMA channel 6 select
- * Bit 11-10: DMA channel 5 select
- * Bit 9-8: Reserved
- * Bit 7-6: DMA channel 3 select
- * Bit 5-4: DMA channel 2 select
- * Bit 3-2: DMA channel 1 select
- * Bit 1-0: DMA channel 0 select
- * 00 = Reserved value
- * 01 = PC/PCI DMA
- * 10 = Reserved value
- * 11 = LPC I/F DMA
- */
- pci_read_config_word(dev, PCI_DMA_C, &tmpword);
- switch(conf->fir_dma) {
- case 0x07:
- tmpword |= 0xc000;
- break;
- case 0x06:
- tmpword |= 0x3000;
- break;
- case 0x05:
- tmpword |= 0x0c00;
- break;
- case 0x03:
- tmpword |= 0x00c0;
- break;
- case 0x02:
- tmpword |= 0x0030;
- break;
- case 0x01:
- tmpword |= 0x000c;
- break;
- case 0x00:
- tmpword |= 0x0003;
- break;
- default:
- break; /* do not change settings */
- }
- pr_debug("PCI_DMA_C (write): 0x%04x\n", tmpword);
- pci_write_config_word(dev, PCI_DMA_C, tmpword);
-
- /*
- * GEN2_DEC bits:
- * Bit 15-4: Generic I/O range
- * Bit 3-1: reserved (read as 0)
- * Bit 0: enable GEN2 range on LPC I/F
- */
- tmpword = conf->fir_io & 0xfff8;
- tmpword |= 0x0001;
- pr_debug("GEN2_DEC (write): 0x%04x\n", tmpword);
- pci_write_config_word(dev, GEN2_DEC, tmpword);
-
- /* Pre-configure chip */
- return preconfigure_smsc_chip(conf);
-}
-
-/*
- * Pre-configure a certain port on the ALi 1533 bridge.
- * This is based on reverse-engineering since ALi does not
- * provide any data sheet for the 1533 chip.
- */
-static void __init preconfigure_ali_port(struct pci_dev *dev,
- unsigned short port)
-{
- unsigned char reg;
- /* These bits obviously control the different ports */
- unsigned char mask;
- unsigned char tmpbyte;
-
- switch(port) {
- case 0x0130:
- case 0x0178:
- reg = 0xb0;
- mask = 0x80;
- break;
- case 0x03f8:
- reg = 0xb4;
- mask = 0x80;
- break;
- case 0x02f8:
- reg = 0xb4;
- mask = 0x30;
- break;
- case 0x02e8:
- reg = 0xb4;
- mask = 0x08;
- break;
- default:
- net_err_ratelimited("Failed to configure unsupported port on ALi 1533 bridge: 0x%04x\n",
- port);
- return;
- }
-
- pci_read_config_byte(dev, reg, &tmpbyte);
- /* Turn on the right bits */
- tmpbyte |= mask;
- pci_write_config_byte(dev, reg, tmpbyte);
- net_info_ratelimited("Activated ALi 1533 ISA bridge port 0x%04x\n",
- port);
-}
-
-static int __init preconfigure_through_ali(struct pci_dev *dev,
- struct
- smsc_ircc_subsystem_configuration
- *conf)
-{
- /* Configure the two ports on the ALi 1533 */
- preconfigure_ali_port(dev, conf->sir_io);
- preconfigure_ali_port(dev, conf->fir_io);
-
- /* Pre-configure chip */
- return preconfigure_smsc_chip(conf);
-}
-
-static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
- unsigned short ircc_fir,
- unsigned short ircc_sir,
- unsigned char ircc_dma,
- unsigned char ircc_irq)
-{
- struct pci_dev *dev = NULL;
- unsigned short ss_vendor = 0x0000;
- unsigned short ss_device = 0x0000;
- int ret = 0;
-
- for_each_pci_dev(dev) {
- struct smsc_ircc_subsystem_configuration *conf;
-
- /*
- * Cache the subsystem vendor/device:
- * some manufacturers fail to set this for all components,
- * so we save it in case there is just 0x0000 0x0000 on the
- * device we want to check.
- */
- if (dev->subsystem_vendor != 0x0000U) {
- ss_vendor = dev->subsystem_vendor;
- ss_device = dev->subsystem_device;
- }
- conf = subsystem_configurations;
- for( ; conf->subvendor; conf++) {
- if(conf->vendor == dev->vendor &&
- conf->device == dev->device &&
- conf->subvendor == ss_vendor &&
- /* Sometimes these are cached values */
- (conf->subdevice == ss_device ||
- conf->subdevice == 0xffff)) {
- struct smsc_ircc_subsystem_configuration
- tmpconf;
-
- memcpy(&tmpconf, conf,
- sizeof(struct smsc_ircc_subsystem_configuration));
-
- /*
- * Override the default values with anything
- * passed in as parameter
- */
- if (ircc_cfg != 0)
- tmpconf.cfg_base = ircc_cfg;
- if (ircc_fir != 0)
- tmpconf.fir_io = ircc_fir;
- if (ircc_sir != 0)
- tmpconf.sir_io = ircc_sir;
- if (ircc_dma != DMA_INVAL)
- tmpconf.fir_dma = ircc_dma;
- if (ircc_irq != IRQ_INVAL)
- tmpconf.fir_irq = ircc_irq;
-
- net_info_ratelimited("Detected unconfigured %s SMSC IrDA chip, pre-configuring device\n",
- conf->name);
- if (conf->preconfigure)
- ret = conf->preconfigure(dev, &tmpconf);
- else
- ret = -ENODEV;
- }
- }
- }
-
- return ret;
-}
-#endif // CONFIG_PCI
-
-/************************************************
- *
- * Transceivers specific functions
- *
- ************************************************/
-
-
-/*
- * Function smsc_ircc_set_transceiver_smsc_ircc_atc(fir_base, speed)
- *
- * Program transceiver through smsc-ircc ATC circuitry
- *
- */
-
-static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed)
-{
- unsigned long jiffies_now, jiffies_timeout;
- u8 val;
-
- jiffies_now = jiffies;
- jiffies_timeout = jiffies + SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES;
-
- /* ATC */
- register_bank(fir_base, 4);
- outb((inb(fir_base + IRCC_ATC) & IRCC_ATC_MASK) | IRCC_ATC_nPROGREADY|IRCC_ATC_ENABLE,
- fir_base + IRCC_ATC);
-
- while ((val = (inb(fir_base + IRCC_ATC) & IRCC_ATC_nPROGREADY)) &&
- !time_after(jiffies, jiffies_timeout))
- /* empty */;
-
- if (val)
- net_warn_ratelimited("%s(): ATC: 0x%02x\n",
- __func__, inb(fir_base + IRCC_ATC));
-}
-
-/*
- * Function smsc_ircc_probe_transceiver_smsc_ircc_atc(fir_base)
- *
- * Probe transceiver smsc-ircc ATC circuitry
- *
- */
-
-static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base)
-{
- return 0;
-}
-
-/*
- * Function smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(self, speed)
- *
- * Set transceiver
- *
- */
-
-static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed)
-{
- u8 fast_mode;
-
- switch (speed) {
- default:
- case 576000 :
- fast_mode = 0;
- break;
- case 1152000 :
- case 4000000 :
- fast_mode = IRCC_LCR_A_FAST;
- break;
- }
- register_bank(fir_base, 0);
- outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast_mode, fir_base + IRCC_LCR_A);
-}
-
-/*
- * Function smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(fir_base)
- *
- * Probe transceiver
- *
- */
-
-static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base)
-{
- return 0;
-}
-
-/*
- * Function smsc_ircc_set_transceiver_toshiba_sat1800(fir_base, speed)
- *
- * Set transceiver
- *
- */
-
-static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed)
-{
- u8 fast_mode;
-
- switch (speed) {
- default:
- case 576000 :
- fast_mode = 0;
- break;
- case 1152000 :
- case 4000000 :
- fast_mode = /*IRCC_LCR_A_FAST |*/ IRCC_LCR_A_GP_DATA;
- break;
-
- }
- /* This causes an interrupt */
- register_bank(fir_base, 0);
- outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast_mode, fir_base + IRCC_LCR_A);
-}
-
-/*
- * Function smsc_ircc_probe_transceiver_toshiba_sat1800(fir_base)
- *
- * Probe transceiver
- *
- */
-
-static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base)
-{
- return 0;
-}
-
-
-module_init(smsc_ircc_init);
-module_exit(smsc_ircc_cleanup);
diff --git a/drivers/staging/irda/drivers/smsc-ircc2.h b/drivers/staging/irda/drivers/smsc-ircc2.h
deleted file mode 100644
index 4829fa22cb29..000000000000
--- a/drivers/staging/irda/drivers/smsc-ircc2.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*********************************************************************
- *
- * Description: Definitions for the SMC IrCC chipset
- * Status: Experimental.
- * Author: Daniele Peri (peri@csai.unipa.it)
- *
- * Copyright (c) 2002 Daniele Peri
- * All Rights Reserved.
- *
- * Based on smc-ircc.h:
- *
- * Copyright (c) 1999-2000, Dag Brattli <dagb@cs.uit.no>
- * Copyright (c) 1998-1999, Thomas Davis (tadavis@jps.net>
- * 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.
- *
- * 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 SMSC_IRCC2_H
-#define SMSC_IRCC2_H
-
-/* DMA modes needed */
-#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */
-#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */
-
-/* Master Control Register */
-#define IRCC_MASTER 0x07
-#define IRCC_MASTER_POWERDOWN 0x80
-#define IRCC_MASTER_RESET 0x40
-#define IRCC_MASTER_INT_EN 0x20
-#define IRCC_MASTER_ERROR_RESET 0x10
-
-/* Register block 0 */
-
-/* Interrupt Identification */
-#define IRCC_IIR 0x01
-#define IRCC_IIR_ACTIVE_FRAME 0x80
-#define IRCC_IIR_EOM 0x40
-#define IRCC_IIR_RAW_MODE 0x20
-#define IRCC_IIR_FIFO 0x10
-
-/* Interrupt Enable */
-#define IRCC_IER 0x02
-#define IRCC_IER_ACTIVE_FRAME 0x80
-#define IRCC_IER_EOM 0x40
-#define IRCC_IER_RAW_MODE 0x20
-#define IRCC_IER_FIFO 0x10
-
-/* Line Status Register */
-#define IRCC_LSR 0x03
-#define IRCC_LSR_UNDERRUN 0x80
-#define IRCC_LSR_OVERRUN 0x40
-#define IRCC_LSR_FRAME_ERROR 0x20
-#define IRCC_LSR_SIZE_ERROR 0x10
-#define IRCC_LSR_CRC_ERROR 0x80
-#define IRCC_LSR_FRAME_ABORT 0x40
-
-/* Line Status Address Register */
-#define IRCC_LSAR 0x03
-#define IRCC_LSAR_ADDRESS_MASK 0x07
-
-/* Line Control Register A */
-#define IRCC_LCR_A 0x04
-#define IRCC_LCR_A_FIFO_RESET 0x80
-#define IRCC_LCR_A_FAST 0x40
-#define IRCC_LCR_A_GP_DATA 0x20
-#define IRCC_LCR_A_RAW_TX 0x10
-#define IRCC_LCR_A_RAW_RX 0x08
-#define IRCC_LCR_A_ABORT 0x04
-#define IRCC_LCR_A_DATA_DONE 0x02
-
-/* Line Control Register B */
-#define IRCC_LCR_B 0x05
-#define IRCC_LCR_B_SCE_DISABLED 0x00
-#define IRCC_LCR_B_SCE_TRANSMIT 0x40
-#define IRCC_LCR_B_SCE_RECEIVE 0x80
-#define IRCC_LCR_B_SCE_UNDEFINED 0xc0
-#define IRCC_LCR_B_SIP_ENABLE 0x20
-#define IRCC_LCR_B_BRICK_WALL 0x10
-
-/* Bus Status Register */
-#define IRCC_BSR 0x06
-#define IRCC_BSR_NOT_EMPTY 0x80
-#define IRCC_BSR_FIFO_FULL 0x40
-#define IRCC_BSR_TIMEOUT 0x20
-
-/* Register block 1 */
-
-#define IRCC_FIFO_THRESHOLD 0x02
-
-#define IRCC_SCE_CFGA 0x00
-#define IRCC_CFGA_AUX_IR 0x80
-#define IRCC_CFGA_HALF_DUPLEX 0x04
-#define IRCC_CFGA_TX_POLARITY 0x02
-#define IRCC_CFGA_RX_POLARITY 0x01
-
-#define IRCC_CFGA_COM 0x00
-#define IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK 0x87
-#define IRCC_CFGA_IRDA_SIR_A 0x08
-#define IRCC_CFGA_ASK_SIR 0x10
-#define IRCC_CFGA_IRDA_SIR_B 0x18
-#define IRCC_CFGA_IRDA_HDLC 0x20
-#define IRCC_CFGA_IRDA_4PPM 0x28
-#define IRCC_CFGA_CONSUMER 0x30
-#define IRCC_CFGA_RAW_IR 0x38
-#define IRCC_CFGA_OTHER 0x40
-
-#define IRCC_IR_HDLC 0x04
-#define IRCC_IR_4PPM 0x01
-#define IRCC_IR_CONSUMER 0x02
-
-#define IRCC_SCE_CFGB 0x01
-#define IRCC_CFGB_LOOPBACK 0x20
-#define IRCC_CFGB_LPBCK_TX_CRC 0x10
-#define IRCC_CFGB_NOWAIT 0x08
-#define IRCC_CFGB_STRING_MOVE 0x04
-#define IRCC_CFGB_DMA_BURST 0x02
-#define IRCC_CFGB_DMA_ENABLE 0x01
-
-#define IRCC_CFGB_MUX_COM 0x00
-#define IRCC_CFGB_MUX_IR 0x40
-#define IRCC_CFGB_MUX_AUX 0x80
-#define IRCC_CFGB_MUX_INACTIVE 0xc0
-
-/* Register block 3 - Identification Registers! */
-#define IRCC_ID_HIGH 0x00 /* 0x10 */
-#define IRCC_ID_LOW 0x01 /* 0xB8 */
-#define IRCC_CHIP_ID 0x02 /* 0xF1 */
-#define IRCC_VERSION 0x03 /* 0x01 */
-#define IRCC_INTERFACE 0x04 /* low 4 = DMA, high 4 = IRQ */
-#define IRCC_INTERFACE_DMA_MASK 0x0F /* low 4 = DMA, high 4 = IRQ */
-#define IRCC_INTERFACE_IRQ_MASK 0xF0 /* low 4 = DMA, high 4 = IRQ */
-
-/* Register block 4 - IrDA */
-#define IRCC_CONTROL 0x00
-#define IRCC_BOF_COUNT_LO 0x01 /* Low byte */
-#define IRCC_BOF_COUNT_HI 0x00 /* High nibble (bit 0-3) */
-#define IRCC_BRICKWALL_CNT_LO 0x02 /* Low byte */
-#define IRCC_BRICKWALL_CNT_HI 0x03 /* High nibble (bit 4-7) */
-#define IRCC_TX_SIZE_LO 0x04 /* Low byte */
-#define IRCC_TX_SIZE_HI 0x03 /* High nibble (bit 0-3) */
-#define IRCC_RX_SIZE_HI 0x05 /* High nibble (bit 0-3) */
-#define IRCC_RX_SIZE_LO 0x06 /* Low byte */
-
-#define IRCC_1152 0x80
-#define IRCC_CRC 0x40
-
-/* Register block 5 - IrDA */
-#define IRCC_ATC 0x00
-#define IRCC_ATC_nPROGREADY 0x80
-#define IRCC_ATC_SPEED 0x40
-#define IRCC_ATC_ENABLE 0x20
-#define IRCC_ATC_MASK 0xE0
-
-
-#define IRCC_IRHALFDUPLEX_TIMEOUT 0x01
-
-#define IRCC_SCE_TX_DELAY_TIMER 0x02
-
-/*
- * Other definitions
- */
-
-#define SMSC_IRCC2_MAX_SIR_SPEED 115200
-#define SMSC_IRCC2_FIR_CHIP_IO_EXTENT 8
-#define SMSC_IRCC2_SIR_CHIP_IO_EXTENT 8
-#define SMSC_IRCC2_FIFO_SIZE 16
-#define SMSC_IRCC2_FIFO_THRESHOLD 64
-/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
-#define SMSC_IRCC2_RX_BUFF_TRUESIZE 14384
-#define SMSC_IRCC2_TX_BUFF_TRUESIZE 14384
-#define SMSC_IRCC2_MIN_TURN_TIME 0x07
-#define SMSC_IRCC2_WINDOW_SIZE 0x07
-/* Maximum wait for hw transmitter to finish */
-#define SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US 1000 /* 1 ms */
-/* Maximum wait for ATC transceiver programming to finish */
-#define SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES 1
-#endif /* SMSC_IRCC2_H */
diff --git a/drivers/staging/irda/drivers/smsc-sio.h b/drivers/staging/irda/drivers/smsc-sio.h
deleted file mode 100644
index 59e20e653ebe..000000000000
--- a/drivers/staging/irda/drivers/smsc-sio.h
+++ /dev/null
@@ -1,100 +0,0 @@
-#ifndef SMSC_SIO_H
-#define SMSC_SIO_H
-
-/******************************************
- Keys. They should work with every SMsC SIO
- ******************************************/
-
-#define SMSCSIO_CFGACCESSKEY 0x55
-#define SMSCSIO_CFGEXITKEY 0xaa
-
-/*****************************
- * Generic SIO Flat (!?) *
- *****************************/
-
-/* Register 0x0d */
-#define SMSCSIOFLAT_DEVICEID_REG 0x0d
-
-/* Register 0x0c */
-#define SMSCSIOFLAT_UARTMODE0C_REG 0x0c
-#define SMSCSIOFLAT_UART2MODE_MASK 0x38
-#define SMSCSIOFLAT_UART2MODE_VAL_COM 0x00
-#define SMSCSIOFLAT_UART2MODE_VAL_IRDA 0x08
-#define SMSCSIOFLAT_UART2MODE_VAL_ASKIR 0x10
-
-/* Register 0x25 */
-#define SMSCSIOFLAT_UART2BASEADDR_REG 0x25
-
-/* Register 0x2b */
-#define SMSCSIOFLAT_FIRBASEADDR_REG 0x2b
-
-/* Register 0x2c */
-#define SMSCSIOFLAT_FIRDMASELECT_REG 0x2c
-#define SMSCSIOFLAT_FIRDMASELECT_MASK 0x0f
-
-/* Register 0x28 */
-#define SMSCSIOFLAT_UARTIRQSELECT_REG 0x28
-#define SMSCSIOFLAT_UART2IRQSELECT_MASK 0x0f
-#define SMSCSIOFLAT_UART1IRQSELECT_MASK 0xf0
-#define SMSCSIOFLAT_UARTIRQSELECT_VAL_NONE 0x00
-
-
-/*********************
- * LPC47N227 *
- *********************/
-
-#define LPC47N227_CFGACCESSKEY 0x55
-#define LPC47N227_CFGEXITKEY 0xaa
-
-/* Register 0x00 */
-#define LPC47N227_FDCPOWERVALIDCONF_REG 0x00
-#define LPC47N227_FDCPOWER_MASK 0x08
-#define LPC47N227_VALID_MASK 0x80
-
-/* Register 0x02 */
-#define LPC47N227_UART12POWER_REG 0x02
-#define LPC47N227_UART1POWERDOWN_MASK 0x08
-#define LPC47N227_UART2POWERDOWN_MASK 0x80
-
-/* Register 0x07 */
-#define LPC47N227_APMBOOTDRIVE_REG 0x07
-#define LPC47N227_PARPORT2AUTOPWRDOWN_MASK 0x10 /* auto power down on if set */
-#define LPC47N227_UART2AUTOPWRDOWN_MASK 0x20 /* auto power down on if set */
-#define LPC47N227_UART1AUTOPWRDOWN_MASK 0x40 /* auto power down on if set */
-
-/* Register 0x0c */
-#define LPC47N227_UARTMODE0C_REG 0x0c
-#define LPC47N227_UART2MODE_MASK 0x38
-#define LPC47N227_UART2MODE_VAL_COM 0x00
-#define LPC47N227_UART2MODE_VAL_IRDA 0x08
-#define LPC47N227_UART2MODE_VAL_ASKIR 0x10
-
-/* Register 0x0d */
-#define LPC47N227_DEVICEID_REG 0x0d
-#define LPC47N227_DEVICEID_DEFVAL 0x5a
-
-/* Register 0x0e */
-#define LPC47N227_REVISIONID_REG 0x0e
-
-/* Register 0x25 */
-#define LPC47N227_UART2BASEADDR_REG 0x25
-
-/* Register 0x28 */
-#define LPC47N227_UARTIRQSELECT_REG 0x28
-#define LPC47N227_UART2IRQSELECT_MASK 0x0f
-#define LPC47N227_UART1IRQSELECT_MASK 0xf0
-#define LPC47N227_UARTIRQSELECT_VAL_NONE 0x00
-
-/* Register 0x2b */
-#define LPC47N227_FIRBASEADDR_REG 0x2b
-
-/* Register 0x2c */
-#define LPC47N227_FIRDMASELECT_REG 0x2c
-#define LPC47N227_FIRDMASELECT_MASK 0x0f
-#define LPC47N227_FIRDMASELECT_VAL_DMA1 0x01 /* 47n227 has three dma channels */
-#define LPC47N227_FIRDMASELECT_VAL_DMA2 0x02
-#define LPC47N227_FIRDMASELECT_VAL_DMA3 0x03
-#define LPC47N227_FIRDMASELECT_VAL_NONE 0x0f
-
-
-#endif
diff --git a/drivers/staging/irda/drivers/stir4200.c b/drivers/staging/irda/drivers/stir4200.c
deleted file mode 100644
index ee2cb70b688d..000000000000
--- a/drivers/staging/irda/drivers/stir4200.c
+++ /dev/null
@@ -1,1134 +0,0 @@
-/*****************************************************************************
-*
-* Filename: stir4200.c
-* Version: 0.4
-* Description: Irda SigmaTel USB Dongle
-* Status: Experimental
-* Author: Stephen Hemminger <shemminger@osdl.org>
-*
-* Based on earlier driver by Paul Stewart <stewart@parc.com>
-*
-* Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at>
-* Copyright (C) 2001, Dag Brattli <dag@brattli.net>
-* Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com>
-* Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.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.
-*
-* 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, write to the Free Software
-* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-*****************************************************************************/
-
-/*
- * This dongle does no framing, and requires polling to receive the
- * data. The STIr4200 has bulk in and out endpoints just like
- * usr-irda devices, but the data it sends and receives is raw; like
- * irtty, it needs to call the wrap and unwrap functions to add and
- * remove SOF/BOF and escape characters to/from the frame.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-
-#include <linux/kernel.h>
-#include <linux/sched/signal.h>
-#include <linux/ktime.h>
-#include <linux/types.h>
-#include <linux/time.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/usb.h>
-#include <linux/crc32.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/crc.h>
-#include <asm/byteorder.h>
-#include <asm/unaligned.h>
-
-MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
-MODULE_DESCRIPTION("IrDA-USB Dongle Driver for SigmaTel STIr4200");
-MODULE_LICENSE("GPL");
-
-static int qos_mtt_bits = 0x07; /* 1 ms or more */
-module_param(qos_mtt_bits, int, 0);
-MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
-
-static int rx_sensitivity = 1; /* FIR 0..4, SIR 0..6 */
-module_param(rx_sensitivity, int, 0);
-MODULE_PARM_DESC(rx_sensitivity, "Set Receiver sensitivity (0-6, 0 is most sensitive)");
-
-static int tx_power = 0; /* 0 = highest ... 3 = lowest */
-module_param(tx_power, int, 0);
-MODULE_PARM_DESC(tx_power, "Set Transmitter power (0-3, 0 is highest power)");
-
-#define STIR_IRDA_HEADER 4
-#define CTRL_TIMEOUT 100 /* milliseconds */
-#define TRANSMIT_TIMEOUT 200 /* milliseconds */
-#define STIR_FIFO_SIZE 4096
-#define FIFO_REGS_SIZE 3
-
-enum FirChars {
- FIR_CE = 0x7d,
- FIR_XBOF = 0x7f,
- FIR_EOF = 0x7e,
-};
-
-enum StirRequests {
- REQ_WRITE_REG = 0x00,
- REQ_READ_REG = 0x01,
- REQ_READ_ROM = 0x02,
- REQ_WRITE_SINGLE = 0x03,
-};
-
-/* Register offsets */
-enum StirRegs {
- REG_RSVD=0,
- REG_MODE,
- REG_PDCLK,
- REG_CTRL1,
- REG_CTRL2,
- REG_FIFOCTL,
- REG_FIFOLSB,
- REG_FIFOMSB,
- REG_DPLL,
- REG_IRDIG,
- REG_TEST=15,
-};
-
-enum StirModeMask {
- MODE_FIR = 0x80,
- MODE_SIR = 0x20,
- MODE_ASK = 0x10,
- MODE_FASTRX = 0x08,
- MODE_FFRSTEN = 0x04,
- MODE_NRESET = 0x02,
- MODE_2400 = 0x01,
-};
-
-enum StirPdclkMask {
- PDCLK_4000000 = 0x02,
- PDCLK_115200 = 0x09,
- PDCLK_57600 = 0x13,
- PDCLK_38400 = 0x1D,
- PDCLK_19200 = 0x3B,
- PDCLK_9600 = 0x77,
- PDCLK_2400 = 0xDF,
-};
-
-enum StirCtrl1Mask {
- CTRL1_SDMODE = 0x80,
- CTRL1_RXSLOW = 0x40,
- CTRL1_TXPWD = 0x10,
- CTRL1_RXPWD = 0x08,
- CTRL1_SRESET = 0x01,
-};
-
-enum StirCtrl2Mask {
- CTRL2_SPWIDTH = 0x08,
- CTRL2_REVID = 0x03,
-};
-
-enum StirFifoCtlMask {
- FIFOCTL_DIR = 0x10,
- FIFOCTL_CLR = 0x08,
- FIFOCTL_EMPTY = 0x04,
-};
-
-enum StirDiagMask {
- IRDIG_RXHIGH = 0x80,
- IRDIG_RXLOW = 0x40,
-};
-
-enum StirTestMask {
- TEST_PLLDOWN = 0x80,
- TEST_LOOPIR = 0x40,
- TEST_LOOPUSB = 0x20,
- TEST_TSTENA = 0x10,
- TEST_TSTOSC = 0x0F,
-};
-
-struct stir_cb {
- struct usb_device *usbdev; /* init: probe_irda */
- struct net_device *netdev; /* network layer */
- struct irlap_cb *irlap; /* The link layer we are binded to */
-
- struct qos_info qos;
- unsigned speed; /* Current speed */
-
- struct task_struct *thread; /* transmit thread */
-
- struct sk_buff *tx_pending;
- void *io_buf; /* transmit/receive buffer */
- __u8 *fifo_status;
-
- iobuff_t rx_buff; /* receive unwrap state machine */
- ktime_t rx_time;
- int receiving;
- struct urb *rx_urb;
-};
-
-
-/* These are the currently known USB ids */
-static const struct usb_device_id dongles[] = {
- /* SigmaTel, Inc, STIr4200 IrDA/USB Bridge */
- { USB_DEVICE(0x066f, 0x4200) },
- { }
-};
-
-MODULE_DEVICE_TABLE(usb, dongles);
-
-/* Send control message to set dongle register */
-static int write_reg(struct stir_cb *stir, __u16 reg, __u8 value)
-{
- struct usb_device *dev = stir->usbdev;
-
- pr_debug("%s: write reg %d = 0x%x\n",
- stir->netdev->name, reg, value);
- return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- REQ_WRITE_SINGLE,
- USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE,
- value, reg, NULL, 0,
- CTRL_TIMEOUT);
-}
-
-/* Send control message to read multiple registers */
-static inline int read_reg(struct stir_cb *stir, __u16 reg,
- __u8 *data, __u16 count)
-{
- struct usb_device *dev = stir->usbdev;
-
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- REQ_READ_REG,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, reg, data, count,
- CTRL_TIMEOUT);
-}
-
-static inline int isfir(u32 speed)
-{
- return speed == 4000000;
-}
-
-/*
- * Prepare a FIR IrDA frame for transmission to the USB dongle. The
- * FIR transmit frame is documented in the datasheet. It consists of
- * a two byte 0x55 0xAA sequence, two little-endian length bytes, a
- * sequence of exactly 16 XBOF bytes of 0x7E, two BOF bytes of 0x7E,
- * then the data escaped as follows:
- *
- * 0x7D -> 0x7D 0x5D
- * 0x7E -> 0x7D 0x5E
- * 0x7F -> 0x7D 0x5F
- *
- * Then, 4 bytes of little endian (stuffed) FCS follow, then two
- * trailing EOF bytes of 0x7E.
- */
-static inline __u8 *stuff_fir(__u8 *p, __u8 c)
-{
- switch(c) {
- case 0x7d:
- case 0x7e:
- case 0x7f:
- *p++ = 0x7d;
- c ^= IRDA_TRANS;
- /* fall through */
- default:
- *p++ = c;
- }
- return p;
-}
-
-/* Take raw data in skb and put it wrapped into buf */
-static unsigned wrap_fir_skb(const struct sk_buff *skb, __u8 *buf)
-{
- __u8 *ptr = buf;
- __u32 fcs = ~(crc32_le(~0, skb->data, skb->len));
- __u16 wraplen;
- int i;
-
- /* Header */
- buf[0] = 0x55;
- buf[1] = 0xAA;
-
- ptr = buf + STIR_IRDA_HEADER;
- memset(ptr, 0x7f, 16);
- ptr += 16;
-
- /* BOF */
- *ptr++ = 0x7e;
- *ptr++ = 0x7e;
-
- /* Address / Control / Information */
- for (i = 0; i < skb->len; i++)
- ptr = stuff_fir(ptr, skb->data[i]);
-
- /* FCS */
- ptr = stuff_fir(ptr, fcs & 0xff);
- ptr = stuff_fir(ptr, (fcs >> 8) & 0xff);
- ptr = stuff_fir(ptr, (fcs >> 16) & 0xff);
- ptr = stuff_fir(ptr, (fcs >> 24) & 0xff);
-
- /* EOFs */
- *ptr++ = 0x7e;
- *ptr++ = 0x7e;
-
- /* Total length, minus the header */
- wraplen = (ptr - buf) - STIR_IRDA_HEADER;
- buf[2] = wraplen & 0xff;
- buf[3] = (wraplen >> 8) & 0xff;
-
- return wraplen + STIR_IRDA_HEADER;
-}
-
-static unsigned wrap_sir_skb(struct sk_buff *skb, __u8 *buf)
-{
- __u16 wraplen;
-
- wraplen = async_wrap_skb(skb, buf + STIR_IRDA_HEADER,
- STIR_FIFO_SIZE - STIR_IRDA_HEADER);
- buf[0] = 0x55;
- buf[1] = 0xAA;
- buf[2] = wraplen & 0xff;
- buf[3] = (wraplen >> 8) & 0xff;
-
- return wraplen + STIR_IRDA_HEADER;
-}
-
-/*
- * Frame is fully formed in the rx_buff so check crc
- * and pass up to irlap
- * setup for next receive
- */
-static void fir_eof(struct stir_cb *stir)
-{
- iobuff_t *rx_buff = &stir->rx_buff;
- int len = rx_buff->len - 4;
- struct sk_buff *skb, *nskb;
- __u32 fcs;
-
- if (unlikely(len <= 0)) {
- pr_debug("%s: short frame len %d\n",
- stir->netdev->name, len);
-
- ++stir->netdev->stats.rx_errors;
- ++stir->netdev->stats.rx_length_errors;
- return;
- }
-
- fcs = ~(crc32_le(~0, rx_buff->data, len));
- if (fcs != get_unaligned_le32(rx_buff->data + len)) {
- pr_debug("crc error calc 0x%x len %d\n", fcs, len);
- stir->netdev->stats.rx_errors++;
- stir->netdev->stats.rx_crc_errors++;
- return;
- }
-
- /* if frame is short then just copy it */
- if (len < IRDA_RX_COPY_THRESHOLD) {
- nskb = dev_alloc_skb(len + 1);
- if (unlikely(!nskb)) {
- ++stir->netdev->stats.rx_dropped;
- return;
- }
- skb_reserve(nskb, 1);
- skb = nskb;
- skb_copy_to_linear_data(nskb, rx_buff->data, len);
- } else {
- nskb = dev_alloc_skb(rx_buff->truesize);
- if (unlikely(!nskb)) {
- ++stir->netdev->stats.rx_dropped;
- return;
- }
- skb_reserve(nskb, 1);
- skb = rx_buff->skb;
- rx_buff->skb = nskb;
- rx_buff->head = nskb->data;
- }
-
- skb_put(skb, len);
-
- skb_reset_mac_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- skb->dev = stir->netdev;
-
- netif_rx(skb);
-
- stir->netdev->stats.rx_packets++;
- stir->netdev->stats.rx_bytes += len;
-
- rx_buff->data = rx_buff->head;
- rx_buff->len = 0;
-}
-
-/* Unwrap FIR stuffed data and bump it to IrLAP */
-static void stir_fir_chars(struct stir_cb *stir,
- const __u8 *bytes, int len)
-{
- iobuff_t *rx_buff = &stir->rx_buff;
- int i;
-
- for (i = 0; i < len; i++) {
- __u8 byte = bytes[i];
-
- switch(rx_buff->state) {
- case OUTSIDE_FRAME:
- /* ignore garbage till start of frame */
- if (unlikely(byte != FIR_EOF))
- continue;
- /* Now receiving frame */
- rx_buff->state = BEGIN_FRAME;
-
- /* Time to initialize receive buffer */
- rx_buff->data = rx_buff->head;
- rx_buff->len = 0;
- continue;
-
- case LINK_ESCAPE:
- if (byte == FIR_EOF) {
- pr_debug("%s: got EOF after escape\n",
- stir->netdev->name);
- goto frame_error;
- }
- rx_buff->state = INSIDE_FRAME;
- byte ^= IRDA_TRANS;
- break;
-
- case BEGIN_FRAME:
- /* ignore multiple BOF/EOF */
- if (byte == FIR_EOF)
- continue;
- rx_buff->state = INSIDE_FRAME;
- rx_buff->in_frame = TRUE;
-
- /* fall through */
- case INSIDE_FRAME:
- switch(byte) {
- case FIR_CE:
- rx_buff->state = LINK_ESCAPE;
- continue;
- case FIR_XBOF:
- /* 0x7f is not used in this framing */
- pr_debug("%s: got XBOF without escape\n",
- stir->netdev->name);
- goto frame_error;
- case FIR_EOF:
- rx_buff->state = OUTSIDE_FRAME;
- rx_buff->in_frame = FALSE;
- fir_eof(stir);
- continue;
- }
- break;
- }
-
- /* add byte to rx buffer */
- if (unlikely(rx_buff->len >= rx_buff->truesize)) {
- pr_debug("%s: fir frame exceeds %d\n",
- stir->netdev->name, rx_buff->truesize);
- ++stir->netdev->stats.rx_over_errors;
- goto error_recovery;
- }
-
- rx_buff->data[rx_buff->len++] = byte;
- continue;
-
- frame_error:
- ++stir->netdev->stats.rx_frame_errors;
-
- error_recovery:
- ++stir->netdev->stats.rx_errors;
- rx_buff->state = OUTSIDE_FRAME;
- rx_buff->in_frame = FALSE;
- }
-}
-
-/* Unwrap SIR stuffed data and bump it up to IrLAP */
-static void stir_sir_chars(struct stir_cb *stir,
- const __u8 *bytes, int len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- async_unwrap_char(stir->netdev, &stir->netdev->stats,
- &stir->rx_buff, bytes[i]);
-}
-
-static inline void unwrap_chars(struct stir_cb *stir,
- const __u8 *bytes, int length)
-{
- if (isfir(stir->speed))
- stir_fir_chars(stir, bytes, length);
- else
- stir_sir_chars(stir, bytes, length);
-}
-
-/* Mode parameters for each speed */
-static const struct {
- unsigned speed;
- __u8 pdclk;
-} stir_modes[] = {
- { 2400, PDCLK_2400 },
- { 9600, PDCLK_9600 },
- { 19200, PDCLK_19200 },
- { 38400, PDCLK_38400 },
- { 57600, PDCLK_57600 },
- { 115200, PDCLK_115200 },
- { 4000000, PDCLK_4000000 },
-};
-
-
-/*
- * Setup chip for speed.
- * Called at startup to initialize the chip
- * and on speed changes.
- *
- * Note: Write multiple registers doesn't appear to work
- */
-static int change_speed(struct stir_cb *stir, unsigned speed)
-{
- int i, err;
- __u8 mode;
-
- for (i = 0; i < ARRAY_SIZE(stir_modes); ++i) {
- if (speed == stir_modes[i].speed)
- goto found;
- }
-
- dev_warn(&stir->netdev->dev, "invalid speed %d\n", speed);
- return -EINVAL;
-
- found:
- pr_debug("speed change from %d to %d\n", stir->speed, speed);
-
- /* Reset modulator */
- err = write_reg(stir, REG_CTRL1, CTRL1_SRESET);
- if (err)
- goto out;
-
- /* Undocumented magic to tweak the DPLL */
- err = write_reg(stir, REG_DPLL, 0x15);
- if (err)
- goto out;
-
- /* Set clock */
- err = write_reg(stir, REG_PDCLK, stir_modes[i].pdclk);
- if (err)
- goto out;
-
- mode = MODE_NRESET | MODE_FASTRX;
- if (isfir(speed))
- mode |= MODE_FIR | MODE_FFRSTEN;
- else
- mode |= MODE_SIR;
-
- if (speed == 2400)
- mode |= MODE_2400;
-
- err = write_reg(stir, REG_MODE, mode);
- if (err)
- goto out;
-
- /* This resets TEMIC style transceiver if any. */
- err = write_reg(stir, REG_CTRL1,
- CTRL1_SDMODE | (tx_power & 3) << 1);
- if (err)
- goto out;
-
- err = write_reg(stir, REG_CTRL1, (tx_power & 3) << 1);
- if (err)
- goto out;
-
- /* Reset sensitivity */
- err = write_reg(stir, REG_CTRL2, (rx_sensitivity & 7) << 5);
- out:
- stir->speed = speed;
- return err;
-}
-
-/*
- * Called from net/core when new frame is available.
- */
-static netdev_tx_t stir_hard_xmit(struct sk_buff *skb,
- struct net_device *netdev)
-{
- struct stir_cb *stir = netdev_priv(netdev);
-
- netif_stop_queue(netdev);
-
- /* the IRDA wrapping routines don't deal with non linear skb */
- SKB_LINEAR_ASSERT(skb);
-
- skb = xchg(&stir->tx_pending, skb);
- wake_up_process(stir->thread);
-
- /* this should never happen unless stop/wakeup problem */
- if (unlikely(skb)) {
- WARN_ON(1);
- dev_kfree_skb(skb);
- }
-
- return NETDEV_TX_OK;
-}
-
-/*
- * Wait for the transmit FIFO to have space for next data
- *
- * If space < 0 then wait till FIFO completely drains.
- * FYI: can take up to 13 seconds at 2400baud.
- */
-static int fifo_txwait(struct stir_cb *stir, int space)
-{
- int err;
- unsigned long count, status;
- unsigned long prev_count = 0x1fff;
-
- /* Read FIFO status and count */
- for (;; prev_count = count) {
- err = read_reg(stir, REG_FIFOCTL, stir->fifo_status,
- FIFO_REGS_SIZE);
- if (unlikely(err != FIFO_REGS_SIZE)) {
- dev_warn(&stir->netdev->dev,
- "FIFO register read error: %d\n", err);
-
- return err;
- }
-
- status = stir->fifo_status[0];
- count = (unsigned)(stir->fifo_status[2] & 0x1f) << 8
- | stir->fifo_status[1];
-
- pr_debug("fifo status 0x%lx count %lu\n", status, count);
-
- /* is fifo receiving already, or empty */
- if (!(status & FIFOCTL_DIR) ||
- (status & FIFOCTL_EMPTY))
- return 0;
-
- if (signal_pending(current))
- return -EINTR;
-
- /* shutting down? */
- if (!netif_running(stir->netdev) ||
- !netif_device_present(stir->netdev))
- return -ESHUTDOWN;
-
- /* only waiting for some space */
- if (space >= 0 && STIR_FIFO_SIZE - 4 > space + count)
- return 0;
-
- /* queue confused */
- if (prev_count < count)
- break;
-
- /* estimate transfer time for remaining chars */
- msleep((count * 8000) / stir->speed);
- }
-
- err = write_reg(stir, REG_FIFOCTL, FIFOCTL_CLR);
- if (err)
- return err;
- err = write_reg(stir, REG_FIFOCTL, 0);
- if (err)
- return err;
-
- return 0;
-}
-
-
-/* Wait for turnaround delay before starting transmit. */
-static void turnaround_delay(const struct stir_cb *stir, long us)
-{
- long ticks;
-
- if (us <= 0)
- return;
-
- us -= ktime_us_delta(ktime_get(), stir->rx_time);
-
- if (us < 10)
- return;
-
- ticks = us / (1000000 / HZ);
- if (ticks > 0)
- schedule_timeout_interruptible(1 + ticks);
- else
- udelay(us);
-}
-
-/*
- * Start receiver by submitting a request to the receive pipe.
- * If nothing is available it will return after rx_interval.
- */
-static int receive_start(struct stir_cb *stir)
-{
- /* reset state */
- stir->receiving = 1;
-
- stir->rx_buff.in_frame = FALSE;
- stir->rx_buff.state = OUTSIDE_FRAME;
-
- stir->rx_urb->status = 0;
- return usb_submit_urb(stir->rx_urb, GFP_KERNEL);
-}
-
-/* Stop all pending receive Urb's */
-static void receive_stop(struct stir_cb *stir)
-{
- stir->receiving = 0;
- usb_kill_urb(stir->rx_urb);
-
- if (stir->rx_buff.in_frame)
- stir->netdev->stats.collisions++;
-}
-/*
- * Wrap data in socket buffer and send it.
- */
-static void stir_send(struct stir_cb *stir, struct sk_buff *skb)
-{
- unsigned wraplen;
- int first_frame = 0;
-
- /* if receiving, need to turnaround */
- if (stir->receiving) {
- receive_stop(stir);
- turnaround_delay(stir, irda_get_mtt(skb));
- first_frame = 1;
- }
-
- if (isfir(stir->speed))
- wraplen = wrap_fir_skb(skb, stir->io_buf);
- else
- wraplen = wrap_sir_skb(skb, stir->io_buf);
-
- /* check for space available in fifo */
- if (!first_frame)
- fifo_txwait(stir, wraplen);
-
- stir->netdev->stats.tx_packets++;
- stir->netdev->stats.tx_bytes += skb->len;
- netif_trans_update(stir->netdev);
- pr_debug("send %d (%d)\n", skb->len, wraplen);
-
- if (usb_bulk_msg(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1),
- stir->io_buf, wraplen,
- NULL, TRANSMIT_TIMEOUT))
- stir->netdev->stats.tx_errors++;
-}
-
-/*
- * Transmit state machine thread
- */
-static int stir_transmit_thread(void *arg)
-{
- struct stir_cb *stir = arg;
- struct net_device *dev = stir->netdev;
- struct sk_buff *skb;
-
- while (!kthread_should_stop()) {
-#ifdef CONFIG_PM
- /* if suspending, then power off and wait */
- if (unlikely(freezing(current))) {
- if (stir->receiving)
- receive_stop(stir);
- else
- fifo_txwait(stir, -1);
-
- write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD);
-
- try_to_freeze();
-
- if (change_speed(stir, stir->speed))
- break;
- }
-#endif
-
- /* if something to send? */
- skb = xchg(&stir->tx_pending, NULL);
- if (skb) {
- unsigned new_speed = irda_get_next_speed(skb);
- netif_wake_queue(dev);
-
- if (skb->len > 0)
- stir_send(stir, skb);
- dev_kfree_skb(skb);
-
- if ((new_speed != -1) && (stir->speed != new_speed)) {
- if (fifo_txwait(stir, -1) ||
- change_speed(stir, new_speed))
- break;
- }
- continue;
- }
-
- /* nothing to send? start receiving */
- if (!stir->receiving &&
- irda_device_txqueue_empty(dev)) {
- /* Wait otherwise chip gets confused. */
- if (fifo_txwait(stir, -1))
- break;
-
- if (unlikely(receive_start(stir))) {
- if (net_ratelimit())
- dev_info(&dev->dev,
- "%s: receive usb submit failed\n",
- stir->netdev->name);
- stir->receiving = 0;
- msleep(10);
- continue;
- }
- }
-
- /* sleep if nothing to send */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
-
- }
- return 0;
-}
-
-
-/*
- * USB bulk receive completion callback.
- * Wakes up every ms (usb round trip) with wrapped
- * data.
- */
-static void stir_rcv_irq(struct urb *urb)
-{
- struct stir_cb *stir = urb->context;
- int err;
-
- /* in process of stopping, just drop data */
- if (!netif_running(stir->netdev))
- return;
-
- /* unlink, shutdown, unplug, other nasties */
- if (urb->status != 0)
- return;
-
- if (urb->actual_length > 0) {
- pr_debug("receive %d\n", urb->actual_length);
- unwrap_chars(stir, urb->transfer_buffer,
- urb->actual_length);
-
- stir->rx_time = ktime_get();
- }
-
- /* kernel thread is stopping receiver don't resubmit */
- if (!stir->receiving)
- return;
-
- /* resubmit existing urb */
- err = usb_submit_urb(urb, GFP_ATOMIC);
-
- /* in case of error, the kernel thread will restart us */
- if (err) {
- dev_warn(&stir->netdev->dev, "usb receive submit error: %d\n",
- err);
- stir->receiving = 0;
- wake_up_process(stir->thread);
- }
-}
-
-/*
- * Function stir_net_open (dev)
- *
- * Network device is taken up. Usually this is done by "ifconfig irda0 up"
- */
-static int stir_net_open(struct net_device *netdev)
-{
- struct stir_cb *stir = netdev_priv(netdev);
- int err;
- char hwname[16];
-
- err = usb_clear_halt(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1));
- if (err)
- goto err_out1;
- err = usb_clear_halt(stir->usbdev, usb_rcvbulkpipe(stir->usbdev, 2));
- if (err)
- goto err_out1;
-
- err = change_speed(stir, 9600);
- if (err)
- goto err_out1;
-
- err = -ENOMEM;
-
- /* Initialize for SIR/FIR to copy data directly into skb. */
- stir->receiving = 0;
- stir->rx_buff.truesize = IRDA_SKB_MAX_MTU;
- stir->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
- if (!stir->rx_buff.skb)
- goto err_out1;
-
- skb_reserve(stir->rx_buff.skb, 1);
- stir->rx_buff.head = stir->rx_buff.skb->data;
- stir->rx_time = ktime_get();
-
- stir->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!stir->rx_urb)
- goto err_out2;
-
- stir->io_buf = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL);
- if (!stir->io_buf)
- goto err_out3;
-
- usb_fill_bulk_urb(stir->rx_urb, stir->usbdev,
- usb_rcvbulkpipe(stir->usbdev, 2),
- stir->io_buf, STIR_FIFO_SIZE,
- stir_rcv_irq, stir);
-
- stir->fifo_status = kmalloc(FIFO_REGS_SIZE, GFP_KERNEL);
- if (!stir->fifo_status)
- goto err_out4;
-
- /*
- * Now that everything should be initialized properly,
- * Open new IrLAP layer instance to take care of us...
- * Note : will send immediately a speed change...
- */
- sprintf(hwname, "usb#%d", stir->usbdev->devnum);
- stir->irlap = irlap_open(netdev, &stir->qos, hwname);
- if (!stir->irlap) {
- dev_err(&stir->usbdev->dev, "irlap_open failed\n");
- goto err_out5;
- }
-
- /** Start kernel thread for transmit. */
- stir->thread = kthread_run(stir_transmit_thread, stir,
- "%s", stir->netdev->name);
- if (IS_ERR(stir->thread)) {
- err = PTR_ERR(stir->thread);
- dev_err(&stir->usbdev->dev, "unable to start kernel thread\n");
- goto err_out6;
- }
-
- netif_start_queue(netdev);
-
- return 0;
-
- err_out6:
- irlap_close(stir->irlap);
- err_out5:
- kfree(stir->fifo_status);
- err_out4:
- kfree(stir->io_buf);
- err_out3:
- usb_free_urb(stir->rx_urb);
- err_out2:
- kfree_skb(stir->rx_buff.skb);
- err_out1:
- return err;
-}
-
-/*
- * Function stir_net_close (stir)
- *
- * Network device is taken down. Usually this is done by
- * "ifconfig irda0 down"
- */
-static int stir_net_close(struct net_device *netdev)
-{
- struct stir_cb *stir = netdev_priv(netdev);
-
- /* Stop transmit processing */
- netif_stop_queue(netdev);
-
- /* Kill transmit thread */
- kthread_stop(stir->thread);
- kfree(stir->fifo_status);
-
- /* Mop up receive urb's */
- usb_kill_urb(stir->rx_urb);
-
- kfree(stir->io_buf);
- usb_free_urb(stir->rx_urb);
- kfree_skb(stir->rx_buff.skb);
-
- /* Stop and remove instance of IrLAP */
- if (stir->irlap)
- irlap_close(stir->irlap);
-
- stir->irlap = NULL;
-
- return 0;
-}
-
-/*
- * IOCTLs : Extra out-of-band network commands...
- */
-static int stir_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
-{
- struct if_irda_req *irq = (struct if_irda_req *) rq;
- struct stir_cb *stir = netdev_priv(netdev);
- int ret = 0;
-
- switch (cmd) {
- case SIOCSBANDWIDTH: /* Set bandwidth */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- /* Check if the device is still there */
- if (netif_device_present(stir->netdev))
- ret = change_speed(stir, irq->ifr_baudrate);
- break;
-
- case SIOCSMEDIABUSY: /* Set media busy */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- /* Check if the IrDA stack is still there */
- if (netif_running(stir->netdev))
- irda_device_set_media_busy(stir->netdev, TRUE);
- break;
-
- case SIOCGRECEIVING:
- /* Only approximately true */
- irq->ifr_receiving = stir->receiving;
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- return ret;
-}
-
-static const struct net_device_ops stir_netdev_ops = {
- .ndo_open = stir_net_open,
- .ndo_stop = stir_net_close,
- .ndo_start_xmit = stir_hard_xmit,
- .ndo_do_ioctl = stir_net_ioctl,
-};
-
-/*
- * This routine is called by the USB subsystem for each new device
- * in the system. We need to check if the device is ours, and in
- * this case start handling it.
- * Note : it might be worth protecting this function by a global
- * spinlock... Or not, because maybe USB already deal with that...
- */
-static int stir_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct stir_cb *stir = NULL;
- struct net_device *net;
- int ret = -ENOMEM;
-
- /* Allocate network device container. */
- net = alloc_irdadev(sizeof(*stir));
- if(!net)
- goto err_out1;
-
- SET_NETDEV_DEV(net, &intf->dev);
- stir = netdev_priv(net);
- stir->netdev = net;
- stir->usbdev = dev;
-
- ret = usb_reset_configuration(dev);
- if (ret != 0) {
- dev_err(&intf->dev, "usb reset configuration failed\n");
- goto err_out2;
- }
-
- printk(KERN_INFO "SigmaTel STIr4200 IRDA/USB found at address %d, "
- "Vendor: %x, Product: %x\n",
- dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct));
-
- /* Initialize QoS for this device */
- irda_init_max_qos_capabilies(&stir->qos);
-
- /* That's the Rx capability. */
- stir->qos.baud_rate.bits &= IR_2400 | IR_9600 | IR_19200 |
- IR_38400 | IR_57600 | IR_115200 |
- (IR_4000000 << 8);
- stir->qos.min_turn_time.bits &= qos_mtt_bits;
- irda_qos_bits_to_value(&stir->qos);
-
- /* Override the network functions we need to use */
- net->netdev_ops = &stir_netdev_ops;
-
- ret = register_netdev(net);
- if (ret != 0)
- goto err_out2;
-
- dev_info(&intf->dev, "IrDA: Registered SigmaTel device %s\n",
- net->name);
-
- usb_set_intfdata(intf, stir);
-
- return 0;
-
-err_out2:
- free_netdev(net);
-err_out1:
- return ret;
-}
-
-/*
- * The current device is removed, the USB layer tell us to shut it down...
- */
-static void stir_disconnect(struct usb_interface *intf)
-{
- struct stir_cb *stir = usb_get_intfdata(intf);
-
- if (!stir)
- return;
-
- unregister_netdev(stir->netdev);
- free_netdev(stir->netdev);
-
- usb_set_intfdata(intf, NULL);
-}
-
-#ifdef CONFIG_PM
-/* USB suspend, so power off the transmitter/receiver */
-static int stir_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct stir_cb *stir = usb_get_intfdata(intf);
-
- netif_device_detach(stir->netdev);
- return 0;
-}
-
-/* Coming out of suspend, so reset hardware */
-static int stir_resume(struct usb_interface *intf)
-{
- struct stir_cb *stir = usb_get_intfdata(intf);
-
- netif_device_attach(stir->netdev);
-
- /* receiver restarted when send thread wakes up */
- return 0;
-}
-#endif
-
-/*
- * USB device callbacks
- */
-static struct usb_driver irda_driver = {
- .name = "stir4200",
- .probe = stir_probe,
- .disconnect = stir_disconnect,
- .id_table = dongles,
-#ifdef CONFIG_PM
- .suspend = stir_suspend,
- .resume = stir_resume,
-#endif
-};
-
-module_usb_driver(irda_driver);
diff --git a/drivers/staging/irda/drivers/tekram-sir.c b/drivers/staging/irda/drivers/tekram-sir.c
deleted file mode 100644
index 9dcf0c103b9d..000000000000
--- a/drivers/staging/irda/drivers/tekram-sir.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/*********************************************************************
- *
- * Filename: tekram.c
- * Version: 1.3
- * Description: Implementation of the Tekram IrMate IR-210B dongle
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Wed Oct 21 20:02:35 1998
- * Modified at: Sun Oct 27 22:02:38 2002
- * Modified by: Martin Diehl <mad@mdiehl.de>
- *
- * Copyright (c) 1998-1999 Dag Brattli,
- * Copyright (c) 2002 Martin Diehl,
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-
-#include "sir-dev.h"
-
-static int tekram_delay = 150; /* default is 150 ms */
-module_param(tekram_delay, int, 0);
-MODULE_PARM_DESC(tekram_delay, "tekram dongle write complete delay");
-
-static int tekram_open(struct sir_dev *);
-static int tekram_close(struct sir_dev *);
-static int tekram_change_speed(struct sir_dev *, unsigned);
-static int tekram_reset(struct sir_dev *);
-
-#define TEKRAM_115200 0x00
-#define TEKRAM_57600 0x01
-#define TEKRAM_38400 0x02
-#define TEKRAM_19200 0x03
-#define TEKRAM_9600 0x04
-
-#define TEKRAM_PW 0x10 /* Pulse select bit */
-
-static struct dongle_driver tekram = {
- .owner = THIS_MODULE,
- .driver_name = "Tekram IR-210B",
- .type = IRDA_TEKRAM_DONGLE,
- .open = tekram_open,
- .close = tekram_close,
- .reset = tekram_reset,
- .set_speed = tekram_change_speed,
-};
-
-static int __init tekram_sir_init(void)
-{
- if (tekram_delay < 1 || tekram_delay > 500)
- tekram_delay = 200;
- pr_debug("%s - using %d ms delay\n",
- tekram.driver_name, tekram_delay);
- return irda_register_dongle(&tekram);
-}
-
-static void __exit tekram_sir_cleanup(void)
-{
- irda_unregister_dongle(&tekram);
-}
-
-static int tekram_open(struct sir_dev *dev)
-{
- struct qos_info *qos = &dev->qos;
-
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
- qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */
- irda_qos_bits_to_value(qos);
-
- /* irda thread waits 50 msec for power settling */
-
- return 0;
-}
-
-static int tekram_close(struct sir_dev *dev)
-{
- /* Power off dongle */
- sirdev_set_dtr_rts(dev, FALSE, FALSE);
-
- return 0;
-}
-
-/*
- * Function tekram_change_speed (dev, state, speed)
- *
- * Set the speed for the Tekram IRMate 210 type dongle. Warning, this
- * function must be called with a process context!
- *
- * Algorithm
- * 1. clear DTR
- * 2. set RTS, and wait at least 7 us
- * 3. send Control Byte to the IR-210 through TXD to set new baud rate
- * wait until the stop bit of Control Byte is sent (for 9600 baud rate,
- * it takes about 100 msec)
- *
- * [oops, why 100 msec? sending 1 byte (10 bits) takes 1.05 msec
- * - is this probably to compensate for delays in tty layer?]
- *
- * 5. clear RTS (return to NORMAL Operation)
- * 6. wait at least 50 us, new setting (baud rate, etc) takes effect here
- * after
- */
-
-#define TEKRAM_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1)
-
-static int tekram_change_speed(struct sir_dev *dev, unsigned speed)
-{
- unsigned state = dev->fsm.substate;
- unsigned delay = 0;
- u8 byte;
- static int ret = 0;
-
- switch(state) {
- case SIRDEV_STATE_DONGLE_SPEED:
-
- switch (speed) {
- default:
- speed = 9600;
- ret = -EINVAL;
- /* fall thru */
- case 9600:
- byte = TEKRAM_PW|TEKRAM_9600;
- break;
- case 19200:
- byte = TEKRAM_PW|TEKRAM_19200;
- break;
- case 38400:
- byte = TEKRAM_PW|TEKRAM_38400;
- break;
- case 57600:
- byte = TEKRAM_PW|TEKRAM_57600;
- break;
- case 115200:
- byte = TEKRAM_115200;
- break;
- }
-
- /* Set DTR, Clear RTS */
- sirdev_set_dtr_rts(dev, TRUE, FALSE);
-
- /* Wait at least 7us */
- udelay(14);
-
- /* Write control byte */
- sirdev_raw_write(dev, &byte, 1);
-
- dev->speed = speed;
-
- state = TEKRAM_STATE_WAIT_SPEED;
- delay = tekram_delay;
- break;
-
- case TEKRAM_STATE_WAIT_SPEED:
- /* Set DTR, Set RTS */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
- udelay(50);
- break;
-
- default:
- net_err_ratelimited("%s - undefined state %d\n",
- __func__, state);
- ret = -EINVAL;
- break;
- }
-
- dev->fsm.substate = state;
- return (delay > 0) ? delay : ret;
-}
-
-/*
- * Function tekram_reset (driver)
- *
- * This function resets the tekram dongle. Warning, this function
- * must be called with a process context!!
- *
- * Algorithm:
- * 0. Clear RTS and DTR, and wait 50 ms (power off the IR-210 )
- * 1. clear RTS
- * 2. set DTR, and wait at least 1 ms
- * 3. clear DTR to SPACE state, wait at least 50 us for further
- * operation
- */
-
-static int tekram_reset(struct sir_dev *dev)
-{
- /* Clear DTR, Set RTS */
- sirdev_set_dtr_rts(dev, FALSE, TRUE);
-
- /* Should sleep 1 ms */
- msleep(1);
-
- /* Set DTR, Set RTS */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- /* Wait at least 50 us */
- udelay(75);
-
- dev->speed = 9600;
-
- return 0;
-}
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-0"); /* IRDA_TEKRAM_DONGLE */
-
-module_init(tekram_sir_init);
-module_exit(tekram_sir_cleanup);
diff --git a/drivers/staging/irda/drivers/toim3232-sir.c b/drivers/staging/irda/drivers/toim3232-sir.c
deleted file mode 100644
index b977d6d33e74..000000000000
--- a/drivers/staging/irda/drivers/toim3232-sir.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*********************************************************************
- *
- * Filename: toim3232-sir.c
- * Version: 1.0
- * Description: Implementation of dongles based on the Vishay/Temic
- * TOIM3232 SIR Endec chipset. Currently only the
- * IRWave IR320ST-2 is tested, although it should work
- * with any TOIM3232 or TOIM4232 chipset based RS232
- * dongle with minimal modification.
- * Based heavily on the Tekram driver (tekram.c),
- * with thanks to Dag Brattli and Martin Diehl.
- * Status: Experimental.
- * Author: David Basden <davidb-irda@rcpt.to>
- * Created at: Thu Feb 09 23:47:32 2006
- *
- * Copyright (c) 2006 David Basden.
- * Copyright (c) 1998-1999 Dag Brattli,
- * Copyright (c) 2002 Martin Diehl,
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-/*
- * This driver has currently only been tested on the IRWave IR320ST-2
- *
- * PROTOCOL:
- *
- * The protocol for talking to the TOIM3232 is quite easy, and is
- * designed to interface with RS232 with only level convertors. The
- * BR/~D line on the chip is brought high to signal 'command mode',
- * where a command byte is sent to select the baudrate of the RS232
- * interface and the pulse length of the IRDA output. When BR/~D
- * is brought low, the dongle then changes to the selected baudrate,
- * and the RS232 interface is used for data until BR/~D is brought
- * high again. The initial speed for the TOIMx323 after RESET is
- * 9600 baud. The baudrate for command-mode is the last selected
- * baud-rate, or 9600 after a RESET.
- *
- * The dongle I have (below) adds some extra hardware on the front end,
- * but this is mostly directed towards pariasitic power from the RS232
- * line rather than changing very much about how to communicate with
- * the TOIM3232.
- *
- * The protocol to talk to the TOIM4232 chipset seems to be almost
- * identical to the TOIM3232 (and the 4232 datasheet is more detailed)
- * so this code will probably work on that as well, although I haven't
- * tested it on that hardware.
- *
- * Target dongle variations that might be common:
- *
- * DTR and RTS function:
- * The data sheet for the 4232 has a sample implementation that hooks the
- * DTR and RTS lines to the RESET and BaudRate/~Data lines of the
- * chip (through line-converters). Given both DTR and RTS would have to
- * be held low in normal operation, and the TOIMx232 requires +5V to
- * signal ground, most dongle designers would almost certainly choose
- * an implementation that kept at least one of DTR or RTS high in
- * normal operation to provide power to the dongle, but will likely
- * vary between designs.
- *
- * User specified command bits:
- * There are two user-controllable output lines from the TOIMx232 that
- * can be set low or high by setting the appropriate bits in the
- * high-nibble of the command byte (when setting speed and pulse length).
- * These might be used to switch on and off added hardware or extra
- * dongle features.
- *
- *
- * Target hardware: IRWave IR320ST-2
- *
- * The IRWave IR320ST-2 is a simple dongle based on the Vishay/Temic
- * TOIM3232 SIR Endec and the Vishay/Temic TFDS4500 SIR IRDA transceiver.
- * It uses a hex inverter and some discrete components to buffer and
- * line convert the RS232 down to 5V.
- *
- * The dongle is powered through a voltage regulator, fed by a large
- * capacitor. To switch the dongle on, DTR is brought high to charge
- * the capacitor and drive the voltage regulator. DTR isn't associated
- * with any control lines on the TOIM3232. Parisitic power is also taken
- * from the RTS, TD and RD lines when brought high, but through resistors.
- * When DTR is low, the circuit might lose power even with RTS high.
- *
- * RTS is inverted and attached to the BR/~D input pin. When RTS
- * is high, BR/~D is low, and the TOIM3232 is in the normal 'data' mode.
- * RTS is brought low, BR/~D is high, and the TOIM3232 is in 'command
- * mode'.
- *
- * For some unknown reason, the RESET line isn't actually connected
- * to anything. This means to reset the dongle to get it to a known
- * state (9600 baud) you must drop DTR and RTS low, wait for the power
- * capacitor to discharge, and then bring DTR (and RTS for data mode)
- * high again, and wait for the capacitor to charge, the power supply
- * to stabilise, and the oscillator clock to stabilise.
- *
- * Fortunately, if the current baudrate is known, the chipset can
- * easily change speed by entering command mode without having to
- * reset the dongle first.
- *
- * Major Components:
- *
- * - Vishay/Temic TOIM3232 SIR Endec to change RS232 pulse timings
- * to IRDA pulse timings
- * - 3.6864MHz crystal to drive TOIM3232 clock oscillator
- * - DM74lS04M Inverting Hex line buffer for RS232 input buffering
- * and level conversion
- * - PJ2951AC 150mA voltage regulator
- * - Vishay/Temic TFDS4500 SIR IRDA front-end transceiver
- *
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-
-#include <net/irda/irda.h>
-
-#include "sir-dev.h"
-
-static int toim3232delay = 150; /* default is 150 ms */
-module_param(toim3232delay, int, 0);
-MODULE_PARM_DESC(toim3232delay, "toim3232 dongle write complete delay");
-
-static int toim3232_open(struct sir_dev *);
-static int toim3232_close(struct sir_dev *);
-static int toim3232_change_speed(struct sir_dev *, unsigned);
-static int toim3232_reset(struct sir_dev *);
-
-#define TOIM3232_115200 0x00
-#define TOIM3232_57600 0x01
-#define TOIM3232_38400 0x02
-#define TOIM3232_19200 0x03
-#define TOIM3232_9600 0x06
-#define TOIM3232_2400 0x0A
-
-#define TOIM3232_PW 0x10 /* Pulse select bit */
-
-static struct dongle_driver toim3232 = {
- .owner = THIS_MODULE,
- .driver_name = "Vishay TOIM3232",
- .type = IRDA_TOIM3232_DONGLE,
- .open = toim3232_open,
- .close = toim3232_close,
- .reset = toim3232_reset,
- .set_speed = toim3232_change_speed,
-};
-
-static int __init toim3232_sir_init(void)
-{
- if (toim3232delay < 1 || toim3232delay > 500)
- toim3232delay = 200;
- pr_debug("%s - using %d ms delay\n",
- toim3232.driver_name, toim3232delay);
- return irda_register_dongle(&toim3232);
-}
-
-static void __exit toim3232_sir_cleanup(void)
-{
- irda_unregister_dongle(&toim3232);
-}
-
-static int toim3232_open(struct sir_dev *dev)
-{
- struct qos_info *qos = &dev->qos;
-
- /* Pull the lines high to start with.
- *
- * For the IR320ST-2, we need to charge the main supply capacitor to
- * switch the device on. We keep DTR high throughout to do this.
- * When RTS, TD and RD are high, they will also trickle-charge the
- * cap. RTS is high for data transmission, and low for baud rate select.
- * -- DGB
- */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- /* The TOI3232 supports many speeds between 1200bps and 115000bps.
- * We really only care about those supported by the IRDA spec, but
- * 38400 seems to be implemented in many places */
- qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
-
- /* From the tekram driver. Not sure what a reasonable value is -- DGB */
- qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */
- irda_qos_bits_to_value(qos);
-
- /* irda thread waits 50 msec for power settling */
-
- return 0;
-}
-
-static int toim3232_close(struct sir_dev *dev)
-{
- /* Power off dongle */
- sirdev_set_dtr_rts(dev, FALSE, FALSE);
-
- return 0;
-}
-
-/*
- * Function toim3232change_speed (dev, state, speed)
- *
- * Set the speed for the TOIM3232 based dongle. Warning, this
- * function must be called with a process context!
- *
- * Algorithm
- * 1. keep DTR high but clear RTS to bring into baud programming mode
- * 2. wait at least 7us to enter programming mode
- * 3. send control word to set baud rate and timing
- * 4. wait at least 1us
- * 5. bring RTS high to enter DATA mode (RS232 is passed through to transceiver)
- * 6. should take effect immediately (although probably worth waiting)
- */
-
-#define TOIM3232_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1)
-
-static int toim3232_change_speed(struct sir_dev *dev, unsigned speed)
-{
- unsigned state = dev->fsm.substate;
- unsigned delay = 0;
- u8 byte;
- static int ret = 0;
-
- switch(state) {
- case SIRDEV_STATE_DONGLE_SPEED:
-
- /* Figure out what we are going to send as a control byte */
- switch (speed) {
- case 2400:
- byte = TOIM3232_PW|TOIM3232_2400;
- break;
- default:
- speed = 9600;
- ret = -EINVAL;
- /* fall thru */
- case 9600:
- byte = TOIM3232_PW|TOIM3232_9600;
- break;
- case 19200:
- byte = TOIM3232_PW|TOIM3232_19200;
- break;
- case 38400:
- byte = TOIM3232_PW|TOIM3232_38400;
- break;
- case 57600:
- byte = TOIM3232_PW|TOIM3232_57600;
- break;
- case 115200:
- byte = TOIM3232_115200;
- break;
- }
-
- /* Set DTR, Clear RTS: Go into baud programming mode */
- sirdev_set_dtr_rts(dev, TRUE, FALSE);
-
- /* Wait at least 7us */
- udelay(14);
-
- /* Write control byte */
- sirdev_raw_write(dev, &byte, 1);
-
- dev->speed = speed;
-
- state = TOIM3232_STATE_WAIT_SPEED;
- delay = toim3232delay;
- break;
-
- case TOIM3232_STATE_WAIT_SPEED:
- /* Have transmitted control byte * Wait for 'at least 1us' */
- udelay(14);
-
- /* Set DTR, Set RTS: Go into normal data mode */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- /* Wait (TODO: check this is needed) */
- udelay(50);
- break;
-
- default:
- printk(KERN_ERR "%s - undefined state %d\n", __func__, state);
- ret = -EINVAL;
- break;
- }
-
- dev->fsm.substate = state;
- return (delay > 0) ? delay : ret;
-}
-
-/*
- * Function toim3232reset (driver)
- *
- * This function resets the toim3232 dongle. Warning, this function
- * must be called with a process context!!
- *
- * What we should do is:
- * 0. Pull RESET high
- * 1. Wait for at least 7us
- * 2. Pull RESET low
- * 3. Wait for at least 7us
- * 4. Pull BR/~D high
- * 5. Wait for at least 7us
- * 6. Send control byte to set baud rate
- * 7. Wait at least 1us after stop bit
- * 8. Pull BR/~D low
- * 9. Should then be in data mode
- *
- * Because the IR320ST-2 doesn't have the RESET line connected for some reason,
- * we'll have to do something else.
- *
- * The default speed after a RESET is 9600, so lets try just bringing it up in
- * data mode after switching it off, waiting for the supply capacitor to
- * discharge, and then switch it back on. This isn't actually pulling RESET
- * high, but it seems to have the same effect.
- *
- * This behaviour will probably work on dongles that have the RESET line connected,
- * but if not, add a flag for the IR320ST-2, and implment the above-listed proper
- * behaviour.
- *
- * RTS is inverted and then fed to BR/~D, so to put it in programming mode, we
- * need to have pull RTS low
- */
-
-static int toim3232_reset(struct sir_dev *dev)
-{
- /* Switch off both DTR and RTS to switch off dongle */
- sirdev_set_dtr_rts(dev, FALSE, FALSE);
-
- /* Should sleep a while. This might be evil doing it this way.*/
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(50));
-
- /* Set DTR, Set RTS (data mode) */
- sirdev_set_dtr_rts(dev, TRUE, TRUE);
-
- /* Wait at least 10 ms for power to stabilize again */
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(10));
-
- /* Speed should now be 9600 */
- dev->speed = 9600;
-
- return 0;
-}
-
-MODULE_AUTHOR("David Basden <davidb-linux@rcpt.to>");
-MODULE_DESCRIPTION("Vishay/Temic TOIM3232 based dongle driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-12"); /* IRDA_TOIM3232_DONGLE */
-
-module_init(toim3232_sir_init);
-module_exit(toim3232_sir_cleanup);
diff --git a/drivers/staging/irda/drivers/via-ircc.c b/drivers/staging/irda/drivers/via-ircc.c
deleted file mode 100644
index ca4442a9d631..000000000000
--- a/drivers/staging/irda/drivers/via-ircc.c
+++ /dev/null
@@ -1,1593 +0,0 @@
-/********************************************************************
- Filename: via-ircc.c
- Version: 1.0
- Description: Driver for the VIA VT8231/VT8233 IrDA chipsets
- Author: VIA Technologies,inc
- Date : 08/06/2003
-
-Copyright (c) 1998-2003 VIA Technologies, 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, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTIES OR REPRESENTATIONS; 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/>.
-
-F01 Oct/02/02: Modify code for V0.11(move out back to back transfer)
-F02 Oct/28/02: Add SB device ID for 3147 and 3177.
- Comment :
- jul/09/2002 : only implement two kind of dongle currently.
- Oct/02/2002 : work on VT8231 and VT8233 .
- Aug/06/2003 : change driver format to pci driver .
-
-2004-02-16: <sda@bdit.de>
-- Removed unneeded 'legacy' pci stuff.
-- Make sure SIR mode is set (hw_init()) before calling mode-dependent stuff.
-- On speed change from core, don't send SIR frame with new speed.
- Use current speed and change speeds later.
-- Make module-param dongle_id actually work.
-- New dongle_id 17 (0x11): TDFS4500. Single-ended SIR only.
- Tested with home-grown PCB on EPIA boards.
-- Code cleanup.
-
- ********************************************************************/
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/rtnetlink.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-
-#include <linux/pm.h>
-
-#include <net/irda/wrapper.h>
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-
-#include "via-ircc.h"
-
-#define VIA_MODULE_NAME "via-ircc"
-#define CHIP_IO_EXTENT 0x40
-
-static char *driver_name = VIA_MODULE_NAME;
-
-/* Module parameters */
-static int qos_mtt_bits = 0x07; /* 1 ms or more */
-static int dongle_id = 0; /* default: probe */
-
-/* We can't guess the type of connected dongle, user *must* supply it. */
-module_param(dongle_id, int, 0);
-
-/* Some prototypes */
-static int via_ircc_open(struct pci_dev *pdev, chipio_t *info,
- unsigned int id);
-static int via_ircc_dma_receive(struct via_ircc_cb *self);
-static int via_ircc_dma_receive_complete(struct via_ircc_cb *self,
- int iobase);
-static netdev_tx_t via_ircc_hard_xmit_sir(struct sk_buff *skb,
- struct net_device *dev);
-static netdev_tx_t via_ircc_hard_xmit_fir(struct sk_buff *skb,
- struct net_device *dev);
-static void via_hw_init(struct via_ircc_cb *self);
-static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 baud);
-static irqreturn_t via_ircc_interrupt(int irq, void *dev_id);
-static int via_ircc_is_receiving(struct via_ircc_cb *self);
-static int via_ircc_read_dongle_id(int iobase);
-
-static int via_ircc_net_open(struct net_device *dev);
-static int via_ircc_net_close(struct net_device *dev);
-static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq,
- int cmd);
-static void via_ircc_change_dongle_speed(int iobase, int speed,
- int dongle_id);
-static int RxTimerHandler(struct via_ircc_cb *self, int iobase);
-static void hwreset(struct via_ircc_cb *self);
-static int via_ircc_dma_xmit(struct via_ircc_cb *self, u16 iobase);
-static int upload_rxdata(struct via_ircc_cb *self, int iobase);
-static int via_init_one(struct pci_dev *pcidev, const struct pci_device_id *id);
-static void via_remove_one(struct pci_dev *pdev);
-
-/* FIXME : Should use udelay() instead, even if we are x86 only - Jean II */
-static void iodelay(int udelay)
-{
- u8 data;
- int i;
-
- for (i = 0; i < udelay; i++) {
- data = inb(0x80);
- }
-}
-
-static const struct pci_device_id via_pci_tbl[] = {
- { PCI_VENDOR_ID_VIA, 0x8231, PCI_ANY_ID, PCI_ANY_ID,0,0,0 },
- { PCI_VENDOR_ID_VIA, 0x3109, PCI_ANY_ID, PCI_ANY_ID,0,0,1 },
- { PCI_VENDOR_ID_VIA, 0x3074, PCI_ANY_ID, PCI_ANY_ID,0,0,2 },
- { PCI_VENDOR_ID_VIA, 0x3147, PCI_ANY_ID, PCI_ANY_ID,0,0,3 },
- { PCI_VENDOR_ID_VIA, 0x3177, PCI_ANY_ID, PCI_ANY_ID,0,0,4 },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci,via_pci_tbl);
-
-
-static struct pci_driver via_driver = {
- .name = VIA_MODULE_NAME,
- .id_table = via_pci_tbl,
- .probe = via_init_one,
- .remove = via_remove_one,
-};
-
-
-/*
- * Function via_ircc_init ()
- *
- * Initialize chip. Just find out chip type and resource.
- */
-static int __init via_ircc_init(void)
-{
- int rc;
-
- rc = pci_register_driver(&via_driver);
- if (rc < 0) {
- pr_debug("%s(): error rc = %d, returning -ENODEV...\n",
- __func__, rc);
- return -ENODEV;
- }
- return 0;
-}
-
-static int via_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
-{
- int rc;
- u8 temp,oldPCI_40,oldPCI_44,bTmp,bTmp1;
- u16 Chipset,FirDRQ1,FirDRQ0,FirIRQ,FirIOBase;
- chipio_t info;
-
- pr_debug("%s(): Device ID=(0X%X)\n", __func__, id->device);
-
- rc = pci_enable_device (pcidev);
- if (rc) {
- pr_debug("%s(): error rc = %d\n", __func__, rc);
- return -ENODEV;
- }
-
- // South Bridge exist
- if ( ReadLPCReg(0x20) != 0x3C )
- Chipset=0x3096;
- else
- Chipset=0x3076;
-
- if (Chipset==0x3076) {
- pr_debug("%s(): Chipset = 3076\n", __func__);
-
- WriteLPCReg(7,0x0c );
- temp=ReadLPCReg(0x30);//check if BIOS Enable Fir
- if((temp&0x01)==1) { // BIOS close or no FIR
- WriteLPCReg(0x1d, 0x82 );
- WriteLPCReg(0x23,0x18);
- temp=ReadLPCReg(0xF0);
- if((temp&0x01)==0) {
- temp=(ReadLPCReg(0x74)&0x03); //DMA
- FirDRQ0=temp + 4;
- temp=(ReadLPCReg(0x74)&0x0C) >> 2;
- FirDRQ1=temp + 4;
- } else {
- temp=(ReadLPCReg(0x74)&0x0C) >> 2; //DMA
- FirDRQ0=temp + 4;
- FirDRQ1=FirDRQ0;
- }
- FirIRQ=(ReadLPCReg(0x70)&0x0f); //IRQ
- FirIOBase=ReadLPCReg(0x60 ) << 8; //IO Space :high byte
- FirIOBase=FirIOBase| ReadLPCReg(0x61) ; //low byte
- FirIOBase=FirIOBase ;
- info.fir_base=FirIOBase;
- info.irq=FirIRQ;
- info.dma=FirDRQ1;
- info.dma2=FirDRQ0;
- pci_read_config_byte(pcidev,0x40,&bTmp);
- pci_write_config_byte(pcidev,0x40,((bTmp | 0x08) & 0xfe));
- pci_read_config_byte(pcidev,0x42,&bTmp);
- pci_write_config_byte(pcidev,0x42,(bTmp | 0xf0));
- pci_write_config_byte(pcidev,0x5a,0xc0);
- WriteLPCReg(0x28, 0x70 );
- rc = via_ircc_open(pcidev, &info, 0x3076);
- } else
- rc = -ENODEV; //IR not turn on
- } else { //Not VT1211
- pr_debug("%s(): Chipset = 3096\n", __func__);
-
- pci_read_config_byte(pcidev,0x67,&bTmp);//check if BIOS Enable Fir
- if((bTmp&0x01)==1) { // BIOS enable FIR
- //Enable Double DMA clock
- pci_read_config_byte(pcidev,0x42,&oldPCI_40);
- pci_write_config_byte(pcidev,0x42,oldPCI_40 | 0x80);
- pci_read_config_byte(pcidev,0x40,&oldPCI_40);
- pci_write_config_byte(pcidev,0x40,oldPCI_40 & 0xf7);
- pci_read_config_byte(pcidev,0x44,&oldPCI_44);
- pci_write_config_byte(pcidev,0x44,0x4e);
- //---------- read configuration from Function0 of south bridge
- if((bTmp&0x02)==0) {
- pci_read_config_byte(pcidev,0x44,&bTmp1); //DMA
- FirDRQ0 = (bTmp1 & 0x30) >> 4;
- pci_read_config_byte(pcidev,0x44,&bTmp1);
- FirDRQ1 = (bTmp1 & 0xc0) >> 6;
- } else {
- pci_read_config_byte(pcidev,0x44,&bTmp1); //DMA
- FirDRQ0 = (bTmp1 & 0x30) >> 4 ;
- FirDRQ1=0;
- }
- pci_read_config_byte(pcidev,0x47,&bTmp1); //IRQ
- FirIRQ = bTmp1 & 0x0f;
-
- pci_read_config_byte(pcidev,0x69,&bTmp);
- FirIOBase = bTmp << 8;//hight byte
- pci_read_config_byte(pcidev,0x68,&bTmp);
- FirIOBase = (FirIOBase | bTmp ) & 0xfff0;
- //-------------------------
- info.fir_base=FirIOBase;
- info.irq=FirIRQ;
- info.dma=FirDRQ1;
- info.dma2=FirDRQ0;
- rc = via_ircc_open(pcidev, &info, 0x3096);
- } else
- rc = -ENODEV; //IR not turn on !!!!!
- }//Not VT1211
-
- pr_debug("%s(): End - rc = %d\n", __func__, rc);
- return rc;
-}
-
-static void __exit via_ircc_cleanup(void)
-{
- /* Cleanup all instances of the driver */
- pci_unregister_driver (&via_driver);
-}
-
-static const struct net_device_ops via_ircc_sir_ops = {
- .ndo_start_xmit = via_ircc_hard_xmit_sir,
- .ndo_open = via_ircc_net_open,
- .ndo_stop = via_ircc_net_close,
- .ndo_do_ioctl = via_ircc_net_ioctl,
-};
-static const struct net_device_ops via_ircc_fir_ops = {
- .ndo_start_xmit = via_ircc_hard_xmit_fir,
- .ndo_open = via_ircc_net_open,
- .ndo_stop = via_ircc_net_close,
- .ndo_do_ioctl = via_ircc_net_ioctl,
-};
-
-/*
- * Function via_ircc_open(pdev, iobase, irq)
- *
- * Open driver instance
- *
- */
-static int via_ircc_open(struct pci_dev *pdev, chipio_t *info, unsigned int id)
-{
- struct net_device *dev;
- struct via_ircc_cb *self;
- int err;
-
- /* Allocate new instance of the driver */
- dev = alloc_irdadev(sizeof(struct via_ircc_cb));
- if (dev == NULL)
- return -ENOMEM;
-
- self = netdev_priv(dev);
- self->netdev = dev;
- spin_lock_init(&self->lock);
-
- pci_set_drvdata(pdev, self);
-
- /* Initialize Resource */
- self->io.cfg_base = info->cfg_base;
- self->io.fir_base = info->fir_base;
- self->io.irq = info->irq;
- self->io.fir_ext = CHIP_IO_EXTENT;
- self->io.dma = info->dma;
- self->io.dma2 = info->dma2;
- self->io.fifo_size = 32;
- self->chip_id = id;
- self->st_fifo.len = 0;
- self->RxDataReady = 0;
-
- /* Reserve the ioports that we need */
- if (!request_region(self->io.fir_base, self->io.fir_ext, driver_name)) {
- pr_debug("%s(), can't get iobase of 0x%03x\n",
- __func__, self->io.fir_base);
- err = -ENODEV;
- goto err_out1;
- }
-
- /* Initialize QoS for this device */
- irda_init_max_qos_capabilies(&self->qos);
-
- /* Check if user has supplied the dongle id or not */
- if (!dongle_id)
- dongle_id = via_ircc_read_dongle_id(self->io.fir_base);
- self->io.dongle_id = dongle_id;
-
- /* The only value we must override it the baudrate */
- /* Maximum speeds and capabilities are dongle-dependent. */
- switch( self->io.dongle_id ){
- case 0x0d:
- self->qos.baud_rate.bits =
- IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200 |
- IR_576000 | IR_1152000 | (IR_4000000 << 8);
- break;
- default:
- self->qos.baud_rate.bits =
- IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200;
- break;
- }
-
- /* Following was used for testing:
- *
- * self->qos.baud_rate.bits = IR_9600;
- *
- * Is is no good, as it prohibits (error-prone) speed-changes.
- */
-
- self->qos.min_turn_time.bits = qos_mtt_bits;
- irda_qos_bits_to_value(&self->qos);
-
- /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
- self->rx_buff.truesize = 14384 + 2048;
- self->tx_buff.truesize = 14384 + 2048;
-
- /* Allocate memory if needed */
- self->rx_buff.head =
- dma_zalloc_coherent(&pdev->dev, self->rx_buff.truesize,
- &self->rx_buff_dma, GFP_KERNEL);
- if (self->rx_buff.head == NULL) {
- err = -ENOMEM;
- goto err_out2;
- }
-
- self->tx_buff.head =
- dma_zalloc_coherent(&pdev->dev, self->tx_buff.truesize,
- &self->tx_buff_dma, GFP_KERNEL);
- if (self->tx_buff.head == NULL) {
- err = -ENOMEM;
- goto err_out3;
- }
-
- self->rx_buff.in_frame = FALSE;
- self->rx_buff.state = OUTSIDE_FRAME;
- self->tx_buff.data = self->tx_buff.head;
- self->rx_buff.data = self->rx_buff.head;
-
- /* Reset Tx queue info */
- self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
- self->tx_fifo.tail = self->tx_buff.head;
-
- /* Override the network functions we need to use */
- dev->netdev_ops = &via_ircc_sir_ops;
-
- err = register_netdev(dev);
- if (err)
- goto err_out4;
-
- net_info_ratelimited("IrDA: Registered device %s (via-ircc)\n",
- dev->name);
-
- /* Initialise the hardware..
- */
- self->io.speed = 9600;
- via_hw_init(self);
- return 0;
- err_out4:
- dma_free_coherent(&pdev->dev, self->tx_buff.truesize,
- self->tx_buff.head, self->tx_buff_dma);
- err_out3:
- dma_free_coherent(&pdev->dev, self->rx_buff.truesize,
- self->rx_buff.head, self->rx_buff_dma);
- err_out2:
- release_region(self->io.fir_base, self->io.fir_ext);
- err_out1:
- free_netdev(dev);
- return err;
-}
-
-/*
- * Function via_remove_one(pdev)
- *
- * Close driver instance
- *
- */
-static void via_remove_one(struct pci_dev *pdev)
-{
- struct via_ircc_cb *self = pci_get_drvdata(pdev);
- int iobase;
-
- iobase = self->io.fir_base;
-
- ResetChip(iobase, 5); //hardware reset.
- /* Remove netdevice */
- unregister_netdev(self->netdev);
-
- /* Release the PORT that this driver is using */
- pr_debug("%s(), Releasing Region %03x\n",
- __func__, self->io.fir_base);
- release_region(self->io.fir_base, self->io.fir_ext);
- if (self->tx_buff.head)
- dma_free_coherent(&pdev->dev, self->tx_buff.truesize,
- self->tx_buff.head, self->tx_buff_dma);
- if (self->rx_buff.head)
- dma_free_coherent(&pdev->dev, self->rx_buff.truesize,
- self->rx_buff.head, self->rx_buff_dma);
-
- free_netdev(self->netdev);
-
- pci_disable_device(pdev);
-}
-
-/*
- * Function via_hw_init(self)
- *
- * Returns non-negative on success.
- *
- * Formerly via_ircc_setup
- */
-static void via_hw_init(struct via_ircc_cb *self)
-{
- int iobase = self->io.fir_base;
-
- SetMaxRxPacketSize(iobase, 0x0fff); //set to max:4095
- // FIFO Init
- EnRXFIFOReadyInt(iobase, OFF);
- EnRXFIFOHalfLevelInt(iobase, OFF);
- EnTXFIFOHalfLevelInt(iobase, OFF);
- EnTXFIFOUnderrunEOMInt(iobase, ON);
- EnTXFIFOReadyInt(iobase, OFF);
- InvertTX(iobase, OFF);
- InvertRX(iobase, OFF);
-
- if (ReadLPCReg(0x20) == 0x3c)
- WriteLPCReg(0xF0, 0); // for VT1211
- /* Int Init */
- EnRXSpecInt(iobase, ON);
-
- /* The following is basically hwreset */
- /* If this is the case, why not just call hwreset() ? Jean II */
- ResetChip(iobase, 5);
- EnableDMA(iobase, OFF);
- EnableTX(iobase, OFF);
- EnableRX(iobase, OFF);
- EnRXDMA(iobase, OFF);
- EnTXDMA(iobase, OFF);
- RXStart(iobase, OFF);
- TXStart(iobase, OFF);
- InitCard(iobase);
- CommonInit(iobase);
- SIRFilter(iobase, ON);
- SetSIR(iobase, ON);
- CRC16(iobase, ON);
- EnTXCRC(iobase, 0);
- WriteReg(iobase, I_ST_CT_0, 0x00);
- SetBaudRate(iobase, 9600);
- SetPulseWidth(iobase, 12);
- SetSendPreambleCount(iobase, 0);
-
- self->io.speed = 9600;
- self->st_fifo.len = 0;
-
- via_ircc_change_dongle_speed(iobase, self->io.speed,
- self->io.dongle_id);
-
- WriteReg(iobase, I_ST_CT_0, 0x80);
-}
-
-/*
- * Function via_ircc_read_dongle_id (void)
- *
- */
-static int via_ircc_read_dongle_id(int iobase)
-{
- net_err_ratelimited("via-ircc: dongle probing not supported, please specify dongle_id module parameter\n");
- return 9; /* Default to IBM */
-}
-
-/*
- * Function via_ircc_change_dongle_speed (iobase, speed, dongle_id)
- * Change speed of the attach dongle
- * only implement two type of dongle currently.
- */
-static void via_ircc_change_dongle_speed(int iobase, int speed,
- int dongle_id)
-{
- u8 mode = 0;
-
- /* speed is unused, as we use IsSIROn()/IsMIROn() */
- speed = speed;
-
- pr_debug("%s(): change_dongle_speed to %d for 0x%x, %d\n",
- __func__, speed, iobase, dongle_id);
-
- switch (dongle_id) {
-
- /* Note: The dongle_id's listed here are derived from
- * nsc-ircc.c */
-
- case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
- UseOneRX(iobase, ON); // use one RX pin RX1,RX2
- InvertTX(iobase, OFF);
- InvertRX(iobase, OFF);
-
- EnRX2(iobase, ON); //sir to rx2
- EnGPIOtoRX2(iobase, OFF);
-
- if (IsSIROn(iobase)) { //sir
- // Mode select Off
- SlowIRRXLowActive(iobase, ON);
- udelay(1000);
- SlowIRRXLowActive(iobase, OFF);
- } else {
- if (IsMIROn(iobase)) { //mir
- // Mode select On
- SlowIRRXLowActive(iobase, OFF);
- udelay(20);
- } else { // fir
- if (IsFIROn(iobase)) { //fir
- // Mode select On
- SlowIRRXLowActive(iobase, OFF);
- udelay(20);
- }
- }
- }
- break;
-
- case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
- UseOneRX(iobase, ON); //use ONE RX....RX1
- InvertTX(iobase, OFF);
- InvertRX(iobase, OFF); // invert RX pin
-
- EnRX2(iobase, ON);
- EnGPIOtoRX2(iobase, OFF);
- if (IsSIROn(iobase)) { //sir
- // Mode select On
- SlowIRRXLowActive(iobase, ON);
- udelay(20);
- // Mode select Off
- SlowIRRXLowActive(iobase, OFF);
- }
- if (IsMIROn(iobase)) { //mir
- // Mode select On
- SlowIRRXLowActive(iobase, OFF);
- udelay(20);
- // Mode select Off
- SlowIRRXLowActive(iobase, ON);
- } else { // fir
- if (IsFIROn(iobase)) { //fir
- // Mode select On
- SlowIRRXLowActive(iobase, OFF);
- // TX On
- WriteTX(iobase, ON);
- udelay(20);
- // Mode select OFF
- SlowIRRXLowActive(iobase, ON);
- udelay(20);
- // TX Off
- WriteTX(iobase, OFF);
- }
- }
- break;
-
- case 0x0d:
- UseOneRX(iobase, OFF); // use two RX pin RX1,RX2
- InvertTX(iobase, OFF);
- InvertRX(iobase, OFF);
- SlowIRRXLowActive(iobase, OFF);
- if (IsSIROn(iobase)) { //sir
- EnGPIOtoRX2(iobase, OFF);
- WriteGIO(iobase, OFF);
- EnRX2(iobase, OFF); //sir to rx2
- } else { // fir mir
- EnGPIOtoRX2(iobase, OFF);
- WriteGIO(iobase, OFF);
- EnRX2(iobase, OFF); //fir to rx
- }
- break;
-
- case 0x11: /* Temic TFDS4500 */
-
- pr_debug("%s: Temic TFDS4500: One RX pin, TX normal, RX inverted\n",
- __func__);
-
- UseOneRX(iobase, ON); //use ONE RX....RX1
- InvertTX(iobase, OFF);
- InvertRX(iobase, ON); // invert RX pin
-
- EnRX2(iobase, ON); //sir to rx2
- EnGPIOtoRX2(iobase, OFF);
-
- if( IsSIROn(iobase) ){ //sir
-
- // Mode select On
- SlowIRRXLowActive(iobase, ON);
- udelay(20);
- // Mode select Off
- SlowIRRXLowActive(iobase, OFF);
-
- } else{
- pr_debug("%s: Warning: TFDS4500 not running in SIR mode !\n",
- __func__);
- }
- break;
-
- case 0x0ff: /* Vishay */
- if (IsSIROn(iobase))
- mode = 0;
- else if (IsMIROn(iobase))
- mode = 1;
- else if (IsFIROn(iobase))
- mode = 2;
- else if (IsVFIROn(iobase))
- mode = 5; //VFIR-16
- SI_SetMode(iobase, mode);
- break;
-
- default:
- net_err_ratelimited("%s: Error: dongle_id %d unsupported !\n",
- __func__, dongle_id);
- }
-}
-
-/*
- * Function via_ircc_change_speed (self, baud)
- *
- * Change the speed of the device
- *
- */
-static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 speed)
-{
- struct net_device *dev = self->netdev;
- u16 iobase;
- u8 value = 0, bTmp;
-
- iobase = self->io.fir_base;
- /* Update accounting for new speed */
- self->io.speed = speed;
- pr_debug("%s: change_speed to %d bps.\n", __func__, speed);
-
- WriteReg(iobase, I_ST_CT_0, 0x0);
-
- /* Controller mode sellection */
- switch (speed) {
- case 2400:
- case 9600:
- case 19200:
- case 38400:
- case 57600:
- case 115200:
- value = (115200/speed)-1;
- SetSIR(iobase, ON);
- CRC16(iobase, ON);
- break;
- case 576000:
- /* FIXME: this can't be right, as it's the same as 115200,
- * and 576000 is MIR, not SIR. */
- value = 0;
- SetSIR(iobase, ON);
- CRC16(iobase, ON);
- break;
- case 1152000:
- value = 0;
- SetMIR(iobase, ON);
- /* FIXME: CRC ??? */
- break;
- case 4000000:
- value = 0;
- SetFIR(iobase, ON);
- SetPulseWidth(iobase, 0);
- SetSendPreambleCount(iobase, 14);
- CRC16(iobase, OFF);
- EnTXCRC(iobase, ON);
- break;
- case 16000000:
- value = 0;
- SetVFIR(iobase, ON);
- /* FIXME: CRC ??? */
- break;
- default:
- value = 0;
- break;
- }
-
- /* Set baudrate to 0x19[2..7] */
- bTmp = (ReadReg(iobase, I_CF_H_1) & 0x03);
- bTmp |= value << 2;
- WriteReg(iobase, I_CF_H_1, bTmp);
-
- /* Some dongles may need to be informed about speed changes. */
- via_ircc_change_dongle_speed(iobase, speed, self->io.dongle_id);
-
- /* Set FIFO size to 64 */
- SetFIFO(iobase, 64);
-
- /* Enable IR */
- WriteReg(iobase, I_ST_CT_0, 0x80);
-
- // EnTXFIFOHalfLevelInt(iobase,ON);
-
- /* Enable some interrupts so we can receive frames */
- //EnAllInt(iobase,ON);
-
- if (IsSIROn(iobase)) {
- SIRFilter(iobase, ON);
- SIRRecvAny(iobase, ON);
- } else {
- SIRFilter(iobase, OFF);
- SIRRecvAny(iobase, OFF);
- }
-
- if (speed > 115200) {
- /* Install FIR xmit handler */
- dev->netdev_ops = &via_ircc_fir_ops;
- via_ircc_dma_receive(self);
- } else {
- /* Install SIR xmit handler */
- dev->netdev_ops = &via_ircc_sir_ops;
- }
- netif_wake_queue(dev);
-}
-
-/*
- * Function via_ircc_hard_xmit (skb, dev)
- *
- * Transmit the frame!
- *
- */
-static netdev_tx_t via_ircc_hard_xmit_sir(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct via_ircc_cb *self;
- unsigned long flags;
- u16 iobase;
- __u32 speed;
-
- self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
- iobase = self->io.fir_base;
-
- netif_stop_queue(dev);
- /* Check if we need to change the speed */
- speed = irda_get_next_speed(skb);
- if ((speed != self->io.speed) && (speed != -1)) {
- /* Check for empty frame */
- if (!skb->len) {
- via_ircc_change_speed(self, speed);
- netif_trans_update(dev);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- } else
- self->new_speed = speed;
- }
- InitCard(iobase);
- CommonInit(iobase);
- SIRFilter(iobase, ON);
- SetSIR(iobase, ON);
- CRC16(iobase, ON);
- EnTXCRC(iobase, 0);
- WriteReg(iobase, I_ST_CT_0, 0x00);
-
- spin_lock_irqsave(&self->lock, flags);
- self->tx_buff.data = self->tx_buff.head;
- self->tx_buff.len =
- async_wrap_skb(skb, self->tx_buff.data,
- self->tx_buff.truesize);
-
- dev->stats.tx_bytes += self->tx_buff.len;
- /* Send this frame with old speed */
- SetBaudRate(iobase, self->io.speed);
- SetPulseWidth(iobase, 12);
- SetSendPreambleCount(iobase, 0);
- WriteReg(iobase, I_ST_CT_0, 0x80);
-
- EnableTX(iobase, ON);
- EnableRX(iobase, OFF);
-
- ResetChip(iobase, 0);
- ResetChip(iobase, 1);
- ResetChip(iobase, 2);
- ResetChip(iobase, 3);
- ResetChip(iobase, 4);
-
- EnAllInt(iobase, ON);
- EnTXDMA(iobase, ON);
- EnRXDMA(iobase, OFF);
-
- irda_setup_dma(self->io.dma, self->tx_buff_dma, self->tx_buff.len,
- DMA_TX_MODE);
-
- SetSendByte(iobase, self->tx_buff.len);
- RXStart(iobase, OFF);
- TXStart(iobase, ON);
-
- netif_trans_update(dev);
- spin_unlock_irqrestore(&self->lock, flags);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-static netdev_tx_t via_ircc_hard_xmit_fir(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct via_ircc_cb *self;
- u16 iobase;
- __u32 speed;
- unsigned long flags;
-
- self = netdev_priv(dev);
- iobase = self->io.fir_base;
-
- if (self->st_fifo.len)
- return NETDEV_TX_OK;
- if (self->chip_id == 0x3076)
- iodelay(1500);
- else
- udelay(1500);
- netif_stop_queue(dev);
- speed = irda_get_next_speed(skb);
- if ((speed != self->io.speed) && (speed != -1)) {
- if (!skb->len) {
- via_ircc_change_speed(self, speed);
- netif_trans_update(dev);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- } else
- self->new_speed = speed;
- }
- spin_lock_irqsave(&self->lock, flags);
- self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail;
- self->tx_fifo.queue[self->tx_fifo.free].len = skb->len;
-
- self->tx_fifo.tail += skb->len;
- dev->stats.tx_bytes += skb->len;
- skb_copy_from_linear_data(skb,
- self->tx_fifo.queue[self->tx_fifo.free].start, skb->len);
- self->tx_fifo.len++;
- self->tx_fifo.free++;
-//F01 if (self->tx_fifo.len == 1) {
- via_ircc_dma_xmit(self, iobase);
-//F01 }
-//F01 if (self->tx_fifo.free < (MAX_TX_WINDOW -1 )) netif_wake_queue(self->netdev);
- netif_trans_update(dev);
- dev_kfree_skb(skb);
- spin_unlock_irqrestore(&self->lock, flags);
- return NETDEV_TX_OK;
-
-}
-
-static int via_ircc_dma_xmit(struct via_ircc_cb *self, u16 iobase)
-{
- EnTXDMA(iobase, OFF);
- self->io.direction = IO_XMIT;
- EnPhys(iobase, ON);
- EnableTX(iobase, ON);
- EnableRX(iobase, OFF);
- ResetChip(iobase, 0);
- ResetChip(iobase, 1);
- ResetChip(iobase, 2);
- ResetChip(iobase, 3);
- ResetChip(iobase, 4);
- EnAllInt(iobase, ON);
- EnTXDMA(iobase, ON);
- EnRXDMA(iobase, OFF);
- irda_setup_dma(self->io.dma,
- ((u8 *)self->tx_fifo.queue[self->tx_fifo.ptr].start -
- self->tx_buff.head) + self->tx_buff_dma,
- self->tx_fifo.queue[self->tx_fifo.ptr].len, DMA_TX_MODE);
- pr_debug("%s: tx_fifo.ptr=%x,len=%x,tx_fifo.len=%x..\n",
- __func__, self->tx_fifo.ptr,
- self->tx_fifo.queue[self->tx_fifo.ptr].len,
- self->tx_fifo.len);
-
- SetSendByte(iobase, self->tx_fifo.queue[self->tx_fifo.ptr].len);
- RXStart(iobase, OFF);
- TXStart(iobase, ON);
- return 0;
-
-}
-
-/*
- * Function via_ircc_dma_xmit_complete (self)
- *
- * The transfer of a frame in finished. This function will only be called
- * by the interrupt handler
- *
- */
-static int via_ircc_dma_xmit_complete(struct via_ircc_cb *self)
-{
- int iobase;
- u8 Tx_status;
-
- iobase = self->io.fir_base;
- /* Disable DMA */
-// DisableDmaChannel(self->io.dma);
- /* Check for underrun! */
- /* Clear bit, by writing 1 into it */
- Tx_status = GetTXStatus(iobase);
- if (Tx_status & 0x08) {
- self->netdev->stats.tx_errors++;
- self->netdev->stats.tx_fifo_errors++;
- hwreset(self);
- /* how to clear underrun? */
- } else {
- self->netdev->stats.tx_packets++;
- ResetChip(iobase, 3);
- ResetChip(iobase, 4);
- }
- /* Check if we need to change the speed */
- if (self->new_speed) {
- via_ircc_change_speed(self, self->new_speed);
- self->new_speed = 0;
- }
-
- /* Finished with this frame, so prepare for next */
- if (IsFIROn(iobase)) {
- if (self->tx_fifo.len) {
- self->tx_fifo.len--;
- self->tx_fifo.ptr++;
- }
- }
- pr_debug("%s: tx_fifo.len=%x ,tx_fifo.ptr=%x,tx_fifo.free=%x...\n",
- __func__,
- self->tx_fifo.len, self->tx_fifo.ptr, self->tx_fifo.free);
-/* F01_S
- // Any frames to be sent back-to-back?
- if (self->tx_fifo.len) {
- // Not finished yet!
- via_ircc_dma_xmit(self, iobase);
- ret = FALSE;
- } else {
-F01_E*/
- // Reset Tx FIFO info
- self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
- self->tx_fifo.tail = self->tx_buff.head;
-//F01 }
-
- // Make sure we have room for more frames
-//F01 if (self->tx_fifo.free < (MAX_TX_WINDOW -1 )) {
- // Not busy transmitting anymore
- // Tell the network layer, that we can accept more frames
- netif_wake_queue(self->netdev);
-//F01 }
- return TRUE;
-}
-
-/*
- * Function via_ircc_dma_receive (self)
- *
- * Set configuration for receive a frame.
- *
- */
-static int via_ircc_dma_receive(struct via_ircc_cb *self)
-{
- int iobase;
-
- iobase = self->io.fir_base;
-
- self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
- self->tx_fifo.tail = self->tx_buff.head;
- self->RxDataReady = 0;
- self->io.direction = IO_RECV;
- self->rx_buff.data = self->rx_buff.head;
- self->st_fifo.len = self->st_fifo.pending_bytes = 0;
- self->st_fifo.tail = self->st_fifo.head = 0;
-
- EnPhys(iobase, ON);
- EnableTX(iobase, OFF);
- EnableRX(iobase, ON);
-
- ResetChip(iobase, 0);
- ResetChip(iobase, 1);
- ResetChip(iobase, 2);
- ResetChip(iobase, 3);
- ResetChip(iobase, 4);
-
- EnAllInt(iobase, ON);
- EnTXDMA(iobase, OFF);
- EnRXDMA(iobase, ON);
- irda_setup_dma(self->io.dma2, self->rx_buff_dma,
- self->rx_buff.truesize, DMA_RX_MODE);
- TXStart(iobase, OFF);
- RXStart(iobase, ON);
-
- return 0;
-}
-
-/*
- * Function via_ircc_dma_receive_complete (self)
- *
- * Controller Finished with receiving frames,
- * and this routine is call by ISR
- *
- */
-static int via_ircc_dma_receive_complete(struct via_ircc_cb *self,
- int iobase)
-{
- struct st_fifo *st_fifo;
- struct sk_buff *skb;
- int len, i;
- u8 status = 0;
-
- iobase = self->io.fir_base;
- st_fifo = &self->st_fifo;
-
- if (self->io.speed < 4000000) { //Speed below FIR
- len = GetRecvByte(iobase, self);
- skb = dev_alloc_skb(len + 1);
- if (skb == NULL)
- return FALSE;
- // Make sure IP header gets aligned
- skb_reserve(skb, 1);
- skb_put(skb, len - 2);
- if (self->chip_id == 0x3076) {
- for (i = 0; i < len - 2; i++)
- skb->data[i] = self->rx_buff.data[i * 2];
- } else {
- if (self->chip_id == 0x3096) {
- for (i = 0; i < len - 2; i++)
- skb->data[i] =
- self->rx_buff.data[i];
- }
- }
- // Move to next frame
- self->rx_buff.data += len;
- self->netdev->stats.rx_bytes += len;
- self->netdev->stats.rx_packets++;
- skb->dev = self->netdev;
- skb_reset_mac_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- netif_rx(skb);
- return TRUE;
- }
-
- else { //FIR mode
- len = GetRecvByte(iobase, self);
- if (len == 0)
- return TRUE; //interrupt only, data maybe move by RxT
- if (((len - 4) < 2) || ((len - 4) > 2048)) {
- pr_debug("%s(): Trouble:len=%x,CurCount=%x,LastCount=%x\n",
- __func__, len, RxCurCount(iobase, self),
- self->RxLastCount);
- hwreset(self);
- return FALSE;
- }
- pr_debug("%s(): fifo.len=%x,len=%x,CurCount=%x..\n",
- __func__,
- st_fifo->len, len - 4, RxCurCount(iobase, self));
-
- st_fifo->entries[st_fifo->tail].status = status;
- st_fifo->entries[st_fifo->tail].len = len;
- st_fifo->pending_bytes += len;
- st_fifo->tail++;
- st_fifo->len++;
- if (st_fifo->tail > MAX_RX_WINDOW)
- st_fifo->tail = 0;
- self->RxDataReady = 0;
-
- // It maybe have MAX_RX_WINDOW package receive by
- // receive_complete before Timer IRQ
-/* F01_S
- if (st_fifo->len < (MAX_RX_WINDOW+2 )) {
- RXStart(iobase,ON);
- SetTimer(iobase,4);
- }
- else {
-F01_E */
- EnableRX(iobase, OFF);
- EnRXDMA(iobase, OFF);
- RXStart(iobase, OFF);
-//F01_S
- // Put this entry back in fifo
- if (st_fifo->head > MAX_RX_WINDOW)
- st_fifo->head = 0;
- status = st_fifo->entries[st_fifo->head].status;
- len = st_fifo->entries[st_fifo->head].len;
- st_fifo->head++;
- st_fifo->len--;
-
- skb = dev_alloc_skb(len + 1 - 4);
- /*
- * if frame size, data ptr, or skb ptr are wrong, then get next
- * entry.
- */
- if ((skb == NULL) || (skb->data == NULL) ||
- (self->rx_buff.data == NULL) || (len < 6)) {
- self->netdev->stats.rx_dropped++;
- kfree_skb(skb);
- return TRUE;
- }
- skb_reserve(skb, 1);
- skb_put(skb, len - 4);
-
- skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4);
- pr_debug("%s(): len=%x.rx_buff=%p\n", __func__,
- len - 4, self->rx_buff.data);
-
- // Move to next frame
- self->rx_buff.data += len;
- self->netdev->stats.rx_bytes += len;
- self->netdev->stats.rx_packets++;
- skb->dev = self->netdev;
- skb_reset_mac_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- netif_rx(skb);
-
-//F01_E
- } //FIR
- return TRUE;
-
-}
-
-/*
- * if frame is received , but no INT ,then use this routine to upload frame.
- */
-static int upload_rxdata(struct via_ircc_cb *self, int iobase)
-{
- struct sk_buff *skb;
- int len;
- struct st_fifo *st_fifo;
- st_fifo = &self->st_fifo;
-
- len = GetRecvByte(iobase, self);
-
- pr_debug("%s(): len=%x\n", __func__, len);
-
- if ((len - 4) < 2) {
- self->netdev->stats.rx_dropped++;
- return FALSE;
- }
-
- skb = dev_alloc_skb(len + 1);
- if (skb == NULL) {
- self->netdev->stats.rx_dropped++;
- return FALSE;
- }
- skb_reserve(skb, 1);
- skb_put(skb, len - 4 + 1);
- skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4 + 1);
- st_fifo->tail++;
- st_fifo->len++;
- if (st_fifo->tail > MAX_RX_WINDOW)
- st_fifo->tail = 0;
- // Move to next frame
- self->rx_buff.data += len;
- self->netdev->stats.rx_bytes += len;
- self->netdev->stats.rx_packets++;
- skb->dev = self->netdev;
- skb_reset_mac_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- netif_rx(skb);
- if (st_fifo->len < (MAX_RX_WINDOW + 2)) {
- RXStart(iobase, ON);
- } else {
- EnableRX(iobase, OFF);
- EnRXDMA(iobase, OFF);
- RXStart(iobase, OFF);
- }
- return TRUE;
-}
-
-/*
- * Implement back to back receive , use this routine to upload data.
- */
-
-static int RxTimerHandler(struct via_ircc_cb *self, int iobase)
-{
- struct st_fifo *st_fifo;
- struct sk_buff *skb;
- int len;
- u8 status;
-
- st_fifo = &self->st_fifo;
-
- if (CkRxRecv(iobase, self)) {
- // if still receiving ,then return ,don't upload frame
- self->RetryCount = 0;
- SetTimer(iobase, 20);
- self->RxDataReady++;
- return FALSE;
- } else
- self->RetryCount++;
-
- if ((self->RetryCount >= 1) ||
- ((st_fifo->pending_bytes + 2048) > self->rx_buff.truesize) ||
- (st_fifo->len >= (MAX_RX_WINDOW))) {
- while (st_fifo->len > 0) { //upload frame
- // Put this entry back in fifo
- if (st_fifo->head > MAX_RX_WINDOW)
- st_fifo->head = 0;
- status = st_fifo->entries[st_fifo->head].status;
- len = st_fifo->entries[st_fifo->head].len;
- st_fifo->head++;
- st_fifo->len--;
-
- skb = dev_alloc_skb(len + 1 - 4);
- /*
- * if frame size, data ptr, or skb ptr are wrong,
- * then get next entry.
- */
- if ((skb == NULL) || (skb->data == NULL) ||
- (self->rx_buff.data == NULL) || (len < 6)) {
- self->netdev->stats.rx_dropped++;
- continue;
- }
- skb_reserve(skb, 1);
- skb_put(skb, len - 4);
- skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4);
-
- pr_debug("%s(): len=%x.head=%x\n", __func__,
- len - 4, st_fifo->head);
-
- // Move to next frame
- self->rx_buff.data += len;
- self->netdev->stats.rx_bytes += len;
- self->netdev->stats.rx_packets++;
- skb->dev = self->netdev;
- skb_reset_mac_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- netif_rx(skb);
- } //while
- self->RetryCount = 0;
-
- pr_debug("%s(): End of upload HostStatus=%x,RxStatus=%x\n",
- __func__, GetHostStatus(iobase), GetRXStatus(iobase));
-
- /*
- * if frame is receive complete at this routine ,then upload
- * frame.
- */
- if ((GetRXStatus(iobase) & 0x10) &&
- (RxCurCount(iobase, self) != self->RxLastCount)) {
- upload_rxdata(self, iobase);
- if (irda_device_txqueue_empty(self->netdev))
- via_ircc_dma_receive(self);
- }
- } // timer detect complete
- else
- SetTimer(iobase, 4);
- return TRUE;
-
-}
-
-
-
-/*
- * Function via_ircc_interrupt (irq, dev_id)
- *
- * An interrupt from the chip has arrived. Time to do some work
- *
- */
-static irqreturn_t via_ircc_interrupt(int dummy, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct via_ircc_cb *self = netdev_priv(dev);
- int iobase;
- u8 iHostIntType, iRxIntType, iTxIntType;
-
- iobase = self->io.fir_base;
- spin_lock(&self->lock);
- iHostIntType = GetHostStatus(iobase);
-
- pr_debug("%s(): iHostIntType %02x: %s %s %s %02x\n",
- __func__, iHostIntType,
- (iHostIntType & 0x40) ? "Timer" : "",
- (iHostIntType & 0x20) ? "Tx" : "",
- (iHostIntType & 0x10) ? "Rx" : "",
- (iHostIntType & 0x0e) >> 1);
-
- if ((iHostIntType & 0x40) != 0) { //Timer Event
- self->EventFlag.TimeOut++;
- ClearTimerInt(iobase, 1);
- if (self->io.direction == IO_XMIT) {
- via_ircc_dma_xmit(self, iobase);
- }
- if (self->io.direction == IO_RECV) {
- /*
- * frame ready hold too long, must reset.
- */
- if (self->RxDataReady > 30) {
- hwreset(self);
- if (irda_device_txqueue_empty(self->netdev)) {
- via_ircc_dma_receive(self);
- }
- } else { // call this to upload frame.
- RxTimerHandler(self, iobase);
- }
- } //RECV
- } //Timer Event
- if ((iHostIntType & 0x20) != 0) { //Tx Event
- iTxIntType = GetTXStatus(iobase);
-
- pr_debug("%s(): iTxIntType %02x: %s %s %s %s\n",
- __func__, iTxIntType,
- (iTxIntType & 0x08) ? "FIFO underr." : "",
- (iTxIntType & 0x04) ? "EOM" : "",
- (iTxIntType & 0x02) ? "FIFO ready" : "",
- (iTxIntType & 0x01) ? "Early EOM" : "");
-
- if (iTxIntType & 0x4) {
- self->EventFlag.EOMessage++; // read and will auto clean
- if (via_ircc_dma_xmit_complete(self)) {
- if (irda_device_txqueue_empty
- (self->netdev)) {
- via_ircc_dma_receive(self);
- }
- } else {
- self->EventFlag.Unknown++;
- }
- } //EOP
- } //Tx Event
- //----------------------------------------
- if ((iHostIntType & 0x10) != 0) { //Rx Event
- /* Check if DMA has finished */
- iRxIntType = GetRXStatus(iobase);
-
- pr_debug("%s(): iRxIntType %02x: %s %s %s %s %s %s %s\n",
- __func__, iRxIntType,
- (iRxIntType & 0x80) ? "PHY err." : "",
- (iRxIntType & 0x40) ? "CRC err" : "",
- (iRxIntType & 0x20) ? "FIFO overr." : "",
- (iRxIntType & 0x10) ? "EOF" : "",
- (iRxIntType & 0x08) ? "RxData" : "",
- (iRxIntType & 0x02) ? "RxMaxLen" : "",
- (iRxIntType & 0x01) ? "SIR bad" : "");
- if (!iRxIntType)
- pr_debug("%s(): RxIRQ =0\n", __func__);
-
- if (iRxIntType & 0x10) {
- if (via_ircc_dma_receive_complete(self, iobase)) {
-//F01 if(!(IsFIROn(iobase))) via_ircc_dma_receive(self);
- via_ircc_dma_receive(self);
- }
- } // No ERR
- else { //ERR
- pr_debug("%s(): RxIRQ ERR:iRxIntType=%x,HostIntType=%x,CurCount=%x,RxLastCount=%x_____\n",
- __func__, iRxIntType, iHostIntType,
- RxCurCount(iobase, self), self->RxLastCount);
-
- if (iRxIntType & 0x20) { //FIFO OverRun ERR
- ResetChip(iobase, 0);
- ResetChip(iobase, 1);
- } else { //PHY,CRC ERR
-
- if (iRxIntType != 0x08)
- hwreset(self); //F01
- }
- via_ircc_dma_receive(self);
- } //ERR
-
- } //Rx Event
- spin_unlock(&self->lock);
- return IRQ_RETVAL(iHostIntType);
-}
-
-static void hwreset(struct via_ircc_cb *self)
-{
- int iobase;
- iobase = self->io.fir_base;
-
- ResetChip(iobase, 5);
- EnableDMA(iobase, OFF);
- EnableTX(iobase, OFF);
- EnableRX(iobase, OFF);
- EnRXDMA(iobase, OFF);
- EnTXDMA(iobase, OFF);
- RXStart(iobase, OFF);
- TXStart(iobase, OFF);
- InitCard(iobase);
- CommonInit(iobase);
- SIRFilter(iobase, ON);
- SetSIR(iobase, ON);
- CRC16(iobase, ON);
- EnTXCRC(iobase, 0);
- WriteReg(iobase, I_ST_CT_0, 0x00);
- SetBaudRate(iobase, 9600);
- SetPulseWidth(iobase, 12);
- SetSendPreambleCount(iobase, 0);
- WriteReg(iobase, I_ST_CT_0, 0x80);
-
- /* Restore speed. */
- via_ircc_change_speed(self, self->io.speed);
-
- self->st_fifo.len = 0;
-}
-
-/*
- * Function via_ircc_is_receiving (self)
- *
- * Return TRUE is we are currently receiving a frame
- *
- */
-static int via_ircc_is_receiving(struct via_ircc_cb *self)
-{
- int status = FALSE;
- int iobase;
-
- IRDA_ASSERT(self != NULL, return FALSE;);
-
- iobase = self->io.fir_base;
- if (CkRxRecv(iobase, self))
- status = TRUE;
-
- pr_debug("%s(): status=%x....\n", __func__, status);
-
- return status;
-}
-
-
-/*
- * Function via_ircc_net_open (dev)
- *
- * Start the device
- *
- */
-static int via_ircc_net_open(struct net_device *dev)
-{
- struct via_ircc_cb *self;
- int iobase;
- char hwname[32];
-
- IRDA_ASSERT(dev != NULL, return -1;);
- self = netdev_priv(dev);
- dev->stats.rx_packets = 0;
- IRDA_ASSERT(self != NULL, return 0;);
- iobase = self->io.fir_base;
- if (request_irq(self->io.irq, via_ircc_interrupt, 0, dev->name, dev)) {
- net_warn_ratelimited("%s, unable to allocate irq=%d\n",
- driver_name, self->io.irq);
- return -EAGAIN;
- }
- /*
- * Always allocate the DMA channel after the IRQ, and clean up on
- * failure.
- */
- if (request_dma(self->io.dma, dev->name)) {
- net_warn_ratelimited("%s, unable to allocate dma=%d\n",
- driver_name, self->io.dma);
- free_irq(self->io.irq, dev);
- return -EAGAIN;
- }
- if (self->io.dma2 != self->io.dma) {
- if (request_dma(self->io.dma2, dev->name)) {
- net_warn_ratelimited("%s, unable to allocate dma2=%d\n",
- driver_name, self->io.dma2);
- free_irq(self->io.irq, dev);
- free_dma(self->io.dma);
- return -EAGAIN;
- }
- }
-
-
- /* turn on interrupts */
- EnAllInt(iobase, ON);
- EnInternalLoop(iobase, OFF);
- EnExternalLoop(iobase, OFF);
-
- /* */
- via_ircc_dma_receive(self);
-
- /* Ready to play! */
- netif_start_queue(dev);
-
- /*
- * Open new IrLAP layer instance, now that everything should be
- * initialized properly
- */
- sprintf(hwname, "VIA @ 0x%x", iobase);
- self->irlap = irlap_open(dev, &self->qos, hwname);
-
- self->RxLastCount = 0;
-
- return 0;
-}
-
-/*
- * Function via_ircc_net_close (dev)
- *
- * Stop the device
- *
- */
-static int via_ircc_net_close(struct net_device *dev)
-{
- struct via_ircc_cb *self;
- int iobase;
-
- IRDA_ASSERT(dev != NULL, return -1;);
- self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
-
- /* Stop device */
- netif_stop_queue(dev);
- /* Stop and remove instance of IrLAP */
- if (self->irlap)
- irlap_close(self->irlap);
- self->irlap = NULL;
- iobase = self->io.fir_base;
- EnTXDMA(iobase, OFF);
- EnRXDMA(iobase, OFF);
- DisableDmaChannel(self->io.dma);
-
- /* Disable interrupts */
- EnAllInt(iobase, OFF);
- free_irq(self->io.irq, dev);
- free_dma(self->io.dma);
- if (self->io.dma2 != self->io.dma)
- free_dma(self->io.dma2);
-
- return 0;
-}
-
-/*
- * Function via_ircc_net_ioctl (dev, rq, cmd)
- *
- * Process IOCTL commands for this device
- *
- */
-static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq,
- int cmd)
-{
- struct if_irda_req *irq = (struct if_irda_req *) rq;
- struct via_ircc_cb *self;
- unsigned long flags;
- int ret = 0;
-
- IRDA_ASSERT(dev != NULL, return -1;);
- self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return -1;);
- pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name,
- cmd);
- /* Disable interrupts & save flags */
- spin_lock_irqsave(&self->lock, flags);
- switch (cmd) {
- case SIOCSBANDWIDTH: /* Set bandwidth */
- if (!capable(CAP_NET_ADMIN)) {
- ret = -EPERM;
- goto out;
- }
- via_ircc_change_speed(self, irq->ifr_baudrate);
- break;
- case SIOCSMEDIABUSY: /* Set media busy */
- if (!capable(CAP_NET_ADMIN)) {
- ret = -EPERM;
- goto out;
- }
- irda_device_set_media_busy(self->netdev, TRUE);
- break;
- case SIOCGRECEIVING: /* Check if we are receiving right now */
- irq->ifr_receiving = via_ircc_is_receiving(self);
- break;
- default:
- ret = -EOPNOTSUPP;
- }
- out:
- spin_unlock_irqrestore(&self->lock, flags);
- return ret;
-}
-
-MODULE_AUTHOR("VIA Technologies,inc");
-MODULE_DESCRIPTION("VIA IrDA Device Driver");
-MODULE_LICENSE("GPL");
-
-module_init(via_ircc_init);
-module_exit(via_ircc_cleanup);
diff --git a/drivers/staging/irda/drivers/via-ircc.h b/drivers/staging/irda/drivers/via-ircc.h
deleted file mode 100644
index ac1525573398..000000000000
--- a/drivers/staging/irda/drivers/via-ircc.h
+++ /dev/null
@@ -1,846 +0,0 @@
-/*********************************************************************
- *
- * Filename: via-ircc.h
- * Version: 1.0
- * Description: Driver for the VIA VT8231/VT8233 IrDA chipsets
- * Author: VIA Technologies, inc
- * Date : 08/06/2003
-
-Copyright (c) 1998-2003 VIA Technologies, 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, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTIES OR REPRESENTATIONS; 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/>.
-
- * Comment:
- * jul/08/2002 : Rx buffer length should use Rx ring ptr.
- * Oct/28/2002 : Add SB id for 3147 and 3177.
- * jul/09/2002 : only implement two kind of dongle currently.
- * Oct/02/2002 : work on VT8231 and VT8233 .
- * Aug/06/2003 : change driver format to pci driver .
- ********************************************************************/
-#ifndef via_IRCC_H
-#define via_IRCC_H
-#include <linux/spinlock.h>
-#include <linux/pm.h>
-#include <linux/types.h>
-#include <asm/io.h>
-
-#define MAX_TX_WINDOW 7
-#define MAX_RX_WINDOW 7
-
-struct st_fifo_entry {
- int status;
- int len;
-};
-
-struct st_fifo {
- struct st_fifo_entry entries[MAX_RX_WINDOW + 2];
- int pending_bytes;
- int head;
- int tail;
- int len;
-};
-
-struct frame_cb {
- void *start; /* Start of frame in DMA mem */
- int len; /* Length of frame in DMA mem */
-};
-
-struct tx_fifo {
- struct frame_cb queue[MAX_TX_WINDOW + 2]; /* Info about frames in queue */
- int ptr; /* Currently being sent */
- int len; /* Length of queue */
- int free; /* Next free slot */
- void *tail; /* Next free start in DMA mem */
-};
-
-
-struct eventflag // for keeping track of Interrupt Events
-{
- //--------tx part
- unsigned char TxFIFOUnderRun;
- unsigned char EOMessage;
- unsigned char TxFIFOReady;
- unsigned char EarlyEOM;
- //--------rx part
- unsigned char PHYErr;
- unsigned char CRCErr;
- unsigned char RxFIFOOverRun;
- unsigned char EOPacket;
- unsigned char RxAvail;
- unsigned char TooLargePacket;
- unsigned char SIRBad;
- //--------unknown
- unsigned char Unknown;
- //----------
- unsigned char TimeOut;
- unsigned char RxDMATC;
- unsigned char TxDMATC;
-};
-
-/* Private data for each instance */
-struct via_ircc_cb {
- struct st_fifo st_fifo; /* Info about received frames */
- struct tx_fifo tx_fifo; /* Info about frames to be transmitted */
-
- struct net_device *netdev; /* Yes! we are some kind of netdevice */
-
- struct irlap_cb *irlap; /* The link layer we are binded to */
- struct qos_info qos; /* QoS capabilities for this device */
-
- chipio_t io; /* IrDA controller information */
- iobuff_t tx_buff; /* Transmit buffer */
- iobuff_t rx_buff; /* Receive buffer */
- dma_addr_t tx_buff_dma;
- dma_addr_t rx_buff_dma;
-
- __u8 ier; /* Interrupt enable register */
-
- spinlock_t lock; /* For serializing operations */
-
- __u32 flags; /* Interface flags */
- __u32 new_speed;
- int index; /* Instance index */
-
- struct eventflag EventFlag;
- unsigned int chip_id; /* to remember chip id */
- unsigned int RetryCount;
- unsigned int RxDataReady;
- unsigned int RxLastCount;
-};
-
-
-//---------I=Infrared, H=Host, M=Misc, T=Tx, R=Rx, ST=Status,
-// CF=Config, CT=Control, L=Low, H=High, C=Count
-#define I_CF_L_0 0x10
-#define I_CF_H_0 0x11
-#define I_SIR_BOF 0x12
-#define I_SIR_EOF 0x13
-#define I_ST_CT_0 0x15
-#define I_ST_L_1 0x16
-#define I_ST_H_1 0x17
-#define I_CF_L_1 0x18
-#define I_CF_H_1 0x19
-#define I_CF_L_2 0x1a
-#define I_CF_H_2 0x1b
-#define I_CF_3 0x1e
-#define H_CT 0x20
-#define H_ST 0x21
-#define M_CT 0x22
-#define TX_CT_1 0x23
-#define TX_CT_2 0x24
-#define TX_ST 0x25
-#define RX_CT 0x26
-#define RX_ST 0x27
-#define RESET 0x28
-#define P_ADDR 0x29
-#define RX_C_L 0x2a
-#define RX_C_H 0x2b
-#define RX_P_L 0x2c
-#define RX_P_H 0x2d
-#define TX_C_L 0x2e
-#define TX_C_H 0x2f
-#define TIMER 0x32
-#define I_CF_4 0x33
-#define I_T_C_L 0x34
-#define I_T_C_H 0x35
-#define VERSION 0x3f
-//-------------------------------
-#define StartAddr 0x10 // the first register address
-#define EndAddr 0x3f // the last register address
-#define GetBit(val,bit) val = (unsigned char) ((val>>bit) & 0x1)
- // Returns the bit
-#define SetBit(val,bit) val= (unsigned char ) (val | (0x1 << bit))
- // Sets bit to 1
-#define ResetBit(val,bit) val= (unsigned char ) (val & ~(0x1 << bit))
- // Sets bit to 0
-
-#define OFF 0
-#define ON 1
-#define DMA_TX_MODE 0x08
-#define DMA_RX_MODE 0x04
-
-#define DMA1 0
-#define DMA2 0xc0
-#define MASK1 DMA1+0x0a
-#define MASK2 DMA2+0x14
-
-#define Clk_bit 0x40
-#define Tx_bit 0x01
-#define Rd_Valid 0x08
-#define RxBit 0x08
-
-static void DisableDmaChannel(unsigned int channel)
-{
- switch (channel) { // 8 Bit DMA channels DMAC1
- case 0:
- outb(4, MASK1); //mask channel 0
- break;
- case 1:
- outb(5, MASK1); //Mask channel 1
- break;
- case 2:
- outb(6, MASK1); //Mask channel 2
- break;
- case 3:
- outb(7, MASK1); //Mask channel 3
- break;
- case 5:
- outb(5, MASK2); //Mask channel 5
- break;
- case 6:
- outb(6, MASK2); //Mask channel 6
- break;
- case 7:
- outb(7, MASK2); //Mask channel 7
- break;
- default:
- break;
- }
-}
-
-static unsigned char ReadLPCReg(int iRegNum)
-{
- unsigned char iVal;
-
- outb(0x87, 0x2e);
- outb(0x87, 0x2e);
- outb(iRegNum, 0x2e);
- iVal = inb(0x2f);
- outb(0xaa, 0x2e);
-
- return iVal;
-}
-
-static void WriteLPCReg(int iRegNum, unsigned char iVal)
-{
-
- outb(0x87, 0x2e);
- outb(0x87, 0x2e);
- outb(iRegNum, 0x2e);
- outb(iVal, 0x2f);
- outb(0xAA, 0x2e);
-}
-
-static __u8 ReadReg(unsigned int BaseAddr, int iRegNum)
-{
- return (__u8) inb(BaseAddr + iRegNum);
-}
-
-static void WriteReg(unsigned int BaseAddr, int iRegNum, unsigned char iVal)
-{
- outb(iVal, BaseAddr + iRegNum);
-}
-
-static int WriteRegBit(unsigned int BaseAddr, unsigned char RegNum,
- unsigned char BitPos, unsigned char value)
-{
- __u8 Rtemp, Wtemp;
-
- if (BitPos > 7) {
- return -1;
- }
- if ((RegNum < StartAddr) || (RegNum > EndAddr))
- return -1;
- Rtemp = ReadReg(BaseAddr, RegNum);
- if (value == 0)
- Wtemp = ResetBit(Rtemp, BitPos);
- else {
- if (value == 1)
- Wtemp = SetBit(Rtemp, BitPos);
- else
- return -1;
- }
- WriteReg(BaseAddr, RegNum, Wtemp);
- return 0;
-}
-
-static __u8 CheckRegBit(unsigned int BaseAddr, unsigned char RegNum,
- unsigned char BitPos)
-{
- __u8 temp;
-
- if (BitPos > 7)
- return 0xff;
- if ((RegNum < StartAddr) || (RegNum > EndAddr)) {
-// printf("what is the register %x!\n",RegNum);
- }
- temp = ReadReg(BaseAddr, RegNum);
- return GetBit(temp, BitPos);
-}
-
-static void SetMaxRxPacketSize(__u16 iobase, __u16 size)
-{
- __u16 low, high;
- if ((size & 0xe000) == 0) {
- low = size & 0x00ff;
- high = (size & 0x1f00) >> 8;
- WriteReg(iobase, I_CF_L_2, low);
- WriteReg(iobase, I_CF_H_2, high);
-
- }
-
-}
-
-//for both Rx and Tx
-
-static void SetFIFO(__u16 iobase, __u16 value)
-{
- switch (value) {
- case 128:
- WriteRegBit(iobase, 0x11, 0, 0);
- WriteRegBit(iobase, 0x11, 7, 1);
- break;
- case 64:
- WriteRegBit(iobase, 0x11, 0, 0);
- WriteRegBit(iobase, 0x11, 7, 0);
- break;
- case 32:
- WriteRegBit(iobase, 0x11, 0, 1);
- WriteRegBit(iobase, 0x11, 7, 0);
- break;
- default:
- WriteRegBit(iobase, 0x11, 0, 0);
- WriteRegBit(iobase, 0x11, 7, 0);
- }
-
-}
-
-#define CRC16(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,7,val) //0 for 32 CRC
-/*
-#define SetVFIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,5,val)
-#define SetFIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,6,val)
-#define SetMIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,5,val)
-#define SetSIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,4,val)
-*/
-#define SIRFilter(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,3,val)
-#define Filter(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,2,val)
-#define InvertTX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,1,val)
-#define InvertRX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,0,val)
-//****************************I_CF_H_0
-#define EnableTX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,4,val)
-#define EnableRX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,3,val)
-#define EnableDMA(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,2,val)
-#define SIRRecvAny(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,1,val)
-#define DiableTrans(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,0,val)
-//***************************I_SIR_BOF,I_SIR_EOF
-#define SetSIRBOF(BaseAddr,val) WriteReg(BaseAddr,I_SIR_BOF,val)
-#define SetSIREOF(BaseAddr,val) WriteReg(BaseAddr,I_SIR_EOF,val)
-#define GetSIRBOF(BaseAddr) ReadReg(BaseAddr,I_SIR_BOF)
-#define GetSIREOF(BaseAddr) ReadReg(BaseAddr,I_SIR_EOF)
-//*******************I_ST_CT_0
-#define EnPhys(BaseAddr,val) WriteRegBit(BaseAddr,I_ST_CT_0,7,val)
-#define IsModeError(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,6) //RO
-#define IsVFIROn(BaseAddr) CheckRegBit(BaseAddr,0x14,0) //RO for VT1211 only
-#define IsFIROn(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,5) //RO
-#define IsMIROn(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,4) //RO
-#define IsSIROn(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,3) //RO
-#define IsEnableTX(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,2) //RO
-#define IsEnableRX(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,1) //RO
-#define Is16CRC(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,0) //RO
-//***************************I_CF_3
-#define DisableAdjacentPulseWidth(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,5,val) //1 disable
-#define DisablePulseWidthAdjust(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,4,val) //1 disable
-#define UseOneRX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,1,val) //0 use two RX
-#define SlowIRRXLowActive(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,0,val) //0 show RX high=1 in SIR
-//***************************H_CT
-#define EnAllInt(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,7,val)
-#define TXStart(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,6,val)
-#define RXStart(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,5,val)
-#define ClearRXInt(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,4,val) // 1 clear
-//*****************H_ST
-#define IsRXInt(BaseAddr) CheckRegBit(BaseAddr,H_ST,4)
-#define GetIntIndentify(BaseAddr) ((ReadReg(BaseAddr,H_ST)&0xf1) >>1)
-#define IsHostBusy(BaseAddr) CheckRegBit(BaseAddr,H_ST,0)
-#define GetHostStatus(BaseAddr) ReadReg(BaseAddr,H_ST) //RO
-//**************************M_CT
-#define EnTXDMA(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,7,val)
-#define EnRXDMA(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,6,val)
-#define SwapDMA(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,5,val)
-#define EnInternalLoop(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,4,val)
-#define EnExternalLoop(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,3,val)
-//**************************TX_CT_1
-#define EnTXFIFOHalfLevelInt(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_1,4,val) //half empty int (1 half)
-#define EnTXFIFOUnderrunEOMInt(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_1,5,val)
-#define EnTXFIFOReadyInt(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_1,6,val) //int when reach it threshold (setting by bit 4)
-//**************************TX_CT_2
-#define ForceUnderrun(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,7,val) // force an underrun int
-#define EnTXCRC(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,6,val) //1 for FIR,MIR...0 (not SIR)
-#define ForceBADCRC(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,5,val) //force an bad CRC
-#define SendSIP(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,4,val) //send indication pulse for prevent SIR disturb
-#define ClearEnTX(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,3,val) // opposite to EnTX
-//*****************TX_ST
-#define GetTXStatus(BaseAddr) ReadReg(BaseAddr,TX_ST) //RO
-//**************************RX_CT
-#define EnRXSpecInt(BaseAddr,val) WriteRegBit(BaseAddr,RX_CT,0,val)
-#define EnRXFIFOReadyInt(BaseAddr,val) WriteRegBit(BaseAddr,RX_CT,1,val) //enable int when reach it threshold (setting by bit 7)
-#define EnRXFIFOHalfLevelInt(BaseAddr,val) WriteRegBit(BaseAddr,RX_CT,7,val) //enable int when (1) half full...or (0) just not full
-//*****************RX_ST
-#define GetRXStatus(BaseAddr) ReadReg(BaseAddr,RX_ST) //RO
-//***********************P_ADDR
-#define SetPacketAddr(BaseAddr,addr) WriteReg(BaseAddr,P_ADDR,addr)
-//***********************I_CF_4
-#define EnGPIOtoRX2(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_4,7,val)
-#define EnTimerInt(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_4,1,val)
-#define ClearTimerInt(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_4,0,val)
-//***********************I_T_C_L
-#define WriteGIO(BaseAddr,val) WriteRegBit(BaseAddr,I_T_C_L,7,val)
-#define ReadGIO(BaseAddr) CheckRegBit(BaseAddr,I_T_C_L,7)
-#define ReadRX(BaseAddr) CheckRegBit(BaseAddr,I_T_C_L,3) //RO
-#define WriteTX(BaseAddr,val) WriteRegBit(BaseAddr,I_T_C_L,0,val)
-//***********************I_T_C_H
-#define EnRX2(BaseAddr,val) WriteRegBit(BaseAddr,I_T_C_H,7,val)
-#define ReadRX2(BaseAddr) CheckRegBit(BaseAddr,I_T_C_H,7)
-//**********************Version
-#define GetFIRVersion(BaseAddr) ReadReg(BaseAddr,VERSION)
-
-
-static void SetTimer(__u16 iobase, __u8 count)
-{
- EnTimerInt(iobase, OFF);
- WriteReg(iobase, TIMER, count);
- EnTimerInt(iobase, ON);
-}
-
-
-static void SetSendByte(__u16 iobase, __u32 count)
-{
- __u32 low, high;
-
- if ((count & 0xf000) == 0) {
- low = count & 0x00ff;
- high = (count & 0x0f00) >> 8;
- WriteReg(iobase, TX_C_L, low);
- WriteReg(iobase, TX_C_H, high);
- }
-}
-
-static void ResetChip(__u16 iobase, __u8 type)
-{
- __u8 value;
-
- value = (type + 2) << 4;
- WriteReg(iobase, RESET, type);
-}
-
-static int CkRxRecv(__u16 iobase, struct via_ircc_cb *self)
-{
- __u8 low, high;
- __u16 wTmp = 0, wTmp1 = 0, wTmp_new = 0;
-
- low = ReadReg(iobase, RX_C_L);
- high = ReadReg(iobase, RX_C_H);
- wTmp1 = high;
- wTmp = (wTmp1 << 8) | low;
- udelay(10);
- low = ReadReg(iobase, RX_C_L);
- high = ReadReg(iobase, RX_C_H);
- wTmp1 = high;
- wTmp_new = (wTmp1 << 8) | low;
- if (wTmp_new != wTmp)
- return 1;
- else
- return 0;
-
-}
-
-static __u16 RxCurCount(__u16 iobase, struct via_ircc_cb * self)
-{
- __u8 low, high;
- __u16 wTmp = 0, wTmp1 = 0;
-
- low = ReadReg(iobase, RX_P_L);
- high = ReadReg(iobase, RX_P_H);
- wTmp1 = high;
- wTmp = (wTmp1 << 8) | low;
- return wTmp;
-}
-
-/* This Routine can only use in recevie_complete
- * for it will update last count.
- */
-
-static __u16 GetRecvByte(__u16 iobase, struct via_ircc_cb * self)
-{
- __u8 low, high;
- __u16 wTmp, wTmp1, ret;
-
- low = ReadReg(iobase, RX_P_L);
- high = ReadReg(iobase, RX_P_H);
- wTmp1 = high;
- wTmp = (wTmp1 << 8) | low;
-
-
- if (wTmp >= self->RxLastCount)
- ret = wTmp - self->RxLastCount;
- else
- ret = (0x8000 - self->RxLastCount) + wTmp;
- self->RxLastCount = wTmp;
-
-/* RX_P is more actually the RX_C
- low=ReadReg(iobase,RX_C_L);
- high=ReadReg(iobase,RX_C_H);
-
- if(!(high&0xe000)) {
- temp=(high<<8)+low;
- return temp;
- }
- else return 0;
-*/
- return ret;
-}
-
-static void Sdelay(__u16 scale)
-{
- __u8 bTmp;
- int i, j;
-
- for (j = 0; j < scale; j++) {
- for (i = 0; i < 0x20; i++) {
- bTmp = inb(0xeb);
- outb(bTmp, 0xeb);
- }
- }
-}
-
-static void Tdelay(__u16 scale)
-{
- __u8 bTmp;
- int i, j;
-
- for (j = 0; j < scale; j++) {
- for (i = 0; i < 0x50; i++) {
- bTmp = inb(0xeb);
- outb(bTmp, 0xeb);
- }
- }
-}
-
-
-static void ActClk(__u16 iobase, __u8 value)
-{
- __u8 bTmp;
- bTmp = ReadReg(iobase, 0x34);
- if (value)
- WriteReg(iobase, 0x34, bTmp | Clk_bit);
- else
- WriteReg(iobase, 0x34, bTmp & ~Clk_bit);
-}
-
-static void ClkTx(__u16 iobase, __u8 Clk, __u8 Tx)
-{
- __u8 bTmp;
-
- bTmp = ReadReg(iobase, 0x34);
- if (Clk == 0)
- bTmp &= ~Clk_bit;
- else {
- if (Clk == 1)
- bTmp |= Clk_bit;
- }
- WriteReg(iobase, 0x34, bTmp);
- Sdelay(1);
- if (Tx == 0)
- bTmp &= ~Tx_bit;
- else {
- if (Tx == 1)
- bTmp |= Tx_bit;
- }
- WriteReg(iobase, 0x34, bTmp);
-}
-
-static void Wr_Byte(__u16 iobase, __u8 data)
-{
- __u8 bData = data;
-// __u8 btmp;
- int i;
-
- ClkTx(iobase, 0, 1);
-
- Tdelay(2);
- ActClk(iobase, 1);
- Tdelay(1);
-
- for (i = 0; i < 8; i++) { //LDN
-
- if ((bData >> i) & 0x01) {
- ClkTx(iobase, 0, 1); //bit data = 1;
- } else {
- ClkTx(iobase, 0, 0); //bit data = 1;
- }
- Tdelay(2);
- Sdelay(1);
- ActClk(iobase, 1); //clk hi
- Tdelay(1);
- }
-}
-
-static __u8 Rd_Indx(__u16 iobase, __u8 addr, __u8 index)
-{
- __u8 data = 0, bTmp, data_bit;
- int i;
-
- bTmp = addr | (index << 1) | 0;
- ClkTx(iobase, 0, 0);
- Tdelay(2);
- ActClk(iobase, 1);
- udelay(1);
- Wr_Byte(iobase, bTmp);
- Sdelay(1);
- ClkTx(iobase, 0, 0);
- Tdelay(2);
- for (i = 0; i < 10; i++) {
- ActClk(iobase, 1);
- Tdelay(1);
- ActClk(iobase, 0);
- Tdelay(1);
- ClkTx(iobase, 0, 1);
- Tdelay(1);
- bTmp = ReadReg(iobase, 0x34);
- if (!(bTmp & Rd_Valid))
- break;
- }
- if (!(bTmp & Rd_Valid)) {
- for (i = 0; i < 8; i++) {
- ActClk(iobase, 1);
- Tdelay(1);
- ActClk(iobase, 0);
- bTmp = ReadReg(iobase, 0x34);
- data_bit = 1 << i;
- if (bTmp & RxBit)
- data |= data_bit;
- else
- data &= ~data_bit;
- Tdelay(2);
- }
- } else {
- for (i = 0; i < 2; i++) {
- ActClk(iobase, 1);
- Tdelay(1);
- ActClk(iobase, 0);
- Tdelay(2);
- }
- bTmp = ReadReg(iobase, 0x34);
- }
- for (i = 0; i < 1; i++) {
- ActClk(iobase, 1);
- Tdelay(1);
- ActClk(iobase, 0);
- Tdelay(2);
- }
- ClkTx(iobase, 0, 0);
- Tdelay(1);
- for (i = 0; i < 3; i++) {
- ActClk(iobase, 1);
- Tdelay(1);
- ActClk(iobase, 0);
- Tdelay(2);
- }
- return data;
-}
-
-static void Wr_Indx(__u16 iobase, __u8 addr, __u8 index, __u8 data)
-{
- int i;
- __u8 bTmp;
-
- ClkTx(iobase, 0, 0);
- udelay(2);
- ActClk(iobase, 1);
- udelay(1);
- bTmp = addr | (index << 1) | 1;
- Wr_Byte(iobase, bTmp);
- Wr_Byte(iobase, data);
- for (i = 0; i < 2; i++) {
- ClkTx(iobase, 0, 0);
- Tdelay(2);
- ActClk(iobase, 1);
- Tdelay(1);
- }
- ActClk(iobase, 0);
-}
-
-static void ResetDongle(__u16 iobase)
-{
- int i;
- ClkTx(iobase, 0, 0);
- Tdelay(1);
- for (i = 0; i < 30; i++) {
- ActClk(iobase, 1);
- Tdelay(1);
- ActClk(iobase, 0);
- Tdelay(1);
- }
- ActClk(iobase, 0);
-}
-
-static void SetSITmode(__u16 iobase)
-{
-
- __u8 bTmp;
-
- bTmp = ReadLPCReg(0x28);
- WriteLPCReg(0x28, bTmp | 0x10); //select ITMOFF
- bTmp = ReadReg(iobase, 0x35);
- WriteReg(iobase, 0x35, bTmp | 0x40); // Driver ITMOFF
- WriteReg(iobase, 0x28, bTmp | 0x80); // enable All interrupt
-}
-
-static void SI_SetMode(__u16 iobase, int mode)
-{
- //__u32 dTmp;
- __u8 bTmp;
-
- WriteLPCReg(0x28, 0x70); // S/W Reset
- SetSITmode(iobase);
- ResetDongle(iobase);
- udelay(10);
- Wr_Indx(iobase, 0x40, 0x0, 0x17); //RX ,APEN enable,Normal power
- Wr_Indx(iobase, 0x40, 0x1, mode); //Set Mode
- Wr_Indx(iobase, 0x40, 0x2, 0xff); //Set power to FIR VFIR > 1m
- bTmp = Rd_Indx(iobase, 0x40, 1);
-}
-
-static void InitCard(__u16 iobase)
-{
- ResetChip(iobase, 5);
- WriteReg(iobase, I_ST_CT_0, 0x00); // open CHIP on
- SetSIRBOF(iobase, 0xc0); // hardware default value
- SetSIREOF(iobase, 0xc1);
-}
-
-static void CommonInit(__u16 iobase)
-{
-// EnTXCRC(iobase,0);
- SwapDMA(iobase, OFF);
- SetMaxRxPacketSize(iobase, 0x0fff); //set to max:4095
- EnRXFIFOReadyInt(iobase, OFF);
- EnRXFIFOHalfLevelInt(iobase, OFF);
- EnTXFIFOHalfLevelInt(iobase, OFF);
- EnTXFIFOUnderrunEOMInt(iobase, ON);
-// EnTXFIFOReadyInt(iobase,ON);
- InvertTX(iobase, OFF);
- InvertRX(iobase, OFF);
-// WriteLPCReg(0xF0,0); //(if VT1211 then do this)
- if (IsSIROn(iobase)) {
- SIRFilter(iobase, ON);
- SIRRecvAny(iobase, ON);
- } else {
- SIRFilter(iobase, OFF);
- SIRRecvAny(iobase, OFF);
- }
- EnRXSpecInt(iobase, ON);
- WriteReg(iobase, I_ST_CT_0, 0x80);
- EnableDMA(iobase, ON);
-}
-
-static void SetBaudRate(__u16 iobase, __u32 rate)
-{
- __u8 value = 11, temp;
-
- if (IsSIROn(iobase)) {
- switch (rate) {
- case (__u32) (2400L):
- value = 47;
- break;
- case (__u32) (9600L):
- value = 11;
- break;
- case (__u32) (19200L):
- value = 5;
- break;
- case (__u32) (38400L):
- value = 2;
- break;
- case (__u32) (57600L):
- value = 1;
- break;
- case (__u32) (115200L):
- value = 0;
- break;
- default:
- break;
- }
- } else if (IsMIROn(iobase)) {
- value = 0; // will automatically be fixed in 1.152M
- } else if (IsFIROn(iobase)) {
- value = 0; // will automatically be fixed in 4M
- }
- temp = (ReadReg(iobase, I_CF_H_1) & 0x03);
- temp |= value << 2;
- WriteReg(iobase, I_CF_H_1, temp);
-}
-
-static void SetPulseWidth(__u16 iobase, __u8 width)
-{
- __u8 temp, temp1, temp2;
-
- temp = (ReadReg(iobase, I_CF_L_1) & 0x1f);
- temp1 = (ReadReg(iobase, I_CF_H_1) & 0xfc);
- temp2 = (width & 0x07) << 5;
- temp |= temp2;
- temp2 = (width & 0x18) >> 3;
- temp1 |= temp2;
- WriteReg(iobase, I_CF_L_1, temp);
- WriteReg(iobase, I_CF_H_1, temp1);
-}
-
-static void SetSendPreambleCount(__u16 iobase, __u8 count)
-{
- __u8 temp;
-
- temp = ReadReg(iobase, I_CF_L_1) & 0xe0;
- temp |= count;
- WriteReg(iobase, I_CF_L_1, temp);
-
-}
-
-static void SetVFIR(__u16 BaseAddr, __u8 val)
-{
- __u8 tmp;
-
- tmp = ReadReg(BaseAddr, I_CF_L_0);
- WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f);
- WriteRegBit(BaseAddr, I_CF_H_0, 5, val);
-}
-
-static void SetFIR(__u16 BaseAddr, __u8 val)
-{
- __u8 tmp;
-
- WriteRegBit(BaseAddr, I_CF_H_0, 5, 0);
- tmp = ReadReg(BaseAddr, I_CF_L_0);
- WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f);
- WriteRegBit(BaseAddr, I_CF_L_0, 6, val);
-}
-
-static void SetMIR(__u16 BaseAddr, __u8 val)
-{
- __u8 tmp;
-
- WriteRegBit(BaseAddr, I_CF_H_0, 5, 0);
- tmp = ReadReg(BaseAddr, I_CF_L_0);
- WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f);
- WriteRegBit(BaseAddr, I_CF_L_0, 5, val);
-}
-
-static void SetSIR(__u16 BaseAddr, __u8 val)
-{
- __u8 tmp;
-
- WriteRegBit(BaseAddr, I_CF_H_0, 5, 0);
- tmp = ReadReg(BaseAddr, I_CF_L_0);
- WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f);
- WriteRegBit(BaseAddr, I_CF_L_0, 4, val);
-}
-
-#endif /* via_IRCC_H */
diff --git a/drivers/staging/irda/drivers/vlsi_ir.c b/drivers/staging/irda/drivers/vlsi_ir.c
deleted file mode 100644
index 3dff3c55ddf5..000000000000
--- a/drivers/staging/irda/drivers/vlsi_ir.c
+++ /dev/null
@@ -1,1872 +0,0 @@
-/*********************************************************************
- *
- * vlsi_ir.c: VLSI82C147 PCI IrDA controller driver for Linux
- *
- * Copyright (c) 2001-2003 Martin Diehl
- *
- * 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.
- *
- * 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/module.h>
-
-#define DRIVER_NAME "vlsi_ir"
-#define DRIVER_VERSION "v0.5"
-#define DRIVER_DESCRIPTION "IrDA SIR/MIR/FIR driver for VLSI 82C147"
-#define DRIVER_AUTHOR "Martin Diehl <info@mdiehl.de>"
-
-MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_LICENSE("GPL");
-
-/********************************************************/
-
-#include <linux/kernel.h>
-#include <linux/ktime.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/math64.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <asm/byteorder.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/crc.h>
-
-#include "vlsi_ir.h"
-
-/********************************************************/
-
-static /* const */ char drivername[] = DRIVER_NAME;
-
-static const struct pci_device_id vlsi_irda_table[] = {
- {
- .class = PCI_CLASS_WIRELESS_IRDA << 8,
- .class_mask = PCI_CLASS_SUBCLASS_MASK << 8,
- .vendor = PCI_VENDOR_ID_VLSI,
- .device = PCI_DEVICE_ID_VLSI_82C147,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { /* all zeroes */ }
-};
-
-MODULE_DEVICE_TABLE(pci, vlsi_irda_table);
-
-/********************************************************/
-
-/* clksrc: which clock source to be used
- * 0: auto - try PLL, fallback to 40MHz XCLK
- * 1: on-chip 48MHz PLL
- * 2: external 48MHz XCLK
- * 3: external 40MHz XCLK (HP OB-800)
- */
-
-static int clksrc = 0; /* default is 0(auto) */
-module_param(clksrc, int, 0);
-MODULE_PARM_DESC(clksrc, "clock input source selection");
-
-/* ringsize: size of the tx and rx descriptor rings
- * independent for tx and rx
- * specify as ringsize=tx[,rx]
- * allowed values: 4, 8, 16, 32, 64
- * Due to the IrDA 1.x max. allowed window size=7,
- * there should be no gain when using rings larger than 8
- */
-
-static int ringsize[] = {8,8}; /* default is tx=8 / rx=8 */
-module_param_array(ringsize, int, NULL, 0);
-MODULE_PARM_DESC(ringsize, "TX, RX ring descriptor size");
-
-/* sirpulse: tuning of the SIR pulse width within IrPHY 1.3 limits
- * 0: very short, 1.5us (exception: 6us at 2.4 kbaud)
- * 1: nominal 3/16 bittime width
- * note: IrDA compliant peer devices should be happy regardless
- * which one is used. Primary goal is to save some power
- * on the sender's side - at 9.6kbaud for example the short
- * pulse width saves more than 90% of the transmitted IR power.
- */
-
-static int sirpulse = 1; /* default is 3/16 bittime */
-module_param(sirpulse, int, 0);
-MODULE_PARM_DESC(sirpulse, "SIR pulse width tuning");
-
-/* qos_mtt_bits: encoded min-turn-time value we require the peer device
- * to use before transmitting to us. "Type 1" (per-station)
- * bitfield according to IrLAP definition (section 6.6.8)
- * Don't know which transceiver is used by my OB800 - the
- * pretty common HP HDLS-1100 requires 1 msec - so lets use this.
- */
-
-static int qos_mtt_bits = 0x07; /* default is 1 ms or more */
-module_param(qos_mtt_bits, int, 0);
-MODULE_PARM_DESC(qos_mtt_bits, "IrLAP bitfield representing min-turn-time");
-
-/********************************************************/
-
-static void vlsi_reg_debug(unsigned iobase, const char *s)
-{
- int i;
-
- printk(KERN_DEBUG "%s: ", s);
- for (i = 0; i < 0x20; i++)
- printk("%02x", (unsigned)inb((iobase+i)));
- printk("\n");
-}
-
-static void vlsi_ring_debug(struct vlsi_ring *r)
-{
- struct ring_descr *rd;
- unsigned i;
-
- printk(KERN_DEBUG "%s - ring %p / size %u / mask 0x%04x / len %u / dir %d / hw %p\n",
- __func__, r, r->size, r->mask, r->len, r->dir, r->rd[0].hw);
- printk(KERN_DEBUG "%s - head = %d / tail = %d\n", __func__,
- atomic_read(&r->head) & r->mask, atomic_read(&r->tail) & r->mask);
- for (i = 0; i < r->size; i++) {
- rd = &r->rd[i];
- printk(KERN_DEBUG "%s - ring descr %u: ", __func__, i);
- printk("skb=%p data=%p hw=%p\n", rd->skb, rd->buf, rd->hw);
- printk(KERN_DEBUG "%s - hw: status=%02x count=%u addr=0x%08x\n",
- __func__, (unsigned) rd_get_status(rd),
- (unsigned) rd_get_count(rd), (unsigned) rd_get_addr(rd));
- }
-}
-
-/********************************************************/
-
-/* needed regardless of CONFIG_PROC_FS */
-static struct proc_dir_entry *vlsi_proc_root = NULL;
-
-#ifdef CONFIG_PROC_FS
-
-static void vlsi_proc_pdev(struct seq_file *seq, struct pci_dev *pdev)
-{
- unsigned iobase = pci_resource_start(pdev, 0);
- unsigned i;
-
- seq_printf(seq, "\n%s (vid/did: [%04x:%04x])\n",
- pci_name(pdev), (int)pdev->vendor, (int)pdev->device);
- seq_printf(seq, "pci-power-state: %u\n", (unsigned) pdev->current_state);
- seq_printf(seq, "resources: irq=%u / io=0x%04x / dma_mask=0x%016Lx\n",
- pdev->irq, (unsigned)pci_resource_start(pdev, 0), (unsigned long long)pdev->dma_mask);
- seq_puts(seq, "hw registers: ");
- for (i = 0; i < 0x20; i++)
- seq_printf(seq, "%02x", (unsigned)inb((iobase+i)));
- seq_putc(seq, '\n');
-}
-
-static void vlsi_proc_ndev(struct seq_file *seq, struct net_device *ndev)
-{
- vlsi_irda_dev_t *idev = netdev_priv(ndev);
- u8 byte;
- u16 word;
- s32 sec, usec;
- unsigned iobase = ndev->base_addr;
-
- seq_printf(seq, "\n%s link state: %s / %s / %s / %s\n", ndev->name,
- netif_device_present(ndev) ? "attached" : "detached",
- netif_running(ndev) ? "running" : "not running",
- netif_carrier_ok(ndev) ? "carrier ok" : "no carrier",
- netif_queue_stopped(ndev) ? "queue stopped" : "queue running");
-
- if (!netif_running(ndev))
- return;
-
- seq_puts(seq, "\nhw-state:\n");
- pci_read_config_byte(idev->pdev, VLSI_PCI_IRMISC, &byte);
- seq_printf(seq, "IRMISC:%s%s%s uart%s",
- (byte&IRMISC_IRRAIL) ? " irrail" : "",
- (byte&IRMISC_IRPD) ? " irpd" : "",
- (byte&IRMISC_UARTTST) ? " uarttest" : "",
- (byte&IRMISC_UARTEN) ? "@" : " disabled\n");
- if (byte&IRMISC_UARTEN) {
- seq_printf(seq, "0x%s\n",
- (byte&2) ? ((byte&1) ? "3e8" : "2e8")
- : ((byte&1) ? "3f8" : "2f8"));
- }
- pci_read_config_byte(idev->pdev, VLSI_PCI_CLKCTL, &byte);
- seq_printf(seq, "CLKCTL: PLL %s%s%s / clock %s / wakeup %s\n",
- (byte&CLKCTL_PD_INV) ? "powered" : "down",
- (byte&CLKCTL_LOCK) ? " locked" : "",
- (byte&CLKCTL_EXTCLK) ? ((byte&CLKCTL_XCKSEL)?" / 40 MHz XCLK":" / 48 MHz XCLK") : "",
- (byte&CLKCTL_CLKSTP) ? "stopped" : "running",
- (byte&CLKCTL_WAKE) ? "enabled" : "disabled");
- pci_read_config_byte(idev->pdev, VLSI_PCI_MSTRPAGE, &byte);
- seq_printf(seq, "MSTRPAGE: 0x%02x\n", (unsigned)byte);
-
- byte = inb(iobase+VLSI_PIO_IRINTR);
- seq_printf(seq, "IRINTR:%s%s%s%s%s%s%s%s\n",
- (byte&IRINTR_ACTEN) ? " ACTEN" : "",
- (byte&IRINTR_RPKTEN) ? " RPKTEN" : "",
- (byte&IRINTR_TPKTEN) ? " TPKTEN" : "",
- (byte&IRINTR_OE_EN) ? " OE_EN" : "",
- (byte&IRINTR_ACTIVITY) ? " ACTIVITY" : "",
- (byte&IRINTR_RPKTINT) ? " RPKTINT" : "",
- (byte&IRINTR_TPKTINT) ? " TPKTINT" : "",
- (byte&IRINTR_OE_INT) ? " OE_INT" : "");
- word = inw(iobase+VLSI_PIO_RINGPTR);
- seq_printf(seq, "RINGPTR: rx=%u / tx=%u\n", RINGPTR_GET_RX(word), RINGPTR_GET_TX(word));
- word = inw(iobase+VLSI_PIO_RINGBASE);
- seq_printf(seq, "RINGBASE: busmap=0x%08x\n",
- ((unsigned)word << 10)|(MSTRPAGE_VALUE<<24));
- word = inw(iobase+VLSI_PIO_RINGSIZE);
- seq_printf(seq, "RINGSIZE: rx=%u / tx=%u\n", RINGSIZE_TO_RXSIZE(word),
- RINGSIZE_TO_TXSIZE(word));
-
- word = inw(iobase+VLSI_PIO_IRCFG);
- seq_printf(seq, "IRCFG:%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
- (word&IRCFG_LOOP) ? " LOOP" : "",
- (word&IRCFG_ENTX) ? " ENTX" : "",
- (word&IRCFG_ENRX) ? " ENRX" : "",
- (word&IRCFG_MSTR) ? " MSTR" : "",
- (word&IRCFG_RXANY) ? " RXANY" : "",
- (word&IRCFG_CRC16) ? " CRC16" : "",
- (word&IRCFG_FIR) ? " FIR" : "",
- (word&IRCFG_MIR) ? " MIR" : "",
- (word&IRCFG_SIR) ? " SIR" : "",
- (word&IRCFG_SIRFILT) ? " SIRFILT" : "",
- (word&IRCFG_SIRTEST) ? " SIRTEST" : "",
- (word&IRCFG_TXPOL) ? " TXPOL" : "",
- (word&IRCFG_RXPOL) ? " RXPOL" : "");
- word = inw(iobase+VLSI_PIO_IRENABLE);
- seq_printf(seq, "IRENABLE:%s%s%s%s%s%s%s%s\n",
- (word&IRENABLE_PHYANDCLOCK) ? " PHYANDCLOCK" : "",
- (word&IRENABLE_CFGER) ? " CFGERR" : "",
- (word&IRENABLE_FIR_ON) ? " FIR_ON" : "",
- (word&IRENABLE_MIR_ON) ? " MIR_ON" : "",
- (word&IRENABLE_SIR_ON) ? " SIR_ON" : "",
- (word&IRENABLE_ENTXST) ? " ENTXST" : "",
- (word&IRENABLE_ENRXST) ? " ENRXST" : "",
- (word&IRENABLE_CRC16_ON) ? " CRC16_ON" : "");
- word = inw(iobase+VLSI_PIO_PHYCTL);
- seq_printf(seq, "PHYCTL: baud-divisor=%u / pulsewidth=%u / preamble=%u\n",
- (unsigned)PHYCTL_TO_BAUD(word),
- (unsigned)PHYCTL_TO_PLSWID(word),
- (unsigned)PHYCTL_TO_PREAMB(word));
- word = inw(iobase+VLSI_PIO_NPHYCTL);
- seq_printf(seq, "NPHYCTL: baud-divisor=%u / pulsewidth=%u / preamble=%u\n",
- (unsigned)PHYCTL_TO_BAUD(word),
- (unsigned)PHYCTL_TO_PLSWID(word),
- (unsigned)PHYCTL_TO_PREAMB(word));
- word = inw(iobase+VLSI_PIO_MAXPKT);
- seq_printf(seq, "MAXPKT: max. rx packet size = %u\n", word);
- word = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK;
- seq_printf(seq, "RCVBCNT: rx-fifo filling level = %u\n", word);
-
- seq_puts(seq, "\nsw-state:\n");
- seq_printf(seq, "IrPHY setup: %d baud - %s encoding\n", idev->baud,
- (idev->mode==IFF_SIR)?"SIR":((idev->mode==IFF_MIR)?"MIR":"FIR"));
- sec = div_s64_rem(ktime_us_delta(ktime_get(), idev->last_rx),
- USEC_PER_SEC, &usec);
- seq_printf(seq, "last rx: %ul.%06u sec\n", sec, usec);
-
- seq_printf(seq, "RX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu",
- ndev->stats.rx_packets, ndev->stats.rx_bytes, ndev->stats.rx_errors,
- ndev->stats.rx_dropped);
- seq_printf(seq, " / overrun=%lu / length=%lu / frame=%lu / crc=%lu\n",
- ndev->stats.rx_over_errors, ndev->stats.rx_length_errors,
- ndev->stats.rx_frame_errors, ndev->stats.rx_crc_errors);
- seq_printf(seq, "TX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu / fifo=%lu\n",
- ndev->stats.tx_packets, ndev->stats.tx_bytes, ndev->stats.tx_errors,
- ndev->stats.tx_dropped, ndev->stats.tx_fifo_errors);
-
-}
-
-static void vlsi_proc_ring(struct seq_file *seq, struct vlsi_ring *r)
-{
- struct ring_descr *rd;
- unsigned i, j;
- int h, t;
-
- seq_printf(seq, "size %u / mask 0x%04x / len %u / dir %d / hw %p\n",
- r->size, r->mask, r->len, r->dir, r->rd[0].hw);
- h = atomic_read(&r->head) & r->mask;
- t = atomic_read(&r->tail) & r->mask;
- seq_printf(seq, "head = %d / tail = %d ", h, t);
- if (h == t)
- seq_puts(seq, "(empty)\n");
- else {
- if (((t+1)&r->mask) == h)
- seq_puts(seq, "(full)\n");
- else
- seq_printf(seq, "(level = %d)\n", ((unsigned)(t-h) & r->mask));
- rd = &r->rd[h];
- j = (unsigned) rd_get_count(rd);
- seq_printf(seq, "current: rd = %d / status = %02x / len = %u\n",
- h, (unsigned)rd_get_status(rd), j);
- if (j > 0) {
- seq_printf(seq, " data: %*ph\n",
- min_t(unsigned, j, 20), rd->buf);
- }
- }
- for (i = 0; i < r->size; i++) {
- rd = &r->rd[i];
- seq_printf(seq, "> ring descr %u: ", i);
- seq_printf(seq, "skb=%p data=%p hw=%p\n", rd->skb, rd->buf, rd->hw);
- seq_printf(seq, " hw: status=%02x count=%u busaddr=0x%08x\n",
- (unsigned) rd_get_status(rd),
- (unsigned) rd_get_count(rd), (unsigned) rd_get_addr(rd));
- }
-}
-
-static int vlsi_seq_show(struct seq_file *seq, void *v)
-{
- struct net_device *ndev = seq->private;
- vlsi_irda_dev_t *idev = netdev_priv(ndev);
- unsigned long flags;
-
- seq_printf(seq, "\n%s %s\n\n", DRIVER_NAME, DRIVER_VERSION);
- seq_printf(seq, "clksrc: %s\n",
- (clksrc>=2) ? ((clksrc==3)?"40MHz XCLK":"48MHz XCLK")
- : ((clksrc==1)?"48MHz PLL":"autodetect"));
- seq_printf(seq, "ringsize: tx=%d / rx=%d\n",
- ringsize[0], ringsize[1]);
- seq_printf(seq, "sirpulse: %s\n", (sirpulse)?"3/16 bittime":"short");
- seq_printf(seq, "qos_mtt_bits: 0x%02x\n", (unsigned)qos_mtt_bits);
-
- spin_lock_irqsave(&idev->lock, flags);
- if (idev->pdev != NULL) {
- vlsi_proc_pdev(seq, idev->pdev);
-
- if (idev->pdev->current_state == 0)
- vlsi_proc_ndev(seq, ndev);
- else
- seq_printf(seq, "\nPCI controller down - resume_ok = %d\n",
- idev->resume_ok);
- if (netif_running(ndev) && idev->rx_ring && idev->tx_ring) {
- seq_puts(seq, "\n--------- RX ring -----------\n\n");
- vlsi_proc_ring(seq, idev->rx_ring);
- seq_puts(seq, "\n--------- TX ring -----------\n\n");
- vlsi_proc_ring(seq, idev->tx_ring);
- }
- }
- seq_putc(seq, '\n');
- spin_unlock_irqrestore(&idev->lock, flags);
-
- return 0;
-}
-
-static int vlsi_seq_open(struct inode *inode, struct file *file)
-{
- return single_open(file, vlsi_seq_show, PDE_DATA(inode));
-}
-
-static const struct file_operations vlsi_proc_fops = {
- .owner = THIS_MODULE,
- .open = vlsi_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-#define VLSI_PROC_FOPS (&vlsi_proc_fops)
-
-#else /* CONFIG_PROC_FS */
-#define VLSI_PROC_FOPS NULL
-#endif
-
-/********************************************************/
-
-static struct vlsi_ring *vlsi_alloc_ring(struct pci_dev *pdev, struct ring_descr_hw *hwmap,
- unsigned size, unsigned len, int dir)
-{
- struct vlsi_ring *r;
- struct ring_descr *rd;
- unsigned i, j;
- dma_addr_t busaddr;
-
- if (!size || ((size-1)&size)!=0) /* must be >0 and power of 2 */
- return NULL;
-
- r = kmalloc(sizeof(*r) + size * sizeof(struct ring_descr), GFP_KERNEL);
- if (!r)
- return NULL;
- memset(r, 0, sizeof(*r));
-
- r->pdev = pdev;
- r->dir = dir;
- r->len = len;
- r->rd = (struct ring_descr *)(r+1);
- r->mask = size - 1;
- r->size = size;
- atomic_set(&r->head, 0);
- atomic_set(&r->tail, 0);
-
- for (i = 0; i < size; i++) {
- rd = r->rd + i;
- memset(rd, 0, sizeof(*rd));
- rd->hw = hwmap + i;
- rd->buf = kmalloc(len, GFP_KERNEL|GFP_DMA);
- if (rd->buf)
- busaddr = pci_map_single(pdev, rd->buf, len, dir);
- if (rd->buf == NULL || pci_dma_mapping_error(pdev, busaddr)) {
- if (rd->buf) {
- net_err_ratelimited("%s: failed to create PCI-MAP for %p\n",
- __func__, rd->buf);
- kfree(rd->buf);
- rd->buf = NULL;
- }
- for (j = 0; j < i; j++) {
- rd = r->rd + j;
- busaddr = rd_get_addr(rd);
- rd_set_addr_status(rd, 0, 0);
- pci_unmap_single(pdev, busaddr, len, dir);
- kfree(rd->buf);
- rd->buf = NULL;
- }
- kfree(r);
- return NULL;
- }
- rd_set_addr_status(rd, busaddr, 0);
- /* initially, the dma buffer is owned by the CPU */
- rd->skb = NULL;
- }
- return r;
-}
-
-static int vlsi_free_ring(struct vlsi_ring *r)
-{
- struct ring_descr *rd;
- unsigned i;
- dma_addr_t busaddr;
-
- for (i = 0; i < r->size; i++) {
- rd = r->rd + i;
- if (rd->skb)
- dev_kfree_skb_any(rd->skb);
- busaddr = rd_get_addr(rd);
- rd_set_addr_status(rd, 0, 0);
- if (busaddr)
- pci_unmap_single(r->pdev, busaddr, r->len, r->dir);
- kfree(rd->buf);
- }
- kfree(r);
- return 0;
-}
-
-static int vlsi_create_hwif(vlsi_irda_dev_t *idev)
-{
- char *ringarea;
- struct ring_descr_hw *hwmap;
-
- idev->virtaddr = NULL;
- idev->busaddr = 0;
-
- ringarea = pci_zalloc_consistent(idev->pdev, HW_RING_AREA_SIZE,
- &idev->busaddr);
- if (!ringarea)
- goto out;
-
- hwmap = (struct ring_descr_hw *)ringarea;
- idev->rx_ring = vlsi_alloc_ring(idev->pdev, hwmap, ringsize[1],
- XFER_BUF_SIZE, PCI_DMA_FROMDEVICE);
- if (idev->rx_ring == NULL)
- goto out_unmap;
-
- hwmap += MAX_RING_DESCR;
- idev->tx_ring = vlsi_alloc_ring(idev->pdev, hwmap, ringsize[0],
- XFER_BUF_SIZE, PCI_DMA_TODEVICE);
- if (idev->tx_ring == NULL)
- goto out_free_rx;
-
- idev->virtaddr = ringarea;
- return 0;
-
-out_free_rx:
- vlsi_free_ring(idev->rx_ring);
-out_unmap:
- idev->rx_ring = idev->tx_ring = NULL;
- pci_free_consistent(idev->pdev, HW_RING_AREA_SIZE, ringarea, idev->busaddr);
- idev->busaddr = 0;
-out:
- return -ENOMEM;
-}
-
-static int vlsi_destroy_hwif(vlsi_irda_dev_t *idev)
-{
- vlsi_free_ring(idev->rx_ring);
- vlsi_free_ring(idev->tx_ring);
- idev->rx_ring = idev->tx_ring = NULL;
-
- if (idev->busaddr)
- pci_free_consistent(idev->pdev,HW_RING_AREA_SIZE,idev->virtaddr,idev->busaddr);
-
- idev->virtaddr = NULL;
- idev->busaddr = 0;
-
- return 0;
-}
-
-/********************************************************/
-
-static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd)
-{
- u16 status;
- int crclen, len = 0;
- struct sk_buff *skb;
- int ret = 0;
- struct net_device *ndev = pci_get_drvdata(r->pdev);
- vlsi_irda_dev_t *idev = netdev_priv(ndev);
-
- pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir);
- /* dma buffer now owned by the CPU */
- status = rd_get_status(rd);
- if (status & RD_RX_ERROR) {
- if (status & RD_RX_OVER)
- ret |= VLSI_RX_OVER;
- if (status & RD_RX_LENGTH)
- ret |= VLSI_RX_LENGTH;
- if (status & RD_RX_PHYERR)
- ret |= VLSI_RX_FRAME;
- if (status & RD_RX_CRCERR)
- ret |= VLSI_RX_CRC;
- goto done;
- }
-
- len = rd_get_count(rd);
- crclen = (idev->mode==IFF_FIR) ? sizeof(u32) : sizeof(u16);
- len -= crclen; /* remove trailing CRC */
- if (len <= 0) {
- pr_debug("%s: strange frame (len=%d)\n", __func__, len);
- ret |= VLSI_RX_DROP;
- goto done;
- }
-
- if (idev->mode == IFF_SIR) { /* hw checks CRC in MIR, FIR mode */
-
- /* rd->buf is a streaming PCI_DMA_FROMDEVICE map. Doing the
- * endian-adjustment there just in place will dirty a cache line
- * which belongs to the map and thus we must be sure it will
- * get flushed before giving the buffer back to hardware.
- * vlsi_fill_rx() will do this anyway - but here we rely on.
- */
- le16_to_cpus(rd->buf+len);
- if (irda_calc_crc16(INIT_FCS,rd->buf,len+crclen) != GOOD_FCS) {
- pr_debug("%s: crc error\n", __func__);
- ret |= VLSI_RX_CRC;
- goto done;
- }
- }
-
- if (!rd->skb) {
- net_warn_ratelimited("%s: rx packet lost\n", __func__);
- ret |= VLSI_RX_DROP;
- goto done;
- }
-
- skb = rd->skb;
- rd->skb = NULL;
- skb->dev = ndev;
- skb_put_data(skb, rd->buf, len);
- skb_reset_mac_header(skb);
- if (in_interrupt())
- netif_rx(skb);
- else
- netif_rx_ni(skb);
-
-done:
- rd_set_status(rd, 0);
- rd_set_count(rd, 0);
- /* buffer still owned by CPU */
-
- return (ret) ? -ret : len;
-}
-
-static void vlsi_fill_rx(struct vlsi_ring *r)
-{
- struct ring_descr *rd;
-
- for (rd = ring_last(r); rd != NULL; rd = ring_put(r)) {
- if (rd_is_active(rd)) {
- net_warn_ratelimited("%s: driver bug: rx descr race with hw\n",
- __func__);
- vlsi_ring_debug(r);
- break;
- }
- if (!rd->skb) {
- rd->skb = dev_alloc_skb(IRLAP_SKB_ALLOCSIZE);
- if (rd->skb) {
- skb_reserve(rd->skb,1);
- rd->skb->protocol = htons(ETH_P_IRDA);
- }
- else
- break; /* probably not worth logging? */
- }
- /* give dma buffer back to busmaster */
- pci_dma_sync_single_for_device(r->pdev, rd_get_addr(rd), r->len, r->dir);
- rd_activate(rd);
- }
-}
-
-static void vlsi_rx_interrupt(struct net_device *ndev)
-{
- vlsi_irda_dev_t *idev = netdev_priv(ndev);
- struct vlsi_ring *r = idev->rx_ring;
- struct ring_descr *rd;
- int ret;
-
- for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) {
-
- if (rd_is_active(rd))
- break;
-
- ret = vlsi_process_rx(r, rd);
-
- if (ret < 0) {
- ret = -ret;
- ndev->stats.rx_errors++;
- if (ret & VLSI_RX_DROP)
- ndev->stats.rx_dropped++;
- if (ret & VLSI_RX_OVER)
- ndev->stats.rx_over_errors++;
- if (ret & VLSI_RX_LENGTH)
- ndev->stats.rx_length_errors++;
- if (ret & VLSI_RX_FRAME)
- ndev->stats.rx_frame_errors++;
- if (ret & VLSI_RX_CRC)
- ndev->stats.rx_crc_errors++;
- }
- else if (ret > 0) {
- ndev->stats.rx_packets++;
- ndev->stats.rx_bytes += ret;
- }
- }
-
- idev->last_rx = ktime_get(); /* remember "now" for later mtt delay */
-
- vlsi_fill_rx(r);
-
- if (ring_first(r) == NULL) {
- /* we are in big trouble, if this should ever happen */
- net_err_ratelimited("%s: rx ring exhausted!\n", __func__);
- vlsi_ring_debug(r);
- }
- else
- outw(0, ndev->base_addr+VLSI_PIO_PROMPT);
-}
-
-/* caller must have stopped the controller from busmastering */
-
-static void vlsi_unarm_rx(vlsi_irda_dev_t *idev)
-{
- struct net_device *ndev = pci_get_drvdata(idev->pdev);
- struct vlsi_ring *r = idev->rx_ring;
- struct ring_descr *rd;
- int ret;
-
- for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) {
-
- ret = 0;
- if (rd_is_active(rd)) {
- rd_set_status(rd, 0);
- if (rd_get_count(rd)) {
- pr_debug("%s - dropping rx packet\n", __func__);
- ret = -VLSI_RX_DROP;
- }
- rd_set_count(rd, 0);
- pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir);
- if (rd->skb) {
- dev_kfree_skb_any(rd->skb);
- rd->skb = NULL;
- }
- }
- else
- ret = vlsi_process_rx(r, rd);
-
- if (ret < 0) {
- ret = -ret;
- ndev->stats.rx_errors++;
- if (ret & VLSI_RX_DROP)
- ndev->stats.rx_dropped++;
- if (ret & VLSI_RX_OVER)
- ndev->stats.rx_over_errors++;
- if (ret & VLSI_RX_LENGTH)
- ndev->stats.rx_length_errors++;
- if (ret & VLSI_RX_FRAME)
- ndev->stats.rx_frame_errors++;
- if (ret & VLSI_RX_CRC)
- ndev->stats.rx_crc_errors++;
- }
- else if (ret > 0) {
- ndev->stats.rx_packets++;
- ndev->stats.rx_bytes += ret;
- }
- }
-}
-
-/********************************************************/
-
-static int vlsi_process_tx(struct vlsi_ring *r, struct ring_descr *rd)
-{
- u16 status;
- int len;
- int ret;
-
- pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir);
- /* dma buffer now owned by the CPU */
- status = rd_get_status(rd);
- if (status & RD_TX_UNDRN)
- ret = VLSI_TX_FIFO;
- else
- ret = 0;
- rd_set_status(rd, 0);
-
- if (rd->skb) {
- len = rd->skb->len;
- dev_kfree_skb_any(rd->skb);
- rd->skb = NULL;
- }
- else /* tx-skb already freed? - should never happen */
- len = rd_get_count(rd); /* incorrect for SIR! (due to wrapping) */
-
- rd_set_count(rd, 0);
- /* dma buffer still owned by the CPU */
-
- return (ret) ? -ret : len;
-}
-
-static int vlsi_set_baud(vlsi_irda_dev_t *idev, unsigned iobase)
-{
- u16 nphyctl;
- u16 config;
- unsigned mode;
- int ret;
- int baudrate;
- int fifocnt;
-
- baudrate = idev->new_baud;
- pr_debug("%s: %d -> %d\n", __func__, idev->baud, idev->new_baud);
- if (baudrate == 4000000) {
- mode = IFF_FIR;
- config = IRCFG_FIR;
- nphyctl = PHYCTL_FIR;
- }
- else if (baudrate == 1152000) {
- mode = IFF_MIR;
- config = IRCFG_MIR | IRCFG_CRC16;
- nphyctl = PHYCTL_MIR(clksrc==3);
- }
- else {
- mode = IFF_SIR;
- config = IRCFG_SIR | IRCFG_SIRFILT | IRCFG_RXANY;
- switch(baudrate) {
- default:
- net_warn_ratelimited("%s: undefined baudrate %d - fallback to 9600!\n",
- __func__, baudrate);
- baudrate = 9600;
- /* fallthru */
- case 2400:
- case 9600:
- case 19200:
- case 38400:
- case 57600:
- case 115200:
- nphyctl = PHYCTL_SIR(baudrate,sirpulse,clksrc==3);
- break;
- }
- }
- config |= IRCFG_MSTR | IRCFG_ENRX;
-
- fifocnt = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK;
- if (fifocnt != 0) {
- pr_debug("%s: rx fifo not empty(%d)\n", __func__, fifocnt);
- }
-
- outw(0, iobase+VLSI_PIO_IRENABLE);
- outw(config, iobase+VLSI_PIO_IRCFG);
- outw(nphyctl, iobase+VLSI_PIO_NPHYCTL);
- wmb();
- outw(IRENABLE_PHYANDCLOCK, iobase+VLSI_PIO_IRENABLE);
- mb();
-
- udelay(1); /* chip applies IRCFG on next rising edge of its 8MHz clock */
-
- /* read back settings for validation */
-
- config = inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_MASK;
-
- if (mode == IFF_FIR)
- config ^= IRENABLE_FIR_ON;
- else if (mode == IFF_MIR)
- config ^= (IRENABLE_MIR_ON|IRENABLE_CRC16_ON);
- else
- config ^= IRENABLE_SIR_ON;
-
- if (config != (IRENABLE_PHYANDCLOCK|IRENABLE_ENRXST)) {
- net_warn_ratelimited("%s: failed to set %s mode!\n",
- __func__,
- mode == IFF_SIR ? "SIR" :
- mode == IFF_MIR ? "MIR" : "FIR");
- ret = -1;
- }
- else {
- if (inw(iobase+VLSI_PIO_PHYCTL) != nphyctl) {
- net_warn_ratelimited("%s: failed to apply baudrate %d\n",
- __func__, baudrate);
- ret = -1;
- }
- else {
- idev->mode = mode;
- idev->baud = baudrate;
- idev->new_baud = 0;
- ret = 0;
- }
- }
-
- if (ret)
- vlsi_reg_debug(iobase,__func__);
-
- return ret;
-}
-
-static netdev_tx_t vlsi_hard_start_xmit(struct sk_buff *skb,
- struct net_device *ndev)
-{
- vlsi_irda_dev_t *idev = netdev_priv(ndev);
- struct vlsi_ring *r = idev->tx_ring;
- struct ring_descr *rd;
- unsigned long flags;
- unsigned iobase = ndev->base_addr;
- u8 status;
- u16 config;
- int mtt, diff;
- int len, speed;
- char *msg = NULL;
-
- speed = irda_get_next_speed(skb);
- spin_lock_irqsave(&idev->lock, flags);
- if (speed != -1 && speed != idev->baud) {
- netif_stop_queue(ndev);
- idev->new_baud = speed;
- status = RD_TX_CLRENTX; /* stop tx-ring after this frame */
- }
- else
- status = 0;
-
- if (skb->len == 0) {
- /* handle zero packets - should be speed change */
- if (status == 0) {
- msg = "bogus zero-length packet";
- goto drop_unlock;
- }
-
- /* due to the completely asynch tx operation we might have
- * IrLAP racing with the hardware here, f.e. if the controller
- * is just sending the last packet with current speed while
- * the LAP is already switching the speed using synchronous
- * len=0 packet. Immediate execution would lead to hw lockup
- * requiring a powercycle to reset. Good candidate to trigger
- * this is the final UA:RSP packet after receiving a DISC:CMD
- * when getting the LAP down.
- * Note that we are not protected by the queue_stop approach
- * because the final UA:RSP arrives _without_ request to apply
- * new-speed-after-this-packet - hence the driver doesn't know
- * this was the last packet and doesn't stop the queue. So the
- * forced switch to default speed from LAP gets through as fast
- * as only some 10 usec later while the UA:RSP is still processed
- * by the hardware and we would get screwed.
- */
-
- if (ring_first(idev->tx_ring) == NULL) {
- /* no race - tx-ring already empty */
- vlsi_set_baud(idev, iobase);
- netif_wake_queue(ndev);
- }
- else
- ;
- /* keep the speed change pending like it would
- * for any len>0 packet. tx completion interrupt
- * will apply it when the tx ring becomes empty.
- */
- spin_unlock_irqrestore(&idev->lock, flags);
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
- }
-
- /* sanity checks - simply drop the packet */
-
- rd = ring_last(r);
- if (!rd) {
- msg = "ring full, but queue wasn't stopped";
- goto drop_unlock;
- }
-
- if (rd_is_active(rd)) {
- msg = "entry still owned by hw";
- goto drop_unlock;
- }
-
- if (!rd->buf) {
- msg = "tx ring entry without pci buffer";
- goto drop_unlock;
- }
-
- if (rd->skb) {
- msg = "ring entry with old skb still attached";
- goto drop_unlock;
- }
-
- /* no need for serialization or interrupt disable during mtt */
- spin_unlock_irqrestore(&idev->lock, flags);
-
- if ((mtt = irda_get_mtt(skb)) > 0) {
- diff = ktime_us_delta(ktime_get(), idev->last_rx);
- if (mtt > diff)
- udelay(mtt - diff);
- /* must not sleep here - called under netif_tx_lock! */
- }
-
- /* tx buffer already owned by CPU due to pci_dma_sync_single_for_cpu()
- * after subsequent tx-completion
- */
-
- if (idev->mode == IFF_SIR) {
- status |= RD_TX_DISCRC; /* no hw-crc creation */
- len = async_wrap_skb(skb, rd->buf, r->len);
-
- /* Some rare worst case situation in SIR mode might lead to
- * potential buffer overflow. The wrapper detects this, returns
- * with a shortened frame (without FCS/EOF) but doesn't provide
- * any error indication about the invalid packet which we are
- * going to transmit.
- * Therefore we log if the buffer got filled to the point, where the
- * wrapper would abort, i.e. when there are less than 5 bytes left to
- * allow appending the FCS/EOF.
- */
-
- if (len >= r->len-5)
- net_warn_ratelimited("%s: possible buffer overflow with SIR wrapping!\n",
- __func__);
- }
- else {
- /* hw deals with MIR/FIR mode wrapping */
- status |= RD_TX_PULSE; /* send 2 us highspeed indication pulse */
- len = skb->len;
- if (len > r->len) {
- msg = "frame exceeds tx buffer length";
- goto drop;
- }
- else
- skb_copy_from_linear_data(skb, rd->buf, len);
- }
-
- rd->skb = skb; /* remember skb for tx-complete stats */
-
- rd_set_count(rd, len);
- rd_set_status(rd, status); /* not yet active! */
-
- /* give dma buffer back to busmaster-hw (flush caches to make
- * CPU-driven changes visible from the pci bus).
- */
-
- pci_dma_sync_single_for_device(r->pdev, rd_get_addr(rd), r->len, r->dir);
-
-/* Switching to TX mode here races with the controller
- * which may stop TX at any time when fetching an inactive descriptor
- * or one with CLR_ENTX set. So we switch on TX only, if TX was not running
- * _after_ the new descriptor was activated on the ring. This ensures
- * we will either find TX already stopped or we can be sure, there
- * will be a TX-complete interrupt even if the chip stopped doing
- * TX just after we found it still running. The ISR will then find
- * the non-empty ring and restart TX processing. The enclosing
- * spinlock provides the correct serialization to prevent race with isr.
- */
-
- spin_lock_irqsave(&idev->lock,flags);
-
- rd_activate(rd);
-
- if (!(inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_ENTXST)) {
- int fifocnt;
-
- fifocnt = inw(ndev->base_addr+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK;
- if (fifocnt != 0) {
- pr_debug("%s: rx fifo not empty(%d)\n",
- __func__, fifocnt);
- }
-
- config = inw(iobase+VLSI_PIO_IRCFG);
- mb();
- outw(config | IRCFG_ENTX, iobase+VLSI_PIO_IRCFG);
- wmb();
- outw(0, iobase+VLSI_PIO_PROMPT);
- }
-
- if (ring_put(r) == NULL) {
- netif_stop_queue(ndev);
- pr_debug("%s: tx ring full - queue stopped\n", __func__);
- }
- spin_unlock_irqrestore(&idev->lock, flags);
-
- return NETDEV_TX_OK;
-
-drop_unlock:
- spin_unlock_irqrestore(&idev->lock, flags);
-drop:
- net_warn_ratelimited("%s: dropping packet - %s\n", __func__, msg);
- dev_kfree_skb_any(skb);
- ndev->stats.tx_errors++;
- ndev->stats.tx_dropped++;
- /* Don't even think about returning NET_XMIT_DROP (=1) here!
- * In fact any retval!=0 causes the packet scheduler to requeue the
- * packet for later retry of transmission - which isn't exactly
- * what we want after we've just called dev_kfree_skb_any ;-)
- */
- return NETDEV_TX_OK;
-}
-
-static void vlsi_tx_interrupt(struct net_device *ndev)
-{
- vlsi_irda_dev_t *idev = netdev_priv(ndev);
- struct vlsi_ring *r = idev->tx_ring;
- struct ring_descr *rd;
- unsigned iobase;
- int ret;
- u16 config;
-
- for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) {
-
- if (rd_is_active(rd))
- break;
-
- ret = vlsi_process_tx(r, rd);
-
- if (ret < 0) {
- ret = -ret;
- ndev->stats.tx_errors++;
- if (ret & VLSI_TX_DROP)
- ndev->stats.tx_dropped++;
- if (ret & VLSI_TX_FIFO)
- ndev->stats.tx_fifo_errors++;
- }
- else if (ret > 0){
- ndev->stats.tx_packets++;
- ndev->stats.tx_bytes += ret;
- }
- }
-
- iobase = ndev->base_addr;
-
- if (idev->new_baud && rd == NULL) /* tx ring empty and speed change pending */
- vlsi_set_baud(idev, iobase);
-
- config = inw(iobase+VLSI_PIO_IRCFG);
- if (rd == NULL) /* tx ring empty: re-enable rx */
- outw((config & ~IRCFG_ENTX) | IRCFG_ENRX, iobase+VLSI_PIO_IRCFG);
-
- else if (!(inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_ENTXST)) {
- int fifocnt;
-
- fifocnt = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK;
- if (fifocnt != 0) {
- pr_debug("%s: rx fifo not empty(%d)\n",
- __func__, fifocnt);
- }
- outw(config | IRCFG_ENTX, iobase+VLSI_PIO_IRCFG);
- }
-
- outw(0, iobase+VLSI_PIO_PROMPT);
-
- if (netif_queue_stopped(ndev) && !idev->new_baud) {
- netif_wake_queue(ndev);
- pr_debug("%s: queue awoken\n", __func__);
- }
-}
-
-/* caller must have stopped the controller from busmastering */
-
-static void vlsi_unarm_tx(vlsi_irda_dev_t *idev)
-{
- struct net_device *ndev = pci_get_drvdata(idev->pdev);
- struct vlsi_ring *r = idev->tx_ring;
- struct ring_descr *rd;
- int ret;
-
- for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) {
-
- ret = 0;
- if (rd_is_active(rd)) {
- rd_set_status(rd, 0);
- rd_set_count(rd, 0);
- pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir);
- if (rd->skb) {
- dev_kfree_skb_any(rd->skb);
- rd->skb = NULL;
- }
- pr_debug("%s - dropping tx packet\n", __func__);
- ret = -VLSI_TX_DROP;
- }
- else
- ret = vlsi_process_tx(r, rd);
-
- if (ret < 0) {
- ret = -ret;
- ndev->stats.tx_errors++;
- if (ret & VLSI_TX_DROP)
- ndev->stats.tx_dropped++;
- if (ret & VLSI_TX_FIFO)
- ndev->stats.tx_fifo_errors++;
- }
- else if (ret > 0){
- ndev->stats.tx_packets++;
- ndev->stats.tx_bytes += ret;
- }
- }
-
-}
-
-/********************************************************/
-
-static int vlsi_start_clock(struct pci_dev *pdev)
-{
- u8 clkctl, lock;
- int i, count;
-
- if (clksrc < 2) { /* auto or PLL: try PLL */
- clkctl = CLKCTL_PD_INV | CLKCTL_CLKSTP;
- pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
-
- /* procedure to detect PLL lock synchronisation:
- * after 0.5 msec initial delay we expect to find 3 PLL lock
- * indications within 10 msec for successful PLL detection.
- */
- udelay(500);
- count = 0;
- for (i = 500; i <= 10000; i += 50) { /* max 10 msec */
- pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &lock);
- if (lock&CLKCTL_LOCK) {
- if (++count >= 3)
- break;
- }
- udelay(50);
- }
- if (count < 3) {
- if (clksrc == 1) { /* explicitly asked for PLL hence bail out */
- net_err_ratelimited("%s: no PLL or failed to lock!\n",
- __func__);
- clkctl = CLKCTL_CLKSTP;
- pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
- return -1;
- }
- else /* was: clksrc=0(auto) */
- clksrc = 3; /* fallback to 40MHz XCLK (OB800) */
-
- pr_debug("%s: PLL not locked, fallback to clksrc=%d\n",
- __func__, clksrc);
- }
- else
- clksrc = 1; /* got successful PLL lock */
- }
-
- if (clksrc != 1) {
- /* we get here if either no PLL detected in auto-mode or
- an external clock source was explicitly specified */
-
- clkctl = CLKCTL_EXTCLK | CLKCTL_CLKSTP;
- if (clksrc == 3)
- clkctl |= CLKCTL_XCKSEL;
- pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
-
- /* no way to test for working XCLK */
- }
- else
- pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &clkctl);
-
- /* ok, now going to connect the chip with the clock source */
-
- clkctl &= ~CLKCTL_CLKSTP;
- pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
-
- return 0;
-}
-
-static void vlsi_stop_clock(struct pci_dev *pdev)
-{
- u8 clkctl;
-
- /* disconnect chip from clock source */
- pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &clkctl);
- clkctl |= CLKCTL_CLKSTP;
- pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
-
- /* disable all clock sources */
- clkctl &= ~(CLKCTL_EXTCLK | CLKCTL_PD_INV);
- pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
-}
-
-/********************************************************/
-
-/* writing all-zero to the VLSI PCI IO register area seems to prevent
- * some occasional situations where the hardware fails (symptoms are
- * what appears as stalled tx/rx state machines, i.e. everything ok for
- * receive or transmit but hw makes no progress or is unable to access
- * the bus memory locations).
- * Best place to call this is immediately after/before the internal clock
- * gets started/stopped.
- */
-
-static inline void vlsi_clear_regs(unsigned iobase)
-{
- unsigned i;
- const unsigned chip_io_extent = 32;
-
- for (i = 0; i < chip_io_extent; i += sizeof(u16))
- outw(0, iobase + i);
-}
-
-static int vlsi_init_chip(struct pci_dev *pdev)
-{
- struct net_device *ndev = pci_get_drvdata(pdev);
- vlsi_irda_dev_t *idev = netdev_priv(ndev);
- unsigned iobase;
- u16 ptr;
-
- /* start the clock and clean the registers */
-
- if (vlsi_start_clock(pdev)) {
- net_err_ratelimited("%s: no valid clock source\n", __func__);
- return -1;
- }
- iobase = ndev->base_addr;
- vlsi_clear_regs(iobase);
-
- outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); /* w/c pending IRQ, disable all INT */
-
- outw(0, iobase+VLSI_PIO_IRENABLE); /* disable IrPHY-interface */
-
- /* disable everything, particularly IRCFG_MSTR - (also resetting the RING_PTR) */
-
- outw(0, iobase+VLSI_PIO_IRCFG);
- wmb();
-
- outw(MAX_PACKET_LENGTH, iobase+VLSI_PIO_MAXPKT); /* max possible value=0x0fff */
-
- outw(BUS_TO_RINGBASE(idev->busaddr), iobase+VLSI_PIO_RINGBASE);
-
- outw(TX_RX_TO_RINGSIZE(idev->tx_ring->size, idev->rx_ring->size),
- iobase+VLSI_PIO_RINGSIZE);
-
- ptr = inw(iobase+VLSI_PIO_RINGPTR);
- atomic_set(&idev->rx_ring->head, RINGPTR_GET_RX(ptr));
- atomic_set(&idev->rx_ring->tail, RINGPTR_GET_RX(ptr));
- atomic_set(&idev->tx_ring->head, RINGPTR_GET_TX(ptr));
- atomic_set(&idev->tx_ring->tail, RINGPTR_GET_TX(ptr));
-
- vlsi_set_baud(idev, iobase); /* idev->new_baud used as provided by caller */
-
- outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); /* just in case - w/c pending IRQ's */
- wmb();
-
- /* DO NOT BLINDLY ENABLE IRINTR_ACTEN!
- * basically every received pulse fires an ACTIVITY-INT
- * leading to >>1000 INT's per second instead of few 10
- */
-
- outb(IRINTR_RPKTEN|IRINTR_TPKTEN, iobase+VLSI_PIO_IRINTR);
-
- return 0;
-}
-
-static int vlsi_start_hw(vlsi_irda_dev_t *idev)
-{
- struct pci_dev *pdev = idev->pdev;
- struct net_device *ndev = pci_get_drvdata(pdev);
- unsigned iobase = ndev->base_addr;
- u8 byte;
-
- /* we don't use the legacy UART, disable its address decoding */
-
- pci_read_config_byte(pdev, VLSI_PCI_IRMISC, &byte);
- byte &= ~(IRMISC_UARTEN | IRMISC_UARTTST);
- pci_write_config_byte(pdev, VLSI_PCI_IRMISC, byte);
-
- /* enable PCI busmaster access to our 16MB page */
-
- pci_write_config_byte(pdev, VLSI_PCI_MSTRPAGE, MSTRPAGE_VALUE);
- pci_set_master(pdev);
-
- if (vlsi_init_chip(pdev) < 0) {
- pci_disable_device(pdev);
- return -1;
- }
-
- vlsi_fill_rx(idev->rx_ring);
-
- idev->last_rx = ktime_get(); /* first mtt may start from now on */
-
- outw(0, iobase+VLSI_PIO_PROMPT); /* kick hw state machine */
-
- return 0;
-}
-
-static int vlsi_stop_hw(vlsi_irda_dev_t *idev)
-{
- struct pci_dev *pdev = idev->pdev;
- struct net_device *ndev = pci_get_drvdata(pdev);
- unsigned iobase = ndev->base_addr;
- unsigned long flags;
-
- spin_lock_irqsave(&idev->lock,flags);
- outw(0, iobase+VLSI_PIO_IRENABLE);
- outw(0, iobase+VLSI_PIO_IRCFG); /* disable everything */
-
- /* disable and w/c irqs */
- outb(0, iobase+VLSI_PIO_IRINTR);
- wmb();
- outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR);
- spin_unlock_irqrestore(&idev->lock,flags);
-
- vlsi_unarm_tx(idev);
- vlsi_unarm_rx(idev);
-
- vlsi_clear_regs(iobase);
- vlsi_stop_clock(pdev);
-
- pci_disable_device(pdev);
-
- return 0;
-}
-
-/**************************************************************/
-
-static void vlsi_tx_timeout(struct net_device *ndev)
-{
- vlsi_irda_dev_t *idev = netdev_priv(ndev);
-
-
- vlsi_reg_debug(ndev->base_addr, __func__);
- vlsi_ring_debug(idev->tx_ring);
-
- if (netif_running(ndev))
- netif_stop_queue(ndev);
-
- vlsi_stop_hw(idev);
-
- /* now simply restart the whole thing */
-
- if (!idev->new_baud)
- idev->new_baud = idev->baud; /* keep current baudrate */
-
- if (vlsi_start_hw(idev))
- net_err_ratelimited("%s: failed to restart hw - %s(%s) unusable!\n",
- __func__, pci_name(idev->pdev), ndev->name);
- else
- netif_start_queue(ndev);
-}
-
-static int vlsi_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
-{
- vlsi_irda_dev_t *idev = netdev_priv(ndev);
- struct if_irda_req *irq = (struct if_irda_req *) rq;
- unsigned long flags;
- u16 fifocnt;
- int ret = 0;
-
- switch (cmd) {
- case SIOCSBANDWIDTH:
- if (!capable(CAP_NET_ADMIN)) {
- ret = -EPERM;
- break;
- }
- spin_lock_irqsave(&idev->lock, flags);
- idev->new_baud = irq->ifr_baudrate;
- /* when called from userland there might be a minor race window here
- * if the stack tries to change speed concurrently - which would be
- * pretty strange anyway with the userland having full control...
- */
- vlsi_set_baud(idev, ndev->base_addr);
- spin_unlock_irqrestore(&idev->lock, flags);
- break;
- case SIOCSMEDIABUSY:
- if (!capable(CAP_NET_ADMIN)) {
- ret = -EPERM;
- break;
- }
- irda_device_set_media_busy(ndev, TRUE);
- break;
- case SIOCGRECEIVING:
- /* the best we can do: check whether there are any bytes in rx fifo.
- * The trustable window (in case some data arrives just afterwards)
- * may be as short as 1usec or so at 4Mbps.
- */
- fifocnt = inw(ndev->base_addr+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK;
- irq->ifr_receiving = (fifocnt!=0) ? 1 : 0;
- break;
- default:
- net_warn_ratelimited("%s: notsupp - cmd=%04x\n",
- __func__, cmd);
- ret = -EOPNOTSUPP;
- }
-
- return ret;
-}
-
-/********************************************************/
-
-static irqreturn_t vlsi_interrupt(int irq, void *dev_instance)
-{
- struct net_device *ndev = dev_instance;
- vlsi_irda_dev_t *idev = netdev_priv(ndev);
- unsigned iobase;
- u8 irintr;
- int boguscount = 5;
- unsigned long flags;
- int handled = 0;
-
- iobase = ndev->base_addr;
- spin_lock_irqsave(&idev->lock,flags);
- do {
- irintr = inb(iobase+VLSI_PIO_IRINTR);
- mb();
- outb(irintr, iobase+VLSI_PIO_IRINTR); /* acknowledge asap */
-
- if (!(irintr&=IRINTR_INT_MASK)) /* not our INT - probably shared */
- break;
-
- handled = 1;
-
- if (unlikely(!(irintr & ~IRINTR_ACTIVITY)))
- break; /* nothing todo if only activity */
-
- if (irintr&IRINTR_RPKTINT)
- vlsi_rx_interrupt(ndev);
-
- if (irintr&IRINTR_TPKTINT)
- vlsi_tx_interrupt(ndev);
-
- } while (--boguscount > 0);
- spin_unlock_irqrestore(&idev->lock,flags);
-
- if (boguscount <= 0)
- net_info_ratelimited("%s: too much work in interrupt!\n",
- __func__);
- return IRQ_RETVAL(handled);
-}
-
-/********************************************************/
-
-static int vlsi_open(struct net_device *ndev)
-{
- vlsi_irda_dev_t *idev = netdev_priv(ndev);
- int err = -EAGAIN;
- char hwname[32];
-
- if (pci_request_regions(idev->pdev, drivername)) {
- net_warn_ratelimited("%s: io resource busy\n", __func__);
- goto errout;
- }
- ndev->base_addr = pci_resource_start(idev->pdev,0);
- ndev->irq = idev->pdev->irq;
-
- /* under some rare occasions the chip apparently comes up with
- * IRQ's pending. We better w/c pending IRQ and disable them all
- */
-
- outb(IRINTR_INT_MASK, ndev->base_addr+VLSI_PIO_IRINTR);
-
- if (request_irq(ndev->irq, vlsi_interrupt, IRQF_SHARED,
- drivername, ndev)) {
- net_warn_ratelimited("%s: couldn't get IRQ: %d\n",
- __func__, ndev->irq);
- goto errout_io;
- }
-
- if ((err = vlsi_create_hwif(idev)) != 0)
- goto errout_irq;
-
- sprintf(hwname, "VLSI-FIR @ 0x%04x", (unsigned)ndev->base_addr);
- idev->irlap = irlap_open(ndev,&idev->qos,hwname);
- if (!idev->irlap)
- goto errout_free_ring;
-
- idev->last_rx = ktime_get(); /* first mtt may start from now on */
-
- idev->new_baud = 9600; /* start with IrPHY using 9600(SIR) mode */
-
- if ((err = vlsi_start_hw(idev)) != 0)
- goto errout_close_irlap;
-
- netif_start_queue(ndev);
-
- net_info_ratelimited("%s: device %s operational\n",
- __func__, ndev->name);
-
- return 0;
-
-errout_close_irlap:
- irlap_close(idev->irlap);
-errout_free_ring:
- vlsi_destroy_hwif(idev);
-errout_irq:
- free_irq(ndev->irq,ndev);
-errout_io:
- pci_release_regions(idev->pdev);
-errout:
- return err;
-}
-
-static int vlsi_close(struct net_device *ndev)
-{
- vlsi_irda_dev_t *idev = netdev_priv(ndev);
-
- netif_stop_queue(ndev);
-
- if (idev->irlap)
- irlap_close(idev->irlap);
- idev->irlap = NULL;
-
- vlsi_stop_hw(idev);
-
- vlsi_destroy_hwif(idev);
-
- free_irq(ndev->irq,ndev);
-
- pci_release_regions(idev->pdev);
-
- net_info_ratelimited("%s: device %s stopped\n", __func__, ndev->name);
-
- return 0;
-}
-
-static const struct net_device_ops vlsi_netdev_ops = {
- .ndo_open = vlsi_open,
- .ndo_stop = vlsi_close,
- .ndo_start_xmit = vlsi_hard_start_xmit,
- .ndo_do_ioctl = vlsi_ioctl,
- .ndo_tx_timeout = vlsi_tx_timeout,
-};
-
-static int vlsi_irda_init(struct net_device *ndev)
-{
- vlsi_irda_dev_t *idev = netdev_priv(ndev);
- struct pci_dev *pdev = idev->pdev;
-
- ndev->irq = pdev->irq;
- ndev->base_addr = pci_resource_start(pdev,0);
-
- /* PCI busmastering
- * see include file for details why we need these 2 masks, in this order!
- */
-
- if (pci_set_dma_mask(pdev,DMA_MASK_USED_BY_HW) ||
- pci_set_dma_mask(pdev,DMA_MASK_MSTRPAGE)) {
- net_err_ratelimited("%s: aborting due to PCI BM-DMA address limitations\n",
- __func__);
- return -1;
- }
-
- irda_init_max_qos_capabilies(&idev->qos);
-
- /* the VLSI82C147 does not support 576000! */
-
- idev->qos.baud_rate.bits = IR_2400 | IR_9600
- | IR_19200 | IR_38400 | IR_57600 | IR_115200
- | IR_1152000 | (IR_4000000 << 8);
-
- idev->qos.min_turn_time.bits = qos_mtt_bits;
-
- irda_qos_bits_to_value(&idev->qos);
-
- /* currently no public media definitions for IrDA */
-
- ndev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA;
- ndev->if_port = IF_PORT_UNKNOWN;
-
- ndev->netdev_ops = &vlsi_netdev_ops;
- ndev->watchdog_timeo = 500*HZ/1000; /* max. allowed turn time for IrLAP */
-
- SET_NETDEV_DEV(ndev, &pdev->dev);
-
- return 0;
-}
-
-/**************************************************************/
-
-static int
-vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
- struct net_device *ndev;
- vlsi_irda_dev_t *idev;
-
- if (pci_enable_device(pdev))
- goto out;
- else
- pdev->current_state = 0; /* hw must be running now */
-
- net_info_ratelimited("%s: IrDA PCI controller %s detected\n",
- drivername, pci_name(pdev));
-
- if ( !pci_resource_start(pdev,0) ||
- !(pci_resource_flags(pdev,0) & IORESOURCE_IO) ) {
- net_err_ratelimited("%s: bar 0 invalid", __func__);
- goto out_disable;
- }
-
- ndev = alloc_irdadev(sizeof(*idev));
- if (ndev==NULL) {
- net_err_ratelimited("%s: Unable to allocate device memory.\n",
- __func__);
- goto out_disable;
- }
-
- idev = netdev_priv(ndev);
-
- spin_lock_init(&idev->lock);
- mutex_init(&idev->mtx);
- mutex_lock(&idev->mtx);
- idev->pdev = pdev;
-
- if (vlsi_irda_init(ndev) < 0)
- goto out_freedev;
-
- if (register_netdev(ndev) < 0) {
- net_err_ratelimited("%s: register_netdev failed\n", __func__);
- goto out_freedev;
- }
-
- if (vlsi_proc_root != NULL) {
- struct proc_dir_entry *ent;
-
- ent = proc_create_data(ndev->name, S_IFREG|S_IRUGO,
- vlsi_proc_root, VLSI_PROC_FOPS, ndev);
- if (!ent) {
- net_warn_ratelimited("%s: failed to create proc entry\n",
- __func__);
- } else {
- proc_set_size(ent, 0);
- }
- idev->proc_entry = ent;
- }
- net_info_ratelimited("%s: registered device %s\n",
- drivername, ndev->name);
-
- pci_set_drvdata(pdev, ndev);
- mutex_unlock(&idev->mtx);
-
- return 0;
-
-out_freedev:
- mutex_unlock(&idev->mtx);
- free_netdev(ndev);
-out_disable:
- pci_disable_device(pdev);
-out:
- return -ENODEV;
-}
-
-static void vlsi_irda_remove(struct pci_dev *pdev)
-{
- struct net_device *ndev = pci_get_drvdata(pdev);
- vlsi_irda_dev_t *idev;
-
- if (!ndev) {
- net_err_ratelimited("%s: lost netdevice?\n", drivername);
- return;
- }
-
- unregister_netdev(ndev);
-
- idev = netdev_priv(ndev);
- mutex_lock(&idev->mtx);
- if (idev->proc_entry) {
- remove_proc_entry(ndev->name, vlsi_proc_root);
- idev->proc_entry = NULL;
- }
- mutex_unlock(&idev->mtx);
-
- free_netdev(ndev);
-
- net_info_ratelimited("%s: %s removed\n", drivername, pci_name(pdev));
-}
-
-#ifdef CONFIG_PM
-
-/* The Controller doesn't provide PCI PM capabilities as defined by PCI specs.
- * Some of the Linux PCI-PM code however depends on this, for example in
- * pci_set_power_state(). So we have to take care to perform the required
- * operations on our own (particularly reflecting the pdev->current_state)
- * otherwise we might get cheated by pci-pm.
- */
-
-
-static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct net_device *ndev = pci_get_drvdata(pdev);
- vlsi_irda_dev_t *idev;
-
- if (!ndev) {
- net_err_ratelimited("%s - %s: no netdevice\n",
- __func__, pci_name(pdev));
- return 0;
- }
- idev = netdev_priv(ndev);
- mutex_lock(&idev->mtx);
- if (pdev->current_state != 0) { /* already suspended */
- if (state.event > pdev->current_state) { /* simply go deeper */
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
- pdev->current_state = state.event;
- }
- else
- net_err_ratelimited("%s - %s: invalid suspend request %u -> %u\n",
- __func__, pci_name(pdev),
- pdev->current_state, state.event);
- mutex_unlock(&idev->mtx);
- return 0;
- }
-
- if (netif_running(ndev)) {
- netif_device_detach(ndev);
- vlsi_stop_hw(idev);
- pci_save_state(pdev);
- if (!idev->new_baud)
- /* remember speed settings to restore on resume */
- idev->new_baud = idev->baud;
- }
-
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
- pdev->current_state = state.event;
- idev->resume_ok = 1;
- mutex_unlock(&idev->mtx);
- return 0;
-}
-
-static int vlsi_irda_resume(struct pci_dev *pdev)
-{
- struct net_device *ndev = pci_get_drvdata(pdev);
- vlsi_irda_dev_t *idev;
-
- if (!ndev) {
- net_err_ratelimited("%s - %s: no netdevice\n",
- __func__, pci_name(pdev));
- return 0;
- }
- idev = netdev_priv(ndev);
- mutex_lock(&idev->mtx);
- if (pdev->current_state == 0) {
- mutex_unlock(&idev->mtx);
- net_warn_ratelimited("%s - %s: already resumed\n",
- __func__, pci_name(pdev));
- return 0;
- }
-
- pci_set_power_state(pdev, PCI_D0);
- pdev->current_state = PM_EVENT_ON;
-
- if (!idev->resume_ok) {
- /* should be obsolete now - but used to happen due to:
- * - pci layer initially setting pdev->current_state = 4 (unknown)
- * - pci layer did not walk the save_state-tree (might be APM problem)
- * so we could not refuse to suspend from undefined state
- * - vlsi_irda_suspend detected invalid state and refused to save
- * configuration for resume - but was too late to stop suspending
- * - vlsi_irda_resume got screwed when trying to resume from garbage
- *
- * now we explicitly set pdev->current_state = 0 after enabling the
- * device and independently resume_ok should catch any garbage config.
- */
- net_warn_ratelimited("%s - hm, nothing to resume?\n", __func__);
- mutex_unlock(&idev->mtx);
- return 0;
- }
-
- if (netif_running(ndev)) {
- pci_restore_state(pdev);
- vlsi_start_hw(idev);
- netif_device_attach(ndev);
- }
- idev->resume_ok = 0;
- mutex_unlock(&idev->mtx);
- return 0;
-}
-
-#endif /* CONFIG_PM */
-
-/*********************************************************/
-
-static struct pci_driver vlsi_irda_driver = {
- .name = drivername,
- .id_table = vlsi_irda_table,
- .probe = vlsi_irda_probe,
- .remove = vlsi_irda_remove,
-#ifdef CONFIG_PM
- .suspend = vlsi_irda_suspend,
- .resume = vlsi_irda_resume,
-#endif
-};
-
-#define PROC_DIR ("driver/" DRIVER_NAME)
-
-static int __init vlsi_mod_init(void)
-{
- int i, ret;
-
- if (clksrc < 0 || clksrc > 3) {
- net_err_ratelimited("%s: invalid clksrc=%d\n",
- drivername, clksrc);
- return -1;
- }
-
- for (i = 0; i < 2; i++) {
- switch(ringsize[i]) {
- case 4:
- case 8:
- case 16:
- case 32:
- case 64:
- break;
- default:
- net_warn_ratelimited("%s: invalid %s ringsize %d, using default=8\n",
- drivername,
- i ? "rx" : "tx",
- ringsize[i]);
- ringsize[i] = 8;
- break;
- }
- }
-
- sirpulse = !!sirpulse;
-
- /* proc_mkdir returns NULL if !CONFIG_PROC_FS.
- * Failure to create the procfs entry is handled like running
- * without procfs - it's not required for the driver to work.
- */
- vlsi_proc_root = proc_mkdir(PROC_DIR, NULL);
-
- ret = pci_register_driver(&vlsi_irda_driver);
-
- if (ret && vlsi_proc_root)
- remove_proc_entry(PROC_DIR, NULL);
- return ret;
-
-}
-
-static void __exit vlsi_mod_exit(void)
-{
- pci_unregister_driver(&vlsi_irda_driver);
- if (vlsi_proc_root)
- remove_proc_entry(PROC_DIR, NULL);
-}
-
-module_init(vlsi_mod_init);
-module_exit(vlsi_mod_exit);
diff --git a/drivers/staging/irda/drivers/vlsi_ir.h b/drivers/staging/irda/drivers/vlsi_ir.h
deleted file mode 100644
index f9db2ce4c5c6..000000000000
--- a/drivers/staging/irda/drivers/vlsi_ir.h
+++ /dev/null
@@ -1,757 +0,0 @@
-
-/*********************************************************************
- *
- * vlsi_ir.h: VLSI82C147 PCI IrDA controller driver for Linux
- *
- * Version: 0.5
- *
- * Copyright (c) 2001-2003 Martin Diehl
- *
- * 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.
- *
- * 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 IRDA_VLSI_FIR_H
-#define IRDA_VLSI_FIR_H
-
-/* ================================================================
- * compatibility stuff
- */
-
-/* definitions not present in pci_ids.h */
-
-#ifndef PCI_CLASS_WIRELESS_IRDA
-#define PCI_CLASS_WIRELESS_IRDA 0x0d00
-#endif
-
-#ifndef PCI_CLASS_SUBCLASS_MASK
-#define PCI_CLASS_SUBCLASS_MASK 0xffff
-#endif
-
-/* ================================================================ */
-
-/* non-standard PCI registers */
-
-enum vlsi_pci_regs {
- VLSI_PCI_CLKCTL = 0x40, /* chip clock input control */
- VLSI_PCI_MSTRPAGE = 0x41, /* addr [31:24] for all busmaster cycles */
- VLSI_PCI_IRMISC = 0x42 /* mainly legacy UART related */
-};
-
-/* ------------------------------------------ */
-
-/* VLSI_PCI_CLKCTL: Clock Control Register (u8, rw) */
-
-/* Three possible clock sources: either on-chip 48MHz PLL or
- * external clock applied to EXTCLK pin. External clock may
- * be either 48MHz or 40MHz, which is indicated by XCKSEL.
- * CLKSTP controls whether the selected clock source gets
- * connected to the IrDA block.
- *
- * On my HP OB-800 the BIOS sets external 40MHz clock as source
- * when IrDA enabled and I've never detected any PLL lock success.
- * Apparently the 14.3...MHz OSC input required for the PLL to work
- * is not connected and the 40MHz EXTCLK is provided externally.
- * At least this is what makes the driver working for me.
- */
-
-enum vlsi_pci_clkctl {
-
- /* PLL control */
-
- CLKCTL_PD_INV = 0x04, /* PD#: inverted power down signal,
- * i.e. PLL is powered, if PD_INV set */
- CLKCTL_LOCK = 0x40, /* (ro) set, if PLL is locked */
-
- /* clock source selection */
-
- CLKCTL_EXTCLK = 0x20, /* set to select external clock input, not PLL */
- CLKCTL_XCKSEL = 0x10, /* set to indicate EXTCLK is 40MHz, not 48MHz */
-
- /* IrDA block control */
-
- CLKCTL_CLKSTP = 0x80, /* set to disconnect from selected clock source */
- CLKCTL_WAKE = 0x08 /* set to enable wakeup feature: whenever IR activity
- * is detected, PD_INV gets set(?) and CLKSTP cleared */
-};
-
-/* ------------------------------------------ */
-
-/* VLSI_PCI_MSTRPAGE: Master Page Register (u8, rw) and busmastering stuff */
-
-#define DMA_MASK_USED_BY_HW 0xffffffff
-#define DMA_MASK_MSTRPAGE 0x00ffffff
-#define MSTRPAGE_VALUE (DMA_MASK_MSTRPAGE >> 24)
-
- /* PCI busmastering is somewhat special for this guy - in short:
- *
- * We select to operate using fixed MSTRPAGE=0, use ISA DMA
- * address restrictions to make the PCI BM api aware of this,
- * but ensure the hardware is dealing with real 32bit access.
- *
- * In detail:
- * The chip executes normal 32bit busmaster cycles, i.e.
- * drives all 32 address lines. These addresses however are
- * composed of [0:23] taken from various busaddr-pointers
- * and [24:31] taken from the MSTRPAGE register in the VLSI82C147
- * config space. Therefore _all_ busmastering must be
- * targeted to/from one single 16MB (busaddr-) superpage!
- * The point is to make sure all the allocations for memory
- * locations with busmaster access (ring descriptors, buffers)
- * are indeed bus-mappable to the same 16MB range (for x86 this
- * means they must reside in the same 16MB physical memory address
- * range). The only constraint we have which supports "several objects
- * mappable to common 16MB range" paradigma, is the old ISA DMA
- * restriction to the first 16MB of physical address range.
- * Hence the approach here is to enable PCI busmaster support using
- * the correct 32bit dma-mask used by the chip. Afterwards the device's
- * dma-mask gets restricted to 24bit, which must be honoured somehow by
- * all allocations for memory areas to be exposed to the chip ...
- *
- * Note:
- * Don't be surprised to get "Setting latency timer..." messages every
- * time when PCI busmastering is enabled for the chip.
- * The chip has its PCI latency timer RO fixed at 0 - which is not a
- * problem here, because it is never requesting _burst_ transactions.
- */
-
-/* ------------------------------------------ */
-
-/* VLSI_PCIIRMISC: IR Miscellaneous Register (u8, rw) */
-
-/* legacy UART emulation - not used by this driver - would require:
- * (see below for some register-value definitions)
- *
- * - IRMISC_UARTEN must be set to enable UART address decoding
- * - IRMISC_UARTSEL configured
- * - IRCFG_MASTER must be cleared
- * - IRCFG_SIR must be set
- * - IRENABLE_PHYANDCLOCK must be asserted 0->1 (and hence IRENABLE_SIR_ON)
- */
-
-enum vlsi_pci_irmisc {
-
- /* IR transceiver control */
-
- IRMISC_IRRAIL = 0x40, /* (ro?) IR rail power indication (and control?)
- * 0=3.3V / 1=5V. Probably set during power-on?
- * unclear - not touched by driver */
- IRMISC_IRPD = 0x08, /* transceiver power down, if set */
-
- /* legacy UART control */
-
- IRMISC_UARTTST = 0x80, /* UART test mode - "always write 0" */
- IRMISC_UARTEN = 0x04, /* enable UART address decoding */
-
- /* bits [1:0] IRMISC_UARTSEL to select legacy UART address */
-
- IRMISC_UARTSEL_3f8 = 0x00,
- IRMISC_UARTSEL_2f8 = 0x01,
- IRMISC_UARTSEL_3e8 = 0x02,
- IRMISC_UARTSEL_2e8 = 0x03
-};
-
-/* ================================================================ */
-
-/* registers mapped to 32 byte PCI IO space */
-
-/* note: better access all registers at the indicated u8/u16 size
- * although some of them contain only 1 byte of information.
- * some of them (particaluarly PROMPT and IRCFG) ignore
- * access when using the wrong addressing mode!
- */
-
-enum vlsi_pio_regs {
- VLSI_PIO_IRINTR = 0x00, /* interrupt enable/request (u8, rw) */
- VLSI_PIO_RINGPTR = 0x02, /* rx/tx ring pointer (u16, ro) */
- VLSI_PIO_RINGBASE = 0x04, /* [23:10] of ring address (u16, rw) */
- VLSI_PIO_RINGSIZE = 0x06, /* rx/tx ring size (u16, rw) */
- VLSI_PIO_PROMPT = 0x08, /* triggers ring processing (u16, wo) */
- /* 0x0a-0x0f: reserved / duplicated UART regs */
- VLSI_PIO_IRCFG = 0x10, /* configuration select (u16, rw) */
- VLSI_PIO_SIRFLAG = 0x12, /* BOF/EOF for filtered SIR (u16, ro) */
- VLSI_PIO_IRENABLE = 0x14, /* enable and status register (u16, rw/ro) */
- VLSI_PIO_PHYCTL = 0x16, /* physical layer current status (u16, ro) */
- VLSI_PIO_NPHYCTL = 0x18, /* next physical layer select (u16, rw) */
- VLSI_PIO_MAXPKT = 0x1a, /* [11:0] max len for packet receive (u16, rw) */
- VLSI_PIO_RCVBCNT = 0x1c /* current receive-FIFO byte count (u16, ro) */
- /* 0x1e-0x1f: reserved / duplicated UART regs */
-};
-
-/* ------------------------------------------ */
-
-/* VLSI_PIO_IRINTR: Interrupt Register (u8, rw) */
-
-/* enable-bits:
- * 1 = enable / 0 = disable
- * interrupt condition bits:
- * set according to corresponding interrupt source
- * (regardless of the state of the enable bits)
- * enable bit status indicates whether interrupt gets raised
- * write-to-clear
- * note: RPKTINT and TPKTINT behave different in legacy UART mode (which we don't use :-)
- */
-
-enum vlsi_pio_irintr {
- IRINTR_ACTEN = 0x80, /* activity interrupt enable */
- IRINTR_ACTIVITY = 0x40, /* activity monitor (traffic detected) */
- IRINTR_RPKTEN = 0x20, /* receive packet interrupt enable*/
- IRINTR_RPKTINT = 0x10, /* rx-packet transferred from fifo to memory finished */
- IRINTR_TPKTEN = 0x08, /* transmit packet interrupt enable */
- IRINTR_TPKTINT = 0x04, /* last bit of tx-packet+crc shifted to ir-pulser */
- IRINTR_OE_EN = 0x02, /* UART rx fifo overrun error interrupt enable */
- IRINTR_OE_INT = 0x01 /* UART rx fifo overrun error (read LSR to clear) */
-};
-
-/* we use this mask to check whether the (shared PCI) interrupt is ours */
-
-#define IRINTR_INT_MASK (IRINTR_ACTIVITY|IRINTR_RPKTINT|IRINTR_TPKTINT)
-
-/* ------------------------------------------ */
-
-/* VLSI_PIO_RINGPTR: Ring Pointer Read-Back Register (u16, ro) */
-
-/* _both_ ring pointers are indices relative to the _entire_ rx,tx-ring!
- * i.e. the referenced descriptor is located
- * at RINGBASE + PTR * sizeof(descr) for rx and tx
- * therefore, the tx-pointer has offset MAX_RING_DESCR
- */
-
-#define MAX_RING_DESCR 64 /* tx, rx rings may contain up to 64 descr each */
-
-#define RINGPTR_RX_MASK (MAX_RING_DESCR-1)
-#define RINGPTR_TX_MASK ((MAX_RING_DESCR-1)<<8)
-
-#define RINGPTR_GET_RX(p) ((p)&RINGPTR_RX_MASK)
-#define RINGPTR_GET_TX(p) (((p)&RINGPTR_TX_MASK)>>8)
-
-/* ------------------------------------------ */
-
-/* VLSI_PIO_RINGBASE: Ring Pointer Base Address Register (u16, ro) */
-
-/* Contains [23:10] part of the ring base (bus-) address
- * which must be 1k-alinged. [31:24] is taken from
- * VLSI_PCI_MSTRPAGE above.
- * The controller initiates non-burst PCI BM cycles to
- * fetch and update the descriptors in the ring.
- * Once fetched, the descriptor remains cached onchip
- * until it gets closed and updated due to the ring
- * processing state machine.
- * The entire ring area is split in rx and tx areas with each
- * area consisting of 64 descriptors of 8 bytes each.
- * The rx(tx) ring is located at ringbase+0 (ringbase+64*8).
- */
-
-#define BUS_TO_RINGBASE(p) (((p)>>10)&0x3fff)
-
-/* ------------------------------------------ */
-
-/* VLSI_PIO_RINGSIZE: Ring Size Register (u16, rw) */
-
-/* bit mask to indicate the ring size to be used for rx and tx.
- * possible values encoded bits
- * 4 0000
- * 8 0001
- * 16 0011
- * 32 0111
- * 64 1111
- * located at [15:12] for tx and [11:8] for rx ([7:0] unused)
- *
- * note: probably a good idea to have IRCFG_MSTR cleared when writing
- * this so the state machines are stopped and the RINGPTR is reset!
- */
-
-#define SIZE_TO_BITS(num) ((((num)-1)>>2)&0x0f)
-#define TX_RX_TO_RINGSIZE(tx,rx) ((SIZE_TO_BITS(tx)<<12)|(SIZE_TO_BITS(rx)<<8))
-#define RINGSIZE_TO_RXSIZE(rs) ((((rs)&0x0f00)>>6)+4)
-#define RINGSIZE_TO_TXSIZE(rs) ((((rs)&0xf000)>>10)+4)
-
-
-/* ------------------------------------------ */
-
-/* VLSI_PIO_PROMPT: Ring Prompting Register (u16, write-to-start) */
-
-/* writing any value kicks the ring processing state machines
- * for both tx, rx rings as follows:
- * - active rings (currently owning an active descriptor)
- * ignore the prompt and continue
- * - idle rings fetch the next descr from the ring and start
- * their processing
- */
-
-/* ------------------------------------------ */
-
-/* VLSI_PIO_IRCFG: IR Config Register (u16, rw) */
-
-/* notes:
- * - not more than one SIR/MIR/FIR bit must be set at any time
- * - SIR, MIR, FIR and CRC16 select the configuration which will
- * be applied on next 0->1 transition of IRENABLE_PHYANDCLOCK (see below).
- * - besides allowing the PCI interface to execute busmaster cycles
- * and therefore the ring SM to operate, the MSTR bit has side-effects:
- * when MSTR is cleared, the RINGPTR's get reset and the legacy UART mode
- * (in contrast to busmaster access mode) gets enabled.
- * - clearing ENRX or setting ENTX while data is received may stall the
- * receive fifo until ENRX reenabled _and_ another packet arrives
- * - SIRFILT means the chip performs the required unwrapping of hardware
- * headers (XBOF's, BOF/EOF) and un-escaping in the _receive_ direction.
- * Only the resulting IrLAP payload is copied to the receive buffers -
- * but with the 16bit FCS still encluded. Question remains, whether it
- * was already checked or we should do it before passing the packet to IrLAP?
- */
-
-enum vlsi_pio_ircfg {
- IRCFG_LOOP = 0x4000, /* enable loopback test mode */
- IRCFG_ENTX = 0x1000, /* transmit enable */
- IRCFG_ENRX = 0x0800, /* receive enable */
- IRCFG_MSTR = 0x0400, /* master enable */
- IRCFG_RXANY = 0x0200, /* receive any packet */
- IRCFG_CRC16 = 0x0080, /* 16bit (not 32bit) CRC select for MIR/FIR */
- IRCFG_FIR = 0x0040, /* FIR 4PPM encoding mode enable */
- IRCFG_MIR = 0x0020, /* MIR HDLC encoding mode enable */
- IRCFG_SIR = 0x0010, /* SIR encoding mode enable */
- IRCFG_SIRFILT = 0x0008, /* enable SIR decode filter (receiver unwrapping) */
- IRCFG_SIRTEST = 0x0004, /* allow SIR decode filter when not in SIR mode */
- IRCFG_TXPOL = 0x0002, /* invert tx polarity when set */
- IRCFG_RXPOL = 0x0001 /* invert rx polarity when set */
-};
-
-/* ------------------------------------------ */
-
-/* VLSI_PIO_SIRFLAG: SIR Flag Register (u16, ro) */
-
-/* register contains hardcoded BOF=0xc0 at [7:0] and EOF=0xc1 at [15:8]
- * which is used for unwrapping received frames in SIR decode-filter mode
- */
-
-/* ------------------------------------------ */
-
-/* VLSI_PIO_IRENABLE: IR Enable Register (u16, rw/ro) */
-
-/* notes:
- * - IREN acts as gate for latching the configured IR mode information
- * from IRCFG and IRPHYCTL when IREN=reset and applying them when
- * IREN gets set afterwards.
- * - ENTXST reflects IRCFG_ENTX
- * - ENRXST = IRCFG_ENRX && (!IRCFG_ENTX || IRCFG_LOOP)
- */
-
-enum vlsi_pio_irenable {
- IRENABLE_PHYANDCLOCK = 0x8000, /* enable IR phy and gate the mode config (rw) */
- IRENABLE_CFGER = 0x4000, /* mode configuration error (ro) */
- IRENABLE_FIR_ON = 0x2000, /* FIR on status (ro) */
- IRENABLE_MIR_ON = 0x1000, /* MIR on status (ro) */
- IRENABLE_SIR_ON = 0x0800, /* SIR on status (ro) */
- IRENABLE_ENTXST = 0x0400, /* transmit enable status (ro) */
- IRENABLE_ENRXST = 0x0200, /* Receive enable status (ro) */
- IRENABLE_CRC16_ON = 0x0100 /* 16bit (not 32bit) CRC enabled status (ro) */
-};
-
-#define IRENABLE_MASK 0xff00 /* Read mask */
-
-/* ------------------------------------------ */
-
-/* VLSI_PIO_PHYCTL: IR Physical Layer Current Control Register (u16, ro) */
-
-/* read-back of the currently applied physical layer status.
- * applied from VLSI_PIO_NPHYCTL at rising edge of IRENABLE_PHYANDCLOCK
- * contents identical to VLSI_PIO_NPHYCTL (see below)
- */
-
-/* ------------------------------------------ */
-
-/* VLSI_PIO_NPHYCTL: IR Physical Layer Next Control Register (u16, rw) */
-
-/* latched during IRENABLE_PHYANDCLOCK=0 and applied at 0-1 transition
- *
- * consists of BAUD[15:10], PLSWID[9:5] and PREAMB[4:0] bits defined as follows:
- *
- * SIR-mode: BAUD = (115.2kHz / baudrate) - 1
- * PLSWID = (pulsetime * freq / (BAUD+1)) - 1
- * where pulsetime is the requested IrPHY pulse width
- * and freq is 8(16)MHz for 40(48)MHz primary input clock
- * PREAMB: don't care for SIR
- *
- * The nominal SIR pulse width is 3/16 bit time so we have PLSWID=12
- * fixed for all SIR speeds at 40MHz input clock (PLSWID=24 at 48MHz).
- * IrPHY also allows shorter pulses down to the nominal pulse duration
- * at 115.2kbaud (minus some tolerance) which is 1.41 usec.
- * Using the expression PLSWID = 12/(BAUD+1)-1 (multiplied by two for 48MHz)
- * we get the minimum acceptable PLSWID values according to the VLSI
- * specification, which provides 1.5 usec pulse width for all speeds (except
- * for 2.4kbaud getting 6usec). This is fine with IrPHY v1.3 specs and
- * reduces the transceiver power which drains the battery. At 9.6kbaud for
- * example this amounts to more than 90% battery power saving!
- *
- * MIR-mode: BAUD = 0
- * PLSWID = 9(10) for 40(48) MHz input clock
- * to get nominal MIR pulse width
- * PREAMB = 1
- *
- * FIR-mode: BAUD = 0
- * PLSWID: don't care
- * PREAMB = 15
- */
-
-#define PHYCTL_BAUD_SHIFT 10
-#define PHYCTL_BAUD_MASK 0xfc00
-#define PHYCTL_PLSWID_SHIFT 5
-#define PHYCTL_PLSWID_MASK 0x03e0
-#define PHYCTL_PREAMB_SHIFT 0
-#define PHYCTL_PREAMB_MASK 0x001f
-
-#define PHYCTL_TO_BAUD(bwp) (((bwp)&PHYCTL_BAUD_MASK)>>PHYCTL_BAUD_SHIFT)
-#define PHYCTL_TO_PLSWID(bwp) (((bwp)&PHYCTL_PLSWID_MASK)>>PHYCTL_PLSWID_SHIFT)
-#define PHYCTL_TO_PREAMB(bwp) (((bwp)&PHYCTL_PREAMB_MASK)>>PHYCTL_PREAMB_SHIFT)
-
-#define BWP_TO_PHYCTL(b,w,p) ((((b)<<PHYCTL_BAUD_SHIFT)&PHYCTL_BAUD_MASK) \
- | (((w)<<PHYCTL_PLSWID_SHIFT)&PHYCTL_PLSWID_MASK) \
- | (((p)<<PHYCTL_PREAMB_SHIFT)&PHYCTL_PREAMB_MASK))
-
-#define BAUD_BITS(br) ((115200/(br))-1)
-
-static inline unsigned
-calc_width_bits(unsigned baudrate, unsigned widthselect, unsigned clockselect)
-{
- unsigned tmp;
-
- if (widthselect) /* nominal 3/16 puls width */
- return (clockselect) ? 12 : 24;
-
- tmp = ((clockselect) ? 12 : 24) / (BAUD_BITS(baudrate)+1);
-
- /* intermediate result of integer division needed here */
-
- return (tmp>0) ? (tmp-1) : 0;
-}
-
-#define PHYCTL_SIR(br,ws,cs) BWP_TO_PHYCTL(BAUD_BITS(br),calc_width_bits((br),(ws),(cs)),0)
-#define PHYCTL_MIR(cs) BWP_TO_PHYCTL(0,((cs)?9:10),1)
-#define PHYCTL_FIR BWP_TO_PHYCTL(0,0,15)
-
-/* quite ugly, I know. But implementing these calculations here avoids
- * having magic numbers in the code and allows some playing with pulsewidths
- * without risk to violate the standards.
- * FWIW, here is the table for reference:
- *
- * baudrate BAUD min-PLSWID nom-PLSWID PREAMB
- * 2400 47 0(0) 12(24) 0
- * 9600 11 0(0) 12(24) 0
- * 19200 5 1(2) 12(24) 0
- * 38400 2 3(6) 12(24) 0
- * 57600 1 5(10) 12(24) 0
- * 115200 0 11(22) 12(24) 0
- * MIR 0 - 9(10) 1
- * FIR 0 - 0 15
- *
- * note: x(y) means x-value for 40MHz / y-value for 48MHz primary input clock
- */
-
-/* ------------------------------------------ */
-
-
-/* VLSI_PIO_MAXPKT: Maximum Packet Length register (u16, rw) */
-
-/* maximum acceptable length for received packets */
-
-/* hw imposed limitation - register uses only [11:0] */
-#define MAX_PACKET_LENGTH 0x0fff
-
-/* IrLAP I-field (apparently not defined elsewhere) */
-#define IRDA_MTU 2048
-
-/* complete packet consists of A(1)+C(1)+I(<=IRDA_MTU) */
-#define IRLAP_SKB_ALLOCSIZE (1+1+IRDA_MTU)
-
-/* the buffers we use to exchange frames with the hardware need to be
- * larger than IRLAP_SKB_ALLOCSIZE because we may have up to 4 bytes FCS
- * appended and, in SIR mode, a lot of frame wrapping bytes. The worst
- * case appears to be a SIR packet with I-size==IRDA_MTU and all bytes
- * requiring to be escaped to provide transparency. Furthermore, the peer
- * might ask for quite a number of additional XBOFs:
- * up to 115+48 XBOFS 163
- * regular BOF 1
- * A-field 1
- * C-field 1
- * I-field, IRDA_MTU, all escaped 4096
- * FCS (16 bit at SIR, escaped) 4
- * EOF 1
- * AFAICS nothing in IrLAP guarantees A/C field not to need escaping
- * (f.e. 0xc0/0xc1 - i.e. BOF/EOF - are legal values there) so in the
- * worst case we have 4269 bytes total frame size.
- * However, the VLSI uses 12 bits only for all buffer length values,
- * which limits the maximum useable buffer size <= 4095.
- * Note this is not a limitation in the receive case because we use
- * the SIR filtering mode where the hw unwraps the frame and only the
- * bare packet+fcs is stored into the buffer - in contrast to the SIR
- * tx case where we have to pass frame-wrapped packets to the hw.
- * If this would ever become an issue in real life, the only workaround
- * I see would be using the legacy UART emulation in SIR mode.
- */
-
-#define XFER_BUF_SIZE MAX_PACKET_LENGTH
-
-/* ------------------------------------------ */
-
-/* VLSI_PIO_RCVBCNT: Receive Byte Count Register (u16, ro) */
-
-/* receive packet counter gets incremented on every non-filtered
- * byte which was put in the receive fifo and reset for each
- * new packet. Used to decide whether we are just in the middle
- * of receiving
- */
-
-/* better apply the [11:0] mask when reading, as some docs say the
- * reserved [15:12] would return 1 when reading - which is wrong AFAICS
- */
-#define RCVBCNT_MASK 0x0fff
-
-/******************************************************************/
-
-/* descriptors for rx/tx ring
- *
- * accessed by hardware - don't change!
- *
- * the descriptor is owned by hardware, when the ACTIVE status bit
- * is set and nothing (besides reading status to test the bit)
- * shall be done. The bit gets cleared by hw, when the descriptor
- * gets closed. Premature reaping of descriptors owned be the chip
- * can be achieved by disabling IRCFG_MSTR
- *
- * Attention: Writing addr overwrites status!
- *
- * ### FIXME: depends on endianess (but there ain't no non-i586 ob800 ;-)
- */
-
-struct ring_descr_hw {
- volatile __le16 rd_count; /* tx/rx count [11:0] */
- __le16 reserved;
- union {
- __le32 addr; /* [23:0] of the buffer's busaddress */
- struct {
- u8 addr_res[3];
- volatile u8 status; /* descriptor status */
- } __packed rd_s;
- } __packed rd_u;
-} __packed;
-
-#define rd_addr rd_u.addr
-#define rd_status rd_u.rd_s.status
-
-/* ring descriptor status bits */
-
-#define RD_ACTIVE 0x80 /* descriptor owned by hw (both TX,RX) */
-
-/* TX ring descriptor status */
-
-#define RD_TX_DISCRC 0x40 /* do not send CRC (for SIR) */
-#define RD_TX_BADCRC 0x20 /* force a bad CRC */
-#define RD_TX_PULSE 0x10 /* send indication pulse after this frame (MIR/FIR) */
-#define RD_TX_FRCEUND 0x08 /* force underrun */
-#define RD_TX_CLRENTX 0x04 /* clear ENTX after this frame */
-#define RD_TX_UNDRN 0x01 /* TX fifo underrun (probably PCI problem) */
-
-/* RX ring descriptor status */
-
-#define RD_RX_PHYERR 0x40 /* physical encoding error */
-#define RD_RX_CRCERR 0x20 /* CRC error (MIR/FIR) */
-#define RD_RX_LENGTH 0x10 /* frame exceeds buffer length */
-#define RD_RX_OVER 0x08 /* RX fifo overrun (probably PCI problem) */
-#define RD_RX_SIRBAD 0x04 /* EOF missing: BOF follows BOF (SIR, filtered) */
-
-#define RD_RX_ERROR 0x7c /* any error in received frame */
-
-/* the memory required to hold the 2 descriptor rings */
-#define HW_RING_AREA_SIZE (2 * MAX_RING_DESCR * sizeof(struct ring_descr_hw))
-
-/******************************************************************/
-
-/* sw-ring descriptors consists of a bus-mapped transfer buffer with
- * associated skb and a pointer to the hw entry descriptor
- */
-
-struct ring_descr {
- struct ring_descr_hw *hw;
- struct sk_buff *skb;
- void *buf;
-};
-
-/* wrappers for operations on hw-exposed ring descriptors
- * access to the hw-part of the descriptors must use these.
- */
-
-static inline int rd_is_active(struct ring_descr *rd)
-{
- return (rd->hw->rd_status & RD_ACTIVE) != 0;
-}
-
-static inline void rd_activate(struct ring_descr *rd)
-{
- rd->hw->rd_status |= RD_ACTIVE;
-}
-
-static inline void rd_set_status(struct ring_descr *rd, u8 s)
-{
- rd->hw->rd_status = s; /* may pass ownership to the hardware */
-}
-
-static inline void rd_set_addr_status(struct ring_descr *rd, dma_addr_t a, u8 s)
-{
- /* order is important for two reasons:
- * - overlayed: writing addr overwrites status
- * - we want to write status last so we have valid address in
- * case status has RD_ACTIVE set
- */
-
- if ((a & ~DMA_MASK_MSTRPAGE)>>24 != MSTRPAGE_VALUE) {
- net_err_ratelimited("%s: pci busaddr inconsistency!\n",
- __func__);
- dump_stack();
- return;
- }
-
- a &= DMA_MASK_MSTRPAGE; /* clear highbyte to make sure we won't write
- * to status - just in case MSTRPAGE_VALUE!=0
- */
- rd->hw->rd_addr = cpu_to_le32(a);
- wmb();
- rd_set_status(rd, s); /* may pass ownership to the hardware */
-}
-
-static inline void rd_set_count(struct ring_descr *rd, u16 c)
-{
- rd->hw->rd_count = cpu_to_le16(c);
-}
-
-static inline u8 rd_get_status(struct ring_descr *rd)
-{
- return rd->hw->rd_status;
-}
-
-static inline dma_addr_t rd_get_addr(struct ring_descr *rd)
-{
- dma_addr_t a;
-
- a = le32_to_cpu(rd->hw->rd_addr);
- return (a & DMA_MASK_MSTRPAGE) | (MSTRPAGE_VALUE << 24);
-}
-
-static inline u16 rd_get_count(struct ring_descr *rd)
-{
- return le16_to_cpu(rd->hw->rd_count);
-}
-
-/******************************************************************/
-
-/* sw descriptor rings for rx, tx:
- *
- * operations follow producer-consumer paradigm, with the hw
- * in the middle doing the processing.
- * ring size must be power of two.
- *
- * producer advances r->tail after inserting for processing
- * consumer advances r->head after removing processed rd
- * ring is empty if head==tail / full if (tail+1)==head
- */
-
-struct vlsi_ring {
- struct pci_dev *pdev;
- int dir;
- unsigned len;
- unsigned size;
- unsigned mask;
- atomic_t head, tail;
- struct ring_descr *rd;
-};
-
-/* ring processing helpers */
-
-static inline struct ring_descr *ring_last(struct vlsi_ring *r)
-{
- int t;
-
- t = atomic_read(&r->tail) & r->mask;
- return (((t+1) & r->mask) == (atomic_read(&r->head) & r->mask)) ? NULL : &r->rd[t];
-}
-
-static inline struct ring_descr *ring_put(struct vlsi_ring *r)
-{
- atomic_inc(&r->tail);
- return ring_last(r);
-}
-
-static inline struct ring_descr *ring_first(struct vlsi_ring *r)
-{
- int h;
-
- h = atomic_read(&r->head) & r->mask;
- return (h == (atomic_read(&r->tail) & r->mask)) ? NULL : &r->rd[h];
-}
-
-static inline struct ring_descr *ring_get(struct vlsi_ring *r)
-{
- atomic_inc(&r->head);
- return ring_first(r);
-}
-
-/******************************************************************/
-
-/* our private compound VLSI-PCI-IRDA device information */
-
-typedef struct vlsi_irda_dev {
- struct pci_dev *pdev;
-
- struct irlap_cb *irlap;
-
- struct qos_info qos;
-
- unsigned mode;
- int baud, new_baud;
-
- dma_addr_t busaddr;
- void *virtaddr;
- struct vlsi_ring *tx_ring, *rx_ring;
-
- ktime_t last_rx;
-
- spinlock_t lock;
- struct mutex mtx;
-
- u8 resume_ok;
- struct proc_dir_entry *proc_entry;
-
-} vlsi_irda_dev_t;
-
-/********************************************************/
-
-/* the remapped error flags we use for returning from frame
- * post-processing in vlsi_process_tx/rx() after it was completed
- * by the hardware. These functions either return the >=0 number
- * of transferred bytes in case of success or the negative (-)
- * of the or'ed error flags.
- */
-
-#define VLSI_TX_DROP 0x0001
-#define VLSI_TX_FIFO 0x0002
-
-#define VLSI_RX_DROP 0x0100
-#define VLSI_RX_OVER 0x0200
-#define VLSI_RX_LENGTH 0x0400
-#define VLSI_RX_FRAME 0x0800
-#define VLSI_RX_CRC 0x1000
-
-/********************************************************/
-
-#endif /* IRDA_VLSI_FIR_H */
-
diff --git a/drivers/staging/irda/drivers/w83977af.h b/drivers/staging/irda/drivers/w83977af.h
deleted file mode 100644
index 04476c2e9121..000000000000
--- a/drivers/staging/irda/drivers/w83977af.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef W83977AF_H
-#define W83977AF_H
-
-#define W977_EFIO_BASE 0x370
-#define W977_EFIO2_BASE 0x3f0
-#define W977_DEVICE_IR 0x06
-
-
-/*
- * Enter extended function mode
- */
-static inline void w977_efm_enter(unsigned int efio)
-{
- outb(0x87, efio);
- outb(0x87, efio);
-}
-
-/*
- * Select a device to configure
- */
-
-static inline void w977_select_device(__u8 devnum, unsigned int efio)
-{
- outb(0x07, efio);
- outb(devnum, efio+1);
-}
-
-/*
- * Write a byte to a register
- */
-static inline void w977_write_reg(__u8 reg, __u8 value, unsigned int efio)
-{
- outb(reg, efio);
- outb(value, efio+1);
-}
-
-/*
- * read a byte from a register
- */
-static inline __u8 w977_read_reg(__u8 reg, unsigned int efio)
-{
- outb(reg, efio);
- return inb(efio+1);
-}
-
-/*
- * Exit extended function mode
- */
-static inline void w977_efm_exit(unsigned int efio)
-{
- outb(0xAA, efio);
-}
-#endif
diff --git a/drivers/staging/irda/drivers/w83977af_ir.c b/drivers/staging/irda/drivers/w83977af_ir.c
deleted file mode 100644
index 282b6c9ae05b..000000000000
--- a/drivers/staging/irda/drivers/w83977af_ir.c
+++ /dev/null
@@ -1,1285 +0,0 @@
-/*********************************************************************
- *
- * Filename: w83977af_ir.c
- * Version: 1.0
- * Description: FIR driver for the Winbond W83977AF Super I/O chip
- * Status: Experimental.
- * Author: Paul VanderSpek
- * Created at: Wed Nov 4 11:46:16 1998
- * Modified at: Fri Jan 28 12:10:59 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
- * Copyright (c) 1998-1999 Rebel.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.
- *
- * Neither Paul VanderSpek nor Rebel.com admit liability nor provide
- * warranty for any of this software. This material is provided "AS-IS"
- * and at no charge.
- *
- * If you find bugs in this file, its very likely that the same bug
- * will also be in pc87108.c since the implementations are quite
- * similar.
- *
- * Notice that all functions that needs to access the chip in _any_
- * way, must save BSR register on entry, and restore it on exit.
- * It is _very_ important to follow this policy!
- *
- * __u8 bank;
- *
- * bank = inb( iobase+BSR);
- *
- * do_your_stuff_here();
- *
- * outb( bank, iobase+BSR);
- *
- ********************************************************************/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/rtnetlink.h>
-#include <linux/dma-mapping.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/irda_device.h>
-#include "w83977af.h"
-#include "w83977af_ir.h"
-
-#define CONFIG_USE_W977_PNP /* Currently needed */
-#define PIO_MAX_SPEED 115200
-
-static char *driver_name = "w83977af_ir";
-static int qos_mtt_bits = 0x07; /* 1 ms or more */
-
-#define CHIP_IO_EXTENT 8
-
-static unsigned int io[] = { 0x180, ~0, ~0, ~0 };
-#ifdef CONFIG_ARCH_NETWINDER /* Adjust to NetWinder differences */
-static unsigned int irq[] = { 6, 0, 0, 0 };
-#else
-static unsigned int irq[] = { 11, 0, 0, 0 };
-#endif
-static unsigned int dma[] = { 1, 0, 0, 0 };
-static unsigned int efbase[] = { W977_EFIO_BASE, W977_EFIO2_BASE };
-static unsigned int efio = W977_EFIO_BASE;
-
-static struct w83977af_ir *dev_self[] = { NULL, NULL, NULL, NULL};
-
-/* Some prototypes */
-static int w83977af_open(int i, unsigned int iobase, unsigned int irq,
- unsigned int dma);
-static int w83977af_close(struct w83977af_ir *self);
-static int w83977af_probe(int iobase, int irq, int dma);
-static int w83977af_dma_receive(struct w83977af_ir *self);
-static int w83977af_dma_receive_complete(struct w83977af_ir *self);
-static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
-static void w83977af_dma_write(struct w83977af_ir *self, int iobase);
-static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed);
-static int w83977af_is_receiving(struct w83977af_ir *self);
-
-static int w83977af_net_open(struct net_device *dev);
-static int w83977af_net_close(struct net_device *dev);
-static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-
-/*
- * Function w83977af_init ()
- *
- * Initialize chip. Just try to find out how many chips we are dealing with
- * and where they are
- */
-static int __init w83977af_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dev_self) && io[i] < 2000; i++) {
- if (w83977af_open(i, io[i], irq[i], dma[i]) == 0)
- return 0;
- }
- return -ENODEV;
-}
-
-/*
- * Function w83977af_cleanup ()
- *
- * Close all configured chips
- *
- */
-static void __exit w83977af_cleanup(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dev_self); i++) {
- if (dev_self[i])
- w83977af_close(dev_self[i]);
- }
-}
-
-static const struct net_device_ops w83977_netdev_ops = {
- .ndo_open = w83977af_net_open,
- .ndo_stop = w83977af_net_close,
- .ndo_start_xmit = w83977af_hard_xmit,
- .ndo_do_ioctl = w83977af_net_ioctl,
-};
-
-/*
- * Function w83977af_open (iobase, irq)
- *
- * Open driver instance
- *
- */
-static int w83977af_open(int i, unsigned int iobase, unsigned int irq,
- unsigned int dma)
-{
- struct net_device *dev;
- struct w83977af_ir *self;
- int err;
-
- /* Lock the port that we need */
- if (!request_region(iobase, CHIP_IO_EXTENT, driver_name)) {
- pr_debug("%s: can't get iobase of 0x%03x\n",
- __func__, iobase);
- return -ENODEV;
- }
-
- if (w83977af_probe(iobase, irq, dma) == -1) {
- err = -1;
- goto err_out;
- }
- /*
- * Allocate new instance of the driver
- */
- dev = alloc_irdadev(sizeof(struct w83977af_ir));
- if (!dev) {
- pr_err("IrDA: Can't allocate memory for IrDA control block!\n");
- err = -ENOMEM;
- goto err_out;
- }
-
- self = netdev_priv(dev);
- spin_lock_init(&self->lock);
-
- /* Initialize IO */
- self->io.fir_base = iobase;
- self->io.irq = irq;
- self->io.fir_ext = CHIP_IO_EXTENT;
- self->io.dma = dma;
- self->io.fifo_size = 32;
-
- /* Initialize QoS for this device */
- irda_init_max_qos_capabilies(&self->qos);
-
- /* The only value we must override it the baudrate */
-
- /* FIXME: The HP HDLS-1100 does not support 1152000! */
- self->qos.baud_rate.bits = IR_9600 | IR_19200 | IR_38400 | IR_57600 |
- IR_115200 | IR_576000 | IR_1152000 | (IR_4000000 << 8);
-
- /* The HP HDLS-1100 needs 1 ms according to the specs */
- self->qos.min_turn_time.bits = qos_mtt_bits;
- irda_qos_bits_to_value(&self->qos);
-
- /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
- self->rx_buff.truesize = 14384;
- self->tx_buff.truesize = 4000;
-
- /* Allocate memory if needed */
- self->rx_buff.head =
- dma_zalloc_coherent(NULL, self->rx_buff.truesize,
- &self->rx_buff_dma, GFP_KERNEL);
- if (!self->rx_buff.head) {
- err = -ENOMEM;
- goto err_out1;
- }
-
- self->tx_buff.head =
- dma_zalloc_coherent(NULL, self->tx_buff.truesize,
- &self->tx_buff_dma, GFP_KERNEL);
- if (!self->tx_buff.head) {
- err = -ENOMEM;
- goto err_out2;
- }
-
- self->rx_buff.in_frame = FALSE;
- self->rx_buff.state = OUTSIDE_FRAME;
- self->tx_buff.data = self->tx_buff.head;
- self->rx_buff.data = self->rx_buff.head;
- self->netdev = dev;
-
- dev->netdev_ops = &w83977_netdev_ops;
-
- err = register_netdev(dev);
- if (err) {
- net_err_ratelimited("%s:, register_netdevice() failed!\n",
- __func__);
- goto err_out3;
- }
- net_info_ratelimited("IrDA: Registered device %s\n", dev->name);
-
- /* Need to store self somewhere */
- dev_self[i] = self;
-
- return 0;
-err_out3:
- dma_free_coherent(NULL, self->tx_buff.truesize,
- self->tx_buff.head, self->tx_buff_dma);
-err_out2:
- dma_free_coherent(NULL, self->rx_buff.truesize,
- self->rx_buff.head, self->rx_buff_dma);
-err_out1:
- free_netdev(dev);
-err_out:
- release_region(iobase, CHIP_IO_EXTENT);
- return err;
-}
-
-/*
- * Function w83977af_close (self)
- *
- * Close driver instance
- *
- */
-static int w83977af_close(struct w83977af_ir *self)
-{
- int iobase;
-
- iobase = self->io.fir_base;
-
-#ifdef CONFIG_USE_W977_PNP
- /* enter PnP configuration mode */
- w977_efm_enter(efio);
-
- w977_select_device(W977_DEVICE_IR, efio);
-
- /* Deactivate device */
- w977_write_reg(0x30, 0x00, efio);
-
- w977_efm_exit(efio);
-#endif /* CONFIG_USE_W977_PNP */
-
- /* Remove netdevice */
- unregister_netdev(self->netdev);
-
- /* Release the PORT that this driver is using */
- pr_debug("%s: Releasing Region %03x\n", __func__, self->io.fir_base);
- release_region(self->io.fir_base, self->io.fir_ext);
-
- if (self->tx_buff.head)
- dma_free_coherent(NULL, self->tx_buff.truesize,
- self->tx_buff.head, self->tx_buff_dma);
-
- if (self->rx_buff.head)
- dma_free_coherent(NULL, self->rx_buff.truesize,
- self->rx_buff.head, self->rx_buff_dma);
-
- free_netdev(self->netdev);
-
- return 0;
-}
-
-static int w83977af_probe(int iobase, int irq, int dma)
-{
- int version;
- int i;
-
- for (i = 0; i < 2; i++) {
-#ifdef CONFIG_USE_W977_PNP
- /* Enter PnP configuration mode */
- w977_efm_enter(efbase[i]);
-
- w977_select_device(W977_DEVICE_IR, efbase[i]);
-
- /* Configure PnP port, IRQ, and DMA channel */
- w977_write_reg(0x60, (iobase >> 8) & 0xff, efbase[i]);
- w977_write_reg(0x61, (iobase) & 0xff, efbase[i]);
-
- w977_write_reg(0x70, irq, efbase[i]);
-#ifdef CONFIG_ARCH_NETWINDER
- /* Netwinder uses 1 higher than Linux */
- w977_write_reg(0x74, dma + 1, efbase[i]);
-#else
- w977_write_reg(0x74, dma, efbase[i]);
-#endif /* CONFIG_ARCH_NETWINDER */
- w977_write_reg(0x75, 0x04, efbase[i]);/* Disable Tx DMA */
-
- /* Set append hardware CRC, enable IR bank selection */
- w977_write_reg(0xf0, APEDCRC | ENBNKSEL, efbase[i]);
-
- /* Activate device */
- w977_write_reg(0x30, 0x01, efbase[i]);
-
- w977_efm_exit(efbase[i]);
-#endif /* CONFIG_USE_W977_PNP */
- /* Disable Advanced mode */
- switch_bank(iobase, SET2);
- outb(iobase + 2, 0x00);
-
- /* Turn on UART (global) interrupts */
- switch_bank(iobase, SET0);
- outb(HCR_EN_IRQ, iobase + HCR);
-
- /* Switch to advanced mode */
- switch_bank(iobase, SET2);
- outb(inb(iobase + ADCR1) | ADCR1_ADV_SL, iobase + ADCR1);
-
- /* Set default IR-mode */
- switch_bank(iobase, SET0);
- outb(HCR_SIR, iobase + HCR);
-
- /* Read the Advanced IR ID */
- switch_bank(iobase, SET3);
- version = inb(iobase + AUID);
-
- /* Should be 0x1? */
- if (0x10 == (version & 0xf0)) {
- efio = efbase[i];
-
- /* Set FIFO size to 32 */
- switch_bank(iobase, SET2);
- outb(ADCR2_RXFS32 | ADCR2_TXFS32, iobase + ADCR2);
-
- /* Set FIFO threshold to TX17, RX16 */
- switch_bank(iobase, SET0);
- outb(UFR_RXTL | UFR_TXTL | UFR_TXF_RST | UFR_RXF_RST |
- UFR_EN_FIFO, iobase + UFR);
-
- /* Receiver frame length */
- switch_bank(iobase, SET4);
- outb(2048 & 0xff, iobase + 6);
- outb((2048 >> 8) & 0x1f, iobase + 7);
-
- /*
- * Init HP HSDL-1100 transceiver.
- *
- * Set IRX_MSL since we have 2 * receive paths IRRX,
- * and IRRXH. Clear IRSL0D since we want IRSL0 * to
- * be a input pin used for IRRXH
- *
- * IRRX pin 37 connected to receiver
- * IRTX pin 38 connected to transmitter
- * FIRRX pin 39 connected to receiver (IRSL0)
- * CIRRX pin 40 connected to pin 37
- */
- switch_bank(iobase, SET7);
- outb(0x40, iobase + 7);
-
- net_info_ratelimited("W83977AF (IR) driver loaded. Version: 0x%02x\n",
- version);
-
- return 0;
- } else {
- /* Try next extented function register address */
- pr_debug("%s: Wrong chip version\n", __func__);
- }
- }
- return -1;
-}
-
-static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed)
-{
- int ir_mode = HCR_SIR;
- int iobase;
- __u8 set;
-
- iobase = self->io.fir_base;
-
- /* Update accounting for new speed */
- self->io.speed = speed;
-
- /* Save current bank */
- set = inb(iobase + SSR);
-
- /* Disable interrupts */
- switch_bank(iobase, SET0);
- outb(0, iobase + ICR);
-
- /* Select Set 2 */
- switch_bank(iobase, SET2);
- outb(0x00, iobase + ABHL);
-
- switch (speed) {
- case 9600: outb(0x0c, iobase + ABLL); break;
- case 19200: outb(0x06, iobase + ABLL); break;
- case 38400: outb(0x03, iobase + ABLL); break;
- case 57600: outb(0x02, iobase + ABLL); break;
- case 115200: outb(0x01, iobase + ABLL); break;
- case 576000:
- ir_mode = HCR_MIR_576;
- pr_debug("%s: handling baud of 576000\n", __func__);
- break;
- case 1152000:
- ir_mode = HCR_MIR_1152;
- pr_debug("%s: handling baud of 1152000\n", __func__);
- break;
- case 4000000:
- ir_mode = HCR_FIR;
- pr_debug("%s: handling baud of 4000000\n", __func__);
- break;
- default:
- ir_mode = HCR_FIR;
- pr_debug("%s: unknown baud rate of %d\n", __func__, speed);
- break;
- }
-
- /* Set speed mode */
- switch_bank(iobase, SET0);
- outb(ir_mode, iobase + HCR);
-
- /* set FIFO size to 32 */
- switch_bank(iobase, SET2);
- outb(ADCR2_RXFS32 | ADCR2_TXFS32, iobase + ADCR2);
-
- /* set FIFO threshold to TX17, RX16 */
- switch_bank(iobase, SET0);
- outb(0x00, iobase + UFR); /* Reset */
- outb(UFR_EN_FIFO, iobase + UFR); /* First we must enable FIFO */
- outb(0xa7, iobase + UFR);
-
- netif_wake_queue(self->netdev);
-
- /* Enable some interrupts so we can receive frames */
- switch_bank(iobase, SET0);
- if (speed > PIO_MAX_SPEED) {
- outb(ICR_EFSFI, iobase + ICR);
- w83977af_dma_receive(self);
- } else {
- outb(ICR_ERBRI, iobase + ICR);
- }
-
- /* Restore SSR */
- outb(set, iobase + SSR);
-}
-
-/*
- * Function w83977af_hard_xmit (skb, dev)
- *
- * Sets up a DMA transfer to send the current frame.
- *
- */
-static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct w83977af_ir *self;
- __s32 speed;
- int iobase;
- __u8 set;
- int mtt;
-
- self = netdev_priv(dev);
-
- iobase = self->io.fir_base;
-
- pr_debug("%s: %ld, skb->len=%d\n", __func__, jiffies, (int)skb->len);
-
- /* Lock transmit buffer */
- netif_stop_queue(dev);
-
- /* Check if we need to change the speed */
- speed = irda_get_next_speed(skb);
- if ((speed != self->io.speed) && (speed != -1)) {
- /* Check for empty frame */
- if (!skb->len) {
- w83977af_change_speed(self, speed);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- self->new_speed = speed;
- }
-
- /* Save current set */
- set = inb(iobase + SSR);
-
- /* Decide if we should use PIO or DMA transfer */
- if (self->io.speed > PIO_MAX_SPEED) {
- self->tx_buff.data = self->tx_buff.head;
- skb_copy_from_linear_data(skb, self->tx_buff.data, skb->len);
- self->tx_buff.len = skb->len;
-
- mtt = irda_get_mtt(skb);
- pr_debug("%s: %ld, mtt=%d\n", __func__, jiffies, mtt);
- if (mtt > 1000)
- mdelay(mtt / 1000);
- else if (mtt)
- udelay(mtt);
-
- /* Enable DMA interrupt */
- switch_bank(iobase, SET0);
- outb(ICR_EDMAI, iobase + ICR);
- w83977af_dma_write(self, iobase);
- } else {
- self->tx_buff.data = self->tx_buff.head;
- self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
- self->tx_buff.truesize);
-
- /* Add interrupt on tx low level (will fire immediately) */
- switch_bank(iobase, SET0);
- outb(ICR_ETXTHI, iobase + ICR);
- }
- dev_kfree_skb(skb);
-
- /* Restore set register */
- outb(set, iobase + SSR);
-
- return NETDEV_TX_OK;
-}
-
-/*
- * Function w83977af_dma_write (self, iobase)
- *
- * Send frame using DMA
- *
- */
-static void w83977af_dma_write(struct w83977af_ir *self, int iobase)
-{
- __u8 set;
-
- pr_debug("%s: len=%d\n", __func__, self->tx_buff.len);
-
- /* Save current set */
- set = inb(iobase + SSR);
-
- /* Disable DMA */
- switch_bank(iobase, SET0);
- outb(inb(iobase + HCR) & ~HCR_EN_DMA, iobase + HCR);
-
- /* Choose transmit DMA channel */
- switch_bank(iobase, SET2);
- outb(ADCR1_D_CHSW | /*ADCR1_DMA_F|*/ADCR1_ADV_SL, iobase + ADCR1);
- irda_setup_dma(self->io.dma, self->tx_buff_dma, self->tx_buff.len,
- DMA_MODE_WRITE);
- self->io.direction = IO_XMIT;
-
- /* Enable DMA */
- switch_bank(iobase, SET0);
- outb(inb(iobase + HCR) | HCR_EN_DMA | HCR_TX_WT, iobase + HCR);
-
- /* Restore set register */
- outb(set, iobase + SSR);
-}
-
-/*
- * Function w83977af_pio_write (iobase, buf, len, fifo_size)
- *
- *
- *
- */
-static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
-{
- int actual = 0;
- __u8 set;
-
- /* Save current bank */
- set = inb(iobase + SSR);
-
- switch_bank(iobase, SET0);
- if (!(inb_p(iobase + USR) & USR_TSRE)) {
- pr_debug("%s: warning, FIFO not empty yet!\n", __func__);
-
- fifo_size -= 17;
- pr_debug("%s: %d bytes left in tx fifo\n", __func__, fifo_size);
- }
-
- /* Fill FIFO with current frame */
- while ((fifo_size-- > 0) && (actual < len)) {
- /* Transmit next byte */
- outb(buf[actual++], iobase + TBR);
- }
-
- pr_debug("%s: fifo_size %d ; %d sent of %d\n",
- __func__, fifo_size, actual, len);
-
- /* Restore bank */
- outb(set, iobase + SSR);
-
- return actual;
-}
-
-/*
- * Function w83977af_dma_xmit_complete (self)
- *
- * The transfer of a frame in finished. So do the necessary things
- *
- *
- */
-static void w83977af_dma_xmit_complete(struct w83977af_ir *self)
-{
- int iobase;
- __u8 set;
-
- pr_debug("%s: %ld\n", __func__, jiffies);
-
- IRDA_ASSERT(self, return;);
-
- iobase = self->io.fir_base;
-
- /* Save current set */
- set = inb(iobase + SSR);
-
- /* Disable DMA */
- switch_bank(iobase, SET0);
- outb(inb(iobase + HCR) & ~HCR_EN_DMA, iobase + HCR);
-
- /* Check for underrun! */
- if (inb(iobase + AUDR) & AUDR_UNDR) {
- pr_debug("%s: Transmit underrun!\n", __func__);
-
- self->netdev->stats.tx_errors++;
- self->netdev->stats.tx_fifo_errors++;
-
- /* Clear bit, by writing 1 to it */
- outb(AUDR_UNDR, iobase + AUDR);
- } else {
- self->netdev->stats.tx_packets++;
- }
-
- if (self->new_speed) {
- w83977af_change_speed(self, self->new_speed);
- self->new_speed = 0;
- }
-
- /* Unlock tx_buff and request another frame */
- /* Tell the network layer, that we want more frames */
- netif_wake_queue(self->netdev);
-
- /* Restore set */
- outb(set, iobase + SSR);
-}
-
-/*
- * Function w83977af_dma_receive (self)
- *
- * Get ready for receiving a frame. The device will initiate a DMA
- * if it starts to receive a frame.
- *
- */
-static int w83977af_dma_receive(struct w83977af_ir *self)
-{
- int iobase;
- __u8 set;
-#ifdef CONFIG_ARCH_NETWINDER
- unsigned long flags;
- __u8 hcr;
-#endif
- IRDA_ASSERT(self, return -1;);
-
- pr_debug("%s\n", __func__);
-
- iobase = self->io.fir_base;
-
- /* Save current set */
- set = inb(iobase + SSR);
-
- /* Disable DMA */
- switch_bank(iobase, SET0);
- outb(inb(iobase + HCR) & ~HCR_EN_DMA, iobase + HCR);
-
- /* Choose DMA Rx, DMA Fairness, and Advanced mode */
- switch_bank(iobase, SET2);
- outb((inb(iobase + ADCR1) & ~ADCR1_D_CHSW)/*|ADCR1_DMA_F*/ | ADCR1_ADV_SL,
- iobase + ADCR1);
-
- self->io.direction = IO_RECV;
- self->rx_buff.data = self->rx_buff.head;
-
-#ifdef CONFIG_ARCH_NETWINDER
- spin_lock_irqsave(&self->lock, flags);
-
- disable_dma(self->io.dma);
- clear_dma_ff(self->io.dma);
- set_dma_mode(self->io.dma, DMA_MODE_READ);
- set_dma_addr(self->io.dma, self->rx_buff_dma);
- set_dma_count(self->io.dma, self->rx_buff.truesize);
-#else
- irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize,
- DMA_MODE_READ);
-#endif
- /*
- * Reset Rx FIFO. This will also flush the ST_FIFO, it's very
- * important that we don't reset the Tx FIFO since it might not
- * be finished transmitting yet
- */
- switch_bank(iobase, SET0);
- outb(UFR_RXTL | UFR_TXTL | UFR_RXF_RST | UFR_EN_FIFO, iobase + UFR);
- self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0;
-
- /* Enable DMA */
- switch_bank(iobase, SET0);
-#ifdef CONFIG_ARCH_NETWINDER
- hcr = inb(iobase + HCR);
- outb(hcr | HCR_EN_DMA, iobase + HCR);
- enable_dma(self->io.dma);
- spin_unlock_irqrestore(&self->lock, flags);
-#else
- outb(inb(iobase + HCR) | HCR_EN_DMA, iobase + HCR);
-#endif
- /* Restore set */
- outb(set, iobase + SSR);
-
- return 0;
-}
-
-/*
- * Function w83977af_receive_complete (self)
- *
- * Finished with receiving a frame
- *
- */
-static int w83977af_dma_receive_complete(struct w83977af_ir *self)
-{
- struct sk_buff *skb;
- struct st_fifo *st_fifo;
- int len;
- int iobase;
- __u8 set;
- __u8 status;
-
- pr_debug("%s\n", __func__);
-
- st_fifo = &self->st_fifo;
-
- iobase = self->io.fir_base;
-
- /* Save current set */
- set = inb(iobase + SSR);
-
- iobase = self->io.fir_base;
-
- /* Read status FIFO */
- switch_bank(iobase, SET5);
- while ((status = inb(iobase + FS_FO)) & FS_FO_FSFDR) {
- st_fifo->entries[st_fifo->tail].status = status;
-
- st_fifo->entries[st_fifo->tail].len = inb(iobase + RFLFL);
- st_fifo->entries[st_fifo->tail].len |= inb(iobase + RFLFH) << 8;
-
- st_fifo->tail++;
- st_fifo->len++;
- }
-
- while (st_fifo->len) {
- /* Get first entry */
- status = st_fifo->entries[st_fifo->head].status;
- len = st_fifo->entries[st_fifo->head].len;
- st_fifo->head++;
- st_fifo->len--;
-
- /* Check for errors */
- if (status & FS_FO_ERR_MSK) {
- if (status & FS_FO_LST_FR) {
- /* Add number of lost frames to stats */
- self->netdev->stats.rx_errors += len;
- } else {
- /* Skip frame */
- self->netdev->stats.rx_errors++;
-
- self->rx_buff.data += len;
-
- if (status & FS_FO_MX_LEX)
- self->netdev->stats.rx_length_errors++;
-
- if (status & FS_FO_PHY_ERR)
- self->netdev->stats.rx_frame_errors++;
-
- if (status & FS_FO_CRC_ERR)
- self->netdev->stats.rx_crc_errors++;
- }
- /* The errors below can be reported in both cases */
- if (status & FS_FO_RX_OV)
- self->netdev->stats.rx_fifo_errors++;
-
- if (status & FS_FO_FSF_OV)
- self->netdev->stats.rx_fifo_errors++;
-
- } else {
- /* Check if we have transferred all data to memory */
- switch_bank(iobase, SET0);
- if (inb(iobase + USR) & USR_RDR)
- udelay(80); /* Should be enough!? */
-
- skb = dev_alloc_skb(len + 1);
- if (!skb) {
- pr_info("%s: memory squeeze, dropping frame\n",
- __func__);
- /* Restore set register */
- outb(set, iobase + SSR);
-
- return FALSE;
- }
-
- /* Align to 20 bytes */
- skb_reserve(skb, 1);
-
- /* Copy frame without CRC */
- if (self->io.speed < 4000000) {
- skb_put(skb, len - 2);
- skb_copy_to_linear_data(skb,
- self->rx_buff.data,
- len - 2);
- } else {
- skb_put(skb, len - 4);
- skb_copy_to_linear_data(skb,
- self->rx_buff.data,
- len - 4);
- }
-
- /* Move to next frame */
- self->rx_buff.data += len;
- self->netdev->stats.rx_packets++;
-
- skb->dev = self->netdev;
- skb_reset_mac_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- netif_rx(skb);
- }
- }
- /* Restore set register */
- outb(set, iobase + SSR);
-
- return TRUE;
-}
-
-/*
- * Function pc87108_pio_receive (self)
- *
- * Receive all data in receiver FIFO
- *
- */
-static void w83977af_pio_receive(struct w83977af_ir *self)
-{
- __u8 byte = 0x00;
- int iobase;
-
- IRDA_ASSERT(self, return;);
-
- iobase = self->io.fir_base;
-
- /* Receive all characters in Rx FIFO */
- do {
- byte = inb(iobase + RBR);
- async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff,
- byte);
- } while (inb(iobase + USR) & USR_RDR); /* Data available */
-}
-
-/*
- * Function w83977af_sir_interrupt (self, eir)
- *
- * Handle SIR interrupt
- *
- */
-static __u8 w83977af_sir_interrupt(struct w83977af_ir *self, int isr)
-{
- int actual;
- __u8 new_icr = 0;
- __u8 set;
- int iobase;
-
- pr_debug("%s: isr=%#x\n", __func__, isr);
-
- iobase = self->io.fir_base;
- /* Transmit FIFO low on data */
- if (isr & ISR_TXTH_I) {
- /* Write data left in transmit buffer */
- actual = w83977af_pio_write(self->io.fir_base,
- self->tx_buff.data,
- self->tx_buff.len,
- self->io.fifo_size);
-
- self->tx_buff.data += actual;
- self->tx_buff.len -= actual;
-
- self->io.direction = IO_XMIT;
-
- /* Check if finished */
- if (self->tx_buff.len > 0) {
- new_icr |= ICR_ETXTHI;
- } else {
- set = inb(iobase + SSR);
- switch_bank(iobase, SET0);
- outb(AUDR_SFEND, iobase + AUDR);
- outb(set, iobase + SSR);
-
- self->netdev->stats.tx_packets++;
-
- /* Feed me more packets */
- netif_wake_queue(self->netdev);
- new_icr |= ICR_ETBREI;
- }
- }
- /* Check if transmission has completed */
- if (isr & ISR_TXEMP_I) {
- /* Check if we need to change the speed? */
- if (self->new_speed) {
- pr_debug("%s: Changing speed!\n", __func__);
- w83977af_change_speed(self, self->new_speed);
- self->new_speed = 0;
- }
-
- /* Turn around and get ready to receive some data */
- self->io.direction = IO_RECV;
- new_icr |= ICR_ERBRI;
- }
-
- /* Rx FIFO threshold or timeout */
- if (isr & ISR_RXTH_I) {
- w83977af_pio_receive(self);
-
- /* Keep receiving */
- new_icr |= ICR_ERBRI;
- }
- return new_icr;
-}
-
-/*
- * Function pc87108_fir_interrupt (self, eir)
- *
- * Handle MIR/FIR interrupt
- *
- */
-static __u8 w83977af_fir_interrupt(struct w83977af_ir *self, int isr)
-{
- __u8 new_icr = 0;
- __u8 set;
- int iobase;
-
- iobase = self->io.fir_base;
- set = inb(iobase + SSR);
-
- /* End of frame detected in FIFO */
- if (isr & (ISR_FEND_I | ISR_FSF_I)) {
- if (w83977af_dma_receive_complete(self)) {
- /* Wait for next status FIFO interrupt */
- new_icr |= ICR_EFSFI;
- } else {
- /* DMA not finished yet */
-
- /* Set timer value, resolution 1 ms */
- switch_bank(iobase, SET4);
- outb(0x01, iobase + TMRL); /* 1 ms */
- outb(0x00, iobase + TMRH);
-
- /* Start timer */
- outb(IR_MSL_EN_TMR, iobase + IR_MSL);
-
- new_icr |= ICR_ETMRI;
- }
- }
- /* Timer finished */
- if (isr & ISR_TMR_I) {
- /* Disable timer */
- switch_bank(iobase, SET4);
- outb(0, iobase + IR_MSL);
-
- /* Clear timer event */
- /* switch_bank(iobase, SET0); */
-/* outb(ASCR_CTE, iobase+ASCR); */
-
- /* Check if this is a TX timer interrupt */
- if (self->io.direction == IO_XMIT) {
- w83977af_dma_write(self, iobase);
-
- new_icr |= ICR_EDMAI;
- } else {
- /* Check if DMA has now finished */
- w83977af_dma_receive_complete(self);
-
- new_icr |= ICR_EFSFI;
- }
- }
- /* Finished with DMA */
- if (isr & ISR_DMA_I) {
- w83977af_dma_xmit_complete(self);
-
- /* Check if there are more frames to be transmitted */
- /* if (irda_device_txqueue_empty(self)) { */
-
- /* Prepare for receive
- *
- * ** Netwinder Tx DMA likes that we do this anyway **
- */
- w83977af_dma_receive(self);
- new_icr = ICR_EFSFI;
- /* } */
- }
-
- /* Restore set */
- outb(set, iobase + SSR);
-
- return new_icr;
-}
-
-/*
- * Function w83977af_interrupt (irq, dev_id, regs)
- *
- * An interrupt from the chip has arrived. Time to do some work
- *
- */
-static irqreturn_t w83977af_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct w83977af_ir *self;
- __u8 set, icr, isr;
- int iobase;
-
- self = netdev_priv(dev);
-
- iobase = self->io.fir_base;
-
- /* Save current bank */
- set = inb(iobase + SSR);
- switch_bank(iobase, SET0);
-
- icr = inb(iobase + ICR);
- isr = inb(iobase + ISR) & icr; /* Mask out the interesting ones */
-
- outb(0, iobase + ICR); /* Disable interrupts */
-
- if (isr) {
- /* Dispatch interrupt handler for the current speed */
- if (self->io.speed > PIO_MAX_SPEED)
- icr = w83977af_fir_interrupt(self, isr);
- else
- icr = w83977af_sir_interrupt(self, isr);
- }
-
- outb(icr, iobase + ICR); /* Restore (new) interrupts */
- outb(set, iobase + SSR); /* Restore bank register */
- return IRQ_RETVAL(isr);
-}
-
-/*
- * Function w83977af_is_receiving (self)
- *
- * Return TRUE is we are currently receiving a frame
- *
- */
-static int w83977af_is_receiving(struct w83977af_ir *self)
-{
- int status = FALSE;
- int iobase;
- __u8 set;
-
- IRDA_ASSERT(self, return FALSE;);
-
- if (self->io.speed > 115200) {
- iobase = self->io.fir_base;
-
- /* Check if rx FIFO is not empty */
- set = inb(iobase + SSR);
- switch_bank(iobase, SET2);
- if ((inb(iobase + RXFDTH) & 0x3f) != 0) {
- /* We are receiving something */
- status = TRUE;
- }
- outb(set, iobase + SSR);
- } else {
- status = (self->rx_buff.state != OUTSIDE_FRAME);
- }
-
- return status;
-}
-
-/*
- * Function w83977af_net_open (dev)
- *
- * Start the device
- *
- */
-static int w83977af_net_open(struct net_device *dev)
-{
- struct w83977af_ir *self;
- int iobase;
- char hwname[32];
- __u8 set;
-
- IRDA_ASSERT(dev, return -1;);
- self = netdev_priv(dev);
-
- IRDA_ASSERT(self, return 0;);
-
- iobase = self->io.fir_base;
-
- if (request_irq(self->io.irq, w83977af_interrupt, 0, dev->name,
- (void *)dev)) {
- return -EAGAIN;
- }
- /*
- * Always allocate the DMA channel after the IRQ,
- * and clean up on failure.
- */
- if (request_dma(self->io.dma, dev->name)) {
- free_irq(self->io.irq, dev);
- return -EAGAIN;
- }
-
- /* Save current set */
- set = inb(iobase + SSR);
-
- /* Enable some interrupts so we can receive frames again */
- switch_bank(iobase, SET0);
- if (self->io.speed > 115200) {
- outb(ICR_EFSFI, iobase + ICR);
- w83977af_dma_receive(self);
- } else {
- outb(ICR_ERBRI, iobase + ICR);
- }
-
- /* Restore bank register */
- outb(set, iobase + SSR);
-
- /* Ready to play! */
- netif_start_queue(dev);
-
- /* Give self a hardware name */
- sprintf(hwname, "w83977af @ 0x%03x", self->io.fir_base);
-
- /*
- * Open new IrLAP layer instance, now that everything should be
- * initialized properly
- */
- self->irlap = irlap_open(dev, &self->qos, hwname);
-
- return 0;
-}
-
-/*
- * Function w83977af_net_close (dev)
- *
- * Stop the device
- *
- */
-static int w83977af_net_close(struct net_device *dev)
-{
- struct w83977af_ir *self;
- int iobase;
- __u8 set;
-
- IRDA_ASSERT(dev, return -1;);
-
- self = netdev_priv(dev);
-
- IRDA_ASSERT(self, return 0;);
-
- iobase = self->io.fir_base;
-
- /* Stop device */
- netif_stop_queue(dev);
-
- /* Stop and remove instance of IrLAP */
- if (self->irlap)
- irlap_close(self->irlap);
- self->irlap = NULL;
-
- disable_dma(self->io.dma);
-
- /* Save current set */
- set = inb(iobase + SSR);
-
- /* Disable interrupts */
- switch_bank(iobase, SET0);
- outb(0, iobase + ICR);
-
- free_irq(self->io.irq, dev);
- free_dma(self->io.dma);
-
- /* Restore bank register */
- outb(set, iobase + SSR);
-
- return 0;
-}
-
-/*
- * Function w83977af_net_ioctl (dev, rq, cmd)
- *
- * Process IOCTL commands for this device
- *
- */
-static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct if_irda_req *irq = (struct if_irda_req *)rq;
- struct w83977af_ir *self;
- unsigned long flags;
- int ret = 0;
-
- IRDA_ASSERT(dev, return -1;);
-
- self = netdev_priv(dev);
-
- IRDA_ASSERT(self, return -1;);
-
- pr_debug("%s: %s, (cmd=0x%X)\n", __func__, dev->name, cmd);
-
- spin_lock_irqsave(&self->lock, flags);
-
- switch (cmd) {
- case SIOCSBANDWIDTH: /* Set bandwidth */
- if (!capable(CAP_NET_ADMIN)) {
- ret = -EPERM;
- goto out;
- }
- w83977af_change_speed(self, irq->ifr_baudrate);
- break;
- case SIOCSMEDIABUSY: /* Set media busy */
- if (!capable(CAP_NET_ADMIN)) {
- ret = -EPERM;
- goto out;
- }
- irda_device_set_media_busy(self->netdev, TRUE);
- break;
- case SIOCGRECEIVING: /* Check if we are receiving right now */
- irq->ifr_receiving = w83977af_is_receiving(self);
- break;
- default:
- ret = -EOPNOTSUPP;
- }
-out:
- spin_unlock_irqrestore(&self->lock, flags);
- return ret;
-}
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("Winbond W83977AF IrDA Device Driver");
-MODULE_LICENSE("GPL");
-
-module_param(qos_mtt_bits, int, 0);
-MODULE_PARM_DESC(qos_mtt_bits, "Mimimum Turn Time");
-module_param_hw_array(io, int, ioport, NULL, 0);
-MODULE_PARM_DESC(io, "Base I/O addresses");
-module_param_hw_array(irq, int, irq, NULL, 0);
-MODULE_PARM_DESC(irq, "IRQ lines");
-
-/*
- * Function init_module (void)
- *
- *
- *
- */
-module_init(w83977af_init);
-
-/*
- * Function cleanup_module (void)
- *
- *
- *
- */
-module_exit(w83977af_cleanup);
diff --git a/drivers/staging/irda/drivers/w83977af_ir.h b/drivers/staging/irda/drivers/w83977af_ir.h
deleted file mode 100644
index fefe9b11e200..000000000000
--- a/drivers/staging/irda/drivers/w83977af_ir.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/*********************************************************************
- *
- * Filename: w83977af_ir.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Paul VanderSpek
- * Created at: Thu Nov 19 13:55:34 1998
- * Modified at: Tue Jan 11 13:08:19 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-2000 Dag Brattli, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef W83977AF_IR_H
-#define W83977AF_IR_H
-
-#include <asm/io.h>
-#include <linux/types.h>
-
-/* Flags for configuration register CRF0 */
-#define ENBNKSEL 0x01
-#define APEDCRC 0x02
-#define TXW4C 0x04
-#define RXW4C 0x08
-
-/* Bank 0 */
-#define RBR 0x00 /* Receiver buffer register */
-#define TBR 0x00 /* Transmitter buffer register */
-
-#define ICR 0x01 /* Interrupt configuration register */
-#define ICR_ERBRI 0x01 /* Receiver buffer register interrupt */
-#define ICR_ETBREI 0x02 /* Transeiver empty interrupt */
-#define ICR_EUSRI 0x04//* IR status interrupt */
-#define ICR_EHSRI 0x04
-#define ICR_ETXURI 0x04 /* Tx underrun */
-#define ICR_EDMAI 0x10 /* DMA interrupt */
-#define ICR_ETXTHI 0x20 /* Transmitter threshold interrupt */
-#define ICR_EFSFI 0x40 /* Frame status FIFO interrupt */
-#define ICR_ETMRI 0x80 /* Timer interrupt */
-
-#define UFR 0x02 /* FIFO control register */
-#define UFR_EN_FIFO 0x01 /* Enable FIFO's */
-#define UFR_RXF_RST 0x02 /* Reset Rx FIFO */
-#define UFR_TXF_RST 0x04 /* Reset Tx FIFO */
-#define UFR_RXTL 0x80 /* Rx FIFO threshold (set to 16) */
-#define UFR_TXTL 0x20 /* Tx FIFO threshold (set to 17) */
-
-#define ISR 0x02 /* Interrupt status register */
-#define ISR_RXTH_I 0x01 /* Receive threshold interrupt */
-#define ISR_TXEMP_I 0x02 /* Transmitter empty interrupt */
-#define ISR_FEND_I 0x04
-#define ISR_DMA_I 0x10
-#define ISR_TXTH_I 0x20 /* Transmitter threshold interrupt */
-#define ISR_FSF_I 0x40
-#define ISR_TMR_I 0x80 /* Timer interrupt */
-
-#define UCR 0x03 /* Uart control register */
-#define UCR_DLS8 0x03 /* 8N1 */
-
-#define SSR 0x03 /* Sets select register */
-#define SET0 UCR_DLS8 /* Make sure we keep 8N1 */
-#define SET1 (0x80|UCR_DLS8) /* Make sure we keep 8N1 */
-#define SET2 0xE0
-#define SET3 0xE4
-#define SET4 0xE8
-#define SET5 0xEC
-#define SET6 0xF0
-#define SET7 0xF4
-
-#define HCR 0x04
-#define HCR_MODE_MASK ~(0xD0)
-#define HCR_SIR 0x60
-#define HCR_MIR_576 0x20
-#define HCR_MIR_1152 0x80
-#define HCR_FIR 0xA0
-#define HCR_EN_DMA 0x04
-#define HCR_EN_IRQ 0x08
-#define HCR_TX_WT 0x08
-
-#define USR 0x05 /* IR status register */
-#define USR_RDR 0x01 /* Receive data ready */
-#define USR_TSRE 0x40 /* Transmitter empty? */
-
-#define AUDR 0x07
-#define AUDR_SFEND 0x08 /* Set a frame end */
-#define AUDR_RXBSY 0x20 /* Rx busy */
-#define AUDR_UNDR 0x40 /* Transeiver underrun */
-
-/* Set 2 */
-#define ABLL 0x00 /* Advanced baud rate divisor latch (low byte) */
-#define ABHL 0x01 /* Advanced baud rate divisor latch (high byte) */
-
-#define ADCR1 0x02
-#define ADCR1_ADV_SL 0x01
-#define ADCR1_D_CHSW 0x08 /* the specs are wrong. its bit 3, not 4 */
-#define ADCR1_DMA_F 0x02
-
-#define ADCR2 0x04
-#define ADCR2_TXFS32 0x01
-#define ADCR2_RXFS32 0x04
-
-#define RXFDTH 0x07
-
-/* Set 3 */
-#define AUID 0x00
-
-/* Set 4 */
-#define TMRL 0x00 /* Timer value register (low byte) */
-#define TMRH 0x01 /* Timer value register (high byte) */
-
-#define IR_MSL 0x02 /* Infrared mode select */
-#define IR_MSL_EN_TMR 0x01 /* Enable timer */
-
-#define TFRLL 0x04 /* Transmitter frame length (low byte) */
-#define TFRLH 0x05 /* Transmitter frame length (high byte) */
-#define RFRLL 0x06 /* Receiver frame length (low byte) */
-#define RFRLH 0x07 /* Receiver frame length (high byte) */
-
-/* Set 5 */
-
-#define FS_FO 0x05 /* Frame status FIFO */
-#define FS_FO_FSFDR 0x80 /* Frame status FIFO data ready */
-#define FS_FO_LST_FR 0x40 /* Frame lost */
-#define FS_FO_MX_LEX 0x10 /* Max frame len exceeded */
-#define FS_FO_PHY_ERR 0x08 /* Physical layer error */
-#define FS_FO_CRC_ERR 0x04
-#define FS_FO_RX_OV 0x02 /* Receive overrun */
-#define FS_FO_FSF_OV 0x01 /* Frame status FIFO overrun */
-#define FS_FO_ERR_MSK 0x5f /* Error mask */
-
-#define RFLFL 0x06
-#define RFLFH 0x07
-
-/* Set 6 */
-#define IR_CFG2 0x00
-#define IR_CFG2_DIS_CRC 0x02
-
-/* Set 7 */
-#define IRM_CR 0x07 /* Infrared module control register */
-#define IRM_CR_IRX_MSL 0x40
-#define IRM_CR_AF_MNT 0x80 /* Automatic format */
-
-/* For storing entries in the status FIFO */
-struct st_fifo_entry {
- int status;
- int len;
-};
-
-struct st_fifo {
- struct st_fifo_entry entries[10];
- int head;
- int tail;
- int len;
-};
-
-/* Private data for each instance */
-struct w83977af_ir {
- struct st_fifo st_fifo;
-
- int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */
- int tx_len; /* Number of frames in tx_buff */
-
- struct net_device *netdev; /* Yes! we are some kind of netdevice */
-
- struct irlap_cb *irlap; /* The link layer we are binded to */
- struct qos_info qos; /* QoS capabilities for this device */
-
- chipio_t io; /* IrDA controller information */
- iobuff_t tx_buff; /* Transmit buffer */
- iobuff_t rx_buff; /* Receive buffer */
- dma_addr_t tx_buff_dma;
- dma_addr_t rx_buff_dma;
-
- /* Note : currently locking is *very* incomplete, but this
- * will get you started. Check in nsc-ircc.c for a proper
- * locking strategy. - Jean II */
- spinlock_t lock; /* For serializing operations */
-
- __u32 new_speed;
-};
-
-static inline void switch_bank( int iobase, int set)
-{
- outb(set, iobase+SSR);
-}
-
-#endif
diff --git a/drivers/staging/irda/include/net/irda/af_irda.h b/drivers/staging/irda/include/net/irda/af_irda.h
deleted file mode 100644
index 0df574931522..000000000000
--- a/drivers/staging/irda/include/net/irda/af_irda.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*********************************************************************
- *
- * Filename: af_irda.h
- * Version: 1.0
- * Description: IrDA sockets declarations
- * Status: Stable
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Tue Dec 9 21:13:12 1997
- * Modified at: Fri Jan 28 13:16:32 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved.
- * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef AF_IRDA_H
-#define AF_IRDA_H
-
-#include <linux/irda.h>
-#include <net/irda/irda.h>
-#include <net/irda/iriap.h> /* struct iriap_cb */
-#include <net/irda/irias_object.h> /* struct ias_value */
-#include <net/irda/irlmp.h> /* struct lsap_cb */
-#include <net/irda/irttp.h> /* struct tsap_cb */
-#include <net/irda/discovery.h> /* struct discovery_t */
-#include <net/sock.h>
-
-/* IrDA Socket */
-struct irda_sock {
- /* struct sock has to be the first member of irda_sock */
- struct sock sk;
- __u32 saddr; /* my local address */
- __u32 daddr; /* peer address */
-
- struct lsap_cb *lsap; /* LSAP used by Ultra */
- __u8 pid; /* Protocol IP (PID) used by Ultra */
-
- struct tsap_cb *tsap; /* TSAP used by this connection */
- __u8 dtsap_sel; /* remote TSAP address */
- __u8 stsap_sel; /* local TSAP address */
-
- __u32 max_sdu_size_rx;
- __u32 max_sdu_size_tx;
- __u32 max_data_size;
- __u8 max_header_size;
- struct qos_info qos_tx;
-
- __u16_host_order mask; /* Hint bits mask */
- __u16_host_order hints; /* Hint bits */
-
- void *ckey; /* IrLMP client handle */
- void *skey; /* IrLMP service handle */
-
- struct ias_object *ias_obj; /* Our service name + lsap in IAS */
- struct iriap_cb *iriap; /* Used to query remote IAS */
- struct ias_value *ias_result; /* Result of remote IAS query */
-
- hashbin_t *cachelog; /* Result of discovery query */
- __u32 cachedaddr; /* Result of selective discovery query */
-
- int nslots; /* Number of slots to use for discovery */
-
- int errno; /* status of the IAS query */
-
- wait_queue_head_t query_wait; /* Wait for the answer to a query */
- struct timer_list watchdog; /* Timeout for discovery */
-
- LOCAL_FLOW tx_flow;
- LOCAL_FLOW rx_flow;
-};
-
-static inline struct irda_sock *irda_sk(struct sock *sk)
-{
- return (struct irda_sock *)sk;
-}
-
-#endif /* AF_IRDA_H */
diff --git a/drivers/staging/irda/include/net/irda/crc.h b/drivers/staging/irda/include/net/irda/crc.h
deleted file mode 100644
index f202296df9bb..000000000000
--- a/drivers/staging/irda/include/net/irda/crc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*********************************************************************
- *
- * Filename: crc.h
- * Version:
- * Description: CRC routines
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Aug 4 20:40:53 1997
- * Modified at: Sun May 2 20:25:23 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- ********************************************************************/
-
-#ifndef IRDA_CRC_H
-#define IRDA_CRC_H
-
-#include <linux/types.h>
-#include <linux/crc-ccitt.h>
-
-#define INIT_FCS 0xffff /* Initial FCS value */
-#define GOOD_FCS 0xf0b8 /* Good final FCS value */
-
-/* Recompute the FCS with one more character appended. */
-#define irda_fcs(fcs, c) crc_ccitt_byte(fcs, c)
-
-/* Recompute the FCS with len bytes appended. */
-#define irda_calc_crc16(fcs, buf, len) crc_ccitt(fcs, buf, len)
-
-#endif
diff --git a/drivers/staging/irda/include/net/irda/discovery.h b/drivers/staging/irda/include/net/irda/discovery.h
deleted file mode 100644
index 63ae32530567..000000000000
--- a/drivers/staging/irda/include/net/irda/discovery.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*********************************************************************
- *
- * Filename: discovery.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Tue Apr 6 16:53:53 1999
- * Modified at: Tue Oct 5 10:05:10 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
- * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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 DISCOVERY_H
-#define DISCOVERY_H
-
-#include <asm/param.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irqueue.h> /* irda_queue_t */
-#include <net/irda/irlap_event.h> /* LAP_REASON */
-
-#define DISCOVERY_EXPIRE_TIMEOUT (2*sysctl_discovery_timeout*HZ)
-#define DISCOVERY_DEFAULT_SLOTS 0
-
-/*
- * This type is used by the protocols that transmit 16 bits words in
- * little endian format. A little endian machine stores MSB of word in
- * byte[1] and LSB in byte[0]. A big endian machine stores MSB in byte[0]
- * and LSB in byte[1].
- *
- * This structure is used in the code for things that are endian neutral
- * but that fit in a word so that we can manipulate them efficiently.
- * By endian neutral, I mean things that are really an array of bytes,
- * and always used as such, for example the hint bits. Jean II
- */
-typedef union {
- __u16 word;
- __u8 byte[2];
-} __u16_host_order;
-
-/* Types of discovery */
-typedef enum {
- DISCOVERY_LOG, /* What's in our discovery log */
- DISCOVERY_ACTIVE, /* Doing our own discovery on the medium */
- DISCOVERY_PASSIVE, /* Peer doing discovery on the medium */
- EXPIRY_TIMEOUT, /* Entry expired due to timeout */
-} DISCOVERY_MODE;
-
-#define NICKNAME_MAX_LEN 21
-
-/* Basic discovery information about a peer */
-typedef struct irda_device_info discinfo_t; /* linux/irda.h */
-
-/*
- * The DISCOVERY structure is used for both discovery requests and responses
- */
-typedef struct discovery_t {
- irda_queue_t q; /* Must be first! */
-
- discinfo_t data; /* Basic discovery information */
- int name_len; /* Length of nickname */
-
- LAP_REASON condition; /* More info about the discovery */
- int gen_addr_bit; /* Need to generate a new device
- * address? */
- int nslots; /* Number of slots to use when
- * discovering */
- unsigned long timestamp; /* Last time discovered */
- unsigned long firststamp; /* First time discovered */
-} discovery_t;
-
-void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *discovery);
-void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log);
-void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force);
-struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn,
- __u16 mask, int old_entries);
-
-#endif
diff --git a/drivers/staging/irda/include/net/irda/ircomm_core.h b/drivers/staging/irda/include/net/irda/ircomm_core.h
deleted file mode 100644
index 2a580ce9edad..000000000000
--- a/drivers/staging/irda/include/net/irda/ircomm_core.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_core.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Wed Jun 9 08:58:43 1999
- * Modified at: Mon Dec 13 11:52:29 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Dag Brattli, 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.
- *
- * 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 IRCOMM_CORE_H
-#define IRCOMM_CORE_H
-
-#include <net/irda/irda.h>
-#include <net/irda/irqueue.h>
-#include <net/irda/ircomm_event.h>
-
-#define IRCOMM_MAGIC 0x98347298
-#define IRCOMM_HEADER_SIZE 1
-
-struct ircomm_cb; /* Forward decl. */
-
-/*
- * A small call-table, so we don't have to check the service-type whenever
- * we want to do something
- */
-typedef struct {
- int (*data_request)(struct ircomm_cb *, struct sk_buff *, int clen);
- int (*connect_request)(struct ircomm_cb *, struct sk_buff *,
- struct ircomm_info *);
- int (*connect_response)(struct ircomm_cb *, struct sk_buff *);
- int (*disconnect_request)(struct ircomm_cb *, struct sk_buff *,
- struct ircomm_info *);
-} call_t;
-
-struct ircomm_cb {
- irda_queue_t queue;
- magic_t magic;
-
- notify_t notify;
- call_t issue;
-
- int state;
- int line; /* Which TTY line we are using */
-
- struct tsap_cb *tsap;
- struct lsap_cb *lsap;
-
- __u8 dlsap_sel; /* Destination LSAP/TSAP selector */
- __u8 slsap_sel; /* Source LSAP/TSAP selector */
-
- __u32 saddr; /* Source device address (link we are using) */
- __u32 daddr; /* Destination device address */
-
- int max_header_size; /* Header space we must reserve for each frame */
- int max_data_size; /* The amount of data we can fill in each frame */
-
- LOCAL_FLOW flow_status; /* Used by ircomm_lmp */
- int pkt_count; /* Number of frames we have sent to IrLAP */
-
- __u8 service_type;
-};
-
-extern hashbin_t *ircomm;
-
-struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line);
-int ircomm_close(struct ircomm_cb *self);
-
-int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb);
-void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb);
-void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb);
-int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb);
-int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel,
- __u32 saddr, __u32 daddr, struct sk_buff *skb,
- __u8 service_type);
-void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
- struct ircomm_info *info);
-void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
- struct ircomm_info *info);
-int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata);
-int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata);
-void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
- struct ircomm_info *info);
-void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow);
-
-#define ircomm_is_connected(self) (self->state == IRCOMM_CONN)
-
-#endif
diff --git a/drivers/staging/irda/include/net/irda/ircomm_event.h b/drivers/staging/irda/include/net/irda/ircomm_event.h
deleted file mode 100644
index 5bbc32998d57..000000000000
--- a/drivers/staging/irda/include/net/irda/ircomm_event.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_event.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Jun 6 23:51:13 1999
- * Modified at: Thu Jun 10 08:36:25 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Dag Brattli, 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.
- *
- * 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 IRCOMM_EVENT_H
-#define IRCOMM_EVENT_H
-
-#include <net/irda/irmod.h>
-
-typedef enum {
- IRCOMM_IDLE,
- IRCOMM_WAITI,
- IRCOMM_WAITR,
- IRCOMM_CONN,
-} IRCOMM_STATE;
-
-/* IrCOMM Events */
-typedef enum {
- IRCOMM_CONNECT_REQUEST,
- IRCOMM_CONNECT_RESPONSE,
- IRCOMM_TTP_CONNECT_INDICATION,
- IRCOMM_LMP_CONNECT_INDICATION,
- IRCOMM_TTP_CONNECT_CONFIRM,
- IRCOMM_LMP_CONNECT_CONFIRM,
-
- IRCOMM_LMP_DISCONNECT_INDICATION,
- IRCOMM_TTP_DISCONNECT_INDICATION,
- IRCOMM_DISCONNECT_REQUEST,
-
- IRCOMM_TTP_DATA_INDICATION,
- IRCOMM_LMP_DATA_INDICATION,
- IRCOMM_DATA_REQUEST,
- IRCOMM_CONTROL_REQUEST,
- IRCOMM_CONTROL_INDICATION,
-} IRCOMM_EVENT;
-
-/*
- * Used for passing information through the state-machine
- */
-struct ircomm_info {
- __u32 saddr; /* Source device address */
- __u32 daddr; /* Destination device address */
- __u8 dlsap_sel;
- LM_REASON reason; /* Reason for disconnect */
- __u32 max_data_size;
- __u32 max_header_size;
-
- struct qos_info *qos;
-};
-
-extern const char *const ircomm_state[];
-
-struct ircomm_cb; /* Forward decl. */
-
-int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb, struct ircomm_info *info);
-void ircomm_next_state(struct ircomm_cb *self, IRCOMM_STATE state);
-
-#endif
diff --git a/drivers/staging/irda/include/net/irda/ircomm_lmp.h b/drivers/staging/irda/include/net/irda/ircomm_lmp.h
deleted file mode 100644
index 5042a5021a04..000000000000
--- a/drivers/staging/irda/include/net/irda/ircomm_lmp.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_lmp.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Wed Jun 9 10:06:07 1999
- * Modified at: Fri Aug 13 07:32:32 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Dag Brattli, 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.
- *
- * 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 IRCOMM_LMP_H
-#define IRCOMM_LMP_H
-
-#include <net/irda/ircomm_core.h>
-
-int ircomm_open_lsap(struct ircomm_cb *self);
-
-#endif
diff --git a/drivers/staging/irda/include/net/irda/ircomm_param.h b/drivers/staging/irda/include/net/irda/ircomm_param.h
deleted file mode 100644
index 1f67432321c4..000000000000
--- a/drivers/staging/irda/include/net/irda/ircomm_param.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_param.h
- * Version: 1.0
- * Description: Parameter handling for the IrCOMM protocol
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Jun 7 08:47:28 1999
- * Modified at: Wed Aug 25 13:46:33 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Dag Brattli, 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.
- *
- * 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 IRCOMM_PARAMS_H
-#define IRCOMM_PARAMS_H
-
-#include <net/irda/parameters.h>
-
-/* Parameters common to all service types */
-#define IRCOMM_SERVICE_TYPE 0x00
-#define IRCOMM_PORT_TYPE 0x01 /* Only used in LM-IAS */
-#define IRCOMM_PORT_NAME 0x02 /* Only used in LM-IAS */
-
-/* Parameters for both 3 wire and 9 wire */
-#define IRCOMM_DATA_RATE 0x10
-#define IRCOMM_DATA_FORMAT 0x11
-#define IRCOMM_FLOW_CONTROL 0x12
-#define IRCOMM_XON_XOFF 0x13
-#define IRCOMM_ENQ_ACK 0x14
-#define IRCOMM_LINE_STATUS 0x15
-#define IRCOMM_BREAK 0x16
-
-/* Parameters for 9 wire */
-#define IRCOMM_DTE 0x20
-#define IRCOMM_DCE 0x21
-#define IRCOMM_POLL 0x22
-
-/* Service type (details) */
-#define IRCOMM_3_WIRE_RAW 0x01
-#define IRCOMM_3_WIRE 0x02
-#define IRCOMM_9_WIRE 0x04
-#define IRCOMM_CENTRONICS 0x08
-
-/* Port type (details) */
-#define IRCOMM_SERIAL 0x00
-#define IRCOMM_PARALLEL 0x01
-
-/* Data format (details) */
-#define IRCOMM_WSIZE_5 0x00
-#define IRCOMM_WSIZE_6 0x01
-#define IRCOMM_WSIZE_7 0x02
-#define IRCOMM_WSIZE_8 0x03
-
-#define IRCOMM_1_STOP_BIT 0x00
-#define IRCOMM_2_STOP_BIT 0x04 /* 1.5 if char len 5 */
-
-#define IRCOMM_PARITY_DISABLE 0x00
-#define IRCOMM_PARITY_ENABLE 0x08
-
-#define IRCOMM_PARITY_ODD 0x00
-#define IRCOMM_PARITY_EVEN 0x10
-#define IRCOMM_PARITY_MARK 0x20
-#define IRCOMM_PARITY_SPACE 0x30
-
-/* Flow control */
-#define IRCOMM_XON_XOFF_IN 0x01
-#define IRCOMM_XON_XOFF_OUT 0x02
-#define IRCOMM_RTS_CTS_IN 0x04
-#define IRCOMM_RTS_CTS_OUT 0x08
-#define IRCOMM_DSR_DTR_IN 0x10
-#define IRCOMM_DSR_DTR_OUT 0x20
-#define IRCOMM_ENQ_ACK_IN 0x40
-#define IRCOMM_ENQ_ACK_OUT 0x80
-
-/* Line status */
-#define IRCOMM_OVERRUN_ERROR 0x02
-#define IRCOMM_PARITY_ERROR 0x04
-#define IRCOMM_FRAMING_ERROR 0x08
-
-/* DTE (Data terminal equipment) line settings */
-#define IRCOMM_DELTA_DTR 0x01
-#define IRCOMM_DELTA_RTS 0x02
-#define IRCOMM_DTR 0x04
-#define IRCOMM_RTS 0x08
-
-/* DCE (Data communications equipment) line settings */
-#define IRCOMM_DELTA_CTS 0x01 /* Clear to send has changed */
-#define IRCOMM_DELTA_DSR 0x02 /* Data set ready has changed */
-#define IRCOMM_DELTA_RI 0x04 /* Ring indicator has changed */
-#define IRCOMM_DELTA_CD 0x08 /* Carrier detect has changed */
-#define IRCOMM_CTS 0x10 /* Clear to send is high */
-#define IRCOMM_DSR 0x20 /* Data set ready is high */
-#define IRCOMM_RI 0x40 /* Ring indicator is high */
-#define IRCOMM_CD 0x80 /* Carrier detect is high */
-#define IRCOMM_DCE_DELTA_ANY 0x0f
-
-/*
- * Parameter state
- */
-struct ircomm_params {
- /* General control params */
- __u8 service_type;
- __u8 port_type;
- char port_name[32];
-
- /* Control params for 3- and 9-wire service type */
- __u32 data_rate; /* Data rate in bps */
- __u8 data_format;
- __u8 flow_control;
- char xonxoff[2];
- char enqack[2];
- __u8 line_status;
- __u8 _break;
-
- __u8 null_modem;
-
- /* Control params for 9-wire service type */
- __u8 dte;
- __u8 dce;
- __u8 poll;
-
- /* Control params for Centronics service type */
-};
-
-struct ircomm_tty_cb; /* Forward decl. */
-
-int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush);
-
-extern pi_param_info_t ircomm_param_info;
-
-#endif /* IRCOMM_PARAMS_H */
-
diff --git a/drivers/staging/irda/include/net/irda/ircomm_ttp.h b/drivers/staging/irda/include/net/irda/ircomm_ttp.h
deleted file mode 100644
index c5627288bca3..000000000000
--- a/drivers/staging/irda/include/net/irda/ircomm_ttp.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_ttp.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Wed Jun 9 10:06:07 1999
- * Modified at: Fri Aug 13 07:32:22 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Dag Brattli, 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.
- *
- * 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 IRCOMM_TTP_H
-#define IRCOMM_TTP_H
-
-#include <net/irda/ircomm_core.h>
-
-int ircomm_open_tsap(struct ircomm_cb *self);
-
-#endif
-
diff --git a/drivers/staging/irda/include/net/irda/ircomm_tty.h b/drivers/staging/irda/include/net/irda/ircomm_tty.h
deleted file mode 100644
index 8d4f588974bc..000000000000
--- a/drivers/staging/irda/include/net/irda/ircomm_tty.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_tty.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Jun 6 23:24:22 1999
- * Modified at: Fri Jan 28 13:16:57 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999-2000 Dag Brattli, 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.
- *
- * 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 IRCOMM_TTY_H
-#define IRCOMM_TTY_H
-
-#include <linux/serial.h>
-#include <linux/termios.h>
-#include <linux/timer.h>
-#include <linux/tty.h> /* struct tty_struct */
-
-#include <net/irda/irias_object.h>
-#include <net/irda/ircomm_core.h>
-#include <net/irda/ircomm_param.h>
-
-#define IRCOMM_TTY_PORTS 32
-#define IRCOMM_TTY_MAGIC 0x3432
-#define IRCOMM_TTY_MAJOR 161
-#define IRCOMM_TTY_MINOR 0
-
-/* This is used as an initial value to max_header_size before the proper
- * value is filled in (5 for ttp, 4 for lmp). This allow us to detect
- * the state of the underlying connection. - Jean II */
-#define IRCOMM_TTY_HDR_UNINITIALISED 16
-/* Same for payload size. See qos.c for the smallest max data size */
-#define IRCOMM_TTY_DATA_UNINITIALISED (64 - IRCOMM_TTY_HDR_UNINITIALISED)
-
-/*
- * IrCOMM TTY driver state
- */
-struct ircomm_tty_cb {
- irda_queue_t queue; /* Must be first */
- struct tty_port port;
- magic_t magic;
-
- int state; /* Connect state */
-
- struct ircomm_cb *ircomm; /* IrCOMM layer instance */
-
- struct sk_buff *tx_skb; /* Transmit buffer */
- struct sk_buff *ctrl_skb; /* Control data buffer */
-
- /* Parameters */
- struct ircomm_params settings;
-
- __u8 service_type; /* The service that we support */
- int client; /* True if we are a client */
- LOCAL_FLOW flow; /* IrTTP flow status */
-
- int line;
-
- __u8 dlsap_sel;
- __u8 slsap_sel;
-
- __u32 saddr;
- __u32 daddr;
-
- __u32 max_data_size; /* Max data we can transmit in one packet */
- __u32 max_header_size; /* The amount of header space we must reserve */
- __u32 tx_data_size; /* Max data size of current tx_skb */
-
- struct iriap_cb *iriap; /* Instance used for querying remote IAS */
- struct ias_object* obj;
- void *skey;
- void *ckey;
-
- struct timer_list watchdog_timer;
- struct work_struct tqueue;
-
- /* Protect concurent access to :
- * o self->ctrl_skb
- * o self->tx_skb
- * Maybe other things may gain to be protected as well...
- * Jean II */
- spinlock_t spinlock;
-};
-
-void ircomm_tty_start(struct tty_struct *tty);
-void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self);
-
-int ircomm_tty_tiocmget(struct tty_struct *tty);
-int ircomm_tty_tiocmset(struct tty_struct *tty, unsigned int set,
- unsigned int clear);
-int ircomm_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
- unsigned long arg);
-void ircomm_tty_set_termios(struct tty_struct *tty,
- struct ktermios *old_termios);
-
-#endif
-
-
-
-
-
-
-
diff --git a/drivers/staging/irda/include/net/irda/ircomm_tty_attach.h b/drivers/staging/irda/include/net/irda/ircomm_tty_attach.h
deleted file mode 100644
index 20dcbdf258cf..000000000000
--- a/drivers/staging/irda/include/net/irda/ircomm_tty_attach.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_tty_attach.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Wed Jun 9 15:55:18 1999
- * Modified at: Fri Dec 10 21:04:55 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Dag Brattli, 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.
- *
- * 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 IRCOMM_TTY_ATTACH_H
-#define IRCOMM_TTY_ATTACH_H
-
-#include <net/irda/ircomm_tty.h>
-
-typedef enum {
- IRCOMM_TTY_IDLE,
- IRCOMM_TTY_SEARCH,
- IRCOMM_TTY_QUERY_PARAMETERS,
- IRCOMM_TTY_QUERY_LSAP_SEL,
- IRCOMM_TTY_SETUP,
- IRCOMM_TTY_READY,
-} IRCOMM_TTY_STATE;
-
-/* IrCOMM TTY Events */
-typedef enum {
- IRCOMM_TTY_ATTACH_CABLE,
- IRCOMM_TTY_DETACH_CABLE,
- IRCOMM_TTY_DATA_REQUEST,
- IRCOMM_TTY_DATA_INDICATION,
- IRCOMM_TTY_DISCOVERY_REQUEST,
- IRCOMM_TTY_DISCOVERY_INDICATION,
- IRCOMM_TTY_CONNECT_CONFIRM,
- IRCOMM_TTY_CONNECT_INDICATION,
- IRCOMM_TTY_DISCONNECT_REQUEST,
- IRCOMM_TTY_DISCONNECT_INDICATION,
- IRCOMM_TTY_WD_TIMER_EXPIRED,
- IRCOMM_TTY_GOT_PARAMETERS,
- IRCOMM_TTY_GOT_LSAPSEL,
-} IRCOMM_TTY_EVENT;
-
-/* Used for passing information through the state-machine */
-struct ircomm_tty_info {
- __u32 saddr; /* Source device address */
- __u32 daddr; /* Destination device address */
- __u8 dlsap_sel;
-};
-
-extern const char *const ircomm_state[];
-extern const char *const ircomm_tty_state[];
-
-int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
- struct sk_buff *skb, struct ircomm_tty_info *info);
-
-
-int ircomm_tty_attach_cable(struct ircomm_tty_cb *self);
-void ircomm_tty_detach_cable(struct ircomm_tty_cb *self);
-void ircomm_tty_connect_confirm(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *skb);
-void ircomm_tty_disconnect_indication(void *instance, void *sap,
- LM_REASON reason,
- struct sk_buff *skb);
-void ircomm_tty_connect_indication(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *skb);
-int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self);
-void ircomm_tty_link_established(struct ircomm_tty_cb *self);
-
-#endif /* IRCOMM_TTY_ATTACH_H */
diff --git a/drivers/staging/irda/include/net/irda/irda.h b/drivers/staging/irda/include/net/irda/irda.h
deleted file mode 100644
index 92c8fb575213..000000000000
--- a/drivers/staging/irda/include/net/irda/irda.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*********************************************************************
- *
- * Filename: irda.h
- * Version: 1.0
- * Description: IrDA common include file for kernel internal use
- * Status: Stable
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Tue Dec 9 21:13:12 1997
- * Modified at: Fri Jan 28 13:16:32 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved.
- * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef NET_IRDA_H
-#define NET_IRDA_H
-
-#include <linux/skbuff.h> /* struct sk_buff */
-#include <linux/kernel.h>
-#include <linux/if.h> /* sa_family_t in <linux/irda.h> */
-#include <linux/irda.h>
-
-typedef __u32 magic_t;
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-/* Hack to do small backoff when setting media busy in IrLAP */
-#ifndef SMALL
-#define SMALL 5
-#endif
-
-#ifndef IRDA_MIN /* Lets not mix this MIN with other header files */
-#define IRDA_MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-
-#ifndef IRDA_ALIGN
-# define IRDA_ALIGN __attribute__((aligned))
-#endif
-
-#ifdef CONFIG_IRDA_DEBUG
-#define IRDA_ASSERT(expr, func) \
-do { if(!(expr)) { \
- printk( "Assertion failed! %s:%s:%d %s\n", \
- __FILE__,__func__,__LINE__,(#expr) ); \
- func } } while (0)
-#define IRDA_ASSERT_LABEL(label) label
-#else
-#define IRDA_ASSERT(expr, func) do { (void)(expr); } while (0)
-#define IRDA_ASSERT_LABEL(label)
-#endif /* CONFIG_IRDA_DEBUG */
-
-/*
- * Magic numbers used by Linux-IrDA. Random numbers which must be unique to
- * give the best protection
- */
-
-#define IRTTY_MAGIC 0x2357
-#define LAP_MAGIC 0x1357
-#define LMP_MAGIC 0x4321
-#define LMP_LSAP_MAGIC 0x69333
-#define LMP_LAP_MAGIC 0x3432
-#define IRDA_DEVICE_MAGIC 0x63454
-#define IAS_MAGIC 0x007
-#define TTP_MAGIC 0x241169
-#define TTP_TSAP_MAGIC 0x4345
-#define IROBEX_MAGIC 0x341324
-#define HB_MAGIC 0x64534
-#define IRLAN_MAGIC 0x754
-#define IAS_OBJECT_MAGIC 0x34234
-#define IAS_ATTRIB_MAGIC 0x45232
-#define IRDA_TASK_MAGIC 0x38423
-
-#define IAS_DEVICE_ID 0x0000 /* Defined by IrDA, IrLMP section 4.1 (page 68) */
-#define IAS_PNP_ID 0xd342
-#define IAS_OBEX_ID 0x34323
-#define IAS_IRLAN_ID 0x34234
-#define IAS_IRCOMM_ID 0x2343
-#define IAS_IRLPT_ID 0x9876
-
-struct net_device;
-struct packet_type;
-
-void irda_proc_register(void);
-void irda_proc_unregister(void);
-
-int irda_sysctl_register(void);
-void irda_sysctl_unregister(void);
-
-int irsock_init(void);
-void irsock_cleanup(void);
-
-int irda_nl_register(void);
-void irda_nl_unregister(void);
-
-int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype, struct net_device *orig_dev);
-
-#endif /* NET_IRDA_H */
diff --git a/drivers/staging/irda/include/net/irda/irda_device.h b/drivers/staging/irda/include/net/irda/irda_device.h
deleted file mode 100644
index 664bf8178412..000000000000
--- a/drivers/staging/irda/include/net/irda/irda_device.h
+++ /dev/null
@@ -1,285 +0,0 @@
-/*********************************************************************
- *
- * Filename: irda_device.h
- * Version: 0.9
- * Description: Contains various declarations used by the drivers
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Tue Apr 14 12:41:42 1998
- * Modified at: Mon Mar 20 09:08:57 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
- * Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>,
- * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- ********************************************************************/
-
-/*
- * This header contains all the IrDA definitions a driver really
- * needs, and therefore the driver should not need to include
- * any other IrDA headers - Jean II
- */
-
-#ifndef IRDA_DEVICE_H
-#define IRDA_DEVICE_H
-
-#include <linux/tty.h>
-#include <linux/netdevice.h>
-#include <linux/spinlock.h>
-#include <linux/skbuff.h> /* struct sk_buff */
-#include <linux/irda.h>
-#include <linux/types.h>
-
-#include <net/pkt_sched.h>
-#include <net/irda/irda.h>
-#include <net/irda/qos.h> /* struct qos_info */
-#include <net/irda/irqueue.h> /* irda_queue_t */
-
-/* A few forward declarations (to make compiler happy) */
-struct irlap_cb;
-
-/* Some non-standard interface flags (should not conflict with any in if.h) */
-#define IFF_SIR 0x0001 /* Supports SIR speeds */
-#define IFF_MIR 0x0002 /* Supports MIR speeds */
-#define IFF_FIR 0x0004 /* Supports FIR speeds */
-#define IFF_VFIR 0x0008 /* Supports VFIR speeds */
-#define IFF_PIO 0x0010 /* Supports PIO transfer of data */
-#define IFF_DMA 0x0020 /* Supports DMA transfer of data */
-#define IFF_SHM 0x0040 /* Supports shared memory data transfers */
-#define IFF_DONGLE 0x0080 /* Interface has a dongle attached */
-#define IFF_AIR 0x0100 /* Supports Advanced IR (AIR) standards */
-
-#define IO_XMIT 0x01
-#define IO_RECV 0x02
-
-typedef enum {
- IRDA_IRLAP, /* IrDA mode, and deliver to IrLAP */
- IRDA_RAW, /* IrDA mode */
- SHARP_ASK,
- TV_REMOTE, /* Also known as Consumer Electronics IR */
-} INFRARED_MODE;
-
-typedef enum {
- IRDA_TASK_INIT, /* All tasks are initialized with this state */
- IRDA_TASK_DONE, /* Signals that the task is finished */
- IRDA_TASK_WAIT,
- IRDA_TASK_WAIT1,
- IRDA_TASK_WAIT2,
- IRDA_TASK_WAIT3,
- IRDA_TASK_CHILD_INIT, /* Initializing child task */
- IRDA_TASK_CHILD_WAIT, /* Waiting for child task to finish */
- IRDA_TASK_CHILD_DONE /* Child task is finished */
-} IRDA_TASK_STATE;
-
-struct irda_task;
-typedef int (*IRDA_TASK_CALLBACK) (struct irda_task *task);
-
-struct irda_task {
- irda_queue_t q;
- magic_t magic;
-
- IRDA_TASK_STATE state;
- IRDA_TASK_CALLBACK function;
- IRDA_TASK_CALLBACK finished;
-
- struct irda_task *parent;
- struct timer_list timer;
-
- void *instance; /* Instance being called */
- void *param; /* Parameter to be used by instance */
-};
-
-/* Dongle info */
-struct dongle_reg;
-typedef struct {
- struct dongle_reg *issue; /* Registration info */
- struct net_device *dev; /* Device we are attached to */
- struct irda_task *speed_task; /* Task handling speed change */
- struct irda_task *reset_task; /* Task handling reset */
- __u32 speed; /* Current speed */
-
- /* Callbacks to the IrDA device driver */
- int (*set_mode)(struct net_device *, int mode);
- int (*read)(struct net_device *dev, __u8 *buf, int len);
- int (*write)(struct net_device *dev, __u8 *buf, int len);
- int (*set_dtr_rts)(struct net_device *dev, int dtr, int rts);
-} dongle_t;
-
-/* Dongle registration info */
-struct dongle_reg {
- irda_queue_t q; /* Must be first */
- IRDA_DONGLE type;
-
- void (*open)(dongle_t *dongle, struct qos_info *qos);
- void (*close)(dongle_t *dongle);
- int (*reset)(struct irda_task *task);
- int (*change_speed)(struct irda_task *task);
- struct module *owner;
-};
-
-/*
- * Per-packet information we need to hide inside sk_buff
- * (must not exceed 48 bytes, check with struct sk_buff)
- * The default_qdisc_pad field is a temporary hack.
- */
-struct irda_skb_cb {
- unsigned int default_qdisc_pad;
- magic_t magic; /* Be sure that we can trust the information */
- __u32 next_speed; /* The Speed to be set *after* this frame */
- __u16 mtt; /* Minimum turn around time */
- __u16 xbofs; /* Number of xbofs required, used by SIR mode */
- __u16 next_xbofs; /* Number of xbofs required *after* this frame */
- void *context; /* May be used by drivers */
- void (*destructor)(struct sk_buff *skb); /* Used for flow control */
- __u16 xbofs_delay; /* Number of xbofs used for generating the mtt */
- __u8 line; /* Used by IrCOMM in IrLPT mode */
-};
-
-/* Chip specific info */
-typedef struct {
- int cfg_base; /* Config register IO base */
- int sir_base; /* SIR IO base */
- int fir_base; /* FIR IO base */
- int mem_base; /* Shared memory base */
- int sir_ext; /* Length of SIR iobase */
- int fir_ext; /* Length of FIR iobase */
- int irq, irq2; /* Interrupts used */
- int dma, dma2; /* DMA channel(s) used */
- int fifo_size; /* FIFO size */
- int irqflags; /* interrupt flags (ie, IRQF_SHARED) */
- int direction; /* Link direction, used by some FIR drivers */
- int enabled; /* Powered on? */
- int suspended; /* Suspended by APM */
- __u32 speed; /* Currently used speed */
- __u32 new_speed; /* Speed we must change to when Tx is finished */
- int dongle_id; /* Dongle or transceiver currently used */
-} chipio_t;
-
-/* IO buffer specific info (inspired by struct sk_buff) */
-typedef struct {
- int state; /* Receiving state (transmit state not used) */
- int in_frame; /* True if receiving frame */
-
- __u8 *head; /* start of buffer */
- __u8 *data; /* start of data in buffer */
-
- int len; /* current length of data */
- int truesize; /* total allocated size of buffer */
- __u16 fcs;
-
- struct sk_buff *skb; /* ZeroCopy Rx in async_unwrap_char() */
-} iobuff_t;
-
-/* Maximum SIR frame (skb) that we expect to receive *unwrapped*.
- * Max LAP MTU (I field) is 2048 bytes max (IrLAP 1.1, chapt 6.6.5, p40).
- * Max LAP header is 2 bytes (for now).
- * Max CRC is 2 bytes at SIR, 4 bytes at FIR.
- * Need 1 byte for skb_reserve() to align IP header for IrLAN.
- * Add a few extra bytes just to be safe (buffer is power of two anyway)
- * Jean II */
-#define IRDA_SKB_MAX_MTU 2064
-/* Maximum SIR frame that we expect to send, wrapped (i.e. with XBOFS
- * and escaped characters on top of above). */
-#define IRDA_SIR_MAX_FRAME 4269
-
-/* The SIR unwrapper async_unwrap_char() will use a Rx-copy-break mechanism
- * when using the optional ZeroCopy Rx, where only small frames are memcpy
- * to a smaller skb to save memory. This is the threshold under which copy
- * will happen (and over which it won't happen).
- * Some FIR drivers may use this #define as well...
- * This is the same value as various Ethernet drivers. - Jean II */
-#define IRDA_RX_COPY_THRESHOLD 256
-
-/* Function prototypes */
-int irda_device_init(void);
-void irda_device_cleanup(void);
-
-/* IrLAP entry points used by the drivers.
- * We declare them here to avoid the driver pulling a whole bunch stack
- * headers they don't really need - Jean II */
-struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos,
- const char *hw_name);
-void irlap_close(struct irlap_cb *self);
-
-/* Interface to be uses by IrLAP */
-void irda_device_set_media_busy(struct net_device *dev, int status);
-int irda_device_is_media_busy(struct net_device *dev);
-int irda_device_is_receiving(struct net_device *dev);
-
-/* Interface for internal use */
-static inline int irda_device_txqueue_empty(const struct net_device *dev)
-{
- return qdisc_all_tx_empty(dev);
-}
-int irda_device_set_raw_mode(struct net_device* self, int status);
-struct net_device *alloc_irdadev(int sizeof_priv);
-
-void irda_setup_dma(int channel, dma_addr_t buffer, int count, int mode);
-
-/*
- * Function irda_get_mtt (skb)
- *
- * Utility function for getting the minimum turnaround time out of
- * the skb, where it has been hidden in the cb field.
- */
-static inline __u16 irda_get_mtt(const struct sk_buff *skb)
-{
- const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb;
- return (cb->magic == LAP_MAGIC) ? cb->mtt : 10000;
-}
-
-/*
- * Function irda_get_next_speed (skb)
- *
- * Extract the speed that should be set *after* this frame from the skb
- *
- * Note : return -1 for user space frames
- */
-static inline __u32 irda_get_next_speed(const struct sk_buff *skb)
-{
- const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb;
- return (cb->magic == LAP_MAGIC) ? cb->next_speed : -1;
-}
-
-/*
- * Function irda_get_next_xbofs (skb)
- *
- * Extract the xbofs that should be set for this frame from the skb
- *
- * Note : default to 10 for user space frames
- */
-static inline __u16 irda_get_xbofs(const struct sk_buff *skb)
-{
- const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb;
- return (cb->magic == LAP_MAGIC) ? cb->xbofs : 10;
-}
-
-/*
- * Function irda_get_next_xbofs (skb)
- *
- * Extract the xbofs that should be set *after* this frame from the skb
- *
- * Note : return -1 for user space frames
- */
-static inline __u16 irda_get_next_xbofs(const struct sk_buff *skb)
-{
- const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb;
- return (cb->magic == LAP_MAGIC) ? cb->next_xbofs : -1;
-}
-#endif /* IRDA_DEVICE_H */
-
-
diff --git a/drivers/staging/irda/include/net/irda/iriap.h b/drivers/staging/irda/include/net/irda/iriap.h
deleted file mode 100644
index fcc896491a95..000000000000
--- a/drivers/staging/irda/include/net/irda/iriap.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*********************************************************************
- *
- * Filename: iriap.h
- * Version: 0.5
- * Description: Information Access Protocol (IAP)
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Thu Aug 21 00:02:07 1997
- * Modified at: Sat Dec 25 16:42:09 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1997-1999 Dag Brattli <dagb@cs.uit.no>,
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRIAP_H
-#define IRIAP_H
-
-#include <linux/types.h>
-#include <linux/skbuff.h>
-
-#include <net/irda/iriap_event.h>
-#include <net/irda/irias_object.h>
-#include <net/irda/irqueue.h> /* irda_queue_t */
-#include <net/irda/timer.h> /* struct timer_list */
-
-#define IAP_LST 0x80
-#define IAP_ACK 0x40
-
-#define IAS_SERVER 0
-#define IAS_CLIENT 1
-
-/* IrIAP Op-codes */
-#define GET_INFO_BASE 0x01
-#define GET_OBJECTS 0x02
-#define GET_VALUE 0x03
-#define GET_VALUE_BY_CLASS 0x04
-#define GET_OBJECT_INFO 0x05
-#define GET_ATTRIB_NAMES 0x06
-
-#define IAS_SUCCESS 0
-#define IAS_CLASS_UNKNOWN 1
-#define IAS_ATTRIB_UNKNOWN 2
-#define IAS_DISCONNECT 10
-
-typedef void (*CONFIRM_CALLBACK)(int result, __u16 obj_id,
- struct ias_value *value, void *priv);
-
-struct iriap_cb {
- irda_queue_t q; /* Must be first */
- magic_t magic; /* Magic cookie */
-
- int mode; /* Client or server */
-
- __u32 saddr;
- __u32 daddr;
- __u8 operation;
-
- struct sk_buff *request_skb;
- struct lsap_cb *lsap;
- __u8 slsap_sel;
-
- /* Client states */
- IRIAP_STATE client_state;
- IRIAP_STATE call_state;
-
- /* Server states */
- IRIAP_STATE server_state;
- IRIAP_STATE r_connect_state;
-
- CONFIRM_CALLBACK confirm;
- void *priv; /* Used to identify client */
-
- __u8 max_header_size;
- __u32 max_data_size;
-
- struct timer_list watchdog_timer;
-};
-
-int iriap_init(void);
-void iriap_cleanup(void);
-
-struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv,
- CONFIRM_CALLBACK callback);
-void iriap_close(struct iriap_cb *self);
-
-int iriap_getvaluebyclass_request(struct iriap_cb *self,
- __u32 saddr, __u32 daddr,
- char *name, char *attr);
-void iriap_connect_request(struct iriap_cb *self);
-void iriap_send_ack( struct iriap_cb *self);
-void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb);
-
-void iriap_register_server(void);
-
-#endif
-
-
diff --git a/drivers/staging/irda/include/net/irda/iriap_event.h b/drivers/staging/irda/include/net/irda/iriap_event.h
deleted file mode 100644
index 89747f06d9eb..000000000000
--- a/drivers/staging/irda/include/net/irda/iriap_event.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*********************************************************************
- *
- * Filename: iriap_event.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Aug 4 20:40:53 1997
- * Modified at: Sun Oct 31 22:02:54 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRIAP_FSM_H
-#define IRIAP_FSM_H
-
-/* Forward because of circular include dependecies */
-struct iriap_cb;
-
-/* IrIAP states */
-typedef enum {
- /* Client */
- S_DISCONNECT,
- S_CONNECTING,
- S_CALL,
-
- /* S-Call */
- S_MAKE_CALL,
- S_CALLING,
- S_OUTSTANDING,
- S_REPLYING,
- S_WAIT_FOR_CALL,
- S_WAIT_ACTIVE,
-
- /* Server */
- R_DISCONNECT,
- R_CALL,
-
- /* R-Connect */
- R_WAITING,
- R_WAIT_ACTIVE,
- R_RECEIVING,
- R_EXECUTE,
- R_RETURNING,
-} IRIAP_STATE;
-
-typedef enum {
- IAP_CALL_REQUEST,
- IAP_CALL_REQUEST_GVBC,
- IAP_CALL_RESPONSE,
- IAP_RECV_F_LST,
- IAP_LM_DISCONNECT_INDICATION,
- IAP_LM_CONNECT_INDICATION,
- IAP_LM_CONNECT_CONFIRM,
-} IRIAP_EVENT;
-
-void iriap_next_client_state (struct iriap_cb *self, IRIAP_STATE state);
-void iriap_next_call_state (struct iriap_cb *self, IRIAP_STATE state);
-void iriap_next_server_state (struct iriap_cb *self, IRIAP_STATE state);
-void iriap_next_r_connect_state(struct iriap_cb *self, IRIAP_STATE state);
-
-
-void iriap_do_client_event(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-void iriap_do_call_event (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-
-void iriap_do_server_event (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-void iriap_do_r_connect_event(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-
-#endif /* IRIAP_FSM_H */
-
diff --git a/drivers/staging/irda/include/net/irda/irias_object.h b/drivers/staging/irda/include/net/irda/irias_object.h
deleted file mode 100644
index 83f78081799c..000000000000
--- a/drivers/staging/irda/include/net/irda/irias_object.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*********************************************************************
- *
- * Filename: irias_object.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Thu Oct 1 22:49:50 1998
- * Modified at: Wed Dec 15 11:20:57 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef LM_IAS_OBJECT_H
-#define LM_IAS_OBJECT_H
-
-#include <net/irda/irda.h>
-#include <net/irda/irqueue.h>
-
-/* LM-IAS Attribute types */
-#define IAS_MISSING 0
-#define IAS_INTEGER 1
-#define IAS_OCT_SEQ 2
-#define IAS_STRING 3
-
-/* Object ownership of attributes (user or kernel) */
-#define IAS_KERNEL_ATTR 0
-#define IAS_USER_ATTR 1
-
-/*
- * LM-IAS Object
- */
-struct ias_object {
- irda_queue_t q; /* Must be first! */
- magic_t magic;
-
- char *name;
- int id;
- hashbin_t *attribs;
-};
-
-/*
- * Values used by LM-IAS attributes
- */
-struct ias_value {
- __u8 type; /* Value description */
- __u8 owner; /* Managed from user/kernel space */
- int charset; /* Only used by string type */
- int len;
-
- /* Value */
- union {
- int integer;
- char *string;
- __u8 *oct_seq;
- } t;
-};
-
-/*
- * Attributes used by LM-IAS objects
- */
-struct ias_attrib {
- irda_queue_t q; /* Must be first! */
- int magic;
-
- char *name; /* Attribute name */
- struct ias_value *value; /* Attribute value */
-};
-
-struct ias_object *irias_new_object(char *name, int id);
-void irias_insert_object(struct ias_object *obj);
-int irias_delete_object(struct ias_object *obj);
-int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib,
- int cleanobject);
-void __irias_delete_object(struct ias_object *obj);
-
-void irias_add_integer_attrib(struct ias_object *obj, char *name, int value,
- int user);
-void irias_add_string_attrib(struct ias_object *obj, char *name, char *value,
- int user);
-void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets,
- int len, int user);
-int irias_object_change_attribute(char *obj_name, char *attrib_name,
- struct ias_value *new_value);
-struct ias_object *irias_find_object(char *name);
-struct ias_attrib *irias_find_attrib(struct ias_object *obj, char *name);
-
-struct ias_value *irias_new_string_value(char *string);
-struct ias_value *irias_new_integer_value(int integer);
-struct ias_value *irias_new_octseq_value(__u8 *octseq , int len);
-struct ias_value *irias_new_missing_value(void);
-void irias_delete_value(struct ias_value *value);
-
-extern struct ias_value irias_missing;
-extern hashbin_t *irias_objects;
-
-#endif
diff --git a/drivers/staging/irda/include/net/irda/irlan_client.h b/drivers/staging/irda/include/net/irda/irlan_client.h
deleted file mode 100644
index fa8455eda280..000000000000
--- a/drivers/staging/irda/include/net/irda/irlan_client.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlan_client.h
- * Version: 0.3
- * Description: IrDA LAN access layer
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Thu Apr 22 14:13:34 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRLAN_CLIENT_H
-#define IRLAN_CLIENT_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-
-#include <net/irda/irias_object.h>
-#include <net/irda/irlan_event.h>
-
-void irlan_client_discovery_indication(discinfo_t *, DISCOVERY_MODE, void *);
-void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr);
-
-void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb);
-void irlan_client_get_value_confirm(int result, __u16 obj_id,
- struct ias_value *value, void *priv);
-#endif
diff --git a/drivers/staging/irda/include/net/irda/irlan_common.h b/drivers/staging/irda/include/net/irda/irlan_common.h
deleted file mode 100644
index 550c2d6ec7ff..000000000000
--- a/drivers/staging/irda/include/net/irda/irlan_common.h
+++ /dev/null
@@ -1,230 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlan_common.h
- * Version: 0.8
- * Description: IrDA LAN access layer
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Sun Oct 31 19:41:24 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRLAN_H
-#define IRLAN_H
-
-#include <asm/param.h> /* for HZ */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/if_ether.h>
-
-#include <net/irda/irttp.h>
-
-#define IRLAN_MTU 1518
-#define IRLAN_TIMEOUT 10*HZ /* 10 seconds */
-
-/* Command packet types */
-#define CMD_GET_PROVIDER_INFO 0
-#define CMD_GET_MEDIA_CHAR 1
-#define CMD_OPEN_DATA_CHANNEL 2
-#define CMD_CLOSE_DATA_CHAN 3
-#define CMD_RECONNECT_DATA_CHAN 4
-#define CMD_FILTER_OPERATION 5
-
-/* Some responses */
-#define RSP_SUCCESS 0
-#define RSP_INSUFFICIENT_RESOURCES 1
-#define RSP_INVALID_COMMAND_FORMAT 2
-#define RSP_COMMAND_NOT_SUPPORTED 3
-#define RSP_PARAM_NOT_SUPPORTED 4
-#define RSP_VALUE_NOT_SUPPORTED 5
-#define RSP_NOT_OPEN 6
-#define RSP_AUTHENTICATION_REQUIRED 7
-#define RSP_INVALID_PASSWORD 8
-#define RSP_PROTOCOL_ERROR 9
-#define RSP_ASYNCHRONOUS_ERROR 255
-
-/* Media types */
-#define MEDIA_802_3 1
-#define MEDIA_802_5 2
-
-/* Filter parameters */
-#define DATA_CHAN 1
-#define FILTER_TYPE 2
-#define FILTER_MODE 3
-
-/* Filter types */
-#define IRLAN_DIRECTED 0x01
-#define IRLAN_FUNCTIONAL 0x02
-#define IRLAN_GROUP 0x04
-#define IRLAN_MAC_FRAME 0x08
-#define IRLAN_MULTICAST 0x10
-#define IRLAN_BROADCAST 0x20
-#define IRLAN_IPX_SOCKET 0x40
-
-/* Filter modes */
-#define ALL 1
-#define FILTER 2
-#define NONE 3
-
-/* Filter operations */
-#define GET 1
-#define CLEAR 2
-#define ADD 3
-#define REMOVE 4
-#define DYNAMIC 5
-
-/* Access types */
-#define ACCESS_DIRECT 1
-#define ACCESS_PEER 2
-#define ACCESS_HOSTED 3
-
-#define IRLAN_BYTE 0
-#define IRLAN_SHORT 1
-#define IRLAN_ARRAY 2
-
-/* IrLAN sits on top if IrTTP */
-#define IRLAN_MAX_HEADER (TTP_HEADER+LMP_HEADER)
-/* 1 byte for the command code and 1 byte for the parameter count */
-#define IRLAN_CMD_HEADER 2
-
-#define IRLAN_STRING_PARAMETER_LEN(name, value) (1 + strlen((name)) + 2 \
- + strlen ((value)))
-#define IRLAN_BYTE_PARAMETER_LEN(name) (1 + strlen((name)) + 2 + 1)
-#define IRLAN_SHORT_PARAMETER_LEN(name) (1 + strlen((name)) + 2 + 2)
-
-/*
- * IrLAN client
- */
-struct irlan_client_cb {
- int state;
-
- int open_retries;
-
- struct tsap_cb *tsap_ctrl;
- __u32 max_sdu_size;
- __u8 max_header_size;
-
- int access_type; /* Access type of provider */
- __u8 reconnect_key[255];
- __u8 key_len;
-
- __u16 recv_arb_val;
- __u16 max_frame;
- int filter_type;
-
- int unicast_open;
- int broadcast_open;
-
- int tx_busy;
- struct sk_buff_head txq; /* Transmit control queue */
-
- struct iriap_cb *iriap;
-
- struct timer_list kick_timer;
-};
-
-/*
- * IrLAN provider
- */
-struct irlan_provider_cb {
- int state;
-
- struct tsap_cb *tsap_ctrl;
- __u32 max_sdu_size;
- __u8 max_header_size;
-
- /*
- * Store some values here which are used by the provider to parse
- * the filter operations
- */
- int data_chan;
- int filter_type;
- int filter_mode;
- int filter_operation;
- int filter_entry;
- int access_type; /* Access type */
- __u16 send_arb_val;
-
- __u8 mac_address[ETH_ALEN]; /* Generated MAC address for peer device */
-};
-
-/*
- * IrLAN control block
- */
-struct irlan_cb {
- int magic;
- struct list_head dev_list;
- struct net_device *dev; /* Ethernet device structure*/
-
- __u32 saddr; /* Source device address */
- __u32 daddr; /* Destination device address */
- int disconnect_reason; /* Why we got disconnected */
-
- int media; /* Media type */
- __u8 version[2]; /* IrLAN version */
-
- struct tsap_cb *tsap_data; /* Data TSAP */
-
- int use_udata; /* Use Unit Data transfers */
-
- __u8 stsap_sel_data; /* Source data TSAP selector */
- __u8 dtsap_sel_data; /* Destination data TSAP selector */
- __u8 dtsap_sel_ctrl; /* Destination ctrl TSAP selector */
-
- struct irlan_client_cb client; /* Client specific fields */
- struct irlan_provider_cb provider; /* Provider specific fields */
-
- __u32 max_sdu_size;
- __u8 max_header_size;
-
- wait_queue_head_t open_wait;
- struct timer_list watchdog_timer;
-};
-
-void irlan_close(struct irlan_cb *self);
-void irlan_close_tsaps(struct irlan_cb *self);
-
-int irlan_register_netdev(struct irlan_cb *self);
-void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel);
-void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout);
-
-void irlan_open_data_tsap(struct irlan_cb *self);
-
-int irlan_run_ctrl_tx_queue(struct irlan_cb *self);
-
-struct irlan_cb *irlan_get_any(void);
-void irlan_get_provider_info(struct irlan_cb *self);
-void irlan_get_media_char(struct irlan_cb *self);
-void irlan_open_data_channel(struct irlan_cb *self);
-void irlan_close_data_channel(struct irlan_cb *self);
-void irlan_set_multicast_filter(struct irlan_cb *self, int status);
-void irlan_set_broadcast_filter(struct irlan_cb *self, int status);
-
-int irlan_insert_byte_param(struct sk_buff *skb, char *param, __u8 value);
-int irlan_insert_short_param(struct sk_buff *skb, char *param, __u16 value);
-int irlan_insert_string_param(struct sk_buff *skb, char *param, char *value);
-int irlan_insert_array_param(struct sk_buff *skb, char *name, __u8 *value,
- __u16 value_len);
-
-int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len);
-
-#endif
-
-
diff --git a/drivers/staging/irda/include/net/irda/irlan_eth.h b/drivers/staging/irda/include/net/irda/irlan_eth.h
deleted file mode 100644
index de5c81691f33..000000000000
--- a/drivers/staging/irda/include/net/irda/irlan_eth.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlan_eth.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Thu Oct 15 08:36:58 1998
- * Modified at: Fri May 14 23:29:00 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRLAN_ETH_H
-#define IRLAN_ETH_H
-
-struct net_device *alloc_irlandev(const char *name);
-int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb);
-
-void irlan_eth_flow_indication( void *instance, void *sap, LOCAL_FLOW flow);
-#endif
diff --git a/drivers/staging/irda/include/net/irda/irlan_event.h b/drivers/staging/irda/include/net/irda/irlan_event.h
deleted file mode 100644
index 018b5a77e610..000000000000
--- a/drivers/staging/irda/include/net/irda/irlan_event.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlan_event.h
- * Version:
- * Description: LAN access
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Tue Feb 2 09:45:17 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRLAN_EVENT_H
-#define IRLAN_EVENT_H
-
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-
-#include <net/irda/irlan_common.h>
-
-typedef enum {
- IRLAN_IDLE,
- IRLAN_QUERY,
- IRLAN_CONN,
- IRLAN_INFO,
- IRLAN_MEDIA,
- IRLAN_OPEN,
- IRLAN_WAIT,
- IRLAN_ARB,
- IRLAN_DATA,
- IRLAN_CLOSE,
- IRLAN_SYNC
-} IRLAN_STATE;
-
-typedef enum {
- IRLAN_DISCOVERY_INDICATION,
- IRLAN_IAS_PROVIDER_AVAIL,
- IRLAN_IAS_PROVIDER_NOT_AVAIL,
- IRLAN_LAP_DISCONNECT,
- IRLAN_LMP_DISCONNECT,
- IRLAN_CONNECT_COMPLETE,
- IRLAN_DATA_INDICATION,
- IRLAN_DATA_CONNECT_INDICATION,
- IRLAN_RETRY_CONNECT,
-
- IRLAN_CONNECT_INDICATION,
- IRLAN_GET_INFO_CMD,
- IRLAN_GET_MEDIA_CMD,
- IRLAN_OPEN_DATA_CMD,
- IRLAN_FILTER_CONFIG_CMD,
-
- IRLAN_CHECK_CON_ARB,
- IRLAN_PROVIDER_SIGNAL,
-
- IRLAN_WATCHDOG_TIMEOUT,
-} IRLAN_EVENT;
-
-extern const char * const irlan_state[];
-
-void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-
-void irlan_do_provider_event(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-
-void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state);
-void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state);
-
-#endif
diff --git a/drivers/staging/irda/include/net/irda/irlan_filter.h b/drivers/staging/irda/include/net/irda/irlan_filter.h
deleted file mode 100644
index a5a2539485bd..000000000000
--- a/drivers/staging/irda/include/net/irda/irlan_filter.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlan_filter.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Fri Jan 29 15:24:08 1999
- * Modified at: Sun Feb 7 23:35:31 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998 Dag Brattli, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRLAN_FILTER_H
-#define IRLAN_FILTER_H
-
-void irlan_check_command_param(struct irlan_cb *self, char *param,
- char *value);
-void irlan_filter_request(struct irlan_cb *self, struct sk_buff *skb);
-#ifdef CONFIG_PROC_FS
-void irlan_print_filter(struct seq_file *seq, int filter_type);
-#endif
-
-#endif /* IRLAN_FILTER_H */
diff --git a/drivers/staging/irda/include/net/irda/irlan_provider.h b/drivers/staging/irda/include/net/irda/irlan_provider.h
deleted file mode 100644
index 92f3b0e1029b..000000000000
--- a/drivers/staging/irda/include/net/irda/irlan_provider.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlan_provider.h
- * Version: 0.1
- * Description: IrDA LAN access layer
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Sun May 9 12:26:11 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRLAN_SERVER_H
-#define IRLAN_SERVER_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-
-#include <net/irda/irlan_common.h>
-
-void irlan_provider_ctrl_disconnect_indication(void *instance, void *sap,
- LM_REASON reason,
- struct sk_buff *skb);
-
-
-void irlan_provider_connect_response(struct irlan_cb *, struct tsap_cb *);
-
-int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb);
-int irlan_provider_parse_command(struct irlan_cb *self, int cmd,
- struct sk_buff *skb);
-
-void irlan_provider_send_reply(struct irlan_cb *self, int command,
- int ret_code);
-int irlan_provider_open_ctrl_tsap(struct irlan_cb *self);
-
-#endif
-
-
diff --git a/drivers/staging/irda/include/net/irda/irlap.h b/drivers/staging/irda/include/net/irda/irlap.h
deleted file mode 100644
index 6f23e820618c..000000000000
--- a/drivers/staging/irda/include/net/irda/irlap.h
+++ /dev/null
@@ -1,311 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlap.h
- * Version: 0.8
- * Description: An IrDA LAP driver for Linux
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Aug 4 20:40:53 1997
- * Modified at: Fri Dec 10 13:21:17 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRLAP_H
-#define IRLAP_H
-
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/timer.h>
-
-#include <net/irda/irqueue.h> /* irda_queue_t */
-#include <net/irda/qos.h> /* struct qos_info */
-#include <net/irda/discovery.h> /* discovery_t */
-#include <net/irda/irlap_event.h> /* IRLAP_STATE, ... */
-#include <net/irda/irmod.h> /* struct notify_t */
-
-#define CONFIG_IRDA_DYNAMIC_WINDOW 1
-
-#define LAP_RELIABLE 1
-#define LAP_UNRELIABLE 0
-
-#define LAP_ADDR_HEADER 1 /* IrLAP Address Header */
-#define LAP_CTRL_HEADER 1 /* IrLAP Control Header */
-
-/* May be different when we get VFIR */
-#define LAP_MAX_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER)
-
-/* Each IrDA device gets a random 32 bits IRLAP device address */
-#define LAP_ALEN 4
-
-#define BROADCAST 0xffffffff /* Broadcast device address */
-#define CBROADCAST 0xfe /* Connection broadcast address */
-#define XID_FORMAT 0x01 /* Discovery XID format */
-
-/* Nobody seems to use this constant. */
-#define LAP_WINDOW_SIZE 8
-/* We keep the LAP queue very small to minimise the amount of buffering.
- * this improve latency and reduce resource consumption.
- * This work only because we have synchronous refilling of IrLAP through
- * the flow control mechanism (via scheduler and IrTTP).
- * 2 buffers is the minimum we can work with, one that we send while polling
- * IrTTP, and another to know that we should not send the pf bit.
- * Jean II */
-#define LAP_HIGH_THRESHOLD 2
-/* Some rare non TTP clients don't implement flow control, and
- * so don't comply with the above limit (and neither with this one).
- * For IAP and management, it doesn't matter, because they never transmit much.
- *.For IrLPT, this should be fixed.
- * - Jean II */
-#define LAP_MAX_QUEUE 10
-/* Please note that all IrDA management frames (LMP/TTP conn req/disc and
- * IAS queries) fall in the second category and are sent to LAP even if TTP
- * is stopped. This means that those frames will wait only a maximum of
- * two (2) data frames before beeing sent on the "wire", which speed up
- * new socket setup when the link is saturated.
- * Same story for two sockets competing for the medium : if one saturates
- * the LAP, when the other want to transmit it only has to wait for
- * maximum three (3) packets (2 + one scheduling), which improve performance
- * of delay sensitive applications.
- * Jean II */
-
-#define NR_EXPECTED 1
-#define NR_UNEXPECTED 0
-#define NR_INVALID -1
-
-#define NS_EXPECTED 1
-#define NS_UNEXPECTED 0
-#define NS_INVALID -1
-
-/*
- * Meta information passed within the IrLAP state machine
- */
-struct irlap_info {
- __u8 caddr; /* Connection address */
- __u8 control; /* Frame type */
- __u8 cmd;
-
- __u32 saddr;
- __u32 daddr;
-
- int pf; /* Poll/final bit set */
-
- __u8 nr; /* Sequence number of next frame expected */
- __u8 ns; /* Sequence number of frame sent */
-
- int S; /* Number of slots */
- int slot; /* Random chosen slot */
- int s; /* Current slot */
-
- discovery_t *discovery; /* Discovery information */
-};
-
-/* Main structure of IrLAP */
-struct irlap_cb {
- irda_queue_t q; /* Must be first */
- magic_t magic;
-
- /* Device we are attached to */
- struct net_device *netdev;
- char hw_name[2*IFNAMSIZ + 1];
-
- /* Connection state */
- volatile IRLAP_STATE state; /* Current state */
-
- /* Timers used by IrLAP */
- struct timer_list query_timer;
- struct timer_list slot_timer;
- struct timer_list discovery_timer;
- struct timer_list final_timer;
- struct timer_list poll_timer;
- struct timer_list wd_timer;
- struct timer_list backoff_timer;
-
- /* Media busy stuff */
- struct timer_list media_busy_timer;
- int media_busy;
-
- /* Timeouts which will be different with different turn time */
- int slot_timeout;
- int poll_timeout;
- int final_timeout;
- int wd_timeout;
-
- struct sk_buff_head txq; /* Frames to be transmitted */
- struct sk_buff_head txq_ultra;
-
- __u8 caddr; /* Connection address */
- __u32 saddr; /* Source device address */
- __u32 daddr; /* Destination device address */
-
- int retry_count; /* Times tried to establish connection */
- int add_wait; /* True if we are waiting for frame */
-
- __u8 connect_pending;
- __u8 disconnect_pending;
-
- /* To send a faster RR if tx queue empty */
-#ifdef CONFIG_IRDA_FAST_RR
- int fast_RR_timeout;
- int fast_RR;
-#endif /* CONFIG_IRDA_FAST_RR */
-
- int N1; /* N1 * F-timer = Negitiated link disconnect warning threshold */
- int N2; /* N2 * F-timer = Negitiated link disconnect time */
- int N3; /* Connection retry count */
-
- int local_busy;
- int remote_busy;
- int xmitflag;
-
- __u8 vs; /* Next frame to be sent */
- __u8 vr; /* Next frame to be received */
- __u8 va; /* Last frame acked */
- int window; /* Nr of I-frames allowed to send */
- int window_size; /* Current negotiated window size */
-
-#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
- __u32 line_capacity; /* Number of bytes allowed to send */
- __u32 bytes_left; /* Number of bytes still allowed to transmit */
-#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
-
- struct sk_buff_head wx_list;
-
- __u8 ack_required;
-
- /* XID parameters */
- __u8 S; /* Number of slots */
- __u8 slot; /* Random chosen slot */
- __u8 s; /* Current slot */
- int frame_sent; /* Have we sent reply? */
-
- hashbin_t *discovery_log;
- discovery_t *discovery_cmd;
-
- __u32 speed; /* Link speed */
-
- struct qos_info qos_tx; /* QoS requested by peer */
- struct qos_info qos_rx; /* QoS requested by self */
- struct qos_info *qos_dev; /* QoS supported by device */
-
- notify_t notify; /* Callbacks to IrLMP */
-
- int mtt_required; /* Minimum turnaround time required */
- int xbofs_delay; /* Nr of XBOF's used to MTT */
- int bofs_count; /* Negotiated extra BOFs */
- int next_bofs; /* Negotiated extra BOFs after next frame */
-
- int mode; /* IrLAP mode (primary, secondary or monitor) */
-};
-
-/*
- * Function prototypes
- */
-int irlap_init(void);
-void irlap_cleanup(void);
-
-struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos,
- const char *hw_name);
-void irlap_close(struct irlap_cb *self);
-
-void irlap_connect_request(struct irlap_cb *self, __u32 daddr,
- struct qos_info *qos, int sniff);
-void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb);
-void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb);
-void irlap_connect_confirm(struct irlap_cb *, struct sk_buff *skb);
-
-void irlap_data_indication(struct irlap_cb *, struct sk_buff *, int unreliable);
-void irlap_data_request(struct irlap_cb *, struct sk_buff *, int unreliable);
-
-#ifdef CONFIG_IRDA_ULTRA
-void irlap_unitdata_request(struct irlap_cb *, struct sk_buff *);
-void irlap_unitdata_indication(struct irlap_cb *, struct sk_buff *);
-#endif /* CONFIG_IRDA_ULTRA */
-
-void irlap_disconnect_request(struct irlap_cb *);
-void irlap_disconnect_indication(struct irlap_cb *, LAP_REASON reason);
-
-void irlap_status_indication(struct irlap_cb *, int quality_of_link);
-
-void irlap_test_request(__u8 *info, int len);
-
-void irlap_discovery_request(struct irlap_cb *, discovery_t *discovery);
-void irlap_discovery_confirm(struct irlap_cb *, hashbin_t *discovery_log);
-void irlap_discovery_indication(struct irlap_cb *, discovery_t *discovery);
-
-void irlap_reset_indication(struct irlap_cb *self);
-void irlap_reset_confirm(void);
-
-void irlap_update_nr_received(struct irlap_cb *, int nr);
-int irlap_validate_nr_received(struct irlap_cb *, int nr);
-int irlap_validate_ns_received(struct irlap_cb *, int ns);
-
-int irlap_generate_rand_time_slot(int S, int s);
-void irlap_initiate_connection_state(struct irlap_cb *);
-void irlap_flush_all_queues(struct irlap_cb *);
-void irlap_wait_min_turn_around(struct irlap_cb *, struct qos_info *);
-
-void irlap_apply_default_connection_parameters(struct irlap_cb *self);
-void irlap_apply_connection_parameters(struct irlap_cb *self, int now);
-
-#define IRLAP_GET_HEADER_SIZE(self) (LAP_MAX_HEADER)
-#define IRLAP_GET_TX_QUEUE_LEN(self) skb_queue_len(&self->txq)
-
-/* Return TRUE if the node is in primary mode (i.e. master)
- * - Jean II */
-static inline int irlap_is_primary(struct irlap_cb *self)
-{
- int ret;
- switch(self->state) {
- case LAP_XMIT_P:
- case LAP_NRM_P:
- ret = 1;
- break;
- case LAP_XMIT_S:
- case LAP_NRM_S:
- ret = 0;
- break;
- default:
- ret = -1;
- }
- return ret;
-}
-
-/* Clear a pending IrLAP disconnect. - Jean II */
-static inline void irlap_clear_disconnect(struct irlap_cb *self)
-{
- self->disconnect_pending = FALSE;
-}
-
-/*
- * Function irlap_next_state (self, state)
- *
- * Switches state and provides debug information
- *
- */
-static inline void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state)
-{
- /*
- if (!self || self->magic != LAP_MAGIC)
- return;
-
- pr_debug("next LAP state = %s\n", irlap_state[state]);
- */
- self->state = state;
-}
-
-#endif
diff --git a/drivers/staging/irda/include/net/irda/irlap_event.h b/drivers/staging/irda/include/net/irda/irlap_event.h
deleted file mode 100644
index e4325fee1267..000000000000
--- a/drivers/staging/irda/include/net/irda/irlap_event.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*********************************************************************
- *
- *
- * Filename: irlap_event.h
- * Version: 0.1
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sat Aug 16 00:59:29 1997
- * Modified at: Tue Dec 21 11:20:30 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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 IRLAP_EVENT_H
-#define IRLAP_EVENT_H
-
-#include <net/irda/irda.h>
-
-/* A few forward declarations (to make compiler happy) */
-struct irlap_cb;
-struct irlap_info;
-
-/* IrLAP States */
-typedef enum {
- LAP_NDM, /* Normal disconnected mode */
- LAP_QUERY,
- LAP_REPLY,
- LAP_CONN, /* Connect indication */
- LAP_SETUP, /* Setting up connection */
- LAP_OFFLINE, /* A really boring state */
- LAP_XMIT_P,
- LAP_PCLOSE,
- LAP_NRM_P, /* Normal response mode as primary */
- LAP_RESET_WAIT,
- LAP_RESET,
- LAP_NRM_S, /* Normal response mode as secondary */
- LAP_XMIT_S,
- LAP_SCLOSE,
- LAP_RESET_CHECK,
-} IRLAP_STATE;
-
-/* IrLAP Events */
-typedef enum {
- /* Services events */
- DISCOVERY_REQUEST,
- CONNECT_REQUEST,
- CONNECT_RESPONSE,
- DISCONNECT_REQUEST,
- DATA_REQUEST,
- RESET_REQUEST,
- RESET_RESPONSE,
-
- /* Send events */
- SEND_I_CMD,
- SEND_UI_FRAME,
-
- /* Receive events */
- RECV_DISCOVERY_XID_CMD,
- RECV_DISCOVERY_XID_RSP,
- RECV_SNRM_CMD,
- RECV_TEST_CMD,
- RECV_TEST_RSP,
- RECV_UA_RSP,
- RECV_DM_RSP,
- RECV_RD_RSP,
- RECV_I_CMD,
- RECV_I_RSP,
- RECV_UI_FRAME,
- RECV_FRMR_RSP,
- RECV_RR_CMD,
- RECV_RR_RSP,
- RECV_RNR_CMD,
- RECV_RNR_RSP,
- RECV_REJ_CMD,
- RECV_REJ_RSP,
- RECV_SREJ_CMD,
- RECV_SREJ_RSP,
- RECV_DISC_CMD,
-
- /* Timer events */
- SLOT_TIMER_EXPIRED,
- QUERY_TIMER_EXPIRED,
- FINAL_TIMER_EXPIRED,
- POLL_TIMER_EXPIRED,
- DISCOVERY_TIMER_EXPIRED,
- WD_TIMER_EXPIRED,
- BACKOFF_TIMER_EXPIRED,
- MEDIA_BUSY_TIMER_EXPIRED,
-} IRLAP_EVENT;
-
-/*
- * Disconnect reason code
- */
-typedef enum { /* FIXME check the two first reason codes */
- LAP_DISC_INDICATION=1, /* Received a disconnect request from peer */
- LAP_NO_RESPONSE, /* To many retransmits without response */
- LAP_RESET_INDICATION, /* To many retransmits, or invalid nr/ns */
- LAP_FOUND_NONE, /* No devices were discovered */
- LAP_MEDIA_BUSY,
- LAP_PRIMARY_CONFLICT,
-} LAP_REASON;
-
-extern const char *const irlap_state[];
-
-void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-void irlap_print_event(IRLAP_EVENT event);
-
-int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb);
-
-#endif
diff --git a/drivers/staging/irda/include/net/irda/irlap_frame.h b/drivers/staging/irda/include/net/irda/irlap_frame.h
deleted file mode 100644
index cbc12a926e5f..000000000000
--- a/drivers/staging/irda/include/net/irda/irlap_frame.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlap_frame.h
- * Version: 0.9
- * Description: IrLAP frame declarations
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Tue Aug 19 10:27:26 1997
- * Modified at: Sat Dec 25 21:07:26 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1997-1999 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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 IRLAP_FRAME_H
-#define IRLAP_FRAME_H
-
-#include <linux/skbuff.h>
-
-#include <net/irda/irda.h>
-
-/* A few forward declarations (to make compiler happy) */
-struct irlap_cb;
-struct discovery_t;
-
-/* Frame types and templates */
-#define INVALID 0xff
-
-/* Unnumbered (U) commands */
-#define SNRM_CMD 0x83 /* Set Normal Response Mode */
-#define DISC_CMD 0x43 /* Disconnect */
-#define XID_CMD 0x2f /* Exchange Station Identification */
-#define TEST_CMD 0xe3 /* Test */
-
-/* Unnumbered responses */
-#define RNRM_RSP 0x83 /* Request Normal Response Mode */
-#define UA_RSP 0x63 /* Unnumbered Acknowledgement */
-#define FRMR_RSP 0x87 /* Frame Reject */
-#define DM_RSP 0x0f /* Disconnect Mode */
-#define RD_RSP 0x43 /* Request Disconnection */
-#define XID_RSP 0xaf /* Exchange Station Identification */
-#define TEST_RSP 0xe3 /* Test frame */
-
-/* Supervisory (S) */
-#define RR 0x01 /* Receive Ready */
-#define REJ 0x09 /* Reject */
-#define RNR 0x05 /* Receive Not Ready */
-#define SREJ 0x0d /* Selective Reject */
-
-/* Information (I) */
-#define I_FRAME 0x00 /* Information Format */
-#define UI_FRAME 0x03 /* Unnumbered Information */
-
-#define CMD_FRAME 0x01
-#define RSP_FRAME 0x00
-
-#define PF_BIT 0x10 /* Poll/final bit */
-
-/* Some IrLAP field lengths */
-/*
- * Only baud rate triplet is 4 bytes (PV can be 2 bytes).
- * All others params (7) are 3 bytes, so that's 7*3 + 1*4 bytes.
- */
-#define IRLAP_NEGOCIATION_PARAMS_LEN 25
-#define IRLAP_DISCOVERY_INFO_LEN 32
-
-struct disc_frame {
- __u8 caddr; /* Connection address */
- __u8 control;
-} __packed;
-
-struct xid_frame {
- __u8 caddr; /* Connection address */
- __u8 control;
- __u8 ident; /* Should always be XID_FORMAT */
- __le32 saddr; /* Source device address */
- __le32 daddr; /* Destination device address */
- __u8 flags; /* Discovery flags */
- __u8 slotnr;
- __u8 version;
-} __packed;
-
-struct test_frame {
- __u8 caddr; /* Connection address */
- __u8 control;
- __le32 saddr; /* Source device address */
- __le32 daddr; /* Destination device address */
-} __packed;
-
-struct ua_frame {
- __u8 caddr;
- __u8 control;
- __le32 saddr; /* Source device address */
- __le32 daddr; /* Dest device address */
-} __packed;
-
-struct dm_frame {
- __u8 caddr; /* Connection address */
- __u8 control;
-} __packed;
-
-struct rd_frame {
- __u8 caddr; /* Connection address */
- __u8 control;
-} __packed;
-
-struct rr_frame {
- __u8 caddr; /* Connection address */
- __u8 control;
-} __packed;
-
-struct i_frame {
- __u8 caddr;
- __u8 control;
-} __packed;
-
-struct snrm_frame {
- __u8 caddr;
- __u8 control;
- __le32 saddr;
- __le32 daddr;
- __u8 ncaddr;
-} __packed;
-
-void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb);
-void irlap_send_discovery_xid_frame(struct irlap_cb *, int S, __u8 s,
- __u8 command,
- struct discovery_t *discovery);
-void irlap_send_snrm_frame(struct irlap_cb *, struct qos_info *);
-void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr,
- struct sk_buff *cmd);
-void irlap_send_ua_response_frame(struct irlap_cb *, struct qos_info *);
-void irlap_send_dm_frame(struct irlap_cb *self);
-void irlap_send_rd_frame(struct irlap_cb *self);
-void irlap_send_disc_frame(struct irlap_cb *self);
-void irlap_send_rr_frame(struct irlap_cb *self, int command);
-
-void irlap_send_data_primary(struct irlap_cb *, struct sk_buff *);
-void irlap_send_data_primary_poll(struct irlap_cb *, struct sk_buff *);
-void irlap_send_data_secondary(struct irlap_cb *, struct sk_buff *);
-void irlap_send_data_secondary_final(struct irlap_cb *, struct sk_buff *);
-void irlap_resend_rejected_frames(struct irlap_cb *, int command);
-void irlap_resend_rejected_frame(struct irlap_cb *self, int command);
-
-void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
- __u8 caddr, int command);
-
-int irlap_insert_qos_negotiation_params(struct irlap_cb *self,
- struct sk_buff *skb);
-
-#endif
diff --git a/drivers/staging/irda/include/net/irda/irlmp.h b/drivers/staging/irda/include/net/irda/irlmp.h
deleted file mode 100644
index f132924cc9da..000000000000
--- a/drivers/staging/irda/include/net/irda/irlmp.h
+++ /dev/null
@@ -1,295 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlmp.h
- * Version: 0.9
- * Description: IrDA Link Management Protocol (LMP) layer
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Aug 17 20:54:32 1997
- * Modified at: Fri Dec 10 13:23:01 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRLMP_H
-#define IRLMP_H
-
-#include <asm/param.h> /* for HZ */
-
-#include <linux/types.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/qos.h>
-#include <net/irda/irlap.h> /* LAP_MAX_HEADER, ... */
-#include <net/irda/irlmp_event.h>
-#include <net/irda/irqueue.h>
-#include <net/irda/discovery.h>
-
-/* LSAP-SEL's */
-#define LSAP_MASK 0x7f
-#define LSAP_IAS 0x00
-#define LSAP_ANY 0xff
-#define LSAP_MAX 0x6f /* 0x70-0x7f are reserved */
-#define LSAP_CONNLESS 0x70 /* Connectionless LSAP, mostly used for Ultra */
-
-#define DEV_ADDR_ANY 0xffffffff
-
-#define LMP_HEADER 2 /* Dest LSAP + Source LSAP */
-#define LMP_CONTROL_HEADER 4 /* LMP_HEADER + opcode + parameter */
-#define LMP_PID_HEADER 1 /* Used by Ultra */
-#define LMP_MAX_HEADER (LMP_CONTROL_HEADER+LAP_MAX_HEADER)
-
-#define LM_MAX_CONNECTIONS 10
-
-#define LM_IDLE_TIMEOUT 2*HZ /* 2 seconds for now */
-
-typedef enum {
- S_PNP = 0,
- S_PDA,
- S_COMPUTER,
- S_PRINTER,
- S_MODEM,
- S_FAX,
- S_LAN,
- S_TELEPHONY,
- S_COMM,
- S_OBEX,
- S_ANY,
- S_END,
-} SERVICE;
-
-/* For selective discovery */
-typedef void (*DISCOVERY_CALLBACK1) (discinfo_t *, DISCOVERY_MODE, void *);
-/* For expiry (the same) */
-typedef void (*DISCOVERY_CALLBACK2) (discinfo_t *, DISCOVERY_MODE, void *);
-
-typedef struct {
- irda_queue_t queue; /* Must be first */
-
- __u16_host_order hints; /* Hint bits */
-} irlmp_service_t;
-
-typedef struct {
- irda_queue_t queue; /* Must be first */
-
- __u16_host_order hint_mask;
-
- DISCOVERY_CALLBACK1 disco_callback; /* Selective discovery */
- DISCOVERY_CALLBACK2 expir_callback; /* Selective expiration */
- void *priv; /* Used to identify client */
-} irlmp_client_t;
-
-/*
- * Information about each logical LSAP connection
- */
-struct lsap_cb {
- irda_queue_t queue; /* Must be first */
- magic_t magic;
-
- unsigned long connected; /* set_bit used on this */
- int persistent;
-
- __u8 slsap_sel; /* Source (this) LSAP address */
- __u8 dlsap_sel; /* Destination LSAP address (if connected) */
-#ifdef CONFIG_IRDA_ULTRA
- __u8 pid; /* Used by connectionless LSAP */
-#endif /* CONFIG_IRDA_ULTRA */
- struct sk_buff *conn_skb; /* Store skb here while connecting */
-
- struct timer_list watchdog_timer;
-
- LSAP_STATE lsap_state; /* Connection state */
- notify_t notify; /* Indication/Confirm entry points */
- struct qos_info qos; /* QoS for this connection */
-
- struct lap_cb *lap; /* Pointer to LAP connection structure */
-};
-
-/*
- * Used for caching the last slsap->dlsap->handle mapping
- *
- * We don't need to keep/match the remote address in the cache because
- * we are associated with a specific LAP (which implies it).
- * Jean II
- */
-typedef struct {
- int valid;
-
- __u8 slsap_sel;
- __u8 dlsap_sel;
- struct lsap_cb *lsap;
-} CACHE_ENTRY;
-
-/*
- * Information about each registered IrLAP layer
- */
-struct lap_cb {
- irda_queue_t queue; /* Must be first */
- magic_t magic;
-
- int reason; /* LAP disconnect reason */
-
- IRLMP_STATE lap_state;
-
- struct irlap_cb *irlap; /* Instance of IrLAP layer */
- hashbin_t *lsaps; /* LSAP associated with this link */
- struct lsap_cb *flow_next; /* Next lsap to be polled for Tx */
-
- __u8 caddr; /* Connection address */
- __u32 saddr; /* Source device address */
- __u32 daddr; /* Destination device address */
-
- struct qos_info *qos; /* LAP QoS for this session */
- struct timer_list idle_timer;
-
-#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
- /* The lsap cache was moved from struct irlmp_cb to here because
- * it must be associated with the specific LAP. Also, this
- * improves performance. - Jean II */
- CACHE_ENTRY cache; /* Caching last slsap->dlsap->handle mapping */
-#endif
-};
-
-/*
- * Main structure for IrLMP
- */
-struct irlmp_cb {
- magic_t magic;
-
- __u8 conflict_flag;
-
- discovery_t discovery_cmd; /* Discovery command to use by IrLAP */
- discovery_t discovery_rsp; /* Discovery response to use by IrLAP */
-
- /* Last lsap picked automatically by irlmp_find_free_slsap() */
- int last_lsap_sel;
-
- struct timer_list discovery_timer;
-
- hashbin_t *links; /* IrLAP connection table */
- hashbin_t *unconnected_lsaps;
- hashbin_t *clients;
- hashbin_t *services;
-
- hashbin_t *cachelog; /* Current discovery log */
-
- int running;
-
- __u16_host_order hints; /* Hint bits */
-};
-
-/* Prototype declarations */
-int irlmp_init(void);
-void irlmp_cleanup(void);
-struct lsap_cb *irlmp_open_lsap(__u8 slsap, notify_t *notify, __u8 pid);
-void irlmp_close_lsap( struct lsap_cb *self);
-
-__u16 irlmp_service_to_hint(int service);
-void *irlmp_register_service(__u16 hints);
-int irlmp_unregister_service(void *handle);
-void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
- DISCOVERY_CALLBACK2 expir_clb, void *priv);
-int irlmp_unregister_client(void *handle);
-int irlmp_update_client(void *handle, __u16 hint_mask,
- DISCOVERY_CALLBACK1 disco_clb,
- DISCOVERY_CALLBACK2 expir_clb, void *priv);
-
-void irlmp_register_link(struct irlap_cb *, __u32 saddr, notify_t *);
-void irlmp_unregister_link(__u32 saddr);
-
-int irlmp_connect_request(struct lsap_cb *, __u8 dlsap_sel,
- __u32 saddr, __u32 daddr,
- struct qos_info *, struct sk_buff *);
-void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb);
-int irlmp_connect_response(struct lsap_cb *, struct sk_buff *);
-void irlmp_connect_confirm(struct lsap_cb *, struct sk_buff *);
-struct lsap_cb *irlmp_dup(struct lsap_cb *self, void *instance);
-
-void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
- struct sk_buff *userdata);
-int irlmp_disconnect_request(struct lsap_cb *, struct sk_buff *userdata);
-
-void irlmp_discovery_confirm(hashbin_t *discovery_log, DISCOVERY_MODE mode);
-void irlmp_discovery_request(int nslots);
-discinfo_t *irlmp_get_discoveries(int *pn, __u16 mask, int nslots);
-void irlmp_do_expiry(void);
-void irlmp_do_discovery(int nslots);
-discovery_t *irlmp_get_discovery_response(void);
-void irlmp_discovery_expiry(discinfo_t *expiry, int number);
-
-int irlmp_data_request(struct lsap_cb *, struct sk_buff *);
-void irlmp_data_indication(struct lsap_cb *, struct sk_buff *);
-
-int irlmp_udata_request(struct lsap_cb *, struct sk_buff *);
-void irlmp_udata_indication(struct lsap_cb *, struct sk_buff *);
-
-#ifdef CONFIG_IRDA_ULTRA
-int irlmp_connless_data_request(struct lsap_cb *, struct sk_buff *, __u8);
-void irlmp_connless_data_indication(struct lsap_cb *, struct sk_buff *);
-#endif /* CONFIG_IRDA_ULTRA */
-
-void irlmp_status_indication(struct lap_cb *, LINK_STATUS link, LOCK_STATUS lock);
-void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow);
-
-LM_REASON irlmp_convert_lap_reason(LAP_REASON);
-
-static inline __u32 irlmp_get_saddr(const struct lsap_cb *self)
-{
- return (self && self->lap) ? self->lap->saddr : 0;
-}
-
-static inline __u32 irlmp_get_daddr(const struct lsap_cb *self)
-{
- return (self && self->lap) ? self->lap->daddr : 0;
-}
-
-const char *irlmp_reason_str(LM_REASON reason);
-
-extern int sysctl_discovery_timeout;
-extern int sysctl_discovery_slots;
-extern int sysctl_discovery;
-extern int sysctl_lap_keepalive_time; /* in ms, default is LM_IDLE_TIMEOUT */
-extern struct irlmp_cb *irlmp;
-
-/* Check if LAP queue is full.
- * Used by IrTTP for low control, see comments in irlap.h - Jean II */
-static inline int irlmp_lap_tx_queue_full(struct lsap_cb *self)
-{
- if (self == NULL)
- return 0;
- if (self->lap == NULL)
- return 0;
- if (self->lap->irlap == NULL)
- return 0;
-
- return IRLAP_GET_TX_QUEUE_LEN(self->lap->irlap) >= LAP_HIGH_THRESHOLD;
-}
-
-/* After doing a irlmp_dup(), this get one of the two socket back into
- * a state where it's waiting incoming connections.
- * Note : this can be used *only* if the socket is not yet connected
- * (i.e. NO irlmp_connect_response() done on this socket).
- * - Jean II */
-static inline void irlmp_listen(struct lsap_cb *self)
-{
- self->dlsap_sel = LSAP_ANY;
- self->lap = NULL;
- self->lsap_state = LSAP_DISCONNECTED;
- /* Started when we received the LM_CONNECT_INDICATION */
- del_timer(&self->watchdog_timer);
-}
-
-#endif
diff --git a/drivers/staging/irda/include/net/irda/irlmp_event.h b/drivers/staging/irda/include/net/irda/irlmp_event.h
deleted file mode 100644
index a1a082fe384e..000000000000
--- a/drivers/staging/irda/include/net/irda/irlmp_event.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlmp_event.h
- * Version: 0.1
- * Description: IrDA-LMP event handling
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Aug 4 20:40:53 1997
- * Modified at: Thu Jul 8 12:18:54 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRLMP_EVENT_H
-#define IRLMP_EVENT_H
-
-/* A few forward declarations (to make compiler happy) */
-struct irlmp_cb;
-struct lsap_cb;
-struct lap_cb;
-struct discovery_t;
-
-/* LAP states */
-typedef enum {
- /* IrLAP connection control states */
- LAP_STANDBY, /* No LAP connection */
- LAP_U_CONNECT, /* Starting LAP connection */
- LAP_ACTIVE, /* LAP connection is active */
-} IRLMP_STATE;
-
-/* LSAP connection control states */
-typedef enum {
- LSAP_DISCONNECTED, /* No LSAP connection */
- LSAP_CONNECT, /* Connect indication from peer */
- LSAP_CONNECT_PEND, /* Connect request from service user */
- LSAP_DATA_TRANSFER_READY, /* LSAP connection established */
- LSAP_SETUP, /* Trying to set up LSAP connection */
- LSAP_SETUP_PEND, /* Request to start LAP connection */
-} LSAP_STATE;
-
-typedef enum {
- /* LSAP events */
- LM_CONNECT_REQUEST,
- LM_CONNECT_CONFIRM,
- LM_CONNECT_RESPONSE,
- LM_CONNECT_INDICATION,
-
- LM_DISCONNECT_INDICATION,
- LM_DISCONNECT_REQUEST,
-
- LM_DATA_REQUEST,
- LM_UDATA_REQUEST,
- LM_DATA_INDICATION,
- LM_UDATA_INDICATION,
-
- LM_WATCHDOG_TIMEOUT,
-
- /* IrLAP events */
- LM_LAP_CONNECT_REQUEST,
- LM_LAP_CONNECT_INDICATION,
- LM_LAP_CONNECT_CONFIRM,
- LM_LAP_DISCONNECT_INDICATION,
- LM_LAP_DISCONNECT_REQUEST,
- LM_LAP_DISCOVERY_REQUEST,
- LM_LAP_DISCOVERY_CONFIRM,
- LM_LAP_IDLE_TIMEOUT,
-} IRLMP_EVENT;
-
-extern const char *const irlmp_state[];
-extern const char *const irlsap_state[];
-
-void irlmp_watchdog_timer_expired(struct timer_list *t);
-void irlmp_discovery_timer_expired(struct timer_list *t);
-void irlmp_idle_timer_expired(struct timer_list *t);
-
-void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event,
- struct sk_buff *skb);
-int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event,
- struct sk_buff *skb);
-
-#endif /* IRLMP_EVENT_H */
-
-
-
-
diff --git a/drivers/staging/irda/include/net/irda/irlmp_frame.h b/drivers/staging/irda/include/net/irda/irlmp_frame.h
deleted file mode 100644
index 1906eb71422e..000000000000
--- a/drivers/staging/irda/include/net/irda/irlmp_frame.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlmp_frame.h
- * Version: 0.9
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Tue Aug 19 02:09:59 1997
- * Modified at: Fri Dec 10 13:21:53 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>,
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRMLP_FRAME_H
-#define IRMLP_FRAME_H
-
-#include <linux/skbuff.h>
-
-#include <net/irda/discovery.h>
-
-/* IrLMP frame opcodes */
-#define CONNECT_CMD 0x01
-#define CONNECT_CNF 0x81
-#define DISCONNECT 0x02
-#define ACCESSMODE_CMD 0x03
-#define ACCESSMODE_CNF 0x83
-
-#define CONTROL_BIT 0x80
-
-void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
- int expedited, struct sk_buff *skb);
-void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
- __u8 opcode, struct sk_buff *skb);
-void irlmp_link_data_indication(struct lap_cb *, struct sk_buff *,
- int unreliable);
-#ifdef CONFIG_IRDA_ULTRA
-void irlmp_link_unitdata_indication(struct lap_cb *, struct sk_buff *);
-#endif /* CONFIG_IRDA_ULTRA */
-
-void irlmp_link_connect_indication(struct lap_cb *, __u32 saddr, __u32 daddr,
- struct qos_info *qos, struct sk_buff *skb);
-void irlmp_link_connect_request(__u32 daddr);
-void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos,
- struct sk_buff *skb);
-void irlmp_link_disconnect_indication(struct lap_cb *, struct irlap_cb *,
- LAP_REASON reason, struct sk_buff *);
-void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log);
-void irlmp_link_discovery_indication(struct lap_cb *, discovery_t *discovery);
-
-#endif
diff --git a/drivers/staging/irda/include/net/irda/irmod.h b/drivers/staging/irda/include/net/irda/irmod.h
deleted file mode 100644
index 86f0dbb8ee5d..000000000000
--- a/drivers/staging/irda/include/net/irda/irmod.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*********************************************************************
- *
- * Filename: irmod.h
- * Version: 0.3
- * Description: IrDA module and utilities functions
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Dec 15 13:58:52 1997
- * Modified at: Fri Jan 28 13:15:24 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved.
- * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charg.
- *
- ********************************************************************/
-
-#ifndef IRMOD_H
-#define IRMOD_H
-
-/* Misc status information */
-typedef enum {
- STATUS_OK,
- STATUS_ABORTED,
- STATUS_NO_ACTIVITY,
- STATUS_NOISY,
- STATUS_REMOTE,
-} LINK_STATUS;
-
-typedef enum {
- LOCK_NO_CHANGE,
- LOCK_LOCKED,
- LOCK_UNLOCKED,
-} LOCK_STATUS;
-
-typedef enum { FLOW_STOP, FLOW_START } LOCAL_FLOW;
-
-/*
- * IrLMP disconnect reasons. The order is very important, since they
- * correspond to disconnect reasons sent in IrLMP disconnect frames, so
- * please do not touch :-)
- */
-typedef enum {
- LM_USER_REQUEST = 1, /* User request */
- LM_LAP_DISCONNECT, /* Unexpected IrLAP disconnect */
- LM_CONNECT_FAILURE, /* Failed to establish IrLAP connection */
- LM_LAP_RESET, /* IrLAP reset */
- LM_INIT_DISCONNECT, /* Link Management initiated disconnect */
- LM_LSAP_NOTCONN, /* Data delivered on unconnected LSAP */
- LM_NON_RESP_CLIENT, /* Non responsive LM-MUX client */
- LM_NO_AVAIL_CLIENT, /* No available LM-MUX client */
- LM_CONN_HALF_OPEN, /* Connection is half open */
- LM_BAD_SOURCE_ADDR, /* Illegal source address (i.e 0x00) */
-} LM_REASON;
-#define LM_UNKNOWN 0xff /* Unspecified disconnect reason */
-
-/* A few forward declarations (to make compiler happy) */
-struct qos_info; /* in <net/irda/qos.h> */
-
-/*
- * Notify structure used between transport and link management layers
- */
-typedef struct {
- int (*data_indication)(void *priv, void *sap, struct sk_buff *skb);
- int (*udata_indication)(void *priv, void *sap, struct sk_buff *skb);
- void (*connect_confirm)(void *instance, void *sap,
- struct qos_info *qos, __u32 max_sdu_size,
- __u8 max_header_size, struct sk_buff *skb);
- void (*connect_indication)(void *instance, void *sap,
- struct qos_info *qos, __u32 max_sdu_size,
- __u8 max_header_size, struct sk_buff *skb);
- void (*disconnect_indication)(void *instance, void *sap,
- LM_REASON reason, struct sk_buff *);
- void (*flow_indication)(void *instance, void *sap, LOCAL_FLOW flow);
- void (*status_indication)(void *instance,
- LINK_STATUS link, LOCK_STATUS lock);
- void *instance; /* Layer instance pointer */
- char name[16]; /* Name of layer */
-} notify_t;
-
-#define NOTIFY_MAX_NAME 16
-
-/* Zero the notify structure */
-void irda_notify_init(notify_t *notify);
-
-/* Locking wrapper - Note the inverted logic on irda_lock().
- * Those function basically return false if the lock is already in the
- * position you want to set it. - Jean II */
-#define irda_lock(lock) (! test_and_set_bit(0, (void *) (lock)))
-#define irda_unlock(lock) (test_and_clear_bit(0, (void *) (lock)))
-
-#endif /* IRMOD_H */
-
-
-
-
-
-
-
-
-
diff --git a/drivers/staging/irda/include/net/irda/irqueue.h b/drivers/staging/irda/include/net/irda/irqueue.h
deleted file mode 100644
index 37f512bd6733..000000000000
--- a/drivers/staging/irda/include/net/irda/irqueue.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*********************************************************************
- *
- * Filename: irqueue.h
- * Version: 0.3
- * Description: General queue implementation
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Tue Jun 9 13:26:50 1998
- * Modified at: Thu Oct 7 13:25:16 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (C) 1998-1999, Aage Kvalnes <aage@cs.uit.no>
- * Copyright (c) 1998, Dag Brattli
- * All Rights Reserved.
- *
- * This code is taken from the Vortex Operating System written by Aage
- * Kvalnes and has been ported to Linux and Linux/IR by Dag Brattli
- *
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/types.h>
-#include <linux/spinlock.h>
-
-#ifndef IRDA_QUEUE_H
-#define IRDA_QUEUE_H
-
-#define NAME_SIZE 32
-
-/*
- * Hash types (some flags can be xored)
- * See comments in irqueue.c for which one to use...
- */
-#define HB_NOLOCK 0 /* No concurent access prevention */
-#define HB_LOCK 1 /* Prevent concurent write with global lock */
-
-/*
- * Hash defines
- */
-#define HASHBIN_SIZE 8
-#define HASHBIN_MASK 0x7
-
-#ifndef IRDA_ALIGN
-#define IRDA_ALIGN __attribute__((aligned))
-#endif
-
-#define Q_NULL { NULL, NULL, "", 0 }
-
-typedef void (*FREE_FUNC)(void *arg);
-
-struct irda_queue {
- struct irda_queue *q_next;
- struct irda_queue *q_prev;
-
- char q_name[NAME_SIZE];
- long q_hash; /* Must be able to cast a (void *) */
-};
-typedef struct irda_queue irda_queue_t;
-
-typedef struct hashbin_t {
- __u32 magic;
- int hb_type;
- int hb_size;
- spinlock_t hb_spinlock; /* HB_LOCK - Can be used by the user */
-
- irda_queue_t* hb_queue[HASHBIN_SIZE] IRDA_ALIGN;
-
- irda_queue_t* hb_current;
-} hashbin_t;
-
-hashbin_t *hashbin_new(int type);
-int hashbin_delete(hashbin_t* hashbin, FREE_FUNC func);
-int hashbin_clear(hashbin_t* hashbin, FREE_FUNC free_func);
-void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, long hashv,
- const char* name);
-void* hashbin_remove(hashbin_t* hashbin, long hashv, const char* name);
-void* hashbin_remove_first(hashbin_t *hashbin);
-void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry);
-void* hashbin_find(hashbin_t* hashbin, long hashv, const char* name);
-void* hashbin_lock_find(hashbin_t* hashbin, long hashv, const char* name);
-void* hashbin_find_next(hashbin_t* hashbin, long hashv, const char* name,
- void ** pnext);
-irda_queue_t *hashbin_get_first(hashbin_t *hashbin);
-irda_queue_t *hashbin_get_next(hashbin_t *hashbin);
-
-#define HASHBIN_GET_SIZE(hashbin) hashbin->hb_size
-
-#endif
diff --git a/drivers/staging/irda/include/net/irda/irttp.h b/drivers/staging/irda/include/net/irda/irttp.h
deleted file mode 100644
index 98682d4bae8f..000000000000
--- a/drivers/staging/irda/include/net/irda/irttp.h
+++ /dev/null
@@ -1,210 +0,0 @@
-/*********************************************************************
- *
- * Filename: irttp.h
- * Version: 1.0
- * Description: Tiny Transport Protocol (TTP) definitions
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Aug 31 20:14:31 1997
- * Modified at: Sun Dec 12 13:09:07 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef IRTTP_H
-#define IRTTP_H
-
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irlmp.h> /* struct lsap_cb */
-#include <net/irda/qos.h> /* struct qos_info */
-#include <net/irda/irqueue.h>
-
-#define TTP_MAX_CONNECTIONS LM_MAX_CONNECTIONS
-#define TTP_HEADER 1
-#define TTP_MAX_HEADER (TTP_HEADER + LMP_MAX_HEADER)
-#define TTP_SAR_HEADER 5
-#define TTP_PARAMETERS 0x80
-#define TTP_MORE 0x80
-
-/* Transmission queue sizes */
-/* Worst case scenario, two window of data - Jean II */
-#define TTP_TX_MAX_QUEUE 14
-/* We need to keep at least 5 frames to make sure that we can refill
- * appropriately the LAP layer. LAP keeps only two buffers, and we need
- * to have 7 to make a full window - Jean II */
-#define TTP_TX_LOW_THRESHOLD 5
-/* Most clients are synchronous with respect to flow control, so we can
- * keep a low number of Tx buffers in TTP - Jean II */
-#define TTP_TX_HIGH_THRESHOLD 7
-
-/* Receive queue sizes */
-/* Minimum of credit that the peer should hold.
- * If the peer has less credits than 9 frames, we will explicitly send
- * him some credits (through irttp_give_credit() and a specific frame).
- * Note that when we give credits it's likely that it won't be sent in
- * this LAP window, but in the next one. So, we make sure that the peer
- * has something to send while waiting for credits (one LAP window == 7
- * + 1 frames while he process the credits). - Jean II */
-#define TTP_RX_MIN_CREDIT 8
-/* This is the default maximum number of credits held by the peer, so the
- * default maximum number of frames he can send us before needing flow
- * control answer from us (this may be negociated differently at TSAP setup).
- * We want to minimise the number of times we have to explicitly send some
- * credit to the peer, hoping we can piggyback it on the return data. In
- * particular, it doesn't make sense for us to send credit more than once
- * per LAP window.
- * Moreover, giving credits has some latency, so we need strictly more than
- * a LAP window, otherwise we may already have credits in our Tx queue.
- * But on the other hand, we don't want to keep too many Rx buffer here
- * before starting to flow control the other end, so make it exactly one
- * LAP window + 1 + MIN_CREDITS. - Jean II */
-#define TTP_RX_DEFAULT_CREDIT 16
-/* Maximum number of credits we can allow the peer to have, and therefore
- * maximum Rx queue size.
- * Note that we try to deliver packets to the higher layer every time we
- * receive something, so in normal mode the Rx queue will never contains
- * more than one or two packets. - Jean II */
-#define TTP_RX_MAX_CREDIT 21
-
-/* What clients should use when calling ttp_open_tsap() */
-#define DEFAULT_INITIAL_CREDIT TTP_RX_DEFAULT_CREDIT
-
-/* Some priorities for disconnect requests */
-#define P_NORMAL 0
-#define P_HIGH 1
-
-#define TTP_SAR_DISABLE 0
-#define TTP_SAR_UNBOUND 0xffffffff
-
-/* Parameters */
-#define TTP_MAX_SDU_SIZE 0x01
-
-/*
- * This structure contains all data associated with one instance of a TTP
- * connection.
- */
-struct tsap_cb {
- irda_queue_t q; /* Must be first */
- magic_t magic; /* Just in case */
-
- __u8 stsap_sel; /* Source TSAP */
- __u8 dtsap_sel; /* Destination TSAP */
-
- struct lsap_cb *lsap; /* Corresponding LSAP to this TSAP */
-
- __u8 connected; /* TSAP connected */
-
- __u8 initial_credit; /* Initial credit to give peer */
-
- int avail_credit; /* Available credit to return to peer */
- int remote_credit; /* Credit held by peer TTP entity */
- int send_credit; /* Credit held by local TTP entity */
-
- struct sk_buff_head tx_queue; /* Frames to be transmitted */
- struct sk_buff_head rx_queue; /* Received frames */
- struct sk_buff_head rx_fragments;
- int tx_queue_lock;
- int rx_queue_lock;
- spinlock_t lock;
-
- notify_t notify; /* Callbacks to client layer */
-
- struct net_device_stats stats;
- struct timer_list todo_timer;
-
- __u32 max_seg_size; /* Max data that fit into an IrLAP frame */
- __u8 max_header_size;
-
- int rx_sdu_busy; /* RxSdu.busy */
- __u32 rx_sdu_size; /* Current size of a partially received frame */
- __u32 rx_max_sdu_size; /* Max receive user data size */
-
- int tx_sdu_busy; /* TxSdu.busy */
- __u32 tx_max_sdu_size; /* Max transmit user data size */
-
- int close_pend; /* Close, but disconnect_pend */
- unsigned long disconnect_pend; /* Disconnect, but still data to send */
- struct sk_buff *disconnect_skb;
-};
-
-struct irttp_cb {
- magic_t magic;
- hashbin_t *tsaps;
-};
-
-int irttp_init(void);
-void irttp_cleanup(void);
-
-struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify);
-int irttp_close_tsap(struct tsap_cb *self);
-
-int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb);
-int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb);
-
-int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
- __u32 saddr, __u32 daddr,
- struct qos_info *qos, __u32 max_sdu_size,
- struct sk_buff *userdata);
-int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
- struct sk_buff *userdata);
-int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *skb,
- int priority);
-void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow);
-struct tsap_cb *irttp_dup(struct tsap_cb *self, void *instance);
-
-static inline __u32 irttp_get_saddr(struct tsap_cb *self)
-{
- return irlmp_get_saddr(self->lsap);
-}
-
-static inline __u32 irttp_get_daddr(struct tsap_cb *self)
-{
- return irlmp_get_daddr(self->lsap);
-}
-
-static inline __u32 irttp_get_max_seg_size(struct tsap_cb *self)
-{
- return self->max_seg_size;
-}
-
-/* After doing a irttp_dup(), this get one of the two socket back into
- * a state where it's waiting incoming connections.
- * Note : this can be used *only* if the socket is not yet connected
- * (i.e. NO irttp_connect_response() done on this socket).
- * - Jean II */
-static inline void irttp_listen(struct tsap_cb *self)
-{
- irlmp_listen(self->lsap);
- self->dtsap_sel = LSAP_ANY;
-}
-
-/* Return TRUE if the node is in primary mode (i.e. master)
- * - Jean II */
-static inline int irttp_is_primary(struct tsap_cb *self)
-{
- if ((self == NULL) ||
- (self->lsap == NULL) ||
- (self->lsap->lap == NULL) ||
- (self->lsap->lap->irlap == NULL))
- return -2;
- return irlap_is_primary(self->lsap->lap->irlap);
-}
-
-#endif /* IRTTP_H */
diff --git a/drivers/staging/irda/include/net/irda/parameters.h b/drivers/staging/irda/include/net/irda/parameters.h
deleted file mode 100644
index 2d9cd0007cba..000000000000
--- a/drivers/staging/irda/include/net/irda/parameters.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*********************************************************************
- *
- * Filename: parameters.h
- * Version: 1.0
- * Description: A more general way to handle (pi,pl,pv) parameters
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Jun 7 08:47:28 1999
- * Modified at: Sun Jan 30 14:05:14 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999-2000 Dag Brattli, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Michel Dänzer <daenzer@debian.org>, 10/2001
- * - simplify irda_pv_t to avoid endianness issues
- *
- ********************************************************************/
-
-#ifndef IRDA_PARAMS_H
-#define IRDA_PARAMS_H
-
-/*
- * The currently supported types. Beware not to change the sequence since
- * it a good reason why the sized integers has a value equal to their size
- */
-typedef enum {
- PV_INTEGER, /* Integer of any (pl) length */
- PV_INT_8_BITS, /* Integer of 8 bits in length */
- PV_INT_16_BITS, /* Integer of 16 bits in length */
- PV_STRING, /* \0 terminated string */
- PV_INT_32_BITS, /* Integer of 32 bits in length */
- PV_OCT_SEQ, /* Octet sequence */
- PV_NO_VALUE /* Does not contain any value (pl=0) */
-} PV_TYPE;
-
-/* Bit 7 of type field */
-#define PV_BIG_ENDIAN 0x80
-#define PV_LITTLE_ENDIAN 0x00
-#define PV_MASK 0x7f /* To mask away endian bit */
-
-#define PV_PUT 0
-#define PV_GET 1
-
-typedef union {
- char *c;
- __u32 i;
- __u32 *ip;
-} irda_pv_t;
-
-typedef struct {
- __u8 pi;
- __u8 pl;
- irda_pv_t pv;
-} irda_param_t;
-
-typedef int (*PI_HANDLER)(void *self, irda_param_t *param, int get);
-typedef int (*PV_HANDLER)(void *self, __u8 *buf, int len, __u8 pi,
- PV_TYPE type, PI_HANDLER func);
-
-typedef struct {
- const PI_HANDLER func; /* Handler for this parameter identifier */
- PV_TYPE type; /* Data type for this parameter */
-} pi_minor_info_t;
-
-typedef struct {
- const pi_minor_info_t *pi_minor_call_table;
- int len;
-} pi_major_info_t;
-
-typedef struct {
- const pi_major_info_t *tables;
- int len;
- __u8 pi_mask;
- int pi_major_offset;
-} pi_param_info_t;
-
-int irda_param_pack(__u8 *buf, char *fmt, ...);
-
-int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len,
- pi_param_info_t *info);
-int irda_param_extract_all(void *self, __u8 *buf, int len,
- pi_param_info_t *info);
-
-#define irda_param_insert_byte(buf,pi,pv) irda_param_pack(buf,"bbb",pi,1,pv)
-
-#endif /* IRDA_PARAMS_H */
-
diff --git a/drivers/staging/irda/include/net/irda/qos.h b/drivers/staging/irda/include/net/irda/qos.h
deleted file mode 100644
index a0315b50ac27..000000000000
--- a/drivers/staging/irda/include/net/irda/qos.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*********************************************************************
- *
- * Filename: qos.h
- * Version: 1.0
- * Description: Quality of Service definitions
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Fri Sep 19 23:21:09 1997
- * Modified at: Thu Dec 2 13:51:54 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Dag Brattli, 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.
- *
- * 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 IRDA_QOS_H
-#define IRDA_QOS_H
-
-#include <linux/skbuff.h>
-
-#include <net/irda/parameters.h>
-
-#define PI_BAUD_RATE 0x01
-#define PI_MAX_TURN_TIME 0x82
-#define PI_DATA_SIZE 0x83
-#define PI_WINDOW_SIZE 0x84
-#define PI_ADD_BOFS 0x85
-#define PI_MIN_TURN_TIME 0x86
-#define PI_LINK_DISC 0x08
-
-#define IR_115200_MAX 0x3f
-
-/* Baud rates (first byte) */
-#define IR_2400 0x01
-#define IR_9600 0x02
-#define IR_19200 0x04
-#define IR_38400 0x08
-#define IR_57600 0x10
-#define IR_115200 0x20
-#define IR_576000 0x40
-#define IR_1152000 0x80
-
-/* Baud rates (second byte) */
-#define IR_4000000 0x01
-#define IR_16000000 0x02
-
-/* Quality of Service information */
-struct qos_value {
- __u32 value;
- __u16 bits; /* LSB is first byte, MSB is second byte */
-};
-
-struct qos_info {
- magic_t magic;
-
- struct qos_value baud_rate; /* IR_11520O | ... */
- struct qos_value max_turn_time;
- struct qos_value data_size;
- struct qos_value window_size;
- struct qos_value additional_bofs;
- struct qos_value min_turn_time;
- struct qos_value link_disc_time;
-
- struct qos_value power;
-};
-
-extern int sysctl_max_baud_rate;
-extern int sysctl_max_inactive_time;
-
-void irda_init_max_qos_capabilies(struct qos_info *qos);
-void irda_qos_compute_intersection(struct qos_info *, struct qos_info *);
-
-__u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time);
-
-void irda_qos_bits_to_value(struct qos_info *qos);
-
-/* So simple, how could we not inline those two ?
- * Note : one byte is 10 bits if you include start and stop bits
- * Jean II */
-#define irlap_min_turn_time_in_bytes(speed, min_turn_time) ( \
- speed * min_turn_time / 10000000 \
-)
-#define irlap_xbofs_in_usec(speed, xbofs) ( \
- xbofs * 10000000 / speed \
-)
-
-#endif
-
diff --git a/drivers/staging/irda/include/net/irda/timer.h b/drivers/staging/irda/include/net/irda/timer.h
deleted file mode 100644
index 6dab15f5dae1..000000000000
--- a/drivers/staging/irda/include/net/irda/timer.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*********************************************************************
- *
- * Filename: timer.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sat Aug 16 00:59:29 1997
- * Modified at: Thu Oct 7 12:25:24 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1997, 1998-1999 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef TIMER_H
-#define TIMER_H
-
-#include <linux/timer.h>
-#include <linux/jiffies.h>
-
-#include <asm/param.h> /* for HZ */
-
-#include <net/irda/irda.h>
-
-/* A few forward declarations (to make compiler happy) */
-struct irlmp_cb;
-struct irlap_cb;
-struct lsap_cb;
-struct lap_cb;
-
-/*
- * Timeout definitions, some defined in IrLAP 6.13.5 - p. 92
- */
-#define POLL_TIMEOUT (450*HZ/1000) /* Must never exceed 500 ms */
-#define FINAL_TIMEOUT (500*HZ/1000) /* Must never exceed 500 ms */
-
-/*
- * Normally twice of p-timer. Note 3, IrLAP 6.3.11.2 - p. 60 suggests
- * at least twice duration of the P-timer.
- */
-#define WD_TIMEOUT (POLL_TIMEOUT*2)
-
-#define MEDIABUSY_TIMEOUT (500*HZ/1000) /* 500 msec */
-#define SMALLBUSY_TIMEOUT (100*HZ/1000) /* 100 msec - IrLAP 6.13.4 */
-
-/*
- * Slot timer must never exceed 85 ms, and must always be at least 25 ms,
- * suggested to 75-85 msec by IrDA lite. This doesn't work with a lot of
- * devices, and other stackes uses a lot more, so it's best we do it as well
- * (Note : this is the default value and sysctl overrides it - Jean II)
- */
-#define SLOT_TIMEOUT (90*HZ/1000)
-
-/*
- * The latest discovery frame (XID) is longer due to the extra discovery
- * information (hints, device name...). This is its extra length.
- * We use that when setting the query timeout. Jean II
- */
-#define XIDEXTRA_TIMEOUT (34*HZ/1000) /* 34 msec */
-
-#define WATCHDOG_TIMEOUT (20*HZ) /* 20 sec */
-
-static inline void irda_start_timer(struct timer_list *ptimer, int timeout,
- void (*callback)(struct timer_list *))
-{
- ptimer->function = callback;
-
- /* Set new value for timer (update or add timer).
- * We use mod_timer() because it's more efficient and also
- * safer with respect to race conditions - Jean II */
- mod_timer(ptimer, jiffies + timeout);
-}
-
-
-void irlap_start_slot_timer(struct irlap_cb *self, int timeout);
-void irlap_start_query_timer(struct irlap_cb *self, int S, int s);
-void irlap_start_final_timer(struct irlap_cb *self, int timeout);
-void irlap_start_wd_timer(struct irlap_cb *self, int timeout);
-void irlap_start_backoff_timer(struct irlap_cb *self, int timeout);
-
-void irlap_start_mbusy_timer(struct irlap_cb *self, int timeout);
-void irlap_stop_mbusy_timer(struct irlap_cb *);
-
-void irlmp_start_watchdog_timer(struct lsap_cb *, int timeout);
-void irlmp_start_discovery_timer(struct irlmp_cb *, int timeout);
-void irlmp_start_idle_timer(struct lap_cb *, int timeout);
-void irlmp_stop_idle_timer(struct lap_cb *self);
-
-#endif
-
diff --git a/drivers/staging/irda/include/net/irda/wrapper.h b/drivers/staging/irda/include/net/irda/wrapper.h
deleted file mode 100644
index eef53ebe3d76..000000000000
--- a/drivers/staging/irda/include/net/irda/wrapper.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*********************************************************************
- *
- * Filename: wrapper.h
- * Version: 1.2
- * Description: IrDA SIR async wrapper layer
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Aug 4 20:40:53 1997
- * Modified at: Tue Jan 11 12:37:29 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef WRAPPER_H
-#define WRAPPER_H
-
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-
-#include <net/irda/irda_device.h> /* iobuff_t */
-
-#define BOF 0xc0 /* Beginning of frame */
-#define XBOF 0xff
-#define EOF 0xc1 /* End of frame */
-#define CE 0x7d /* Control escape */
-
-#define STA BOF /* Start flag */
-#define STO EOF /* End flag */
-
-#define IRDA_TRANS 0x20 /* Asynchronous transparency modifier */
-
-/* States for receiving a frame in async mode */
-enum {
- OUTSIDE_FRAME,
- BEGIN_FRAME,
- LINK_ESCAPE,
- INSIDE_FRAME
-};
-
-/* Proto definitions */
-int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize);
-void async_unwrap_char(struct net_device *dev, struct net_device_stats *stats,
- iobuff_t *buf, __u8 byte);
-
-#endif
diff --git a/drivers/staging/irda/net/Kconfig b/drivers/staging/irda/net/Kconfig
deleted file mode 100644
index 6abeae6c666a..000000000000
--- a/drivers/staging/irda/net/Kconfig
+++ /dev/null
@@ -1,96 +0,0 @@
-#
-# IrDA protocol configuration
-#
-
-menuconfig IRDA
- depends on NET && !S390
- tristate "IrDA (infrared) subsystem support"
- select CRC_CCITT
- ---help---
- Say Y here if you want to build support for the IrDA (TM) protocols.
- The Infrared Data Associations (tm) specifies standards for wireless
- infrared communication and is supported by most laptops and PDA's.
-
- To use Linux support for the IrDA (tm) protocols, you will also need
- some user-space utilities like irattach. For more information, see
- the file <file:Documentation/networking/irda.txt>. You also want to
- read the IR-HOWTO, available at
- <http://www.tldp.org/docs.html#howto>.
-
- If you want to exchange bits of data (vCal, vCard) with a PDA, you
- will need to install some OBEX application, such as OpenObex :
- <http://sourceforge.net/projects/openobex/>
-
- To compile this support as a module, choose M here: the module will
- be called irda.
-
-comment "IrDA protocols"
- depends on IRDA
-
-source "drivers/staging/irda/net/irlan/Kconfig"
-
-source "drivers/staging/irda/net/irnet/Kconfig"
-
-source "drivers/staging/irda/net/ircomm/Kconfig"
-
-config IRDA_ULTRA
- bool "Ultra (connectionless) protocol"
- depends on IRDA
- help
- Say Y here to support the connectionless Ultra IRDA protocol.
- Ultra allows to exchange data over IrDA with really simple devices
- (watch, beacon) without the overhead of the IrDA protocol (no handshaking,
- no management frames, simple fixed header).
- Ultra is available as a special socket : socket(AF_IRDA, SOCK_DGRAM, 1);
-
-comment "IrDA options"
- depends on IRDA
-
-config IRDA_CACHE_LAST_LSAP
- bool "Cache last LSAP"
- depends on IRDA
- help
- Say Y here if you want IrLMP to cache the last LSAP used. This
- makes sense since most frames will be sent/received on the same
- connection. Enabling this option will save a hash-lookup per frame.
-
- If unsure, say Y.
-
-config IRDA_FAST_RR
- bool "Fast RRs (low latency)"
- depends on IRDA
- ---help---
- Say Y here is you want IrLAP to send fast RR (Receive Ready) frames
- when acting as a primary station.
- Disabling this option will make latency over IrDA very bad. Enabling
- this option will make the IrDA stack send more packet than strictly
- necessary, thus reduce your battery life (but not that much).
-
- Fast RR will make IrLAP send out a RR frame immediately when
- receiving a frame if its own transmit queue is currently empty. This
- will give a lot of speed improvement when receiving much data since
- the secondary station will not have to wait the max. turn around
- time (usually 500ms) before it is allowed to transmit the next time.
- If the transmit queue of the secondary is also empty, the primary will
- start backing-off before sending another RR frame, waiting longer
- each time until the back-off reaches the max. turn around time.
- This back-off increase in controlled via
- /proc/sys/net/irda/fast_poll_increase
-
- If unsure, say Y.
-
-config IRDA_DEBUG
- bool "Debug information"
- depends on IRDA
- help
- Say Y here if you want the IrDA subsystem to write debug information
- to your syslog. You can change the debug level in
- /proc/sys/net/irda/debug .
- When this option is enabled, the IrDA also perform many extra internal
- verifications which will usually prevent the kernel to crash in case of
- bugs.
-
- If unsure, say Y (since it makes it easier to find the bugs).
-
-source "drivers/staging/irda/drivers/Kconfig"
-
diff --git a/drivers/staging/irda/net/Makefile b/drivers/staging/irda/net/Makefile
deleted file mode 100644
index bd1a635b88cf..000000000000
--- a/drivers/staging/irda/net/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Makefile for the Linux IrDA protocol layer.
-#
-
-subdir-ccflags-y += -I$(srctree)/drivers/staging/irda/include
-
-obj-$(CONFIG_IRDA) += irda.o
-obj-$(CONFIG_IRLAN) += irlan/
-obj-$(CONFIG_IRNET) += irnet/
-obj-$(CONFIG_IRCOMM) += ircomm/
-
-irda-y := iriap.o iriap_event.o irlmp.o irlmp_event.o irlmp_frame.o \
- irlap.o irlap_event.o irlap_frame.o timer.o qos.o irqueue.o \
- irttp.o irda_device.o irias_object.o wrapper.o af_irda.o \
- discovery.o parameters.o irnetlink.o irmod.o
-irda-$(CONFIG_PROC_FS) += irproc.o
-irda-$(CONFIG_SYSCTL) += irsysctl.o
diff --git a/drivers/staging/irda/net/af_irda.c b/drivers/staging/irda/net/af_irda.c
deleted file mode 100644
index c13553a9ee11..000000000000
--- a/drivers/staging/irda/net/af_irda.c
+++ /dev/null
@@ -1,2692 +0,0 @@
-/*********************************************************************
- *
- * Filename: af_irda.c
- * Version: 0.9
- * Description: IrDA sockets implementation
- * Status: Stable
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun May 31 10:12:43 1998
- * Modified at: Sat Dec 25 21:10:23 1999
- * Modified by: Dag Brattli <dag@brattli.net>
- * Sources: af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc.
- *
- * Copyright (c) 1999 Dag Brattli <dagb@cs.uit.no>
- * Copyright (c) 1999-2003 Jean Tourrilhes <jt@hpl.hp.com>
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Linux-IrDA now supports four different types of IrDA sockets:
- *
- * o SOCK_STREAM: TinyTP connections with SAR disabled. The
- * max SDU size is 0 for conn. of this type
- * o SOCK_SEQPACKET: TinyTP connections with SAR enabled. TTP may
- * fragment the messages, but will preserve
- * the message boundaries
- * o SOCK_DGRAM: IRDAPROTO_UNITDATA: TinyTP connections with Unitdata
- * (unreliable) transfers
- * IRDAPROTO_ULTRA: Connectionless and unreliable data
- *
- ********************************************************************/
-
-#include <linux/capability.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/slab.h>
-#include <linux/sched/signal.h>
-#include <linux/init.h>
-#include <linux/net.h>
-#include <linux/irda.h>
-#include <linux/poll.h>
-
-#include <asm/ioctls.h> /* TIOCOUTQ, TIOCINQ */
-#include <linux/uaccess.h>
-
-#include <net/sock.h>
-#include <net/tcp_states.h>
-
-#include <net/irda/af_irda.h>
-
-static int irda_create(struct net *net, struct socket *sock, int protocol, int kern);
-
-static const struct proto_ops irda_stream_ops;
-static const struct proto_ops irda_seqpacket_ops;
-static const struct proto_ops irda_dgram_ops;
-
-#ifdef CONFIG_IRDA_ULTRA
-static const struct proto_ops irda_ultra_ops;
-#define ULTRA_MAX_DATA 382
-#endif /* CONFIG_IRDA_ULTRA */
-
-#define IRDA_MAX_HEADER (TTP_MAX_HEADER)
-
-/*
- * Function irda_data_indication (instance, sap, skb)
- *
- * Received some data from TinyTP. Just queue it on the receive queue
- *
- */
-static int irda_data_indication(void *instance, void *sap, struct sk_buff *skb)
-{
- struct irda_sock *self;
- struct sock *sk;
- int err;
-
- self = instance;
- sk = instance;
-
- err = sock_queue_rcv_skb(sk, skb);
- if (err) {
- pr_debug("%s(), error: no more mem!\n", __func__);
- self->rx_flow = FLOW_STOP;
-
- /* When we return error, TTP will need to requeue the skb */
- return err;
- }
-
- return 0;
-}
-
-/*
- * Function irda_disconnect_indication (instance, sap, reason, skb)
- *
- * Connection has been closed. Check reason to find out why
- *
- */
-static void irda_disconnect_indication(void *instance, void *sap,
- LM_REASON reason, struct sk_buff *skb)
-{
- struct irda_sock *self;
- struct sock *sk;
-
- self = instance;
-
- pr_debug("%s(%p)\n", __func__, self);
-
- /* Don't care about it, but let's not leak it */
- if(skb)
- dev_kfree_skb(skb);
-
- sk = instance;
- if (sk == NULL) {
- pr_debug("%s(%p) : BUG : sk is NULL\n",
- __func__, self);
- return;
- }
-
- /* Prevent race conditions with irda_release() and irda_shutdown() */
- bh_lock_sock(sk);
- if (!sock_flag(sk, SOCK_DEAD) && sk->sk_state != TCP_CLOSE) {
- sk->sk_state = TCP_CLOSE;
- sk->sk_shutdown |= SEND_SHUTDOWN;
-
- sk->sk_state_change(sk);
-
- /* Close our TSAP.
- * If we leave it open, IrLMP put it back into the list of
- * unconnected LSAPs. The problem is that any incoming request
- * can then be matched to this socket (and it will be, because
- * it is at the head of the list). This would prevent any
- * listening socket waiting on the same TSAP to get those
- * requests. Some apps forget to close sockets, or hang to it
- * a bit too long, so we may stay in this dead state long
- * enough to be noticed...
- * Note : all socket function do check sk->sk_state, so we are
- * safe...
- * Jean II
- */
- if (self->tsap) {
- irttp_close_tsap(self->tsap);
- self->tsap = NULL;
- }
- }
- bh_unlock_sock(sk);
-
- /* Note : once we are there, there is not much you want to do
- * with the socket anymore, apart from closing it.
- * For example, bind() and connect() won't reset sk->sk_err,
- * sk->sk_shutdown and sk->sk_flags to valid values...
- * Jean II
- */
-}
-
-/*
- * Function irda_connect_confirm (instance, sap, qos, max_sdu_size, skb)
- *
- * Connections has been confirmed by the remote device
- *
- */
-static void irda_connect_confirm(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size, __u8 max_header_size,
- struct sk_buff *skb)
-{
- struct irda_sock *self;
- struct sock *sk;
-
- self = instance;
-
- pr_debug("%s(%p)\n", __func__, self);
-
- sk = instance;
- if (sk == NULL) {
- dev_kfree_skb(skb);
- return;
- }
-
- dev_kfree_skb(skb);
- // Should be ??? skb_queue_tail(&sk->sk_receive_queue, skb);
-
- /* How much header space do we need to reserve */
- self->max_header_size = max_header_size;
-
- /* IrTTP max SDU size in transmit direction */
- self->max_sdu_size_tx = max_sdu_size;
-
- /* Find out what the largest chunk of data that we can transmit is */
- switch (sk->sk_type) {
- case SOCK_STREAM:
- if (max_sdu_size != 0) {
- net_err_ratelimited("%s: max_sdu_size must be 0\n",
- __func__);
- return;
- }
- self->max_data_size = irttp_get_max_seg_size(self->tsap);
- break;
- case SOCK_SEQPACKET:
- if (max_sdu_size == 0) {
- net_err_ratelimited("%s: max_sdu_size cannot be 0\n",
- __func__);
- return;
- }
- self->max_data_size = max_sdu_size;
- break;
- default:
- self->max_data_size = irttp_get_max_seg_size(self->tsap);
- }
-
- pr_debug("%s(), max_data_size=%d\n", __func__,
- self->max_data_size);
-
- memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
-
- /* We are now connected! */
- sk->sk_state = TCP_ESTABLISHED;
- sk->sk_state_change(sk);
-}
-
-/*
- * Function irda_connect_indication(instance, sap, qos, max_sdu_size, userdata)
- *
- * Incoming connection
- *
- */
-static void irda_connect_indication(void *instance, void *sap,
- struct qos_info *qos, __u32 max_sdu_size,
- __u8 max_header_size, struct sk_buff *skb)
-{
- struct irda_sock *self;
- struct sock *sk;
-
- self = instance;
-
- pr_debug("%s(%p)\n", __func__, self);
-
- sk = instance;
- if (sk == NULL) {
- dev_kfree_skb(skb);
- return;
- }
-
- /* How much header space do we need to reserve */
- self->max_header_size = max_header_size;
-
- /* IrTTP max SDU size in transmit direction */
- self->max_sdu_size_tx = max_sdu_size;
-
- /* Find out what the largest chunk of data that we can transmit is */
- switch (sk->sk_type) {
- case SOCK_STREAM:
- if (max_sdu_size != 0) {
- net_err_ratelimited("%s: max_sdu_size must be 0\n",
- __func__);
- kfree_skb(skb);
- return;
- }
- self->max_data_size = irttp_get_max_seg_size(self->tsap);
- break;
- case SOCK_SEQPACKET:
- if (max_sdu_size == 0) {
- net_err_ratelimited("%s: max_sdu_size cannot be 0\n",
- __func__);
- kfree_skb(skb);
- return;
- }
- self->max_data_size = max_sdu_size;
- break;
- default:
- self->max_data_size = irttp_get_max_seg_size(self->tsap);
- }
-
- pr_debug("%s(), max_data_size=%d\n", __func__,
- self->max_data_size);
-
- memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
-
- skb_queue_tail(&sk->sk_receive_queue, skb);
- sk->sk_state_change(sk);
-}
-
-/*
- * Function irda_connect_response (handle)
- *
- * Accept incoming connection
- *
- */
-static void irda_connect_response(struct irda_sock *self)
-{
- struct sk_buff *skb;
-
- skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER, GFP_KERNEL);
- if (skb == NULL) {
- pr_debug("%s() Unable to allocate sk_buff!\n",
- __func__);
- return;
- }
-
- /* Reserve space for MUX_CONTROL and LAP header */
- skb_reserve(skb, IRDA_MAX_HEADER);
-
- irttp_connect_response(self->tsap, self->max_sdu_size_rx, skb);
-}
-
-/*
- * Function irda_flow_indication (instance, sap, flow)
- *
- * Used by TinyTP to tell us if it can accept more data or not
- *
- */
-static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
-{
- struct irda_sock *self;
- struct sock *sk;
-
- self = instance;
- sk = instance;
- BUG_ON(sk == NULL);
-
- switch (flow) {
- case FLOW_STOP:
- pr_debug("%s(), IrTTP wants us to slow down\n",
- __func__);
- self->tx_flow = flow;
- break;
- case FLOW_START:
- self->tx_flow = flow;
- pr_debug("%s(), IrTTP wants us to start again\n",
- __func__);
- wake_up_interruptible(sk_sleep(sk));
- break;
- default:
- pr_debug("%s(), Unknown flow command!\n", __func__);
- /* Unknown flow command, better stop */
- self->tx_flow = flow;
- break;
- }
-}
-
-/*
- * Function irda_getvalue_confirm (obj_id, value, priv)
- *
- * Got answer from remote LM-IAS, just pass object to requester...
- *
- * Note : duplicate from above, but we need our own version that
- * doesn't touch the dtsap_sel and save the full value structure...
- */
-static void irda_getvalue_confirm(int result, __u16 obj_id,
- struct ias_value *value, void *priv)
-{
- struct irda_sock *self;
-
- self = priv;
- if (!self) {
- net_warn_ratelimited("%s: lost myself!\n", __func__);
- return;
- }
-
- pr_debug("%s(%p)\n", __func__, self);
-
- /* We probably don't need to make any more queries */
- iriap_close(self->iriap);
- self->iriap = NULL;
-
- /* Check if request succeeded */
- if (result != IAS_SUCCESS) {
- pr_debug("%s(), IAS query failed! (%d)\n", __func__,
- result);
-
- self->errno = result; /* We really need it later */
-
- /* Wake up any processes waiting for result */
- wake_up_interruptible(&self->query_wait);
-
- return;
- }
-
- /* Pass the object to the caller (so the caller must delete it) */
- self->ias_result = value;
- self->errno = 0;
-
- /* Wake up any processes waiting for result */
- wake_up_interruptible(&self->query_wait);
-}
-
-/*
- * Function irda_selective_discovery_indication (discovery)
- *
- * Got a selective discovery indication from IrLMP.
- *
- * IrLMP is telling us that this node is new and matching our hint bit
- * filter. Wake up any process waiting for answer...
- */
-static void irda_selective_discovery_indication(discinfo_t *discovery,
- DISCOVERY_MODE mode,
- void *priv)
-{
- struct irda_sock *self;
-
- self = priv;
- if (!self) {
- net_warn_ratelimited("%s: lost myself!\n", __func__);
- return;
- }
-
- /* Pass parameter to the caller */
- self->cachedaddr = discovery->daddr;
-
- /* Wake up process if its waiting for device to be discovered */
- wake_up_interruptible(&self->query_wait);
-}
-
-/*
- * Function irda_discovery_timeout (priv)
- *
- * Timeout in the selective discovery process
- *
- * We were waiting for a node to be discovered, but nothing has come up
- * so far. Wake up the user and tell him that we failed...
- */
-static void irda_discovery_timeout(struct timer_list *t)
-{
- struct irda_sock *self;
-
- self = from_timer(self, t, watchdog);
- BUG_ON(self == NULL);
-
- /* Nothing for the caller */
- self->cachelog = NULL;
- self->cachedaddr = 0;
- self->errno = -ETIME;
-
- /* Wake up process if its still waiting... */
- wake_up_interruptible(&self->query_wait);
-}
-
-/*
- * Function irda_open_tsap (self)
- *
- * Open local Transport Service Access Point (TSAP)
- *
- */
-static int irda_open_tsap(struct irda_sock *self, __u8 tsap_sel, char *name)
-{
- notify_t notify;
-
- if (self->tsap) {
- pr_debug("%s: busy!\n", __func__);
- return -EBUSY;
- }
-
- /* Initialize callbacks to be used by the IrDA stack */
- irda_notify_init(&notify);
- notify.connect_confirm = irda_connect_confirm;
- notify.connect_indication = irda_connect_indication;
- notify.disconnect_indication = irda_disconnect_indication;
- notify.data_indication = irda_data_indication;
- notify.udata_indication = irda_data_indication;
- notify.flow_indication = irda_flow_indication;
- notify.instance = self;
- strncpy(notify.name, name, NOTIFY_MAX_NAME);
-
- self->tsap = irttp_open_tsap(tsap_sel, DEFAULT_INITIAL_CREDIT,
- &notify);
- if (self->tsap == NULL) {
- pr_debug("%s(), Unable to allocate TSAP!\n",
- __func__);
- return -ENOMEM;
- }
- /* Remember which TSAP selector we actually got */
- self->stsap_sel = self->tsap->stsap_sel;
-
- return 0;
-}
-
-/*
- * Function irda_open_lsap (self)
- *
- * Open local Link Service Access Point (LSAP). Used for opening Ultra
- * sockets
- */
-#ifdef CONFIG_IRDA_ULTRA
-static int irda_open_lsap(struct irda_sock *self, int pid)
-{
- notify_t notify;
-
- if (self->lsap) {
- net_warn_ratelimited("%s(), busy!\n", __func__);
- return -EBUSY;
- }
-
- /* Initialize callbacks to be used by the IrDA stack */
- irda_notify_init(&notify);
- notify.udata_indication = irda_data_indication;
- notify.instance = self;
- strncpy(notify.name, "Ultra", NOTIFY_MAX_NAME);
-
- self->lsap = irlmp_open_lsap(LSAP_CONNLESS, &notify, pid);
- if (self->lsap == NULL) {
- pr_debug("%s(), Unable to allocate LSAP!\n", __func__);
- return -ENOMEM;
- }
-
- return 0;
-}
-#endif /* CONFIG_IRDA_ULTRA */
-
-/*
- * Function irda_find_lsap_sel (self, name)
- *
- * Try to lookup LSAP selector in remote LM-IAS
- *
- * Basically, we start a IAP query, and then go to sleep. When the query
- * return, irda_getvalue_confirm will wake us up, and we can examine the
- * result of the query...
- * Note that in some case, the query fail even before we go to sleep,
- * creating some races...
- */
-static int irda_find_lsap_sel(struct irda_sock *self, char *name)
-{
- pr_debug("%s(%p, %s)\n", __func__, self, name);
-
- if (self->iriap) {
- net_warn_ratelimited("%s(): busy with a previous query\n",
- __func__);
- return -EBUSY;
- }
-
- self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
- irda_getvalue_confirm);
- if(self->iriap == NULL)
- return -ENOMEM;
-
- /* Treat unexpected wakeup as disconnect */
- self->errno = -EHOSTUNREACH;
-
- /* Query remote LM-IAS */
- iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr,
- name, "IrDA:TinyTP:LsapSel");
-
- /* Wait for answer, if not yet finished (or failed) */
- if (wait_event_interruptible(self->query_wait, (self->iriap==NULL)))
- /* Treat signals as disconnect */
- return -EHOSTUNREACH;
-
- /* Check what happened */
- if (self->errno)
- {
- /* Requested object/attribute doesn't exist */
- if((self->errno == IAS_CLASS_UNKNOWN) ||
- (self->errno == IAS_ATTRIB_UNKNOWN))
- return -EADDRNOTAVAIL;
- else
- return -EHOSTUNREACH;
- }
-
- /* Get the remote TSAP selector */
- switch (self->ias_result->type) {
- case IAS_INTEGER:
- pr_debug("%s() int=%d\n",
- __func__, self->ias_result->t.integer);
-
- if (self->ias_result->t.integer != -1)
- self->dtsap_sel = self->ias_result->t.integer;
- else
- self->dtsap_sel = 0;
- break;
- default:
- self->dtsap_sel = 0;
- pr_debug("%s(), bad type!\n", __func__);
- break;
- }
- if (self->ias_result)
- irias_delete_value(self->ias_result);
-
- if (self->dtsap_sel)
- return 0;
-
- return -EADDRNOTAVAIL;
-}
-
-/*
- * Function irda_discover_daddr_and_lsap_sel (self, name)
- *
- * This try to find a device with the requested service.
- *
- * It basically look into the discovery log. For each address in the list,
- * it queries the LM-IAS of the device to find if this device offer
- * the requested service.
- * If there is more than one node supporting the service, we complain
- * to the user (it should move devices around).
- * The, we set both the destination address and the lsap selector to point
- * on the service on the unique device we have found.
- *
- * Note : this function fails if there is more than one device in range,
- * because IrLMP doesn't disconnect the LAP when the last LSAP is closed.
- * Moreover, we would need to wait the LAP disconnection...
- */
-static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
-{
- discinfo_t *discoveries; /* Copy of the discovery log */
- int number; /* Number of nodes in the log */
- int i;
- int err = -ENETUNREACH;
- __u32 daddr = DEV_ADDR_ANY; /* Address we found the service on */
- __u8 dtsap_sel = 0x0; /* TSAP associated with it */
-
- pr_debug("%s(), name=%s\n", __func__, name);
-
- /* Ask lmp for the current discovery log
- * Note : we have to use irlmp_get_discoveries(), as opposed
- * to play with the cachelog directly, because while we are
- * making our ias query, le log might change... */
- discoveries = irlmp_get_discoveries(&number, self->mask.word,
- self->nslots);
- /* Check if the we got some results */
- if (discoveries == NULL)
- return -ENETUNREACH; /* No nodes discovered */
-
- /*
- * Now, check all discovered devices (if any), and connect
- * client only about the services that the client is
- * interested in...
- */
- for(i = 0; i < number; i++) {
- /* Try the address in the log */
- self->daddr = discoveries[i].daddr;
- self->saddr = 0x0;
- pr_debug("%s(), trying daddr = %08x\n",
- __func__, self->daddr);
-
- /* Query remote LM-IAS for this service */
- err = irda_find_lsap_sel(self, name);
- switch (err) {
- case 0:
- /* We found the requested service */
- if(daddr != DEV_ADDR_ANY) {
- pr_debug("%s(), discovered service ''%s'' in two different devices !!!\n",
- __func__, name);
- self->daddr = DEV_ADDR_ANY;
- kfree(discoveries);
- return -ENOTUNIQ;
- }
- /* First time we found that one, save it ! */
- daddr = self->daddr;
- dtsap_sel = self->dtsap_sel;
- break;
- case -EADDRNOTAVAIL:
- /* Requested service simply doesn't exist on this node */
- break;
- default:
- /* Something bad did happen :-( */
- pr_debug("%s(), unexpected IAS query failure\n",
- __func__);
- self->daddr = DEV_ADDR_ANY;
- kfree(discoveries);
- return -EHOSTUNREACH;
- }
- }
- /* Cleanup our copy of the discovery log */
- kfree(discoveries);
-
- /* Check out what we found */
- if(daddr == DEV_ADDR_ANY) {
- pr_debug("%s(), cannot discover service ''%s'' in any device !!!\n",
- __func__, name);
- self->daddr = DEV_ADDR_ANY;
- return -EADDRNOTAVAIL;
- }
-
- /* Revert back to discovered device & service */
- self->daddr = daddr;
- self->saddr = 0x0;
- self->dtsap_sel = dtsap_sel;
-
- pr_debug("%s(), discovered requested service ''%s'' at address %08x\n",
- __func__, name, self->daddr);
-
- return 0;
-}
-
-/*
- * Function irda_getname (sock, uaddr, uaddr_len, peer)
- *
- * Return the our own, or peers socket address (sockaddr_irda)
- *
- */
-static int irda_getname(struct socket *sock, struct sockaddr *uaddr,
- int peer)
-{
- struct sockaddr_irda saddr;
- struct sock *sk = sock->sk;
- struct irda_sock *self = irda_sk(sk);
-
- memset(&saddr, 0, sizeof(saddr));
- if (peer) {
- if (sk->sk_state != TCP_ESTABLISHED)
- return -ENOTCONN;
-
- saddr.sir_family = AF_IRDA;
- saddr.sir_lsap_sel = self->dtsap_sel;
- saddr.sir_addr = self->daddr;
- } else {
- saddr.sir_family = AF_IRDA;
- saddr.sir_lsap_sel = self->stsap_sel;
- saddr.sir_addr = self->saddr;
- }
-
- pr_debug("%s(), tsap_sel = %#x\n", __func__, saddr.sir_lsap_sel);
- pr_debug("%s(), addr = %08x\n", __func__, saddr.sir_addr);
-
- memcpy(uaddr, &saddr, sizeof (struct sockaddr_irda));
-
- return sizeof (struct sockaddr_irda);
-}
-
-/*
- * Function irda_listen (sock, backlog)
- *
- * Just move to the listen state
- *
- */
-static int irda_listen(struct socket *sock, int backlog)
-{
- struct sock *sk = sock->sk;
- int err = -EOPNOTSUPP;
-
- lock_sock(sk);
-
- if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) &&
- (sk->sk_type != SOCK_DGRAM))
- goto out;
-
- if (sk->sk_state != TCP_LISTEN) {
- sk->sk_max_ack_backlog = backlog;
- sk->sk_state = TCP_LISTEN;
-
- err = 0;
- }
-out:
- release_sock(sk);
-
- return err;
-}
-
-/*
- * Function irda_bind (sock, uaddr, addr_len)
- *
- * Used by servers to register their well known TSAP
- *
- */
-static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
-{
- struct sock *sk = sock->sk;
- struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr;
- struct irda_sock *self = irda_sk(sk);
- int err;
-
- pr_debug("%s(%p)\n", __func__, self);
-
- if (addr_len != sizeof(struct sockaddr_irda))
- return -EINVAL;
-
- lock_sock(sk);
-#ifdef CONFIG_IRDA_ULTRA
- /* Special care for Ultra sockets */
- if ((sk->sk_type == SOCK_DGRAM) &&
- (sk->sk_protocol == IRDAPROTO_ULTRA)) {
- self->pid = addr->sir_lsap_sel;
- err = -EOPNOTSUPP;
- if (self->pid & 0x80) {
- pr_debug("%s(), extension in PID not supp!\n",
- __func__);
- goto out;
- }
- err = irda_open_lsap(self, self->pid);
- if (err < 0)
- goto out;
-
- /* Pretend we are connected */
- sock->state = SS_CONNECTED;
- sk->sk_state = TCP_ESTABLISHED;
- err = 0;
-
- goto out;
- }
-#endif /* CONFIG_IRDA_ULTRA */
-
- self->ias_obj = irias_new_object(addr->sir_name, jiffies);
- err = -ENOMEM;
- if (self->ias_obj == NULL)
- goto out;
-
- err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name);
- if (err < 0) {
- irias_delete_object(self->ias_obj);
- self->ias_obj = NULL;
- goto out;
- }
-
- /* Register with LM-IAS */
- irias_add_integer_attrib(self->ias_obj, "IrDA:TinyTP:LsapSel",
- self->stsap_sel, IAS_KERNEL_ATTR);
- irias_insert_object(self->ias_obj);
-
- err = 0;
-out:
- release_sock(sk);
- return err;
-}
-
-/*
- * Function irda_accept (sock, newsock, flags)
- *
- * Wait for incoming connection
- *
- */
-static int irda_accept(struct socket *sock, struct socket *newsock, int flags,
- bool kern)
-{
- struct sock *sk = sock->sk;
- struct irda_sock *new, *self = irda_sk(sk);
- struct sock *newsk;
- struct sk_buff *skb = NULL;
- int err;
-
- err = irda_create(sock_net(sk), newsock, sk->sk_protocol, kern);
- if (err)
- return err;
-
- err = -EINVAL;
-
- lock_sock(sk);
- if (sock->state != SS_UNCONNECTED)
- goto out;
-
- err = -EOPNOTSUPP;
- if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) &&
- (sk->sk_type != SOCK_DGRAM))
- goto out;
-
- err = -EINVAL;
- if (sk->sk_state != TCP_LISTEN)
- goto out;
-
- /*
- * The read queue this time is holding sockets ready to use
- * hooked into the SABM we saved
- */
-
- /*
- * We can perform the accept only if there is incoming data
- * on the listening socket.
- * So, we will block the caller until we receive any data.
- * If the caller was waiting on select() or poll() before
- * calling us, the data is waiting for us ;-)
- * Jean II
- */
- while (1) {
- skb = skb_dequeue(&sk->sk_receive_queue);
- if (skb)
- break;
-
- /* Non blocking operation */
- err = -EWOULDBLOCK;
- if (flags & O_NONBLOCK)
- goto out;
-
- err = wait_event_interruptible(*(sk_sleep(sk)),
- skb_peek(&sk->sk_receive_queue));
- if (err)
- goto out;
- }
-
- newsk = newsock->sk;
- err = -EIO;
- if (newsk == NULL)
- goto out;
-
- newsk->sk_state = TCP_ESTABLISHED;
-
- new = irda_sk(newsk);
-
- /* Now attach up the new socket */
- new->tsap = irttp_dup(self->tsap, new);
- err = -EPERM; /* value does not seem to make sense. -arnd */
- if (!new->tsap) {
- pr_debug("%s(), dup failed!\n", __func__);
- goto out;
- }
-
- new->stsap_sel = new->tsap->stsap_sel;
- new->dtsap_sel = new->tsap->dtsap_sel;
- new->saddr = irttp_get_saddr(new->tsap);
- new->daddr = irttp_get_daddr(new->tsap);
-
- new->max_sdu_size_tx = self->max_sdu_size_tx;
- new->max_sdu_size_rx = self->max_sdu_size_rx;
- new->max_data_size = self->max_data_size;
- new->max_header_size = self->max_header_size;
-
- memcpy(&new->qos_tx, &self->qos_tx, sizeof(struct qos_info));
-
- /* Clean up the original one to keep it in listen state */
- irttp_listen(self->tsap);
-
- sk->sk_ack_backlog--;
-
- newsock->state = SS_CONNECTED;
-
- irda_connect_response(new);
- err = 0;
-out:
- kfree_skb(skb);
- release_sock(sk);
- return err;
-}
-
-/*
- * Function irda_connect (sock, uaddr, addr_len, flags)
- *
- * Connect to a IrDA device
- *
- * The main difference with a "standard" connect is that with IrDA we need
- * to resolve the service name into a TSAP selector (in TCP, port number
- * doesn't have to be resolved).
- * Because of this service name resolution, we can offer "auto-connect",
- * where we connect to a service without specifying a destination address.
- *
- * Note : by consulting "errno", the user space caller may learn the cause
- * of the failure. Most of them are visible in the function, others may come
- * from subroutines called and are listed here :
- * o EBUSY : already processing a connect
- * o EHOSTUNREACH : bad addr->sir_addr argument
- * o EADDRNOTAVAIL : bad addr->sir_name argument
- * o ENOTUNIQ : more than one node has addr->sir_name (auto-connect)
- * o ENETUNREACH : no node found on the network (auto-connect)
- */
-static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
- int addr_len, int flags)
-{
- struct sock *sk = sock->sk;
- struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr;
- struct irda_sock *self = irda_sk(sk);
- int err;
-
- pr_debug("%s(%p)\n", __func__, self);
-
- lock_sock(sk);
- /* Don't allow connect for Ultra sockets */
- err = -ESOCKTNOSUPPORT;
- if ((sk->sk_type == SOCK_DGRAM) && (sk->sk_protocol == IRDAPROTO_ULTRA))
- goto out;
-
- if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
- sock->state = SS_CONNECTED;
- err = 0;
- goto out; /* Connect completed during a ERESTARTSYS event */
- }
-
- if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) {
- sock->state = SS_UNCONNECTED;
- err = -ECONNREFUSED;
- goto out;
- }
-
- err = -EISCONN; /* No reconnect on a seqpacket socket */
- if (sk->sk_state == TCP_ESTABLISHED)
- goto out;
-
- sk->sk_state = TCP_CLOSE;
- sock->state = SS_UNCONNECTED;
-
- err = -EINVAL;
- if (addr_len != sizeof(struct sockaddr_irda))
- goto out;
-
- /* Check if user supplied any destination device address */
- if ((!addr->sir_addr) || (addr->sir_addr == DEV_ADDR_ANY)) {
- /* Try to find one suitable */
- err = irda_discover_daddr_and_lsap_sel(self, addr->sir_name);
- if (err) {
- pr_debug("%s(), auto-connect failed!\n", __func__);
- goto out;
- }
- } else {
- /* Use the one provided by the user */
- self->daddr = addr->sir_addr;
- pr_debug("%s(), daddr = %08x\n", __func__, self->daddr);
-
- /* If we don't have a valid service name, we assume the
- * user want to connect on a specific LSAP. Prevent
- * the use of invalid LSAPs (IrLMP 1.1 p10). Jean II */
- if((addr->sir_name[0] != '\0') ||
- (addr->sir_lsap_sel >= 0x70)) {
- /* Query remote LM-IAS using service name */
- err = irda_find_lsap_sel(self, addr->sir_name);
- if (err) {
- pr_debug("%s(), connect failed!\n", __func__);
- goto out;
- }
- } else {
- /* Directly connect to the remote LSAP
- * specified by the sir_lsap field.
- * Please use with caution, in IrDA LSAPs are
- * dynamic and there is no "well-known" LSAP. */
- self->dtsap_sel = addr->sir_lsap_sel;
- }
- }
-
- /* Check if we have opened a local TSAP */
- if (!self->tsap) {
- err = irda_open_tsap(self, LSAP_ANY, addr->sir_name);
- if (err)
- goto out;
- }
-
- /* Move to connecting socket, start sending Connect Requests */
- sock->state = SS_CONNECTING;
- sk->sk_state = TCP_SYN_SENT;
-
- /* Connect to remote device */
- err = irttp_connect_request(self->tsap, self->dtsap_sel,
- self->saddr, self->daddr, NULL,
- self->max_sdu_size_rx, NULL);
- if (err) {
- pr_debug("%s(), connect failed!\n", __func__);
- goto out;
- }
-
- /* Now the loop */
- err = -EINPROGRESS;
- if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
- goto out;
-
- err = -ERESTARTSYS;
- if (wait_event_interruptible(*(sk_sleep(sk)),
- (sk->sk_state != TCP_SYN_SENT)))
- goto out;
-
- if (sk->sk_state != TCP_ESTABLISHED) {
- sock->state = SS_UNCONNECTED;
- err = sock_error(sk);
- if (!err)
- err = -ECONNRESET;
- goto out;
- }
-
- sock->state = SS_CONNECTED;
-
- /* At this point, IrLMP has assigned our source address */
- self->saddr = irttp_get_saddr(self->tsap);
- err = 0;
-out:
- release_sock(sk);
- return err;
-}
-
-static struct proto irda_proto = {
- .name = "IRDA",
- .owner = THIS_MODULE,
- .obj_size = sizeof(struct irda_sock),
-};
-
-/*
- * Function irda_create (sock, protocol)
- *
- * Create IrDA socket
- *
- */
-static int irda_create(struct net *net, struct socket *sock, int protocol,
- int kern)
-{
- struct sock *sk;
- struct irda_sock *self;
-
- if (protocol < 0 || protocol > SK_PROTOCOL_MAX)
- return -EINVAL;
-
- if (net != &init_net)
- return -EAFNOSUPPORT;
-
- /* Check for valid socket type */
- switch (sock->type) {
- case SOCK_STREAM: /* For TTP connections with SAR disabled */
- case SOCK_SEQPACKET: /* For TTP connections with SAR enabled */
- case SOCK_DGRAM: /* For TTP Unitdata or LMP Ultra transfers */
- break;
- default:
- return -ESOCKTNOSUPPORT;
- }
-
- /* Allocate networking socket */
- sk = sk_alloc(net, PF_IRDA, GFP_KERNEL, &irda_proto, kern);
- if (sk == NULL)
- return -ENOMEM;
-
- self = irda_sk(sk);
- pr_debug("%s() : self is %p\n", __func__, self);
-
- init_waitqueue_head(&self->query_wait);
-
- switch (sock->type) {
- case SOCK_STREAM:
- sock->ops = &irda_stream_ops;
- self->max_sdu_size_rx = TTP_SAR_DISABLE;
- break;
- case SOCK_SEQPACKET:
- sock->ops = &irda_seqpacket_ops;
- self->max_sdu_size_rx = TTP_SAR_UNBOUND;
- break;
- case SOCK_DGRAM:
- switch (protocol) {
-#ifdef CONFIG_IRDA_ULTRA
- case IRDAPROTO_ULTRA:
- sock->ops = &irda_ultra_ops;
- /* Initialise now, because we may send on unbound
- * sockets. Jean II */
- self->max_data_size = ULTRA_MAX_DATA - LMP_PID_HEADER;
- self->max_header_size = IRDA_MAX_HEADER + LMP_PID_HEADER;
- break;
-#endif /* CONFIG_IRDA_ULTRA */
- case IRDAPROTO_UNITDATA:
- sock->ops = &irda_dgram_ops;
- /* We let Unitdata conn. be like seqpack conn. */
- self->max_sdu_size_rx = TTP_SAR_UNBOUND;
- break;
- default:
- sk_free(sk);
- return -ESOCKTNOSUPPORT;
- }
- break;
- default:
- sk_free(sk);
- return -ESOCKTNOSUPPORT;
- }
-
- /* Initialise networking socket struct */
- sock_init_data(sock, sk); /* Note : set sk->sk_refcnt to 1 */
- sk->sk_family = PF_IRDA;
- sk->sk_protocol = protocol;
-
- /* Register as a client with IrLMP */
- self->ckey = irlmp_register_client(0, NULL, NULL, NULL);
- self->mask.word = 0xffff;
- self->rx_flow = self->tx_flow = FLOW_START;
- self->nslots = DISCOVERY_DEFAULT_SLOTS;
- self->daddr = DEV_ADDR_ANY; /* Until we get connected */
- self->saddr = 0x0; /* so IrLMP assign us any link */
- return 0;
-}
-
-/*
- * Function irda_destroy_socket (self)
- *
- * Destroy socket
- *
- */
-static void irda_destroy_socket(struct irda_sock *self)
-{
- pr_debug("%s(%p)\n", __func__, self);
-
- /* Unregister with IrLMP */
- irlmp_unregister_client(self->ckey);
- irlmp_unregister_service(self->skey);
-
- /* Unregister with LM-IAS */
- if (self->ias_obj) {
- irias_delete_object(self->ias_obj);
- self->ias_obj = NULL;
- }
-
- if (self->iriap) {
- iriap_close(self->iriap);
- self->iriap = NULL;
- }
-
- if (self->tsap) {
- irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
- irttp_close_tsap(self->tsap);
- self->tsap = NULL;
- }
-#ifdef CONFIG_IRDA_ULTRA
- if (self->lsap) {
- irlmp_close_lsap(self->lsap);
- self->lsap = NULL;
- }
-#endif /* CONFIG_IRDA_ULTRA */
-}
-
-/*
- * Function irda_release (sock)
- */
-static int irda_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- if (sk == NULL)
- return 0;
-
- lock_sock(sk);
- sk->sk_state = TCP_CLOSE;
- sk->sk_shutdown |= SEND_SHUTDOWN;
- sk->sk_state_change(sk);
-
- /* Destroy IrDA socket */
- irda_destroy_socket(irda_sk(sk));
-
- sock_orphan(sk);
- sock->sk = NULL;
- release_sock(sk);
-
- /* Purge queues (see sock_init_data()) */
- skb_queue_purge(&sk->sk_receive_queue);
-
- /* Destroy networking socket if we are the last reference on it,
- * i.e. if(sk->sk_refcnt == 0) -> sk_free(sk) */
- sock_put(sk);
-
- /* Notes on socket locking and deallocation... - Jean II
- * In theory we should put pairs of sock_hold() / sock_put() to
- * prevent the socket to be destroyed whenever there is an
- * outstanding request or outstanding incoming packet or event.
- *
- * 1) This may include IAS request, both in connect and getsockopt.
- * Unfortunately, the situation is a bit more messy than it looks,
- * because we close iriap and kfree(self) above.
- *
- * 2) This may include selective discovery in getsockopt.
- * Same stuff as above, irlmp registration and self are gone.
- *
- * Probably 1 and 2 may not matter, because it's all triggered
- * by a process and the socket layer already prevent the
- * socket to go away while a process is holding it, through
- * sockfd_put() and fput()...
- *
- * 3) This may include deferred TSAP closure. In particular,
- * we may receive a late irda_disconnect_indication()
- * Fortunately, (tsap_cb *)->close_pend should protect us
- * from that.
- *
- * I did some testing on SMP, and it looks solid. And the socket
- * memory leak is now gone... - Jean II
- */
-
- return 0;
-}
-
-/*
- * Function irda_sendmsg (sock, msg, len)
- *
- * Send message down to TinyTP. This function is used for both STREAM and
- * SEQPACK services. This is possible since it forces the client to
- * fragment the message if necessary
- */
-static int irda_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
-{
- struct sock *sk = sock->sk;
- struct irda_sock *self;
- struct sk_buff *skb;
- int err = -EPIPE;
-
- pr_debug("%s(), len=%zd\n", __func__, len);
-
- /* Note : socket.c set MSG_EOR on SEQPACKET sockets */
- if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT |
- MSG_NOSIGNAL)) {
- return -EINVAL;
- }
-
- lock_sock(sk);
-
- if (sk->sk_shutdown & SEND_SHUTDOWN)
- goto out_err;
-
- if (sk->sk_state != TCP_ESTABLISHED) {
- err = -ENOTCONN;
- goto out;
- }
-
- self = irda_sk(sk);
-
- /* Check if IrTTP is wants us to slow down */
-
- if (wait_event_interruptible(*(sk_sleep(sk)),
- (self->tx_flow != FLOW_STOP || sk->sk_state != TCP_ESTABLISHED))) {
- err = -ERESTARTSYS;
- goto out;
- }
-
- /* Check if we are still connected */
- if (sk->sk_state != TCP_ESTABLISHED) {
- err = -ENOTCONN;
- goto out;
- }
-
- /* Check that we don't send out too big frames */
- if (len > self->max_data_size) {
- pr_debug("%s(), Chopping frame from %zd to %d bytes!\n",
- __func__, len, self->max_data_size);
- len = self->max_data_size;
- }
-
- skb = sock_alloc_send_skb(sk, len + self->max_header_size + 16,
- msg->msg_flags & MSG_DONTWAIT, &err);
- if (!skb)
- goto out_err;
-
- skb_reserve(skb, self->max_header_size + 16);
- skb_reset_transport_header(skb);
- skb_put(skb, len);
- err = memcpy_from_msg(skb_transport_header(skb), msg, len);
- if (err) {
- kfree_skb(skb);
- goto out_err;
- }
-
- /*
- * Just send the message to TinyTP, and let it deal with possible
- * errors. No need to duplicate all that here
- */
- err = irttp_data_request(self->tsap, skb);
- if (err) {
- pr_debug("%s(), err=%d\n", __func__, err);
- goto out_err;
- }
-
- release_sock(sk);
- /* Tell client how much data we actually sent */
- return len;
-
-out_err:
- err = sk_stream_error(sk, msg->msg_flags, err);
-out:
- release_sock(sk);
- return err;
-
-}
-
-/*
- * Function irda_recvmsg_dgram (sock, msg, size, flags)
- *
- * Try to receive message and copy it to user. The frame is discarded
- * after being read, regardless of how much the user actually read
- */
-static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg,
- size_t size, int flags)
-{
- struct sock *sk = sock->sk;
- struct irda_sock *self = irda_sk(sk);
- struct sk_buff *skb;
- size_t copied;
- int err;
-
- skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
- flags & MSG_DONTWAIT, &err);
- if (!skb)
- return err;
-
- skb_reset_transport_header(skb);
- copied = skb->len;
-
- if (copied > size) {
- pr_debug("%s(), Received truncated frame (%zd < %zd)!\n",
- __func__, copied, size);
- copied = size;
- msg->msg_flags |= MSG_TRUNC;
- }
- skb_copy_datagram_msg(skb, 0, msg, copied);
-
- skb_free_datagram(sk, skb);
-
- /*
- * Check if we have previously stopped IrTTP and we know
- * have more free space in our rx_queue. If so tell IrTTP
- * to start delivering frames again before our rx_queue gets
- * empty
- */
- if (self->rx_flow == FLOW_STOP) {
- if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) {
- pr_debug("%s(), Starting IrTTP\n", __func__);
- self->rx_flow = FLOW_START;
- irttp_flow_request(self->tsap, FLOW_START);
- }
- }
-
- return copied;
-}
-
-/*
- * Function irda_recvmsg_stream (sock, msg, size, flags)
- */
-static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg,
- size_t size, int flags)
-{
- struct sock *sk = sock->sk;
- struct irda_sock *self = irda_sk(sk);
- int noblock = flags & MSG_DONTWAIT;
- size_t copied = 0;
- int target, err;
- long timeo;
-
- if ((err = sock_error(sk)) < 0)
- return err;
-
- if (sock->flags & __SO_ACCEPTCON)
- return -EINVAL;
-
- err =-EOPNOTSUPP;
- if (flags & MSG_OOB)
- return -EOPNOTSUPP;
-
- err = 0;
- target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
- timeo = sock_rcvtimeo(sk, noblock);
-
- do {
- int chunk;
- struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue);
-
- if (skb == NULL) {
- DEFINE_WAIT(wait);
- err = 0;
-
- if (copied >= target)
- break;
-
- prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
-
- /*
- * POSIX 1003.1g mandates this order.
- */
- err = sock_error(sk);
- if (err)
- ;
- else if (sk->sk_shutdown & RCV_SHUTDOWN)
- ;
- else if (noblock)
- err = -EAGAIN;
- else if (signal_pending(current))
- err = sock_intr_errno(timeo);
- else if (sk->sk_state != TCP_ESTABLISHED)
- err = -ENOTCONN;
- else if (skb_peek(&sk->sk_receive_queue) == NULL)
- /* Wait process until data arrives */
- schedule();
-
- finish_wait(sk_sleep(sk), &wait);
-
- if (err)
- return err;
- if (sk->sk_shutdown & RCV_SHUTDOWN)
- break;
-
- continue;
- }
-
- chunk = min_t(unsigned int, skb->len, size);
- if (memcpy_to_msg(msg, skb->data, chunk)) {
- skb_queue_head(&sk->sk_receive_queue, skb);
- if (copied == 0)
- copied = -EFAULT;
- break;
- }
- copied += chunk;
- size -= chunk;
-
- /* Mark read part of skb as used */
- if (!(flags & MSG_PEEK)) {
- skb_pull(skb, chunk);
-
- /* put the skb back if we didn't use it up.. */
- if (skb->len) {
- pr_debug("%s(), back on q!\n",
- __func__);
- skb_queue_head(&sk->sk_receive_queue, skb);
- break;
- }
-
- kfree_skb(skb);
- } else {
- pr_debug("%s() questionable!?\n", __func__);
-
- /* put message back and return */
- skb_queue_head(&sk->sk_receive_queue, skb);
- break;
- }
- } while (size);
-
- /*
- * Check if we have previously stopped IrTTP and we know
- * have more free space in our rx_queue. If so tell IrTTP
- * to start delivering frames again before our rx_queue gets
- * empty
- */
- if (self->rx_flow == FLOW_STOP) {
- if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) {
- pr_debug("%s(), Starting IrTTP\n", __func__);
- self->rx_flow = FLOW_START;
- irttp_flow_request(self->tsap, FLOW_START);
- }
- }
-
- return copied;
-}
-
-/*
- * Function irda_sendmsg_dgram (sock, msg, len)
- *
- * Send message down to TinyTP for the unreliable sequenced
- * packet service...
- *
- */
-static int irda_sendmsg_dgram(struct socket *sock, struct msghdr *msg,
- size_t len)
-{
- struct sock *sk = sock->sk;
- struct irda_sock *self;
- struct sk_buff *skb;
- int err;
-
- pr_debug("%s(), len=%zd\n", __func__, len);
-
- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
- return -EINVAL;
-
- lock_sock(sk);
-
- if (sk->sk_shutdown & SEND_SHUTDOWN) {
- send_sig(SIGPIPE, current, 0);
- err = -EPIPE;
- goto out;
- }
-
- err = -ENOTCONN;
- if (sk->sk_state != TCP_ESTABLISHED)
- goto out;
-
- self = irda_sk(sk);
-
- /*
- * Check that we don't send out too big frames. This is an unreliable
- * service, so we have no fragmentation and no coalescence
- */
- if (len > self->max_data_size) {
- pr_debug("%s(), Warning too much data! Chopping frame from %zd to %d bytes!\n",
- __func__, len, self->max_data_size);
- len = self->max_data_size;
- }
-
- skb = sock_alloc_send_skb(sk, len + self->max_header_size,
- msg->msg_flags & MSG_DONTWAIT, &err);
- err = -ENOBUFS;
- if (!skb)
- goto out;
-
- skb_reserve(skb, self->max_header_size);
- skb_reset_transport_header(skb);
-
- pr_debug("%s(), appending user data\n", __func__);
- skb_put(skb, len);
- err = memcpy_from_msg(skb_transport_header(skb), msg, len);
- if (err) {
- kfree_skb(skb);
- goto out;
- }
-
- /*
- * Just send the message to TinyTP, and let it deal with possible
- * errors. No need to duplicate all that here
- */
- err = irttp_udata_request(self->tsap, skb);
- if (err) {
- pr_debug("%s(), err=%d\n", __func__, err);
- goto out;
- }
-
- release_sock(sk);
- return len;
-
-out:
- release_sock(sk);
- return err;
-}
-
-/*
- * Function irda_sendmsg_ultra (sock, msg, len)
- *
- * Send message down to IrLMP for the unreliable Ultra
- * packet service...
- */
-#ifdef CONFIG_IRDA_ULTRA
-static int irda_sendmsg_ultra(struct socket *sock, struct msghdr *msg,
- size_t len)
-{
- struct sock *sk = sock->sk;
- struct irda_sock *self;
- __u8 pid = 0;
- int bound = 0;
- struct sk_buff *skb;
- int err;
-
- pr_debug("%s(), len=%zd\n", __func__, len);
-
- err = -EINVAL;
- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
- return -EINVAL;
-
- lock_sock(sk);
-
- err = -EPIPE;
- if (sk->sk_shutdown & SEND_SHUTDOWN) {
- send_sig(SIGPIPE, current, 0);
- goto out;
- }
-
- self = irda_sk(sk);
-
- /* Check if an address was specified with sendto. Jean II */
- if (msg->msg_name) {
- DECLARE_SOCKADDR(struct sockaddr_irda *, addr, msg->msg_name);
- err = -EINVAL;
- /* Check address, extract pid. Jean II */
- if (msg->msg_namelen < sizeof(*addr))
- goto out;
- if (addr->sir_family != AF_IRDA)
- goto out;
-
- pid = addr->sir_lsap_sel;
- if (pid & 0x80) {
- pr_debug("%s(), extension in PID not supp!\n",
- __func__);
- err = -EOPNOTSUPP;
- goto out;
- }
- } else {
- /* Check that the socket is properly bound to an Ultra
- * port. Jean II */
- if ((self->lsap == NULL) ||
- (sk->sk_state != TCP_ESTABLISHED)) {
- pr_debug("%s(), socket not bound to Ultra PID.\n",
- __func__);
- err = -ENOTCONN;
- goto out;
- }
- /* Use PID from socket */
- bound = 1;
- }
-
- /*
- * Check that we don't send out too big frames. This is an unreliable
- * service, so we have no fragmentation and no coalescence
- */
- if (len > self->max_data_size) {
- pr_debug("%s(), Warning too much data! Chopping frame from %zd to %d bytes!\n",
- __func__, len, self->max_data_size);
- len = self->max_data_size;
- }
-
- skb = sock_alloc_send_skb(sk, len + self->max_header_size,
- msg->msg_flags & MSG_DONTWAIT, &err);
- err = -ENOBUFS;
- if (!skb)
- goto out;
-
- skb_reserve(skb, self->max_header_size);
- skb_reset_transport_header(skb);
-
- pr_debug("%s(), appending user data\n", __func__);
- skb_put(skb, len);
- err = memcpy_from_msg(skb_transport_header(skb), msg, len);
- if (err) {
- kfree_skb(skb);
- goto out;
- }
-
- err = irlmp_connless_data_request((bound ? self->lsap : NULL),
- skb, pid);
- if (err)
- pr_debug("%s(), err=%d\n", __func__, err);
-out:
- release_sock(sk);
- return err ? : len;
-}
-#endif /* CONFIG_IRDA_ULTRA */
-
-/*
- * Function irda_shutdown (sk, how)
- */
-static int irda_shutdown(struct socket *sock, int how)
-{
- struct sock *sk = sock->sk;
- struct irda_sock *self = irda_sk(sk);
-
- pr_debug("%s(%p)\n", __func__, self);
-
- lock_sock(sk);
-
- sk->sk_state = TCP_CLOSE;
- sk->sk_shutdown |= SEND_SHUTDOWN;
- sk->sk_state_change(sk);
-
- if (self->iriap) {
- iriap_close(self->iriap);
- self->iriap = NULL;
- }
-
- if (self->tsap) {
- irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
- irttp_close_tsap(self->tsap);
- self->tsap = NULL;
- }
-
- /* A few cleanup so the socket look as good as new... */
- self->rx_flow = self->tx_flow = FLOW_START; /* needed ??? */
- self->daddr = DEV_ADDR_ANY; /* Until we get re-connected */
- self->saddr = 0x0; /* so IrLMP assign us any link */
-
- release_sock(sk);
-
- return 0;
-}
-
-/*
- * Function irda_poll (file, sock, wait)
- */
-static __poll_t irda_poll(struct file * file, struct socket *sock,
- poll_table *wait)
-{
- struct sock *sk = sock->sk;
- struct irda_sock *self = irda_sk(sk);
- __poll_t mask;
-
- poll_wait(file, sk_sleep(sk), wait);
- mask = 0;
-
- /* Exceptional events? */
- if (sk->sk_err)
- mask |= EPOLLERR;
- if (sk->sk_shutdown & RCV_SHUTDOWN) {
- pr_debug("%s(), POLLHUP\n", __func__);
- mask |= EPOLLHUP;
- }
-
- /* Readable? */
- if (!skb_queue_empty(&sk->sk_receive_queue)) {
- pr_debug("Socket is readable\n");
- mask |= EPOLLIN | EPOLLRDNORM;
- }
-
- /* Connection-based need to check for termination and startup */
- switch (sk->sk_type) {
- case SOCK_STREAM:
- if (sk->sk_state == TCP_CLOSE) {
- pr_debug("%s(), POLLHUP\n", __func__);
- mask |= EPOLLHUP;
- }
-
- if (sk->sk_state == TCP_ESTABLISHED) {
- if ((self->tx_flow == FLOW_START) &&
- sock_writeable(sk))
- {
- mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
- }
- }
- break;
- case SOCK_SEQPACKET:
- if ((self->tx_flow == FLOW_START) &&
- sock_writeable(sk))
- {
- mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
- }
- break;
- case SOCK_DGRAM:
- if (sock_writeable(sk))
- mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
- break;
- default:
- break;
- }
-
- return mask;
-}
-
-/*
- * Function irda_ioctl (sock, cmd, arg)
- */
-static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct sock *sk = sock->sk;
- int err;
-
- pr_debug("%s(), cmd=%#x\n", __func__, cmd);
-
- err = -EINVAL;
- switch (cmd) {
- case TIOCOUTQ: {
- long amount;
-
- amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
- if (amount < 0)
- amount = 0;
- err = put_user(amount, (unsigned int __user *)arg);
- break;
- }
-
- case TIOCINQ: {
- struct sk_buff *skb;
- long amount = 0L;
- /* These two are safe on a single CPU system as only user tasks fiddle here */
- if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
- amount = skb->len;
- err = put_user(amount, (unsigned int __user *)arg);
- break;
- }
-
- case SIOCGSTAMP:
- if (sk != NULL)
- err = sock_get_timestamp(sk, (struct timeval __user *)arg);
- break;
-
- case SIOCGIFADDR:
- case SIOCSIFADDR:
- case SIOCGIFDSTADDR:
- case SIOCSIFDSTADDR:
- case SIOCGIFBRDADDR:
- case SIOCSIFBRDADDR:
- case SIOCGIFNETMASK:
- case SIOCSIFNETMASK:
- case SIOCGIFMETRIC:
- case SIOCSIFMETRIC:
- break;
- default:
- pr_debug("%s(), doing device ioctl!\n", __func__);
- err = -ENOIOCTLCMD;
- }
-
- return err;
-}
-
-#ifdef CONFIG_COMPAT
-/*
- * Function irda_ioctl (sock, cmd, arg)
- */
-static int irda_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- /*
- * All IRDA's ioctl are standard ones.
- */
- return -ENOIOCTLCMD;
-}
-#endif
-
-/*
- * Function irda_setsockopt (sock, level, optname, optval, optlen)
- *
- * Set some options for the socket
- *
- */
-static int irda_setsockopt(struct socket *sock, int level, int optname,
- char __user *optval, unsigned int optlen)
-{
- struct sock *sk = sock->sk;
- struct irda_sock *self = irda_sk(sk);
- struct irda_ias_set *ias_opt;
- struct ias_object *ias_obj;
- struct ias_attrib * ias_attr; /* Attribute in IAS object */
- int opt, free_ias = 0, err = 0;
-
- pr_debug("%s(%p)\n", __func__, self);
-
- if (level != SOL_IRLMP)
- return -ENOPROTOOPT;
-
- lock_sock(sk);
-
- switch (optname) {
- case IRLMP_IAS_SET:
- /* The user want to add an attribute to an existing IAS object
- * (in the IAS database) or to create a new object with this
- * attribute.
- * We first query IAS to know if the object exist, and then
- * create the right attribute...
- */
-
- if (optlen != sizeof(struct irda_ias_set)) {
- err = -EINVAL;
- goto out;
- }
-
- /* Copy query to the driver. */
- ias_opt = memdup_user(optval, optlen);
- if (IS_ERR(ias_opt)) {
- err = PTR_ERR(ias_opt);
- goto out;
- }
-
- /* Find the object we target.
- * If the user gives us an empty string, we use the object
- * associated with this socket. This will workaround
- * duplicated class name - Jean II */
- if(ias_opt->irda_class_name[0] == '\0') {
- if(self->ias_obj == NULL) {
- kfree(ias_opt);
- err = -EINVAL;
- goto out;
- }
- ias_obj = self->ias_obj;
- } else
- ias_obj = irias_find_object(ias_opt->irda_class_name);
-
- /* Only ROOT can mess with the global IAS database.
- * Users can only add attributes to the object associated
- * with the socket they own - Jean II */
- if((!capable(CAP_NET_ADMIN)) &&
- ((ias_obj == NULL) || (ias_obj != self->ias_obj))) {
- kfree(ias_opt);
- err = -EPERM;
- goto out;
- }
-
- /* If the object doesn't exist, create it */
- if(ias_obj == (struct ias_object *) NULL) {
- /* Create a new object */
- ias_obj = irias_new_object(ias_opt->irda_class_name,
- jiffies);
- if (ias_obj == NULL) {
- kfree(ias_opt);
- err = -ENOMEM;
- goto out;
- }
- free_ias = 1;
- }
-
- /* Do we have the attribute already ? */
- if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) {
- kfree(ias_opt);
- if (free_ias) {
- kfree(ias_obj->name);
- kfree(ias_obj);
- }
- err = -EINVAL;
- goto out;
- }
-
- /* Look at the type */
- switch(ias_opt->irda_attrib_type) {
- case IAS_INTEGER:
- /* Add an integer attribute */
- irias_add_integer_attrib(
- ias_obj,
- ias_opt->irda_attrib_name,
- ias_opt->attribute.irda_attrib_int,
- IAS_USER_ATTR);
- break;
- case IAS_OCT_SEQ:
- /* Check length */
- if(ias_opt->attribute.irda_attrib_octet_seq.len >
- IAS_MAX_OCTET_STRING) {
- kfree(ias_opt);
- if (free_ias) {
- kfree(ias_obj->name);
- kfree(ias_obj);
- }
-
- err = -EINVAL;
- goto out;
- }
- /* Add an octet sequence attribute */
- irias_add_octseq_attrib(
- ias_obj,
- ias_opt->irda_attrib_name,
- ias_opt->attribute.irda_attrib_octet_seq.octet_seq,
- ias_opt->attribute.irda_attrib_octet_seq.len,
- IAS_USER_ATTR);
- break;
- case IAS_STRING:
- /* Should check charset & co */
- /* Check length */
- /* The length is encoded in a __u8, and
- * IAS_MAX_STRING == 256, so there is no way
- * userspace can pass us a string too large.
- * Jean II */
- /* NULL terminate the string (avoid troubles) */
- ias_opt->attribute.irda_attrib_string.string[ias_opt->attribute.irda_attrib_string.len] = '\0';
- /* Add a string attribute */
- irias_add_string_attrib(
- ias_obj,
- ias_opt->irda_attrib_name,
- ias_opt->attribute.irda_attrib_string.string,
- IAS_USER_ATTR);
- break;
- default :
- kfree(ias_opt);
- if (free_ias) {
- kfree(ias_obj->name);
- kfree(ias_obj);
- }
- err = -EINVAL;
- goto out;
- }
- irias_insert_object(ias_obj);
- kfree(ias_opt);
- break;
- case IRLMP_IAS_DEL:
- /* The user want to delete an object from our local IAS
- * database. We just need to query the IAS, check is the
- * object is not owned by the kernel and delete it.
- */
-
- if (optlen != sizeof(struct irda_ias_set)) {
- err = -EINVAL;
- goto out;
- }
-
- /* Copy query to the driver. */
- ias_opt = memdup_user(optval, optlen);
- if (IS_ERR(ias_opt)) {
- err = PTR_ERR(ias_opt);
- goto out;
- }
-
- /* Find the object we target.
- * If the user gives us an empty string, we use the object
- * associated with this socket. This will workaround
- * duplicated class name - Jean II */
- if(ias_opt->irda_class_name[0] == '\0')
- ias_obj = self->ias_obj;
- else
- ias_obj = irias_find_object(ias_opt->irda_class_name);
- if(ias_obj == (struct ias_object *) NULL) {
- kfree(ias_opt);
- err = -EINVAL;
- goto out;
- }
-
- /* Only ROOT can mess with the global IAS database.
- * Users can only del attributes from the object associated
- * with the socket they own - Jean II */
- if((!capable(CAP_NET_ADMIN)) &&
- ((ias_obj == NULL) || (ias_obj != self->ias_obj))) {
- kfree(ias_opt);
- err = -EPERM;
- goto out;
- }
-
- /* Find the attribute (in the object) we target */
- ias_attr = irias_find_attrib(ias_obj,
- ias_opt->irda_attrib_name);
- if(ias_attr == (struct ias_attrib *) NULL) {
- kfree(ias_opt);
- err = -EINVAL;
- goto out;
- }
-
- /* Check is the user space own the object */
- if(ias_attr->value->owner != IAS_USER_ATTR) {
- pr_debug("%s(), attempting to delete a kernel attribute\n",
- __func__);
- kfree(ias_opt);
- err = -EPERM;
- goto out;
- }
-
- /* Remove the attribute (and maybe the object) */
- irias_delete_attrib(ias_obj, ias_attr, 1);
- kfree(ias_opt);
- break;
- case IRLMP_MAX_SDU_SIZE:
- if (optlen < sizeof(int)) {
- err = -EINVAL;
- goto out;
- }
-
- if (get_user(opt, (int __user *)optval)) {
- err = -EFAULT;
- goto out;
- }
-
- /* Only possible for a seqpacket service (TTP with SAR) */
- if (sk->sk_type != SOCK_SEQPACKET) {
- pr_debug("%s(), setting max_sdu_size = %d\n",
- __func__, opt);
- self->max_sdu_size_rx = opt;
- } else {
- net_warn_ratelimited("%s: not allowed to set MAXSDUSIZE for this socket type!\n",
- __func__);
- err = -ENOPROTOOPT;
- goto out;
- }
- break;
- case IRLMP_HINTS_SET:
- if (optlen < sizeof(int)) {
- err = -EINVAL;
- goto out;
- }
-
- /* The input is really a (__u8 hints[2]), easier as an int */
- if (get_user(opt, (int __user *)optval)) {
- err = -EFAULT;
- goto out;
- }
-
- /* Unregister any old registration */
- irlmp_unregister_service(self->skey);
-
- self->skey = irlmp_register_service((__u16) opt);
- break;
- case IRLMP_HINT_MASK_SET:
- /* As opposed to the previous case which set the hint bits
- * that we advertise, this one set the filter we use when
- * making a discovery (nodes which don't match any hint
- * bit in the mask are not reported).
- */
- if (optlen < sizeof(int)) {
- err = -EINVAL;
- goto out;
- }
-
- /* The input is really a (__u8 hints[2]), easier as an int */
- if (get_user(opt, (int __user *)optval)) {
- err = -EFAULT;
- goto out;
- }
-
- /* Set the new hint mask */
- self->mask.word = (__u16) opt;
- /* Mask out extension bits */
- self->mask.word &= 0x7f7f;
- /* Check if no bits */
- if(!self->mask.word)
- self->mask.word = 0xFFFF;
-
- break;
- default:
- err = -ENOPROTOOPT;
- break;
- }
-
-out:
- release_sock(sk);
-
- return err;
-}
-
-/*
- * Function irda_extract_ias_value(ias_opt, ias_value)
- *
- * Translate internal IAS value structure to the user space representation
- *
- * The external representation of IAS values, as we exchange them with
- * user space program is quite different from the internal representation,
- * as stored in the IAS database (because we need a flat structure for
- * crossing kernel boundary).
- * This function transform the former in the latter. We also check
- * that the value type is valid.
- */
-static int irda_extract_ias_value(struct irda_ias_set *ias_opt,
- struct ias_value *ias_value)
-{
- /* Look at the type */
- switch (ias_value->type) {
- case IAS_INTEGER:
- /* Copy the integer */
- ias_opt->attribute.irda_attrib_int = ias_value->t.integer;
- break;
- case IAS_OCT_SEQ:
- /* Set length */
- ias_opt->attribute.irda_attrib_octet_seq.len = ias_value->len;
- /* Copy over */
- memcpy(ias_opt->attribute.irda_attrib_octet_seq.octet_seq,
- ias_value->t.oct_seq, ias_value->len);
- break;
- case IAS_STRING:
- /* Set length */
- ias_opt->attribute.irda_attrib_string.len = ias_value->len;
- ias_opt->attribute.irda_attrib_string.charset = ias_value->charset;
- /* Copy over */
- memcpy(ias_opt->attribute.irda_attrib_string.string,
- ias_value->t.string, ias_value->len);
- /* NULL terminate the string (avoid troubles) */
- ias_opt->attribute.irda_attrib_string.string[ias_value->len] = '\0';
- break;
- case IAS_MISSING:
- default :
- return -EINVAL;
- }
-
- /* Copy type over */
- ias_opt->irda_attrib_type = ias_value->type;
-
- return 0;
-}
-
-/*
- * Function irda_getsockopt (sock, level, optname, optval, optlen)
- */
-static int irda_getsockopt(struct socket *sock, int level, int optname,
- char __user *optval, int __user *optlen)
-{
- struct sock *sk = sock->sk;
- struct irda_sock *self = irda_sk(sk);
- struct irda_device_list list = { 0 };
- struct irda_device_info *discoveries;
- struct irda_ias_set * ias_opt; /* IAS get/query params */
- struct ias_object * ias_obj; /* Object in IAS */
- struct ias_attrib * ias_attr; /* Attribute in IAS object */
- int daddr = DEV_ADDR_ANY; /* Dest address for IAS queries */
- int val = 0;
- int len = 0;
- int err = 0;
- int offset, total;
-
- pr_debug("%s(%p)\n", __func__, self);
-
- if (level != SOL_IRLMP)
- return -ENOPROTOOPT;
-
- if (get_user(len, optlen))
- return -EFAULT;
-
- if(len < 0)
- return -EINVAL;
-
- lock_sock(sk);
-
- switch (optname) {
- case IRLMP_ENUMDEVICES:
-
- /* Offset to first device entry */
- offset = sizeof(struct irda_device_list) -
- sizeof(struct irda_device_info);
-
- if (len < offset) {
- err = -EINVAL;
- goto out;
- }
-
- /* Ask lmp for the current discovery log */
- discoveries = irlmp_get_discoveries(&list.len, self->mask.word,
- self->nslots);
- /* Check if the we got some results */
- if (discoveries == NULL) {
- err = -EAGAIN;
- goto out; /* Didn't find any devices */
- }
-
- /* Write total list length back to client */
- if (copy_to_user(optval, &list, offset))
- err = -EFAULT;
-
- /* Copy the list itself - watch for overflow */
- if (list.len > 2048) {
- err = -EINVAL;
- goto bed;
- }
- total = offset + (list.len * sizeof(struct irda_device_info));
- if (total > len)
- total = len;
- if (copy_to_user(optval+offset, discoveries, total - offset))
- err = -EFAULT;
-
- /* Write total number of bytes used back to client */
- if (put_user(total, optlen))
- err = -EFAULT;
-bed:
- /* Free up our buffer */
- kfree(discoveries);
- break;
- case IRLMP_MAX_SDU_SIZE:
- val = self->max_data_size;
- len = sizeof(int);
- if (put_user(len, optlen)) {
- err = -EFAULT;
- goto out;
- }
-
- if (copy_to_user(optval, &val, len)) {
- err = -EFAULT;
- goto out;
- }
-
- break;
- case IRLMP_IAS_GET:
- /* The user want an object from our local IAS database.
- * We just need to query the IAS and return the value
- * that we found */
-
- /* Check that the user has allocated the right space for us */
- if (len != sizeof(struct irda_ias_set)) {
- err = -EINVAL;
- goto out;
- }
-
- /* Copy query to the driver. */
- ias_opt = memdup_user(optval, len);
- if (IS_ERR(ias_opt)) {
- err = PTR_ERR(ias_opt);
- goto out;
- }
-
- /* Find the object we target.
- * If the user gives us an empty string, we use the object
- * associated with this socket. This will workaround
- * duplicated class name - Jean II */
- if(ias_opt->irda_class_name[0] == '\0')
- ias_obj = self->ias_obj;
- else
- ias_obj = irias_find_object(ias_opt->irda_class_name);
- if(ias_obj == (struct ias_object *) NULL) {
- kfree(ias_opt);
- err = -EINVAL;
- goto out;
- }
-
- /* Find the attribute (in the object) we target */
- ias_attr = irias_find_attrib(ias_obj,
- ias_opt->irda_attrib_name);
- if(ias_attr == (struct ias_attrib *) NULL) {
- kfree(ias_opt);
- err = -EINVAL;
- goto out;
- }
-
- /* Translate from internal to user structure */
- err = irda_extract_ias_value(ias_opt, ias_attr->value);
- if(err) {
- kfree(ias_opt);
- goto out;
- }
-
- /* Copy reply to the user */
- if (copy_to_user(optval, ias_opt,
- sizeof(struct irda_ias_set))) {
- kfree(ias_opt);
- err = -EFAULT;
- goto out;
- }
- /* Note : don't need to put optlen, we checked it */
- kfree(ias_opt);
- break;
- case IRLMP_IAS_QUERY:
- /* The user want an object from a remote IAS database.
- * We need to use IAP to query the remote database and
- * then wait for the answer to come back. */
-
- /* Check that the user has allocated the right space for us */
- if (len != sizeof(struct irda_ias_set)) {
- err = -EINVAL;
- goto out;
- }
-
- /* Copy query to the driver. */
- ias_opt = memdup_user(optval, len);
- if (IS_ERR(ias_opt)) {
- err = PTR_ERR(ias_opt);
- goto out;
- }
-
- /* At this point, there are two cases...
- * 1) the socket is connected - that's the easy case, we
- * just query the device we are connected to...
- * 2) the socket is not connected - the user doesn't want
- * to connect and/or may not have a valid service name
- * (so can't create a fake connection). In this case,
- * we assume that the user pass us a valid destination
- * address in the requesting structure...
- */
- if(self->daddr != DEV_ADDR_ANY) {
- /* We are connected - reuse known daddr */
- daddr = self->daddr;
- } else {
- /* We are not connected, we must specify a valid
- * destination address */
- daddr = ias_opt->daddr;
- if((!daddr) || (daddr == DEV_ADDR_ANY)) {
- kfree(ias_opt);
- err = -EINVAL;
- goto out;
- }
- }
-
- /* Check that we can proceed with IAP */
- if (self->iriap) {
- net_warn_ratelimited("%s: busy with a previous query\n",
- __func__);
- kfree(ias_opt);
- err = -EBUSY;
- goto out;
- }
-
- self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
- irda_getvalue_confirm);
-
- if (self->iriap == NULL) {
- kfree(ias_opt);
- err = -ENOMEM;
- goto out;
- }
-
- /* Treat unexpected wakeup as disconnect */
- self->errno = -EHOSTUNREACH;
-
- /* Query remote LM-IAS */
- iriap_getvaluebyclass_request(self->iriap,
- self->saddr, daddr,
- ias_opt->irda_class_name,
- ias_opt->irda_attrib_name);
-
- /* Wait for answer, if not yet finished (or failed) */
- if (wait_event_interruptible(self->query_wait,
- (self->iriap == NULL))) {
- /* pending request uses copy of ias_opt-content
- * we can free it regardless! */
- kfree(ias_opt);
- /* Treat signals as disconnect */
- err = -EHOSTUNREACH;
- goto out;
- }
-
- /* Check what happened */
- if (self->errno)
- {
- kfree(ias_opt);
- /* Requested object/attribute doesn't exist */
- if((self->errno == IAS_CLASS_UNKNOWN) ||
- (self->errno == IAS_ATTRIB_UNKNOWN))
- err = -EADDRNOTAVAIL;
- else
- err = -EHOSTUNREACH;
-
- goto out;
- }
-
- /* Translate from internal to user structure */
- err = irda_extract_ias_value(ias_opt, self->ias_result);
- if (self->ias_result)
- irias_delete_value(self->ias_result);
- if (err) {
- kfree(ias_opt);
- goto out;
- }
-
- /* Copy reply to the user */
- if (copy_to_user(optval, ias_opt,
- sizeof(struct irda_ias_set))) {
- kfree(ias_opt);
- err = -EFAULT;
- goto out;
- }
- /* Note : don't need to put optlen, we checked it */
- kfree(ias_opt);
- break;
- case IRLMP_WAITDEVICE:
- /* This function is just another way of seeing life ;-)
- * IRLMP_ENUMDEVICES assumes that you have a static network,
- * and that you just want to pick one of the devices present.
- * On the other hand, in here we assume that no device is
- * present and that at some point in the future a device will
- * come into range. When this device arrive, we just wake
- * up the caller, so that he has time to connect to it before
- * the device goes away...
- * Note : once the node has been discovered for more than a
- * few second, it won't trigger this function, unless it
- * goes away and come back changes its hint bits (so we
- * might call it IRLMP_WAITNEWDEVICE).
- */
-
- /* Check that the user is passing us an int */
- if (len != sizeof(int)) {
- err = -EINVAL;
- goto out;
- }
- /* Get timeout in ms (max time we block the caller) */
- if (get_user(val, (int __user *)optval)) {
- err = -EFAULT;
- goto out;
- }
-
- /* Tell IrLMP we want to be notified */
- irlmp_update_client(self->ckey, self->mask.word,
- irda_selective_discovery_indication,
- NULL, (void *) self);
-
- /* Do some discovery (and also return cached results) */
- irlmp_discovery_request(self->nslots);
-
- /* Wait until a node is discovered */
- if (!self->cachedaddr) {
- pr_debug("%s(), nothing discovered yet, going to sleep...\n",
- __func__);
-
- /* Set watchdog timer to expire in <val> ms. */
- self->errno = 0;
- timer_setup(&self->watchdog, irda_discovery_timeout, 0);
- mod_timer(&self->watchdog,
- jiffies + msecs_to_jiffies(val));
-
- /* Wait for IR-LMP to call us back */
- err = __wait_event_interruptible(self->query_wait,
- (self->cachedaddr != 0 || self->errno == -ETIME));
-
- /* If watchdog is still activated, kill it! */
- del_timer(&(self->watchdog));
-
- pr_debug("%s(), ...waking up !\n", __func__);
-
- if (err != 0)
- goto out;
- }
- else
- pr_debug("%s(), found immediately !\n",
- __func__);
-
- /* Tell IrLMP that we have been notified */
- irlmp_update_client(self->ckey, self->mask.word,
- NULL, NULL, NULL);
-
- /* Check if the we got some results */
- if (!self->cachedaddr) {
- err = -EAGAIN; /* Didn't find any devices */
- goto out;
- }
- daddr = self->cachedaddr;
- /* Cleanup */
- self->cachedaddr = 0;
-
- /* We return the daddr of the device that trigger the
- * wakeup. As irlmp pass us only the new devices, we
- * are sure that it's not an old device.
- * If the user want more details, he should query
- * the whole discovery log and pick one device...
- */
- if (put_user(daddr, (int __user *)optval)) {
- err = -EFAULT;
- goto out;
- }
-
- break;
- default:
- err = -ENOPROTOOPT;
- }
-
-out:
-
- release_sock(sk);
-
- return err;
-}
-
-static const struct net_proto_family irda_family_ops = {
- .family = PF_IRDA,
- .create = irda_create,
- .owner = THIS_MODULE,
-};
-
-static const struct proto_ops irda_stream_ops = {
- .family = PF_IRDA,
- .owner = THIS_MODULE,
- .release = irda_release,
- .bind = irda_bind,
- .connect = irda_connect,
- .socketpair = sock_no_socketpair,
- .accept = irda_accept,
- .getname = irda_getname,
- .poll = irda_poll,
- .ioctl = irda_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = irda_compat_ioctl,
-#endif
- .listen = irda_listen,
- .shutdown = irda_shutdown,
- .setsockopt = irda_setsockopt,
- .getsockopt = irda_getsockopt,
- .sendmsg = irda_sendmsg,
- .recvmsg = irda_recvmsg_stream,
- .mmap = sock_no_mmap,
- .sendpage = sock_no_sendpage,
-};
-
-static const struct proto_ops irda_seqpacket_ops = {
- .family = PF_IRDA,
- .owner = THIS_MODULE,
- .release = irda_release,
- .bind = irda_bind,
- .connect = irda_connect,
- .socketpair = sock_no_socketpair,
- .accept = irda_accept,
- .getname = irda_getname,
- .poll = datagram_poll,
- .ioctl = irda_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = irda_compat_ioctl,
-#endif
- .listen = irda_listen,
- .shutdown = irda_shutdown,
- .setsockopt = irda_setsockopt,
- .getsockopt = irda_getsockopt,
- .sendmsg = irda_sendmsg,
- .recvmsg = irda_recvmsg_dgram,
- .mmap = sock_no_mmap,
- .sendpage = sock_no_sendpage,
-};
-
-static const struct proto_ops irda_dgram_ops = {
- .family = PF_IRDA,
- .owner = THIS_MODULE,
- .release = irda_release,
- .bind = irda_bind,
- .connect = irda_connect,
- .socketpair = sock_no_socketpair,
- .accept = irda_accept,
- .getname = irda_getname,
- .poll = datagram_poll,
- .ioctl = irda_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = irda_compat_ioctl,
-#endif
- .listen = irda_listen,
- .shutdown = irda_shutdown,
- .setsockopt = irda_setsockopt,
- .getsockopt = irda_getsockopt,
- .sendmsg = irda_sendmsg_dgram,
- .recvmsg = irda_recvmsg_dgram,
- .mmap = sock_no_mmap,
- .sendpage = sock_no_sendpage,
-};
-
-#ifdef CONFIG_IRDA_ULTRA
-static const struct proto_ops irda_ultra_ops = {
- .family = PF_IRDA,
- .owner = THIS_MODULE,
- .release = irda_release,
- .bind = irda_bind,
- .connect = sock_no_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .getname = irda_getname,
- .poll = datagram_poll,
- .ioctl = irda_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = irda_compat_ioctl,
-#endif
- .listen = sock_no_listen,
- .shutdown = irda_shutdown,
- .setsockopt = irda_setsockopt,
- .getsockopt = irda_getsockopt,
- .sendmsg = irda_sendmsg_ultra,
- .recvmsg = irda_recvmsg_dgram,
- .mmap = sock_no_mmap,
- .sendpage = sock_no_sendpage,
-};
-#endif /* CONFIG_IRDA_ULTRA */
-
-/*
- * Function irsock_init (pro)
- *
- * Initialize IrDA protocol
- *
- */
-int __init irsock_init(void)
-{
- int rc = proto_register(&irda_proto, 0);
-
- if (rc == 0)
- rc = sock_register(&irda_family_ops);
-
- return rc;
-}
-
-/*
- * Function irsock_cleanup (void)
- *
- * Remove IrDA protocol
- *
- */
-void irsock_cleanup(void)
-{
- sock_unregister(PF_IRDA);
- proto_unregister(&irda_proto);
-}
diff --git a/drivers/staging/irda/net/discovery.c b/drivers/staging/irda/net/discovery.c
deleted file mode 100644
index 1e54954a4081..000000000000
--- a/drivers/staging/irda/net/discovery.c
+++ /dev/null
@@ -1,417 +0,0 @@
-/*********************************************************************
- *
- * Filename: discovery.c
- * Version: 0.1
- * Description: Routines for handling discoveries at the IrLMP layer
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Tue Apr 6 15:33:50 1999
- * Modified at: Sat Oct 9 17:11:31 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- * Modified at: Fri May 28 3:11 CST 1999
- * Modified by: Horst von Brand <vonbrand@sleipnir.valparaiso.cl>
- *
- * Copyright (c) 1999 Dag Brattli, 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.
- *
- * 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/string.h>
-#include <linux/socket.h>
-#include <linux/fs.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irlmp.h>
-
-#include <net/irda/discovery.h>
-
-#include <asm/unaligned.h>
-
-/*
- * Function irlmp_add_discovery (cachelog, discovery)
- *
- * Add a new discovery to the cachelog, and remove any old discoveries
- * from the same device
- *
- * Note : we try to preserve the time this device was *first* discovered
- * (as opposed to the time of last discovery used for cleanup). This is
- * used by clients waiting for discovery events to tell if the device
- * discovered is "new" or just the same old one. They can't rely there
- * on a binary flag (new/old), because not all discovery events are
- * propagated to them, and they might not always listen, so they would
- * miss some new devices popping up...
- * Jean II
- */
-void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *new)
-{
- discovery_t *discovery, *node;
- unsigned long flags;
-
- /* Set time of first discovery if node is new (see below) */
- new->firststamp = new->timestamp;
-
- spin_lock_irqsave(&cachelog->hb_spinlock, flags);
-
- /*
- * Remove all discoveries of devices that has previously been
- * discovered on the same link with the same name (info), or the
- * same daddr. We do this since some devices (mostly PDAs) change
- * their device address between every discovery.
- */
- discovery = (discovery_t *) hashbin_get_first(cachelog);
- while (discovery != NULL ) {
- node = discovery;
-
- /* Be sure to stay one item ahead */
- discovery = (discovery_t *) hashbin_get_next(cachelog);
-
- if ((node->data.saddr == new->data.saddr) &&
- ((node->data.daddr == new->data.daddr) ||
- (strcmp(node->data.info, new->data.info) == 0)))
- {
- /* This discovery is a previous discovery
- * from the same device, so just remove it
- */
- hashbin_remove_this(cachelog, (irda_queue_t *) node);
- /* Check if hints bits are unchanged */
- if (get_unaligned((__u16 *)node->data.hints) == get_unaligned((__u16 *)new->data.hints))
- /* Set time of first discovery for this node */
- new->firststamp = node->firststamp;
- kfree(node);
- }
- }
-
- /* Insert the new and updated version */
- hashbin_insert(cachelog, (irda_queue_t *) new, new->data.daddr, NULL);
-
- spin_unlock_irqrestore(&cachelog->hb_spinlock, flags);
-}
-
-/*
- * Function irlmp_add_discovery_log (cachelog, log)
- *
- * Merge a disovery log into the cachelog.
- *
- */
-void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log)
-{
- discovery_t *discovery;
-
- /*
- * If log is missing this means that IrLAP was unable to perform the
- * discovery, so restart discovery again with just the half timeout
- * of the normal one.
- */
- /* Well... It means that there was nobody out there - Jean II */
- if (log == NULL) {
- /* irlmp_start_discovery_timer(irlmp, 150); */
- return;
- }
-
- /*
- * Locking : we are the only owner of this discovery log, so
- * no need to lock it.
- * We just need to lock the global log in irlmp_add_discovery().
- */
- discovery = (discovery_t *) hashbin_remove_first(log);
- while (discovery != NULL) {
- irlmp_add_discovery(cachelog, discovery);
-
- discovery = (discovery_t *) hashbin_remove_first(log);
- }
-
- /* Delete the now empty log */
- hashbin_delete(log, (FREE_FUNC) kfree);
-}
-
-/*
- * Function irlmp_expire_discoveries (log, saddr, force)
- *
- * Go through all discoveries and expire all that has stayed too long
- *
- * Note : this assume that IrLAP won't change its saddr, which
- * currently is a valid assumption...
- */
-void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force)
-{
- discovery_t * discovery;
- discovery_t * curr;
- unsigned long flags;
- discinfo_t * buffer = NULL;
- int n; /* Size of the full log */
- int i = 0; /* How many we expired */
-
- IRDA_ASSERT(log != NULL, return;);
- spin_lock_irqsave(&log->hb_spinlock, flags);
-
- discovery = (discovery_t *) hashbin_get_first(log);
- while (discovery != NULL) {
- /* Be sure to be one item ahead */
- curr = discovery;
- discovery = (discovery_t *) hashbin_get_next(log);
-
- /* Test if it's time to expire this discovery */
- if ((curr->data.saddr == saddr) &&
- (force ||
- ((jiffies - curr->timestamp) > DISCOVERY_EXPIRE_TIMEOUT)))
- {
- /* Create buffer as needed.
- * As this function get called a lot and most time
- * we don't have anything to put in the log (we are
- * quite picky), we can save a lot of overhead
- * by not calling kmalloc. Jean II */
- if(buffer == NULL) {
- /* Create the client specific buffer */
- n = HASHBIN_GET_SIZE(log);
- buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC);
- if (!buffer) {
- spin_unlock_irqrestore(&log->hb_spinlock, flags);
- return;
- }
-
- }
-
- /* Copy discovery information */
- memcpy(&(buffer[i]), &(curr->data),
- sizeof(discinfo_t));
- i++;
-
- /* Remove it from the log */
- curr = hashbin_remove_this(log, (irda_queue_t *) curr);
- kfree(curr);
- }
- }
-
- /* Drop the spinlock before calling the higher layers, as
- * we can't guarantee they won't call us back and create a
- * deadlock. We will work on our own private data, so we
- * don't care to be interrupted. - Jean II */
- spin_unlock_irqrestore(&log->hb_spinlock, flags);
-
- if(buffer == NULL)
- return;
-
- /* Tell IrLMP and registered clients about it */
- irlmp_discovery_expiry(buffer, i);
-
- /* Free up our buffer */
- kfree(buffer);
-}
-
-#if 0
-/*
- * Function irlmp_dump_discoveries (log)
- *
- * Print out all discoveries in log
- *
- */
-void irlmp_dump_discoveries(hashbin_t *log)
-{
- discovery_t *discovery;
-
- IRDA_ASSERT(log != NULL, return;);
-
- discovery = (discovery_t *) hashbin_get_first(log);
- while (discovery != NULL) {
- pr_debug("Discovery:\n");
- pr_debug(" daddr=%08x\n", discovery->data.daddr);
- pr_debug(" saddr=%08x\n", discovery->data.saddr);
- pr_debug(" nickname=%s\n", discovery->data.info);
-
- discovery = (discovery_t *) hashbin_get_next(log);
- }
-}
-#endif
-
-/*
- * Function irlmp_copy_discoveries (log, pn, mask)
- *
- * Copy all discoveries in a buffer
- *
- * This function implement a safe way for lmp clients to access the
- * discovery log. The basic problem is that we don't want the log
- * to change (add/remove) while the client is reading it. If the
- * lmp client manipulate directly the hashbin, he is sure to get
- * into troubles...
- * The idea is that we copy all the current discovery log in a buffer
- * which is specific to the client and pass this copy to him. As we
- * do this operation with the spinlock grabbed, we are safe...
- * Note : we don't want those clients to grab the spinlock, because
- * we have no control on how long they will hold it...
- * Note : we choose to copy the log in "struct irda_device_info" to
- * save space...
- * Note : the client must kfree himself() the log...
- * Jean II
- */
-struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn,
- __u16 mask, int old_entries)
-{
- discovery_t * discovery;
- unsigned long flags;
- discinfo_t * buffer = NULL;
- int j_timeout = (sysctl_discovery_timeout * HZ);
- int n; /* Size of the full log */
- int i = 0; /* How many we picked */
-
- IRDA_ASSERT(pn != NULL, return NULL;);
- IRDA_ASSERT(log != NULL, return NULL;);
-
- /* Save spin lock */
- spin_lock_irqsave(&log->hb_spinlock, flags);
-
- discovery = (discovery_t *) hashbin_get_first(log);
- while (discovery != NULL) {
- /* Mask out the ones we don't want :
- * We want to match the discovery mask, and to get only
- * the most recent one (unless we want old ones) */
- if ((get_unaligned((__u16 *)discovery->data.hints) & mask) &&
- ((old_entries) ||
- ((jiffies - discovery->firststamp) < j_timeout))) {
- /* Create buffer as needed.
- * As this function get called a lot and most time
- * we don't have anything to put in the log (we are
- * quite picky), we can save a lot of overhead
- * by not calling kmalloc. Jean II */
- if(buffer == NULL) {
- /* Create the client specific buffer */
- n = HASHBIN_GET_SIZE(log);
- buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC);
- if (!buffer) {
- spin_unlock_irqrestore(&log->hb_spinlock, flags);
- return NULL;
- }
-
- }
-
- /* Copy discovery information */
- memcpy(&(buffer[i]), &(discovery->data),
- sizeof(discinfo_t));
- i++;
- }
- discovery = (discovery_t *) hashbin_get_next(log);
- }
-
- spin_unlock_irqrestore(&log->hb_spinlock, flags);
-
- /* Get the actual number of device in the buffer and return */
- *pn = i;
- return buffer;
-}
-
-#ifdef CONFIG_PROC_FS
-static inline discovery_t *discovery_seq_idx(loff_t pos)
-
-{
- discovery_t *discovery;
-
- for (discovery = (discovery_t *) hashbin_get_first(irlmp->cachelog);
- discovery != NULL;
- discovery = (discovery_t *) hashbin_get_next(irlmp->cachelog)) {
- if (pos-- == 0)
- break;
- }
-
- return discovery;
-}
-
-static void *discovery_seq_start(struct seq_file *seq, loff_t *pos)
-{
- spin_lock_irq(&irlmp->cachelog->hb_spinlock);
- return *pos ? discovery_seq_idx(*pos - 1) : SEQ_START_TOKEN;
-}
-
-static void *discovery_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- ++*pos;
- return (v == SEQ_START_TOKEN)
- ? (void *) hashbin_get_first(irlmp->cachelog)
- : (void *) hashbin_get_next(irlmp->cachelog);
-}
-
-static void discovery_seq_stop(struct seq_file *seq, void *v)
-{
- spin_unlock_irq(&irlmp->cachelog->hb_spinlock);
-}
-
-static int discovery_seq_show(struct seq_file *seq, void *v)
-{
- if (v == SEQ_START_TOKEN)
- seq_puts(seq, "IrLMP: Discovery log:\n\n");
- else {
- const discovery_t *discovery = v;
-
- seq_printf(seq, "nickname: %s, hint: 0x%02x%02x",
- discovery->data.info,
- discovery->data.hints[0],
- discovery->data.hints[1]);
-#if 0
- if ( discovery->data.hints[0] & HINT_PNP)
- seq_puts(seq, "PnP Compatible ");
- if ( discovery->data.hints[0] & HINT_PDA)
- seq_puts(seq, "PDA/Palmtop ");
- if ( discovery->data.hints[0] & HINT_COMPUTER)
- seq_puts(seq, "Computer ");
- if ( discovery->data.hints[0] & HINT_PRINTER)
- seq_puts(seq, "Printer ");
- if ( discovery->data.hints[0] & HINT_MODEM)
- seq_puts(seq, "Modem ");
- if ( discovery->data.hints[0] & HINT_FAX)
- seq_puts(seq, "Fax ");
- if ( discovery->data.hints[0] & HINT_LAN)
- seq_puts(seq, "LAN Access ");
-
- if ( discovery->data.hints[1] & HINT_TELEPHONY)
- seq_puts(seq, "Telephony ");
- if ( discovery->data.hints[1] & HINT_FILE_SERVER)
- seq_puts(seq, "File Server ");
- if ( discovery->data.hints[1] & HINT_COMM)
- seq_puts(seq, "IrCOMM ");
- if ( discovery->data.hints[1] & HINT_OBEX)
- seq_puts(seq, "IrOBEX ");
-#endif
- seq_printf(seq,", saddr: 0x%08x, daddr: 0x%08x\n\n",
- discovery->data.saddr,
- discovery->data.daddr);
-
- seq_putc(seq, '\n');
- }
- return 0;
-}
-
-static const struct seq_operations discovery_seq_ops = {
- .start = discovery_seq_start,
- .next = discovery_seq_next,
- .stop = discovery_seq_stop,
- .show = discovery_seq_show,
-};
-
-static int discovery_seq_open(struct inode *inode, struct file *file)
-{
- IRDA_ASSERT(irlmp != NULL, return -EINVAL;);
-
- return seq_open(file, &discovery_seq_ops);
-}
-
-const struct file_operations discovery_seq_fops = {
- .owner = THIS_MODULE,
- .open = discovery_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-#endif
diff --git a/drivers/staging/irda/net/ircomm/Kconfig b/drivers/staging/irda/net/ircomm/Kconfig
deleted file mode 100644
index 19492c1707b7..000000000000
--- a/drivers/staging/irda/net/ircomm/Kconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-config IRCOMM
- tristate "IrCOMM protocol"
- depends on IRDA && TTY
- help
- Say Y here if you want to build support for the IrCOMM protocol.
- To compile it as modules, choose M here: the modules will be
- called ircomm and ircomm_tty.
- IrCOMM implements serial port emulation, and makes it possible to
- use all existing applications that understands TTY's with an
- infrared link. Thus you should be able to use application like PPP,
- minicom and others.
-
diff --git a/drivers/staging/irda/net/ircomm/Makefile b/drivers/staging/irda/net/ircomm/Makefile
deleted file mode 100644
index ab23b5ba7e33..000000000000
--- a/drivers/staging/irda/net/ircomm/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for the Linux IrDA IrCOMM protocol layer.
-#
-
-obj-$(CONFIG_IRCOMM) += ircomm.o ircomm-tty.o
-
-ircomm-y := ircomm_core.o ircomm_event.o ircomm_lmp.o ircomm_ttp.o
-ircomm-tty-y := ircomm_tty.o ircomm_tty_attach.o ircomm_tty_ioctl.o ircomm_param.o
diff --git a/drivers/staging/irda/net/ircomm/ircomm_core.c b/drivers/staging/irda/net/ircomm/ircomm_core.c
deleted file mode 100644
index 3af219545f6d..000000000000
--- a/drivers/staging/irda/net/ircomm/ircomm_core.c
+++ /dev/null
@@ -1,563 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_core.c
- * Version: 1.0
- * Description: IrCOMM service interface
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Jun 6 20:37:34 1999
- * Modified at: Tue Dec 21 13:26:41 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
- * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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/module.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irmod.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/iriap.h>
-#include <net/irda/irttp.h>
-#include <net/irda/irias_object.h>
-
-#include <net/irda/ircomm_event.h>
-#include <net/irda/ircomm_lmp.h>
-#include <net/irda/ircomm_ttp.h>
-#include <net/irda/ircomm_param.h>
-#include <net/irda/ircomm_core.h>
-
-static int __ircomm_close(struct ircomm_cb *self);
-static void ircomm_control_indication(struct ircomm_cb *self,
- struct sk_buff *skb, int clen);
-
-#ifdef CONFIG_PROC_FS
-extern struct proc_dir_entry *proc_irda;
-static int ircomm_seq_open(struct inode *, struct file *);
-
-static const struct file_operations ircomm_proc_fops = {
- .owner = THIS_MODULE,
- .open = ircomm_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-#endif /* CONFIG_PROC_FS */
-
-hashbin_t *ircomm = NULL;
-
-static int __init ircomm_init(void)
-{
- ircomm = hashbin_new(HB_LOCK);
- if (ircomm == NULL) {
- net_err_ratelimited("%s(), can't allocate hashbin!\n",
- __func__);
- return -ENOMEM;
- }
-
-#ifdef CONFIG_PROC_FS
- { struct proc_dir_entry *ent;
- ent = proc_create("ircomm", 0, proc_irda, &ircomm_proc_fops);
- if (!ent) {
- printk(KERN_ERR "ircomm_init: can't create /proc entry!\n");
- return -ENODEV;
- }
- }
-#endif /* CONFIG_PROC_FS */
-
- net_info_ratelimited("IrCOMM protocol (Dag Brattli)\n");
-
- return 0;
-}
-
-static void __exit ircomm_cleanup(void)
-{
- hashbin_delete(ircomm, (FREE_FUNC) __ircomm_close);
-
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("ircomm", proc_irda);
-#endif /* CONFIG_PROC_FS */
-}
-
-/*
- * Function ircomm_open (client_notify)
- *
- * Start a new IrCOMM instance
- *
- */
-struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line)
-{
- struct ircomm_cb *self = NULL;
- int ret;
-
- pr_debug("%s(), service_type=0x%02x\n", __func__ ,
- service_type);
-
- IRDA_ASSERT(ircomm != NULL, return NULL;);
-
- self = kzalloc(sizeof(struct ircomm_cb), GFP_KERNEL);
- if (self == NULL)
- return NULL;
-
- self->notify = *notify;
- self->magic = IRCOMM_MAGIC;
-
- /* Check if we should use IrLMP or IrTTP */
- if (service_type & IRCOMM_3_WIRE_RAW) {
- self->flow_status = FLOW_START;
- ret = ircomm_open_lsap(self);
- } else
- ret = ircomm_open_tsap(self);
-
- if (ret < 0) {
- kfree(self);
- return NULL;
- }
-
- self->service_type = service_type;
- self->line = line;
-
- hashbin_insert(ircomm, (irda_queue_t *) self, line, NULL);
-
- ircomm_next_state(self, IRCOMM_IDLE);
-
- return self;
-}
-
-EXPORT_SYMBOL(ircomm_open);
-
-/*
- * Function ircomm_close_instance (self)
- *
- * Remove IrCOMM instance
- *
- */
-static int __ircomm_close(struct ircomm_cb *self)
-{
- /* Disconnect link if any */
- ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL);
-
- /* Remove TSAP */
- if (self->tsap) {
- irttp_close_tsap(self->tsap);
- self->tsap = NULL;
- }
-
- /* Remove LSAP */
- if (self->lsap) {
- irlmp_close_lsap(self->lsap);
- self->lsap = NULL;
- }
- self->magic = 0;
-
- kfree(self);
-
- return 0;
-}
-
-/*
- * Function ircomm_close (self)
- *
- * Closes and removes the specified IrCOMM instance
- *
- */
-int ircomm_close(struct ircomm_cb *self)
-{
- struct ircomm_cb *entry;
-
- IRDA_ASSERT(self != NULL, return -EIO;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;);
-
- entry = hashbin_remove(ircomm, self->line, NULL);
-
- IRDA_ASSERT(entry == self, return -1;);
-
- return __ircomm_close(self);
-}
-
-EXPORT_SYMBOL(ircomm_close);
-
-/*
- * Function ircomm_connect_request (self, service_type)
- *
- * Impl. of this function is differ from one of the reference. This
- * function does discovery as well as sending connect request
- *
- */
-int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel,
- __u32 saddr, __u32 daddr, struct sk_buff *skb,
- __u8 service_type)
-{
- struct ircomm_info info;
- int ret;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
-
- self->service_type= service_type;
-
- info.dlsap_sel = dlsap_sel;
- info.saddr = saddr;
- info.daddr = daddr;
-
- ret = ircomm_do_event(self, IRCOMM_CONNECT_REQUEST, skb, &info);
-
- return ret;
-}
-
-EXPORT_SYMBOL(ircomm_connect_request);
-
-/*
- * Function ircomm_connect_indication (self, qos, skb)
- *
- * Notify user layer about the incoming connection
- *
- */
-void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
- struct ircomm_info *info)
-{
- /*
- * If there are any data hiding in the control channel, we must
- * deliver it first. The side effect is that the control channel
- * will be removed from the skb
- */
- if (self->notify.connect_indication)
- self->notify.connect_indication(self->notify.instance, self,
- info->qos, info->max_data_size,
- info->max_header_size, skb);
- else {
- pr_debug("%s(), missing handler\n", __func__);
- }
-}
-
-/*
- * Function ircomm_connect_response (self, userdata, max_sdu_size)
- *
- * User accepts connection
- *
- */
-int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata)
-{
- int ret;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
-
- ret = ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata, NULL);
-
- return ret;
-}
-
-EXPORT_SYMBOL(ircomm_connect_response);
-
-/*
- * Function connect_confirm (self, skb)
- *
- * Notify user layer that the link is now connected
- *
- */
-void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
- struct ircomm_info *info)
-{
- if (self->notify.connect_confirm )
- self->notify.connect_confirm(self->notify.instance,
- self, info->qos,
- info->max_data_size,
- info->max_header_size, skb);
- else {
- pr_debug("%s(), missing handler\n", __func__);
- }
-}
-
-/*
- * Function ircomm_data_request (self, userdata)
- *
- * Send IrCOMM data to peer device
- *
- */
-int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb)
-{
- int ret;
-
- IRDA_ASSERT(self != NULL, return -EFAULT;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
- IRDA_ASSERT(skb != NULL, return -EFAULT;);
-
- ret = ircomm_do_event(self, IRCOMM_DATA_REQUEST, skb, NULL);
-
- return ret;
-}
-
-EXPORT_SYMBOL(ircomm_data_request);
-
-/*
- * Function ircomm_data_indication (self, skb)
- *
- * Data arrived, so deliver it to user
- *
- */
-void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
-{
- IRDA_ASSERT(skb->len > 0, return;);
-
- if (self->notify.data_indication)
- self->notify.data_indication(self->notify.instance, self, skb);
- else {
- pr_debug("%s(), missing handler\n", __func__);
- }
-}
-
-/*
- * Function ircomm_process_data (self, skb)
- *
- * Data arrived which may contain control channel data
- *
- */
-void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb)
-{
- int clen;
-
- IRDA_ASSERT(skb->len > 0, return;);
-
- clen = skb->data[0];
-
- /*
- * Input validation check: a stir4200/mcp2150 combinations sometimes
- * results in frames with clen > remaining packet size. These are
- * illegal; if we throw away just this frame then it seems to carry on
- * fine
- */
- if (unlikely(skb->len < (clen + 1))) {
- pr_debug("%s() throwing away illegal frame\n",
- __func__);
- return;
- }
-
- /*
- * If there are any data hiding in the control channel, we must
- * deliver it first. The side effect is that the control channel
- * will be removed from the skb
- */
- if (clen > 0)
- ircomm_control_indication(self, skb, clen);
-
- /* Remove control channel from data channel */
- skb_pull(skb, clen+1);
-
- if (skb->len)
- ircomm_data_indication(self, skb);
- else {
- pr_debug("%s(), data was control info only!\n",
- __func__);
- }
-}
-
-/*
- * Function ircomm_control_request (self, params)
- *
- * Send control data to peer device
- *
- */
-int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb)
-{
- int ret;
-
- IRDA_ASSERT(self != NULL, return -EFAULT;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
- IRDA_ASSERT(skb != NULL, return -EFAULT;);
-
- ret = ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb, NULL);
-
- return ret;
-}
-
-EXPORT_SYMBOL(ircomm_control_request);
-
-/*
- * Function ircomm_control_indication (self, skb)
- *
- * Data has arrived on the control channel
- *
- */
-static void ircomm_control_indication(struct ircomm_cb *self,
- struct sk_buff *skb, int clen)
-{
- /* Use udata for delivering data on the control channel */
- if (self->notify.udata_indication) {
- struct sk_buff *ctrl_skb;
-
- /* We don't own the skb, so clone it */
- ctrl_skb = skb_clone(skb, GFP_ATOMIC);
- if (!ctrl_skb)
- return;
-
- /* Remove data channel from control channel */
- skb_trim(ctrl_skb, clen+1);
-
- self->notify.udata_indication(self->notify.instance, self,
- ctrl_skb);
-
- /* Drop reference count -
- * see ircomm_tty_control_indication(). */
- dev_kfree_skb(ctrl_skb);
- } else {
- pr_debug("%s(), missing handler\n", __func__);
- }
-}
-
-/*
- * Function ircomm_disconnect_request (self, userdata, priority)
- *
- * User layer wants to disconnect the IrCOMM connection
- *
- */
-int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata)
-{
- struct ircomm_info info;
- int ret;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
-
- ret = ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, userdata,
- &info);
- return ret;
-}
-
-EXPORT_SYMBOL(ircomm_disconnect_request);
-
-/*
- * Function disconnect_indication (self, skb)
- *
- * Tell user that the link has been disconnected
- *
- */
-void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
- struct ircomm_info *info)
-{
- IRDA_ASSERT(info != NULL, return;);
-
- if (self->notify.disconnect_indication) {
- self->notify.disconnect_indication(self->notify.instance, self,
- info->reason, skb);
- } else {
- pr_debug("%s(), missing handler\n", __func__);
- }
-}
-
-/*
- * Function ircomm_flow_request (self, flow)
- *
- *
- *
- */
-void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
-
- if (self->service_type == IRCOMM_3_WIRE_RAW)
- return;
-
- irttp_flow_request(self->tsap, flow);
-}
-
-EXPORT_SYMBOL(ircomm_flow_request);
-
-#ifdef CONFIG_PROC_FS
-static void *ircomm_seq_start(struct seq_file *seq, loff_t *pos)
-{
- struct ircomm_cb *self;
- loff_t off = 0;
-
- spin_lock_irq(&ircomm->hb_spinlock);
-
- for (self = (struct ircomm_cb *) hashbin_get_first(ircomm);
- self != NULL;
- self = (struct ircomm_cb *) hashbin_get_next(ircomm)) {
- if (off++ == *pos)
- break;
-
- }
- return self;
-}
-
-static void *ircomm_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- ++*pos;
-
- return (void *) hashbin_get_next(ircomm);
-}
-
-static void ircomm_seq_stop(struct seq_file *seq, void *v)
-{
- spin_unlock_irq(&ircomm->hb_spinlock);
-}
-
-static int ircomm_seq_show(struct seq_file *seq, void *v)
-{
- const struct ircomm_cb *self = v;
-
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EINVAL; );
-
- if(self->line < 0x10)
- seq_printf(seq, "ircomm%d", self->line);
- else
- seq_printf(seq, "irlpt%d", self->line - 0x10);
-
- seq_printf(seq,
- " state: %s, slsap_sel: %#02x, dlsap_sel: %#02x, mode:",
- ircomm_state[ self->state],
- self->slsap_sel, self->dlsap_sel);
-
- if(self->service_type & IRCOMM_3_WIRE_RAW)
- seq_printf(seq, " 3-wire-raw");
- if(self->service_type & IRCOMM_3_WIRE)
- seq_printf(seq, " 3-wire");
- if(self->service_type & IRCOMM_9_WIRE)
- seq_printf(seq, " 9-wire");
- if(self->service_type & IRCOMM_CENTRONICS)
- seq_printf(seq, " Centronics");
- seq_putc(seq, '\n');
-
- return 0;
-}
-
-static const struct seq_operations ircomm_seq_ops = {
- .start = ircomm_seq_start,
- .next = ircomm_seq_next,
- .stop = ircomm_seq_stop,
- .show = ircomm_seq_show,
-};
-
-static int ircomm_seq_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &ircomm_seq_ops);
-}
-#endif /* CONFIG_PROC_FS */
-
-MODULE_AUTHOR("Dag Brattli <dag@brattli.net>");
-MODULE_DESCRIPTION("IrCOMM protocol");
-MODULE_LICENSE("GPL");
-
-module_init(ircomm_init);
-module_exit(ircomm_cleanup);
diff --git a/drivers/staging/irda/net/ircomm/ircomm_event.c b/drivers/staging/irda/net/ircomm/ircomm_event.c
deleted file mode 100644
index b0730ac9f388..000000000000
--- a/drivers/staging/irda/net/ircomm/ircomm_event.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_event.c
- * Version: 1.0
- * Description: IrCOMM layer state machine
- * Status: Stable
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Jun 6 20:33:11 1999
- * Modified at: Sun Dec 12 13:44:32 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Dag Brattli, 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.
- *
- * 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/proc_fs.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/iriap.h>
-#include <net/irda/irttp.h>
-#include <net/irda/irias_object.h>
-
-#include <net/irda/ircomm_core.h>
-#include <net/irda/ircomm_event.h>
-
-static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb, struct ircomm_info *info);
-static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb, struct ircomm_info *info);
-static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb, struct ircomm_info *info);
-static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb, struct ircomm_info *info);
-
-const char *const ircomm_state[] = {
- "IRCOMM_IDLE",
- "IRCOMM_WAITI",
- "IRCOMM_WAITR",
- "IRCOMM_CONN",
-};
-
-static const char *const ircomm_event[] __maybe_unused = {
- "IRCOMM_CONNECT_REQUEST",
- "IRCOMM_CONNECT_RESPONSE",
- "IRCOMM_TTP_CONNECT_INDICATION",
- "IRCOMM_LMP_CONNECT_INDICATION",
- "IRCOMM_TTP_CONNECT_CONFIRM",
- "IRCOMM_LMP_CONNECT_CONFIRM",
-
- "IRCOMM_LMP_DISCONNECT_INDICATION",
- "IRCOMM_TTP_DISCONNECT_INDICATION",
- "IRCOMM_DISCONNECT_REQUEST",
-
- "IRCOMM_TTP_DATA_INDICATION",
- "IRCOMM_LMP_DATA_INDICATION",
- "IRCOMM_DATA_REQUEST",
- "IRCOMM_CONTROL_REQUEST",
- "IRCOMM_CONTROL_INDICATION",
-};
-
-static int (*state[])(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb, struct ircomm_info *info) =
-{
- ircomm_state_idle,
- ircomm_state_waiti,
- ircomm_state_waitr,
- ircomm_state_conn,
-};
-
-/*
- * Function ircomm_state_idle (self, event, skb)
- *
- * IrCOMM is currently idle
- *
- */
-static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb, struct ircomm_info *info)
-{
- int ret = 0;
-
- switch (event) {
- case IRCOMM_CONNECT_REQUEST:
- ircomm_next_state(self, IRCOMM_WAITI);
- ret = self->issue.connect_request(self, skb, info);
- break;
- case IRCOMM_TTP_CONNECT_INDICATION:
- case IRCOMM_LMP_CONNECT_INDICATION:
- ircomm_next_state(self, IRCOMM_WAITR);
- ircomm_connect_indication(self, skb, info);
- break;
- default:
- pr_debug("%s(), unknown event: %s\n", __func__ ,
- ircomm_event[event]);
- ret = -EINVAL;
- }
- return ret;
-}
-
-/*
- * Function ircomm_state_waiti (self, event, skb)
- *
- * The IrCOMM user has requested an IrCOMM connection to the remote
- * device and is awaiting confirmation
- */
-static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb, struct ircomm_info *info)
-{
- int ret = 0;
-
- switch (event) {
- case IRCOMM_TTP_CONNECT_CONFIRM:
- case IRCOMM_LMP_CONNECT_CONFIRM:
- ircomm_next_state(self, IRCOMM_CONN);
- ircomm_connect_confirm(self, skb, info);
- break;
- case IRCOMM_TTP_DISCONNECT_INDICATION:
- case IRCOMM_LMP_DISCONNECT_INDICATION:
- ircomm_next_state(self, IRCOMM_IDLE);
- ircomm_disconnect_indication(self, skb, info);
- break;
- default:
- pr_debug("%s(), unknown event: %s\n", __func__ ,
- ircomm_event[event]);
- ret = -EINVAL;
- }
- return ret;
-}
-
-/*
- * Function ircomm_state_waitr (self, event, skb)
- *
- * IrCOMM has received an incoming connection request and is awaiting
- * response from the user
- */
-static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb, struct ircomm_info *info)
-{
- int ret = 0;
-
- switch (event) {
- case IRCOMM_CONNECT_RESPONSE:
- ircomm_next_state(self, IRCOMM_CONN);
- ret = self->issue.connect_response(self, skb);
- break;
- case IRCOMM_DISCONNECT_REQUEST:
- ircomm_next_state(self, IRCOMM_IDLE);
- ret = self->issue.disconnect_request(self, skb, info);
- break;
- case IRCOMM_TTP_DISCONNECT_INDICATION:
- case IRCOMM_LMP_DISCONNECT_INDICATION:
- ircomm_next_state(self, IRCOMM_IDLE);
- ircomm_disconnect_indication(self, skb, info);
- break;
- default:
- pr_debug("%s(), unknown event = %s\n", __func__ ,
- ircomm_event[event]);
- ret = -EINVAL;
- }
- return ret;
-}
-
-/*
- * Function ircomm_state_conn (self, event, skb)
- *
- * IrCOMM is connected to the peer IrCOMM device
- *
- */
-static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb, struct ircomm_info *info)
-{
- int ret = 0;
-
- switch (event) {
- case IRCOMM_DATA_REQUEST:
- ret = self->issue.data_request(self, skb, 0);
- break;
- case IRCOMM_TTP_DATA_INDICATION:
- ircomm_process_data(self, skb);
- break;
- case IRCOMM_LMP_DATA_INDICATION:
- ircomm_data_indication(self, skb);
- break;
- case IRCOMM_CONTROL_REQUEST:
- /* Just send a separate frame for now */
- ret = self->issue.data_request(self, skb, skb->len);
- break;
- case IRCOMM_TTP_DISCONNECT_INDICATION:
- case IRCOMM_LMP_DISCONNECT_INDICATION:
- ircomm_next_state(self, IRCOMM_IDLE);
- ircomm_disconnect_indication(self, skb, info);
- break;
- case IRCOMM_DISCONNECT_REQUEST:
- ircomm_next_state(self, IRCOMM_IDLE);
- ret = self->issue.disconnect_request(self, skb, info);
- break;
- default:
- pr_debug("%s(), unknown event = %s\n", __func__ ,
- ircomm_event[event]);
- ret = -EINVAL;
- }
- return ret;
-}
-
-/*
- * Function ircomm_do_event (self, event, skb)
- *
- * Process event
- *
- */
-int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb, struct ircomm_info *info)
-{
- pr_debug("%s: state=%s, event=%s\n", __func__ ,
- ircomm_state[self->state], ircomm_event[event]);
-
- return (*state[self->state])(self, event, skb, info);
-}
-
-/*
- * Function ircomm_next_state (self, state)
- *
- * Switch state
- *
- */
-void ircomm_next_state(struct ircomm_cb *self, IRCOMM_STATE state)
-{
- self->state = state;
-
- pr_debug("%s: next state=%s, service type=%d\n", __func__ ,
- ircomm_state[self->state], self->service_type);
-}
diff --git a/drivers/staging/irda/net/ircomm/ircomm_lmp.c b/drivers/staging/irda/net/ircomm/ircomm_lmp.c
deleted file mode 100644
index e4cc847bb933..000000000000
--- a/drivers/staging/irda/net/ircomm/ircomm_lmp.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_lmp.c
- * Version: 1.0
- * Description: Interface between IrCOMM and IrLMP
- * Status: Stable
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Jun 6 20:48:27 1999
- * Modified at: Sun Dec 12 13:44:17 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- * Sources: Previous IrLPT work by Thomas Davis
- *
- * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
- * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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/init.h>
-#include <linux/gfp.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/iriap.h>
-#include <net/irda/irda_device.h> /* struct irda_skb_cb */
-
-#include <net/irda/ircomm_event.h>
-#include <net/irda/ircomm_lmp.h>
-
-
-/*
- * Function ircomm_lmp_connect_request (self, userdata)
- *
- *
- *
- */
-static int ircomm_lmp_connect_request(struct ircomm_cb *self,
- struct sk_buff *userdata,
- struct ircomm_info *info)
-{
- int ret = 0;
-
- /* Don't forget to refcount it - should be NULL anyway */
- if(userdata)
- skb_get(userdata);
-
- ret = irlmp_connect_request(self->lsap, info->dlsap_sel,
- info->saddr, info->daddr, NULL, userdata);
- return ret;
-}
-
-/*
- * Function ircomm_lmp_connect_response (self, skb)
- *
- *
- *
- */
-static int ircomm_lmp_connect_response(struct ircomm_cb *self,
- struct sk_buff *userdata)
-{
- struct sk_buff *tx_skb;
-
- /* Any userdata supplied? */
- if (userdata == NULL) {
- tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
- if (!tx_skb)
- return -ENOMEM;
-
- /* Reserve space for MUX and LAP header */
- skb_reserve(tx_skb, LMP_MAX_HEADER);
- } else {
- /*
- * Check that the client has reserved enough space for
- * headers
- */
- IRDA_ASSERT(skb_headroom(userdata) >= LMP_MAX_HEADER,
- return -1;);
-
- /* Don't forget to refcount it - should be NULL anyway */
- skb_get(userdata);
- tx_skb = userdata;
- }
-
- return irlmp_connect_response(self->lsap, tx_skb);
-}
-
-static int ircomm_lmp_disconnect_request(struct ircomm_cb *self,
- struct sk_buff *userdata,
- struct ircomm_info *info)
-{
- struct sk_buff *tx_skb;
- int ret;
-
- if (!userdata) {
- tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
- if (!tx_skb)
- return -ENOMEM;
-
- /* Reserve space for MUX and LAP header */
- skb_reserve(tx_skb, LMP_MAX_HEADER);
- userdata = tx_skb;
- } else {
- /* Don't forget to refcount it - should be NULL anyway */
- skb_get(userdata);
- }
-
- ret = irlmp_disconnect_request(self->lsap, userdata);
-
- return ret;
-}
-
-/*
- * Function ircomm_lmp_flow_control (skb)
- *
- * This function is called when a data frame we have sent to IrLAP has
- * been deallocated. We do this to make sure we don't flood IrLAP with
- * frames, since we are not using the IrTTP flow control mechanism
- */
-static void ircomm_lmp_flow_control(struct sk_buff *skb)
-{
- struct irda_skb_cb *cb;
- struct ircomm_cb *self;
- int line;
-
- IRDA_ASSERT(skb != NULL, return;);
-
- cb = (struct irda_skb_cb *) skb->cb;
-
- line = cb->line;
-
- self = (struct ircomm_cb *) hashbin_lock_find(ircomm, line, NULL);
- if (!self) {
- pr_debug("%s(), didn't find myself\n", __func__);
- return;
- }
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
-
- self->pkt_count--;
-
- if ((self->pkt_count < 2) && (self->flow_status == FLOW_STOP)) {
- pr_debug("%s(), asking TTY to start again!\n", __func__);
- self->flow_status = FLOW_START;
- if (self->notify.flow_indication)
- self->notify.flow_indication(self->notify.instance,
- self, FLOW_START);
- }
-}
-
-/*
- * Function ircomm_lmp_data_request (self, userdata)
- *
- * Send data frame to peer device
- *
- */
-static int ircomm_lmp_data_request(struct ircomm_cb *self,
- struct sk_buff *skb,
- int not_used)
-{
- struct irda_skb_cb *cb;
- int ret;
-
- IRDA_ASSERT(skb != NULL, return -1;);
-
- cb = (struct irda_skb_cb *) skb->cb;
-
- cb->line = self->line;
-
- pr_debug("%s(), sending frame\n", __func__);
-
- /* Don't forget to refcount it - see ircomm_tty_do_softint() */
- skb_get(skb);
-
- skb_orphan(skb);
- skb->destructor = ircomm_lmp_flow_control;
-
- if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) {
- pr_debug("%s(), asking TTY to slow down!\n", __func__);
- self->flow_status = FLOW_STOP;
- if (self->notify.flow_indication)
- self->notify.flow_indication(self->notify.instance,
- self, FLOW_STOP);
- }
- ret = irlmp_data_request(self->lsap, skb);
- if (ret) {
- net_err_ratelimited("%s(), failed\n", __func__);
- /* irlmp_data_request already free the packet */
- }
-
- return ret;
-}
-
-/*
- * Function ircomm_lmp_data_indication (instance, sap, skb)
- *
- * Incoming data which we must deliver to the state machine, to check
- * we are still connected.
- */
-static int ircomm_lmp_data_indication(void *instance, void *sap,
- struct sk_buff *skb)
-{
- struct ircomm_cb *self = (struct ircomm_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
- IRDA_ASSERT(skb != NULL, return -1;);
-
- ircomm_do_event(self, IRCOMM_LMP_DATA_INDICATION, skb, NULL);
-
- /* Drop reference count - see ircomm_tty_data_indication(). */
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
- * Function ircomm_lmp_connect_confirm (instance, sap, qos, max_sdu_size,
- * max_header_size, skb)
- *
- * Connection has been confirmed by peer device
- *
- */
-static void ircomm_lmp_connect_confirm(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_seg_size,
- __u8 max_header_size,
- struct sk_buff *skb)
-{
- struct ircomm_cb *self = (struct ircomm_cb *) instance;
- struct ircomm_info info;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
- IRDA_ASSERT(qos != NULL, return;);
-
- info.max_data_size = max_seg_size;
- info.max_header_size = max_header_size;
- info.qos = qos;
-
- ircomm_do_event(self, IRCOMM_LMP_CONNECT_CONFIRM, skb, &info);
-
- /* Drop reference count - see ircomm_tty_connect_confirm(). */
- dev_kfree_skb(skb);
-}
-
-/*
- * Function ircomm_lmp_connect_indication (instance, sap, qos, max_sdu_size,
- * max_header_size, skb)
- *
- * Peer device wants to make a connection with us
- *
- */
-static void ircomm_lmp_connect_indication(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_seg_size,
- __u8 max_header_size,
- struct sk_buff *skb)
-{
- struct ircomm_cb *self = (struct ircomm_cb *)instance;
- struct ircomm_info info;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
- IRDA_ASSERT(qos != NULL, return;);
-
- info.max_data_size = max_seg_size;
- info.max_header_size = max_header_size;
- info.qos = qos;
-
- ircomm_do_event(self, IRCOMM_LMP_CONNECT_INDICATION, skb, &info);
-
- /* Drop reference count - see ircomm_tty_connect_indication(). */
- dev_kfree_skb(skb);
-}
-
-/*
- * Function ircomm_lmp_disconnect_indication (instance, sap, reason, skb)
- *
- * Peer device has closed the connection, or the link went down for some
- * other reason
- */
-static void ircomm_lmp_disconnect_indication(void *instance, void *sap,
- LM_REASON reason,
- struct sk_buff *skb)
-{
- struct ircomm_cb *self = (struct ircomm_cb *) instance;
- struct ircomm_info info;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
-
- info.reason = reason;
-
- ircomm_do_event(self, IRCOMM_LMP_DISCONNECT_INDICATION, skb, &info);
-
- /* Drop reference count - see ircomm_tty_disconnect_indication(). */
- if(skb)
- dev_kfree_skb(skb);
-}
-/*
- * Function ircomm_open_lsap (self)
- *
- * Open LSAP. This function will only be used when using "raw" services
- *
- */
-int ircomm_open_lsap(struct ircomm_cb *self)
-{
- notify_t notify;
-
- /* Register callbacks */
- irda_notify_init(&notify);
- notify.data_indication = ircomm_lmp_data_indication;
- notify.connect_confirm = ircomm_lmp_connect_confirm;
- notify.connect_indication = ircomm_lmp_connect_indication;
- notify.disconnect_indication = ircomm_lmp_disconnect_indication;
- notify.instance = self;
- strlcpy(notify.name, "IrCOMM", sizeof(notify.name));
-
- self->lsap = irlmp_open_lsap(LSAP_ANY, &notify, 0);
- if (!self->lsap) {
- pr_debug("%sfailed to allocate tsap\n", __func__);
- return -1;
- }
- self->slsap_sel = self->lsap->slsap_sel;
-
- /*
- * Initialize the call-table for issuing commands
- */
- self->issue.data_request = ircomm_lmp_data_request;
- self->issue.connect_request = ircomm_lmp_connect_request;
- self->issue.connect_response = ircomm_lmp_connect_response;
- self->issue.disconnect_request = ircomm_lmp_disconnect_request;
-
- return 0;
-}
diff --git a/drivers/staging/irda/net/ircomm/ircomm_param.c b/drivers/staging/irda/net/ircomm/ircomm_param.c
deleted file mode 100644
index 5728e76ca6d5..000000000000
--- a/drivers/staging/irda/net/ircomm/ircomm_param.c
+++ /dev/null
@@ -1,501 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_param.c
- * Version: 1.0
- * Description: Parameter handling for the IrCOMM protocol
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Jun 7 10:25:11 1999
- * Modified at: Sun Jan 30 14:32:03 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999-2000 Dag Brattli, 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.
- *
- * 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/gfp.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/parameters.h>
-
-#include <net/irda/ircomm_core.h>
-#include <net/irda/ircomm_tty_attach.h>
-#include <net/irda/ircomm_tty.h>
-
-#include <net/irda/ircomm_param.h>
-
-static int ircomm_param_service_type(void *instance, irda_param_t *param,
- int get);
-static int ircomm_param_port_type(void *instance, irda_param_t *param,
- int get);
-static int ircomm_param_port_name(void *instance, irda_param_t *param,
- int get);
-static int ircomm_param_service_type(void *instance, irda_param_t *param,
- int get);
-static int ircomm_param_data_rate(void *instance, irda_param_t *param,
- int get);
-static int ircomm_param_data_format(void *instance, irda_param_t *param,
- int get);
-static int ircomm_param_flow_control(void *instance, irda_param_t *param,
- int get);
-static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get);
-static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get);
-static int ircomm_param_line_status(void *instance, irda_param_t *param,
- int get);
-static int ircomm_param_dte(void *instance, irda_param_t *param, int get);
-static int ircomm_param_dce(void *instance, irda_param_t *param, int get);
-static int ircomm_param_poll(void *instance, irda_param_t *param, int get);
-
-static const pi_minor_info_t pi_minor_call_table_common[] = {
- { ircomm_param_service_type, PV_INT_8_BITS },
- { ircomm_param_port_type, PV_INT_8_BITS },
- { ircomm_param_port_name, PV_STRING }
-};
-static const pi_minor_info_t pi_minor_call_table_non_raw[] = {
- { ircomm_param_data_rate, PV_INT_32_BITS | PV_BIG_ENDIAN },
- { ircomm_param_data_format, PV_INT_8_BITS },
- { ircomm_param_flow_control, PV_INT_8_BITS },
- { ircomm_param_xon_xoff, PV_INT_16_BITS },
- { ircomm_param_enq_ack, PV_INT_16_BITS },
- { ircomm_param_line_status, PV_INT_8_BITS }
-};
-static const pi_minor_info_t pi_minor_call_table_9_wire[] = {
- { ircomm_param_dte, PV_INT_8_BITS },
- { ircomm_param_dce, PV_INT_8_BITS },
- { ircomm_param_poll, PV_NO_VALUE },
-};
-
-static const pi_major_info_t pi_major_call_table[] = {
- { pi_minor_call_table_common, 3 },
- { pi_minor_call_table_non_raw, 6 },
- { pi_minor_call_table_9_wire, 3 }
-/* { pi_minor_call_table_centronics } */
-};
-
-pi_param_info_t ircomm_param_info = { pi_major_call_table, 3, 0x0f, 4 };
-
-/*
- * Function ircomm_param_request (self, pi, flush)
- *
- * Queue a parameter for the control channel
- *
- */
-int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
-{
- unsigned long flags;
- struct sk_buff *skb;
- int count;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- /* Make sure we don't send parameters for raw mode */
- if (self->service_type == IRCOMM_3_WIRE_RAW)
- return 0;
-
- spin_lock_irqsave(&self->spinlock, flags);
-
- skb = self->ctrl_skb;
- if (!skb) {
- skb = alloc_skb(256, GFP_ATOMIC);
- if (!skb) {
- spin_unlock_irqrestore(&self->spinlock, flags);
- return -ENOMEM;
- }
-
- skb_reserve(skb, self->max_header_size);
- self->ctrl_skb = skb;
- }
- /*
- * Inserting is a little bit tricky since we don't know how much
- * room we will need. But this should hopefully work OK
- */
- count = irda_param_insert(self, pi, skb_tail_pointer(skb),
- skb_tailroom(skb), &ircomm_param_info);
- if (count < 0) {
- net_warn_ratelimited("%s(), no room for parameter!\n",
- __func__);
- spin_unlock_irqrestore(&self->spinlock, flags);
- return -1;
- }
- skb_put(skb, count);
- pr_debug("%s(), skb->len=%d\n", __func__, skb->len);
-
- spin_unlock_irqrestore(&self->spinlock, flags);
-
- if (flush) {
- /* ircomm_tty_do_softint will take care of the rest */
- schedule_work(&self->tqueue);
- }
-
- return count;
-}
-
-/*
- * Function ircomm_param_service_type (self, buf, len)
- *
- * Handle service type, this function will both be called after the LM-IAS
- * query and then the remote device sends its initial parameters
- *
- */
-static int ircomm_param_service_type(void *instance, irda_param_t *param,
- int get)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
- __u8 service_type = (__u8) param->pv.i;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- if (get) {
- param->pv.i = self->settings.service_type;
- return 0;
- }
-
- /* Find all common service types */
- service_type &= self->service_type;
- if (!service_type) {
- pr_debug("%s(), No common service type to use!\n", __func__);
- return -1;
- }
- pr_debug("%s(), services in common=%02x\n", __func__ ,
- service_type);
-
- /*
- * Now choose a preferred service type of those available
- */
- if (service_type & IRCOMM_CENTRONICS)
- self->settings.service_type = IRCOMM_CENTRONICS;
- else if (service_type & IRCOMM_9_WIRE)
- self->settings.service_type = IRCOMM_9_WIRE;
- else if (service_type & IRCOMM_3_WIRE)
- self->settings.service_type = IRCOMM_3_WIRE;
- else if (service_type & IRCOMM_3_WIRE_RAW)
- self->settings.service_type = IRCOMM_3_WIRE_RAW;
-
- pr_debug("%s(), resulting service type=0x%02x\n", __func__ ,
- self->settings.service_type);
-
- /*
- * Now the line is ready for some communication. Check if we are a
- * server, and send over some initial parameters.
- * Client do it in ircomm_tty_state_setup().
- * Note : we may get called from ircomm_tty_getvalue_confirm(),
- * therefore before we even have open any socket. And self->client
- * is initialised to TRUE only later. So, we check if the link is
- * really initialised. - Jean II
- */
- if ((self->max_header_size != IRCOMM_TTY_HDR_UNINITIALISED) &&
- (!self->client) &&
- (self->settings.service_type != IRCOMM_3_WIRE_RAW))
- {
- /* Init connection */
- ircomm_tty_send_initial_parameters(self);
- ircomm_tty_link_established(self);
- }
-
- return 0;
-}
-
-/*
- * Function ircomm_param_port_type (self, param)
- *
- * The port type parameter tells if the devices are serial or parallel.
- * Since we only advertise serial service, this parameter should only
- * be equal to IRCOMM_SERIAL.
- */
-static int ircomm_param_port_type(void *instance, irda_param_t *param, int get)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- if (get)
- param->pv.i = IRCOMM_SERIAL;
- else {
- self->settings.port_type = (__u8) param->pv.i;
-
- pr_debug("%s(), port type=%d\n", __func__ ,
- self->settings.port_type);
- }
- return 0;
-}
-
-/*
- * Function ircomm_param_port_name (self, param)
- *
- * Exchange port name
- *
- */
-static int ircomm_param_port_name(void *instance, irda_param_t *param, int get)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- if (get) {
- pr_debug("%s(), not imp!\n", __func__);
- } else {
- pr_debug("%s(), port-name=%s\n", __func__ , param->pv.c);
- strncpy(self->settings.port_name, param->pv.c, 32);
- }
-
- return 0;
-}
-
-/*
- * Function ircomm_param_data_rate (self, param)
- *
- * Exchange data rate to be used in this settings
- *
- */
-static int ircomm_param_data_rate(void *instance, irda_param_t *param, int get)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- if (get)
- param->pv.i = self->settings.data_rate;
- else
- self->settings.data_rate = param->pv.i;
-
- pr_debug("%s(), data rate = %d\n", __func__ , param->pv.i);
-
- return 0;
-}
-
-/*
- * Function ircomm_param_data_format (self, param)
- *
- * Exchange data format to be used in this settings
- *
- */
-static int ircomm_param_data_format(void *instance, irda_param_t *param,
- int get)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- if (get)
- param->pv.i = self->settings.data_format;
- else
- self->settings.data_format = (__u8) param->pv.i;
-
- return 0;
-}
-
-/*
- * Function ircomm_param_flow_control (self, param)
- *
- * Exchange flow control settings to be used in this settings
- *
- */
-static int ircomm_param_flow_control(void *instance, irda_param_t *param,
- int get)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- if (get)
- param->pv.i = self->settings.flow_control;
- else
- self->settings.flow_control = (__u8) param->pv.i;
-
- pr_debug("%s(), flow control = 0x%02x\n", __func__ , (__u8)param->pv.i);
-
- return 0;
-}
-
-/*
- * Function ircomm_param_xon_xoff (self, param)
- *
- * Exchange XON/XOFF characters
- *
- */
-static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- if (get) {
- param->pv.i = self->settings.xonxoff[0];
- param->pv.i |= self->settings.xonxoff[1] << 8;
- } else {
- self->settings.xonxoff[0] = (__u16) param->pv.i & 0xff;
- self->settings.xonxoff[1] = (__u16) param->pv.i >> 8;
- }
-
- pr_debug("%s(), XON/XOFF = 0x%02x,0x%02x\n", __func__ ,
- param->pv.i & 0xff, param->pv.i >> 8);
-
- return 0;
-}
-
-/*
- * Function ircomm_param_enq_ack (self, param)
- *
- * Exchange ENQ/ACK characters
- *
- */
-static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- if (get) {
- param->pv.i = self->settings.enqack[0];
- param->pv.i |= self->settings.enqack[1] << 8;
- } else {
- self->settings.enqack[0] = (__u16) param->pv.i & 0xff;
- self->settings.enqack[1] = (__u16) param->pv.i >> 8;
- }
-
- pr_debug("%s(), ENQ/ACK = 0x%02x,0x%02x\n", __func__ ,
- param->pv.i & 0xff, param->pv.i >> 8);
-
- return 0;
-}
-
-/*
- * Function ircomm_param_line_status (self, param)
- *
- *
- *
- */
-static int ircomm_param_line_status(void *instance, irda_param_t *param,
- int get)
-{
- pr_debug("%s(), not impl.\n", __func__);
-
- return 0;
-}
-
-/*
- * Function ircomm_param_dte (instance, param)
- *
- * If we get here, there must be some sort of null-modem connection, and
- * we are probably working in server mode as well.
- */
-static int ircomm_param_dte(void *instance, irda_param_t *param, int get)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
- __u8 dte;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- if (get)
- param->pv.i = self->settings.dte;
- else {
- dte = (__u8) param->pv.i;
-
- self->settings.dce = 0;
-
- if (dte & IRCOMM_DELTA_DTR)
- self->settings.dce |= (IRCOMM_DELTA_DSR|
- IRCOMM_DELTA_RI |
- IRCOMM_DELTA_CD);
- if (dte & IRCOMM_DTR)
- self->settings.dce |= (IRCOMM_DSR|
- IRCOMM_RI |
- IRCOMM_CD);
-
- if (dte & IRCOMM_DELTA_RTS)
- self->settings.dce |= IRCOMM_DELTA_CTS;
- if (dte & IRCOMM_RTS)
- self->settings.dce |= IRCOMM_CTS;
-
- /* Take appropriate actions */
- ircomm_tty_check_modem_status(self);
-
- /* Null modem cable emulator */
- self->settings.null_modem = TRUE;
- }
-
- return 0;
-}
-
-/*
- * Function ircomm_param_dce (instance, param)
- *
- *
- *
- */
-static int ircomm_param_dce(void *instance, irda_param_t *param, int get)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
- __u8 dce;
-
- pr_debug("%s(), dce = 0x%02x\n", __func__ , (__u8)param->pv.i);
-
- dce = (__u8) param->pv.i;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- self->settings.dce = dce;
-
- /* Check if any of the settings have changed */
- if (dce & 0x0f) {
- if (dce & IRCOMM_DELTA_CTS) {
- pr_debug("%s(), CTS\n", __func__);
- }
- }
-
- ircomm_tty_check_modem_status(self);
-
- return 0;
-}
-
-/*
- * Function ircomm_param_poll (instance, param)
- *
- * Called when the peer device is polling for the line settings
- *
- */
-static int ircomm_param_poll(void *instance, irda_param_t *param, int get)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- /* Poll parameters are always of length 0 (just a signal) */
- if (!get) {
- /* Respond with DTE line settings */
- ircomm_param_request(self, IRCOMM_DTE, TRUE);
- }
- return 0;
-}
-
-
-
-
-
diff --git a/drivers/staging/irda/net/ircomm/ircomm_ttp.c b/drivers/staging/irda/net/ircomm/ircomm_ttp.c
deleted file mode 100644
index 4b81e0934770..000000000000
--- a/drivers/staging/irda/net/ircomm/ircomm_ttp.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_ttp.c
- * Version: 1.0
- * Description: Interface between IrCOMM and IrTTP
- * Status: Stable
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Jun 6 20:48:27 1999
- * Modified at: Mon Dec 13 11:35:13 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
- * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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/init.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/iriap.h>
-#include <net/irda/irttp.h>
-
-#include <net/irda/ircomm_event.h>
-#include <net/irda/ircomm_ttp.h>
-
-static int ircomm_ttp_data_indication(void *instance, void *sap,
- struct sk_buff *skb);
-static void ircomm_ttp_connect_confirm(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *skb);
-static void ircomm_ttp_connect_indication(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *skb);
-static void ircomm_ttp_flow_indication(void *instance, void *sap,
- LOCAL_FLOW cmd);
-static void ircomm_ttp_disconnect_indication(void *instance, void *sap,
- LM_REASON reason,
- struct sk_buff *skb);
-static int ircomm_ttp_data_request(struct ircomm_cb *self,
- struct sk_buff *skb,
- int clen);
-static int ircomm_ttp_connect_request(struct ircomm_cb *self,
- struct sk_buff *userdata,
- struct ircomm_info *info);
-static int ircomm_ttp_connect_response(struct ircomm_cb *self,
- struct sk_buff *userdata);
-static int ircomm_ttp_disconnect_request(struct ircomm_cb *self,
- struct sk_buff *userdata,
- struct ircomm_info *info);
-
-/*
- * Function ircomm_open_tsap (self)
- *
- *
- *
- */
-int ircomm_open_tsap(struct ircomm_cb *self)
-{
- notify_t notify;
-
- /* Register callbacks */
- irda_notify_init(&notify);
- notify.data_indication = ircomm_ttp_data_indication;
- notify.connect_confirm = ircomm_ttp_connect_confirm;
- notify.connect_indication = ircomm_ttp_connect_indication;
- notify.flow_indication = ircomm_ttp_flow_indication;
- notify.disconnect_indication = ircomm_ttp_disconnect_indication;
- notify.instance = self;
- strlcpy(notify.name, "IrCOMM", sizeof(notify.name));
-
- self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
- &notify);
- if (!self->tsap) {
- pr_debug("%sfailed to allocate tsap\n", __func__);
- return -1;
- }
- self->slsap_sel = self->tsap->stsap_sel;
-
- /*
- * Initialize the call-table for issuing commands
- */
- self->issue.data_request = ircomm_ttp_data_request;
- self->issue.connect_request = ircomm_ttp_connect_request;
- self->issue.connect_response = ircomm_ttp_connect_response;
- self->issue.disconnect_request = ircomm_ttp_disconnect_request;
-
- return 0;
-}
-
-/*
- * Function ircomm_ttp_connect_request (self, userdata)
- *
- *
- *
- */
-static int ircomm_ttp_connect_request(struct ircomm_cb *self,
- struct sk_buff *userdata,
- struct ircomm_info *info)
-{
- int ret = 0;
-
- /* Don't forget to refcount it - should be NULL anyway */
- if(userdata)
- skb_get(userdata);
-
- ret = irttp_connect_request(self->tsap, info->dlsap_sel,
- info->saddr, info->daddr, NULL,
- TTP_SAR_DISABLE, userdata);
-
- return ret;
-}
-
-/*
- * Function ircomm_ttp_connect_response (self, skb)
- *
- *
- *
- */
-static int ircomm_ttp_connect_response(struct ircomm_cb *self,
- struct sk_buff *userdata)
-{
- int ret;
-
- /* Don't forget to refcount it - should be NULL anyway */
- if(userdata)
- skb_get(userdata);
-
- ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, userdata);
-
- return ret;
-}
-
-/*
- * Function ircomm_ttp_data_request (self, userdata)
- *
- * Send IrCOMM data to IrTTP layer. Currently we do not try to combine
- * control data with pure data, so they will be sent as separate frames.
- * Should not be a big problem though, since control frames are rare. But
- * some of them are sent after connection establishment, so this can
- * increase the latency a bit.
- */
-static int ircomm_ttp_data_request(struct ircomm_cb *self,
- struct sk_buff *skb,
- int clen)
-{
- int ret;
-
- IRDA_ASSERT(skb != NULL, return -1;);
-
- pr_debug("%s(), clen=%d\n", __func__ , clen);
-
- /*
- * Insert clen field, currently we either send data only, or control
- * only frames, to make things easier and avoid queueing
- */
- IRDA_ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;);
-
- /* Don't forget to refcount it - see ircomm_tty_do_softint() */
- skb_get(skb);
-
- skb_push(skb, IRCOMM_HEADER_SIZE);
-
- skb->data[0] = clen;
-
- ret = irttp_data_request(self->tsap, skb);
- if (ret) {
- net_err_ratelimited("%s(), failed\n", __func__);
- /* irttp_data_request already free the packet */
- }
-
- return ret;
-}
-
-/*
- * Function ircomm_ttp_data_indication (instance, sap, skb)
- *
- * Incoming data
- *
- */
-static int ircomm_ttp_data_indication(void *instance, void *sap,
- struct sk_buff *skb)
-{
- struct ircomm_cb *self = (struct ircomm_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
- IRDA_ASSERT(skb != NULL, return -1;);
-
- ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL);
-
- /* Drop reference count - see ircomm_tty_data_indication(). */
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-static void ircomm_ttp_connect_confirm(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *skb)
-{
- struct ircomm_cb *self = (struct ircomm_cb *) instance;
- struct ircomm_info info;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
- IRDA_ASSERT(qos != NULL, goto out;);
-
- if (max_sdu_size != TTP_SAR_DISABLE) {
- net_err_ratelimited("%s(), SAR not allowed for IrCOMM!\n",
- __func__);
- goto out;
- }
-
- info.max_data_size = irttp_get_max_seg_size(self->tsap)
- - IRCOMM_HEADER_SIZE;
- info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
- info.qos = qos;
-
- ircomm_do_event(self, IRCOMM_TTP_CONNECT_CONFIRM, skb, &info);
-
-out:
- /* Drop reference count - see ircomm_tty_connect_confirm(). */
- dev_kfree_skb(skb);
-}
-
-/*
- * Function ircomm_ttp_connect_indication (instance, sap, qos, max_sdu_size,
- * max_header_size, skb)
- *
- *
- *
- */
-static void ircomm_ttp_connect_indication(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *skb)
-{
- struct ircomm_cb *self = (struct ircomm_cb *)instance;
- struct ircomm_info info;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
- IRDA_ASSERT(qos != NULL, goto out;);
-
- if (max_sdu_size != TTP_SAR_DISABLE) {
- net_err_ratelimited("%s(), SAR not allowed for IrCOMM!\n",
- __func__);
- goto out;
- }
-
- info.max_data_size = irttp_get_max_seg_size(self->tsap)
- - IRCOMM_HEADER_SIZE;
- info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
- info.qos = qos;
-
- ircomm_do_event(self, IRCOMM_TTP_CONNECT_INDICATION, skb, &info);
-
-out:
- /* Drop reference count - see ircomm_tty_connect_indication(). */
- dev_kfree_skb(skb);
-}
-
-/*
- * Function ircomm_ttp_disconnect_request (self, userdata, info)
- *
- *
- *
- */
-static int ircomm_ttp_disconnect_request(struct ircomm_cb *self,
- struct sk_buff *userdata,
- struct ircomm_info *info)
-{
- int ret;
-
- /* Don't forget to refcount it - should be NULL anyway */
- if(userdata)
- skb_get(userdata);
-
- ret = irttp_disconnect_request(self->tsap, userdata, P_NORMAL);
-
- return ret;
-}
-
-/*
- * Function ircomm_ttp_disconnect_indication (instance, sap, reason, skb)
- *
- *
- *
- */
-static void ircomm_ttp_disconnect_indication(void *instance, void *sap,
- LM_REASON reason,
- struct sk_buff *skb)
-{
- struct ircomm_cb *self = (struct ircomm_cb *) instance;
- struct ircomm_info info;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
-
- info.reason = reason;
-
- ircomm_do_event(self, IRCOMM_TTP_DISCONNECT_INDICATION, skb, &info);
-
- /* Drop reference count - see ircomm_tty_disconnect_indication(). */
- if(skb)
- dev_kfree_skb(skb);
-}
-
-/*
- * Function ircomm_ttp_flow_indication (instance, sap, cmd)
- *
- * Layer below is telling us to start or stop the flow of data
- *
- */
-static void ircomm_ttp_flow_indication(void *instance, void *sap,
- LOCAL_FLOW cmd)
-{
- struct ircomm_cb *self = (struct ircomm_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
-
- if (self->notify.flow_indication)
- self->notify.flow_indication(self->notify.instance, self, cmd);
-}
-
-
diff --git a/drivers/staging/irda/net/ircomm/ircomm_tty.c b/drivers/staging/irda/net/ircomm/ircomm_tty.c
deleted file mode 100644
index 473abfaffe7b..000000000000
--- a/drivers/staging/irda/net/ircomm/ircomm_tty.c
+++ /dev/null
@@ -1,1329 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_tty.c
- * Version: 1.0
- * Description: IrCOMM serial TTY driver
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Jun 6 21:00:56 1999
- * Modified at: Wed Feb 23 00:09:02 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- * Sources: serial.c and previous IrCOMM work by Takahide Higuchi
- *
- * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
- * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/sched/signal.h>
-#include <linux/seq_file.h>
-#include <linux/termios.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/interrupt.h>
-#include <linux/device.h> /* for MODULE_ALIAS_CHARDEV_MAJOR */
-
-#include <linux/uaccess.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irmod.h>
-
-#include <net/irda/ircomm_core.h>
-#include <net/irda/ircomm_param.h>
-#include <net/irda/ircomm_tty_attach.h>
-#include <net/irda/ircomm_tty.h>
-
-static int ircomm_tty_install(struct tty_driver *driver,
- struct tty_struct *tty);
-static int ircomm_tty_open(struct tty_struct *tty, struct file *filp);
-static void ircomm_tty_close(struct tty_struct * tty, struct file *filp);
-static int ircomm_tty_write(struct tty_struct * tty,
- const unsigned char *buf, int count);
-static int ircomm_tty_write_room(struct tty_struct *tty);
-static void ircomm_tty_throttle(struct tty_struct *tty);
-static void ircomm_tty_unthrottle(struct tty_struct *tty);
-static int ircomm_tty_chars_in_buffer(struct tty_struct *tty);
-static void ircomm_tty_flush_buffer(struct tty_struct *tty);
-static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch);
-static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout);
-static void ircomm_tty_hangup(struct tty_struct *tty);
-static void ircomm_tty_do_softint(struct work_struct *work);
-static void ircomm_tty_shutdown(struct ircomm_tty_cb *self);
-static void ircomm_tty_stop(struct tty_struct *tty);
-
-static int ircomm_tty_data_indication(void *instance, void *sap,
- struct sk_buff *skb);
-static int ircomm_tty_control_indication(void *instance, void *sap,
- struct sk_buff *skb);
-static void ircomm_tty_flow_indication(void *instance, void *sap,
- LOCAL_FLOW cmd);
-#ifdef CONFIG_PROC_FS
-static const struct file_operations ircomm_tty_proc_fops;
-#endif /* CONFIG_PROC_FS */
-static struct tty_driver *driver;
-
-static hashbin_t *ircomm_tty = NULL;
-
-static const struct tty_operations ops = {
- .install = ircomm_tty_install,
- .open = ircomm_tty_open,
- .close = ircomm_tty_close,
- .write = ircomm_tty_write,
- .write_room = ircomm_tty_write_room,
- .chars_in_buffer = ircomm_tty_chars_in_buffer,
- .flush_buffer = ircomm_tty_flush_buffer,
- .ioctl = ircomm_tty_ioctl, /* ircomm_tty_ioctl.c */
- .tiocmget = ircomm_tty_tiocmget, /* ircomm_tty_ioctl.c */
- .tiocmset = ircomm_tty_tiocmset, /* ircomm_tty_ioctl.c */
- .throttle = ircomm_tty_throttle,
- .unthrottle = ircomm_tty_unthrottle,
- .send_xchar = ircomm_tty_send_xchar,
- .set_termios = ircomm_tty_set_termios,
- .stop = ircomm_tty_stop,
- .start = ircomm_tty_start,
- .hangup = ircomm_tty_hangup,
- .wait_until_sent = ircomm_tty_wait_until_sent,
-#ifdef CONFIG_PROC_FS
- .proc_fops = &ircomm_tty_proc_fops,
-#endif /* CONFIG_PROC_FS */
-};
-
-static void ircomm_port_raise_dtr_rts(struct tty_port *port, int raise)
-{
- struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb,
- port);
- /*
- * Here, we use to lock those two guys, but as ircomm_param_request()
- * does it itself, I don't see the point (and I see the deadlock).
- * Jean II
- */
- if (raise)
- self->settings.dte |= IRCOMM_RTS | IRCOMM_DTR;
- else
- self->settings.dte &= ~(IRCOMM_RTS | IRCOMM_DTR);
-
- ircomm_param_request(self, IRCOMM_DTE, TRUE);
-}
-
-static int ircomm_port_carrier_raised(struct tty_port *port)
-{
- struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb,
- port);
- return self->settings.dce & IRCOMM_CD;
-}
-
-static const struct tty_port_operations ircomm_port_ops = {
- .dtr_rts = ircomm_port_raise_dtr_rts,
- .carrier_raised = ircomm_port_carrier_raised,
-};
-
-/*
- * Function ircomm_tty_init()
- *
- * Init IrCOMM TTY layer/driver
- *
- */
-static int __init ircomm_tty_init(void)
-{
- driver = alloc_tty_driver(IRCOMM_TTY_PORTS);
- if (!driver)
- return -ENOMEM;
- ircomm_tty = hashbin_new(HB_LOCK);
- if (ircomm_tty == NULL) {
- net_err_ratelimited("%s(), can't allocate hashbin!\n",
- __func__);
- put_tty_driver(driver);
- return -ENOMEM;
- }
-
- driver->driver_name = "ircomm";
- driver->name = "ircomm";
- driver->major = IRCOMM_TTY_MAJOR;
- driver->minor_start = IRCOMM_TTY_MINOR;
- driver->type = TTY_DRIVER_TYPE_SERIAL;
- driver->subtype = SERIAL_TYPE_NORMAL;
- driver->init_termios = tty_std_termios;
- driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(driver, &ops);
- if (tty_register_driver(driver)) {
- net_err_ratelimited("%s(): Couldn't register serial driver\n",
- __func__);
- put_tty_driver(driver);
- return -1;
- }
- return 0;
-}
-
-static void __exit __ircomm_tty_cleanup(struct ircomm_tty_cb *self)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- ircomm_tty_shutdown(self);
-
- self->magic = 0;
- tty_port_destroy(&self->port);
- kfree(self);
-}
-
-/*
- * Function ircomm_tty_cleanup ()
- *
- * Remove IrCOMM TTY layer/driver
- *
- */
-static void __exit ircomm_tty_cleanup(void)
-{
- int ret;
-
- ret = tty_unregister_driver(driver);
- if (ret) {
- net_err_ratelimited("%s(), failed to unregister driver\n",
- __func__);
- return;
- }
-
- hashbin_delete(ircomm_tty, (FREE_FUNC) __ircomm_tty_cleanup);
- put_tty_driver(driver);
-}
-
-/*
- * Function ircomm_startup (self)
- *
- *
- *
- */
-static int ircomm_tty_startup(struct ircomm_tty_cb *self)
-{
- notify_t notify;
- int ret = -ENODEV;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- /* Check if already open */
- if (tty_port_initialized(&self->port)) {
- pr_debug("%s(), already open so break out!\n", __func__);
- return 0;
- }
- tty_port_set_initialized(&self->port, 1);
-
- /* Register with IrCOMM */
- irda_notify_init(&notify);
- /* These callbacks we must handle ourselves */
- notify.data_indication = ircomm_tty_data_indication;
- notify.udata_indication = ircomm_tty_control_indication;
- notify.flow_indication = ircomm_tty_flow_indication;
-
- /* Use the ircomm_tty interface for these ones */
- notify.disconnect_indication = ircomm_tty_disconnect_indication;
- notify.connect_confirm = ircomm_tty_connect_confirm;
- notify.connect_indication = ircomm_tty_connect_indication;
- strlcpy(notify.name, "ircomm_tty", sizeof(notify.name));
- notify.instance = self;
-
- if (!self->ircomm) {
- self->ircomm = ircomm_open(&notify, self->service_type,
- self->line);
- }
- if (!self->ircomm)
- goto err;
-
- self->slsap_sel = self->ircomm->slsap_sel;
-
- /* Connect IrCOMM link with remote device */
- ret = ircomm_tty_attach_cable(self);
- if (ret < 0) {
- net_err_ratelimited("%s(), error attaching cable!\n", __func__);
- goto err;
- }
-
- return 0;
-err:
- tty_port_set_initialized(&self->port, 0);
- return ret;
-}
-
-/*
- * Function ircomm_block_til_ready (self, filp)
- *
- *
- *
- */
-static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
- struct tty_struct *tty, struct file *filp)
-{
- struct tty_port *port = &self->port;
- DECLARE_WAITQUEUE(wait, current);
- int retval;
- int do_clocal = 0;
- unsigned long flags;
-
- /*
- * If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- */
- if (tty_io_error(tty)) {
- tty_port_set_active(port, 1);
- return 0;
- }
-
- if (filp->f_flags & O_NONBLOCK) {
- /* nonblock mode is set */
- if (C_BAUD(tty))
- tty_port_raise_dtr_rts(port);
- tty_port_set_active(port, 1);
- pr_debug("%s(), O_NONBLOCK requested!\n", __func__);
- return 0;
- }
-
- if (C_CLOCAL(tty)) {
- pr_debug("%s(), doing CLOCAL!\n", __func__);
- do_clocal = 1;
- }
-
- /* Wait for carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, port->count is dropped by one, so that
- * mgsl_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
-
- retval = 0;
- add_wait_queue(&port->open_wait, &wait);
-
- pr_debug("%s(%d):block_til_ready before block on %s open_count=%d\n",
- __FILE__, __LINE__, tty->driver->name, port->count);
-
- spin_lock_irqsave(&port->lock, flags);
- port->count--;
- port->blocked_open++;
- spin_unlock_irqrestore(&port->lock, flags);
-
- while (1) {
- if (C_BAUD(tty) && tty_port_initialized(port))
- tty_port_raise_dtr_rts(port);
-
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
- retval = (port->flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS;
- break;
- }
-
- /*
- * Check if link is ready now. Even if CLOCAL is
- * specified, we cannot return before the IrCOMM link is
- * ready
- */
- if ((do_clocal || tty_port_carrier_raised(port)) &&
- self->state == IRCOMM_TTY_READY)
- {
- break;
- }
-
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-
- pr_debug("%s(%d):block_til_ready blocking on %s open_count=%d\n",
- __FILE__, __LINE__, tty->driver->name, port->count);
-
- schedule();
- }
-
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&port->open_wait, &wait);
-
- spin_lock_irqsave(&port->lock, flags);
- if (!tty_hung_up_p(filp))
- port->count++;
- port->blocked_open--;
- spin_unlock_irqrestore(&port->lock, flags);
-
- pr_debug("%s(%d):block_til_ready after blocking on %s open_count=%d\n",
- __FILE__, __LINE__, tty->driver->name, port->count);
-
- if (!retval)
- tty_port_set_active(port, 1);
-
- return retval;
-}
-
-
-static int ircomm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
-{
- struct ircomm_tty_cb *self;
- unsigned int line = tty->index;
-
- /* Check if instance already exists */
- self = hashbin_lock_find(ircomm_tty, line, NULL);
- if (!self) {
- /* No, so make new instance */
- self = kzalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL);
- if (self == NULL)
- return -ENOMEM;
-
- tty_port_init(&self->port);
- self->port.ops = &ircomm_port_ops;
- self->magic = IRCOMM_TTY_MAGIC;
- self->flow = FLOW_STOP;
-
- self->line = line;
- INIT_WORK(&self->tqueue, ircomm_tty_do_softint);
- self->max_header_size = IRCOMM_TTY_HDR_UNINITIALISED;
- self->max_data_size = IRCOMM_TTY_DATA_UNINITIALISED;
-
- /* Init some important stuff */
- timer_setup(&self->watchdog_timer, NULL, 0);
- spin_lock_init(&self->spinlock);
-
- /*
- * Force TTY into raw mode by default which is usually what
- * we want for IrCOMM and IrLPT. This way applications will
- * not have to twiddle with printcap etc.
- *
- * Note this is completely usafe and doesn't work properly
- */
- tty->termios.c_iflag = 0;
- tty->termios.c_oflag = 0;
-
- /* Insert into hash */
- hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL);
- }
-
- tty->driver_data = self;
-
- return tty_port_install(&self->port, driver, tty);
-}
-
-/*
- * Function ircomm_tty_open (tty, filp)
- *
- * This routine is called when a particular tty device is opened. This
- * routine is mandatory; if this routine is not filled in, the attempted
- * open will fail with ENODEV.
- */
-static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
-{
- struct ircomm_tty_cb *self = tty->driver_data;
- unsigned long flags;
- int ret;
-
- /* ++ is not atomic, so this should be protected - Jean II */
- spin_lock_irqsave(&self->port.lock, flags);
- self->port.count++;
- spin_unlock_irqrestore(&self->port.lock, flags);
- tty_port_tty_set(&self->port, tty);
-
- pr_debug("%s(), %s%d, count = %d\n", __func__ , tty->driver->name,
- self->line, self->port.count);
-
- /* Not really used by us, but lets do it anyway */
- self->port.low_latency = (self->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
- /* Check if this is a "normal" ircomm device, or an irlpt device */
- if (self->line < 0x10) {
- self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
- self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */
- /* Jan Kiszka -> add DSR/RI -> Conform to IrCOMM spec */
- self->settings.dce = IRCOMM_CTS | IRCOMM_CD | IRCOMM_DSR | IRCOMM_RI; /* Default line settings */
- pr_debug("%s(), IrCOMM device\n", __func__);
- } else {
- pr_debug("%s(), IrLPT device\n", __func__);
- self->service_type = IRCOMM_3_WIRE_RAW;
- self->settings.service_type = IRCOMM_3_WIRE_RAW; /* Default */
- }
-
- ret = ircomm_tty_startup(self);
- if (ret)
- return ret;
-
- ret = ircomm_tty_block_til_ready(self, tty, filp);
- if (ret) {
- pr_debug("%s(), returning after block_til_ready with %d\n",
- __func__, ret);
-
- return ret;
- }
- return 0;
-}
-
-/*
- * Function ircomm_tty_close (tty, filp)
- *
- * This routine is called when a particular tty device is closed.
- *
- */
-static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- struct tty_port *port = &self->port;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- if (tty_port_close_start(port, tty, filp) == 0)
- return;
-
- ircomm_tty_shutdown(self);
-
- tty_driver_flush_buffer(tty);
-
- tty_port_close_end(port, tty);
- tty_port_tty_set(port, NULL);
-}
-
-/*
- * Function ircomm_tty_flush_buffer (tty)
- *
- *
- *
- */
-static void ircomm_tty_flush_buffer(struct tty_struct *tty)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- /*
- * Let do_softint() do this to avoid race condition with
- * do_softint() ;-)
- */
- schedule_work(&self->tqueue);
-}
-
-/*
- * Function ircomm_tty_do_softint (work)
- *
- * We use this routine to give the write wakeup to the user at at a
- * safe time (as fast as possible after write have completed). This
- * can be compared to the Tx interrupt.
- */
-static void ircomm_tty_do_softint(struct work_struct *work)
-{
- struct ircomm_tty_cb *self =
- container_of(work, struct ircomm_tty_cb, tqueue);
- struct tty_struct *tty;
- unsigned long flags;
- struct sk_buff *skb, *ctrl_skb;
-
- if (!self || self->magic != IRCOMM_TTY_MAGIC)
- return;
-
- tty = tty_port_tty_get(&self->port);
- if (!tty)
- return;
-
- /* Unlink control buffer */
- spin_lock_irqsave(&self->spinlock, flags);
-
- ctrl_skb = self->ctrl_skb;
- self->ctrl_skb = NULL;
-
- spin_unlock_irqrestore(&self->spinlock, flags);
-
- /* Flush control buffer if any */
- if(ctrl_skb) {
- if(self->flow == FLOW_START)
- ircomm_control_request(self->ircomm, ctrl_skb);
- /* Drop reference count - see ircomm_ttp_data_request(). */
- dev_kfree_skb(ctrl_skb);
- }
-
- if (tty->hw_stopped)
- goto put;
-
- /* Unlink transmit buffer */
- spin_lock_irqsave(&self->spinlock, flags);
-
- skb = self->tx_skb;
- self->tx_skb = NULL;
-
- spin_unlock_irqrestore(&self->spinlock, flags);
-
- /* Flush transmit buffer if any */
- if (skb) {
- ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL);
- /* Drop reference count - see ircomm_ttp_data_request(). */
- dev_kfree_skb(skb);
- }
-
- /* Check if user (still) wants to be waken up */
- tty_wakeup(tty);
-put:
- tty_kref_put(tty);
-}
-
-/*
- * Function ircomm_tty_write (tty, buf, count)
- *
- * This routine is called by the kernel to write a series of characters
- * to the tty device. The characters may come from user space or kernel
- * space. This routine will return the number of characters actually
- * accepted for writing. This routine is mandatory.
- */
-static int ircomm_tty_write(struct tty_struct *tty,
- const unsigned char *buf, int count)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- unsigned long flags;
- struct sk_buff *skb;
- int tailroom = 0;
- int len = 0;
- int size;
-
- pr_debug("%s(), count=%d, hw_stopped=%d\n", __func__ , count,
- tty->hw_stopped);
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- /* We may receive packets from the TTY even before we have finished
- * our setup. Not cool.
- * The problem is that we don't know the final header and data size
- * to create the proper skb, so any skb we would create would have
- * bogus header and data size, so need care.
- * We use a bogus header size to safely detect this condition.
- * Another problem is that hw_stopped was set to 0 way before it
- * should be, so we would drop this skb. It should now be fixed.
- * One option is to not accept data until we are properly setup.
- * But, I suspect that when it happens, the ppp line discipline
- * just "drops" the data, which might screw up connect scripts.
- * The second option is to create a "safe skb", with large header
- * and small size (see ircomm_tty_open() for values).
- * We just need to make sure that when the real values get filled,
- * we don't mess up the original "safe skb" (see tx_data_size).
- * Jean II */
- if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED) {
- pr_debug("%s() : not initialised\n", __func__);
-#ifdef IRCOMM_NO_TX_BEFORE_INIT
- /* We didn't consume anything, TTY will retry */
- return 0;
-#endif
- }
-
- if (count < 1)
- return 0;
-
- /* Protect our manipulation of self->tx_skb and related */
- spin_lock_irqsave(&self->spinlock, flags);
-
- /* Fetch current transmit buffer */
- skb = self->tx_skb;
-
- /*
- * Send out all the data we get, possibly as multiple fragmented
- * frames, but this will only happen if the data is larger than the
- * max data size. The normal case however is just the opposite, and
- * this function may be called multiple times, and will then actually
- * defragment the data and send it out as one packet as soon as
- * possible, but at a safer point in time
- */
- while (count) {
- size = count;
-
- /* Adjust data size to the max data size */
- if (size > self->max_data_size)
- size = self->max_data_size;
-
- /*
- * Do we already have a buffer ready for transmit, or do
- * we need to allocate a new frame
- */
- if (skb) {
- /*
- * Any room for more data at the end of the current
- * transmit buffer? Cannot use skb_tailroom, since
- * dev_alloc_skb gives us a larger skb than we
- * requested
- * Note : use tx_data_size, because max_data_size
- * may have changed and we don't want to overwrite
- * the skb. - Jean II
- */
- if ((tailroom = (self->tx_data_size - skb->len)) > 0) {
- /* Adjust data to tailroom */
- if (size > tailroom)
- size = tailroom;
- } else {
- /*
- * Current transmit frame is full, so break
- * out, so we can send it as soon as possible
- */
- break;
- }
- } else {
- /* Prepare a full sized frame */
- skb = alloc_skb(self->max_data_size+
- self->max_header_size,
- GFP_ATOMIC);
- if (!skb) {
- spin_unlock_irqrestore(&self->spinlock, flags);
- return -ENOBUFS;
- }
- skb_reserve(skb, self->max_header_size);
- self->tx_skb = skb;
- /* Remember skb size because max_data_size may
- * change later on - Jean II */
- self->tx_data_size = self->max_data_size;
- }
-
- /* Copy data */
- skb_put_data(skb, buf + len, size);
-
- count -= size;
- len += size;
- }
-
- spin_unlock_irqrestore(&self->spinlock, flags);
-
- /*
- * Schedule a new thread which will transmit the frame as soon
- * as possible, but at a safe point in time. We do this so the
- * "user" can give us data multiple times, as PPP does (because of
- * its 256 byte tx buffer). We will then defragment and send out
- * all this data as one single packet.
- */
- schedule_work(&self->tqueue);
-
- return len;
-}
-
-/*
- * Function ircomm_tty_write_room (tty)
- *
- * This routine returns the numbers of characters the tty driver will
- * accept for queuing to be written. This number is subject to change as
- * output buffers get emptied, or if the output flow control is acted.
- */
-static int ircomm_tty_write_room(struct tty_struct *tty)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- unsigned long flags;
- int ret;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
-#ifdef IRCOMM_NO_TX_BEFORE_INIT
- /* max_header_size tells us if the channel is initialised or not. */
- if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED)
- /* Don't bother us yet */
- return 0;
-#endif
-
- /* Check if we are allowed to transmit any data.
- * hw_stopped is the regular flow control.
- * Jean II */
- if (tty->hw_stopped)
- ret = 0;
- else {
- spin_lock_irqsave(&self->spinlock, flags);
- if (self->tx_skb)
- ret = self->tx_data_size - self->tx_skb->len;
- else
- ret = self->max_data_size;
- spin_unlock_irqrestore(&self->spinlock, flags);
- }
- pr_debug("%s(), ret=%d\n", __func__ , ret);
-
- return ret;
-}
-
-/*
- * Function ircomm_tty_wait_until_sent (tty, timeout)
- *
- * This routine waits until the device has written out all of the
- * characters in its transmitter FIFO.
- */
-static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- unsigned long orig_jiffies, poll_time;
- unsigned long flags;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- orig_jiffies = jiffies;
-
- /* Set poll time to 200 ms */
- poll_time = msecs_to_jiffies(200);
- if (timeout)
- poll_time = min_t(unsigned long, timeout, poll_time);
-
- spin_lock_irqsave(&self->spinlock, flags);
- while (self->tx_skb && self->tx_skb->len) {
- spin_unlock_irqrestore(&self->spinlock, flags);
- schedule_timeout_interruptible(poll_time);
- spin_lock_irqsave(&self->spinlock, flags);
- if (signal_pending(current))
- break;
- if (timeout && time_after(jiffies, orig_jiffies + timeout))
- break;
- }
- spin_unlock_irqrestore(&self->spinlock, flags);
- __set_current_state(TASK_RUNNING);
-}
-
-/*
- * Function ircomm_tty_throttle (tty)
- *
- * This routine notifies the tty driver that input buffers for the line
- * discipline are close to full, and it should somehow signal that no
- * more characters should be sent to the tty.
- */
-static void ircomm_tty_throttle(struct tty_struct *tty)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- /* Software flow control? */
- if (I_IXOFF(tty))
- ircomm_tty_send_xchar(tty, STOP_CHAR(tty));
-
- /* Hardware flow control? */
- if (C_CRTSCTS(tty)) {
- self->settings.dte &= ~IRCOMM_RTS;
- self->settings.dte |= IRCOMM_DELTA_RTS;
-
- ircomm_param_request(self, IRCOMM_DTE, TRUE);
- }
-
- ircomm_flow_request(self->ircomm, FLOW_STOP);
-}
-
-/*
- * Function ircomm_tty_unthrottle (tty)
- *
- * This routine notifies the tty drivers that it should signals that
- * characters can now be sent to the tty without fear of overrunning the
- * input buffers of the line disciplines.
- */
-static void ircomm_tty_unthrottle(struct tty_struct *tty)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- /* Using software flow control? */
- if (I_IXOFF(tty))
- ircomm_tty_send_xchar(tty, START_CHAR(tty));
-
- /* Using hardware flow control? */
- if (C_CRTSCTS(tty)) {
- self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);
-
- ircomm_param_request(self, IRCOMM_DTE, TRUE);
- pr_debug("%s(), FLOW_START\n", __func__);
- }
- ircomm_flow_request(self->ircomm, FLOW_START);
-}
-
-/*
- * Function ircomm_tty_chars_in_buffer (tty)
- *
- * Indicates if there are any data in the buffer
- *
- */
-static int ircomm_tty_chars_in_buffer(struct tty_struct *tty)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- unsigned long flags;
- int len = 0;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- spin_lock_irqsave(&self->spinlock, flags);
-
- if (self->tx_skb)
- len = self->tx_skb->len;
-
- spin_unlock_irqrestore(&self->spinlock, flags);
-
- return len;
-}
-
-static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
-{
- unsigned long flags;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- if (!tty_port_initialized(&self->port))
- return;
- tty_port_set_initialized(&self->port, 0);
-
- ircomm_tty_detach_cable(self);
-
- spin_lock_irqsave(&self->spinlock, flags);
-
- del_timer(&self->watchdog_timer);
-
- /* Free parameter buffer */
- if (self->ctrl_skb) {
- dev_kfree_skb(self->ctrl_skb);
- self->ctrl_skb = NULL;
- }
-
- /* Free transmit buffer */
- if (self->tx_skb) {
- dev_kfree_skb(self->tx_skb);
- self->tx_skb = NULL;
- }
-
- if (self->ircomm) {
- ircomm_close(self->ircomm);
- self->ircomm = NULL;
- }
-
- spin_unlock_irqrestore(&self->spinlock, flags);
-}
-
-/*
- * Function ircomm_tty_hangup (tty)
- *
- * This routine notifies the tty driver that it should hangup the tty
- * device.
- *
- */
-static void ircomm_tty_hangup(struct tty_struct *tty)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- struct tty_port *port = &self->port;
- unsigned long flags;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- /* ircomm_tty_flush_buffer(tty); */
- ircomm_tty_shutdown(self);
-
- spin_lock_irqsave(&port->lock, flags);
- if (port->tty) {
- set_bit(TTY_IO_ERROR, &port->tty->flags);
- tty_kref_put(port->tty);
- }
- port->tty = NULL;
- port->count = 0;
- spin_unlock_irqrestore(&port->lock, flags);
- tty_port_set_active(port, 0);
-
- wake_up_interruptible(&port->open_wait);
-}
-
-/*
- * Function ircomm_tty_send_xchar (tty, ch)
- *
- * This routine is used to send a high-priority XON/XOFF character to
- * the device.
- */
-static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch)
-{
- pr_debug("%s(), not impl\n", __func__);
-}
-
-/*
- * Function ircomm_tty_start (tty)
- *
- * This routine notifies the tty driver that it resume sending
- * characters to the tty device.
- */
-void ircomm_tty_start(struct tty_struct *tty)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
-
- ircomm_flow_request(self->ircomm, FLOW_START);
-}
-
-/*
- * Function ircomm_tty_stop (tty)
- *
- * This routine notifies the tty driver that it should stop outputting
- * characters to the tty device.
- */
-static void ircomm_tty_stop(struct tty_struct *tty)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- ircomm_flow_request(self->ircomm, FLOW_STOP);
-}
-
-/*
- * Function ircomm_check_modem_status (self)
- *
- * Check for any changes in the DCE's line settings. This function should
- * be called whenever the dce parameter settings changes, to update the
- * flow control settings and other things
- */
-void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
-{
- struct tty_struct *tty;
- int status;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- tty = tty_port_tty_get(&self->port);
-
- status = self->settings.dce;
-
- if (status & IRCOMM_DCE_DELTA_ANY) {
- /*wake_up_interruptible(&self->delta_msr_wait);*/
- }
- if (tty_port_check_carrier(&self->port) && (status & IRCOMM_DELTA_CD)) {
- pr_debug("%s(), ircomm%d CD now %s...\n", __func__ , self->line,
- (status & IRCOMM_CD) ? "on" : "off");
-
- if (status & IRCOMM_CD) {
- wake_up_interruptible(&self->port.open_wait);
- } else {
- pr_debug("%s(), Doing serial hangup..\n", __func__);
- if (tty)
- tty_hangup(tty);
-
- /* Hangup will remote the tty, so better break out */
- goto put;
- }
- }
- if (tty && tty_port_cts_enabled(&self->port)) {
- if (tty->hw_stopped) {
- if (status & IRCOMM_CTS) {
- pr_debug("%s(), CTS tx start...\n", __func__);
- tty->hw_stopped = 0;
-
- /* Wake up processes blocked on open */
- wake_up_interruptible(&self->port.open_wait);
-
- schedule_work(&self->tqueue);
- goto put;
- }
- } else {
- if (!(status & IRCOMM_CTS)) {
- pr_debug("%s(), CTS tx stop...\n", __func__);
- tty->hw_stopped = 1;
- }
- }
- }
-put:
- tty_kref_put(tty);
-}
-
-/*
- * Function ircomm_tty_data_indication (instance, sap, skb)
- *
- * Handle incoming data, and deliver it to the line discipline
- *
- */
-static int ircomm_tty_data_indication(void *instance, void *sap,
- struct sk_buff *skb)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
- struct tty_struct *tty;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
- IRDA_ASSERT(skb != NULL, return -1;);
-
- tty = tty_port_tty_get(&self->port);
- if (!tty) {
- pr_debug("%s(), no tty!\n", __func__);
- return 0;
- }
-
- /*
- * If we receive data when hardware is stopped then something is wrong.
- * We try to poll the peers line settings to check if we are up todate.
- * Devices like WinCE can do this, and since they don't send any
- * params, we can just as well declare the hardware for running.
- */
- if (tty->hw_stopped && (self->flow == FLOW_START)) {
- pr_debug("%s(), polling for line settings!\n", __func__);
- ircomm_param_request(self, IRCOMM_POLL, TRUE);
-
- /* We can just as well declare the hardware for running */
- ircomm_tty_send_initial_parameters(self);
- ircomm_tty_link_established(self);
- }
- tty_kref_put(tty);
-
- /*
- * Use flip buffer functions since the code may be called from interrupt
- * context
- */
- tty_insert_flip_string(&self->port, skb->data, skb->len);
- tty_flip_buffer_push(&self->port);
-
- /* No need to kfree_skb - see ircomm_ttp_data_indication() */
-
- return 0;
-}
-
-/*
- * Function ircomm_tty_control_indication (instance, sap, skb)
- *
- * Parse all incoming parameters (easy!)
- *
- */
-static int ircomm_tty_control_indication(void *instance, void *sap,
- struct sk_buff *skb)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
- int clen;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
- IRDA_ASSERT(skb != NULL, return -1;);
-
- clen = skb->data[0];
-
- irda_param_extract_all(self, skb->data+1, IRDA_MIN(skb->len-1, clen),
- &ircomm_param_info);
-
- /* No need to kfree_skb - see ircomm_control_indication() */
-
- return 0;
-}
-
-/*
- * Function ircomm_tty_flow_indication (instance, sap, cmd)
- *
- * This function is called by IrTTP when it wants us to slow down the
- * transmission of data. We just mark the hardware as stopped, and wait
- * for IrTTP to notify us that things are OK again.
- */
-static void ircomm_tty_flow_indication(void *instance, void *sap,
- LOCAL_FLOW cmd)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
- struct tty_struct *tty;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- tty = tty_port_tty_get(&self->port);
-
- switch (cmd) {
- case FLOW_START:
- pr_debug("%s(), hw start!\n", __func__);
- if (tty)
- tty->hw_stopped = 0;
-
- /* ircomm_tty_do_softint will take care of the rest */
- schedule_work(&self->tqueue);
- break;
- default: /* If we get here, something is very wrong, better stop */
- case FLOW_STOP:
- pr_debug("%s(), hw stopped!\n", __func__);
- if (tty)
- tty->hw_stopped = 1;
- break;
- }
-
- tty_kref_put(tty);
- self->flow = cmd;
-}
-
-#ifdef CONFIG_PROC_FS
-static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m)
-{
- struct tty_struct *tty;
- char sep;
-
- seq_printf(m, "State: %s\n", ircomm_tty_state[self->state]);
-
- seq_puts(m, "Service type: ");
- if (self->service_type & IRCOMM_9_WIRE)
- seq_puts(m, "9_WIRE");
- else if (self->service_type & IRCOMM_3_WIRE)
- seq_puts(m, "3_WIRE");
- else if (self->service_type & IRCOMM_3_WIRE_RAW)
- seq_puts(m, "3_WIRE_RAW");
- else
- seq_puts(m, "No common service type!\n");
- seq_putc(m, '\n');
-
- seq_printf(m, "Port name: %s\n", self->settings.port_name);
-
- seq_printf(m, "DTE status:");
- sep = ' ';
- if (self->settings.dte & IRCOMM_RTS) {
- seq_printf(m, "%cRTS", sep);
- sep = '|';
- }
- if (self->settings.dte & IRCOMM_DTR) {
- seq_printf(m, "%cDTR", sep);
- sep = '|';
- }
- seq_putc(m, '\n');
-
- seq_puts(m, "DCE status:");
- sep = ' ';
- if (self->settings.dce & IRCOMM_CTS) {
- seq_printf(m, "%cCTS", sep);
- sep = '|';
- }
- if (self->settings.dce & IRCOMM_DSR) {
- seq_printf(m, "%cDSR", sep);
- sep = '|';
- }
- if (self->settings.dce & IRCOMM_CD) {
- seq_printf(m, "%cCD", sep);
- sep = '|';
- }
- if (self->settings.dce & IRCOMM_RI) {
- seq_printf(m, "%cRI", sep);
- sep = '|';
- }
- seq_putc(m, '\n');
-
- seq_puts(m, "Configuration: ");
- if (!self->settings.null_modem)
- seq_puts(m, "DTE <-> DCE\n");
- else
- seq_puts(m, "DTE <-> DTE (null modem emulation)\n");
-
- seq_printf(m, "Data rate: %d\n", self->settings.data_rate);
-
- seq_puts(m, "Flow control:");
- sep = ' ';
- if (self->settings.flow_control & IRCOMM_XON_XOFF_IN) {
- seq_printf(m, "%cXON_XOFF_IN", sep);
- sep = '|';
- }
- if (self->settings.flow_control & IRCOMM_XON_XOFF_OUT) {
- seq_printf(m, "%cXON_XOFF_OUT", sep);
- sep = '|';
- }
- if (self->settings.flow_control & IRCOMM_RTS_CTS_IN) {
- seq_printf(m, "%cRTS_CTS_IN", sep);
- sep = '|';
- }
- if (self->settings.flow_control & IRCOMM_RTS_CTS_OUT) {
- seq_printf(m, "%cRTS_CTS_OUT", sep);
- sep = '|';
- }
- if (self->settings.flow_control & IRCOMM_DSR_DTR_IN) {
- seq_printf(m, "%cDSR_DTR_IN", sep);
- sep = '|';
- }
- if (self->settings.flow_control & IRCOMM_DSR_DTR_OUT) {
- seq_printf(m, "%cDSR_DTR_OUT", sep);
- sep = '|';
- }
- if (self->settings.flow_control & IRCOMM_ENQ_ACK_IN) {
- seq_printf(m, "%cENQ_ACK_IN", sep);
- sep = '|';
- }
- if (self->settings.flow_control & IRCOMM_ENQ_ACK_OUT) {
- seq_printf(m, "%cENQ_ACK_OUT", sep);
- sep = '|';
- }
- seq_putc(m, '\n');
-
- seq_puts(m, "Flags:");
- sep = ' ';
- if (tty_port_cts_enabled(&self->port)) {
- seq_printf(m, "%cASYNC_CTS_FLOW", sep);
- sep = '|';
- }
- if (tty_port_check_carrier(&self->port)) {
- seq_printf(m, "%cASYNC_CHECK_CD", sep);
- sep = '|';
- }
- if (tty_port_initialized(&self->port)) {
- seq_printf(m, "%cASYNC_INITIALIZED", sep);
- sep = '|';
- }
- if (self->port.flags & ASYNC_LOW_LATENCY) {
- seq_printf(m, "%cASYNC_LOW_LATENCY", sep);
- sep = '|';
- }
- if (tty_port_active(&self->port)) {
- seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep);
- sep = '|';
- }
- seq_putc(m, '\n');
-
- seq_printf(m, "Role: %s\n", self->client ? "client" : "server");
- seq_printf(m, "Open count: %d\n", self->port.count);
- seq_printf(m, "Max data size: %d\n", self->max_data_size);
- seq_printf(m, "Max header size: %d\n", self->max_header_size);
-
- tty = tty_port_tty_get(&self->port);
- if (tty) {
- seq_printf(m, "Hardware: %s\n",
- tty->hw_stopped ? "Stopped" : "Running");
- tty_kref_put(tty);
- }
-}
-
-static int ircomm_tty_proc_show(struct seq_file *m, void *v)
-{
- struct ircomm_tty_cb *self;
- unsigned long flags;
-
- spin_lock_irqsave(&ircomm_tty->hb_spinlock, flags);
-
- self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
- while (self != NULL) {
- if (self->magic != IRCOMM_TTY_MAGIC)
- break;
-
- ircomm_tty_line_info(self, m);
- self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty);
- }
- spin_unlock_irqrestore(&ircomm_tty->hb_spinlock, flags);
- return 0;
-}
-
-static int ircomm_tty_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ircomm_tty_proc_show, NULL);
-}
-
-static const struct file_operations ircomm_tty_proc_fops = {
- .owner = THIS_MODULE,
- .open = ircomm_tty_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-#endif /* CONFIG_PROC_FS */
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("IrCOMM serial TTY driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(IRCOMM_TTY_MAJOR);
-
-module_init(ircomm_tty_init);
-module_exit(ircomm_tty_cleanup);
diff --git a/drivers/staging/irda/net/ircomm/ircomm_tty_attach.c b/drivers/staging/irda/net/ircomm/ircomm_tty_attach.c
deleted file mode 100644
index e2d5ce8ba0db..000000000000
--- a/drivers/staging/irda/net/ircomm/ircomm_tty_attach.c
+++ /dev/null
@@ -1,987 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_tty_attach.c
- * Version:
- * Description: Code for attaching the serial driver to IrCOMM
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sat Jun 5 17:42:00 1999
- * Modified at: Tue Jan 4 14:20:49 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
- * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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/init.h>
-#include <linux/sched.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/iriap.h>
-#include <net/irda/irttp.h>
-#include <net/irda/irias_object.h>
-#include <net/irda/parameters.h>
-
-#include <net/irda/ircomm_core.h>
-#include <net/irda/ircomm_param.h>
-#include <net/irda/ircomm_event.h>
-
-#include <net/irda/ircomm_tty.h>
-#include <net/irda/ircomm_tty_attach.h>
-
-static void ircomm_tty_ias_register(struct ircomm_tty_cb *self);
-static void ircomm_tty_discovery_indication(discinfo_t *discovery,
- DISCOVERY_MODE mode,
- void *priv);
-static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,
- struct ias_value *value, void *priv);
-static void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self,
- int timeout);
-static void ircomm_tty_watchdog_timer_expired(struct timer_list *timer);
-
-static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,
- IRCOMM_TTY_EVENT event,
- struct sk_buff *skb,
- struct ircomm_tty_info *info);
-static int ircomm_tty_state_search(struct ircomm_tty_cb *self,
- IRCOMM_TTY_EVENT event,
- struct sk_buff *skb,
- struct ircomm_tty_info *info);
-static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,
- IRCOMM_TTY_EVENT event,
- struct sk_buff *skb,
- struct ircomm_tty_info *info);
-static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,
- IRCOMM_TTY_EVENT event,
- struct sk_buff *skb,
- struct ircomm_tty_info *info);
-static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
- IRCOMM_TTY_EVENT event,
- struct sk_buff *skb,
- struct ircomm_tty_info *info);
-static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
- IRCOMM_TTY_EVENT event,
- struct sk_buff *skb,
- struct ircomm_tty_info *info);
-
-const char *const ircomm_tty_state[] = {
- "IRCOMM_TTY_IDLE",
- "IRCOMM_TTY_SEARCH",
- "IRCOMM_TTY_QUERY_PARAMETERS",
- "IRCOMM_TTY_QUERY_LSAP_SEL",
- "IRCOMM_TTY_SETUP",
- "IRCOMM_TTY_READY",
- "*** ERROR *** ",
-};
-
-static const char *const ircomm_tty_event[] __maybe_unused = {
- "IRCOMM_TTY_ATTACH_CABLE",
- "IRCOMM_TTY_DETACH_CABLE",
- "IRCOMM_TTY_DATA_REQUEST",
- "IRCOMM_TTY_DATA_INDICATION",
- "IRCOMM_TTY_DISCOVERY_REQUEST",
- "IRCOMM_TTY_DISCOVERY_INDICATION",
- "IRCOMM_TTY_CONNECT_CONFIRM",
- "IRCOMM_TTY_CONNECT_INDICATION",
- "IRCOMM_TTY_DISCONNECT_REQUEST",
- "IRCOMM_TTY_DISCONNECT_INDICATION",
- "IRCOMM_TTY_WD_TIMER_EXPIRED",
- "IRCOMM_TTY_GOT_PARAMETERS",
- "IRCOMM_TTY_GOT_LSAPSEL",
- "*** ERROR ****",
-};
-
-static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
- struct sk_buff *skb, struct ircomm_tty_info *info) =
-{
- ircomm_tty_state_idle,
- ircomm_tty_state_search,
- ircomm_tty_state_query_parameters,
- ircomm_tty_state_query_lsap_sel,
- ircomm_tty_state_setup,
- ircomm_tty_state_ready,
-};
-
-/*
- * Function ircomm_tty_attach_cable (driver)
- *
- * Try to attach cable (IrCOMM link). This function will only return
- * when the link has been connected, or if an error condition occurs.
- * If success, the return value is the resulting service type.
- */
-int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
-{
- struct tty_struct *tty;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- /* Check if somebody has already connected to us */
- if (ircomm_is_connected(self->ircomm)) {
- pr_debug("%s(), already connected!\n", __func__);
- return 0;
- }
-
- /* Make sure nobody tries to write before the link is up */
- tty = tty_port_tty_get(&self->port);
- if (tty) {
- tty->hw_stopped = 1;
- tty_kref_put(tty);
- }
-
- ircomm_tty_ias_register(self);
-
- ircomm_tty_do_event(self, IRCOMM_TTY_ATTACH_CABLE, NULL, NULL);
-
- return 0;
-}
-
-/*
- * Function ircomm_detach_cable (driver)
- *
- * Detach cable, or cable has been detached by peer
- *
- */
-void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- del_timer(&self->watchdog_timer);
-
- /* Remove discovery handler */
- if (self->ckey) {
- irlmp_unregister_client(self->ckey);
- self->ckey = NULL;
- }
- /* Remove IrCOMM hint bits */
- if (self->skey) {
- irlmp_unregister_service(self->skey);
- self->skey = NULL;
- }
-
- if (self->iriap) {
- iriap_close(self->iriap);
- self->iriap = NULL;
- }
-
- /* Remove LM-IAS object */
- if (self->obj) {
- irias_delete_object(self->obj);
- self->obj = NULL;
- }
-
- ircomm_tty_do_event(self, IRCOMM_TTY_DETACH_CABLE, NULL, NULL);
-
- /* Reset some values */
- self->daddr = self->saddr = 0;
- self->dlsap_sel = self->slsap_sel = 0;
-
- memset(&self->settings, 0, sizeof(struct ircomm_params));
-}
-
-/*
- * Function ircomm_tty_ias_register (self)
- *
- * Register with LM-IAS depending on which service type we are
- *
- */
-static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
-{
- __u8 oct_seq[6];
- __u16 hints;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- /* Compute hint bits based on service */
- hints = irlmp_service_to_hint(S_COMM);
- if (self->service_type & IRCOMM_3_WIRE_RAW)
- hints |= irlmp_service_to_hint(S_PRINTER);
-
- /* Advertise IrCOMM hint bit in discovery */
- if (!self->skey)
- self->skey = irlmp_register_service(hints);
- /* Set up a discovery handler */
- if (!self->ckey)
- self->ckey = irlmp_register_client(hints,
- ircomm_tty_discovery_indication,
- NULL, (void *) self);
-
- /* If already done, no need to do it again */
- if (self->obj)
- return;
-
- if (self->service_type & IRCOMM_3_WIRE_RAW) {
- /* Register IrLPT with LM-IAS */
- self->obj = irias_new_object("IrLPT", IAS_IRLPT_ID);
- irias_add_integer_attrib(self->obj, "IrDA:IrLMP:LsapSel",
- self->slsap_sel, IAS_KERNEL_ATTR);
- } else {
- /* Register IrCOMM with LM-IAS */
- self->obj = irias_new_object("IrDA:IrCOMM", IAS_IRCOMM_ID);
- irias_add_integer_attrib(self->obj, "IrDA:TinyTP:LsapSel",
- self->slsap_sel, IAS_KERNEL_ATTR);
-
- /* Code the parameters into the buffer */
- irda_param_pack(oct_seq, "bbbbbb",
- IRCOMM_SERVICE_TYPE, 1, self->service_type,
- IRCOMM_PORT_TYPE, 1, IRCOMM_SERIAL);
-
- /* Register parameters with LM-IAS */
- irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6,
- IAS_KERNEL_ATTR);
- }
- irias_insert_object(self->obj);
-}
-
-/*
- * Function ircomm_tty_ias_unregister (self)
- *
- * Remove our IAS object and client hook while connected.
- *
- */
-static void ircomm_tty_ias_unregister(struct ircomm_tty_cb *self)
-{
- /* Remove LM-IAS object now so it is not reused.
- * IrCOMM deals very poorly with multiple incoming connections.
- * It should looks a lot more like IrNET, and "dup" a server TSAP
- * to the application TSAP (based on various rules).
- * This is a cheap workaround allowing multiple clients to
- * connect to us. It will not always work.
- * Each IrCOMM socket has an IAS entry. Incoming connection will
- * pick the first one found. So, when we are fully connected,
- * we remove our IAS entries so that the next IAS entry is used.
- * We do that for *both* client and server, because a server
- * can also create client instances.
- * Jean II */
- if (self->obj) {
- irias_delete_object(self->obj);
- self->obj = NULL;
- }
-
-#if 0
- /* Remove discovery handler.
- * While we are connected, we no longer need to receive
- * discovery events. This would be the case if there is
- * multiple IrLAP interfaces. Jean II */
- if (self->ckey) {
- irlmp_unregister_client(self->ckey);
- self->ckey = NULL;
- }
-#endif
-}
-
-/*
- * Function ircomm_send_initial_parameters (self)
- *
- * Send initial parameters to the remote IrCOMM device. These parameters
- * must be sent before any data.
- */
-int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self)
-{
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- if (self->service_type & IRCOMM_3_WIRE_RAW)
- return 0;
-
- /*
- * Set default values, but only if the application for some reason
- * haven't set them already
- */
- pr_debug("%s(), data-rate = %d\n", __func__ ,
- self->settings.data_rate);
- if (!self->settings.data_rate)
- self->settings.data_rate = 9600;
- pr_debug("%s(), data-format = %d\n", __func__ ,
- self->settings.data_format);
- if (!self->settings.data_format)
- self->settings.data_format = IRCOMM_WSIZE_8; /* 8N1 */
-
- pr_debug("%s(), flow-control = %d\n", __func__ ,
- self->settings.flow_control);
- /*self->settings.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/
-
- /* Do not set delta values for the initial parameters */
- self->settings.dte = IRCOMM_DTR | IRCOMM_RTS;
-
- /* Only send service type parameter when we are the client */
- if (self->client)
- ircomm_param_request(self, IRCOMM_SERVICE_TYPE, FALSE);
- ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE);
- ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
-
- /* For a 3 wire service, we just flush the last parameter and return */
- if (self->settings.service_type == IRCOMM_3_WIRE) {
- ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE);
- return 0;
- }
-
- /* Only 9-wire service types continue here */
- ircomm_param_request(self, IRCOMM_FLOW_CONTROL, FALSE);
-#if 0
- ircomm_param_request(self, IRCOMM_XON_XOFF, FALSE);
- ircomm_param_request(self, IRCOMM_ENQ_ACK, FALSE);
-#endif
- /* Notify peer that we are ready to receive data */
- ircomm_param_request(self, IRCOMM_DTE, TRUE);
-
- return 0;
-}
-
-/*
- * Function ircomm_tty_discovery_indication (discovery)
- *
- * Remote device is discovered, try query the remote IAS to see which
- * device it is, and which services it has.
- *
- */
-static void ircomm_tty_discovery_indication(discinfo_t *discovery,
- DISCOVERY_MODE mode,
- void *priv)
-{
- struct ircomm_tty_cb *self;
- struct ircomm_tty_info info;
-
- /* Important note :
- * We need to drop all passive discoveries.
- * The LSAP management of IrComm is deficient and doesn't deal
- * with the case of two instance connecting to each other
- * simultaneously (it will deadlock in LMP).
- * The proper fix would be to use the same technique as in IrNET,
- * to have one server socket and separate instances for the
- * connecting/connected socket.
- * The workaround is to drop passive discovery, which drastically
- * reduce the probability of this happening.
- * Jean II */
- if(mode == DISCOVERY_PASSIVE)
- return;
-
- info.daddr = discovery->daddr;
- info.saddr = discovery->saddr;
-
- self = priv;
- ircomm_tty_do_event(self, IRCOMM_TTY_DISCOVERY_INDICATION,
- NULL, &info);
-}
-
-/*
- * Function ircomm_tty_disconnect_indication (instance, sap, reason, skb)
- *
- * Link disconnected
- *
- */
-void ircomm_tty_disconnect_indication(void *instance, void *sap,
- LM_REASON reason,
- struct sk_buff *skb)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
- struct tty_struct *tty;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- tty = tty_port_tty_get(&self->port);
- if (!tty)
- return;
-
- /* This will stop control data transfers */
- self->flow = FLOW_STOP;
-
- /* Stop data transfers */
- tty->hw_stopped = 1;
-
- ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL,
- NULL);
- tty_kref_put(tty);
-}
-
-/*
- * Function ircomm_tty_getvalue_confirm (result, obj_id, value, priv)
- *
- * Got result from the IAS query we make
- *
- */
-static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,
- struct ias_value *value,
- void *priv)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) priv;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- /* We probably don't need to make any more queries */
- iriap_close(self->iriap);
- self->iriap = NULL;
-
- /* Check if request succeeded */
- if (result != IAS_SUCCESS) {
- pr_debug("%s(), got NULL value!\n", __func__);
- return;
- }
-
- switch (value->type) {
- case IAS_OCT_SEQ:
- pr_debug("%s(), got octet sequence\n", __func__);
-
- irda_param_extract_all(self, value->t.oct_seq, value->len,
- &ircomm_param_info);
-
- ircomm_tty_do_event(self, IRCOMM_TTY_GOT_PARAMETERS, NULL,
- NULL);
- break;
- case IAS_INTEGER:
- /* Got LSAP selector */
- pr_debug("%s(), got lsapsel = %d\n", __func__ ,
- value->t.integer);
-
- if (value->t.integer == -1) {
- pr_debug("%s(), invalid value!\n", __func__);
- } else
- self->dlsap_sel = value->t.integer;
-
- ircomm_tty_do_event(self, IRCOMM_TTY_GOT_LSAPSEL, NULL, NULL);
- break;
- case IAS_MISSING:
- pr_debug("%s(), got IAS_MISSING\n", __func__);
- break;
- default:
- pr_debug("%s(), got unknown type!\n", __func__);
- break;
- }
- irias_delete_value(value);
-}
-
-/*
- * Function ircomm_tty_connect_confirm (instance, sap, qos, max_sdu_size, skb)
- *
- * Connection confirmed
- *
- */
-void ircomm_tty_connect_confirm(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_data_size,
- __u8 max_header_size,
- struct sk_buff *skb)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- self->client = TRUE;
- self->max_data_size = max_data_size;
- self->max_header_size = max_header_size;
- self->flow = FLOW_START;
-
- ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL);
-
- /* No need to kfree_skb - see ircomm_ttp_connect_confirm() */
-}
-
-/*
- * Function ircomm_tty_connect_indication (instance, sap, qos, max_sdu_size,
- * skb)
- *
- * we are discovered and being requested to connect by remote device !
- *
- */
-void ircomm_tty_connect_indication(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_data_size,
- __u8 max_header_size,
- struct sk_buff *skb)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
- int clen;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- self->client = FALSE;
- self->max_data_size = max_data_size;
- self->max_header_size = max_header_size;
- self->flow = FLOW_START;
-
- clen = skb->data[0];
- if (clen)
- irda_param_extract_all(self, skb->data+1,
- IRDA_MIN(skb->len, clen),
- &ircomm_param_info);
-
- ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL);
-
- /* No need to kfree_skb - see ircomm_ttp_connect_indication() */
-}
-
-/*
- * Function ircomm_tty_link_established (self)
- *
- * Called when the IrCOMM link is established
- *
- */
-void ircomm_tty_link_established(struct ircomm_tty_cb *self)
-{
- struct tty_struct *tty;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- tty = tty_port_tty_get(&self->port);
- if (!tty)
- return;
-
- del_timer(&self->watchdog_timer);
-
- /*
- * IrCOMM link is now up, and if we are not using hardware
- * flow-control, then declare the hardware as running. Otherwise we
- * will have to wait for the peer device (DCE) to raise the CTS
- * line.
- */
- if (tty_port_cts_enabled(&self->port) &&
- ((self->settings.dce & IRCOMM_CTS) == 0)) {
- pr_debug("%s(), waiting for CTS ...\n", __func__);
- goto put;
- } else {
- pr_debug("%s(), starting hardware!\n", __func__);
-
- tty->hw_stopped = 0;
-
- /* Wake up processes blocked on open */
- wake_up_interruptible(&self->port.open_wait);
- }
-
- schedule_work(&self->tqueue);
-put:
- tty_kref_put(tty);
-}
-
-/*
- * Function ircomm_tty_start_watchdog_timer (self, timeout)
- *
- * Start the watchdog timer. This timer is used to make sure that any
- * connection attempt is successful, and if not, we will retry after
- * the timeout
- */
-static void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self,
- int timeout)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- irda_start_timer(&self->watchdog_timer, timeout,
- ircomm_tty_watchdog_timer_expired);
-}
-
-/*
- * Function ircomm_tty_watchdog_timer_expired (data)
- *
- * Called when the connect procedure have taken to much time.
- *
- */
-static void ircomm_tty_watchdog_timer_expired(struct timer_list *t)
-{
- struct ircomm_tty_cb *self = from_timer(self, t, watchdog_timer);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- ircomm_tty_do_event(self, IRCOMM_TTY_WD_TIMER_EXPIRED, NULL, NULL);
-}
-
-
-/*
- * Function ircomm_tty_do_event (self, event, skb)
- *
- * Process event
- *
- */
-int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
- struct sk_buff *skb, struct ircomm_tty_info *info)
-{
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- pr_debug("%s: state=%s, event=%s\n", __func__ ,
- ircomm_tty_state[self->state], ircomm_tty_event[event]);
-
- return (*state[self->state])(self, event, skb, info);
-}
-
-/*
- * Function ircomm_tty_next_state (self, state)
- *
- * Switch state
- *
- */
-static inline void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
-{
- /*
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
- pr_debug("%s: next state=%s, service type=%d\n", __func__ ,
- ircomm_tty_state[self->state], self->service_type);
- */
- self->state = state;
-}
-
-/*
- * Function ircomm_tty_state_idle (self, event, skb, info)
- *
- * Just hanging around
- *
- */
-static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,
- IRCOMM_TTY_EVENT event,
- struct sk_buff *skb,
- struct ircomm_tty_info *info)
-{
- int ret = 0;
-
- pr_debug("%s: state=%s, event=%s\n", __func__ ,
- ircomm_tty_state[self->state], ircomm_tty_event[event]);
- switch (event) {
- case IRCOMM_TTY_ATTACH_CABLE:
- /* Try to discover any remote devices */
- ircomm_tty_start_watchdog_timer(self, 3*HZ);
- ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
-
- irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
- break;
- case IRCOMM_TTY_DISCOVERY_INDICATION:
- self->daddr = info->daddr;
- self->saddr = info->saddr;
-
- if (self->iriap) {
- net_warn_ratelimited("%s(), busy with a previous query\n",
- __func__);
- return -EBUSY;
- }
-
- self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
- ircomm_tty_getvalue_confirm);
-
- iriap_getvaluebyclass_request(self->iriap,
- self->saddr, self->daddr,
- "IrDA:IrCOMM", "Parameters");
-
- ircomm_tty_start_watchdog_timer(self, 3*HZ);
- ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);
- break;
- case IRCOMM_TTY_CONNECT_INDICATION:
- del_timer(&self->watchdog_timer);
-
- /* Accept connection */
- ircomm_connect_response(self->ircomm, NULL);
- ircomm_tty_next_state(self, IRCOMM_TTY_READY);
- break;
- case IRCOMM_TTY_WD_TIMER_EXPIRED:
- /* Just stay idle */
- break;
- case IRCOMM_TTY_DETACH_CABLE:
- ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
- break;
- default:
- pr_debug("%s(), unknown event: %s\n", __func__ ,
- ircomm_tty_event[event]);
- ret = -EINVAL;
- }
- return ret;
-}
-
-/*
- * Function ircomm_tty_state_search (self, event, skb, info)
- *
- * Trying to discover an IrCOMM device
- *
- */
-static int ircomm_tty_state_search(struct ircomm_tty_cb *self,
- IRCOMM_TTY_EVENT event,
- struct sk_buff *skb,
- struct ircomm_tty_info *info)
-{
- int ret = 0;
-
- pr_debug("%s: state=%s, event=%s\n", __func__ ,
- ircomm_tty_state[self->state], ircomm_tty_event[event]);
-
- switch (event) {
- case IRCOMM_TTY_DISCOVERY_INDICATION:
- self->daddr = info->daddr;
- self->saddr = info->saddr;
-
- if (self->iriap) {
- net_warn_ratelimited("%s(), busy with a previous query\n",
- __func__);
- return -EBUSY;
- }
-
- self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
- ircomm_tty_getvalue_confirm);
-
- if (self->service_type == IRCOMM_3_WIRE_RAW) {
- iriap_getvaluebyclass_request(self->iriap, self->saddr,
- self->daddr, "IrLPT",
- "IrDA:IrLMP:LsapSel");
- ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);
- } else {
- iriap_getvaluebyclass_request(self->iriap, self->saddr,
- self->daddr,
- "IrDA:IrCOMM",
- "Parameters");
-
- ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);
- }
- ircomm_tty_start_watchdog_timer(self, 3*HZ);
- break;
- case IRCOMM_TTY_CONNECT_INDICATION:
- del_timer(&self->watchdog_timer);
- ircomm_tty_ias_unregister(self);
-
- /* Accept connection */
- ircomm_connect_response(self->ircomm, NULL);
- ircomm_tty_next_state(self, IRCOMM_TTY_READY);
- break;
- case IRCOMM_TTY_WD_TIMER_EXPIRED:
-#if 1
- /* Give up */
-#else
- /* Try to discover any remote devices */
- ircomm_tty_start_watchdog_timer(self, 3*HZ);
- irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
-#endif
- break;
- case IRCOMM_TTY_DETACH_CABLE:
- ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
- break;
- default:
- pr_debug("%s(), unknown event: %s\n", __func__ ,
- ircomm_tty_event[event]);
- ret = -EINVAL;
- }
- return ret;
-}
-
-/*
- * Function ircomm_tty_state_query (self, event, skb, info)
- *
- * Querying the remote LM-IAS for IrCOMM parameters
- *
- */
-static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,
- IRCOMM_TTY_EVENT event,
- struct sk_buff *skb,
- struct ircomm_tty_info *info)
-{
- int ret = 0;
-
- pr_debug("%s: state=%s, event=%s\n", __func__ ,
- ircomm_tty_state[self->state], ircomm_tty_event[event]);
-
- switch (event) {
- case IRCOMM_TTY_GOT_PARAMETERS:
- if (self->iriap) {
- net_warn_ratelimited("%s(), busy with a previous query\n",
- __func__);
- return -EBUSY;
- }
-
- self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
- ircomm_tty_getvalue_confirm);
-
- iriap_getvaluebyclass_request(self->iriap, self->saddr,
- self->daddr, "IrDA:IrCOMM",
- "IrDA:TinyTP:LsapSel");
-
- ircomm_tty_start_watchdog_timer(self, 3*HZ);
- ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);
- break;
- case IRCOMM_TTY_WD_TIMER_EXPIRED:
- /* Go back to search mode */
- ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
- ircomm_tty_start_watchdog_timer(self, 3*HZ);
- break;
- case IRCOMM_TTY_CONNECT_INDICATION:
- del_timer(&self->watchdog_timer);
- ircomm_tty_ias_unregister(self);
-
- /* Accept connection */
- ircomm_connect_response(self->ircomm, NULL);
- ircomm_tty_next_state(self, IRCOMM_TTY_READY);
- break;
- case IRCOMM_TTY_DETACH_CABLE:
- ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
- break;
- default:
- pr_debug("%s(), unknown event: %s\n", __func__ ,
- ircomm_tty_event[event]);
- ret = -EINVAL;
- }
- return ret;
-}
-
-/*
- * Function ircomm_tty_state_query_lsap_sel (self, event, skb, info)
- *
- * Query remote LM-IAS for the LSAP selector which we can connect to
- *
- */
-static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,
- IRCOMM_TTY_EVENT event,
- struct sk_buff *skb,
- struct ircomm_tty_info *info)
-{
- int ret = 0;
-
- pr_debug("%s: state=%s, event=%s\n", __func__ ,
- ircomm_tty_state[self->state], ircomm_tty_event[event]);
-
- switch (event) {
- case IRCOMM_TTY_GOT_LSAPSEL:
- /* Connect to remote device */
- ret = ircomm_connect_request(self->ircomm, self->dlsap_sel,
- self->saddr, self->daddr,
- NULL, self->service_type);
- ircomm_tty_start_watchdog_timer(self, 3*HZ);
- ircomm_tty_next_state(self, IRCOMM_TTY_SETUP);
- break;
- case IRCOMM_TTY_WD_TIMER_EXPIRED:
- /* Go back to search mode */
- ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
- ircomm_tty_start_watchdog_timer(self, 3*HZ);
- break;
- case IRCOMM_TTY_CONNECT_INDICATION:
- del_timer(&self->watchdog_timer);
- ircomm_tty_ias_unregister(self);
-
- /* Accept connection */
- ircomm_connect_response(self->ircomm, NULL);
- ircomm_tty_next_state(self, IRCOMM_TTY_READY);
- break;
- case IRCOMM_TTY_DETACH_CABLE:
- ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
- break;
- default:
- pr_debug("%s(), unknown event: %s\n", __func__ ,
- ircomm_tty_event[event]);
- ret = -EINVAL;
- }
- return ret;
-}
-
-/*
- * Function ircomm_tty_state_setup (self, event, skb, info)
- *
- * Trying to connect
- *
- */
-static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
- IRCOMM_TTY_EVENT event,
- struct sk_buff *skb,
- struct ircomm_tty_info *info)
-{
- int ret = 0;
-
- pr_debug("%s: state=%s, event=%s\n", __func__ ,
- ircomm_tty_state[self->state], ircomm_tty_event[event]);
-
- switch (event) {
- case IRCOMM_TTY_CONNECT_CONFIRM:
- del_timer(&self->watchdog_timer);
- ircomm_tty_ias_unregister(self);
-
- /*
- * Send initial parameters. This will also send out queued
- * parameters waiting for the connection to come up
- */
- ircomm_tty_send_initial_parameters(self);
- ircomm_tty_link_established(self);
- ircomm_tty_next_state(self, IRCOMM_TTY_READY);
- break;
- case IRCOMM_TTY_CONNECT_INDICATION:
- del_timer(&self->watchdog_timer);
- ircomm_tty_ias_unregister(self);
-
- /* Accept connection */
- ircomm_connect_response(self->ircomm, NULL);
- ircomm_tty_next_state(self, IRCOMM_TTY_READY);
- break;
- case IRCOMM_TTY_WD_TIMER_EXPIRED:
- /* Go back to search mode */
- ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
- ircomm_tty_start_watchdog_timer(self, 3*HZ);
- break;
- case IRCOMM_TTY_DETACH_CABLE:
- /* ircomm_disconnect_request(self->ircomm, NULL); */
- ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
- break;
- default:
- pr_debug("%s(), unknown event: %s\n", __func__ ,
- ircomm_tty_event[event]);
- ret = -EINVAL;
- }
- return ret;
-}
-
-/*
- * Function ircomm_tty_state_ready (self, event, skb, info)
- *
- * IrCOMM is now connected
- *
- */
-static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
- IRCOMM_TTY_EVENT event,
- struct sk_buff *skb,
- struct ircomm_tty_info *info)
-{
- int ret = 0;
-
- switch (event) {
- case IRCOMM_TTY_DATA_REQUEST:
- ret = ircomm_data_request(self->ircomm, skb);
- break;
- case IRCOMM_TTY_DETACH_CABLE:
- ircomm_disconnect_request(self->ircomm, NULL);
- ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
- break;
- case IRCOMM_TTY_DISCONNECT_INDICATION:
- ircomm_tty_ias_register(self);
- ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
- ircomm_tty_start_watchdog_timer(self, 3*HZ);
-
- if (tty_port_check_carrier(&self->port)) {
- /* Drop carrier */
- self->settings.dce = IRCOMM_DELTA_CD;
- ircomm_tty_check_modem_status(self);
- } else {
- pr_debug("%s(), hanging up!\n", __func__);
- tty_port_tty_hangup(&self->port, false);
- }
- break;
- default:
- pr_debug("%s(), unknown event: %s\n", __func__ ,
- ircomm_tty_event[event]);
- ret = -EINVAL;
- }
- return ret;
-}
-
diff --git a/drivers/staging/irda/net/ircomm/ircomm_tty_ioctl.c b/drivers/staging/irda/net/ircomm/ircomm_tty_ioctl.c
deleted file mode 100644
index 171c3dee760e..000000000000
--- a/drivers/staging/irda/net/ircomm/ircomm_tty_ioctl.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/*********************************************************************
- *
- * Filename: ircomm_tty_ioctl.c
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Thu Jun 10 14:39:09 1999
- * Modified at: Wed Jan 5 14:45:43 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999-2000 Dag Brattli, 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.
- *
- * 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/init.h>
-#include <linux/fs.h>
-#include <linux/termios.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-
-#include <linux/uaccess.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irmod.h>
-
-#include <net/irda/ircomm_core.h>
-#include <net/irda/ircomm_param.h>
-#include <net/irda/ircomm_tty_attach.h>
-#include <net/irda/ircomm_tty.h>
-
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-/*
- * Function ircomm_tty_change_speed (driver)
- *
- * Change speed of the driver. If the remote device is a DCE, then this
- * should make it change the speed of its serial port
- */
-static void ircomm_tty_change_speed(struct ircomm_tty_cb *self,
- struct tty_struct *tty)
-{
- unsigned int cflag, cval;
- int baud;
-
- if (!self->ircomm)
- return;
-
- cflag = tty->termios.c_cflag;
-
- /* byte size and parity */
- switch (cflag & CSIZE) {
- case CS5: cval = IRCOMM_WSIZE_5; break;
- case CS6: cval = IRCOMM_WSIZE_6; break;
- case CS7: cval = IRCOMM_WSIZE_7; break;
- case CS8: cval = IRCOMM_WSIZE_8; break;
- default: cval = IRCOMM_WSIZE_5; break;
- }
- if (cflag & CSTOPB)
- cval |= IRCOMM_2_STOP_BIT;
-
- if (cflag & PARENB)
- cval |= IRCOMM_PARITY_ENABLE;
- if (!(cflag & PARODD))
- cval |= IRCOMM_PARITY_EVEN;
-
- /* Determine divisor based on baud rate */
- baud = tty_get_baud_rate(tty);
- if (!baud)
- baud = 9600; /* B0 transition handled in rs_set_termios */
-
- self->settings.data_rate = baud;
- ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE);
-
- /* CTS flow control flag and modem status interrupts */
- tty_port_set_cts_flow(&self->port, cflag & CRTSCTS);
- if (cflag & CRTSCTS) {
- self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
- /* This got me. Bummer. Jean II */
- if (self->service_type == IRCOMM_3_WIRE_RAW)
- net_warn_ratelimited("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n",
- __func__);
- } else {
- self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
- }
- tty_port_set_check_carrier(&self->port, ~cflag & CLOCAL);
-
- self->settings.data_format = cval;
-
- ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
- ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE);
-}
-
-/*
- * Function ircomm_tty_set_termios (tty, old_termios)
- *
- * This routine allows the tty driver to be notified when device's
- * termios settings have changed. Note that a well-designed tty driver
- * should be prepared to accept the case where old == NULL, and try to
- * do something rational.
- */
-void ircomm_tty_set_termios(struct tty_struct *tty,
- struct ktermios *old_termios)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- unsigned int cflag = tty->termios.c_cflag;
-
- if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(tty->termios.c_iflag) ==
- RELEVANT_IFLAG(old_termios->c_iflag)))
- {
- return;
- }
-
- ircomm_tty_change_speed(self, tty);
-
- /* Handle transition to B0 status */
- if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) {
- self->settings.dte &= ~(IRCOMM_DTR|IRCOMM_RTS);
- ircomm_param_request(self, IRCOMM_DTE, TRUE);
- }
-
- /* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
- self->settings.dte |= IRCOMM_DTR;
- if (!C_CRTSCTS(tty) || !tty_throttled(tty))
- self->settings.dte |= IRCOMM_RTS;
- ircomm_param_request(self, IRCOMM_DTE, TRUE);
- }
-
- /* Handle turning off CRTSCTS */
- if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty))
- {
- tty->hw_stopped = 0;
- ircomm_tty_start(tty);
- }
-}
-
-/*
- * Function ircomm_tty_tiocmget (tty)
- *
- *
- *
- */
-int ircomm_tty_tiocmget(struct tty_struct *tty)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- unsigned int result;
-
- if (tty_io_error(tty))
- return -EIO;
-
- result = ((self->settings.dte & IRCOMM_RTS) ? TIOCM_RTS : 0)
- | ((self->settings.dte & IRCOMM_DTR) ? TIOCM_DTR : 0)
- | ((self->settings.dce & IRCOMM_CD) ? TIOCM_CAR : 0)
- | ((self->settings.dce & IRCOMM_RI) ? TIOCM_RNG : 0)
- | ((self->settings.dce & IRCOMM_DSR) ? TIOCM_DSR : 0)
- | ((self->settings.dce & IRCOMM_CTS) ? TIOCM_CTS : 0);
- return result;
-}
-
-/*
- * Function ircomm_tty_tiocmset (tty, set, clear)
- *
- *
- *
- */
-int ircomm_tty_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
-
- if (tty_io_error(tty))
- return -EIO;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
- if (set & TIOCM_RTS)
- self->settings.dte |= IRCOMM_RTS;
- if (set & TIOCM_DTR)
- self->settings.dte |= IRCOMM_DTR;
-
- if (clear & TIOCM_RTS)
- self->settings.dte &= ~IRCOMM_RTS;
- if (clear & TIOCM_DTR)
- self->settings.dte &= ~IRCOMM_DTR;
-
- if ((set|clear) & TIOCM_RTS)
- self->settings.dte |= IRCOMM_DELTA_RTS;
- if ((set|clear) & TIOCM_DTR)
- self->settings.dte |= IRCOMM_DELTA_DTR;
-
- ircomm_param_request(self, IRCOMM_DTE, TRUE);
-
- return 0;
-}
-
-/*
- * Function get_serial_info (driver, retinfo)
- *
- *
- *
- */
-static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
- struct serial_struct __user *retinfo)
-{
- struct serial_struct info;
-
- memset(&info, 0, sizeof(info));
- info.line = self->line;
- info.flags = self->port.flags;
- info.baud_base = self->settings.data_rate;
- info.close_delay = self->port.close_delay;
- info.closing_wait = self->port.closing_wait;
-
- /* For compatibility */
- info.type = PORT_16550A;
-
- if (copy_to_user(retinfo, &info, sizeof(*retinfo)))
- return -EFAULT;
-
- return 0;
-}
-
-/*
- * Function set_serial_info (driver, new_info)
- *
- *
- *
- */
-static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *self,
- struct serial_struct __user *new_info)
-{
- return 0;
-}
-
-/*
- * Function ircomm_tty_ioctl (tty, cmd, arg)
- *
- *
- *
- */
-int ircomm_tty_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
- int ret = 0;
-
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
- (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
- if (tty_io_error(tty))
- return -EIO;
- }
-
- switch (cmd) {
- case TIOCGSERIAL:
- ret = ircomm_tty_get_serial_info(self, (struct serial_struct __user *) arg);
- break;
- case TIOCSSERIAL:
- ret = ircomm_tty_set_serial_info(self, (struct serial_struct __user *) arg);
- break;
- case TIOCMIWAIT:
- pr_debug("(), TIOCMIWAIT, not impl!\n");
- break;
-
- case TIOCGICOUNT:
- pr_debug("%s(), TIOCGICOUNT not impl!\n", __func__);
- return 0;
- default:
- ret = -ENOIOCTLCMD; /* ioctls which we must ignore */
- }
- return ret;
-}
-
-
-
diff --git a/drivers/staging/irda/net/irda_device.c b/drivers/staging/irda/net/irda_device.c
deleted file mode 100644
index 682b4eea15e0..000000000000
--- a/drivers/staging/irda/net/irda_device.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*********************************************************************
- *
- * Filename: irda_device.c
- * Version: 0.9
- * Description: Utility functions used by the device drivers
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sat Oct 9 09:22:27 1999
- * Modified at: Sun Jan 23 17:41:24 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
- * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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/string.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/capability.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/if_arp.h>
-#include <linux/netdevice.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/kmod.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-
-#include <asm/ioctls.h>
-#include <linux/uaccess.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-
-#include <net/irda/irda_device.h>
-#include <net/irda/irlap.h>
-#include <net/irda/timer.h>
-#include <net/irda/wrapper.h>
-
-static void __irda_task_delete(struct irda_task *task);
-
-static hashbin_t *dongles;
-static hashbin_t *tasks;
-
-static void irda_task_timer_expired(struct timer_list *timer);
-
-int __init irda_device_init(void)
-{
- dongles = hashbin_new(HB_NOLOCK);
- if (!dongles) {
- net_warn_ratelimited("IrDA: Can't allocate dongles hashbin!\n");
- return -ENOMEM;
- }
- spin_lock_init(&dongles->hb_spinlock);
-
- tasks = hashbin_new(HB_LOCK);
- if (!tasks) {
- net_warn_ratelimited("IrDA: Can't allocate tasks hashbin!\n");
- hashbin_delete(dongles, NULL);
- return -ENOMEM;
- }
-
- /* We no longer initialise the driver ourselves here, we let
- * the system do it for us... - Jean II
- */
-
- return 0;
-}
-
-static void leftover_dongle(void *arg)
-{
- struct dongle_reg *reg = arg;
-
- net_warn_ratelimited("IrDA: Dongle type %x not unregistered\n",
- reg->type);
-}
-
-void irda_device_cleanup(void)
-{
- hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete);
-
- hashbin_delete(dongles, leftover_dongle);
-}
-
-/*
- * Function irda_device_set_media_busy (self, status)
- *
- * Called when we have detected that another station is transmitting
- * in contention mode.
- */
-void irda_device_set_media_busy(struct net_device *dev, int status)
-{
- struct irlap_cb *self;
-
- pr_debug("%s(%s)\n", __func__, status ? "TRUE" : "FALSE");
-
- self = (struct irlap_cb *)dev->atalk_ptr;
-
- /* Some drivers may enable the receive interrupt before calling
- * irlap_open(), or they may disable the receive interrupt
- * after calling irlap_close().
- * The IrDA stack is protected from this in irlap_driver_rcv().
- * However, the driver calls directly the wrapper, that calls
- * us directly. Make sure we protect ourselves.
- * Jean II
- */
- if (!self || self->magic != LAP_MAGIC)
- return;
-
- if (status) {
- self->media_busy = TRUE;
- if (status == SMALL)
- irlap_start_mbusy_timer(self, SMALLBUSY_TIMEOUT);
- else
- irlap_start_mbusy_timer(self, MEDIABUSY_TIMEOUT);
- pr_debug("Media busy!\n");
- } else {
- self->media_busy = FALSE;
- irlap_stop_mbusy_timer(self);
- }
-}
-EXPORT_SYMBOL(irda_device_set_media_busy);
-
-/*
- * Function irda_device_is_receiving (dev)
- *
- * Check if the device driver is currently receiving data
- *
- */
-int irda_device_is_receiving(struct net_device *dev)
-{
- struct if_irda_req req;
- int ret;
-
- if (!dev->netdev_ops->ndo_do_ioctl) {
- net_err_ratelimited("%s: do_ioctl not impl. by device driver\n",
- __func__);
- return -1;
- }
-
- ret = (dev->netdev_ops->ndo_do_ioctl)(dev, (struct ifreq *) &req,
- SIOCGRECEIVING);
- if (ret < 0)
- return ret;
-
- return req.ifr_receiving;
-}
-
-static void __irda_task_delete(struct irda_task *task)
-{
- del_timer(&task->timer);
-
- kfree(task);
-}
-
-static void irda_task_delete(struct irda_task *task)
-{
- /* Unregister task */
- hashbin_remove(tasks, (long)task, NULL);
-
- __irda_task_delete(task);
-}
-
-/*
- * Function irda_task_kick (task)
- *
- * Tries to execute a task possible multiple times until the task is either
- * finished, or askes for a timeout. When a task is finished, we do post
- * processing, and notify the parent task, that is waiting for this task
- * to complete.
- */
-static int irda_task_kick(struct irda_task *task)
-{
- int finished = TRUE;
- int count = 0;
- int timeout;
-
- IRDA_ASSERT(task != NULL, return -1;);
- IRDA_ASSERT(task->magic == IRDA_TASK_MAGIC, return -1;);
-
- /* Execute task until it's finished, or askes for a timeout */
- do {
- timeout = task->function(task);
- if (count++ > 100) {
- net_err_ratelimited("%s: error in task handler!\n",
- __func__);
- irda_task_delete(task);
- return TRUE;
- }
- } while ((timeout == 0) && (task->state != IRDA_TASK_DONE));
-
- if (timeout < 0) {
- net_err_ratelimited("%s: Error executing task!\n", __func__);
- irda_task_delete(task);
- return TRUE;
- }
-
- /* Check if we are finished */
- if (task->state == IRDA_TASK_DONE) {
- del_timer(&task->timer);
-
- /* Do post processing */
- if (task->finished)
- task->finished(task);
-
- /* Notify parent */
- if (task->parent) {
- /* Check if parent is waiting for us to complete */
- if (task->parent->state == IRDA_TASK_CHILD_WAIT) {
- task->parent->state = IRDA_TASK_CHILD_DONE;
-
- /* Stop timer now that we are here */
- del_timer(&task->parent->timer);
-
- /* Kick parent task */
- irda_task_kick(task->parent);
- }
- }
- irda_task_delete(task);
- } else if (timeout > 0) {
- irda_start_timer(&task->timer, timeout,
- irda_task_timer_expired);
- finished = FALSE;
- } else {
- pr_debug("%s(), not finished, and no timeout!\n",
- __func__);
- finished = FALSE;
- }
-
- return finished;
-}
-
-/*
- * Function irda_task_timer_expired (data)
- *
- * Task time has expired. We now try to execute task (again), and restart
- * the timer if the task has not finished yet
- */
-static void irda_task_timer_expired(struct timer_list *t)
-{
- struct irda_task *task = from_timer(task, t, timer);
-
- irda_task_kick(task);
-}
-
-/*
- * Function irda_device_setup (dev)
- *
- * This function should be used by low level device drivers in a similar way
- * as ether_setup() is used by normal network device drivers
- */
-static void irda_device_setup(struct net_device *dev)
-{
- dev->hard_header_len = 0;
- dev->addr_len = LAP_ALEN;
-
- dev->type = ARPHRD_IRDA;
- dev->tx_queue_len = 8; /* Window size + 1 s-frame */
-
- memset(dev->broadcast, 0xff, LAP_ALEN);
-
- dev->mtu = 2048;
- dev->flags = IFF_NOARP;
-}
-
-/*
- * Funciton alloc_irdadev
- * Allocates and sets up an IRDA device in a manner similar to
- * alloc_etherdev.
- */
-struct net_device *alloc_irdadev(int sizeof_priv)
-{
- return alloc_netdev(sizeof_priv, "irda%d", NET_NAME_UNKNOWN,
- irda_device_setup);
-}
-EXPORT_SYMBOL(alloc_irdadev);
-
-#ifdef CONFIG_ISA_DMA_API
-/*
- * Function setup_dma (idev, buffer, count, mode)
- *
- * Setup the DMA channel. Commonly used by LPC FIR drivers
- *
- */
-void irda_setup_dma(int channel, dma_addr_t buffer, int count, int mode)
-{
- unsigned long flags;
-
- flags = claim_dma_lock();
-
- disable_dma(channel);
- clear_dma_ff(channel);
- set_dma_mode(channel, mode);
- set_dma_addr(channel, buffer);
- set_dma_count(channel, count);
- enable_dma(channel);
-
- release_dma_lock(flags);
-}
-EXPORT_SYMBOL(irda_setup_dma);
-#endif
diff --git a/drivers/staging/irda/net/iriap.c b/drivers/staging/irda/net/iriap.c
deleted file mode 100644
index d64192e9db8b..000000000000
--- a/drivers/staging/irda/net/iriap.c
+++ /dev/null
@@ -1,1085 +0,0 @@
-/*********************************************************************
- *
- * Filename: iriap.c
- * Version: 0.8
- * Description: Information Access Protocol (IAP)
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Thu Aug 21 00:02:07 1997
- * Modified at: Sat Dec 25 16:42:42 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-
-#include <asm/byteorder.h>
-#include <asm/unaligned.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irttp.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/irias_object.h>
-#include <net/irda/iriap_event.h>
-#include <net/irda/iriap.h>
-
-/* FIXME: This one should go in irlmp.c */
-static const char *const ias_charset_types[] __maybe_unused = {
- "CS_ASCII",
- "CS_ISO_8859_1",
- "CS_ISO_8859_2",
- "CS_ISO_8859_3",
- "CS_ISO_8859_4",
- "CS_ISO_8859_5",
- "CS_ISO_8859_6",
- "CS_ISO_8859_7",
- "CS_ISO_8859_8",
- "CS_ISO_8859_9",
- "CS_UNICODE"
-};
-
-static hashbin_t *iriap = NULL;
-static void *service_handle;
-
-static void __iriap_close(struct iriap_cb *self);
-static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode);
-static void iriap_disconnect_indication(void *instance, void *sap,
- LM_REASON reason, struct sk_buff *skb);
-static void iriap_connect_indication(void *instance, void *sap,
- struct qos_info *qos, __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *skb);
-static void iriap_connect_confirm(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size, __u8 max_header_size,
- struct sk_buff *skb);
-static int iriap_data_indication(void *instance, void *sap,
- struct sk_buff *skb);
-
-static void iriap_watchdog_timer_expired(struct timer_list *t);
-
-static inline void iriap_start_watchdog_timer(struct iriap_cb *self,
- int timeout)
-{
- irda_start_timer(&self->watchdog_timer, timeout,
- iriap_watchdog_timer_expired);
-}
-
-static struct lock_class_key irias_objects_key;
-
-/*
- * Function iriap_init (void)
- *
- * Initializes the IrIAP layer, called by the module initialization code
- * in irmod.c
- */
-int __init iriap_init(void)
-{
- struct ias_object *obj;
- struct iriap_cb *server;
- __u8 oct_seq[6];
- __u16 hints;
-
- /* Allocate master array */
- iriap = hashbin_new(HB_LOCK);
- if (!iriap)
- return -ENOMEM;
-
- /* Object repository - defined in irias_object.c */
- irias_objects = hashbin_new(HB_LOCK);
- if (!irias_objects) {
- net_warn_ratelimited("%s: Can't allocate irias_objects hashbin!\n",
- __func__);
- hashbin_delete(iriap, NULL);
- return -ENOMEM;
- }
-
- lockdep_set_class_and_name(&irias_objects->hb_spinlock, &irias_objects_key,
- "irias_objects");
-
- /*
- * Register some default services for IrLMP
- */
- hints = irlmp_service_to_hint(S_COMPUTER);
- service_handle = irlmp_register_service(hints);
-
- /* Register the Device object with LM-IAS */
- obj = irias_new_object("Device", IAS_DEVICE_ID);
- irias_add_string_attrib(obj, "DeviceName", "Linux", IAS_KERNEL_ATTR);
-
- oct_seq[0] = 0x01; /* Version 1 */
- oct_seq[1] = 0x00; /* IAS support bits */
- oct_seq[2] = 0x00; /* LM-MUX support bits */
-#ifdef CONFIG_IRDA_ULTRA
- oct_seq[2] |= 0x04; /* Connectionless Data support */
-#endif
- irias_add_octseq_attrib(obj, "IrLMPSupport", oct_seq, 3,
- IAS_KERNEL_ATTR);
- irias_insert_object(obj);
-
- /*
- * Register server support with IrLMP so we can accept incoming
- * connections
- */
- server = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
- if (!server) {
- pr_debug("%s(), unable to open server\n", __func__);
- return -1;
- }
- iriap_register_lsap(server, LSAP_IAS, IAS_SERVER);
-
- return 0;
-}
-
-/*
- * Function iriap_cleanup (void)
- *
- * Initializes the IrIAP layer, called by the module cleanup code in
- * irmod.c
- */
-void iriap_cleanup(void)
-{
- irlmp_unregister_service(service_handle);
-
- hashbin_delete(iriap, (FREE_FUNC) __iriap_close);
- hashbin_delete(irias_objects, (FREE_FUNC) __irias_delete_object);
-}
-
-/*
- * Function iriap_open (void)
- *
- * Opens an instance of the IrIAP layer, and registers with IrLMP
- */
-struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv,
- CONFIRM_CALLBACK callback)
-{
- struct iriap_cb *self;
-
- self = kzalloc(sizeof(*self), GFP_ATOMIC);
- if (!self)
- return NULL;
-
- /*
- * Initialize instance
- */
-
- self->magic = IAS_MAGIC;
- self->mode = mode;
- if (mode == IAS_CLIENT) {
- if (iriap_register_lsap(self, slsap_sel, mode)) {
- kfree(self);
- return NULL;
- }
- }
-
- self->confirm = callback;
- self->priv = priv;
-
- /* iriap_getvaluebyclass_request() will construct packets before
- * we connect, so this must have a sane value... Jean II */
- self->max_header_size = LMP_MAX_HEADER;
-
- timer_setup(&self->watchdog_timer, NULL, 0);
-
- hashbin_insert(iriap, (irda_queue_t *) self, (long) self, NULL);
-
- /* Initialize state machines */
- iriap_next_client_state(self, S_DISCONNECT);
- iriap_next_call_state(self, S_MAKE_CALL);
- iriap_next_server_state(self, R_DISCONNECT);
- iriap_next_r_connect_state(self, R_WAITING);
-
- return self;
-}
-EXPORT_SYMBOL(iriap_open);
-
-/*
- * Function __iriap_close (self)
- *
- * Removes (deallocates) the IrIAP instance
- *
- */
-static void __iriap_close(struct iriap_cb *self)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- del_timer(&self->watchdog_timer);
-
- if (self->request_skb)
- dev_kfree_skb(self->request_skb);
-
- self->magic = 0;
-
- kfree(self);
-}
-
-/*
- * Function iriap_close (void)
- *
- * Closes IrIAP and deregisters with IrLMP
- */
-void iriap_close(struct iriap_cb *self)
-{
- struct iriap_cb *entry;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- if (self->lsap) {
- irlmp_close_lsap(self->lsap);
- self->lsap = NULL;
- }
-
- entry = (struct iriap_cb *) hashbin_remove(iriap, (long) self, NULL);
- IRDA_ASSERT(entry == self, return;);
-
- __iriap_close(self);
-}
-EXPORT_SYMBOL(iriap_close);
-
-static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode)
-{
- notify_t notify;
-
- irda_notify_init(&notify);
- notify.connect_confirm = iriap_connect_confirm;
- notify.connect_indication = iriap_connect_indication;
- notify.disconnect_indication = iriap_disconnect_indication;
- notify.data_indication = iriap_data_indication;
- notify.instance = self;
- if (mode == IAS_CLIENT)
- strcpy(notify.name, "IrIAS cli");
- else
- strcpy(notify.name, "IrIAS srv");
-
- self->lsap = irlmp_open_lsap(slsap_sel, &notify, 0);
- if (self->lsap == NULL) {
- net_err_ratelimited("%s: Unable to allocated LSAP!\n",
- __func__);
- return -1;
- }
- self->slsap_sel = self->lsap->slsap_sel;
-
- return 0;
-}
-
-/*
- * Function iriap_disconnect_indication (handle, reason)
- *
- * Got disconnect, so clean up everything associated with this connection
- *
- */
-static void iriap_disconnect_indication(void *instance, void *sap,
- LM_REASON reason,
- struct sk_buff *skb)
-{
- struct iriap_cb *self;
-
- pr_debug("%s(), reason=%s [%d]\n", __func__,
- irlmp_reason_str(reason), reason);
-
- self = instance;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- IRDA_ASSERT(iriap != NULL, return;);
-
- del_timer(&self->watchdog_timer);
-
- /* Not needed */
- if (skb)
- dev_kfree_skb(skb);
-
- if (self->mode == IAS_CLIENT) {
- pr_debug("%s(), disconnect as client\n", __func__);
-
-
- iriap_do_client_event(self, IAP_LM_DISCONNECT_INDICATION,
- NULL);
- /*
- * Inform service user that the request failed by sending
- * it a NULL value. Warning, the client might close us, so
- * remember no to use self anymore after calling confirm
- */
- if (self->confirm)
- self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
- } else {
- pr_debug("%s(), disconnect as server\n", __func__);
- iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION,
- NULL);
- iriap_close(self);
- }
-}
-
-/*
- * Function iriap_disconnect_request (handle)
- */
-static void iriap_disconnect_request(struct iriap_cb *self)
-{
- struct sk_buff *tx_skb;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
- if (tx_skb == NULL) {
- pr_debug("%s(), Could not allocate an sk_buff of length %d\n",
- __func__, LMP_MAX_HEADER);
- return;
- }
-
- /*
- * Reserve space for MUX control and LAP header
- */
- skb_reserve(tx_skb, LMP_MAX_HEADER);
-
- irlmp_disconnect_request(self->lsap, tx_skb);
-}
-
-/*
- * Function iriap_getvaluebyclass (addr, name, attr)
- *
- * Retrieve all values from attribute in all objects with given class
- * name
- */
-int iriap_getvaluebyclass_request(struct iriap_cb *self,
- __u32 saddr, __u32 daddr,
- char *name, char *attr)
-{
- struct sk_buff *tx_skb;
- int name_len, attr_len, skb_len;
- __u8 *frame;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return -1;);
-
- /* Client must supply the destination device address */
- if (!daddr)
- return -1;
-
- self->daddr = daddr;
- self->saddr = saddr;
-
- /*
- * Save operation, so we know what the later indication is about
- */
- self->operation = GET_VALUE_BY_CLASS;
-
- /* Give ourselves 10 secs to finish this operation */
- iriap_start_watchdog_timer(self, 10*HZ);
-
- name_len = strlen(name); /* Up to IAS_MAX_CLASSNAME = 60 */
- attr_len = strlen(attr); /* Up to IAS_MAX_ATTRIBNAME = 60 */
-
- skb_len = self->max_header_size+2+name_len+1+attr_len+4;
- tx_skb = alloc_skb(skb_len, GFP_ATOMIC);
- if (!tx_skb)
- return -ENOMEM;
-
- /* Reserve space for MUX and LAP header */
- skb_reserve(tx_skb, self->max_header_size);
- skb_put(tx_skb, 3+name_len+attr_len);
- frame = tx_skb->data;
-
- /* Build frame */
- frame[0] = IAP_LST | GET_VALUE_BY_CLASS;
- frame[1] = name_len; /* Insert length of name */
- memcpy(frame+2, name, name_len); /* Insert name */
- frame[2+name_len] = attr_len; /* Insert length of attr */
- memcpy(frame+3+name_len, attr, attr_len); /* Insert attr */
-
- iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, tx_skb);
-
- /* Drop reference count - see state_s_disconnect(). */
- dev_kfree_skb(tx_skb);
-
- return 0;
-}
-EXPORT_SYMBOL(iriap_getvaluebyclass_request);
-
-/*
- * Function iriap_getvaluebyclass_confirm (self, skb)
- *
- * Got result from GetValueByClass command. Parse it and return result
- * to service user.
- *
- */
-static void iriap_getvaluebyclass_confirm(struct iriap_cb *self,
- struct sk_buff *skb)
-{
- struct ias_value *value;
- int charset;
- __u32 value_len;
- __u32 tmp_cpu32;
- __u16 obj_id;
- __u16 len;
- __u8 type;
- __u8 *fp;
- int n;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
-
- /* Initialize variables */
- fp = skb->data;
- n = 2;
-
- /* Get length, MSB first */
- len = get_unaligned_be16(fp + n);
- n += 2;
-
- pr_debug("%s(), len=%d\n", __func__, len);
-
- /* Get object ID, MSB first */
- obj_id = get_unaligned_be16(fp + n);
- n += 2;
-
- type = fp[n++];
- pr_debug("%s(), Value type = %d\n", __func__, type);
-
- switch (type) {
- case IAS_INTEGER:
- memcpy(&tmp_cpu32, fp+n, 4); n += 4;
- be32_to_cpus(&tmp_cpu32);
- value = irias_new_integer_value(tmp_cpu32);
-
- /* Legal values restricted to 0x01-0x6f, page 15 irttp */
- pr_debug("%s(), lsap=%d\n", __func__, value->t.integer);
- break;
- case IAS_STRING:
- charset = fp[n++];
-
- switch (charset) {
- case CS_ASCII:
- break;
-/* case CS_ISO_8859_1: */
-/* case CS_ISO_8859_2: */
-/* case CS_ISO_8859_3: */
-/* case CS_ISO_8859_4: */
-/* case CS_ISO_8859_5: */
-/* case CS_ISO_8859_6: */
-/* case CS_ISO_8859_7: */
-/* case CS_ISO_8859_8: */
-/* case CS_ISO_8859_9: */
-/* case CS_UNICODE: */
- default:
- pr_debug("%s(), charset [%d] %s, not supported\n",
- __func__, charset,
- charset < ARRAY_SIZE(ias_charset_types) ?
- ias_charset_types[charset] :
- "(unknown)");
-
- /* Aborting, close connection! */
- iriap_disconnect_request(self);
- return;
- /* break; */
- }
- value_len = fp[n++];
- pr_debug("%s(), strlen=%d\n", __func__, value_len);
-
- /* Make sure the string is null-terminated */
- if (n + value_len < skb->len)
- fp[n + value_len] = 0x00;
- pr_debug("Got string %s\n", fp+n);
-
- /* Will truncate to IAS_MAX_STRING bytes */
- value = irias_new_string_value(fp+n);
- break;
- case IAS_OCT_SEQ:
- value_len = get_unaligned_be16(fp + n);
- n += 2;
-
- /* Will truncate to IAS_MAX_OCTET_STRING bytes */
- value = irias_new_octseq_value(fp+n, value_len);
- break;
- default:
- value = irias_new_missing_value();
- break;
- }
-
- /* Finished, close connection! */
- iriap_disconnect_request(self);
-
- /* Warning, the client might close us, so remember no to use self
- * anymore after calling confirm
- */
- if (self->confirm)
- self->confirm(IAS_SUCCESS, obj_id, value, self->priv);
- else {
- pr_debug("%s(), missing handler!\n", __func__);
- irias_delete_value(value);
- }
-}
-
-/*
- * Function iriap_getvaluebyclass_response ()
- *
- * Send answer back to remote LM-IAS
- *
- */
-static void iriap_getvaluebyclass_response(struct iriap_cb *self,
- __u16 obj_id,
- __u8 ret_code,
- struct ias_value *value)
-{
- struct sk_buff *tx_skb;
- int n;
- __be32 tmp_be32;
- __be16 tmp_be16;
- __u8 *fp;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
- IRDA_ASSERT(value != NULL, return;);
- IRDA_ASSERT(value->len <= 1024, return;);
-
- /* Initialize variables */
- n = 0;
-
- /*
- * We must adjust the size of the response after the length of the
- * value. We add 32 bytes because of the 6 bytes for the frame and
- * max 5 bytes for the value coding.
- */
- tx_skb = alloc_skb(value->len + self->max_header_size + 32,
- GFP_ATOMIC);
- if (!tx_skb)
- return;
-
- /* Reserve space for MUX and LAP header */
- skb_reserve(tx_skb, self->max_header_size);
- skb_put(tx_skb, 6);
-
- fp = tx_skb->data;
-
- /* Build frame */
- fp[n++] = GET_VALUE_BY_CLASS | IAP_LST;
- fp[n++] = ret_code;
-
- /* Insert list length (MSB first) */
- tmp_be16 = htons(0x0001);
- memcpy(fp+n, &tmp_be16, 2); n += 2;
-
- /* Insert object identifier ( MSB first) */
- tmp_be16 = cpu_to_be16(obj_id);
- memcpy(fp+n, &tmp_be16, 2); n += 2;
-
- switch (value->type) {
- case IAS_STRING:
- skb_put(tx_skb, 3 + value->len);
- fp[n++] = value->type;
- fp[n++] = 0; /* ASCII */
- fp[n++] = (__u8) value->len;
- memcpy(fp+n, value->t.string, value->len); n+=value->len;
- break;
- case IAS_INTEGER:
- skb_put(tx_skb, 5);
- fp[n++] = value->type;
-
- tmp_be32 = cpu_to_be32(value->t.integer);
- memcpy(fp+n, &tmp_be32, 4); n += 4;
- break;
- case IAS_OCT_SEQ:
- skb_put(tx_skb, 3 + value->len);
- fp[n++] = value->type;
-
- tmp_be16 = cpu_to_be16(value->len);
- memcpy(fp+n, &tmp_be16, 2); n += 2;
- memcpy(fp+n, value->t.oct_seq, value->len); n+=value->len;
- break;
- case IAS_MISSING:
- pr_debug("%s: sending IAS_MISSING\n", __func__);
- skb_put(tx_skb, 1);
- fp[n++] = value->type;
- break;
- default:
- pr_debug("%s(), type not implemented!\n", __func__);
- break;
- }
- iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, tx_skb);
-
- /* Drop reference count - see state_r_execute(). */
- dev_kfree_skb(tx_skb);
-}
-
-/*
- * Function iriap_getvaluebyclass_indication (self, skb)
- *
- * getvaluebyclass is requested from peer LM-IAS
- *
- */
-static void iriap_getvaluebyclass_indication(struct iriap_cb *self,
- struct sk_buff *skb)
-{
- struct ias_object *obj;
- struct ias_attrib *attrib;
- int name_len;
- int attr_len;
- char name[IAS_MAX_CLASSNAME + 1]; /* 60 bytes */
- char attr[IAS_MAX_ATTRIBNAME + 1]; /* 60 bytes */
- __u8 *fp;
- int n;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
-
- fp = skb->data;
- n = 1;
-
- name_len = fp[n++];
-
- IRDA_ASSERT(name_len < IAS_MAX_CLASSNAME + 1, return;);
-
- memcpy(name, fp+n, name_len); n+=name_len;
- name[name_len] = '\0';
-
- attr_len = fp[n++];
-
- IRDA_ASSERT(attr_len < IAS_MAX_ATTRIBNAME + 1, return;);
-
- memcpy(attr, fp+n, attr_len); n+=attr_len;
- attr[attr_len] = '\0';
-
- pr_debug("LM-IAS: Looking up %s: %s\n", name, attr);
- obj = irias_find_object(name);
-
- if (obj == NULL) {
- pr_debug("LM-IAS: Object %s not found\n", name);
- iriap_getvaluebyclass_response(self, 0x1235, IAS_CLASS_UNKNOWN,
- &irias_missing);
- return;
- }
- pr_debug("LM-IAS: found %s, id=%d\n", obj->name, obj->id);
-
- attrib = irias_find_attrib(obj, attr);
- if (attrib == NULL) {
- pr_debug("LM-IAS: Attribute %s not found\n", attr);
- iriap_getvaluebyclass_response(self, obj->id,
- IAS_ATTRIB_UNKNOWN,
- &irias_missing);
- return;
- }
-
- /* We have a match; send the value. */
- iriap_getvaluebyclass_response(self, obj->id, IAS_SUCCESS,
- attrib->value);
-}
-
-/*
- * Function iriap_send_ack (void)
- *
- * Currently not used
- *
- */
-void iriap_send_ack(struct iriap_cb *self)
-{
- struct sk_buff *tx_skb;
- __u8 *frame;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- tx_skb = alloc_skb(LMP_MAX_HEADER + 1, GFP_ATOMIC);
- if (!tx_skb)
- return;
-
- /* Reserve space for MUX and LAP header */
- skb_reserve(tx_skb, self->max_header_size);
- skb_put(tx_skb, 1);
- frame = tx_skb->data;
-
- /* Build frame */
- frame[0] = IAP_LST | IAP_ACK | self->operation;
-
- irlmp_data_request(self->lsap, tx_skb);
-}
-
-void iriap_connect_request(struct iriap_cb *self)
-{
- int ret;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- ret = irlmp_connect_request(self->lsap, LSAP_IAS,
- self->saddr, self->daddr,
- NULL, NULL);
- if (ret < 0) {
- pr_debug("%s(), connect failed!\n", __func__);
- self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
- }
-}
-
-/*
- * Function iriap_connect_confirm (handle, skb)
- *
- * LSAP connection confirmed!
- *
- */
-static void iriap_connect_confirm(void *instance, void *sap,
- struct qos_info *qos, __u32 max_seg_size,
- __u8 max_header_size,
- struct sk_buff *skb)
-{
- struct iriap_cb *self;
-
- self = instance;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
-
- self->max_data_size = max_seg_size;
- self->max_header_size = max_header_size;
-
- del_timer(&self->watchdog_timer);
-
- iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, skb);
-
- /* Drop reference count - see state_s_make_call(). */
- dev_kfree_skb(skb);
-}
-
-/*
- * Function iriap_connect_indication ( handle, skb)
- *
- * Remote LM-IAS is requesting connection
- *
- */
-static void iriap_connect_indication(void *instance, void *sap,
- struct qos_info *qos, __u32 max_seg_size,
- __u8 max_header_size,
- struct sk_buff *skb)
-{
- struct iriap_cb *self, *new;
-
- self = instance;
-
- IRDA_ASSERT(skb != NULL, return;);
- IRDA_ASSERT(self != NULL, goto out;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, goto out;);
-
- /* Start new server */
- new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
- if (!new) {
- pr_debug("%s(), open failed\n", __func__);
- goto out;
- }
-
- /* Now attach up the new "socket" */
- new->lsap = irlmp_dup(self->lsap, new);
- if (!new->lsap) {
- pr_debug("%s(), dup failed!\n", __func__);
- goto out;
- }
-
- new->max_data_size = max_seg_size;
- new->max_header_size = max_header_size;
-
- /* Clean up the original one to keep it in listen state */
- irlmp_listen(self->lsap);
-
- iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, skb);
-
-out:
- /* Drop reference count - see state_r_disconnect(). */
- dev_kfree_skb(skb);
-}
-
-/*
- * Function iriap_data_indication (handle, skb)
- *
- * Receives data from connection identified by handle from IrLMP
- *
- */
-static int iriap_data_indication(void *instance, void *sap,
- struct sk_buff *skb)
-{
- struct iriap_cb *self;
- __u8 *frame;
- __u8 opcode;
-
- self = instance;
-
- IRDA_ASSERT(skb != NULL, return 0;);
- IRDA_ASSERT(self != NULL, goto out;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, goto out;);
-
- frame = skb->data;
-
- if (self->mode == IAS_SERVER) {
- /* Call server */
- pr_debug("%s(), Calling server!\n", __func__);
- iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb);
- goto out;
- }
- opcode = frame[0];
- if (~opcode & IAP_LST) {
- net_warn_ratelimited("%s:, IrIAS multiframe commands or results is not implemented yet!\n",
- __func__);
- goto out;
- }
-
- /* Check for ack frames since they don't contain any data */
- if (opcode & IAP_ACK) {
- pr_debug("%s() Got ack frame!\n", __func__);
- goto out;
- }
-
- opcode &= ~IAP_LST; /* Mask away LST bit */
-
- switch (opcode) {
- case GET_INFO_BASE:
- pr_debug("IrLMP GetInfoBaseDetails not implemented!\n");
- break;
- case GET_VALUE_BY_CLASS:
- iriap_do_call_event(self, IAP_RECV_F_LST, NULL);
-
- switch (frame[1]) {
- case IAS_SUCCESS:
- iriap_getvaluebyclass_confirm(self, skb);
- break;
- case IAS_CLASS_UNKNOWN:
- pr_debug("%s(), No such class!\n", __func__);
- /* Finished, close connection! */
- iriap_disconnect_request(self);
-
- /*
- * Warning, the client might close us, so remember
- * no to use self anymore after calling confirm
- */
- if (self->confirm)
- self->confirm(IAS_CLASS_UNKNOWN, 0, NULL,
- self->priv);
- break;
- case IAS_ATTRIB_UNKNOWN:
- pr_debug("%s(), No such attribute!\n", __func__);
- /* Finished, close connection! */
- iriap_disconnect_request(self);
-
- /*
- * Warning, the client might close us, so remember
- * no to use self anymore after calling confirm
- */
- if (self->confirm)
- self->confirm(IAS_ATTRIB_UNKNOWN, 0, NULL,
- self->priv);
- break;
- }
- break;
- default:
- pr_debug("%s(), Unknown op-code: %02x\n", __func__,
- opcode);
- break;
- }
-
-out:
- /* Cleanup - sub-calls will have done skb_get() as needed. */
- dev_kfree_skb(skb);
- return 0;
-}
-
-/*
- * Function iriap_call_indication (self, skb)
- *
- * Received call to server from peer LM-IAS
- *
- */
-void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb)
-{
- __u8 *fp;
- __u8 opcode;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
-
- fp = skb->data;
-
- opcode = fp[0];
- if (~opcode & 0x80) {
- net_warn_ratelimited("%s: IrIAS multiframe commands or results is not implemented yet!\n",
- __func__);
- return;
- }
- opcode &= 0x7f; /* Mask away LST bit */
-
- switch (opcode) {
- case GET_INFO_BASE:
- net_warn_ratelimited("%s: GetInfoBaseDetails not implemented yet!\n",
- __func__);
- break;
- case GET_VALUE_BY_CLASS:
- iriap_getvaluebyclass_indication(self, skb);
- break;
- }
- /* skb will be cleaned up in iriap_data_indication */
-}
-
-/*
- * Function iriap_watchdog_timer_expired (data)
- *
- * Query has taken too long time, so abort
- *
- */
-static void iriap_watchdog_timer_expired(struct timer_list *t)
-{
- struct iriap_cb *self = from_timer(self, t, watchdog_timer);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- /* iriap_close(self); */
-}
-
-#ifdef CONFIG_PROC_FS
-
-static const char *const ias_value_types[] = {
- "IAS_MISSING",
- "IAS_INTEGER",
- "IAS_OCT_SEQ",
- "IAS_STRING"
-};
-
-static inline struct ias_object *irias_seq_idx(loff_t pos)
-{
- struct ias_object *obj;
-
- for (obj = (struct ias_object *) hashbin_get_first(irias_objects);
- obj; obj = (struct ias_object *) hashbin_get_next(irias_objects)) {
- if (pos-- == 0)
- break;
- }
-
- return obj;
-}
-
-static void *irias_seq_start(struct seq_file *seq, loff_t *pos)
-{
- spin_lock_irq(&irias_objects->hb_spinlock);
-
- return *pos ? irias_seq_idx(*pos - 1) : SEQ_START_TOKEN;
-}
-
-static void *irias_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- ++*pos;
-
- return (v == SEQ_START_TOKEN)
- ? (void *) hashbin_get_first(irias_objects)
- : (void *) hashbin_get_next(irias_objects);
-}
-
-static void irias_seq_stop(struct seq_file *seq, void *v)
-{
- spin_unlock_irq(&irias_objects->hb_spinlock);
-}
-
-static int irias_seq_show(struct seq_file *seq, void *v)
-{
- if (v == SEQ_START_TOKEN)
- seq_puts(seq, "LM-IAS Objects:\n");
- else {
- struct ias_object *obj = v;
- struct ias_attrib *attrib;
-
- IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -EINVAL;);
-
- seq_printf(seq, "name: %s, id=%d\n",
- obj->name, obj->id);
-
- /* Careful for priority inversions here !
- * All other uses of attrib spinlock are independent of
- * the object spinlock, so we are safe. Jean II */
- spin_lock(&obj->attribs->hb_spinlock);
-
- /* List all attributes for this object */
- for (attrib = (struct ias_attrib *) hashbin_get_first(obj->attribs);
- attrib != NULL;
- attrib = (struct ias_attrib *) hashbin_get_next(obj->attribs)) {
-
- IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC,
- goto outloop; );
-
- seq_printf(seq, " - Attribute name: \"%s\", ",
- attrib->name);
- seq_printf(seq, "value[%s]: ",
- ias_value_types[attrib->value->type]);
-
- switch (attrib->value->type) {
- case IAS_INTEGER:
- seq_printf(seq, "%d\n",
- attrib->value->t.integer);
- break;
- case IAS_STRING:
- seq_printf(seq, "\"%s\"\n",
- attrib->value->t.string);
- break;
- case IAS_OCT_SEQ:
- seq_printf(seq, "octet sequence (%d bytes)\n",
- attrib->value->len);
- break;
- case IAS_MISSING:
- seq_puts(seq, "missing\n");
- break;
- default:
- seq_printf(seq, "type %d?\n",
- attrib->value->type);
- }
- seq_putc(seq, '\n');
-
- }
- IRDA_ASSERT_LABEL(outloop:)
- spin_unlock(&obj->attribs->hb_spinlock);
- }
-
- return 0;
-}
-
-static const struct seq_operations irias_seq_ops = {
- .start = irias_seq_start,
- .next = irias_seq_next,
- .stop = irias_seq_stop,
- .show = irias_seq_show,
-};
-
-static int irias_seq_open(struct inode *inode, struct file *file)
-{
- IRDA_ASSERT( irias_objects != NULL, return -EINVAL;);
-
- return seq_open(file, &irias_seq_ops);
-}
-
-const struct file_operations irias_seq_fops = {
- .owner = THIS_MODULE,
- .open = irias_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-#endif /* PROC_FS */
diff --git a/drivers/staging/irda/net/iriap_event.c b/drivers/staging/irda/net/iriap_event.c
deleted file mode 100644
index e6098b2e048a..000000000000
--- a/drivers/staging/irda/net/iriap_event.c
+++ /dev/null
@@ -1,496 +0,0 @@
-/*********************************************************************
- *
- * Filename: iriap_event.c
- * Version: 0.1
- * Description: IAP Finite State Machine
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Thu Aug 21 00:02:07 1997
- * Modified at: Wed Mar 1 11:28:34 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1997, 1999-2000 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/slab.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/iriap.h>
-#include <net/irda/iriap_event.h>
-
-static void state_s_disconnect (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-static void state_s_connecting (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-static void state_s_call (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-
-static void state_s_make_call (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-static void state_s_calling (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-static void state_s_outstanding (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-static void state_s_replying (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-static void state_s_wait_active (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-
-static void state_r_disconnect (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-static void state_r_call (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-static void state_r_waiting (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-static void state_r_wait_active (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-static void state_r_receiving (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-static void state_r_execute (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-static void state_r_returning (struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb);
-
-static void (*iriap_state[])(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb) = {
- /* Client FSM */
- state_s_disconnect,
- state_s_connecting,
- state_s_call,
-
- /* S-Call FSM */
- state_s_make_call,
- state_s_calling,
- state_s_outstanding,
- state_s_replying,
- state_s_wait_for_call,
- state_s_wait_active,
-
- /* Server FSM */
- state_r_disconnect,
- state_r_call,
-
- /* R-Connect FSM */
- state_r_waiting,
- state_r_wait_active,
- state_r_receiving,
- state_r_execute,
- state_r_returning,
-};
-
-void iriap_next_client_state(struct iriap_cb *self, IRIAP_STATE state)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- self->client_state = state;
-}
-
-void iriap_next_call_state(struct iriap_cb *self, IRIAP_STATE state)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- self->call_state = state;
-}
-
-void iriap_next_server_state(struct iriap_cb *self, IRIAP_STATE state)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- self->server_state = state;
-}
-
-void iriap_next_r_connect_state(struct iriap_cb *self, IRIAP_STATE state)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- self->r_connect_state = state;
-}
-
-void iriap_do_client_event(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- (*iriap_state[ self->client_state]) (self, event, skb);
-}
-
-void iriap_do_call_event(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- (*iriap_state[ self->call_state]) (self, event, skb);
-}
-
-void iriap_do_server_event(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- (*iriap_state[ self->server_state]) (self, event, skb);
-}
-
-void iriap_do_r_connect_event(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- (*iriap_state[ self->r_connect_state]) (self, event, skb);
-}
-
-
-/*
- * Function state_s_disconnect (event, skb)
- *
- * S-Disconnect, The device has no LSAP connection to a particular
- * remote device.
- */
-static void state_s_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- switch (event) {
- case IAP_CALL_REQUEST_GVBC:
- iriap_next_client_state(self, S_CONNECTING);
- IRDA_ASSERT(self->request_skb == NULL, return;);
- /* Don't forget to refcount it -
- * see iriap_getvaluebyclass_request(). */
- skb_get(skb);
- self->request_skb = skb;
- iriap_connect_request(self);
- break;
- case IAP_LM_DISCONNECT_INDICATION:
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__, event);
- break;
- }
-}
-
-/*
- * Function state_s_connecting (self, event, skb)
- *
- * S-Connecting
- *
- */
-static void state_s_connecting(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- switch (event) {
- case IAP_LM_CONNECT_CONFIRM:
- /*
- * Jump to S-Call FSM
- */
- iriap_do_call_event(self, IAP_CALL_REQUEST, skb);
- /* iriap_call_request(self, 0,0,0); */
- iriap_next_client_state(self, S_CALL);
- break;
- case IAP_LM_DISCONNECT_INDICATION:
- /* Abort calls */
- iriap_next_call_state(self, S_MAKE_CALL);
- iriap_next_client_state(self, S_DISCONNECT);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__, event);
- break;
- }
-}
-
-/*
- * Function state_s_call (self, event, skb)
- *
- * S-Call, The device can process calls to a specific remote
- * device. Whenever the LSAP connection is disconnected, this state
- * catches that event and clears up
- */
-static void state_s_call(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
-
- switch (event) {
- case IAP_LM_DISCONNECT_INDICATION:
- /* Abort calls */
- iriap_next_call_state(self, S_MAKE_CALL);
- iriap_next_client_state(self, S_DISCONNECT);
- break;
- default:
- pr_debug("state_s_call: Unknown event %d\n", event);
- break;
- }
-}
-
-/*
- * Function state_s_make_call (event, skb)
- *
- * S-Make-Call
- *
- */
-static void state_s_make_call(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- struct sk_buff *tx_skb;
-
- IRDA_ASSERT(self != NULL, return;);
-
- switch (event) {
- case IAP_CALL_REQUEST:
- /* Already refcounted - see state_s_disconnect() */
- tx_skb = self->request_skb;
- self->request_skb = NULL;
-
- irlmp_data_request(self->lsap, tx_skb);
- iriap_next_call_state(self, S_OUTSTANDING);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__, event);
- break;
- }
-}
-
-/*
- * Function state_s_calling (event, skb)
- *
- * S-Calling
- *
- */
-static void state_s_calling(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- pr_debug("%s(), Not implemented\n", __func__);
-}
-
-/*
- * Function state_s_outstanding (event, skb)
- *
- * S-Outstanding, The device is waiting for a response to a command
- *
- */
-static void state_s_outstanding(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
-
- switch (event) {
- case IAP_RECV_F_LST:
- /*iriap_send_ack(self);*/
- /*LM_Idle_request(idle); */
-
- iriap_next_call_state(self, S_WAIT_FOR_CALL);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__, event);
- break;
- }
-}
-
-/*
- * Function state_s_replying (event, skb)
- *
- * S-Replying, The device is collecting a multiple part response
- */
-static void state_s_replying(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- pr_debug("%s(), Not implemented\n", __func__);
-}
-
-/*
- * Function state_s_wait_for_call (event, skb)
- *
- * S-Wait-for-Call
- *
- */
-static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- pr_debug("%s(), Not implemented\n", __func__);
-}
-
-
-/*
- * Function state_s_wait_active (event, skb)
- *
- * S-Wait-Active
- *
- */
-static void state_s_wait_active(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- pr_debug("%s(), Not implemented\n", __func__);
-}
-
-/**************************************************************************
- *
- * Server FSM
- *
- **************************************************************************/
-
-/*
- * Function state_r_disconnect (self, event, skb)
- *
- * LM-IAS server is disconnected (not processing any requests!)
- *
- */
-static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- struct sk_buff *tx_skb;
-
- switch (event) {
- case IAP_LM_CONNECT_INDICATION:
- tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
- if (tx_skb == NULL)
- return;
-
- /* Reserve space for MUX_CONTROL and LAP header */
- skb_reserve(tx_skb, LMP_MAX_HEADER);
-
- irlmp_connect_response(self->lsap, tx_skb);
- /*LM_Idle_request(idle); */
-
- iriap_next_server_state(self, R_CALL);
-
- /*
- * Jump to R-Connect FSM, we skip R-Waiting since we do not
- * care about LM_Idle_request()!
- */
- iriap_next_r_connect_state(self, R_RECEIVING);
- break;
- default:
- pr_debug("%s(), unknown event %d\n", __func__, event);
- break;
- }
-}
-
-/*
- * Function state_r_call (self, event, skb)
- */
-static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- switch (event) {
- case IAP_LM_DISCONNECT_INDICATION:
- /* Abort call */
- iriap_next_server_state(self, R_DISCONNECT);
- iriap_next_r_connect_state(self, R_WAITING);
- break;
- default:
- pr_debug("%s(), unknown event!\n", __func__);
- break;
- }
-}
-
-/*
- * R-Connect FSM
- */
-
-/*
- * Function state_r_waiting (self, event, skb)
- */
-static void state_r_waiting(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- pr_debug("%s(), Not implemented\n", __func__);
-}
-
-static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- pr_debug("%s(), Not implemented\n", __func__);
-}
-
-/*
- * Function state_r_receiving (self, event, skb)
- *
- * We are receiving a command
- *
- */
-static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- switch (event) {
- case IAP_RECV_F_LST:
- iriap_next_r_connect_state(self, R_EXECUTE);
-
- iriap_call_indication(self, skb);
- break;
- default:
- pr_debug("%s(), unknown event!\n", __func__);
- break;
- }
-}
-
-/*
- * Function state_r_execute (self, event, skb)
- *
- * The server is processing the request
- *
- */
-static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(skb != NULL, return;);
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
-
- switch (event) {
- case IAP_CALL_RESPONSE:
- /*
- * Since we don't implement the Waiting state, we return
- * to state Receiving instead, DB.
- */
- iriap_next_r_connect_state(self, R_RECEIVING);
-
- /* Don't forget to refcount it - see
- * iriap_getvaluebyclass_response(). */
- skb_get(skb);
-
- irlmp_data_request(self->lsap, skb);
- break;
- default:
- pr_debug("%s(), unknown event!\n", __func__);
- break;
- }
-}
-
-static void state_r_returning(struct iriap_cb *self, IRIAP_EVENT event,
- struct sk_buff *skb)
-{
- pr_debug("%s(), event=%d\n", __func__, event);
-
- switch (event) {
- case IAP_RECV_F_LST:
- break;
- default:
- break;
- }
-}
diff --git a/drivers/staging/irda/net/irias_object.c b/drivers/staging/irda/net/irias_object.c
deleted file mode 100644
index 53b86d0e1630..000000000000
--- a/drivers/staging/irda/net/irias_object.c
+++ /dev/null
@@ -1,555 +0,0 @@
-/*********************************************************************
- *
- * Filename: irias_object.c
- * Version: 0.3
- * Description: IAS object database and functions
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Thu Oct 1 22:50:04 1998
- * Modified at: Wed Dec 15 11:23:16 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/socket.h>
-#include <linux/module.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irias_object.h>
-
-hashbin_t *irias_objects;
-
-/*
- * Used when a missing value needs to be returned
- */
-struct ias_value irias_missing = { IAS_MISSING, 0, 0, 0, {0}};
-
-
-/*
- * Function ias_new_object (name, id)
- *
- * Create a new IAS object
- *
- */
-struct ias_object *irias_new_object( char *name, int id)
-{
- struct ias_object *obj;
-
- obj = kzalloc(sizeof(struct ias_object), GFP_ATOMIC);
- if (obj == NULL) {
- net_warn_ratelimited("%s(), Unable to allocate object!\n",
- __func__);
- return NULL;
- }
-
- obj->magic = IAS_OBJECT_MAGIC;
- obj->name = kstrndup(name, IAS_MAX_CLASSNAME, GFP_ATOMIC);
- if (!obj->name) {
- net_warn_ratelimited("%s(), Unable to allocate name!\n",
- __func__);
- kfree(obj);
- return NULL;
- }
- obj->id = id;
-
- /* Locking notes : the attrib spinlock has lower precendence
- * than the objects spinlock. Never grap the objects spinlock
- * while holding any attrib spinlock (risk of deadlock). Jean II */
- obj->attribs = hashbin_new(HB_LOCK);
-
- if (obj->attribs == NULL) {
- net_warn_ratelimited("%s(), Unable to allocate attribs!\n",
- __func__);
- kfree(obj->name);
- kfree(obj);
- return NULL;
- }
-
- return obj;
-}
-EXPORT_SYMBOL(irias_new_object);
-
-/*
- * Function irias_delete_attrib (attrib)
- *
- * Delete given attribute and deallocate all its memory
- *
- */
-static void __irias_delete_attrib(struct ias_attrib *attrib)
-{
- IRDA_ASSERT(attrib != NULL, return;);
- IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;);
-
- kfree(attrib->name);
-
- irias_delete_value(attrib->value);
- attrib->magic = ~IAS_ATTRIB_MAGIC;
-
- kfree(attrib);
-}
-
-void __irias_delete_object(struct ias_object *obj)
-{
- IRDA_ASSERT(obj != NULL, return;);
- IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
-
- kfree(obj->name);
-
- hashbin_delete(obj->attribs, (FREE_FUNC) __irias_delete_attrib);
-
- obj->magic = ~IAS_OBJECT_MAGIC;
-
- kfree(obj);
-}
-
-/*
- * Function irias_delete_object (obj)
- *
- * Remove object from hashbin and deallocate all attributes associated with
- * with this object and the object itself
- *
- */
-int irias_delete_object(struct ias_object *obj)
-{
- struct ias_object *node;
-
- IRDA_ASSERT(obj != NULL, return -1;);
- IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;);
-
- /* Remove from list */
- node = hashbin_remove_this(irias_objects, (irda_queue_t *) obj);
- if (!node)
- pr_debug("%s(), object already removed!\n",
- __func__);
-
- /* Destroy */
- __irias_delete_object(obj);
-
- return 0;
-}
-EXPORT_SYMBOL(irias_delete_object);
-
-/*
- * Function irias_delete_attrib (obj)
- *
- * Remove attribute from hashbin and, if it was the last attribute of
- * the object, remove the object as well.
- *
- */
-int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib,
- int cleanobject)
-{
- struct ias_attrib *node;
-
- IRDA_ASSERT(obj != NULL, return -1;);
- IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;);
- IRDA_ASSERT(attrib != NULL, return -1;);
-
- /* Remove attribute from object */
- node = hashbin_remove_this(obj->attribs, (irda_queue_t *) attrib);
- if (!node)
- return 0; /* Already removed or non-existent */
-
- /* Deallocate attribute */
- __irias_delete_attrib(node);
-
- /* Check if object has still some attributes, destroy it if none.
- * At first glance, this look dangerous, as the kernel reference
- * various IAS objects. However, we only use this function on
- * user attributes, not kernel attributes, so there is no risk
- * of deleting a kernel object this way. Jean II */
- node = (struct ias_attrib *) hashbin_get_first(obj->attribs);
- if (cleanobject && !node)
- irias_delete_object(obj);
-
- return 0;
-}
-
-/*
- * Function irias_insert_object (obj)
- *
- * Insert an object into the LM-IAS database
- *
- */
-void irias_insert_object(struct ias_object *obj)
-{
- IRDA_ASSERT(obj != NULL, return;);
- IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
-
- hashbin_insert(irias_objects, (irda_queue_t *) obj, 0, obj->name);
-}
-EXPORT_SYMBOL(irias_insert_object);
-
-/*
- * Function irias_find_object (name)
- *
- * Find object with given name
- *
- */
-struct ias_object *irias_find_object(char *name)
-{
- IRDA_ASSERT(name != NULL, return NULL;);
-
- /* Unsafe (locking), object might change */
- return hashbin_lock_find(irias_objects, 0, name);
-}
-EXPORT_SYMBOL(irias_find_object);
-
-/*
- * Function irias_find_attrib (obj, name)
- *
- * Find named attribute in object
- *
- */
-struct ias_attrib *irias_find_attrib(struct ias_object *obj, char *name)
-{
- struct ias_attrib *attrib;
-
- IRDA_ASSERT(obj != NULL, return NULL;);
- IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return NULL;);
- IRDA_ASSERT(name != NULL, return NULL;);
-
- attrib = hashbin_lock_find(obj->attribs, 0, name);
- if (attrib == NULL)
- return NULL;
-
- /* Unsafe (locking), attrib might change */
- return attrib;
-}
-
-/*
- * Function irias_add_attribute (obj, attrib)
- *
- * Add attribute to object
- *
- */
-static void irias_add_attrib(struct ias_object *obj, struct ias_attrib *attrib,
- int owner)
-{
- IRDA_ASSERT(obj != NULL, return;);
- IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
-
- IRDA_ASSERT(attrib != NULL, return;);
- IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;);
-
- /* Set if attrib is owned by kernel or user space */
- attrib->value->owner = owner;
-
- hashbin_insert(obj->attribs, (irda_queue_t *) attrib, 0, attrib->name);
-}
-
-/*
- * Function irias_object_change_attribute (obj_name, attrib_name, new_value)
- *
- * Change the value of an objects attribute.
- *
- */
-int irias_object_change_attribute(char *obj_name, char *attrib_name,
- struct ias_value *new_value)
-{
- struct ias_object *obj;
- struct ias_attrib *attrib;
- unsigned long flags;
-
- /* Find object */
- obj = hashbin_lock_find(irias_objects, 0, obj_name);
- if (obj == NULL) {
- net_warn_ratelimited("%s: Unable to find object: %s\n",
- __func__, obj_name);
- return -1;
- }
-
- /* Slightly unsafe (obj might get removed under us) */
- spin_lock_irqsave(&obj->attribs->hb_spinlock, flags);
-
- /* Find attribute */
- attrib = hashbin_find(obj->attribs, 0, attrib_name);
- if (attrib == NULL) {
- net_warn_ratelimited("%s: Unable to find attribute: %s\n",
- __func__, attrib_name);
- spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags);
- return -1;
- }
-
- if ( attrib->value->type != new_value->type) {
- pr_debug("%s(), changing value type not allowed!\n",
- __func__);
- spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags);
- return -1;
- }
-
- /* Delete old value */
- irias_delete_value(attrib->value);
-
- /* Insert new value */
- attrib->value = new_value;
-
- /* Success */
- spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags);
- return 0;
-}
-EXPORT_SYMBOL(irias_object_change_attribute);
-
-/*
- * Function irias_object_add_integer_attrib (obj, name, value)
- *
- * Add an integer attribute to an LM-IAS object
- *
- */
-void irias_add_integer_attrib(struct ias_object *obj, char *name, int value,
- int owner)
-{
- struct ias_attrib *attrib;
-
- IRDA_ASSERT(obj != NULL, return;);
- IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
- IRDA_ASSERT(name != NULL, return;);
-
- attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC);
- if (attrib == NULL) {
- net_warn_ratelimited("%s: Unable to allocate attribute!\n",
- __func__);
- return;
- }
-
- attrib->magic = IAS_ATTRIB_MAGIC;
- attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
-
- /* Insert value */
- attrib->value = irias_new_integer_value(value);
- if (!attrib->name || !attrib->value) {
- net_warn_ratelimited("%s: Unable to allocate attribute!\n",
- __func__);
- if (attrib->value)
- irias_delete_value(attrib->value);
- kfree(attrib->name);
- kfree(attrib);
- return;
- }
-
- irias_add_attrib(obj, attrib, owner);
-}
-EXPORT_SYMBOL(irias_add_integer_attrib);
-
- /*
- * Function irias_add_octseq_attrib (obj, name, octet_seq, len)
- *
- * Add a octet sequence attribute to an LM-IAS object
- *
- */
-
-void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets,
- int len, int owner)
-{
- struct ias_attrib *attrib;
-
- IRDA_ASSERT(obj != NULL, return;);
- IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
-
- IRDA_ASSERT(name != NULL, return;);
- IRDA_ASSERT(octets != NULL, return;);
-
- attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC);
- if (attrib == NULL) {
- net_warn_ratelimited("%s: Unable to allocate attribute!\n",
- __func__);
- return;
- }
-
- attrib->magic = IAS_ATTRIB_MAGIC;
- attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
-
- attrib->value = irias_new_octseq_value( octets, len);
- if (!attrib->name || !attrib->value) {
- net_warn_ratelimited("%s: Unable to allocate attribute!\n",
- __func__);
- if (attrib->value)
- irias_delete_value(attrib->value);
- kfree(attrib->name);
- kfree(attrib);
- return;
- }
-
- irias_add_attrib(obj, attrib, owner);
-}
-EXPORT_SYMBOL(irias_add_octseq_attrib);
-
-/*
- * Function irias_object_add_string_attrib (obj, string)
- *
- * Add a string attribute to an LM-IAS object
- *
- */
-void irias_add_string_attrib(struct ias_object *obj, char *name, char *value,
- int owner)
-{
- struct ias_attrib *attrib;
-
- IRDA_ASSERT(obj != NULL, return;);
- IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
-
- IRDA_ASSERT(name != NULL, return;);
- IRDA_ASSERT(value != NULL, return;);
-
- attrib = kzalloc(sizeof( struct ias_attrib), GFP_ATOMIC);
- if (attrib == NULL) {
- net_warn_ratelimited("%s: Unable to allocate attribute!\n",
- __func__);
- return;
- }
-
- attrib->magic = IAS_ATTRIB_MAGIC;
- attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
-
- attrib->value = irias_new_string_value(value);
- if (!attrib->name || !attrib->value) {
- net_warn_ratelimited("%s: Unable to allocate attribute!\n",
- __func__);
- if (attrib->value)
- irias_delete_value(attrib->value);
- kfree(attrib->name);
- kfree(attrib);
- return;
- }
-
- irias_add_attrib(obj, attrib, owner);
-}
-EXPORT_SYMBOL(irias_add_string_attrib);
-
-/*
- * Function irias_new_integer_value (integer)
- *
- * Create new IAS integer value
- *
- */
-struct ias_value *irias_new_integer_value(int integer)
-{
- struct ias_value *value;
-
- value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
- if (value == NULL)
- return NULL;
-
- value->type = IAS_INTEGER;
- value->len = 4;
- value->t.integer = integer;
-
- return value;
-}
-EXPORT_SYMBOL(irias_new_integer_value);
-
-/*
- * Function irias_new_string_value (string)
- *
- * Create new IAS string value
- *
- * Per IrLMP 1.1, 4.3.3.2, strings are up to 256 chars - Jean II
- */
-struct ias_value *irias_new_string_value(char *string)
-{
- struct ias_value *value;
-
- value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
- if (value == NULL)
- return NULL;
-
- value->type = IAS_STRING;
- value->charset = CS_ASCII;
- value->t.string = kstrndup(string, IAS_MAX_STRING, GFP_ATOMIC);
- if (!value->t.string) {
- net_warn_ratelimited("%s: Unable to kmalloc!\n", __func__);
- kfree(value);
- return NULL;
- }
-
- value->len = strlen(value->t.string);
-
- return value;
-}
-
-/*
- * Function irias_new_octseq_value (octets, len)
- *
- * Create new IAS octet-sequence value
- *
- * Per IrLMP 1.1, 4.3.3.2, octet-sequence are up to 1024 bytes - Jean II
- */
-struct ias_value *irias_new_octseq_value(__u8 *octseq , int len)
-{
- struct ias_value *value;
-
- value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
- if (value == NULL)
- return NULL;
-
- value->type = IAS_OCT_SEQ;
- /* Check length */
- if(len > IAS_MAX_OCTET_STRING)
- len = IAS_MAX_OCTET_STRING;
- value->len = len;
-
- value->t.oct_seq = kmemdup(octseq, len, GFP_ATOMIC);
- if (value->t.oct_seq == NULL){
- net_warn_ratelimited("%s: Unable to kmalloc!\n", __func__);
- kfree(value);
- return NULL;
- }
- return value;
-}
-
-struct ias_value *irias_new_missing_value(void)
-{
- struct ias_value *value;
-
- value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
- if (value == NULL)
- return NULL;
-
- value->type = IAS_MISSING;
-
- return value;
-}
-
-/*
- * Function irias_delete_value (value)
- *
- * Delete IAS value
- *
- */
-void irias_delete_value(struct ias_value *value)
-{
- IRDA_ASSERT(value != NULL, return;);
-
- switch (value->type) {
- case IAS_INTEGER: /* Fallthrough */
- case IAS_MISSING:
- /* No need to deallocate */
- break;
- case IAS_STRING:
- /* Deallocate string */
- kfree(value->t.string);
- break;
- case IAS_OCT_SEQ:
- /* Deallocate byte stream */
- kfree(value->t.oct_seq);
- break;
- default:
- pr_debug("%s(), Unknown value type!\n", __func__);
- break;
- }
- kfree(value);
-}
-EXPORT_SYMBOL(irias_delete_value);
diff --git a/drivers/staging/irda/net/irlan/Kconfig b/drivers/staging/irda/net/irlan/Kconfig
deleted file mode 100644
index 951abc2e3a7f..000000000000
--- a/drivers/staging/irda/net/irlan/Kconfig
+++ /dev/null
@@ -1,14 +0,0 @@
-config IRLAN
- tristate "IrLAN protocol"
- depends on IRDA
- help
- Say Y here if you want to build support for the IrLAN protocol.
- To compile it as a module, choose M here: the module will be called
- irlan. IrLAN emulates an Ethernet and makes it possible to put up
- a wireless LAN using infrared beams.
-
- The IrLAN protocol can be used to talk with infrared access points
- like the HP NetbeamIR, or the ESI JetEye NET. You can also connect
- to another Linux machine running the IrLAN protocol for ad-hoc
- networking!
-
diff --git a/drivers/staging/irda/net/irlan/Makefile b/drivers/staging/irda/net/irlan/Makefile
deleted file mode 100644
index 94eefbc8e6b9..000000000000
--- a/drivers/staging/irda/net/irlan/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for the Linux IrDA IrLAN protocol layer.
-#
-
-obj-$(CONFIG_IRLAN) += irlan.o
-
-irlan-y := irlan_common.o irlan_eth.o irlan_event.o irlan_client.o irlan_provider.o irlan_filter.o irlan_provider_event.o irlan_client_event.o
diff --git a/drivers/staging/irda/net/irlan/irlan_client.c b/drivers/staging/irda/net/irlan/irlan_client.c
deleted file mode 100644
index 0b65e80849ae..000000000000
--- a/drivers/staging/irda/net/irlan/irlan_client.c
+++ /dev/null
@@ -1,559 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlan_client.c
- * Version: 0.9
- * Description: IrDA LAN Access Protocol (IrLAN) Client
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Tue Dec 14 15:47:02 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
- * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
- * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <linux/bitops.h>
-#include <net/arp.h>
-
-#include <asm/byteorder.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irttp.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/irias_object.h>
-#include <net/irda/iriap.h>
-#include <net/irda/timer.h>
-
-#include <net/irda/irlan_common.h>
-#include <net/irda/irlan_event.h>
-#include <net/irda/irlan_eth.h>
-#include <net/irda/irlan_provider.h>
-#include <net/irda/irlan_client.h>
-
-#undef CONFIG_IRLAN_GRATUITOUS_ARP
-
-static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap,
- LM_REASON reason,
- struct sk_buff *);
-static int irlan_client_ctrl_data_indication(void *instance, void *sap,
- struct sk_buff *skb);
-static void irlan_client_ctrl_connect_confirm(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *);
-static void irlan_check_response_param(struct irlan_cb *self, char *param,
- char *value, int val_len);
-static void irlan_client_open_ctrl_tsap(struct irlan_cb *self);
-
-static void irlan_client_kick_timer_expired(struct timer_list *t)
-{
- struct irlan_cb *self = from_timer(self, t, client.kick_timer);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- /*
- * If we are in peer mode, the client may not have got the discovery
- * indication it needs to make progress. If the client is still in
- * IDLE state, we must kick it to, but only if the provider is not IDLE
- */
- if ((self->provider.access_type == ACCESS_PEER) &&
- (self->client.state == IRLAN_IDLE) &&
- (self->provider.state != IRLAN_IDLE)) {
- irlan_client_wakeup(self, self->saddr, self->daddr);
- }
-}
-
-static void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout)
-{
- irda_start_timer(&self->client.kick_timer, timeout,
- irlan_client_kick_timer_expired);
-}
-
-/*
- * Function irlan_client_wakeup (self, saddr, daddr)
- *
- * Wake up client
- *
- */
-void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- /*
- * Check if we are already awake, or if we are a provider in direct
- * mode (in that case we must leave the client idle
- */
- if ((self->client.state != IRLAN_IDLE) ||
- (self->provider.access_type == ACCESS_DIRECT))
- {
- pr_debug("%s(), already awake!\n", __func__);
- return;
- }
-
- /* Addresses may have changed! */
- self->saddr = saddr;
- self->daddr = daddr;
-
- if (self->disconnect_reason == LM_USER_REQUEST) {
- pr_debug("%s(), still stopped by user\n", __func__);
- return;
- }
-
- /* Open TSAPs */
- irlan_client_open_ctrl_tsap(self);
- irlan_open_data_tsap(self);
-
- irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL);
-
- /* Start kick timer */
- irlan_client_start_kick_timer(self, 2*HZ);
-}
-
-/*
- * Function irlan_discovery_indication (daddr)
- *
- * Remote device with IrLAN server support discovered
- *
- */
-void irlan_client_discovery_indication(discinfo_t *discovery,
- DISCOVERY_MODE mode,
- void *priv)
-{
- struct irlan_cb *self;
- __u32 saddr, daddr;
-
- IRDA_ASSERT(discovery != NULL, return;);
-
- /*
- * I didn't check it, but I bet that IrLAN suffer from the same
- * deficiency as IrComm and doesn't handle two instances
- * simultaneously connecting to each other.
- * Same workaround, drop passive discoveries.
- * Jean II */
- if(mode == DISCOVERY_PASSIVE)
- return;
-
- saddr = discovery->saddr;
- daddr = discovery->daddr;
-
- /* Find instance */
- rcu_read_lock();
- self = irlan_get_any();
- if (self) {
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, goto out;);
-
- pr_debug("%s(), Found instance (%08x)!\n", __func__ ,
- daddr);
-
- irlan_client_wakeup(self, saddr, daddr);
- }
-IRDA_ASSERT_LABEL(out:)
- rcu_read_unlock();
-}
-
-/*
- * Function irlan_client_data_indication (handle, skb)
- *
- * This function gets the data that is received on the control channel
- *
- */
-static int irlan_client_ctrl_data_indication(void *instance, void *sap,
- struct sk_buff *skb)
-{
- struct irlan_cb *self;
-
- self = instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
- IRDA_ASSERT(skb != NULL, return -1;);
-
- irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb);
-
- /* Ready for a new command */
- pr_debug("%s(), clearing tx_busy\n", __func__);
- self->client.tx_busy = FALSE;
-
- /* Check if we have some queued commands waiting to be sent */
- irlan_run_ctrl_tx_queue(self);
-
- return 0;
-}
-
-static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap,
- LM_REASON reason,
- struct sk_buff *userdata)
-{
- struct irlan_cb *self;
- struct tsap_cb *tsap;
- struct sk_buff *skb;
-
- pr_debug("%s(), reason=%d\n", __func__ , reason);
-
- self = instance;
- tsap = sap;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
- IRDA_ASSERT(tsap != NULL, return;);
- IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
-
- IRDA_ASSERT(tsap == self->client.tsap_ctrl, return;);
-
- /* Remove frames queued on the control channel */
- while ((skb = skb_dequeue(&self->client.txq)) != NULL) {
- dev_kfree_skb(skb);
- }
- self->client.tx_busy = FALSE;
-
- irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
-}
-
-/*
- * Function irlan_client_open_tsaps (self)
- *
- * Initialize callbacks and open IrTTP TSAPs
- *
- */
-static void irlan_client_open_ctrl_tsap(struct irlan_cb *self)
-{
- struct tsap_cb *tsap;
- notify_t notify;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- /* Check if already open */
- if (self->client.tsap_ctrl)
- return;
-
- irda_notify_init(&notify);
-
- /* Set up callbacks */
- notify.data_indication = irlan_client_ctrl_data_indication;
- notify.connect_confirm = irlan_client_ctrl_connect_confirm;
- notify.disconnect_indication = irlan_client_ctrl_disconnect_indication;
- notify.instance = self;
- strlcpy(notify.name, "IrLAN ctrl (c)", sizeof(notify.name));
-
- tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, &notify);
- if (!tsap) {
- pr_debug("%s(), Got no tsap!\n", __func__);
- return;
- }
- self->client.tsap_ctrl = tsap;
-}
-
-/*
- * Function irlan_client_connect_confirm (handle, skb)
- *
- * Connection to peer IrLAN laye confirmed
- *
- */
-static void irlan_client_ctrl_connect_confirm(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *skb)
-{
- struct irlan_cb *self;
-
- self = instance;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- self->client.max_sdu_size = max_sdu_size;
- self->client.max_header_size = max_header_size;
-
- /* TODO: we could set the MTU depending on the max_sdu_size */
-
- irlan_do_client_event(self, IRLAN_CONNECT_COMPLETE, NULL);
-}
-
-/*
- * Function print_ret_code (code)
- *
- * Print return code of request to peer IrLAN layer.
- *
- */
-static void print_ret_code(__u8 code)
-{
- switch(code) {
- case 0:
- printk(KERN_INFO "Success\n");
- break;
- case 1:
- net_warn_ratelimited("IrLAN: Insufficient resources\n");
- break;
- case 2:
- net_warn_ratelimited("IrLAN: Invalid command format\n");
- break;
- case 3:
- net_warn_ratelimited("IrLAN: Command not supported\n");
- break;
- case 4:
- net_warn_ratelimited("IrLAN: Parameter not supported\n");
- break;
- case 5:
- net_warn_ratelimited("IrLAN: Value not supported\n");
- break;
- case 6:
- net_warn_ratelimited("IrLAN: Not open\n");
- break;
- case 7:
- net_warn_ratelimited("IrLAN: Authentication required\n");
- break;
- case 8:
- net_warn_ratelimited("IrLAN: Invalid password\n");
- break;
- case 9:
- net_warn_ratelimited("IrLAN: Protocol error\n");
- break;
- case 255:
- net_warn_ratelimited("IrLAN: Asynchronous status\n");
- break;
- }
-}
-
-/*
- * Function irlan_client_parse_response (self, skb)
- *
- * Extract all parameters from received buffer, then feed them to
- * check_params for parsing
- */
-void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb)
-{
- __u8 *frame;
- __u8 *ptr;
- int count;
- int ret;
- __u16 val_len;
- int i;
- char *name;
- char *value;
-
- IRDA_ASSERT(skb != NULL, return;);
-
- pr_debug("%s() skb->len=%d\n", __func__ , (int)skb->len);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- if (!skb) {
- net_err_ratelimited("%s(), Got NULL skb!\n", __func__);
- return;
- }
- frame = skb->data;
-
- /*
- * Check return code and print it if not success
- */
- if (frame[0]) {
- print_ret_code(frame[0]);
- return;
- }
-
- name = kmalloc(255, GFP_ATOMIC);
- if (!name)
- return;
- value = kmalloc(1016, GFP_ATOMIC);
- if (!value) {
- kfree(name);
- return;
- }
-
- /* How many parameters? */
- count = frame[1];
-
- pr_debug("%s(), got %d parameters\n", __func__ , count);
-
- ptr = frame+2;
-
- /* For all parameters */
- for (i=0; i<count;i++) {
- ret = irlan_extract_param(ptr, name, value, &val_len);
- if (ret < 0) {
- pr_debug("%s(), IrLAN, Error!\n", __func__);
- break;
- }
- ptr += ret;
- irlan_check_response_param(self, name, value, val_len);
- }
- /* Cleanup */
- kfree(name);
- kfree(value);
-}
-
-/*
- * Function irlan_check_response_param (self, param, value, val_len)
- *
- * Check which parameter is received and update local variables
- *
- */
-static void irlan_check_response_param(struct irlan_cb *self, char *param,
- char *value, int val_len)
-{
- __u16 tmp_cpu; /* Temporary value in host order */
- __u8 *bytes;
- int i;
-
- pr_debug("%s(), parm=%s\n", __func__ , param);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- /* Media type */
- if (strcmp(param, "MEDIA") == 0) {
- if (strcmp(value, "802.3") == 0)
- self->media = MEDIA_802_3;
- else
- self->media = MEDIA_802_5;
- return;
- }
- if (strcmp(param, "FILTER_TYPE") == 0) {
- if (strcmp(value, "DIRECTED") == 0)
- self->client.filter_type |= IRLAN_DIRECTED;
- else if (strcmp(value, "FUNCTIONAL") == 0)
- self->client.filter_type |= IRLAN_FUNCTIONAL;
- else if (strcmp(value, "GROUP") == 0)
- self->client.filter_type |= IRLAN_GROUP;
- else if (strcmp(value, "MAC_FRAME") == 0)
- self->client.filter_type |= IRLAN_MAC_FRAME;
- else if (strcmp(value, "MULTICAST") == 0)
- self->client.filter_type |= IRLAN_MULTICAST;
- else if (strcmp(value, "BROADCAST") == 0)
- self->client.filter_type |= IRLAN_BROADCAST;
- else if (strcmp(value, "IPX_SOCKET") == 0)
- self->client.filter_type |= IRLAN_IPX_SOCKET;
-
- }
- if (strcmp(param, "ACCESS_TYPE") == 0) {
- if (strcmp(value, "DIRECT") == 0)
- self->client.access_type = ACCESS_DIRECT;
- else if (strcmp(value, "PEER") == 0)
- self->client.access_type = ACCESS_PEER;
- else if (strcmp(value, "HOSTED") == 0)
- self->client.access_type = ACCESS_HOSTED;
- else {
- pr_debug("%s(), unknown access type!\n", __func__);
- }
- }
- /* IRLAN version */
- if (strcmp(param, "IRLAN_VER") == 0) {
- pr_debug("IrLAN version %d.%d\n", (__u8)value[0],
- (__u8)value[1]);
-
- self->version[0] = value[0];
- self->version[1] = value[1];
- return;
- }
- /* Which remote TSAP to use for data channel */
- if (strcmp(param, "DATA_CHAN") == 0) {
- self->dtsap_sel_data = value[0];
- pr_debug("Data TSAP = %02x\n", self->dtsap_sel_data);
- return;
- }
- if (strcmp(param, "CON_ARB") == 0) {
- memcpy(&tmp_cpu, value, 2); /* Align value */
- le16_to_cpus(&tmp_cpu); /* Convert to host order */
- self->client.recv_arb_val = tmp_cpu;
- pr_debug("%s(), receive arb val=%d\n", __func__ ,
- self->client.recv_arb_val);
- }
- if (strcmp(param, "MAX_FRAME") == 0) {
- memcpy(&tmp_cpu, value, 2); /* Align value */
- le16_to_cpus(&tmp_cpu); /* Convert to host order */
- self->client.max_frame = tmp_cpu;
- pr_debug("%s(), max frame=%d\n", __func__ ,
- self->client.max_frame);
- }
-
- /* RECONNECT_KEY, in case the link goes down! */
- if (strcmp(param, "RECONNECT_KEY") == 0) {
- pr_debug("Got reconnect key: ");
- /* for (i = 0; i < val_len; i++) */
-/* printk("%02x", value[i]); */
- memcpy(self->client.reconnect_key, value, val_len);
- self->client.key_len = val_len;
- pr_debug("\n");
- }
- /* FILTER_ENTRY, have we got an ethernet address? */
- if (strcmp(param, "FILTER_ENTRY") == 0) {
- bytes = value;
- pr_debug("Ethernet address = %pM\n", bytes);
- for (i = 0; i < 6; i++)
- self->dev->dev_addr[i] = bytes[i];
- }
-}
-
-/*
- * Function irlan_client_get_value_confirm (obj_id, value)
- *
- * Got results from remote LM-IAS
- *
- */
-void irlan_client_get_value_confirm(int result, __u16 obj_id,
- struct ias_value *value, void *priv)
-{
- struct irlan_cb *self;
-
- IRDA_ASSERT(priv != NULL, return;);
-
- self = priv;
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- /* We probably don't need to make any more queries */
- iriap_close(self->client.iriap);
- self->client.iriap = NULL;
-
- /* Check if request succeeded */
- if (result != IAS_SUCCESS) {
- pr_debug("%s(), got NULL value!\n", __func__);
- irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL,
- NULL);
- return;
- }
-
- switch (value->type) {
- case IAS_INTEGER:
- self->dtsap_sel_ctrl = value->t.integer;
-
- if (value->t.integer != -1) {
- irlan_do_client_event(self, IRLAN_IAS_PROVIDER_AVAIL,
- NULL);
- return;
- }
- irias_delete_value(value);
- break;
- default:
- pr_debug("%s(), unknown type!\n", __func__);
- break;
- }
- irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL);
-}
diff --git a/drivers/staging/irda/net/irlan/irlan_client_event.c b/drivers/staging/irda/net/irlan/irlan_client_event.c
deleted file mode 100644
index cc93fabbbb19..000000000000
--- a/drivers/staging/irda/net/irlan/irlan_client_event.c
+++ /dev/null
@@ -1,511 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlan_client_event.c
- * Version: 0.9
- * Description: IrLAN client state machine
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Sun Dec 26 21:52:24 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/skbuff.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/timer.h>
-#include <net/irda/irmod.h>
-#include <net/irda/iriap.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/irttp.h>
-
-#include <net/irda/irlan_common.h>
-#include <net/irda/irlan_client.h>
-#include <net/irda/irlan_event.h>
-
-static int irlan_client_state_idle (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-static int irlan_client_state_conn (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-static int irlan_client_state_info (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-static int irlan_client_state_open (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-static int irlan_client_state_wait (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-static int irlan_client_state_arb (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-static int irlan_client_state_data (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-static int irlan_client_state_sync (struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-
-static int (*state[])(struct irlan_cb *, IRLAN_EVENT event, struct sk_buff *) =
-{
- irlan_client_state_idle,
- irlan_client_state_query,
- irlan_client_state_conn,
- irlan_client_state_info,
- irlan_client_state_media,
- irlan_client_state_open,
- irlan_client_state_wait,
- irlan_client_state_arb,
- irlan_client_state_data,
- irlan_client_state_close,
- irlan_client_state_sync
-};
-
-void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- (*state[ self->client.state]) (self, event, skb);
-}
-
-/*
- * Function irlan_client_state_idle (event, skb, info)
- *
- * IDLE, We are waiting for an indication that there is a provider
- * available.
- */
-static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
-
- switch (event) {
- case IRLAN_DISCOVERY_INDICATION:
- if (self->client.iriap) {
- net_warn_ratelimited("%s(), busy with a previous query\n",
- __func__);
- return -EBUSY;
- }
-
- self->client.iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
- irlan_client_get_value_confirm);
- /* Get some values from peer IAS */
- irlan_next_client_state(self, IRLAN_QUERY);
- iriap_getvaluebyclass_request(self->client.iriap,
- self->saddr, self->daddr,
- "IrLAN", "IrDA:TinyTP:LsapSel");
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
- * Function irlan_client_state_query (event, skb, info)
- *
- * QUERY, We have queryed the remote IAS and is ready to connect
- * to provider, just waiting for the confirm.
- *
- */
-static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
-
- switch(event) {
- case IRLAN_IAS_PROVIDER_AVAIL:
- IRDA_ASSERT(self->dtsap_sel_ctrl != 0, return -1;);
-
- self->client.open_retries = 0;
-
- irttp_connect_request(self->client.tsap_ctrl,
- self->dtsap_sel_ctrl,
- self->saddr, self->daddr, NULL,
- IRLAN_MTU, NULL);
- irlan_next_client_state(self, IRLAN_CONN);
- break;
- case IRLAN_IAS_PROVIDER_NOT_AVAIL:
- pr_debug("%s(), IAS_PROVIDER_NOT_AVAIL\n", __func__);
- irlan_next_client_state(self, IRLAN_IDLE);
-
- /* Give the client a kick! */
- if ((self->provider.access_type == ACCESS_PEER) &&
- (self->provider.state != IRLAN_IDLE))
- irlan_client_wakeup(self, self->saddr, self->daddr);
- break;
- case IRLAN_LMP_DISCONNECT:
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
- * Function irlan_client_state_conn (event, skb, info)
- *
- * CONN, We have connected to a provider but has not issued any
- * commands yet.
- *
- */
-static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return -1;);
-
- switch (event) {
- case IRLAN_CONNECT_COMPLETE:
- /* Send getinfo cmd */
- irlan_get_provider_info(self);
- irlan_next_client_state(self, IRLAN_INFO);
- break;
- case IRLAN_LMP_DISCONNECT:
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
- * Function irlan_client_state_info (self, event, skb, info)
- *
- * INFO, We have issued a GetInfo command and is awaiting a reply.
- */
-static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return -1;);
-
- switch (event) {
- case IRLAN_DATA_INDICATION:
- IRDA_ASSERT(skb != NULL, return -1;);
-
- irlan_client_parse_response(self, skb);
-
- irlan_next_client_state(self, IRLAN_MEDIA);
-
- irlan_get_media_char(self);
- break;
-
- case IRLAN_LMP_DISCONNECT:
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
- * Function irlan_client_state_media (self, event, skb, info)
- *
- * MEDIA, The irlan_client has issued a GetMedia command and is awaiting a
- * reply.
- *
- */
-static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return -1;);
-
- switch(event) {
- case IRLAN_DATA_INDICATION:
- irlan_client_parse_response(self, skb);
- irlan_open_data_channel(self);
- irlan_next_client_state(self, IRLAN_OPEN);
- break;
- case IRLAN_LMP_DISCONNECT:
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
- * Function irlan_client_state_open (self, event, skb, info)
- *
- * OPEN, The irlan_client has issued a OpenData command and is awaiting a
- * reply
- *
- */
-static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- struct qos_info qos;
-
- IRDA_ASSERT(self != NULL, return -1;);
-
- switch(event) {
- case IRLAN_DATA_INDICATION:
- irlan_client_parse_response(self, skb);
-
- /*
- * Check if we have got the remote TSAP for data
- * communications
- */
- IRDA_ASSERT(self->dtsap_sel_data != 0, return -1;);
-
- /* Check which access type we are dealing with */
- switch (self->client.access_type) {
- case ACCESS_PEER:
- if (self->provider.state == IRLAN_OPEN) {
-
- irlan_next_client_state(self, IRLAN_ARB);
- irlan_do_client_event(self, IRLAN_CHECK_CON_ARB,
- NULL);
- } else {
-
- irlan_next_client_state(self, IRLAN_WAIT);
- }
- break;
- case ACCESS_DIRECT:
- case ACCESS_HOSTED:
- qos.link_disc_time.bits = 0x01; /* 3 secs */
-
- irttp_connect_request(self->tsap_data,
- self->dtsap_sel_data,
- self->saddr, self->daddr, &qos,
- IRLAN_MTU, NULL);
-
- irlan_next_client_state(self, IRLAN_DATA);
- break;
- default:
- pr_debug("%s(), unknown access type!\n", __func__);
- break;
- }
- break;
- case IRLAN_LMP_DISCONNECT:
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
-
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
- * Function irlan_client_state_wait (self, event, skb, info)
- *
- * WAIT, The irlan_client is waiting for the local provider to enter the
- * provider OPEN state.
- *
- */
-static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return -1;);
-
- switch(event) {
- case IRLAN_PROVIDER_SIGNAL:
- irlan_next_client_state(self, IRLAN_ARB);
- irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, NULL);
- break;
- case IRLAN_LMP_DISCONNECT:
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- struct qos_info qos;
-
- IRDA_ASSERT(self != NULL, return -1;);
-
- switch(event) {
- case IRLAN_CHECK_CON_ARB:
- if (self->client.recv_arb_val == self->provider.send_arb_val) {
- irlan_next_client_state(self, IRLAN_CLOSE);
- irlan_close_data_channel(self);
- } else if (self->client.recv_arb_val <
- self->provider.send_arb_val)
- {
- qos.link_disc_time.bits = 0x01; /* 3 secs */
-
- irlan_next_client_state(self, IRLAN_DATA);
- irttp_connect_request(self->tsap_data,
- self->dtsap_sel_data,
- self->saddr, self->daddr, &qos,
- IRLAN_MTU, NULL);
- } else if (self->client.recv_arb_val >
- self->provider.send_arb_val)
- {
- pr_debug("%s(), lost the battle :-(\n", __func__);
- }
- break;
- case IRLAN_DATA_CONNECT_INDICATION:
- irlan_next_client_state(self, IRLAN_DATA);
- break;
- case IRLAN_LMP_DISCONNECT:
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- case IRLAN_WATCHDOG_TIMEOUT:
- pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
- * Function irlan_client_state_data (self, event, skb, info)
- *
- * DATA, The data channel is connected, allowing data transfers between
- * the local and remote machines.
- *
- */
-static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
-
- switch(event) {
- case IRLAN_DATA_INDICATION:
- irlan_client_parse_response(self, skb);
- break;
- case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
- case IRLAN_LAP_DISCONNECT:
- irlan_next_client_state(self, IRLAN_IDLE);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
- * Function irlan_client_state_close (self, event, skb, info)
- *
- *
- *
- */
-static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
- * Function irlan_client_state_sync (self, event, skb, info)
- *
- *
- *
- */
-static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/drivers/staging/irda/net/irlan/irlan_common.c b/drivers/staging/irda/net/irlan/irlan_common.c
deleted file mode 100644
index fdcd7147007d..000000000000
--- a/drivers/staging/irda/net/irlan/irlan_common.c
+++ /dev/null
@@ -1,1176 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlan_common.c
- * Version: 0.9
- * Description: IrDA LAN Access Protocol Implementation
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Sun Dec 26 21:53:10 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>,
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/gfp.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-#include <linux/sched.h>
-#include <linux/seq_file.h>
-#include <linux/random.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/rtnetlink.h>
-#include <linux/moduleparam.h>
-#include <linux/bitops.h>
-
-#include <asm/byteorder.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irttp.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/iriap.h>
-#include <net/irda/timer.h>
-
-#include <net/irda/irlan_common.h>
-#include <net/irda/irlan_client.h>
-#include <net/irda/irlan_provider.h>
-#include <net/irda/irlan_eth.h>
-#include <net/irda/irlan_filter.h>
-
-
-/* extern char sysctl_devname[]; */
-
-/*
- * Master structure
- */
-static LIST_HEAD(irlans);
-
-static void *ckey;
-static void *skey;
-
-/* Module parameters */
-static bool eth; /* Use "eth" or "irlan" name for devices */
-static int access = ACCESS_PEER; /* PEER, DIRECT or HOSTED */
-
-#ifdef CONFIG_PROC_FS
-static const char *const irlan_access[] = {
- "UNKNOWN",
- "DIRECT",
- "PEER",
- "HOSTED"
-};
-
-static const char *const irlan_media[] = {
- "UNKNOWN",
- "802.3",
- "802.5"
-};
-
-extern struct proc_dir_entry *proc_irda;
-
-static int irlan_seq_open(struct inode *inode, struct file *file);
-
-static const struct file_operations irlan_fops = {
- .owner = THIS_MODULE,
- .open = irlan_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-extern struct proc_dir_entry *proc_irda;
-#endif /* CONFIG_PROC_FS */
-
-static struct irlan_cb __init *irlan_open(__u32 saddr, __u32 daddr);
-static void __irlan_close(struct irlan_cb *self);
-static int __irlan_insert_param(struct sk_buff *skb, char *param, int type,
- __u8 value_byte, __u16 value_short,
- __u8 *value_array, __u16 value_len);
-static void irlan_open_unicast_addr(struct irlan_cb *self);
-static void irlan_get_unicast_addr(struct irlan_cb *self);
-void irlan_close_tsaps(struct irlan_cb *self);
-
-/*
- * Function irlan_init (void)
- *
- * Initialize IrLAN layer
- *
- */
-static int __init irlan_init(void)
-{
- struct irlan_cb *new;
- __u16 hints;
-
-#ifdef CONFIG_PROC_FS
- { struct proc_dir_entry *proc;
- proc = proc_create("irlan", 0, proc_irda, &irlan_fops);
- if (!proc) {
- printk(KERN_ERR "irlan_init: can't create /proc entry!\n");
- return -ENODEV;
- }
- }
-#endif /* CONFIG_PROC_FS */
-
- hints = irlmp_service_to_hint(S_LAN);
-
- /* Register with IrLMP as a client */
- ckey = irlmp_register_client(hints, &irlan_client_discovery_indication,
- NULL, NULL);
- if (!ckey)
- goto err_ckey;
-
- /* Register with IrLMP as a service */
- skey = irlmp_register_service(hints);
- if (!skey)
- goto err_skey;
-
- /* Start the master IrLAN instance (the only one for now) */
- new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY);
- if (!new)
- goto err_open;
-
- /* The master will only open its (listen) control TSAP */
- irlan_provider_open_ctrl_tsap(new);
-
- /* Do some fast discovery! */
- irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
-
- return 0;
-
-err_open:
- irlmp_unregister_service(skey);
-err_skey:
- irlmp_unregister_client(ckey);
-err_ckey:
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("irlan", proc_irda);
-#endif /* CONFIG_PROC_FS */
-
- return -ENOMEM;
-}
-
-static void __exit irlan_cleanup(void)
-{
- struct irlan_cb *self, *next;
-
- irlmp_unregister_client(ckey);
- irlmp_unregister_service(skey);
-
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("irlan", proc_irda);
-#endif /* CONFIG_PROC_FS */
-
- /* Cleanup any leftover network devices */
- rtnl_lock();
- list_for_each_entry_safe(self, next, &irlans, dev_list) {
- __irlan_close(self);
- }
- rtnl_unlock();
-}
-
-/*
- * Function irlan_open (void)
- *
- * Open new instance of a client/provider, we should only register the
- * network device if this instance is ment for a particular client/provider
- */
-static struct irlan_cb __init *irlan_open(__u32 saddr, __u32 daddr)
-{
- struct net_device *dev;
- struct irlan_cb *self;
-
- /* Create network device with irlan */
- dev = alloc_irlandev(eth ? "eth%d" : "irlan%d");
- if (!dev)
- return NULL;
-
- self = netdev_priv(dev);
- self->dev = dev;
-
- /*
- * Initialize local device structure
- */
- self->magic = IRLAN_MAGIC;
- self->saddr = saddr;
- self->daddr = daddr;
-
- /* Provider access can only be PEER, DIRECT, or HOSTED */
- self->provider.access_type = access;
- if (access == ACCESS_DIRECT) {
- /*
- * Since we are emulating an IrLAN sever we will have to
- * give ourself an ethernet address!
- */
- dev->dev_addr[0] = 0x40;
- dev->dev_addr[1] = 0x00;
- dev->dev_addr[2] = 0x00;
- dev->dev_addr[3] = 0x00;
- get_random_bytes(dev->dev_addr+4, 1);
- get_random_bytes(dev->dev_addr+5, 1);
- }
-
- self->media = MEDIA_802_3;
- self->disconnect_reason = LM_USER_REQUEST;
- timer_setup(&self->watchdog_timer, NULL, 0);
- timer_setup(&self->client.kick_timer, NULL, 0);
- init_waitqueue_head(&self->open_wait);
-
- skb_queue_head_init(&self->client.txq);
-
- irlan_next_client_state(self, IRLAN_IDLE);
- irlan_next_provider_state(self, IRLAN_IDLE);
-
- if (register_netdev(dev)) {
- pr_debug("%s(), register_netdev() failed!\n",
- __func__);
- self = NULL;
- free_netdev(dev);
- } else {
- rtnl_lock();
- list_add_rcu(&self->dev_list, &irlans);
- rtnl_unlock();
- }
-
- return self;
-}
-/*
- * Function __irlan_close (self)
- *
- * This function closes and deallocates the IrLAN client instances. Be
- * aware that other functions which calls client_close() must
- * remove self from irlans list first.
- */
-static void __irlan_close(struct irlan_cb *self)
-{
- ASSERT_RTNL();
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- del_timer_sync(&self->watchdog_timer);
- del_timer_sync(&self->client.kick_timer);
-
- /* Close all open connections and remove TSAPs */
- irlan_close_tsaps(self);
-
- if (self->client.iriap)
- iriap_close(self->client.iriap);
-
- /* Remove frames queued on the control channel */
- skb_queue_purge(&self->client.txq);
-
- /* Unregister and free self via destructor */
- unregister_netdevice(self->dev);
-}
-
-/* Find any instance of irlan, used for client discovery wakeup */
-struct irlan_cb *irlan_get_any(void)
-{
- struct irlan_cb *self;
-
- list_for_each_entry_rcu(self, &irlans, dev_list) {
- return self;
- }
- return NULL;
-}
-
-/*
- * Function irlan_connect_indication (instance, sap, qos, max_sdu_size, skb)
- *
- * Here we receive the connect indication for the data channel
- *
- */
-static void irlan_connect_indication(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *skb)
-{
- struct irlan_cb *self;
- struct tsap_cb *tsap;
-
- self = instance;
- tsap = sap;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
- IRDA_ASSERT(tsap == self->tsap_data,return;);
-
- self->max_sdu_size = max_sdu_size;
- self->max_header_size = max_header_size;
-
- pr_debug("%s: We are now connected!\n", __func__);
-
- del_timer(&self->watchdog_timer);
-
- /* If you want to pass the skb to *both* state machines, you will
- * need to skb_clone() it, so that you don't free it twice.
- * As the state machines don't need it, git rid of it here...
- * Jean II */
- if (skb)
- dev_kfree_skb(skb);
-
- irlan_do_provider_event(self, IRLAN_DATA_CONNECT_INDICATION, NULL);
- irlan_do_client_event(self, IRLAN_DATA_CONNECT_INDICATION, NULL);
-
- if (self->provider.access_type == ACCESS_PEER) {
- /*
- * Data channel is open, so we are now allowed to
- * configure the remote filter
- */
- irlan_get_unicast_addr(self);
- irlan_open_unicast_addr(self);
- }
- /* Ready to transfer Ethernet frames (at last) */
- netif_start_queue(self->dev); /* Clear reason */
-}
-
-static void irlan_connect_confirm(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *skb)
-{
- struct irlan_cb *self;
-
- self = instance;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- self->max_sdu_size = max_sdu_size;
- self->max_header_size = max_header_size;
-
- /* TODO: we could set the MTU depending on the max_sdu_size */
-
- pr_debug("%s: We are now connected!\n", __func__);
- del_timer(&self->watchdog_timer);
-
- /*
- * Data channel is open, so we are now allowed to configure the remote
- * filter
- */
- irlan_get_unicast_addr(self);
- irlan_open_unicast_addr(self);
-
- /* Open broadcast and multicast filter by default */
- irlan_set_broadcast_filter(self, TRUE);
- irlan_set_multicast_filter(self, TRUE);
-
- /* Ready to transfer Ethernet frames */
- netif_start_queue(self->dev);
- self->disconnect_reason = 0; /* Clear reason */
- wake_up_interruptible(&self->open_wait);
-}
-
-/*
- * Function irlan_client_disconnect_indication (handle)
- *
- * Callback function for the IrTTP layer. Indicates a disconnection of
- * the specified connection (handle)
- */
-static void irlan_disconnect_indication(void *instance,
- void *sap, LM_REASON reason,
- struct sk_buff *userdata)
-{
- struct irlan_cb *self;
- struct tsap_cb *tsap;
-
- pr_debug("%s(), reason=%d\n", __func__ , reason);
-
- self = instance;
- tsap = sap;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
- IRDA_ASSERT(tsap != NULL, return;);
- IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
-
- IRDA_ASSERT(tsap == self->tsap_data, return;);
-
- pr_debug("IrLAN, data channel disconnected by peer!\n");
-
- /* Save reason so we know if we should try to reconnect or not */
- self->disconnect_reason = reason;
-
- switch (reason) {
- case LM_USER_REQUEST: /* User request */
- pr_debug("%s(), User requested\n", __func__);
- break;
- case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */
- pr_debug("%s(), Unexpected IrLAP disconnect\n", __func__);
- break;
- case LM_CONNECT_FAILURE: /* Failed to establish IrLAP connection */
- pr_debug("%s(), IrLAP connect failed\n", __func__);
- break;
- case LM_LAP_RESET: /* IrLAP reset */
- pr_debug("%s(), IrLAP reset\n", __func__);
- break;
- case LM_INIT_DISCONNECT:
- pr_debug("%s(), IrLMP connect failed\n", __func__);
- break;
- default:
- net_err_ratelimited("%s(), Unknown disconnect reason\n",
- __func__);
- break;
- }
-
- /* If you want to pass the skb to *both* state machines, you will
- * need to skb_clone() it, so that you don't free it twice.
- * As the state machines don't need it, git rid of it here...
- * Jean II */
- if (userdata)
- dev_kfree_skb(userdata);
-
- irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
- irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
-
- wake_up_interruptible(&self->open_wait);
-}
-
-void irlan_open_data_tsap(struct irlan_cb *self)
-{
- struct tsap_cb *tsap;
- notify_t notify;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- /* Check if already open */
- if (self->tsap_data)
- return;
-
- irda_notify_init(&notify);
-
- notify.data_indication = irlan_eth_receive;
- notify.udata_indication = irlan_eth_receive;
- notify.connect_indication = irlan_connect_indication;
- notify.connect_confirm = irlan_connect_confirm;
- notify.flow_indication = irlan_eth_flow_indication;
- notify.disconnect_indication = irlan_disconnect_indication;
- notify.instance = self;
- strlcpy(notify.name, "IrLAN data", sizeof(notify.name));
-
- tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, &notify);
- if (!tsap) {
- pr_debug("%s(), Got no tsap!\n", __func__);
- return;
- }
- self->tsap_data = tsap;
-
- /*
- * This is the data TSAP selector which we will pass to the client
- * when the client ask for it.
- */
- self->stsap_sel_data = self->tsap_data->stsap_sel;
-}
-
-void irlan_close_tsaps(struct irlan_cb *self)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- /* Disconnect and close all open TSAP connections */
- if (self->tsap_data) {
- irttp_disconnect_request(self->tsap_data, NULL, P_NORMAL);
- irttp_close_tsap(self->tsap_data);
- self->tsap_data = NULL;
- }
- if (self->client.tsap_ctrl) {
- irttp_disconnect_request(self->client.tsap_ctrl, NULL,
- P_NORMAL);
- irttp_close_tsap(self->client.tsap_ctrl);
- self->client.tsap_ctrl = NULL;
- }
- if (self->provider.tsap_ctrl) {
- irttp_disconnect_request(self->provider.tsap_ctrl, NULL,
- P_NORMAL);
- irttp_close_tsap(self->provider.tsap_ctrl);
- self->provider.tsap_ctrl = NULL;
- }
- self->disconnect_reason = LM_USER_REQUEST;
-}
-
-/*
- * Function irlan_ias_register (self, tsap_sel)
- *
- * Register with LM-IAS
- *
- */
-void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel)
-{
- struct ias_object *obj;
- struct ias_value *new_value;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- /*
- * Check if object has already been registered by a previous provider.
- * If that is the case, we just change the value of the attribute
- */
- if (!irias_find_object("IrLAN")) {
- obj = irias_new_object("IrLAN", IAS_IRLAN_ID);
- irias_add_integer_attrib(obj, "IrDA:TinyTP:LsapSel", tsap_sel,
- IAS_KERNEL_ATTR);
- irias_insert_object(obj);
- } else {
- new_value = irias_new_integer_value(tsap_sel);
- irias_object_change_attribute("IrLAN", "IrDA:TinyTP:LsapSel",
- new_value);
- }
-
- /* Register PnP object only if not registered before */
- if (!irias_find_object("PnP")) {
- obj = irias_new_object("PnP", IAS_PNP_ID);
-#if 0
- irias_add_string_attrib(obj, "Name", sysctl_devname,
- IAS_KERNEL_ATTR);
-#else
- irias_add_string_attrib(obj, "Name", "Linux", IAS_KERNEL_ATTR);
-#endif
- irias_add_string_attrib(obj, "DeviceID", "HWP19F0",
- IAS_KERNEL_ATTR);
- irias_add_integer_attrib(obj, "CompCnt", 1, IAS_KERNEL_ATTR);
- if (self->provider.access_type == ACCESS_PEER)
- irias_add_string_attrib(obj, "Comp#01", "PNP8389",
- IAS_KERNEL_ATTR);
- else
- irias_add_string_attrib(obj, "Comp#01", "PNP8294",
- IAS_KERNEL_ATTR);
-
- irias_add_string_attrib(obj, "Manufacturer",
- "Linux-IrDA Project", IAS_KERNEL_ATTR);
- irias_insert_object(obj);
- }
-}
-
-/*
- * Function irlan_run_ctrl_tx_queue (self)
- *
- * Try to send the next command in the control transmit queue
- *
- */
-int irlan_run_ctrl_tx_queue(struct irlan_cb *self)
-{
- struct sk_buff *skb;
-
- if (irda_lock(&self->client.tx_busy) == FALSE)
- return -EBUSY;
-
- skb = skb_dequeue(&self->client.txq);
- if (!skb) {
- self->client.tx_busy = FALSE;
- return 0;
- }
-
- /* Check that it's really possible to send commands */
- if ((self->client.tsap_ctrl == NULL) ||
- (self->client.state == IRLAN_IDLE))
- {
- self->client.tx_busy = FALSE;
- dev_kfree_skb(skb);
- return -1;
- }
- pr_debug("%s(), sending ...\n", __func__);
-
- return irttp_data_request(self->client.tsap_ctrl, skb);
-}
-
-/*
- * Function irlan_ctrl_data_request (self, skb)
- *
- * This function makes sure that commands on the control channel is being
- * sent in a command/response fashion
- */
-static void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb)
-{
- /* Queue command */
- skb_queue_tail(&self->client.txq, skb);
-
- /* Try to send command */
- irlan_run_ctrl_tx_queue(self);
-}
-
-/*
- * Function irlan_get_provider_info (self)
- *
- * Send Get Provider Information command to peer IrLAN layer
- *
- */
-void irlan_get_provider_info(struct irlan_cb *self)
-{
- struct sk_buff *skb;
- __u8 *frame;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER,
- GFP_ATOMIC);
- if (!skb)
- return;
-
- /* Reserve space for TTP, LMP, and LAP header */
- skb_reserve(skb, self->client.max_header_size);
- skb_put(skb, 2);
-
- frame = skb->data;
-
- frame[0] = CMD_GET_PROVIDER_INFO;
- frame[1] = 0x00; /* Zero parameters */
-
- irlan_ctrl_data_request(self, skb);
-}
-
-/*
- * Function irlan_open_data_channel (self)
- *
- * Send an Open Data Command to provider
- *
- */
-void irlan_open_data_channel(struct irlan_cb *self)
-{
- struct sk_buff *skb;
- __u8 *frame;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
- IRLAN_STRING_PARAMETER_LEN("MEDIA", "802.3") +
- IRLAN_STRING_PARAMETER_LEN("ACCESS_TYPE", "DIRECT"),
- GFP_ATOMIC);
- if (!skb)
- return;
-
- skb_reserve(skb, self->client.max_header_size);
- skb_put(skb, 2);
-
- frame = skb->data;
-
- /* Build frame */
- frame[0] = CMD_OPEN_DATA_CHANNEL;
- frame[1] = 0x02; /* Two parameters */
-
- irlan_insert_string_param(skb, "MEDIA", "802.3");
- irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT");
- /* irlan_insert_string_param(skb, "MODE", "UNRELIABLE"); */
-
-/* self->use_udata = TRUE; */
-
- irlan_ctrl_data_request(self, skb);
-}
-
-void irlan_close_data_channel(struct irlan_cb *self)
-{
- struct sk_buff *skb;
- __u8 *frame;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- /* Check if the TSAP is still there */
- if (self->client.tsap_ctrl == NULL)
- return;
-
- skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
- IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN"),
- GFP_ATOMIC);
- if (!skb)
- return;
-
- skb_reserve(skb, self->client.max_header_size);
- skb_put(skb, 2);
-
- frame = skb->data;
-
- /* Build frame */
- frame[0] = CMD_CLOSE_DATA_CHAN;
- frame[1] = 0x01; /* One parameter */
-
- irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
-
- irlan_ctrl_data_request(self, skb);
-}
-
-/*
- * Function irlan_open_unicast_addr (self)
- *
- * Make IrLAN provider accept ethernet frames addressed to the unicast
- * address.
- *
- */
-static void irlan_open_unicast_addr(struct irlan_cb *self)
-{
- struct sk_buff *skb;
- __u8 *frame;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
- IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
- IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") +
- IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "FILTER"),
- GFP_ATOMIC);
- if (!skb)
- return;
-
- /* Reserve space for TTP, LMP, and LAP header */
- skb_reserve(skb, self->max_header_size);
- skb_put(skb, 2);
-
- frame = skb->data;
-
- frame[0] = CMD_FILTER_OPERATION;
- frame[1] = 0x03; /* Three parameters */
- irlan_insert_byte_param(skb, "DATA_CHAN" , self->dtsap_sel_data);
- irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
- irlan_insert_string_param(skb, "FILTER_MODE", "FILTER");
-
- irlan_ctrl_data_request(self, skb);
-}
-
-/*
- * Function irlan_set_broadcast_filter (self, status)
- *
- * Make IrLAN provider accept ethernet frames addressed to the broadcast
- * address. Be careful with the use of this one, since there may be a lot
- * of broadcast traffic out there. We can still function without this
- * one but then _we_ have to initiate all communication with other
- * hosts, since ARP request for this host will not be answered.
- */
-void irlan_set_broadcast_filter(struct irlan_cb *self, int status)
-{
- struct sk_buff *skb;
- __u8 *frame;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
- IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
- IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "BROADCAST") +
- /* We may waste one byte here...*/
- IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "FILTER"),
- GFP_ATOMIC);
- if (!skb)
- return;
-
- /* Reserve space for TTP, LMP, and LAP header */
- skb_reserve(skb, self->client.max_header_size);
- skb_put(skb, 2);
-
- frame = skb->data;
-
- frame[0] = CMD_FILTER_OPERATION;
- frame[1] = 0x03; /* Three parameters */
- irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
- irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST");
- if (status)
- irlan_insert_string_param(skb, "FILTER_MODE", "FILTER");
- else
- irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
-
- irlan_ctrl_data_request(self, skb);
-}
-
-/*
- * Function irlan_set_multicast_filter (self, status)
- *
- * Make IrLAN provider accept ethernet frames addressed to the multicast
- * address.
- *
- */
-void irlan_set_multicast_filter(struct irlan_cb *self, int status)
-{
- struct sk_buff *skb;
- __u8 *frame;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
- IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
- IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "MULTICAST") +
- /* We may waste one byte here...*/
- IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "NONE"),
- GFP_ATOMIC);
- if (!skb)
- return;
-
- /* Reserve space for TTP, LMP, and LAP header */
- skb_reserve(skb, self->client.max_header_size);
- skb_put(skb, 2);
-
- frame = skb->data;
-
- frame[0] = CMD_FILTER_OPERATION;
- frame[1] = 0x03; /* Three parameters */
- irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
- irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST");
- if (status)
- irlan_insert_string_param(skb, "FILTER_MODE", "ALL");
- else
- irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
-
- irlan_ctrl_data_request(self, skb);
-}
-
-/*
- * Function irlan_get_unicast_addr (self)
- *
- * Retrieves the unicast address from the IrLAN provider. This address
- * will be inserted into the devices structure, so the ethernet layer
- * can construct its packets.
- *
- */
-static void irlan_get_unicast_addr(struct irlan_cb *self)
-{
- struct sk_buff *skb;
- __u8 *frame;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
- IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
- IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") +
- IRLAN_STRING_PARAMETER_LEN("FILTER_OPERATION",
- "DYNAMIC"),
- GFP_ATOMIC);
- if (!skb)
- return;
-
- /* Reserve space for TTP, LMP, and LAP header */
- skb_reserve(skb, self->client.max_header_size);
- skb_put(skb, 2);
-
- frame = skb->data;
-
- frame[0] = CMD_FILTER_OPERATION;
- frame[1] = 0x03; /* Three parameters */
- irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
- irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
- irlan_insert_string_param(skb, "FILTER_OPERATION", "DYNAMIC");
-
- irlan_ctrl_data_request(self, skb);
-}
-
-/*
- * Function irlan_get_media_char (self)
- *
- *
- *
- */
-void irlan_get_media_char(struct irlan_cb *self)
-{
- struct sk_buff *skb;
- __u8 *frame;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
- IRLAN_STRING_PARAMETER_LEN("MEDIA", "802.3"),
- GFP_ATOMIC);
-
- if (!skb)
- return;
-
- /* Reserve space for TTP, LMP, and LAP header */
- skb_reserve(skb, self->client.max_header_size);
- skb_put(skb, 2);
-
- frame = skb->data;
-
- /* Build frame */
- frame[0] = CMD_GET_MEDIA_CHAR;
- frame[1] = 0x01; /* One parameter */
-
- irlan_insert_string_param(skb, "MEDIA", "802.3");
- irlan_ctrl_data_request(self, skb);
-}
-
-/*
- * Function insert_byte_param (skb, param, value)
- *
- * Insert byte parameter into frame
- *
- */
-int irlan_insert_byte_param(struct sk_buff *skb, char *param, __u8 value)
-{
- return __irlan_insert_param(skb, param, IRLAN_BYTE, value, 0, NULL, 0);
-}
-
-int irlan_insert_short_param(struct sk_buff *skb, char *param, __u16 value)
-{
- return __irlan_insert_param(skb, param, IRLAN_SHORT, 0, value, NULL, 0);
-}
-
-/*
- * Function insert_string (skb, param, value)
- *
- * Insert string parameter into frame
- *
- */
-int irlan_insert_string_param(struct sk_buff *skb, char *param, char *string)
-{
- int string_len = strlen(string);
-
- return __irlan_insert_param(skb, param, IRLAN_ARRAY, 0, 0, string,
- string_len);
-}
-
-/*
- * Function insert_array_param(skb, param, value, len_value)
- *
- * Insert array parameter into frame
- *
- */
-int irlan_insert_array_param(struct sk_buff *skb, char *name, __u8 *array,
- __u16 array_len)
-{
- return __irlan_insert_param(skb, name, IRLAN_ARRAY, 0, 0, array,
- array_len);
-}
-
-/*
- * Function insert_param (skb, param, value, byte)
- *
- * Insert parameter at end of buffer, structure of a parameter is:
- *
- * -----------------------------------------------------------------------
- * | Name Length[1] | Param Name[1..255] | Val Length[2] | Value[0..1016]|
- * -----------------------------------------------------------------------
- */
-static int __irlan_insert_param(struct sk_buff *skb, char *param, int type,
- __u8 value_byte, __u16 value_short,
- __u8 *value_array, __u16 value_len)
-{
- __u8 *frame;
- __u8 param_len;
- __le16 tmp_le; /* Temporary value in little endian format */
- int n=0;
-
- if (skb == NULL) {
- pr_debug("%s(), Got NULL skb\n", __func__);
- return 0;
- }
-
- param_len = strlen(param);
- switch (type) {
- case IRLAN_BYTE:
- value_len = 1;
- break;
- case IRLAN_SHORT:
- value_len = 2;
- break;
- case IRLAN_ARRAY:
- IRDA_ASSERT(value_array != NULL, return 0;);
- IRDA_ASSERT(value_len > 0, return 0;);
- break;
- default:
- pr_debug("%s(), Unknown parameter type!\n", __func__);
- return 0;
- }
-
- /* Insert at end of sk-buffer */
- frame = skb_tail_pointer(skb);
-
- /* Make space for data */
- if (skb_tailroom(skb) < (param_len+value_len+3)) {
- pr_debug("%s(), No more space at end of skb\n", __func__);
- return 0;
- }
- skb_put(skb, param_len+value_len+3);
-
- /* Insert parameter length */
- frame[n++] = param_len;
-
- /* Insert parameter */
- memcpy(frame+n, param, param_len); n += param_len;
-
- /* Insert value length (2 byte little endian format, LSB first) */
- tmp_le = cpu_to_le16(value_len);
- memcpy(frame+n, &tmp_le, 2); n += 2; /* To avoid alignment problems */
-
- /* Insert value */
- switch (type) {
- case IRLAN_BYTE:
- frame[n++] = value_byte;
- break;
- case IRLAN_SHORT:
- tmp_le = cpu_to_le16(value_short);
- memcpy(frame+n, &tmp_le, 2); n += 2;
- break;
- case IRLAN_ARRAY:
- memcpy(frame+n, value_array, value_len); n+=value_len;
- break;
- default:
- break;
- }
- IRDA_ASSERT(n == (param_len+value_len+3), return 0;);
-
- return param_len+value_len+3;
-}
-
-/*
- * Function irlan_extract_param (buf, name, value, len)
- *
- * Extracts a single parameter name/value pair from buffer and updates
- * the buffer pointer to point to the next name/value pair.
- */
-int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len)
-{
- __u8 name_len;
- __u16 val_len;
- int n=0;
-
- /* get length of parameter name (1 byte) */
- name_len = buf[n++];
-
- if (name_len > 254) {
- pr_debug("%s(), name_len > 254\n", __func__);
- return -RSP_INVALID_COMMAND_FORMAT;
- }
-
- /* get parameter name */
- memcpy(name, buf+n, name_len);
- name[name_len] = '\0';
- n+=name_len;
-
- /*
- * Get length of parameter value (2 bytes in little endian
- * format)
- */
- memcpy(&val_len, buf+n, 2); /* To avoid alignment problems */
- le16_to_cpus(&val_len); n+=2;
-
- if (val_len >= 1016) {
- pr_debug("%s(), parameter length to long\n", __func__);
- return -RSP_INVALID_COMMAND_FORMAT;
- }
- *len = val_len;
-
- /* get parameter value */
- memcpy(value, buf+n, val_len);
- value[val_len] = '\0';
- n+=val_len;
-
- pr_debug("Parameter: %s ", name);
- pr_debug("Value: %s\n", value);
-
- return n;
-}
-
-#ifdef CONFIG_PROC_FS
-
-/*
- * Start of reading /proc entries.
- * Return entry at pos,
- * or start_token to indicate print header line
- * or NULL if end of file
- */
-static void *irlan_seq_start(struct seq_file *seq, loff_t *pos)
-{
- rcu_read_lock();
- return seq_list_start_head(&irlans, *pos);
-}
-
-/* Return entry after v, and increment pos */
-static void *irlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- return seq_list_next(v, &irlans, pos);
-}
-
-/* End of reading /proc file */
-static void irlan_seq_stop(struct seq_file *seq, void *v)
-{
- rcu_read_unlock();
-}
-
-
-/*
- * Show one entry in /proc file.
- */
-static int irlan_seq_show(struct seq_file *seq, void *v)
-{
- if (v == &irlans)
- seq_puts(seq, "IrLAN instances:\n");
- else {
- struct irlan_cb *self = list_entry(v, struct irlan_cb, dev_list);
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
-
- seq_printf(seq,"ifname: %s,\n",
- self->dev->name);
- seq_printf(seq,"client state: %s, ",
- irlan_state[ self->client.state]);
- seq_printf(seq,"provider state: %s,\n",
- irlan_state[ self->provider.state]);
- seq_printf(seq,"saddr: %#08x, ",
- self->saddr);
- seq_printf(seq,"daddr: %#08x\n",
- self->daddr);
- seq_printf(seq,"version: %d.%d,\n",
- self->version[1], self->version[0]);
- seq_printf(seq,"access type: %s\n",
- irlan_access[self->client.access_type]);
- seq_printf(seq,"media: %s\n",
- irlan_media[self->media]);
-
- seq_printf(seq,"local filter:\n");
- seq_printf(seq,"remote filter: ");
- irlan_print_filter(seq, self->client.filter_type);
- seq_printf(seq,"tx busy: %s\n",
- netif_queue_stopped(self->dev) ? "TRUE" : "FALSE");
-
- seq_putc(seq,'\n');
- }
- return 0;
-}
-
-static const struct seq_operations irlan_seq_ops = {
- .start = irlan_seq_start,
- .next = irlan_seq_next,
- .stop = irlan_seq_stop,
- .show = irlan_seq_show,
-};
-
-static int irlan_seq_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &irlan_seq_ops);
-}
-#endif
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("The Linux IrDA LAN protocol");
-MODULE_LICENSE("GPL");
-
-module_param(eth, bool, 0);
-MODULE_PARM_DESC(eth, "Name devices ethX (0) or irlanX (1)");
-module_param(access, int, 0);
-MODULE_PARM_DESC(access, "Access type DIRECT=1, PEER=2, HOSTED=3");
-
-module_init(irlan_init);
-module_exit(irlan_cleanup);
-
diff --git a/drivers/staging/irda/net/irlan/irlan_eth.c b/drivers/staging/irda/net/irlan/irlan_eth.c
deleted file mode 100644
index 3be852808a9d..000000000000
--- a/drivers/staging/irda/net/irlan/irlan_eth.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlan_eth.c
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Thu Oct 15 08:37:58 1998
- * Modified at: Tue Mar 21 09:06:41 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
- * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
- * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- *
- * Copyright (c) 1998-2000 Dag Brattli, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/if_arp.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <net/arp.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irmod.h>
-#include <net/irda/irlan_common.h>
-#include <net/irda/irlan_client.h>
-#include <net/irda/irlan_event.h>
-#include <net/irda/irlan_eth.h>
-
-static int irlan_eth_open(struct net_device *dev);
-static int irlan_eth_close(struct net_device *dev);
-static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static void irlan_eth_set_multicast_list(struct net_device *dev);
-
-static const struct net_device_ops irlan_eth_netdev_ops = {
- .ndo_open = irlan_eth_open,
- .ndo_stop = irlan_eth_close,
- .ndo_start_xmit = irlan_eth_xmit,
- .ndo_set_rx_mode = irlan_eth_set_multicast_list,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/*
- * Function irlan_eth_setup (dev)
- *
- * The network device initialization function.
- *
- */
-static void irlan_eth_setup(struct net_device *dev)
-{
- ether_setup(dev);
-
- dev->netdev_ops = &irlan_eth_netdev_ops;
- dev->needs_free_netdev = true;
- dev->min_mtu = 0;
- dev->max_mtu = ETH_MAX_MTU;
-
- /*
- * Lets do all queueing in IrTTP instead of this device driver.
- * Queueing here as well can introduce some strange latency
- * problems, which we will avoid by setting the queue size to 0.
- */
- /*
- * The bugs in IrTTP and IrLAN that created this latency issue
- * have now been fixed, and we can propagate flow control properly
- * to the network layer. However, this requires a minimal queue of
- * packets for the device.
- * Without flow control, the Tx Queue is 14 (ttp) + 0 (dev) = 14
- * With flow control, the Tx Queue is 7 (ttp) + 4 (dev) = 11
- * See irlan_eth_flow_indication()...
- * Note : this number was randomly selected and would need to
- * be adjusted.
- * Jean II */
- dev->tx_queue_len = 4;
-}
-
-/*
- * Function alloc_irlandev
- *
- * Allocate network device and control block
- *
- */
-struct net_device *alloc_irlandev(const char *name)
-{
- return alloc_netdev(sizeof(struct irlan_cb), name, NET_NAME_UNKNOWN,
- irlan_eth_setup);
-}
-
-/*
- * Function irlan_eth_open (dev)
- *
- * Network device has been opened by user
- *
- */
-static int irlan_eth_open(struct net_device *dev)
-{
- struct irlan_cb *self = netdev_priv(dev);
-
- /* Ready to play! */
- netif_stop_queue(dev); /* Wait until data link is ready */
-
- /* We are now open, so time to do some work */
- self->disconnect_reason = 0;
- irlan_client_wakeup(self, self->saddr, self->daddr);
-
- /* Make sure we have a hardware address before we return,
- so DHCP clients gets happy */
- return wait_event_interruptible(self->open_wait,
- !self->tsap_data->connected);
-}
-
-/*
- * Function irlan_eth_close (dev)
- *
- * Stop the ether network device, his function will usually be called by
- * ifconfig down. We should now disconnect the link, We start the
- * close timer, so that the instance will be removed if we are unable
- * to discover the remote device after the disconnect.
- */
-static int irlan_eth_close(struct net_device *dev)
-{
- struct irlan_cb *self = netdev_priv(dev);
-
- /* Stop device */
- netif_stop_queue(dev);
-
- irlan_close_data_channel(self);
- irlan_close_tsaps(self);
-
- irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
- irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
-
- /* Remove frames queued on the control channel */
- skb_queue_purge(&self->client.txq);
-
- self->client.tx_busy = 0;
-
- return 0;
-}
-
-/*
- * Function irlan_eth_tx (skb)
- *
- * Transmits ethernet frames over IrDA link.
- *
- */
-static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct irlan_cb *self = netdev_priv(dev);
- int ret;
- unsigned int len;
-
- /* skb headroom large enough to contain all IrDA-headers? */
- if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) {
- struct sk_buff *new_skb =
- skb_realloc_headroom(skb, self->max_header_size);
-
- /* We have to free the original skb anyway */
- dev_kfree_skb(skb);
-
- /* Did the realloc succeed? */
- if (new_skb == NULL)
- return NETDEV_TX_OK;
-
- /* Use the new skb instead */
- skb = new_skb;
- }
-
- netif_trans_update(dev);
-
- len = skb->len;
- /* Now queue the packet in the transport layer */
- if (self->use_udata)
- ret = irttp_udata_request(self->tsap_data, skb);
- else
- ret = irttp_data_request(self->tsap_data, skb);
-
- if (ret < 0) {
- /*
- * IrTTPs tx queue is full, so we just have to
- * drop the frame! You might think that we should
- * just return -1 and don't deallocate the frame,
- * but that is dangerous since it's possible that
- * we have replaced the original skb with a new
- * one with larger headroom, and that would really
- * confuse do_dev_queue_xmit() in dev.c! I have
- * tried :-) DB
- */
- /* irttp_data_request already free the packet */
- dev->stats.tx_dropped++;
- } else {
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += len;
- }
-
- return NETDEV_TX_OK;
-}
-
-/*
- * Function irlan_eth_receive (handle, skb)
- *
- * This function gets the data that is received on the data channel
- *
- */
-int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb)
-{
- struct irlan_cb *self = instance;
- struct net_device *dev = self->dev;
-
- if (skb == NULL) {
- dev->stats.rx_dropped++;
- return 0;
- }
- if (skb->len < ETH_HLEN) {
- pr_debug("%s() : IrLAN frame too short (%d)\n",
- __func__, skb->len);
- dev->stats.rx_dropped++;
- dev_kfree_skb(skb);
- return 0;
- }
-
- /*
- * Adopt this frame! Important to set all these fields since they
- * might have been previously set by the low level IrDA network
- * device driver
- */
- skb->protocol = eth_type_trans(skb, dev); /* Remove eth header */
-
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
-
- netif_rx(skb); /* Eat it! */
-
- return 0;
-}
-
-/*
- * Function irlan_eth_flow (status)
- *
- * Do flow control between IP/Ethernet and IrLAN/IrTTP. This is done by
- * controlling the queue stop/start.
- *
- * The IrDA link layer has the advantage to have flow control, and
- * IrTTP now properly handles that. Flow controlling the higher layers
- * prevent us to drop Tx packets in here (up to 15% for a TCP socket,
- * more for UDP socket).
- * Also, this allow us to reduce the overall transmit queue, which means
- * less latency in case of mixed traffic.
- * Jean II
- */
-void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
-{
- struct irlan_cb *self;
- struct net_device *dev;
-
- self = instance;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- dev = self->dev;
-
- IRDA_ASSERT(dev != NULL, return;);
-
- pr_debug("%s() : flow %s ; running %d\n", __func__,
- flow == FLOW_STOP ? "FLOW_STOP" : "FLOW_START",
- netif_running(dev));
-
- switch (flow) {
- case FLOW_STOP:
- /* IrTTP is full, stop higher layers */
- netif_stop_queue(dev);
- break;
- case FLOW_START:
- default:
- /* Tell upper layers that its time to transmit frames again */
- /* Schedule network layer */
- netif_wake_queue(dev);
- break;
- }
-}
-
-/*
- * Function set_multicast_list (dev)
- *
- * Configure the filtering of the device
- *
- */
-#define HW_MAX_ADDRS 4 /* Must query to get it! */
-static void irlan_eth_set_multicast_list(struct net_device *dev)
-{
- struct irlan_cb *self = netdev_priv(dev);
-
- /* Check if data channel has been connected yet */
- if (self->client.state != IRLAN_DATA) {
- pr_debug("%s(), delaying!\n", __func__);
- return;
- }
-
- if (dev->flags & IFF_PROMISC) {
- /* Enable promiscuous mode */
- net_warn_ratelimited("Promiscuous mode not implemented by IrLAN!\n");
- } else if ((dev->flags & IFF_ALLMULTI) ||
- netdev_mc_count(dev) > HW_MAX_ADDRS) {
- /* Disable promiscuous mode, use normal mode. */
- pr_debug("%s(), Setting multicast filter\n", __func__);
- /* hardware_set_filter(NULL); */
-
- irlan_set_multicast_filter(self, TRUE);
- } else if (!netdev_mc_empty(dev)) {
- pr_debug("%s(), Setting multicast filter\n", __func__);
- /* Walk the address list, and load the filter */
- /* hardware_set_filter(dev->mc_list); */
-
- irlan_set_multicast_filter(self, TRUE);
- } else {
- pr_debug("%s(), Clearing multicast filter\n", __func__);
- irlan_set_multicast_filter(self, FALSE);
- }
-
- if (dev->flags & IFF_BROADCAST)
- irlan_set_broadcast_filter(self, TRUE);
- else
- irlan_set_broadcast_filter(self, FALSE);
-}
diff --git a/drivers/staging/irda/net/irlan/irlan_event.c b/drivers/staging/irda/net/irlan/irlan_event.c
deleted file mode 100644
index 9a1cc11c16f6..000000000000
--- a/drivers/staging/irda/net/irlan/irlan_event.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlan_event.c
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Tue Oct 20 09:10:16 1998
- * Modified at: Sat Oct 30 12:59:01 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <net/irda/irlan_event.h>
-
-const char * const irlan_state[] = {
- "IRLAN_IDLE",
- "IRLAN_QUERY",
- "IRLAN_CONN",
- "IRLAN_INFO",
- "IRLAN_MEDIA",
- "IRLAN_OPEN",
- "IRLAN_WAIT",
- "IRLAN_ARB",
- "IRLAN_DATA",
- "IRLAN_CLOSE",
- "IRLAN_SYNC",
-};
-
-void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state)
-{
- pr_debug("%s(), %s\n", __func__ , irlan_state[state]);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- self->client.state = state;
-}
-
-void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state)
-{
- pr_debug("%s(), %s\n", __func__ , irlan_state[state]);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- self->provider.state = state;
-}
-
diff --git a/drivers/staging/irda/net/irlan/irlan_filter.c b/drivers/staging/irda/net/irlan/irlan_filter.c
deleted file mode 100644
index e755e90b2f26..000000000000
--- a/drivers/staging/irda/net/irlan/irlan_filter.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlan_filter.c
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Fri Jan 29 11:16:38 1999
- * Modified at: Sat Oct 30 12:58:45 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/skbuff.h>
-#include <linux/random.h>
-#include <linux/seq_file.h>
-
-#include <net/irda/irlan_common.h>
-#include <net/irda/irlan_filter.h>
-
-/*
- * Function irlan_filter_request (self, skb)
- *
- * Handle filter request from client peer device
- *
- */
-void irlan_filter_request(struct irlan_cb *self, struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- if ((self->provider.filter_type == IRLAN_DIRECTED) &&
- (self->provider.filter_operation == DYNAMIC))
- {
- pr_debug("Giving peer a dynamic Ethernet address\n");
- self->provider.mac_address[0] = 0x40;
- self->provider.mac_address[1] = 0x00;
- self->provider.mac_address[2] = 0x00;
- self->provider.mac_address[3] = 0x00;
-
- /* Use arbitration value to generate MAC address */
- if (self->provider.access_type == ACCESS_PEER) {
- self->provider.mac_address[4] =
- self->provider.send_arb_val & 0xff;
- self->provider.mac_address[5] =
- (self->provider.send_arb_val >> 8) & 0xff;
- } else {
- /* Just generate something for now */
- get_random_bytes(self->provider.mac_address+4, 1);
- get_random_bytes(self->provider.mac_address+5, 1);
- }
-
- skb->data[0] = 0x00; /* Success */
- skb->data[1] = 0x03;
- irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
- irlan_insert_short_param(skb, "MAX_ENTRY", 0x0001);
- irlan_insert_array_param(skb, "FILTER_ENTRY",
- self->provider.mac_address, 6);
- return;
- }
-
- if ((self->provider.filter_type == IRLAN_DIRECTED) &&
- (self->provider.filter_mode == FILTER))
- {
- pr_debug("Directed filter on\n");
- skb->data[0] = 0x00; /* Success */
- skb->data[1] = 0x00;
- return;
- }
- if ((self->provider.filter_type == IRLAN_DIRECTED) &&
- (self->provider.filter_mode == NONE))
- {
- pr_debug("Directed filter off\n");
- skb->data[0] = 0x00; /* Success */
- skb->data[1] = 0x00;
- return;
- }
-
- if ((self->provider.filter_type == IRLAN_BROADCAST) &&
- (self->provider.filter_mode == FILTER))
- {
- pr_debug("Broadcast filter on\n");
- skb->data[0] = 0x00; /* Success */
- skb->data[1] = 0x00;
- return;
- }
- if ((self->provider.filter_type == IRLAN_BROADCAST) &&
- (self->provider.filter_mode == NONE))
- {
- pr_debug("Broadcast filter off\n");
- skb->data[0] = 0x00; /* Success */
- skb->data[1] = 0x00;
- return;
- }
- if ((self->provider.filter_type == IRLAN_MULTICAST) &&
- (self->provider.filter_mode == FILTER))
- {
- pr_debug("Multicast filter on\n");
- skb->data[0] = 0x00; /* Success */
- skb->data[1] = 0x00;
- return;
- }
- if ((self->provider.filter_type == IRLAN_MULTICAST) &&
- (self->provider.filter_mode == NONE))
- {
- pr_debug("Multicast filter off\n");
- skb->data[0] = 0x00; /* Success */
- skb->data[1] = 0x00;
- return;
- }
- if ((self->provider.filter_type == IRLAN_MULTICAST) &&
- (self->provider.filter_operation == GET))
- {
- pr_debug("Multicast filter get\n");
- skb->data[0] = 0x00; /* Success? */
- skb->data[1] = 0x02;
- irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
- irlan_insert_short_param(skb, "MAX_ENTRY", 16);
- return;
- }
- skb->data[0] = 0x00; /* Command not supported */
- skb->data[1] = 0x00;
-
- pr_debug("Not implemented!\n");
-}
-
-/*
- * Function check_request_param (self, param, value)
- *
- * Check parameters in request from peer device
- *
- */
-void irlan_check_command_param(struct irlan_cb *self, char *param, char *value)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- pr_debug("%s, %s\n", param, value);
-
- /*
- * This is experimental!! DB.
- */
- if (strcmp(param, "MODE") == 0) {
- self->use_udata = TRUE;
- return;
- }
-
- /*
- * FILTER_TYPE
- */
- if (strcmp(param, "FILTER_TYPE") == 0) {
- if (strcmp(value, "DIRECTED") == 0) {
- self->provider.filter_type = IRLAN_DIRECTED;
- return;
- }
- if (strcmp(value, "MULTICAST") == 0) {
- self->provider.filter_type = IRLAN_MULTICAST;
- return;
- }
- if (strcmp(value, "BROADCAST") == 0) {
- self->provider.filter_type = IRLAN_BROADCAST;
- return;
- }
- }
- /*
- * FILTER_MODE
- */
- if (strcmp(param, "FILTER_MODE") == 0) {
- if (strcmp(value, "ALL") == 0) {
- self->provider.filter_mode = ALL;
- return;
- }
- if (strcmp(value, "FILTER") == 0) {
- self->provider.filter_mode = FILTER;
- return;
- }
- if (strcmp(value, "NONE") == 0) {
- self->provider.filter_mode = FILTER;
- return;
- }
- }
- /*
- * FILTER_OPERATION
- */
- if (strcmp(param, "FILTER_OPERATION") == 0) {
- if (strcmp(value, "DYNAMIC") == 0) {
- self->provider.filter_operation = DYNAMIC;
- return;
- }
- if (strcmp(value, "GET") == 0) {
- self->provider.filter_operation = GET;
- return;
- }
- }
-}
-
-/*
- * Function irlan_print_filter (filter_type, buf)
- *
- * Print status of filter. Used by /proc file system
- *
- */
-#ifdef CONFIG_PROC_FS
-#define MASK2STR(m,s) { .mask = m, .str = s }
-
-void irlan_print_filter(struct seq_file *seq, int filter_type)
-{
- static struct {
- int mask;
- const char *str;
- } filter_mask2str[] = {
- MASK2STR(IRLAN_DIRECTED, "DIRECTED"),
- MASK2STR(IRLAN_FUNCTIONAL, "FUNCTIONAL"),
- MASK2STR(IRLAN_GROUP, "GROUP"),
- MASK2STR(IRLAN_MAC_FRAME, "MAC_FRAME"),
- MASK2STR(IRLAN_MULTICAST, "MULTICAST"),
- MASK2STR(IRLAN_BROADCAST, "BROADCAST"),
- MASK2STR(IRLAN_IPX_SOCKET, "IPX_SOCKET"),
- MASK2STR(0, NULL)
- }, *p;
-
- for (p = filter_mask2str; p->str; p++) {
- if (filter_type & p->mask)
- seq_printf(seq, "%s ", p->str);
- }
- seq_putc(seq, '\n');
-}
-#undef MASK2STR
-#endif
diff --git a/drivers/staging/irda/net/irlan/irlan_provider.c b/drivers/staging/irda/net/irlan/irlan_provider.c
deleted file mode 100644
index 15c292cf2644..000000000000
--- a/drivers/staging/irda/net/irlan/irlan_provider.c
+++ /dev/null
@@ -1,408 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlan_provider.c
- * Version: 0.9
- * Description: IrDA LAN Access Protocol Implementation
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Sat Oct 30 12:52:10 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
- * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
- * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/random.h>
-#include <linux/bitops.h>
-#include <linux/slab.h>
-
-#include <asm/byteorder.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irttp.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/irias_object.h>
-#include <net/irda/iriap.h>
-#include <net/irda/timer.h>
-
-#include <net/irda/irlan_common.h>
-#include <net/irda/irlan_eth.h>
-#include <net/irda/irlan_event.h>
-#include <net/irda/irlan_provider.h>
-#include <net/irda/irlan_filter.h>
-#include <net/irda/irlan_client.h>
-
-static void irlan_provider_connect_indication(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *skb);
-
-/*
- * Function irlan_provider_control_data_indication (handle, skb)
- *
- * This function gets the data that is received on the control channel
- *
- */
-static int irlan_provider_data_indication(void *instance, void *sap,
- struct sk_buff *skb)
-{
- struct irlan_cb *self;
- __u8 code;
-
- self = instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
-
- IRDA_ASSERT(skb != NULL, return -1;);
-
- code = skb->data[0];
- switch(code) {
- case CMD_GET_PROVIDER_INFO:
- pr_debug("Got GET_PROVIDER_INFO command!\n");
- irlan_do_provider_event(self, IRLAN_GET_INFO_CMD, skb);
- break;
-
- case CMD_GET_MEDIA_CHAR:
- pr_debug("Got GET_MEDIA_CHAR command!\n");
- irlan_do_provider_event(self, IRLAN_GET_MEDIA_CMD, skb);
- break;
- case CMD_OPEN_DATA_CHANNEL:
- pr_debug("Got OPEN_DATA_CHANNEL command!\n");
- irlan_do_provider_event(self, IRLAN_OPEN_DATA_CMD, skb);
- break;
- case CMD_FILTER_OPERATION:
- pr_debug("Got FILTER_OPERATION command!\n");
- irlan_do_provider_event(self, IRLAN_FILTER_CONFIG_CMD, skb);
- break;
- case CMD_RECONNECT_DATA_CHAN:
- pr_debug("%s(), Got RECONNECT_DATA_CHAN command\n", __func__);
- pr_debug("%s(), NOT IMPLEMENTED\n", __func__);
- break;
- case CMD_CLOSE_DATA_CHAN:
- pr_debug("Got CLOSE_DATA_CHAN command!\n");
- pr_debug("%s(), NOT IMPLEMENTED\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown command!\n", __func__);
- break;
- }
- return 0;
-}
-
-/*
- * Function irlan_provider_connect_indication (handle, skb, priv)
- *
- * Got connection from peer IrLAN client
- *
- */
-static void irlan_provider_connect_indication(void *instance, void *sap,
- struct qos_info *qos,
- __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *skb)
-{
- struct irlan_cb *self;
- struct tsap_cb *tsap;
-
- self = instance;
- tsap = sap;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- IRDA_ASSERT(tsap == self->provider.tsap_ctrl,return;);
- IRDA_ASSERT(self->provider.state == IRLAN_IDLE, return;);
-
- self->provider.max_sdu_size = max_sdu_size;
- self->provider.max_header_size = max_header_size;
-
- irlan_do_provider_event(self, IRLAN_CONNECT_INDICATION, NULL);
-
- /*
- * If we are in peer mode, the client may not have got the discovery
- * indication it needs to make progress. If the client is still in
- * IDLE state, we must kick it.
- */
- if ((self->provider.access_type == ACCESS_PEER) &&
- (self->client.state == IRLAN_IDLE))
- {
- irlan_client_wakeup(self, self->saddr, self->daddr);
- }
-}
-
-/*
- * Function irlan_provider_connect_response (handle)
- *
- * Accept incoming connection
- *
- */
-void irlan_provider_connect_response(struct irlan_cb *self,
- struct tsap_cb *tsap)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- /* Just accept */
- irttp_connect_response(tsap, IRLAN_MTU, NULL);
-}
-
-static void irlan_provider_disconnect_indication(void *instance, void *sap,
- LM_REASON reason,
- struct sk_buff *userdata)
-{
- struct irlan_cb *self;
- struct tsap_cb *tsap;
-
- pr_debug("%s(), reason=%d\n", __func__ , reason);
-
- self = instance;
- tsap = sap;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
- IRDA_ASSERT(tsap != NULL, return;);
- IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
-
- IRDA_ASSERT(tsap == self->provider.tsap_ctrl, return;);
-
- irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
-}
-
-/*
- * Function irlan_parse_open_data_cmd (self, skb)
- *
- *
- *
- */
-int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb)
-{
- int ret;
-
- ret = irlan_provider_parse_command(self, CMD_OPEN_DATA_CHANNEL, skb);
-
- /* Open data channel */
- irlan_open_data_tsap(self);
-
- return ret;
-}
-
-/*
- * Function parse_command (skb)
- *
- * Extract all parameters from received buffer, then feed them to
- * check_params for parsing
- *
- */
-int irlan_provider_parse_command(struct irlan_cb *self, int cmd,
- struct sk_buff *skb)
-{
- __u8 *frame;
- __u8 *ptr;
- int count;
- __u16 val_len;
- int i;
- char *name;
- char *value;
- int ret = RSP_SUCCESS;
-
- IRDA_ASSERT(skb != NULL, return -RSP_PROTOCOL_ERROR;);
-
- pr_debug("%s(), skb->len=%d\n", __func__ , (int)skb->len);
-
- IRDA_ASSERT(self != NULL, return -RSP_PROTOCOL_ERROR;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -RSP_PROTOCOL_ERROR;);
-
- if (!skb)
- return -RSP_PROTOCOL_ERROR;
-
- frame = skb->data;
-
- name = kmalloc(255, GFP_ATOMIC);
- if (!name)
- return -RSP_INSUFFICIENT_RESOURCES;
- value = kmalloc(1016, GFP_ATOMIC);
- if (!value) {
- kfree(name);
- return -RSP_INSUFFICIENT_RESOURCES;
- }
-
- /* How many parameters? */
- count = frame[1];
-
- pr_debug("Got %d parameters\n", count);
-
- ptr = frame+2;
-
- /* For all parameters */
- for (i=0; i<count;i++) {
- ret = irlan_extract_param(ptr, name, value, &val_len);
- if (ret < 0) {
- pr_debug("%s(), IrLAN, Error!\n", __func__);
- break;
- }
- ptr+=ret;
- ret = RSP_SUCCESS;
- irlan_check_command_param(self, name, value);
- }
- /* Cleanup */
- kfree(name);
- kfree(value);
-
- return ret;
-}
-
-/*
- * Function irlan_provider_send_reply (self, info)
- *
- * Send reply to query to peer IrLAN layer
- *
- */
-void irlan_provider_send_reply(struct irlan_cb *self, int command,
- int ret_code)
-{
- struct sk_buff *skb;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
- /* Bigger param length comes from CMD_GET_MEDIA_CHAR */
- IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") +
- IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "BROADCAST") +
- IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "MULTICAST") +
- IRLAN_STRING_PARAMETER_LEN("ACCESS_TYPE", "HOSTED"),
- GFP_ATOMIC);
-
- if (!skb)
- return;
-
- /* Reserve space for TTP, LMP, and LAP header */
- skb_reserve(skb, self->provider.max_header_size);
- skb_put(skb, 2);
-
- switch (command) {
- case CMD_GET_PROVIDER_INFO:
- skb->data[0] = 0x00; /* Success */
- skb->data[1] = 0x02; /* 2 parameters */
- switch (self->media) {
- case MEDIA_802_3:
- irlan_insert_string_param(skb, "MEDIA", "802.3");
- break;
- case MEDIA_802_5:
- irlan_insert_string_param(skb, "MEDIA", "802.5");
- break;
- default:
- pr_debug("%s(), unknown media type!\n", __func__);
- break;
- }
- irlan_insert_short_param(skb, "IRLAN_VER", 0x0101);
- break;
-
- case CMD_GET_MEDIA_CHAR:
- skb->data[0] = 0x00; /* Success */
- skb->data[1] = 0x05; /* 5 parameters */
- irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
- irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST");
- irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST");
-
- switch (self->provider.access_type) {
- case ACCESS_DIRECT:
- irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT");
- break;
- case ACCESS_PEER:
- irlan_insert_string_param(skb, "ACCESS_TYPE", "PEER");
- break;
- case ACCESS_HOSTED:
- irlan_insert_string_param(skb, "ACCESS_TYPE", "HOSTED");
- break;
- default:
- pr_debug("%s(), Unknown access type\n", __func__);
- break;
- }
- irlan_insert_short_param(skb, "MAX_FRAME", 0x05ee);
- break;
- case CMD_OPEN_DATA_CHANNEL:
- skb->data[0] = 0x00; /* Success */
- if (self->provider.send_arb_val) {
- skb->data[1] = 0x03; /* 3 parameters */
- irlan_insert_short_param(skb, "CON_ARB",
- self->provider.send_arb_val);
- } else
- skb->data[1] = 0x02; /* 2 parameters */
- irlan_insert_byte_param(skb, "DATA_CHAN", self->stsap_sel_data);
- irlan_insert_string_param(skb, "RECONNECT_KEY", "LINUX RULES!");
- break;
- case CMD_FILTER_OPERATION:
- irlan_filter_request(self, skb);
- break;
- default:
- pr_debug("%s(), Unknown command!\n", __func__);
- break;
- }
-
- irttp_data_request(self->provider.tsap_ctrl, skb);
-}
-
-/*
- * Function irlan_provider_register(void)
- *
- * Register provider support so we can accept incoming connections.
- *
- */
-int irlan_provider_open_ctrl_tsap(struct irlan_cb *self)
-{
- struct tsap_cb *tsap;
- notify_t notify;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
-
- /* Check if already open */
- if (self->provider.tsap_ctrl)
- return -1;
-
- /*
- * First register well known control TSAP
- */
- irda_notify_init(&notify);
- notify.data_indication = irlan_provider_data_indication;
- notify.connect_indication = irlan_provider_connect_indication;
- notify.disconnect_indication = irlan_provider_disconnect_indication;
- notify.instance = self;
- strlcpy(notify.name, "IrLAN ctrl (p)", sizeof(notify.name));
-
- tsap = irttp_open_tsap(LSAP_ANY, 1, &notify);
- if (!tsap) {
- pr_debug("%s(), Got no tsap!\n", __func__);
- return -1;
- }
- self->provider.tsap_ctrl = tsap;
-
- /* Register with LM-IAS */
- irlan_ias_register(self, tsap->stsap_sel);
-
- return 0;
-}
-
diff --git a/drivers/staging/irda/net/irlan/irlan_provider_event.c b/drivers/staging/irda/net/irlan/irlan_provider_event.c
deleted file mode 100644
index 9c4f7f51d6b5..000000000000
--- a/drivers/staging/irda/net/irlan/irlan_provider_event.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlan_provider_event.c
- * Version: 0.9
- * Description: IrLAN provider state machine)
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Sat Oct 30 12:52:41 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <net/irda/irda.h>
-#include <net/irda/iriap.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/irttp.h>
-
-#include <net/irda/irlan_provider.h>
-#include <net/irda/irlan_event.h>
-
-static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb);
-
-static int (*state[])(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb) =
-{
- irlan_provider_state_idle,
- NULL, /* Query */
- NULL, /* Info */
- irlan_provider_state_info,
- NULL, /* Media */
- irlan_provider_state_open,
- NULL, /* Wait */
- NULL, /* Arb */
- irlan_provider_state_data,
- NULL, /* Close */
- NULL, /* Sync */
-};
-
-void irlan_do_provider_event(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(*state[ self->provider.state] != NULL, return;);
-
- (*state[self->provider.state]) (self, event, skb);
-}
-
-/*
- * Function irlan_provider_state_idle (event, skb, info)
- *
- * IDLE, We are waiting for an indication that there is a provider
- * available.
- */
-static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return -1;);
-
- switch(event) {
- case IRLAN_CONNECT_INDICATION:
- irlan_provider_connect_response( self, self->provider.tsap_ctrl);
- irlan_next_provider_state( self, IRLAN_INFO);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
- * Function irlan_provider_state_info (self, event, skb, info)
- *
- * INFO, We have issued a GetInfo command and is awaiting a reply.
- */
-static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- int ret;
-
- IRDA_ASSERT(self != NULL, return -1;);
-
- switch(event) {
- case IRLAN_GET_INFO_CMD:
- /* Be sure to use 802.3 in case of peer mode */
- if (self->provider.access_type == ACCESS_PEER) {
- self->media = MEDIA_802_3;
-
- /* Check if client has started yet */
- if (self->client.state == IRLAN_IDLE) {
- /* This should get the client going */
- irlmp_discovery_request(8);
- }
- }
-
- irlan_provider_send_reply(self, CMD_GET_PROVIDER_INFO,
- RSP_SUCCESS);
- /* Keep state */
- break;
- case IRLAN_GET_MEDIA_CMD:
- irlan_provider_send_reply(self, CMD_GET_MEDIA_CHAR,
- RSP_SUCCESS);
- /* Keep state */
- break;
- case IRLAN_OPEN_DATA_CMD:
- ret = irlan_parse_open_data_cmd(self, skb);
- if (self->provider.access_type == ACCESS_PEER) {
- /* FIXME: make use of random functions! */
- self->provider.send_arb_val = (jiffies & 0xffff);
- }
- irlan_provider_send_reply(self, CMD_OPEN_DATA_CHANNEL, ret);
-
- if (ret == RSP_SUCCESS) {
- irlan_next_provider_state(self, IRLAN_OPEN);
-
- /* Signal client that we are now open */
- irlan_do_client_event(self, IRLAN_PROVIDER_SIGNAL, NULL);
- }
- break;
- case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
- case IRLAN_LAP_DISCONNECT:
- irlan_next_provider_state(self, IRLAN_IDLE);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
- * Function irlan_provider_state_open (self, event, skb, info)
- *
- * OPEN, The client has issued a OpenData command and is awaiting a
- * reply
- *
- */
-static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return -1;);
-
- switch(event) {
- case IRLAN_FILTER_CONFIG_CMD:
- irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb);
- irlan_provider_send_reply(self, CMD_FILTER_OPERATION,
- RSP_SUCCESS);
- /* Keep state */
- break;
- case IRLAN_DATA_CONNECT_INDICATION:
- irlan_next_provider_state(self, IRLAN_DATA);
- irlan_provider_connect_response(self, self->tsap_data);
- break;
- case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
- case IRLAN_LAP_DISCONNECT:
- irlan_next_provider_state(self, IRLAN_IDLE);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
- * Function irlan_provider_state_data (self, event, skb, info)
- *
- * DATA, The data channel is connected, allowing data transfers between
- * the local and remote machines.
- *
- */
-static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
-
- switch(event) {
- case IRLAN_FILTER_CONFIG_CMD:
- irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb);
- irlan_provider_send_reply(self, CMD_FILTER_OPERATION,
- RSP_SUCCESS);
- break;
- case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
- case IRLAN_LAP_DISCONNECT:
- irlan_next_provider_state(self, IRLAN_IDLE);
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__ , event);
- break;
- }
- if (skb)
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-
-
-
-
-
-
-
-
-
diff --git a/drivers/staging/irda/net/irlap.c b/drivers/staging/irda/net/irlap.c
deleted file mode 100644
index d7d894423b4f..000000000000
--- a/drivers/staging/irda/net/irlap.c
+++ /dev/null
@@ -1,1207 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlap.c
- * Version: 1.0
- * Description: IrLAP implementation for Linux
- * Status: Stable
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Aug 4 20:40:53 1997
- * Modified at: Tue Dec 14 09:26:44 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
- * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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/slab.h>
-#include <linux/string.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/random.h>
-#include <linux/module.h>
-#include <linux/seq_file.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-#include <net/irda/irqueue.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/irlmp_frame.h>
-#include <net/irda/irlap_frame.h>
-#include <net/irda/irlap.h>
-#include <net/irda/timer.h>
-#include <net/irda/qos.h>
-
-static hashbin_t *irlap = NULL;
-int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ;
-
-/* This is the delay of missed pf period before generating an event
- * to the application. The spec mandate 3 seconds, but in some cases
- * it's way too long. - Jean II */
-int sysctl_warn_noreply_time = 3;
-
-extern void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb);
-static void __irlap_close(struct irlap_cb *self);
-static void irlap_init_qos_capabilities(struct irlap_cb *self,
- struct qos_info *qos_user);
-
-static const char *const lap_reasons[] __maybe_unused = {
- "ERROR, NOT USED",
- "LAP_DISC_INDICATION",
- "LAP_NO_RESPONSE",
- "LAP_RESET_INDICATION",
- "LAP_FOUND_NONE",
- "LAP_MEDIA_BUSY",
- "LAP_PRIMARY_CONFLICT",
- "ERROR, NOT USED",
-};
-
-int __init irlap_init(void)
-{
- /* Check if the compiler did its job properly.
- * May happen on some ARM configuration, check with Russell King. */
- IRDA_ASSERT(sizeof(struct xid_frame) == 14, ;);
- IRDA_ASSERT(sizeof(struct test_frame) == 10, ;);
- IRDA_ASSERT(sizeof(struct ua_frame) == 10, ;);
- IRDA_ASSERT(sizeof(struct snrm_frame) == 11, ;);
-
- /* Allocate master array */
- irlap = hashbin_new(HB_LOCK);
- if (irlap == NULL) {
- net_err_ratelimited("%s: can't allocate irlap hashbin!\n",
- __func__);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void irlap_cleanup(void)
-{
- IRDA_ASSERT(irlap != NULL, return;);
-
- hashbin_delete(irlap, (FREE_FUNC) __irlap_close);
-}
-
-/*
- * Function irlap_open (driver)
- *
- * Initialize IrLAP layer
- *
- */
-struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos,
- const char *hw_name)
-{
- struct irlap_cb *self;
-
- /* Initialize the irlap structure. */
- self = kzalloc(sizeof(struct irlap_cb), GFP_KERNEL);
- if (self == NULL)
- return NULL;
-
- self->magic = LAP_MAGIC;
-
- /* Make a binding between the layers */
- self->netdev = dev;
- self->qos_dev = qos;
- /* Copy hardware name */
- if(hw_name != NULL) {
- strlcpy(self->hw_name, hw_name, sizeof(self->hw_name));
- } else {
- self->hw_name[0] = '\0';
- }
-
- /* FIXME: should we get our own field? */
- dev->atalk_ptr = self;
-
- self->state = LAP_OFFLINE;
-
- /* Initialize transmit queue */
- skb_queue_head_init(&self->txq);
- skb_queue_head_init(&self->txq_ultra);
- skb_queue_head_init(&self->wx_list);
-
- /* My unique IrLAP device address! */
- /* We don't want the broadcast address, neither the NULL address
- * (most often used to signify "invalid"), and we don't want an
- * address already in use (otherwise connect won't be able
- * to select the proper link). - Jean II */
- do {
- get_random_bytes(&self->saddr, sizeof(self->saddr));
- } while ((self->saddr == 0x0) || (self->saddr == BROADCAST) ||
- (hashbin_lock_find(irlap, self->saddr, NULL)) );
- /* Copy to the driver */
- memcpy(dev->dev_addr, &self->saddr, 4);
-
- timer_setup(&self->slot_timer, NULL, 0);
- timer_setup(&self->query_timer, NULL, 0);
- timer_setup(&self->discovery_timer, NULL, 0);
- timer_setup(&self->final_timer, NULL, 0);
- timer_setup(&self->poll_timer, NULL, 0);
- timer_setup(&self->wd_timer, NULL, 0);
- timer_setup(&self->backoff_timer, NULL, 0);
- timer_setup(&self->media_busy_timer, NULL, 0);
-
- irlap_apply_default_connection_parameters(self);
-
- self->N3 = 3; /* # connections attempts to try before giving up */
-
- self->state = LAP_NDM;
-
- hashbin_insert(irlap, (irda_queue_t *) self, self->saddr, NULL);
-
- irlmp_register_link(self, self->saddr, &self->notify);
-
- return self;
-}
-EXPORT_SYMBOL(irlap_open);
-
-/*
- * Function __irlap_close (self)
- *
- * Remove IrLAP and all allocated memory. Stop any pending timers.
- *
- */
-static void __irlap_close(struct irlap_cb *self)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- /* Stop timers */
- del_timer(&self->slot_timer);
- del_timer(&self->query_timer);
- del_timer(&self->discovery_timer);
- del_timer(&self->final_timer);
- del_timer(&self->poll_timer);
- del_timer(&self->wd_timer);
- del_timer(&self->backoff_timer);
- del_timer(&self->media_busy_timer);
-
- irlap_flush_all_queues(self);
-
- self->magic = 0;
-
- kfree(self);
-}
-
-/*
- * Function irlap_close (self)
- *
- * Remove IrLAP instance
- *
- */
-void irlap_close(struct irlap_cb *self)
-{
- struct irlap_cb *lap;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- /* We used to send a LAP_DISC_INDICATION here, but this was
- * racy. This has been move within irlmp_unregister_link()
- * itself. Jean II */
-
- /* Kill the LAP and all LSAPs on top of it */
- irlmp_unregister_link(self->saddr);
- self->notify.instance = NULL;
-
- /* Be sure that we manage to remove ourself from the hash */
- lap = hashbin_remove(irlap, self->saddr, NULL);
- if (!lap) {
- pr_debug("%s(), Didn't find myself!\n", __func__);
- return;
- }
- __irlap_close(lap);
-}
-EXPORT_SYMBOL(irlap_close);
-
-/*
- * Function irlap_connect_indication (self, skb)
- *
- * Another device is attempting to make a connection
- *
- */
-void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- irlap_init_qos_capabilities(self, NULL); /* No user QoS! */
-
- irlmp_link_connect_indication(self->notify.instance, self->saddr,
- self->daddr, &self->qos_tx, skb);
-}
-
-/*
- * Function irlap_connect_response (self, skb)
- *
- * Service user has accepted incoming connection
- *
- */
-void irlap_connect_response(struct irlap_cb *self, struct sk_buff *userdata)
-{
- irlap_do_event(self, CONNECT_RESPONSE, userdata, NULL);
-}
-
-/*
- * Function irlap_connect_request (self, daddr, qos_user, sniff)
- *
- * Request connection with another device, sniffing is not implemented
- * yet.
- *
- */
-void irlap_connect_request(struct irlap_cb *self, __u32 daddr,
- struct qos_info *qos_user, int sniff)
-{
- pr_debug("%s(), daddr=0x%08x\n", __func__, daddr);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- self->daddr = daddr;
-
- /*
- * If the service user specifies QoS values for this connection,
- * then use them
- */
- irlap_init_qos_capabilities(self, qos_user);
-
- if ((self->state == LAP_NDM) && !self->media_busy)
- irlap_do_event(self, CONNECT_REQUEST, NULL, NULL);
- else
- self->connect_pending = TRUE;
-}
-
-/*
- * Function irlap_connect_confirm (self, skb)
- *
- * Connection request has been accepted
- *
- */
-void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- irlmp_link_connect_confirm(self->notify.instance, &self->qos_tx, skb);
-}
-
-/*
- * Function irlap_data_indication (self, skb)
- *
- * Received data frames from IR-port, so we just pass them up to
- * IrLMP for further processing
- *
- */
-void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb,
- int unreliable)
-{
- /* Hide LAP header from IrLMP layer */
- skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
-
- irlmp_link_data_indication(self->notify.instance, skb, unreliable);
-}
-
-
-/*
- * Function irlap_data_request (self, skb)
- *
- * Queue data for transmission, must wait until XMIT state
- *
- */
-void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
- int unreliable)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
- return;);
- skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
-
- /*
- * Must set frame format now so that the rest of the code knows
- * if its dealing with an I or an UI frame
- */
- if (unreliable)
- skb->data[1] = UI_FRAME;
- else
- skb->data[1] = I_FRAME;
-
- /* Don't forget to refcount it - see irlmp_connect_request(). */
- skb_get(skb);
-
- /* Add at the end of the queue (keep ordering) - Jean II */
- skb_queue_tail(&self->txq, skb);
-
- /*
- * Send event if this frame only if we are in the right state
- * FIXME: udata should be sent first! (skb_queue_head?)
- */
- if ((self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) {
- /* If we are not already processing the Tx queue, trigger
- * transmission immediately - Jean II */
- if((skb_queue_len(&self->txq) <= 1) && (!self->local_busy))
- irlap_do_event(self, DATA_REQUEST, skb, NULL);
- /* Otherwise, the packets will be sent normally at the
- * next pf-poll - Jean II */
- }
-}
-
-/*
- * Function irlap_unitdata_request (self, skb)
- *
- * Send Ultra data. This is data that must be sent outside any connection
- *
- */
-#ifdef CONFIG_IRDA_ULTRA
-void irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
- return;);
- skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
-
- skb->data[0] = CBROADCAST;
- skb->data[1] = UI_FRAME;
-
- /* Don't need to refcount, see irlmp_connless_data_request() */
-
- skb_queue_tail(&self->txq_ultra, skb);
-
- irlap_do_event(self, SEND_UI_FRAME, NULL, NULL);
-}
-#endif /*CONFIG_IRDA_ULTRA */
-
-/*
- * Function irlap_udata_indication (self, skb)
- *
- * Receive Ultra data. This is data that is received outside any connection
- *
- */
-#ifdef CONFIG_IRDA_ULTRA
-void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
-
- /* Hide LAP header from IrLMP layer */
- skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
-
- irlmp_link_unitdata_indication(self->notify.instance, skb);
-}
-#endif /* CONFIG_IRDA_ULTRA */
-
-/*
- * Function irlap_disconnect_request (void)
- *
- * Request to disconnect connection by service user
- */
-void irlap_disconnect_request(struct irlap_cb *self)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- /* Don't disconnect until all data frames are successfully sent */
- if (!skb_queue_empty(&self->txq)) {
- self->disconnect_pending = TRUE;
- return;
- }
-
- /* Check if we are in the right state for disconnecting */
- switch (self->state) {
- case LAP_XMIT_P: /* FALLTHROUGH */
- case LAP_XMIT_S: /* FALLTHROUGH */
- case LAP_CONN: /* FALLTHROUGH */
- case LAP_RESET_WAIT: /* FALLTHROUGH */
- case LAP_RESET_CHECK:
- irlap_do_event(self, DISCONNECT_REQUEST, NULL, NULL);
- break;
- default:
- pr_debug("%s(), disconnect pending!\n", __func__);
- self->disconnect_pending = TRUE;
- break;
- }
-}
-
-/*
- * Function irlap_disconnect_indication (void)
- *
- * Disconnect request from other device
- *
- */
-void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason)
-{
- pr_debug("%s(), reason=%s\n", __func__, lap_reasons[reason]);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- /* Flush queues */
- irlap_flush_all_queues(self);
-
- switch (reason) {
- case LAP_RESET_INDICATION:
- pr_debug("%s(), Sending reset request!\n", __func__);
- irlap_do_event(self, RESET_REQUEST, NULL, NULL);
- break;
- case LAP_NO_RESPONSE: /* FALLTHROUGH */
- case LAP_DISC_INDICATION: /* FALLTHROUGH */
- case LAP_FOUND_NONE: /* FALLTHROUGH */
- case LAP_MEDIA_BUSY:
- irlmp_link_disconnect_indication(self->notify.instance, self,
- reason, NULL);
- break;
- default:
- net_err_ratelimited("%s: Unknown reason %d\n",
- __func__, reason);
- }
-}
-
-/*
- * Function irlap_discovery_request (gen_addr_bit)
- *
- * Start one single discovery operation.
- *
- */
-void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery)
-{
- struct irlap_info info;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
- IRDA_ASSERT(discovery != NULL, return;);
-
- pr_debug("%s(), nslots = %d\n", __func__, discovery->nslots);
-
- IRDA_ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) ||
- (discovery->nslots == 8) || (discovery->nslots == 16),
- return;);
-
- /* Discovery is only possible in NDM mode */
- if (self->state != LAP_NDM) {
- pr_debug("%s(), discovery only possible in NDM mode\n",
- __func__);
- irlap_discovery_confirm(self, NULL);
- /* Note : in theory, if we are not in NDM, we could postpone
- * the discovery like we do for connection request.
- * In practice, it's not worth it. If the media was busy,
- * it's likely next time around it won't be busy. If we are
- * in REPLY state, we will get passive discovery info & event.
- * Jean II */
- return;
- }
-
- /* Check if last discovery request finished in time, or if
- * it was aborted due to the media busy flag. */
- if (self->discovery_log != NULL) {
- hashbin_delete(self->discovery_log, (FREE_FUNC) kfree);
- self->discovery_log = NULL;
- }
-
- /* All operations will occur at predictable time, no need to lock */
- self->discovery_log = hashbin_new(HB_NOLOCK);
-
- if (self->discovery_log == NULL) {
- net_warn_ratelimited("%s(), Unable to allocate discovery log!\n",
- __func__);
- return;
- }
-
- info.S = discovery->nslots; /* Number of slots */
- info.s = 0; /* Current slot */
-
- self->discovery_cmd = discovery;
- info.discovery = discovery;
-
- /* sysctl_slot_timeout bounds are checked in irsysctl.c - Jean II */
- self->slot_timeout = msecs_to_jiffies(sysctl_slot_timeout);
-
- irlap_do_event(self, DISCOVERY_REQUEST, NULL, &info);
-}
-
-/*
- * Function irlap_discovery_confirm (log)
- *
- * A device has been discovered in front of this station, we
- * report directly to LMP.
- */
-void irlap_discovery_confirm(struct irlap_cb *self, hashbin_t *discovery_log)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- IRDA_ASSERT(self->notify.instance != NULL, return;);
-
- /*
- * Check for successful discovery, since we are then allowed to clear
- * the media busy condition (IrLAP 6.13.4 - p.94). This should allow
- * us to make connection attempts much faster and easier (i.e. no
- * collisions).
- * Setting media busy to false will also generate an event allowing
- * to process pending events in NDM state machine.
- * Note : the spec doesn't define what's a successful discovery is.
- * If we want Ultra to work, it's successful even if there is
- * nobody discovered - Jean II
- */
- if (discovery_log)
- irda_device_set_media_busy(self->netdev, FALSE);
-
- /* Inform IrLMP */
- irlmp_link_discovery_confirm(self->notify.instance, discovery_log);
-}
-
-/*
- * Function irlap_discovery_indication (log)
- *
- * Somebody is trying to discover us!
- *
- */
-void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
- IRDA_ASSERT(discovery != NULL, return;);
-
- IRDA_ASSERT(self->notify.instance != NULL, return;);
-
- /* A device is very likely to connect immediately after it performs
- * a successful discovery. This means that in our case, we are much
- * more likely to receive a connection request over the medium.
- * So, we backoff to avoid collisions.
- * IrLAP spec 6.13.4 suggest 100ms...
- * Note : this little trick actually make a *BIG* difference. If I set
- * my Linux box with discovery enabled and one Ultra frame sent every
- * second, my Palm has no trouble connecting to it every time !
- * Jean II */
- irda_device_set_media_busy(self->netdev, SMALL);
-
- irlmp_link_discovery_indication(self->notify.instance, discovery);
-}
-
-/*
- * Function irlap_status_indication (quality_of_link)
- */
-void irlap_status_indication(struct irlap_cb *self, int quality_of_link)
-{
- switch (quality_of_link) {
- case STATUS_NO_ACTIVITY:
- net_info_ratelimited("IrLAP, no activity on link!\n");
- break;
- case STATUS_NOISY:
- net_info_ratelimited("IrLAP, noisy link!\n");
- break;
- default:
- break;
- }
- irlmp_status_indication(self->notify.instance,
- quality_of_link, LOCK_NO_CHANGE);
-}
-
-/*
- * Function irlap_reset_indication (void)
- */
-void irlap_reset_indication(struct irlap_cb *self)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- if (self->state == LAP_RESET_WAIT)
- irlap_do_event(self, RESET_REQUEST, NULL, NULL);
- else
- irlap_do_event(self, RESET_RESPONSE, NULL, NULL);
-}
-
-/*
- * Function irlap_reset_confirm (void)
- */
-void irlap_reset_confirm(void)
-{
-}
-
-/*
- * Function irlap_generate_rand_time_slot (S, s)
- *
- * Generate a random time slot between s and S-1 where
- * S = Number of slots (0 -> S-1)
- * s = Current slot
- */
-int irlap_generate_rand_time_slot(int S, int s)
-{
- static int rand;
- int slot;
-
- IRDA_ASSERT((S - s) > 0, return 0;);
-
- rand += jiffies;
- rand ^= (rand << 12);
- rand ^= (rand >> 20);
-
- slot = s + rand % (S-s);
-
- IRDA_ASSERT((slot >= s) || (slot < S), return 0;);
-
- return slot;
-}
-
-/*
- * Function irlap_update_nr_received (nr)
- *
- * Remove all acknowledged frames in current window queue. This code is
- * not intuitive and you should not try to change it. If you think it
- * contains bugs, please mail a patch to the author instead.
- */
-void irlap_update_nr_received(struct irlap_cb *self, int nr)
-{
- struct sk_buff *skb = NULL;
- int count = 0;
-
- /*
- * Remove all the ack-ed frames from the window queue.
- */
-
- /*
- * Optimize for the common case. It is most likely that the receiver
- * will acknowledge all the frames we have sent! So in that case we
- * delete all frames stored in window.
- */
- if (nr == self->vs) {
- while ((skb = skb_dequeue(&self->wx_list)) != NULL) {
- dev_kfree_skb(skb);
- }
- /* The last acked frame is the next to send minus one */
- self->va = nr - 1;
- } else {
- /* Remove all acknowledged frames in current window */
- while ((skb_peek(&self->wx_list) != NULL) &&
- (((self->va+1) % 8) != nr))
- {
- skb = skb_dequeue(&self->wx_list);
- dev_kfree_skb(skb);
-
- self->va = (self->va + 1) % 8;
- count++;
- }
- }
-
- /* Advance window */
- self->window = self->window_size - skb_queue_len(&self->wx_list);
-}
-
-/*
- * Function irlap_validate_ns_received (ns)
- *
- * Validate the next to send (ns) field from received frame.
- */
-int irlap_validate_ns_received(struct irlap_cb *self, int ns)
-{
- /* ns as expected? */
- if (ns == self->vr)
- return NS_EXPECTED;
- /*
- * Stations are allowed to treat invalid NS as unexpected NS
- * IrLAP, Recv ... with-invalid-Ns. p. 84
- */
- return NS_UNEXPECTED;
-
- /* return NR_INVALID; */
-}
-/*
- * Function irlap_validate_nr_received (nr)
- *
- * Validate the next to receive (nr) field from received frame.
- *
- */
-int irlap_validate_nr_received(struct irlap_cb *self, int nr)
-{
- /* nr as expected? */
- if (nr == self->vs) {
- pr_debug("%s(), expected!\n", __func__);
- return NR_EXPECTED;
- }
-
- /*
- * unexpected nr? (but within current window), first we check if the
- * ns numbers of the frames in the current window wrap.
- */
- if (self->va < self->vs) {
- if ((nr >= self->va) && (nr <= self->vs))
- return NR_UNEXPECTED;
- } else {
- if ((nr >= self->va) || (nr <= self->vs))
- return NR_UNEXPECTED;
- }
-
- /* Invalid nr! */
- return NR_INVALID;
-}
-
-/*
- * Function irlap_initiate_connection_state ()
- *
- * Initialize the connection state parameters
- *
- */
-void irlap_initiate_connection_state(struct irlap_cb *self)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- /* Next to send and next to receive */
- self->vs = self->vr = 0;
-
- /* Last frame which got acked (0 - 1) % 8 */
- self->va = 7;
-
- self->window = 1;
-
- self->remote_busy = FALSE;
- self->retry_count = 0;
-}
-
-/*
- * Function irlap_wait_min_turn_around (self, qos)
- *
- * Wait negotiated minimum turn around time, this function actually sets
- * the number of BOS's that must be sent before the next transmitted
- * frame in order to delay for the specified amount of time. This is
- * done to avoid using timers, and the forbidden udelay!
- */
-void irlap_wait_min_turn_around(struct irlap_cb *self, struct qos_info *qos)
-{
- __u32 min_turn_time;
- __u32 speed;
-
- /* Get QoS values. */
- speed = qos->baud_rate.value;
- min_turn_time = qos->min_turn_time.value;
-
- /* No need to calculate XBOFs for speeds over 115200 bps */
- if (speed > 115200) {
- self->mtt_required = min_turn_time;
- return;
- }
-
- /*
- * Send additional BOF's for the next frame for the requested
- * min turn time, so now we must calculate how many chars (XBOF's) we
- * must send for the requested time period (min turn time)
- */
- self->xbofs_delay = irlap_min_turn_time_in_bytes(speed, min_turn_time);
-}
-
-/*
- * Function irlap_flush_all_queues (void)
- *
- * Flush all queues
- *
- */
-void irlap_flush_all_queues(struct irlap_cb *self)
-{
- struct sk_buff* skb;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- /* Free transmission queue */
- while ((skb = skb_dequeue(&self->txq)) != NULL)
- dev_kfree_skb(skb);
-
- while ((skb = skb_dequeue(&self->txq_ultra)) != NULL)
- dev_kfree_skb(skb);
-
- /* Free sliding window buffered packets */
- while ((skb = skb_dequeue(&self->wx_list)) != NULL)
- dev_kfree_skb(skb);
-}
-
-/*
- * Function irlap_setspeed (self, speed)
- *
- * Change the speed of the IrDA port
- *
- */
-static void irlap_change_speed(struct irlap_cb *self, __u32 speed, int now)
-{
- struct sk_buff *skb;
-
- pr_debug("%s(), setting speed to %d\n", __func__, speed);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- self->speed = speed;
-
- /* Change speed now, or just piggyback speed on frames */
- if (now) {
- /* Send down empty frame to trigger speed change */
- skb = alloc_skb(0, GFP_ATOMIC);
- if (skb)
- irlap_queue_xmit(self, skb);
- }
-}
-
-/*
- * Function irlap_init_qos_capabilities (self, qos)
- *
- * Initialize QoS for this IrLAP session, What we do is to compute the
- * intersection of the QoS capabilities for the user, driver and for
- * IrLAP itself. Normally, IrLAP will not specify any values, but it can
- * be used to restrict certain values.
- */
-static void irlap_init_qos_capabilities(struct irlap_cb *self,
- struct qos_info *qos_user)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
- IRDA_ASSERT(self->netdev != NULL, return;);
-
- /* Start out with the maximum QoS support possible */
- irda_init_max_qos_capabilies(&self->qos_rx);
-
- /* Apply drivers QoS capabilities */
- irda_qos_compute_intersection(&self->qos_rx, self->qos_dev);
-
- /*
- * Check for user supplied QoS parameters. The service user is only
- * allowed to supply these values. We check each parameter since the
- * user may not have set all of them.
- */
- if (qos_user) {
- pr_debug("%s(), Found user specified QoS!\n", __func__);
-
- if (qos_user->baud_rate.bits)
- self->qos_rx.baud_rate.bits &= qos_user->baud_rate.bits;
-
- if (qos_user->max_turn_time.bits)
- self->qos_rx.max_turn_time.bits &= qos_user->max_turn_time.bits;
- if (qos_user->data_size.bits)
- self->qos_rx.data_size.bits &= qos_user->data_size.bits;
-
- if (qos_user->link_disc_time.bits)
- self->qos_rx.link_disc_time.bits &= qos_user->link_disc_time.bits;
- }
-
- /* Use 500ms in IrLAP for now */
- self->qos_rx.max_turn_time.bits &= 0x01;
-
- /* Set data size */
- /*self->qos_rx.data_size.bits &= 0x03;*/
-
- irda_qos_bits_to_value(&self->qos_rx);
-}
-
-/*
- * Function irlap_apply_default_connection_parameters (void, now)
- *
- * Use the default connection and transmission parameters
- */
-void irlap_apply_default_connection_parameters(struct irlap_cb *self)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- /* xbofs : Default value in NDM */
- self->next_bofs = 12;
- self->bofs_count = 12;
-
- /* NDM Speed is 9600 */
- irlap_change_speed(self, 9600, TRUE);
-
- /* Set mbusy when going to NDM state */
- irda_device_set_media_busy(self->netdev, TRUE);
-
- /*
- * Generate random connection address for this session, which must
- * be 7 bits wide and different from 0x00 and 0xfe
- */
- while ((self->caddr == 0x00) || (self->caddr == 0xfe)) {
- get_random_bytes(&self->caddr, sizeof(self->caddr));
- self->caddr &= 0xfe;
- }
-
- /* Use default values until connection has been negitiated */
- self->slot_timeout = sysctl_slot_timeout;
- self->final_timeout = FINAL_TIMEOUT;
- self->poll_timeout = POLL_TIMEOUT;
- self->wd_timeout = WD_TIMEOUT;
-
- /* Set some default values */
- self->qos_tx.baud_rate.value = 9600;
- self->qos_rx.baud_rate.value = 9600;
- self->qos_tx.max_turn_time.value = 0;
- self->qos_rx.max_turn_time.value = 0;
- self->qos_tx.min_turn_time.value = 0;
- self->qos_rx.min_turn_time.value = 0;
- self->qos_tx.data_size.value = 64;
- self->qos_rx.data_size.value = 64;
- self->qos_tx.window_size.value = 1;
- self->qos_rx.window_size.value = 1;
- self->qos_tx.additional_bofs.value = 12;
- self->qos_rx.additional_bofs.value = 12;
- self->qos_tx.link_disc_time.value = 0;
- self->qos_rx.link_disc_time.value = 0;
-
- irlap_flush_all_queues(self);
-
- self->disconnect_pending = FALSE;
- self->connect_pending = FALSE;
-}
-
-/*
- * Function irlap_apply_connection_parameters (qos, now)
- *
- * Initialize IrLAP with the negotiated QoS values
- *
- * If 'now' is false, the speed and xbofs will be changed after the next
- * frame is sent.
- * If 'now' is true, the speed and xbofs is changed immediately
- */
-void irlap_apply_connection_parameters(struct irlap_cb *self, int now)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- /* Set the negotiated xbofs value */
- self->next_bofs = self->qos_tx.additional_bofs.value;
- if (now)
- self->bofs_count = self->next_bofs;
-
- /* Set the negotiated link speed (may need the new xbofs value) */
- irlap_change_speed(self, self->qos_tx.baud_rate.value, now);
-
- self->window_size = self->qos_tx.window_size.value;
- self->window = self->qos_tx.window_size.value;
-
-#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
- /*
- * Calculate how many bytes it is possible to transmit before the
- * link must be turned around
- */
- self->line_capacity =
- irlap_max_line_capacity(self->qos_tx.baud_rate.value,
- self->qos_tx.max_turn_time.value);
- self->bytes_left = self->line_capacity;
-#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
-
-
- /*
- * Initialize timeout values, some of the rules are listed on
- * page 92 in IrLAP.
- */
- IRDA_ASSERT(self->qos_tx.max_turn_time.value != 0, return;);
- IRDA_ASSERT(self->qos_rx.max_turn_time.value != 0, return;);
- /* The poll timeout applies only to the primary station.
- * It defines the maximum time the primary stay in XMIT mode
- * before timeout and turning the link around (sending a RR).
- * Or, this is how much we can keep the pf bit in primary mode.
- * Therefore, it must be lower or equal than our *OWN* max turn around.
- * Jean II */
- self->poll_timeout = msecs_to_jiffies(
- self->qos_tx.max_turn_time.value);
- /* The Final timeout applies only to the primary station.
- * It defines the maximum time the primary wait (mostly in RECV mode)
- * for an answer from the secondary station before polling it again.
- * Therefore, it must be greater or equal than our *PARTNER*
- * max turn around time - Jean II */
- self->final_timeout = msecs_to_jiffies(
- self->qos_rx.max_turn_time.value);
- /* The Watchdog Bit timeout applies only to the secondary station.
- * It defines the maximum time the secondary wait (mostly in RECV mode)
- * for poll from the primary station before getting annoyed.
- * Therefore, it must be greater or equal than our *PARTNER*
- * max turn around time - Jean II */
- self->wd_timeout = self->final_timeout * 2;
-
- /*
- * N1 and N2 are maximum retry count for *both* the final timer
- * and the wd timer (with a factor 2) as defined above.
- * After N1 retry of a timer, we give a warning to the user.
- * After N2 retry, we consider the link dead and disconnect it.
- * Jean II
- */
-
- /*
- * Set N1 to 0 if Link Disconnect/Threshold Time = 3 and set it to
- * 3 seconds otherwise. See page 71 in IrLAP for more details.
- * Actually, it's not always 3 seconds, as we allow to set
- * it via sysctl... Max maxtt is 500ms, and N1 need to be multiple
- * of 2, so 1 second is minimum we can allow. - Jean II
- */
- if (self->qos_tx.link_disc_time.value == sysctl_warn_noreply_time)
- /*
- * If we set N1 to 0, it will trigger immediately, which is
- * not what we want. What we really want is to disable it,
- * Jean II
- */
- self->N1 = -2; /* Disable - Need to be multiple of 2*/
- else
- self->N1 = sysctl_warn_noreply_time * 1000 /
- self->qos_rx.max_turn_time.value;
-
- pr_debug("Setting N1 = %d\n", self->N1);
-
- /* Set N2 to match our own disconnect time */
- self->N2 = self->qos_tx.link_disc_time.value * 1000 /
- self->qos_rx.max_turn_time.value;
- pr_debug("Setting N2 = %d\n", self->N2);
-}
-
-#ifdef CONFIG_PROC_FS
-struct irlap_iter_state {
- int id;
-};
-
-static void *irlap_seq_start(struct seq_file *seq, loff_t *pos)
-{
- struct irlap_iter_state *iter = seq->private;
- struct irlap_cb *self;
-
- /* Protect our access to the tsap list */
- spin_lock_irq(&irlap->hb_spinlock);
- iter->id = 0;
-
- for (self = (struct irlap_cb *) hashbin_get_first(irlap);
- self; self = (struct irlap_cb *) hashbin_get_next(irlap)) {
- if (iter->id == *pos)
- break;
- ++iter->id;
- }
-
- return self;
-}
-
-static void *irlap_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- struct irlap_iter_state *iter = seq->private;
-
- ++*pos;
- ++iter->id;
- return (void *) hashbin_get_next(irlap);
-}
-
-static void irlap_seq_stop(struct seq_file *seq, void *v)
-{
- spin_unlock_irq(&irlap->hb_spinlock);
-}
-
-static int irlap_seq_show(struct seq_file *seq, void *v)
-{
- const struct irlap_iter_state *iter = seq->private;
- const struct irlap_cb *self = v;
-
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -EINVAL;);
-
- seq_printf(seq, "irlap%d ", iter->id);
- seq_printf(seq, "state: %s\n",
- irlap_state[self->state]);
-
- seq_printf(seq, " device name: %s, ",
- (self->netdev) ? self->netdev->name : "bug");
- seq_printf(seq, "hardware name: %s\n", self->hw_name);
-
- seq_printf(seq, " caddr: %#02x, ", self->caddr);
- seq_printf(seq, "saddr: %#08x, ", self->saddr);
- seq_printf(seq, "daddr: %#08x\n", self->daddr);
-
- seq_printf(seq, " win size: %d, ",
- self->window_size);
- seq_printf(seq, "win: %d, ", self->window);
-#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
- seq_printf(seq, "line capacity: %d, ",
- self->line_capacity);
- seq_printf(seq, "bytes left: %d\n", self->bytes_left);
-#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
- seq_printf(seq, " tx queue len: %d ",
- skb_queue_len(&self->txq));
- seq_printf(seq, "win queue len: %d ",
- skb_queue_len(&self->wx_list));
- seq_printf(seq, "rbusy: %s", self->remote_busy ?
- "TRUE" : "FALSE");
- seq_printf(seq, " mbusy: %s\n", self->media_busy ?
- "TRUE" : "FALSE");
-
- seq_printf(seq, " retrans: %d ", self->retry_count);
- seq_printf(seq, "vs: %d ", self->vs);
- seq_printf(seq, "vr: %d ", self->vr);
- seq_printf(seq, "va: %d\n", self->va);
-
- seq_printf(seq, " qos\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\tcomp\n");
-
- seq_printf(seq, " tx\t%d\t",
- self->qos_tx.baud_rate.value);
- seq_printf(seq, "%d\t",
- self->qos_tx.max_turn_time.value);
- seq_printf(seq, "%d\t",
- self->qos_tx.data_size.value);
- seq_printf(seq, "%d\t",
- self->qos_tx.window_size.value);
- seq_printf(seq, "%d\t",
- self->qos_tx.additional_bofs.value);
- seq_printf(seq, "%d\t",
- self->qos_tx.min_turn_time.value);
- seq_printf(seq, "%d\t",
- self->qos_tx.link_disc_time.value);
- seq_printf(seq, "\n");
-
- seq_printf(seq, " rx\t%d\t",
- self->qos_rx.baud_rate.value);
- seq_printf(seq, "%d\t",
- self->qos_rx.max_turn_time.value);
- seq_printf(seq, "%d\t",
- self->qos_rx.data_size.value);
- seq_printf(seq, "%d\t",
- self->qos_rx.window_size.value);
- seq_printf(seq, "%d\t",
- self->qos_rx.additional_bofs.value);
- seq_printf(seq, "%d\t",
- self->qos_rx.min_turn_time.value);
- seq_printf(seq, "%d\n",
- self->qos_rx.link_disc_time.value);
-
- return 0;
-}
-
-static const struct seq_operations irlap_seq_ops = {
- .start = irlap_seq_start,
- .next = irlap_seq_next,
- .stop = irlap_seq_stop,
- .show = irlap_seq_show,
-};
-
-static int irlap_seq_open(struct inode *inode, struct file *file)
-{
- if (irlap == NULL)
- return -EINVAL;
-
- return seq_open_private(file, &irlap_seq_ops,
- sizeof(struct irlap_iter_state));
-}
-
-const struct file_operations irlap_seq_fops = {
- .owner = THIS_MODULE,
- .open = irlap_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_private,
-};
-
-#endif /* CONFIG_PROC_FS */
diff --git a/drivers/staging/irda/net/irlap_event.c b/drivers/staging/irda/net/irlap_event.c
deleted file mode 100644
index 634188b07e0a..000000000000
--- a/drivers/staging/irda/net/irlap_event.c
+++ /dev/null
@@ -1,2316 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlap_event.c
- * Version: 0.9
- * Description: IrLAP state machine implementation
- * Status: Experimental.
- * Author: Dag Brattli <dag@brattli.net>
- * Created at: Sat Aug 16 00:59:29 1997
- * Modified at: Sat Dec 25 21:07:57 1999
- * Modified by: Dag Brattli <dag@brattli.net>
- *
- * Copyright (c) 1998-2000 Dag Brattli <dag@brattli.net>,
- * Copyright (c) 1998 Thomas Davis <ratbert@radiks.net>
- * All Rights Reserved.
- * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irlap_event.h>
-
-#include <net/irda/timer.h>
-#include <net/irda/irlap.h>
-#include <net/irda/irlap_frame.h>
-#include <net/irda/qos.h>
-#include <net/irda/parameters.h>
-#include <net/irda/irlmp.h> /* irlmp_flow_indication(), ... */
-
-#include <net/irda/irda_device.h>
-
-#ifdef CONFIG_IRDA_FAST_RR
-int sysctl_fast_poll_increase = 50;
-#endif
-
-static int irlap_state_ndm (struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_query (struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_reply (struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_conn (struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_setup (struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_xmit_p (struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_pclose (struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_nrm_p (struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_reset (struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_nrm_s (struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_xmit_s (struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_sclose (struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_reset_check(struct irlap_cb *, IRLAP_EVENT event,
- struct sk_buff *, struct irlap_info *);
-
-static const char *const irlap_event[] __maybe_unused = {
- "DISCOVERY_REQUEST",
- "CONNECT_REQUEST",
- "CONNECT_RESPONSE",
- "DISCONNECT_REQUEST",
- "DATA_REQUEST",
- "RESET_REQUEST",
- "RESET_RESPONSE",
- "SEND_I_CMD",
- "SEND_UI_FRAME",
- "RECV_DISCOVERY_XID_CMD",
- "RECV_DISCOVERY_XID_RSP",
- "RECV_SNRM_CMD",
- "RECV_TEST_CMD",
- "RECV_TEST_RSP",
- "RECV_UA_RSP",
- "RECV_DM_RSP",
- "RECV_RD_RSP",
- "RECV_I_CMD",
- "RECV_I_RSP",
- "RECV_UI_FRAME",
- "RECV_FRMR_RSP",
- "RECV_RR_CMD",
- "RECV_RR_RSP",
- "RECV_RNR_CMD",
- "RECV_RNR_RSP",
- "RECV_REJ_CMD",
- "RECV_REJ_RSP",
- "RECV_SREJ_CMD",
- "RECV_SREJ_RSP",
- "RECV_DISC_CMD",
- "SLOT_TIMER_EXPIRED",
- "QUERY_TIMER_EXPIRED",
- "FINAL_TIMER_EXPIRED",
- "POLL_TIMER_EXPIRED",
- "DISCOVERY_TIMER_EXPIRED",
- "WD_TIMER_EXPIRED",
- "BACKOFF_TIMER_EXPIRED",
- "MEDIA_BUSY_TIMER_EXPIRED",
-};
-
-const char *const irlap_state[] = {
- "LAP_NDM",
- "LAP_QUERY",
- "LAP_REPLY",
- "LAP_CONN",
- "LAP_SETUP",
- "LAP_OFFLINE",
- "LAP_XMIT_P",
- "LAP_PCLOSE",
- "LAP_NRM_P",
- "LAP_RESET_WAIT",
- "LAP_RESET",
- "LAP_NRM_S",
- "LAP_XMIT_S",
- "LAP_SCLOSE",
- "LAP_RESET_CHECK",
-};
-
-static int (*state[])(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info) =
-{
- irlap_state_ndm,
- irlap_state_query,
- irlap_state_reply,
- irlap_state_conn,
- irlap_state_setup,
- irlap_state_offline,
- irlap_state_xmit_p,
- irlap_state_pclose,
- irlap_state_nrm_p,
- irlap_state_reset_wait,
- irlap_state_reset,
- irlap_state_nrm_s,
- irlap_state_xmit_s,
- irlap_state_sclose,
- irlap_state_reset_check,
-};
-
-/*
- * Function irda_poll_timer_expired (data)
- *
- * Poll timer has expired. Normally we must now send a RR frame to the
- * remote device
- */
-static void irlap_poll_timer_expired(struct timer_list *t)
-{
- struct irlap_cb *self = from_timer(self, t, poll_timer);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL);
-}
-
-/*
- * Calculate and set time before we will have to send back the pf bit
- * to the peer. Use in primary.
- * Make sure that state is XMIT_P/XMIT_S when calling this function
- * (and that nobody messed up with the state). - Jean II
- */
-static void irlap_start_poll_timer(struct irlap_cb *self, int timeout)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
-#ifdef CONFIG_IRDA_FAST_RR
- /*
- * Send out the RR frames faster if our own transmit queue is empty, or
- * if the peer is busy. The effect is a much faster conversation
- */
- if (skb_queue_empty(&self->txq) || self->remote_busy) {
- if (self->fast_RR == TRUE) {
- /*
- * Assert that the fast poll timer has not reached the
- * normal poll timer yet
- */
- if (self->fast_RR_timeout < timeout) {
- /*
- * FIXME: this should be a more configurable
- * function
- */
- self->fast_RR_timeout +=
- (sysctl_fast_poll_increase * HZ/1000);
-
- /* Use this fast(er) timeout instead */
- timeout = self->fast_RR_timeout;
- }
- } else {
- self->fast_RR = TRUE;
-
- /* Start with just 0 ms */
- self->fast_RR_timeout = 0;
- timeout = 0;
- }
- } else
- self->fast_RR = FALSE;
-
- pr_debug("%s(), timeout=%d (%ld)\n", __func__, timeout, jiffies);
-#endif /* CONFIG_IRDA_FAST_RR */
-
- if (timeout == 0)
- irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL);
- else
- irda_start_timer(&self->poll_timer, timeout,
- irlap_poll_timer_expired);
-}
-
-/*
- * Function irlap_do_event (event, skb, info)
- *
- * Rushes through the state machine without any delay. If state == XMIT
- * then send queued data frames.
- */
-void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- int ret;
-
- if (!self || self->magic != LAP_MAGIC)
- return;
-
- pr_debug("%s(), event = %s, state = %s\n", __func__,
- irlap_event[event], irlap_state[self->state]);
-
- ret = (*state[self->state])(self, event, skb, info);
-
- /*
- * Check if there are any pending events that needs to be executed
- */
- switch (self->state) {
- case LAP_XMIT_P: /* FALLTHROUGH */
- case LAP_XMIT_S:
- /*
- * We just received the pf bit and are at the beginning
- * of a new LAP transmit window.
- * Check if there are any queued data frames, and do not
- * try to disconnect link if we send any data frames, since
- * that will change the state away form XMIT
- */
- pr_debug("%s() : queue len = %d\n", __func__,
- skb_queue_len(&self->txq));
-
- if (!skb_queue_empty(&self->txq)) {
- /* Prevent race conditions with irlap_data_request() */
- self->local_busy = TRUE;
-
- /* Theory of operation.
- * We send frames up to when we fill the window or
- * reach line capacity. Those frames will queue up
- * in the device queue, and the driver will slowly
- * send them.
- * After each frame that we send, we poll the higher
- * layer for more data. It's the right time to do
- * that because the link layer need to perform the mtt
- * and then send the first frame, so we can afford
- * to send a bit of time in kernel space.
- * The explicit flow indication allow to minimise
- * buffers (== lower latency), to avoid higher layer
- * polling via timers (== less context switches) and
- * to implement a crude scheduler - Jean II */
-
- /* Try to send away all queued data frames */
- while ((skb = skb_dequeue(&self->txq)) != NULL) {
- /* Send one frame */
- ret = (*state[self->state])(self, SEND_I_CMD,
- skb, NULL);
- /* Drop reference count.
- * It will be increase as needed in
- * irlap_send_data_xxx() */
- kfree_skb(skb);
-
- /* Poll the higher layers for one more frame */
- irlmp_flow_indication(self->notify.instance,
- FLOW_START);
-
- if (ret == -EPROTO)
- break; /* Try again later! */
- }
- /* Finished transmitting */
- self->local_busy = FALSE;
- } else if (self->disconnect_pending) {
- self->disconnect_pending = FALSE;
-
- ret = (*state[self->state])(self, DISCONNECT_REQUEST,
- NULL, NULL);
- }
- break;
-/* case LAP_NDM: */
-/* case LAP_CONN: */
-/* case LAP_RESET_WAIT: */
-/* case LAP_RESET_CHECK: */
- default:
- break;
- }
-}
-
-/*
- * Function irlap_state_ndm (event, skb, frame)
- *
- * NDM (Normal Disconnected Mode) state
- *
- */
-static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- discovery_t *discovery_rsp;
- int ret = 0;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- switch (event) {
- case CONNECT_REQUEST:
- IRDA_ASSERT(self->netdev != NULL, return -1;);
-
- if (self->media_busy) {
- /* Note : this will never happen, because we test
- * media busy in irlap_connect_request() and
- * postpone the event... - Jean II */
- pr_debug("%s(), CONNECT_REQUEST: media busy!\n",
- __func__);
-
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
- irlap_disconnect_indication(self, LAP_MEDIA_BUSY);
- } else {
- irlap_send_snrm_frame(self, &self->qos_rx);
-
- /* Start Final-bit timer */
- irlap_start_final_timer(self, self->final_timeout);
-
- self->retry_count = 0;
- irlap_next_state(self, LAP_SETUP);
- }
- break;
- case RECV_SNRM_CMD:
- /* Check if the frame contains and I field */
- if (info) {
- self->daddr = info->daddr;
- self->caddr = info->caddr;
-
- irlap_next_state(self, LAP_CONN);
-
- irlap_connect_indication(self, skb);
- } else {
- pr_debug("%s(), SNRM frame does not contain an I field!\n",
- __func__);
- }
- break;
- case DISCOVERY_REQUEST:
- IRDA_ASSERT(info != NULL, return -1;);
-
- if (self->media_busy) {
- pr_debug("%s(), DISCOVERY_REQUEST: media busy!\n",
- __func__);
- /* irlap->log.condition = MEDIA_BUSY; */
-
- /* This will make IrLMP try again */
- irlap_discovery_confirm(self, NULL);
- /* Note : the discovery log is not cleaned up here,
- * it will be done in irlap_discovery_request()
- * Jean II */
- return 0;
- }
-
- self->S = info->S;
- self->s = info->s;
- irlap_send_discovery_xid_frame(self, info->S, info->s, TRUE,
- info->discovery);
- self->frame_sent = FALSE;
- self->s++;
-
- irlap_start_slot_timer(self, self->slot_timeout);
- irlap_next_state(self, LAP_QUERY);
- break;
- case RECV_DISCOVERY_XID_CMD:
- IRDA_ASSERT(info != NULL, return -1;);
-
- /* Assert that this is not the final slot */
- if (info->s <= info->S) {
- self->slot = irlap_generate_rand_time_slot(info->S,
- info->s);
- if (self->slot == info->s) {
- discovery_rsp = irlmp_get_discovery_response();
- discovery_rsp->data.daddr = info->daddr;
-
- irlap_send_discovery_xid_frame(self, info->S,
- self->slot,
- FALSE,
- discovery_rsp);
- self->frame_sent = TRUE;
- } else
- self->frame_sent = FALSE;
-
- /*
- * Go to reply state until end of discovery to
- * inhibit our own transmissions. Set the timer
- * to not stay forever there... Jean II
- */
- irlap_start_query_timer(self, info->S, info->s);
- irlap_next_state(self, LAP_REPLY);
- } else {
- /* This is the final slot. How is it possible ?
- * This would happen is both discoveries are just slightly
- * offset (if they are in sync, all packets are lost).
- * Most often, all the discovery requests will be received
- * in QUERY state (see my comment there), except for the
- * last frame that will come here.
- * The big trouble when it happen is that active discovery
- * doesn't happen, because nobody answer the discoveries
- * frame of the other guy, so the log shows up empty.
- * What should we do ?
- * Not much. It's too late to answer those discovery frames,
- * so we just pass the info to IrLMP who will put it in the
- * log (and post an event).
- * Another cause would be devices that do discovery much
- * slower than us, however the latest fixes should minimise
- * those cases...
- * Jean II
- */
- pr_debug("%s(), Receiving final discovery request, missed the discovery slots :-(\n",
- __func__);
-
- /* Last discovery request -> in the log */
- irlap_discovery_indication(self, info->discovery);
- }
- break;
- case MEDIA_BUSY_TIMER_EXPIRED:
- /* A bunch of events may be postponed because the media is
- * busy (usually immediately after we close a connection),
- * or while we are doing discovery (state query/reply).
- * In all those cases, the media busy flag will be cleared
- * when it's OK for us to process those postponed events.
- * This event is not mentioned in the state machines in the
- * IrLAP spec. It's because they didn't consider Ultra and
- * postponing connection request is optional.
- * Jean II */
-#ifdef CONFIG_IRDA_ULTRA
- /* Send any pending Ultra frames if any */
- if (!skb_queue_empty(&self->txq_ultra)) {
- /* We don't send the frame, just post an event.
- * Also, previously this code was in timer.c...
- * Jean II */
- ret = (*state[self->state])(self, SEND_UI_FRAME,
- NULL, NULL);
- }
-#endif /* CONFIG_IRDA_ULTRA */
- /* Check if we should try to connect.
- * This code was previously in irlap_do_event() */
- if (self->connect_pending) {
- self->connect_pending = FALSE;
-
- /* This one *should* not pend in this state, except
- * if a socket try to connect and immediately
- * disconnect. - clear - Jean II */
- if (self->disconnect_pending)
- irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- else
- ret = (*state[self->state])(self,
- CONNECT_REQUEST,
- NULL, NULL);
- self->disconnect_pending = FALSE;
- }
- /* Note : one way to test if this code works well (including
- * media busy and small busy) is to create a user space
- * application generating an Ultra packet every 3.05 sec (or
- * 2.95 sec) and to see how it interact with discovery.
- * It's fairly easy to check that no packet is lost, that the
- * packets are postponed during discovery and that after
- * discovery indication you have a 100ms "gap".
- * As connection request and Ultra are now processed the same
- * way, this avoid the tedious job of trying IrLAP connection
- * in all those cases...
- * Jean II */
- break;
-#ifdef CONFIG_IRDA_ULTRA
- case SEND_UI_FRAME:
- {
- int i;
- /* Only allowed to repeat an operation twice */
- for (i=0; ((i<2) && (self->media_busy == FALSE)); i++) {
- skb = skb_dequeue(&self->txq_ultra);
- if (skb)
- irlap_send_ui_frame(self, skb, CBROADCAST,
- CMD_FRAME);
- else
- break;
- /* irlap_send_ui_frame() won't increase skb reference
- * count, so no dev_kfree_skb() - Jean II */
- }
- if (i == 2) {
- /* Force us to listen 500 ms again */
- irda_device_set_media_busy(self->netdev, TRUE);
- }
- break;
- }
- case RECV_UI_FRAME:
- /* Only accept broadcast frames in NDM mode */
- if (info->caddr != CBROADCAST) {
- pr_debug("%s(), not a broadcast frame!\n",
- __func__);
- } else
- irlap_unitdata_indication(self, skb);
- break;
-#endif /* CONFIG_IRDA_ULTRA */
- case RECV_TEST_CMD:
- /* Remove test frame header */
- skb_pull(skb, sizeof(struct test_frame));
-
- /*
- * Send response. This skb will not be sent out again, and
- * will only be used to send out the same info as the cmd
- */
- irlap_send_test_frame(self, CBROADCAST, info->daddr, skb);
- break;
- case RECV_TEST_RSP:
- pr_debug("%s() not implemented!\n", __func__);
- break;
- default:
- pr_debug("%s(), Unknown event %s\n", __func__,
- irlap_event[event]);
-
- ret = -1;
- break;
- }
- return ret;
-}
-
-/*
- * Function irlap_state_query (event, skb, info)
- *
- * QUERY state
- *
- */
-static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- int ret = 0;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- switch (event) {
- case RECV_DISCOVERY_XID_RSP:
- IRDA_ASSERT(info != NULL, return -1;);
- IRDA_ASSERT(info->discovery != NULL, return -1;);
-
- pr_debug("%s(), daddr=%08x\n", __func__,
- info->discovery->data.daddr);
-
- if (!self->discovery_log) {
- net_warn_ratelimited("%s: discovery log is gone! maybe the discovery timeout has been set too short?\n",
- __func__);
- break;
- }
- hashbin_insert(self->discovery_log,
- (irda_queue_t *) info->discovery,
- info->discovery->data.daddr, NULL);
-
- /* Keep state */
- /* irlap_next_state(self, LAP_QUERY); */
-
- break;
- case RECV_DISCOVERY_XID_CMD:
- /* Yes, it is possible to receive those frames in this mode.
- * Note that most often the last discovery request won't
- * occur here but in NDM state (see my comment there).
- * What should we do ?
- * Not much. We are currently performing our own discovery,
- * therefore we can't answer those frames. We don't want
- * to change state either. We just pass the info to
- * IrLMP who will put it in the log (and post an event).
- * Jean II
- */
-
- IRDA_ASSERT(info != NULL, return -1;);
-
- pr_debug("%s(), Receiving discovery request (s = %d) while performing discovery :-(\n",
- __func__, info->s);
-
- /* Last discovery request ? */
- if (info->s == 0xff)
- irlap_discovery_indication(self, info->discovery);
- break;
- case SLOT_TIMER_EXPIRED:
- /*
- * Wait a little longer if we detect an incoming frame. This
- * is not mentioned in the spec, but is a good thing to do,
- * since we want to work even with devices that violate the
- * timing requirements.
- */
- if (irda_device_is_receiving(self->netdev) && !self->add_wait) {
- pr_debug("%s(), device is slow to answer, waiting some more!\n",
- __func__);
- irlap_start_slot_timer(self, msecs_to_jiffies(10));
- self->add_wait = TRUE;
- return ret;
- }
- self->add_wait = FALSE;
-
- if (self->s < self->S) {
- irlap_send_discovery_xid_frame(self, self->S,
- self->s, TRUE,
- self->discovery_cmd);
- self->s++;
- irlap_start_slot_timer(self, self->slot_timeout);
-
- /* Keep state */
- irlap_next_state(self, LAP_QUERY);
- } else {
- /* This is the final slot! */
- irlap_send_discovery_xid_frame(self, self->S, 0xff,
- TRUE,
- self->discovery_cmd);
-
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
- /*
- * We are now finished with the discovery procedure,
- * so now we must return the results
- */
- irlap_discovery_confirm(self, self->discovery_log);
-
- /* IrLMP should now have taken care of the log */
- self->discovery_log = NULL;
- }
- break;
- default:
- pr_debug("%s(), Unknown event %s\n", __func__,
- irlap_event[event]);
-
- ret = -1;
- break;
- }
- return ret;
-}
-
-/*
- * Function irlap_state_reply (self, event, skb, info)
- *
- * REPLY, we have received a XID discovery frame from a device and we
- * are waiting for the right time slot to send a response XID frame
- *
- */
-static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- discovery_t *discovery_rsp;
- int ret=0;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- switch (event) {
- case QUERY_TIMER_EXPIRED:
- pr_debug("%s(), QUERY_TIMER_EXPIRED <%ld>\n",
- __func__, jiffies);
- irlap_next_state(self, LAP_NDM);
- break;
- case RECV_DISCOVERY_XID_CMD:
- IRDA_ASSERT(info != NULL, return -1;);
- /* Last frame? */
- if (info->s == 0xff) {
- del_timer(&self->query_timer);
-
- /* info->log.condition = REMOTE; */
-
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
- irlap_discovery_indication(self, info->discovery);
- } else {
- /* If it's our slot, send our reply */
- if ((info->s >= self->slot) && (!self->frame_sent)) {
- discovery_rsp = irlmp_get_discovery_response();
- discovery_rsp->data.daddr = info->daddr;
-
- irlap_send_discovery_xid_frame(self, info->S,
- self->slot,
- FALSE,
- discovery_rsp);
-
- self->frame_sent = TRUE;
- }
- /* Readjust our timer to accommodate devices
- * doing faster or slower discovery than us...
- * Jean II */
- irlap_start_query_timer(self, info->S, info->s);
-
- /* Keep state */
- //irlap_next_state(self, LAP_REPLY);
- }
- break;
- default:
- pr_debug("%s(), Unknown event %d, %s\n", __func__,
- event, irlap_event[event]);
-
- ret = -1;
- break;
- }
- return ret;
-}
-
-/*
- * Function irlap_state_conn (event, skb, info)
- *
- * CONN, we have received a SNRM command and is waiting for the upper
- * layer to accept or refuse connection
- *
- */
-static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- int ret = 0;
-
- pr_debug("%s(), event=%s\n", __func__, irlap_event[event]);
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- switch (event) {
- case CONNECT_RESPONSE:
- skb_pull(skb, sizeof(struct snrm_frame));
-
- IRDA_ASSERT(self->netdev != NULL, return -1;);
-
- irlap_qos_negotiate(self, skb);
-
- irlap_initiate_connection_state(self);
-
- /*
- * Applying the parameters now will make sure we change speed
- * *after* we have sent the next frame
- */
- irlap_apply_connection_parameters(self, FALSE);
-
- /*
- * Sending this frame will force a speed change after it has
- * been sent (i.e. the frame will be sent at 9600).
- */
- irlap_send_ua_response_frame(self, &self->qos_rx);
-
-#if 0
- /*
- * We are allowed to send two frames, but this may increase
- * the connect latency, so lets not do it for now.
- */
- /* This is full of good intentions, but doesn't work in
- * practice.
- * After sending the first UA response, we switch the
- * dongle to the negotiated speed, which is usually
- * different than 9600 kb/s.
- * From there, there is two solutions :
- * 1) The other end has received the first UA response :
- * it will set up the connection, move to state LAP_NRM_P,
- * and will ignore and drop the second UA response.
- * Actually, it's even worse : the other side will almost
- * immediately send a RR that will likely collide with the
- * UA response (depending on negotiated turnaround).
- * 2) The other end has not received the first UA response,
- * will stay at 9600 and will never see the second UA response.
- * Jean II */
- irlap_send_ua_response_frame(self, &self->qos_rx);
-#endif
-
- /*
- * The WD-timer could be set to the duration of the P-timer
- * for this case, but it is recommended to use twice the
- * value (note 3 IrLAP p. 60).
- */
- irlap_start_wd_timer(self, self->wd_timeout);
- irlap_next_state(self, LAP_NRM_S);
-
- break;
- case RECV_DISCOVERY_XID_CMD:
- pr_debug("%s(), event RECV_DISCOVER_XID_CMD!\n",
- __func__);
- irlap_next_state(self, LAP_NDM);
-
- break;
- case DISCONNECT_REQUEST:
- pr_debug("%s(), Disconnect request!\n", __func__);
- irlap_send_dm_frame(self);
- irlap_next_state( self, LAP_NDM);
- irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- break;
- default:
- pr_debug("%s(), Unknown event %d, %s\n", __func__,
- event, irlap_event[event]);
-
- ret = -1;
- break;
- }
-
- return ret;
-}
-
-/*
- * Function irlap_state_setup (event, skb, frame)
- *
- * SETUP state, The local layer has transmitted a SNRM command frame to
- * a remote peer layer and is awaiting a reply .
- *
- */
-static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- int ret = 0;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- switch (event) {
- case FINAL_TIMER_EXPIRED:
- if (self->retry_count < self->N3) {
-/*
- * Perform random backoff, Wait a random number of time units, minimum
- * duration half the time taken to transmitt a SNRM frame, maximum duration
- * 1.5 times the time taken to transmit a SNRM frame. So this time should
- * between 15 msecs and 45 msecs.
- */
- irlap_start_backoff_timer(self, msecs_to_jiffies(20 +
- (jiffies % 30)));
- } else {
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
- irlap_disconnect_indication(self, LAP_FOUND_NONE);
- }
- break;
- case BACKOFF_TIMER_EXPIRED:
- irlap_send_snrm_frame(self, &self->qos_rx);
- irlap_start_final_timer(self, self->final_timeout);
- self->retry_count++;
- break;
- case RECV_SNRM_CMD:
- pr_debug("%s(), SNRM battle!\n", __func__);
-
- IRDA_ASSERT(skb != NULL, return 0;);
- IRDA_ASSERT(info != NULL, return 0;);
-
- /*
- * The device with the largest device address wins the battle
- * (both have sent a SNRM command!)
- */
- if (info &&(info->daddr > self->saddr)) {
- del_timer(&self->final_timer);
- irlap_initiate_connection_state(self);
-
- IRDA_ASSERT(self->netdev != NULL, return -1;);
-
- skb_pull(skb, sizeof(struct snrm_frame));
-
- irlap_qos_negotiate(self, skb);
-
- /* Send UA frame and then change link settings */
- irlap_apply_connection_parameters(self, FALSE);
- irlap_send_ua_response_frame(self, &self->qos_rx);
-
- irlap_next_state(self, LAP_NRM_S);
- irlap_connect_confirm(self, skb);
-
- /*
- * The WD-timer could be set to the duration of the
- * P-timer for this case, but it is recommended
- * to use twice the value (note 3 IrLAP p. 60).
- */
- irlap_start_wd_timer(self, self->wd_timeout);
- } else {
- /* We just ignore the other device! */
- irlap_next_state(self, LAP_SETUP);
- }
- break;
- case RECV_UA_RSP:
- /* Stop F-timer */
- del_timer(&self->final_timer);
-
- /* Initiate connection state */
- irlap_initiate_connection_state(self);
-
- /* Negotiate connection parameters */
- IRDA_ASSERT(skb->len > 10, return -1;);
-
- skb_pull(skb, sizeof(struct ua_frame));
-
- IRDA_ASSERT(self->netdev != NULL, return -1;);
-
- irlap_qos_negotiate(self, skb);
-
- /* Set the new link setting *now* (before the rr frame) */
- irlap_apply_connection_parameters(self, TRUE);
- self->retry_count = 0;
-
- /* Wait for turnaround time to give a chance to the other
- * device to be ready to receive us.
- * Note : the time to switch speed is typically larger
- * than the turnaround time, but as we don't have the other
- * side speed switch time, that's our best guess...
- * Jean II */
- irlap_wait_min_turn_around(self, &self->qos_tx);
-
- /* This frame will actually be sent at the new speed */
- irlap_send_rr_frame(self, CMD_FRAME);
-
- /* The timer is set to half the normal timer to quickly
- * detect a failure to negotiate the new connection
- * parameters. IrLAP 6.11.3.2, note 3.
- * Note that currently we don't process this failure
- * properly, as we should do a quick disconnect.
- * Jean II */
- irlap_start_final_timer(self, self->final_timeout/2);
- irlap_next_state(self, LAP_NRM_P);
-
- irlap_connect_confirm(self, skb);
- break;
- case RECV_DM_RSP: /* FALLTHROUGH */
- case RECV_DISC_CMD:
- del_timer(&self->final_timer);
- irlap_next_state(self, LAP_NDM);
-
- irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- break;
- default:
- pr_debug("%s(), Unknown event %d, %s\n", __func__,
- event, irlap_event[event]);
-
- ret = -1;
- break;
- }
- return ret;
-}
-
-/*
- * Function irlap_state_offline (self, event, skb, info)
- *
- * OFFLINE state, not used for now!
- *
- */
-static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- pr_debug("%s(), Unknown event\n", __func__);
-
- return -1;
-}
-
-/*
- * Function irlap_state_xmit_p (self, event, skb, info)
- *
- * XMIT, Only the primary station has right to transmit, and we
- * therefore do not expect to receive any transmissions from other
- * stations.
- *
- */
-static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- int ret = 0;
-
- switch (event) {
- case SEND_I_CMD:
- /*
- * Only send frame if send-window > 0.
- */
- if ((self->window > 0) && (!self->remote_busy)) {
- int nextfit;
-#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
- struct sk_buff *skb_next;
-
- /* With DYNAMIC_WINDOW, we keep the window size
- * maximum, and adapt on the packets we are sending.
- * At 115k, we can send only 2 packets of 2048 bytes
- * in a 500 ms turnaround. Without this option, we
- * would always limit the window to 2. With this
- * option, if we send smaller packets, we can send
- * up to 7 of them (always depending on QoS).
- * Jean II */
-
- /* Look at the next skb. This is safe, as we are
- * the only consumer of the Tx queue (if we are not,
- * we have other problems) - Jean II */
- skb_next = skb_peek(&self->txq);
-
- /* Check if a subsequent skb exist and would fit in
- * the current window (with respect to turnaround
- * time).
- * This allow us to properly mark the current packet
- * with the pf bit, to avoid falling back on the
- * second test below, and avoid waiting the
- * end of the window and sending a extra RR.
- * Note : (skb_next != NULL) <=> (skb_queue_len() > 0)
- * Jean II */
- nextfit = ((skb_next != NULL) &&
- ((skb_next->len + skb->len) <=
- self->bytes_left));
-
- /*
- * The current packet may not fit ! Because of test
- * above, this should not happen any more !!!
- * Test if we have transmitted more bytes over the
- * link than its possible to do with the current
- * speed and turn-around-time.
- */
- if((!nextfit) && (skb->len > self->bytes_left)) {
- pr_debug("%s(), Not allowed to transmit more bytes!\n",
- __func__);
- /* Requeue the skb */
- skb_queue_head(&self->txq, skb_get(skb));
- /*
- * We should switch state to LAP_NRM_P, but
- * that is not possible since we must be sure
- * that we poll the other side. Since we have
- * used up our time, the poll timer should
- * trigger anyway now, so we just wait for it
- * DB
- */
- /*
- * Sorry, but that's not totally true. If
- * we send 2000B packets, we may wait another
- * 1000B until our turnaround expire. That's
- * why we need to be proactive in avoiding
- * coming here. - Jean II
- */
- return -EPROTO;
- }
-
- /* Subtract space used by this skb */
- self->bytes_left -= skb->len;
-#else /* CONFIG_IRDA_DYNAMIC_WINDOW */
- /* Window has been adjusted for the max packet
- * size, so much simpler... - Jean II */
- nextfit = !skb_queue_empty(&self->txq);
-#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
- /*
- * Send data with poll bit cleared only if window > 1
- * and there is more frames after this one to be sent
- */
- if ((self->window > 1) && (nextfit)) {
- /* More packet to send in current window */
- irlap_send_data_primary(self, skb);
- irlap_next_state(self, LAP_XMIT_P);
- } else {
- /* Final packet of window */
- irlap_send_data_primary_poll(self, skb);
-
- /*
- * Make sure state machine does not try to send
- * any more frames
- */
- ret = -EPROTO;
- }
-#ifdef CONFIG_IRDA_FAST_RR
- /* Peer may want to reply immediately */
- self->fast_RR = FALSE;
-#endif /* CONFIG_IRDA_FAST_RR */
- } else {
- pr_debug("%s(), Unable to send! remote busy?\n",
- __func__);
- skb_queue_head(&self->txq, skb_get(skb));
-
- /*
- * The next ret is important, because it tells
- * irlap_next_state _not_ to deliver more frames
- */
- ret = -EPROTO;
- }
- break;
- case POLL_TIMER_EXPIRED:
- pr_debug("%s(), POLL_TIMER_EXPIRED <%ld>\n",
- __func__, jiffies);
- irlap_send_rr_frame(self, CMD_FRAME);
- /* Return to NRM properly - Jean II */
- self->window = self->window_size;
-#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
- /* Allowed to transmit a maximum number of bytes again. */
- self->bytes_left = self->line_capacity;
-#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
- irlap_start_final_timer(self, self->final_timeout);
- irlap_next_state(self, LAP_NRM_P);
- break;
- case DISCONNECT_REQUEST:
- del_timer(&self->poll_timer);
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_disc_frame(self);
- irlap_flush_all_queues(self);
- irlap_start_final_timer(self, self->final_timeout);
- self->retry_count = 0;
- irlap_next_state(self, LAP_PCLOSE);
- break;
- case DATA_REQUEST:
- /* Nothing to do, irlap_do_event() will send the packet
- * when we return... - Jean II */
- break;
- default:
- pr_debug("%s(), Unknown event %s\n",
- __func__, irlap_event[event]);
-
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-/*
- * Function irlap_state_pclose (event, skb, info)
- *
- * PCLOSE state
- */
-static int irlap_state_pclose(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- int ret = 0;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- switch (event) {
- case RECV_UA_RSP: /* FALLTHROUGH */
- case RECV_DM_RSP:
- del_timer(&self->final_timer);
-
- /* Set new link parameters */
- irlap_apply_default_connection_parameters(self);
-
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
- irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- break;
- case FINAL_TIMER_EXPIRED:
- if (self->retry_count < self->N3) {
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_disc_frame(self);
- irlap_start_final_timer(self, self->final_timeout);
- self->retry_count++;
- /* Keep state */
- } else {
- irlap_apply_default_connection_parameters(self);
-
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
- irlap_disconnect_indication(self, LAP_NO_RESPONSE);
- }
- break;
- default:
- pr_debug("%s(), Unknown event %d\n", __func__, event);
-
- ret = -1;
- break;
- }
- return ret;
-}
-
-/*
- * Function irlap_state_nrm_p (self, event, skb, info)
- *
- * NRM_P (Normal Response Mode as Primary), The primary station has given
- * permissions to a secondary station to transmit IrLAP resonse frames
- * (by sending a frame with the P bit set). The primary station will not
- * transmit any frames and is expecting to receive frames only from the
- * secondary to which transmission permissions has been given.
- */
-static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- int ret = 0;
- int ns_status;
- int nr_status;
-
- switch (event) {
- case RECV_I_RSP: /* Optimize for the common case */
- if (unlikely(skb->len <= LAP_ADDR_HEADER + LAP_CTRL_HEADER)) {
- /*
- * Input validation check: a stir4200/mcp2150
- * combination sometimes results in an empty i:rsp.
- * This makes no sense; we can just ignore the frame
- * and send an rr:cmd immediately. This happens before
- * changing nr or ns so triggers a retransmit
- */
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_rr_frame(self, CMD_FRAME);
- /* Keep state */
- break;
- }
- /* FIXME: must check for remote_busy below */
-#ifdef CONFIG_IRDA_FAST_RR
- /*
- * Reset the fast_RR so we can use the fast RR code with
- * full speed the next time since peer may have more frames
- * to transmitt
- */
- self->fast_RR = FALSE;
-#endif /* CONFIG_IRDA_FAST_RR */
- IRDA_ASSERT( info != NULL, return -1;);
-
- ns_status = irlap_validate_ns_received(self, info->ns);
- nr_status = irlap_validate_nr_received(self, info->nr);
-
- /*
- * Check for expected I(nformation) frame
- */
- if ((ns_status == NS_EXPECTED) && (nr_status == NR_EXPECTED)) {
-
- /* Update Vr (next frame for us to receive) */
- self->vr = (self->vr + 1) % 8;
-
- /* Update Nr received, cleanup our retry queue */
- irlap_update_nr_received(self, info->nr);
-
- /*
- * Got expected NR, so reset the
- * retry_count. This is not done by IrLAP spec,
- * which is strange!
- */
- self->retry_count = 0;
- self->ack_required = TRUE;
-
- /* poll bit cleared? */
- if (!info->pf) {
- /* Keep state, do not move this line */
- irlap_next_state(self, LAP_NRM_P);
-
- irlap_data_indication(self, skb, FALSE);
- } else {
- /* No longer waiting for pf */
- del_timer(&self->final_timer);
-
- irlap_wait_min_turn_around(self, &self->qos_tx);
-
- /* Call higher layer *before* changing state
- * to give them a chance to send data in the
- * next LAP frame.
- * Jean II */
- irlap_data_indication(self, skb, FALSE);
-
- /* XMIT states are the most dangerous state
- * to be in, because user requests are
- * processed directly and may change state.
- * On the other hand, in NDM_P, those
- * requests are queued and we will process
- * them when we return to irlap_do_event().
- * Jean II
- */
- irlap_next_state(self, LAP_XMIT_P);
-
- /* This is the last frame.
- * Make sure it's always called in XMIT state.
- * - Jean II */
- irlap_start_poll_timer(self, self->poll_timeout);
- }
- break;
-
- }
- /* Unexpected next to send (Ns) */
- if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED))
- {
- if (!info->pf) {
- irlap_update_nr_received(self, info->nr);
-
- /*
- * Wait until the last frame before doing
- * anything
- */
-
- /* Keep state */
- irlap_next_state(self, LAP_NRM_P);
- } else {
- pr_debug("%s(), missing or duplicate frame!\n",
- __func__);
-
- /* Update Nr received */
- irlap_update_nr_received(self, info->nr);
-
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_rr_frame(self, CMD_FRAME);
-
- self->ack_required = FALSE;
-
- irlap_start_final_timer(self, self->final_timeout);
- irlap_next_state(self, LAP_NRM_P);
- }
- break;
- }
- /*
- * Unexpected next to receive (Nr)
- */
- if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED))
- {
- if (info->pf) {
- self->vr = (self->vr + 1) % 8;
-
- /* Update Nr received */
- irlap_update_nr_received(self, info->nr);
-
- /* Resend rejected frames */
- irlap_resend_rejected_frames(self, CMD_FRAME);
-
- self->ack_required = FALSE;
-
- /* Make sure we account for the time
- * to transmit our frames. See comemnts
- * in irlap_send_data_primary_poll().
- * Jean II */
- irlap_start_final_timer(self, 2 * self->final_timeout);
-
- /* Keep state, do not move this line */
- irlap_next_state(self, LAP_NRM_P);
-
- irlap_data_indication(self, skb, FALSE);
- } else {
- /*
- * Do not resend frames until the last
- * frame has arrived from the other
- * device. This is not documented in
- * IrLAP!!
- */
- self->vr = (self->vr + 1) % 8;
-
- /* Update Nr received */
- irlap_update_nr_received(self, info->nr);
-
- self->ack_required = FALSE;
-
- /* Keep state, do not move this line!*/
- irlap_next_state(self, LAP_NRM_P);
-
- irlap_data_indication(self, skb, FALSE);
- }
- break;
- }
- /*
- * Unexpected next to send (Ns) and next to receive (Nr)
- * Not documented by IrLAP!
- */
- if ((ns_status == NS_UNEXPECTED) &&
- (nr_status == NR_UNEXPECTED))
- {
- pr_debug("%s(), unexpected nr and ns!\n",
- __func__);
- if (info->pf) {
- /* Resend rejected frames */
- irlap_resend_rejected_frames(self, CMD_FRAME);
-
- /* Give peer some time to retransmit!
- * But account for our own Tx. */
- irlap_start_final_timer(self, 2 * self->final_timeout);
-
- /* Keep state, do not move this line */
- irlap_next_state(self, LAP_NRM_P);
- } else {
- /* Update Nr received */
- /* irlap_update_nr_received( info->nr); */
-
- self->ack_required = FALSE;
- }
- break;
- }
-
- /*
- * Invalid NR or NS
- */
- if ((nr_status == NR_INVALID) || (ns_status == NS_INVALID)) {
- if (info->pf) {
- del_timer(&self->final_timer);
-
- irlap_next_state(self, LAP_RESET_WAIT);
-
- irlap_disconnect_indication(self, LAP_RESET_INDICATION);
- self->xmitflag = TRUE;
- } else {
- del_timer(&self->final_timer);
-
- irlap_disconnect_indication(self, LAP_RESET_INDICATION);
-
- self->xmitflag = FALSE;
- }
- break;
- }
- pr_debug("%s(), Not implemented!\n", __func__);
- pr_debug("%s(), event=%s, ns_status=%d, nr_status=%d\n",
- __func__, irlap_event[event], ns_status, nr_status);
- break;
- case RECV_UI_FRAME:
- /* Poll bit cleared? */
- if (!info->pf) {
- irlap_data_indication(self, skb, TRUE);
- irlap_next_state(self, LAP_NRM_P);
- } else {
- del_timer(&self->final_timer);
- irlap_data_indication(self, skb, TRUE);
- irlap_next_state(self, LAP_XMIT_P);
- pr_debug("%s: RECV_UI_FRAME: next state %s\n",
- __func__, irlap_state[self->state]);
- irlap_start_poll_timer(self, self->poll_timeout);
- }
- break;
- case RECV_RR_RSP:
- /*
- * If you get a RR, the remote isn't busy anymore,
- * no matter what the NR
- */
- self->remote_busy = FALSE;
-
- /* Stop final timer */
- del_timer(&self->final_timer);
-
- /*
- * Nr as expected?
- */
- ret = irlap_validate_nr_received(self, info->nr);
- if (ret == NR_EXPECTED) {
- /* Update Nr received */
- irlap_update_nr_received(self, info->nr);
-
- /*
- * Got expected NR, so reset the retry_count. This
- * is not done by the IrLAP standard , which is
- * strange! DB.
- */
- self->retry_count = 0;
- irlap_wait_min_turn_around(self, &self->qos_tx);
-
- irlap_next_state(self, LAP_XMIT_P);
-
- /* Start poll timer */
- irlap_start_poll_timer(self, self->poll_timeout);
- } else if (ret == NR_UNEXPECTED) {
- IRDA_ASSERT(info != NULL, return -1;);
- /*
- * Unexpected nr!
- */
-
- /* Update Nr received */
- irlap_update_nr_received(self, info->nr);
-
- pr_debug("RECV_RR_FRAME: Retrans:%d, nr=%d, va=%d, vs=%d, vr=%d\n",
- self->retry_count, info->nr, self->va,
- self->vs, self->vr);
-
- /* Resend rejected frames */
- irlap_resend_rejected_frames(self, CMD_FRAME);
- irlap_start_final_timer(self, self->final_timeout * 2);
-
- irlap_next_state(self, LAP_NRM_P);
- } else if (ret == NR_INVALID) {
- pr_debug("%s(), Received RR with invalid nr !\n",
- __func__);
-
- irlap_next_state(self, LAP_RESET_WAIT);
-
- irlap_disconnect_indication(self, LAP_RESET_INDICATION);
- self->xmitflag = TRUE;
- }
- break;
- case RECV_RNR_RSP:
- IRDA_ASSERT(info != NULL, return -1;);
-
- /* Stop final timer */
- del_timer(&self->final_timer);
- self->remote_busy = TRUE;
-
- /* Update Nr received */
- irlap_update_nr_received(self, info->nr);
- irlap_next_state(self, LAP_XMIT_P);
-
- /* Start poll timer */
- irlap_start_poll_timer(self, self->poll_timeout);
- break;
- case RECV_FRMR_RSP:
- del_timer(&self->final_timer);
- self->xmitflag = TRUE;
- irlap_next_state(self, LAP_RESET_WAIT);
- irlap_reset_indication(self);
- break;
- case FINAL_TIMER_EXPIRED:
- /*
- * We are allowed to wait for additional 300 ms if
- * final timer expires when we are in the middle
- * of receiving a frame (page 45, IrLAP). Check that
- * we only do this once for each frame.
- */
- if (irda_device_is_receiving(self->netdev) && !self->add_wait) {
- pr_debug("FINAL_TIMER_EXPIRED when receiving a frame! Waiting a little bit more!\n");
- irlap_start_final_timer(self, msecs_to_jiffies(300));
-
- /*
- * Don't allow this to happen one more time in a row,
- * or else we can get a pretty tight loop here if
- * if we only receive half a frame. DB.
- */
- self->add_wait = TRUE;
- break;
- }
- self->add_wait = FALSE;
-
- /* N2 is the disconnect timer. Until we reach it, we retry */
- if (self->retry_count < self->N2) {
- if (skb_peek(&self->wx_list) == NULL) {
- /* Retry sending the pf bit to the secondary */
- pr_debug("nrm_p: resending rr");
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_rr_frame(self, CMD_FRAME);
- } else {
- pr_debug("nrm_p: resend frames");
- irlap_resend_rejected_frames(self, CMD_FRAME);
- }
-
- irlap_start_final_timer(self, self->final_timeout);
- self->retry_count++;
- pr_debug("irlap_state_nrm_p: FINAL_TIMER_EXPIRED: retry_count=%d\n",
- self->retry_count);
-
- /* Early warning event. I'm using a pretty liberal
- * interpretation of the spec and generate an event
- * every time the timer is multiple of N1 (and not
- * only the first time). This allow application
- * to know precisely if connectivity restart...
- * Jean II */
- if((self->retry_count % self->N1) == 0)
- irlap_status_indication(self,
- STATUS_NO_ACTIVITY);
-
- /* Keep state */
- } else {
- irlap_apply_default_connection_parameters(self);
-
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
- irlap_disconnect_indication(self, LAP_NO_RESPONSE);
- }
- break;
- case RECV_REJ_RSP:
- irlap_update_nr_received(self, info->nr);
- if (self->remote_busy) {
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_rr_frame(self, CMD_FRAME);
- } else
- irlap_resend_rejected_frames(self, CMD_FRAME);
- irlap_start_final_timer(self, 2 * self->final_timeout);
- break;
- case RECV_SREJ_RSP:
- irlap_update_nr_received(self, info->nr);
- if (self->remote_busy) {
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_rr_frame(self, CMD_FRAME);
- } else
- irlap_resend_rejected_frame(self, CMD_FRAME);
- irlap_start_final_timer(self, 2 * self->final_timeout);
- break;
- case RECV_RD_RSP:
- pr_debug("%s(), RECV_RD_RSP\n", __func__);
-
- irlap_flush_all_queues(self);
- irlap_next_state(self, LAP_XMIT_P);
- /* Call back the LAP state machine to do a proper disconnect */
- irlap_disconnect_request(self);
- break;
- default:
- pr_debug("%s(), Unknown event %s\n",
- __func__, irlap_event[event]);
-
- ret = -1;
- break;
- }
- return ret;
-}
-
-/*
- * Function irlap_state_reset_wait (event, skb, info)
- *
- * We have informed the service user of a reset condition, and is
- * awaiting reset of disconnect request.
- *
- */
-static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- int ret = 0;
-
- pr_debug("%s(), event = %s\n", __func__, irlap_event[event]);
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- switch (event) {
- case RESET_REQUEST:
- if (self->xmitflag) {
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_snrm_frame(self, NULL);
- irlap_start_final_timer(self, self->final_timeout);
- irlap_next_state(self, LAP_RESET);
- } else {
- irlap_start_final_timer(self, self->final_timeout);
- irlap_next_state(self, LAP_RESET);
- }
- break;
- case DISCONNECT_REQUEST:
- irlap_wait_min_turn_around( self, &self->qos_tx);
- irlap_send_disc_frame( self);
- irlap_flush_all_queues( self);
- irlap_start_final_timer( self, self->final_timeout);
- self->retry_count = 0;
- irlap_next_state( self, LAP_PCLOSE);
- break;
- default:
- pr_debug("%s(), Unknown event %s\n", __func__,
- irlap_event[event]);
-
- ret = -1;
- break;
- }
- return ret;
-}
-
-/*
- * Function irlap_state_reset (self, event, skb, info)
- *
- * We have sent a SNRM reset command to the peer layer, and is awaiting
- * reply.
- *
- */
-static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- int ret = 0;
-
- pr_debug("%s(), event = %s\n", __func__, irlap_event[event]);
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- switch (event) {
- case RECV_DISC_CMD:
- del_timer(&self->final_timer);
-
- irlap_apply_default_connection_parameters(self);
-
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
- irlap_disconnect_indication(self, LAP_NO_RESPONSE);
-
- break;
- case RECV_UA_RSP:
- del_timer(&self->final_timer);
-
- /* Initiate connection state */
- irlap_initiate_connection_state(self);
-
- irlap_reset_confirm();
-
- self->remote_busy = FALSE;
-
- irlap_next_state(self, LAP_XMIT_P);
-
- irlap_start_poll_timer(self, self->poll_timeout);
-
- break;
- case FINAL_TIMER_EXPIRED:
- if (self->retry_count < 3) {
- irlap_wait_min_turn_around(self, &self->qos_tx);
-
- IRDA_ASSERT(self->netdev != NULL, return -1;);
- irlap_send_snrm_frame(self, self->qos_dev);
-
- self->retry_count++; /* Experimental!! */
-
- irlap_start_final_timer(self, self->final_timeout);
- irlap_next_state(self, LAP_RESET);
- } else if (self->retry_count >= self->N3) {
- irlap_apply_default_connection_parameters(self);
-
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
- irlap_disconnect_indication(self, LAP_NO_RESPONSE);
- }
- break;
- case RECV_SNRM_CMD:
- /*
- * SNRM frame is not allowed to contain an I-field in this
- * state
- */
- if (!info) {
- pr_debug("%s(), RECV_SNRM_CMD\n", __func__);
- irlap_initiate_connection_state(self);
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_ua_response_frame(self, &self->qos_rx);
- irlap_reset_confirm();
- irlap_start_wd_timer(self, self->wd_timeout);
- irlap_next_state(self, LAP_NDM);
- } else {
- pr_debug("%s(), SNRM frame contained an I field!\n",
- __func__);
- }
- break;
- default:
- pr_debug("%s(), Unknown event %s\n",
- __func__, irlap_event[event]);
-
- ret = -1;
- break;
- }
- return ret;
-}
-
-/*
- * Function irlap_state_xmit_s (event, skb, info)
- *
- * XMIT_S, The secondary station has been given the right to transmit,
- * and we therefore do not expect to receive any transmissions from other
- * stations.
- */
-static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- int ret = 0;
-
- pr_debug("%s(), event=%s\n", __func__, irlap_event[event]);
-
- IRDA_ASSERT(self != NULL, return -ENODEV;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
-
- switch (event) {
- case SEND_I_CMD:
- /*
- * Send frame only if send window > 0
- */
- if ((self->window > 0) && (!self->remote_busy)) {
- int nextfit;
-#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
- struct sk_buff *skb_next;
-
- /*
- * Same deal as in irlap_state_xmit_p(), so see
- * the comments at that point.
- * We are the secondary, so there are only subtle
- * differences. - Jean II
- */
-
- /* Check if a subsequent skb exist and would fit in
- * the current window (with respect to turnaround
- * time). - Jean II */
- skb_next = skb_peek(&self->txq);
- nextfit = ((skb_next != NULL) &&
- ((skb_next->len + skb->len) <=
- self->bytes_left));
-
- /*
- * Test if we have transmitted more bytes over the
- * link than its possible to do with the current
- * speed and turn-around-time.
- */
- if((!nextfit) && (skb->len > self->bytes_left)) {
- pr_debug("%s(), Not allowed to transmit more bytes!\n",
- __func__);
- /* Requeue the skb */
- skb_queue_head(&self->txq, skb_get(skb));
-
- /*
- * Switch to NRM_S, this is only possible
- * when we are in secondary mode, since we
- * must be sure that we don't miss any RR
- * frames
- */
- self->window = self->window_size;
- self->bytes_left = self->line_capacity;
- irlap_start_wd_timer(self, self->wd_timeout);
-
- irlap_next_state(self, LAP_NRM_S);
- /* Slight difference with primary :
- * here we would wait for the other side to
- * expire the turnaround. - Jean II */
-
- return -EPROTO; /* Try again later */
- }
- /* Subtract space used by this skb */
- self->bytes_left -= skb->len;
-#else /* CONFIG_IRDA_DYNAMIC_WINDOW */
- /* Window has been adjusted for the max packet
- * size, so much simpler... - Jean II */
- nextfit = !skb_queue_empty(&self->txq);
-#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
- /*
- * Send data with final bit cleared only if window > 1
- * and there is more frames to be sent
- */
- if ((self->window > 1) && (nextfit)) {
- irlap_send_data_secondary(self, skb);
- irlap_next_state(self, LAP_XMIT_S);
- } else {
- irlap_send_data_secondary_final(self, skb);
- irlap_next_state(self, LAP_NRM_S);
-
- /*
- * Make sure state machine does not try to send
- * any more frames
- */
- ret = -EPROTO;
- }
- } else {
- pr_debug("%s(), Unable to send!\n", __func__);
- skb_queue_head(&self->txq, skb_get(skb));
- ret = -EPROTO;
- }
- break;
- case DISCONNECT_REQUEST:
- irlap_send_rd_frame(self);
- irlap_flush_all_queues(self);
- irlap_start_wd_timer(self, self->wd_timeout);
- irlap_next_state(self, LAP_SCLOSE);
- break;
- case DATA_REQUEST:
- /* Nothing to do, irlap_do_event() will send the packet
- * when we return... - Jean II */
- break;
- default:
- pr_debug("%s(), Unknown event %s\n", __func__,
- irlap_event[event]);
-
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-/*
- * Function irlap_state_nrm_s (event, skb, info)
- *
- * NRM_S (Normal Response Mode as Secondary) state, in this state we are
- * expecting to receive frames from the primary station
- *
- */
-static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- int ns_status;
- int nr_status;
- int ret = 0;
-
- pr_debug("%s(), event=%s\n", __func__, irlap_event[event]);
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- switch (event) {
- case RECV_I_CMD: /* Optimize for the common case */
- /* FIXME: must check for remote_busy below */
- pr_debug("%s(), event=%s nr=%d, vs=%d, ns=%d, vr=%d, pf=%d\n",
- __func__, irlap_event[event], info->nr,
- self->vs, info->ns, self->vr, info->pf);
-
- self->retry_count = 0;
-
- ns_status = irlap_validate_ns_received(self, info->ns);
- nr_status = irlap_validate_nr_received(self, info->nr);
- /*
- * Check for expected I(nformation) frame
- */
- if ((ns_status == NS_EXPECTED) && (nr_status == NR_EXPECTED)) {
-
- /* Update Vr (next frame for us to receive) */
- self->vr = (self->vr + 1) % 8;
-
- /* Update Nr received */
- irlap_update_nr_received(self, info->nr);
-
- /*
- * poll bit cleared?
- */
- if (!info->pf) {
-
- self->ack_required = TRUE;
-
- /*
- * Starting WD-timer here is optional, but
- * not recommended. Note 6 IrLAP p. 83
- */
-#if 0
- irda_start_timer(WD_TIMER, self->wd_timeout);
-#endif
- /* Keep state, do not move this line */
- irlap_next_state(self, LAP_NRM_S);
-
- irlap_data_indication(self, skb, FALSE);
- break;
- } else {
- /*
- * We should wait before sending RR, and
- * also before changing to XMIT_S
- * state. (note 1, IrLAP p. 82)
- */
- irlap_wait_min_turn_around(self, &self->qos_tx);
-
- /*
- * Give higher layers a chance to
- * immediately reply with some data before
- * we decide if we should send a RR frame
- * or not
- */
- irlap_data_indication(self, skb, FALSE);
-
- /* Any pending data requests? */
- if (!skb_queue_empty(&self->txq) &&
- (self->window > 0))
- {
- self->ack_required = TRUE;
-
- del_timer(&self->wd_timer);
-
- irlap_next_state(self, LAP_XMIT_S);
- } else {
- irlap_send_rr_frame(self, RSP_FRAME);
- irlap_start_wd_timer(self,
- self->wd_timeout);
-
- /* Keep the state */
- irlap_next_state(self, LAP_NRM_S);
- }
- break;
- }
- }
- /*
- * Check for Unexpected next to send (Ns)
- */
- if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED))
- {
- /* Unexpected next to send, with final bit cleared */
- if (!info->pf) {
- irlap_update_nr_received(self, info->nr);
-
- irlap_start_wd_timer(self, self->wd_timeout);
- } else {
- /* Update Nr received */
- irlap_update_nr_received(self, info->nr);
-
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_rr_frame(self, RSP_FRAME);
-
- irlap_start_wd_timer(self, self->wd_timeout);
- }
- break;
- }
-
- /*
- * Unexpected Next to Receive(NR) ?
- */
- if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED))
- {
- if (info->pf) {
- pr_debug("RECV_I_RSP: frame(s) lost\n");
-
- self->vr = (self->vr + 1) % 8;
-
- /* Update Nr received */
- irlap_update_nr_received(self, info->nr);
-
- /* Resend rejected frames */
- irlap_resend_rejected_frames(self, RSP_FRAME);
-
- /* Keep state, do not move this line */
- irlap_next_state(self, LAP_NRM_S);
-
- irlap_data_indication(self, skb, FALSE);
- irlap_start_wd_timer(self, self->wd_timeout);
- break;
- }
- /*
- * This is not documented in IrLAP!! Unexpected NR
- * with poll bit cleared
- */
- if (!info->pf) {
- self->vr = (self->vr + 1) % 8;
-
- /* Update Nr received */
- irlap_update_nr_received(self, info->nr);
-
- /* Keep state, do not move this line */
- irlap_next_state(self, LAP_NRM_S);
-
- irlap_data_indication(self, skb, FALSE);
- irlap_start_wd_timer(self, self->wd_timeout);
- }
- break;
- }
-
- if (ret == NR_INVALID) {
- pr_debug("NRM_S, NR_INVALID not implemented!\n");
- }
- if (ret == NS_INVALID) {
- pr_debug("NRM_S, NS_INVALID not implemented!\n");
- }
- break;
- case RECV_UI_FRAME:
- /*
- * poll bit cleared?
- */
- if (!info->pf) {
- irlap_data_indication(self, skb, TRUE);
- irlap_next_state(self, LAP_NRM_S); /* Keep state */
- } else {
- /*
- * Any pending data requests?
- */
- if (!skb_queue_empty(&self->txq) &&
- (self->window > 0) && !self->remote_busy)
- {
- irlap_data_indication(self, skb, TRUE);
-
- del_timer(&self->wd_timer);
-
- irlap_next_state(self, LAP_XMIT_S);
- } else {
- irlap_data_indication(self, skb, TRUE);
-
- irlap_wait_min_turn_around(self, &self->qos_tx);
-
- irlap_send_rr_frame(self, RSP_FRAME);
- self->ack_required = FALSE;
-
- irlap_start_wd_timer(self, self->wd_timeout);
-
- /* Keep the state */
- irlap_next_state(self, LAP_NRM_S);
- }
- }
- break;
- case RECV_RR_CMD:
- self->retry_count = 0;
-
- /*
- * Nr as expected?
- */
- nr_status = irlap_validate_nr_received(self, info->nr);
- if (nr_status == NR_EXPECTED) {
- if (!skb_queue_empty(&self->txq) &&
- (self->window > 0)) {
- self->remote_busy = FALSE;
-
- /* Update Nr received */
- irlap_update_nr_received(self, info->nr);
- del_timer(&self->wd_timer);
-
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_next_state(self, LAP_XMIT_S);
- } else {
- self->remote_busy = FALSE;
- /* Update Nr received */
- irlap_update_nr_received(self, info->nr);
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_start_wd_timer(self, self->wd_timeout);
-
- /* Note : if the link is idle (this case),
- * we never go in XMIT_S, so we never get a
- * chance to process any DISCONNECT_REQUEST.
- * Do it now ! - Jean II */
- if (self->disconnect_pending) {
- /* Disconnect */
- irlap_send_rd_frame(self);
- irlap_flush_all_queues(self);
-
- irlap_next_state(self, LAP_SCLOSE);
- } else {
- /* Just send back pf bit */
- irlap_send_rr_frame(self, RSP_FRAME);
-
- irlap_next_state(self, LAP_NRM_S);
- }
- }
- } else if (nr_status == NR_UNEXPECTED) {
- self->remote_busy = FALSE;
- irlap_update_nr_received(self, info->nr);
- irlap_resend_rejected_frames(self, RSP_FRAME);
-
- irlap_start_wd_timer(self, self->wd_timeout);
-
- /* Keep state */
- irlap_next_state(self, LAP_NRM_S);
- } else {
- pr_debug("%s(), invalid nr not implemented!\n",
- __func__);
- }
- break;
- case RECV_SNRM_CMD:
- /* SNRM frame is not allowed to contain an I-field */
- if (!info) {
- del_timer(&self->wd_timer);
- pr_debug("%s(), received SNRM cmd\n", __func__);
- irlap_next_state(self, LAP_RESET_CHECK);
-
- irlap_reset_indication(self);
- } else {
- pr_debug("%s(), SNRM frame contained an I-field!\n",
- __func__);
-
- }
- break;
- case RECV_REJ_CMD:
- irlap_update_nr_received(self, info->nr);
- if (self->remote_busy) {
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_rr_frame(self, RSP_FRAME);
- } else
- irlap_resend_rejected_frames(self, RSP_FRAME);
- irlap_start_wd_timer(self, self->wd_timeout);
- break;
- case RECV_SREJ_CMD:
- irlap_update_nr_received(self, info->nr);
- if (self->remote_busy) {
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_rr_frame(self, RSP_FRAME);
- } else
- irlap_resend_rejected_frame(self, RSP_FRAME);
- irlap_start_wd_timer(self, self->wd_timeout);
- break;
- case WD_TIMER_EXPIRED:
- /*
- * Wait until retry_count * n matches negotiated threshold/
- * disconnect time (note 2 in IrLAP p. 82)
- *
- * Similar to irlap_state_nrm_p() -> FINAL_TIMER_EXPIRED
- * Note : self->wd_timeout = (self->final_timeout * 2),
- * which explain why we use (self->N2 / 2) here !!!
- * Jean II
- */
- pr_debug("%s(), retry_count = %d\n", __func__,
- self->retry_count);
-
- if (self->retry_count < (self->N2 / 2)) {
- /* No retry, just wait for primary */
- irlap_start_wd_timer(self, self->wd_timeout);
- self->retry_count++;
-
- if((self->retry_count % (self->N1 / 2)) == 0)
- irlap_status_indication(self,
- STATUS_NO_ACTIVITY);
- } else {
- irlap_apply_default_connection_parameters(self);
-
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
- irlap_disconnect_indication(self, LAP_NO_RESPONSE);
- }
- break;
- case RECV_DISC_CMD:
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
- /* Send disconnect response */
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_ua_response_frame(self, NULL);
-
- del_timer(&self->wd_timer);
- irlap_flush_all_queues(self);
- /* Set default link parameters */
- irlap_apply_default_connection_parameters(self);
-
- irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- break;
- case RECV_DISCOVERY_XID_CMD:
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_rr_frame(self, RSP_FRAME);
- self->ack_required = TRUE;
- irlap_start_wd_timer(self, self->wd_timeout);
- irlap_next_state(self, LAP_NRM_S);
-
- break;
- case RECV_TEST_CMD:
- /* Remove test frame header (only LAP header in NRM) */
- skb_pull(skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER);
-
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_start_wd_timer(self, self->wd_timeout);
-
- /* Send response (info will be copied) */
- irlap_send_test_frame(self, self->caddr, info->daddr, skb);
- break;
- default:
- pr_debug("%s(), Unknown event %d, (%s)\n", __func__,
- event, irlap_event[event]);
-
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-/*
- * Function irlap_state_sclose (self, event, skb, info)
- */
-static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
-{
- IRDA_ASSERT(self != NULL, return -ENODEV;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
-
- switch (event) {
- case RECV_DISC_CMD:
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
- /* Send disconnect response */
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_ua_response_frame(self, NULL);
-
- del_timer(&self->wd_timer);
- /* Set default link parameters */
- irlap_apply_default_connection_parameters(self);
-
- irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- break;
- case RECV_DM_RSP:
- /* IrLAP-1.1 p.82: in SCLOSE, S and I type RSP frames
- * shall take us down into default NDM state, like DM_RSP
- */
- case RECV_RR_RSP:
- case RECV_RNR_RSP:
- case RECV_REJ_RSP:
- case RECV_SREJ_RSP:
- case RECV_I_RSP:
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
- del_timer(&self->wd_timer);
- irlap_apply_default_connection_parameters(self);
-
- irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- break;
- case WD_TIMER_EXPIRED:
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
- irlap_apply_default_connection_parameters(self);
-
- irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- break;
- default:
- /* IrLAP-1.1 p.82: in SCLOSE, basically any received frame
- * with pf=1 shall restart the wd-timer and resend the rd:rsp
- */
- if (info != NULL && info->pf) {
- del_timer(&self->wd_timer);
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_rd_frame(self);
- irlap_start_wd_timer(self, self->wd_timeout);
- break; /* stay in SCLOSE */
- }
-
- pr_debug("%s(), Unknown event %d, (%s)\n", __func__,
- event, irlap_event[event]);
-
- break;
- }
-
- return -1;
-}
-
-static int irlap_state_reset_check( struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb,
- struct irlap_info *info)
-{
- int ret = 0;
-
- pr_debug("%s(), event=%s\n", __func__, irlap_event[event]);
-
- IRDA_ASSERT(self != NULL, return -ENODEV;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
-
- switch (event) {
- case RESET_RESPONSE:
- irlap_send_ua_response_frame(self, &self->qos_rx);
- irlap_initiate_connection_state(self);
- irlap_start_wd_timer(self, WD_TIMEOUT);
- irlap_flush_all_queues(self);
-
- irlap_next_state(self, LAP_NRM_S);
- break;
- case DISCONNECT_REQUEST:
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_rd_frame(self);
- irlap_start_wd_timer(self, WD_TIMEOUT);
- irlap_next_state(self, LAP_SCLOSE);
- break;
- default:
- pr_debug("%s(), Unknown event %d, (%s)\n", __func__,
- event, irlap_event[event]);
-
- ret = -EINVAL;
- break;
- }
- return ret;
-}
diff --git a/drivers/staging/irda/net/irlap_frame.c b/drivers/staging/irda/net/irlap_frame.c
deleted file mode 100644
index debda3de4726..000000000000
--- a/drivers/staging/irda/net/irlap_frame.c
+++ /dev/null
@@ -1,1407 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlap_frame.c
- * Version: 1.0
- * Description: Build and transmit IrLAP frames
- * Status: Stable
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Tue Aug 19 10:27:26 1997
- * Modified at: Wed Jan 5 08:59:04 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/skbuff.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/netdevice.h>
-#include <linux/irda.h>
-#include <linux/slab.h>
-
-#include <net/pkt_sched.h>
-#include <net/sock.h>
-
-#include <asm/byteorder.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-#include <net/irda/irlap.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/timer.h>
-#include <net/irda/irlap_frame.h>
-#include <net/irda/qos.h>
-
-static void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb,
- int command);
-
-/*
- * Function irlap_insert_info (self, skb)
- *
- * Insert minimum turnaround time and speed information into the skb. We
- * need to do this since it's per packet relevant information. Safe to
- * have this function inlined since it's only called from one place
- */
-static inline void irlap_insert_info(struct irlap_cb *self,
- struct sk_buff *skb)
-{
- struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb;
-
- /*
- * Insert MTT (min. turn time) and speed into skb, so that the
- * device driver knows which settings to use
- */
- cb->magic = LAP_MAGIC;
- cb->mtt = self->mtt_required;
- cb->next_speed = self->speed;
-
- /* Reset */
- self->mtt_required = 0;
-
- /*
- * Delay equals negotiated BOFs count, plus the number of BOFs to
- * force the negotiated minimum turnaround time
- */
- cb->xbofs = self->bofs_count;
- cb->next_xbofs = self->next_bofs;
- cb->xbofs_delay = self->xbofs_delay;
-
- /* Reset XBOF's delay (used only for getting min turn time) */
- self->xbofs_delay = 0;
- /* Put the correct xbofs value for the next packet */
- self->bofs_count = self->next_bofs;
-}
-
-/*
- * Function irlap_queue_xmit (self, skb)
- *
- * A little wrapper for dev_queue_xmit, so we can insert some common
- * code into it.
- */
-void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb)
-{
- /* Some common init stuff */
- skb->dev = self->netdev;
- skb_reset_mac_header(skb);
- skb_reset_network_header(skb);
- skb_reset_transport_header(skb);
- skb->protocol = htons(ETH_P_IRDA);
- skb->priority = TC_PRIO_BESTEFFORT;
-
- irlap_insert_info(self, skb);
-
- if (unlikely(self->mode & IRDA_MODE_MONITOR)) {
- pr_debug("%s(): %s is in monitor mode\n", __func__,
- self->netdev->name);
- dev_kfree_skb(skb);
- return;
- }
-
- dev_queue_xmit(skb);
-}
-
-/*
- * Function irlap_send_snrm_cmd (void)
- *
- * Transmits a connect SNRM command frame
- */
-void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos)
-{
- struct sk_buff *tx_skb;
- struct snrm_frame *frame;
- int ret;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- /* Allocate frame */
- tx_skb = alloc_skb(sizeof(struct snrm_frame) +
- IRLAP_NEGOCIATION_PARAMS_LEN,
- GFP_ATOMIC);
- if (!tx_skb)
- return;
-
- frame = skb_put(tx_skb, 2);
-
- /* Insert connection address field */
- if (qos)
- frame->caddr = CMD_FRAME | CBROADCAST;
- else
- frame->caddr = CMD_FRAME | self->caddr;
-
- /* Insert control field */
- frame->control = SNRM_CMD | PF_BIT;
-
- /*
- * If we are establishing a connection then insert QoS parameters
- */
- if (qos) {
- skb_put(tx_skb, 9); /* 25 left */
- frame->saddr = cpu_to_le32(self->saddr);
- frame->daddr = cpu_to_le32(self->daddr);
-
- frame->ncaddr = self->caddr;
-
- ret = irlap_insert_qos_negotiation_params(self, tx_skb);
- if (ret < 0) {
- dev_kfree_skb(tx_skb);
- return;
- }
- }
- irlap_queue_xmit(self, tx_skb);
-}
-
-/*
- * Function irlap_recv_snrm_cmd (skb, info)
- *
- * Received SNRM (Set Normal Response Mode) command frame
- *
- */
-static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb,
- struct irlap_info *info)
-{
- struct snrm_frame *frame;
-
- if (pskb_may_pull(skb,sizeof(struct snrm_frame))) {
- frame = (struct snrm_frame *) skb->data;
-
- /* Copy the new connection address ignoring the C/R bit */
- info->caddr = frame->ncaddr & 0xFE;
-
- /* Check if the new connection address is valid */
- if ((info->caddr == 0x00) || (info->caddr == 0xfe)) {
- pr_debug("%s(), invalid connection address!\n",
- __func__);
- return;
- }
-
- /* Copy peer device address */
- info->daddr = le32_to_cpu(frame->saddr);
- info->saddr = le32_to_cpu(frame->daddr);
-
- /* Only accept if addressed directly to us */
- if (info->saddr != self->saddr) {
- pr_debug("%s(), not addressed to us!\n",
- __func__);
- return;
- }
- irlap_do_event(self, RECV_SNRM_CMD, skb, info);
- } else {
- /* Signal that this SNRM frame does not contain and I-field */
- irlap_do_event(self, RECV_SNRM_CMD, skb, NULL);
- }
-}
-
-/*
- * Function irlap_send_ua_response_frame (qos)
- *
- * Send UA (Unnumbered Acknowledgement) frame
- *
- */
-void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos)
-{
- struct sk_buff *tx_skb;
- struct ua_frame *frame;
- int ret;
-
- pr_debug("%s() <%ld>\n", __func__, jiffies);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- /* Allocate frame */
- tx_skb = alloc_skb(sizeof(struct ua_frame) +
- IRLAP_NEGOCIATION_PARAMS_LEN,
- GFP_ATOMIC);
- if (!tx_skb)
- return;
-
- frame = skb_put(tx_skb, 10);
-
- /* Build UA response */
- frame->caddr = self->caddr;
- frame->control = UA_RSP | PF_BIT;
-
- frame->saddr = cpu_to_le32(self->saddr);
- frame->daddr = cpu_to_le32(self->daddr);
-
- /* Should we send QoS negotiation parameters? */
- if (qos) {
- ret = irlap_insert_qos_negotiation_params(self, tx_skb);
- if (ret < 0) {
- dev_kfree_skb(tx_skb);
- return;
- }
- }
-
- irlap_queue_xmit(self, tx_skb);
-}
-
-
-/*
- * Function irlap_send_dm_frame (void)
- *
- * Send disconnected mode (DM) frame
- *
- */
-void irlap_send_dm_frame( struct irlap_cb *self)
-{
- struct sk_buff *tx_skb = NULL;
- struct dm_frame *frame;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- tx_skb = alloc_skb(sizeof(struct dm_frame), GFP_ATOMIC);
- if (!tx_skb)
- return;
-
- frame = skb_put(tx_skb, 2);
-
- if (self->state == LAP_NDM)
- frame->caddr = CBROADCAST;
- else
- frame->caddr = self->caddr;
-
- frame->control = DM_RSP | PF_BIT;
-
- irlap_queue_xmit(self, tx_skb);
-}
-
-/*
- * Function irlap_send_disc_frame (void)
- *
- * Send disconnect (DISC) frame
- *
- */
-void irlap_send_disc_frame(struct irlap_cb *self)
-{
- struct sk_buff *tx_skb = NULL;
- struct disc_frame *frame;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- tx_skb = alloc_skb(sizeof(struct disc_frame), GFP_ATOMIC);
- if (!tx_skb)
- return;
-
- frame = skb_put(tx_skb, 2);
-
- frame->caddr = self->caddr | CMD_FRAME;
- frame->control = DISC_CMD | PF_BIT;
-
- irlap_queue_xmit(self, tx_skb);
-}
-
-/*
- * Function irlap_send_discovery_xid_frame (S, s, command)
- *
- * Build and transmit a XID (eXchange station IDentifier) discovery
- * frame.
- */
-void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s,
- __u8 command, discovery_t *discovery)
-{
- struct sk_buff *tx_skb = NULL;
- struct xid_frame *frame;
- __u32 bcast = BROADCAST;
- __u8 *info;
-
- pr_debug("%s(), s=%d, S=%d, command=%d\n", __func__,
- s, S, command);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
- IRDA_ASSERT(discovery != NULL, return;);
-
- tx_skb = alloc_skb(sizeof(struct xid_frame) + IRLAP_DISCOVERY_INFO_LEN,
- GFP_ATOMIC);
- if (!tx_skb)
- return;
-
- skb_put(tx_skb, 14);
- frame = (struct xid_frame *) tx_skb->data;
-
- if (command) {
- frame->caddr = CBROADCAST | CMD_FRAME;
- frame->control = XID_CMD | PF_BIT;
- } else {
- frame->caddr = CBROADCAST;
- frame->control = XID_RSP | PF_BIT;
- }
- frame->ident = XID_FORMAT;
-
- frame->saddr = cpu_to_le32(self->saddr);
-
- if (command)
- frame->daddr = cpu_to_le32(bcast);
- else
- frame->daddr = cpu_to_le32(discovery->data.daddr);
-
- switch (S) {
- case 1:
- frame->flags = 0x00;
- break;
- case 6:
- frame->flags = 0x01;
- break;
- case 8:
- frame->flags = 0x02;
- break;
- case 16:
- frame->flags = 0x03;
- break;
- default:
- frame->flags = 0x02;
- break;
- }
-
- frame->slotnr = s;
- frame->version = 0x00;
-
- /*
- * Provide info for final slot only in commands, and for all
- * responses. Send the second byte of the hint only if the
- * EXTENSION bit is set in the first byte.
- */
- if (!command || (frame->slotnr == 0xff)) {
- int len;
-
- if (discovery->data.hints[0] & HINT_EXTENSION) {
- info = skb_put(tx_skb, 2);
- info[0] = discovery->data.hints[0];
- info[1] = discovery->data.hints[1];
- } else {
- info = skb_put(tx_skb, 1);
- info[0] = discovery->data.hints[0];
- }
- info = skb_put(tx_skb, 1);
- info[0] = discovery->data.charset;
-
- len = IRDA_MIN(discovery->name_len, skb_tailroom(tx_skb));
- skb_put_data(tx_skb, discovery->data.info, len);
- }
- irlap_queue_xmit(self, tx_skb);
-}
-
-/*
- * Function irlap_recv_discovery_xid_rsp (skb, info)
- *
- * Received a XID discovery response
- *
- */
-static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self,
- struct sk_buff *skb,
- struct irlap_info *info)
-{
- struct xid_frame *xid;
- discovery_t *discovery = NULL;
- __u8 *discovery_info;
- char *text;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- if (!pskb_may_pull(skb, sizeof(struct xid_frame))) {
- net_err_ratelimited("%s: frame too short!\n", __func__);
- return;
- }
-
- xid = (struct xid_frame *) skb->data;
-
- info->daddr = le32_to_cpu(xid->saddr);
- info->saddr = le32_to_cpu(xid->daddr);
-
- /* Make sure frame is addressed to us */
- if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
- pr_debug("%s(), frame is not addressed to us!\n",
- __func__);
- return;
- }
-
- if ((discovery = kzalloc(sizeof(discovery_t), GFP_ATOMIC)) == NULL) {
- net_warn_ratelimited("%s: kmalloc failed!\n", __func__);
- return;
- }
-
- discovery->data.daddr = info->daddr;
- discovery->data.saddr = self->saddr;
- discovery->timestamp = jiffies;
-
- pr_debug("%s(), daddr=%08x\n", __func__,
- discovery->data.daddr);
-
- discovery_info = skb_pull(skb, sizeof(struct xid_frame));
-
- /* Get info returned from peer */
- discovery->data.hints[0] = discovery_info[0];
- if (discovery_info[0] & HINT_EXTENSION) {
- pr_debug("EXTENSION\n");
- discovery->data.hints[1] = discovery_info[1];
- discovery->data.charset = discovery_info[2];
- text = (char *) &discovery_info[3];
- } else {
- discovery->data.hints[1] = 0;
- discovery->data.charset = discovery_info[1];
- text = (char *) &discovery_info[2];
- }
- /*
- * Terminate info string, should be safe since this is where the
- * FCS bytes resides.
- */
- skb->data[skb->len] = '\0';
- strncpy(discovery->data.info, text, NICKNAME_MAX_LEN);
- discovery->name_len = strlen(discovery->data.info);
-
- info->discovery = discovery;
-
- irlap_do_event(self, RECV_DISCOVERY_XID_RSP, skb, info);
-}
-
-/*
- * Function irlap_recv_discovery_xid_cmd (skb, info)
- *
- * Received a XID discovery command
- *
- */
-static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
- struct sk_buff *skb,
- struct irlap_info *info)
-{
- struct xid_frame *xid;
- discovery_t *discovery = NULL;
- __u8 *discovery_info;
- char *text;
-
- if (!pskb_may_pull(skb, sizeof(struct xid_frame))) {
- net_err_ratelimited("%s: frame too short!\n", __func__);
- return;
- }
-
- xid = (struct xid_frame *) skb->data;
-
- info->daddr = le32_to_cpu(xid->saddr);
- info->saddr = le32_to_cpu(xid->daddr);
-
- /* Make sure frame is addressed to us */
- if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
- pr_debug("%s(), frame is not addressed to us!\n",
- __func__);
- return;
- }
-
- switch (xid->flags & 0x03) {
- case 0x00:
- info->S = 1;
- break;
- case 0x01:
- info->S = 6;
- break;
- case 0x02:
- info->S = 8;
- break;
- case 0x03:
- info->S = 16;
- break;
- default:
- /* Error!! */
- return;
- }
- info->s = xid->slotnr;
-
- discovery_info = skb_pull(skb, sizeof(struct xid_frame));
-
- /*
- * Check if last frame
- */
- if (info->s == 0xff) {
- /* Check if things are sane at this point... */
- if((discovery_info == NULL) ||
- !pskb_may_pull(skb, 3)) {
- net_err_ratelimited("%s: discovery frame too short!\n",
- __func__);
- return;
- }
-
- /*
- * We now have some discovery info to deliver!
- */
- discovery = kzalloc(sizeof(discovery_t), GFP_ATOMIC);
- if (!discovery)
- return;
-
- discovery->data.daddr = info->daddr;
- discovery->data.saddr = self->saddr;
- discovery->timestamp = jiffies;
-
- discovery->data.hints[0] = discovery_info[0];
- if (discovery_info[0] & HINT_EXTENSION) {
- discovery->data.hints[1] = discovery_info[1];
- discovery->data.charset = discovery_info[2];
- text = (char *) &discovery_info[3];
- } else {
- discovery->data.hints[1] = 0;
- discovery->data.charset = discovery_info[1];
- text = (char *) &discovery_info[2];
- }
- /*
- * Terminate string, should be safe since this is where the
- * FCS bytes resides.
- */
- skb->data[skb->len] = '\0';
- strncpy(discovery->data.info, text, NICKNAME_MAX_LEN);
- discovery->name_len = strlen(discovery->data.info);
-
- info->discovery = discovery;
- } else
- info->discovery = NULL;
-
- irlap_do_event(self, RECV_DISCOVERY_XID_CMD, skb, info);
-}
-
-/*
- * Function irlap_send_rr_frame (self, command)
- *
- * Build and transmit RR (Receive Ready) frame. Notice that it is currently
- * only possible to send RR frames with the poll bit set.
- */
-void irlap_send_rr_frame(struct irlap_cb *self, int command)
-{
- struct sk_buff *tx_skb;
- struct rr_frame *frame;
-
- tx_skb = alloc_skb(sizeof(struct rr_frame), GFP_ATOMIC);
- if (!tx_skb)
- return;
-
- frame = skb_put(tx_skb, 2);
-
- frame->caddr = self->caddr;
- frame->caddr |= (command) ? CMD_FRAME : 0;
-
- frame->control = RR | PF_BIT | (self->vr << 5);
-
- irlap_queue_xmit(self, tx_skb);
-}
-
-/*
- * Function irlap_send_rd_frame (self)
- *
- * Request disconnect. Used by a secondary station to request the
- * disconnection of the link.
- */
-void irlap_send_rd_frame(struct irlap_cb *self)
-{
- struct sk_buff *tx_skb;
- struct rd_frame *frame;
-
- tx_skb = alloc_skb(sizeof(struct rd_frame), GFP_ATOMIC);
- if (!tx_skb)
- return;
-
- frame = skb_put(tx_skb, 2);
-
- frame->caddr = self->caddr;
- frame->control = RD_RSP | PF_BIT;
-
- irlap_queue_xmit(self, tx_skb);
-}
-
-/*
- * Function irlap_recv_rr_frame (skb, info)
- *
- * Received RR (Receive Ready) frame from peer station, no harm in
- * making it inline since its called only from one single place
- * (irlap_driver_rcv).
- */
-static inline void irlap_recv_rr_frame(struct irlap_cb *self,
- struct sk_buff *skb,
- struct irlap_info *info, int command)
-{
- info->nr = skb->data[1] >> 5;
-
- /* Check if this is a command or a response frame */
- if (command)
- irlap_do_event(self, RECV_RR_CMD, skb, info);
- else
- irlap_do_event(self, RECV_RR_RSP, skb, info);
-}
-
-/*
- * Function irlap_recv_rnr_frame (self, skb, info)
- *
- * Received RNR (Receive Not Ready) frame from peer station
- *
- */
-static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb,
- struct irlap_info *info, int command)
-{
- info->nr = skb->data[1] >> 5;
-
- pr_debug("%s(), nr=%d, %ld\n", __func__, info->nr, jiffies);
-
- if (command)
- irlap_do_event(self, RECV_RNR_CMD, skb, info);
- else
- irlap_do_event(self, RECV_RNR_RSP, skb, info);
-}
-
-static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb,
- struct irlap_info *info, int command)
-{
- info->nr = skb->data[1] >> 5;
-
- /* Check if this is a command or a response frame */
- if (command)
- irlap_do_event(self, RECV_REJ_CMD, skb, info);
- else
- irlap_do_event(self, RECV_REJ_RSP, skb, info);
-}
-
-static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb,
- struct irlap_info *info, int command)
-{
- info->nr = skb->data[1] >> 5;
-
- /* Check if this is a command or a response frame */
- if (command)
- irlap_do_event(self, RECV_SREJ_CMD, skb, info);
- else
- irlap_do_event(self, RECV_SREJ_RSP, skb, info);
-}
-
-static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb,
- struct irlap_info *info, int command)
-{
- /* Check if this is a command or a response frame */
- if (command)
- irlap_do_event(self, RECV_DISC_CMD, skb, info);
- else
- irlap_do_event(self, RECV_RD_RSP, skb, info);
-}
-
-/*
- * Function irlap_recv_ua_frame (skb, frame)
- *
- * Received UA (Unnumbered Acknowledgement) frame
- *
- */
-static inline void irlap_recv_ua_frame(struct irlap_cb *self,
- struct sk_buff *skb,
- struct irlap_info *info)
-{
- irlap_do_event(self, RECV_UA_RSP, skb, info);
-}
-
-/*
- * Function irlap_send_data_primary(self, skb)
- *
- * Send I-frames as the primary station but without the poll bit set
- *
- */
-void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb)
-{
- struct sk_buff *tx_skb;
-
- if (skb->data[1] == I_FRAME) {
-
- /*
- * Insert frame sequence number (Vs) in control field before
- * inserting into transmit window queue.
- */
- skb->data[1] = I_FRAME | (self->vs << 1);
-
- /*
- * Insert frame in store, in case of retransmissions
- * Increase skb reference count, see irlap_do_event()
- */
- skb_get(skb);
- skb_queue_tail(&self->wx_list, skb);
-
- /* Copy buffer */
- tx_skb = skb_clone(skb, GFP_ATOMIC);
- if (tx_skb == NULL) {
- return;
- }
-
- self->vs = (self->vs + 1) % 8;
- self->ack_required = FALSE;
- self->window -= 1;
-
- irlap_send_i_frame( self, tx_skb, CMD_FRAME);
- } else {
- pr_debug("%s(), sending unreliable frame\n", __func__);
- irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
- self->window -= 1;
- }
-}
-/*
- * Function irlap_send_data_primary_poll (self, skb)
- *
- * Send I(nformation) frame as primary with poll bit set
- */
-void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
-{
- struct sk_buff *tx_skb;
- int transmission_time;
-
- /* Stop P timer */
- del_timer(&self->poll_timer);
-
- /* Is this reliable or unreliable data? */
- if (skb->data[1] == I_FRAME) {
-
- /*
- * Insert frame sequence number (Vs) in control field before
- * inserting into transmit window queue.
- */
- skb->data[1] = I_FRAME | (self->vs << 1);
-
- /*
- * Insert frame in store, in case of retransmissions
- * Increase skb reference count, see irlap_do_event()
- */
- skb_get(skb);
- skb_queue_tail(&self->wx_list, skb);
-
- /* Copy buffer */
- tx_skb = skb_clone(skb, GFP_ATOMIC);
- if (tx_skb == NULL) {
- return;
- }
-
- /*
- * Set poll bit if necessary. We do this to the copied
- * skb, since retransmitted need to set or clear the poll
- * bit depending on when they are sent.
- */
- tx_skb->data[1] |= PF_BIT;
-
- self->vs = (self->vs + 1) % 8;
- self->ack_required = FALSE;
-
- irlap_next_state(self, LAP_NRM_P);
- irlap_send_i_frame(self, tx_skb, CMD_FRAME);
- } else {
- pr_debug("%s(), sending unreliable frame\n", __func__);
-
- if (self->ack_required) {
- irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
- irlap_next_state(self, LAP_NRM_P);
- irlap_send_rr_frame(self, CMD_FRAME);
- self->ack_required = FALSE;
- } else {
- skb->data[1] |= PF_BIT;
- irlap_next_state(self, LAP_NRM_P);
- irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
- }
- }
-
- /* How much time we took for transmission of all frames.
- * We don't know, so let assume we used the full window. Jean II */
- transmission_time = self->final_timeout;
-
- /* Reset parameter so that we can fill next window */
- self->window = self->window_size;
-
-#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
- /* Remove what we have not used. Just do a prorata of the
- * bytes left in window to window capacity.
- * See max_line_capacities[][] in qos.c for details. Jean II */
- transmission_time -= (self->final_timeout * self->bytes_left
- / self->line_capacity);
- pr_debug("%s() adjusting transmission_time : ft=%d, bl=%d, lc=%d -> tt=%d\n",
- __func__, self->final_timeout, self->bytes_left,
- self->line_capacity, transmission_time);
-
- /* We are allowed to transmit a maximum number of bytes again. */
- self->bytes_left = self->line_capacity;
-#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
-
- /*
- * The network layer has a intermediate buffer between IrLAP
- * and the IrDA driver which can contain 8 frames. So, even
- * though IrLAP is currently sending the *last* frame of the
- * tx-window, the driver most likely has only just started
- * sending the *first* frame of the same tx-window.
- * I.e. we are always at the very beginning of or Tx window.
- * Now, we are supposed to set the final timer from the end
- * of our tx-window to let the other peer reply. So, we need
- * to add extra time to compensate for the fact that we
- * are really at the start of tx-window, otherwise the final timer
- * might expire before he can answer...
- * Jean II
- */
- irlap_start_final_timer(self, self->final_timeout + transmission_time);
-
- /*
- * The clever amongst you might ask why we do this adjustement
- * only here, and not in all the other cases in irlap_event.c.
- * In all those other case, we only send a very short management
- * frame (few bytes), so the adjustement would be lost in the
- * noise...
- * The exception of course is irlap_resend_rejected_frame().
- * Jean II */
-}
-
-/*
- * Function irlap_send_data_secondary_final (self, skb)
- *
- * Send I(nformation) frame as secondary with final bit set
- *
- */
-void irlap_send_data_secondary_final(struct irlap_cb *self,
- struct sk_buff *skb)
-{
- struct sk_buff *tx_skb = NULL;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
-
- /* Is this reliable or unreliable data? */
- if (skb->data[1] == I_FRAME) {
-
- /*
- * Insert frame sequence number (Vs) in control field before
- * inserting into transmit window queue.
- */
- skb->data[1] = I_FRAME | (self->vs << 1);
-
- /*
- * Insert frame in store, in case of retransmissions
- * Increase skb reference count, see irlap_do_event()
- */
- skb_get(skb);
- skb_queue_tail(&self->wx_list, skb);
-
- tx_skb = skb_clone(skb, GFP_ATOMIC);
- if (tx_skb == NULL) {
- return;
- }
-
- tx_skb->data[1] |= PF_BIT;
-
- self->vs = (self->vs + 1) % 8;
- self->ack_required = FALSE;
-
- irlap_send_i_frame(self, tx_skb, RSP_FRAME);
- } else {
- if (self->ack_required) {
- irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME);
- irlap_send_rr_frame(self, RSP_FRAME);
- self->ack_required = FALSE;
- } else {
- skb->data[1] |= PF_BIT;
- irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME);
- }
- }
-
- self->window = self->window_size;
-#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
- /* We are allowed to transmit a maximum number of bytes again. */
- self->bytes_left = self->line_capacity;
-#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
-
- irlap_start_wd_timer(self, self->wd_timeout);
-}
-
-/*
- * Function irlap_send_data_secondary (self, skb)
- *
- * Send I(nformation) frame as secondary without final bit set
- *
- */
-void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb)
-{
- struct sk_buff *tx_skb = NULL;
-
- /* Is this reliable or unreliable data? */
- if (skb->data[1] == I_FRAME) {
-
- /*
- * Insert frame sequence number (Vs) in control field before
- * inserting into transmit window queue.
- */
- skb->data[1] = I_FRAME | (self->vs << 1);
-
- /*
- * Insert frame in store, in case of retransmissions
- * Increase skb reference count, see irlap_do_event()
- */
- skb_get(skb);
- skb_queue_tail(&self->wx_list, skb);
-
- tx_skb = skb_clone(skb, GFP_ATOMIC);
- if (tx_skb == NULL) {
- return;
- }
-
- self->vs = (self->vs + 1) % 8;
- self->ack_required = FALSE;
- self->window -= 1;
-
- irlap_send_i_frame(self, tx_skb, RSP_FRAME);
- } else {
- irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME);
- self->window -= 1;
- }
-}
-
-/*
- * Function irlap_resend_rejected_frames (nr)
- *
- * Resend frames which has not been acknowledged. Should be safe to
- * traverse the list without locking it since this function will only be
- * called from interrupt context (BH)
- */
-void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
-{
- struct sk_buff *tx_skb;
- struct sk_buff *skb;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- /* Resend unacknowledged frame(s) */
- skb_queue_walk(&self->wx_list, skb) {
- irlap_wait_min_turn_around(self, &self->qos_tx);
-
- /* We copy the skb to be retransmitted since we will have to
- * modify it. Cloning will confuse packet sniffers
- */
- /* tx_skb = skb_clone( skb, GFP_ATOMIC); */
- tx_skb = skb_copy(skb, GFP_ATOMIC);
- if (!tx_skb) {
- pr_debug("%s(), unable to copy\n", __func__);
- return;
- }
-
- /* Clear old Nr field + poll bit */
- tx_skb->data[1] &= 0x0f;
-
- /*
- * Set poll bit on the last frame retransmitted
- */
- if (skb_queue_is_last(&self->wx_list, skb))
- tx_skb->data[1] |= PF_BIT; /* Set p/f bit */
- else
- tx_skb->data[1] &= ~PF_BIT; /* Clear p/f bit */
-
- irlap_send_i_frame(self, tx_skb, command);
- }
-#if 0 /* Not yet */
- /*
- * We can now fill the window with additional data frames
- */
- while (!skb_queue_empty(&self->txq)) {
-
- pr_debug("%s(), sending additional frames!\n", __func__);
- if (self->window > 0) {
- skb = skb_dequeue( &self->txq);
- IRDA_ASSERT(skb != NULL, return;);
-
- /*
- * If send window > 1 then send frame with pf
- * bit cleared
- */
- if ((self->window > 1) &&
- !skb_queue_empty(&self->txq)) {
- irlap_send_data_primary(self, skb);
- } else {
- irlap_send_data_primary_poll(self, skb);
- }
- kfree_skb(skb);
- }
- }
-#endif
-}
-
-void irlap_resend_rejected_frame(struct irlap_cb *self, int command)
-{
- struct sk_buff *tx_skb;
- struct sk_buff *skb;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- /* Resend unacknowledged frame(s) */
- skb = skb_peek(&self->wx_list);
- if (skb != NULL) {
- irlap_wait_min_turn_around(self, &self->qos_tx);
-
- /* We copy the skb to be retransmitted since we will have to
- * modify it. Cloning will confuse packet sniffers
- */
- /* tx_skb = skb_clone( skb, GFP_ATOMIC); */
- tx_skb = skb_copy(skb, GFP_ATOMIC);
- if (!tx_skb) {
- pr_debug("%s(), unable to copy\n", __func__);
- return;
- }
-
- /* Clear old Nr field + poll bit */
- tx_skb->data[1] &= 0x0f;
-
- /* Set poll/final bit */
- tx_skb->data[1] |= PF_BIT; /* Set p/f bit */
-
- irlap_send_i_frame(self, tx_skb, command);
- }
-}
-
-/*
- * Function irlap_send_ui_frame (self, skb, command)
- *
- * Contruct and transmit an Unnumbered Information (UI) frame
- *
- */
-void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
- __u8 caddr, int command)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
-
- /* Insert connection address */
- skb->data[0] = caddr | ((command) ? CMD_FRAME : 0);
-
- irlap_queue_xmit(self, skb);
-}
-
-/*
- * Function irlap_send_i_frame (skb)
- *
- * Contruct and transmit Information (I) frame
- */
-static void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb,
- int command)
-{
- /* Insert connection address */
- skb->data[0] = self->caddr;
- skb->data[0] |= (command) ? CMD_FRAME : 0;
-
- /* Insert next to receive (Vr) */
- skb->data[1] |= (self->vr << 5); /* insert nr */
-
- irlap_queue_xmit(self, skb);
-}
-
-/*
- * Function irlap_recv_i_frame (skb, frame)
- *
- * Receive and parse an I (Information) frame, no harm in making it inline
- * since it's called only from one single place (irlap_driver_rcv).
- */
-static inline void irlap_recv_i_frame(struct irlap_cb *self,
- struct sk_buff *skb,
- struct irlap_info *info, int command)
-{
- info->nr = skb->data[1] >> 5; /* Next to receive */
- info->pf = skb->data[1] & PF_BIT; /* Final bit */
- info->ns = (skb->data[1] >> 1) & 0x07; /* Next to send */
-
- /* Check if this is a command or a response frame */
- if (command)
- irlap_do_event(self, RECV_I_CMD, skb, info);
- else
- irlap_do_event(self, RECV_I_RSP, skb, info);
-}
-
-/*
- * Function irlap_recv_ui_frame (self, skb, info)
- *
- * Receive and parse an Unnumbered Information (UI) frame
- *
- */
-static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
- struct irlap_info *info)
-{
- info->pf = skb->data[1] & PF_BIT; /* Final bit */
-
- irlap_do_event(self, RECV_UI_FRAME, skb, info);
-}
-
-/*
- * Function irlap_recv_frmr_frame (skb, frame)
- *
- * Received Frame Reject response.
- *
- */
-static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb,
- struct irlap_info *info)
-{
- __u8 *frame;
- int w, x, y, z;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
- IRDA_ASSERT(info != NULL, return;);
-
- if (!pskb_may_pull(skb, 4)) {
- net_err_ratelimited("%s: frame too short!\n", __func__);
- return;
- }
-
- frame = skb->data;
-
- info->nr = frame[2] >> 5; /* Next to receive */
- info->pf = frame[2] & PF_BIT; /* Final bit */
- info->ns = (frame[2] >> 1) & 0x07; /* Next to send */
-
- w = frame[3] & 0x01;
- x = frame[3] & 0x02;
- y = frame[3] & 0x04;
- z = frame[3] & 0x08;
-
- if (w) {
- pr_debug("Rejected control field is undefined or not implemented\n");
- }
- if (x) {
- pr_debug("Rejected control field was invalid because it contained a non permitted I field\n");
- }
- if (y) {
- pr_debug("Received I field exceeded the maximum negotiated for the existing connection or exceeded the maximum this station supports if no connection exists\n");
- }
- if (z) {
- pr_debug("Rejected control field control field contained an invalid Nr count\n");
- }
- irlap_do_event(self, RECV_FRMR_RSP, skb, info);
-}
-
-/*
- * Function irlap_send_test_frame (self, daddr)
- *
- * Send a test frame response
- *
- */
-void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr,
- struct sk_buff *cmd)
-{
- struct sk_buff *tx_skb;
- struct test_frame *frame;
-
- tx_skb = alloc_skb(cmd->len + sizeof(struct test_frame), GFP_ATOMIC);
- if (!tx_skb)
- return;
-
- /* Broadcast frames must include saddr and daddr fields */
- if (caddr == CBROADCAST) {
- frame = skb_put(tx_skb, sizeof(struct test_frame));
-
- /* Insert the swapped addresses */
- frame->saddr = cpu_to_le32(self->saddr);
- frame->daddr = cpu_to_le32(daddr);
- } else
- frame = skb_put(tx_skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER);
-
- frame->caddr = caddr;
- frame->control = TEST_RSP | PF_BIT;
-
- /* Copy info */
- skb_put_data(tx_skb, cmd->data, cmd->len);
-
- /* Return to sender */
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_queue_xmit(self, tx_skb);
-}
-
-/*
- * Function irlap_recv_test_frame (self, skb)
- *
- * Receive a test frame
- *
- */
-static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb,
- struct irlap_info *info, int command)
-{
- struct test_frame *frame;
-
- if (!pskb_may_pull(skb, sizeof(*frame))) {
- net_err_ratelimited("%s: frame too short!\n", __func__);
- return;
- }
- frame = (struct test_frame *) skb->data;
-
- /* Broadcast frames must carry saddr and daddr fields */
- if (info->caddr == CBROADCAST) {
- if (skb->len < sizeof(struct test_frame)) {
- pr_debug("%s() test frame too short!\n",
- __func__);
- return;
- }
-
- /* Read and swap addresses */
- info->daddr = le32_to_cpu(frame->saddr);
- info->saddr = le32_to_cpu(frame->daddr);
-
- /* Make sure frame is addressed to us */
- if ((info->saddr != self->saddr) &&
- (info->saddr != BROADCAST)) {
- return;
- }
- }
-
- if (command)
- irlap_do_event(self, RECV_TEST_CMD, skb, info);
- else
- irlap_do_event(self, RECV_TEST_RSP, skb, info);
-}
-
-/*
- * Function irlap_driver_rcv (skb, netdev, ptype)
- *
- * Called when a frame is received. Dispatches the right receive function
- * for processing of the frame.
- *
- * Note on skb management :
- * After calling the higher layers of the IrDA stack, we always
- * kfree() the skb, which drop the reference count (and potentially
- * destroy it).
- * If a higher layer of the stack want to keep the skb around (to put
- * in a queue or pass it to the higher layer), it will need to use
- * skb_get() to keep a reference on it. This is usually done at the
- * LMP level in irlmp.c.
- * Jean II
- */
-int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *ptype, struct net_device *orig_dev)
-{
- struct irlap_info info;
- struct irlap_cb *self;
- int command;
- __u8 control;
- int ret = -1;
-
- if (!net_eq(dev_net(dev), &init_net))
- goto out;
-
- /* FIXME: should we get our own field? */
- self = (struct irlap_cb *) dev->atalk_ptr;
-
- /* If the net device is down, then IrLAP is gone! */
- if (!self || self->magic != LAP_MAGIC)
- goto err;
-
- /* We are no longer an "old" protocol, so we need to handle
- * share and non linear skbs. This should never happen, so
- * we don't need to be clever about it. Jean II */
- if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
- net_err_ratelimited("%s: can't clone shared skb!\n", __func__);
- goto err;
- }
-
- /* Check if frame is large enough for parsing */
- if (!pskb_may_pull(skb, 2)) {
- net_err_ratelimited("%s: frame too short!\n", __func__);
- goto err;
- }
-
- command = skb->data[0] & CMD_FRAME;
- info.caddr = skb->data[0] & CBROADCAST;
-
- info.pf = skb->data[1] & PF_BIT;
- info.control = skb->data[1] & ~PF_BIT; /* Mask away poll/final bit */
-
- control = info.control;
-
- /* First we check if this frame has a valid connection address */
- if ((info.caddr != self->caddr) && (info.caddr != CBROADCAST)) {
- pr_debug("%s(), wrong connection address!\n",
- __func__);
- goto out;
- }
- /*
- * Optimize for the common case and check if the frame is an
- * I(nformation) frame. Only I-frames have bit 0 set to 0
- */
- if (~control & 0x01) {
- irlap_recv_i_frame(self, skb, &info, command);
- goto out;
- }
- /*
- * We now check is the frame is an S(upervisory) frame. Only
- * S-frames have bit 0 set to 1 and bit 1 set to 0
- */
- if (~control & 0x02) {
- /*
- * Received S(upervisory) frame, check which frame type it is
- * only the first nibble is of interest
- */
- switch (control & 0x0f) {
- case RR:
- irlap_recv_rr_frame(self, skb, &info, command);
- break;
- case RNR:
- irlap_recv_rnr_frame(self, skb, &info, command);
- break;
- case REJ:
- irlap_recv_rej_frame(self, skb, &info, command);
- break;
- case SREJ:
- irlap_recv_srej_frame(self, skb, &info, command);
- break;
- default:
- net_warn_ratelimited("%s: Unknown S-frame %02x received!\n",
- __func__, info.control);
- break;
- }
- goto out;
- }
- /*
- * This must be a C(ontrol) frame
- */
- switch (control) {
- case XID_RSP:
- irlap_recv_discovery_xid_rsp(self, skb, &info);
- break;
- case XID_CMD:
- irlap_recv_discovery_xid_cmd(self, skb, &info);
- break;
- case SNRM_CMD:
- irlap_recv_snrm_cmd(self, skb, &info);
- break;
- case DM_RSP:
- irlap_do_event(self, RECV_DM_RSP, skb, &info);
- break;
- case DISC_CMD: /* And RD_RSP since they have the same value */
- irlap_recv_disc_frame(self, skb, &info, command);
- break;
- case TEST_CMD:
- irlap_recv_test_frame(self, skb, &info, command);
- break;
- case UA_RSP:
- irlap_recv_ua_frame(self, skb, &info);
- break;
- case FRMR_RSP:
- irlap_recv_frmr_frame(self, skb, &info);
- break;
- case UI_FRAME:
- irlap_recv_ui_frame(self, skb, &info);
- break;
- default:
- net_warn_ratelimited("%s: Unknown frame %02x received!\n",
- __func__, info.control);
- break;
- }
-out:
- ret = 0;
-err:
- /* Always drop our reference on the skb */
- dev_kfree_skb(skb);
- return ret;
-}
diff --git a/drivers/staging/irda/net/irlmp.c b/drivers/staging/irda/net/irlmp.c
deleted file mode 100644
index 7af618fb66c0..000000000000
--- a/drivers/staging/irda/net/irlmp.c
+++ /dev/null
@@ -1,1996 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlmp.c
- * Version: 1.0
- * Description: IrDA Link Management Protocol (LMP) layer
- * Status: Stable.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Aug 17 20:54:32 1997
- * Modified at: Wed Jan 5 11:26:03 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/skbuff.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/kmod.h>
-#include <linux/random.h>
-#include <linux/seq_file.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/timer.h>
-#include <net/irda/qos.h>
-#include <net/irda/irlap.h>
-#include <net/irda/iriap.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/irlmp_frame.h>
-
-#include <asm/unaligned.h>
-
-static __u8 irlmp_find_free_slsap(void);
-static int irlmp_slsap_inuse(__u8 slsap_sel);
-
-/* Master structure */
-struct irlmp_cb *irlmp = NULL;
-
-/* These can be altered by the sysctl interface */
-int sysctl_discovery = 0;
-int sysctl_discovery_timeout = 3; /* 3 seconds by default */
-int sysctl_discovery_slots = 6; /* 6 slots by default */
-int sysctl_lap_keepalive_time = LM_IDLE_TIMEOUT * 1000 / HZ;
-char sysctl_devname[65];
-
-static const char *irlmp_reasons[] = {
- "ERROR, NOT USED",
- "LM_USER_REQUEST",
- "LM_LAP_DISCONNECT",
- "LM_CONNECT_FAILURE",
- "LM_LAP_RESET",
- "LM_INIT_DISCONNECT",
- "ERROR, NOT USED",
- "UNKNOWN",
-};
-
-const char *irlmp_reason_str(LM_REASON reason)
-{
- reason = min_t(size_t, reason, ARRAY_SIZE(irlmp_reasons) - 1);
- return irlmp_reasons[reason];
-}
-
-/*
- * Function irlmp_init (void)
- *
- * Create (allocate) the main IrLMP structure
- *
- */
-int __init irlmp_init(void)
-{
- /* Initialize the irlmp structure. */
- irlmp = kzalloc( sizeof(struct irlmp_cb), GFP_KERNEL);
- if (irlmp == NULL)
- return -ENOMEM;
-
- irlmp->magic = LMP_MAGIC;
-
- irlmp->clients = hashbin_new(HB_LOCK);
- irlmp->services = hashbin_new(HB_LOCK);
- irlmp->links = hashbin_new(HB_LOCK);
- irlmp->unconnected_lsaps = hashbin_new(HB_LOCK);
- irlmp->cachelog = hashbin_new(HB_NOLOCK);
-
- if ((irlmp->clients == NULL) ||
- (irlmp->services == NULL) ||
- (irlmp->links == NULL) ||
- (irlmp->unconnected_lsaps == NULL) ||
- (irlmp->cachelog == NULL)) {
- return -ENOMEM;
- }
-
- spin_lock_init(&irlmp->cachelog->hb_spinlock);
-
- irlmp->last_lsap_sel = 0x0f; /* Reserved 0x00-0x0f */
- strcpy(sysctl_devname, "Linux");
-
- timer_setup(&irlmp->discovery_timer, NULL, 0);
-
- /* Do discovery every 3 seconds, conditionally */
- if (sysctl_discovery)
- irlmp_start_discovery_timer(irlmp,
- sysctl_discovery_timeout*HZ);
-
- return 0;
-}
-
-/*
- * Function irlmp_cleanup (void)
- *
- * Remove IrLMP layer
- *
- */
-void irlmp_cleanup(void)
-{
- /* Check for main structure */
- IRDA_ASSERT(irlmp != NULL, return;);
- IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return;);
-
- del_timer(&irlmp->discovery_timer);
-
- hashbin_delete(irlmp->links, (FREE_FUNC) kfree);
- hashbin_delete(irlmp->unconnected_lsaps, (FREE_FUNC) kfree);
- hashbin_delete(irlmp->clients, (FREE_FUNC) kfree);
- hashbin_delete(irlmp->services, (FREE_FUNC) kfree);
- hashbin_delete(irlmp->cachelog, (FREE_FUNC) kfree);
-
- /* De-allocate main structure */
- kfree(irlmp);
- irlmp = NULL;
-}
-
-/*
- * Function irlmp_open_lsap (slsap, notify)
- *
- * Register with IrLMP and create a local LSAP,
- * returns handle to LSAP.
- */
-struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify, __u8 pid)
-{
- struct lsap_cb *self;
-
- IRDA_ASSERT(notify != NULL, return NULL;);
- IRDA_ASSERT(irlmp != NULL, return NULL;);
- IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return NULL;);
- IRDA_ASSERT(notify->instance != NULL, return NULL;);
-
- /* Does the client care which Source LSAP selector it gets? */
- if (slsap_sel == LSAP_ANY) {
- slsap_sel = irlmp_find_free_slsap();
- if (!slsap_sel)
- return NULL;
- } else if (irlmp_slsap_inuse(slsap_sel))
- return NULL;
-
- /* Allocate new instance of a LSAP connection */
- self = kzalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
- if (self == NULL)
- return NULL;
-
- self->magic = LMP_LSAP_MAGIC;
- self->slsap_sel = slsap_sel;
-
- /* Fix connectionless LSAP's */
- if (slsap_sel == LSAP_CONNLESS) {
-#ifdef CONFIG_IRDA_ULTRA
- self->dlsap_sel = LSAP_CONNLESS;
- self->pid = pid;
-#endif /* CONFIG_IRDA_ULTRA */
- } else
- self->dlsap_sel = LSAP_ANY;
- /* self->connected = FALSE; -> already NULL via memset() */
-
- timer_setup(&self->watchdog_timer, NULL, 0);
-
- self->notify = *notify;
-
- self->lsap_state = LSAP_DISCONNECTED;
-
- /* Insert into queue of unconnected LSAPs */
- hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self,
- (long) self, NULL);
-
- return self;
-}
-EXPORT_SYMBOL(irlmp_open_lsap);
-
-/*
- * Function __irlmp_close_lsap (self)
- *
- * Remove an instance of LSAP
- */
-static void __irlmp_close_lsap(struct lsap_cb *self)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
-
- /*
- * Set some of the variables to preset values
- */
- self->magic = 0;
- del_timer(&self->watchdog_timer); /* Important! */
-
- if (self->conn_skb)
- dev_kfree_skb(self->conn_skb);
-
- kfree(self);
-}
-
-/*
- * Function irlmp_close_lsap (self)
- *
- * Close and remove LSAP
- *
- */
-void irlmp_close_lsap(struct lsap_cb *self)
-{
- struct lap_cb *lap;
- struct lsap_cb *lsap = NULL;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
-
- /*
- * Find out if we should remove this LSAP from a link or from the
- * list of unconnected lsaps (not associated with a link)
- */
- lap = self->lap;
- if (lap) {
- IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
- /* We might close a LSAP before it has completed the
- * connection setup. In those case, higher layers won't
- * send a proper disconnect request. Harmless, except
- * that we will forget to close LAP... - Jean II */
- if(self->lsap_state != LSAP_DISCONNECTED) {
- self->lsap_state = LSAP_DISCONNECTED;
- irlmp_do_lap_event(self->lap,
- LM_LAP_DISCONNECT_REQUEST, NULL);
- }
- /* Now, remove from the link */
- lsap = hashbin_remove(lap->lsaps, (long) self, NULL);
-#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
- lap->cache.valid = FALSE;
-#endif
- }
- self->lap = NULL;
- /* Check if we found the LSAP! If not then try the unconnected lsaps */
- if (!lsap) {
- lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self,
- NULL);
- }
- if (!lsap) {
- pr_debug("%s(), Looks like somebody has removed me already!\n",
- __func__);
- return;
- }
- __irlmp_close_lsap(self);
-}
-EXPORT_SYMBOL(irlmp_close_lsap);
-
-/*
- * Function irlmp_register_irlap (saddr, notify)
- *
- * Register IrLAP layer with IrLMP. There is possible to have multiple
- * instances of the IrLAP layer, each connected to different IrDA ports
- *
- */
-void irlmp_register_link(struct irlap_cb *irlap, __u32 saddr, notify_t *notify)
-{
- struct lap_cb *lap;
-
- IRDA_ASSERT(irlmp != NULL, return;);
- IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return;);
- IRDA_ASSERT(notify != NULL, return;);
-
- /*
- * Allocate new instance of a LSAP connection
- */
- lap = kzalloc(sizeof(struct lap_cb), GFP_KERNEL);
- if (lap == NULL)
- return;
-
- lap->irlap = irlap;
- lap->magic = LMP_LAP_MAGIC;
- lap->saddr = saddr;
- lap->daddr = DEV_ADDR_ANY;
-#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
- lap->cache.valid = FALSE;
-#endif
- lap->lsaps = hashbin_new(HB_LOCK);
- if (lap->lsaps == NULL) {
- net_warn_ratelimited("%s(), unable to kmalloc lsaps\n",
- __func__);
- kfree(lap);
- return;
- }
-
- lap->lap_state = LAP_STANDBY;
-
- timer_setup(&lap->idle_timer, NULL, 0);
-
- /*
- * Insert into queue of LMP links
- */
- hashbin_insert(irlmp->links, (irda_queue_t *) lap, lap->saddr, NULL);
-
- /*
- * We set only this variable so IrLAP can tell us on which link the
- * different events happened on
- */
- irda_notify_init(notify);
- notify->instance = lap;
-}
-
-/*
- * Function irlmp_unregister_irlap (saddr)
- *
- * IrLAP layer has been removed!
- *
- */
-void irlmp_unregister_link(__u32 saddr)
-{
- struct lap_cb *link;
-
- /* We must remove ourselves from the hashbin *first*. This ensure
- * that no more LSAPs will be open on this link and no discovery
- * will be triggered anymore. Jean II */
- link = hashbin_remove(irlmp->links, saddr, NULL);
- if (link) {
- IRDA_ASSERT(link->magic == LMP_LAP_MAGIC, return;);
-
- /* Kill all the LSAPs on this link. Jean II */
- link->reason = LAP_DISC_INDICATION;
- link->daddr = DEV_ADDR_ANY;
- irlmp_do_lap_event(link, LM_LAP_DISCONNECT_INDICATION, NULL);
-
- /* Remove all discoveries discovered at this link */
- irlmp_expire_discoveries(irlmp->cachelog, link->saddr, TRUE);
-
- /* Final cleanup */
- del_timer(&link->idle_timer);
- link->magic = 0;
- hashbin_delete(link->lsaps, (FREE_FUNC) __irlmp_close_lsap);
- kfree(link);
- }
-}
-
-/*
- * Function irlmp_connect_request (handle, dlsap, userdata)
- *
- * Connect with a peer LSAP
- *
- */
-int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
- __u32 saddr, __u32 daddr,
- struct qos_info *qos, struct sk_buff *userdata)
-{
- struct sk_buff *tx_skb = userdata;
- struct lap_cb *lap;
- struct lsap_cb *lsap;
- int ret;
-
- IRDA_ASSERT(self != NULL, return -EBADR;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;);
-
- pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n",
- __func__, self->slsap_sel, dlsap_sel, saddr, daddr);
-
- if (test_bit(0, &self->connected)) {
- ret = -EISCONN;
- goto err;
- }
-
- /* Client must supply destination device address */
- if (!daddr) {
- ret = -EINVAL;
- goto err;
- }
-
- /* Any userdata? */
- if (tx_skb == NULL) {
- tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
- if (!tx_skb)
- return -ENOMEM;
-
- skb_reserve(tx_skb, LMP_MAX_HEADER);
- }
-
- /* Make room for MUX control header (3 bytes) */
- IRDA_ASSERT(skb_headroom(tx_skb) >= LMP_CONTROL_HEADER, return -1;);
- skb_push(tx_skb, LMP_CONTROL_HEADER);
-
- self->dlsap_sel = dlsap_sel;
-
- /*
- * Find the link to where we should try to connect since there may
- * be more than one IrDA port on this machine. If the client has
- * passed us the saddr (and already knows which link to use), then
- * we use that to find the link, if not then we have to look in the
- * discovery log and check if any of the links has discovered a
- * device with the given daddr
- */
- if ((!saddr) || (saddr == DEV_ADDR_ANY)) {
- discovery_t *discovery;
- unsigned long flags;
-
- spin_lock_irqsave(&irlmp->cachelog->hb_spinlock, flags);
- if (daddr != DEV_ADDR_ANY)
- discovery = hashbin_find(irlmp->cachelog, daddr, NULL);
- else {
- pr_debug("%s(), no daddr\n", __func__);
- discovery = (discovery_t *)
- hashbin_get_first(irlmp->cachelog);
- }
-
- if (discovery) {
- saddr = discovery->data.saddr;
- daddr = discovery->data.daddr;
- }
- spin_unlock_irqrestore(&irlmp->cachelog->hb_spinlock, flags);
- }
- lap = hashbin_lock_find(irlmp->links, saddr, NULL);
- if (lap == NULL) {
- pr_debug("%s(), Unable to find a usable link!\n", __func__);
- ret = -EHOSTUNREACH;
- goto err;
- }
-
- /* Check if LAP is disconnected or already connected */
- if (lap->daddr == DEV_ADDR_ANY)
- lap->daddr = daddr;
- else if (lap->daddr != daddr) {
- /* Check if some LSAPs are active on this LAP */
- if (HASHBIN_GET_SIZE(lap->lsaps) == 0) {
- /* No active connection, but LAP hasn't been
- * disconnected yet (waiting for timeout in LAP).
- * Maybe we could give LAP a bit of help in this case.
- */
- pr_debug("%s(), sorry, but I'm waiting for LAP to timeout!\n",
- __func__);
- ret = -EAGAIN;
- goto err;
- }
-
- /* LAP is already connected to a different node, and LAP
- * can only talk to one node at a time */
- pr_debug("%s(), sorry, but link is busy!\n", __func__);
- ret = -EBUSY;
- goto err;
- }
-
- self->lap = lap;
-
- /*
- * Remove LSAP from list of unconnected LSAPs and insert it into the
- * list of connected LSAPs for the particular link
- */
- lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, NULL);
-
- IRDA_ASSERT(lsap != NULL, return -1;);
- IRDA_ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
- IRDA_ASSERT(lsap->lap != NULL, return -1;);
- IRDA_ASSERT(lsap->lap->magic == LMP_LAP_MAGIC, return -1;);
-
- hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (long) self,
- NULL);
-
- set_bit(0, &self->connected); /* TRUE */
-
- /*
- * User supplied qos specifications?
- */
- if (qos)
- self->qos = *qos;
-
- irlmp_do_lsap_event(self, LM_CONNECT_REQUEST, tx_skb);
-
- /* Drop reference count - see irlap_data_request(). */
- dev_kfree_skb(tx_skb);
-
- return 0;
-
-err:
- /* Cleanup */
- if(tx_skb)
- dev_kfree_skb(tx_skb);
- return ret;
-}
-EXPORT_SYMBOL(irlmp_connect_request);
-
-/*
- * Function irlmp_connect_indication (self)
- *
- * Incoming connection
- *
- */
-void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb)
-{
- int max_seg_size;
- int lap_header_size;
- int max_header_size;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
- IRDA_ASSERT(self->lap != NULL, return;);
-
- pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
- __func__, self->slsap_sel, self->dlsap_sel);
-
- /* Note : self->lap is set in irlmp_link_data_indication(),
- * (case CONNECT_CMD:) because we have no way to set it here.
- * Similarly, self->dlsap_sel is usually set in irlmp_find_lsap().
- * Jean II */
-
- self->qos = *self->lap->qos;
-
- max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
- lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap);
- max_header_size = LMP_HEADER + lap_header_size;
-
- /* Hide LMP_CONTROL_HEADER header from layer above */
- skb_pull(skb, LMP_CONTROL_HEADER);
-
- if (self->notify.connect_indication) {
- /* Don't forget to refcount it - see irlap_driver_rcv(). */
- skb_get(skb);
- self->notify.connect_indication(self->notify.instance, self,
- &self->qos, max_seg_size,
- max_header_size, skb);
- }
-}
-
-/*
- * Function irlmp_connect_response (handle, userdata)
- *
- * Service user is accepting connection
- *
- */
-int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata)
-{
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
- IRDA_ASSERT(userdata != NULL, return -1;);
-
- /* We set the connected bit and move the lsap to the connected list
- * in the state machine itself. Jean II */
-
- pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
- __func__, self->slsap_sel, self->dlsap_sel);
-
- /* Make room for MUX control header (3 bytes) */
- IRDA_ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;);
- skb_push(userdata, LMP_CONTROL_HEADER);
-
- irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata);
-
- /* Drop reference count - see irlap_data_request(). */
- dev_kfree_skb(userdata);
-
- return 0;
-}
-EXPORT_SYMBOL(irlmp_connect_response);
-
-/*
- * Function irlmp_connect_confirm (handle, skb)
- *
- * LSAP connection confirmed peer device!
- */
-void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb)
-{
- int max_header_size;
- int lap_header_size;
- int max_seg_size;
-
- IRDA_ASSERT(skb != NULL, return;);
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
- IRDA_ASSERT(self->lap != NULL, return;);
-
- self->qos = *self->lap->qos;
-
- max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
- lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap);
- max_header_size = LMP_HEADER + lap_header_size;
-
- pr_debug("%s(), max_header_size=%d\n",
- __func__, max_header_size);
-
- /* Hide LMP_CONTROL_HEADER header from layer above */
- skb_pull(skb, LMP_CONTROL_HEADER);
-
- if (self->notify.connect_confirm) {
- /* Don't forget to refcount it - see irlap_driver_rcv() */
- skb_get(skb);
- self->notify.connect_confirm(self->notify.instance, self,
- &self->qos, max_seg_size,
- max_header_size, skb);
- }
-}
-
-/*
- * Function irlmp_dup (orig, instance)
- *
- * Duplicate LSAP, can be used by servers to confirm a connection on a
- * new LSAP so it can keep listening on the old one.
- *
- */
-struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance)
-{
- struct lsap_cb *new;
- unsigned long flags;
-
- spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags);
-
- /* Only allowed to duplicate unconnected LSAP's, and only LSAPs
- * that have received a connect indication. Jean II */
- if ((!hashbin_find(irlmp->unconnected_lsaps, (long) orig, NULL)) ||
- (orig->lap == NULL)) {
- pr_debug("%s(), invalid LSAP (wrong state)\n",
- __func__);
- spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock,
- flags);
- return NULL;
- }
-
- /* Allocate a new instance */
- new = kmemdup(orig, sizeof(*new), GFP_ATOMIC);
- if (!new) {
- pr_debug("%s(), unable to kmalloc\n", __func__);
- spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock,
- flags);
- return NULL;
- }
- /* new->lap = orig->lap; => done in the memcpy() */
- /* new->slsap_sel = orig->slsap_sel; => done in the memcpy() */
- new->conn_skb = NULL;
-
- spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags);
-
- /* Not everything is the same */
- new->notify.instance = instance;
-
- timer_setup(&new->watchdog_timer, NULL, 0);
-
- hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) new,
- (long) new, NULL);
-
-#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
- /* Make sure that we invalidate the LSAP cache */
- new->lap->cache.valid = FALSE;
-#endif /* CONFIG_IRDA_CACHE_LAST_LSAP */
-
- return new;
-}
-
-/*
- * Function irlmp_disconnect_request (handle, userdata)
- *
- * The service user is requesting disconnection, this will not remove the
- * LSAP, but only mark it as disconnected
- */
-int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata)
-{
- struct lsap_cb *lsap;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
- IRDA_ASSERT(userdata != NULL, return -1;);
-
- /* Already disconnected ?
- * There is a race condition between irlmp_disconnect_indication()
- * and us that might mess up the hashbins below. This fixes it.
- * Jean II */
- if (! test_and_clear_bit(0, &self->connected)) {
- pr_debug("%s(), already disconnected!\n", __func__);
- dev_kfree_skb(userdata);
- return -1;
- }
-
- skb_push(userdata, LMP_CONTROL_HEADER);
-
- /*
- * Do the event before the other stuff since we must know
- * which lap layer that the frame should be transmitted on
- */
- irlmp_do_lsap_event(self, LM_DISCONNECT_REQUEST, userdata);
-
- /* Drop reference count - see irlap_data_request(). */
- dev_kfree_skb(userdata);
-
- /*
- * Remove LSAP from list of connected LSAPs for the particular link
- * and insert it into the list of unconnected LSAPs
- */
- IRDA_ASSERT(self->lap != NULL, return -1;);
- IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
- IRDA_ASSERT(self->lap->lsaps != NULL, return -1;);
-
- lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL);
-#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
- self->lap->cache.valid = FALSE;
-#endif
-
- IRDA_ASSERT(lsap != NULL, return -1;);
- IRDA_ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
- IRDA_ASSERT(lsap == self, return -1;);
-
- hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self,
- (long) self, NULL);
-
- /* Reset some values */
- self->dlsap_sel = LSAP_ANY;
- self->lap = NULL;
-
- return 0;
-}
-EXPORT_SYMBOL(irlmp_disconnect_request);
-
-/*
- * Function irlmp_disconnect_indication (reason, userdata)
- *
- * LSAP is being closed!
- */
-void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
- struct sk_buff *skb)
-{
- struct lsap_cb *lsap;
-
- pr_debug("%s(), reason=%s [%d]\n", __func__,
- irlmp_reason_str(reason), reason);
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
-
- pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
- __func__, self->slsap_sel, self->dlsap_sel);
-
- /* Already disconnected ?
- * There is a race condition between irlmp_disconnect_request()
- * and us that might mess up the hashbins below. This fixes it.
- * Jean II */
- if (! test_and_clear_bit(0, &self->connected)) {
- pr_debug("%s(), already disconnected!\n", __func__);
- return;
- }
-
- /*
- * Remove association between this LSAP and the link it used
- */
- IRDA_ASSERT(self->lap != NULL, return;);
- IRDA_ASSERT(self->lap->lsaps != NULL, return;);
-
- lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL);
-#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
- self->lap->cache.valid = FALSE;
-#endif
-
- IRDA_ASSERT(lsap != NULL, return;);
- IRDA_ASSERT(lsap == self, return;);
- hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap,
- (long) lsap, NULL);
-
- self->dlsap_sel = LSAP_ANY;
- self->lap = NULL;
-
- /*
- * Inform service user
- */
- if (self->notify.disconnect_indication) {
- /* Don't forget to refcount it - see irlap_driver_rcv(). */
- if(skb)
- skb_get(skb);
- self->notify.disconnect_indication(self->notify.instance,
- self, reason, skb);
- } else {
- pr_debug("%s(), no handler\n", __func__);
- }
-}
-
-/*
- * Function irlmp_do_expiry (void)
- *
- * Do a cleanup of the discovery log (remove old entries)
- *
- * Note : separate from irlmp_do_discovery() so that we can handle
- * passive discovery properly.
- */
-void irlmp_do_expiry(void)
-{
- struct lap_cb *lap;
-
- /*
- * Expire discovery on all links which are *not* connected.
- * On links which are connected, we can't do discovery
- * anymore and can't refresh the log, so we freeze the
- * discovery log to keep info about the device we are
- * connected to.
- * This info is mandatory if we want irlmp_connect_request()
- * to work properly. - Jean II
- */
- lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
- while (lap != NULL) {
- IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
-
- if (lap->lap_state == LAP_STANDBY) {
- /* Expire discoveries discovered on this link */
- irlmp_expire_discoveries(irlmp->cachelog, lap->saddr,
- FALSE);
- }
- lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
- }
-}
-
-/*
- * Function irlmp_do_discovery (nslots)
- *
- * Do some discovery on all links
- *
- * Note : log expiry is done above.
- */
-void irlmp_do_discovery(int nslots)
-{
- struct lap_cb *lap;
- __u16 *data_hintsp;
-
- /* Make sure the value is sane */
- if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){
- net_warn_ratelimited("%s: invalid value for number of slots!\n",
- __func__);
- nslots = sysctl_discovery_slots = 8;
- }
-
- /* Construct new discovery info to be used by IrLAP, */
- data_hintsp = (__u16 *) irlmp->discovery_cmd.data.hints;
- put_unaligned(irlmp->hints.word, data_hintsp);
-
- /*
- * Set character set for device name (we use ASCII), and
- * copy device name. Remember to make room for a \0 at the
- * end
- */
- irlmp->discovery_cmd.data.charset = CS_ASCII;
- strncpy(irlmp->discovery_cmd.data.info, sysctl_devname,
- NICKNAME_MAX_LEN);
- irlmp->discovery_cmd.name_len = strlen(irlmp->discovery_cmd.data.info);
- irlmp->discovery_cmd.nslots = nslots;
-
- /*
- * Try to send discovery packets on all links
- */
- lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
- while (lap != NULL) {
- IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
-
- if (lap->lap_state == LAP_STANDBY) {
- /* Try to discover */
- irlmp_do_lap_event(lap, LM_LAP_DISCOVERY_REQUEST,
- NULL);
- }
- lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
- }
-}
-
-/*
- * Function irlmp_discovery_request (nslots)
- *
- * Do a discovery of devices in front of the computer
- *
- * If the caller has registered a client discovery callback, this
- * allow him to receive the full content of the discovery log through
- * this callback (as normally he will receive only new discoveries).
- */
-void irlmp_discovery_request(int nslots)
-{
- /* Return current cached discovery log (in full) */
- irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_LOG);
-
- /*
- * Start a single discovery operation if discovery is not already
- * running
- */
- if (!sysctl_discovery) {
- /* Check if user wants to override the default */
- if (nslots == DISCOVERY_DEFAULT_SLOTS)
- nslots = sysctl_discovery_slots;
-
- irlmp_do_discovery(nslots);
- /* Note : we never do expiry here. Expiry will run on the
- * discovery timer regardless of the state of sysctl_discovery
- * Jean II */
- }
-}
-EXPORT_SYMBOL(irlmp_discovery_request);
-
-/*
- * Function irlmp_get_discoveries (pn, mask, slots)
- *
- * Return the current discovery log
- *
- * If discovery is not enabled, you should call this function again
- * after 1 or 2 seconds (i.e. after discovery has been done).
- */
-struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots)
-{
- /* If discovery is not enabled, it's likely that the discovery log
- * will be empty. So, we trigger a single discovery, so that next
- * time the user call us there might be some results in the log.
- * Jean II
- */
- if (!sysctl_discovery) {
- /* Check if user wants to override the default */
- if (nslots == DISCOVERY_DEFAULT_SLOTS)
- nslots = sysctl_discovery_slots;
-
- /* Start discovery - will complete sometime later */
- irlmp_do_discovery(nslots);
- /* Note : we never do expiry here. Expiry will run on the
- * discovery timer regardless of the state of sysctl_discovery
- * Jean II */
- }
-
- /* Return current cached discovery log */
- return irlmp_copy_discoveries(irlmp->cachelog, pn, mask, TRUE);
-}
-EXPORT_SYMBOL(irlmp_get_discoveries);
-
-/*
- * Function irlmp_notify_client (log)
- *
- * Notify all about discovered devices
- *
- * Clients registered with IrLMP are :
- * o IrComm
- * o IrLAN
- * o Any socket (in any state - ouch, that may be a lot !)
- * The client may have defined a callback to be notified in case of
- * partial/selective discovery based on the hints that it passed to IrLMP.
- */
-static inline void
-irlmp_notify_client(irlmp_client_t *client,
- hashbin_t *log, DISCOVERY_MODE mode)
-{
- discinfo_t *discoveries; /* Copy of the discovery log */
- int number; /* Number of nodes in the log */
- int i;
-
- /* Check if client wants or not partial/selective log (optimisation) */
- if (!client->disco_callback)
- return;
-
- /*
- * Locking notes :
- * the old code was manipulating the log directly, which was
- * very racy. Now, we use copy_discoveries, that protects
- * itself while dumping the log for us.
- * The overhead of the copy is compensated by the fact that
- * we only pass new discoveries in normal mode and don't
- * pass the same old entry every 3s to the caller as we used
- * to do (virtual function calling is expensive).
- * Jean II
- */
-
- /*
- * Now, check all discovered devices (if any), and notify client
- * only about the services that the client is interested in
- * We also notify only about the new devices unless the caller
- * explicitly request a dump of the log. Jean II
- */
- discoveries = irlmp_copy_discoveries(log, &number,
- client->hint_mask.word,
- (mode == DISCOVERY_LOG));
- /* Check if the we got some results */
- if (discoveries == NULL)
- return; /* No nodes discovered */
-
- /* Pass all entries to the listener */
- for(i = 0; i < number; i++)
- client->disco_callback(&(discoveries[i]), mode, client->priv);
-
- /* Free up our buffer */
- kfree(discoveries);
-}
-
-/*
- * Function irlmp_discovery_confirm ( self, log)
- *
- * Some device(s) answered to our discovery request! Check to see which
- * device it is, and give indication to the client(s)
- *
- */
-void irlmp_discovery_confirm(hashbin_t *log, DISCOVERY_MODE mode)
-{
- irlmp_client_t *client;
- irlmp_client_t *client_next;
-
- IRDA_ASSERT(log != NULL, return;);
-
- if (!(HASHBIN_GET_SIZE(log)))
- return;
-
- /* For each client - notify callback may touch client list */
- client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
- while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL,
- (void *) &client_next) ) {
- /* Check if we should notify client */
- irlmp_notify_client(client, log, mode);
-
- client = client_next;
- }
-}
-
-/*
- * Function irlmp_discovery_expiry (expiry)
- *
- * This device is no longer been discovered, and therefore it is being
- * purged from the discovery log. Inform all clients who have
- * registered for this event...
- *
- * Note : called exclusively from discovery.c
- * Note : this is no longer called under discovery spinlock, so the
- * client can do whatever he wants in the callback.
- */
-void irlmp_discovery_expiry(discinfo_t *expiries, int number)
-{
- irlmp_client_t *client;
- irlmp_client_t *client_next;
- int i;
-
- IRDA_ASSERT(expiries != NULL, return;);
-
- /* For each client - notify callback may touch client list */
- client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
- while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL,
- (void *) &client_next) ) {
-
- /* Pass all entries to the listener */
- for(i = 0; i < number; i++) {
- /* Check if we should notify client */
- if ((client->expir_callback) &&
- (client->hint_mask.word &
- get_unaligned((__u16 *)expiries[i].hints)
- & 0x7f7f) )
- client->expir_callback(&(expiries[i]),
- EXPIRY_TIMEOUT,
- client->priv);
- }
-
- /* Next client */
- client = client_next;
- }
-}
-
-/*
- * Function irlmp_get_discovery_response ()
- *
- * Used by IrLAP to get the discovery info it needs when answering
- * discovery requests by other devices.
- */
-discovery_t *irlmp_get_discovery_response(void)
-{
- IRDA_ASSERT(irlmp != NULL, return NULL;);
-
- put_unaligned(irlmp->hints.word, (__u16 *)irlmp->discovery_rsp.data.hints);
-
- /*
- * Set character set for device name (we use ASCII), and
- * copy device name. Remember to make room for a \0 at the
- * end
- */
- irlmp->discovery_rsp.data.charset = CS_ASCII;
-
- strncpy(irlmp->discovery_rsp.data.info, sysctl_devname,
- NICKNAME_MAX_LEN);
- irlmp->discovery_rsp.name_len = strlen(irlmp->discovery_rsp.data.info);
-
- return &irlmp->discovery_rsp;
-}
-
-/*
- * Function irlmp_data_request (self, skb)
- *
- * Send some data to peer device
- *
- * Note on skb management :
- * After calling the lower layers of the IrDA stack, we always
- * kfree() the skb, which drop the reference count (and potentially
- * destroy it).
- * IrLMP and IrLAP may queue the packet, and in those cases will need
- * to use skb_get() to keep it around.
- * Jean II
- */
-int irlmp_data_request(struct lsap_cb *self, struct sk_buff *userdata)
-{
- int ret;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
-
- /* Make room for MUX header */
- IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;);
- skb_push(userdata, LMP_HEADER);
-
- ret = irlmp_do_lsap_event(self, LM_DATA_REQUEST, userdata);
-
- /* Drop reference count - see irlap_data_request(). */
- dev_kfree_skb(userdata);
-
- return ret;
-}
-EXPORT_SYMBOL(irlmp_data_request);
-
-/*
- * Function irlmp_data_indication (handle, skb)
- *
- * Got data from LAP layer so pass it up to upper layer
- *
- */
-void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb)
-{
- /* Hide LMP header from layer above */
- skb_pull(skb, LMP_HEADER);
-
- if (self->notify.data_indication) {
- /* Don't forget to refcount it - see irlap_driver_rcv(). */
- skb_get(skb);
- self->notify.data_indication(self->notify.instance, self, skb);
- }
-}
-
-/*
- * Function irlmp_udata_request (self, skb)
- */
-int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *userdata)
-{
- int ret;
-
- IRDA_ASSERT(userdata != NULL, return -1;);
-
- /* Make room for MUX header */
- IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;);
- skb_push(userdata, LMP_HEADER);
-
- ret = irlmp_do_lsap_event(self, LM_UDATA_REQUEST, userdata);
-
- /* Drop reference count - see irlap_data_request(). */
- dev_kfree_skb(userdata);
-
- return ret;
-}
-
-/*
- * Function irlmp_udata_indication (self, skb)
- *
- * Send unreliable data (but still within the connection)
- *
- */
-void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
-
- /* Hide LMP header from layer above */
- skb_pull(skb, LMP_HEADER);
-
- if (self->notify.udata_indication) {
- /* Don't forget to refcount it - see irlap_driver_rcv(). */
- skb_get(skb);
- self->notify.udata_indication(self->notify.instance, self,
- skb);
- }
-}
-
-/*
- * Function irlmp_connless_data_request (self, skb)
- */
-#ifdef CONFIG_IRDA_ULTRA
-int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *userdata,
- __u8 pid)
-{
- struct sk_buff *clone_skb;
- struct lap_cb *lap;
-
- IRDA_ASSERT(userdata != NULL, return -1;);
-
- /* Make room for MUX and PID header */
- IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER+LMP_PID_HEADER,
- return -1;);
-
- /* Insert protocol identifier */
- skb_push(userdata, LMP_PID_HEADER);
- if(self != NULL)
- userdata->data[0] = self->pid;
- else
- userdata->data[0] = pid;
-
- /* Connectionless sockets must use 0x70 */
- skb_push(userdata, LMP_HEADER);
- userdata->data[0] = userdata->data[1] = LSAP_CONNLESS;
-
- /* Try to send Connectionless packets out on all links */
- lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
- while (lap != NULL) {
- IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;);
-
- clone_skb = skb_clone(userdata, GFP_ATOMIC);
- if (!clone_skb) {
- dev_kfree_skb(userdata);
- return -ENOMEM;
- }
-
- irlap_unitdata_request(lap->irlap, clone_skb);
- /* irlap_unitdata_request() don't increase refcount,
- * so no dev_kfree_skb() - Jean II */
-
- lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
- }
- dev_kfree_skb(userdata);
-
- return 0;
-}
-#endif /* CONFIG_IRDA_ULTRA */
-
-/*
- * Function irlmp_connless_data_indication (self, skb)
- *
- * Receive unreliable data outside any connection. Mostly used by Ultra
- *
- */
-#ifdef CONFIG_IRDA_ULTRA
-void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
-
- /* Hide LMP and PID header from layer above */
- skb_pull(skb, LMP_HEADER+LMP_PID_HEADER);
-
- if (self->notify.udata_indication) {
- /* Don't forget to refcount it - see irlap_driver_rcv(). */
- skb_get(skb);
- self->notify.udata_indication(self->notify.instance, self,
- skb);
- }
-}
-#endif /* CONFIG_IRDA_ULTRA */
-
-/*
- * Propagate status indication from LAP to LSAPs (via LMP)
- * This don't trigger any change of state in lap_cb, lmp_cb or lsap_cb,
- * and the event is stateless, therefore we can bypass both state machines
- * and send the event direct to the LSAP user.
- * Jean II
- */
-void irlmp_status_indication(struct lap_cb *self,
- LINK_STATUS link, LOCK_STATUS lock)
-{
- struct lsap_cb *next;
- struct lsap_cb *curr;
-
- /* Send status_indication to all LSAPs using this link */
- curr = (struct lsap_cb *) hashbin_get_first( self->lsaps);
- while (NULL != hashbin_find_next(self->lsaps, (long) curr, NULL,
- (void *) &next) ) {
- IRDA_ASSERT(curr->magic == LMP_LSAP_MAGIC, return;);
- /*
- * Inform service user if he has requested it
- */
- if (curr->notify.status_indication != NULL)
- curr->notify.status_indication(curr->notify.instance,
- link, lock);
- else
- pr_debug("%s(), no handler\n", __func__);
-
- curr = next;
- }
-}
-
-/*
- * Receive flow control indication from LAP.
- * LAP want us to send it one more frame. We implement a simple round
- * robin scheduler between the active sockets so that we get a bit of
- * fairness. Note that the round robin is far from perfect, but it's
- * better than nothing.
- * We then poll the selected socket so that we can do synchronous
- * refilling of IrLAP (which allow to minimise the number of buffers).
- * Jean II
- */
-void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow)
-{
- struct lsap_cb *next;
- struct lsap_cb *curr;
- int lsap_todo;
-
- IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
- IRDA_ASSERT(flow == FLOW_START, return;);
-
- /* Get the number of lsap. That's the only safe way to know
- * that we have looped around... - Jean II */
- lsap_todo = HASHBIN_GET_SIZE(self->lsaps);
- pr_debug("%s() : %d lsaps to scan\n", __func__, lsap_todo);
-
- /* Poll lsap in order until the queue is full or until we
- * tried them all.
- * Most often, the current LSAP will have something to send,
- * so we will go through this loop only once. - Jean II */
- while((lsap_todo--) &&
- (IRLAP_GET_TX_QUEUE_LEN(self->irlap) < LAP_HIGH_THRESHOLD)) {
- /* Try to find the next lsap we should poll. */
- next = self->flow_next;
- /* If we have no lsap, restart from first one */
- if(next == NULL)
- next = (struct lsap_cb *) hashbin_get_first(self->lsaps);
- /* Verify current one and find the next one */
- curr = hashbin_find_next(self->lsaps, (long) next, NULL,
- (void *) &self->flow_next);
- /* Uh-oh... Paranoia */
- if(curr == NULL)
- break;
- pr_debug("%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n",
- __func__, curr, next, self->flow_next, lsap_todo,
- IRLAP_GET_TX_QUEUE_LEN(self->irlap));
-
- /* Inform lsap user that it can send one more packet. */
- if (curr->notify.flow_indication != NULL)
- curr->notify.flow_indication(curr->notify.instance,
- curr, flow);
- else
- pr_debug("%s(), no handler\n", __func__);
- }
-}
-
-#if 0
-/*
- * Function irlmp_hint_to_service (hint)
- *
- * Returns a list of all servics contained in the given hint bits. This
- * function assumes that the hint bits have the size of two bytes only
- */
-__u8 *irlmp_hint_to_service(__u8 *hint)
-{
- __u8 *service;
- int i = 0;
-
- /*
- * Allocate array to store services in. 16 entries should be safe
- * since we currently only support 2 hint bytes
- */
- service = kmalloc(16, GFP_ATOMIC);
- if (!service)
- return NULL;
-
- if (!hint[0]) {
- pr_debug("<None>\n");
- kfree(service);
- return NULL;
- }
- if (hint[0] & HINT_PNP)
- pr_debug("PnP Compatible ");
- if (hint[0] & HINT_PDA)
- pr_debug("PDA/Palmtop ");
- if (hint[0] & HINT_COMPUTER)
- pr_debug("Computer ");
- if (hint[0] & HINT_PRINTER) {
- pr_debug("Printer ");
- service[i++] = S_PRINTER;
- }
- if (hint[0] & HINT_MODEM)
- pr_debug("Modem ");
- if (hint[0] & HINT_FAX)
- pr_debug("Fax ");
- if (hint[0] & HINT_LAN) {
- pr_debug("LAN Access ");
- service[i++] = S_LAN;
- }
- /*
- * Test if extension byte exists. This byte will usually be
- * there, but this is not really required by the standard.
- * (IrLMP p. 29)
- */
- if (hint[0] & HINT_EXTENSION) {
- if (hint[1] & HINT_TELEPHONY) {
- pr_debug("Telephony ");
- service[i++] = S_TELEPHONY;
- }
- if (hint[1] & HINT_FILE_SERVER)
- pr_debug("File Server ");
-
- if (hint[1] & HINT_COMM) {
- pr_debug("IrCOMM ");
- service[i++] = S_COMM;
- }
- if (hint[1] & HINT_OBEX) {
- pr_debug("IrOBEX ");
- service[i++] = S_OBEX;
- }
- }
- pr_debug("\n");
-
- /* So that client can be notified about any discovery */
- service[i++] = S_ANY;
-
- service[i] = S_END;
-
- return service;
-}
-#endif
-
-static const __u16 service_hint_mapping[S_END][2] = {
- { HINT_PNP, 0 }, /* S_PNP */
- { HINT_PDA, 0 }, /* S_PDA */
- { HINT_COMPUTER, 0 }, /* S_COMPUTER */
- { HINT_PRINTER, 0 }, /* S_PRINTER */
- { HINT_MODEM, 0 }, /* S_MODEM */
- { HINT_FAX, 0 }, /* S_FAX */
- { HINT_LAN, 0 }, /* S_LAN */
- { HINT_EXTENSION, HINT_TELEPHONY }, /* S_TELEPHONY */
- { HINT_EXTENSION, HINT_COMM }, /* S_COMM */
- { HINT_EXTENSION, HINT_OBEX }, /* S_OBEX */
- { 0xFF, 0xFF }, /* S_ANY */
-};
-
-/*
- * Function irlmp_service_to_hint (service)
- *
- * Converts a service type, to a hint bit
- *
- * Returns: a 16 bit hint value, with the service bit set
- */
-__u16 irlmp_service_to_hint(int service)
-{
- __u16_host_order hint;
-
- hint.byte[0] = service_hint_mapping[service][0];
- hint.byte[1] = service_hint_mapping[service][1];
-
- return hint.word;
-}
-EXPORT_SYMBOL(irlmp_service_to_hint);
-
-/*
- * Function irlmp_register_service (service)
- *
- * Register local service with IrLMP
- *
- */
-void *irlmp_register_service(__u16 hints)
-{
- irlmp_service_t *service;
-
- pr_debug("%s(), hints = %04x\n", __func__, hints);
-
- /* Make a new registration */
- service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC);
- if (!service)
- return NULL;
-
- service->hints.word = hints;
- hashbin_insert(irlmp->services, (irda_queue_t *) service,
- (long) service, NULL);
-
- irlmp->hints.word |= hints;
-
- return (void *)service;
-}
-EXPORT_SYMBOL(irlmp_register_service);
-
-/*
- * Function irlmp_unregister_service (handle)
- *
- * Unregister service with IrLMP.
- *
- * Returns: 0 on success, -1 on error
- */
-int irlmp_unregister_service(void *handle)
-{
- irlmp_service_t *service;
- unsigned long flags;
-
- if (!handle)
- return -1;
-
- /* Caller may call with invalid handle (it's legal) - Jean II */
- service = hashbin_lock_find(irlmp->services, (long) handle, NULL);
- if (!service) {
- pr_debug("%s(), Unknown service!\n", __func__);
- return -1;
- }
-
- hashbin_remove_this(irlmp->services, (irda_queue_t *) service);
- kfree(service);
-
- /* Remove old hint bits */
- irlmp->hints.word = 0;
-
- /* Refresh current hint bits */
- spin_lock_irqsave(&irlmp->services->hb_spinlock, flags);
- service = (irlmp_service_t *) hashbin_get_first(irlmp->services);
- while (service) {
- irlmp->hints.word |= service->hints.word;
-
- service = (irlmp_service_t *)hashbin_get_next(irlmp->services);
- }
- spin_unlock_irqrestore(&irlmp->services->hb_spinlock, flags);
- return 0;
-}
-EXPORT_SYMBOL(irlmp_unregister_service);
-
-/*
- * Function irlmp_register_client (hint_mask, callback1, callback2)
- *
- * Register a local client with IrLMP
- * First callback is selective discovery (based on hints)
- * Second callback is for selective discovery expiries
- *
- * Returns: handle > 0 on success, 0 on error
- */
-void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
- DISCOVERY_CALLBACK2 expir_clb, void *priv)
-{
- irlmp_client_t *client;
-
- IRDA_ASSERT(irlmp != NULL, return NULL;);
-
- /* Make a new registration */
- client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC);
- if (!client)
- return NULL;
-
- /* Register the details */
- client->hint_mask.word = hint_mask;
- client->disco_callback = disco_clb;
- client->expir_callback = expir_clb;
- client->priv = priv;
-
- hashbin_insert(irlmp->clients, (irda_queue_t *) client,
- (long) client, NULL);
-
- return (void *) client;
-}
-EXPORT_SYMBOL(irlmp_register_client);
-
-/*
- * Function irlmp_update_client (handle, hint_mask, callback1, callback2)
- *
- * Updates specified client (handle) with possibly new hint_mask and
- * callback
- *
- * Returns: 0 on success, -1 on error
- */
-int irlmp_update_client(void *handle, __u16 hint_mask,
- DISCOVERY_CALLBACK1 disco_clb,
- DISCOVERY_CALLBACK2 expir_clb, void *priv)
-{
- irlmp_client_t *client;
-
- if (!handle)
- return -1;
-
- client = hashbin_lock_find(irlmp->clients, (long) handle, NULL);
- if (!client) {
- pr_debug("%s(), Unknown client!\n", __func__);
- return -1;
- }
-
- client->hint_mask.word = hint_mask;
- client->disco_callback = disco_clb;
- client->expir_callback = expir_clb;
- client->priv = priv;
-
- return 0;
-}
-EXPORT_SYMBOL(irlmp_update_client);
-
-/*
- * Function irlmp_unregister_client (handle)
- *
- * Returns: 0 on success, -1 on error
- *
- */
-int irlmp_unregister_client(void *handle)
-{
- struct irlmp_client *client;
-
- if (!handle)
- return -1;
-
- /* Caller may call with invalid handle (it's legal) - Jean II */
- client = hashbin_lock_find(irlmp->clients, (long) handle, NULL);
- if (!client) {
- pr_debug("%s(), Unknown client!\n", __func__);
- return -1;
- }
-
- pr_debug("%s(), removing client!\n", __func__);
- hashbin_remove_this(irlmp->clients, (irda_queue_t *) client);
- kfree(client);
-
- return 0;
-}
-EXPORT_SYMBOL(irlmp_unregister_client);
-
-/*
- * Function irlmp_slsap_inuse (slsap)
- *
- * Check if the given source LSAP selector is in use
- *
- * This function is clearly not very efficient. On the mitigating side, the
- * stack make sure that in 99% of the cases, we are called only once
- * for each socket allocation. We could probably keep a bitmap
- * of the allocated LSAP, but I'm not sure the complexity is worth it.
- * Jean II
- */
-static int irlmp_slsap_inuse(__u8 slsap_sel)
-{
- struct lsap_cb *self;
- struct lap_cb *lap;
- unsigned long flags;
-
- IRDA_ASSERT(irlmp != NULL, return TRUE;);
- IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;);
- IRDA_ASSERT(slsap_sel != LSAP_ANY, return TRUE;);
-
-#ifdef CONFIG_IRDA_ULTRA
- /* Accept all bindings to the connectionless LSAP */
- if (slsap_sel == LSAP_CONNLESS)
- return FALSE;
-#endif /* CONFIG_IRDA_ULTRA */
-
- /* Valid values are between 0 and 127 (0x0-0x6F) */
- if (slsap_sel > LSAP_MAX)
- return TRUE;
-
- /*
- * Check if slsap is already in use. To do this we have to loop over
- * every IrLAP connection and check every LSAP associated with each
- * the connection.
- */
- spin_lock_irqsave_nested(&irlmp->links->hb_spinlock, flags,
- SINGLE_DEPTH_NESTING);
- lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
- while (lap != NULL) {
- IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, goto errlap;);
-
- /* Careful for priority inversions here !
- * irlmp->links is never taken while another IrDA
- * spinlock is held, so we are safe. Jean II */
- spin_lock(&lap->lsaps->hb_spinlock);
-
- /* For this IrLAP, check all the LSAPs */
- self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
- while (self != NULL) {
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC,
- goto errlsap;);
-
- if (self->slsap_sel == slsap_sel) {
- pr_debug("Source LSAP selector=%02x in use\n",
- self->slsap_sel);
- goto errlsap;
- }
- self = (struct lsap_cb*) hashbin_get_next(lap->lsaps);
- }
- spin_unlock(&lap->lsaps->hb_spinlock);
-
- /* Next LAP */
- lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
- }
- spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags);
-
- /*
- * Server sockets are typically waiting for connections and
- * therefore reside in the unconnected list. We don't want
- * to give out their LSAPs for obvious reasons...
- * Jean II
- */
- spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags);
-
- self = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps);
- while (self != NULL) {
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, goto erruncon;);
- if (self->slsap_sel == slsap_sel) {
- pr_debug("Source LSAP selector=%02x in use (unconnected)\n",
- self->slsap_sel);
- goto erruncon;
- }
- self = (struct lsap_cb*) hashbin_get_next(irlmp->unconnected_lsaps);
- }
- spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags);
-
- return FALSE;
-
- /* Error exit from within one of the two nested loops.
- * Make sure we release the right spinlock in the righ order.
- * Jean II */
-errlsap:
- spin_unlock(&lap->lsaps->hb_spinlock);
-IRDA_ASSERT_LABEL(errlap:)
- spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags);
- return TRUE;
-
- /* Error exit from within the unconnected loop.
- * Just one spinlock to release... Jean II */
-erruncon:
- spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags);
- return TRUE;
-}
-
-/*
- * Function irlmp_find_free_slsap ()
- *
- * Find a free source LSAP to use. This function is called if the service
- * user has requested a source LSAP equal to LM_ANY
- */
-static __u8 irlmp_find_free_slsap(void)
-{
- __u8 lsap_sel;
- int wrapped = 0;
-
- IRDA_ASSERT(irlmp != NULL, return -1;);
- IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return -1;);
-
- /* Most users don't really care which LSAPs they are given,
- * and therefore we automatically give them a free LSAP.
- * This function try to find a suitable LSAP, i.e. which is
- * not in use and is within the acceptable range. Jean II */
-
- do {
- /* Always increment to LSAP number before using it.
- * In theory, we could reuse the last LSAP number, as long
- * as it is no longer in use. Some IrDA stack do that.
- * However, the previous socket may be half closed, i.e.
- * we closed it, we think it's no longer in use, but the
- * other side did not receive our close and think it's
- * active and still send data on it.
- * This is similar to what is done with PIDs and TCP ports.
- * Also, this reduce the number of calls to irlmp_slsap_inuse()
- * which is an expensive function to call.
- * Jean II */
- irlmp->last_lsap_sel++;
-
- /* Check if we need to wraparound (0x70-0x7f are reserved) */
- if (irlmp->last_lsap_sel > LSAP_MAX) {
- /* 0x00-0x10 are also reserved for well know ports */
- irlmp->last_lsap_sel = 0x10;
-
- /* Make sure we terminate the loop */
- if (wrapped++) {
- net_err_ratelimited("%s: no more free LSAPs !\n",
- __func__);
- return 0;
- }
- }
-
- /* If the LSAP is in use, try the next one.
- * Despite the autoincrement, we need to check if the lsap
- * is really in use or not, first because LSAP may be
- * directly allocated in irlmp_open_lsap(), and also because
- * we may wraparound on old sockets. Jean II */
- } while (irlmp_slsap_inuse(irlmp->last_lsap_sel));
-
- /* Got it ! */
- lsap_sel = irlmp->last_lsap_sel;
- pr_debug("%s(), found free lsap_sel=%02x\n",
- __func__, lsap_sel);
-
- return lsap_sel;
-}
-
-/*
- * Function irlmp_convert_lap_reason (lap_reason)
- *
- * Converts IrLAP disconnect reason codes to IrLMP disconnect reason
- * codes
- *
- */
-LM_REASON irlmp_convert_lap_reason( LAP_REASON lap_reason)
-{
- int reason = LM_LAP_DISCONNECT;
-
- switch (lap_reason) {
- case LAP_DISC_INDICATION: /* Received a disconnect request from peer */
- pr_debug("%s(), LAP_DISC_INDICATION\n", __func__);
- reason = LM_USER_REQUEST;
- break;
- case LAP_NO_RESPONSE: /* To many retransmits without response */
- pr_debug("%s(), LAP_NO_RESPONSE\n", __func__);
- reason = LM_LAP_DISCONNECT;
- break;
- case LAP_RESET_INDICATION:
- pr_debug("%s(), LAP_RESET_INDICATION\n", __func__);
- reason = LM_LAP_RESET;
- break;
- case LAP_FOUND_NONE:
- case LAP_MEDIA_BUSY:
- case LAP_PRIMARY_CONFLICT:
- pr_debug("%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n",
- __func__);
- reason = LM_CONNECT_FAILURE;
- break;
- default:
- pr_debug("%s(), Unknown IrLAP disconnect reason %d!\n",
- __func__, lap_reason);
- reason = LM_LAP_DISCONNECT;
- break;
- }
-
- return reason;
-}
-
-#ifdef CONFIG_PROC_FS
-
-struct irlmp_iter_state {
- hashbin_t *hashbin;
-};
-
-#define LSAP_START_TOKEN ((void *)1)
-#define LINK_START_TOKEN ((void *)2)
-
-static void *irlmp_seq_hb_idx(struct irlmp_iter_state *iter, loff_t *off)
-{
- void *element;
-
- spin_lock_irq(&iter->hashbin->hb_spinlock);
- for (element = hashbin_get_first(iter->hashbin);
- element != NULL;
- element = hashbin_get_next(iter->hashbin)) {
- if (!off || (*off)-- == 0) {
- /* NB: hashbin left locked */
- return element;
- }
- }
- spin_unlock_irq(&iter->hashbin->hb_spinlock);
- iter->hashbin = NULL;
- return NULL;
-}
-
-
-static void *irlmp_seq_start(struct seq_file *seq, loff_t *pos)
-{
- struct irlmp_iter_state *iter = seq->private;
- void *v;
- loff_t off = *pos;
-
- iter->hashbin = NULL;
- if (off-- == 0)
- return LSAP_START_TOKEN;
-
- iter->hashbin = irlmp->unconnected_lsaps;
- v = irlmp_seq_hb_idx(iter, &off);
- if (v)
- return v;
-
- if (off-- == 0)
- return LINK_START_TOKEN;
-
- iter->hashbin = irlmp->links;
- return irlmp_seq_hb_idx(iter, &off);
-}
-
-static void *irlmp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- struct irlmp_iter_state *iter = seq->private;
-
- ++*pos;
-
- if (v == LSAP_START_TOKEN) { /* start of list of lsaps */
- iter->hashbin = irlmp->unconnected_lsaps;
- v = irlmp_seq_hb_idx(iter, NULL);
- return v ? v : LINK_START_TOKEN;
- }
-
- if (v == LINK_START_TOKEN) { /* start of list of links */
- iter->hashbin = irlmp->links;
- return irlmp_seq_hb_idx(iter, NULL);
- }
-
- v = hashbin_get_next(iter->hashbin);
-
- if (v == NULL) { /* no more in this hash bin */
- spin_unlock_irq(&iter->hashbin->hb_spinlock);
-
- if (iter->hashbin == irlmp->unconnected_lsaps)
- v = LINK_START_TOKEN;
-
- iter->hashbin = NULL;
- }
- return v;
-}
-
-static void irlmp_seq_stop(struct seq_file *seq, void *v)
-{
- struct irlmp_iter_state *iter = seq->private;
-
- if (iter->hashbin)
- spin_unlock_irq(&iter->hashbin->hb_spinlock);
-}
-
-static int irlmp_seq_show(struct seq_file *seq, void *v)
-{
- const struct irlmp_iter_state *iter = seq->private;
- struct lsap_cb *self = v;
-
- if (v == LSAP_START_TOKEN)
- seq_puts(seq, "Unconnected LSAPs:\n");
- else if (v == LINK_START_TOKEN)
- seq_puts(seq, "\nRegistered Link Layers:\n");
- else if (iter->hashbin == irlmp->unconnected_lsaps) {
- self = v;
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -EINVAL; );
- seq_printf(seq, "lsap state: %s, ",
- irlsap_state[ self->lsap_state]);
- seq_printf(seq,
- "slsap_sel: %#02x, dlsap_sel: %#02x, ",
- self->slsap_sel, self->dlsap_sel);
- seq_printf(seq, "(%s)", self->notify.name);
- seq_printf(seq, "\n");
- } else if (iter->hashbin == irlmp->links) {
- struct lap_cb *lap = v;
-
- seq_printf(seq, "lap state: %s, ",
- irlmp_state[lap->lap_state]);
-
- seq_printf(seq, "saddr: %#08x, daddr: %#08x, ",
- lap->saddr, lap->daddr);
- seq_printf(seq, "num lsaps: %d",
- HASHBIN_GET_SIZE(lap->lsaps));
- seq_printf(seq, "\n");
-
- /* Careful for priority inversions here !
- * All other uses of attrib spinlock are independent of
- * the object spinlock, so we are safe. Jean II */
- spin_lock(&lap->lsaps->hb_spinlock);
-
- seq_printf(seq, "\n Connected LSAPs:\n");
- for (self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
- self != NULL;
- self = (struct lsap_cb *)hashbin_get_next(lap->lsaps)) {
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC,
- goto outloop;);
- seq_printf(seq, " lsap state: %s, ",
- irlsap_state[ self->lsap_state]);
- seq_printf(seq,
- "slsap_sel: %#02x, dlsap_sel: %#02x, ",
- self->slsap_sel, self->dlsap_sel);
- seq_printf(seq, "(%s)", self->notify.name);
- seq_putc(seq, '\n');
-
- }
- IRDA_ASSERT_LABEL(outloop:)
- spin_unlock(&lap->lsaps->hb_spinlock);
- seq_putc(seq, '\n');
- } else
- return -EINVAL;
-
- return 0;
-}
-
-static const struct seq_operations irlmp_seq_ops = {
- .start = irlmp_seq_start,
- .next = irlmp_seq_next,
- .stop = irlmp_seq_stop,
- .show = irlmp_seq_show,
-};
-
-static int irlmp_seq_open(struct inode *inode, struct file *file)
-{
- IRDA_ASSERT(irlmp != NULL, return -EINVAL;);
-
- return seq_open_private(file, &irlmp_seq_ops,
- sizeof(struct irlmp_iter_state));
-}
-
-const struct file_operations irlmp_seq_fops = {
- .owner = THIS_MODULE,
- .open = irlmp_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_private,
-};
-
-#endif /* PROC_FS */
diff --git a/drivers/staging/irda/net/irlmp_event.c b/drivers/staging/irda/net/irlmp_event.c
deleted file mode 100644
index ddad0994b6dc..000000000000
--- a/drivers/staging/irda/net/irlmp_event.c
+++ /dev/null
@@ -1,886 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlmp_event.c
- * Version: 0.8
- * Description: An IrDA LMP event driver for Linux
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Aug 4 20:40:53 1997
- * Modified at: Tue Dec 14 23:04:16 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/kernel.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/timer.h>
-#include <net/irda/irlap.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/irlmp_frame.h>
-#include <net/irda/irlmp_event.h>
-
-const char *const irlmp_state[] = {
- "LAP_STANDBY",
- "LAP_U_CONNECT",
- "LAP_ACTIVE",
-};
-
-const char *const irlsap_state[] = {
- "LSAP_DISCONNECTED",
- "LSAP_CONNECT",
- "LSAP_CONNECT_PEND",
- "LSAP_DATA_TRANSFER_READY",
- "LSAP_SETUP",
- "LSAP_SETUP_PEND",
-};
-
-static const char *const irlmp_event[] __maybe_unused = {
- "LM_CONNECT_REQUEST",
- "LM_CONNECT_CONFIRM",
- "LM_CONNECT_RESPONSE",
- "LM_CONNECT_INDICATION",
-
- "LM_DISCONNECT_INDICATION",
- "LM_DISCONNECT_REQUEST",
-
- "LM_DATA_REQUEST",
- "LM_UDATA_REQUEST",
- "LM_DATA_INDICATION",
- "LM_UDATA_INDICATION",
-
- "LM_WATCHDOG_TIMEOUT",
-
- /* IrLAP events */
- "LM_LAP_CONNECT_REQUEST",
- "LM_LAP_CONNECT_INDICATION",
- "LM_LAP_CONNECT_CONFIRM",
- "LM_LAP_DISCONNECT_INDICATION",
- "LM_LAP_DISCONNECT_REQUEST",
- "LM_LAP_DISCOVERY_REQUEST",
- "LM_LAP_DISCOVERY_CONFIRM",
- "LM_LAP_IDLE_TIMEOUT",
-};
-
-/* LAP Connection control proto declarations */
-static void irlmp_state_standby (struct lap_cb *, IRLMP_EVENT,
- struct sk_buff *);
-static void irlmp_state_u_connect(struct lap_cb *, IRLMP_EVENT,
- struct sk_buff *);
-static void irlmp_state_active (struct lap_cb *, IRLMP_EVENT,
- struct sk_buff *);
-
-/* LSAP Connection control proto declarations */
-static int irlmp_state_disconnected(struct lsap_cb *, IRLMP_EVENT,
- struct sk_buff *);
-static int irlmp_state_connect (struct lsap_cb *, IRLMP_EVENT,
- struct sk_buff *);
-static int irlmp_state_connect_pend(struct lsap_cb *, IRLMP_EVENT,
- struct sk_buff *);
-static int irlmp_state_dtr (struct lsap_cb *, IRLMP_EVENT,
- struct sk_buff *);
-static int irlmp_state_setup (struct lsap_cb *, IRLMP_EVENT,
- struct sk_buff *);
-static int irlmp_state_setup_pend (struct lsap_cb *, IRLMP_EVENT,
- struct sk_buff *);
-
-static void (*lap_state[]) (struct lap_cb *, IRLMP_EVENT, struct sk_buff *) =
-{
- irlmp_state_standby,
- irlmp_state_u_connect,
- irlmp_state_active,
-};
-
-static int (*lsap_state[])( struct lsap_cb *, IRLMP_EVENT, struct sk_buff *) =
-{
- irlmp_state_disconnected,
- irlmp_state_connect,
- irlmp_state_connect_pend,
- irlmp_state_dtr,
- irlmp_state_setup,
- irlmp_state_setup_pend
-};
-
-static inline void irlmp_next_lap_state(struct lap_cb *self,
- IRLMP_STATE state)
-{
- /*
- pr_debug("%s(), LMP LAP = %s\n", __func__, irlmp_state[state]);
- */
- self->lap_state = state;
-}
-
-static inline void irlmp_next_lsap_state(struct lsap_cb *self,
- LSAP_STATE state)
-{
- /*
- IRDA_ASSERT(self != NULL, return;);
- pr_debug("%s(), LMP LSAP = %s\n", __func__, irlsap_state[state]);
- */
- self->lsap_state = state;
-}
-
-/* Do connection control events */
-int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
-
- pr_debug("%s(), EVENT = %s, STATE = %s\n",
- __func__, irlmp_event[event], irlsap_state[self->lsap_state]);
-
- return (*lsap_state[self->lsap_state]) (self, event, skb);
-}
-
-/*
- * Function do_lap_event (event, skb, info)
- *
- * Do IrLAP control events
- *
- */
-void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
-
- pr_debug("%s(), EVENT = %s, STATE = %s\n", __func__,
- irlmp_event[event],
- irlmp_state[self->lap_state]);
-
- (*lap_state[self->lap_state]) (self, event, skb);
-}
-
-void irlmp_discovery_timer_expired(struct timer_list *t)
-{
- /* We always cleanup the log (active & passive discovery) */
- irlmp_do_expiry();
-
- irlmp_do_discovery(sysctl_discovery_slots);
-
- /* Restart timer */
- irlmp_start_discovery_timer(irlmp, sysctl_discovery_timeout * HZ);
-}
-
-void irlmp_watchdog_timer_expired(struct timer_list *t)
-{
- struct lsap_cb *self = from_timer(self, t, watchdog_timer);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
-
- irlmp_do_lsap_event(self, LM_WATCHDOG_TIMEOUT, NULL);
-}
-
-void irlmp_idle_timer_expired(struct timer_list *t)
-{
- struct lap_cb *self = from_timer(self, t, idle_timer);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
-
- irlmp_do_lap_event(self, LM_LAP_IDLE_TIMEOUT, NULL);
-}
-
-/*
- * Send an event on all LSAPs attached to this LAP.
- */
-static inline void
-irlmp_do_all_lsap_event(hashbin_t * lsap_hashbin,
- IRLMP_EVENT event)
-{
- struct lsap_cb *lsap;
- struct lsap_cb *lsap_next;
-
- /* Note : this function use the new hashbin_find_next()
- * function, instead of the old hashbin_get_next().
- * This make sure that we are always pointing one lsap
- * ahead, so that if the current lsap is removed as the
- * result of sending the event, we don't care.
- * Also, as we store the context ourselves, if an enumeration
- * of the same lsap hashbin happens as the result of sending the
- * event, we don't care.
- * The only problem is if the next lsap is removed. In that case,
- * hashbin_find_next() will return NULL and we will abort the
- * enumeration. - Jean II */
-
- /* Also : we don't accept any skb in input. We can *NOT* pass
- * the same skb to multiple clients safely, we would need to
- * skb_clone() it. - Jean II */
-
- lsap = (struct lsap_cb *) hashbin_get_first(lsap_hashbin);
-
- while (NULL != hashbin_find_next(lsap_hashbin,
- (long) lsap,
- NULL,
- (void *) &lsap_next) ) {
- irlmp_do_lsap_event(lsap, event, NULL);
- lsap = lsap_next;
- }
-}
-
-/*********************************************************************
- *
- * LAP connection control states
- *
- ********************************************************************/
-
-/*
- * Function irlmp_state_standby (event, skb, info)
- *
- * STANDBY, The IrLAP connection does not exist.
- *
- */
-static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self->irlap != NULL, return;);
-
- switch (event) {
- case LM_LAP_DISCOVERY_REQUEST:
- /* irlmp_next_station_state( LMP_DISCOVER); */
-
- irlap_discovery_request(self->irlap, &irlmp->discovery_cmd);
- break;
- case LM_LAP_CONNECT_INDICATION:
- /* It's important to switch state first, to avoid IrLMP to
- * think that the link is free since IrLMP may then start
- * discovery before the connection is properly set up. DB.
- */
- irlmp_next_lap_state(self, LAP_ACTIVE);
-
- /* Just accept connection TODO, this should be fixed */
- irlap_connect_response(self->irlap, skb);
- break;
- case LM_LAP_CONNECT_REQUEST:
- pr_debug("%s() LS_CONNECT_REQUEST\n", __func__);
-
- irlmp_next_lap_state(self, LAP_U_CONNECT);
-
- /* FIXME: need to set users requested QoS */
- irlap_connect_request(self->irlap, self->daddr, NULL, 0);
- break;
- case LM_LAP_DISCONNECT_INDICATION:
- pr_debug("%s(), Error LM_LAP_DISCONNECT_INDICATION\n",
- __func__);
-
- irlmp_next_lap_state(self, LAP_STANDBY);
- break;
- default:
- pr_debug("%s(), Unknown event %s\n",
- __func__, irlmp_event[event]);
- break;
- }
-}
-
-/*
- * Function irlmp_state_u_connect (event, skb, info)
- *
- * U_CONNECT, The layer above has tried to open an LSAP connection but
- * since the IrLAP connection does not exist, we must first start an
- * IrLAP connection. We are now waiting response from IrLAP.
- * */
-static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
- struct sk_buff *skb)
-{
- pr_debug("%s(), event=%s\n", __func__, irlmp_event[event]);
-
- switch (event) {
- case LM_LAP_CONNECT_INDICATION:
- /* It's important to switch state first, to avoid IrLMP to
- * think that the link is free since IrLMP may then start
- * discovery before the connection is properly set up. DB.
- */
- irlmp_next_lap_state(self, LAP_ACTIVE);
-
- /* Just accept connection TODO, this should be fixed */
- irlap_connect_response(self->irlap, skb);
-
- /* Tell LSAPs that they can start sending data */
- irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);
-
- /* Note : by the time we get there (LAP retries and co),
- * the lsaps may already have gone. This avoid getting stuck
- * forever in LAP_ACTIVE state - Jean II */
- if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
- pr_debug("%s() NO LSAPs !\n", __func__);
- irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
- }
- break;
- case LM_LAP_CONNECT_REQUEST:
- /* Already trying to connect */
- break;
- case LM_LAP_CONNECT_CONFIRM:
- /* For all lsap_ce E Associated do LS_Connect_confirm */
- irlmp_next_lap_state(self, LAP_ACTIVE);
-
- /* Tell LSAPs that they can start sending data */
- irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);
-
- /* Note : by the time we get there (LAP retries and co),
- * the lsaps may already have gone. This avoid getting stuck
- * forever in LAP_ACTIVE state - Jean II */
- if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
- pr_debug("%s() NO LSAPs !\n", __func__);
- irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
- }
- break;
- case LM_LAP_DISCONNECT_INDICATION:
- pr_debug("%s(), LM_LAP_DISCONNECT_INDICATION\n", __func__);
- irlmp_next_lap_state(self, LAP_STANDBY);
-
- /* Send disconnect event to all LSAPs using this link */
- irlmp_do_all_lsap_event(self->lsaps,
- LM_LAP_DISCONNECT_INDICATION);
- break;
- case LM_LAP_DISCONNECT_REQUEST:
- pr_debug("%s(), LM_LAP_DISCONNECT_REQUEST\n", __func__);
-
- /* One of the LSAP did timeout or was closed, if it was
- * the last one, try to get out of here - Jean II */
- if (HASHBIN_GET_SIZE(self->lsaps) <= 1) {
- irlap_disconnect_request(self->irlap);
- }
- break;
- default:
- pr_debug("%s(), Unknown event %s\n",
- __func__, irlmp_event[event]);
- break;
- }
-}
-
-/*
- * Function irlmp_state_active (event, skb, info)
- *
- * ACTIVE, IrLAP connection is active
- *
- */
-static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
- struct sk_buff *skb)
-{
- switch (event) {
- case LM_LAP_CONNECT_REQUEST:
- pr_debug("%s(), LS_CONNECT_REQUEST\n", __func__);
-
- /*
- * IrLAP may have a pending disconnect. We tried to close
- * IrLAP, but it was postponed because the link was
- * busy or we were still sending packets. As we now
- * need it, make sure it stays on. Jean II
- */
- irlap_clear_disconnect(self->irlap);
-
- /*
- * LAP connection already active, just bounce back! Since we
- * don't know which LSAP that tried to do this, we have to
- * notify all LSAPs using this LAP, but that should be safe to
- * do anyway.
- */
- irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);
-
- /* Needed by connect indication */
- irlmp_do_all_lsap_event(irlmp->unconnected_lsaps,
- LM_LAP_CONNECT_CONFIRM);
- /* Keep state */
- break;
- case LM_LAP_DISCONNECT_REQUEST:
- /*
- * Need to find out if we should close IrLAP or not. If there
- * is only one LSAP connection left on this link, that LSAP
- * must be the one that tries to close IrLAP. It will be
- * removed later and moved to the list of unconnected LSAPs
- */
- if (HASHBIN_GET_SIZE(self->lsaps) > 0) {
- /* Timer value is checked in irsysctl - Jean II */
- irlmp_start_idle_timer(self, sysctl_lap_keepalive_time * HZ / 1000);
- } else {
- /* No more connections, so close IrLAP */
-
- /* We don't want to change state just yet, because
- * we want to reflect accurately the real state of
- * the LAP, not the state we wish it was in,
- * so that we don't lose LM_LAP_CONNECT_REQUEST.
- * In some cases, IrLAP won't close the LAP
- * immediately. For example, it might still be
- * retrying packets or waiting for the pf bit.
- * As the LAP always send a DISCONNECT_INDICATION
- * in PCLOSE or SCLOSE, just change state on that.
- * Jean II */
- irlap_disconnect_request(self->irlap);
- }
- break;
- case LM_LAP_IDLE_TIMEOUT:
- if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
- /* Same reasoning as above - keep state */
- irlap_disconnect_request(self->irlap);
- }
- break;
- case LM_LAP_DISCONNECT_INDICATION:
- irlmp_next_lap_state(self, LAP_STANDBY);
-
- /* In some case, at this point our side has already closed
- * all lsaps, and we are waiting for the idle_timer to
- * expire. If another device reconnect immediately, the
- * idle timer will expire in the midle of the connection
- * initialisation, screwing up things a lot...
- * Therefore, we must stop the timer... */
- irlmp_stop_idle_timer(self);
-
- /*
- * Inform all connected LSAP's using this link
- */
- irlmp_do_all_lsap_event(self->lsaps,
- LM_LAP_DISCONNECT_INDICATION);
-
- /* Force an expiry of the discovery log.
- * Now that the LAP is free, the system may attempt to
- * connect to another device. Unfortunately, our entries
- * are stale. There is a small window (<3s) before the
- * normal discovery will run and where irlmp_connect_request()
- * can get the wrong info, so make sure things get
- * cleaned *NOW* ;-) - Jean II */
- irlmp_do_expiry();
- break;
- default:
- pr_debug("%s(), Unknown event %s\n",
- __func__, irlmp_event[event]);
- break;
- }
-}
-
-/*********************************************************************
- *
- * LSAP connection control states
- *
- ********************************************************************/
-
-/*
- * Function irlmp_state_disconnected (event, skb, info)
- *
- * DISCONNECTED
- *
- */
-static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
- struct sk_buff *skb)
-{
- int ret = 0;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
-
- switch (event) {
-#ifdef CONFIG_IRDA_ULTRA
- case LM_UDATA_INDICATION:
- /* This is most bizarre. Those packets are aka unreliable
- * connected, aka IrLPT or SOCK_DGRAM/IRDAPROTO_UNITDATA.
- * Why do we pass them as Ultra ??? Jean II */
- irlmp_connless_data_indication(self, skb);
- break;
-#endif /* CONFIG_IRDA_ULTRA */
- case LM_CONNECT_REQUEST:
- pr_debug("%s(), LM_CONNECT_REQUEST\n", __func__);
-
- if (self->conn_skb) {
- net_warn_ratelimited("%s: busy with another request!\n",
- __func__);
- return -EBUSY;
- }
- /* Don't forget to refcount it (see irlmp_connect_request()) */
- skb_get(skb);
- self->conn_skb = skb;
-
- irlmp_next_lsap_state(self, LSAP_SETUP_PEND);
-
- /* Start watchdog timer (5 secs for now) */
- irlmp_start_watchdog_timer(self, 5*HZ);
-
- irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
- break;
- case LM_CONNECT_INDICATION:
- if (self->conn_skb) {
- net_warn_ratelimited("%s: busy with another request!\n",
- __func__);
- return -EBUSY;
- }
- /* Don't forget to refcount it (see irlap_driver_rcv()) */
- skb_get(skb);
- self->conn_skb = skb;
-
- irlmp_next_lsap_state(self, LSAP_CONNECT_PEND);
-
- /* Start watchdog timer
- * This is not mentionned in the spec, but there is a rare
- * race condition that can get the socket stuck.
- * If we receive this event while our LAP is closing down,
- * the LM_LAP_CONNECT_REQUEST get lost and we get stuck in
- * CONNECT_PEND state forever.
- * The other cause of getting stuck down there is if the
- * higher layer never reply to the CONNECT_INDICATION.
- * Anyway, it make sense to make sure that we always have
- * a backup plan. 1 second is plenty (should be immediate).
- * Jean II */
- irlmp_start_watchdog_timer(self, 1*HZ);
-
- irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
- break;
- default:
- pr_debug("%s(), Unknown event %s on LSAP %#02x\n",
- __func__, irlmp_event[event], self->slsap_sel);
- break;
- }
- return ret;
-}
-
-/*
- * Function irlmp_state_connect (self, event, skb)
- *
- * CONNECT
- *
- */
-static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event,
- struct sk_buff *skb)
-{
- struct lsap_cb *lsap;
- int ret = 0;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
-
- switch (event) {
- case LM_CONNECT_RESPONSE:
- /*
- * Bind this LSAP to the IrLAP link where the connect was
- * received
- */
- lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self,
- NULL);
-
- IRDA_ASSERT(lsap == self, return -1;);
- IRDA_ASSERT(self->lap != NULL, return -1;);
- IRDA_ASSERT(self->lap->lsaps != NULL, return -1;);
-
- hashbin_insert(self->lap->lsaps, (irda_queue_t *) self,
- (long) self, NULL);
-
- set_bit(0, &self->connected); /* TRUE */
-
- irlmp_send_lcf_pdu(self->lap, self->dlsap_sel,
- self->slsap_sel, CONNECT_CNF, skb);
-
- del_timer(&self->watchdog_timer);
-
- irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY);
- break;
- case LM_WATCHDOG_TIMEOUT:
- /* May happen, who knows...
- * Jean II */
- pr_debug("%s() WATCHDOG_TIMEOUT!\n", __func__);
-
- /* Disconnect, get out... - Jean II */
- self->lap = NULL;
- self->dlsap_sel = LSAP_ANY;
- irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
- break;
- default:
- /* LM_LAP_DISCONNECT_INDICATION : Should never happen, we
- * are *not* yet bound to the IrLAP link. Jean II */
- pr_debug("%s(), Unknown event %s on LSAP %#02x\n",
- __func__, irlmp_event[event], self->slsap_sel);
- break;
- }
- return ret;
-}
-
-/*
- * Function irlmp_state_connect_pend (event, skb, info)
- *
- * CONNECT_PEND
- *
- */
-static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
- struct sk_buff *skb)
-{
- struct sk_buff *tx_skb;
- int ret = 0;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
-
- switch (event) {
- case LM_CONNECT_REQUEST:
- /* Keep state */
- break;
- case LM_CONNECT_RESPONSE:
- pr_debug("%s(), LM_CONNECT_RESPONSE, no indication issued yet\n",
- __func__);
- /* Keep state */
- break;
- case LM_DISCONNECT_REQUEST:
- pr_debug("%s(), LM_DISCONNECT_REQUEST, not yet bound to IrLAP connection\n",
- __func__);
- /* Keep state */
- break;
- case LM_LAP_CONNECT_CONFIRM:
- pr_debug("%s(), LS_CONNECT_CONFIRM\n", __func__);
- irlmp_next_lsap_state(self, LSAP_CONNECT);
-
- tx_skb = self->conn_skb;
- self->conn_skb = NULL;
-
- irlmp_connect_indication(self, tx_skb);
- /* Drop reference count - see irlmp_connect_indication(). */
- dev_kfree_skb(tx_skb);
- break;
- case LM_WATCHDOG_TIMEOUT:
- /* Will happen in some rare cases because of a race condition.
- * Just make sure we don't stay there forever...
- * Jean II */
- pr_debug("%s() WATCHDOG_TIMEOUT!\n", __func__);
-
- /* Go back to disconnected mode, keep the socket waiting */
- self->lap = NULL;
- self->dlsap_sel = LSAP_ANY;
- if(self->conn_skb)
- dev_kfree_skb(self->conn_skb);
- self->conn_skb = NULL;
- irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
- break;
- default:
- /* LM_LAP_DISCONNECT_INDICATION : Should never happen, we
- * are *not* yet bound to the IrLAP link. Jean II */
- pr_debug("%s(), Unknown event %s on LSAP %#02x\n",
- __func__, irlmp_event[event], self->slsap_sel);
- break;
- }
- return ret;
-}
-
-/*
- * Function irlmp_state_dtr (self, event, skb)
- *
- * DATA_TRANSFER_READY
- *
- */
-static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event,
- struct sk_buff *skb)
-{
- LM_REASON reason;
- int ret = 0;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
- IRDA_ASSERT(self->lap != NULL, return -1;);
-
- switch (event) {
- case LM_DATA_REQUEST: /* Optimize for the common case */
- irlmp_send_data_pdu(self->lap, self->dlsap_sel,
- self->slsap_sel, FALSE, skb);
- break;
- case LM_DATA_INDICATION: /* Optimize for the common case */
- irlmp_data_indication(self, skb);
- break;
- case LM_UDATA_REQUEST:
- IRDA_ASSERT(skb != NULL, return -1;);
- irlmp_send_data_pdu(self->lap, self->dlsap_sel,
- self->slsap_sel, TRUE, skb);
- break;
- case LM_UDATA_INDICATION:
- irlmp_udata_indication(self, skb);
- break;
- case LM_CONNECT_REQUEST:
- pr_debug("%s(), LM_CONNECT_REQUEST, error, LSAP already connected\n",
- __func__);
- /* Keep state */
- break;
- case LM_CONNECT_RESPONSE:
- pr_debug("%s(), LM_CONNECT_RESPONSE, error, LSAP already connected\n",
- __func__);
- /* Keep state */
- break;
- case LM_DISCONNECT_REQUEST:
- irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, self->slsap_sel,
- DISCONNECT, skb);
- irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
- /* Called only from irlmp_disconnect_request(), will
- * unbind from LAP over there. Jean II */
-
- /* Try to close the LAP connection if its still there */
- if (self->lap) {
- pr_debug("%s(), trying to close IrLAP\n",
- __func__);
- irlmp_do_lap_event(self->lap,
- LM_LAP_DISCONNECT_REQUEST,
- NULL);
- }
- break;
- case LM_LAP_DISCONNECT_INDICATION:
- irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
-
- reason = irlmp_convert_lap_reason(self->lap->reason);
-
- irlmp_disconnect_indication(self, reason, NULL);
- break;
- case LM_DISCONNECT_INDICATION:
- irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
-
- IRDA_ASSERT(self->lap != NULL, return -1;);
- IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
-
- IRDA_ASSERT(skb != NULL, return -1;);
- IRDA_ASSERT(skb->len > 3, return -1;);
- reason = skb->data[3];
-
- /* Try to close the LAP connection */
- pr_debug("%s(), trying to close IrLAP\n", __func__);
- irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
-
- irlmp_disconnect_indication(self, reason, skb);
- break;
- default:
- pr_debug("%s(), Unknown event %s on LSAP %#02x\n",
- __func__, irlmp_event[event], self->slsap_sel);
- break;
- }
- return ret;
-}
-
-/*
- * Function irlmp_state_setup (event, skb, info)
- *
- * SETUP, Station Control has set up the underlying IrLAP connection.
- * An LSAP connection request has been transmitted to the peer
- * LSAP-Connection Control FSM and we are awaiting reply.
- */
-static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event,
- struct sk_buff *skb)
-{
- LM_REASON reason;
- int ret = 0;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
-
- switch (event) {
- case LM_CONNECT_CONFIRM:
- irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY);
-
- del_timer(&self->watchdog_timer);
-
- irlmp_connect_confirm(self, skb);
- break;
- case LM_DISCONNECT_INDICATION:
- irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
-
- IRDA_ASSERT(self->lap != NULL, return -1;);
- IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
-
- IRDA_ASSERT(skb != NULL, return -1;);
- IRDA_ASSERT(skb->len > 3, return -1;);
- reason = skb->data[3];
-
- /* Try to close the LAP connection */
- pr_debug("%s(), trying to close IrLAP\n", __func__);
- irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
-
- irlmp_disconnect_indication(self, reason, skb);
- break;
- case LM_LAP_DISCONNECT_INDICATION:
- irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
-
- del_timer(&self->watchdog_timer);
-
- IRDA_ASSERT(self->lap != NULL, return -1;);
- IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
-
- reason = irlmp_convert_lap_reason(self->lap->reason);
-
- irlmp_disconnect_indication(self, reason, skb);
- break;
- case LM_WATCHDOG_TIMEOUT:
- pr_debug("%s() WATCHDOG_TIMEOUT!\n", __func__);
-
- IRDA_ASSERT(self->lap != NULL, return -1;);
- irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
- irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
-
- irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL);
- break;
- default:
- pr_debug("%s(), Unknown event %s on LSAP %#02x\n",
- __func__, irlmp_event[event], self->slsap_sel);
- break;
- }
- return ret;
-}
-
-/*
- * Function irlmp_state_setup_pend (event, skb, info)
- *
- * SETUP_PEND, An LM_CONNECT_REQUEST has been received from the service
- * user to set up an LSAP connection. A request has been sent to the
- * LAP FSM to set up the underlying IrLAP connection, and we
- * are awaiting confirm.
- */
-static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event,
- struct sk_buff *skb)
-{
- struct sk_buff *tx_skb;
- LM_REASON reason;
- int ret = 0;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(irlmp != NULL, return -1;);
-
- switch (event) {
- case LM_LAP_CONNECT_CONFIRM:
- IRDA_ASSERT(self->conn_skb != NULL, return -1;);
-
- tx_skb = self->conn_skb;
- self->conn_skb = NULL;
-
- irlmp_send_lcf_pdu(self->lap, self->dlsap_sel,
- self->slsap_sel, CONNECT_CMD, tx_skb);
- /* Drop reference count - see irlap_data_request(). */
- dev_kfree_skb(tx_skb);
-
- irlmp_next_lsap_state(self, LSAP_SETUP);
- break;
- case LM_WATCHDOG_TIMEOUT:
- pr_debug("%s() : WATCHDOG_TIMEOUT !\n", __func__);
-
- IRDA_ASSERT(self->lap != NULL, return -1;);
- irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
- irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
-
- irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL);
- break;
- case LM_LAP_DISCONNECT_INDICATION: /* LS_Disconnect.indication */
- del_timer( &self->watchdog_timer);
-
- irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
-
- reason = irlmp_convert_lap_reason(self->lap->reason);
-
- irlmp_disconnect_indication(self, reason, NULL);
- break;
- default:
- pr_debug("%s(), Unknown event %s on LSAP %#02x\n",
- __func__, irlmp_event[event], self->slsap_sel);
- break;
- }
- return ret;
-}
diff --git a/drivers/staging/irda/net/irlmp_frame.c b/drivers/staging/irda/net/irlmp_frame.c
deleted file mode 100644
index 38b0f994bc7b..000000000000
--- a/drivers/staging/irda/net/irlmp_frame.c
+++ /dev/null
@@ -1,476 +0,0 @@
-/*********************************************************************
- *
- * Filename: irlmp_frame.c
- * Version: 0.9
- * Description: IrLMP frame implementation
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Tue Aug 19 02:09:59 1997
- * Modified at: Mon Dec 13 13:41:12 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
- * All Rights Reserved.
- * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/skbuff.h>
-#include <linux/kernel.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irlap.h>
-#include <net/irda/timer.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/irlmp_frame.h>
-#include <net/irda/discovery.h>
-
-static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap,
- __u8 slsap, int status, hashbin_t *);
-
-inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
- int expedited, struct sk_buff *skb)
-{
- skb->data[0] = dlsap;
- skb->data[1] = slsap;
-
- if (expedited) {
- pr_debug("%s(), sending expedited data\n", __func__);
- irlap_data_request(self->irlap, skb, TRUE);
- } else
- irlap_data_request(self->irlap, skb, FALSE);
-}
-
-/*
- * Function irlmp_send_lcf_pdu (dlsap, slsap, opcode,skb)
- *
- * Send Link Control Frame to IrLAP
- */
-void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
- __u8 opcode, struct sk_buff *skb)
-{
- __u8 *frame;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
-
- frame = skb->data;
-
- frame[0] = dlsap | CONTROL_BIT;
- frame[1] = slsap;
-
- frame[2] = opcode;
-
- if (opcode == DISCONNECT)
- frame[3] = 0x01; /* Service user request */
- else
- frame[3] = 0x00; /* rsvd */
-
- irlap_data_request(self->irlap, skb, FALSE);
-}
-
-/*
- * Function irlmp_input (skb)
- *
- * Used by IrLAP to pass received data frames to IrLMP layer
- *
- */
-void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
- int unreliable)
-{
- struct lsap_cb *lsap;
- __u8 slsap_sel; /* Source (this) LSAP address */
- __u8 dlsap_sel; /* Destination LSAP address */
- __u8 *fp;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
- IRDA_ASSERT(skb->len > 2, return;);
-
- fp = skb->data;
-
- /*
- * The next statements may be confusing, but we do this so that
- * destination LSAP of received frame is source LSAP in our view
- */
- slsap_sel = fp[0] & LSAP_MASK;
- dlsap_sel = fp[1];
-
- /*
- * Check if this is an incoming connection, since we must deal with
- * it in a different way than other established connections.
- */
- if ((fp[0] & CONTROL_BIT) && (fp[2] == CONNECT_CMD)) {
- pr_debug("%s(), incoming connection, source LSAP=%d, dest LSAP=%d\n",
- __func__, slsap_sel, dlsap_sel);
-
- /* Try to find LSAP among the unconnected LSAPs */
- lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, CONNECT_CMD,
- irlmp->unconnected_lsaps);
-
- /* Maybe LSAP was already connected, so try one more time */
- if (!lsap) {
- pr_debug("%s(), incoming connection for LSAP already connected\n",
- __func__);
- lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0,
- self->lsaps);
- }
- } else
- lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0,
- self->lsaps);
-
- if (lsap == NULL) {
- pr_debug("IrLMP, Sorry, no LSAP for received frame!\n");
- pr_debug("%s(), slsap_sel = %02x, dlsap_sel = %02x\n",
- __func__, slsap_sel, dlsap_sel);
- if (fp[0] & CONTROL_BIT) {
- pr_debug("%s(), received control frame %02x\n",
- __func__, fp[2]);
- } else {
- pr_debug("%s(), received data frame\n", __func__);
- }
- return;
- }
-
- /*
- * Check if we received a control frame?
- */
- if (fp[0] & CONTROL_BIT) {
- switch (fp[2]) {
- case CONNECT_CMD:
- lsap->lap = self;
- irlmp_do_lsap_event(lsap, LM_CONNECT_INDICATION, skb);
- break;
- case CONNECT_CNF:
- irlmp_do_lsap_event(lsap, LM_CONNECT_CONFIRM, skb);
- break;
- case DISCONNECT:
- pr_debug("%s(), Disconnect indication!\n",
- __func__);
- irlmp_do_lsap_event(lsap, LM_DISCONNECT_INDICATION,
- skb);
- break;
- case ACCESSMODE_CMD:
- pr_debug("Access mode cmd not implemented!\n");
- break;
- case ACCESSMODE_CNF:
- pr_debug("Access mode cnf not implemented!\n");
- break;
- default:
- pr_debug("%s(), Unknown control frame %02x\n",
- __func__, fp[2]);
- break;
- }
- } else if (unreliable) {
- /* Optimize and bypass the state machine if possible */
- if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
- irlmp_udata_indication(lsap, skb);
- else
- irlmp_do_lsap_event(lsap, LM_UDATA_INDICATION, skb);
- } else {
- /* Optimize and bypass the state machine if possible */
- if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
- irlmp_data_indication(lsap, skb);
- else
- irlmp_do_lsap_event(lsap, LM_DATA_INDICATION, skb);
- }
-}
-
-/*
- * Function irlmp_link_unitdata_indication (self, skb)
- *
- *
- *
- */
-#ifdef CONFIG_IRDA_ULTRA
-void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb)
-{
- struct lsap_cb *lsap;
- __u8 slsap_sel; /* Source (this) LSAP address */
- __u8 dlsap_sel; /* Destination LSAP address */
- __u8 pid; /* Protocol identifier */
- __u8 *fp;
- unsigned long flags;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
- IRDA_ASSERT(skb->len > 2, return;);
-
- fp = skb->data;
-
- /*
- * The next statements may be confusing, but we do this so that
- * destination LSAP of received frame is source LSAP in our view
- */
- slsap_sel = fp[0] & LSAP_MASK;
- dlsap_sel = fp[1];
- pid = fp[2];
-
- if (pid & 0x80) {
- pr_debug("%s(), extension in PID not supp!\n",
- __func__);
- return;
- }
-
- /* Check if frame is addressed to the connectionless LSAP */
- if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) {
- pr_debug("%s(), dropping frame!\n", __func__);
- return;
- }
-
- /* Search the connectionless LSAP */
- spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags);
- lsap = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps);
- while (lsap != NULL) {
- /*
- * Check if source LSAP and dest LSAP selectors and PID match.
- */
- if ((lsap->slsap_sel == slsap_sel) &&
- (lsap->dlsap_sel == dlsap_sel) &&
- (lsap->pid == pid))
- {
- break;
- }
- lsap = (struct lsap_cb *) hashbin_get_next(irlmp->unconnected_lsaps);
- }
- spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags);
-
- if (lsap)
- irlmp_connless_data_indication(lsap, skb);
- else {
- pr_debug("%s(), found no matching LSAP!\n", __func__);
- }
-}
-#endif /* CONFIG_IRDA_ULTRA */
-
-/*
- * Function irlmp_link_disconnect_indication (reason, userdata)
- *
- * IrLAP has disconnected
- *
- */
-void irlmp_link_disconnect_indication(struct lap_cb *lap,
- struct irlap_cb *irlap,
- LAP_REASON reason,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(lap != NULL, return;);
- IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
-
- lap->reason = reason;
- lap->daddr = DEV_ADDR_ANY;
-
- /* FIXME: must do something with the skb if any */
-
- /*
- * Inform station state machine
- */
- irlmp_do_lap_event(lap, LM_LAP_DISCONNECT_INDICATION, NULL);
-}
-
-/*
- * Function irlmp_link_connect_indication (qos)
- *
- * Incoming LAP connection!
- *
- */
-void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr,
- __u32 daddr, struct qos_info *qos,
- struct sk_buff *skb)
-{
- /* Copy QoS settings for this session */
- self->qos = qos;
-
- /* Update destination device address */
- self->daddr = daddr;
- IRDA_ASSERT(self->saddr == saddr, return;);
-
- irlmp_do_lap_event(self, LM_LAP_CONNECT_INDICATION, skb);
-}
-
-/*
- * Function irlmp_link_connect_confirm (qos)
- *
- * LAP connection confirmed!
- *
- */
-void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos,
- struct sk_buff *skb)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
- IRDA_ASSERT(qos != NULL, return;);
-
- /* Don't need use the skb for now */
-
- /* Copy QoS settings for this session */
- self->qos = qos;
-
- irlmp_do_lap_event(self, LM_LAP_CONNECT_CONFIRM, NULL);
-}
-
-/*
- * Function irlmp_link_discovery_indication (self, log)
- *
- * Device is discovering us
- *
- * It's not an answer to our own discoveries, just another device trying
- * to perform discovery, but we don't want to miss the opportunity
- * to exploit this information, because :
- * o We may not actively perform discovery (just passive discovery)
- * o This type of discovery is much more reliable. In some cases, it
- * seem that less than 50% of our discoveries get an answer, while
- * we always get ~100% of these.
- * o Make faster discovery, statistically divide time of discovery
- * events by 2 (important for the latency aspect and user feel)
- * o Even is we do active discovery, the other node might not
- * answer our discoveries (ex: Palm). The Palm will just perform
- * one active discovery and connect directly to us.
- *
- * However, when both devices discover each other, they might attempt to
- * connect to each other following the discovery event, and it would create
- * collisions on the medium (SNRM battle).
- * The "fix" for that is to disable all connection requests in IrLAP
- * for 100ms after a discovery indication by setting the media_busy flag.
- * Previously, we used to postpone the event which was quite ugly. Now
- * that IrLAP takes care of this problem, just pass the event up...
- *
- * Jean II
- */
-void irlmp_link_discovery_indication(struct lap_cb *self,
- discovery_t *discovery)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
-
- /* Add to main log, cleanup */
- irlmp_add_discovery(irlmp->cachelog, discovery);
-
- /* Just handle it the same way as a discovery confirm,
- * bypass the LM_LAP state machine (see below) */
- irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_PASSIVE);
-}
-
-/*
- * Function irlmp_link_discovery_confirm (self, log)
- *
- * Called by IrLAP with a list of discoveries after the discovery
- * request has been carried out. A NULL log is received if IrLAP
- * was unable to carry out the discovery request
- *
- */
-void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
-
- /* Add to main log, cleanup */
- irlmp_add_discovery_log(irlmp->cachelog, log);
-
- /* Propagate event to various LSAPs registered for it.
- * We bypass the LM_LAP state machine because
- * 1) We do it regardless of the LM_LAP state
- * 2) It doesn't affect the LM_LAP state
- * 3) Faster, slimer, simpler, ...
- * Jean II */
- irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_ACTIVE);
-}
-
-#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
-static inline void irlmp_update_cache(struct lap_cb *lap,
- struct lsap_cb *lsap)
-{
- /* Prevent concurrent read to get garbage */
- lap->cache.valid = FALSE;
- /* Update cache entry */
- lap->cache.dlsap_sel = lsap->dlsap_sel;
- lap->cache.slsap_sel = lsap->slsap_sel;
- lap->cache.lsap = lsap;
- lap->cache.valid = TRUE;
-}
-#endif
-
-/*
- * Function irlmp_find_handle (self, dlsap_sel, slsap_sel, status, queue)
- *
- * Find handle associated with destination and source LSAP
- *
- * Any IrDA connection (LSAP/TSAP) is uniquely identified by
- * 3 parameters, the local lsap, the remote lsap and the remote address.
- * We may initiate multiple connections to the same remote service
- * (they will have different local lsap), a remote device may initiate
- * multiple connections to the same local service (they will have
- * different remote lsap), or multiple devices may connect to the same
- * service and may use the same remote lsap (and they will have
- * different remote address).
- * So, where is the remote address ? Each LAP connection is made with
- * a single remote device, so imply a specific remote address.
- * Jean II
- */
-static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap_sel,
- __u8 slsap_sel, int status,
- hashbin_t *queue)
-{
- struct lsap_cb *lsap;
- unsigned long flags;
-
- /*
- * Optimize for the common case. We assume that the last frame
- * received is in the same connection as the last one, so check in
- * cache first to avoid the linear search
- */
-#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
- if ((self->cache.valid) &&
- (self->cache.slsap_sel == slsap_sel) &&
- (self->cache.dlsap_sel == dlsap_sel))
- {
- return self->cache.lsap;
- }
-#endif
-
- spin_lock_irqsave(&queue->hb_spinlock, flags);
-
- lsap = (struct lsap_cb *) hashbin_get_first(queue);
- while (lsap != NULL) {
- /*
- * If this is an incoming connection, then the destination
- * LSAP selector may have been specified as LM_ANY so that
- * any client can connect. In that case we only need to check
- * if the source LSAP (in our view!) match!
- */
- if ((status == CONNECT_CMD) &&
- (lsap->slsap_sel == slsap_sel) &&
- (lsap->dlsap_sel == LSAP_ANY)) {
- /* This is where the dest lsap sel is set on incoming
- * lsaps */
- lsap->dlsap_sel = dlsap_sel;
- break;
- }
- /*
- * Check if source LSAP and dest LSAP selectors match.
- */
- if ((lsap->slsap_sel == slsap_sel) &&
- (lsap->dlsap_sel == dlsap_sel))
- break;
-
- lsap = (struct lsap_cb *) hashbin_get_next(queue);
- }
-#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
- if(lsap)
- irlmp_update_cache(self, lsap);
-#endif
- spin_unlock_irqrestore(&queue->hb_spinlock, flags);
-
- /* Return what we've found or NULL */
- return lsap;
-}
diff --git a/drivers/staging/irda/net/irmod.c b/drivers/staging/irda/net/irmod.c
deleted file mode 100644
index 4319f4ff66b0..000000000000
--- a/drivers/staging/irda/net/irmod.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*********************************************************************
- *
- * Filename: irmod.c
- * Version: 0.9
- * Description: IrDA stack main entry points
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Dec 15 13:55:39 1997
- * Modified at: Wed Jan 5 15:12:41 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1997, 1999-2000 Dag Brattli, All Rights Reserved.
- * Copyright (c) 2000-2004 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-/*
- * This file contains the main entry points of the IrDA stack.
- * They are in this file and not af_irda.c because some developpers
- * are using the IrDA stack without the socket API (compiling out
- * af_irda.c).
- * Jean II
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irmod.h> /* notify_t */
-#include <net/irda/irlap.h> /* irlap_init */
-#include <net/irda/irlmp.h> /* irlmp_init */
-#include <net/irda/iriap.h> /* iriap_init */
-#include <net/irda/irttp.h> /* irttp_init */
-#include <net/irda/irda_device.h> /* irda_device_init */
-
-/* Packet type handler.
- * Tell the kernel how IrDA packets should be handled.
- */
-static struct packet_type irda_packet_type __read_mostly = {
- .type = cpu_to_be16(ETH_P_IRDA),
- .func = irlap_driver_rcv, /* Packet type handler irlap_frame.c */
-};
-
-/*
- * Function irda_notify_init (notify)
- *
- * Used for initializing the notify structure
- *
- */
-void irda_notify_init(notify_t *notify)
-{
- notify->data_indication = NULL;
- notify->udata_indication = NULL;
- notify->connect_confirm = NULL;
- notify->connect_indication = NULL;
- notify->disconnect_indication = NULL;
- notify->flow_indication = NULL;
- notify->status_indication = NULL;
- notify->instance = NULL;
- strlcpy(notify->name, "Unknown", sizeof(notify->name));
-}
-EXPORT_SYMBOL(irda_notify_init);
-
-/*
- * Function irda_init (void)
- *
- * Protocol stack initialisation entry point.
- * Initialise the various components of the IrDA stack
- */
-static int __init irda_init(void)
-{
- int ret = 0;
-
- /* Lower layer of the stack */
- irlmp_init();
- irlap_init();
-
- /* Driver/dongle support */
- irda_device_init();
-
- /* Higher layers of the stack */
- iriap_init();
- irttp_init();
- ret = irsock_init();
- if (ret < 0)
- goto out_err_1;
-
- /* Add IrDA packet type (Start receiving packets) */
- dev_add_pack(&irda_packet_type);
-
- /* External APIs */
-#ifdef CONFIG_PROC_FS
- irda_proc_register();
-#endif
-#ifdef CONFIG_SYSCTL
- ret = irda_sysctl_register();
- if (ret < 0)
- goto out_err_2;
-#endif
-
- ret = irda_nl_register();
- if (ret < 0)
- goto out_err_3;
-
- return 0;
-
- out_err_3:
-#ifdef CONFIG_SYSCTL
- irda_sysctl_unregister();
- out_err_2:
-#endif
-#ifdef CONFIG_PROC_FS
- irda_proc_unregister();
-#endif
-
- /* Remove IrDA packet type (stop receiving packets) */
- dev_remove_pack(&irda_packet_type);
-
- /* Remove higher layers */
- irsock_cleanup();
- out_err_1:
- irttp_cleanup();
- iriap_cleanup();
-
- /* Remove lower layers */
- irda_device_cleanup();
- irlap_cleanup(); /* Must be done before irlmp_cleanup()! DB */
-
- /* Remove middle layer */
- irlmp_cleanup();
-
-
- return ret;
-}
-
-/*
- * Function irda_cleanup (void)
- *
- * Protocol stack cleanup/removal entry point.
- * Cleanup the various components of the IrDA stack
- */
-static void __exit irda_cleanup(void)
-{
- /* Remove External APIs */
- irda_nl_unregister();
-
-#ifdef CONFIG_SYSCTL
- irda_sysctl_unregister();
-#endif
-#ifdef CONFIG_PROC_FS
- irda_proc_unregister();
-#endif
-
- /* Remove IrDA packet type (stop receiving packets) */
- dev_remove_pack(&irda_packet_type);
-
- /* Remove higher layers */
- irsock_cleanup();
- irttp_cleanup();
- iriap_cleanup();
-
- /* Remove lower layers */
- irda_device_cleanup();
- irlap_cleanup(); /* Must be done before irlmp_cleanup()! DB */
-
- /* Remove middle layer */
- irlmp_cleanup();
-}
-
-/*
- * The IrDA stack must be initialised *before* drivers get initialised,
- * and *before* higher protocols (IrLAN/IrCOMM/IrNET) get initialised,
- * otherwise bad things will happen (hashbins will be NULL for example).
- * Those modules are at module_init()/device_initcall() level.
- *
- * On the other hand, it needs to be initialised *after* the basic
- * networking, the /proc/net filesystem and sysctl module. Those are
- * currently initialised in .../init/main.c (before initcalls).
- * Also, IrDA drivers needs to be initialised *after* the random number
- * generator (main stack and higher layer init don't need it anymore).
- *
- * Jean II
- */
-device_initcall(irda_init);
-module_exit(irda_cleanup);
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no> & Jean Tourrilhes <jt@hpl.hp.com>");
-MODULE_DESCRIPTION("The Linux IrDA Protocol Stack");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_NETPROTO(PF_IRDA);
diff --git a/drivers/staging/irda/net/irnet/Kconfig b/drivers/staging/irda/net/irnet/Kconfig
deleted file mode 100644
index 28c557f0fdd2..000000000000
--- a/drivers/staging/irda/net/irnet/Kconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-config IRNET
- tristate "IrNET protocol"
- depends on IRDA && PPP
- help
- Say Y here if you want to build support for the IrNET protocol.
- To compile it as a module, choose M here: the module will be
- called irnet. IrNET is a PPP driver, so you will also need a
- working PPP subsystem (driver, daemon and config)...
-
- IrNET is an alternate way to transfer TCP/IP traffic over IrDA. It
- uses synchronous PPP over a set of point to point IrDA sockets. You
- can use it between Linux machine or with W2k.
-
diff --git a/drivers/staging/irda/net/irnet/Makefile b/drivers/staging/irda/net/irnet/Makefile
deleted file mode 100644
index 61c365c8a2a0..000000000000
--- a/drivers/staging/irda/net/irnet/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for the Linux IrDA IrNET protocol layer.
-#
-
-obj-$(CONFIG_IRNET) += irnet.o
-
-irnet-y := irnet_ppp.o irnet_irda.o
diff --git a/drivers/staging/irda/net/irnet/irnet.h b/drivers/staging/irda/net/irnet/irnet.h
deleted file mode 100644
index 9d451f8ed47a..000000000000
--- a/drivers/staging/irda/net/irnet/irnet.h
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- * IrNET protocol module : Synchronous PPP over an IrDA socket.
- *
- * Jean II - HPL `00 - <jt@hpl.hp.com>
- *
- * This file contains definitions and declarations global to the IrNET module,
- * all grouped in one place...
- * This file is a *private* header, so other modules don't want to know
- * what's in there...
- *
- * Note : as most part of the Linux kernel, this module is available
- * under the GNU General Public License (GPL).
- */
-
-#ifndef IRNET_H
-#define IRNET_H
-
-/************************** DOCUMENTATION ***************************/
-/*
- * What is IrNET
- * -------------
- * IrNET is a protocol allowing to carry TCP/IP traffic between two
- * IrDA peers in an efficient fashion. It is a thin layer, passing PPP
- * packets to IrTTP and vice versa. It uses PPP in synchronous mode,
- * because IrTTP offer a reliable sequenced packet service (as opposed
- * to a byte stream). In fact, you could see IrNET as carrying TCP/IP
- * in a IrDA socket, using PPP to provide the glue.
- *
- * The main difference with traditional PPP over IrCOMM is that we
- * avoid the framing and serial emulation which are a performance
- * bottleneck. It also allows multipoint communications in a sensible
- * fashion.
- *
- * The main difference with IrLAN is that we use PPP for the link
- * management, which is more standard, interoperable and flexible than
- * the IrLAN protocol. For example, PPP adds authentication,
- * encryption, compression, header compression and automated routing
- * setup. And, as IrNET let PPP do the hard work, the implementation
- * is much simpler than IrLAN.
- *
- * The Linux implementation
- * ------------------------
- * IrNET is written on top of the Linux-IrDA stack, and interface with
- * the generic Linux PPP driver. Because IrNET depend on recent
- * changes of the PPP driver interface, IrNET will work only with very
- * recent kernel (2.3.99-pre6 and up).
- *
- * The present implementation offer the following features :
- * o simple user interface using pppd
- * o efficient implementation (interface directly to PPP and IrTTP)
- * o addressing (you can specify the name of the IrNET recipient)
- * o multipoint operation (limited by IrLAP specification)
- * o information in /proc/net/irda/irnet
- * o IrNET events on /dev/irnet (for user space daemon)
- * o IrNET daemon (irnetd) to automatically handle incoming requests
- * o Windows 2000 compatibility (tested, but need more work)
- * Currently missing :
- * o Lot's of testing (that's your job)
- * o Connection retries (may be too hard to do)
- * o Check pppd persist mode
- * o User space daemon (to automatically handle incoming requests)
- *
- * The setup is not currently the most easy, but this should get much
- * better when everything will get integrated...
- *
- * Acknowledgements
- * ----------------
- * This module is based on :
- * o The PPP driver (ppp_synctty/ppp_generic) by Paul Mackerras
- * o The IrLAN protocol (irlan_common/XXX) by Dag Brattli
- * o The IrSock interface (af_irda) by Dag Brattli
- * o Some other bits from the kernel and my drivers...
- * Infinite thanks to those brave souls for providing the infrastructure
- * upon which IrNET is built.
- *
- * Thanks to all my colleagues in HP for helping me. In particular,
- * thanks to Salil Pradhan and Bill Serra for W2k testing...
- * Thanks to Luiz Magalhaes for irnetd and much testing...
- *
- * Thanks to Alan Cox for answering lot's of my stupid questions, and
- * to Paul Mackerras answering my questions on how to best integrate
- * IrNET and pppd.
- *
- * Jean II
- *
- * Note on some implementations choices...
- * ------------------------------------
- * 1) Direct interface vs tty/socket
- * I could have used a tty interface to hook to ppp and use the full
- * socket API to connect to IrDA. The code would have been easier to
- * maintain, and maybe the code would have been smaller...
- * Instead, we hook directly to ppp_generic and to IrTTP, which make
- * things more complicated...
- *
- * The first reason is flexibility : this allow us to create IrNET
- * instances on demand (no /dev/ircommX crap) and to allow linkname
- * specification on pppd command line...
- *
- * Second reason is speed optimisation. If you look closely at the
- * transmit and receive paths, you will notice that they are "super lean"
- * (that's why they look ugly), with no function calls and as little data
- * copy and modification as I could...
- *
- * 2) irnetd in user space
- * irnetd is implemented in user space, which is necessary to call pppd.
- * This also give maximum benefits in term of flexibility and customability,
- * and allow to offer the event channel, useful for other stuff like debug.
- *
- * On the other hand, this require a loose coordination between the
- * present module and irnetd. One critical area is how incoming request
- * are handled.
- * When irnet receive an incoming request, it send an event to irnetd and
- * drop the incoming IrNET socket.
- * irnetd start a pppd instance, which create a new IrNET socket. This new
- * socket is then connected in the originating node to the pppd instance.
- * At this point, in the originating node, the first socket is closed.
- *
- * I admit, this is a bit messy and waste some resources. The alternative
- * is caching incoming socket, and that's also quite messy and waste
- * resources.
- * We also make connection time slower. For example, on a 115 kb/s link it
- * adds 60ms to the connection time (770 ms). However, this is slower than
- * the time it takes to fire up pppd on my P133...
- *
- *
- * History :
- * -------
- *
- * v1 - 15.5.00 - Jean II
- * o Basic IrNET (hook to ppp_generic & IrTTP - incl. multipoint)
- * o control channel on /dev/irnet (set name/address)
- * o event channel on /dev/irnet (for user space daemon)
- *
- * v2 - 5.6.00 - Jean II
- * o Enable DROP_NOT_READY to avoid PPP timeouts & other weirdness...
- * o Add DISCONNECT_TO event and rename DISCONNECT_FROM.
- * o Set official device number alloaction on /dev/irnet
- *
- * v3 - 30.8.00 - Jean II
- * o Update to latest Linux-IrDA changes :
- * - queue_t => irda_queue_t
- * o Update to ppp-2.4.0 :
- * - move irda_irnet_connect from PPPIOCATTACH to TIOCSETD
- * o Add EXPIRE event (depend on new IrDA-Linux patch)
- * o Switch from `hashbin_remove' to `hashbin_remove_this' to fix
- * a multilink bug... (depend on new IrDA-Linux patch)
- * o fix a self->daddr to self->raddr in irda_irnet_connect to fix
- * another multilink bug (darn !)
- * o Remove LINKNAME_IOCTL cruft
- *
- * v3b - 31.8.00 - Jean II
- * o Dump discovery log at event channel startup
- *
- * v4 - 28.9.00 - Jean II
- * o Fix interaction between poll/select and dump discovery log
- * o Add IRNET_BLOCKED_LINK event (depend on new IrDA-Linux patch)
- * o Add IRNET_NOANSWER_FROM event (mostly to help support)
- * o Release flow control in disconnect_indication
- * o Block packets while connecting (speed up connections)
- *
- * v5 - 11.01.01 - Jean II
- * o Init self->max_header_size, just in case...
- * o Set up ap->chan.hdrlen, to get zero copy on tx side working.
- * o avoid tx->ttp->flow->ppp->tx->... loop, by checking flow state
- * Thanks to Christian Gennerat for finding this bug !
- * ---
- * o Declare the proper MTU/MRU that we can support
- * (but PPP doesn't read the MTU value :-()
- * o Declare hashbin HB_NOLOCK instead of HB_LOCAL to avoid
- * disabling and enabling irq twice
- *
- * v6 - 31.05.01 - Jean II
- * o Print source address in Found, Discovery, Expiry & Request events
- * o Print requested source address in /proc/net/irnet
- * o Change control channel input. Allow multiple commands in one line.
- * o Add saddr command to change ap->rsaddr (and use that in IrDA)
- * ---
- * o Make the IrDA connection procedure totally asynchronous.
- * Heavy rewrite of the IAS query code and the whole connection
- * procedure. Now, irnet_connect() no longer need to be called from
- * a process context...
- * o Enable IrDA connect retries in ppp_irnet_send(). The good thing
- * is that IrDA connect retries are directly driven by PPP LCP
- * retries (we retry for each LCP packet), so that everything
- * is transparently controlled from pppd lcp-max-configure.
- * o Add ttp_connect flag to prevent rentry on the connect procedure
- * o Test and fixups to eliminate side effects of retries
- *
- * v7 - 22.08.01 - Jean II
- * o Cleanup : Change "saddr = 0x0" to "saddr = DEV_ADDR_ANY"
- * o Fix bug in BLOCK_WHEN_CONNECT introduced in v6 : due to the
- * asynchronous IAS query, self->tsap is NULL when PPP send the
- * first packet. This was preventing "connect-delay 0" to work.
- * Change the test in ppp_irnet_send() to self->ttp_connect.
- *
- * v8 - 1.11.01 - Jean II
- * o Tighten the use of self->ttp_connect and self->ttp_open to
- * prevent various race conditions.
- * o Avoid leaking discovery log and skb
- * o Replace "self" with "server" in irnet_connect_indication() to
- * better detect cut'n'paste error ;-)
- *
- * v9 - 29.11.01 - Jean II
- * o Fix event generation in disconnect indication that I broke in v8
- * It was always generation "No-Answer" because I was testing ttp_open
- * just after clearing it. *blush*.
- * o Use newly created irttp_listen() to fix potential crash when LAP
- * destroyed before irnet module removed.
- *
- * v10 - 4.3.2 - Jean II
- * o When receiving a disconnect indication, don't reenable the
- * PPP Tx queue, this will trigger a reconnect. Instead, close
- * the channel, which will kill pppd...
- *
- * v11 - 20.3.02 - Jean II
- * o Oops ! v10 fix disabled IrNET retries and passive behaviour.
- * Better fix in irnet_disconnect_indication() :
- * - if connected, kill pppd via hangup.
- * - if not connected, reenable ppp Tx, which trigger IrNET retry.
- *
- * v12 - 10.4.02 - Jean II
- * o Fix race condition in irnet_connect_indication().
- * If the socket was already trying to connect, drop old connection
- * and use new one only if acting as primary. See comments.
- *
- * v13 - 30.5.02 - Jean II
- * o Update module init code
- *
- * v14 - 20.2.03 - Jean II
- * o Add discovery hint bits in the control channel.
- * o Remove obsolete MOD_INC/DEC_USE_COUNT in favor of .owner
- *
- * v15 - 7.4.03 - Jean II
- * o Replace spin_lock_irqsave() with spin_lock_bh() so that we can
- * use ppp_unit_number(). It's probably also better overall...
- * o Disable call to ppp_unregister_channel(), because we can't do it.
- */
-
-/***************************** INCLUDES *****************************/
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-#include <linux/tty.h>
-#include <linux/proc_fs.h>
-#include <linux/netdevice.h>
-#include <linux/poll.h>
-#include <linux/capability.h>
-#include <linux/ctype.h> /* isspace() */
-#include <linux/string.h> /* skip_spaces() */
-#include <linux/uaccess.h>
-#include <linux/init.h>
-
-#include <linux/ppp_defs.h>
-#include <linux/ppp-ioctl.h>
-#include <linux/ppp_channel.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/iriap.h>
-#include <net/irda/irias_object.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/irttp.h>
-#include <net/irda/discovery.h>
-
-/***************************** OPTIONS *****************************/
-/*
- * Define or undefine to compile or not some optional part of the
- * IrNET driver...
- * Note : the present defaults make sense, play with that at your
- * own risk...
- */
-/* IrDA side of the business... */
-#define DISCOVERY_NOMASK /* To enable W2k compatibility... */
-#define ADVERTISE_HINT /* Advertise IrLAN hint bit */
-#define ALLOW_SIMULT_CONNECT /* This seem to work, cross fingers... */
-#define DISCOVERY_EVENTS /* Query the discovery log to post events */
-#define INITIAL_DISCOVERY /* Dump current discovery log as events */
-#undef STREAM_COMPAT /* Not needed - potentially messy */
-#undef CONNECT_INDIC_KICK /* Might mess IrDA, not needed */
-#undef FAIL_SEND_DISCONNECT /* Might mess IrDA, not needed */
-#undef PASS_CONNECT_PACKETS /* Not needed ? Safe */
-#undef MISSING_PPP_API /* Stuff I wish I could do */
-
-/* PPP side of the business */
-#define BLOCK_WHEN_CONNECT /* Block packets when connecting */
-#define CONNECT_IN_SEND /* Retry IrDA connection procedure */
-#undef FLUSH_TO_PPP /* Not sure about this one, let's play safe */
-#undef SECURE_DEVIRNET /* Bah... */
-
-/****************************** DEBUG ******************************/
-
-/*
- * This set of flags enable and disable all the various warning,
- * error and debug message of this driver.
- * Each section can be enabled and disabled independently
- */
-/* In the PPP part */
-#define DEBUG_CTRL_TRACE 0 /* Control channel */
-#define DEBUG_CTRL_INFO 0 /* various info */
-#define DEBUG_CTRL_ERROR 1 /* problems */
-#define DEBUG_FS_TRACE 0 /* filesystem callbacks */
-#define DEBUG_FS_INFO 0 /* various info */
-#define DEBUG_FS_ERROR 1 /* problems */
-#define DEBUG_PPP_TRACE 0 /* PPP related functions */
-#define DEBUG_PPP_INFO 0 /* various info */
-#define DEBUG_PPP_ERROR 1 /* problems */
-#define DEBUG_MODULE_TRACE 0 /* module insertion/removal */
-#define DEBUG_MODULE_ERROR 1 /* problems */
-
-/* In the IrDA part */
-#define DEBUG_IRDA_SR_TRACE 0 /* IRDA subroutines */
-#define DEBUG_IRDA_SR_INFO 0 /* various info */
-#define DEBUG_IRDA_SR_ERROR 1 /* problems */
-#define DEBUG_IRDA_SOCK_TRACE 0 /* IRDA main socket functions */
-#define DEBUG_IRDA_SOCK_INFO 0 /* various info */
-#define DEBUG_IRDA_SOCK_ERROR 1 /* problems */
-#define DEBUG_IRDA_SERV_TRACE 0 /* The IrNET server */
-#define DEBUG_IRDA_SERV_INFO 0 /* various info */
-#define DEBUG_IRDA_SERV_ERROR 1 /* problems */
-#define DEBUG_IRDA_TCB_TRACE 0 /* IRDA IrTTP callbacks */
-#define DEBUG_IRDA_CB_INFO 0 /* various info */
-#define DEBUG_IRDA_CB_ERROR 1 /* problems */
-#define DEBUG_IRDA_OCB_TRACE 0 /* IRDA other callbacks */
-#define DEBUG_IRDA_OCB_INFO 0 /* various info */
-#define DEBUG_IRDA_OCB_ERROR 1 /* problems */
-
-#define DEBUG_ASSERT 0 /* Verify all assertions */
-
-/*
- * These are the macros we are using to actually print the debug
- * statements. Don't look at it, it's ugly...
- *
- * One of the trick is that, as the DEBUG_XXX are constant, the
- * compiler will optimise away the if() in all cases.
- */
-/* All error messages (will show up in the normal logs) */
-#define DERROR(dbg, format, args...) \
- {if(DEBUG_##dbg) \
- printk(KERN_INFO "irnet: %s(): " format, __func__ , ##args);}
-
-/* Normal debug message (will show up in /var/log/debug) */
-#define DEBUG(dbg, format, args...) \
- {if(DEBUG_##dbg) \
- printk(KERN_DEBUG "irnet: %s(): " format, __func__ , ##args);}
-
-/* Entering a function (trace) */
-#define DENTER(dbg, format, args...) \
- {if(DEBUG_##dbg) \
- printk(KERN_DEBUG "irnet: -> %s" format, __func__ , ##args);}
-
-/* Entering and exiting a function in one go (trace) */
-#define DPASS(dbg, format, args...) \
- {if(DEBUG_##dbg) \
- printk(KERN_DEBUG "irnet: <>%s" format, __func__ , ##args);}
-
-/* Exiting a function (trace) */
-#define DEXIT(dbg, format, args...) \
- {if(DEBUG_##dbg) \
- printk(KERN_DEBUG "irnet: <-%s()" format, __func__ , ##args);}
-
-/* Exit a function with debug */
-#define DRETURN(ret, dbg, args...) \
- {DEXIT(dbg, ": " args);\
- return ret; }
-
-/* Exit a function on failed condition */
-#define DABORT(cond, ret, dbg, args...) \
- {if(cond) {\
- DERROR(dbg, args);\
- return ret; }}
-
-/* Invalid assertion, print out an error and exit... */
-#define DASSERT(cond, ret, dbg, args...) \
- {if((DEBUG_ASSERT) && !(cond)) {\
- DERROR(dbg, "Invalid assertion: " args);\
- return ret; }}
-
-/************************ CONSTANTS & MACROS ************************/
-
-/* Paranoia */
-#define IRNET_MAGIC 0xB00754
-
-/* Number of control events in the control channel buffer... */
-#define IRNET_MAX_EVENTS 8 /* Should be more than enough... */
-
-/****************************** TYPES ******************************/
-
-/*
- * This is the main structure where we store all the data pertaining to
- * one instance of irnet.
- * Note : in irnet functions, a pointer this structure is usually called
- * "ap" or "self". If the code is borrowed from the IrDA stack, it tend
- * to be called "self", and if it is borrowed from the PPP driver it is
- * "ap". Apart from that, it's exactly the same structure ;-)
- */
-typedef struct irnet_socket
-{
- /* ------------------- Instance management ------------------- */
- /* We manage a linked list of IrNET socket instances */
- irda_queue_t q; /* Must be first - for hasbin */
- int magic; /* Paranoia */
-
- /* --------------------- FileSystem part --------------------- */
- /* "pppd" interact directly with us on a /dev/ file */
- struct file * file; /* File descriptor of this instance */
- /* TTY stuff - to keep "pppd" happy */
- struct ktermios termios; /* Various tty flags */
- /* Stuff for the control channel */
- int event_index; /* Last read in the event log */
-
- /* ------------------------- PPP part ------------------------- */
- /* We interface directly to the ppp_generic driver in the kernel */
- int ppp_open; /* registered with ppp_generic */
- struct ppp_channel chan; /* Interface to generic ppp layer */
-
- int mru; /* Max size of PPP payload */
- u32 xaccm[8]; /* Asynchronous character map (just */
- u32 raccm; /* to please pppd - dummy) */
- unsigned int flags; /* PPP flags (compression, ...) */
- unsigned int rbits; /* Unused receive flags ??? */
- struct work_struct disconnect_work; /* Process context disconnection */
- /* ------------------------ IrTTP part ------------------------ */
- /* We create a pseudo "socket" over the IrDA tranport */
- unsigned long ttp_open; /* Set when IrTTP is ready */
- unsigned long ttp_connect; /* Set when IrTTP is connecting */
- struct tsap_cb * tsap; /* IrTTP instance (the connection) */
-
- char rname[NICKNAME_MAX_LEN + 1];
- /* IrDA nickname of destination */
- __u32 rdaddr; /* Requested peer IrDA address */
- __u32 rsaddr; /* Requested local IrDA address */
- __u32 daddr; /* actual peer IrDA address */
- __u32 saddr; /* my local IrDA address */
- __u8 dtsap_sel; /* Remote TSAP selector */
- __u8 stsap_sel; /* Local TSAP selector */
-
- __u32 max_sdu_size_rx;/* Socket parameters used for IrTTP */
- __u32 max_sdu_size_tx;
- __u32 max_data_size;
- __u8 max_header_size;
- LOCAL_FLOW tx_flow; /* State of the Tx path in IrTTP */
-
- /* ------------------- IrLMP and IrIAS part ------------------- */
- /* Used for IrDA Discovery and socket name resolution */
- void * ckey; /* IrLMP client handle */
- __u16 mask; /* Hint bits mask (filter discov.)*/
- int nslots; /* Number of slots for discovery */
-
- struct iriap_cb * iriap; /* Used to query remote IAS */
- int errno; /* status of the IAS query */
-
- /* -------------------- Discovery log part -------------------- */
- /* Used by initial discovery on the control channel
- * and by irnet_discover_daddr_and_lsap_sel() */
- struct irda_device_info *discoveries; /* Copy of the discovery log */
- int disco_index; /* Last read in the discovery log */
- int disco_number; /* Size of the discovery log */
-
- struct mutex lock;
-
-} irnet_socket;
-
-/*
- * This is the various event that we will generate on the control channel
- */
-typedef enum irnet_event
-{
- IRNET_DISCOVER, /* New IrNET node discovered */
- IRNET_EXPIRE, /* IrNET node expired */
- IRNET_CONNECT_TO, /* IrNET socket has connected to other node */
- IRNET_CONNECT_FROM, /* Other node has connected to IrNET socket */
- IRNET_REQUEST_FROM, /* Non satisfied connection request */
- IRNET_NOANSWER_FROM, /* Failed connection request */
- IRNET_BLOCKED_LINK, /* Link (IrLAP) is blocked for > 3s */
- IRNET_DISCONNECT_FROM, /* IrNET socket has disconnected */
- IRNET_DISCONNECT_TO /* Closing IrNET socket */
-} irnet_event;
-
-/*
- * This is the storage for an event and its arguments
- */
-typedef struct irnet_log
-{
- irnet_event event;
- int unit;
- __u32 saddr;
- __u32 daddr;
- char name[NICKNAME_MAX_LEN + 1]; /* 21 + 1 */
- __u16_host_order hints; /* Discovery hint bits */
-} irnet_log;
-
-/*
- * This is the storage for all events and related stuff...
- */
-typedef struct irnet_ctrl_channel
-{
- irnet_log log[IRNET_MAX_EVENTS]; /* Event log */
- int index; /* Current index in log */
- spinlock_t spinlock; /* Serialize access to the event log */
- wait_queue_head_t rwait; /* processes blocked on read (or poll) */
-} irnet_ctrl_channel;
-
-/**************************** PROTOTYPES ****************************/
-/*
- * Global functions of the IrNET module
- * Note : we list here also functions called from one file to the other.
- */
-
-/* -------------------------- IRDA PART -------------------------- */
-int irda_irnet_create(irnet_socket *); /* Initialise an IrNET socket */
-int irda_irnet_connect(irnet_socket *); /* Try to connect over IrDA */
-void irda_irnet_destroy(irnet_socket *); /* Teardown an IrNET socket */
-int irda_irnet_init(void); /* Initialise IrDA part of IrNET */
-void irda_irnet_cleanup(void); /* Teardown IrDA part of IrNET */
-
-/**************************** VARIABLES ****************************/
-
-/* Control channel stuff - allocated in irnet_irda.h */
-extern struct irnet_ctrl_channel irnet_events;
-
-#endif /* IRNET_H */
diff --git a/drivers/staging/irda/net/irnet/irnet_irda.c b/drivers/staging/irda/net/irnet/irnet_irda.c
deleted file mode 100644
index e390bceeb2f8..000000000000
--- a/drivers/staging/irda/net/irnet/irnet_irda.c
+++ /dev/null
@@ -1,1885 +0,0 @@
-/*
- * IrNET protocol module : Synchronous PPP over an IrDA socket.
- *
- * Jean II - HPL `00 - <jt@hpl.hp.com>
- *
- * This file implement the IRDA interface of IrNET.
- * Basically, we sit on top of IrTTP. We set up IrTTP, IrIAS properly,
- * and exchange frames with IrTTP.
- */
-
-#include "irnet_irda.h" /* Private header */
-#include <linux/sched.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <asm/unaligned.h>
-
-/*
- * PPP disconnect work: we need to make sure we're in
- * process context when calling ppp_unregister_channel().
- */
-static void irnet_ppp_disconnect(struct work_struct *work)
-{
- irnet_socket * self =
- container_of(work, irnet_socket, disconnect_work);
-
- if (self == NULL)
- return;
- /*
- * If we were connected, cleanup & close the PPP
- * channel, which will kill pppd (hangup) and the rest.
- */
- if (self->ppp_open && !self->ttp_open && !self->ttp_connect) {
- ppp_unregister_channel(&self->chan);
- self->ppp_open = 0;
- }
-}
-
-/************************* CONTROL CHANNEL *************************/
-/*
- * When ppp is not active, /dev/irnet act as a control channel.
- * Writing allow to set up the IrDA destination of the IrNET channel,
- * and any application may be read events happening on IrNET...
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Post an event to the control channel...
- * Put the event in the log, and then wait all process blocked on read
- * so they can read the log...
- */
-static void
-irnet_post_event(irnet_socket * ap,
- irnet_event event,
- __u32 saddr,
- __u32 daddr,
- char * name,
- __u16 hints)
-{
- int index; /* In the log */
-
- DENTER(CTRL_TRACE, "(ap=0x%p, event=%d, daddr=%08x, name=``%s'')\n",
- ap, event, daddr, name);
-
- /* Protect this section via spinlock.
- * Note : as we are the only event producer, we only need to exclude
- * ourself when touching the log, which is nice and easy.
- */
- spin_lock_bh(&irnet_events.spinlock);
-
- /* Copy the event in the log */
- index = irnet_events.index;
- irnet_events.log[index].event = event;
- irnet_events.log[index].daddr = daddr;
- irnet_events.log[index].saddr = saddr;
- /* Try to copy IrDA nickname */
- if(name)
- strcpy(irnet_events.log[index].name, name);
- else
- irnet_events.log[index].name[0] = '\0';
- /* Copy hints */
- irnet_events.log[index].hints.word = hints;
- /* Try to get ppp unit number */
- if((ap != (irnet_socket *) NULL) && (ap->ppp_open))
- irnet_events.log[index].unit = ppp_unit_number(&ap->chan);
- else
- irnet_events.log[index].unit = -1;
-
- /* Increment the index
- * Note that we increment the index only after the event is written,
- * to make sure that the readers don't get garbage... */
- irnet_events.index = (index + 1) % IRNET_MAX_EVENTS;
-
- DEBUG(CTRL_INFO, "New event index is %d\n", irnet_events.index);
-
- /* Spin lock end */
- spin_unlock_bh(&irnet_events.spinlock);
-
- /* Now : wake up everybody waiting for events... */
- wake_up_interruptible_all(&irnet_events.rwait);
-
- DEXIT(CTRL_TRACE, "\n");
-}
-
-/************************* IRDA SUBROUTINES *************************/
-/*
- * These are a bunch of subroutines called from other functions
- * down there, mostly common code or to improve readability...
- *
- * Note : we duplicate quite heavily some routines of af_irda.c,
- * because our input structure (self) is quite different
- * (struct irnet instead of struct irda_sock), which make sharing
- * the same code impossible (at least, without templates).
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Function irda_open_tsap (self)
- *
- * Open local Transport Service Access Point (TSAP)
- *
- * Create a IrTTP instance for us and set all the IrTTP callbacks.
- */
-static inline int
-irnet_open_tsap(irnet_socket * self)
-{
- notify_t notify; /* Callback structure */
-
- DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self);
-
- DABORT(self->tsap != NULL, -EBUSY, IRDA_SR_ERROR, "Already busy !\n");
-
- /* Initialize IrTTP callbacks to be used by the IrDA stack */
- irda_notify_init(&notify);
- notify.connect_confirm = irnet_connect_confirm;
- notify.connect_indication = irnet_connect_indication;
- notify.disconnect_indication = irnet_disconnect_indication;
- notify.data_indication = irnet_data_indication;
- /*notify.udata_indication = NULL;*/
- notify.flow_indication = irnet_flow_indication;
- notify.status_indication = irnet_status_indication;
- notify.instance = self;
- strlcpy(notify.name, IRNET_NOTIFY_NAME, sizeof(notify.name));
-
- /* Open an IrTTP instance */
- self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
- &notify);
- DABORT(self->tsap == NULL, -ENOMEM,
- IRDA_SR_ERROR, "Unable to allocate TSAP !\n");
-
- /* Remember which TSAP selector we actually got */
- self->stsap_sel = self->tsap->stsap_sel;
-
- DEXIT(IRDA_SR_TRACE, " - tsap=0x%p, sel=0x%X\n",
- self->tsap, self->stsap_sel);
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_ias_to_tsap (self, result, value)
- *
- * Examine an IAS object and extract TSAP
- *
- * We do an IAP query to find the TSAP associated with the IrNET service.
- * When IrIAP pass us the result of the query, this function look at
- * the return values to check for failures and extract the TSAP if
- * possible.
- * Also deallocate value
- * The failure is in self->errno
- * Return TSAP or -1
- */
-static inline __u8
-irnet_ias_to_tsap(irnet_socket * self,
- int result,
- struct ias_value * value)
-{
- __u8 dtsap_sel = 0; /* TSAP we are looking for */
-
- DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self);
-
- /* By default, no error */
- self->errno = 0;
-
- /* Check if request succeeded */
- switch(result)
- {
- /* Standard errors : service not available */
- case IAS_CLASS_UNKNOWN:
- case IAS_ATTRIB_UNKNOWN:
- DEBUG(IRDA_SR_INFO, "IAS object doesn't exist ! (%d)\n", result);
- self->errno = -EADDRNOTAVAIL;
- break;
-
- /* Other errors, most likely IrDA stack failure */
- default :
- DEBUG(IRDA_SR_INFO, "IAS query failed ! (%d)\n", result);
- self->errno = -EHOSTUNREACH;
- break;
-
- /* Success : we got what we wanted */
- case IAS_SUCCESS:
- break;
- }
-
- /* Check what was returned to us */
- if(value != NULL)
- {
- /* What type of argument have we got ? */
- switch(value->type)
- {
- case IAS_INTEGER:
- DEBUG(IRDA_SR_INFO, "result=%d\n", value->t.integer);
- if(value->t.integer != -1)
- /* Get the remote TSAP selector */
- dtsap_sel = value->t.integer;
- else
- self->errno = -EADDRNOTAVAIL;
- break;
- default:
- self->errno = -EADDRNOTAVAIL;
- DERROR(IRDA_SR_ERROR, "bad type ! (0x%X)\n", value->type);
- break;
- }
-
- /* Cleanup */
- irias_delete_value(value);
- }
- else /* value == NULL */
- {
- /* Nothing returned to us - usually result != SUCCESS */
- if(!(self->errno))
- {
- DERROR(IRDA_SR_ERROR,
- "IrDA bug : result == SUCCESS && value == NULL\n");
- self->errno = -EHOSTUNREACH;
- }
- }
- DEXIT(IRDA_SR_TRACE, "\n");
-
- /* Return the TSAP */
- return dtsap_sel;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_find_lsap_sel (self)
- *
- * Try to lookup LSAP selector in remote LM-IAS
- *
- * Basically, we start a IAP query, and then go to sleep. When the query
- * return, irnet_getvalue_confirm will wake us up, and we can examine the
- * result of the query...
- * Note that in some case, the query fail even before we go to sleep,
- * creating some races...
- */
-static inline int
-irnet_find_lsap_sel(irnet_socket * self)
-{
- DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self);
-
- /* This should not happen */
- DABORT(self->iriap, -EBUSY, IRDA_SR_ERROR, "busy with a previous query.\n");
-
- /* Create an IAP instance, will be closed in irnet_getvalue_confirm() */
- self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
- irnet_getvalue_confirm);
-
- /* Treat unexpected signals as disconnect */
- self->errno = -EHOSTUNREACH;
-
- /* Query remote LM-IAS */
- iriap_getvaluebyclass_request(self->iriap, self->rsaddr, self->daddr,
- IRNET_SERVICE_NAME, IRNET_IAS_VALUE);
-
- /* The above request is non-blocking.
- * After a while, IrDA will call us back in irnet_getvalue_confirm()
- * We will then call irnet_ias_to_tsap() and finish the
- * connection procedure */
-
- DEXIT(IRDA_SR_TRACE, "\n");
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_connect_tsap (self)
- *
- * Initialise the TTP socket and initiate TTP connection
- *
- */
-static inline int
-irnet_connect_tsap(irnet_socket * self)
-{
- int err;
-
- DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self);
-
- /* Open a local TSAP (an IrTTP instance) */
- err = irnet_open_tsap(self);
- if(err != 0)
- {
- clear_bit(0, &self->ttp_connect);
- DERROR(IRDA_SR_ERROR, "connect aborted!\n");
- return err;
- }
-
- /* Connect to remote device */
- err = irttp_connect_request(self->tsap, self->dtsap_sel,
- self->rsaddr, self->daddr, NULL,
- self->max_sdu_size_rx, NULL);
- if(err != 0)
- {
- clear_bit(0, &self->ttp_connect);
- DERROR(IRDA_SR_ERROR, "connect aborted!\n");
- return err;
- }
-
- /* The above call is non-blocking.
- * After a while, the IrDA stack will either call us back in
- * irnet_connect_confirm() or irnet_disconnect_indication()
- * See you there ;-) */
-
- DEXIT(IRDA_SR_TRACE, "\n");
- return err;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_discover_next_daddr (self)
- *
- * Query the IrNET TSAP of the next device in the log.
- *
- * Used in the TSAP discovery procedure.
- */
-static inline int
-irnet_discover_next_daddr(irnet_socket * self)
-{
- /* Close the last instance of IrIAP, and open a new one.
- * We can't reuse the IrIAP instance in the IrIAP callback */
- if(self->iriap)
- {
- iriap_close(self->iriap);
- self->iriap = NULL;
- }
- /* Create a new IAP instance */
- self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
- irnet_discovervalue_confirm);
- if(self->iriap == NULL)
- return -ENOMEM;
-
- /* Next discovery - before the call to avoid races */
- self->disco_index++;
-
- /* Check if we have one more address to try */
- if(self->disco_index < self->disco_number)
- {
- /* Query remote LM-IAS */
- iriap_getvaluebyclass_request(self->iriap,
- self->discoveries[self->disco_index].saddr,
- self->discoveries[self->disco_index].daddr,
- IRNET_SERVICE_NAME, IRNET_IAS_VALUE);
- /* The above request is non-blocking.
- * After a while, IrDA will call us back in irnet_discovervalue_confirm()
- * We will then call irnet_ias_to_tsap() and come back here again... */
- return 0;
- }
- else
- return 1;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_discover_daddr_and_lsap_sel (self)
- *
- * This try to find a device with the requested service.
- *
- * Initiate a TSAP discovery procedure.
- * It basically look into the discovery log. For each address in the list,
- * it queries the LM-IAS of the device to find if this device offer
- * the requested service.
- * If there is more than one node supporting the service, we complain
- * to the user (it should move devices around).
- * If we find one node which have the requested TSAP, we connect to it.
- *
- * This function just start the whole procedure. It request the discovery
- * log and submit the first IAS query.
- * The bulk of the job is handled in irnet_discovervalue_confirm()
- *
- * Note : this procedure fails if there is more than one device in range
- * on the same dongle, because IrLMP doesn't disconnect the LAP when the
- * last LSAP is closed. Moreover, we would need to wait the LAP
- * disconnection...
- */
-static inline int
-irnet_discover_daddr_and_lsap_sel(irnet_socket * self)
-{
- int ret;
-
- DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self);
-
- /* Ask lmp for the current discovery log */
- self->discoveries = irlmp_get_discoveries(&self->disco_number, self->mask,
- DISCOVERY_DEFAULT_SLOTS);
-
- /* Check if the we got some results */
- if(self->discoveries == NULL)
- {
- self->disco_number = -1;
- clear_bit(0, &self->ttp_connect);
- DRETURN(-ENETUNREACH, IRDA_SR_INFO, "No Cachelog...\n");
- }
- DEBUG(IRDA_SR_INFO, "Got the log (0x%p), size is %d\n",
- self->discoveries, self->disco_number);
-
- /* Start with the first discovery */
- self->disco_index = -1;
- self->daddr = DEV_ADDR_ANY;
-
- /* This will fail if the log is empty - this is non-blocking */
- ret = irnet_discover_next_daddr(self);
- if(ret)
- {
- /* Close IAP */
- if(self->iriap)
- iriap_close(self->iriap);
- self->iriap = NULL;
-
- /* Cleanup our copy of the discovery log */
- kfree(self->discoveries);
- self->discoveries = NULL;
-
- clear_bit(0, &self->ttp_connect);
- DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n");
- }
-
- /* Follow me in irnet_discovervalue_confirm() */
-
- DEXIT(IRDA_SR_TRACE, "\n");
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_dname_to_daddr (self)
- *
- * Convert an IrDA nickname to a valid IrDA address
- *
- * It basically look into the discovery log until there is a match.
- */
-static inline int
-irnet_dname_to_daddr(irnet_socket * self)
-{
- struct irda_device_info *discoveries; /* Copy of the discovery log */
- int number; /* Number of nodes in the log */
- int i;
-
- DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self);
-
- /* Ask lmp for the current discovery log */
- discoveries = irlmp_get_discoveries(&number, 0xffff,
- DISCOVERY_DEFAULT_SLOTS);
- /* Check if the we got some results */
- if(discoveries == NULL)
- DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n");
-
- /*
- * Now, check all discovered devices (if any), and connect
- * client only about the services that the client is
- * interested in...
- */
- for(i = 0; i < number; i++)
- {
- /* Does the name match ? */
- if(!strncmp(discoveries[i].info, self->rname, NICKNAME_MAX_LEN))
- {
- /* Yes !!! Get it.. */
- self->daddr = discoveries[i].daddr;
- DEBUG(IRDA_SR_INFO, "discovered device ``%s'' at address 0x%08x.\n",
- self->rname, self->daddr);
- kfree(discoveries);
- DEXIT(IRDA_SR_TRACE, "\n");
- return 0;
- }
- }
- /* No luck ! */
- DEBUG(IRDA_SR_INFO, "cannot discover device ``%s'' !!!\n", self->rname);
- kfree(discoveries);
- return -EADDRNOTAVAIL;
-}
-
-
-/************************* SOCKET ROUTINES *************************/
-/*
- * This are the main operations on IrNET sockets, basically to create
- * and destroy IrNET sockets. These are called from the PPP part...
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Create a IrNET instance : just initialise some parameters...
- */
-int
-irda_irnet_create(irnet_socket * self)
-{
- DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self);
-
- self->magic = IRNET_MAGIC; /* Paranoia */
-
- self->ttp_open = 0; /* Prevent higher layer from accessing IrTTP */
- self->ttp_connect = 0; /* Not connecting yet */
- self->rname[0] = '\0'; /* May be set via control channel */
- self->rdaddr = DEV_ADDR_ANY; /* May be set via control channel */
- self->rsaddr = DEV_ADDR_ANY; /* May be set via control channel */
- self->daddr = DEV_ADDR_ANY; /* Until we get connected */
- self->saddr = DEV_ADDR_ANY; /* Until we get connected */
- self->max_sdu_size_rx = TTP_SAR_UNBOUND;
-
- /* Register as a client with IrLMP */
- self->ckey = irlmp_register_client(0, NULL, NULL, NULL);
-#ifdef DISCOVERY_NOMASK
- self->mask = 0xffff; /* For W2k compatibility */
-#else /* DISCOVERY_NOMASK */
- self->mask = irlmp_service_to_hint(S_LAN);
-#endif /* DISCOVERY_NOMASK */
- self->tx_flow = FLOW_START; /* Flow control from IrTTP */
-
- INIT_WORK(&self->disconnect_work, irnet_ppp_disconnect);
-
- DEXIT(IRDA_SOCK_TRACE, "\n");
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Connect to the other side :
- * o convert device name to an address
- * o find the socket number (dlsap)
- * o Establish the connection
- *
- * Note : We no longer mimic af_irda. The IAS query for finding the TSAP
- * is done asynchronously, like the TTP connection. This allow us to
- * call this function from any context (not only process).
- * The downside is that following what's happening in there is tricky
- * because it involve various functions all over the place...
- */
-int
-irda_irnet_connect(irnet_socket * self)
-{
- int err;
-
- DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self);
-
- /* Check if we are already trying to connect.
- * Because irda_irnet_connect() can be called directly by pppd plus
- * packet retries in ppp_generic and connect may take time, plus we may
- * race with irnet_connect_indication(), we need to be careful there... */
- if(test_and_set_bit(0, &self->ttp_connect))
- DRETURN(-EBUSY, IRDA_SOCK_INFO, "Already connecting...\n");
- if((self->iriap != NULL) || (self->tsap != NULL))
- DERROR(IRDA_SOCK_ERROR, "Socket not cleaned up...\n");
-
- /* Insert ourselves in the hashbin so that the IrNET server can find us.
- * Notes : 4th arg is string of 32 char max and must be null terminated
- * When 4th arg is used (string), 3rd arg isn't (int)
- * Can't re-insert (MUST remove first) so check for that... */
- if((irnet_server.running) && (self->q.q_next == NULL))
- {
- spin_lock_bh(&irnet_server.spinlock);
- hashbin_insert(irnet_server.list, (irda_queue_t *) self, 0, self->rname);
- spin_unlock_bh(&irnet_server.spinlock);
- DEBUG(IRDA_SOCK_INFO, "Inserted ``%s'' in hashbin...\n", self->rname);
- }
-
- /* If we don't have anything (no address, no name) */
- if((self->rdaddr == DEV_ADDR_ANY) && (self->rname[0] == '\0'))
- {
- /* Try to find a suitable address */
- if((err = irnet_discover_daddr_and_lsap_sel(self)) != 0)
- DRETURN(err, IRDA_SOCK_INFO, "auto-connect failed!\n");
- /* In most cases, the call above is non-blocking */
- }
- else
- {
- /* If we have only the name (no address), try to get an address */
- if(self->rdaddr == DEV_ADDR_ANY)
- {
- if((err = irnet_dname_to_daddr(self)) != 0)
- DRETURN(err, IRDA_SOCK_INFO, "name connect failed!\n");
- }
- else
- /* Use the requested destination address */
- self->daddr = self->rdaddr;
-
- /* Query remote LM-IAS to find LSAP selector */
- irnet_find_lsap_sel(self);
- /* The above call is non blocking */
- }
-
- /* At this point, we are waiting for the IrDA stack to call us back,
- * or we have already failed.
- * We will finish the connection procedure in irnet_connect_tsap().
- */
- DEXIT(IRDA_SOCK_TRACE, "\n");
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irda_irnet_destroy(self)
- *
- * Destroy irnet instance
- *
- * Note : this need to be called from a process context.
- */
-void
-irda_irnet_destroy(irnet_socket * self)
-{
- DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self);
- if(self == NULL)
- return;
-
- /* Remove ourselves from hashbin (if we are queued in hashbin)
- * Note : `irnet_server.running' protect us from calls in hashbin_delete() */
- if((irnet_server.running) && (self->q.q_next != NULL))
- {
- struct irnet_socket * entry;
- DEBUG(IRDA_SOCK_INFO, "Removing from hash..\n");
- spin_lock_bh(&irnet_server.spinlock);
- entry = hashbin_remove_this(irnet_server.list, (irda_queue_t *) self);
- self->q.q_next = NULL;
- spin_unlock_bh(&irnet_server.spinlock);
- DASSERT(entry == self, , IRDA_SOCK_ERROR, "Can't remove from hash.\n");
- }
-
- /* If we were connected, post a message */
- if(test_bit(0, &self->ttp_open))
- {
- /* Note : as the disconnect comes from ppp_generic, the unit number
- * doesn't exist anymore when we post the event, so we need to pass
- * NULL as the first arg... */
- irnet_post_event(NULL, IRNET_DISCONNECT_TO,
- self->saddr, self->daddr, self->rname, 0);
- }
-
- /* Prevent various IrDA callbacks from messing up things
- * Need to be first */
- clear_bit(0, &self->ttp_connect);
-
- /* Prevent higher layer from accessing IrTTP */
- clear_bit(0, &self->ttp_open);
-
- /* Unregister with IrLMP */
- irlmp_unregister_client(self->ckey);
-
- /* Unregister with LM-IAS */
- if(self->iriap)
- {
- iriap_close(self->iriap);
- self->iriap = NULL;
- }
-
- /* Cleanup eventual discoveries from connection attempt or control channel */
- if(self->discoveries != NULL)
- {
- /* Cleanup our copy of the discovery log */
- kfree(self->discoveries);
- self->discoveries = NULL;
- }
-
- /* Close our IrTTP connection */
- if(self->tsap)
- {
- DEBUG(IRDA_SOCK_INFO, "Closing our TTP connection.\n");
- irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
- irttp_close_tsap(self->tsap);
- self->tsap = NULL;
- }
- self->stsap_sel = 0;
-
- DEXIT(IRDA_SOCK_TRACE, "\n");
-}
-
-
-/************************** SERVER SOCKET **************************/
-/*
- * The IrNET service is composed of one server socket and a variable
- * number of regular IrNET sockets. The server socket is supposed to
- * handle incoming connections and redirect them to one IrNET sockets.
- * It's a superset of the regular IrNET socket, but has a very distinct
- * behaviour...
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_daddr_to_dname (self)
- *
- * Convert an IrDA address to a IrDA nickname
- *
- * It basically look into the discovery log until there is a match.
- */
-static inline int
-irnet_daddr_to_dname(irnet_socket * self)
-{
- struct irda_device_info *discoveries; /* Copy of the discovery log */
- int number; /* Number of nodes in the log */
- int i;
-
- DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self);
-
- /* Ask lmp for the current discovery log */
- discoveries = irlmp_get_discoveries(&number, 0xffff,
- DISCOVERY_DEFAULT_SLOTS);
- /* Check if the we got some results */
- if (discoveries == NULL)
- DRETURN(-ENETUNREACH, IRDA_SERV_INFO, "Cachelog empty...\n");
-
- /* Now, check all discovered devices (if any) */
- for(i = 0; i < number; i++)
- {
- /* Does the name match ? */
- if(discoveries[i].daddr == self->daddr)
- {
- /* Yes !!! Get it.. */
- strlcpy(self->rname, discoveries[i].info, sizeof(self->rname));
- self->rname[sizeof(self->rname) - 1] = '\0';
- DEBUG(IRDA_SERV_INFO, "Device 0x%08x is in fact ``%s''.\n",
- self->daddr, self->rname);
- kfree(discoveries);
- DEXIT(IRDA_SERV_TRACE, "\n");
- return 0;
- }
- }
- /* No luck ! */
- DEXIT(IRDA_SERV_INFO, ": cannot discover device 0x%08x !!!\n", self->daddr);
- kfree(discoveries);
- return -EADDRNOTAVAIL;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irda_find_socket (self)
- *
- * Find the correct IrNET socket
- *
- * Look into the list of IrNET sockets and finds one with the right
- * properties...
- */
-static inline irnet_socket *
-irnet_find_socket(irnet_socket * self)
-{
- irnet_socket * new = (irnet_socket *) NULL;
- int err;
-
- DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self);
-
- /* Get the addresses of the requester */
- self->daddr = irttp_get_daddr(self->tsap);
- self->saddr = irttp_get_saddr(self->tsap);
-
- /* Try to get the IrDA nickname of the requester */
- err = irnet_daddr_to_dname(self);
-
- /* Protect access to the instance list */
- spin_lock_bh(&irnet_server.spinlock);
-
- /* So now, try to get an socket having specifically
- * requested that nickname */
- if(err == 0)
- {
- new = (irnet_socket *) hashbin_find(irnet_server.list,
- 0, self->rname);
- if(new)
- DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches rname ``%s''.\n",
- new, new->rname);
- }
-
- /* If no name matches, try to find an socket by the destination address */
- /* It can be either the requested destination address (set via the
- * control channel), or the current destination address if the
- * socket is in the middle of a connection request */
- if(new == (irnet_socket *) NULL)
- {
- new = (irnet_socket *) hashbin_get_first(irnet_server.list);
- while(new !=(irnet_socket *) NULL)
- {
- /* Does it have the same address ? */
- if((new->rdaddr == self->daddr) || (new->daddr == self->daddr))
- {
- /* Yes !!! Get it.. */
- DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches daddr %#08x.\n",
- new, self->daddr);
- break;
- }
- new = (irnet_socket *) hashbin_get_next(irnet_server.list);
- }
- }
-
- /* If we don't have any socket, get the first unconnected socket */
- if(new == (irnet_socket *) NULL)
- {
- new = (irnet_socket *) hashbin_get_first(irnet_server.list);
- while(new !=(irnet_socket *) NULL)
- {
- /* Is it available ? */
- if(!(test_bit(0, &new->ttp_open)) && (new->rdaddr == DEV_ADDR_ANY) &&
- (new->rname[0] == '\0') && (new->ppp_open))
- {
- /* Yes !!! Get it.. */
- DEBUG(IRDA_SERV_INFO, "Socket 0x%p is free.\n",
- new);
- break;
- }
- new = (irnet_socket *) hashbin_get_next(irnet_server.list);
- }
- }
-
- /* Spin lock end */
- spin_unlock_bh(&irnet_server.spinlock);
-
- DEXIT(IRDA_SERV_TRACE, " - new = 0x%p\n", new);
- return new;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irda_connect_socket (self)
- *
- * Connect an incoming connection to the socket
- *
- */
-static inline int
-irnet_connect_socket(irnet_socket * server,
- irnet_socket * new,
- struct qos_info * qos,
- __u32 max_sdu_size,
- __u8 max_header_size)
-{
- DENTER(IRDA_SERV_TRACE, "(server=0x%p, new=0x%p)\n",
- server, new);
-
- /* Now attach up the new socket */
- new->tsap = irttp_dup(server->tsap, new);
- DABORT(new->tsap == NULL, -1, IRDA_SERV_ERROR, "dup failed!\n");
-
- /* Set up all the relevant parameters on the new socket */
- new->stsap_sel = new->tsap->stsap_sel;
- new->dtsap_sel = new->tsap->dtsap_sel;
- new->saddr = irttp_get_saddr(new->tsap);
- new->daddr = irttp_get_daddr(new->tsap);
-
- new->max_header_size = max_header_size;
- new->max_sdu_size_tx = max_sdu_size;
- new->max_data_size = max_sdu_size;
-#ifdef STREAM_COMPAT
- /* If we want to receive "stream sockets" */
- if(max_sdu_size == 0)
- new->max_data_size = irttp_get_max_seg_size(new->tsap);
-#endif /* STREAM_COMPAT */
-
- /* Clean up the original one to keep it in listen state */
- irttp_listen(server->tsap);
-
- /* Send a connection response on the new socket */
- irttp_connect_response(new->tsap, new->max_sdu_size_rx, NULL);
-
- /* Allow PPP to send its junk over the new socket... */
- set_bit(0, &new->ttp_open);
-
- /* Not connecting anymore, and clean up last possible remains
- * of connection attempts on the socket */
- clear_bit(0, &new->ttp_connect);
- if(new->iriap)
- {
- iriap_close(new->iriap);
- new->iriap = NULL;
- }
- if(new->discoveries != NULL)
- {
- kfree(new->discoveries);
- new->discoveries = NULL;
- }
-
-#ifdef CONNECT_INDIC_KICK
- /* As currently we don't block packets in ppp_irnet_send() while passive,
- * this is not really needed...
- * Also, not doing it give IrDA a chance to finish the setup properly
- * before being swamped with packets... */
- ppp_output_wakeup(&new->chan);
-#endif /* CONNECT_INDIC_KICK */
-
- /* Notify the control channel */
- irnet_post_event(new, IRNET_CONNECT_FROM,
- new->saddr, new->daddr, server->rname, 0);
-
- DEXIT(IRDA_SERV_TRACE, "\n");
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irda_disconnect_server (self)
- *
- * Cleanup the server socket when the incoming connection abort
- *
- */
-static inline void
-irnet_disconnect_server(irnet_socket * self,
- struct sk_buff *skb)
-{
- DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self);
-
- /* Put the received packet in the black hole */
- kfree_skb(skb);
-
-#ifdef FAIL_SEND_DISCONNECT
- /* Tell the other party we don't want to be connected */
- /* Hum... Is it the right thing to do ? And do we need to send
- * a connect response before ? It looks ok without this... */
- irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
-#endif /* FAIL_SEND_DISCONNECT */
-
- /* Notify the control channel (see irnet_find_socket()) */
- irnet_post_event(NULL, IRNET_REQUEST_FROM,
- self->saddr, self->daddr, self->rname, 0);
-
- /* Clean up the server to keep it in listen state */
- irttp_listen(self->tsap);
-
- DEXIT(IRDA_SERV_TRACE, "\n");
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irda_setup_server (self)
- *
- * Create a IrTTP server and set it up...
- *
- * Register the IrLAN hint bit, create a IrTTP instance for us,
- * set all the IrTTP callbacks and create an IrIAS entry...
- */
-static inline int
-irnet_setup_server(void)
-{
- __u16 hints;
-
- DENTER(IRDA_SERV_TRACE, "()\n");
-
- /* Initialise the regular socket part of the server */
- irda_irnet_create(&irnet_server.s);
-
- /* Open a local TSAP (an IrTTP instance) for the server */
- irnet_open_tsap(&irnet_server.s);
-
- /* PPP part setup */
- irnet_server.s.ppp_open = 0;
- irnet_server.s.chan.private = NULL;
- irnet_server.s.file = NULL;
-
- /* Get the hint bit corresponding to IrLAN */
- /* Note : we overload the IrLAN hint bit. As it is only a "hint", and as
- * we provide roughly the same functionality as IrLAN, this is ok.
- * In fact, the situation is similar as JetSend overloading the Obex hint
- */
- hints = irlmp_service_to_hint(S_LAN);
-
-#ifdef ADVERTISE_HINT
- /* Register with IrLMP as a service (advertise our hint bit) */
- irnet_server.skey = irlmp_register_service(hints);
-#endif /* ADVERTISE_HINT */
-
- /* Register with LM-IAS (so that people can connect to us) */
- irnet_server.ias_obj = irias_new_object(IRNET_SERVICE_NAME, jiffies);
- irias_add_integer_attrib(irnet_server.ias_obj, IRNET_IAS_VALUE,
- irnet_server.s.stsap_sel, IAS_KERNEL_ATTR);
- irias_insert_object(irnet_server.ias_obj);
-
-#ifdef DISCOVERY_EVENTS
- /* Tell IrLMP we want to be notified of newly discovered nodes */
- irlmp_update_client(irnet_server.s.ckey, hints,
- irnet_discovery_indication, irnet_expiry_indication,
- (void *) &irnet_server.s);
-#endif
-
- DEXIT(IRDA_SERV_TRACE, " - self=0x%p\n", &irnet_server.s);
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irda_destroy_server (self)
- *
- * Destroy the IrTTP server...
- *
- * Reverse of the previous function...
- */
-static inline void
-irnet_destroy_server(void)
-{
- DENTER(IRDA_SERV_TRACE, "()\n");
-
-#ifdef ADVERTISE_HINT
- /* Unregister with IrLMP */
- irlmp_unregister_service(irnet_server.skey);
-#endif /* ADVERTISE_HINT */
-
- /* Unregister with LM-IAS */
- if(irnet_server.ias_obj)
- irias_delete_object(irnet_server.ias_obj);
-
- /* Cleanup the socket part */
- irda_irnet_destroy(&irnet_server.s);
-
- DEXIT(IRDA_SERV_TRACE, "\n");
-}
-
-
-/************************ IRDA-TTP CALLBACKS ************************/
-/*
- * When we create a IrTTP instance, we pass to it a set of callbacks
- * that IrTTP will call in case of various events.
- * We take care of those events here.
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_data_indication (instance, sap, skb)
- *
- * Received some data from TinyTP. Just queue it on the receive queue
- *
- */
-static int
-irnet_data_indication(void * instance,
- void * sap,
- struct sk_buff *skb)
-{
- irnet_socket * ap = (irnet_socket *) instance;
- unsigned char * p;
- int code = 0;
-
- DENTER(IRDA_TCB_TRACE, "(self/ap=0x%p, skb=0x%p)\n",
- ap, skb);
- DASSERT(skb != NULL, 0, IRDA_CB_ERROR, "skb is NULL !!!\n");
-
- /* Check is ppp is ready to receive our packet */
- if(!ap->ppp_open)
- {
- DERROR(IRDA_CB_ERROR, "PPP not ready, dropping packet...\n");
- /* When we return error, TTP will need to requeue the skb and
- * will stop the sender. IrTTP will stall until we send it a
- * flow control request... */
- return -ENOMEM;
- }
-
- /* strip address/control field if present */
- p = skb->data;
- if((p[0] == PPP_ALLSTATIONS) && (p[1] == PPP_UI))
- {
- /* chop off address/control */
- if(skb->len < 3)
- goto err_exit;
- p = skb_pull(skb, 2);
- }
-
- /* decompress protocol field if compressed */
- if(p[0] & 1)
- {
- /* protocol is compressed */
- *(u8 *)skb_push(skb, 1) = 0;
- }
- else
- if(skb->len < 2)
- goto err_exit;
-
- /* pass to generic ppp layer */
- /* Note : how do I know if ppp can accept or not the packet ? This is
- * essential if I want to manage flow control smoothly... */
- ppp_input(&ap->chan, skb);
-
- DEXIT(IRDA_TCB_TRACE, "\n");
- return 0;
-
- err_exit:
- DERROR(IRDA_CB_ERROR, "Packet too small, dropping...\n");
- kfree_skb(skb);
- ppp_input_error(&ap->chan, code);
- return 0; /* Don't return an error code, only for flow control... */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_disconnect_indication (instance, sap, reason, skb)
- *
- * Connection has been closed. Chech reason to find out why
- *
- * Note : there are many cases where we come here :
- * o attempted to connect, timeout
- * o connected, link is broken, LAP has timeout
- * o connected, other side close the link
- * o connection request on the server not handled
- */
-static void
-irnet_disconnect_indication(void * instance,
- void * sap,
- LM_REASON reason,
- struct sk_buff *skb)
-{
- irnet_socket * self = (irnet_socket *) instance;
- int test_open;
- int test_connect;
-
- DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self);
- DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");
-
- /* Don't care about it, but let's not leak it */
- if(skb)
- dev_kfree_skb(skb);
-
- /* Prevent higher layer from accessing IrTTP */
- test_open = test_and_clear_bit(0, &self->ttp_open);
- /* Not connecting anymore...
- * (note : TSAP is open, so IAP callbacks are no longer pending...) */
- test_connect = test_and_clear_bit(0, &self->ttp_connect);
-
- /* If both self->ttp_open and self->ttp_connect are NULL, it mean that we
- * have a race condition with irda_irnet_destroy() or
- * irnet_connect_indication(), so don't mess up tsap...
- */
- if(!(test_open || test_connect))
- {
- DERROR(IRDA_CB_ERROR, "Race condition detected...\n");
- return;
- }
-
- /* If we were active, notify the control channel */
- if(test_open)
- irnet_post_event(self, IRNET_DISCONNECT_FROM,
- self->saddr, self->daddr, self->rname, 0);
- else
- /* If we were trying to connect, notify the control channel */
- if((self->tsap) && (self != &irnet_server.s))
- irnet_post_event(self, IRNET_NOANSWER_FROM,
- self->saddr, self->daddr, self->rname, 0);
-
- /* Close our IrTTP connection, cleanup tsap */
- if((self->tsap) && (self != &irnet_server.s))
- {
- DEBUG(IRDA_CB_INFO, "Closing our TTP connection.\n");
- irttp_close_tsap(self->tsap);
- self->tsap = NULL;
- }
- /* Cleanup the socket in case we want to reconnect in ppp_output_wakeup() */
- self->stsap_sel = 0;
- self->daddr = DEV_ADDR_ANY;
- self->tx_flow = FLOW_START;
-
- /* Deal with the ppp instance if it's still alive */
- if(self->ppp_open)
- {
- if(test_open)
- {
- /* ppp_unregister_channel() wants a user context. */
- schedule_work(&self->disconnect_work);
- }
- else
- {
- /* If we were trying to connect, flush (drain) ppp_generic
- * Tx queue (most often we have blocked it), which will
- * trigger an other attempt to connect. If we are passive,
- * this will empty the Tx queue after last try. */
- ppp_output_wakeup(&self->chan);
- }
- }
-
- DEXIT(IRDA_TCB_TRACE, "\n");
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_connect_confirm (instance, sap, qos, max_sdu_size, skb)
- *
- * Connections has been confirmed by the remote device
- *
- */
-static void
-irnet_connect_confirm(void * instance,
- void * sap,
- struct qos_info *qos,
- __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *skb)
-{
- irnet_socket * self = (irnet_socket *) instance;
-
- DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self);
-
- /* Check if socket is closing down (via irda_irnet_destroy()) */
- if(! test_bit(0, &self->ttp_connect))
- {
- DERROR(IRDA_CB_ERROR, "Socket no longer connecting. Ouch !\n");
- return;
- }
-
- /* How much header space do we need to reserve */
- self->max_header_size = max_header_size;
-
- /* IrTTP max SDU size in transmit direction */
- self->max_sdu_size_tx = max_sdu_size;
- self->max_data_size = max_sdu_size;
-#ifdef STREAM_COMPAT
- if(max_sdu_size == 0)
- self->max_data_size = irttp_get_max_seg_size(self->tsap);
-#endif /* STREAM_COMPAT */
-
- /* At this point, IrLMP has assigned our source address */
- self->saddr = irttp_get_saddr(self->tsap);
-
- /* Allow higher layer to access IrTTP */
- set_bit(0, &self->ttp_open);
- clear_bit(0, &self->ttp_connect); /* Not racy, IrDA traffic is serial */
- /* Give a kick in the ass of ppp_generic so that he sends us some data */
- ppp_output_wakeup(&self->chan);
-
- /* Check size of received packet */
- if(skb->len > 0)
- {
-#ifdef PASS_CONNECT_PACKETS
- DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n");
- /* Try to pass it to PPP */
- irnet_data_indication(instance, sap, skb);
-#else /* PASS_CONNECT_PACKETS */
- DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n");
- kfree_skb(skb); /* Note : will be optimised with other kfree... */
-#endif /* PASS_CONNECT_PACKETS */
- }
- else
- kfree_skb(skb);
-
- /* Notify the control channel */
- irnet_post_event(self, IRNET_CONNECT_TO,
- self->saddr, self->daddr, self->rname, 0);
-
- DEXIT(IRDA_TCB_TRACE, "\n");
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_flow_indication (instance, sap, flow)
- *
- * Used by TinyTP to tell us if it can accept more data or not
- *
- */
-static void
-irnet_flow_indication(void * instance,
- void * sap,
- LOCAL_FLOW flow)
-{
- irnet_socket * self = (irnet_socket *) instance;
- LOCAL_FLOW oldflow = self->tx_flow;
-
- DENTER(IRDA_TCB_TRACE, "(self=0x%p, flow=%d)\n", self, flow);
-
- /* Update our state */
- self->tx_flow = flow;
-
- /* Check what IrTTP want us to do... */
- switch(flow)
- {
- case FLOW_START:
- DEBUG(IRDA_CB_INFO, "IrTTP wants us to start again\n");
- /* Check if we really need to wake up PPP */
- if(oldflow == FLOW_STOP)
- ppp_output_wakeup(&self->chan);
- else
- DEBUG(IRDA_CB_INFO, "But we were already transmitting !!!\n");
- break;
- case FLOW_STOP:
- DEBUG(IRDA_CB_INFO, "IrTTP wants us to slow down\n");
- break;
- default:
- DEBUG(IRDA_CB_INFO, "Unknown flow command!\n");
- break;
- }
-
- DEXIT(IRDA_TCB_TRACE, "\n");
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_status_indication (instance, sap, reason, skb)
- *
- * Link (IrLAP) status report.
- *
- */
-static void
-irnet_status_indication(void * instance,
- LINK_STATUS link,
- LOCK_STATUS lock)
-{
- irnet_socket * self = (irnet_socket *) instance;
-
- DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self);
- DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");
-
- /* We can only get this event if we are connected */
- switch(link)
- {
- case STATUS_NO_ACTIVITY:
- irnet_post_event(self, IRNET_BLOCKED_LINK,
- self->saddr, self->daddr, self->rname, 0);
- break;
- default:
- DEBUG(IRDA_CB_INFO, "Unknown status...\n");
- }
-
- DEXIT(IRDA_TCB_TRACE, "\n");
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_connect_indication(instance, sap, qos, max_sdu_size, userdata)
- *
- * Incoming connection
- *
- * In theory, this function is called only on the server socket.
- * Some other node is attempting to connect to the IrNET service, and has
- * sent a connection request on our server socket.
- * We just redirect the connection to the relevant IrNET socket.
- *
- * Note : we also make sure that between 2 irnet nodes, there can
- * exist only one irnet connection.
- */
-static void
-irnet_connect_indication(void * instance,
- void * sap,
- struct qos_info *qos,
- __u32 max_sdu_size,
- __u8 max_header_size,
- struct sk_buff *skb)
-{
- irnet_socket * server = &irnet_server.s;
- irnet_socket * new = (irnet_socket *) NULL;
-
- DENTER(IRDA_TCB_TRACE, "(server=0x%p)\n", server);
- DASSERT(instance == &irnet_server, , IRDA_CB_ERROR,
- "Invalid instance (0x%p) !!!\n", instance);
- DASSERT(sap == irnet_server.s.tsap, , IRDA_CB_ERROR, "Invalid sap !!!\n");
-
- /* Try to find the most appropriate IrNET socket */
- new = irnet_find_socket(server);
-
- /* After all this hard work, do we have an socket ? */
- if(new == (irnet_socket *) NULL)
- {
- DEXIT(IRDA_CB_INFO, ": No socket waiting for this connection.\n");
- irnet_disconnect_server(server, skb);
- return;
- }
-
- /* Is the socket already busy ? */
- if(test_bit(0, &new->ttp_open))
- {
- DEXIT(IRDA_CB_INFO, ": Socket already connected.\n");
- irnet_disconnect_server(server, skb);
- return;
- }
-
- /* The following code is a bit tricky, so need comments ;-)
- */
- /* If ttp_connect is set, the socket is trying to connect to the other
- * end and may have sent a IrTTP connection request and is waiting for
- * a connection response (that may never come).
- * Now, the pain is that the socket may have opened a tsap and is
- * waiting on it, while the other end is trying to connect to it on
- * another tsap.
- * Because IrNET can be peer to peer, we need to workaround this.
- * Furthermore, the way the irnetd script is implemented, the
- * target will create a second IrNET connection back to the
- * originator and expect the originator to bind this new connection
- * to the original PPPD instance.
- * And of course, if we don't use irnetd, we can have a race when
- * both side try to connect simultaneously, which could leave both
- * connections half closed (yuck).
- * Conclusions :
- * 1) The "originator" must accept the new connection and get rid
- * of the old one so that irnetd works
- * 2) One side must deny the new connection to avoid races,
- * but both side must agree on which side it is...
- * Most often, the originator is primary at the LAP layer.
- * Jean II
- */
- /* Now, let's look at the way I wrote the test...
- * We need to clear up the ttp_connect flag atomically to prevent
- * irnet_disconnect_indication() to mess up the tsap we are going to close.
- * We want to clear the ttp_connect flag only if we close the tsap,
- * otherwise we will never close it, so we need to check for primary
- * *before* doing the test on the flag.
- * And of course, ALLOW_SIMULT_CONNECT can disable this entirely...
- * Jean II
- */
-
- /* Socket already connecting ? On primary ? */
- if(0
-#ifdef ALLOW_SIMULT_CONNECT
- || ((irttp_is_primary(server->tsap) == 1) && /* primary */
- (test_and_clear_bit(0, &new->ttp_connect)))
-#endif /* ALLOW_SIMULT_CONNECT */
- )
- {
- DERROR(IRDA_CB_ERROR, "Socket already connecting, but going to reuse it !\n");
-
- /* Cleanup the old TSAP if necessary - IrIAP will be cleaned up later */
- if(new->tsap != NULL)
- {
- /* Close the old connection the new socket was attempting,
- * so that we can hook it up to the new connection.
- * It's now safe to do it... */
- irttp_close_tsap(new->tsap);
- new->tsap = NULL;
- }
- }
- else
- {
- /* Three options :
- * 1) socket was not connecting or connected : ttp_connect should be 0.
- * 2) we don't want to connect the socket because we are secondary or
- * ALLOW_SIMULT_CONNECT is undefined. ttp_connect should be 1.
- * 3) we are half way in irnet_disconnect_indication(), and it's a
- * nice race condition... Fortunately, we can detect that by checking
- * if tsap is still alive. On the other hand, we can't be in
- * irda_irnet_destroy() otherwise we would not have found this
- * socket in the hashbin.
- * Jean II */
- if((test_bit(0, &new->ttp_connect)) || (new->tsap != NULL))
- {
- /* Don't mess this socket, somebody else in in charge... */
- DERROR(IRDA_CB_ERROR, "Race condition detected, socket in use, abort connect...\n");
- irnet_disconnect_server(server, skb);
- return;
- }
- }
-
- /* So : at this point, we have a socket, and it is idle. Good ! */
- irnet_connect_socket(server, new, qos, max_sdu_size, max_header_size);
-
- /* Check size of received packet */
- if(skb->len > 0)
- {
-#ifdef PASS_CONNECT_PACKETS
- DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n");
- /* Try to pass it to PPP */
- irnet_data_indication(new, new->tsap, skb);
-#else /* PASS_CONNECT_PACKETS */
- DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n");
- kfree_skb(skb); /* Note : will be optimised with other kfree... */
-#endif /* PASS_CONNECT_PACKETS */
- }
- else
- kfree_skb(skb);
-
- DEXIT(IRDA_TCB_TRACE, "\n");
-}
-
-
-/********************** IRDA-IAS/LMP CALLBACKS **********************/
-/*
- * These are the callbacks called by other layers of the IrDA stack,
- * mainly LMP for discovery and IAS for name queries.
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_getvalue_confirm (result, obj_id, value, priv)
- *
- * Got answer from remote LM-IAS, just connect
- *
- * This is the reply to a IAS query we were doing to find the TSAP of
- * the device we want to connect to.
- * If we have found a valid TSAP, just initiate the TTP connection
- * on this TSAP.
- */
-static void
-irnet_getvalue_confirm(int result,
- __u16 obj_id,
- struct ias_value *value,
- void * priv)
-{
- irnet_socket * self = (irnet_socket *) priv;
-
- DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self);
- DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n");
-
- /* Check if already connected (via irnet_connect_socket())
- * or socket is closing down (via irda_irnet_destroy()) */
- if(! test_bit(0, &self->ttp_connect))
- {
- DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n");
- return;
- }
-
- /* We probably don't need to make any more queries */
- iriap_close(self->iriap);
- self->iriap = NULL;
-
- /* Post process the IAS reply */
- self->dtsap_sel = irnet_ias_to_tsap(self, result, value);
-
- /* If error, just go out */
- if(self->errno)
- {
- clear_bit(0, &self->ttp_connect);
- DERROR(IRDA_OCB_ERROR, "IAS connect failed ! (0x%X)\n", self->errno);
- return;
- }
-
- DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n",
- self->daddr, self->dtsap_sel);
-
- /* Start up TTP - non blocking */
- irnet_connect_tsap(self);
-
- DEXIT(IRDA_OCB_TRACE, "\n");
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_discovervalue_confirm (result, obj_id, value, priv)
- *
- * Handle the TSAP discovery procedure state machine.
- * Got answer from remote LM-IAS, try next device
- *
- * We are doing a TSAP discovery procedure, and we got an answer to
- * a IAS query we were doing to find the TSAP on one of the address
- * in the discovery log.
- *
- * If we have found a valid TSAP for the first time, save it. If it's
- * not the first time we found one, complain.
- *
- * If we have more addresses in the log, just initiate a new query.
- * Note that those query may fail (see irnet_discover_daddr_and_lsap_sel())
- *
- * Otherwise, wrap up the procedure (cleanup), check if we have found
- * any device and connect to it.
- */
-static void
-irnet_discovervalue_confirm(int result,
- __u16 obj_id,
- struct ias_value *value,
- void * priv)
-{
- irnet_socket * self = (irnet_socket *) priv;
- __u8 dtsap_sel; /* TSAP we are looking for */
-
- DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self);
- DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n");
-
- /* Check if already connected (via irnet_connect_socket())
- * or socket is closing down (via irda_irnet_destroy()) */
- if(! test_bit(0, &self->ttp_connect))
- {
- DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n");
- return;
- }
-
- /* Post process the IAS reply */
- dtsap_sel = irnet_ias_to_tsap(self, result, value);
-
- /* Have we got something ? */
- if(self->errno == 0)
- {
- /* We found the requested service */
- if(self->daddr != DEV_ADDR_ANY)
- {
- DERROR(IRDA_OCB_ERROR, "More than one device in range supports IrNET...\n");
- }
- else
- {
- /* First time we found that one, save it ! */
- self->daddr = self->discoveries[self->disco_index].daddr;
- self->dtsap_sel = dtsap_sel;
- }
- }
-
- /* If no failure */
- if((self->errno == -EADDRNOTAVAIL) || (self->errno == 0))
- {
- int ret;
-
- /* Search the next node */
- ret = irnet_discover_next_daddr(self);
- if(!ret)
- {
- /* In this case, the above request was non-blocking.
- * We will return here after a while... */
- return;
- }
- /* In this case, we have processed the last discovery item */
- }
-
- /* No more queries to be done (failure or last one) */
-
- /* We probably don't need to make any more queries */
- iriap_close(self->iriap);
- self->iriap = NULL;
-
- /* No more items : remove the log and signal termination */
- DEBUG(IRDA_OCB_INFO, "Cleaning up log (0x%p)\n",
- self->discoveries);
- if(self->discoveries != NULL)
- {
- /* Cleanup our copy of the discovery log */
- kfree(self->discoveries);
- self->discoveries = NULL;
- }
- self->disco_number = -1;
-
- /* Check out what we found */
- if(self->daddr == DEV_ADDR_ANY)
- {
- self->daddr = DEV_ADDR_ANY;
- clear_bit(0, &self->ttp_connect);
- DEXIT(IRDA_OCB_TRACE, ": cannot discover IrNET in any device !!!\n");
- return;
- }
-
- /* We have a valid address - just connect */
-
- DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n",
- self->daddr, self->dtsap_sel);
-
- /* Start up TTP - non blocking */
- irnet_connect_tsap(self);
-
- DEXIT(IRDA_OCB_TRACE, "\n");
-}
-
-#ifdef DISCOVERY_EVENTS
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_discovery_indication (discovery)
- *
- * Got a discovery indication from IrLMP, post an event
- *
- * Note : IrLMP take care of matching the hint mask for us, and also
- * check if it is a "new" node for us...
- *
- * As IrLMP filter on the IrLAN hint bit, we get both IrLAN and IrNET
- * nodes, so it's only at connection time that we will know if the
- * node support IrNET, IrLAN or both. The other solution is to check
- * in IAS the PNP ids and service name.
- * Note : even if a node support IrNET (or IrLAN), it's no guarantee
- * that we will be able to connect to it, the node might already be
- * busy...
- *
- * One last thing : in some case, this function will trigger duplicate
- * discovery events. On the other hand, we should catch all
- * discoveries properly (i.e. not miss one). Filtering duplicate here
- * is to messy, so we leave that to user space...
- */
-static void
-irnet_discovery_indication(discinfo_t * discovery,
- DISCOVERY_MODE mode,
- void * priv)
-{
- irnet_socket * self = &irnet_server.s;
-
- DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self);
- DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR,
- "Invalid instance (0x%p) !!!\n", priv);
-
- DEBUG(IRDA_OCB_INFO, "Discovered new IrNET/IrLAN node %s...\n",
- discovery->info);
-
- /* Notify the control channel */
- irnet_post_event(NULL, IRNET_DISCOVER,
- discovery->saddr, discovery->daddr, discovery->info,
- get_unaligned((__u16 *)discovery->hints));
-
- DEXIT(IRDA_OCB_TRACE, "\n");
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_expiry_indication (expiry)
- *
- * Got a expiry indication from IrLMP, post an event
- *
- * Note : IrLMP take care of matching the hint mask for us, we only
- * check if it is a "new" node...
- */
-static void
-irnet_expiry_indication(discinfo_t * expiry,
- DISCOVERY_MODE mode,
- void * priv)
-{
- irnet_socket * self = &irnet_server.s;
-
- DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self);
- DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR,
- "Invalid instance (0x%p) !!!\n", priv);
-
- DEBUG(IRDA_OCB_INFO, "IrNET/IrLAN node %s expired...\n",
- expiry->info);
-
- /* Notify the control channel */
- irnet_post_event(NULL, IRNET_EXPIRE,
- expiry->saddr, expiry->daddr, expiry->info,
- get_unaligned((__u16 *)expiry->hints));
-
- DEXIT(IRDA_OCB_TRACE, "\n");
-}
-#endif /* DISCOVERY_EVENTS */
-
-
-/*********************** PROC ENTRY CALLBACKS ***********************/
-/*
- * We create a instance in the /proc filesystem, and here we take care
- * of that...
- */
-
-#ifdef CONFIG_PROC_FS
-static int
-irnet_proc_show(struct seq_file *m, void *v)
-{
- irnet_socket * self;
- char * state;
- int i = 0;
-
- /* Get the IrNET server information... */
- seq_printf(m, "IrNET server - ");
- seq_printf(m, "IrDA state: %s, ",
- (irnet_server.running ? "running" : "dead"));
- seq_printf(m, "stsap_sel: %02x, ", irnet_server.s.stsap_sel);
- seq_printf(m, "dtsap_sel: %02x\n", irnet_server.s.dtsap_sel);
-
- /* Do we need to continue ? */
- if(!irnet_server.running)
- return 0;
-
- /* Protect access to the instance list */
- spin_lock_bh(&irnet_server.spinlock);
-
- /* Get the sockets one by one... */
- self = (irnet_socket *) hashbin_get_first(irnet_server.list);
- while(self != NULL)
- {
- /* Start printing info about the socket. */
- seq_printf(m, "\nIrNET socket %d - ", i++);
-
- /* First, get the requested configuration */
- seq_printf(m, "Requested IrDA name: \"%s\", ", self->rname);
- seq_printf(m, "daddr: %08x, ", self->rdaddr);
- seq_printf(m, "saddr: %08x\n", self->rsaddr);
-
- /* Second, get all the PPP info */
- seq_printf(m, " PPP state: %s",
- (self->ppp_open ? "registered" : "unregistered"));
- if(self->ppp_open)
- {
- seq_printf(m, ", unit: ppp%d",
- ppp_unit_number(&self->chan));
- seq_printf(m, ", channel: %d",
- ppp_channel_index(&self->chan));
- seq_printf(m, ", mru: %d",
- self->mru);
- /* Maybe add self->flags ? Later... */
- }
-
- /* Then, get all the IrDA specific info... */
- if(self->ttp_open)
- state = "connected";
- else
- if(self->tsap != NULL)
- state = "connecting";
- else
- if(self->iriap != NULL)
- state = "searching";
- else
- if(self->ttp_connect)
- state = "weird";
- else
- state = "idle";
- seq_printf(m, "\n IrDA state: %s, ", state);
- seq_printf(m, "daddr: %08x, ", self->daddr);
- seq_printf(m, "stsap_sel: %02x, ", self->stsap_sel);
- seq_printf(m, "dtsap_sel: %02x\n", self->dtsap_sel);
-
- /* Next socket, please... */
- self = (irnet_socket *) hashbin_get_next(irnet_server.list);
- }
-
- /* Spin lock end */
- spin_unlock_bh(&irnet_server.spinlock);
-
- return 0;
-}
-
-static int irnet_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, irnet_proc_show, NULL);
-}
-
-static const struct file_operations irnet_proc_fops = {
- .owner = THIS_MODULE,
- .open = irnet_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-#endif /* PROC_FS */
-
-
-/********************** CONFIGURATION/CLEANUP **********************/
-/*
- * Initialisation and teardown of the IrDA part, called at module
- * insertion and removal...
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Prepare the IrNET layer for operation...
- */
-int __init
-irda_irnet_init(void)
-{
- int err = 0;
-
- DENTER(MODULE_TRACE, "()\n");
-
- /* Pure paranoia - should be redundant */
- memset(&irnet_server, 0, sizeof(struct irnet_root));
-
- /* Setup start of irnet instance list */
- irnet_server.list = hashbin_new(HB_NOLOCK);
- DABORT(irnet_server.list == NULL, -ENOMEM,
- MODULE_ERROR, "Can't allocate hashbin!\n");
- /* Init spinlock for instance list */
- spin_lock_init(&irnet_server.spinlock);
-
- /* Initialise control channel */
- init_waitqueue_head(&irnet_events.rwait);
- irnet_events.index = 0;
- /* Init spinlock for event logging */
- spin_lock_init(&irnet_events.spinlock);
-
-#ifdef CONFIG_PROC_FS
- /* Add a /proc file for irnet infos */
- proc_create("irnet", 0, proc_irda, &irnet_proc_fops);
-#endif /* CONFIG_PROC_FS */
-
- /* Setup the IrNET server */
- err = irnet_setup_server();
-
- if(!err)
- /* We are no longer functional... */
- irnet_server.running = 1;
-
- DEXIT(MODULE_TRACE, "\n");
- return err;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Cleanup at exit...
- */
-void __exit
-irda_irnet_cleanup(void)
-{
- DENTER(MODULE_TRACE, "()\n");
-
- /* We are no longer there... */
- irnet_server.running = 0;
-
-#ifdef CONFIG_PROC_FS
- /* Remove our /proc file */
- remove_proc_entry("irnet", proc_irda);
-#endif /* CONFIG_PROC_FS */
-
- /* Remove our IrNET server from existence */
- irnet_destroy_server();
-
- /* Remove all instances of IrNET socket still present */
- hashbin_delete(irnet_server.list, (FREE_FUNC) irda_irnet_destroy);
-
- DEXIT(MODULE_TRACE, "\n");
-}
diff --git a/drivers/staging/irda/net/irnet/irnet_irda.h b/drivers/staging/irda/net/irnet/irnet_irda.h
deleted file mode 100644
index 3e408952a3f1..000000000000
--- a/drivers/staging/irda/net/irnet/irnet_irda.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * IrNET protocol module : Synchronous PPP over an IrDA socket.
- *
- * Jean II - HPL `00 - <jt@hpl.hp.com>
- *
- * This file contains all definitions and declarations necessary for the
- * IRDA part of the IrNET module (dealing with IrTTP, IrIAS and co).
- * This file is a private header, so other modules don't want to know
- * what's in there...
- */
-
-#ifndef IRNET_IRDA_H
-#define IRNET_IRDA_H
-
-/***************************** INCLUDES *****************************/
-/* Please add other headers in irnet.h */
-
-#include "irnet.h" /* Module global include */
-
-/************************ CONSTANTS & MACROS ************************/
-
-/*
- * Name of the service (socket name) used by IrNET
- */
-/* IAS object name (or part of it) */
-#define IRNET_SERVICE_NAME "IrNetv1"
-/* IAS attribute */
-#define IRNET_IAS_VALUE "IrDA:TinyTP:LsapSel"
-/* LMP notify name for client (only for /proc/net/irda/irlmp) */
-#define IRNET_NOTIFY_NAME "IrNET socket"
-/* LMP notify name for server (only for /proc/net/irda/irlmp) */
-#define IRNET_NOTIFY_NAME_SERV "IrNET server"
-
-/****************************** TYPES ******************************/
-
-/*
- * This is the main structure where we store all the data pertaining to
- * the IrNET server (listen for connection requests) and the root
- * of the IrNET socket list
- */
-typedef struct irnet_root
-{
- irnet_socket s; /* To pretend we are a client... */
-
- /* Generic stuff */
- int magic; /* Paranoia */
- int running; /* Are we operational ? */
-
- /* Link list of all IrNET instances opened */
- hashbin_t * list;
- spinlock_t spinlock; /* Serialize access to the list */
- /* Note : the way hashbin has been designed is absolutely not
- * reentrant, beware... So, we blindly protect all with spinlock */
-
- /* Handle for the hint bit advertised in IrLMP */
- void * skey;
-
- /* Server socket part */
- struct ias_object * ias_obj; /* Our service name + lsap in IAS */
-
-} irnet_root;
-
-
-/**************************** PROTOTYPES ****************************/
-
-/* ----------------------- CONTROL CHANNEL ----------------------- */
-static void
- irnet_post_event(irnet_socket *,
- irnet_event,
- __u32,
- __u32,
- char *,
- __u16);
-/* ----------------------- IRDA SUBROUTINES ----------------------- */
-static inline int
- irnet_open_tsap(irnet_socket *);
-static inline __u8
- irnet_ias_to_tsap(irnet_socket *,
- int,
- struct ias_value *);
-static inline int
- irnet_find_lsap_sel(irnet_socket *);
-static inline int
- irnet_connect_tsap(irnet_socket *);
-static inline int
- irnet_discover_next_daddr(irnet_socket *);
-static inline int
- irnet_discover_daddr_and_lsap_sel(irnet_socket *);
-static inline int
- irnet_dname_to_daddr(irnet_socket *);
-/* ------------------------ SERVER SOCKET ------------------------ */
-static inline int
- irnet_daddr_to_dname(irnet_socket *);
-static inline irnet_socket *
- irnet_find_socket(irnet_socket *);
-static inline int
- irnet_connect_socket(irnet_socket *,
- irnet_socket *,
- struct qos_info *,
- __u32,
- __u8);
-static inline void
- irnet_disconnect_server(irnet_socket *,
- struct sk_buff *);
-static inline int
- irnet_setup_server(void);
-static inline void
- irnet_destroy_server(void);
-/* ---------------------- IRDA-TTP CALLBACKS ---------------------- */
-static int
- irnet_data_indication(void *, /* instance */
- void *, /* sap */
- struct sk_buff *);
-static void
- irnet_disconnect_indication(void *,
- void *,
- LM_REASON,
- struct sk_buff *);
-static void
- irnet_connect_confirm(void *,
- void *,
- struct qos_info *,
- __u32,
- __u8,
- struct sk_buff *);
-static void
- irnet_flow_indication(void *,
- void *,
- LOCAL_FLOW);
-static void
- irnet_status_indication(void *,
- LINK_STATUS,
- LOCK_STATUS);
-static void
- irnet_connect_indication(void *,
- void *,
- struct qos_info *,
- __u32,
- __u8,
- struct sk_buff *);
-/* -------------------- IRDA-IAS/LMP CALLBACKS -------------------- */
-static void
- irnet_getvalue_confirm(int,
- __u16,
- struct ias_value *,
- void *);
-static void
- irnet_discovervalue_confirm(int,
- __u16,
- struct ias_value *,
- void *);
-#ifdef DISCOVERY_EVENTS
-static void
- irnet_discovery_indication(discinfo_t *,
- DISCOVERY_MODE,
- void *);
-static void
- irnet_expiry_indication(discinfo_t *,
- DISCOVERY_MODE,
- void *);
-#endif
-
-/**************************** VARIABLES ****************************/
-
-/*
- * The IrNET server. Listen to connection requests and co...
- */
-static struct irnet_root irnet_server;
-
-/* Control channel stuff (note : extern) */
-struct irnet_ctrl_channel irnet_events;
-
-/* The /proc/net/irda directory, defined elsewhere... */
-#ifdef CONFIG_PROC_FS
-extern struct proc_dir_entry *proc_irda;
-#endif /* CONFIG_PROC_FS */
-
-#endif /* IRNET_IRDA_H */
diff --git a/drivers/staging/irda/net/irnet/irnet_ppp.c b/drivers/staging/irda/net/irnet/irnet_ppp.c
deleted file mode 100644
index c90a158af4b7..000000000000
--- a/drivers/staging/irda/net/irnet/irnet_ppp.c
+++ /dev/null
@@ -1,1189 +0,0 @@
-/*
- * IrNET protocol module : Synchronous PPP over an IrDA socket.
- *
- * Jean II - HPL `00 - <jt@hpl.hp.com>
- *
- * This file implement the PPP interface and /dev/irnet character device.
- * The PPP interface hook to the ppp_generic module, handle all our
- * relationship to the PPP code in the kernel (and by extension to pppd),
- * and exchange PPP frames with this module (send/receive).
- * The /dev/irnet device is used primarily for 2 functions :
- * 1) as a stub for pppd (the ppp daemon), so that we can appropriately
- * generate PPP sessions (we pretend we are a tty).
- * 2) as a control channel (write commands, read events)
- */
-
-#include <linux/sched/signal.h>
-#include <linux/slab.h>
-
-#include "irnet_ppp.h" /* Private header */
-/* Please put other headers in irnet.h - Thanks */
-
-/* Generic PPP callbacks (to call us) */
-static const struct ppp_channel_ops irnet_ppp_ops = {
- .start_xmit = ppp_irnet_send,
- .ioctl = ppp_irnet_ioctl
-};
-
-/************************* CONTROL CHANNEL *************************/
-/*
- * When a pppd instance is not active on /dev/irnet, it acts as a control
- * channel.
- * Writing allow to set up the IrDA destination of the IrNET channel,
- * and any application may be read events happening in IrNET...
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Write is used to send a command to configure a IrNET channel
- * before it is open by pppd. The syntax is : "command argument"
- * Currently there is only two defined commands :
- * o name : set the requested IrDA nickname of the IrNET peer.
- * o addr : set the requested IrDA address of the IrNET peer.
- * Note : the code is crude, but effective...
- */
-static inline ssize_t
-irnet_ctrl_write(irnet_socket * ap,
- const char __user *buf,
- size_t count)
-{
- char command[IRNET_MAX_COMMAND];
- char * start; /* Current command being processed */
- char * next; /* Next command to process */
- int length; /* Length of current command */
-
- DENTER(CTRL_TRACE, "(ap=0x%p, count=%zd)\n", ap, count);
-
- /* Check for overflow... */
- DABORT(count >= IRNET_MAX_COMMAND, -ENOMEM,
- CTRL_ERROR, "Too much data !!!\n");
-
- /* Get the data in the driver */
- if(copy_from_user(command, buf, count))
- {
- DERROR(CTRL_ERROR, "Invalid user space pointer.\n");
- return -EFAULT;
- }
-
- /* Safe terminate the string */
- command[count] = '\0';
- DEBUG(CTRL_INFO, "Command line received is ``%s'' (%zd).\n",
- command, count);
-
- /* Check every commands in the command line */
- next = command;
- while(next != NULL)
- {
- /* Look at the next command */
- start = next;
-
- /* Scrap whitespaces before the command */
- start = skip_spaces(start);
-
- /* ',' is our command separator */
- next = strchr(start, ',');
- if(next)
- {
- *next = '\0'; /* Terminate command */
- length = next - start; /* Length */
- next++; /* Skip the '\0' */
- }
- else
- length = strlen(start);
-
- DEBUG(CTRL_INFO, "Found command ``%s'' (%d).\n", start, length);
-
- /* Check if we recognised one of the known command
- * We can't use "switch" with strings, so hack with "continue" */
-
- /* First command : name -> Requested IrDA nickname */
- if(!strncmp(start, "name", 4))
- {
- /* Copy the name only if is included and not "any" */
- if((length > 5) && (strcmp(start + 5, "any")))
- {
- /* Strip out trailing whitespaces */
- while(isspace(start[length - 1]))
- length--;
-
- DABORT(length < 5 || length > NICKNAME_MAX_LEN + 5,
- -EINVAL, CTRL_ERROR, "Invalid nickname.\n");
-
- /* Copy the name for later reuse */
- memcpy(ap->rname, start + 5, length - 5);
- ap->rname[length - 5] = '\0';
- }
- else
- ap->rname[0] = '\0';
- DEBUG(CTRL_INFO, "Got rname = ``%s''\n", ap->rname);
-
- /* Restart the loop */
- continue;
- }
-
- /* Second command : addr, daddr -> Requested IrDA destination address
- * Also process : saddr -> Requested IrDA source address */
- if((!strncmp(start, "addr", 4)) ||
- (!strncmp(start, "daddr", 5)) ||
- (!strncmp(start, "saddr", 5)))
- {
- __u32 addr = DEV_ADDR_ANY;
-
- /* Copy the address only if is included and not "any" */
- if((length > 5) && (strcmp(start + 5, "any")))
- {
- char * begp = start + 5;
- char * endp;
-
- /* Scrap whitespaces before the command */
- begp = skip_spaces(begp);
-
- /* Convert argument to a number (last arg is the base) */
- addr = simple_strtoul(begp, &endp, 16);
- /* Has it worked ? (endp should be start + length) */
- DABORT(endp <= (start + 5), -EINVAL,
- CTRL_ERROR, "Invalid address.\n");
- }
- /* Which type of address ? */
- if(start[0] == 's')
- {
- /* Save it */
- ap->rsaddr = addr;
- DEBUG(CTRL_INFO, "Got rsaddr = %08x\n", ap->rsaddr);
- }
- else
- {
- /* Save it */
- ap->rdaddr = addr;
- DEBUG(CTRL_INFO, "Got rdaddr = %08x\n", ap->rdaddr);
- }
-
- /* Restart the loop */
- continue;
- }
-
- /* Other possible command : connect N (number of retries) */
-
- /* No command matched -> Failed... */
- DABORT(1, -EINVAL, CTRL_ERROR, "Not a recognised IrNET command.\n");
- }
-
- /* Success : we have parsed all commands successfully */
- return count;
-}
-
-#ifdef INITIAL_DISCOVERY
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_get_discovery_log (self)
- *
- * Query the content on the discovery log if not done
- *
- * This function query the current content of the discovery log
- * at the startup of the event channel and save it in the internal struct.
- */
-static void
-irnet_get_discovery_log(irnet_socket * ap)
-{
- __u16 mask = irlmp_service_to_hint(S_LAN);
-
- /* Ask IrLMP for the current discovery log */
- ap->discoveries = irlmp_get_discoveries(&ap->disco_number, mask,
- DISCOVERY_DEFAULT_SLOTS);
-
- /* Check if the we got some results */
- if(ap->discoveries == NULL)
- ap->disco_number = -1;
-
- DEBUG(CTRL_INFO, "Got the log (0x%p), size is %d\n",
- ap->discoveries, ap->disco_number);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_read_discovery_log (self, event)
- *
- * Read the content on the discovery log
- *
- * This function dump the current content of the discovery log
- * at the startup of the event channel.
- * Return 1 if wrote an event on the control channel...
- *
- * State of the ap->disco_XXX variables :
- * Socket creation : discoveries = NULL ; disco_index = 0 ; disco_number = 0
- * While reading : discoveries = ptr ; disco_index = X ; disco_number = Y
- * After reading : discoveries = NULL ; disco_index = Y ; disco_number = -1
- */
-static inline int
-irnet_read_discovery_log(irnet_socket *ap, char *event, int buf_size)
-{
- int done_event = 0;
-
- DENTER(CTRL_TRACE, "(ap=0x%p, event=0x%p)\n",
- ap, event);
-
- /* Test if we have some work to do or we have already finished */
- if(ap->disco_number == -1)
- {
- DEBUG(CTRL_INFO, "Already done\n");
- return 0;
- }
-
- /* Test if it's the first time and therefore we need to get the log */
- if(ap->discoveries == NULL)
- irnet_get_discovery_log(ap);
-
- /* Check if we have more item to dump */
- if(ap->disco_index < ap->disco_number)
- {
- /* Write an event */
- snprintf(event, buf_size,
- "Found %08x (%s) behind %08x {hints %02X-%02X}\n",
- ap->discoveries[ap->disco_index].daddr,
- ap->discoveries[ap->disco_index].info,
- ap->discoveries[ap->disco_index].saddr,
- ap->discoveries[ap->disco_index].hints[0],
- ap->discoveries[ap->disco_index].hints[1]);
- DEBUG(CTRL_INFO, "Writing discovery %d : %s\n",
- ap->disco_index, ap->discoveries[ap->disco_index].info);
-
- /* We have an event */
- done_event = 1;
- /* Next discovery */
- ap->disco_index++;
- }
-
- /* Check if we have done the last item */
- if(ap->disco_index >= ap->disco_number)
- {
- /* No more items : remove the log and signal termination */
- DEBUG(CTRL_INFO, "Cleaning up log (0x%p)\n",
- ap->discoveries);
- if(ap->discoveries != NULL)
- {
- /* Cleanup our copy of the discovery log */
- kfree(ap->discoveries);
- ap->discoveries = NULL;
- }
- ap->disco_number = -1;
- }
-
- return done_event;
-}
-#endif /* INITIAL_DISCOVERY */
-
-/*------------------------------------------------------------------*/
-/*
- * Read is used to get IrNET events
- */
-static inline ssize_t
-irnet_ctrl_read(irnet_socket * ap,
- struct file * file,
- char __user * buf,
- size_t count)
-{
- DECLARE_WAITQUEUE(wait, current);
- char event[75];
- ssize_t ret = 0;
-
- DENTER(CTRL_TRACE, "(ap=0x%p, count=%zd)\n", ap, count);
-
-#ifdef INITIAL_DISCOVERY
- /* Check if we have read the log */
- if (irnet_read_discovery_log(ap, event, sizeof(event)))
- {
- count = min(strlen(event), count);
- if (copy_to_user(buf, event, count))
- {
- DERROR(CTRL_ERROR, "Invalid user space pointer.\n");
- return -EFAULT;
- }
-
- DEXIT(CTRL_TRACE, "\n");
- return count;
- }
-#endif /* INITIAL_DISCOVERY */
-
- /* Put ourselves on the wait queue to be woken up */
- add_wait_queue(&irnet_events.rwait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- for(;;)
- {
- /* If there is unread events */
- ret = 0;
- if(ap->event_index != irnet_events.index)
- break;
- ret = -EAGAIN;
- if(file->f_flags & O_NONBLOCK)
- break;
- ret = -ERESTARTSYS;
- if(signal_pending(current))
- break;
- /* Yield and wait to be woken up */
- schedule();
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&irnet_events.rwait, &wait);
-
- /* Did we got it ? */
- if(ret != 0)
- {
- /* No, return the error code */
- DEXIT(CTRL_TRACE, " - ret %zd\n", ret);
- return ret;
- }
-
- /* Which event is it ? */
- switch(irnet_events.log[ap->event_index].event)
- {
- case IRNET_DISCOVER:
- snprintf(event, sizeof(event),
- "Discovered %08x (%s) behind %08x {hints %02X-%02X}\n",
- irnet_events.log[ap->event_index].daddr,
- irnet_events.log[ap->event_index].name,
- irnet_events.log[ap->event_index].saddr,
- irnet_events.log[ap->event_index].hints.byte[0],
- irnet_events.log[ap->event_index].hints.byte[1]);
- break;
- case IRNET_EXPIRE:
- snprintf(event, sizeof(event),
- "Expired %08x (%s) behind %08x {hints %02X-%02X}\n",
- irnet_events.log[ap->event_index].daddr,
- irnet_events.log[ap->event_index].name,
- irnet_events.log[ap->event_index].saddr,
- irnet_events.log[ap->event_index].hints.byte[0],
- irnet_events.log[ap->event_index].hints.byte[1]);
- break;
- case IRNET_CONNECT_TO:
- snprintf(event, sizeof(event), "Connected to %08x (%s) on ppp%d\n",
- irnet_events.log[ap->event_index].daddr,
- irnet_events.log[ap->event_index].name,
- irnet_events.log[ap->event_index].unit);
- break;
- case IRNET_CONNECT_FROM:
- snprintf(event, sizeof(event), "Connection from %08x (%s) on ppp%d\n",
- irnet_events.log[ap->event_index].daddr,
- irnet_events.log[ap->event_index].name,
- irnet_events.log[ap->event_index].unit);
- break;
- case IRNET_REQUEST_FROM:
- snprintf(event, sizeof(event), "Request from %08x (%s) behind %08x\n",
- irnet_events.log[ap->event_index].daddr,
- irnet_events.log[ap->event_index].name,
- irnet_events.log[ap->event_index].saddr);
- break;
- case IRNET_NOANSWER_FROM:
- snprintf(event, sizeof(event), "No-answer from %08x (%s) on ppp%d\n",
- irnet_events.log[ap->event_index].daddr,
- irnet_events.log[ap->event_index].name,
- irnet_events.log[ap->event_index].unit);
- break;
- case IRNET_BLOCKED_LINK:
- snprintf(event, sizeof(event), "Blocked link with %08x (%s) on ppp%d\n",
- irnet_events.log[ap->event_index].daddr,
- irnet_events.log[ap->event_index].name,
- irnet_events.log[ap->event_index].unit);
- break;
- case IRNET_DISCONNECT_FROM:
- snprintf(event, sizeof(event), "Disconnection from %08x (%s) on ppp%d\n",
- irnet_events.log[ap->event_index].daddr,
- irnet_events.log[ap->event_index].name,
- irnet_events.log[ap->event_index].unit);
- break;
- case IRNET_DISCONNECT_TO:
- snprintf(event, sizeof(event), "Disconnected to %08x (%s)\n",
- irnet_events.log[ap->event_index].daddr,
- irnet_events.log[ap->event_index].name);
- break;
- default:
- snprintf(event, sizeof(event), "Bug\n");
- }
- /* Increment our event index */
- ap->event_index = (ap->event_index + 1) % IRNET_MAX_EVENTS;
-
- DEBUG(CTRL_INFO, "Event is :%s", event);
-
- count = min(strlen(event), count);
- if (copy_to_user(buf, event, count))
- {
- DERROR(CTRL_ERROR, "Invalid user space pointer.\n");
- return -EFAULT;
- }
-
- DEXIT(CTRL_TRACE, "\n");
- return count;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Poll : called when someone do a select on /dev/irnet.
- * Just check if there are new events...
- */
-static inline __poll_t
-irnet_ctrl_poll(irnet_socket * ap,
- struct file * file,
- poll_table * wait)
-{
- __poll_t mask;
-
- DENTER(CTRL_TRACE, "(ap=0x%p)\n", ap);
-
- poll_wait(file, &irnet_events.rwait, wait);
- mask = EPOLLOUT | EPOLLWRNORM;
- /* If there is unread events */
- if(ap->event_index != irnet_events.index)
- mask |= EPOLLIN | EPOLLRDNORM;
-#ifdef INITIAL_DISCOVERY
- if(ap->disco_number != -1)
- {
- /* Test if it's the first time and therefore we need to get the log */
- if(ap->discoveries == NULL)
- irnet_get_discovery_log(ap);
- /* Recheck */
- if(ap->disco_number != -1)
- mask |= EPOLLIN | EPOLLRDNORM;
- }
-#endif /* INITIAL_DISCOVERY */
-
- DEXIT(CTRL_TRACE, " - mask=0x%X\n", mask);
- return mask;
-}
-
-
-/*********************** FILESYSTEM CALLBACKS ***********************/
-/*
- * Implement the usual open, read, write functions that will be called
- * by the file system when some action is performed on /dev/irnet.
- * Most of those actions will in fact be performed by "pppd" or
- * the control channel, we just act as a redirector...
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Open : when somebody open /dev/irnet
- * We basically create a new instance of irnet and initialise it.
- */
-static int
-dev_irnet_open(struct inode * inode,
- struct file * file)
-{
- struct irnet_socket * ap;
- int err;
-
- DENTER(FS_TRACE, "(file=0x%p)\n", file);
-
-#ifdef SECURE_DEVIRNET
- /* This could (should?) be enforced by the permissions on /dev/irnet. */
- if(!capable(CAP_NET_ADMIN))
- return -EPERM;
-#endif /* SECURE_DEVIRNET */
-
- /* Allocate a private structure for this IrNET instance */
- ap = kzalloc(sizeof(*ap), GFP_KERNEL);
- DABORT(ap == NULL, -ENOMEM, FS_ERROR, "Can't allocate struct irnet...\n");
-
- /* initialize the irnet structure */
- ap->file = file;
-
- /* PPP channel setup */
- ap->ppp_open = 0;
- ap->chan.private = ap;
- ap->chan.ops = &irnet_ppp_ops;
- ap->chan.mtu = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN);
- ap->chan.hdrlen = 2 + TTP_MAX_HEADER; /* for A/C + Max IrDA hdr */
- /* PPP parameters */
- ap->mru = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN);
- ap->xaccm[0] = ~0U;
- ap->xaccm[3] = 0x60000000U;
- ap->raccm = ~0U;
-
- /* Setup the IrDA part... */
- err = irda_irnet_create(ap);
- if(err)
- {
- DERROR(FS_ERROR, "Can't setup IrDA link...\n");
- kfree(ap);
-
- return err;
- }
-
- /* For the control channel */
- ap->event_index = irnet_events.index; /* Cancel all past events */
-
- mutex_init(&ap->lock);
-
- /* Put our stuff where we will be able to find it later */
- file->private_data = ap;
-
- DEXIT(FS_TRACE, " - ap=0x%p\n", ap);
-
- return 0;
-}
-
-
-/*------------------------------------------------------------------*/
-/*
- * Close : when somebody close /dev/irnet
- * Destroy the instance of /dev/irnet
- */
-static int
-dev_irnet_close(struct inode * inode,
- struct file * file)
-{
- irnet_socket * ap = file->private_data;
-
- DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n",
- file, ap);
- DABORT(ap == NULL, 0, FS_ERROR, "ap is NULL !!!\n");
-
- /* Detach ourselves */
- file->private_data = NULL;
-
- /* Close IrDA stuff */
- irda_irnet_destroy(ap);
-
- /* Disconnect from the generic PPP layer if not already done */
- if(ap->ppp_open)
- {
- DERROR(FS_ERROR, "Channel still registered - deregistering !\n");
- ap->ppp_open = 0;
- ppp_unregister_channel(&ap->chan);
- }
-
- kfree(ap);
-
- DEXIT(FS_TRACE, "\n");
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Write does nothing.
- * (we receive packet from ppp_generic through ppp_irnet_send())
- */
-static ssize_t
-dev_irnet_write(struct file * file,
- const char __user *buf,
- size_t count,
- loff_t * ppos)
-{
- irnet_socket * ap = file->private_data;
-
- DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%zd)\n",
- file, ap, count);
- DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n");
-
- /* If we are connected to ppp_generic, let it handle the job */
- if(ap->ppp_open)
- return -EAGAIN;
- else
- return irnet_ctrl_write(ap, buf, count);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Read doesn't do much either.
- * (pppd poll us, but ultimately reads through /dev/ppp)
- */
-static ssize_t
-dev_irnet_read(struct file * file,
- char __user * buf,
- size_t count,
- loff_t * ppos)
-{
- irnet_socket * ap = file->private_data;
-
- DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%zd)\n",
- file, ap, count);
- DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n");
-
- /* If we are connected to ppp_generic, let it handle the job */
- if(ap->ppp_open)
- return -EAGAIN;
- else
- return irnet_ctrl_read(ap, file, buf, count);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Poll : called when someone do a select on /dev/irnet
- */
-static __poll_t
-dev_irnet_poll(struct file * file,
- poll_table * wait)
-{
- irnet_socket * ap = file->private_data;
- __poll_t mask;
-
- DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n",
- file, ap);
-
- mask = EPOLLOUT | EPOLLWRNORM;
- DABORT(ap == NULL, mask, FS_ERROR, "ap is NULL !!!\n");
-
- /* If we are connected to ppp_generic, let it handle the job */
- if(!ap->ppp_open)
- mask |= irnet_ctrl_poll(ap, file, wait);
-
- DEXIT(FS_TRACE, " - mask=0x%X\n", mask);
- return mask;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * IOCtl : Called when someone does some ioctls on /dev/irnet
- * This is the way pppd configure us and control us while the PPP
- * instance is active.
- */
-static long
-dev_irnet_ioctl(
- struct file * file,
- unsigned int cmd,
- unsigned long arg)
-{
- irnet_socket * ap = file->private_data;
- int err;
- int val;
- void __user *argp = (void __user *)arg;
-
- DENTER(FS_TRACE, "(file=0x%p, ap=0x%p, cmd=0x%X)\n",
- file, ap, cmd);
-
- /* Basic checks... */
- DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n");
-#ifdef SECURE_DEVIRNET
- if(!capable(CAP_NET_ADMIN))
- return -EPERM;
-#endif /* SECURE_DEVIRNET */
-
- err = -EFAULT;
- switch(cmd)
- {
- /* Set discipline (should be N_SYNC_PPP or N_TTY) */
- case TIOCSETD:
- if(get_user(val, (int __user *)argp))
- break;
- if((val == N_SYNC_PPP) || (val == N_PPP))
- {
- DEBUG(FS_INFO, "Entering PPP discipline.\n");
- /* PPP channel setup (ap->chan in configured in dev_irnet_open())*/
- if (mutex_lock_interruptible(&ap->lock))
- return -EINTR;
-
- err = ppp_register_channel(&ap->chan);
- if(err == 0)
- {
- /* Our ppp side is active */
- ap->ppp_open = 1;
-
- DEBUG(FS_INFO, "Trying to establish a connection.\n");
- /* Setup the IrDA link now - may fail... */
- irda_irnet_connect(ap);
- }
- else
- DERROR(FS_ERROR, "Can't setup PPP channel...\n");
-
- mutex_unlock(&ap->lock);
- }
- else
- {
- /* In theory, should be N_TTY */
- DEBUG(FS_INFO, "Exiting PPP discipline.\n");
- /* Disconnect from the generic PPP layer */
- if (mutex_lock_interruptible(&ap->lock))
- return -EINTR;
-
- if(ap->ppp_open)
- {
- ap->ppp_open = 0;
- ppp_unregister_channel(&ap->chan);
- }
- else
- DERROR(FS_ERROR, "Channel not registered !\n");
- err = 0;
-
- mutex_unlock(&ap->lock);
- }
- break;
-
- /* Query PPP channel and unit number */
- case PPPIOCGCHAN:
- if (mutex_lock_interruptible(&ap->lock))
- return -EINTR;
-
- if(ap->ppp_open && !put_user(ppp_channel_index(&ap->chan),
- (int __user *)argp))
- err = 0;
-
- mutex_unlock(&ap->lock);
- break;
- case PPPIOCGUNIT:
- if (mutex_lock_interruptible(&ap->lock))
- return -EINTR;
-
- if(ap->ppp_open && !put_user(ppp_unit_number(&ap->chan),
- (int __user *)argp))
- err = 0;
-
- mutex_unlock(&ap->lock);
- break;
-
- /* All these ioctls can be passed both directly and from ppp_generic,
- * so we just deal with them in one place...
- */
- case PPPIOCGFLAGS:
- case PPPIOCSFLAGS:
- case PPPIOCGASYNCMAP:
- case PPPIOCSASYNCMAP:
- case PPPIOCGRASYNCMAP:
- case PPPIOCSRASYNCMAP:
- case PPPIOCGXASYNCMAP:
- case PPPIOCSXASYNCMAP:
- case PPPIOCGMRU:
- case PPPIOCSMRU:
- DEBUG(FS_INFO, "Standard PPP ioctl.\n");
- if(!capable(CAP_NET_ADMIN))
- err = -EPERM;
- else {
- if (mutex_lock_interruptible(&ap->lock))
- return -EINTR;
-
- err = ppp_irnet_ioctl(&ap->chan, cmd, arg);
-
- mutex_unlock(&ap->lock);
- }
- break;
-
- /* TTY IOCTLs : Pretend that we are a tty, to keep pppd happy */
- /* Get termios */
- case TCGETS:
- DEBUG(FS_INFO, "Get termios.\n");
- if (mutex_lock_interruptible(&ap->lock))
- return -EINTR;
-
-#ifndef TCGETS2
- if(!kernel_termios_to_user_termios((struct termios __user *)argp, &ap->termios))
- err = 0;
-#else
- if(kernel_termios_to_user_termios_1((struct termios __user *)argp, &ap->termios))
- err = 0;
-#endif
-
- mutex_unlock(&ap->lock);
- break;
- /* Set termios */
- case TCSETSF:
- DEBUG(FS_INFO, "Set termios.\n");
- if (mutex_lock_interruptible(&ap->lock))
- return -EINTR;
-
-#ifndef TCGETS2
- if(!user_termios_to_kernel_termios(&ap->termios, (struct termios __user *)argp))
- err = 0;
-#else
- if(!user_termios_to_kernel_termios_1(&ap->termios, (struct termios __user *)argp))
- err = 0;
-#endif
-
- mutex_unlock(&ap->lock);
- break;
-
- /* Set DTR/RTS */
- case TIOCMBIS:
- case TIOCMBIC:
- /* Set exclusive/non-exclusive mode */
- case TIOCEXCL:
- case TIOCNXCL:
- DEBUG(FS_INFO, "TTY compatibility.\n");
- err = 0;
- break;
-
- case TCGETA:
- DEBUG(FS_INFO, "TCGETA\n");
- break;
-
- case TCFLSH:
- DEBUG(FS_INFO, "TCFLSH\n");
- /* Note : this will flush buffers in PPP, so it *must* be done
- * We should also worry that we don't accept junk here and that
- * we get rid of our own buffers */
-#ifdef FLUSH_TO_PPP
- if (mutex_lock_interruptible(&ap->lock))
- return -EINTR;
- ppp_output_wakeup(&ap->chan);
- mutex_unlock(&ap->lock);
-#endif /* FLUSH_TO_PPP */
- err = 0;
- break;
-
- case FIONREAD:
- DEBUG(FS_INFO, "FIONREAD\n");
- val = 0;
- if(put_user(val, (int __user *)argp))
- break;
- err = 0;
- break;
-
- default:
- DERROR(FS_ERROR, "Unsupported ioctl (0x%X)\n", cmd);
- err = -ENOTTY;
- }
-
- DEXIT(FS_TRACE, " - err = 0x%X\n", err);
- return err;
-}
-
-/************************** PPP CALLBACKS **************************/
-/*
- * This are the functions that the generic PPP driver in the kernel
- * will call to communicate to us.
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Prepare the ppp frame for transmission over the IrDA socket.
- * We make sure that the header space is enough, and we change ppp header
- * according to flags passed by pppd.
- * This is not a callback, but just a helper function used in ppp_irnet_send()
- */
-static inline struct sk_buff *
-irnet_prepare_skb(irnet_socket * ap,
- struct sk_buff * skb)
-{
- unsigned char * data;
- int proto; /* PPP protocol */
- int islcp; /* Protocol == LCP */
- int needaddr; /* Need PPP address */
-
- DENTER(PPP_TRACE, "(ap=0x%p, skb=0x%p)\n",
- ap, skb);
-
- /* Extract PPP protocol from the frame */
- data = skb->data;
- proto = (data[0] << 8) + data[1];
-
- /* LCP packets with codes between 1 (configure-request)
- * and 7 (code-reject) must be sent as though no options
- * have been negotiated. */
- islcp = (proto == PPP_LCP) && (1 <= data[2]) && (data[2] <= 7);
-
- /* compress protocol field if option enabled */
- if((data[0] == 0) && (ap->flags & SC_COMP_PROT) && (!islcp))
- skb_pull(skb,1);
-
- /* Check if we need address/control fields */
- needaddr = 2*((ap->flags & SC_COMP_AC) == 0 || islcp);
-
- /* Is the skb headroom large enough to contain all IrDA-headers? */
- if((skb_headroom(skb) < (ap->max_header_size + needaddr)) ||
- (skb_shared(skb)))
- {
- struct sk_buff * new_skb;
-
- DEBUG(PPP_INFO, "Reallocating skb\n");
-
- /* Create a new skb */
- new_skb = skb_realloc_headroom(skb, ap->max_header_size + needaddr);
-
- /* We have to free the original skb anyway */
- dev_kfree_skb(skb);
-
- /* Did the realloc succeed ? */
- DABORT(new_skb == NULL, NULL, PPP_ERROR, "Could not realloc skb\n");
-
- /* Use the new skb instead */
- skb = new_skb;
- }
-
- /* prepend address/control fields if necessary */
- if(needaddr)
- {
- skb_push(skb, 2);
- skb->data[0] = PPP_ALLSTATIONS;
- skb->data[1] = PPP_UI;
- }
-
- DEXIT(PPP_TRACE, "\n");
-
- return skb;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Send a packet to the peer over the IrTTP connection.
- * Returns 1 iff the packet was accepted.
- * Returns 0 iff packet was not consumed.
- * If the packet was not accepted, we will call ppp_output_wakeup
- * at some later time to reactivate flow control in ppp_generic.
- */
-static int
-ppp_irnet_send(struct ppp_channel * chan,
- struct sk_buff * skb)
-{
- irnet_socket * self = (struct irnet_socket *) chan->private;
- int ret;
-
- DENTER(PPP_TRACE, "(channel=0x%p, ap/self=0x%p)\n",
- chan, self);
-
- /* Check if things are somewhat valid... */
- DASSERT(self != NULL, 0, PPP_ERROR, "Self is NULL !!!\n");
-
- /* Check if we are connected */
- if(!(test_bit(0, &self->ttp_open)))
- {
-#ifdef CONNECT_IN_SEND
- /* Let's try to connect one more time... */
- /* Note : we won't be connected after this call, but we should be
- * ready for next packet... */
- /* If we are already connecting, this will fail */
- irda_irnet_connect(self);
-#endif /* CONNECT_IN_SEND */
-
- DEBUG(PPP_INFO, "IrTTP not ready ! (%ld-%ld)\n",
- self->ttp_open, self->ttp_connect);
-
- /* Note : we can either drop the packet or block the packet.
- *
- * Blocking the packet allow us a better connection time,
- * because by calling ppp_output_wakeup() we can have
- * ppp_generic resending the LCP request immediately to us,
- * rather than waiting for one of pppd periodic transmission of
- * LCP request.
- *
- * On the other hand, if we block all packet, all those periodic
- * transmissions of pppd accumulate in ppp_generic, creating a
- * backlog of LCP request. When we eventually connect later on,
- * we have to transmit all this backlog before we can connect
- * proper (if we don't timeout before).
- *
- * The current strategy is as follow :
- * While we are attempting to connect, we block packets to get
- * a better connection time.
- * If we fail to connect, we drain the queue and start dropping packets
- */
-#ifdef BLOCK_WHEN_CONNECT
- /* If we are attempting to connect */
- if(test_bit(0, &self->ttp_connect))
- {
- /* Blocking packet, ppp_generic will retry later */
- return 0;
- }
-#endif /* BLOCK_WHEN_CONNECT */
-
- /* Dropping packet, pppd will retry later */
- dev_kfree_skb(skb);
- return 1;
- }
-
- /* Check if the queue can accept any packet, otherwise block */
- if(self->tx_flow != FLOW_START)
- DRETURN(0, PPP_INFO, "IrTTP queue full (%d skbs)...\n",
- skb_queue_len(&self->tsap->tx_queue));
-
- /* Prepare ppp frame for transmission */
- skb = irnet_prepare_skb(self, skb);
- DABORT(skb == NULL, 1, PPP_ERROR, "Prepare skb for Tx failed.\n");
-
- /* Send the packet to IrTTP */
- ret = irttp_data_request(self->tsap, skb);
- if(ret < 0)
- {
- /*
- * > IrTTPs tx queue is full, so we just have to
- * > drop the frame! You might think that we should
- * > just return -1 and don't deallocate the frame,
- * > but that is dangerous since it's possible that
- * > we have replaced the original skb with a new
- * > one with larger headroom, and that would really
- * > confuse do_dev_queue_xmit() in dev.c! I have
- * > tried :-) DB
- * Correction : we verify the flow control above (self->tx_flow),
- * so we come here only if IrTTP doesn't like the packet (empty,
- * too large, IrTTP not connected). In those rare cases, it's ok
- * to drop it, we don't want to see it here again...
- * Jean II
- */
- DERROR(PPP_ERROR, "IrTTP doesn't like this packet !!! (0x%X)\n", ret);
- /* irttp_data_request already free the packet */
- }
-
- DEXIT(PPP_TRACE, "\n");
- return 1; /* Packet has been consumed */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Take care of the ioctls that ppp_generic doesn't want to deal with...
- * Note : we are also called from dev_irnet_ioctl().
- */
-static int
-ppp_irnet_ioctl(struct ppp_channel * chan,
- unsigned int cmd,
- unsigned long arg)
-{
- irnet_socket * ap = (struct irnet_socket *) chan->private;
- int err;
- int val;
- u32 accm[8];
- void __user *argp = (void __user *)arg;
-
- DENTER(PPP_TRACE, "(channel=0x%p, ap=0x%p, cmd=0x%X)\n",
- chan, ap, cmd);
-
- /* Basic checks... */
- DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n");
-
- err = -EFAULT;
- switch(cmd)
- {
- /* PPP flags */
- case PPPIOCGFLAGS:
- val = ap->flags | ap->rbits;
- if(put_user(val, (int __user *) argp))
- break;
- err = 0;
- break;
- case PPPIOCSFLAGS:
- if(get_user(val, (int __user *) argp))
- break;
- ap->flags = val & ~SC_RCV_BITS;
- ap->rbits = val & SC_RCV_BITS;
- err = 0;
- break;
-
- /* Async map stuff - all dummy to please pppd */
- case PPPIOCGASYNCMAP:
- if(put_user(ap->xaccm[0], (u32 __user *) argp))
- break;
- err = 0;
- break;
- case PPPIOCSASYNCMAP:
- if(get_user(ap->xaccm[0], (u32 __user *) argp))
- break;
- err = 0;
- break;
- case PPPIOCGRASYNCMAP:
- if(put_user(ap->raccm, (u32 __user *) argp))
- break;
- err = 0;
- break;
- case PPPIOCSRASYNCMAP:
- if(get_user(ap->raccm, (u32 __user *) argp))
- break;
- err = 0;
- break;
- case PPPIOCGXASYNCMAP:
- if(copy_to_user(argp, ap->xaccm, sizeof(ap->xaccm)))
- break;
- err = 0;
- break;
- case PPPIOCSXASYNCMAP:
- if(copy_from_user(accm, argp, sizeof(accm)))
- break;
- accm[2] &= ~0x40000000U; /* can't escape 0x5e */
- accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */
- memcpy(ap->xaccm, accm, sizeof(ap->xaccm));
- err = 0;
- break;
-
- /* Max PPP frame size */
- case PPPIOCGMRU:
- if(put_user(ap->mru, (int __user *) argp))
- break;
- err = 0;
- break;
- case PPPIOCSMRU:
- if(get_user(val, (int __user *) argp))
- break;
- if(val < PPP_MRU)
- val = PPP_MRU;
- ap->mru = val;
- err = 0;
- break;
-
- default:
- DEBUG(PPP_INFO, "Unsupported ioctl (0x%X)\n", cmd);
- err = -ENOIOCTLCMD;
- }
-
- DEXIT(PPP_TRACE, " - err = 0x%X\n", err);
- return err;
-}
-
-/************************** INITIALISATION **************************/
-/*
- * Module initialisation and all that jazz...
- */
-
-/*------------------------------------------------------------------*/
-/*
- * Hook our device callbacks in the filesystem, to connect our code
- * to /dev/irnet
- */
-static inline int __init
-ppp_irnet_init(void)
-{
- int err = 0;
-
- DENTER(MODULE_TRACE, "()\n");
-
- /* Allocate ourselves as a minor in the misc range */
- err = misc_register(&irnet_misc_device);
-
- DEXIT(MODULE_TRACE, "\n");
- return err;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Cleanup at exit...
- */
-static inline void __exit
-ppp_irnet_cleanup(void)
-{
- DENTER(MODULE_TRACE, "()\n");
-
- /* De-allocate /dev/irnet minor in misc range */
- misc_deregister(&irnet_misc_device);
-
- DEXIT(MODULE_TRACE, "\n");
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Module main entry point
- */
-static int __init
-irnet_init(void)
-{
- int err;
-
- /* Initialise both parts... */
- err = irda_irnet_init();
- if(!err)
- err = ppp_irnet_init();
- return err;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Module exit
- */
-static void __exit
-irnet_cleanup(void)
-{
- irda_irnet_cleanup();
- ppp_irnet_cleanup();
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Module magic
- */
-module_init(irnet_init);
-module_exit(irnet_cleanup);
-MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>");
-MODULE_DESCRIPTION("IrNET : Synchronous PPP over IrDA");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV(10, 187);
diff --git a/drivers/staging/irda/net/irnet/irnet_ppp.h b/drivers/staging/irda/net/irnet/irnet_ppp.h
deleted file mode 100644
index e6d5aa2a8aac..000000000000
--- a/drivers/staging/irda/net/irnet/irnet_ppp.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * IrNET protocol module : Synchronous PPP over an IrDA socket.
- *
- * Jean II - HPL `00 - <jt@hpl.hp.com>
- *
- * This file contains all definitions and declarations necessary for the
- * PPP part of the IrNET module.
- * This file is a private header, so other modules don't want to know
- * what's in there...
- */
-
-#ifndef IRNET_PPP_H
-#define IRNET_PPP_H
-
-/***************************** INCLUDES *****************************/
-
-#include "irnet.h" /* Module global include */
-#include <linux/miscdevice.h>
-
-/************************ CONSTANTS & MACROS ************************/
-
-/* IrNET control channel stuff */
-#define IRNET_MAX_COMMAND 256 /* Max length of a command line */
-
-/* PPP hardcore stuff */
-
-/* Bits in rbits (PPP flags in irnet struct) */
-#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
-
-/* Bit numbers in busy */
-#define XMIT_BUSY 0
-#define RECV_BUSY 1
-#define XMIT_WAKEUP 2
-#define XMIT_FULL 3
-
-/* Queue management */
-#define PPPSYNC_MAX_RQLEN 32 /* arbitrary */
-
-/****************************** TYPES ******************************/
-
-
-/**************************** PROTOTYPES ****************************/
-
-/* ----------------------- CONTROL CHANNEL ----------------------- */
-static inline ssize_t
- irnet_ctrl_write(irnet_socket *,
- const char *,
- size_t);
-static inline ssize_t
- irnet_ctrl_read(irnet_socket *,
- struct file *,
- char *,
- size_t);
-static inline unsigned int
- irnet_ctrl_poll(irnet_socket *,
- struct file *,
- poll_table *);
-/* ----------------------- CHARACTER DEVICE ----------------------- */
-static int
- dev_irnet_open(struct inode *, /* fs callback : open */
- struct file *),
- dev_irnet_close(struct inode *,
- struct file *);
-static ssize_t
- dev_irnet_write(struct file *,
- const char __user *,
- size_t,
- loff_t *),
- dev_irnet_read(struct file *,
- char __user *,
- size_t,
- loff_t *);
-static __poll_t
- dev_irnet_poll(struct file *,
- poll_table *);
-static long
- dev_irnet_ioctl(struct file *,
- unsigned int,
- unsigned long);
-/* ------------------------ PPP INTERFACE ------------------------ */
-static inline struct sk_buff *
- irnet_prepare_skb(irnet_socket *,
- struct sk_buff *);
-static int
- ppp_irnet_send(struct ppp_channel *,
- struct sk_buff *);
-static int
- ppp_irnet_ioctl(struct ppp_channel *,
- unsigned int,
- unsigned long);
-
-/**************************** VARIABLES ****************************/
-
-/* Filesystem callbacks (to call us) */
-static const struct file_operations irnet_device_fops =
-{
- .owner = THIS_MODULE,
- .read = dev_irnet_read,
- .write = dev_irnet_write,
- .poll = dev_irnet_poll,
- .unlocked_ioctl = dev_irnet_ioctl,
- .open = dev_irnet_open,
- .release = dev_irnet_close,
- .llseek = noop_llseek,
- /* Also : llseek, readdir, mmap, flush, fsync, fasync, lock, readv, writev */
-};
-
-/* Structure so that the misc major (drivers/char/misc.c) take care of us... */
-static struct miscdevice irnet_misc_device =
-{
- .minor = IRNET_MINOR,
- .name = "irnet",
- .fops = &irnet_device_fops
-};
-
-#endif /* IRNET_PPP_H */
diff --git a/drivers/staging/irda/net/irnetlink.c b/drivers/staging/irda/net/irnetlink.c
deleted file mode 100644
index 7fc340e574cf..000000000000
--- a/drivers/staging/irda/net/irnetlink.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * IrDA netlink layer, for stack configuration.
- *
- * Copyright (c) 2007 Samuel Ortiz <samuel@sortiz.org>
- *
- * Partly based on the 802.11 nelink implementation
- * (see net/wireless/nl80211.c) which is:
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
- *
- * 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/socket.h>
-#include <linux/irda.h>
-#include <linux/gfp.h>
-#include <net/net_namespace.h>
-#include <net/sock.h>
-#include <net/irda/irda.h>
-#include <net/irda/irlap.h>
-#include <net/genetlink.h>
-
-
-
-static struct genl_family irda_nl_family;
-
-static struct net_device * ifname_to_netdev(struct net *net, struct genl_info *info)
-{
- char * ifname;
-
- if (!info->attrs[IRDA_NL_ATTR_IFNAME])
- return NULL;
-
- ifname = nla_data(info->attrs[IRDA_NL_ATTR_IFNAME]);
-
- pr_debug("%s(): Looking for %s\n", __func__, ifname);
-
- return dev_get_by_name(net, ifname);
-}
-
-static int irda_nl_set_mode(struct sk_buff *skb, struct genl_info *info)
-{
- struct net_device * dev;
- struct irlap_cb * irlap;
- u32 mode;
-
- if (!info->attrs[IRDA_NL_ATTR_MODE])
- return -EINVAL;
-
- mode = nla_get_u32(info->attrs[IRDA_NL_ATTR_MODE]);
-
- pr_debug("%s(): Switching to mode: %d\n", __func__, mode);
-
- dev = ifname_to_netdev(&init_net, info);
- if (!dev)
- return -ENODEV;
-
- irlap = (struct irlap_cb *)dev->atalk_ptr;
- if (!irlap) {
- dev_put(dev);
- return -ENODEV;
- }
-
- irlap->mode = mode;
-
- dev_put(dev);
-
- return 0;
-}
-
-static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info)
-{
- struct net_device * dev;
- struct irlap_cb * irlap;
- struct sk_buff *msg;
- void *hdr;
- int ret = -ENOBUFS;
-
- dev = ifname_to_netdev(&init_net, info);
- if (!dev)
- return -ENODEV;
-
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!msg) {
- dev_put(dev);
- return -ENOMEM;
- }
-
- irlap = (struct irlap_cb *)dev->atalk_ptr;
- if (!irlap) {
- ret = -ENODEV;
- goto err_out;
- }
-
- hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
- &irda_nl_family, 0, IRDA_NL_CMD_GET_MODE);
- if (hdr == NULL) {
- ret = -EMSGSIZE;
- goto err_out;
- }
-
- if(nla_put_string(msg, IRDA_NL_ATTR_IFNAME,
- dev->name))
- goto err_out;
-
- if(nla_put_u32(msg, IRDA_NL_ATTR_MODE, irlap->mode))
- goto err_out;
-
- genlmsg_end(msg, hdr);
-
- return genlmsg_reply(msg, info);
-
- err_out:
- nlmsg_free(msg);
- dev_put(dev);
-
- return ret;
-}
-
-static const struct nla_policy irda_nl_policy[IRDA_NL_ATTR_MAX + 1] = {
- [IRDA_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING,
- .len = IFNAMSIZ-1 },
- [IRDA_NL_ATTR_MODE] = { .type = NLA_U32 },
-};
-
-static const struct genl_ops irda_nl_ops[] = {
- {
- .cmd = IRDA_NL_CMD_SET_MODE,
- .doit = irda_nl_set_mode,
- .policy = irda_nl_policy,
- .flags = GENL_ADMIN_PERM,
- },
- {
- .cmd = IRDA_NL_CMD_GET_MODE,
- .doit = irda_nl_get_mode,
- .policy = irda_nl_policy,
- /* can be retrieved by unprivileged users */
- },
-
-};
-
-static struct genl_family irda_nl_family __ro_after_init = {
- .name = IRDA_NL_NAME,
- .hdrsize = 0,
- .version = IRDA_NL_VERSION,
- .maxattr = IRDA_NL_CMD_MAX,
- .module = THIS_MODULE,
- .ops = irda_nl_ops,
- .n_ops = ARRAY_SIZE(irda_nl_ops),
-};
-
-int __init irda_nl_register(void)
-{
- return genl_register_family(&irda_nl_family);
-}
-
-void irda_nl_unregister(void)
-{
- genl_unregister_family(&irda_nl_family);
-}
diff --git a/drivers/staging/irda/net/irproc.c b/drivers/staging/irda/net/irproc.c
deleted file mode 100644
index 77cfdde9d82f..000000000000
--- a/drivers/staging/irda/net/irproc.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*********************************************************************
- *
- * Filename: irproc.c
- * Version: 1.0
- * Description: Various entries in the /proc file system
- * Status: Experimental.
- * Author: Thomas Davis, <ratbert@radiks.net>
- * Created at: Sat Feb 21 21:33:24 1998
- * Modified at: Sun Nov 14 08:54:54 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-1999, Dag Brattli <dagb@cs.uit.no>
- * Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>,
- * 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.
- *
- * I, Thomas Davis, provide no warranty for any of this software.
- * This material is provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <net/net_namespace.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irlap.h>
-#include <net/irda/irlmp.h>
-
-extern const struct file_operations discovery_seq_fops;
-extern const struct file_operations irlap_seq_fops;
-extern const struct file_operations irlmp_seq_fops;
-extern const struct file_operations irttp_seq_fops;
-extern const struct file_operations irias_seq_fops;
-
-struct irda_entry {
- const char *name;
- const struct file_operations *fops;
-};
-
-struct proc_dir_entry *proc_irda;
-EXPORT_SYMBOL(proc_irda);
-
-static const struct irda_entry irda_dirs[] = {
- {"discovery", &discovery_seq_fops},
- {"irttp", &irttp_seq_fops},
- {"irlmp", &irlmp_seq_fops},
- {"irlap", &irlap_seq_fops},
- {"irias", &irias_seq_fops},
-};
-
-/*
- * Function irda_proc_register (void)
- *
- * Register irda entry in /proc file system
- *
- */
-void __init irda_proc_register(void)
-{
- int i;
-
- proc_irda = proc_mkdir("irda", init_net.proc_net);
- if (proc_irda == NULL)
- return;
-
- for (i = 0; i < ARRAY_SIZE(irda_dirs); i++)
- (void) proc_create(irda_dirs[i].name, 0, proc_irda,
- irda_dirs[i].fops);
-}
-
-/*
- * Function irda_proc_unregister (void)
- *
- * Unregister irda entry in /proc file system
- *
- */
-void irda_proc_unregister(void)
-{
- int i;
-
- if (proc_irda) {
- for (i=0; i<ARRAY_SIZE(irda_dirs); i++)
- remove_proc_entry(irda_dirs[i].name, proc_irda);
-
- remove_proc_entry("irda", init_net.proc_net);
- proc_irda = NULL;
- }
-}
-
-
diff --git a/drivers/staging/irda/net/irqueue.c b/drivers/staging/irda/net/irqueue.c
deleted file mode 100644
index 14291cbc4097..000000000000
--- a/drivers/staging/irda/net/irqueue.c
+++ /dev/null
@@ -1,912 +0,0 @@
-/*********************************************************************
- *
- * Filename: irqueue.c
- * Version: 0.3
- * Description: General queue implementation
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Tue Jun 9 13:29:31 1998
- * Modified at: Sun Dec 12 13:48:22 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- * Modified at: Thu Jan 4 14:29:10 CET 2001
- * Modified by: Marc Zyngier <mzyngier@freesurf.fr>
- *
- * Copyright (C) 1998-1999, Aage Kvalnes <aage@cs.uit.no>
- * Copyright (C) 1998, Dag Brattli,
- * All Rights Reserved.
- *
- * This code is taken from the Vortex Operating System written by Aage
- * Kvalnes. Aage has agreed that this code can use the GPL licence,
- * although he does not use that licence in his own code.
- *
- * This copyright does however _not_ include the ELF hash() function
- * which I currently don't know which licence or copyright it
- * has. Please inform me if you know.
- *
- * 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-/*
- * NOTE :
- * There are various problems with this package :
- * o the hash function for ints is pathetic (but could be changed)
- * o locking is sometime suspicious (especially during enumeration)
- * o most users have only a few elements (== overhead)
- * o most users never use search, so don't benefit from hashing
- * Problem already fixed :
- * o not 64 bit compliant (most users do hashv = (int) self)
- * o hashbin_remove() is broken => use hashbin_remove_this()
- * I think most users would be better served by a simple linked list
- * (like include/linux/list.h) with a global spinlock per list.
- * Jean II
- */
-
-/*
- * Notes on the concurrent access to hashbin and other SMP issues
- * -------------------------------------------------------------
- * Hashbins are very often in the IrDA stack a global repository of
- * information, and therefore used in a very asynchronous manner following
- * various events (driver calls, timers, user calls...).
- * Therefore, very often it is highly important to consider the
- * management of concurrent access to the hashbin and how to guarantee the
- * consistency of the operations on it.
- *
- * First, we need to define the objective of locking :
- * 1) Protect user data (content pointed by the hashbin)
- * 2) Protect hashbin structure itself (linked list in each bin)
- *
- * OLD LOCKING
- * -----------
- *
- * The previous locking strategy, either HB_LOCAL or HB_GLOBAL were
- * both inadequate in *both* aspect.
- * o HB_GLOBAL was using a spinlock for each bin (local locking).
- * o HB_LOCAL was disabling irq on *all* CPUs, so use a single
- * global semaphore.
- * The problems were :
- * A) Global irq disabling is no longer supported by the kernel
- * B) No protection for the hashbin struct global data
- * o hashbin_delete()
- * o hb_current
- * C) No protection for user data in some cases
- *
- * A) HB_LOCAL use global irq disabling, so doesn't work on kernel
- * 2.5.X. Even when it is supported (kernel 2.4.X and earlier), its
- * performance is not satisfactory on SMP setups. Most hashbins were
- * HB_LOCAL, so (A) definitely need fixing.
- * B) HB_LOCAL could be modified to fix (B). However, because HB_GLOBAL
- * lock only the individual bins, it will never be able to lock the
- * global data, so can't do (B).
- * C) Some functions return pointer to data that is still in the
- * hashbin :
- * o hashbin_find()
- * o hashbin_get_first()
- * o hashbin_get_next()
- * As the data is still in the hashbin, it may be changed or free'd
- * while the caller is examinimg the data. In those case, locking can't
- * be done within the hashbin, but must include use of the data within
- * the caller.
- * The caller can easily do this with HB_LOCAL (just disable irqs).
- * However, this is impossible with HB_GLOBAL because the caller has no
- * way to know the proper bin, so don't know which spinlock to use.
- *
- * Quick summary : can no longer use HB_LOCAL, and HB_GLOBAL is
- * fundamentally broken and will never work.
- *
- * NEW LOCKING
- * -----------
- *
- * To fix those problems, I've introduce a few changes in the
- * hashbin locking :
- * 1) New HB_LOCK scheme
- * 2) hashbin->hb_spinlock
- * 3) New hashbin usage policy
- *
- * HB_LOCK :
- * -------
- * HB_LOCK is a locking scheme intermediate between the old HB_LOCAL
- * and HB_GLOBAL. It uses a single spinlock to protect the whole content
- * of the hashbin. As it is a single spinlock, it can protect the global
- * data of the hashbin and not only the bins themselves.
- * HB_LOCK can only protect some of the hashbin calls, so it only lock
- * call that can be made 100% safe and leave other call unprotected.
- * HB_LOCK in theory is slower than HB_GLOBAL, but as the hashbin
- * content is always small contention is not high, so it doesn't matter
- * much. HB_LOCK is probably faster than HB_LOCAL.
- *
- * hashbin->hb_spinlock :
- * --------------------
- * The spinlock that HB_LOCK uses is available for caller, so that
- * the caller can protect unprotected calls (see below).
- * If the caller want to do entirely its own locking (HB_NOLOCK), he
- * can do so and may use safely this spinlock.
- * Locking is done like this :
- * spin_lock_irqsave(&hashbin->hb_spinlock, flags);
- * Releasing the lock :
- * spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
- *
- * Safe & Protected calls :
- * ----------------------
- * The following calls are safe or protected via HB_LOCK :
- * o hashbin_new() -> safe
- * o hashbin_delete()
- * o hashbin_insert()
- * o hashbin_remove_first()
- * o hashbin_remove()
- * o hashbin_remove_this()
- * o HASHBIN_GET_SIZE() -> atomic
- *
- * The following calls only protect the hashbin itself :
- * o hashbin_lock_find()
- * o hashbin_find_next()
- *
- * Unprotected calls :
- * -----------------
- * The following calls need to be protected by the caller :
- * o hashbin_find()
- * o hashbin_get_first()
- * o hashbin_get_next()
- *
- * Locking Policy :
- * --------------
- * If the hashbin is used only in a single thread of execution
- * (explicitly or implicitely), you can use HB_NOLOCK
- * If the calling module already provide concurrent access protection,
- * you may use HB_NOLOCK.
- *
- * In all other cases, you need to use HB_LOCK and lock the hashbin
- * every time before calling one of the unprotected calls. You also must
- * use the pointer returned by the unprotected call within the locked
- * region.
- *
- * Extra care for enumeration :
- * --------------------------
- * hashbin_get_first() and hashbin_get_next() use the hashbin to
- * store the current position, in hb_current.
- * As long as the hashbin remains locked, this is safe. If you unlock
- * the hashbin, the current position may change if anybody else modify
- * or enumerate the hashbin.
- * Summary : do the full enumeration while locked.
- *
- * Alternatively, you may use hashbin_find_next(). But, this will
- * be slower, is more complex to use and doesn't protect the hashbin
- * content. So, care is needed here as well.
- *
- * Other issues :
- * ------------
- * I believe that we are overdoing it by using spin_lock_irqsave()
- * and we should use only spin_lock_bh() or similar. But, I don't have
- * the balls to try it out.
- * Don't believe that because hashbin are now (somewhat) SMP safe
- * that the rest of the code is. Higher layers tend to be safest,
- * but LAP and LMP would need some serious dedicated love.
- *
- * Jean II
- */
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irqueue.h>
-
-/************************ QUEUE SUBROUTINES ************************/
-
-/*
- * Hashbin
- */
-#define GET_HASHBIN(x) ( x & HASHBIN_MASK )
-
-/*
- * Function hash (name)
- *
- * This function hash the input string 'name' using the ELF hash
- * function for strings.
- */
-static __u32 hash( const char* name)
-{
- __u32 h = 0;
- __u32 g;
-
- while(*name) {
- h = (h<<4) + *name++;
- g = h & 0xf0000000;
- if (g)
- h ^=g>>24;
- h &=~g;
- }
- return h;
-}
-
-/*
- * Function enqueue_first (queue, proc)
- *
- * Insert item first in queue.
- *
- */
-static void enqueue_first(irda_queue_t **queue, irda_queue_t* element)
-{
-
- /*
- * Check if queue is empty.
- */
- if ( *queue == NULL ) {
- /*
- * Queue is empty. Insert one element into the queue.
- */
- element->q_next = element->q_prev = *queue = element;
-
- } else {
- /*
- * Queue is not empty. Insert element into front of queue.
- */
- element->q_next = (*queue);
- (*queue)->q_prev->q_next = element;
- element->q_prev = (*queue)->q_prev;
- (*queue)->q_prev = element;
- (*queue) = element;
- }
-}
-
-
-/*
- * Function dequeue (queue)
- *
- * Remove first entry in queue
- *
- */
-static irda_queue_t *dequeue_first(irda_queue_t **queue)
-{
- irda_queue_t *ret;
-
- pr_debug("dequeue_first()\n");
-
- /*
- * Set return value
- */
- ret = *queue;
-
- if ( *queue == NULL ) {
- /*
- * Queue was empty.
- */
- } else if ( (*queue)->q_next == *queue ) {
- /*
- * Queue only contained a single element. It will now be
- * empty.
- */
- *queue = NULL;
- } else {
- /*
- * Queue contained several element. Remove the first one.
- */
- (*queue)->q_prev->q_next = (*queue)->q_next;
- (*queue)->q_next->q_prev = (*queue)->q_prev;
- *queue = (*queue)->q_next;
- }
-
- /*
- * Return the removed entry (or NULL of queue was empty).
- */
- return ret;
-}
-
-/*
- * Function dequeue_general (queue, element)
- *
- *
- */
-static irda_queue_t *dequeue_general(irda_queue_t **queue, irda_queue_t* element)
-{
- irda_queue_t *ret;
-
- pr_debug("dequeue_general()\n");
-
- /*
- * Set return value
- */
- ret = *queue;
-
- if ( *queue == NULL ) {
- /*
- * Queue was empty.
- */
- } else if ( (*queue)->q_next == *queue ) {
- /*
- * Queue only contained a single element. It will now be
- * empty.
- */
- *queue = NULL;
-
- } else {
- /*
- * Remove specific element.
- */
- element->q_prev->q_next = element->q_next;
- element->q_next->q_prev = element->q_prev;
- if ( (*queue) == element)
- (*queue) = element->q_next;
- }
-
- /*
- * Return the removed entry (or NULL of queue was empty).
- */
- return ret;
-}
-
-/************************ HASHBIN MANAGEMENT ************************/
-
-/*
- * Function hashbin_create ( type, name )
- *
- * Create hashbin!
- *
- */
-hashbin_t *hashbin_new(int type)
-{
- hashbin_t* hashbin;
-
- /*
- * Allocate new hashbin
- */
- hashbin = kzalloc(sizeof(*hashbin), GFP_ATOMIC);
- if (!hashbin)
- return NULL;
-
- /*
- * Initialize structure
- */
- hashbin->hb_type = type;
- hashbin->magic = HB_MAGIC;
- //hashbin->hb_current = NULL;
-
- /* Make sure all spinlock's are unlocked */
- if ( hashbin->hb_type & HB_LOCK ) {
- spin_lock_init(&hashbin->hb_spinlock);
- }
-
- return hashbin;
-}
-EXPORT_SYMBOL(hashbin_new);
-
-
-/*
- * Function hashbin_delete (hashbin, free_func)
- *
- * Destroy hashbin, the free_func can be a user supplied special routine
- * for deallocating this structure if it's complex. If not the user can
- * just supply kfree, which should take care of the job.
- */
-int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func)
-{
- irda_queue_t* queue;
- unsigned long flags = 0;
- int i;
-
- IRDA_ASSERT(hashbin != NULL, return -1;);
- IRDA_ASSERT(hashbin->magic == HB_MAGIC, return -1;);
-
- /* Synchronize */
- if (hashbin->hb_type & HB_LOCK)
- spin_lock_irqsave(&hashbin->hb_spinlock, flags);
-
- /*
- * Free the entries in the hashbin, TODO: use hashbin_clear when
- * it has been shown to work
- */
- for (i = 0; i < HASHBIN_SIZE; i ++ ) {
- while (1) {
- queue = dequeue_first((irda_queue_t**) &hashbin->hb_queue[i]);
-
- if (!queue)
- break;
-
- if (free_func) {
- if (hashbin->hb_type & HB_LOCK)
- spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
- free_func(queue);
- if (hashbin->hb_type & HB_LOCK)
- spin_lock_irqsave(&hashbin->hb_spinlock, flags);
- }
- }
- }
-
- /* Cleanup local data */
- hashbin->hb_current = NULL;
- hashbin->magic = ~HB_MAGIC;
-
- /* Release lock */
- if (hashbin->hb_type & HB_LOCK)
- spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
-
- /*
- * Free the hashbin structure
- */
- kfree(hashbin);
-
- return 0;
-}
-EXPORT_SYMBOL(hashbin_delete);
-
-/********************* HASHBIN LIST OPERATIONS *********************/
-
-/*
- * Function hashbin_insert (hashbin, entry, name)
- *
- * Insert an entry into the hashbin
- *
- */
-void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, long hashv,
- const char* name)
-{
- unsigned long flags = 0;
- int bin;
-
- IRDA_ASSERT( hashbin != NULL, return;);
- IRDA_ASSERT( hashbin->magic == HB_MAGIC, return;);
-
- /*
- * Locate hashbin
- */
- if ( name )
- hashv = hash( name );
- bin = GET_HASHBIN( hashv );
-
- /* Synchronize */
- if ( hashbin->hb_type & HB_LOCK ) {
- spin_lock_irqsave(&hashbin->hb_spinlock, flags);
- } /* Default is no-lock */
-
- /*
- * Store name and key
- */
- entry->q_hash = hashv;
- if ( name )
- strlcpy( entry->q_name, name, sizeof(entry->q_name));
-
- /*
- * Insert new entry first
- */
- enqueue_first( (irda_queue_t**) &hashbin->hb_queue[ bin ],
- entry);
- hashbin->hb_size++;
-
- /* Release lock */
- if ( hashbin->hb_type & HB_LOCK ) {
- spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
- } /* Default is no-lock */
-}
-EXPORT_SYMBOL(hashbin_insert);
-
-/*
- * Function hashbin_remove_first (hashbin)
- *
- * Remove first entry of the hashbin
- *
- * Note : this function no longer use hashbin_remove(), but does things
- * similar to hashbin_remove_this(), so can be considered safe.
- * Jean II
- */
-void *hashbin_remove_first( hashbin_t *hashbin)
-{
- unsigned long flags = 0;
- irda_queue_t *entry = NULL;
-
- /* Synchronize */
- if ( hashbin->hb_type & HB_LOCK ) {
- spin_lock_irqsave(&hashbin->hb_spinlock, flags);
- } /* Default is no-lock */
-
- entry = hashbin_get_first( hashbin);
- if ( entry != NULL) {
- int bin;
- long hashv;
- /*
- * Locate hashbin
- */
- hashv = entry->q_hash;
- bin = GET_HASHBIN( hashv );
-
- /*
- * Dequeue the entry...
- */
- dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ],
- entry);
- hashbin->hb_size--;
- entry->q_next = NULL;
- entry->q_prev = NULL;
-
- /*
- * Check if this item is the currently selected item, and in
- * that case we must reset hb_current
- */
- if ( entry == hashbin->hb_current)
- hashbin->hb_current = NULL;
- }
-
- /* Release lock */
- if ( hashbin->hb_type & HB_LOCK ) {
- spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
- } /* Default is no-lock */
-
- return entry;
-}
-
-
-/*
- * Function hashbin_remove (hashbin, hashv, name)
- *
- * Remove entry with the given name
- *
- * The use of this function is highly discouraged, because the whole
- * concept behind hashbin_remove() is broken. In many cases, it's not
- * possible to guarantee the unicity of the index (either hashv or name),
- * leading to removing the WRONG entry.
- * The only simple safe use is :
- * hashbin_remove(hasbin, (int) self, NULL);
- * In other case, you must think hard to guarantee unicity of the index.
- * Jean II
- */
-void* hashbin_remove( hashbin_t* hashbin, long hashv, const char* name)
-{
- int bin, found = FALSE;
- unsigned long flags = 0;
- irda_queue_t* entry;
-
- IRDA_ASSERT( hashbin != NULL, return NULL;);
- IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
-
- /*
- * Locate hashbin
- */
- if ( name )
- hashv = hash( name );
- bin = GET_HASHBIN( hashv );
-
- /* Synchronize */
- if ( hashbin->hb_type & HB_LOCK ) {
- spin_lock_irqsave(&hashbin->hb_spinlock, flags);
- } /* Default is no-lock */
-
- /*
- * Search for entry
- */
- entry = hashbin->hb_queue[ bin ];
- if ( entry ) {
- do {
- /*
- * Check for key
- */
- if ( entry->q_hash == hashv ) {
- /*
- * Name compare too?
- */
- if ( name ) {
- if ( strcmp( entry->q_name, name) == 0)
- {
- found = TRUE;
- break;
- }
- } else {
- found = TRUE;
- break;
- }
- }
- entry = entry->q_next;
- } while ( entry != hashbin->hb_queue[ bin ] );
- }
-
- /*
- * If entry was found, dequeue it
- */
- if ( found ) {
- dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ],
- entry);
- hashbin->hb_size--;
-
- /*
- * Check if this item is the currently selected item, and in
- * that case we must reset hb_current
- */
- if ( entry == hashbin->hb_current)
- hashbin->hb_current = NULL;
- }
-
- /* Release lock */
- if ( hashbin->hb_type & HB_LOCK ) {
- spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
- } /* Default is no-lock */
-
-
- /* Return */
- if ( found )
- return entry;
- else
- return NULL;
-
-}
-EXPORT_SYMBOL(hashbin_remove);
-
-/*
- * Function hashbin_remove_this (hashbin, entry)
- *
- * Remove entry with the given name
- *
- * In some cases, the user of hashbin can't guarantee the unicity
- * of either the hashv or name.
- * In those cases, using the above function is guaranteed to cause troubles,
- * so we use this one instead...
- * And by the way, it's also faster, because we skip the search phase ;-)
- */
-void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry)
-{
- unsigned long flags = 0;
- int bin;
- long hashv;
-
- IRDA_ASSERT( hashbin != NULL, return NULL;);
- IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
- IRDA_ASSERT( entry != NULL, return NULL;);
-
- /* Synchronize */
- if ( hashbin->hb_type & HB_LOCK ) {
- spin_lock_irqsave(&hashbin->hb_spinlock, flags);
- } /* Default is no-lock */
-
- /* Check if valid and not already removed... */
- if((entry->q_next == NULL) || (entry->q_prev == NULL)) {
- entry = NULL;
- goto out;
- }
-
- /*
- * Locate hashbin
- */
- hashv = entry->q_hash;
- bin = GET_HASHBIN( hashv );
-
- /*
- * Dequeue the entry...
- */
- dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ],
- entry);
- hashbin->hb_size--;
- entry->q_next = NULL;
- entry->q_prev = NULL;
-
- /*
- * Check if this item is the currently selected item, and in
- * that case we must reset hb_current
- */
- if ( entry == hashbin->hb_current)
- hashbin->hb_current = NULL;
-out:
- /* Release lock */
- if ( hashbin->hb_type & HB_LOCK ) {
- spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
- } /* Default is no-lock */
-
- return entry;
-}
-EXPORT_SYMBOL(hashbin_remove_this);
-
-/*********************** HASHBIN ENUMERATION ***********************/
-
-/*
- * Function hashbin_common_find (hashbin, hashv, name)
- *
- * Find item with the given hashv or name
- *
- */
-void* hashbin_find( hashbin_t* hashbin, long hashv, const char* name )
-{
- int bin;
- irda_queue_t* entry;
-
- pr_debug("hashbin_find()\n");
-
- IRDA_ASSERT( hashbin != NULL, return NULL;);
- IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
-
- /*
- * Locate hashbin
- */
- if ( name )
- hashv = hash( name );
- bin = GET_HASHBIN( hashv );
-
- /*
- * Search for entry
- */
- entry = hashbin->hb_queue[ bin];
- if ( entry ) {
- do {
- /*
- * Check for key
- */
- if ( entry->q_hash == hashv ) {
- /*
- * Name compare too?
- */
- if ( name ) {
- if ( strcmp( entry->q_name, name ) == 0 ) {
- return entry;
- }
- } else {
- return entry;
- }
- }
- entry = entry->q_next;
- } while ( entry != hashbin->hb_queue[ bin ] );
- }
-
- return NULL;
-}
-EXPORT_SYMBOL(hashbin_find);
-
-/*
- * Function hashbin_lock_find (hashbin, hashv, name)
- *
- * Find item with the given hashv or name
- *
- * Same, but with spinlock protection...
- * I call it safe, but it's only safe with respect to the hashbin, not its
- * content. - Jean II
- */
-void* hashbin_lock_find( hashbin_t* hashbin, long hashv, const char* name )
-{
- unsigned long flags = 0;
- irda_queue_t* entry;
-
- /* Synchronize */
- spin_lock_irqsave(&hashbin->hb_spinlock, flags);
-
- /*
- * Search for entry
- */
- entry = hashbin_find(hashbin, hashv, name);
-
- /* Release lock */
- spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
-
- return entry;
-}
-EXPORT_SYMBOL(hashbin_lock_find);
-
-/*
- * Function hashbin_find (hashbin, hashv, name, pnext)
- *
- * Find an item with the given hashv or name, and its successor
- *
- * This function allow to do concurrent enumerations without the
- * need to lock over the whole session, because the caller keep the
- * context of the search. On the other hand, it might fail and return
- * NULL if the entry is removed. - Jean II
- */
-void* hashbin_find_next( hashbin_t* hashbin, long hashv, const char* name,
- void ** pnext)
-{
- unsigned long flags = 0;
- irda_queue_t* entry;
-
- /* Synchronize */
- spin_lock_irqsave(&hashbin->hb_spinlock, flags);
-
- /*
- * Search for current entry
- * This allow to check if the current item is still in the
- * hashbin or has been removed.
- */
- entry = hashbin_find(hashbin, hashv, name);
-
- /*
- * Trick hashbin_get_next() to return what we want
- */
- if(entry) {
- hashbin->hb_current = entry;
- *pnext = hashbin_get_next( hashbin );
- } else
- *pnext = NULL;
-
- /* Release lock */
- spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
-
- return entry;
-}
-
-/*
- * Function hashbin_get_first (hashbin)
- *
- * Get a pointer to first element in hashbin, this function must be
- * called before any calls to hashbin_get_next()!
- *
- */
-irda_queue_t *hashbin_get_first( hashbin_t* hashbin)
-{
- irda_queue_t *entry;
- int i;
-
- IRDA_ASSERT( hashbin != NULL, return NULL;);
- IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
-
- if ( hashbin == NULL)
- return NULL;
-
- for ( i = 0; i < HASHBIN_SIZE; i ++ ) {
- entry = hashbin->hb_queue[ i];
- if ( entry) {
- hashbin->hb_current = entry;
- return entry;
- }
- }
- /*
- * Did not find any item in hashbin
- */
- return NULL;
-}
-EXPORT_SYMBOL(hashbin_get_first);
-
-/*
- * Function hashbin_get_next (hashbin)
- *
- * Get next item in hashbin. A series of hashbin_get_next() calls must
- * be started by a call to hashbin_get_first(). The function returns
- * NULL when all items have been traversed
- *
- * The context of the search is stored within the hashbin, so you must
- * protect yourself from concurrent enumerations. - Jean II
- */
-irda_queue_t *hashbin_get_next( hashbin_t *hashbin)
-{
- irda_queue_t* entry;
- int bin;
- int i;
-
- IRDA_ASSERT( hashbin != NULL, return NULL;);
- IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
-
- if ( hashbin->hb_current == NULL) {
- IRDA_ASSERT( hashbin->hb_current != NULL, return NULL;);
- return NULL;
- }
- entry = hashbin->hb_current->q_next;
- bin = GET_HASHBIN( entry->q_hash);
-
- /*
- * Make sure that we are not back at the beginning of the queue
- * again
- */
- if ( entry != hashbin->hb_queue[ bin ]) {
- hashbin->hb_current = entry;
-
- return entry;
- }
-
- /*
- * Check that this is not the last queue in hashbin
- */
- if ( bin >= HASHBIN_SIZE)
- return NULL;
-
- /*
- * Move to next queue in hashbin
- */
- bin++;
- for ( i = bin; i < HASHBIN_SIZE; i++ ) {
- entry = hashbin->hb_queue[ i];
- if ( entry) {
- hashbin->hb_current = entry;
-
- return entry;
- }
- }
- return NULL;
-}
-EXPORT_SYMBOL(hashbin_get_next);
diff --git a/drivers/staging/irda/net/irsysctl.c b/drivers/staging/irda/net/irsysctl.c
deleted file mode 100644
index 873da5e7d428..000000000000
--- a/drivers/staging/irda/net/irsysctl.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*********************************************************************
- *
- * Filename: irsysctl.c
- * Version: 1.0
- * Description: Sysctl interface for IrDA
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun May 24 22:12:06 1998
- * Modified at: Fri Jun 4 02:50:15 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
- * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/mm.h>
-#include <linux/ctype.h>
-#include <linux/sysctl.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h> /* irda_debug */
-#include <net/irda/irlmp.h>
-#include <net/irda/timer.h>
-#include <net/irda/irias_object.h>
-
-extern int sysctl_discovery;
-extern int sysctl_discovery_slots;
-extern int sysctl_discovery_timeout;
-extern int sysctl_slot_timeout;
-extern int sysctl_fast_poll_increase;
-extern char sysctl_devname[];
-extern int sysctl_max_baud_rate;
-extern unsigned int sysctl_min_tx_turn_time;
-extern unsigned int sysctl_max_tx_data_size;
-extern unsigned int sysctl_max_tx_window;
-extern int sysctl_max_noreply_time;
-extern int sysctl_warn_noreply_time;
-extern int sysctl_lap_keepalive_time;
-
-extern struct irlmp_cb *irlmp;
-
-/* this is needed for the proc_dointvec_minmax - Jean II */
-static int max_discovery_slots = 16; /* ??? */
-static int min_discovery_slots = 1;
-/* IrLAP 6.13.2 says 25ms to 10+70ms - allow higher since some devices
- * seems to require it. (from Dag's comment) */
-static int max_slot_timeout = 160;
-static int min_slot_timeout = 20;
-static int max_max_baud_rate = 16000000; /* See qos.c - IrLAP spec */
-static int min_max_baud_rate = 2400;
-static int max_min_tx_turn_time = 10000; /* See qos.c - IrLAP spec */
-static int min_min_tx_turn_time;
-static int max_max_tx_data_size = 2048; /* See qos.c - IrLAP spec */
-static int min_max_tx_data_size = 64;
-static int max_max_tx_window = 7; /* See qos.c - IrLAP spec */
-static int min_max_tx_window = 1;
-static int max_max_noreply_time = 40; /* See qos.c - IrLAP spec */
-static int min_max_noreply_time = 3;
-static int max_warn_noreply_time = 3; /* 3s == standard */
-static int min_warn_noreply_time = 1; /* 1s == min WD_TIMER */
-static int max_lap_keepalive_time = 10000; /* 10s */
-static int min_lap_keepalive_time = 100; /* 100us */
-/* For other sysctl, I've no idea of the range. Maybe Dag could help
- * us on that - Jean II */
-
-static int do_devname(struct ctl_table *table, int write,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- int ret;
-
- ret = proc_dostring(table, write, buffer, lenp, ppos);
- if (ret == 0 && write) {
- struct ias_value *val;
-
- val = irias_new_string_value(sysctl_devname);
- if (val)
- irias_object_change_attribute("Device", "DeviceName", val);
- }
- return ret;
-}
-
-
-static int do_discovery(struct ctl_table *table, int write,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- int ret;
-
- ret = proc_dointvec(table, write, buffer, lenp, ppos);
- if (ret)
- return ret;
-
- if (irlmp == NULL)
- return -ENODEV;
-
- if (sysctl_discovery)
- irlmp_start_discovery_timer(irlmp, sysctl_discovery_timeout*HZ);
- else
- del_timer_sync(&irlmp->discovery_timer);
-
- return ret;
-}
-
-/* One file */
-static struct ctl_table irda_table[] = {
- {
- .procname = "discovery",
- .data = &sysctl_discovery,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = do_discovery,
- },
- {
- .procname = "devname",
- .data = sysctl_devname,
- .maxlen = 65,
- .mode = 0644,
- .proc_handler = do_devname,
- },
-#ifdef CONFIG_IRDA_FAST_RR
- {
- .procname = "fast_poll_increase",
- .data = &sysctl_fast_poll_increase,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
-#endif
- {
- .procname = "discovery_slots",
- .data = &sysctl_discovery_slots,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_discovery_slots,
- .extra2 = &max_discovery_slots
- },
- {
- .procname = "discovery_timeout",
- .data = &sysctl_discovery_timeout,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
- {
- .procname = "slot_timeout",
- .data = &sysctl_slot_timeout,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_slot_timeout,
- .extra2 = &max_slot_timeout
- },
- {
- .procname = "max_baud_rate",
- .data = &sysctl_max_baud_rate,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_max_baud_rate,
- .extra2 = &max_max_baud_rate
- },
- {
- .procname = "min_tx_turn_time",
- .data = &sysctl_min_tx_turn_time,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_min_tx_turn_time,
- .extra2 = &max_min_tx_turn_time
- },
- {
- .procname = "max_tx_data_size",
- .data = &sysctl_max_tx_data_size,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_max_tx_data_size,
- .extra2 = &max_max_tx_data_size
- },
- {
- .procname = "max_tx_window",
- .data = &sysctl_max_tx_window,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_max_tx_window,
- .extra2 = &max_max_tx_window
- },
- {
- .procname = "max_noreply_time",
- .data = &sysctl_max_noreply_time,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_max_noreply_time,
- .extra2 = &max_max_noreply_time
- },
- {
- .procname = "warn_noreply_time",
- .data = &sysctl_warn_noreply_time,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_warn_noreply_time,
- .extra2 = &max_warn_noreply_time
- },
- {
- .procname = "lap_keepalive_time",
- .data = &sysctl_lap_keepalive_time,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &min_lap_keepalive_time,
- .extra2 = &max_lap_keepalive_time
- },
- { }
-};
-
-static struct ctl_table_header *irda_table_header;
-
-/*
- * Function irda_sysctl_register (void)
- *
- * Register our sysctl interface
- *
- */
-int __init irda_sysctl_register(void)
-{
- irda_table_header = register_net_sysctl(&init_net, "net/irda", irda_table);
- if (!irda_table_header)
- return -ENOMEM;
-
- return 0;
-}
-
-/*
- * Function irda_sysctl_unregister (void)
- *
- * Unregister our sysctl interface
- *
- */
-void irda_sysctl_unregister(void)
-{
- unregister_net_sysctl_table(irda_table_header);
-}
-
-
-
diff --git a/drivers/staging/irda/net/irttp.c b/drivers/staging/irda/net/irttp.c
deleted file mode 100644
index 741a94f39b4e..000000000000
--- a/drivers/staging/irda/net/irttp.c
+++ /dev/null
@@ -1,1886 +0,0 @@
-/*********************************************************************
- *
- * Filename: irttp.c
- * Version: 1.2
- * Description: Tiny Transport Protocol (TTP) implementation
- * Status: Stable
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sun Aug 31 20:14:31 1997
- * Modified at: Wed Jan 5 11:31:27 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-
-#include <asm/byteorder.h>
-#include <asm/unaligned.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irlap.h>
-#include <net/irda/irlmp.h>
-#include <net/irda/parameters.h>
-#include <net/irda/irttp.h>
-
-static struct irttp_cb *irttp;
-
-static void __irttp_close_tsap(struct tsap_cb *self);
-
-static int irttp_data_indication(void *instance, void *sap,
- struct sk_buff *skb);
-static int irttp_udata_indication(void *instance, void *sap,
- struct sk_buff *skb);
-static void irttp_disconnect_indication(void *instance, void *sap,
- LM_REASON reason, struct sk_buff *);
-static void irttp_connect_indication(void *instance, void *sap,
- struct qos_info *qos, __u32 max_sdu_size,
- __u8 header_size, struct sk_buff *skb);
-static void irttp_connect_confirm(void *instance, void *sap,
- struct qos_info *qos, __u32 max_sdu_size,
- __u8 header_size, struct sk_buff *skb);
-static void irttp_run_tx_queue(struct tsap_cb *self);
-static void irttp_run_rx_queue(struct tsap_cb *self);
-
-static void irttp_flush_queues(struct tsap_cb *self);
-static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb);
-static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);
-static int irttp_param_max_sdu_size(void *instance, irda_param_t *param,
- int get);
-
-static void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow);
-static void irttp_status_indication(void *instance,
- LINK_STATUS link, LOCK_STATUS lock);
-
-/* Information for parsing parameters in IrTTP */
-static const pi_minor_info_t pi_minor_call_table[] = {
- { NULL, 0 }, /* 0x00 */
- { irttp_param_max_sdu_size, PV_INTEGER | PV_BIG_ENDIAN } /* 0x01 */
-};
-static const pi_major_info_t pi_major_call_table[] = {
- { pi_minor_call_table, 2 }
-};
-static pi_param_info_t param_info = { pi_major_call_table, 1, 0x0f, 4 };
-
-/************************ GLOBAL PROCEDURES ************************/
-
-/*
- * Function irttp_init (void)
- *
- * Initialize the IrTTP layer. Called by module initialization code
- *
- */
-int __init irttp_init(void)
-{
- irttp = kzalloc(sizeof(struct irttp_cb), GFP_KERNEL);
- if (irttp == NULL)
- return -ENOMEM;
-
- irttp->magic = TTP_MAGIC;
-
- irttp->tsaps = hashbin_new(HB_LOCK);
- if (!irttp->tsaps) {
- net_err_ratelimited("%s: can't allocate IrTTP hashbin!\n",
- __func__);
- kfree(irttp);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-/*
- * Function irttp_cleanup (void)
- *
- * Called by module destruction/cleanup code
- *
- */
-void irttp_cleanup(void)
-{
- /* Check for main structure */
- IRDA_ASSERT(irttp->magic == TTP_MAGIC, return;);
-
- /*
- * Delete hashbin and close all TSAP instances in it
- */
- hashbin_delete(irttp->tsaps, (FREE_FUNC) __irttp_close_tsap);
-
- irttp->magic = 0;
-
- /* De-allocate main structure */
- kfree(irttp);
-
- irttp = NULL;
-}
-
-/*************************** SUBROUTINES ***************************/
-
-/*
- * Function irttp_start_todo_timer (self, timeout)
- *
- * Start todo timer.
- *
- * Made it more effient and unsensitive to race conditions - Jean II
- */
-static inline void irttp_start_todo_timer(struct tsap_cb *self, int timeout)
-{
- /* Set new value for timer */
- mod_timer(&self->todo_timer, jiffies + timeout);
-}
-
-/*
- * Function irttp_todo_expired (data)
- *
- * Todo timer has expired!
- *
- * One of the restriction of the timer is that it is run only on the timer
- * interrupt which run every 10ms. This mean that even if you set the timer
- * with a delay of 0, it may take up to 10ms before it's run.
- * So, to minimise latency and keep cache fresh, we try to avoid using
- * it as much as possible.
- * Note : we can't use tasklets, because they can't be asynchronously
- * killed (need user context), and we can't guarantee that here...
- * Jean II
- */
-static void irttp_todo_expired(struct timer_list *t)
-{
- struct tsap_cb *self = from_timer(self, t, todo_timer);
-
- /* Check that we still exist */
- if (!self || self->magic != TTP_TSAP_MAGIC)
- return;
-
- pr_debug("%s(instance=%p)\n", __func__, self);
-
- /* Try to make some progress, especially on Tx side - Jean II */
- irttp_run_rx_queue(self);
- irttp_run_tx_queue(self);
-
- /* Check if time for disconnect */
- if (test_bit(0, &self->disconnect_pend)) {
- /* Check if it's possible to disconnect yet */
- if (skb_queue_empty(&self->tx_queue)) {
- /* Make sure disconnect is not pending anymore */
- clear_bit(0, &self->disconnect_pend); /* FALSE */
-
- /* Note : self->disconnect_skb may be NULL */
- irttp_disconnect_request(self, self->disconnect_skb,
- P_NORMAL);
- self->disconnect_skb = NULL;
- } else {
- /* Try again later */
- irttp_start_todo_timer(self, HZ/10);
-
- /* No reason to try and close now */
- return;
- }
- }
-
- /* Check if it's closing time */
- if (self->close_pend)
- /* Finish cleanup */
- irttp_close_tsap(self);
-}
-
-/*
- * Function irttp_flush_queues (self)
- *
- * Flushes (removes all frames) in transitt-buffer (tx_list)
- */
-static void irttp_flush_queues(struct tsap_cb *self)
-{
- struct sk_buff *skb;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-
- /* Deallocate frames waiting to be sent */
- while ((skb = skb_dequeue(&self->tx_queue)) != NULL)
- dev_kfree_skb(skb);
-
- /* Deallocate received frames */
- while ((skb = skb_dequeue(&self->rx_queue)) != NULL)
- dev_kfree_skb(skb);
-
- /* Deallocate received fragments */
- while ((skb = skb_dequeue(&self->rx_fragments)) != NULL)
- dev_kfree_skb(skb);
-}
-
-/*
- * Function irttp_reassemble (self)
- *
- * Makes a new (continuous) skb of all the fragments in the fragment
- * queue
- *
- */
-static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
-{
- struct sk_buff *skb, *frag;
- int n = 0; /* Fragment index */
-
- IRDA_ASSERT(self != NULL, return NULL;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
-
- pr_debug("%s(), self->rx_sdu_size=%d\n", __func__,
- self->rx_sdu_size);
-
- skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
- if (!skb)
- return NULL;
-
- /*
- * Need to reserve space for TTP header in case this skb needs to
- * be requeued in case delivery failes
- */
- skb_reserve(skb, TTP_HEADER);
- skb_put(skb, self->rx_sdu_size);
-
- /*
- * Copy all fragments to a new buffer
- */
- while ((frag = skb_dequeue(&self->rx_fragments)) != NULL) {
- skb_copy_to_linear_data_offset(skb, n, frag->data, frag->len);
- n += frag->len;
-
- dev_kfree_skb(frag);
- }
-
- pr_debug("%s(), frame len=%d, rx_sdu_size=%d, rx_max_sdu_size=%d\n",
- __func__, n, self->rx_sdu_size, self->rx_max_sdu_size);
- /* Note : irttp_run_rx_queue() calculate self->rx_sdu_size
- * by summing the size of all fragments, so we should always
- * have n == self->rx_sdu_size, except in cases where we
- * droped the last fragment (when self->rx_sdu_size exceed
- * self->rx_max_sdu_size), where n < self->rx_sdu_size.
- * Jean II */
- IRDA_ASSERT(n <= self->rx_sdu_size, n = self->rx_sdu_size;);
-
- /* Set the new length */
- skb_trim(skb, n);
-
- self->rx_sdu_size = 0;
-
- return skb;
-}
-
-/*
- * Function irttp_fragment_skb (skb)
- *
- * Fragments a frame and queues all the fragments for transmission
- *
- */
-static inline void irttp_fragment_skb(struct tsap_cb *self,
- struct sk_buff *skb)
-{
- struct sk_buff *frag;
- __u8 *frame;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
-
- /*
- * Split frame into a number of segments
- */
- while (skb->len > self->max_seg_size) {
- pr_debug("%s(), fragmenting ...\n", __func__);
-
- /* Make new segment */
- frag = alloc_skb(self->max_seg_size+self->max_header_size,
- GFP_ATOMIC);
- if (!frag)
- return;
-
- skb_reserve(frag, self->max_header_size);
-
- /* Copy data from the original skb into this fragment. */
- skb_copy_from_linear_data(skb, skb_put(frag, self->max_seg_size),
- self->max_seg_size);
-
- /* Insert TTP header, with the more bit set */
- frame = skb_push(frag, TTP_HEADER);
- frame[0] = TTP_MORE;
-
- /* Hide the copied data from the original skb */
- skb_pull(skb, self->max_seg_size);
-
- /* Queue fragment */
- skb_queue_tail(&self->tx_queue, frag);
- }
- /* Queue what is left of the original skb */
- pr_debug("%s(), queuing last segment\n", __func__);
-
- frame = skb_push(skb, TTP_HEADER);
- frame[0] = 0x00; /* Clear more bit */
-
- /* Queue fragment */
- skb_queue_tail(&self->tx_queue, skb);
-}
-
-/*
- * Function irttp_param_max_sdu_size (self, param)
- *
- * Handle the MaxSduSize parameter in the connect frames, this function
- * will be called both when this parameter needs to be inserted into, and
- * extracted from the connect frames
- */
-static int irttp_param_max_sdu_size(void *instance, irda_param_t *param,
- int get)
-{
- struct tsap_cb *self;
-
- self = instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-
- if (get)
- param->pv.i = self->tx_max_sdu_size;
- else
- self->tx_max_sdu_size = param->pv.i;
-
- pr_debug("%s(), MaxSduSize=%d\n", __func__, param->pv.i);
-
- return 0;
-}
-
-/*************************** CLIENT CALLS ***************************/
-/************************** LMP CALLBACKS **************************/
-/* Everything is happily mixed up. Waiting for next clean up - Jean II */
-
-/*
- * Initialization, that has to be done on new tsap
- * instance allocation and on duplication
- */
-static void irttp_init_tsap(struct tsap_cb *tsap)
-{
- spin_lock_init(&tsap->lock);
- timer_setup(&tsap->todo_timer, irttp_todo_expired, 0);
-
- skb_queue_head_init(&tsap->rx_queue);
- skb_queue_head_init(&tsap->tx_queue);
- skb_queue_head_init(&tsap->rx_fragments);
-}
-
-/*
- * Function irttp_open_tsap (stsap, notify)
- *
- * Create TSAP connection endpoint,
- */
-struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify)
-{
- struct tsap_cb *self;
- struct lsap_cb *lsap;
- notify_t ttp_notify;
-
- IRDA_ASSERT(irttp->magic == TTP_MAGIC, return NULL;);
-
- /* The IrLMP spec (IrLMP 1.1 p10) says that we have the right to
- * use only 0x01-0x6F. Of course, we can use LSAP_ANY as well.
- * JeanII */
- if ((stsap_sel != LSAP_ANY) &&
- ((stsap_sel < 0x01) || (stsap_sel >= 0x70))) {
- pr_debug("%s(), invalid tsap!\n", __func__);
- return NULL;
- }
-
- self = kzalloc(sizeof(struct tsap_cb), GFP_ATOMIC);
- if (self == NULL)
- return NULL;
-
- /* Initialize internal objects */
- irttp_init_tsap(self);
-
- /* Initialize callbacks for IrLMP to use */
- irda_notify_init(&ttp_notify);
- ttp_notify.connect_confirm = irttp_connect_confirm;
- ttp_notify.connect_indication = irttp_connect_indication;
- ttp_notify.disconnect_indication = irttp_disconnect_indication;
- ttp_notify.data_indication = irttp_data_indication;
- ttp_notify.udata_indication = irttp_udata_indication;
- ttp_notify.flow_indication = irttp_flow_indication;
- if (notify->status_indication != NULL)
- ttp_notify.status_indication = irttp_status_indication;
- ttp_notify.instance = self;
- strncpy(ttp_notify.name, notify->name, NOTIFY_MAX_NAME);
-
- self->magic = TTP_TSAP_MAGIC;
- self->connected = FALSE;
-
- /*
- * Create LSAP at IrLMP layer
- */
- lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0);
- if (lsap == NULL) {
- pr_debug("%s: unable to allocate LSAP!!\n", __func__);
- __irttp_close_tsap(self);
- return NULL;
- }
-
- /*
- * If user specified LSAP_ANY as source TSAP selector, then IrLMP
- * will replace it with whatever source selector which is free, so
- * the stsap_sel we have might not be valid anymore
- */
- self->stsap_sel = lsap->slsap_sel;
- pr_debug("%s(), stsap_sel=%02x\n", __func__, self->stsap_sel);
-
- self->notify = *notify;
- self->lsap = lsap;
-
- hashbin_insert(irttp->tsaps, (irda_queue_t *) self, (long) self, NULL);
-
- if (credit > TTP_RX_MAX_CREDIT)
- self->initial_credit = TTP_RX_MAX_CREDIT;
- else
- self->initial_credit = credit;
-
- return self;
-}
-EXPORT_SYMBOL(irttp_open_tsap);
-
-/*
- * Function irttp_close (handle)
- *
- * Remove an instance of a TSAP. This function should only deal with the
- * deallocation of the TSAP, and resetting of the TSAPs values;
- *
- */
-static void __irttp_close_tsap(struct tsap_cb *self)
-{
- /* First make sure we're connected. */
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-
- irttp_flush_queues(self);
-
- del_timer(&self->todo_timer);
-
- /* This one won't be cleaned up if we are disconnect_pend + close_pend
- * and we receive a disconnect_indication */
- if (self->disconnect_skb)
- dev_kfree_skb(self->disconnect_skb);
-
- self->connected = FALSE;
- self->magic = ~TTP_TSAP_MAGIC;
-
- kfree(self);
-}
-
-/*
- * Function irttp_close (self)
- *
- * Remove TSAP from list of all TSAPs and then deallocate all resources
- * associated with this TSAP
- *
- * Note : because we *free* the tsap structure, it is the responsibility
- * of the caller to make sure we are called only once and to deal with
- * possible race conditions. - Jean II
- */
-int irttp_close_tsap(struct tsap_cb *self)
-{
- struct tsap_cb *tsap;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-
- /* Make sure tsap has been disconnected */
- if (self->connected) {
- /* Check if disconnect is not pending */
- if (!test_bit(0, &self->disconnect_pend)) {
- net_warn_ratelimited("%s: TSAP still connected!\n",
- __func__);
- irttp_disconnect_request(self, NULL, P_NORMAL);
- }
- self->close_pend = TRUE;
- irttp_start_todo_timer(self, HZ/10);
-
- return 0; /* Will be back! */
- }
-
- tsap = hashbin_remove(irttp->tsaps, (long) self, NULL);
-
- IRDA_ASSERT(tsap == self, return -1;);
-
- /* Close corresponding LSAP */
- if (self->lsap) {
- irlmp_close_lsap(self->lsap);
- self->lsap = NULL;
- }
-
- __irttp_close_tsap(self);
-
- return 0;
-}
-EXPORT_SYMBOL(irttp_close_tsap);
-
-/*
- * Function irttp_udata_request (self, skb)
- *
- * Send unreliable data on this TSAP
- *
- */
-int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb)
-{
- int ret;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
- IRDA_ASSERT(skb != NULL, return -1;);
-
- /* Take shortcut on zero byte packets */
- if (skb->len == 0) {
- ret = 0;
- goto err;
- }
-
- /* Check that nothing bad happens */
- if (!self->connected) {
- net_warn_ratelimited("%s(), Not connected\n", __func__);
- ret = -ENOTCONN;
- goto err;
- }
-
- if (skb->len > self->max_seg_size) {
- net_err_ratelimited("%s(), UData is too large for IrLAP!\n",
- __func__);
- ret = -EMSGSIZE;
- goto err;
- }
-
- irlmp_udata_request(self->lsap, skb);
- self->stats.tx_packets++;
-
- return 0;
-
-err:
- dev_kfree_skb(skb);
- return ret;
-}
-EXPORT_SYMBOL(irttp_udata_request);
-
-
-/*
- * Function irttp_data_request (handle, skb)
- *
- * Queue frame for transmission. If SAR is enabled, fragement the frame
- * and queue the fragments for transmission
- */
-int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
-{
- __u8 *frame;
- int ret;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
- IRDA_ASSERT(skb != NULL, return -1;);
-
- pr_debug("%s() : queue len = %d\n", __func__,
- skb_queue_len(&self->tx_queue));
-
- /* Take shortcut on zero byte packets */
- if (skb->len == 0) {
- ret = 0;
- goto err;
- }
-
- /* Check that nothing bad happens */
- if (!self->connected) {
- net_warn_ratelimited("%s: Not connected\n", __func__);
- ret = -ENOTCONN;
- goto err;
- }
-
- /*
- * Check if SAR is disabled, and the frame is larger than what fits
- * inside an IrLAP frame
- */
- if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) {
- net_err_ratelimited("%s: SAR disabled, and data is too large for IrLAP!\n",
- __func__);
- ret = -EMSGSIZE;
- goto err;
- }
-
- /*
- * Check if SAR is enabled, and the frame is larger than the
- * TxMaxSduSize
- */
- if ((self->tx_max_sdu_size != 0) &&
- (self->tx_max_sdu_size != TTP_SAR_UNBOUND) &&
- (skb->len > self->tx_max_sdu_size)) {
- net_err_ratelimited("%s: SAR enabled, but data is larger than TxMaxSduSize!\n",
- __func__);
- ret = -EMSGSIZE;
- goto err;
- }
- /*
- * Check if transmit queue is full
- */
- if (skb_queue_len(&self->tx_queue) >= TTP_TX_MAX_QUEUE) {
- /*
- * Give it a chance to empty itself
- */
- irttp_run_tx_queue(self);
-
- /* Drop packet. This error code should trigger the caller
- * to resend the data in the client code - Jean II */
- ret = -ENOBUFS;
- goto err;
- }
-
- /* Queue frame, or queue frame segments */
- if ((self->tx_max_sdu_size == 0) || (skb->len < self->max_seg_size)) {
- /* Queue frame */
- IRDA_ASSERT(skb_headroom(skb) >= TTP_HEADER, return -1;);
- frame = skb_push(skb, TTP_HEADER);
- frame[0] = 0x00; /* Clear more bit */
-
- skb_queue_tail(&self->tx_queue, skb);
- } else {
- /*
- * Fragment the frame, this function will also queue the
- * fragments, we don't care about the fact the transmit
- * queue may be overfilled by all the segments for a little
- * while
- */
- irttp_fragment_skb(self, skb);
- }
-
- /* Check if we can accept more data from client */
- if ((!self->tx_sdu_busy) &&
- (skb_queue_len(&self->tx_queue) > TTP_TX_HIGH_THRESHOLD)) {
- /* Tx queue filling up, so stop client. */
- if (self->notify.flow_indication) {
- self->notify.flow_indication(self->notify.instance,
- self, FLOW_STOP);
- }
- /* self->tx_sdu_busy is the state of the client.
- * Update state after notifying client to avoid
- * race condition with irttp_flow_indication().
- * If the queue empty itself after our test but before
- * we set the flag, we will fix ourselves below in
- * irttp_run_tx_queue().
- * Jean II */
- self->tx_sdu_busy = TRUE;
- }
-
- /* Try to make some progress */
- irttp_run_tx_queue(self);
-
- return 0;
-
-err:
- dev_kfree_skb(skb);
- return ret;
-}
-EXPORT_SYMBOL(irttp_data_request);
-
-/*
- * Function irttp_run_tx_queue (self)
- *
- * Transmit packets queued for transmission (if possible)
- *
- */
-static void irttp_run_tx_queue(struct tsap_cb *self)
-{
- struct sk_buff *skb;
- unsigned long flags;
- int n;
-
- pr_debug("%s() : send_credit = %d, queue_len = %d\n",
- __func__,
- self->send_credit, skb_queue_len(&self->tx_queue));
-
- /* Get exclusive access to the tx queue, otherwise don't touch it */
- if (irda_lock(&self->tx_queue_lock) == FALSE)
- return;
-
- /* Try to send out frames as long as we have credits
- * and as long as LAP is not full. If LAP is full, it will
- * poll us through irttp_flow_indication() - Jean II */
- while ((self->send_credit > 0) &&
- (!irlmp_lap_tx_queue_full(self->lsap)) &&
- (skb = skb_dequeue(&self->tx_queue))) {
- /*
- * Since we can transmit and receive frames concurrently,
- * the code below is a critical region and we must assure that
- * nobody messes with the credits while we update them.
- */
- spin_lock_irqsave(&self->lock, flags);
-
- n = self->avail_credit;
- self->avail_credit = 0;
-
- /* Only room for 127 credits in frame */
- if (n > 127) {
- self->avail_credit = n-127;
- n = 127;
- }
- self->remote_credit += n;
- self->send_credit--;
-
- spin_unlock_irqrestore(&self->lock, flags);
-
- /*
- * More bit must be set by the data_request() or fragment()
- * functions
- */
- skb->data[0] |= (n & 0x7f);
-
- /* Detach from socket.
- * The current skb has a reference to the socket that sent
- * it (skb->sk). When we pass it to IrLMP, the skb will be
- * stored in in IrLAP (self->wx_list). When we are within
- * IrLAP, we lose the notion of socket, so we should not
- * have a reference to a socket. So, we drop it here.
- *
- * Why does it matter ?
- * When the skb is freed (kfree_skb), if it is associated
- * with a socket, it release buffer space on the socket
- * (through sock_wfree() and sock_def_write_space()).
- * If the socket no longer exist, we may crash. Hard.
- * When we close a socket, we make sure that associated packets
- * in IrTTP are freed. However, we have no way to cancel
- * the packet that we have passed to IrLAP. So, if a packet
- * remains in IrLAP (retry on the link or else) after we
- * close the socket, we are dead !
- * Jean II */
- if (skb->sk != NULL) {
- /* IrSOCK application, IrOBEX, ... */
- skb_orphan(skb);
- }
- /* IrCOMM over IrTTP, IrLAN, ... */
-
- /* Pass the skb to IrLMP - done */
- irlmp_data_request(self->lsap, skb);
- self->stats.tx_packets++;
- }
-
- /* Check if we can accept more frames from client.
- * We don't want to wait until the todo timer to do that, and we
- * can't use tasklets (grr...), so we are obliged to give control
- * to client. That's ok, this test will be true not too often
- * (max once per LAP window) and we are called from places
- * where we can spend a bit of time doing stuff. - Jean II */
- if ((self->tx_sdu_busy) &&
- (skb_queue_len(&self->tx_queue) < TTP_TX_LOW_THRESHOLD) &&
- (!self->close_pend)) {
- if (self->notify.flow_indication)
- self->notify.flow_indication(self->notify.instance,
- self, FLOW_START);
-
- /* self->tx_sdu_busy is the state of the client.
- * We don't really have a race here, but it's always safer
- * to update our state after the client - Jean II */
- self->tx_sdu_busy = FALSE;
- }
-
- /* Reset lock */
- self->tx_queue_lock = 0;
-}
-
-/*
- * Function irttp_give_credit (self)
- *
- * Send a dataless flowdata TTP-PDU and give available credit to peer
- * TSAP
- */
-static inline void irttp_give_credit(struct tsap_cb *self)
-{
- struct sk_buff *tx_skb = NULL;
- unsigned long flags;
- int n;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-
- pr_debug("%s() send=%d,avail=%d,remote=%d\n",
- __func__,
- self->send_credit, self->avail_credit, self->remote_credit);
-
- /* Give credit to peer */
- tx_skb = alloc_skb(TTP_MAX_HEADER, GFP_ATOMIC);
- if (!tx_skb)
- return;
-
- /* Reserve space for LMP, and LAP header */
- skb_reserve(tx_skb, LMP_MAX_HEADER);
-
- /*
- * Since we can transmit and receive frames concurrently,
- * the code below is a critical region and we must assure that
- * nobody messes with the credits while we update them.
- */
- spin_lock_irqsave(&self->lock, flags);
-
- n = self->avail_credit;
- self->avail_credit = 0;
-
- /* Only space for 127 credits in frame */
- if (n > 127) {
- self->avail_credit = n - 127;
- n = 127;
- }
- self->remote_credit += n;
-
- spin_unlock_irqrestore(&self->lock, flags);
-
- skb_put(tx_skb, 1);
- tx_skb->data[0] = (__u8) (n & 0x7f);
-
- irlmp_data_request(self->lsap, tx_skb);
- self->stats.tx_packets++;
-}
-
-/*
- * Function irttp_udata_indication (instance, sap, skb)
- *
- * Received some unit-data (unreliable)
- *
- */
-static int irttp_udata_indication(void *instance, void *sap,
- struct sk_buff *skb)
-{
- struct tsap_cb *self;
- int err;
-
- self = instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
- IRDA_ASSERT(skb != NULL, return -1;);
-
- self->stats.rx_packets++;
-
- /* Just pass data to layer above */
- if (self->notify.udata_indication) {
- err = self->notify.udata_indication(self->notify.instance,
- self, skb);
- /* Same comment as in irttp_do_data_indication() */
- if (!err)
- return 0;
- }
- /* Either no handler, or handler returns an error */
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/*
- * Function irttp_data_indication (instance, sap, skb)
- *
- * Receive segment from IrLMP.
- *
- */
-static int irttp_data_indication(void *instance, void *sap,
- struct sk_buff *skb)
-{
- struct tsap_cb *self;
- unsigned long flags;
- int n;
-
- self = instance;
-
- n = skb->data[0] & 0x7f; /* Extract the credits */
-
- self->stats.rx_packets++;
-
- /* Deal with inbound credit
- * Since we can transmit and receive frames concurrently,
- * the code below is a critical region and we must assure that
- * nobody messes with the credits while we update them.
- */
- spin_lock_irqsave(&self->lock, flags);
- self->send_credit += n;
- if (skb->len > 1)
- self->remote_credit--;
- spin_unlock_irqrestore(&self->lock, flags);
-
- /*
- * Data or dataless packet? Dataless frames contains only the
- * TTP_HEADER.
- */
- if (skb->len > 1) {
- /*
- * We don't remove the TTP header, since we must preserve the
- * more bit, so the defragment routing knows what to do
- */
- skb_queue_tail(&self->rx_queue, skb);
- } else {
- /* Dataless flowdata TTP-PDU */
- dev_kfree_skb(skb);
- }
-
-
- /* Push data to the higher layer.
- * We do it synchronously because running the todo timer for each
- * receive packet would be too much overhead and latency.
- * By passing control to the higher layer, we run the risk that
- * it may take time or grab a lock. Most often, the higher layer
- * will only put packet in a queue.
- * Anyway, packets are only dripping through the IrDA, so we can
- * have time before the next packet.
- * Further, we are run from NET_BH, so the worse that can happen is
- * us missing the optimal time to send back the PF bit in LAP.
- * Jean II */
- irttp_run_rx_queue(self);
-
- /* We now give credits to peer in irttp_run_rx_queue().
- * We need to send credit *NOW*, otherwise we are going
- * to miss the next Tx window. The todo timer may take
- * a while before it's run... - Jean II */
-
- /*
- * If the peer device has given us some credits and we didn't have
- * anyone from before, then we need to shedule the tx queue.
- * We need to do that because our Tx have stopped (so we may not
- * get any LAP flow indication) and the user may be stopped as
- * well. - Jean II
- */
- if (self->send_credit == n) {
- /* Restart pushing stuff to LAP */
- irttp_run_tx_queue(self);
- /* Note : we don't want to schedule the todo timer
- * because it has horrible latency. No tasklets
- * because the tasklet API is broken. - Jean II */
- }
-
- return 0;
-}
-
-/*
- * Function irttp_status_indication (self, reason)
- *
- * Status_indication, just pass to the higher layer...
- *
- */
-static void irttp_status_indication(void *instance,
- LINK_STATUS link, LOCK_STATUS lock)
-{
- struct tsap_cb *self;
-
- self = instance;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-
- /* Check if client has already closed the TSAP and gone away */
- if (self->close_pend)
- return;
-
- /*
- * Inform service user if he has requested it
- */
- if (self->notify.status_indication != NULL)
- self->notify.status_indication(self->notify.instance,
- link, lock);
- else
- pr_debug("%s(), no handler\n", __func__);
-}
-
-/*
- * Function irttp_flow_indication (self, reason)
- *
- * Flow_indication : IrLAP tells us to send more data.
- *
- */
-static void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
-{
- struct tsap_cb *self;
-
- self = instance;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-
- pr_debug("%s(instance=%p)\n", __func__, self);
-
- /* We are "polled" directly from LAP, and the LAP want to fill
- * its Tx window. We want to do our best to send it data, so that
- * we maximise the window. On the other hand, we want to limit the
- * amount of work here so that LAP doesn't hang forever waiting
- * for packets. - Jean II */
-
- /* Try to send some packets. Currently, LAP calls us every time
- * there is one free slot, so we will send only one packet.
- * This allow the scheduler to do its round robin - Jean II */
- irttp_run_tx_queue(self);
-
- /* Note regarding the interraction with higher layer.
- * irttp_run_tx_queue() may call the client when its queue
- * start to empty, via notify.flow_indication(). Initially.
- * I wanted this to happen in a tasklet, to avoid client
- * grabbing the CPU, but we can't use tasklets safely. And timer
- * is definitely too slow.
- * This will happen only once per LAP window, and usually at
- * the third packet (unless window is smaller). LAP is still
- * doing mtt and sending first packet so it's sort of OK
- * to do that. Jean II */
-
- /* If we need to send disconnect. try to do it now */
- if (self->disconnect_pend)
- irttp_start_todo_timer(self, 0);
-}
-
-/*
- * Function irttp_flow_request (self, command)
- *
- * This function could be used by the upper layers to tell IrTTP to stop
- * delivering frames if the receive queues are starting to get full, or
- * to tell IrTTP to start delivering frames again.
- */
-void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow)
-{
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-
- switch (flow) {
- case FLOW_STOP:
- pr_debug("%s(), flow stop\n", __func__);
- self->rx_sdu_busy = TRUE;
- break;
- case FLOW_START:
- pr_debug("%s(), flow start\n", __func__);
- self->rx_sdu_busy = FALSE;
-
- /* Client say he can accept more data, try to free our
- * queues ASAP - Jean II */
- irttp_run_rx_queue(self);
-
- break;
- default:
- pr_debug("%s(), Unknown flow command!\n", __func__);
- }
-}
-EXPORT_SYMBOL(irttp_flow_request);
-
-/*
- * Function irttp_connect_request (self, dtsap_sel, daddr, qos)
- *
- * Try to connect to remote destination TSAP selector
- *
- */
-int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
- __u32 saddr, __u32 daddr,
- struct qos_info *qos, __u32 max_sdu_size,
- struct sk_buff *userdata)
-{
- struct sk_buff *tx_skb;
- __u8 *frame;
- __u8 n;
-
- pr_debug("%s(), max_sdu_size=%d\n", __func__, max_sdu_size);
-
- IRDA_ASSERT(self != NULL, return -EBADR;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;);
-
- if (self->connected) {
- if (userdata)
- dev_kfree_skb(userdata);
- return -EISCONN;
- }
-
- /* Any userdata supplied? */
- if (userdata == NULL) {
- tx_skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER,
- GFP_ATOMIC);
- if (!tx_skb)
- return -ENOMEM;
-
- /* Reserve space for MUX_CONTROL and LAP header */
- skb_reserve(tx_skb, TTP_MAX_HEADER + TTP_SAR_HEADER);
- } else {
- tx_skb = userdata;
- /*
- * Check that the client has reserved enough space for
- * headers
- */
- IRDA_ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER,
- { dev_kfree_skb(userdata); return -1; });
- }
-
- /* Initialize connection parameters */
- self->connected = FALSE;
- self->avail_credit = 0;
- self->rx_max_sdu_size = max_sdu_size;
- self->rx_sdu_size = 0;
- self->rx_sdu_busy = FALSE;
- self->dtsap_sel = dtsap_sel;
-
- n = self->initial_credit;
-
- self->remote_credit = 0;
- self->send_credit = 0;
-
- /*
- * Give away max 127 credits for now
- */
- if (n > 127) {
- self->avail_credit = n - 127;
- n = 127;
- }
-
- self->remote_credit = n;
-
- /* SAR enabled? */
- if (max_sdu_size > 0) {
- IRDA_ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER),
- { dev_kfree_skb(tx_skb); return -1; });
-
- /* Insert SAR parameters */
- frame = skb_push(tx_skb, TTP_HEADER + TTP_SAR_HEADER);
-
- frame[0] = TTP_PARAMETERS | n;
- frame[1] = 0x04; /* Length */
- frame[2] = 0x01; /* MaxSduSize */
- frame[3] = 0x02; /* Value length */
-
- put_unaligned(cpu_to_be16((__u16) max_sdu_size),
- (__be16 *)(frame+4));
- } else {
- /* Insert plain TTP header */
- frame = skb_push(tx_skb, TTP_HEADER);
-
- /* Insert initial credit in frame */
- frame[0] = n & 0x7f;
- }
-
- /* Connect with IrLMP. No QoS parameters for now */
- return irlmp_connect_request(self->lsap, dtsap_sel, saddr, daddr, qos,
- tx_skb);
-}
-EXPORT_SYMBOL(irttp_connect_request);
-
-/*
- * Function irttp_connect_confirm (handle, qos, skb)
- *
- * Service user confirms TSAP connection with peer.
- *
- */
-static void irttp_connect_confirm(void *instance, void *sap,
- struct qos_info *qos, __u32 max_seg_size,
- __u8 max_header_size, struct sk_buff *skb)
-{
- struct tsap_cb *self;
- int parameters;
- int ret;
- __u8 plen;
- __u8 n;
-
- self = instance;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
-
- self->max_seg_size = max_seg_size - TTP_HEADER;
- self->max_header_size = max_header_size + TTP_HEADER;
-
- /*
- * Check if we have got some QoS parameters back! This should be the
- * negotiated QoS for the link.
- */
- if (qos) {
- pr_debug("IrTTP, Negotiated BAUD_RATE: %02x\n",
- qos->baud_rate.bits);
- pr_debug("IrTTP, Negotiated BAUD_RATE: %d bps.\n",
- qos->baud_rate.value);
- }
-
- n = skb->data[0] & 0x7f;
-
- pr_debug("%s(), Initial send_credit=%d\n", __func__, n);
-
- self->send_credit = n;
- self->tx_max_sdu_size = 0;
- self->connected = TRUE;
-
- parameters = skb->data[0] & 0x80;
-
- IRDA_ASSERT(skb->len >= TTP_HEADER, return;);
- skb_pull(skb, TTP_HEADER);
-
- if (parameters) {
- plen = skb->data[0];
-
- ret = irda_param_extract_all(self, skb->data+1,
- IRDA_MIN(skb->len-1, plen),
- &param_info);
-
- /* Any errors in the parameter list? */
- if (ret < 0) {
- net_warn_ratelimited("%s: error extracting parameters\n",
- __func__);
- dev_kfree_skb(skb);
-
- /* Do not accept this connection attempt */
- return;
- }
- /* Remove parameters */
- skb_pull(skb, IRDA_MIN(skb->len, plen+1));
- }
-
- pr_debug("%s() send=%d,avail=%d,remote=%d\n", __func__,
- self->send_credit, self->avail_credit, self->remote_credit);
-
- pr_debug("%s(), MaxSduSize=%d\n", __func__,
- self->tx_max_sdu_size);
-
- if (self->notify.connect_confirm) {
- self->notify.connect_confirm(self->notify.instance, self, qos,
- self->tx_max_sdu_size,
- self->max_header_size, skb);
- } else
- dev_kfree_skb(skb);
-}
-
-/*
- * Function irttp_connect_indication (handle, skb)
- *
- * Some other device is connecting to this TSAP
- *
- */
-static void irttp_connect_indication(void *instance, void *sap,
- struct qos_info *qos, __u32 max_seg_size, __u8 max_header_size,
- struct sk_buff *skb)
-{
- struct tsap_cb *self;
- struct lsap_cb *lsap;
- int parameters;
- int ret;
- __u8 plen;
- __u8 n;
-
- self = instance;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
- IRDA_ASSERT(skb != NULL, return;);
-
- lsap = sap;
-
- self->max_seg_size = max_seg_size - TTP_HEADER;
- self->max_header_size = max_header_size+TTP_HEADER;
-
- pr_debug("%s(), TSAP sel=%02x\n", __func__, self->stsap_sel);
-
- /* Need to update dtsap_sel if its equal to LSAP_ANY */
- self->dtsap_sel = lsap->dlsap_sel;
-
- n = skb->data[0] & 0x7f;
-
- self->send_credit = n;
- self->tx_max_sdu_size = 0;
-
- parameters = skb->data[0] & 0x80;
-
- IRDA_ASSERT(skb->len >= TTP_HEADER, return;);
- skb_pull(skb, TTP_HEADER);
-
- if (parameters) {
- plen = skb->data[0];
-
- ret = irda_param_extract_all(self, skb->data+1,
- IRDA_MIN(skb->len-1, plen),
- &param_info);
-
- /* Any errors in the parameter list? */
- if (ret < 0) {
- net_warn_ratelimited("%s: error extracting parameters\n",
- __func__);
- dev_kfree_skb(skb);
-
- /* Do not accept this connection attempt */
- return;
- }
-
- /* Remove parameters */
- skb_pull(skb, IRDA_MIN(skb->len, plen+1));
- }
-
- if (self->notify.connect_indication) {
- self->notify.connect_indication(self->notify.instance, self,
- qos, self->tx_max_sdu_size,
- self->max_header_size, skb);
- } else
- dev_kfree_skb(skb);
-}
-
-/*
- * Function irttp_connect_response (handle, userdata)
- *
- * Service user is accepting the connection, just pass it down to
- * IrLMP!
- *
- */
-int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
- struct sk_buff *userdata)
-{
- struct sk_buff *tx_skb;
- __u8 *frame;
- int ret;
- __u8 n;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-
- pr_debug("%s(), Source TSAP selector=%02x\n", __func__,
- self->stsap_sel);
-
- /* Any userdata supplied? */
- if (userdata == NULL) {
- tx_skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER,
- GFP_ATOMIC);
- if (!tx_skb)
- return -ENOMEM;
-
- /* Reserve space for MUX_CONTROL and LAP header */
- skb_reserve(tx_skb, TTP_MAX_HEADER + TTP_SAR_HEADER);
- } else {
- tx_skb = userdata;
- /*
- * Check that the client has reserved enough space for
- * headers
- */
- IRDA_ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER,
- { dev_kfree_skb(userdata); return -1; });
- }
-
- self->avail_credit = 0;
- self->remote_credit = 0;
- self->rx_max_sdu_size = max_sdu_size;
- self->rx_sdu_size = 0;
- self->rx_sdu_busy = FALSE;
-
- n = self->initial_credit;
-
- /* Frame has only space for max 127 credits (7 bits) */
- if (n > 127) {
- self->avail_credit = n - 127;
- n = 127;
- }
-
- self->remote_credit = n;
- self->connected = TRUE;
-
- /* SAR enabled? */
- if (max_sdu_size > 0) {
- IRDA_ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER),
- { dev_kfree_skb(tx_skb); return -1; });
-
- /* Insert TTP header with SAR parameters */
- frame = skb_push(tx_skb, TTP_HEADER + TTP_SAR_HEADER);
-
- frame[0] = TTP_PARAMETERS | n;
- frame[1] = 0x04; /* Length */
-
- /* irda_param_insert(self, IRTTP_MAX_SDU_SIZE, frame+1, */
-/* TTP_SAR_HEADER, &param_info) */
-
- frame[2] = 0x01; /* MaxSduSize */
- frame[3] = 0x02; /* Value length */
-
- put_unaligned(cpu_to_be16((__u16) max_sdu_size),
- (__be16 *)(frame+4));
- } else {
- /* Insert TTP header */
- frame = skb_push(tx_skb, TTP_HEADER);
-
- frame[0] = n & 0x7f;
- }
-
- ret = irlmp_connect_response(self->lsap, tx_skb);
-
- return ret;
-}
-EXPORT_SYMBOL(irttp_connect_response);
-
-/*
- * Function irttp_dup (self, instance)
- *
- * Duplicate TSAP, can be used by servers to confirm a connection on a
- * new TSAP so it can keep listening on the old one.
- */
-struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance)
-{
- struct tsap_cb *new;
- unsigned long flags;
-
- /* Protect our access to the old tsap instance */
- spin_lock_irqsave(&irttp->tsaps->hb_spinlock, flags);
-
- /* Find the old instance */
- if (!hashbin_find(irttp->tsaps, (long) orig, NULL)) {
- pr_debug("%s(), unable to find TSAP\n", __func__);
- spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
- return NULL;
- }
-
- /* Allocate a new instance */
- new = kmemdup(orig, sizeof(struct tsap_cb), GFP_ATOMIC);
- if (!new) {
- pr_debug("%s(), unable to kmalloc\n", __func__);
- spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
- return NULL;
- }
- spin_lock_init(&new->lock);
-
- /* We don't need the old instance any more */
- spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
-
- /* Try to dup the LSAP (may fail if we were too slow) */
- new->lsap = irlmp_dup(orig->lsap, new);
- if (!new->lsap) {
- pr_debug("%s(), dup failed!\n", __func__);
- kfree(new);
- return NULL;
- }
-
- /* Not everything should be copied */
- new->notify.instance = instance;
-
- /* Initialize internal objects */
- irttp_init_tsap(new);
-
- /* This is locked */
- hashbin_insert(irttp->tsaps, (irda_queue_t *) new, (long) new, NULL);
-
- return new;
-}
-EXPORT_SYMBOL(irttp_dup);
-
-/*
- * Function irttp_disconnect_request (self)
- *
- * Close this connection please! If priority is high, the queued data
- * segments, if any, will be deallocated first
- *
- */
-int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata,
- int priority)
-{
- int ret;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-
- /* Already disconnected? */
- if (!self->connected) {
- pr_debug("%s(), already disconnected!\n", __func__);
- if (userdata)
- dev_kfree_skb(userdata);
- return -1;
- }
-
- /* Disconnect already pending ?
- * We need to use an atomic operation to prevent reentry. This
- * function may be called from various context, like user, timer
- * for following a disconnect_indication() (i.e. net_bh).
- * Jean II */
- if (test_and_set_bit(0, &self->disconnect_pend)) {
- pr_debug("%s(), disconnect already pending\n",
- __func__);
- if (userdata)
- dev_kfree_skb(userdata);
-
- /* Try to make some progress */
- irttp_run_tx_queue(self);
- return -1;
- }
-
- /*
- * Check if there is still data segments in the transmit queue
- */
- if (!skb_queue_empty(&self->tx_queue)) {
- if (priority == P_HIGH) {
- /*
- * No need to send the queued data, if we are
- * disconnecting right now since the data will
- * not have any usable connection to be sent on
- */
- pr_debug("%s(): High priority!!()\n", __func__);
- irttp_flush_queues(self);
- } else if (priority == P_NORMAL) {
- /*
- * Must delay disconnect until after all data segments
- * have been sent and the tx_queue is empty
- */
- /* We'll reuse this one later for the disconnect */
- self->disconnect_skb = userdata; /* May be NULL */
-
- irttp_run_tx_queue(self);
-
- irttp_start_todo_timer(self, HZ/10);
- return -1;
- }
- }
- /* Note : we don't need to check if self->rx_queue is full and the
- * state of self->rx_sdu_busy because the disconnect response will
- * be sent at the LMP level (so even if the peer has its Tx queue
- * full of data). - Jean II */
-
- pr_debug("%s(), Disconnecting ...\n", __func__);
- self->connected = FALSE;
-
- if (!userdata) {
- struct sk_buff *tx_skb;
- tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
- if (!tx_skb)
- return -ENOMEM;
-
- /*
- * Reserve space for MUX and LAP header
- */
- skb_reserve(tx_skb, LMP_MAX_HEADER);
-
- userdata = tx_skb;
- }
- ret = irlmp_disconnect_request(self->lsap, userdata);
-
- /* The disconnect is no longer pending */
- clear_bit(0, &self->disconnect_pend); /* FALSE */
-
- return ret;
-}
-EXPORT_SYMBOL(irttp_disconnect_request);
-
-/*
- * Function irttp_disconnect_indication (self, reason)
- *
- * Disconnect indication, TSAP disconnected by peer?
- *
- */
-static void irttp_disconnect_indication(void *instance, void *sap,
- LM_REASON reason, struct sk_buff *skb)
-{
- struct tsap_cb *self;
-
- self = instance;
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-
- /* Prevent higher layer to send more data */
- self->connected = FALSE;
-
- /* Check if client has already tried to close the TSAP */
- if (self->close_pend) {
- /* In this case, the higher layer is probably gone. Don't
- * bother it and clean up the remains - Jean II */
- if (skb)
- dev_kfree_skb(skb);
- irttp_close_tsap(self);
- return;
- }
-
- /* If we are here, we assume that is the higher layer is still
- * waiting for the disconnect notification and able to process it,
- * even if he tried to disconnect. Otherwise, it would have already
- * attempted to close the tsap and self->close_pend would be TRUE.
- * Jean II */
-
- /* No need to notify the client if has already tried to disconnect */
- if (self->notify.disconnect_indication)
- self->notify.disconnect_indication(self->notify.instance, self,
- reason, skb);
- else
- if (skb)
- dev_kfree_skb(skb);
-}
-
-/*
- * Function irttp_do_data_indication (self, skb)
- *
- * Try to deliver reassembled skb to layer above, and requeue it if that
- * for some reason should fail. We mark rx sdu as busy to apply back
- * pressure is necessary.
- */
-static void irttp_do_data_indication(struct tsap_cb *self, struct sk_buff *skb)
-{
- int err;
-
- /* Check if client has already closed the TSAP and gone away */
- if (self->close_pend) {
- dev_kfree_skb(skb);
- return;
- }
-
- err = self->notify.data_indication(self->notify.instance, self, skb);
-
- /* Usually the layer above will notify that it's input queue is
- * starting to get filled by using the flow request, but this may
- * be difficult, so it can instead just refuse to eat it and just
- * give an error back
- */
- if (err) {
- pr_debug("%s() requeueing skb!\n", __func__);
-
- /* Make sure we take a break */
- self->rx_sdu_busy = TRUE;
-
- /* Need to push the header in again */
- skb_push(skb, TTP_HEADER);
- skb->data[0] = 0x00; /* Make sure MORE bit is cleared */
-
- /* Put skb back on queue */
- skb_queue_head(&self->rx_queue, skb);
- }
-}
-
-/*
- * Function irttp_run_rx_queue (self)
- *
- * Check if we have any frames to be transmitted, or if we have any
- * available credit to give away.
- */
-static void irttp_run_rx_queue(struct tsap_cb *self)
-{
- struct sk_buff *skb;
- int more = 0;
-
- pr_debug("%s() send=%d,avail=%d,remote=%d\n", __func__,
- self->send_credit, self->avail_credit, self->remote_credit);
-
- /* Get exclusive access to the rx queue, otherwise don't touch it */
- if (irda_lock(&self->rx_queue_lock) == FALSE)
- return;
-
- /*
- * Reassemble all frames in receive queue and deliver them
- */
- while (!self->rx_sdu_busy && (skb = skb_dequeue(&self->rx_queue))) {
- /* This bit will tell us if it's the last fragment or not */
- more = skb->data[0] & 0x80;
-
- /* Remove TTP header */
- skb_pull(skb, TTP_HEADER);
-
- /* Add the length of the remaining data */
- self->rx_sdu_size += skb->len;
-
- /*
- * If SAR is disabled, or user has requested no reassembly
- * of received fragments then we just deliver them
- * immediately. This can be requested by clients that
- * implements byte streams without any message boundaries
- */
- if (self->rx_max_sdu_size == TTP_SAR_DISABLE) {
- irttp_do_data_indication(self, skb);
- self->rx_sdu_size = 0;
-
- continue;
- }
-
- /* Check if this is a fragment, and not the last fragment */
- if (more) {
- /*
- * Queue the fragment if we still are within the
- * limits of the maximum size of the rx_sdu
- */
- if (self->rx_sdu_size <= self->rx_max_sdu_size) {
- pr_debug("%s(), queueing frag\n",
- __func__);
- skb_queue_tail(&self->rx_fragments, skb);
- } else {
- /* Free the part of the SDU that is too big */
- dev_kfree_skb(skb);
- }
- continue;
- }
- /*
- * This is the last fragment, so time to reassemble!
- */
- if ((self->rx_sdu_size <= self->rx_max_sdu_size) ||
- (self->rx_max_sdu_size == TTP_SAR_UNBOUND)) {
- /*
- * A little optimizing. Only queue the fragment if
- * there are other fragments. Since if this is the
- * last and only fragment, there is no need to
- * reassemble :-)
- */
- if (!skb_queue_empty(&self->rx_fragments)) {
- skb_queue_tail(&self->rx_fragments,
- skb);
-
- skb = irttp_reassemble_skb(self);
- }
-
- /* Now we can deliver the reassembled skb */
- irttp_do_data_indication(self, skb);
- } else {
- pr_debug("%s(), Truncated frame\n", __func__);
-
- /* Free the part of the SDU that is too big */
- dev_kfree_skb(skb);
-
- /* Deliver only the valid but truncated part of SDU */
- skb = irttp_reassemble_skb(self);
-
- irttp_do_data_indication(self, skb);
- }
- self->rx_sdu_size = 0;
- }
-
- /*
- * It's not trivial to keep track of how many credits are available
- * by incrementing at each packet, because delivery may fail
- * (irttp_do_data_indication() may requeue the frame) and because
- * we need to take care of fragmentation.
- * We want the other side to send up to initial_credit packets.
- * We have some frames in our queues, and we have already allowed it
- * to send remote_credit.
- * No need to spinlock, write is atomic and self correcting...
- * Jean II
- */
- self->avail_credit = (self->initial_credit -
- (self->remote_credit +
- skb_queue_len(&self->rx_queue) +
- skb_queue_len(&self->rx_fragments)));
-
- /* Do we have too much credits to send to peer ? */
- if ((self->remote_credit <= TTP_RX_MIN_CREDIT) &&
- (self->avail_credit > 0)) {
- /* Send explicit credit frame */
- irttp_give_credit(self);
- /* Note : do *NOT* check if tx_queue is non-empty, that
- * will produce deadlocks. I repeat : send a credit frame
- * even if we have something to send in our Tx queue.
- * If we have credits, it means that our Tx queue is blocked.
- *
- * Let's suppose the peer can't keep up with our Tx. He will
- * flow control us by not sending us any credits, and we
- * will stop Tx and start accumulating credits here.
- * Up to the point where the peer will stop its Tx queue,
- * for lack of credits.
- * Let's assume the peer application is single threaded.
- * It will block on Tx and never consume any Rx buffer.
- * Deadlock. Guaranteed. - Jean II
- */
- }
-
- /* Reset lock */
- self->rx_queue_lock = 0;
-}
-
-#ifdef CONFIG_PROC_FS
-struct irttp_iter_state {
- int id;
-};
-
-static void *irttp_seq_start(struct seq_file *seq, loff_t *pos)
-{
- struct irttp_iter_state *iter = seq->private;
- struct tsap_cb *self;
-
- /* Protect our access to the tsap list */
- spin_lock_irq(&irttp->tsaps->hb_spinlock);
- iter->id = 0;
-
- for (self = (struct tsap_cb *) hashbin_get_first(irttp->tsaps);
- self != NULL;
- self = (struct tsap_cb *) hashbin_get_next(irttp->tsaps)) {
- if (iter->id == *pos)
- break;
- ++iter->id;
- }
-
- return self;
-}
-
-static void *irttp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- struct irttp_iter_state *iter = seq->private;
-
- ++*pos;
- ++iter->id;
- return (void *) hashbin_get_next(irttp->tsaps);
-}
-
-static void irttp_seq_stop(struct seq_file *seq, void *v)
-{
- spin_unlock_irq(&irttp->tsaps->hb_spinlock);
-}
-
-static int irttp_seq_show(struct seq_file *seq, void *v)
-{
- const struct irttp_iter_state *iter = seq->private;
- const struct tsap_cb *self = v;
-
- seq_printf(seq, "TSAP %d, ", iter->id);
- seq_printf(seq, "stsap_sel: %02x, ",
- self->stsap_sel);
- seq_printf(seq, "dtsap_sel: %02x\n",
- self->dtsap_sel);
- seq_printf(seq, " connected: %s, ",
- self->connected ? "TRUE" : "FALSE");
- seq_printf(seq, "avail credit: %d, ",
- self->avail_credit);
- seq_printf(seq, "remote credit: %d, ",
- self->remote_credit);
- seq_printf(seq, "send credit: %d\n",
- self->send_credit);
- seq_printf(seq, " tx packets: %lu, ",
- self->stats.tx_packets);
- seq_printf(seq, "rx packets: %lu, ",
- self->stats.rx_packets);
- seq_printf(seq, "tx_queue len: %u ",
- skb_queue_len(&self->tx_queue));
- seq_printf(seq, "rx_queue len: %u\n",
- skb_queue_len(&self->rx_queue));
- seq_printf(seq, " tx_sdu_busy: %s, ",
- self->tx_sdu_busy ? "TRUE" : "FALSE");
- seq_printf(seq, "rx_sdu_busy: %s\n",
- self->rx_sdu_busy ? "TRUE" : "FALSE");
- seq_printf(seq, " max_seg_size: %u, ",
- self->max_seg_size);
- seq_printf(seq, "tx_max_sdu_size: %u, ",
- self->tx_max_sdu_size);
- seq_printf(seq, "rx_max_sdu_size: %u\n",
- self->rx_max_sdu_size);
-
- seq_printf(seq, " Used by (%s)\n\n",
- self->notify.name);
- return 0;
-}
-
-static const struct seq_operations irttp_seq_ops = {
- .start = irttp_seq_start,
- .next = irttp_seq_next,
- .stop = irttp_seq_stop,
- .show = irttp_seq_show,
-};
-
-static int irttp_seq_open(struct inode *inode, struct file *file)
-{
- return seq_open_private(file, &irttp_seq_ops,
- sizeof(struct irttp_iter_state));
-}
-
-const struct file_operations irttp_seq_fops = {
- .owner = THIS_MODULE,
- .open = irttp_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_private,
-};
-
-#endif /* PROC_FS */
diff --git a/drivers/staging/irda/net/parameters.c b/drivers/staging/irda/net/parameters.c
deleted file mode 100644
index 16ce32ffe004..000000000000
--- a/drivers/staging/irda/net/parameters.c
+++ /dev/null
@@ -1,584 +0,0 @@
-/*********************************************************************
- *
- * Filename: parameters.c
- * Version: 1.0
- * Description: A more general way to handle (pi,pl,pv) parameters
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Jun 7 10:25:11 1999
- * Modified at: Sun Jan 30 14:08:39 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999-2000 Dag Brattli, 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.
- *
- * 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/types.h>
-#include <linux/module.h>
-
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/parameters.h>
-
-static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi,
- PV_TYPE type, PI_HANDLER func);
-static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi,
- PV_TYPE type, PI_HANDLER func);
-static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi,
- PV_TYPE type, PI_HANDLER func);
-static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi,
- PV_TYPE type, PI_HANDLER func);
-
-static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi,
- PV_TYPE type, PI_HANDLER func);
-static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi,
- PV_TYPE type, PI_HANDLER func);
-
-static int irda_param_unpack(__u8 *buf, char *fmt, ...);
-
-/* Parameter value call table. Must match PV_TYPE */
-static const PV_HANDLER pv_extract_table[] = {
- irda_extract_integer, /* Handler for any length integers */
- irda_extract_integer, /* Handler for 8 bits integers */
- irda_extract_integer, /* Handler for 16 bits integers */
- irda_extract_string, /* Handler for strings */
- irda_extract_integer, /* Handler for 32 bits integers */
- irda_extract_octseq, /* Handler for octet sequences */
- irda_extract_no_value /* Handler for no value parameters */
-};
-
-static const PV_HANDLER pv_insert_table[] = {
- irda_insert_integer, /* Handler for any length integers */
- irda_insert_integer, /* Handler for 8 bits integers */
- irda_insert_integer, /* Handler for 16 bits integers */
- NULL, /* Handler for strings */
- irda_insert_integer, /* Handler for 32 bits integers */
- NULL, /* Handler for octet sequences */
- irda_insert_no_value /* Handler for no value parameters */
-};
-
-/*
- * Function irda_insert_no_value (self, buf, len, pi, type, func)
- */
-static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi,
- PV_TYPE type, PI_HANDLER func)
-{
- irda_param_t p;
- int ret;
-
- p.pi = pi;
- p.pl = 0;
-
- /* Call handler for this parameter */
- ret = (*func)(self, &p, PV_GET);
-
- /* Extract values anyway, since handler may need them */
- irda_param_pack(buf, "bb", p.pi, p.pl);
-
- if (ret < 0)
- return ret;
-
- return 2; /* Inserted pl+2 bytes */
-}
-
-/*
- * Function irda_extract_no_value (self, buf, len, type, func)
- *
- * Extracts a parameter without a pv field (pl=0)
- *
- */
-static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi,
- PV_TYPE type, PI_HANDLER func)
-{
- irda_param_t p;
- int ret;
-
- /* Extract values anyway, since handler may need them */
- irda_param_unpack(buf, "bb", &p.pi, &p.pl);
-
- /* Call handler for this parameter */
- ret = (*func)(self, &p, PV_PUT);
-
- if (ret < 0)
- return ret;
-
- return 2; /* Extracted pl+2 bytes */
-}
-
-/*
- * Function irda_insert_integer (self, buf, len, pi, type, func)
- */
-static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi,
- PV_TYPE type, PI_HANDLER func)
-{
- irda_param_t p;
- int n = 0;
- int err;
-
- p.pi = pi; /* In case handler needs to know */
- p.pl = type & PV_MASK; /* The integer type codes the length as well */
- p.pv.i = 0; /* Clear value */
-
- /* Call handler for this parameter */
- err = (*func)(self, &p, PV_GET);
- if (err < 0)
- return err;
-
- /*
- * If parameter length is still 0, then (1) this is an any length
- * integer, and (2) the handler function does not care which length
- * we choose to use, so we pick the one the gives the fewest bytes.
- */
- if (p.pl == 0) {
- if (p.pv.i < 0xff) {
- pr_debug("%s(), using 1 byte\n", __func__);
- p.pl = 1;
- } else if (p.pv.i < 0xffff) {
- pr_debug("%s(), using 2 bytes\n", __func__);
- p.pl = 2;
- } else {
- pr_debug("%s(), using 4 bytes\n", __func__);
- p.pl = 4; /* Default length */
- }
- }
- /* Check if buffer is long enough for insertion */
- if (len < (2+p.pl)) {
- net_warn_ratelimited("%s: buffer too short for insertion!\n",
- __func__);
- return -1;
- }
- pr_debug("%s(), pi=%#x, pl=%d, pi=%d\n", __func__,
- p.pi, p.pl, p.pv.i);
- switch (p.pl) {
- case 1:
- n += irda_param_pack(buf, "bbb", p.pi, p.pl, (__u8) p.pv.i);
- break;
- case 2:
- if (type & PV_BIG_ENDIAN)
- p.pv.i = cpu_to_be16((__u16) p.pv.i);
- else
- p.pv.i = cpu_to_le16((__u16) p.pv.i);
- n += irda_param_pack(buf, "bbs", p.pi, p.pl, (__u16) p.pv.i);
- break;
- case 4:
- if (type & PV_BIG_ENDIAN)
- cpu_to_be32s(&p.pv.i);
- else
- cpu_to_le32s(&p.pv.i);
- n += irda_param_pack(buf, "bbi", p.pi, p.pl, p.pv.i);
-
- break;
- default:
- net_warn_ratelimited("%s: length %d not supported\n",
- __func__, p.pl);
- /* Skip parameter */
- return -1;
- }
-
- return p.pl+2; /* Inserted pl+2 bytes */
-}
-
-/*
- * Function irda_extract integer (self, buf, len, pi, type, func)
- *
- * Extract a possibly variable length integer from buffer, and call
- * handler for processing of the parameter
- */
-static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi,
- PV_TYPE type, PI_HANDLER func)
-{
- irda_param_t p;
- int n = 0;
- int extract_len; /* Real length we extract */
- int err;
-
- p.pi = pi; /* In case handler needs to know */
- p.pl = buf[1]; /* Extract length of value */
- p.pv.i = 0; /* Clear value */
- extract_len = p.pl; /* Default : extract all */
-
- /* Check if buffer is long enough for parsing */
- if (len < (2+p.pl)) {
- net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n",
- __func__, p.pl, len);
- return -1;
- }
-
- /*
- * Check that the integer length is what we expect it to be. If the
- * handler want a 16 bits integer then a 32 bits is not good enough
- * PV_INTEGER means that the handler is flexible.
- */
- if (((type & PV_MASK) != PV_INTEGER) && ((type & PV_MASK) != p.pl)) {
- net_err_ratelimited("%s: invalid parameter length! Expected %d bytes, but value had %d bytes!\n",
- __func__, type & PV_MASK, p.pl);
-
- /* Most parameters are bit/byte fields or little endian,
- * so it's ok to only extract a subset of it (the subset
- * that the handler expect). This is necessary, as some
- * broken implementations seems to add extra undefined bits.
- * If the parameter is shorter than we expect or is big
- * endian, we can't play those tricks. Jean II */
- if((p.pl < (type & PV_MASK)) || (type & PV_BIG_ENDIAN)) {
- /* Skip parameter */
- return p.pl+2;
- } else {
- /* Extract subset of it, fallthrough */
- extract_len = type & PV_MASK;
- }
- }
-
-
- switch (extract_len) {
- case 1:
- n += irda_param_unpack(buf+2, "b", &p.pv.i);
- break;
- case 2:
- n += irda_param_unpack(buf+2, "s", &p.pv.i);
- if (type & PV_BIG_ENDIAN)
- p.pv.i = be16_to_cpu((__u16) p.pv.i);
- else
- p.pv.i = le16_to_cpu((__u16) p.pv.i);
- break;
- case 4:
- n += irda_param_unpack(buf+2, "i", &p.pv.i);
- if (type & PV_BIG_ENDIAN)
- be32_to_cpus(&p.pv.i);
- else
- le32_to_cpus(&p.pv.i);
- break;
- default:
- net_warn_ratelimited("%s: length %d not supported\n",
- __func__, p.pl);
-
- /* Skip parameter */
- return p.pl+2;
- }
-
- pr_debug("%s(), pi=%#x, pl=%d, pi=%d\n", __func__,
- p.pi, p.pl, p.pv.i);
- /* Call handler for this parameter */
- err = (*func)(self, &p, PV_PUT);
- if (err < 0)
- return err;
-
- return p.pl+2; /* Extracted pl+2 bytes */
-}
-
-/*
- * Function irda_extract_string (self, buf, len, type, func)
- */
-static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi,
- PV_TYPE type, PI_HANDLER func)
-{
- char str[33];
- irda_param_t p;
- int err;
-
- p.pi = pi; /* In case handler needs to know */
- p.pl = buf[1]; /* Extract length of value */
- if (p.pl > 32)
- p.pl = 32;
-
- pr_debug("%s(), pi=%#x, pl=%d\n", __func__,
- p.pi, p.pl);
-
- /* Check if buffer is long enough for parsing */
- if (len < (2+p.pl)) {
- net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n",
- __func__, p.pl, len);
- return -1;
- }
-
- /* Should be safe to copy string like this since we have already
- * checked that the buffer is long enough */
- strncpy(str, buf+2, p.pl);
-
- pr_debug("%s(), str=0x%02x 0x%02x\n",
- __func__, (__u8)str[0], (__u8)str[1]);
-
- /* Null terminate string */
- str[p.pl] = '\0';
-
- p.pv.c = str; /* Handler will need to take a copy */
-
- /* Call handler for this parameter */
- err = (*func)(self, &p, PV_PUT);
- if (err < 0)
- return err;
-
- return p.pl+2; /* Extracted pl+2 bytes */
-}
-
-/*
- * Function irda_extract_octseq (self, buf, len, type, func)
- */
-static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi,
- PV_TYPE type, PI_HANDLER func)
-{
- irda_param_t p;
-
- p.pi = pi; /* In case handler needs to know */
- p.pl = buf[1]; /* Extract length of value */
-
- /* Check if buffer is long enough for parsing */
- if (len < (2+p.pl)) {
- net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n",
- __func__, p.pl, len);
- return -1;
- }
-
- pr_debug("%s(), not impl\n", __func__);
-
- return p.pl+2; /* Extracted pl+2 bytes */
-}
-
-/*
- * Function irda_param_pack (skb, fmt, ...)
- *
- * Format:
- * 'i' = 32 bits integer
- * 's' = string
- *
- */
-int irda_param_pack(__u8 *buf, char *fmt, ...)
-{
- irda_pv_t arg;
- va_list args;
- char *p;
- int n = 0;
-
- va_start(args, fmt);
-
- for (p = fmt; *p != '\0'; p++) {
- switch (*p) {
- case 'b': /* 8 bits unsigned byte */
- buf[n++] = (__u8)va_arg(args, int);
- break;
- case 's': /* 16 bits unsigned short */
- arg.i = (__u16)va_arg(args, int);
- put_unaligned((__u16)arg.i, (__u16 *)(buf+n)); n+=2;
- break;
- case 'i': /* 32 bits unsigned integer */
- arg.i = va_arg(args, __u32);
- put_unaligned(arg.i, (__u32 *)(buf+n)); n+=4;
- break;
-#if 0
- case 'c': /* \0 terminated string */
- arg.c = va_arg(args, char *);
- strcpy(buf+n, arg.c);
- n += strlen(arg.c) + 1;
- break;
-#endif
- default:
- va_end(args);
- return -1;
- }
- }
- va_end(args);
-
- return 0;
-}
-EXPORT_SYMBOL(irda_param_pack);
-
-/*
- * Function irda_param_unpack (skb, fmt, ...)
- */
-static int irda_param_unpack(__u8 *buf, char *fmt, ...)
-{
- irda_pv_t arg;
- va_list args;
- char *p;
- int n = 0;
-
- va_start(args, fmt);
-
- for (p = fmt; *p != '\0'; p++) {
- switch (*p) {
- case 'b': /* 8 bits byte */
- arg.ip = va_arg(args, __u32 *);
- *arg.ip = buf[n++];
- break;
- case 's': /* 16 bits short */
- arg.ip = va_arg(args, __u32 *);
- *arg.ip = get_unaligned((__u16 *)(buf+n)); n+=2;
- break;
- case 'i': /* 32 bits unsigned integer */
- arg.ip = va_arg(args, __u32 *);
- *arg.ip = get_unaligned((__u32 *)(buf+n)); n+=4;
- break;
-#if 0
- case 'c': /* \0 terminated string */
- arg.c = va_arg(args, char *);
- strcpy(arg.c, buf+n);
- n += strlen(arg.c) + 1;
- break;
-#endif
- default:
- va_end(args);
- return -1;
- }
-
- }
- va_end(args);
-
- return 0;
-}
-
-/*
- * Function irda_param_insert (self, pi, buf, len, info)
- *
- * Insert the specified parameter (pi) into buffer. Returns number of
- * bytes inserted
- */
-int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len,
- pi_param_info_t *info)
-{
- const pi_minor_info_t *pi_minor_info;
- __u8 pi_minor;
- __u8 pi_major;
- int type;
- int ret = -1;
- int n = 0;
-
- IRDA_ASSERT(buf != NULL, return ret;);
- IRDA_ASSERT(info != NULL, return ret;);
-
- pi_minor = pi & info->pi_mask;
- pi_major = pi >> info->pi_major_offset;
-
- /* Check if the identifier value (pi) is valid */
- if ((pi_major > info->len-1) ||
- (pi_minor > info->tables[pi_major].len-1))
- {
- pr_debug("%s(), no handler for parameter=0x%02x\n",
- __func__, pi);
-
- /* Skip this parameter */
- return -1;
- }
-
- /* Lookup the info on how to parse this parameter */
- pi_minor_info = &info->tables[pi_major].pi_minor_call_table[pi_minor];
-
- /* Find expected data type for this parameter identifier (pi)*/
- type = pi_minor_info->type;
-
- /* Check if handler has been implemented */
- if (!pi_minor_info->func) {
- net_info_ratelimited("%s: no handler for pi=%#x\n",
- __func__, pi);
- /* Skip this parameter */
- return -1;
- }
-
- /* Insert parameter value */
- ret = (*pv_insert_table[type & PV_MASK])(self, buf+n, len, pi, type,
- pi_minor_info->func);
- return ret;
-}
-EXPORT_SYMBOL(irda_param_insert);
-
-/*
- * Function irda_param_extract (self, buf, len, info)
- *
- * Parse all parameters. If len is correct, then everything should be
- * safe. Returns the number of bytes that was parsed
- *
- */
-static int irda_param_extract(void *self, __u8 *buf, int len,
- pi_param_info_t *info)
-{
- const pi_minor_info_t *pi_minor_info;
- __u8 pi_minor;
- __u8 pi_major;
- int type;
- int ret = -1;
- int n = 0;
-
- IRDA_ASSERT(buf != NULL, return ret;);
- IRDA_ASSERT(info != NULL, return ret;);
-
- pi_minor = buf[n] & info->pi_mask;
- pi_major = buf[n] >> info->pi_major_offset;
-
- /* Check if the identifier value (pi) is valid */
- if ((pi_major > info->len-1) ||
- (pi_minor > info->tables[pi_major].len-1))
- {
- pr_debug("%s(), no handler for parameter=0x%02x\n",
- __func__, buf[0]);
-
- /* Skip this parameter */
- return 2 + buf[n + 1]; /* Continue */
- }
-
- /* Lookup the info on how to parse this parameter */
- pi_minor_info = &info->tables[pi_major].pi_minor_call_table[pi_minor];
-
- /* Find expected data type for this parameter identifier (pi)*/
- type = pi_minor_info->type;
-
- pr_debug("%s(), pi=[%d,%d], type=%d\n", __func__,
- pi_major, pi_minor, type);
-
- /* Check if handler has been implemented */
- if (!pi_minor_info->func) {
- net_info_ratelimited("%s: no handler for pi=%#x\n",
- __func__, buf[n]);
- /* Skip this parameter */
- return 2 + buf[n + 1]; /* Continue */
- }
-
- /* Parse parameter value */
- ret = (*pv_extract_table[type & PV_MASK])(self, buf+n, len, buf[n],
- type, pi_minor_info->func);
- return ret;
-}
-
-/*
- * Function irda_param_extract_all (self, buf, len, info)
- *
- * Parse all parameters. If len is correct, then everything should be
- * safe. Returns the number of bytes that was parsed
- *
- */
-int irda_param_extract_all(void *self, __u8 *buf, int len,
- pi_param_info_t *info)
-{
- int ret = -1;
- int n = 0;
-
- IRDA_ASSERT(buf != NULL, return ret;);
- IRDA_ASSERT(info != NULL, return ret;);
-
- /*
- * Parse all parameters. Each parameter must be at least two bytes
- * long or else there is no point in trying to parse it
- */
- while (len > 2) {
- ret = irda_param_extract(self, buf+n, len, info);
- if (ret < 0)
- return ret;
-
- n += ret;
- len -= ret;
- }
- return n;
-}
-EXPORT_SYMBOL(irda_param_extract_all);
diff --git a/drivers/staging/irda/net/qos.c b/drivers/staging/irda/net/qos.c
deleted file mode 100644
index 25ba8509ad3e..000000000000
--- a/drivers/staging/irda/net/qos.c
+++ /dev/null
@@ -1,771 +0,0 @@
-/*********************************************************************
- *
- * Filename: qos.c
- * Version: 1.0
- * Description: IrLAP QoS parameter negotiation
- * Status: Stable
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Tue Sep 9 00:00:26 1997
- * Modified at: Sun Jan 30 14:29:16 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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/export.h>
-
-#include <asm/byteorder.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/parameters.h>
-#include <net/irda/qos.h>
-#include <net/irda/irlap.h>
-#include <net/irda/irlap_frame.h>
-
-/*
- * Maximum values of the baud rate we negotiate with the other end.
- * Most often, you don't have to change that, because Linux-IrDA will
- * use the maximum offered by the link layer, which usually works fine.
- * In some very rare cases, you may want to limit it to lower speeds...
- */
-int sysctl_max_baud_rate = 16000000;
-/*
- * Maximum value of the lap disconnect timer we negotiate with the other end.
- * Most often, the value below represent the best compromise, but some user
- * may want to keep the LAP alive longer or shorter in case of link failure.
- * Remember that the threshold time (early warning) is fixed to 3s...
- */
-int sysctl_max_noreply_time = 12;
-/*
- * Minimum turn time to be applied before transmitting to the peer.
- * Nonzero values (usec) are used as lower limit to the per-connection
- * mtt value which was announced by the other end during negotiation.
- * Might be helpful if the peer device provides too short mtt.
- * Default is 10us which means using the unmodified value given by the
- * peer except if it's 0 (0 is likely a bug in the other stack).
- */
-unsigned int sysctl_min_tx_turn_time = 10;
-/*
- * Maximum data size to be used in transmission in payload of LAP frame.
- * There is a bit of confusion in the IrDA spec :
- * The LAP spec defines the payload of a LAP frame (I field) to be
- * 2048 bytes max (IrLAP 1.1, chapt 6.6.5, p40).
- * On the other hand, the PHY mention frames of 2048 bytes max (IrPHY
- * 1.2, chapt 5.3.2.1, p41). But, this number includes the LAP header
- * (2 bytes), and CRC (32 bits at 4 Mb/s). So, for the I field (LAP
- * payload), that's only 2042 bytes. Oups !
- * My nsc-ircc hardware has troubles receiving 2048 bytes frames at 4 Mb/s,
- * so adjust to 2042... I don't know if this bug applies only for 2048
- * bytes frames or all negotiated frame sizes, but you can use the sysctl
- * to play with this value anyway.
- * Jean II */
-unsigned int sysctl_max_tx_data_size = 2042;
-/*
- * Maximum transmit window, i.e. number of LAP frames between turn-around.
- * This allow to override what the peer told us. Some peers are buggy and
- * don't always support what they tell us.
- * Jean II */
-unsigned int sysctl_max_tx_window = 7;
-
-static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get);
-static int irlap_param_link_disconnect(void *instance, irda_param_t *parm,
- int get);
-static int irlap_param_max_turn_time(void *instance, irda_param_t *param,
- int get);
-static int irlap_param_data_size(void *instance, irda_param_t *param, int get);
-static int irlap_param_window_size(void *instance, irda_param_t *param,
- int get);
-static int irlap_param_additional_bofs(void *instance, irda_param_t *parm,
- int get);
-static int irlap_param_min_turn_time(void *instance, irda_param_t *param,
- int get);
-
-#ifndef CONFIG_IRDA_DYNAMIC_WINDOW
-static __u32 irlap_requested_line_capacity(struct qos_info *qos);
-#endif
-
-static __u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */
-static __u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000,
- 1152000, 4000000, 16000000 }; /* bps */
-static __u32 data_sizes[] = { 64, 128, 256, 512, 1024, 2048 }; /* bytes */
-static __u32 add_bofs[] = { 48, 24, 12, 5, 3, 2, 1, 0 }; /* bytes */
-static __u32 max_turn_times[] = { 500, 250, 100, 50 }; /* ms */
-static __u32 link_disc_times[] = { 3, 8, 12, 16, 20, 25, 30, 40 }; /* secs */
-
-static __u32 max_line_capacities[10][4] = {
- /* 500 ms 250 ms 100 ms 50 ms (max turn time) */
- { 100, 0, 0, 0 }, /* 2400 bps */
- { 400, 0, 0, 0 }, /* 9600 bps */
- { 800, 0, 0, 0 }, /* 19200 bps */
- { 1600, 0, 0, 0 }, /* 38400 bps */
- { 2360, 0, 0, 0 }, /* 57600 bps */
- { 4800, 2400, 960, 480 }, /* 115200 bps */
- { 28800, 11520, 5760, 2880 }, /* 576000 bps */
- { 57600, 28800, 11520, 5760 }, /* 1152000 bps */
- { 200000, 100000, 40000, 20000 }, /* 4000000 bps */
- { 800000, 400000, 160000, 80000 }, /* 16000000 bps */
-};
-
-static const pi_minor_info_t pi_minor_call_table_type_0[] = {
- { NULL, 0 },
-/* 01 */{ irlap_param_baud_rate, PV_INTEGER | PV_LITTLE_ENDIAN },
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
- { NULL, 0 },
-/* 08 */{ irlap_param_link_disconnect, PV_INT_8_BITS }
-};
-
-static const pi_minor_info_t pi_minor_call_table_type_1[] = {
- { NULL, 0 },
- { NULL, 0 },
-/* 82 */{ irlap_param_max_turn_time, PV_INT_8_BITS },
-/* 83 */{ irlap_param_data_size, PV_INT_8_BITS },
-/* 84 */{ irlap_param_window_size, PV_INT_8_BITS },
-/* 85 */{ irlap_param_additional_bofs, PV_INT_8_BITS },
-/* 86 */{ irlap_param_min_turn_time, PV_INT_8_BITS },
-};
-
-static const pi_major_info_t pi_major_call_table[] = {
- { pi_minor_call_table_type_0, 9 },
- { pi_minor_call_table_type_1, 7 },
-};
-
-static pi_param_info_t irlap_param_info = { pi_major_call_table, 2, 0x7f, 7 };
-
-/* ---------------------- LOCAL SUBROUTINES ---------------------- */
-/* Note : we start with a bunch of local subroutines.
- * As the compiler is "one pass", this is the only way to get them to
- * inline properly...
- * Jean II
- */
-/*
- * Function value_index (value, array, size)
- *
- * Returns the index to the value in the specified array
- */
-static inline int value_index(__u32 value, __u32 *array, int size)
-{
- int i;
-
- for (i=0; i < size; i++)
- if (array[i] == value)
- break;
- return i;
-}
-
-/*
- * Function index_value (index, array)
- *
- * Returns value to index in array, easy!
- *
- */
-static inline __u32 index_value(int index, __u32 *array)
-{
- return array[index];
-}
-
-/*
- * Function msb_index (word)
- *
- * Returns index to most significant bit (MSB) in word
- *
- */
-static int msb_index (__u16 word)
-{
- __u16 msb = 0x8000;
- int index = 15; /* Current MSB */
-
- /* Check for buggy peers.
- * Note : there is a small probability that it could be us, but I
- * would expect driver authors to catch that pretty early and be
- * able to check precisely what's going on. If a end user sees this,
- * it's very likely the peer. - Jean II */
- if (word == 0) {
- net_warn_ratelimited("%s(), Detected buggy peer, adjust null PV to 0x1!\n",
- __func__);
- /* The only safe choice (we don't know the array size) */
- word = 0x1;
- }
-
- while (msb) {
- if (word & msb)
- break; /* Found it! */
- msb >>=1;
- index--;
- }
- return index;
-}
-
-/*
- * Function value_lower_bits (value, array)
- *
- * Returns a bit field marking all possibility lower than value.
- */
-static inline int value_lower_bits(__u32 value, __u32 *array, int size, __u16 *field)
-{
- int i;
- __u16 mask = 0x1;
- __u16 result = 0x0;
-
- for (i=0; i < size; i++) {
- /* Add the current value to the bit field, shift mask */
- result |= mask;
- mask <<= 1;
- /* Finished ? */
- if (array[i] >= value)
- break;
- }
- /* Send back a valid index */
- if(i >= size)
- i = size - 1; /* Last item */
- *field = result;
- return i;
-}
-
-/*
- * Function value_highest_bit (value, array)
- *
- * Returns a bit field marking the highest possibility lower than value.
- */
-static inline int value_highest_bit(__u32 value, __u32 *array, int size, __u16 *field)
-{
- int i;
- __u16 mask = 0x1;
- __u16 result = 0x0;
-
- for (i=0; i < size; i++) {
- /* Finished ? */
- if (array[i] <= value)
- break;
- /* Shift mask */
- mask <<= 1;
- }
- /* Set the current value to the bit field */
- result |= mask;
- /* Send back a valid index */
- if(i >= size)
- i = size - 1; /* Last item */
- *field = result;
- return i;
-}
-
-/* -------------------------- MAIN CALLS -------------------------- */
-
-/*
- * Function irda_qos_compute_intersection (qos, new)
- *
- * Compute the intersection of the old QoS capabilities with new ones
- *
- */
-void irda_qos_compute_intersection(struct qos_info *qos, struct qos_info *new)
-{
- IRDA_ASSERT(qos != NULL, return;);
- IRDA_ASSERT(new != NULL, return;);
-
- /* Apply */
- qos->baud_rate.bits &= new->baud_rate.bits;
- qos->window_size.bits &= new->window_size.bits;
- qos->min_turn_time.bits &= new->min_turn_time.bits;
- qos->max_turn_time.bits &= new->max_turn_time.bits;
- qos->data_size.bits &= new->data_size.bits;
- qos->link_disc_time.bits &= new->link_disc_time.bits;
- qos->additional_bofs.bits &= new->additional_bofs.bits;
-
- irda_qos_bits_to_value(qos);
-}
-
-/*
- * Function irda_init_max_qos_capabilies (qos)
- *
- * The purpose of this function is for layers and drivers to be able to
- * set the maximum QoS possible and then "and in" their own limitations
- *
- */
-void irda_init_max_qos_capabilies(struct qos_info *qos)
-{
- int i;
- /*
- * These are the maximum supported values as specified on pages
- * 39-43 in IrLAP
- */
-
- /* Use sysctl to set some configurable values... */
- /* Set configured max speed */
- i = value_lower_bits(sysctl_max_baud_rate, baud_rates, 10,
- &qos->baud_rate.bits);
- sysctl_max_baud_rate = index_value(i, baud_rates);
-
- /* Set configured max disc time */
- i = value_lower_bits(sysctl_max_noreply_time, link_disc_times, 8,
- &qos->link_disc_time.bits);
- sysctl_max_noreply_time = index_value(i, link_disc_times);
-
- /* LSB is first byte, MSB is second byte */
- qos->baud_rate.bits &= 0x03ff;
-
- qos->window_size.bits = 0x7f;
- qos->min_turn_time.bits = 0xff;
- qos->max_turn_time.bits = 0x0f;
- qos->data_size.bits = 0x3f;
- qos->link_disc_time.bits &= 0xff;
- qos->additional_bofs.bits = 0xff;
-}
-EXPORT_SYMBOL(irda_init_max_qos_capabilies);
-
-/*
- * Function irlap_adjust_qos_settings (qos)
- *
- * Adjust QoS settings in case some values are not possible to use because
- * of other settings
- */
-static void irlap_adjust_qos_settings(struct qos_info *qos)
-{
- __u32 line_capacity;
- int index;
-
- /*
- * Make sure the mintt is sensible.
- * Main culprit : Ericsson T39. - Jean II
- */
- if (sysctl_min_tx_turn_time > qos->min_turn_time.value) {
- int i;
-
- net_warn_ratelimited("%s(), Detected buggy peer, adjust mtt to %dus!\n",
- __func__, sysctl_min_tx_turn_time);
-
- /* We don't really need bits, but easier this way */
- i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times,
- 8, &qos->min_turn_time.bits);
- sysctl_min_tx_turn_time = index_value(i, min_turn_times);
- qos->min_turn_time.value = sysctl_min_tx_turn_time;
- }
-
- /*
- * Not allowed to use a max turn time less than 500 ms if the baudrate
- * is less than 115200
- */
- if ((qos->baud_rate.value < 115200) &&
- (qos->max_turn_time.value < 500))
- {
- pr_debug("%s(), adjusting max turn time from %d to 500 ms\n",
- __func__, qos->max_turn_time.value);
- qos->max_turn_time.value = 500;
- }
-
- /*
- * The data size must be adjusted according to the baud rate and max
- * turn time
- */
- index = value_index(qos->data_size.value, data_sizes, 6);
- line_capacity = irlap_max_line_capacity(qos->baud_rate.value,
- qos->max_turn_time.value);
-
-#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
- while ((qos->data_size.value > line_capacity) && (index > 0)) {
- qos->data_size.value = data_sizes[index--];
- pr_debug("%s(), reducing data size to %d\n",
- __func__, qos->data_size.value);
- }
-#else /* Use method described in section 6.6.11 of IrLAP */
- while (irlap_requested_line_capacity(qos) > line_capacity) {
- IRDA_ASSERT(index != 0, return;);
-
- /* Must be able to send at least one frame */
- if (qos->window_size.value > 1) {
- qos->window_size.value--;
- pr_debug("%s(), reducing window size to %d\n",
- __func__, qos->window_size.value);
- } else if (index > 1) {
- qos->data_size.value = data_sizes[index--];
- pr_debug("%s(), reducing data size to %d\n",
- __func__, qos->data_size.value);
- } else {
- net_warn_ratelimited("%s(), nothing more we can do!\n",
- __func__);
- }
- }
-#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
- /*
- * Fix tx data size according to user limits - Jean II
- */
- if (qos->data_size.value > sysctl_max_tx_data_size)
- /* Allow non discrete adjustement to avoid losing capacity */
- qos->data_size.value = sysctl_max_tx_data_size;
- /*
- * Override Tx window if user request it. - Jean II
- */
- if (qos->window_size.value > sysctl_max_tx_window)
- qos->window_size.value = sysctl_max_tx_window;
-}
-
-/*
- * Function irlap_negotiate (qos_device, qos_session, skb)
- *
- * Negotiate QoS values, not really that much negotiation :-)
- * We just set the QoS capabilities for the peer station
- *
- */
-int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb)
-{
- int ret;
-
- ret = irda_param_extract_all(self, skb->data, skb->len,
- &irlap_param_info);
-
- /* Convert the negotiated bits to values */
- irda_qos_bits_to_value(&self->qos_tx);
- irda_qos_bits_to_value(&self->qos_rx);
-
- irlap_adjust_qos_settings(&self->qos_tx);
-
- pr_debug("Setting BAUD_RATE to %d bps.\n",
- self->qos_tx.baud_rate.value);
- pr_debug("Setting DATA_SIZE to %d bytes\n",
- self->qos_tx.data_size.value);
- pr_debug("Setting WINDOW_SIZE to %d\n",
- self->qos_tx.window_size.value);
- pr_debug("Setting XBOFS to %d\n",
- self->qos_tx.additional_bofs.value);
- pr_debug("Setting MAX_TURN_TIME to %d ms.\n",
- self->qos_tx.max_turn_time.value);
- pr_debug("Setting MIN_TURN_TIME to %d usecs.\n",
- self->qos_tx.min_turn_time.value);
- pr_debug("Setting LINK_DISC to %d secs.\n",
- self->qos_tx.link_disc_time.value);
- return ret;
-}
-
-/*
- * Function irlap_insert_negotiation_params (qos, fp)
- *
- * Insert QoS negotiaion pararameters into frame
- *
- */
-int irlap_insert_qos_negotiation_params(struct irlap_cb *self,
- struct sk_buff *skb)
-{
- int ret;
-
- /* Insert data rate */
- ret = irda_param_insert(self, PI_BAUD_RATE, skb_tail_pointer(skb),
- skb_tailroom(skb), &irlap_param_info);
- if (ret < 0)
- return ret;
- skb_put(skb, ret);
-
- /* Insert max turnaround time */
- ret = irda_param_insert(self, PI_MAX_TURN_TIME, skb_tail_pointer(skb),
- skb_tailroom(skb), &irlap_param_info);
- if (ret < 0)
- return ret;
- skb_put(skb, ret);
-
- /* Insert data size */
- ret = irda_param_insert(self, PI_DATA_SIZE, skb_tail_pointer(skb),
- skb_tailroom(skb), &irlap_param_info);
- if (ret < 0)
- return ret;
- skb_put(skb, ret);
-
- /* Insert window size */
- ret = irda_param_insert(self, PI_WINDOW_SIZE, skb_tail_pointer(skb),
- skb_tailroom(skb), &irlap_param_info);
- if (ret < 0)
- return ret;
- skb_put(skb, ret);
-
- /* Insert additional BOFs */
- ret = irda_param_insert(self, PI_ADD_BOFS, skb_tail_pointer(skb),
- skb_tailroom(skb), &irlap_param_info);
- if (ret < 0)
- return ret;
- skb_put(skb, ret);
-
- /* Insert minimum turnaround time */
- ret = irda_param_insert(self, PI_MIN_TURN_TIME, skb_tail_pointer(skb),
- skb_tailroom(skb), &irlap_param_info);
- if (ret < 0)
- return ret;
- skb_put(skb, ret);
-
- /* Insert link disconnect/threshold time */
- ret = irda_param_insert(self, PI_LINK_DISC, skb_tail_pointer(skb),
- skb_tailroom(skb), &irlap_param_info);
- if (ret < 0)
- return ret;
- skb_put(skb, ret);
-
- return 0;
-}
-
-/*
- * Function irlap_param_baud_rate (instance, param, get)
- *
- * Negotiate data-rate
- *
- */
-static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get)
-{
- __u16 final;
-
- struct irlap_cb *self = (struct irlap_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- if (get) {
- param->pv.i = self->qos_rx.baud_rate.bits;
- pr_debug("%s(), baud rate = 0x%02x\n",
- __func__, param->pv.i);
- } else {
- /*
- * Stations must agree on baud rate, so calculate
- * intersection
- */
- pr_debug("Requested BAUD_RATE: 0x%04x\n", (__u16)param->pv.i);
- final = (__u16) param->pv.i & self->qos_rx.baud_rate.bits;
-
- pr_debug("Final BAUD_RATE: 0x%04x\n", final);
- self->qos_tx.baud_rate.bits = final;
- self->qos_rx.baud_rate.bits = final;
- }
-
- return 0;
-}
-
-/*
- * Function irlap_param_link_disconnect (instance, param, get)
- *
- * Negotiate link disconnect/threshold time.
- *
- */
-static int irlap_param_link_disconnect(void *instance, irda_param_t *param,
- int get)
-{
- __u16 final;
-
- struct irlap_cb *self = (struct irlap_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- if (get)
- param->pv.i = self->qos_rx.link_disc_time.bits;
- else {
- /*
- * Stations must agree on link disconnect/threshold
- * time.
- */
- pr_debug("LINK_DISC: %02x\n", (__u8)param->pv.i);
- final = (__u8) param->pv.i & self->qos_rx.link_disc_time.bits;
-
- pr_debug("Final LINK_DISC: %02x\n", final);
- self->qos_tx.link_disc_time.bits = final;
- self->qos_rx.link_disc_time.bits = final;
- }
- return 0;
-}
-
-/*
- * Function irlap_param_max_turn_time (instance, param, get)
- *
- * Negotiate the maximum turnaround time. This is a type 1 parameter and
- * will be negotiated independently for each station
- *
- */
-static int irlap_param_max_turn_time(void *instance, irda_param_t *param,
- int get)
-{
- struct irlap_cb *self = (struct irlap_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- if (get)
- param->pv.i = self->qos_rx.max_turn_time.bits;
- else
- self->qos_tx.max_turn_time.bits = (__u8) param->pv.i;
-
- return 0;
-}
-
-/*
- * Function irlap_param_data_size (instance, param, get)
- *
- * Negotiate the data size. This is a type 1 parameter and
- * will be negotiated independently for each station
- *
- */
-static int irlap_param_data_size(void *instance, irda_param_t *param, int get)
-{
- struct irlap_cb *self = (struct irlap_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- if (get)
- param->pv.i = self->qos_rx.data_size.bits;
- else
- self->qos_tx.data_size.bits = (__u8) param->pv.i;
-
- return 0;
-}
-
-/*
- * Function irlap_param_window_size (instance, param, get)
- *
- * Negotiate the window size. This is a type 1 parameter and
- * will be negotiated independently for each station
- *
- */
-static int irlap_param_window_size(void *instance, irda_param_t *param,
- int get)
-{
- struct irlap_cb *self = (struct irlap_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- if (get)
- param->pv.i = self->qos_rx.window_size.bits;
- else
- self->qos_tx.window_size.bits = (__u8) param->pv.i;
-
- return 0;
-}
-
-/*
- * Function irlap_param_additional_bofs (instance, param, get)
- *
- * Negotiate additional BOF characters. This is a type 1 parameter and
- * will be negotiated independently for each station.
- */
-static int irlap_param_additional_bofs(void *instance, irda_param_t *param, int get)
-{
- struct irlap_cb *self = (struct irlap_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- if (get)
- param->pv.i = self->qos_rx.additional_bofs.bits;
- else
- self->qos_tx.additional_bofs.bits = (__u8) param->pv.i;
-
- return 0;
-}
-
-/*
- * Function irlap_param_min_turn_time (instance, param, get)
- *
- * Negotiate the minimum turn around time. This is a type 1 parameter and
- * will be negotiated independently for each station
- */
-static int irlap_param_min_turn_time(void *instance, irda_param_t *param,
- int get)
-{
- struct irlap_cb *self = (struct irlap_cb *) instance;
-
- IRDA_ASSERT(self != NULL, return -1;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
-
- if (get)
- param->pv.i = self->qos_rx.min_turn_time.bits;
- else
- self->qos_tx.min_turn_time.bits = (__u8) param->pv.i;
-
- return 0;
-}
-
-/*
- * Function irlap_max_line_capacity (speed, max_turn_time, min_turn_time)
- *
- * Calculate the maximum line capacity
- *
- */
-__u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time)
-{
- __u32 line_capacity;
- int i,j;
-
- pr_debug("%s(), speed=%d, max_turn_time=%d\n",
- __func__, speed, max_turn_time);
-
- i = value_index(speed, baud_rates, 10);
- j = value_index(max_turn_time, max_turn_times, 4);
-
- IRDA_ASSERT(((i >=0) && (i <10)), return 0;);
- IRDA_ASSERT(((j >=0) && (j <4)), return 0;);
-
- line_capacity = max_line_capacities[i][j];
-
- pr_debug("%s(), line capacity=%d bytes\n",
- __func__, line_capacity);
-
- return line_capacity;
-}
-
-#ifndef CONFIG_IRDA_DYNAMIC_WINDOW
-static __u32 irlap_requested_line_capacity(struct qos_info *qos)
-{
- __u32 line_capacity;
-
- line_capacity = qos->window_size.value *
- (qos->data_size.value + 6 + qos->additional_bofs.value) +
- irlap_min_turn_time_in_bytes(qos->baud_rate.value,
- qos->min_turn_time.value);
-
- pr_debug("%s(), requested line capacity=%d\n",
- __func__, line_capacity);
-
- return line_capacity;
-}
-#endif
-
-void irda_qos_bits_to_value(struct qos_info *qos)
-{
- int index;
-
- IRDA_ASSERT(qos != NULL, return;);
-
- index = msb_index(qos->baud_rate.bits);
- qos->baud_rate.value = baud_rates[index];
-
- index = msb_index(qos->data_size.bits);
- qos->data_size.value = data_sizes[index];
-
- index = msb_index(qos->window_size.bits);
- qos->window_size.value = index+1;
-
- index = msb_index(qos->min_turn_time.bits);
- qos->min_turn_time.value = min_turn_times[index];
-
- index = msb_index(qos->max_turn_time.bits);
- qos->max_turn_time.value = max_turn_times[index];
-
- index = msb_index(qos->link_disc_time.bits);
- qos->link_disc_time.value = link_disc_times[index];
-
- index = msb_index(qos->additional_bofs.bits);
- qos->additional_bofs.value = add_bofs[index];
-}
-EXPORT_SYMBOL(irda_qos_bits_to_value);
diff --git a/drivers/staging/irda/net/timer.c b/drivers/staging/irda/net/timer.c
deleted file mode 100644
index cf00c0d848aa..000000000000
--- a/drivers/staging/irda/net/timer.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*********************************************************************
- *
- * Filename: timer.c
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Sat Aug 16 00:59:29 1997
- * Modified at: Wed Dec 8 12:50:34 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/delay.h>
-
-#include <net/irda/timer.h>
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-#include <net/irda/irlap.h>
-#include <net/irda/irlmp.h>
-
-extern int sysctl_slot_timeout;
-
-static void irlap_slot_timer_expired(struct timer_list *t);
-static void irlap_query_timer_expired(struct timer_list *t);
-static void irlap_final_timer_expired(struct timer_list *t);
-static void irlap_wd_timer_expired(struct timer_list *t);
-static void irlap_backoff_timer_expired(struct timer_list *t);
-static void irlap_media_busy_expired(struct timer_list *t);
-
-void irlap_start_slot_timer(struct irlap_cb *self, int timeout)
-{
- irda_start_timer(&self->slot_timer, timeout,
- irlap_slot_timer_expired);
-}
-
-void irlap_start_query_timer(struct irlap_cb *self, int S, int s)
-{
- int timeout;
-
- /* Calculate when the peer discovery should end. Normally, we
- * get the end-of-discovery frame, so this is just in case
- * we miss it.
- * Basically, we multiply the number of remaining slots by our
- * slot time, plus add some extra time to properly receive the last
- * discovery packet (which is longer due to extra discovery info),
- * to avoid messing with for incoming connections requests and
- * to accommodate devices that perform discovery slower than us.
- * Jean II */
- timeout = msecs_to_jiffies(sysctl_slot_timeout) * (S - s)
- + XIDEXTRA_TIMEOUT + SMALLBUSY_TIMEOUT;
-
- /* Set or re-set the timer. We reset the timer for each received
- * discovery query, which allow us to automatically adjust to
- * the speed of the peer discovery (faster or slower). Jean II */
- irda_start_timer(&self->query_timer, timeout,
- irlap_query_timer_expired);
-}
-
-void irlap_start_final_timer(struct irlap_cb *self, int timeout)
-{
- irda_start_timer(&self->final_timer, timeout,
- irlap_final_timer_expired);
-}
-
-void irlap_start_wd_timer(struct irlap_cb *self, int timeout)
-{
- irda_start_timer(&self->wd_timer, timeout,
- irlap_wd_timer_expired);
-}
-
-void irlap_start_backoff_timer(struct irlap_cb *self, int timeout)
-{
- irda_start_timer(&self->backoff_timer, timeout,
- irlap_backoff_timer_expired);
-}
-
-void irlap_start_mbusy_timer(struct irlap_cb *self, int timeout)
-{
- irda_start_timer(&self->media_busy_timer, timeout,
- irlap_media_busy_expired);
-}
-
-void irlap_stop_mbusy_timer(struct irlap_cb *self)
-{
- /* If timer is activated, kill it! */
- del_timer(&self->media_busy_timer);
-
- /* If we are in NDM, there is a bunch of events in LAP that
- * that be pending due to the media_busy condition, such as
- * CONNECT_REQUEST and SEND_UI_FRAME. If we don't generate
- * an event, they will wait forever...
- * Jean II */
- if (self->state == LAP_NDM)
- irlap_do_event(self, MEDIA_BUSY_TIMER_EXPIRED, NULL, NULL);
-}
-
-void irlmp_start_watchdog_timer(struct lsap_cb *self, int timeout)
-{
- irda_start_timer(&self->watchdog_timer, timeout,
- irlmp_watchdog_timer_expired);
-}
-
-void irlmp_start_discovery_timer(struct irlmp_cb *self, int timeout)
-{
- irda_start_timer(&self->discovery_timer, timeout,
- irlmp_discovery_timer_expired);
-}
-
-void irlmp_start_idle_timer(struct lap_cb *self, int timeout)
-{
- irda_start_timer(&self->idle_timer, timeout,
- irlmp_idle_timer_expired);
-}
-
-void irlmp_stop_idle_timer(struct lap_cb *self)
-{
- /* If timer is activated, kill it! */
- del_timer(&self->idle_timer);
-}
-
-/*
- * Function irlap_slot_timer_expired (data)
- *
- * IrLAP slot timer has expired
- *
- */
-static void irlap_slot_timer_expired(struct timer_list *t)
-{
- struct irlap_cb *self = from_timer(self, t, slot_timer);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- irlap_do_event(self, SLOT_TIMER_EXPIRED, NULL, NULL);
-}
-
-/*
- * Function irlap_query_timer_expired (data)
- *
- * IrLAP query timer has expired
- *
- */
-static void irlap_query_timer_expired(struct timer_list *t)
-{
- struct irlap_cb *self = from_timer(self, t, query_timer);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- irlap_do_event(self, QUERY_TIMER_EXPIRED, NULL, NULL);
-}
-
-/*
- * Function irda_final_timer_expired (data)
- *
- *
- *
- */
-static void irlap_final_timer_expired(struct timer_list *t)
-{
- struct irlap_cb *self = from_timer(self, t, final_timer);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- irlap_do_event(self, FINAL_TIMER_EXPIRED, NULL, NULL);
-}
-
-/*
- * Function irda_wd_timer_expired (data)
- *
- *
- *
- */
-static void irlap_wd_timer_expired(struct timer_list *t)
-{
- struct irlap_cb *self = from_timer(self, t, wd_timer);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- irlap_do_event(self, WD_TIMER_EXPIRED, NULL, NULL);
-}
-
-/*
- * Function irda_backoff_timer_expired (data)
- *
- *
- *
- */
-static void irlap_backoff_timer_expired(struct timer_list *t)
-{
- struct irlap_cb *self = from_timer(self, t, backoff_timer);
-
- IRDA_ASSERT(self != NULL, return;);
- IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
-
- irlap_do_event(self, BACKOFF_TIMER_EXPIRED, NULL, NULL);
-}
-
-
-/*
- * Function irtty_media_busy_expired (data)
- *
- *
- */
-static void irlap_media_busy_expired(struct timer_list *t)
-{
- struct irlap_cb *self = from_timer(self, t, media_busy_timer);
-
- IRDA_ASSERT(self != NULL, return;);
-
- irda_device_set_media_busy(self->netdev, FALSE);
- /* Note : the LAP event will be send in irlap_stop_mbusy_timer(),
- * to catch other cases where the flag is cleared (for example
- * after a discovery) - Jean II */
-}
diff --git a/drivers/staging/irda/net/wrapper.c b/drivers/staging/irda/net/wrapper.c
deleted file mode 100644
index 40a0f993bf13..000000000000
--- a/drivers/staging/irda/net/wrapper.c
+++ /dev/null
@@ -1,492 +0,0 @@
-/*********************************************************************
- *
- * Filename: wrapper.c
- * Version: 1.2
- * Description: IrDA SIR async wrapper layer
- * Status: Stable
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Aug 4 20:40:53 1997
- * Modified at: Fri Jan 28 13:21:09 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- * Modified at: Fri May 28 3:11 CST 1999
- * Modified by: Horst von Brand <vonbrand@sleipnir.valparaiso.cl>
- *
- * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
- * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/skbuff.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include <asm/byteorder.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/crc.h>
-#include <net/irda/irlap.h>
-#include <net/irda/irlap_frame.h>
-#include <net/irda/irda_device.h>
-
-/************************** FRAME WRAPPING **************************/
-/*
- * Unwrap and unstuff SIR frames
- *
- * Note : at FIR and MIR, HDLC framing is used and usually handled
- * by the controller, so we come here only for SIR... Jean II
- */
-
-/*
- * Function stuff_byte (byte, buf)
- *
- * Byte stuff one single byte and put the result in buffer pointed to by
- * buf. The buffer must at all times be able to have two bytes inserted.
- *
- * This is in a tight loop, better inline it, so need to be prior to callers.
- * (2000 bytes on P6 200MHz, non-inlined ~370us, inline ~170us) - Jean II
- */
-static inline int stuff_byte(__u8 byte, __u8 *buf)
-{
- switch (byte) {
- case BOF: /* FALLTHROUGH */
- case EOF: /* FALLTHROUGH */
- case CE:
- /* Insert transparently coded */
- buf[0] = CE; /* Send link escape */
- buf[1] = byte^IRDA_TRANS; /* Complement bit 5 */
- return 2;
- /* break; */
- default:
- /* Non-special value, no transparency required */
- buf[0] = byte;
- return 1;
- /* break; */
- }
-}
-
-/*
- * Function async_wrap (skb, *tx_buff, buffsize)
- *
- * Makes a new buffer with wrapping and stuffing, should check that
- * we don't get tx buffer overflow.
- */
-int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize)
-{
- struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb;
- int xbofs;
- int i;
- int n;
- union {
- __u16 value;
- __u8 bytes[2];
- } fcs;
-
- /* Initialize variables */
- fcs.value = INIT_FCS;
- n = 0;
-
- /*
- * Send XBOF's for required min. turn time and for the negotiated
- * additional XBOFS
- */
-
- if (cb->magic != LAP_MAGIC) {
- /*
- * This will happen for all frames sent from user-space.
- * Nothing to worry about, but we set the default number of
- * BOF's
- */
- pr_debug("%s(), wrong magic in skb!\n", __func__);
- xbofs = 10;
- } else
- xbofs = cb->xbofs + cb->xbofs_delay;
-
- pr_debug("%s(), xbofs=%d\n", __func__, xbofs);
-
- /* Check that we never use more than 115 + 48 xbofs */
- if (xbofs > 163) {
- pr_debug("%s(), too many xbofs (%d)\n", __func__,
- xbofs);
- xbofs = 163;
- }
-
- memset(tx_buff + n, XBOF, xbofs);
- n += xbofs;
-
- /* Start of packet character BOF */
- tx_buff[n++] = BOF;
-
- /* Insert frame and calc CRC */
- for (i=0; i < skb->len; i++) {
- /*
- * Check for the possibility of tx buffer overflow. We use
- * bufsize-5 since the maximum number of bytes that can be
- * transmitted after this point is 5.
- */
- if(n >= (buffsize-5)) {
- net_err_ratelimited("%s(), tx buffer overflow (n=%d)\n",
- __func__, n);
- return n;
- }
-
- n += stuff_byte(skb->data[i], tx_buff+n);
- fcs.value = irda_fcs(fcs.value, skb->data[i]);
- }
-
- /* Insert CRC in little endian format (LSB first) */
- fcs.value = ~fcs.value;
-#ifdef __LITTLE_ENDIAN
- n += stuff_byte(fcs.bytes[0], tx_buff+n);
- n += stuff_byte(fcs.bytes[1], tx_buff+n);
-#else /* ifdef __BIG_ENDIAN */
- n += stuff_byte(fcs.bytes[1], tx_buff+n);
- n += stuff_byte(fcs.bytes[0], tx_buff+n);
-#endif
- tx_buff[n++] = EOF;
-
- return n;
-}
-EXPORT_SYMBOL(async_wrap_skb);
-
-/************************* FRAME UNWRAPPING *************************/
-/*
- * Unwrap and unstuff SIR frames
- *
- * Complete rewrite by Jean II :
- * More inline, faster, more compact, more logical. Jean II
- * (16 bytes on P6 200MHz, old 5 to 7 us, new 4 to 6 us)
- * (24 bytes on P6 200MHz, old 9 to 10 us, new 7 to 8 us)
- * (for reference, 115200 b/s is 1 byte every 69 us)
- * And reduce wrapper.o by ~900B in the process ;-)
- *
- * Then, we have the addition of ZeroCopy, which is optional
- * (i.e. the driver must initiate it) and improve final processing.
- * (2005 B frame + EOF on P6 200MHz, without 30 to 50 us, with 10 to 25 us)
- *
- * Note : at FIR and MIR, HDLC framing is used and usually handled
- * by the controller, so we come here only for SIR... Jean II
- */
-
-/*
- * We can also choose where we want to do the CRC calculation. We can
- * do it "inline", as we receive the bytes, or "postponed", when
- * receiving the End-Of-Frame.
- * (16 bytes on P6 200MHz, inlined 4 to 6 us, postponed 4 to 5 us)
- * (24 bytes on P6 200MHz, inlined 7 to 8 us, postponed 5 to 7 us)
- * With ZeroCopy :
- * (2005 B frame on P6 200MHz, inlined 10 to 25 us, postponed 140 to 180 us)
- * Without ZeroCopy :
- * (2005 B frame on P6 200MHz, inlined 30 to 50 us, postponed 150 to 180 us)
- * (Note : numbers taken with irq disabled)
- *
- * From those numbers, it's not clear which is the best strategy, because
- * we end up running through a lot of data one way or another (i.e. cache
- * misses). I personally prefer to avoid the huge latency spike of the
- * "postponed" solution, because it come just at the time when we have
- * lot's of protocol processing to do and it will hurt our ability to
- * reach low link turnaround times... Jean II
- */
-//#define POSTPONE_RX_CRC
-
-/*
- * Function async_bump (buf, len, stats)
- *
- * Got a frame, make a copy of it, and pass it up the stack! We can try
- * to inline it since it's only called from state_inside_frame
- */
-static inline void
-async_bump(struct net_device *dev,
- struct net_device_stats *stats,
- iobuff_t *rx_buff)
-{
- struct sk_buff *newskb;
- struct sk_buff *dataskb;
- int docopy;
-
- /* Check if we need to copy the data to a new skb or not.
- * If the driver doesn't use ZeroCopy Rx, we have to do it.
- * With ZeroCopy Rx, the rx_buff already point to a valid
- * skb. But, if the frame is small, it is more efficient to
- * copy it to save memory (copy will be fast anyway - that's
- * called Rx-copy-break). Jean II */
- docopy = ((rx_buff->skb == NULL) ||
- (rx_buff->len < IRDA_RX_COPY_THRESHOLD));
-
- /* Allocate a new skb */
- newskb = dev_alloc_skb(docopy ? rx_buff->len + 1 : rx_buff->truesize);
- if (!newskb) {
- stats->rx_dropped++;
- /* We could deliver the current skb if doing ZeroCopy Rx,
- * but this would stall the Rx path. Better drop the
- * packet... Jean II */
- return;
- }
-
- /* Align IP header to 20 bytes (i.e. increase skb->data)
- * Note this is only useful with IrLAN, as PPP has a variable
- * header size (2 or 1 bytes) - Jean II */
- skb_reserve(newskb, 1);
-
- if(docopy) {
- /* Copy data without CRC (length already checked) */
- skb_copy_to_linear_data(newskb, rx_buff->data,
- rx_buff->len - 2);
- /* Deliver this skb */
- dataskb = newskb;
- } else {
- /* We are using ZeroCopy. Deliver old skb */
- dataskb = rx_buff->skb;
- /* And hook the new skb to the rx_buff */
- rx_buff->skb = newskb;
- rx_buff->head = newskb->data; /* NOT newskb->head */
- //printk(KERN_DEBUG "ZeroCopy : len = %d, dataskb = %p, newskb = %p\n", rx_buff->len, dataskb, newskb);
- }
-
- /* Set proper length on skb (without CRC) */
- skb_put(dataskb, rx_buff->len - 2);
-
- /* Feed it to IrLAP layer */
- dataskb->dev = dev;
- skb_reset_mac_header(dataskb);
- dataskb->protocol = htons(ETH_P_IRDA);
-
- netif_rx(dataskb);
-
- stats->rx_packets++;
- stats->rx_bytes += rx_buff->len;
-
- /* Clean up rx_buff (redundant with async_unwrap_bof() ???) */
- rx_buff->data = rx_buff->head;
- rx_buff->len = 0;
-}
-
-/*
- * Function async_unwrap_bof(dev, byte)
- *
- * Handle Beginning Of Frame character received within a frame
- *
- */
-static inline void
-async_unwrap_bof(struct net_device *dev,
- struct net_device_stats *stats,
- iobuff_t *rx_buff, __u8 byte)
-{
- switch(rx_buff->state) {
- case LINK_ESCAPE:
- case INSIDE_FRAME:
- /* Not supposed to happen, the previous frame is not
- * finished - Jean II */
- pr_debug("%s(), Discarding incomplete frame\n",
- __func__);
- stats->rx_errors++;
- stats->rx_missed_errors++;
- irda_device_set_media_busy(dev, TRUE);
- break;
-
- case OUTSIDE_FRAME:
- case BEGIN_FRAME:
- default:
- /* We may receive multiple BOF at the start of frame */
- break;
- }
-
- /* Now receiving frame */
- rx_buff->state = BEGIN_FRAME;
- rx_buff->in_frame = TRUE;
-
- /* Time to initialize receive buffer */
- rx_buff->data = rx_buff->head;
- rx_buff->len = 0;
- rx_buff->fcs = INIT_FCS;
-}
-
-/*
- * Function async_unwrap_eof(dev, byte)
- *
- * Handle End Of Frame character received within a frame
- *
- */
-static inline void
-async_unwrap_eof(struct net_device *dev,
- struct net_device_stats *stats,
- iobuff_t *rx_buff, __u8 byte)
-{
-#ifdef POSTPONE_RX_CRC
- int i;
-#endif
-
- switch(rx_buff->state) {
- case OUTSIDE_FRAME:
- /* Probably missed the BOF */
- stats->rx_errors++;
- stats->rx_missed_errors++;
- irda_device_set_media_busy(dev, TRUE);
- break;
-
- case BEGIN_FRAME:
- case LINK_ESCAPE:
- case INSIDE_FRAME:
- default:
- /* Note : in the case of BEGIN_FRAME and LINK_ESCAPE,
- * the fcs will most likely not match and generate an
- * error, as expected - Jean II */
- rx_buff->state = OUTSIDE_FRAME;
- rx_buff->in_frame = FALSE;
-
-#ifdef POSTPONE_RX_CRC
- /* If we haven't done the CRC as we receive bytes, we
- * must do it now... Jean II */
- for(i = 0; i < rx_buff->len; i++)
- rx_buff->fcs = irda_fcs(rx_buff->fcs,
- rx_buff->data[i]);
-#endif
-
- /* Test FCS and signal success if the frame is good */
- if (rx_buff->fcs == GOOD_FCS) {
- /* Deliver frame */
- async_bump(dev, stats, rx_buff);
- break;
- } else {
- /* Wrong CRC, discard frame! */
- irda_device_set_media_busy(dev, TRUE);
-
- pr_debug("%s(), crc error\n", __func__);
- stats->rx_errors++;
- stats->rx_crc_errors++;
- }
- break;
- }
-}
-
-/*
- * Function async_unwrap_ce(dev, byte)
- *
- * Handle Character Escape character received within a frame
- *
- */
-static inline void
-async_unwrap_ce(struct net_device *dev,
- struct net_device_stats *stats,
- iobuff_t *rx_buff, __u8 byte)
-{
- switch(rx_buff->state) {
- case OUTSIDE_FRAME:
- /* Activate carrier sense */
- irda_device_set_media_busy(dev, TRUE);
- break;
-
- case LINK_ESCAPE:
- net_warn_ratelimited("%s: state not defined\n", __func__);
- break;
-
- case BEGIN_FRAME:
- case INSIDE_FRAME:
- default:
- /* Stuffed byte coming */
- rx_buff->state = LINK_ESCAPE;
- break;
- }
-}
-
-/*
- * Function async_unwrap_other(dev, byte)
- *
- * Handle other characters received within a frame
- *
- */
-static inline void
-async_unwrap_other(struct net_device *dev,
- struct net_device_stats *stats,
- iobuff_t *rx_buff, __u8 byte)
-{
- switch(rx_buff->state) {
- /* This is on the critical path, case are ordered by
- * probability (most frequent first) - Jean II */
- case INSIDE_FRAME:
- /* Must be the next byte of the frame */
- if (rx_buff->len < rx_buff->truesize) {
- rx_buff->data[rx_buff->len++] = byte;
-#ifndef POSTPONE_RX_CRC
- rx_buff->fcs = irda_fcs(rx_buff->fcs, byte);
-#endif
- } else {
- pr_debug("%s(), Rx buffer overflow, aborting\n",
- __func__);
- rx_buff->state = OUTSIDE_FRAME;
- }
- break;
-
- case LINK_ESCAPE:
- /*
- * Stuffed char, complement bit 5 of byte
- * following CE, IrLAP p.114
- */
- byte ^= IRDA_TRANS;
- if (rx_buff->len < rx_buff->truesize) {
- rx_buff->data[rx_buff->len++] = byte;
-#ifndef POSTPONE_RX_CRC
- rx_buff->fcs = irda_fcs(rx_buff->fcs, byte);
-#endif
- rx_buff->state = INSIDE_FRAME;
- } else {
- pr_debug("%s(), Rx buffer overflow, aborting\n",
- __func__);
- rx_buff->state = OUTSIDE_FRAME;
- }
- break;
-
- case OUTSIDE_FRAME:
- /* Activate carrier sense */
- if(byte != XBOF)
- irda_device_set_media_busy(dev, TRUE);
- break;
-
- case BEGIN_FRAME:
- default:
- rx_buff->data[rx_buff->len++] = byte;
-#ifndef POSTPONE_RX_CRC
- rx_buff->fcs = irda_fcs(rx_buff->fcs, byte);
-#endif
- rx_buff->state = INSIDE_FRAME;
- break;
- }
-}
-
-/*
- * Function async_unwrap_char (dev, rx_buff, byte)
- *
- * Parse and de-stuff frame received from the IrDA-port
- *
- * This is the main entry point for SIR drivers.
- */
-void async_unwrap_char(struct net_device *dev,
- struct net_device_stats *stats,
- iobuff_t *rx_buff, __u8 byte)
-{
- switch(byte) {
- case CE:
- async_unwrap_ce(dev, stats, rx_buff, byte);
- break;
- case BOF:
- async_unwrap_bof(dev, stats, rx_buff, byte);
- break;
- case EOF:
- async_unwrap_eof(dev, stats, rx_buff, byte);
- break;
- default:
- async_unwrap_other(dev, stats, rx_buff, byte);
- break;
- }
-}
-EXPORT_SYMBOL(async_unwrap_char);
-
diff --git a/drivers/staging/ks7010/Makefile b/drivers/staging/ks7010/Makefile
index 69fcf8d655c7..07dc16cc86f5 100644
--- a/drivers/staging/ks7010/Makefile
+++ b/drivers/staging/ks7010/Makefile
@@ -1,4 +1,3 @@
obj-$(CONFIG_KS7010) += ks7010.o
-ccflags-y += -DKS_WLAN_DEBUG=0
ks7010-y := michael_mic.o ks_hostif.o ks_wlan_net.o ks7010_sdio.o
diff --git a/drivers/staging/ks7010/eap_packet.h b/drivers/staging/ks7010/eap_packet.h
index dca2a142e834..58c2a3dafca2 100644
--- a/drivers/staging/ks7010/eap_packet.h
+++ b/drivers/staging/ks7010/eap_packet.h
@@ -3,12 +3,8 @@
#define EAP_PACKET_H
#include <linux/compiler.h>
-
-#define WBIT(n) (1 << (n))
-
-#ifndef ETH_ALEN
-#define ETH_ALEN 6
-#endif
+#include <linux/bitops.h>
+#include <uapi/linux/if_ether.h>
#define ETHER_HDR_SIZE 20
@@ -20,9 +16,6 @@ struct ether_hdr {
unsigned char h_command;
unsigned char h_vendor_id[3];
__be16 h_proto; /* packet type ID field */
-#define ETHER_PROTOCOL_TYPE_EAP 0x888e
-#define ETHER_PROTOCOL_TYPE_IP 0x0800
-#define ETHER_PROTOCOL_TYPE_ARP 0x0806
/* followed by length octets of data */
} __packed;
@@ -104,23 +97,23 @@ struct wpa_eapol_key {
/* followed by key_data_length bytes of key_data */
} __packed;
-#define WPA_KEY_INFO_TYPE_MASK (WBIT(0) | WBIT(1) | WBIT(2))
-#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 WBIT(0)
-#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES WBIT(1)
-#define WPA_KEY_INFO_KEY_TYPE WBIT(3) /* 1 = Pairwise, 0 = Group key */
+#define WPA_KEY_INFO_TYPE_MASK GENMASK(2, 0)
+#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0)
+#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)
+#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */
/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */
-#define WPA_KEY_INFO_KEY_INDEX_MASK (WBIT(4) | WBIT(5))
+#define WPA_KEY_INFO_KEY_INDEX_MASK GENMASK(5, 4)
#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4
-#define WPA_KEY_INFO_INSTALL WBIT(6) /* pairwise */
-#define WPA_KEY_INFO_TXRX WBIT(6) /* group */
-#define WPA_KEY_INFO_ACK WBIT(7)
-#define WPA_KEY_INFO_MIC WBIT(8)
-#define WPA_KEY_INFO_SECURE WBIT(9)
-#define WPA_KEY_INFO_ERROR WBIT(10)
-#define WPA_KEY_INFO_REQUEST WBIT(11)
-#define WPA_KEY_INFO_ENCR_KEY_DATA WBIT(12) /* IEEE 802.11i/RSN only */
-
-#define WPA_CAPABILITY_PREAUTH WBIT(0)
+#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */
+#define WPA_KEY_INFO_TXRX BIT(6) /* group */
+#define WPA_KEY_INFO_ACK BIT(7)
+#define WPA_KEY_INFO_MIC BIT(8)
+#define WPA_KEY_INFO_SECURE BIT(9)
+#define WPA_KEY_INFO_ERROR BIT(10)
+#define WPA_KEY_INFO_REQUEST BIT(11)
+#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */
+
+#define WPA_CAPABILITY_PREAUTH BIT(0)
#define GENERIC_INFO_ELEM 0xdd
#define RSN_INFO_ELEM 0x30
diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c
index 8cfdff198334..b8f55a11ee1c 100644
--- a/drivers/staging/ks7010/ks7010_sdio.c
+++ b/drivers/staging/ks7010/ks7010_sdio.c
@@ -32,19 +32,39 @@ static const struct sdio_device_id ks7010_sdio_ids[] = {
};
MODULE_DEVICE_TABLE(sdio, ks7010_sdio_ids);
-#define inc_txqhead(priv) \
- (priv->tx_dev.qhead = (priv->tx_dev.qhead + 1) % TX_DEVICE_BUFF_SIZE)
-#define inc_txqtail(priv) \
- (priv->tx_dev.qtail = (priv->tx_dev.qtail + 1) % TX_DEVICE_BUFF_SIZE)
-#define cnt_txqbody(priv) \
- (((priv->tx_dev.qtail + TX_DEVICE_BUFF_SIZE) - (priv->tx_dev.qhead)) % TX_DEVICE_BUFF_SIZE)
-
-#define inc_rxqhead(priv) \
- (priv->rx_dev.qhead = (priv->rx_dev.qhead + 1) % RX_DEVICE_BUFF_SIZE)
-#define inc_rxqtail(priv) \
- (priv->rx_dev.qtail = (priv->rx_dev.qtail + 1) % RX_DEVICE_BUFF_SIZE)
-#define cnt_rxqbody(priv) \
- (((priv->rx_dev.qtail + RX_DEVICE_BUFF_SIZE) - (priv->rx_dev.qhead)) % RX_DEVICE_BUFF_SIZE)
+static inline void inc_txqhead(struct ks_wlan_private *priv)
+{
+ priv->tx_dev.qhead = (priv->tx_dev.qhead + 1) % TX_DEVICE_BUFF_SIZE;
+}
+
+static inline void inc_txqtail(struct ks_wlan_private *priv)
+{
+ priv->tx_dev.qtail = (priv->tx_dev.qtail + 1) % TX_DEVICE_BUFF_SIZE;
+}
+
+static inline unsigned int cnt_txqbody(struct ks_wlan_private *priv)
+{
+ unsigned int tx_cnt = priv->tx_dev.qtail - priv->tx_dev.qhead;
+
+ return (tx_cnt + TX_DEVICE_BUFF_SIZE) % TX_DEVICE_BUFF_SIZE;
+}
+
+static inline void inc_rxqhead(struct ks_wlan_private *priv)
+{
+ priv->rx_dev.qhead = (priv->rx_dev.qhead + 1) % RX_DEVICE_BUFF_SIZE;
+}
+
+static inline void inc_rxqtail(struct ks_wlan_private *priv)
+{
+ priv->rx_dev.qtail = (priv->rx_dev.qtail + 1) % RX_DEVICE_BUFF_SIZE;
+}
+
+static inline unsigned int cnt_rxqbody(struct ks_wlan_private *priv)
+{
+ unsigned int rx_cnt = priv->rx_dev.qtail - priv->rx_dev.qhead;
+
+ return (rx_cnt + RX_DEVICE_BUFF_SIZE) % RX_DEVICE_BUFF_SIZE;
+}
/* Read single byte from device address into byte (CMD52) */
static int ks7010_sdio_readb(struct ks_wlan_private *priv, unsigned int address,
@@ -92,22 +112,17 @@ static void ks_wlan_hw_sleep_doze_request(struct ks_wlan_private *priv)
{
int ret;
- DPRINTK(4, "\n");
-
/* clear request */
atomic_set(&priv->sleepstatus.doze_request, 0);
if (atomic_read(&priv->sleepstatus.status) == 0) {
ret = ks7010_sdio_writeb(priv, GCR_B, GCR_B_DOZE);
if (ret) {
- DPRINTK(1, " error : GCR_B\n");
+ netdev_err(priv->net_dev, " error : GCR_B\n");
goto set_sleep_mode;
}
- DPRINTK(3, "sleep_mode=SLP_SLEEP\n");
atomic_set(&priv->sleepstatus.status, 1);
priv->last_doze = jiffies;
- } else {
- DPRINTK(1, "sleep_mode=%d\n", priv->sleep_mode);
}
set_sleep_mode:
@@ -118,23 +133,18 @@ static void ks_wlan_hw_sleep_wakeup_request(struct ks_wlan_private *priv)
{
int ret;
- DPRINTK(4, "\n");
-
/* clear request */
atomic_set(&priv->sleepstatus.wakeup_request, 0);
if (atomic_read(&priv->sleepstatus.status) == 1) {
ret = ks7010_sdio_writeb(priv, WAKEUP, WAKEUP_REQ);
if (ret) {
- DPRINTK(1, " error : WAKEUP\n");
+ netdev_err(priv->net_dev, " error : WAKEUP\n");
goto set_sleep_mode;
}
- DPRINTK(4, "wake up : WAKEUP\n");
atomic_set(&priv->sleepstatus.status, 0);
priv->last_wakeup = jiffies;
++priv->wakeup_count;
- } else {
- DPRINTK(1, "sleep_mode=%d\n", priv->sleep_mode);
}
set_sleep_mode:
@@ -145,19 +155,13 @@ void ks_wlan_hw_wakeup_request(struct ks_wlan_private *priv)
{
int ret;
- DPRINTK(4, "\n");
if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
ret = ks7010_sdio_writeb(priv, WAKEUP, WAKEUP_REQ);
if (ret)
- DPRINTK(1, " error : WAKEUP\n");
- else
- DPRINTK(4, "wake up : WAKEUP\n");
+ netdev_err(priv->net_dev, " error : WAKEUP\n");
priv->last_wakeup = jiffies;
++priv->wakeup_count;
- } else {
- DPRINTK(1, "psstatus=%d\n",
- atomic_read(&priv->psstatus.status));
}
}
@@ -181,11 +185,11 @@ static void _ks_wlan_hw_power_save(struct ks_wlan_private *priv)
if (atomic_read(&priv->psstatus.status) == PS_SNOOZE)
return;
- DPRINTK(5, "\npsstatus.status=%d\npsstatus.confirm_wait=%d\npsstatus.snooze_guard=%d\ncnt_txqbody=%d\n",
- atomic_read(&priv->psstatus.status),
- atomic_read(&priv->psstatus.confirm_wait),
- atomic_read(&priv->psstatus.snooze_guard),
- cnt_txqbody(priv));
+ netdev_dbg(priv->net_dev, "\npsstatus.status=%d\npsstatus.confirm_wait=%d\npsstatus.snooze_guard=%d\ncnt_txqbody=%d\n",
+ atomic_read(&priv->psstatus.status),
+ atomic_read(&priv->psstatus.confirm_wait),
+ atomic_read(&priv->psstatus.snooze_guard),
+ cnt_txqbody(priv));
if (atomic_read(&priv->psstatus.confirm_wait) ||
atomic_read(&priv->psstatus.snooze_guard) ||
@@ -196,7 +200,7 @@ static void _ks_wlan_hw_power_save(struct ks_wlan_private *priv)
ret = ks7010_sdio_readb(priv, INT_PENDING, &byte);
if (ret) {
- DPRINTK(1, " error : INT_PENDING\n");
+ netdev_err(priv->net_dev, " error : INT_PENDING\n");
goto queue_delayed_work;
}
if (byte)
@@ -204,11 +208,10 @@ static void _ks_wlan_hw_power_save(struct ks_wlan_private *priv)
ret = ks7010_sdio_writeb(priv, GCR_B, GCR_B_DOZE);
if (ret) {
- DPRINTK(1, " error : GCR_B\n");
+ netdev_err(priv->net_dev, " error : GCR_B\n");
goto queue_delayed_work;
}
atomic_set(&priv->psstatus.status, PS_SNOOZE);
- DPRINTK(3, "psstatus.status=PS_SNOOZE\n");
return;
@@ -237,7 +240,7 @@ static int enqueue_txdev(struct ks_wlan_private *priv, unsigned char *p,
}
if ((TX_DEVICE_BUFF_SIZE - 1) <= cnt_txqbody(priv)) {
- DPRINTK(1, "tx buffer overflow\n");
+ netdev_err(priv->net_dev, "tx buffer overflow\n");
ret = -EOVERFLOW;
goto err_complete;
}
@@ -268,22 +271,21 @@ static int write_to_device(struct ks_wlan_private *priv, unsigned char *buffer,
hdr = (struct hostif_hdr *)buffer;
- DPRINTK(4, "size=%d\n", hdr->size);
if (le16_to_cpu(hdr->event) < HIF_DATA_REQ ||
le16_to_cpu(hdr->event) > HIF_REQ_MAX) {
- DPRINTK(1, "unknown event=%04X\n", hdr->event);
+ netdev_err(priv->net_dev, "unknown event=%04X\n", hdr->event);
return 0;
}
ret = ks7010_sdio_write(priv, DATA_WINDOW, buffer, size);
if (ret) {
- DPRINTK(1, " write error : retval=%d\n", ret);
+ netdev_err(priv->net_dev, " write error : retval=%d\n", ret);
return ret;
}
ret = ks7010_sdio_writeb(priv, WRITE_STATUS, REG_STATUS_BUSY);
if (ret) {
- DPRINTK(1, " error : WRITE_STATUS\n");
+ netdev_err(priv->net_dev, " error : WRITE_STATUS\n");
return ret;
}
@@ -295,7 +297,6 @@ static void tx_device_task(struct ks_wlan_private *priv)
struct tx_device_buffer *sp;
int ret;
- DPRINTK(4, "\n");
if (cnt_txqbody(priv) <= 0 ||
atomic_read(&priv->psstatus.status) == PS_SNOOZE)
return;
@@ -304,7 +305,7 @@ static void tx_device_task(struct ks_wlan_private *priv)
if (priv->dev_state >= DEVICE_STATE_BOOT) {
ret = write_to_device(priv, sp->sendp, sp->size);
if (ret) {
- DPRINTK(1, "write_to_device error !!(%d)\n", ret);
+ netdev_err(priv->net_dev, "write_to_device error !!(%d)\n", ret);
queue_delayed_work(priv->wq, &priv->rw_dwork, 1);
return;
}
@@ -330,7 +331,7 @@ int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, unsigned long size,
if (le16_to_cpu(hdr->event) < HIF_DATA_REQ ||
le16_to_cpu(hdr->event) > HIF_REQ_MAX) {
- DPRINTK(1, "unknown event=%04X\n", hdr->event);
+ netdev_err(priv->net_dev, "unknown event=%04X\n", hdr->event);
return 0;
}
@@ -338,7 +339,6 @@ int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, unsigned long size,
priv->hostt.buff[priv->hostt.qtail] = le16_to_cpu(hdr->event);
priv->hostt.qtail = (priv->hostt.qtail + 1) % SME_EVENT_BUFF_SIZE;
- DPRINTK(4, "event=%04X\n", hdr->event);
spin_lock(&priv->tx_dev.tx_dev_lock);
result = enqueue_txdev(priv, p, size, complete_handler, skb);
spin_unlock(&priv->tx_dev.tx_dev_lock);
@@ -354,8 +354,6 @@ static void rx_event_task(unsigned long dev)
struct ks_wlan_private *priv = (struct ks_wlan_private *)dev;
struct rx_device_buffer *rp;
- DPRINTK(4, "\n");
-
if (cnt_rxqbody(priv) > 0 && priv->dev_state >= DEVICE_STATE_BOOT) {
rp = &priv->rx_dev.rx_dev_buff[priv->rx_dev.qhead];
hostif_receive(priv, rp->data, rp->size);
@@ -373,11 +371,9 @@ static void ks_wlan_hw_rx(struct ks_wlan_private *priv, uint16_t size)
struct hostif_hdr *hdr;
unsigned short event = 0;
- DPRINTK(4, "\n");
-
/* receive data */
if (cnt_rxqbody(priv) >= (RX_DEVICE_BUFF_SIZE - 1)) {
- DPRINTK(1, "rx buffer overflow\n");
+ netdev_err(priv->net_dev, "rx buffer overflow\n");
return;
}
rx_buffer = &priv->rx_dev.rx_dev_buff[priv->rx_dev.qtail];
@@ -389,15 +385,14 @@ static void ks_wlan_hw_rx(struct ks_wlan_private *priv, uint16_t size)
/* length check */
if (size > 2046 || size == 0) {
-#ifdef KS_WLAN_DEBUG
- if (KS_WLAN_DEBUG > 5)
- print_hex_dump_bytes("INVALID DATA dump: ",
- DUMP_PREFIX_OFFSET,
- rx_buffer->data, 32);
+#ifdef DEBUG
+ print_hex_dump_bytes("INVALID DATA dump: ",
+ DUMP_PREFIX_OFFSET,
+ rx_buffer->data, 32);
#endif
ret = ks7010_sdio_writeb(priv, READ_STATUS, REG_STATUS_IDLE);
if (ret)
- DPRINTK(1, " error : READ_STATUS\n");
+ netdev_err(priv->net_dev, " error : READ_STATUS\n");
/* length check fail */
return;
@@ -410,11 +405,11 @@ static void ks_wlan_hw_rx(struct ks_wlan_private *priv, uint16_t size)
ret = ks7010_sdio_writeb(priv, READ_STATUS, REG_STATUS_IDLE);
if (ret)
- DPRINTK(1, " error : READ_STATUS\n");
+ netdev_err(priv->net_dev, " error : READ_STATUS\n");
if (atomic_read(&priv->psstatus.confirm_wait)) {
if (IS_HIF_CONF(event)) {
- DPRINTK(4, "IS_HIF_CONF true !!\n");
+ netdev_dbg(priv->net_dev, "IS_HIF_CONF true !!\n");
atomic_dec(&priv->psstatus.confirm_wait);
}
}
@@ -430,18 +425,16 @@ static void ks7010_rw_function(struct work_struct *work)
priv = container_of(work, struct ks_wlan_private, rw_dwork.work);
- DPRINTK(4, "\n");
-
/* wait after DOZE */
if (time_after(priv->last_doze + ((30 * HZ) / 1000), jiffies)) {
- DPRINTK(4, "wait after DOZE\n");
+ netdev_dbg(priv->net_dev, "wait after DOZE\n");
queue_delayed_work(priv->wq, &priv->rw_dwork, 1);
return;
}
/* wait after WAKEUP */
while (time_after(priv->last_wakeup + ((30 * HZ) / 1000), jiffies)) {
- DPRINTK(4, "wait after WAKEUP\n");
+ netdev_dbg(priv->net_dev, "wait after WAKEUP\n");
dev_info(&priv->ks_sdio_card->func->dev,
"wake: %lu %lu\n",
priv->last_wakeup + (30 * HZ) / 1000,
@@ -474,11 +467,10 @@ static void ks7010_rw_function(struct work_struct *work)
/* read (WriteStatus/ReadDataSize FN1:00_0014) */
ret = ks7010_sdio_readb(priv, WSTATUS_RSIZE, &byte);
if (ret) {
- DPRINTK(1, " error : WSTATUS_RSIZE psstatus=%d\n",
- atomic_read(&priv->psstatus.status));
+ netdev_err(priv->net_dev, " error : WSTATUS_RSIZE psstatus=%d\n",
+ atomic_read(&priv->psstatus.status));
goto release_host;
}
- DPRINTK(4, "WSTATUS_RSIZE=%02X\n", byte);
if (byte & RSIZE_MASK) { /* Read schedule */
ks_wlan_hw_rx(priv, (uint16_t)((byte & RSIZE_MASK) << 4));
@@ -501,17 +493,15 @@ static void ks_sdio_interrupt(struct sdio_func *func)
card = sdio_get_drvdata(func);
priv = card->priv;
- DPRINTK(4, "\n");
if (priv->dev_state < DEVICE_STATE_BOOT)
goto queue_delayed_work;
ret = ks7010_sdio_readb(priv, INT_PENDING, &status);
if (ret) {
- DPRINTK(1, "error : INT_PENDING\n");
+ netdev_err(priv->net_dev, "error : INT_PENDING\n");
goto queue_delayed_work;
}
- DPRINTK(4, "INT_PENDING=%02X\n", status);
/* schedule task for interrupt status */
/* bit7 -> Write General Communication B register */
@@ -522,7 +512,7 @@ static void ks_sdio_interrupt(struct sdio_func *func)
atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
ret = ks7010_sdio_readb(priv, GCR_B, &byte);
if (ret) {
- DPRINTK(1, " error : GCR_B\n");
+ netdev_err(priv->net_dev, " error : GCR_B\n");
goto queue_delayed_work;
}
if (byte == GCR_B_ACTIVE) {
@@ -538,10 +528,9 @@ static void ks_sdio_interrupt(struct sdio_func *func)
/* read (WriteStatus/ReadDataSize FN1:00_0014) */
ret = ks7010_sdio_readb(priv, WSTATUS_RSIZE, &byte);
if (ret) {
- DPRINTK(1, " error : WSTATUS_RSIZE\n");
+ netdev_err(priv->net_dev, " error : WSTATUS_RSIZE\n");
goto queue_delayed_work;
}
- DPRINTK(4, "WSTATUS_RSIZE=%02X\n", byte);
rsize = byte & RSIZE_MASK;
if (rsize != 0) /* Read schedule */
ks_wlan_hw_rx(priv, (uint16_t)(rsize << 4));
@@ -638,7 +627,7 @@ static int ks7010_sdio_data_compare(struct ks_wlan_private *priv, u32 address,
if (memcmp(data, read_buf, size) != 0) {
ret = -EIO;
- DPRINTK(0, "data compare error (%d)\n", ret);
+ netdev_err(priv->net_dev, "data compare error (%d)\n", ret);
goto err_free_read_buf;
}
@@ -669,7 +658,7 @@ static int ks7010_upload_firmware(struct ks_sdio_card *card)
/* Firmware running ? */
ret = ks7010_sdio_readb(priv, GCR_A, &byte);
if (byte == GCR_A_RUN) {
- DPRINTK(0, "MAC firmware running ...\n");
+ netdev_dbg(priv->net_dev, "MAC firmware running ...\n");
goto release_host_and_free;
}
@@ -689,7 +678,6 @@ static int ks7010_upload_firmware(struct ks_sdio_card *card)
size = length;
length = 0;
}
- DPRINTK(4, "size = %d\n", size);
if (size == 0)
break;
memcpy(rom_buf, fw_entry->data + n, size);
@@ -715,8 +703,6 @@ static int ks7010_upload_firmware(struct ks_sdio_card *card)
if (ret)
goto release_firmware;
- DPRINTK(4, " REMAP Request : GCR_A\n");
-
/* Firmware running check */
for (n = 0; n < 50; ++n) {
mdelay(10); /* wait_ms(10); */
@@ -727,9 +713,8 @@ static int ks7010_upload_firmware(struct ks_sdio_card *card)
if (byte == GCR_A_RUN)
break;
}
- DPRINTK(4, "firmware wakeup (%d)!!!!\n", n);
if ((50) <= n) {
- DPRINTK(1, "firmware can't start\n");
+ netdev_err(priv->net_dev, "firmware can't start\n");
ret = -EIO;
goto release_firmware;
}
@@ -747,20 +732,14 @@ static int ks7010_upload_firmware(struct ks_sdio_card *card)
static void ks7010_card_init(struct ks_wlan_private *priv)
{
- DPRINTK(5, "\ncard_init_task()\n");
-
init_completion(&priv->confirm_wait);
- DPRINTK(5, "init_completion()\n");
-
/* get mac address & firmware version */
hostif_sme_enqueue(priv, SME_START);
- DPRINTK(5, "hostif_sme_enqueu()\n");
-
if (!wait_for_completion_interruptible_timeout
(&priv->confirm_wait, 5 * HZ)) {
- DPRINTK(1, "wait time out!! SME_START\n");
+ netdev_dbg(priv->net_dev, "wait time out!! SME_START\n");
}
if (priv->mac_address_valid && priv->version_size != 0)
@@ -787,14 +766,12 @@ static void ks7010_card_init(struct ks_wlan_private *priv)
if (!wait_for_completion_interruptible_timeout
(&priv->confirm_wait, 5 * HZ)) {
- DPRINTK(1, "wait time out!! wireless parameter set\n");
+ netdev_dbg(priv->net_dev, "wait time out!! wireless parameter set\n");
}
if (priv->dev_state >= DEVICE_STATE_PREINIT) {
- DPRINTK(1, "DEVICE READY!!\n");
+ netdev_dbg(priv->net_dev, "DEVICE READY!!\n");
priv->dev_state = DEVICE_STATE_READY;
- } else {
- DPRINTK(1, "dev_state=%d\n", priv->dev_state);
}
}
@@ -846,11 +823,10 @@ static int ks7010_sdio_probe(struct sdio_func *func,
sdio_claim_host(func);
ret = sdio_set_block_size(func, KS7010_IO_BLOCK_SIZE);
- DPRINTK(5, "multi_block=%d sdio_set_block_size()=%d %d\n",
+ dev_dbg(&card->func->dev, "multi_block=%d sdio_set_block_size()=%d %d\n",
func->card->cccr.multi_block, func->cur_blksize, ret);
ret = sdio_enable_func(func);
- DPRINTK(5, "sdio_enable_func() %d\n", ret);
if (ret)
goto err_free_card;
@@ -871,7 +847,7 @@ static int ks7010_sdio_probe(struct sdio_func *func,
sdio_set_drvdata(func, card);
- DPRINTK(5, "class = 0x%X, vendor = 0x%X, device = 0x%X\n",
+ dev_dbg(&card->func->dev, "class = 0x%X, vendor = 0x%X, device = 0x%X\n",
func->class, func->vendor, func->device);
/* private memory allocate */
@@ -916,9 +892,9 @@ static int ks7010_sdio_probe(struct sdio_func *func,
ret = ks7010_upload_firmware(card);
if (ret) {
- dev_err(&card->func->dev,
- "ks7010: firmware load failed !! return code = %d\n",
- ret);
+ netdev_err(priv->net_dev,
+ "ks7010: firmware load failed !! return code = %d\n",
+ ret);
goto err_free_netdev;
}
@@ -928,7 +904,7 @@ static int ks7010_sdio_probe(struct sdio_func *func,
ret = ks7010_sdio_writeb(priv, INT_PENDING, 0xff);
sdio_release_host(func);
if (ret)
- DPRINTK(1, " error : INT_PENDING\n");
+ netdev_err(priv->net_dev, " error : INT_PENDING\n");
/* enable ks7010sdio interrupt */
byte = (INT_GCR_B | INT_READ_STATUS | INT_WRITE_STATUS);
@@ -936,14 +912,13 @@ static int ks7010_sdio_probe(struct sdio_func *func,
ret = ks7010_sdio_writeb(priv, INT_ENABLE, byte);
sdio_release_host(func);
if (ret)
- DPRINTK(1, " err : INT_ENABLE\n");
+ netdev_err(priv->net_dev, " err : INT_ENABLE\n");
- DPRINTK(4, " enable Interrupt : INT_ENABLE=%02X\n", byte);
priv->dev_state = DEVICE_STATE_BOOT;
priv->wq = create_workqueue("wq");
if (!priv->wq) {
- DPRINTK(1, "create_workqueue failed !!\n");
+ netdev_err(priv->net_dev, "create_workqueue failed !!\n");
goto err_free_netdev;
}
@@ -983,7 +958,7 @@ static int send_stop_request(struct sdio_func *func)
pp = kzalloc(hif_align_size(sizeof(*pp)), GFP_KERNEL);
if (!pp) {
- DPRINTK(3, "allocate memory failed..\n");
+ netdev_err(card->priv->net_dev, "allocate memory failed..\n");
return -ENOMEM;
}
@@ -1011,35 +986,28 @@ static void ks7010_sdio_remove(struct sdio_func *func)
if (!card)
return;
- DPRINTK(1, "priv = card->priv\n");
priv = card->priv;
if (priv) {
struct net_device *netdev = priv->net_dev;
ks_wlan_net_stop(netdev);
- DPRINTK(1, "ks_wlan_net_stop\n");
/* interrupt disable */
sdio_claim_host(func);
sdio_writeb(func, 0, INT_ENABLE, &ret);
sdio_writeb(func, 0xff, INT_PENDING, &ret);
sdio_release_host(func);
- DPRINTK(1, "interrupt disable\n");
ret = send_stop_request(func);
if (ret) /* memory allocation failure */
return;
- DPRINTK(1, "STOP Req\n");
-
if (priv->wq) {
flush_workqueue(priv->wq);
destroy_workqueue(priv->wq);
}
- DPRINTK(1, "destroy_workqueue(priv->wq);\n");
hostif_exit(priv);
- DPRINTK(1, "hostif_exit\n");
unregister_netdev(netdev);
@@ -1050,17 +1018,10 @@ static void ks7010_sdio_remove(struct sdio_func *func)
sdio_claim_host(func);
sdio_release_irq(func);
- DPRINTK(1, "sdio_release_irq()\n");
sdio_disable_func(func);
- DPRINTK(1, "sdio_disable_func()\n");
sdio_release_host(func);
-
sdio_set_drvdata(func, NULL);
-
kfree(card);
- DPRINTK(1, "kfree()\n");
-
- DPRINTK(5, " Bye !!\n");
}
static struct sdio_driver ks7010_sdio_driver = {
diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c
index 975dbbb3abd0..676961cf4103 100644
--- a/drivers/staging/ks7010/ks_hostif.c
+++ b/drivers/staging/ks7010/ks_hostif.c
@@ -21,18 +21,26 @@
/* Include Wireless Extension definition and check version */
#include <net/iw_handler.h> /* New driver API */
-/* macro */
-#define inc_smeqhead(priv) \
- (priv->sme_i.qhead = (priv->sme_i.qhead + 1) % SME_EVENT_BUFF_SIZE)
-#define inc_smeqtail(priv) \
- (priv->sme_i.qtail = (priv->sme_i.qtail + 1) % SME_EVENT_BUFF_SIZE)
-#define cnt_smeqbody(priv) \
- (((priv->sme_i.qtail + SME_EVENT_BUFF_SIZE) - (priv->sme_i.qhead)) % SME_EVENT_BUFF_SIZE)
+static inline void inc_smeqhead(struct ks_wlan_private *priv)
+{
+ priv->sme_i.qhead = (priv->sme_i.qhead + 1) % SME_EVENT_BUFF_SIZE;
+}
+
+static inline void inc_smeqtail(struct ks_wlan_private *priv)
+{
+ priv->sme_i.qtail = (priv->sme_i.qtail + 1) % SME_EVENT_BUFF_SIZE;
+}
+
+static inline unsigned int cnt_smeqbody(struct ks_wlan_private *priv)
+{
+ unsigned int sme_cnt = priv->sme_i.qtail - priv->sme_i.qhead;
+
+ return (sme_cnt + SME_EVENT_BUFF_SIZE) % SME_EVENT_BUFF_SIZE;
+}
#define KS_WLAN_MEM_FLAG (GFP_ATOMIC)
-static
-inline u8 get_BYTE(struct ks_wlan_private *priv)
+static inline u8 get_byte(struct ks_wlan_private *priv)
{
u8 data;
@@ -42,25 +50,23 @@ inline u8 get_BYTE(struct ks_wlan_private *priv)
return data;
}
-static
-inline u16 get_WORD(struct ks_wlan_private *priv)
+static inline u16 get_word(struct ks_wlan_private *priv)
{
u16 data;
- data = (get_BYTE(priv) & 0xff);
- data |= ((get_BYTE(priv) << 8) & 0xff00);
+ data = (get_byte(priv) & 0xff);
+ data |= ((get_byte(priv) << 8) & 0xff00);
return data;
}
-static
-inline u32 get_DWORD(struct ks_wlan_private *priv)
+static inline u32 get_dword(struct ks_wlan_private *priv)
{
u32 data;
- data = (get_BYTE(priv) & 0xff);
- data |= ((get_BYTE(priv) << 8) & 0x0000ff00);
- data |= ((get_BYTE(priv) << 16) & 0x00ff0000);
- data |= ((get_BYTE(priv) << 24) & 0xff000000);
+ data = (get_byte(priv) & 0xff);
+ data |= ((get_byte(priv) << 8) & 0x0000ff00);
+ data |= ((get_byte(priv) << 16) & 0x00ff0000);
+ data |= ((get_byte(priv) << 24) & 0xff000000);
return data;
}
@@ -79,26 +85,20 @@ static void ks_wlan_hw_wakeup_task(struct work_struct *work)
&priv->psstatus.wakeup_wait,
msecs_to_jiffies(20));
if (time_left <= 0) {
- DPRINTK(1, "wake up timeout or interrupted !!!\n");
+ netdev_dbg(priv->net_dev, "wake up timeout or interrupted !!!\n");
schedule_work(&priv->wakeup_work);
return;
}
- } else {
- DPRINTK(1, "ps_status=%d\n", ps_status);
}
/* power save */
- if (atomic_read(&priv->sme_task.count) > 0) {
- DPRINTK(4, "sme task enable.\n");
+ if (atomic_read(&priv->sme_task.count) > 0)
tasklet_enable(&priv->sme_task);
- }
}
static
int ks_wlan_do_power_save(struct ks_wlan_private *priv)
{
- DPRINTK(4, "psstatus.status=%d\n", atomic_read(&priv->psstatus.status));
-
if (is_connect_status(priv->connect_status))
hostif_sme_enqueue(priv, SME_POW_MNGMT_REQUEST);
else
@@ -113,7 +113,6 @@ int get_current_ap(struct ks_wlan_private *priv, struct link_ap_info_t *ap_info)
union iwreq_data wrqu;
struct net_device *netdev = priv->net_dev;
- DPRINTK(3, "\n");
ap = &priv->current_ap;
if (is_disconnect_status(priv->connect_status)) {
@@ -186,34 +185,43 @@ int get_current_ap(struct ks_wlan_private *priv, struct link_ap_info_t *ap_info)
if (is_connect_status(priv->connect_status)) {
memcpy(wrqu.ap_addr.sa_data,
priv->current_ap.bssid, ETH_ALEN);
- DPRINTK(3,
- "IWEVENT: connect bssid=%pM\n", wrqu.ap_addr.sa_data);
+ netdev_dbg(priv->net_dev,
+ "IWEVENT: connect bssid=%pM\n", wrqu.ap_addr.sa_data);
wireless_send_event(netdev, SIOCGIWAP, &wrqu, NULL);
}
- DPRINTK(4, "\n Link AP\n");
- DPRINTK(4, " bssid=%02X:%02X:%02X:%02X:%02X:%02X\n"
+ netdev_dbg(priv->net_dev, " Link AP\n");
+ netdev_dbg(priv->net_dev, " bssid=%02X:%02X:%02X:%02X:%02X:%02X\n"
" essid=%s\n"
" rate_set=%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X\n"
" channel=%d\n"
" rssi=%d\n"
" sq=%d\n"
" capability=%04X\n",
- ap->bssid[0], ap->bssid[1], ap->bssid[2],
- ap->bssid[3], ap->bssid[4], ap->bssid[5],
- &(ap->ssid.body[0]),
- ap->rate_set.body[0], ap->rate_set.body[1],
- ap->rate_set.body[2], ap->rate_set.body[3],
- ap->rate_set.body[4], ap->rate_set.body[5],
- ap->rate_set.body[6], ap->rate_set.body[7],
- ap->channel, ap->rssi, ap->sq, ap->capability);
- DPRINTK(4, "\n Link AP\n rsn.mode=%d\n rsn.size=%d\n",
- ap_info->rsn_mode, ap_info->rsn.size);
- DPRINTK(4, "\n ext_rate_set_size=%d\n rate_set_size=%d\n",
- ap_info->ext_rate_set.size, ap_info->rate_set.size);
+ ap->bssid[0], ap->bssid[1], ap->bssid[2],
+ ap->bssid[3], ap->bssid[4], ap->bssid[5],
+ &(ap->ssid.body[0]),
+ ap->rate_set.body[0], ap->rate_set.body[1],
+ ap->rate_set.body[2], ap->rate_set.body[3],
+ ap->rate_set.body[4], ap->rate_set.body[5],
+ ap->rate_set.body[6], ap->rate_set.body[7],
+ ap->channel, ap->rssi, ap->sq, ap->capability);
+ netdev_dbg(priv->net_dev, " Link AP\n rsn.mode=%d\n rsn.size=%d\n",
+ ap_info->rsn_mode, ap_info->rsn.size);
+ netdev_dbg(priv->net_dev, " ext_rate_set_size=%d\n rate_set_size=%d\n",
+ ap_info->ext_rate_set.size, ap_info->rate_set.size);
return 0;
}
+static u8 read_ie(unsigned char *bp, u8 max, u8 *body)
+{
+ u8 size = (*(bp + 1) <= max) ? *(bp + 1) : max;
+
+ memcpy(body, bp + 2, size);
+ return size;
+}
+
+
static
int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info,
struct local_ap_t *ap)
@@ -221,7 +229,6 @@ int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info,
unsigned char *bp;
int bsize, offset;
- DPRINTK(3, "\n");
memset(ap, 0, sizeof(struct local_ap_t));
/* bssid */
@@ -242,28 +249,19 @@ int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info,
offset = 0;
while (bsize > offset) {
- /* DPRINTK(4, "Element ID=%d\n",*bp); */
- switch (*bp) {
- case 0: /* ssid */
- if (*(bp + 1) <= SSID_MAX_SIZE) {
- ap->ssid.size = *(bp + 1);
- } else {
- DPRINTK(1, "size over :: ssid size=%d\n",
- *(bp + 1));
- ap->ssid.size = SSID_MAX_SIZE;
- }
- memcpy(ap->ssid.body, bp + 2, ap->ssid.size);
+ switch (*bp) { /* Information Element ID */
+ case WLAN_EID_SSID:
+ ap->ssid.size = read_ie(bp, IEEE80211_MAX_SSID_LEN,
+ ap->ssid.body);
break;
- case 1: /* rate */
- case 50: /* ext rate */
+ case WLAN_EID_SUPP_RATES:
+ case WLAN_EID_EXT_SUPP_RATES:
if ((*(bp + 1) + ap->rate_set.size) <=
RATE_SET_MAX_SIZE) {
memcpy(&ap->rate_set.body[ap->rate_set.size],
bp + 2, *(bp + 1));
ap->rate_set.size += *(bp + 1);
} else {
- DPRINTK(1, "size over :: rate size=%d\n",
- (*(bp + 1) + ap->rate_set.size));
memcpy(&ap->rate_set.body[ap->rate_set.size],
bp + 2,
RATE_SET_MAX_SIZE - ap->rate_set.size);
@@ -271,47 +269,34 @@ int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info,
(RATE_SET_MAX_SIZE - ap->rate_set.size);
}
break;
- case 3: /* DS parameter */
+ case WLAN_EID_DS_PARAMS:
break;
- case 48: /* RSN(WPA2) */
+ case WLAN_EID_RSN:
ap->rsn_ie.id = *bp;
- if (*(bp + 1) <= RSN_IE_BODY_MAX) {
- ap->rsn_ie.size = *(bp + 1);
- } else {
- DPRINTK(1, "size over :: rsn size=%d\n",
- *(bp + 1));
- ap->rsn_ie.size = RSN_IE_BODY_MAX;
- }
- memcpy(ap->rsn_ie.body, bp + 2, ap->rsn_ie.size);
+ ap->rsn_ie.size = read_ie(bp, RSN_IE_BODY_MAX,
+ ap->rsn_ie.body);
break;
- case 221: /* WPA */
- if (memcmp(bp + 2, "\x00\x50\xf2\x01", 4) == 0) { /* WPA OUI check */
+ case WLAN_EID_VENDOR_SPECIFIC: /* WPA */
+ /* WPA OUI check */
+ if (memcmp(bp + 2, CIPHER_ID_WPA_WEP40, 4) == 0) {
ap->wpa_ie.id = *bp;
- if (*(bp + 1) <= RSN_IE_BODY_MAX) {
- ap->wpa_ie.size = *(bp + 1);
- } else {
- DPRINTK(1,
- "size over :: wpa size=%d\n",
- *(bp + 1));
- ap->wpa_ie.size = RSN_IE_BODY_MAX;
- }
- memcpy(ap->wpa_ie.body, bp + 2,
- ap->wpa_ie.size);
+ ap->wpa_ie.size = read_ie(bp, RSN_IE_BODY_MAX,
+ ap->wpa_ie.body);
}
break;
- case 2: /* FH parameter */
- case 4: /* CF parameter */
- case 5: /* TIM */
- case 6: /* IBSS parameter */
- case 7: /* Country */
- case 42: /* ERP information */
- case 47: /* Reserve ID 47 Broadcom AP */
+ case WLAN_EID_FH_PARAMS:
+ case WLAN_EID_CF_PARAMS:
+ case WLAN_EID_TIM:
+ case WLAN_EID_IBSS_PARAMS:
+ case WLAN_EID_COUNTRY:
+ case WLAN_EID_ERP_INFO:
break;
default:
- DPRINTK(4, "unknown Element ID=%d\n", *bp);
+ netdev_err(priv->net_dev, "unknown Element ID=%d\n", *bp);
break;
}
+
offset += 2; /* id & size field */
offset += *(bp + 1); /* +size offset */
bp += (*(bp + 1) + 2); /* pointer update */
@@ -339,7 +324,7 @@ int hostif_data_indication_wpa(struct ks_wlan_private *priv,
eth_proto = ntohs(eth_hdr->h_proto);
if (eth_hdr->h_dest_snap != eth_hdr->h_source_snap) {
- DPRINTK(1, "invalid data format\n");
+ netdev_err(priv->net_dev, "invalid data format\n");
priv->nstats.rx_errors++;
return -EINVAL;
}
@@ -350,20 +335,20 @@ int hostif_data_indication_wpa(struct ks_wlan_private *priv,
(auth_type == TYPE_GMK2 &&
priv->wpa.group_suite == IW_AUTH_CIPHER_TKIP)) &&
key->key_len) {
- DPRINTK(4, "TKIP: protocol=%04X: size=%u\n",
- eth_proto, priv->rx_size);
+ netdev_dbg(priv->net_dev, "TKIP: protocol=%04X: size=%u\n",
+ eth_proto, priv->rx_size);
/* MIC save */
memcpy(&recv_mic[0], (priv->rxp) + ((priv->rx_size) - 8), 8);
priv->rx_size = priv->rx_size - 8;
if (auth_type > 0 && auth_type < 4) { /* auth_type check */
- MichaelMICFunction(&michael_mic,
- (uint8_t *)key->rx_mic_key,
- (uint8_t *)priv->rxp,
- (int)priv->rx_size,
- (uint8_t)0, /* priority */
- (uint8_t *)michael_mic.Result);
+ michael_mic_function(&michael_mic,
+ (uint8_t *)key->rx_mic_key,
+ (uint8_t *)priv->rxp,
+ (int)priv->rx_size,
+ (uint8_t)0, /* priority */
+ (uint8_t *)michael_mic.result);
}
- if (memcmp(michael_mic.Result, recv_mic, 8) != 0) {
+ if (memcmp(michael_mic.result, recv_mic, 8) != 0) {
now = jiffies;
mic_failure = &priv->wpa.mic_failure;
/* MIC FAILURE */
@@ -371,7 +356,7 @@ int hostif_data_indication_wpa(struct ks_wlan_private *priv,
(now - mic_failure->last_failure_time) / HZ >= 60) {
mic_failure->failure = 0;
}
- DPRINTK(4, "MIC FAILURE\n");
+ netdev_err(priv->net_dev, "MIC FAILURE\n");
if (mic_failure->failure == 0) {
mic_failure->failure = 1;
mic_failure->counter = 0;
@@ -392,7 +377,6 @@ int hostif_data_indication_wpa(struct ks_wlan_private *priv,
eth_hdr->h_source);
memset(&wrqu, 0, sizeof(wrqu));
wrqu.data.length = strlen(buf);
- DPRINTK(4, "IWEVENT:MICHAELMICFAILURE\n");
wireless_send_event(priv->net_dev, IWEVCUSTOM, &wrqu,
buf);
return -EINVAL;
@@ -414,30 +398,26 @@ void hostif_data_indication(struct ks_wlan_private *priv)
size_t size;
int ret;
- DPRINTK(3, "\n");
-
/* min length check */
if (priv->rx_size <= ETH_HLEN) {
- DPRINTK(3, "rx_size = %d\n", priv->rx_size);
priv->nstats.rx_errors++;
return;
}
- auth_type = get_WORD(priv); /* AuthType */
- get_WORD(priv); /* Reserve Area */
+ auth_type = get_word(priv); /* AuthType */
+ get_word(priv); /* Reserve Area */
eth_hdr = (struct ether_hdr *)(priv->rxp);
eth_proto = ntohs(eth_hdr->h_proto);
- DPRINTK(3, "ether protocol = %04X\n", eth_proto);
/* source address check */
if (memcmp(&priv->eth_addr[0], eth_hdr->h_source, ETH_ALEN) == 0) {
- DPRINTK(1, "invalid : source is own mac address !!\n");
- DPRINTK(1,
- "eth_hdrernet->h_dest=%02X:%02X:%02X:%02X:%02X:%02X\n",
- eth_hdr->h_source[0], eth_hdr->h_source[1],
- eth_hdr->h_source[2], eth_hdr->h_source[3],
- eth_hdr->h_source[4], eth_hdr->h_source[5]);
+ netdev_err(priv->net_dev, "invalid : source is own mac address !!\n");
+ netdev_err(priv->net_dev,
+ "eth_hdrernet->h_dest=%02X:%02X:%02X:%02X:%02X:%02X\n",
+ eth_hdr->h_source[0], eth_hdr->h_source[1],
+ eth_hdr->h_source[2], eth_hdr->h_source[3],
+ eth_hdr->h_source[4], eth_hdr->h_source[5]);
priv->nstats.rx_errors++;
return;
}
@@ -463,7 +443,8 @@ void hostif_data_indication(struct ks_wlan_private *priv)
priv->nstats.rx_dropped++;
return;
}
- DPRINTK(4, "SNAP, rx_ind_size = %d\n", rx_ind_size);
+ netdev_dbg(priv->net_dev, "SNAP, rx_ind_size = %d\n",
+ rx_ind_size);
size = ETH_ALEN * 2;
skb_put_data(skb, priv->rxp, size);
@@ -482,20 +463,24 @@ void hostif_data_indication(struct ks_wlan_private *priv)
priv->nstats.rx_dropped++;
return;
}
- DPRINTK(3, "NETBEUI/NetBIOS rx_ind_size=%d\n", rx_ind_size);
+ netdev_dbg(priv->net_dev, "NETBEUI/NetBIOS rx_ind_size=%d\n",
+ rx_ind_size);
- skb_put_data(skb, priv->rxp, 12); /* 8802/FDDI MAC copy */
+ /* 8802/FDDI MAC copy */
+ skb_put_data(skb, priv->rxp, 12);
- temp[0] = (((rx_ind_size - 12) >> 8) & 0xff); /* NETBEUI size add */
+ /* NETBEUI size add */
+ temp[0] = (((rx_ind_size - 12) >> 8) & 0xff);
temp[1] = ((rx_ind_size - 12) & 0xff);
skb_put_data(skb, temp, 2);
- skb_put_data(skb, priv->rxp + 12, rx_ind_size - 14); /* copy after Type */
+ /* copy after Type */
+ skb_put_data(skb, priv->rxp + 12, rx_ind_size - 14);
aa1x_hdr = (struct ieee802_1x_hdr *)(priv->rxp + 14);
break;
default: /* other rx data */
- DPRINTK(2, "invalid data format\n");
+ netdev_err(priv->net_dev, "invalid data format\n");
priv->nstats.rx_errors++;
return;
}
@@ -521,27 +506,24 @@ void hostif_mib_get_confirm(struct ks_wlan_private *priv)
u16 mib_val_size;
u16 mib_val_type;
- DPRINTK(3, "\n");
-
- mib_status = get_DWORD(priv); /* MIB status */
- mib_attribute = get_DWORD(priv); /* MIB atttibute */
- mib_val_size = get_WORD(priv); /* MIB value size */
- mib_val_type = get_WORD(priv); /* MIB value type */
+ mib_status = get_dword(priv); /* MIB status */
+ mib_attribute = get_dword(priv); /* MIB atttibute */
+ mib_val_size = get_word(priv); /* MIB value size */
+ mib_val_type = get_word(priv); /* MIB value type */
if (mib_status) {
/* in case of error */
- DPRINTK(1, "attribute=%08X, status=%08X\n", mib_attribute,
- mib_status);
+ netdev_err(priv->net_dev, "attribute=%08X, status=%08X\n",
+ mib_attribute, mib_status);
return;
}
switch (mib_attribute) {
case DOT11_MAC_ADDRESS:
/* MAC address */
- DPRINTK(3, " mib_attribute=DOT11_MAC_ADDRESS\n");
hostif_sme_enqueue(priv, SME_GET_MAC_ADDRESS);
memcpy(priv->eth_addr, priv->rxp, ETH_ALEN);
- priv->mac_address_valid = 1;
+ priv->mac_address_valid = true;
dev->dev_addr[0] = priv->eth_addr[0];
dev->dev_addr[1] = priv->eth_addr[1];
dev->dev_addr[2] = priv->eth_addr[2];
@@ -554,7 +536,6 @@ void hostif_mib_get_confirm(struct ks_wlan_private *priv)
break;
case DOT11_PRODUCT_VERSION:
/* firmware version */
- DPRINTK(3, " mib_attribute=DOT11_PRODUCT_VERSION\n");
priv->version_size = priv->rx_size;
memcpy(priv->firmware_version, priv->rxp, priv->rx_size);
priv->firmware_version[priv->rx_size] = '\0';
@@ -566,14 +547,12 @@ void hostif_mib_get_confirm(struct ks_wlan_private *priv)
break;
case LOCAL_GAIN:
memcpy(&priv->gain, priv->rxp, sizeof(priv->gain));
- DPRINTK(3, "tx_mode=%d, rx_mode=%d, tx_gain=%d, rx_gain=%d\n",
- priv->gain.tx_mode, priv->gain.rx_mode,
- priv->gain.tx_gain, priv->gain.rx_gain);
+ netdev_dbg(priv->net_dev, "tx_mode=%d, rx_mode=%d, tx_gain=%d, rx_gain=%d\n",
+ priv->gain.tx_mode, priv->gain.rx_mode,
+ priv->gain.tx_gain, priv->gain.rx_gain);
break;
case LOCAL_EEPROM_SUM:
memcpy(&priv->eeprom_sum, priv->rxp, sizeof(priv->eeprom_sum));
- DPRINTK(1, "eeprom_sum.type=%x, eeprom_sum.result=%x\n",
- priv->eeprom_sum.type, priv->eeprom_sum.result);
if (priv->eeprom_sum.type == 0) {
priv->eeprom_checksum = EEPROM_CHECKSUM_NONE;
} else if (priv->eeprom_sum.type == 1) {
@@ -588,7 +567,8 @@ void hostif_mib_get_confirm(struct ks_wlan_private *priv)
}
break;
default:
- DPRINTK(1, "mib_attribute=%08x\n", (unsigned int)mib_attribute);
+ netdev_err(priv->net_dev, "mib_attribute=%08x\n",
+ (unsigned int)mib_attribute);
break;
}
}
@@ -599,15 +579,13 @@ void hostif_mib_set_confirm(struct ks_wlan_private *priv)
u32 mib_status; /* +04 MIB Status */
u32 mib_attribute; /* +08 MIB attribute */
- DPRINTK(3, "\n");
-
- mib_status = get_DWORD(priv); /* MIB Status */
- mib_attribute = get_DWORD(priv); /* MIB attribute */
+ mib_status = get_dword(priv); /* MIB Status */
+ mib_attribute = get_dword(priv); /* MIB attribute */
if (mib_status) {
/* in case of error */
- DPRINTK(1, "error :: attribute=%08X, status=%08X\n",
- mib_attribute, mib_status);
+ netdev_err(priv->net_dev, "error :: attribute=%08X, status=%08X\n",
+ mib_attribute, mib_status);
}
switch (mib_attribute) {
@@ -622,32 +600,24 @@ void hostif_mib_set_confirm(struct ks_wlan_private *priv)
hostif_sme_enqueue(priv, SME_WEP_INDEX_CONFIRM);
break;
case DOT11_WEP_DEFAULT_KEY_VALUE1:
- DPRINTK(2, "DOT11_WEP_DEFAULT_KEY_VALUE1:mib_status=%d\n",
- (int)mib_status);
if (priv->wpa.rsn_enabled)
hostif_sme_enqueue(priv, SME_SET_PMK_TSC);
else
hostif_sme_enqueue(priv, SME_WEP_KEY1_CONFIRM);
break;
case DOT11_WEP_DEFAULT_KEY_VALUE2:
- DPRINTK(2, "DOT11_WEP_DEFAULT_KEY_VALUE2:mib_status=%d\n",
- (int)mib_status);
if (priv->wpa.rsn_enabled)
hostif_sme_enqueue(priv, SME_SET_GMK1_TSC);
else
hostif_sme_enqueue(priv, SME_WEP_KEY2_CONFIRM);
break;
case DOT11_WEP_DEFAULT_KEY_VALUE3:
- DPRINTK(2, "DOT11_WEP_DEFAULT_KEY_VALUE3:mib_status=%d\n",
- (int)mib_status);
if (priv->wpa.rsn_enabled)
hostif_sme_enqueue(priv, SME_SET_GMK2_TSC);
else
hostif_sme_enqueue(priv, SME_WEP_KEY3_CONFIRM);
break;
case DOT11_WEP_DEFAULT_KEY_VALUE4:
- DPRINTK(2, "DOT11_WEP_DEFAULT_KEY_VALUE4:mib_status=%d\n",
- (int)mib_status);
if (!priv->wpa.rsn_enabled)
hostif_sme_enqueue(priv, SME_WEP_KEY4_CONFIRM);
break;
@@ -656,8 +626,6 @@ void hostif_mib_set_confirm(struct ks_wlan_private *priv)
hostif_sme_enqueue(priv, SME_WEP_FLAG_CONFIRM);
break;
case DOT11_RSN_ENABLED:
- DPRINTK(2, "DOT11_RSN_ENABLED:mib_status=%d\n",
- (int)mib_status);
hostif_sme_enqueue(priv, SME_RSN_ENABLED_CONFIRM);
break;
case LOCAL_RSN_MODE:
@@ -670,53 +638,38 @@ void hostif_mib_set_confirm(struct ks_wlan_private *priv)
hostif_sme_enqueue(priv, SME_MULTICAST_CONFIRM);
break;
case LOCAL_CURRENTADDRESS:
- priv->mac_address_valid = 1;
+ priv->mac_address_valid = true;
break;
case DOT11_RSN_CONFIG_MULTICAST_CIPHER:
- DPRINTK(2, "DOT11_RSN_CONFIG_MULTICAST_CIPHER:mib_status=%d\n",
- (int)mib_status);
hostif_sme_enqueue(priv, SME_RSN_MCAST_CONFIRM);
break;
case DOT11_RSN_CONFIG_UNICAST_CIPHER:
- DPRINTK(2, "DOT11_RSN_CONFIG_UNICAST_CIPHER:mib_status=%d\n",
- (int)mib_status);
hostif_sme_enqueue(priv, SME_RSN_UCAST_CONFIRM);
break;
case DOT11_RSN_CONFIG_AUTH_SUITE:
- DPRINTK(2, "DOT11_RSN_CONFIG_AUTH_SUITE:mib_status=%d\n",
- (int)mib_status);
hostif_sme_enqueue(priv, SME_RSN_AUTH_CONFIRM);
break;
case DOT11_PMK_TSC:
- DPRINTK(2, "DOT11_PMK_TSC:mib_status=%d\n", (int)mib_status);
break;
case DOT11_GMK1_TSC:
- DPRINTK(2, "DOT11_GMK1_TSC:mib_status=%d\n", (int)mib_status);
if (atomic_read(&priv->psstatus.snooze_guard))
atomic_set(&priv->psstatus.snooze_guard, 0);
break;
case DOT11_GMK2_TSC:
- DPRINTK(2, "DOT11_GMK2_TSC:mib_status=%d\n", (int)mib_status);
if (atomic_read(&priv->psstatus.snooze_guard))
atomic_set(&priv->psstatus.snooze_guard, 0);
break;
case LOCAL_PMK:
- DPRINTK(2, "LOCAL_PMK:mib_status=%d\n", (int)mib_status);
break;
case LOCAL_GAIN:
- DPRINTK(2, "LOCAL_GAIN:mib_status=%d\n", (int)mib_status);
break;
#ifdef WPS
case LOCAL_WPS_ENABLE:
- DPRINTK(2, "LOCAL_WPS_ENABLE:mib_status=%d\n", (int)mib_status);
break;
case LOCAL_WPS_PROBE_REQ:
- DPRINTK(2, "LOCAL_WPS_PROBE_REQ:mib_status=%d\n",
- (int)mib_status);
break;
#endif /* WPS */
case LOCAL_REGION:
- DPRINTK(2, "LOCAL_REGION:mib_status=%d\n", (int)mib_status);
default:
break;
}
@@ -725,8 +678,6 @@ void hostif_mib_set_confirm(struct ks_wlan_private *priv)
static
void hostif_power_mgmt_confirm(struct ks_wlan_private *priv)
{
- DPRINTK(3, "\n");
-
if (priv->reg.power_mgmt > POWER_MGMT_ACTIVE &&
priv->reg.operation_mode == MODE_INFRASTRUCTURE) {
atomic_set(&priv->psstatus.confirm_wait, 0);
@@ -740,8 +691,6 @@ void hostif_power_mgmt_confirm(struct ks_wlan_private *priv)
static
void hostif_sleep_confirm(struct ks_wlan_private *priv)
{
- DPRINTK(3, "\n");
-
atomic_set(&priv->sleepstatus.doze_request, 1);
queue_delayed_work(priv->wq, &priv->rw_dwork, 1);
}
@@ -757,11 +706,10 @@ void hostif_start_confirm(struct ks_wlan_private *priv)
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
if (is_connect_status(priv->connect_status)) {
eth_zero_addr(wrqu.ap_addr.sa_data);
- DPRINTK(3, "IWEVENT: disconnect\n");
wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
}
#endif
- DPRINTK(3, " scan_ind_count=%d\n", priv->scan_ind_count);
+ netdev_dbg(priv->net_dev, " scan_ind_count=%d\n", priv->scan_ind_count);
hostif_sme_enqueue(priv, SME_START_CONFIRM);
}
@@ -774,27 +722,23 @@ void hostif_connect_indication(struct ks_wlan_private *priv)
struct net_device *netdev = priv->net_dev;
union iwreq_data wrqu0;
- connect_code = get_WORD(priv);
+ connect_code = get_word(priv);
switch (connect_code) {
case RESULT_CONNECT: /* connect */
- DPRINTK(3, "connect :: scan_ind_count=%d\n",
- priv->scan_ind_count);
if (!(priv->connect_status & FORCE_DISCONNECT))
netif_carrier_on(netdev);
tmp = FORCE_DISCONNECT & priv->connect_status;
priv->connect_status = tmp + CONNECT_STATUS;
break;
- case RESULT_DISCONNECT: /* disconnect */
- DPRINTK(3, "disconnect :: scan_ind_count=%d\n",
- priv->scan_ind_count);
+ case RESULT_DISCONNECT: /* disconnect */
netif_carrier_off(netdev);
tmp = FORCE_DISCONNECT & priv->connect_status;
priv->connect_status = tmp + DISCONNECT_STATUS;
break;
default:
- DPRINTK(1, "unknown connect_code=%d :: scan_ind_count=%d\n",
- connect_code, priv->scan_ind_count);
+ netdev_dbg(priv->net_dev, "unknown connect_code=%d :: scan_ind_count=%d\n",
+ connect_code, priv->scan_ind_count);
netif_carrier_off(netdev);
tmp = FORCE_DISCONNECT & priv->connect_status;
priv->connect_status = tmp + DISCONNECT_STATUS;
@@ -816,9 +760,8 @@ void hostif_connect_indication(struct ks_wlan_private *priv)
if (is_disconnect_status(priv->connect_status) &&
is_connect_status(old_status)) {
eth_zero_addr(wrqu0.ap_addr.sa_data);
- DPRINTK(3, "IWEVENT: disconnect\n");
- DPRINTK(3, "disconnect :: scan_ind_count=%d\n",
- priv->scan_ind_count);
+ netdev_dbg(priv->net_dev, "disconnect :: scan_ind_count=%d\n",
+ priv->scan_ind_count);
wireless_send_event(netdev, SIOCGIWAP, &wrqu0, NULL);
}
priv->scan_ind_count = 0;
@@ -830,16 +773,18 @@ void hostif_scan_indication(struct ks_wlan_private *priv)
int i;
struct ap_info_t *ap_info;
- DPRINTK(3, "scan_ind_count = %d\n", priv->scan_ind_count);
+ netdev_dbg(priv->net_dev, "scan_ind_count = %d\n", priv->scan_ind_count);
ap_info = (struct ap_info_t *)(priv->rxp);
if (priv->scan_ind_count) {
- for (i = 0; i < priv->aplist.size; i++) { /* bssid check */
- if (memcmp(ap_info->bssid,
- priv->aplist.ap[i].bssid, ETH_ALEN) != 0)
+ /* bssid check */
+ for (i = 0; i < priv->aplist.size; i++) {
+ u8 *bssid = priv->aplist.ap[i].bssid;
+
+ if (ether_addr_equal(ap_info->bssid, bssid))
continue;
- if (ap_info->frame_type == FRAME_TYPE_PROBE_RESP)
+ if (ap_info->frame_type == IEEE80211_STYPE_PROBE_RESP)
get_ap_information(priv, ap_info,
&priv->aplist.ap[i]);
return;
@@ -847,14 +792,14 @@ void hostif_scan_indication(struct ks_wlan_private *priv)
}
priv->scan_ind_count++;
if (priv->scan_ind_count < LOCAL_APLIST_MAX + 1) {
- DPRINTK(4, " scan_ind_count=%d :: aplist.size=%d\n",
+ netdev_dbg(priv->net_dev, " scan_ind_count=%d :: aplist.size=%d\n",
priv->scan_ind_count, priv->aplist.size);
get_ap_information(priv, (struct ap_info_t *)(priv->rxp),
&(priv->aplist.ap[priv->scan_ind_count - 1]));
priv->aplist.size = priv->scan_ind_count;
} else {
- DPRINTK(4, " count over :: scan_ind_count=%d\n",
- priv->scan_ind_count);
+ netdev_dbg(priv->net_dev, " count over :: scan_ind_count=%d\n",
+ priv->scan_ind_count);
}
}
@@ -866,7 +811,6 @@ void hostif_stop_confirm(struct ks_wlan_private *priv)
struct net_device *netdev = priv->net_dev;
union iwreq_data wrqu0;
- DPRINTK(3, "\n");
if (priv->dev_state == DEVICE_STATE_SLEEP)
priv->dev_state = DEVICE_STATE_READY;
@@ -883,10 +827,7 @@ void hostif_stop_confirm(struct ks_wlan_private *priv)
if (is_disconnect_status(priv->connect_status) &&
is_connect_status(old_status)) {
eth_zero_addr(wrqu0.ap_addr.sa_data);
- DPRINTK(3, "IWEVENT: disconnect\n");
netdev_info(netdev, "IWEVENT: disconnect\n");
- DPRINTK(3, "disconnect :: scan_ind_count=%d\n",
- priv->scan_ind_count);
wireless_send_event(netdev, SIOCGIWAP, &wrqu0, NULL);
}
priv->scan_ind_count = 0;
@@ -898,7 +839,6 @@ void hostif_stop_confirm(struct ks_wlan_private *priv)
static
void hostif_ps_adhoc_set_confirm(struct ks_wlan_private *priv)
{
- DPRINTK(3, "\n");
priv->infra_status = 0; /* infrastructure mode cancel */
hostif_sme_enqueue(priv, SME_MODE_SET_CONFIRM);
}
@@ -908,9 +848,7 @@ void hostif_infrastructure_set_confirm(struct ks_wlan_private *priv)
{
u16 result_code;
- DPRINTK(3, "\n");
- result_code = get_WORD(priv);
- DPRINTK(3, "result code = %d\n", result_code);
+ result_code = get_word(priv);
priv->infra_status = 1; /* infrastructure mode set */
hostif_sme_enqueue(priv, SME_MODE_SET_CONFIRM);
}
@@ -918,7 +856,6 @@ void hostif_infrastructure_set_confirm(struct ks_wlan_private *priv)
static
void hostif_adhoc_set_confirm(struct ks_wlan_private *priv)
{
- DPRINTK(3, "\n");
priv->infra_status = 1; /* infrastructure mode set */
hostif_sme_enqueue(priv, SME_MODE_SET_CONFIRM);
}
@@ -937,7 +874,6 @@ void hostif_associate_indication(struct ks_wlan_private *priv)
static const char associnfo_leader0[] = "ASSOCINFO(ReqIEs=";
static const char associnfo_leader1[] = " RespIEs=";
- DPRINTK(3, "\n");
assoc_req = (struct association_request_t *)(priv->rxp);
assoc_resp = (struct association_response_t *)(assoc_req + 1);
pb = (unsigned char *)(assoc_resp + 1);
@@ -963,7 +899,6 @@ void hostif_associate_indication(struct ks_wlan_private *priv)
pbuf += sprintf(pbuf, ")");
wrqu.data.length += 1;
- DPRINTK(3, "IWEVENT:ASSOCINFO\n");
wireless_send_event(priv->net_dev, IWEVCUSTOM, &wrqu, buf);
}
@@ -974,16 +909,15 @@ void hostif_bss_scan_confirm(struct ks_wlan_private *priv)
struct net_device *dev = priv->net_dev;
union iwreq_data wrqu;
- result_code = get_DWORD(priv);
- DPRINTK(2, "result=%d :: scan_ind_count=%d\n", result_code,
- priv->scan_ind_count);
+ result_code = get_dword(priv);
+ netdev_dbg(priv->net_dev, "result=%d :: scan_ind_count=%d\n", result_code,
+ priv->scan_ind_count);
priv->sme_i.sme_flag &= ~SME_AP_SCAN;
hostif_sme_enqueue(priv, SME_BSS_SCAN_CONFIRM);
wrqu.data.length = 0;
wrqu.data.flags = 0;
- DPRINTK(3, "IWEVENT: SCAN CONFIRM\n");
wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
priv->scan_ind_count = 0;
}
@@ -997,32 +931,32 @@ void hostif_phy_information_confirm(struct ks_wlan_private *priv)
unsigned int transmitted_frame_count, received_fragment_count;
unsigned int failed_count, fcs_error_count;
- DPRINTK(3, "\n");
- rssi = get_BYTE(priv);
- signal = get_BYTE(priv);
- noise = get_BYTE(priv);
- link_speed = get_BYTE(priv);
- transmitted_frame_count = get_DWORD(priv);
- received_fragment_count = get_DWORD(priv);
- failed_count = get_DWORD(priv);
- fcs_error_count = get_DWORD(priv);
-
- DPRINTK(4, "phyinfo confirm rssi=%d signal=%d\n", rssi, signal);
+ rssi = get_byte(priv);
+ signal = get_byte(priv);
+ noise = get_byte(priv);
+ link_speed = get_byte(priv);
+ transmitted_frame_count = get_dword(priv);
+ received_fragment_count = get_dword(priv);
+ failed_count = get_dword(priv);
+ fcs_error_count = get_dword(priv);
+
+ netdev_dbg(priv->net_dev, "phyinfo confirm rssi=%d signal=%d\n",
+ rssi, signal);
priv->current_rate = (link_speed & RATE_MASK);
wstats->qual.qual = signal;
wstats->qual.level = 256 - rssi;
wstats->qual.noise = 0; /* invalid noise value */
wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
- DPRINTK(3, "\n rssi=%u\n"
+ netdev_dbg(priv->net_dev, "\n rssi=%u\n"
" signal=%u\n"
" link_speed=%ux500Kbps\n"
" transmitted_frame_count=%u\n"
" received_fragment_count=%u\n"
" failed_count=%u\n"
" fcs_error_count=%u\n",
- rssi, signal, link_speed, transmitted_frame_count,
- received_fragment_count, failed_count, fcs_error_count);
+ rssi, signal, link_speed, transmitted_frame_count,
+ received_fragment_count, failed_count, fcs_error_count);
/* wake_up_interruptible_all(&priv->confirm_wait); */
complete(&priv->confirm_wait);
}
@@ -1030,7 +964,7 @@ void hostif_phy_information_confirm(struct ks_wlan_private *priv)
static
void hostif_mic_failure_confirm(struct ks_wlan_private *priv)
{
- DPRINTK(3, "mic_failure=%u\n", priv->wpa.mic_failure.failure);
+ netdev_dbg(priv->net_dev, "mic_failure=%u\n", priv->wpa.mic_failure.failure);
hostif_sme_enqueue(priv, SME_MIC_FAILURE_CONFIRM);
}
@@ -1039,8 +973,7 @@ void hostif_event_check(struct ks_wlan_private *priv)
{
unsigned short event;
- DPRINTK(4, "\n");
- event = get_WORD(priv); /* get event */
+ event = get_word(priv); /* get event */
switch (event) {
case HIF_DATA_IND:
hostif_data_indication(priv);
@@ -1095,7 +1028,6 @@ void hostif_event_check(struct ks_wlan_private *priv)
break;
case HIF_AP_SET_CONF:
default:
- //DPRINTK(1, "undefined event[%04X]\n", event);
netdev_err(priv->net_dev, "undefined event[%04X]\n", event);
/* wake_up_all(&priv->confirm_wait); */
complete(&priv->confirm_wait);
@@ -1143,7 +1075,7 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
skb_len = skb->len;
if (skb_len > ETH_FRAME_LEN) {
- DPRINTK(1, "bad length skb_len=%d\n", skb_len);
+ netdev_err(priv->net_dev, "bad length skb_len=%d\n", skb_len);
ret = -EOVERFLOW;
goto err_kfree_skb;
}
@@ -1151,7 +1083,6 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
if (is_disconnect_status(priv->connect_status) ||
(priv->connect_status & FORCE_DISCONNECT) ||
priv->wpa.mic_failure.stop) {
- DPRINTK(3, " DISCONNECT\n");
if (netif_queue_stopped(priv->net_dev))
netif_wake_queue(priv->net_dev);
if (skb)
@@ -1160,8 +1091,8 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
return 0;
}
- /* for PowerSave */
- if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) { /* power save wakeup */
+ /* power save wakeup */
+ if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
if (!netif_queue_stopped(priv->net_dev))
netif_stop_queue(priv->net_dev);
}
@@ -1181,8 +1112,8 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
/* skb check */
eth = (struct ethhdr *)skb->data;
if (memcmp(&priv->eth_addr[0], eth->h_source, ETH_ALEN) != 0) {
- DPRINTK(1, "invalid mac address !!\n");
- DPRINTK(1, "ethernet->h_source=%pM\n", eth->h_source);
+ netdev_err(priv->net_dev, "invalid mac address !!\n");
+ netdev_err(priv->net_dev, "ethernet->h_source=%pM\n", eth->h_source);
ret = -ENXIO;
goto err_kfree;
}
@@ -1197,7 +1128,7 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
/* EtherType/Length check */
if (*(buffer + 1) + (*buffer << 8) > 1500) {
/* ProtocolEAP = *(buffer+1) + (*buffer << 8); */
- /* DPRINTK(2, "Send [SNAP]Type %x\n",ProtocolEAP); */
+ /* netdev_dbg(priv->net_dev, "Send [SNAP]Type %x\n",ProtocolEAP); */
/* SAP/CTL/OUI(6 byte) add */
*p++ = 0xAA; /* DSAP */
*p++ = 0xAA; /* SSAP */
@@ -1207,7 +1138,6 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
*p++ = 0x00; /* OUI ("000000") */
skb_len += 6;
} else {
- DPRINTK(4, "DIX\n");
/* Length(2 byte) delete */
buffer += 2;
length -= 2;
@@ -1224,7 +1154,7 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
eth_proto = ntohs(eth_hdr->h_proto);
/* for MIC FAILURE REPORT check */
- if (eth_proto == ETHER_PROTOCOL_TYPE_EAP &&
+ if (eth_proto == ETH_P_PAE &&
priv->wpa.mic_failure.failure > 0) {
aa1x_hdr = (struct ieee802_1x_hdr *)(eth_hdr + 1);
if (aa1x_hdr->type == IEEE802_1X_TYPE_EAPOL_KEY) {
@@ -1234,20 +1164,21 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
}
if (priv->wpa.rsn_enabled && priv->wpa.key[0].key_len) {
- if (eth_proto == ETHER_PROTOCOL_TYPE_EAP &&
+ /* no encryption */
+ if (eth_proto == ETH_P_PAE &&
priv->wpa.key[1].key_len == 0 &&
priv->wpa.key[2].key_len == 0 &&
priv->wpa.key[3].key_len == 0) {
- pp->auth_type = cpu_to_le16((uint16_t)TYPE_AUTH); /* no encryption */
+ pp->auth_type = cpu_to_le16((uint16_t)TYPE_AUTH);
} else {
if (priv->wpa.pairwise_suite == IW_AUTH_CIPHER_TKIP) {
- MichaelMICFunction(&michael_mic,
- (uint8_t *)priv->wpa.key[0].tx_mic_key,
- (uint8_t *)&pp->data[0],
- (int)skb_len,
- (uint8_t)0, /* priority */
- (uint8_t *)michael_mic.Result);
- memcpy(p, michael_mic.Result, 8);
+ michael_mic_function(&michael_mic,
+ (uint8_t *)priv->wpa.key[0].tx_mic_key,
+ (uint8_t *)&pp->data[0],
+ (int)skb_len,
+ (uint8_t)0, /* priority */
+ (uint8_t *)michael_mic.result);
+ memcpy(p, michael_mic.result, 8);
length += 8;
skb_len += 8;
p += 8;
@@ -1261,7 +1192,7 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
}
}
} else {
- if (eth_proto == ETHER_PROTOCOL_TYPE_EAP)
+ if (eth_proto == ETH_P_PAE)
pp->auth_type = cpu_to_le16((uint16_t)TYPE_AUTH);
else
pp->auth_type = cpu_to_le16((uint16_t)TYPE_DATA);
@@ -1278,11 +1209,11 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
send_packet_complete, skb);
/* MIC FAILURE REPORT check */
- if (eth_proto == ETHER_PROTOCOL_TYPE_EAP &&
+ if (eth_proto == ETH_P_PAE &&
priv->wpa.mic_failure.failure > 0) {
if (keyinfo & WPA_KEY_INFO_ERROR &&
keyinfo & WPA_KEY_INFO_REQUEST) {
- DPRINTK(3, " MIC ERROR Report SET : %04X\n", keyinfo);
+ netdev_err(priv->net_dev, " MIC ERROR Report SET : %04X\n", keyinfo);
hostif_sme_enqueue(priv, SME_MIC_FAILURE_REQUEST);
}
if (priv->wpa.mic_failure.failure == 2)
@@ -1299,11 +1230,11 @@ err_kfree_skb:
return ret;
}
-#define ps_confirm_wait_inc(priv) \
- do { \
- if (atomic_read(&priv->psstatus.status) > PS_ACTIVE_SET) \
- atomic_inc(&priv->psstatus.confirm_wait); \
- } while (0)
+static inline void ps_confirm_wait_inc(struct ks_wlan_private *priv)
+{
+ if (atomic_read(&priv->psstatus.status) > PS_ACTIVE_SET)
+ atomic_inc(&priv->psstatus.confirm_wait);
+}
static
void hostif_mib_get_request(struct ks_wlan_private *priv,
@@ -1311,8 +1242,6 @@ void hostif_mib_get_request(struct ks_wlan_private *priv,
{
struct hostif_mib_get_request_t *pp;
- DPRINTK(3, "\n");
-
pp = hostif_generic_request(sizeof(*pp), HIF_MIB_GET_REQ);
if (!pp)
return;
@@ -1331,12 +1260,8 @@ void hostif_mib_set_request(struct ks_wlan_private *priv,
{
struct hostif_mib_set_request_t *pp;
- DPRINTK(3, "\n");
-
- if (priv->dev_state < DEVICE_STATE_BOOT) {
- DPRINTK(3, "DeviceRemove\n");
+ if (priv->dev_state < DEVICE_STATE_BOOT)
return;
- }
pp = hostif_generic_request(sizeof(*pp), HIF_MIB_SET_REQ);
if (!pp)
@@ -1357,8 +1282,6 @@ void hostif_start_request(struct ks_wlan_private *priv, unsigned char mode)
{
struct hostif_start_request_t *pp;
- DPRINTK(3, "\n");
-
pp = hostif_generic_request(sizeof(*pp), HIF_START_REQ);
if (!pp)
return;
@@ -1373,137 +1296,63 @@ void hostif_start_request(struct ks_wlan_private *priv, unsigned char mode)
priv->scan_ind_count = 0;
}
-static
-void hostif_ps_adhoc_set_request(struct ks_wlan_private *priv)
+static __le16 ks_wlan_cap(struct ks_wlan_private *priv)
{
- struct hostif_ps_adhoc_set_request_t *pp;
- u16 capability;
+ u16 capability = 0x0000;
- DPRINTK(3, "\n");
+ if (priv->reg.preamble == SHORT_PREAMBLE)
+ capability |= WLAN_CAPABILITY_SHORT_PREAMBLE;
- pp = hostif_generic_request(sizeof(*pp), HIF_PS_ADH_SET_REQ);
- if (!pp)
- return;
+ capability &= ~(WLAN_CAPABILITY_PBCC); /* pbcc not support */
- pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type));
- pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode));
- pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type));
- pp->channel = cpu_to_le16((uint16_t)(priv->reg.channel));
- pp->rate_set.size = priv->reg.rate_set.size;
- memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0],
- priv->reg.rate_set.size);
-
- capability = 0x0000;
- if (priv->reg.preamble == SHORT_PREAMBLE) {
- /* short preamble */
- capability |= BSS_CAP_SHORT_PREAMBLE;
- }
- capability &= ~(BSS_CAP_PBCC); /* pbcc not support */
if (priv->reg.phy_type != D_11B_ONLY_MODE) {
- capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */
- capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM */
+ capability |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+ capability &= ~(WLAN_CAPABILITY_DSSS_OFDM);
}
- pp->capability = cpu_to_le16((uint16_t)capability);
- /* send to device request */
- ps_confirm_wait_inc(priv);
- ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL);
+ return cpu_to_le16((uint16_t)capability);
}
-static
-void hostif_infrastructure_set_request(struct ks_wlan_private *priv)
+static void init_request(struct ks_wlan_private *priv, struct hostif_request_t *req)
{
- struct hostif_infrastructure_set_request_t *pp;
- u16 capability;
+ req->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type));
+ req->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode));
+ req->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type));
+ req->rate_set.size = priv->reg.rate_set.size;
+ req->capability = ks_wlan_cap(priv);
+ memcpy(&req->rate_set.body[0], &priv->reg.rate_set.body[0],
+ priv->reg.rate_set.size);
+}
- DPRINTK(3, "ssid.size=%d\n", priv->reg.ssid.size);
+static
+void hostif_ps_adhoc_set_request(struct ks_wlan_private *priv)
+{
+ struct hostif_ps_adhoc_set_request_t *pp;
- pp = hostif_generic_request(sizeof(*pp), HIF_INFRA_SET_REQ);
+ pp = hostif_generic_request(sizeof(*pp), HIF_PS_ADH_SET_REQ);
if (!pp)
return;
- pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type));
- pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode));
- pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type));
-
- pp->rate_set.size = priv->reg.rate_set.size;
- memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0],
- priv->reg.rate_set.size);
- pp->ssid.size = priv->reg.ssid.size;
- memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size);
-
- capability = 0x0000;
- if (priv->reg.preamble == SHORT_PREAMBLE) {
- /* short preamble */
- capability |= BSS_CAP_SHORT_PREAMBLE;
- }
- capability &= ~(BSS_CAP_PBCC); /* pbcc not support */
- if (priv->reg.phy_type != D_11B_ONLY_MODE) {
- capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */
- capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */
- }
- pp->capability = cpu_to_le16((uint16_t)capability);
- pp->beacon_lost_count =
- cpu_to_le16((uint16_t)(priv->reg.beacon_lost_count));
- pp->auth_type = cpu_to_le16((uint16_t)(priv->reg.authenticate_type));
-
- pp->channel_list.body[0] = 1;
- pp->channel_list.body[1] = 8;
- pp->channel_list.body[2] = 2;
- pp->channel_list.body[3] = 9;
- pp->channel_list.body[4] = 3;
- pp->channel_list.body[5] = 10;
- pp->channel_list.body[6] = 4;
- pp->channel_list.body[7] = 11;
- pp->channel_list.body[8] = 5;
- pp->channel_list.body[9] = 12;
- pp->channel_list.body[10] = 6;
- pp->channel_list.body[11] = 13;
- pp->channel_list.body[12] = 7;
- if (priv->reg.phy_type == D_11G_ONLY_MODE) {
- pp->channel_list.size = 13;
- } else {
- pp->channel_list.body[13] = 14;
- pp->channel_list.size = 14;
- }
+ init_request(priv, &pp->request);
+ pp->channel = cpu_to_le16((uint16_t)(priv->reg.channel));
/* send to device request */
ps_confirm_wait_inc(priv);
ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL);
}
-static void hostif_infrastructure_set2_request(struct ks_wlan_private *priv)
+static
+void hostif_infrastructure_set_request(struct ks_wlan_private *priv, int event)
{
- struct hostif_infrastructure_set2_request_t *pp;
- u16 capability;
-
- DPRINTK(2, "ssid.size=%d\n", priv->reg.ssid.size);
+ struct hostif_infrastructure_set_request_t *pp;
- pp = hostif_generic_request(sizeof(*pp), HIF_INFRA_SET2_REQ);
+ pp = hostif_generic_request(sizeof(*pp), event);
if (!pp)
return;
- pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type));
- pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode));
- pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type));
-
- pp->rate_set.size = priv->reg.rate_set.size;
- memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0],
- priv->reg.rate_set.size);
+ init_request(priv, &pp->request);
pp->ssid.size = priv->reg.ssid.size;
memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size);
-
- capability = 0x0000;
- if (priv->reg.preamble == SHORT_PREAMBLE) {
- /* short preamble */
- capability |= BSS_CAP_SHORT_PREAMBLE;
- }
- capability &= ~(BSS_CAP_PBCC); /* pbcc not support */
- if (priv->reg.phy_type != D_11B_ONLY_MODE) {
- capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */
- capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */
- }
- pp->capability = cpu_to_le16((uint16_t)capability);
pp->beacon_lost_count =
cpu_to_le16((uint16_t)(priv->reg.beacon_lost_count));
pp->auth_type = cpu_to_le16((uint16_t)(priv->reg.authenticate_type));
@@ -1528,8 +1377,6 @@ static void hostif_infrastructure_set2_request(struct ks_wlan_private *priv)
pp->channel_list.size = 14;
}
- memcpy(pp->bssid, priv->reg.bssid, ETH_ALEN);
-
/* send to device request */
ps_confirm_wait_inc(priv);
ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL);
@@ -1539,36 +1386,16 @@ static
void hostif_adhoc_set_request(struct ks_wlan_private *priv)
{
struct hostif_adhoc_set_request_t *pp;
- u16 capability;
-
- DPRINTK(3, "\n");
pp = hostif_generic_request(sizeof(*pp), HIF_ADH_SET_REQ);
if (!pp)
return;
- pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type));
- pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode));
- pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type));
+ init_request(priv, &pp->request);
pp->channel = cpu_to_le16((uint16_t)(priv->reg.channel));
- pp->rate_set.size = priv->reg.rate_set.size;
- memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0],
- priv->reg.rate_set.size);
pp->ssid.size = priv->reg.ssid.size;
memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size);
- capability = 0x0000;
- if (priv->reg.preamble == SHORT_PREAMBLE) {
- /* short preamble */
- capability |= BSS_CAP_SHORT_PREAMBLE;
- }
- capability &= ~(BSS_CAP_PBCC); /* pbcc not support */
- if (priv->reg.phy_type != D_11B_ONLY_MODE) {
- capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */
- capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */
- }
- pp->capability = cpu_to_le16((uint16_t)capability);
-
/* send to device request */
ps_confirm_wait_inc(priv);
ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL);
@@ -1578,35 +1405,15 @@ static
void hostif_adhoc_set2_request(struct ks_wlan_private *priv)
{
struct hostif_adhoc_set2_request_t *pp;
- u16 capability;
-
- DPRINTK(3, "\n");
pp = hostif_generic_request(sizeof(*pp), HIF_ADH_SET_REQ);
if (!pp)
return;
- pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type));
- pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode));
- pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type));
- pp->rate_set.size = priv->reg.rate_set.size;
- memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0],
- priv->reg.rate_set.size);
+ init_request(priv, &pp->request);
pp->ssid.size = priv->reg.ssid.size;
memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size);
- capability = 0x0000;
- if (priv->reg.preamble == SHORT_PREAMBLE) {
- /* short preamble */
- capability |= BSS_CAP_SHORT_PREAMBLE;
- }
- capability &= ~(BSS_CAP_PBCC); /* pbcc not support */
- if (priv->reg.phy_type != D_11B_ONLY_MODE) {
- capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */
- capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */
- }
- pp->capability = cpu_to_le16((uint16_t)capability);
-
pp->channel_list.body[0] = priv->reg.channel;
pp->channel_list.size = 1;
memcpy(pp->bssid, priv->reg.bssid, ETH_ALEN);
@@ -1621,8 +1428,6 @@ void hostif_stop_request(struct ks_wlan_private *priv)
{
struct hostif_stop_request_t *pp;
- DPRINTK(3, "\n");
-
pp = hostif_generic_request(sizeof(*pp), HIF_STOP_REQ);
if (!pp)
return;
@@ -1637,8 +1442,6 @@ void hostif_phy_information_request(struct ks_wlan_private *priv)
{
struct hostif_phy_information_request_t *pp;
- DPRINTK(3, "\n");
-
pp = hostif_generic_request(sizeof(*pp), HIF_PHY_INFO_REQ);
if (!pp)
return;
@@ -1663,9 +1466,6 @@ void hostif_power_mgmt_request(struct ks_wlan_private *priv,
{
struct hostif_power_mgmt_request_t *pp;
- DPRINTK(3, "mode=%lu wake_up=%lu receive_dtims=%lu\n", mode, wake_up,
- receive_dtims);
-
pp = hostif_generic_request(sizeof(*pp), HIF_POWER_MGMT_REQ);
if (!pp)
return;
@@ -1685,8 +1485,6 @@ void hostif_sleep_request(struct ks_wlan_private *priv,
{
struct hostif_sleep_request_t *pp;
- DPRINTK(3, "mode=%lu\n", (long)mode);
-
if (mode == SLP_SLEEP) {
pp = hostif_generic_request(sizeof(*pp), HIF_SLEEP_REQ);
if (!pp)
@@ -1700,7 +1498,7 @@ void hostif_sleep_request(struct ks_wlan_private *priv,
atomic_set(&priv->sleepstatus.wakeup_request, 1);
queue_delayed_work(priv->wq, &priv->rw_dwork, 1);
} else {
- DPRINTK(3, "invalid mode %ld\n", (long)mode);
+ netdev_err(priv->net_dev, "invalid mode %ld\n", (long)mode);
return;
}
}
@@ -1712,8 +1510,6 @@ void hostif_bss_scan_request(struct ks_wlan_private *priv,
{
struct hostif_bss_scan_request_t *pp;
- DPRINTK(2, "\n");
-
pp = hostif_generic_request(sizeof(*pp), HIF_SCAN_REQ);
if (!pp)
return;
@@ -1764,8 +1560,6 @@ void hostif_mic_failure_request(struct ks_wlan_private *priv,
{
struct hostif_mic_failure_request_t *pp;
- DPRINTK(3, "count=%d :: timer=%d\n", failure_count, timer);
-
pp = hostif_generic_request(sizeof(*pp), HIF_MIC_FAILURE_REQ);
if (!pp)
return;
@@ -1805,14 +1599,12 @@ static void devio_rec_ind(struct ks_wlan_private *priv, unsigned char *p,
void hostif_receive(struct ks_wlan_private *priv, unsigned char *p,
unsigned int size)
{
- DPRINTK(4, "\n");
-
devio_rec_ind(priv, p, size);
priv->rxp = p;
priv->rx_size = size;
- if (get_WORD(priv) == priv->rx_size) { /* length check !! */
+ if (get_word(priv) == priv->rx_size) { /* length check !! */
hostif_event_check(priv); /* event check */
}
}
@@ -2137,11 +1929,11 @@ void hostif_sme_mode_setup(struct ks_wlan_private *priv)
case MODE_INFRASTRUCTURE:
/* Infrastructure mode */
if (!is_valid_ether_addr((u8 *)priv->reg.bssid)) {
- hostif_infrastructure_set_request(priv);
+ hostif_infrastructure_set_request(priv, HIF_INFRA_SET_REQ);
} else {
- hostif_infrastructure_set2_request(priv);
- DPRINTK(2,
- "Infra bssid = %pM\n", priv->reg.bssid);
+ hostif_infrastructure_set_request(priv, HIF_INFRA_SET2_REQ);
+ netdev_dbg(priv->net_dev,
+ "Infra bssid = %pM\n", priv->reg.bssid);
}
break;
case MODE_ADHOC:
@@ -2150,8 +1942,8 @@ void hostif_sme_mode_setup(struct ks_wlan_private *priv)
hostif_adhoc_set_request(priv);
} else {
hostif_adhoc_set2_request(priv);
- DPRINTK(2,
- "Adhoc bssid = %pM\n", priv->reg.bssid);
+ netdev_dbg(priv->net_dev,
+ "Adhoc bssid = %pM\n", priv->reg.bssid);
}
break;
default:
@@ -2169,8 +1961,6 @@ void hostif_sme_multicast_set(struct ks_wlan_private *priv)
__le32 filter_type;
int i = 0;
- DPRINTK(3, "\n");
-
spin_lock(&priv->multicast_spin);
memset(set_address, 0, NIC_MAX_MCAST_LIST * ETH_ALEN);
@@ -2220,7 +2010,6 @@ void hostif_sme_power_mgmt_set(struct ks_wlan_private *priv)
{
unsigned long mode, wake_up, receive_dtims;
- DPRINTK(3, "\n");
switch (priv->reg.power_mgmt) {
case POWER_MGMT_ACTIVE:
mode = POWER_ACTIVE;
@@ -2261,7 +2050,6 @@ void hostif_sme_power_mgmt_set(struct ks_wlan_private *priv)
static
void hostif_sme_sleep_set(struct ks_wlan_private *priv)
{
- DPRINTK(3, "\n");
switch (priv->sleep_mode) {
case SLP_SLEEP:
hostif_sleep_request(priv, priv->sleep_mode);
@@ -2345,7 +2133,6 @@ void hostif_sme_set_pmksa(struct ks_wlan_private *priv)
struct pmk_t *pmk;
int i;
- DPRINTK(4, "pmklist.size=%d\n", priv->pmklist.size);
i = 0;
list_for_each_entry(pmk, &priv->pmklist.head, list) {
if (i < PMK_LIST_MAX) {
@@ -2369,7 +2156,6 @@ void hostif_sme_execute(struct ks_wlan_private *priv, int event)
{
__le32 val;
- DPRINTK(3, "event=%d\n", event);
switch (event) {
case SME_START:
if (priv->dev_state == DEVICE_STATE_BOOT)
@@ -2403,8 +2189,8 @@ void hostif_sme_execute(struct ks_wlan_private *priv, int event)
priv->wpa.mic_failure.failure - 1,
priv->wpa.mic_failure.counter);
} else {
- DPRINTK(4, "SME_MIC_FAILURE_REQUEST: failure count=%u error?\n",
- priv->wpa.mic_failure.failure);
+ netdev_err(priv->net_dev, "SME_MIC_FAILURE_REQUEST: failure count=%u error?\n",
+ priv->wpa.mic_failure.failure);
}
break;
case SME_MIC_FAILURE_CONFIRM:
@@ -2544,8 +2330,6 @@ void hostif_sme_task(unsigned long dev)
{
struct ks_wlan_private *priv = (struct ks_wlan_private *)dev;
- DPRINTK(3, "\n");
-
if (priv->dev_state < DEVICE_STATE_BOOT)
return;
@@ -2561,16 +2345,10 @@ void hostif_sme_task(unsigned long dev)
/* send to Station Management Entity module */
void hostif_sme_enqueue(struct ks_wlan_private *priv, unsigned short event)
{
- DPRINTK(3, "\n");
-
/* enqueue sme event */
if (cnt_smeqbody(priv) < (SME_EVENT_BUFF_SIZE - 1)) {
priv->sme_i.event_buff[priv->sme_i.qtail] = event;
inc_smeqtail(priv);
-#ifdef KS_WLAN_DEBUG
- if (priv->sme_i.max_event_count < cnt_smeqbody(priv))
- priv->sme_i.max_event_count = cnt_smeqbody(priv);
-#endif /* KS_WLAN_DEBUG */
} else {
/* in case of buffer overflow */
netdev_err(priv->net_dev, "sme queue buffer overflow\n");
@@ -2579,55 +2357,79 @@ void hostif_sme_enqueue(struct ks_wlan_private *priv, unsigned short event)
tasklet_schedule(&priv->sme_task);
}
-int hostif_init(struct ks_wlan_private *priv)
+static inline void hostif_aplist_init(struct ks_wlan_private *priv)
{
- int i;
-
- DPRINTK(3, "\n");
-
+ size_t size = LOCAL_APLIST_MAX * sizeof(struct local_ap_t);
priv->aplist.size = 0;
- for (i = 0; i < LOCAL_APLIST_MAX; i++)
- memset(&priv->aplist.ap[i], 0, sizeof(struct local_ap_t));
+ memset(&priv->aplist.ap[0], 0, size);
+}
+
+static inline void hostif_status_init(struct ks_wlan_private *priv)
+{
priv->infra_status = 0;
priv->current_rate = 4;
priv->connect_status = DISCONNECT_STATUS;
+}
- spin_lock_init(&priv->multicast_spin);
+static inline void hostif_sme_init(struct ks_wlan_private *priv)
+{
+ priv->sme_i.sme_status = SME_IDLE;
+ priv->sme_i.qhead = 0;
+ priv->sme_i.qtail = 0;
+ spin_lock_init(&priv->sme_i.sme_spin);
+ priv->sme_i.sme_flag = 0;
+ tasklet_init(&priv->sme_task, hostif_sme_task, (unsigned long)priv);
+}
- spin_lock_init(&priv->dev_read_lock);
- init_waitqueue_head(&priv->devread_wait);
- priv->dev_count = 0;
- atomic_set(&priv->event_count, 0);
- atomic_set(&priv->rec_count, 0);
+static inline void hostif_wpa_init(struct ks_wlan_private *priv)
+{
+ memset(&priv->wpa, 0, sizeof(priv->wpa));
+ priv->wpa.rsn_enabled = 0;
+ priv->wpa.mic_failure.failure = 0;
+ priv->wpa.mic_failure.last_failure_time = 0;
+ priv->wpa.mic_failure.stop = 0;
+}
- /* for power save */
+static inline void hostif_power_save_init(struct ks_wlan_private *priv)
+{
atomic_set(&priv->psstatus.status, PS_NONE);
atomic_set(&priv->psstatus.confirm_wait, 0);
atomic_set(&priv->psstatus.snooze_guard, 0);
init_completion(&priv->psstatus.wakeup_wait);
INIT_WORK(&priv->wakeup_work, ks_wlan_hw_wakeup_task);
+}
+
+static inline void hostif_pmklist_init(struct ks_wlan_private *priv)
+{
+ int i;
- /* WPA */
- memset(&priv->wpa, 0, sizeof(priv->wpa));
- priv->wpa.rsn_enabled = 0;
- priv->wpa.mic_failure.failure = 0;
- priv->wpa.mic_failure.last_failure_time = 0;
- priv->wpa.mic_failure.stop = 0;
memset(&priv->pmklist, 0, sizeof(priv->pmklist));
INIT_LIST_HEAD(&priv->pmklist.head);
for (i = 0; i < PMK_LIST_MAX; i++)
INIT_LIST_HEAD(&priv->pmklist.pmk[i].list);
+}
- priv->sme_i.sme_status = SME_IDLE;
- priv->sme_i.qhead = 0;
- priv->sme_i.qtail = 0;
-#ifdef KS_WLAN_DEBUG
- priv->sme_i.max_event_count = 0;
-#endif
- spin_lock_init(&priv->sme_i.sme_spin);
- priv->sme_i.sme_flag = 0;
+static inline void hostif_counters_init(struct ks_wlan_private *priv)
+{
+ priv->dev_count = 0;
+ atomic_set(&priv->event_count, 0);
+ atomic_set(&priv->rec_count, 0);
+}
- tasklet_init(&priv->sme_task, hostif_sme_task, (unsigned long)priv);
+int hostif_init(struct ks_wlan_private *priv)
+{
+ hostif_aplist_init(priv);
+ hostif_status_init(priv);
+
+ spin_lock_init(&priv->multicast_spin);
+ spin_lock_init(&priv->dev_read_lock);
+ init_waitqueue_head(&priv->devread_wait);
+
+ hostif_counters_init(priv);
+ hostif_power_save_init(priv);
+ hostif_wpa_init(priv);
+ hostif_pmklist_init(priv);
+ hostif_sme_init(priv);
return 0;
}
diff --git a/drivers/staging/ks7010/ks_hostif.h b/drivers/staging/ks7010/ks_hostif.h
index 5bae8d468e23..2f918b11b337 100644
--- a/drivers/staging/ks7010/ks_hostif.h
+++ b/drivers/staging/ks7010/ks_hostif.h
@@ -13,6 +13,7 @@
#define _KS_HOSTIF_H_
#include <linux/compiler.h>
+#include <linux/ieee80211.h>
/*
* HOST-MAC I/F events
@@ -58,7 +59,7 @@
/*
* HOST-MAC I/F data structure
- * Byte alignmet Little Endian
+ * Byte alignment Little Endian
*/
struct hostif_hdr {
@@ -224,10 +225,9 @@ struct hostif_start_confirm_t {
__le16 result_code;
} __packed;
-#define SSID_MAX_SIZE 32
struct ssid_t {
u8 size;
- u8 body[SSID_MAX_SIZE];
+ u8 body[IEEE80211_MAX_SSID_LEN];
u8 ssid_pad;
} __packed;
@@ -284,20 +284,8 @@ struct ap_info_t {
u8 pad0; /* +09 */
__le16 beacon_period; /* +10 */
__le16 capability; /* +12 */
-#define BSS_CAP_ESS BIT(0)
-#define BSS_CAP_IBSS BIT(1)
-#define BSS_CAP_CF_POLABLE BIT(2)
-#define BSS_CAP_CF_POLL_REQ BIT(3)
-#define BSS_CAP_PRIVACY BIT(4)
-#define BSS_CAP_SHORT_PREAMBLE BIT(5)
-#define BSS_CAP_PBCC BIT(6)
-#define BSS_CAP_CHANNEL_AGILITY BIT(7)
-#define BSS_CAP_SHORT_SLOT_TIME BIT(10)
-#define BSS_CAP_DSSS_OFDM BIT(13)
u8 frame_type; /* +14 */
u8 ch_info; /* +15 */
-#define FRAME_TYPE_BEACON 0x80
-#define FRAME_TYPE_PROBE_RESP 0x50
__le16 body_size; /* +16 */
u8 body[1024]; /* +18 */
/* +1032 */
@@ -347,6 +335,22 @@ struct hostif_stop_confirm_t {
__le16 result_code;
} __packed;
+#define D_11B_ONLY_MODE 0
+#define D_11G_ONLY_MODE 1
+#define D_11BG_COMPATIBLE_MODE 2
+#define D_11A_ONLY_MODE 3
+
+#define CTS_MODE_FALSE 0
+#define CTS_MODE_TRUE 1
+
+struct hostif_request_t {
+ __le16 phy_type;
+ __le16 cts_mode;
+ __le16 scan_type;
+ __le16 capability;
+ struct rate_set16_t rate_set;
+} __packed;
+
/**
* struct hostif_ps_adhoc_set_request_t - pseudo adhoc mode
* @capability: bit5 : preamble
@@ -356,18 +360,8 @@ struct hostif_stop_confirm_t {
*/
struct hostif_ps_adhoc_set_request_t {
struct hostif_hdr header;
- __le16 phy_type;
-#define D_11B_ONLY_MODE 0
-#define D_11G_ONLY_MODE 1
-#define D_11BG_COMPATIBLE_MODE 2
-#define D_11A_ONLY_MODE 3
- __le16 cts_mode;
-#define CTS_MODE_FALSE 0
-#define CTS_MODE_TRUE 1
+ struct hostif_request_t request;
__le16 channel;
- struct rate_set16_t rate_set;
- __le16 capability;
- __le16 scan_type;
} __packed;
struct hostif_ps_adhoc_set_confirm_t {
@@ -375,48 +369,23 @@ struct hostif_ps_adhoc_set_confirm_t {
__le16 result_code;
} __packed;
-/**
- * struct hostif_infrastructure_set_request_t
- * @capability: bit5 : preamble
- * bit6 : pbcc - Not supported always 0
- * bit10 : ShortSlotTime
- * bit13 : DSSS-OFDM - Not supported always 0
- */
-struct hostif_infrastructure_set_request_t {
- struct hostif_hdr header;
- __le16 phy_type;
- __le16 cts_mode;
- struct rate_set16_t rate_set;
- struct ssid_t ssid;
- __le16 capability;
- __le16 beacon_lost_count;
- __le16 auth_type;
#define AUTH_TYPE_OPEN_SYSTEM 0
#define AUTH_TYPE_SHARED_KEY 1
- struct channel_list_t channel_list;
- __le16 scan_type;
-} __packed;
/**
- * struct hostif_infrastructure_set2_request_t
+ * struct hostif_infrastructure_set_request_t
* @capability: bit5 : preamble
* bit6 : pbcc - Not supported always 0
* bit10 : ShortSlotTime
* bit13 : DSSS-OFDM - Not supported always 0
*/
-struct hostif_infrastructure_set2_request_t {
+struct hostif_infrastructure_set_request_t {
struct hostif_hdr header;
- __le16 phy_type;
- __le16 cts_mode;
- struct rate_set16_t rate_set;
+ struct hostif_request_t request;
struct ssid_t ssid;
- __le16 capability;
__le16 beacon_lost_count;
__le16 auth_type;
-#define AUTH_TYPE_OPEN_SYSTEM 0
-#define AUTH_TYPE_SHARED_KEY 1
struct channel_list_t channel_list;
- __le16 scan_type;
u8 bssid[ETH_ALEN];
} __packed;
@@ -434,13 +403,9 @@ struct hostif_infrastructure_set_confirm_t {
*/
struct hostif_adhoc_set_request_t {
struct hostif_hdr header;
- __le16 phy_type;
- __le16 cts_mode;
- __le16 channel;
- struct rate_set16_t rate_set;
+ struct hostif_request_t request;
struct ssid_t ssid;
- __le16 capability;
- __le16 scan_type;
+ __le16 channel;
} __packed;
/**
@@ -452,13 +417,9 @@ struct hostif_adhoc_set_request_t {
*/
struct hostif_adhoc_set2_request_t {
struct hostif_hdr header;
- __le16 phy_type;
- __le16 cts_mode;
+ struct hostif_request_t request;
__le16 reserved;
- struct rate_set16_t rate_set;
struct ssid_t ssid;
- __le16 capability;
- __le16 scan_type;
struct channel_list_t channel_list;
u8 bssid[ETH_ALEN];
} __packed;
@@ -475,8 +436,6 @@ struct last_associate_t {
struct association_request_t {
u8 type;
-#define FRAME_TYPE_ASSOC_REQ 0x00
-#define FRAME_TYPE_REASSOC_REQ 0x20
u8 pad;
__le16 capability;
__le16 listen_interval;
@@ -486,8 +445,6 @@ struct association_request_t {
struct association_response_t {
u8 type;
-#define FRAME_TYPE_ASSOC_RESP 0x10
-#define FRAME_TYPE_REASSOC_RESP 0x30
u8 pad;
__le16 capability;
__le16 status;
diff --git a/drivers/staging/ks7010/ks_wlan.h b/drivers/staging/ks7010/ks_wlan.h
index 3767079be00d..1b7036c32d1c 100644
--- a/drivers/staging/ks7010/ks_wlan.h
+++ b/drivers/staging/ks7010/ks_wlan.h
@@ -34,16 +34,6 @@
#include "ks7010_sdio.h"
-#ifdef KS_WLAN_DEBUG
-#define DPRINTK(n, fmt, args...) \
- do { \
- if (KS_WLAN_DEBUG > (n)) \
- pr_notice("%s: "fmt, __func__, ## args); \
- } while (0)
-#else
-#define DPRINTK(n, fmt, args...)
-#endif
-
struct ks_wlan_parameter {
u8 operation_mode; /* Operation Mode */
u8 channel; /* Channel */
@@ -64,7 +54,7 @@ struct ks_wlan_parameter {
#define BEACON_LOST_COUNT_MAX 65535
u32 beacon_lost_count; /* Beacon Lost Count */
u32 rts; /* RTS Threashold */
- u32 fragment; /* Fragmentation Threashold */
+ u32 fragment; /* Fragmentation Threshold */
u32 privacy_invoked;
u32 wep_index;
struct {
@@ -97,7 +87,7 @@ enum {
#define SME_WEP_VAL2 BIT(6)
#define SME_WEP_VAL3 BIT(7)
#define SME_WEP_VAL4 BIT(8)
-#define SME_WEP_VAL_MASK (SME_WEP_VAL1 | SME_WEP_VAL2 | SME_WEP_VAL3 | SME_WEP_VAL4)
+#define SME_WEP_VAL_MASK GENMASK(8, 5)
#define SME_RSN BIT(9)
#define SME_RSN_MULTICAST BIT(10)
#define SME_RSN_UNICAST BIT(11)
@@ -202,10 +192,6 @@ struct sme_info {
int event_buff[SME_EVENT_BUFF_SIZE];
unsigned int qhead;
unsigned int qtail;
-#ifdef KS_WLAN_DEBUG
- /* for debug */
- unsigned int max_event_count;
-#endif
spinlock_t sme_spin;
unsigned long sme_flag;
};
@@ -420,7 +406,6 @@ struct ks_wlan_private {
struct tasklet_struct rx_bh_task;
struct net_device *net_dev;
- int reg_net; /* register_netdev */
struct net_device_stats nstats;
struct iw_statistics wstats;
@@ -470,7 +455,7 @@ struct ks_wlan_private {
unsigned char firmware_version[128 + 1];
int version_size;
- int mac_address_valid; /* Mac Address Status */
+ bool mac_address_valid; /* Mac Address Status */
int dev_state;
diff --git a/drivers/staging/ks7010/ks_wlan_ioctl.h b/drivers/staging/ks7010/ks_wlan_ioctl.h
index 28b381c24b42..121e7cb808a2 100644
--- a/drivers/staging/ks7010/ks_wlan_ioctl.h
+++ b/drivers/staging/ks7010/ks_wlan_ioctl.h
@@ -58,7 +58,6 @@
#include "ks_wlan.h"
#include <linux/netdevice.h>
-int ks_wlan_read_config_file(struct ks_wlan_private *priv);
int ks_wlan_setup_parameter(struct ks_wlan_private *priv,
unsigned int commit_flag);
diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c
index e48c55769c94..9078e13b0d4a 100644
--- a/drivers/staging/ks7010/ks_wlan_net.c
+++ b/drivers/staging/ks7010/ks_wlan_net.c
@@ -86,7 +86,7 @@ int ks_wlan_update_phy_information(struct ks_wlan_private *priv)
{
struct iw_statistics *wstats = &priv->wstats;
- DPRINTK(4, "in_interrupt = %ld\n", in_interrupt());
+ netdev_dbg(priv->net_dev, "in_interrupt = %ld\n", in_interrupt());
if (priv->dev_state < DEVICE_STATE_READY)
return -EBUSY; /* not finished initialize */
@@ -103,7 +103,7 @@ int ks_wlan_update_phy_information(struct ks_wlan_private *priv)
/* interruptible_sleep_on_timeout(&priv->confirm_wait, HZ/2); */
if (!wait_for_completion_interruptible_timeout
(&priv->confirm_wait, HZ / 2)) {
- DPRINTK(1, "wait time out!!\n");
+ netdev_dbg(priv->net_dev, "wait time out!!\n");
}
atomic_inc(&update_phyinfo);
@@ -116,15 +116,13 @@ int ks_wlan_update_phy_information(struct ks_wlan_private *priv)
static
void ks_wlan_update_phyinfo_timeout(struct timer_list *unused)
{
- DPRINTK(4, "in_interrupt = %ld\n", in_interrupt());
+ pr_debug("in_interrupt = %ld\n", in_interrupt());
atomic_set(&update_phyinfo, 0);
}
int ks_wlan_setup_parameter(struct ks_wlan_private *priv,
unsigned int commit_flag)
{
- DPRINTK(2, "\n");
-
hostif_sme_enqueue(priv, SME_STOP_REQUEST);
if (commit_flag & SME_RTS)
@@ -268,8 +266,6 @@ static int ks_wlan_set_essid(struct net_device *dev,
struct ks_wlan_private *priv = netdev_priv(dev);
size_t len;
- DPRINTK(2, " %d\n", dwrq->flags);
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
@@ -280,7 +276,6 @@ static int ks_wlan_set_essid(struct net_device *dev,
memset(priv->reg.ssid.body, 0, sizeof(priv->reg.ssid.body));
priv->reg.ssid.size = 0;
} else {
-#if 1
len = dwrq->length;
/* iwconfig uses nul termination in SSID.. */
if (len > 0 && extra[len - 1] == '\0')
@@ -290,28 +285,14 @@ static int ks_wlan_set_essid(struct net_device *dev,
if (len > IW_ESSID_MAX_SIZE)
return -EINVAL;
-#else
- /* Check the size of the string */
- if (dwrq->length > IW_ESSID_MAX_SIZE + 1)
- return -E2BIG;
-
-#endif
-
/* Set the SSID */
memset(priv->reg.ssid.body, 0, sizeof(priv->reg.ssid.body));
-
-#if 1
memcpy(priv->reg.ssid.body, extra, len);
priv->reg.ssid.size = len;
-#else
- memcpy(priv->reg.ssid.body, extra, dwrq->length);
- priv->reg.ssid.size = dwrq->length;
-#endif
}
/* Write it to the card */
priv->need_commit |= SME_MODE_SET;
-// return -EINPROGRESS; /* Call commit handler */
ks_wlan_setup_parameter(priv, priv->need_commit);
priv->need_commit = 0;
return 0;
@@ -352,8 +333,6 @@ static int ks_wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
{
struct ks_wlan_private *priv = netdev_priv(dev);
- DPRINTK(2, "\n");
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
@@ -370,7 +349,7 @@ static int ks_wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
return -EOPNOTSUPP;
}
- DPRINTK(2, "bssid = %pM\n", priv->reg.bssid);
+ netdev_dbg(dev, "bssid = %pM\n", priv->reg.bssid);
/* Write it to the card */
if (priv->need_commit) {
@@ -683,8 +662,8 @@ static int ks_wlan_get_rate(struct net_device *dev,
{
struct ks_wlan_private *priv = netdev_priv(dev);
- DPRINTK(2, "in_interrupt = %ld update_phyinfo = %d\n",
- in_interrupt(), atomic_read(&update_phyinfo));
+ netdev_dbg(dev, "in_interrupt = %ld update_phyinfo = %d\n",
+ in_interrupt(), atomic_read(&update_phyinfo));
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
@@ -785,8 +764,6 @@ static int ks_wlan_set_mode(struct net_device *dev,
{
struct ks_wlan_private *priv = netdev_priv(dev);
- DPRINTK(2, "mode=%d\n", *uwrq);
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
@@ -848,8 +825,6 @@ static int ks_wlan_set_encode(struct net_device *dev,
int current_index = priv->reg.wep_index;
int i;
- DPRINTK(2, "flags=%04X\n", dwrq->flags);
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
@@ -986,7 +961,6 @@ static int ks_wlan_get_encode(struct net_device *dev,
/* dwrq->flags |= IW_ENCODE_NOKEY; */
}
dwrq->flags |= index + 1;
- DPRINTK(2, "encoding flag = 0x%04X\n", dwrq->flags);
/* Copy the key to the user buffer */
if ((index >= 0) && (index < 4))
dwrq->length = priv->reg.wep_key[index].size;
@@ -1058,8 +1032,6 @@ static int ks_wlan_get_range(struct net_device *dev,
struct iw_range *range = (struct iw_range *)extra;
int i, k;
- DPRINTK(2, "\n");
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
@@ -1300,8 +1272,6 @@ static int ks_wlan_set_scan(struct net_device *dev,
struct ks_wlan_private *priv = netdev_priv(dev);
struct iw_scan_req *req = NULL;
- DPRINTK(2, "\n");
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
@@ -1366,8 +1336,8 @@ static inline char *ks_wlan_translate_scan(struct net_device *dev,
/* Add mode */
iwe.cmd = SIOCGIWMODE;
capabilities = ap->capability;
- if (capabilities & (BSS_CAP_ESS | BSS_CAP_IBSS)) {
- if (capabilities & BSS_CAP_ESS)
+ if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+ if (capabilities & WLAN_CAPABILITY_ESS)
iwe.u.mode = IW_MODE_INFRA;
else
iwe.u.mode = IW_MODE_ADHOC;
@@ -1396,7 +1366,7 @@ static inline char *ks_wlan_translate_scan(struct net_device *dev,
/* Add encryption capability */
iwe.cmd = SIOCGIWENCODE;
- if (capabilities & BSS_CAP_PRIVACY)
+ if (capabilities & WLAN_CAPABILITY_PRIVACY)
iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
else
iwe.u.data.flags = IW_ENCODE_DISABLED;
@@ -1450,7 +1420,7 @@ static inline char *ks_wlan_translate_scan(struct net_device *dev,
pbuf += sprintf(pbuf, "%02x", ap->rsn_ie.body[i]);
iwe.u.data.length += (ap->rsn_ie.size) * 2;
- DPRINTK(4, "ap->rsn.size=%d\n", ap->rsn_ie.size);
+ netdev_dbg(dev, "ap->rsn.size=%d\n", ap->rsn_ie.size);
current_ev =
iwe_stream_add_point(info, current_ev, end_buf, &iwe,
@@ -1472,8 +1442,8 @@ static inline char *ks_wlan_translate_scan(struct net_device *dev,
pbuf += sprintf(pbuf, "%02x", ap->wpa_ie.body[i]);
iwe.u.data.length += (ap->wpa_ie.size) * 2;
- DPRINTK(4, "ap->rsn.size=%d\n", ap->wpa_ie.size);
- DPRINTK(4, "iwe.u.data.length=%d\n", iwe.u.data.length);
+ netdev_dbg(dev, "ap->rsn.size=%d\n", ap->wpa_ie.size);
+ netdev_dbg(dev, "iwe.u.data.length=%d\n", iwe.u.data.length);
current_ev =
iwe_stream_add_point(info, current_ev, end_buf, &iwe,
@@ -1494,21 +1464,16 @@ static int ks_wlan_get_scan(struct net_device *dev,
int i;
char *current_ev = extra;
- DPRINTK(2, "\n");
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
/* for SLEEP MODE */
- if (priv->sme_i.sme_flag & SME_AP_SCAN) {
- DPRINTK(2, "flag AP_SCAN\n");
+ if (priv->sme_i.sme_flag & SME_AP_SCAN)
return -EAGAIN;
- }
if (priv->aplist.size == 0) {
/* Client error, no scan results...
* The caller need to restart the scan.
*/
- DPRINTK(2, "aplist 0\n");
return -ENODATA;
}
@@ -1552,8 +1517,6 @@ static int ks_wlan_set_genie(struct net_device *dev,
{
struct ks_wlan_private *priv = netdev_priv(dev);
- DPRINTK(2, "\n");
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
/* for SLEEP MODE */
@@ -1569,8 +1532,6 @@ static int ks_wlan_set_auth_mode(struct net_device *dev,
int index = (vwrq->flags & IW_AUTH_INDEX);
int value = vwrq->value;
- DPRINTK(2, "index=%d:value=%08X\n", index, value);
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
/* for SLEEP MODE */
@@ -1702,8 +1663,6 @@ static int ks_wlan_get_auth_mode(struct net_device *dev,
struct ks_wlan_private *priv = netdev_priv(dev);
int index = (vwrq->flags & IW_AUTH_INDEX);
- DPRINTK(2, "index=%d\n", index);
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
@@ -1753,9 +1712,6 @@ static int ks_wlan_set_encode_ext(struct net_device *dev,
if (!enc)
return -EINVAL;
- DPRINTK(2, "flags=%04X:: ext_flags=%08X\n", dwrq->flags,
- enc->ext_flags);
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
@@ -1865,8 +1821,6 @@ static int ks_wlan_set_pmksa(struct net_device *dev,
struct pmk_t *pmk;
struct list_head *ptr;
- DPRINTK(2, "\n");
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
@@ -1875,7 +1829,6 @@ static int ks_wlan_set_pmksa(struct net_device *dev,
return -EINVAL;
pmksa = (struct iw_pmksa *)extra;
- DPRINTK(2, "cmd=%d\n", pmksa->cmd);
switch (pmksa->cmd) {
case IW_PMKSA_ADD:
@@ -1987,8 +1940,6 @@ static int ks_wlan_set_stop_request(struct net_device *dev,
{
struct ks_wlan_private *priv = netdev_priv(dev);
- DPRINTK(2, "\n");
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
@@ -2009,8 +1960,6 @@ static int ks_wlan_set_mlme(struct net_device *dev,
struct iw_mlme *mlme = (struct iw_mlme *)extra;
__u32 mode;
- DPRINTK(2, ":%d :%d\n", mlme->cmd, mlme->reason_code);
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
@@ -2269,8 +2218,6 @@ static int ks_wlan_set_sleep_mode(struct net_device *dev,
{
struct ks_wlan_private *priv = netdev_priv(dev);
- DPRINTK(2, "\n");
-
if (*uwrq == SLP_SLEEP) {
priv->sleep_mode = *uwrq;
netdev_info(dev, "SET_SLEEP_MODE %d\n", priv->sleep_mode);
@@ -2296,7 +2243,6 @@ static int ks_wlan_get_sleep_mode(struct net_device *dev,
{
struct ks_wlan_private *priv = netdev_priv(dev);
- DPRINTK(2, "GET_SLEEP_MODE %d\n", priv->sleep_mode);
*uwrq = priv->sleep_mode;
return 0;
@@ -2310,8 +2256,6 @@ static int ks_wlan_set_wps_enable(struct net_device *dev,
{
struct ks_wlan_private *priv = netdev_priv(dev);
- DPRINTK(2, "\n");
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
/* for SLEEP MODE */
@@ -2331,8 +2275,6 @@ static int ks_wlan_get_wps_enable(struct net_device *dev,
{
struct ks_wlan_private *priv = netdev_priv(dev);
- DPRINTK(2, "\n");
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
/* for SLEEP MODE */
@@ -2350,12 +2292,8 @@ static int ks_wlan_set_wps_probe_req(struct net_device *dev,
unsigned char len;
struct ks_wlan_private *priv = netdev_priv(dev);
- DPRINTK(2, "\n");
-
if (priv->sleep_mode == SLP_SLEEP)
return -EPERM;
- /* for SLEEP MODE */
- DPRINTK(2, "dwrq->length=%d\n", dwrq->length);
/* length check */
if (p[1] + 2 != dwrq->length || dwrq->length > 256)
@@ -2367,10 +2305,10 @@ static int ks_wlan_set_wps_probe_req(struct net_device *dev,
memcpy(priv->wps.ie, &len, sizeof(len));
p = memcpy(priv->wps.ie + 1, p, len);
- DPRINTK(2, "%d(%#x): %02X %02X %02X %02X ... %02X %02X %02X\n",
- priv->wps.ielen, priv->wps.ielen, p[0], p[1], p[2], p[3],
- p[priv->wps.ielen - 3], p[priv->wps.ielen - 2],
- p[priv->wps.ielen - 1]);
+ netdev_dbg(dev, "%d(%#x): %02X %02X %02X %02X ... %02X %02X %02X\n",
+ priv->wps.ielen, priv->wps.ielen, p[0], p[1], p[2], p[3],
+ p[priv->wps.ielen - 3], p[priv->wps.ielen - 2],
+ p[priv->wps.ielen - 1]);
hostif_sme_enqueue(priv, SME_WPS_PROBE_REQUEST);
@@ -2789,7 +2727,6 @@ static int ks_wlan_netdev_ioctl(struct net_device *dev, struct ifreq *rq,
ret = -EOPNOTSUPP;
}
- DPRINTK(5, "return=%d\n", ret);
return ret;
}
@@ -2815,7 +2752,7 @@ int ks_wlan_set_mac_address(struct net_device *dev, void *addr)
memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len);
memcpy(priv->eth_addr, mac_addr->sa_data, ETH_ALEN);
- priv->mac_address_valid = 0;
+ priv->mac_address_valid = false;
hostif_sme_enqueue(priv, SME_MACADDRESS_SET_REQUEST);
netdev_info(dev, "ks_wlan: MAC ADDRESS = %pM\n", priv->eth_addr);
return 0;
@@ -2826,8 +2763,8 @@ void ks_wlan_tx_timeout(struct net_device *dev)
{
struct ks_wlan_private *priv = netdev_priv(dev);
- DPRINTK(1, "head(%d) tail(%d)!!\n", priv->tx_dev.qhead,
- priv->tx_dev.qtail);
+ netdev_dbg(dev, "head(%d) tail(%d)!!\n", priv->tx_dev.qhead,
+ priv->tx_dev.qtail);
if (!netif_queue_stopped(dev))
netif_stop_queue(dev);
priv->nstats.tx_errors++;
@@ -2840,7 +2777,7 @@ int ks_wlan_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct ks_wlan_private *priv = netdev_priv(dev);
int ret;
- DPRINTK(3, "in_interrupt()=%ld\n", in_interrupt());
+ netdev_dbg(dev, "in_interrupt()=%ld\n", in_interrupt());
if (!skb) {
netdev_err(dev, "ks_wlan: skb == NULL!!!\n");
@@ -2858,15 +2795,13 @@ int ks_wlan_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_trans_update(dev);
if (ret)
- DPRINTK(4, "hostif_data_request error: =%d\n", ret);
+ netdev_err(dev, "hostif_data_request error: =%d\n", ret);
return 0;
}
void send_packet_complete(struct ks_wlan_private *priv, struct sk_buff *skb)
{
- DPRINTK(3, "\n");
-
priv->nstats.tx_packets++;
if (netif_queue_stopped(priv->net_dev))
@@ -2887,7 +2822,6 @@ void ks_wlan_set_multicast_list(struct net_device *dev)
{
struct ks_wlan_private *priv = netdev_priv(dev);
- DPRINTK(4, "\n");
if (priv->dev_state < DEVICE_STATE_READY)
return; /* not finished initialize */
hostif_sme_enqueue(priv, SME_MULTICAST_REQUEST);
@@ -2914,9 +2848,6 @@ int ks_wlan_close(struct net_device *dev)
{
netif_stop_queue(dev);
- DPRINTK(4, "%s: Shutting down ethercard, status was 0x%4.4x.\n",
- dev->name, 0x00);
-
return 0;
}
@@ -2944,7 +2875,7 @@ int ks_wlan_net_start(struct net_device *dev)
/* int rc; */
priv = netdev_priv(dev);
- priv->mac_address_valid = 0;
+ priv->mac_address_valid = false;
priv->need_commit = 0;
priv->device_open_status = 1;
@@ -2966,7 +2897,7 @@ int ks_wlan_net_start(struct net_device *dev)
/* The ks_wlan-specific entries in the device structure. */
dev->netdev_ops = &ks_wlan_netdev_ops;
- dev->wireless_handlers = (struct iw_handler_def *)&ks_wlan_handler_def;
+ dev->wireless_handlers = &ks_wlan_handler_def;
dev->watchdog_timeo = TX_TIMEOUT;
netif_carrier_off(dev);
diff --git a/drivers/staging/ks7010/michael_mic.c b/drivers/staging/ks7010/michael_mic.c
index 80497ef5b1aa..292eae29c552 100644
--- a/drivers/staging/ks7010/michael_mic.c
+++ b/drivers/staging/ks7010/michael_mic.c
@@ -11,123 +11,107 @@
#include <linux/types.h>
#include <linux/string.h>
+#include <linux/bitops.h>
+#include <asm/unaligned.h>
#include "michael_mic.h"
-// Rotation functions on 32 bit values
-#define ROL32(A, n) (((A) << (n)) | (((A) >> (32 - (n))) & ((1UL << (n)) - 1)))
-#define ROR32(A, n) ROL32((A), 32 - (n))
-// Convert from Byte[] to UInt32 in a portable way
-#define getUInt32(A, B) ((uint32_t)(A[B + 0] << 0) \
- + (A[B + 1] << 8) + (A[B + 2] << 16) + (A[B + 3] << 24))
-
-// Convert from UInt32 to Byte[] in a portable way
-#define putUInt32(A, B, C) \
-do { \
- A[B + 0] = (uint8_t)(C & 0xff); \
- A[B + 1] = (uint8_t)((C >> 8) & 0xff); \
- A[B + 2] = (uint8_t)((C >> 16) & 0xff); \
- A[B + 3] = (uint8_t)((C >> 24) & 0xff); \
-} while (0)
// Reset the state to the empty message.
-#define MichaelClear(A) \
-do { \
- A->L = A->K0; \
- A->R = A->K1; \
- A->nBytesInM = 0; \
-} while (0)
-
-static
-void MichaelInitializeFunction(struct michael_mic_t *Mic, uint8_t *key)
+static inline void michael_clear(struct michael_mic_t *mic)
+{
+ mic->l = mic->k0;
+ mic->r = mic->k1;
+ mic->m_bytes = 0;
+}
+
+static void michael_init(struct michael_mic_t *mic, u8 *key)
{
// Set the key
- Mic->K0 = getUInt32(key, 0);
- Mic->K1 = getUInt32(key, 4);
+ mic->k0 = get_unaligned_le32(key);
+ mic->k1 = get_unaligned_le32(key + 4);
//clear();
- MichaelClear(Mic);
+ michael_clear(mic);
+}
+
+static inline void michael_block(struct michael_mic_t *mic)
+{
+ mic->r ^= rol32(mic->l, 17);
+ mic->l += mic->r;
+ mic->r ^= ((mic->l & 0xff00ff00) >> 8) |
+ ((mic->l & 0x00ff00ff) << 8);
+ mic->l += mic->r;
+ mic->r ^= rol32(mic->l, 3); \
+ mic->l += mic->r;
+ mic->r ^= ror32(mic->l, 2); \
+ mic->l += mic->r;
}
-#define MichaelBlockFunction(L, R) \
-do { \
- R ^= ROL32(L, 17); \
- L += R; \
- R ^= ((L & 0xff00ff00) >> 8) | ((L & 0x00ff00ff) << 8); \
- L += R; \
- R ^= ROL32(L, 3); \
- L += R; \
- R ^= ROR32(L, 2); \
- L += R; \
-} while (0)
-
-static
-void MichaelAppend(struct michael_mic_t *Mic, uint8_t *src, int nBytes)
+static void michael_append(struct michael_mic_t *mic, u8 *src, int bytes)
{
int addlen;
- if (Mic->nBytesInM) {
- addlen = 4 - Mic->nBytesInM;
- if (addlen > nBytes)
- addlen = nBytes;
- memcpy(&Mic->M[Mic->nBytesInM], src, addlen);
- Mic->nBytesInM += addlen;
+ if (mic->m_bytes) {
+ addlen = 4 - mic->m_bytes;
+ if (addlen > bytes)
+ addlen = bytes;
+ memcpy(&mic->m[mic->m_bytes], src, addlen);
+ mic->m_bytes += addlen;
src += addlen;
- nBytes -= addlen;
+ bytes -= addlen;
- if (Mic->nBytesInM < 4)
+ if (mic->m_bytes < 4)
return;
- Mic->L ^= getUInt32(Mic->M, 0);
- MichaelBlockFunction(Mic->L, Mic->R);
- Mic->nBytesInM = 0;
+ mic->l ^= get_unaligned_le32(mic->m);
+ michael_block(mic);
+ mic->m_bytes = 0;
}
- while (nBytes >= 4) {
- Mic->L ^= getUInt32(src, 0);
- MichaelBlockFunction(Mic->L, Mic->R);
+ while (bytes >= 4) {
+ mic->l ^= get_unaligned_le32(src);
+ michael_block(mic);
src += 4;
- nBytes -= 4;
+ bytes -= 4;
}
- if (nBytes > 0) {
- Mic->nBytesInM = nBytes;
- memcpy(Mic->M, src, nBytes);
+ if (bytes > 0) {
+ mic->m_bytes = bytes;
+ memcpy(mic->m, src, bytes);
}
}
-static
-void MichaelGetMIC(struct michael_mic_t *Mic, uint8_t *dst)
+static void michael_get_mic(struct michael_mic_t *mic, u8 *dst)
{
- u8 *data = Mic->M;
+ u8 *data = mic->m;
- switch (Mic->nBytesInM) {
+ switch (mic->m_bytes) {
case 0:
- Mic->L ^= 0x5a;
+ mic->l ^= 0x5a;
break;
case 1:
- Mic->L ^= data[0] | 0x5a00;
+ mic->l ^= data[0] | 0x5a00;
break;
case 2:
- Mic->L ^= data[0] | (data[1] << 8) | 0x5a0000;
+ mic->l ^= data[0] | (data[1] << 8) | 0x5a0000;
break;
case 3:
- Mic->L ^= data[0] | (data[1] << 8) | (data[2] << 16) |
+ mic->l ^= data[0] | (data[1] << 8) | (data[2] << 16) |
0x5a000000;
break;
}
- MichaelBlockFunction(Mic->L, Mic->R);
- MichaelBlockFunction(Mic->L, Mic->R);
+ michael_block(mic);
+ michael_block(mic);
// The appendByte function has already computed the result.
- putUInt32(dst, 0, Mic->L);
- putUInt32(dst, 4, Mic->R);
+ put_unaligned_le32(mic->l, dst);
+ put_unaligned_le32(mic->r, dst + 4);
// Reset to the empty message.
- MichaelClear(Mic);
+ michael_clear(mic);
}
-void MichaelMICFunction(struct michael_mic_t *Mic, u8 *Key,
- u8 *Data, int Len, u8 priority,
- u8 *Result)
+void michael_mic_function(struct michael_mic_t *mic, u8 *key,
+ u8 *data, int len, u8 priority, u8 *result)
{
u8 pad_data[4] = { priority, 0, 0, 0 };
// Compute the MIC value
@@ -140,9 +124,9 @@ void MichaelMICFunction(struct michael_mic_t *Mic, u8 *Key,
* |DA|SA|Priority|0 |Data|M0|M1|M2|M3|M4|M5|M6|M7|
* +--+--+--------+--+----+--+--+--+--+--+--+--+--+
*/
- MichaelInitializeFunction(Mic, Key);
- MichaelAppend(Mic, (uint8_t *)Data, 12); /* |DA|SA| */
- MichaelAppend(Mic, pad_data, 4); /* |Priority|0|0|0| */
- MichaelAppend(Mic, (uint8_t *)(Data + 12), Len - 12); /* |Data| */
- MichaelGetMIC(Mic, Result);
+ michael_init(mic, key);
+ michael_append(mic, data, 12); /* |DA|SA| */
+ michael_append(mic, pad_data, 4); /* |Priority|0|0|0| */
+ michael_append(mic, data + 12, len - 12); /* |Data| */
+ michael_get_mic(mic, result);
}
diff --git a/drivers/staging/ks7010/michael_mic.h b/drivers/staging/ks7010/michael_mic.h
index 758e429446f1..894a8d4121a4 100644
--- a/drivers/staging/ks7010/michael_mic.h
+++ b/drivers/staging/ks7010/michael_mic.h
@@ -11,15 +11,14 @@
/* MichaelMIC routine define */
struct michael_mic_t {
- u32 K0; // Key
- u32 K1; // Key
- u32 L; // Current state
- u32 R; // Current state
- u8 M[4]; // Message accumulator (single word)
- int nBytesInM; // # bytes in M
- u8 Result[8];
+ u32 k0; // Key
+ u32 k1; // Key
+ u32 l; // Current state
+ u32 r; // Current state
+ u8 m[4]; // Message accumulator (single word)
+ int m_bytes; // # bytes in M
+ u8 result[8];
};
-void MichaelMICFunction(struct michael_mic_t *Mic, u8 *Key,
- u8 *Data, int Len, u8 priority,
- u8 *Result);
+void michael_mic_function(struct michael_mic_t *mic, u8 *key,
+ u8 *data, int len, u8 priority, u8 *result);
diff --git a/drivers/staging/lustre/TODO b/drivers/staging/lustre/TODO
index f194417d0af7..94446487748a 100644
--- a/drivers/staging/lustre/TODO
+++ b/drivers/staging/lustre/TODO
@@ -1,12 +1,302 @@
-* Possible remaining coding style fix.
-* Remove deadcode.
-* Separate client/server functionality. Functions only used by server can be
- removed from client.
-* Clean up libcfs layer. Ideally we can remove include/linux/libcfs entirely.
-* Clean up CLIO layer. Lustre client readahead/writeback control needs to better
- suit kernel providings.
-* Add documents in Documentation.
-* Other minor misc cleanups...
+Currently all the work directed toward the lustre upstream client is tracked
+at the following link:
+
+https://jira.hpdd.intel.com/browse/LU-9679
+
+Under this ticket you will see the following work items that need to be
+addressed:
+
+******************************************************************************
+* libcfs cleanup
+*
+* https://jira.hpdd.intel.com/browse/LU-9859
+*
+* Track all the cleanups and simplification of the libcfs module. Remove
+* functions the kernel provides. Possible intergrate some of the functionality
+* into the kernel proper.
+*
+******************************************************************************
+
+https://jira.hpdd.intel.com/browse/LU-100086
+
+LNET_MINOR conflicts with USERIO_MINOR
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8130
+
+Fix and simplify libcfs hash handling
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8703
+
+The current way we handle SMP is wrong. Platforms like ARM and KNL can have
+core and NUMA setups with things like NUMA nodes with no cores. We need to
+handle such cases. This work also greatly simplified the lustre SMP code.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9019
+
+Replace libcfs time API with standard kernel APIs. Also migrate away from
+jiffies. We found jiffies can vary on nodes which can lead to corner cases
+that can break the file system due to nodes having inconsistent behavior.
+So move to time64_t and ktime_t as much as possible.
+
+******************************************************************************
+* Proper IB support for ko2iblnd
+******************************************************************************
+https://jira.hpdd.intel.com/browse/LU-9179
+
+Poor performance for the ko2iblnd driver. This is related to many of the
+patches below that are missing from the linux client.
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9886
+
+Crash in upstream kiblnd_handle_early_rxs()
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10394 / LU-10526 / LU-10089
+
+Default to default to using MEM_REG
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10459
+
+throttle tx based on queue depth
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9943
+
+correct WR fast reg accounting
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10291
+
+remove concurrent_sends tunable
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10213
+
+calculate qp max_send_wrs properly
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9810
+
+use less CQ entries for each connection
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10129 / LU-9180
+
+rework map_on_demand behavior
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10129
+
+query device capabilities
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10015
+
+fix race at kiblnd_connect_peer
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9983
+
+allow for discontiguous fragments
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9500
+
+Don't Page Align remote_addr with FastReg
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9448
+
+handle empty CPTs
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9507
+
+Don't Assert On Reconnect with MultiQP
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9472
+
+Fix FastReg map/unmap for MLX5
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9425
+
+Turn on 2 sges by default
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8943
+
+Enable Multiple OPA Endpoints between Nodes
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-5718
+
+multiple sges for work request
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9094
+
+kill timedout txs from ibp_tx_queue
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9094
+
+reconnect peer for REJ_INVALID_SERVICE_ID
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8752
+
+Stop MLX5 triggering a dump_cqe
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8874
+
+Move ko2iblnd to latest RDMA changes
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8875 / LU-8874
+
+Change to new RDMA done callback mechanism
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9164 / LU-8874
+
+Incorporate RDMA map/unamp API's into ko2iblnd
+
+******************************************************************************
+* sysfs/debugfs fixes
+*
+* https://jira.hpdd.intel.com/browse/LU-8066
+*
+* The original migration to sysfs was done in haste without properly working
+* utilities to test the changes. This covers the work to restore the proper
+* behavior. Huge project to make this right.
+*
+******************************************************************************
+
+https://jira.hpdd.intel.com/browse/LU-9431
+
+The function class_process_proc_param was used for our mass updates of proc
+tunables. It didn't work with sysfs and it was just ugly so it was removed.
+In the process the ability to mass update thousands of clients was lost. This
+work restores this in a sane way.
+
+------------------------------------------------------------------------------
+https://jira.hpdd.intel.com/browse/LU-9091
+
+One the major request of users is the ability to pass in parameters into a
+sysfs file in various different units. For example we can set max_pages_per_rpc
+but this can vary on platforms due to different platform sizes. So you can
+set this like max_pages_per_rpc=16MiB. The original code to handle this written
+before the string helpers were created so the code doesn't follow that format
+but it would be easy to move to. Currently the string helpers does the reverse
+of what we need, changing bytes to string. We need to change a string to bytes.
+
+******************************************************************************
+* Proper user land to kernel space interface for Lustre
+*
+* https://jira.hpdd.intel.com/browse/LU-9680
+*
+******************************************************************************
+
+https://jira.hpdd.intel.com/browse/LU-8915
+
+Don't use linux list structure as user land arguments for lnet selftest.
+This code is pretty poor quality and really needs to be reworked.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8834
+
+The lustre ioctl LL_IOC_FUTIMES_3 is very generic. Need to either work with
+other file systems with similar functionality and make a common syscall
+interface or rework our server code to automagically do it for us.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-6202
+
+Cleanup up ioctl handling. We have many obsolete ioctls. Also the way we do
+ioctls can be changed over to netlink. This also has the benefit of working
+better with HPC systems that do IO forwarding. Such systems don't like ioctls
+very well.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9667
+
+More cleanups by making our utilities use sysfs instead of ioctls for LNet.
+Also it has been requested to move the remaining ioctls to the netlink API.
+
+******************************************************************************
+* Misc
+******************************************************************************
+
+------------------------------------------------------------------------------
+https://jira.hpdd.intel.com/browse/LU-9855
+
+Clean up obdclass preprocessor code. One of the major eye sores is the various
+pointer redirections and macros used by the obdclass. This makes the code very
+difficult to understand. It was requested by the Al Viro to clean this up before
+we leave staging.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9633
+
+Migrate to sphinx kernel-doc style comments. Add documents in Documentation.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-6142
+
+Possible remaining coding style fix. Remove deadcode. Enforce kernel code
+style. Other minor misc cleanups...
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8837
+
+Separate client/server functionality. Functions only used by server can be
+removed from client. Most of this has been done but we need a inspect of the
+code to make sure.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-8964
+
+Lustre client readahead/writeback control needs to better suit kernel providings.
+Currently its being explored. We could end up replacing the CLIO read ahead
+abstract with the kernel proper version.
+
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9862
+
+Patch that landed for LU-7890 leads to static checker errors
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-9868
+
+dcache/namei fixes for lustre
+------------------------------------------------------------------------------
+
+https://jira.hpdd.intel.com/browse/LU-10467
+
+use standard linux wait_events macros work by Neil Brown
+
+------------------------------------------------------------------------------
Please send any patches to Greg Kroah-Hartman <greg@kroah.com>, Andreas Dilger
-<andreas.dilger@intel.com>, and Oleg Drokin <oleg.drokin@intel.com>.
+<andreas.dilger@intel.com>, James Simmons <jsimmons@infradead.org> and
+Oleg Drokin <oleg.drokin@intel.com>.
diff --git a/drivers/staging/lustre/include/linux/libcfs/curproc.h b/drivers/staging/lustre/include/linux/libcfs/curproc.h
index 3cb3f086148e..4702956805a6 100644
--- a/drivers/staging/lustre/include/linux/libcfs/curproc.h
+++ b/drivers/staging/lustre/include/linux/libcfs/curproc.h
@@ -56,30 +56,21 @@
typedef u32 cfs_cap_t;
-#define CFS_CAP_CHOWN 0
-#define CFS_CAP_DAC_OVERRIDE 1
-#define CFS_CAP_DAC_READ_SEARCH 2
-#define CFS_CAP_FOWNER 3
-#define CFS_CAP_FSETID 4
-#define CFS_CAP_LINUX_IMMUTABLE 9
-#define CFS_CAP_SYS_ADMIN 21
-#define CFS_CAP_SYS_BOOT 23
-#define CFS_CAP_SYS_RESOURCE 24
+#define CFS_CAP_FS_MASK (BIT(CAP_CHOWN) | \
+ BIT(CAP_DAC_OVERRIDE) | \
+ BIT(CAP_DAC_READ_SEARCH) | \
+ BIT(CAP_FOWNER) | \
+ BIT(CAP_FSETID) | \
+ BIT(CAP_LINUX_IMMUTABLE) | \
+ BIT(CAP_SYS_ADMIN) | \
+ BIT(CAP_SYS_BOOT) | \
+ BIT(CAP_SYS_RESOURCE))
-#define CFS_CAP_FS_MASK (BIT(CFS_CAP_CHOWN) | \
- BIT(CFS_CAP_DAC_OVERRIDE) | \
- BIT(CFS_CAP_DAC_READ_SEARCH) | \
- BIT(CFS_CAP_FOWNER) | \
- BIT(CFS_CAP_FSETID) | \
- BIT(CFS_CAP_LINUX_IMMUTABLE) | \
- BIT(CFS_CAP_SYS_ADMIN) | \
- BIT(CFS_CAP_SYS_BOOT) | \
- BIT(CFS_CAP_SYS_RESOURCE))
-
-void cfs_cap_raise(cfs_cap_t cap);
-void cfs_cap_lower(cfs_cap_t cap);
-int cfs_cap_raised(cfs_cap_t cap);
-cfs_cap_t cfs_curproc_cap_pack(void);
+static inline cfs_cap_t cfs_curproc_cap_pack(void)
+{
+ /* cfs_cap_t is only the first word of kernel_cap_t */
+ return (cfs_cap_t)(current_cap().cap[0]);
+}
/* __LIBCFS_CURPROC_H__ */
#endif
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/libcfs.h
index ca3472cc952f..392793582956 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs.h
@@ -64,14 +64,21 @@
#define LNET_ACCEPTOR_MIN_RESERVED_PORT 512
#define LNET_ACCEPTOR_MAX_RESERVED_PORT 1023
-/*
- * Defined by platform
- */
-sigset_t cfs_block_allsigs(void);
-sigset_t cfs_block_sigs(unsigned long sigs);
-sigset_t cfs_block_sigsinv(unsigned long sigs);
-void cfs_restore_sigs(sigset_t sigset);
-void cfs_clear_sigpending(void);
+/* Block all signals except for the @sigs */
+static inline void cfs_block_sigsinv(unsigned long sigs, sigset_t *old)
+{
+ sigset_t new;
+
+ siginitsetinv(&new, sigs);
+ sigorsets(&new, &current->blocked, &new);
+ sigprocmask(SIG_BLOCK, &new, old);
+}
+
+static inline void
+cfs_restore_sigs(sigset_t *old)
+{
+ sigprocmask(SIG_SETMASK, old, NULL);
+}
struct libcfs_ioctl_handler {
struct list_head item;
@@ -105,10 +112,6 @@ static inline void *__container_of(void *ptr, unsigned long shift)
#define _LIBCFS_H
-void *libcfs_kvzalloc(size_t size, gfp_t flags);
-void *libcfs_kvzalloc_cpt(struct cfs_cpt_table *cptab, int cpt, size_t size,
- gfp_t flags);
-
extern struct miscdevice libcfs_dev;
/**
* The path of debug log dump upcall script.
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h
index e5c156e9d907..3a72117140ed 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h
@@ -189,18 +189,15 @@ int cfs_crypto_hash_digest(enum cfs_crypto_hash_alg hash_alg,
unsigned char *key, unsigned int key_len,
unsigned char *hash, unsigned int *hash_len);
-/* cfs crypto hash descriptor */
-struct cfs_crypto_hash_desc;
-
-struct cfs_crypto_hash_desc *
+struct ahash_request *
cfs_crypto_hash_init(enum cfs_crypto_hash_alg hash_alg,
unsigned char *key, unsigned int key_len);
-int cfs_crypto_hash_update_page(struct cfs_crypto_hash_desc *desc,
+int cfs_crypto_hash_update_page(struct ahash_request *desc,
struct page *page, unsigned int offset,
unsigned int len);
-int cfs_crypto_hash_update(struct cfs_crypto_hash_desc *desc, const void *buf,
+int cfs_crypto_hash_update(struct ahash_request *desc, const void *buf,
unsigned int buf_len);
-int cfs_crypto_hash_final(struct cfs_crypto_hash_desc *desc,
+int cfs_crypto_hash_final(struct ahash_request *desc,
unsigned char *hash, unsigned int *hash_len);
int cfs_crypto_register(void);
void cfs_crypto_unregister(void);
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h
index 1b98f0953afb..9290a19429e7 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h
@@ -66,8 +66,8 @@ extern unsigned int libcfs_panic_on_lbug;
# define DEBUG_SUBSYSTEM S_UNDEFINED
#endif
-#define CDEBUG_DEFAULT_MAX_DELAY (cfs_time_seconds(600)) /* jiffies */
-#define CDEBUG_DEFAULT_MIN_DELAY ((cfs_time_seconds(1) + 1) / 2) /* jiffies */
+#define CDEBUG_DEFAULT_MAX_DELAY (600 * HZ) /* jiffies */
+#define CDEBUG_DEFAULT_MIN_DELAY ((HZ + 1) / 2) /* jiffies */
#define CDEBUG_DEFAULT_BACKOFF 2
struct cfs_debug_limit_state {
unsigned long cdls_next;
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h
index 9699646decb9..c4f25be78268 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h
@@ -62,7 +62,7 @@ static inline int cfs_time_aftereq(unsigned long t1, unsigned long t2)
static inline unsigned long cfs_time_shift(int seconds)
{
- return cfs_time_add(cfs_time_current(), cfs_time_seconds(seconds));
+ return cfs_time_add(cfs_time_current(), seconds * HZ);
}
/*
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h
index aece13698eb4..805cb326af86 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h
@@ -65,11 +65,6 @@ static inline unsigned long cfs_time_current(void)
return jiffies;
}
-static inline long cfs_time_seconds(int seconds)
-{
- return ((long)seconds) * msecs_to_jiffies(MSEC_PER_SEC);
-}
-
static inline long cfs_duration_sec(long d)
{
return d / msecs_to_jiffies(MSEC_PER_SEC);
@@ -85,7 +80,7 @@ static inline u64 cfs_time_add_64(u64 t, u64 d)
static inline u64 cfs_time_shift_64(int seconds)
{
return cfs_time_add_64(cfs_time_current_64(),
- cfs_time_seconds(seconds));
+ seconds * HZ);
}
static inline int cfs_time_before_64(u64 t1, u64 t2)
diff --git a/drivers/staging/lustre/include/linux/lnet/api.h b/drivers/staging/lustre/include/linux/lnet/api.h
index 31fcd33171b4..dae2e4f0056c 100644
--- a/drivers/staging/lustre/include/linux/lnet/api.h
+++ b/drivers/staging/lustre/include/linux/lnet/api.h
@@ -169,6 +169,7 @@ int LNetEQFree(struct lnet_handle_eq eventq_in);
int LNetEQPoll(struct lnet_handle_eq *eventqs_in,
int neq_in,
int timeout_ms,
+ int interruptible,
struct lnet_event *event_out,
int *which_eq_out);
/** @} lnet_eq */
diff --git a/drivers/staging/lustre/lnet/Kconfig b/drivers/staging/lustre/lnet/Kconfig
index 6bcb53d0c6f4..ad049e6f24e4 100644
--- a/drivers/staging/lustre/lnet/Kconfig
+++ b/drivers/staging/lustre/lnet/Kconfig
@@ -1,6 +1,6 @@
config LNET
tristate "Lustre networking subsystem (LNet)"
- depends on INET && m
+ depends on INET
help
The Lustre network layer, also known as LNet, is a networking abstaction
level API that was initially created to allow Lustre Filesystem to utilize
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
index ec84edfda271..7ae2955c4db6 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
@@ -1211,7 +1211,7 @@ static struct kib_hca_dev *kiblnd_current_hdev(struct kib_dev *dev)
CDEBUG(D_NET, "%s: Wait for failover\n",
dev->ibd_ifname);
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1) / 100);
+ schedule_timeout(HZ / 100);
read_lock_irqsave(&kiblnd_data.kib_global_lock, flags);
}
@@ -1921,7 +1921,7 @@ struct list_head *kiblnd_pool_alloc_node(struct kib_poolset *ps)
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(interval);
- if (interval < cfs_time_seconds(1))
+ if (interval < HZ)
interval *= 2;
goto again;
@@ -2541,7 +2541,7 @@ static void kiblnd_base_shutdown(void)
"Waiting for %d threads to terminate\n",
atomic_read(&kiblnd_data.kib_nthreads));
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
+ schedule_timeout(HZ);
}
/* fall through */
@@ -2592,7 +2592,7 @@ static void kiblnd_shutdown(struct lnet_ni *ni)
libcfs_nid2str(ni->ni_nid),
atomic_read(&net->ibn_npeers));
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
+ schedule_timeout(HZ);
}
kiblnd_net_fini_pools(net);
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
index b3e7f28eb978..6690a6cd4e34 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
@@ -3288,8 +3288,6 @@ kiblnd_connd(void *arg)
int peer_index = 0;
unsigned long deadline = jiffies;
- cfs_block_allsigs();
-
init_waitqueue_entry(&wait, current);
kiblnd_data.kib_connd = current;
@@ -3542,8 +3540,6 @@ kiblnd_scheduler(void *arg)
int busy_loops = 0;
int rc;
- cfs_block_allsigs();
-
init_waitqueue_entry(&wait, current);
sched = kiblnd_data.kib_scheds[KIB_THREAD_CPT(id)];
@@ -3676,8 +3672,6 @@ kiblnd_failover_thread(void *arg)
LASSERT(*kiblnd_tunables.kib_dev_failover);
- cfs_block_allsigs();
-
init_waitqueue_entry(&wait, current);
write_lock_irqsave(glock, flags);
@@ -3728,8 +3722,8 @@ kiblnd_failover_thread(void *arg)
add_wait_queue(&kiblnd_data.kib_failover_waitq, &wait);
write_unlock_irqrestore(glock, flags);
- rc = schedule_timeout(long_sleep ? cfs_time_seconds(10) :
- cfs_time_seconds(1));
+ rc = schedule_timeout(long_sleep ? 10 * HZ :
+ HZ);
remove_wait_queue(&kiblnd_data.kib_failover_waitq, &wait);
write_lock_irqsave(glock, flags);
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
index ff292216290d..7086678e1c3e 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
@@ -1677,7 +1677,7 @@ ksocknal_destroy_conn(struct ksock_conn *conn)
switch (conn->ksnc_rx_state) {
case SOCKNAL_RX_LNET_PAYLOAD:
last_rcv = conn->ksnc_rx_deadline -
- cfs_time_seconds(*ksocknal_tunables.ksnd_timeout);
+ *ksocknal_tunables.ksnd_timeout * HZ;
CERROR("Completing partial receive from %s[%d], ip %pI4h:%d, with error, wanted: %zd, left: %d, last alive is %ld secs ago\n",
libcfs_id2str(conn->ksnc_peer->ksnp_id), conn->ksnc_type,
&conn->ksnc_ipaddr, conn->ksnc_port,
@@ -2356,7 +2356,7 @@ ksocknal_base_shutdown(void)
ksocknal_data.ksnd_nthreads);
read_unlock(&ksocknal_data.ksnd_global_lock);
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
+ schedule_timeout(HZ);
read_lock(&ksocknal_data.ksnd_global_lock);
}
read_unlock(&ksocknal_data.ksnd_global_lock);
@@ -2599,7 +2599,7 @@ ksocknal_shutdown(struct lnet_ni *ni)
"waiting for %d peers to disconnect\n",
net->ksnn_npeers);
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
+ schedule_timeout(HZ);
ksocknal_debug_peerhash(ni);
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h
index d50ebdf863fa..570f54ed57b1 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h
@@ -304,15 +304,6 @@ struct ksock_tx { /* transmit packet */
/* network zero copy callback descriptor embedded in struct ksock_tx */
-/*
- * space for the rx frag descriptors; we either read a single contiguous
- * header, or up to LNET_MAX_IOV frags of payload of either type.
- */
-union ksock_rxiovspace {
- struct kvec iov[LNET_MAX_IOV];
- struct bio_vec kiov[LNET_MAX_IOV];
-};
-
#define SOCKNAL_RX_KSM_HEADER 1 /* reading ksock message header */
#define SOCKNAL_RX_LNET_HEADER 2 /* reading lnet message header */
#define SOCKNAL_RX_PARSE 3 /* Calling lnet_parse() */
@@ -359,7 +350,7 @@ struct ksock_conn {
__u8 ksnc_rx_state; /* what is being read */
int ksnc_rx_nob_left; /* # bytes to next hdr/body */
struct iov_iter ksnc_rx_to; /* copy destination */
- union ksock_rxiovspace ksnc_rx_iov_space; /* space for frag descriptors */
+ struct kvec ksnc_rx_iov_space[LNET_MAX_IOV]; /* space for frag descriptors */
__u32 ksnc_rx_csum; /* partial checksum for incoming
* data
*/
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
index 11fd3a36424f..036fecbcede8 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
@@ -189,7 +189,7 @@ ksocknal_transmit(struct ksock_conn *conn, struct ksock_tx *tx)
if (ksocknal_data.ksnd_stall_tx) {
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(ksocknal_data.ksnd_stall_tx));
+ schedule_timeout(ksocknal_data.ksnd_stall_tx * HZ);
}
LASSERT(tx->tx_resid);
@@ -294,7 +294,7 @@ ksocknal_receive(struct ksock_conn *conn)
if (ksocknal_data.ksnd_stall_rx) {
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(ksocknal_data.ksnd_stall_rx));
+ schedule_timeout(ksocknal_data.ksnd_stall_rx * HZ);
}
rc = ksocknal_connsock_addref(conn);
@@ -986,7 +986,7 @@ int
ksocknal_new_packet(struct ksock_conn *conn, int nob_to_skip)
{
static char ksocknal_slop_buffer[4096];
- struct kvec *kvec = (struct kvec *)&conn->ksnc_rx_iov_space;
+ struct kvec *kvec = conn->ksnc_rx_iov_space;
int nob;
unsigned int niov;
@@ -1059,7 +1059,7 @@ ksocknal_new_packet(struct ksock_conn *conn, int nob_to_skip)
static int
ksocknal_process_receive(struct ksock_conn *conn)
{
- struct kvec *kvec = (struct kvec *)&conn->ksnc_rx_iov_space;
+ struct kvec *kvec = conn->ksnc_rx_iov_space;
struct lnet_hdr *lhdr;
struct lnet_process_id *id;
int rc;
@@ -1324,8 +1324,6 @@ int ksocknal_scheduler(void *arg)
info = ksocknal_data.ksnd_sched_info[KSOCK_THREAD_CPT(id)];
sched = &info->ksi_scheds[KSOCK_THREAD_SID(id)];
- cfs_block_allsigs();
-
rc = cfs_cpt_bind(lnet_cpt_table(), info->ksi_cpt);
if (rc) {
CWARN("Can't set CPU partition affinity to %d: %d\n",
@@ -1780,7 +1778,7 @@ ksocknal_connect(struct ksock_route *route)
int rc = 0;
deadline = cfs_time_add(cfs_time_current(),
- cfs_time_seconds(*ksocknal_tunables.ksnd_timeout));
+ *ksocknal_tunables.ksnd_timeout * HZ);
write_lock_bh(&ksocknal_data.ksnd_global_lock);
@@ -1878,7 +1876,7 @@ ksocknal_connect(struct ksock_route *route)
* so min_reconnectms should be good heuristic
*/
route->ksnr_retry_interval =
- cfs_time_seconds(*ksocknal_tunables.ksnd_min_reconnectms) / 1000;
+ *ksocknal_tunables.ksnd_min_reconnectms * HZ / 1000;
route->ksnr_timeout = cfs_time_add(cfs_time_current(),
route->ksnr_retry_interval);
}
@@ -1899,10 +1897,10 @@ ksocknal_connect(struct ksock_route *route)
route->ksnr_retry_interval *= 2;
route->ksnr_retry_interval =
max(route->ksnr_retry_interval,
- cfs_time_seconds(*ksocknal_tunables.ksnd_min_reconnectms) / 1000);
+ (long)*ksocknal_tunables.ksnd_min_reconnectms * HZ / 1000);
route->ksnr_retry_interval =
min(route->ksnr_retry_interval,
- cfs_time_seconds(*ksocknal_tunables.ksnd_max_reconnectms) / 1000);
+ (long)*ksocknal_tunables.ksnd_max_reconnectms * HZ / 1000);
LASSERT(route->ksnr_retry_interval);
route->ksnr_timeout = cfs_time_add(cfs_time_current(),
@@ -1972,7 +1970,7 @@ ksocknal_connd_check_start(time64_t sec, long *timeout)
if (sec - ksocknal_data.ksnd_connd_failed_stamp <= 1) {
/* may run out of resource, retry later */
- *timeout = cfs_time_seconds(1);
+ *timeout = HZ;
return 0;
}
@@ -2031,8 +2029,8 @@ ksocknal_connd_check_stop(time64_t sec, long *timeout)
val = (int)(ksocknal_data.ksnd_connd_starting_stamp +
SOCKNAL_CONND_TIMEOUT - sec);
- *timeout = (val > 0) ? cfs_time_seconds(val) :
- cfs_time_seconds(SOCKNAL_CONND_TIMEOUT);
+ *timeout = (val > 0) ? val * HZ :
+ SOCKNAL_CONND_TIMEOUT * HZ;
if (val > 0)
return 0;
@@ -2078,8 +2076,6 @@ ksocknal_connd(void *arg)
int nloops = 0;
int cons_retry = 0;
- cfs_block_allsigs();
-
init_waitqueue_entry(&wait, current);
spin_lock_bh(connd_lock);
@@ -2307,7 +2303,7 @@ ksocknal_send_keepalive_locked(struct ksock_peer *peer)
if (*ksocknal_tunables.ksnd_keepalive <= 0 ||
time_before(cfs_time_current(),
cfs_time_add(peer->ksnp_last_alive,
- cfs_time_seconds(*ksocknal_tunables.ksnd_keepalive))))
+ *ksocknal_tunables.ksnd_keepalive * HZ)))
return 0;
if (time_before(cfs_time_current(), peer->ksnp_send_keepalive))
@@ -2472,8 +2468,6 @@ ksocknal_reaper(void *arg)
int peer_index = 0;
unsigned long deadline = cfs_time_current();
- cfs_block_allsigs();
-
INIT_LIST_HEAD(&enomem_conns);
init_waitqueue_entry(&wait, current);
@@ -2563,7 +2557,7 @@ ksocknal_reaper(void *arg)
ksocknal_data.ksnd_peer_hash_size;
}
- deadline = cfs_time_add(deadline, cfs_time_seconds(p));
+ deadline = cfs_time_add(deadline, p * HZ);
}
if (nenomem_conns) {
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c
index cb28dd2baf2f..7941cfa526bc 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c
@@ -189,7 +189,7 @@ ksocknal_lib_recv(struct ksock_conn *conn)
if (!(conn->ksnc_rx_to.type & ITER_BVEC) &&
conn->ksnc_proto != &ksocknal_protocol_v2x)
return rc;
-
+
/* accumulate checksum */
conn->ksnc_msg.ksm_csum = 0;
iov_iter_for_each_range(&conn->ksnc_rx_to, rc, lustre_csum, conn);
diff --git a/drivers/staging/lustre/lnet/libcfs/Makefile b/drivers/staging/lustre/lnet/libcfs/Makefile
index 730f2c675047..b7dc7ac11cc5 100644
--- a/drivers/staging/lustre/lnet/libcfs/Makefile
+++ b/drivers/staging/lustre/lnet/libcfs/Makefile
@@ -5,12 +5,10 @@ subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include
obj-$(CONFIG_LNET) += libcfs.o
libcfs-linux-objs := linux-tracefile.o linux-debug.o
-libcfs-linux-objs += linux-prim.o linux-cpu.o
-libcfs-linux-objs += linux-curproc.o
+libcfs-linux-objs += linux-cpu.o
libcfs-linux-objs += linux-module.o
libcfs-linux-objs += linux-crypto.o
libcfs-linux-objs += linux-crypto-adler.o
-libcfs-linux-objs += linux-mem.o
libcfs-linux-objs := $(addprefix linux/,$(libcfs-linux-objs))
diff --git a/drivers/staging/lustre/lnet/libcfs/debug.c b/drivers/staging/lustre/lnet/libcfs/debug.c
index 551c45bf4108..1371224a8cb9 100644
--- a/drivers/staging/lustre/lnet/libcfs/debug.c
+++ b/drivers/staging/lustre/lnet/libcfs/debug.c
@@ -113,7 +113,7 @@ static int param_set_delay_minmax(const char *val,
if (rc)
return -EINVAL;
- d = cfs_time_seconds(sec) / 100;
+ d = sec * HZ / 100;
if (d < min || d > max)
return -EINVAL;
@@ -440,7 +440,7 @@ int libcfs_debug_clear_buffer(void)
return 0;
}
-/* Debug markers, although printed by S_LNET should not be be marked as such. */
+/* Debug markers, although printed by S_LNET should not be marked as such. */
#undef DEBUG_SUBSYSTEM
#define DEBUG_SUBSYSTEM S_UNDEFINED
int libcfs_debug_mark_buffer(const char *text)
diff --git a/drivers/staging/lustre/lnet/libcfs/fail.c b/drivers/staging/lustre/lnet/libcfs/fail.c
index 39439b303d65..d3f1e866c6a7 100644
--- a/drivers/staging/lustre/lnet/libcfs/fail.c
+++ b/drivers/staging/lustre/lnet/libcfs/fail.c
@@ -134,7 +134,7 @@ int __cfs_fail_timeout_set(u32 id, u32 value, int ms, int set)
CERROR("cfs_fail_timeout id %x sleeping for %dms\n",
id, ms);
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(ms) / 1000);
+ schedule_timeout(ms * HZ / 1000);
CERROR("cfs_fail_timeout id %x awake\n", id);
}
return ret;
diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c
index c07165e0ad95..388521e4e354 100644
--- a/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c
+++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c
@@ -743,7 +743,7 @@ cfs_cpt_table_create(int ncpt)
goto failed;
}
- if (!zalloc_cpumask_var(&mask, GFP_NOFS)){
+ if (!zalloc_cpumask_var(&mask, GFP_NOFS)) {
CERROR("Failed to allocate scratch cpumask\n");
goto failed;
}
diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c
index 80072b2a443c..b55006264155 100644
--- a/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c
+++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c
@@ -42,7 +42,7 @@ static int cfs_crypto_hash_speeds[CFS_HASH_ALG_MAX];
/**
* Initialize the state descriptor for the specified hash algorithm.
*
- * An internal routine to allocate the hash-specific state in \a hdesc for
+ * An internal routine to allocate the hash-specific state in \a req for
* use with cfs_crypto_hash_digest() to compute the hash of a single message,
* though possibly in multiple chunks. The descriptor internal state should
* be freed with cfs_crypto_hash_final().
@@ -50,7 +50,7 @@ static int cfs_crypto_hash_speeds[CFS_HASH_ALG_MAX];
* \param[in] hash_alg hash algorithm id (CFS_HASH_ALG_*)
* \param[out] type pointer to the hash description in hash_types[]
* array
- * \param[in,out] hdesc hash state descriptor to be initialized
+ * \param[in,out] req hash state descriptor to be initialized
* \param[in] key initial hash value/state, NULL to use default
* value
* \param[in] key_len length of \a key
@@ -194,7 +194,7 @@ EXPORT_SYMBOL(cfs_crypto_hash_digest);
* \retval pointer to descriptor of hash instance
* \retval ERR_PTR(errno) in case of error
*/
-struct cfs_crypto_hash_desc *
+struct ahash_request *
cfs_crypto_hash_init(enum cfs_crypto_hash_alg hash_alg,
unsigned char *key, unsigned int key_len)
{
@@ -206,14 +206,14 @@ cfs_crypto_hash_init(enum cfs_crypto_hash_alg hash_alg,
if (err)
return ERR_PTR(err);
- return (struct cfs_crypto_hash_desc *)req;
+ return req;
}
EXPORT_SYMBOL(cfs_crypto_hash_init);
/**
* Update hash digest computed on data within the given \a page
*
- * \param[in] hdesc hash state descriptor
+ * \param[in] hreq hash state descriptor
* \param[in] page data page on which to compute the hash
* \param[in] offset offset within \a page at which to start hash
* \param[in] len length of data on which to compute hash
@@ -221,11 +221,10 @@ EXPORT_SYMBOL(cfs_crypto_hash_init);
* \retval 0 for success
* \retval negative errno on failure
*/
-int cfs_crypto_hash_update_page(struct cfs_crypto_hash_desc *hdesc,
+int cfs_crypto_hash_update_page(struct ahash_request *req,
struct page *page, unsigned int offset,
unsigned int len)
{
- struct ahash_request *req = (void *)hdesc;
struct scatterlist sl;
sg_init_table(&sl, 1);
@@ -239,17 +238,16 @@ EXPORT_SYMBOL(cfs_crypto_hash_update_page);
/**
* Update hash digest computed on the specified data
*
- * \param[in] hdesc hash state descriptor
+ * \param[in] req hash state descriptor
* \param[in] buf data buffer on which to compute the hash
* \param[in] buf_len length of \buf on which to compute hash
*
* \retval 0 for success
* \retval negative errno on failure
*/
-int cfs_crypto_hash_update(struct cfs_crypto_hash_desc *hdesc,
+int cfs_crypto_hash_update(struct ahash_request *req,
const void *buf, unsigned int buf_len)
{
- struct ahash_request *req = (void *)hdesc;
struct scatterlist sl;
sg_init_one(&sl, buf, buf_len);
@@ -262,20 +260,19 @@ EXPORT_SYMBOL(cfs_crypto_hash_update);
/**
* Finish hash calculation, copy hash digest to buffer, clean up hash descriptor
*
- * \param[in] hdesc hash descriptor
+ * \param[in] req hash descriptor
* \param[out] hash pointer to hash buffer to store hash digest
- * \param[in,out] hash_len pointer to hash buffer size, if \a hdesc = NULL
- * only free \a hdesc instead of computing the hash
+ * \param[in,out] hash_len pointer to hash buffer size, if \a req = NULL
+ * only free \a req instead of computing the hash
*
* \retval 0 for success
* \retval -EOVERFLOW if hash_len is too small for the hash digest
* \retval negative errno for other errors from lower layers
*/
-int cfs_crypto_hash_final(struct cfs_crypto_hash_desc *hdesc,
+int cfs_crypto_hash_final(struct ahash_request *req,
unsigned char *hash, unsigned int *hash_len)
{
int err;
- struct ahash_request *req = (void *)hdesc;
int size = crypto_ahash_digestsize(crypto_ahash_reqtfm(req));
if (!hash || !hash_len) {
@@ -331,7 +328,7 @@ static void cfs_crypto_performance_test(enum cfs_crypto_hash_alg hash_alg)
for (start = jiffies, end = start + msecs_to_jiffies(MSEC_PER_SEC),
bcount = 0; time_before(jiffies, end); bcount++) {
- struct cfs_crypto_hash_desc *hdesc;
+ struct ahash_request *hdesc;
int i;
hdesc = cfs_crypto_hash_init(hash_alg, NULL, 0);
diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c
deleted file mode 100644
index 1d8949f1a4fa..000000000000
--- a/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c
+++ /dev/null
@@ -1,108 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * 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.
- *
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.gnu.org/licenses/gpl-2.0.html
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2011, 2015, Intel Corporation.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * libcfs/libcfs/linux/linux-curproc.c
- *
- * Lustre curproc API implementation for Linux kernel
- *
- * Author: Nikita Danilov <nikita@clusterfs.com>
- */
-
-#include <linux/sched.h>
-#include <linux/fs_struct.h>
-
-#include <linux/compat.h>
-#include <linux/thread_info.h>
-
-#define DEBUG_SUBSYSTEM S_LNET
-
-#include <linux/libcfs/libcfs.h>
-
-/*
- * Implementation of cfs_curproc API (see portals/include/libcfs/curproc.h)
- * for Linux kernel.
- */
-
-void cfs_cap_raise(cfs_cap_t cap)
-{
- struct cred *cred;
-
- cred = prepare_creds();
- if (cred) {
- cap_raise(cred->cap_effective, cap);
- commit_creds(cred);
- }
-}
-EXPORT_SYMBOL(cfs_cap_raise);
-
-void cfs_cap_lower(cfs_cap_t cap)
-{
- struct cred *cred;
-
- cred = prepare_creds();
- if (cred) {
- cap_lower(cred->cap_effective, cap);
- commit_creds(cred);
- }
-}
-EXPORT_SYMBOL(cfs_cap_lower);
-
-int cfs_cap_raised(cfs_cap_t cap)
-{
- return cap_raised(current_cap(), cap);
-}
-EXPORT_SYMBOL(cfs_cap_raised);
-
-static void cfs_kernel_cap_pack(kernel_cap_t kcap, cfs_cap_t *cap)
-{
- /* XXX lost high byte */
- *cap = kcap.cap[0];
-}
-
-cfs_cap_t cfs_curproc_cap_pack(void)
-{
- cfs_cap_t cap;
-
- cfs_kernel_cap_pack(current_cap(), &cap);
- return cap;
-}
-EXPORT_SYMBOL(cfs_curproc_cap_pack);
-
-/*
- * Local variables:
- * c-indentation-style: "K&R"
- * c-basic-offset: 8
- * tab-width: 8
- * fill-column: 80
- * scroll-step: 1
- * End:
- */
diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c
deleted file mode 100644
index 963df0ef4afb..000000000000
--- a/drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c
+++ /dev/null
@@ -1,51 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * 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.
- *
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.gnu.org/licenses/gpl-2.0.html
- *
- */
-/*
- * This file creates a memory allocation primitive for Lustre, that
- * allows to fallback to vmalloc allocations should regular kernel allocations
- * fail due to size or system memory fragmentation.
- *
- * Author: Oleg Drokin <green@linuxhacker.ru>
- *
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Seagate Technology.
- */
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <linux/libcfs/libcfs.h>
-
-void *libcfs_kvzalloc(size_t size, gfp_t flags)
-{
- void *ret;
-
- ret = kzalloc(size, flags | __GFP_NOWARN);
- if (!ret)
- ret = __vmalloc(size, flags | __GFP_ZERO, PAGE_KERNEL);
- return ret;
-}
-EXPORT_SYMBOL(libcfs_kvzalloc);
-
-void *libcfs_kvzalloc_cpt(struct cfs_cpt_table *cptab, int cpt, size_t size,
- gfp_t flags)
-{
- return kvzalloc_node(size, flags, cfs_cpt_spread_node(cptab, cpt));
-}
-EXPORT_SYMBOL(libcfs_kvzalloc_cpt);
diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c
deleted file mode 100644
index 6f92ea272186..000000000000
--- a/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c
+++ /dev/null
@@ -1,113 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * 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.
- *
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.gnu.org/licenses/gpl-2.0.html
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2011, 2012, Intel Corporation.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- */
-
-#define DEBUG_SUBSYSTEM S_LNET
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/fs_struct.h>
-#include <linux/sched/signal.h>
-
-#include <linux/libcfs/libcfs.h>
-
-#if defined(CONFIG_KGDB)
-#include <linux/kgdb.h>
-#endif
-
-sigset_t
-cfs_block_allsigs(void)
-{
- unsigned long flags;
- sigset_t old;
-
- spin_lock_irqsave(&current->sighand->siglock, flags);
- old = current->blocked;
- sigfillset(&current->blocked);
- recalc_sigpending();
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
-
- return old;
-}
-EXPORT_SYMBOL(cfs_block_allsigs);
-
-sigset_t cfs_block_sigs(unsigned long sigs)
-{
- unsigned long flags;
- sigset_t old;
-
- spin_lock_irqsave(&current->sighand->siglock, flags);
- old = current->blocked;
- sigaddsetmask(&current->blocked, sigs);
- recalc_sigpending();
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
- return old;
-}
-EXPORT_SYMBOL(cfs_block_sigs);
-
-/* Block all signals except for the @sigs */
-sigset_t cfs_block_sigsinv(unsigned long sigs)
-{
- unsigned long flags;
- sigset_t old;
-
- spin_lock_irqsave(&current->sighand->siglock, flags);
- old = current->blocked;
- sigaddsetmask(&current->blocked, ~sigs);
- recalc_sigpending();
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
-
- return old;
-}
-EXPORT_SYMBOL(cfs_block_sigsinv);
-
-void
-cfs_restore_sigs(sigset_t old)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&current->sighand->siglock, flags);
- current->blocked = old;
- recalc_sigpending();
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
-}
-EXPORT_SYMBOL(cfs_restore_sigs);
-
-void
-cfs_clear_sigpending(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&current->sighand->siglock, flags);
- clear_tsk_thread_flag(current, TIF_SIGPENDING);
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
-}
-EXPORT_SYMBOL(cfs_clear_sigpending);
diff --git a/drivers/staging/lustre/lnet/libcfs/tracefile.c b/drivers/staging/lustre/lnet/libcfs/tracefile.c
index 57913aae1d88..4affca750bc5 100644
--- a/drivers/staging/lustre/lnet/libcfs/tracefile.c
+++ b/drivers/staging/lustre/lnet/libcfs/tracefile.c
@@ -441,7 +441,7 @@ console:
if (cfs_time_after(cfs_time_current(),
cdls->cdls_next + libcfs_console_max_delay +
- cfs_time_seconds(10))) {
+ 10 * HZ)) {
/* last timeout was a long time ago */
cdls->cdls_delay /= libcfs_console_backoff * 4;
} else {
@@ -1071,7 +1071,7 @@ end_loop:
init_waitqueue_entry(&__wait, current);
add_wait_queue(&tctl->tctl_waitq, &__wait);
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
+ schedule_timeout(HZ);
remove_wait_queue(&tctl->tctl_waitq, &__wait);
}
complete(&tctl->tctl_stop);
diff --git a/drivers/staging/lustre/lnet/lnet/acceptor.c b/drivers/staging/lustre/lnet/lnet/acceptor.c
index ee85cab6f437..5648f17eddc0 100644
--- a/drivers/staging/lustre/lnet/lnet/acceptor.c
+++ b/drivers/staging/lustre/lnet/lnet/acceptor.c
@@ -240,7 +240,7 @@ lnet_accept(struct socket *sock, __u32 magic)
return -EPROTO;
}
- if (magic == le32_to_cpu(LNET_PROTO_TCP_MAGIC))
+ if (lnet_accept_magic(magic, LNET_PROTO_TCP_MAGIC))
str = "'old' socknal/tcpnal";
else
str = "unrecognised";
@@ -335,8 +335,6 @@ lnet_acceptor(void *arg)
LASSERT(!lnet_acceptor_state.pta_sock);
- cfs_block_allsigs();
-
rc = lnet_sock_listen(&lnet_acceptor_state.pta_sock, 0, accept_port,
accept_backlog);
if (rc) {
@@ -365,7 +363,7 @@ lnet_acceptor(void *arg)
if (rc != -EAGAIN) {
CWARN("Accept error %d: pausing...\n", rc);
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
+ schedule_timeout(HZ);
}
continue;
}
diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c
index 2c7abad57104..90266be0132d 100644
--- a/drivers/staging/lustre/lnet/lnet/api-ni.c
+++ b/drivers/staging/lustre/lnet/lnet/api-ni.c
@@ -961,19 +961,15 @@ static void
lnet_ping_md_unlink(struct lnet_ping_info *pinfo,
struct lnet_handle_md *md_handle)
{
- sigset_t blocked = cfs_block_allsigs();
-
LNetMDUnlink(*md_handle);
LNetInvalidateMDHandle(md_handle);
/* NB md could be busy; this just starts the unlink */
while (pinfo->pi_features != LNET_PING_FEAT_INVAL) {
CDEBUG(D_NET, "Still waiting for ping MD to unlink\n");
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
+ set_current_state(TASK_NOLOAD);
+ schedule_timeout(HZ);
}
-
- cfs_restore_sigs(blocked);
}
static void
@@ -1109,7 +1105,7 @@ lnet_clear_zombies_nis_locked(void)
libcfs_nid2str(ni->ni_nid));
}
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
+ schedule_timeout(HZ);
lnet_net_lock(LNET_LOCK_EX);
continue;
}
@@ -1218,6 +1214,7 @@ lnet_startup_lndni(struct lnet_ni *ni, struct lnet_ioctl_config_data *conf)
struct lnet_lnd *lnd;
struct lnet_tx_queue *tq;
int i;
+ u32 seed;
lnd_type = LNET_NETTYP(LNET_NIDNET(ni->ni_nid));
@@ -1356,6 +1353,12 @@ lnet_startup_lndni(struct lnet_ni *ni, struct lnet_ioctl_config_data *conf)
tq->tq_credits = lnet_ni_tq_credits(ni);
}
+ /* Nodes with small feet have little entropy. The NID for this
+ * node gives the most entropy in the low bits.
+ */
+ seed = LNET_NIDADDR(ni->ni_nid);
+ add_device_randomness(&seed, sizeof(seed));
+
CDEBUG(D_LNI, "Added LNI %s [%d/%d/%d/%d]\n",
libcfs_nid2str(ni->ni_nid), ni->ni_peertxcredits,
lnet_ni_tq_credits(ni) * LNET_CPT_NUMBER,
@@ -2141,7 +2144,6 @@ static int lnet_ping(struct lnet_process_id id, int timeout_ms,
int nob;
int rc;
int rc2;
- sigset_t blocked;
infosz = offsetof(struct lnet_ping_info, pi_ni[n_ids]);
@@ -2197,13 +2199,9 @@ static int lnet_ping(struct lnet_process_id id, int timeout_ms,
do {
/* MUST block for unlink to complete */
- if (unlinked)
- blocked = cfs_block_allsigs();
-
- rc2 = LNetEQPoll(&eqh, 1, timeout_ms, &event, &which);
- if (unlinked)
- cfs_restore_sigs(blocked);
+ rc2 = LNetEQPoll(&eqh, 1, timeout_ms, !unlinked,
+ &event, &which);
CDEBUG(D_NET, "poll %d(%d %d)%s\n", rc2,
(rc2 <= 0) ? -1 : event.type,
diff --git a/drivers/staging/lustre/lnet/lnet/lib-eq.c b/drivers/staging/lustre/lnet/lnet/lib-eq.c
index a173b69e2f92..ea53b5cb3f72 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-eq.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-eq.c
@@ -308,7 +308,7 @@ lnet_eq_dequeue_event(struct lnet_eq *eq, struct lnet_event *ev)
*/
static int
-lnet_eq_wait_locked(int *timeout_ms)
+lnet_eq_wait_locked(int *timeout_ms, long state)
__must_hold(&the_lnet.ln_eq_wait_lock)
{
int tms = *timeout_ms;
@@ -320,7 +320,7 @@ __must_hold(&the_lnet.ln_eq_wait_lock)
return -ENXIO; /* don't want to wait and no new event */
init_waitqueue_entry(&wl, current);
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(state);
add_wait_queue(&the_lnet.ln_eq_waitq, &wl);
lnet_eq_wait_unlock();
@@ -359,6 +359,7 @@ __must_hold(&the_lnet.ln_eq_wait_lock)
* \param timeout_ms Time in milliseconds to wait for an event to occur on
* one of the EQs. The constant LNET_TIME_FOREVER can be used to indicate an
* infinite timeout.
+ * \param interruptible, if true, use TASK_INTERRUPTIBLE, else TASK_NOLOAD
* \param event,which On successful return (1 or -EOVERFLOW), \a event will
* hold the next event in the EQs, and \a which will contain the index of the
* EQ from which the event was taken.
@@ -372,6 +373,7 @@ __must_hold(&the_lnet.ln_eq_wait_lock)
*/
int
LNetEQPoll(struct lnet_handle_eq *eventqs, int neq, int timeout_ms,
+ int interruptible,
struct lnet_event *event, int *which)
{
int wait = 1;
@@ -412,7 +414,9 @@ LNetEQPoll(struct lnet_handle_eq *eventqs, int neq, int timeout_ms,
* 0 : don't want to wait anymore, but might have new event
* so need to call dequeue again
*/
- wait = lnet_eq_wait_locked(&timeout_ms);
+ wait = lnet_eq_wait_locked(&timeout_ms,
+ interruptible ? TASK_INTERRUPTIBLE
+ : TASK_NOLOAD);
if (wait < 0) /* no new event */
break;
}
diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c
index c673037dbce4..ed43b3f4b114 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-move.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-move.c
@@ -524,7 +524,7 @@ lnet_peer_is_alive(struct lnet_peer *lp, unsigned long now)
return 0;
deadline = cfs_time_add(lp->lp_last_alive,
- cfs_time_seconds(lp->lp_ni->ni_peertimeout));
+ lp->lp_ni->ni_peertimeout * HZ);
alive = cfs_time_after(deadline, now);
/* Update obsolete lp_alive except for routers assumed to be dead
@@ -562,7 +562,7 @@ lnet_peer_alive_locked(struct lnet_peer *lp)
unsigned long next_query =
cfs_time_add(lp->lp_last_query,
- cfs_time_seconds(lnet_queryinterval));
+ lnet_queryinterval * HZ);
if (time_before(now, next_query)) {
if (lp->lp_alive)
diff --git a/drivers/staging/lustre/lnet/lnet/lib-ptl.c b/drivers/staging/lustre/lnet/lnet/lib-ptl.c
index 471f2f6c86f4..fc47379c5938 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-ptl.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-ptl.c
@@ -841,6 +841,7 @@ lnet_portals_destroy(void)
cfs_array_free(the_lnet.ln_portals);
the_lnet.ln_portals = NULL;
+ the_lnet.ln_nportals = 0;
}
int
@@ -851,12 +852,12 @@ lnet_portals_create(void)
size = offsetof(struct lnet_portal, ptl_mt_maps[LNET_CPT_NUMBER]);
- the_lnet.ln_nportals = MAX_PORTALS;
- the_lnet.ln_portals = cfs_array_alloc(the_lnet.ln_nportals, size);
+ the_lnet.ln_portals = cfs_array_alloc(MAX_PORTALS, size);
if (!the_lnet.ln_portals) {
CERROR("Failed to allocate portals table\n");
return -ENOMEM;
}
+ the_lnet.ln_nportals = MAX_PORTALS;
for (i = 0; i < the_lnet.ln_nportals; i++) {
if (lnet_ptl_setup(the_lnet.ln_portals[i], i)) {
diff --git a/drivers/staging/lustre/lnet/lnet/net_fault.c b/drivers/staging/lustre/lnet/lnet/net_fault.c
index e3468cef273b..a63b7941d435 100644
--- a/drivers/staging/lustre/lnet/lnet/net_fault.c
+++ b/drivers/staging/lustre/lnet/lnet/net_fault.c
@@ -315,9 +315,8 @@ drop_rule_match(struct lnet_drop_rule *rule, lnet_nid_t src,
rule->dr_time_base = now;
rule->dr_drop_time = rule->dr_time_base +
- cfs_time_seconds(
- prandom_u32_max(attr->u.drop.da_interval));
- rule->dr_time_base += cfs_time_seconds(attr->u.drop.da_interval);
+ prandom_u32_max(attr->u.drop.da_interval) * HZ;
+ rule->dr_time_base += attr->u.drop.da_interval * HZ;
CDEBUG(D_NET, "Drop Rule %s->%s: next drop : %lu\n",
libcfs_nid2str(attr->fa_src),
@@ -440,8 +439,7 @@ static struct delay_daemon_data delay_dd;
static unsigned long
round_timeout(unsigned long timeout)
{
- return cfs_time_seconds((unsigned int)
- cfs_duration_sec(cfs_time_sub(timeout, 0)) + 1);
+ return (unsigned int)rounddown(timeout, HZ) + HZ;
}
static void
@@ -483,10 +481,8 @@ delay_rule_match(struct lnet_delay_rule *rule, lnet_nid_t src,
rule->dl_time_base = now;
rule->dl_delay_time = rule->dl_time_base +
- cfs_time_seconds(
- prandom_u32_max(
- attr->u.delay.la_interval));
- rule->dl_time_base += cfs_time_seconds(attr->u.delay.la_interval);
+ prandom_u32_max(attr->u.delay.la_interval) * HZ;
+ rule->dl_time_base += attr->u.delay.la_interval * HZ;
CDEBUG(D_NET, "Delay Rule %s->%s: next delay : %lu\n",
libcfs_nid2str(attr->fa_src),
diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c
index 3e157c10fec4..3d4caa609c83 100644
--- a/drivers/staging/lustre/lnet/lnet/peer.c
+++ b/drivers/staging/lustre/lnet/lnet/peer.c
@@ -137,7 +137,7 @@ lnet_peer_table_deathrow_wait_locked(struct lnet_peer_table *ptable,
ptable->pt_zombies);
}
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1) >> 1);
+ schedule_timeout(HZ >> 1);
lnet_net_lock(cpt_locked);
}
}
diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c
index 6504761ca598..a3c3f4959f46 100644
--- a/drivers/staging/lustre/lnet/lnet/router.c
+++ b/drivers/staging/lustre/lnet/lnet/router.c
@@ -808,7 +808,7 @@ lnet_wait_known_routerstate(void)
return;
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
+ schedule_timeout(HZ);
}
}
@@ -1011,7 +1011,7 @@ lnet_ping_router_locked(struct lnet_peer *rtr)
if (secs && !rtr->lp_ping_notsent &&
cfs_time_after(now, cfs_time_add(rtr->lp_ping_timestamp,
- cfs_time_seconds(secs)))) {
+ secs * HZ))) {
int rc;
struct lnet_process_id id;
struct lnet_handle_md mdh;
@@ -1185,7 +1185,7 @@ lnet_prune_rc_data(int wait_unlink)
CDEBUG(((i & (-i)) == i) ? D_WARNING : D_NET,
"Waiting for rc buffers to unlink\n");
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1) / 4);
+ schedule_timeout(HZ / 4);
lnet_net_lock(LNET_LOCK_EX);
}
@@ -1226,8 +1226,6 @@ lnet_router_checker(void *arg)
struct lnet_peer *rtr;
struct list_head *entry;
- cfs_block_allsigs();
-
while (the_lnet.ln_rc_state == LNET_RC_STATE_RUNNING) {
__u64 version;
int cpt;
@@ -1282,7 +1280,7 @@ rescan:
else
wait_event_interruptible_timeout(the_lnet.ln_rc_waitq,
false,
- cfs_time_seconds(1));
+ HZ);
}
lnet_prune_rc_data(1); /* wait for UNLINK */
diff --git a/drivers/staging/lustre/lnet/selftest/conctl.c b/drivers/staging/lustre/lnet/selftest/conctl.c
index 34ba440b3c02..a2d8092bdeb7 100644
--- a/drivers/staging/lustre/lnet/selftest/conctl.c
+++ b/drivers/staging/lustre/lnet/selftest/conctl.c
@@ -648,14 +648,10 @@ static int lst_test_add_ioctl(struct lstio_test_args *args)
return -EINVAL;
if (args->lstio_tes_param) {
- param = kmalloc(args->lstio_tes_param_len, GFP_KERNEL);
- if (!param)
- goto out;
- if (copy_from_user(param, args->lstio_tes_param,
- args->lstio_tes_param_len)) {
- rc = -EFAULT;
- goto out;
- }
+ param = memdup_user(args->lstio_tes_param,
+ args->lstio_tes_param_len);
+ if (IS_ERR(param))
+ return PTR_ERR(param);
}
rc = -EFAULT;
@@ -674,7 +670,7 @@ static int lst_test_add_ioctl(struct lstio_test_args *args)
args->lstio_tes_param_len,
&ret, args->lstio_tes_resultp);
- if (ret)
+ if (!rc && ret)
rc = (copy_to_user(args->lstio_tes_retp, &ret,
sizeof(ret))) ? -EFAULT : 0;
out:
diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c
index 7aa515c34594..6dcc966b293b 100644
--- a/drivers/staging/lustre/lnet/selftest/conrpc.c
+++ b/drivers/staging/lustre/lnet/selftest/conrpc.c
@@ -359,7 +359,7 @@ lstcon_rpc_trans_postwait(struct lstcon_rpc_trans *trans, int timeout)
rc = wait_event_interruptible_timeout(trans->tas_waitq,
lstcon_rpc_trans_check(trans),
- cfs_time_seconds(timeout));
+ timeout * HZ);
rc = (rc > 0) ? 0 : ((rc < 0) ? -EINTR : -ETIMEDOUT);
mutex_lock(&console_session.ses_mutex);
@@ -1350,7 +1350,7 @@ lstcon_rpc_cleanup_wait(void)
CWARN("Session is shutting down, waiting for termination of transactions\n");
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
+ schedule_timeout(HZ);
mutex_lock(&console_session.ses_mutex);
}
diff --git a/drivers/staging/lustre/lnet/selftest/framework.c b/drivers/staging/lustre/lnet/selftest/framework.c
index c7697f66f663..0ca1e3a780ca 100644
--- a/drivers/staging/lustre/lnet/selftest/framework.c
+++ b/drivers/staging/lustre/lnet/selftest/framework.c
@@ -187,7 +187,7 @@ sfw_del_session_timer(void)
return 0;
}
- return EBUSY; /* racing with sfw_session_expired() */
+ return -EBUSY; /* racing with sfw_session_expired() */
}
static void
diff --git a/drivers/staging/lustre/lnet/selftest/rpc.c b/drivers/staging/lustre/lnet/selftest/rpc.c
index f8198ad1046e..9613b0a77007 100644
--- a/drivers/staging/lustre/lnet/selftest/rpc.c
+++ b/drivers/staging/lustre/lnet/selftest/rpc.c
@@ -1604,7 +1604,7 @@ srpc_startup(void)
/* 1 second pause to avoid timestamp reuse */
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
+ schedule_timeout(HZ);
srpc_data.rpc_matchbits = ((__u64)ktime_get_real_seconds()) << 48;
srpc_data.rpc_state = SRPC_STATE_NONE;
diff --git a/drivers/staging/lustre/lnet/selftest/selftest.h b/drivers/staging/lustre/lnet/selftest/selftest.h
index ad04534f000c..05466b85e1c0 100644
--- a/drivers/staging/lustre/lnet/selftest/selftest.h
+++ b/drivers/staging/lustre/lnet/selftest/selftest.h
@@ -575,7 +575,7 @@ swi_state2str(int state)
#define selftest_wait_events() \
do { \
set_current_state(TASK_UNINTERRUPTIBLE); \
- schedule_timeout(cfs_time_seconds(1) / 10); \
+ schedule_timeout(HZ / 10); \
} while (0)
#define lst_wait_until(cond, lock, fmt, ...) \
diff --git a/drivers/staging/lustre/lnet/selftest/timer.c b/drivers/staging/lustre/lnet/selftest/timer.c
index ab125a8524c5..1b2c5fc81358 100644
--- a/drivers/staging/lustre/lnet/selftest/timer.c
+++ b/drivers/staging/lustre/lnet/selftest/timer.c
@@ -170,14 +170,12 @@ stt_timer_main(void *arg)
{
int rc = 0;
- cfs_block_allsigs();
-
while (!stt_data.stt_shuttingdown) {
stt_check_timers(&stt_data.stt_prev_slot);
rc = wait_event_timeout(stt_data.stt_waitq,
stt_data.stt_shuttingdown,
- cfs_time_seconds(STTIMER_SLOTTIME));
+ STTIMER_SLOTTIME * HZ);
}
spin_lock(&stt_data.stt_lock);
diff --git a/drivers/staging/lustre/lustre/Kconfig b/drivers/staging/lustre/lustre/Kconfig
index 90d826946c6a..ccb78a945995 100644
--- a/drivers/staging/lustre/lustre/Kconfig
+++ b/drivers/staging/lustre/lustre/Kconfig
@@ -1,6 +1,5 @@
config LUSTRE_FS
tristate "Lustre file system client support"
- depends on m && !MIPS && !XTENSA && !SUPERH
depends on LNET
select CRYPTO
select CRYPTO_CRC32
diff --git a/drivers/staging/lustre/lustre/fid/fid_request.c b/drivers/staging/lustre/lustre/fid/fid_request.c
index 009c2367f74e..030680f37c79 100644
--- a/drivers/staging/lustre/lustre/fid/fid_request.c
+++ b/drivers/staging/lustre/lustre/fid/fid_request.c
@@ -118,22 +118,22 @@ static int seq_client_rpc(struct lu_client_seq *seq,
goto out_req;
out = req_capsule_server_get(&req->rq_pill, &RMF_SEQ_RANGE);
- *output = *out;
- if (!lu_seq_range_is_sane(output)) {
+ if (!lu_seq_range_is_sane(out)) {
CERROR("%s: Invalid range received from server: "
- DRANGE "\n", seq->lcs_name, PRANGE(output));
+ DRANGE "\n", seq->lcs_name, PRANGE(out));
rc = -EINVAL;
goto out_req;
}
- if (lu_seq_range_is_exhausted(output)) {
+ if (lu_seq_range_is_exhausted(out)) {
CERROR("%s: Range received from server is exhausted: "
- DRANGE "]\n", seq->lcs_name, PRANGE(output));
+ DRANGE "]\n", seq->lcs_name, PRANGE(out));
rc = -EINVAL;
goto out_req;
}
+ *output = *out;
CDEBUG_LIMIT(debug_mask, "%s: Allocated %s-sequence " DRANGE "]\n",
seq->lcs_name, opcname, PRANGE(output));
@@ -174,6 +174,7 @@ static int seq_client_alloc_seq(const struct lu_env *env,
if (rc) {
CERROR("%s: Can't allocate new meta-sequence, rc %d\n",
seq->lcs_name, rc);
+ *seqnr = U64_MAX;
return rc;
}
CDEBUG(D_INFO, "%s: New range - " DRANGE "\n",
@@ -192,71 +193,49 @@ static int seq_client_alloc_seq(const struct lu_env *env,
return rc;
}
-static int seq_fid_alloc_prep(struct lu_client_seq *seq,
- wait_queue_entry_t *link)
-{
- if (seq->lcs_update) {
- add_wait_queue(&seq->lcs_waitq, link);
- set_current_state(TASK_UNINTERRUPTIBLE);
- mutex_unlock(&seq->lcs_mutex);
-
- schedule();
-
- mutex_lock(&seq->lcs_mutex);
- remove_wait_queue(&seq->lcs_waitq, link);
- set_current_state(TASK_RUNNING);
- return -EAGAIN;
- }
- ++seq->lcs_update;
- mutex_unlock(&seq->lcs_mutex);
- return 0;
-}
-
-static void seq_fid_alloc_fini(struct lu_client_seq *seq)
-{
- LASSERT(seq->lcs_update == 1);
- mutex_lock(&seq->lcs_mutex);
- --seq->lcs_update;
- wake_up(&seq->lcs_waitq);
-}
-
/* Allocate new fid on passed client @seq and save it to @fid. */
int seq_client_alloc_fid(const struct lu_env *env,
struct lu_client_seq *seq, struct lu_fid *fid)
{
- wait_queue_entry_t link;
int rc;
LASSERT(seq);
LASSERT(fid);
- init_waitqueue_entry(&link, current);
- mutex_lock(&seq->lcs_mutex);
+ spin_lock(&seq->lcs_lock);
if (OBD_FAIL_CHECK(OBD_FAIL_SEQ_EXHAUST))
seq->lcs_fid.f_oid = seq->lcs_width;
- while (1) {
+ wait_event_cmd(seq->lcs_waitq,
+ (!fid_is_zero(&seq->lcs_fid) &&
+ fid_oid(&seq->lcs_fid) < seq->lcs_width) ||
+ !seq->lcs_update,
+ spin_unlock(&seq->lcs_lock),
+ spin_lock(&seq->lcs_lock));
+
+ if (!fid_is_zero(&seq->lcs_fid) &&
+ fid_oid(&seq->lcs_fid) < seq->lcs_width) {
+ /* Just bump last allocated fid and return to caller. */
+ seq->lcs_fid.f_oid += 1;
+ rc = 0;
+ } else {
u64 seqnr;
- if (!fid_is_zero(&seq->lcs_fid) &&
- fid_oid(&seq->lcs_fid) < seq->lcs_width) {
- /* Just bump last allocated fid and return to caller. */
- seq->lcs_fid.f_oid += 1;
- rc = 0;
- break;
- }
-
- rc = seq_fid_alloc_prep(seq, &link);
- if (rc)
- continue;
+ LASSERT(seq->lcs_update == 0);
+ seq->lcs_update = 1;
+ spin_unlock(&seq->lcs_lock);
rc = seq_client_alloc_seq(env, seq, &seqnr);
+
+ spin_lock(&seq->lcs_lock);
+ seq->lcs_update = 0;
+ wake_up(&seq->lcs_waitq);
+
if (rc) {
CERROR("%s: Can't allocate new sequence, rc %d\n",
seq->lcs_name, rc);
- seq_fid_alloc_fini(seq);
- mutex_unlock(&seq->lcs_mutex);
+ spin_unlock(&seq->lcs_lock);
return rc;
}
@@ -272,13 +251,10 @@ int seq_client_alloc_fid(const struct lu_env *env,
* to setup FLD for it.
*/
rc = 1;
-
- seq_fid_alloc_fini(seq);
- break;
}
*fid = seq->lcs_fid;
- mutex_unlock(&seq->lcs_mutex);
+ spin_unlock(&seq->lcs_lock);
CDEBUG(D_INFO,
"%s: Allocated FID " DFID "\n", seq->lcs_name, PFID(fid));
@@ -292,23 +268,14 @@ EXPORT_SYMBOL(seq_client_alloc_fid);
*/
void seq_client_flush(struct lu_client_seq *seq)
{
- wait_queue_entry_t link;
LASSERT(seq);
- init_waitqueue_entry(&link, current);
- mutex_lock(&seq->lcs_mutex);
-
- while (seq->lcs_update) {
- add_wait_queue(&seq->lcs_waitq, &link);
- set_current_state(TASK_UNINTERRUPTIBLE);
- mutex_unlock(&seq->lcs_mutex);
+ spin_lock(&seq->lcs_lock);
- schedule();
-
- mutex_lock(&seq->lcs_mutex);
- remove_wait_queue(&seq->lcs_waitq, &link);
- set_current_state(TASK_RUNNING);
- }
+ wait_event_cmd(seq->lcs_waitq,
+ !seq->lcs_update,
+ spin_unlock(&seq->lcs_lock),
+ spin_lock(&seq->lcs_lock));
fid_zero(&seq->lcs_fid);
/**
@@ -319,7 +286,7 @@ void seq_client_flush(struct lu_client_seq *seq)
seq->lcs_space.lsr_index = -1;
lu_seq_range_init(&seq->lcs_space);
- mutex_unlock(&seq->lcs_mutex);
+ spin_unlock(&seq->lcs_lock);
}
EXPORT_SYMBOL(seq_client_flush);
@@ -382,7 +349,7 @@ static int seq_client_init(struct lu_client_seq *seq,
seq->lcs_type = type;
- mutex_init(&seq->lcs_mutex);
+ spin_lock_init(&seq->lcs_lock);
if (type == LUSTRE_SEQ_METADATA)
seq->lcs_width = LUSTRE_METADATA_SEQ_MAX_WIDTH;
else
diff --git a/drivers/staging/lustre/lustre/fid/lproc_fid.c b/drivers/staging/lustre/lustre/fid/lproc_fid.c
index 083419f77697..a1e5bf9f36ec 100644
--- a/drivers/staging/lustre/lustre/fid/lproc_fid.c
+++ b/drivers/staging/lustre/lustre/fid/lproc_fid.c
@@ -98,33 +98,43 @@ ldebugfs_fid_space_seq_write(struct file *file,
size_t count, loff_t *off)
{
struct lu_client_seq *seq;
+ struct lu_seq_range range;
int rc;
seq = ((struct seq_file *)file->private_data)->private;
- mutex_lock(&seq->lcs_mutex);
- rc = ldebugfs_fid_write_common(buffer, count, &seq->lcs_space);
+ rc = ldebugfs_fid_write_common(buffer, count, &range);
- if (rc == 0) {
+ spin_lock(&seq->lcs_lock);
+ if (seq->lcs_update)
+ /* An RPC call is active to update lcs_space */
+ rc = -EBUSY;
+ if (rc > 0)
+ seq->lcs_space = range;
+ spin_unlock(&seq->lcs_lock);
+
+ if (rc > 0) {
CDEBUG(D_INFO, "%s: Space: " DRANGE "\n",
- seq->lcs_name, PRANGE(&seq->lcs_space));
+ seq->lcs_name, PRANGE(&range));
}
- mutex_unlock(&seq->lcs_mutex);
-
- return count;
+ return rc;
}
static int
ldebugfs_fid_space_seq_show(struct seq_file *m, void *unused)
{
struct lu_client_seq *seq = (struct lu_client_seq *)m->private;
+ int rc = 0;
- mutex_lock(&seq->lcs_mutex);
- seq_printf(m, "[%#llx - %#llx]:%x:%s\n", PRANGE(&seq->lcs_space));
- mutex_unlock(&seq->lcs_mutex);
+ spin_lock(&seq->lcs_lock);
+ if (seq->lcs_update)
+ rc = -EBUSY;
+ else
+ seq_printf(m, "[%#llx - %#llx]:%x:%s\n", PRANGE(&seq->lcs_space));
+ spin_unlock(&seq->lcs_lock);
- return 0;
+ return rc;
}
static ssize_t
@@ -142,7 +152,7 @@ ldebugfs_fid_width_seq_write(struct file *file,
if (rc)
return rc;
- mutex_lock(&seq->lcs_mutex);
+ spin_lock(&seq->lcs_lock);
if (seq->lcs_type == LUSTRE_SEQ_DATA)
max = LUSTRE_DATA_SEQ_MAX_WIDTH;
else
@@ -155,7 +165,7 @@ ldebugfs_fid_width_seq_write(struct file *file,
seq->lcs_width);
}
- mutex_unlock(&seq->lcs_mutex);
+ spin_unlock(&seq->lcs_lock);
return count;
}
@@ -165,9 +175,9 @@ ldebugfs_fid_width_seq_show(struct seq_file *m, void *unused)
{
struct lu_client_seq *seq = (struct lu_client_seq *)m->private;
- mutex_lock(&seq->lcs_mutex);
+ spin_lock(&seq->lcs_lock);
seq_printf(m, "%llu\n", seq->lcs_width);
- mutex_unlock(&seq->lcs_mutex);
+ spin_unlock(&seq->lcs_lock);
return 0;
}
@@ -177,9 +187,9 @@ ldebugfs_fid_fid_seq_show(struct seq_file *m, void *unused)
{
struct lu_client_seq *seq = (struct lu_client_seq *)m->private;
- mutex_lock(&seq->lcs_mutex);
+ spin_lock(&seq->lcs_lock);
seq_printf(m, DFID "\n", PFID(&seq->lcs_fid));
- mutex_unlock(&seq->lcs_mutex);
+ spin_unlock(&seq->lcs_lock);
return 0;
}
diff --git a/drivers/staging/lustre/lustre/fld/fld_cache.c b/drivers/staging/lustre/lustre/fld/fld_cache.c
index ecf8b9e1ed5c..2d61ca4e51cf 100644
--- a/drivers/staging/lustre/lustre/fld/fld_cache.c
+++ b/drivers/staging/lustre/lustre/fld/fld_cache.c
@@ -263,7 +263,7 @@ static void fld_cache_punch_hole(struct fld_cache *cache,
fldt = kzalloc(sizeof(*fldt), GFP_ATOMIC);
if (!fldt) {
kfree(f_new);
- /* overlap is not allowed, so dont mess up list. */
+ /* overlap is not allowed, so don't mess up list. */
return;
}
/* break f_curr RANGE into three RANGES:
diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h
index 90419dca2e1e..341a145c3331 100644
--- a/drivers/staging/lustre/lustre/include/cl_object.h
+++ b/drivers/staging/lustre/lustre/include/cl_object.h
@@ -1833,7 +1833,7 @@ struct cl_io {
*/
ci_verify_layout:1,
/**
- * file is released, restore has to to be triggered by vvp layer
+ * file is released, restore has to be triggered by vvp layer
*/
ci_restore_needed:1,
/**
diff --git a/drivers/staging/lustre/lustre/include/lprocfs_status.h b/drivers/staging/lustre/lustre/include/lprocfs_status.h
index 835a729dd8d0..426e8f3c9809 100644
--- a/drivers/staging/lustre/lustre/include/lprocfs_status.h
+++ b/drivers/staging/lustre/lustre/include/lprocfs_status.h
@@ -114,7 +114,7 @@ struct rename_stats {
* LPROCFS_CNTR_AVGMINMAX indicates a multi-valued counter samples,
* (i.e. counter can be incremented by more than "1"). When specified,
* the counter maintains min, max and sum in addition to a simple
- * invocation count. This allows averages to be be computed.
+ * invocation count. This allows averages to be computed.
* If not specified, the counter is an increment-by-1 counter.
* min, max, sum, etc. are not maintained.
*
diff --git a/drivers/staging/lustre/lustre/include/lu_object.h b/drivers/staging/lustre/lustre/include/lu_object.h
index 34e35fbff978..35c7b582f36d 100644
--- a/drivers/staging/lustre/lustre/include/lu_object.h
+++ b/drivers/staging/lustre/lustre/include/lu_object.h
@@ -1328,13 +1328,6 @@ struct lu_kmem_descr {
int lu_kmem_init(struct lu_kmem_descr *caches);
void lu_kmem_fini(struct lu_kmem_descr *caches);
-void lu_buf_free(struct lu_buf *buf);
-void lu_buf_alloc(struct lu_buf *buf, size_t size);
-void lu_buf_realloc(struct lu_buf *buf, size_t size);
-
-int lu_buf_check_and_grow(struct lu_buf *buf, size_t len);
-struct lu_buf *lu_buf_check_and_alloc(struct lu_buf *buf, size_t len);
-
extern __u32 lu_context_tags_default;
extern __u32 lu_session_tags_default;
diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm.h b/drivers/staging/lustre/lustre/include/lustre_dlm.h
index e0b17052b2ea..239aa2b1268f 100644
--- a/drivers/staging/lustre/lustre/include/lustre_dlm.h
+++ b/drivers/staging/lustre/lustre/include/lustre_dlm.h
@@ -60,7 +60,7 @@ struct obd_device;
#define OBD_LDLM_DEVICENAME "ldlm"
#define LDLM_DEFAULT_LRU_SIZE (100 * num_online_cpus())
-#define LDLM_DEFAULT_MAX_ALIVE (cfs_time_seconds(3900)) /* 65 min */
+#define LDLM_DEFAULT_MAX_ALIVE (65 * 60 * HZ) /* 65 min */
#define LDLM_DEFAULT_PARALLEL_AST_LIMIT 1024
/**
diff --git a/drivers/staging/lustre/lustre/include/lustre_export.h b/drivers/staging/lustre/lustre/include/lustre_export.h
index 66ac9dc7302a..40cd168ed2ea 100644
--- a/drivers/staging/lustre/lustre/include/lustre_export.h
+++ b/drivers/staging/lustre/lustre/include/lustre_export.h
@@ -87,6 +87,8 @@ struct obd_export {
struct obd_uuid exp_client_uuid;
/** To link all exports on an obd device */
struct list_head exp_obd_chain;
+ /** work_struct for destruction of export */
+ struct work_struct exp_zombie_work;
struct hlist_node exp_uuid_hash; /** uuid-export hash*/
/** Obd device of this export */
struct obd_device *exp_obd;
diff --git a/drivers/staging/lustre/lustre/include/lustre_fid.h b/drivers/staging/lustre/lustre/include/lustre_fid.h
index d19c7a27ee48..094ad282de2c 100644
--- a/drivers/staging/lustre/lustre/include/lustre_fid.h
+++ b/drivers/staging/lustre/lustre/include/lustre_fid.h
@@ -324,7 +324,7 @@ enum lu_mgr_type {
struct lu_client_seq {
/* Sequence-controller export. */
struct obd_export *lcs_exp;
- struct mutex lcs_mutex;
+ spinlock_t lcs_lock;
/*
* Range of allowed for allocation sequences. When using lu_client_seq on
diff --git a/drivers/staging/lustre/lustre/include/lustre_import.h b/drivers/staging/lustre/lustre/include/lustre_import.h
index ea158e0630e2..1731048f1ff2 100644
--- a/drivers/staging/lustre/lustre/include/lustre_import.h
+++ b/drivers/staging/lustre/lustre/include/lustre_import.h
@@ -162,8 +162,8 @@ struct obd_import {
struct ptlrpc_client *imp_client;
/** List element for linking into pinger chain */
struct list_head imp_pinger_chain;
- /** List element for linking into chain for destruction */
- struct list_head imp_zombie_chain;
+ /** work struct for destruction of import */
+ struct work_struct imp_zombie_work;
/**
* Lists of requests that are retained for replay, waiting for a reply,
diff --git a/drivers/staging/lustre/lustre/include/lustre_lib.h b/drivers/staging/lustre/lustre/include/lustre_lib.h
index ca1dce15337e..0053eafc1c10 100644
--- a/drivers/staging/lustre/lustre/include/lustre_lib.h
+++ b/drivers/staging/lustre/lustre/include/lustre_lib.h
@@ -76,281 +76,49 @@ int do_set_info_async(struct obd_import *imp,
void target_send_reply(struct ptlrpc_request *req, int rc, int fail_id);
-/*
- * l_wait_event is a flexible sleeping function, permitting simple caller
- * configuration of interrupt and timeout sensitivity along with actions to
- * be performed in the event of either exception.
- *
- * The first form of usage looks like this:
- *
- * struct l_wait_info lwi = LWI_TIMEOUT_INTR(timeout, timeout_handler,
- * intr_handler, callback_data);
- * rc = l_wait_event(waitq, condition, &lwi);
- *
- * l_wait_event() makes the current process wait on 'waitq' until 'condition'
- * is TRUE or a "killable" signal (SIGTERM, SIKGILL, SIGINT) is pending. It
- * returns 0 to signify 'condition' is TRUE, but if a signal wakes it before
- * 'condition' becomes true, it optionally calls the specified 'intr_handler'
- * if not NULL, and returns -EINTR.
- *
- * If a non-zero timeout is specified, signals are ignored until the timeout
- * has expired. At this time, if 'timeout_handler' is not NULL it is called.
- * If it returns FALSE l_wait_event() continues to wait as described above with
- * signals enabled. Otherwise it returns -ETIMEDOUT.
- *
- * LWI_INTR(intr_handler, callback_data) is shorthand for
- * LWI_TIMEOUT_INTR(0, NULL, intr_handler, callback_data)
- *
- * The second form of usage looks like this:
- *
- * struct l_wait_info lwi = LWI_TIMEOUT(timeout, timeout_handler);
- * rc = l_wait_event(waitq, condition, &lwi);
- *
- * This form is the same as the first except that it COMPLETELY IGNORES
- * SIGNALS. The caller must therefore beware that if 'timeout' is zero, or if
- * 'timeout_handler' is not NULL and returns FALSE, then the ONLY thing that
- * can unblock the current process is 'condition' becoming TRUE.
- *
- * Another form of usage is:
- * struct l_wait_info lwi = LWI_TIMEOUT_INTERVAL(timeout, interval,
- * timeout_handler);
- * rc = l_wait_event(waitq, condition, &lwi);
- * This is the same as previous case, but condition is checked once every
- * 'interval' jiffies (if non-zero).
- *
- * Subtle synchronization point: this macro does *not* necessary takes
- * wait-queue spin-lock before returning, and, hence, following idiom is safe
- * ONLY when caller provides some external locking:
- *
- * Thread1 Thread2
- *
- * l_wait_event(&obj->wq, ....); (1)
- *
- * wake_up(&obj->wq): (2)
- * spin_lock(&q->lock); (2.1)
- * __wake_up_common(q, ...); (2.2)
- * spin_unlock(&q->lock, flags); (2.3)
- *
- * kfree(obj); (3)
- *
- * As l_wait_event() may "short-cut" execution and return without taking
- * wait-queue spin-lock, some additional synchronization is necessary to
- * guarantee that step (3) can begin only after (2.3) finishes.
- *
- * XXX nikita: some ptlrpc daemon threads have races of that sort.
- *
- */
-static inline int back_to_sleep(void *arg)
-{
- return 0;
-}
-
-#define LWI_ON_SIGNAL_NOOP ((void (*)(void *))(-1))
-
-struct l_wait_info {
- long lwi_timeout;
- long lwi_interval;
- int lwi_allow_intr;
- int (*lwi_on_timeout)(void *);
- void (*lwi_on_signal)(void *);
- void *lwi_cb_data;
-};
-
-/* NB: LWI_TIMEOUT ignores signals completely */
-#define LWI_TIMEOUT(time, cb, data) \
-((struct l_wait_info) { \
- .lwi_timeout = time, \
- .lwi_on_timeout = cb, \
- .lwi_cb_data = data, \
- .lwi_interval = 0, \
- .lwi_allow_intr = 0 \
-})
-
-#define LWI_TIMEOUT_INTERVAL(time, interval, cb, data) \
-((struct l_wait_info) { \
- .lwi_timeout = time, \
- .lwi_on_timeout = cb, \
- .lwi_cb_data = data, \
- .lwi_interval = interval, \
- .lwi_allow_intr = 0 \
-})
-
-#define LWI_TIMEOUT_INTR(time, time_cb, sig_cb, data) \
-((struct l_wait_info) { \
- .lwi_timeout = time, \
- .lwi_on_timeout = time_cb, \
- .lwi_on_signal = sig_cb, \
- .lwi_cb_data = data, \
- .lwi_interval = 0, \
- .lwi_allow_intr = 0 \
-})
-
-#define LWI_TIMEOUT_INTR_ALL(time, time_cb, sig_cb, data) \
-((struct l_wait_info) { \
- .lwi_timeout = time, \
- .lwi_on_timeout = time_cb, \
- .lwi_on_signal = sig_cb, \
- .lwi_cb_data = data, \
- .lwi_interval = 0, \
- .lwi_allow_intr = 1 \
-})
-
-#define LWI_INTR(cb, data) LWI_TIMEOUT_INTR(0, NULL, cb, data)
-
#define LUSTRE_FATAL_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | \
sigmask(SIGTERM) | sigmask(SIGQUIT) | \
sigmask(SIGALRM))
-
-/**
- * wait_queue_entry_t of Linux (version < 2.6.34) is a FIFO list for exclusively
- * waiting threads, which is not always desirable because all threads will
- * be waken up again and again, even user only needs a few of them to be
- * active most time. This is not good for performance because cache can
- * be polluted by different threads.
- *
- * LIFO list can resolve this problem because we always wakeup the most
- * recent active thread by default.
- *
- * NB: please don't call non-exclusive & exclusive wait on the same
- * waitq if add_wait_queue_exclusive_head is used.
- */
-#define add_wait_queue_exclusive_head(waitq, link) \
-{ \
- unsigned long flags; \
- \
- spin_lock_irqsave(&((waitq)->lock), flags); \
- __add_wait_queue_exclusive(waitq, link); \
- spin_unlock_irqrestore(&((waitq)->lock), flags); \
+static inline int l_fatal_signal_pending(struct task_struct *p)
+{
+ return signal_pending(p) && sigtestsetmask(&p->pending.signal, LUSTRE_FATAL_SIGS);
}
-/*
- * wait for @condition to become true, but no longer than timeout, specified
- * by @info.
- */
-#define __l_wait_event(wq, condition, info, ret, l_add_wait) \
-do { \
- wait_queue_entry_t __wait; \
- long __timeout = info->lwi_timeout; \
- sigset_t __blocked; \
- int __allow_intr = info->lwi_allow_intr; \
- \
- ret = 0; \
- if (condition) \
- break; \
- \
- init_waitqueue_entry(&__wait, current); \
- l_add_wait(&wq, &__wait); \
- \
- /* Block all signals (just the non-fatal ones if no timeout). */ \
- if (info->lwi_on_signal && (__timeout == 0 || __allow_intr)) \
- __blocked = cfs_block_sigsinv(LUSTRE_FATAL_SIGS); \
- else \
- __blocked = cfs_block_sigsinv(0); \
- \
- for (;;) { \
- if (condition) \
- break; \
- \
- set_current_state(TASK_INTERRUPTIBLE); \
- \
- if (__timeout == 0) { \
- schedule(); \
- } else { \
- long interval = info->lwi_interval ? \
- min_t(long, \
- info->lwi_interval, __timeout) : \
- __timeout; \
- long remaining = schedule_timeout(interval);\
- __timeout = cfs_time_sub(__timeout, \
- cfs_time_sub(interval, remaining));\
- if (__timeout == 0) { \
- if (!info->lwi_on_timeout || \
- info->lwi_on_timeout(info->lwi_cb_data)) { \
- ret = -ETIMEDOUT; \
- break; \
- } \
- /* Take signals after the timeout expires. */ \
- if (info->lwi_on_signal) \
- (void)cfs_block_sigsinv(LUSTRE_FATAL_SIGS);\
- } \
- } \
- \
- set_current_state(TASK_RUNNING); \
- \
- if (condition) \
- break; \
- if (signal_pending(current)) { \
- if (info->lwi_on_signal && \
- (__timeout == 0 || __allow_intr)) { \
- if (info->lwi_on_signal != LWI_ON_SIGNAL_NOOP) \
- info->lwi_on_signal(info->lwi_cb_data);\
- ret = -EINTR; \
- break; \
- } \
- /* We have to do this here because some signals */ \
- /* are not blockable - ie from strace(1). */ \
- /* In these cases we want to schedule_timeout() */ \
- /* again, because we don't want that to return */ \
- /* -EINTR when the RPC actually succeeded. */ \
- /* the recalc_sigpending() below will deliver the */ \
- /* signal properly. */ \
- cfs_clear_sigpending(); \
- } \
- } \
- \
- cfs_restore_sigs(__blocked); \
- \
- remove_wait_queue(&wq, &__wait); \
-} while (0)
-
-#define l_wait_event(wq, condition, info) \
-({ \
- int __ret; \
- struct l_wait_info *__info = (info); \
- \
- __l_wait_event(wq, condition, __info, \
- __ret, add_wait_queue); \
- __ret; \
-})
+/** @} lib */
-#define l_wait_event_exclusive(wq, condition, info) \
-({ \
- int __ret; \
- struct l_wait_info *__info = (info); \
- \
- __l_wait_event(wq, condition, __info, \
- __ret, add_wait_queue_exclusive); \
- __ret; \
-})
-#define l_wait_event_exclusive_head(wq, condition, info) \
-({ \
- int __ret; \
- struct l_wait_info *__info = (info); \
- \
- __l_wait_event(wq, condition, __info, \
- __ret, add_wait_queue_exclusive_head); \
- __ret; \
-})
-#define l_wait_condition(wq, condition) \
-({ \
- struct l_wait_info lwi = { 0 }; \
- l_wait_event(wq, condition, &lwi); \
+/* l_wait_event_abortable() is a bit like wait_event_killable()
+ * except there is a fixed set of signals which will abort:
+ * LUSTRE_FATAL_SIGS
+ */
+#define l_wait_event_abortable(wq, condition) \
+({ \
+ sigset_t __old_blocked; \
+ int __ret = 0; \
+ cfs_block_sigsinv(LUSTRE_FATAL_SIGS, &__old_blocked); \
+ __ret = wait_event_interruptible(wq, condition); \
+ cfs_restore_sigs(&__old_blocked); \
+ __ret; \
})
-#define l_wait_condition_exclusive(wq, condition) \
-({ \
- struct l_wait_info lwi = { 0 }; \
- l_wait_event_exclusive(wq, condition, &lwi); \
+#define l_wait_event_abortable_timeout(wq, condition, timeout) \
+({ \
+ sigset_t __old_blocked; \
+ int __ret = 0; \
+ cfs_block_sigsinv(LUSTRE_FATAL_SIGS, &__old_blocked); \
+ __ret = wait_event_interruptible_timeout(wq, condition, timeout);\
+ cfs_restore_sigs(&__old_blocked); \
+ __ret; \
})
-#define l_wait_condition_exclusive_head(wq, condition) \
-({ \
- struct l_wait_info lwi = { 0 }; \
- l_wait_event_exclusive_head(wq, condition, &lwi); \
+#define l_wait_event_abortable_exclusive(wq, condition) \
+({ \
+ sigset_t __old_blocked; \
+ int __ret = 0; \
+ cfs_block_sigsinv(LUSTRE_FATAL_SIGS, &__old_blocked); \
+ __ret = wait_event_interruptible_exclusive(wq, condition); \
+ cfs_restore_sigs(&__old_blocked); \
+ __ret; \
})
-
-/** @} lib */
-
#endif /* _LUSTRE_LIB_H */
diff --git a/drivers/staging/lustre/lustre/include/lustre_lmv.h b/drivers/staging/lustre/lustre/include/lustre_lmv.h
index f4298e5f7543..080ec1f8e19f 100644
--- a/drivers/staging/lustre/lustre/include/lustre_lmv.h
+++ b/drivers/staging/lustre/lustre/include/lustre_lmv.h
@@ -63,7 +63,7 @@ lsm_md_eq(const struct lmv_stripe_md *lsm1, const struct lmv_stripe_md *lsm2)
lsm1->lsm_md_master_mdt_index != lsm2->lsm_md_master_mdt_index ||
lsm1->lsm_md_hash_type != lsm2->lsm_md_hash_type ||
lsm1->lsm_md_layout_version != lsm2->lsm_md_layout_version ||
- !strcmp(lsm1->lsm_md_pool_name, lsm2->lsm_md_pool_name))
+ strcmp(lsm1->lsm_md_pool_name, lsm2->lsm_md_pool_name) != 0)
return false;
for (idx = 0; idx < lsm1->lsm_md_stripe_count; idx++) {
diff --git a/drivers/staging/lustre/lustre/include/lustre_mdc.h b/drivers/staging/lustre/lustre/include/lustre_mdc.h
index 007e1ec3f0f4..a9c9992a2502 100644
--- a/drivers/staging/lustre/lustre/include/lustre_mdc.h
+++ b/drivers/staging/lustre/lustre/include/lustre_mdc.h
@@ -124,7 +124,7 @@ static inline void mdc_get_rpc_lock(struct mdc_rpc_lock *lck,
*/
while (unlikely(lck->rpcl_it == MDC_FAKE_RPCL_IT)) {
mutex_unlock(&lck->rpcl_mutex);
- schedule_timeout(cfs_time_seconds(1) / 4);
+ schedule_timeout(HZ / 4);
goto again;
}
diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h
index 3ff5de4770e8..d35ae0cda8d2 100644
--- a/drivers/staging/lustre/lustre/include/lustre_net.h
+++ b/drivers/staging/lustre/lustre/include/lustre_net.h
@@ -1259,8 +1259,6 @@ enum {
SVC_STOPPING = 1 << 1,
SVC_STARTING = 1 << 2,
SVC_RUNNING = 1 << 3,
- SVC_EVENT = 1 << 4,
- SVC_SIGNAL = 1 << 5,
};
#define PTLRPC_THR_NAME_LEN 32
@@ -1303,11 +1301,6 @@ struct ptlrpc_thread {
char t_name[PTLRPC_THR_NAME_LEN];
};
-static inline int thread_is_init(struct ptlrpc_thread *thread)
-{
- return thread->t_flags == 0;
-}
-
static inline int thread_is_stopped(struct ptlrpc_thread *thread)
{
return !!(thread->t_flags & SVC_STOPPED);
@@ -1328,16 +1321,6 @@ static inline int thread_is_running(struct ptlrpc_thread *thread)
return !!(thread->t_flags & SVC_RUNNING);
}
-static inline int thread_is_event(struct ptlrpc_thread *thread)
-{
- return !!(thread->t_flags & SVC_EVENT);
-}
-
-static inline int thread_is_signal(struct ptlrpc_thread *thread)
-{
- return !!(thread->t_flags & SVC_SIGNAL);
-}
-
static inline void thread_clear_flags(struct ptlrpc_thread *thread, __u32 flags)
{
thread->t_flags &= ~flags;
@@ -1821,6 +1804,9 @@ int ptlrpc_register_rqbd(struct ptlrpc_request_buffer_desc *rqbd);
*/
void ptlrpc_request_committed(struct ptlrpc_request *req, int force);
+int ptlrpc_inc_ref(void);
+void ptlrpc_dec_ref(void);
+
void ptlrpc_init_client(int req_portal, int rep_portal, char *name,
struct ptlrpc_client *);
struct ptlrpc_connection *ptlrpc_uuid_to_connection(struct obd_uuid *uuid);
@@ -2268,7 +2254,7 @@ static inline int ptlrpc_send_limit_expired(struct ptlrpc_request *req)
{
if (req->rq_delay_limit != 0 &&
time_before(cfs_time_add(req->rq_queued_time,
- cfs_time_seconds(req->rq_delay_limit)),
+ req->rq_delay_limit * HZ),
cfs_time_current())) {
return 1;
}
diff --git a/drivers/staging/lustre/lustre/include/lustre_sec.h b/drivers/staging/lustre/lustre/include/lustre_sec.h
index 64b6fd4fed8f..c5cb07acd0da 100644
--- a/drivers/staging/lustre/lustre/include/lustre_sec.h
+++ b/drivers/staging/lustre/lustre/include/lustre_sec.h
@@ -1058,9 +1058,6 @@ int sptlrpc_current_user_desc_size(void);
int sptlrpc_pack_user_desc(struct lustre_msg *msg, int offset);
int sptlrpc_unpack_user_desc(struct lustre_msg *req, int offset, int swabbed);
-#define CFS_CAP_CHOWN_MASK (1 << CFS_CAP_CHOWN)
-#define CFS_CAP_SYS_RESOURCE_MASK (1 << CFS_CAP_SYS_RESOURCE)
-
enum {
LUSTRE_SEC_NONE = 0,
LUSTRE_SEC_REMOTE = 1,
diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h
index 4368f4e9f208..f1233ca7d337 100644
--- a/drivers/staging/lustre/lustre/include/obd.h
+++ b/drivers/staging/lustre/lustre/include/obd.h
@@ -191,7 +191,7 @@ struct client_obd {
struct sptlrpc_flavor cl_flvr_mgc; /* fixed flavor of mgc->mgs */
/* the grant values are protected by loi_list_lock below */
- unsigned long cl_dirty_pages; /* all _dirty_ in pahges */
+ unsigned long cl_dirty_pages; /* all _dirty_ in pages */
unsigned long cl_dirty_max_pages; /* allowed w/o rpc */
unsigned long cl_dirty_transit; /* dirty synchronous */
unsigned long cl_avail_grant; /* bytes of credit for ost */
diff --git a/drivers/staging/lustre/lustre/include/obd_class.h b/drivers/staging/lustre/lustre/include/obd_class.h
index 531e8ddfa9e5..f24dd74ffa09 100644
--- a/drivers/staging/lustre/lustre/include/obd_class.h
+++ b/drivers/staging/lustre/lustre/include/obd_class.h
@@ -294,10 +294,10 @@ struct obdo;
void obdo_to_ioobj(const struct obdo *oa, struct obd_ioobj *ioobj);
-#define OBT(dev) (dev)->obd_type
-#define OBP(dev, op) (dev)->obd_type->typ_dt_ops->op
-#define MDP(dev, op) (dev)->obd_type->typ_md_ops->op
-#define CTXTP(ctxt, op) (ctxt)->loc_logops->lop_##op
+#define OBT(dev) ((dev)->obd_type)
+#define OBP(dev, op) ((dev)->obd_type->typ_dt_ops->op)
+#define MDP(dev, op) ((dev)->obd_type->typ_md_ops->op)
+#define CTXTP(ctxt, op) ((ctxt)->loc_logops->lop_##op)
/*
* Ensure obd_setup: used for cleanup which must be called
diff --git a/drivers/staging/lustre/lustre/include/obd_support.h b/drivers/staging/lustre/lustre/include/obd_support.h
index 3f4fe290f6ea..8595091b8b86 100644
--- a/drivers/staging/lustre/lustre/include/obd_support.h
+++ b/drivers/staging/lustre/lustre/include/obd_support.h
@@ -516,7 +516,7 @@ extern char obd_jobid_var[];
#define POISON_PTR(ptr) ((void)0)
#else
#define POISON(ptr, c, s) memset(ptr, c, s)
-#define POISON_PTR(ptr) (ptr) = (void *)0xdeadbeef
+#define POISON_PTR(ptr) ((ptr) = (void *)0xdeadbeef)
#endif
#ifdef POISON_BULK
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
index 657ab95091a0..411b540b96d9 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
@@ -310,24 +310,6 @@ reprocess:
return LDLM_ITER_CONTINUE;
}
-struct ldlm_flock_wait_data {
- struct ldlm_lock *fwd_lock;
-};
-
-static void
-ldlm_flock_interrupted_wait(void *data)
-{
- struct ldlm_lock *lock;
-
- lock = ((struct ldlm_flock_wait_data *)data)->fwd_lock;
-
- lock_res_and_lock(lock);
-
- /* client side - set flag to prevent lock from being put on LRU list */
- ldlm_set_cbpending(lock);
- unlock_res_and_lock(lock);
-}
-
/**
* Flock completion callback function.
*
@@ -342,8 +324,6 @@ int
ldlm_flock_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)
{
struct file_lock *getlk = lock->l_ast_data;
- struct ldlm_flock_wait_data fwd;
- struct l_wait_info lwi;
int rc = 0;
OBD_FAIL_TIMEOUT(OBD_FAIL_LDLM_CP_CB_WAIT2, 4);
@@ -372,13 +352,17 @@ ldlm_flock_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)
LDLM_DEBUG(lock,
"client-side enqueue returned a blocked lock, sleeping");
- fwd.fwd_lock = lock;
- lwi = LWI_TIMEOUT_INTR(0, NULL, ldlm_flock_interrupted_wait, &fwd);
/* Go to sleep until the lock is granted. */
- rc = l_wait_event(lock->l_waitq, is_granted_or_cancelled(lock), &lwi);
+ rc = l_wait_event_abortable(lock->l_waitq, is_granted_or_cancelled(lock));
if (rc) {
+ lock_res_and_lock(lock);
+
+ /* client side - set flag to prevent lock from being put on LRU list */
+ ldlm_set_cbpending(lock);
+ unlock_res_and_lock(lock);
+
LDLM_DEBUG(lock, "client-side enqueue waking up: failed (%d)",
rc);
return rc;
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
index 7cbc6a06afec..95bea351d21d 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
@@ -1349,7 +1349,6 @@ out:
if ((flags & LDLM_FL_LVB_READY) && !ldlm_is_lvb_ready(lock)) {
__u64 wait_flags = LDLM_FL_LVB_READY |
LDLM_FL_DESTROYED | LDLM_FL_FAIL_NOTIFIED;
- struct l_wait_info lwi;
if (lock->l_completion_ast) {
int err = lock->l_completion_ast(lock,
@@ -1366,13 +1365,10 @@ out:
}
}
- lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(obd_timeout),
- NULL, LWI_ON_SIGNAL_NOOP, NULL);
-
/* XXX FIXME see comment on CAN_MATCH in lustre_dlm.h */
- l_wait_event(lock->l_waitq,
- lock->l_flags & wait_flags,
- &lwi);
+ wait_event_idle_timeout(lock->l_waitq,
+ lock->l_flags & wait_flags,
+ obd_timeout * HZ);
if (!ldlm_is_lvb_ready(lock)) {
if (flags & LDLM_FL_TEST_LOCK)
LDLM_LOCK_RELEASE(lock);
@@ -1913,14 +1909,12 @@ void ldlm_cancel_callback(struct ldlm_lock *lock)
ldlm_set_bl_done(lock);
wake_up_all(&lock->l_waitq);
} else if (!ldlm_is_bl_done(lock)) {
- struct l_wait_info lwi = { 0 };
-
/*
* The lock is guaranteed to have been canceled once
* returning from this function.
*/
unlock_res_and_lock(lock);
- l_wait_event(lock->l_waitq, is_bl_done(lock), &lwi);
+ wait_event_idle(lock->l_waitq, is_bl_done(lock));
lock_res_and_lock(lock);
}
}
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
index 5f6e7c933b81..c772c68e5a49 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
@@ -163,7 +163,7 @@ static void ldlm_handle_cp_callback(struct ptlrpc_request *req,
LDLM_DEBUG(lock, "client completion callback handler START");
if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_CANCEL_BL_CB_RACE)) {
- int to = cfs_time_seconds(1);
+ int to = HZ;
while (to > 0) {
set_current_state(TASK_INTERRUPTIBLE);
@@ -327,7 +327,7 @@ static void ldlm_handle_gl_callback(struct ptlrpc_request *req,
!lock->l_readers && !lock->l_writers &&
cfs_time_after(cfs_time_current(),
cfs_time_add(lock->l_last_used,
- cfs_time_seconds(10)))) {
+ 10 * HZ))) {
unlock_res_and_lock(lock);
if (ldlm_bl_to_thread_lock(ns, NULL, lock))
ldlm_handle_bl_callback(ns, NULL, lock);
@@ -833,17 +833,15 @@ static int ldlm_bl_thread_main(void *arg)
/* cannot use bltd after this, it is only on caller's stack */
while (1) {
- struct l_wait_info lwi = { 0 };
struct ldlm_bl_work_item *blwi = NULL;
struct obd_export *exp = NULL;
int rc;
rc = ldlm_bl_get_work(blp, &blwi, &exp);
if (!rc)
- l_wait_event_exclusive(blp->blp_waitq,
- ldlm_bl_get_work(blp, &blwi,
- &exp),
- &lwi);
+ wait_event_idle_exclusive(blp->blp_waitq,
+ ldlm_bl_get_work(blp, &blwi,
+ &exp));
atomic_inc(&blp->blp_busy_threads);
if (ldlm_bl_thread_need_create(blp, blwi))
@@ -871,6 +869,10 @@ int ldlm_get_ref(void)
{
int rc = 0;
+ rc = ptlrpc_inc_ref();
+ if (rc)
+ return rc;
+
mutex_lock(&ldlm_ref_mutex);
if (++ldlm_refcount == 1) {
rc = ldlm_setup();
@@ -879,14 +881,18 @@ int ldlm_get_ref(void)
}
mutex_unlock(&ldlm_ref_mutex);
+ if (rc)
+ ptlrpc_dec_ref();
+
return rc;
}
void ldlm_put_ref(void)
{
+ int rc = 0;
mutex_lock(&ldlm_ref_mutex);
if (ldlm_refcount == 1) {
- int rc = ldlm_cleanup();
+ rc = ldlm_cleanup();
if (rc)
CERROR("ldlm_cleanup failed: %d\n", rc);
@@ -896,6 +902,8 @@ void ldlm_put_ref(void)
ldlm_refcount--;
}
mutex_unlock(&ldlm_ref_mutex);
+ if (!rc)
+ ptlrpc_dec_ref();
}
static ssize_t cancel_unused_locks_before_replay_show(struct kobject *kobj,
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
index 8563bd32befa..53b8f33e54b5 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
@@ -784,9 +784,6 @@ static int ldlm_pool_granted(struct ldlm_pool *pl)
return atomic_read(&pl->pl_granted);
}
-static struct ptlrpc_thread *ldlm_pools_thread;
-static struct completion ldlm_pools_comp;
-
/*
* count locks from all namespaces (if possible). Returns number of
* cached locks.
@@ -899,8 +896,12 @@ static unsigned long ldlm_pools_cli_scan(struct shrinker *s,
sc->gfp_mask);
}
-static int ldlm_pools_recalc(enum ldlm_side client)
+static void ldlm_pools_recalc(struct work_struct *ws);
+static DECLARE_DELAYED_WORK(ldlm_recalc_pools, ldlm_pools_recalc);
+
+static void ldlm_pools_recalc(struct work_struct *ws)
{
+ enum ldlm_side client = LDLM_NAMESPACE_CLIENT;
struct ldlm_namespace *ns;
struct ldlm_namespace *ns_old = NULL;
/* seconds of sleep if no active namespaces */
@@ -982,97 +983,19 @@ static int ldlm_pools_recalc(enum ldlm_side client)
/* Wake up the blocking threads from time to time. */
ldlm_bl_thread_wakeup();
- return time;
-}
-
-static int ldlm_pools_thread_main(void *arg)
-{
- struct ptlrpc_thread *thread = (struct ptlrpc_thread *)arg;
- int c_time;
-
- thread_set_flags(thread, SVC_RUNNING);
- wake_up(&thread->t_ctl_waitq);
-
- CDEBUG(D_DLMTRACE, "%s: pool thread starting, process %d\n",
- "ldlm_poold", current_pid());
-
- while (1) {
- struct l_wait_info lwi;
-
- /*
- * Recal all pools on this tick.
- */
- c_time = ldlm_pools_recalc(LDLM_NAMESPACE_CLIENT);
-
- /*
- * Wait until the next check time, or until we're
- * stopped.
- */
- lwi = LWI_TIMEOUT(cfs_time_seconds(c_time),
- NULL, NULL);
- l_wait_event(thread->t_ctl_waitq,
- thread_is_stopping(thread) ||
- thread_is_event(thread),
- &lwi);
-
- if (thread_test_and_clear_flags(thread, SVC_STOPPING))
- break;
- thread_test_and_clear_flags(thread, SVC_EVENT);
- }
-
- thread_set_flags(thread, SVC_STOPPED);
- wake_up(&thread->t_ctl_waitq);
-
- CDEBUG(D_DLMTRACE, "%s: pool thread exiting, process %d\n",
- "ldlm_poold", current_pid());
-
- complete_and_exit(&ldlm_pools_comp, 0);
+ schedule_delayed_work(&ldlm_recalc_pools, time * HZ);
}
static int ldlm_pools_thread_start(void)
{
- struct l_wait_info lwi = { 0 };
- struct task_struct *task;
-
- if (ldlm_pools_thread)
- return -EALREADY;
-
- ldlm_pools_thread = kzalloc(sizeof(*ldlm_pools_thread), GFP_NOFS);
- if (!ldlm_pools_thread)
- return -ENOMEM;
-
- init_completion(&ldlm_pools_comp);
- init_waitqueue_head(&ldlm_pools_thread->t_ctl_waitq);
+ schedule_delayed_work(&ldlm_recalc_pools, 0);
- task = kthread_run(ldlm_pools_thread_main, ldlm_pools_thread,
- "ldlm_poold");
- if (IS_ERR(task)) {
- CERROR("Can't start pool thread, error %ld\n", PTR_ERR(task));
- kfree(ldlm_pools_thread);
- ldlm_pools_thread = NULL;
- return PTR_ERR(task);
- }
- l_wait_event(ldlm_pools_thread->t_ctl_waitq,
- thread_is_running(ldlm_pools_thread), &lwi);
return 0;
}
static void ldlm_pools_thread_stop(void)
{
- if (!ldlm_pools_thread)
- return;
-
- thread_set_flags(ldlm_pools_thread, SVC_STOPPING);
- wake_up(&ldlm_pools_thread->t_ctl_waitq);
-
- /*
- * Make sure that pools thread is finished before freeing @thread.
- * This fixes possible race and oops due to accessing freed memory
- * in pools thread.
- */
- wait_for_completion(&ldlm_pools_comp);
- kfree(ldlm_pools_thread);
- ldlm_pools_thread = NULL;
+ cancel_delayed_work_sync(&ldlm_recalc_pools);
}
static struct shrinker ldlm_pools_cli_shrinker = {
@@ -1086,20 +1009,15 @@ int ldlm_pools_init(void)
int rc;
rc = ldlm_pools_thread_start();
- if (rc)
- return rc;
-
- rc = register_shrinker(&ldlm_pools_cli_shrinker);
- if (rc)
- ldlm_pools_thread_stop();
+ if (!rc)
+ rc = register_shrinker(&ldlm_pools_cli_shrinker);
return rc;
}
void ldlm_pools_fini(void)
{
- if (ldlm_pools_thread)
- unregister_shrinker(&ldlm_pools_cli_shrinker);
+ unregister_shrinker(&ldlm_pools_cli_shrinker);
ldlm_pools_thread_stop();
}
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
index 6aa37463db46..c3c9186b74ce 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
@@ -72,15 +72,6 @@ MODULE_PARM_DESC(ldlm_enqueue_min, "lock enqueue timeout minimum");
/* in client side, whether the cached locks will be canceled before replay */
unsigned int ldlm_cancel_unused_locks_before_replay = 1;
-static void interrupted_completion_wait(void *data)
-{
-}
-
-struct lock_wait_data {
- struct ldlm_lock *lwd_lock;
- __u32 lwd_conn_cnt;
-};
-
struct ldlm_async_args {
struct lustre_handle lock_handle;
};
@@ -112,10 +103,8 @@ static int ldlm_request_bufsize(int count, int type)
return sizeof(struct ldlm_request) + avail;
}
-static int ldlm_expired_completion_wait(void *data)
+static void ldlm_expired_completion_wait(struct ldlm_lock *lock, __u32 conn_cnt)
{
- struct lock_wait_data *lwd = data;
- struct ldlm_lock *lock = lwd->lwd_lock;
struct obd_import *imp;
struct obd_device *obd;
@@ -135,19 +124,17 @@ static int ldlm_expired_completion_wait(void *data)
if (last_dump == 0)
libcfs_debug_dumplog();
}
- return 0;
+ return;
}
obd = lock->l_conn_export->exp_obd;
imp = obd->u.cli.cl_import;
- ptlrpc_fail_import(imp, lwd->lwd_conn_cnt);
+ ptlrpc_fail_import(imp, conn_cnt);
LDLM_ERROR(lock,
"lock timed out (enqueued at %lld, %llds ago), entering recovery for %s@%s",
(s64)lock->l_last_activity,
(s64)(ktime_get_real_seconds() - lock->l_last_activity),
obd2cli_tgt(obd), imp->imp_connection->c_remote_uuid.uuid);
-
- return 0;
}
/**
@@ -251,11 +238,10 @@ EXPORT_SYMBOL(ldlm_completion_ast_async);
int ldlm_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data)
{
/* XXX ALLOCATE - 160 bytes */
- struct lock_wait_data lwd;
struct obd_device *obd;
struct obd_import *imp = NULL;
- struct l_wait_info lwi;
__u32 timeout;
+ __u32 conn_cnt = 0;
int rc = 0;
if (flags == LDLM_FL_WAIT_NOREPROC) {
@@ -281,32 +267,33 @@ noreproc:
timeout = ldlm_cp_timeout(lock);
- lwd.lwd_lock = lock;
lock->l_last_activity = ktime_get_real_seconds();
- if (ldlm_is_no_timeout(lock)) {
- LDLM_DEBUG(lock, "waiting indefinitely because of NO_TIMEOUT");
- lwi = LWI_INTR(interrupted_completion_wait, &lwd);
- } else {
- lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(timeout),
- ldlm_expired_completion_wait,
- interrupted_completion_wait, &lwd);
- }
-
if (imp) {
spin_lock(&imp->imp_lock);
- lwd.lwd_conn_cnt = imp->imp_conn_cnt;
+ conn_cnt = imp->imp_conn_cnt;
spin_unlock(&imp->imp_lock);
}
-
if (OBD_FAIL_CHECK_RESET(OBD_FAIL_LDLM_INTR_CP_AST,
OBD_FAIL_LDLM_CP_BL_RACE | OBD_FAIL_ONCE)) {
ldlm_set_fail_loc(lock);
rc = -EINTR;
} else {
- /* Go to sleep until the lock is granted or cancelled. */
- rc = l_wait_event(lock->l_waitq,
- is_granted_or_cancelled(lock), &lwi);
+ /* Go to sleep until the lock is granted or canceled. */
+ if (!ldlm_is_no_timeout(lock)) {
+ /* Wait uninterruptible for a while first */
+ rc = wait_event_idle_timeout(lock->l_waitq,
+ is_granted_or_cancelled(lock),
+ timeout * HZ);
+ if (rc == 0)
+ ldlm_expired_completion_wait(lock, conn_cnt);
+ }
+ /* Now wait abortable */
+ if (rc == 0)
+ rc = l_wait_event_abortable(lock->l_waitq,
+ is_granted_or_cancelled(lock));
+ else
+ rc = 0;
}
if (rc) {
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
index 9958533cc227..4c44603ab6f9 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
@@ -799,7 +799,7 @@ static void cleanup_resource(struct ldlm_resource *res, struct list_head *q,
LDLM_DEBUG(lock, "setting FL_LOCAL_ONLY");
if (lock->l_flags & LDLM_FL_FAIL_LOC) {
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(4));
+ schedule_timeout(4 * HZ);
set_current_state(TASK_RUNNING);
}
if (lock->l_completion_ast)
@@ -879,7 +879,6 @@ static int __ldlm_namespace_free(struct ldlm_namespace *ns, int force)
ldlm_namespace_cleanup(ns, force ? LDLM_FL_LOCAL_ONLY : 0);
if (atomic_read(&ns->ns_bref) > 0) {
- struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
int rc;
CDEBUG(D_DLMTRACE,
@@ -887,11 +886,12 @@ static int __ldlm_namespace_free(struct ldlm_namespace *ns, int force)
ldlm_ns_name(ns), atomic_read(&ns->ns_bref));
force_wait:
if (force)
- lwi = LWI_TIMEOUT(msecs_to_jiffies(obd_timeout *
- MSEC_PER_SEC) / 4, NULL, NULL);
-
- rc = l_wait_event(ns->ns_waitq,
- atomic_read(&ns->ns_bref) == 0, &lwi);
+ rc = wait_event_idle_timeout(ns->ns_waitq,
+ atomic_read(&ns->ns_bref) == 0,
+ obd_timeout * HZ / 4) ? 0 : -ETIMEDOUT;
+ else
+ rc = l_wait_event_abortable(ns->ns_waitq,
+ atomic_read(&ns->ns_bref) == 0);
/* Forced cleanups should be able to reclaim all references,
* so it's safe to wait forever... we can't leak locks...
diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c
index 549369739d80..11b82c639bfe 100644
--- a/drivers/staging/lustre/lustre/llite/dcache.c
+++ b/drivers/staging/lustre/lustre/llite/dcache.c
@@ -74,6 +74,12 @@ static void ll_release(struct dentry *de)
* an AST before calling d_revalidate_it(). The dentry still exists (marked
* INVALID) so d_lookup() matches it, but we have no lock on it (so
* lock_match() fails) and we spin around real_lookup().
+ *
+ * This race doesn't apply to lookups in d_alloc_parallel(), and for
+ * those we want to ensure that only one dentry with a given name is
+ * in ll_lookup_nd() at a time. So allow invalid dentries to match
+ * while d_in_lookup(). We will be called again when the lookup
+ * completes, and can give a different answer then.
*/
static int ll_dcompare(const struct dentry *dentry,
unsigned int len, const char *str,
@@ -90,7 +96,11 @@ static int ll_dcompare(const struct dentry *dentry,
d_count(dentry));
/* mountpoint is always valid */
- if (d_mountpoint((struct dentry *)dentry))
+ if (d_mountpoint(dentry))
+ return 0;
+
+ /* ensure exclusion against parallel lookup of the same name */
+ if (d_in_lookup((struct dentry *)dentry))
return 0;
if (d_lustre_invalid(dentry))
@@ -111,7 +121,7 @@ static int ll_ddelete(const struct dentry *de)
LASSERT(de);
CDEBUG(D_DENTRY, "%s dentry %pd (%p, parent %p, inode %p) %s%s\n",
- d_lustre_invalid((struct dentry *)de) ? "deleting" : "keeping",
+ d_lustre_invalid(de) ? "deleting" : "keeping",
de, de, de->d_parent, d_inode(de),
d_unhashed(de) ? "" : "hashed,",
list_empty(&de->d_subdirs) ? "" : "subdirs");
@@ -119,7 +129,7 @@ static int ll_ddelete(const struct dentry *de)
/* kernel >= 2.6.38 last refcount is decreased after this function. */
LASSERT(d_count(de) == 1);
- if (d_lustre_invalid((struct dentry *)de))
+ if (d_lustre_invalid(de))
return 1;
return 0;
}
diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c
index 99b0b77c75f5..d10d27268323 100644
--- a/drivers/staging/lustre/lustre/llite/dir.c
+++ b/drivers/staging/lustre/lustre/llite/dir.c
@@ -885,7 +885,7 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
switch (cmd) {
case Q_SETQUOTA:
case Q_SETINFO:
- if (!capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN))
return -EPERM;
break;
case Q_GETQUOTA:
@@ -893,7 +893,7 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
!uid_eq(current_euid(), make_kuid(&init_user_ns, id))) ||
(type == GRPQUOTA &&
!in_egroup_p(make_kgid(&init_user_ns, id)))) &&
- !capable(CFS_CAP_SYS_ADMIN))
+ !capable(CAP_SYS_ADMIN))
return -EPERM;
break;
case Q_GETINFO:
@@ -1452,7 +1452,7 @@ out_quotactl:
}
case OBD_IOC_CHANGELOG_SEND:
case OBD_IOC_CHANGELOG_CLEAR:
- if (!capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN))
return -EPERM;
rc = copy_and_ioctl(cmd, sbi->ll_md_exp, (void __user *)arg,
@@ -1497,7 +1497,7 @@ out_quotactl:
if (totalsize >= MDS_MAXREQSIZE / 3)
return -E2BIG;
- hur = libcfs_kvzalloc(totalsize, GFP_NOFS);
+ hur = kzalloc(totalsize, GFP_NOFS);
if (!hur)
return -ENOMEM;
@@ -1556,7 +1556,7 @@ out_quotactl:
return rc;
}
case LL_IOC_HSM_CT_START:
- if (!capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN))
return -EPERM;
rc = copy_and_ioctl(cmd, sbi->ll_md_exp, (void __user *)arg,
diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c
index 938b859b6650..ca5faea13b7e 100644
--- a/drivers/staging/lustre/lustre/llite/file.c
+++ b/drivers/staging/lustre/lustre/llite/file.c
@@ -1315,10 +1315,10 @@ static int ll_lov_setea(struct inode *inode, struct file *file,
sizeof(struct lov_user_ost_data);
int rc;
- if (!capable(CFS_CAP_SYS_ADMIN))
+ if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- lump = libcfs_kvzalloc(lum_size, GFP_NOFS);
+ lump = kzalloc(lum_size, GFP_NOFS);
if (!lump)
return -ENOMEM;
@@ -1570,7 +1570,7 @@ int ll_fid2path(struct inode *inode, void __user *arg)
size_t outsize;
int rc;
- if (!capable(CFS_CAP_DAC_READ_SEARCH) &&
+ if (!capable(CAP_DAC_READ_SEARCH) &&
!(ll_i2sbi(inode)->ll_flags & LL_SBI_USER_FID2PATH))
return -EPERM;
@@ -1840,7 +1840,7 @@ int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss)
* NOT defined in HSM_USER_MASK.
*/
if (((hss->hss_setmask | hss->hss_clearmask) & ~HSM_USER_MASK) &&
- !capable(CFS_CAP_SYS_ADMIN))
+ !capable(CAP_SYS_ADMIN))
return -EPERM;
/* Detect out-of range archive id */
@@ -2998,7 +2998,7 @@ static int ll_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
num_bytes = sizeof(*fiemap) + (extent_count *
sizeof(struct fiemap_extent));
- fiemap = libcfs_kvzalloc(num_bytes, GFP_NOFS);
+ fiemap = kvzalloc(num_bytes, GFP_KERNEL);
if (!fiemap)
return -ENOMEM;
@@ -3361,7 +3361,7 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock)
goto out;
}
- lvbdata = libcfs_kvzalloc(lmmsize, GFP_NOFS);
+ lvbdata = kvzalloc(lmmsize, GFP_NOFS);
if (!lvbdata) {
rc = -ENOMEM;
goto out;
diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h
index f68c2e88f12b..d46bcf71b273 100644
--- a/drivers/staging/lustre/lustre/llite/llite_internal.h
+++ b/drivers/staging/lustre/lustre/llite/llite_internal.h
@@ -1070,8 +1070,8 @@ struct ll_statahead_info {
sai_agl_valid:1,/* AGL is valid for the dir */
sai_in_readpage:1;/* statahead in readdir() */
wait_queue_head_t sai_waitq; /* stat-ahead wait queue */
- struct ptlrpc_thread sai_thread; /* stat-ahead thread */
- struct ptlrpc_thread sai_agl_thread; /* AGL thread */
+ struct task_struct *sai_task; /* stat-ahead thread */
+ struct task_struct *sai_agl_task; /* AGL thread */
struct list_head sai_interim_entries; /* entries which got async
* stat reply, but not
* instantiated
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
index 6735a6f006d2..e7500c53fafc 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -879,9 +879,15 @@ int ll_fill_super(struct super_block *sb)
CDEBUG(D_VFSTRACE, "VFS Op: sb %p\n", sb);
+ err = ptlrpc_inc_ref();
+ if (err)
+ return err;
+
cfg = kzalloc(sizeof(*cfg), GFP_NOFS);
- if (!cfg)
- return -ENOMEM;
+ if (!cfg) {
+ err = -ENOMEM;
+ goto out_put;
+ }
try_module_get(THIS_MODULE);
@@ -891,7 +897,8 @@ int ll_fill_super(struct super_block *sb)
if (!sbi) {
module_put(THIS_MODULE);
kfree(cfg);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto out_put;
}
err = ll_options(lsi->lsi_lmd->lmd_opts, &sbi->ll_flags);
@@ -958,6 +965,9 @@ out_free:
LCONSOLE_WARN("Mounted %s\n", profilenm);
kfree(cfg);
+out_put:
+ if (err)
+ ptlrpc_dec_ref();
return err;
} /* ll_fill_super */
@@ -986,16 +996,12 @@ void ll_put_super(struct super_block *sb)
}
/* Wait for unstable pages to be committed to stable storage */
- if (!force) {
- struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
-
- rc = l_wait_event(sbi->ll_cache->ccc_unstable_waitq,
- !atomic_long_read(&sbi->ll_cache->ccc_unstable_nr),
- &lwi);
- }
+ if (!force)
+ rc = l_wait_event_abortable(sbi->ll_cache->ccc_unstable_waitq,
+ !atomic_long_read(&sbi->ll_cache->ccc_unstable_nr));
ccc_count = atomic_long_read(&sbi->ll_cache->ccc_unstable_nr);
- if (!force && rc != -EINTR)
+ if (!force && rc != -ERESTARTSYS)
LASSERTF(!ccc_count, "count: %li\n", ccc_count);
/* We need to set force before the lov_disconnect in
@@ -1032,6 +1038,8 @@ void ll_put_super(struct super_block *sb)
cl_env_cache_purge(~0);
module_put(THIS_MODULE);
+
+ ptlrpc_dec_ref();
} /* client_put_super */
struct inode *ll_inode_from_resource_lock(struct ldlm_lock *lock)
@@ -1197,13 +1205,12 @@ static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md)
lmv_free_memmd(lli->lli_lsm_md);
lli->lli_lsm_md = NULL;
return 0;
- } else {
- /*
- * The lustre_md from req does not include stripeEA,
- * see ll_md_setattr
- */
- return 0;
}
+ /*
+ * The lustre_md from req does not include stripeEA,
+ * see ll_md_setattr
+ */
+ return 0;
}
/* set the directory layout */
@@ -1454,7 +1461,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import)
/* POSIX: check before ATTR_*TIME_SET set (from setattr_prepare) */
if (attr->ia_valid & TIMES_SET_FLAGS) {
if ((!uid_eq(current_fsuid(), inode->i_uid)) &&
- !capable(CFS_CAP_FOWNER))
+ !capable(CAP_FOWNER))
return -EPERM;
}
@@ -1988,8 +1995,7 @@ void ll_umount_begin(struct super_block *sb)
struct ll_sb_info *sbi = ll_s2sbi(sb);
struct obd_device *obd;
struct obd_ioctl_data *ioc_data;
- wait_queue_head_t waitq;
- struct l_wait_info lwi;
+ int cnt = 0;
CDEBUG(D_VFSTRACE, "VFS Op: superblock %p count %d active %d\n", sb,
sb->s_count, atomic_read(&sb->s_active));
@@ -2025,10 +2031,10 @@ void ll_umount_begin(struct super_block *sb)
* and then continue. For now, we just periodically checking for vfs
* to decrement mnt_cnt and hope to finish it within 10sec.
*/
- init_waitqueue_head(&waitq);
- lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(10),
- cfs_time_seconds(1), NULL, NULL);
- l_wait_event(waitq, may_umount(sbi->ll_mnt.mnt), &lwi);
+ while (cnt < 10 && !may_umount(sbi->ll_mnt.mnt)) {
+ schedule_timeout_uninterruptible(HZ);
+ cnt++;
+ }
schedule();
}
@@ -2143,7 +2149,7 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req,
md.posix_acl = NULL;
}
#endif
- rc = -ENOMEM;
+ rc = PTR_ERR(*inode);
CERROR("new_inode -fatal: rc %d\n", rc);
goto out;
}
@@ -2602,7 +2608,7 @@ int ll_getparent(struct file *file, struct getparent __user *arg)
u32 linkno;
int rc;
- if (!capable(CFS_CAP_DAC_READ_SEARCH) &&
+ if (!capable(CAP_DAC_READ_SEARCH) &&
!(ll_i2sbi(inode)->ll_flags & LL_SBI_USER_FID2PATH))
return -EPERM;
@@ -2653,7 +2659,7 @@ int ll_getparent(struct file *file, struct getparent __user *arg)
}
lb_free:
- lu_buf_free(&buf);
+ kvfree(buf.lb_buf);
ldata_free:
kfree(ldata);
return rc;
diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c
index c0533bd6f352..214b07554e62 100644
--- a/drivers/staging/lustre/lustre/llite/llite_mmap.c
+++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c
@@ -177,14 +177,14 @@ static int ll_page_mkwrite0(struct vm_area_struct *vma, struct page *vmpage,
vio->u.fault.ft_vma = vma;
vio->u.fault.ft_vmpage = vmpage;
- set = cfs_block_sigsinv(sigmask(SIGKILL) | sigmask(SIGTERM));
+ cfs_block_sigsinv(sigmask(SIGKILL) | sigmask(SIGTERM), &set);
inode = vvp_object_inode(io->ci_obj);
lli = ll_i2info(inode);
result = cl_io_loop(env, io);
- cfs_restore_sigs(set);
+ cfs_restore_sigs(&set);
if (result == 0) {
struct inode *inode = file_inode(vma->vm_file);
@@ -334,7 +334,7 @@ static int ll_fault(struct vm_fault *vmf)
* so that it can be killed by admin but not cause segfault by
* other signals.
*/
- set = cfs_block_sigsinv(sigmask(SIGKILL) | sigmask(SIGTERM));
+ cfs_block_sigsinv(sigmask(SIGKILL) | sigmask(SIGTERM), &set);
restart:
result = ll_fault0(vmf->vma, vmf);
@@ -360,7 +360,7 @@ restart:
result = VM_FAULT_LOCKED;
}
- cfs_restore_sigs(set);
+ cfs_restore_sigs(&set);
return result;
}
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c
index a2687f46a16d..6c9ec462eb41 100644
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -380,52 +380,45 @@ void ll_i2gids(__u32 *suppgids, struct inode *i1, struct inode *i2)
}
/*
- * try to reuse three types of dentry:
- * 1. unhashed alias, this one is unhashed by d_invalidate (but it may be valid
- * by concurrent .revalidate).
- * 2. INVALID alias (common case for no valid ldlm lock held, but this flag may
- * be cleared by others calling d_lustre_revalidate).
- * 3. DISCONNECTED alias.
+ * Try to reuse unhashed or invalidated dentries.
+ * This is very similar to d_exact_alias(), and any changes in one should be
+ * considered for inclusion in the other. The differences are that we don't
+ * need an unhashed alias, and we don't want d_compare to be used for
+ * comparison.
*/
static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry)
{
- struct dentry *alias, *discon_alias, *invalid_alias;
+ struct dentry *alias;
if (hlist_empty(&inode->i_dentry))
return NULL;
- discon_alias = NULL;
- invalid_alias = NULL;
-
spin_lock(&inode->i_lock);
hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
LASSERT(alias != dentry);
+ /*
+ * Don't need alias->d_lock here, because aliases with
+ * d_parent == entry->d_parent are not subject to name or
+ * parent changes, because the parent inode i_mutex is held.
+ */
- spin_lock(&alias->d_lock);
- if ((alias->d_flags & DCACHE_DISCONNECTED) &&
- S_ISDIR(inode->i_mode))
- /* LASSERT(last_discon == NULL); LU-405, bz 20055 */
- discon_alias = alias;
- else if (alias->d_parent == dentry->d_parent &&
- alias->d_name.hash == dentry->d_name.hash &&
- alias->d_name.len == dentry->d_name.len &&
- memcmp(alias->d_name.name, dentry->d_name.name,
- dentry->d_name.len) == 0)
- invalid_alias = alias;
- spin_unlock(&alias->d_lock);
-
- if (invalid_alias)
- break;
- }
- alias = invalid_alias ?: discon_alias ?: NULL;
- if (alias) {
+ if (alias->d_parent != dentry->d_parent)
+ continue;
+ if (alias->d_name.hash != dentry->d_name.hash)
+ continue;
+ if (alias->d_name.len != dentry->d_name.len ||
+ memcmp(alias->d_name.name, dentry->d_name.name,
+ dentry->d_name.len) != 0)
+ continue;
spin_lock(&alias->d_lock);
dget_dlock(alias);
spin_unlock(&alias->d_lock);
+ spin_unlock(&inode->i_lock);
+ return alias;
}
spin_unlock(&inode->i_lock);
- return alias;
+ return NULL;
}
/*
@@ -434,7 +427,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry)
*/
struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de)
{
- if (inode) {
+ if (inode && !S_ISDIR(inode->i_mode)) {
struct dentry *new = ll_find_alias(inode, de);
if (new) {
@@ -445,8 +438,13 @@ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de)
new, d_inode(new), d_count(new), new->d_flags);
return new;
}
+ d_add(de, inode);
+ } else {
+ struct dentry *new = d_splice_alias(inode, de);
+
+ if (new)
+ de = new;
}
- d_add(de, inode);
CDEBUG(D_DENTRY, "Add dentry %p inode %p refc %d flags %#x\n",
de, d_inode(de), d_count(de), de->d_flags);
return de;
diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c
index 90c7324575e4..155ce3cf6f60 100644
--- a/drivers/staging/lustre/lustre/llite/statahead.c
+++ b/drivers/staging/lustre/lustre/llite/statahead.c
@@ -267,7 +267,7 @@ sa_kill(struct ll_statahead_info *sai, struct sa_entry *entry)
/* called by scanner after use, sa_entry will be killed */
static void
-sa_put(struct ll_statahead_info *sai, struct sa_entry *entry)
+sa_put(struct ll_statahead_info *sai, struct sa_entry *entry, struct ll_inode_info *lli)
{
struct sa_entry *tmp, *next;
@@ -295,7 +295,11 @@ sa_put(struct ll_statahead_info *sai, struct sa_entry *entry)
sa_kill(sai, tmp);
}
- wake_up(&sai->sai_thread.t_ctl_waitq);
+ spin_lock(&lli->lli_sa_lock);
+ if (sai->sai_task)
+ wake_up_process(sai->sai_task);
+ spin_unlock(&lli->lli_sa_lock);
+
}
/*
@@ -383,7 +387,7 @@ static void ll_agl_add(struct ll_statahead_info *sai,
}
if (added > 0)
- wake_up(&sai->sai_agl_thread.t_ctl_waitq);
+ wake_up_process(sai->sai_agl_task);
}
/* allocate sai */
@@ -403,8 +407,6 @@ static struct ll_statahead_info *ll_sai_alloc(struct dentry *dentry)
sai->sai_max = LL_SA_RPC_MIN;
sai->sai_index = 1;
init_waitqueue_head(&sai->sai_waitq);
- init_waitqueue_head(&sai->sai_thread.t_ctl_waitq);
- init_waitqueue_head(&sai->sai_agl_thread.t_ctl_waitq);
INIT_LIST_HEAD(&sai->sai_interim_entries);
INIT_LIST_HEAD(&sai->sai_entries);
@@ -466,8 +468,8 @@ static void ll_sai_put(struct ll_statahead_info *sai)
lli->lli_sai = NULL;
spin_unlock(&lli->lli_sa_lock);
- LASSERT(thread_is_stopped(&sai->sai_thread));
- LASSERT(thread_is_stopped(&sai->sai_agl_thread));
+ LASSERT(sai->sai_task == NULL);
+ LASSERT(sai->sai_agl_task == NULL);
LASSERT(sai->sai_sent == sai->sai_replied);
LASSERT(!sa_has_callback(sai));
@@ -647,7 +649,6 @@ static int ll_statahead_interpret(struct ptlrpc_request *req,
struct ll_inode_info *lli = ll_i2info(dir);
struct ll_statahead_info *sai = lli->lli_sai;
struct sa_entry *entry = (struct sa_entry *)minfo->mi_cbdata;
- wait_queue_head_t *waitq = NULL;
__u64 handle = 0;
if (it_disposition(it, DISP_LOOKUP_NEG))
@@ -658,7 +659,6 @@ static int ll_statahead_interpret(struct ptlrpc_request *req,
* sai should be always valid, no need to refcount
*/
LASSERT(sai);
- LASSERT(!thread_is_stopped(&sai->sai_thread));
LASSERT(entry);
CDEBUG(D_READA, "sa_entry %.*s rc %d\n",
@@ -682,8 +682,9 @@ static int ll_statahead_interpret(struct ptlrpc_request *req,
spin_lock(&lli->lli_sa_lock);
if (rc) {
if (__sa_make_ready(sai, entry, rc))
- waitq = &sai->sai_waitq;
+ wake_up(&sai->sai_waitq);
} else {
+ int first = 0;
entry->se_minfo = minfo;
entry->se_req = ptlrpc_request_addref(req);
/*
@@ -694,14 +695,15 @@ static int ll_statahead_interpret(struct ptlrpc_request *req,
*/
entry->se_handle = handle;
if (!sa_has_callback(sai))
- waitq = &sai->sai_thread.t_ctl_waitq;
+ first = 1;
list_add_tail(&entry->se_list, &sai->sai_interim_entries);
+
+ if (first && sai->sai_task)
+ wake_up_process(sai->sai_task);
}
sai->sai_replied++;
- if (waitq)
- wake_up(waitq);
spin_unlock(&lli->lli_sa_lock);
return rc;
@@ -861,37 +863,13 @@ static int ll_agl_thread(void *arg)
struct inode *dir = d_inode(parent);
struct ll_inode_info *plli = ll_i2info(dir);
struct ll_inode_info *clli;
- struct ll_sb_info *sbi = ll_i2sbi(dir);
- struct ll_statahead_info *sai;
- struct ptlrpc_thread *thread;
- struct l_wait_info lwi = { 0 };
+ /* We already own this reference, so it is safe to take it without a lock. */
+ struct ll_statahead_info *sai = plli->lli_sai;
- sai = ll_sai_get(dir);
- thread = &sai->sai_agl_thread;
- thread->t_pid = current_pid();
CDEBUG(D_READA, "agl thread started: sai %p, parent %pd\n",
sai, parent);
- atomic_inc(&sbi->ll_agl_total);
- spin_lock(&plli->lli_agl_lock);
- sai->sai_agl_valid = 1;
- if (thread_is_init(thread))
- /* If someone else has changed the thread state
- * (e.g. already changed to SVC_STOPPING), we can't just
- * blindly overwrite that setting.
- */
- thread_set_flags(thread, SVC_RUNNING);
- spin_unlock(&plli->lli_agl_lock);
- wake_up(&thread->t_ctl_waitq);
-
- while (1) {
- l_wait_event(thread->t_ctl_waitq,
- !list_empty(&sai->sai_agls) ||
- !thread_is_running(thread),
- &lwi);
-
- if (!thread_is_running(thread))
- break;
+ while (!kthread_should_stop()) {
spin_lock(&plli->lli_agl_lock);
/* The statahead thread maybe help to process AGL entries,
@@ -906,6 +884,12 @@ static int ll_agl_thread(void *arg)
} else {
spin_unlock(&plli->lli_agl_lock);
}
+
+ set_current_state(TASK_IDLE);
+ if (list_empty(&sai->sai_agls) &&
+ !kthread_should_stop())
+ schedule();
+ __set_current_state(TASK_RUNNING);
}
spin_lock(&plli->lli_agl_lock);
@@ -919,20 +903,16 @@ static int ll_agl_thread(void *arg)
iput(&clli->lli_vfs_inode);
spin_lock(&plli->lli_agl_lock);
}
- thread_set_flags(thread, SVC_STOPPED);
spin_unlock(&plli->lli_agl_lock);
- wake_up(&thread->t_ctl_waitq);
- ll_sai_put(sai);
CDEBUG(D_READA, "agl thread stopped: sai %p, parent %pd\n",
sai, parent);
+ ll_sai_put(sai);
return 0;
}
/* start agl thread */
static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai)
{
- struct ptlrpc_thread *thread = &sai->sai_agl_thread;
- struct l_wait_info lwi = { 0 };
struct ll_inode_info *plli;
struct task_struct *task;
@@ -940,17 +920,22 @@ static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai)
sai, parent);
plli = ll_i2info(d_inode(parent));
- task = kthread_run(ll_agl_thread, parent, "ll_agl_%u",
- plli->lli_opendir_pid);
+ task = kthread_create(ll_agl_thread, parent, "ll_agl_%u",
+ plli->lli_opendir_pid);
if (IS_ERR(task)) {
CERROR("can't start ll_agl thread, rc: %ld\n", PTR_ERR(task));
- thread_set_flags(thread, SVC_STOPPED);
return;
}
- l_wait_event(thread->t_ctl_waitq,
- thread_is_running(thread) || thread_is_stopped(thread),
- &lwi);
+ sai->sai_agl_task = task;
+ atomic_inc(&ll_i2sbi(d_inode(parent))->ll_agl_total);
+ spin_lock(&plli->lli_agl_lock);
+ sai->sai_agl_valid = 1;
+ spin_unlock(&plli->lli_agl_lock);
+ /* Get an extra reference that the thread holds */
+ ll_sai_get(d_inode(parent));
+
+ wake_up_process(task);
}
/* statahead thread main function */
@@ -960,20 +945,13 @@ static int ll_statahead_thread(void *arg)
struct inode *dir = d_inode(parent);
struct ll_inode_info *lli = ll_i2info(dir);
struct ll_sb_info *sbi = ll_i2sbi(dir);
- struct ll_statahead_info *sai;
- struct ptlrpc_thread *sa_thread;
- struct ptlrpc_thread *agl_thread;
+ struct ll_statahead_info *sai = lli->lli_sai;
struct page *page = NULL;
__u64 pos = 0;
int first = 0;
int rc = 0;
struct md_op_data *op_data;
- struct l_wait_info lwi = { 0 };
- sai = ll_sai_get(dir);
- sa_thread = &sai->sai_thread;
- agl_thread = &sai->sai_agl_thread;
- sa_thread->t_pid = current_pid();
CDEBUG(D_READA, "statahead thread starting: sai %p, parent %pd\n",
sai, parent);
@@ -986,21 +964,7 @@ static int ll_statahead_thread(void *arg)
op_data->op_max_pages = ll_i2sbi(dir)->ll_md_brw_pages;
- if (sbi->ll_flags & LL_SBI_AGL_ENABLED)
- ll_start_agl(parent, sai);
-
- atomic_inc(&sbi->ll_sa_total);
- spin_lock(&lli->lli_sa_lock);
- if (thread_is_init(sa_thread))
- /* If someone else has changed the thread state
- * (e.g. already changed to SVC_STOPPING), we can't just
- * blindly overwrite that setting.
- */
- thread_set_flags(sa_thread, SVC_RUNNING);
- spin_unlock(&lli->lli_sa_lock);
- wake_up(&sa_thread->t_ctl_waitq);
-
- while (pos != MDS_DIR_END_OFF && thread_is_running(sa_thread)) {
+ while (pos != MDS_DIR_END_OFF && sai->sai_task) {
struct lu_dirpage *dp;
struct lu_dirent *ent;
@@ -1017,7 +981,7 @@ static int ll_statahead_thread(void *arg)
dp = page_address(page);
for (ent = lu_dirent_start(dp);
- ent && thread_is_running(sa_thread) && !sa_low_hit(sai);
+ ent && sai->sai_task && !sa_low_hit(sai);
ent = lu_dirent_next(ent)) {
struct lu_fid fid;
__u64 hash;
@@ -1067,14 +1031,7 @@ static int ll_statahead_thread(void *arg)
fid_le_to_cpu(&fid, &ent->lde_fid);
- /* wait for spare statahead window */
do {
- l_wait_event(sa_thread->t_ctl_waitq,
- !sa_sent_full(sai) ||
- sa_has_callback(sai) ||
- !list_empty(&sai->sai_agls) ||
- !thread_is_running(sa_thread),
- &lwi);
sa_handle_callback(sai);
spin_lock(&lli->lli_agl_lock);
@@ -1094,8 +1051,16 @@ static int ll_statahead_thread(void *arg)
spin_lock(&lli->lli_agl_lock);
}
spin_unlock(&lli->lli_agl_lock);
- } while (sa_sent_full(sai) &&
- thread_is_running(sa_thread));
+
+ set_current_state(TASK_IDLE);
+ if (sa_sent_full(sai) &&
+ !sa_has_callback(sai) &&
+ agl_list_empty(sai) &&
+ sai->sai_task)
+ /* wait for spare statahead window */
+ schedule();
+ __set_current_state(TASK_RUNNING);
+ } while (sa_sent_full(sai) && sai->sai_task);
sa_statahead(parent, name, namelen, &fid);
}
@@ -1118,7 +1083,7 @@ static int ll_statahead_thread(void *arg)
if (rc < 0) {
spin_lock(&lli->lli_sa_lock);
- thread_set_flags(sa_thread, SVC_STOPPING);
+ sai->sai_task = NULL;
lli->lli_sa_enabled = 0;
spin_unlock(&lli->lli_sa_lock);
}
@@ -1127,59 +1092,46 @@ static int ll_statahead_thread(void *arg)
* statahead is finished, but statahead entries need to be cached, wait
* for file release to stop me.
*/
- while (thread_is_running(sa_thread)) {
- l_wait_event(sa_thread->t_ctl_waitq,
- sa_has_callback(sai) ||
- !agl_list_empty(sai) ||
- !thread_is_running(sa_thread),
- &lwi);
-
+ while (sai->sai_task) {
sa_handle_callback(sai);
+
+ set_current_state(TASK_IDLE);
+ if (!sa_has_callback(sai) &&
+ sai->sai_task)
+ schedule();
+ __set_current_state(TASK_RUNNING);
}
out:
- if (sai->sai_agl_valid) {
- spin_lock(&lli->lli_agl_lock);
- thread_set_flags(agl_thread, SVC_STOPPING);
- spin_unlock(&lli->lli_agl_lock);
- wake_up(&agl_thread->t_ctl_waitq);
+ if (sai->sai_agl_task) {
+ kthread_stop(sai->sai_agl_task);
CDEBUG(D_READA, "stop agl thread: sai %p pid %u\n",
- sai, (unsigned int)agl_thread->t_pid);
- l_wait_event(agl_thread->t_ctl_waitq,
- thread_is_stopped(agl_thread),
- &lwi);
- } else {
- /* Set agl_thread flags anyway. */
- thread_set_flags(agl_thread, SVC_STOPPED);
+ sai, (unsigned int)sai->sai_agl_task->pid);
+ sai->sai_agl_task = NULL;
}
-
/*
* wait for inflight statahead RPCs to finish, and then we can free sai
* safely because statahead RPC will access sai data
*/
while (sai->sai_sent != sai->sai_replied) {
/* in case we're not woken up, timeout wait */
- lwi = LWI_TIMEOUT(msecs_to_jiffies(MSEC_PER_SEC >> 3),
- NULL, NULL);
- l_wait_event(sa_thread->t_ctl_waitq,
- sai->sai_sent == sai->sai_replied, &lwi);
+ schedule_timeout_idle(HZ>>3);
}
/* release resources held by statahead RPCs */
sa_handle_callback(sai);
- spin_lock(&lli->lli_sa_lock);
- thread_set_flags(sa_thread, SVC_STOPPED);
- spin_unlock(&lli->lli_sa_lock);
-
CDEBUG(D_READA, "statahead thread stopped: sai %p, parent %pd\n",
sai, parent);
+ spin_lock(&lli->lli_sa_lock);
+ sai->sai_task = NULL;
+ spin_unlock(&lli->lli_sa_lock);
+
wake_up(&sai->sai_waitq);
- wake_up(&sa_thread->t_ctl_waitq);
ll_sai_put(sai);
- return rc;
+ do_exit(rc);
}
/* authorize opened dir handle @key to statahead */
@@ -1221,13 +1173,13 @@ void ll_deauthorize_statahead(struct inode *dir, void *key)
lli->lli_opendir_pid = 0;
lli->lli_sa_enabled = 0;
sai = lli->lli_sai;
- if (sai && thread_is_running(&sai->sai_thread)) {
+ if (sai && sai->sai_task) {
/*
* statahead thread may not quit yet because it needs to cache
* entries, now it's time to tell it to quit.
*/
- thread_set_flags(&sai->sai_thread, SVC_STOPPING);
- wake_up(&sai->sai_thread.t_ctl_waitq);
+ wake_up_process(sai->sai_task);
+ sai->sai_task = NULL;
}
spin_unlock(&lli->lli_sa_lock);
}
@@ -1382,7 +1334,6 @@ static int revalidate_statahead_dentry(struct inode *dir,
{
struct ll_inode_info *lli = ll_i2info(dir);
struct sa_entry *entry = NULL;
- struct l_wait_info lwi = { 0 };
struct ll_dentry_data *ldd;
int rc = 0;
@@ -1432,10 +1383,8 @@ static int revalidate_statahead_dentry(struct inode *dir,
spin_lock(&lli->lli_sa_lock);
sai->sai_index_wait = entry->se_index;
spin_unlock(&lli->lli_sa_lock);
- lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(30), NULL,
- LWI_ON_SIGNAL_NOOP, NULL);
- rc = l_wait_event(sai->sai_waitq, sa_ready(entry), &lwi);
- if (rc < 0) {
+ if (0 == wait_event_idle_timeout(sai->sai_waitq,
+ sa_ready(entry), 30 * HZ)) {
/*
* entry may not be ready, so it may be used by inflight
* statahead RPC, don't free it.
@@ -1500,7 +1449,7 @@ out_unplug:
*/
ldd = ll_d2d(*dentryp);
ldd->lld_sa_generation = lli->lli_sa_generation;
- sa_put(sai, entry);
+ sa_put(sai, entry, lli);
return rc;
}
@@ -1520,8 +1469,6 @@ static int start_statahead_thread(struct inode *dir, struct dentry *dentry)
{
struct ll_inode_info *lli = ll_i2info(dir);
struct ll_statahead_info *sai = NULL;
- struct l_wait_info lwi = { 0 };
- struct ptlrpc_thread *thread;
struct task_struct *task;
struct dentry *parent = dentry->d_parent;
int rc;
@@ -1561,19 +1508,21 @@ static int start_statahead_thread(struct inode *dir, struct dentry *dentry)
CDEBUG(D_READA, "start statahead thread: [pid %d] [parent %pd]\n",
current_pid(), parent);
- task = kthread_run(ll_statahead_thread, parent, "ll_sa_%u",
- lli->lli_opendir_pid);
- thread = &sai->sai_thread;
+ task = kthread_create(ll_statahead_thread, parent, "ll_sa_%u",
+ lli->lli_opendir_pid);
if (IS_ERR(task)) {
rc = PTR_ERR(task);
CERROR("can't start ll_sa thread, rc : %d\n", rc);
goto out;
}
- l_wait_event(thread->t_ctl_waitq,
- thread_is_running(thread) || thread_is_stopped(thread),
- &lwi);
- ll_sai_put(sai);
+ if (ll_i2sbi(parent->d_inode)->ll_flags & LL_SBI_AGL_ENABLED)
+ ll_start_agl(parent, sai);
+
+ atomic_inc(&ll_i2sbi(parent->d_inode)->ll_sa_total);
+ sai->sai_task = task;
+
+ wake_up_process(task);
/*
* We don't stat-ahead for the first dirent since we are already in
diff --git a/drivers/staging/lustre/lustre/llite/super25.c b/drivers/staging/lustre/lustre/llite/super25.c
index 9b0bb3541a84..861e7a60f408 100644
--- a/drivers/staging/lustre/lustre/llite/super25.c
+++ b/drivers/staging/lustre/lustre/llite/super25.c
@@ -85,8 +85,7 @@ MODULE_ALIAS_FS("lustre");
static int __init lustre_init(void)
{
- struct lnet_process_id lnet_id;
- int i, rc;
+ int rc;
BUILD_BUG_ON(sizeof(LUSTRE_VOLATILE_HDR) !=
LUSTRE_VOLATILE_HDR_LEN + 1);
@@ -125,20 +124,6 @@ static int __init lustre_init(void)
goto out_debugfs;
}
- /* Nodes with small feet have little entropy. The NID for this
- * node gives the most entropy in the low bits
- */
- for (i = 0;; i++) {
- u32 seed;
-
- if (LNetGetId(i, &lnet_id) == -ENOENT)
- break;
- if (LNET_NETTYP(LNET_NIDNET(lnet_id.nid)) != LOLND) {
- seed = LNET_NIDADDR(lnet_id.nid);
- add_device_randomness(&seed, sizeof(seed));
- }
- }
-
rc = vvp_global_init();
if (rc != 0)
goto out_sysfs;
diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c
index 532384c91447..2d78432963dc 100644
--- a/drivers/staging/lustre/lustre/llite/xattr.c
+++ b/drivers/staging/lustre/lustre/llite/xattr.c
@@ -75,7 +75,7 @@ static int xattr_type_filter(struct ll_sb_info *sbi,
return -EOPNOTSUPP;
if (handler->flags == XATTR_TRUSTED_T &&
- !capable(CFS_CAP_SYS_ADMIN))
+ !capable(CAP_SYS_ADMIN))
return -EPERM;
return 0;
@@ -87,10 +87,10 @@ ll_xattr_set_common(const struct xattr_handler *handler,
const char *name, const void *value, size_t size,
int flags)
{
- char fullname[strlen(handler->prefix) + strlen(name) + 1];
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct ptlrpc_request *req = NULL;
const char *pv = value;
+ char *fullname;
__u64 valid;
int rc;
@@ -141,10 +141,13 @@ ll_xattr_set_common(const struct xattr_handler *handler,
return -EPERM;
}
- sprintf(fullname, "%s%s\n", handler->prefix, name);
+ fullname = kasprintf(GFP_KERNEL, "%s%s\n", handler->prefix, name);
+ if (!fullname)
+ return -ENOMEM;
rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode),
valid, fullname, pv, size, 0, flags,
ll_i2suppgid(inode), &req);
+ kfree(fullname);
if (rc) {
if (rc == -EOPNOTSUPP && handler->flags == XATTR_USER_T) {
LCONSOLE_INFO("Disabling user_xattr feature because it is not supported on the server\n");
@@ -364,11 +367,11 @@ static int ll_xattr_get_common(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode,
const char *name, void *buffer, size_t size)
{
- char fullname[strlen(handler->prefix) + strlen(name) + 1];
struct ll_sb_info *sbi = ll_i2sbi(inode);
#ifdef CONFIG_FS_POSIX_ACL
struct ll_inode_info *lli = ll_i2info(inode);
#endif
+ char *fullname;
int rc;
CDEBUG(D_VFSTRACE, "VFS Op:inode=" DFID "(%p)\n",
@@ -411,9 +414,13 @@ static int ll_xattr_get_common(const struct xattr_handler *handler,
if (handler->flags == XATTR_ACL_DEFAULT_T && !S_ISDIR(inode->i_mode))
return -ENODATA;
#endif
- sprintf(fullname, "%s%s\n", handler->prefix, name);
- return ll_xattr_list(inode, fullname, handler->flags, buffer, size,
- OBD_MD_FLXATTR);
+ fullname = kasprintf(GFP_KERNEL, "%s%s\n", handler->prefix, name);
+ if (!fullname)
+ return -ENOMEM;
+ rc = ll_xattr_list(inode, fullname, handler->flags, buffer, size,
+ OBD_MD_FLXATTR);
+ kfree(fullname);
+ return rc;
}
static ssize_t ll_getxattr_lov(struct inode *inode, void *buf, size_t buf_size)
diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c
index c2c57f65431e..e8a9b9902c37 100644
--- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c
+++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c
@@ -1035,7 +1035,7 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
reqlen = offsetof(typeof(*hur),
hur_user_item[nr])
+ hur->hur_request.hr_data_len;
- req = libcfs_kvzalloc(reqlen, GFP_NOFS);
+ req = kvzalloc(reqlen, GFP_NOFS);
if (!req)
return -ENOMEM;
@@ -2695,7 +2695,7 @@ static int lmv_unpackmd(struct obd_export *exp, struct lmv_stripe_md **lsmp,
if (lsm && !lmm) {
int i;
- for (i = 1; i < lsm->lsm_md_stripe_count; i++) {
+ for (i = 0; i < lsm->lsm_md_stripe_count; i++) {
/*
* For migrating inode, the master stripe and master
* object will be the same, so do not need iput, see
@@ -2733,7 +2733,7 @@ static int lmv_unpackmd(struct obd_export *exp, struct lmv_stripe_md **lsmp,
lsm_size = lmv_stripe_md_size(0);
if (!lsm) {
- lsm = libcfs_kvzalloc(lsm_size, GFP_NOFS);
+ lsm = kvzalloc(lsm_size, GFP_NOFS);
if (!lsm)
return -ENOMEM;
allocated = true;
diff --git a/drivers/staging/lustre/lustre/lov/lov_ea.c b/drivers/staging/lustre/lustre/lov/lov_ea.c
index d563dd73343a..c56a971745e8 100644
--- a/drivers/staging/lustre/lustre/lov/lov_ea.c
+++ b/drivers/staging/lustre/lustre/lov/lov_ea.c
@@ -89,7 +89,7 @@ struct lov_stripe_md *lsm_alloc_plain(u16 stripe_count)
oinfo_ptrs_size = sizeof(struct lov_oinfo *) * stripe_count;
lsm_size = sizeof(*lsm) + oinfo_ptrs_size;
- lsm = libcfs_kvzalloc(lsm_size, GFP_NOFS);
+ lsm = kvzalloc(lsm_size, GFP_NOFS);
if (!lsm)
return NULL;
diff --git a/drivers/staging/lustre/lustre/lov/lov_io.c b/drivers/staging/lustre/lustre/lov/lov_io.c
index c5f5d1b106dc..b823f8a21856 100644
--- a/drivers/staging/lustre/lustre/lov/lov_io.c
+++ b/drivers/staging/lustre/lustre/lov/lov_io.c
@@ -243,7 +243,7 @@ static int lov_io_subio_init(const struct lu_env *env, struct lov_io *lio,
* when writing a page. -jay
*/
lio->lis_subs =
- libcfs_kvzalloc(lsm->lsm_stripe_count *
+ kvzalloc(lsm->lsm_stripe_count *
sizeof(lio->lis_subs[0]),
GFP_NOFS);
if (lio->lis_subs) {
@@ -483,7 +483,7 @@ lov_io_data_version_end(const struct lu_env *env, const struct cl_io_slice *ios)
struct lov_io_sub *sub;
list_for_each_entry(sub, &lio->lis_active, sub_linkage) {
- lov_io_end_wrapper(env, sub->sub_io);
+ lov_io_end_wrapper(sub->sub_env, sub->sub_io);
parent->u.ci_data_version.dv_data_version +=
sub->sub_io->u.ci_data_version.dv_data_version;
diff --git a/drivers/staging/lustre/lustre/lov/lov_lock.c b/drivers/staging/lustre/lustre/lov/lov_lock.c
index 2fcdeb707ff9..b0292100bf26 100644
--- a/drivers/staging/lustre/lustre/lov/lov_lock.c
+++ b/drivers/staging/lustre/lustre/lov/lov_lock.c
@@ -145,7 +145,7 @@ static struct lov_lock *lov_lock_sub_init(const struct lu_env *env,
nr++;
}
LASSERT(nr > 0);
- lovlck = libcfs_kvzalloc(offsetof(struct lov_lock, lls_sub[nr]),
+ lovlck = kvzalloc(offsetof(struct lov_lock, lls_sub[nr]),
GFP_NOFS);
if (!lovlck)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/staging/lustre/lustre/lov/lov_object.c b/drivers/staging/lustre/lustre/lov/lov_object.c
index 897cf2cd4a24..f7c69680cb7d 100644
--- a/drivers/staging/lustre/lustre/lov/lov_object.c
+++ b/drivers/staging/lustre/lustre/lov/lov_object.c
@@ -242,7 +242,7 @@ static int lov_init_raid0(const struct lu_env *env, struct lov_device *dev,
r0->lo_nr = lsm->lsm_stripe_count;
LASSERT(r0->lo_nr <= lov_targets_nr(dev));
- r0->lo_sub = libcfs_kvzalloc(r0->lo_nr * sizeof(r0->lo_sub[0]),
+ r0->lo_sub = kvzalloc(r0->lo_nr * sizeof(r0->lo_sub[0]),
GFP_NOFS);
if (r0->lo_sub) {
int psz = 0;
@@ -723,15 +723,13 @@ static void lov_conf_unlock(struct lov_object *lov)
static int lov_layout_wait(const struct lu_env *env, struct lov_object *lov)
{
- struct l_wait_info lwi = { 0 };
-
while (atomic_read(&lov->lo_active_ios) > 0) {
CDEBUG(D_INODE, "file:" DFID " wait for active IO, now: %d.\n",
PFID(lu_object_fid(lov2lu(lov))),
atomic_read(&lov->lo_active_ios));
- l_wait_event(lov->lo_waitq,
- atomic_read(&lov->lo_active_ios) == 0, &lwi);
+ wait_event_idle(lov->lo_waitq,
+ atomic_read(&lov->lo_active_ios) == 0);
}
return 0;
}
@@ -1175,7 +1173,8 @@ static int fiemap_for_stripe(const struct lu_env *env, struct cl_object *obj,
/* If this is a continuation FIEMAP call and we are on
* starting stripe then lun_start needs to be set to
- * end_offset */
+ * end_offset
+ */
if (fs->fs_end_offset != 0 && stripeno == fs->fs_start_stripe)
lun_start = fs->fs_end_offset;
@@ -1200,7 +1199,8 @@ static int fiemap_for_stripe(const struct lu_env *env, struct cl_object *obj,
if (IS_ERR(subobj))
return PTR_ERR(subobj);
/* If the output buffer is very large and the objects have many
- * extents we may need to loop on a single OST repeatedly */
+ * extents we may need to loop on a single OST repeatedly
+ */
do {
if (fiemap->fm_extent_count > 0) {
/* Don't get too many extents. */
@@ -1250,7 +1250,8 @@ inactive_tgt:
ost_done = true;
fs->fs_device_done = true;
/* If last stripe has hold at the end,
- * we need to return */
+ * we need to return
+ */
if (stripeno == fs->fs_last_stripe) {
fiemap->fm_mapped_extents = 0;
fs->fs_finish = true;
@@ -1284,7 +1285,8 @@ inactive_tgt:
}
/* Clear the EXTENT_LAST flag which can be present on
- * the last extent */
+ * the last extent
+ */
if (fm_ext[ext_count - 1].fe_flags & FIEMAP_EXTENT_LAST)
fm_ext[ext_count - 1].fe_flags &= ~FIEMAP_EXTENT_LAST;
if (lov_stripe_size(lsm, fm_ext[ext_count - 1].fe_logical +
@@ -1377,7 +1379,7 @@ static int lov_object_fiemap(const struct lu_env *env, struct cl_object *obj,
if (fiemap_count_to_size(fiemap->fm_extent_count) < buffer_size)
buffer_size = fiemap_count_to_size(fiemap->fm_extent_count);
- fm_local = libcfs_kvzalloc(buffer_size, GFP_NOFS);
+ fm_local = kvzalloc(buffer_size, GFP_NOFS);
if (!fm_local) {
rc = -ENOMEM;
goto out;
diff --git a/drivers/staging/lustre/lustre/lov/lov_pack.c b/drivers/staging/lustre/lustre/lov/lov_pack.c
index e5b11c4085a9..b1060d02a164 100644
--- a/drivers/staging/lustre/lustre/lov/lov_pack.c
+++ b/drivers/staging/lustre/lustre/lov/lov_pack.c
@@ -333,7 +333,7 @@ int lov_getstripe(struct lov_object *obj, struct lov_stripe_md *lsm,
lmmk_size = lov_mds_md_size(stripe_count, lsm->lsm_magic);
- lmmk = libcfs_kvzalloc(lmmk_size, GFP_NOFS);
+ lmmk = kvzalloc(lmmk_size, GFP_NOFS);
if (!lmmk) {
rc = -ENOMEM;
goto out;
diff --git a/drivers/staging/lustre/lustre/lov/lov_request.c b/drivers/staging/lustre/lustre/lov/lov_request.c
index cfa1d7f92b0f..051450d67524 100644
--- a/drivers/staging/lustre/lustre/lov/lov_request.c
+++ b/drivers/staging/lustre/lustre/lov/lov_request.c
@@ -99,8 +99,7 @@ static int lov_check_set(struct lov_obd *lov, int idx)
*/
static int lov_check_and_wait_active(struct lov_obd *lov, int ost_idx)
{
- wait_queue_head_t waitq;
- struct l_wait_info lwi;
+ int cnt = 0;
struct lov_tgt_desc *tgt;
int rc = 0;
@@ -125,11 +124,10 @@ static int lov_check_and_wait_active(struct lov_obd *lov, int ost_idx)
mutex_unlock(&lov->lov_lock);
- init_waitqueue_head(&waitq);
- lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(obd_timeout),
- cfs_time_seconds(1), NULL, NULL);
-
- rc = l_wait_event(waitq, lov_check_set(lov, ost_idx), &lwi);
+ while (cnt < obd_timeout && !lov_check_set(lov, ost_idx)) {
+ schedule_timeout_uninterruptible(HZ);
+ cnt++;
+ }
if (tgt->ltd_active)
return 1;
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c
index 3114907ac5ff..695ef44532cf 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c
@@ -660,7 +660,7 @@ static int mdc_finish_enqueue(struct obd_export *exp,
LDLM_DEBUG(lock, "layout lock returned by: %s, lvb_len: %d",
ldlm_it2str(it->it_op), lvb_len);
- lmm = libcfs_kvzalloc(lvb_len, GFP_NOFS);
+ lmm = kvzalloc(lvb_len, GFP_NOFS);
if (!lmm) {
LDLM_LOCK_PUT(lock);
return -ENOMEM;
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c
index 03e55bca4ada..3b1c8e5a3053 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_request.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c
@@ -838,7 +838,6 @@ static int mdc_getpage(struct obd_export *exp, const struct lu_fid *fid,
struct ptlrpc_bulk_desc *desc;
struct ptlrpc_request *req;
wait_queue_head_t waitq;
- struct l_wait_info lwi;
int resends = 0;
int rc;
int i;
@@ -888,9 +887,7 @@ restart_bulk:
exp->exp_obd->obd_name, -EIO);
return -EIO;
}
- lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(resends), NULL, NULL,
- NULL);
- l_wait_event(waitq, 0, &lwi);
+ wait_event_idle_timeout(waitq, 0, resends * HZ);
goto restart_bulk;
}
@@ -1058,13 +1055,14 @@ static void mdc_adjust_dirpages(struct page **pages, int cfs_pgs, int lu_pgs)
__u64 hash_end = le64_to_cpu(dp->ldp_hash_end);
__u32 flags = le32_to_cpu(dp->ldp_flags);
struct lu_dirpage *first = dp;
- struct lu_dirent *end_dirent = NULL;
- struct lu_dirent *ent;
while (--lu_pgs > 0) {
- ent = lu_dirent_start(dp);
- for (end_dirent = ent; ent;
- end_dirent = ent, ent = lu_dirent_next(ent));
+ struct lu_dirent *end_dirent = NULL;
+ struct lu_dirent *ent;
+
+ for (ent = lu_dirent_start(dp); ent;
+ ent = lu_dirent_next(ent))
+ end_dirent = ent;
/* Advance dp to next lu_dirpage. */
dp = (struct lu_dirpage *)((char *)dp + LU_PAGE_SIZE);
diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c
index 79ff85feab64..c61cd23a96df 100644
--- a/drivers/staging/lustre/lustre/mgc/mgc_request.c
+++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c
@@ -535,7 +535,6 @@ static int mgc_requeue_thread(void *data)
spin_lock(&config_list_lock);
rq_state |= RQ_RUNNING;
while (!(rq_state & RQ_STOP)) {
- struct l_wait_info lwi;
struct config_llog_data *cld, *cld_prev;
int rand = prandom_u32_max(MGC_TIMEOUT_RAND_CENTISEC);
int to;
@@ -556,9 +555,9 @@ static int mgc_requeue_thread(void *data)
to = msecs_to_jiffies(MGC_TIMEOUT_MIN_SECONDS * MSEC_PER_SEC);
/* rand is centi-seconds */
to += msecs_to_jiffies(rand * MSEC_PER_SEC / 100);
- lwi = LWI_TIMEOUT(to, NULL, NULL);
- l_wait_event(rq_waitq, rq_state & (RQ_STOP | RQ_PRECLEANUP),
- &lwi);
+ wait_event_idle_timeout(rq_waitq,
+ rq_state & (RQ_STOP | RQ_PRECLEANUP),
+ to);
/*
* iterate & processing through the list. for each cld, process
@@ -601,9 +600,7 @@ static int mgc_requeue_thread(void *data)
config_log_put(cld_prev);
/* Wait a bit to see if anyone else needs a requeue */
- lwi = (struct l_wait_info) { 0 };
- l_wait_event(rq_waitq, rq_state & (RQ_NOW | RQ_STOP),
- &lwi);
+ wait_event_idle(rq_waitq, rq_state & (RQ_NOW | RQ_STOP));
spin_lock(&config_list_lock);
}
@@ -1630,9 +1627,7 @@ restart:
if (rcl == -ESHUTDOWN &&
atomic_read(&mgc->u.cli.cl_mgc_refcount) > 0 && !retry) {
- int secs = cfs_time_seconds(obd_timeout);
struct obd_import *imp;
- struct l_wait_info lwi;
mutex_unlock(&cld->cld_lock);
imp = class_exp2cliimp(mgc->u.cli.cl_mgc_mgsexp);
@@ -1647,9 +1642,9 @@ restart:
*/
ptlrpc_pinger_force(imp);
- lwi = LWI_TIMEOUT(secs, NULL, NULL);
- l_wait_event(imp->imp_recovery_waitq,
- !mgc_import_in_recovery(imp), &lwi);
+ wait_event_idle_timeout(imp->imp_recovery_waitq,
+ !mgc_import_in_recovery(imp),
+ obd_timeout * HZ);
if (imp->imp_state == LUSTRE_IMP_FULL) {
retry = true;
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_io.c b/drivers/staging/lustre/lustre/obdclass/cl_io.c
index 6ec5218a18c1..ab84e011b560 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_io.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_io.c
@@ -1097,23 +1097,24 @@ EXPORT_SYMBOL(cl_sync_io_init);
int cl_sync_io_wait(const struct lu_env *env, struct cl_sync_io *anchor,
long timeout)
{
- struct l_wait_info lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(timeout),
- NULL, NULL, NULL);
- int rc;
+ int rc = 1;
LASSERT(timeout >= 0);
- rc = l_wait_event(anchor->csi_waitq,
- atomic_read(&anchor->csi_sync_nr) == 0,
- &lwi);
- if (rc < 0) {
+ if (timeout == 0)
+ wait_event_idle(anchor->csi_waitq,
+ atomic_read(&anchor->csi_sync_nr) == 0);
+ else
+ rc = wait_event_idle_timeout(anchor->csi_waitq,
+ atomic_read(&anchor->csi_sync_nr) == 0,
+ timeout * HZ);
+ if (rc == 0) {
+ rc = -ETIMEDOUT;
CERROR("IO failed: %d, still wait for %d remaining entries\n",
rc, atomic_read(&anchor->csi_sync_nr));
- lwi = (struct l_wait_info) { 0 };
- (void)l_wait_event(anchor->csi_waitq,
- atomic_read(&anchor->csi_sync_nr) == 0,
- &lwi);
+ wait_event_idle(anchor->csi_waitq,
+ atomic_read(&anchor->csi_sync_nr) == 0);
} else {
rc = anchor->csi_sync_rc;
}
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_lock.c b/drivers/staging/lustre/lustre/obdclass/cl_lock.c
index 3b683b774fef..9ca29a26a38b 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_lock.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_lock.c
@@ -224,7 +224,7 @@ EXPORT_SYMBOL(cl_lock_release);
const char *cl_lock_mode_name(const enum cl_lock_mode mode)
{
- static const char *names[] = {
+ static const char * const names[] = {
[CLM_READ] = "R",
[CLM_WRITE] = "W",
[CLM_GROUP] = "G"
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_object.c b/drivers/staging/lustre/lustre/obdclass/cl_object.c
index 7b18d775b001..7809f6ae1809 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_object.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_object.c
@@ -495,7 +495,7 @@ static struct cache_stats cl_env_stats = {
int cl_site_stats_print(const struct cl_site *site, struct seq_file *m)
{
size_t i;
- static const char *pstate[] = {
+ static const char * const pstate[] = {
[CPS_CACHED] = "c",
[CPS_OWNED] = "o",
[CPS_PAGEOUT] = "w",
diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c
index b1d6ba4a3190..63ccbabb4c5a 100644
--- a/drivers/staging/lustre/lustre/obdclass/genops.c
+++ b/drivers/staging/lustre/lustre/obdclass/genops.c
@@ -48,10 +48,7 @@ struct kmem_cache *obdo_cachep;
EXPORT_SYMBOL(obdo_cachep);
static struct kmem_cache *import_cachep;
-static struct list_head obd_zombie_imports;
-static struct list_head obd_zombie_exports;
-static spinlock_t obd_zombie_impexp_lock;
-static void obd_zombie_impexp_notify(void);
+static struct workqueue_struct *zombie_wq;
static void obd_zombie_export_add(struct obd_export *exp);
static void obd_zombie_import_add(struct obd_import *imp);
@@ -701,6 +698,13 @@ void class_export_put(struct obd_export *exp)
}
EXPORT_SYMBOL(class_export_put);
+static void obd_zombie_exp_cull(struct work_struct *ws)
+{
+ struct obd_export *export = container_of(ws, struct obd_export, exp_zombie_work);
+
+ class_export_destroy(export);
+}
+
/* Creates a new export, adds it to the hash table, and returns a
* pointer to it. The refcount is 2: one for the hash reference, and
* one for the pointer returned by this function.
@@ -741,6 +745,7 @@ struct obd_export *class_new_export(struct obd_device *obd,
INIT_HLIST_NODE(&export->exp_uuid_hash);
spin_lock_init(&export->exp_bl_list_lock);
INIT_LIST_HEAD(&export->exp_bl_list);
+ INIT_WORK(&export->exp_zombie_work, obd_zombie_exp_cull);
export->exp_sp_peer = LUSTRE_SP_ANY;
export->exp_flvr.sf_rpc = SPTLRPC_FLVR_INVALID;
@@ -862,7 +867,6 @@ EXPORT_SYMBOL(class_import_get);
void class_import_put(struct obd_import *imp)
{
- LASSERT(list_empty(&imp->imp_zombie_chain));
LASSERT_ATOMIC_GT_LT(&imp->imp_refcount, 0, LI_POISON);
CDEBUG(D_INFO, "import %p refcount=%d obd=%s\n", imp,
@@ -894,6 +898,13 @@ static void init_imp_at(struct imp_at *at)
}
}
+static void obd_zombie_imp_cull(struct work_struct *ws)
+{
+ struct obd_import *import = container_of(ws, struct obd_import, imp_zombie_work);
+
+ class_import_destroy(import);
+}
+
struct obd_import *class_new_import(struct obd_device *obd)
{
struct obd_import *imp;
@@ -903,7 +914,6 @@ struct obd_import *class_new_import(struct obd_device *obd)
return NULL;
INIT_LIST_HEAD(&imp->imp_pinger_chain);
- INIT_LIST_HEAD(&imp->imp_zombie_chain);
INIT_LIST_HEAD(&imp->imp_replay_list);
INIT_LIST_HEAD(&imp->imp_sending_list);
INIT_LIST_HEAD(&imp->imp_delayed_list);
@@ -917,6 +927,7 @@ struct obd_import *class_new_import(struct obd_device *obd)
imp->imp_obd = class_incref(obd, "import", imp);
mutex_init(&imp->imp_sec_mutex);
init_waitqueue_head(&imp->imp_recovery_waitq);
+ INIT_WORK(&imp->imp_zombie_work, obd_zombie_imp_cull);
atomic_set(&imp->imp_refcount, 2);
atomic_set(&imp->imp_unregistering, 0);
@@ -1098,81 +1109,6 @@ EXPORT_SYMBOL(class_fail_export);
void (*class_export_dump_hook)(struct obd_export *) = NULL;
#endif
-/* Total amount of zombies to be destroyed */
-static int zombies_count;
-
-/**
- * kill zombie imports and exports
- */
-static void obd_zombie_impexp_cull(void)
-{
- struct obd_import *import;
- struct obd_export *export;
-
- do {
- spin_lock(&obd_zombie_impexp_lock);
-
- import = NULL;
- if (!list_empty(&obd_zombie_imports)) {
- import = list_entry(obd_zombie_imports.next,
- struct obd_import,
- imp_zombie_chain);
- list_del_init(&import->imp_zombie_chain);
- }
-
- export = NULL;
- if (!list_empty(&obd_zombie_exports)) {
- export = list_entry(obd_zombie_exports.next,
- struct obd_export,
- exp_obd_chain);
- list_del_init(&export->exp_obd_chain);
- }
-
- spin_unlock(&obd_zombie_impexp_lock);
-
- if (import) {
- class_import_destroy(import);
- spin_lock(&obd_zombie_impexp_lock);
- zombies_count--;
- spin_unlock(&obd_zombie_impexp_lock);
- }
-
- if (export) {
- class_export_destroy(export);
- spin_lock(&obd_zombie_impexp_lock);
- zombies_count--;
- spin_unlock(&obd_zombie_impexp_lock);
- }
-
- cond_resched();
- } while (import || export);
-}
-
-static struct completion obd_zombie_start;
-static struct completion obd_zombie_stop;
-static unsigned long obd_zombie_flags;
-static wait_queue_head_t obd_zombie_waitq;
-static pid_t obd_zombie_pid;
-
-enum {
- OBD_ZOMBIE_STOP = 0x0001,
-};
-
-/**
- * check for work for kill zombie import/export thread.
- */
-static int obd_zombie_impexp_check(void *arg)
-{
- int rc;
-
- spin_lock(&obd_zombie_impexp_lock);
- rc = (zombies_count == 0) &&
- !test_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags);
- spin_unlock(&obd_zombie_impexp_lock);
-
- return rc;
-}
-
/**
* Add export to the obd_zombie thread and notify it.
*/
@@ -1182,12 +1118,7 @@ static void obd_zombie_export_add(struct obd_export *exp)
LASSERT(!list_empty(&exp->exp_obd_chain));
list_del_init(&exp->exp_obd_chain);
spin_unlock(&exp->exp_obd->obd_dev_lock);
- spin_lock(&obd_zombie_impexp_lock);
- zombies_count++;
- list_add(&exp->exp_obd_chain, &obd_zombie_exports);
- spin_unlock(&obd_zombie_impexp_lock);
-
- obd_zombie_impexp_notify();
+ queue_work(zombie_wq, &exp->exp_zombie_work);
}
/**
@@ -1196,40 +1127,7 @@ static void obd_zombie_export_add(struct obd_export *exp)
static void obd_zombie_import_add(struct obd_import *imp)
{
LASSERT(!imp->imp_sec);
- spin_lock(&obd_zombie_impexp_lock);
- LASSERT(list_empty(&imp->imp_zombie_chain));
- zombies_count++;
- list_add(&imp->imp_zombie_chain, &obd_zombie_imports);
- spin_unlock(&obd_zombie_impexp_lock);
-
- obd_zombie_impexp_notify();
-}
-
-/**
- * notify import/export destroy thread about new zombie.
- */
-static void obd_zombie_impexp_notify(void)
-{
- /*
- * Make sure obd_zombie_impexp_thread get this notification.
- * It is possible this signal only get by obd_zombie_barrier, and
- * barrier gulps this notification and sleeps away and hangs ensues
- */
- wake_up_all(&obd_zombie_waitq);
-}
-
-/**
- * check whether obd_zombie is idle
- */
-static int obd_zombie_is_idle(void)
-{
- int rc;
-
- LASSERT(!test_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags));
- spin_lock(&obd_zombie_impexp_lock);
- rc = (zombies_count == 0);
- spin_unlock(&obd_zombie_impexp_lock);
- return rc;
+ queue_work(zombie_wq, &imp->imp_zombie_work);
}
/**
@@ -1237,64 +1135,19 @@ static int obd_zombie_is_idle(void)
*/
void obd_zombie_barrier(void)
{
- struct l_wait_info lwi = { 0 };
-
- if (obd_zombie_pid == current_pid())
- /* don't wait for myself */
- return;
- l_wait_event(obd_zombie_waitq, obd_zombie_is_idle(), &lwi);
+ flush_workqueue(zombie_wq);
}
EXPORT_SYMBOL(obd_zombie_barrier);
/**
- * destroy zombie export/import thread.
- */
-static int obd_zombie_impexp_thread(void *unused)
-{
- unshare_fs_struct();
- complete(&obd_zombie_start);
-
- obd_zombie_pid = current_pid();
-
- while (!test_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags)) {
- struct l_wait_info lwi = { 0 };
-
- l_wait_event(obd_zombie_waitq,
- !obd_zombie_impexp_check(NULL), &lwi);
- obd_zombie_impexp_cull();
-
- /*
- * Notify obd_zombie_barrier callers that queues
- * may be empty.
- */
- wake_up(&obd_zombie_waitq);
- }
-
- complete(&obd_zombie_stop);
-
- return 0;
-}
-
-/**
* start destroy zombie import/export thread
*/
int obd_zombie_impexp_init(void)
{
- struct task_struct *task;
-
- INIT_LIST_HEAD(&obd_zombie_imports);
- INIT_LIST_HEAD(&obd_zombie_exports);
- spin_lock_init(&obd_zombie_impexp_lock);
- init_completion(&obd_zombie_start);
- init_completion(&obd_zombie_stop);
- init_waitqueue_head(&obd_zombie_waitq);
- obd_zombie_pid = 0;
-
- task = kthread_run(obd_zombie_impexp_thread, NULL, "obd_zombid");
- if (IS_ERR(task))
- return PTR_ERR(task);
+ zombie_wq = alloc_workqueue("obd_zombid", 0, 0);
+ if (!zombie_wq)
+ return -ENOMEM;
- wait_for_completion(&obd_zombie_start);
return 0;
}
@@ -1303,9 +1156,7 @@ int obd_zombie_impexp_init(void)
*/
void obd_zombie_impexp_stop(void)
{
- set_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags);
- obd_zombie_impexp_notify();
- wait_for_completion(&obd_zombie_stop);
+ destroy_workqueue(zombie_wq);
}
struct obd_request_slot_waiter {
@@ -1336,7 +1187,6 @@ static bool obd_request_slot_avail(struct client_obd *cli,
int obd_get_request_slot(struct client_obd *cli)
{
struct obd_request_slot_waiter orsw;
- struct l_wait_info lwi;
int rc;
spin_lock(&cli->cl_loi_list_lock);
@@ -1351,11 +1201,9 @@ int obd_get_request_slot(struct client_obd *cli)
orsw.orsw_signaled = false;
spin_unlock(&cli->cl_loi_list_lock);
- lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
- rc = l_wait_event(orsw.orsw_waitq,
- obd_request_slot_avail(cli, &orsw) ||
- orsw.orsw_signaled,
- &lwi);
+ rc = l_wait_event_abortable(orsw.orsw_waitq,
+ obd_request_slot_avail(cli, &orsw) ||
+ orsw.orsw_signaled);
/*
* Here, we must take the lock to avoid the on-stack 'orsw' to be
@@ -1593,7 +1441,6 @@ static inline bool obd_mod_rpc_slot_avail(struct client_obd *cli,
u16 obd_get_mod_rpc_slot(struct client_obd *cli, __u32 opc,
struct lookup_intent *it)
{
- struct l_wait_info lwi = LWI_INTR(NULL, NULL);
bool close_req = false;
u16 i, max;
@@ -1631,8 +1478,8 @@ u16 obd_get_mod_rpc_slot(struct client_obd *cli, __u32 opc,
CDEBUG(D_RPCTRACE, "%s: sleeping for a modify RPC slot opc %u, max %hu\n",
cli->cl_import->imp_obd->obd_name, opc, max);
- l_wait_event(cli->cl_mod_rpcs_waitq,
- obd_mod_rpc_slot_avail(cli, close_req), &lwi);
+ wait_event_idle(cli->cl_mod_rpcs_waitq,
+ obd_mod_rpc_slot_avail(cli, close_req));
} while (true);
}
EXPORT_SYMBOL(obd_get_mod_rpc_slot);
diff --git a/drivers/staging/lustre/lustre/obdclass/linkea.c b/drivers/staging/lustre/lustre/obdclass/linkea.c
index fe1638b0916e..74c99ee216bb 100644
--- a/drivers/staging/lustre/lustre/obdclass/linkea.c
+++ b/drivers/staging/lustre/lustre/obdclass/linkea.c
@@ -33,9 +33,11 @@
int linkea_data_new(struct linkea_data *ldata, struct lu_buf *buf)
{
- ldata->ld_buf = lu_buf_check_and_alloc(buf, PAGE_SIZE);
- if (!ldata->ld_buf->lb_buf)
+ buf->lb_buf = kzalloc(PAGE_SIZE, GFP_NOFS);
+ if (!buf->lb_buf)
return -ENOMEM;
+ buf->lb_len = PAGE_SIZE;
+ ldata->ld_buf = buf;
ldata->ld_leh = ldata->ld_buf->lb_buf;
ldata->ld_leh->leh_magic = LINK_EA_MAGIC;
ldata->ld_leh->leh_len = sizeof(struct link_ea_header);
@@ -158,11 +160,15 @@ int linkea_add_buf(struct linkea_data *ldata, const struct lu_name *lname,
}
if (leh->leh_len + reclen > ldata->ld_buf->lb_len) {
- if (lu_buf_check_and_grow(ldata->ld_buf,
- leh->leh_len + reclen) < 0)
+ /* Note: this never happens as MAX_LINKEA_SIZE is 4096, while
+ * the initial allocation is PAGE_SIZE.
+ */
+ void *b = krealloc(ldata->ld_buf->lb_buf, leh->leh_len + reclen, GFP_NOFS);
+ if (!b)
return -ENOMEM;
- leh = ldata->ld_leh = ldata->ld_buf->lb_buf;
+ ldata->ld_buf->lb_len = leh->leh_len + reclen;
+ leh = ldata->ld_leh = ldata->ld_buf->lb_buf = b;
}
ldata->ld_lee = ldata->ld_buf->lb_buf + leh->leh_len;
diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
index 57951237def2..7bceee7f121e 100644
--- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
+++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
@@ -180,7 +180,7 @@ int obd_ioctl_getdata(char **buf, int *len, void __user *arg)
* obdfilter-survey is an example, which relies on ioctl. So we'd
* better avoid vmalloc on ioctl path. LU-66
*/
- *buf = libcfs_kvzalloc(hdr.ioc_len, GFP_NOFS);
+ *buf = kvzalloc(hdr.ioc_len, GFP_KERNEL);
if (!*buf) {
CERROR("Cannot allocate control buffer of len %d\n",
hdr.ioc_len);
@@ -251,7 +251,7 @@ static long obd_class_ioctl(struct file *filp, unsigned int cmd,
int err = 0;
/* Allow non-root access for OBD_IOC_PING_TARGET - used by lfs check */
- if (!capable(CFS_CAP_SYS_ADMIN) && (cmd != OBD_IOC_PING_TARGET))
+ if (!capable(CAP_SYS_ADMIN) && (cmd != OBD_IOC_PING_TARGET))
return err = -EACCES;
if ((cmd & 0xffffff00) == ((int)'T') << 8) /* ignore all tty ioctls */
return err = -ENOTTY;
diff --git a/drivers/staging/lustre/lustre/obdclass/llog.c b/drivers/staging/lustre/lustre/obdclass/llog.c
index cd051e31233e..693e1129f1f9 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog.c
@@ -155,7 +155,7 @@ int llog_init_handle(const struct lu_env *env, struct llog_handle *handle,
LASSERT(!handle->lgh_hdr);
LASSERT(chunk_size >= LLOG_MIN_CHUNK_SIZE);
- llh = libcfs_kvzalloc(sizeof(*llh), GFP_NOFS);
+ llh = kvzalloc(sizeof(*llh), GFP_KERNEL);
if (!llh)
return -ENOMEM;
handle->lgh_hdr = llh;
@@ -240,7 +240,7 @@ static int llog_process_thread(void *arg)
/* expect chunk_size to be power of two */
LASSERT(is_power_of_2(chunk_size));
- buf = libcfs_kvzalloc(chunk_size, GFP_NOFS);
+ buf = kvzalloc(chunk_size, GFP_NOFS);
if (!buf) {
lpi->lpi_rc = -ENOMEM;
return 0;
@@ -466,7 +466,7 @@ int llog_open(const struct lu_env *env, struct llog_ctxt *ctxt,
struct llog_handle **lgh, struct llog_logid *logid,
char *name, enum llog_open_param open_param)
{
- int raised;
+ const struct cred *old_cred = NULL;
int rc;
LASSERT(ctxt);
@@ -483,12 +483,18 @@ int llog_open(const struct lu_env *env, struct llog_ctxt *ctxt,
(*lgh)->lgh_ctxt = ctxt;
(*lgh)->lgh_logops = ctxt->loc_logops;
- raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE);
- if (!raised)
- cfs_cap_raise(CFS_CAP_SYS_RESOURCE);
+ if (cap_raised(current_cap(), CAP_SYS_RESOURCE)) {
+ struct cred *cred = prepare_creds();
+
+ if (cred) {
+ cap_raise(cred->cap_effective, CAP_SYS_RESOURCE);
+ old_cred = override_creds(cred);
+ }
+ }
rc = ctxt->loc_logops->lop_open(env, *lgh, logid, name, open_param);
- if (!raised)
- cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
+ if (old_cred)
+ revert_creds(old_cred);
+
if (rc) {
llog_free_handle(*lgh);
*lgh = NULL;
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_obd.c b/drivers/staging/lustre/lustre/obdclass/llog_obd.c
index 28bbaa2136ac..26aea114a29b 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_obd.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_obd.c
@@ -104,7 +104,6 @@ EXPORT_SYMBOL(__llog_ctxt_put);
int llog_cleanup(const struct lu_env *env, struct llog_ctxt *ctxt)
{
- struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
struct obd_llog_group *olg;
int rc, idx;
@@ -129,8 +128,8 @@ int llog_cleanup(const struct lu_env *env, struct llog_ctxt *ctxt)
CERROR("Error %d while cleaning up ctxt %p\n",
rc, ctxt);
- l_wait_event(olg->olg_waitq,
- llog_group_ctxt_null(olg, idx), &lwi);
+ l_wait_event_abortable(olg->olg_waitq,
+ llog_group_ctxt_null(olg, idx));
return rc;
}
diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
index e1f4ef2bddd4..2ed350527398 100644
--- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
+++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
@@ -1467,7 +1467,7 @@ int lprocfs_write_frac_u64_helper(const char __user *buffer,
{
char kernbuf[22], *end, *pbuf;
__u64 whole, frac = 0, units;
- unsigned frac_d = 1;
+ unsigned int frac_d = 1;
int sign = 1;
if (count > (sizeof(kernbuf) - 1))
@@ -1585,7 +1585,7 @@ int ldebugfs_seq_create(struct dentry *parent, const char *name,
struct dentry *entry;
/* Disallow secretly (un)writable entries. */
- LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0));
+ LASSERT((!seq_fops->write) == ((mode & 0222) == 0));
entry = debugfs_create_file(name, mode, parent, data, seq_fops);
if (IS_ERR_OR_NULL(entry))
diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c
index 2719abbff85f..3ae16e8501c2 100644
--- a/drivers/staging/lustre/lustre/obdclass/lu_object.c
+++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c
@@ -1380,12 +1380,8 @@ static void key_fini(struct lu_context *ctx, int index)
lu_ref_del(&key->lct_reference, "ctx", ctx);
atomic_dec(&key->lct_used);
- if ((ctx->lc_tags & LCT_NOREF) == 0) {
-#ifdef CONFIG_MODULE_UNLOAD
- LINVRNT(module_refcount(key->lct_owner) > 0);
-#endif
+ if ((ctx->lc_tags & LCT_NOREF) == 0)
module_put(key->lct_owner);
- }
ctx->lc_value[index] = NULL;
}
}
@@ -1411,7 +1407,7 @@ void lu_context_key_degister(struct lu_context_key *key)
while (atomic_read(&key->lct_used) > 1) {
spin_unlock(&lu_keys_guard);
CDEBUG(D_INFO, "%s: \"%s\" %p, %d\n",
- __func__, key->lct_owner ? key->lct_owner->name : "",
+ __func__, module_name(key->lct_owner),
key, atomic_read(&key->lct_used));
schedule();
spin_lock(&lu_keys_guard);
@@ -1551,7 +1547,7 @@ void lu_context_key_quiesce(struct lu_context_key *key)
spin_unlock(&lu_keys_guard);
CDEBUG(D_INFO, "%s: \"%s\" %p, %d (%d)\n",
__func__,
- key->lct_owner ? key->lct_owner->name : "",
+ module_name(key->lct_owner),
key, atomic_read(&key->lct_used),
atomic_read(&lu_key_initing_cnt));
schedule();
@@ -1619,7 +1615,6 @@ static int keys_fill(struct lu_context *ctx)
LINVRNT(key->lct_init);
LINVRNT(key->lct_index == i);
- LASSERT(key->lct_owner);
if (!(ctx->lc_tags & LCT_NOREF) &&
!try_module_get(key->lct_owner)) {
/* module is unloading, skip this key */
@@ -1797,10 +1792,10 @@ int lu_env_refill(struct lu_env *env)
EXPORT_SYMBOL(lu_env_refill);
struct lu_site_stats {
- unsigned lss_populated;
- unsigned lss_max_search;
- unsigned lss_total;
- unsigned lss_busy;
+ unsigned int lss_populated;
+ unsigned int lss_max_search;
+ unsigned int lss_total;
+ unsigned int lss_busy;
};
static void lu_site_stats_get(struct cfs_hash *hs,
@@ -2061,73 +2056,3 @@ void lu_kmem_fini(struct lu_kmem_descr *caches)
}
}
EXPORT_SYMBOL(lu_kmem_fini);
-
-void lu_buf_free(struct lu_buf *buf)
-{
- LASSERT(buf);
- if (buf->lb_buf) {
- LASSERT(buf->lb_len > 0);
- kvfree(buf->lb_buf);
- buf->lb_buf = NULL;
- buf->lb_len = 0;
- }
-}
-EXPORT_SYMBOL(lu_buf_free);
-
-void lu_buf_alloc(struct lu_buf *buf, size_t size)
-{
- LASSERT(buf);
- LASSERT(!buf->lb_buf);
- LASSERT(!buf->lb_len);
- buf->lb_buf = libcfs_kvzalloc(size, GFP_NOFS);
- if (likely(buf->lb_buf))
- buf->lb_len = size;
-}
-EXPORT_SYMBOL(lu_buf_alloc);
-
-void lu_buf_realloc(struct lu_buf *buf, size_t size)
-{
- lu_buf_free(buf);
- lu_buf_alloc(buf, size);
-}
-EXPORT_SYMBOL(lu_buf_realloc);
-
-struct lu_buf *lu_buf_check_and_alloc(struct lu_buf *buf, size_t len)
-{
- if (!buf->lb_buf && !buf->lb_len)
- lu_buf_alloc(buf, len);
-
- if ((len > buf->lb_len) && buf->lb_buf)
- lu_buf_realloc(buf, len);
-
- return buf;
-}
-EXPORT_SYMBOL(lu_buf_check_and_alloc);
-
-/**
- * Increase the size of the \a buf.
- * preserves old data in buffer
- * old buffer remains unchanged on error
- * \retval 0 or -ENOMEM
- */
-int lu_buf_check_and_grow(struct lu_buf *buf, size_t len)
-{
- char *ptr;
-
- if (len <= buf->lb_len)
- return 0;
-
- ptr = libcfs_kvzalloc(len, GFP_NOFS);
- if (!ptr)
- return -ENOMEM;
-
- /* Free the old buf */
- if (buf->lb_buf) {
- memcpy(ptr, buf->lb_buf, buf->lb_len);
- kvfree(buf->lb_buf);
- }
-
- buf->lb_buf = ptr;
- buf->lb_len = len;
- return 0;
-}
diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c
index 2d6da2431a09..f53b1a3c342e 100644
--- a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c
+++ b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c
@@ -184,8 +184,8 @@ int class_handle_init(void)
LASSERT(!handle_hash);
- handle_hash = libcfs_kvzalloc(sizeof(*bucket) * HANDLE_HASH_SIZE,
- GFP_NOFS);
+ handle_hash = kvzalloc(sizeof(*bucket) * HANDLE_HASH_SIZE,
+ GFP_KERNEL);
if (!handle_hash)
return -ENOMEM;
diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c
index 997c0f9aafb5..277576b586db 100644
--- a/drivers/staging/lustre/lustre/obdclass/obd_config.c
+++ b/drivers/staging/lustre/lustre/obdclass/obd_config.c
@@ -455,7 +455,7 @@ static int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg)
spin_unlock(&obd->obd_dev_lock);
while (obd->obd_conn_inprogress > 0)
- yield();
+ cond_resched();
smp_rmb();
if (lcfg->lcfg_bufcount >= 2 && LUSTRE_CFG_BUFLEN(lcfg, 1) > 0) {
diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
index acc1ea773c9c..f5e8214ac37b 100644
--- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c
+++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
@@ -243,7 +243,7 @@ int lustre_start_mgc(struct super_block *sb)
libcfs_nid2str_r(nid, nidstr, sizeof(nidstr));
mgcname = kasprintf(GFP_NOFS,
"%s%s", LUSTRE_MGC_OBDNAME, nidstr);
- niduuid = kasprintf(GFP_NOFS, "%s_%x", mgcname, i);
+ niduuid = kasprintf(GFP_NOFS, "%s_%x", mgcname, 0);
if (!mgcname || !niduuid) {
rc = -ENOMEM;
goto out_free;
diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c
index b9c1dc7e61b0..99a76db51ae0 100644
--- a/drivers/staging/lustre/lustre/obdecho/echo_client.c
+++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c
@@ -752,7 +752,7 @@ static struct lu_device *echo_device_free(const struct lu_env *env,
spin_unlock(&ec->ec_lock);
CERROR("echo_client still has objects at cleanup time, wait for 1 second\n");
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(1));
+ schedule_timeout(HZ);
lu_site_purge(env, ed->ed_site, -1);
spin_lock(&ec->ec_lock);
}
@@ -1502,7 +1502,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
switch (cmd) {
case OBD_IOC_CREATE: /* may create echo object */
- if (!capable(CFS_CAP_SYS_ADMIN)) {
+ if (!capable(CAP_SYS_ADMIN)) {
rc = -EPERM;
goto out;
}
@@ -1511,7 +1511,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
goto out;
case OBD_IOC_DESTROY:
- if (!capable(CFS_CAP_SYS_ADMIN)) {
+ if (!capable(CAP_SYS_ADMIN)) {
rc = -EPERM;
goto out;
}
@@ -1534,7 +1534,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
goto out;
case OBD_IOC_SETATTR:
- if (!capable(CFS_CAP_SYS_ADMIN)) {
+ if (!capable(CAP_SYS_ADMIN)) {
rc = -EPERM;
goto out;
}
@@ -1547,7 +1547,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
goto out;
case OBD_IOC_BRW_WRITE:
- if (!capable(CFS_CAP_SYS_ADMIN)) {
+ if (!capable(CAP_SYS_ADMIN)) {
rc = -EPERM;
goto out;
}
diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c
index 5767ac2a7d16..459503727ce3 100644
--- a/drivers/staging/lustre/lustre/osc/osc_cache.c
+++ b/drivers/staging/lustre/lustre/osc/osc_cache.c
@@ -934,8 +934,6 @@ static int osc_extent_wait(const struct lu_env *env, struct osc_extent *ext,
enum osc_extent_state state)
{
struct osc_object *obj = ext->oe_obj;
- struct l_wait_info lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(600), NULL,
- LWI_ON_SIGNAL_NOOP, NULL);
int rc = 0;
osc_object_lock(obj);
@@ -958,18 +956,19 @@ static int osc_extent_wait(const struct lu_env *env, struct osc_extent *ext,
osc_extent_release(env, ext);
/* wait for the extent until its state becomes @state */
- rc = l_wait_event(ext->oe_waitq, extent_wait_cb(ext, state), &lwi);
- if (rc == -ETIMEDOUT) {
+ rc = wait_event_idle_timeout(ext->oe_waitq,
+ extent_wait_cb(ext, state), 600 * HZ);
+ if (rc == 0) {
OSC_EXTENT_DUMP(D_ERROR, ext,
"%s: wait ext to %u timedout, recovery in progress?\n",
cli_name(osc_cli(obj)), state);
- lwi = LWI_INTR(NULL, NULL);
- rc = l_wait_event(ext->oe_waitq, extent_wait_cb(ext, state),
- &lwi);
+ wait_event_idle(ext->oe_waitq, extent_wait_cb(ext, state));
}
- if (rc == 0 && ext->oe_rc < 0)
+ if (ext->oe_rc < 0)
rc = ext->oe_rc;
+ else
+ rc = 0;
return rc;
}
@@ -1530,7 +1529,7 @@ static int osc_enter_cache_try(struct client_obd *cli,
if (rc < 0)
return 0;
- if (cli->cl_dirty_pages <= cli->cl_dirty_max_pages &&
+ if (cli->cl_dirty_pages < cli->cl_dirty_max_pages &&
atomic_long_read(&obd_dirty_pages) + 1 <= obd_max_dirty_pages) {
osc_consume_write_grant(cli, &oap->oap_brw_page);
if (transient) {
@@ -1569,12 +1568,9 @@ static int osc_enter_cache(const struct lu_env *env, struct client_obd *cli,
struct osc_object *osc = oap->oap_obj;
struct lov_oinfo *loi = osc->oo_oinfo;
struct osc_cache_waiter ocw;
- struct l_wait_info lwi;
+ unsigned long timeout = (AT_OFF ? obd_timeout : at_max) * HZ;
int rc = -EDQUOT;
- lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(AT_OFF ? obd_timeout : at_max),
- NULL, LWI_ON_SIGNAL_NOOP, NULL);
-
OSC_DUMP_GRANT(D_CACHE, cli, "need:%d\n", bytes);
spin_lock(&cli->cl_loi_list_lock);
@@ -1617,13 +1613,15 @@ static int osc_enter_cache(const struct lu_env *env, struct client_obd *cli,
CDEBUG(D_CACHE, "%s: sleeping for cache space @ %p for %p\n",
cli_name(cli), &ocw, oap);
- rc = l_wait_event(ocw.ocw_waitq, ocw_granted(cli, &ocw), &lwi);
+ rc = wait_event_idle_timeout(ocw.ocw_waitq,
+ ocw_granted(cli, &ocw), timeout);
spin_lock(&cli->cl_loi_list_lock);
- if (rc < 0) {
- /* l_wait_event is interrupted by signal, or timed out */
+ if (rc == 0) {
+ /* wait_event is interrupted by signal, or timed out */
list_del_init(&ocw.ocw_entry);
+ rc = -ETIMEDOUT;
break;
}
LASSERT(list_empty(&ocw.ocw_entry));
@@ -2347,7 +2345,7 @@ int osc_prep_async_page(struct osc_object *osc, struct osc_page *ops,
oap->oap_obj_off = offset;
LASSERT(!(offset & ~PAGE_MASK));
- if (capable(CFS_CAP_SYS_RESOURCE))
+ if (capable(CAP_SYS_RESOURCE))
oap->oap_brw_flags = OBD_BRW_NOQUOTA;
INIT_LIST_HEAD(&oap->oap_pending_item);
@@ -2386,7 +2384,7 @@ int osc_queue_async_io(const struct lu_env *env, struct cl_io *io,
/* Set the OBD_BRW_SRVLOCK before the page is queued. */
brw_flags |= ops->ops_srvlock ? OBD_BRW_SRVLOCK : 0;
- if (capable(CFS_CAP_SYS_RESOURCE)) {
+ if (capable(CAP_SYS_RESOURCE)) {
brw_flags |= OBD_BRW_NOQUOTA;
cmd |= OBD_BRW_NOQUOTA;
}
diff --git a/drivers/staging/lustre/lustre/osc/osc_object.c b/drivers/staging/lustre/lustre/osc/osc_object.c
index f82c87a77550..6baa8e2e00c9 100644
--- a/drivers/staging/lustre/lustre/osc/osc_object.c
+++ b/drivers/staging/lustre/lustre/osc/osc_object.c
@@ -328,7 +328,7 @@ int osc_object_is_contended(struct osc_object *obj)
* ll_file_is_contended.
*/
retry_time = cfs_time_add(obj->oo_contention_time,
- cfs_time_seconds(osc_contention_time));
+ osc_contention_time * HZ);
if (cfs_time_after(cur_time, retry_time)) {
osc_object_clear_contended(obj);
return 0;
@@ -454,12 +454,10 @@ struct lu_object *osc_object_alloc(const struct lu_env *env,
int osc_object_invalidate(const struct lu_env *env, struct osc_object *osc)
{
- struct l_wait_info lwi = { 0 };
-
CDEBUG(D_INODE, "Invalidate osc object: %p, # of active IOs: %d\n",
osc, atomic_read(&osc->oo_nr_ios));
- l_wait_event(osc->oo_io_waitq, !atomic_read(&osc->oo_nr_ios), &lwi);
+ wait_event_idle(osc->oo_io_waitq, !atomic_read(&osc->oo_nr_ios));
/* Discard all dirty pages of this object. */
osc_cache_truncate_start(env, osc, 0, NULL);
diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c
index 20094b6309f9..01a930dbbf64 100644
--- a/drivers/staging/lustre/lustre/osc/osc_page.c
+++ b/drivers/staging/lustre/lustre/osc/osc_page.c
@@ -307,7 +307,7 @@ void osc_page_submit(const struct lu_env *env, struct osc_page *opg,
oap->oap_count = opg->ops_to - opg->ops_from;
oap->oap_brw_flags = brw_flags | OBD_BRW_SYNC;
- if (capable(CFS_CAP_SYS_RESOURCE)) {
+ if (capable(CAP_SYS_RESOURCE)) {
oap->oap_brw_flags |= OBD_BRW_NOQUOTA;
oap->oap_cmd |= OBD_BRW_NOQUOTA;
}
@@ -759,7 +759,6 @@ out:
static int osc_lru_alloc(const struct lu_env *env, struct client_obd *cli,
struct osc_page *opg)
{
- struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
struct osc_io *oio = osc_env_io(env);
int rc = 0;
@@ -782,9 +781,8 @@ static int osc_lru_alloc(const struct lu_env *env, struct client_obd *cli,
cond_resched();
- rc = l_wait_event(osc_lru_waitq,
- atomic_long_read(cli->cl_lru_left) > 0,
- &lwi);
+ rc = l_wait_event_abortable(osc_lru_waitq,
+ atomic_long_read(cli->cl_lru_left) > 0);
if (rc < 0)
break;
diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c
index 45b1ebf33363..1c2bbbf5d864 100644
--- a/drivers/staging/lustre/lustre/osc/osc_request.c
+++ b/drivers/staging/lustre/lustre/osc/osc_request.c
@@ -552,14 +552,12 @@ static int osc_destroy(const struct lu_env *env, struct obd_export *exp,
req->rq_interpret_reply = osc_destroy_interpret;
if (!osc_can_send_destroy(cli)) {
- struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
-
/*
* Wait until the number of on-going destroy RPCs drops
* under max_rpc_in_flight
*/
- l_wait_event_exclusive(cli->cl_destroy_waitq,
- osc_can_send_destroy(cli), &lwi);
+ l_wait_event_abortable_exclusive(cli->cl_destroy_waitq,
+ osc_can_send_destroy(cli));
}
/* Do not wait for response */
@@ -933,7 +931,7 @@ static u32 osc_checksum_bulk(int nob, u32 pg_count,
{
__u32 cksum;
int i = 0;
- struct cfs_crypto_hash_desc *hdesc;
+ struct ahash_request *hdesc;
unsigned int bufsize;
unsigned char cfs_alg = cksum_obd2cfs(cksum_type);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c
index bac4b2304bad..ca096fadb9c0 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/client.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/client.c
@@ -504,19 +504,16 @@ void ptlrpc_request_cache_free(struct ptlrpc_request *req)
*/
void ptlrpc_free_rq_pool(struct ptlrpc_request_pool *pool)
{
- struct list_head *l, *tmp;
struct ptlrpc_request *req;
- spin_lock(&pool->prp_lock);
- list_for_each_safe(l, tmp, &pool->prp_req_list) {
- req = list_entry(l, struct ptlrpc_request, rq_list);
+ while ((req = list_first_entry_or_null(&pool->prp_req_list,
+ struct ptlrpc_request, rq_list))) {
list_del(&req->rq_list);
LASSERT(req->rq_reqbuf);
LASSERT(req->rq_reqbuf_len == pool->prp_rq_size);
kvfree(req->rq_reqbuf);
ptlrpc_request_cache_free(req);
}
- spin_unlock(&pool->prp_lock);
kfree(pool);
}
EXPORT_SYMBOL(ptlrpc_free_rq_pool);
@@ -544,10 +541,10 @@ int ptlrpc_add_rqs_to_pool(struct ptlrpc_request_pool *pool, int num_rq)
struct lustre_msg *msg;
spin_unlock(&pool->prp_lock);
- req = ptlrpc_request_cache_alloc(GFP_NOFS);
+ req = ptlrpc_request_cache_alloc(GFP_KERNEL);
if (!req)
return i;
- msg = libcfs_kvzalloc(size, GFP_NOFS);
+ msg = kvzalloc(size, GFP_KERNEL);
if (!msg) {
ptlrpc_request_cache_free(req);
return i;
@@ -656,16 +653,13 @@ static void __ptlrpc_free_req_to_pool(struct ptlrpc_request *request)
void ptlrpc_add_unreplied(struct ptlrpc_request *req)
{
struct obd_import *imp = req->rq_import;
- struct list_head *tmp;
struct ptlrpc_request *iter;
assert_spin_locked(&imp->imp_lock);
LASSERT(list_empty(&req->rq_unreplied_list));
/* unreplied list is sorted by xid in ascending order */
- list_for_each_prev(tmp, &imp->imp_unreplied_list) {
- iter = list_entry(tmp, struct ptlrpc_request,
- rq_unreplied_list);
+ list_for_each_entry_reverse(iter, &imp->imp_unreplied_list, rq_unreplied_list) {
LASSERT(req->rq_xid != iter->rq_xid);
if (req->rq_xid < iter->rq_xid)
@@ -766,7 +760,7 @@ int ptlrpc_request_bufs_pack(struct ptlrpc_request *request,
* fail_loc
*/
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(cfs_time_seconds(2));
+ schedule_timeout(2 * HZ);
set_current_state(TASK_RUNNING);
}
}
@@ -1001,18 +995,14 @@ struct ptlrpc_request_set *ptlrpc_prep_fcset(int max, set_producer_func func,
*/
void ptlrpc_set_destroy(struct ptlrpc_request_set *set)
{
- struct list_head *tmp;
- struct list_head *next;
+ struct ptlrpc_request *req;
int expected_phase;
int n = 0;
/* Requests on the set should either all be completed, or all be new */
expected_phase = (atomic_read(&set->set_remaining) == 0) ?
RQ_PHASE_COMPLETE : RQ_PHASE_NEW;
- list_for_each(tmp, &set->set_requests) {
- struct ptlrpc_request *req =
- list_entry(tmp, struct ptlrpc_request, rq_set_chain);
-
+ list_for_each_entry(req, &set->set_requests, rq_set_chain) {
LASSERT(req->rq_phase == expected_phase);
n++;
}
@@ -1021,9 +1011,9 @@ void ptlrpc_set_destroy(struct ptlrpc_request_set *set)
atomic_read(&set->set_remaining) == n, "%d / %d\n",
atomic_read(&set->set_remaining), n);
- list_for_each_safe(tmp, next, &set->set_requests) {
- struct ptlrpc_request *req =
- list_entry(tmp, struct ptlrpc_request, rq_set_chain);
+ while ((req = list_first_entry_or_null(&set->set_requests,
+ struct ptlrpc_request,
+ rq_set_chain))) {
list_del_init(&req->rq_set_chain);
LASSERT(req->rq_phase == expected_phase);
@@ -1588,7 +1578,8 @@ static int ptlrpc_send_new_req(struct ptlrpc_request *req)
spin_lock(&imp->imp_lock);
if (!list_empty(&req->rq_list)) {
list_del_init(&req->rq_list);
- atomic_dec(&req->rq_import->imp_inflight);
+ if (atomic_dec_and_test(&req->rq_import->imp_inflight))
+ wake_up_all(&req->rq_import->imp_recovery_waitq);
}
spin_unlock(&imp->imp_lock);
ptlrpc_rqphase_move(req, RQ_PHASE_NEW);
@@ -1639,7 +1630,7 @@ static inline int ptlrpc_set_producer(struct ptlrpc_request_set *set)
*/
int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set)
{
- struct list_head *tmp, *next;
+ struct ptlrpc_request *req, *next;
struct list_head comp_reqs;
int force_timer_recalc = 0;
@@ -1647,9 +1638,7 @@ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set)
return 1;
INIT_LIST_HEAD(&comp_reqs);
- list_for_each_safe(tmp, next, &set->set_requests) {
- struct ptlrpc_request *req =
- list_entry(tmp, struct ptlrpc_request, rq_set_chain);
+ list_for_each_entry_safe(req, next, &set->set_requests, rq_set_chain) {
struct obd_import *imp = req->rq_import;
int unregistered = 0;
int rc = 0;
@@ -1773,7 +1762,7 @@ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set)
}
/*
- * ptlrpc_set_wait->l_wait_event sets lwi_allow_intr
+ * ptlrpc_set_wait allow signal to abort the timeout
* so it sets rq_intr regardless of individual rpc
* timeouts. The synchronous IO waiting path sets
* rq_intr irrespective of whether ptlrpcd
@@ -2121,19 +2110,15 @@ int ptlrpc_expire_one_request(struct ptlrpc_request *req, int async_unlink)
/**
* Time out all uncompleted requests in request set pointed by \a data
- * Callback used when waiting on sets with l_wait_event.
- * Always returns 1.
+ * Called when wait_event_idle_timeout times out.
*/
-int ptlrpc_expired_set(void *data)
+void ptlrpc_expired_set(struct ptlrpc_request_set *set)
{
- struct ptlrpc_request_set *set = data;
- struct list_head *tmp;
+ struct ptlrpc_request *req;
time64_t now = ktime_get_real_seconds();
/* A timeout expired. See which reqs it applies to... */
- list_for_each(tmp, &set->set_requests) {
- struct ptlrpc_request *req =
- list_entry(tmp, struct ptlrpc_request, rq_set_chain);
+ list_for_each_entry(req, &set->set_requests, rq_set_chain) {
/* don't expire request waiting for context */
if (req->rq_wait_ctx)
@@ -2155,13 +2140,6 @@ int ptlrpc_expired_set(void *data)
*/
ptlrpc_expire_one_request(req, 1);
}
-
- /*
- * When waiting for a whole set, we always break out of the
- * sleep so we can recalculate the timeout, or enable interrupts
- * if everyone's timed out.
- */
- return 1;
}
/**
@@ -2177,18 +2155,14 @@ EXPORT_SYMBOL(ptlrpc_mark_interrupted);
/**
* Interrupts (sets interrupted flag) all uncompleted requests in
- * a set \a data. Callback for l_wait_event for interruptible waits.
+ * a set \a data. Called when l_wait_event_abortable_timeout receives signal.
*/
-static void ptlrpc_interrupted_set(void *data)
+static void ptlrpc_interrupted_set(struct ptlrpc_request_set *set)
{
- struct ptlrpc_request_set *set = data;
- struct list_head *tmp;
-
+ struct ptlrpc_request *req;
CDEBUG(D_RPCTRACE, "INTERRUPTED SET %p\n", set);
- list_for_each(tmp, &set->set_requests) {
- struct ptlrpc_request *req =
- list_entry(tmp, struct ptlrpc_request, rq_set_chain);
+ list_for_each_entry(req, &set->set_requests, rq_set_chain) {
if (req->rq_phase != RQ_PHASE_RPC &&
req->rq_phase != RQ_PHASE_UNREG_RPC)
@@ -2203,14 +2177,12 @@ static void ptlrpc_interrupted_set(void *data)
*/
int ptlrpc_set_next_timeout(struct ptlrpc_request_set *set)
{
- struct list_head *tmp;
time64_t now = ktime_get_real_seconds();
int timeout = 0;
struct ptlrpc_request *req;
time64_t deadline;
- list_for_each(tmp, &set->set_requests) {
- req = list_entry(tmp, struct ptlrpc_request, rq_set_chain);
+ list_for_each_entry(req, &set->set_requests, rq_set_chain) {
/* Request in-flight? */
if (!(((req->rq_phase == RQ_PHASE_RPC) && !req->rq_waiting) ||
@@ -2249,17 +2221,13 @@ int ptlrpc_set_next_timeout(struct ptlrpc_request_set *set)
*/
int ptlrpc_set_wait(struct ptlrpc_request_set *set)
{
- struct list_head *tmp;
struct ptlrpc_request *req;
- struct l_wait_info lwi;
int rc, timeout;
if (set->set_producer)
(void)ptlrpc_set_producer(set);
else
- list_for_each(tmp, &set->set_requests) {
- req = list_entry(tmp, struct ptlrpc_request,
- rq_set_chain);
+ list_for_each_entry(req, &set->set_requests, rq_set_chain) {
if (req->rq_phase == RQ_PHASE_NEW)
(void)ptlrpc_send_new_req(req);
}
@@ -2277,46 +2245,47 @@ int ptlrpc_set_wait(struct ptlrpc_request_set *set)
CDEBUG(D_RPCTRACE, "set %p going to sleep for %d seconds\n",
set, timeout);
- if (timeout == 0 && !signal_pending(current))
+ if (timeout == 0 && !signal_pending(current)) {
/*
* No requests are in-flight (ether timed out
* or delayed), so we can allow interrupts.
* We still want to block for a limited time,
* so we allow interrupts during the timeout.
*/
- lwi = LWI_TIMEOUT_INTR_ALL(cfs_time_seconds(1),
- ptlrpc_expired_set,
- ptlrpc_interrupted_set, set);
- else
+ rc = l_wait_event_abortable_timeout(set->set_waitq,
+ ptlrpc_check_set(NULL, set),
+ HZ);
+ if (rc == 0) {
+ rc = -ETIMEDOUT;
+ ptlrpc_expired_set(set);
+ } else if (rc < 0) {
+ rc = -EINTR;
+ ptlrpc_interrupted_set(set);
+ } else
+ rc = 0;
+ } else {
/*
* At least one request is in flight, so no
* interrupts are allowed. Wait until all
* complete, or an in-flight req times out.
*/
- lwi = LWI_TIMEOUT(cfs_time_seconds(timeout ? timeout : 1),
- ptlrpc_expired_set, set);
-
- rc = l_wait_event(set->set_waitq, ptlrpc_check_set(NULL, set), &lwi);
-
- /*
- * LU-769 - if we ignored the signal because it was already
- * pending when we started, we need to handle it now or we risk
- * it being ignored forever
- */
- if (rc == -ETIMEDOUT && !lwi.lwi_allow_intr &&
- signal_pending(current)) {
- sigset_t blocked_sigs =
- cfs_block_sigsinv(LUSTRE_FATAL_SIGS);
-
- /*
- * In fact we only interrupt for the "fatal" signals
- * like SIGINT or SIGKILL. We still ignore less
- * important signals since ptlrpc set is not easily
- * reentrant from userspace again
- */
- if (signal_pending(current))
- ptlrpc_interrupted_set(set);
- cfs_restore_sigs(blocked_sigs);
+ rc = wait_event_idle_timeout(set->set_waitq,
+ ptlrpc_check_set(NULL, set),
+ (timeout ? timeout : 1) * HZ);
+ if (rc == 0) {
+ ptlrpc_expired_set(set);
+ rc = -ETIMEDOUT;
+ /*
+ * LU-769 - if we ignored the signal
+ * because it was already pending when
+ * we started, we need to handle it
+ * now or we risk it being ignored
+ * forever
+ */
+ if (l_fatal_signal_pending(current))
+ ptlrpc_interrupted_set(set);
+ } else
+ rc = 0;
}
LASSERT(rc == 0 || rc == -EINTR || rc == -ETIMEDOUT);
@@ -2331,9 +2300,7 @@ int ptlrpc_set_wait(struct ptlrpc_request_set *set)
* the error cases -eeb.
*/
if (rc == 0 && atomic_read(&set->set_remaining) == 0) {
- list_for_each(tmp, &set->set_requests) {
- req = list_entry(tmp, struct ptlrpc_request,
- rq_set_chain);
+ list_for_each_entry(req, &set->set_requests, rq_set_chain) {
spin_lock(&req->rq_lock);
req->rq_invalid_rqset = 1;
spin_unlock(&req->rq_lock);
@@ -2344,9 +2311,7 @@ int ptlrpc_set_wait(struct ptlrpc_request_set *set)
LASSERT(atomic_read(&set->set_remaining) == 0);
rc = set->set_rc; /* rq_status of already freed requests if any */
- list_for_each(tmp, &set->set_requests) {
- req = list_entry(tmp, struct ptlrpc_request, rq_set_chain);
-
+ list_for_each_entry(req, &set->set_requests, rq_set_chain) {
LASSERT(req->rq_phase == RQ_PHASE_COMPLETE);
if (req->rq_status != 0)
rc = req->rq_status;
@@ -2495,7 +2460,6 @@ static int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async)
{
int rc;
wait_queue_head_t *wq;
- struct l_wait_info lwi;
/* Might sleep. */
LASSERT(!in_interrupt());
@@ -2524,7 +2488,7 @@ static int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async)
return 0;
/*
- * We have to l_wait_event() whatever the result, to give liblustre
+ * We have to wait_event_idle_timeout() whatever the result, to give liblustre
* a chance to run reply_in_callback(), and to make sure we've
* unlinked before returning a req to the pool.
*/
@@ -2538,16 +2502,17 @@ static int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async)
* Network access will complete in finite time but the HUGE
* timeout lets us CWARN for visibility of sluggish NALs
*/
- lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(LONG_UNLINK),
- cfs_time_seconds(1), NULL, NULL);
- rc = l_wait_event(*wq, !ptlrpc_client_recv_or_unlink(request),
- &lwi);
- if (rc == 0) {
+ int cnt = 0;
+ while (cnt < LONG_UNLINK &&
+ (rc = wait_event_idle_timeout(*wq,
+ !ptlrpc_client_recv_or_unlink(request),
+ HZ)) == 0)
+ cnt += 1;
+ if (rc > 0) {
ptlrpc_rqphase_move(request, request->rq_next_phase);
return 1;
}
- LASSERT(rc == -ETIMEDOUT);
DEBUG_REQ(D_WARNING, request,
"Unexpectedly long timeout receiving_reply=%d req_ulinked=%d reply_unlinked=%d",
request->rq_receiving_reply,
@@ -2725,8 +2690,7 @@ EXPORT_SYMBOL(ptlrpc_request_addref);
void ptlrpc_retain_replayable_request(struct ptlrpc_request *req,
struct obd_import *imp)
{
- struct list_head *tmp;
-
+ struct ptlrpc_request *iter;
assert_spin_locked(&imp->imp_lock);
if (req->rq_transno == 0) {
@@ -2753,10 +2717,7 @@ void ptlrpc_retain_replayable_request(struct ptlrpc_request *req,
LASSERT(imp->imp_replayable);
/* Balanced in ptlrpc_free_committed, usually. */
ptlrpc_request_addref(req);
- list_for_each_prev(tmp, &imp->imp_replay_list) {
- struct ptlrpc_request *iter =
- list_entry(tmp, struct ptlrpc_request, rq_replay_list);
-
+ list_for_each_entry_reverse(iter, &imp->imp_replay_list, rq_replay_list) {
/*
* We may have duplicate transnos if we create and then
* open a file, or for closes retained if to match creating
@@ -2964,7 +2925,7 @@ int ptlrpc_replay_req(struct ptlrpc_request *req)
*/
void ptlrpc_abort_inflight(struct obd_import *imp)
{
- struct list_head *tmp, *n;
+ struct ptlrpc_request *req, *n;
/*
* Make sure that no new requests get processed for this import.
@@ -2978,10 +2939,7 @@ void ptlrpc_abort_inflight(struct obd_import *imp)
* locked? Also, how do we know if the requests on the list are
* being freed at this time?
*/
- list_for_each_safe(tmp, n, &imp->imp_sending_list) {
- struct ptlrpc_request *req =
- list_entry(tmp, struct ptlrpc_request, rq_list);
-
+ list_for_each_entry_safe(req, n, &imp->imp_sending_list, rq_list) {
DEBUG_REQ(D_RPCTRACE, req, "inflight");
spin_lock(&req->rq_lock);
@@ -2993,10 +2951,7 @@ void ptlrpc_abort_inflight(struct obd_import *imp)
spin_unlock(&req->rq_lock);
}
- list_for_each_safe(tmp, n, &imp->imp_delayed_list) {
- struct ptlrpc_request *req =
- list_entry(tmp, struct ptlrpc_request, rq_list);
-
+ list_for_each_entry_safe(req, n, &imp->imp_delayed_list, rq_list) {
DEBUG_REQ(D_RPCTRACE, req, "aborting waiting req");
spin_lock(&req->rq_lock);
@@ -3023,12 +2978,9 @@ void ptlrpc_abort_inflight(struct obd_import *imp)
*/
void ptlrpc_abort_set(struct ptlrpc_request_set *set)
{
- struct list_head *tmp, *pos;
-
- list_for_each_safe(pos, tmp, &set->set_requests) {
- struct ptlrpc_request *req =
- list_entry(pos, struct ptlrpc_request, rq_set_chain);
+ struct ptlrpc_request *req, *tmp;
+ list_for_each_entry_safe(req, tmp, &set->set_requests, rq_set_chain) {
spin_lock(&req->rq_lock);
if (req->rq_phase != RQ_PHASE_RPC) {
spin_unlock(&req->rq_lock);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c
index 811b7ab3a582..130bacc2c891 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/events.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/events.c
@@ -490,8 +490,6 @@ int ptlrpc_uuid_to_peer(struct obd_uuid *uuid,
static void ptlrpc_ni_fini(void)
{
- wait_queue_head_t waitq;
- struct l_wait_info lwi;
int rc;
int retries;
@@ -515,10 +513,7 @@ static void ptlrpc_ni_fini(void)
if (retries != 0)
CWARN("Event queue still busy\n");
- /* Wait for a bit */
- init_waitqueue_head(&waitq);
- lwi = LWI_TIMEOUT(cfs_time_seconds(2), NULL, NULL);
- l_wait_event(waitq, 0, &lwi);
+ schedule_timeout_uninterruptible(2 * HZ);
break;
}
}
diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c
index 5b0f65536c29..a2c4fc3488b1 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/import.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/import.c
@@ -242,15 +242,13 @@ ptlrpc_inflight_deadline(struct ptlrpc_request *req, time64_t now)
static unsigned int ptlrpc_inflight_timeout(struct obd_import *imp)
{
time64_t now = ktime_get_real_seconds();
- struct list_head *tmp, *n;
- struct ptlrpc_request *req;
+ struct ptlrpc_request *req, *n;
unsigned int timeout = 0;
spin_lock(&imp->imp_lock);
- list_for_each_safe(tmp, n, &imp->imp_sending_list) {
- req = list_entry(tmp, struct ptlrpc_request, rq_list);
+ list_for_each_entry_safe(req, n, &imp->imp_sending_list, rq_list)
timeout = max(ptlrpc_inflight_deadline(req, now), timeout);
- }
+
spin_unlock(&imp->imp_lock);
return timeout;
}
@@ -263,9 +261,7 @@ static unsigned int ptlrpc_inflight_timeout(struct obd_import *imp)
*/
void ptlrpc_invalidate_import(struct obd_import *imp)
{
- struct list_head *tmp, *n;
- struct ptlrpc_request *req;
- struct l_wait_info lwi;
+ struct ptlrpc_request *req, *n;
unsigned int timeout;
int rc;
@@ -306,19 +302,15 @@ void ptlrpc_invalidate_import(struct obd_import *imp)
* callbacks. Cap it at obd_timeout -- these should all
* have been locally cancelled by ptlrpc_abort_inflight.
*/
- lwi = LWI_TIMEOUT_INTERVAL(
- cfs_timeout_cap(cfs_time_seconds(timeout)),
- (timeout > 1) ? cfs_time_seconds(1) :
- cfs_time_seconds(1) / 2,
- NULL, NULL);
- rc = l_wait_event(imp->imp_recovery_waitq,
- (atomic_read(&imp->imp_inflight) == 0),
- &lwi);
- if (rc) {
+ rc = wait_event_idle_timeout(imp->imp_recovery_waitq,
+ atomic_read(&imp->imp_inflight) == 0,
+ obd_timeout * HZ);
+
+ if (rc == 0) {
const char *cli_tgt = obd2cli_tgt(imp->imp_obd);
- CERROR("%s: rc = %d waiting for callback (%d != 0)\n",
- cli_tgt, rc,
+ CERROR("%s: timeout waiting for callback (%d != 0)\n",
+ cli_tgt,
atomic_read(&imp->imp_inflight));
spin_lock(&imp->imp_lock);
@@ -341,19 +333,13 @@ void ptlrpc_invalidate_import(struct obd_import *imp)
*/
rc = 0;
} else {
- list_for_each_safe(tmp, n,
- &imp->imp_sending_list) {
- req = list_entry(tmp,
- struct ptlrpc_request,
- rq_list);
+ list_for_each_entry_safe(req, n,
+ &imp->imp_sending_list, rq_list) {
DEBUG_REQ(D_ERROR, req,
"still on sending list");
}
- list_for_each_safe(tmp, n,
- &imp->imp_delayed_list) {
- req = list_entry(tmp,
- struct ptlrpc_request,
- rq_list);
+ list_for_each_entry_safe(req, n,
+ &imp->imp_delayed_list, rq_list) {
DEBUG_REQ(D_ERROR, req,
"still on delayed list");
}
@@ -365,7 +351,7 @@ void ptlrpc_invalidate_import(struct obd_import *imp)
}
spin_unlock(&imp->imp_lock);
}
- } while (rc != 0);
+ } while (rc == 0);
/*
* Let's additionally check that no new rpcs added to import in
@@ -430,21 +416,19 @@ void ptlrpc_fail_import(struct obd_import *imp, __u32 conn_cnt)
int ptlrpc_reconnect_import(struct obd_import *imp)
{
- struct l_wait_info lwi;
- int secs = cfs_time_seconds(obd_timeout);
int rc;
ptlrpc_pinger_force(imp);
CDEBUG(D_HA, "%s: recovery started, waiting %u seconds\n",
- obd2cli_tgt(imp->imp_obd), secs);
+ obd2cli_tgt(imp->imp_obd), obd_timeout);
- lwi = LWI_TIMEOUT(secs, NULL, NULL);
- rc = l_wait_event(imp->imp_recovery_waitq,
- !ptlrpc_import_in_recovery(imp), &lwi);
+ rc = wait_event_idle_timeout(imp->imp_recovery_waitq,
+ !ptlrpc_import_in_recovery(imp),
+ obd_timeout * HZ);
CDEBUG(D_HA, "%s: recovery finished s:%s\n", obd2cli_tgt(imp->imp_obd),
ptlrpc_import_state_name(imp->imp_state));
- return rc;
+ return rc == 0 ? -ETIMEDOUT : 0;
}
EXPORT_SYMBOL(ptlrpc_reconnect_import);
@@ -564,14 +548,13 @@ static int import_select_connection(struct obd_import *imp)
static int ptlrpc_first_transno(struct obd_import *imp, __u64 *transno)
{
struct ptlrpc_request *req;
- struct list_head *tmp;
/* The requests in committed_list always have smaller transnos than
* the requests in replay_list
*/
if (!list_empty(&imp->imp_committed_list)) {
- tmp = imp->imp_committed_list.next;
- req = list_entry(tmp, struct ptlrpc_request, rq_replay_list);
+ req = list_first_entry(&imp->imp_committed_list,
+ struct ptlrpc_request, rq_replay_list);
*transno = req->rq_transno;
if (req->rq_transno == 0) {
DEBUG_REQ(D_ERROR, req,
@@ -581,8 +564,8 @@ static int ptlrpc_first_transno(struct obd_import *imp, __u64 *transno)
return 1;
}
if (!list_empty(&imp->imp_replay_list)) {
- tmp = imp->imp_replay_list.next;
- req = list_entry(tmp, struct ptlrpc_request, rq_replay_list);
+ req = list_first_entry(&imp->imp_replay_list,
+ struct ptlrpc_request, rq_replay_list);
*transno = req->rq_transno;
if (req->rq_transno == 0) {
DEBUG_REQ(D_ERROR, req, "zero transno in replay_list");
@@ -1503,25 +1486,25 @@ int ptlrpc_disconnect_import(struct obd_import *imp, int noclose)
}
if (ptlrpc_import_in_recovery(imp)) {
- struct l_wait_info lwi;
long timeout;
if (AT_OFF) {
if (imp->imp_server_timeout)
- timeout = cfs_time_seconds(obd_timeout / 2);
+ timeout = obd_timeout * HZ / 2;
else
- timeout = cfs_time_seconds(obd_timeout);
+ timeout = obd_timeout * HZ;
} else {
int idx = import_at_get_index(imp,
imp->imp_client->cli_request_portal);
- timeout = cfs_time_seconds(
- at_get(&imp->imp_at.iat_service_estimate[idx]));
+ timeout = at_get(&imp->imp_at.iat_service_estimate[idx]) * HZ;
}
- lwi = LWI_TIMEOUT_INTR(cfs_timeout_cap(timeout),
- back_to_sleep, LWI_ON_SIGNAL_NOOP, NULL);
- rc = l_wait_event(imp->imp_recovery_waitq,
- !ptlrpc_import_in_recovery(imp), &lwi);
+ if (wait_event_idle_timeout(imp->imp_recovery_waitq,
+ !ptlrpc_import_in_recovery(imp),
+ cfs_timeout_cap(timeout)) == 0)
+ l_wait_event_abortable(
+ imp->imp_recovery_waitq,
+ !ptlrpc_import_in_recovery(imp));
}
spin_lock(&imp->imp_lock);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/layout.c b/drivers/staging/lustre/lustre/ptlrpc/layout.c
index 18769d335751..2855f38c8190 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/layout.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/layout.c
@@ -1555,7 +1555,7 @@ struct req_format RQF_OST_GET_INFO_FIEMAP =
EXPORT_SYMBOL(RQF_OST_GET_INFO_FIEMAP);
/* Convenience macro */
-#define FMT_FIELD(fmt, i, j) (fmt)->rf_fields[(i)].d[(j)]
+#define FMT_FIELD(fmt, i, j) ((fmt)->rf_fields[(i)].d[(j)])
/**
* Initializes the capsule abstraction by computing and setting the \a rf_idx
diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
index 047d712e850c..86883abaad2c 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
@@ -229,7 +229,6 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async)
{
struct ptlrpc_bulk_desc *desc = req->rq_bulk;
wait_queue_head_t *wq;
- struct l_wait_info lwi;
int rc;
LASSERT(!in_interrupt()); /* might sleep */
@@ -246,7 +245,7 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async)
/* the unlink ensures the callback happens ASAP and is the last
* one. If it fails, it must be because completion just happened,
- * but we must still l_wait_event() in this case to give liblustre
+ * but we must still wait_event() in this case to give liblustre
* a chance to run client_bulk_callback()
*/
mdunlink_iterate_helper(desc->bd_mds, desc->bd_md_max_brw);
@@ -270,15 +269,17 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async)
/* Network access will complete in finite time but the HUGE
* timeout lets us CWARN for visibility of sluggish LNDs
*/
- lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(LONG_UNLINK),
- cfs_time_seconds(1), NULL, NULL);
- rc = l_wait_event(*wq, !ptlrpc_client_bulk_active(req), &lwi);
- if (rc == 0) {
+ int cnt = 0;
+ while (cnt < LONG_UNLINK &&
+ (rc = wait_event_idle_timeout(*wq,
+ !ptlrpc_client_bulk_active(req),
+ HZ)) == 0)
+ cnt += 1;
+ if (rc > 0) {
ptlrpc_rqphase_move(req, req->rq_next_phase);
return 1;
}
- LASSERT(rc == -ETIMEDOUT);
DEBUG_REQ(D_WARNING, req, "Unexpectedly long timeout: desc %p",
desc);
}
diff --git a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
index a64e125df95f..f73463ac401f 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
@@ -260,17 +260,16 @@ lustre_get_emerg_rs(struct ptlrpc_service_part *svcpt)
/* See if we have anything in a pool, and wait if nothing */
while (list_empty(&svcpt->scp_rep_idle)) {
- struct l_wait_info lwi;
int rc;
spin_unlock(&svcpt->scp_rep_lock);
/* If we cannot get anything for some long time, we better
* bail out instead of waiting infinitely
*/
- lwi = LWI_TIMEOUT(cfs_time_seconds(10), NULL, NULL);
- rc = l_wait_event(svcpt->scp_rep_waitq,
- !list_empty(&svcpt->scp_rep_idle), &lwi);
- if (rc != 0)
+ rc = wait_event_idle_timeout(svcpt->scp_rep_waitq,
+ !list_empty(&svcpt->scp_rep_idle),
+ 10 * HZ);
+ if (rc == 0)
goto out;
spin_lock(&svcpt->scp_rep_lock);
}
diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c
index fe6b47bfe8be..0775b7a048bb 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/pinger.c
@@ -141,7 +141,7 @@ static long pinger_check_timeout(unsigned long time)
}
mutex_unlock(&pinger_mutex);
- return cfs_time_sub(cfs_time_add(time, cfs_time_seconds(timeout)),
+ return cfs_time_sub(cfs_time_add(time, timeout * HZ),
cfs_time_current());
}
@@ -217,37 +217,29 @@ static void ptlrpc_pinger_process_import(struct obd_import *imp,
}
}
-static int ptlrpc_pinger_main(void *arg)
-{
- struct ptlrpc_thread *thread = arg;
-
- /* Record that the thread is running */
- thread_set_flags(thread, SVC_RUNNING);
- wake_up(&thread->t_ctl_waitq);
+static struct workqueue_struct *pinger_wq;
+static void ptlrpc_pinger_main(struct work_struct *ws);
+static DECLARE_DELAYED_WORK(ping_work, ptlrpc_pinger_main);
- /* And now, loop forever, pinging as needed. */
- while (1) {
- unsigned long this_ping = cfs_time_current();
- struct l_wait_info lwi;
- long time_to_next_wake;
- struct timeout_item *item;
- struct list_head *iter;
+static void ptlrpc_pinger_main(struct work_struct *ws)
+{
+ unsigned long this_ping = cfs_time_current();
+ long time_to_next_wake;
+ struct timeout_item *item;
+ struct obd_import *imp;
+ do {
mutex_lock(&pinger_mutex);
list_for_each_entry(item, &timeout_list, ti_chain) {
item->ti_cb(item, item->ti_cb_data);
}
- list_for_each(iter, &pinger_imports) {
- struct obd_import *imp =
- list_entry(iter, struct obd_import,
- imp_pinger_chain);
-
+ list_for_each_entry(imp, &pinger_imports, imp_pinger_chain) {
ptlrpc_pinger_process_import(imp, this_ping);
/* obd_timeout might have changed */
if (imp->imp_pingable && imp->imp_next_ping &&
cfs_time_after(imp->imp_next_ping,
cfs_time_add(this_ping,
- cfs_time_seconds(PING_INTERVAL))))
+ PING_INTERVAL * HZ)))
ptlrpc_update_next_ping(imp, 0);
}
mutex_unlock(&pinger_mutex);
@@ -264,55 +256,25 @@ static int ptlrpc_pinger_main(void *arg)
CDEBUG(D_INFO, "next wakeup in " CFS_DURATION_T " (%ld)\n",
time_to_next_wake,
cfs_time_add(this_ping,
- cfs_time_seconds(PING_INTERVAL)));
- if (time_to_next_wake > 0) {
- lwi = LWI_TIMEOUT(max_t(long, time_to_next_wake,
- cfs_time_seconds(1)),
- NULL, NULL);
- l_wait_event(thread->t_ctl_waitq,
- thread_is_stopping(thread) ||
- thread_is_event(thread),
- &lwi);
- if (thread_test_and_clear_flags(thread, SVC_STOPPING))
- break;
- /* woken after adding import to reset timer */
- thread_test_and_clear_flags(thread, SVC_EVENT);
- }
- }
-
- thread_set_flags(thread, SVC_STOPPED);
- wake_up(&thread->t_ctl_waitq);
+ PING_INTERVAL * HZ));
+ } while (time_to_next_wake <= 0);
- CDEBUG(D_NET, "pinger thread exiting, process %d\n", current_pid());
- return 0;
+ queue_delayed_work(pinger_wq, &ping_work,
+ round_jiffies_up_relative(time_to_next_wake));
}
-static struct ptlrpc_thread pinger_thread;
-
int ptlrpc_start_pinger(void)
{
- struct l_wait_info lwi = { 0 };
- struct task_struct *task;
- int rc;
-
- if (!thread_is_init(&pinger_thread) &&
- !thread_is_stopped(&pinger_thread))
+ if (pinger_wq)
return -EALREADY;
- init_waitqueue_head(&pinger_thread.t_ctl_waitq);
-
- strcpy(pinger_thread.t_name, "ll_ping");
-
- task = kthread_run(ptlrpc_pinger_main, &pinger_thread,
- pinger_thread.t_name);
- if (IS_ERR(task)) {
- rc = PTR_ERR(task);
- CERROR("cannot start pinger thread: rc = %d\n", rc);
- return rc;
+ pinger_wq = alloc_workqueue("ptlrpc_pinger", WQ_MEM_RECLAIM, 1);
+ if (!pinger_wq) {
+ CERROR("cannot start pinger workqueue\n");
+ return -ENOMEM;
}
- l_wait_event(pinger_thread.t_ctl_waitq,
- thread_is_running(&pinger_thread), &lwi);
+ queue_delayed_work(pinger_wq, &ping_work, 0);
return 0;
}
@@ -320,19 +282,15 @@ static int ptlrpc_pinger_remove_timeouts(void);
int ptlrpc_stop_pinger(void)
{
- struct l_wait_info lwi = { 0 };
int rc = 0;
- if (thread_is_init(&pinger_thread) ||
- thread_is_stopped(&pinger_thread))
+ if (!pinger_wq)
return -EALREADY;
ptlrpc_pinger_remove_timeouts();
- thread_set_flags(&pinger_thread, SVC_STOPPING);
- wake_up(&pinger_thread.t_ctl_waitq);
-
- l_wait_event(pinger_thread.t_ctl_waitq,
- thread_is_stopped(&pinger_thread), &lwi);
+ cancel_delayed_work_sync(&ping_work);
+ destroy_workqueue(pinger_wq);
+ pinger_wq = NULL;
return rc;
}
@@ -515,6 +473,5 @@ static int ptlrpc_pinger_remove_timeouts(void)
void ptlrpc_pinger_wake_up(void)
{
- thread_add_flags(&pinger_thread, SVC_EVENT);
- wake_up(&pinger_thread.t_ctl_waitq);
+ mod_delayed_work(pinger_wq, &ping_work, 0);
}
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h
index f9decbd1459d..b7a8d7537a66 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h
@@ -68,7 +68,7 @@ void ptlrpc_request_cache_free(struct ptlrpc_request *req);
void ptlrpc_init_xid(void);
void ptlrpc_set_add_new_req(struct ptlrpcd_ctl *pc,
struct ptlrpc_request *req);
-int ptlrpc_expired_set(void *data);
+void ptlrpc_expired_set(struct ptlrpc_request_set *set);
int ptlrpc_set_next_timeout(struct ptlrpc_request_set *set);
void ptlrpc_resend_req(struct ptlrpc_request *request);
void ptlrpc_set_bulk_mbits(struct ptlrpc_request *req);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c
index 131fc6d9646e..38923418669f 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c
@@ -45,6 +45,42 @@ extern spinlock_t ptlrpc_last_xid_lock;
extern spinlock_t ptlrpc_rs_debug_lock;
#endif
+DEFINE_MUTEX(ptlrpc_startup);
+static int ptlrpc_active = 0;
+
+int ptlrpc_inc_ref(void)
+{
+ int rc = 0;
+
+ mutex_lock(&ptlrpc_startup);
+ if (ptlrpc_active++ == 0) {
+ ptlrpc_put_connection_superhack = ptlrpc_connection_put;
+
+ rc = ptlrpc_init_portals();
+ if (!rc) {
+ rc= ptlrpc_start_pinger();
+ if (rc)
+ ptlrpc_exit_portals();
+ }
+ if (rc)
+ ptlrpc_active--;
+ }
+ mutex_unlock(&ptlrpc_startup);
+ return rc;
+}
+EXPORT_SYMBOL(ptlrpc_inc_ref);
+
+void ptlrpc_dec_ref(void)
+{
+ mutex_lock(&ptlrpc_startup);
+ if (--ptlrpc_active == 0) {
+ ptlrpc_stop_pinger();
+ ptlrpc_exit_portals();
+ }
+ mutex_unlock(&ptlrpc_startup);
+}
+EXPORT_SYMBOL(ptlrpc_dec_ref);
+
static int __init ptlrpc_init(void)
{
int rc, cleanup_phase = 0;
@@ -71,24 +107,12 @@ static int __init ptlrpc_init(void)
if (rc)
goto cleanup;
- cleanup_phase = 2;
- rc = ptlrpc_init_portals();
- if (rc)
- goto cleanup;
-
cleanup_phase = 3;
rc = ptlrpc_connection_init();
if (rc)
goto cleanup;
- cleanup_phase = 4;
- ptlrpc_put_connection_superhack = ptlrpc_connection_put;
-
- rc = ptlrpc_start_pinger();
- if (rc)
- goto cleanup;
-
cleanup_phase = 5;
rc = ldlm_init();
if (rc)
@@ -122,15 +146,9 @@ cleanup:
ldlm_exit();
/* Fall through */
case 5:
- ptlrpc_stop_pinger();
- /* Fall through */
- case 4:
ptlrpc_connection_fini();
/* Fall through */
case 3:
- ptlrpc_exit_portals();
- /* Fall through */
- case 2:
ptlrpc_request_cache_fini();
/* Fall through */
case 1:
@@ -150,8 +168,6 @@ static void __exit ptlrpc_exit(void)
ptlrpc_nrs_fini();
sptlrpc_fini();
ldlm_exit();
- ptlrpc_stop_pinger();
- ptlrpc_exit_portals();
ptlrpc_request_cache_fini();
ptlrpc_hr_fini();
ptlrpc_connection_fini();
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
index 8b865294d933..c0fa13942bd8 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
@@ -197,17 +197,14 @@ ptlrpcd_select_pc(struct ptlrpc_request *req)
static int ptlrpcd_steal_rqset(struct ptlrpc_request_set *des,
struct ptlrpc_request_set *src)
{
- struct list_head *tmp, *pos;
- struct ptlrpc_request *req;
+ struct ptlrpc_request *req, *tmp;
int rc = 0;
spin_lock(&src->set_new_req_lock);
if (likely(!list_empty(&src->set_new_requests))) {
- list_for_each_safe(pos, tmp, &src->set_new_requests) {
- req = list_entry(pos, struct ptlrpc_request,
- rq_set_chain);
+ list_for_each_entry_safe(req, tmp, &src->set_new_requests, rq_set_chain)
req->rq_set = des;
- }
+
list_splice_init(&src->set_new_requests, &des->set_requests);
rc = atomic_read(&src->set_new_count);
atomic_add(rc, &des->set_remaining);
@@ -230,12 +227,13 @@ void ptlrpcd_add_req(struct ptlrpc_request *req)
spin_lock(&req->rq_lock);
if (req->rq_invalid_rqset) {
- struct l_wait_info lwi = LWI_TIMEOUT(cfs_time_seconds(5),
- back_to_sleep, NULL);
-
req->rq_invalid_rqset = 0;
spin_unlock(&req->rq_lock);
- l_wait_event(req->rq_set_waitq, !req->rq_set, &lwi);
+ if (wait_event_idle_timeout(req->rq_set_waitq,
+ !req->rq_set,
+ 5 * HZ) == 0)
+ wait_event_idle(req->rq_set_waitq,
+ !req->rq_set);
} else if (req->rq_set) {
/* If we have a valid "rq_set", just reuse it to avoid double
* linked.
@@ -272,8 +270,7 @@ static inline void ptlrpc_reqset_get(struct ptlrpc_request_set *set)
*/
static int ptlrpcd_check(struct lu_env *env, struct ptlrpcd_ctl *pc)
{
- struct list_head *tmp, *pos;
- struct ptlrpc_request *req;
+ struct ptlrpc_request *req, *tmp;
struct ptlrpc_request_set *set = pc->pc_set;
int rc = 0;
int rc2;
@@ -319,8 +316,7 @@ static int ptlrpcd_check(struct lu_env *env, struct ptlrpcd_ctl *pc)
/* NB: ptlrpc_check_set has already moved completed request at the
* head of seq::set_requests
*/
- list_for_each_safe(pos, tmp, &set->set_requests) {
- req = list_entry(pos, struct ptlrpc_request, rq_set_chain);
+ list_for_each_entry_safe(req, tmp, &set->set_requests, rq_set_chain) {
if (req->rq_phase != RQ_PHASE_COMPLETE)
break;
@@ -434,16 +430,17 @@ static int ptlrpcd(void *arg)
* new_req_list and ptlrpcd_check() moves them into the set.
*/
do {
- struct l_wait_info lwi;
int timeout;
timeout = ptlrpc_set_next_timeout(set);
- lwi = LWI_TIMEOUT(cfs_time_seconds(timeout ? timeout : 1),
- ptlrpc_expired_set, set);
lu_context_enter(&env.le_ctx);
lu_context_enter(env.le_ses);
- l_wait_event(set->set_waitq, ptlrpcd_check(&env, pc), &lwi);
+ if (wait_event_idle_timeout(set->set_waitq,
+ ptlrpcd_check(&env, pc),
+ (timeout ? timeout : 1) * HZ) == 0)
+ ptlrpc_expired_set(set);
+
lu_context_exit(&env.le_ctx);
lu_context_exit(env.le_ses);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/recover.c b/drivers/staging/lustre/lustre/ptlrpc/recover.c
index e4d3f23e9f3a..2ea0a7ff87dd 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/recover.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/recover.c
@@ -66,8 +66,7 @@ void ptlrpc_initiate_recovery(struct obd_import *imp)
int ptlrpc_replay_next(struct obd_import *imp, int *inflight)
{
int rc = 0;
- struct list_head *tmp, *pos;
- struct ptlrpc_request *req = NULL;
+ struct ptlrpc_request *req = NULL, *pos;
__u64 last_transno;
*inflight = 0;
@@ -86,8 +85,8 @@ int ptlrpc_replay_next(struct obd_import *imp, int *inflight)
/* Replay all the committed open requests on committed_list first */
if (!list_empty(&imp->imp_committed_list)) {
- tmp = imp->imp_committed_list.prev;
- req = list_entry(tmp, struct ptlrpc_request, rq_replay_list);
+ req = list_last_entry(&imp->imp_committed_list,
+ struct ptlrpc_request, rq_replay_list);
/* The last request on committed_list hasn't been replayed */
if (req->rq_transno > last_transno) {
@@ -119,13 +118,13 @@ int ptlrpc_replay_next(struct obd_import *imp, int *inflight)
* the imp_replay_list
*/
if (!req) {
- list_for_each_safe(tmp, pos, &imp->imp_replay_list) {
- req = list_entry(tmp, struct ptlrpc_request,
- rq_replay_list);
-
- if (req->rq_transno > last_transno)
+ struct ptlrpc_request *tmp;
+ list_for_each_entry_safe(tmp, pos, &imp->imp_replay_list,
+ rq_replay_list) {
+ if (tmp->rq_transno > last_transno) {
+ req = tmp;
break;
- req = NULL;
+ }
}
}
@@ -211,13 +210,10 @@ int ptlrpc_resend(struct obd_import *imp)
*/
void ptlrpc_wake_delayed(struct obd_import *imp)
{
- struct list_head *tmp, *pos;
- struct ptlrpc_request *req;
+ struct ptlrpc_request *req, *pos;
spin_lock(&imp->imp_lock);
- list_for_each_safe(tmp, pos, &imp->imp_delayed_list) {
- req = list_entry(tmp, struct ptlrpc_request, rq_list);
-
+ list_for_each_entry_safe(req, pos, &imp->imp_delayed_list, rq_list) {
DEBUG_REQ(D_HA, req, "waking (set %p):", req->rq_set);
ptlrpc_client_wake_req(req);
}
@@ -346,17 +342,15 @@ int ptlrpc_recover_import(struct obd_import *imp, char *new_uuid, int async)
goto out;
if (!async) {
- struct l_wait_info lwi;
- int secs = cfs_time_seconds(obd_timeout);
-
CDEBUG(D_HA, "%s: recovery started, waiting %u seconds\n",
- obd2cli_tgt(imp->imp_obd), secs);
+ obd2cli_tgt(imp->imp_obd), obd_timeout);
- lwi = LWI_TIMEOUT(secs, NULL, NULL);
- rc = l_wait_event(imp->imp_recovery_waitq,
- !ptlrpc_import_in_recovery(imp), &lwi);
+ rc = wait_event_idle_timeout(imp->imp_recovery_waitq,
+ !ptlrpc_import_in_recovery(imp),
+ obd_timeout * HZ);
CDEBUG(D_HA, "%s: recovery finished\n",
obd2cli_tgt(imp->imp_obd));
+ rc = rc ? 0 : -ETIMEDOUT;
}
out:
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c
index 617e004d00f8..3cb1e075f077 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c
@@ -339,11 +339,9 @@ static int import_sec_validate_get(struct obd_import *imp,
}
*sec = sptlrpc_import_sec_ref(imp);
- /* Only output an error when the import is still active */
if (!*sec) {
- if (list_empty(&imp->imp_zombie_chain))
- CERROR("import %p (%s) with no sec\n",
- imp, ptlrpc_import_state_name(imp->imp_state));
+ CERROR("import %p (%s) with no sec\n",
+ imp, ptlrpc_import_state_name(imp->imp_state));
return -EACCES;
}
@@ -442,7 +440,7 @@ int sptlrpc_req_ctx_switch(struct ptlrpc_request *req,
/* save request message */
reqmsg_size = req->rq_reqlen;
if (reqmsg_size != 0) {
- reqmsg = libcfs_kvzalloc(reqmsg_size, GFP_NOFS);
+ reqmsg = kvzalloc(reqmsg_size, GFP_NOFS);
if (!reqmsg)
return -ENOMEM;
memcpy(reqmsg, req->rq_reqmsg, reqmsg_size);
@@ -554,9 +552,8 @@ int ctx_check_refresh(struct ptlrpc_cli_ctx *ctx)
}
static
-int ctx_refresh_timeout(void *data)
+int ctx_refresh_timeout(struct ptlrpc_request *req)
{
- struct ptlrpc_request *req = data;
int rc;
/* conn_cnt is needed in expire_one_request */
@@ -575,10 +572,8 @@ int ctx_refresh_timeout(void *data)
}
static
-void ctx_refresh_interrupt(void *data)
+void ctx_refresh_interrupt(struct ptlrpc_request *req)
{
- struct ptlrpc_request *req = data;
-
spin_lock(&req->rq_lock);
req->rq_intr = 1;
spin_unlock(&req->rq_lock);
@@ -611,7 +606,6 @@ int sptlrpc_req_refresh_ctx(struct ptlrpc_request *req, long timeout)
{
struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx;
struct ptlrpc_sec *sec;
- struct l_wait_info lwi;
int rc;
LASSERT(ctx);
@@ -743,10 +737,28 @@ again:
req->rq_restart = 0;
spin_unlock(&req->rq_lock);
- lwi = LWI_TIMEOUT_INTR(msecs_to_jiffies(timeout * MSEC_PER_SEC),
- ctx_refresh_timeout, ctx_refresh_interrupt,
- req);
- rc = l_wait_event(req->rq_reply_waitq, ctx_check_refresh(ctx), &lwi);
+ rc = wait_event_idle_timeout(req->rq_reply_waitq,
+ ctx_check_refresh(ctx),
+ timeout * HZ);
+ if (rc == 0 && ctx_refresh_timeout(req) == 0) {
+ /* Keep waiting, but enable some signals */
+ rc = l_wait_event_abortable(req->rq_reply_waitq,
+ ctx_check_refresh(ctx));
+ if (rc == 0)
+ rc = 1;
+ }
+
+ if (rc > 0)
+ /* condition is true */
+ rc = 0;
+ else if (rc == 0)
+ /* Timed out */
+ rc = -ETIMEDOUT;
+ else {
+ /* Aborted by signal */
+ rc = -EINTR;
+ ctx_refresh_interrupt(req);
+ }
/*
* following cases could lead us here:
@@ -1075,7 +1087,7 @@ int sptlrpc_cli_unwrap_early_reply(struct ptlrpc_request *req,
early_size = req->rq_nob_received;
early_bufsz = size_roundup_power2(early_size);
- early_buf = libcfs_kvzalloc(early_bufsz, GFP_NOFS);
+ early_buf = kvzalloc(early_bufsz, GFP_NOFS);
if (!early_buf) {
rc = -ENOMEM;
goto err_req;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
index 134ee727e8b7..625b9520d78f 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
@@ -375,9 +375,9 @@ static inline void enc_pools_alloc(void)
{
LASSERT(page_pools.epp_max_pools);
page_pools.epp_pools =
- libcfs_kvzalloc(page_pools.epp_max_pools *
+ kvzalloc(page_pools.epp_max_pools *
sizeof(*page_pools.epp_pools),
- GFP_NOFS);
+ GFP_KERNEL);
}
static inline void enc_pools_free(void)
@@ -530,7 +530,7 @@ EXPORT_SYMBOL(bulk_sec_desc_unpack);
int sptlrpc_get_bulk_checksum(struct ptlrpc_bulk_desc *desc, __u8 alg,
void *buf, int buflen)
{
- struct cfs_crypto_hash_desc *hdesc;
+ struct ahash_request *hdesc;
int hashsize;
unsigned int bufsize;
int i, err;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
index 8d1e0edfcede..2c8bad7b7877 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
@@ -55,7 +55,6 @@ static spinlock_t sec_gc_list_lock;
static LIST_HEAD(sec_gc_ctx_list);
static spinlock_t sec_gc_ctx_list_lock;
-static struct ptlrpc_thread sec_gc_thread;
static atomic_t sec_gc_wait_del = ATOMIC_INIT(0);
void sptlrpc_gc_add_sec(struct ptlrpc_sec *sec)
@@ -139,95 +138,53 @@ static void sec_do_gc(struct ptlrpc_sec *sec)
sec->ps_gc_next = ktime_get_real_seconds() + sec->ps_gc_interval;
}
-static int sec_gc_main(void *arg)
-{
- struct ptlrpc_thread *thread = arg;
- struct l_wait_info lwi;
-
- unshare_fs_struct();
+static void sec_gc_main(struct work_struct *ws);
+static DECLARE_DELAYED_WORK(sec_gc_work, sec_gc_main);
- /* Record that the thread is running */
- thread_set_flags(thread, SVC_RUNNING);
- wake_up(&thread->t_ctl_waitq);
-
- while (1) {
- struct ptlrpc_sec *sec;
+static void sec_gc_main(struct work_struct *ws)
+{
+ struct ptlrpc_sec *sec;
- thread_clear_flags(thread, SVC_SIGNAL);
- sec_process_ctx_list();
+ sec_process_ctx_list();
again:
- /* go through sec list do gc.
- * FIXME here we iterate through the whole list each time which
- * is not optimal. we perhaps want to use balanced binary tree
- * to trace each sec as order of expiry time.
- * another issue here is we wakeup as fixed interval instead of
- * according to each sec's expiry time
+ /* go through sec list do gc.
+ * FIXME here we iterate through the whole list each time which
+ * is not optimal. we perhaps want to use balanced binary tree
+ * to trace each sec as order of expiry time.
+ * another issue here is we wakeup as fixed interval instead of
+ * according to each sec's expiry time
+ */
+ mutex_lock(&sec_gc_mutex);
+ list_for_each_entry(sec, &sec_gc_list, ps_gc_list) {
+ /* if someone is waiting to be deleted, let it
+ * proceed as soon as possible.
*/
- mutex_lock(&sec_gc_mutex);
- list_for_each_entry(sec, &sec_gc_list, ps_gc_list) {
- /* if someone is waiting to be deleted, let it
- * proceed as soon as possible.
- */
- if (atomic_read(&sec_gc_wait_del)) {
- CDEBUG(D_SEC, "deletion pending, start over\n");
- mutex_unlock(&sec_gc_mutex);
- goto again;
- }
-
- sec_do_gc(sec);
+ if (atomic_read(&sec_gc_wait_del)) {
+ CDEBUG(D_SEC, "deletion pending, start over\n");
+ mutex_unlock(&sec_gc_mutex);
+ goto again;
}
- mutex_unlock(&sec_gc_mutex);
-
- /* check ctx list again before sleep */
- sec_process_ctx_list();
- lwi = LWI_TIMEOUT(msecs_to_jiffies(SEC_GC_INTERVAL * MSEC_PER_SEC),
- NULL, NULL);
- l_wait_event(thread->t_ctl_waitq,
- thread_is_stopping(thread) ||
- thread_is_signal(thread),
- &lwi);
-
- if (thread_test_and_clear_flags(thread, SVC_STOPPING))
- break;
+ sec_do_gc(sec);
}
+ mutex_unlock(&sec_gc_mutex);
- thread_set_flags(thread, SVC_STOPPED);
- wake_up(&thread->t_ctl_waitq);
- return 0;
+ /* check ctx list again before sleep */
+ sec_process_ctx_list();
+ schedule_delayed_work(&sec_gc_work, SEC_GC_INTERVAL * HZ);
}
int sptlrpc_gc_init(void)
{
- struct l_wait_info lwi = { 0 };
- struct task_struct *task;
-
mutex_init(&sec_gc_mutex);
spin_lock_init(&sec_gc_list_lock);
spin_lock_init(&sec_gc_ctx_list_lock);
- /* initialize thread control */
- memset(&sec_gc_thread, 0, sizeof(sec_gc_thread));
- init_waitqueue_head(&sec_gc_thread.t_ctl_waitq);
-
- task = kthread_run(sec_gc_main, &sec_gc_thread, "sptlrpc_gc");
- if (IS_ERR(task)) {
- CERROR("can't start gc thread: %ld\n", PTR_ERR(task));
- return PTR_ERR(task);
- }
-
- l_wait_event(sec_gc_thread.t_ctl_waitq,
- thread_is_running(&sec_gc_thread), &lwi);
+ schedule_delayed_work(&sec_gc_work, 0);
return 0;
}
void sptlrpc_gc_fini(void)
{
- struct l_wait_info lwi = { 0 };
-
- thread_set_flags(&sec_gc_thread, SVC_STOPPING);
- wake_up(&sec_gc_thread.t_ctl_waitq);
-
- l_wait_event(sec_gc_thread.t_ctl_waitq,
- thread_is_stopped(&sec_gc_thread), &lwi);
+ cancel_delayed_work_sync(&sec_gc_work);
}
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_null.c b/drivers/staging/lustre/lustre/ptlrpc/sec_null.c
index 80cea0b24693..ecc387d1b9b4 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_null.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_null.c
@@ -158,7 +158,7 @@ int null_alloc_reqbuf(struct ptlrpc_sec *sec,
int alloc_size = size_roundup_power2(msgsize);
LASSERT(!req->rq_pool);
- req->rq_reqbuf = libcfs_kvzalloc(alloc_size, GFP_NOFS);
+ req->rq_reqbuf = kvzalloc(alloc_size, GFP_NOFS);
if (!req->rq_reqbuf)
return -ENOMEM;
@@ -201,7 +201,7 @@ int null_alloc_repbuf(struct ptlrpc_sec *sec,
msgsize = size_roundup_power2(msgsize);
- req->rq_repbuf = libcfs_kvzalloc(msgsize, GFP_NOFS);
+ req->rq_repbuf = kvzalloc(msgsize, GFP_NOFS);
if (!req->rq_repbuf)
return -ENOMEM;
@@ -246,7 +246,7 @@ int null_enlarge_reqbuf(struct ptlrpc_sec *sec,
if (req->rq_reqbuf_len < newmsg_size) {
alloc_size = size_roundup_power2(newmsg_size);
- newbuf = libcfs_kvzalloc(alloc_size, GFP_NOFS);
+ newbuf = kvzalloc(alloc_size, GFP_NOFS);
if (!newbuf)
return -ENOMEM;
@@ -317,7 +317,7 @@ int null_alloc_rs(struct ptlrpc_request *req, int msgsize)
/* pre-allocated */
LASSERT(rs->rs_size >= rs_size);
} else {
- rs = libcfs_kvzalloc(rs_size, GFP_NOFS);
+ rs = kvzalloc(rs_size, GFP_NOFS);
if (!rs)
return -ENOMEM;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c
index 44e34056515b..ec3d9af76b17 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c
@@ -562,7 +562,7 @@ int plain_alloc_reqbuf(struct ptlrpc_sec *sec,
LASSERT(!req->rq_pool);
alloc_len = size_roundup_power2(alloc_len);
- req->rq_reqbuf = libcfs_kvzalloc(alloc_len, GFP_NOFS);
+ req->rq_reqbuf = kvzalloc(alloc_len, GFP_NOFS);
if (!req->rq_reqbuf)
return -ENOMEM;
@@ -620,7 +620,7 @@ int plain_alloc_repbuf(struct ptlrpc_sec *sec,
alloc_len = size_roundup_power2(alloc_len);
- req->rq_repbuf = libcfs_kvzalloc(alloc_len, GFP_NOFS);
+ req->rq_repbuf = kvzalloc(alloc_len, GFP_NOFS);
if (!req->rq_repbuf)
return -ENOMEM;
@@ -671,7 +671,7 @@ int plain_enlarge_reqbuf(struct ptlrpc_sec *sec,
if (req->rq_reqbuf_len < newbuf_size) {
newbuf_size = size_roundup_power2(newbuf_size);
- newbuf = libcfs_kvzalloc(newbuf_size, GFP_NOFS);
+ newbuf = kvzalloc(newbuf_size, GFP_NOFS);
if (!newbuf)
return -ENOMEM;
@@ -808,7 +808,7 @@ int plain_alloc_rs(struct ptlrpc_request *req, int msgsize)
/* pre-allocated */
LASSERT(rs->rs_size >= rs_size);
} else {
- rs = libcfs_kvzalloc(rs_size, GFP_NOFS);
+ rs = kvzalloc(rs_size, GFP_NOFS);
if (!rs)
return -ENOMEM;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c
index 63be6e7273f3..f37364e00dfe 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/service.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/service.c
@@ -83,10 +83,10 @@ ptlrpc_alloc_rqbd(struct ptlrpc_service_part *svcpt)
rqbd->rqbd_cbid.cbid_fn = request_in_callback;
rqbd->rqbd_cbid.cbid_arg = rqbd;
INIT_LIST_HEAD(&rqbd->rqbd_reqs);
- rqbd->rqbd_buffer = libcfs_kvzalloc_cpt(svc->srv_cptable,
- svcpt->scp_cpt,
- svc->srv_buf_size,
- GFP_KERNEL);
+ rqbd->rqbd_buffer = kvzalloc_node(svc->srv_buf_size, GFP_KERNEL,
+ cfs_cpt_spread_node(svc->srv_cptable,
+ svcpt->scp_cpt));
+
if (!rqbd->rqbd_buffer) {
kfree(rqbd);
return NULL;
@@ -726,8 +726,6 @@ static void ptlrpc_server_drop_request(struct ptlrpc_request *req)
struct ptlrpc_service_part *svcpt = rqbd->rqbd_svcpt;
struct ptlrpc_service *svc = svcpt->scp_service;
int refcount;
- struct list_head *tmp;
- struct list_head *nxt;
if (!atomic_dec_and_test(&req->rq_refcount))
return;
@@ -776,9 +774,7 @@ static void ptlrpc_server_drop_request(struct ptlrpc_request *req)
/* remove rqbd's reqs from svc's req history while
* I've got the service lock
*/
- list_for_each(tmp, &rqbd->rqbd_reqs) {
- req = list_entry(tmp, struct ptlrpc_request,
- rq_list);
+ list_for_each_entry(req, &rqbd->rqbd_reqs, rq_list) {
/* Track the highest culled req seq */
if (req->rq_history_seq >
svcpt->scp_hist_seq_culled) {
@@ -790,10 +786,9 @@ static void ptlrpc_server_drop_request(struct ptlrpc_request *req)
spin_unlock(&svcpt->scp_lock);
- list_for_each_safe(tmp, nxt, &rqbd->rqbd_reqs) {
- req = list_entry(rqbd->rqbd_reqs.next,
- struct ptlrpc_request,
- rq_list);
+ while ((req = list_first_entry_or_null(
+ &rqbd->rqbd_reqs,
+ struct ptlrpc_request, rq_list))) {
list_del(&req->rq_list);
ptlrpc_server_free_request(req);
}
@@ -1068,7 +1063,7 @@ static int ptlrpc_at_send_early_reply(struct ptlrpc_request *req)
reqcopy = ptlrpc_request_cache_alloc(GFP_NOFS);
if (!reqcopy)
return -ENOMEM;
- reqmsg = libcfs_kvzalloc(req->rq_reqlen, GFP_NOFS);
+ reqmsg = kvzalloc(req->rq_reqlen, GFP_NOFS);
if (!reqmsg) {
rc = -ENOMEM;
goto out_free;
@@ -1897,15 +1892,6 @@ ptlrpc_check_rqbd_pool(struct ptlrpc_service_part *svcpt)
}
}
-static int
-ptlrpc_retry_rqbds(void *arg)
-{
- struct ptlrpc_service_part *svcpt = arg;
-
- svcpt->scp_rqbd_timeout = 0;
- return -ETIMEDOUT;
-}
-
static inline int
ptlrpc_threads_enough(struct ptlrpc_service_part *svcpt)
{
@@ -1968,13 +1954,17 @@ ptlrpc_server_request_incoming(struct ptlrpc_service_part *svcpt)
return !list_empty(&svcpt->scp_req_incoming);
}
+/* We perfer lifo queuing, but kernel doesn't provide that yet. */
+#ifndef wait_event_idle_exclusive_lifo
+#define wait_event_idle_exclusive_lifo wait_event_idle_exclusive
+#define wait_event_idle_exclusive_lifo_timeout wait_event_idle_exclusive_timeout
+#endif
+
static __attribute__((__noinline__)) int
ptlrpc_wait_event(struct ptlrpc_service_part *svcpt,
struct ptlrpc_thread *thread)
{
/* Don't exit while there are replies to be handled */
- struct l_wait_info lwi = LWI_TIMEOUT(svcpt->scp_rqbd_timeout,
- ptlrpc_retry_rqbds, svcpt);
/* XXX: Add this back when libcfs watchdog is merged upstream
lc_watchdog_disable(thread->t_watchdog);
@@ -1982,13 +1972,25 @@ ptlrpc_wait_event(struct ptlrpc_service_part *svcpt,
cond_resched();
- l_wait_event_exclusive_head(svcpt->scp_waitq,
- ptlrpc_thread_stopping(thread) ||
- ptlrpc_server_request_incoming(svcpt) ||
- ptlrpc_server_request_pending(svcpt,
- false) ||
- ptlrpc_rqbd_pending(svcpt) ||
- ptlrpc_at_check(svcpt), &lwi);
+ if (svcpt->scp_rqbd_timeout == 0)
+ wait_event_idle_exclusive_lifo(
+ svcpt->scp_waitq,
+ ptlrpc_thread_stopping(thread) ||
+ ptlrpc_server_request_incoming(svcpt) ||
+ ptlrpc_server_request_pending(svcpt,
+ false) ||
+ ptlrpc_rqbd_pending(svcpt) ||
+ ptlrpc_at_check(svcpt));
+ else if (0 == wait_event_idle_exclusive_lifo_timeout(
+ svcpt->scp_waitq,
+ ptlrpc_thread_stopping(thread) ||
+ ptlrpc_server_request_incoming(svcpt) ||
+ ptlrpc_server_request_pending(svcpt,
+ false) ||
+ ptlrpc_rqbd_pending(svcpt) ||
+ ptlrpc_at_check(svcpt),
+ svcpt->scp_rqbd_timeout))
+ svcpt->scp_rqbd_timeout = 0;
if (ptlrpc_thread_stopping(thread))
return -EINTR;
@@ -2044,7 +2046,7 @@ static int ptlrpc_main(void *arg)
goto out;
}
- env = kzalloc(sizeof(*env), GFP_NOFS);
+ env = kzalloc(sizeof(*env), GFP_KERNEL);
if (!env) {
rc = -ENOMEM;
goto out_srv_fini;
@@ -2070,7 +2072,7 @@ static int ptlrpc_main(void *arg)
}
/* Alloc reply state structure for this one */
- rs = libcfs_kvzalloc(svc->srv_max_reply_size, GFP_NOFS);
+ rs = kvzalloc(svc->srv_max_reply_size, GFP_KERNEL);
if (!rs) {
rc = -ENOMEM;
goto out_srv_fini;
@@ -2149,7 +2151,7 @@ static int ptlrpc_main(void *arg)
* Wait for a timeout (unless something else
* happens) before I try again
*/
- svcpt->scp_rqbd_timeout = cfs_time_seconds(1) / 10;
+ svcpt->scp_rqbd_timeout = HZ / 10;
CDEBUG(D_RPCTRACE, "Posted buffers: %d\n",
svcpt->scp_nrqbds_posted);
}
@@ -2233,7 +2235,7 @@ static int ptlrpc_hr_main(void *arg)
wake_up(&ptlrpc_hr.hr_waitq);
while (!ptlrpc_hr.hr_stopping) {
- l_wait_condition(hrt->hrt_waitq, hrt_dont_sleep(hrt, &replies));
+ wait_event_idle(hrt->hrt_waitq, hrt_dont_sleep(hrt, &replies));
while (!list_empty(&replies)) {
struct ptlrpc_reply_state *rs;
@@ -2312,7 +2314,6 @@ static int ptlrpc_start_hr_threads(void)
static void ptlrpc_svcpt_stop_threads(struct ptlrpc_service_part *svcpt)
{
- struct l_wait_info lwi = { 0 };
struct ptlrpc_thread *thread;
LIST_HEAD(zombie);
@@ -2341,8 +2342,8 @@ static void ptlrpc_svcpt_stop_threads(struct ptlrpc_service_part *svcpt)
CDEBUG(D_INFO, "waiting for stopping-thread %s #%u\n",
svcpt->scp_service->srv_thread_name, thread->t_id);
- l_wait_event(thread->t_ctl_waitq,
- thread_is_stopped(thread), &lwi);
+ wait_event_idle(thread->t_ctl_waitq,
+ thread_is_stopped(thread));
spin_lock(&svcpt->scp_lock);
}
@@ -2403,7 +2404,6 @@ int ptlrpc_start_threads(struct ptlrpc_service *svc)
int ptlrpc_start_thread(struct ptlrpc_service_part *svcpt, int wait)
{
- struct l_wait_info lwi = { 0 };
struct ptlrpc_thread *thread;
struct ptlrpc_service *svc;
struct task_struct *task;
@@ -2499,9 +2499,8 @@ int ptlrpc_start_thread(struct ptlrpc_service_part *svcpt, int wait)
if (!wait)
return 0;
- l_wait_event(thread->t_ctl_waitq,
- thread_is_running(thread) || thread_is_stopped(thread),
- &lwi);
+ wait_event_idle(thread->t_ctl_waitq,
+ thread_is_running(thread) || thread_is_stopped(thread));
rc = thread_is_stopped(thread) ? thread->t_id : 0;
return rc;
@@ -2591,13 +2590,12 @@ static void ptlrpc_wait_replies(struct ptlrpc_service_part *svcpt)
{
while (1) {
int rc;
- struct l_wait_info lwi = LWI_TIMEOUT(cfs_time_seconds(10),
- NULL, NULL);
- rc = l_wait_event(svcpt->scp_waitq,
- atomic_read(&svcpt->scp_nreps_difficult) == 0,
- &lwi);
- if (rc == 0)
+ rc = wait_event_idle_timeout(
+ svcpt->scp_waitq,
+ atomic_read(&svcpt->scp_nreps_difficult) == 0,
+ 10 * HZ);
+ if (rc > 0)
break;
CWARN("Unexpectedly long timeout %s %p\n",
svcpt->scp_service->srv_name, svcpt->scp_service);
@@ -2622,7 +2620,7 @@ ptlrpc_service_unlink_rqbd(struct ptlrpc_service *svc)
{
struct ptlrpc_service_part *svcpt;
struct ptlrpc_request_buffer_desc *rqbd;
- struct l_wait_info lwi;
+ int cnt;
int rc;
int i;
@@ -2662,12 +2660,13 @@ ptlrpc_service_unlink_rqbd(struct ptlrpc_service *svc)
* the HUGE timeout lets us CWARN for visibility
* of sluggish LNDs
*/
- lwi = LWI_TIMEOUT_INTERVAL(
- cfs_time_seconds(LONG_UNLINK),
- cfs_time_seconds(1), NULL, NULL);
- rc = l_wait_event(svcpt->scp_waitq,
- svcpt->scp_nrqbds_posted == 0, &lwi);
- if (rc == -ETIMEDOUT) {
+ cnt = 0;
+ while (cnt < LONG_UNLINK &&
+ (rc = wait_event_idle_timeout(svcpt->scp_waitq,
+ svcpt->scp_nrqbds_posted == 0,
+ HZ)) == 0)
+ cnt++;
+ if (rc == 0) {
CWARN("Service %s waiting for request buffers\n",
svcpt->scp_service->srv_name);
}
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index e68e1d343d53..4c495a10025c 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -23,12 +23,14 @@ source "drivers/staging/media/atomisp/Kconfig"
source "drivers/staging/media/bcm2048/Kconfig"
-source "drivers/staging/media/cxd2099/Kconfig"
-
source "drivers/staging/media/davinci_vpfe/Kconfig"
source "drivers/staging/media/imx/Kconfig"
+source "drivers/staging/media/imx074/Kconfig"
+
+source "drivers/staging/media/mt9t031/Kconfig"
+
source "drivers/staging/media/omap4iss/Kconfig"
source "drivers/staging/media/tegra-vde/Kconfig"
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 59a47f69884f..61a5765cb98f 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -1,7 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_I2C_BCM2048) += bcm2048/
-obj-$(CONFIG_DVB_CXD2099) += cxd2099/
obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/
+obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074/
+obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031/
obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/
obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/
obj-$(CONFIG_INTEL_ATOMISP) += atomisp/
diff --git a/drivers/staging/media/atomisp/i2c/Kconfig b/drivers/staging/media/atomisp/i2c/Kconfig
index db054d3c7ed6..f7f7177b9b37 100644
--- a/drivers/staging/media/atomisp/i2c/Kconfig
+++ b/drivers/staging/media/atomisp/i2c/Kconfig
@@ -28,18 +28,6 @@ config VIDEO_ATOMISP_GC2235
It currently only works with the atomisp driver.
-config VIDEO_ATOMISP_OV8858
- tristate "Omnivision ov8858 sensor support"
- depends on ACPI
- depends on I2C && VIDEO_V4L2 && VIDEO_ATOMISP
- ---help---
- This is a Video4Linux2 sensor-level driver for the Omnivision
- ov8858 RAW sensor.
-
- OV8858 is a 8M raw sensor.
-
- It currently only works with the atomisp driver.
-
config VIDEO_ATOMISP_MSRLIST_HELPER
tristate "Helper library to load, parse and apply large register lists."
depends on I2C
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
index 61b7598469eb..93753cb96180 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
@@ -1204,57 +1204,6 @@ fail_power_off:
return ret;
}
-static int gc0310_g_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *param)
-{
- struct gc0310_device *dev = to_gc0310_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!param)
- return -EINVAL;
-
- if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dev_err(&client->dev, "unsupported buffer type.\n");
- return -EINVAL;
- }
-
- memset(param, 0, sizeof(*param));
- param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
- param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- param->parm.capture.timeperframe.numerator = 1;
- param->parm.capture.capturemode = dev->run_mode;
- param->parm.capture.timeperframe.denominator =
- gc0310_res[dev->fmt_idx].fps;
- }
- return 0;
-}
-
-static int gc0310_s_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *param)
-{
- struct gc0310_device *dev = to_gc0310_sensor(sd);
- dev->run_mode = param->parm.capture.capturemode;
-
- mutex_lock(&dev->input_lock);
- switch (dev->run_mode) {
- case CI_MODE_VIDEO:
- gc0310_res = gc0310_res_video;
- N_RES = N_RES_VIDEO;
- break;
- case CI_MODE_STILL_CAPTURE:
- gc0310_res = gc0310_res_still;
- N_RES = N_RES_STILL;
- break;
- default:
- gc0310_res = gc0310_res_preview;
- N_RES = N_RES_PREVIEW;
- }
- mutex_unlock(&dev->input_lock);
- return 0;
-}
-
static int gc0310_g_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *interval)
{
@@ -1313,8 +1262,6 @@ static const struct v4l2_subdev_sensor_ops gc0310_sensor_ops = {
static const struct v4l2_subdev_video_ops gc0310_video_ops = {
.s_stream = gc0310_s_stream,
- .g_parm = gc0310_g_parm,
- .s_parm = gc0310_s_parm,
.g_frame_interval = gc0310_g_frame_interval,
};
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
index d8de46da64ae..93f9c618f3d8 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
@@ -944,57 +944,6 @@ fail_power_off:
return ret;
}
-static int gc2235_g_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *param)
-{
- struct gc2235_device *dev = to_gc2235_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!param)
- return -EINVAL;
-
- if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dev_err(&client->dev, "unsupported buffer type.\n");
- return -EINVAL;
- }
-
- memset(param, 0, sizeof(*param));
- param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
- param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- param->parm.capture.timeperframe.numerator = 1;
- param->parm.capture.capturemode = dev->run_mode;
- param->parm.capture.timeperframe.denominator =
- gc2235_res[dev->fmt_idx].fps;
- }
- return 0;
-}
-
-static int gc2235_s_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *param)
-{
- struct gc2235_device *dev = to_gc2235_sensor(sd);
- dev->run_mode = param->parm.capture.capturemode;
-
- mutex_lock(&dev->input_lock);
- switch (dev->run_mode) {
- case CI_MODE_VIDEO:
- gc2235_res = gc2235_res_video;
- N_RES = N_RES_VIDEO;
- break;
- case CI_MODE_STILL_CAPTURE:
- gc2235_res = gc2235_res_still;
- N_RES = N_RES_STILL;
- break;
- default:
- gc2235_res = gc2235_res_preview;
- N_RES = N_RES_PREVIEW;
- }
- mutex_unlock(&dev->input_lock);
- return 0;
-}
-
static int gc2235_g_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *interval)
{
@@ -1052,8 +1001,6 @@ static const struct v4l2_subdev_sensor_ops gc2235_sensor_ops = {
static const struct v4l2_subdev_video_ops gc2235_video_ops = {
.s_stream = gc2235_s_stream,
- .g_parm = gc2235_g_parm,
- .s_parm = gc2235_s_parm,
.g_frame_interval = gc2235_g_frame_interval,
};
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
index df253a557c76..834fba8c4fa0 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
@@ -1684,11 +1684,6 @@ static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value)
return !!err;
}
-static int mt9m114_s_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *param)
-{
- return 0;
-}
static int mt9m114_g_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *interval)
@@ -1781,7 +1776,6 @@ static int mt9m114_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
}
static const struct v4l2_subdev_video_ops mt9m114_video_ops = {
- .s_parm = mt9m114_s_parm,
.s_stream = mt9m114_s_stream,
.g_frame_interval = mt9m114_g_frame_interval,
};
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
index 84f8d33ce2d1..11412061c40e 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
@@ -1280,60 +1280,6 @@ fail_power_off:
return ret;
}
-static int ov2680_g_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *param)
-{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!param)
- return -EINVAL;
-
- if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dev_err(&client->dev, "unsupported buffer type.\n");
- return -EINVAL;
- }
-
- memset(param, 0, sizeof(*param));
- param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
- param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- param->parm.capture.timeperframe.numerator = 1;
- param->parm.capture.capturemode = dev->run_mode;
- param->parm.capture.timeperframe.denominator =
- ov2680_res[dev->fmt_idx].fps;
- }
- return 0;
-}
-
-static int ov2680_s_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *param)
-{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- dev->run_mode = param->parm.capture.capturemode;
-
- v4l2_info(client, "\n%s:run_mode :%x\n", __func__, dev->run_mode);
-
- mutex_lock(&dev->input_lock);
- switch (dev->run_mode) {
- case CI_MODE_VIDEO:
- ov2680_res = ov2680_res_video;
- N_RES = N_RES_VIDEO;
- break;
- case CI_MODE_STILL_CAPTURE:
- ov2680_res = ov2680_res_still;
- N_RES = N_RES_STILL;
- break;
- default:
- ov2680_res = ov2680_res_preview;
- N_RES = N_RES_PREVIEW;
- }
- mutex_unlock(&dev->input_lock);
- return 0;
-}
-
static int ov2680_g_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *interval)
{
@@ -1387,8 +1333,6 @@ static int ov2680_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
static const struct v4l2_subdev_video_ops ov2680_video_ops = {
.s_stream = ov2680_s_stream,
- .g_parm = ov2680_g_parm,
- .s_parm = ov2680_s_parm,
.g_frame_interval = ov2680_g_frame_interval,
};
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
index 2b6ae0faf972..e59358ac89ce 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
@@ -1083,57 +1083,6 @@ fail_power_off:
return ret;
}
-static int ov2722_g_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *param)
-{
- struct ov2722_device *dev = to_ov2722_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!param)
- return -EINVAL;
-
- if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dev_err(&client->dev, "unsupported buffer type.\n");
- return -EINVAL;
- }
-
- memset(param, 0, sizeof(*param));
- param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
- param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- param->parm.capture.timeperframe.numerator = 1;
- param->parm.capture.capturemode = dev->run_mode;
- param->parm.capture.timeperframe.denominator =
- ov2722_res[dev->fmt_idx].fps;
- }
- return 0;
-}
-
-static int ov2722_s_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *param)
-{
- struct ov2722_device *dev = to_ov2722_sensor(sd);
- dev->run_mode = param->parm.capture.capturemode;
-
- mutex_lock(&dev->input_lock);
- switch (dev->run_mode) {
- case CI_MODE_VIDEO:
- ov2722_res = ov2722_res_video;
- N_RES = N_RES_VIDEO;
- break;
- case CI_MODE_STILL_CAPTURE:
- ov2722_res = ov2722_res_still;
- N_RES = N_RES_STILL;
- break;
- default:
- ov2722_res = ov2722_res_preview;
- N_RES = N_RES_PREVIEW;
- }
- mutex_unlock(&dev->input_lock);
- return 0;
-}
-
static int ov2722_g_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *interval)
{
@@ -1192,8 +1141,6 @@ static const struct v4l2_subdev_sensor_ops ov2722_sensor_ops = {
static const struct v4l2_subdev_video_ops ov2722_video_ops = {
.s_stream = ov2722_s_stream,
- .g_parm = ov2722_g_parm,
- .s_parm = ov2722_s_parm,
.g_frame_interval = ov2722_g_frame_interval,
};
diff --git a/drivers/staging/media/atomisp/i2c/gc0310.h b/drivers/staging/media/atomisp/i2c/gc0310.h
index c422d0398fc7..af6b11f6e5e7 100644
--- a/drivers/staging/media/atomisp/i2c/gc0310.h
+++ b/drivers/staging/media/atomisp/i2c/gc0310.h
@@ -150,7 +150,6 @@ struct gc0310_device {
struct camera_sensor_platform_data *platform_data;
int vt_pix_clk_freq_mhz;
int fmt_idx;
- int run_mode;
u8 res;
u8 type;
};
@@ -400,48 +399,6 @@ struct gc0310_resolution gc0310_res_preview[] = {
};
#define N_RES_PREVIEW (ARRAY_SIZE(gc0310_res_preview))
-struct gc0310_resolution gc0310_res_still[] = {
- {
- .desc = "gc0310_VGA_30fps",
- .width = 656, // 648,
- .height = 496, // 488,
- .fps = 30,
- //.pix_clk_freq = 73,
- .used = 0,
-#if 0
- .pixels_per_line = 0x0314,
- .lines_per_frame = 0x0213,
-#endif
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
- .skip_frames = 2,
- .regs = gc0310_VGA_30fps,
- },
-};
-#define N_RES_STILL (ARRAY_SIZE(gc0310_res_still))
-
-struct gc0310_resolution gc0310_res_video[] = {
- {
- .desc = "gc0310_VGA_30fps",
- .width = 656, // 648,
- .height = 496, // 488,
- .fps = 30,
- //.pix_clk_freq = 73,
- .used = 0,
-#if 0
- .pixels_per_line = 0x0314,
- .lines_per_frame = 0x0213,
-#endif
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
- .skip_frames = 2,
- .regs = gc0310_VGA_30fps,
- },
-};
-#define N_RES_VIDEO (ARRAY_SIZE(gc0310_res_video))
-
static struct gc0310_resolution *gc0310_res = gc0310_res_preview;
static unsigned long N_RES = N_RES_PREVIEW;
#endif
diff --git a/drivers/staging/media/atomisp/i2c/gc2235.h b/drivers/staging/media/atomisp/i2c/gc2235.h
index 3c30a05c3991..0e805bcfa4d8 100644
--- a/drivers/staging/media/atomisp/i2c/gc2235.h
+++ b/drivers/staging/media/atomisp/i2c/gc2235.h
@@ -156,7 +156,6 @@ struct gc2235_device {
struct camera_sensor_platform_data *platform_data;
int vt_pix_clk_freq_mhz;
int fmt_idx;
- int run_mode;
u8 res;
u8 type;
};
@@ -575,6 +574,11 @@ static struct gc2235_resolution gc2235_res_preview[] = {
};
#define N_RES_PREVIEW (ARRAY_SIZE(gc2235_res_preview))
+/*
+ * Disable non-preview configurations until the configuration selection is
+ * improved.
+ */
+#if 0
static struct gc2235_resolution gc2235_res_still[] = {
{
.desc = "gc2235_1600_900_30fps",
@@ -659,6 +663,7 @@ static struct gc2235_resolution gc2235_res_video[] = {
};
#define N_RES_VIDEO (ARRAY_SIZE(gc2235_res_video))
+#endif
static struct gc2235_resolution *gc2235_res = gc2235_res_preview;
static unsigned long N_RES = N_RES_PREVIEW;
diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h
index 03f75dd80f87..cb38e6e79409 100644
--- a/drivers/staging/media/atomisp/i2c/ov2680.h
+++ b/drivers/staging/media/atomisp/i2c/ov2680.h
@@ -850,74 +850,6 @@ struct ov2680_format {
};
#define N_RES_PREVIEW (ARRAY_SIZE(ov2680_res_preview))
-static struct ov2680_resolution ov2680_res_still[] = {
- {
- .desc = "ov2680_1616x1216_30fps",
- .width = 1616,
- .height = 1216,
- .pix_clk_freq = 66,
- .fps = 30,
- .used = 0,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_1616x1216_30fps,
- },
- {
- .desc = "ov2680_1616x916_30fps",
- .width = 1616,
- .height = 916,
- .fps = 30,
- .pix_clk_freq = 66,
- .used = 0,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_1616x916_30fps,
- },
-};
-#define N_RES_STILL (ARRAY_SIZE(ov2680_res_still))
-
-static struct ov2680_resolution ov2680_res_video[] = {
- {
- .desc = "ov2680_1616x1216_30fps",
- .width = 1616,
- .height = 1216,
- .pix_clk_freq = 66,
- .fps = 30,
- .used = 0,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_1616x1216_30fps,
- },
- {
- .desc = "ov2680_720p_30fps",
- .width = 1616,
- .height = 916,
- .fps = 30,
- .pix_clk_freq = 66,
- .used = 0,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_1616x916_30fps,
- },
-};
-#define N_RES_VIDEO (ARRAY_SIZE(ov2680_res_video))
-
static struct ov2680_resolution *ov2680_res = ov2680_res_preview;
static unsigned long N_RES = N_RES_PREVIEW;
diff --git a/drivers/staging/media/atomisp/i2c/ov2722.h b/drivers/staging/media/atomisp/i2c/ov2722.h
index d8a973d71699..028b04aaaa8f 100644
--- a/drivers/staging/media/atomisp/i2c/ov2722.h
+++ b/drivers/staging/media/atomisp/i2c/ov2722.h
@@ -1148,6 +1148,11 @@ struct ov2722_resolution ov2722_res_preview[] = {
};
#define N_RES_PREVIEW (ARRAY_SIZE(ov2722_res_preview))
+/*
+ * Disable non-preview configurations until the configuration selection is
+ * improved.
+ */
+#if 0
struct ov2722_resolution ov2722_res_still[] = {
{
.desc = "ov2722_480P_30fps",
@@ -1250,6 +1255,7 @@ struct ov2722_resolution ov2722_res_video[] = {
},
};
#define N_RES_VIDEO (ARRAY_SIZE(ov2722_res_video))
+#endif
static struct ov2722_resolution *ov2722_res = ov2722_res_preview;
static unsigned long N_RES = N_RES_PREVIEW;
diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
index 40d01bf4bf28..30a735e59e54 100644
--- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
+++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
@@ -1805,58 +1805,6 @@ fail_power_off:
return ret;
}
-static int ov5693_g_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *param)
-{
- struct ov5693_device *dev = to_ov5693_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!param)
- return -EINVAL;
-
- if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dev_err(&client->dev, "unsupported buffer type.\n");
- return -EINVAL;
- }
-
- memset(param, 0, sizeof(*param));
- param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
- param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- param->parm.capture.timeperframe.numerator = 1;
- param->parm.capture.capturemode = dev->run_mode;
- param->parm.capture.timeperframe.denominator =
- ov5693_res[dev->fmt_idx].fps;
- }
- return 0;
-}
-
-static int ov5693_s_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *param)
-{
- struct ov5693_device *dev = to_ov5693_sensor(sd);
-
- dev->run_mode = param->parm.capture.capturemode;
-
- mutex_lock(&dev->input_lock);
- switch (dev->run_mode) {
- case CI_MODE_VIDEO:
- ov5693_res = ov5693_res_video;
- N_RES = N_RES_VIDEO;
- break;
- case CI_MODE_STILL_CAPTURE:
- ov5693_res = ov5693_res_still;
- N_RES = N_RES_STILL;
- break;
- default:
- ov5693_res = ov5693_res_preview;
- N_RES = N_RES_PREVIEW;
- }
- mutex_unlock(&dev->input_lock);
- return 0;
-}
-
static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *interval)
{
@@ -1899,8 +1847,6 @@ static int ov5693_enum_frame_size(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops ov5693_video_ops = {
.s_stream = ov5693_s_stream,
- .g_parm = ov5693_g_parm,
- .s_parm = ov5693_s_parm,
.g_frame_interval = ov5693_g_frame_interval,
};
@@ -1947,7 +1893,7 @@ static int ov5693_probe(struct i2c_client *client)
struct ov5693_device *dev;
int i2c;
int ret = 0;
- void *pdata = client->dev.platform_data;
+ void *pdata;
unsigned int i;
/*
diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h
index 68cfcb4a6c3c..6d27dd849a62 100644
--- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h
+++ b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h
@@ -1147,6 +1147,11 @@ struct ov5693_resolution ov5693_res_preview[] = {
};
#define N_RES_PREVIEW (ARRAY_SIZE(ov5693_res_preview))
+/*
+ * Disable non-preview configurations until the configuration selection is
+ * improved.
+ */
+#if 0
struct ov5693_resolution ov5693_res_still[] = {
{
.desc = "ov5693_736x496_30fps",
@@ -1364,6 +1369,7 @@ struct ov5693_resolution ov5693_res_video[] = {
},
};
#define N_RES_VIDEO (ARRAY_SIZE(ov5693_res_video))
+#endif
static struct ov5693_resolution *ov5693_res = ov5693_res_preview;
static unsigned long N_RES = N_RES_PREVIEW;
diff --git a/drivers/staging/media/atomisp/i2c/ov8858.c b/drivers/staging/media/atomisp/i2c/ov8858.c
deleted file mode 100644
index 3cf8c710ac65..000000000000
--- a/drivers/staging/media/atomisp/i2c/ov8858.c
+++ /dev/null
@@ -1,2169 +0,0 @@
-/*
- * Support for OmniVision ov8858 camera sensor.
- *
- * Copyright (c) 2014 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as 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/delay.h>
-#include <linux/module.h>
-#include <media/v4l2-device.h>
-#include <linux/acpi.h>
-#include "../include/linux/atomisp_gmin_platform.h"
-#ifdef CONFIG_PLATFORM_BTNS
-#include "ov8858_btns.h"
-#else
-#include "ov8858.h"
-#endif
-static int ov8858_i2c_read(struct i2c_client *client, u16 len, u16 addr,
- u8 *buf)
-{
- struct i2c_msg msg[2];
- u8 address[2];
- int err;
-
- if (!client->adapter) {
- dev_err(&client->dev, "%s error, no adapter\n", __func__);
- return -ENODEV;
- }
-
- dev_dbg(&client->dev, "%s: len = %d, addr = 0x%04x\n",
- __func__, len, addr);
-
- memset(msg, 0, sizeof(msg));
-
- address[0] = (addr >> 8) & 0xff;
- address[1] = addr & 0xff;
-
- msg[0].addr = client->addr;
- msg[0].flags = 0;
- msg[0].len = I2C_MSG_LENGTH;
- msg[0].buf = address;
-
- msg[1].addr = client->addr;
- msg[1].len = len;
- msg[1].flags = I2C_M_RD;
- msg[1].buf = buf;
-
- err = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
- if (err != 2) {
- if (err >= 0)
- err = -EIO;
- goto error;
- }
-
- return 0;
-error:
- dev_err(&client->dev, "reading from address 0x%x error %d", addr, err);
- return err;
-}
-
-static int ov8858_read_reg(struct i2c_client *client, u16 type, u16 reg,
- u16 *val)
-{
- u8 data[OV8858_SHORT_MAX];
- int err;
-
- dev_dbg(&client->dev, "%s: type = %d, reg = 0x%04x\n",
- __func__, type, reg);
-
- /* read only 8 and 16 bit values */
- if (type != OV8858_8BIT && type != OV8858_16BIT) {
- dev_err(&client->dev, "%s error, invalid data length\n",
- __func__);
- return -EINVAL;
- }
-
- memset(data, 0, sizeof(data));
-
- err = ov8858_i2c_read(client, type, reg, data);
- if (err)
- goto error;
-
- /* high byte comes first */
- if (type == OV8858_8BIT)
- *val = (u8)data[0];
- else
- *val = data[0] << 8 | data[1];
-
- dev_dbg(&client->dev, "%s: val = 0x%04x\n", __func__, *val);
-
- return 0;
-
-error:
- dev_err(&client->dev, "read from offset 0x%x error %d", reg, err);
- return err;
-}
-
-static int ov8858_i2c_write(struct i2c_client *client, u16 len, u8 *data)
-{
- struct i2c_msg msg;
- const int num_msg = 1;
- int ret;
-
- msg.addr = client->addr;
- msg.flags = 0;
- msg.len = len;
- msg.buf = data;
-
- ret = i2c_transfer(client->adapter, &msg, 1);
-
- return ret == num_msg ? 0 : -EIO;
-}
-
-static int
-ov8858_write_reg(struct i2c_client *client, u16 data_length, u16 reg, u16 val)
-{
- int ret;
- unsigned char data[4] = {0};
- u16 *wreg;
- const u16 len = data_length + sizeof(u16); /* 16-bit address + data */
-
- dev_dbg(&client->dev,
- "%s: data_length = %d, reg = 0x%04x, val = 0x%04x\n",
- __func__, data_length, reg, val);
-
- if (!client->adapter) {
- dev_err(&client->dev, "%s error, no adapter\n", __func__);
- return -ENODEV;
- }
-
- if (data_length != OV8858_8BIT && data_length != OV8858_16BIT) {
- dev_err(&client->dev, "%s error, invalid length\n", __func__);
- return -EINVAL;
- }
-
- /* high byte goes out first */
- wreg = (u16 *)data;
- *wreg = cpu_to_be16(reg);
-
- if (data_length == OV8858_8BIT) {
- data[2] = (u8)(val);
- } else {
- /* OV8858_16BIT */
- u16 *wdata = (u16 *)&data[2];
- *wdata = be16_to_cpu(val);
- }
-
- ret = ov8858_i2c_write(client, len, data);
- if (ret)
- dev_err(&client->dev,
- "write error: wrote 0x%x to offset 0x%x error %d",
- val, reg, ret);
-
- return ret;
-}
-
-/*
- * ov8858_write_reg_array - Initializes a list of registers
- * @client: i2c driver client structure
- * @reglist: list of registers to be written
- *
- * This function initializes a list of registers. When consecutive addresses
- * are found in a row on the list, this function creates a buffer and sends
- * consecutive data in a single i2c_transfer().
- *
- * __ov8858_flush_reg_array(), __ov8858_buf_reg_array() and
- * __ov8858_write_reg_is_consecutive() are internal functions to
- * ov8858_write_reg_array() and should be not used anywhere else.
- *
- */
-static int __ov8858_flush_reg_array(struct i2c_client *client,
- struct ov8858_write_ctrl *ctrl)
-{
- u16 size;
- if (ctrl->index == 0)
- return 0;
-
- size = sizeof(u16) + ctrl->index; /* 16-bit address + data */
- ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr);
- ctrl->index = 0;
-
- return ov8858_i2c_write(client, size, (u8 *)&ctrl->buffer);
-}
-
-static int __ov8858_buf_reg_array(struct i2c_client *client,
- struct ov8858_write_ctrl *ctrl,
- const struct ov8858_reg *next)
-{
- int size;
- u16 *data16;
-
- switch (next->type) {
- case OV8858_8BIT:
- size = 1;
- ctrl->buffer.data[ctrl->index] = (u8)next->val;
- break;
- case OV8858_16BIT:
- size = 2;
- data16 = (u16 *)&ctrl->buffer.data[ctrl->index];
- *data16 = cpu_to_be16((u16)next->val);
- break;
- default:
- return -EINVAL;
- }
-
- /* When first item is added, we need to store its starting address */
- if (ctrl->index == 0)
- ctrl->buffer.addr = next->sreg;
-
- ctrl->index += size;
-
- /*
- * Buffer cannot guarantee free space for u32? Better flush it to avoid
- * possible lack of memory for next item.
- */
- if (ctrl->index + sizeof(u16) >= OV8858_MAX_WRITE_BUF_SIZE)
- __ov8858_flush_reg_array(client, ctrl);
-
- return 0;
-}
-
-static int
-__ov8858_write_reg_is_consecutive(struct i2c_client *client,
- struct ov8858_write_ctrl *ctrl,
- const struct ov8858_reg *next)
-{
- if (ctrl->index == 0)
- return 1;
-
- return ctrl->buffer.addr + ctrl->index == next->sreg;
-}
-
-static int ov8858_write_reg_array(struct i2c_client *client,
- const struct ov8858_reg *reglist)
-{
- const struct ov8858_reg *next = reglist;
- struct ov8858_write_ctrl ctrl;
- int err;
-
- ctrl.index = 0;
- for (; next->type != OV8858_TOK_TERM; next++) {
- switch (next->type & OV8858_TOK_MASK) {
- case OV8858_TOK_DELAY:
- err = __ov8858_flush_reg_array(client, &ctrl);
- if (err)
- return err;
- msleep(next->val);
- break;
-
- default:
- /*
- * If next address is not consecutive, data needs to be
- * flushed before proceeding
- */
- if (!__ov8858_write_reg_is_consecutive(client,
- &ctrl, next)) {
- err = __ov8858_flush_reg_array(client, &ctrl);
- if (err)
- return err;
- }
- err = __ov8858_buf_reg_array(client, &ctrl, next);
- if (err) {
- dev_err(&client->dev, "%s: write error\n",
- __func__);
- return err;
- }
- break;
- }
- }
-
- return __ov8858_flush_reg_array(client, &ctrl);
-}
-
-static int __ov8858_min_fps_diff(int fps,
- const struct ov8858_fps_setting *fps_list)
-{
- int diff = INT_MAX;
- int i;
-
- if (fps == 0)
- return 0;
-
- for (i = 0; i < MAX_FPS_OPTIONS_SUPPORTED; i++) {
- if (!fps_list[i].fps)
- break;
- if (abs(fps_list[i].fps - fps) < diff)
- diff = abs(fps_list[i].fps - fps);
- }
-
- return diff;
-}
-
-static int __ov8858_nearest_fps_index(int fps,
- const struct ov8858_fps_setting *fps_list)
-{
- int fps_index = 0;
- int i;
-
- for (i = 0; i < MAX_FPS_OPTIONS_SUPPORTED; i++) {
- if (!fps_list[i].fps)
- break;
- if (abs(fps_list[i].fps - fps)
- < abs(fps_list[fps_index].fps - fps))
- fps_index = i;
- }
- return fps_index;
-}
-
-static int __ov8858_update_frame_timing(struct v4l2_subdev *sd,
- u16 *hts, u16 *vts)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
-
- dev_dbg(&client->dev, "%s OV8858_TIMING_HTS=0x%04x\n",
- __func__, *hts);
-
- /* HTS = pixel_per_line / 2 */
- ret = ov8858_write_reg(client, OV8858_16BIT,
- OV8858_TIMING_HTS, *hts >> 1);
- if (ret)
- return ret;
- dev_dbg(&client->dev, "%s OV8858_TIMING_VTS=0x%04x\n",
- __func__, *vts);
-
- return ov8858_write_reg(client, OV8858_16BIT, OV8858_TIMING_VTS, *vts);
-}
-
-static int __ov8858_set_exposure(struct v4l2_subdev *sd, int exposure, int gain,
- int dig_gain, u16 *hts, u16 *vts)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int exp_val, ret;
- dev_dbg(&client->dev, "%s, exposure = %d, gain=%d, dig_gain=%d\n",
- __func__, exposure, gain, dig_gain);
-
- if (dev->limit_exposure_flag) {
- if (exposure > *vts - OV8858_INTEGRATION_TIME_MARGIN)
- exposure = *vts - OV8858_INTEGRATION_TIME_MARGIN;
- } else {
- if (*vts < exposure + OV8858_INTEGRATION_TIME_MARGIN)
- *vts = (u16) exposure + OV8858_INTEGRATION_TIME_MARGIN;
- }
-
- ret = __ov8858_update_frame_timing(sd, hts, vts);
- if (ret)
- return ret;
-
- /* For ov8858, the low 4 bits are fraction bits and must be kept 0 */
- exp_val = exposure << 4;
- ret = ov8858_write_reg(client, OV8858_8BIT,
- OV8858_LONG_EXPO+2, exp_val & 0xFF);
- if (ret)
- return ret;
-
- ret = ov8858_write_reg(client, OV8858_8BIT,
- OV8858_LONG_EXPO+1, (exp_val >> 8) & 0xFF);
- if (ret)
- return ret;
-
- ret = ov8858_write_reg(client, OV8858_8BIT,
- OV8858_LONG_EXPO, (exp_val >> 16) & 0x0F);
- if (ret)
- return ret;
-
- /* Digital gain : to all MWB channel gains */
- if (dig_gain) {
- ret = ov8858_write_reg(client, OV8858_16BIT,
- OV8858_MWB_RED_GAIN_H, dig_gain);
- if (ret)
- return ret;
-
- ret = ov8858_write_reg(client, OV8858_16BIT,
- OV8858_MWB_GREEN_GAIN_H, dig_gain);
- if (ret)
- return ret;
-
- ret = ov8858_write_reg(client, OV8858_16BIT,
- OV8858_MWB_BLUE_GAIN_H, dig_gain);
- if (ret)
- return ret;
- }
-
- ret = ov8858_write_reg(client, OV8858_16BIT, OV8858_LONG_GAIN,
- gain & 0x07ff);
- if (ret)
- return ret;
-
- dev->gain = gain;
- dev->exposure = exposure;
- dev->digital_gain = dig_gain;
-
- return 0;
-}
-
-static int ov8858_set_exposure(struct v4l2_subdev *sd, int exposure, int gain,
- int dig_gain)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- const struct ov8858_resolution *res;
- u16 hts, vts;
- int ret;
-
- mutex_lock(&dev->input_lock);
-
- /* Validate exposure: cannot exceed 16bit value */
- exposure = clamp_t(int, exposure, 0, OV8858_MAX_EXPOSURE_VALUE);
-
- /* Validate gain: must not exceed maximum 8bit value */
- gain = clamp_t(int, gain, 0, OV8858_MAX_GAIN_VALUE);
-
- /* Validate digital gain: must not exceed 12 bit value*/
- dig_gain = clamp_t(int, dig_gain, 0, OV8858_MWB_GAIN_MAX);
-
- res = &dev->curr_res_table[dev->fmt_idx];
- /*
- * Vendor: HTS reg value is half the total pixel line
- */
- hts = res->fps_options[dev->fps_index].pixels_per_line;
- vts = res->fps_options[dev->fps_index].lines_per_frame;
-
- ret = __ov8858_set_exposure(sd, exposure, gain, dig_gain, &hts, &vts);
-
- mutex_unlock(&dev->input_lock);
-
- return ret;
-}
-
-/*
- When exposure gain value set to sensor, the sensor changed value.
- So we need the function to get real value
- */
-static int ov8858_g_update_exposure(struct v4l2_subdev *sd,
- struct atomisp_update_exposure *exposure)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int gain = exposure->gain;
-
- dev_dbg(&client->dev, "%s: gain: %d, digi_gain: %d\n", __func__,
- exposure->gain, exposure->digi_gain);
- exposure->update_digi_gain = dev->digital_gain;
- /* This real gain value fetching function is provided by vendor */
- exposure->update_gain = (((gain & 0x700) >> 8) + 1) * (gain & 0xFF);
-
- return 0;
-}
-
-static int ov8858_s_exposure(struct v4l2_subdev *sd,
- struct atomisp_exposure *exposure)
-{
- return ov8858_set_exposure(sd, exposure->integration_time[0],
- exposure->gain[0], exposure->gain[1]);
-}
-
-static int ov8858_priv_int_data_init(struct v4l2_subdev *sd)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- u32 size = OV8858_OTP_END_ADDR - OV8858_OTP_START_ADDR + 1;
- int r;
- u16 isp_ctrl2 = 0;
-
- if (!dev->otp_data) {
- dev->otp_data = devm_kzalloc(&client->dev, size, GFP_KERNEL);
- if (!dev->otp_data) {
- r = -ENOMEM;
- goto error3;
- }
-
- /* Streaming has to be on */
- r = ov8858_write_reg(client, OV8858_8BIT, OV8858_STREAM_MODE,
- 0x01);
- if (r)
- goto error2;
-
- /* Turn off Dead Pixel Correction */
- r = ov8858_read_reg(client, OV8858_8BIT,
- OV8858_OTP_ISP_CTRL2, &isp_ctrl2);
- if (r)
- goto error1;
-
- r = ov8858_write_reg(client, OV8858_8BIT, OV8858_OTP_ISP_CTRL2,
- isp_ctrl2 & ~OV8858_OTP_DPC_ENABLE);
- if (r)
- goto error1;
-
- /* Enable partial OTP read mode */
- r = ov8858_write_reg(client, OV8858_8BIT, OV8858_OTP_MODE_CTRL,
- OV8858_OTP_MODE_PROGRAM_DISABLE |
- OV8858_OTP_MODE_MANUAL);
- if (r)
- goto error1;
-
- /* Set address range of OTP memory to read */
- r = ov8858_write_reg(client, OV8858_16BIT,
- OV8858_OTP_START_ADDR_REG,
- OV8858_OTP_START_ADDR);
- if (r)
- goto error1;
-
- r = ov8858_write_reg(client, OV8858_16BIT,
- OV8858_OTP_END_ADDR_REG,
- OV8858_OTP_END_ADDR);
- if (r)
- goto error1;
-
- /* Load the OTP data into the OTP buffer */
- r = ov8858_write_reg(client, OV8858_8BIT, OV8858_OTP_LOAD_CTRL,
- OV8858_OTP_LOAD_ENABLE);
- if (r)
- goto error1;
-
- /* Wait for the data to load into the buffer */
- usleep_range(5000, 5500);
-
- /* Read the OTP data from the buffer */
- r = ov8858_i2c_read(client, size, OV8858_OTP_START_ADDR,
- dev->otp_data);
- if (r)
- goto error1;
-
- /* Turn on Dead Pixel Correction */
- r = ov8858_write_reg(client, OV8858_8BIT, OV8858_OTP_ISP_CTRL2,
- isp_ctrl2 | OV8858_OTP_DPC_ENABLE);
- if (r)
- goto error1;
-
- /* Stop streaming */
- r = ov8858_write_reg(client, 1, OV8858_STREAM_MODE, 0x00);
- if (r) {
- dev_err(&client->dev, "%s: cannot turn off streaming\n",
- __func__);
- goto error1;
- }
- }
-
-
- return 0;
-
-error1:
- /* Turn on Dead Pixel Correction and set streaming off */
- ov8858_write_reg(client, OV8858_8BIT, OV8858_OTP_ISP_CTRL2,
- isp_ctrl2 | OV8858_OTP_DPC_ENABLE);
- ov8858_write_reg(client, 1, OV8858_STREAM_MODE, 0x00);
-error2:
- devm_kfree(&client->dev, dev->otp_data);
- dev->otp_data = NULL;
-error3:
- dev_err(&client->dev, "%s: OTP reading failed\n", __func__);
- return r;
-}
-
-static int ov8858_g_priv_int_data(struct v4l2_subdev *sd,
- struct v4l2_private_int_data *priv)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- u32 size = OV8858_OTP_END_ADDR - OV8858_OTP_START_ADDR + 1;
- int r;
-
- mutex_lock(&dev->input_lock);
-
- if (!dev->otp_data) {
- dev_err(&client->dev, "%s: otp data is NULL\n", __func__);
- mutex_unlock(&dev->input_lock);
- return -EFAULT;
- }
-
- if (copy_to_user(priv->data, dev->otp_data,
- min_t(__u32, priv->size, size))) {
- r = -EFAULT;
- dev_err(&client->dev, "%s: OTP reading failed\n", __func__);
- mutex_unlock(&dev->input_lock);
- return r;
- }
-
- priv->size = size;
- mutex_unlock(&dev->input_lock);
-
- return 0;
-}
-
-static int __ov8858_init(struct v4l2_subdev *sd)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- int ret;
- dev_dbg(&client->dev, "%s\n", __func__);
-
- /* Sets the default FPS */
- dev->fps_index = 0;
-
- /* Set default exposure values (initially start values) */
- dev->exposure = 256;
- dev->gain = 16;
- dev->digital_gain = 1024;
- dev->limit_exposure_flag = false;
-
- dev_dbg(&client->dev, "%s: Writing basic settings to ov8858\n",
- __func__);
- ret = ov8858_write_reg_array(client, ov8858_BasicSettings);
- if (ret)
- return ret;
-
- return ov8858_priv_int_data_init(sd);
-}
-
-static int ov8858_init(struct v4l2_subdev *sd, u32 val)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- int ret;
-
- mutex_lock(&dev->input_lock);
- ret = __ov8858_init(sd);
- mutex_unlock(&dev->input_lock);
-
- return ret;
-}
-
-static void ov8858_uninit(struct v4l2_subdev *sd)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- struct v4l2_ctrl *ctrl;
- dev_dbg(&client->dev, "%s:\n", __func__);
-
- dev->exposure = 0;
- dev->gain = 0;
- dev->digital_gain = 0;
- dev->limit_exposure_flag = false;
- mutex_unlock(&dev->input_lock);
- ctrl = v4l2_ctrl_find(sd->ctrl_handler,
- V4L2_CID_EXPOSURE_AUTO_PRIORITY);
- if (ctrl)
- v4l2_ctrl_s_ctrl(ctrl, V4L2_EXPOSURE_AUTO);
- mutex_lock(&dev->input_lock);
-}
-
-static int ov8858_g_comp_delay(struct v4l2_subdev *sd, unsigned int *usec)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- int ret = 0, exposure;
- u16 vts, data;
-
- if (dev->exposure == 0) {
- ret = ov8858_read_reg(client, OV8858_16BIT,
- OV8858_LONG_EXPO + 1, &data);
- if (ret)
- return ret;
- exposure = data;
- exposure >>= 4;
- } else {
- exposure = dev->exposure;
- }
-
- ret = ov8858_read_reg(client, OV8858_16BIT, OV8858_TIMING_VTS, &vts);
- if (ret || vts == 0)
- vts = OV8858_DEPTH_VTS_CONST;
-
- *usec = (exposure * 33333 / vts);
- if (*usec > OV8858_DEPTH_COMP_CONST)
- *usec = *usec - OV8858_DEPTH_COMP_CONST;
- else
- *usec = OV8858_DEPTH_COMP_CONST;
-
- return 0;
-}
-
-static long ov8858_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- switch (cmd) {
- case ATOMISP_IOC_S_EXPOSURE:
- return ov8858_s_exposure(sd, (struct atomisp_exposure *)arg);
- case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA:
- return ov8858_g_priv_int_data(sd, arg);
- case ATOMISP_IOC_G_DEPTH_SYNC_COMP:
- return ov8858_g_comp_delay(sd, (unsigned int *)arg);
- case ATOMISP_IOC_G_UPDATE_EXPOSURE:
- return ov8858_g_update_exposure(sd,
- (struct atomisp_update_exposure *)arg);
- default:
- dev_dbg(&client->dev, "Unhandled command 0x%X\n", cmd);
- return -EINVAL;
- }
-}
-
-static int __power_ctrl(struct v4l2_subdev *sd, bool flag)
-{
- int ret = 0;
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!dev || !dev->platform_data)
- return -ENODEV;
-
- if (dev->platform_data->v1p2_ctrl) {
- ret = dev->platform_data->v1p2_ctrl(sd, flag);
- if (ret) {
- dev_err(&client->dev,
- "failed to power %s 1.2v power rail\n",
- flag ? "up" : "down");
- return ret;
- }
- }
-
- if (dev->platform_data->v2p8_ctrl) {
- ret = dev->platform_data->v2p8_ctrl(sd, flag);
- if (ret) {
- dev_err(&client->dev,
- "failed to power %s 2.8v power rail\n",
- flag ? "up" : "down");
- return ret;
- }
- }
-
- if (dev->platform_data->v1p8_ctrl) {
- ret = dev->platform_data->v1p8_ctrl(sd, flag);
- if (ret) {
- dev_err(&client->dev,
- "failed to power %s 1.8v power rail\n",
- flag ? "up" : "down");
- if (dev->platform_data->v2p8_ctrl)
- dev->platform_data->v2p8_ctrl(sd, 0);
- return ret;
- }
- }
-
- if (flag)
- msleep(20); /* Wait for power lines to stabilize */
- return ret;
-}
-
-static int __gpio_ctrl(struct v4l2_subdev *sd, bool flag)
-{
- struct i2c_client *client;
- struct ov8858_device *dev;
-
- if (!sd)
- return -EINVAL;
-
- client = v4l2_get_subdevdata(sd);
- dev = to_ov8858_sensor(sd);
-
- if (!client || !dev || !dev->platform_data)
- return -ENODEV;
-
- if (dev->platform_data->gpio0_ctrl)
- return dev->platform_data->gpio0_ctrl(sd, flag);
-
- dev_err(&client->dev, "failed to find platform gpio callback\n");
-
- return -EINVAL;
-}
-
-static int power_up(struct v4l2_subdev *sd)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- int ret;
- dev_dbg(&client->dev, "%s\n", __func__);
-
- /* Enable power */
- ret = __power_ctrl(sd, 1);
- if (ret) {
- dev_err(&client->dev, "power rail on failed %d.\n", ret);
- goto fail_power;
- }
-
- /* Enable clock */
- ret = dev->platform_data->flisclk_ctrl(sd, 1);
- if (ret) {
- dev_err(&client->dev, "flisclk on failed %d\n", ret);
- goto fail_clk;
- }
-
- /* Release reset */
- ret = __gpio_ctrl(sd, 1);
- if (ret) {
- dev_err(&client->dev, "gpio on failed %d\n", ret);
- goto fail_gpio;
- }
-
- /* Minumum delay is 8192 clock cycles before first i2c transaction,
- * which is 1.37 ms at the lowest allowed clock rate 6 MHz */
- usleep_range(2000, 2500);
- return 0;
-
-fail_gpio:
- dev->platform_data->flisclk_ctrl(sd, 0);
-fail_clk:
- __power_ctrl(sd, 0);
-fail_power:
- dev_err(&client->dev, "Sensor power-up failed\n");
-
- return ret;
-}
-
-static int power_down(struct v4l2_subdev *sd)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
- dev_dbg(&client->dev, "%s\n", __func__);
-
- ret = dev->platform_data->flisclk_ctrl(sd, 0);
- if (ret)
- dev_err(&client->dev, "flisclk off failed\n");
-
- ret = __gpio_ctrl(sd, 0);
- if (ret)
- dev_err(&client->dev, "gpio off failed\n");
-
- ret = __power_ctrl(sd, 0);
- if (ret)
- dev_err(&client->dev, "power rail off failed.\n");
-
- return ret;
-}
-
-static int __ov8858_s_power(struct v4l2_subdev *sd, int on)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- int ret, r = 0;
-
- if (on == 0) {
- ov8858_uninit(sd);
- if (dev->vcm_driver && dev->vcm_driver->power_down)
- r = dev->vcm_driver->power_down(sd);
- ret = power_down(sd);
- if (r != 0 && ret == 0)
- ret = r;
- } else {
- ret = power_up(sd);
- if (ret)
- power_down(sd);
- if (dev->vcm_driver && dev->vcm_driver->power_up) {
- ret = dev->vcm_driver->power_up(sd);
- if (ret) {
- power_down(sd);
- return ret;
- }
- }
- return __ov8858_init(sd);
- }
-
- return ret;
-}
-
-static int ov8858_s_power(struct v4l2_subdev *sd, int on)
-{
- int ret;
- struct ov8858_device *dev = to_ov8858_sensor(sd);
-
- mutex_lock(&dev->input_lock);
- ret = __ov8858_s_power(sd, on);
- mutex_unlock(&dev->input_lock);
-
- /*
- * FIXME: Compatibility with old behaviour: return to preview
- * when the device is power cycled.
- */
- if (!ret && on)
- v4l2_ctrl_s_ctrl(dev->run_mode, ATOMISP_RUN_MODE_PREVIEW);
-
- return ret;
-}
-
-/*
- * Return value of the specified register, first try getting it from
- * the register list and if not found, get from the sensor via i2c.
- */
-static int ov8858_get_register(struct v4l2_subdev *sd, int reg, int type,
- const struct ov8858_reg *reglist)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- const struct ov8858_reg *next;
- u16 val;
-
- /* Try if the values are in the register list */
- for (next = reglist; next->type != OV8858_TOK_TERM; next++) {
- if (next->sreg == reg) {
- if (type == OV8858_8BIT)
- return next->val;
-
- if (type == OV8858_16BIT &&
- next[1].type != OV8858_TOK_TERM)
- return next[0].val << 8 | next[1].val;
- }
- }
-
- /* If not, read from sensor */
- if (ov8858_read_reg(client, type, reg, &val)) {
- dev_err(&client->dev, "failed to read register 0x%08x\n", reg);
- return -EIO;
- }
-
- return val;
-}
-
-static inline int ov8858_get_register_16bit(struct v4l2_subdev *sd, int reg,
- const struct ov8858_reg *reglist)
-{
- return ov8858_get_register(sd, reg, OV8858_16BIT, reglist);
-}
-
-static inline int ov8858_get_register_8bit(struct v4l2_subdev *sd, int reg,
- const struct ov8858_reg *reglist)
-{
- return ov8858_get_register(sd, reg, OV8858_8BIT, reglist);
-}
-
-static int __ov8858_get_pll1_values(struct v4l2_subdev *sd,
- int *value,
- const struct ov8858_reg *reglist)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- unsigned int prediv_idx;
- unsigned int multiplier;
- unsigned int sys_prediv;
- unsigned int prediv_coef[] = {2, 3, 4, 5, 6, 8, 12, 16};
- int ret;
-
- ret = ov8858_get_register_8bit(sd, OV8858_PLL1_PREDIV0, reglist);
- if (ret < 0)
- return ret;
-
- if (ret & OV8858_PLL1_PREDIV0_MASK)
- *value /= 2;
-
- ret = ov8858_get_register_8bit(sd, OV8858_PLL1_PREDIV, reglist);
-
- if (ret < 0)
- return ret;
-
- prediv_idx = ret & OV8858_PLL1_PREDIV_MASK;
- *value = *value * 2 / prediv_coef[prediv_idx];
-
- ret = ov8858_get_register_16bit(sd, OV8858_PLL1_MULTIPLIER, reglist);
- if (ret < 0)
- return ret;
-
- multiplier = ret;
- *value *= multiplier & OV8858_PLL1_MULTIPLIER_MASK;
- ret = ov8858_get_register_8bit(sd, OV8858_PLL1_SYS_PRE_DIV, reglist);
-
- if (ret < 0)
- return ret;
-
- sys_prediv = ret & OV8858_PLL1_SYS_PRE_DIV_MASK;
- *value /= (sys_prediv + 3);
- ret = ov8858_get_register_8bit(sd, OV8858_PLL1_SYS_DIVIDER, reglist);
-
- if (ret < 0)
- return ret;
-
- if (ret & OV8858_PLL1_SYS_DIVIDER_MASK)
- *value /= 2;
-
- dev_dbg(&client->dev, "%s: *value: %d\n", __func__, *value);
-
- return 0;
-}
-
-static int __ov8858_get_pll2a_values(struct v4l2_subdev *sd, int *value,
- const struct ov8858_reg *reglist)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- unsigned int prediv_idx;
- unsigned int multiplier;
- unsigned int prediv_coef[] = {2, 3, 4, 5, 6, 8, 12, 16};
- int ret;
-
- ret = ov8858_get_register_8bit(sd, OV8858_PLL2_PREDIV0, reglist);
- if (ret < 0)
- return ret;
-
- if (ret & OV8858_PLL2_PREDIV0_MASK)
- *value /= 2;
-
- ret = ov8858_get_register_8bit(sd, OV8858_PLL2_PREDIV, reglist);
- if (ret < 0)
- return ret;
-
- prediv_idx = (ret & OV8858_PLL2_PREDIV_MASK);
- *value = *value * 2 / prediv_coef[prediv_idx];
-
- ret = ov8858_get_register_16bit(sd, OV8858_PLL2_MULTIPLIER, reglist);
- if (ret < 0)
- return ret;
-
- multiplier = ret;
- *value *= multiplier & OV8858_PLL2_MULTIPLIER_MASK;
- dev_dbg(&client->dev, "%s: *value: %d\n", __func__, *value);
-
- return 0;
-}
-static int __ov8858_get_pll2b_values(struct v4l2_subdev *sd, int *value,
- const struct ov8858_reg *reglist)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- unsigned int dac_divider;
- int ret;
-
- ret = ov8858_get_register_8bit(sd, OV8858_PLL2_DAC_DIVIDER, reglist);
- if (ret < 0)
- return ret;
-
- dac_divider = (ret & OV8858_PLL2_DAC_DIVIDER_MASK) + 1;
- *value /= dac_divider;
-
- dev_dbg(&client->dev, "%s: *value: %d\n", __func__, *value);
-
- return 0;
-}
-static int __ov8858_get_pll2c_values(struct v4l2_subdev *sd, int *value,
- const struct ov8858_reg *reglist)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- unsigned int sys_pre_div;
- unsigned int sys_divider_idx;
- unsigned int sys_divider_coef[] = {2, 3, 4, 5, 6, 7, 8, 10};
- int ret;
-
- ret = ov8858_get_register_8bit(sd, OV8858_PLL2_SYS_PRE_DIV, reglist);
- if (ret < 0)
- return ret;
-
- sys_pre_div = (ret & OV8858_PLL2_SYS_PRE_DIV_MASK) + 1;
- *value /= sys_pre_div;
-
- ret = ov8858_get_register_8bit(sd, OV8858_PLL2_SYS_DIVIDER, reglist);
- if (ret < 0)
- return ret;
-
- sys_divider_idx = ret & OV8858_PLL2_SYS_DIVIDER_MASK;
- *value *= 2 / sys_divider_coef[sys_divider_idx];
-
- dev_dbg(&client->dev, "%s: *value: %d\n", __func__, *value);
-
- return 0;
-}
-
-static int ov8858_get_intg_factor(struct v4l2_subdev *sd,
- struct camera_mipi_info *info,
- const struct ov8858_reg *reglist)
-{
- const unsigned int ext_clk = 19200000; /* Hz */
- struct atomisp_sensor_mode_data *m = &info->data;
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct device *d = &client->dev;
- const struct ov8858_resolution *res =
- &dev->curr_res_table[dev->fmt_idx];
- unsigned int pll_sclksel1;
- unsigned int pll_sclksel2;
- unsigned int sys_pre_div;
- unsigned int sclk_pdiv;
- unsigned int sclk = ext_clk;
- u16 hts;
- int ret;
-
- memset(&info->data, 0, sizeof(info->data));
-
- ret = ov8858_get_register_8bit(sd, OV8858_PLL_SCLKSEL1, reglist);
- if (ret < 0)
- return ret;
-
- dev_dbg(d, "%s: OV8858_PLL_SCLKSEL1: 0x%02x\n", __func__, ret);
- pll_sclksel1 = ret & OV8858_PLL_SCLKSEL1_MASK;
-
- ret = ov8858_get_register_8bit(sd, OV8858_PLL_SCLKSEL2, reglist);
- if (ret < 0)
- return ret;
-
- dev_dbg(d, "%s: OV8858_PLL_SCLKSEL2: 0x%02x\n", __func__, ret);
- pll_sclksel2 = ret & OV8858_PLL_SCLKSEL2_MASK;
-
- if (pll_sclksel2) {
- ret = __ov8858_get_pll2a_values(sd, &sclk, reglist);
- if (ret < 0)
- return ret;
- ret = __ov8858_get_pll2b_values(sd, &sclk, reglist);
- if (ret < 0)
- return ret;
- } else if (pll_sclksel1) {
- ret = __ov8858_get_pll2a_values(sd, &sclk, reglist);
- if (ret < 0)
- return ret;
- ret = __ov8858_get_pll2c_values(sd, &sclk, reglist);
- if (ret < 0)
- return ret;
- } else {
- ret = __ov8858_get_pll1_values(sd, &sclk, reglist);
- if (ret < 0)
- return ret;
- }
-
- ret = ov8858_get_register_8bit(sd, OV8858_SRB_HOST_INPUT_DIS, reglist);
- if (ret < 0)
- return ret;
-
- dev_dbg(d, "%s: OV8858_SRB_HOST_INPUT_DIS: 0x%02x\n", __func__, ret);
-
- sys_pre_div = ret & OV8858_SYS_PRE_DIV_MASK;
- sys_pre_div >>= OV8858_SYS_PRE_DIV_OFFSET;
-
- if (sys_pre_div == 1)
- sclk /= 2;
- else if (sys_pre_div == 2)
- sclk /= 4;
-
- sclk_pdiv = ret & OV8858_SCLK_PDIV_MASK;
- sclk_pdiv >>= OV8858_SCLK_PDIV_OFFSET;
-
- if (sclk_pdiv > 1)
- sclk /= sclk_pdiv;
-
- dev_dbg(d, "%s: sclk: %d\n", __func__, sclk);
-
- dev->vt_pix_clk_freq_mhz = sclk;
- m->vt_pix_clk_freq_mhz = sclk;
-
- /* HTS and VTS */
- m->frame_length_lines =
- res->fps_options[dev->fps_index].lines_per_frame;
- m->line_length_pck = res->fps_options[dev->fps_index].pixels_per_line;
-
- m->coarse_integration_time_min = 0;
- m->coarse_integration_time_max_margin = OV8858_INTEGRATION_TIME_MARGIN;
- ret = ov8858_read_reg(client, OV8858_16BIT, OV8858_TIMING_HTS, &hts);
- if (ret < 0)
- return ret;
- m->hts = hts;
- dev_dbg(&client->dev, "%s: get HTS %d\n", __func__, hts);
-
- /* OV Sensor do not use fine integration time. */
- m->fine_integration_time_min = 0;
- m->fine_integration_time_max_margin = 0;
-
- /*
- * read_mode indicate whether binning is used for calculating
- * the correct exposure value from the user side. So adapt the
- * read mode values accordingly.
- */
- m->read_mode = res->bin_factor_x ?
- OV8858_READ_MODE_BINNING_ON : OV8858_READ_MODE_BINNING_OFF;
-
- ret = ov8858_get_register_8bit(sd, OV8858_H_INC_ODD, res->regs);
- if (ret < 0)
- return ret;
- m->binning_factor_x = (ret + 1) / 2;
-
- ret = ov8858_get_register_8bit(sd, OV8858_V_INC_ODD, res->regs);
- if (ret < 0)
- return ret;
- m->binning_factor_y = (ret + 1) / 2;
-
- /* Get the cropping and output resolution to ISP for this mode. */
- ret = ov8858_get_register_16bit(sd, OV8858_HORIZONTAL_START_H,
- res->regs);
- if (ret < 0)
- return ret;
-
- m->crop_horizontal_start = ret;
-
- ret = ov8858_get_register_16bit(sd, OV8858_VERTICAL_START_H, res->regs);
- if (ret < 0)
- return ret;
-
- m->crop_vertical_start = ret;
-
- ret = ov8858_get_register_16bit(sd, OV8858_HORIZONTAL_END_H, res->regs);
- if (ret < 0)
- return ret;
-
- m->crop_horizontal_end = ret;
-
- ret = ov8858_get_register_16bit(sd, OV8858_VERTICAL_END_H, res->regs);
- if (ret < 0)
- return ret;
-
- m->crop_vertical_end = ret;
-
- ret = ov8858_get_register_16bit(sd, OV8858_HORIZONTAL_OUTPUT_SIZE_H,
- res->regs);
- if (ret < 0)
- return ret;
-
- m->output_width = ret;
-
- ret = ov8858_get_register_16bit(sd, OV8858_VERTICAL_OUTPUT_SIZE_H,
- res->regs);
- if (ret < 0)
- return ret;
-
- m->output_height = ret;
-
- return 0;
-}
-
-/*
- * distance - calculate the distance
- * @res: resolution
- * @w: width
- * @h: height
- *
- * Get the gap between res_w/res_h and w/h.
- * distance = (res_w/res_h - w/h) / (w/h) * 8192
- * res->width/height smaller than w/h wouldn't be considered.
- * The gap of ratio larger than 1/8 wouldn't be considered.
- * Returns the value of gap or -1 if fail.
- */
-#define LARGEST_ALLOWED_RATIO_MISMATCH 1024
-static int distance(struct ov8858_resolution const *res, const u32 w,
- const u32 h)
-{
- int ratio;
- int distance;
-
- if (w == 0 || h == 0 ||
- res->width < w || res->height < h)
- return -1;
-
- ratio = res->width << 13;
- ratio /= w;
- ratio *= h;
- ratio /= res->height;
-
- distance = abs(ratio - 8192);
-
- if (distance > LARGEST_ALLOWED_RATIO_MISMATCH)
- return -1;
- return distance;
-}
-
-/*
- * Returns the nearest higher resolution index.
- * @w: width
- * @h: height
- * matching is done based on enveloping resolution and
- * aspect ratio. If the aspect ratio cannot be matched
- * to any index, -1 is returned.
- */
-static int nearest_resolution_index(struct v4l2_subdev *sd, int w, int h)
-{
- int i;
- int idx = -1;
- int dist;
- int fps_diff;
- int min_fps_diff = INT_MAX;
- int min_dist = INT_MAX;
- int min_res_w = INT_MAX;
- const struct ov8858_resolution *tmp_res = NULL;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- dev_dbg(&client->dev, "%s: w=%d, h=%d\n", __func__, w, h);
-
- for (i = 0; i < dev->entries_curr_table; i++) {
- tmp_res = &dev->curr_res_table[i];
- dist = distance(tmp_res, w, h);
- dev_dbg(&client->dev,
- "%s[%d]: %dx%d distance=%d\n", tmp_res->desc,
- i, tmp_res->width, tmp_res->height, dist);
- if (dist == -1)
- continue;
- if (dist < min_dist) {
- min_dist = dist;
- min_res_w = tmp_res->width;
- min_fps_diff = __ov8858_min_fps_diff(dev->fps,
- tmp_res->fps_options);
- idx = i;
- }
- if (dist == min_dist) {
- fps_diff = __ov8858_min_fps_diff(dev->fps,
- tmp_res->fps_options);
- if (fps_diff < min_fps_diff) {
- min_fps_diff = fps_diff;
- idx = i;
- }
- if (tmp_res->width < min_res_w) {
- min_res_w = tmp_res->width;
- idx = i;
- }
- }
- }
-
- return idx;
-}
-
-static int ov8858_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *format)
-{
- struct v4l2_mbus_framefmt *fmt = &format->format;
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- struct camera_mipi_info *ov8858_info = NULL;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- const struct ov8858_resolution *res;
- int ret;
- int idx;
- if (format->pad)
- return -EINVAL;
- if (!fmt)
- return -EINVAL;
-
- ov8858_info = v4l2_get_subdev_hostdata(sd);
- if (ov8858_info == NULL)
- return -EINVAL;
-
- mutex_lock(&dev->input_lock);
-
- if ((fmt->width > OV8858_RES_WIDTH_MAX) ||
- (fmt->height > OV8858_RES_HEIGHT_MAX)) {
- fmt->width = OV8858_RES_WIDTH_MAX;
- fmt->height = OV8858_RES_HEIGHT_MAX;
- } else {
- idx = nearest_resolution_index(sd, fmt->width, fmt->height);
-
- /*
- * nearest_resolution_index() doesn't return smaller
- * resolutions. If it fails, it means the requested resolution
- * is higher than we can support. Fallback to highest possible
- * resolution in this case.
- */
- if (idx == -1)
- idx = dev->entries_curr_table - 1;
-
- fmt->width = dev->curr_res_table[idx].width;
- fmt->height = dev->curr_res_table[idx].height;
- }
-
- fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
- if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *fmt;
- mutex_unlock(&dev->input_lock);
- return 0;
- }
-
- dev->fmt_idx = nearest_resolution_index(sd, fmt->width, fmt->height);
- if (dev->fmt_idx == -1) {
- ret = -EINVAL;
- goto out;
- }
- res = &dev->curr_res_table[dev->fmt_idx];
- dev_dbg(&client->dev, "%s: selected width = %d, height = %d\n",
- __func__, res->width, res->height);
-
- /* Adjust the FPS selection based on the resolution selected */
- dev->fps_index = __ov8858_nearest_fps_index(dev->fps, res->fps_options);
- dev->fps = res->fps_options[dev->fps_index].fps;
- dev->regs = res->fps_options[dev->fps_index].regs;
- if (!dev->regs)
- dev->regs = res->regs;
-
- ret = ov8858_write_reg_array(client, dev->regs);
- if (ret)
- goto out;
-
- dev->pixels_per_line = res->fps_options[dev->fps_index].pixels_per_line;
- dev->lines_per_frame = res->fps_options[dev->fps_index].lines_per_frame;
-
- /* ov8858 only support RGB RAW10 output */
- ov8858_info->metadata_width = res->width * 10 / 8;
- ov8858_info->metadata_height = 2;
- ov8858_info->metadata_format = ATOMISP_INPUT_FORMAT_EMBEDDED;
-
- /* Set the initial exposure */
- ret = __ov8858_set_exposure(sd, dev->exposure, dev->gain,
- dev->digital_gain, &dev->pixels_per_line,
- &dev->lines_per_frame);
- if (ret)
- goto out;
-
- ret = ov8858_get_intg_factor(sd, ov8858_info, dev->regs);
-
-out:
- mutex_unlock(&dev->input_lock);
-
- return ret;
-}
-
-static int ov8858_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *format)
-{
- struct v4l2_mbus_framefmt *fmt = &format->format;
- struct ov8858_device *dev = to_ov8858_sensor(sd);
-
- if (format->pad)
- return -EINVAL;
- if (!fmt)
- return -EINVAL;
-
- mutex_lock(&dev->input_lock);
- fmt->width = dev->curr_res_table[dev->fmt_idx].width;
- fmt->height = dev->curr_res_table[dev->fmt_idx].height;
- fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
- mutex_unlock(&dev->input_lock);
-
- return 0;
-}
-
-static int ov8858_detect(struct i2c_client *client, u16 *id)
-{
- struct i2c_adapter *adapter = client->adapter;
- u16 id_hi = 0;
- u16 id_low = 0;
- int ret;
-
- /* i2c check */
- if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
- return -ENODEV;
-
- dev_dbg(&client->dev, "%s: I2C functionality ok\n", __func__);
- ret = ov8858_read_reg(client, OV8858_8BIT, OV8858_CHIP_ID_HIGH, &id_hi);
- if (ret)
- return ret;
- dev_dbg(&client->dev, "%s: id_high = 0x%04x\n", __func__, id_hi);
- ret = ov8858_read_reg(client, OV8858_8BIT, OV8858_CHIP_ID_LOW, &id_low);
- if (ret)
- return ret;
- dev_dbg(&client->dev, "%s: id_low = 0x%04x\n", __func__, id_low);
- *id = (id_hi << 8) | id_low;
-
- dev_dbg(&client->dev, "%s: chip_id = 0x%04x\n", __func__, *id);
-
- dev_info(&client->dev, "%s: chip_id = 0x%04x\n", __func__, *id);
- if (*id != OV8858_CHIP_ID)
- return -ENODEV;
-
- /* Stream off now. */
- return ov8858_write_reg(client, OV8858_8BIT, OV8858_STREAM_MODE, 0);
-}
-
-static void __ov8858_print_timing(struct v4l2_subdev *sd)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- u16 width = dev->curr_res_table[dev->fmt_idx].width;
- u16 height = dev->curr_res_table[dev->fmt_idx].height;
-
- dev_dbg(&client->dev, "Dump ov8858 timing in stream on:\n");
- dev_dbg(&client->dev, "width: %d:\n", width);
- dev_dbg(&client->dev, "height: %d:\n", height);
- dev_dbg(&client->dev, "pixels_per_line: %d:\n", dev->pixels_per_line);
- dev_dbg(&client->dev, "line per frame: %d:\n", dev->lines_per_frame);
- dev_dbg(&client->dev, "pix freq: %d:\n", dev->vt_pix_clk_freq_mhz);
- /* updated formula: pixels_per_line = 2 * HTS */
- /* updated formula: fps = SCLK / (VTS * HTS) */
- dev_dbg(&client->dev, "init fps: %d:\n", dev->vt_pix_clk_freq_mhz /
- (dev->pixels_per_line / 2) / dev->lines_per_frame);
- dev_dbg(&client->dev, "HBlank: %d nS:\n",
- 1000 * (dev->pixels_per_line - width) /
- (dev->vt_pix_clk_freq_mhz / 1000000));
- dev_dbg(&client->dev, "VBlank: %d uS:\n",
- (dev->lines_per_frame - height) * dev->pixels_per_line /
- (dev->vt_pix_clk_freq_mhz / 1000000));
-}
-
-/*
- * ov8858 stream on/off
- */
-static int ov8858_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
- u16 val;
- dev_dbg(&client->dev, "%s: enable = %d\n", __func__, enable);
-
- /* Set orientation */
- ret = ov8858_read_reg(client, OV8858_8BIT, OV8858_FORMAT2, &val);
- if (ret)
- return ret;
-
- ret = ov8858_write_reg(client, OV8858_8BIT, OV8858_FORMAT2,
- dev->hflip ? val | OV8858_FLIP_ENABLE :
- val & ~OV8858_FLIP_ENABLE);
- if (ret)
- return ret;
-
- ret = ov8858_read_reg(client, OV8858_8BIT, OV8858_FORMAT1, &val);
- if (ret)
- return ret;
-
- ret = ov8858_write_reg(client, OV8858_8BIT, OV8858_FORMAT1,
- dev->vflip ? val | OV8858_FLIP_ENABLE :
- val & ~OV8858_FLIP_ENABLE);
- if (ret)
- return ret;
-
- mutex_lock(&dev->input_lock);
- if (enable) {
- __ov8858_print_timing(sd);
- ret = ov8858_write_reg_array(client, ov8858_streaming);
- if (ret != 0) {
- dev_err(&client->dev, "write_reg_array err\n");
- goto out;
- }
- dev->streaming = 1;
- } else {
- ret = ov8858_write_reg_array(client, ov8858_soft_standby);
- if (ret != 0) {
- dev_err(&client->dev, "write_reg_array err\n");
- goto out;
- }
- dev->streaming = 0;
- dev->fps_index = 0;
- dev->fps = 0;
- }
-out:
- mutex_unlock(&dev->input_lock);
- return ret;
-}
-
-static int __update_ov8858_device_settings(struct ov8858_device *dev,
- u16 sensor_id)
-{
- if (sensor_id == OV8858_CHIP_ID)
-#ifdef CONFIG_PLATFORM_BTNS
- dev->vcm_driver = &ov8858_vcms[OV8858_ID_DEFAULT];
-#else
- dev->vcm_driver = &ov8858_vcms[OV8858_SUNNY];
-#endif
- else
- return -ENODEV;
-
- if (dev->vcm_driver && dev->vcm_driver->init)
- return dev->vcm_driver->init(&dev->sd);
-
- return 0;
-}
-
-static int ov8858_s_config(struct v4l2_subdev *sd,
- int irq, void *pdata)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- u16 sensor_id;
- int ret;
-
- if (pdata == NULL)
- return -ENODEV;
-
- dev->platform_data = pdata;
-
- mutex_lock(&dev->input_lock);
-
- ret = __ov8858_s_power(sd, 1);
- if (ret) {
- dev_err(&client->dev, "power-up error %d!\n", ret);
- mutex_unlock(&dev->input_lock);
- return ret;
- }
-
- ret = dev->platform_data->csi_cfg(sd, 1);
- if (ret)
- goto fail_csi_cfg;
-
- /* config & detect sensor */
- ret = ov8858_detect(client, &sensor_id);
- if (ret) {
- dev_err(&client->dev, "detect error %d!\n", ret);
- goto fail_detect;
- }
-
- dev->sensor_id = sensor_id;
-
- /* power off sensor */
- ret = __ov8858_s_power(sd, 0);
- if (ret) {
- dev->platform_data->csi_cfg(sd, 0);
- dev_err(&client->dev, "__ov8858_s_power-down error %d!\n", ret);
- goto fail_update;
- }
-
- /* Resolution settings depend on sensor type and platform */
- ret = __update_ov8858_device_settings(dev, dev->sensor_id);
- if (ret) {
- dev->platform_data->csi_cfg(sd, 0);
- dev_err(&client->dev, "__update_ov8858_device_settings error %d!\n", ret);
- goto fail_update;
- }
-
- mutex_unlock(&dev->input_lock);
- return ret;
-
-fail_detect:
- dev->platform_data->csi_cfg(sd, 0);
-fail_csi_cfg:
- __ov8858_s_power(sd, 0);
-fail_update:
- mutex_unlock(&dev->input_lock);
- dev_err(&client->dev, "sensor power-gating failed\n");
- return ret;
-}
-
-static int
-ov8858_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- if (code->index)
- return -EINVAL;
- code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-
- return 0;
-}
-
-static int
-ov8858_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_frame_size_enum *fse)
-{
- int index = fse->index;
- struct ov8858_device *dev = to_ov8858_sensor(sd);
-
- mutex_lock(&dev->input_lock);
- if (index >= dev->entries_curr_table) {
- mutex_unlock(&dev->input_lock);
- return -EINVAL;
- }
-
- fse->min_width = dev->curr_res_table[index].width;
- fse->min_height = dev->curr_res_table[index].height;
- fse->max_width = dev->curr_res_table[index].width;
- fse->max_height = dev->curr_res_table[index].height;
- mutex_unlock(&dev->input_lock);
-
- return 0;
-}
-
-static int ov8858_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct ov8858_device *dev = container_of(
- ctrl->handler, struct ov8858_device, ctrl_handler);
- struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
-
- /* input_lock is taken by the control framework, so it
- * doesn't need to be taken here.
- */
-
- switch (ctrl->id) {
- case V4L2_CID_RUN_MODE:
- switch (ctrl->val) {
- case ATOMISP_RUN_MODE_VIDEO:
- dev->curr_res_table = ov8858_res_video;
- dev->entries_curr_table = ARRAY_SIZE(ov8858_res_video);
- break;
- case ATOMISP_RUN_MODE_STILL_CAPTURE:
- dev->curr_res_table = ov8858_res_still;
- dev->entries_curr_table = ARRAY_SIZE(ov8858_res_still);
- break;
- default:
- dev->curr_res_table = ov8858_res_preview;
- dev->entries_curr_table =
- ARRAY_SIZE(ov8858_res_preview);
- }
-
- dev->fmt_idx = 0;
- dev->fps_index = 0;
-
- return 0;
- case V4L2_CID_FOCUS_ABSOLUTE:
- if (dev->vcm_driver && dev->vcm_driver->t_focus_abs)
- return dev->vcm_driver->t_focus_abs(&dev->sd,
- ctrl->val);
- return 0;
- case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
- if (ctrl->val == V4L2_EXPOSURE_AUTO)
- dev->limit_exposure_flag = false;
- else if (ctrl->val == V4L2_EXPOSURE_APERTURE_PRIORITY)
- dev->limit_exposure_flag = true;
- return 0;
- case V4L2_CID_HFLIP:
- dev->hflip = ctrl->val;
- return 0;
- case V4L2_CID_VFLIP:
- dev->vflip = ctrl->val;
- return 0;
- default:
- dev_err(&client->dev, "%s: Error: Invalid ctrl: 0x%X\n",
- __func__, ctrl->id);
- return -EINVAL;
- }
-}
-
-static int ov8858_g_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct ov8858_device *dev = container_of(
- ctrl->handler, struct ov8858_device, ctrl_handler);
- struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
- int r_odd, r_even;
- int i = dev->fmt_idx;
-
- switch (ctrl->id) {
- case V4L2_CID_FOCUS_STATUS:
- if (dev->vcm_driver && dev->vcm_driver->q_focus_status)
- return dev->vcm_driver->q_focus_status(&dev->sd,
- &(ctrl->val));
- return 0;
- case V4L2_CID_BIN_FACTOR_HORZ:
- r_odd = ov8858_get_register_8bit(&dev->sd, OV8858_H_INC_ODD,
- dev->curr_res_table[i].regs);
- if (r_odd < 0)
- return r_odd;
- r_even = ov8858_get_register_8bit(&dev->sd, OV8858_H_INC_EVEN,
- dev->curr_res_table[i].regs);
- if (r_even < 0)
- return r_even;
- ctrl->val = fls(r_odd + (r_even)) - 2;
- return 0;
-
- case V4L2_CID_BIN_FACTOR_VERT:
- r_odd = ov8858_get_register_8bit(&dev->sd, OV8858_V_INC_ODD,
- dev->curr_res_table[i].regs);
- if (r_odd < 0)
- return r_odd;
- r_even = ov8858_get_register_8bit(&dev->sd, OV8858_V_INC_EVEN,
- dev->curr_res_table[i].regs);
- if (r_even < 0)
- return r_even;
- ctrl->val = fls(r_odd + (r_even)) - 2;
- return 0;
- case V4L2_CID_HFLIP:
- ctrl->val = dev->hflip;
- break;
- case V4L2_CID_VFLIP:
- ctrl->val = dev->vflip;
- break;
- case V4L2_CID_EXPOSURE_ABSOLUTE:
- ctrl->val = dev->exposure;
- break;
- default:
- dev_warn(&client->dev,
- "%s: Error: Invalid ctrl: 0x%X\n", __func__, ctrl->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int
-ov8858_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *interval)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- const struct ov8858_resolution *res =
- &dev->curr_res_table[dev->fmt_idx];
-
- mutex_lock(&dev->input_lock);
- interval->interval.denominator = res->fps_options[dev->fps_index].fps;
- interval->interval.numerator = 1;
- mutex_unlock(&dev->input_lock);
- return 0;
-}
-
-static int __ov8858_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *interval)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- const struct ov8858_resolution *res =
- &dev->curr_res_table[dev->fmt_idx];
- struct camera_mipi_info *info = NULL;
- unsigned int fps_index;
- int ret = 0;
- int fps;
-
- info = v4l2_get_subdev_hostdata(sd);
- if (info == NULL)
- return -EINVAL;
-
- if (!interval->interval.numerator)
- interval->interval.numerator = 1;
-
- fps = interval->interval.denominator / interval->interval.numerator;
-
- /* No need to proceed further if we are not streaming */
- if (!dev->streaming) {
- /* Save the new FPS and use it while selecting setting */
- dev->fps = fps;
- return 0;
- }
-
- /* Ignore if we are already using the required FPS. */
- if (fps == res->fps_options[dev->fps_index].fps)
- return 0;
-
- fps_index = __ov8858_nearest_fps_index(fps, res->fps_options);
-
- if (res->fps_options[fps_index].regs &&
- res->fps_options[fps_index].regs != dev->regs) {
- dev_err(&client->dev,
- "Sensor is streaming, can't apply new configuration\n");
- return -EBUSY;
- }
-
- dev->fps_index = fps_index;
- dev->fps = res->fps_options[dev->fps_index].fps;
-
- /* Update the new frametimings based on FPS */
- dev->pixels_per_line =
- res->fps_options[dev->fps_index].pixels_per_line;
- dev->lines_per_frame =
- res->fps_options[dev->fps_index].lines_per_frame;
-
- /* update frametiming. Conside the curren exposure/gain as well */
- ret = __ov8858_update_frame_timing(sd,
- &dev->pixels_per_line, &dev->lines_per_frame);
- if (ret)
- return ret;
-
- /* Update the new values so that user side knows the current settings */
- ret = ov8858_get_intg_factor(sd, info, dev->regs);
- if (ret)
- return ret;
-
- interval->interval.denominator = res->fps_options[dev->fps_index].fps;
- interval->interval.numerator = 1;
- __ov8858_print_timing(sd);
-
- return ret;
-}
-
-static int ov8858_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *interval)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
- int ret;
-
- mutex_lock(&dev->input_lock);
- ret = __ov8858_s_frame_interval(sd, interval);
- mutex_unlock(&dev->input_lock);
-
- return ret;
-}
-
-static int ov8858_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
-{
- struct ov8858_device *dev = to_ov8858_sensor(sd);
-
- mutex_lock(&dev->input_lock);
- *frames = dev->curr_res_table[dev->fmt_idx].skip_frames;
- mutex_unlock(&dev->input_lock);
-
- return 0;
-}
-
-static const struct v4l2_subdev_sensor_ops ov8858_sensor_ops = {
- .g_skip_frames = ov8858_g_skip_frames,
-};
-
-static const struct v4l2_ctrl_ops ctrl_ops = {
- .s_ctrl = ov8858_s_ctrl,
- .g_volatile_ctrl = ov8858_g_ctrl,
-};
-
-static const struct v4l2_subdev_video_ops ov8858_video_ops = {
- .s_stream = ov8858_s_stream,
- .g_frame_interval = ov8858_g_frame_interval,
- .s_frame_interval = ov8858_s_frame_interval,
-};
-
-static const struct v4l2_subdev_core_ops ov8858_core_ops = {
- .s_power = ov8858_s_power,
- .ioctl = ov8858_ioctl,
- .init = ov8858_init,
-};
-
-static const struct v4l2_subdev_pad_ops ov8858_pad_ops = {
- .enum_mbus_code = ov8858_enum_mbus_code,
- .enum_frame_size = ov8858_enum_frame_size,
- .get_fmt = ov8858_get_fmt,
- .set_fmt = ov8858_set_fmt,
-};
-
-static const struct v4l2_subdev_ops ov8858_ops = {
- .core = &ov8858_core_ops,
- .video = &ov8858_video_ops,
- .pad = &ov8858_pad_ops,
- .sensor = &ov8858_sensor_ops,
-};
-
-static const struct media_entity_operations ov_entity_ops = {
- .link_setup = NULL,
-};
-
-static int ov8858_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ov8858_device *dev = to_ov8858_sensor(sd);
-
- media_entity_cleanup(&dev->sd.entity);
- v4l2_ctrl_handler_free(&dev->ctrl_handler);
- dev->platform_data->csi_cfg(sd, 0);
- v4l2_device_unregister_subdev(sd);
- kfree(dev);
-
- return 0;
-}
-
-static const char * const ctrl_run_mode_menu[] = {
- NULL,
- "Video",
- "Still capture",
- "Continuous capture",
- "Preview",
-};
-
-static const struct v4l2_ctrl_config ctrl_run_mode = {
- .ops = &ctrl_ops,
- .id = V4L2_CID_RUN_MODE,
- .name = "run mode",
- .type = V4L2_CTRL_TYPE_MENU,
- .min = 1,
- .def = 4,
- .max = 4,
- .qmenu = ctrl_run_mode_menu,
-};
-
-static const struct v4l2_ctrl_config ctrls[] = {
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_VFLIP,
- .name = "Vertical flip",
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .min = false,
- .max = true,
- .step = 1,
- }, {
- .ops = &ctrl_ops,
- .id = V4L2_CID_HFLIP,
- .name = "Horizontal flip",
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .min = false,
- .max = true,
- .step = 1,
- }, {
- .ops = &ctrl_ops,
- .id = V4L2_CID_EXPOSURE_ABSOLUTE,
- .name = "Absolute exposure",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .max = 0xffff,
- .min = 0x0,
- .step = 1,
- .def = 0x00,
- .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE,
- }, {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FOCUS_ABSOLUTE,
- .name = "Focus absolute",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .step = 1,
- .max = OV8858_MAX_FOCUS_POS,
- }, {
- /* This one is junk: see the spec for proper use of this CID. */
- .ops = &ctrl_ops,
- .id = V4L2_CID_FOCUS_STATUS,
- .name = "Focus status",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .step = 1,
- .max = 100,
- .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE,
- }, {
- /* This is crap. For compatibility use only. */
- .ops = &ctrl_ops,
- .id = V4L2_CID_FOCAL_ABSOLUTE,
- .name = "Focal lenght",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = (OV8858_FOCAL_LENGTH_NUM << 16) |
- OV8858_FOCAL_LENGTH_DEM,
- .max = (OV8858_FOCAL_LENGTH_NUM << 16) |
- OV8858_FOCAL_LENGTH_DEM,
- .step = 1,
- .def = (OV8858_FOCAL_LENGTH_NUM << 16) |
- OV8858_FOCAL_LENGTH_DEM,
- .flags = V4L2_CTRL_FLAG_READ_ONLY,
- }, {
- /* This one is crap, too. For compatibility use only. */
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_ABSOLUTE,
- .name = "F-number",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = (OV8858_F_NUMBER_DEFAULT_NUM << 16) |
- OV8858_F_NUMBER_DEM,
- .max = (OV8858_F_NUMBER_DEFAULT_NUM << 16) |
- OV8858_F_NUMBER_DEM,
- .step = 1,
- .def = (OV8858_F_NUMBER_DEFAULT_NUM << 16) |
- OV8858_F_NUMBER_DEM,
- .flags = V4L2_CTRL_FLAG_READ_ONLY,
- }, {
- /*
- * The most utter crap. _Never_ use this, even for
- * compatibility reasons!
- */
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_RANGE,
- .name = "F-number range",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = (OV8858_F_NUMBER_DEFAULT_NUM << 24) |
- (OV8858_F_NUMBER_DEM << 16) |
- (OV8858_F_NUMBER_DEFAULT_NUM << 8) |
- OV8858_F_NUMBER_DEM,
- .max = (OV8858_F_NUMBER_DEFAULT_NUM << 24) |
- (OV8858_F_NUMBER_DEM << 16) |
- (OV8858_F_NUMBER_DEFAULT_NUM << 8) |
- OV8858_F_NUMBER_DEM,
- .step = 1,
- .def = (OV8858_F_NUMBER_DEFAULT_NUM << 24) |
- (OV8858_F_NUMBER_DEM << 16) |
- (OV8858_F_NUMBER_DEFAULT_NUM << 8) |
- OV8858_F_NUMBER_DEM,
- .flags = V4L2_CTRL_FLAG_READ_ONLY,
- }, {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_HORZ,
- .name = "Horizontal binning factor",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .max = OV8858_BIN_FACTOR_MAX,
- .step = 1,
- .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE,
- }, {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_VERT,
- .name = "Vertical binning factor",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .max = OV8858_BIN_FACTOR_MAX,
- .step = 1,
- .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE,
- }, {
- .ops = &ctrl_ops,
- .id = V4L2_CID_EXPOSURE_AUTO_PRIORITY,
- .name = "Exposure auto priority",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = V4L2_EXPOSURE_AUTO,
- .max = V4L2_EXPOSURE_APERTURE_PRIORITY,
- .step = 1,
- }
-};
-
-static int ov8858_probe(struct i2c_client *client)
-{
- struct ov8858_device *dev;
- unsigned int i;
- int ret = 0;
- struct camera_sensor_platform_data *pdata;
-
- dev_dbg(&client->dev, "%s:\n", __func__);
-
- /* allocate sensor device & init sub device */
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
-
- mutex_init(&dev->input_lock);
-
- dev->fmt_idx = 0;
- dev->sensor_id = OV_ID_DEFAULT;
- dev->vcm_driver = &ov8858_vcms[OV8858_ID_DEFAULT];
-
- v4l2_i2c_subdev_init(&(dev->sd), client, &ov8858_ops);
-
- pdata = gmin_camera_platform_data(&dev->sd,
- ATOMISP_INPUT_FORMAT_RAW_10,
- atomisp_bayer_order_bggr);
- if (!pdata) {
- dev_err(&client->dev,
- "%s: failed to get acpi platform data\n",
- __func__);
- goto out_free;
- }
- ret = ov8858_s_config(&dev->sd, client->irq, pdata);
- if (ret) {
- dev_err(&client->dev,
- "%s: failed to set config\n", __func__);
- goto out_free;
- }
- ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
- if (ret) {
- dev_err(&client->dev,
- "%s: failed to register subdev\n", __func__);
- goto out_free;
- }
-
- /*
- * sd->name is updated with sensor driver name by the v4l2.
- * change it to sensor name in this case.
- */
- snprintf(dev->sd.name, sizeof(dev->sd.name), "%s%x %d-%04x",
- OV_SUBDEV_PREFIX, dev->sensor_id,
- i2c_adapter_id(client->adapter), client->addr);
-
- dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- dev->pad.flags = MEDIA_PAD_FL_SOURCE;
- dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
- dev->sd.entity.ops = &ov_entity_ops;
- dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-
- ret = v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ctrls) + 1);
- if (ret) {
- ov8858_remove(client);
- return ret;
- }
-
- dev->run_mode = v4l2_ctrl_new_custom(&dev->ctrl_handler,
- &ctrl_run_mode, NULL);
-
- for (i = 0; i < ARRAY_SIZE(ctrls); i++)
- v4l2_ctrl_new_custom(&dev->ctrl_handler, &ctrls[i], NULL);
-
- if (dev->ctrl_handler.error) {
- ov8858_remove(client);
- return dev->ctrl_handler.error;
- }
-
- /* Use same lock for controls as for everything else. */
- dev->ctrl_handler.lock = &dev->input_lock;
- dev->sd.ctrl_handler = &dev->ctrl_handler;
- v4l2_ctrl_handler_setup(&dev->ctrl_handler);
-
- ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
- if (ret) {
- ov8858_remove(client);
- return ret;
- }
-
- return 0;
-
-out_free:
- v4l2_device_unregister_subdev(&dev->sd);
- kfree(dev);
- return ret;
-}
-
-static const struct acpi_device_id ov8858_acpi_match[] = {
- {"INT3477"},
- {},
-};
-MODULE_DEVICE_TABLE(acpi, ov8858_acpi_match);
-
-static struct i2c_driver ov8858_driver = {
- .driver = {
- .name = "ov8858",
- .acpi_match_table = ov8858_acpi_match,
- },
- .probe_new = ov8858_probe,
- .remove = ov8858_remove,
-};
-module_i2c_driver(ov8858_driver);
-
-MODULE_DESCRIPTION("A low-level driver for Omnivision OV8858 sensors");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/ov8858.h b/drivers/staging/media/atomisp/i2c/ov8858.h
deleted file mode 100644
index 6c89568bb44e..000000000000
--- a/drivers/staging/media/atomisp/i2c/ov8858.h
+++ /dev/null
@@ -1,1474 +0,0 @@
-/*
- * Support for the Omnivision OV8858 camera sensor.
- *
- * Copyright (c) 2014 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as 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 __OV8858_H__
-#define __OV8858_H__
-#include "../include/linux/atomisp_platform.h"
-#include <media/v4l2-ctrls.h>
-
-#define I2C_MSG_LENGTH 0x2
-
-/*
- * This should be added into include/linux/videodev2.h
- * NOTE: This is most likely not used anywhere.
- */
-#define V4L2_IDENT_OV8858 V4L2_IDENT_UNKNOWN
-
-/*
- * Indexes for VCM driver lists
- */
-#define OV8858_ID_DEFAULT 0
-#define OV8858_SUNNY 1
-
-#define OV8858_OTP_START_ADDR 0x7010
-#define OV8858_OTP_END_ADDR 0x7186
-
-/*
- * ov8858 System control registers
- */
-
-#define OV8858_OTP_LOAD_CTRL 0x3D81
-#define OV8858_OTP_MODE_CTRL 0x3D84
-#define OV8858_OTP_START_ADDR_REG 0x3D88
-#define OV8858_OTP_END_ADDR_REG 0x3D8A
-#define OV8858_OTP_ISP_CTRL2 0x5002
-
-#define OV8858_OTP_MODE_MANUAL BIT(6)
-#define OV8858_OTP_MODE_PROGRAM_DISABLE BIT(7)
-#define OV8858_OTP_LOAD_ENABLE BIT(0)
-#define OV8858_OTP_DPC_ENABLE BIT(3)
-
-#define OV8858_PLL1_PREDIV0 0x030A
-#define OV8858_PLL1_PREDIV 0x0300
-#define OV8858_PLL1_MULTIPLIER 0x0301
-#define OV8858_PLL1_SYS_PRE_DIV 0x0305
-#define OV8858_PLL1_SYS_DIVIDER 0x0306
-
-#define OV8858_PLL1_PREDIV0_MASK BIT(0)
-#define OV8858_PLL1_PREDIV_MASK (BIT(0) | BIT(1) | BIT(2))
-#define OV8858_PLL1_MULTIPLIER_MASK 0x01FF
-#define OV8858_PLL1_SYS_PRE_DIV_MASK (BIT(0) | BIT(1))
-#define OV8858_PLL1_SYS_DIVIDER_MASK BIT(0)
-
-#define OV8858_PLL2_PREDIV0 0x0312
-#define OV8858_PLL2_PREDIV 0x030B
-#define OV8858_PLL2_MULTIPLIER 0x030C
-#define OV8858_PLL2_DAC_DIVIDER 0x0312
-#define OV8858_PLL2_SYS_PRE_DIV 0x030F
-#define OV8858_PLL2_SYS_DIVIDER 0x030E
-
-#define OV8858_PLL2_PREDIV0_MASK BIT(4)
-#define OV8858_PLL2_PREDIV_MASK (BIT(0) | BIT(1) | BIT(2))
-#define OV8858_PLL2_MULTIPLIER_MASK 0x01FF
-#define OV8858_PLL2_DAC_DIVIDER_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
-#define OV8858_PLL2_SYS_PRE_DIV_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
-#define OV8858_PLL2_SYS_DIVIDER_MASK (BIT(0) | BIT(1) | BIT(2))
-
-#define OV8858_PLL_SCLKSEL1 0x3032
-#define OV8858_PLL_SCLKSEL2 0x3033
-#define OV8858_SRB_HOST_INPUT_DIS 0x3106
-
-#define OV8858_PLL_SCLKSEL1_MASK BIT(7)
-#define OV8858_PLL_SCLKSEL2_MASK BIT(1)
-
-#define OV8858_SYS_PRE_DIV_OFFSET 2
-#define OV8858_SYS_PRE_DIV_MASK (BIT(2) | BIT(3))
-#define OV8858_SCLK_PDIV_OFFSET 4
-#define OV8858_SCLK_PDIV_MASK (BIT(4) | BIT(5) | BIT(6) | BIT(7))
-
-#define OV8858_TIMING_HTS 0x380C
-#define OV8858_TIMING_VTS 0x380E
-
-#define OV8858_HORIZONTAL_START_H 0x3800
-#define OV8858_VERTICAL_START_H 0x3802
-#define OV8858_HORIZONTAL_END_H 0x3804
-#define OV8858_VERTICAL_END_H 0x3806
-#define OV8858_HORIZONTAL_OUTPUT_SIZE_H 0x3808
-#define OV8858_VERTICAL_OUTPUT_SIZE_H 0x380A
-
-#define OV8858_GROUP_ACCESS 0x3208
-#define OV8858_GROUP_ZERO 0x00
-#define OV8858_GROUP_ACCESS_HOLD_START 0x00
-#define OV8858_GROUP_ACCESS_HOLD_END 0x10
-#define OV8858_GROUP_ACCESS_DELAY_LAUNCH 0xA0
-#define OV8858_GROUP_ACCESS_QUICK_LAUNCH 0xE0
-
-#define OV_SUBDEV_PREFIX "ov"
-#define OV_ID_DEFAULT 0x0000
-#define OV8858_CHIP_ID 0x8858
-
-#define OV8858_LONG_EXPO 0x3500
-#define OV8858_LONG_GAIN 0x3508
-#define OV8858_LONG_DIGI_GAIN 0x350A
-#define OV8858_SHORT_GAIN 0x350C
-#define OV8858_SHORT_DIGI_GAIN 0x350E
-
-#define OV8858_FORMAT1 0x3820
-#define OV8858_FORMAT2 0x3821
-
-#define OV8858_FLIP_ENABLE 0x06
-
-#define OV8858_MWB_RED_GAIN_H 0x5032
-#define OV8858_MWB_GREEN_GAIN_H 0x5034
-#define OV8858_MWB_BLUE_GAIN_H 0x5036
-#define OV8858_MWB_GAIN_MAX 0x0FFF
-
-#define OV8858_CHIP_ID_HIGH 0x300B
-#define OV8858_CHIP_ID_LOW 0x300C
-#define OV8858_STREAM_MODE 0x0100
-
-#define OV8858_FOCAL_LENGTH_NUM 294 /* 2.94mm */
-#define OV8858_FOCAL_LENGTH_DEM 100
-#define OV8858_F_NUMBER_DEFAULT_NUM 24 /* 2.4 */
-#define OV8858_F_NUMBER_DEM 10
-
-#define OV8858_H_INC_ODD 0x3814
-#define OV8858_H_INC_EVEN 0x3815
-#define OV8858_V_INC_ODD 0x382A
-#define OV8858_V_INC_EVEN 0x382B
-
-#define OV8858_READ_MODE_BINNING_ON 0x0400 /* ToDo: Check this */
-#define OV8858_READ_MODE_BINNING_OFF 0x00 /* ToDo: Check this */
-#define OV8858_BIN_FACTOR_MAX 2
-#define OV8858_INTEGRATION_TIME_MARGIN 14
-
-#define OV8858_MAX_VTS_VALUE 0xFFFF
-#define OV8858_MAX_EXPOSURE_VALUE \
- (OV8858_MAX_VTS_VALUE - OV8858_INTEGRATION_TIME_MARGIN)
-#define OV8858_MAX_GAIN_VALUE 0x07FF
-
-#define OV8858_MAX_FOCUS_POS 1023
-
-#define OV8858_TEST_PATTERN_REG 0x5E00
-
-struct ov8858_vcm {
- int (*power_up)(struct v4l2_subdev *sd);
- int (*power_down)(struct v4l2_subdev *sd);
- int (*init)(struct v4l2_subdev *sd);
- int (*t_focus_abs)(struct v4l2_subdev *sd, s32 value);
- int (*t_focus_rel)(struct v4l2_subdev *sd, s32 value);
- int (*q_focus_status)(struct v4l2_subdev *sd, s32 *value);
- int (*q_focus_abs)(struct v4l2_subdev *sd, s32 *value);
- int (*t_vcm_slew)(struct v4l2_subdev *sd, s32 value);
- int (*t_vcm_timing)(struct v4l2_subdev *sd, s32 value);
-};
-
-/*
- * Defines for register writes and register array processing
- * */
-#define OV8858_BYTE_MAX 32
-#define OV8858_SHORT_MAX 16
-#define OV8858_TOK_MASK 0xFFF0
-
-#define MAX_FPS_OPTIONS_SUPPORTED 3
-
-#define OV8858_DEPTH_COMP_CONST 2200
-#define OV8858_DEPTH_VTS_CONST 2573
-
-enum ov8858_tok_type {
- OV8858_8BIT = 0x0001,
- OV8858_16BIT = 0x0002,
- OV8858_TOK_TERM = 0xF000, /* terminating token for reg list */
- OV8858_TOK_DELAY = 0xFE00 /* delay token for reg list */
-};
-
-/*
- * If register address or register width is not 32 bit width,
- * user needs to convert it manually
- */
-struct s_register_setting {
- u32 reg;
- u32 val;
-};
-
-/**
- * struct ov8858_reg - MI sensor register format
- * @type: type of the register
- * @reg: 16-bit offset to register
- * @val: 8/16/32-bit register value
- *
- * Define a structure for sensor register initialization values
- */
-struct ov8858_reg {
- enum ov8858_tok_type type;
- u16 sreg;
- u32 val; /* @set value for read/mod/write, @mask */
-};
-
-struct ov8858_fps_setting {
- int fps;
- unsigned short pixels_per_line;
- unsigned short lines_per_frame;
- const struct ov8858_reg *regs; /* regs that the fps setting needs */
-};
-
-struct ov8858_resolution {
- u8 *desc;
- const struct ov8858_reg *regs;
- int res;
- int width;
- int height;
- bool used;
- u8 bin_factor_x;
- u8 bin_factor_y;
- unsigned short skip_frames;
- const struct ov8858_fps_setting fps_options[MAX_FPS_OPTIONS_SUPPORTED];
-};
-
-/*
- * ov8858 device structure
- * */
-struct ov8858_device {
- struct v4l2_subdev sd;
- struct media_pad pad;
- struct v4l2_mbus_framefmt format;
-
- struct camera_sensor_platform_data *platform_data;
- struct mutex input_lock; /* serialize sensor's ioctl */
- int fmt_idx;
- int streaming;
- int vt_pix_clk_freq_mhz;
- int fps_index;
- u16 sensor_id; /* Sensor id from registers */
- u16 i2c_id; /* Sensor id from i2c_device_id */
- int exposure;
- int gain;
- u16 digital_gain;
- u16 pixels_per_line;
- u16 lines_per_frame;
- u8 fps;
- u8 *otp_data;
- /* Prevent the framerate from being lowered in low light scenes. */
- int limit_exposure_flag;
- bool hflip;
- bool vflip;
-
- const struct ov8858_reg *regs;
- struct ov8858_vcm *vcm_driver;
- const struct ov8858_resolution *curr_res_table;
- unsigned long entries_curr_table;
-
- struct v4l2_ctrl_handler ctrl_handler;
- struct v4l2_ctrl *run_mode;
-};
-
-#define to_ov8858_sensor(x) container_of(x, struct ov8858_device, sd)
-
-#define OV8858_MAX_WRITE_BUF_SIZE 32
-struct ov8858_write_buffer {
- u16 addr;
- u8 data[OV8858_MAX_WRITE_BUF_SIZE];
-};
-
-struct ov8858_write_ctrl {
- int index;
- struct ov8858_write_buffer buffer;
-};
-
-static const struct ov8858_reg ov8858_soft_standby[] = {
- {OV8858_8BIT, 0x0100, 0x00},
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_streaming[] = {
- {OV8858_8BIT, 0x0100, 0x01},
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_param_hold[] = {
- {OV8858_8BIT, OV8858_GROUP_ACCESS,
- OV8858_GROUP_ZERO | OV8858_GROUP_ACCESS_HOLD_START},
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_param_update[] = {
- {OV8858_8BIT, OV8858_GROUP_ACCESS,
- OV8858_GROUP_ZERO | OV8858_GROUP_ACCESS_HOLD_END},
- {OV8858_8BIT, OV8858_GROUP_ACCESS,
- OV8858_GROUP_ZERO | OV8858_GROUP_ACCESS_DELAY_LAUNCH},
- {OV8858_TOK_TERM, 0, 0}
-};
-
-extern int dw9718_vcm_power_up(struct v4l2_subdev *sd);
-extern int dw9718_vcm_power_down(struct v4l2_subdev *sd);
-extern int dw9718_vcm_init(struct v4l2_subdev *sd);
-extern int dw9718_t_focus_abs(struct v4l2_subdev *sd, s32 value);
-extern int dw9718_t_focus_rel(struct v4l2_subdev *sd, s32 value);
-extern int dw9718_q_focus_status(struct v4l2_subdev *sd, s32 *value);
-extern int dw9718_q_focus_abs(struct v4l2_subdev *sd, s32 *value);
-extern int dw9718_t_vcm_slew(struct v4l2_subdev *sd, s32 value);
-extern int dw9718_t_vcm_timing(struct v4l2_subdev *sd, s32 value);
-
-extern int vcm_power_up(struct v4l2_subdev *sd);
-extern int vcm_power_down(struct v4l2_subdev *sd);
-
-static struct ov8858_vcm ov8858_vcms[] = {
- [OV8858_SUNNY] = {
- .power_up = dw9718_vcm_power_up,
- .power_down = dw9718_vcm_power_down,
- .init = dw9718_vcm_init,
- .t_focus_abs = dw9718_t_focus_abs,
- .t_focus_rel = dw9718_t_focus_rel,
- .q_focus_status = dw9718_q_focus_status,
- .q_focus_abs = dw9718_q_focus_abs,
- .t_vcm_slew = dw9718_t_vcm_slew,
- .t_vcm_timing = dw9718_t_vcm_timing,
- },
- [OV8858_ID_DEFAULT] = {
- .power_up = NULL,
- .power_down = NULL,
- },
-};
-
-
-#define OV8858_RES_WIDTH_MAX 3280
-#define OV8858_RES_HEIGHT_MAX 2464
-
-static struct ov8858_reg ov8858_BasicSettings[] = {
- {OV8858_8BIT, 0x0103, 0x01}, /* software_reset */
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- /* PLL settings */
- {OV8858_8BIT, 0x0300, 0x05}, /* pll1_pre_div = /4 */
- {OV8858_8BIT, 0x0302, 0xAF}, /* pll1_multiplier = 175 */
- {OV8858_8BIT, 0x0303, 0x00}, /* pll1_divm = /(1 + 0) */
- {OV8858_8BIT, 0x0304, 0x03}, /* pll1_div_mipi = /8 */
- {OV8858_8BIT, 0x030B, 0x02}, /* pll2_pre_div = /2 */
- {OV8858_8BIT, 0x030D, 0x4E}, /* pll2_r_divp = 78 */
- {OV8858_8BIT, 0x030E, 0x00}, /* pll2_r_divs = /1 */
- {OV8858_8BIT, 0x030F, 0x04}, /* pll2_r_divsp = /(1 + 4) */
- /* pll2_pre_div0 = /1, pll2_r_divdac = /(1 + 1) */
- {OV8858_8BIT, 0x0312, 0x01},
- {OV8858_8BIT, 0x031E, 0x0C}, /* pll1_no_lat = 1, mipi_bitsel_man = 0 */
-
- /* PAD OEN2, VSYNC out enable=0x80, disable=0x00 */
- {OV8858_8BIT, 0x3002, 0x80},
- /* PAD OUT2, VSYNC pulse direction low-to-high = 1 */
- {OV8858_8BIT, 0x3007, 0x01},
- /* PAD SEL2, VSYNC out value = 0 */
- {OV8858_8BIT, 0x300D, 0x00},
- /* PAD OUT2, VSYNC out select = 0 */
- {OV8858_8BIT, 0x3010, 0x00},
-
- /* Npump clock div = /2, Ppump clock div = /4 */
- {OV8858_8BIT, 0x3015, 0x01},
- /*
- * mipi_lane_mode = 1+3, mipi_lvds_sel = 1 = MIPI enable,
- * r_phy_pd_mipi_man = 0, lane_dis_option = 0
- */
- {OV8858_8BIT, 0x3018, 0x72},
- /* Clock switch output = normal, pclk_div = /1 */
- {OV8858_8BIT, 0x3020, 0x93},
- /*
- * lvds_mode_o = 0, clock lane disable when pd_mipi = 0,
- * pd_mipi enable when rst_sync = 1
- */
- {OV8858_8BIT, 0x3022, 0x01},
- {OV8858_8BIT, 0x3031, 0x0A}, /* mipi_bit_sel = 10 */
- {OV8858_8BIT, 0x3034, 0x00}, /* Unknown */
- /* sclk_div = /1, sclk_pre_div = /1, chip debug = 1 */
- {OV8858_8BIT, 0x3106, 0x01},
-
- {OV8858_8BIT, 0x3305, 0xF1}, /* Unknown */
- {OV8858_8BIT, 0x3307, 0x04}, /* Unknown */
- {OV8858_8BIT, 0x3308, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3309, 0x28}, /* Unknown */
- {OV8858_8BIT, 0x330A, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x330B, 0x20}, /* Unknown */
- {OV8858_8BIT, 0x330C, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x330D, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x330E, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x330F, 0x40}, /* Unknown */
-
- {OV8858_8BIT, 0x3500, 0x00}, /* long exposure = 0x9A20 */
- {OV8858_8BIT, 0x3501, 0x9A}, /* long exposure = 0x9A20 */
- {OV8858_8BIT, 0x3502, 0x20}, /* long exposure = 0x9A20 */
- /*
- * Digital fraction gain delay option = Delay 1 frame,
- * Gain change delay option = Delay 1 frame,
- * Gain delay option = Delay 1 frame,
- * Gain manual as sensor gain = Input gain as real gain format,
- * Exposure delay option (must be 0 = Delay 1 frame,
- * Exposure change delay option (must be 0) = Delay 1 frame
- */
- {OV8858_8BIT, 0x3503, 0x00},
- {OV8858_8BIT, 0x3505, 0x80}, /* gain conversation option */
- /*
- * [10:7] are integer gain, [6:0] are fraction gain. For example:
- * 0x80 is 1x gain, 0x100 is 2x gain, 0x1C0 is 3.5x gain
- */
- {OV8858_8BIT, 0x3508, 0x02}, /* long gain = 0x0200 */
- {OV8858_8BIT, 0x3509, 0x00}, /* long gain = 0x0200 */
- {OV8858_8BIT, 0x350C, 0x00}, /* short gain = 0x0080 */
- {OV8858_8BIT, 0x350D, 0x80}, /* short gain = 0x0080 */
- {OV8858_8BIT, 0x3510, 0x00}, /* short exposure = 0x000200 */
- {OV8858_8BIT, 0x3511, 0x02}, /* short exposure = 0x000200 */
- {OV8858_8BIT, 0x3512, 0x00}, /* short exposure = 0x000200 */
-
- {OV8858_8BIT, 0x3600, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3601, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3602, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3603, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3604, 0x22}, /* Unknown */
- {OV8858_8BIT, 0x3605, 0x30}, /* Unknown */
- {OV8858_8BIT, 0x3606, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3607, 0x20}, /* Unknown */
- {OV8858_8BIT, 0x3608, 0x11}, /* Unknown */
- {OV8858_8BIT, 0x3609, 0x28}, /* Unknown */
- {OV8858_8BIT, 0x360A, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x360B, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x360C, 0xDC}, /* Unknown */
- {OV8858_8BIT, 0x360D, 0x40}, /* Unknown */
- {OV8858_8BIT, 0x360E, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x360F, 0x20}, /* Unknown */
- {OV8858_8BIT, 0x3610, 0x07}, /* Unknown */
- {OV8858_8BIT, 0x3611, 0x20}, /* Unknown */
- {OV8858_8BIT, 0x3612, 0x88}, /* Unknown */
- {OV8858_8BIT, 0x3613, 0x80}, /* Unknown */
- {OV8858_8BIT, 0x3614, 0x58}, /* Unknown */
- {OV8858_8BIT, 0x3615, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3616, 0x4A}, /* Unknown */
- {OV8858_8BIT, 0x3617, 0x90}, /* Unknown */
- {OV8858_8BIT, 0x3618, 0x56}, /* Unknown */
- {OV8858_8BIT, 0x3619, 0x70}, /* Unknown */
- {OV8858_8BIT, 0x361A, 0x99}, /* Unknown */
- {OV8858_8BIT, 0x361B, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x361C, 0x07}, /* Unknown */
- {OV8858_8BIT, 0x361D, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x361E, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x361F, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3633, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x3634, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x3635, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x3636, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x3638, 0xFF}, /* Unknown */
- {OV8858_8BIT, 0x3645, 0x13}, /* Unknown */
- {OV8858_8BIT, 0x3646, 0x83}, /* Unknown */
- {OV8858_8BIT, 0x364A, 0x07}, /* Unknown */
-
- {OV8858_8BIT, 0x3700, 0x30}, /* Unknown */
- {OV8858_8BIT, 0x3701, 0x18}, /* Unknown */
- {OV8858_8BIT, 0x3702, 0x50}, /* Unknown */
- {OV8858_8BIT, 0x3703, 0x32}, /* Unknown */
- {OV8858_8BIT, 0x3704, 0x28}, /* Unknown */
- {OV8858_8BIT, 0x3705, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3706, 0x6A}, /* Unknown */
- {OV8858_8BIT, 0x3707, 0x08}, /* Unknown */
- {OV8858_8BIT, 0x3708, 0x48}, /* Unknown */
- {OV8858_8BIT, 0x3709, 0x66}, /* Unknown */
- {OV8858_8BIT, 0x370A, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x370B, 0x6A}, /* Unknown */
- {OV8858_8BIT, 0x370C, 0x07}, /* Unknown */
- {OV8858_8BIT, 0x3712, 0x44}, /* Unknown */
- {OV8858_8BIT, 0x3714, 0x24}, /* Unknown */
- {OV8858_8BIT, 0x3718, 0x14}, /* Unknown */
- {OV8858_8BIT, 0x3719, 0x31}, /* Unknown */
- {OV8858_8BIT, 0x371E, 0x31}, /* Unknown */
- {OV8858_8BIT, 0x371F, 0x7F}, /* Unknown */
- {OV8858_8BIT, 0x3720, 0x0A}, /* Unknown */
- {OV8858_8BIT, 0x3721, 0x0A}, /* Unknown */
- {OV8858_8BIT, 0x3724, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x3725, 0x02}, /* Unknown */
- {OV8858_8BIT, 0x3726, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x3728, 0x0A}, /* Unknown */
- {OV8858_8BIT, 0x3729, 0x03}, /* Unknown */
- {OV8858_8BIT, 0x372A, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x372B, 0xA6}, /* Unknown */
- {OV8858_8BIT, 0x372C, 0xA6}, /* Unknown */
- {OV8858_8BIT, 0x372D, 0xA6}, /* Unknown */
- {OV8858_8BIT, 0x372E, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x372F, 0x20}, /* Unknown */
- {OV8858_8BIT, 0x3730, 0x02}, /* Unknown */
- {OV8858_8BIT, 0x3731, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x3732, 0x28}, /* Unknown */
- {OV8858_8BIT, 0x3733, 0x10}, /* Unknown */
- {OV8858_8BIT, 0x3734, 0x40}, /* Unknown */
- {OV8858_8BIT, 0x3736, 0x30}, /* Unknown */
- {OV8858_8BIT, 0x373A, 0x0A}, /* Unknown */
- {OV8858_8BIT, 0x373B, 0x0B}, /* Unknown */
- {OV8858_8BIT, 0x373C, 0x14}, /* Unknown */
- {OV8858_8BIT, 0x373E, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x3755, 0x10}, /* Unknown */
- {OV8858_8BIT, 0x3758, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3759, 0x4C}, /* Unknown */
- {OV8858_8BIT, 0x375A, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x375B, 0x26}, /* Unknown */
- {OV8858_8BIT, 0x375C, 0x20}, /* Unknown */
- {OV8858_8BIT, 0x375D, 0x04}, /* Unknown */
- {OV8858_8BIT, 0x375E, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x375F, 0x28}, /* Unknown */
- {OV8858_8BIT, 0x3760, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3761, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3762, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3763, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3766, 0xFF}, /* Unknown */
- {OV8858_8BIT, 0x3768, 0x22}, /* Unknown */
- {OV8858_8BIT, 0x3769, 0x44}, /* Unknown */
- {OV8858_8BIT, 0x376A, 0x44}, /* Unknown */
- {OV8858_8BIT, 0x376B, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x376F, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x3772, 0x46}, /* Unknown */
- {OV8858_8BIT, 0x3773, 0x04}, /* Unknown */
- {OV8858_8BIT, 0x3774, 0x2C}, /* Unknown */
- {OV8858_8BIT, 0x3775, 0x13}, /* Unknown */
- {OV8858_8BIT, 0x3776, 0x08}, /* Unknown */
- {OV8858_8BIT, 0x3777, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */
- {OV8858_8BIT, 0x37A0, 0x88}, /* Unknown */
- {OV8858_8BIT, 0x37A1, 0x7A}, /* Unknown */
- {OV8858_8BIT, 0x37A2, 0x7A}, /* Unknown */
- {OV8858_8BIT, 0x37A3, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37A4, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37A5, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37A6, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37A7, 0x88}, /* Unknown */
- {OV8858_8BIT, 0x37A8, 0x98}, /* Unknown */
- {OV8858_8BIT, 0x37A9, 0x98}, /* Unknown */
- {OV8858_8BIT, 0x37AA, 0x88}, /* Unknown */
- {OV8858_8BIT, 0x37AB, 0x5C}, /* Unknown */
- {OV8858_8BIT, 0x37AC, 0x5C}, /* Unknown */
- {OV8858_8BIT, 0x37AD, 0x55}, /* Unknown */
- {OV8858_8BIT, 0x37AE, 0x19}, /* Unknown */
- {OV8858_8BIT, 0x37AF, 0x19}, /* Unknown */
- {OV8858_8BIT, 0x37B0, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37B1, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37B2, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37B3, 0x84}, /* Unknown */
- {OV8858_8BIT, 0x37B4, 0x84}, /* Unknown */
- {OV8858_8BIT, 0x37B5, 0x66}, /* Unknown */
- {OV8858_8BIT, 0x37B6, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37B7, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37B8, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37B9, 0xFF}, /* Unknown */
-
- {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low */
- {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */
- {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high */
- {OV8858_8BIT, 0x3809, 0xC0}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x09}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0x90}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */
- {OV8858_8BIT, 0x3810, 0x00}, /* h_win offset high */
- {OV8858_8BIT, 0x3811, 0x04}, /* h_win offset low */
- {OV8858_8BIT, 0x3812, 0x00}, /* v_win offset high */
- {OV8858_8BIT, 0x3813, 0x02}, /* v_win offset low */
- {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x40}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
-
- {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x3837, 0x18}, /* Unknown */
- {OV8858_8BIT, 0x3841, 0xFF}, /* AUTO_SIZE_CTRL */
- {OV8858_8BIT, 0x3846, 0x48}, /* Unknown */
-
- {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3D8C, 0x73}, /* OTP_SETTING_STT_ADDRESS */
- {OV8858_8BIT, 0x3D8D, 0xDE}, /* OTP_SETTING_STT_ADDRESS */
- {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */
- {OV8858_8BIT, 0x3F0A, 0x80}, /* PSRAM control register */
-
- {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */
- {OV8858_8BIT, 0x4001, 0x00}, /* BLC CTRL01 */
- {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */
- {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */
- {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */
- {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */
- {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */
- {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */
- {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */
- {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4022, 0x0B}, /* Anchor left end = 0x0BC3 */
- {OV8858_8BIT, 0x4023, 0xC3}, /* Anchor left end = 0x0BC3 */
- {OV8858_8BIT, 0x4024, 0x0C}, /* Anchor right start = 0x0C36 */
- {OV8858_8BIT, 0x4025, 0x36}, /* Anchor right start = 0x0C36 */
- {OV8858_8BIT, 0x4026, 0x0C}, /* Anchor right end = 0x0C37 */
- {OV8858_8BIT, 0x4027, 0x37}, /* Anchor right end = 0x0C37 */
- {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */
- {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */
- {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */
- {OV8858_8BIT, 0x402B, 0x08}, /* Top black line number = 8 */
- {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */
- {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */
- {OV8858_8BIT, 0x402E, 0x0C}, /* Bottom black line start = 12 */
- {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */
-
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4300, 0xFF}, /* clip_max[11:4] = 0xFFF */
- {OV8858_8BIT, 0x4301, 0x00}, /* clip_min[11:4] = 0 */
- {OV8858_8BIT, 0x4302, 0x0F}, /* clip_min/max[3:0] */
- {OV8858_8BIT, 0x4307, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x4316, 0x00}, /* CTRL16 = default */
- {OV8858_8BIT, 0x4503, 0x18}, /* Unknown */
- {OV8858_8BIT, 0x4500, 0x38}, /* Unknown */
- {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */
- /* wkup_dly = Mark1 wakeup delay/2^10 = 0x25 */
- {OV8858_8BIT, 0x4808, 0x25},
- {OV8858_8BIT, 0x4816, 0x52}, /* Embedded data type*/
- {OV8858_8BIT, 0x481F, 0x32}, /* clk_prepare_min = 0x32 */
- {OV8858_8BIT, 0x4825, 0x3A}, /* lpx_p_min = 0x3A */
- {OV8858_8BIT, 0x4826, 0x40}, /* hs_prepare_min = 0x40 */
- {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */
- {OV8858_8BIT, 0x4850, 0x10}, /* LANE SEL01 */
- {OV8858_8BIT, 0x4851, 0x32}, /* LANE SEL02 */
-
- {OV8858_8BIT, 0x4B00, 0x2A}, /* Unknown */
- {OV8858_8BIT, 0x4B0D, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x4D00, 0x04}, /* TPM_CTRL_REG */
- {OV8858_8BIT, 0x4D01, 0x18}, /* TPM_CTRL_REG */
- {OV8858_8BIT, 0x4D02, 0xC3}, /* TPM_CTRL_REG */
- {OV8858_8BIT, 0x4D03, 0xFF}, /* TPM_CTRL_REG */
- {OV8858_8BIT, 0x4D04, 0xFF}, /* TPM_CTRL_REG */
- {OV8858_8BIT, 0x4D05, 0xFF}, /* TPM_CTRL_REG */
-
- /*
- * Lens correction (LENC) function enable = 0
- * Slave sensor AWB Gain function enable = 1
- * Slave sensor AWB Statistics function enable = 1
- * Master sensor AWB Gain function enable = 1
- * Master sensor AWB Statistics function enable = 1
- * Black DPC function enable = 1
- * White DPC function enable =1
- */
- {OV8858_8BIT, 0x5000, 0x7E},
- {OV8858_8BIT, 0x5001, 0x01}, /* BLC function enable = 1 */
- /*
- * Horizontal scale function enable = 0
- * WBMATCH bypass mode = Select slave sensor's gain
- * WBMATCH function enable = 0
- * Master MWB gain support RGBC = 0
- * OTP_DPC function enable = 1
- * Manual mode of VarioPixel function enable = 0
- * Manual enable of VarioPixel function enable = 0
- * Use VSYNC to latch ISP modules's function enable signals = 0
- */
- {OV8858_8BIT, 0x5002, 0x08},
- /*
- * Bypass all ISP modules after BLC module = 0
- * DPC_DBC buffer control enable = 1
- * WBMATCH VSYNC selection = Select master sensor's VSYNC fall
- * Select master AWB gain to embed line = AWB gain before manual mode
- * Enable BLC's input flip_i signal = 0
- */
- {OV8858_8BIT, 0x5003, 0x20},
- {OV8858_8BIT, 0x5041, 0x1D}, /* ISP CTRL41 - embedded data=on */
- {OV8858_8BIT, 0x5046, 0x12}, /* ISP CTRL46 = default */
- /*
- * Tail enable = 1
- * Saturate cross cluster enable = 1
- * Remove cross cluster enable = 1
- * Enable to remove connected defect pixels in same channel = 1
- * Enable to remove connected defect pixels in different channel = 1
- * Smooth enable, use average G for recovery = 1
- * Black/white sensor mode enable = 0
- * Manual mode enable = 0
- */
- {OV8858_8BIT, 0x5780, 0xFC},
- {OV8858_8BIT, 0x5784, 0x0C}, /* DPC CTRL04 */
- {OV8858_8BIT, 0x5787, 0x40}, /* DPC CTRL07 */
- {OV8858_8BIT, 0x5788, 0x08}, /* DPC CTRL08 */
- {OV8858_8BIT, 0x578A, 0x02}, /* DPC CTRL0A */
- {OV8858_8BIT, 0x578B, 0x01}, /* DPC CTRL0B */
- {OV8858_8BIT, 0x578C, 0x01}, /* DPC CTRL0C */
- {OV8858_8BIT, 0x578E, 0x02}, /* DPC CTRL0E */
- {OV8858_8BIT, 0x578F, 0x01}, /* DPC CTRL0F */
- {OV8858_8BIT, 0x5790, 0x01}, /* DPC CTRL10 */
- {OV8858_8BIT, 0x5901, 0x00}, /* VAP CTRL01 = default */
- /* WINC CTRL08 = embedded data in 1st line*/
- {OV8858_8BIT, 0x5A08, 0x00},
- {OV8858_8BIT, 0x5B00, 0x02}, /* OTP CTRL00 */
- {OV8858_8BIT, 0x5B01, 0x10}, /* OTP CTRL01 */
- {OV8858_8BIT, 0x5B02, 0x03}, /* OTP CTRL02 */
- {OV8858_8BIT, 0x5B03, 0xCF}, /* OTP CTRL03 */
- {OV8858_8BIT, 0x5B05, 0x6C}, /* OTP CTRL05 = default */
- {OV8858_8BIT, 0x5E00, 0x00}, /* PRE CTRL00 = default */
- {OV8858_8BIT, 0x5E01, 0x41}, /* PRE_CTRL01 = default */
-
- {OV8858_TOK_TERM, 0, 0}
-};
-
-/*****************************STILL********************************/
-
-static const struct ov8858_reg ov8858_8M[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low 12 */
- {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */
- {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low 3283 */
- {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high 3280 x 2464 */
- {OV8858_8BIT, 0x3809, 0xD0}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x09}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0xa0}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x40}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */
- {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */
- {OV8858_8BIT, 0x4001, 0x00}, /* BLC CTRL01 */
- {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */
- {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */
- {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */
- {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */
- {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */
- {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */
- {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */
- {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4022, 0x0B}, /* Anchor left end = 0x0BC3 */
- {OV8858_8BIT, 0x4023, 0xC3}, /* Anchor left end = 0x0BC3 */
- {OV8858_8BIT, 0x4024, 0x0C}, /* Anchor right start = 0x0C36 */
- {OV8858_8BIT, 0x4025, 0x36}, /* Anchor right start = 0x0C36 */
- {OV8858_8BIT, 0x4026, 0x0C}, /* Anchor right end = 0x0C37 */
- {OV8858_8BIT, 0x4027, 0x37}, /* Anchor right end = 0x0C37 */
- {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */
- {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */
- {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */
- {OV8858_8BIT, 0x402B, 0x08}, /* Top black line number = 8 */
- {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */
- {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */
- {OV8858_8BIT, 0x402E, 0x0C}, /* Bottom black line start = 12 */
- {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_3276x1848[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x10}, /* h_crop_start low 0c->10*/
- {OV8858_8BIT, 0x3802, 0x01}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x42}, /* v_crop_start low 3e->42*/
- {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */
- {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x08}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0x71}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high 3276 x 1848 */
- {OV8858_8BIT, 0x3809, 0xCC}, /* h_output_size low d0->cc*/
- {OV8858_8BIT, 0x380A, 0x07}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0x38}, /* v_output_size low 3c->38*/
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x40}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */
- {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */
- {OV8858_8BIT, 0x4001, 0x00}, /* BLC CTRL01 */
- {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */
- {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */
- {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */
- {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */
- {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */
- {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */
- {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */
- {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4022, 0x0B}, /* Anchor left end = 0x0BC3 */
- {OV8858_8BIT, 0x4023, 0xC3}, /* Anchor left end = 0x0BC3 */
- {OV8858_8BIT, 0x4024, 0x0C}, /* Anchor right start = 0x0C36 */
- {OV8858_8BIT, 0x4025, 0x36}, /* Anchor right start = 0x0C36 */
- {OV8858_8BIT, 0x4026, 0x0C}, /* Anchor right end = 0x0C37 */
- {OV8858_8BIT, 0x4027, 0x37}, /* Anchor right end = 0x0C37 */
- {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */
- {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */
- {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */
- {OV8858_8BIT, 0x402B, 0x08}, /* Top black line number = 8 */
- {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */
- {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */
- {OV8858_8BIT, 0x402E, 0x0C}, /* Bottom black line start = 12 */
- {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_6M[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low */
- {OV8858_8BIT, 0x3802, 0x01}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x3E}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */
- {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x08}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0x71}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high 3280 x 1852 */
- {OV8858_8BIT, 0x3809, 0xD0}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x07}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0x3C}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x40}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */
- {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */
- {OV8858_8BIT, 0x4001, 0x00}, /* BLC CTRL01 */
- {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */
- {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */
- {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */
- {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */
- {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */
- {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */
- {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */
- {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4022, 0x0B}, /* Anchor left end = 0x0BC3 */
- {OV8858_8BIT, 0x4023, 0xC3}, /* Anchor left end = 0x0BC3 */
- {OV8858_8BIT, 0x4024, 0x0C}, /* Anchor right start = 0x0C36 */
- {OV8858_8BIT, 0x4025, 0x36}, /* Anchor right start = 0x0C36 */
- {OV8858_8BIT, 0x4026, 0x0C}, /* Anchor right end = 0x0C37 */
- {OV8858_8BIT, 0x4027, 0x37}, /* Anchor right end = 0x0C37 */
- {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */
- {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */
- {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */
- {OV8858_8BIT, 0x402B, 0x08}, /* Top black line number = 8 */
- {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */
- {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */
- {OV8858_8BIT, 0x402E, 0x0C}, /* Bottom black line start = 12 */
- {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_1080P_60[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x17}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x02}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x26}, /* h_crop_start low */
- {OV8858_8BIT, 0x3802, 0x02}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x8C}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0A}, /* h_crop_end high */
- {OV8858_8BIT, 0x3805, 0x9D}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x07}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0x0A}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x07}, /* h_output_size high*/
- {OV8858_8BIT, 0x3809, 0x90}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0x48}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x04}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0xEC}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x40}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */
- {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */
- {OV8858_8BIT, 0x4001, 0x00}, /* BLC CTRL01 */
- {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */
- {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */
- {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */
- {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */
- {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */
- {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */
- {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */
- {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4022, 0x07}, /* Anchor left end = 0x072D */
- {OV8858_8BIT, 0x4023, 0x2D}, /* Anchor left end = 0x072D */
- {OV8858_8BIT, 0x4024, 0x07}, /* Anchor right start = 0x079E */
- {OV8858_8BIT, 0x4025, 0x9E}, /* Anchor right start = 0x079E */
- {OV8858_8BIT, 0x4026, 0x07}, /* Anchor right end = 0x079F */
- {OV8858_8BIT, 0x4027, 0x9F}, /* Anchor right end = 0x079F */
- {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */
- {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */
- {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */
- {OV8858_8BIT, 0x402B, 0x08}, /* Top black line number = 8 */
- {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */
- {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */
- {OV8858_8BIT, 0x402E, 0x0C}, /* Bottom black line start = 12 */
- {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0xef}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x16}, /* pclk_period = 0x16 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_1080P_30[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x17}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x02}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x26}, /* h_crop_start low */
- {OV8858_8BIT, 0x3802, 0x02}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x8C}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0A}, /* h_crop_end high */
- {OV8858_8BIT, 0x3805, 0x9D}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x07}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0x0A}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x07}, /* h_output_size high*/
- {OV8858_8BIT, 0x3809, 0x90}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0x48}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x40}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */
- {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */
- {OV8858_8BIT, 0x4001, 0x00}, /* BLC CTRL01 */
- {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */
- {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */
- {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */
- {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */
- {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */
- {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */
- {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */
- {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4022, 0x07}, /* Anchor left end = 0x072D */
- {OV8858_8BIT, 0x4023, 0x2D}, /* Anchor left end = 0x072D */
- {OV8858_8BIT, 0x4024, 0x07}, /* Anchor right start = 0x079E */
- {OV8858_8BIT, 0x4025, 0x9E}, /* Anchor right start = 0x079E */
- {OV8858_8BIT, 0x4026, 0x07}, /* Anchor right end = 0x079F */
- {OV8858_8BIT, 0x4027, 0x9F}, /* Anchor right end = 0x079F */
- {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */
- {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */
- {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */
- {OV8858_8BIT, 0x402B, 0x08}, /* Top black line number = 8 */
- {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */
- {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */
- {OV8858_8BIT, 0x402E, 0x0C}, /* Bottom black line start = 12 */
- {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0xef}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x16}, /* pclk_period = 0x16 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_1640x1232[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low 12 */
- {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high 3283 */
- {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x06}, /* h_output_size high 1640 x 1232 */
- {OV8858_8BIT, 0x3809, 0x68}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0xD0}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x09}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0xAA}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x03}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x67}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x03}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x08}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x02}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x16}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x08}, /* PSRAM control register */
- {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */
- {OV8858_8BIT, 0x4001, 0x10}, /* BLC CTRL01 */
- {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */
- {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */
- {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */
- {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */
- {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */
- {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */
- {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */
- {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4022, 0x04}, /* Anchor left end = 0x04B9 */
- {OV8858_8BIT, 0x4023, 0xB9}, /* Anchor left end = 0x04B9 */
- {OV8858_8BIT, 0x4024, 0x05}, /* Anchor right start = 0x052A */
- {OV8858_8BIT, 0x4025, 0x2A}, /* Anchor right start = 0x052A */
- {OV8858_8BIT, 0x4026, 0x05}, /* Anchor right end = 0x052B */
- {OV8858_8BIT, 0x4027, 0x2B}, /* Anchor right end = 0x052B */
- {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */
- {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */
- {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */
- {OV8858_8BIT, 0x402B, 0x04}, /* Top black line number = 8 */
- {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */
- {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */
- {OV8858_8BIT, 0x402E, 0x08}, /* Bottom black line start = 8 */
- {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0xCB}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_1640x1096[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low 12 */
- {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high 3283 */
- {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x06}, /* h_output_size high 1640 x 1096 */
- {OV8858_8BIT, 0x3809, 0x68}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0x48}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x09}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0xAA}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x03}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x67}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x03}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x08}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x02}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x16}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x08}, /* PSRAM control register */
- {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */
- {OV8858_8BIT, 0x4001, 0x10}, /* BLC CTRL01 */
- {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */
- {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */
- {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */
- {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */
- {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */
- {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */
- {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */
- {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4022, 0x04}, /* Anchor left end = 0x04B9 */
- {OV8858_8BIT, 0x4023, 0xB9}, /* Anchor left end = 0x04B9 */
- {OV8858_8BIT, 0x4024, 0x05}, /* Anchor right start = 0x052A */
- {OV8858_8BIT, 0x4025, 0x2A}, /* Anchor right start = 0x052A */
- {OV8858_8BIT, 0x4026, 0x05}, /* Anchor right end = 0x052B */
- {OV8858_8BIT, 0x4027, 0x2B}, /* Anchor right end = 0x052B */
- {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */
- {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */
- {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */
- {OV8858_8BIT, 0x402B, 0x04}, /* Top black line number = 8 */
- {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */
- {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */
- {OV8858_8BIT, 0x402E, 0x08}, /* Bottom black line start = 8 */
- {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0xCB}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-
-static const struct ov8858_reg ov8858_1640x926[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low */
- {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */
- {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x06}, /* h_output_size high 1640 x 926 */
- {OV8858_8BIT, 0x3809, 0x68}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x03}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0x9E}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x09}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0xAA}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x03}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x67}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x03}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x08}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x02}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x16}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x08}, /* PSRAM control register */
- {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */
- {OV8858_8BIT, 0x4001, 0x10}, /* BLC CTRL01 */
- {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */
- {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */
- {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */
- {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */
- {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */
- {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */
- {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */
- {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4022, 0x04}, /* Anchor left end = 0x04B9 */
- {OV8858_8BIT, 0x4023, 0xB9}, /* Anchor left end = 0x04B9 */
- {OV8858_8BIT, 0x4024, 0x05}, /* Anchor right start = 0x052A */
- {OV8858_8BIT, 0x4025, 0x2A}, /* Anchor right start = 0x052A */
- {OV8858_8BIT, 0x4026, 0x05}, /* Anchor right end = 0x052B */
- {OV8858_8BIT, 0x4027, 0x2B}, /* Anchor right end = 0x052B */
- {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */
- {OV8858_8BIT, 0x4029, 0x02}, /* Top zero line number = 2 */
- {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */
- {OV8858_8BIT, 0x402B, 0x04}, /* Top black line number = 8 */
- {OV8858_8BIT, 0x402C, 0x02}, /* Bottom zero start line = 2 */
- {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */
- {OV8858_8BIT, 0x402E, 0x08}, /* Bottom black line start = 8 */
- {OV8858_8BIT, 0x402F, 0x02}, /* Bottom black line number = 2 */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0xCB}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static struct ov8858_resolution ov8858_res_preview[] = {
- {
- .desc = "ov8858_1640x926_PREVIEW",
- .width = 1640,
- .height = 926,
- .used = 0,
- .regs = ov8858_1640x926,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 0,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_1640x1232_PREVIEW",
- .width = 1640,
- .height = 1232,
- .used = 0,
- .regs = ov8858_1640x1232,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 0,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_3276x1848_PREVIEW",
- .width = 3276,
- .height = 1848,
- .used = 0,
- .regs = ov8858_3276x1848,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 0,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_8M_PREVIEW",
- .width = 3280,
- .height = 2464,
- .used = 0,
- .regs = ov8858_8M,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 0,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
-};
-
-static struct ov8858_resolution ov8858_res_still[] = {
- {
- .desc = "ov8858_1640x1232_STILL",
- .width = 1640,
- .height = 1232,
- .used = 0,
- .regs = ov8858_1640x1232,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 0,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_1640x926_STILL",
- .width = 1640,
- .height = 926,
- .used = 0,
- .regs = ov8858_1640x926,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_3276X1848_STILL",
- .width = 3276,
- .height = 1848,
- .used = 0,
- .regs = ov8858_3276x1848,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_8M_STILL",
- .width = 3280,
- .height = 2464,
- .used = 0,
- .regs = ov8858_8M,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- /* Pixel clock: 149.76MHZ */
- .fps = 10,
- .pixels_per_line = 3880,
- .lines_per_frame = 3859,
- },
- {
- }
- },
- },
-};
-
-static struct ov8858_resolution ov8858_res_video[] = {
- {
- .desc = "ov8858_1640x926_VIDEO",
- .width = 1640,
- .height = 926,
- .used = 0,
- .regs = ov8858_1640x926,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_1640x1232_VIDEO",
- .width = 1640,
- .height = 1232,
- .used = 0,
- .regs = ov8858_1640x1232,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_1640x1096_VIDEO",
- .width = 1640,
- .height = 1096,
- .used = 0,
- .regs = ov8858_1640x1096,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_6M_VIDEO",
- .width = 3280,
- .height = 1852,
- .used = 0,
- .regs = ov8858_6M,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_8M_VIDEO",
- .width = 3280,
- .height = 2464,
- .used = 0,
- .regs = ov8858_8M,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
-};
-
-#endif /* __OV8858_H__ */
diff --git a/drivers/staging/media/atomisp/i2c/ov8858_btns.h b/drivers/staging/media/atomisp/i2c/ov8858_btns.h
deleted file mode 100644
index f81851306832..000000000000
--- a/drivers/staging/media/atomisp/i2c/ov8858_btns.h
+++ /dev/null
@@ -1,1276 +0,0 @@
-/*
- * Support for the Omnivision OV8858 camera sensor.
- *
- * Copyright (c) 2014 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as 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 __OV8858_H__
-#define __OV8858_H__
-#include "../include/linux/atomisp_platform.h"
-#include <media/v4l2-ctrls.h>
-
-#define I2C_MSG_LENGTH 0x2
-
-/*
- * This should be added into include/linux/videodev2.h
- * NOTE: This is most likely not used anywhere.
- */
-#define V4L2_IDENT_OV8858 V4L2_IDENT_UNKNOWN
-
-/*
- * Indexes for VCM driver lists
- */
-#define OV8858_ID_DEFAULT 0
-#define OV8858_SUNNY 1
-
-#define OV8858_OTP_START_ADDR 0x7010
-#define OV8858_OTP_END_ADDR 0x7186
-
-/*
- * ov8858 System control registers
- */
-
-#define OV8858_OTP_LOAD_CTRL 0x3D81
-#define OV8858_OTP_MODE_CTRL 0x3D84
-#define OV8858_OTP_START_ADDR_REG 0x3D88
-#define OV8858_OTP_END_ADDR_REG 0x3D8A
-#define OV8858_OTP_ISP_CTRL2 0x5002
-
-#define OV8858_OTP_MODE_MANUAL BIT(6)
-#define OV8858_OTP_MODE_PROGRAM_DISABLE BIT(7)
-#define OV8858_OTP_LOAD_ENABLE BIT(0)
-#define OV8858_OTP_DPC_ENABLE BIT(3)
-
-#define OV8858_PLL1_PREDIV0 0x030A
-#define OV8858_PLL1_PREDIV 0x0300
-#define OV8858_PLL1_MULTIPLIER 0x0301
-#define OV8858_PLL1_SYS_PRE_DIV 0x0305
-#define OV8858_PLL1_SYS_DIVIDER 0x0306
-
-#define OV8858_PLL1_PREDIV0_MASK BIT(0)
-#define OV8858_PLL1_PREDIV_MASK (BIT(0) | BIT(1) | BIT(2))
-#define OV8858_PLL1_MULTIPLIER_MASK 0x01FF
-#define OV8858_PLL1_SYS_PRE_DIV_MASK (BIT(0) | BIT(1))
-#define OV8858_PLL1_SYS_DIVIDER_MASK BIT(0)
-
-#define OV8858_PLL2_PREDIV0 0x0312
-#define OV8858_PLL2_PREDIV 0x030B
-#define OV8858_PLL2_MULTIPLIER 0x030C
-#define OV8858_PLL2_DAC_DIVIDER 0x0312
-#define OV8858_PLL2_SYS_PRE_DIV 0x030F
-#define OV8858_PLL2_SYS_DIVIDER 0x030E
-
-#define OV8858_PLL2_PREDIV0_MASK BIT(4)
-#define OV8858_PLL2_PREDIV_MASK (BIT(0) | BIT(1) | BIT(2))
-#define OV8858_PLL2_MULTIPLIER_MASK 0x01FF
-#define OV8858_PLL2_DAC_DIVIDER_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
-#define OV8858_PLL2_SYS_PRE_DIV_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
-#define OV8858_PLL2_SYS_DIVIDER_MASK (BIT(0) | BIT(1) | BIT(2))
-
-#define OV8858_PLL_SCLKSEL1 0x3032
-#define OV8858_PLL_SCLKSEL2 0x3033
-#define OV8858_SRB_HOST_INPUT_DIS 0x3106
-
-#define OV8858_PLL_SCLKSEL1_MASK BIT(7)
-#define OV8858_PLL_SCLKSEL2_MASK BIT(1)
-
-#define OV8858_SYS_PRE_DIV_OFFSET 2
-#define OV8858_SYS_PRE_DIV_MASK (BIT(2) | BIT(3))
-#define OV8858_SCLK_PDIV_OFFSET 4
-#define OV8858_SCLK_PDIV_MASK (BIT(4) | BIT(5) | BIT(6) | BIT(7))
-
-#define OV8858_TIMING_HTS 0x380C
-#define OV8858_TIMING_VTS 0x380E
-
-#define OV8858_HORIZONTAL_START_H 0x3800
-#define OV8858_VERTICAL_START_H 0x3802
-#define OV8858_HORIZONTAL_END_H 0x3804
-#define OV8858_VERTICAL_END_H 0x3806
-#define OV8858_HORIZONTAL_OUTPUT_SIZE_H 0x3808
-#define OV8858_VERTICAL_OUTPUT_SIZE_H 0x380A
-
-#define OV8858_GROUP_ACCESS 0x3208
-#define OV8858_GROUP_ZERO 0x00
-#define OV8858_GROUP_ACCESS_HOLD_START 0x00
-#define OV8858_GROUP_ACCESS_HOLD_END 0x10
-#define OV8858_GROUP_ACCESS_DELAY_LAUNCH 0xA0
-#define OV8858_GROUP_ACCESS_QUICK_LAUNCH 0xE0
-
-#define OV_SUBDEV_PREFIX "ov"
-#define OV_ID_DEFAULT 0x0000
-#define OV8858_CHIP_ID 0x8858
-
-#define OV8858_LONG_EXPO 0x3500
-#define OV8858_LONG_GAIN 0x3508
-#define OV8858_LONG_DIGI_GAIN 0x350A
-#define OV8858_SHORT_GAIN 0x350C
-#define OV8858_SHORT_DIGI_GAIN 0x350E
-
-#define OV8858_FORMAT1 0x3820
-#define OV8858_FORMAT2 0x3821
-
-#define OV8858_FLIP_ENABLE 0x06
-
-#define OV8858_MWB_RED_GAIN_H 0x5032
-#define OV8858_MWB_GREEN_GAIN_H 0x5034
-#define OV8858_MWB_BLUE_GAIN_H 0x5036
-#define OV8858_MWB_GAIN_MAX 0x0FFF
-
-#define OV8858_CHIP_ID_HIGH 0x300B
-#define OV8858_CHIP_ID_LOW 0x300C
-#define OV8858_STREAM_MODE 0x0100
-
-#define OV8858_FOCAL_LENGTH_NUM 294 /* 2.94mm */
-#define OV8858_FOCAL_LENGTH_DEM 100
-#define OV8858_F_NUMBER_DEFAULT_NUM 24 /* 2.4 */
-#define OV8858_F_NUMBER_DEM 10
-
-#define OV8858_H_INC_ODD 0x3814
-#define OV8858_H_INC_EVEN 0x3815
-#define OV8858_V_INC_ODD 0x382A
-#define OV8858_V_INC_EVEN 0x382B
-
-#define OV8858_READ_MODE_BINNING_ON 0x0400 /* ToDo: Check this */
-#define OV8858_READ_MODE_BINNING_OFF 0x00 /* ToDo: Check this */
-#define OV8858_BIN_FACTOR_MAX 2
-#define OV8858_INTEGRATION_TIME_MARGIN 14
-
-#define OV8858_MAX_VTS_VALUE 0xFFFF
-#define OV8858_MAX_EXPOSURE_VALUE \
- (OV8858_MAX_VTS_VALUE - OV8858_INTEGRATION_TIME_MARGIN)
-#define OV8858_MAX_GAIN_VALUE 0x07FF
-
-#define OV8858_MAX_FOCUS_POS 1023
-
-#define OV8858_TEST_PATTERN_REG 0x5E00
-
-struct ov8858_vcm {
- int (*power_up)(struct v4l2_subdev *sd);
- int (*power_down)(struct v4l2_subdev *sd);
- int (*init)(struct v4l2_subdev *sd);
- int (*t_focus_abs)(struct v4l2_subdev *sd, s32 value);
- int (*t_focus_rel)(struct v4l2_subdev *sd, s32 value);
- int (*q_focus_status)(struct v4l2_subdev *sd, s32 *value);
- int (*q_focus_abs)(struct v4l2_subdev *sd, s32 *value);
- int (*t_vcm_slew)(struct v4l2_subdev *sd, s32 value);
- int (*t_vcm_timing)(struct v4l2_subdev *sd, s32 value);
-};
-
-/*
- * Defines for register writes and register array processing
- * */
-#define OV8858_BYTE_MAX 32
-#define OV8858_SHORT_MAX 16
-#define OV8858_TOK_MASK 0xFFF0
-
-#define MAX_FPS_OPTIONS_SUPPORTED 3
-
-#define OV8858_DEPTH_COMP_CONST 2200
-#define OV8858_DEPTH_VTS_CONST 2573
-
-enum ov8858_tok_type {
- OV8858_8BIT = 0x0001,
- OV8858_16BIT = 0x0002,
- OV8858_TOK_TERM = 0xF000, /* terminating token for reg list */
- OV8858_TOK_DELAY = 0xFE00 /* delay token for reg list */
-};
-
-/*
- * If register address or register width is not 32 bit width,
- * user needs to convert it manually
- */
-struct s_register_setting {
- u32 reg;
- u32 val;
-};
-
-/**
- * struct ov8858_reg - MI sensor register format
- * @type: type of the register
- * @reg: 16-bit offset to register
- * @val: 8/16/32-bit register value
- *
- * Define a structure for sensor register initialization values
- */
-struct ov8858_reg {
- enum ov8858_tok_type type;
- u16 sreg;
- u32 val; /* @set value for read/mod/write, @mask */
-};
-
-struct ov8858_fps_setting {
- int fps;
- unsigned short pixels_per_line;
- unsigned short lines_per_frame;
- const struct ov8858_reg *regs; /* regs that the fps setting needs */
-};
-
-struct ov8858_resolution {
- u8 *desc;
- const struct ov8858_reg *regs;
- int res;
- int width;
- int height;
- bool used;
- u8 bin_factor_x;
- u8 bin_factor_y;
- unsigned short skip_frames;
- const struct ov8858_fps_setting fps_options[MAX_FPS_OPTIONS_SUPPORTED];
-};
-
-/*
- * ov8858 device structure
- * */
-struct ov8858_device {
- struct v4l2_subdev sd;
- struct media_pad pad;
- struct v4l2_mbus_framefmt format;
-
- struct camera_sensor_platform_data *platform_data;
- struct mutex input_lock; /* serialize sensor's ioctl */
- int fmt_idx;
- int streaming;
- int vt_pix_clk_freq_mhz;
- int fps_index;
- u16 sensor_id; /* Sensor id from registers */
- u16 i2c_id; /* Sensor id from i2c_device_id */
- int exposure;
- int gain;
- u16 digital_gain;
- u16 pixels_per_line;
- u16 lines_per_frame;
- u8 fps;
- u8 *otp_data;
- /* Prevent the framerate from being lowered in low light scenes. */
- int limit_exposure_flag;
- bool hflip;
- bool vflip;
-
- const struct ov8858_reg *regs;
- struct ov8858_vcm *vcm_driver;
- const struct ov8858_resolution *curr_res_table;
- unsigned long entries_curr_table;
-
- struct v4l2_ctrl_handler ctrl_handler;
- struct v4l2_ctrl *run_mode;
-};
-
-#define to_ov8858_sensor(x) container_of(x, struct ov8858_device, sd)
-
-#define OV8858_MAX_WRITE_BUF_SIZE 32
-struct ov8858_write_buffer {
- u16 addr;
- u8 data[OV8858_MAX_WRITE_BUF_SIZE];
-};
-
-struct ov8858_write_ctrl {
- int index;
- struct ov8858_write_buffer buffer;
-};
-
-static const struct ov8858_reg ov8858_soft_standby[] = {
- {OV8858_8BIT, 0x0100, 0x00},
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_streaming[] = {
- {OV8858_8BIT, 0x0100, 0x01},
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_param_hold[] = {
- {OV8858_8BIT, OV8858_GROUP_ACCESS,
- OV8858_GROUP_ZERO | OV8858_GROUP_ACCESS_HOLD_START},
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_param_update[] = {
- {OV8858_8BIT, OV8858_GROUP_ACCESS,
- OV8858_GROUP_ZERO | OV8858_GROUP_ACCESS_HOLD_END},
- {OV8858_8BIT, OV8858_GROUP_ACCESS,
- OV8858_GROUP_ZERO | OV8858_GROUP_ACCESS_DELAY_LAUNCH},
- {OV8858_TOK_TERM, 0, 0}
-};
-
-extern int dw9718_vcm_power_up(struct v4l2_subdev *sd);
-extern int dw9718_vcm_power_down(struct v4l2_subdev *sd);
-extern int dw9718_vcm_init(struct v4l2_subdev *sd);
-extern int dw9718_t_focus_abs(struct v4l2_subdev *sd, s32 value);
-extern int dw9718_t_focus_rel(struct v4l2_subdev *sd, s32 value);
-extern int dw9718_q_focus_status(struct v4l2_subdev *sd, s32 *value);
-extern int dw9718_q_focus_abs(struct v4l2_subdev *sd, s32 *value);
-extern int dw9718_t_vcm_slew(struct v4l2_subdev *sd, s32 value);
-extern int dw9718_t_vcm_timing(struct v4l2_subdev *sd, s32 value);
-
-extern int vcm_power_up(struct v4l2_subdev *sd);
-extern int vcm_power_down(struct v4l2_subdev *sd);
-
-static struct ov8858_vcm ov8858_vcms[] = {
- [OV8858_SUNNY] = {
- .power_up = dw9718_vcm_power_up,
- .power_down = dw9718_vcm_power_down,
- .init = dw9718_vcm_init,
- .t_focus_abs = dw9718_t_focus_abs,
- .t_focus_rel = dw9718_t_focus_rel,
- .q_focus_status = dw9718_q_focus_status,
- .q_focus_abs = dw9718_q_focus_abs,
- .t_vcm_slew = dw9718_t_vcm_slew,
- .t_vcm_timing = dw9718_t_vcm_timing,
- },
- [OV8858_ID_DEFAULT] = {
- .power_up = NULL,
- .power_down = NULL,
- },
-};
-
-
-#define OV8858_RES_WIDTH_MAX 3280
-#define OV8858_RES_HEIGHT_MAX 2464
-
-static struct ov8858_reg ov8858_BasicSettings[] = {
- {OV8858_8BIT, 0x0103, 0x01}, /* software_reset */
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- /* PLL settings */
- {OV8858_8BIT, 0x0300, 0x05}, /* pll1_pre_div = /4 */
- {OV8858_8BIT, 0x0302, 0xAF}, /* pll1_multiplier = 175 */
- {OV8858_8BIT, 0x0303, 0x00}, /* pll1_divm = /(1 + 0) */
- {OV8858_8BIT, 0x0304, 0x03}, /* pll1_div_mipi = /8 */
- {OV8858_8BIT, 0x030B, 0x02}, /* pll2_pre_div = /2 */
- {OV8858_8BIT, 0x030D, 0x4E}, /* pll2_r_divp = 78 */
- {OV8858_8BIT, 0x030E, 0x00}, /* pll2_r_divs = /1 */
- {OV8858_8BIT, 0x030F, 0x04}, /* pll2_r_divsp = /(1 + 4) */
- /* pll2_pre_div0 = /1, pll2_r_divdac = /(1 + 1) */
- {OV8858_8BIT, 0x0312, 0x01},
- {OV8858_8BIT, 0x031E, 0x0C}, /* pll1_no_lat = 1, mipi_bitsel_man = 0 */
-
- /* PAD OEN2, VSYNC out enable=0x80, disable=0x00 */
- {OV8858_8BIT, 0x3002, 0x80},
- /* PAD OUT2, VSYNC pulse direction low-to-high = 1 */
- {OV8858_8BIT, 0x3007, 0x01},
- /* PAD SEL2, VSYNC out value = 0 */
- {OV8858_8BIT, 0x300D, 0x00},
- /* PAD OUT2, VSYNC out select = 0 */
- {OV8858_8BIT, 0x3010, 0x00},
-
- /* Npump clock div = /2, Ppump clock div = /4 */
- {OV8858_8BIT, 0x3015, 0x01},
- /*
- * mipi_lane_mode = 1+3, mipi_lvds_sel = 1 = MIPI enable,
- * r_phy_pd_mipi_man = 0, lane_dis_option = 0
- */
- {OV8858_8BIT, 0x3018, 0x72},
- /* Clock switch output = normal, pclk_div = /1 */
- {OV8858_8BIT, 0x3020, 0x93},
- /*
- * lvds_mode_o = 0, clock lane disable when pd_mipi = 0,
- * pd_mipi enable when rst_sync = 1
- */
- {OV8858_8BIT, 0x3022, 0x01},
- {OV8858_8BIT, 0x3031, 0x0A}, /* mipi_bit_sel = 10 */
- {OV8858_8BIT, 0x3034, 0x00}, /* Unknown */
- /* sclk_div = /1, sclk_pre_div = /1, chip debug = 1 */
- {OV8858_8BIT, 0x3106, 0x01},
-
- {OV8858_8BIT, 0x3305, 0xF1}, /* Unknown */
- {OV8858_8BIT, 0x3307, 0x04}, /* Unknown */
- {OV8858_8BIT, 0x3308, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3309, 0x28}, /* Unknown */
- {OV8858_8BIT, 0x330A, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x330B, 0x20}, /* Unknown */
- {OV8858_8BIT, 0x330C, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x330D, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x330E, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x330F, 0x40}, /* Unknown */
-
- {OV8858_8BIT, 0x3500, 0x00}, /* long exposure = 0x9A20 */
- {OV8858_8BIT, 0x3501, 0x9A}, /* long exposure = 0x9A20 */
- {OV8858_8BIT, 0x3502, 0x20}, /* long exposure = 0x9A20 */
- /*
- * Digital fraction gain delay option = Delay 1 frame,
- * Gain change delay option = Delay 1 frame,
- * Gain delay option = Delay 1 frame,
- * Gain manual as sensor gain = Input gain as real gain format,
- * Exposure delay option (must be 0 = Delay 1 frame,
- * Exposure change delay option (must be 0) = Delay 1 frame
- */
- {OV8858_8BIT, 0x3503, 0x00},
- {OV8858_8BIT, 0x3505, 0x80}, /* gain conversation option */
- /*
- * [10:7] are integer gain, [6:0] are fraction gain. For example:
- * 0x80 is 1x gain, 0x100 is 2x gain, 0x1C0 is 3.5x gain
- */
- {OV8858_8BIT, 0x3508, 0x02}, /* long gain = 0x0200 */
- {OV8858_8BIT, 0x3509, 0x00}, /* long gain = 0x0200 */
- {OV8858_8BIT, 0x350C, 0x00}, /* short gain = 0x0080 */
- {OV8858_8BIT, 0x350D, 0x80}, /* short gain = 0x0080 */
- {OV8858_8BIT, 0x3510, 0x00}, /* short exposure = 0x000200 */
- {OV8858_8BIT, 0x3511, 0x02}, /* short exposure = 0x000200 */
- {OV8858_8BIT, 0x3512, 0x00}, /* short exposure = 0x000200 */
-
- {OV8858_8BIT, 0x3600, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3601, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3602, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3603, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3604, 0x22}, /* Unknown */
- {OV8858_8BIT, 0x3605, 0x30}, /* Unknown */
- {OV8858_8BIT, 0x3606, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3607, 0x20}, /* Unknown */
- {OV8858_8BIT, 0x3608, 0x11}, /* Unknown */
- {OV8858_8BIT, 0x3609, 0x28}, /* Unknown */
- {OV8858_8BIT, 0x360A, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x360B, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x360C, 0xDC}, /* Unknown */
- {OV8858_8BIT, 0x360D, 0x40}, /* Unknown */
- {OV8858_8BIT, 0x360E, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x360F, 0x20}, /* Unknown */
- {OV8858_8BIT, 0x3610, 0x07}, /* Unknown */
- {OV8858_8BIT, 0x3611, 0x20}, /* Unknown */
- {OV8858_8BIT, 0x3612, 0x88}, /* Unknown */
- {OV8858_8BIT, 0x3613, 0x80}, /* Unknown */
- {OV8858_8BIT, 0x3614, 0x58}, /* Unknown */
- {OV8858_8BIT, 0x3615, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3616, 0x4A}, /* Unknown */
- {OV8858_8BIT, 0x3617, 0x90}, /* Unknown */
- {OV8858_8BIT, 0x3618, 0x56}, /* Unknown */
- {OV8858_8BIT, 0x3619, 0x70}, /* Unknown */
- {OV8858_8BIT, 0x361A, 0x99}, /* Unknown */
- {OV8858_8BIT, 0x361B, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x361C, 0x07}, /* Unknown */
- {OV8858_8BIT, 0x361D, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x361E, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x361F, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3633, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x3634, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x3635, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x3636, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x3638, 0xFF}, /* Unknown */
- {OV8858_8BIT, 0x3645, 0x13}, /* Unknown */
- {OV8858_8BIT, 0x3646, 0x83}, /* Unknown */
- {OV8858_8BIT, 0x364A, 0x07}, /* Unknown */
-
- {OV8858_8BIT, 0x3700, 0x30}, /* Unknown */
- {OV8858_8BIT, 0x3701, 0x18}, /* Unknown */
- {OV8858_8BIT, 0x3702, 0x50}, /* Unknown */
- {OV8858_8BIT, 0x3703, 0x32}, /* Unknown */
- {OV8858_8BIT, 0x3704, 0x28}, /* Unknown */
- {OV8858_8BIT, 0x3705, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3706, 0x6A}, /* Unknown */
- {OV8858_8BIT, 0x3707, 0x08}, /* Unknown */
- {OV8858_8BIT, 0x3708, 0x48}, /* Unknown */
- {OV8858_8BIT, 0x3709, 0x66}, /* Unknown */
- {OV8858_8BIT, 0x370A, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x370B, 0x6A}, /* Unknown */
- {OV8858_8BIT, 0x370C, 0x07}, /* Unknown */
- {OV8858_8BIT, 0x3712, 0x44}, /* Unknown */
- {OV8858_8BIT, 0x3714, 0x24}, /* Unknown */
- {OV8858_8BIT, 0x3718, 0x14}, /* Unknown */
- {OV8858_8BIT, 0x3719, 0x31}, /* Unknown */
- {OV8858_8BIT, 0x371E, 0x31}, /* Unknown */
- {OV8858_8BIT, 0x371F, 0x7F}, /* Unknown */
- {OV8858_8BIT, 0x3720, 0x0A}, /* Unknown */
- {OV8858_8BIT, 0x3721, 0x0A}, /* Unknown */
- {OV8858_8BIT, 0x3724, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x3725, 0x02}, /* Unknown */
- {OV8858_8BIT, 0x3726, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x3728, 0x0A}, /* Unknown */
- {OV8858_8BIT, 0x3729, 0x03}, /* Unknown */
- {OV8858_8BIT, 0x372A, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x372B, 0xA6}, /* Unknown */
- {OV8858_8BIT, 0x372C, 0xA6}, /* Unknown */
- {OV8858_8BIT, 0x372D, 0xA6}, /* Unknown */
- {OV8858_8BIT, 0x372E, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x372F, 0x20}, /* Unknown */
- {OV8858_8BIT, 0x3730, 0x02}, /* Unknown */
- {OV8858_8BIT, 0x3731, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x3732, 0x28}, /* Unknown */
- {OV8858_8BIT, 0x3733, 0x10}, /* Unknown */
- {OV8858_8BIT, 0x3734, 0x40}, /* Unknown */
- {OV8858_8BIT, 0x3736, 0x30}, /* Unknown */
- {OV8858_8BIT, 0x373A, 0x0A}, /* Unknown */
- {OV8858_8BIT, 0x373B, 0x0B}, /* Unknown */
- {OV8858_8BIT, 0x373C, 0x14}, /* Unknown */
- {OV8858_8BIT, 0x373E, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x3755, 0x10}, /* Unknown */
- {OV8858_8BIT, 0x3758, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3759, 0x4C}, /* Unknown */
- {OV8858_8BIT, 0x375A, 0x0C}, /* Unknown */
- {OV8858_8BIT, 0x375B, 0x26}, /* Unknown */
- {OV8858_8BIT, 0x375C, 0x20}, /* Unknown */
- {OV8858_8BIT, 0x375D, 0x04}, /* Unknown */
- {OV8858_8BIT, 0x375E, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x375F, 0x28}, /* Unknown */
- {OV8858_8BIT, 0x3760, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3761, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3762, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3763, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3766, 0xFF}, /* Unknown */
- {OV8858_8BIT, 0x3768, 0x22}, /* Unknown */
- {OV8858_8BIT, 0x3769, 0x44}, /* Unknown */
- {OV8858_8BIT, 0x376A, 0x44}, /* Unknown */
- {OV8858_8BIT, 0x376B, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x376F, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x3772, 0x46}, /* Unknown */
- {OV8858_8BIT, 0x3773, 0x04}, /* Unknown */
- {OV8858_8BIT, 0x3774, 0x2C}, /* Unknown */
- {OV8858_8BIT, 0x3775, 0x13}, /* Unknown */
- {OV8858_8BIT, 0x3776, 0x08}, /* Unknown */
- {OV8858_8BIT, 0x3777, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */
- {OV8858_8BIT, 0x37A0, 0x88}, /* Unknown */
- {OV8858_8BIT, 0x37A1, 0x7A}, /* Unknown */
- {OV8858_8BIT, 0x37A2, 0x7A}, /* Unknown */
- {OV8858_8BIT, 0x37A3, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37A4, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37A5, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37A6, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37A7, 0x88}, /* Unknown */
- {OV8858_8BIT, 0x37A8, 0x98}, /* Unknown */
- {OV8858_8BIT, 0x37A9, 0x98}, /* Unknown */
- {OV8858_8BIT, 0x37AA, 0x88}, /* Unknown */
- {OV8858_8BIT, 0x37AB, 0x5C}, /* Unknown */
- {OV8858_8BIT, 0x37AC, 0x5C}, /* Unknown */
- {OV8858_8BIT, 0x37AD, 0x55}, /* Unknown */
- {OV8858_8BIT, 0x37AE, 0x19}, /* Unknown */
- {OV8858_8BIT, 0x37AF, 0x19}, /* Unknown */
- {OV8858_8BIT, 0x37B0, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37B1, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37B2, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37B3, 0x84}, /* Unknown */
- {OV8858_8BIT, 0x37B4, 0x84}, /* Unknown */
- {OV8858_8BIT, 0x37B5, 0x66}, /* Unknown */
- {OV8858_8BIT, 0x37B6, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37B7, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37B8, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x37B9, 0xFF}, /* Unknown */
-
- {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low */
- {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */
- {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high */
- {OV8858_8BIT, 0x3809, 0xC0}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x09}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0x90}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */
- {OV8858_8BIT, 0x3810, 0x00}, /* h_win offset high */
- {OV8858_8BIT, 0x3811, 0x04}, /* h_win offset low */
- {OV8858_8BIT, 0x3812, 0x00}, /* v_win offset high */
- {OV8858_8BIT, 0x3813, 0x02}, /* v_win offset low */
- {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x40}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
-
- {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x3837, 0x18}, /* Unknown */
- {OV8858_8BIT, 0x3841, 0xFF}, /* AUTO_SIZE_CTRL */
- {OV8858_8BIT, 0x3846, 0x48}, /* Unknown */
-
- {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3D8C, 0x73}, /* OTP_SETTING_STT_ADDRESS */
- {OV8858_8BIT, 0x3D8D, 0xDE}, /* OTP_SETTING_STT_ADDRESS */
- {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */
- {OV8858_8BIT, 0x3F0A, 0x80}, /* PSRAM control register */
-
- {OV8858_8BIT, 0x4000, 0xF1}, /* BLC CTRL00 = default */
- {OV8858_8BIT, 0x4001, 0x00}, /* BLC CTRL01 */
- {OV8858_8BIT, 0x4002, 0x27}, /* BLC offset = 0x27 */
- {OV8858_8BIT, 0x4005, 0x10}, /* BLC target = 0x0010 */
- {OV8858_8BIT, 0x4009, 0x81}, /* BLC CTRL09 */
- {OV8858_8BIT, 0x400B, 0x0C}, /* BLC CTRL0B = default */
- {OV8858_8BIT, 0x400A, 0x01},
- {OV8858_8BIT, 0x4011, 0x20}, /* BLC CTRL11 = 0x20 */
- {OV8858_8BIT, 0x401B, 0x00}, /* Zero line R coeff. = 0x0000 */
- {OV8858_8BIT, 0x401D, 0x00}, /* Zero line T coeff. = 0x0000 */
- {OV8858_8BIT, 0x401F, 0x00}, /* BLC CTRL1F */
- {OV8858_8BIT, 0x4020, 0x00}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4021, 0x04}, /* Anchor left start = 0x0004 */
- {OV8858_8BIT, 0x4022, 0x0C}, /* Anchor left end = 0x0C60 */
- {OV8858_8BIT, 0x4023, 0x60}, /* Anchor left end = 0x0C60 */
- {OV8858_8BIT, 0x4024, 0x0F}, /* Anchor right start = 0x0F36 */
- {OV8858_8BIT, 0x4025, 0x36}, /* Anchor right start = 0x0F36 */
- {OV8858_8BIT, 0x4026, 0x0F}, /* Anchor right end = 0x0F37 */
- {OV8858_8BIT, 0x4027, 0x37}, /* Anchor right end = 0x0F37 */
- {OV8858_8BIT, 0x4028, 0x00}, /* Top zero line start = 0 */
- {OV8858_8BIT, 0x4029, 0x04}, /* Top zero line number = 4 */
- {OV8858_8BIT, 0x402A, 0x04}, /* Top black line start = 4 */
- {OV8858_8BIT, 0x402B, 0x08}, /* Top black line number = 8 */
- {OV8858_8BIT, 0x402C, 0x00}, /* Bottom zero start line = 0 */
- {OV8858_8BIT, 0x402D, 0x02}, /* Bottom zero line number = 2 */
- {OV8858_8BIT, 0x402E, 0x04}, /* Bottom black line start = 4 */
- {OV8858_8BIT, 0x402F, 0x08}, /* Bottom black line number = 8 */
-
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4300, 0xFF}, /* clip_max[11:4] = 0xFFF */
- {OV8858_8BIT, 0x4301, 0x00}, /* clip_min[11:4] = 0 */
- {OV8858_8BIT, 0x4302, 0x0F}, /* clip_min/max[3:0] */
- {OV8858_8BIT, 0x4307, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x4316, 0x00}, /* CTRL16 = default */
- {OV8858_8BIT, 0x4503, 0x18}, /* Unknown */
- {OV8858_8BIT, 0x4500, 0x38}, /* Unknown */
- {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */
- /* wkup_dly = Mark1 wakeup delay/2^10 = 0x25 */
- {OV8858_8BIT, 0x4808, 0x25},
- {OV8858_8BIT, 0x4816, 0x52}, /* Embedded data type*/
- {OV8858_8BIT, 0x481F, 0x32}, /* clk_prepare_min = 0x32 */
- {OV8858_8BIT, 0x4825, 0x3A}, /* lpx_p_min = 0x3A */
- {OV8858_8BIT, 0x4826, 0x40}, /* hs_prepare_min = 0x40 */
- {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */
- {OV8858_8BIT, 0x4850, 0x10}, /* LANE SEL01 */
- {OV8858_8BIT, 0x4851, 0x32}, /* LANE SEL02 */
-
- {OV8858_8BIT, 0x4B00, 0x2A}, /* Unknown */
- {OV8858_8BIT, 0x4B0D, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x4D00, 0x04}, /* TPM_CTRL_REG */
- {OV8858_8BIT, 0x4D01, 0x18}, /* TPM_CTRL_REG */
- {OV8858_8BIT, 0x4D02, 0xC3}, /* TPM_CTRL_REG */
- {OV8858_8BIT, 0x4D03, 0xFF}, /* TPM_CTRL_REG */
- {OV8858_8BIT, 0x4D04, 0xFF}, /* TPM_CTRL_REG */
- {OV8858_8BIT, 0x4D05, 0xFF}, /* TPM_CTRL_REG */
-
- /*
- * Lens correction (LENC) function enable = 0
- * Slave sensor AWB Gain function enable = 1
- * Slave sensor AWB Statistics function enable = 1
- * Master sensor AWB Gain function enable = 1
- * Master sensor AWB Statistics function enable = 1
- * Black DPC function enable = 1
- * White DPC function enable =1
- */
- {OV8858_8BIT, 0x5000, 0x7E},
- {OV8858_8BIT, 0x5001, 0x01}, /* BLC function enable = 1 */
- /*
- * Horizontal scale function enable = 0
- * WBMATCH bypass mode = Select slave sensor's gain
- * WBMATCH function enable = 0
- * Master MWB gain support RGBC = 0
- * OTP_DPC function enable = 1
- * Manual mode of VarioPixel function enable = 0
- * Manual enable of VarioPixel function enable = 0
- * Use VSYNC to latch ISP modules's function enable signals = 0
- */
- {OV8858_8BIT, 0x5002, 0x08},
- /*
- * Bypass all ISP modules after BLC module = 0
- * DPC_DBC buffer control enable = 1
- * WBMATCH VSYNC selection = Select master sensor's VSYNC fall
- * Select master AWB gain to embed line = AWB gain before manual mode
- * Enable BLC's input flip_i signal = 0
- */
- {OV8858_8BIT, 0x5003, 0x20},
- {OV8858_8BIT, 0x5041, 0x1D}, /* ISP CTRL41 - embedded data=on */
- {OV8858_8BIT, 0x5046, 0x12}, /* ISP CTRL46 = default */
- /*
- * Tail enable = 1
- * Saturate cross cluster enable = 1
- * Remove cross cluster enable = 1
- * Enable to remove connected defect pixels in same channel = 1
- * Enable to remove connected defect pixels in different channel = 1
- * Smooth enable, use average G for recovery = 1
- * Black/white sensor mode enable = 0
- * Manual mode enable = 0
- */
- {OV8858_8BIT, 0x5780, 0xFC},
- {OV8858_8BIT, 0x5784, 0x0C}, /* DPC CTRL04 */
- {OV8858_8BIT, 0x5787, 0x40}, /* DPC CTRL07 */
- {OV8858_8BIT, 0x5788, 0x08}, /* DPC CTRL08 */
- {OV8858_8BIT, 0x578A, 0x02}, /* DPC CTRL0A */
- {OV8858_8BIT, 0x578B, 0x01}, /* DPC CTRL0B */
- {OV8858_8BIT, 0x578C, 0x01}, /* DPC CTRL0C */
- {OV8858_8BIT, 0x578E, 0x02}, /* DPC CTRL0E */
- {OV8858_8BIT, 0x578F, 0x01}, /* DPC CTRL0F */
- {OV8858_8BIT, 0x5790, 0x01}, /* DPC CTRL10 */
- {OV8858_8BIT, 0x5901, 0x00}, /* VAP CTRL01 = default */
- /* WINC CTRL08 = embedded data in 1st line*/
- {OV8858_8BIT, 0x5A08, 0x00},
- {OV8858_8BIT, 0x5B00, 0x02}, /* OTP CTRL00 */
- {OV8858_8BIT, 0x5B01, 0x10}, /* OTP CTRL01 */
- {OV8858_8BIT, 0x5B02, 0x03}, /* OTP CTRL02 */
- {OV8858_8BIT, 0x5B03, 0xCF}, /* OTP CTRL03 */
- {OV8858_8BIT, 0x5B05, 0x6C}, /* OTP CTRL05 = default */
- {OV8858_8BIT, 0x5E00, 0x00}, /* PRE CTRL00 = default */
- {OV8858_8BIT, 0x5E01, 0x41}, /* PRE_CTRL01 = default */
-
- {OV8858_TOK_TERM, 0, 0}
-};
-
-/*****************************STILL********************************/
-
-static const struct ov8858_reg ov8858_8M[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low 12 */
- {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */
- {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low 3283 */
- {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high 3280 x 2464 */
- {OV8858_8BIT, 0x3809, 0xD0}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x09}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0xa0}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x40}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_3276x1848[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x10}, /* h_crop_start low 0c->10*/
- {OV8858_8BIT, 0x3802, 0x01}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x42}, /* v_crop_start low 3e->42*/
- {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */
- {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x08}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0x71}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high 3276 x 1848 */
- {OV8858_8BIT, 0x3809, 0xCC}, /* h_output_size low d0->cc*/
- {OV8858_8BIT, 0x380A, 0x07}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0x38}, /* v_output_size low 3c->38*/
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x40}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_6M[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low */
- {OV8858_8BIT, 0x3802, 0x01}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x3E}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */
- {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x08}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0x71}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x0C}, /* h_output_size high 3280 x 1852 */
- {OV8858_8BIT, 0x3809, 0xD0}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x07}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0x3C}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x40}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0x97}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_1080P_60[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x17}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x02}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x26}, /* h_crop_start low */
- {OV8858_8BIT, 0x3802, 0x02}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x8C}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0A}, /* h_crop_end high */
- {OV8858_8BIT, 0x3805, 0x9D}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x07}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0x0A}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x07}, /* h_output_size high*/
- {OV8858_8BIT, 0x3809, 0x90}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0x48}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x04}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0xEC}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x40}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0xef}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x16}, /* pclk_period = 0x16 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_1080P_30[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x17}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x02}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x26}, /* h_crop_start low */
- {OV8858_8BIT, 0x3802, 0x02}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x8C}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0A}, /* h_crop_end high */
- {OV8858_8BIT, 0x3805, 0x9D}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x07}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0x0A}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x07}, /* h_output_size high*/
- {OV8858_8BIT, 0x3809, 0x90}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0x48}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x0A}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0x0D}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x01}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x40}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x01}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x06}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x01}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x14}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x10}, /* PSRAM control register */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0xef}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x16}, /* pclk_period = 0x16 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_1640x1232[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low 12 */
- {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high 3283 */
- {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x06}, /* h_output_size high 1640 x 1232 */
- {OV8858_8BIT, 0x3809, 0x68}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0xD0}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x09}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0xAA}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x03}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x67}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x03}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x08}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x02}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x16}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x08}, /* PSRAM control register */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0xCB}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static const struct ov8858_reg ov8858_1640x1096[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low 12 */
- {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high 3283 */
- {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x06}, /* h_output_size high 1640 x 1096 */
- {OV8858_8BIT, 0x3809, 0x68}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x04}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0x48}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x09}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0xAA}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x03}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x67}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x03}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x08}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x02}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x16}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x08}, /* PSRAM control register */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0xCB}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-
-static const struct ov8858_reg ov8858_1640x926[] = {
- {OV8858_8BIT, 0x0100, 0x00}, /* software_standby */
- {OV8858_8BIT, 0x3778, 0x16}, /* Unknown */
- {OV8858_8BIT, 0x3800, 0x00}, /* h_crop_start high */
- {OV8858_8BIT, 0x3801, 0x0C}, /* h_crop_start low */
- {OV8858_8BIT, 0x3802, 0x00}, /* v_crop_start high */
- {OV8858_8BIT, 0x3803, 0x0C}, /* v_crop_start low */
- {OV8858_8BIT, 0x3804, 0x0C}, /* h_crop_end high */
- {OV8858_8BIT, 0x3805, 0xD3}, /* h_crop_end low */
- {OV8858_8BIT, 0x3806, 0x09}, /* v_crop_end high */
- {OV8858_8BIT, 0x3807, 0xA3}, /* v_crop_end low */
- {OV8858_8BIT, 0x3808, 0x06}, /* h_output_size high 1640 x 926 */
- {OV8858_8BIT, 0x3809, 0x68}, /* h_output_size low */
- {OV8858_8BIT, 0x380A, 0x03}, /* v_output_size high */
- {OV8858_8BIT, 0x380B, 0x9E}, /* v_output_size low */
- {OV8858_8BIT, 0x380C, 0x07}, /* horizontal timing size high */
- {OV8858_8BIT, 0x380D, 0x94}, /* horizontal timing size low */
- {OV8858_8BIT, 0x380E, 0x09}, /* vertical timing size high */
- {OV8858_8BIT, 0x380F, 0xAA}, /* vertical timing size low */
- {OV8858_8BIT, 0x3814, 0x03}, /* h_odd_inc */
- {OV8858_8BIT, 0x3815, 0x01}, /* h_even_inc */
- {OV8858_8BIT, 0x3820, 0x00}, /* format1 */
- {OV8858_8BIT, 0x3821, 0x67}, /* format2 */
- {OV8858_8BIT, 0x382A, 0x03}, /* v_odd_inc */
- {OV8858_8BIT, 0x382B, 0x01}, /* v_even_inc */
- {OV8858_8BIT, 0x3830, 0x08}, /* Unknown */
- {OV8858_8BIT, 0x3836, 0x02}, /* Unknown */
- {OV8858_8BIT, 0x3D85, 0x16}, /* OTP_REG85 */
- {OV8858_8BIT, 0x3F08, 0x08}, /* PSRAM control register */
- {OV8858_8BIT, 0x4034, 0x3F}, /* Unknown */
- {OV8858_8BIT, 0x403D, 0x04}, /* BLC CTRL3D */
- {OV8858_8BIT, 0x4600, 0x00}, /* Unknown */
- {OV8858_8BIT, 0x4601, 0xCB}, /* Unknown */
- {OV8858_8BIT, 0x4837, 0x14}, /* pclk_period = 0x14 */
- {OV8858_TOK_TERM, 0, 0}
-};
-
-static struct ov8858_resolution ov8858_res_preview[] = {
- {
- .desc = "ov8858_1640x926_PREVIEW",
- .width = 1640,
- .height = 926,
- .used = 0,
- .regs = ov8858_1640x926,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 0,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_1640x1232_PREVIEW",
- .width = 1640,
- .height = 1232,
- .used = 0,
- .regs = ov8858_1640x1232,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 0,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_1936x1096_PREVIEW",
- .width = 1936,
- .height = 1096,
- .used = 0,
- .regs = ov8858_1080P_30,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 0,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_3276x1848_PREVIEW",
- .width = 3276,
- .height = 1848,
- .used = 0,
- .regs = ov8858_3276x1848,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 0,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_8M_PREVIEW",
- .width = 3280,
- .height = 2464,
- .used = 0,
- .regs = ov8858_8M,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 0,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
-};
-
-static struct ov8858_resolution ov8858_res_still[] = {
- {
- .desc = "ov8858_1640x1232_STILL",
- .width = 1640,
- .height = 1232,
- .used = 0,
- .regs = ov8858_1640x1232,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 0,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_1640x926_STILL",
- .width = 1640,
- .height = 926,
- .used = 0,
- .regs = ov8858_1640x926,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_3276X1848_STILL",
- .width = 3276,
- .height = 1848,
- .used = 0,
- .regs = ov8858_3276x1848,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_8M_STILL",
- .width = 3280,
- .height = 2464,
- .used = 0,
- .regs = ov8858_8M,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- /* Pixel clock: 149.76MHZ */
- .fps = 10,
- .pixels_per_line = 3880,
- .lines_per_frame = 3859,
- },
- {
- }
- },
- },
-};
-
-static struct ov8858_resolution ov8858_res_video[] = {
- {
- .desc = "ov8858_1640x926_VIDEO",
- .width = 1640,
- .height = 926,
- .used = 0,
- .regs = ov8858_1640x926,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_1640x1232_VIDEO",
- .width = 1640,
- .height = 1232,
- .used = 0,
- .regs = ov8858_1640x1232,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_1640x1096_VIDEO",
- .width = 1640,
- .height = 1096,
- .used = 0,
- .regs = ov8858_1640x1096,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
- {
- .desc = "ov8858_1080P_30_VIDEO",
- .width = 1936,
- .height = 1096,
- .used = 0,
- .regs = ov8858_1080P_30,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .skip_frames = 1,
- .fps_options = {
- {
- .fps = 30,
- .pixels_per_line = 3880,
- .lines_per_frame = 2573,
- },
- {
- }
- },
- },
-};
-
-#endif /* __OV8858_H__ */
diff --git a/drivers/staging/media/atomisp/include/linux/vlv2_plat_clock.h b/drivers/staging/media/atomisp/include/linux/vlv2_plat_clock.h
deleted file mode 100644
index ed709bdd6498..000000000000
--- a/drivers/staging/media/atomisp/include/linux/vlv2_plat_clock.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * vlv2_plat_clock.h
- *
- * Copyright (C) 2013 Intel Corp
- * Author: Asutosh Pathak <asutosh.pathak@intel.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; 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.
- *
- * 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.
- */
-
-#ifndef __VLV2_PLAT_CLOCK_H
-#define __VLV2_PLAT_CLOCK_H
-
-int vlv2_plat_set_clock_freq(int clock_num, int freq_type);
-int vlv2_plat_get_clock_freq(int clock_num);
-
-int vlv2_plat_configure_clock(int clock_num, u32 conf);
-int vlv2_plat_get_clock_status(int clock_num);
-
-#endif /* __VLV2_PLAT_CLOCK_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/Makefile b/drivers/staging/media/atomisp/pci/atomisp2/Makefile
index ac3805345f20..83f816faba1b 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/Makefile
+++ b/drivers/staging/media/atomisp/pci/atomisp2/Makefile
@@ -215,7 +215,6 @@ INCLUDES += \
-I$(atomisp)/css2400/isp/kernels/aa/aa_2/ \
-I$(atomisp)/css2400/isp/kernels/anr/anr_1.0/ \
-I$(atomisp)/css2400/isp/kernels/anr/anr_2/ \
- -I$(atomisp)/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ \
-I$(atomisp)/css2400/isp/kernels/bh/bh_2/ \
-I$(atomisp)/css2400/isp/kernels/bnlm/ \
-I$(atomisp)/css2400/isp/kernels/bnr/ \
@@ -258,14 +257,10 @@ INCLUDES += \
-I$(atomisp)/css2400/isp/kernels/io_ls/ \
-I$(atomisp)/css2400/isp/kernels/io_ls/bayer_io_ls/ \
-I$(atomisp)/css2400/isp/kernels/io_ls/common/ \
- -I$(atomisp)/css2400/isp/kernels/io_ls/plane_io_ls/ \
- -I$(atomisp)/css2400/isp/kernels/io_ls/yuv420_io_ls/ \
-I$(atomisp)/css2400/isp/kernels/io_ls/yuv444_io_ls/ \
-I$(atomisp)/css2400/isp/kernels/ipu2_io_ls/ \
-I$(atomisp)/css2400/isp/kernels/ipu2_io_ls/bayer_io_ls/ \
-I$(atomisp)/css2400/isp/kernels/ipu2_io_ls/common/ \
- -I$(atomisp)/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ \
- -I$(atomisp)/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ \
-I$(atomisp)/css2400/isp/kernels/ipu2_io_ls/yuv444_io_ls/ \
-I$(atomisp)/css2400/isp/kernels/iterator/ \
-I$(atomisp)/css2400/isp/kernels/iterator/iterator_1.0/ \
@@ -289,9 +284,6 @@ INCLUDES += \
-I$(atomisp)/css2400/isp/kernels/ref/ref_1.0/ \
-I$(atomisp)/css2400/isp/kernels/s3a/ \
-I$(atomisp)/css2400/isp/kernels/s3a/s3a_1.0/ \
- -I$(atomisp)/css2400/isp/kernels/s3a_stat_ls/ \
- -I$(atomisp)/css2400/isp/kernels/scale/ \
- -I$(atomisp)/css2400/isp/kernels/scale/scale_1.0/ \
-I$(atomisp)/css2400/isp/kernels/sc/ \
-I$(atomisp)/css2400/isp/kernels/sc/sc_1.0/ \
-I$(atomisp)/css2400/isp/kernels/sdis/ \
@@ -315,8 +307,6 @@ INCLUDES += \
-I$(atomisp)/css2400/isp/kernels/ynr/ \
-I$(atomisp)/css2400/isp/kernels/ynr/ynr_1.0/ \
-I$(atomisp)/css2400/isp/kernels/ynr/ynr_2/ \
- -I$(atomisp)/css2400/isp/kernels/yuv_ls \
- -I$(atomisp)/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ \
-I$(atomisp)/css2400/isp/modes/interface/ \
-I$(atomisp)/css2400/runtime/binary/interface/ \
-I$(atomisp)/css2400/runtime/bufq/interface/ \
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c
index debf0e3853ff..22f2dbcecc15 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c
+++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c
@@ -1850,7 +1850,7 @@ irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr)
bool frame_done_found[MAX_STREAM_NUM] = {0};
bool css_pipe_done[MAX_STREAM_NUM] = {0};
unsigned int i;
- struct atomisp_sub_device *asd = &isp->asd[0];
+ struct atomisp_sub_device *asd;
dev_dbg(isp->dev, ">%s\n", __func__);
@@ -2091,7 +2091,7 @@ int atomisp_set_sensor_runmode(struct atomisp_sub_device *asd,
struct atomisp_device *isp = asd->isp;
struct v4l2_ctrl *c;
struct v4l2_streamparm p = {0};
- int ret;
+ int ret = 0;
int modes[] = { CI_MODE_NONE,
CI_MODE_VIDEO,
CI_MODE_STILL_CAPTURE,
@@ -2105,13 +2105,8 @@ int atomisp_set_sensor_runmode(struct atomisp_sub_device *asd,
c = v4l2_ctrl_find(isp->inputs[asd->input_curr].camera->ctrl_handler,
V4L2_CID_RUN_MODE);
- if (c) {
+ if (c)
ret = v4l2_ctrl_s_ctrl(c, runmode->mode);
- } else {
- p.parm.capture.capturemode = modes[runmode->mode];
- ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
- video, s_parm, &p);
- }
mutex_unlock(asd->ctrl_handler.lock);
return ret;
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c
index b7f9da014641..7621b4537147 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c
+++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c
@@ -4502,7 +4502,7 @@ int atomisp_css_isr_thread(struct atomisp_device *isp,
{
enum atomisp_input_stream_id stream_id = 0;
struct atomisp_css_event current_event;
- struct atomisp_sub_device *asd = &isp->asd[0];
+ struct atomisp_sub_device *asd;
#ifndef ISP2401
bool reset_wdt_timer[MAX_STREAM_NUM] = {false};
#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.c
index 377ec2a9fa6d..c6d96987561d 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.c
+++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.c
@@ -77,20 +77,6 @@ static int file_input_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
-static int file_input_g_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *param)
-{
- /*to fake*/
- return 0;
-}
-
-static int file_input_s_parm(struct v4l2_subdev *sd,
- struct v4l2_streamparm *param)
-{
- /*to fake*/
- return 0;
-}
-
static int file_input_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
@@ -166,8 +152,6 @@ static int file_input_enum_frame_ival(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops file_input_video_ops = {
.s_stream = file_input_s_stream,
- .g_parm = file_input_g_parm,
- .s_parm = file_input_s_parm,
};
static const struct v4l2_subdev_core_ops file_input_core_ops = {
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c
index 4f9f9dca5e6a..545ef024841d 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c
+++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c
@@ -1279,7 +1279,10 @@ const struct v4l2_file_operations atomisp_fops = {
.mmap = atomisp_mmap,
.unlocked_ioctl = video_ioctl2,
#ifdef CONFIG_COMPAT
+ /*
+ * There are problems with this code. Disable this for now.
.compat_ioctl32 = atomisp_compat_ioctl32,
+ */
#endif
.poll = atomisp_poll,
};
@@ -1291,7 +1294,10 @@ const struct v4l2_file_operations atomisp_file_fops = {
.mmap = atomisp_file_mmap,
.unlocked_ioctl = video_ioctl2,
#ifdef CONFIG_COMPAT
+ /*
+ * There are problems with this code. Disable this for now.
.compat_ioctl32 = atomisp_compat_ioctl32,
+ */
#endif
.poll = atomisp_poll,
};
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c
index f3e18d627b0a..b78276ac22da 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c
+++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c
@@ -819,12 +819,6 @@ static int __atomisp_update_run_mode(struct atomisp_sub_device *asd)
struct atomisp_device *isp = asd->isp;
struct v4l2_ctrl *ctrl = asd->run_mode;
struct v4l2_ctrl *c;
- struct v4l2_streamparm p = {0};
- int modes[] = { CI_MODE_NONE,
- CI_MODE_VIDEO,
- CI_MODE_STILL_CAPTURE,
- CI_MODE_CONTINUOUS,
- CI_MODE_PREVIEW };
s32 mode;
if (ctrl->val != ATOMISP_RUN_MODE_VIDEO &&
@@ -840,11 +834,7 @@ static int __atomisp_update_run_mode(struct atomisp_sub_device *asd)
if (c)
return v4l2_ctrl_s_ctrl(c, mode);
- /* Fall back to obsolete s_parm */
- p.parm.capture.capturemode = modes[mode];
-
- return v4l2_subdev_call(
- isp->inputs[asd->input_curr].camera, video, s_parm, &p);
+ return 0;
}
int atomisp_update_run_mode(struct atomisp_sub_device *asd)
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.c
index b71cc7bcdbab..adc900272f6f 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.c
+++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.c
@@ -27,18 +27,6 @@ static int tpg_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
-static int tpg_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param)
-{
- /*to fake*/
- return 0;
-}
-
-static int tpg_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param)
-{
- /*to fake*/
- return 0;
-}
-
static int tpg_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
@@ -101,8 +89,6 @@ static int tpg_enum_frame_ival(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops tpg_video_ops = {
.s_stream = tpg_s_stream,
- .g_parm = tpg_g_parm,
- .s_parm = tpg_s_parm,
};
static const struct v4l2_subdev_core_ops tpg_core_ops = {
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c
index 548e00e7d67b..ba20344ec560 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c
+++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c
@@ -1137,7 +1137,6 @@ static int init_atomisp_wdts(struct atomisp_device *isp)
for (i = 0; i < isp->num_of_streams; i++) {
struct atomisp_sub_device *asd = &isp->asd[i];
- asd = &isp->asd[i];
#ifndef ISP2401
timer_setup(&asd->wdt, atomisp_wdt, 0);
#else
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/gp_regs_defs.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/gp_regs_defs.h
deleted file mode 100644
index 34e734f6648e..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/gp_regs_defs.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef _gp_regs_defs_h
-#define _gp_regs_defs_h
-
-#define _HRT_GP_REGS_IS_FWD_REG_IDX 0
-
-#define _HRT_GP_REGS_REG_ALIGN 4
-
-#endif /* _gp_regs_defs_h */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/sp_hrt.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/sp_hrt.h
deleted file mode 100644
index 7ee4deba519a..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/sp_hrt.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef ISP2401
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef _sp_hrt_h_
-#define _sp_hrt_h_
-
-#define hrt_sp_dmem(cell) HRT_PROC_TYPE_PROP(cell, _dmem)
-
-#define hrt_sp_dmem_master_port_address(cell) hrt_mem_master_port_address(cell, hrt_sp_dmem(cell))
-
-#endif /* _sp_hrt_h_ */
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/gp_regs_defs.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/gp_regs_defs.h
deleted file mode 100644
index 34e734f6648e..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/gp_regs_defs.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef _gp_regs_defs_h
-#define _gp_regs_defs_h
-
-#define _HRT_GP_REGS_IS_FWD_REG_IDX 0
-
-#define _HRT_GP_REGS_REG_ALIGN 4
-
-#endif /* _gp_regs_defs_h */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/sp_hrt.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/sp_hrt.h
deleted file mode 100644
index 7ee4deba519a..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/sp_hrt.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef ISP2401
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef _sp_hrt_h_
-#define _sp_hrt_h_
-
-#define hrt_sp_dmem(cell) HRT_PROC_TYPE_PROP(cell, _dmem)
-
-#define hrt_sp_dmem_master_port_address(cell) hrt_mem_master_port_address(cell, hrt_sp_dmem(cell))
-
-#endif /* _sp_hrt_h_ */
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/gp_regs_defs.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/gp_regs_defs.h
deleted file mode 100644
index 34e734f6648e..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/gp_regs_defs.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef _gp_regs_defs_h
-#define _gp_regs_defs_h
-
-#define _HRT_GP_REGS_IS_FWD_REG_IDX 0
-
-#define _HRT_GP_REGS_REG_ALIGN 4
-
-#endif /* _gp_regs_defs_h */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/sp_hrt.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/sp_hrt.h
deleted file mode 100644
index 7ee4deba519a..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/sp_hrt.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef ISP2401
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef _sp_hrt_h_
-#define _sp_hrt_h_
-
-#define hrt_sp_dmem(cell) HRT_PROC_TYPE_PROP(cell, _dmem)
-
-#define hrt_sp_dmem_master_port_address(cell) hrt_mem_master_port_address(cell, hrt_sp_dmem(cell))
-
-#endif /* _sp_hrt_h_ */
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_api_version.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_api_version.h
deleted file mode 100644
index efcd6e1679e8..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_api_version.h
+++ /dev/null
@@ -1,673 +0,0 @@
-/*
-#ifndef ISP2401
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-#else
-Support for Intel Camera Imaging ISP subsystem.
-Copyright (c) 2010 - 2015, Intel Corporation.
-#endif
-
-#ifdef ISP2401
-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.
-*/
-#endif
-#ifndef __CSS_API_VERSION_H
-#define __CSS_API_VERSION_H
-
-/* @file
- * CSS API version file. This file contains the version number of the CSS-API.
- *
- * This file is generated from a set of input files describing the CSS-API
- * changes. Don't edit this file directly.
- */
-
-
-/**
-
-The version string has four dot-separated numbers, read left to right:
- The first two are the API version, and should not be changed.
- The third number is incremented by a CSS firmware developer when the
- API change is not backwards compatible.
- The fourth number is incremented by the a CSS firmware developer for
- every API change.
- It should be zeroed when the third number changes.
-
-*/
-
-#ifndef ISP2401
-#define CSS_API_VERSION_STRING "2.1.15.3"
-#else
-#define CSS_API_VERSION_STRING "2.1.20.9"
-#endif
-
-/*
-Change log
-
-v2.0.1.0, initial version:
-- added API versioning
-
-v2.0.1.1, activate CSS-API versioning:
-- added description of major and minor version numbers
-
-v2.0.1.2, modified struct ia_css_frame_info:
-- added new member ia_css_crop_info
-
-v2.0.1.3, added IA_CSS_ERR_NOT_SUPPORTED
-
-v2.1.0.0
-- moved version number to 2.1.0.0
-- created new files for refactoring the code
-
-v2.1.1.0, modified struct ia_css_pipe_config and struct ia_css_pipe_info and struct ia_css_pipe:
-- use array to handle multiple output ports
-
-v2.1.1.1
-- added api to lock/unlock of RAW Buffers to Support HALv3 Feature
-
-v2.1.1.2, modified struct ia_css_stream_config:
-- to support multiple isys streams in one virtual channel, keep the old one for backward compatibility
-
-v2.1.2.0, modify ia_css_stream_config:
-- add isys_config and input_config to support multiple isys stream within one virtual channel
-
-v2.1.2.1, add IA_CSS_STREAM_FORMAT_NUM
-- add IA_CSS_STREAM_FORMAT_NUM definition to reflect the number of ia_css_stream_format enums
-
-v2.1.2.2, modified enum ia_css_stream_format
-- Add 16bit YUV formats to ia_css_stream_format enum:
-- IA_CSS_STREAM_FORMAT_YUV420_16 (directly after IA_CSS_STREAM_FORMAT_YUV420_10)
-- IA_CSS_STREAM_FORMAT_YUV422_16 (directly after IA_CSS_STREAM_FORMAT_YUV422_10)
-
-v2.1.2.3
-- added api to enable/disable digital zoom for capture pipe.
-
-v2.1.2.4, change CSS API to generate the shading table which should be directly sent to ISP:
-- keep the old CSS API (which uses the conversion of the shading table in CSS) for backward compatibility
-
-v2.1.2.5
-- Added SP frame time measurement (in ticks) and result is sent on a new member
-- in ia_css_buffer.h.
-
-v2.1.2.6, add function ia_css_check_firmware_version()
-- the function ia_css_check_firmware_version() returns true when the firmware version matches and returns false otherwise.
-
-v2.1.2.7
-- rename dynamic_data_index to dynamic_queue_id in struct ia_css_frame.
-- update IA_CSS_PIPE_MODE_NUM
-
-v2.1.2.8
-- added flag for video full range
-
-v2.1.2.9
-- add public parameters for xnr3 kernel
-
-v2.1.2.10
-- add new interface to enable output mirroring
-
-v2.1.2.11, MIPI buffers optimization
-- modified struct ia_css_mipi_buffer_config, added number of MIPI buffers needed for the stream
-- backwards compatible, need another patch to remove legacy function and code
-
-v2.1.2.12
-- create consolidated firmware package for 2400, 2401, csi2p, bxtpoc
-
-v2.1.3.0
-- rename ia_css_output_config.enable_mirror
-- add new interface to enable vertical output flipping
-
-v2.1.3.1
-- deprecated ia_css_rx_get_irq_info and ia_css_rx_clear_irq_info because both are hardcoded to work on CSI port 1.
-- added new functions ia_css_rx_port_get_irq_info and ia_css_rx_port_clear_irq_info, both have a port ID as extra argument.
-
-v2.1.3.2
-- reverted v2.1.3.0 change
-
-v2.1.3.3
-- Added isys event queue.
-- Renamed ia_css_dequeue_event to ia_css_dequeue_psys_event
-- Made ia_css_dequeue_event deprecated
-
-v2.1.3.4
-- added new interface to support ACC extension QoS feature.
-- added IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE.
-
-v2.1.3.5
-- added tiled frame format IA_CSS_FRAME_FORMAT_NV12_TILEY
-
-v2.1.3.6
-- added functions ia_css_host_data_allocate and ia_css_host_data_free
-
-v2.1.4.0, default pipe config change
-- disable enable_dz param by default
-
-v2.1.5.0
-- removed mix_range field from yuvp1_y_ee_nr_frng_public_config
-
-v2.1.5.1, exposure IDs per stream
-- added MIN/MAX exposure ID macros
-- made exposure ID sequence per-stream instead of global (across all streams)
-
-#ifdef ISP2401
-v2.1.5.1, Add parameters to mmgr routines via a macro.
-- Replaced mmgr funtions with macros to add caller func name + line #.
-- This is done to help debug memory access issues, allocation issues, etc.
-
-#endif
-v2.1.6.0, Interface for vertical output flip
-- add new interface to enable vertical output flipping
-- rename ia_css_output_config.enable_mirror
-
-#ifndef ISP2401
-v2.1.6.1, Effective res on pipe
-#else
-v2.1.6.2 (2 changes parallel), Effective res on pipe
-#endif
-- Added input_effective_res to struct ia_css_pipe_config in ia_css_pipe_public.h.
-
-#ifndef ISP2401
-v2.1.6.2, CSS-API version file generated from individual changes
-#else
-v2.1.6.3 (2 changes parallel), CSS-API version file generated from individual changes
-#endif
-- Avoid merge-conflicts by generating version file from individual CSS-API changes.
-- Parallel CSS-API changes can map to the same version number after this change.
-- Version numbers for a change could increase due to parallel changes being merged.
-- The version number would not decrease for a change.
-
-#ifndef ISP2401
-v2.1.6.5 (2 changes parallel), Add SP FW error event
-#else
-v2.1.6.6 (4 changes parallel), Add SP FW error event
-#endif
-- Added FW error event. This gets raised when the SP FW runs into an
-- error situation from which it cannot recover.
-
-#ifndef ISP2401
-v2.1.6.5 (2 changes parallel), expose bnr FF enable bits in bnr public API
-#else
-v2.1.6.6 (4 changes parallel), expose bnr FF enable bits in bnr public API
-#endif
-- Added ff enable bits to bnr_public_config_dn_detect_ctrl_config_t struct
-
-#ifndef ISP2401
-v2.1.6.5 (2 changes parallel), ISP configuration per pipe
-#else
-v2.1.6.6 (4 changes parallel), ISP configuration per pipe
-#endif
-- Added ISP configuration per pipe support: p_isp_config field in
-- struct ia_css_pipe_config and ia_css_pipe_set_isp_config_on_pipe
-- and ia_css_pipe_set_isp_config functions
-
-#ifndef ISP2401
-v2.1.7.0, removed css_version.h
-#else
-v2.1.7.0 (2 changes parallel), removed css_version.h
-#endif
-- Removed css_version.h that was used for versioning in manual (non-CI) releases.
-
-#ifndef ISP2401
-v2.1.7.1, Add helpers (get and set) for ISP cfg per pipe
-#else
-v2.1.7.2 (2 changes parallel), Add helpers (get and set) for ISP cfg per pipe
-#endif
-- Add helpers (get and set) for ISP configuration per pipe
-
-#ifndef ISP2401
-v2.1.7.2, Add feature to lock all RAW buffers
-#else
-v2.1.7.3 (2 changes parallel), Add feature to lock all RAW buffers
-#endif
-- This API change adds a boolean flag (lock_all) in the stream_config struct.
-- If this flag is set to true, then all frames will be locked if locking is
-- enabled. By default this flag is set to false.
-- When this flag is false, then only buffers that are sent to the preview pipe
-- will be locked. If continuous viewfinder is disabled, the flag should be set
-- to true.
-
-#ifndef ISP2401
-v2.1.8.0 (2 changes parallel), Various changes to support ACC configuration per pipe
-#else
-v2.1.8.0 (4 changes parallel), Various changes to support ACC configuration per pipe
-#endif
-- Add ia_css_pipe_get_isp_config()
-- Remove ia_css_pipe_set_isp_config_on_pipe (duplicated
-- by ia_css_pipe_set_isp_config)
-- Add isp configuration as parameter for
-- ia_css_pipe_set_isp_config
-- Remove ia_css_pipe_isp_config_set()
-- Remove ia_css_pipe_isp_config_get()
-
-#ifndef ISP2401
-v2.1.8.2 (2 changes parallel), Added member num_invalid_frames to ia_css_pipe_info structure.
-#else
-v2.1.8.3 (4 changes parallel), Added member num_invalid_frames to ia_css_pipe_info structure.
-#endif
-- Added member num_invalid_frames to ia_css_pipe_info structure.
-- This helps the driver make sure that the first valid output
-- frame goes into the first user-supplied output buffer.
-
-#ifndef ISP2401
-v2.1.8.4 (2 changes parallel), ISYS EOF timestamp for output buffers
-#else
-v2.1.8.5 (4 changes parallel), ISYS EOF timestamp for output buffers
-#endif
-- driver gets EOF timer to every out frame . ia_css_buffer modified to accomodate same.
-
-#ifndef ISP2401
-v2.1.8.4 (4 changes parallel), display_config
-#else
-v2.1.8.5 (6 changes parallel), display_config
-#endif
-- Added formats- and output config parameters for configuration of the (optional) display output.
-
-#ifndef ISP2401
-v2.1.8.4 (2 changes parallel), Adding zoom region parameters to CSS API
-#else
-v2.1.8.5 (4 changes parallel), Adding zoom region parameters to CSS API
-#endif
-- Adding ia_css_point and ia_css_region structures to css-api.
-- Adding zoom_region(type ia_css_region) parameter to ia_css_dz_config structure.
-- By using this user can do the zoom based on zoom region and
-- the center of the zoom region is not restricted at the center of the input frame.
-
-#ifndef ISP2401
-v2.1.8.6 (1 changes parallel), Add new ia_css_fw_warning type
-#else
-v2.1.8.7 (3 changes parallel), Add new ia_css_fw_warning type
-#endif
-- Add IA_CSS_FW_WARNING_TAG_EXP_ID_FAILED enum to ia_css_fw_warning type
-- Extend sp_warning() with exp_id parameter
-
-#ifndef ISP2401
-v2.1.8.6 (1 changes parallel), Add includes in GC, GC2 kernel interface files
-#else
-v2.1.8.7 (3 changes parallel), Add includes in GC, GC2 kernel interface files
-#endif
-- add ia_css_ctc_types.h includes in ia_css_gc_types.h and ia_css_gc2_types.h. Needed to get ia_css_vamem_type.
-
-#ifndef ISP2401
-v2.1.9.0 (1 changes parallel), Introduce sp assert event.
-#else
-v2.1.9.0 (3 changes parallel), Introduce sp assert event.
-#endif
-- Add IA_CSS_EVENT_TYPE_FW_ASSERT. The FW sends the event in case an assert goes off.
-
-#ifndef ISP2401
-v2.1.9.1 (1 changes parallel), Exclude driver part from ia_css_buffer.h as it is also used by SP
-#else
-v2.1.9.2 (3 changes parallel), Exclude driver part from ia_css_buffer.h as it is also used by SP
-#endif
-- Excluded driver part of the interface from SP/ISP code
-- Driver I/F is not affected
-
-#ifndef ISP2401
-v2.1.9.2, added IA_CSS_EVENT_TYPE_TIMER
-#else
-v2.1.9.3 (2 changes parallel), added IA_CSS_EVENT_TYPE_TIMER
-#endif
-- Added a new event called IA_CSS_EVENT_TYPE_TIMER
-
-#ifndef ISP2401
-v2.1.10.0 (4 changes parallel), Add a flag "enable_dpc" to "struct ia_css_pipe_config"
-#else
-v2.1.10.0 (6 changes parallel), Add a flag "enable_dpc" to "struct ia_css_pipe_config"
-#endif
-- Add a flag "enable_dpc" to "struct ia_css_pipe_config"
-
-#ifndef ISP2401
-v2.1.10.6 (6 changes parallel), change the pipe version type from integer to enum
-#else
-v2.1.10.8 (9 changes parallel), change the pipe version type from integer to enum
-#endif
-- add new enum to enumerate ISP pipe version
-- change the pipe version type in pipe_config from integer to enum
-
-#ifndef ISP2401
-v2.1.13.0 (8 changes parallel), Stop Support for Skycam B0
-#else
-v2.1.14.0 (12 changes parallel), Stop Support for Skycam B0
-#endif
-- Remove a few pre-processor defines for Skycam B0/C0 as support
-
-#ifndef ISP2401
-v2.1.14.0 (24 changes parallel), change the pipe version type from integer to enum
-#else
-v2.1.15.0 (28 changes parallel), change the pipe version type from integer to enum
-#endif
-- remove the temporary workaround for backward compatability
-
-#ifndef ISP2401
-v2.1.14.0 (13 changes parallel), expose_gamma_enable_option
-#else
-v2.1.15.0 (17 changes parallel), expose_gamma_enable_option
-#endif
-- added enable param to gamma_corr_public_config
-- added documentation to rgbpp_public.h
-
-#ifndef ISP2401
-v2.1.14.0 (12 changes parallel), Remove deprecated FW_ERROR event.
-#else
-v2.1.15.0 (16 changes parallel), Remove deprecated FW_ERROR event.
-#endif
-- Remove code for deprecated FW_ERROR event.
-
-#ifndef ISP2401
-v2.1.14.3 (5 changes parallel), fix IEFD's puclic API types
-#else
-v2.1.15.5 (8 changes parallel), fix IEFD's puclic API types
-#endif
-- fix IEFD public API members types: rad_cu6_x1,rad_cu_unsharp_x1 & unsharp_amount
-
-#ifndef ISP2401
-v2.1.14.3 (5 changes parallel), Add IA_CSS_FW_WARNING_FRAME_PARAM_MISMATCH
-#else
-v2.1.15.5 (8 changes parallel), Add IA_CSS_FW_WARNING_FRAME_PARAM_MISMATCH
-#endif
-- Add IA_CSS_FW_WARNING_FRAME_PARAM_MISMATCH enum to ia_css_fw_warning type
-
-#ifndef ISP2401
-v2.1.14.4 (5 changes parallel), new API getter functions for gdc in buffer information
-#else
-v2.1.15.8 (11 changes parallel), add_flag_to_disable_continous_viewfinder
-- add a new flag in stream_config to disable continuous viewfinder
-- in ZSL use case.
-
-v2.1.16.0 (8 changes parallel), revert ia_css_skc_dvs_statistics field size change
-- Reverted field size change, change was not ready for driver yet.
-
-v2.1.17.0 (7 changes parallel), change CSS API to fix the shading correction off-center issue
-- update the ia_css_shading_info structure in ia_css_types.h
-
-v2.1.17.0 (32 changes parallel), add_flag_to_disable_continous_viewfinder_part2
-- remove the old interfaces
-
-v2.1.17.4 (8 changes parallel), Added public interface for setting the scaler LUT.
-- Added the public struct to output system and modified the global config struct.
-
-v2.1.17.5 (7 changes parallel), Add parameters for new TNR3 component
-- Add new parameters for new TNR3 component
-
-v2.1.17.6 (9 changes parallel), Update skycam DPC_MAX_NUMBER_OF_DP
-- Automated tooling requires an API change request
-- This change changes the implementation of #define DPC_MAX_NUMBER_OF_DP
-- it now returns a different number
-
-v2.1.17.6 (8 changes parallel), Return an error when both DPC and BDS are enabled in a pipe config
-- Return an error when both DPC and BDS are enabled in a pipe config
-
-v2.1.17.6 (9 changes parallel), new API getter functions for gdc in buffer information
-#endif
-- ia_css_pipe_get_dvs_filter() added
-- ia_css_pipe_get_gdc_in_buffer_info() added
-
-#ifndef ISP2401
-v2.1.14.5 (8 changes parallel), Update CNR2 ineffective values
-#else
-v2.1.17.7 (12 changes parallel), Update CNR2 ineffective values
-#endif
-- Fixed Incorrect ineffective values listed in ia_css_cnr_config
-- Correct Ineffective value is 8191
-
-#ifndef ISP2401
-v2.1.14.5 (8 changes parallel), af_roi_api
-#else
-v2.1.17.7 (12 changes parallel), af_roi_api
-#endif
-- added a new function to set AF ROI ia_css_set_af_roi
-- added a new struct ia_css_s3a_roi_offset
-
-#ifndef ISP2401
-v2.1.14.5 (8 changes parallel), remove x_y_end_from_ae_and_awb
-#else
-v2.1.17.7 (12 changes parallel), Enlarge AF AWB_FR stats buffers
-- Enlarge AF and AWB_FR stats buffers to support max grid width per stripe as oppose to per frame
-
-v2.1.17.7 (12 changes parallel), remove x_y_end_from_ae_and_awb
-#endif
-- added a flag to prepare removal of x_end and y_end from ae grid public config
-- added a flag to prepare removal of x_end and y_end from awb grid public config
-
-#ifndef ISP2401
-v2.1.14.5 (4 changes parallel), Added public interface for setting the scaler LUT.
-- Added the public struct to output system and modified the global config struct.
-#else
-v2.1.17.8 (5 changes parallel)
-- added input_yuv , input_raw to ia_css_binary_info.enable
-- struct, these attributes were always there but not saved
-- in the binary_info struct
-#endif
-
-#ifndef ISP2401
-v2.1.14.6 (8 changes parallel), add_flag_to_disable_continous_viewfinder
-- add a new flag in stream_config to disable continuous viewfinder
-- in ZSL use case.
-#else
-v2.1.17.9 (6 changes parallel), cleanup_awb_ae_rgb_integration_flags
-- this change only cleans up an approved api CR see wikis below
-#endif
-
-#ifndef ISP2401
-v2.1.14.6 (8 changes parallel), Enlarge AF AWB_FR stats buffers
-- Enlarge AF and AWB_FR stats buffers to support max grid width per stripe as oppose to per frame
-#else
-v2.1.17.10 (6 changes parallel), output_system_input_resolution
-- adedd gdc_output_system_in_resolution to pipe config struct
-#endif
-
-#ifndef ISP2401
-v2.1.14.8 (6 changes parallel), pipe config option for vf output bci mode downscaling
-#else
-v2.1.17.10 (5 changes parallel), Per pipe DPC configuration is added to ia_css_isp_parameters
-- Per pipe DPC configuration is added to ia_css_isp_parameters
-
-v2.1.17.10 (10 changes parallel), pipe config option for vf output bci mode downscaling
-#endif
-- vf downscaling using yuv_scale binary.
-
-#ifndef ISP2401
-v2.1.14.10 (7 changes parallel), Add scale mode GDC V2 LUT to CSS API
-#else
-v2.1.17.12 (11 changes parallel), Add scale mode GDC V2 LUT to CSS API
-#endif
-- Allow client to set global LUT for gdc v2 (First step in this change. See wiki page for more details)
-
-#ifndef ISP2401
-v2.1.14.10 (8 changes parallel), Include added to type-support.h.
-#else
-v2.1.17.12 (12 changes parallel), Include added to type-support.h.
-#endif
-- Include of hive/cell_support.h was added to type-support.h, in order to
-- have access to define HAVE_STDINT.
-
-#ifndef ISP2401
-v2.1.14.11 (7 changes parallel), Pipe configuration to enable BLI mode downscaling for
-#else
-v2.1.17.13 (11 changes parallel), Pipe configuration to enable BLI mode downscaling for
-#endif
-- BLI mode downscaling for capture post-processing
-
-#ifndef ISP2401
-v2.1.14.14 (9 changes parallel), Fix copyright headers (no functional change)
-#else
-v2.1.17.15 (8 changes parallel), Add copyright headers to css files
-- Add copyright headers to css API files
-
-v2.1.17.15 (8 changes parallel), add copyright header to include files
-- add copyright header to include files
-
-v2.1.17.15 (8 changes parallel), add copyright header to isp files
-- add copyright header to isp files
-
-v2.1.17.15 (8 changes parallel), add copyright header to refactored code
-- add copyright header to refactored code
-- (base, camera, runtime directories)
-
-v2.1.17.16 (13 changes parallel), Fix copyright headers (no functional change)
-#endif
-- No functional change; only fixes copyright headers
-
-#ifndef ISP2401
-v2.1.14.14 (6 changes parallel), Remove continuous mode special case handling in ia_css_pipe_set_isp_config
-#else
-v2.1.17.16 (10 changes parallel), Remove continuous mode special case handling in ia_css_pipe_set_isp_config
-#endif
-- For continuous mode isp_config was being send to all pipes,
-- even though API ia_css_pipe_set_isp_config is for single pipe
-- Removed incorrect case
-
-#ifndef ISP2401
-v2.1.14.14 (6 changes parallel), DVS statistics grid produced by accelerator
-#else
-v2.1.17.16 (5 changes parallel), Added documentation to formats_config header file
-- Added description of ranges for full-range flag
-
-v2.1.17.16 (10 changes parallel), DVS statistics grid produced by accelerator
-#endif
-- Add DVS statistics produced by accelerator grid to pipe info
-- Add ia_css_pipe_has_dvs_stats function
-
-#ifndef ISP2401
-v2.1.14.15 (7 changes parallel), cont_remove_x_y_end_from_ae_and_awb
-#else
-v2.1.17.17 (5 changes parallel), Provide the CSS interface to select the luma only binaries
-- Add a flag "enable_luma_only" to "struct ia_css_pipe_config"
-
-v2.1.17.17 (11 changes parallel), cont_remove_x_y_end_from_ae_and_awb
-#endif
-- this patch doesn't introduce any new api change, it only fixes a recent
-- api merged change (#31938) , in order to have success CI i had to upload an api change request
-
-#ifndef ISP2401
-v2.1.14.17 (6 changes parallel), Add XNR3 blending strength to kernel interface
-- Added a blending strength field to the XNR3 kernel interface to add
-- support for blending.
-#else
-v2.1.17.17 (10 changes parallel), GAC state dump for debug
-- added ia_css_dump_gac_state function
-
-v2.1.17.18 (23 changes parallel), output_format_nv12_16
-- added new output fromat nv12_16
-#endif
-
-#ifndef ISP2401
-v2.1.14.18 (22 changes parallel), eliminate two_pixels_per_clock field
-#else
-v2.1.17.18 (4 changes parallel), Remove author details from SKC src code
-- remove author details from skc src code
-
-v2.1.17.19 (26 changes parallel), eliminate two_pixels_per_clock field
-#endif
-- remove obsolete field two_pixels_per_clock
-
-#ifndef ISP2401
-v2.1.14.19 (3 changes parallel), Fix copyright headers (no functional change)
-#else
-v2.1.17.20 (7 changes parallel), Fix copyright headers (no functional change)
-#endif
-- No functional change; only fixes copyright headers
-
-#ifndef ISP2401
-v2.1.14.21 (3 changes parallel), ia_css_skc_dvs_statistics field size change
-- ia_css_skc_dvs_statistics field size change
-#else
-v2.1.17.20 (11 changes parallel), Add XNR3 blending strength to kernel interface
-- Added a blending strength field to the XNR3 kernel interface to add
-- support for blending.
-#endif
-
-#ifndef ISP2401
-v2.1.15.0 (3 changes parallel), revert ia_css_skc_dvs_statistics field size change
-- Reverted field size change, change was not ready for driver yet.
-#else
-v2.1.17.21 (24 changes parallel), Add N_CSS_PRBS_IDS and N_CSS_TPG_IDS
-- Add N_CSS_PRBS_IDS to reflect the number of ia_css_prbs_id enum
-- Add N_CSS_TPG_IDS to reflect the number of ia_css_tpg_id enum
-#endif
-
-#ifndef ISP2401
-v2.1.15.2 (3 changes parallel), Return an error when both DPC and BDS are enabled in a pipe config
-- Return an error when both DPC and BDS are enabled in a pipe config
-#else
-v2.1.17.23 (8 changes parallel), ia_css_skc_dvs_statistics field size change
-- ia_css_skc_dvs_statistics field size change
-#endif
-
-#ifndef ISP2401
-v2.1.15.3 (2 changes parallel), Update skycam DPC_MAX_NUMBER_OF_DP
-- Automated tooling requires an API change request
-- This change changes the implementation of #define DPC_MAX_NUMBER_OF_DP
-- it now returns a different number
-#else
-v2.1.19.0 (6 changes parallel)
-- Added code to calculate input_res using the Windows specification of binning
-#endif
-
-#ifndef ISP2401
-v2.1.15.3 (18 changes parallel), output_format_nv12_16
-- added new output fromat nv12_16
-#else
-v2.1.20.0 (7 changes parallel), Add interface to select TNR enabled binaries
-- Add a bool "enable_tnr" to "struct ia_css_pipe_config"
-
-v2.1.20.0 (6 changes parallel), OSYS & GDC Debug dump function addition
-- add GDC state dump function
-- add OSYS state dump function
-
-v2.1.20.4 (7 changes parallel), Add ref_buf_select parameter for TNR3 to kernel interface
-- Added a ref_buf_select parameter to the TNR3 kernel interface to add
-- support for multiple reference buffers.
-
-v2.1.20.4 (6 changes parallel), DVS MAX grid dimensions to cover maximal resolution
-- rename DVS_TABLE_HEIGHT/WIDTH to MAX_DVS_COORDS_TABLE_HEIGHT/WIDTH
-- modify value of the above macros to cover max resolution
-
-v2.1.20.5 (54 changes parallel), add input feeder calculations getter
-- add input_feeder_config public struct
-- add get_input_feeder_config getter
-
-v2.1.20.5 (4 changes parallel), Enable runtime updating mapped args for QoS extension pipe
-- added ia_css_pipe_update_qos_ext_mapped_arg()
-
-v2.1.20.7 (77 changes parallel), Add parameters to CPU routines via a macro.
-- Replaced CPU memory allocation functions with macros to add caller func name + line number.
-- This is done to help debug memory access issues, allocation issues, etc.
-- Changed API: only ia_css_env.h
-
-v2.1.20.7 (2 changes parallel), Frame format override
-- Added a function call to the pipe interface for overriding
-- the frame format as set in the pipe.
-- This is an optional interface that can be used under
-- some strict conditions.
-
-v2.1.20.7 (2 changes parallel), Output_system_in_res Information
-- Output_system_in_res_info field added to pipe_info struct
-
-v2.1.20.8, Temprarily disable memory debug features for SVOS.
-- Temporary commented out the additions to allow SKC testing till root cause found
-- Changed files ia_css_env.h and sh_css.c.
-
-v2.1.20.9, Enable ISP 2.7 naming
-- Add IA_CSS_PIPE_VERSION_2_7 to enum ia_css_pipe_version
-- Add #define SH_CSS_ISP_PIPE_VERSION_2_7 4
-#endif
-
-*/
-
-#endif /*__CSS_API_VERSION_H*/
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hive_isp_css_ddr_hrt_modified.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hive_isp_css_ddr_hrt_modified.h
deleted file mode 100644
index 39785aa21459..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hive_isp_css_ddr_hrt_modified.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * Copyright (c) 2010-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.
- */
-
-#ifndef _hive_isp_css_ddr_hrt_modified_h_
-#define _hive_isp_css_ddr_hrt_modified_h_
-
-#include <hmm_64/hmm.h>
-
-/* This function reads an image from DDR and stores it in the img_buf array
- that has been allocated by the caller.
- The specifics of how the pixels are stored into DDR by the DMA are taken
- into account (bits padded to a width of 256, depending on the number of
- elements per ddr word).
- The DMA specific parameters give to this function (elems_per_xword and sign_extend)
- should correspond to those given to the DMA engine.
- The address is a virtual address which will be translated to a physical address before
- data is loaded from or stored to that address.
-
- The return value is 0 in case of success and 1 in case of failure.
- */
-unsigned int
-hrt_isp_css_read_image_from_ddr(
- unsigned short *img_buf,
- unsigned int width,
- unsigned int height,
- unsigned int elems_per_xword,
- unsigned int sign_extend,
- hmm_ptr virt_addr);
-
-/* This function writes an image to DDR, keeping the same aspects into account as the read_image function
- above. */
-unsigned int
-hrt_isp_css_write_image_to_ddr(
- const unsigned short *img_buf,
- unsigned int width,
- unsigned int height,
- unsigned int elems_per_xword,
- unsigned int sign_extend,
- hmm_ptr virt_addr);
-
-/* return the size in bytes of an image (frame or plane). */
-unsigned int
-hrt_isp_css_sizeof_image_in_ddr(
- unsigned int width,
- unsigned int height,
- unsigned int bits_per_element);
-
-unsigned int
-hrt_isp_css_stride_of_image_in_ddr(
- unsigned int width,
- unsigned int bits_per_element);
-
-hmm_ptr
-hrt_isp_css_alloc_image_in_ddr(
- unsigned int width,
- unsigned int height,
- unsigned int elems_per_xword);
-
-hmm_ptr
-hrt_isp_css_calloc_image_in_ddr(
- unsigned int width,
- unsigned int height,
- unsigned int elems_per_xword);
-
-#ifndef HIVE_ISP_NO_GDC
-#include "gdc_v2_defs.h"
-
-hmm_ptr
-hrt_isp_css_alloc_gdc_lut_in_ddr(void);
-
-void
-hrt_isp_css_write_gdc_lut_to_ddr(
- short values[4][HRT_GDC_N],
- hmm_ptr virt_addr);
-#endif
-
-#ifdef _HIVE_ISP_CSS_FPGA_SYSTEM
-hmm_ptr
-hrt_isp_css_alloc_image_for_display(
- unsigned int width,
- unsigned int height,
- unsigned int elems_per_xword);
-
-hmm_ptr
-hrt_isp_css_calloc_image_for_display(
- unsigned int width,
- unsigned int height,
- unsigned int elems_per_xword);
-#endif
-
-/* New set of functions, these do not require the elems_per_xword, but use bits_per_element instead,
- this way the user does not need to know about the width of a DDR word. */
-unsigned int
-hrt_isp_css_read_unsigned(
- unsigned short *target,
- unsigned int width,
- unsigned int height,
- unsigned int source_bits_per_element,
- hmm_ptr source);
-
-unsigned int
-hrt_isp_css_read_signed(
- short *target,
- unsigned int width,
- unsigned int height,
- unsigned int source_bits_per_element,
- hmm_ptr source);
-
-unsigned int
-hrt_isp_css_write_unsigned(
- const unsigned short *source,
- unsigned int width,
- unsigned int height,
- unsigned int target_bits_per_element,
- hmm_ptr target);
-
-unsigned int
-hrt_isp_css_write_signed(
- const short *source,
- unsigned int width,
- unsigned int height,
- unsigned int target_bits_per_element,
- hmm_ptr target);
-
-hmm_ptr
-hrt_isp_css_alloc(
- unsigned int width,
- unsigned int height,
- unsigned int bits_per_element);
-
-hmm_ptr
-hrt_isp_css_calloc(
- unsigned int width,
- unsigned int height,
- unsigned int bits_per_element);
-
-#endif /* _hive_isp_css_ddr_hrt_modified_h_ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hive_isp_css_hrt_modified.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hive_isp_css_hrt_modified.h
deleted file mode 100644
index 342553d10e08..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hive_isp_css_hrt_modified.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * Copyright (c) 2010-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.
- */
-
-#ifndef _hive_isp_css_hrt_h
-#define _hive_isp_css_hrt_h
-
-#include "system_types.h"
-
-#include "hive_isp_css_host_ids_hrt.h"
-#include "hive_isp_css_defs.h"
-
-#ifdef HRT_ISP_CSS_CUSTOM_HOST
-#ifndef HRT_USE_VIR_ADDRS
-#define HRT_USE_VIR_ADDRS
-#endif
-/*#include "hive_isp_css_custom_host_hrt.h"*/
-#endif
-
-#include <gpio_block.h>
-#include <gp_regs.h>
-#include <gp_timer_hrt.h>
- #include <css_receiver_2400_hrt.h>
-// #include <isp2400_mamoiada_params.h>
-// #include <isp2400_support.h>
- /* insert idle signal clearing and setting around hrt_main */
- #if !defined(HRT_HW) || defined(HRT_ISP_CSS_INSERT_IDLE_SIGNAL)
- #define hrt_main _hrt_isp_css_main
- #endif
- #ifdef _HIVE_ISP_CSS_SPECMAN_SYSTEM
- #include "hive_isp_css_2400_specman_system.h"
- #else
-#if defined(IS_ISP_2400_MAMOIADA_SYSTEM)
- #include "hive_isp_css_2400_system.h"
-#elif defined(IS_ISP_2401_MAMOIADA_SYSTEM)
- #include "hive_isp_css_2401_system.h"
-#else
-#error "hive_isp_css_hrt_modified.h: SYSTEM must be one of {2400_MAMOIADA_SYSTEM, 2401_MAMOIADA_SYSTEM}"
-#endif
- #endif
-#include <sp_hrt.h>
-#include <input_system_hrt.h>
-#include <input_selector_hrt.h>
-#include <sig_monitor_hrt.h>
-
-#include "hive_isp_css_sdram_wakeup_hrt.h"
-#include "hive_isp_css_idle_signal_hrt.h"
-#include "hive_isp_css_sp_hrt.h"
-#include "hive_isp_css_isp_hrt.h"
-#include "hive_isp_css_streaming_to_mipi_hrt.h"
-#include "hive_isp_css_testbench_hrt.h"
-#include "hive_isp_css_streaming_monitors_hrt.h"
-#include "hive_isp_css_gp_regs_hrt.h"
-#if defined(IS_ISP_2400_MAMOIADA_SYSTEM)
-#include "hive_isp_css_irq_hrt.h"
-#elif defined(IS_ISP_2401_MAMOIADA_SYSTEM)
-#include "hive_isp_css_2401_irq_hrt.h"
-#else
-#error "hive_isp_css_hrt_modified.h: SYSTEM must be one of {2400_MAMOIADA_SYSTEM, 2401_MAMOIADA_SYSTEM}"
-#endif
-
-#include "hive_isp_css_stream_switch_hrt.h"
-
-#include "hive_isp_css_ddr_hrt_modified.h"
-#include "hive_isp_css_dma_set_hrt.h"
-
-#define HIVE_ISP_CSS_NO_STREAM_SWITCH 1
-
-#endif /* _hive_isp_css_hrt_h */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/input_formatter_global.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/input_formatter_global.h
index 5654d911db65..7558f4964313 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/input_formatter_global.h
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/input_formatter_global.h
@@ -107,22 +107,6 @@ struct input_formatter_cfg_s {
uint32_t block_no_reqs;
};
-#define DEFAULT_IF_CONFIG \
-{ \
- 0, /* start_line */\
- 0, /* start_column */\
- 0, /* left_padding */\
- 0, /* cropped_height */\
- 0, /* cropped_width */\
- 0, /* deinterleaving */\
- 0, /*.buf_vecs */\
- 0, /* buf_start_index */\
- 0, /* buf_increment */\
- 0, /* buf_eol_offset */\
- false, /* is_yuv420_format */\
- false /* block_no_reqs */\
-}
-
extern const hrt_address HIVE_IF_SRST_ADDRESS[N_INPUT_FORMATTER_ID];
extern const hrt_data HIVE_IF_SRST_MASK[N_INPUT_FORMATTER_ID];
extern const uint8_t HIVE_IF_SWITCH_CODE[N_INPUT_FORMATTER_ID];
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/resource_global.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/resource_global.h
deleted file mode 100644
index 01c915c033a9..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/resource_global.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __RESOURCE_GLOBAL_H_INCLUDED__
-#define __RESOURCE_GLOBAL_H_INCLUDED__
-
-#define IS_RESOURCE_VERSION_1
-
-typedef enum {
- DMA_CHANNEL_RESOURCE_TYPE,
- IRQ_CHANNEL_RESOURCE_TYPE,
- MEM_SECTION_RESOURCE_TYPE,
- N_RESOURCE_TYPE
-} resource_type_ID_t;
-
-typedef enum {
- PERMANENT_RESOURCE_RESERVATION,
- PERSISTENT_RESOURCE_RESERVATION,
- DEDICTATED_RESOURCE_RESERVATION,
- SHARED_RESOURCE_RESERVATION,
- N_RESOURCE_RESERVATION
-} resource_reservation_t;
-
-#endif /* __RESOURCE_GLOBAL_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/xmem_global.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/xmem_global.h
deleted file mode 100644
index 1d3a43abe55d..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/xmem_global.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __XMEM_GLOBAL_H_INCLUDED__
-#define __XMEM_GLOBAL_H_INCLUDED__
-
-#include "isp.h"
-
-#endif /* __XMEM_GLOBAL_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bamem.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bamem.h
deleted file mode 100644
index 6928965cf513..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bamem.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __BAMEM_H_INCLUDED__
-#define __BAMEM_H_INCLUDED__
-
-/*
- * This file is included on every cell {SP,ISP,host} and on every system
- * that uses the BAMEM device. It defines the API to DLI bridge
- *
- * System and cell specific interfaces and inline code are included
- * conditionally through Makefile path settings.
- *
- * - . system and cell agnostic interfaces, constants and identifiers
- * - public: system agnostic, cell specific interfaces
- * - private: system dependent, cell specific interfaces & inline implementations
- * - global: system specific constants and identifiers
- * - local: system and cell specific constants and identifiers
- */
-
-
-#include "system_local.h"
-#include "bamem_local.h"
-
-#ifndef __INLINE_BAMEM__
-#define STORAGE_CLASS_BAMEM_H extern
-#define STORAGE_CLASS_BAMEM_C
-#include "bamem_public.h"
-#else /* __INLINE_BAMEM__ */
-#define STORAGE_CLASS_BAMEM_H static inline
-#define STORAGE_CLASS_BAMEM_C static inline
-#include "bamem_private.h"
-#endif /* __INLINE_BAMEM__ */
-
-#endif /* __BAMEM_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bbb_config.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bbb_config.h
deleted file mode 100644
index 18bc5ef3d0bf..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bbb_config.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __BBB_CONFIG_H_INCLUDED__
-#define __BBB_CONFIG_H_INCLUDED__
-/* This header contains BBB defines common to ISP and host */
-
-#define BFA_MAX_KWAY (49)
-#define BFA_RW_LUT_SIZE (7)
-
-#define SAD3x3_IN_SHIFT (2) /* input right shift value for SAD3x3 */
-#define SAD3x3_OUT_SHIFT (2) /* output right shift value for SAD3x3 */
-
-/* XCU and BMA related defines shared between host and ISP
- * also need to be moved here */
-#endif /* __BBB_CONFIG_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/cpu_mem_support.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/cpu_mem_support.h
deleted file mode 100644
index 6d014fafb713..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/cpu_mem_support.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __CPU_MEM_SUPPORT_H_INCLUDED__
-#define __CPU_MEM_SUPPORT_H_INCLUDED__
-
-#if defined (__KERNEL__)
-#include <linux/string.h> /* memset */
-#else
-#include <string.h> /* memset */
-#endif
-
-#include "sh_css_internal.h" /* sh_css_malloc and sh_css_free */
-
-static inline void*
-ia_css_cpu_mem_alloc(unsigned int size)
-{
- return sh_css_malloc(size);
-}
-
-static inline void*
-ia_css_cpu_mem_copy(void* dst, const void* src, unsigned int size)
-{
- if(!src || !dst)
- return NULL;
-
- return memcpy(dst, src, size);
-}
-
-static inline void*
-ia_css_cpu_mem_set_zero(void* dst, unsigned int size)
-{
- if(!dst)
- return NULL;
-
- return memset(dst, 0, size);
-}
-
-static inline void
-ia_css_cpu_mem_free(void* ptr)
-{
- if(!ptr)
- return;
-
- sh_css_free(ptr);
-}
-
-#endif /* __CPU_MEM_SUPPORT_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2400_config.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2400_config.h
deleted file mode 100644
index ab3391716c82..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2400_config.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __ISP2400_CONFIG_H_INCLUDED__
-#define __ISP2400_CONFIG_H_INCLUDED__
-
-#define NUM_BITS 14
-#define NUM_SLICE_ELEMS 4
-#define ROUNDMODE ROUND_NEAREST_EVEN
-#define MAX_SHIFT_1W (NUM_BITS-1) /* Max number of bits a 1w input can be shifted */
-#define MAX_SHIFT_2W (2*NUM_BITS-1) /* Max number of bits a 2w input can be shifted */
-
-#endif /* __ISP2400_CONFIG_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2500_config.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2500_config.h
deleted file mode 100644
index 4fae856f5a23..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2500_config.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __ISP2500_CONFIG_H_INCLUDED__
-#define __ISP2500_CONFIG_H_INCLUDED__
-
-#define NUM_BITS 12
-#define NUM_SLICE_ELEMS 4
-#define ROUNDMODE ROUND_NEAREST_EVEN
-#define MAX_SHIFT_1W (NUM_BITS-1) /* Max number of bits a 1w input can be shifted */
-#define MAX_SHIFT_2W (2*NUM_BITS-1) /* Max number of bits a 2w input can be shifted */
-
-
-#define HAS_div_unit
-
-#define HAS_vec_sub
-
-#endif /* __ISP2500_CONFIG_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2600_config.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2600_config.h
deleted file mode 100644
index 6086be8cb0d3..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2600_config.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __ISP2600_CONFIG_H_INCLUDED__
-#define __ISP2600_CONFIG_H_INCLUDED__
-
-
-#define NUM_BITS 16
-
-
-#define NUM_SLICE_ELEMS 8
-#define ROUNDMODE ROUND_NEAREST_EVEN
-#define MAX_SHIFT_1W (NUM_BITS-1) /* Max number of bits a 1w input can be shifted */
-#define MAX_SHIFT_2W (2*NUM_BITS-1) /* Max number of bits a 2w input can be shifted */
-#define ISP_NWAY 32 /* Number of elements in a vector in ISP 2600 */
-
-#define HAS_div_unit
-#define HAS_1w_sqrt_u_unit
-#define HAS_2w_sqrt_u_unit
-
-#define HAS_vec_sub
-
-#endif /* __ISP2600_CONFIG_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2601_config.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2601_config.h
deleted file mode 100644
index beceefa24ca0..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp2601_config.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef ISP2401
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __ISP2601_CONFIG_H_INCLUDED__
-#define __ISP2601_CONFIG_H_INCLUDED__
-
-#define NUM_BITS 16
-#define ISP_VEC_ELEMBITS NUM_BITS
-#define ISP_NWAY 32
-#define NUM_SLICE_ELEMS 4
-#define ROUNDMODE ROUND_NEAREST_EVEN
-#define MAX_SHIFT_1W (NUM_BITS-1) /* Max number of bits a 1w input can be shifted */
-#define MAX_SHIFT_2W (2*NUM_BITS-1) /* Max number of bits a 2w input can be shifted */
-
-#define HAS_div_unit
-#define HAS_bfa_unit
-#define HAS_1w_sqrt_u_unit
-#define HAS_2w_sqrt_u_unit
-
-#define HAS_vec_sub
-
-/* Bit widths and element widths defined in HW implementation of BFA */
-#define BFA_THRESHOLD_BIT_CNT (8)
-#define BFA_THRESHOLD_MASK ((1<<BFA_THRESHOLD_BIT_CNT)-1)
-#define BFA_SW_BIT_CNT (7)
-#define BFA_SW_MASK ((1<<BFA_SW_BIT_CNT)-1)
-
-#define BFA_RW_BIT_CNT (7)
-#define BFA_RW_MASK ((1<<BFA_RW_BIT_CNT)-1)
-#define BFA_RW_SLOPE_BIT_POS (8)
-#define BFA_RW_SLOPE_BIT_SHIFT (5)
-
-#define BFA_RW_IDX_BIT_CNT (3)
-#define BFA_RW_FRAC_BIT_CNT (5)
-#define BFA_RW_LUT0_FRAC_START_BIT (0)
-#define BFA_RW_LUT0_FRAC_END_BIT (BFA_RW_LUT0_FRAC_START_BIT+BFA_RW_FRAC_BIT_CNT-1) /* 4 */
-#define BFA_RW_LUT1_FRAC_START_BIT (2)
-#define BFA_RW_LUT1_FRAC_END_BIT (BFA_RW_LUT1_FRAC_START_BIT+BFA_RW_FRAC_BIT_CNT-1) /* 6 */
-/* LUT IDX end bit computation, start+idx_bit_cnt-2, one -1 comes as we count
- * bits from 0, another -1 comes as we use 2 lut table, so idx_bit_cnt is one
- * bit more */
-#define BFA_RW_LUT0_IDX_START_BIT (BFA_RW_LUT0_FRAC_END_BIT+1) /* 5 */
-#define BFA_RW_LUT0_IDX_END_BIT (BFA_RW_LUT0_IDX_START_BIT+BFA_RW_IDX_BIT_CNT-2) /* 6 */
-#define BFA_RW_LUT1_IDX_START_BIT (BFA_RW_LUT1_FRAC_END_BIT + 1) /* 7 */
-#define BFA_RW_LUT1_IDX_END_BIT (BFA_RW_LUT1_IDX_START_BIT+BFA_RW_IDX_BIT_CNT-2) /* 8 */
-#define BFA_RW_LUT_THRESHOLD (1<<(BFA_RW_LUT1_IDX_END_BIT-1)) /* 0x80 : next bit after lut1 end is set */
-#define BFA_RW_LUT1_IDX_OFFSET ((1<<(BFA_RW_IDX_BIT_CNT-1))-1) /* 3 */
-
-#define BFA_CP_MASK (0xFFFFFF80)
-#define BFA_SUBABS_SHIFT (6)
-#define BFA_SUBABS_BIT_CNT (8)
-#define BFA_SUBABS_MAX ((1<<BFA_SUBABS_BIT_CNT)-1)
-#define BFA_SUBABSSAT_BIT_CNT (9)
-#define BFA_SUBABSSAT_MAX ((1<<BFA_SUBABSSAT_BIT_CNT)-1)
-#define BFA_WEIGHT_SHIFT (6)
-
-#endif /* __ISP2601_CONFIG_H_INCLUDED__ */
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_config.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_config.h
deleted file mode 100644
index 80506f2419a8..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_config.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __ISP_CONFIG_H_INCLUDED__
-#define __ISP_CONFIG_H_INCLUDED__
-
-#if defined(ISP2400) || defined(ISP2401)
-#include "isp2400_config.h"
-#else
-#error "Please define a core {ISP2400, ISP2401}"
-#endif
-
-#endif /* __ISP_CONFIG_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w.h
deleted file mode 100644
index 0d978e5911c0..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w.h
+++ /dev/null
@@ -1,844 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __ISP_OP1W_H_INCLUDED__
-#define __ISP_OP1W_H_INCLUDED__
-
-/*
- * This file is part of the Multi-precision vector operations exstension package.
- */
-
-/*
- * Single-precision vector operations
- */
-
-/*
- * Prerequisites:
- *
- */
-
-#ifdef INLINE_ISP_OP1W
-#define STORAGE_CLASS_ISP_OP1W_FUNC_H static inline
-#define STORAGE_CLASS_ISP_OP1W_DATA_H static inline_DATA
-#else /* INLINE_ISP_OP1W */
-#define STORAGE_CLASS_ISP_OP1W_FUNC_H extern
-#define STORAGE_CLASS_ISP_OP1W_DATA_H extern_DATA
-#endif /* INLINE_ISP_OP1W */
-
-/*
- * Single-precision data type specification
- */
-
-#include "isp_op1w_types.h"
-#include "isp_op2w_types.h" // for doubling operations.
-
-/*
- * Single-precision prototype specification
- */
-
-/* Arithmetic */
-
-/* @brief bitwise AND
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return bitwise and of both input arguments
- *
- * This function will calculate the bitwise and.
- * result = _a & _b
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_and(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief bitwise OR
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return bitwise or of both input arguments
- *
- * This function will calculate the bitwise or.
- * result = _a | _b
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_or(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief bitwise XOR
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return bitwise xor of both input arguments
- *
- * This function will calculate the bitwise xor.
- * result = _a ^ _b
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_xor(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief bitwise inverse
- *
- * @param[in] _a first argument
- *
- * @return bitwise inverse of both input arguments
- *
- * This function will calculate the bitwise inverse.
- * result = ~_a
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_inv(
- const tvector1w _a);
-
-/* Additive */
-
-/* @brief addition
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return sum of both input arguments
- *
- * This function will calculate the sum of the input arguments.
- * in case of overflow it will wrap around.
- * result = _a + _b
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_add(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief subtraction
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _b subtracted from _a.
- *
- * This function will subtract _b from _a.
- * in case of overflow it will wrap around.
- * result = _a - _b
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_sub(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief saturated addition
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return saturated sum of both input arguments
- *
- * This function will calculate the sum of the input arguments.
- * in case of overflow it will saturate.
- * result = CLIP(_a + _b, MIN_RANGE, MAX_RANGE);
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_addsat(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief saturated subtraction
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return saturated subtraction of both input arguments
- *
- * This function will subtract _b from _a.
- * in case of overflow it will saturate.
- * result = CLIP(_a - _b, MIN_RANGE, MAX_RANGE);
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_subsat(
- const tvector1w _a,
- const tvector1w _b);
-
-#ifdef ISP2401
-/* @brief Unsigned saturated subtraction
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return saturated subtraction of both input arguments
- *
- * This function will subtract _b from _a.
- * in case of overflow it will saturate.
- * result = CLIP(_a - _b, 0, MAX_RANGE);
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w_unsigned OP_1w_subsat_u(
- const tvector1w_unsigned _a,
- const tvector1w_unsigned _b);
-
-#endif
-/* @brief subtraction with shift right and rounding
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return (a - b) >> 1
- *
- * This function subtracts _b from _a and right shifts
- * the result by 1 bit with rounding.
- * No overflow can occur.
- * result = (_a - _b) >> 1
- *
- * Note: This function will be deprecated due to
- * the naming confusion and it will be replaced
- * by "OP_1w_subhalfrnd".
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_subasr1(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief Subtraction with shift right and rounding
- *
- * @param[in] _a first operand
- * @param[in] _b second operand
- *
- * @return (_a - _b) >> 1
- *
- * This function subtracts _b from _a and right shifts
- * the result by 1 bit with rounding.
- * No overflow can occur.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_subhalfrnd(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief Subtraction with shift right and no rounding
- *
- * @param[in] _a first operand
- * @param[in] _b second operand
- *
- * @return (_a - _b) >> 1
- *
- * This function subtracts _b from _a and right shifts
- * the result by 1 bit without rounding (i.e. truncation).
- * No overflow can occur.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_subhalf(
- const tvector1w _a,
- const tvector1w _b);
-
-
-/* @brief saturated absolute value
- *
- * @param[in] _a input
- *
- * @return saturated absolute value of the input
- *
- * This function will calculate the saturated absolute value of the input.
- * in case of overflow it will saturate.
- * if (_a > 0) return _a;<br>
- * else return CLIP(-_a, MIN_RANGE, MAX_RANGE);<br>
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_abs(
- const tvector1w _a);
-
-/* @brief saturated absolute difference
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return sat(abs(a-b));
- *
- * This function will calculate the saturated absolute value
- * of the saturated difference of both inputs.
- * result = sat(abs(sat(_a - _b)));
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_subabssat(
- const tvector1w _a,
- const tvector1w _b);
-
-/* Multiplicative */
-
-/* @brief doubling multiply
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return product of _a and _b
- *
- * This function will calculate the product
- * of the input arguments and returns a double
- * precision result.
- * No overflow can occur.
- * result = _a * _b;
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector2w OP_1w_muld(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief integer multiply
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return product of _a and _b
- *
- * This function will calculate the product
- * of the input arguments and returns the LSB
- * aligned single precision result.
- * In case of overflow it will wrap around.
- * result = _a * _b;
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_mul(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief fractional saturating multiply
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return saturated product of _a and _b
- *
- * This function will calculate the fixed point
- * product of the input arguments
- * and returns a single precision result.
- * In case of overflow it will saturate.
- * FP_UNITY * FP_UNITY => FP_UNITY.
- * result = CLIP(_a * _b >> (NUM_BITS-1), MIN_RANGE, MAX_RANGE);
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_qmul(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief fractional saturating multiply with rounding
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return product of _a and _b
- *
- * This function will calculate the fixed point
- * product of the input arguments
- * and returns a single precision result.
- * FP_UNITY * FP_UNITY => FP_UNITY.
- * Depending on the rounding mode of the core
- * it will round to nearest or to nearest even.
- * result = CLIP(_a * _b >> (NUM_BITS-1), MIN_RANGE, MAX_RANGE);
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_qrmul(
- const tvector1w _a,
- const tvector1w _b);
-
-/* Comparative */
-
-/* @brief equal
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a == _b
- *
- * This function will return true if both inputs
- * are equal, and false if not equal.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tflags OP_1w_eq(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief not equal
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a != _b
- *
- * This function will return false if both inputs
- * are equal, and true if not equal.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tflags OP_1w_ne(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief less or equal
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a <= _b
- *
- * This function will return true if _a is smaller
- * or equal than _b.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tflags OP_1w_le(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief less then
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a < _b
- *
- * This function will return true if _a is smaller
- * than _b.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tflags OP_1w_lt(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief greater or equal
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a >= _b
- *
- * This function will return true if _a is greater
- * or equal than _b.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tflags OP_1w_ge(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief greater than
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a > _b
- *
- * This function will return true if _a is greater
- * than _b.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tflags OP_1w_gt(
- const tvector1w _a,
- const tvector1w _b);
-
-/* Shift */
-
-/* @brief aritmetic shift right
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a >> _b
- *
- * This function will shift _a with _b bits to the right,
- * preserving the sign bit.
- * It asserts 0 <= _b <= MAX_SHIFT_1W.
- *
- * The operation count for this function assumes that
- * the shift amount is a cloned scalar input.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_asr(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief aritmetic shift right with rounding
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a >> _b
- *
- * If _b < NUM_BITS, this function will shift _a with _b bits to the right,
- * preserving the sign bit, and depending on the rounding mode of the core
- * it will round to nearest or to nearest even.
- * If _b >= NUM_BITS, this function will return 0.
- * It asserts 0 <= _b <= MAX_SHIFT_1W.
- * The operation count for this function assumes that
- * the shift amount is a cloned scalar input.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_asrrnd(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief saturating arithmetic shift left
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a << _b
- *
- * If _b < MAX_BITDEPTH, this function will shift _a with _b bits to the left,
- * saturating at MIN_RANGE/MAX_RANGE in case of overflow.
- * If _b >= MAX_BITDEPTH, this function will return MIN_RANGE if _a < 0,
- * MAX_RANGE if _a > 0, 0 if _a == 0.
- * (with MAX_BITDEPTH=64)
- * It asserts 0 <= _b <= MAX_SHIFT_1W.
- * The operation count for this function assumes that
- * the shift amount is a cloned scalar input.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_asl(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief saturating aritmetic shift left
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a << _b
- *
- * This function is identical to OP_1w_asl( )
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_aslsat(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief logical shift left
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a << _b
- *
- * This function will shift _a with _b bits to the left.
- * It will insert zeroes on the right.
- * It asserts 0 <= _b <= MAX_SHIFT_1W.
- * The operation count for this function assumes that
- * the shift amount is a cloned scalar input.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_lsl(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief logical shift right
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a >> _b
- *
- * This function will shift _a with _b bits to the right.
- * It will insert zeroes on the left.
- * It asserts 0 <= _b <= MAX_SHIFT_1W.
- * The operation count for this function assumes that
- * the shift amount is a cloned scalar input.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_lsr(
- const tvector1w _a,
- const tvector1w _b);
-
-#ifdef ISP2401
-/* @brief bidirectional saturating arithmetic shift
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a << |_b| if _b is positive
- * _a >> |_b| if _b is negative
- *
- * If _b > 0, this function will shift _a with _b bits to the left,
- * saturating at MIN_RANGE/MAX_RANGE in case of overflow.
- * if _b < 0, this function will shift _a with _b bits to the right.
- * It asserts -MAX_SHIFT_1W <= _b <= MAX_SHIFT_1W.
- * If _b = 0, it returns _a.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_ashift_sat(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief bidirectional non-saturating arithmetic shift
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a << |_b| if _b is positive
- * _a >> |_b| if _b is negative
- *
- * If _b > 0, this function will shift _a with _b bits to the left,
- * no saturation is performed in case of overflow.
- * if _b < 0, this function will shift _a with _b bits to the right.
- * It asserts -MAX_SHIFT_1W <= _b <= MAX_SHIFT_1W.
- * If _b = 0, it returns _a.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_ashift(
- const tvector1w _a,
- const tvector1w _b);
-
-
-/* @brief bidirectional logical shift
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a << |_b| if _b is positive
- * _a >> |_b| if _b is negative
- *
- * This function will shift _a with _b bits to the left if _b is positive.
- * This function will shift _a with _b bits to the right if _b is negative.
- * It asserts -MAX_SHIFT_1W <= _b <= MAX_SHIFT_1W.
- * It inserts zeros on the left or right depending on the shift direction:
- * right or left.
- * The operation count for this function assumes that
- * the shift amount is a cloned scalar input.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_lshift(
- const tvector1w _a,
- const tvector1w _b);
-
-#endif
-/* Cast */
-
-/* @brief Cast from int to 1w
- *
- * @param[in] _a input
- *
- * @return _a
- *
- * This function casts the input from integer type to
- * single precision. It asserts there is no overflow.
- *
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_int_cast_to_1w(
- const int _a);
-
-/* @brief Cast from 1w to int
- *
- * @param[in] _a input
- *
- * @return _a
- *
- * This function casts the input from single precision type to
- * integer, preserving value and sign.
- *
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H int OP_1w_cast_to_int(
- const tvector1w _a);
-
-/* @brief Cast from 1w to 2w
- *
- * @param[in] _a input
- *
- * @return _a
- *
- * This function casts the input from single precision type to
- * double precision, preserving value and sign.
- *
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector2w OP_1w_cast_to_2w(
- const tvector1w _a);
-
-/* @brief Cast from 2w to 1w
- *
- * @param[in] _a input
- *
- * @return _a
- *
- * This function casts the input from double precision type to
- * single precision. In case of overflow it will wrap around.
- *
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_2w_cast_to_1w(
- const tvector2w _a);
-
-
-/* @brief Cast from 2w to 1w with saturation
- *
- * @param[in] _a input
- *
- * @return _a
- *
- * This function casts the input from double precision type to
- * single precision after saturating it to the range of single
- * precision.
- *
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_2w_sat_cast_to_1w(
- const tvector2w _a);
-
-/* clipping */
-
-/* @brief Clip asymmetrical
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a clipped between ~_b and b
- *
- * This function will clip the first argument between
- * (-_b - 1) and _b.
- * It asserts _b >= 0.
- *
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_clip_asym(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief Clip zero
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a clipped beteween 0 and _b
- *
- * This function will clip the first argument between
- * zero and _b.
- * It asserts _b >= 0.
- *
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_clipz(
- const tvector1w _a,
- const tvector1w _b);
-
-/* division */
-
-/* @brief Truncated division
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return trunc( _a / _b )
- *
- * This function will divide the first argument by
- * the second argument, with rounding toward 0.
- * If _b == 0 and _a < 0, the function will return MIN_RANGE.
- * If _b == 0 and _a == 0, the function will return 0.
- * If _b == 0 and _a > 0, the function will return MAX_RANGE.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_div(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief Fractional saturating divide
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a / _b
- *
- * This function will perform fixed point division of
- * the first argument by the second argument, with rounding toward 0.
- * In case of overflow it will saturate.
- * If _b == 0 and _a < 0, the function will return MIN_RANGE.
- * If _b == 0 and _a == 0, the function will return 0.
- * If _b == 0 and _a > 0, the function will return MAX_RANGE.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_qdiv(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief Modulo
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a % _b
- *
- * This function will return the remainder r = _a - _b * trunc( _a / _b ),
- * Note that the sign of the remainder is always equal to the sign of _a.
- * If _b == 0 the function will return _a.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_mod(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief Unsigned integer Square root
- *
- * @param[in] _a input
- *
- * @return Integer square root of _a
- *
- * This function will calculate the Integer square root of _a
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w_unsigned OP_1w_sqrt_u(
- const tvector1w_unsigned _a);
-
-/* Miscellaneous */
-
-/* @brief Multiplexer
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- * @param[in] _c condition
- *
- * @return _c ? _a : _b
- *
- * This function will return _a if the condition _c
- * is true and _b otherwise.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_mux(
- const tvector1w _a,
- const tvector1w _b,
- const tflags _c);
-
-/* @brief Average without rounding
- *
- * @param[in] _a first operand
- * @param[in] _b second operand
- *
- * @return (_a + _b) >> 1
- *
- * This function will add _a and _b, and right shift
- * the result by one without rounding. No overflow
- * will occur because addition is performed in the
- * proper precision.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_avg(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief Average with rounding
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return (_a + _b) >> 1
- *
- * This function will add _a and _b at full precision,
- * and right shift with rounding the result with 1 bit.
- * Depending on the rounding mode of the core
- * it will round to nearest or to nearest even.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_avgrnd(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief Minimum
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return (_a < _b) ? _a : _b;
- *
- * This function will return the smallest of both
- * input arguments.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_min(
- const tvector1w _a,
- const tvector1w _b);
-
-/* @brief Maximum
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return (_a > _b) ? _a : _b;
- *
- * This function will return the largest of both
- * input arguments.
- */
-STORAGE_CLASS_ISP_OP1W_FUNC_H tvector1w OP_1w_max(
- const tvector1w _a,
- const tvector1w _b);
-
-#ifndef INLINE_ISP_OP1W
-#define STORAGE_CLASS_ISP_OP1W_FUNC_C
-#define STORAGE_CLASS_ISP_OP1W_DATA_C const
-#else /* INLINE_ISP_OP1W */
-#define STORAGE_CLASS_ISP_OP1W_FUNC_C STORAGE_CLASS_ISP_OP1W_FUNC_H
-#define STORAGE_CLASS_ISP_OP1W_DATA_C STORAGE_CLASS_ISP_OP1W_DATA_H
-#include "isp_op1w.c"
-#define ISP_OP1W_INLINED
-#endif /* INLINE_ISP_OP1W */
-
-#endif /* __ISP_OP1W_H_INCLUDED__ */
-
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w_types.h
deleted file mode 100644
index c81e587509a1..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w_types.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __ISP_OP1W_TYPES_H_INCLUDED__
-#define __ISP_OP1W_TYPES_H_INCLUDED__
-
-/*
- * This file is part of the Multi-precision vector operations exstension package.
- */
-
-/*
- * Single-precision vector operations
- */
-
-/*
- * Prerequisites:
- *
- */
-
-#include "mpmath.h"
-
-/*
- * Single-precision data type specification
- */
-
-
-typedef mpsdata_t tvector1w;
-typedef mpsdata_t tscalar1w;
-typedef spsdata_t tflags;
-typedef mpudata_t tvector1w_unsigned;
-typedef mpsdata_t tscalar1w_weight;
-typedef mpsdata_t tvector1w_signed_positive;
-typedef mpsdata_t tvector1w_weight;
-#ifdef ISP2401
-typedef bool tscalar_bool;
-#endif
-
-typedef struct {
- tvector1w d;
- tflags f;
-} tvector1w_tflags1w;
-
-#endif /* __ISP_OP1W_TYPES_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w.h
deleted file mode 100644
index 7575d260b837..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w.h
+++ /dev/null
@@ -1,674 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __ISP_OP2W_H_INCLUDED__
-#define __ISP_OP2W_H_INCLUDED__
-
-/*
- * This file is part of the Multi-precision vector operations exstension package.
- */
-
-/*
- * Double-precision vector operations
- */
-
-/*
- * Prerequisites:
- *
- */
-
-#ifdef INLINE_ISP_OP2W
-#define STORAGE_CLASS_ISP_OP2W_FUNC_H static inline
-#define STORAGE_CLASS_ISP_OP2W_DATA_H static inline_DATA
-#else /* INLINE_ISP_OP2W */
-#define STORAGE_CLASS_ISP_OP2W_FUNC_H extern
-#define STORAGE_CLASS_ISP_OP2W_DATA_H extern_DATA
-#endif /* INLINE_ISP_OP2W */
-
-/*
- * Double-precision data type specification
- */
-
-#include "isp_op2w_types.h"
-
-/*
- * Double-precision prototype specification
- */
-
-/* Arithmetic */
-
-/* @brief bitwise AND
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return bitwise and of both input arguments
- *
- * This function will calculate the bitwise and.
- * result = _a & _b
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_and(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief bitwise OR
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return bitwise or of both input arguments
- *
- * This function will calculate the bitwise or.
- * result = _a | _b
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_or(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief bitwise XOR
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return bitwise xor of both input arguments
- *
- * This function will calculate the bitwise xor.
- * result = _a ^ _b
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_xor(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief bitwise inverse
- *
- * @param[in] _a first argument
- *
- * @return bitwise inverse of both input arguments
- *
- * This function will calculate the bitwise inverse.
- * result = ~_a
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_inv(
- const tvector2w _a);
-
-/* Additive */
-
-/* @brief addition
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return sum of both input arguments
- *
- * This function will calculate the sum of the input arguments.
- * in case of overflow it will wrap around.
- * result = _a + _b
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_add(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief subtraction
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _b subtracted from _a.
- *
- * This function will subtract _b from _a.
- * in case of overflow it will wrap around.
- * result = _a - _b
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_sub(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief saturated addition
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return saturated sum of both input arguments
- *
- * This function will calculate the sum of the input arguments.
- * in case of overflow it will saturate
- * result = CLIP(_a + _b, MIN_RANGE, MAX_RANGE);
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_addsat(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief saturated subtraction
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return saturated subtraction of both input arguments
- *
- * This function will subtract _b from _a.
- * in case of overflow it will saturate
- * result = CLIP(_a - _b, MIN_RANGE, MAX_RANGE);
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_subsat(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief subtraction with shift right and rounding
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return (a - b) >> 1
- *
- * This function subtracts _b from _a and right shifts
- * the result by 1 bit with rounding.
- * No overflow can occur.
- * result = (_a - _b) >> 1
- *
- * Note: This function will be deprecated due to
- * the naming confusion and it will be replaced
- * by "OP_2w_subhalfrnd".
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_subasr1(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief Subtraction with shift right and rounding
- *
- * @param[in] _a first operand
- * @param[in] _b second operand
- *
- * @return (_a - _b) >> 1
- *
- * This function subtracts _b from _a and right shifts
- * the result by 1 bit with rounding.
- * No overflow can occur.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_subhalfrnd(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief Subtraction with shift right and no rounding
- *
- * @param[in] _a first operand
- * @param[in] _b second operand
- *
- * @return (_a - _b) >> 1
- *
- * This function subtracts _b from _a and right shifts
- * the result by 1 bit without rounding (i.e. truncation).
- * No overflow can occur.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_subhalf(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief saturated absolute value
- *
- * @param[in] _a input
- *
- * @return saturated absolute value of the input
- *
- * This function will calculate the saturated absolute value of the input.
- * In case of overflow it will saturate.
- * if (_a > 0) return _a;<br>
- * else return CLIP(-_a, MIN_RANGE, MAX_RANGE);<br>
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_abs(
- const tvector2w _a);
-
-/* @brief saturated absolute difference
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return sat(abs(sat(a-b)));
- *
- * This function will calculate the saturated absolute value
- * of the saturated difference of both inputs.
- * result = sat(abs(sat(_a - _b)));
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_subabssat(
- const tvector2w _a,
- const tvector2w _b);
-
-/* Multiplicative */
-
-/* @brief integer multiply
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return product of _a and _b
- *
- * This function will calculate the product
- * of the input arguments and returns the LSB
- * aligned double precision result.
- * In case of overflow it will wrap around.
- * result = _a * _b;
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_mul(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief fractional saturating multiply
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return saturated product of _a and _b
- *
- * This function will calculate the fixed point
- * product of the input arguments
- * and returns a double precision result.
- * In case of overflow it will saturate.
- * result =((_a * _b) << 1) >> (2*NUM_BITS);
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_qmul(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief fractional saturating multiply with rounding
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return product of _a and _b
- *
- * This function will calculate the fixed point
- * product of the input arguments
- * and returns a double precision result.
- * Depending on the rounding mode of the core
- * it will round to nearest or to nearest even.
- * In case of overflow it will saturate.
- * result = ((_a * _b) << 1) >> (2*NUM_BITS);
- */
-
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_qrmul(
- const tvector2w _a,
- const tvector2w _b);
-
-/* Comparative */
-
-/* @brief equal
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a == _b
- *
- * This function will return true if both inputs
- * are equal, and false if not equal.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tflags OP_2w_eq(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief not equal
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a != _b
- *
- * This function will return false if both inputs
- * are equal, and true if not equal.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tflags OP_2w_ne(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief less or equal
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a <= _b
- *
- * This function will return true if _a is smaller
- * or equal than _b.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tflags OP_2w_le(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief less then
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a < _b
- *
- * This function will return true if _a is smaller
- * than _b.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tflags OP_2w_lt(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief greater or equal
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a >= _b
- *
- * This function will return true if _a is greater
- * or equal than _b.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tflags OP_2w_ge(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief greater than
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a > _b
- *
- * This function will return true if _a is greater
- * than _b.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tflags OP_2w_gt(
- const tvector2w _a,
- const tvector2w _b);
-
-/* Shift */
-
-/* @brief aritmetic shift right
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a >> _b
- *
- * This function will shift _a with _b bits to the right,
- * preserving the sign bit.
- * It asserts 0 <= _b <= MAX_SHIFT_2W.
- * The operation count for this function assumes that
- * the shift amount is a cloned scalar input.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_asr(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief aritmetic shift right with rounding
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a >> _b
- *
- * If _b < 2*NUM_BITS, this function will shift _a with _b bits to the right,
- * preserving the sign bit, and depending on the rounding mode of the core
- * it will round to nearest or to nearest even.
- * If _b >= 2*NUM_BITS, this function will return 0.
- * It asserts 0 <= _b <= MAX_SHIFT_2W.
- * The operation count for this function assumes that
- * the shift amount is a cloned scalar input.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_asrrnd(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief saturating aritmetic shift left
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a << _b
- *
- * If _b < MAX_BITDEPTH, this function will shift _a with _b bits to the left,
- * saturating at MIN_RANGE/MAX_RANGE in case of overflow.
- * If _b >= MAX_BITDEPTH, this function will return MIN_RANGE if _a < 0,
- * MAX_RANGE if _a > 0, 0 if _a == 0.
- * (with MAX_BITDEPTH=64)
- * It asserts 0 <= _b <= MAX_SHIFT_2W.
- * The operation count for this function assumes that
- * the shift amount is a cloned scalar input.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_asl(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief saturating aritmetic shift left
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a << _b
- *
- * This function is identical to OP_2w_asl( )
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_aslsat(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief logical shift left
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a << _b
- *
- * This function will shift _a with _b bits to the left.
- * It will insert zeroes on the right.
- * It asserts 0 <= _b <= MAX_SHIFT_2W.
- * The operation count for this function assumes that
- * the shift amount is a cloned scalar input.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_lsl(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief logical shift right
- *
- * @param[in] _a input
- * @param[in] _b shift amount
- *
- * @return _a >> _b
- *
- * This function will shift _a with _b bits to the right.
- * It will insert zeroes on the left.
- * It asserts 0 <= _b <= MAX_SHIFT_2W.
- * The operation count for this function assumes that
- * the shift amount is a cloned scalar input.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_lsr(
- const tvector2w _a,
- const tvector2w _b);
-
-/* clipping */
-
-/* @brief Clip asymmetrical
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a clipped between ~_b and b
- *
- * This function will clip the first argument between
- * (-_b - 1) and _b.
- * It asserts _b >= 0.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_clip_asym(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief Clip zero
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return _a clipped beteween 0 and _b
- *
- * This function will clip the first argument between
- * zero and _b.
- * It asserts _b >= 0.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_clipz(
- const tvector2w _a,
- const tvector2w _b);
-
-/* division */
-
-/* @brief Truncated division
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return trunc( _a / _b )
- *
- * This function will divide the first argument by
- * the second argument, with rounding toward 0.
- * If _b == 0 and _a < 0, the function will return MIN_RANGE.
- * If _b == 0 and _a == 0, the function will return 0.
- * If _b == 0 and _a > 0, the function will return MAX_RANGE.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_div(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief Saturating truncated division
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return CLIP( trunc( _a / _b ), MIN_RANGE1w, MAX_RANGE1w )
- *
- * This function will divide the first argument by
- * the second argument, with rounding toward 0, and
- * saturate the result to the range of single precision.
- * If _b == 0 and _a < 0, the function will return MIN_RANGE.
- * If _b == 0 and _a == 0, the function will return 0.
- * If _b == 0 and _a > 0, the function will return MAX_RANGE.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector1w OP_2w_divh(
- const tvector2w _a,
- const tvector1w _b);
-
-/* @brief Modulo
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return n/a
- *
- * This function has not yet been implemented.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_mod(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief Unsigned Integer Square root
- *
- * @param[in] _a input
- *
- * @return square root of _a
- *
- * This function will calculate the unsigned integer square root of _a
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector1w_unsigned OP_2w_sqrt_u(
- const tvector2w_unsigned _a);
-
-/* Miscellaneous */
-
-/* @brief Multiplexer
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- * @param[in] _c condition
- *
- * @return _c ? _a : _b
- *
- * This function will return _a if the condition _c
- * is true and _b otherwise.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_mux(
- const tvector2w _a,
- const tvector2w _b,
- const tflags _c);
-
-/* @brief Average without rounding
- *
- * @param[in] _a first operand
- * @param[in] _b second operand
- *
- * @return (_a + _b) >> 1
- *
- * This function will add _a and _b, and right shift
- * the result by one without rounding. No overflow
- * will occur because addition is performed in the
- * proper precision.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_avg(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief Average with rounding
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return (_a + _b) >> 1
- *
- * This function will add _a and _b at full precision,
- * and right shift with rounding the result with 1 bit.
- * Depending on the rounding mode of the core
- * it will round to nearest or to nearest even.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_avgrnd(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief Minimum
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return (_a < _b) ? _a : _b;
- *
- * This function will return the smallest of both
- * input arguments.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_min(
- const tvector2w _a,
- const tvector2w _b);
-
-/* @brief Maximum
- *
- * @param[in] _a first argument
- * @param[in] _b second argument
- *
- * @return (_a > _b) ? _a : _b;
- *
- * This function will return the largest of both
- * input arguments.
- */
-STORAGE_CLASS_ISP_OP2W_FUNC_H tvector2w OP_2w_max(
- const tvector2w _a,
- const tvector2w _b);
-
-#ifndef INLINE_ISP_OP2W
-#define STORAGE_CLASS_ISP_OP2W_FUNC_C
-#define STORAGE_CLASS_ISP_OP2W_DATA_C const
-#else /* INLINE_ISP_OP2W */
-#define STORAGE_CLASS_ISP_OP2W_FUNC_C STORAGE_CLASS_ISP_OP2W_FUNC_H
-#define STORAGE_CLASS_ISP_OP2W_DATA_C STORAGE_CLASS_ISP_OP2W_DATA_H
-#include "isp_op2w.c"
-#define ISP_OP2W_INLINED
-#endif /* INLINE_ISP_OP2W */
-
-#endif /* __ISP_OP2W_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w_types.h
deleted file mode 100644
index 7e86083a8a33..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w_types.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __ISP_OP2W_TYPES_H_INCLUDED__
-#define __ISP_OP2W_TYPES_H_INCLUDED__
-
-/*
- * This file is part of the Multi-precision vector operations exstension package.
- */
-
-/*
- * Double-precision vector operations
- */
-
-/*
- * Prerequisites:
- *
- */
-#include "mpmath.h"
-#include "isp_op1w_types.h"
-
-/*
- * Single-precision data type specification
- */
-
-
-typedef mpsdata_t tvector2w;
-typedef mpsdata_t tscalar2w;
-typedef mpsdata_t tvector2w_signed_positive;
-typedef mpudata_t tvector2w_unsigned;
-
-
-typedef struct {
- tvector2w d;
- tflags f;
-} tvector2w_tflags;
-
-#endif /* __ISP_OP2W_TYPES_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op_count.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op_count.h
deleted file mode 100644
index 8e7b48d026b0..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op_count.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __ISP_OP_COUNT_H_INCLUDED__
-#define __ISP_OP_COUNT_H_INCLUDED__
-
-#include <stdio.h>
-
-typedef struct {
- long long bbb_cnt; /* number of bbb */
- int bbb_op; /* operations per bbb */
- long long total_cnt; /* bbb_cnt * bbb_op */
-} bbb_stat_t;
-
-typedef enum {
- bbb_func_OP_1w_and,
- bbb_func_OP_1w_or,
- bbb_func_OP_1w_xor,
- bbb_func_OP_1w_inv,
- bbb_func_OP_1w_add,
- bbb_func_OP_1w_sub,
- bbb_func_OP_1w_addsat,
- bbb_func_OP_1w_subsat,
- bbb_func_OP_1w_subasr1,
- bbb_func_OP_1w_subhalf,
- bbb_func_OP_1w_subhalfrnd,
- bbb_func_OP_1w_abs,
- bbb_func_OP_1w_subabssat,
-#ifdef ISP2401
- bbb_func_OP_1w_subsat_u,
-#endif
- bbb_func_OP_1w_muld,
- bbb_func_OP_1w_mul,
- bbb_func_OP_1w_qmul,
- bbb_func_OP_1w_qrmul,
- bbb_func_OP_1w_eq,
- bbb_func_OP_1w_ne,
- bbb_func_OP_1w_le,
- bbb_func_OP_1w_lt,
- bbb_func_OP_1w_ge,
- bbb_func_OP_1w_gt,
- bbb_func_OP_1w_asr,
- bbb_func_OP_1w_asrrnd,
- bbb_func_OP_1w_asl,
- bbb_func_OP_1w_aslsat,
- bbb_func_OP_1w_lsl,
- bbb_func_OP_1w_lsr,
-#ifdef ISP2401
- bbb_func_OP_1w_ashift,
- bbb_func_OP_1w_lshift,
-#endif
- bbb_func_OP_int_cast_to_1w ,
- bbb_func_OP_1w_cast_to_int ,
- bbb_func_OP_1w_cast_to_2w ,
- bbb_func_OP_2w_cast_to_1w ,
- bbb_func_OP_2w_sat_cast_to_1w ,
- bbb_func_OP_1w_clip_asym,
- bbb_func_OP_1w_clipz,
- bbb_func_OP_1w_div,
- bbb_func_OP_1w_qdiv,
- bbb_func_OP_1w_mod,
- bbb_func_OP_1w_sqrt_u,
- bbb_func_OP_1w_mux,
- bbb_func_OP_1w_avg,
- bbb_func_OP_1w_avgrnd,
- bbb_func_OP_1w_min,
- bbb_func_OP_1w_max,
- bbb_func_OP_2w_and,
- bbb_func_OP_2w_or,
- bbb_func_OP_2w_xor,
- bbb_func_OP_2w_inv,
- bbb_func_OP_2w_add,
- bbb_func_OP_2w_sub,
- bbb_func_OP_2w_addsat,
- bbb_func_OP_2w_subsat,
- bbb_func_OP_2w_subasr1,
- bbb_func_OP_2w_subhalf,
- bbb_func_OP_2w_subhalfrnd,
- bbb_func_OP_2w_abs,
- bbb_func_OP_2w_subabssat,
- bbb_func_OP_2w_mul,
- bbb_func_OP_2w_qmul,
- bbb_func_OP_2w_qrmul,
- bbb_func_OP_2w_eq,
- bbb_func_OP_2w_ne,
- bbb_func_OP_2w_le,
- bbb_func_OP_2w_lt,
- bbb_func_OP_2w_ge,
- bbb_func_OP_2w_gt,
- bbb_func_OP_2w_asr,
- bbb_func_OP_2w_asrrnd,
- bbb_func_OP_2w_asl,
- bbb_func_OP_2w_aslsat,
- bbb_func_OP_2w_lsl,
- bbb_func_OP_2w_lsr,
- bbb_func_OP_2w_clip_asym,
- bbb_func_OP_2w_clipz,
- bbb_func_OP_2w_div,
- bbb_func_OP_2w_divh,
- bbb_func_OP_2w_mod,
- bbb_func_OP_2w_sqrt_u,
- bbb_func_OP_2w_mux,
- bbb_func_OP_2w_avg,
- bbb_func_OP_2w_avgrnd,
- bbb_func_OP_2w_min,
- bbb_func_OP_2w_max,
- bbb_func_OP_1w_mul_realigning,
-#ifdef ISP2401
- bbb_func_OP_1w_imax32,
- bbb_func_OP_1w_imaxidx32,
- bbb_func_OP_1w_cond_add,
-#endif
-
- bbb_func_num_functions
-} bbb_functions_t;
-
-typedef enum {
- core_func_OP_and,
- core_func_OP_or,
- core_func_OP_xor,
- core_func_OP_inv,
- core_func_OP_add,
- core_func_OP_sub,
- core_func_OP_addsat,
- core_func_OP_subsat,
- core_func_OP_subasr1,
- core_func_OP_abs,
- core_func_OP_subabssat,
-#ifdef ISP2401
- core_func_OP_subsat_u,
-#endif
- core_func_OP_muld,
- core_func_OP_mul,
- core_func_OP_qrmul,
- core_func_OP_eq,
- core_func_OP_ne,
- core_func_OP_le,
- core_func_OP_lt,
- core_func_OP_ge,
- core_func_OP_gt,
- core_func_OP_asr,
- core_func_OP_asl,
- core_func_OP_asrrnd,
- core_func_OP_lsl,
- core_func_OP_lslsat,
- core_func_OP_lsr,
- core_func_OP_lsrrnd,
- core_func_OP_clip_asym,
- core_func_OP_clipz,
- core_func_OP_div,
- core_func_OP_mod,
- core_func_OP_sqrt,
- core_func_OP_mux,
- core_func_OP_avgrnd,
- core_func_OP_min,
- core_func_OP_max,
-
- core_func_num_functions
-
-} core_functions_t;
-
-/* inc_bbb_count() can be used for building blocks that are implemented with one operation
- inc_bbb_count_ext() will be used in case the operation count is not known or greater than one.
-
- For some operations there is a difference in operation count for the cloned version and the
- not cloned version. this difference is not vissible on the reference code side.
- We could add a min and max operation count for those operations, and keep track of those counts
- separately. That way in the report the impact can be seen. */
-
-#ifdef DISABLE_OPCNT
-#define inc_bbb_count(func)
-#define inc_bbb_count_ext(func, cnt)
-#define enable_bbb_count()
-#define disable_bbb_count()
-#else
-#define inc_bbb_count(func) _inc_bbb_count(func)
-#define inc_bbb_count_ext(func, cnt) _inc_bbb_count_ext(func, cnt)
-#define enable_bbb_count() _enable_bbb_count()
-#define disable_bbb_count() _disable_bbb_count()
-#endif
-
-void
-inc_core_count_n(
- core_functions_t func,
- unsigned n);
-
-void
-_enable_bbb_count(void);
-
-void
-_disable_bbb_count(void);
-
-void
-_inc_bbb_count(
- bbb_functions_t func);
-
-void
-_inc_bbb_count_ext(
- bbb_functions_t func,
- int op_count);
-
-void
-bbb_func_reset_count(void);
-
-void
-bbb_func_print_totals(
- FILE * fp,
- unsigned non_zero_only);
-
-void
-core_func_print_totals(
- FILE* fp,
- unsigned non_zero_only);
-
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/osys_public.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/osys_public.h
deleted file mode 100644
index 8695e3c01fa6..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/osys_public.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __OSYS_PUBLIC_H_INCLUDED__
-#define __OSYS_PUBLIC_H_INCLUDED__
-
-#include "system_types.h"
-
-#endif /* __OSYS_PUBLIC_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/pipeline_public.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/pipeline_public.h
deleted file mode 100644
index 32cea582b4c4..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/pipeline_public.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __PIPELINE_PUBLIC_H_INCLUDED__
-#define __PIPELINE_PUBLIC_H_INCLUDED__
-
-#endif /* __PIPELINE_PUBLIC_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func.h
deleted file mode 100644
index c1638c06407d..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func.h
+++ /dev/null
@@ -1,1221 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef _REF_VECTOR_FUNC_H_INCLUDED_
-#define _REF_VECTOR_FUNC_H_INCLUDED_
-
-
-#ifdef INLINE_VECTOR_FUNC
-#define STORAGE_CLASS_REF_VECTOR_FUNC_H static inline
-#define STORAGE_CLASS_REF_VECTOR_DATA_H static inline_DATA
-#else /* INLINE_VECTOR_FUNC */
-#define STORAGE_CLASS_REF_VECTOR_FUNC_H extern
-#define STORAGE_CLASS_REF_VECTOR_DATA_H extern_DATA
-#endif /* INLINE_VECTOR_FUNC */
-
-
-#include "ref_vector_func_types.h"
-
-/* @brief Doubling multiply accumulate with saturation
- *
- * @param[in] acc accumulator
- * @param[in] a multiply input
- * @param[in] b multiply input
- *
- * @return acc + (a*b)
- *
- * This function will do a doubling multiply ont
- * inputs a and b, and will add the result to acc.
- * in case of an overflow of acc, it will saturate.
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector2w OP_1w_maccd_sat(
- tvector2w acc,
- tvector1w a,
- tvector1w b );
-
-/* @brief Doubling multiply accumulate
- *
- * @param[in] acc accumulator
- * @param[in] a multiply input
- * @param[in] b multiply input
- *
- * @return acc + (a*b)
- *
- * This function will do a doubling multiply ont
- * inputs a and b, and will add the result to acc.
- * in case of overflow it will not saturate but wrap around.
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector2w OP_1w_maccd(
- tvector2w acc,
- tvector1w a,
- tvector1w b );
-
-/* @brief Re-aligning multiply
- *
- * @param[in] a multiply input
- * @param[in] b multiply input
- * @param[in] shift shift amount
- *
- * @return (a*b)>>shift
- *
- * This function will multiply a with b, followed by a right
- * shift with rounding. the result is saturated and casted
- * to single precision.
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_mul_realigning(
- tvector1w a,
- tvector1w b,
- tscalar1w shift );
-
-/* @brief Leading bit index
- *
- * @param[in] a input
- *
- * @return index of the leading bit of each element
- *
- * This function finds the index of leading one (set) bit of the
- * input. The index starts with 0 for the LSB and can go upto
- * ISP_VEC_ELEMBITS-1 for the MSB. For an input equal to zero,
- * the returned index is -1.
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_lod(
- tvector1w a);
-
-/* @brief Config Unit Input Processing
- *
- * @param[in] a input
- * @param[in] input_scale input scaling factor
- * @param[in] input_offset input offset factor
- *
- * @return scaled & offset added input clamped to MAXVALUE
- *
- * As part of input processing for piecewise linear estimation config unit,
- * this function will perform scaling followed by adding offset and
- * then clamping to the MAX InputValue
- * It asserts -MAX_SHIFT_1W <= input_scale <= MAX_SHIFT_1W, and
- * -MAX_SHIFT_1W <= input_offset <= MAX_SHIFT_1W
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_input_scaling_offset_clamping(
- tvector1w a,
- tscalar1w_5bit_signed input_scale,
- tscalar1w_5bit_signed input_offset);
-
-/* @brief Config Unit Output Processing
- *
- * @param[in] a output
- * @param[in] output_scale output scaling factor
- *
- * @return scaled & clamped output value
- *
- * As part of output processing for piecewise linear estimation config unit,
- * This function will perform scaling and then clamping to output
- * MAX value.
- * It asserts -MAX_SHIFT_1W <= output_scale <= MAX_SHIFT_1W
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_output_scaling_clamping(
- tvector1w a,
- tscalar1w_5bit_signed output_scale);
-
-/* @brief Config Unit Piecewiselinear estimation
- *
- * @param[in] a input
- * @param[in] config_points config parameter structure
- *
- * @return piecewise linear estimated output
- *
- * Given a set of N points {(x1,y1),()x2,y2), ....,(xn,yn)}, to find
- * the functional value at an arbitrary point around the input set,
- * this function will perform input processing followed by piecewise
- * linear estimation and then output processing to yield the final value.
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_piecewise_estimation(
- tvector1w a,
- ref_config_points config_points);
-
-/* @brief Fast Config Unit
- *
- * @param[in] x input
- * @param[in] init_vectors LUT data structure
- *
- * @return piecewise linear estimated output
- * This block gets an input x and a set of input configuration points stored in a look-up
- * table of 32 elements. First, the x input is clipped to be within the range [x1, xn+1].
- * Then, it computes the interval in which the input lies. Finally, the output is computed
- * by performing linear interpolation based on the interval properties (i.e. x_prev, slope,
- * and offset). This block assumes that the points are equally spaced and that the interval
- * size is a power of 2.
- **/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_XCU(
- tvector1w x,
- xcu_ref_init_vectors init_vectors);
-
-
-/* @brief LXCU
- *
- * @param[in] x input
- * @param[in] init_vectors LUT data structure
- *
- * @return logarithmic piecewise linear estimated output.
- * This block gets an input x and a set of input configuration points stored in a look-up
- * table of 32 elements. It computes the interval in which the input lies.
- * Then output is computed by performing linear interpolation based on the interval
- * properties (i.e. x_prev, slope, * and offset).
- * This BBB assumes spacing x-coordinates of "init vectors" increase exponentially as
- * shown below.
- * interval size : 2^0 2^1 2^2 2^3
- * x-coordinates: x0<--->x1<---->x2<---->x3<---->
- **/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_LXCU(
- tvector1w x,
- xcu_ref_init_vectors init_vectors);
-
-/* @brief Coring
- *
- * @param[in] coring_vec Amount of coring based on brightness level
- * @param[in] filt_input Vector of input pixels on which Coring is applied
- * @param[in] m_CnrCoring0 Coring Level0
- *
- * @return vector of filtered pixels after coring is applied
- *
- * This function will perform adaptive coring based on brightness level to
- * remove noise
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w coring(
- tvector1w coring_vec,
- tvector1w filt_input,
- tscalar1w m_CnrCoring0 );
-
-/* @brief Normalised FIR with coefficients [3,4,1]
- *
- * @param[in] m 1x3 matrix with pixels
- *
- * @return filtered output
- *
- * This function will calculate the
- * Normalised FIR with coefficients [3,4,1],
- *-5dB at Fs/2, -90 degree phase shift (quarter pixel)
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_5dB_m90_nrm (
- const s_1w_1x3_matrix m);
-
-/* @brief Normalised FIR with coefficients [1,4,3]
- *
- * @param[in] m 1x3 matrix with pixels
- *
- * @return filtered output
- *
- * This function will calculate the
- * Normalised FIR with coefficients [1,4,3],
- *-5dB at Fs/2, +90 degree phase shift (quarter pixel)
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_5dB_p90_nrm (
- const s_1w_1x3_matrix m);
-
-/* @brief Normalised FIR with coefficients [1,2,1]
- *
- * @param[in] m 1x3 matrix with pixels
- *
- * @return filtered output
- *
- * This function will calculate the
- * Normalised FIR with coefficients [1,2,1], -6dB at Fs/2
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_6dB_nrm (
- const s_1w_1x3_matrix m);
-
-/* @brief Normalised FIR with coefficients [13,16,3]
- *
- * @param[in] m 1x3 matrix with pixels
- *
- * @return filtered output
- *
- * This function will calculate the
- * Normalised FIR with coefficients [13,16,3],
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_6dB_nrm_ph0 (
- const s_1w_1x3_matrix m);
-
-/* @brief Normalised FIR with coefficients [9,16,7]
- *
- * @param[in] m 1x3 matrix with pixels
- *
- * @return filtered output
- *
- * This function will calculate the
- * Normalised FIR with coefficients [9,16,7],
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_6dB_nrm_ph1 (
- const s_1w_1x3_matrix m);
-
-/* @brief Normalised FIR with coefficients [5,16,11]
- *
- * @param[in] m 1x3 matrix with pixels
- *
- * @return filtered output
- *
- * This function will calculate the
- * Normalised FIR with coefficients [5,16,11],
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_6dB_nrm_ph2 (
- const s_1w_1x3_matrix m);
-
-/* @brief Normalised FIR with coefficients [1,16,15]
- *
- * @param[in] m 1x3 matrix with pixels
- *
- * @return filtered output
- *
- * This function will calculate the
- * Normalised FIR with coefficients [1,16,15],
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_6dB_nrm_ph3 (
- const s_1w_1x3_matrix m);
-
-/* @brief Normalised FIR with programable phase shift
- *
- * @param[in] m 1x3 matrix with pixels
- * @param[in] coeff phase shift
- *
- * @return filtered output
- *
- * This function will calculate the
- * Normalised FIR with coefficients [8-coeff,16,8+coeff],
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_6dB_nrm_calc_coeff (
- const s_1w_1x3_matrix m, tscalar1w_3bit coeff);
-
-/* @brief 3 tap FIR with coefficients [1,1,1]
- *
- * @param[in] m 1x3 matrix with pixels
- *
- * @return filtered output
- *
- * This function will calculate the
- * FIR with coefficients [1,1,1], -9dB at Fs/2 normalized with factor 1/2
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x3m_9dB_nrm (
- const s_1w_1x3_matrix m);
-
-#ifdef ISP2401
-/* @brief symmetric 3 tap FIR acts as LPF or BSF
- *
- * @param[in] m 1x3 matrix with pixels
- * @param[in] k filter coefficient shift
- * @param[in] bsf_flag 1 for BSF and 0 for LPF
- *
- * @return filtered output
- *
- * This function performs variable coefficient symmetric 3 tap filter which can
- * be either used as Low Pass Filter or Band Stop Filter.
- * Symmetric 3tap tap filter with DC gain 1 has filter coefficients [a, 1-2a, a]
- * For LPF 'a' can be approximated as (1 - 2^(-k))/4, k = 0, 1, 2, ...
- * and filter output can be approximated as:
- * out_LPF = ((v00 + v02) - ((v00 + v02) >> k) + (2 * (v01 + (v01 >> k)))) >> 2
- * For BSF 'a' can be approximated as (1 + 2^(-k))/4, k = 0, 1, 2, ...
- * and filter output can be approximated as:
- * out_BSF = ((v00 + v02) + ((v00 + v02) >> k) + (2 * (v01 - (v01 >> k)))) >> 2
- * For a given filter coefficient shift 'k' and bsf_flag this function
- * behaves either as LPF or BSF.
- * All computation is done using 1w arithmetic and implementation does not use
- * any multiplication.
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w
-sym_fir1x3m_lpf_bsf(s_1w_1x3_matrix m,
- tscalar1w k,
- tscalar_bool bsf_flag);
-#endif
-
-/* @brief Normalised 2D FIR with coefficients [1;2;1] * [1,2,1]
- *
- * @param[in] m 3x3 matrix with pixels
- *
- * @return filtered output
- *
- * This function will calculate the
- * Normalised FIR with coefficients [1;2;1] * [1,2,1]
- * Unity gain filter through repeated scaling and rounding
- * - 6 rotate operations per output
- * - 8 vector operations per output
- * _______
- * 14 total operations
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir3x3m_6dB_nrm (
- const s_1w_3x3_matrix m);
-
-/* @brief Normalised 2D FIR with coefficients [1;1;1] * [1,1,1]
- *
- * @param[in] m 3x3 matrix with pixels
- *
- * @return filtered output
- *
- * This function will calculate the
- * Normalised FIR with coefficients [1;1;1] * [1,1,1]
- *
- * (near) Unity gain filter through repeated scaling and rounding
- * - 6 rotate operations per output
- * - 8 vector operations per output
- * _______
- * 14 operations
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir3x3m_9dB_nrm (
- const s_1w_3x3_matrix m);
-
-/* @brief Normalised dual output 2D FIR with coefficients [1;2;1] * [1,2,1]
- *
- * @param[in] m 4x3 matrix with pixels
- *
- * @return two filtered outputs (2x1 matrix)
- *
- * This function will calculate the
- * Normalised FIR with coefficients [1;2;1] * [1,2,1]
- * and produce two outputs (vertical)
- * Unity gain filter through repeated scaling and rounding
- * compute two outputs per call to re-use common intermediates
- * - 4 rotate operations per output
- * - 6 vector operations per output (alternative possible, but in this
- * form it's not obvious to re-use variables)
- * _______
- * 10 total operations
- */
- STORAGE_CLASS_REF_VECTOR_FUNC_H s_1w_2x1_matrix fir3x3m_6dB_out2x1_nrm (
- const s_1w_4x3_matrix m);
-
-/* @brief Normalised dual output 2D FIR with coefficients [1;1;1] * [1,1,1]
- *
- * @param[in] m 4x3 matrix with pixels
- *
- * @return two filtered outputs (2x1 matrix)
- *
- * This function will calculate the
- * Normalised FIR with coefficients [1;1;1] * [1,1,1]
- * and produce two outputs (vertical)
- * (near) Unity gain filter through repeated scaling and rounding
- * compute two outputs per call to re-use common intermediates
- * - 4 rotate operations per output
- * - 7 vector operations per output (alternative possible, but in this
- * form it's not obvious to re-use variables)
- * _______
- * 11 total operations
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H s_1w_2x1_matrix fir3x3m_9dB_out2x1_nrm (
- const s_1w_4x3_matrix m);
-
-/* @brief Normalised 2D FIR 5x5
- *
- * @param[in] m 5x5 matrix with pixels
- *
- * @return filtered output
- *
- * This function will calculate the
- * Normalised FIR with coefficients [1;1;1] * [1;2;1] * [1,2,1] * [1,1,1]
- * and produce a filtered output
- * (near) Unity gain filter through repeated scaling and rounding
- * - 20 rotate operations per output
- * - 28 vector operations per output
- * _______
- * 48 total operations
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir5x5m_15dB_nrm (
- const s_1w_5x5_matrix m);
-
-/* @brief Normalised FIR 1x5
- *
- * @param[in] m 1x5 matrix with pixels
- *
- * @return filtered output
- *
- * This function will calculate the
- * Normalised FIR with coefficients [1,2,1] * [1,1,1] = [1,4,6,4,1]
- * and produce a filtered output
- * (near) Unity gain filter through repeated scaling and rounding
- * - 4 rotate operations per output
- * - 5 vector operations per output
- * _______
- * 9 total operations
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x5m_12dB_nrm (
- const s_1w_1x5_matrix m);
-
-/* @brief Normalised 2D FIR 5x5
- *
- * @param[in] m 5x5 matrix with pixels
- *
- * @return filtered output
- *
- * This function will calculate the
- * Normalised FIR with coefficients [1;2;1] * [1;2;1] * [1,2,1] * [1,2,1]
- * and produce a filtered output
- * (near) Unity gain filter through repeated scaling and rounding
- * - 20 rotate operations per output
- * - 30 vector operations per output
- * _______
- * 50 total operations
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir5x5m_12dB_nrm (
- const s_1w_5x5_matrix m);
-
-/* @brief Approximate averaging FIR 1x5
- *
- * @param[in] m 1x5 matrix with pixels
- *
- * @return filtered output
- *
- * This function will produce filtered output by
- * applying the filter coefficients (1/8) * [1,1,1,1,1]
- * _______
- * 5 vector operations
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x5m_box (
- s_1w_1x5_matrix m);
-
-/* @brief Approximate averaging FIR 1x9
- *
- * @param[in] m 1x9 matrix with pixels
- *
- * @return filtered output
- *
- * This function will produce filtered output by
- * applying the filter coefficients (1/16) * [1,1,1,1,1,1,1,1,1]
- * _______
- * 9 vector operations
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x9m_box (
- s_1w_1x9_matrix m);
-
-/* @brief Approximate averaging FIR 1x11
- *
- * @param[in] m 1x11 matrix with pixels
- *
- * @return filtered output
- *
- * This function will produce filtered output by
- * applying the filter coefficients (1/16) * [1,1,1,1,1,1,1,1,1,1,1]
- * _______
- * 12 vector operations
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w fir1x11m_box (
- s_1w_1x11_matrix m);
-
-/* @brief Symmetric 7 tap filter with normalization
- *
- * @param[in] in 1x7 matrix with pixels
- * @param[in] coeff 1x4 matrix with coefficients
- * @param[in] out_shift output pixel shift value for normalization
- *
- * @return symmetric 7 tap filter output
- *
- * This function performs symmetric 7 tap filter over input pixels.
- * Filter sum is normalized by shifting out_shift bits.
- * Filter sum: p0*c3 + p1*c2 + p2*c1 + p3*c0 + p4*c1 + p5*c2 + p6*c3
- * is implemented as: (p0 + p6)*c3 + (p1 + p5)*c2 + (p2 + p4)*c1 + p3*c0 to
- * reduce multiplication.
- * Input pixels should to be scaled, otherwise overflow is possible during
- * addition
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w
-fir1x7m_sym_nrm(s_1w_1x7_matrix in,
- s_1w_1x4_matrix coeff,
- tvector1w out_shift);
-
-/* @brief Symmetric 7 tap filter with normalization at input side
- *
- * @param[in] in 1x7 matrix with pixels
- * @param[in] coeff 1x4 matrix with coefficients
- *
- * @return symmetric 7 tap filter output
- *
- * This function performs symmetric 7 tap filter over input pixels.
- * Filter sum: p0*c3 + p1*c2 + p2*c1 + p3*c0 + p4*c1 + p5*c2 + p6*c3
- * = (p0 + p6)*c3 + (p1 + p5)*c2 + (p2 + p4)*c1 + p3*c0
- * Input pixels and coefficients are in Qn format, where n =
- * ISP_VEC_ELEMBITS - 1 (ie Q15 for Broxton)
- * To avoid double precision arithmetic input pixel sum and final sum is
- * implemented using avgrnd and coefficient multiplication using qrmul.
- * Final result is in Qm format where m = ISP_VEC_ELEMBITS - 2 (ie Q14 for
- * Broxton)
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w
-fir1x7m_sym_innrm_approx(s_1w_1x7_matrix in,
- s_1w_1x4_matrix coeff);
-
-/* @brief Symmetric 7 tap filter with normalization at output side
- *
- * @param[in] in 1x7 matrix with pixels
- * @param[in] coeff 1x4 matrix with coefficients
- *
- * @return symmetric 7 tap filter output
- *
- * This function performs symmetric 7 tap filter over input pixels.
- * Filter sum: p0*c3 + p1*c2 + p2*c1 + p3*c0 + p4*c1 + p5*c2 + p6*c3
- * = (p0 + p6)*c3 + (p1 + p5)*c2 + (p2 + p4)*c1 + p3*c0
- * Input pixels are in Qn and coefficients are in Qm format, where n =
- * ISP_VEC_ELEMBITS - 2 and m = ISP_VEC_ELEMBITS - 1 (ie Q14 and Q15
- * respectively for Broxton)
- * To avoid double precision arithmetic input pixel sum and final sum is
- * implemented using addsat and coefficient multiplication using qrmul.
- * Final sum is left shifted by 2 and saturated to produce result is Qm format
- * (ie Q15 for Broxton)
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w
-fir1x7m_sym_outnrm_approx(s_1w_1x7_matrix in,
- s_1w_1x4_matrix coeff);
-
-/* @brief 4 tap filter with normalization
- *
- * @param[in] in 1x4 matrix with pixels
- * @param[in] coeff 1x4 matrix with coefficients
- * @param[in] out_shift output pixel shift value for normalization
- *
- * @return 4 tap filter output
- *
- * This function performs 4 tap filter over input pixels.
- * Filter sum is normalized by shifting out_shift bits.
- * Filter sum: p0*c0 + p1*c1 + p2*c2 + p3*c3
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w
-fir1x4m_nrm(s_1w_1x4_matrix in,
- s_1w_1x4_matrix coeff,
- tvector1w out_shift);
-
-/* @brief 4 tap filter with normalization for half pixel interpolation
- *
- * @param[in] in 1x4 matrix with pixels
- *
- * @return 4 tap filter output with filter tap [-1 9 9 -1]/16
- *
- * This function performs 4 tap filter over input pixels.
- * Filter sum: -p0 + 9*p1 + 9*p2 - p3
- * This filter implementation is completely free from multiplication and double
- * precision arithmetic.
- * Typical usage of this filter is to half pixel interpolation of Bezier
- * surface
- * */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w
-fir1x4m_bicubic_bezier_half(s_1w_1x4_matrix in);
-
-/* @brief 4 tap filter with normalization for quarter pixel interpolation
- *
- * @param[in] in 1x4 matrix with pixels
- * @param[in] coeff 1x4 matrix with coefficients
- *
- * @return 4 tap filter output
- *
- * This function performs 4 tap filter over input pixels.
- * Filter sum: p0*c0 + p1*c1 + p2*c2 + p3*c3
- * To avoid double precision arithmetic we implemented multiplication using
- * qrmul and addition using avgrnd. Coefficients( c0 to c3) formats are assumed
- * to be: Qm, Qn, Qo, Qm, where m = n + 2 and o = n + 1.
- * Typical usage of this filter is to quarter pixel interpolation of Bezier
- * surface with filter coefficients:[-9 111 29 -3]/128. For which coefficient
- * values should be: [-9216/2^17 28416/2^15 1484/2^16 -3072/2^17] for
- * ISP_VEC_ELEMBITS = 16.
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w
-fir1x4m_bicubic_bezier_quarter(s_1w_1x4_matrix in,
- s_1w_1x4_matrix coeff);
-
-
-/* @brief Symmetric 3 tap filter with normalization
- *
- * @param[in] in 1x3 matrix with pixels
- * @param[in] coeff 1x2 matrix with coefficients
- * @param[in] out_shift output pixel shift value for normalization
- *
- * @return symmetric 3 tap filter output
- *
- * This function performs symmetric 3 tap filter input pixels.
- * Filter sum is normalized by shifting out_shift bits.
- * Filter sum: p0*c1 + p1*c0 + p2*c1
- * is implemented as: (p0 + p2)*c1 + p1*c0 to reduce multiplication.
- * Input pixels should to be scaled, otherwise overflow is possible during
- * addition
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w
-fir1x3m_sym_nrm(s_1w_1x3_matrix in,
- s_1w_1x2_matrix coeff,
- tvector1w out_shift);
-
-/* @brief Symmetric 3 tap filter with normalization
- *
- * @param[in] in 1x3 matrix with pixels
- * @param[in] coeff 1x2 matrix with coefficients
- *
- * @return symmetric 3 tap filter output
- *
- * This function performs symmetric 3 tap filter over input pixels.
- * Filter sum: p0*c1 + p1*c0 + p2*c1 = (p0 + p2)*c1 + p1*c0
- * Input pixels are in Qn and coefficient c0 is in Qm and c1 is in Qn format,
- * where n = ISP_VEC_ELEMBITS - 1 and m = ISP_VEC_ELEMBITS - 2 ( ie Q15 and Q14
- * respectively for Broxton)
- * To avoid double precision arithmetic input pixel sum is implemented using
- * avgrnd, coefficient multiplication using qrmul and final sum using addsat
- * Final sum is Qm format (ie Q14 for Broxton)
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w
-fir1x3m_sym_nrm_approx(s_1w_1x3_matrix in,
- s_1w_1x2_matrix coeff);
-
-/* @brief Mean of 1x3 matrix
- *
- * @param[in] m 1x3 matrix with pixels
- *
- * @return mean of 1x3 matrix
- *
- * This function calculates the mean of 1x3 pixels,
- * with a factor of 4/3.
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean1x3m(
- s_1w_1x3_matrix m);
-
-/* @brief Mean of 3x3 matrix
- *
- * @param[in] m 3x3 matrix with pixels
- *
- * @return mean of 3x3 matrix
- *
- * This function calculates the mean of 3x3 pixels,
- * with a factor of 16/9.
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean3x3m(
- s_1w_3x3_matrix m);
-
-/* @brief Mean of 1x4 matrix
- *
- * @param[in] m 1x4 matrix with pixels
- *
- * @return mean of 1x4 matrix
- *
- * This function calculates the mean of 1x4 pixels
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean1x4m(
- s_1w_1x4_matrix m);
-
-/* @brief Mean of 4x4 matrix
- *
- * @param[in] m 4x4 matrix with pixels
- *
- * @return mean of 4x4 matrix
- *
- * This function calculates the mean of 4x4 matrix with pixels
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean4x4m(
- s_1w_4x4_matrix m);
-
-/* @brief Mean of 2x3 matrix
- *
- * @param[in] m 2x3 matrix with pixels
- *
- * @return mean of 2x3 matrix
- *
- * This function calculates the mean of 2x3 matrix with pixels
- * with a factor of 8/6.
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean2x3m(
- s_1w_2x3_matrix m);
-
-/* @brief Mean of 1x5 matrix
- *
- * @param[in] m 1x5 matrix with pixels
- *
- * @return mean of 1x5 matrix
- *
- * This function calculates the mean of 1x5 matrix with pixels
- * with a factor of 8/5.
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean1x5m(s_1w_1x5_matrix m);
-
-/* @brief Mean of 1x6 matrix
- *
- * @param[in] m 1x6 matrix with pixels
- *
- * @return mean of 1x6 matrix
- *
- * This function calculates the mean of 1x6 matrix with pixels
- * with a factor of 8/6.
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean1x6m(
- s_1w_1x6_matrix m);
-
-/* @brief Mean of 5x5 matrix
- *
- * @param[in] m 5x5 matrix with pixels
- *
- * @return mean of 5x5 matrix
- *
- * This function calculates the mean of 5x5 matrix with pixels
- * with a factor of 32/25.
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean5x5m(
- s_1w_5x5_matrix m);
-
-/* @brief Mean of 6x6 matrix
- *
- * @param[in] m 6x6 matrix with pixels
- *
- * @return mean of 6x6 matrix
- *
- * This function calculates the mean of 6x6 matrix with pixels
- * with a factor of 64/36.
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w mean6x6m(
- s_1w_6x6_matrix m);
-
-/* @brief Minimum of 4x4 matrix
- *
- * @param[in] m 4x4 matrix with pixels
- *
- * @return minimum of 4x4 matrix
- *
- * This function calculates the minimum of
- * 4x4 matrix with pixels.
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w min4x4m(
- s_1w_4x4_matrix m);
-
-/* @brief Maximum of 4x4 matrix
- *
- * @param[in] m 4x4 matrix with pixels
- *
- * @return maximum of 4x4 matrix
- *
- * This function calculates the maximum of
- * 4x4 matrix with pixels.
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w max4x4m(
- s_1w_4x4_matrix m);
-
-/* @brief SAD between two 3x3 matrices
- *
- * @param[in] a 3x3 matrix with pixels
- *
- * @param[in] b 3x3 matrix with pixels
- *
- * @return 3x3 matrix SAD
- *
- * This function calculates the sum of absolute difference between two matrices.
- * Both input pixels and SAD are normalized by a factor of SAD3x3_IN_SHIFT and
- * SAD3x3_OUT_SHIFT respectively.
- * Computed SAD is 1/(2 ^ (SAD3x3_IN_SHIFT + SAD3x3_OUT_SHIFT)) ie 1/16 factor
- * of original SAD and it's more precise than sad3x3m()
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w sad3x3m_precise(
- s_1w_3x3_matrix a,
- s_1w_3x3_matrix b);
-
-/* @brief SAD between two 3x3 matrices
- *
- * @param[in] a 3x3 matrix with pixels
- *
- * @param[in] b 3x3 matrix with pixels
- *
- * @return 3x3 matrix SAD
- *
- * This function calculates the sum of absolute difference between two matrices.
- * This version saves cycles by avoiding input normalization and wide vector
- * operation during sum computation
- * Input pixel differences are computed by absolute of rounded, halved
- * subtraction. Normalized sum is computed by rounded averages.
- * Computed SAD is (1/2)*(1/16) = 1/32 factor of original SAD. Factor 1/2 comes
- * from input halving operation and factor 1/16 comes from mean operation
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w sad3x3m(
- s_1w_3x3_matrix a,
- s_1w_3x3_matrix b);
-
-/* @brief SAD between two 5x5 matrices
- *
- * @param[in] a 5x5 matrix with pixels
- *
- * @param[in] b 5x5 matrix with pixels
- *
- * @return 5x5 matrix SAD
- *
- * Computed SAD is = 1/32 factor of original SAD.
-*/
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w sad5x5m(
- s_1w_5x5_matrix a,
- s_1w_5x5_matrix b);
-
-/* @brief Absolute gradient between two sets of 1x5 matrices
- *
- * @param[in] m0 first set of 1x5 matrix with pixels
- * @param[in] m1 second set of 1x5 matrix with pixels
- *
- * @return absolute gradient between two 1x5 matrices
- *
- * This function computes mean of two input 1x5 matrices and returns
- * absolute difference between two mean values.
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w
-absgrad1x5m(s_1w_1x5_matrix m0, s_1w_1x5_matrix m1);
-
-/* @brief Bi-linear Interpolation optimized(approximate)
- *
- * @param[in] a input0
- * @param[in] b input1
- * @param[in] c cloned weight factor
- *
- * @return (a-b)*c + b
- *
- * This function will do bi-linear Interpolation on
- * inputs a and b using constant weight factor c
- *
- * Inputs a,b are assumed in S1.15 format
- * Weight factor has to be in range [0,1] and is assumed to be in S2.14 format
- *
- * The bilinear interpolation equation is (a*c) + b*(1-c),
- * But this is implemented as (a-b)*c + b for optimization
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_bilinear_interpol_approx_c(
- tvector1w a,
- tvector1w b,
- tscalar1w_weight c);
-
-/* @brief Bi-linear Interpolation optimized(approximate)
- *
- * @param[in] a input0
- * @param[in] b input1
- * @param[in] c weight factor
- *
- * @return (a-b)*c + b
- *
- * This function will do bi-linear Interpolation on
- * inputs a and b using weight factor c
- *
- * Inputs a,b are assumed in S1.15 format
- * Weight factor has to be in range [0,1] and is assumed to be in S2.14 format
- *
- * The bilinear interpolation equation is (a*c) + b*(1-c),
- * But this is implemented as (a-b)*c + b for optimization
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_bilinear_interpol_approx(
- tvector1w a,
- tvector1w b,
- tvector1w_weight c);
-
-/* @brief Bi-linear Interpolation
- *
- * @param[in] a input0
- * @param[in] b input1
- * @param[in] c weight factor
- *
- * @return (a*c) + b*(1-c)
- *
- * This function will do bi-linear Interpolation on
- * inputs a and b using weight factor c
- *
- * Inputs a,b are assumed in S1.15 format
- * Weight factor has to be in range [0,1] and is assumed to be in S2.14 format
- *
- * The bilinear interpolation equation is (a*c) + b*(1-c),
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_bilinear_interpol(
- tvector1w a,
- tvector1w b,
- tscalar1w_weight c);
-
-/* @brief Generic Block Matching Algorithm
- * @param[in] search_window pointer to input search window of 16x16 pixels
- * @param[in] ref_block pointer to input reference block of 8x8 pixels, where N<=M
- * @param[in] output pointer to output sads
- * @param[in] search_sz search size for SAD computation
- * @param[in] ref_sz block size
- * @param[in] pixel_shift pixel shift to search the data
- * @param[in] search_block_sz search window block size
- * @param[in] shift shift value, with which the output is shifted right
- *
- * @return 0 when the computation is successful.
-
- * * This function compares the reference block with a block of size NxN in the search
- * window. Sum of absolute differences for each pixel in the reference block and the
- * corresponding pixel in the search block. Whole search window os traversed with the
- * reference block with the given pixel shift.
- *
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H int generic_block_matching_algorithm(
- tscalar1w **search_window,
- tscalar1w **ref_block,
- tscalar1w *output,
- int search_sz,
- int ref_sz,
- int pixel_shift,
- int search_block_sz,
- tscalar1w_4bit_bma_shift shift);
-
-#ifndef ISP2401
-/* @brief OP_1w_asp_bma_16_1_32way
-#else
-/* @brief OP_1w_asp_bma_16_1_32way_nomask
-#endif
- *
- * @param[in] search_area input search window of 16x16 pixels
- * @param[in] input_block input reference block of 8x8 pixels, where N<=M
- * @param[in] shift shift value, with which the output is shifted right
- *
- * @return 81 SADs for all the search blocks.
-
- * This function compares the reference block with a block of size 8x8 pixels in the
- * search window of 16x16 pixels. Sum of absolute differences for each pixel in the
- * reference block and the corresponding pixel in the search block is calculated.
- * Whole search window is traversed with the reference block with the pixel shift of 1
- * pixels. The output is right shifted with the given shift value. The shift value is
- * a 4 bit value.
- *
- */
-
-#ifndef ISP2401
-STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_16_1 OP_1w_asp_bma_16_1_32way(
-#else
-STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_16_1 OP_1w_asp_bma_16_1_32way_nomask(
-#endif
- bma_16x16_search_window search_area,
- ref_block_8x8 input_block,
- tscalar1w_4bit_bma_shift shift);
-
-#ifndef ISP2401
-/* @brief OP_1w_asp_bma_16_2_32way
-#else
-/* @brief OP_1w_asp_bma_16_2_32way_nomask
-#endif
- *
- * @param[in] search_area input search window of 16x16 pixels
- * @param[in] input_block input reference block of 8x8 pixels, where N<=M
- * @param[in] shift shift value, with which the output is shifted right
- *
- * @return 25 SADs for all the search blocks.
- * This function compares the reference block with a block of size 8x8 in the search
- * window of 16x61. Sum of absolute differences for each pixel in the reference block
- * and the corresponding pixel in the search block is computed. Whole search window is
- * traversed with the reference block with the given pixel shift of 2 pixels. The output
- * is right shifted with the given shift value. The shift value is a 4 bit value.
- *
- */
-
-#ifndef ISP2401
-STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_16_2 OP_1w_asp_bma_16_2_32way(
-#else
-STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_16_2 OP_1w_asp_bma_16_2_32way_nomask(
-#endif
- bma_16x16_search_window search_area,
- ref_block_8x8 input_block,
- tscalar1w_4bit_bma_shift shift);
-#ifndef ISP2401
-/* @brief OP_1w_asp_bma_14_1_32way
-#else
-/* @brief OP_1w_asp_bma_14_1_32way_nomask
-#endif
- *
- * @param[in] search_area input search block of 16x16 pixels with search window of 14x14 pixels
- * @param[in] input_block input reference block of 8x8 pixels, where N<=M
- * @param[in] shift shift value, with which the output is shifted right
- *
- * @return 49 SADs for all the search blocks.
- * This function compares the reference block with a block of size 8x8 in the search
- * window of 14x14. Sum of absolute differences for each pixel in the reference block
- * and the corresponding pixel in the search block. Whole search window is traversed
- * with the reference block with 2 pixel shift. The output is right shifted with the
- * given shift value. The shift value is a 4 bit value. Input is always a 16x16 block
- * but the search window is 14x14, with last 2 pixels of row and column are not used
- * for computation.
- *
- */
-
-#ifndef ISP2401
-STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_14_1 OP_1w_asp_bma_14_1_32way(
-#else
-STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_14_1 OP_1w_asp_bma_14_1_32way_nomask(
-#endif
- bma_16x16_search_window search_area,
- ref_block_8x8 input_block,
- tscalar1w_4bit_bma_shift shift);
-
-#ifndef ISP2401
-/* @brief OP_1w_asp_bma_14_2_32way
-#else
-/* @brief OP_1w_asp_bma_14_2_32way_nomask
-#endif
- *
- * @param[in] search_area input search block of 16x16 pixels with search window of 14x14 pixels
- * @param[in] input_block input reference block of 8x8 pixels, where N<=M
- * @param[in] shift shift value, with which the output is shifted right
- *
- * @return 16 SADs for all the search blocks.
- * This function compares the reference block with a block of size 8x8 in the search
- * window of 14x14. Sum of absolute differences for each pixel in the reference block
- * and the corresponding pixel in the search block. Whole search window is traversed
- * with the reference block with 2 pixels shift. The output is right shifted with the
- * given shift value. The shift value is a 4 bit value.
- *
- */
-
-#ifndef ISP2401
-STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_14_2 OP_1w_asp_bma_14_2_32way(
-#else
-STORAGE_CLASS_REF_VECTOR_FUNC_H bma_output_14_2 OP_1w_asp_bma_14_2_32way_nomask(
-#endif
- bma_16x16_search_window search_area,
- ref_block_8x8 input_block,
- tscalar1w_4bit_bma_shift shift);
-
-#ifdef ISP2401
-/* @brief multiplex addition and passing
- *
- * @param[in] _a first pixel
- * @param[in] _b second pixel
- * @param[in] _c condition flag
- *
- * @return (_a + _b) if condition flag is true
- * _a if condition flag is false
- *
- * This function does multiplex addition depending on the input condition flag
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H tvector1w OP_1w_cond_add(
- tvector1w _a,
- tvector1w _b,
- tflags _c);
-
-#endif
-#ifdef HAS_bfa_unit
-/* @brief OP_1w_single_bfa_7x7
- *
- * @param[in] weights - spatial and range weight lut
- * @param[in] threshold - threshold plane, for range weight scaling
- * @param[in] central_pix - central pixel plane
- * @param[in] src_plane - src pixel plane
- *
- * @return Bilateral filter output
- *
- * This function implements, 7x7 single bilateral filter.
- * Output = {sum(pixel * weight), sum(weight)}
- * Where sum is summation over 7x7 block set.
- * weight = spatial weight * range weight
- * spatial weights are loaded from spatial_weight_lut depending on src pixel
- * position in the 7x7 block
- * range weights are computed by table look up from range_weight_lut depending
- * on scaled absolute difference between src and central pixels.
- * threshold is used as scaling factor. range_weight_lut consists of
- * BFA_RW_LUT_SIZE numbers of LUT entries to model any distribution function.
- * Piecewise linear approximation technique is used to compute range weight
- * It computes absolute difference between central pixel and 61 src pixels.
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H bfa_7x7_output OP_1w_single_bfa_7x7(
- bfa_weights weights,
- tvector1w threshold,
- tvector1w central_pix,
- s_1w_7x7_matrix src_plane);
-
-/* @brief OP_1w_joint_bfa_7x7
- *
- * @param[in] weights - spatial and range weight lut
- * @param[in] threshold0 - 1st threshold plane, for range weight scaling
- * @param[in] central_pix0 - 1st central pixel plane
- * @param[in] src0_plane - 1st pixel plane
- * @param[in] threshold1 - 2nd threshold plane, for range weight scaling
- * @param[in] central_pix1 - 2nd central pixel plane
- * @param[in] src1_plane - 2nd pixel plane
- *
- * @return Joint bilateral filter output
- *
- * This function implements, 7x7 joint bilateral filter.
- * Output = {sum(pixel * weight), sum(weight)}
- * Where sum is summation over 7x7 block set.
- * weight = spatial weight * range weight
- * spatial weights are loaded from spatial_weight_lut depending on src pixel
- * position in the 7x7 block
- * range weights are computed by table look up from range_weight_lut depending
- * on sum of scaled absolute difference between central pixel and two src pixel
- * planes. threshold is used as scaling factor. range_weight_lut consists of
- * BFA_RW_LUT_SIZE numbers of LUT entries to model any distribution function.
- * Piecewise linear approximation technique is used to compute range weight
- * It computes absolute difference between central pixel and 61 src pixels.
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H bfa_7x7_output OP_1w_joint_bfa_7x7(
- bfa_weights weights,
- tvector1w threshold0,
- tvector1w central_pix0,
- s_1w_7x7_matrix src0_plane,
- tvector1w threshold1,
- tvector1w central_pix1,
- s_1w_7x7_matrix src1_plane);
-
-/* @brief bbb_bfa_gen_spatial_weight_lut
- *
- * @param[in] in - 7x7 matrix of spatial weights
- * @param[in] out - generated LUT
- *
- * @return None
- *
- * This function implements, creates spatial weight look up table used
- * for bilaterl filter instruction.
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H void bbb_bfa_gen_spatial_weight_lut(
- s_1w_7x7_matrix in,
- tvector1w out[BFA_MAX_KWAY]);
-
-/* @brief bbb_bfa_gen_range_weight_lut
- *
- * @param[in] in - input range weight,
- * @param[in] out - generated LUT
- *
- * @return None
- *
- * This function implements, creates range weight look up table used
- * for bilaterl filter instruction.
- * 8 unsigned 7b weights are represented in 7 16bits LUT
- * LUT formation is done as follows:
- * higher 8 bit: Point(N) = Point(N+1) - Point(N)
- * lower 8 bit: Point(N) = Point(N)
- * Weight function can be any monotonic decreasing function for x >= 0
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H void bbb_bfa_gen_range_weight_lut(
- tvector1w in[BFA_RW_LUT_SIZE+1],
- tvector1w out[BFA_RW_LUT_SIZE]);
-#endif
-
-#ifdef ISP2401
-/* @brief OP_1w_imax32
- *
- * @param[in] src - structure that holds an array of 32 elements.
- *
- * @return maximum element among input array.
- *
- *This function gets maximum element from an array of 32 elements.
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H int OP_1w_imax32(
- imax32_ref_in_vector src);
-
-/* @brief OP_1w_imaxidx32
- *
- * @param[in] src - structure that holds a vector of elements.
- *
- * @return index of first element with maximum value among array.
- *
- * This function gets index of first element with maximum value
- * from 32 elements.
- */
-STORAGE_CLASS_REF_VECTOR_FUNC_H int OP_1w_imaxidx32(
- imax32_ref_in_vector src);
-
-#endif
-#ifndef INLINE_VECTOR_FUNC
-#define STORAGE_CLASS_REF_VECTOR_FUNC_C
-#define STORAGE_CLASS_REF_VECTOR_DATA_C const
-#else /* INLINE_VECTOR_FUNC */
-#define STORAGE_CLASS_REF_VECTOR_FUNC_C STORAGE_CLASS_REF_VECTOR_FUNC_H
-#define STORAGE_CLASS_REF_VECTOR_DATA_C STORAGE_CLASS_REF_VECTOR_DATA_H
-#include "ref_vector_func.c"
-#define VECTOR_FUNC_INLINED
-#endif /* INLINE_VECTOR_FUNC */
-
-#endif /*_REF_VECTOR_FUNC_H_INCLUDED_*/
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func_types.h
deleted file mode 100644
index 4dd05eba852e..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func_types.h
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __REF_VECTOR_FUNC_TYPES_H_INCLUDED__
-#define __REF_VECTOR_FUNC_TYPES_H_INCLUDED__
-
-
-/*
- * Prerequisites:
- *
- */
-#include "mpmath.h"
-#include "bbb_config.h"
-#include "isp_op1w_types.h"
-#include "isp_op2w_types.h"
-
-/* Defines for the Config Unit */
-#define MAX_CONFIG_POINTS 5
-#define INPUT_OFFSET_FACTOR 10
-#define INPUT_SCALE_FACTOR 10
-#define OUTPUT_SCALE_FACTOR 10
-#define SLOPE_A_RESOLUTION 10
-#define CONFIG_UNIT_LUT_SIZE_32 32 /*XCU works for ISP_NWAY = 32 */
-#define LXCU_LUT_SIZE 16
-#ifdef ISP2401
-#define IMAX32_ELEM_SIZE 32
-#endif
-
-#define ONE_IN_Q14 (1<<(NUM_BITS-2))
-#define Q29_TO_Q15_SHIFT_VAL (NUM_BITS-2)
-#define Q28_TO_Q15_SHIFT_VAL (NUM_BITS-3)
-#define MAX_ELEM(width_in_bits) ((1<<(width_in_bits))-1)
-
-/* Block matching algorithm related data */
-/* NUM_OF_SADS = ((SEARCH_AREA_HEIGHT - REF_BLOCK_HEIGHT)/PIXEL_SHIFT + 1)* \
- ((SEARCH_AREA_WIDTH - REF_BLOCK_WIDTH)/PIXEL_SHIFT + 1) */
-
-#define SADS(sw_h,sw_w, ref_h, ref_w, p_sh) (((sw_h - ref_h)/p_sh + 1)*((sw_w - ref_w)/p_sh + 1))
-#define SADS_16x16_1 SADS(16, 16, 8, 8, 1)
-#define SADS_16x16_2 SADS(16, 16, 8, 8, 2)
-#define SADS_14x14_1 SADS(14, 14, 8, 8, 1)
-#define SADS_14x14_2 SADS(14, 14, 8, 8, 2)
-
-#define BMA_OUTPUT_MATRIX_DIM(sw_h, ref_h, p_sh) ((sw_h - ref_h)/p_sh + 1)
-#define BMA_OUT_16x16_2_32 BMA_OUTPUT_MATRIX_DIM(16, 8, 2)
-#define BMA_OUT_14x14_2_32 BMA_OUTPUT_MATRIX_DIM(14, 8, 2)
-#define BMA_OUT_16x16_1_32 BMA_OUTPUT_MATRIX_DIM(16, 8, 1)
-#define BMA_OUT_14x14_1_32 BMA_OUTPUT_MATRIX_DIM(14, 8, 1)
-#define BMA_SEARCH_BLOCK_SZ_16 16
-#define BMA_REF_BLOCK_SZ_8 8
-#define PIXEL_SHIFT_2 2
-#define PIXEL_SHIFT_1 1
-#define BMA_SEARCH_WIN_SZ_16 16
-#define BMA_SEARCH_WIN_SZ_14 14
-
-
-/*
- * Struct type specification
- */
-
-typedef unsigned short tscalar1w_3bit; /* tscalar1w in interval [0, 2^3) */
-typedef short tscalar1w_5bit_signed; /* tscalar1w in interval [-2^(5-1), 2^(5-1)) */
-typedef unsigned short tscalar1w_5bit; /* tscalar1w in interval [0, 2^5) */
-typedef short tscalar1w_range1wbit; /* tscalar1w in interval [-NUM_BITS, NUM_BITS] */
-typedef short tscalar1w_unsigned_range1wbit; /* tscalar1w in interval [0, NUM_BITS] */
-typedef unsigned short tvector_8bit; /* 8 bit positive number */
-typedef unsigned short tvector_5bit;
-typedef unsigned short tvector_4bit;
-typedef unsigned short tscalar1w_16bit;
-typedef unsigned short tscalar1w_4bit_bma_shift;
-
-typedef struct {
- tvector1w v0 ;
- tvector1w v1 ;
-} s_1w_2x1_matrix;
-
-#define S_1W_2X1_MATRIX_DEFAULT ((s_1w_2x1_matrix)\
- { 0, 0 })
-
-typedef struct {
- tvector1w v00;
- tvector1w v01;
-} s_1w_1x2_matrix;
-
-#define S_1W_1X2_MATRIX_DEFAULT ((s_1w_1x2_matrix)\
- { 0, 0 })
-
-typedef struct {
- tvector1w v00 ;
- tvector1w v01 ;
- tvector1w v02 ;
-} s_1w_1x3_matrix;
-
-#define S_1W_1X3_MATRIX_DEFAULT ((s_1w_1x3_matrix)\
- { 0, 0, 0, })
-
-typedef struct {
- tvector1w v00; tvector1w v01; tvector1w v02;
- tvector1w v10; tvector1w v11; tvector1w v12;
-} s_1w_2x3_matrix;
-
-#define S_1W_2X3_MATRIX_DEFAULT ((s_1w_2x3_matrix)\
- { 0, 0, 0, \
- 0, 0, 0 })
-
-typedef struct {
- tvector1w v00 ; tvector1w v01 ; tvector1w v02 ;
- tvector1w v10 ; tvector1w v11 ; tvector1w v12 ;
- tvector1w v20 ; tvector1w v21 ; tvector1w v22 ;
-} s_1w_3x3_matrix;
-
-#define S_1W_3X3_MATRIX_DEFAULT ((s_1w_3x3_matrix)\
- { 0, 0, 0, \
- 0, 0, 0, \
- 0, 0, 0 })
-
-typedef struct {
- tvector1w v00 ; tvector1w v01 ; tvector1w v02 ;
- tvector1w v10 ; tvector1w v11 ; tvector1w v12 ;
- tvector1w v20 ; tvector1w v21 ; tvector1w v22 ;
- tvector1w v30 ; tvector1w v31 ; tvector1w v32 ;
-} s_1w_4x3_matrix;
-
-#define S_1W_4X3_MATRIX_DEFAULT ((s_1w_4x3_matrix)\
- { 0, 0, 0, \
- 0, 0, 0, \
- 0, 0, 0, \
- 0, 0, 0 })
-
-typedef struct {
- tvector1w v00 ;
- tvector1w v01 ;
- tvector1w v02 ;
- tvector1w v03 ;
- tvector1w v04 ;
-} s_1w_1x5_matrix;
-
-#define S_1W_1X5_MATRIX_DEFAULT ((s_1w_1x5_matrix)\
- { 0, 0, 0, 0, 0 })
-
-typedef struct {
- tvector1w v00 ; tvector1w v01 ; tvector1w v02 ; tvector1w v03 ; tvector1w v04 ;
- tvector1w v10 ; tvector1w v11 ; tvector1w v12 ; tvector1w v13 ; tvector1w v14 ;
- tvector1w v20 ; tvector1w v21 ; tvector1w v22 ; tvector1w v23 ; tvector1w v24 ;
- tvector1w v30 ; tvector1w v31 ; tvector1w v32 ; tvector1w v33 ; tvector1w v34 ;
- tvector1w v40 ; tvector1w v41 ; tvector1w v42 ; tvector1w v43 ; tvector1w v44 ;
-} s_1w_5x5_matrix;
-
-#define S_1W_5X5_MATRIX_DEFAULT ((s_1w_5x5_matrix)\
- { 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0 })
-#ifndef ISP2401
-
-#else
-
-#endif
-typedef struct {
- tvector1w v00;
- tvector1w v01;
- tvector1w v02;
- tvector1w v03;
- tvector1w v04;
- tvector1w v05;
- tvector1w v06;
-} s_1w_1x7_matrix;
-
-#define S_1W_1X7_MATRIX_DEFAULT ((s_1w_1x7_matrix)\
- { 0, 0, 0, 0, 0, 0, 0 })
-
-typedef struct {
- tvector1w v00;
- tvector1w v01;
- tvector1w v02;
- tvector1w v03;
- tvector1w v04;
- tvector1w v05;
- tvector1w v06;
- tvector1w v07;
- tvector1w v08;
-} s_1w_1x9_matrix;
-
-#define S_1W_1X9_MATRIX_DEFAULT ((s_1w_1x9_matrix)\
- { 0, 0, 0, 0, 0, 0, 0, 0, 0 })
-
-typedef struct {
- tvector1w v00;
- tvector1w v01;
- tvector1w v02;
- tvector1w v03;
-} s_1w_1x4_matrix;
-
-#define S_1W_1X4_MATRIX ((s_1w_1x4_matrix)\
- { 0, 0, 0, 0 })
-
-typedef struct {
- tvector1w v00; tvector1w v01; tvector1w v02; tvector1w v03;
- tvector1w v10; tvector1w v11; tvector1w v12; tvector1w v13;
- tvector1w v20; tvector1w v21; tvector1w v22; tvector1w v23;
- tvector1w v30; tvector1w v31; tvector1w v32; tvector1w v33;
-} s_1w_4x4_matrix;
-
-#define S_1W_4X4_MATRIX_DEFAULT ((s_1w_4x4_matrix)\
- { 0, 0, 0, 0, \
- 0, 0, 0, 0, \
- 0, 0, 0, 0, \
- 0, 0, 0, 0 })
-
-typedef struct {
- tvector1w v00;
- tvector1w v01;
- tvector1w v02;
- tvector1w v03;
- tvector1w v04;
- tvector1w v05;
-} s_1w_1x6_matrix;
-
-#define S_1W_1X6_MATRIX_DEFAULT ((s_1w_1x6_matrix)\
- { 0, 0, 0, 0, 0, 0 })
-
-typedef struct {
- tvector1w v00; tvector1w v01; tvector1w v02; tvector1w v03; tvector1w v04; tvector1w v05;
- tvector1w v10; tvector1w v11; tvector1w v12; tvector1w v13; tvector1w v14; tvector1w v15;
- tvector1w v20; tvector1w v21; tvector1w v22; tvector1w v23; tvector1w v24; tvector1w v25;
- tvector1w v30; tvector1w v31; tvector1w v32; tvector1w v33; tvector1w v34; tvector1w v35;
- tvector1w v40; tvector1w v41; tvector1w v42; tvector1w v43; tvector1w v44; tvector1w v45;
- tvector1w v50; tvector1w v51; tvector1w v52; tvector1w v53; tvector1w v54; tvector1w v55;
-} s_1w_6x6_matrix;
-
-#define S_1W_6X6_MATRIX_DEFAULT ((s_1w_6x6_matrix)\
- { 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0 })
-
-typedef struct {
- tvector1w v00; tvector1w v01; tvector1w v02; tvector1w v03; tvector1w v04;
- tvector1w v05; tvector1w v06; tvector1w v07; tvector1w v08;
- tvector1w v10; tvector1w v11; tvector1w v12; tvector1w v13; tvector1w v14;
- tvector1w v15; tvector1w v16; tvector1w v17; tvector1w v18;
- tvector1w v20; tvector1w v21; tvector1w v22; tvector1w v23; tvector1w v24;
- tvector1w v25; tvector1w v26; tvector1w v27; tvector1w v28;
- tvector1w v30; tvector1w v31; tvector1w v32; tvector1w v33; tvector1w v34;
- tvector1w v35; tvector1w v36; tvector1w v37; tvector1w v38;
- tvector1w v40; tvector1w v41; tvector1w v42; tvector1w v43; tvector1w v44;
- tvector1w v45; tvector1w v46; tvector1w v47; tvector1w v48;
- tvector1w v50; tvector1w v51; tvector1w v52; tvector1w v53; tvector1w v54;
- tvector1w v55; tvector1w v56; tvector1w v57; tvector1w v58;
- tvector1w v60; tvector1w v61; tvector1w v62; tvector1w v63; tvector1w v64;
- tvector1w v65; tvector1w v66; tvector1w v67; tvector1w v68;
- tvector1w v70; tvector1w v71; tvector1w v72; tvector1w v73; tvector1w v74;
- tvector1w v75; tvector1w v76; tvector1w v77; tvector1w v78;
- tvector1w v80; tvector1w v81; tvector1w v82; tvector1w v83; tvector1w v84;
- tvector1w v85; tvector1w v86; tvector1w v87; tvector1w v88;
-} s_1w_9x9_matrix;
-
-#define S_1W_9X9_MATRIX_DEFAULT ((s_1w_9x9_matrix)\
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, 0, 0 })
-
-typedef struct {
- tvector1w v00; tvector1w v01; tvector1w v02; tvector1w v03; tvector1w v04;
- tvector1w v05; tvector1w v06;
- tvector1w v10; tvector1w v11; tvector1w v12; tvector1w v13; tvector1w v14;
- tvector1w v15; tvector1w v16;
- tvector1w v20; tvector1w v21; tvector1w v22; tvector1w v23; tvector1w v24;
- tvector1w v25; tvector1w v26;
- tvector1w v30; tvector1w v31; tvector1w v32; tvector1w v33; tvector1w v34;
- tvector1w v35; tvector1w v36;
- tvector1w v40; tvector1w v41; tvector1w v42; tvector1w v43; tvector1w v44;
- tvector1w v45; tvector1w v46;
- tvector1w v50; tvector1w v51; tvector1w v52; tvector1w v53; tvector1w v54;
- tvector1w v55; tvector1w v56;
- tvector1w v60; tvector1w v61; tvector1w v62; tvector1w v63; tvector1w v64;
- tvector1w v65; tvector1w v66;
-} s_1w_7x7_matrix;
-
-#define S_1W_7X7_MATRIX_DEFAULT ((s_1w_7x7_matrix)\
- { 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0 })
-
-typedef struct {
- tvector1w v0_0;
- tvector1w v0_1;
- tvector1w v0_2;
- tvector1w v0_3;
- tvector1w v0_4;
- tvector1w v0_5;
- tvector1w v0_6;
- tvector1w v0_7;
- tvector1w v0_8;
- tvector1w v0_9;
- tvector1w v0_10;
-} s_1w_1x11_matrix;
-
-#define S_1W_1X11_MATRIX_DEFAULT ((s_1w_1x11_matrix)\
- { 0, 0, 0, 0, 0, 0, 0, 0, 0 })
-
-typedef struct {
- tvector1w x_cord[MAX_CONFIG_POINTS];
- tvector1w slope[MAX_CONFIG_POINTS-1];
- tvector1w y_offset[MAX_CONFIG_POINTS-1];
-} ref_config_points;
-
-typedef struct {
- tscalar1w_range1wbit slope_vec[CONFIG_UNIT_LUT_SIZE_32];
- tscalar1w_range1wbit offset_vec[CONFIG_UNIT_LUT_SIZE_32];
- tscalar1w_16bit x_cord_vec[CONFIG_UNIT_LUT_SIZE_32];
- tscalar1w_16bit x_cord_max;
- tscalar1w_5bit exponent;
- tscalar1w_5bit slope_resolution;
-} xcu_ref_init_vectors;
-
-typedef struct {
-#ifdef ISP2401
- tvector1w elem[IMAX32_ELEM_SIZE];
-} imax32_ref_in_vector;
-
-typedef struct {
-#endif
- tscalar1w search[BMA_SEARCH_BLOCK_SZ_16][BMA_SEARCH_BLOCK_SZ_16];
-} bma_16x16_search_window;
-
-typedef struct {
- tscalar1w ref[BMA_REF_BLOCK_SZ_8][BMA_REF_BLOCK_SZ_8];
-} ref_block_8x8;
-
-typedef struct {
- tscalar1w sads[SADS_16x16_1];
-} bma_output_16_1;
-
-typedef struct {
- tscalar1w sads[SADS_16x16_2];
-} bma_output_16_2;
-
-typedef struct {
- tscalar1w sads[SADS_14x14_2];
-} bma_output_14_2;
-
-typedef struct {
- tscalar1w sads[SADS_14x14_1];
-} bma_output_14_1;
-
-typedef struct {
- tvector1w spatial_weight_lut[BFA_MAX_KWAY]; /* spatial weight LUT */
- /* range weight LUT, (BFA_RW_LUT_SIZE + 1) numbers of LUT values are compressed in BFA_RW_LUT_SIZE buffer.
- * range_weight_lut[k] = packed(drop[k], range_weight[k])
- * where, drop[k] = range_weight[k+1] - range_weight[k]
- * pack(msb, lsb): two 8bits numbers packed in one 16bits number */
- tvector1w range_weight_lut[BFA_RW_LUT_SIZE];
-} bfa_weights;
-
-/* Return type for BFA BBBs */
-typedef struct {
- tvector2w sop; /* weighted sum of pixels */
- tvector1w sow; /* sum of weights */
-} bfa_7x7_output;
-#endif /* __REF_VECTOR_FUNC_TYPES_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mpmath.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mpmath.h
deleted file mode 100644
index cd938375e02e..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mpmath.h
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __MPMATH_H_INCLUDED__
-#define __MPMATH_H_INCLUDED__
-
-
-#ifdef INLINE_MPMATH
-#define STORAGE_CLASS_MPMATH_FUNC_H static inline
-#define STORAGE_CLASS_MPMATH_DATA_H static inline_DATA
-#else /* INLINE_MPMATH */
-#define STORAGE_CLASS_MPMATH_FUNC_H extern
-#define STORAGE_CLASS_MPMATH_DATA_H extern_DATA
-#endif /* INLINE_MPMATH */
-
-#include <type_support.h>
-
-/*
- * Implementation limits
- */
-#define MIN_BITDEPTH 1
-#define MAX_BITDEPTH 64
-
-#define ROUND_NEAREST_EVEN 0
-#define ROUND_NEAREST 1
-
-/*
- * The MP types
- *
- * "vector lane data" is scalar. With "scalar data" for limited range shift and address values
- */
-typedef unsigned long long mpudata_t; /* Type of reference MP scalar / vector lane data; unsigned */
-typedef long long mpsdata_t; /* Type of reference MP scalar / vector lane data; signed */
-typedef unsigned short spudata_t; /* Type of reference SP scalar / vector lane data; unsigned */
-typedef short spsdata_t; /* Type of reference SP scalar / vector lane data; signed */
-typedef unsigned short bitdepth_t;
-
-typedef enum {
- mp_zero_ID,
- mp_one_ID,
- mp_mone_ID,
- mp_smin_ID,
- mp_smax_ID,
- mp_umin_ID,
- mp_umax_ID,
- N_mp_const_ID
-} mp_const_ID_t;
-
-#ifdef ISP2401
-/* _isValidMpudata is for internal use by mpmath and bbb's.
- * isValidMpudata is for external use by functions on top.
- */
-#ifndef ENABLE_VALID_MP_DATA_CHECK
-#define _isValidMpsdata(data,bitdepth) (1)
-#define _isValidMpudata(data,bitdepth) (1)
-#else
-#define _isValidMpsdata(data,bitdepth) isValidMpsdata(data,bitdepth)
-#define _isValidMpudata(data,bitdepth) isValidMpsdata(data,bitdepth)
-
-#endif
-#endif
-STORAGE_CLASS_MPMATH_FUNC_H bool isValidMpsdata(
- const mpsdata_t data,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H bool isValidMpudata(
- const mpudata_t data,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_castd (
- const mpsdata_t in0,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_casth (
- const mpsdata_t in0,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_scasth (
- const mpsdata_t in0,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_qcastd (
- const mpsdata_t in0,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_qcasth (
- const mpsdata_t in0,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_qrcasth (
- const mpsdata_t in0,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_abs (
- const mpsdata_t in0,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_limit (
- const mpsdata_t bnd_low,
- const mpsdata_t in0,
- const mpsdata_t bnd_high,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_max (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_min (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_mux (
- const spudata_t sel,
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_rmux (
- const spudata_t sel,
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_add (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_sadd (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_sub (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_ssub (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_addasr1 (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_subasr1 (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_lsr (
- const mpsdata_t in0,
- const spsdata_t shft,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_asr (
- const mpsdata_t in0,
- const spsdata_t shft,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_rasr (
- const mpsdata_t in0,
- const spsdata_t shft,
- const bitdepth_t bitdepth);
-
-/* "mp_rasr_u()" is implemented by "mp_rasr()" */
-STORAGE_CLASS_MPMATH_FUNC_H mpudata_t mp_rasr_u (
- const mpudata_t in0,
- const spsdata_t shft,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_lsl (
- const mpsdata_t in0,
- const spsdata_t shft,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_asl (
- const mpsdata_t in0,
- const spsdata_t shft,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_muld (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_mul (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_qmul (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_qrmul (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_qdiv (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_qdivh (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_div (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_divh (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_and (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_compl (
- const mpsdata_t in0,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_or (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_xor (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isEQ (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isNE (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isGT (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isGE (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isLT (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isLE (
- const mpsdata_t in0,
- const mpsdata_t in1,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isEQZ (
- const mpsdata_t in0,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isNEZ (
- const mpsdata_t in0,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isGTZ (
- const mpsdata_t in0,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isGEZ (
- const mpsdata_t in0,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isLTZ (
- const mpsdata_t in0,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H spudata_t mp_isLEZ (
- const mpsdata_t in0,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpsdata_t mp_const (
- const mp_const_ID_t ID,
- const bitdepth_t bitdepth);
-
-STORAGE_CLASS_MPMATH_FUNC_H mpudata_t mp_sqrt_u(
- const mpudata_t in0,
- const bitdepth_t bitdepth);
-
-#ifndef INLINE_MPMATH
-#define STORAGE_CLASS_MPMATH_FUNC_C
-#define STORAGE_CLASS_MPMATH_DATA_C const
-#else /* INLINE_MPMATH */
-#define STORAGE_CLASS_MPMATH_FUNC_C STORAGE_CLASS_MPMATH_FUNC_H
-#define STORAGE_CLASS_MPMATH_DATA_C STORAGE_CLASS_MPMATH_DATA_H
-#include "mpmath.c"
-#define MPMATH_INLINED
-#endif /* INLINE_MPMATH */
-
-#endif /* __MPMATH_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/osys.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/osys.h
deleted file mode 100644
index a607242c5f1a..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/osys.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __OSYS_H_INCLUDED__
-#define __OSYS_H_INCLUDED__
-
-/*
- * This file is included on every cell {SP,ISP,host} and on every system
- * that uses the OSYS device. It defines the API to DLI bridge
- *
- * System and cell specific interfaces and inline code are included
- * conditionally through Makefile path settings.
- *
- * - . system and cell agnostic interfaces, constants and identifiers
- * - public: system agnostic, cell specific interfaces
- * - private: system dependent, cell specific interfaces & inline implementations
- * - global: system specific constants and identifiers
- * - local: system and cell specific constants and identifiers
- *
- */
-
-
-#include "system_local.h"
-#include "osys_local.h"
-
-#ifndef __INLINE_OSYS__
-#define STORAGE_CLASS_OSYS_H extern
-#define STORAGE_CLASS_OSYS_C
-#include "osys_public.h"
-#else /* __INLINE_OSYS__ */
-#define STORAGE_CLASS_OSYS_H static inline
-#define STORAGE_CLASS_OSYS_C static inline
-#include "osys_private.h"
-#endif /* __INLINE_OSYS__ */
-
-#endif /* __OSYS_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/stream_buffer.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/stream_buffer.h
deleted file mode 100644
index 53d535e4f2ae..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/stream_buffer.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __STREAM_BUFFER_H_INCLUDED__
-#define __STREAM_BUFFER_H_INCLUDED__
-
-/*
- * This file is included on every cell {SP,ISP,host} and on every system
- * that uses the DMA device. It defines the API to DLI bridge
- *
- * System and cell specific interfaces and inline code are included
- * conditionally through Makefile path settings.
- *
- * - . system and cell agnostic interfaces, constants and identifiers
- * - public: system agnostic, cell specific interfaces
- * - private: system dependent, cell specific interfaces & inline implementations
- * - global: system specific constants and identifiers
- * - local: system and cell specific constants and identifiers
- *
- */
-
-
-#include "system_local.h"
-#include "stream_buffer_local.h"
-
-#ifndef __INLINE_STREAM_BUFFER__
-#define STORAGE_CLASS_STREAM_BUFFER_H extern
-#define STORAGE_CLASS_STREAM_BUFFER_C
-#include "stream_buffer_public.h"
-#else /* __INLINE_STREAM_BUFFER__ */
-#define STORAGE_CLASS_STREAM_BUFFER_H static inline
-#define STORAGE_CLASS_STREAM_BUFFER_C static inline
-#include "stream_buffer_private.h"
-#endif /* __INLINE_STREAM_BUFFER__ */
-
-#endif /* __STREAM_BUFFER_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_func.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_func.h
deleted file mode 100644
index 5368b9062897..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_func.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __VECTOR_FUNC_H_INCLUDED__
-#define __VECTOR_FUNC_H_INCLUDED__
-
-
-/* TODO: Later filters will be moved to types directory,
- * and we should only include matrix_MxN types */
-#include "filters/filters_1.0/filter_2x2.h"
-#include "filters/filters_1.0/filter_3x3.h"
-#include "filters/filters_1.0/filter_4x4.h"
-#include "filters/filters_1.0/filter_5x5.h"
-
-#include "vector_func_local.h"
-
-#ifndef __INLINE_VECTOR_FUNC__
-#define STORAGE_CLASS_VECTOR_FUNC_H extern
-#define STORAGE_CLASS_VECTOR_FUNC_C
-#include "vector_func_public.h"
-#else /* __INLINE_VECTOR_FUNC__ */
-#define STORAGE_CLASS_VECTOR_FUNC_H static inline
-#define STORAGE_CLASS_VECTOR_FUNC_C static inline
-#include "vector_func_private.h"
-#endif /* __INLINE_VECTOR_FUNC__ */
-
-#endif /* __VECTOR_FUNC_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_ops.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_ops.h
deleted file mode 100644
index 4923f2d5518b..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_ops.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __VECTOR_OPS_H_INCLUDED__
-#define __VECTOR_OPS_H_INCLUDED__
-
-
-#include "vector_ops_local.h"
-
-#ifndef __INLINE_VECTOR_OPS__
-#define STORAGE_CLASS_VECTOR_OPS_H extern
-#define STORAGE_CLASS_VECTOR_OPS_C
-#include "vector_ops_public.h"
-#else /* __INLINE_VECTOR_OPS__ */
-#define STORAGE_CLASS_VECTOR_OPS_H static inline
-#define STORAGE_CLASS_VECTOR_OPS_C static inline
-#include "vector_ops_private.h"
-#endif /* __INLINE_VECTOR_OPS__ */
-
-#endif /* __VECTOR_OPS_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/xmem.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/xmem.h
deleted file mode 100644
index 13083fe55141..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/xmem.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __XMEM_H_INCLUDED__
-#define __XMEM_H_INCLUDED__
-
-/*
- * This file is included on every cell {SP,ISP,host} and on every system
- * that uses the XMEM device. It defines the API to DLI bridge
- *
- * System and cell specific interfaces and inline code are included
- * conditionally through Makefile path settings.
- *
- * - . system and cell agnostic interfaces, constants and identifiers
- * - public: system agnostic, cell specific interfaces
- * - private: system dependent, cell specific interfaces & inline implementations
- * - global: system specific constants and identifiers
- * - local: system and cell specific constants and identifiers
- */
-
-
-#include "system_local.h"
-#include "xmem_local.h"
-
-#ifndef __INLINE_XMEM__
-#define STORAGE_CLASS_XMEM_H extern
-#define STORAGE_CLASS_XMEM_C
-#include "xmem_public.h"
-#else /* __INLINE_XMEM__ */
-#define STORAGE_CLASS_XMEM_H static inline
-#define STORAGE_CLASS_XMEM_C static inline
-#include "xmem_private.h"
-#endif /* __INLINE_XMEM__ */
-
-#endif /* __XMEM_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_shared/socket_global.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_shared/socket_global.h
deleted file mode 100644
index 2b7025e90250..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_shared/socket_global.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __SOCKET_GLOBAL_H_INCLUDED__
-#define __SOCKET_GLOBAL_H_INCLUDED__
-
-#include "stream_buffer.h"
-
-/* define the socket port direction */
-typedef enum {
- SOCKET_PORT_DIRECTION_NULL,
- SOCKET_PORT_DIRECTION_IN,
- SOCKET_PORT_DIRECTION_OUT
-} socket_port_direction_t;
-
-/* pointer to the port's callout function */
-typedef void (*socket_port_callout_fp)(void);
-typedef struct socket_port_s socket_port_t;
-typedef struct socket_s socket_t;
-
-/* data structure of the socket port */
-struct socket_port_s {
- unsigned channel; /* the port entity */
- socket_port_direction_t direction; /* the port direction */
- socket_port_callout_fp callout; /* the port callout function */
-
- socket_t *socket; /* point to the socket */
-
- struct {
- unsigned data;
- } buf; /* the buffer at the port */
-};
-
-/* data structure of the socket */
-struct socket_s {
- socket_port_t *in; /* the in-direction port */
- socket_port_t *out; /* the out-direction port */
- stream_buffer_t buf; /* the buffer between in-ports and out-ports */
-};
-
-#endif /* __SOCKET_GLOBAL_H_INCLUDED__ */
-
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_shared/stream_buffer_global.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_shared/stream_buffer_global.h
deleted file mode 100644
index b9664b9608dc..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_shared/stream_buffer_global.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __STREAM_BUFFER_GLOBAL_H_INCLUDED__
-#define __STREAM_BUFFER_GLOBAL_H_INCLUDED__
-
-typedef struct stream_buffer_s stream_buffer_t;
-struct stream_buffer_s {
- unsigned base;
- unsigned limit;
- unsigned top;
-};
-
-#endif /* __STREAM_BUFFER_GLOBAL_H_INCLUDED__ */
-
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_frame_public.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_frame_public.h
index ba7a076c3afa..0beb7347a4f3 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_frame_public.h
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_frame_public.h
@@ -121,15 +121,9 @@ struct ia_css_frame_info {
};
#define IA_CSS_BINARY_DEFAULT_FRAME_INFO \
-{ \
- {0, /* width */ \
- 0}, /* height */ \
- 0, /* padded_width */ \
- IA_CSS_FRAME_FORMAT_NUM, /* format */ \
- 0, /* raw_bit_depth */ \
- IA_CSS_BAYER_ORDER_NUM, /* raw_bayer_order */ \
- {0, /*start col */ \
- 0}, /*start line */ \
+(struct ia_css_frame_info) { \
+ .format = IA_CSS_FRAME_FORMAT_NUM, \
+ .raw_bayer_order = IA_CSS_BAYER_ORDER_NUM, \
}
/**
@@ -190,18 +184,11 @@ struct ia_css_frame {
};
#define DEFAULT_FRAME \
-{ \
- IA_CSS_BINARY_DEFAULT_FRAME_INFO, /* info */ \
- 0, /* data */ \
- 0, /* data_bytes */ \
- SH_CSS_INVALID_QUEUE_ID, /* dynamic_data_index */ \
- IA_CSS_BUFFER_TYPE_INVALID, /* buf_type */ \
- IA_CSS_FRAME_FLASH_STATE_NONE, /* flash_state */ \
- 0, /* exp_id */ \
- 0, /* isp_config_id */ \
- false, /* valid */ \
- false, /* contiguous */ \
- { 0 } /* planes */ \
+(struct ia_css_frame) { \
+ .info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
+ .dynamic_queue_id = SH_CSS_INVALID_QUEUE_ID, \
+ .buf_type = IA_CSS_BUFFER_TYPE_INVALID, \
+ .flash_state = IA_CSS_FRAME_FLASH_STATE_NONE, \
}
/* @brief Fill a frame with zeros
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe.h
index d0c0e6b92025..f6870fa7a18c 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe.h
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe.h
@@ -33,22 +33,17 @@ struct ia_css_preview_settings {
/* 2401 only for these two - do we in fact use them for anything real */
struct ia_css_frame *delay_frames[MAX_NUM_DELAY_FRAMES];
struct ia_css_frame *tnr_frames[NUM_TNR_FRAMES];
-
+
struct ia_css_pipe *copy_pipe;
struct ia_css_pipe *capture_pipe;
struct ia_css_pipe *acc_pipe;
};
#define IA_CSS_DEFAULT_PREVIEW_SETTINGS \
-{ \
- IA_CSS_BINARY_DEFAULT_SETTINGS, /* copy_binary */\
- IA_CSS_BINARY_DEFAULT_SETTINGS, /* preview_binary */\
- IA_CSS_BINARY_DEFAULT_SETTINGS, /* vf_pp_binary */\
- { NULL }, /* dvs_frames */ \
- { NULL }, /* tnr_frames */ \
- NULL, /* copy_pipe */\
- NULL, /* capture_pipe */\
- NULL, /* acc_pipe */\
+(struct ia_css_preview_settings) { \
+ .copy_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \
+ .preview_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \
+ .vf_pp_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \
}
struct ia_css_capture_settings {
@@ -70,20 +65,15 @@ struct ia_css_capture_settings {
};
#define IA_CSS_DEFAULT_CAPTURE_SETTINGS \
-{ \
- IA_CSS_BINARY_DEFAULT_SETTINGS, /* copy_binary */\
- {IA_CSS_BINARY_DEFAULT_SETTINGS}, /* primary_binary */\
- 0, /* num_primary_stage */\
- IA_CSS_BINARY_DEFAULT_SETTINGS, /* pre_isp_binary */\
- IA_CSS_BINARY_DEFAULT_SETTINGS, /* anr_gdc_binary */\
- IA_CSS_BINARY_DEFAULT_SETTINGS, /* post_isp_binary */\
- IA_CSS_BINARY_DEFAULT_SETTINGS, /* capture_pp_binary */\
- IA_CSS_BINARY_DEFAULT_SETTINGS, /* vf_pp_binary */\
- IA_CSS_BINARY_DEFAULT_SETTINGS, /* capture_ldc_binary */\
- NULL, /* yuv_scaler_binary */ \
- { NULL }, /* delay_frames[ref_frames] */ \
- NULL, /* is_output_stage */ \
- 0, /* num_yuv_scaler */ \
+(struct ia_css_capture_settings) { \
+ .copy_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \
+ .primary_binary = {IA_CSS_BINARY_DEFAULT_SETTINGS}, \
+ .pre_isp_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \
+ .anr_gdc_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \
+ .post_isp_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \
+ .capture_pp_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \
+ .vf_pp_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \
+ .capture_ldc_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \
}
struct ia_css_video_settings {
@@ -105,18 +95,10 @@ struct ia_css_video_settings {
};
#define IA_CSS_DEFAULT_VIDEO_SETTINGS \
-{ \
- IA_CSS_BINARY_DEFAULT_SETTINGS, /* copy_binary */ \
- IA_CSS_BINARY_DEFAULT_SETTINGS, /* video_binary */ \
- IA_CSS_BINARY_DEFAULT_SETTINGS, /* vf_pp_binary */ \
- NULL, /* yuv_scaler_binary */ \
- { NULL }, /* delay_frames */ \
- { NULL }, /* tnr_frames */ \
- NULL, /* vf_pp_in_frame */ \
- NULL, /* copy_pipe */ \
- NULL, /* capture_pipe */ \
- NULL, /* is_output_stage */ \
- 0, /* num_yuv_scaler */ \
+(struct ia_css_video_settings) { \
+ .copy_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \
+ .video_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \
+ .vf_pp_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \
}
struct ia_css_yuvpp_settings {
@@ -130,14 +112,8 @@ struct ia_css_yuvpp_settings {
};
#define IA_CSS_DEFAULT_YUVPP_SETTINGS \
-{ \
- IA_CSS_BINARY_DEFAULT_SETTINGS, /* copy_binary */ \
- NULL, /* yuv_scaler_binary */ \
- NULL, /* vf_pp_binary */ \
- NULL, /* is_output_stage */ \
- 0, /* num_yuv_scaler */ \
- 0, /* num_vf_pp */ \
- 0, /* num_output */ \
+(struct ia_css_yuvpp_settings) { \
+ .copy_binary = IA_CSS_BINARY_DEFAULT_SETTINGS, \
}
struct osys_object;
@@ -185,35 +161,26 @@ struct ia_css_pipe {
};
#define IA_CSS_DEFAULT_PIPE \
-{ \
- false, /* stop_requested */ \
- DEFAULT_PIPE_CONFIG, /* config */ \
- DEFAULT_PIPE_EXTRA_CONFIG, /* extra_config */ \
- DEFAULT_PIPE_INFO, /* info */ \
- IA_CSS_PIPE_ID_ACC, /* mode (pipe_id) */ \
- NULL, /* shading_table */ \
- DEFAULT_PIPELINE, /* pipeline */ \
- {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* output_info */ \
- IA_CSS_BINARY_DEFAULT_FRAME_INFO, /* bds_output_info */ \
- {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* vf_output_info */ \
- IA_CSS_BINARY_DEFAULT_FRAME_INFO, /* out_yuv_ds_input_info */ \
- IA_CSS_BINARY_DEFAULT_FRAME_INFO, /* vf_yuv_ds_input_info */ \
- NULL, /* output_stage */ \
- NULL, /* vf_stage */ \
- SH_CSS_BDS_FACTOR_1_00, /* required_bds_factor */ \
- 1, /* dvs_frame_delay */ \
- 0, /* num_invalid_frames */ \
- {true}, /* enable_viewfinder */ \
- NULL, /* stream */ \
- DEFAULT_FRAME, /* in_frame_struct */ \
- DEFAULT_FRAME, /* out_frame_struct */ \
- DEFAULT_FRAME, /* vf_frame_struct */ \
- { NULL }, /* continuous_frames */ \
- { NULL }, /* cont_md_buffers */ \
- { IA_CSS_DEFAULT_PREVIEW_SETTINGS }, /* pipe_settings */ \
- 0, /* scaler_pp_lut */ \
- NULL, /* osys object */ \
- PIPE_ENTRY_EMPTY_TOKEN, /* pipe_num */\
+(struct ia_css_pipe) { \
+ .config = DEFAULT_PIPE_CONFIG, \
+ .info = DEFAULT_PIPE_INFO, \
+ .mode = IA_CSS_PIPE_ID_ACC, /* (pipe_id) */ \
+ .pipeline = DEFAULT_PIPELINE, \
+ .output_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \
+ .bds_output_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
+ .vf_output_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \
+ .out_yuv_ds_input_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
+ .vf_yuv_ds_input_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
+ .required_bds_factor = SH_CSS_BDS_FACTOR_1_00, \
+ .dvs_frame_delay = 1, \
+ .enable_viewfinder = {true}, \
+ .in_frame_struct = DEFAULT_FRAME, \
+ .out_frame_struct = DEFAULT_FRAME, \
+ .vf_frame_struct = DEFAULT_FRAME, \
+ .pipe_settings = { \
+ .preview = IA_CSS_DEFAULT_PREVIEW_SETTINGS \
+ }, \
+ .pipe_num = PIPE_ENTRY_EMPTY_TOKEN, \
}
void ia_css_pipe_map_queue(struct ia_css_pipe *pipe, bool map);
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe_public.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe_public.h
index df0aad9a6ab9..11225d5ac442 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe_public.h
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_pipe_public.h
@@ -152,82 +152,20 @@ struct ia_css_pipe_config {
};
-#ifdef ISP2401
-/**
- * Default origin of internal frame positioned on shading table.
- */
-#define IA_CSS_PIPE_DEFAULT_INTERNAL_FRAME_ORIGIN_BQS_ON_SCTBL \
-{ \
- 0, /* x [bqs] */ \
- 0 /* y [bqs] */ \
-}
-
-/**
- * Default settings for newly created pipe configurations.
- */
-#define DEFAULT_PIPE_CONFIG \
-{ \
- IA_CSS_PIPE_MODE_PREVIEW, /* mode */ \
- 1, /* isp_pipe_version */ \
- { 0, 0 }, /* pipe_effective_input_res */ \
- { 0, 0 }, /* bayer_ds_out_res */ \
- { 0, 0 }, /* vf_pp_in_res */ \
- { 0, 0 }, /* capt_pp_in_res */ \
- { 0, 0 }, /* output_system_in_res */ \
- { 0, 0 }, /* dvs_crop_out_res */ \
- {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* output_info */ \
- {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* vf_output_info */ \
- NULL, /* acc_extension */ \
- NULL, /* acc_stages */ \
- 0, /* num_acc_stages */ \
- DEFAULT_CAPTURE_CONFIG, /* default_capture_config */ \
- { 0, 0 }, /* dvs_envelope */ \
- IA_CSS_FRAME_DELAY_1, /* dvs_frame_delay */ \
- -1, /* acc_num_execs */ \
- false, /* enable_dz */ \
- false, /* enable_dpc */ \
- false, /* enable_vfpp_bci */ \
- false, /* enable_luma_only */ \
- false, /* enable_tnr */ \
- NULL, /* p_isp_config */\
- { 0, 0 }, /* gdc_in_buffer_res */ \
- { 0, 0 }, /* gdc_in_buffer_offset */ \
- IA_CSS_PIPE_DEFAULT_INTERNAL_FRAME_ORIGIN_BQS_ON_SCTBL /* internal_frame_origin_bqs_on_sctbl */ \
-}
-
-#else
-
/**
* Default settings for newly created pipe configurations.
*/
#define DEFAULT_PIPE_CONFIG \
-{ \
- IA_CSS_PIPE_MODE_PREVIEW, /* mode */ \
- 1, /* isp_pipe_version */ \
- { 0, 0 }, /* pipe_effective_input_res */ \
- { 0, 0 }, /* bayer_ds_out_res */ \
- { 0, 0 }, /* vf_pp_in_res */ \
- { 0, 0 }, /* capt_pp_in_res */ \
- { 0, 0 }, /* dvs_crop_out_res */ \
- {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* output_info */ \
- {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* vf_output_info */ \
- NULL, /* acc_extension */ \
- NULL, /* acc_stages */ \
- 0, /* num_acc_stages */ \
- DEFAULT_CAPTURE_CONFIG, /* default_capture_config */ \
- { 0, 0 }, /* dvs_envelope */ \
- IA_CSS_FRAME_DELAY_1, /* dvs_frame_delay */ \
- -1, /* acc_num_execs */ \
- false, /* enable_dz */ \
- false, /* enable_dpc */ \
- false, /* enable_vfpp_bci */ \
- NULL, /* p_isp_config */\
- { 0, 0 }, /* gdc_in_buffer_res */ \
- { 0, 0 } /* gdc_in_buffer_offset */ \
+(struct ia_css_pipe_config) { \
+ .mode = IA_CSS_PIPE_MODE_PREVIEW, \
+ .isp_pipe_version = 1, \
+ .output_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \
+ .vf_output_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \
+ .default_capture_config = DEFAULT_CAPTURE_CONFIG, \
+ .dvs_frame_delay = IA_CSS_FRAME_DELAY_1, \
+ .acc_num_execs = -1, \
}
-#endif
-
/* Pipe info, this struct describes properties of a pipe after it's stream has
* been created.
* ~~~** DO NOT ADD NEW FIELD **~~~ This structure will be deprecated.
@@ -272,33 +210,15 @@ struct ia_css_pipe_info {
/**
* Defaults for ia_css_pipe_info structs.
*/
-#ifdef ISP2401
-
-#define DEFAULT_PIPE_INFO \
-{ \
- {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* output_info */ \
- {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* vf_output_info */ \
- IA_CSS_BINARY_DEFAULT_FRAME_INFO, /* raw_output_info */ \
- { 0, 0}, /* output system in res */ \
- DEFAULT_SHADING_INFO, /* shading_info */ \
- DEFAULT_GRID_INFO, /* grid_info */ \
- 0 /* num_invalid_frames */ \
-}
-
-#else
-
#define DEFAULT_PIPE_INFO \
-{ \
- {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* output_info */ \
- {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, /* vf_output_info */ \
- IA_CSS_BINARY_DEFAULT_FRAME_INFO, /* raw_output_info */ \
- DEFAULT_SHADING_INFO, /* shading_info */ \
- DEFAULT_GRID_INFO, /* grid_info */ \
- 0 /* num_invalid_frames */ \
+(struct ia_css_pipe_info) { \
+ .output_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \
+ .vf_output_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \
+ .raw_output_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
+ .shading_info = DEFAULT_SHADING_INFO, \
+ .grid_info = DEFAULT_GRID_INFO, \
}
-#endif
-
/* @brief Load default pipe configuration
* @param[out] pipe_config The pipe configuration.
* @return None
@@ -402,7 +322,7 @@ ia_css_pipe_set_isp_config(struct ia_css_pipe *pipe,
exception holds for IA_CSS_EVENT_TYPE_PORT_EOF, for this event an IRQ is always
raised.
Note that events are still queued and the Host can poll for them. The
- or_mask and and_mask may be be active at the same time\n
+ or_mask and and_mask may be active at the same time\n
\n
Default values, for all pipe id's, after ia_css_init:\n
or_mask = IA_CSS_EVENT_TYPE_ALL\n
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_types.h
index 725b90072cfe..259ab3f074ba 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_types.h
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/ia_css_types.h
@@ -370,52 +370,20 @@ struct ia_css_shading_info {
} info;
};
-#ifndef ISP2401
-
-/* Default Shading Correction information of Shading Correction Type 1. */
-#define DEFAULT_SHADING_INFO_TYPE_1 \
-{ \
- IA_CSS_SHADING_CORRECTION_TYPE_1, /* type */ \
- { /* info */ \
- { \
- 0, /* enable */ \
- 0, /* num_hor_grids */ \
- 0, /* num_ver_grids */ \
- 0, /* bqs_per_grid_cell */ \
- 1, /* bayer_scale_hor_ratio_in */ \
- 1, /* bayer_scale_hor_ratio_out */ \
- 1, /* bayer_scale_ver_ratio_in */ \
- 1, /* bayer_scale_ver_ratio_out */ \
- 0, /* sc_bayer_origin_x_bqs_on_shading_table */ \
- 0 /* sc_bayer_origin_y_bqs_on_shading_table */ \
- } \
- } \
-}
-
-#else
-
/* Default Shading Correction information of Shading Correction Type 1. */
#define DEFAULT_SHADING_INFO_TYPE_1 \
-{ \
- IA_CSS_SHADING_CORRECTION_TYPE_1, /* type */ \
- { /* info */ \
- { \
- 0, /* num_hor_grids */ \
- 0, /* num_ver_grids */ \
- 0, /* bqs_per_grid_cell */ \
- 1, /* bayer_scale_hor_ratio_in */ \
- 1, /* bayer_scale_hor_ratio_out */ \
- 1, /* bayer_scale_ver_ratio_in */ \
- 1, /* bayer_scale_ver_ratio_out */ \
- {0, 0}, /* isp_input_sensor_data_res_bqs */ \
- {0, 0}, /* sensor_data_res_bqs */ \
- {0, 0} /* sensor_data_origin_bqs_on_sctbl */ \
+(struct ia_css_shading_info) { \
+ .type = IA_CSS_SHADING_CORRECTION_TYPE_1, \
+ .info = { \
+ .type_1 = { \
+ .bayer_scale_hor_ratio_in = 1, \
+ .bayer_scale_hor_ratio_out = 1, \
+ .bayer_scale_ver_ratio_in = 1, \
+ .bayer_scale_ver_ratio_out = 1, \
} \
} \
}
-#endif
-
/* Default Shading Correction information. */
#define DEFAULT_SHADING_INFO DEFAULT_SHADING_INFO_TYPE_1
@@ -438,12 +406,9 @@ struct ia_css_grid_info {
/* defaults for ia_css_grid_info structs */
#define DEFAULT_GRID_INFO \
-{ \
- 0, /* isp_in_width */ \
- 0, /* isp_in_height */ \
- DEFAULT_3A_GRID_INFO, /* s3a_grid */ \
- DEFAULT_DVS_GRID_INFO, /* dvs_grid */ \
- IA_CSS_VAMEM_TYPE_1 /* vamem_type */ \
+(struct ia_css_grid_info) { \
+ .dvs_grid = DEFAULT_DVS_GRID_INFO, \
+ .vamem_type = IA_CSS_VAMEM_TYPE_1 \
}
/* Morphing table, used for geometric distortion and chromatic abberration
@@ -534,11 +499,8 @@ struct ia_css_capture_config {
/* default settings for ia_css_capture_config structs */
#define DEFAULT_CAPTURE_CONFIG \
-{ \
- IA_CSS_CAPTURE_MODE_PRIMARY, /* mode (capture) */ \
- false, /* enable_xnr */ \
- false, /* enable_raw_output */ \
- false /* enable_capture_pp_bli */ \
+(struct ia_css_capture_config) { \
+ .mode = IA_CSS_CAPTURE_MODE_PRIMARY, \
}
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/aa/aa_2/ia_css_aa2_state.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/aa/aa_2/ia_css_aa2_state.h
deleted file mode 100644
index cc404018b112..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/aa/aa_2/ia_css_aa2_state.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_AA2_STATE_H
-#define __IA_CSS_AA2_STATE_H
-
-#include "type_support.h"
-#include "vmem.h" /* for VMEM_ARRAY*/
-
-/* Denotes the maximum number of pixels per line that can be processed:
-* MAX_AA_VECTORS_PER_LINE = maximum_line_width / ISP_NWAY */
-#ifndef MAX_AA_VECTORS_PER_LINE
-#error Please define MAX_AA_VECTORS_PER_LINE.
-#endif
-
-/* This uses 2 history lines for both y, u and v*/
-#define AA_STATE_Y_BUFFER_HEIGHT 2
-#define AA_STATE_UV_BUFFER_HEIGHT 2
-#define AA_STATE_Y_BUFFER_WIDTH MAX_AA_VECTORS_PER_LINE
-/* The number of u and v elements is half y due to yuv420 downsampling. */
-#define AA_STATE_UV_BUFFER_WIDTH (AA_STATE_Y_BUFFER_WIDTH/2)
-
-
-struct ia_css_isp_aa_vmem_state {
- VMEM_ARRAY(y[AA_STATE_Y_BUFFER_HEIGHT], AA_STATE_Y_BUFFER_WIDTH*ISP_NWAY);
- VMEM_ARRAY(u[AA_STATE_UV_BUFFER_HEIGHT], AA_STATE_UV_BUFFER_WIDTH*ISP_NWAY);
- VMEM_ARRAY(v[AA_STATE_UV_BUFFER_HEIGHT], AA_STATE_UV_BUFFER_WIDTH*ISP_NWAY);
-};
-
-#endif /* __IA_CSS_AA2_STATE_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_load_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_load_param.h
deleted file mode 100644
index 8e1f300bcd39..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_load_param.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_BAYER_LOAD_PARAM_H
-#define __IA_CSS_BAYER_LOAD_PARAM_H
-
-#include "ia_css_bayer_ls_param.h"
-
-#endif /* __IA_CSS_BAYER_LOAD_PARAM_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_ls_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_ls_param.h
deleted file mode 100644
index a0d355454aa3..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_ls_param.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_BAYER_LS_PARAM_H
-#define __IA_CSS_BAYER_LS_PARAM_H
-
-#include "type_support.h"
-#ifndef ISP2401
-
-#define NUM_BAYER_LS 2
-#define BAYER_IDX_GR 0
-#define BAYER_IDX_R 1
-#define BAYER_IDX_B 2
-#define BAYER_IDX_GB 3
-#define BAYER_QUAD_WIDTH 2
-#define BAYER_QUAD_HEIGHT 2
-#define NOF_BAYER_VECTORS 4
-
-/* bayer load/store */
-struct sh_css_isp_bayer_ls_isp_config {
- uint32_t base_address[NUM_BAYER_LS];
- uint32_t width[NUM_BAYER_LS];
- uint32_t height[NUM_BAYER_LS];
- uint32_t stride[NUM_BAYER_LS];
-};
-
-#else
-#include "../../io_ls/common/ia_css_common_io_types.h"
-#endif
-
-#endif /* __IA_CSS_BAYER_LS_PARAM_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_store_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_store_param.h
deleted file mode 100644
index f330be80efa6..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bayer_ls/bayer_ls_1.0/ia_css_bayer_store_param.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_BAYER_STORE_PARAM_H
-#define __IA_CSS_BAYER_STORE_PARAM_H
-
-#include "ia_css_bayer_ls_param.h"
-
-
-#endif /* __IA_CSS_BAYER_STORE_PARAM_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bnlm/ia_css_bnlm_state.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bnlm/ia_css_bnlm_state.h
deleted file mode 100644
index 79cce0e40e82..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/bnlm/ia_css_bnlm_state.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_BNLM_STATE_H
-#define __IA_CSS_BNLM_STATE_H
-
-
-#include "type_support.h"
-#include "vmem.h" /* for VMEM_ARRAY*/
-#include "bnlm.isp.h"
-
-struct bnlm_vmem_state {
- /* State buffers required for BNLM */
- VMEM_ARRAY(buf[BNLM_STATE_BUF_HEIGHT], BNLM_STATE_BUF_WIDTH*ISP_NWAY);
-};
-
-
-
-#endif /* __IA_CSS_BNLM_STATE_H */
-
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/cnr/cnr_1.0/ia_css_cnr_state.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/cnr/cnr_1.0/ia_css_cnr_state.h
deleted file mode 100644
index 795fba76bb20..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/cnr/cnr_1.0/ia_css_cnr_state.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_CNR_STATE_H
-#define __IA_CSS_CNR_STATE_H
-
-#include "type_support.h"
-
-#include "vmem.h"
-
-typedef struct
-{
- VMEM_ARRAY(u, ISP_NWAY);
- VMEM_ARRAY(v, ISP_NWAY);
-} s_cnr_buf;
-
-/* CNR (color noise reduction) */
-struct sh_css_isp_cnr_vmem_state {
- s_cnr_buf cnr_buf[2][MAX_VECTORS_PER_BUF_LINE/2];
-};
-
-#endif /* __IA_CSS_CNR_STATE_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/cnr/cnr_2/ia_css_cnr_state.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/cnr/cnr_2/ia_css_cnr_state.h
deleted file mode 100644
index e533e2fa8cd5..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/cnr/cnr_2/ia_css_cnr_state.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_CNR2_STATE_H
-#define __IA_CSS_CNR2_STATE_H
-
-#include "type_support.h"
-#include "vmem.h"
-
-typedef struct
-{
- VMEM_ARRAY(y, (MAX_VECTORS_PER_BUF_LINE/2)*ISP_NWAY);
- VMEM_ARRAY(u, (MAX_VECTORS_PER_BUF_LINE/2)*ISP_NWAY);
- VMEM_ARRAY(v, (MAX_VECTORS_PER_BUF_LINE/2)*ISP_NWAY);
-} s_cnr_buf;
-
-/* CNR (color noise reduction) */
-struct sh_css_isp_cnr_vmem_state {
- s_cnr_buf cnr_buf;
-};
-
-#endif /* __IA_CSS_CNR2_STATE_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/dp/dp_1.0/ia_css_dp_state.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/dp/dp_1.0/ia_css_dp_state.h
deleted file mode 100644
index f832b3697908..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/dp/dp_1.0/ia_css_dp_state.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_DP_STATE_H
-#define __IA_CSS_DP_STATE_H
-
-#include "type_support.h"
-
-#include "vmem.h"
-#ifndef ISP2401
-#if NEED_BDS_OTHER_THAN_1_00
-#else
-#if ENABLE_FIXED_BAYER_DS
-#endif
-#define MAX_VECTORS_PER_DP_LINE MAX_VECTORS_PER_BUF_INPUT_LINE
-#else
-#define MAX_VECTORS_PER_DP_LINE MAX_VECTORS_PER_BUF_LINE
-#endif
-
-/* DP (Defect Pixel Correction) */
-struct sh_css_isp_dp_vmem_state {
- VMEM_ARRAY(dp_buf[4], MAX_VECTORS_PER_DP_LINE*ISP_NWAY);
-};
-
-#endif /* __IA_CSS_DP_STATE_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/dpc2/ia_css_dpc2_state.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/dpc2/ia_css_dpc2_state.h
deleted file mode 100644
index cbf1e81e83a6..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/dpc2/ia_css_dpc2_state.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_DPC2_STATE_H
-#define __IA_CSS_DPC2_STATE_H
-
-#include "type_support.h"
-#include "vmem.h" /* for VMEM_ARRAY*/
-
-#include "ia_css_dpc2_param.h"
-
-struct sh_css_isp_dpc2_vmem_state {
- VMEM_ARRAY(dpc2_input_lines[DPC2_STATE_INPUT_BUFFER_HEIGHT], DPC2_STATE_INPUT_BUFFER_WIDTH*ISP_NWAY);
- VMEM_ARRAY(dpc2_local_deviations[DPC2_STATE_LOCAL_DEVIATION_BUFFER_HEIGHT], DPC2_STATE_LOCAL_DEVIATION_BUFFER_WIDTH*ISP_NWAY);
- VMEM_ARRAY(dpc2_second_min[DPC2_STATE_SECOND_MINMAX_BUFFER_HEIGHT], DPC2_STATE_SECOND_MINMAX_BUFFER_WIDTH*ISP_NWAY);
- VMEM_ARRAY(dpc2_second_max[DPC2_STATE_SECOND_MINMAX_BUFFER_HEIGHT], DPC2_STATE_SECOND_MINMAX_BUFFER_WIDTH*ISP_NWAY);
-};
-
-#endif /* __IA_CSS_DPC2_STATE_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/eed1_8/ia_css_eed1_8_state.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/eed1_8/ia_css_eed1_8_state.h
deleted file mode 100644
index 47e451b15044..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/eed1_8/ia_css_eed1_8_state.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_EED1_8_STATE_H
-#define __IA_CSS_EED1_8_STATE_H
-
-#include "type_support.h"
-#include "vmem.h" /* for VMEM_ARRAY*/
-
-#include "ia_css_eed1_8_param.h"
-
-struct eed1_8_vmem_state {
- VMEM_ARRAY(eed1_8_input_lines[EED1_8_STATE_INPUT_BUFFER_HEIGHT], EED1_8_STATE_INPUT_BUFFER_WIDTH*ISP_NWAY);
- VMEM_ARRAY(eed1_8_LD_H[EED1_8_STATE_LD_H_HEIGHT], EED1_8_STATE_LD_H_WIDTH*ISP_NWAY);
- VMEM_ARRAY(eed1_8_LD_V[EED1_8_STATE_LD_V_HEIGHT], EED1_8_STATE_LD_V_WIDTH*ISP_NWAY);
- VMEM_ARRAY(eed1_8_D_Hr[EED1_8_STATE_D_HR_HEIGHT], EED1_8_STATE_D_HR_WIDTH*ISP_NWAY);
- VMEM_ARRAY(eed1_8_D_Hb[EED1_8_STATE_D_HB_HEIGHT], EED1_8_STATE_D_HB_WIDTH*ISP_NWAY);
- VMEM_ARRAY(eed1_8_D_Vr[EED1_8_STATE_D_VR_HEIGHT], EED1_8_STATE_D_VR_WIDTH*ISP_NWAY);
- VMEM_ARRAY(eed1_8_D_Vb[EED1_8_STATE_D_VB_HEIGHT], EED1_8_STATE_D_VB_WIDTH*ISP_NWAY);
- VMEM_ARRAY(eed1_8_rb_zipped[EED1_8_STATE_RB_ZIPPED_HEIGHT], EED1_8_STATE_RB_ZIPPED_WIDTH*ISP_NWAY);
-#if EED1_8_FC_ENABLE_MEDIAN
- VMEM_ARRAY(eed1_8_Yc[EED1_8_STATE_YC_HEIGHT], EED1_8_STATE_YC_WIDTH*ISP_NWAY);
- VMEM_ARRAY(eed1_8_Cg[EED1_8_STATE_CG_HEIGHT], EED1_8_STATE_CG_WIDTH*ISP_NWAY);
- VMEM_ARRAY(eed1_8_Co[EED1_8_STATE_CO_HEIGHT], EED1_8_STATE_CO_WIDTH*ISP_NWAY);
- VMEM_ARRAY(eed1_8_AbsK[EED1_8_STATE_ABSK_HEIGHT], EED1_8_STATE_ABSK_WIDTH*ISP_NWAY);
-#endif
-};
-
-#endif /* __IA_CSS_EED1_8_STATE_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/plane_io_ls/ia_css_plane_io_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/plane_io_ls/ia_css_plane_io_param.h
deleted file mode 100644
index 213ef3b385aa..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/plane_io_ls/ia_css_plane_io_param.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef ISP2401
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_PLANE_IO_PARAM_H
-#define __IA_CSS_PLANE_IO_PARAM_H
-
-#include "../common/ia_css_common_io_param.h"
-
-#endif /* __IA_CSS_PLANE_IO_PARAM_H */
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/plane_io_ls/ia_css_plane_io_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/plane_io_ls/ia_css_plane_io_types.h
deleted file mode 100644
index d635741505e2..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/plane_io_ls/ia_css_plane_io_types.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef ISP2401
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_PLANE_IO_TYPES_H
-#define __IA_CSS_PLANE_IO_TYPES_H
-
-#include "../common/ia_css_common_io_types.h"
-
-#define PLANE_IO_LS_NUM_PLANES 3
-
-struct ia_css_plane_io_config {
- struct ia_css_common_io_config get_plane_io_config[PLANE_IO_LS_NUM_PLANES];
- struct ia_css_common_io_config put_plane_io_config[PLANE_IO_LS_NUM_PLANES];
-};
-
-#endif /* __IA_CSS_PLANE_IO_TYPES_H */
-
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/yuv420_io_ls/ia_css_yuv420_io_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/yuv420_io_ls/ia_css_yuv420_io_param.h
deleted file mode 100644
index 52450a9a55a1..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/yuv420_io_ls/ia_css_yuv420_io_param.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef ISP2401
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_YUV420_IO_PARAM
-#define __IA_CSS_YUV420_IO_PARAM
-
-#include "../common/ia_css_common_io_param.h"
-
-#endif
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/yuv420_io_ls/ia_css_yuv420_io_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/yuv420_io_ls/ia_css_yuv420_io_types.h
deleted file mode 100644
index 99ec1143b214..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/io_ls/yuv420_io_ls/ia_css_yuv420_io_types.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef ISP2401
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_YUV420_IO_TYPES
-#define __IA_CSS_YUV420_IO_TYPES
-
-#include "../common/ia_css_common_io_types.h"
-
-#endif
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ia_css_plane_io_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ia_css_plane_io_param.h
deleted file mode 100644
index 881b7e5236dc..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ia_css_plane_io_param.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifdef ISP2401
-/**
-Support for Intel Camera Imaging ISP subsystem.
-Copyright (c) 2010 - 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.
-*/
-
-#ifndef __IA_CSS_PLANE_IO_PARAM_H
-#define __IA_CSS_PLANE_IO_PARAM_H
-
-#include "../common/ia_css_common_io_param.h"
-
-#endif /* __IA_CSS_PLANE_IO_PARAM_H */
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ia_css_plane_io_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ia_css_plane_io_types.h
deleted file mode 100644
index f4b9e8de3d8e..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/plane_io_ls/ia_css_plane_io_types.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifdef ISP2401
-/**
-Support for Intel Camera Imaging ISP subsystem.
-Copyright (c) 2010 - 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.
-*/
-
-#ifndef __IA_CSS_PLANE_IO_TYPES_H
-#define __IA_CSS_PLANE_IO_TYPES_H
-
-#include "../common/ia_css_common_io_types.h"
-
-#define PLANE_IO_LS_NUM_PLANES 3
-
-struct ia_css_plane_io_config {
- struct ia_css_common_io_config get_plane_io_config[PLANE_IO_LS_NUM_PLANES];
- struct ia_css_common_io_config put_plane_io_config[PLANE_IO_LS_NUM_PLANES];
-};
-
-#endif /* __IA_CSS_PLANE_IO_TYPES_H */
-
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ia_css_yuv420_io_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ia_css_yuv420_io_param.h
deleted file mode 100644
index 86184b545fed..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ia_css_yuv420_io_param.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifdef ISP2401
-/**
-Support for Intel Camera Imaging ISP subsystem.
-Copyright (c) 2010 - 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.
-*/
-
-#ifndef __IA_CSS_YUV420_IO_PARAM
-#define __IA_CSS_YUV420_IO_PARAM
-
-#include "../common/ia_css_common_io_param.h"
-
-#endif
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ia_css_yuv420_io_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ia_css_yuv420_io_types.h
deleted file mode 100644
index ad750f530013..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/ipu2_io_ls/yuv420_io_ls/ia_css_yuv420_io_types.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifdef ISP2401
-/**
-Support for Intel Camera Imaging ISP subsystem.
-Copyright (c) 2010 - 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.
-*/
-
-#ifndef __IA_CSS_YUV420_IO_TYPES
-#define __IA_CSS_YUV420_IO_TYPES
-
-#include "../common/ia_css_common_io_types.h"
-
-#endif
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/norm/norm_1.0/ia_css_norm_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/norm/norm_1.0/ia_css_norm_types.h
deleted file mode 100644
index 5581bddf9f9b..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/norm/norm_1.0/ia_css_norm_types.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_NORM_TYPES_H
-#define __IA_CSS_NORM_TYPES_H
-
-
-#endif /* __IA_CSS_NORM_TYPES_H */
-
-
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a/s3a_1.0/ia_css_s3a_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a/s3a_1.0/ia_css_s3a_types.h
index 8d674d2c6427..63e70669f085 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a/s3a_1.0/ia_css_s3a_types.h
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a/s3a_1.0/ia_css_s3a_types.h
@@ -28,7 +28,7 @@
/* 3A configuration. This configures the 3A statistics collection
* module.
*/
-
+
/* 3A statistics grid
*
* ISP block: S3A1 (3A Support for 3A ver.1 (Histogram is not used for AE))
@@ -54,7 +54,7 @@ struct ia_css_3a_grid_info {
uint32_t awb_fr_enable; /** awb_fr enabled in binary,
0:disabled, 1:enabled */
struct awb_fr_public_grid_config awb_fr_grd_info;/** see description in awb_fr_public.h*/
-
+
uint32_t elem_bit_depth; /** TODO:Taken from BYT - need input from AIQ
if needed for SKC
Bit depth of element used
@@ -98,52 +98,6 @@ struct ia_css_3a_grid_info {
};
-#if defined(SYSTEM_css_skycam_c0_system)
-#if defined USE_NEW_AE_STRUCT || defined USE_NEW_AWB_STRUCT
-#define DEFAULT_3A_GRID_INFO \
-{ \
- 0, /* ae_enable */ \
- {0,0,0,0,0,0,0}, /* AE: width,height,b_width,b_height,x_start,y_start*/ \
- 0, /* awb_enable */ \
- {0,0,0,0,0,0}, /* AWB: width,height,b_width,b_height,x_start,y_start*/ \
- 0, /* af_enable */ \
- {0,0,0,0,0,0,0}, /* AF: width,height,b_width,b_height,x_start,y_start,ff_en*/ \
- 0, /* awb_fr_enable */ \
- {0,0,0,0,0,0,0}, /* AWB_FR: width,height,b_width,b_height,x_start,y_start,ff_en*/ \
- 0, /* elem_bit_depth */ \
-}
-#else
-#define DEFAULT_3A_GRID_INFO \
-{ \
- 0, /* ae_enable */ \
- {0,0,0,0,0,0,0,0,0}, /* AE: width,height,b_width,b_height,x_start,y_start,x_end,y_end*/ \
- 0, /* awb_enable */ \
- {0,0,0,0,0,0,0,0}, /* AWB: width,height,b_width,b_height,x_start,y_start,x_end,y_end*/ \
- 0, /* af_enable */ \
- {0,0,0,0,0,0,0}, /* AF: width,height,b_width,b_height,x_start,y_start,ff_en*/ \
- 0, /* awb_fr_enable */ \
- {0,0,0,0,0,0,0}, /* AWB_FR: width,height,b_width,b_height,x_start,y_start,ff_en*/ \
- 0, /* elem_bit_depth */ \
-}
-#endif /* USE_NEW_AE_STRUCT || defined USE_NEW_AWB_STRUCT */
-
-#else
-#define DEFAULT_3A_GRID_INFO \
-{ \
- 0, /* enable */ \
- 0, /* use_dmem */ \
- 0, /* has_histogram */ \
- 0, /* width */ \
- 0, /* height */ \
- 0, /* aligned_width */ \
- 0, /* aligned_height */ \
- 0, /* bqs_per_grid_cell */ \
- 0, /* deci_factor_log2 */ \
- 0, /* elem_bit_depth */ \
-}
-
-#endif
-
/* This struct should be split into 3, for AE, AWB and AF.
* However, that will require driver/ 3A lib modifications.
*/
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a_stat_ls/ia_css_s3a_stat_ls_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a_stat_ls/ia_css_s3a_stat_ls_param.h
deleted file mode 100644
index 9aa019539f47..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a_stat_ls/ia_css_s3a_stat_ls_param.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_S3A_STAT_LS_PARAM_H
-#define __IA_CSS_S3A_STAT_LS_PARAM_H
-
-#include "type_support.h"
-#ifdef ISP2401
-#include "../../io_ls/common/ia_css_common_io_types.h"
-#endif
-
-#define NUM_S3A_LS 1
-
-/* s3a statistics store */
-#ifdef ISP2401
-struct ia_css_s3a_stat_ls_configuration {
- uint32_t s3a_grid_size_log2;
-};
-
-#endif
-struct sh_css_isp_s3a_stat_ls_isp_config {
-#ifndef ISP2401
- uint32_t base_address[NUM_S3A_LS];
- uint32_t width[NUM_S3A_LS];
- uint32_t height[NUM_S3A_LS];
- uint32_t stride[NUM_S3A_LS];
-#endif
- uint32_t s3a_grid_size_log2[NUM_S3A_LS];
-};
-
-#ifndef ISP2401
-
-#endif
-#endif /* __IA_CSS_S3A_STAT_LS_PARAM_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a_stat_ls/ia_css_s3a_stat_store_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a_stat_ls/ia_css_s3a_stat_store_param.h
deleted file mode 100644
index 676b42d364e8..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a_stat_ls/ia_css_s3a_stat_store_param.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_S3A_STAT_STORE_PARAM_H
-#define __IA_CSS_S3A_STAT_STORE_PARAM_H
-
-#include "ia_css_s3a_stat_ls_param.h"
-
-
-#endif /* __IA_CSS_S3A_STAT_STORE_PARAM_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/scale/scale_1.0/ia_css_scale_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/scale/scale_1.0/ia_css_scale_param.h
deleted file mode 100644
index fd19f008ff91..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/scale/scale_1.0/ia_css_scale_param.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef _IA_CSS_SCALE_PARAM_H
-#define _IA_CSS_SCALE_PARAM_H
-
-#include "uds/uds_1.0/ia_css_uds_param.h"
-
-#endif /* _IA_CSS_SCALE_PARAM_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_common_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_common_types.h
index 031983c357e4..381e5730d405 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_common_types.h
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_common_types.h
@@ -41,20 +41,6 @@ struct ia_css_sdis_info {
uint32_t deci_factor_log2;
};
-#define IA_CSS_DEFAULT_SDIS_INFO \
- { \
- { { 0, 0 }, /* dim */ \
- { 0, 0 }, /* pad */ \
- }, /* grid */ \
- { { 0, 0 }, /* dim */ \
- { 0, 0 }, /* pad */ \
- }, /* coef */ \
- { { 0, 0 }, /* dim */ \
- { 0, 0 }, /* pad */ \
- }, /* proj */ \
- 0, /* dis_deci_factor_log2 */ \
- }
-
/* DVS statistics grid
*
* ISP block: SDVS1 (DIS/DVS Support for DIS/DVS ver.1 (2-axes))
@@ -209,16 +195,17 @@ struct ia_css_dvs_stat_grid_info {
/* DVS statistics generated by accelerator default grid info
*/
-#define DEFAULT_DVS_GRID_INFO { \
-{ \
- { 0, 0, 0}, /* GBL CFG reg: kappa, match_shifrt, binning mode*/ \
- {{{0, 0, 0, 0}, {0, 0, 0}, {0, 0} }, \
- {{0, 0, 0, 0}, {0, 0, 0}, {0, 0} }, \
- {{0, 0, 0, 0}, {0, 0, 0}, {0, 0} } }, \
- {{0, 0, 0, 0}, {4, 0, 0, 0}, {0, 0, 0, 0} } } \
+#define DEFAULT_DVS_GRID_INFO \
+(union ia_css_dvs_grid_u) { \
+ .dvs_stat_grid_info = (struct ia_css_dvs_stat_grid_info) { \
+ .fe_roi_cfg = { \
+ [1] = (struct dvs_stat_public_dvs_level_fe_roi_cfg) { \
+ .x_start = 4 \
+ } \
+ } \
+ } \
}
-
/* Union that holds all types of DVS statistics grid info in
* CSS format
* */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_param.h
deleted file mode 100644
index 586cc4315c1f..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/common/ia_css_sdis_param.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_SDIS_PARAM_COMMON_H
-#define __IA_CSS_SDIS_PARAM_COMMON_H
-
-
-#include "sdis/common/ia_css_sdis_common.host.h"
-
-#endif /* __IA_CSS_SDIS_PARAM_COMMON_H */
-
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c
index 9478c12abe89..0fdd696bf654 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c
@@ -169,8 +169,7 @@ ia_css_sdis_init_info(
unsigned enabled)
{
if (!enabled) {
- struct ia_css_sdis_info default_dis = IA_CSS_DEFAULT_SDIS_INFO;
- *dis = default_dis;
+ *dis = (struct ia_css_sdis_info) { };
return;
}
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis_param.h
deleted file mode 100644
index 2dd8696802d0..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_1.0/ia_css_sdis_param.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_SDIS_PARAM_H
-#define __IA_CSS_SDIS_PARAM_H
-
-#include "sdis.isp.h"
-
-#endif /* __IA_CSS_SDIS_PARAM_H */
-
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_2/ia_css_sdis_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_2/ia_css_sdis_param.h
deleted file mode 100644
index cea352e45713..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/sdis/sdis_2/ia_css_sdis_param.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_SDIS2_PARAM_H
-#define __IA_CSS_SDIS2_PARAM_H
-
-#include "sdis.isp.h"
-
-#endif /* __IA_CSS_SDIS2_PARAM_H */
-
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_wrapper_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_wrapper_param.h
deleted file mode 100644
index 1a98555fd5d9..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_wrapper_param.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_XNR3_WRAPPER_PARAM_H
-#define __IA_CSS_XNR3_WRAPPER_PARAM_H
-
-#include "ia_css_xnr3_param.h"
-
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_load_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_load_param.h
deleted file mode 100644
index 400c6790cbf5..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_load_param.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_YUV_LOAD_PARAM_H
-#define __IA_CSS_YUV_LOAD_PARAM_H
-
-#include "ia_css_yuv_ls_param.h"
-
-#endif /* __IA_CSS_YUV_LOAD_PARAM_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_ls_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_ls_param.h
deleted file mode 100644
index c9ff0cb2493a..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_ls_param.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_YUV_LS_PARAM_H
-#define __IA_CSS_YUV_LS_PARAM_H
-
-#include "type_support.h"
-#ifndef ISP2401
-
-/* The number of load/store kernels in a pipeline can be greater than one.
- * A kernel can consume more than one input or can produce more
- * than one output.
- */
-#define NUM_YUV_LS 2
-
-/* YUV load/store */
-struct sh_css_isp_yuv_ls_isp_config {
- unsigned base_address[NUM_YUV_LS];
- unsigned width[NUM_YUV_LS];
- unsigned height[NUM_YUV_LS];
- unsigned stride[NUM_YUV_LS];
-};
-
-#else
-#include "../../io_ls/common/ia_css_common_io_types.h"
-#endif
-
-#endif /* __IA_CSS_YUV_LS_PARAM_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_store_param.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_store_param.h
deleted file mode 100644
index 69c474ea1ffd..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/yuv_ls/yuv_ls_1.0/ia_css_yuv_store_param.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-
-#ifndef __IA_CSS_YUV_STORE_PARAM_H
-#define __IA_CSS_YUV_STORE_PARAM_H
-
-#include "ia_css_yuv_ls_param.h"
-
-
-#endif /* __IA_CSS_YUV_STORE_PARAM_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/modes/interface/isp_exprs.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/modes/interface/isp_exprs.h
deleted file mode 100644
index e625ba62cc15..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/modes/interface/isp_exprs.h
+++ /dev/null
@@ -1,286 +0,0 @@
-#ifndef ISP2401
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * 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.
- */
-#else
-/**
-Support for Intel Camera Imaging ISP subsystem.
-Copyright (c) 2010 - 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.
-*/
-#endif
-
-#ifndef _COMMON_ISP_EXPRS_H_
-#define _COMMON_ISP_EXPRS_H_
-
-/* Binary independent pre-processor expressions */
-
-#include "sh_css_defs.h"
-#include "isp_const.h"
-
-#ifdef __HOST
-#error "isp_exprs.h: Do not include on HOST, contains ISP specific defines"
-#endif
-
-#ifndef __ISP
-#if defined(MODE)
-#define MODE aap
-#error "isp_exprs.h: is mode independent, but MODE is set"
-#endif
-#if defined(VARIABLE_RESOLUTION)
-#define VARIABLE_RESOLUTION noot
-#error "isp_exprs.h: is mode independent, but VARIABLE_RESOLUTION is set"
-#endif
-#if defined(DECI_FACTOR_LOG2)
-#define DECI_FACTOR_LOG2 mies
-#error "isp_exprs.h: is mode independent, but DECI_FACTOR_LOG2 is set"
-#endif
-#endif
-
-#define LOG_VECTOR_STEP _ISP_LOG_VECTOR_STEP(MODE)
-/* should be even and multiple of vf downscaling */
-#define ISP_OUTPUT_CHUNK_LOG_FACTOR (MAX_VF_LOG_DOWNSCALE<=1 ? LOG_VECTOR_STEP : \
- umax(VF_LOG_DOWNSCALE, LOG_VECTOR_STEP))
-
-#define CEIL_DIV_CHUNKS(n,c) ((c) == 1 ? (n) \
- : CEIL_SHIFT(CEIL_DIV((n), (c)), ISP_OUTPUT_CHUNK_LOG_FACTOR)<<ISP_OUTPUT_CHUNK_LOG_FACTOR)
-
-
-#define ISP_VARIABLE_INPUT (ISP_INPUT == IA_CSS_BINARY_INPUT_VARIABLE)
-
-/* Binary independent versions, see isp_defs.h for binary dependent ones */
-#ifndef __ISP
-#define IMAGEFORMAT_IS_RAW(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_RAW)
-
-#define IMAGEFORMAT_IS_RAW_INTERLEAVED(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_RAW)
-
-#define IMAGEFORMAT_IS_RGB(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_RGBA888 || (fmt) == IA_CSS_FRAME_FORMAT_PLANAR_RGB888 || \
- (fmt) == IA_CSS_FRAME_FORMAT_RGB565)
-
-#define IMAGEFORMAT_IS_RGB_INTERLEAVED(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_RGBA888 || (fmt) == IA_CSS_FRAME_FORMAT_RGB565)
-
-#define IMAGEFORMAT_UV_INTERLEAVED(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_NV11 || \
- (fmt) == IA_CSS_FRAME_FORMAT_NV12 || (fmt) == IA_CSS_FRAME_FORMAT_NV21 || \
- (fmt) == IA_CSS_FRAME_FORMAT_NV16 || (fmt) == IA_CSS_FRAME_FORMAT_NV61 || \
- (fmt) == IA_CSS_FRAME_FORMAT_UYVY || (fmt) == IA_CSS_FRAME_FORMAT_YUYV || \
- (fmt) == IA_CSS_FRAME_FORMAT_NV12_16 || (fmt) == IA_CSS_FRAME_FORMAT_NV12_TILEY)
-
-#define IMAGEFORMAT_YUV_INTERLEAVED(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_UYVY || (fmt) == IA_CSS_FRAME_FORMAT_YUYV)
-
-#define IMAGEFORMAT_INTERLEAVED(fmt) (IMAGEFORMAT_UV_INTERLEAVED(fmt) || IMAGEFORMAT_IS_RGB_INTERLEAVED(fmt))
-
-#define IMAGEFORMAT_SUB_SAMPL_420(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_YUV420 || (fmt) == IA_CSS_FRAME_FORMAT_YV12 || \
- (fmt) == IA_CSS_FRAME_FORMAT_NV12 || (fmt) == IA_CSS_FRAME_FORMAT_NV21 || \
- (fmt) == IA_CSS_FRAME_FORMAT_NV12_16 || (fmt) == IA_CSS_FRAME_FORMAT_NV12TILEY)
-
-#define IMAGEFORMAT_SUB_SAMPL_422(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_YUV422 || (fmt) == IA_CSS_FRAME_FORMAT_YV16 || \
- (fmt) == IA_CSS_FRAME_FORMAT_NV16 || (fmt) == IA_CSS_FRAME_FORMAT_NV61)
-
-#define IMAGEFORMAT_SUB_SAMPL_444(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_YUV444)
-
-#define IMAGEFORMAT_UV_SWAPPED(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_NV21 || (fmt) == IA_CSS_FRAME_FORMAT_NV61)
-
-#define IMAGEFORMAT_IS_RGBA(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_RGBA888)
-
-#define IMAGEFORMAT_IS_NV11(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_NV11)
-
-#define IMAGEFORMAT_IS_16BIT(fmt) ((fmt) == IA_CSS_FRAME_FORMAT_YUV420_16 || (fmt) == IA_CSS_FRAME_FORMAT_NV12_16 || (fmt) == IA_CSS_FRAME_FORMAT_YUV422_16)
-
-#endif
-
-
-/******** GDCAC settings *******/
-#define GDCAC_BPP ISP_VEC_ELEMBITS /* We use 14 bits per pixel component for the GDCAC mode */
-#define GDC_INPUT_BLOCK_WIDTH 2 /* Two vectors are needed */
-#define GDC_OUTPUT_BLOCK_WIDTH 1 /* One vector is produced */
-
-#if ISP_VEC_NELEMS == 16
-/* For 16*16 output block, the distortion fits in 13.312 lines __ALWAYS__ */
-#define GDC_INPUT_BLOCK_HEIGHT 14
-#elif ISP_VEC_NELEMS == 64
-/* For 64*64 output block, the distortion fits in 47. lines __ALWAYS__ */
-#define GDC_INPUT_BLOCK_HEIGHT 48
-#endif
-/*******************************/
-
-
-#define ENABLE_HUP ((isp_input_width - isp_envelope_width) < isp_output_width)
-#define ENABLE_VUP ((isp_input_height - isp_envelope_height) < isp_output_height)
-
-#define ISP_INPUT_WIDTH (ENABLE_DS | ENABLE_HUP ? isp_input_width : ISP_INTERNAL_WIDTH)
-#define ISP_INPUT_HEIGHT (ENABLE_DS | ENABLE_VUP ? isp_input_height : isp_internal_height)
-
-#define DECI_FACTOR_LOG2 (ISP_FIXED_S3A_DECI_LOG ? ISP_FIXED_S3A_DECI_LOG : isp_deci_log_factor)
-
-#define ISP_S3ATBL_WIDTH \
- _ISP_S3ATBL_ISP_WIDTH(_ISP_S3A_ELEMS_ISP_WIDTH((ENABLE_HUP ? ISP_INTERNAL_WIDTH : ISP_INPUT_WIDTH), ISP_LEFT_CROPPING), \
- DECI_FACTOR_LOG2)
-#define S3ATBL_WIDTH_BYTES (sizeof(struct ia_css_3a_output) * ISP_S3ATBL_WIDTH)
-#define S3ATBL_WIDTH_SHORTS (S3ATBL_WIDTH_BYTES / sizeof(short))
-
-/* should be even?? */
-#define ISP_UV_OUTPUT_CHUNK_VECS CEIL_DIV(ISP_OUTPUT_CHUNK_VECS, 2)
-
-
-#if defined(__ISP) || defined(INIT_VARS)
-
-#define ISP_USE_IF (ISP_INPUT == IA_CSS_BINARY_INPUT_MEMORY ? 0 : \
- ISP_INPUT == IA_CSS_BINARY_INPUT_SENSOR ? 1 : \
- isp_online)
-
-#define ISP_DVS_ENVELOPE_WIDTH 0
-#define ISP_DVS_ENVELOPE_HEIGHT 0
-
-#define _ISP_INPUT_WIDTH_VECS _ISP_VECS(ISP_INPUT_WIDTH)
-
-#if !defined(__ISP) || (VARIABLE_RESOLUTION && !__HOST)
-#define ISP_INPUT_WIDTH_VECS isp_vectors_per_input_line
-#else
-#define ISP_INPUT_WIDTH_VECS _ISP_INPUT_WIDTH_VECS
-#endif
-
-#if !defined(__ISP) || VARIABLE_RESOLUTION
-#define ISP_INTERNAL_WIDTH_VECS isp_vectors_per_line
-#else
-#define ISP_INTERNAL_WIDTH_VECS _ISP_INTERNAL_WIDTH_VECS
-#endif
-
-#define _ISP_INTERNAL_HEIGHT __ISP_INTERNAL_HEIGHT(isp_output_height, ISP_TOP_CROPPING, ISP_DVS_ENVELOPE_HEIGHT)
-
-#define ISP_INTERNAL_HEIGHT isp_internal_height
-
-#define _ISP_INTERNAL_WIDTH __ISP_INTERNAL_WIDTH(ISP_OUTPUT_WIDTH, ISP_DVS_ENVELOPE_WIDTH, \
- ISP_LEFT_CROPPING, MODE, ISP_C_SUBSAMPLING, \
- OUTPUT_NUM_CHUNKS, ISP_PIPELINING)
-
-#define ISP_UV_INTERNAL_WIDTH (ISP_INTERNAL_WIDTH / 2)
-#define ISP_UV_INTERNAL_HEIGHT (ISP_INTERNAL_HEIGHT / 2)
-
-#define _ISP_INTERNAL_WIDTH_VECS (_ISP_INTERNAL_WIDTH / ISP_VEC_NELEMS)
-#define _ISP_UV_INTERNAL_WIDTH_VECS CEIL_DIV(ISP_UV_INTERNAL_WIDTH, ISP_VEC_NELEMS)
-
-#define ISP_VF_OUTPUT_WIDTH _ISP_VF_OUTPUT_WIDTH(ISP_VF_OUTPUT_WIDTH_VECS)
-#define ISP_VF_OUTPUT_HEIGHT _ISP_VF_OUTPUT_HEIGHT(isp_output_height, VF_LOG_DOWNSCALE)
-
-#if defined (__ISP) && !VARIABLE_RESOLUTION
-#define ISP_INTERNAL_WIDTH _ISP_INTERNAL_WIDTH
-#define ISP_VF_OUTPUT_WIDTH_VECS _ISP_VF_OUTPUT_WIDTH_VECS
-#else
-#define ISP_INTERNAL_WIDTH (VARIABLE_RESOLUTION ? isp_internal_width : _ISP_INTERNAL_WIDTH)
-#define ISP_VF_OUTPUT_WIDTH_VECS (VARIABLE_RESOLUTION ? isp_vf_output_width_vecs : _ISP_VF_OUTPUT_WIDTH_VECS)
-#endif
-
-#if defined(__ISP) && !VARIABLE_RESOLUTION
-#define ISP_OUTPUT_WIDTH ISP_MAX_OUTPUT_WIDTH
-#define VF_LOG_DOWNSCALE MAX_VF_LOG_DOWNSCALE
-#else
-#define ISP_OUTPUT_WIDTH isp_output_width
-#define VF_LOG_DOWNSCALE isp_vf_downscale_bits
-#endif
-
-#if !defined(__ISP) || VARIABLE_RESOLUTION
-#define _ISP_MAX_VF_OUTPUT_WIDTH __ISP_MAX_VF_OUTPUT_WIDTH(2*SH_CSS_MAX_VF_WIDTH, ISP_LEFT_CROPPING)
-#elif defined(MODE) && MODE == IA_CSS_BINARY_MODE_PRIMARY && ISP_OUTPUT_WIDTH > 3328
-/* Because of vmem issues, should be fixed later */
-#define _ISP_MAX_VF_OUTPUT_WIDTH (SH_CSS_MAX_VF_WIDTH - 2*ISP_VEC_NELEMS + (ISP_LEFT_CROPPING ? 2 * ISP_VEC_NELEMS : 0))
-#else
-#define _ISP_MAX_VF_OUTPUT_WIDTH (ISP_VF_OUTPUT_WIDTH + (ISP_LEFT_CROPPING ? (2 >> VF_LOG_DOWNSCALE) * ISP_VEC_NELEMS : 0))
-#endif
-
-#define ISP_MAX_VF_OUTPUT_VECS CEIL_DIV(_ISP_MAX_VF_OUTPUT_WIDTH, ISP_VEC_NELEMS)
-
-
-
-#define ISP_MIN_STRIPE_WIDTH (ISP_PIPELINING * (1<<_ISP_LOG_VECTOR_STEP(MODE)))
-
-/******* STRIPING-RELATED MACROS *******/
-#define NO_STRIPING (ISP_NUM_STRIPES == 1)
-
-#define ISP_OUTPUT_CHUNK_VECS \
- (NO_STRIPING ? CEIL_DIV_CHUNKS(ISP_OUTPUT_VECS_EXTRA_CROP, OUTPUT_NUM_CHUNKS) \
- : ISP_IO_STRIPE_WIDTH_VECS(ISP_OUTPUT_VECS_EXTRA_CROP, ISP_LEFT_PADDING_VECS, ISP_NUM_STRIPES, ISP_MIN_STRIPE_WIDTH) )
-
-#define VECTORS_PER_LINE \
- (NO_STRIPING ? ISP_INTERNAL_WIDTH_VECS \
- : ISP_IO_STRIPE_WIDTH_VECS(ISP_INTERNAL_WIDTH_VECS, ISP_LEFT_PADDING_VECS, ISP_NUM_STRIPES, ISP_MIN_STRIPE_WIDTH) )
-
-#define VECTORS_PER_INPUT_LINE \
- (NO_STRIPING ? ISP_INPUT_WIDTH_VECS \
- : ISP_IO_STRIPE_WIDTH_VECS(ISP_INPUT_WIDTH_VECS, ISP_LEFT_PADDING_VECS, ISP_NUM_STRIPES, ISP_MIN_STRIPE_WIDTH)+_ISP_EXTRA_PADDING_VECS)
-
-
-#define ISP_MAX_VF_OUTPUT_STRIPE_VECS \
- (NO_STRIPING ? ISP_MAX_VF_OUTPUT_VECS \
- : CEIL_MUL(CEIL_DIV(ISP_MAX_VF_OUTPUT_VECS, ISP_NUM_STRIPES), 2))
-#define _ISP_VF_OUTPUT_WIDTH_VECS \
- (NO_STRIPING ? __ISP_VF_OUTPUT_WIDTH_VECS(ISP_OUTPUT_WIDTH, VF_LOG_DOWNSCALE) \
- : __ISP_VF_OUTPUT_WIDTH_VECS(CEIL_DIV(ISP_OUTPUT_WIDTH, ISP_NUM_STRIPES), VF_LOG_DOWNSCALE))
-
-#define ISP_IO_STRIPE_WIDTH_VECS(width, padding, num_stripes, min_stripe) \
- MAX(CEIL_MUL(padding + CEIL_DIV(width-padding, num_stripes) \
- , 2) \
- , min_stripe)
-////////// INPUT & INTERNAL
-/* should be even */
-#define INPUT_NUM_CHUNKS OUTPUT_NUM_CHUNKS
-
-#define INPUT_VECTORS_PER_CHUNK CEIL_DIV_CHUNKS(VECTORS_PER_INPUT_LINE, INPUT_NUM_CHUNKS)
-
-/* only for ISP code, will be removed: */
-#define VECTORS_PER_FULL_LINE ISP_INTERNAL_WIDTH_VECS
-#define VECTORS_PER_INPUT_FULL_LINE ISP_INPUT_WIDTH_VECS
-
-////////// OUTPUT
-/* should at least even and also multiple of vf scaling */
-#define ISP_OUTPUT_VECS_EXTRA_CROP CEIL_DIV(ISP_OUTPUT_WIDTH_EXTRA_CROP, ISP_VEC_NELEMS)
-
-/* Output is decoupled from input */
-#define ISP_OUTPUT_WIDTH_EXTRA_CROP CEIL_MUL(CEIL_MUL((ENABLE_DVS_ENVELOPE ? ISP_OUTPUT_WIDTH : ISP_INTERNAL_WIDTH), 2*ISP_VEC_NELEMS), \
- ISP_C_SUBSAMPLING * OUTPUT_NUM_CHUNKS * HIVE_ISP_DDR_WORD_BYTES)
-
-#define ISP_MAX_VF_OUTPUT_CHUNK_VECS \
- (NO_CHUNKING ? ISP_MAX_VF_OUTPUT_STRIPE_VECS \
- : 2*CEIL_DIV(ISP_MAX_VF_OUTPUT_STRIPE_VECS, 2*OUTPUT_NUM_CHUNKS))
-
-#define OUTPUT_VECTORS_PER_CHUNK CEIL_DIV_CHUNKS(VECTORS_PER_LINE,OUTPUT_NUM_CHUNKS)
-
-/* should be even?? */
-#define OUTPUT_C_VECTORS_PER_CHUNK CEIL_DIV(OUTPUT_VECTORS_PER_CHUNK, 2)
-
-#ifndef ISP2401
-/**** SCTBL defs *******/
-#define ISP_SCTBL_HEIGHT \
- _ISP_SCTBL_HEIGHT(ISP_INPUT_HEIGHT, DECI_FACTOR_LOG2)
-
-#endif
-/**** UDS defs *********/
-#define UDS_DMACH_STRIDE_B_IN_Y (( ISP_INTERNAL_WIDTH /BITS8_ELEMENTS_PER_XMEM_ADDR)*HIVE_ISP_DDR_WORD_BYTES)
-#define UDS_DMACH_STRIDE_B_IN_C (((ISP_INTERNAL_WIDTH/2)/BITS8_ELEMENTS_PER_XMEM_ADDR)*HIVE_ISP_DDR_WORD_BYTES)
-
-#else /* defined(__ISP) || defined(INIT_VARS) */
-
-#define ISP_INTERNAL_WIDTH isp_internal_width
-#define ISP_INTERNAL_HEIGHT isp_internal_height
-
-#endif /* defined(__ISP) || defined(INIT_VARS) */
-
-#endif /* _COMMON_ISP_EXPRS_H_ */
-
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/interface/ia_css_binary.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/interface/ia_css_binary.h
index 5a58abe2b233..732e49a241eb 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/interface/ia_css_binary.h
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/interface/ia_css_binary.h
@@ -93,17 +93,6 @@ struct ia_css_cas_binary_descr {
bool *is_output_stage;
};
-#define IA_CSS_DEFAULT_CAS_BINARY_DESCR \
-{ \
- 0, \
- 0, \
- NULL, \
- NULL, \
- NULL, \
- NULL, \
- NULL, \
-}
-
struct ia_css_binary_descr {
int mode;
bool online;
@@ -171,80 +160,15 @@ struct ia_css_binary {
struct ia_css_isp_param_css_segments css_params;
};
-#ifdef ISP2401
-
#define IA_CSS_BINARY_DEFAULT_SETTINGS \
-{ \
- NULL, \
- IA_CSS_STREAM_FORMAT_YUV420_8_LEGACY, \
- IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
- IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
- {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \
- { 0, 0},/* effective_in_frame_res */ \
- IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
- 0, /* input_buf_vectors */ \
- 0, /* deci_factor_log2 */ \
- 0, /* vf_downscale_log2 */ \
- 0, /* s3atbl_width */ \
- 0, /* s3atbl_height */ \
- 0, /* s3atbl_isp_width */ \
- 0, /* s3atbl_isp_height */ \
- 0, /* morph_tbl_width */ \
- 0, /* morph_tbl_aligned_width */ \
- 0, /* morph_tbl_height */ \
- 0, /* sctbl_width_per_color */ \
- 0, /* sctbl_aligned_width_per_color */ \
- 0, /* sctbl_height */ \
- 0, /* sctbl_legacy_width_per_color */ \
- 0, /* sctbl_legacy_height */ \
- IA_CSS_DEFAULT_SDIS_INFO, /* dis */ \
- { 0, 0},/* dvs_envelope_info */ \
- false, /* online */ \
- 0, /* uds_xc */ \
- 0, /* uds_yc */ \
- 0, /* left_padding */ \
- DEFAULT_BINARY_METRICS, /* metrics */ \
- IA_CSS_DEFAULT_ISP_MEM_PARAMS, /* mem_params */ \
- IA_CSS_DEFAULT_ISP_CSS_PARAMS, /* css_params */ \
+(struct ia_css_binary) { \
+ .input_format = IA_CSS_STREAM_FORMAT_YUV420_8_LEGACY, \
+ .in_frame_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
+ .internal_frame_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
+ .out_frame_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \
+ .vf_frame_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
}
-#else
-
-#define IA_CSS_BINARY_DEFAULT_SETTINGS \
-{ \
- NULL, \
- IA_CSS_STREAM_FORMAT_YUV420_8_LEGACY, \
- IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
- IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
- {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \
- { 0, 0},/* effective_in_frame_res */ \
- IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
- 0, /* input_buf_vectors */ \
- 0, /* deci_factor_log2 */ \
- 0, /* vf_downscale_log2 */ \
- 0, /* s3atbl_width */ \
- 0, /* s3atbl_height */ \
- 0, /* s3atbl_isp_width */ \
- 0, /* s3atbl_isp_height */ \
- 0, /* morph_tbl_width */ \
- 0, /* morph_tbl_aligned_width */ \
- 0, /* morph_tbl_height */ \
- 0, /* sctbl_width_per_color */ \
- 0, /* sctbl_aligned_width_per_color */ \
- 0, /* sctbl_height */ \
- IA_CSS_DEFAULT_SDIS_INFO, /* dis */ \
- { 0, 0},/* dvs_envelope_info */ \
- false, /* online */ \
- 0, /* uds_xc */ \
- 0, /* uds_yc */ \
- 0, /* left_padding */ \
- DEFAULT_BINARY_METRICS, /* metrics */ \
- IA_CSS_DEFAULT_ISP_MEM_PARAMS, /* mem_params */ \
- IA_CSS_DEFAULT_ISP_CSS_PARAMS, /* css_params */ \
-}
-
-#endif
-
enum ia_css_err
ia_css_binary_init_infos(void);
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/src/binary.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/src/binary.c
index 295e07049393..a0f0e9062c4c 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/src/binary.c
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/src/binary.c
@@ -490,7 +490,6 @@ ia_css_binary_get_shading_info_type_1(const struct ia_css_binary *binary, /* [in
struct sh_css_shading_table_bayer_origin_compute_results res;
#else
struct sh_css_binary_sc_requirements scr;
- struct ia_css_shading_info default_shading_info_type_1 = DEFAULT_SHADING_INFO_TYPE_1;
#endif
#ifndef ISP2401
@@ -542,7 +541,7 @@ ia_css_binary_get_shading_info_type_1(const struct ia_css_binary *binary, /* [in
&res);
if (err != IA_CSS_SUCCESS)
#else
- *shading_info = default_shading_info_type_1;
+ *shading_info = DEFAULT_SHADING_INFO_TYPE_1;
err = sh_css_binary_get_sc_requirements(binary, required_bds_factor, stream_config, &scr);
if (err != IA_CSS_SUCCESS) {
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/debug/src/ia_css_debug.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/debug/src/ia_css_debug.c
index f22d73b56bc6..60395904f89a 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/debug/src/ia_css_debug.c
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/debug/src/ia_css_debug.c
@@ -2858,13 +2858,7 @@ ia_css_debug_pipe_graph_dump_stage(
if (l && enable_info[l-1] == ',')
enable_info[--l] = '\0';
- if (l <= ENABLE_LINE_MAX_LENGTH) {
- /* It fits on one line, copy string and init */
- /* other helper strings with empty string */
- strcpy_s(enable_info,
- sizeof(enable_info),
- ei);
- } else {
+ if (l > ENABLE_LINE_MAX_LENGTH) {
/* Too big for one line, find last comma */
p = ENABLE_LINE_MAX_LENGTH;
while (ei[p] != ',')
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/frame/src/frame.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/frame/src/frame.c
index 5faa89ad8a23..7562beadabef 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/frame/src/frame.c
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/frame/src/frame.c
@@ -196,7 +196,7 @@ enum ia_css_err ia_css_frame_map(struct ia_css_frame **frame,
attribute, context);
if (me->data == mmgr_NULL)
err = IA_CSS_ERR_INVALID_ARGUMENTS;
- };
+ }
if (err != IA_CSS_SUCCESS) {
sh_css_free(me);
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/isp_param/interface/ia_css_isp_param_types.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/isp_param/interface/ia_css_isp_param_types.h
index fa3f09347b22..9d111793bb65 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/isp_param/interface/ia_css_isp_param_types.h
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/isp_param/interface/ia_css_isp_param_types.h
@@ -94,14 +94,5 @@ union ia_css_all_memory_offsets {
} array[IA_CSS_NUM_PARAM_CLASSES];
};
-#define IA_CSS_DEFAULT_ISP_MEM_PARAMS \
- { { { { NULL, 0 } } } }
-
-#define IA_CSS_DEFAULT_ISP_CSS_PARAMS \
- { { { { 0, 0 } } } }
-
-#define IA_CSS_DEFAULT_ISP_ISP_PARAMS \
- { { { { 0, 0 } } } }
-
#endif /* _IA_CSS_ISP_PARAM_TYPES_H_ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/interface/ia_css_pipeline.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/interface/ia_css_pipeline.h
index e64936e2d46e..85ed7db0af55 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/interface/ia_css_pipeline.h
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/interface/ia_css_pipeline.h
@@ -74,21 +74,15 @@ struct ia_css_pipeline {
};
#define DEFAULT_PIPELINE \
-{ \
- IA_CSS_PIPE_ID_PREVIEW, /* pipe_id */ \
- 0, /* pipe_num */ \
- false, /* stop_requested */ \
- NULL, /* stages */ \
- NULL, /* current_stage */ \
- 0, /* num_stages */ \
- DEFAULT_FRAME, /* in_frame */ \
- {DEFAULT_FRAME}, /* out_frame */ \
- {DEFAULT_FRAME}, /* vf_frame */ \
- IA_CSS_FRAME_DELAY_1, /* frame_delay */ \
- 0, /* inout_port_config */ \
- -1, /* num_execs */ \
- true, /* acquire_isp_each_stage */\
- QOS_INVALID /* pipe_qos_config */\
+(struct ia_css_pipeline) { \
+ .pipe_id = IA_CSS_PIPE_ID_PREVIEW, \
+ .in_frame = DEFAULT_FRAME, \
+ .out_frame = {DEFAULT_FRAME}, \
+ .vf_frame = {DEFAULT_FRAME}, \
+ .dvs_frame_delay = IA_CSS_FRAME_DELAY_1, \
+ .num_execs = -1, \
+ .acquire_isp_each_stage = true, \
+ .pipe_qos_config = QOS_INVALID \
}
/* Stage descriptor used to create a new stage in the pipeline */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/src/pipeline.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/src/pipeline.c
index 8f93d29d1c51..81a50c73ad0b 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/src/pipeline.c
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/src/pipeline.c
@@ -692,17 +692,16 @@ static void pipeline_init_defaults(
unsigned int pipe_num,
unsigned int dvs_frame_delay)
{
- struct ia_css_frame init_frame = DEFAULT_FRAME;
unsigned int i;
pipeline->pipe_id = pipe_id;
pipeline->stages = NULL;
pipeline->stop_requested = false;
pipeline->current_stage = NULL;
- pipeline->in_frame = init_frame;
+ pipeline->in_frame = DEFAULT_FRAME;
for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
- pipeline->out_frame[i] = init_frame;
- pipeline->vf_frame[i] = init_frame;
+ pipeline->out_frame[i] = DEFAULT_FRAME;
+ pipeline->vf_frame[i] = DEFAULT_FRAME;
}
pipeline->num_execs = -1;
pipeline->acquire_isp_each_stage = true;
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c
index 322bb3de6098..37116faab631 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c
@@ -112,8 +112,6 @@ static int thread_alive;
#define STATS_ENABLED(stage) (stage && stage->binary && stage->binary->info && \
(stage->binary->info->sp.enable.s3a || stage->binary->info->sp.enable.dis))
-#define DEFAULT_PLANES { {0, 0, 0, 0} }
-
struct sh_css my_css;
int (*sh_css_printf) (const char *fmt, va_list args) = NULL;
@@ -194,7 +192,7 @@ sh_css_pipe_start(struct ia_css_stream *stream);
* @param[in] stream Point to the target "ia_css_stream" instance.
*
* @return
- * - IA_CSS_SUCCESS, if the "stop" requests have been sucessfully sent out.
+ * - IA_CSS_SUCCESS, if the "stop" requests have been successfully sent out.
* - CSS error code, otherwise.
*
*
@@ -1054,7 +1052,7 @@ sh_css_config_input_network(struct ia_css_stream *stream)
if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE) {
/*
* We need to poll the ISYS HW in capture_indication itself
- * for "non-continous" capture usecase for getting accurate
+ * for "non-continuous" capture usecase for getting accurate
* isys frame capture timestamps.
* This is because the capturepipe propcessing takes longer
* to execute than the input system frame capture.
@@ -2291,25 +2289,19 @@ init_pipe_defaults(enum ia_css_pipe_mode mode,
struct ia_css_pipe *pipe,
bool copy_pipe)
{
- static struct ia_css_pipe default_pipe = IA_CSS_DEFAULT_PIPE;
- static struct ia_css_preview_settings prev = IA_CSS_DEFAULT_PREVIEW_SETTINGS;
- static struct ia_css_capture_settings capt = IA_CSS_DEFAULT_CAPTURE_SETTINGS;
- static struct ia_css_video_settings video = IA_CSS_DEFAULT_VIDEO_SETTINGS;
- static struct ia_css_yuvpp_settings yuvpp = IA_CSS_DEFAULT_YUVPP_SETTINGS;
-
if (pipe == NULL) {
IA_CSS_ERROR("NULL pipe parameter");
return IA_CSS_ERR_INVALID_ARGUMENTS;
}
/* Initialize pipe to pre-defined defaults */
- *pipe = default_pipe;
+ *pipe = IA_CSS_DEFAULT_PIPE;
/* TODO: JB should not be needed, but temporary backward reference */
switch (mode) {
case IA_CSS_PIPE_MODE_PREVIEW:
pipe->mode = IA_CSS_PIPE_ID_PREVIEW;
- pipe->pipe_settings.preview = prev;
+ pipe->pipe_settings.preview = IA_CSS_DEFAULT_PREVIEW_SETTINGS;
break;
case IA_CSS_PIPE_MODE_CAPTURE:
if (copy_pipe) {
@@ -2317,11 +2309,11 @@ init_pipe_defaults(enum ia_css_pipe_mode mode,
} else {
pipe->mode = IA_CSS_PIPE_ID_CAPTURE;
}
- pipe->pipe_settings.capture = capt;
+ pipe->pipe_settings.capture = IA_CSS_DEFAULT_CAPTURE_SETTINGS;
break;
case IA_CSS_PIPE_MODE_VIDEO:
pipe->mode = IA_CSS_PIPE_ID_VIDEO;
- pipe->pipe_settings.video = video;
+ pipe->pipe_settings.video = IA_CSS_DEFAULT_VIDEO_SETTINGS;
break;
case IA_CSS_PIPE_MODE_ACC:
pipe->mode = IA_CSS_PIPE_ID_ACC;
@@ -2331,7 +2323,7 @@ init_pipe_defaults(enum ia_css_pipe_mode mode,
break;
case IA_CSS_PIPE_MODE_YUVPP:
pipe->mode = IA_CSS_PIPE_ID_YUVPP;
- pipe->pipe_settings.yuvpp = yuvpp;
+ pipe->pipe_settings.yuvpp = IA_CSS_DEFAULT_YUVPP_SETTINGS;
break;
default:
return IA_CSS_ERR_INVALID_ARGUMENTS;
@@ -3657,7 +3649,7 @@ static enum ia_css_err create_host_video_pipeline(struct ia_css_pipe *pipe)
in_frame = me->stages->args.out_frame[0];
} else if (pipe->stream->config.continuous) {
#ifdef USE_INPUT_SYSTEM_VERSION_2401
- /* When continous is enabled, configure in_frame with the
+ /* When continuous is enabled, configure in_frame with the
* last pipe, which is the copy pipe.
*/
in_frame = pipe->stream->last_pipe->continuous_frames[0];
@@ -3854,7 +3846,7 @@ create_host_preview_pipeline(struct ia_css_pipe *pipe)
* - Direct Sensor Mode Online Preview
* - Buffered Sensor Mode Online Preview
* - Direct Sensor Mode Continuous Preview
- * - Buffered Sensor Mode Continous Preview
+ * - Buffered Sensor Mode Continuous Preview
*/
sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
@@ -4715,7 +4707,7 @@ ia_css_dequeue_psys_event(struct ia_css_event *event)
event->timer_subcode = payload[2];
}
/* It's a non timer event. So clear first half of the timer event data.
- * If the second part of the TIMER event is not recieved, we discard
+ * If the second part of the TIMER event is not received, we discard
* the first half of the timer data and process the non timer event without
* affecting the flow. So the non timer event falls through
* the code. */
@@ -5588,8 +5580,7 @@ static enum ia_css_err load_video_binaries(struct ia_css_pipe *pipe)
/* we build up the pipeline starting at the end */
/* YUV post-processing if needed */
if (need_scaler) {
- struct ia_css_cas_binary_descr cas_scaler_descr
- = IA_CSS_DEFAULT_CAS_BINARY_DESCR;
+ struct ia_css_cas_binary_descr cas_scaler_descr = { };
/* NV12 is the common format that is supported by both */
/* yuv_scaler and the video_xx_isp2_min binaries. */
@@ -6244,8 +6235,8 @@ static enum ia_css_err load_primary_binaries(
pipe_out_info->res);
if (need_extra_yuv_scaler) {
- struct ia_css_cas_binary_descr cas_scaler_descr
- = IA_CSS_DEFAULT_CAS_BINARY_DESCR;
+ struct ia_css_cas_binary_descr cas_scaler_descr = { };
+
err = ia_css_pipe_create_cas_scaler_desc_single_output(
&capt_pp_out_info,
pipe_out_info,
@@ -6958,7 +6949,7 @@ static enum ia_css_err ia_css_pipe_create_cas_scaler_desc_single_output(
unsigned int i;
unsigned int hor_ds_factor = 0, ver_ds_factor = 0;
enum ia_css_err err = IA_CSS_SUCCESS;
- struct ia_css_frame_info tmp_in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO;
+ struct ia_css_frame_info tmp_in_info;
unsigned max_scale_factor_per_stage = MAX_PREFERRED_YUV_DS_PER_STEP;
@@ -7232,7 +7223,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe)
struct ia_css_frame_info *vf_pp_in_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
struct ia_css_yuvpp_settings *mycs;
struct ia_css_binary *next_binary;
- struct ia_css_cas_binary_descr cas_scaler_descr = IA_CSS_DEFAULT_CAS_BINARY_DESCR;
+ struct ia_css_cas_binary_descr cas_scaler_descr = { };
unsigned int i, j;
bool need_isp_copy_binary = false;
@@ -7610,7 +7601,7 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe)
* except for the following:
* - Direct Sensor Mode Online Capture
* - Direct Sensor Mode Continuous Capture
- * - Buffered Sensor Mode Continous Capture
+ * - Buffered Sensor Mode Continuous Capture
*/
sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
buffered_sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR;
@@ -7950,7 +7941,7 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe)
* - Direct Sensor Mode Online Capture
* - Direct Sensor Mode Online Capture
* - Direct Sensor Mode Continuous Capture
- * - Buffered Sensor Mode Continous Capture
+ * - Buffered Sensor Mode Continuous Capture
*/
sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
@@ -8827,10 +8818,8 @@ sh_css_init_host_sp_control_vars(void)
*/
void ia_css_pipe_config_defaults(struct ia_css_pipe_config *pipe_config)
{
- struct ia_css_pipe_config def_config = DEFAULT_PIPE_CONFIG;
-
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_config_defaults()\n");
- *pipe_config = def_config;
+ *pipe_config = DEFAULT_PIPE_CONFIG;
}
void
@@ -8915,7 +8904,7 @@ ia_css_pipe_create(const struct ia_css_pipe_config *config,
err = ia_css_pipe_create_extra(config, NULL, pipe);
if(err == IA_CSS_SUCCESS) {
- IA_CSS_LOG("pipe created successfuly = %p", *pipe);
+ IA_CSS_LOG("pipe created successfully = %p", *pipe);
}
IA_CSS_LEAVE_ERR_PRIVATE(err);
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_legacy.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_legacy.h
index 4bcc35d219f8..4fd25ba2cd0d 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_legacy.h
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_legacy.h
@@ -52,17 +52,6 @@ struct ia_css_pipe_extra_config {
bool disable_vf_pp;
};
-#define DEFAULT_PIPE_EXTRA_CONFIG \
-{ \
- false, /* enable_raw_binning */ \
- false, /* enable_yuv_ds */ \
- false, /* enable_high_speed */ \
- false, /* enable_dvs_6axis */ \
- false, /* enable_reduced_pipe */ \
- false, /* enable_fractional_ds */ \
- false, /* disable_vf_pp */ \
-}
-
enum ia_css_err
ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
const struct ia_css_pipe_extra_config *extra_config,
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_metrics.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_metrics.h
index 40840ea318ab..2ef9238d95ad 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_metrics.h
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_metrics.h
@@ -24,16 +24,6 @@ struct sh_css_pc_histogram {
unsigned *msink;
};
-#if !defined(__USE_DESIGNATED_INITIALISERS__)
-#define DEFAULT_PC_HISTOGRAM \
-{ \
- 0, \
- NULL, \
- NULL, \
- NULL \
-}
-#endif
-
struct sh_css_binary_metrics {
unsigned mode;
unsigned id;
@@ -42,17 +32,6 @@ struct sh_css_binary_metrics {
struct sh_css_binary_metrics *next;
};
-#if !defined(__USE_DESIGNATED_INITIALISERS__)
-#define DEFAULT_BINARY_METRICS \
-{ \
- 0, \
- 0, \
- DEFAULT_PC_HISTOGRAM, \
- DEFAULT_PC_HISTOGRAM, \
- NULL \
-}
-#endif
-
struct ia_css_frame_metrics {
unsigned num_frames;
};
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo_dev.h b/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo_dev.h
deleted file mode 100644
index 9e51a657ece4..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo_dev.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Support for Medifield PNW Camera Imaging ISP subsystem.
- *
- * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
- *
- * Copyright (c) 2010 Silicon Hive www.siliconhive.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 __HMM_BO_DEV_H__
-#define __HMM_BO_DEV_H__
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include "mmu/isp_mmu.h"
-#include "hmm/hmm_common.h"
-#include "hmm/hmm_vm.h"
-#include "ia_css_types.h"
-
-#define check_bodev_null_return(bdev, exp) \
- check_null_return(bdev, exp, \
- "NULL hmm_bo_device.\n")
-
-#define check_bodev_null_return_void(bdev) \
- check_null_return_void(bdev, \
- "NULL hmm_bo_device.\n")
-
-#define HMM_BO_DEVICE_INITED 0x1
-
-#define HMM_BO_CACHE_SIZE 2
-
-
-struct hmm_buffer_object;
-
-struct hmm_bo_device {
- /* isp_mmu provides lock itself */
- struct isp_mmu mmu;
-
- /* hmm_vm provides lock itself */
- struct hmm_vm vaddr_space;
-
- struct list_head free_bo_list;
- struct list_head active_bo_list;
-
- /* list lock is used to protect both of the buffer object lists */
- spinlock_t list_lock;
-#ifdef CONFIG_ION
- struct ion_client *iclient;
-#endif
- int flag;
-};
-
-int hmm_bo_device_init(struct hmm_bo_device *bdev,
- struct isp_mmu_client *mmu_driver,
- unsigned int vaddr_start, unsigned int size);
-
-/*
- * clean up all hmm_bo_device related things.
- */
-void hmm_bo_device_exit(struct hmm_bo_device *bdev);
-
-/*
- * whether the bo device is inited or not.
- */
-int hmm_bo_device_inited(struct hmm_bo_device *bdev);
-
-/*
- * find the buffer object with virtual address vaddr.
- * return NULL if no such buffer object found.
- */
-struct hmm_buffer_object *hmm_bo_device_search_start(
- struct hmm_bo_device *bdev, ia_css_ptr vaddr);
-
-/*
- * find the buffer object with virtual address vaddr.
- * return NULL if no such buffer object found.
- */
-struct hmm_buffer_object *hmm_bo_device_search_in_range(
- struct hmm_bo_device *bdev, ia_css_ptr vaddr);
-
-/*
- * find the buffer object with kernel virtual address vaddr.
- * return NULL if no such buffer object found.
- */
-struct hmm_buffer_object *hmm_bo_device_search_vmap_start(
- struct hmm_bo_device *bdev, const void *vaddr);
-
-/*
- * find a buffer object with pgnr pages from free_bo_list and
- * activate it (remove from free_bo_list and add to
- * active_bo_list)
- *
- * return NULL if no such buffer object found.
- */
-struct hmm_buffer_object *hmm_bo_device_get_bo(
- struct hmm_bo_device *bdev, unsigned int pgnr);
-
-/*
- * destroy all buffer objects in the free_bo_list.
- */
-void hmm_bo_device_destroy_free_bo_list(struct hmm_bo_device *bdev);
-/*
- * destroy buffer object with start virtual address vaddr.
- */
-void hmm_bo_device_destroy_free_bo_addr(struct hmm_bo_device *bdev,
- ia_css_ptr vaddr);
-/*
- * destroy all buffer objects with pgnr pages.
- */
-void hmm_bo_device_destroy_free_bo_size(struct hmm_bo_device *bdev,
- unsigned int pgnr);
-
-#endif
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu.h b/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu.h
deleted file mode 100644
index 031c0398bf65..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Support for Medifield PNW Camera Imaging ISP subsystem.
- *
- * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
- *
- * Copyright (c) 2010 Silicon Hive www.siliconhive.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 SH_MMU_H_
-#define SH_MMU_H_
-
-
-#include <sh_css.h>
-
-#include "mmu/isp_mmu.h"
-
-
-/*
- * include SH header file here
- */
-
-/*
- * set page directory base address (physical address).
- *
- * must be provided.
- */
-static int sh_set_pd_base(struct isp_mmu *mmu,
- unsigned int phys)
-{
- sh_css_mmu_set_page_table_base_address((void *)phys);
- return 0;
-}
-
-/*
- * callback to flush tlb.
- *
- * tlb_flush_range will at least flush TLBs containing
- * address mapping from addr to addr + size.
- *
- * tlb_flush_all will flush all TLBs.
- *
- * tlb_flush_all is must be provided. if tlb_flush_range is
- * not valid, it will set to tlb_flush_all by default.
- */
-static void sh_tlb_flush(struct isp_mmu *mmu)
-{
- sh_css_mmu_invalidate_cache();
-}
-
-static struct isp_mmu_driver sh_mmu_driver = {
- .name = "Silicon Hive ISP3000 MMU",
- .pte_valid_mask = 0x1,
- .set_pd_base = sh_set_pd_base,
- .tlb_flush_all = sh_tlb_flush,
-};
-
-#define ISP_VM_START 0x0
-#define ISP_VM_SIZE (1 << 30) /* 1G address space */
-#define ISP_PTR_NULL NULL
-
-#endif /* SH_MMU_H_ */
-
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/mmu/isp_mmu.c b/drivers/staging/media/atomisp/pci/atomisp2/mmu/isp_mmu.c
index e36c2a33b41a..f21075c1e503 100644
--- a/drivers/staging/media/atomisp/pci/atomisp2/mmu/isp_mmu.c
+++ b/drivers/staging/media/atomisp/pci/atomisp2/mmu/isp_mmu.c
@@ -450,7 +450,7 @@ static void mmu_l1_unmap(struct isp_mmu *mmu, phys_addr_t l1_pt,
ptr = end;
}
/*
- * use the same L2 page next time, so we dont
+ * use the same L2 page next time, so we don't
* need to invalidate and free this PT.
*/
/* atomisp_set_pte(l1_pt, idx, NULL_PTE); */
diff --git a/drivers/staging/media/cxd2099/Kconfig b/drivers/staging/media/cxd2099/Kconfig
deleted file mode 100644
index b48aefddc84c..000000000000
--- a/drivers/staging/media/cxd2099/Kconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-config DVB_CXD2099
- tristate "CXD2099AR Common Interface driver"
- depends on DVB_CORE && PCI && I2C
- ---help---
- Support for the CI module found on cards based on
- - Micronas ngene PCIe bridge: cineS2 etc.
- - Digital Devices PCIe bridge: Octopus series
-
- For now, data is passed through '/dev/dvb/adapterX/sec0':
- - Encrypted data must be written to 'sec0'.
- - Decrypted data can be read from 'sec0'.
- - Setup the CAM using device 'ca0'.
diff --git a/drivers/staging/media/cxd2099/Makefile b/drivers/staging/media/cxd2099/Makefile
deleted file mode 100644
index 30432c9aabc4..000000000000
--- a/drivers/staging/media/cxd2099/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-obj-$(CONFIG_DVB_CXD2099) += cxd2099.o
-
-ccflags-y += -Idrivers/media/dvb-frontends/
-ccflags-y += -Idrivers/media/tuners/
diff --git a/drivers/staging/media/cxd2099/TODO b/drivers/staging/media/cxd2099/TODO
deleted file mode 100644
index 375bb6f8ee2c..000000000000
--- a/drivers/staging/media/cxd2099/TODO
+++ /dev/null
@@ -1,12 +0,0 @@
-For now, data is passed through '/dev/dvb/adapterX/sec0':
- - Encrypted data must be written to 'sec0'.
- - Decrypted data can be read from 'sec0'.
- - Setup the CAM using device 'ca0'.
-
-But this is wrong. There are some discussions about the proper way for
-doing it, as seen at:
- http://www.mail-archive.com/linux-media@vger.kernel.org/msg22196.html
-
-While there's no proper fix for it, the driver should be kept in staging.
-
-Patches should be submitted to: linux-media@vger.kernel.org.
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
index bffe2153b910..634d38c4bea1 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
@@ -444,7 +444,7 @@ static int vpfe_register_entities(struct vpfe_device *vpfe_dev)
for (i = 0; i < vpfe_dev->num_ext_subdevs; i++)
/*
* if entity has no pads (ex: amplifier),
- * cant establish link
+ * can't establish link
*/
if (vpfe_dev->sd[i]->entity.num_pads) {
ret = media_create_pad_link(&vpfe_dev->sd[i]->entity,
diff --git a/drivers/staging/media/imx/Kconfig b/drivers/staging/media/imx/Kconfig
index 2be921cd0d55..bfc17de56b17 100644
--- a/drivers/staging/media/imx/Kconfig
+++ b/drivers/staging/media/imx/Kconfig
@@ -1,7 +1,9 @@
config VIDEO_IMX_MEDIA
tristate "i.MX5/6 V4L2 media core driver"
- depends on MEDIA_CONTROLLER && VIDEO_V4L2 && ARCH_MXC && IMX_IPUV3_CORE
+ depends on ARCH_MXC || COMPILE_TEST
+ depends on MEDIA_CONTROLLER && VIDEO_V4L2 && IMX_IPUV3_CORE
depends on VIDEO_V4L2_SUBDEV_API
+ depends on HAS_DMA
select VIDEOBUF2_DMA_CONTIG
select V4L2_FWNODE
---help---
diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c
index c6d7e80932ad..98923fc844ce 100644
--- a/drivers/staging/media/imx/imx-ic-prp.c
+++ b/drivers/staging/media/imx/imx-ic-prp.c
@@ -462,6 +462,7 @@ static int prp_registered(struct v4l2_subdev *sd)
}
static const struct v4l2_subdev_pad_ops prp_pad_ops = {
+ .init_cfg = imx_media_init_cfg,
.enum_mbus_code = prp_enum_mbus_code,
.get_fmt = prp_get_fmt,
.set_fmt = prp_set_fmt,
diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c
index 143038c6c403..ae453fd422f0 100644
--- a/drivers/staging/media/imx/imx-ic-prpencvf.c
+++ b/drivers/staging/media/imx/imx-ic-prpencvf.c
@@ -923,7 +923,7 @@ static int prp_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_size_enum *fse)
{
struct prp_priv *priv = sd_to_priv(sd);
- struct v4l2_subdev_format format = {0};
+ struct v4l2_subdev_format format = {};
const struct imx_media_pixfmt *cc;
int ret = 0;
@@ -1253,6 +1253,7 @@ static void prp_unregistered(struct v4l2_subdev *sd)
}
static const struct v4l2_subdev_pad_ops prp_pad_ops = {
+ .init_cfg = imx_media_init_cfg,
.enum_mbus_code = prp_enum_mbus_code,
.enum_frame_size = prp_enum_frame_size,
.get_fmt = prp_get_fmt,
diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c
index 576bdc7e9c42..0ccabe04b0e1 100644
--- a/drivers/staging/media/imx/imx-media-capture.c
+++ b/drivers/staging/media/imx/imx-media-capture.c
@@ -141,7 +141,8 @@ static int capture_enum_frameintervals(struct file *file, void *fh,
fie.code = cc->codes[0];
- ret = v4l2_subdev_call(priv->src_sd, pad, enum_frame_interval, NULL, &fie);
+ ret = v4l2_subdev_call(priv->src_sd, pad, enum_frame_interval,
+ NULL, &fie);
if (ret)
return ret;
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index eb7be5093a9d..1aa2be891704 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -400,6 +400,7 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
case V4L2_PIX_FMT_SRGGB8:
+ case V4L2_PIX_FMT_GREY:
burst_size = 16;
passthrough = true;
passthrough_bits = 8;
@@ -668,11 +669,10 @@ static int csi_setup(struct csi_priv *priv)
static int csi_start(struct csi_priv *priv)
{
- struct v4l2_fract *output_fi, *input_fi;
+ struct v4l2_fract *output_fi;
int ret;
output_fi = &priv->frame_interval[priv->active_output_pad];
- input_fi = &priv->frame_interval[CSI_SINK_PAD];
if (priv->dest == IPU_CSI_DEST_IDMAC) {
ret = csi_idmac_start(priv);
@@ -1715,6 +1715,7 @@ static const struct v4l2_subdev_video_ops csi_video_ops = {
};
static const struct v4l2_subdev_pad_ops csi_pad_ops = {
+ .init_cfg = imx_media_init_cfg,
.enum_mbus_code = csi_enum_mbus_code,
.enum_frame_size = csi_enum_frame_size,
.enum_frame_interval = csi_enum_frame_interval,
@@ -1797,6 +1798,10 @@ static int imx_csi_probe(struct platform_device *pdev)
*/
priv->dev->of_node = pdata->of_node;
pinctrl = devm_pinctrl_get_select_default(priv->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(priv->vdev);
+ goto free;
+ }
ret = v4l2_async_register_subdev(&priv->sd);
if (ret)
diff --git a/drivers/staging/media/imx/imx-media-internal-sd.c b/drivers/staging/media/imx/imx-media-internal-sd.c
index 70833fe503b5..daf66c2d69ab 100644
--- a/drivers/staging/media/imx/imx-media-internal-sd.c
+++ b/drivers/staging/media/imx/imx-media-internal-sd.c
@@ -271,7 +271,7 @@ static int add_internal_subdev(struct imx_media_dev *imxmd,
int ipu_id)
{
struct imx_media_internal_sd_platformdata pdata;
- struct platform_device_info pdevinfo = {0};
+ struct platform_device_info pdevinfo = {};
struct platform_device *pdev;
pdata.grp_id = isd->id->grp_id;
diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
index 13dafa77a2eb..fab98fc0d6a0 100644
--- a/drivers/staging/media/imx/imx-media-utils.c
+++ b/drivers/staging/media/imx/imx-media-utils.c
@@ -93,7 +93,7 @@ static const struct imx_media_pixfmt rgb_formats[] = {
.bpp = 32,
.ipufmt = true,
},
- /*** raw bayer formats start here ***/
+ /*** raw bayer and grayscale formats start here ***/
{
.fourcc = V4L2_PIX_FMT_SBGGR8,
.codes = {MEDIA_BUS_FMT_SBGGR8_1X8},
@@ -162,6 +162,12 @@ static const struct imx_media_pixfmt rgb_formats[] = {
.cs = IPUV3_COLORSPACE_RGB,
.bpp = 16,
.bayer = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .codes = {MEDIA_BUS_FMT_Y8_1X8},
+ .cs = IPUV3_COLORSPACE_RGB,
+ .bpp = 8,
+ .bayer = true,
},
/***
* non-mbus RGB formats start here. NOTE! when adding non-mbus
@@ -219,58 +225,63 @@ static void init_mbus_colorimetry(struct v4l2_mbus_framefmt *mbus,
mbus->ycbcr_enc);
}
+static const
+struct imx_media_pixfmt *__find_format(u32 fourcc,
+ u32 code,
+ bool allow_non_mbus,
+ bool allow_bayer,
+ const struct imx_media_pixfmt *array,
+ u32 array_size)
+{
+ const struct imx_media_pixfmt *fmt;
+ int i, j;
+
+ for (i = 0; i < array_size; i++) {
+ fmt = &array[i];
+
+ if ((!allow_non_mbus && !fmt->codes[0]) ||
+ (!allow_bayer && fmt->bayer))
+ continue;
+
+ if (fourcc && fmt->fourcc == fourcc)
+ return fmt;
+
+ if (!code)
+ continue;
+
+ for (j = 0; fmt->codes[j]; j++) {
+ if (code == fmt->codes[j])
+ return fmt;
+ }
+ }
+ return NULL;
+}
+
static const struct imx_media_pixfmt *find_format(u32 fourcc,
u32 code,
enum codespace_sel cs_sel,
bool allow_non_mbus,
bool allow_bayer)
{
- const struct imx_media_pixfmt *array, *fmt, *ret = NULL;
- u32 array_size;
- int i, j;
+ const struct imx_media_pixfmt *ret;
switch (cs_sel) {
case CS_SEL_YUV:
- array_size = NUM_YUV_FORMATS;
- array = yuv_formats;
- break;
+ return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
+ yuv_formats, NUM_YUV_FORMATS);
case CS_SEL_RGB:
- array_size = NUM_RGB_FORMATS;
- array = rgb_formats;
- break;
+ return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
+ rgb_formats, NUM_RGB_FORMATS);
case CS_SEL_ANY:
- array_size = NUM_YUV_FORMATS + NUM_RGB_FORMATS;
- array = yuv_formats;
- break;
+ ret = __find_format(fourcc, code, allow_non_mbus, allow_bayer,
+ yuv_formats, NUM_YUV_FORMATS);
+ if (ret)
+ return ret;
+ return __find_format(fourcc, code, allow_non_mbus, allow_bayer,
+ rgb_formats, NUM_RGB_FORMATS);
default:
return NULL;
}
-
- for (i = 0; i < array_size; i++) {
- if (cs_sel == CS_SEL_ANY && i >= NUM_YUV_FORMATS)
- fmt = &rgb_formats[i - NUM_YUV_FORMATS];
- else
- fmt = &array[i];
-
- if ((!allow_non_mbus && fmt->codes[0] == 0) ||
- (!allow_bayer && fmt->bayer))
- continue;
-
- if (fourcc && fmt->fourcc == fourcc) {
- ret = fmt;
- goto out;
- }
-
- for (j = 0; code && fmt->codes[j]; j++) {
- if (code == fmt->codes[j]) {
- ret = fmt;
- goto out;
- }
- }
- }
-
-out:
- return ret;
}
static int enum_format(u32 *fourcc, u32 *code, u32 index,
@@ -465,6 +476,35 @@ int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
/*
+ * Initializes the TRY format to the ACTIVE format on all pads
+ * of a subdev. Can be used as the .init_cfg pad operation.
+ */
+int imx_media_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg)
+{
+ struct v4l2_mbus_framefmt *mf_try;
+ struct v4l2_subdev_format format;
+ unsigned int pad;
+ int ret;
+
+ for (pad = 0; pad < sd->entity.num_pads; pad++) {
+ memset(&format, 0, sizeof(format));
+
+ format.pad = pad;
+ format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format);
+ if (ret)
+ continue;
+
+ mf_try = v4l2_subdev_get_try_format(sd, cfg, pad);
+ *mf_try = format.format;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(imx_media_init_cfg);
+
+/*
* Check whether the field and colorimetry parameters in tryfmt are
* uninitialized, and if so fill them with the values from fmt,
* or if tryfmt->colorspace has been initialized, all the default
diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c
index 433474d58e3e..482250d47e7c 100644
--- a/drivers/staging/media/imx/imx-media-vdic.c
+++ b/drivers/staging/media/imx/imx-media-vdic.c
@@ -177,7 +177,7 @@ static int vdic_get_ipu_resources(struct vdic_priv *priv)
priv->vdi_in_ch = ch;
ch = ipu_idmac_get(priv->ipu, IPUV3_CHANNEL_MEM_VDI_NEXT);
- if (IS_ERR(priv->vdi_in_ch_n)) {
+ if (IS_ERR(ch)) {
err_chan = IPUV3_CHANNEL_MEM_VDI_NEXT;
ret = PTR_ERR(ch);
goto out_err_chan;
@@ -909,6 +909,7 @@ static void vdic_unregistered(struct v4l2_subdev *sd)
}
static const struct v4l2_subdev_pad_ops vdic_pad_ops = {
+ .init_cfg = imx_media_init_cfg,
.enum_mbus_code = vdic_enum_mbus_code,
.get_fmt = vdic_get_fmt,
.set_fmt = vdic_set_fmt,
diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
index 2fd6dfdf37d6..e945e0ed6dd6 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -172,6 +172,8 @@ int imx_media_enum_ipu_format(u32 *code, u32 index, enum codespace_sel cs_sel);
int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
u32 width, u32 height, u32 code, u32 field,
const struct imx_media_pixfmt **cc);
+int imx_media_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg);
void imx_media_fill_default_mbus_fields(struct v4l2_mbus_framefmt *tryfmt,
struct v4l2_mbus_framefmt *fmt,
bool ic_route);
diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c
index 477d191c568b..ceeeb3069a02 100644
--- a/drivers/staging/media/imx/imx6-mipi-csi2.c
+++ b/drivers/staging/media/imx/imx6-mipi-csi2.c
@@ -447,6 +447,16 @@ out:
return ret;
}
+static struct v4l2_mbus_framefmt *
+__csi2_get_fmt(struct csi2_dev *csi2, struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_format(&csi2->sd, cfg, pad);
+ else
+ return &csi2->format_mbus;
+}
+
static int csi2_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *sdformat)
@@ -456,11 +466,7 @@ static int csi2_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&csi2->lock);
- if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt = v4l2_subdev_get_try_format(&csi2->sd, cfg,
- sdformat->pad);
- else
- fmt = &csi2->format_mbus;
+ fmt = __csi2_get_fmt(csi2, cfg, sdformat->pad, sdformat->which);
sdformat->format = *fmt;
@@ -474,6 +480,7 @@ static int csi2_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_format *sdformat)
{
struct csi2_dev *csi2 = sd_to_dev(sd);
+ struct v4l2_mbus_framefmt *fmt;
int ret = 0;
if (sdformat->pad >= CSI2_NUM_PADS)
@@ -490,10 +497,9 @@ static int csi2_set_fmt(struct v4l2_subdev *sd,
if (sdformat->pad != CSI2_SINK_PAD)
sdformat->format = csi2->format_mbus;
- if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY)
- cfg->try_fmt = sdformat->format;
- else
- csi2->format_mbus = sdformat->format;
+ fmt = __csi2_get_fmt(csi2, cfg, sdformat->pad, sdformat->which);
+
+ *fmt = sdformat->format;
out:
mutex_unlock(&csi2->lock);
return ret;
@@ -531,6 +537,7 @@ static const struct v4l2_subdev_video_ops csi2_video_ops = {
};
static const struct v4l2_subdev_pad_ops csi2_pad_ops = {
+ .init_cfg = imx_media_init_cfg,
.get_fmt = csi2_get_fmt,
.set_fmt = csi2_set_fmt,
};
diff --git a/drivers/staging/media/imx074/Kconfig b/drivers/staging/media/imx074/Kconfig
new file mode 100644
index 000000000000..229cbeea580b
--- /dev/null
+++ b/drivers/staging/media/imx074/Kconfig
@@ -0,0 +1,5 @@
+config SOC_CAMERA_IMX074
+ tristate "imx074 support (DEPRECATED)"
+ depends on SOC_CAMERA && I2C
+ help
+ This driver supports IMX074 cameras from Sony
diff --git a/drivers/staging/media/imx074/Makefile b/drivers/staging/media/imx074/Makefile
new file mode 100644
index 000000000000..7d183574aa84
--- /dev/null
+++ b/drivers/staging/media/imx074/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o
diff --git a/drivers/staging/media/imx074/TODO b/drivers/staging/media/imx074/TODO
new file mode 100644
index 000000000000..15580a4f950c
--- /dev/null
+++ b/drivers/staging/media/imx074/TODO
@@ -0,0 +1,5 @@
+This sensor driver needs to be converted to a regular
+v4l2 subdev driver. The soc_camera framework is deprecated and
+will be removed in the future. Unless someone does this work this
+sensor driver will be deleted when the soc_camera framework is
+deleted.
diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/staging/media/imx074/imx074.c
index 77f1e0243d6e..77f1e0243d6e 100644
--- a/drivers/media/i2c/soc_camera/imx074.c
+++ b/drivers/staging/media/imx074/imx074.c
diff --git a/drivers/staging/media/mt9t031/Kconfig b/drivers/staging/media/mt9t031/Kconfig
new file mode 100644
index 000000000000..f48e06a03cdb
--- /dev/null
+++ b/drivers/staging/media/mt9t031/Kconfig
@@ -0,0 +1,11 @@
+config SOC_CAMERA_IMX074
+ tristate "imx074 support (DEPRECATED)"
+ depends on SOC_CAMERA && I2C
+ help
+ This driver supports IMX074 cameras from Sony
+
+config SOC_CAMERA_MT9T031
+ tristate "mt9t031 support (DEPRECATED)"
+ depends on SOC_CAMERA && I2C
+ help
+ This driver supports MT9T031 cameras from Micron.
diff --git a/drivers/staging/media/mt9t031/Makefile b/drivers/staging/media/mt9t031/Makefile
new file mode 100644
index 000000000000..bfd24c442b33
--- /dev/null
+++ b/drivers/staging/media/mt9t031/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
diff --git a/drivers/staging/media/mt9t031/TODO b/drivers/staging/media/mt9t031/TODO
new file mode 100644
index 000000000000..15580a4f950c
--- /dev/null
+++ b/drivers/staging/media/mt9t031/TODO
@@ -0,0 +1,5 @@
+This sensor driver needs to be converted to a regular
+v4l2 subdev driver. The soc_camera framework is deprecated and
+will be removed in the future. Unless someone does this work this
+sensor driver will be deleted when the soc_camera framework is
+deleted.
diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/staging/media/mt9t031/mt9t031.c
index 4802d30e47de..4802d30e47de 100644
--- a/drivers/media/i2c/soc_camera/mt9t031.c
+++ b/drivers/staging/media/mt9t031/mt9t031.c
diff --git a/drivers/staging/most/core.c b/drivers/staging/most/core.c
index 3dda8d81bf0b..8f2833526f7f 100644
--- a/drivers/staging/most/core.c
+++ b/drivers/staging/most/core.c
@@ -583,6 +583,7 @@ static ssize_t components_show(struct device_driver *drv, char *buf)
}
return offs;
}
+
/**
* split_string - parses buf and extracts ':' separated substrings.
*
@@ -915,7 +916,6 @@ static void arm_mbo(struct mbo *mbo)
unsigned long flags;
struct most_channel *c;
- BUG_ON((!mbo) || (!mbo->context));
c = mbo->context;
if (c->is_poisoned) {
@@ -1018,8 +1018,6 @@ static void most_write_completion(struct mbo *mbo)
{
struct most_channel *c;
- BUG_ON((!mbo) || (!mbo->context));
-
c = mbo->context;
if (mbo->status == MBO_E_INVAL)
pr_info("WARN: Tx MBO status: invalid\n");
@@ -1202,7 +1200,6 @@ int most_start_channel(struct most_interface *iface, int id,
num_buffer = arm_mbo_chain(c, c->cfg.direction,
most_write_completion);
if (unlikely(!num_buffer)) {
- pr_info("failed to allocate memory\n");
ret = -ENOMEM;
goto error;
}
@@ -1381,7 +1378,6 @@ int most_register_interface(struct most_interface *iface)
iface->p = kzalloc(sizeof(*iface->p), GFP_KERNEL);
if (!iface->p) {
- pr_info("Failed to allocate interface instance\n");
ida_simple_remove(&mdev_id, id);
return -ENOMEM;
}
@@ -1474,7 +1470,8 @@ void most_deregister_interface(struct most_interface *iface)
int i;
struct most_channel *c;
- pr_info("deregistering device %s (%s)\n", dev_name(&iface->dev), iface->description);
+ pr_info("deregistering device %s (%s)\n", dev_name(&iface->dev),
+ iface->description);
for (i = 0; i < iface->num_channels; i++) {
c = iface->p->channel[i];
if (c->pipe0.comp)
diff --git a/drivers/staging/most/core.h b/drivers/staging/most/core.h
index 74a29163b68a..884bd71fafce 100644
--- a/drivers/staging/most/core.h
+++ b/drivers/staging/most/core.h
@@ -184,7 +184,7 @@ struct mbo {
u16 buffer_length;
u16 processed_length;
enum mbo_status_flags status;
- void (*complete)(struct mbo *);
+ void (*complete)(struct mbo *mbo);
};
/**
diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
index 264ad362d858..d20284b49557 100644
--- a/drivers/staging/mt29f_spinand/mt29f_spinand.c
+++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c
@@ -316,6 +316,7 @@ static int spinand_read_page_to_cache(struct spi_device *spi_nand, u16 page_id)
row = page_id;
cmd.cmd = CMD_READ;
cmd.n_addr = 3;
+ cmd.addr[0] = (u8)((row & 0xff0000) >> 16);
cmd.addr[1] = (u8)((row & 0xff00) >> 8);
cmd.addr[2] = (u8)(row & 0x00ff);
@@ -464,6 +465,7 @@ static int spinand_program_execute(struct spi_device *spi_nand, u16 page_id)
row = page_id;
cmd.cmd = CMD_PROG_PAGE_EXC;
cmd.n_addr = 3;
+ cmd.addr[0] = (u8)((row & 0xff0000) >> 16);
cmd.addr[1] = (u8)((row & 0xff00) >> 8);
cmd.addr[2] = (u8)(row & 0x00ff);
@@ -579,6 +581,7 @@ static int spinand_erase_block_erase(struct spi_device *spi_nand, u16 block_id)
row = block_id;
cmd.cmd = CMD_ERASE_BLK;
cmd.n_addr = 3;
+ cmd.addr[0] = (u8)((row & 0xff0000) >> 16);
cmd.addr[1] = (u8)((row & 0xff00) >> 8);
cmd.addr[2] = (u8)(row & 0x00ff);
diff --git a/drivers/staging/mt7621-dma/Kconfig b/drivers/staging/mt7621-dma/Kconfig
new file mode 100644
index 000000000000..2423c40099d1
--- /dev/null
+++ b/drivers/staging/mt7621-dma/Kconfig
@@ -0,0 +1,12 @@
+config DMA_RALINK
+ tristate "RALINK DMA support"
+ depends on RALINK && !SOC_RT288X
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+
+config MTK_HSDMA
+ tristate "MTK HSDMA support"
+ depends on RALINK && SOC_MT7621
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+
diff --git a/drivers/staging/mt7621-dma/Makefile b/drivers/staging/mt7621-dma/Makefile
new file mode 100644
index 000000000000..d3152d45cf45
--- /dev/null
+++ b/drivers/staging/mt7621-dma/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_DMA_RALINK) += ralink-gdma.o
+obj-$(CONFIG_MTK_HSDMA) += mtk-hsdma.o
+
+ccflags-y += -I$(srctree)/drivers/dma
diff --git a/drivers/staging/mt7621-dma/TODO b/drivers/staging/mt7621-dma/TODO
new file mode 100644
index 000000000000..fdbc5002c32a
--- /dev/null
+++ b/drivers/staging/mt7621-dma/TODO
@@ -0,0 +1,5 @@
+
+- general code review and clean up
+- ensure device-tree requirements are documented
+
+Cc: NeilBrown <neil@brown.name>
diff --git a/drivers/staging/mt7621-dma/mtk-hsdma.c b/drivers/staging/mt7621-dma/mtk-hsdma.c
new file mode 100644
index 000000000000..df6ebf41bdea
--- /dev/null
+++ b/drivers/staging/mt7621-dma/mtk-hsdma.c
@@ -0,0 +1,768 @@
+/*
+ * Copyright (C) 2015, Michael Lee <igvtee@gmail.com>
+ * MTK HSDMA support
+ *
+ * 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/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/irq.h>
+#include <linux/of_dma.h>
+#include <linux/reset.h>
+#include <linux/of_device.h>
+
+#include "virt-dma.h"
+
+#define HSDMA_BASE_OFFSET 0x800
+
+#define HSDMA_REG_TX_BASE 0x00
+#define HSDMA_REG_TX_CNT 0x04
+#define HSDMA_REG_TX_CTX 0x08
+#define HSDMA_REG_TX_DTX 0x0c
+#define HSDMA_REG_RX_BASE 0x100
+#define HSDMA_REG_RX_CNT 0x104
+#define HSDMA_REG_RX_CRX 0x108
+#define HSDMA_REG_RX_DRX 0x10c
+#define HSDMA_REG_INFO 0x200
+#define HSDMA_REG_GLO_CFG 0x204
+#define HSDMA_REG_RST_CFG 0x208
+#define HSDMA_REG_DELAY_INT 0x20c
+#define HSDMA_REG_FREEQ_THRES 0x210
+#define HSDMA_REG_INT_STATUS 0x220
+#define HSDMA_REG_INT_MASK 0x228
+#define HSDMA_REG_SCH_Q01 0x280
+#define HSDMA_REG_SCH_Q23 0x284
+
+#define HSDMA_DESCS_MAX 0xfff
+#define HSDMA_DESCS_NUM 8
+#define HSDMA_DESCS_MASK (HSDMA_DESCS_NUM - 1)
+#define HSDMA_NEXT_DESC(x) (((x) + 1) & HSDMA_DESCS_MASK)
+
+/* HSDMA_REG_INFO */
+#define HSDMA_INFO_INDEX_MASK 0xf
+#define HSDMA_INFO_INDEX_SHIFT 24
+#define HSDMA_INFO_BASE_MASK 0xff
+#define HSDMA_INFO_BASE_SHIFT 16
+#define HSDMA_INFO_RX_MASK 0xff
+#define HSDMA_INFO_RX_SHIFT 8
+#define HSDMA_INFO_TX_MASK 0xff
+#define HSDMA_INFO_TX_SHIFT 0
+
+/* HSDMA_REG_GLO_CFG */
+#define HSDMA_GLO_TX_2B_OFFSET BIT(31)
+#define HSDMA_GLO_CLK_GATE BIT(30)
+#define HSDMA_GLO_BYTE_SWAP BIT(29)
+#define HSDMA_GLO_MULTI_DMA BIT(10)
+#define HSDMA_GLO_TWO_BUF BIT(9)
+#define HSDMA_GLO_32B_DESC BIT(8)
+#define HSDMA_GLO_BIG_ENDIAN BIT(7)
+#define HSDMA_GLO_TX_DONE BIT(6)
+#define HSDMA_GLO_BT_MASK 0x3
+#define HSDMA_GLO_BT_SHIFT 4
+#define HSDMA_GLO_RX_BUSY BIT(3)
+#define HSDMA_GLO_RX_DMA BIT(2)
+#define HSDMA_GLO_TX_BUSY BIT(1)
+#define HSDMA_GLO_TX_DMA BIT(0)
+
+#define HSDMA_BT_SIZE_16BYTES (0 << HSDMA_GLO_BT_SHIFT)
+#define HSDMA_BT_SIZE_32BYTES (1 << HSDMA_GLO_BT_SHIFT)
+#define HSDMA_BT_SIZE_64BYTES (2 << HSDMA_GLO_BT_SHIFT)
+#define HSDMA_BT_SIZE_128BYTES (3 << HSDMA_GLO_BT_SHIFT)
+
+#define HSDMA_GLO_DEFAULT (HSDMA_GLO_MULTI_DMA | \
+ HSDMA_GLO_RX_DMA | HSDMA_GLO_TX_DMA | HSDMA_BT_SIZE_32BYTES)
+
+/* HSDMA_REG_RST_CFG */
+#define HSDMA_RST_RX_SHIFT 16
+#define HSDMA_RST_TX_SHIFT 0
+
+/* HSDMA_REG_DELAY_INT */
+#define HSDMA_DELAY_INT_EN BIT(15)
+#define HSDMA_DELAY_PEND_OFFSET 8
+#define HSDMA_DELAY_TIME_OFFSET 0
+#define HSDMA_DELAY_TX_OFFSET 16
+#define HSDMA_DELAY_RX_OFFSET 0
+
+#define HSDMA_DELAY_INIT(x) (HSDMA_DELAY_INT_EN | \
+ ((x) << HSDMA_DELAY_PEND_OFFSET))
+#define HSDMA_DELAY(x) ((HSDMA_DELAY_INIT(x) << \
+ HSDMA_DELAY_TX_OFFSET) | HSDMA_DELAY_INIT(x))
+
+/* HSDMA_REG_INT_STATUS */
+#define HSDMA_INT_DELAY_RX_COH BIT(31)
+#define HSDMA_INT_DELAY_RX_INT BIT(30)
+#define HSDMA_INT_DELAY_TX_COH BIT(29)
+#define HSDMA_INT_DELAY_TX_INT BIT(28)
+#define HSDMA_INT_RX_MASK 0x3
+#define HSDMA_INT_RX_SHIFT 16
+#define HSDMA_INT_RX_Q0 BIT(16)
+#define HSDMA_INT_TX_MASK 0xf
+#define HSDMA_INT_TX_SHIFT 0
+#define HSDMA_INT_TX_Q0 BIT(0)
+
+/* tx/rx dma desc flags */
+#define HSDMA_PLEN_MASK 0x3fff
+#define HSDMA_DESC_DONE BIT(31)
+#define HSDMA_DESC_LS0 BIT(30)
+#define HSDMA_DESC_PLEN0(_x) (((_x) & HSDMA_PLEN_MASK) << 16)
+#define HSDMA_DESC_TAG BIT(15)
+#define HSDMA_DESC_LS1 BIT(14)
+#define HSDMA_DESC_PLEN1(_x) ((_x) & HSDMA_PLEN_MASK)
+
+/* align 4 bytes */
+#define HSDMA_ALIGN_SIZE 3
+/* align size 128bytes */
+#define HSDMA_MAX_PLEN 0x3f80
+
+struct hsdma_desc {
+ u32 addr0;
+ u32 flags;
+ u32 addr1;
+ u32 unused;
+};
+
+struct mtk_hsdma_sg {
+ dma_addr_t src_addr;
+ dma_addr_t dst_addr;
+ u32 len;
+};
+
+struct mtk_hsdma_desc {
+ struct virt_dma_desc vdesc;
+ unsigned int num_sgs;
+ struct mtk_hsdma_sg sg[1];
+};
+
+struct mtk_hsdma_chan {
+ struct virt_dma_chan vchan;
+ unsigned int id;
+ dma_addr_t desc_addr;
+ int tx_idx;
+ int rx_idx;
+ struct hsdma_desc *tx_ring;
+ struct hsdma_desc *rx_ring;
+ struct mtk_hsdma_desc *desc;
+ unsigned int next_sg;
+};
+
+struct mtk_hsdam_engine {
+ struct dma_device ddev;
+ struct device_dma_parameters dma_parms;
+ void __iomem *base;
+ struct tasklet_struct task;
+ volatile unsigned long chan_issued;
+
+ struct mtk_hsdma_chan chan[1];
+};
+
+static inline struct mtk_hsdam_engine *mtk_hsdma_chan_get_dev(
+ struct mtk_hsdma_chan *chan)
+{
+ return container_of(chan->vchan.chan.device, struct mtk_hsdam_engine,
+ ddev);
+}
+
+static inline struct mtk_hsdma_chan *to_mtk_hsdma_chan(struct dma_chan *c)
+{
+ return container_of(c, struct mtk_hsdma_chan, vchan.chan);
+}
+
+static inline struct mtk_hsdma_desc *to_mtk_hsdma_desc(
+ struct virt_dma_desc *vdesc)
+{
+ return container_of(vdesc, struct mtk_hsdma_desc, vdesc);
+}
+
+static inline u32 mtk_hsdma_read(struct mtk_hsdam_engine *hsdma, u32 reg)
+{
+ return readl(hsdma->base + reg);
+}
+
+static inline void mtk_hsdma_write(struct mtk_hsdam_engine *hsdma,
+ unsigned reg, u32 val)
+{
+ writel(val, hsdma->base + reg);
+}
+
+static void mtk_hsdma_reset_chan(struct mtk_hsdam_engine *hsdma,
+ struct mtk_hsdma_chan *chan)
+{
+ chan->tx_idx = 0;
+ chan->rx_idx = HSDMA_DESCS_NUM - 1;
+
+ mtk_hsdma_write(hsdma, HSDMA_REG_TX_CTX, chan->tx_idx);
+ mtk_hsdma_write(hsdma, HSDMA_REG_RX_CRX, chan->rx_idx);
+
+ mtk_hsdma_write(hsdma, HSDMA_REG_RST_CFG,
+ 0x1 << (chan->id + HSDMA_RST_TX_SHIFT));
+ mtk_hsdma_write(hsdma, HSDMA_REG_RST_CFG,
+ 0x1 << (chan->id + HSDMA_RST_RX_SHIFT));
+}
+
+static void hsdma_dump_reg(struct mtk_hsdam_engine *hsdma)
+{
+ dev_dbg(hsdma->ddev.dev, "tbase %08x, tcnt %08x, " \
+ "tctx %08x, tdtx: %08x, rbase %08x, " \
+ "rcnt %08x, rctx %08x, rdtx %08x\n",
+ mtk_hsdma_read(hsdma, HSDMA_REG_TX_BASE),
+ mtk_hsdma_read(hsdma, HSDMA_REG_TX_CNT),
+ mtk_hsdma_read(hsdma, HSDMA_REG_TX_CTX),
+ mtk_hsdma_read(hsdma, HSDMA_REG_TX_DTX),
+ mtk_hsdma_read(hsdma, HSDMA_REG_RX_BASE),
+ mtk_hsdma_read(hsdma, HSDMA_REG_RX_CNT),
+ mtk_hsdma_read(hsdma, HSDMA_REG_RX_CRX),
+ mtk_hsdma_read(hsdma, HSDMA_REG_RX_DRX));
+
+ dev_dbg(hsdma->ddev.dev, "info %08x, glo %08x, delay %08x, " \
+ "intr_stat %08x, intr_mask %08x\n",
+ mtk_hsdma_read(hsdma, HSDMA_REG_INFO),
+ mtk_hsdma_read(hsdma, HSDMA_REG_GLO_CFG),
+ mtk_hsdma_read(hsdma, HSDMA_REG_DELAY_INT),
+ mtk_hsdma_read(hsdma, HSDMA_REG_INT_STATUS),
+ mtk_hsdma_read(hsdma, HSDMA_REG_INT_MASK));
+}
+
+static void hsdma_dump_desc(struct mtk_hsdam_engine *hsdma,
+ struct mtk_hsdma_chan *chan)
+{
+ struct hsdma_desc *tx_desc;
+ struct hsdma_desc *rx_desc;
+ int i;
+
+ dev_dbg(hsdma->ddev.dev, "tx idx: %d, rx idx: %d\n",
+ chan->tx_idx, chan->rx_idx);
+
+ for (i = 0; i < HSDMA_DESCS_NUM; i++) {
+ tx_desc = &chan->tx_ring[i];
+ rx_desc = &chan->rx_ring[i];
+
+ dev_dbg(hsdma->ddev.dev, "%d tx addr0: %08x, flags %08x, " \
+ "tx addr1: %08x, rx addr0 %08x, flags %08x\n",
+ i, tx_desc->addr0, tx_desc->flags, \
+ tx_desc->addr1, rx_desc->addr0, rx_desc->flags);
+ }
+}
+
+static void mtk_hsdma_reset(struct mtk_hsdam_engine *hsdma,
+ struct mtk_hsdma_chan *chan)
+{
+ int i;
+
+ /* disable dma */
+ mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, 0);
+
+ /* disable intr */
+ mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, 0);
+
+ /* init desc value */
+ for (i = 0; i < HSDMA_DESCS_NUM; i++) {
+ chan->tx_ring[i].addr0 = 0;
+ chan->tx_ring[i].flags = HSDMA_DESC_LS0 |
+ HSDMA_DESC_DONE;
+ }
+ for (i = 0; i < HSDMA_DESCS_NUM; i++) {
+ chan->rx_ring[i].addr0 = 0;
+ chan->rx_ring[i].flags = 0;
+ }
+
+ /* reset */
+ mtk_hsdma_reset_chan(hsdma, chan);
+
+ /* enable intr */
+ mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, HSDMA_INT_RX_Q0);
+
+ /* enable dma */
+ mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, HSDMA_GLO_DEFAULT);
+}
+
+static int mtk_hsdma_terminate_all(struct dma_chan *c)
+{
+ struct mtk_hsdma_chan *chan = to_mtk_hsdma_chan(c);
+ struct mtk_hsdam_engine *hsdma = mtk_hsdma_chan_get_dev(chan);
+ unsigned long timeout;
+ LIST_HEAD(head);
+
+ spin_lock_bh(&chan->vchan.lock);
+ chan->desc = NULL;
+ clear_bit(chan->id, &hsdma->chan_issued);
+ vchan_get_all_descriptors(&chan->vchan, &head);
+ spin_unlock_bh(&chan->vchan.lock);
+
+ vchan_dma_desc_free_list(&chan->vchan, &head);
+
+ /* wait dma transfer complete */
+ timeout = jiffies + msecs_to_jiffies(2000);
+ while (mtk_hsdma_read(hsdma, HSDMA_REG_GLO_CFG) &
+ (HSDMA_GLO_RX_BUSY | HSDMA_GLO_TX_BUSY)) {
+ if (time_after_eq(jiffies, timeout)) {
+ hsdma_dump_desc(hsdma, chan);
+ mtk_hsdma_reset(hsdma, chan);
+ dev_err(hsdma->ddev.dev, "timeout, reset it\n");
+ break;
+ }
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static int mtk_hsdma_start_transfer(struct mtk_hsdam_engine *hsdma,
+ struct mtk_hsdma_chan *chan)
+{
+ dma_addr_t src, dst;
+ size_t len, tlen;
+ struct hsdma_desc *tx_desc, *rx_desc;
+ struct mtk_hsdma_sg *sg;
+ unsigned int i;
+ int rx_idx;
+
+ sg = &chan->desc->sg[0];
+ len = sg->len;
+ chan->desc->num_sgs = DIV_ROUND_UP(len, HSDMA_MAX_PLEN);
+
+ /* tx desc */
+ src = sg->src_addr;
+ for (i = 0; i < chan->desc->num_sgs; i++) {
+ if (len > HSDMA_MAX_PLEN)
+ tlen = HSDMA_MAX_PLEN;
+ else
+ tlen = len;
+
+ if (i & 0x1) {
+ tx_desc->addr1 = src;
+ tx_desc->flags |= HSDMA_DESC_PLEN1(tlen);
+ } else {
+ tx_desc = &chan->tx_ring[chan->tx_idx];
+ tx_desc->addr0 = src;
+ tx_desc->flags = HSDMA_DESC_PLEN0(tlen);
+
+ /* update index */
+ chan->tx_idx = HSDMA_NEXT_DESC(chan->tx_idx);
+ }
+
+ src += tlen;
+ len -= tlen;
+ }
+ if (i & 0x1)
+ tx_desc->flags |= HSDMA_DESC_LS0;
+ else
+ tx_desc->flags |= HSDMA_DESC_LS1;
+
+ /* rx desc */
+ rx_idx = HSDMA_NEXT_DESC(chan->rx_idx);
+ len = sg->len;
+ dst = sg->dst_addr;
+ for (i = 0; i < chan->desc->num_sgs; i++) {
+ rx_desc = &chan->rx_ring[rx_idx];
+ if (len > HSDMA_MAX_PLEN)
+ tlen = HSDMA_MAX_PLEN;
+ else
+ tlen = len;
+
+ rx_desc->addr0 = dst;
+ rx_desc->flags = HSDMA_DESC_PLEN0(tlen);
+
+ dst += tlen;
+ len -= tlen;
+
+ /* update index */
+ rx_idx = HSDMA_NEXT_DESC(rx_idx);
+ }
+
+ /* make sure desc and index all up to date */
+ wmb();
+ mtk_hsdma_write(hsdma, HSDMA_REG_TX_CTX, chan->tx_idx);
+
+ return 0;
+}
+
+static int gdma_next_desc(struct mtk_hsdma_chan *chan)
+{
+ struct virt_dma_desc *vdesc;
+
+ vdesc = vchan_next_desc(&chan->vchan);
+ if (!vdesc) {
+ chan->desc = NULL;
+ return 0;
+ }
+ chan->desc = to_mtk_hsdma_desc(vdesc);
+ chan->next_sg = 0;
+
+ return 1;
+}
+
+static void mtk_hsdma_chan_done(struct mtk_hsdam_engine *hsdma,
+ struct mtk_hsdma_chan *chan)
+{
+ struct mtk_hsdma_desc *desc;
+ int chan_issued;
+
+ chan_issued = 0;
+ spin_lock_bh(&chan->vchan.lock);
+ desc = chan->desc;
+ if (likely(desc)) {
+ if (chan->next_sg == desc->num_sgs) {
+ list_del(&desc->vdesc.node);
+ vchan_cookie_complete(&desc->vdesc);
+ chan_issued = gdma_next_desc(chan);
+ }
+ } else
+ dev_dbg(hsdma->ddev.dev, "no desc to complete\n");
+
+ if (chan_issued)
+ set_bit(chan->id, &hsdma->chan_issued);
+ spin_unlock_bh(&chan->vchan.lock);
+}
+
+static irqreturn_t mtk_hsdma_irq(int irq, void *devid)
+{
+ struct mtk_hsdam_engine *hsdma = devid;
+ u32 status;
+
+ status = mtk_hsdma_read(hsdma, HSDMA_REG_INT_STATUS);
+ if (unlikely(!status))
+ return IRQ_NONE;
+
+ if (likely(status & HSDMA_INT_RX_Q0))
+ tasklet_schedule(&hsdma->task);
+ else
+ dev_dbg(hsdma->ddev.dev, "unhandle irq status %08x\n",
+ status);
+ /* clean intr bits */
+ mtk_hsdma_write(hsdma, HSDMA_REG_INT_STATUS, status);
+
+ return IRQ_HANDLED;
+}
+
+static void mtk_hsdma_issue_pending(struct dma_chan *c)
+{
+ struct mtk_hsdma_chan *chan = to_mtk_hsdma_chan(c);
+ struct mtk_hsdam_engine *hsdma = mtk_hsdma_chan_get_dev(chan);
+
+ spin_lock_bh(&chan->vchan.lock);
+ if (vchan_issue_pending(&chan->vchan) && !chan->desc) {
+ if (gdma_next_desc(chan)) {
+ set_bit(chan->id, &hsdma->chan_issued);
+ tasklet_schedule(&hsdma->task);
+ } else
+ dev_dbg(hsdma->ddev.dev, "no desc to issue\n");
+ }
+ spin_unlock_bh(&chan->vchan.lock);
+}
+
+static struct dma_async_tx_descriptor *mtk_hsdma_prep_dma_memcpy(
+ struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
+ size_t len, unsigned long flags)
+{
+ struct mtk_hsdma_chan *chan = to_mtk_hsdma_chan(c);
+ struct mtk_hsdma_desc *desc;
+
+ if (len <= 0)
+ return NULL;
+
+ desc = kzalloc(sizeof(struct mtk_hsdma_desc), GFP_ATOMIC);
+ if (!desc) {
+ dev_err(c->device->dev, "alloc memcpy decs error\n");
+ return NULL;
+ }
+
+ desc->sg[0].src_addr = src;
+ desc->sg[0].dst_addr = dest;
+ desc->sg[0].len = len;
+
+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
+}
+
+static enum dma_status mtk_hsdma_tx_status(struct dma_chan *c,
+ dma_cookie_t cookie,
+ struct dma_tx_state *state)
+{
+ return dma_cookie_status(c, cookie, state);
+}
+
+static void mtk_hsdma_free_chan_resources(struct dma_chan *c)
+{
+ vchan_free_chan_resources(to_virt_chan(c));
+}
+
+static void mtk_hsdma_desc_free(struct virt_dma_desc *vdesc)
+{
+ kfree(container_of(vdesc, struct mtk_hsdma_desc, vdesc));
+}
+
+static void mtk_hsdma_tx(struct mtk_hsdam_engine *hsdma)
+{
+ struct mtk_hsdma_chan *chan;
+
+ if (test_and_clear_bit(0, &hsdma->chan_issued)) {
+ chan = &hsdma->chan[0];
+ if (chan->desc)
+ mtk_hsdma_start_transfer(hsdma, chan);
+ else
+ dev_dbg(hsdma->ddev.dev, "chan 0 no desc to issue\n");
+ }
+}
+
+static void mtk_hsdma_rx(struct mtk_hsdam_engine *hsdma)
+{
+ struct mtk_hsdma_chan *chan;
+ int next_idx, drx_idx, cnt;
+
+ chan = &hsdma->chan[0];
+ next_idx = HSDMA_NEXT_DESC(chan->rx_idx);
+ drx_idx = mtk_hsdma_read(hsdma, HSDMA_REG_RX_DRX);
+
+ cnt = (drx_idx - next_idx) & HSDMA_DESCS_MASK;
+ if (!cnt)
+ return;
+
+ chan->next_sg += cnt;
+ chan->rx_idx = (chan->rx_idx + cnt) & HSDMA_DESCS_MASK;
+
+ /* update rx crx */
+ wmb();
+ mtk_hsdma_write(hsdma, HSDMA_REG_RX_CRX, chan->rx_idx);
+
+ mtk_hsdma_chan_done(hsdma, chan);
+}
+
+static void mtk_hsdma_tasklet(unsigned long arg)
+{
+ struct mtk_hsdam_engine *hsdma = (struct mtk_hsdam_engine *)arg;
+
+ mtk_hsdma_rx(hsdma);
+ mtk_hsdma_tx(hsdma);
+}
+
+static int mtk_hsdam_alloc_desc(struct mtk_hsdam_engine *hsdma,
+ struct mtk_hsdma_chan *chan)
+{
+ int i;
+
+ chan->tx_ring = dma_alloc_coherent(hsdma->ddev.dev,
+ 2 * HSDMA_DESCS_NUM * sizeof(*chan->tx_ring),
+ &chan->desc_addr, GFP_ATOMIC | __GFP_ZERO);
+ if (!chan->tx_ring)
+ goto no_mem;
+
+ chan->rx_ring = &chan->tx_ring[HSDMA_DESCS_NUM];
+
+ /* init tx ring value */
+ for (i = 0; i < HSDMA_DESCS_NUM; i++)
+ chan->tx_ring[i].flags = HSDMA_DESC_LS0 | HSDMA_DESC_DONE;
+
+ return 0;
+no_mem:
+ return -ENOMEM;
+}
+
+static void mtk_hsdam_free_desc(struct mtk_hsdam_engine *hsdma,
+ struct mtk_hsdma_chan *chan)
+{
+ if (chan->tx_ring) {
+ dma_free_coherent(hsdma->ddev.dev,
+ 2 * HSDMA_DESCS_NUM * sizeof(*chan->tx_ring),
+ chan->tx_ring, chan->desc_addr);
+ chan->tx_ring = NULL;
+ chan->rx_ring = NULL;
+ }
+}
+
+static int mtk_hsdma_init(struct mtk_hsdam_engine *hsdma)
+{
+ struct mtk_hsdma_chan *chan;
+ int ret;
+ u32 reg;
+
+ /* init desc */
+ chan = &hsdma->chan[0];
+ ret = mtk_hsdam_alloc_desc(hsdma, chan);
+ if (ret)
+ return ret;
+
+ /* tx */
+ mtk_hsdma_write(hsdma, HSDMA_REG_TX_BASE, chan->desc_addr);
+ mtk_hsdma_write(hsdma, HSDMA_REG_TX_CNT, HSDMA_DESCS_NUM);
+ /* rx */
+ mtk_hsdma_write(hsdma, HSDMA_REG_RX_BASE, chan->desc_addr +
+ (sizeof(struct hsdma_desc) * HSDMA_DESCS_NUM));
+ mtk_hsdma_write(hsdma, HSDMA_REG_RX_CNT, HSDMA_DESCS_NUM);
+ /* reset */
+ mtk_hsdma_reset_chan(hsdma, chan);
+
+ /* enable rx intr */
+ mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, HSDMA_INT_RX_Q0);
+
+ /* enable dma */
+ mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, HSDMA_GLO_DEFAULT);
+
+ /* hardware info */
+ reg = mtk_hsdma_read(hsdma, HSDMA_REG_INFO);
+ dev_info(hsdma->ddev.dev, "rx: %d, tx: %d\n",
+ (reg >> HSDMA_INFO_RX_SHIFT) & HSDMA_INFO_RX_MASK,
+ (reg >> HSDMA_INFO_TX_SHIFT) & HSDMA_INFO_TX_MASK);
+
+ hsdma_dump_reg(hsdma);
+
+ return ret;
+}
+
+static void mtk_hsdma_uninit(struct mtk_hsdam_engine *hsdma)
+{
+ struct mtk_hsdma_chan *chan;
+
+ /* disable dma */
+ mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, 0);
+
+ /* disable intr */
+ mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, 0);
+
+ /* free desc */
+ chan = &hsdma->chan[0];
+ mtk_hsdam_free_desc(hsdma, chan);
+
+ /* tx */
+ mtk_hsdma_write(hsdma, HSDMA_REG_TX_BASE, 0);
+ mtk_hsdma_write(hsdma, HSDMA_REG_TX_CNT, 0);
+ /* rx */
+ mtk_hsdma_write(hsdma, HSDMA_REG_RX_BASE, 0);
+ mtk_hsdma_write(hsdma, HSDMA_REG_RX_CNT, 0);
+ /* reset */
+ mtk_hsdma_reset_chan(hsdma, chan);
+}
+
+static const struct of_device_id mtk_hsdma_of_match[] = {
+ { .compatible = "mediatek,mt7621-hsdma" },
+ { },
+};
+
+static int mtk_hsdma_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct mtk_hsdma_chan *chan;
+ struct mtk_hsdam_engine *hsdma;
+ struct dma_device *dd;
+ struct resource *res;
+ int ret;
+ int irq;
+ void __iomem *base;
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ match = of_match_device(mtk_hsdma_of_match, &pdev->dev);
+ if (!match)
+ return -EINVAL;
+
+ hsdma = devm_kzalloc(&pdev->dev, sizeof(*hsdma), GFP_KERNEL);
+ if (!hsdma) {
+ dev_err(&pdev->dev, "alloc dma device failed\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+ hsdma->base = base + HSDMA_BASE_OFFSET;
+ tasklet_init(&hsdma->task, mtk_hsdma_tasklet, (unsigned long)hsdma);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq\n");
+ return -EINVAL;
+ }
+ ret = devm_request_irq(&pdev->dev, irq, mtk_hsdma_irq,
+ 0, dev_name(&pdev->dev), hsdma);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request irq\n");
+ return ret;
+ }
+
+ device_reset(&pdev->dev);
+
+ dd = &hsdma->ddev;
+ dma_cap_set(DMA_MEMCPY, dd->cap_mask);
+ dd->copy_align = HSDMA_ALIGN_SIZE;
+ dd->device_free_chan_resources = mtk_hsdma_free_chan_resources;
+ dd->device_prep_dma_memcpy = mtk_hsdma_prep_dma_memcpy;
+ dd->device_terminate_all = mtk_hsdma_terminate_all;
+ dd->device_tx_status = mtk_hsdma_tx_status;
+ dd->device_issue_pending = mtk_hsdma_issue_pending;
+ dd->dev = &pdev->dev;
+ dd->dev->dma_parms = &hsdma->dma_parms;
+ dma_set_max_seg_size(dd->dev, HSDMA_MAX_PLEN);
+ INIT_LIST_HEAD(&dd->channels);
+
+ chan = &hsdma->chan[0];
+ chan->id = 0;
+ chan->vchan.desc_free = mtk_hsdma_desc_free;
+ vchan_init(&chan->vchan, dd);
+
+ /* init hardware */
+ ret = mtk_hsdma_init(hsdma);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to alloc ring descs\n");
+ return ret;
+ }
+
+ ret = dma_async_device_register(dd);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register dma device\n");
+ return ret;
+ }
+
+ ret = of_dma_controller_register(pdev->dev.of_node,
+ of_dma_xlate_by_chan_id, hsdma);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register of dma controller\n");
+ goto err_unregister;
+ }
+
+ platform_set_drvdata(pdev, hsdma);
+
+ return 0;
+
+err_unregister:
+ dma_async_device_unregister(dd);
+ return ret;
+}
+
+static int mtk_hsdma_remove(struct platform_device *pdev)
+{
+ struct mtk_hsdam_engine *hsdma = platform_get_drvdata(pdev);
+
+ mtk_hsdma_uninit(hsdma);
+
+ of_dma_controller_free(pdev->dev.of_node);
+ dma_async_device_unregister(&hsdma->ddev);
+
+ return 0;
+}
+
+static struct platform_driver mtk_hsdma_driver = {
+ .probe = mtk_hsdma_probe,
+ .remove = mtk_hsdma_remove,
+ .driver = {
+ .name = "hsdma-mt7621",
+ .of_match_table = mtk_hsdma_of_match,
+ },
+};
+module_platform_driver(mtk_hsdma_driver);
+
+MODULE_AUTHOR("Michael Lee <igvtee@gmail.com>");
+MODULE_DESCRIPTION("MTK HSDMA driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/mt7621-dma/ralink-gdma.c b/drivers/staging/mt7621-dma/ralink-gdma.c
new file mode 100644
index 000000000000..6d9fe175ea52
--- /dev/null
+++ b/drivers/staging/mt7621-dma/ralink-gdma.c
@@ -0,0 +1,930 @@
+/*
+ * Copyright (C) 2013, Lars-Peter Clausen <lars@metafoo.de>
+ * GDMA4740 DMAC support
+ *
+ * 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/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/irq.h>
+#include <linux/of_dma.h>
+#include <linux/reset.h>
+#include <linux/of_device.h>
+
+#include "virt-dma.h"
+
+#define GDMA_REG_SRC_ADDR(x) (0x00 + (x) * 0x10)
+#define GDMA_REG_DST_ADDR(x) (0x04 + (x) * 0x10)
+
+#define GDMA_REG_CTRL0(x) (0x08 + (x) * 0x10)
+#define GDMA_REG_CTRL0_TX_MASK 0xffff
+#define GDMA_REG_CTRL0_TX_SHIFT 16
+#define GDMA_REG_CTRL0_CURR_MASK 0xff
+#define GDMA_REG_CTRL0_CURR_SHIFT 8
+#define GDMA_REG_CTRL0_SRC_ADDR_FIXED BIT(7)
+#define GDMA_REG_CTRL0_DST_ADDR_FIXED BIT(6)
+#define GDMA_REG_CTRL0_BURST_MASK 0x7
+#define GDMA_REG_CTRL0_BURST_SHIFT 3
+#define GDMA_REG_CTRL0_DONE_INT BIT(2)
+#define GDMA_REG_CTRL0_ENABLE BIT(1)
+#define GDMA_REG_CTRL0_SW_MODE BIT(0)
+
+#define GDMA_REG_CTRL1(x) (0x0c + (x) * 0x10)
+#define GDMA_REG_CTRL1_SEG_MASK 0xf
+#define GDMA_REG_CTRL1_SEG_SHIFT 22
+#define GDMA_REG_CTRL1_REQ_MASK 0x3f
+#define GDMA_REG_CTRL1_SRC_REQ_SHIFT 16
+#define GDMA_REG_CTRL1_DST_REQ_SHIFT 8
+#define GDMA_REG_CTRL1_CONTINOUS BIT(14)
+#define GDMA_REG_CTRL1_NEXT_MASK 0x1f
+#define GDMA_REG_CTRL1_NEXT_SHIFT 3
+#define GDMA_REG_CTRL1_COHERENT BIT(2)
+#define GDMA_REG_CTRL1_FAIL BIT(1)
+#define GDMA_REG_CTRL1_MASK BIT(0)
+
+#define GDMA_REG_UNMASK_INT 0x200
+#define GDMA_REG_DONE_INT 0x204
+
+#define GDMA_REG_GCT 0x220
+#define GDMA_REG_GCT_CHAN_MASK 0x3
+#define GDMA_REG_GCT_CHAN_SHIFT 3
+#define GDMA_REG_GCT_VER_MASK 0x3
+#define GDMA_REG_GCT_VER_SHIFT 1
+#define GDMA_REG_GCT_ARBIT_RR BIT(0)
+
+#define GDMA_REG_REQSTS 0x2a0
+#define GDMA_REG_ACKSTS 0x2a4
+#define GDMA_REG_FINSTS 0x2a8
+
+/* for RT305X gdma registers */
+#define GDMA_RT305X_CTRL0_REQ_MASK 0xf
+#define GDMA_RT305X_CTRL0_SRC_REQ_SHIFT 12
+#define GDMA_RT305X_CTRL0_DST_REQ_SHIFT 8
+
+#define GDMA_RT305X_CTRL1_FAIL BIT(4)
+#define GDMA_RT305X_CTRL1_NEXT_MASK 0x7
+#define GDMA_RT305X_CTRL1_NEXT_SHIFT 1
+
+#define GDMA_RT305X_STATUS_INT 0x80
+#define GDMA_RT305X_STATUS_SIGNAL 0x84
+#define GDMA_RT305X_GCT 0x88
+
+/* for MT7621 gdma registers */
+#define GDMA_REG_PERF_START(x) (0x230 + (x) * 0x8)
+#define GDMA_REG_PERF_END(x) (0x234 + (x) * 0x8)
+
+enum gdma_dma_transfer_size {
+ GDMA_TRANSFER_SIZE_4BYTE = 0,
+ GDMA_TRANSFER_SIZE_8BYTE = 1,
+ GDMA_TRANSFER_SIZE_16BYTE = 2,
+ GDMA_TRANSFER_SIZE_32BYTE = 3,
+ GDMA_TRANSFER_SIZE_64BYTE = 4,
+};
+
+struct gdma_dma_sg {
+ dma_addr_t src_addr;
+ dma_addr_t dst_addr;
+ u32 len;
+};
+
+struct gdma_dma_desc {
+ struct virt_dma_desc vdesc;
+
+ enum dma_transfer_direction direction;
+ bool cyclic;
+
+ u32 residue;
+ unsigned int num_sgs;
+ struct gdma_dma_sg sg[];
+};
+
+struct gdma_dmaengine_chan {
+ struct virt_dma_chan vchan;
+ unsigned int id;
+ unsigned int slave_id;
+
+ dma_addr_t fifo_addr;
+ enum gdma_dma_transfer_size burst_size;
+
+ struct gdma_dma_desc *desc;
+ unsigned int next_sg;
+};
+
+struct gdma_dma_dev {
+ struct dma_device ddev;
+ struct device_dma_parameters dma_parms;
+ struct gdma_data *data;
+ void __iomem *base;
+ struct tasklet_struct task;
+ volatile unsigned long chan_issued;
+ atomic_t cnt;
+
+ struct gdma_dmaengine_chan chan[];
+};
+
+struct gdma_data {
+ int chancnt;
+ u32 done_int_reg;
+ void (*init)(struct gdma_dma_dev *dma_dev);
+ int (*start_transfer)(struct gdma_dmaengine_chan *chan);
+};
+
+static struct gdma_dma_dev *gdma_dma_chan_get_dev(
+ struct gdma_dmaengine_chan *chan)
+{
+ return container_of(chan->vchan.chan.device, struct gdma_dma_dev,
+ ddev);
+}
+
+static struct gdma_dmaengine_chan *to_gdma_dma_chan(struct dma_chan *c)
+{
+ return container_of(c, struct gdma_dmaengine_chan, vchan.chan);
+}
+
+static struct gdma_dma_desc *to_gdma_dma_desc(struct virt_dma_desc *vdesc)
+{
+ return container_of(vdesc, struct gdma_dma_desc, vdesc);
+}
+
+static inline uint32_t gdma_dma_read(struct gdma_dma_dev *dma_dev,
+ unsigned int reg)
+{
+ return readl(dma_dev->base + reg);
+}
+
+static inline void gdma_dma_write(struct gdma_dma_dev *dma_dev,
+ unsigned reg, uint32_t val)
+{
+ writel(val, dma_dev->base + reg);
+}
+
+static struct gdma_dma_desc *gdma_dma_alloc_desc(unsigned int num_sgs)
+{
+ return kzalloc(sizeof(struct gdma_dma_desc) +
+ sizeof(struct gdma_dma_sg) * num_sgs, GFP_ATOMIC);
+}
+
+static enum gdma_dma_transfer_size gdma_dma_maxburst(u32 maxburst)
+{
+ if (maxburst < 2)
+ return GDMA_TRANSFER_SIZE_4BYTE;
+ else if (maxburst < 4)
+ return GDMA_TRANSFER_SIZE_8BYTE;
+ else if (maxburst < 8)
+ return GDMA_TRANSFER_SIZE_16BYTE;
+ else if (maxburst < 16)
+ return GDMA_TRANSFER_SIZE_32BYTE;
+ else
+ return GDMA_TRANSFER_SIZE_64BYTE;
+}
+
+static int gdma_dma_config(struct dma_chan *c,
+ struct dma_slave_config *config)
+{
+ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c);
+ struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan);
+
+ if (config->device_fc) {
+ dev_err(dma_dev->ddev.dev, "not support flow controller\n");
+ return -EINVAL;
+ }
+
+ switch (config->direction) {
+ case DMA_MEM_TO_DEV:
+ if (config->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) {
+ dev_err(dma_dev->ddev.dev, "only support 4 byte buswidth\n");
+ return -EINVAL;
+ }
+ chan->slave_id = config->slave_id;
+ chan->fifo_addr = config->dst_addr;
+ chan->burst_size = gdma_dma_maxburst(config->dst_maxburst);
+ break;
+ case DMA_DEV_TO_MEM:
+ if (config->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) {
+ dev_err(dma_dev->ddev.dev, "only support 4 byte buswidth\n");
+ return -EINVAL;
+ }
+ chan->slave_id = config->slave_id;
+ chan->fifo_addr = config->src_addr;
+ chan->burst_size = gdma_dma_maxburst(config->src_maxburst);
+ break;
+ default:
+ dev_err(dma_dev->ddev.dev, "direction type %d error\n",
+ config->direction);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int gdma_dma_terminate_all(struct dma_chan *c)
+{
+ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c);
+ struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan);
+ unsigned long flags, timeout;
+ LIST_HEAD(head);
+ int i = 0;
+
+ spin_lock_irqsave(&chan->vchan.lock, flags);
+ chan->desc = NULL;
+ clear_bit(chan->id, &dma_dev->chan_issued);
+ vchan_get_all_descriptors(&chan->vchan, &head);
+ spin_unlock_irqrestore(&chan->vchan.lock, flags);
+
+ vchan_dma_desc_free_list(&chan->vchan, &head);
+
+ /* wait dma transfer complete */
+ timeout = jiffies + msecs_to_jiffies(5000);
+ while (gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)) &
+ GDMA_REG_CTRL0_ENABLE) {
+ if (time_after_eq(jiffies, timeout)) {
+ dev_err(dma_dev->ddev.dev, "chan %d wait timeout\n",
+ chan->id);
+ /* restore to init value */
+ gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), 0);
+ break;
+ }
+ cpu_relax();
+ i++;
+ }
+
+ if (i)
+ dev_dbg(dma_dev->ddev.dev, "terminate chan %d loops %d\n",
+ chan->id, i);
+
+ return 0;
+}
+
+static void rt305x_dump_reg(struct gdma_dma_dev *dma_dev, int id)
+{
+ dev_dbg(dma_dev->ddev.dev, "chan %d, src %08x, dst %08x, ctr0 %08x, " \
+ "ctr1 %08x, intr %08x, signal %08x\n", id,
+ gdma_dma_read(dma_dev, GDMA_REG_SRC_ADDR(id)),
+ gdma_dma_read(dma_dev, GDMA_REG_DST_ADDR(id)),
+ gdma_dma_read(dma_dev, GDMA_REG_CTRL0(id)),
+ gdma_dma_read(dma_dev, GDMA_REG_CTRL1(id)),
+ gdma_dma_read(dma_dev, GDMA_RT305X_STATUS_INT),
+ gdma_dma_read(dma_dev, GDMA_RT305X_STATUS_SIGNAL));
+}
+
+static int rt305x_gdma_start_transfer(struct gdma_dmaengine_chan *chan)
+{
+ struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan);
+ dma_addr_t src_addr, dst_addr;
+ struct gdma_dma_sg *sg;
+ uint32_t ctrl0, ctrl1;
+
+ /* verify chan is already stopped */
+ ctrl0 = gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id));
+ if (unlikely(ctrl0 & GDMA_REG_CTRL0_ENABLE)) {
+ dev_err(dma_dev->ddev.dev, "chan %d is start(%08x).\n",
+ chan->id, ctrl0);
+ rt305x_dump_reg(dma_dev, chan->id);
+ return -EINVAL;
+ }
+
+ sg = &chan->desc->sg[chan->next_sg];
+ if (chan->desc->direction == DMA_MEM_TO_DEV) {
+ src_addr = sg->src_addr;
+ dst_addr = chan->fifo_addr;
+ ctrl0 = GDMA_REG_CTRL0_DST_ADDR_FIXED | \
+ (8 << GDMA_RT305X_CTRL0_SRC_REQ_SHIFT) | \
+ (chan->slave_id << GDMA_RT305X_CTRL0_DST_REQ_SHIFT);
+ } else if (chan->desc->direction == DMA_DEV_TO_MEM) {
+ src_addr = chan->fifo_addr;
+ dst_addr = sg->dst_addr;
+ ctrl0 = GDMA_REG_CTRL0_SRC_ADDR_FIXED | \
+ (chan->slave_id << GDMA_RT305X_CTRL0_SRC_REQ_SHIFT) | \
+ (8 << GDMA_RT305X_CTRL0_DST_REQ_SHIFT);
+ } else if (chan->desc->direction == DMA_MEM_TO_MEM) {
+ /*
+ * TODO: memcpy function have bugs. sometime it will copy
+ * more 8 bytes data when using dmatest verify.
+ */
+ src_addr = sg->src_addr;
+ dst_addr = sg->dst_addr;
+ ctrl0 = GDMA_REG_CTRL0_SW_MODE | \
+ (8 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \
+ (8 << GDMA_REG_CTRL1_DST_REQ_SHIFT);
+ } else {
+ dev_err(dma_dev->ddev.dev, "direction type %d error\n",
+ chan->desc->direction);
+ return -EINVAL;
+ }
+
+ ctrl0 |= (sg->len << GDMA_REG_CTRL0_TX_SHIFT) | \
+ (chan->burst_size << GDMA_REG_CTRL0_BURST_SHIFT) | \
+ GDMA_REG_CTRL0_DONE_INT | GDMA_REG_CTRL0_ENABLE;
+ ctrl1 = chan->id << GDMA_REG_CTRL1_NEXT_SHIFT;
+
+ chan->next_sg++;
+ gdma_dma_write(dma_dev, GDMA_REG_SRC_ADDR(chan->id), src_addr);
+ gdma_dma_write(dma_dev, GDMA_REG_DST_ADDR(chan->id), dst_addr);
+ gdma_dma_write(dma_dev, GDMA_REG_CTRL1(chan->id), ctrl1);
+
+ /* make sure next_sg is update */
+ wmb();
+ gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), ctrl0);
+
+ return 0;
+}
+
+static void rt3883_dump_reg(struct gdma_dma_dev *dma_dev, int id)
+{
+ dev_dbg(dma_dev->ddev.dev, "chan %d, src %08x, dst %08x, ctr0 %08x, " \
+ "ctr1 %08x, unmask %08x, done %08x, " \
+ "req %08x, ack %08x, fin %08x\n", id,
+ gdma_dma_read(dma_dev, GDMA_REG_SRC_ADDR(id)),
+ gdma_dma_read(dma_dev, GDMA_REG_DST_ADDR(id)),
+ gdma_dma_read(dma_dev, GDMA_REG_CTRL0(id)),
+ gdma_dma_read(dma_dev, GDMA_REG_CTRL1(id)),
+ gdma_dma_read(dma_dev, GDMA_REG_UNMASK_INT),
+ gdma_dma_read(dma_dev, GDMA_REG_DONE_INT),
+ gdma_dma_read(dma_dev, GDMA_REG_REQSTS),
+ gdma_dma_read(dma_dev, GDMA_REG_ACKSTS),
+ gdma_dma_read(dma_dev, GDMA_REG_FINSTS));
+}
+
+static int rt3883_gdma_start_transfer(struct gdma_dmaengine_chan *chan)
+{
+ struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan);
+ dma_addr_t src_addr, dst_addr;
+ struct gdma_dma_sg *sg;
+ uint32_t ctrl0, ctrl1;
+
+ /* verify chan is already stopped */
+ ctrl0 = gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id));
+ if (unlikely(ctrl0 & GDMA_REG_CTRL0_ENABLE)) {
+ dev_err(dma_dev->ddev.dev, "chan %d is start(%08x).\n",
+ chan->id, ctrl0);
+ rt3883_dump_reg(dma_dev, chan->id);
+ return -EINVAL;
+ }
+
+ sg = &chan->desc->sg[chan->next_sg];
+ if (chan->desc->direction == DMA_MEM_TO_DEV) {
+ src_addr = sg->src_addr;
+ dst_addr = chan->fifo_addr;
+ ctrl0 = GDMA_REG_CTRL0_DST_ADDR_FIXED;
+ ctrl1 = (32 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \
+ (chan->slave_id << GDMA_REG_CTRL1_DST_REQ_SHIFT);
+ } else if (chan->desc->direction == DMA_DEV_TO_MEM) {
+ src_addr = chan->fifo_addr;
+ dst_addr = sg->dst_addr;
+ ctrl0 = GDMA_REG_CTRL0_SRC_ADDR_FIXED;
+ ctrl1 = (chan->slave_id << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \
+ (32 << GDMA_REG_CTRL1_DST_REQ_SHIFT) | \
+ GDMA_REG_CTRL1_COHERENT;
+ } else if (chan->desc->direction == DMA_MEM_TO_MEM) {
+ src_addr = sg->src_addr;
+ dst_addr = sg->dst_addr;
+ ctrl0 = GDMA_REG_CTRL0_SW_MODE;
+ ctrl1 = (32 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \
+ (32 << GDMA_REG_CTRL1_DST_REQ_SHIFT) | \
+ GDMA_REG_CTRL1_COHERENT;
+ } else {
+ dev_err(dma_dev->ddev.dev, "direction type %d error\n",
+ chan->desc->direction);
+ return -EINVAL;
+ }
+
+ ctrl0 |= (sg->len << GDMA_REG_CTRL0_TX_SHIFT) | \
+ (chan->burst_size << GDMA_REG_CTRL0_BURST_SHIFT) | \
+ GDMA_REG_CTRL0_DONE_INT | GDMA_REG_CTRL0_ENABLE;
+ ctrl1 |= chan->id << GDMA_REG_CTRL1_NEXT_SHIFT;
+
+ chan->next_sg++;
+ gdma_dma_write(dma_dev, GDMA_REG_SRC_ADDR(chan->id), src_addr);
+ gdma_dma_write(dma_dev, GDMA_REG_DST_ADDR(chan->id), dst_addr);
+ gdma_dma_write(dma_dev, GDMA_REG_CTRL1(chan->id), ctrl1);
+
+ /* make sure next_sg is update */
+ wmb();
+ gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), ctrl0);
+
+ return 0;
+}
+
+static inline int gdma_start_transfer(struct gdma_dma_dev *dma_dev,
+ struct gdma_dmaengine_chan *chan)
+{
+ return dma_dev->data->start_transfer(chan);
+}
+
+static int gdma_next_desc(struct gdma_dmaengine_chan *chan)
+{
+ struct virt_dma_desc *vdesc;
+
+ vdesc = vchan_next_desc(&chan->vchan);
+ if (!vdesc) {
+ chan->desc = NULL;
+ return 0;
+ }
+ chan->desc = to_gdma_dma_desc(vdesc);
+ chan->next_sg = 0;
+
+ return 1;
+}
+
+static void gdma_dma_chan_irq(struct gdma_dma_dev *dma_dev,
+ struct gdma_dmaengine_chan *chan)
+{
+ struct gdma_dma_desc *desc;
+ unsigned long flags;
+ int chan_issued;
+
+ chan_issued = 0;
+ spin_lock_irqsave(&chan->vchan.lock, flags);
+ desc = chan->desc;
+ if (desc) {
+ if (desc->cyclic) {
+ vchan_cyclic_callback(&desc->vdesc);
+ if (chan->next_sg == desc->num_sgs)
+ chan->next_sg = 0;
+ chan_issued = 1;
+ } else {
+ desc->residue -= desc->sg[chan->next_sg - 1].len;
+ if (chan->next_sg == desc->num_sgs) {
+ list_del(&desc->vdesc.node);
+ vchan_cookie_complete(&desc->vdesc);
+ chan_issued = gdma_next_desc(chan);
+ } else
+ chan_issued = 1;
+ }
+ } else
+ dev_dbg(dma_dev->ddev.dev, "chan %d no desc to complete\n",
+ chan->id);
+ if (chan_issued)
+ set_bit(chan->id, &dma_dev->chan_issued);
+ spin_unlock_irqrestore(&chan->vchan.lock, flags);
+}
+
+static irqreturn_t gdma_dma_irq(int irq, void *devid)
+{
+ struct gdma_dma_dev *dma_dev = devid;
+ u32 done, done_reg;
+ unsigned int i;
+
+ done_reg = dma_dev->data->done_int_reg;
+ done = gdma_dma_read(dma_dev, done_reg);
+ if (unlikely(!done))
+ return IRQ_NONE;
+
+ /* clean done bits */
+ gdma_dma_write(dma_dev, done_reg, done);
+
+ i = 0;
+ while (done) {
+ if (done & 0x1) {
+ gdma_dma_chan_irq(dma_dev, &dma_dev->chan[i]);
+ atomic_dec(&dma_dev->cnt);
+ }
+ done >>= 1;
+ i++;
+ }
+
+ /* start only have work to do */
+ if (dma_dev->chan_issued)
+ tasklet_schedule(&dma_dev->task);
+
+ return IRQ_HANDLED;
+}
+
+static void gdma_dma_issue_pending(struct dma_chan *c)
+{
+ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c);
+ struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->vchan.lock, flags);
+ if (vchan_issue_pending(&chan->vchan) && !chan->desc) {
+ if (gdma_next_desc(chan)) {
+ set_bit(chan->id, &dma_dev->chan_issued);
+ tasklet_schedule(&dma_dev->task);
+ } else
+ dev_dbg(dma_dev->ddev.dev, "chan %d no desc to issue\n",
+ chan->id);
+ }
+ spin_unlock_irqrestore(&chan->vchan.lock, flags);
+}
+
+static struct dma_async_tx_descriptor *gdma_dma_prep_slave_sg(
+ struct dma_chan *c, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c);
+ struct gdma_dma_desc *desc;
+ struct scatterlist *sg;
+ unsigned int i;
+
+ desc = gdma_dma_alloc_desc(sg_len);
+ if (!desc) {
+ dev_err(c->device->dev, "alloc sg decs error\n");
+ return NULL;
+ }
+ desc->residue = 0;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ if (direction == DMA_MEM_TO_DEV)
+ desc->sg[i].src_addr = sg_dma_address(sg);
+ else if (direction == DMA_DEV_TO_MEM)
+ desc->sg[i].dst_addr = sg_dma_address(sg);
+ else {
+ dev_err(c->device->dev, "direction type %d error\n",
+ direction);
+ goto free_desc;
+ }
+
+ if (unlikely(sg_dma_len(sg) > GDMA_REG_CTRL0_TX_MASK)) {
+ dev_err(c->device->dev, "sg len too large %d\n",
+ sg_dma_len(sg));
+ goto free_desc;
+ }
+ desc->sg[i].len = sg_dma_len(sg);
+ desc->residue += sg_dma_len(sg);
+ }
+
+ desc->num_sgs = sg_len;
+ desc->direction = direction;
+ desc->cyclic = false;
+
+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
+
+free_desc:
+ kfree(desc);
+ return NULL;
+}
+
+static struct dma_async_tx_descriptor *gdma_dma_prep_dma_memcpy(
+ struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
+ size_t len, unsigned long flags)
+{
+ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c);
+ struct gdma_dma_desc *desc;
+ unsigned int num_periods, i;
+ size_t xfer_count;
+
+ if (len <= 0)
+ return NULL;
+
+ chan->burst_size = gdma_dma_maxburst(len >> 2);
+
+ xfer_count = GDMA_REG_CTRL0_TX_MASK;
+ num_periods = DIV_ROUND_UP(len, xfer_count);
+
+ desc = gdma_dma_alloc_desc(num_periods);
+ if (!desc) {
+ dev_err(c->device->dev, "alloc memcpy decs error\n");
+ return NULL;
+ }
+ desc->residue = len;
+
+ for (i = 0; i < num_periods; i++) {
+ desc->sg[i].src_addr = src;
+ desc->sg[i].dst_addr = dest;
+ if (len > xfer_count)
+ desc->sg[i].len = xfer_count;
+ else
+ desc->sg[i].len = len;
+ src += desc->sg[i].len;
+ dest += desc->sg[i].len;
+ len -= desc->sg[i].len;
+ }
+
+ desc->num_sgs = num_periods;
+ desc->direction = DMA_MEM_TO_MEM;
+ desc->cyclic = false;
+
+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
+}
+
+static struct dma_async_tx_descriptor *gdma_dma_prep_dma_cyclic(
+ struct dma_chan *c, dma_addr_t buf_addr, size_t buf_len,
+ size_t period_len, enum dma_transfer_direction direction,
+ unsigned long flags)
+{
+ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c);
+ struct gdma_dma_desc *desc;
+ unsigned int num_periods, i;
+
+ if (buf_len % period_len)
+ return NULL;
+
+ if (period_len > GDMA_REG_CTRL0_TX_MASK) {
+ dev_err(c->device->dev, "cyclic len too large %d\n",
+ period_len);
+ return NULL;
+ }
+
+ num_periods = buf_len / period_len;
+ desc = gdma_dma_alloc_desc(num_periods);
+ if (!desc) {
+ dev_err(c->device->dev, "alloc cyclic decs error\n");
+ return NULL;
+ }
+ desc->residue = buf_len;
+
+ for (i = 0; i < num_periods; i++) {
+ if (direction == DMA_MEM_TO_DEV)
+ desc->sg[i].src_addr = buf_addr;
+ else if (direction == DMA_DEV_TO_MEM)
+ desc->sg[i].dst_addr = buf_addr;
+ else {
+ dev_err(c->device->dev, "direction type %d error\n",
+ direction);
+ goto free_desc;
+ }
+ desc->sg[i].len = period_len;
+ buf_addr += period_len;
+ }
+
+ desc->num_sgs = num_periods;
+ desc->direction = direction;
+ desc->cyclic = true;
+
+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
+
+free_desc:
+ kfree(desc);
+ return NULL;
+}
+
+static enum dma_status gdma_dma_tx_status(struct dma_chan *c,
+ dma_cookie_t cookie,
+ struct dma_tx_state *state)
+{
+ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c);
+ struct virt_dma_desc *vdesc;
+ enum dma_status status;
+ unsigned long flags;
+ struct gdma_dma_desc *desc;
+
+ status = dma_cookie_status(c, cookie, state);
+ if (status == DMA_COMPLETE || !state)
+ return status;
+
+ spin_lock_irqsave(&chan->vchan.lock, flags);
+ desc = chan->desc;
+ if (desc && (cookie == desc->vdesc.tx.cookie)) {
+ /*
+ * We never update edesc->residue in the cyclic case, so we
+ * can tell the remaining room to the end of the circular
+ * buffer.
+ */
+ if (desc->cyclic)
+ state->residue = desc->residue -
+ ((chan->next_sg - 1) * desc->sg[0].len);
+ else
+ state->residue = desc->residue;
+ } else {
+ vdesc = vchan_find_desc(&chan->vchan, cookie);
+ if (vdesc)
+ state->residue = to_gdma_dma_desc(vdesc)->residue;
+ }
+ spin_unlock_irqrestore(&chan->vchan.lock, flags);
+
+ dev_dbg(c->device->dev, "tx residue %d bytes\n", state->residue);
+
+ return status;
+}
+
+static void gdma_dma_free_chan_resources(struct dma_chan *c)
+{
+ vchan_free_chan_resources(to_virt_chan(c));
+}
+
+static void gdma_dma_desc_free(struct virt_dma_desc *vdesc)
+{
+ kfree(container_of(vdesc, struct gdma_dma_desc, vdesc));
+}
+
+static void gdma_dma_tasklet(unsigned long arg)
+{
+ struct gdma_dma_dev *dma_dev = (struct gdma_dma_dev *)arg;
+ struct gdma_dmaengine_chan *chan;
+ static unsigned int last_chan;
+ unsigned int i, chan_mask;
+
+ /* record last chan to round robin all chans */
+ i = last_chan;
+ chan_mask = dma_dev->data->chancnt - 1;
+ do {
+ /*
+ * on mt7621. when verify with dmatest with all
+ * channel is enable. we need to limit only two
+ * channel is working at the same time. otherwise the
+ * data will have problem.
+ */
+ if (atomic_read(&dma_dev->cnt) >= 2) {
+ last_chan = i;
+ break;
+ }
+
+ if (test_and_clear_bit(i, &dma_dev->chan_issued)) {
+ chan = &dma_dev->chan[i];
+ if (chan->desc) {
+ atomic_inc(&dma_dev->cnt);
+ gdma_start_transfer(dma_dev, chan);
+ } else
+ dev_dbg(dma_dev->ddev.dev, "chan %d no desc to issue\n", chan->id);
+
+ if (!dma_dev->chan_issued)
+ break;
+ }
+
+ i = (i + 1) & chan_mask;
+ } while (i != last_chan);
+}
+
+static void rt305x_gdma_init(struct gdma_dma_dev *dma_dev)
+{
+ uint32_t gct;
+
+ /* all chans round robin */
+ gdma_dma_write(dma_dev, GDMA_RT305X_GCT, GDMA_REG_GCT_ARBIT_RR);
+
+ gct = gdma_dma_read(dma_dev, GDMA_RT305X_GCT);
+ dev_info(dma_dev->ddev.dev, "revision: %d, channels: %d\n",
+ (gct >> GDMA_REG_GCT_VER_SHIFT) & GDMA_REG_GCT_VER_MASK,
+ 8 << ((gct >> GDMA_REG_GCT_CHAN_SHIFT) &
+ GDMA_REG_GCT_CHAN_MASK));
+}
+
+static void rt3883_gdma_init(struct gdma_dma_dev *dma_dev)
+{
+ uint32_t gct;
+
+ /* all chans round robin */
+ gdma_dma_write(dma_dev, GDMA_REG_GCT, GDMA_REG_GCT_ARBIT_RR);
+
+ gct = gdma_dma_read(dma_dev, GDMA_REG_GCT);
+ dev_info(dma_dev->ddev.dev, "revision: %d, channels: %d\n",
+ (gct >> GDMA_REG_GCT_VER_SHIFT) & GDMA_REG_GCT_VER_MASK,
+ 8 << ((gct >> GDMA_REG_GCT_CHAN_SHIFT) &
+ GDMA_REG_GCT_CHAN_MASK));
+}
+
+static struct gdma_data rt305x_gdma_data = {
+ .chancnt = 8,
+ .done_int_reg = GDMA_RT305X_STATUS_INT,
+ .init = rt305x_gdma_init,
+ .start_transfer = rt305x_gdma_start_transfer,
+};
+
+static struct gdma_data rt3883_gdma_data = {
+ .chancnt = 16,
+ .done_int_reg = GDMA_REG_DONE_INT,
+ .init = rt3883_gdma_init,
+ .start_transfer = rt3883_gdma_start_transfer,
+};
+
+static const struct of_device_id gdma_of_match_table[] = {
+ { .compatible = "ralink,rt305x-gdma", .data = &rt305x_gdma_data },
+ { .compatible = "ralink,rt3883-gdma", .data = &rt3883_gdma_data },
+ { },
+};
+
+static int gdma_dma_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct gdma_dmaengine_chan *chan;
+ struct gdma_dma_dev *dma_dev;
+ struct dma_device *dd;
+ unsigned int i;
+ struct resource *res;
+ int ret;
+ int irq;
+ void __iomem *base;
+ struct gdma_data *data;
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ match = of_match_device(gdma_of_match_table, &pdev->dev);
+ if (!match)
+ return -EINVAL;
+ data = (struct gdma_data *) match->data;
+
+ dma_dev = devm_kzalloc(&pdev->dev, sizeof(*dma_dev) +
+ (sizeof(struct gdma_dmaengine_chan) * data->chancnt),
+ GFP_KERNEL);
+ if (!dma_dev) {
+ dev_err(&pdev->dev, "alloc dma device failed\n");
+ return -EINVAL;
+ }
+ dma_dev->data = data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+ dma_dev->base = base;
+ tasklet_init(&dma_dev->task, gdma_dma_tasklet, (unsigned long)dma_dev);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq\n");
+ return -EINVAL;
+ }
+ ret = devm_request_irq(&pdev->dev, irq, gdma_dma_irq,
+ 0, dev_name(&pdev->dev), dma_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request irq\n");
+ return ret;
+ }
+
+ device_reset(&pdev->dev);
+
+ dd = &dma_dev->ddev;
+ dma_cap_set(DMA_MEMCPY, dd->cap_mask);
+ dma_cap_set(DMA_SLAVE, dd->cap_mask);
+ dma_cap_set(DMA_CYCLIC, dd->cap_mask);
+ dd->device_free_chan_resources = gdma_dma_free_chan_resources;
+ dd->device_prep_dma_memcpy = gdma_dma_prep_dma_memcpy;
+ dd->device_prep_slave_sg = gdma_dma_prep_slave_sg;
+ dd->device_prep_dma_cyclic = gdma_dma_prep_dma_cyclic;
+ dd->device_config = gdma_dma_config;
+ dd->device_terminate_all = gdma_dma_terminate_all;
+ dd->device_tx_status = gdma_dma_tx_status;
+ dd->device_issue_pending = gdma_dma_issue_pending;
+
+ dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ dd->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+
+ dd->dev = &pdev->dev;
+ dd->dev->dma_parms = &dma_dev->dma_parms;
+ dma_set_max_seg_size(dd->dev, GDMA_REG_CTRL0_TX_MASK);
+ INIT_LIST_HEAD(&dd->channels);
+
+ for (i = 0; i < data->chancnt; i++) {
+ chan = &dma_dev->chan[i];
+ chan->id = i;
+ chan->vchan.desc_free = gdma_dma_desc_free;
+ vchan_init(&chan->vchan, dd);
+ }
+
+ /* init hardware */
+ data->init(dma_dev);
+
+ ret = dma_async_device_register(dd);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register dma device\n");
+ return ret;
+ }
+
+ ret = of_dma_controller_register(pdev->dev.of_node,
+ of_dma_xlate_by_chan_id, dma_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register of dma controller\n");
+ goto err_unregister;
+ }
+
+ platform_set_drvdata(pdev, dma_dev);
+
+ return 0;
+
+err_unregister:
+ dma_async_device_unregister(dd);
+ return ret;
+}
+
+static int gdma_dma_remove(struct platform_device *pdev)
+{
+ struct gdma_dma_dev *dma_dev = platform_get_drvdata(pdev);
+
+ tasklet_kill(&dma_dev->task);
+ of_dma_controller_free(pdev->dev.of_node);
+ dma_async_device_unregister(&dma_dev->ddev);
+
+ return 0;
+}
+
+static struct platform_driver gdma_dma_driver = {
+ .probe = gdma_dma_probe,
+ .remove = gdma_dma_remove,
+ .driver = {
+ .name = "gdma-rt2880",
+ .of_match_table = gdma_of_match_table,
+ },
+};
+module_platform_driver(gdma_dma_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Ralink/MTK DMA driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/mt7621-dts/Kconfig b/drivers/staging/mt7621-dts/Kconfig
new file mode 100644
index 000000000000..94a9e16c0b92
--- /dev/null
+++ b/drivers/staging/mt7621-dts/Kconfig
@@ -0,0 +1,5 @@
+config DTB_GNUBEE1
+ bool "GnuBee1 NAS"
+ depends on SOC_MT7621 && DTB_RT_NONE
+ select BUILTIN_DTB
+
diff --git a/drivers/staging/mt7621-dts/Makefile b/drivers/staging/mt7621-dts/Makefile
new file mode 100644
index 000000000000..195eba4a5c65
--- /dev/null
+++ b/drivers/staging/mt7621-dts/Makefile
@@ -0,0 +1,3 @@
+dtb-$(CONFIG_DTB_GNUBEE1) += gbpc1.dtb
+
+obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y))
diff --git a/drivers/staging/mt7621-dts/TODO b/drivers/staging/mt7621-dts/TODO
new file mode 100644
index 000000000000..15803132c1ea
--- /dev/null
+++ b/drivers/staging/mt7621-dts/TODO
@@ -0,0 +1,5 @@
+
+- ensure all usage matches code
+- ensure all features used are documented
+
+Cc: NeilBrown <neil@brown.name> \ No newline at end of file
diff --git a/drivers/staging/mt7621-dts/gbpc1.dts b/drivers/staging/mt7621-dts/gbpc1.dts
new file mode 100644
index 000000000000..515c7cbdd15e
--- /dev/null
+++ b/drivers/staging/mt7621-dts/gbpc1.dts
@@ -0,0 +1,143 @@
+/dts-v1/;
+
+#include "mt7621.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "gnubee,gb-pc1", "mediatek,mt7621-soc";
+ model = "GB-PC1";
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x0 0x1c000000>, <0x20000000 0x4000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,57600";
+ };
+
+ palmbus: palmbus@1E000000 {
+ i2c@900 {
+ status = "okay";
+ };
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+
+ reset {
+ label = "reset";
+ gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>;
+ linux,code = <KEY_RESTART>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ system {
+ label = "gb-pc1:green:system";
+ gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
+ };
+
+ status {
+ label = "gb-pc1:green:status";
+ gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
+ };
+
+ lan1 {
+ label = "gb-pc1:green:lan1";
+ gpios = <&gpio0 24 GPIO_ACTIVE_LOW>;
+ };
+
+ lan2 {
+ label = "gb-pc1:green:lan2";
+ gpios = <&gpio0 25 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
+
+&sdhci {
+ status = "okay";
+};
+
+&spi0 {
+ status = "okay";
+
+ m25p80@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+ m25p,chunked-io = <32>;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x0 0x30000>;
+ read-only;
+ };
+
+ partition@30000 {
+ label = "u-boot-env";
+ reg = <0x30000 0x10000>;
+ read-only;
+ };
+
+ factory: partition@40000 {
+ label = "factory";
+ reg = <0x40000 0x10000>;
+ read-only;
+ };
+
+ partition@50000 {
+ label = "firmware";
+ reg = <0x50000 0xFB0000>;
+ };
+
+ };
+};
+
+&sysclock {
+ compatible = "fixed-clock";
+ clock-frequency = <90000000>;
+};
+
+&cpuclock {
+ compatible = "fixed-clock";
+ clock-frequency = <900000000>;
+};
+
+&pcie {
+ status = "okay";
+};
+
+&ethernet {
+ //mtd-mac-address = <&factory 0xe000>;
+ gmac1: mac@0 {
+ compatible = "mediatek,eth-mac";
+ reg = <0>;
+ phy-handle = <&phy1>;
+ };
+
+ mdio-bus {
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ phy-mode = "rgmii";
+ };
+ };
+};
+
+&pinctrl {
+ state_default: pinctrl0 {
+ gpio {
+ ralink,group = "wdt", "rgmii2", "uart3";
+ ralink,function = "gpio";
+ };
+ };
+};
diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt7621-dts/mt7621.dtsi
new file mode 100644
index 000000000000..ebcaa8b1fc81
--- /dev/null
+++ b/drivers/staging/mt7621-dts/mt7621.dtsi
@@ -0,0 +1,471 @@
+#include <dt-bindings/interrupt-controller/mips-gic.h>
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "mediatek,mt7621-soc";
+
+ cpus {
+ cpu@0 {
+ compatible = "mips,mips1004Kc";
+ };
+
+ cpu@1 {
+ compatible = "mips,mips1004Kc";
+ };
+ };
+
+ cpuintc: cpuintc@0 {
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "mti,cpu-interrupt-controller";
+ };
+
+ aliases {
+ serial0 = &uartlite;
+ };
+
+ cpuclock: cpuclock@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+
+ /* FIXME: there should be way to detect this */
+ clock-frequency = <880000000>;
+ };
+
+ sysclock: sysclock@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+
+ /* FIXME: there should be way to detect this */
+ clock-frequency = <50000000>;
+ };
+
+ palmbus: palmbus@1E000000 {
+ compatible = "palmbus";
+ reg = <0x1E000000 0x100000>;
+ ranges = <0x0 0x1E000000 0x0FFFFF>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sysc: sysc@0 {
+ compatible = "mtk,mt7621-sysc";
+ reg = <0x0 0x100>;
+ };
+
+ wdt: wdt@100 {
+ compatible = "mtk,mt7621-wdt";
+ reg = <0x100 0x100>;
+ };
+
+ gpio@600 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "mtk,mt7621-gpio";
+ reg = <0x600 0x100>;
+
+ gpio0: bank@0 {
+ reg = <0>;
+ compatible = "mtk,mt7621-gpio-bank";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio1: bank@1 {
+ reg = <1>;
+ compatible = "mtk,mt7621-gpio-bank";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio2: bank@2 {
+ reg = <2>;
+ compatible = "mtk,mt7621-gpio-bank";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ };
+
+ i2c: i2c@900 {
+ compatible = "mediatek,mt7621-i2c";
+ reg = <0x900 0x100>;
+
+ clocks = <&sysclock>;
+
+ resets = <&rstctrl 16>;
+ reset-names = "i2c";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ status = "disabled";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c_pins>;
+ };
+
+ i2s: i2s@a00 {
+ compatible = "mediatek,mt7621-i2s";
+ reg = <0xa00 0x100>;
+
+ clocks = <&sysclock>;
+
+ resets = <&rstctrl 17>;
+ reset-names = "i2s";
+
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SHARED 16 IRQ_TYPE_LEVEL_HIGH>;
+
+ txdma-req = <2>;
+ rxdma-req = <3>;
+
+ dmas = <&gdma 4>,
+ <&gdma 6>;
+ dma-names = "tx", "rx";
+
+ status = "disabled";
+ };
+
+ memc: memc@5000 {
+ compatible = "mtk,mt7621-memc";
+ reg = <0x300 0x100>;
+ };
+
+ cpc: cpc@1fbf0000 {
+ compatible = "mtk,mt7621-cpc";
+ reg = <0x1fbf0000 0x8000>;
+ };
+
+ mc: mc@1fbf8000 {
+ compatible = "mtk,mt7621-mc";
+ reg = <0x1fbf8000 0x8000>;
+ };
+
+ uartlite: uartlite@c00 {
+ compatible = "ns16550a";
+ reg = <0xc00 0x100>;
+
+ clocks = <&sysclock>;
+ clock-frequency = <50000000>;
+
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SHARED 26 IRQ_TYPE_LEVEL_HIGH>;
+
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ no-loopback-test;
+ };
+
+ spi0: spi@b00 {
+ status = "disabled";
+
+ compatible = "ralink,mt7621-spi";
+ reg = <0xb00 0x100>;
+
+ clocks = <&sysclock>;
+
+ resets = <&rstctrl 18>;
+ reset-names = "spi";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi_pins>;
+ };
+
+ gdma: gdma@2800 {
+ compatible = "ralink,rt3883-gdma";
+ reg = <0x2800 0x800>;
+
+ resets = <&rstctrl 14>;
+ reset-names = "dma";
+
+ interrupt-parent = <&gic>;
+ interrupts = <0 13 4>;
+
+ #dma-cells = <1>;
+ #dma-channels = <16>;
+ #dma-requests = <16>;
+
+ status = "disabled";
+ };
+
+ hsdma: hsdma@7000 {
+ compatible = "mediatek,mt7621-hsdma";
+ reg = <0x7000 0x1000>;
+
+ resets = <&rstctrl 5>;
+ reset-names = "hsdma";
+
+ interrupt-parent = <&gic>;
+ interrupts = <0 11 4>;
+
+ #dma-cells = <1>;
+ #dma-channels = <1>;
+ #dma-requests = <1>;
+
+ status = "disabled";
+ };
+ };
+
+ pinctrl: pinctrl {
+ compatible = "ralink,rt2880-pinmux";
+ pinctrl-names = "default";
+ pinctrl-0 = <&state_default>;
+
+ state_default: pinctrl0 {
+ };
+
+ i2c_pins: i2c {
+ i2c {
+ ralink,group = "i2c";
+ ralink,function = "i2c";
+ };
+ };
+
+ spi_pins: spi {
+ spi {
+ ralink,group = "spi";
+ ralink,function = "spi";
+ };
+ };
+
+ uart1_pins: uart1 {
+ uart1 {
+ ralink,group = "uart1";
+ ralink,function = "uart1";
+ };
+ };
+
+ uart2_pins: uart2 {
+ uart2 {
+ ralink,group = "uart2";
+ ralink,function = "uart2";
+ };
+ };
+
+ uart3_pins: uart3 {
+ uart3 {
+ ralink,group = "uart3";
+ ralink,function = "uart3";
+ };
+ };
+
+ rgmii1_pins: rgmii1 {
+ rgmii1 {
+ ralink,group = "rgmii1";
+ ralink,function = "rgmii1";
+ };
+ };
+
+ rgmii2_pins: rgmii2 {
+ rgmii2 {
+ ralink,group = "rgmii2";
+ ralink,function = "rgmii2";
+ };
+ };
+
+ mdio_pins: mdio {
+ mdio {
+ ralink,group = "mdio";
+ ralink,function = "mdio";
+ };
+ };
+
+ pcie_pins: pcie {
+ pcie {
+ ralink,group = "pcie";
+ ralink,function = "pcie rst";
+ };
+ };
+
+ nand_pins: nand {
+ spi-nand {
+ ralink,group = "spi";
+ ralink,function = "nand1";
+ };
+
+ sdhci-nand {
+ ralink,group = "sdhci";
+ ralink,function = "nand2";
+ };
+ };
+
+ sdhci_pins: sdhci {
+ sdhci {
+ ralink,group = "sdhci";
+ ralink,function = "sdhci";
+ };
+ };
+ };
+
+ rstctrl: rstctrl {
+ compatible = "ralink,rt2880-reset";
+ #reset-cells = <1>;
+ };
+
+ clkctrl: clkctrl {
+ compatible = "ralink,rt2880-clock";
+ #clock-cells = <1>;
+ };
+
+ sdhci: sdhci@1E130000 {
+ status = "disabled";
+
+ compatible = "ralink,mt7620-sdhci";
+ reg = <0x1E130000 0x4000>;
+
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SHARED 20 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ xhci: xhci@1E1C0000 {
+ status = "okay";
+
+ compatible = "mediatek,mt8173-xhci";
+ reg = <0x1e1c0000 0x1000
+ 0x1e1d0700 0x0100>;
+ reg-names = "mac", "ippc";
+
+ clocks = <&sysclock>;
+ clock-names = "sys_ck";
+
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SHARED 22 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ gic: interrupt-controller@1fbc0000 {
+ compatible = "mti,gic";
+ reg = <0x1fbc0000 0x2000>;
+
+ interrupt-controller;
+ #interrupt-cells = <3>;
+
+ mti,reserved-cpu-vectors = <7>;
+
+ timer {
+ compatible = "mti,gic-timer";
+ interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>;
+ clocks = <&cpuclock>;
+ };
+ };
+
+ nand: nand@1e003000 {
+ status = "disabled";
+
+ compatible = "mtk,mt7621-nand";
+ bank-width = <2>;
+ reg = <0x1e003000 0x800
+ 0x1e003800 0x800>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+
+ ethsys: syscon@1e000000 {
+ compatible = "mediatek,mt7621-ethsys",
+ "syscon";
+ reg = <0x1e000000 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ ethernet: ethernet@1e100000 {
+ compatible = "mediatek,mt7621-eth";
+ reg = <0x1e100000 0x10000>;
+
+ clocks = <&sysclock>;
+ clock-names = "ethif";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ resets = <&rstctrl 6 &rstctrl 23>;
+ reset-names = "fe", "eth";
+
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SHARED 3 IRQ_TYPE_LEVEL_HIGH>;
+
+ mediatek,ethsys = <&ethsys>;
+
+ mediatek,switch = <&gsw>;
+
+ mdio-bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ phy1f: ethernet-phy@1f {
+ reg = <0x1f>;
+ phy-mode = "rgmii";
+ };
+ };
+ };
+
+ gsw: gsw@1e110000 {
+ compatible = "mediatek,mt7621-gsw";
+ reg = <0x1e110000 0x8000>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SHARED 23 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ pcie: pcie@1e140000 {
+ compatible = "mediatek,mt7621-pci";
+ reg = <0x1e140000 0x100
+ 0x1e142000 0x100>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie_pins>;
+
+ device_type = "pci";
+
+ bus-range = <0 255>;
+ ranges = <
+ 0x02000000 0 0x00000000 0x60000000 0 0x10000000 /* pci memory */
+ 0x01000000 0 0x00000000 0x1e160000 0 0x00010000 /* io space */
+ >;
+
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SHARED 4 IRQ_TYPE_LEVEL_HIGH
+ GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH
+ GIC_SHARED 25 IRQ_TYPE_LEVEL_HIGH>;
+
+ status = "disabled";
+
+ resets = <&rstctrl 24 &rstctrl 25 &rstctrl 26>;
+ reset-names = "pcie0", "pcie1", "pcie2";
+ clocks = <&clkctrl 24 &clkctrl 25 &clkctrl 26>;
+ clock-names = "pcie0", "pcie1", "pcie2";
+
+ pcie0 {
+ reg = <0x0000 0 0 0 0>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ device_type = "pci";
+ };
+
+ pcie1 {
+ reg = <0x0800 0 0 0 0>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ device_type = "pci";
+ };
+
+ pcie2 {
+ reg = <0x1000 0 0 0 0>;
+
+ #address-cells = <3>;
+ #size-cells = <2>;
+
+ device_type = "pci";
+ };
+ };
+};
diff --git a/drivers/staging/mt7621-eth/Documentation/devicetree/bindings/net/mediatek-net-gsw.txt b/drivers/staging/mt7621-eth/Documentation/devicetree/bindings/net/mediatek-net-gsw.txt
new file mode 100644
index 000000000000..596b38552697
--- /dev/null
+++ b/drivers/staging/mt7621-eth/Documentation/devicetree/bindings/net/mediatek-net-gsw.txt
@@ -0,0 +1,48 @@
+Mediatek Gigabit Switch
+=======================
+
+The mediatek gigabit switch can be found on Mediatek SoCs.
+
+Required properties:
+- compatible: Should be "mediatek,mt7620-gsw", "mediatek,mt7621-gsw",
+ "mediatek,mt7623-gsw"
+- reg: Address and length of the register set for the device
+- interrupts: Should contain the gigabit switches interrupt
+
+
+Additional required properties for ARM based SoCs:
+- mediatek,reset-pin: phandle describing the reset GPIO
+- clocks: the clocks used by the switch
+- clock-names: the names of the clocks listed in the clocks property
+ these should be "trgpll", "esw", "gp2", "gp1"
+- mt7530-supply: the phandle of the regulator used to power the switch
+- mediatek,pctl-regmap: phandle to the port control regmap. this is used to
+ setup the drive current
+
+
+Optional properties:
+- interrupt-parent: Should be the phandle for the interrupt controller
+ that services interrupts for this device
+
+Example:
+
+gsw: switch@1b100000 {
+ compatible = "mediatek,mt7623-gsw";
+ reg = <0 0x1b110000 0 0x300000>;
+
+ interrupt-parent = <&pio>;
+ interrupts = <168 IRQ_TYPE_EDGE_RISING>;
+
+ clocks = <&apmixedsys CLK_APMIXED_TRGPLL>,
+ <&ethsys CLK_ETHSYS_ESW>,
+ <&ethsys CLK_ETHSYS_GP2>,
+ <&ethsys CLK_ETHSYS_GP1>;
+ clock-names = "trgpll", "esw", "gp2", "gp1";
+
+ mt7530-supply = <&mt6323_vpa_reg>;
+
+ mediatek,pctl-regmap = <&syscfg_pctl_a>;
+ mediatek,reset-pin = <&pio 15 0>;
+
+ status = "okay";
+};
diff --git a/drivers/staging/mt7621-eth/Kconfig b/drivers/staging/mt7621-eth/Kconfig
new file mode 100644
index 000000000000..44ea86c7a96c
--- /dev/null
+++ b/drivers/staging/mt7621-eth/Kconfig
@@ -0,0 +1,39 @@
+config NET_VENDOR_MEDIATEK_STAGING
+ bool "MediaTek ethernet driver - staging version"
+ depends on RALINK
+ ---help---
+ If you have an MT7621 Mediatek SoC with ethernet, say Y.
+
+if NET_VENDOR_MEDIATEK_STAGING
+choice
+ prompt "MAC type"
+
+config NET_MEDIATEK_MT7621
+ bool "MT7621"
+ depends on MIPS && SOC_MT7621
+
+endchoice
+
+config NET_MEDIATEK_SOC_STAGING
+ tristate "MediaTek SoC Gigabit Ethernet support"
+ depends on NET_VENDOR_MEDIATEK_STAGING
+ select PHYLIB
+ ---help---
+ This driver supports the gigabit ethernet MACs in the
+ MediaTek SoC family.
+
+config NET_MEDIATEK_MDIO
+ def_bool NET_MEDIATEK_SOC_STAGING
+ depends on NET_MEDIATEK_MT7621
+ select PHYLIB
+
+config NET_MEDIATEK_MDIO_MT7620
+ def_bool NET_MEDIATEK_SOC_STAGING
+ depends on NET_MEDIATEK_MT7621
+ select NET_MEDIATEK_MDIO
+
+config NET_MEDIATEK_GSW_MT7621
+ def_tristate NET_MEDIATEK_SOC_STAGING
+ depends on NET_MEDIATEK_MT7621
+
+endif #NET_VENDOR_MEDIATEK_STAGING
diff --git a/drivers/staging/mt7621-eth/Makefile b/drivers/staging/mt7621-eth/Makefile
new file mode 100644
index 000000000000..018bcc3596b3
--- /dev/null
+++ b/drivers/staging/mt7621-eth/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the Ralink SoCs built-in ethernet macs
+#
+
+mtk-eth-soc-y += mtk_eth_soc.o ethtool.o
+
+mtk-eth-soc-$(CONFIG_NET_MEDIATEK_MDIO) += mdio.o
+mtk-eth-soc-$(CONFIG_NET_MEDIATEK_MDIO_MT7620) += mdio_mt7620.o
+
+mtk-eth-soc-$(CONFIG_NET_MEDIATEK_MT7621) += soc_mt7621.o
+
+obj-$(CONFIG_NET_MEDIATEK_GSW_MT7621) += gsw_mt7621.o
+
+obj-$(CONFIG_NET_MEDIATEK_SOC_STAGING) += mtk-eth-soc.o
diff --git a/drivers/staging/mt7621-eth/TODO b/drivers/staging/mt7621-eth/TODO
new file mode 100644
index 000000000000..f9e47d4b4cd4
--- /dev/null
+++ b/drivers/staging/mt7621-eth/TODO
@@ -0,0 +1,13 @@
+
+- verify devicetree documentation is consistent with code
+- fix ethtool - currently doesn't return valid data.
+- general code review and clean up
+- add support for second MAC on mt7621
+- convert gsw code to use switchdev interfaces
+- md7620_mmi_write etc should probably be wrapped
+ in a regmap abstraction.
+- Get soc_mt7621 to work with QDMA TX if possible.
+- Ensure phys are correctly configured when a cable
+ is plugged in.
+
+Cc: NeilBrown <neil@brown.name>
diff --git a/drivers/staging/mt7621-eth/ethtool.c b/drivers/staging/mt7621-eth/ethtool.c
new file mode 100644
index 000000000000..38ba0c040aba
--- /dev/null
+++ b/drivers/staging/mt7621-eth/ethtool.c
@@ -0,0 +1,225 @@
+/* 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; 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.
+ *
+ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#include "mtk_eth_soc.h"
+
+static const char mtk_gdma_str[][ETH_GSTRING_LEN] = {
+#define _FE(x...) # x,
+MTK_STAT_REG_DECLARE
+#undef _FE
+};
+
+static int mtk_get_link_ksettings(struct net_device *dev,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ int err;
+
+ if (!mac->phy_dev)
+ return -ENODEV;
+
+ if (mac->phy_flags == MTK_PHY_FLAG_ATTACH) {
+ err = phy_read_status(mac->phy_dev);
+ if (err)
+ return -ENODEV;
+ }
+
+ phy_ethtool_ksettings_get(mac->phy_dev, cmd);
+ return 0;
+}
+
+static int mtk_set_link_ksettings(struct net_device *dev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+
+ if (!mac->phy_dev)
+ return -ENODEV;
+
+ if (cmd->base.phy_address != mac->phy_dev->mdio.addr) {
+ if (mac->hw->phy->phy_node[cmd->base.phy_address]) {
+ mac->phy_dev = mac->hw->phy->phy[cmd->base.phy_address];
+ mac->phy_flags = MTK_PHY_FLAG_PORT;
+ } else if (mac->hw->mii_bus) {
+ mac->phy_dev = mdiobus_get_phy(mac->hw->mii_bus, cmd->base.phy_address);
+ if (!mac->phy_dev)
+ return -ENODEV;
+ mac->phy_flags = MTK_PHY_FLAG_ATTACH;
+ } else {
+ return -ENODEV;
+ }
+ }
+
+ return phy_ethtool_ksettings_set(mac->phy_dev, cmd);
+
+}
+
+static void mtk_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_soc_data *soc = mac->hw->soc;
+
+ strlcpy(info->driver, mac->hw->dev->driver->name, sizeof(info->driver));
+ strlcpy(info->bus_info, dev_name(mac->hw->dev), sizeof(info->bus_info));
+
+ if (soc->reg_table[MTK_REG_MTK_COUNTER_BASE])
+ info->n_stats = ARRAY_SIZE(mtk_gdma_str);
+}
+
+static u32 mtk_get_msglevel(struct net_device *dev)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+
+ return mac->hw->msg_enable;
+}
+
+static void mtk_set_msglevel(struct net_device *dev, u32 value)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+
+ mac->hw->msg_enable = value;
+}
+
+static int mtk_nway_reset(struct net_device *dev)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+
+ if (!mac->phy_dev)
+ return -EOPNOTSUPP;
+
+ return genphy_restart_aneg(mac->phy_dev);
+}
+
+static u32 mtk_get_link(struct net_device *dev)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ int err;
+
+ if (!mac->phy_dev)
+ goto out_get_link;
+
+ if (mac->phy_flags == MTK_PHY_FLAG_ATTACH) {
+ err = genphy_update_link(mac->phy_dev);
+ if (err)
+ goto out_get_link;
+ }
+
+ return mac->phy_dev->link;
+
+out_get_link:
+ return ethtool_op_get_link(dev);
+}
+
+static int mtk_set_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+
+ if ((ring->tx_pending < 2) ||
+ (ring->rx_pending < 2) ||
+ (ring->rx_pending > mac->hw->soc->dma_ring_size) ||
+ (ring->tx_pending > mac->hw->soc->dma_ring_size))
+ return -EINVAL;
+
+ dev->netdev_ops->ndo_stop(dev);
+
+ mac->hw->tx_ring.tx_ring_size = BIT(fls(ring->tx_pending) - 1);
+ mac->hw->rx_ring[0].rx_ring_size = BIT(fls(ring->rx_pending) - 1);
+
+ return dev->netdev_ops->ndo_open(dev);
+}
+
+static void mtk_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+
+ ring->rx_max_pending = mac->hw->soc->dma_ring_size;
+ ring->tx_max_pending = mac->hw->soc->dma_ring_size;
+ ring->rx_pending = mac->hw->rx_ring[0].rx_ring_size;
+ ring->tx_pending = mac->hw->tx_ring.tx_ring_size;
+}
+
+static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ switch (stringset) {
+ case ETH_SS_STATS:
+ memcpy(data, *mtk_gdma_str, sizeof(mtk_gdma_str));
+ break;
+ }
+}
+
+static int mtk_get_sset_count(struct net_device *dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(mtk_gdma_str);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void mtk_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_hw_stats *hwstats = mac->hw_stats;
+ u64 *data_src, *data_dst;
+ unsigned int start;
+ int i;
+
+ if (netif_running(dev) && netif_device_present(dev)) {
+ if (spin_trylock(&hwstats->stats_lock)) {
+ mtk_stats_update_mac(mac);
+ spin_unlock(&hwstats->stats_lock);
+ }
+ }
+
+ do {
+ data_src = &hwstats->tx_bytes;
+ data_dst = data;
+ start = u64_stats_fetch_begin_irq(&hwstats->syncp);
+
+ for (i = 0; i < ARRAY_SIZE(mtk_gdma_str); i++)
+ *data_dst++ = *data_src++;
+
+ } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start));
+}
+
+static struct ethtool_ops mtk_ethtool_ops = {
+ .get_link_ksettings = mtk_get_link_ksettings,
+ .set_link_ksettings = mtk_set_link_ksettings,
+ .get_drvinfo = mtk_get_drvinfo,
+ .get_msglevel = mtk_get_msglevel,
+ .set_msglevel = mtk_set_msglevel,
+ .nway_reset = mtk_nway_reset,
+ .get_link = mtk_get_link,
+ .set_ringparam = mtk_set_ringparam,
+ .get_ringparam = mtk_get_ringparam,
+};
+
+void mtk_set_ethtool_ops(struct net_device *netdev)
+{
+ struct mtk_mac *mac = netdev_priv(netdev);
+ struct mtk_soc_data *soc = mac->hw->soc;
+
+ if (soc->reg_table[MTK_REG_MTK_COUNTER_BASE]) {
+ mtk_ethtool_ops.get_strings = mtk_get_strings;
+ mtk_ethtool_ops.get_sset_count = mtk_get_sset_count;
+ mtk_ethtool_ops.get_ethtool_stats = mtk_get_ethtool_stats;
+ }
+
+ netdev->ethtool_ops = &mtk_ethtool_ops;
+}
diff --git a/drivers/staging/mt7621-eth/ethtool.h b/drivers/staging/mt7621-eth/ethtool.h
new file mode 100644
index 000000000000..40b4cf011660
--- /dev/null
+++ b/drivers/staging/mt7621-eth/ethtool.h
@@ -0,0 +1,22 @@
+/* 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; 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.
+ *
+ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#ifndef MTK_ETHTOOL_H
+#define MTK_ETHTOOL_H
+
+#include <linux/ethtool.h>
+
+void mtk_set_ethtool_ops(struct net_device *netdev);
+
+#endif /* MTK_ETHTOOL_H */
diff --git a/drivers/staging/mt7621-eth/gsw_mt7620.h b/drivers/staging/mt7621-eth/gsw_mt7620.h
new file mode 100644
index 000000000000..1766939e2101
--- /dev/null
+++ b/drivers/staging/mt7621-eth/gsw_mt7620.h
@@ -0,0 +1,277 @@
+/* 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; 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.
+ *
+ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#ifndef _RALINK_GSW_MT7620_H__
+#define _RALINK_GSW_MT7620_H__
+
+#define GSW_REG_PHY_TIMEOUT (5 * HZ)
+
+#define MT7620_GSW_REG_PIAC 0x0004
+
+#define GSW_NUM_VLANS 16
+#define GSW_NUM_VIDS 4096
+#define GSW_NUM_PORTS 7
+#define GSW_PORT6 6
+
+#define GSW_MDIO_ACCESS BIT(31)
+#define GSW_MDIO_READ BIT(19)
+#define GSW_MDIO_WRITE BIT(18)
+#define GSW_MDIO_START BIT(16)
+#define GSW_MDIO_ADDR_SHIFT 20
+#define GSW_MDIO_REG_SHIFT 25
+
+#define GSW_REG_PORT_PMCR(x) (0x3000 + (x * 0x100))
+#define GSW_REG_PORT_STATUS(x) (0x3008 + (x * 0x100))
+#define GSW_REG_SMACCR0 0x3fE4
+#define GSW_REG_SMACCR1 0x3fE8
+#define GSW_REG_CKGCR 0x3ff0
+
+#define GSW_REG_IMR 0x7008
+#define GSW_REG_ISR 0x700c
+#define GSW_REG_GPC1 0x7014
+
+#define SYSC_REG_CHIP_REV_ID 0x0c
+#define SYSC_REG_CFG 0x10
+#define SYSC_REG_CFG1 0x14
+#define RST_CTRL_MCM BIT(2)
+#define SYSC_PAD_RGMII2_MDIO 0x58
+#define SYSC_GPIO_MODE 0x60
+
+#define PORT_IRQ_ST_CHG 0x7f
+
+#define MT7621_ESW_PHY_POLLING 0x0000
+#define MT7620_ESW_PHY_POLLING 0x7000
+
+#define PMCR_IPG BIT(18)
+#define PMCR_MAC_MODE BIT(16)
+#define PMCR_FORCE BIT(15)
+#define PMCR_TX_EN BIT(14)
+#define PMCR_RX_EN BIT(13)
+#define PMCR_BACKOFF BIT(9)
+#define PMCR_BACKPRES BIT(8)
+#define PMCR_RX_FC BIT(5)
+#define PMCR_TX_FC BIT(4)
+#define PMCR_SPEED(_x) (_x << 2)
+#define PMCR_DUPLEX BIT(1)
+#define PMCR_LINK BIT(0)
+
+#define PHY_AN_EN BIT(31)
+#define PHY_PRE_EN BIT(30)
+#define PMY_MDC_CONF(_x) ((_x & 0x3f) << 24)
+
+/* ethernet subsystem config register */
+#define ETHSYS_SYSCFG0 0x14
+/* ethernet subsystem clock register */
+#define ETHSYS_CLKCFG0 0x2c
+#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11)
+
+/* p5 RGMII wrapper TX clock control register */
+#define MT7530_P5RGMIITXCR 0x7b04
+/* p5 RGMII wrapper RX clock control register */
+#define MT7530_P5RGMIIRXCR 0x7b00
+/* TRGMII TDX ODT registers */
+#define MT7530_TRGMII_TD0_ODT 0x7a54
+#define MT7530_TRGMII_TD1_ODT 0x7a5c
+#define MT7530_TRGMII_TD2_ODT 0x7a64
+#define MT7530_TRGMII_TD3_ODT 0x7a6c
+#define MT7530_TRGMII_TD4_ODT 0x7a74
+#define MT7530_TRGMII_TD5_ODT 0x7a7c
+/* TRGMII TCK ctrl register */
+#define MT7530_TRGMII_TCK_CTRL 0x7a78
+/* TRGMII Tx ctrl register */
+#define MT7530_TRGMII_TXCTRL 0x7a40
+/* port 6 extended control register */
+#define MT7530_P6ECR 0x7830
+/* IO driver control register */
+#define MT7530_IO_DRV_CR 0x7810
+/* top signal control register */
+#define MT7530_TOP_SIG_CTRL 0x7808
+/* modified hwtrap register */
+#define MT7530_MHWTRAP 0x7804
+/* hwtrap status register */
+#define MT7530_HWTRAP 0x7800
+/* status interrupt register */
+#define MT7530_SYS_INT_STS 0x700c
+/* system nterrupt register */
+#define MT7530_SYS_INT_EN 0x7008
+/* system control register */
+#define MT7530_SYS_CTRL 0x7000
+/* port MAC status register */
+#define MT7530_PMSR_P(x) (0x3008 + (x * 0x100))
+/* port MAC control register */
+#define MT7530_PMCR_P(x) (0x3000 + (x * 0x100))
+
+#define MT7621_XTAL_SHIFT 6
+#define MT7621_XTAL_MASK 0x7
+#define MT7621_XTAL_25 6
+#define MT7621_XTAL_40 3
+#define MT7621_MDIO_DRV_MASK (3 << 4)
+#define MT7621_GE1_MODE_MASK (3 << 12)
+
+#define TRGMII_TXCTRL_TXC_INV BIT(30)
+#define P6ECR_INTF_MODE_RGMII BIT(1)
+#define P5RGMIIRXCR_C_ALIGN BIT(8)
+#define P5RGMIIRXCR_DELAY_2 BIT(1)
+#define P5RGMIITXCR_DELAY_2 (BIT(8) | BIT(2))
+
+/* TOP_SIG_CTRL bits */
+#define TOP_SIG_CTRL_NORMAL (BIT(17) | BIT(16))
+
+/* MHWTRAP bits */
+#define MHWTRAP_MANUAL BIT(16)
+#define MHWTRAP_P5_MAC_SEL BIT(13)
+#define MHWTRAP_P6_DIS BIT(8)
+#define MHWTRAP_P5_RGMII_MODE BIT(7)
+#define MHWTRAP_P5_DIS BIT(6)
+#define MHWTRAP_PHY_ACCESS BIT(5)
+
+/* HWTRAP bits */
+#define HWTRAP_XTAL_SHIFT 9
+#define HWTRAP_XTAL_MASK 0x3
+
+/* SYS_CTRL bits */
+#define SYS_CTRL_SW_RST BIT(1)
+#define SYS_CTRL_REG_RST BIT(0)
+
+/* PMCR bits */
+#define PMCR_IFG_XMIT_96 BIT(18)
+#define PMCR_MAC_MODE BIT(16)
+#define PMCR_FORCE_MODE BIT(15)
+#define PMCR_TX_EN BIT(14)
+#define PMCR_RX_EN BIT(13)
+#define PMCR_BACK_PRES_EN BIT(9)
+#define PMCR_BACKOFF_EN BIT(8)
+#define PMCR_TX_FC_EN BIT(5)
+#define PMCR_RX_FC_EN BIT(4)
+#define PMCR_FORCE_SPEED_1000 BIT(3)
+#define PMCR_FORCE_FDX BIT(1)
+#define PMCR_FORCE_LNK BIT(0)
+#define PMCR_FIXED_LINK (PMCR_IFG_XMIT_96 | PMCR_MAC_MODE | \
+ PMCR_FORCE_MODE | PMCR_TX_EN | PMCR_RX_EN | \
+ PMCR_BACK_PRES_EN | PMCR_BACKOFF_EN | \
+ PMCR_FORCE_SPEED_1000 | PMCR_FORCE_FDX | \
+ PMCR_FORCE_LNK)
+
+#define PMCR_FIXED_LINK_FC (PMCR_FIXED_LINK | \
+ PMCR_TX_FC_EN | PMCR_RX_FC_EN)
+
+/* TRGMII control registers */
+#define GSW_INTF_MODE 0x390
+#define GSW_TRGMII_TD0_ODT 0x354
+#define GSW_TRGMII_TD1_ODT 0x35c
+#define GSW_TRGMII_TD2_ODT 0x364
+#define GSW_TRGMII_TD3_ODT 0x36c
+#define GSW_TRGMII_TXCTL_ODT 0x374
+#define GSW_TRGMII_TCK_ODT 0x37c
+#define GSW_TRGMII_RCK_CTRL 0x300
+
+#define INTF_MODE_TRGMII BIT(1)
+#define TRGMII_RCK_CTRL_RX_RST BIT(31)
+
+/* Mac control registers */
+#define MTK_MAC_P2_MCR 0x200
+#define MTK_MAC_P1_MCR 0x100
+
+#define MAC_MCR_MAX_RX_2K BIT(29)
+#define MAC_MCR_IPG_CFG (BIT(18) | BIT(16))
+#define MAC_MCR_FORCE_MODE BIT(15)
+#define MAC_MCR_TX_EN BIT(14)
+#define MAC_MCR_RX_EN BIT(13)
+#define MAC_MCR_BACKOFF_EN BIT(9)
+#define MAC_MCR_BACKPR_EN BIT(8)
+#define MAC_MCR_FORCE_RX_FC BIT(5)
+#define MAC_MCR_FORCE_TX_FC BIT(4)
+#define MAC_MCR_SPEED_1000 BIT(3)
+#define MAC_MCR_FORCE_DPX BIT(1)
+#define MAC_MCR_FORCE_LINK BIT(0)
+#define MAC_MCR_FIXED_LINK (MAC_MCR_MAX_RX_2K | MAC_MCR_IPG_CFG | \
+ MAC_MCR_FORCE_MODE | MAC_MCR_TX_EN | \
+ MAC_MCR_RX_EN | MAC_MCR_BACKOFF_EN | \
+ MAC_MCR_BACKPR_EN | MAC_MCR_FORCE_RX_FC | \
+ MAC_MCR_FORCE_TX_FC | MAC_MCR_SPEED_1000 | \
+ MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_LINK)
+#define MAC_MCR_FIXED_LINK_FC (MAC_MCR_MAX_RX_2K | MAC_MCR_IPG_CFG | \
+ MAC_MCR_FIXED_LINK)
+
+/* possible XTAL speed */
+#define MT7623_XTAL_40 0
+#define MT7623_XTAL_20 1
+#define MT7623_XTAL_25 3
+
+/* GPIO port control registers */
+#define GPIO_OD33_CTRL8 0x4c0
+#define GPIO_BIAS_CTRL 0xed0
+#define GPIO_DRV_SEL10 0xf00
+
+/* on MT7620 the functio of port 4 can be software configured */
+enum {
+ PORT4_EPHY = 0,
+ PORT4_EXT,
+};
+
+/* struct mt7620_gsw - the structure that holds the SoC specific data
+ * @dev: The Device struct
+ * @base: The base address
+ * @piac_offset: The PIAC base may change depending on SoC
+ * @irq: The IRQ we are using
+ * @port4: The port4 mode on MT7620
+ * @autopoll: Is MDIO autopolling enabled
+ * @ethsys: The ethsys register map
+ * @pctl: The pin control register map
+ * @clk_gsw: The switch clock
+ * @clk_gp1: The gmac1 clock
+ * @clk_gp2: The gmac2 clock
+ * @clk_trgpll: The trgmii pll clock
+ */
+struct mt7620_gsw {
+ struct device *dev;
+ void __iomem *base;
+ u32 piac_offset;
+ int irq;
+ int port4;
+ unsigned long int autopoll;
+
+ struct regmap *ethsys;
+ struct regmap *pctl;
+
+ struct clk *clk_gsw;
+ struct clk *clk_gp1;
+ struct clk *clk_gp2;
+ struct clk *clk_trgpll;
+};
+
+/* switch register I/O wrappers */
+void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg);
+u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg);
+
+/* the callback used by the driver core to bringup the switch */
+int mtk_gsw_init(struct mtk_eth *eth);
+
+/* MDIO access wrappers */
+int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val);
+int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg);
+void mt7620_mdio_link_adjust(struct mtk_eth *eth, int port);
+int mt7620_has_carrier(struct mtk_eth *eth);
+void mt7620_print_link_state(struct mtk_eth *eth, int port, int link,
+ int speed, int duplex);
+void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val);
+u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg);
+void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg);
+
+u32 _mt7620_mii_write(struct mt7620_gsw *gsw, u32 phy_addr,
+ u32 phy_register, u32 write_data);
+u32 _mt7620_mii_read(struct mt7620_gsw *gsw, int phy_addr, int phy_reg);
+void mt7620_handle_carrier(struct mtk_eth *eth);
+
+#endif
diff --git a/drivers/staging/mt7621-eth/gsw_mt7621.c b/drivers/staging/mt7621-eth/gsw_mt7621.c
new file mode 100644
index 000000000000..ce8d7d7577c7
--- /dev/null
+++ b/drivers/staging/mt7621-eth/gsw_mt7621.c
@@ -0,0 +1,298 @@
+/* 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; 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.
+ *
+ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+
+#include <ralink_regs.h>
+
+#include "mtk_eth_soc.h"
+#include "gsw_mt7620.h"
+
+void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg)
+{
+ iowrite32(val, gsw->base + reg);
+}
+EXPORT_SYMBOL_GPL(mtk_switch_w32);
+
+u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg)
+{
+ return ioread32(gsw->base + reg);
+}
+EXPORT_SYMBOL_GPL(mtk_switch_r32);
+
+static irqreturn_t gsw_interrupt_mt7621(int irq, void *_eth)
+{
+ struct mtk_eth *eth = (struct mtk_eth *)_eth;
+ struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv;
+ u32 reg, i;
+
+ reg = mt7530_mdio_r32(gsw, MT7530_SYS_INT_STS);
+
+ for (i = 0; i < 5; i++) {
+ unsigned int link;
+
+ if ((reg & BIT(i)) == 0)
+ continue;
+
+ link = mt7530_mdio_r32(gsw, MT7530_PMSR_P(i)) & 0x1;
+
+ if (link == eth->link[i])
+ continue;
+
+ eth->link[i] = link;
+ if (link)
+ netdev_info(*eth->netdev,
+ "port %d link up\n", i);
+ else
+ netdev_info(*eth->netdev,
+ "port %d link down\n", i);
+ }
+
+ mt7530_mdio_w32(gsw, MT7530_SYS_INT_STS, 0x1f);
+
+ return IRQ_HANDLED;
+}
+
+static void mt7621_hw_init(struct mtk_eth *eth, struct mt7620_gsw *gsw,
+ struct device_node *np)
+{
+ u32 i;
+ u32 val;
+
+ /* hardware reset the switch */
+ mtk_reset(eth, RST_CTRL_MCM);
+ mdelay(10);
+
+ /* reduce RGMII2 PAD driving strength */
+ rt_sysc_m32(MT7621_MDIO_DRV_MASK, 0, SYSC_PAD_RGMII2_MDIO);
+
+ /* gpio mux - RGMII1=Normal mode */
+ rt_sysc_m32(BIT(14), 0, SYSC_GPIO_MODE);
+
+ /* set GMAC1 RGMII mode */
+ rt_sysc_m32(MT7621_GE1_MODE_MASK, 0, SYSC_REG_CFG1);
+
+ /* enable MDIO to control MT7530 */
+ rt_sysc_m32(3 << 12, 0, SYSC_GPIO_MODE);
+
+ /* turn off all PHYs */
+ for (i = 0; i <= 4; i++) {
+ val = _mt7620_mii_read(gsw, i, 0x0);
+ val |= BIT(11);
+ _mt7620_mii_write(gsw, i, 0x0, val);
+ }
+
+ /* reset the switch */
+ mt7530_mdio_w32(gsw, MT7530_SYS_CTRL,
+ SYS_CTRL_SW_RST | SYS_CTRL_REG_RST);
+ usleep_range(10, 20);
+
+ if ((rt_sysc_r32(SYSC_REG_CHIP_REV_ID) & 0xFFFF) == 0x0101) {
+ /* GE1, Force 1000M/FD, FC ON, MAX_RX_LENGTH 1536 */
+ mtk_switch_w32(gsw, MAC_MCR_FIXED_LINK, MTK_MAC_P2_MCR);
+ mt7530_mdio_w32(gsw, MT7530_PMCR_P(6), PMCR_FIXED_LINK);
+ } else {
+ /* GE1, Force 1000M/FD, FC ON, MAX_RX_LENGTH 1536 */
+ mtk_switch_w32(gsw, MAC_MCR_FIXED_LINK_FC, MTK_MAC_P1_MCR);
+ mt7530_mdio_w32(gsw, MT7530_PMCR_P(6), PMCR_FIXED_LINK_FC);
+ }
+
+ /* GE2, Link down */
+ mtk_switch_w32(gsw, MAC_MCR_FORCE_MODE, MTK_MAC_P2_MCR);
+
+ /* Enable Port 6, P5 as GMAC5, P5 disable */
+ val = mt7530_mdio_r32(gsw, MT7530_MHWTRAP);
+ /* Enable Port 6 */
+ val &= ~MHWTRAP_P6_DIS;
+ /* Disable Port 5 */
+ val |= MHWTRAP_P5_DIS;
+ /* manual override of HW-Trap */
+ val |= MHWTRAP_MANUAL;
+ mt7530_mdio_w32(gsw, MT7530_MHWTRAP, val);
+
+ val = rt_sysc_r32(SYSC_REG_CFG);
+ val = (val >> MT7621_XTAL_SHIFT) & MT7621_XTAL_MASK;
+ if (val < MT7621_XTAL_25 && val >= MT7621_XTAL_40) {
+ /* 40Mhz */
+
+ /* disable MT7530 core clock */
+ _mt7620_mii_write(gsw, 0, 13, 0x1f);
+ _mt7620_mii_write(gsw, 0, 14, 0x410);
+ _mt7620_mii_write(gsw, 0, 13, 0x401f);
+ _mt7620_mii_write(gsw, 0, 14, 0x0);
+
+ /* disable MT7530 PLL */
+ _mt7620_mii_write(gsw, 0, 13, 0x1f);
+ _mt7620_mii_write(gsw, 0, 14, 0x40d);
+ _mt7620_mii_write(gsw, 0, 13, 0x401f);
+ _mt7620_mii_write(gsw, 0, 14, 0x2020);
+
+ /* for MT7530 core clock = 500Mhz */
+ _mt7620_mii_write(gsw, 0, 13, 0x1f);
+ _mt7620_mii_write(gsw, 0, 14, 0x40e);
+ _mt7620_mii_write(gsw, 0, 13, 0x401f);
+ _mt7620_mii_write(gsw, 0, 14, 0x119);
+
+ /* enable MT7530 PLL */
+ _mt7620_mii_write(gsw, 0, 13, 0x1f);
+ _mt7620_mii_write(gsw, 0, 14, 0x40d);
+ _mt7620_mii_write(gsw, 0, 13, 0x401f);
+ _mt7620_mii_write(gsw, 0, 14, 0x2820);
+
+ usleep_range(20, 40);
+
+ /* enable MT7530 core clock */
+ _mt7620_mii_write(gsw, 0, 13, 0x1f);
+ _mt7620_mii_write(gsw, 0, 14, 0x410);
+ _mt7620_mii_write(gsw, 0, 13, 0x401f);
+ }
+
+ /* RGMII */
+ _mt7620_mii_write(gsw, 0, 14, 0x1);
+
+ /* set MT7530 central align */
+ mt7530_mdio_m32(gsw, BIT(0), P6ECR_INTF_MODE_RGMII, MT7530_P6ECR);
+ mt7530_mdio_m32(gsw, TRGMII_TXCTRL_TXC_INV, 0,
+ MT7530_TRGMII_TXCTRL);
+ mt7530_mdio_w32(gsw, MT7530_TRGMII_TCK_CTRL, 0x855);
+
+ /* delay setting for 10/1000M */
+ mt7530_mdio_w32(gsw, MT7530_P5RGMIIRXCR,
+ P5RGMIIRXCR_C_ALIGN | P5RGMIIRXCR_DELAY_2);
+ mt7530_mdio_w32(gsw, MT7530_P5RGMIITXCR, 0x14);
+
+ /* lower Tx Driving*/
+ mt7530_mdio_w32(gsw, MT7530_TRGMII_TD0_ODT, 0x44);
+ mt7530_mdio_w32(gsw, MT7530_TRGMII_TD1_ODT, 0x44);
+ mt7530_mdio_w32(gsw, MT7530_TRGMII_TD2_ODT, 0x44);
+ mt7530_mdio_w32(gsw, MT7530_TRGMII_TD3_ODT, 0x44);
+ mt7530_mdio_w32(gsw, MT7530_TRGMII_TD4_ODT, 0x44);
+ mt7530_mdio_w32(gsw, MT7530_TRGMII_TD5_ODT, 0x44);
+
+ /* turn on all PHYs */
+ for (i = 0; i <= 4; i++) {
+ val = _mt7620_mii_read(gsw, i, 0);
+ val &= ~BIT(11);
+ _mt7620_mii_write(gsw, i, 0, val);
+ }
+
+#define MT7530_NUM_PORTS 8
+#define REG_ESW_PORT_PCR(x) (0x2004 | ((x) << 8))
+#define REG_ESW_PORT_PVC(x) (0x2010 | ((x) << 8))
+#define REG_ESW_PORT_PPBV1(x) (0x2014 | ((x) << 8))
+#define MT7530_CPU_PORT 6
+
+ /* This is copied from mt7530_apply_config in libreCMC driver */
+ {
+ int i;
+ for (i = 0; i < MT7530_NUM_PORTS; i++)
+ mt7530_mdio_w32(gsw, REG_ESW_PORT_PCR(i), 0x00400000);
+
+ mt7530_mdio_w32(gsw, REG_ESW_PORT_PCR(MT7530_CPU_PORT), 0x00ff0000);
+
+ for (i = 0; i < MT7530_NUM_PORTS; i++)
+ mt7530_mdio_w32(gsw, REG_ESW_PORT_PVC(i), 0x810000c0);
+
+ }
+
+ /* enable irq */
+ mt7530_mdio_m32(gsw, 0, 3 << 16, MT7530_TOP_SIG_CTRL);
+ mt7530_mdio_w32(gsw, MT7530_SYS_INT_EN, 0x1f);
+
+}
+
+static const struct of_device_id mediatek_gsw_match[] = {
+ { .compatible = "mediatek,mt7621-gsw" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mediatek_gsw_match);
+
+int mtk_gsw_init(struct mtk_eth *eth)
+{
+ struct device_node *np = eth->switch_np;
+ struct platform_device *pdev = of_find_device_by_node(np);
+ struct mt7620_gsw *gsw;
+
+ if (!pdev)
+ return -ENODEV;
+
+ if (!of_device_is_compatible(np, mediatek_gsw_match->compatible))
+ return -EINVAL;
+
+ gsw = platform_get_drvdata(pdev);
+ eth->sw_priv = gsw;
+
+ if (!gsw->irq)
+ return -EINVAL;
+
+ request_irq(gsw->irq, gsw_interrupt_mt7621, 0,
+ "gsw", eth);
+ disable_irq(gsw->irq);
+
+ mt7621_hw_init(eth, gsw, np);
+
+ enable_irq(gsw->irq);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_gsw_init);
+
+static int mt7621_gsw_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct mt7620_gsw *gsw;
+
+ gsw = devm_kzalloc(&pdev->dev, sizeof(struct mt7620_gsw), GFP_KERNEL);
+ if (!gsw)
+ return -ENOMEM;
+
+ gsw->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(gsw->base))
+ return PTR_ERR(gsw->base);
+
+ gsw->dev = &pdev->dev;
+ gsw->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+
+ platform_set_drvdata(pdev, gsw);
+
+ return 0;
+}
+
+static int mt7621_gsw_remove(struct platform_device *pdev)
+{
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver gsw_driver = {
+ .probe = mt7621_gsw_probe,
+ .remove = mt7621_gsw_remove,
+ .driver = {
+ .name = "mt7621-gsw",
+ .owner = THIS_MODULE,
+ .of_match_table = mediatek_gsw_match,
+ },
+};
+
+module_platform_driver(gsw_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("GBit switch driver for Mediatek MT7621 SoC");
diff --git a/drivers/staging/mt7621-eth/mdio.c b/drivers/staging/mt7621-eth/mdio.c
new file mode 100644
index 000000000000..9d713078ef90
--- /dev/null
+++ b/drivers/staging/mt7621-eth/mdio.c
@@ -0,0 +1,271 @@
+/* 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; version 2 of the License
+ *
+ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/phy.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
+
+#include "mtk_eth_soc.h"
+#include "mdio.h"
+
+static int mtk_mdio_reset(struct mii_bus *bus)
+{
+ /* TODO */
+ return 0;
+}
+
+static void mtk_phy_link_adjust(struct net_device *dev)
+{
+ struct mtk_eth *eth = netdev_priv(dev);
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&eth->phy->lock, flags);
+ for (i = 0; i < 8; i++) {
+ if (eth->phy->phy_node[i]) {
+ struct phy_device *phydev = eth->phy->phy[i];
+ int status_change = 0;
+
+ if (phydev->link)
+ if (eth->phy->duplex[i] != phydev->duplex ||
+ eth->phy->speed[i] != phydev->speed)
+ status_change = 1;
+
+ if (phydev->link != eth->link[i])
+ status_change = 1;
+
+ switch (phydev->speed) {
+ case SPEED_1000:
+ case SPEED_100:
+ case SPEED_10:
+ eth->link[i] = phydev->link;
+ eth->phy->duplex[i] = phydev->duplex;
+ eth->phy->speed[i] = phydev->speed;
+
+ if (status_change &&
+ eth->soc->mdio_adjust_link)
+ eth->soc->mdio_adjust_link(eth, i);
+ break;
+ }
+ }
+ }
+}
+
+int mtk_connect_phy_node(struct mtk_eth *eth, struct mtk_mac *mac,
+ struct device_node *phy_node)
+{
+ const __be32 *_port = NULL;
+ struct phy_device *phydev;
+ int phy_mode, port;
+
+ _port = of_get_property(phy_node, "reg", NULL);
+
+ if (!_port || (be32_to_cpu(*_port) >= 0x20)) {
+ pr_err("%s: invalid port id\n", phy_node->name);
+ return -EINVAL;
+ }
+ port = be32_to_cpu(*_port);
+ phy_mode = of_get_phy_mode(phy_node);
+ if (phy_mode < 0) {
+ dev_err(eth->dev, "incorrect phy-mode %d\n", phy_mode);
+ eth->phy->phy_node[port] = NULL;
+ return -EINVAL;
+ }
+
+ phydev = of_phy_connect(eth->netdev[mac->id], phy_node,
+ mtk_phy_link_adjust, 0, phy_mode);
+ if (!phydev) {
+ dev_err(eth->dev, "could not connect to PHY\n");
+ eth->phy->phy_node[port] = NULL;
+ return -ENODEV;
+ }
+
+ phydev->supported &= PHY_GBIT_FEATURES;
+ phydev->advertising = phydev->supported;
+
+ dev_info(eth->dev,
+ "connected port %d to PHY at %s [uid=%08x, driver=%s]\n",
+ port, phydev_name(phydev), phydev->phy_id,
+ phydev->drv->name);
+
+ eth->phy->phy[port] = phydev;
+ eth->link[port] = 0;
+
+ return 0;
+}
+
+static void phy_init(struct mtk_eth *eth, struct mtk_mac *mac,
+ struct phy_device *phy)
+{
+ phy_attach(eth->netdev[mac->id], phydev_name(phy),
+ PHY_INTERFACE_MODE_MII);
+
+ phy->autoneg = AUTONEG_ENABLE;
+ phy->speed = 0;
+ phy->duplex = 0;
+ phy->supported &= PHY_BASIC_FEATURES;
+ phy->advertising = phy->supported | ADVERTISED_Autoneg;
+
+ phy_start_aneg(phy);
+}
+
+static int mtk_phy_connect(struct mtk_mac *mac)
+{
+ struct mtk_eth *eth = mac->hw;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ if (eth->phy->phy_node[i]) {
+ if (!mac->phy_dev) {
+ mac->phy_dev = eth->phy->phy[i];
+ mac->phy_flags = MTK_PHY_FLAG_PORT;
+ }
+ } else if (eth->mii_bus) {
+ struct phy_device *phy;
+ phy = mdiobus_get_phy(eth->mii_bus, i);
+ if (phy) {
+ phy_init(eth, mac, phy);
+ if (!mac->phy_dev) {
+ mac->phy_dev = phy;
+ mac->phy_flags = MTK_PHY_FLAG_ATTACH;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void mtk_phy_disconnect(struct mtk_mac *mac)
+{
+ struct mtk_eth *eth = mac->hw;
+ unsigned long flags;
+ int i;
+
+ for (i = 0; i < 8; i++)
+ if (eth->phy->phy_fixed[i]) {
+ spin_lock_irqsave(&eth->phy->lock, flags);
+ eth->link[i] = 0;
+ if (eth->soc->mdio_adjust_link)
+ eth->soc->mdio_adjust_link(eth, i);
+ spin_unlock_irqrestore(&eth->phy->lock, flags);
+ } else if (eth->phy->phy[i]) {
+ phy_disconnect(eth->phy->phy[i]);
+ } else if (eth->mii_bus) {
+ struct phy_device *phy = mdiobus_get_phy(eth->mii_bus, i);
+ if (phy)
+ phy_detach(phy);
+ }
+}
+
+static void mtk_phy_start(struct mtk_mac *mac)
+{
+ struct mtk_eth *eth = mac->hw;
+ unsigned long flags;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ if (eth->phy->phy_fixed[i]) {
+ spin_lock_irqsave(&eth->phy->lock, flags);
+ eth->link[i] = 1;
+ if (eth->soc->mdio_adjust_link)
+ eth->soc->mdio_adjust_link(eth, i);
+ spin_unlock_irqrestore(&eth->phy->lock, flags);
+ } else if (eth->phy->phy[i]) {
+ phy_start(eth->phy->phy[i]);
+ }
+ }
+}
+
+static void mtk_phy_stop(struct mtk_mac *mac)
+{
+ struct mtk_eth *eth = mac->hw;
+ unsigned long flags;
+ int i;
+
+ for (i = 0; i < 8; i++)
+ if (eth->phy->phy_fixed[i]) {
+ spin_lock_irqsave(&eth->phy->lock, flags);
+ eth->link[i] = 0;
+ if (eth->soc->mdio_adjust_link)
+ eth->soc->mdio_adjust_link(eth, i);
+ spin_unlock_irqrestore(&eth->phy->lock, flags);
+ } else if (eth->phy->phy[i]) {
+ phy_stop(eth->phy->phy[i]);
+ }
+}
+
+static struct mtk_phy phy_ralink = {
+ .connect = mtk_phy_connect,
+ .disconnect = mtk_phy_disconnect,
+ .start = mtk_phy_start,
+ .stop = mtk_phy_stop,
+};
+
+int mtk_mdio_init(struct mtk_eth *eth)
+{
+ struct device_node *mii_np;
+ int err;
+
+ if (!eth->soc->mdio_read || !eth->soc->mdio_write)
+ return 0;
+
+ spin_lock_init(&phy_ralink.lock);
+ eth->phy = &phy_ralink;
+
+ mii_np = of_get_child_by_name(eth->dev->of_node, "mdio-bus");
+ if (!mii_np) {
+ dev_err(eth->dev, "no %s child node found", "mdio-bus");
+ return -ENODEV;
+ }
+
+ if (!of_device_is_available(mii_np)) {
+ err = 0;
+ goto err_put_node;
+ }
+
+ eth->mii_bus = mdiobus_alloc();
+ if (!eth->mii_bus) {
+ err = -ENOMEM;
+ goto err_put_node;
+ }
+
+ eth->mii_bus->name = "mdio";
+ eth->mii_bus->read = eth->soc->mdio_read;
+ eth->mii_bus->write = eth->soc->mdio_write;
+ eth->mii_bus->reset = mtk_mdio_reset;
+ eth->mii_bus->priv = eth;
+ eth->mii_bus->parent = eth->dev;
+
+ snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%s", mii_np->name);
+ err = of_mdiobus_register(eth->mii_bus, mii_np);
+ if (err)
+ goto err_free_bus;
+
+ return 0;
+
+err_free_bus:
+ kfree(eth->mii_bus);
+err_put_node:
+ of_node_put(mii_np);
+ eth->mii_bus = NULL;
+ return err;
+}
+
+void mtk_mdio_cleanup(struct mtk_eth *eth)
+{
+ if (!eth->mii_bus)
+ return;
+
+ mdiobus_unregister(eth->mii_bus);
+ of_node_put(eth->mii_bus->dev.of_node);
+ kfree(eth->mii_bus);
+}
diff --git a/drivers/staging/mt7621-eth/mdio.h b/drivers/staging/mt7621-eth/mdio.h
new file mode 100644
index 000000000000..b14e23842a01
--- /dev/null
+++ b/drivers/staging/mt7621-eth/mdio.h
@@ -0,0 +1,27 @@
+/* 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; 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.
+ *
+ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#ifndef _RALINK_MDIO_H__
+#define _RALINK_MDIO_H__
+
+#ifdef CONFIG_NET_MEDIATEK_MDIO
+int mtk_mdio_init(struct mtk_eth *eth);
+void mtk_mdio_cleanup(struct mtk_eth *eth);
+int mtk_connect_phy_node(struct mtk_eth *eth, struct mtk_mac *mac,
+ struct device_node *phy_node);
+#else
+static inline int mtk_mdio_init(struct mtk_eth *eth) { return 0; }
+static inline void mtk_mdio_cleanup(struct mtk_eth *eth) {}
+#endif
+#endif
diff --git a/drivers/staging/mt7621-eth/mdio_mt7620.c b/drivers/staging/mt7621-eth/mdio_mt7620.c
new file mode 100644
index 000000000000..ced605c2914e
--- /dev/null
+++ b/drivers/staging/mt7621-eth/mdio_mt7620.c
@@ -0,0 +1,173 @@
+/* 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; 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.
+ *
+ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include "mtk_eth_soc.h"
+#include "gsw_mt7620.h"
+#include "mdio.h"
+
+static int mt7620_mii_busy_wait(struct mt7620_gsw *gsw)
+{
+ unsigned long t_start = jiffies;
+
+ while (1) {
+ if (!(mtk_switch_r32(gsw,
+ gsw->piac_offset + MT7620_GSW_REG_PIAC) &
+ GSW_MDIO_ACCESS))
+ return 0;
+ if (time_after(jiffies, t_start + GSW_REG_PHY_TIMEOUT))
+ break;
+ }
+
+ dev_err(gsw->dev, "mdio: MDIO timeout\n");
+ return -1;
+}
+
+u32 _mt7620_mii_write(struct mt7620_gsw *gsw, u32 phy_addr,
+ u32 phy_register, u32 write_data)
+{
+ if (mt7620_mii_busy_wait(gsw))
+ return -1;
+
+ write_data &= 0xffff;
+
+ mtk_switch_w32(gsw, GSW_MDIO_ACCESS | GSW_MDIO_START | GSW_MDIO_WRITE |
+ (phy_register << GSW_MDIO_REG_SHIFT) |
+ (phy_addr << GSW_MDIO_ADDR_SHIFT) | write_data,
+ MT7620_GSW_REG_PIAC);
+
+ if (mt7620_mii_busy_wait(gsw))
+ return -1;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(_mt7620_mii_write);
+
+u32 _mt7620_mii_read(struct mt7620_gsw *gsw, int phy_addr, int phy_reg)
+{
+ u32 d;
+
+ if (mt7620_mii_busy_wait(gsw))
+ return 0xffff;
+
+ mtk_switch_w32(gsw, GSW_MDIO_ACCESS | GSW_MDIO_START | GSW_MDIO_READ |
+ (phy_reg << GSW_MDIO_REG_SHIFT) |
+ (phy_addr << GSW_MDIO_ADDR_SHIFT),
+ MT7620_GSW_REG_PIAC);
+
+ if (mt7620_mii_busy_wait(gsw))
+ return 0xffff;
+
+ d = mtk_switch_r32(gsw, MT7620_GSW_REG_PIAC) & 0xffff;
+
+ return d;
+}
+EXPORT_SYMBOL_GPL(_mt7620_mii_read);
+
+int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val)
+{
+ struct mtk_eth *eth = bus->priv;
+ struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv;
+
+ return _mt7620_mii_write(gsw, phy_addr, phy_reg, val);
+}
+
+int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg)
+{
+ struct mtk_eth *eth = bus->priv;
+ struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv;
+
+ return _mt7620_mii_read(gsw, phy_addr, phy_reg);
+}
+
+void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val)
+{
+ _mt7620_mii_write(gsw, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
+ _mt7620_mii_write(gsw, 0x1f, (reg >> 2) & 0xf, val & 0xffff);
+ _mt7620_mii_write(gsw, 0x1f, 0x10, val >> 16);
+}
+EXPORT_SYMBOL_GPL(mt7530_mdio_w32);
+
+u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg)
+{
+ u16 high, low;
+
+ _mt7620_mii_write(gsw, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
+ low = _mt7620_mii_read(gsw, 0x1f, (reg >> 2) & 0xf);
+ high = _mt7620_mii_read(gsw, 0x1f, 0x10);
+
+ return (high << 16) | (low & 0xffff);
+}
+EXPORT_SYMBOL_GPL(mt7530_mdio_r32);
+
+void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg)
+{
+ u32 val = mt7530_mdio_r32(gsw, reg);
+
+ val &= ~mask;
+ val |= set;
+ mt7530_mdio_w32(gsw, reg, val);
+}
+EXPORT_SYMBOL_GPL(mt7530_mdio_m32);
+
+static unsigned char *mtk_speed_str(int speed)
+{
+ switch (speed) {
+ case 2:
+ case SPEED_1000:
+ return "1000";
+ case 1:
+ case SPEED_100:
+ return "100";
+ case 0:
+ case SPEED_10:
+ return "10";
+ }
+
+ return "? ";
+}
+
+int mt7620_has_carrier(struct mtk_eth *eth)
+{
+ struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv;
+ int i;
+
+ for (i = 0; i < GSW_PORT6; i++)
+ if (mt7530_mdio_r32(gsw, GSW_REG_PORT_STATUS(i)) & 0x1)
+ return 1;
+ return 0;
+}
+
+void mt7620_print_link_state(struct mtk_eth *eth, int port, int link,
+ int speed, int duplex)
+{
+ struct mt7620_gsw *gsw = eth->sw_priv;
+
+ if (link)
+ dev_info(gsw->dev, "port %d link up (%sMbps/%s duplex)\n",
+ port, mtk_speed_str(speed),
+ (duplex) ? "Full" : "Half");
+ else
+ dev_info(gsw->dev, "port %d link down\n", port);
+}
+
+void mt7620_mdio_link_adjust(struct mtk_eth *eth, int port)
+{
+ mt7620_print_link_state(eth, port, eth->link[port],
+ eth->phy->speed[port],
+ (eth->phy->duplex[port] == DUPLEX_FULL));
+}
diff --git a/drivers/staging/mt7621-eth/mtk_eth_soc.c b/drivers/staging/mt7621-eth/mtk_eth_soc.c
new file mode 100644
index 000000000000..cbc7339843a5
--- /dev/null
+++ b/drivers/staging/mt7621-eth/mtk_eth_soc.c
@@ -0,0 +1,2178 @@
+/* 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; 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.
+ *
+ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/clk.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
+#include <linux/if_vlan.h>
+#include <linux/reset.h>
+#include <linux/tcp.h>
+#include <linux/io.h>
+#include <linux/bug.h>
+#include <linux/regmap.h>
+
+#include "mtk_eth_soc.h"
+#include "mdio.h"
+#include "ethtool.h"
+
+#define MAX_RX_LENGTH 1536
+#define MTK_RX_ETH_HLEN (VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)
+#define MTK_RX_HLEN (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN)
+#define DMA_DUMMY_DESC 0xffffffff
+#define MTK_DEFAULT_MSG_ENABLE \
+ (NETIF_MSG_DRV | \
+ NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK | \
+ NETIF_MSG_TIMER | \
+ NETIF_MSG_IFDOWN | \
+ NETIF_MSG_IFUP | \
+ NETIF_MSG_RX_ERR | \
+ NETIF_MSG_TX_ERR)
+
+#define TX_DMA_DESP2_DEF (TX_DMA_LS0 | TX_DMA_DONE)
+#define NEXT_TX_DESP_IDX(X) (((X) + 1) & (ring->tx_ring_size - 1))
+#define NEXT_RX_DESP_IDX(X) (((X) + 1) & (ring->rx_ring_size - 1))
+
+#define SYSC_REG_RSTCTRL 0x34
+
+static int mtk_msg_level = -1;
+module_param_named(msg_level, mtk_msg_level, int, 0);
+MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)");
+
+static const u16 mtk_reg_table_default[MTK_REG_COUNT] = {
+ [MTK_REG_PDMA_GLO_CFG] = MTK_PDMA_GLO_CFG,
+ [MTK_REG_PDMA_RST_CFG] = MTK_PDMA_RST_CFG,
+ [MTK_REG_DLY_INT_CFG] = MTK_DLY_INT_CFG,
+ [MTK_REG_TX_BASE_PTR0] = MTK_TX_BASE_PTR0,
+ [MTK_REG_TX_MAX_CNT0] = MTK_TX_MAX_CNT0,
+ [MTK_REG_TX_CTX_IDX0] = MTK_TX_CTX_IDX0,
+ [MTK_REG_TX_DTX_IDX0] = MTK_TX_DTX_IDX0,
+ [MTK_REG_RX_BASE_PTR0] = MTK_RX_BASE_PTR0,
+ [MTK_REG_RX_MAX_CNT0] = MTK_RX_MAX_CNT0,
+ [MTK_REG_RX_CALC_IDX0] = MTK_RX_CALC_IDX0,
+ [MTK_REG_RX_DRX_IDX0] = MTK_RX_DRX_IDX0,
+ [MTK_REG_MTK_INT_ENABLE] = MTK_INT_ENABLE,
+ [MTK_REG_MTK_INT_STATUS] = MTK_INT_STATUS,
+ [MTK_REG_MTK_DMA_VID_BASE] = MTK_DMA_VID0,
+ [MTK_REG_MTK_COUNTER_BASE] = MTK_GDMA1_TX_GBCNT,
+ [MTK_REG_MTK_RST_GL] = MTK_RST_GL,
+};
+
+static const u16 *mtk_reg_table = mtk_reg_table_default;
+
+void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)
+{
+ __raw_writel(val, eth->base + reg);
+}
+
+u32 mtk_r32(struct mtk_eth *eth, unsigned reg)
+{
+ return __raw_readl(eth->base + reg);
+}
+
+static void mtk_reg_w32(struct mtk_eth *eth, u32 val, enum mtk_reg reg)
+{
+ mtk_w32(eth, val, mtk_reg_table[reg]);
+}
+
+static u32 mtk_reg_r32(struct mtk_eth *eth, enum mtk_reg reg)
+{
+ return mtk_r32(eth, mtk_reg_table[reg]);
+}
+
+/* these bits are also exposed via the reset-controller API. however the switch
+ * and FE need to be brought out of reset in the exakt same moemtn and the
+ * reset-controller api does not provide this feature yet. Do the reset manually
+ * until we fixed the reset-controller api to be able to do this
+ */
+void mtk_reset(struct mtk_eth *eth, u32 reset_bits)
+{
+ u32 val;
+
+ regmap_read(eth->ethsys, SYSC_REG_RSTCTRL, &val);
+ val |= reset_bits;
+ regmap_write(eth->ethsys, SYSC_REG_RSTCTRL, val);
+ usleep_range(10, 20);
+ val &= ~reset_bits;
+ regmap_write(eth->ethsys, SYSC_REG_RSTCTRL, val);
+ usleep_range(10, 20);
+}
+EXPORT_SYMBOL(mtk_reset);
+
+static inline void mtk_irq_ack(struct mtk_eth *eth, u32 mask)
+{
+ if (eth->soc->dma_type & MTK_PDMA)
+ mtk_reg_w32(eth, mask, MTK_REG_MTK_INT_STATUS);
+ if (eth->soc->dma_type & MTK_QDMA)
+ mtk_w32(eth, mask, MTK_QMTK_INT_STATUS);
+}
+
+static inline u32 mtk_irq_pending(struct mtk_eth *eth)
+{
+ u32 status = 0;
+
+ if (eth->soc->dma_type & MTK_PDMA)
+ status |= mtk_reg_r32(eth, MTK_REG_MTK_INT_STATUS);
+ if (eth->soc->dma_type & MTK_QDMA)
+ status |= mtk_r32(eth, MTK_QMTK_INT_STATUS);
+
+ return status;
+}
+
+static void mtk_irq_ack_status(struct mtk_eth *eth, u32 mask)
+{
+ u32 status_reg = MTK_REG_MTK_INT_STATUS;
+
+ if (mtk_reg_table[MTK_REG_MTK_INT_STATUS2])
+ status_reg = MTK_REG_MTK_INT_STATUS2;
+
+ mtk_reg_w32(eth, mask, status_reg);
+}
+
+static u32 mtk_irq_pending_status(struct mtk_eth *eth)
+{
+ u32 status_reg = MTK_REG_MTK_INT_STATUS;
+
+ if (mtk_reg_table[MTK_REG_MTK_INT_STATUS2])
+ status_reg = MTK_REG_MTK_INT_STATUS2;
+
+ return mtk_reg_r32(eth, status_reg);
+}
+
+static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
+{
+ u32 val;
+
+ if (eth->soc->dma_type & MTK_PDMA) {
+ val = mtk_reg_r32(eth, MTK_REG_MTK_INT_ENABLE);
+ mtk_reg_w32(eth, val & ~mask, MTK_REG_MTK_INT_ENABLE);
+ /* flush write */
+ mtk_reg_r32(eth, MTK_REG_MTK_INT_ENABLE);
+ }
+ if (eth->soc->dma_type & MTK_QDMA) {
+ val = mtk_r32(eth, MTK_QMTK_INT_ENABLE);
+ mtk_w32(eth, val & ~mask, MTK_QMTK_INT_ENABLE);
+ /* flush write */
+ mtk_r32(eth, MTK_QMTK_INT_ENABLE);
+ }
+}
+
+static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask)
+{
+ u32 val;
+
+ if (eth->soc->dma_type & MTK_PDMA) {
+ val = mtk_reg_r32(eth, MTK_REG_MTK_INT_ENABLE);
+ mtk_reg_w32(eth, val | mask, MTK_REG_MTK_INT_ENABLE);
+ /* flush write */
+ mtk_reg_r32(eth, MTK_REG_MTK_INT_ENABLE);
+ }
+ if (eth->soc->dma_type & MTK_QDMA) {
+ val = mtk_r32(eth, MTK_QMTK_INT_ENABLE);
+ mtk_w32(eth, val | mask, MTK_QMTK_INT_ENABLE);
+ /* flush write */
+ mtk_r32(eth, MTK_QMTK_INT_ENABLE);
+ }
+}
+
+static inline u32 mtk_irq_enabled(struct mtk_eth *eth)
+{
+ u32 enabled = 0;
+
+ if (eth->soc->dma_type & MTK_PDMA)
+ enabled |= mtk_reg_r32(eth, MTK_REG_MTK_INT_ENABLE);
+ if (eth->soc->dma_type & MTK_QDMA)
+ enabled |= mtk_r32(eth, MTK_QMTK_INT_ENABLE);
+
+ return enabled;
+}
+
+static inline void mtk_hw_set_macaddr(struct mtk_mac *mac,
+ unsigned char *macaddr)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mac->hw->page_lock, flags);
+ mtk_w32(mac->hw, (macaddr[0] << 8) | macaddr[1], MTK_GDMA1_MAC_ADRH);
+ mtk_w32(mac->hw, (macaddr[2] << 24) | (macaddr[3] << 16) |
+ (macaddr[4] << 8) | macaddr[5],
+ MTK_GDMA1_MAC_ADRL);
+ spin_unlock_irqrestore(&mac->hw->page_lock, flags);
+}
+
+static int mtk_set_mac_address(struct net_device *dev, void *p)
+{
+ int ret = eth_mac_addr(dev, p);
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+
+ if (ret)
+ return ret;
+
+ if (eth->soc->set_mac)
+ eth->soc->set_mac(mac, dev->dev_addr);
+ else
+ mtk_hw_set_macaddr(mac, p);
+
+ return 0;
+}
+
+static inline int mtk_max_frag_size(int mtu)
+{
+ /* make sure buf_size will be at least MAX_RX_LENGTH */
+ if (mtu + MTK_RX_ETH_HLEN < MAX_RX_LENGTH)
+ mtu = MAX_RX_LENGTH - MTK_RX_ETH_HLEN;
+
+ return SKB_DATA_ALIGN(MTK_RX_HLEN + mtu) +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+}
+
+static inline int mtk_max_buf_size(int frag_size)
+{
+ int buf_size = frag_size - NET_SKB_PAD - NET_IP_ALIGN -
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+ WARN_ON(buf_size < MAX_RX_LENGTH);
+
+ return buf_size;
+}
+
+static inline void mtk_get_rxd(struct mtk_rx_dma *rxd,
+ struct mtk_rx_dma *dma_rxd)
+{
+ rxd->rxd1 = READ_ONCE(dma_rxd->rxd1);
+ rxd->rxd2 = READ_ONCE(dma_rxd->rxd2);
+ rxd->rxd3 = READ_ONCE(dma_rxd->rxd3);
+ rxd->rxd4 = READ_ONCE(dma_rxd->rxd4);
+}
+
+static inline void mtk_set_txd_pdma(struct mtk_tx_dma *txd,
+ struct mtk_tx_dma *dma_txd)
+{
+ WRITE_ONCE(dma_txd->txd1, txd->txd1);
+ WRITE_ONCE(dma_txd->txd3, txd->txd3);
+ WRITE_ONCE(dma_txd->txd4, txd->txd4);
+ /* clean dma done flag last */
+ WRITE_ONCE(dma_txd->txd2, txd->txd2);
+}
+
+static void mtk_clean_rx(struct mtk_eth *eth, struct mtk_rx_ring *ring)
+{
+ int i;
+
+ if (ring->rx_data && ring->rx_dma) {
+ for (i = 0; i < ring->rx_ring_size; i++) {
+ if (!ring->rx_data[i])
+ continue;
+ if (!ring->rx_dma[i].rxd1)
+ continue;
+ dma_unmap_single(eth->dev,
+ ring->rx_dma[i].rxd1,
+ ring->rx_buf_size,
+ DMA_FROM_DEVICE);
+ skb_free_frag(ring->rx_data[i]);
+ }
+ kfree(ring->rx_data);
+ ring->rx_data = NULL;
+ }
+
+ if (ring->rx_dma) {
+ dma_free_coherent(eth->dev,
+ ring->rx_ring_size * sizeof(*ring->rx_dma),
+ ring->rx_dma,
+ ring->rx_phys);
+ ring->rx_dma = NULL;
+ }
+}
+
+static int mtk_dma_rx_alloc(struct mtk_eth *eth, struct mtk_rx_ring *ring)
+{
+ int i, pad = 0;
+
+ ring->frag_size = mtk_max_frag_size(ETH_DATA_LEN);
+ ring->rx_buf_size = mtk_max_buf_size(ring->frag_size);
+ ring->rx_ring_size = eth->soc->dma_ring_size;
+ ring->rx_data = kcalloc(ring->rx_ring_size, sizeof(*ring->rx_data),
+ GFP_KERNEL);
+ if (!ring->rx_data)
+ goto no_rx_mem;
+
+ for (i = 0; i < ring->rx_ring_size; i++) {
+ ring->rx_data[i] = netdev_alloc_frag(ring->frag_size);
+ if (!ring->rx_data[i])
+ goto no_rx_mem;
+ }
+
+ ring->rx_dma = dma_alloc_coherent(eth->dev,
+ ring->rx_ring_size * sizeof(*ring->rx_dma),
+ &ring->rx_phys,
+ GFP_ATOMIC | __GFP_ZERO);
+ if (!ring->rx_dma)
+ goto no_rx_mem;
+
+ if (!eth->soc->rx_2b_offset)
+ pad = NET_IP_ALIGN;
+
+ for (i = 0; i < ring->rx_ring_size; i++) {
+ dma_addr_t dma_addr = dma_map_single(eth->dev,
+ ring->rx_data[i] + NET_SKB_PAD + pad,
+ ring->rx_buf_size,
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(eth->dev, dma_addr)))
+ goto no_rx_mem;
+ ring->rx_dma[i].rxd1 = (unsigned int)dma_addr;
+
+ if (eth->soc->rx_sg_dma)
+ ring->rx_dma[i].rxd2 = RX_DMA_PLEN0(ring->rx_buf_size);
+ else
+ ring->rx_dma[i].rxd2 = RX_DMA_LSO;
+ }
+ ring->rx_calc_idx = ring->rx_ring_size - 1;
+ /* make sure that all changes to the dma ring are flushed before we
+ * continue
+ */
+ wmb();
+
+ return 0;
+
+no_rx_mem:
+ return -ENOMEM;
+}
+
+static void mtk_txd_unmap(struct device *dev, struct mtk_tx_buf *tx_buf)
+{
+ if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) {
+ dma_unmap_single(dev,
+ dma_unmap_addr(tx_buf, dma_addr0),
+ dma_unmap_len(tx_buf, dma_len0),
+ DMA_TO_DEVICE);
+ } else if (tx_buf->flags & MTK_TX_FLAGS_PAGE0) {
+ dma_unmap_page(dev,
+ dma_unmap_addr(tx_buf, dma_addr0),
+ dma_unmap_len(tx_buf, dma_len0),
+ DMA_TO_DEVICE);
+ }
+ if (tx_buf->flags & MTK_TX_FLAGS_PAGE1)
+ dma_unmap_page(dev,
+ dma_unmap_addr(tx_buf, dma_addr1),
+ dma_unmap_len(tx_buf, dma_len1),
+ DMA_TO_DEVICE);
+
+ tx_buf->flags = 0;
+ if (tx_buf->skb && (tx_buf->skb != (struct sk_buff *)DMA_DUMMY_DESC))
+ dev_kfree_skb_any(tx_buf->skb);
+ tx_buf->skb = NULL;
+}
+
+static void mtk_pdma_tx_clean(struct mtk_eth *eth)
+{
+ struct mtk_tx_ring *ring = &eth->tx_ring;
+ int i;
+
+ if (ring->tx_buf) {
+ for (i = 0; i < ring->tx_ring_size; i++)
+ mtk_txd_unmap(eth->dev, &ring->tx_buf[i]);
+ kfree(ring->tx_buf);
+ ring->tx_buf = NULL;
+ }
+
+ if (ring->tx_dma) {
+ dma_free_coherent(eth->dev,
+ ring->tx_ring_size * sizeof(*ring->tx_dma),
+ ring->tx_dma,
+ ring->tx_phys);
+ ring->tx_dma = NULL;
+ }
+}
+
+static void mtk_qdma_tx_clean(struct mtk_eth *eth)
+{
+ struct mtk_tx_ring *ring = &eth->tx_ring;
+ int i;
+
+ if (ring->tx_buf) {
+ for (i = 0; i < ring->tx_ring_size; i++)
+ mtk_txd_unmap(eth->dev, &ring->tx_buf[i]);
+ kfree(ring->tx_buf);
+ ring->tx_buf = NULL;
+ }
+
+ if (ring->tx_dma) {
+ dma_free_coherent(eth->dev,
+ ring->tx_ring_size * sizeof(*ring->tx_dma),
+ ring->tx_dma,
+ ring->tx_phys);
+ ring->tx_dma = NULL;
+ }
+}
+
+void mtk_stats_update_mac(struct mtk_mac *mac)
+{
+ struct mtk_hw_stats *hw_stats = mac->hw_stats;
+ unsigned int base = mtk_reg_table[MTK_REG_MTK_COUNTER_BASE];
+ u64 stats;
+
+ base += hw_stats->reg_offset;
+
+ u64_stats_update_begin(&hw_stats->syncp);
+
+ if (mac->hw->soc->new_stats) {
+ hw_stats->rx_bytes += mtk_r32(mac->hw, base);
+ stats = mtk_r32(mac->hw, base + 0x04);
+ if (stats)
+ hw_stats->rx_bytes += (stats << 32);
+ hw_stats->rx_packets += mtk_r32(mac->hw, base + 0x08);
+ hw_stats->rx_overflow += mtk_r32(mac->hw, base + 0x10);
+ hw_stats->rx_fcs_errors += mtk_r32(mac->hw, base + 0x14);
+ hw_stats->rx_short_errors += mtk_r32(mac->hw, base + 0x18);
+ hw_stats->rx_long_errors += mtk_r32(mac->hw, base + 0x1c);
+ hw_stats->rx_checksum_errors += mtk_r32(mac->hw, base + 0x20);
+ hw_stats->rx_flow_control_packets +=
+ mtk_r32(mac->hw, base + 0x24);
+ hw_stats->tx_skip += mtk_r32(mac->hw, base + 0x28);
+ hw_stats->tx_collisions += mtk_r32(mac->hw, base + 0x2c);
+ hw_stats->tx_bytes += mtk_r32(mac->hw, base + 0x30);
+ stats = mtk_r32(mac->hw, base + 0x34);
+ if (stats)
+ hw_stats->tx_bytes += (stats << 32);
+ hw_stats->tx_packets += mtk_r32(mac->hw, base + 0x38);
+ } else {
+ hw_stats->tx_bytes += mtk_r32(mac->hw, base);
+ hw_stats->tx_packets += mtk_r32(mac->hw, base + 0x04);
+ hw_stats->tx_skip += mtk_r32(mac->hw, base + 0x08);
+ hw_stats->tx_collisions += mtk_r32(mac->hw, base + 0x0c);
+ hw_stats->rx_bytes += mtk_r32(mac->hw, base + 0x20);
+ hw_stats->rx_packets += mtk_r32(mac->hw, base + 0x24);
+ hw_stats->rx_overflow += mtk_r32(mac->hw, base + 0x28);
+ hw_stats->rx_fcs_errors += mtk_r32(mac->hw, base + 0x2c);
+ hw_stats->rx_short_errors += mtk_r32(mac->hw, base + 0x30);
+ hw_stats->rx_long_errors += mtk_r32(mac->hw, base + 0x34);
+ hw_stats->rx_checksum_errors += mtk_r32(mac->hw, base + 0x38);
+ hw_stats->rx_flow_control_packets +=
+ mtk_r32(mac->hw, base + 0x3c);
+ }
+
+ u64_stats_update_end(&hw_stats->syncp);
+}
+
+static void mtk_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *storage)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_hw_stats *hw_stats = mac->hw_stats;
+ unsigned int base = mtk_reg_table[MTK_REG_MTK_COUNTER_BASE];
+ unsigned int start;
+
+ if (!base) {
+ netdev_stats_to_stats64(storage, &dev->stats);
+ return;
+ }
+
+ if (netif_running(dev) && netif_device_present(dev)) {
+ if (spin_trylock(&hw_stats->stats_lock)) {
+ mtk_stats_update_mac(mac);
+ spin_unlock(&hw_stats->stats_lock);
+ }
+ }
+
+ do {
+ start = u64_stats_fetch_begin_irq(&hw_stats->syncp);
+ storage->rx_packets = hw_stats->rx_packets;
+ storage->tx_packets = hw_stats->tx_packets;
+ storage->rx_bytes = hw_stats->rx_bytes;
+ storage->tx_bytes = hw_stats->tx_bytes;
+ storage->collisions = hw_stats->tx_collisions;
+ storage->rx_length_errors = hw_stats->rx_short_errors +
+ hw_stats->rx_long_errors;
+ storage->rx_over_errors = hw_stats->rx_overflow;
+ storage->rx_crc_errors = hw_stats->rx_fcs_errors;
+ storage->rx_errors = hw_stats->rx_checksum_errors;
+ storage->tx_aborted_errors = hw_stats->tx_skip;
+ } while (u64_stats_fetch_retry_irq(&hw_stats->syncp, start));
+
+ storage->tx_errors = dev->stats.tx_errors;
+ storage->rx_dropped = dev->stats.rx_dropped;
+ storage->tx_dropped = dev->stats.tx_dropped;
+}
+
+static int mtk_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+ u32 idx = (vid & 0xf);
+ u32 vlan_cfg;
+
+ if (!((mtk_reg_table[MTK_REG_MTK_DMA_VID_BASE]) &&
+ (dev->features & NETIF_F_HW_VLAN_CTAG_TX)))
+ return 0;
+
+ if (test_bit(idx, &eth->vlan_map)) {
+ netdev_warn(dev, "disable tx vlan offload\n");
+ dev->wanted_features &= ~NETIF_F_HW_VLAN_CTAG_TX;
+ netdev_update_features(dev);
+ } else {
+ vlan_cfg = mtk_r32(eth,
+ mtk_reg_table[MTK_REG_MTK_DMA_VID_BASE] +
+ ((idx >> 1) << 2));
+ if (idx & 0x1) {
+ vlan_cfg &= 0xffff;
+ vlan_cfg |= (vid << 16);
+ } else {
+ vlan_cfg &= 0xffff0000;
+ vlan_cfg |= vid;
+ }
+ mtk_w32(eth,
+ vlan_cfg, mtk_reg_table[MTK_REG_MTK_DMA_VID_BASE] +
+ ((idx >> 1) << 2));
+ set_bit(idx, &eth->vlan_map);
+ }
+
+ return 0;
+}
+
+static int mtk_vlan_rx_kill_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+ u32 idx = (vid & 0xf);
+
+ if (!((mtk_reg_table[MTK_REG_MTK_DMA_VID_BASE]) &&
+ (dev->features & NETIF_F_HW_VLAN_CTAG_TX)))
+ return 0;
+
+ clear_bit(idx, &eth->vlan_map);
+
+ return 0;
+}
+
+static inline u32 mtk_pdma_empty_txd(struct mtk_tx_ring *ring)
+{
+ barrier();
+ return (u32)(ring->tx_ring_size -
+ ((ring->tx_next_idx - ring->tx_free_idx) &
+ (ring->tx_ring_size - 1)));
+}
+
+static int mtk_skb_padto(struct sk_buff *skb, struct mtk_eth *eth)
+{
+ unsigned int len;
+ int ret;
+
+ if (unlikely(skb->len >= VLAN_ETH_ZLEN))
+ return 0;
+
+ if (eth->soc->padding_64b && !eth->soc->padding_bug)
+ return 0;
+
+ if (skb_vlan_tag_present(skb))
+ len = ETH_ZLEN;
+ else if (skb->protocol == cpu_to_be16(ETH_P_8021Q))
+ len = VLAN_ETH_ZLEN;
+ else if (!eth->soc->padding_64b)
+ len = ETH_ZLEN;
+ else
+ return 0;
+
+ if (skb->len >= len)
+ return 0;
+
+ ret = skb_pad(skb, len - skb->len);
+ if (ret < 0)
+ return ret;
+ skb->len = len;
+ skb_set_tail_pointer(skb, len);
+
+ return ret;
+}
+
+static int mtk_pdma_tx_map(struct sk_buff *skb, struct net_device *dev,
+ int tx_num, struct mtk_tx_ring *ring, bool gso)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+ struct skb_frag_struct *frag;
+ struct mtk_tx_dma txd, *ptxd;
+ struct mtk_tx_buf *tx_buf;
+ int i, j, k, frag_size, frag_map_size, offset;
+ dma_addr_t mapped_addr;
+ unsigned int nr_frags;
+ u32 def_txd4;
+
+ if (mtk_skb_padto(skb, eth)) {
+ netif_warn(eth, tx_err, dev, "tx padding failed!\n");
+ return -1;
+ }
+
+ tx_buf = &ring->tx_buf[ring->tx_next_idx];
+ memset(tx_buf, 0, sizeof(*tx_buf));
+ memset(&txd, 0, sizeof(txd));
+ nr_frags = skb_shinfo(skb)->nr_frags;
+
+ /* init tx descriptor */
+ def_txd4 = eth->soc->txd4;
+ txd.txd4 = def_txd4;
+
+ if (eth->soc->mac_count > 1)
+ txd.txd4 |= (mac->id + 1) << TX_DMA_FPORT_SHIFT;
+
+ if (gso)
+ txd.txd4 |= TX_DMA_TSO;
+
+ /* TX Checksum offload */
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ txd.txd4 |= TX_DMA_CHKSUM;
+
+ /* VLAN header offload */
+ if (skb_vlan_tag_present(skb)) {
+ u16 tag = skb_vlan_tag_get(skb);
+
+ txd.txd4 |= TX_DMA_INS_VLAN |
+ ((tag >> VLAN_PRIO_SHIFT) << 4) |
+ (tag & 0xF);
+ }
+
+ mapped_addr = dma_map_single(&dev->dev, skb->data,
+ skb_headlen(skb), DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(&dev->dev, mapped_addr)))
+ return -1;
+
+ txd.txd1 = mapped_addr;
+ txd.txd2 = TX_DMA_PLEN0(skb_headlen(skb));
+
+ tx_buf->flags |= MTK_TX_FLAGS_SINGLE0;
+ dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr);
+ dma_unmap_len_set(tx_buf, dma_len0, skb_headlen(skb));
+
+ /* TX SG offload */
+ j = ring->tx_next_idx;
+ k = 0;
+ for (i = 0; i < nr_frags; i++) {
+ offset = 0;
+ frag = &skb_shinfo(skb)->frags[i];
+ frag_size = skb_frag_size(frag);
+
+ while (frag_size > 0) {
+ frag_map_size = min(frag_size, TX_DMA_BUF_LEN);
+ mapped_addr = skb_frag_dma_map(&dev->dev, frag, offset,
+ frag_map_size,
+ DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(&dev->dev, mapped_addr)))
+ goto err_dma;
+
+ if (k & 0x1) {
+ j = NEXT_TX_DESP_IDX(j);
+ txd.txd1 = mapped_addr;
+ txd.txd2 = TX_DMA_PLEN0(frag_map_size);
+ txd.txd4 = def_txd4;
+
+ tx_buf = &ring->tx_buf[j];
+ memset(tx_buf, 0, sizeof(*tx_buf));
+
+ tx_buf->flags |= MTK_TX_FLAGS_PAGE0;
+ dma_unmap_addr_set(tx_buf, dma_addr0,
+ mapped_addr);
+ dma_unmap_len_set(tx_buf, dma_len0,
+ frag_map_size);
+ } else {
+ txd.txd3 = mapped_addr;
+ txd.txd2 |= TX_DMA_PLEN1(frag_map_size);
+
+ tx_buf->skb = (struct sk_buff *)DMA_DUMMY_DESC;
+ tx_buf->flags |= MTK_TX_FLAGS_PAGE1;
+ dma_unmap_addr_set(tx_buf, dma_addr1,
+ mapped_addr);
+ dma_unmap_len_set(tx_buf, dma_len1,
+ frag_map_size);
+
+ if (!((i == (nr_frags - 1)) &&
+ (frag_map_size == frag_size))) {
+ mtk_set_txd_pdma(&txd,
+ &ring->tx_dma[j]);
+ memset(&txd, 0, sizeof(txd));
+ }
+ }
+ frag_size -= frag_map_size;
+ offset += frag_map_size;
+ k++;
+ }
+ }
+
+ /* set last segment */
+ if (k & 0x1)
+ txd.txd2 |= TX_DMA_LS1;
+ else
+ txd.txd2 |= TX_DMA_LS0;
+ mtk_set_txd_pdma(&txd, &ring->tx_dma[j]);
+
+ /* store skb to cleanup */
+ tx_buf->skb = skb;
+
+ netdev_sent_queue(dev, skb->len);
+ skb_tx_timestamp(skb);
+
+ ring->tx_next_idx = NEXT_TX_DESP_IDX(j);
+ /* make sure that all changes to the dma ring are flushed before we
+ * continue
+ */
+ wmb();
+ atomic_set(&ring->tx_free_count, mtk_pdma_empty_txd(ring));
+
+ if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) || !skb->xmit_more)
+ mtk_reg_w32(eth, ring->tx_next_idx, MTK_REG_TX_CTX_IDX0);
+
+ return 0;
+
+err_dma:
+ j = ring->tx_next_idx;
+ for (i = 0; i < tx_num; i++) {
+ ptxd = &ring->tx_dma[j];
+ tx_buf = &ring->tx_buf[j];
+
+ /* unmap dma */
+ mtk_txd_unmap(&dev->dev, tx_buf);
+
+ ptxd->txd2 = TX_DMA_DESP2_DEF;
+ j = NEXT_TX_DESP_IDX(j);
+ }
+ /* make sure that all changes to the dma ring are flushed before we
+ * continue
+ */
+ wmb();
+ return -1;
+}
+
+/* the qdma core needs scratch memory to be setup */
+static int mtk_init_fq_dma(struct mtk_eth *eth)
+{
+ unsigned int phy_ring_head, phy_ring_tail;
+ int cnt = eth->soc->dma_ring_size;
+ dma_addr_t dma_addr;
+ int i;
+
+ eth->scratch_ring = dma_alloc_coherent(eth->dev,
+ cnt * sizeof(struct mtk_tx_dma),
+ &phy_ring_head,
+ GFP_ATOMIC | __GFP_ZERO);
+ if (unlikely(!eth->scratch_ring))
+ return -ENOMEM;
+
+ eth->scratch_head = kcalloc(cnt, QDMA_PAGE_SIZE,
+ GFP_KERNEL);
+ dma_addr = dma_map_single(eth->dev,
+ eth->scratch_head, cnt * QDMA_PAGE_SIZE,
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(eth->dev, dma_addr)))
+ return -ENOMEM;
+
+ memset(eth->scratch_ring, 0x0, sizeof(struct mtk_tx_dma) * cnt);
+ phy_ring_tail = phy_ring_head + (sizeof(struct mtk_tx_dma) * (cnt - 1));
+
+ for (i = 0; i < cnt; i++) {
+ eth->scratch_ring[i].txd1 = (dma_addr + (i * QDMA_PAGE_SIZE));
+ if (i < cnt - 1)
+ eth->scratch_ring[i].txd2 = (phy_ring_head +
+ ((i + 1) * sizeof(struct mtk_tx_dma)));
+ eth->scratch_ring[i].txd3 = TX_QDMA_SDL(QDMA_PAGE_SIZE);
+ }
+
+ mtk_w32(eth, phy_ring_head, MTK_QDMA_FQ_HEAD);
+ mtk_w32(eth, phy_ring_tail, MTK_QDMA_FQ_TAIL);
+ mtk_w32(eth, (cnt << 16) | cnt, MTK_QDMA_FQ_CNT);
+ mtk_w32(eth, QDMA_PAGE_SIZE << 16, MTK_QDMA_FQ_BLEN);
+
+ return 0;
+}
+
+static void *mtk_qdma_phys_to_virt(struct mtk_tx_ring *ring, u32 desc)
+{
+ void *ret = ring->tx_dma;
+
+ return ret + (desc - ring->tx_phys);
+}
+
+static struct mtk_tx_dma *mtk_tx_next_qdma(struct mtk_tx_ring *ring,
+ struct mtk_tx_dma *txd)
+{
+ return mtk_qdma_phys_to_virt(ring, txd->txd2);
+}
+
+static struct mtk_tx_buf *mtk_desc_to_tx_buf(struct mtk_tx_ring *ring,
+ struct mtk_tx_dma *txd)
+{
+ int idx = txd - ring->tx_dma;
+
+ return &ring->tx_buf[idx];
+}
+
+static int mtk_qdma_tx_map(struct sk_buff *skb, struct net_device *dev,
+ int tx_num, struct mtk_tx_ring *ring, bool gso)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+ struct mtk_tx_dma *itxd, *txd;
+ struct mtk_tx_buf *tx_buf;
+ dma_addr_t mapped_addr;
+ unsigned int nr_frags;
+ int i, n_desc = 1;
+ u32 txd4 = eth->soc->txd4;
+
+ itxd = ring->tx_next_free;
+ if (itxd == ring->tx_last_free)
+ return -ENOMEM;
+
+ if (eth->soc->mac_count > 1)
+ txd4 |= (mac->id + 1) << TX_DMA_FPORT_SHIFT;
+
+ tx_buf = mtk_desc_to_tx_buf(ring, itxd);
+ memset(tx_buf, 0, sizeof(*tx_buf));
+
+ if (gso)
+ txd4 |= TX_DMA_TSO;
+
+ /* TX Checksum offload */
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ txd4 |= TX_DMA_CHKSUM;
+
+ /* VLAN header offload */
+ if (skb_vlan_tag_present(skb))
+ txd4 |= TX_DMA_INS_VLAN_MT7621 | skb_vlan_tag_get(skb);
+
+ mapped_addr = dma_map_single(&dev->dev, skb->data,
+ skb_headlen(skb), DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(&dev->dev, mapped_addr)))
+ return -ENOMEM;
+
+ WRITE_ONCE(itxd->txd1, mapped_addr);
+ tx_buf->flags |= MTK_TX_FLAGS_SINGLE0;
+ dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr);
+ dma_unmap_len_set(tx_buf, dma_len0, skb_headlen(skb));
+
+ /* TX SG offload */
+ txd = itxd;
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ for (i = 0; i < nr_frags; i++) {
+ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+ unsigned int offset = 0;
+ int frag_size = skb_frag_size(frag);
+
+ while (frag_size) {
+ bool last_frag = false;
+ unsigned int frag_map_size;
+
+ txd = mtk_tx_next_qdma(ring, txd);
+ if (txd == ring->tx_last_free)
+ goto err_dma;
+
+ n_desc++;
+ frag_map_size = min(frag_size, TX_DMA_BUF_LEN);
+ mapped_addr = skb_frag_dma_map(&dev->dev, frag, offset,
+ frag_map_size,
+ DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(&dev->dev, mapped_addr)))
+ goto err_dma;
+
+ if (i == nr_frags - 1 &&
+ (frag_size - frag_map_size) == 0)
+ last_frag = true;
+
+ WRITE_ONCE(txd->txd1, mapped_addr);
+ WRITE_ONCE(txd->txd3, (QDMA_TX_SWC |
+ TX_DMA_PLEN0(frag_map_size) |
+ last_frag * TX_DMA_LS0) |
+ mac->id);
+ WRITE_ONCE(txd->txd4, 0);
+
+ tx_buf->skb = (struct sk_buff *)DMA_DUMMY_DESC;
+ tx_buf = mtk_desc_to_tx_buf(ring, txd);
+ memset(tx_buf, 0, sizeof(*tx_buf));
+
+ tx_buf->flags |= MTK_TX_FLAGS_PAGE0;
+ dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr);
+ dma_unmap_len_set(tx_buf, dma_len0, frag_map_size);
+ frag_size -= frag_map_size;
+ offset += frag_map_size;
+ }
+ }
+
+ /* store skb to cleanup */
+ tx_buf->skb = skb;
+
+ WRITE_ONCE(itxd->txd4, txd4);
+ WRITE_ONCE(itxd->txd3, (QDMA_TX_SWC | TX_DMA_PLEN0(skb_headlen(skb)) |
+ (!nr_frags * TX_DMA_LS0)));
+
+ netdev_sent_queue(dev, skb->len);
+ skb_tx_timestamp(skb);
+
+ ring->tx_next_free = mtk_tx_next_qdma(ring, txd);
+ atomic_sub(n_desc, &ring->tx_free_count);
+
+ /* make sure that all changes to the dma ring are flushed before we
+ * continue
+ */
+ wmb();
+
+ if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) || !skb->xmit_more)
+ mtk_w32(eth, txd->txd2, MTK_QTX_CTX_PTR);
+
+ return 0;
+
+err_dma:
+ do {
+ tx_buf = mtk_desc_to_tx_buf(ring, txd);
+
+ /* unmap dma */
+ mtk_txd_unmap(&dev->dev, tx_buf);
+
+ itxd->txd3 = TX_DMA_DESP2_DEF;
+ itxd = mtk_tx_next_qdma(ring, itxd);
+ } while (itxd != txd);
+
+ return -ENOMEM;
+}
+
+static inline int mtk_cal_txd_req(struct sk_buff *skb)
+{
+ int i, nfrags;
+ struct skb_frag_struct *frag;
+
+ nfrags = 1;
+ if (skb_is_gso(skb)) {
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ frag = &skb_shinfo(skb)->frags[i];
+ nfrags += DIV_ROUND_UP(frag->size, TX_DMA_BUF_LEN);
+ }
+ } else {
+ nfrags += skb_shinfo(skb)->nr_frags;
+ }
+
+ return DIV_ROUND_UP(nfrags, 2);
+}
+
+static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+ struct mtk_tx_ring *ring = &eth->tx_ring;
+ struct net_device_stats *stats = &dev->stats;
+ int tx_num;
+ int len = skb->len;
+ bool gso = false;
+
+ tx_num = mtk_cal_txd_req(skb);
+ if (unlikely(atomic_read(&ring->tx_free_count) <= tx_num)) {
+ netif_stop_queue(dev);
+ netif_err(eth, tx_queued, dev,
+ "Tx Ring full when queue awake!\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ /* TSO: fill MSS info in tcp checksum field */
+ if (skb_is_gso(skb)) {
+ if (skb_cow_head(skb, 0)) {
+ netif_warn(eth, tx_err, dev,
+ "GSO expand head fail.\n");
+ goto drop;
+ }
+
+ if (skb_shinfo(skb)->gso_type &
+ (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
+ gso = true;
+ tcp_hdr(skb)->check = htons(skb_shinfo(skb)->gso_size);
+ }
+ }
+
+ if (ring->tx_map(skb, dev, tx_num, ring, gso) < 0)
+ goto drop;
+
+ stats->tx_packets++;
+ stats->tx_bytes += len;
+
+ if (unlikely(atomic_read(&ring->tx_free_count) <= ring->tx_thresh)) {
+ netif_stop_queue(dev);
+ smp_mb();
+ if (unlikely(atomic_read(&ring->tx_free_count) >
+ ring->tx_thresh))
+ netif_wake_queue(dev);
+ }
+
+ return NETDEV_TX_OK;
+
+drop:
+ stats->tx_dropped++;
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+static int mtk_poll_rx(struct napi_struct *napi, int budget,
+ struct mtk_eth *eth, u32 rx_intr)
+{
+ struct mtk_soc_data *soc = eth->soc;
+ struct mtk_rx_ring *ring = &eth->rx_ring[0];
+ int idx = ring->rx_calc_idx;
+ u32 checksum_bit;
+ struct sk_buff *skb;
+ u8 *data, *new_data;
+ struct mtk_rx_dma *rxd, trxd;
+ int done = 0, pad;
+
+ if (eth->soc->hw_features & NETIF_F_RXCSUM)
+ checksum_bit = soc->checksum_bit;
+ else
+ checksum_bit = 0;
+
+ if (eth->soc->rx_2b_offset)
+ pad = 0;
+ else
+ pad = NET_IP_ALIGN;
+
+ while (done < budget) {
+ struct net_device *netdev;
+ unsigned int pktlen;
+ dma_addr_t dma_addr;
+ int mac = 0;
+
+ idx = NEXT_RX_DESP_IDX(idx);
+ rxd = &ring->rx_dma[idx];
+ data = ring->rx_data[idx];
+
+ mtk_get_rxd(&trxd, rxd);
+ if (!(trxd.rxd2 & RX_DMA_DONE))
+ break;
+
+ /* find out which mac the packet come from. values start at 1 */
+ if (eth->soc->mac_count > 1) {
+ mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) &
+ RX_DMA_FPORT_MASK;
+ mac--;
+ if (mac < 0 || mac >= eth->soc->mac_count)
+ goto release_desc;
+ }
+
+ netdev = eth->netdev[mac];
+
+ /* alloc new buffer */
+ new_data = napi_alloc_frag(ring->frag_size);
+ if (unlikely(!new_data || !netdev)) {
+ netdev->stats.rx_dropped++;
+ goto release_desc;
+ }
+ dma_addr = dma_map_single(&netdev->dev,
+ new_data + NET_SKB_PAD + pad,
+ ring->rx_buf_size,
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(&netdev->dev, dma_addr))) {
+ skb_free_frag(new_data);
+ goto release_desc;
+ }
+
+ /* receive data */
+ skb = build_skb(data, ring->frag_size);
+ if (unlikely(!skb)) {
+ put_page(virt_to_head_page(new_data));
+ goto release_desc;
+ }
+ skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
+
+ dma_unmap_single(&netdev->dev, trxd.rxd1,
+ ring->rx_buf_size, DMA_FROM_DEVICE);
+ pktlen = RX_DMA_GET_PLEN0(trxd.rxd2);
+ skb->dev = netdev;
+ skb_put(skb, pktlen);
+ if (trxd.rxd4 & checksum_bit)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb_checksum_none_assert(skb);
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += pktlen;
+
+ if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX &&
+ RX_DMA_VID(trxd.rxd3))
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+ RX_DMA_VID(trxd.rxd3));
+ napi_gro_receive(napi, skb);
+
+ ring->rx_data[idx] = new_data;
+ rxd->rxd1 = (unsigned int)dma_addr;
+
+release_desc:
+ if (eth->soc->rx_sg_dma)
+ rxd->rxd2 = RX_DMA_PLEN0(ring->rx_buf_size);
+ else
+ rxd->rxd2 = RX_DMA_LSO;
+
+ ring->rx_calc_idx = idx;
+ /* make sure that all changes to the dma ring are flushed before
+ * we continue
+ */
+ wmb();
+ if (eth->soc->dma_type == MTK_QDMA)
+ mtk_w32(eth, ring->rx_calc_idx, MTK_QRX_CRX_IDX0);
+ else
+ mtk_reg_w32(eth, ring->rx_calc_idx,
+ MTK_REG_RX_CALC_IDX0);
+ done++;
+ }
+
+ if (done < budget)
+ mtk_irq_ack(eth, rx_intr);
+
+ return done;
+}
+
+static int mtk_pdma_tx_poll(struct mtk_eth *eth, int budget, bool *tx_again)
+{
+ struct sk_buff *skb;
+ struct mtk_tx_buf *tx_buf;
+ int done = 0;
+ u32 idx, hwidx;
+ struct mtk_tx_ring *ring = &eth->tx_ring;
+ unsigned int bytes = 0;
+
+ idx = ring->tx_free_idx;
+ hwidx = mtk_reg_r32(eth, MTK_REG_TX_DTX_IDX0);
+
+ while ((idx != hwidx) && budget) {
+ tx_buf = &ring->tx_buf[idx];
+ skb = tx_buf->skb;
+
+ if (!skb)
+ break;
+
+ if (skb != (struct sk_buff *)DMA_DUMMY_DESC) {
+ bytes += skb->len;
+ done++;
+ budget--;
+ }
+ mtk_txd_unmap(eth->dev, tx_buf);
+ idx = NEXT_TX_DESP_IDX(idx);
+ }
+ ring->tx_free_idx = idx;
+ atomic_set(&ring->tx_free_count, mtk_pdma_empty_txd(ring));
+
+ /* read hw index again make sure no new tx packet */
+ if (idx != hwidx || idx != mtk_reg_r32(eth, MTK_REG_TX_DTX_IDX0))
+ *tx_again = 1;
+
+ if (done)
+ netdev_completed_queue(*eth->netdev, done, bytes);
+
+ return done;
+}
+
+static int mtk_qdma_tx_poll(struct mtk_eth *eth, int budget, bool *tx_again)
+{
+ struct mtk_tx_ring *ring = &eth->tx_ring;
+ struct mtk_tx_dma *desc;
+ struct sk_buff *skb;
+ struct mtk_tx_buf *tx_buf;
+ int total = 0, done[MTK_MAX_DEVS];
+ unsigned int bytes[MTK_MAX_DEVS];
+ u32 cpu, dma;
+ static int condition;
+ int i;
+
+ memset(done, 0, sizeof(done));
+ memset(bytes, 0, sizeof(bytes));
+
+ cpu = mtk_r32(eth, MTK_QTX_CRX_PTR);
+ dma = mtk_r32(eth, MTK_QTX_DRX_PTR);
+
+ desc = mtk_qdma_phys_to_virt(ring, cpu);
+
+ while ((cpu != dma) && budget) {
+ u32 next_cpu = desc->txd2;
+ int mac;
+
+ desc = mtk_tx_next_qdma(ring, desc);
+ if ((desc->txd3 & QDMA_TX_OWNER_CPU) == 0)
+ break;
+
+ mac = (desc->txd4 >> TX_DMA_FPORT_SHIFT) &
+ TX_DMA_FPORT_MASK;
+ mac--;
+
+ tx_buf = mtk_desc_to_tx_buf(ring, desc);
+ skb = tx_buf->skb;
+ if (!skb) {
+ condition = 1;
+ break;
+ }
+
+ if (skb != (struct sk_buff *)DMA_DUMMY_DESC) {
+ bytes[mac] += skb->len;
+ done[mac]++;
+ budget--;
+ }
+ mtk_txd_unmap(eth->dev, tx_buf);
+
+ ring->tx_last_free->txd2 = next_cpu;
+ ring->tx_last_free = desc;
+ atomic_inc(&ring->tx_free_count);
+
+ cpu = next_cpu;
+ }
+
+ mtk_w32(eth, cpu, MTK_QTX_CRX_PTR);
+
+ /* read hw index again make sure no new tx packet */
+ if (cpu != dma || cpu != mtk_r32(eth, MTK_QTX_DRX_PTR))
+ *tx_again = true;
+
+ for (i = 0; i < eth->soc->mac_count; i++) {
+ if (!done[i])
+ continue;
+ netdev_completed_queue(eth->netdev[i], done[i], bytes[i]);
+ total += done[i];
+ }
+
+ return total;
+}
+
+static int mtk_poll_tx(struct mtk_eth *eth, int budget, u32 tx_intr,
+ bool *tx_again)
+{
+ struct mtk_tx_ring *ring = &eth->tx_ring;
+ struct net_device *netdev = eth->netdev[0];
+ int done;
+
+ done = eth->tx_ring.tx_poll(eth, budget, tx_again);
+ if (!*tx_again)
+ mtk_irq_ack(eth, tx_intr);
+
+ if (!done)
+ return 0;
+
+ smp_mb();
+ if (unlikely(!netif_queue_stopped(netdev)))
+ return done;
+
+ if (atomic_read(&ring->tx_free_count) > ring->tx_thresh)
+ netif_wake_queue(netdev);
+
+ return done;
+}
+
+static void mtk_stats_update(struct mtk_eth *eth)
+{
+ int i;
+
+ for (i = 0; i < eth->soc->mac_count; i++) {
+ if (!eth->mac[i] || !eth->mac[i]->hw_stats)
+ continue;
+ if (spin_trylock(&eth->mac[i]->hw_stats->stats_lock)) {
+ mtk_stats_update_mac(eth->mac[i]);
+ spin_unlock(&eth->mac[i]->hw_stats->stats_lock);
+ }
+ }
+}
+
+static int mtk_poll(struct napi_struct *napi, int budget)
+{
+ struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi);
+ u32 status, mtk_status, mask, tx_intr, rx_intr, status_intr;
+ int tx_done, rx_done;
+ bool tx_again = false;
+
+ status = mtk_irq_pending(eth);
+ mtk_status = mtk_irq_pending_status(eth);
+ tx_intr = eth->soc->tx_int;
+ rx_intr = eth->soc->rx_int;
+ status_intr = eth->soc->status_int;
+ tx_done = 0;
+ rx_done = 0;
+ tx_again = 0;
+
+ if (status & tx_intr)
+ tx_done = mtk_poll_tx(eth, budget, tx_intr, &tx_again);
+
+ if (status & rx_intr)
+ rx_done = mtk_poll_rx(napi, budget, eth, rx_intr);
+
+ if (unlikely(mtk_status & status_intr)) {
+ mtk_stats_update(eth);
+ mtk_irq_ack_status(eth, status_intr);
+ }
+
+ if (unlikely(netif_msg_intr(eth))) {
+ mask = mtk_irq_enabled(eth);
+ netdev_info(eth->netdev[0],
+ "done tx %d, rx %d, intr 0x%08x/0x%x\n",
+ tx_done, rx_done, status, mask);
+ }
+
+ if (tx_again || rx_done == budget)
+ return budget;
+
+ status = mtk_irq_pending(eth);
+ if (status & (tx_intr | rx_intr))
+ return budget;
+
+ napi_complete(napi);
+ mtk_irq_enable(eth, tx_intr | rx_intr);
+
+ return rx_done;
+}
+
+static int mtk_pdma_tx_alloc(struct mtk_eth *eth)
+{
+ int i;
+ struct mtk_tx_ring *ring = &eth->tx_ring;
+
+ ring->tx_ring_size = eth->soc->dma_ring_size;
+ ring->tx_free_idx = 0;
+ ring->tx_next_idx = 0;
+ ring->tx_thresh = max((unsigned long)ring->tx_ring_size >> 2,
+ MAX_SKB_FRAGS);
+
+ ring->tx_buf = kcalloc(ring->tx_ring_size, sizeof(*ring->tx_buf),
+ GFP_KERNEL);
+ if (!ring->tx_buf)
+ goto no_tx_mem;
+
+ ring->tx_dma = dma_alloc_coherent(eth->dev,
+ ring->tx_ring_size * sizeof(*ring->tx_dma),
+ &ring->tx_phys,
+ GFP_ATOMIC | __GFP_ZERO);
+ if (!ring->tx_dma)
+ goto no_tx_mem;
+
+ for (i = 0; i < ring->tx_ring_size; i++) {
+ ring->tx_dma[i].txd2 = TX_DMA_DESP2_DEF;
+ ring->tx_dma[i].txd4 = eth->soc->txd4;
+ }
+
+ atomic_set(&ring->tx_free_count, mtk_pdma_empty_txd(ring));
+ ring->tx_map = mtk_pdma_tx_map;
+ ring->tx_poll = mtk_pdma_tx_poll;
+ ring->tx_clean = mtk_pdma_tx_clean;
+
+ /* make sure that all changes to the dma ring are flushed before we
+ * continue
+ */
+ wmb();
+
+ mtk_reg_w32(eth, ring->tx_phys, MTK_REG_TX_BASE_PTR0);
+ mtk_reg_w32(eth, ring->tx_ring_size, MTK_REG_TX_MAX_CNT0);
+ mtk_reg_w32(eth, 0, MTK_REG_TX_CTX_IDX0);
+ mtk_reg_w32(eth, MTK_PST_DTX_IDX0, MTK_REG_PDMA_RST_CFG);
+
+ return 0;
+
+no_tx_mem:
+ return -ENOMEM;
+}
+
+static int mtk_qdma_tx_alloc_tx(struct mtk_eth *eth)
+{
+ struct mtk_tx_ring *ring = &eth->tx_ring;
+ int i, sz = sizeof(*ring->tx_dma);
+
+ ring->tx_ring_size = eth->soc->dma_ring_size;
+ ring->tx_buf = kcalloc(ring->tx_ring_size, sizeof(*ring->tx_buf),
+ GFP_KERNEL);
+ if (!ring->tx_buf)
+ goto no_tx_mem;
+
+ ring->tx_dma = dma_alloc_coherent(eth->dev,
+ ring->tx_ring_size * sz,
+ &ring->tx_phys,
+ GFP_ATOMIC | __GFP_ZERO);
+ if (!ring->tx_dma)
+ goto no_tx_mem;
+
+ memset(ring->tx_dma, 0, ring->tx_ring_size * sz);
+ for (i = 0; i < ring->tx_ring_size; i++) {
+ int next = (i + 1) % ring->tx_ring_size;
+ u32 next_ptr = ring->tx_phys + next * sz;
+
+ ring->tx_dma[i].txd2 = next_ptr;
+ ring->tx_dma[i].txd3 = TX_DMA_DESP2_DEF;
+ }
+
+ atomic_set(&ring->tx_free_count, ring->tx_ring_size - 2);
+ ring->tx_next_free = &ring->tx_dma[0];
+ ring->tx_last_free = &ring->tx_dma[ring->tx_ring_size - 2];
+ ring->tx_thresh = max((unsigned long)ring->tx_ring_size >> 2,
+ MAX_SKB_FRAGS);
+
+ ring->tx_map = mtk_qdma_tx_map;
+ ring->tx_poll = mtk_qdma_tx_poll;
+ ring->tx_clean = mtk_qdma_tx_clean;
+
+ /* make sure that all changes to the dma ring are flushed before we
+ * continue
+ */
+ wmb();
+
+ mtk_w32(eth, ring->tx_phys, MTK_QTX_CTX_PTR);
+ mtk_w32(eth, ring->tx_phys, MTK_QTX_DTX_PTR);
+ mtk_w32(eth,
+ ring->tx_phys + ((ring->tx_ring_size - 1) * sz),
+ MTK_QTX_CRX_PTR);
+ mtk_w32(eth,
+ ring->tx_phys + ((ring->tx_ring_size - 1) * sz),
+ MTK_QTX_DRX_PTR);
+
+ return 0;
+
+no_tx_mem:
+ return -ENOMEM;
+}
+
+static int mtk_qdma_init(struct mtk_eth *eth, int ring)
+{
+ int err;
+
+ err = mtk_init_fq_dma(eth);
+ if (err)
+ return err;
+
+ err = mtk_qdma_tx_alloc_tx(eth);
+ if (err)
+ return err;
+
+ err = mtk_dma_rx_alloc(eth, &eth->rx_ring[ring]);
+ if (err)
+ return err;
+
+ mtk_w32(eth, eth->rx_ring[ring].rx_phys, MTK_QRX_BASE_PTR0);
+ mtk_w32(eth, eth->rx_ring[ring].rx_ring_size, MTK_QRX_MAX_CNT0);
+ mtk_w32(eth, eth->rx_ring[ring].rx_calc_idx, MTK_QRX_CRX_IDX0);
+ mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_QDMA_RST_IDX);
+ mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, MTK_QTX_CFG(0));
+
+ /* Enable random early drop and set drop threshold automatically */
+ mtk_w32(eth, 0x174444, MTK_QDMA_FC_THRES);
+ mtk_w32(eth, 0x0, MTK_QDMA_HRED2);
+
+ return 0;
+}
+
+static int mtk_pdma_qdma_init(struct mtk_eth *eth)
+{
+ int err = mtk_qdma_init(eth, 1);
+
+ if (err)
+ return err;
+
+ err = mtk_dma_rx_alloc(eth, &eth->rx_ring[0]);
+ if (err)
+ return err;
+
+ mtk_reg_w32(eth, eth->rx_ring[0].rx_phys, MTK_REG_RX_BASE_PTR0);
+ mtk_reg_w32(eth, eth->rx_ring[0].rx_ring_size, MTK_REG_RX_MAX_CNT0);
+ mtk_reg_w32(eth, eth->rx_ring[0].rx_calc_idx, MTK_REG_RX_CALC_IDX0);
+ mtk_reg_w32(eth, MTK_PST_DRX_IDX0, MTK_REG_PDMA_RST_CFG);
+
+ return 0;
+}
+
+static int mtk_pdma_init(struct mtk_eth *eth)
+{
+ struct mtk_rx_ring *ring = &eth->rx_ring[0];
+ int err;
+
+ err = mtk_pdma_tx_alloc(eth);
+ if (err)
+ return err;
+
+ err = mtk_dma_rx_alloc(eth, ring);
+ if (err)
+ return err;
+
+ mtk_reg_w32(eth, ring->rx_phys, MTK_REG_RX_BASE_PTR0);
+ mtk_reg_w32(eth, ring->rx_ring_size, MTK_REG_RX_MAX_CNT0);
+ mtk_reg_w32(eth, ring->rx_calc_idx, MTK_REG_RX_CALC_IDX0);
+ mtk_reg_w32(eth, MTK_PST_DRX_IDX0, MTK_REG_PDMA_RST_CFG);
+
+ return 0;
+}
+
+static void mtk_dma_free(struct mtk_eth *eth)
+{
+ int i;
+
+ for (i = 0; i < eth->soc->mac_count; i++)
+ if (eth->netdev[i])
+ netdev_reset_queue(eth->netdev[i]);
+ eth->tx_ring.tx_clean(eth);
+ mtk_clean_rx(eth, &eth->rx_ring[0]);
+ mtk_clean_rx(eth, &eth->rx_ring[1]);
+ kfree(eth->scratch_head);
+}
+
+static void mtk_tx_timeout(struct net_device *dev)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+ struct mtk_tx_ring *ring = &eth->tx_ring;
+
+ eth->netdev[mac->id]->stats.tx_errors++;
+ netif_err(eth, tx_err, dev,
+ "transmit timed out\n");
+ if (eth->soc->dma_type & MTK_PDMA) {
+ netif_info(eth, drv, dev, "pdma_cfg:%08x\n",
+ mtk_reg_r32(eth, MTK_REG_PDMA_GLO_CFG));
+ netif_info(eth, drv, dev, "tx_ring=%d, "
+ "base=%08x, max=%u, ctx=%u, dtx=%u, fdx=%hu, next=%hu\n",
+ 0, mtk_reg_r32(eth, MTK_REG_TX_BASE_PTR0),
+ mtk_reg_r32(eth, MTK_REG_TX_MAX_CNT0),
+ mtk_reg_r32(eth, MTK_REG_TX_CTX_IDX0),
+ mtk_reg_r32(eth, MTK_REG_TX_DTX_IDX0),
+ ring->tx_free_idx,
+ ring->tx_next_idx);
+ }
+ if (eth->soc->dma_type & MTK_QDMA) {
+ netif_info(eth, drv, dev, "qdma_cfg:%08x\n",
+ mtk_r32(eth, MTK_QDMA_GLO_CFG));
+ netif_info(eth, drv, dev, "tx_ring=%d, "
+ "ctx=%08x, dtx=%08x, crx=%08x, drx=%08x, free=%hu\n",
+ 0, mtk_r32(eth, MTK_QTX_CTX_PTR),
+ mtk_r32(eth, MTK_QTX_DTX_PTR),
+ mtk_r32(eth, MTK_QTX_CRX_PTR),
+ mtk_r32(eth, MTK_QTX_DRX_PTR),
+ atomic_read(&ring->tx_free_count));
+ }
+ netif_info(eth, drv, dev,
+ "rx_ring=%d, base=%08x, max=%u, calc=%u, drx=%u\n",
+ 0, mtk_reg_r32(eth, MTK_REG_RX_BASE_PTR0),
+ mtk_reg_r32(eth, MTK_REG_RX_MAX_CNT0),
+ mtk_reg_r32(eth, MTK_REG_RX_CALC_IDX0),
+ mtk_reg_r32(eth, MTK_REG_RX_DRX_IDX0));
+
+ schedule_work(&mac->pending_work);
+}
+
+static irqreturn_t mtk_handle_irq(int irq, void *_eth)
+{
+ struct mtk_eth *eth = _eth;
+ u32 status, int_mask;
+
+ status = mtk_irq_pending(eth);
+ if (unlikely(!status))
+ return IRQ_NONE;
+
+ int_mask = (eth->soc->rx_int | eth->soc->tx_int);
+ if (likely(status & int_mask)) {
+ if (likely(napi_schedule_prep(&eth->rx_napi)))
+ __napi_schedule(&eth->rx_napi);
+ } else {
+ mtk_irq_ack(eth, status);
+ }
+ mtk_irq_disable(eth, int_mask);
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void mtk_poll_controller(struct net_device *dev)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+ u32 int_mask = eth->soc->tx_int | eth->soc->rx_int;
+
+ mtk_irq_disable(eth, int_mask);
+ mtk_handle_irq(dev->irq, dev);
+ mtk_irq_enable(eth, int_mask);
+}
+#endif
+
+int mtk_set_clock_cycle(struct mtk_eth *eth)
+{
+ unsigned long sysclk = eth->sysclk;
+
+ sysclk /= MTK_US_CYC_CNT_DIVISOR;
+ sysclk <<= MTK_US_CYC_CNT_SHIFT;
+
+ mtk_w32(eth, (mtk_r32(eth, MTK_GLO_CFG) &
+ ~(MTK_US_CYC_CNT_MASK << MTK_US_CYC_CNT_SHIFT)) |
+ sysclk,
+ MTK_GLO_CFG);
+ return 0;
+}
+
+void mtk_fwd_config(struct mtk_eth *eth)
+{
+ u32 fwd_cfg;
+
+ fwd_cfg = mtk_r32(eth, MTK_GDMA1_FWD_CFG);
+
+ /* disable jumbo frame */
+ if (eth->soc->jumbo_frame)
+ fwd_cfg &= ~MTK_GDM1_JMB_EN;
+
+ /* set unicast/multicast/broadcast frame to cpu */
+ fwd_cfg &= ~0xffff;
+
+ mtk_w32(eth, fwd_cfg, MTK_GDMA1_FWD_CFG);
+}
+
+void mtk_csum_config(struct mtk_eth *eth)
+{
+ if (eth->soc->hw_features & NETIF_F_RXCSUM)
+ mtk_w32(eth, mtk_r32(eth, MTK_GDMA1_FWD_CFG) |
+ (MTK_GDM1_ICS_EN | MTK_GDM1_TCS_EN | MTK_GDM1_UCS_EN),
+ MTK_GDMA1_FWD_CFG);
+ else
+ mtk_w32(eth, mtk_r32(eth, MTK_GDMA1_FWD_CFG) &
+ ~(MTK_GDM1_ICS_EN | MTK_GDM1_TCS_EN | MTK_GDM1_UCS_EN),
+ MTK_GDMA1_FWD_CFG);
+ if (eth->soc->hw_features & NETIF_F_IP_CSUM)
+ mtk_w32(eth, mtk_r32(eth, MTK_CDMA_CSG_CFG) |
+ (MTK_ICS_GEN_EN | MTK_TCS_GEN_EN | MTK_UCS_GEN_EN),
+ MTK_CDMA_CSG_CFG);
+ else
+ mtk_w32(eth, mtk_r32(eth, MTK_CDMA_CSG_CFG) &
+ ~(MTK_ICS_GEN_EN | MTK_TCS_GEN_EN | MTK_UCS_GEN_EN),
+ MTK_CDMA_CSG_CFG);
+}
+
+static int mtk_start_dma(struct mtk_eth *eth)
+{
+ unsigned long flags;
+ u32 val;
+ int err;
+
+ if (eth->soc->dma_type == MTK_PDMA)
+ err = mtk_pdma_init(eth);
+ else if (eth->soc->dma_type == MTK_QDMA)
+ err = mtk_qdma_init(eth, 0);
+ else
+ err = mtk_pdma_qdma_init(eth);
+ if (err) {
+ mtk_dma_free(eth);
+ return err;
+ }
+
+ spin_lock_irqsave(&eth->page_lock, flags);
+
+ val = MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN;
+ if (eth->soc->rx_2b_offset)
+ val |= MTK_RX_2B_OFFSET;
+ val |= eth->soc->pdma_glo_cfg;
+
+ if (eth->soc->dma_type & MTK_PDMA)
+ mtk_reg_w32(eth, val, MTK_REG_PDMA_GLO_CFG);
+
+ if (eth->soc->dma_type & MTK_QDMA)
+ mtk_w32(eth, val, MTK_QDMA_GLO_CFG);
+
+ spin_unlock_irqrestore(&eth->page_lock, flags);
+
+ return 0;
+}
+
+static int mtk_open(struct net_device *dev)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+
+ if (!atomic_read(&eth->dma_refcnt)) {
+ int err = mtk_start_dma(eth);
+
+ if (err)
+ return err;
+
+ napi_enable(&eth->rx_napi);
+ mtk_irq_enable(eth, eth->soc->tx_int | eth->soc->rx_int);
+ }
+ atomic_inc(&eth->dma_refcnt);
+
+ if (eth->phy)
+ eth->phy->start(mac);
+
+ if (eth->soc->has_carrier && eth->soc->has_carrier(eth))
+ netif_carrier_on(dev);
+
+ netif_start_queue(dev);
+ eth->soc->fwd_config(eth);
+
+ return 0;
+}
+
+static void mtk_stop_dma(struct mtk_eth *eth, u32 glo_cfg)
+{
+ unsigned long flags;
+ u32 val;
+ int i;
+
+ /* stop the dma enfine */
+ spin_lock_irqsave(&eth->page_lock, flags);
+ val = mtk_r32(eth, glo_cfg);
+ mtk_w32(eth, val & ~(MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN),
+ glo_cfg);
+ spin_unlock_irqrestore(&eth->page_lock, flags);
+
+ /* wait for dma stop */
+ for (i = 0; i < 10; i++) {
+ val = mtk_r32(eth, glo_cfg);
+ if (val & (MTK_TX_DMA_BUSY | MTK_RX_DMA_BUSY)) {
+ msleep(20);
+ continue;
+ }
+ break;
+ }
+}
+
+static int mtk_stop(struct net_device *dev)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+
+ netif_tx_disable(dev);
+ if (eth->phy)
+ eth->phy->stop(mac);
+
+ if (!atomic_dec_and_test(&eth->dma_refcnt))
+ return 0;
+
+ mtk_irq_disable(eth, eth->soc->tx_int | eth->soc->rx_int);
+ napi_disable(&eth->rx_napi);
+
+ if (eth->soc->dma_type & MTK_PDMA)
+ mtk_stop_dma(eth, mtk_reg_table[MTK_REG_PDMA_GLO_CFG]);
+
+ if (eth->soc->dma_type & MTK_QDMA)
+ mtk_stop_dma(eth, MTK_QDMA_GLO_CFG);
+
+ mtk_dma_free(eth);
+
+ return 0;
+}
+
+static int __init mtk_init_hw(struct mtk_eth *eth)
+{
+ int i, err;
+
+ eth->soc->reset_fe(eth);
+
+ if (eth->soc->switch_init)
+ if (eth->soc->switch_init(eth)) {
+ dev_err(eth->dev, "failed to initialize switch core\n");
+ return -ENODEV;
+ }
+
+ err = devm_request_irq(eth->dev, eth->irq, mtk_handle_irq, 0,
+ dev_name(eth->dev), eth);
+ if (err)
+ return err;
+
+ err = mtk_mdio_init(eth);
+ if (err)
+ return err;
+
+ /* disable delay and normal interrupt */
+ mtk_reg_w32(eth, 0, MTK_REG_DLY_INT_CFG);
+ if (eth->soc->dma_type & MTK_QDMA)
+ mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
+ mtk_irq_disable(eth, eth->soc->tx_int | eth->soc->rx_int);
+
+ /* frame engine will push VLAN tag regarding to VIDX field in Tx desc */
+ if (mtk_reg_table[MTK_REG_MTK_DMA_VID_BASE])
+ for (i = 0; i < 16; i += 2)
+ mtk_w32(eth, ((i + 1) << 16) + i,
+ mtk_reg_table[MTK_REG_MTK_DMA_VID_BASE] +
+ (i * 2));
+
+ if (eth->soc->fwd_config(eth))
+ dev_err(eth->dev, "unable to get clock\n");
+
+ if (mtk_reg_table[MTK_REG_MTK_RST_GL]) {
+ mtk_reg_w32(eth, 1, MTK_REG_MTK_RST_GL);
+ mtk_reg_w32(eth, 0, MTK_REG_MTK_RST_GL);
+ }
+
+ return 0;
+}
+
+static int __init mtk_init(struct net_device *dev)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+ struct device_node *port;
+ const char *mac_addr;
+ int err;
+
+ mac_addr = of_get_mac_address(mac->of_node);
+ if (mac_addr)
+ ether_addr_copy(dev->dev_addr, mac_addr);
+
+ /* If the mac address is invalid, use random mac address */
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ random_ether_addr(dev->dev_addr);
+ dev_err(eth->dev, "generated random MAC address %pM\n",
+ dev->dev_addr);
+ dev->addr_assign_type = NET_ADDR_RANDOM;
+ }
+ mac->hw->soc->set_mac(mac, dev->dev_addr);
+
+ if (eth->soc->port_init)
+ for_each_child_of_node(mac->of_node, port)
+ if (of_device_is_compatible(port,
+ "mediatek,eth-port") &&
+ of_device_is_available(port))
+ eth->soc->port_init(eth, mac, port);
+
+ if (eth->phy) {
+ err = eth->phy->connect(mac);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static void mtk_uninit(struct net_device *dev)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+
+ if (eth->phy)
+ eth->phy->disconnect(mac);
+ mtk_mdio_cleanup(eth);
+
+ mtk_irq_disable(eth, ~0);
+ free_irq(dev->irq, dev);
+}
+
+static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+
+ if (!mac->phy_dev)
+ return -ENODEV;
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ return phy_mii_ioctl(mac->phy_dev, ifr, cmd);
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int mtk_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
+ int frag_size, old_mtu;
+ u32 fwd_cfg;
+
+ if (!eth->soc->jumbo_frame)
+ return eth_change_mtu(dev, new_mtu);
+
+ frag_size = mtk_max_frag_size(new_mtu);
+ if (new_mtu < 68 || frag_size > PAGE_SIZE)
+ return -EINVAL;
+
+ old_mtu = dev->mtu;
+ dev->mtu = new_mtu;
+
+ /* return early if the buffer sizes will not change */
+ if (old_mtu <= ETH_DATA_LEN && new_mtu <= ETH_DATA_LEN)
+ return 0;
+ if (old_mtu > ETH_DATA_LEN && new_mtu > ETH_DATA_LEN)
+ return 0;
+
+ if (new_mtu <= ETH_DATA_LEN)
+ eth->rx_ring[0].frag_size = mtk_max_frag_size(ETH_DATA_LEN);
+ else
+ eth->rx_ring[0].frag_size = PAGE_SIZE;
+ eth->rx_ring[0].rx_buf_size =
+ mtk_max_buf_size(eth->rx_ring[0].frag_size);
+
+ if (!netif_running(dev))
+ return 0;
+
+ mtk_stop(dev);
+ fwd_cfg = mtk_r32(eth, MTK_GDMA1_FWD_CFG);
+ if (new_mtu <= ETH_DATA_LEN) {
+ fwd_cfg &= ~MTK_GDM1_JMB_EN;
+ } else {
+ fwd_cfg &= ~(MTK_GDM1_JMB_LEN_MASK << MTK_GDM1_JMB_LEN_SHIFT);
+ fwd_cfg |= (DIV_ROUND_UP(frag_size, 1024) <<
+ MTK_GDM1_JMB_LEN_SHIFT) | MTK_GDM1_JMB_EN;
+ }
+ mtk_w32(eth, fwd_cfg, MTK_GDMA1_FWD_CFG);
+
+ return mtk_open(dev);
+}
+
+static void mtk_pending_work(struct work_struct *work)
+{
+ struct mtk_mac *mac = container_of(work, struct mtk_mac, pending_work);
+ struct mtk_eth *eth = mac->hw;
+ struct net_device *dev = eth->netdev[mac->id];
+ int err;
+
+ rtnl_lock();
+ mtk_stop(dev);
+
+ err = mtk_open(dev);
+ if (err) {
+ netif_alert(eth, ifup, dev,
+ "Driver up/down cycle failed, closing device.\n");
+ dev_close(dev);
+ }
+ rtnl_unlock();
+}
+
+static int mtk_cleanup(struct mtk_eth *eth)
+{
+ int i;
+
+ for (i = 0; i < eth->soc->mac_count; i++) {
+ struct mtk_mac *mac = netdev_priv(eth->netdev[i]);
+
+ if (!eth->netdev[i])
+ continue;
+
+ unregister_netdev(eth->netdev[i]);
+ free_netdev(eth->netdev[i]);
+ cancel_work_sync(&mac->pending_work);
+ }
+
+ return 0;
+}
+
+static const struct net_device_ops mtk_netdev_ops = {
+ .ndo_init = mtk_init,
+ .ndo_uninit = mtk_uninit,
+ .ndo_open = mtk_open,
+ .ndo_stop = mtk_stop,
+ .ndo_start_xmit = mtk_start_xmit,
+ .ndo_set_mac_address = mtk_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_do_ioctl = mtk_do_ioctl,
+ .ndo_change_mtu = mtk_change_mtu,
+ .ndo_tx_timeout = mtk_tx_timeout,
+ .ndo_get_stats64 = mtk_get_stats64,
+ .ndo_vlan_rx_add_vid = mtk_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = mtk_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = mtk_poll_controller,
+#endif
+};
+
+static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
+{
+ struct mtk_mac *mac;
+ const __be32 *_id = of_get_property(np, "reg", NULL);
+ int id, err;
+
+ if (!_id) {
+ dev_err(eth->dev, "missing mac id\n");
+ return -EINVAL;
+ }
+ id = be32_to_cpup(_id);
+ if (id >= eth->soc->mac_count || eth->netdev[id]) {
+ dev_err(eth->dev, "%d is not a valid mac id\n", id);
+ return -EINVAL;
+ }
+
+ eth->netdev[id] = alloc_etherdev(sizeof(*mac));
+ if (!eth->netdev[id]) {
+ dev_err(eth->dev, "alloc_etherdev failed\n");
+ return -ENOMEM;
+ }
+ mac = netdev_priv(eth->netdev[id]);
+ eth->mac[id] = mac;
+ mac->id = id;
+ mac->hw = eth;
+ mac->of_node = np;
+ INIT_WORK(&mac->pending_work, mtk_pending_work);
+
+ if (mtk_reg_table[MTK_REG_MTK_COUNTER_BASE]) {
+ mac->hw_stats = devm_kzalloc(eth->dev,
+ sizeof(*mac->hw_stats),
+ GFP_KERNEL);
+ if (!mac->hw_stats)
+ return -ENOMEM;
+ spin_lock_init(&mac->hw_stats->stats_lock);
+ mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
+ }
+
+ SET_NETDEV_DEV(eth->netdev[id], eth->dev);
+ eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
+ eth->netdev[id]->base_addr = (unsigned long)eth->base;
+
+ if (eth->soc->init_data)
+ eth->soc->init_data(eth->soc, eth->netdev[id]);
+
+ eth->netdev[id]->vlan_features = eth->soc->hw_features &
+ ~(NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX);
+ eth->netdev[id]->features |= eth->soc->hw_features;
+
+ if (mtk_reg_table[MTK_REG_MTK_DMA_VID_BASE])
+ eth->netdev[id]->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+
+ mtk_set_ethtool_ops(eth->netdev[id]);
+
+ err = register_netdev(eth->netdev[id]);
+ if (err) {
+ dev_err(eth->dev, "error bringing up device\n");
+ return err;
+ }
+ eth->netdev[id]->irq = eth->irq;
+ netif_info(eth, probe, eth->netdev[id],
+ "mediatek frame engine at 0x%08lx, irq %d\n",
+ eth->netdev[id]->base_addr, eth->netdev[id]->irq);
+
+ return 0;
+}
+
+static int mtk_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ const struct of_device_id *match;
+ struct device_node *mac_np;
+ struct mtk_soc_data *soc;
+ struct mtk_eth *eth;
+ struct clk *sysclk;
+ int err;
+
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+ device_reset(&pdev->dev);
+
+ match = of_match_device(of_mtk_match, &pdev->dev);
+ soc = (struct mtk_soc_data *)match->data;
+
+ if (soc->reg_table)
+ mtk_reg_table = soc->reg_table;
+
+ eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL);
+ if (!eth)
+ return -ENOMEM;
+
+ eth->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(eth->base))
+ return PTR_ERR(eth->base);
+
+ spin_lock_init(&eth->page_lock);
+
+ eth->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "mediatek,ethsys");
+ if (IS_ERR(eth->ethsys))
+ return PTR_ERR(eth->ethsys);
+
+ eth->irq = platform_get_irq(pdev, 0);
+ if (eth->irq < 0) {
+ dev_err(&pdev->dev, "no IRQ resource found\n");
+ return -ENXIO;
+ }
+
+ sysclk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(sysclk)) {
+ dev_err(&pdev->dev,
+ "the clock is not defined in the devicetree\n");
+ return -ENXIO;
+ }
+ eth->sysclk = clk_get_rate(sysclk);
+
+ eth->switch_np = of_parse_phandle(pdev->dev.of_node,
+ "mediatek,switch", 0);
+ if (soc->has_switch && !eth->switch_np) {
+ dev_err(&pdev->dev, "failed to read switch phandle\n");
+ return -ENODEV;
+ }
+
+ eth->dev = &pdev->dev;
+ eth->soc = soc;
+ eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE);
+
+ err = mtk_init_hw(eth);
+ if (err)
+ return err;
+
+ if (eth->soc->mac_count > 1) {
+ for_each_child_of_node(pdev->dev.of_node, mac_np) {
+ if (!of_device_is_compatible(mac_np,
+ "mediatek,eth-mac"))
+ continue;
+
+ if (!of_device_is_available(mac_np))
+ continue;
+
+ err = mtk_add_mac(eth, mac_np);
+ if (err)
+ goto err_free_dev;
+ }
+
+ init_dummy_netdev(&eth->dummy_dev);
+ netif_napi_add(&eth->dummy_dev, &eth->rx_napi, mtk_poll,
+ soc->napi_weight);
+ } else {
+ err = mtk_add_mac(eth, pdev->dev.of_node);
+ if (err)
+ goto err_free_dev;
+ netif_napi_add(eth->netdev[0], &eth->rx_napi, mtk_poll,
+ soc->napi_weight);
+ }
+
+ platform_set_drvdata(pdev, eth);
+
+ return 0;
+
+err_free_dev:
+ mtk_cleanup(eth);
+ return err;
+}
+
+static int mtk_remove(struct platform_device *pdev)
+{
+ struct mtk_eth *eth = platform_get_drvdata(pdev);
+
+ netif_napi_del(&eth->rx_napi);
+ mtk_cleanup(eth);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver mtk_driver = {
+ .probe = mtk_probe,
+ .remove = mtk_remove,
+ .driver = {
+ .name = "mtk_soc_eth",
+ .owner = THIS_MODULE,
+ .of_match_table = of_mtk_match,
+ },
+};
+
+module_platform_driver(mtk_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Ethernet driver for MediaTek SoC");
diff --git a/drivers/staging/mt7621-eth/mtk_eth_soc.h b/drivers/staging/mt7621-eth/mtk_eth_soc.h
new file mode 100644
index 000000000000..443f88d8af65
--- /dev/null
+++ b/drivers/staging/mt7621-eth/mtk_eth_soc.h
@@ -0,0 +1,721 @@
+/* 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; 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.
+ *
+ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#ifndef MTK_ETH_H
+#define MTK_ETH_H
+
+#include <linux/mii.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/dma-mapping.h>
+#include <linux/phy.h>
+#include <linux/ethtool.h>
+#include <linux/version.h>
+#include <linux/atomic.h>
+
+/* these registers have different offsets depending on the SoC. we use a lookup
+ * table for these
+ */
+enum mtk_reg {
+ MTK_REG_PDMA_GLO_CFG = 0,
+ MTK_REG_PDMA_RST_CFG,
+ MTK_REG_DLY_INT_CFG,
+ MTK_REG_TX_BASE_PTR0,
+ MTK_REG_TX_MAX_CNT0,
+ MTK_REG_TX_CTX_IDX0,
+ MTK_REG_TX_DTX_IDX0,
+ MTK_REG_RX_BASE_PTR0,
+ MTK_REG_RX_MAX_CNT0,
+ MTK_REG_RX_CALC_IDX0,
+ MTK_REG_RX_DRX_IDX0,
+ MTK_REG_MTK_INT_ENABLE,
+ MTK_REG_MTK_INT_STATUS,
+ MTK_REG_MTK_DMA_VID_BASE,
+ MTK_REG_MTK_COUNTER_BASE,
+ MTK_REG_MTK_RST_GL,
+ MTK_REG_MTK_INT_STATUS2,
+ MTK_REG_COUNT
+};
+
+/* delayed interrupt bits */
+#define MTK_DELAY_EN_INT 0x80
+#define MTK_DELAY_MAX_INT 0x04
+#define MTK_DELAY_MAX_TOUT 0x04
+#define MTK_DELAY_TIME 20
+#define MTK_DELAY_CHAN (((MTK_DELAY_EN_INT | MTK_DELAY_MAX_INT) << 8) \
+ | MTK_DELAY_MAX_TOUT)
+#define MTK_DELAY_INIT ((MTK_DELAY_CHAN << 16) | MTK_DELAY_CHAN)
+#define MTK_PSE_FQFC_CFG_INIT 0x80504000
+#define MTK_PSE_FQFC_CFG_256Q 0xff908000
+
+/* interrupt bits */
+#define MTK_CNT_PPE_AF BIT(31)
+#define MTK_CNT_GDM_AF BIT(29)
+#define MTK_PSE_P2_FC BIT(26)
+#define MTK_PSE_BUF_DROP BIT(24)
+#define MTK_GDM_OTHER_DROP BIT(23)
+#define MTK_PSE_P1_FC BIT(22)
+#define MTK_PSE_P0_FC BIT(21)
+#define MTK_PSE_FQ_EMPTY BIT(20)
+#define MTK_GE1_STA_CHG BIT(18)
+#define MTK_TX_COHERENT BIT(17)
+#define MTK_RX_COHERENT BIT(16)
+#define MTK_TX_DONE_INT3 BIT(11)
+#define MTK_TX_DONE_INT2 BIT(10)
+#define MTK_TX_DONE_INT1 BIT(9)
+#define MTK_TX_DONE_INT0 BIT(8)
+#define MTK_RX_DONE_INT0 BIT(2)
+#define MTK_TX_DLY_INT BIT(1)
+#define MTK_RX_DLY_INT BIT(0)
+
+#define MTK_RX_DONE_INT MTK_RX_DONE_INT0
+#define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \
+ MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3)
+
+#define RT5350_RX_DLY_INT BIT(30)
+#define RT5350_TX_DLY_INT BIT(28)
+#define RT5350_RX_DONE_INT1 BIT(17)
+#define RT5350_RX_DONE_INT0 BIT(16)
+#define RT5350_TX_DONE_INT3 BIT(3)
+#define RT5350_TX_DONE_INT2 BIT(2)
+#define RT5350_TX_DONE_INT1 BIT(1)
+#define RT5350_TX_DONE_INT0 BIT(0)
+
+#define RT5350_RX_DONE_INT (RT5350_RX_DONE_INT0 | RT5350_RX_DONE_INT1)
+#define RT5350_TX_DONE_INT (RT5350_TX_DONE_INT0 | RT5350_TX_DONE_INT1 | \
+ RT5350_TX_DONE_INT2 | RT5350_TX_DONE_INT3)
+
+/* registers */
+#define MTK_GDMA_OFFSET 0x0020
+#define MTK_PSE_OFFSET 0x0040
+#define MTK_GDMA2_OFFSET 0x0060
+#define MTK_CDMA_OFFSET 0x0080
+#define MTK_DMA_VID0 0x00a8
+#define MTK_PDMA_OFFSET 0x0100
+#define MTK_PPE_OFFSET 0x0200
+#define MTK_CMTABLE_OFFSET 0x0400
+#define MTK_POLICYTABLE_OFFSET 0x1000
+
+#define MT7621_GDMA_OFFSET 0x0500
+#define MT7620_GDMA_OFFSET 0x0600
+
+#define RT5350_PDMA_OFFSET 0x0800
+#define RT5350_SDM_OFFSET 0x0c00
+
+#define MTK_MDIO_ACCESS 0x00
+#define MTK_MDIO_CFG 0x04
+#define MTK_GLO_CFG 0x08
+#define MTK_RST_GL 0x0C
+#define MTK_INT_STATUS 0x10
+#define MTK_INT_ENABLE 0x14
+#define MTK_MDIO_CFG2 0x18
+#define MTK_FOC_TS_T 0x1C
+
+#define MTK_GDMA1_FWD_CFG (MTK_GDMA_OFFSET + 0x00)
+#define MTK_GDMA1_SCH_CFG (MTK_GDMA_OFFSET + 0x04)
+#define MTK_GDMA1_SHPR_CFG (MTK_GDMA_OFFSET + 0x08)
+#define MTK_GDMA1_MAC_ADRL (MTK_GDMA_OFFSET + 0x0C)
+#define MTK_GDMA1_MAC_ADRH (MTK_GDMA_OFFSET + 0x10)
+
+#define MTK_GDMA2_FWD_CFG (MTK_GDMA2_OFFSET + 0x00)
+#define MTK_GDMA2_SCH_CFG (MTK_GDMA2_OFFSET + 0x04)
+#define MTK_GDMA2_SHPR_CFG (MTK_GDMA2_OFFSET + 0x08)
+#define MTK_GDMA2_MAC_ADRL (MTK_GDMA2_OFFSET + 0x0C)
+#define MTK_GDMA2_MAC_ADRH (MTK_GDMA2_OFFSET + 0x10)
+
+#define MTK_PSE_FQ_CFG (MTK_PSE_OFFSET + 0x00)
+#define MTK_CDMA_FC_CFG (MTK_PSE_OFFSET + 0x04)
+#define MTK_GDMA1_FC_CFG (MTK_PSE_OFFSET + 0x08)
+#define MTK_GDMA2_FC_CFG (MTK_PSE_OFFSET + 0x0C)
+
+#define MTK_CDMA_CSG_CFG (MTK_CDMA_OFFSET + 0x00)
+#define MTK_CDMA_SCH_CFG (MTK_CDMA_OFFSET + 0x04)
+
+#define MT7621_GDMA_FWD_CFG(x) (MT7621_GDMA_OFFSET + (x * 0x1000))
+
+/* FIXME this might be different for different SOCs */
+#define MT7620_GDMA1_FWD_CFG (MT7621_GDMA_OFFSET + 0x00)
+
+#define RT5350_TX_BASE_PTR0 (RT5350_PDMA_OFFSET + 0x00)
+#define RT5350_TX_MAX_CNT0 (RT5350_PDMA_OFFSET + 0x04)
+#define RT5350_TX_CTX_IDX0 (RT5350_PDMA_OFFSET + 0x08)
+#define RT5350_TX_DTX_IDX0 (RT5350_PDMA_OFFSET + 0x0C)
+#define RT5350_TX_BASE_PTR1 (RT5350_PDMA_OFFSET + 0x10)
+#define RT5350_TX_MAX_CNT1 (RT5350_PDMA_OFFSET + 0x14)
+#define RT5350_TX_CTX_IDX1 (RT5350_PDMA_OFFSET + 0x18)
+#define RT5350_TX_DTX_IDX1 (RT5350_PDMA_OFFSET + 0x1C)
+#define RT5350_TX_BASE_PTR2 (RT5350_PDMA_OFFSET + 0x20)
+#define RT5350_TX_MAX_CNT2 (RT5350_PDMA_OFFSET + 0x24)
+#define RT5350_TX_CTX_IDX2 (RT5350_PDMA_OFFSET + 0x28)
+#define RT5350_TX_DTX_IDX2 (RT5350_PDMA_OFFSET + 0x2C)
+#define RT5350_TX_BASE_PTR3 (RT5350_PDMA_OFFSET + 0x30)
+#define RT5350_TX_MAX_CNT3 (RT5350_PDMA_OFFSET + 0x34)
+#define RT5350_TX_CTX_IDX3 (RT5350_PDMA_OFFSET + 0x38)
+#define RT5350_TX_DTX_IDX3 (RT5350_PDMA_OFFSET + 0x3C)
+#define RT5350_RX_BASE_PTR0 (RT5350_PDMA_OFFSET + 0x100)
+#define RT5350_RX_MAX_CNT0 (RT5350_PDMA_OFFSET + 0x104)
+#define RT5350_RX_CALC_IDX0 (RT5350_PDMA_OFFSET + 0x108)
+#define RT5350_RX_DRX_IDX0 (RT5350_PDMA_OFFSET + 0x10C)
+#define RT5350_RX_BASE_PTR1 (RT5350_PDMA_OFFSET + 0x110)
+#define RT5350_RX_MAX_CNT1 (RT5350_PDMA_OFFSET + 0x114)
+#define RT5350_RX_CALC_IDX1 (RT5350_PDMA_OFFSET + 0x118)
+#define RT5350_RX_DRX_IDX1 (RT5350_PDMA_OFFSET + 0x11C)
+#define RT5350_PDMA_GLO_CFG (RT5350_PDMA_OFFSET + 0x204)
+#define RT5350_PDMA_RST_CFG (RT5350_PDMA_OFFSET + 0x208)
+#define RT5350_DLY_INT_CFG (RT5350_PDMA_OFFSET + 0x20c)
+#define RT5350_MTK_INT_STATUS (RT5350_PDMA_OFFSET + 0x220)
+#define RT5350_MTK_INT_ENABLE (RT5350_PDMA_OFFSET + 0x228)
+#define RT5350_PDMA_SCH_CFG (RT5350_PDMA_OFFSET + 0x280)
+
+#define MTK_PDMA_GLO_CFG (MTK_PDMA_OFFSET + 0x00)
+#define MTK_PDMA_RST_CFG (MTK_PDMA_OFFSET + 0x04)
+#define MTK_PDMA_SCH_CFG (MTK_PDMA_OFFSET + 0x08)
+#define MTK_DLY_INT_CFG (MTK_PDMA_OFFSET + 0x0C)
+#define MTK_TX_BASE_PTR0 (MTK_PDMA_OFFSET + 0x10)
+#define MTK_TX_MAX_CNT0 (MTK_PDMA_OFFSET + 0x14)
+#define MTK_TX_CTX_IDX0 (MTK_PDMA_OFFSET + 0x18)
+#define MTK_TX_DTX_IDX0 (MTK_PDMA_OFFSET + 0x1C)
+#define MTK_TX_BASE_PTR1 (MTK_PDMA_OFFSET + 0x20)
+#define MTK_TX_MAX_CNT1 (MTK_PDMA_OFFSET + 0x24)
+#define MTK_TX_CTX_IDX1 (MTK_PDMA_OFFSET + 0x28)
+#define MTK_TX_DTX_IDX1 (MTK_PDMA_OFFSET + 0x2C)
+#define MTK_RX_BASE_PTR0 (MTK_PDMA_OFFSET + 0x30)
+#define MTK_RX_MAX_CNT0 (MTK_PDMA_OFFSET + 0x34)
+#define MTK_RX_CALC_IDX0 (MTK_PDMA_OFFSET + 0x38)
+#define MTK_RX_DRX_IDX0 (MTK_PDMA_OFFSET + 0x3C)
+#define MTK_TX_BASE_PTR2 (MTK_PDMA_OFFSET + 0x40)
+#define MTK_TX_MAX_CNT2 (MTK_PDMA_OFFSET + 0x44)
+#define MTK_TX_CTX_IDX2 (MTK_PDMA_OFFSET + 0x48)
+#define MTK_TX_DTX_IDX2 (MTK_PDMA_OFFSET + 0x4C)
+#define MTK_TX_BASE_PTR3 (MTK_PDMA_OFFSET + 0x50)
+#define MTK_TX_MAX_CNT3 (MTK_PDMA_OFFSET + 0x54)
+#define MTK_TX_CTX_IDX3 (MTK_PDMA_OFFSET + 0x58)
+#define MTK_TX_DTX_IDX3 (MTK_PDMA_OFFSET + 0x5C)
+#define MTK_RX_BASE_PTR1 (MTK_PDMA_OFFSET + 0x60)
+#define MTK_RX_MAX_CNT1 (MTK_PDMA_OFFSET + 0x64)
+#define MTK_RX_CALC_IDX1 (MTK_PDMA_OFFSET + 0x68)
+#define MTK_RX_DRX_IDX1 (MTK_PDMA_OFFSET + 0x6C)
+
+/* Switch DMA configuration */
+#define RT5350_SDM_CFG (RT5350_SDM_OFFSET + 0x00)
+#define RT5350_SDM_RRING (RT5350_SDM_OFFSET + 0x04)
+#define RT5350_SDM_TRING (RT5350_SDM_OFFSET + 0x08)
+#define RT5350_SDM_MAC_ADRL (RT5350_SDM_OFFSET + 0x0C)
+#define RT5350_SDM_MAC_ADRH (RT5350_SDM_OFFSET + 0x10)
+#define RT5350_SDM_TPCNT (RT5350_SDM_OFFSET + 0x100)
+#define RT5350_SDM_TBCNT (RT5350_SDM_OFFSET + 0x104)
+#define RT5350_SDM_RPCNT (RT5350_SDM_OFFSET + 0x108)
+#define RT5350_SDM_RBCNT (RT5350_SDM_OFFSET + 0x10C)
+#define RT5350_SDM_CS_ERR (RT5350_SDM_OFFSET + 0x110)
+
+#define RT5350_SDM_ICS_EN BIT(16)
+#define RT5350_SDM_TCS_EN BIT(17)
+#define RT5350_SDM_UCS_EN BIT(18)
+
+/* QDMA registers */
+#define MTK_QTX_CFG(x) (0x1800 + (x * 0x10))
+#define MTK_QTX_SCH(x) (0x1804 + (x * 0x10))
+#define MTK_QRX_BASE_PTR0 0x1900
+#define MTK_QRX_MAX_CNT0 0x1904
+#define MTK_QRX_CRX_IDX0 0x1908
+#define MTK_QRX_DRX_IDX0 0x190C
+#define MTK_QDMA_GLO_CFG 0x1A04
+#define MTK_QDMA_RST_IDX 0x1A08
+#define MTK_QDMA_DELAY_INT 0x1A0C
+#define MTK_QDMA_FC_THRES 0x1A10
+#define MTK_QMTK_INT_STATUS 0x1A18
+#define MTK_QMTK_INT_ENABLE 0x1A1C
+#define MTK_QDMA_HRED2 0x1A44
+
+#define MTK_QTX_CTX_PTR 0x1B00
+#define MTK_QTX_DTX_PTR 0x1B04
+
+#define MTK_QTX_CRX_PTR 0x1B10
+#define MTK_QTX_DRX_PTR 0x1B14
+
+#define MTK_QDMA_FQ_HEAD 0x1B20
+#define MTK_QDMA_FQ_TAIL 0x1B24
+#define MTK_QDMA_FQ_CNT 0x1B28
+#define MTK_QDMA_FQ_BLEN 0x1B2C
+
+#define QDMA_PAGE_SIZE 2048
+#define QDMA_TX_OWNER_CPU BIT(31)
+#define QDMA_TX_SWC BIT(14)
+#define TX_QDMA_SDL(_x) (((_x) & 0x3fff) << 16)
+#define QDMA_RES_THRES 4
+
+/* MDIO_CFG register bits */
+#define MTK_MDIO_CFG_AUTO_POLL_EN BIT(29)
+#define MTK_MDIO_CFG_GP1_BP_EN BIT(16)
+#define MTK_MDIO_CFG_GP1_FRC_EN BIT(15)
+#define MTK_MDIO_CFG_GP1_SPEED_10 (0 << 13)
+#define MTK_MDIO_CFG_GP1_SPEED_100 (1 << 13)
+#define MTK_MDIO_CFG_GP1_SPEED_1000 (2 << 13)
+#define MTK_MDIO_CFG_GP1_DUPLEX BIT(12)
+#define MTK_MDIO_CFG_GP1_FC_TX BIT(11)
+#define MTK_MDIO_CFG_GP1_FC_RX BIT(10)
+#define MTK_MDIO_CFG_GP1_LNK_DWN BIT(9)
+#define MTK_MDIO_CFG_GP1_AN_FAIL BIT(8)
+#define MTK_MDIO_CFG_MDC_CLK_DIV_1 (0 << 6)
+#define MTK_MDIO_CFG_MDC_CLK_DIV_2 (1 << 6)
+#define MTK_MDIO_CFG_MDC_CLK_DIV_4 (2 << 6)
+#define MTK_MDIO_CFG_MDC_CLK_DIV_8 (3 << 6)
+#define MTK_MDIO_CFG_TURBO_MII_FREQ BIT(5)
+#define MTK_MDIO_CFG_TURBO_MII_MODE BIT(4)
+#define MTK_MDIO_CFG_RX_CLK_SKEW_0 (0 << 2)
+#define MTK_MDIO_CFG_RX_CLK_SKEW_200 (1 << 2)
+#define MTK_MDIO_CFG_RX_CLK_SKEW_400 (2 << 2)
+#define MTK_MDIO_CFG_RX_CLK_SKEW_INV (3 << 2)
+#define MTK_MDIO_CFG_TX_CLK_SKEW_0 0
+#define MTK_MDIO_CFG_TX_CLK_SKEW_200 1
+#define MTK_MDIO_CFG_TX_CLK_SKEW_400 2
+#define MTK_MDIO_CFG_TX_CLK_SKEW_INV 3
+
+/* uni-cast port */
+#define MTK_GDM1_JMB_LEN_MASK 0xf
+#define MTK_GDM1_JMB_LEN_SHIFT 28
+#define MTK_GDM1_ICS_EN BIT(22)
+#define MTK_GDM1_TCS_EN BIT(21)
+#define MTK_GDM1_UCS_EN BIT(20)
+#define MTK_GDM1_JMB_EN BIT(19)
+#define MTK_GDM1_STRPCRC BIT(16)
+#define MTK_GDM1_UFRC_P_CPU (0 << 12)
+#define MTK_GDM1_UFRC_P_GDMA1 (1 << 12)
+#define MTK_GDM1_UFRC_P_PPE (6 << 12)
+
+/* checksums */
+#define MTK_ICS_GEN_EN BIT(2)
+#define MTK_UCS_GEN_EN BIT(1)
+#define MTK_TCS_GEN_EN BIT(0)
+
+/* dma mode */
+#define MTK_PDMA BIT(0)
+#define MTK_QDMA BIT(1)
+#define MTK_PDMA_RX_QDMA_TX (MTK_PDMA | MTK_QDMA)
+
+/* dma ring */
+#define MTK_PST_DRX_IDX0 BIT(16)
+#define MTK_PST_DTX_IDX3 BIT(3)
+#define MTK_PST_DTX_IDX2 BIT(2)
+#define MTK_PST_DTX_IDX1 BIT(1)
+#define MTK_PST_DTX_IDX0 BIT(0)
+
+#define MTK_RX_2B_OFFSET BIT(31)
+#define MTK_TX_WB_DDONE BIT(6)
+#define MTK_RX_DMA_BUSY BIT(3)
+#define MTK_TX_DMA_BUSY BIT(1)
+#define MTK_RX_DMA_EN BIT(2)
+#define MTK_TX_DMA_EN BIT(0)
+
+#define MTK_PDMA_SIZE_4DWORDS (0 << 4)
+#define MTK_PDMA_SIZE_8DWORDS (1 << 4)
+#define MTK_PDMA_SIZE_16DWORDS (2 << 4)
+
+#define MTK_US_CYC_CNT_MASK 0xff
+#define MTK_US_CYC_CNT_SHIFT 0x8
+#define MTK_US_CYC_CNT_DIVISOR 1000000
+
+/* PDMA descriptor rxd2 */
+#define RX_DMA_DONE BIT(31)
+#define RX_DMA_LSO BIT(30)
+#define RX_DMA_PLEN0(_x) (((_x) & 0x3fff) << 16)
+#define RX_DMA_GET_PLEN0(_x) (((_x) >> 16) & 0x3fff)
+#define RX_DMA_TAG BIT(15)
+
+/* PDMA descriptor rxd3 */
+#define RX_DMA_TPID(_x) (((_x) >> 16) & 0xffff)
+#define RX_DMA_VID(_x) ((_x) & 0xfff)
+
+/* PDMA descriptor rxd4 */
+#define RX_DMA_L4VALID BIT(30)
+#define RX_DMA_FPORT_SHIFT 19
+#define RX_DMA_FPORT_MASK 0x7
+
+struct mtk_rx_dma {
+ unsigned int rxd1;
+ unsigned int rxd2;
+ unsigned int rxd3;
+ unsigned int rxd4;
+} __packed __aligned(4);
+
+/* PDMA tx descriptor bits */
+#define TX_DMA_BUF_LEN 0x3fff
+#define TX_DMA_PLEN0_MASK (TX_DMA_BUF_LEN << 16)
+#define TX_DMA_PLEN0(_x) (((_x) & TX_DMA_BUF_LEN) << 16)
+#define TX_DMA_PLEN1(_x) ((_x) & TX_DMA_BUF_LEN)
+#define TX_DMA_GET_PLEN0(_x) (((_x) >> 16) & TX_DMA_BUF_LEN)
+#define TX_DMA_GET_PLEN1(_x) ((_x) & TX_DMA_BUF_LEN)
+#define TX_DMA_LS1 BIT(14)
+#define TX_DMA_LS0 BIT(30)
+#define TX_DMA_DONE BIT(31)
+#define TX_DMA_FPORT_SHIFT 25
+#define TX_DMA_FPORT_MASK 0x7
+#define TX_DMA_INS_VLAN_MT7621 BIT(16)
+#define TX_DMA_INS_VLAN BIT(7)
+#define TX_DMA_INS_PPPOE BIT(12)
+#define TX_DMA_TAG BIT(15)
+#define TX_DMA_TAG_MASK BIT(15)
+#define TX_DMA_QN(_x) ((_x) << 16)
+#define TX_DMA_PN(_x) ((_x) << 24)
+#define TX_DMA_QN_MASK TX_DMA_QN(0x7)
+#define TX_DMA_PN_MASK TX_DMA_PN(0x7)
+#define TX_DMA_UDF BIT(20)
+#define TX_DMA_CHKSUM (0x7 << 29)
+#define TX_DMA_TSO BIT(28)
+#define TX_DMA_DESP4_DEF (TX_DMA_QN(3) | TX_DMA_PN(1))
+
+/* frame engine counters */
+#define MTK_PPE_AC_BCNT0 (MTK_CMTABLE_OFFSET + 0x00)
+#define MTK_GDMA1_TX_GBCNT (MTK_CMTABLE_OFFSET + 0x300)
+#define MTK_GDMA2_TX_GBCNT (MTK_GDMA1_TX_GBCNT + 0x40)
+
+/* phy device flags */
+#define MTK_PHY_FLAG_PORT BIT(0)
+#define MTK_PHY_FLAG_ATTACH BIT(1)
+
+struct mtk_tx_dma {
+ unsigned int txd1;
+ unsigned int txd2;
+ unsigned int txd3;
+ unsigned int txd4;
+} __packed __aligned(4);
+
+struct mtk_eth;
+struct mtk_mac;
+
+/* manage the attached phys */
+struct mtk_phy {
+ spinlock_t lock;
+
+ struct phy_device *phy[8];
+ struct device_node *phy_node[8];
+ const __be32 *phy_fixed[8];
+ int duplex[8];
+ int speed[8];
+ int tx_fc[8];
+ int rx_fc[8];
+ int (*connect)(struct mtk_mac *mac);
+ void (*disconnect)(struct mtk_mac *mac);
+ void (*start)(struct mtk_mac *mac);
+ void (*stop)(struct mtk_mac *mac);
+};
+
+/* struct mtk_soc_data - the structure that holds the SoC specific data
+ * @reg_table: Some of the legacy registers changed their location
+ * over time. Their offsets are stored in this table
+ *
+ * @init_data: Some features depend on the silicon revision. This
+ * callback allows runtime modification of the content of
+ * this struct
+ * @reset_fe: This callback is used to trigger the reset of the frame
+ * engine
+ * @set_mac: This callback is used to set the unicast mac address
+ * filter
+ * @fwd_config: This callback is used to setup the forward config
+ * register of the MAC
+ * @switch_init: This callback is used to bring up the switch core
+ * @port_init: Some SoCs have ports that can be router to a switch port
+ * or an external PHY. This callback is used to setup these
+ * ports.
+ * @has_carrier: This callback allows driver to check if there is a cable
+ * attached.
+ * @mdio_init: This callbck is used to setup the MDIO bus if one is
+ * present
+ * @mdio_cleanup: This callback is used to cleanup the MDIO state.
+ * @mdio_write: This callback is used to write data to the MDIO bus.
+ * @mdio_read: This callback is used to write data to the MDIO bus.
+ * @mdio_adjust_link: This callback is used to apply the PHY settings.
+ * @piac_offset: the PIAC register has a different different base offset
+ * @hw_features: feature set depends on the SoC type
+ * @dma_ring_size: allow GBit SoCs to set bigger rings than FE SoCs
+ * @napi_weight: allow GBit SoCs to set bigger napi weight than FE SoCs
+ * @dma_type: SoCs is PDMA, QDMA or a mix of the 2
+ * @pdma_glo_cfg: the default DMA configuration
+ * @rx_int: the TX interrupt bits used by the SoC
+ * @tx_int: the TX interrupt bits used by the SoC
+ * @status_int: the Status interrupt bits used by the SoC
+ * @checksum_bit: the bits used to turn on HW checksumming
+ * @txd4: default value of the TXD4 descriptor
+ * @mac_count: the number of MACs that the SoC has
+ * @new_stats: there is a old and new way to read hardware stats
+ * registers
+ * @jumbo_frame: does the SoC support jumbo frames ?
+ * @rx_2b_offset: tell the rx dma to offset the data by 2 bytes
+ * @rx_sg_dma: scatter gather support
+ * @padding_64b enable 64 bit padding
+ * @padding_bug: rt2880 has a padding bug
+ * @has_switch: does the SoC have a built-in switch
+ *
+ * Although all of the supported SoCs share the same basic functionality, there
+ * are several SoC specific functions and features that we need to support. This
+ * struct holds the SoC specific data so that the common core can figure out
+ * how to setup and use these differences.
+ */
+struct mtk_soc_data {
+ const u16 *reg_table;
+
+ void (*init_data)(struct mtk_soc_data *data, struct net_device *netdev);
+ void (*reset_fe)(struct mtk_eth *eth);
+ void (*set_mac)(struct mtk_mac *mac, unsigned char *macaddr);
+ int (*fwd_config)(struct mtk_eth *eth);
+ int (*switch_init)(struct mtk_eth *eth);
+ void (*port_init)(struct mtk_eth *eth, struct mtk_mac *mac,
+ struct device_node *port);
+ int (*has_carrier)(struct mtk_eth *eth);
+ int (*mdio_init)(struct mtk_eth *eth);
+ void (*mdio_cleanup)(struct mtk_eth *eth);
+ int (*mdio_write)(struct mii_bus *bus, int phy_addr, int phy_reg,
+ u16 val);
+ int (*mdio_read)(struct mii_bus *bus, int phy_addr, int phy_reg);
+ void (*mdio_adjust_link)(struct mtk_eth *eth, int port);
+ u32 piac_offset;
+ netdev_features_t hw_features;
+ u32 dma_ring_size;
+ u32 napi_weight;
+ u32 dma_type;
+ u32 pdma_glo_cfg;
+ u32 rx_int;
+ u32 tx_int;
+ u32 status_int;
+ u32 checksum_bit;
+ u32 txd4;
+ u32 mac_count;
+
+ u32 new_stats:1;
+ u32 jumbo_frame:1;
+ u32 rx_2b_offset:1;
+ u32 rx_sg_dma:1;
+ u32 padding_64b:1;
+ u32 padding_bug:1;
+ u32 has_switch:1;
+};
+
+/* ugly macro hack to make sure hw_stats and ethtool strings are consistent */
+#define MTK_STAT_OFFSET 0x40
+#define MTK_STAT_REG_DECLARE \
+ _FE(tx_bytes) \
+ _FE(tx_packets) \
+ _FE(tx_skip) \
+ _FE(tx_collisions) \
+ _FE(rx_bytes) \
+ _FE(rx_packets) \
+ _FE(rx_overflow) \
+ _FE(rx_fcs_errors) \
+ _FE(rx_short_errors) \
+ _FE(rx_long_errors) \
+ _FE(rx_checksum_errors) \
+ _FE(rx_flow_control_packets)
+
+/* struct mtk_hw_stats - the structure that holds the traffic statistics.
+ * @stats_lock: make sure that stats operations are atomic
+ * @reg_offset: the status register offset of the SoC
+ * @syncp: the refcount
+ *
+ * All of the supported SoCs have hardware counters for traffic statstics.
+ * Whenever the status IRQ triggers we can read the latest stats from these
+ * counters and store them in this struct.
+ */
+struct mtk_hw_stats {
+ spinlock_t stats_lock;
+ u32 reg_offset;
+ struct u64_stats_sync syncp;
+
+#define _FE(x) u64 x;
+ MTK_STAT_REG_DECLARE
+#undef _FE
+};
+
+/* PDMA descriptor can point at 1-2 segments. This enum allows us to track how
+ * memory was allocated so that it can be freed properly
+ */
+enum mtk_tx_flags {
+ MTK_TX_FLAGS_SINGLE0 = 0x01,
+ MTK_TX_FLAGS_PAGE0 = 0x02,
+ MTK_TX_FLAGS_PAGE1 = 0x04,
+};
+
+/* struct mtk_tx_buf - This struct holds the pointers to the memory pointed at
+ * by the TX descriptor s
+ * @skb: The SKB pointer of the packet being sent
+ * @dma_addr0: The base addr of the first segment
+ * @dma_len0: The length of the first segment
+ * @dma_addr1: The base addr of the second segment
+ * @dma_len1: The length of the second segment
+ */
+struct mtk_tx_buf {
+ struct sk_buff *skb;
+ u32 flags;
+ DEFINE_DMA_UNMAP_ADDR(dma_addr0);
+ DEFINE_DMA_UNMAP_LEN(dma_len0);
+ DEFINE_DMA_UNMAP_ADDR(dma_addr1);
+ DEFINE_DMA_UNMAP_LEN(dma_len1);
+};
+
+/* struct mtk_tx_ring - This struct holds info describing a TX ring
+ * @tx_dma: The descriptor ring
+ * @tx_buf: The memory pointed at by the ring
+ * @tx_phys: The physical addr of tx_buf
+ * @tx_next_free: Pointer to the next free descriptor
+ * @tx_last_free: Pointer to the last free descriptor
+ * @tx_thresh: The threshold of minimum amount of free descriptors
+ * @tx_map: Callback to map a new packet into the ring
+ * @tx_poll: Callback for the housekeeping function
+ * @tx_clean: Callback for the cleanup function
+ * @tx_ring_size: How many descriptors are in the ring
+ * @tx_free_idx: The index of th next free descriptor
+ * @tx_next_idx: QDMA uses a linked list. This element points to the next
+ * free descriptor in the list
+ * @tx_free_count: QDMA uses a linked list. Track how many free descriptors
+ * are present
+ */
+struct mtk_tx_ring {
+ struct mtk_tx_dma *tx_dma;
+ struct mtk_tx_buf *tx_buf;
+ dma_addr_t tx_phys;
+ struct mtk_tx_dma *tx_next_free;
+ struct mtk_tx_dma *tx_last_free;
+ u16 tx_thresh;
+ int (*tx_map)(struct sk_buff *skb, struct net_device *dev, int tx_num,
+ struct mtk_tx_ring *ring, bool gso);
+ int (*tx_poll)(struct mtk_eth *eth, int budget, bool *tx_again);
+ void (*tx_clean)(struct mtk_eth *eth);
+
+ /* PDMA only */
+ u16 tx_ring_size;
+ u16 tx_free_idx;
+
+ /* QDMA only */
+ u16 tx_next_idx;
+ atomic_t tx_free_count;
+};
+
+/* struct mtk_rx_ring - This struct holds info describing a RX ring
+ * @rx_dma: The descriptor ring
+ * @rx_data: The memory pointed at by the ring
+ * @trx_phys: The physical addr of rx_buf
+ * @rx_ring_size: How many descriptors are in the ring
+ * @rx_buf_size: The size of each packet buffer
+ * @rx_calc_idx: The current head of ring
+ */
+struct mtk_rx_ring {
+ struct mtk_rx_dma *rx_dma;
+ u8 **rx_data;
+ dma_addr_t rx_phys;
+ u16 rx_ring_size;
+ u16 frag_size;
+ u16 rx_buf_size;
+ u16 rx_calc_idx;
+};
+
+/* currently no SoC has more than 2 macs */
+#define MTK_MAX_DEVS 2
+
+/* struct mtk_eth - This is the main datasructure for holding the state
+ * of the driver
+ * @dev: The device pointer
+ * @base: The mapped register i/o base
+ * @page_lock: Make sure that register operations are atomic
+ * @soc: pointer to our SoC specific data
+ * @dummy_dev: we run 2 netdevs on 1 physical DMA ring and need a
+ * dummy for NAPI to work
+ * @netdev: The netdev instances
+ * @mac: Each netdev is linked to a physical MAC
+ * @switch_np: The phandle for the switch
+ * @irq: The IRQ that we are using
+ * @msg_enable: Ethtool msg level
+ * @ysclk: The sysclk rate - neeed for calibration
+ * @ethsys: The register map pointing at the range used to setup
+ * MII modes
+ * @dma_refcnt: track how many netdevs are using the DMA engine
+ * @tx_ring: Pointer to the memore holding info about the TX ring
+ * @rx_ring: Pointer to the memore holding info about the RX ring
+ * @rx_napi: The NAPI struct
+ * @scratch_ring: Newer SoCs need memory for a second HW managed TX ring
+ * @scratch_head: The scratch memory that scratch_ring points to.
+ * @phy: Info about the attached PHYs
+ * @mii_bus: If there is a bus we need to create an instance for it
+ * @link: Track if the ports have a physical link
+ * @sw_priv: Pointer to the switches private data
+ * @vlan_map: RX VID tracking
+ */
+
+struct mtk_eth {
+ struct device *dev;
+ void __iomem *base;
+ spinlock_t page_lock;
+ struct mtk_soc_data *soc;
+ struct net_device dummy_dev;
+ struct net_device *netdev[MTK_MAX_DEVS];
+ struct mtk_mac *mac[MTK_MAX_DEVS];
+ struct device_node *switch_np;
+ int irq;
+ u32 msg_enable;
+ unsigned long sysclk;
+ struct regmap *ethsys;
+ atomic_t dma_refcnt;
+ struct mtk_tx_ring tx_ring;
+ struct mtk_rx_ring rx_ring[2];
+ struct napi_struct rx_napi;
+ struct mtk_tx_dma *scratch_ring;
+ void *scratch_head;
+ struct mtk_phy *phy;
+ struct mii_bus *mii_bus;
+ int link[8];
+ void *sw_priv;
+ unsigned long vlan_map;
+};
+
+/* struct mtk_mac - the structure that holds the info about the MACs of the
+ * SoC
+ * @id: The number of the MAC
+ * @of_node: Our devicetree node
+ * @hw: Backpointer to our main datastruture
+ * @hw_stats: Packet statistics counter
+ * @phy_dev: The attached PHY if available
+ * @phy_flags: The PHYs flags
+ * @pending_work: The workqueue used to reset the dma ring
+ */
+struct mtk_mac {
+ int id;
+ struct device_node *of_node;
+ struct mtk_eth *hw;
+ struct mtk_hw_stats *hw_stats;
+ struct phy_device *phy_dev;
+ u32 phy_flags;
+ struct work_struct pending_work;
+};
+
+/* the struct describing the SoC. these are declared in the soc_xyz.c files */
+extern const struct of_device_id of_mtk_match[];
+
+/* read the hardware status register */
+void mtk_stats_update_mac(struct mtk_mac *mac);
+
+/* default checksum setup handler */
+void mtk_reset(struct mtk_eth *eth, u32 reset_bits);
+
+/* register i/o wrappers */
+void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg);
+u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
+
+/* default clock calibration handler */
+int mtk_set_clock_cycle(struct mtk_eth *eth);
+
+/* default checksum setup handler */
+void mtk_csum_config(struct mtk_eth *eth);
+
+/* default forward config handler */
+void mtk_fwd_config(struct mtk_eth *eth);
+
+#endif /* MTK_ETH_H */
diff --git a/drivers/staging/mt7621-eth/soc_mt7621.c b/drivers/staging/mt7621-eth/soc_mt7621.c
new file mode 100644
index 000000000000..743c0eed89b6
--- /dev/null
+++ b/drivers/staging/mt7621-eth/soc_mt7621.c
@@ -0,0 +1,160 @@
+/* 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; 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.
+ *
+ * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/if_vlan.h>
+#include <linux/of_net.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+
+#include "mtk_eth_soc.h"
+#include "gsw_mt7620.h"
+#include "mdio.h"
+
+#define MT7620_CDMA_CSG_CFG 0x400
+#define MT7621_CDMP_IG_CTRL (MT7620_CDMA_CSG_CFG + 0x00)
+#define MT7621_CDMP_EG_CTRL (MT7620_CDMA_CSG_CFG + 0x04)
+#define MT7621_RESET_FE BIT(6)
+#define MT7621_L4_VALID BIT(24)
+
+#define MT7621_TX_DMA_UDF BIT(19)
+
+#define CDMA_ICS_EN BIT(2)
+#define CDMA_UCS_EN BIT(1)
+#define CDMA_TCS_EN BIT(0)
+
+#define GDMA_ICS_EN BIT(22)
+#define GDMA_TCS_EN BIT(21)
+#define GDMA_UCS_EN BIT(20)
+
+/* frame engine counters */
+#define MT7621_REG_MIB_OFFSET 0x2000
+#define MT7621_PPE_AC_BCNT0 (MT7621_REG_MIB_OFFSET + 0x00)
+#define MT7621_GDM1_TX_GBCNT (MT7621_REG_MIB_OFFSET + 0x400)
+#define MT7621_GDM2_TX_GBCNT (MT7621_GDM1_TX_GBCNT + 0x40)
+
+#define GSW_REG_GDMA1_MAC_ADRL 0x508
+#define GSW_REG_GDMA1_MAC_ADRH 0x50C
+#define GSW_REG_GDMA2_MAC_ADRL 0x1508
+#define GSW_REG_GDMA2_MAC_ADRH 0x150C
+
+
+#define MT7621_MTK_RST_GL 0x04
+#define MT7620_MTK_INT_STATUS2 0x08
+
+/* MTK_INT_STATUS reg on mt7620 define CNT_GDM1_AF at BIT(29)
+ * but after test it should be BIT(13).
+ */
+#define MT7621_MTK_GDM1_AF BIT(28)
+#define MT7621_MTK_GDM2_AF BIT(29)
+
+static const u16 mt7621_reg_table[MTK_REG_COUNT] = {
+ [MTK_REG_PDMA_GLO_CFG] = RT5350_PDMA_GLO_CFG,
+ [MTK_REG_PDMA_RST_CFG] = RT5350_PDMA_RST_CFG,
+ [MTK_REG_DLY_INT_CFG] = RT5350_DLY_INT_CFG,
+ [MTK_REG_TX_BASE_PTR0] = RT5350_TX_BASE_PTR0,
+ [MTK_REG_TX_MAX_CNT0] = RT5350_TX_MAX_CNT0,
+ [MTK_REG_TX_CTX_IDX0] = RT5350_TX_CTX_IDX0,
+ [MTK_REG_TX_DTX_IDX0] = RT5350_TX_DTX_IDX0,
+ [MTK_REG_RX_BASE_PTR0] = RT5350_RX_BASE_PTR0,
+ [MTK_REG_RX_MAX_CNT0] = RT5350_RX_MAX_CNT0,
+ [MTK_REG_RX_CALC_IDX0] = RT5350_RX_CALC_IDX0,
+ [MTK_REG_RX_DRX_IDX0] = RT5350_RX_DRX_IDX0,
+ [MTK_REG_MTK_INT_ENABLE] = RT5350_MTK_INT_ENABLE,
+ [MTK_REG_MTK_INT_STATUS] = RT5350_MTK_INT_STATUS,
+ [MTK_REG_MTK_DMA_VID_BASE] = 0,
+ [MTK_REG_MTK_COUNTER_BASE] = MT7621_GDM1_TX_GBCNT,
+ [MTK_REG_MTK_RST_GL] = MT7621_MTK_RST_GL,
+ [MTK_REG_MTK_INT_STATUS2] = MT7620_MTK_INT_STATUS2,
+};
+
+static void mt7621_mtk_reset(struct mtk_eth *eth)
+{
+ mtk_reset(eth, MT7621_RESET_FE);
+}
+
+static int mt7621_fwd_config(struct mtk_eth *eth)
+{
+ /* Setup GMAC1 only, there is no support for GMAC2 yet */
+ mtk_w32(eth, mtk_r32(eth, MT7620_GDMA1_FWD_CFG) & ~0xffff,
+ MT7620_GDMA1_FWD_CFG);
+
+ /* Enable RX checksum */
+ mtk_w32(eth, mtk_r32(eth, MT7620_GDMA1_FWD_CFG) | (GDMA_ICS_EN |
+ GDMA_TCS_EN | GDMA_UCS_EN),
+ MT7620_GDMA1_FWD_CFG);
+
+ /* Enable RX VLan Offloading */
+ mtk_w32(eth, 0, MT7621_CDMP_EG_CTRL);
+
+ return 0;
+}
+
+static void mt7621_set_mac(struct mtk_mac *mac, unsigned char *hwaddr)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mac->hw->page_lock, flags);
+ if (mac->id == 0) {
+ mtk_w32(mac->hw, (hwaddr[0] << 8) | hwaddr[1], GSW_REG_GDMA1_MAC_ADRH);
+ mtk_w32(mac->hw, (hwaddr[2] << 24) | (hwaddr[3] << 16) |
+ (hwaddr[4] << 8) | hwaddr[5],
+ GSW_REG_GDMA1_MAC_ADRL);
+ }
+ if (mac->id == 1) {
+ mtk_w32(mac->hw, (hwaddr[0] << 8) | hwaddr[1], GSW_REG_GDMA2_MAC_ADRH);
+ mtk_w32(mac->hw, (hwaddr[2] << 24) | (hwaddr[3] << 16) |
+ (hwaddr[4] << 8) | hwaddr[5],
+ GSW_REG_GDMA2_MAC_ADRL);
+ }
+ spin_unlock_irqrestore(&mac->hw->page_lock, flags);
+}
+
+static struct mtk_soc_data mt7621_data = {
+ .hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
+ NETIF_F_IPV6_CSUM,
+ .dma_type = MTK_PDMA,
+ .dma_ring_size = 256,
+ .napi_weight = 64,
+ .new_stats = 1,
+ .padding_64b = 1,
+ .rx_2b_offset = 1,
+ .rx_sg_dma = 1,
+ .has_switch = 1,
+ .mac_count = 2,
+ .reset_fe = mt7621_mtk_reset,
+ .set_mac = mt7621_set_mac,
+ .fwd_config = mt7621_fwd_config,
+ .switch_init = mtk_gsw_init,
+ .reg_table = mt7621_reg_table,
+ .pdma_glo_cfg = MTK_PDMA_SIZE_16DWORDS,
+ .rx_int = RT5350_RX_DONE_INT,
+ .tx_int = RT5350_TX_DONE_INT,
+ .status_int = MT7621_MTK_GDM1_AF | MT7621_MTK_GDM2_AF,
+ .checksum_bit = MT7621_L4_VALID,
+ .has_carrier = mt7620_has_carrier,
+ .mdio_read = mt7620_mdio_read,
+ .mdio_write = mt7620_mdio_write,
+ .mdio_adjust_link = mt7620_mdio_link_adjust,
+};
+
+const struct of_device_id of_mtk_match[] = {
+ { .compatible = "mediatek,mt7621-eth", .data = &mt7621_data },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, of_mtk_match);
diff --git a/drivers/staging/mt7621-gpio/Kconfig b/drivers/staging/mt7621-gpio/Kconfig
new file mode 100644
index 000000000000..c741ec3f4e50
--- /dev/null
+++ b/drivers/staging/mt7621-gpio/Kconfig
@@ -0,0 +1,6 @@
+config GPIO_MT7621
+ bool "Mediatek GPIO Support"
+ depends on SOC_MT7620 || SOC_MT7621
+ select ARCH_REQUIRE_GPIOLIB
+ help
+ Say yes here to support the Mediatek SoC GPIO device
diff --git a/drivers/staging/mt7621-gpio/Makefile b/drivers/staging/mt7621-gpio/Makefile
new file mode 100644
index 000000000000..e269ab1b8717
--- /dev/null
+++ b/drivers/staging/mt7621-gpio/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o
+
+ccflags-y += -I$(srctree)/$(src)/include
diff --git a/drivers/staging/mt7621-gpio/TODO b/drivers/staging/mt7621-gpio/TODO
new file mode 100644
index 000000000000..71439054e2e4
--- /dev/null
+++ b/drivers/staging/mt7621-gpio/TODO
@@ -0,0 +1,5 @@
+
+- general code review and clean up
+- ensure device-tree requirements are documented
+
+Cc: NeilBrown <neil@brown.name>
diff --git a/drivers/staging/mt7621-gpio/gpio-mt7621.c b/drivers/staging/mt7621-gpio/gpio-mt7621.c
new file mode 100644
index 000000000000..51235687ddb6
--- /dev/null
+++ b/drivers/staging/mt7621-gpio/gpio-mt7621.c
@@ -0,0 +1,352 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/spinlock.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#define MTK_MAX_BANK 3
+#define MTK_BANK_WIDTH 32
+
+enum mediatek_gpio_reg {
+ GPIO_REG_CTRL = 0,
+ GPIO_REG_POL,
+ GPIO_REG_DATA,
+ GPIO_REG_DSET,
+ GPIO_REG_DCLR,
+ GPIO_REG_REDGE,
+ GPIO_REG_FEDGE,
+ GPIO_REG_HLVL,
+ GPIO_REG_LLVL,
+ GPIO_REG_STAT,
+ GPIO_REG_EDGE,
+};
+
+static void __iomem *mediatek_gpio_membase;
+static int mediatek_gpio_irq;
+static struct irq_domain *mediatek_gpio_irq_domain;
+
+static struct mtk_gc {
+ struct gpio_chip chip;
+ spinlock_t lock;
+ int bank;
+ u32 rising;
+ u32 falling;
+} *gc_map[MTK_MAX_BANK];
+
+static inline struct mtk_gc
+*to_mediatek_gpio(struct gpio_chip *chip)
+{
+ struct mtk_gc *mgc;
+
+ mgc = container_of(chip, struct mtk_gc, chip);
+
+ return mgc;
+}
+
+static inline void
+mtk_gpio_w32(struct mtk_gc *rg, u8 reg, u32 val)
+{
+ iowrite32(val, mediatek_gpio_membase + (reg * 0x10) + (rg->bank * 0x4));
+}
+
+static inline u32
+mtk_gpio_r32(struct mtk_gc *rg, u8 reg)
+{
+ return ioread32(mediatek_gpio_membase + (reg * 0x10) + (rg->bank * 0x4));
+}
+
+static void
+mediatek_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct mtk_gc *rg = to_mediatek_gpio(chip);
+
+ mtk_gpio_w32(rg, (value) ? GPIO_REG_DSET : GPIO_REG_DCLR, BIT(offset));
+}
+
+static int
+mediatek_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct mtk_gc *rg = to_mediatek_gpio(chip);
+
+ return !!(mtk_gpio_r32(rg, GPIO_REG_DATA) & BIT(offset));
+}
+
+static int
+mediatek_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct mtk_gc *rg = to_mediatek_gpio(chip);
+ unsigned long flags;
+ u32 t;
+
+ spin_lock_irqsave(&rg->lock, flags);
+ t = mtk_gpio_r32(rg, GPIO_REG_CTRL);
+ t &= ~BIT(offset);
+ mtk_gpio_w32(rg, GPIO_REG_CTRL, t);
+ spin_unlock_irqrestore(&rg->lock, flags);
+
+ return 0;
+}
+
+static int
+mediatek_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct mtk_gc *rg = to_mediatek_gpio(chip);
+ unsigned long flags;
+ u32 t;
+
+ spin_lock_irqsave(&rg->lock, flags);
+ t = mtk_gpio_r32(rg, GPIO_REG_CTRL);
+ t |= BIT(offset);
+ mtk_gpio_w32(rg, GPIO_REG_CTRL, t);
+ mediatek_gpio_set(chip, offset, value);
+ spin_unlock_irqrestore(&rg->lock, flags);
+
+ return 0;
+}
+
+static int
+mediatek_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ struct mtk_gc *rg = to_mediatek_gpio(chip);
+ unsigned long flags;
+ u32 t;
+
+ spin_lock_irqsave(&rg->lock, flags);
+ t = mtk_gpio_r32(rg, GPIO_REG_CTRL);
+ spin_unlock_irqrestore(&rg->lock, flags);
+
+ if (t & BIT(offset))
+ return 0;
+
+ return 1;
+}
+
+static int
+mediatek_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
+{
+ struct mtk_gc *rg = to_mediatek_gpio(chip);
+
+ return irq_create_mapping(mediatek_gpio_irq_domain, pin + (rg->bank * MTK_BANK_WIDTH));
+}
+
+static int
+mediatek_gpio_bank_probe(struct platform_device *pdev, struct device_node *bank)
+{
+ const __be32 *id = of_get_property(bank, "reg", NULL);
+ struct mtk_gc *rg = devm_kzalloc(&pdev->dev,
+ sizeof(struct mtk_gc), GFP_KERNEL);
+
+ if (!rg || !id || be32_to_cpu(*id) > MTK_MAX_BANK)
+ return -ENOMEM;
+
+ gc_map[be32_to_cpu(*id)] = rg;
+
+ memset(rg, 0, sizeof(struct mtk_gc));
+
+ spin_lock_init(&rg->lock);
+
+ rg->chip.parent = &pdev->dev;
+ rg->chip.label = dev_name(&pdev->dev);
+ rg->chip.of_node = bank;
+ rg->chip.base = MTK_BANK_WIDTH * be32_to_cpu(*id);
+ rg->chip.ngpio = MTK_BANK_WIDTH;
+ rg->chip.direction_input = mediatek_gpio_direction_input;
+ rg->chip.direction_output = mediatek_gpio_direction_output;
+ rg->chip.get_direction = mediatek_gpio_get_direction;
+ rg->chip.get = mediatek_gpio_get;
+ rg->chip.set = mediatek_gpio_set;
+ if (mediatek_gpio_irq_domain)
+ rg->chip.to_irq = mediatek_gpio_to_irq;
+ rg->bank = be32_to_cpu(*id);
+
+ /* set polarity to low for all gpios */
+ mtk_gpio_w32(rg, GPIO_REG_POL, 0);
+
+ dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
+
+ return gpiochip_add(&rg->chip);
+}
+
+static void
+mediatek_gpio_irq_handler(struct irq_desc *desc)
+{
+ int i;
+
+ for (i = 0; i < MTK_MAX_BANK; i++) {
+ struct mtk_gc *rg = gc_map[i];
+ unsigned long pending;
+ int bit;
+
+ if (!rg)
+ continue;
+
+ pending = mtk_gpio_r32(rg, GPIO_REG_STAT);
+
+ for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) {
+ u32 map = irq_find_mapping(mediatek_gpio_irq_domain, (MTK_BANK_WIDTH * i) + bit);
+
+ generic_handle_irq(map);
+ mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit));
+ }
+ }
+}
+
+static void
+mediatek_gpio_irq_unmask(struct irq_data *d)
+{
+ int pin = d->hwirq;
+ int bank = pin / 32;
+ struct mtk_gc *rg = gc_map[bank];
+ unsigned long flags;
+ u32 rise, fall;
+
+ if (!rg)
+ return;
+
+ rise = mtk_gpio_r32(rg, GPIO_REG_REDGE);
+ fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
+
+ spin_lock_irqsave(&rg->lock, flags);
+ mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(d->hwirq) & rg->rising));
+ mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(d->hwirq) & rg->falling));
+ spin_unlock_irqrestore(&rg->lock, flags);
+}
+
+static void
+mediatek_gpio_irq_mask(struct irq_data *d)
+{
+ int pin = d->hwirq;
+ int bank = pin / 32;
+ struct mtk_gc *rg = gc_map[bank];
+ unsigned long flags;
+ u32 rise, fall;
+
+ if (!rg)
+ return;
+
+ rise = mtk_gpio_r32(rg, GPIO_REG_REDGE);
+ fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
+
+ spin_lock_irqsave(&rg->lock, flags);
+ mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(d->hwirq));
+ mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(d->hwirq));
+ spin_unlock_irqrestore(&rg->lock, flags);
+}
+
+static int
+mediatek_gpio_irq_type(struct irq_data *d, unsigned int type)
+{
+ int pin = d->hwirq;
+ int bank = pin / 32;
+ struct mtk_gc *rg = gc_map[bank];
+ u32 mask = BIT(d->hwirq);
+
+ if (!rg)
+ return -1;
+
+ if (type == IRQ_TYPE_PROBE) {
+ if ((rg->rising | rg->falling) & mask)
+ return 0;
+
+ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+ }
+
+ if (type & IRQ_TYPE_EDGE_RISING)
+ rg->rising |= mask;
+ else
+ rg->rising &= ~mask;
+
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ rg->falling |= mask;
+ else
+ rg->falling &= ~mask;
+
+ return 0;
+}
+
+static struct irq_chip mediatek_gpio_irq_chip = {
+ .name = "GPIO",
+ .irq_unmask = mediatek_gpio_irq_unmask,
+ .irq_mask = mediatek_gpio_irq_mask,
+ .irq_mask_ack = mediatek_gpio_irq_mask,
+ .irq_set_type = mediatek_gpio_irq_type,
+};
+
+static int
+mediatek_gpio_gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(irq, &mediatek_gpio_irq_chip, handle_level_irq);
+ irq_set_handler_data(irq, d);
+
+ return 0;
+}
+
+static const struct irq_domain_ops irq_domain_ops = {
+ .xlate = irq_domain_xlate_onecell,
+ .map = mediatek_gpio_gpio_map,
+};
+
+static int
+mediatek_gpio_probe(struct platform_device *pdev)
+{
+ struct device_node *bank, *np = pdev->dev.of_node;
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ mediatek_gpio_membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mediatek_gpio_membase))
+ return PTR_ERR(mediatek_gpio_membase);
+
+ mediatek_gpio_irq = irq_of_parse_and_map(np, 0);
+ if (mediatek_gpio_irq) {
+ mediatek_gpio_irq_domain = irq_domain_add_linear(np,
+ MTK_MAX_BANK * MTK_BANK_WIDTH,
+ &irq_domain_ops, NULL);
+ if (!mediatek_gpio_irq_domain)
+ dev_err(&pdev->dev, "irq_domain_add_linear failed\n");
+ }
+
+ for_each_child_of_node(np, bank)
+ if (of_device_is_compatible(bank, "mtk,mt7621-gpio-bank"))
+ mediatek_gpio_bank_probe(pdev, bank);
+
+ if (mediatek_gpio_irq_domain)
+ irq_set_chained_handler(mediatek_gpio_irq, mediatek_gpio_irq_handler);
+
+ return 0;
+}
+
+static const struct of_device_id mediatek_gpio_match[] = {
+ { .compatible = "mtk,mt7621-gpio" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mediatek_gpio_match);
+
+static struct platform_driver mediatek_gpio_driver = {
+ .probe = mediatek_gpio_probe,
+ .driver = {
+ .name = "mt7621_gpio",
+ .of_match_table = mediatek_gpio_match,
+ },
+};
+
+static int __init
+mediatek_gpio_init(void)
+{
+ return platform_driver_register(&mediatek_gpio_driver);
+}
+
+subsys_initcall(mediatek_gpio_init);
diff --git a/drivers/staging/mt7621-mmc/Kconfig b/drivers/staging/mt7621-mmc/Kconfig
new file mode 100644
index 000000000000..c6dfe8c637dc
--- /dev/null
+++ b/drivers/staging/mt7621-mmc/Kconfig
@@ -0,0 +1,16 @@
+config MTK_MMC
+ tristate "MTK SD/MMC"
+ depends on !MTD_NAND_RALINK && MMC
+
+config MTK_AEE_KDUMP
+ bool "MTK AEE KDUMP"
+ depends on MTK_MMC
+
+config MTK_MMC_CD_POLL
+ bool "Card Detect with Polling"
+ depends on MTK_MMC
+
+config MTK_MMC_EMMC_8BIT
+ bool "eMMC 8-bit support"
+ depends on MTK_MMC && RALINK_MT7628
+
diff --git a/drivers/staging/mt7621-mmc/Makefile b/drivers/staging/mt7621-mmc/Makefile
new file mode 100644
index 000000000000..caead0b54703
--- /dev/null
+++ b/drivers/staging/mt7621-mmc/Makefile
@@ -0,0 +1,42 @@
+# Copyright Statement:
+#
+# This software/firmware and related documentation ("MediaTek Software") are
+# protected under relevant copyright laws. The information contained herein
+# is confidential and proprietary to MediaTek Inc. and/or its licensors.
+# Without the prior written permission of MediaTek inc. and/or its licensors,
+# any reproduction, modification, use or disclosure of MediaTek Software,
+# and information contained herein, in whole or in part, shall be strictly prohibited.
+#
+# MediaTek Inc. (C) 2010. All rights reserved.
+#
+# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+#
+# The following software/firmware and/or related documentation ("MediaTek Software")
+# have been modified by MediaTek Inc. All revisions are subject to any receiver's
+# applicable license agreements with MediaTek Inc.
+
+obj-$(CONFIG_MTK_MMC) += mtk_sd.o
+mtk_sd-objs := sd.o dbg.o
+ifeq ($(CONFIG_MTK_AEE_KDUMP),y)
+EXTRA_CFLAGS += -DMT6575_SD_DEBUG
+endif
+
+clean:
+ @rm -f *.o modules.order .*.cmd
diff --git a/drivers/staging/mt7621-mmc/TODO b/drivers/staging/mt7621-mmc/TODO
new file mode 100644
index 000000000000..febb32d37e07
--- /dev/null
+++ b/drivers/staging/mt7621-mmc/TODO
@@ -0,0 +1,8 @@
+
+- general code review and clean up
+- ensure device-tree requirements are documented
+- should probably be merged with drivers/mmc/host/mtk-sd.c
+- possibly fix to work with highmem pages so a bounce buffer isn't
+ needed.
+
+Cc: NeilBrown <neil@brown.name>
diff --git a/drivers/staging/mt7621-mmc/board.h b/drivers/staging/mt7621-mmc/board.h
new file mode 100644
index 000000000000..33bfc7b9597a
--- /dev/null
+++ b/drivers/staging/mt7621-mmc/board.h
@@ -0,0 +1,137 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef __ARCH_ARM_MACH_BOARD_H
+#define __ARCH_ARM_MACH_BOARD_H
+
+#include <generated/autoconf.h>
+#include <linux/pm.h>
+/* --- chhung */
+// #include <mach/mt6575.h>
+// #include <board-custom.h>
+/* end of chhung */
+
+typedef void (*sdio_irq_handler_t)(void*); /* external irq handler */
+typedef void (*pm_callback_t)(pm_message_t state, void *data);
+
+#define MSDC_CD_PIN_EN (1 << 0) /* card detection pin is wired */
+#define MSDC_WP_PIN_EN (1 << 1) /* write protection pin is wired */
+#define MSDC_RST_PIN_EN (1 << 2) /* emmc reset pin is wired */
+#define MSDC_SDIO_IRQ (1 << 3) /* use internal sdio irq (bus) */
+#define MSDC_EXT_SDIO_IRQ (1 << 4) /* use external sdio irq */
+#define MSDC_REMOVABLE (1 << 5) /* removable slot */
+#define MSDC_SYS_SUSPEND (1 << 6) /* suspended by system */
+#define MSDC_HIGHSPEED (1 << 7) /* high-speed mode support */
+#define MSDC_UHS1 (1 << 8) /* uhs-1 mode support */
+#define MSDC_DDR (1 << 9) /* ddr mode support */
+
+
+#define MSDC_SMPL_RISING (0)
+#define MSDC_SMPL_FALLING (1)
+
+#define MSDC_CMD_PIN (0)
+#define MSDC_DAT_PIN (1)
+#define MSDC_CD_PIN (2)
+#define MSDC_WP_PIN (3)
+#define MSDC_RST_PIN (4)
+
+enum {
+ MSDC_CLKSRC_48MHZ = 0,
+// MSDC_CLKSRC_26MHZ = 0,
+// MSDC_CLKSRC_197MHZ = 1,
+// MSDC_CLKSRC_208MHZ = 2
+};
+
+struct msdc_hw {
+ unsigned char clk_src; /* host clock source */
+ unsigned char cmd_edge; /* command latch edge */
+ unsigned char data_edge; /* data latch edge */
+ unsigned char clk_drv; /* clock pad driving */
+ unsigned char cmd_drv; /* command pad driving */
+ unsigned char dat_drv; /* data pad driving */
+ unsigned long flags; /* hardware capability flags */
+ unsigned long data_pins; /* data pins */
+ unsigned long data_offset; /* data address offset */
+
+ /* config gpio pull mode */
+ void (*config_gpio_pin)(int type, int pull);
+
+ /* external power control for card */
+ void (*ext_power_on)(void);
+ void (*ext_power_off)(void);
+
+ /* external sdio irq operations */
+ void (*request_sdio_eirq)(sdio_irq_handler_t sdio_irq_handler, void *data);
+ void (*enable_sdio_eirq)(void);
+ void (*disable_sdio_eirq)(void);
+
+ /* external cd irq operations */
+ void (*request_cd_eirq)(sdio_irq_handler_t cd_irq_handler, void *data);
+ void (*enable_cd_eirq)(void);
+ void (*disable_cd_eirq)(void);
+ int (*get_cd_status)(void);
+
+ /* power management callback for external module */
+ void (*register_pm)(pm_callback_t pm_cb, void *data);
+};
+
+extern struct msdc_hw msdc0_hw;
+extern struct msdc_hw msdc1_hw;
+extern struct msdc_hw msdc2_hw;
+extern struct msdc_hw msdc3_hw;
+
+/*GPS driver*/
+#define GPS_FLAG_FORCE_OFF 0x0001
+struct mt3326_gps_hardware {
+ int (*ext_power_on)(int);
+ int (*ext_power_off)(int);
+};
+extern struct mt3326_gps_hardware mt3326_gps_hw;
+
+/* NAND driver */
+struct mt6575_nand_host_hw {
+ unsigned int nfi_bus_width; /* NFI_BUS_WIDTH */
+ unsigned int nfi_access_timing; /* NFI_ACCESS_TIMING */
+ unsigned int nfi_cs_num; /* NFI_CS_NUM */
+ unsigned int nand_sec_size; /* NAND_SECTOR_SIZE */
+ unsigned int nand_sec_shift; /* NAND_SECTOR_SHIFT */
+ unsigned int nand_ecc_size;
+ unsigned int nand_ecc_bytes;
+ unsigned int nand_ecc_mode;
+};
+extern struct mt6575_nand_host_hw mt6575_nand_hw;
+
+#endif /* __ARCH_ARM_MACH_BOARD_H */
+
diff --git a/drivers/staging/mt7621-mmc/dbg.c b/drivers/staging/mt7621-mmc/dbg.c
new file mode 100644
index 000000000000..4dc115b53993
--- /dev/null
+++ b/drivers/staging/mt7621-mmc/dbg.c
@@ -0,0 +1,347 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+// #include <mach/mt6575_gpt.h> /* --- by chhung */
+#include "dbg.h"
+#include "mt6575_sd.h"
+#include <linux/seq_file.h>
+
+static char cmd_buf[256];
+
+/* for debug zone */
+unsigned int sd_debug_zone[4]={
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+/* mode select */
+u32 dma_size[4]={
+ 512,
+ 512,
+ 512,
+ 512
+};
+msdc_mode drv_mode[4]={
+ MODE_SIZE_DEP, /* using DMA or not depend on the size */
+ MODE_SIZE_DEP,
+ MODE_SIZE_DEP,
+ MODE_SIZE_DEP
+};
+
+#if defined (MT6575_SD_DEBUG)
+/* for driver profile */
+#define TICKS_ONE_MS (13000)
+u32 gpt_enable = 0;
+u32 sdio_pro_enable = 0; /* make sure gpt is enabled */
+u32 sdio_pro_time = 0; /* no more than 30s */
+struct sdio_profile sdio_perfomance = {0};
+
+#if 0 /* --- chhung */
+void msdc_init_gpt(void)
+{
+ GPT_CONFIG config;
+
+ config.num = GPT6;
+ config.mode = GPT_FREE_RUN;
+ config.clkSrc = GPT_CLK_SRC_SYS;
+ config.clkDiv = GPT_CLK_DIV_1; /* 13MHz GPT6 */
+
+ if (GPT_Config(config) == FALSE )
+ return;
+
+ GPT_Start(GPT6);
+}
+#endif /* end of --- */
+
+u32 msdc_time_calc(u32 old_L32, u32 old_H32, u32 new_L32, u32 new_H32)
+{
+ u32 ret = 0;
+
+ if (new_H32 == old_H32) {
+ ret = new_L32 - old_L32;
+ } else if(new_H32 == (old_H32 + 1)) {
+ if (new_L32 > old_L32) {
+ printk("msdc old_L<0x%x> new_L<0x%x>\n", old_L32, new_L32);
+ }
+ ret = (0xffffffff - old_L32);
+ ret += new_L32;
+ } else {
+ printk("msdc old_H<0x%x> new_H<0x%x>\n", old_H32, new_H32);
+ }
+
+ return ret;
+}
+
+void msdc_sdio_profile(struct sdio_profile* result)
+{
+ struct cmd_profile* cmd;
+ u32 i;
+
+ printk("sdio === performance dump ===\n");
+ printk("sdio === total execute tick<%d> time<%dms> Tx<%dB> Rx<%dB>\n",
+ result->total_tc, result->total_tc / TICKS_ONE_MS,
+ result->total_tx_bytes, result->total_rx_bytes);
+
+ /* CMD52 Dump */
+ cmd = &result->cmd52_rx;
+ printk("sdio === CMD52 Rx <%d>times tick<%d> Max<%d> Min<%d> Aver<%d>\n", cmd->count, cmd->tot_tc,
+ cmd->max_tc, cmd->min_tc, cmd->tot_tc/cmd->count);
+ cmd = &result->cmd52_tx;
+ printk("sdio === CMD52 Tx <%d>times tick<%d> Max<%d> Min<%d> Aver<%d>\n", cmd->count, cmd->tot_tc,
+ cmd->max_tc, cmd->min_tc, cmd->tot_tc/cmd->count);
+
+ /* CMD53 Rx bytes + block mode */
+ for (i=0; i<512; i++) {
+ cmd = &result->cmd53_rx_byte[i];
+ if (cmd->count) {
+ printk("sdio<%6d><%3dB>_Rx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n", cmd->count, i, cmd->tot_tc,
+ cmd->max_tc, cmd->min_tc, cmd->tot_tc/cmd->count,
+ cmd->tot_bytes, (cmd->tot_bytes/10)*13 / (cmd->tot_tc/10));
+ }
+ }
+ for (i=0; i<100; i++) {
+ cmd = &result->cmd53_rx_blk[i];
+ if (cmd->count) {
+ printk("sdio<%6d><%3d>B_Rx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n", cmd->count, i, cmd->tot_tc,
+ cmd->max_tc, cmd->min_tc, cmd->tot_tc/cmd->count,
+ cmd->tot_bytes, (cmd->tot_bytes/10)*13 / (cmd->tot_tc/10));
+ }
+ }
+
+ /* CMD53 Tx bytes + block mode */
+ for (i=0; i<512; i++) {
+ cmd = &result->cmd53_tx_byte[i];
+ if (cmd->count) {
+ printk("sdio<%6d><%3dB>_Tx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n", cmd->count, i, cmd->tot_tc,
+ cmd->max_tc, cmd->min_tc, cmd->tot_tc/cmd->count,
+ cmd->tot_bytes, (cmd->tot_bytes/10)*13 / (cmd->tot_tc/10));
+ }
+ }
+ for (i=0; i<100; i++) {
+ cmd = &result->cmd53_tx_blk[i];
+ if (cmd->count) {
+ printk("sdio<%6d><%3d>B_Tx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n", cmd->count, i, cmd->tot_tc,
+ cmd->max_tc, cmd->min_tc, cmd->tot_tc/cmd->count,
+ cmd->tot_bytes, (cmd->tot_bytes/10)*13 / (cmd->tot_tc/10));
+ }
+ }
+
+ printk("sdio === performance dump done ===\n");
+}
+
+//========= sdio command table ===========
+void msdc_performance(u32 opcode, u32 sizes, u32 bRx, u32 ticks)
+{
+ struct sdio_profile* result = &sdio_perfomance;
+ struct cmd_profile* cmd;
+ u32 block;
+
+ if (sdio_pro_enable == 0) {
+ return;
+ }
+
+ if (opcode == 52) {
+ cmd = bRx ? &result->cmd52_rx : &result->cmd52_tx;
+ } else if (opcode == 53) {
+ if (sizes < 512) {
+ cmd = bRx ? &result->cmd53_rx_byte[sizes] : &result->cmd53_tx_byte[sizes];
+ } else {
+ block = sizes / 512;
+ if (block >= 99) {
+ printk("cmd53 error blocks\n");
+ while(1);
+ }
+ cmd = bRx ? &result->cmd53_rx_blk[block] : &result->cmd53_tx_blk[block];
+ }
+ } else {
+ return;
+ }
+
+ /* update the members */
+ if (ticks > cmd->max_tc){
+ cmd->max_tc = ticks;
+ }
+ if (cmd->min_tc == 0 || ticks < cmd->min_tc) {
+ cmd->min_tc = ticks;
+ }
+ cmd->tot_tc += ticks;
+ cmd->tot_bytes += sizes;
+ cmd->count ++;
+
+ if (bRx) {
+ result->total_rx_bytes += sizes;
+ } else {
+ result->total_tx_bytes += sizes;
+ }
+ result->total_tc += ticks;
+
+ /* dump when total_tc > 30s */
+ if (result->total_tc >= sdio_pro_time * TICKS_ONE_MS * 1000) {
+ msdc_sdio_profile(result);
+ memset(result, 0 , sizeof(struct sdio_profile));
+ }
+}
+
+//========== driver proc interface ===========
+static int msdc_debug_proc_read(struct seq_file *s, void *p)
+{
+ seq_printf(s, "\n=========================================\n");
+ seq_printf(s, "Index<0> + Id + Zone\n");
+ seq_printf(s, "-> PWR<9> WRN<8> | FIO<7> OPS<6> FUN<5> CFG<4> | INT<3> RSP<2> CMD<1> DMA<0>\n");
+ seq_printf(s, "-> echo 0 3 0x3ff >msdc_bebug -> host[3] debug zone set to 0x3ff\n");
+ seq_printf(s, "-> MSDC[0] Zone: 0x%.8x\n", sd_debug_zone[0]);
+ seq_printf(s, "-> MSDC[1] Zone: 0x%.8x\n", sd_debug_zone[1]);
+ seq_printf(s, "-> MSDC[2] Zone: 0x%.8x\n", sd_debug_zone[2]);
+ seq_printf(s, "-> MSDC[3] Zone: 0x%.8x\n", sd_debug_zone[3]);
+
+ seq_printf(s, "Index<1> + ID:4|Mode:4 + DMA_SIZE\n");
+ seq_printf(s, "-> 0)PIO 1)DMA 2)SIZE\n");
+ seq_printf(s, "-> echo 1 22 0x200 >msdc_bebug -> host[2] size mode, dma when >= 512\n");
+ seq_printf(s, "-> MSDC[0] mode<%d> size<%d>\n", drv_mode[0], dma_size[0]);
+ seq_printf(s, "-> MSDC[1] mode<%d> size<%d>\n", drv_mode[1], dma_size[1]);
+ seq_printf(s, "-> MSDC[2] mode<%d> size<%d>\n", drv_mode[2], dma_size[2]);
+ seq_printf(s, "-> MSDC[3] mode<%d> size<%d>\n", drv_mode[3], dma_size[3]);
+
+ seq_printf(s, "Index<3> + SDIO_PROFILE + TIME\n");
+ seq_printf(s, "-> echo 3 1 0x1E >msdc_bebug -> enable sdio_profile, 30s\n");
+ seq_printf(s, "-> SDIO_PROFILE<%d> TIME<%ds>\n", sdio_pro_enable, sdio_pro_time);
+ seq_printf(s, "=========================================\n\n");
+
+ return 0;
+}
+
+static ssize_t msdc_debug_proc_write(struct file *file,
+ const char __user *buf, size_t count, loff_t *data)
+{
+ int ret;
+
+ int cmd, p1, p2;
+ int id, zone;
+ int mode, size;
+
+ if (count == 0)return -1;
+ if(count > 255)count = 255;
+
+ ret = copy_from_user(cmd_buf, buf, count);
+ if (ret < 0)return -1;
+
+ cmd_buf[count] = '\0';
+ printk("msdc Write %s\n", cmd_buf);
+
+ sscanf(cmd_buf, "%x %x %x", &cmd, &p1, &p2);
+
+ if(cmd == SD_TOOL_ZONE) {
+ id = p1; zone = p2; zone &= 0x3ff;
+ printk("msdc host_id<%d> zone<0x%.8x>\n", id, zone);
+ if(id >=0 && id<=3){
+ sd_debug_zone[id] = zone;
+ }
+ else if(id == 4){
+ sd_debug_zone[0] = sd_debug_zone[1] = zone;
+ sd_debug_zone[2] = sd_debug_zone[3] = zone;
+ }
+ else{
+ printk("msdc host_id error when set debug zone\n");
+ }
+ } else if (cmd == SD_TOOL_DMA_SIZE) {
+ id = p1>>4; mode = (p1&0xf); size = p2;
+ if(id >=0 && id<=3){
+ drv_mode[id] = mode;
+ dma_size[id] = p2;
+ }
+ else if(id == 4){
+ drv_mode[0] = drv_mode[1] = mode;
+ drv_mode[2] = drv_mode[3] = mode;
+ dma_size[0] = dma_size[1] = p2;
+ dma_size[2] = dma_size[3] = p2;
+ }
+ else{
+ printk("msdc host_id error when select mode\n");
+ }
+ } else if (cmd == SD_TOOL_SDIO_PROFILE) {
+ if (p1 == 1) { /* enable profile */
+ if (gpt_enable == 0) {
+ // msdc_init_gpt(); /* --- by chhung */
+ gpt_enable = 1;
+ }
+ sdio_pro_enable = 1;
+ if (p2 == 0) p2 = 1; if (p2 >= 30) p2 = 30;
+ sdio_pro_time = p2 ;
+ } else if (p1 == 0) {
+ /* todo */
+ sdio_pro_enable = 0;
+ }
+ }
+
+ return count;
+}
+
+static int msdc_debug_show(struct inode *inode, struct file *file)
+{
+ return single_open(file, msdc_debug_proc_read, NULL);
+}
+
+static const struct file_operations msdc_debug_fops = {
+ .owner = THIS_MODULE,
+ .open = msdc_debug_show,
+ .read = seq_read,
+ .write = msdc_debug_proc_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+int msdc_debug_proc_init(void)
+{
+ struct proc_dir_entry *de = proc_create("msdc_debug", 0667, NULL, &msdc_debug_fops);
+
+ if (!de || IS_ERR(de))
+ printk("!! Create MSDC debug PROC fail !!\n");
+
+ return 0 ;
+}
+EXPORT_SYMBOL_GPL(msdc_debug_proc_init);
+#endif
diff --git a/drivers/staging/mt7621-mmc/dbg.h b/drivers/staging/mt7621-mmc/dbg.h
new file mode 100644
index 000000000000..e58c4312933e
--- /dev/null
+++ b/drivers/staging/mt7621-mmc/dbg.h
@@ -0,0 +1,156 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+#ifndef __MT_MSDC_DEUBG__
+#define __MT_MSDC_DEUBG__
+
+//==========================
+extern u32 sdio_pro_enable;
+/* for a type command, e.g. CMD53, 2 blocks */
+struct cmd_profile {
+ u32 max_tc; /* Max tick count */
+ u32 min_tc;
+ u32 tot_tc; /* total tick count */
+ u32 tot_bytes;
+ u32 count; /* the counts of the command */
+};
+
+/* dump when total_tc and total_bytes */
+struct sdio_profile {
+ u32 total_tc; /* total tick count of CMD52 and CMD53 */
+ u32 total_tx_bytes; /* total bytes of CMD53 Tx */
+ u32 total_rx_bytes; /* total bytes of CMD53 Rx */
+
+ /*CMD52*/
+ struct cmd_profile cmd52_tx;
+ struct cmd_profile cmd52_rx;
+
+ /*CMD53 in byte unit */
+ struct cmd_profile cmd53_tx_byte[512];
+ struct cmd_profile cmd53_rx_byte[512];
+
+ /*CMD53 in block unit */
+ struct cmd_profile cmd53_tx_blk[100];
+ struct cmd_profile cmd53_rx_blk[100];
+};
+
+//==========================
+typedef enum {
+ SD_TOOL_ZONE = 0,
+ SD_TOOL_DMA_SIZE = 1,
+ SD_TOOL_PM_ENABLE = 2,
+ SD_TOOL_SDIO_PROFILE = 3,
+} msdc_dbg;
+
+typedef enum {
+ MODE_PIO = 0,
+ MODE_DMA = 1,
+ MODE_SIZE_DEP = 2,
+} msdc_mode;
+extern msdc_mode drv_mode[4];
+extern u32 dma_size[4];
+
+/* Debug message event */
+#define DBG_EVT_NONE (0) /* No event */
+#define DBG_EVT_DMA (1 << 0) /* DMA related event */
+#define DBG_EVT_CMD (1 << 1) /* MSDC CMD related event */
+#define DBG_EVT_RSP (1 << 2) /* MSDC CMD RSP related event */
+#define DBG_EVT_INT (1 << 3) /* MSDC INT event */
+#define DBG_EVT_CFG (1 << 4) /* MSDC CFG event */
+#define DBG_EVT_FUC (1 << 5) /* Function event */
+#define DBG_EVT_OPS (1 << 6) /* Read/Write operation event */
+#define DBG_EVT_FIO (1 << 7) /* FIFO operation event */
+#define DBG_EVT_WRN (1 << 8) /* Warning event */
+#define DBG_EVT_PWR (1 << 9) /* Power event */
+#define DBG_EVT_ALL (0xffffffff)
+
+#define DBG_EVT_MASK (DBG_EVT_ALL)
+
+extern unsigned int sd_debug_zone[4];
+#define TAG "msdc"
+#if 0 /* +++ chhung */
+#define BUG_ON(x) \
+do { \
+ if (x) { \
+ printk("[BUG] %s LINE:%d FILE:%s\n", #x, __LINE__, __FILE__); \
+ while(1); \
+ } \
+}while(0)
+#endif /* end of +++ */
+
+#define N_MSG(evt, fmt, args...)
+/*
+do { \
+ if ((DBG_EVT_##evt) & sd_debug_zone[host->id]) { \
+ printk(KERN_ERR TAG"%d -> "fmt" <- %s() : L<%d> PID<%s><0x%x>\n", \
+ host->id, ##args , __FUNCTION__, __LINE__, current->comm, current->pid); \
+ } \
+} while(0)
+*/
+
+#define ERR_MSG(fmt, args...) \
+do { \
+ printk(KERN_ERR TAG"%d -> "fmt" <- %s() : L<%d> PID<%s><0x%x>\n", \
+ host->id, ##args , __FUNCTION__, __LINE__, current->comm, current->pid); \
+} while(0);
+
+#if 1
+//defined CONFIG_MTK_MMC_CD_POLL
+#define INIT_MSG(fmt, args...)
+#define IRQ_MSG(fmt, args...)
+#else
+#define INIT_MSG(fmt, args...) \
+do { \
+ printk(KERN_ERR TAG"%d -> "fmt" <- %s() : L<%d> PID<%s><0x%x>\n", \
+ host->id, ##args , __FUNCTION__, __LINE__, current->comm, current->pid); \
+} while(0);
+
+/* PID in ISR in not corrent */
+#define IRQ_MSG(fmt, args...) \
+do { \
+ printk(KERN_ERR TAG"%d -> "fmt" <- %s() : L<%d>\n", \
+ host->id, ##args , __FUNCTION__, __LINE__); \
+} while(0);
+#endif
+
+int msdc_debug_proc_init(void);
+
+#if 0 /* --- chhung */
+void msdc_init_gpt(void);
+extern void GPT_GetCounter64(UINT32 *cntL32, UINT32 *cntH32);
+#endif /* end of --- */
+u32 msdc_time_calc(u32 old_L32, u32 old_H32, u32 new_L32, u32 new_H32);
+void msdc_performance(u32 opcode, u32 sizes, u32 bRx, u32 ticks);
+
+#endif
diff --git a/drivers/staging/mt7621-mmc/mt6575_sd.h b/drivers/staging/mt7621-mmc/mt6575_sd.h
new file mode 100644
index 000000000000..e90c4f1d1df7
--- /dev/null
+++ b/drivers/staging/mt7621-mmc/mt6575_sd.h
@@ -0,0 +1,1001 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef MT6575_SD_H
+#define MT6575_SD_H
+
+#include <linux/bitops.h>
+#include <linux/mmc/host.h>
+
+// #include <mach/mt6575_reg_base.h> /* --- by chhung */
+
+/*--------------------------------------------------------------------------*/
+/* Common Macro */
+/*--------------------------------------------------------------------------*/
+#define REG_ADDR(x) ((volatile u32*)(base + OFFSET_##x))
+
+/*--------------------------------------------------------------------------*/
+/* Common Definition */
+/*--------------------------------------------------------------------------*/
+#define MSDC_FIFO_SZ (128)
+#define MSDC_FIFO_THD (64) // (128)
+#define MSDC_NUM (4)
+
+#define MSDC_MS (0)
+#define MSDC_SDMMC (1)
+
+#define MSDC_MODE_UNKNOWN (0)
+#define MSDC_MODE_PIO (1)
+#define MSDC_MODE_DMA_BASIC (2)
+#define MSDC_MODE_DMA_DESC (3)
+#define MSDC_MODE_DMA_ENHANCED (4)
+#define MSDC_MODE_MMC_STREAM (5)
+
+#define MSDC_BUS_1BITS (0)
+#define MSDC_BUS_4BITS (1)
+#define MSDC_BUS_8BITS (2)
+
+#define MSDC_BRUST_8B (3)
+#define MSDC_BRUST_16B (4)
+#define MSDC_BRUST_32B (5)
+#define MSDC_BRUST_64B (6)
+
+#define MSDC_PIN_PULL_NONE (0)
+#define MSDC_PIN_PULL_DOWN (1)
+#define MSDC_PIN_PULL_UP (2)
+#define MSDC_PIN_KEEP (3)
+
+#define MSDC_MAX_SCLK (48000000) /* +/- by chhung */
+#define MSDC_MIN_SCLK (260000)
+
+#define MSDC_AUTOCMD12 (0x0001)
+#define MSDC_AUTOCMD23 (0x0002)
+#define MSDC_AUTOCMD19 (0x0003)
+
+#define MSDC_EMMC_BOOTMODE0 (0) /* Pull low CMD mode */
+#define MSDC_EMMC_BOOTMODE1 (1) /* Reset CMD mode */
+
+enum {
+ RESP_NONE = 0,
+ RESP_R1,
+ RESP_R2,
+ RESP_R3,
+ RESP_R4,
+ RESP_R5,
+ RESP_R6,
+ RESP_R7,
+ RESP_R1B
+};
+
+/*--------------------------------------------------------------------------*/
+/* Register Offset */
+/*--------------------------------------------------------------------------*/
+#define OFFSET_MSDC_CFG (0x0)
+#define OFFSET_MSDC_IOCON (0x04)
+#define OFFSET_MSDC_PS (0x08)
+#define OFFSET_MSDC_INT (0x0c)
+#define OFFSET_MSDC_INTEN (0x10)
+#define OFFSET_MSDC_FIFOCS (0x14)
+#define OFFSET_MSDC_TXDATA (0x18)
+#define OFFSET_MSDC_RXDATA (0x1c)
+#define OFFSET_SDC_CFG (0x30)
+#define OFFSET_SDC_CMD (0x34)
+#define OFFSET_SDC_ARG (0x38)
+#define OFFSET_SDC_STS (0x3c)
+#define OFFSET_SDC_RESP0 (0x40)
+#define OFFSET_SDC_RESP1 (0x44)
+#define OFFSET_SDC_RESP2 (0x48)
+#define OFFSET_SDC_RESP3 (0x4c)
+#define OFFSET_SDC_BLK_NUM (0x50)
+#define OFFSET_SDC_CSTS (0x58)
+#define OFFSET_SDC_CSTS_EN (0x5c)
+#define OFFSET_SDC_DCRC_STS (0x60)
+#define OFFSET_EMMC_CFG0 (0x70)
+#define OFFSET_EMMC_CFG1 (0x74)
+#define OFFSET_EMMC_STS (0x78)
+#define OFFSET_EMMC_IOCON (0x7c)
+#define OFFSET_SDC_ACMD_RESP (0x80)
+#define OFFSET_SDC_ACMD19_TRG (0x84)
+#define OFFSET_SDC_ACMD19_STS (0x88)
+#define OFFSET_MSDC_DMA_SA (0x90)
+#define OFFSET_MSDC_DMA_CA (0x94)
+#define OFFSET_MSDC_DMA_CTRL (0x98)
+#define OFFSET_MSDC_DMA_CFG (0x9c)
+#define OFFSET_MSDC_DBG_SEL (0xa0)
+#define OFFSET_MSDC_DBG_OUT (0xa4)
+#define OFFSET_MSDC_PATCH_BIT (0xb0)
+#define OFFSET_MSDC_PATCH_BIT1 (0xb4)
+#define OFFSET_MSDC_PAD_CTL0 (0xe0)
+#define OFFSET_MSDC_PAD_CTL1 (0xe4)
+#define OFFSET_MSDC_PAD_CTL2 (0xe8)
+#define OFFSET_MSDC_PAD_TUNE (0xec)
+#define OFFSET_MSDC_DAT_RDDLY0 (0xf0)
+#define OFFSET_MSDC_DAT_RDDLY1 (0xf4)
+#define OFFSET_MSDC_HW_DBG (0xf8)
+#define OFFSET_MSDC_VERSION (0x100)
+#define OFFSET_MSDC_ECO_VER (0x104)
+
+/*--------------------------------------------------------------------------*/
+/* Register Address */
+/*--------------------------------------------------------------------------*/
+
+/* common register */
+#define MSDC_CFG REG_ADDR(MSDC_CFG)
+#define MSDC_IOCON REG_ADDR(MSDC_IOCON)
+#define MSDC_PS REG_ADDR(MSDC_PS)
+#define MSDC_INT REG_ADDR(MSDC_INT)
+#define MSDC_INTEN REG_ADDR(MSDC_INTEN)
+#define MSDC_FIFOCS REG_ADDR(MSDC_FIFOCS)
+#define MSDC_TXDATA REG_ADDR(MSDC_TXDATA)
+#define MSDC_RXDATA REG_ADDR(MSDC_RXDATA)
+#define MSDC_PATCH_BIT0 REG_ADDR(MSDC_PATCH_BIT)
+
+/* sdmmc register */
+#define SDC_CFG REG_ADDR(SDC_CFG)
+#define SDC_CMD REG_ADDR(SDC_CMD)
+#define SDC_ARG REG_ADDR(SDC_ARG)
+#define SDC_STS REG_ADDR(SDC_STS)
+#define SDC_RESP0 REG_ADDR(SDC_RESP0)
+#define SDC_RESP1 REG_ADDR(SDC_RESP1)
+#define SDC_RESP2 REG_ADDR(SDC_RESP2)
+#define SDC_RESP3 REG_ADDR(SDC_RESP3)
+#define SDC_BLK_NUM REG_ADDR(SDC_BLK_NUM)
+#define SDC_CSTS REG_ADDR(SDC_CSTS)
+#define SDC_CSTS_EN REG_ADDR(SDC_CSTS_EN)
+#define SDC_DCRC_STS REG_ADDR(SDC_DCRC_STS)
+
+/* emmc register*/
+#define EMMC_CFG0 REG_ADDR(EMMC_CFG0)
+#define EMMC_CFG1 REG_ADDR(EMMC_CFG1)
+#define EMMC_STS REG_ADDR(EMMC_STS)
+#define EMMC_IOCON REG_ADDR(EMMC_IOCON)
+
+/* auto command register */
+#define SDC_ACMD_RESP REG_ADDR(SDC_ACMD_RESP)
+#define SDC_ACMD19_TRG REG_ADDR(SDC_ACMD19_TRG)
+#define SDC_ACMD19_STS REG_ADDR(SDC_ACMD19_STS)
+
+/* dma register */
+#define MSDC_DMA_SA REG_ADDR(MSDC_DMA_SA)
+#define MSDC_DMA_CA REG_ADDR(MSDC_DMA_CA)
+#define MSDC_DMA_CTRL REG_ADDR(MSDC_DMA_CTRL)
+#define MSDC_DMA_CFG REG_ADDR(MSDC_DMA_CFG)
+
+/* pad ctrl register */
+#define MSDC_PAD_CTL0 REG_ADDR(MSDC_PAD_CTL0)
+#define MSDC_PAD_CTL1 REG_ADDR(MSDC_PAD_CTL1)
+#define MSDC_PAD_CTL2 REG_ADDR(MSDC_PAD_CTL2)
+
+/* data read delay */
+#define MSDC_DAT_RDDLY0 REG_ADDR(MSDC_DAT_RDDLY0)
+#define MSDC_DAT_RDDLY1 REG_ADDR(MSDC_DAT_RDDLY1)
+
+/* debug register */
+#define MSDC_DBG_SEL REG_ADDR(MSDC_DBG_SEL)
+#define MSDC_DBG_OUT REG_ADDR(MSDC_DBG_OUT)
+
+/* misc register */
+#define MSDC_PATCH_BIT REG_ADDR(MSDC_PATCH_BIT)
+#define MSDC_PATCH_BIT1 REG_ADDR(MSDC_PATCH_BIT1)
+#define MSDC_PAD_TUNE REG_ADDR(MSDC_PAD_TUNE)
+#define MSDC_HW_DBG REG_ADDR(MSDC_HW_DBG)
+#define MSDC_VERSION REG_ADDR(MSDC_VERSION)
+#define MSDC_ECO_VER REG_ADDR(MSDC_ECO_VER) /* ECO Version */
+
+/*--------------------------------------------------------------------------*/
+/* Register Mask */
+/*--------------------------------------------------------------------------*/
+
+/* MSDC_CFG mask */
+#define MSDC_CFG_MODE (0x1 << 0) /* RW */
+#define MSDC_CFG_CKPDN (0x1 << 1) /* RW */
+#define MSDC_CFG_RST (0x1 << 2) /* RW */
+#define MSDC_CFG_PIO (0x1 << 3) /* RW */
+#define MSDC_CFG_CKDRVEN (0x1 << 4) /* RW */
+#define MSDC_CFG_BV18SDT (0x1 << 5) /* RW */
+#define MSDC_CFG_BV18PSS (0x1 << 6) /* R */
+#define MSDC_CFG_CKSTB (0x1 << 7) /* R */
+#define MSDC_CFG_CKDIV (0xff << 8) /* RW */
+#define MSDC_CFG_CKMOD (0x3 << 16) /* RW */
+
+/* MSDC_IOCON mask */
+#define MSDC_IOCON_SDR104CKS (0x1 << 0) /* RW */
+#define MSDC_IOCON_RSPL (0x1 << 1) /* RW */
+#define MSDC_IOCON_DSPL (0x1 << 2) /* RW */
+#define MSDC_IOCON_DDLSEL (0x1 << 3) /* RW */
+#define MSDC_IOCON_DDR50CKD (0x1 << 4) /* RW */
+#define MSDC_IOCON_DSPLSEL (0x1 << 5) /* RW */
+#define MSDC_IOCON_D0SPL (0x1 << 16) /* RW */
+#define MSDC_IOCON_D1SPL (0x1 << 17) /* RW */
+#define MSDC_IOCON_D2SPL (0x1 << 18) /* RW */
+#define MSDC_IOCON_D3SPL (0x1 << 19) /* RW */
+#define MSDC_IOCON_D4SPL (0x1 << 20) /* RW */
+#define MSDC_IOCON_D5SPL (0x1 << 21) /* RW */
+#define MSDC_IOCON_D6SPL (0x1 << 22) /* RW */
+#define MSDC_IOCON_D7SPL (0x1 << 23) /* RW */
+#define MSDC_IOCON_RISCSZ (0x3 << 24) /* RW */
+
+/* MSDC_PS mask */
+#define MSDC_PS_CDEN (0x1 << 0) /* RW */
+#define MSDC_PS_CDSTS (0x1 << 1) /* R */
+#define MSDC_PS_CDDEBOUNCE (0xf << 12) /* RW */
+#define MSDC_PS_DAT (0xff << 16) /* R */
+#define MSDC_PS_CMD (0x1 << 24) /* R */
+#define MSDC_PS_WP (0x1UL<< 31) /* R */
+
+/* MSDC_INT mask */
+#define MSDC_INT_MMCIRQ (0x1 << 0) /* W1C */
+#define MSDC_INT_CDSC (0x1 << 1) /* W1C */
+#define MSDC_INT_ACMDRDY (0x1 << 3) /* W1C */
+#define MSDC_INT_ACMDTMO (0x1 << 4) /* W1C */
+#define MSDC_INT_ACMDCRCERR (0x1 << 5) /* W1C */
+#define MSDC_INT_DMAQ_EMPTY (0x1 << 6) /* W1C */
+#define MSDC_INT_SDIOIRQ (0x1 << 7) /* W1C */
+#define MSDC_INT_CMDRDY (0x1 << 8) /* W1C */
+#define MSDC_INT_CMDTMO (0x1 << 9) /* W1C */
+#define MSDC_INT_RSPCRCERR (0x1 << 10) /* W1C */
+#define MSDC_INT_CSTA (0x1 << 11) /* R */
+#define MSDC_INT_XFER_COMPL (0x1 << 12) /* W1C */
+#define MSDC_INT_DXFER_DONE (0x1 << 13) /* W1C */
+#define MSDC_INT_DATTMO (0x1 << 14) /* W1C */
+#define MSDC_INT_DATCRCERR (0x1 << 15) /* W1C */
+#define MSDC_INT_ACMD19_DONE (0x1 << 16) /* W1C */
+
+/* MSDC_INTEN mask */
+#define MSDC_INTEN_MMCIRQ (0x1 << 0) /* RW */
+#define MSDC_INTEN_CDSC (0x1 << 1) /* RW */
+#define MSDC_INTEN_ACMDRDY (0x1 << 3) /* RW */
+#define MSDC_INTEN_ACMDTMO (0x1 << 4) /* RW */
+#define MSDC_INTEN_ACMDCRCERR (0x1 << 5) /* RW */
+#define MSDC_INTEN_DMAQ_EMPTY (0x1 << 6) /* RW */
+#define MSDC_INTEN_SDIOIRQ (0x1 << 7) /* RW */
+#define MSDC_INTEN_CMDRDY (0x1 << 8) /* RW */
+#define MSDC_INTEN_CMDTMO (0x1 << 9) /* RW */
+#define MSDC_INTEN_RSPCRCERR (0x1 << 10) /* RW */
+#define MSDC_INTEN_CSTA (0x1 << 11) /* RW */
+#define MSDC_INTEN_XFER_COMPL (0x1 << 12) /* RW */
+#define MSDC_INTEN_DXFER_DONE (0x1 << 13) /* RW */
+#define MSDC_INTEN_DATTMO (0x1 << 14) /* RW */
+#define MSDC_INTEN_DATCRCERR (0x1 << 15) /* RW */
+#define MSDC_INTEN_ACMD19_DONE (0x1 << 16) /* RW */
+
+/* MSDC_FIFOCS mask */
+#define MSDC_FIFOCS_RXCNT (0xff << 0) /* R */
+#define MSDC_FIFOCS_TXCNT (0xff << 16) /* R */
+#define MSDC_FIFOCS_CLR (0x1UL<< 31) /* RW */
+
+/* SDC_CFG mask */
+#define SDC_CFG_SDIOINTWKUP (0x1 << 0) /* RW */
+#define SDC_CFG_INSWKUP (0x1 << 1) /* RW */
+#define SDC_CFG_BUSWIDTH (0x3 << 16) /* RW */
+#define SDC_CFG_SDIO (0x1 << 19) /* RW */
+#define SDC_CFG_SDIOIDE (0x1 << 20) /* RW */
+#define SDC_CFG_INTATGAP (0x1 << 21) /* RW */
+#define SDC_CFG_DTOC (0xffUL << 24) /* RW */
+
+/* SDC_CMD mask */
+#define SDC_CMD_OPC (0x3f << 0) /* RW */
+#define SDC_CMD_BRK (0x1 << 6) /* RW */
+#define SDC_CMD_RSPTYP (0x7 << 7) /* RW */
+#define SDC_CMD_DTYP (0x3 << 11) /* RW */
+#define SDC_CMD_DTYP (0x3 << 11) /* RW */
+#define SDC_CMD_RW (0x1 << 13) /* RW */
+#define SDC_CMD_STOP (0x1 << 14) /* RW */
+#define SDC_CMD_GOIRQ (0x1 << 15) /* RW */
+#define SDC_CMD_BLKLEN (0xfff<< 16) /* RW */
+#define SDC_CMD_AUTOCMD (0x3 << 28) /* RW */
+#define SDC_CMD_VOLSWTH (0x1 << 30) /* RW */
+
+/* SDC_STS mask */
+#define SDC_STS_SDCBUSY (0x1 << 0) /* RW */
+#define SDC_STS_CMDBUSY (0x1 << 1) /* RW */
+#define SDC_STS_SWR_COMPL (0x1 << 31) /* RW */
+
+/* SDC_DCRC_STS mask */
+#define SDC_DCRC_STS_NEG (0xf << 8) /* RO */
+#define SDC_DCRC_STS_POS (0xff << 0) /* RO */
+
+/* EMMC_CFG0 mask */
+#define EMMC_CFG0_BOOTSTART (0x1 << 0) /* W */
+#define EMMC_CFG0_BOOTSTOP (0x1 << 1) /* W */
+#define EMMC_CFG0_BOOTMODE (0x1 << 2) /* RW */
+#define EMMC_CFG0_BOOTACKDIS (0x1 << 3) /* RW */
+#define EMMC_CFG0_BOOTWDLY (0x7 << 12) /* RW */
+#define EMMC_CFG0_BOOTSUPP (0x1 << 15) /* RW */
+
+/* EMMC_CFG1 mask */
+#define EMMC_CFG1_BOOTDATTMC (0xfffff << 0) /* RW */
+#define EMMC_CFG1_BOOTACKTMC (0xfffUL << 20) /* RW */
+
+/* EMMC_STS mask */
+#define EMMC_STS_BOOTCRCERR (0x1 << 0) /* W1C */
+#define EMMC_STS_BOOTACKERR (0x1 << 1) /* W1C */
+#define EMMC_STS_BOOTDATTMO (0x1 << 2) /* W1C */
+#define EMMC_STS_BOOTACKTMO (0x1 << 3) /* W1C */
+#define EMMC_STS_BOOTUPSTATE (0x1 << 4) /* R */
+#define EMMC_STS_BOOTACKRCV (0x1 << 5) /* W1C */
+#define EMMC_STS_BOOTDATRCV (0x1 << 6) /* R */
+
+/* EMMC_IOCON mask */
+#define EMMC_IOCON_BOOTRST (0x1 << 0) /* RW */
+
+/* SDC_ACMD19_TRG mask */
+#define SDC_ACMD19_TRG_TUNESEL (0xf << 0) /* RW */
+
+/* MSDC_DMA_CTRL mask */
+#define MSDC_DMA_CTRL_START (0x1 << 0) /* W */
+#define MSDC_DMA_CTRL_STOP (0x1 << 1) /* W */
+#define MSDC_DMA_CTRL_RESUME (0x1 << 2) /* W */
+#define MSDC_DMA_CTRL_MODE (0x1 << 8) /* RW */
+#define MSDC_DMA_CTRL_LASTBUF (0x1 << 10) /* RW */
+#define MSDC_DMA_CTRL_BRUSTSZ (0x7 << 12) /* RW */
+#define MSDC_DMA_CTRL_XFERSZ (0xffffUL << 16)/* RW */
+
+/* MSDC_DMA_CFG mask */
+#define MSDC_DMA_CFG_STS (0x1 << 0) /* R */
+#define MSDC_DMA_CFG_DECSEN (0x1 << 1) /* RW */
+#define MSDC_DMA_CFG_BDCSERR (0x1 << 4) /* R */
+#define MSDC_DMA_CFG_GPDCSERR (0x1 << 5) /* R */
+
+/* MSDC_PATCH_BIT mask */
+#define MSDC_PATCH_BIT_WFLSMODE (0x1 << 0) /* RW */
+#define MSDC_PATCH_BIT_ODDSUPP (0x1 << 1) /* RW */
+#define MSDC_PATCH_BIT_CKGEN_CK (0x1 << 6) /* E2: Fixed to 1 */
+#define MSDC_PATCH_BIT_IODSSEL (0x1 << 16) /* RW */
+#define MSDC_PATCH_BIT_IOINTSEL (0x1 << 17) /* RW */
+#define MSDC_PATCH_BIT_BUSYDLY (0xf << 18) /* RW */
+#define MSDC_PATCH_BIT_WDOD (0xf << 22) /* RW */
+#define MSDC_PATCH_BIT_IDRTSEL (0x1 << 26) /* RW */
+#define MSDC_PATCH_BIT_CMDFSEL (0x1 << 27) /* RW */
+#define MSDC_PATCH_BIT_INTDLSEL (0x1 << 28) /* RW */
+#define MSDC_PATCH_BIT_SPCPUSH (0x1 << 29) /* RW */
+#define MSDC_PATCH_BIT_DECRCTMO (0x1 << 30) /* RW */
+
+/* MSDC_PATCH_BIT1 mask */
+#define MSDC_PATCH_BIT1_WRDAT_CRCS (0x7 << 3)
+#define MSDC_PATCH_BIT1_CMD_RSP (0x7 << 0)
+
+/* MSDC_PAD_CTL0 mask */
+#define MSDC_PAD_CTL0_CLKDRVN (0x7 << 0) /* RW */
+#define MSDC_PAD_CTL0_CLKDRVP (0x7 << 4) /* RW */
+#define MSDC_PAD_CTL0_CLKSR (0x1 << 8) /* RW */
+#define MSDC_PAD_CTL0_CLKPD (0x1 << 16) /* RW */
+#define MSDC_PAD_CTL0_CLKPU (0x1 << 17) /* RW */
+#define MSDC_PAD_CTL0_CLKSMT (0x1 << 18) /* RW */
+#define MSDC_PAD_CTL0_CLKIES (0x1 << 19) /* RW */
+#define MSDC_PAD_CTL0_CLKTDSEL (0xf << 20) /* RW */
+#define MSDC_PAD_CTL0_CLKRDSEL (0xffUL<< 24) /* RW */
+
+/* MSDC_PAD_CTL1 mask */
+#define MSDC_PAD_CTL1_CMDDRVN (0x7 << 0) /* RW */
+#define MSDC_PAD_CTL1_CMDDRVP (0x7 << 4) /* RW */
+#define MSDC_PAD_CTL1_CMDSR (0x1 << 8) /* RW */
+#define MSDC_PAD_CTL1_CMDPD (0x1 << 16) /* RW */
+#define MSDC_PAD_CTL1_CMDPU (0x1 << 17) /* RW */
+#define MSDC_PAD_CTL1_CMDSMT (0x1 << 18) /* RW */
+#define MSDC_PAD_CTL1_CMDIES (0x1 << 19) /* RW */
+#define MSDC_PAD_CTL1_CMDTDSEL (0xf << 20) /* RW */
+#define MSDC_PAD_CTL1_CMDRDSEL (0xffUL<< 24) /* RW */
+
+/* MSDC_PAD_CTL2 mask */
+#define MSDC_PAD_CTL2_DATDRVN (0x7 << 0) /* RW */
+#define MSDC_PAD_CTL2_DATDRVP (0x7 << 4) /* RW */
+#define MSDC_PAD_CTL2_DATSR (0x1 << 8) /* RW */
+#define MSDC_PAD_CTL2_DATPD (0x1 << 16) /* RW */
+#define MSDC_PAD_CTL2_DATPU (0x1 << 17) /* RW */
+#define MSDC_PAD_CTL2_DATIES (0x1 << 19) /* RW */
+#define MSDC_PAD_CTL2_DATSMT (0x1 << 18) /* RW */
+#define MSDC_PAD_CTL2_DATTDSEL (0xf << 20) /* RW */
+#define MSDC_PAD_CTL2_DATRDSEL (0xffUL<< 24) /* RW */
+
+/* MSDC_PAD_TUNE mask */
+#define MSDC_PAD_TUNE_DATWRDLY (0x1F << 0) /* RW */
+#define MSDC_PAD_TUNE_DATRRDLY (0x1F << 8) /* RW */
+#define MSDC_PAD_TUNE_CMDRDLY (0x1F << 16) /* RW */
+#define MSDC_PAD_TUNE_CMDRRDLY (0x1FUL << 22) /* RW */
+#define MSDC_PAD_TUNE_CLKTXDLY (0x1FUL << 27) /* RW */
+
+/* MSDC_DAT_RDDLY0/1 mask */
+#define MSDC_DAT_RDDLY0_D0 (0x1F << 0) /* RW */
+#define MSDC_DAT_RDDLY0_D1 (0x1F << 8) /* RW */
+#define MSDC_DAT_RDDLY0_D2 (0x1F << 16) /* RW */
+#define MSDC_DAT_RDDLY0_D3 (0x1F << 24) /* RW */
+
+#define MSDC_DAT_RDDLY1_D4 (0x1F << 0) /* RW */
+#define MSDC_DAT_RDDLY1_D5 (0x1F << 8) /* RW */
+#define MSDC_DAT_RDDLY1_D6 (0x1F << 16) /* RW */
+#define MSDC_DAT_RDDLY1_D7 (0x1F << 24) /* RW */
+
+#define MSDC_CKGEN_MSDC_DLY_SEL (0x1F<<10)
+#define MSDC_INT_DAT_LATCH_CK_SEL (0x7<<7)
+#define MSDC_CKGEN_MSDC_CK_SEL (0x1<<6)
+#define CARD_READY_FOR_DATA (1<<8)
+#define CARD_CURRENT_STATE(x) ((x&0x00001E00)>>9)
+
+/*--------------------------------------------------------------------------*/
+/* Descriptor Structure */
+/*--------------------------------------------------------------------------*/
+typedef struct {
+ u32 hwo:1; /* could be changed by hw */
+ u32 bdp:1;
+ u32 rsv0:6;
+ u32 chksum:8;
+ u32 intr:1;
+ u32 rsv1:15;
+ void *next;
+ void *ptr;
+ u32 buflen:16;
+ u32 extlen:8;
+ u32 rsv2:8;
+ u32 arg;
+ u32 blknum;
+ u32 cmd;
+} gpd_t;
+
+typedef struct {
+ u32 eol:1;
+ u32 rsv0:7;
+ u32 chksum:8;
+ u32 rsv1:1;
+ u32 blkpad:1;
+ u32 dwpad:1;
+ u32 rsv2:13;
+ void *next;
+ void *ptr;
+ u32 buflen:16;
+ u32 rsv3:16;
+} bd_t;
+
+/*--------------------------------------------------------------------------*/
+/* Register Debugging Structure */
+/*--------------------------------------------------------------------------*/
+
+typedef struct {
+ u32 msdc:1;
+ u32 ckpwn:1;
+ u32 rst:1;
+ u32 pio:1;
+ u32 ckdrven:1;
+ u32 start18v:1;
+ u32 pass18v:1;
+ u32 ckstb:1;
+ u32 ckdiv:8;
+ u32 ckmod:2;
+ u32 pad:14;
+} msdc_cfg_reg;
+typedef struct {
+ u32 sdr104cksel:1;
+ u32 rsmpl:1;
+ u32 dsmpl:1;
+ u32 ddlysel:1;
+ u32 ddr50ckd:1;
+ u32 dsplsel:1;
+ u32 pad1:10;
+ u32 d0spl:1;
+ u32 d1spl:1;
+ u32 d2spl:1;
+ u32 d3spl:1;
+ u32 d4spl:1;
+ u32 d5spl:1;
+ u32 d6spl:1;
+ u32 d7spl:1;
+ u32 riscsz:1;
+ u32 pad2:7;
+} msdc_iocon_reg;
+typedef struct {
+ u32 cden:1;
+ u32 cdsts:1;
+ u32 pad1:10;
+ u32 cddebounce:4;
+ u32 dat:8;
+ u32 cmd:1;
+ u32 pad2:6;
+ u32 wp:1;
+} msdc_ps_reg;
+typedef struct {
+ u32 mmcirq:1;
+ u32 cdsc:1;
+ u32 pad1:1;
+ u32 atocmdrdy:1;
+ u32 atocmdtmo:1;
+ u32 atocmdcrc:1;
+ u32 dmaqempty:1;
+ u32 sdioirq:1;
+ u32 cmdrdy:1;
+ u32 cmdtmo:1;
+ u32 rspcrc:1;
+ u32 csta:1;
+ u32 xfercomp:1;
+ u32 dxferdone:1;
+ u32 dattmo:1;
+ u32 datcrc:1;
+ u32 atocmd19done:1;
+ u32 pad2:15;
+} msdc_int_reg;
+typedef struct {
+ u32 mmcirq:1;
+ u32 cdsc:1;
+ u32 pad1:1;
+ u32 atocmdrdy:1;
+ u32 atocmdtmo:1;
+ u32 atocmdcrc:1;
+ u32 dmaqempty:1;
+ u32 sdioirq:1;
+ u32 cmdrdy:1;
+ u32 cmdtmo:1;
+ u32 rspcrc:1;
+ u32 csta:1;
+ u32 xfercomp:1;
+ u32 dxferdone:1;
+ u32 dattmo:1;
+ u32 datcrc:1;
+ u32 atocmd19done:1;
+ u32 pad2:15;
+} msdc_inten_reg;
+typedef struct {
+ u32 rxcnt:8;
+ u32 pad1:8;
+ u32 txcnt:8;
+ u32 pad2:7;
+ u32 clr:1;
+} msdc_fifocs_reg;
+typedef struct {
+ u32 val;
+} msdc_txdat_reg;
+typedef struct {
+ u32 val;
+} msdc_rxdat_reg;
+typedef struct {
+ u32 sdiowkup:1;
+ u32 inswkup:1;
+ u32 pad1:14;
+ u32 buswidth:2;
+ u32 pad2:1;
+ u32 sdio:1;
+ u32 sdioide:1;
+ u32 intblkgap:1;
+ u32 pad4:2;
+ u32 dtoc:8;
+} sdc_cfg_reg;
+typedef struct {
+ u32 cmd:6;
+ u32 brk:1;
+ u32 rsptyp:3;
+ u32 pad1:1;
+ u32 dtype:2;
+ u32 rw:1;
+ u32 stop:1;
+ u32 goirq:1;
+ u32 blklen:12;
+ u32 atocmd:2;
+ u32 volswth:1;
+ u32 pad2:1;
+} sdc_cmd_reg;
+typedef struct {
+ u32 arg;
+} sdc_arg_reg;
+typedef struct {
+ u32 sdcbusy:1;
+ u32 cmdbusy:1;
+ u32 pad:29;
+ u32 swrcmpl:1;
+} sdc_sts_reg;
+typedef struct {
+ u32 val;
+} sdc_resp0_reg;
+typedef struct {
+ u32 val;
+} sdc_resp1_reg;
+typedef struct {
+ u32 val;
+} sdc_resp2_reg;
+typedef struct {
+ u32 val;
+} sdc_resp3_reg;
+typedef struct {
+ u32 num;
+} sdc_blknum_reg;
+typedef struct {
+ u32 sts;
+} sdc_csts_reg;
+typedef struct {
+ u32 sts;
+} sdc_cstsen_reg;
+typedef struct {
+ u32 datcrcsts:8;
+ u32 ddrcrcsts:4;
+ u32 pad:20;
+} sdc_datcrcsts_reg;
+typedef struct {
+ u32 bootstart:1;
+ u32 bootstop:1;
+ u32 bootmode:1;
+ u32 pad1:9;
+ u32 bootwaidly:3;
+ u32 bootsupp:1;
+ u32 pad2:16;
+} emmc_cfg0_reg;
+typedef struct {
+ u32 bootcrctmc:16;
+ u32 pad:4;
+ u32 bootacktmc:12;
+} emmc_cfg1_reg;
+typedef struct {
+ u32 bootcrcerr:1;
+ u32 bootackerr:1;
+ u32 bootdattmo:1;
+ u32 bootacktmo:1;
+ u32 bootupstate:1;
+ u32 bootackrcv:1;
+ u32 bootdatrcv:1;
+ u32 pad:25;
+} emmc_sts_reg;
+typedef struct {
+ u32 bootrst:1;
+ u32 pad:31;
+} emmc_iocon_reg;
+typedef struct {
+ u32 val;
+} msdc_acmd_resp_reg;
+typedef struct {
+ u32 tunesel:4;
+ u32 pad:28;
+} msdc_acmd19_trg_reg;
+typedef struct {
+ u32 val;
+} msdc_acmd19_sts_reg;
+typedef struct {
+ u32 addr;
+} msdc_dma_sa_reg;
+typedef struct {
+ u32 addr;
+} msdc_dma_ca_reg;
+typedef struct {
+ u32 start:1;
+ u32 stop:1;
+ u32 resume:1;
+ u32 pad1:5;
+ u32 mode:1;
+ u32 pad2:1;
+ u32 lastbuf:1;
+ u32 pad3:1;
+ u32 brustsz:3;
+ u32 pad4:1;
+ u32 xfersz:16;
+} msdc_dma_ctrl_reg;
+typedef struct {
+ u32 status:1;
+ u32 decsen:1;
+ u32 pad1:2;
+ u32 bdcsen:1;
+ u32 gpdcsen:1;
+ u32 pad2:26;
+} msdc_dma_cfg_reg;
+typedef struct {
+ u32 sel:16;
+ u32 pad2:16;
+} msdc_dbg_sel_reg;
+typedef struct {
+ u32 val;
+} msdc_dbg_out_reg;
+typedef struct {
+ u32 clkdrvn:3;
+ u32 rsv0:1;
+ u32 clkdrvp:3;
+ u32 rsv1:1;
+ u32 clksr:1;
+ u32 rsv2:7;
+ u32 clkpd:1;
+ u32 clkpu:1;
+ u32 clksmt:1;
+ u32 clkies:1;
+ u32 clktdsel:4;
+ u32 clkrdsel:8;
+} msdc_pad_ctl0_reg;
+typedef struct {
+ u32 cmddrvn:3;
+ u32 rsv0:1;
+ u32 cmddrvp:3;
+ u32 rsv1:1;
+ u32 cmdsr:1;
+ u32 rsv2:7;
+ u32 cmdpd:1;
+ u32 cmdpu:1;
+ u32 cmdsmt:1;
+ u32 cmdies:1;
+ u32 cmdtdsel:4;
+ u32 cmdrdsel:8;
+} msdc_pad_ctl1_reg;
+typedef struct {
+ u32 datdrvn:3;
+ u32 rsv0:1;
+ u32 datdrvp:3;
+ u32 rsv1:1;
+ u32 datsr:1;
+ u32 rsv2:7;
+ u32 datpd:1;
+ u32 datpu:1;
+ u32 datsmt:1;
+ u32 daties:1;
+ u32 dattdsel:4;
+ u32 datrdsel:8;
+} msdc_pad_ctl2_reg;
+typedef struct {
+ u32 wrrxdly:3;
+ u32 pad1:5;
+ u32 rdrxdly:8;
+ u32 pad2:16;
+} msdc_pad_tune_reg;
+typedef struct {
+ u32 dat0:5;
+ u32 rsv0:3;
+ u32 dat1:5;
+ u32 rsv1:3;
+ u32 dat2:5;
+ u32 rsv2:3;
+ u32 dat3:5;
+ u32 rsv3:3;
+} msdc_dat_rddly0;
+typedef struct {
+ u32 dat4:5;
+ u32 rsv4:3;
+ u32 dat5:5;
+ u32 rsv5:3;
+ u32 dat6:5;
+ u32 rsv6:3;
+ u32 dat7:5;
+ u32 rsv7:3;
+} msdc_dat_rddly1;
+typedef struct {
+ u32 dbg0sel:8;
+ u32 dbg1sel:6;
+ u32 pad1:2;
+ u32 dbg2sel:6;
+ u32 pad2:2;
+ u32 dbg3sel:6;
+ u32 pad3:2;
+} msdc_hw_dbg_reg;
+typedef struct {
+ u32 val;
+} msdc_version_reg;
+typedef struct {
+ u32 val;
+} msdc_eco_ver_reg;
+
+struct msdc_regs {
+ msdc_cfg_reg msdc_cfg; /* base+0x00h */
+ msdc_iocon_reg msdc_iocon; /* base+0x04h */
+ msdc_ps_reg msdc_ps; /* base+0x08h */
+ msdc_int_reg msdc_int; /* base+0x0ch */
+ msdc_inten_reg msdc_inten; /* base+0x10h */
+ msdc_fifocs_reg msdc_fifocs; /* base+0x14h */
+ msdc_txdat_reg msdc_txdat; /* base+0x18h */
+ msdc_rxdat_reg msdc_rxdat; /* base+0x1ch */
+ u32 rsv1[4];
+ sdc_cfg_reg sdc_cfg; /* base+0x30h */
+ sdc_cmd_reg sdc_cmd; /* base+0x34h */
+ sdc_arg_reg sdc_arg; /* base+0x38h */
+ sdc_sts_reg sdc_sts; /* base+0x3ch */
+ sdc_resp0_reg sdc_resp0; /* base+0x40h */
+ sdc_resp1_reg sdc_resp1; /* base+0x44h */
+ sdc_resp2_reg sdc_resp2; /* base+0x48h */
+ sdc_resp3_reg sdc_resp3; /* base+0x4ch */
+ sdc_blknum_reg sdc_blknum; /* base+0x50h */
+ u32 rsv2[1];
+ sdc_csts_reg sdc_csts; /* base+0x58h */
+ sdc_cstsen_reg sdc_cstsen; /* base+0x5ch */
+ sdc_datcrcsts_reg sdc_dcrcsta; /* base+0x60h */
+ u32 rsv3[3];
+ emmc_cfg0_reg emmc_cfg0; /* base+0x70h */
+ emmc_cfg1_reg emmc_cfg1; /* base+0x74h */
+ emmc_sts_reg emmc_sts; /* base+0x78h */
+ emmc_iocon_reg emmc_iocon; /* base+0x7ch */
+ msdc_acmd_resp_reg acmd_resp; /* base+0x80h */
+ msdc_acmd19_trg_reg acmd19_trg; /* base+0x84h */
+ msdc_acmd19_sts_reg acmd19_sts; /* base+0x88h */
+ u32 rsv4[1];
+ msdc_dma_sa_reg dma_sa; /* base+0x90h */
+ msdc_dma_ca_reg dma_ca; /* base+0x94h */
+ msdc_dma_ctrl_reg dma_ctrl; /* base+0x98h */
+ msdc_dma_cfg_reg dma_cfg; /* base+0x9ch */
+ msdc_dbg_sel_reg dbg_sel; /* base+0xa0h */
+ msdc_dbg_out_reg dbg_out; /* base+0xa4h */
+ u32 rsv5[2];
+ u32 patch0; /* base+0xb0h */
+ u32 patch1; /* base+0xb4h */
+ u32 rsv6[10];
+ msdc_pad_ctl0_reg pad_ctl0; /* base+0xe0h */
+ msdc_pad_ctl1_reg pad_ctl1; /* base+0xe4h */
+ msdc_pad_ctl2_reg pad_ctl2; /* base+0xe8h */
+ msdc_pad_tune_reg pad_tune; /* base+0xech */
+ msdc_dat_rddly0 dat_rddly0; /* base+0xf0h */
+ msdc_dat_rddly1 dat_rddly1; /* base+0xf4h */
+ msdc_hw_dbg_reg hw_dbg; /* base+0xf8h */
+ u32 rsv7[1];
+ msdc_version_reg version; /* base+0x100h */
+ msdc_eco_ver_reg eco_ver; /* base+0x104h */
+};
+
+struct scatterlist_ex {
+ u32 cmd;
+ u32 arg;
+ u32 sglen;
+ struct scatterlist *sg;
+};
+
+#define DMA_FLAG_NONE (0x00000000)
+#define DMA_FLAG_EN_CHKSUM (0x00000001)
+#define DMA_FLAG_PAD_BLOCK (0x00000002)
+#define DMA_FLAG_PAD_DWORD (0x00000004)
+
+struct msdc_dma {
+ u32 flags; /* flags */
+ u32 xfersz; /* xfer size in bytes */
+ u32 sglen; /* size of scatter list */
+ u32 blklen; /* block size */
+ struct scatterlist *sg; /* I/O scatter list */
+ struct scatterlist_ex *esg; /* extended I/O scatter list */
+ u8 mode; /* dma mode */
+ u8 burstsz; /* burst size */
+ u8 intr; /* dma done interrupt */
+ u8 padding; /* padding */
+ u32 cmd; /* enhanced mode command */
+ u32 arg; /* enhanced mode arg */
+ u32 rsp; /* enhanced mode command response */
+ u32 autorsp; /* auto command response */
+
+ gpd_t *gpd; /* pointer to gpd array */
+ bd_t *bd; /* pointer to bd array */
+ dma_addr_t gpd_addr; /* the physical address of gpd array */
+ dma_addr_t bd_addr; /* the physical address of bd array */
+ u32 used_gpd; /* the number of used gpd elements */
+ u32 used_bd; /* the number of used bd elements */
+};
+
+struct msdc_host
+{
+ struct msdc_hw *hw;
+
+ struct mmc_host *mmc; /* mmc structure */
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ struct mmc_request *mrq;
+ int cmd_rsp;
+ int cmd_rsp_done;
+ int cmd_r1b_done;
+
+ int error;
+ spinlock_t lock; /* mutex */
+ struct semaphore sem;
+
+ u32 blksz; /* host block size */
+ u32 base; /* host base address */
+ int id; /* host id */
+ int pwr_ref; /* core power reference count */
+
+ u32 xfer_size; /* total transferred size */
+
+ struct msdc_dma dma; /* dma channel */
+ u32 dma_addr; /* dma transfer address */
+ u32 dma_left_size; /* dma transfer left size */
+ u32 dma_xfer_size; /* dma transfer size in bytes */
+ int dma_xfer; /* dma transfer mode */
+
+ u32 timeout_ns; /* data timeout ns */
+ u32 timeout_clks; /* data timeout clks */
+
+ atomic_t abort; /* abort transfer */
+
+ int irq; /* host interrupt */
+
+ struct tasklet_struct card_tasklet;
+#if 0
+ struct work_struct card_workqueue;
+#else
+ struct delayed_work card_delaywork;
+#endif
+
+ struct completion cmd_done;
+ struct completion xfer_done;
+ struct pm_message pm_state;
+
+ u32 mclk; /* mmc subsystem clock */
+ u32 hclk; /* host clock speed */
+ u32 sclk; /* SD/MS clock speed */
+ u8 core_clkon; /* Host core clock on ? */
+ u8 card_clkon; /* Card clock on ? */
+ u8 core_power; /* core power */
+ u8 power_mode; /* host power mode */
+ u8 card_inserted; /* card inserted ? */
+ u8 suspend; /* host suspended ? */
+ u8 reserved;
+ u8 app_cmd; /* for app command */
+ u32 app_cmd_arg;
+ u64 starttime;
+};
+
+static inline unsigned int uffs(unsigned int x)
+{
+ unsigned int r = 1;
+
+ if (!x)
+ return 0;
+ if (!(x & 0xffff)) {
+ x >>= 16;
+ r += 16;
+ }
+ if (!(x & 0xff)) {
+ x >>= 8;
+ r += 8;
+ }
+ if (!(x & 0xf)) {
+ x >>= 4;
+ r += 4;
+ }
+ if (!(x & 3)) {
+ x >>= 2;
+ r += 2;
+ }
+ if (!(x & 1)) {
+ x >>= 1;
+ r += 1;
+ }
+ return r;
+}
+#define sdr_read8(reg) __raw_readb(reg)
+#define sdr_read16(reg) __raw_readw(reg)
+#define sdr_read32(reg) __raw_readl(reg)
+#define sdr_write8(reg,val) __raw_writeb(val,reg)
+#define sdr_write16(reg,val) __raw_writew(val,reg)
+#define sdr_write32(reg,val) __raw_writel(val,reg)
+
+#define sdr_set_bits(reg,bs) ((*(volatile u32*)(reg)) |= (u32)(bs))
+#define sdr_clr_bits(reg,bs) ((*(volatile u32*)(reg)) &= ~((u32)(bs)))
+
+#define sdr_set_field(reg,field,val) \
+ do { \
+ volatile unsigned int tv = sdr_read32(reg); \
+ tv &= ~(field); \
+ tv |= ((val) << (uffs((unsigned int)field) - 1)); \
+ sdr_write32(reg,tv); \
+ } while(0)
+#define sdr_get_field(reg,field,val) \
+ do { \
+ volatile unsigned int tv = sdr_read32(reg); \
+ val = ((tv & (field)) >> (uffs((unsigned int)field) - 1)); \
+ } while(0)
+
+#endif
+
diff --git a/drivers/staging/mt7621-mmc/sd.c b/drivers/staging/mt7621-mmc/sd.c
new file mode 100644
index 000000000000..a1d0173eba56
--- /dev/null
+++ b/drivers/staging/mt7621-mmc/sd.c
@@ -0,0 +1,3074 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/core.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/sdio.h>
+#include <linux/dma-mapping.h>
+
+/* +++ by chhung */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/pm.h>
+#include <linux/of.h>
+
+#define MSDC_SMPL_FALLING (1)
+#define MSDC_CD_PIN_EN (1 << 0) /* card detection pin is wired */
+#define MSDC_WP_PIN_EN (1 << 1) /* write protection pin is wired */
+#define MSDC_REMOVABLE (1 << 5) /* removable slot */
+#define MSDC_SYS_SUSPEND (1 << 6) /* suspended by system */
+#define MSDC_HIGHSPEED (1 << 7)
+
+//#define IRQ_SDC 14 //MT7620 /*FIXME*/
+#ifdef CONFIG_SOC_MT7621
+#define RALINK_SYSCTL_BASE 0xbe000000
+#define RALINK_MSDC_BASE 0xbe130000
+#else
+#define RALINK_SYSCTL_BASE 0xb0000000
+#define RALINK_MSDC_BASE 0xb0130000
+#endif
+#define IRQ_SDC 22 /*FIXME*/
+
+#include <asm/dma.h>
+/* end of +++ */
+
+
+#include <asm/mach-ralink/ralink_regs.h>
+
+#if 0 /* --- by chhung */
+#include <mach/board.h>
+#include <mach/mt6575_devs.h>
+#include <mach/mt6575_typedefs.h>
+#include <mach/mt6575_clock_manager.h>
+#include <mach/mt6575_pm_ldo.h>
+//#include <mach/mt6575_pll.h>
+//#include <mach/mt6575_gpio.h>
+//#include <mach/mt6575_gpt_sw.h>
+#include <asm/tcm.h>
+// #include <mach/mt6575_gpt.h>
+#endif /* end of --- */
+
+#include "mt6575_sd.h"
+#include "dbg.h"
+
+/* +++ by chhung */
+#include "board.h"
+/* end of +++ */
+
+#if 0 /* --- by chhung */
+#define isb() __asm__ __volatile__ ("" : : : "memory")
+#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
+ : : "r" (0) : "memory")
+#define dmb() __asm__ __volatile__ ("" : : : "memory")
+#endif /* end of --- */
+
+#define DRV_NAME "mtk-sd"
+
+#define HOST_MAX_NUM (1) /* +/- by chhung */
+
+#if defined (CONFIG_SOC_MT7620)
+#define HOST_MAX_MCLK (48000000) /* +/- by chhung */
+#elif defined (CONFIG_SOC_MT7621)
+#define HOST_MAX_MCLK (50000000) /* +/- by chhung */
+#endif
+#define HOST_MIN_MCLK (260000)
+
+#define HOST_MAX_BLKSZ (2048)
+
+#define MSDC_OCR_AVAIL (MMC_VDD_28_29 | MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33)
+
+#define GPIO_PULL_DOWN (0)
+#define GPIO_PULL_UP (1)
+
+#if 0 /* --- by chhung */
+#define MSDC_CLKSRC_REG (0xf100000C)
+#define PDN_REG (0xF1000010)
+#endif /* end of --- */
+
+#define DEFAULT_DEBOUNCE (8) /* 8 cycles */
+#define DEFAULT_DTOC (40) /* data timeout counter. 65536x40 sclk. */
+
+#define CMD_TIMEOUT (HZ/10) /* 100ms */
+#define DAT_TIMEOUT (HZ/2 * 5) /* 500ms x5 */
+
+#define MAX_DMA_CNT (64 * 1024 - 512) /* a single transaction for WIFI may be 50K*/
+
+#define MAX_GPD_NUM (1 + 1) /* one null gpd */
+#define MAX_BD_NUM (1024)
+#define MAX_BD_PER_GPD (MAX_BD_NUM)
+
+#define MAX_HW_SGMTS (MAX_BD_NUM)
+#define MAX_PHY_SGMTS (MAX_BD_NUM)
+#define MAX_SGMT_SZ (MAX_DMA_CNT)
+#define MAX_REQ_SZ (MAX_SGMT_SZ * 8)
+
+#ifdef MT6575_SD_DEBUG
+static struct msdc_regs *msdc_reg[HOST_MAX_NUM];
+#endif
+
+static int mtk_sw_poll;
+
+static int cd_active_low = 1;
+
+//=================================
+#define PERI_MSDC0_PDN (15)
+//#define PERI_MSDC1_PDN (16)
+//#define PERI_MSDC2_PDN (17)
+//#define PERI_MSDC3_PDN (18)
+
+struct msdc_host *msdc_6575_host[] = {NULL,NULL,NULL,NULL};
+#if 0 /* --- by chhung */
+/* gate means clock power down */
+static int g_clk_gate = 0;
+#define msdc_gate_clock(id) \
+ do { \
+ g_clk_gate &= ~(1 << ((id) + PERI_MSDC0_PDN)); \
+ } while(0)
+/* not like power down register. 1 means clock on. */
+#define msdc_ungate_clock(id) \
+ do { \
+ g_clk_gate |= 1 << ((id) + PERI_MSDC0_PDN); \
+ } while(0)
+
+// do we need sync object or not
+void msdc_clk_status(int * status)
+{
+ *status = g_clk_gate;
+}
+#endif /* end of --- */
+
+/* +++ by chhung */
+struct msdc_hw msdc0_hw = {
+ .clk_src = 0,
+ .cmd_edge = MSDC_SMPL_FALLING,
+ .data_edge = MSDC_SMPL_FALLING,
+ .clk_drv = 4,
+ .cmd_drv = 4,
+ .dat_drv = 4,
+ .data_pins = 4,
+ .data_offset = 0,
+ .flags = MSDC_SYS_SUSPEND | MSDC_CD_PIN_EN | MSDC_REMOVABLE | MSDC_HIGHSPEED,
+// .flags = MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE,
+};
+
+static struct resource mtk_sd_resources[] = {
+ [0] = {
+ .start = RALINK_MSDC_BASE,
+ .end = RALINK_MSDC_BASE+0x3fff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_SDC, /*FIXME*/
+ .end = IRQ_SDC, /*FIXME*/
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device mtk_sd_device = {
+ .name = "mtk-sd",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(mtk_sd_resources),
+ .resource = mtk_sd_resources,
+};
+/* end of +++ */
+
+static int msdc_rsp[] = {
+ 0, /* RESP_NONE */
+ 1, /* RESP_R1 */
+ 2, /* RESP_R2 */
+ 3, /* RESP_R3 */
+ 4, /* RESP_R4 */
+ 1, /* RESP_R5 */
+ 1, /* RESP_R6 */
+ 1, /* RESP_R7 */
+ 7, /* RESP_R1b */
+};
+
+/* For Inhanced DMA */
+#define msdc_init_gpd_ex(gpd,extlen,cmd,arg,blknum) \
+ do { \
+ ((gpd_t*)gpd)->extlen = extlen; \
+ ((gpd_t*)gpd)->cmd = cmd; \
+ ((gpd_t*)gpd)->arg = arg; \
+ ((gpd_t*)gpd)->blknum = blknum; \
+ }while(0)
+
+#define msdc_init_bd(bd, blkpad, dwpad, dptr, dlen) \
+ do { \
+ BUG_ON(dlen > 0xFFFFUL); \
+ ((bd_t*)bd)->blkpad = blkpad; \
+ ((bd_t*)bd)->dwpad = dwpad; \
+ ((bd_t*)bd)->ptr = (void*)dptr; \
+ ((bd_t*)bd)->buflen = dlen; \
+ }while(0)
+
+#define msdc_txfifocnt() ((sdr_read32(MSDC_FIFOCS) & MSDC_FIFOCS_TXCNT) >> 16)
+#define msdc_rxfifocnt() ((sdr_read32(MSDC_FIFOCS) & MSDC_FIFOCS_RXCNT) >> 0)
+#define msdc_fifo_write32(v) sdr_write32(MSDC_TXDATA, (v))
+#define msdc_fifo_write8(v) sdr_write8(MSDC_TXDATA, (v))
+#define msdc_fifo_read32() sdr_read32(MSDC_RXDATA)
+#define msdc_fifo_read8() sdr_read8(MSDC_RXDATA)
+
+
+#define msdc_dma_on() sdr_clr_bits(MSDC_CFG, MSDC_CFG_PIO)
+#define msdc_dma_off() sdr_set_bits(MSDC_CFG, MSDC_CFG_PIO)
+
+#define msdc_retry(expr,retry,cnt) \
+ do { \
+ int backup = cnt; \
+ while (retry) { \
+ if (!(expr)) break; \
+ if (cnt-- == 0) { \
+ retry--; mdelay(1); cnt = backup; \
+ } \
+ } \
+ WARN_ON(retry == 0); \
+ } while(0)
+
+#if 0 /* --- by chhung */
+#define msdc_reset() \
+ do { \
+ int retry = 3, cnt = 1000; \
+ sdr_set_bits(MSDC_CFG, MSDC_CFG_RST); \
+ dsb(); \
+ msdc_retry(sdr_read32(MSDC_CFG) & MSDC_CFG_RST, retry, cnt); \
+ } while(0)
+#else
+#define msdc_reset() \
+ do { \
+ int retry = 3, cnt = 1000; \
+ sdr_set_bits(MSDC_CFG, MSDC_CFG_RST); \
+ msdc_retry(sdr_read32(MSDC_CFG) & MSDC_CFG_RST, retry, cnt); \
+ } while(0)
+#endif /* end of +/- */
+
+#define msdc_clr_int() \
+ do { \
+ volatile u32 val = sdr_read32(MSDC_INT); \
+ sdr_write32(MSDC_INT, val); \
+ } while(0)
+
+#define msdc_clr_fifo() \
+ do { \
+ int retry = 3, cnt = 1000; \
+ sdr_set_bits(MSDC_FIFOCS, MSDC_FIFOCS_CLR); \
+ msdc_retry(sdr_read32(MSDC_FIFOCS) & MSDC_FIFOCS_CLR, retry, cnt); \
+ } while(0)
+
+#define msdc_irq_save(val) \
+ do { \
+ val = sdr_read32(MSDC_INTEN); \
+ sdr_clr_bits(MSDC_INTEN, val); \
+ } while(0)
+
+#define msdc_irq_restore(val) \
+ do { \
+ sdr_set_bits(MSDC_INTEN, val); \
+ } while(0)
+
+/* clock source for host: global */
+#if defined (CONFIG_SOC_MT7620)
+static u32 hclks[] = {48000000}; /* +/- by chhung */
+#elif defined (CONFIG_SOC_MT7621)
+static u32 hclks[] = {50000000}; /* +/- by chhung */
+#endif
+
+//============================================
+// the power for msdc host controller: global
+// always keep the VMC on.
+//============================================
+#define msdc_vcore_on(host) \
+ do { \
+ INIT_MSG("[+]VMC ref. count<%d>", ++host->pwr_ref); \
+ (void)hwPowerOn(MT65XX_POWER_LDO_VMC, VOL_3300, "SD"); \
+ } while (0)
+#define msdc_vcore_off(host) \
+ do { \
+ INIT_MSG("[-]VMC ref. count<%d>", --host->pwr_ref); \
+ (void)hwPowerDown(MT65XX_POWER_LDO_VMC, "SD"); \
+ } while (0)
+
+//====================================
+// the vdd output for card: global
+// always keep the VMCH on.
+//====================================
+#define msdc_vdd_on(host) \
+ do { \
+ (void)hwPowerOn(MT65XX_POWER_LDO_VMCH, VOL_3300, "SD"); \
+ } while (0)
+#define msdc_vdd_off(host) \
+ do { \
+ (void)hwPowerDown(MT65XX_POWER_LDO_VMCH, "SD"); \
+ } while (0)
+
+#define sdc_is_busy() (sdr_read32(SDC_STS) & SDC_STS_SDCBUSY)
+#define sdc_is_cmd_busy() (sdr_read32(SDC_STS) & SDC_STS_CMDBUSY)
+
+#define sdc_send_cmd(cmd,arg) \
+ do { \
+ sdr_write32(SDC_ARG, (arg)); \
+ sdr_write32(SDC_CMD, (cmd)); \
+ } while(0)
+
+// can modify to read h/w register.
+//#define is_card_present(h) ((sdr_read32(MSDC_PS) & MSDC_PS_CDSTS) ? 0 : 1);
+#define is_card_present(h) (((struct msdc_host*)(h))->card_inserted)
+
+/* +++ by chhung */
+#ifndef __ASSEMBLY__
+#define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff)
+#else
+#define PHYSADDR(a) ((a) & 0x1fffffff)
+#endif
+/* end of +++ */
+static unsigned int msdc_do_command(struct msdc_host *host,
+ struct mmc_command *cmd,
+ int tune,
+ unsigned long timeout);
+
+static int msdc_tune_cmdrsp(struct msdc_host*host,struct mmc_command *cmd);
+
+#ifdef MT6575_SD_DEBUG
+static void msdc_dump_card_status(struct msdc_host *host, u32 status)
+{
+/* N_MSG is currently a no-op */
+#if 0
+ static char *state[] = {
+ "Idle", /* 0 */
+ "Ready", /* 1 */
+ "Ident", /* 2 */
+ "Stby", /* 3 */
+ "Tran", /* 4 */
+ "Data", /* 5 */
+ "Rcv", /* 6 */
+ "Prg", /* 7 */
+ "Dis", /* 8 */
+ "Reserved", /* 9 */
+ "Reserved", /* 10 */
+ "Reserved", /* 11 */
+ "Reserved", /* 12 */
+ "Reserved", /* 13 */
+ "Reserved", /* 14 */
+ "I/O mode", /* 15 */
+ };
+#endif
+ if (status & R1_OUT_OF_RANGE)
+ N_MSG(RSP, "[CARD_STATUS] Out of Range");
+ if (status & R1_ADDRESS_ERROR)
+ N_MSG(RSP, "[CARD_STATUS] Address Error");
+ if (status & R1_BLOCK_LEN_ERROR)
+ N_MSG(RSP, "[CARD_STATUS] Block Len Error");
+ if (status & R1_ERASE_SEQ_ERROR)
+ N_MSG(RSP, "[CARD_STATUS] Erase Seq Error");
+ if (status & R1_ERASE_PARAM)
+ N_MSG(RSP, "[CARD_STATUS] Erase Param");
+ if (status & R1_WP_VIOLATION)
+ N_MSG(RSP, "[CARD_STATUS] WP Violation");
+ if (status & R1_CARD_IS_LOCKED)
+ N_MSG(RSP, "[CARD_STATUS] Card is Locked");
+ if (status & R1_LOCK_UNLOCK_FAILED)
+ N_MSG(RSP, "[CARD_STATUS] Lock/Unlock Failed");
+ if (status & R1_COM_CRC_ERROR)
+ N_MSG(RSP, "[CARD_STATUS] Command CRC Error");
+ if (status & R1_ILLEGAL_COMMAND)
+ N_MSG(RSP, "[CARD_STATUS] Illegal Command");
+ if (status & R1_CARD_ECC_FAILED)
+ N_MSG(RSP, "[CARD_STATUS] Card ECC Failed");
+ if (status & R1_CC_ERROR)
+ N_MSG(RSP, "[CARD_STATUS] CC Error");
+ if (status & R1_ERROR)
+ N_MSG(RSP, "[CARD_STATUS] Error");
+ if (status & R1_UNDERRUN)
+ N_MSG(RSP, "[CARD_STATUS] Underrun");
+ if (status & R1_OVERRUN)
+ N_MSG(RSP, "[CARD_STATUS] Overrun");
+ if (status & R1_CID_CSD_OVERWRITE)
+ N_MSG(RSP, "[CARD_STATUS] CID/CSD Overwrite");
+ if (status & R1_WP_ERASE_SKIP)
+ N_MSG(RSP, "[CARD_STATUS] WP Eraser Skip");
+ if (status & R1_CARD_ECC_DISABLED)
+ N_MSG(RSP, "[CARD_STATUS] Card ECC Disabled");
+ if (status & R1_ERASE_RESET)
+ N_MSG(RSP, "[CARD_STATUS] Erase Reset");
+ if (status & R1_READY_FOR_DATA)
+ N_MSG(RSP, "[CARD_STATUS] Ready for Data");
+ if (status & R1_SWITCH_ERROR)
+ N_MSG(RSP, "[CARD_STATUS] Switch error");
+ if (status & R1_APP_CMD)
+ N_MSG(RSP, "[CARD_STATUS] App Command");
+
+ N_MSG(RSP, "[CARD_STATUS] '%s' State", state[R1_CURRENT_STATE(status)]);
+}
+
+static void msdc_dump_ocr_reg(struct msdc_host *host, u32 resp)
+{
+ if (resp & (1 << 7))
+ N_MSG(RSP, "[OCR] Low Voltage Range");
+ if (resp & (1 << 15))
+ N_MSG(RSP, "[OCR] 2.7-2.8 volt");
+ if (resp & (1 << 16))
+ N_MSG(RSP, "[OCR] 2.8-2.9 volt");
+ if (resp & (1 << 17))
+ N_MSG(RSP, "[OCR] 2.9-3.0 volt");
+ if (resp & (1 << 18))
+ N_MSG(RSP, "[OCR] 3.0-3.1 volt");
+ if (resp & (1 << 19))
+ N_MSG(RSP, "[OCR] 3.1-3.2 volt");
+ if (resp & (1 << 20))
+ N_MSG(RSP, "[OCR] 3.2-3.3 volt");
+ if (resp & (1 << 21))
+ N_MSG(RSP, "[OCR] 3.3-3.4 volt");
+ if (resp & (1 << 22))
+ N_MSG(RSP, "[OCR] 3.4-3.5 volt");
+ if (resp & (1 << 23))
+ N_MSG(RSP, "[OCR] 3.5-3.6 volt");
+ if (resp & (1 << 24))
+ N_MSG(RSP, "[OCR] Switching to 1.8V Accepted (S18A)");
+ if (resp & (1 << 30))
+ N_MSG(RSP, "[OCR] Card Capacity Status (CCS)");
+ if (resp & (1 << 31))
+ N_MSG(RSP, "[OCR] Card Power Up Status (Idle)");
+ else
+ N_MSG(RSP, "[OCR] Card Power Up Status (Busy)");
+}
+
+static void msdc_dump_rca_resp(struct msdc_host *host, u32 resp)
+{
+ u32 status = (((resp >> 15) & 0x1) << 23) |
+ (((resp >> 14) & 0x1) << 22) |
+ (((resp >> 13) & 0x1) << 19) |
+ (resp & 0x1fff);
+
+ N_MSG(RSP, "[RCA] 0x%.4x", resp >> 16);
+ msdc_dump_card_status(host, status);
+}
+
+static void msdc_dump_io_resp(struct msdc_host *host, u32 resp)
+{
+ u32 flags = (resp >> 8) & 0xFF;
+#if 0
+ char *state[] = {"DIS", "CMD", "TRN", "RFU"};
+#endif
+ if (flags & (1 << 7))
+ N_MSG(RSP, "[IO] COM_CRC_ERR");
+ if (flags & (1 << 6))
+ N_MSG(RSP, "[IO] Illgal command");
+ if (flags & (1 << 3))
+ N_MSG(RSP, "[IO] Error");
+ if (flags & (1 << 2))
+ N_MSG(RSP, "[IO] RFU");
+ if (flags & (1 << 1))
+ N_MSG(RSP, "[IO] Function number error");
+ if (flags & (1 << 0))
+ N_MSG(RSP, "[IO] Out of range");
+
+ N_MSG(RSP, "[IO] State: %s, Data:0x%x", state[(resp >> 12) & 0x3], resp & 0xFF);
+}
+#endif
+
+static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks)
+{
+ u32 base = host->base;
+ u32 timeout, clk_ns;
+
+ host->timeout_ns = ns;
+ host->timeout_clks = clks;
+
+ clk_ns = 1000000000UL / host->sclk;
+ timeout = ns / clk_ns + clks;
+ timeout = timeout >> 16; /* in 65536 sclk cycle unit */
+ timeout = timeout > 1 ? timeout - 1 : 0;
+ timeout = timeout > 255 ? 255 : timeout;
+
+ sdr_set_field(SDC_CFG, SDC_CFG_DTOC, timeout);
+
+ N_MSG(OPS, "Set read data timeout: %dns %dclks -> %d x 65536 cycles",
+ ns, clks, timeout + 1);
+}
+
+/* msdc_eirq_sdio() will be called when EIRQ(for WIFI) */
+static void msdc_eirq_sdio(void *data)
+{
+ struct msdc_host *host = (struct msdc_host *)data;
+
+ N_MSG(INT, "SDIO EINT");
+
+ mmc_signal_sdio_irq(host->mmc);
+}
+
+/* msdc_eirq_cd will not be used! We not using EINT for card detection. */
+static void msdc_eirq_cd(void *data)
+{
+ struct msdc_host *host = (struct msdc_host *)data;
+
+ N_MSG(INT, "CD EINT");
+
+#if 0
+ tasklet_hi_schedule(&host->card_tasklet);
+#else
+ schedule_delayed_work(&host->card_delaywork, HZ);
+#endif
+}
+
+#if 0
+static void msdc_tasklet_card(unsigned long arg)
+{
+ struct msdc_host *host = (struct msdc_host *)arg;
+#else
+static void msdc_tasklet_card(struct work_struct *work)
+{
+ struct msdc_host *host = (struct msdc_host *)container_of(work,
+ struct msdc_host, card_delaywork.work);
+#endif
+ struct msdc_hw *hw = host->hw;
+ u32 base = host->base;
+ u32 inserted;
+ u32 status = 0;
+ //u32 change = 0;
+
+ spin_lock(&host->lock);
+
+ if (hw->get_cd_status) { // NULL
+ inserted = hw->get_cd_status();
+ } else {
+ status = sdr_read32(MSDC_PS);
+ if (cd_active_low)
+ inserted = (status & MSDC_PS_CDSTS) ? 0 : 1;
+ else
+ inserted = (status & MSDC_PS_CDSTS) ? 1 : 0;
+ }
+
+#if 0
+ change = host->card_inserted ^ inserted;
+ host->card_inserted = inserted;
+
+ if (change && !host->suspend) {
+ if (inserted) {
+ host->mmc->f_max = HOST_MAX_MCLK; // work around
+ }
+ mmc_detect_change(host->mmc, msecs_to_jiffies(20));
+ }
+#else /* Make sure: handle the last interrupt */
+ host->card_inserted = inserted;
+
+ if (!host->suspend) {
+ host->mmc->f_max = HOST_MAX_MCLK;
+ mmc_detect_change(host->mmc, msecs_to_jiffies(20));
+ }
+
+ IRQ_MSG("card found<%s>", inserted ? "inserted" : "removed");
+#endif
+
+ spin_unlock(&host->lock);
+}
+
+#if 0 /* --- by chhung */
+/* For E2 only */
+static u8 clk_src_bit[4] = {
+ 0, 3, 5, 7
+};
+
+static void msdc_select_clksrc(struct msdc_host* host, unsigned char clksrc)
+{
+ u32 val;
+ u32 base = host->base;
+
+ BUG_ON(clksrc > 3);
+ INIT_MSG("set clock source to <%d>", clksrc);
+
+ val = sdr_read32(MSDC_CLKSRC_REG);
+ if (sdr_read32(MSDC_ECO_VER) >= 4) {
+ val &= ~(0x3 << clk_src_bit[host->id]);
+ val |= clksrc << clk_src_bit[host->id];
+ } else {
+ val &= ~0x3; val |= clksrc;
+ }
+ sdr_write32(MSDC_CLKSRC_REG, val);
+
+ host->hclk = hclks[clksrc];
+ host->hw->clk_src = clksrc;
+}
+#endif /* end of --- */
+
+static void msdc_set_mclk(struct msdc_host *host, int ddr, unsigned int hz)
+{
+ //struct msdc_hw *hw = host->hw;
+ u32 base = host->base;
+ u32 mode;
+ u32 flags;
+ u32 div;
+ u32 sclk;
+ u32 hclk = host->hclk;
+ //u8 clksrc = hw->clk_src;
+
+ if (!hz) { // set mmc system clock to 0 ?
+ //ERR_MSG("set mclk to 0!!!");
+ msdc_reset();
+ return;
+ }
+
+ msdc_irq_save(flags);
+
+#if defined (CONFIG_MT7621_FPGA) || defined (CONFIG_MT7628_FPGA)
+ mode = 0x0; /* use divisor */
+ if (hz >= (hclk >> 1)) {
+ div = 0; /* mean div = 1/2 */
+ sclk = hclk >> 1; /* sclk = clk / 2 */
+ } else {
+ div = (hclk + ((hz << 2) - 1)) / (hz << 2);
+ sclk = (hclk >> 2) / div;
+ }
+#else
+ if (ddr) {
+ mode = 0x2; /* ddr mode and use divisor */
+ if (hz >= (hclk >> 2)) {
+ div = 1; /* mean div = 1/4 */
+ sclk = hclk >> 2; /* sclk = clk / 4 */
+ } else {
+ div = (hclk + ((hz << 2) - 1)) / (hz << 2);
+ sclk = (hclk >> 2) / div;
+ }
+ } else if (hz >= hclk) { /* bug fix */
+ mode = 0x1; /* no divisor and divisor is ignored */
+ div = 0;
+ sclk = hclk;
+ } else {
+ mode = 0x0; /* use divisor */
+ if (hz >= (hclk >> 1)) {
+ div = 0; /* mean div = 1/2 */
+ sclk = hclk >> 1; /* sclk = clk / 2 */
+ } else {
+ div = (hclk + ((hz << 2) - 1)) / (hz << 2);
+ sclk = (hclk >> 2) / div;
+ }
+ }
+#endif
+ /* set clock mode and divisor */
+ sdr_set_field(MSDC_CFG, MSDC_CFG_CKMOD, mode);
+ sdr_set_field(MSDC_CFG, MSDC_CFG_CKDIV, div);
+
+ /* wait clock stable */
+ while (!(sdr_read32(MSDC_CFG) & MSDC_CFG_CKSTB));
+
+ host->sclk = sclk;
+ host->mclk = hz;
+ msdc_set_timeout(host, host->timeout_ns, host->timeout_clks); // need?
+
+ INIT_MSG("================");
+ INIT_MSG("!!! Set<%dKHz> Source<%dKHz> -> sclk<%dKHz>", hz/1000, hclk/1000, sclk/1000);
+ INIT_MSG("================");
+
+ msdc_irq_restore(flags);
+}
+
+/* Fix me. when need to abort */
+static void msdc_abort_data(struct msdc_host *host)
+{
+ u32 base = host->base;
+ struct mmc_command *stop = host->mrq->stop;
+
+ ERR_MSG("Need to Abort. dma<%d>", host->dma_xfer);
+
+ msdc_reset();
+ msdc_clr_fifo();
+ msdc_clr_int();
+
+ // need to check FIFO count 0 ?
+
+ if (stop) { /* try to stop, but may not success */
+ ERR_MSG("stop when abort CMD<%d>", stop->opcode);
+ (void)msdc_do_command(host, stop, 0, CMD_TIMEOUT);
+ }
+
+ //if (host->mclk >= 25000000) {
+ // msdc_set_mclk(host, 0, host->mclk >> 1);
+ //}
+}
+
+#if 0 /* --- by chhung */
+static void msdc_pin_config(struct msdc_host *host, int mode)
+{
+ struct msdc_hw *hw = host->hw;
+ u32 base = host->base;
+ int pull = (mode == MSDC_PIN_PULL_UP) ? GPIO_PULL_UP : GPIO_PULL_DOWN;
+
+ /* Config WP pin */
+ if (hw->flags & MSDC_WP_PIN_EN) {
+ if (hw->config_gpio_pin) /* NULL */
+ hw->config_gpio_pin(MSDC_WP_PIN, pull);
+ }
+
+ switch (mode) {
+ case MSDC_PIN_PULL_UP:
+ //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPU, 1); /* Check & FIXME */
+ //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPD, 0); /* Check & FIXME */
+ sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPU, 1);
+ sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPD, 0);
+ sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPU, 1);
+ sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPD, 0);
+ break;
+ case MSDC_PIN_PULL_DOWN:
+ //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPU, 0); /* Check & FIXME */
+ //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPD, 1); /* Check & FIXME */
+ sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPU, 0);
+ sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPD, 1);
+ sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPU, 0);
+ sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPD, 1);
+ break;
+ case MSDC_PIN_PULL_NONE:
+ default:
+ //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPU, 0); /* Check & FIXME */
+ //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPD, 0); /* Check & FIXME */
+ sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPU, 0);
+ sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPD, 0);
+ sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPU, 0);
+ sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPD, 0);
+ break;
+ }
+
+ N_MSG(CFG, "Pins mode(%d), down(%d), up(%d)",
+ mode, MSDC_PIN_PULL_DOWN, MSDC_PIN_PULL_UP);
+}
+
+void msdc_pin_reset(struct msdc_host *host, int mode)
+{
+ struct msdc_hw *hw = (struct msdc_hw *)host->hw;
+ u32 base = host->base;
+ int pull = (mode == MSDC_PIN_PULL_UP) ? GPIO_PULL_UP : GPIO_PULL_DOWN;
+
+ /* Config reset pin */
+ if (hw->flags & MSDC_RST_PIN_EN) {
+ if (hw->config_gpio_pin) /* NULL */
+ hw->config_gpio_pin(MSDC_RST_PIN, pull);
+
+ if (mode == MSDC_PIN_PULL_UP) {
+ sdr_clr_bits(EMMC_IOCON, EMMC_IOCON_BOOTRST);
+ } else {
+ sdr_set_bits(EMMC_IOCON, EMMC_IOCON_BOOTRST);
+ }
+ }
+}
+
+static void msdc_core_power(struct msdc_host *host, int on)
+{
+ N_MSG(CFG, "Turn %s %s power (copower: %d -> %d)",
+ on ? "on" : "off", "core", host->core_power, on);
+
+ if (on && host->core_power == 0) {
+ msdc_vcore_on(host);
+ host->core_power = 1;
+ msleep(1);
+ } else if (!on && host->core_power == 1) {
+ msdc_vcore_off(host);
+ host->core_power = 0;
+ msleep(1);
+ }
+}
+
+static void msdc_host_power(struct msdc_host *host, int on)
+{
+ N_MSG(CFG, "Turn %s %s power ", on ? "on" : "off", "host");
+
+ if (on) {
+ //msdc_core_power(host, 1); // need do card detection.
+ msdc_pin_reset(host, MSDC_PIN_PULL_UP);
+ } else {
+ msdc_pin_reset(host, MSDC_PIN_PULL_DOWN);
+ //msdc_core_power(host, 0);
+ }
+}
+
+static void msdc_card_power(struct msdc_host *host, int on)
+{
+ N_MSG(CFG, "Turn %s %s power ", on ? "on" : "off", "card");
+
+ if (on) {
+ msdc_pin_config(host, MSDC_PIN_PULL_UP);
+ if (host->hw->ext_power_on) {
+ host->hw->ext_power_on();
+ } else {
+ //msdc_vdd_on(host); // need todo card detection.
+ }
+ msleep(1);
+ } else {
+ if (host->hw->ext_power_off) {
+ host->hw->ext_power_off();
+ } else {
+ //msdc_vdd_off(host);
+ }
+ msdc_pin_config(host, MSDC_PIN_PULL_DOWN);
+ msleep(1);
+ }
+}
+
+static void msdc_set_power_mode(struct msdc_host *host, u8 mode)
+{
+ N_MSG(CFG, "Set power mode(%d)", mode);
+
+ if (host->power_mode == MMC_POWER_OFF && mode != MMC_POWER_OFF) {
+ msdc_host_power(host, 1);
+ msdc_card_power(host, 1);
+ } else if (host->power_mode != MMC_POWER_OFF && mode == MMC_POWER_OFF) {
+ msdc_card_power(host, 0);
+ msdc_host_power(host, 0);
+ }
+ host->power_mode = mode;
+}
+#endif /* end of --- */
+
+#ifdef CONFIG_PM
+/*
+ register as callback function of WIFI(combo_sdio_register_pm) .
+ can called by msdc_drv_suspend/resume too.
+*/
+static void msdc_pm(pm_message_t state, void *data)
+{
+ struct msdc_host *host = (struct msdc_host *)data;
+ int evt = state.event;
+
+ if (evt == PM_EVENT_USER_RESUME || evt == PM_EVENT_USER_SUSPEND) {
+ INIT_MSG("USR_%s: suspend<%d> power<%d>",
+ evt == PM_EVENT_USER_RESUME ? "EVENT_USER_RESUME" : "EVENT_USER_SUSPEND",
+ host->suspend, host->power_mode);
+ }
+
+ if (evt == PM_EVENT_SUSPEND || evt == PM_EVENT_USER_SUSPEND) {
+ if (host->suspend) /* already suspend */ /* default 0*/
+ return;
+
+ /* for memory card. already power off by mmc */
+ if (evt == PM_EVENT_SUSPEND && host->power_mode == MMC_POWER_OFF)
+ return;
+
+ host->suspend = 1;
+ host->pm_state = state; /* default PMSG_RESUME */
+
+ INIT_MSG("%s Suspend", evt == PM_EVENT_SUSPEND ? "PM" : "USR");
+ if(host->hw->flags & MSDC_SYS_SUSPEND) /* set for card */
+ (void)mmc_suspend_host(host->mmc);
+ else {
+ // host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY; /* just for double confirm */ /* --- by chhung */
+ mmc_remove_host(host->mmc);
+ }
+ } else if (evt == PM_EVENT_RESUME || evt == PM_EVENT_USER_RESUME) {
+ if (!host->suspend){
+ //ERR_MSG("warning: already resume");
+ return;
+ }
+
+ /* No PM resume when USR suspend */
+ if (evt == PM_EVENT_RESUME && host->pm_state.event == PM_EVENT_USER_SUSPEND) {
+ ERR_MSG("PM Resume when in USR Suspend"); /* won't happen. */
+ return;
+ }
+
+ host->suspend = 0;
+ host->pm_state = state;
+
+ INIT_MSG("%s Resume", evt == PM_EVENT_RESUME ? "PM" : "USR");
+ if(host->hw->flags & MSDC_SYS_SUSPEND) { /* will not set for WIFI */
+ (void)mmc_resume_host(host->mmc);
+ }
+ else {
+ // host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY; /* --- by chhung */
+ mmc_add_host(host->mmc);
+ }
+ }
+}
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* mmc_host_ops members */
+/*--------------------------------------------------------------------------*/
+static unsigned int msdc_command_start(struct msdc_host *host,
+ struct mmc_command *cmd,
+ int tune, /* not used */
+ unsigned long timeout)
+{
+ u32 base = host->base;
+ u32 opcode = cmd->opcode;
+ u32 rawcmd;
+ u32 wints = MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO |
+ MSDC_INT_ACMDRDY | MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO |
+ MSDC_INT_ACMD19_DONE;
+
+ u32 resp;
+ unsigned long tmo;
+
+ /* Protocol layer does not provide response type, but our hardware needs
+ * to know exact type, not just size!
+ */
+ if (opcode == MMC_SEND_OP_COND || opcode == SD_APP_OP_COND)
+ resp = RESP_R3;
+ else if (opcode == MMC_SET_RELATIVE_ADDR || opcode == SD_SEND_RELATIVE_ADDR)
+ resp = (mmc_cmd_type(cmd) == MMC_CMD_BCR) ? RESP_R6 : RESP_R1;
+ else if (opcode == MMC_FAST_IO)
+ resp = RESP_R4;
+ else if (opcode == MMC_GO_IRQ_STATE)
+ resp = RESP_R5;
+ else if (opcode == MMC_SELECT_CARD)
+ resp = (cmd->arg != 0) ? RESP_R1B : RESP_NONE;
+ else if (opcode == SD_IO_RW_DIRECT || opcode == SD_IO_RW_EXTENDED)
+ resp = RESP_R1; /* SDIO workaround. */
+ else if (opcode == SD_SEND_IF_COND && (mmc_cmd_type(cmd) == MMC_CMD_BCR))
+ resp = RESP_R1;
+ else {
+ switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_R1:
+ resp = RESP_R1;
+ break;
+ case MMC_RSP_R1B:
+ resp = RESP_R1B;
+ break;
+ case MMC_RSP_R2:
+ resp = RESP_R2;
+ break;
+ case MMC_RSP_R3:
+ resp = RESP_R3;
+ break;
+ case MMC_RSP_NONE:
+ default:
+ resp = RESP_NONE;
+ break;
+ }
+ }
+
+ cmd->error = 0;
+ /* rawcmd :
+ * vol_swt << 30 | auto_cmd << 28 | blklen << 16 | go_irq << 15 |
+ * stop << 14 | rw << 13 | dtype << 11 | rsptyp << 7 | brk << 6 | opcode
+ */
+ rawcmd = opcode | msdc_rsp[resp] << 7 | host->blksz << 16;
+
+ if (opcode == MMC_READ_MULTIPLE_BLOCK) {
+ rawcmd |= (2 << 11);
+ } else if (opcode == MMC_READ_SINGLE_BLOCK) {
+ rawcmd |= (1 << 11);
+ } else if (opcode == MMC_WRITE_MULTIPLE_BLOCK) {
+ rawcmd |= ((2 << 11) | (1 << 13));
+ } else if (opcode == MMC_WRITE_BLOCK) {
+ rawcmd |= ((1 << 11) | (1 << 13));
+ } else if (opcode == SD_IO_RW_EXTENDED) {
+ if (cmd->data->flags & MMC_DATA_WRITE)
+ rawcmd |= (1 << 13);
+ if (cmd->data->blocks > 1)
+ rawcmd |= (2 << 11);
+ else
+ rawcmd |= (1 << 11);
+ } else if (opcode == SD_IO_RW_DIRECT && cmd->flags == (unsigned int)-1) {
+ rawcmd |= (1 << 14);
+ } else if ((opcode == SD_APP_SEND_SCR) ||
+ (opcode == SD_APP_SEND_NUM_WR_BLKS) ||
+ (opcode == SD_SWITCH && (mmc_cmd_type(cmd) == MMC_CMD_ADTC)) ||
+ (opcode == SD_APP_SD_STATUS && (mmc_cmd_type(cmd) == MMC_CMD_ADTC)) ||
+ (opcode == MMC_SEND_EXT_CSD && (mmc_cmd_type(cmd) == MMC_CMD_ADTC))) {
+ rawcmd |= (1 << 11);
+ } else if (opcode == MMC_STOP_TRANSMISSION) {
+ rawcmd |= (1 << 14);
+ rawcmd &= ~(0x0FFF << 16);
+ }
+
+ N_MSG(CMD, "CMD<%d><0x%.8x> Arg<0x%.8x>", opcode , rawcmd, cmd->arg);
+
+ tmo = jiffies + timeout;
+
+ if (opcode == MMC_SEND_STATUS) {
+ for (;;) {
+ if (!sdc_is_cmd_busy())
+ break;
+
+ if (time_after(jiffies, tmo)) {
+ ERR_MSG("XXX cmd_busy timeout: before CMD<%d>", opcode);
+ cmd->error = (unsigned int)-ETIMEDOUT;
+ msdc_reset();
+ goto end;
+ }
+ }
+ }else {
+ for (;;) {
+ if (!sdc_is_busy())
+ break;
+ if (time_after(jiffies, tmo)) {
+ ERR_MSG("XXX sdc_busy timeout: before CMD<%d>", opcode);
+ cmd->error = (unsigned int)-ETIMEDOUT;
+ msdc_reset();
+ goto end;
+ }
+ }
+ }
+
+ //BUG_ON(in_interrupt());
+ host->cmd = cmd;
+ host->cmd_rsp = resp;
+
+ init_completion(&host->cmd_done);
+
+ sdr_set_bits(MSDC_INTEN, wints);
+ sdc_send_cmd(rawcmd, cmd->arg);
+
+end:
+ return cmd->error;
+}
+
+static unsigned int msdc_command_resp(struct msdc_host *host,
+ struct mmc_command *cmd,
+ int tune,
+ unsigned long timeout)
+{
+ u32 base = host->base;
+ u32 opcode = cmd->opcode;
+ //u32 rawcmd;
+ u32 resp;
+ u32 wints = MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO |
+ MSDC_INT_ACMDRDY | MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO |
+ MSDC_INT_ACMD19_DONE;
+
+ resp = host->cmd_rsp;
+
+ BUG_ON(in_interrupt());
+ //init_completion(&host->cmd_done);
+ //sdr_set_bits(MSDC_INTEN, wints);
+
+ spin_unlock(&host->lock);
+ if(!wait_for_completion_timeout(&host->cmd_done, 10*timeout)){
+ ERR_MSG("XXX CMD<%d> wait_for_completion timeout ARG<0x%.8x>", opcode, cmd->arg);
+ cmd->error = (unsigned int)-ETIMEDOUT;
+ msdc_reset();
+ }
+ spin_lock(&host->lock);
+
+ sdr_clr_bits(MSDC_INTEN, wints);
+ host->cmd = NULL;
+
+//end:
+#ifdef MT6575_SD_DEBUG
+ switch (resp) {
+ case RESP_NONE:
+ N_MSG(RSP, "CMD_RSP(%d): %d RSP(%d)", opcode, cmd->error, resp);
+ break;
+ case RESP_R2:
+ N_MSG(RSP, "CMD_RSP(%d): %d RSP(%d)= %.8x %.8x %.8x %.8x",
+ opcode, cmd->error, resp, cmd->resp[0], cmd->resp[1],
+ cmd->resp[2], cmd->resp[3]);
+ break;
+ default: /* Response types 1, 3, 4, 5, 6, 7(1b) */
+ N_MSG(RSP, "CMD_RSP(%d): %d RSP(%d)= 0x%.8x",
+ opcode, cmd->error, resp, cmd->resp[0]);
+ if (cmd->error == 0) {
+ switch (resp) {
+ case RESP_R1:
+ case RESP_R1B:
+ msdc_dump_card_status(host, cmd->resp[0]);
+ break;
+ case RESP_R3:
+ msdc_dump_ocr_reg(host, cmd->resp[0]);
+ break;
+ case RESP_R5:
+ msdc_dump_io_resp(host, cmd->resp[0]);
+ break;
+ case RESP_R6:
+ msdc_dump_rca_resp(host, cmd->resp[0]);
+ break;
+ }
+ }
+ break;
+ }
+#endif
+
+ /* do we need to save card's RCA when SD_SEND_RELATIVE_ADDR */
+
+ if (!tune) {
+ return cmd->error;
+ }
+
+ /* memory card CRC */
+ if(host->hw->flags & MSDC_REMOVABLE && cmd->error == (unsigned int)(-EIO) ) {
+ if (sdr_read32(SDC_CMD) & 0x1800) { /* check if has data phase */
+ msdc_abort_data(host);
+ } else {
+ /* do basic: reset*/
+ msdc_reset();
+ msdc_clr_fifo();
+ msdc_clr_int();
+ }
+ cmd->error = msdc_tune_cmdrsp(host,cmd);
+ }
+
+ // check DAT0
+ /* if (resp == RESP_R1B) {
+ while ((sdr_read32(MSDC_PS) & 0x10000) != 0x10000);
+ } */
+ /* CMD12 Error Handle */
+
+ return cmd->error;
+}
+
+static unsigned int msdc_do_command(struct msdc_host *host,
+ struct mmc_command *cmd,
+ int tune,
+ unsigned long timeout)
+{
+ if (msdc_command_start(host, cmd, tune, timeout))
+ goto end;
+
+ if (msdc_command_resp(host, cmd, tune, timeout))
+ goto end;
+
+end:
+
+ N_MSG(CMD, " return<%d> resp<0x%.8x>", cmd->error, cmd->resp[0]);
+ return cmd->error;
+}
+
+/* The abort condition when PIO read/write
+ tmo:
+*/
+static int msdc_pio_abort(struct msdc_host *host, struct mmc_data *data, unsigned long tmo)
+{
+ int ret = 0;
+ u32 base = host->base;
+
+ if (atomic_read(&host->abort)) {
+ ret = 1;
+ }
+
+ if (time_after(jiffies, tmo)) {
+ data->error = (unsigned int)-ETIMEDOUT;
+ ERR_MSG("XXX PIO Data Timeout: CMD<%d>", host->mrq->cmd->opcode);
+ ret = 1;
+ }
+
+ if(ret) {
+ msdc_reset();
+ msdc_clr_fifo();
+ msdc_clr_int();
+ ERR_MSG("msdc pio find abort");
+ }
+ return ret;
+}
+
+/*
+ Need to add a timeout, or WDT timeout, system reboot.
+*/
+// pio mode data read/write
+static int msdc_pio_read(struct msdc_host *host, struct mmc_data *data)
+{
+ struct scatterlist *sg = data->sg;
+ u32 base = host->base;
+ u32 num = data->sg_len;
+ u32 *ptr;
+ u8 *u8ptr;
+ u32 left = 0;
+ u32 count, size = 0;
+ u32 wints = MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR ;
+ unsigned long tmo = jiffies + DAT_TIMEOUT;
+
+ sdr_set_bits(MSDC_INTEN, wints);
+ while (num) {
+ left = sg_dma_len(sg);
+ ptr = sg_virt(sg);
+ while (left) {
+ if ((left >= MSDC_FIFO_THD) && (msdc_rxfifocnt() >= MSDC_FIFO_THD)) {
+ count = MSDC_FIFO_THD >> 2;
+ do {
+ *ptr++ = msdc_fifo_read32();
+ } while (--count);
+ left -= MSDC_FIFO_THD;
+ } else if ((left < MSDC_FIFO_THD) && msdc_rxfifocnt() >= left) {
+ while (left > 3) {
+ *ptr++ = msdc_fifo_read32();
+ left -= 4;
+ }
+
+ u8ptr = (u8 *)ptr;
+ while(left) {
+ * u8ptr++ = msdc_fifo_read8();
+ left--;
+ }
+ }
+
+ if (msdc_pio_abort(host, data, tmo)) {
+ goto end;
+ }
+ }
+ size += sg_dma_len(sg);
+ sg = sg_next(sg); num--;
+ }
+end:
+ data->bytes_xfered += size;
+ N_MSG(FIO, " PIO Read<%d>bytes", size);
+
+ sdr_clr_bits(MSDC_INTEN, wints);
+ if(data->error) ERR_MSG("read pio data->error<%d> left<%d> size<%d>", data->error, left, size);
+ return data->error;
+}
+
+/* please make sure won't using PIO when size >= 512
+ which means, memory card block read/write won't using pio
+ then don't need to handle the CMD12 when data error.
+*/
+static int msdc_pio_write(struct msdc_host* host, struct mmc_data *data)
+{
+ u32 base = host->base;
+ struct scatterlist *sg = data->sg;
+ u32 num = data->sg_len;
+ u32 *ptr;
+ u8 *u8ptr;
+ u32 left;
+ u32 count, size = 0;
+ u32 wints = MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR ;
+ unsigned long tmo = jiffies + DAT_TIMEOUT;
+
+ sdr_set_bits(MSDC_INTEN, wints);
+ while (num) {
+ left = sg_dma_len(sg);
+ ptr = sg_virt(sg);
+
+ while (left) {
+ if (left >= MSDC_FIFO_SZ && msdc_txfifocnt() == 0) {
+ count = MSDC_FIFO_SZ >> 2;
+ do {
+ msdc_fifo_write32(*ptr); ptr++;
+ } while (--count);
+ left -= MSDC_FIFO_SZ;
+ } else if (left < MSDC_FIFO_SZ && msdc_txfifocnt() == 0) {
+ while (left > 3) {
+ msdc_fifo_write32(*ptr); ptr++;
+ left -= 4;
+ }
+
+ u8ptr = (u8*)ptr;
+ while(left){
+ msdc_fifo_write8(*u8ptr); u8ptr++;
+ left--;
+ }
+ }
+
+ if (msdc_pio_abort(host, data, tmo)) {
+ goto end;
+ }
+ }
+ size += sg_dma_len(sg);
+ sg = sg_next(sg); num--;
+ }
+end:
+ data->bytes_xfered += size;
+ N_MSG(FIO, " PIO Write<%d>bytes", size);
+ if(data->error) ERR_MSG("write pio data->error<%d>", data->error);
+
+ sdr_clr_bits(MSDC_INTEN, wints);
+ return data->error;
+}
+
+#if 0 /* --- by chhung */
+// DMA resume / start / stop
+static void msdc_dma_resume(struct msdc_host *host)
+{
+ u32 base = host->base;
+
+ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_RESUME, 1);
+
+ N_MSG(DMA, "DMA resume");
+}
+#endif /* end of --- */
+
+static void msdc_dma_start(struct msdc_host *host)
+{
+ u32 base = host->base;
+ u32 wints = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR ;
+
+ sdr_set_bits(MSDC_INTEN, wints);
+ //dsb(); /* --- by chhung */
+ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_START, 1);
+
+ N_MSG(DMA, "DMA start");
+}
+
+static void msdc_dma_stop(struct msdc_host *host)
+{
+ u32 base = host->base;
+ //u32 retries=500;
+ u32 wints = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR ;
+
+ N_MSG(DMA, "DMA status: 0x%.8x",sdr_read32(MSDC_DMA_CFG));
+ //while (sdr_read32(MSDC_DMA_CFG) & MSDC_DMA_CFG_STS);
+
+ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_STOP, 1);
+ while (sdr_read32(MSDC_DMA_CFG) & MSDC_DMA_CFG_STS);
+
+ //dsb(); /* --- by chhung */
+ sdr_clr_bits(MSDC_INTEN, wints); /* Not just xfer_comp */
+
+ N_MSG(DMA, "DMA stop");
+}
+
+#if 0 /* --- by chhung */
+/* dump a gpd list */
+static void msdc_dma_dump(struct msdc_host *host, struct msdc_dma *dma)
+{
+ gpd_t *gpd = dma->gpd;
+ bd_t *bd = dma->bd;
+ bd_t *ptr;
+ int i = 0;
+ int p_to_v;
+
+ if (dma->mode != MSDC_MODE_DMA_DESC) {
+ return;
+ }
+
+ ERR_MSG("try to dump gpd and bd");
+
+ /* dump gpd */
+ ERR_MSG(".gpd<0x%.8x> gpd_phy<0x%.8x>", (int)gpd, (int)dma->gpd_addr);
+ ERR_MSG("...hwo <%d>", gpd->hwo );
+ ERR_MSG("...bdp <%d>", gpd->bdp );
+ ERR_MSG("...chksum<0x%.8x>", gpd->chksum );
+ //ERR_MSG("...intr <0x%.8x>", gpd->intr );
+ ERR_MSG("...next <0x%.8x>", (int)gpd->next );
+ ERR_MSG("...ptr <0x%.8x>", (int)gpd->ptr );
+ ERR_MSG("...buflen<0x%.8x>", gpd->buflen );
+ //ERR_MSG("...extlen<0x%.8x>", gpd->extlen );
+ //ERR_MSG("...arg <0x%.8x>", gpd->arg );
+ //ERR_MSG("...blknum<0x%.8x>", gpd->blknum );
+ //ERR_MSG("...cmd <0x%.8x>", gpd->cmd );
+
+ /* dump bd */
+ ERR_MSG(".bd<0x%.8x> bd_phy<0x%.8x> gpd_ptr<0x%.8x>", (int)bd, (int)dma->bd_addr, (int)gpd->ptr);
+ ptr = bd;
+ p_to_v = ((u32)bd - (u32)dma->bd_addr);
+ while (1) {
+ ERR_MSG(".bd[%d]", i); i++;
+ ERR_MSG("...eol <%d>", ptr->eol );
+ ERR_MSG("...chksum<0x%.8x>", ptr->chksum );
+ //ERR_MSG("...blkpad<0x%.8x>", ptr->blkpad );
+ //ERR_MSG("...dwpad <0x%.8x>", ptr->dwpad );
+ ERR_MSG("...next <0x%.8x>", (int)ptr->next );
+ ERR_MSG("...ptr <0x%.8x>", (int)ptr->ptr );
+ ERR_MSG("...buflen<0x%.8x>", (int)ptr->buflen );
+
+ if (ptr->eol == 1) {
+ break;
+ }
+
+ /* find the next bd, virtual address of ptr->next */
+ /* don't need to enable when use malloc */
+ //BUG_ON( (ptr->next + p_to_v)!=(ptr+1) );
+ //ERR_MSG(".next bd<0x%.8x><0x%.8x>", (ptr->next + p_to_v), (ptr+1));
+ ptr++;
+ }
+
+ ERR_MSG("dump gpd and bd finished");
+}
+#endif /* end of --- */
+
+/* calc checksum */
+static u8 msdc_dma_calcs(u8 *buf, u32 len)
+{
+ u32 i, sum = 0;
+ for (i = 0; i < len; i++) {
+ sum += buf[i];
+ }
+ return 0xFF - (u8)sum;
+}
+
+/* gpd bd setup + dma registers */
+static int msdc_dma_config(struct msdc_host *host, struct msdc_dma *dma)
+{
+ u32 base = host->base;
+ u32 sglen = dma->sglen;
+ //u32 i, j, num, bdlen, arg, xfersz;
+ u32 j, num, bdlen;
+ u8 blkpad, dwpad, chksum;
+ struct scatterlist *sg = dma->sg;
+ gpd_t *gpd;
+ bd_t *bd;
+
+ switch (dma->mode) {
+ case MSDC_MODE_DMA_BASIC:
+ BUG_ON(dma->xfersz > 65535);
+ BUG_ON(dma->sglen != 1);
+ sdr_write32(MSDC_DMA_SA, PHYSADDR(sg_dma_address(sg)));
+ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_LASTBUF, 1);
+//#if defined (CONFIG_RALINK_MT7620)
+ if (ralink_soc == MT762X_SOC_MT7620A)
+ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_XFERSZ, sg_dma_len(sg));
+//#elif defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628)
+ else
+ sdr_write32((volatile u32*)(RALINK_MSDC_BASE+0xa8), sg_dma_len(sg));
+//#endif
+ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_BRUSTSZ, dma->burstsz);
+ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_MODE, 0);
+ break;
+ case MSDC_MODE_DMA_DESC:
+ blkpad = (dma->flags & DMA_FLAG_PAD_BLOCK) ? 1 : 0;
+ dwpad = (dma->flags & DMA_FLAG_PAD_DWORD) ? 1 : 0;
+ chksum = (dma->flags & DMA_FLAG_EN_CHKSUM) ? 1 : 0;
+
+ /* calculate the required number of gpd */
+ num = (sglen + MAX_BD_PER_GPD - 1) / MAX_BD_PER_GPD;
+ BUG_ON(num !=1 );
+
+ gpd = dma->gpd;
+ bd = dma->bd;
+ bdlen = sglen;
+
+ /* modify gpd*/
+ //gpd->intr = 0;
+ gpd->hwo = 1; /* hw will clear it */
+ gpd->bdp = 1;
+ gpd->chksum = 0; /* need to clear first. */
+ gpd->chksum = (chksum ? msdc_dma_calcs((u8 *)gpd, 16) : 0);
+
+ /* modify bd*/
+ for (j = 0; j < bdlen; j++) {
+ msdc_init_bd(&bd[j], blkpad, dwpad, sg_dma_address(sg), sg_dma_len(sg));
+ if(j == bdlen - 1) {
+ bd[j].eol = 1; /* the last bd */
+ } else {
+ bd[j].eol = 0;
+ }
+ bd[j].chksum = 0; /* checksume need to clear first */
+ bd[j].chksum = (chksum ? msdc_dma_calcs((u8 *)(&bd[j]), 16) : 0);
+ sg++;
+ }
+
+ dma->used_gpd += 2;
+ dma->used_bd += bdlen;
+
+ sdr_set_field(MSDC_DMA_CFG, MSDC_DMA_CFG_DECSEN, chksum);
+ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_BRUSTSZ, dma->burstsz);
+ sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_MODE, 1);
+
+ sdr_write32(MSDC_DMA_SA, PHYSADDR((u32)dma->gpd_addr));
+ break;
+
+ default:
+ break;
+ }
+
+ N_MSG(DMA, "DMA_CTRL = 0x%x", sdr_read32(MSDC_DMA_CTRL));
+ N_MSG(DMA, "DMA_CFG = 0x%x", sdr_read32(MSDC_DMA_CFG));
+ N_MSG(DMA, "DMA_SA = 0x%x", sdr_read32(MSDC_DMA_SA));
+
+ return 0;
+}
+
+static void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma,
+ struct scatterlist *sg, unsigned int sglen)
+{
+ BUG_ON(sglen > MAX_BD_NUM); /* not support currently */
+
+ dma->sg = sg;
+ dma->flags = DMA_FLAG_EN_CHKSUM;
+ //dma->flags = DMA_FLAG_NONE; /* CHECKME */
+ dma->sglen = sglen;
+ dma->xfersz = host->xfer_size;
+ dma->burstsz = MSDC_BRUST_64B;
+
+ if (sglen == 1 && sg_dma_len(sg) <= MAX_DMA_CNT)
+ dma->mode = MSDC_MODE_DMA_BASIC;
+ else
+ dma->mode = MSDC_MODE_DMA_DESC;
+
+ N_MSG(DMA, "DMA mode<%d> sglen<%d> xfersz<%d>", dma->mode, dma->sglen, dma->xfersz);
+
+ msdc_dma_config(host, dma);
+
+ /*if (dma->mode == MSDC_MODE_DMA_DESC) {
+ //msdc_dma_dump(host, dma);
+ } */
+}
+
+/* set block number before send command */
+static void msdc_set_blknum(struct msdc_host *host, u32 blknum)
+{
+ u32 base = host->base;
+
+ sdr_write32(SDC_BLK_NUM, blknum);
+}
+
+static int msdc_do_request(struct mmc_host*mmc, struct mmc_request*mrq)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ u32 base = host->base;
+ //u32 intsts = 0;
+ unsigned int left=0;
+ int dma = 0, read = 1, dir = DMA_FROM_DEVICE, send_type=0;
+
+ #define SND_DAT 0
+ #define SND_CMD 1
+
+ BUG_ON(mmc == NULL);
+ BUG_ON(mrq == NULL);
+
+ host->error = 0;
+ atomic_set(&host->abort, 0);
+
+ cmd = mrq->cmd;
+ data = mrq->cmd->data;
+
+#if 0 /* --- by chhung */
+ //if(host->id ==1){
+ N_MSG(OPS, "enable clock!");
+ msdc_ungate_clock(host->id);
+ //}
+#endif /* end of --- */
+
+ if (!data) {
+ send_type=SND_CMD;
+ if (msdc_do_command(host, cmd, 1, CMD_TIMEOUT) != 0) {
+ goto done;
+ }
+ } else {
+ BUG_ON(data->blksz > HOST_MAX_BLKSZ);
+ send_type=SND_DAT;
+
+ data->error = 0;
+ read = data->flags & MMC_DATA_READ ? 1 : 0;
+ host->data = data;
+ host->xfer_size = data->blocks * data->blksz;
+ host->blksz = data->blksz;
+
+ /* deside the transfer mode */
+ if (drv_mode[host->id] == MODE_PIO) {
+ host->dma_xfer = dma = 0;
+ } else if (drv_mode[host->id] == MODE_DMA) {
+ host->dma_xfer = dma = 1;
+ } else if (drv_mode[host->id] == MODE_SIZE_DEP) {
+ host->dma_xfer = dma = ((host->xfer_size >= dma_size[host->id]) ? 1 : 0);
+ }
+
+ if (read) {
+ if ((host->timeout_ns != data->timeout_ns) ||
+ (host->timeout_clks != data->timeout_clks)) {
+ msdc_set_timeout(host, data->timeout_ns, data->timeout_clks);
+ }
+ }
+
+ msdc_set_blknum(host, data->blocks);
+ //msdc_clr_fifo(); /* no need */
+
+ if (dma) {
+ msdc_dma_on(); /* enable DMA mode first!! */
+ init_completion(&host->xfer_done);
+
+ /* start the command first*/
+ if (msdc_command_start(host, cmd, 1, CMD_TIMEOUT) != 0)
+ goto done;
+
+ dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ (void)dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len, dir);
+ msdc_dma_setup(host, &host->dma, data->sg, data->sg_len);
+
+ /* then wait command done */
+ if (msdc_command_resp(host, cmd, 1, CMD_TIMEOUT) != 0)
+ goto done;
+
+ /* for read, the data coming too fast, then CRC error
+ start DMA no business with CRC. */
+ //init_completion(&host->xfer_done);
+ msdc_dma_start(host);
+
+ spin_unlock(&host->lock);
+ if(!wait_for_completion_timeout(&host->xfer_done, DAT_TIMEOUT)){
+ ERR_MSG("XXX CMD<%d> wait xfer_done<%d> timeout!!", cmd->opcode, data->blocks * data->blksz);
+ ERR_MSG(" DMA_SA = 0x%x", sdr_read32(MSDC_DMA_SA));
+ ERR_MSG(" DMA_CA = 0x%x", sdr_read32(MSDC_DMA_CA));
+ ERR_MSG(" DMA_CTRL = 0x%x", sdr_read32(MSDC_DMA_CTRL));
+ ERR_MSG(" DMA_CFG = 0x%x", sdr_read32(MSDC_DMA_CFG));
+ data->error = (unsigned int)-ETIMEDOUT;
+
+ msdc_reset();
+ msdc_clr_fifo();
+ msdc_clr_int();
+ }
+ spin_lock(&host->lock);
+ msdc_dma_stop(host);
+ } else {
+ /* Firstly: send command */
+ if (msdc_do_command(host, cmd, 1, CMD_TIMEOUT) != 0) {
+ goto done;
+ }
+
+ /* Secondly: pio data phase */
+ if (read) {
+ if (msdc_pio_read(host, data)){
+ goto done;
+ }
+ } else {
+ if (msdc_pio_write(host, data)) {
+ goto done;
+ }
+ }
+
+ /* For write case: make sure contents in fifo flushed to device */
+ if (!read) {
+ while (1) {
+ left=msdc_txfifocnt();
+ if (left == 0) {
+ break;
+ }
+ if (msdc_pio_abort(host, data, jiffies + DAT_TIMEOUT)) {
+ break;
+ /* Fix me: what about if data error, when stop ? how to? */
+ }
+ }
+ } else {
+ /* Fix me: read case: need to check CRC error */
+ }
+
+ /* For write case: SDCBUSY and Xfer_Comp will assert when DAT0 not busy.
+ For read case : SDCBUSY and Xfer_Comp will assert when last byte read out from FIFO.
+ */
+
+ /* try not to wait xfer_comp interrupt.
+ the next command will check SDC_BUSY.
+ SDC_BUSY means xfer_comp assert
+ */
+
+ } // PIO mode
+
+ /* Last: stop transfer */
+ if (data->stop){
+ if (msdc_do_command(host, data->stop, 0, CMD_TIMEOUT) != 0) {
+ goto done;
+ }
+ }
+ }
+
+done:
+ if (data != NULL) {
+ host->data = NULL;
+ host->dma_xfer = 0;
+ if (dma != 0) {
+ msdc_dma_off();
+ host->dma.used_bd = 0;
+ host->dma.used_gpd = 0;
+ dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len, dir);
+ }
+ host->blksz = 0;
+
+#if 0 // don't stop twice!
+ if(host->hw->flags & MSDC_REMOVABLE && data->error) {
+ msdc_abort_data(host);
+ /* reset in IRQ, stop command has issued. -> No need */
+ }
+#endif
+
+ N_MSG(OPS, "CMD<%d> data<%s %s> blksz<%d> block<%d> error<%d>",cmd->opcode, (dma? "dma":"pio"),
+ (read ? "read ":"write") ,data->blksz, data->blocks, data->error);
+ }
+
+#if 0 /* --- by chhung */
+#if 1
+ //if(host->id==1) {
+ if(send_type==SND_CMD) {
+ if(cmd->opcode == MMC_SEND_STATUS) {
+ if((cmd->resp[0] & CARD_READY_FOR_DATA) ||(CARD_CURRENT_STATE(cmd->resp[0]) != 7)){
+ N_MSG(OPS,"disable clock, CMD13 IDLE");
+ msdc_gate_clock(host->id);
+ }
+ } else {
+ N_MSG(OPS,"disable clock, CMD<%d>", cmd->opcode);
+ msdc_gate_clock(host->id);
+ }
+ } else {
+ if(read) {
+ N_MSG(OPS,"disable clock!!! Read CMD<%d>",cmd->opcode);
+ msdc_gate_clock(host->id);
+ }
+ }
+ //}
+#else
+ msdc_gate_clock(host->id);
+#endif
+#endif /* end of --- */
+
+ if (mrq->cmd->error) host->error = 0x001;
+ if (mrq->data && mrq->data->error) host->error |= 0x010;
+ if (mrq->stop && mrq->stop->error) host->error |= 0x100;
+
+ //if (host->error) ERR_MSG("host->error<%d>", host->error);
+
+ return host->error;
+}
+
+static int msdc_app_cmd(struct mmc_host *mmc, struct msdc_host *host)
+{
+ struct mmc_command cmd;
+ struct mmc_request mrq;
+ u32 err;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ cmd.opcode = MMC_APP_CMD;
+#if 0 /* bug: we meet mmc->card is null when ACMD6 */
+ cmd.arg = mmc->card->rca << 16;
+#else
+ cmd.arg = host->app_cmd_arg;
+#endif
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+ mrq.cmd = &cmd; cmd.mrq = &mrq;
+ cmd.data = NULL;
+
+ err = msdc_do_command(host, &cmd, 0, CMD_TIMEOUT);
+ return err;
+}
+
+static int msdc_tune_cmdrsp(struct msdc_host*host, struct mmc_command *cmd)
+{
+ int result = -1;
+ u32 base = host->base;
+ u32 rsmpl, cur_rsmpl, orig_rsmpl;
+ u32 rrdly, cur_rrdly = 0xffffffff, orig_rrdly;
+ u32 skip = 1;
+
+ /* ==== don't support 3.0 now ====
+ 1: R_SMPL[1]
+ 2: PAD_CMD_RESP_RXDLY[26:22]
+ ==========================*/
+
+ // save the previous tune result
+ sdr_get_field(MSDC_IOCON, MSDC_IOCON_RSPL, orig_rsmpl);
+ sdr_get_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRRDLY, orig_rrdly);
+
+ rrdly = 0;
+ do {
+ for (rsmpl = 0; rsmpl < 2; rsmpl++) {
+ /* Lv1: R_SMPL[1] */
+ cur_rsmpl = (orig_rsmpl + rsmpl) % 2;
+ if (skip == 1) {
+ skip = 0;
+ continue;
+ }
+ sdr_set_field(MSDC_IOCON, MSDC_IOCON_RSPL, cur_rsmpl);
+
+ if (host->app_cmd) {
+ result = msdc_app_cmd(host->mmc, host);
+ if (result) {
+ ERR_MSG("TUNE_CMD app_cmd<%d> failed: RESP_RXDLY<%d>,R_SMPL<%d>",
+ host->mrq->cmd->opcode, cur_rrdly, cur_rsmpl);
+ continue;
+ }
+ }
+ result = msdc_do_command(host, cmd, 0, CMD_TIMEOUT); // not tune.
+ ERR_MSG("TUNE_CMD<%d> %s PAD_CMD_RESP_RXDLY[26:22]<%d> R_SMPL[1]<%d>", cmd->opcode,
+ (result == 0) ? "PASS" : "FAIL", cur_rrdly, cur_rsmpl);
+
+ if (result == 0) {
+ return 0;
+ }
+ if (result != (unsigned int)(-EIO)) {
+ ERR_MSG("TUNE_CMD<%d> Error<%d> not -EIO", cmd->opcode, result);
+ return result;
+ }
+
+ /* should be EIO */
+ if (sdr_read32(SDC_CMD) & 0x1800) { /* check if has data phase */
+ msdc_abort_data(host);
+ }
+ }
+
+ /* Lv2: PAD_CMD_RESP_RXDLY[26:22] */
+ cur_rrdly = (orig_rrdly + rrdly + 1) % 32;
+ sdr_set_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRRDLY, cur_rrdly);
+ }while (++rrdly < 32);
+
+ return result;
+}
+
+/* Support SD2.0 Only */
+static int msdc_tune_bread(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+ u32 base = host->base;
+ u32 ddr=0;
+ u32 dcrc=0;
+ u32 rxdly, cur_rxdly0, cur_rxdly1;
+ u32 dsmpl, cur_dsmpl, orig_dsmpl;
+ u32 cur_dat0, cur_dat1, cur_dat2, cur_dat3;
+ u32 cur_dat4, cur_dat5, cur_dat6, cur_dat7;
+ u32 orig_dat0, orig_dat1, orig_dat2, orig_dat3;
+ u32 orig_dat4, orig_dat5, orig_dat6, orig_dat7;
+ int result = -1;
+ u32 skip = 1;
+
+ sdr_get_field(MSDC_IOCON, MSDC_IOCON_DSPL, orig_dsmpl);
+
+ /* Tune Method 2. */
+ sdr_set_field(MSDC_IOCON, MSDC_IOCON_DDLSEL, 1);
+
+ rxdly = 0;
+ do {
+ for (dsmpl = 0; dsmpl < 2; dsmpl++) {
+ cur_dsmpl = (orig_dsmpl + dsmpl) % 2;
+ if (skip == 1) {
+ skip = 0;
+ continue;
+ }
+ sdr_set_field(MSDC_IOCON, MSDC_IOCON_DSPL, cur_dsmpl);
+
+ if (host->app_cmd) {
+ result = msdc_app_cmd(host->mmc, host);
+ if (result) {
+ ERR_MSG("TUNE_BREAD app_cmd<%d> failed", host->mrq->cmd->opcode);
+ continue;
+ }
+ }
+ result = msdc_do_request(mmc,mrq);
+
+ sdr_get_field(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc); /* RO */
+ if (!ddr) dcrc &= ~SDC_DCRC_STS_NEG;
+ ERR_MSG("TUNE_BREAD<%s> dcrc<0x%x> DATRDDLY0/1<0x%x><0x%x> dsmpl<0x%x>",
+ (result == 0 && dcrc == 0) ? "PASS" : "FAIL", dcrc,
+ sdr_read32(MSDC_DAT_RDDLY0), sdr_read32(MSDC_DAT_RDDLY1), cur_dsmpl);
+
+ /* Fix me: result is 0, but dcrc is still exist */
+ if (result == 0 && dcrc == 0) {
+ goto done;
+ } else {
+ /* there is a case: command timeout, and data phase not processed */
+ if (mrq->data->error != 0 && mrq->data->error != (unsigned int)(-EIO)) {
+ ERR_MSG("TUNE_READ: result<0x%x> cmd_error<%d> data_error<%d>",
+ result, mrq->cmd->error, mrq->data->error);
+ goto done;
+ }
+ }
+ }
+
+ cur_rxdly0 = sdr_read32(MSDC_DAT_RDDLY0);
+ cur_rxdly1 = sdr_read32(MSDC_DAT_RDDLY1);
+
+ /* E1 ECO. YD: Reverse */
+ if (sdr_read32(MSDC_ECO_VER) >= 4) {
+ orig_dat0 = (cur_rxdly0 >> 24) & 0x1F;
+ orig_dat1 = (cur_rxdly0 >> 16) & 0x1F;
+ orig_dat2 = (cur_rxdly0 >> 8) & 0x1F;
+ orig_dat3 = (cur_rxdly0 >> 0) & 0x1F;
+ orig_dat4 = (cur_rxdly1 >> 24) & 0x1F;
+ orig_dat5 = (cur_rxdly1 >> 16) & 0x1F;
+ orig_dat6 = (cur_rxdly1 >> 8) & 0x1F;
+ orig_dat7 = (cur_rxdly1 >> 0) & 0x1F;
+ } else {
+ orig_dat0 = (cur_rxdly0 >> 0) & 0x1F;
+ orig_dat1 = (cur_rxdly0 >> 8) & 0x1F;
+ orig_dat2 = (cur_rxdly0 >> 16) & 0x1F;
+ orig_dat3 = (cur_rxdly0 >> 24) & 0x1F;
+ orig_dat4 = (cur_rxdly1 >> 0) & 0x1F;
+ orig_dat5 = (cur_rxdly1 >> 8) & 0x1F;
+ orig_dat6 = (cur_rxdly1 >> 16) & 0x1F;
+ orig_dat7 = (cur_rxdly1 >> 24) & 0x1F;
+ }
+
+ if (ddr) {
+ cur_dat0 = (dcrc & (1 << 0) || dcrc & (1 << 8)) ? ((orig_dat0 + 1) % 32) : orig_dat0;
+ cur_dat1 = (dcrc & (1 << 1) || dcrc & (1 << 9)) ? ((orig_dat1 + 1) % 32) : orig_dat1;
+ cur_dat2 = (dcrc & (1 << 2) || dcrc & (1 << 10)) ? ((orig_dat2 + 1) % 32) : orig_dat2;
+ cur_dat3 = (dcrc & (1 << 3) || dcrc & (1 << 11)) ? ((orig_dat3 + 1) % 32) : orig_dat3;
+ } else {
+ cur_dat0 = (dcrc & (1 << 0)) ? ((orig_dat0 + 1) % 32) : orig_dat0;
+ cur_dat1 = (dcrc & (1 << 1)) ? ((orig_dat1 + 1) % 32) : orig_dat1;
+ cur_dat2 = (dcrc & (1 << 2)) ? ((orig_dat2 + 1) % 32) : orig_dat2;
+ cur_dat3 = (dcrc & (1 << 3)) ? ((orig_dat3 + 1) % 32) : orig_dat3;
+ }
+ cur_dat4 = (dcrc & (1 << 4)) ? ((orig_dat4 + 1) % 32) : orig_dat4;
+ cur_dat5 = (dcrc & (1 << 5)) ? ((orig_dat5 + 1) % 32) : orig_dat5;
+ cur_dat6 = (dcrc & (1 << 6)) ? ((orig_dat6 + 1) % 32) : orig_dat6;
+ cur_dat7 = (dcrc & (1 << 7)) ? ((orig_dat7 + 1) % 32) : orig_dat7;
+
+ cur_rxdly0 = (cur_dat0 << 24) | (cur_dat1 << 16) | (cur_dat2 << 8) | (cur_dat3 << 0);
+ cur_rxdly1 = (cur_dat4 << 24) | (cur_dat5 << 16) | (cur_dat6 << 8) | (cur_dat7 << 0);
+
+ sdr_write32(MSDC_DAT_RDDLY0, cur_rxdly0);
+ sdr_write32(MSDC_DAT_RDDLY1, cur_rxdly1);
+
+ } while (++rxdly < 32);
+
+done:
+ return result;
+}
+
+static int msdc_tune_bwrite(struct mmc_host *mmc,struct mmc_request *mrq)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+ u32 base = host->base;
+
+ u32 wrrdly, cur_wrrdly = 0xffffffff, orig_wrrdly;
+ u32 dsmpl, cur_dsmpl, orig_dsmpl;
+ u32 rxdly, cur_rxdly0;
+ u32 orig_dat0, orig_dat1, orig_dat2, orig_dat3;
+ u32 cur_dat0, cur_dat1, cur_dat2, cur_dat3;
+ int result = -1;
+ u32 skip = 1;
+
+ // MSDC_IOCON_DDR50CKD need to check. [Fix me]
+
+ sdr_get_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, orig_wrrdly);
+ sdr_get_field(MSDC_IOCON, MSDC_IOCON_DSPL, orig_dsmpl );
+
+ /* Tune Method 2. just DAT0 */
+ sdr_set_field(MSDC_IOCON, MSDC_IOCON_DDLSEL, 1);
+ cur_rxdly0 = sdr_read32(MSDC_DAT_RDDLY0);
+
+ /* E1 ECO. YD: Reverse */
+ if (sdr_read32(MSDC_ECO_VER) >= 4) {
+ orig_dat0 = (cur_rxdly0 >> 24) & 0x1F;
+ orig_dat1 = (cur_rxdly0 >> 16) & 0x1F;
+ orig_dat2 = (cur_rxdly0 >> 8) & 0x1F;
+ orig_dat3 = (cur_rxdly0 >> 0) & 0x1F;
+ } else {
+ orig_dat0 = (cur_rxdly0 >> 0) & 0x1F;
+ orig_dat1 = (cur_rxdly0 >> 8) & 0x1F;
+ orig_dat2 = (cur_rxdly0 >> 16) & 0x1F;
+ orig_dat3 = (cur_rxdly0 >> 24) & 0x1F;
+ }
+
+ rxdly = 0;
+ do {
+ wrrdly = 0;
+ do {
+ for (dsmpl = 0; dsmpl < 2; dsmpl++) {
+ cur_dsmpl = (orig_dsmpl + dsmpl) % 2;
+ if (skip == 1) {
+ skip = 0;
+ continue;
+ }
+ sdr_set_field(MSDC_IOCON, MSDC_IOCON_DSPL, cur_dsmpl);
+
+ if (host->app_cmd) {
+ result = msdc_app_cmd(host->mmc, host);
+ if (result) {
+ ERR_MSG("TUNE_BWRITE app_cmd<%d> failed", host->mrq->cmd->opcode);
+ continue;
+ }
+ }
+ result = msdc_do_request(mmc,mrq);
+
+ ERR_MSG("TUNE_BWRITE<%s> DSPL<%d> DATWRDLY<%d> MSDC_DAT_RDDLY0<0x%x>",
+ result == 0 ? "PASS" : "FAIL",
+ cur_dsmpl, cur_wrrdly, cur_rxdly0);
+
+ if (result == 0) {
+ goto done;
+ }
+ else {
+ /* there is a case: command timeout, and data phase not processed */
+ if (mrq->data->error != (unsigned int)(-EIO)) {
+ ERR_MSG("TUNE_READ: result<0x%x> cmd_error<%d> data_error<%d>",
+ result, mrq->cmd->error, mrq->data->error);
+ goto done;
+ }
+ }
+ }
+ cur_wrrdly = (orig_wrrdly + wrrdly + 1) % 32;
+ sdr_set_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, cur_wrrdly);
+ } while (++wrrdly < 32);
+
+ cur_dat0 = (orig_dat0 + rxdly) % 32; /* only adjust bit-1 for crc */
+ cur_dat1 = orig_dat1;
+ cur_dat2 = orig_dat2;
+ cur_dat3 = orig_dat3;
+
+ cur_rxdly0 = (cur_dat0 << 24) | (cur_dat1 << 16) | (cur_dat2 << 8) | (cur_dat3 << 0);
+ sdr_write32(MSDC_DAT_RDDLY0, cur_rxdly0);
+ } while (++rxdly < 32);
+
+done:
+ return result;
+}
+
+static int msdc_get_card_status(struct mmc_host *mmc, struct msdc_host *host, u32 *status)
+{
+ struct mmc_command cmd;
+ struct mmc_request mrq;
+ u32 err;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ cmd.opcode = MMC_SEND_STATUS;
+ if (mmc->card) {
+ cmd.arg = mmc->card->rca << 16;
+ } else {
+ ERR_MSG("cmd13 mmc card is null");
+ cmd.arg = host->app_cmd_arg;
+ }
+ cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+ mrq.cmd = &cmd; cmd.mrq = &mrq;
+ cmd.data = NULL;
+
+ err = msdc_do_command(host, &cmd, 1, CMD_TIMEOUT);
+
+ if (status) {
+ *status = cmd.resp[0];
+ }
+
+ return err;
+}
+
+static int msdc_check_busy(struct mmc_host *mmc, struct msdc_host *host)
+{
+ u32 err = 0;
+ u32 status = 0;
+
+ do {
+ err = msdc_get_card_status(mmc, host, &status);
+ if (err) return err;
+ /* need cmd12? */
+ ERR_MSG("cmd<13> resp<0x%x>", status);
+ } while (R1_CURRENT_STATE(status) == 7);
+
+ return err;
+}
+
+/* failed when msdc_do_request */
+static int msdc_tune_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ //u32 base = host->base;
+ int ret=0, read;
+
+ cmd = mrq->cmd;
+ data = mrq->cmd->data;
+
+ read = data->flags & MMC_DATA_READ ? 1 : 0;
+
+ if (read) {
+ if (data->error == (unsigned int)(-EIO)) {
+ ret = msdc_tune_bread(mmc,mrq);
+ }
+ } else {
+ ret = msdc_check_busy(mmc, host);
+ if (ret){
+ ERR_MSG("XXX cmd13 wait program done failed");
+ return ret;
+ }
+ /* CRC and TO */
+ /* Fix me: don't care card status? */
+ ret = msdc_tune_bwrite(mmc,mrq);
+ }
+
+ return ret;
+}
+
+/* ops.request */
+static void msdc_ops_request(struct mmc_host *mmc,struct mmc_request *mrq)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+
+ //=== for sdio profile ===
+#if 0 /* --- by chhung */
+ u32 old_H32, old_L32, new_H32, new_L32;
+ u32 ticks = 0, opcode = 0, sizes = 0, bRx = 0;
+#endif /* end of --- */
+
+ if(host->mrq){
+ ERR_MSG("XXX host->mrq<0x%.8x>", (int)host->mrq);
+ BUG();
+ }
+
+ if (!is_card_present(host) || host->power_mode == MMC_POWER_OFF) {
+ ERR_MSG("cmd<%d> card<%d> power<%d>", mrq->cmd->opcode, is_card_present(host), host->power_mode);
+ mrq->cmd->error = (unsigned int)-ENOMEDIUM;
+
+#if 1
+ mrq->done(mrq); // call done directly.
+#else
+ mrq->cmd->retries = 0; // please don't retry.
+ mmc_request_done(mmc, mrq);
+#endif
+
+ return;
+ }
+
+ /* start to process */
+ spin_lock(&host->lock);
+#if 0 /* --- by chhung */
+ if (sdio_pro_enable) { //=== for sdio profile ===
+ if (mrq->cmd->opcode == 52 || mrq->cmd->opcode == 53) {
+ GPT_GetCounter64(&old_L32, &old_H32);
+ }
+ }
+#endif /* end of --- */
+
+ host->mrq = mrq;
+
+ if (msdc_do_request(mmc,mrq)) {
+ if(host->hw->flags & MSDC_REMOVABLE && ralink_soc == MT762X_SOC_MT7621AT && mrq->data && mrq->data->error) {
+ msdc_tune_request(mmc,mrq);
+ }
+ }
+
+ /* ==== when request done, check if app_cmd ==== */
+ if (mrq->cmd->opcode == MMC_APP_CMD) {
+ host->app_cmd = 1;
+ host->app_cmd_arg = mrq->cmd->arg; /* save the RCA */
+ } else {
+ host->app_cmd = 0;
+ //host->app_cmd_arg = 0;
+ }
+
+ host->mrq = NULL;
+
+#if 0 /* --- by chhung */
+ //=== for sdio profile ===
+ if (sdio_pro_enable) {
+ if (mrq->cmd->opcode == 52 || mrq->cmd->opcode == 53) {
+ GPT_GetCounter64(&new_L32, &new_H32);
+ ticks = msdc_time_calc(old_L32, old_H32, new_L32, new_H32);
+
+ opcode = mrq->cmd->opcode;
+ if (mrq->cmd->data) {
+ sizes = mrq->cmd->data->blocks * mrq->cmd->data->blksz;
+ bRx = mrq->cmd->data->flags & MMC_DATA_READ ? 1 : 0 ;
+ } else {
+ bRx = mrq->cmd->arg & 0x80000000 ? 1 : 0;
+ }
+
+ if (!mrq->cmd->error) {
+ msdc_performance(opcode, sizes, bRx, ticks);
+ }
+ }
+ }
+#endif /* end of --- */
+ spin_unlock(&host->lock);
+
+ mmc_request_done(mmc, mrq);
+
+ return;
+}
+
+/* called by ops.set_ios */
+static void msdc_set_buswidth(struct msdc_host *host, u32 width)
+{
+ u32 base = host->base;
+ u32 val = sdr_read32(SDC_CFG);
+
+ val &= ~SDC_CFG_BUSWIDTH;
+
+ switch (width) {
+ default:
+ case MMC_BUS_WIDTH_1:
+ width = 1;
+ val |= (MSDC_BUS_1BITS << 16);
+ break;
+ case MMC_BUS_WIDTH_4:
+ val |= (MSDC_BUS_4BITS << 16);
+ break;
+ case MMC_BUS_WIDTH_8:
+ val |= (MSDC_BUS_8BITS << 16);
+ break;
+ }
+
+ sdr_write32(SDC_CFG, val);
+
+ N_MSG(CFG, "Bus Width = %d", width);
+}
+
+/* ops.set_ios */
+static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+ struct msdc_hw *hw=host->hw;
+ u32 base = host->base;
+ u32 ddr = 0;
+
+#ifdef MT6575_SD_DEBUG
+ static char *vdd[] = {
+ "1.50v", "1.55v", "1.60v", "1.65v", "1.70v", "1.80v", "1.90v",
+ "2.00v", "2.10v", "2.20v", "2.30v", "2.40v", "2.50v", "2.60v",
+ "2.70v", "2.80v", "2.90v", "3.00v", "3.10v", "3.20v", "3.30v",
+ "3.40v", "3.50v", "3.60v"
+ };
+ static char *power_mode[] = {
+ "OFF", "UP", "ON"
+ };
+ static char *bus_mode[] = {
+ "UNKNOWN", "OPENDRAIN", "PUSHPULL"
+ };
+ static char *timing[] = {
+ "LEGACY", "MMC_HS", "SD_HS"
+ };
+
+ printk("SET_IOS: CLK(%dkHz), BUS(%s), BW(%u), PWR(%s), VDD(%s), TIMING(%s)",
+ ios->clock / 1000, bus_mode[ios->bus_mode],
+ (ios->bus_width == MMC_BUS_WIDTH_4) ? 4 : 1,
+ power_mode[ios->power_mode], vdd[ios->vdd], timing[ios->timing]);
+#endif
+
+ msdc_set_buswidth(host, ios->bus_width);
+
+ /* Power control ??? */
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ case MMC_POWER_UP:
+ // msdc_set_power_mode(host, ios->power_mode); /* --- by chhung */
+ break;
+ case MMC_POWER_ON:
+ host->power_mode = MMC_POWER_ON;
+ break;
+ default:
+ break;
+ }
+
+ /* Clock control */
+ if (host->mclk != ios->clock) {
+ if(ios->clock > 25000000) {
+ //if (!(host->hw->flags & MSDC_REMOVABLE)) {
+ INIT_MSG("SD data latch edge<%d>", hw->data_edge);
+ sdr_set_field(MSDC_IOCON, MSDC_IOCON_RSPL, hw->cmd_edge);
+ sdr_set_field(MSDC_IOCON, MSDC_IOCON_DSPL, hw->data_edge);
+ //} /* for tuning debug */
+ } else { /* default value */
+ sdr_write32(MSDC_IOCON, 0x00000000);
+ // sdr_write32(MSDC_DAT_RDDLY0, 0x00000000);
+ sdr_write32(MSDC_DAT_RDDLY0, 0x10101010); // for MT7620 E2 and afterward
+ sdr_write32(MSDC_DAT_RDDLY1, 0x00000000);
+ // sdr_write32(MSDC_PAD_TUNE, 0x00000000);
+ sdr_write32(MSDC_PAD_TUNE, 0x84101010); // for MT7620 E2 and afterward
+ }
+ msdc_set_mclk(host, ddr, ios->clock);
+ }
+}
+
+/* ops.get_ro */
+static int msdc_ops_get_ro(struct mmc_host *mmc)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+ u32 base = host->base;
+ unsigned long flags;
+ int ro = 0;
+
+ if (host->hw->flags & MSDC_WP_PIN_EN) { /* set for card */
+ spin_lock_irqsave(&host->lock, flags);
+ ro = (sdr_read32(MSDC_PS) >> 31);
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+ return ro;
+}
+
+/* ops.get_cd */
+static int msdc_ops_get_cd(struct mmc_host *mmc)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+ u32 base = host->base;
+ unsigned long flags;
+ int present = 1;
+
+ /* for sdio, MSDC_REMOVABLE not set, always return 1 */
+ if (!(host->hw->flags & MSDC_REMOVABLE)) {
+ /* For sdio, read H/W always get<1>, but may timeout some times */
+#if 1
+ host->card_inserted = 1;
+ return 1;
+#else
+ host->card_inserted = (host->pm_state.event == PM_EVENT_USER_RESUME) ? 1 : 0;
+ INIT_MSG("sdio ops_get_cd<%d>", host->card_inserted);
+ return host->card_inserted;
+#endif
+ }
+
+ /* MSDC_CD_PIN_EN set for card */
+ if (host->hw->flags & MSDC_CD_PIN_EN) {
+ spin_lock_irqsave(&host->lock, flags);
+#if 0
+ present = host->card_inserted; /* why not read from H/W: Fix me*/
+#else
+ // CD
+ if (cd_active_low)
+ present = (sdr_read32(MSDC_PS) & MSDC_PS_CDSTS) ? 0 : 1;
+ else
+ present = (sdr_read32(MSDC_PS) & MSDC_PS_CDSTS) ? 1 : 0;
+ host->card_inserted = present;
+#endif
+ spin_unlock_irqrestore(&host->lock, flags);
+ } else {
+ present = 0; /* TODO? Check DAT3 pins for card detection */
+ }
+
+ INIT_MSG("ops_get_cd return<%d>", present);
+ return present;
+}
+
+/* ops.enable_sdio_irq */
+static void msdc_ops_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct msdc_host *host = mmc_priv(mmc);
+ struct msdc_hw *hw = host->hw;
+ u32 base = host->base;
+ u32 tmp;
+
+ if (hw->flags & MSDC_EXT_SDIO_IRQ) { /* yes for sdio */
+ if (enable) {
+ hw->enable_sdio_eirq(); /* combo_sdio_enable_eirq */
+ } else {
+ hw->disable_sdio_eirq(); /* combo_sdio_disable_eirq */
+ }
+ } else {
+ ERR_MSG("XXX "); /* so never enter here */
+ tmp = sdr_read32(SDC_CFG);
+ /* FIXME. Need to interrupt gap detection */
+ if (enable) {
+ tmp |= (SDC_CFG_SDIOIDE | SDC_CFG_SDIOINTWKUP);
+ } else {
+ tmp &= ~(SDC_CFG_SDIOIDE | SDC_CFG_SDIOINTWKUP);
+ }
+ sdr_write32(SDC_CFG, tmp);
+ }
+}
+
+static struct mmc_host_ops mt_msdc_ops = {
+ .request = msdc_ops_request,
+ .set_ios = msdc_ops_set_ios,
+ .get_ro = msdc_ops_get_ro,
+ .get_cd = msdc_ops_get_cd,
+ .enable_sdio_irq = msdc_ops_enable_sdio_irq,
+};
+
+/*--------------------------------------------------------------------------*/
+/* interrupt handler */
+/*--------------------------------------------------------------------------*/
+static irqreturn_t msdc_irq(int irq, void *dev_id)
+{
+ struct msdc_host *host = (struct msdc_host *)dev_id;
+ struct mmc_data *data = host->data;
+ struct mmc_command *cmd = host->cmd;
+ u32 base = host->base;
+
+ u32 cmdsts = MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO | MSDC_INT_CMDRDY |
+ MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO | MSDC_INT_ACMDRDY |
+ MSDC_INT_ACMD19_DONE;
+ u32 datsts = MSDC_INT_DATCRCERR |MSDC_INT_DATTMO;
+
+ u32 intsts = sdr_read32(MSDC_INT);
+ u32 inten = sdr_read32(MSDC_INTEN); inten &= intsts;
+
+ sdr_write32(MSDC_INT, intsts); /* clear interrupts */
+ /* MSG will cause fatal error */
+
+ /* card change interrupt */
+ if (intsts & MSDC_INT_CDSC){
+ if (mtk_sw_poll)
+ return IRQ_HANDLED;
+ IRQ_MSG("MSDC_INT_CDSC irq<0x%.8x>", intsts);
+#if 0 /* ---/+++ by chhung: fix slot mechanical bounce issue */
+ tasklet_hi_schedule(&host->card_tasklet);
+#else
+ schedule_delayed_work(&host->card_delaywork, HZ);
+#endif
+ /* tuning when plug card ? */
+ }
+
+ /* sdio interrupt */
+ if (intsts & MSDC_INT_SDIOIRQ){
+ IRQ_MSG("XXX MSDC_INT_SDIOIRQ"); /* seems not sdio irq */
+ //mmc_signal_sdio_irq(host->mmc);
+ }
+
+ /* transfer complete interrupt */
+ if (data != NULL) {
+ if (inten & MSDC_INT_XFER_COMPL) {
+ data->bytes_xfered = host->dma.xfersz;
+ complete(&host->xfer_done);
+ }
+
+ if (intsts & datsts) {
+ /* do basic reset, or stop command will sdc_busy */
+ msdc_reset();
+ msdc_clr_fifo();
+ msdc_clr_int();
+ atomic_set(&host->abort, 1); /* For PIO mode exit */
+
+ if (intsts & MSDC_INT_DATTMO){
+ IRQ_MSG("XXX CMD<%d> MSDC_INT_DATTMO", host->mrq->cmd->opcode);
+ data->error = (unsigned int)-ETIMEDOUT;
+ }
+ else if (intsts & MSDC_INT_DATCRCERR){
+ IRQ_MSG("XXX CMD<%d> MSDC_INT_DATCRCERR, SDC_DCRC_STS<0x%x>", host->mrq->cmd->opcode, sdr_read32(SDC_DCRC_STS));
+ data->error = (unsigned int)-EIO;
+ }
+
+ //if(sdr_read32(MSDC_INTEN) & MSDC_INT_XFER_COMPL) {
+ if (host->dma_xfer) {
+ complete(&host->xfer_done); /* Read CRC come fast, XFER_COMPL not enabled */
+ } /* PIO mode can't do complete, because not init */
+ }
+ }
+
+ /* command interrupts */
+ if ((cmd != NULL) && (intsts & cmdsts)) {
+ if ((intsts & MSDC_INT_CMDRDY) || (intsts & MSDC_INT_ACMDRDY) ||
+ (intsts & MSDC_INT_ACMD19_DONE)) {
+ u32 *rsp = &cmd->resp[0];
+
+ switch (host->cmd_rsp) {
+ case RESP_NONE:
+ break;
+ case RESP_R2:
+ *rsp++ = sdr_read32(SDC_RESP3); *rsp++ = sdr_read32(SDC_RESP2);
+ *rsp++ = sdr_read32(SDC_RESP1); *rsp++ = sdr_read32(SDC_RESP0);
+ break;
+ default: /* Response types 1, 3, 4, 5, 6, 7(1b) */
+ if ((intsts & MSDC_INT_ACMDRDY) || (intsts & MSDC_INT_ACMD19_DONE)) {
+ *rsp = sdr_read32(SDC_ACMD_RESP);
+ } else {
+ *rsp = sdr_read32(SDC_RESP0);
+ }
+ break;
+ }
+ } else if ((intsts & MSDC_INT_RSPCRCERR) || (intsts & MSDC_INT_ACMDCRCERR)) {
+ if(intsts & MSDC_INT_ACMDCRCERR){
+ IRQ_MSG("XXX CMD<%d> MSDC_INT_ACMDCRCERR",cmd->opcode);
+ }
+ else {
+ IRQ_MSG("XXX CMD<%d> MSDC_INT_RSPCRCERR",cmd->opcode);
+ }
+ cmd->error = (unsigned int)-EIO;
+ } else if ((intsts & MSDC_INT_CMDTMO) || (intsts & MSDC_INT_ACMDTMO)) {
+ if(intsts & MSDC_INT_ACMDTMO){
+ IRQ_MSG("XXX CMD<%d> MSDC_INT_ACMDTMO",cmd->opcode);
+ }
+ else {
+ IRQ_MSG("XXX CMD<%d> MSDC_INT_CMDTMO",cmd->opcode);
+ }
+ cmd->error = (unsigned int)-ETIMEDOUT;
+ msdc_reset();
+ msdc_clr_fifo();
+ msdc_clr_int();
+ }
+ complete(&host->cmd_done);
+ }
+
+ /* mmc irq interrupts */
+ if (intsts & MSDC_INT_MMCIRQ) {
+ printk(KERN_INFO "msdc[%d] MMCIRQ: SDC_CSTS=0x%.8x\r\n", host->id, sdr_read32(SDC_CSTS));
+ }
+
+#ifdef MT6575_SD_DEBUG
+ {
+/* msdc_int_reg *int_reg = (msdc_int_reg*)&intsts;*/
+ N_MSG(INT, "IRQ_EVT(0x%x): MMCIRQ(%d) CDSC(%d), ACRDY(%d), ACTMO(%d), ACCRE(%d) AC19DN(%d)",
+ intsts,
+ int_reg->mmcirq,
+ int_reg->cdsc,
+ int_reg->atocmdrdy,
+ int_reg->atocmdtmo,
+ int_reg->atocmdcrc,
+ int_reg->atocmd19done);
+ N_MSG(INT, "IRQ_EVT(0x%x): SDIO(%d) CMDRDY(%d), CMDTMO(%d), RSPCRC(%d), CSTA(%d)",
+ intsts,
+ int_reg->sdioirq,
+ int_reg->cmdrdy,
+ int_reg->cmdtmo,
+ int_reg->rspcrc,
+ int_reg->csta);
+ N_MSG(INT, "IRQ_EVT(0x%x): XFCMP(%d) DXDONE(%d), DATTMO(%d), DATCRC(%d), DMAEMP(%d)",
+ intsts,
+ int_reg->xfercomp,
+ int_reg->dxferdone,
+ int_reg->dattmo,
+ int_reg->datcrc,
+ int_reg->dmaqempty);
+
+ }
+#endif
+
+ return IRQ_HANDLED;
+}
+
+/*--------------------------------------------------------------------------*/
+/* platform_driver members */
+/*--------------------------------------------------------------------------*/
+/* called by msdc_drv_probe/remove */
+static void msdc_enable_cd_irq(struct msdc_host *host, int enable)
+{
+ struct msdc_hw *hw = host->hw;
+ u32 base = host->base;
+
+ /* for sdio, not set */
+ if ((hw->flags & MSDC_CD_PIN_EN) == 0) {
+ /* Pull down card detection pin since it is not avaiable */
+ /*
+ if (hw->config_gpio_pin)
+ hw->config_gpio_pin(MSDC_CD_PIN, GPIO_PULL_DOWN);
+ */
+ sdr_clr_bits(MSDC_PS, MSDC_PS_CDEN);
+ sdr_clr_bits(MSDC_INTEN, MSDC_INTEN_CDSC);
+ sdr_clr_bits(SDC_CFG, SDC_CFG_INSWKUP);
+ return;
+ }
+
+ N_MSG(CFG, "CD IRQ Eanable(%d)", enable);
+
+ if (enable) {
+ if (hw->enable_cd_eirq) { /* not set, never enter */
+ hw->enable_cd_eirq();
+ } else {
+ /* card detection circuit relies on the core power so that the core power
+ * shouldn't be turned off. Here adds a reference count to keep
+ * the core power alive.
+ */
+ //msdc_vcore_on(host); //did in msdc_init_hw()
+
+ if (hw->config_gpio_pin) /* NULL */
+ hw->config_gpio_pin(MSDC_CD_PIN, GPIO_PULL_UP);
+
+ sdr_set_field(MSDC_PS, MSDC_PS_CDDEBOUNCE, DEFAULT_DEBOUNCE);
+ sdr_set_bits(MSDC_PS, MSDC_PS_CDEN);
+ sdr_set_bits(MSDC_INTEN, MSDC_INTEN_CDSC);
+ sdr_set_bits(SDC_CFG, SDC_CFG_INSWKUP); /* not in document! Fix me */
+ }
+ } else {
+ if (hw->disable_cd_eirq) {
+ hw->disable_cd_eirq();
+ } else {
+ if (hw->config_gpio_pin) /* NULL */
+ hw->config_gpio_pin(MSDC_CD_PIN, GPIO_PULL_DOWN);
+
+ sdr_clr_bits(SDC_CFG, SDC_CFG_INSWKUP);
+ sdr_clr_bits(MSDC_PS, MSDC_PS_CDEN);
+ sdr_clr_bits(MSDC_INTEN, MSDC_INTEN_CDSC);
+
+ /* Here decreases a reference count to core power since card
+ * detection circuit is shutdown.
+ */
+ //msdc_vcore_off(host);
+ }
+ }
+}
+
+/* called by msdc_drv_probe */
+static void msdc_init_hw(struct msdc_host *host)
+{
+ u32 base = host->base;
+ struct msdc_hw *hw = host->hw;
+
+#ifdef MT6575_SD_DEBUG
+ msdc_reg[host->id] = (struct msdc_regs *)host->base;
+#endif
+
+ /* Power on */
+#if 0 /* --- by chhung */
+ msdc_vcore_on(host);
+ msdc_pin_reset(host, MSDC_PIN_PULL_UP);
+ msdc_select_clksrc(host, hw->clk_src);
+ enable_clock(PERI_MSDC0_PDN + host->id, "SD");
+ msdc_vdd_on(host);
+#endif /* end of --- */
+ /* Configure to MMC/SD mode */
+ sdr_set_field(MSDC_CFG, MSDC_CFG_MODE, MSDC_SDMMC);
+
+ /* Reset */
+ msdc_reset();
+ msdc_clr_fifo();
+
+ /* Disable card detection */
+ sdr_clr_bits(MSDC_PS, MSDC_PS_CDEN);
+
+ /* Disable and clear all interrupts */
+ sdr_clr_bits(MSDC_INTEN, sdr_read32(MSDC_INTEN));
+ sdr_write32(MSDC_INT, sdr_read32(MSDC_INT));
+
+#if 1
+ /* reset tuning parameter */
+ sdr_write32(MSDC_PAD_CTL0, 0x00090000);
+ sdr_write32(MSDC_PAD_CTL1, 0x000A0000);
+ sdr_write32(MSDC_PAD_CTL2, 0x000A0000);
+ // sdr_write32(MSDC_PAD_TUNE, 0x00000000);
+ sdr_write32(MSDC_PAD_TUNE, 0x84101010); // for MT7620 E2 and afterward
+ // sdr_write32(MSDC_DAT_RDDLY0, 0x00000000);
+ sdr_write32(MSDC_DAT_RDDLY0, 0x10101010); // for MT7620 E2 and afterward
+ sdr_write32(MSDC_DAT_RDDLY1, 0x00000000);
+ sdr_write32(MSDC_IOCON, 0x00000000);
+#if 0 // use MT7620 default value: 0x403c004f
+ sdr_write32(MSDC_PATCH_BIT0, 0x003C000F); /* bit0 modified: Rx Data Clock Source: 1 -> 2.0*/
+#endif
+
+ if (sdr_read32(MSDC_ECO_VER) >= 4) {
+ if (host->id == 1) {
+ sdr_set_field(MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_WRDAT_CRCS, 1);
+ sdr_set_field(MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_CMD_RSP, 1);
+
+ /* internal clock: latch read data */
+ sdr_set_bits(MSDC_PATCH_BIT0, MSDC_PATCH_BIT_CKGEN_CK);
+ }
+ }
+#endif
+
+ /* for safety, should clear SDC_CFG.SDIO_INT_DET_EN & set SDC_CFG.SDIO in
+ pre-loader,uboot,kernel drivers. and SDC_CFG.SDIO_INT_DET_EN will be only
+ set when kernel driver wants to use SDIO bus interrupt */
+ /* Configure to enable SDIO mode. it's must otherwise sdio cmd5 failed */
+ sdr_set_bits(SDC_CFG, SDC_CFG_SDIO);
+
+ /* disable detect SDIO device interupt function */
+ sdr_clr_bits(SDC_CFG, SDC_CFG_SDIOIDE);
+
+ /* eneable SMT for glitch filter */
+ sdr_set_bits(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKSMT);
+ sdr_set_bits(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDSMT);
+ sdr_set_bits(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATSMT);
+
+#if 1
+ /* set clk, cmd, dat pad driving */
+ sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVN, hw->clk_drv);
+ sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVP, hw->clk_drv);
+ sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVN, hw->cmd_drv);
+ sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVP, hw->cmd_drv);
+ sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVN, hw->dat_drv);
+ sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVP, hw->dat_drv);
+#else
+ sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVN, 0);
+ sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVP, 0);
+ sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVN, 0);
+ sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVP, 0);
+ sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVN, 0);
+ sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVP, 0);
+#endif
+
+ /* set sampling edge */
+
+ /* write crc timeout detection */
+ sdr_set_field(MSDC_PATCH_BIT0, 1 << 30, 1);
+
+ /* Configure to default data timeout */
+ sdr_set_field(SDC_CFG, SDC_CFG_DTOC, DEFAULT_DTOC);
+
+ msdc_set_buswidth(host, MMC_BUS_WIDTH_1);
+
+ N_MSG(FUC, "init hardware done!");
+}
+
+/* called by msdc_drv_remove */
+static void msdc_deinit_hw(struct msdc_host *host)
+{
+ u32 base = host->base;
+
+ /* Disable and clear all interrupts */
+ sdr_clr_bits(MSDC_INTEN, sdr_read32(MSDC_INTEN));
+ sdr_write32(MSDC_INT, sdr_read32(MSDC_INT));
+
+ /* Disable card detection */
+ msdc_enable_cd_irq(host, 0);
+ // msdc_set_power_mode(host, MMC_POWER_OFF); /* make sure power down */ /* --- by chhung */
+}
+
+/* init gpd and bd list in msdc_drv_probe */
+static void msdc_init_gpd_bd(struct msdc_host *host, struct msdc_dma *dma)
+{
+ gpd_t *gpd = dma->gpd;
+ bd_t *bd = dma->bd;
+ bd_t *ptr, *prev;
+
+ /* we just support one gpd */
+ int bdlen = MAX_BD_PER_GPD;
+
+ /* init the 2 gpd */
+ memset(gpd, 0, sizeof(gpd_t) * 2);
+ //gpd->next = (void *)virt_to_phys(gpd + 1); /* pointer to a null gpd, bug! kmalloc <-> virt_to_phys */
+ //gpd->next = (dma->gpd_addr + 1); /* bug */
+ gpd->next = (void *)((u32)dma->gpd_addr + sizeof(gpd_t));
+
+ //gpd->intr = 0;
+ gpd->bdp = 1; /* hwo, cs, bd pointer */
+ //gpd->ptr = (void*)virt_to_phys(bd);
+ gpd->ptr = (void *)dma->bd_addr; /* physical address */
+
+ memset(bd, 0, sizeof(bd_t) * bdlen);
+ ptr = bd + bdlen - 1;
+ //ptr->eol = 1; /* 0 or 1 [Fix me]*/
+ //ptr->next = 0;
+
+ while (ptr != bd) {
+ prev = ptr - 1;
+ prev->next = (void *)(dma->bd_addr + sizeof(bd_t) *(ptr - bd));
+ ptr = prev;
+ }
+}
+
+static int msdc_drv_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ __iomem void *base;
+ struct mmc_host *mmc;
+ struct resource *mem;
+ struct msdc_host *host;
+ struct msdc_hw *hw;
+ int ret, irq;
+
+ pdev->dev.platform_data = &msdc0_hw;
+
+ if (of_property_read_bool(pdev->dev.of_node, "mtk,wp-en"))
+ msdc0_hw.flags |= MSDC_WP_PIN_EN;
+
+ /* Allocate MMC host for this device */
+ mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev);
+ if (!mmc) return -ENOMEM;
+
+ hw = (struct msdc_hw*)pdev->dev.platform_data;
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+
+ //BUG_ON((!hw) || (!mem) || (irq < 0)); /* --- by chhung */
+
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ /* Set host parameters to mmc */
+ mmc->ops = &mt_msdc_ops;
+ mmc->f_min = HOST_MIN_MCLK;
+ mmc->f_max = HOST_MAX_MCLK;
+ mmc->ocr_avail = MSDC_OCR_AVAIL;
+
+ /* For sd card: MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE | MSDC_HIGHSPEED,
+ For sdio : MSDC_EXT_SDIO_IRQ | MSDC_HIGHSPEED */
+ if (hw->flags & MSDC_HIGHSPEED) {
+ mmc->caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
+ }
+ if (hw->data_pins == 4) { /* current data_pins are all 4*/
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+ } else if (hw->data_pins == 8) {
+ mmc->caps |= MMC_CAP_8_BIT_DATA;
+ }
+ if ((hw->flags & MSDC_SDIO_IRQ) || (hw->flags & MSDC_EXT_SDIO_IRQ))
+ mmc->caps |= MMC_CAP_SDIO_IRQ; /* yes for sdio */
+
+ cd_active_low = !of_property_read_bool(pdev->dev.of_node, "mediatek,cd-high");
+ mtk_sw_poll = of_property_read_bool(pdev->dev.of_node, "mediatek,cd-poll");
+
+ if (mtk_sw_poll)
+ mmc->caps |= MMC_CAP_NEEDS_POLL;
+
+ /* MMC core transfer sizes tunable parameters */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(3,10,0)
+ mmc->max_segs = MAX_HW_SGMTS;
+#else
+ mmc->max_hw_segs = MAX_HW_SGMTS;
+ mmc->max_phys_segs = MAX_PHY_SGMTS;
+#endif
+ mmc->max_seg_size = MAX_SGMT_SZ;
+ mmc->max_blk_size = HOST_MAX_BLKSZ;
+ mmc->max_req_size = MAX_REQ_SZ;
+ mmc->max_blk_count = mmc->max_req_size;
+
+ host = mmc_priv(mmc);
+ host->hw = hw;
+ host->mmc = mmc;
+ host->id = pdev->id;
+ if (host->id < 0 || host->id >= 4)
+ host->id = 0;
+ host->error = 0;
+ host->irq = irq;
+ host->base = (unsigned long) base;
+ host->mclk = 0; /* mclk: the request clock of mmc sub-system */
+ host->hclk = hclks[hw->clk_src]; /* hclk: clock of clock source to msdc controller */
+ host->sclk = 0; /* sclk: the really clock after divition */
+ host->pm_state = PMSG_RESUME;
+ host->suspend = 0;
+ host->core_clkon = 0;
+ host->card_clkon = 0;
+ host->core_power = 0;
+ host->power_mode = MMC_POWER_OFF;
+// host->card_inserted = hw->flags & MSDC_REMOVABLE ? 0 : 1;
+ host->timeout_ns = 0;
+ host->timeout_clks = DEFAULT_DTOC * 65536;
+
+ host->mrq = NULL;
+ //init_MUTEX(&host->sem); /* we don't need to support multiple threads access */
+
+ host->dma.used_gpd = 0;
+ host->dma.used_bd = 0;
+ mmc_dev(mmc)->dma_mask = NULL;
+
+ /* using dma_alloc_coherent*/ /* todo: using 1, for all 4 slots */
+ host->dma.gpd = dma_alloc_coherent(NULL, MAX_GPD_NUM * sizeof(gpd_t), &host->dma.gpd_addr, GFP_KERNEL);
+ host->dma.bd = dma_alloc_coherent(NULL, MAX_BD_NUM * sizeof(bd_t), &host->dma.bd_addr, GFP_KERNEL);
+ BUG_ON((!host->dma.gpd) || (!host->dma.bd));
+ msdc_init_gpd_bd(host, &host->dma);
+ /*for emmc*/
+ msdc_6575_host[pdev->id] = host;
+
+#if 0
+ tasklet_init(&host->card_tasklet, msdc_tasklet_card, (ulong)host);
+#else
+ INIT_DELAYED_WORK(&host->card_delaywork, msdc_tasklet_card);
+#endif
+ spin_lock_init(&host->lock);
+ msdc_init_hw(host);
+
+ if (ralink_soc == MT762X_SOC_MT7621AT)
+ ret = request_irq((unsigned int)irq, msdc_irq, 0, dev_name(&pdev->dev), host);
+ else
+ ret = request_irq((unsigned int)irq, msdc_irq, IRQF_TRIGGER_LOW, dev_name(&pdev->dev), host);
+
+ if (ret) goto release;
+ // mt65xx_irq_unmask(irq); /* --- by chhung */
+
+ if (hw->flags & MSDC_CD_PIN_EN) { /* not set for sdio */
+ if (hw->request_cd_eirq) { /* not set for MT6575 */
+ hw->request_cd_eirq(msdc_eirq_cd, (void*)host); /* msdc_eirq_cd will not be used! */
+ }
+ }
+
+ if (hw->request_sdio_eirq) /* set to combo_sdio_request_eirq() for WIFI */
+ hw->request_sdio_eirq(msdc_eirq_sdio, (void*)host); /* msdc_eirq_sdio() will be called when EIRQ */
+
+ if (hw->register_pm) {/* yes for sdio */
+#ifdef CONFIG_PM
+ hw->register_pm(msdc_pm, (void*)host); /* combo_sdio_register_pm() */
+#endif
+ if(hw->flags & MSDC_SYS_SUSPEND) { /* will not set for WIFI */
+ ERR_MSG("MSDC_SYS_SUSPEND and register_pm both set");
+ }
+ //mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY; /* pm not controlled by system but by client. */ /* --- by chhung */
+ }
+
+ platform_set_drvdata(pdev, mmc);
+
+ ret = mmc_add_host(mmc);
+ if (ret) goto free_irq;
+
+ /* Config card detection pin and enable interrupts */
+ if (hw->flags & MSDC_CD_PIN_EN) { /* set for card */
+ msdc_enable_cd_irq(host, 1);
+ } else {
+ msdc_enable_cd_irq(host, 0);
+ }
+
+ return 0;
+
+free_irq:
+ free_irq(irq, host);
+release:
+ platform_set_drvdata(pdev, NULL);
+ msdc_deinit_hw(host);
+
+#if 0
+ tasklet_kill(&host->card_tasklet);
+#else
+ cancel_delayed_work_sync(&host->card_delaywork);
+#endif
+
+ if (mem)
+ release_mem_region(mem->start, mem->end - mem->start + 1);
+
+ mmc_free_host(mmc);
+
+ return ret;
+}
+
+/* 4 device share one driver, using "drvdata" to show difference */
+static int msdc_drv_remove(struct platform_device *pdev)
+{
+ struct mmc_host *mmc;
+ struct msdc_host *host;
+ struct resource *mem;
+
+ mmc = platform_get_drvdata(pdev);
+ BUG_ON(!mmc);
+
+ host = mmc_priv(mmc);
+ BUG_ON(!host);
+
+ ERR_MSG("removed !!!");
+
+ platform_set_drvdata(pdev, NULL);
+ mmc_remove_host(host->mmc);
+ msdc_deinit_hw(host);
+
+#if 0
+ tasklet_kill(&host->card_tasklet);
+#else
+ cancel_delayed_work_sync(&host->card_delaywork);
+#endif
+ free_irq(host->irq, host);
+
+ dma_free_coherent(NULL, MAX_GPD_NUM * sizeof(gpd_t), host->dma.gpd, host->dma.gpd_addr);
+ dma_free_coherent(NULL, MAX_BD_NUM * sizeof(bd_t), host->dma.bd, host->dma.bd_addr);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (mem)
+ release_mem_region(mem->start, mem->end - mem->start + 1);
+
+ mmc_free_host(host->mmc);
+
+ return 0;
+}
+
+/* Fix me: Power Flow */
+#ifdef CONFIG_PM
+static int msdc_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int ret = 0;
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct msdc_host *host = mmc_priv(mmc);
+
+ if (mmc && state.event == PM_EVENT_SUSPEND && (host->hw->flags & MSDC_SYS_SUSPEND)) { /* will set for card */
+ msdc_pm(state, (void*)host);
+ }
+
+ return ret;
+}
+
+static int msdc_drv_resume(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct msdc_host *host = mmc_priv(mmc);
+ struct pm_message state;
+
+ state.event = PM_EVENT_RESUME;
+ if (mmc && (host->hw->flags & MSDC_SYS_SUSPEND)) {/* will set for card */
+ msdc_pm(state, (void*)host);
+ }
+
+ /* This mean WIFI not controller by PM */
+
+ return ret;
+}
+#endif
+
+static const struct of_device_id mt7620_sdhci_match[] = {
+ { .compatible = "ralink,mt7620-sdhci" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt7620_sdhci_match);
+
+static struct platform_driver mt_msdc_driver = {
+ .probe = msdc_drv_probe,
+ .remove = msdc_drv_remove,
+#ifdef CONFIG_PM
+ .suspend = msdc_drv_suspend,
+ .resume = msdc_drv_resume,
+#endif
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = mt7620_sdhci_match,
+ },
+};
+
+/*--------------------------------------------------------------------------*/
+/* module init/exit */
+/*--------------------------------------------------------------------------*/
+static int __init mt_msdc_init(void)
+{
+ int ret;
+/* +++ by chhung */
+ u32 reg;
+
+#if defined (CONFIG_MTD_ANY_RALINK)
+ extern int ra_check_flash_type(void);
+ if(ra_check_flash_type() == 2) { /* NAND */
+ printk("%s: !!!!! SDXC Module Initialize Fail !!!!!", __func__);
+ return 0;
+ }
+#endif
+ printk("MTK MSDC device init.\n");
+ mtk_sd_device.dev.platform_data = &msdc0_hw;
+if (ralink_soc == MT762X_SOC_MT7620A || ralink_soc == MT762X_SOC_MT7621AT) {
+//#if defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621)
+ reg = sdr_read32((volatile u32*)(RALINK_SYSCTL_BASE + 0x60)) & ~(0x3<<18);
+//#if defined (CONFIG_RALINK_MT7620)
+ if (ralink_soc == MT762X_SOC_MT7620A)
+ reg |= 0x1<<18;
+//#endif
+} else {
+//#elif defined (CONFIG_RALINK_MT7628)
+ /* TODO: maybe omitted when RAether already toggle AGPIO_CFG */
+ reg = sdr_read32((volatile u32*)(RALINK_SYSCTL_BASE + 0x3c));
+ reg |= 0x1e << 16;
+ sdr_write32((volatile u32*)(RALINK_SYSCTL_BASE + 0x3c), reg);
+
+ reg = sdr_read32((volatile u32*)(RALINK_SYSCTL_BASE + 0x60)) & ~(0x3<<10);
+#if defined (CONFIG_MTK_MMC_EMMC_8BIT)
+ reg |= 0x3<<26 | 0x3<<28 | 0x3<<30;
+ msdc0_hw.data_pins = 8,
+#endif
+//#endif
+}
+ sdr_write32((volatile u32*)(RALINK_SYSCTL_BASE + 0x60), reg);
+ //platform_device_register(&mtk_sd_device);
+/* end of +++ */
+
+ ret = platform_driver_register(&mt_msdc_driver);
+ if (ret) {
+ printk(KERN_ERR DRV_NAME ": Can't register driver");
+ return ret;
+ }
+ printk(KERN_INFO DRV_NAME ": MediaTek MT6575 MSDC Driver\n");
+
+#if defined (MT6575_SD_DEBUG)
+ msdc_debug_proc_init();
+#endif
+ return 0;
+}
+
+static void __exit mt_msdc_exit(void)
+{
+// platform_device_unregister(&mtk_sd_device);
+ platform_driver_unregister(&mt_msdc_driver);
+}
+
+module_init(mt_msdc_init);
+module_exit(mt_msdc_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MediaTek MT6575 SD/MMC Card Driver");
+MODULE_AUTHOR("Infinity Chen <infinity.chen@mediatek.com>");
+
+EXPORT_SYMBOL(msdc_6575_host);
diff --git a/drivers/staging/mt7621-pci/Makefile b/drivers/staging/mt7621-pci/Makefile
new file mode 100644
index 000000000000..607b84bedcc3
--- /dev/null
+++ b/drivers/staging/mt7621-pci/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SOC_MT7621) += pci-mt7621.o
diff --git a/drivers/staging/mt7621-pci/TODO b/drivers/staging/mt7621-pci/TODO
new file mode 100644
index 000000000000..cf30f629b9fd
--- /dev/null
+++ b/drivers/staging/mt7621-pci/TODO
@@ -0,0 +1,12 @@
+
+- general code review and cleanup
+- can this be converted to not require PCI_DRIVERS_LEGACY ??
+ The irq returned by pcibios_map_irq is a "hwirq" (hardware irq number)
+ and pci_assign_irq() assigns this directly to dev->irq, which
+ expects a "virq" (virtual irq number). These numbers are different
+ on MIPS. There is a gross hack to make it work on one
+ specific platform, so it can be tested.
+- Should this be merged with arch/mips/pci/pci-mt7620.c ??
+- ensure device-tree requirements are documented
+
+Cc: NeilBrown <neil@brown.name>
diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c
new file mode 100644
index 000000000000..1fa41eb8a87f
--- /dev/null
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
@@ -0,0 +1,840 @@
+/**************************************************************************
+ *
+ * BRIEF MODULE DESCRIPTION
+ * PCI init for Ralink RT2880 solution
+ *
+ * Copyright 2007 Ralink Inc. (bruce_chang@ralinktech.com.tw)
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.
+ *
+ *
+ **************************************************************************
+ * May 2007 Bruce Chang
+ * Initial Release
+ *
+ * May 2009 Bruce Chang
+ * support RT2880/RT3883 PCIe
+ *
+ * May 2011 Bruce Chang
+ * support RT6855/MT7620 PCIe
+ *
+ **************************************************************************
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <asm/pci.h>
+#include <asm/io.h>
+#include <asm/mips-cm.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+
+#include <ralink_regs.h>
+
+extern void pcie_phy_init(void);
+extern void chk_phy_pll(void);
+
+/*
+ * These functions and structures provide the BIOS scan and mapping of the PCI
+ * devices.
+ */
+
+#define CONFIG_PCIE_PORT0
+#define CONFIG_PCIE_PORT1
+#define CONFIG_PCIE_PORT2
+#define RALINK_PCIE0_CLK_EN (1<<24)
+#define RALINK_PCIE1_CLK_EN (1<<25)
+#define RALINK_PCIE2_CLK_EN (1<<26)
+
+#define RALINK_PCI_CONFIG_ADDR 0x20
+#define RALINK_PCI_CONFIG_DATA_VIRTUAL_REG 0x24
+#define SURFBOARDINT_PCIE0 11 /* PCIE0 */
+#define RALINK_INT_PCIE0 SURFBOARDINT_PCIE0
+#define RALINK_INT_PCIE1 SURFBOARDINT_PCIE1
+#define RALINK_INT_PCIE2 SURFBOARDINT_PCIE2
+#define SURFBOARDINT_PCIE1 31 /* PCIE1 */
+#define SURFBOARDINT_PCIE2 32 /* PCIE2 */
+#define RALINK_PCI_MEMBASE *(volatile u32 *)(RALINK_PCI_BASE + 0x0028)
+#define RALINK_PCI_IOBASE *(volatile u32 *)(RALINK_PCI_BASE + 0x002C)
+#define RALINK_PCIE0_RST (1<<24)
+#define RALINK_PCIE1_RST (1<<25)
+#define RALINK_PCIE2_RST (1<<26)
+#define RALINK_SYSCTL_BASE 0xBE000000
+
+#define RALINK_PCI_PCICFG_ADDR *(volatile u32 *)(RALINK_PCI_BASE + 0x0000)
+#define RALINK_PCI_PCIMSK_ADDR *(volatile u32 *)(RALINK_PCI_BASE + 0x000C)
+#define RALINK_PCI_BASE 0xBE140000
+
+#define RALINK_PCIEPHY_P0P1_CTL_OFFSET (RALINK_PCI_BASE + 0x9000)
+#define RT6855_PCIE0_OFFSET 0x2000
+#define RT6855_PCIE1_OFFSET 0x3000
+#define RT6855_PCIE2_OFFSET 0x4000
+
+#define RALINK_PCI0_BAR0SETUP_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0010)
+#define RALINK_PCI0_IMBASEBAR0_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0018)
+#define RALINK_PCI0_ID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0030)
+#define RALINK_PCI0_CLASS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0034)
+#define RALINK_PCI0_SUBID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0038)
+#define RALINK_PCI0_STATUS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0050)
+#define RALINK_PCI0_DERR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0060)
+#define RALINK_PCI0_ECRC *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0064)
+
+#define RALINK_PCI1_BAR0SETUP_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0010)
+#define RALINK_PCI1_IMBASEBAR0_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0018)
+#define RALINK_PCI1_ID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0030)
+#define RALINK_PCI1_CLASS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0034)
+#define RALINK_PCI1_SUBID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0038)
+#define RALINK_PCI1_STATUS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0050)
+#define RALINK_PCI1_DERR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0060)
+#define RALINK_PCI1_ECRC *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0064)
+
+#define RALINK_PCI2_BAR0SETUP_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0010)
+#define RALINK_PCI2_IMBASEBAR0_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0018)
+#define RALINK_PCI2_ID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0030)
+#define RALINK_PCI2_CLASS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0034)
+#define RALINK_PCI2_SUBID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0038)
+#define RALINK_PCI2_STATUS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0050)
+#define RALINK_PCI2_DERR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0060)
+#define RALINK_PCI2_ECRC *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0064)
+
+#define RALINK_PCIEPHY_P0P1_CTL_OFFSET (RALINK_PCI_BASE + 0x9000)
+#define RALINK_PCIEPHY_P2_CTL_OFFSET (RALINK_PCI_BASE + 0xA000)
+
+
+#define MV_WRITE(ofs, data) \
+ *(volatile u32 *)(RALINK_PCI_BASE+(ofs)) = cpu_to_le32(data)
+#define MV_READ(ofs, data) \
+ *(data) = le32_to_cpu(*(volatile u32 *)(RALINK_PCI_BASE+(ofs)))
+#define MV_READ_DATA(ofs) \
+ le32_to_cpu(*(volatile u32 *)(RALINK_PCI_BASE+(ofs)))
+
+#define MV_WRITE_16(ofs, data) \
+ *(volatile u16 *)(RALINK_PCI_BASE+(ofs)) = cpu_to_le16(data)
+#define MV_READ_16(ofs, data) \
+ *(data) = le16_to_cpu(*(volatile u16 *)(RALINK_PCI_BASE+(ofs)))
+
+#define MV_WRITE_8(ofs, data) \
+ *(volatile u8 *)(RALINK_PCI_BASE+(ofs)) = data
+#define MV_READ_8(ofs, data) \
+ *(data) = *(volatile u8 *)(RALINK_PCI_BASE+(ofs))
+
+
+
+#define RALINK_PCI_MM_MAP_BASE 0x60000000
+#define RALINK_PCI_IO_MAP_BASE 0x1e160000
+
+#define RALINK_SYSTEM_CONTROL_BASE 0xbe000000
+#define GPIO_PERST
+#define ASSERT_SYSRST_PCIE(val) do { \
+ if (*(unsigned int *)(0xbe00000c) == 0x00030101) \
+ RALINK_RSTCTRL |= val; \
+ else \
+ RALINK_RSTCTRL &= ~val; \
+ } while(0)
+#define DEASSERT_SYSRST_PCIE(val) do { \
+ if (*(unsigned int *)(0xbe00000c) == 0x00030101) \
+ RALINK_RSTCTRL &= ~val; \
+ else \
+ RALINK_RSTCTRL |= val; \
+ } while(0)
+#define RALINK_SYSCFG1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x14)
+#define RALINK_CLKCFG1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x30)
+#define RALINK_RSTCTRL *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x34)
+#define RALINK_GPIOMODE *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x60)
+#define RALINK_PCIE_CLK_GEN *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x7c)
+#define RALINK_PCIE_CLK_GEN1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x80)
+#define PPLL_CFG1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x9c)
+#define PPLL_DRV *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0xa0)
+//RALINK_SYSCFG1 bit
+#define RALINK_PCI_HOST_MODE_EN (1<<7)
+#define RALINK_PCIE_RC_MODE_EN (1<<8)
+//RALINK_RSTCTRL bit
+#define RALINK_PCIE_RST (1<<23)
+#define RALINK_PCI_RST (1<<24)
+//RALINK_CLKCFG1 bit
+#define RALINK_PCI_CLK_EN (1<<19)
+#define RALINK_PCIE_CLK_EN (1<<21)
+//RALINK_GPIOMODE bit
+#define PCI_SLOTx2 (1<<11)
+#define PCI_SLOTx1 (2<<11)
+//MTK PCIE PLL bit
+#define PDRV_SW_SET (1<<31)
+#define LC_CKDRVPD_ (1<<19)
+
+#define MEMORY_BASE 0x0
+static int pcie_link_status = 0;
+
+#define PCI_ACCESS_READ_1 0
+#define PCI_ACCESS_READ_2 1
+#define PCI_ACCESS_READ_4 2
+#define PCI_ACCESS_WRITE_1 3
+#define PCI_ACCESS_WRITE_2 4
+#define PCI_ACCESS_WRITE_4 5
+
+static int config_access(unsigned char access_type, struct pci_bus *bus,
+ unsigned int devfn, unsigned int where, u32 * data)
+{
+ unsigned int slot = PCI_SLOT(devfn);
+ u8 func = PCI_FUNC(devfn);
+ uint32_t address_reg, data_reg;
+ unsigned int address;
+
+ address_reg = RALINK_PCI_CONFIG_ADDR;
+ data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG;
+
+ address = (((where&0xF00)>>8)<<24) |(bus->number << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | 0x80000000;
+ MV_WRITE(address_reg, address);
+
+ switch(access_type) {
+ case PCI_ACCESS_WRITE_1:
+ MV_WRITE_8(data_reg+(where&0x3), *data);
+ break;
+ case PCI_ACCESS_WRITE_2:
+ MV_WRITE_16(data_reg+(where&0x3), *data);
+ break;
+ case PCI_ACCESS_WRITE_4:
+ MV_WRITE(data_reg, *data);
+ break;
+ case PCI_ACCESS_READ_1:
+ MV_READ_8( data_reg+(where&0x3), data);
+ break;
+ case PCI_ACCESS_READ_2:
+ MV_READ_16(data_reg+(where&0x3), data);
+ break;
+ case PCI_ACCESS_READ_4:
+ MV_READ(data_reg, data);
+ break;
+ default:
+ printk("no specify access type\n");
+ break;
+ }
+ return 0;
+}
+
+static int
+read_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 * val)
+{
+ return config_access(PCI_ACCESS_READ_1, bus, devfn, (unsigned int)where, (u32 *)val);
+}
+
+static int
+read_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 * val)
+{
+ return config_access(PCI_ACCESS_READ_2, bus, devfn, (unsigned int)where, (u32 *)val);
+}
+
+static int
+read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 * val)
+{
+ return config_access(PCI_ACCESS_READ_4, bus, devfn, (unsigned int)where, (u32 *)val);
+}
+
+static int
+write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val)
+{
+ if (config_access(PCI_ACCESS_WRITE_1, bus, devfn, (unsigned int)where, (u32 *)&val))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val)
+{
+ if (config_access(PCI_ACCESS_WRITE_2, bus, devfn, where, (u32 *)&val))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val)
+{
+ if (config_access(PCI_ACCESS_WRITE_4, bus, devfn, where, &val))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val)
+{
+ switch (size) {
+ case 1:
+ return read_config_byte(bus, devfn, where, (u8 *) val);
+ case 2:
+ return read_config_word(bus, devfn, where, (u16 *) val);
+ default:
+ return read_config_dword(bus, devfn, where, val);
+ }
+}
+
+static int
+pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val)
+{
+ switch (size) {
+ case 1:
+ return write_config_byte(bus, devfn, where, (u8) val);
+ case 2:
+ return write_config_word(bus, devfn, where, (u16) val);
+ default:
+ return write_config_dword(bus, devfn, where, val);
+ }
+}
+
+struct pci_ops mt7621_pci_ops= {
+ .read = pci_config_read,
+ .write = pci_config_write,
+};
+
+static struct resource mt7621_res_pci_mem1 = {
+ .name = "PCI MEM1",
+ .start = RALINK_PCI_MM_MAP_BASE,
+ .end = (u32)((RALINK_PCI_MM_MAP_BASE + (unsigned char *)0x0fffffff)),
+ .flags = IORESOURCE_MEM,
+};
+static struct resource mt7621_res_pci_io1 = {
+ .name = "PCI I/O1",
+ .start = RALINK_PCI_IO_MAP_BASE,
+ .end = (u32)((RALINK_PCI_IO_MAP_BASE + (unsigned char *)0x0ffff)),
+ .flags = IORESOURCE_IO,
+};
+
+static struct pci_controller mt7621_controller = {
+ .pci_ops = &mt7621_pci_ops,
+ .mem_resource = &mt7621_res_pci_mem1,
+ .io_resource = &mt7621_res_pci_io1,
+ .mem_offset = 0x00000000UL,
+ .io_offset = 0x00000000UL,
+ .io_map_base = 0xa0000000,
+};
+
+static void
+read_config(unsigned long bus, unsigned long dev, unsigned long func, unsigned long reg, unsigned long *val)
+{
+ unsigned int address_reg, data_reg, address;
+
+ address_reg = RALINK_PCI_CONFIG_ADDR;
+ data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG;
+ address = (((reg & 0xF00)>>8)<<24) | (bus << 16) | (dev << 11) | (func << 8) | (reg & 0xfc) | 0x80000000 ;
+ MV_WRITE(address_reg, address);
+ MV_READ(data_reg, val);
+ return;
+}
+
+static void
+write_config(unsigned long bus, unsigned long dev, unsigned long func, unsigned long reg, unsigned long val)
+{
+ unsigned int address_reg, data_reg, address;
+
+ address_reg = RALINK_PCI_CONFIG_ADDR;
+ data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG;
+ address = (((reg & 0xF00)>>8)<<24) | (bus << 16) | (dev << 11) | (func << 8) | (reg & 0xfc) | 0x80000000 ;
+ MV_WRITE(address_reg, address);
+ MV_WRITE(data_reg, val);
+ return;
+}
+
+
+int
+pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ u16 cmd;
+ u32 val;
+ int irq = 0;
+
+ if ((dev->bus->number == 0) && (slot == 0)) {
+ write_config(0, 0, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE);
+ read_config(0, 0, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val);
+ printk("BAR0 at slot 0 = %x\n", val);
+ printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot);
+ } else if((dev->bus->number == 0) && (slot == 0x1)) {
+ write_config(0, 1, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE);
+ read_config(0, 1, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val);
+ printk("BAR0 at slot 1 = %x\n", val);
+ printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot);
+ } else if((dev->bus->number == 0) && (slot == 0x2)) {
+ write_config(0, 2, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE);
+ read_config(0, 2, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val);
+ printk("BAR0 at slot 2 = %x\n", val);
+ printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot);
+ } else if ((dev->bus->number == 1) && (slot == 0x0)) {
+ switch (pcie_link_status) {
+ case 2:
+ case 6:
+ irq = RALINK_INT_PCIE1;
+ break;
+ case 4:
+ irq = RALINK_INT_PCIE2;
+ break;
+ default:
+ irq = RALINK_INT_PCIE0;
+ }
+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
+ } else if ((dev->bus->number == 2) && (slot == 0x0)) {
+ switch (pcie_link_status) {
+ case 5:
+ case 6:
+ irq = RALINK_INT_PCIE2;
+ break;
+ default:
+ irq = RALINK_INT_PCIE1;
+ }
+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
+ } else if ((dev->bus->number == 2) && (slot == 0x1)) {
+ switch (pcie_link_status) {
+ case 5:
+ case 6:
+ irq = RALINK_INT_PCIE2;
+ break;
+ default:
+ irq = RALINK_INT_PCIE1;
+ }
+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
+ } else if ((dev->bus->number ==3) && (slot == 0x0)) {
+ irq = RALINK_INT_PCIE2;
+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
+ } else if ((dev->bus->number ==3) && (slot == 0x1)) {
+ irq = RALINK_INT_PCIE2;
+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
+ } else if ((dev->bus->number ==3) && (slot == 0x2)) {
+ irq = RALINK_INT_PCIE2;
+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
+ } else {
+ printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot);
+ return 0;
+ }
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x14); //configure cache line size 0x14
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xFF); //configure latency timer 0x10
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd = cmd | PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+#ifdef CONFIG_DTB_GNUBEE1
+ /*
+ * 'irq' here is a hwirq, but a virq is needed. Until we know how and where
+ * to convert one to the other, we have this hack for the GNUBEE1
+ */
+ return irq == 11 ? 22 : irq;
+#else
+ return irq;
+#endif
+}
+
+void
+set_pcie_phy(u32 *addr, int start_b, int bits, int val)
+{
+// printk("0x%p:", addr);
+// printk(" %x", *addr);
+ *(unsigned int *)(addr) &= ~(((1<<bits) - 1)<<start_b);
+ *(unsigned int *)(addr) |= val << start_b;
+// printk(" -> %x\n", *addr);
+}
+
+void
+bypass_pipe_rst(void)
+{
+#if defined (CONFIG_PCIE_PORT0)
+ /* PCIe Port 0 */
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x02c), 12, 1, 0x01); // rg_pe1_pipe_rst_b
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x02c), 4, 1, 0x01); // rg_pe1_pipe_cmd_frc[4]
+#endif
+#if defined (CONFIG_PCIE_PORT1)
+ /* PCIe Port 1 */
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x12c), 12, 1, 0x01); // rg_pe1_pipe_rst_b
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x12c), 4, 1, 0x01); // rg_pe1_pipe_cmd_frc[4]
+#endif
+#if defined (CONFIG_PCIE_PORT2)
+ /* PCIe Port 2 */
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x02c), 12, 1, 0x01); // rg_pe1_pipe_rst_b
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x02c), 4, 1, 0x01); // rg_pe1_pipe_cmd_frc[4]
+#endif
+}
+
+void
+set_phy_for_ssc(void)
+{
+ unsigned long reg = (*(volatile u32 *)(RALINK_SYSCTL_BASE + 0x10));
+
+ reg = (reg >> 6) & 0x7;
+#if defined (CONFIG_PCIE_PORT0) || defined (CONFIG_PCIE_PORT1)
+ /* Set PCIe Port0 & Port1 PHY to disable SSC */
+ /* Debug Xtal Type */
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x400), 8, 1, 0x01); // rg_pe1_frc_h_xtal_type
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x400), 9, 2, 0x00); // rg_pe1_h_xtal_type
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 4, 1, 0x01); // rg_pe1_frc_phy_en //Force Port 0 enable control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 4, 1, 0x01); // rg_pe1_frc_phy_en //Force Port 1 enable control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 5, 1, 0x00); // rg_pe1_phy_en //Port 0 disable
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 5, 1, 0x00); // rg_pe1_phy_en //Port 1 disable
+ if(reg <= 5 && reg >= 3) { // 40MHz Xtal
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 6, 2, 0x01); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode)
+ printk("***** Xtal 40MHz *****\n");
+ } else { // 25MHz | 20MHz Xtal
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 6, 2, 0x00); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode)
+ if (reg >= 6) {
+ printk("***** Xtal 25MHz *****\n");
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4bc), 4, 2, 0x01); // RG_PE1_H_PLL_FBKSEL //Feedback clock select
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x49c), 0,31, 0x18000000); // RG_PE1_H_LCDDS_PCW_NCPO //DDS NCPO PCW (for host mode)
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a4), 0,16, 0x18d); // RG_PE1_H_LCDDS_SSC_PRD //DDS SSC dither period control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a8), 0,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA //DDS SSC dither amplitude control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a8), 16,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA1 //DDS SSC dither amplitude control for initial
+ } else {
+ printk("***** Xtal 20MHz *****\n");
+ }
+ }
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a0), 5, 1, 0x01); // RG_PE1_LCDDS_CLK_PH_INV //DDS clock inversion
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 22, 2, 0x02); // RG_PE1_H_PLL_BC
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 18, 4, 0x06); // RG_PE1_H_PLL_BP
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 12, 4, 0x02); // RG_PE1_H_PLL_IR
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 8, 4, 0x01); // RG_PE1_H_PLL_IC
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4ac), 16, 3, 0x00); // RG_PE1_H_PLL_BR
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 1, 3, 0x02); // RG_PE1_PLL_DIVEN
+ if(reg <= 5 && reg >= 3) { // 40MHz Xtal
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x414), 6, 2, 0x01); // rg_pe1_mstckdiv //value of da_pe1_mstckdiv when force mode enable
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x414), 5, 1, 0x01); // rg_pe1_frc_mstckdiv //force mode enable of da_pe1_mstckdiv
+ }
+ /* Enable PHY and disable force mode */
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 5, 1, 0x01); // rg_pe1_phy_en //Port 0 enable
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 5, 1, 0x01); // rg_pe1_phy_en //Port 1 enable
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 4, 1, 0x00); // rg_pe1_frc_phy_en //Force Port 0 disable control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 4, 1, 0x00); // rg_pe1_frc_phy_en //Force Port 1 disable control
+#endif
+#if defined (CONFIG_PCIE_PORT2)
+ /* Set PCIe Port2 PHY to disable SSC */
+ /* Debug Xtal Type */
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x400), 8, 1, 0x01); // rg_pe1_frc_h_xtal_type
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x400), 9, 2, 0x00); // rg_pe1_h_xtal_type
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 4, 1, 0x01); // rg_pe1_frc_phy_en //Force Port 0 enable control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 5, 1, 0x00); // rg_pe1_phy_en //Port 0 disable
+ if(reg <= 5 && reg >= 3) { // 40MHz Xtal
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 6, 2, 0x01); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode)
+ } else { // 25MHz | 20MHz Xtal
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 6, 2, 0x00); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode)
+ if (reg >= 6) { // 25MHz Xtal
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4bc), 4, 2, 0x01); // RG_PE1_H_PLL_FBKSEL //Feedback clock select
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x49c), 0,31, 0x18000000); // RG_PE1_H_LCDDS_PCW_NCPO //DDS NCPO PCW (for host mode)
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a4), 0,16, 0x18d); // RG_PE1_H_LCDDS_SSC_PRD //DDS SSC dither period control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a8), 0,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA //DDS SSC dither amplitude control
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a8), 16,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA1 //DDS SSC dither amplitude control for initial
+ }
+ }
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a0), 5, 1, 0x01); // RG_PE1_LCDDS_CLK_PH_INV //DDS clock inversion
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 22, 2, 0x02); // RG_PE1_H_PLL_BC
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 18, 4, 0x06); // RG_PE1_H_PLL_BP
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 12, 4, 0x02); // RG_PE1_H_PLL_IR
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 8, 4, 0x01); // RG_PE1_H_PLL_IC
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4ac), 16, 3, 0x00); // RG_PE1_H_PLL_BR
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 1, 3, 0x02); // RG_PE1_PLL_DIVEN
+ if(reg <= 5 && reg >= 3) { // 40MHz Xtal
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x414), 6, 2, 0x01); // rg_pe1_mstckdiv //value of da_pe1_mstckdiv when force mode enable
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x414), 5, 1, 0x01); // rg_pe1_frc_mstckdiv //force mode enable of da_pe1_mstckdiv
+ }
+ /* Enable PHY and disable force mode */
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 5, 1, 0x01); // rg_pe1_phy_en //Port 0 enable
+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 4, 1, 0x00); // rg_pe1_frc_phy_en //Force Port 0 disable control
+#endif
+}
+
+void setup_cm_memory_region(struct resource *mem_resource)
+{
+ resource_size_t mask;
+ if (mips_cps_numiocu(0)) {
+ /* FIXME: hardware doesn't accept mask values with 1s after
+ 0s (e.g. 0xffef), so it would be great to warn if that's
+ about to happen */
+ mask = ~(mem_resource->end - mem_resource->start);
+
+ write_gcr_reg1_base(mem_resource->start);
+ write_gcr_reg1_mask(mask | CM_GCR_REGn_MASK_CMTGT_IOCU0);
+ printk("PCI coherence region base: 0x%08llx, mask/settings: 0x%08llx\n",
+ (unsigned long long)read_gcr_reg1_base(),
+ (unsigned long long)read_gcr_reg1_mask());
+ }
+}
+
+static int mt7621_pci_probe(struct platform_device *pdev)
+{
+ unsigned long val = 0;
+
+ iomem_resource.start = 0;
+ iomem_resource.end= ~0;
+ ioport_resource.start= 0;
+ ioport_resource.end = ~0;
+
+#if defined (CONFIG_PCIE_PORT0)
+ val = RALINK_PCIE0_RST;
+#endif
+#if defined (CONFIG_PCIE_PORT1)
+ val |= RALINK_PCIE1_RST;
+#endif
+#if defined (CONFIG_PCIE_PORT2)
+ val |= RALINK_PCIE2_RST;
+#endif
+ ASSERT_SYSRST_PCIE(RALINK_PCIE0_RST | RALINK_PCIE1_RST | RALINK_PCIE2_RST);
+ printk("pull PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL);
+#if defined GPIO_PERST /* add GPIO control instead of PERST_N */ /*chhung*/
+ *(unsigned int *)(0xbe000060) &= ~(0x3<<10 | 0x3<<3);
+ *(unsigned int *)(0xbe000060) |= 0x1<<10 | 0x1<<3;
+ mdelay(100);
+ *(unsigned int *)(0xbe000600) |= 0x1<<19 | 0x1<<8 | 0x1<<7; // use GPIO19/GPIO8/GPIO7 (PERST_N/UART_RXD3/UART_TXD3)
+ mdelay(100);
+ *(unsigned int *)(0xbe000620) &= ~(0x1<<19 | 0x1<<8 | 0x1<<7); // clear DATA
+
+ mdelay(100);
+#else
+ *(unsigned int *)(0xbe000060) &= ~0x00000c00;
+#endif
+#if defined (CONFIG_PCIE_PORT0)
+ val = RALINK_PCIE0_RST;
+#endif
+#if defined (CONFIG_PCIE_PORT1)
+ val |= RALINK_PCIE1_RST;
+#endif
+#if defined (CONFIG_PCIE_PORT2)
+ val |= RALINK_PCIE2_RST;
+#endif
+ DEASSERT_SYSRST_PCIE(val);
+ printk("release PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL);
+
+ if ((*(unsigned int *)(0xbe00000c)&0xFFFF) == 0x0101) // MT7621 E2
+ bypass_pipe_rst();
+ set_phy_for_ssc();
+ printk("release PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL);
+
+#if defined (CONFIG_PCIE_PORT0)
+ read_config(0, 0, 0, 0x70c, &val);
+ printk("Port 0 N_FTS = %x\n", (unsigned int)val);
+#endif
+#if defined (CONFIG_PCIE_PORT1)
+ read_config(0, 1, 0, 0x70c, &val);
+ printk("Port 1 N_FTS = %x\n", (unsigned int)val);
+#endif
+#if defined (CONFIG_PCIE_PORT2)
+ read_config(0, 2, 0, 0x70c, &val);
+ printk("Port 2 N_FTS = %x\n", (unsigned int)val);
+#endif
+
+ RALINK_RSTCTRL = (RALINK_RSTCTRL | RALINK_PCIE_RST);
+ RALINK_SYSCFG1 &= ~(0x30);
+ RALINK_SYSCFG1 |= (2<<4);
+ RALINK_PCIE_CLK_GEN &= 0x7fffffff;
+ RALINK_PCIE_CLK_GEN1 &= 0x80ffffff;
+ RALINK_PCIE_CLK_GEN1 |= 0xa << 24;
+ RALINK_PCIE_CLK_GEN |= 0x80000000;
+ mdelay(50);
+ RALINK_RSTCTRL = (RALINK_RSTCTRL & ~RALINK_PCIE_RST);
+
+
+#if defined GPIO_PERST /* add GPIO control instead of PERST_N */ /*chhung*/
+ *(unsigned int *)(0xbe000620) |= 0x1<<19 | 0x1<<8 | 0x1<<7; // set DATA
+ mdelay(100);
+#else
+ RALINK_PCI_PCICFG_ADDR &= ~(1<<1); //de-assert PERST
+#endif
+ mdelay(500);
+
+
+ mdelay(500);
+#if defined (CONFIG_PCIE_PORT0)
+ if(( RALINK_PCI0_STATUS & 0x1) == 0)
+ {
+ printk("PCIE0 no card, disable it(RST&CLK)\n");
+ ASSERT_SYSRST_PCIE(RALINK_PCIE0_RST);
+ RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE0_CLK_EN);
+ pcie_link_status &= ~(1<<0);
+ } else {
+ pcie_link_status |= 1<<0;
+ RALINK_PCI_PCIMSK_ADDR |= (1<<20); // enable pcie1 interrupt
+ }
+#endif
+#if defined (CONFIG_PCIE_PORT1)
+ if(( RALINK_PCI1_STATUS & 0x1) == 0)
+ {
+ printk("PCIE1 no card, disable it(RST&CLK)\n");
+ ASSERT_SYSRST_PCIE(RALINK_PCIE1_RST);
+ RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE1_CLK_EN);
+ pcie_link_status &= ~(1<<1);
+ } else {
+ pcie_link_status |= 1<<1;
+ RALINK_PCI_PCIMSK_ADDR |= (1<<21); // enable pcie1 interrupt
+ }
+#endif
+#if defined (CONFIG_PCIE_PORT2)
+ if (( RALINK_PCI2_STATUS & 0x1) == 0) {
+ printk("PCIE2 no card, disable it(RST&CLK)\n");
+ ASSERT_SYSRST_PCIE(RALINK_PCIE2_RST);
+ RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE2_CLK_EN);
+ pcie_link_status &= ~(1<<2);
+ } else {
+ pcie_link_status |= 1<<2;
+ RALINK_PCI_PCIMSK_ADDR |= (1<<22); // enable pcie2 interrupt
+ }
+#endif
+ if (pcie_link_status == 0)
+ return 0;
+
+/*
+pcie(2/1/0) link status pcie2_num pcie1_num pcie0_num
+3'b000 x x x
+3'b001 x x 0
+3'b010 x 0 x
+3'b011 x 1 0
+3'b100 0 x x
+3'b101 1 x 0
+3'b110 1 0 x
+3'b111 2 1 0
+*/
+ switch(pcie_link_status) {
+ case 2:
+ RALINK_PCI_PCICFG_ADDR &= ~0x00ff0000;
+ RALINK_PCI_PCICFG_ADDR |= 0x1 << 16; //port0
+ RALINK_PCI_PCICFG_ADDR |= 0x0 << 20; //port1
+ break;
+ case 4:
+ RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000;
+ RALINK_PCI_PCICFG_ADDR |= 0x1 << 16; //port0
+ RALINK_PCI_PCICFG_ADDR |= 0x2 << 20; //port1
+ RALINK_PCI_PCICFG_ADDR |= 0x0 << 24; //port2
+ break;
+ case 5:
+ RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000;
+ RALINK_PCI_PCICFG_ADDR |= 0x0 << 16; //port0
+ RALINK_PCI_PCICFG_ADDR |= 0x2 << 20; //port1
+ RALINK_PCI_PCICFG_ADDR |= 0x1 << 24; //port2
+ break;
+ case 6:
+ RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000;
+ RALINK_PCI_PCICFG_ADDR |= 0x2 << 16; //port0
+ RALINK_PCI_PCICFG_ADDR |= 0x0 << 20; //port1
+ RALINK_PCI_PCICFG_ADDR |= 0x1 << 24; //port2
+ break;
+ }
+ printk(" -> %x\n", RALINK_PCI_PCICFG_ADDR);
+ //printk(" RALINK_PCI_ARBCTL = %x\n", RALINK_PCI_ARBCTL);
+
+/*
+ ioport_resource.start = mt7621_res_pci_io1.start;
+ ioport_resource.end = mt7621_res_pci_io1.end;
+*/
+
+ RALINK_PCI_MEMBASE = 0xffffffff; //RALINK_PCI_MM_MAP_BASE;
+ RALINK_PCI_IOBASE = RALINK_PCI_IO_MAP_BASE;
+
+#if defined (CONFIG_PCIE_PORT0)
+ //PCIe0
+ if((pcie_link_status & 0x1) != 0) {
+ RALINK_PCI0_BAR0SETUP_ADDR = 0x7FFF0001; //open 7FFF:2G; ENABLE
+ RALINK_PCI0_IMBASEBAR0_ADDR = MEMORY_BASE;
+ RALINK_PCI0_CLASS = 0x06040001;
+ printk("PCIE0 enabled\n");
+ }
+#endif
+#if defined (CONFIG_PCIE_PORT1)
+ //PCIe1
+ if ((pcie_link_status & 0x2) != 0) {
+ RALINK_PCI1_BAR0SETUP_ADDR = 0x7FFF0001; //open 7FFF:2G; ENABLE
+ RALINK_PCI1_IMBASEBAR0_ADDR = MEMORY_BASE;
+ RALINK_PCI1_CLASS = 0x06040001;
+ printk("PCIE1 enabled\n");
+ }
+#endif
+#if defined (CONFIG_PCIE_PORT2)
+ //PCIe2
+ if ((pcie_link_status & 0x4) != 0) {
+ RALINK_PCI2_BAR0SETUP_ADDR = 0x7FFF0001; //open 7FFF:2G; ENABLE
+ RALINK_PCI2_IMBASEBAR0_ADDR = MEMORY_BASE;
+ RALINK_PCI2_CLASS = 0x06040001;
+ printk("PCIE2 enabled\n");
+ }
+#endif
+
+
+ switch(pcie_link_status) {
+ case 7:
+ read_config(0, 2, 0, 0x4, &val);
+ write_config(0, 2, 0, 0x4, val|0x4);
+ // write_config(0, 1, 0, 0x4, val|0x7);
+ read_config(0, 2, 0, 0x70c, &val);
+ val &= ~(0xff)<<8;
+ val |= 0x50<<8;
+ write_config(0, 2, 0, 0x70c, val);
+ case 3:
+ case 5:
+ case 6:
+ read_config(0, 1, 0, 0x4, &val);
+ write_config(0, 1, 0, 0x4, val|0x4);
+ // write_config(0, 1, 0, 0x4, val|0x7);
+ read_config(0, 1, 0, 0x70c, &val);
+ val &= ~(0xff)<<8;
+ val |= 0x50<<8;
+ write_config(0, 1, 0, 0x70c, val);
+ default:
+ read_config(0, 0, 0, 0x4, &val);
+ write_config(0, 0, 0, 0x4, val|0x4); //bus master enable
+ // write_config(0, 0, 0, 0x4, val|0x7); //bus master enable
+ read_config(0, 0, 0, 0x70c, &val);
+ val &= ~(0xff)<<8;
+ val |= 0x50<<8;
+ write_config(0, 0, 0, 0x70c, val);
+ }
+
+ pci_load_of_ranges(&mt7621_controller, pdev->dev.of_node);
+ setup_cm_memory_region(mt7621_controller.mem_resource);
+ register_pci_controller(&mt7621_controller);
+ return 0;
+
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+static const struct of_device_id mt7621_pci_ids[] = {
+ { .compatible = "mediatek,mt7621-pci" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt7621_pci_ids);
+
+static struct platform_driver mt7621_pci_driver = {
+ .probe = mt7621_pci_probe,
+ .driver = {
+ .name = "mt7621-pci",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(mt7621_pci_ids),
+ },
+};
+
+static int __init mt7621_pci_init(void)
+{
+ return platform_driver_register(&mt7621_pci_driver);
+}
+
+arch_initcall(mt7621_pci_init);
diff --git a/drivers/staging/mt7621-pinctrl/Kconfig b/drivers/staging/mt7621-pinctrl/Kconfig
new file mode 100644
index 000000000000..37cf9c3273be
--- /dev/null
+++ b/drivers/staging/mt7621-pinctrl/Kconfig
@@ -0,0 +1,4 @@
+config PINCTRL_RT2880
+ bool "RT2800 pinctrl driver for RALINK/Mediatek SOCs"
+ depends on RALINK
+ select PINMUX
diff --git a/drivers/staging/mt7621-pinctrl/Makefile b/drivers/staging/mt7621-pinctrl/Makefile
new file mode 100644
index 000000000000..856102137a1e
--- /dev/null
+++ b/drivers/staging/mt7621-pinctrl/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_PINCTRL_RT2880) += pinctrl-rt2880.o
+
+ccflags-y += -I$(srctree)/drivers/pinctrl
diff --git a/drivers/staging/mt7621-pinctrl/TODO b/drivers/staging/mt7621-pinctrl/TODO
new file mode 100644
index 000000000000..b2c235a16d5c
--- /dev/null
+++ b/drivers/staging/mt7621-pinctrl/TODO
@@ -0,0 +1,6 @@
+
+- general code review and cleanup
+- should probably be always selected by 'config RALINK'
+- ensure device-tree requirements are documented
+
+Cc: NeilBrown <neil@brown.name>
diff --git a/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c b/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c
new file mode 100644
index 000000000000..3d2d1c2a006f
--- /dev/null
+++ b/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c
@@ -0,0 +1,472 @@
+/*
+ * linux/drivers/pinctrl/pinctrl-rt2880.c
+ *
+ * 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
+ * publishhed by the Free Software Foundation.
+ *
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+#include <asm/mach-ralink/pinmux.h>
+#include <asm/mach-ralink/mt7620.h>
+
+#include "core.h"
+
+#define SYSC_REG_GPIO_MODE 0x60
+#define SYSC_REG_GPIO_MODE2 0x64
+
+struct rt2880_priv {
+ struct device *dev;
+
+ struct pinctrl_pin_desc *pads;
+ struct pinctrl_desc *desc;
+
+ struct rt2880_pmx_func **func;
+ int func_count;
+
+ struct rt2880_pmx_group *groups;
+ const char **group_names;
+ int group_count;
+
+ uint8_t *gpio;
+ int max_pins;
+};
+
+static int rt2880_get_group_count(struct pinctrl_dev *pctrldev)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+
+ return p->group_count;
+}
+
+static const char *rt2880_get_group_name(struct pinctrl_dev *pctrldev,
+ unsigned group)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+
+ if (group >= p->group_count)
+ return NULL;
+
+ return p->group_names[group];
+}
+
+static int rt2880_get_group_pins(struct pinctrl_dev *pctrldev,
+ unsigned group,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+
+ if (group >= p->group_count)
+ return -EINVAL;
+
+ *pins = p->groups[group].func[0].pins;
+ *num_pins = p->groups[group].func[0].pin_count;
+
+ return 0;
+}
+
+static void rt2880_pinctrl_dt_free_map(struct pinctrl_dev *pctrldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+ int i;
+
+ for (i = 0; i < num_maps; i++)
+ if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN ||
+ map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
+ kfree(map[i].data.configs.configs);
+ kfree(map);
+}
+
+static void rt2880_pinctrl_pin_dbg_show(struct pinctrl_dev *pctrldev,
+ struct seq_file *s,
+ unsigned offset)
+{
+ seq_printf(s, "ralink pio");
+}
+
+static void rt2880_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctrldev,
+ struct device_node *np,
+ struct pinctrl_map **map)
+{
+ const char *function;
+ int func = of_property_read_string(np, "ralink,function", &function);
+ int grps = of_property_count_strings(np, "ralink,group");
+ int i;
+
+ if (func || !grps)
+ return;
+
+ for (i = 0; i < grps; i++) {
+ const char *group;
+
+ of_property_read_string_index(np, "ralink,group", i, &group);
+
+ (*map)->type = PIN_MAP_TYPE_MUX_GROUP;
+ (*map)->name = function;
+ (*map)->data.mux.group = group;
+ (*map)->data.mux.function = function;
+ (*map)++;
+ }
+}
+
+static int rt2880_pinctrl_dt_node_to_map(struct pinctrl_dev *pctrldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map,
+ unsigned *num_maps)
+{
+ int max_maps = 0;
+ struct pinctrl_map *tmp;
+ struct device_node *np;
+
+ for_each_child_of_node(np_config, np) {
+ int ret = of_property_count_strings(np, "ralink,group");
+
+ if (ret >= 0)
+ max_maps += ret;
+ }
+
+ if (!max_maps)
+ return max_maps;
+
+ *map = kzalloc(max_maps * sizeof(struct pinctrl_map), GFP_KERNEL);
+ if (!*map)
+ return -ENOMEM;
+
+ tmp = *map;
+
+ for_each_child_of_node(np_config, np)
+ rt2880_pinctrl_dt_subnode_to_map(pctrldev, np, &tmp);
+ *num_maps = max_maps;
+
+ return 0;
+}
+
+static const struct pinctrl_ops rt2880_pctrl_ops = {
+ .get_groups_count = rt2880_get_group_count,
+ .get_group_name = rt2880_get_group_name,
+ .get_group_pins = rt2880_get_group_pins,
+ .pin_dbg_show = rt2880_pinctrl_pin_dbg_show,
+ .dt_node_to_map = rt2880_pinctrl_dt_node_to_map,
+ .dt_free_map = rt2880_pinctrl_dt_free_map,
+};
+
+static int rt2880_pmx_func_count(struct pinctrl_dev *pctrldev)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+
+ return p->func_count;
+}
+
+static const char *rt2880_pmx_func_name(struct pinctrl_dev *pctrldev,
+ unsigned func)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+
+ return p->func[func]->name;
+}
+
+static int rt2880_pmx_group_get_groups(struct pinctrl_dev *pctrldev,
+ unsigned func,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+
+ if (p->func[func]->group_count == 1)
+ *groups = &p->group_names[p->func[func]->groups[0]];
+ else
+ *groups = p->group_names;
+
+ *num_groups = p->func[func]->group_count;
+
+ return 0;
+}
+
+static int rt2880_pmx_group_enable(struct pinctrl_dev *pctrldev,
+ unsigned func,
+ unsigned group)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+ u32 mode = 0;
+ u32 reg = SYSC_REG_GPIO_MODE;
+ int i;
+ int shift;
+
+ /* dont allow double use */
+ if (p->groups[group].enabled) {
+ dev_err(p->dev, "%s is already enabled\n", p->groups[group].name);
+ return -EBUSY;
+ }
+
+ p->groups[group].enabled = 1;
+ p->func[func]->enabled = 1;
+
+ shift = p->groups[group].shift;
+ if (shift >= 32) {
+ shift -= 32;
+ reg = SYSC_REG_GPIO_MODE2;
+ }
+ mode = rt_sysc_r32(reg);
+ mode &= ~(p->groups[group].mask << shift);
+
+ /* mark the pins as gpio */
+ for (i = 0; i < p->groups[group].func[0].pin_count; i++)
+ p->gpio[p->groups[group].func[0].pins[i]] = 1;
+
+ /* function 0 is gpio and needs special handling */
+ if (func == 0) {
+ mode |= p->groups[group].gpio << shift;
+ } else {
+ for (i = 0; i < p->func[func]->pin_count; i++)
+ p->gpio[p->func[func]->pins[i]] = 0;
+ mode |= p->func[func]->value << shift;
+ }
+ rt_sysc_w32(mode, reg);
+
+ return 0;
+}
+
+static int rt2880_pmx_group_gpio_request_enable(struct pinctrl_dev *pctrldev,
+ struct pinctrl_gpio_range *range,
+ unsigned pin)
+{
+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
+
+ if (!p->gpio[pin]) {
+ dev_err(p->dev, "pin %d is not set to gpio mux\n", pin);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct pinmux_ops rt2880_pmx_group_ops = {
+ .get_functions_count = rt2880_pmx_func_count,
+ .get_function_name = rt2880_pmx_func_name,
+ .get_function_groups = rt2880_pmx_group_get_groups,
+ .set_mux = rt2880_pmx_group_enable,
+ .gpio_request_enable = rt2880_pmx_group_gpio_request_enable,
+};
+
+static struct pinctrl_desc rt2880_pctrl_desc = {
+ .owner = THIS_MODULE,
+ .name = "rt2880-pinmux",
+ .pctlops = &rt2880_pctrl_ops,
+ .pmxops = &rt2880_pmx_group_ops,
+};
+
+static struct rt2880_pmx_func gpio_func = {
+ .name = "gpio",
+};
+
+static int rt2880_pinmux_index(struct rt2880_priv *p)
+{
+ struct rt2880_pmx_func **f;
+ struct rt2880_pmx_group *mux = p->groups;
+ int i, j, c = 0;
+
+ /* count the mux functions */
+ while (mux->name) {
+ p->group_count++;
+ mux++;
+ }
+
+ /* allocate the group names array needed by the gpio function */
+ p->group_names = devm_kzalloc(p->dev, sizeof(char *) * p->group_count, GFP_KERNEL);
+ if (!p->group_names)
+ return -1;
+
+ for (i = 0; i < p->group_count; i++) {
+ p->group_names[i] = p->groups[i].name;
+ p->func_count += p->groups[i].func_count;
+ }
+
+ /* we have a dummy function[0] for gpio */
+ p->func_count++;
+
+ /* allocate our function and group mapping index buffers */
+ f = p->func = devm_kzalloc(p->dev, sizeof(struct rt2880_pmx_func) * p->func_count, GFP_KERNEL);
+ gpio_func.groups = devm_kzalloc(p->dev, sizeof(int) * p->group_count, GFP_KERNEL);
+ if (!f || !gpio_func.groups)
+ return -1;
+
+ /* add a backpointer to the function so it knows its group */
+ gpio_func.group_count = p->group_count;
+ for (i = 0; i < gpio_func.group_count; i++)
+ gpio_func.groups[i] = i;
+
+ f[c] = &gpio_func;
+ c++;
+
+ /* add remaining functions */
+ for (i = 0; i < p->group_count; i++) {
+ for (j = 0; j < p->groups[i].func_count; j++) {
+ f[c] = &p->groups[i].func[j];
+ f[c]->groups = devm_kzalloc(p->dev, sizeof(int), GFP_KERNEL);
+ f[c]->groups[0] = i;
+ f[c]->group_count = 1;
+ c++;
+ }
+ }
+ return 0;
+}
+
+static int rt2880_pinmux_pins(struct rt2880_priv *p)
+{
+ int i, j;
+
+ /* loop over the functions and initialize the pins array. also work out the highest pin used */
+ for (i = 0; i < p->func_count; i++) {
+ int pin;
+
+ if (!p->func[i]->pin_count)
+ continue;
+
+ p->func[i]->pins = devm_kzalloc(p->dev, sizeof(int) * p->func[i]->pin_count, GFP_KERNEL);
+ for (j = 0; j < p->func[i]->pin_count; j++)
+ p->func[i]->pins[j] = p->func[i]->pin_first + j;
+
+ pin = p->func[i]->pin_first + p->func[i]->pin_count;
+ if (pin > p->max_pins)
+ p->max_pins = pin;
+ }
+
+ /* the buffer that tells us which pins are gpio */
+ p->gpio = devm_kzalloc(p->dev,sizeof(uint8_t) * p->max_pins,
+ GFP_KERNEL);
+ /* the pads needed to tell pinctrl about our pins */
+ p->pads = devm_kzalloc(p->dev,
+ sizeof(struct pinctrl_pin_desc) * p->max_pins,
+ GFP_KERNEL);
+ if (!p->pads || !p->gpio ) {
+ dev_err(p->dev, "Failed to allocate gpio data\n");
+ return -ENOMEM;
+ }
+
+ memset(p->gpio, 1, sizeof(uint8_t) * p->max_pins);
+ for (i = 0; i < p->func_count; i++) {
+ if (!p->func[i]->pin_count)
+ continue;
+
+ for (j = 0; j < p->func[i]->pin_count; j++)
+ p->gpio[p->func[i]->pins[j]] = 0;
+ }
+
+ /* pin 0 is always a gpio */
+ p->gpio[0] = 1;
+
+ /* set the pads */
+ for (i = 0; i < p->max_pins; i++) {
+ /* strlen("ioXY") + 1 = 5 */
+ char *name = devm_kzalloc(p->dev, 5, GFP_KERNEL);
+
+ if (!name) {
+ dev_err(p->dev, "Failed to allocate pad name\n");
+ return -ENOMEM;
+ }
+ snprintf(name, 5, "io%d", i);
+ p->pads[i].number = i;
+ p->pads[i].name = name;
+ }
+ p->desc->pins = p->pads;
+ p->desc->npins = p->max_pins;
+
+ return 0;
+}
+
+static int rt2880_pinmux_probe(struct platform_device *pdev)
+{
+ struct rt2880_priv *p;
+ struct pinctrl_dev *dev;
+ struct device_node *np;
+
+ if (!rt2880_pinmux_data)
+ return -ENOSYS;
+
+ /* setup the private data */
+ p = devm_kzalloc(&pdev->dev, sizeof(struct rt2880_priv), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ p->dev = &pdev->dev;
+ p->desc = &rt2880_pctrl_desc;
+ p->groups = rt2880_pinmux_data;
+ platform_set_drvdata(pdev, p);
+
+ /* init the device */
+ if (rt2880_pinmux_index(p)) {
+ dev_err(&pdev->dev, "failed to load index\n");
+ return -EINVAL;
+ }
+ if (rt2880_pinmux_pins(p)) {
+ dev_err(&pdev->dev, "failed to load pins\n");
+ return -EINVAL;
+ }
+ dev = pinctrl_register(p->desc, &pdev->dev, p);
+ if (IS_ERR(dev))
+ return PTR_ERR(dev);
+
+ /* finalize by adding gpio ranges for enables gpio controllers */
+ for_each_compatible_node(np, NULL, "ralink,rt2880-gpio") {
+ const __be32 *ngpio, *gpiobase;
+ struct pinctrl_gpio_range *range;
+ char *name;
+
+ if (!of_device_is_available(np))
+ continue;
+
+ ngpio = of_get_property(np, "ralink,num-gpios", NULL);
+ gpiobase = of_get_property(np, "ralink,gpio-base", NULL);
+ if (!ngpio || !gpiobase) {
+ dev_err(&pdev->dev, "failed to load chip info\n");
+ return -EINVAL;
+ }
+
+ range = devm_kzalloc(p->dev, sizeof(struct pinctrl_gpio_range) + 4, GFP_KERNEL);
+ range->name = name = (char *) &range[1];
+ sprintf(name, "pio");
+ range->npins = __be32_to_cpu(*ngpio);
+ range->base = __be32_to_cpu(*gpiobase);
+ range->pin_base = range->base;
+ pinctrl_add_gpio_range(dev, range);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id rt2880_pinmux_match[] = {
+ { .compatible = "ralink,rt2880-pinmux" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt2880_pinmux_match);
+
+static struct platform_driver rt2880_pinmux_driver = {
+ .probe = rt2880_pinmux_probe,
+ .driver = {
+ .name = "rt2880-pinmux",
+ .owner = THIS_MODULE,
+ .of_match_table = rt2880_pinmux_match,
+ },
+};
+
+int __init rt2880_pinmux_init(void)
+{
+ return platform_driver_register(&rt2880_pinmux_driver);
+}
+
+core_initcall_sync(rt2880_pinmux_init);
diff --git a/drivers/staging/mt7621-spi/Kconfig b/drivers/staging/mt7621-spi/Kconfig
new file mode 100644
index 000000000000..0b90f4cfa426
--- /dev/null
+++ b/drivers/staging/mt7621-spi/Kconfig
@@ -0,0 +1,6 @@
+config SPI_MT7621
+ tristate "MediaTek MT7621 SPI Controller"
+ depends on RALINK
+ help
+ This selects a driver for the MediaTek MT7621 SPI Controller.
+
diff --git a/drivers/staging/mt7621-spi/Makefile b/drivers/staging/mt7621-spi/Makefile
new file mode 100644
index 000000000000..3be508f63bac
--- /dev/null
+++ b/drivers/staging/mt7621-spi/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SPI_MT7621) += spi-mt7621.o
diff --git a/drivers/staging/mt7621-spi/TODO b/drivers/staging/mt7621-spi/TODO
new file mode 100644
index 000000000000..fdbc5002c32a
--- /dev/null
+++ b/drivers/staging/mt7621-spi/TODO
@@ -0,0 +1,5 @@
+
+- general code review and clean up
+- ensure device-tree requirements are documented
+
+Cc: NeilBrown <neil@brown.name>
diff --git a/drivers/staging/mt7621-spi/spi-mt7621.c b/drivers/staging/mt7621-spi/spi-mt7621.c
new file mode 100644
index 000000000000..d95e0b32f1f0
--- /dev/null
+++ b/drivers/staging/mt7621-spi/spi-mt7621.c
@@ -0,0 +1,489 @@
+/*
+ * spi-mt7621.c -- MediaTek MT7621 SPI controller driver
+ *
+ * Copyright (C) 2011 Sergiy <piratfm@gmail.com>
+ * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name>
+ *
+ * Some parts are based on spi-orion.c:
+ * Author: Shadi Ammouri <shadi@marvell.com>
+ * Copyright (C) 2007-2008 Marvell 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/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/reset.h>
+#include <linux/spi/spi.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/swab.h>
+
+#include <ralink_regs.h>
+
+#define SPI_BPW_MASK(bits) BIT((bits) - 1)
+
+#define DRIVER_NAME "spi-mt7621"
+/* in usec */
+#define RALINK_SPI_WAIT_MAX_LOOP 2000
+
+/* SPISTAT register bit field */
+#define SPISTAT_BUSY BIT(0)
+
+#define MT7621_SPI_TRANS 0x00
+#define SPITRANS_BUSY BIT(16)
+
+#define MT7621_SPI_OPCODE 0x04
+#define MT7621_SPI_DATA0 0x08
+#define MT7621_SPI_DATA4 0x18
+#define SPI_CTL_TX_RX_CNT_MASK 0xff
+#define SPI_CTL_START BIT(8)
+
+#define MT7621_SPI_POLAR 0x38
+#define MT7621_SPI_MASTER 0x28
+#define MT7621_SPI_MOREBUF 0x2c
+#define MT7621_SPI_SPACE 0x3c
+
+#define MT7621_CPHA BIT(5)
+#define MT7621_CPOL BIT(4)
+#define MT7621_LSB_FIRST BIT(3)
+
+#define RT2880_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH)
+
+struct mt7621_spi;
+
+struct mt7621_spi {
+ struct spi_master *master;
+ void __iomem *base;
+ unsigned int sys_freq;
+ unsigned int speed;
+ struct clk *clk;
+ spinlock_t lock;
+
+ struct mt7621_spi_ops *ops;
+};
+
+static inline struct mt7621_spi *spidev_to_mt7621_spi(struct spi_device *spi)
+{
+ return spi_master_get_devdata(spi->master);
+}
+
+static inline u32 mt7621_spi_read(struct mt7621_spi *rs, u32 reg)
+{
+ return ioread32(rs->base + reg);
+}
+
+static inline void mt7621_spi_write(struct mt7621_spi *rs, u32 reg, u32 val)
+{
+ iowrite32(val, rs->base + reg);
+}
+
+static void mt7621_spi_reset(struct mt7621_spi *rs, int duplex)
+{
+ u32 master = mt7621_spi_read(rs, MT7621_SPI_MASTER);
+
+ master |= 7 << 29;
+ master |= 1 << 2;
+ if (duplex)
+ master |= 1 << 10;
+ else
+ master &= ~(1 << 10);
+
+ mt7621_spi_write(rs, MT7621_SPI_MASTER, master);
+}
+
+static void mt7621_spi_set_cs(struct spi_device *spi, int enable)
+{
+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
+ int cs = spi->chip_select;
+ u32 polar = 0;
+
+ mt7621_spi_reset(rs, cs);
+ if (enable)
+ polar = BIT(cs);
+ mt7621_spi_write(rs, MT7621_SPI_POLAR, polar);
+}
+
+static int mt7621_spi_prepare(struct spi_device *spi, unsigned int speed)
+{
+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
+ u32 rate;
+ u32 reg;
+
+ dev_dbg(&spi->dev, "speed:%u\n", speed);
+
+ rate = DIV_ROUND_UP(rs->sys_freq, speed);
+ dev_dbg(&spi->dev, "rate-1:%u\n", rate);
+
+ if (rate > 4097)
+ return -EINVAL;
+
+ if (rate < 2)
+ rate = 2;
+
+ reg = mt7621_spi_read(rs, MT7621_SPI_MASTER);
+ reg &= ~(0xfff << 16);
+ reg |= (rate - 2) << 16;
+ rs->speed = speed;
+
+ reg &= ~MT7621_LSB_FIRST;
+ if (spi->mode & SPI_LSB_FIRST)
+ reg |= MT7621_LSB_FIRST;
+
+ reg &= ~(MT7621_CPHA | MT7621_CPOL);
+ switch(spi->mode & (SPI_CPOL | SPI_CPHA)) {
+ case SPI_MODE_0:
+ break;
+ case SPI_MODE_1:
+ reg |= MT7621_CPHA;
+ break;
+ case SPI_MODE_2:
+ reg |= MT7621_CPOL;
+ break;
+ case SPI_MODE_3:
+ reg |= MT7621_CPOL | MT7621_CPHA;
+ break;
+ }
+ mt7621_spi_write(rs, MT7621_SPI_MASTER, reg);
+
+ return 0;
+}
+
+static inline int mt7621_spi_wait_till_ready(struct spi_device *spi)
+{
+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
+ int i;
+
+ for (i = 0; i < RALINK_SPI_WAIT_MAX_LOOP; i++) {
+ u32 status;
+
+ status = mt7621_spi_read(rs, MT7621_SPI_TRANS);
+ if ((status & SPITRANS_BUSY) == 0) {
+ return 0;
+ }
+ cpu_relax();
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int mt7621_spi_transfer_half_duplex(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct mt7621_spi *rs = spi_master_get_devdata(master);
+ struct spi_device *spi = m->spi;
+ unsigned int speed = spi->max_speed_hz;
+ struct spi_transfer *t = NULL;
+ int status = 0;
+ int i, len = 0;
+ int rx_len = 0;
+ u32 data[9] = { 0 };
+ u32 val;
+
+ mt7621_spi_wait_till_ready(spi);
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ const u8 *buf = t->tx_buf;
+
+ if (t->rx_buf)
+ rx_len += t->len;
+
+ if (!buf)
+ continue;
+
+ if (t->speed_hz < speed)
+ speed = t->speed_hz;
+
+ if (WARN_ON(len + t->len > 36)) {
+ status = -EIO;
+ goto msg_done;
+ }
+
+ for (i = 0; i < t->len; i++, len++)
+ data[len / 4] |= buf[i] << (8 * (len & 3));
+ }
+
+ if (WARN_ON(rx_len > 32)) {
+ status = -EIO;
+ goto msg_done;
+ }
+
+ if (mt7621_spi_prepare(spi, speed)) {
+ status = -EIO;
+ goto msg_done;
+ }
+ data[0] = swab32(data[0]);
+ if (len < 4)
+ data[0] >>= (4 - len) * 8;
+
+ for (i = 0; i < len; i += 4)
+ mt7621_spi_write(rs, MT7621_SPI_OPCODE + i, data[i / 4]);
+
+ val = (min_t(int, len, 4) * 8) << 24;
+ if (len > 4)
+ val |= (len - 4) * 8;
+ val |= (rx_len * 8) << 12;
+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);
+
+ mt7621_spi_set_cs(spi, 1);
+
+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS);
+ val |= SPI_CTL_START;
+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val);
+
+ mt7621_spi_wait_till_ready(spi);
+
+ mt7621_spi_set_cs(spi, 0);
+
+ for (i = 0; i < rx_len; i += 4)
+ data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i);
+
+ m->actual_length = len + rx_len;
+
+ len = 0;
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ u8 *buf = t->rx_buf;
+
+ if (!buf)
+ continue;
+
+ for (i = 0; i < t->len; i++, len++)
+ buf[i] = data[len / 4] >> (8 * (len & 3));
+ }
+
+msg_done:
+ m->status = status;
+ spi_finalize_current_message(master);
+
+ return 0;
+}
+
+static int mt7621_spi_transfer_full_duplex(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct mt7621_spi *rs = spi_master_get_devdata(master);
+ struct spi_device *spi = m->spi;
+ unsigned int speed = spi->max_speed_hz;
+ struct spi_transfer *t = NULL;
+ int status = 0;
+ int i, len = 0;
+ int rx_len = 0;
+ u32 data[9] = { 0 };
+ u32 val = 0;
+
+ mt7621_spi_wait_till_ready(spi);
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ const u8 *buf = t->tx_buf;
+
+ if (t->rx_buf)
+ rx_len += t->len;
+
+ if (!buf)
+ continue;
+
+ if (WARN_ON(len + t->len > 16)) {
+ status = -EIO;
+ goto msg_done;
+ }
+
+ for (i = 0; i < t->len; i++, len++)
+ data[len / 4] |= buf[i] << (8 * (len & 3));
+ if (speed > t->speed_hz)
+ speed = t->speed_hz;
+ }
+
+ if (WARN_ON(rx_len > 16)) {
+ status = -EIO;
+ goto msg_done;
+ }
+
+ if (mt7621_spi_prepare(spi, speed)) {
+ status = -EIO;
+ goto msg_done;
+ }
+
+ for (i = 0; i < len; i += 4)
+ mt7621_spi_write(rs, MT7621_SPI_DATA0 + i, data[i / 4]);
+
+ val |= len * 8;
+ val |= (rx_len * 8) << 12;
+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);
+
+ mt7621_spi_set_cs(spi, 1);
+
+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS);
+ val |= SPI_CTL_START;
+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val);
+
+ mt7621_spi_wait_till_ready(spi);
+
+ mt7621_spi_set_cs(spi, 0);
+
+ for (i = 0; i < rx_len; i += 4)
+ data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA4 + i);
+
+ m->actual_length = rx_len;
+
+ len = 0;
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ u8 *buf = t->rx_buf;
+
+ if (!buf)
+ continue;
+
+ for (i = 0; i < t->len; i++, len++)
+ buf[i] = data[len / 4] >> (8 * (len & 3));
+ }
+
+msg_done:
+ m->status = status;
+ spi_finalize_current_message(master);
+
+ return 0;
+}
+
+static int mt7621_spi_transfer_one_message(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct spi_device *spi = m->spi;
+ int cs = spi->chip_select;
+
+ if (cs)
+ return mt7621_spi_transfer_full_duplex(master, m);
+ return mt7621_spi_transfer_half_duplex(master, m);
+}
+
+static int mt7621_spi_setup(struct spi_device *spi)
+{
+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
+
+ if ((spi->max_speed_hz == 0) ||
+ (spi->max_speed_hz > (rs->sys_freq / 2)))
+ spi->max_speed_hz = (rs->sys_freq / 2);
+
+ if (spi->max_speed_hz < (rs->sys_freq / 4097)) {
+ dev_err(&spi->dev, "setup: requested speed is too low %d Hz\n",
+ spi->max_speed_hz);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id mt7621_spi_match[] = {
+ { .compatible = "ralink,mt7621-spi" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt7621_spi_match);
+
+static size_t max_transfer_size(struct spi_device *spi)
+{
+ return 32;
+}
+
+static int mt7621_spi_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct spi_master *master;
+ struct mt7621_spi *rs;
+ unsigned long flags;
+ void __iomem *base;
+ struct resource *r;
+ int status = 0;
+ struct clk *clk;
+ struct mt7621_spi_ops *ops;
+
+ match = of_match_device(mt7621_spi_match, &pdev->dev);
+ if (!match)
+ return -EINVAL;
+ ops = (struct mt7621_spi_ops *)match->data;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "unable to get SYS clock, err=%d\n",
+ status);
+ return PTR_ERR(clk);
+ }
+
+ status = clk_prepare_enable(clk);
+ if (status)
+ return status;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*rs));
+ if (master == NULL) {
+ dev_info(&pdev->dev, "master allocation failed\n");
+ return -ENOMEM;
+ }
+
+ master->mode_bits = RT2880_SPI_MODE_BITS;
+
+ master->setup = mt7621_spi_setup;
+ master->transfer_one_message = mt7621_spi_transfer_one_message;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->dev.of_node = pdev->dev.of_node;
+ master->num_chipselect = 2;
+ master->max_transfer_size = max_transfer_size;
+
+ dev_set_drvdata(&pdev->dev, master);
+
+ rs = spi_master_get_devdata(master);
+ rs->base = base;
+ rs->clk = clk;
+ rs->master = master;
+ rs->sys_freq = clk_get_rate(rs->clk);
+ rs->ops = ops;
+ dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq);
+ spin_lock_irqsave(&rs->lock, flags);
+
+ device_reset(&pdev->dev);
+
+ mt7621_spi_reset(rs, 0);
+
+ return spi_register_master(master);
+}
+
+static int mt7621_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct mt7621_spi *rs;
+
+ master = dev_get_drvdata(&pdev->dev);
+ rs = spi_master_get_devdata(master);
+
+ clk_disable(rs->clk);
+ spi_unregister_master(master);
+
+ return 0;
+}
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+
+static struct platform_driver mt7621_spi_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = mt7621_spi_match,
+ },
+ .probe = mt7621_spi_probe,
+ .remove = mt7621_spi_remove,
+};
+
+module_platform_driver(mt7621_spi_driver);
+
+MODULE_DESCRIPTION("MT7621 SPI driver");
+MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c
index 30532d8c310b..e461168313bf 100644
--- a/drivers/staging/netlogic/xlr_net.c
+++ b/drivers/staging/netlogic/xlr_net.c
@@ -993,8 +993,7 @@ static int xlr_net_probe(struct platform_device *pdev)
/*
* Allocate our adapter data structure and attach it to the device.
*/
- adapter = (struct xlr_adapter *)
- devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL);
+ adapter = devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL);
if (!adapter)
return -ENOMEM;
diff --git a/drivers/staging/pi433/Documentation/pi433.txt b/drivers/staging/pi433/Documentation/pi433.txt
index 7d9dc2244848..d0b7000faafc 100644
--- a/drivers/staging/pi433/Documentation/pi433.txt
+++ b/drivers/staging/pi433/Documentation/pi433.txt
@@ -92,7 +92,7 @@ rf params:
shaping0_3 - gauss filter with BT 0.3 (FSK only)
shapingBR - filter cut off at BR (OOK only)
shaping2BR - filter cut off at 2*BR (OOK only)
- paRamp (FSK only)
+ pa_ramp (FSK only)
ramp3400 - amp ramps up in 3.4ms
ramp2000 - amp ramps up in 2.0ms
ramp1000 - amp ramps up in 1ms
@@ -180,7 +180,7 @@ rf params:
threshold value for the signal strength on the receiver input.
If this value is exceeded, a reception cycle starts
Allowed values: 0...255
- thresholdDecrement
+ threshold_decrement
in order to adapt to different levels of singnal strength, over
time the receiver gets more and more sensitive. This value
determs, how fast the sensitivity increases.
@@ -192,11 +192,11 @@ rf params:
step_4_0db - increase in 4 db steps
step_5_0db - increase in 5 db steps
step_6_0db - increase in 6 db steps
- antennaImpedance
+ antenna_impedance
sets the electrical adoption of the antenna
- fiftyOhm - for antennas with an impedance of 50Ohm
- twohundretOhm - for antennas with an impedance of 200Ohm
- lnaGain
+ fifty_ohm - for antennas with an impedance of 50Ohm
+ two_hundred_ohm - for antennas with an impedance of 200Ohm
+ lna_gain
sets the gain of the low noise amp
automatic - lna gain is determined by an agc
max - lna gain is set to maximum
@@ -215,9 +215,9 @@ rf params:
Allowd values: 0...7
dagc;
operation mode of the digital automatic gain control
- normalMode
+ normal_mode
improve
- improve4LowModulationIndex
+ improve_for_low_modulation_index
packet format:
enable_sync
@@ -232,12 +232,12 @@ rf params:
amount of bytes that were requested by the read request.
Attention: should be used in combination with sync, only
enable_address_filtering;
- filteringOff - no address filtering will take place
- nodeAddress - all telegrams, not matching the node
- address will be internally discarded
- nodeOrBroadcastAddress - all telegrams, neither matching the
- node, nor the broadcast address will
- be internally discarded
+ filtering_off - no address filtering will take place
+ node_address - all telegrams, not matching the node
+ address will be internally discarded
+ node_or_broadcast_address - all telegrams, neither matching the
+ node, nor the broadcast address will
+ be internally discarded
Attention: Sync option must be enabled in order to use this feature
enable_crc
optionOn - a crc will be calculated over the payload of
diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
index edcd7e798f99..d1e0ddbc79ce 100644
--- a/drivers/staging/pi433/pi433_if.c
+++ b/drivers/staging/pi433/pi433_if.c
@@ -187,10 +187,12 @@ rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg)
ret = rf69_set_ook_threshold_dec(dev->spi, rx_cfg->threshold_decrement);
if (ret < 0)
return ret;
- ret = rf69_set_bandwidth(dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent);
+ ret = rf69_set_bandwidth(dev->spi, rx_cfg->bw_mantisse,
+ rx_cfg->bw_exponent);
if (ret < 0)
return ret;
- ret = rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent);
+ ret = rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse,
+ rx_cfg->bw_exponent);
if (ret < 0)
return ret;
ret = rf69_set_dagc(dev->spi, rx_cfg->dagc);
@@ -206,7 +208,8 @@ rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg)
if (ret < 0)
return ret;
- ret = rf69_set_fifo_fill_condition(dev->spi, afterSyncInterrupt);
+ ret = rf69_set_fifo_fill_condition(dev->spi,
+ after_sync_interrupt);
if (ret < 0)
return ret;
} else {
@@ -219,15 +222,16 @@ rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg)
return ret;
}
if (rx_cfg->enable_length_byte == OPTION_ON) {
- ret = rf69_set_packet_format(dev->spi, packetLengthVar);
+ ret = rf69_set_packet_format(dev->spi, packet_length_var);
if (ret < 0)
return ret;
} else {
- ret = rf69_set_packet_format(dev->spi, packetLengthFix);
+ ret = rf69_set_packet_format(dev->spi, packet_length_fix);
if (ret < 0)
return ret;
}
- ret = rf69_set_adressFiltering(dev->spi, rx_cfg->enable_address_filtering);
+ ret = rf69_set_address_filtering(dev->spi,
+ rx_cfg->enable_address_filtering);
if (ret < 0)
return ret;
@@ -253,7 +257,7 @@ rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg)
payload_length = rx_cfg->fixed_message_length;
if (rx_cfg->enable_length_byte == OPTION_ON)
payload_length++;
- if (rx_cfg->enable_address_filtering != filteringOff)
+ if (rx_cfg->enable_address_filtering != filtering_off)
payload_length++;
ret = rf69_set_payload_length(dev->spi, payload_length);
if (ret < 0)
@@ -270,11 +274,12 @@ rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg)
if (ret < 0)
return ret;
}
- if (rx_cfg->enable_address_filtering != filteringOff) {
+ if (rx_cfg->enable_address_filtering != filtering_off) {
ret = rf69_set_node_address(dev->spi, rx_cfg->node_address);
if (ret < 0)
return ret;
- ret = rf69_set_broadcast_address(dev->spi, rx_cfg->broadcast_address);
+ ret = rf69_set_broadcast_address(dev->spi,
+ rx_cfg->broadcast_address);
if (ret < 0)
return ret;
}
@@ -311,7 +316,8 @@ rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg)
/* packet format enable */
if (tx_cfg->enable_preamble == OPTION_ON) {
- ret = rf69_set_preamble_length(dev->spi, tx_cfg->preamble_length);
+ ret = rf69_set_preamble_length(dev->spi,
+ tx_cfg->preamble_length);
if (ret < 0)
return ret;
} else {
@@ -331,11 +337,11 @@ rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg)
}
if (tx_cfg->enable_length_byte == OPTION_ON) {
- ret = rf69_set_packet_format(dev->spi, packetLengthVar);
+ ret = rf69_set_packet_format(dev->spi, packet_length_var);
if (ret < 0)
return ret;
} else {
- ret = rf69_set_packet_format(dev->spi, packetLengthFix);
+ ret = rf69_set_packet_format(dev->spi, packet_length_fix);
if (ret < 0)
return ret;
}
@@ -437,7 +443,7 @@ pi433_receive(void *data)
return retval;
/* now check RSSI, if low wait for getting high (RSSI interrupt) */
- while (!rf69_get_flag(dev->spi, rssiExceededThreshold)) {
+ while (!rf69_get_flag(dev->spi, rssi_exceeded_threshold)) {
/* allow tx to interrupt us while waiting for high RSSI */
dev->interrupt_rx_allowed = true;
wake_up_interruptible(&dev->tx_wait_queue);
@@ -446,7 +452,7 @@ pi433_receive(void *data)
dev_dbg(dev->dev, "rx: going to wait for high RSSI level");
retval = wait_event_interruptible(dev->rx_wait_queue,
rf69_get_flag(dev->spi,
- rssiExceededThreshold));
+ rssi_exceeded_threshold));
if (retval) /* wait was interrupted */
goto abort;
dev->interrupt_rx_allowed = false;
@@ -470,10 +476,12 @@ pi433_receive(void *data)
goto abort;
}
bytes_total = dev->rx_cfg.fixed_message_length;
- dev_dbg(dev->dev, "rx: msg len set to %d by fixed length", bytes_total);
+ dev_dbg(dev->dev, "rx: msg len set to %d by fixed length",
+ bytes_total);
} else {
bytes_total = dev->rx_buffer_size;
- dev_dbg(dev->dev, "rx: msg len set to %d as requested by read", bytes_total);
+ dev_dbg(dev->dev, "rx: msg len set to %d as requested by read",
+ bytes_total);
}
/* length byte enabled? */
@@ -489,11 +497,12 @@ pi433_receive(void *data)
goto abort;
}
dev->free_in_fifo++;
- dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte", bytes_total);
+ dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte",
+ bytes_total);
}
/* address byte enabled? */
- if (dev->rx_cfg.enable_address_filtering != filteringOff) {
+ if (dev->rx_cfg.enable_address_filtering != filtering_off) {
u8 dummy;
bytes_total--;
@@ -519,7 +528,8 @@ pi433_receive(void *data)
/* need to drop bytes or acquire? */
if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped)
- bytes_to_read = dev->rx_bytes_to_drop - dev->rx_bytes_dropped;
+ bytes_to_read = dev->rx_bytes_to_drop -
+ dev->rx_bytes_dropped;
else
bytes_to_read = bytes_total - dev->rx_position;
@@ -620,8 +630,10 @@ pi433_tx_thread(void *data)
device->buffer[position++] = tx_cfg.address_byte;
/* finally get message data from fifo */
- retval = kfifo_out(&device->tx_fifo, &device->buffer[position], sizeof(device->buffer) - position);
- dev_dbg(device->dev, "read %d message byte(s) from fifo queue.", retval);
+ retval = kfifo_out(&device->tx_fifo, &device->buffer[position],
+ sizeof(device->buffer) - position);
+ dev_dbg(device->dev,
+ "read %d message byte(s) from fifo queue.", retval);
mutex_unlock(&device->tx_fifo_lock);
/* if rx is active, we need to interrupt the waiting for
@@ -699,12 +711,13 @@ pi433_tx_thread(void *data)
while ((repetitions > 0) && (size > position)) {
if ((size - position) > device->free_in_fifo) {
/* msg to big for fifo - take a part */
- int temp = device->free_in_fifo;
+ int write_size = device->free_in_fifo;
+
device->free_in_fifo = 0;
rf69_write_fifo(spi,
&device->buffer[position],
- temp);
- position += temp;
+ write_size);
+ position += write_size;
} else {
/* msg fits into fifo - take all */
device->free_in_fifo -= size;
@@ -724,7 +737,8 @@ pi433_tx_thread(void *data)
}
/* we are done. Wait for packet to get sent */
- dev_dbg(device->dev, "thread: wait for packet to get sent/fifo to be empty");
+ dev_dbg(device->dev,
+ "thread: wait for packet to get sent/fifo to be empty");
wait_event_interruptible(device->fifo_wait_queue,
device->free_in_fifo == FIFO_SIZE ||
kthread_should_stop());
@@ -819,7 +833,8 @@ pi433_write(struct file *filp, const char __user *buf,
* - message
*/
mutex_lock(&device->tx_fifo_lock);
- retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg, sizeof(instance->tx_cfg));
+ retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg,
+ sizeof(instance->tx_cfg));
if (retval != sizeof(instance->tx_cfg))
goto abort;
@@ -983,7 +998,7 @@ static int pi433_release(struct inode *inode, struct file *filp)
/*-------------------------------------------------------------------------*/
-static int setup_GPIOs(struct pi433_device *device)
+static int setup_gpio(struct pi433_device *device)
{
char name[5];
int retval;
@@ -996,10 +1011,12 @@ static int setup_GPIOs(struct pi433_device *device)
for (i = 0; i < NUM_DIO; i++) {
/* "construct" name and get the gpio descriptor */
snprintf(name, sizeof(name), "DIO%d", i);
- device->gpiod[i] = gpiod_get(&device->spi->dev, name, 0 /*GPIOD_IN*/);
+ device->gpiod[i] = gpiod_get(&device->spi->dev, name,
+ 0 /*GPIOD_IN*/);
if (device->gpiod[i] == ERR_PTR(-ENOENT)) {
- dev_dbg(&device->spi->dev, "Could not find entry for %s. Ignoring.", name);
+ dev_dbg(&device->spi->dev,
+ "Could not find entry for %s. Ignoring.", name);
continue;
}
@@ -1043,7 +1060,7 @@ static int setup_GPIOs(struct pi433_device *device)
return 0;
}
-static void free_GPIOs(struct pi433_device *device)
+static void free_gpio(struct pi433_device *device)
{
int i;
@@ -1158,7 +1175,7 @@ static int pi433_probe(struct spi_device *spi)
mutex_init(&device->rx_lock);
/* setup GPIO (including irq_handler) for the different DIOs */
- retval = setup_GPIOs(device);
+ retval = setup_gpio(device);
if (retval) {
dev_dbg(&spi->dev, "setup of GPIOs failed");
goto GPIO_failed;
@@ -1183,7 +1200,7 @@ static int pi433_probe(struct spi_device *spi)
retval = rf69_set_output_power_level(spi, 13);
if (retval < 0)
goto minor_failed;
- retval = rf69_set_antenna_impedance(spi, fiftyOhm);
+ retval = rf69_set_antenna_impedance(spi, fifty_ohm);
if (retval < 0)
goto minor_failed;
@@ -1245,7 +1262,7 @@ send_thread_failed:
device_create_failed:
pi433_free_minor(device);
minor_failed:
- free_GPIOs(device);
+ free_gpio(device);
GPIO_failed:
kfree(device);
@@ -1257,7 +1274,7 @@ static int pi433_remove(struct spi_device *spi)
struct pi433_device *device = spi_get_drvdata(spi);
/* free GPIOs */
- free_GPIOs(device);
+ free_gpio(device);
/* make sure ops on existing fds can abort cleanly */
device->spi = NULL;
@@ -1315,7 +1332,7 @@ static int __init pi433_init(void)
* that will key udev/mdev to add/remove /dev nodes. Last, register
* Last, register the driver which manages those device numbers.
*/
- status = alloc_chrdev_region(&pi433_dev, 0 /*firstminor*/, N_PI433_MINORS /*count*/, "pi433" /*name*/);
+ status = alloc_chrdev_region(&pi433_dev, 0, N_PI433_MINORS, "pi433");
if (status < 0)
return status;
diff --git a/drivers/staging/pi433/pi433_if.h b/drivers/staging/pi433/pi433_if.h
index 7314f69af198..b6e214c29ddf 100644
--- a/drivers/staging/pi433/pi433_if.h
+++ b/drivers/staging/pi433/pi433_if.h
@@ -67,9 +67,9 @@ struct pi433_tx_cfg {
enum modulation modulation;
enum mod_shaping mod_shaping;
- enum paRamp pa_ramp;
+ enum pa_ramp pa_ramp;
- enum txStartCondition tx_start_condition;
+ enum tx_start_condition tx_start_condition;
__u16 repetitions;
@@ -115,9 +115,9 @@ struct pi433_rx_cfg {
enum modulation modulation;
__u8 rssi_threshold;
- enum thresholdDecrement threshold_decrement;
- enum antennaImpedance antenna_impedance;
- enum lnaGain lna_gain;
+ enum threshold_decrement threshold_decrement;
+ enum antenna_impedance antenna_impedance;
+ enum lna_gain lna_gain;
enum mantisse bw_mantisse; /* normal: 0x50 */
__u8 bw_exponent; /* during AFC: 0x8b */
enum dagc dagc;
@@ -125,7 +125,7 @@ struct pi433_rx_cfg {
/* packet format */
enum option_on_off enable_sync;
enum option_on_off enable_length_byte; /* should be used in combination with sync, only */
- enum addressFiltering enable_address_filtering; /* operational with sync, only */
+ enum address_filtering enable_address_filtering; /* operational with sync, only */
enum option_on_off enable_crc; /* only operational, if sync on and fixed length or length byte is used */
__u8 sync_length;
diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c
index 7ccdff6ae213..5b0554823263 100644
--- a/drivers/staging/pi433/rf69.c
+++ b/drivers/staging/pi433/rf69.c
@@ -151,11 +151,11 @@ int rf69_set_modulation(struct spi_device *spi, enum modulation modulation)
static enum modulation rf69_get_modulation(struct spi_device *spi)
{
- u8 currentValue;
+ u8 modulation_reg;
- currentValue = rf69_read_reg(spi, REG_DATAMODUL);
+ modulation_reg = rf69_read_reg(spi, REG_DATAMODUL);
- switch (currentValue & MASK_DATAMODUL_MODULATION_TYPE) {
+ switch (modulation_reg & MASK_DATAMODUL_MODULATION_TYPE) {
case DATAMODUL_MODULATION_TYPE_OOK:
return OOK;
case DATAMODUL_MODULATION_TYPE_FSK:
@@ -201,26 +201,26 @@ int rf69_set_modulation_shaping(struct spi_device *spi,
}
}
-int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate)
+int rf69_set_bit_rate(struct spi_device *spi, u16 bit_rate)
{
int retval;
- u32 bitRate_min;
- u32 bitRate_reg;
+ u32 bit_rate_min;
+ u32 bit_rate_reg;
u8 msb;
u8 lsb;
// check input value
- bitRate_min = F_OSC / 8388608; // 8388608 = 2^23;
- if (bitRate < bitRate_min) {
+ bit_rate_min = F_OSC / 8388608; // 8388608 = 2^23;
+ if (bit_rate < bit_rate_min) {
dev_dbg(&spi->dev, "setBitRate: illegal input param");
return -EINVAL;
}
// calculate reg settings
- bitRate_reg = (F_OSC / bitRate);
+ bit_rate_reg = (F_OSC / bit_rate);
- msb = (bitRate_reg & 0xff00) >> 8;
- lsb = (bitRate_reg & 0xff);
+ msb = (bit_rate_reg & 0xff00) >> 8;
+ lsb = (bit_rate_reg & 0xff);
// transmit to RF 69
retval = rf69_write_reg(spi, REG_BITRATE_MSB, msb);
@@ -330,24 +330,24 @@ int rf69_disable_amplifier(struct spi_device *spi, u8 amplifier_mask)
return rf69_clear_bit(spi, REG_PALEVEL, amplifier_mask);
}
-int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel)
+int rf69_set_output_power_level(struct spi_device *spi, u8 power_level)
{
// TODO: Dependency to PA0,1,2 setting
- powerLevel += 18;
+ power_level += 18;
// check input value
- if (powerLevel > 0x1f) {
+ if (power_level > 0x1f) {
dev_dbg(&spi->dev, "set: illegal input param");
return -EINVAL;
}
// write value
- return rf69_read_mod_write(spi, REG_PALEVEL, MASK_PALEVEL_OUTPUT_POWER, powerLevel);
+ return rf69_read_mod_write(spi, REG_PALEVEL, MASK_PALEVEL_OUTPUT_POWER, power_level);
}
-int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp)
+int rf69_set_pa_ramp(struct spi_device *spi, enum pa_ramp pa_ramp)
{
- switch (paRamp) {
+ switch (pa_ramp) {
case ramp3400:
return rf69_write_reg(spi, REG_PARAMP, PARAMP_3400);
case ramp2000:
@@ -386,12 +386,12 @@ int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp)
}
}
-int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance)
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antenna_impedance antenna_impedance)
{
- switch (antennaImpedance) {
- case fiftyOhm:
+ switch (antenna_impedance) {
+ case fifty_ohm:
return rf69_clear_bit(spi, REG_LNA, MASK_LNA_ZIN);
- case twohundretOhm:
+ case two_hundred_ohm:
return rf69_set_bit(spi, REG_LNA, MASK_LNA_ZIN);
default:
dev_dbg(&spi->dev, "set: illegal input param");
@@ -399,9 +399,9 @@ int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance ant
}
}
-int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain)
+int rf69_set_lna_gain(struct spi_device *spi, enum lna_gain lna_gain)
{
- switch (lnaGain) {
+ switch (lna_gain) {
case automatic:
return rf69_read_mod_write(spi, REG_LNA, MASK_LNA_GAIN, LNA_GAIN_AUTO);
case max:
@@ -425,7 +425,7 @@ int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain)
static int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg,
enum mantisse mantisse, u8 exponent)
{
- u8 newValue;
+ u8 bandwidth;
// check value for mantisse and exponent
if (exponent > 7) {
@@ -441,29 +441,29 @@ static int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg,
}
// read old value
- newValue = rf69_read_reg(spi, reg);
+ bandwidth = rf69_read_reg(spi, reg);
// "delete" mantisse and exponent = just keep the DCC setting
- newValue = newValue & MASK_BW_DCC_FREQ;
+ bandwidth = bandwidth & MASK_BW_DCC_FREQ;
// add new mantisse
switch (mantisse) {
case mantisse16:
- newValue = newValue | BW_MANT_16;
+ bandwidth = bandwidth | BW_MANT_16;
break;
case mantisse20:
- newValue = newValue | BW_MANT_20;
+ bandwidth = bandwidth | BW_MANT_20;
break;
case mantisse24:
- newValue = newValue | BW_MANT_24;
+ bandwidth = bandwidth | BW_MANT_24;
break;
}
// add new exponent
- newValue = newValue | exponent;
+ bandwidth = bandwidth | exponent;
// write back
- return rf69_write_reg(spi, reg, newValue);
+ return rf69_write_reg(spi, reg, bandwidth);
}
int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent)
@@ -476,9 +476,9 @@ int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse
return rf69_set_bandwidth_intern(spi, REG_AFCBW, mantisse, exponent);
}
-int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement thresholdDecrement)
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum threshold_decrement threshold_decrement)
{
- switch (thresholdDecrement) {
+ switch (threshold_decrement) {
case dec_every8th:
return rf69_read_mod_write(spi, REG_OOKPEAK, MASK_OOKPEAK_THRESDEC, OOKPEAK_THRESHDEC_EVERY_8TH);
case dec_every4th:
@@ -501,31 +501,31 @@ int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement t
}
}
-int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value)
+int rf69_set_dio_mapping(struct spi_device *spi, u8 dio_number, u8 value)
{
u8 mask;
u8 shift;
- u8 regaddr;
- u8 regValue;
+ u8 dio_addr;
+ u8 dio_value;
- switch (DIONumber) {
+ switch (dio_number) {
case 0:
- mask = MASK_DIO0; shift = SHIFT_DIO0; regaddr = REG_DIOMAPPING1;
+ mask = MASK_DIO0; shift = SHIFT_DIO0; dio_addr = REG_DIOMAPPING1;
break;
case 1:
- mask = MASK_DIO1; shift = SHIFT_DIO1; regaddr = REG_DIOMAPPING1;
+ mask = MASK_DIO1; shift = SHIFT_DIO1; dio_addr = REG_DIOMAPPING1;
break;
case 2:
- mask = MASK_DIO2; shift = SHIFT_DIO2; regaddr = REG_DIOMAPPING1;
+ mask = MASK_DIO2; shift = SHIFT_DIO2; dio_addr = REG_DIOMAPPING1;
break;
case 3:
- mask = MASK_DIO3; shift = SHIFT_DIO3; regaddr = REG_DIOMAPPING1;
+ mask = MASK_DIO3; shift = SHIFT_DIO3; dio_addr = REG_DIOMAPPING1;
break;
case 4:
- mask = MASK_DIO4; shift = SHIFT_DIO4; regaddr = REG_DIOMAPPING2;
+ mask = MASK_DIO4; shift = SHIFT_DIO4; dio_addr = REG_DIOMAPPING2;
break;
case 5:
- mask = MASK_DIO5; shift = SHIFT_DIO5; regaddr = REG_DIOMAPPING2;
+ mask = MASK_DIO5; shift = SHIFT_DIO5; dio_addr = REG_DIOMAPPING2;
break;
default:
dev_dbg(&spi->dev, "set: illegal input param");
@@ -533,33 +533,33 @@ int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value)
}
// read reg
- regValue = rf69_read_reg(spi, regaddr);
+ dio_value = rf69_read_reg(spi, dio_addr);
// delete old value
- regValue = regValue & ~mask;
+ dio_value = dio_value & ~mask;
// add new value
- regValue = regValue | value << shift;
+ dio_value = dio_value | value << shift;
// write back
- return rf69_write_reg(spi, regaddr, regValue);
+ return rf69_write_reg(spi, dio_addr, dio_value);
}
bool rf69_get_flag(struct spi_device *spi, enum flag flag)
{
switch (flag) {
- case modeSwitchCompleted:
+ case mode_switch_completed:
return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_MODE_READY);
- case readyToReceive:
+ case ready_to_receive:
return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_RX_READY);
- case readyToSend:
+ case ready_to_send:
return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_TX_READY);
- case pllLocked:
+ case pll_locked:
return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_PLL_LOCK);
- case rssiExceededThreshold:
+ case rssi_exceeded_threshold:
return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_RSSI);
case timeout:
return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_TIMEOUT);
case automode:
return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_AUTOMODE);
- case syncAddressMatch:
+ case sync_address_match:
return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH);
case fifo_full:
return (rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_FULL);
@@ -571,13 +571,13 @@ bool rf69_get_flag(struct spi_device *spi, enum flag flag)
return (rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_LEVEL);
case fifo_overrun:
return (rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_OVERRUN);
- case packetSent:
+ case packet_sent:
return (rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_PACKET_SENT);
case payload_ready:
return (rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_PAYLOAD_READY);
- case crcOk:
+ case crc_ok:
return (rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_CRC_OK);
- case batteryLow:
+ case battery_low:
return (rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_LOW_BAT);
default: return false;
}
@@ -590,7 +590,7 @@ int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold)
return rf69_write_reg(spi, REG_RSSITHRESH, threshold);
}
-int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength)
+int rf69_set_preamble_length(struct spi_device *spi, u16 preamble_length)
{
int retval;
u8 msb, lsb;
@@ -598,8 +598,8 @@ int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength)
/* no value check needed - u16 exactly matches register size */
/* calculate reg settings */
- msb = (preambleLength & 0xff00) >> 8;
- lsb = (preambleLength & 0xff);
+ msb = (preamble_length & 0xff00) >> 8;
+ lsb = (preamble_length & 0xff);
/* transmit to chip */
retval = rf69_write_reg(spi, REG_PREAMBLE_MSB, msb);
@@ -625,7 +625,7 @@ int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifo_fill_conditio
switch (fifo_fill_condition) {
case always:
return rf69_set_bit(spi, REG_SYNC_CONFIG, MASK_SYNC_CONFIG_FIFO_FILL_CONDITION);
- case afterSyncInterrupt:
+ case after_sync_interrupt:
return rf69_clear_bit(spi, REG_SYNC_CONFIG, MASK_SYNC_CONFIG_FIFO_FILL_CONDITION);
default:
dev_dbg(&spi->dev, "set: illegal input param");
@@ -633,40 +633,40 @@ int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifo_fill_conditio
}
}
-int rf69_set_sync_size(struct spi_device *spi, u8 syncSize)
+int rf69_set_sync_size(struct spi_device *spi, u8 sync_size)
{
// check input value
- if (syncSize > 0x07) {
+ if (sync_size > 0x07) {
dev_dbg(&spi->dev, "set: illegal input param");
return -EINVAL;
}
// write value
- return rf69_read_mod_write(spi, REG_SYNC_CONFIG, MASK_SYNC_CONFIG_SYNC_SIZE, (syncSize << 3));
+ return rf69_read_mod_write(spi, REG_SYNC_CONFIG, MASK_SYNC_CONFIG_SYNC_SIZE, (sync_size << 3));
}
-int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8])
+int rf69_set_sync_values(struct spi_device *spi, u8 sync_values[8])
{
int retval = 0;
- retval += rf69_write_reg(spi, REG_SYNCVALUE1, syncValues[0]);
- retval += rf69_write_reg(spi, REG_SYNCVALUE2, syncValues[1]);
- retval += rf69_write_reg(spi, REG_SYNCVALUE3, syncValues[2]);
- retval += rf69_write_reg(spi, REG_SYNCVALUE4, syncValues[3]);
- retval += rf69_write_reg(spi, REG_SYNCVALUE5, syncValues[4]);
- retval += rf69_write_reg(spi, REG_SYNCVALUE6, syncValues[5]);
- retval += rf69_write_reg(spi, REG_SYNCVALUE7, syncValues[6]);
- retval += rf69_write_reg(spi, REG_SYNCVALUE8, syncValues[7]);
+ retval += rf69_write_reg(spi, REG_SYNCVALUE1, sync_values[0]);
+ retval += rf69_write_reg(spi, REG_SYNCVALUE2, sync_values[1]);
+ retval += rf69_write_reg(spi, REG_SYNCVALUE3, sync_values[2]);
+ retval += rf69_write_reg(spi, REG_SYNCVALUE4, sync_values[3]);
+ retval += rf69_write_reg(spi, REG_SYNCVALUE5, sync_values[4]);
+ retval += rf69_write_reg(spi, REG_SYNCVALUE6, sync_values[5]);
+ retval += rf69_write_reg(spi, REG_SYNCVALUE7, sync_values[6]);
+ retval += rf69_write_reg(spi, REG_SYNCVALUE8, sync_values[7]);
return retval;
}
-int rf69_set_packet_format(struct spi_device *spi, enum packetFormat packetFormat)
+int rf69_set_packet_format(struct spi_device *spi, enum packet_format packet_format)
{
- switch (packetFormat) {
- case packetLengthVar:
+ switch (packet_format) {
+ case packet_length_var:
return rf69_set_bit(spi, REG_PACKETCONFIG1, MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE);
- case packetLengthFix:
+ case packet_length_fix:
return rf69_clear_bit(spi, REG_PACKETCONFIG1, MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE);
default:
dev_dbg(&spi->dev, "set: illegal input param");
@@ -684,14 +684,14 @@ int rf69_disable_crc(struct spi_device *spi)
return rf69_clear_bit(spi, REG_PACKETCONFIG1, MASK_PACKETCONFIG1_CRC_ON);
}
-int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering addressFiltering)
+int rf69_set_address_filtering(struct spi_device *spi, enum address_filtering address_filtering)
{
- switch (addressFiltering) {
- case filteringOff:
+ switch (address_filtering) {
+ case filtering_off:
return rf69_read_mod_write(spi, REG_PACKETCONFIG1, MASK_PACKETCONFIG1_ADDRESSFILTERING, PACKETCONFIG1_ADDRESSFILTERING_OFF);
- case nodeAddress:
+ case node_address:
return rf69_read_mod_write(spi, REG_PACKETCONFIG1, MASK_PACKETCONFIG1_ADDRESSFILTERING, PACKETCONFIG1_ADDRESSFILTERING_NODE);
- case nodeOrBroadcastAddress:
+ case node_or_broadcast_address:
return rf69_read_mod_write(spi, REG_PACKETCONFIG1, MASK_PACKETCONFIG1_ADDRESSFILTERING, PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST);
default:
dev_dbg(&spi->dev, "set: illegal input param");
@@ -704,19 +704,19 @@ int rf69_set_payload_length(struct spi_device *spi, u8 payload_length)
return rf69_write_reg(spi, REG_PAYLOAD_LENGTH, payload_length);
}
-int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress)
+int rf69_set_node_address(struct spi_device *spi, u8 node_address)
{
- return rf69_write_reg(spi, REG_NODEADRS, nodeAddress);
+ return rf69_write_reg(spi, REG_NODEADRS, node_address);
}
-int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress)
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcast_address)
{
- return rf69_write_reg(spi, REG_BROADCASTADRS, broadcastAddress);
+ return rf69_write_reg(spi, REG_BROADCASTADRS, broadcast_address);
}
-int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition txStartCondition)
+int rf69_set_tx_start_condition(struct spi_device *spi, enum tx_start_condition tx_start_condition)
{
- switch (txStartCondition) {
+ switch (tx_start_condition) {
case fifo_level:
return rf69_clear_bit(spi, REG_FIFO_THRESH, MASK_FIFO_THRESH_TXSTART);
case fifo_not_empty:
@@ -751,11 +751,11 @@ int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold)
int rf69_set_dagc(struct spi_device *spi, enum dagc dagc)
{
switch (dagc) {
- case normalMode:
+ case normal_mode:
return rf69_write_reg(spi, REG_TESTDAGC, DAGC_NORMAL);
case improve:
return rf69_write_reg(spi, REG_TESTDAGC, DAGC_IMPROVED_LOWBETA0);
- case improve4LowModulationIndex:
+ case improve_for_low_modulation_index:
return rf69_write_reg(spi, REG_TESTDAGC, DAGC_IMPROVED_LOWBETA1);
default:
dev_dbg(&spi->dev, "set: illegal input param");
diff --git a/drivers/staging/pi433/rf69.h b/drivers/staging/pi433/rf69.h
index 09d221b8b6df..b9f6850e3316 100644
--- a/drivers/staging/pi433/rf69.h
+++ b/drivers/staging/pi433/rf69.h
@@ -29,35 +29,35 @@ int rf69_set_mode(struct spi_device *spi, enum mode mode);
int rf69_set_data_mode(struct spi_device *spi, u8 data_mode);
int rf69_set_modulation(struct spi_device *spi, enum modulation modulation);
int rf69_set_modulation_shaping(struct spi_device *spi, enum mod_shaping mod_shaping);
-int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate);
+int rf69_set_bit_rate(struct spi_device *spi, u16 bit_rate);
int rf69_set_deviation(struct spi_device *spi, u32 deviation);
int rf69_set_frequency(struct spi_device *spi, u32 frequency);
int rf69_enable_amplifier(struct spi_device *spi, u8 amplifier_mask);
int rf69_disable_amplifier(struct spi_device *spi, u8 amplifier_mask);
-int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel);
-int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp);
-int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance);
-int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain);
+int rf69_set_output_power_level(struct spi_device *spi, u8 power_level);
+int rf69_set_pa_ramp(struct spi_device *spi, enum pa_ramp pa_ramp);
+int rf69_set_antenna_impedance(struct spi_device *spi, enum antenna_impedance antenna_impedance);
+int rf69_set_lna_gain(struct spi_device *spi, enum lna_gain lna_gain);
int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent);
int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse, u8 exponent);
-int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement thresholdDecrement);
-int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value);
+int rf69_set_ook_threshold_dec(struct spi_device *spi, enum threshold_decrement threshold_decrement);
+int rf69_set_dio_mapping(struct spi_device *spi, u8 dio_number, u8 value);
bool rf69_get_flag(struct spi_device *spi, enum flag flag);
int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold);
-int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength);
+int rf69_set_preamble_length(struct spi_device *spi, u16 preamble_length);
int rf69_enable_sync(struct spi_device *spi);
int rf69_disable_sync(struct spi_device *spi);
int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifo_fill_condition fifo_fill_condition);
int rf69_set_sync_size(struct spi_device *spi, u8 sync_size);
-int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8]);
-int rf69_set_packet_format(struct spi_device *spi, enum packetFormat packetFormat);
+int rf69_set_sync_values(struct spi_device *spi, u8 sync_values[8]);
+int rf69_set_packet_format(struct spi_device *spi, enum packet_format packet_format);
int rf69_enable_crc(struct spi_device *spi);
int rf69_disable_crc(struct spi_device *spi);
-int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering addressFiltering);
+int rf69_set_address_filtering(struct spi_device *spi, enum address_filtering address_filtering);
int rf69_set_payload_length(struct spi_device *spi, u8 payload_length);
-int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress);
-int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress);
-int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition txStartCondition);
+int rf69_set_node_address(struct spi_device *spi, u8 node_address);
+int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcast_address);
+int rf69_set_tx_start_condition(struct spi_device *spi, enum tx_start_condition tx_start_condition);
int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold);
int rf69_set_dagc(struct spi_device *spi, enum dagc dagc);
diff --git a/drivers/staging/pi433/rf69_enum.h b/drivers/staging/pi433/rf69_enum.h
index 03440cfa957c..493bd0025453 100644
--- a/drivers/staging/pi433/rf69_enum.h
+++ b/drivers/staging/pi433/rf69_enum.h
@@ -41,7 +41,7 @@ enum mod_shaping {
SHAPING_2BR
};
-enum paRamp {
+enum pa_ramp {
ramp3400,
ramp2000,
ramp1000,
@@ -60,12 +60,12 @@ enum paRamp {
ramp10
};
-enum antennaImpedance {
- fiftyOhm,
- twohundretOhm
+enum antenna_impedance {
+ fifty_ohm,
+ two_hundred_ohm
};
-enum lnaGain {
+enum lna_gain {
automatic,
max,
max_minus_6,
@@ -82,7 +82,7 @@ enum mantisse {
mantisse24
};
-enum thresholdDecrement {
+enum threshold_decrement {
dec_every8th,
dec_every4th,
dec_every2nd,
@@ -94,50 +94,50 @@ enum thresholdDecrement {
};
enum flag {
- modeSwitchCompleted,
- readyToReceive,
- readyToSend,
- pllLocked,
- rssiExceededThreshold,
+ mode_switch_completed,
+ ready_to_receive,
+ ready_to_send,
+ pll_locked,
+ rssi_exceeded_threshold,
timeout,
automode,
- syncAddressMatch,
+ sync_address_match,
fifo_full,
// fifo_not_empty, collision with next enum; replaced by following enum...
fifo_empty,
fifo_level_below_threshold,
fifo_overrun,
- packetSent,
+ packet_sent,
payload_ready,
- crcOk,
- batteryLow
+ crc_ok,
+ battery_low
};
enum fifo_fill_condition {
- afterSyncInterrupt,
+ after_sync_interrupt,
always
};
-enum packetFormat {
- packetLengthFix,
- packetLengthVar
+enum packet_format {
+ packet_length_fix,
+ packet_length_var
};
-enum txStartCondition {
+enum tx_start_condition {
fifo_level,
fifo_not_empty
};
-enum addressFiltering {
- filteringOff,
- nodeAddress,
- nodeOrBroadcastAddress
+enum address_filtering {
+ filtering_off,
+ node_address,
+ node_or_broadcast_address
};
enum dagc {
- normalMode,
+ normal_mode,
improve,
- improve4LowModulationIndex
+ improve_for_low_modulation_index
};
#endif
diff --git a/drivers/staging/rtl8188eu/Kconfig b/drivers/staging/rtl8188eu/Kconfig
index cb836c59d564..673fdce25530 100644
--- a/drivers/staging/rtl8188eu/Kconfig
+++ b/drivers/staging/rtl8188eu/Kconfig
@@ -4,6 +4,10 @@ config R8188EU
depends on m
select WIRELESS_EXT
select WEXT_PRIV
+ select LIB80211
+ select LIB80211_CRYPT_WEP
+ select LIB80211_CRYPT_CCMP
+ select LIB80211_CRYPT_TKIP
---help---
This option adds the Realtek RTL8188EU USB device such as TP-Link TL-WN725N.
If built as a module, it will be called r8188eu.
diff --git a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
index bb867a987c2b..0b0fdccc7278 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
@@ -577,7 +577,7 @@ u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen)
u8 match = false;
u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
- if (ie_ptr == NULL)
+ if (!ie_ptr)
return match;
eid = ie_ptr[0];
@@ -926,7 +926,7 @@ void rtw_macaddr_cfg(u8 *mac_addr)
{
u8 mac[ETH_ALEN];
- if (mac_addr == NULL)
+ if (!mac_addr)
return;
if (rtw_initmac && mac_pton(rtw_initmac, mac)) {
@@ -952,7 +952,7 @@ void rtw_macaddr_cfg(u8 *mac_addr)
DBG_88E("MAC Address from efuse error, assign default one !!!\n");
}
- DBG_88E("rtw_macaddr_cfg MAC Address = %pM\n", (mac_addr));
+ DBG_88E("%s MAC Address = %pM\n", __func__, (mac_addr));
}
static int rtw_get_cipher_info(struct wlan_network *pnetwork)
@@ -965,7 +965,7 @@ static int rtw_get_cipher_info(struct wlan_network *pnetwork)
pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12);
if (pbuf && (wpa_ielen > 0)) {
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_cipher_info: wpa_ielen: %d", wpa_ielen));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: wpa_ielen: %d", __func__, wpa_ielen));
if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x)) {
pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
pnetwork->BcnInfo.group_cipher = group_cipher;
@@ -1014,10 +1014,10 @@ void rtw_get_bcn_info(struct wlan_network *pnetwork)
pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS;
}
rtw_get_sec_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &rsn_len, NULL, &wpa_len);
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid));
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len));
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid));
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: ssid =%s\n", __func__, pnetwork->network.Ssid.Ssid));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: wpa_len =%d rsn_len =%d\n", __func__, wpa_len, rsn_len));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: ssid =%s\n", __func__, pnetwork->network.Ssid.Ssid));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: wpa_len =%d rsn_len =%d\n", __func__, wpa_len, rsn_len));
if (rsn_len > 0) {
pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2;
diff --git a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
index 767928a2cbb4..2183c613e61b 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
@@ -207,7 +207,7 @@ release_mlme_lock:
exit:
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
- ("rtw_set_802_11_bssid: status=%d\n", status));
+ ("%s: status=%d\n", __func__, status));
return status;
@@ -316,7 +316,7 @@ release_mlme_lock:
exit:
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
- ("-rtw_set_802_11_ssid: status =%d\n", status));
+ ("-%s: status =%d\n", __func__, status));
return status;
}
@@ -418,22 +418,22 @@ u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_s
u8 res = true;
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("+rtw_set_802_11_bssid_list_scan(), fw_state =%x\n", get_fwstate(pmlmepriv)));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("+%s(), fw_state =%x\n", __func__, get_fwstate(pmlmepriv)));
- if (padapter == NULL) {
+ if (!padapter) {
res = false;
goto exit;
}
if (!padapter->hw_init_completed) {
res = false;
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n === rtw_set_802_11_bssid_list_scan:hw_init_completed == false ===\n"));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n === %s:hw_init_completed == false ===\n", __func__));
goto exit;
}
if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) ||
(pmlmepriv->LinkDetectInfo.bBusyTraffic)) {
/* Scan or linking is in progress, do nothing. */
- RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("rtw_set_802_11_bssid_list_scan fail since fw_state = %x\n", get_fwstate(pmlmepriv)));
+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("%s fail since fw_state = %x\n", __func__, get_fwstate(pmlmepriv)));
res = true;
if (check_fwstate(pmlmepriv,
@@ -473,7 +473,7 @@ u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum ndis_802_11
psecuritypriv->ndisauthtype = authmode;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
- ("rtw_set_802_11_authentication_mode:psecuritypriv->ndisauthtype=%d",
+ ("%s:psecuritypriv->ndisauthtype=%d", __func__,
psecuritypriv->ndisauthtype));
if (psecuritypriv->ndisauthtype > 3)
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c
index 1cd49e292804..8d49e3047201 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c
@@ -790,7 +790,7 @@ void rtw_indicate_connect(struct adapter *padapter)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_connect\n"));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+%s\n", __func__));
pmlmepriv->to_join = false;
@@ -806,7 +806,7 @@ void rtw_indicate_connect(struct adapter *padapter)
rtw_set_scan_deny(padapter, 3000);
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-rtw_indicate_connect: fw_state=0x%08x\n", get_fwstate(pmlmepriv)));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-%s: fw_state=0x%08x\n", __func__, get_fwstate(pmlmepriv)));
}
/*
@@ -897,7 +897,7 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str
* Commented by Albert 2012/07/21
* When doing the WPS, the wps_ie_len won't equal to 0
* And the Wi-Fi driver shouldn't allow the data
- * packet to be tramsmitted.
+ * packet to be transmitted.
*/
if (padapter->securitypriv.wps_ie_len != 0) {
psta->ieee8021x_blocked = true;
@@ -1371,7 +1371,7 @@ void _rtw_join_timeout_handler (struct timer_list *t)
}
/*
- * rtw_scan_timeout_handler - Timeout/Faliure handler for CMD SiteSurvey
+ * rtw_scan_timeout_handler - Timeout/Failure handler for CMD SiteSurvey
* @adapter: pointer to struct adapter structure
*/
void rtw_scan_timeout_handler (struct timer_list *t)
@@ -1756,7 +1756,7 @@ int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_
uint ndissecuritytype = psecuritypriv->ndisencryptstatus;
RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
- ("+rtw_restruct_sec_ie: ndisauthmode=%d ndissecuritytype=%d\n",
+ ("+%s: ndisauthmode=%d ndissecuritytype=%d\n", __func__,
ndisauthmode, ndissecuritytype));
/* copy fixed ie only */
@@ -1983,7 +1983,7 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len)
if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable))
return;
- DBG_88E("+rtw_update_ht_cap()\n");
+ DBG_88E("+%s()\n", __func__);
/* maybe needs check if ap supports rx ampdu. */
if ((!phtpriv->ampdu_enable) && (pregistrypriv->ampdu_enable == 1)) {
@@ -2057,7 +2057,7 @@ void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitfr
issued |= (phtpriv->candidate_tid_bitmap >> priority) & 0x1;
if (issued == 0) {
- DBG_88E("rtw_issue_addbareq_cmd, p=%d\n", priority);
+ DBG_88E("%s, p=%d\n", __func__, priority);
psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority);
rtw_addbareq_cmd(padapter, (u8)priority, pattrib->ra);
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
index bcb6919bb7d5..19266cf1edbd 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
@@ -163,13 +163,13 @@ struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv)
struct xmit_buf *pxmitbuf;
pmgntframe = rtw_alloc_xmitframe(pxmitpriv);
- if (pmgntframe == NULL) {
+ if (!pmgntframe) {
DBG_88E("%s, alloc xmitframe fail\n", __func__);
return NULL;
}
pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv);
- if (pxmitbuf == NULL) {
+ if (!pxmitbuf) {
DBG_88E("%s, alloc xmitbuf fail\n", __func__);
rtw_free_xmitframe(pxmitpriv, pmgntframe);
return NULL;
@@ -332,7 +332,7 @@ static void issue_beacon(struct adapter *padapter, int timeout_ms)
u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
- if (pmgntframe == NULL) {
+ if (!pmgntframe) {
DBG_88E("%s, alloc mgnt frame fail\n", __func__);
return;
}
@@ -478,7 +478,7 @@ static void issue_probersp(struct adapter *padapter, unsigned char *da)
unsigned int rate_len;
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
- if (pmgntframe == NULL) {
+ if (!pmgntframe) {
DBG_88E("%s, alloc mgnt frame fail\n", __func__);
return;
}
@@ -623,10 +623,10 @@ static int issue_probereq(struct adapter *padapter,
int bssrate_len = 0;
u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+issue_probereq\n"));
+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+%s\n", __func__));
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
- if (pmgntframe == NULL)
+ if (!pmgntframe)
goto exit;
/* update attribute */
@@ -912,7 +912,7 @@ static void issue_asocrsp(struct adapter *padapter, unsigned short status,
DBG_88E("%s\n", __func__);
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
- if (pmgntframe == NULL)
+ if (!pmgntframe)
return;
/* update attribute */
@@ -1039,7 +1039,7 @@ static void issue_assocreq(struct adapter *padapter)
struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
- if (pmgntframe == NULL)
+ if (!pmgntframe)
goto exit;
/* update attribute */
@@ -1133,7 +1133,7 @@ static void issue_assocreq(struct adapter *padapter)
/* RSN */
p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ie)), _RSN_IE_2_, &ie_len, (pmlmeinfo->network.IELength - sizeof(struct ndis_802_11_fixed_ie)));
- if (p != NULL)
+ if (p)
pframe = rtw_set_ie(pframe, _RSN_IE_2_, ie_len, (p + 2), &(pattrib->pktlen));
/* HT caps */
@@ -1221,7 +1221,7 @@ static int _issue_nulldata(struct adapter *padapter, unsigned char *da,
pnetwork = &(pmlmeinfo->network);
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
- if (pmgntframe == NULL)
+ if (!pmgntframe)
goto exit;
/* update attribute */
@@ -1338,7 +1338,7 @@ static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da,
DBG_88E("%s\n", __func__);
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
- if (pmgntframe == NULL)
+ if (!pmgntframe)
goto exit;
/* update attribute */
@@ -1584,7 +1584,7 @@ static void issue_action_BA(struct adapter *padapter, unsigned char *raddr,
DBG_88E("%s, category=%d, action=%d, status=%d\n", __func__, category, action, status);
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
- if (pmgntframe == NULL)
+ if (!pmgntframe)
return;
/* update attribute */
@@ -1632,7 +1632,7 @@ static void issue_action_BA(struct adapter *padapter, unsigned char *raddr,
&pattrib->pktlen);
psta = rtw_get_stainfo(pstapriv, raddr);
- if (psta != NULL) {
+ if (psta) {
start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1;
DBG_88E("BA_starting_seqctrl=%d for TID=%d\n", start_seq, status & 0x07);
@@ -1743,7 +1743,7 @@ static void issue_action_BSSCoexistPacket(struct adapter *padapter)
action = ACT_PUBLIC_BSSCOEXIST;
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
- if (pmgntframe == NULL)
+ if (!pmgntframe)
return;
/* update attribute */
@@ -2091,7 +2091,7 @@ static u8 collect_bss_info(struct adapter *padapter,
/* checking SSID */
p = rtw_get_ie(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset);
- if (p == NULL) {
+ if (!p) {
DBG_88E("marc: cannot find SSID for survey event\n");
return _FAIL;
}
@@ -2122,7 +2122,7 @@ static u8 collect_bss_info(struct adapter *padapter,
}
p = rtw_get_ie(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset);
- if (p != NULL) {
+ if (p) {
if (len > (NDIS_802_11_LENGTH_RATES_EX-i)) {
DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len);
return _FAIL;
@@ -2253,7 +2253,7 @@ static void start_create_ibss(struct adapter *padapter)
pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
}
} else {
- DBG_88E("start_create_ibss, invalid cap:%x\n", caps);
+ DBG_88E("%s, invalid cap:%x\n", __func__, caps);
return;
}
}
@@ -2568,7 +2568,7 @@ static unsigned int OnProbeReq(struct adapter *padapter,
len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_);
/* check (wildcard) SSID */
- if (p != NULL) {
+ if (p) {
if ((ielen != 0 && memcmp((void *)(p+2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength)) ||
(ielen == 0 && pmlmeinfo->hidden_ssid_mode))
return _SUCCESS;
@@ -2705,7 +2705,7 @@ static unsigned int OnAuth(struct adapter *padapter,
if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
return _FAIL;
- DBG_88E("+OnAuth\n");
+ DBG_88E("+%s\n", __func__);
sa = GetAddr2Ptr(pframe);
@@ -2735,11 +2735,11 @@ static unsigned int OnAuth(struct adapter *padapter,
}
pstat = rtw_get_stainfo(pstapriv, sa);
- if (pstat == NULL) {
+ if (!pstat) {
/* allocate a new one */
DBG_88E("going to alloc stainfo for sa=%pM\n", sa);
pstat = rtw_alloc_stainfo(pstapriv, sa);
- if (pstat == NULL) {
+ if (!pstat) {
DBG_88E(" Exceed the upper limit of supported clients...\n");
status = _STATS_UNABLE_HANDLE_STA_;
goto auth_fail;
@@ -2973,7 +2973,7 @@ static unsigned int OnAssocReq(struct adapter *padapter,
}
pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
- if (pstat == NULL) {
+ if (!pstat) {
status = _RSON_CLS2_;
goto asoc_class2_error;
}
@@ -3014,7 +3014,7 @@ static unsigned int OnAssocReq(struct adapter *padapter,
/* checking SSID */
p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len,
pkt_len - WLAN_HDR_A3_LEN - ie_offset);
- if (p == NULL)
+ if (!p)
status = _STATS_FAILURE_;
if (ie_len == 0) { /* broadcast ssid, however it is not allowed in assocreq */
@@ -3122,7 +3122,7 @@ static unsigned int OnAssocReq(struct adapter *padapter,
goto OnAssocReqFail;
pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
- if (wpa_ie == NULL) {
+ if (!wpa_ie) {
if (elems.wps_ie) {
DBG_88E("STA included WPS IE in "
"(Re)Association Request - assume WPS is "
@@ -3653,7 +3653,7 @@ static unsigned int OnAction_back(struct adapter *padapter,
addr = GetAddr2Ptr(pframe);
psta = rtw_get_stainfo(pstapriv, addr);
- if (psta == NULL)
+ if (!psta)
return _SUCCESS;
frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr));
@@ -4144,13 +4144,13 @@ void mgt_dispatcher(struct adapter *padapter, struct recv_frame *precv_frame)
struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(pframe));
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
- ("+mgt_dispatcher: type(0x%x) subtype(0x%x)\n",
+ ("+%s: type(0x%x) subtype(0x%x)\n", __func__,
(unsigned int)GetFrameType(pframe),
(unsigned int)GetFrameSubType(pframe)));
if (GetFrameType(pframe) != WIFI_MGT_TYPE) {
RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
- ("mgt_dispatcher: type(0x%x) error!\n",
+ ("%s: type(0x%x) error!\n", __func__,
(unsigned int)GetFrameType(pframe)));
return;
}
@@ -4170,7 +4170,7 @@ void mgt_dispatcher(struct adapter *padapter, struct recv_frame *precv_frame)
}
ptable += index;
- if (psta != NULL) {
+ if (psta) {
if (GetRetry(pframe)) {
if (precv_frame->attrib.seq_num ==
psta->RxMgmtFrameSeqNum) {
@@ -4355,7 +4355,7 @@ void report_join_res(struct adapter *padapter, int res)
pjoinbss_evt->network.join_res = res;
pjoinbss_evt->network.aid = res;
- DBG_88E("report_join_res(%d)\n", res);
+ DBG_88E("%s(%d)\n", __func__, res);
rtw_joinbss_event_prehandle(padapter, (u8 *)&pjoinbss_evt->network);
@@ -4415,7 +4415,7 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr,
pdel_sta_evt->mac_id = mac_id;
- DBG_88E("report_del_sta_event: delete STA, mac_id =%d\n", mac_id);
+ DBG_88E("%s: delete STA, mac_id =%d\n", __func__, mac_id);
rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
}
@@ -4460,7 +4460,7 @@ void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr,
ether_addr_copy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr);
padd_sta_evt->cam_id = cam_idx;
- DBG_88E("report_add_sta_event: add STA\n");
+ DBG_88E("%s: add STA\n", __func__);
rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
}
@@ -4702,7 +4702,7 @@ void linked_status_chk(struct adapter *padapter)
rx_chk_limit = 4;
psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress);
- if (psta != NULL) {
+ if (psta) {
bool is_p2p_enable = false;
if (!chk_ap_is_alive(padapter, psta))
@@ -4782,7 +4782,7 @@ void linked_status_chk(struct adapter *padapter)
if (pmlmeinfo->FW_sta_info[i].status == 1) {
psta = pmlmeinfo->FW_sta_info[i].psta;
- if (psta == NULL)
+ if (!psta)
continue;
if (pmlmeinfo->FW_sta_info[i].rx_pkt == sta_rx_pkts(psta)) {
if (pmlmeinfo->FW_sta_info[i].retry < 3) {
@@ -4852,7 +4852,7 @@ void link_timer_hdl(struct timer_list *t)
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) {
- DBG_88E("link_timer_hdl:no beacon while connecting\n");
+ DBG_88E("%s:no beacon while connecting\n", __func__);
pmlmeinfo->state = WIFI_FW_NULL_STATE;
report_join_res(padapter, -3);
} else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) {
@@ -4863,7 +4863,7 @@ void link_timer_hdl(struct timer_list *t)
return;
}
- DBG_88E("link_timer_hdl: auth timeout and try again\n");
+ DBG_88E("%s: auth timeout and try again\n", __func__);
pmlmeinfo->auth_seq = 1;
issue_auth(padapter, NULL, 0);
set_link_timer(pmlmeext, REAUTH_TO);
@@ -4875,7 +4875,7 @@ void link_timer_hdl(struct timer_list *t)
return;
}
- DBG_88E("link_timer_hdl: assoc timeout and try again\n");
+ DBG_88E("%s: assoc timeout and try again\n", __func__);
issue_assocreq(padapter);
set_link_timer(pmlmeext, REASSOC_TO);
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c
index 6506a1587df0..05936a45eb93 100644
--- a/drivers/staging/rtl8188eu/core/rtw_recv.c
+++ b/drivers/staging/rtl8188eu/core/rtw_recv.c
@@ -23,6 +23,7 @@
#include <mon.h>
#include <wifi.h>
#include <linux/vmalloc.h>
+#include <net/lib80211.h>
#define ETHERNET_HEADER_SIZE 14 /* Ethernet Header Length */
#define LLC_HEADER_SIZE 6 /* LLC Header Length */
@@ -220,31 +221,20 @@ u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter)
static int recvframe_chkmic(struct adapter *adapter,
struct recv_frame *precvframe)
{
- int i, res = _SUCCESS;
- u32 datalen;
- u8 miccode[8];
- u8 bmic_err = false, brpt_micerror = true;
- u8 *pframe, *payload, *pframemic;
- u8 *mickey;
- struct sta_info *stainfo;
- struct rx_pkt_attrib *prxattrib = &precvframe->attrib;
- struct security_priv *psecuritypriv = &adapter->securitypriv;
-
- struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
-
- stainfo = rtw_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]);
+ int res = _SUCCESS;
+ struct rx_pkt_attrib *prxattrib = &precvframe->attrib;
+ struct sta_info *stainfo = rtw_get_stainfo(&adapter->stapriv, prxattrib->ta);
if (prxattrib->encrypt == _TKIP_) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- ("\n %s: prxattrib->encrypt==_TKIP_\n", __func__));
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- ("\n %s: da=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
- __func__, prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2],
- prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5]));
-
- /* calculate mic code */
- if (stainfo != NULL) {
+ if (stainfo) {
+ int key_idx;
+ const int iv_len = 8, icv_len = 4, key_length = 32;
+ struct sk_buff *skb = precvframe->pkt;
+ u8 key[32], iv[8], icv[4], *pframe = skb->data;
+ void *crypto_private = NULL;
+ struct lib80211_crypto_ops *crypto_ops = try_then_request_module(lib80211_get_crypto_ops("TKIP"), "lib80211_crypt_tkip");
+ struct security_priv *psecuritypriv = &adapter->securitypriv;
+
if (IS_MCAST(prxattrib->ra)) {
if (!psecuritypriv) {
res = _FAIL;
@@ -253,115 +243,58 @@ static int recvframe_chkmic(struct adapter *adapter,
DBG_88E("\n %s: didn't install group key!!!!!!!!!!\n", __func__);
goto exit;
}
- mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0];
-
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- ("\n %s: bcmc key\n", __func__));
+ key_idx = prxattrib->key_index;
+ memcpy(key, psecuritypriv->dot118021XGrpKey[key_idx].skey, 16);
+ memcpy(key + 16, psecuritypriv->dot118021XGrprxmickey[key_idx].skey, 16);
} else {
- mickey = &stainfo->dot11tkiprxmickey.skey[0];
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("\n %s: unicast key\n", __func__));
+ key_idx = 0;
+ memcpy(key, stainfo->dot118021x_UncstKey.skey, 16);
+ memcpy(key + 16, stainfo->dot11tkiprxmickey.skey, 16);
}
- /* icv_len included the mic code */
- datalen = precvframe->pkt->len-prxattrib->hdrlen -
- prxattrib->iv_len-prxattrib->icv_len-8;
- pframe = precvframe->pkt->data;
- payload = pframe+prxattrib->hdrlen+prxattrib->iv_len;
-
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n prxattrib->iv_len=%d prxattrib->icv_len=%d\n", prxattrib->iv_len, prxattrib->icv_len));
- rtw_seccalctkipmic(mickey, pframe, payload, datalen, &miccode[0],
- (unsigned char)prxattrib->priority); /* care the length of the data */
+ if (!crypto_ops) {
+ res = _FAIL;
+ goto exit_lib80211_tkip;
+ }
- pframemic = payload+datalen;
+ memcpy(iv, pframe + prxattrib->hdrlen, iv_len);
+ memcpy(icv, pframe + skb->len - icv_len, icv_len);
+ memmove(pframe + iv_len, pframe, prxattrib->hdrlen);
- bmic_err = false;
+ skb_pull(skb, iv_len);
+ skb_trim(skb, skb->len - icv_len);
- for (i = 0; i < 8; i++) {
- if (miccode[i] != *(pframemic+i)) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("%s: miccode[%d](%02x)!=*(pframemic+%d)(%02x) ",
- __func__, i, miccode[i], i, *(pframemic + i)));
- bmic_err = true;
- }
+ crypto_private = crypto_ops->init(key_idx);
+ if (!crypto_private) {
+ res = _FAIL;
+ goto exit_lib80211_tkip;
+ }
+ if (crypto_ops->set_key(key, key_length, NULL, crypto_private) < 0) {
+ res = _FAIL;
+ goto exit_lib80211_tkip;
+ }
+ if (crypto_ops->decrypt_msdu(skb, key_idx, prxattrib->hdrlen, crypto_private)) {
+ res = _FAIL;
+ goto exit_lib80211_tkip;
}
- if (bmic_err) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("\n *(pframemic-8)-*(pframemic-1)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
- *(pframemic-8), *(pframemic-7), *(pframemic-6),
- *(pframemic-5), *(pframemic-4), *(pframemic-3),
- *(pframemic-2), *(pframemic-1)));
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("\n *(pframemic-16)-*(pframemic-9)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
- *(pframemic-16), *(pframemic-15), *(pframemic-14),
- *(pframemic-13), *(pframemic-12), *(pframemic-11),
- *(pframemic-10), *(pframemic-9)));
- {
- uint i;
+ memmove(pframe, pframe + iv_len, prxattrib->hdrlen);
+ skb_push(skb, iv_len);
+ skb_put(skb, icv_len);
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("\n ======demp packet (len=%d)======\n",
- precvframe->pkt->len));
- for (i = 0; i < precvframe->pkt->len; i += 8) {
- RT_TRACE(_module_rtl871x_recv_c_,
- _drv_err_,
- ("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x",
- *(precvframe->pkt->data+i),
- *(precvframe->pkt->data+i+1),
- *(precvframe->pkt->data+i+2),
- *(precvframe->pkt->data+i+3),
- *(precvframe->pkt->data+i+4),
- *(precvframe->pkt->data+i+5),
- *(precvframe->pkt->data+i+6),
- *(precvframe->pkt->data+i+7)));
- }
- RT_TRACE(_module_rtl871x_recv_c_,
- _drv_err_,
- ("\n ====== demp packet end [len=%d]======\n",
- precvframe->pkt->len));
- RT_TRACE(_module_rtl871x_recv_c_,
- _drv_err_,
- ("\n hrdlen=%d,\n",
- prxattrib->hdrlen));
- }
+ memcpy(pframe + prxattrib->hdrlen, iv, iv_len);
+ memcpy(pframe + skb->len - icv_len, icv, icv_len);
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
- ("ra=0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x psecuritypriv->binstallGrpkey=%d ",
- prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2],
- prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5], psecuritypriv->binstallGrpkey));
-
- /* double check key_index for some timing issue , */
- /* cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue */
- if ((IS_MCAST(prxattrib->ra) == true) && (prxattrib->key_index != pmlmeinfo->key_index))
- brpt_micerror = false;
-
- if ((prxattrib->bdecrypted) && (brpt_micerror)) {
- rtw_handle_tkip_mic_err(adapter, (u8)IS_MCAST(prxattrib->ra));
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted));
- DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted);
- } else {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted));
- DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted);
- }
- res = _FAIL;
- } else {
- /* mic checked ok */
- if ((!psecuritypriv->bcheck_grpkey) && (IS_MCAST(prxattrib->ra))) {
- psecuritypriv->bcheck_grpkey = true;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("psecuritypriv->bcheck_grpkey = true"));
- }
- }
+exit_lib80211_tkip:
+ if (crypto_ops && crypto_private)
+ crypto_ops->deinit(crypto_private);
} else {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
("%s: rtw_get_stainfo==NULL!!!\n", __func__));
}
-
- skb_trim(precvframe->pkt, precvframe->pkt->len - 8);
}
exit:
-
return res;
}
@@ -404,7 +337,7 @@ static struct recv_frame *decryptor(struct adapter *padapter,
switch (prxattrib->encrypt) {
case _WEP40_:
case _WEP104_:
- rtw_wep_decrypt(padapter, (u8 *)precv_frame);
+ res = rtw_wep_decrypt(padapter, (u8 *)precv_frame);
break;
case _TKIP_:
res = rtw_tkip_decrypt(padapter, (u8 *)precv_frame);
@@ -454,7 +387,7 @@ static struct recv_frame *portctrl(struct adapter *adapter,
prtnframe = NULL;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:adapter->securitypriv.dot11AuthAlgrthm=%d\n", adapter->securitypriv.dot11AuthAlgrthm));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########%s:adapter->securitypriv.dot11AuthAlgrthm=%d\n", __func__, adapter->securitypriv.dot11AuthAlgrthm));
if (auth_alg == 2) {
/* get ether_type */
@@ -465,7 +398,7 @@ static struct recv_frame *portctrl(struct adapter *adapter,
if ((psta != NULL) && (psta->ieee8021x_blocked)) {
/* blocked */
/* only accept EAPOL frame */
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked==1\n"));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########%s:psta->ieee8021x_blocked==1\n", __func__));
if (ether_type == eapol_type) {
prtnframe = precv_frame;
@@ -477,23 +410,23 @@ static struct recv_frame *portctrl(struct adapter *adapter,
} else {
/* allowed */
/* check decryption status, and decrypt the frame if needed */
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked==0\n"));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########%s:psta->ieee8021x_blocked==0\n", __func__));
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- ("portctrl:precv_frame->hdr.attrib.privacy=%x\n",
- precv_frame->attrib.privacy));
+ ("%s:precv_frame->hdr.attrib.privacy=%x\n",
+ __func__, precv_frame->attrib.privacy));
if (pattrib->bdecrypted == 0)
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:prxstat->decrypted=%x\n", pattrib->bdecrypted));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("%s:prxstat->decrypted=%x\n", __func__, pattrib->bdecrypted));
prtnframe = precv_frame;
/* check is the EAPOL frame or not (Rekey) */
if (ether_type == eapol_type) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("########portctrl:ether_type==0x888e\n"));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("########%s:ether_type==0x888e\n", __func__));
/* check Rekey */
prtnframe = precv_frame;
} else {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:ether_type=0x%04x\n", ether_type));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########%s:ether_type=0x%04x\n", __func__, ether_type));
}
}
} else {
@@ -512,14 +445,14 @@ static int recv_decache(struct recv_frame *precv_frame, u8 bretry,
(precv_frame->attrib.frag_num & 0xf);
if (tid > 15) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, (tid>15)! seq_ctrl=0x%x, tid=0x%x\n", seq_ctrl, tid));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s, (tid>15)! seq_ctrl=0x%x, tid=0x%x\n", __func__, seq_ctrl, tid));
return _FAIL;
}
if (1) {/* if (bretry) */
if (seq_ctrl == prxcache->tid_rxseq[tid]) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, seq_ctrl=0x%x, tid=0x%x, tid_rxseq=0x%x\n", seq_ctrl, tid, prxcache->tid_rxseq[tid]));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s, seq_ctrl=0x%x, tid=0x%x, tid_rxseq=0x%x\n", __func__, seq_ctrl, tid, prxcache->tid_rxseq[tid]));
return _FAIL;
}
@@ -718,7 +651,7 @@ int sta2sta_data_frame(struct adapter *adapter, struct recv_frame *precv_frame,
*psta = rtw_get_stainfo(pstapriv, sta_addr); /* get ap_info */
if (*psta == NULL) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under sta2sta_data_frame ; drop pkt\n"));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under %s ; drop pkt\n", __func__));
ret = _FAIL;
goto exit;
}
@@ -754,7 +687,7 @@ static int ap2sta_data_frame(
/* da should be for me */
if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- (" ap2sta_data_frame: compare DA fail; DA=%pM\n", (pattrib->dst)));
+ (" %s: compare DA fail; DA=%pM\n", __func__, (pattrib->dst)));
ret = _FAIL;
goto exit;
}
@@ -764,7 +697,7 @@ static int ap2sta_data_frame(
!memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
(memcmp(pattrib->bssid, mybssid, ETH_ALEN))) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
- (" ap2sta_data_frame: compare BSSID fail ; BSSID=%pM\n", (pattrib->bssid)));
+ (" %s: compare BSSID fail ; BSSID=%pM\n", __func__, (pattrib->bssid)));
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("mybssid=%pM\n", (mybssid)));
if (!bmcast) {
@@ -1009,10 +942,10 @@ static int validate_recv_mgnt_frame(struct adapter *padapter,
{
struct sta_info *psta;
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+validate_recv_mgnt_frame\n"));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+%s\n", __func__));
precv_frame = recvframe_chk_defrag(padapter, precv_frame);
- if (precv_frame == NULL) {
+ if (!precv_frame) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
("%s: fragment packet\n", __func__));
return _SUCCESS;
@@ -1060,7 +993,7 @@ static int validate_recv_data_frame(struct adapter *adapter,
psa = get_sa(ptr);
pbssid = get_hdr_bssid(ptr);
- if (pbssid == NULL) {
+ if (!pbssid) {
ret = _FAIL;
goto exit;
}
@@ -1102,7 +1035,7 @@ static int validate_recv_data_frame(struct adapter *adapter,
else if (ret == RTW_RX_HANDLED)
goto exit;
- if (psta == NULL) {
+ if (!psta) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" after to_fr_ds_chk; psta==NULL\n"));
ret = _FAIL;
goto exit;
@@ -1141,7 +1074,7 @@ static int validate_recv_data_frame(struct adapter *adapter,
}
if (pattrib->privacy) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("validate_recv_data_frame:pattrib->privacy=%x\n", pattrib->privacy));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("%s:pattrib->privacy=%x\n", __func__, pattrib->privacy));
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n ^^^^^^^^^^^IS_MCAST(pattrib->ra(0x%02x))=%d^^^^^^^^^^^^^^^6\n", pattrib->ra[0], IS_MCAST(pattrib->ra)));
GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, IS_MCAST(pattrib->ra));
@@ -1436,7 +1369,7 @@ struct recv_frame *recvframe_chk_defrag(struct adapter *padapter,
psta_addr = pfhdr->attrib.ta;
psta = rtw_get_stainfo(pstapriv, psta_addr);
- if (psta == NULL) {
+ if (!psta) {
u8 type = GetFrameType(pfhdr->pkt->data);
if (type != WIFI_DATA_TYPE) {
@@ -1455,7 +1388,7 @@ struct recv_frame *recvframe_chk_defrag(struct adapter *padapter,
if (ismfrag == 1) {
/* 0~(n-1) fragment frame */
/* enqueue to defraf_g */
- if (pdefrag_q != NULL) {
+ if (pdefrag_q) {
if (fragnum == 0) {
/* the first fragment */
if (!list_empty(&pdefrag_q->queue))
@@ -1482,7 +1415,7 @@ struct recv_frame *recvframe_chk_defrag(struct adapter *padapter,
if ((ismfrag == 0) && (fragnum != 0)) {
/* the last fragment frame */
/* enqueue the last fragment */
- if (pdefrag_q != NULL) {
+ if (pdefrag_q) {
phead = get_list_head(pdefrag_q);
list_add_tail(&pfhdr->list, phead);
@@ -1714,8 +1647,8 @@ static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reor
if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
- ("recv_indicatepkts_in_order: indicate=%d seq=%d amsdu=%d\n",
- preorder_ctrl->indicate_seq, pattrib->seq_num, pattrib->amsdu));
+ ("%s: indicate=%d seq=%d amsdu=%d\n",
+ __func__, preorder_ctrl->indicate_seq, pattrib->seq_num, pattrib->amsdu));
plist = plist->next;
list_del_init(&(prframe->list));
@@ -1762,7 +1695,7 @@ static int recv_indicatepkt_reorder(struct adapter *padapter,
(pattrib->ack_policy != 0)) {
if ((!padapter->bDriverStopped) &&
(!padapter->bSurpriseRemoved)) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ recv_indicatepkt_reorder -recv_func recv_indicatepkt\n"));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ %s -recv_func recv_indicatepkt\n", __func__));
rtw_recv_indicatepkt(padapter, prframe);
return _SUCCESS;
@@ -1792,7 +1725,7 @@ static int recv_indicatepkt_reorder(struct adapter *padapter,
spin_lock_bh(&ppending_recvframe_queue->lock);
RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
- ("recv_indicatepkt_reorder: indicate=%d seq=%d\n",
+ ("%s: indicate=%d seq=%d\n", __func__,
preorder_ctrl->indicate_seq, pattrib->seq_num));
/* s2. check if winstart_b(indicate_seq) needs to been updated */
@@ -1884,10 +1817,10 @@ static int process_recv_indicatepkts(struct adapter *padapter,
if ((!padapter->bDriverStopped) &&
(!padapter->bSurpriseRemoved)) {
/* indicate this recv_frame */
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func recv_indicatepkt\n"));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ %s- recv_func recv_indicatepkt\n", __func__));
rtw_recv_indicatepkt(padapter, prframe);
} else {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func free_indicatepkt\n"));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ %s- recv_func free_indicatepkt\n", __func__));
RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_func:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved));
retval = _FAIL;
@@ -1928,20 +1861,20 @@ static int recv_func_posthandle(struct adapter *padapter,
LedControl8188eu(padapter, LED_CTL_RX);
prframe = decryptor(padapter, prframe);
- if (prframe == NULL) {
+ if (!prframe) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decryptor: drop pkt\n"));
ret = _FAIL;
goto _recv_data_drop;
}
prframe = recvframe_chk_defrag(padapter, prframe);
- if (prframe == NULL) {
+ if (!prframe) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chk_defrag: drop pkt\n"));
goto _recv_data_drop;
}
prframe = portctrl(padapter, prframe);
- if (prframe == NULL) {
+ if (!prframe) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("portctrl: drop pkt\n"));
ret = _FAIL;
goto _recv_data_drop;
@@ -2012,7 +1945,7 @@ s32 rtw_recv_entry(struct recv_frame *precvframe)
ret = recv_func(padapter, precvframe);
if (ret == _FAIL) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("rtw_recv_entry: recv_func return fail!!!\n"));
+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("%s: recv_func return fail!!!\n", __func__));
goto _recv_entry_drop;
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c
index 5b1ef229df2a..bfe0b217e679 100644
--- a/drivers/staging/rtl8188eu/core/rtw_security.c
+++ b/drivers/staging/rtl8188eu/core/rtw_security.c
@@ -18,6 +18,7 @@
#include <drv_types.h>
#include <wifi.h>
#include <osdep_intf.h>
+#include <net/lib80211.h>
/* WEP related ===== */
@@ -195,48 +196,57 @@ void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe)
}
-void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe)
+int rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe)
{
- /* exclude ICV */
- u8 crc[4];
- struct arc4context mycontext;
- int length;
- u32 keylength;
- u8 *pframe, *payload, *iv, wepkey[16];
- u8 keyindex;
struct rx_pkt_attrib *prxattrib = &(((struct recv_frame *)precvframe)->attrib);
- struct security_priv *psecuritypriv = &padapter->securitypriv;
+ if ((prxattrib->encrypt == _WEP40_) || (prxattrib->encrypt == _WEP104_)) {
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct sk_buff *skb = ((struct recv_frame *)precvframe)->pkt;
+ u8 *pframe = skb->data;
+ void *crypto_private = NULL;
+ int status = _SUCCESS;
+ const int keyindex = prxattrib->key_index;
+ struct lib80211_crypto_ops *crypto_ops = try_then_request_module(lib80211_get_crypto_ops("WEP"), "lib80211_crypt_wep");
+ char iv[4], icv[4];
+
+ if (!crypto_ops) {
+ status = _FAIL;
+ goto exit;
+ }
- pframe = (unsigned char *)((struct recv_frame *)precvframe)->pkt->data;
+ memcpy(iv, pframe + prxattrib->hdrlen, 4);
+ memcpy(icv, pframe + skb->len - 4, 4);
- /* start to decrypt recvframe */
- if ((prxattrib->encrypt == _WEP40_) || (prxattrib->encrypt == _WEP104_)) {
- iv = pframe+prxattrib->hdrlen;
- keyindex = prxattrib->key_index;
- keylength = psecuritypriv->dot11DefKeylen[keyindex];
- memcpy(&wepkey[0], iv, 3);
- memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[keyindex].skey[0], keylength);
- length = ((struct recv_frame *)precvframe)->pkt->len-prxattrib->hdrlen-prxattrib->iv_len;
-
- payload = pframe+prxattrib->iv_len+prxattrib->hdrlen;
-
- /* decrypt payload include icv */
- arcfour_init(&mycontext, wepkey, 3+keylength);
- arcfour_encrypt(&mycontext, payload, payload, length);
-
- /* calculate icv and compare the icv */
- *((__le32 *)crc) = getcrc32(payload, length - 4);
-
- if (crc[3] != payload[length-1] ||
- crc[2] != payload[length-2] ||
- crc[1] != payload[length-3] ||
- crc[0] != payload[length-4]) {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
- ("rtw_wep_decrypt:icv error crc (%4ph)!=payload (%4ph)\n",
- &crc, &payload[length-4]));
+ crypto_private = crypto_ops->init(keyindex);
+ if (!crypto_private) {
+ status = _FAIL;
+ goto exit;
}
+ if (crypto_ops->set_key(psecuritypriv->dot11DefKey[keyindex].skey,
+ psecuritypriv->dot11DefKeylen[keyindex], NULL, crypto_private) < 0) {
+ status = _FAIL;
+ goto exit;
+ }
+ if (crypto_ops->decrypt_mpdu(skb, prxattrib->hdrlen, crypto_private)) {
+ status = _FAIL;
+ goto exit;
+ }
+
+ memmove(pframe, pframe + 4, prxattrib->hdrlen);
+ skb_push(skb, 4);
+ skb_put(skb, 4);
+
+ memcpy(pframe + prxattrib->hdrlen, iv, 4);
+ memcpy(pframe + skb->len - 4, icv, 4);
+
+exit:
+ if (crypto_ops && crypto_private)
+ crypto_ops->deinit(crypto_private);
+ return status;
}
+
+ return _FAIL;
}
/* 3 ===== TKIP related ===== */
@@ -593,7 +603,7 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe)
stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]);
if (stainfo != NULL) {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt: stainfo!= NULL!!!\n"));
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo!= NULL!!!\n", __func__));
if (IS_MCAST(pattrib->ra))
prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey;
@@ -633,78 +643,78 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe)
}
}
} else {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt: stainfo==NULL!!!\n"));
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo==NULL!!!\n", __func__));
res = _FAIL;
}
}
return res;
}
-/* The hlen isn't include the IV */
u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe)
-{ /* exclude ICV */
- u16 pnl;
- u32 pnh;
- u8 rc4key[16];
- u8 ttkey[16];
- u8 crc[4];
- struct arc4context mycontext;
- int length;
-
- u8 *pframe, *payload, *iv, *prwskey;
- union pn48 dot11txpn;
- struct sta_info *stainfo;
- struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib;
- struct security_priv *psecuritypriv = &padapter->securitypriv;
- u32 res = _SUCCESS;
-
-
- pframe = (unsigned char *)((struct recv_frame *)precvframe)->pkt->data;
+{
+ struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib;
+ u32 res = _SUCCESS;
/* 4 start to decrypt recvframe */
if (prxattrib->encrypt == _TKIP_) {
- stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]);
- if (stainfo != NULL) {
+ struct sta_info *stainfo = rtw_get_stainfo(&padapter->stapriv, prxattrib->ta);
+
+ if (stainfo) {
+ int key_idx;
+ const int iv_len = 8, icv_len = 4, key_length = 32;
+ void *crypto_private = NULL;
+ struct sk_buff *skb = ((struct recv_frame *)precvframe)->pkt;
+ u8 key[32], iv[8], icv[4], *pframe = skb->data;
+ struct lib80211_crypto_ops *crypto_ops = try_then_request_module(lib80211_get_crypto_ops("TKIP"), "lib80211_crypt_tkip");
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+
if (IS_MCAST(prxattrib->ra)) {
if (!psecuritypriv->binstallGrpkey) {
res = _FAIL;
DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__);
goto exit;
}
- prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey;
+ key_idx = prxattrib->key_index;
+ memcpy(key, psecuritypriv->dot118021XGrpKey[key_idx].skey, 16);
+ memcpy(key + 16, psecuritypriv->dot118021XGrprxmickey[key_idx].skey, 16);
} else {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt: stainfo!= NULL!!!\n"));
- prwskey = &stainfo->dot118021x_UncstKey.skey[0];
+ key_idx = 0;
+ memcpy(key, stainfo->dot118021x_UncstKey.skey, 16);
+ memcpy(key + 16, stainfo->dot11tkiprxmickey.skey, 16);
}
- iv = pframe+prxattrib->hdrlen;
- payload = pframe+prxattrib->iv_len+prxattrib->hdrlen;
- length = ((struct recv_frame *)precvframe)->pkt->len-prxattrib->hdrlen-prxattrib->iv_len;
-
- GET_TKIP_PN(iv, dot11txpn);
-
- pnl = (u16)(dot11txpn.val);
- pnh = (u32)(dot11txpn.val>>16);
+ if (!crypto_ops) {
+ res = _FAIL;
+ goto exit_lib80211_tkip;
+ }
- phase1((u16 *)&ttkey[0], prwskey, &prxattrib->ta[0], pnh);
- phase2(&rc4key[0], prwskey, (unsigned short *)&ttkey[0], pnl);
+ memcpy(iv, pframe + prxattrib->hdrlen, iv_len);
+ memcpy(icv, pframe + skb->len - icv_len, icv_len);
- /* 4 decrypt payload include icv */
+ crypto_private = crypto_ops->init(key_idx);
+ if (!crypto_private) {
+ res = _FAIL;
+ goto exit_lib80211_tkip;
+ }
+ if (crypto_ops->set_key(key, key_length, NULL, crypto_private) < 0) {
+ res = _FAIL;
+ goto exit_lib80211_tkip;
+ }
+ if (crypto_ops->decrypt_mpdu(skb, prxattrib->hdrlen, crypto_private)) {
+ res = _FAIL;
+ goto exit_lib80211_tkip;
+ }
- arcfour_init(&mycontext, rc4key, 16);
- arcfour_encrypt(&mycontext, payload, payload, length);
+ memmove(pframe, pframe + iv_len, prxattrib->hdrlen);
+ skb_push(skb, iv_len);
+ skb_put(skb, icv_len);
- *((__le32 *)crc) = getcrc32(payload, length-4);
+ memcpy(pframe + prxattrib->hdrlen, iv, iv_len);
+ memcpy(pframe + skb->len - icv_len, icv, icv_len);
- if (crc[3] != payload[length-1] ||
- crc[2] != payload[length-2] ||
- crc[1] != payload[length-3] ||
- crc[0] != payload[length-4]) {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
- ("rtw_wep_decrypt:icv error crc (%4ph)!=payload (%4ph)\n",
- &crc, &payload[length-4]));
- res = _FAIL;
- }
+exit_lib80211_tkip:
+ if (crypto_ops && crypto_private)
+ crypto_ops->deinit(crypto_private);
} else {
RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt: stainfo==NULL!!!\n"));
res = _FAIL;
@@ -1235,8 +1245,8 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe)
else
stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]);
- if (stainfo != NULL) {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo!= NULL!!!\n"));
+ if (stainfo) {
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo!= NULL!!!\n", __func__));
if (IS_MCAST(pattrib->ra))
prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey;
@@ -1256,7 +1266,7 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe)
}
}
} else{
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo==NULL!!!\n"));
+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo==NULL!!!\n", __func__));
res = _FAIL;
}
}
@@ -1265,217 +1275,24 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe)
return res;
}
-static int aes_decipher(u8 *key, uint hdrlen,
- u8 *pframe, uint plen)
+u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe)
{
- static u8 message[MAX_MSG_SIZE];
- uint qc_exists, a4_exists, i, j, payload_remainder,
- num_blocks, payload_index;
- int res = _SUCCESS;
-
- u8 pn_vector[6];
- u8 mic_iv[16];
- u8 mic_header1[16];
- u8 mic_header2[16];
- u8 ctr_preload[16];
-
- /* Intermediate Buffers */
- u8 chain_buffer[16];
- u8 aes_out[16];
- u8 padded_buffer[16];
- u8 mic[8];
-
-/* uint offset = 0; */
- uint frtype = GetFrameType(pframe);
- uint frsubtype = GetFrameSubType(pframe);
- frsubtype >>= 4;
-
- memset(mic_iv, 0, 16);
- memset(mic_header1, 0, 16);
- memset(mic_header2, 0, 16);
- memset(ctr_preload, 0, 16);
- memset(chain_buffer, 0, 16);
- memset(aes_out, 0, 16);
- memset(padded_buffer, 0, 16);
-
- /* start to decrypt the payload */
-
- num_blocks = (plen-8) / 16; /* plen including llc, payload_length and mic) */
-
- payload_remainder = (plen-8) % 16;
-
- pn_vector[0] = pframe[hdrlen];
- pn_vector[1] = pframe[hdrlen+1];
- pn_vector[2] = pframe[hdrlen+4];
- pn_vector[3] = pframe[hdrlen+5];
- pn_vector[4] = pframe[hdrlen+6];
- pn_vector[5] = pframe[hdrlen+7];
-
- if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN))
- a4_exists = 0;
- else
- a4_exists = 1;
-
- if ((frtype == WIFI_DATA_CFACK) || (frtype == WIFI_DATA_CFPOLL) ||
- (frtype == WIFI_DATA_CFACKPOLL)) {
- qc_exists = 1;
- if (hdrlen != WLAN_HDR_A3_QOS_LEN)
- hdrlen += 2;
- } else if ((frsubtype == 0x08) || (frsubtype == 0x09) ||
- (frsubtype == 0x0a) || (frsubtype == 0x0b)) {
- if (hdrlen != WLAN_HDR_A3_QOS_LEN)
- hdrlen += 2;
- qc_exists = 1;
- } else {
- qc_exists = 0;
- }
-
- /* now, decrypt pframe with hdrlen offset and plen long */
-
- payload_index = hdrlen + 8; /* 8 is for extiv */
-
- for (i = 0; i < num_blocks; i++) {
- construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, i+1);
-
- aes128k128d(key, ctr_preload, aes_out);
- bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);
-
- for (j = 0; j < 16; j++)
- pframe[payload_index++] = chain_buffer[j];
- }
-
- if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/
- /* encrypt it and copy the unpadded part back */
- construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, num_blocks+1);
-
- for (j = 0; j < 16; j++)
- padded_buffer[j] = 0x00;
- for (j = 0; j < payload_remainder; j++)
- padded_buffer[j] = pframe[payload_index+j];
- aes128k128d(key, ctr_preload, aes_out);
- bitwise_xor(aes_out, padded_buffer, chain_buffer);
- for (j = 0; j < payload_remainder; j++)
- pframe[payload_index++] = chain_buffer[j];
- }
-
- /* start to calculate the mic */
- if ((hdrlen+plen+8) <= MAX_MSG_SIZE)
- memcpy(message, pframe, (hdrlen + plen+8)); /* 8 is for ext iv len */
-
- pn_vector[0] = pframe[hdrlen];
- pn_vector[1] = pframe[hdrlen+1];
- pn_vector[2] = pframe[hdrlen+4];
- pn_vector[3] = pframe[hdrlen+5];
- pn_vector[4] = pframe[hdrlen+6];
- pn_vector[5] = pframe[hdrlen+7];
- construct_mic_iv(mic_iv, qc_exists, a4_exists, message, plen-8, pn_vector);
-
- construct_mic_header1(mic_header1, hdrlen, message);
- construct_mic_header2(mic_header2, message, a4_exists, qc_exists);
-
- payload_remainder = (plen-8) % 16;
- num_blocks = (plen-8) / 16;
-
- /* Find start of payload */
- payload_index = hdrlen + 8;
-
- /* Calculate MIC */
- aes128k128d(key, mic_iv, aes_out);
- bitwise_xor(aes_out, mic_header1, chain_buffer);
- aes128k128d(key, chain_buffer, aes_out);
- bitwise_xor(aes_out, mic_header2, chain_buffer);
- aes128k128d(key, chain_buffer, aes_out);
-
- for (i = 0; i < num_blocks; i++) {
- bitwise_xor(aes_out, &message[payload_index], chain_buffer);
-
- payload_index += 16;
- aes128k128d(key, chain_buffer, aes_out);
- }
-
- /* Add on the final payload block if it needs padding */
- if (payload_remainder > 0) {
- for (j = 0; j < 16; j++)
- padded_buffer[j] = 0x00;
- for (j = 0; j < payload_remainder; j++)
- padded_buffer[j] = message[payload_index++];
- bitwise_xor(aes_out, padded_buffer, chain_buffer);
- aes128k128d(key, chain_buffer, aes_out);
- }
-
- for (j = 0 ; j < 8; j++)
- mic[j] = aes_out[j];
-
- /* Insert MIC into payload */
- for (j = 0; j < 8; j++)
- message[payload_index+j] = mic[j];
-
- payload_index = hdrlen + 8;
- for (i = 0; i < num_blocks; i++) {
- construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, i+1);
- aes128k128d(key, ctr_preload, aes_out);
- bitwise_xor(aes_out, &message[payload_index], chain_buffer);
- for (j = 0; j < 16; j++)
- message[payload_index++] = chain_buffer[j];
- }
-
- if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/
- /* encrypt it and copy the unpadded part back */
- construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, num_blocks+1);
-
- for (j = 0; j < 16; j++)
- padded_buffer[j] = 0x00;
- for (j = 0; j < payload_remainder; j++)
- padded_buffer[j] = message[payload_index+j];
- aes128k128d(key, ctr_preload, aes_out);
- bitwise_xor(aes_out, padded_buffer, chain_buffer);
- for (j = 0; j < payload_remainder; j++)
- message[payload_index++] = chain_buffer[j];
- }
-
- /* Encrypt the MIC */
- construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, 0);
-
- for (j = 0; j < 16; j++)
- padded_buffer[j] = 0x00;
- for (j = 0; j < 8; j++)
- padded_buffer[j] = message[j+hdrlen+8+plen-8];
-
- aes128k128d(key, ctr_preload, aes_out);
- bitwise_xor(aes_out, padded_buffer, chain_buffer);
- for (j = 0; j < 8; j++)
- message[payload_index++] = chain_buffer[j];
-
- /* compare the mic */
- for (i = 0; i < 8; i++) {
- if (pframe[hdrlen+8+plen-8+i] != message[hdrlen+8+plen-8+i]) {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
- ("aes_decipher:mic check error mic[%d]: pframe(%x)!=message(%x)\n",
- i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i]));
- DBG_88E("aes_decipher:mic check error mic[%d]: pframe(%x)!=message(%x)\n",
- i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i]);
- res = _FAIL;
- }
- }
- return res;
-}
-
-u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe)
-{ /* exclude ICV */
- /* Intermediate Buffers */
- int length;
- u8 *pframe, *prwskey; /* *payload,*iv */
- struct sta_info *stainfo;
- struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib;
- struct security_priv *psecuritypriv = &padapter->securitypriv;
- u32 res = _SUCCESS;
+ struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib;
+ u32 res = _SUCCESS;
- pframe = (unsigned char *)((struct recv_frame *)precvframe)->pkt->data;
/* 4 start to encrypt each fragment */
if (prxattrib->encrypt == _AES_) {
- stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]);
+ struct sta_info *stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]);
+
if (stainfo != NULL) {
- RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_decrypt: stainfo!= NULL!!!\n"));
+ int key_idx;
+ const int key_length = 16, iv_len = 8, icv_len = 8;
+ struct sk_buff *skb = ((struct recv_frame *)precvframe)->pkt;
+ void *crypto_private = NULL;
+ u8 *key, *pframe = skb->data;
+ struct lib80211_crypto_ops *crypto_ops = try_then_request_module(lib80211_get_crypto_ops("CCMP"), "lib80211_crypt_ccmp");
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ char iv[8], icv[8];
if (IS_MCAST(prxattrib->ra)) {
/* in concurrent we should use sw descrypt in group key, so we remove this message */
@@ -1484,18 +1301,45 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe)
DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__);
goto exit;
}
- prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey;
- if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) {
- DBG_88E("not match packet_index=%d, install_index=%d\n",
- prxattrib->key_index, psecuritypriv->dot118021XGrpKeyid);
- res = _FAIL;
- goto exit;
- }
+ key_idx = psecuritypriv->dot118021XGrpKeyid;
+ key = psecuritypriv->dot118021XGrpKey[key_idx].skey;
} else {
- prwskey = &stainfo->dot118021x_UncstKey.skey[0];
+ key_idx = 0;
+ key = stainfo->dot118021x_UncstKey.skey;
+ }
+
+ if (!crypto_ops) {
+ res = _FAIL;
+ goto exit_lib80211_ccmp;
}
- length = ((struct recv_frame *)precvframe)->pkt->len-prxattrib->hdrlen-prxattrib->iv_len;
- res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length);
+
+ memcpy(iv, pframe + prxattrib->hdrlen, iv_len);
+ memcpy(icv, pframe + skb->len - icv_len, icv_len);
+
+ crypto_private = crypto_ops->init(key_idx);
+ if (!crypto_private) {
+ res = _FAIL;
+ goto exit_lib80211_ccmp;
+ }
+ if (crypto_ops->set_key(key, key_length, NULL, crypto_private) < 0) {
+ res = _FAIL;
+ goto exit_lib80211_ccmp;
+ }
+ if (crypto_ops->decrypt_mpdu(skb, prxattrib->hdrlen, crypto_private)) {
+ res = _FAIL;
+ goto exit_lib80211_ccmp;
+ }
+
+ memmove(pframe, pframe + iv_len, prxattrib->hdrlen);
+ skb_push(skb, iv_len);
+ skb_put(skb, icv_len);
+
+ memcpy(pframe + prxattrib->hdrlen, iv, iv_len);
+ memcpy(pframe + skb->len - icv_len, icv, icv_len);
+
+exit_lib80211_ccmp:
+ if (crypto_ops && crypto_private)
+ crypto_ops->deinit(crypto_private);
} else {
RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo==NULL!!!\n"));
res = _FAIL;
diff --git a/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c
index 2fd2a9e2416e..f42aa4e0ddb8 100644
--- a/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c
+++ b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c
@@ -194,9 +194,9 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
_rtw_init_stainfo(psta);
memcpy(psta->hwaddr, hwaddr, ETH_ALEN);
index = wifi_mac_hash(hwaddr);
- RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, ("rtw_alloc_stainfo: index=%x", index));
+ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, ("%s: index=%x", __func__, index));
if (index >= NUM_STA) {
- RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("ERROR => rtw_alloc_stainfo: index >= NUM_STA"));
+ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("ERROR => %s: index >= NUM_STA", __func__));
psta = NULL;
goto exit;
}
diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
index 2db8a5d11c0d..9a130cbf6def 100644
--- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
+++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
@@ -715,7 +715,7 @@ void HT_caps_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE)
struct ht_priv *phtpriv = &pmlmepriv->htpriv;
u8 *HT_cap = (u8 *)(&pmlmeinfo->HT_caps);
- if (pIE == NULL)
+ if (!pIE)
return;
if (!phtpriv->ht_option)
@@ -755,7 +755,7 @@ void HT_info_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct ht_priv *phtpriv = &pmlmepriv->htpriv;
- if (pIE == NULL)
+ if (!pIE)
return;
if (!phtpriv->ht_option)
@@ -1534,7 +1534,7 @@ int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie, uint var_ie_l
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
pIE = (struct ndis_802_11_var_ie *)rtw_get_ie(pvar_ie, _SUPPORTEDRATES_IE_, &ie_len, var_ie_len);
- if (pIE == NULL)
+ if (!pIE)
return _FAIL;
if (ie_len > NDIS_802_11_LENGTH_RATES_EX)
return _FAIL;
diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c
index e8d9858f2942..3c034486346b 100644
--- a/drivers/staging/rtl8188eu/core/rtw_xmit.c
+++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c
@@ -387,34 +387,27 @@ u8 qos_acm(u8 acm_mask, u8 priority)
return change_priority;
}
-static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib)
+static void set_qos(struct sk_buff *skb, struct pkt_attrib *pattrib)
{
- struct ethhdr etherhdr;
- struct iphdr ip_hdr;
- s32 user_prio = 0;
-
- _rtw_open_pktfile(ppktfile->pkt, ppktfile);
- _rtw_pktfile_read(ppktfile, (unsigned char *)&etherhdr, ETH_HLEN);
-
- /* get user_prio from IP hdr */
if (pattrib->ether_type == 0x0800) {
- _rtw_pktfile_read(ppktfile, (u8 *)&ip_hdr, sizeof(ip_hdr));
-/* user_prio = (ntohs(ip_hdr.tos) >> 5) & 0x3; */
- user_prio = ip_hdr.tos >> 5;
+ struct iphdr ip_hdr;
+
+ skb_copy_bits(skb, ETH_HLEN, &ip_hdr, sizeof(ip_hdr));
+ pattrib->priority = ip_hdr.tos >> 5;
} else if (pattrib->ether_type == ETH_P_PAE) {
/* "When priority processing of data frames is supported, */
/* a STA's SME should send EAPOL-Key frames at the highest priority." */
- user_prio = 7;
+ pattrib->priority = 7;
+ } else {
+ pattrib->priority = 0;
}
- pattrib->priority = user_prio;
pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN;
pattrib->subtype = WIFI_QOS_DATA_TYPE;
}
static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct pkt_attrib *pattrib)
{
- struct pkt_file pktfile;
struct sta_info *psta = NULL;
struct ethhdr etherhdr;
@@ -425,9 +418,7 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
struct qos_priv *pqospriv = &pmlmepriv->qospriv;
int res = _SUCCESS;
-
- _rtw_open_pktfile(pkt, &pktfile);
- _rtw_pktfile_read(&pktfile, (u8 *)&etherhdr, ETH_HLEN);
+ skb_copy_bits(pkt, 0, &etherhdr, ETH_HLEN);
pattrib->ether_type = ntohs(etherhdr.h_proto);
@@ -448,22 +439,23 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN);
}
- pattrib->pktlen = pktfile.pkt_len;
+ pattrib->pktlen = pkt->len - ETH_HLEN;
if (pattrib->ether_type == ETH_P_IP) {
/* The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time */
/* to prevent DHCP protocol fail */
u8 tmp[24];
- _rtw_pktfile_read(&pktfile, &tmp[0], 24);
+ skb_copy_bits(pkt, ETH_HLEN, tmp, 24);
+
pattrib->dhcp_pkt = 0;
- if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */
+ if (pkt->len > ETH_HLEN + 24 + 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */
if (pattrib->ether_type == ETH_P_IP) {/* IP header */
if (((tmp[21] == 68) && (tmp[23] == 67)) ||
((tmp[21] == 67) && (tmp[23] == 68))) {
/* 68 : UDP BOOTP client */
/* 67 : UDP BOOTP server */
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====================== update_attrib: get DHCP Packet\n"));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====================== %s: get DHCP Packet\n", __func__));
/* Use low rate to send DHCP packet. */
pattrib->dhcp_pkt = 1;
}
@@ -487,7 +479,7 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
psta = rtw_get_bcmc_stainfo(padapter);
} else {
psta = rtw_get_stainfo(pstapriv, pattrib->ra);
- if (psta == NULL) { /* if we cannot get psta => drrp the pkt */
+ if (!psta) { /* if we cannot get psta => drrp the pkt */
RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra: %pM\n", (pattrib->ra)));
res = _FAIL;
goto exit;
@@ -516,10 +508,10 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
if (check_fwstate(pmlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) {
if (psta->qos_option)
- set_qos(&pktfile, pattrib);
+ set_qos(pkt, pattrib);
} else {
if (pqospriv->qos_option) {
- set_qos(&pktfile, pattrib);
+ set_qos(pkt, pattrib);
if (pmlmepriv->acm_mask != 0)
pattrib->priority = qos_acm(pmlmepriv->acm_mask, pattrib->priority);
@@ -587,16 +579,16 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p
}
RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
- ("update_attrib: encrypt=%d\n", pattrib->encrypt));
+ ("%s: encrypt=%d\n", __func__, pattrib->encrypt));
if (pattrib->encrypt && !psecuritypriv->hw_decrypted) {
pattrib->bswenc = true;
RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
- ("update_attrib: encrypt=%d bswenc = true\n",
+ ("%s: encrypt=%d bswenc = true\n", __func__,
pattrib->encrypt));
} else {
pattrib->bswenc = false;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("update_attrib: bswenc = false\n"));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s: bswenc = false\n", __func__));
}
update_attrib_phy_info(pattrib, psta);
@@ -630,7 +622,7 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr
if (pattrib->encrypt == _TKIP_) {/* if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_PRIVACY_) */
/* encode mic code */
- if (stainfo != NULL) {
+ if (stainfo) {
u8 null_key[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0};
@@ -698,11 +690,11 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr
}
}
rtw_secgetmic(&micdata, &mic[0]);
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: before add mic code!!!\n"));
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: pattrib->last_txcmdsz=%d!!!\n", pattrib->last_txcmdsz));
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: mic[0]=0x%.2x , mic[1]=0x%.2x , mic[2]= 0x%.2x, mic[3]=0x%.2x\n\
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: before add mic code!!!\n", __func__));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: pattrib->last_txcmdsz=%d!!!\n", __func__, pattrib->last_txcmdsz));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: mic[0]=0x%.2x , mic[1]=0x%.2x , mic[2]= 0x%.2x, mic[3]=0x%.2x\n\
mic[4]= 0x%.2x , mic[5]= 0x%.2x , mic[6]= 0x%.2x , mic[7]= 0x%.2x !!!!\n",
- mic[0], mic[1], mic[2], mic[3], mic[4], mic[5], mic[6], mic[7]));
+ __func__, mic[0], mic[1], mic[2], mic[3], mic[4], mic[5], mic[6], mic[7]));
/* add mic code and add the mic code length in last_txcmdsz */
memcpy(payload, &mic[0], 8);
@@ -718,7 +710,7 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr
*(payload + curfragnum + 4), *(payload + curfragnum + 5),
*(payload + curfragnum + 6), *(payload + curfragnum + 7)));
} else {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: rtw_get_stainfo==NULL!!!\n"));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: rtw_get_stainfo==NULL!!!\n", __func__));
}
}
@@ -732,7 +724,7 @@ static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmi
if (pattrib->bswenc) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("### xmitframe_swencrypt\n"));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("### %s\n", __func__));
switch (pattrib->encrypt) {
case _WEP40_:
case _WEP104_:
@@ -951,7 +943,6 @@ This sub-routine will perform all the following:
*/
s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct xmit_frame *pxmitframe)
{
- struct pkt_file pktfile;
s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz;
size_t addr;
u8 *pframe, *mem_start;
@@ -962,11 +953,11 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
u8 *pbuf_start;
s32 bmcst = IS_MCAST(pattrib->ra);
s32 res = _SUCCESS;
-
+ size_t remainder = pkt->len - ETH_HLEN;
psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
- if (psta == NULL)
+ if (!psta)
return _FAIL;
if (pxmitframe->buf_addr == NULL) {
@@ -981,15 +972,12 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
mem_start = pbuf_start + hw_hdr_offset;
if (rtw_make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n"));
- DBG_88E("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n");
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: rtw_make_wlanhdr fail; drop pkt\n", __func__));
+ DBG_88E("%s: rtw_make_wlanhdr fail; drop pkt\n", __func__);
res = _FAIL;
goto exit;
}
- _rtw_open_pktfile(pkt, &pktfile);
- _rtw_pktfile_read(&pktfile, NULL, ETH_HLEN);
-
frg_inx = 0;
frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */
@@ -1029,8 +1017,8 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
memcpy(pframe, pattrib->iv, pattrib->iv_len);
RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_,
- ("rtw_xmitframe_coalesce: keyid=%d pattrib->iv[3]=%.2x pframe=%.2x %.2x %.2x %.2x\n",
- padapter->securitypriv.dot11PrivacyKeyIndex, pattrib->iv[3], *pframe, *(pframe+1), *(pframe+2), *(pframe+3)));
+ ("%s: keyid=%d pattrib->iv[3]=%.2x pframe=%.2x %.2x %.2x %.2x\n",
+ __func__, padapter->securitypriv.dot11PrivacyKeyIndex, pattrib->iv[3], *pframe, *(pframe+1), *(pframe+2), *(pframe+3)));
pframe += pattrib->iv_len;
@@ -1046,12 +1034,9 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
if ((pattrib->icv_len > 0) && (pattrib->bswenc))
mpdu_len -= pattrib->icv_len;
- if (bmcst) {
- /* don't do fragment to broadcat/multicast packets */
- mem_sz = _rtw_pktfile_read(&pktfile, pframe, pattrib->pktlen);
- } else {
- mem_sz = _rtw_pktfile_read(&pktfile, pframe, mpdu_len);
- }
+ mem_sz = min_t(size_t, bmcst ? pattrib->pktlen : mpdu_len, remainder);
+ skb_copy_bits(pkt, pkt->len - remainder, pframe, mem_sz);
+ remainder -= mem_sz;
pframe += mem_sz;
@@ -1062,7 +1047,7 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
frg_inx++;
- if (bmcst || pktfile.pkt_len == 0) {
+ if (bmcst || remainder == 0) {
pattrib->nr_frags = frg_inx;
pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + ((pattrib->nr_frags == 1) ? llc_sz : 0) +
@@ -1154,7 +1139,7 @@ void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len)
case AUTO_VCS:
default:
perp = rtw_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len);
- if (perp == NULL) {
+ if (!perp) {
pxmitpriv->vcs = NONE_VCS;
} else {
protection = (*(perp + 2)) & BIT(1);
@@ -1222,7 +1207,7 @@ s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue;
- if (pxmitbuf == NULL)
+ if (!pxmitbuf)
return _FAIL;
spin_lock_irqsave(&pfree_queue->lock, irql);
@@ -1268,7 +1253,7 @@ s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
unsigned long irql;
struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
- if (pxmitbuf == NULL)
+ if (!pxmitbuf)
return _FAIL;
if (pxmitbuf->sctx) {
@@ -1359,8 +1344,8 @@ s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitfram
struct sk_buff *pndis_pkt = NULL;
- if (pxmitframe == NULL) {
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====== rtw_free_xmitframe():pxmitframe == NULL!!!!!!!!!!\n"));
+ if (!pxmitframe) {
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====== %s:pxmitframe == NULL!!!!!!!!!!\n", __func__));
goto exit;
}
@@ -1376,7 +1361,7 @@ s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitfram
list_add_tail(&pxmitframe->list, get_list_head(pfree_xmit_queue));
pxmitpriv->free_xmitframe_cnt++;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe():free_xmitframe_cnt=%d\n", pxmitpriv->free_xmitframe_cnt));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("%s:free_xmitframe_cnt=%d\n", __func__, pxmitpriv->free_xmitframe_cnt));
spin_unlock_bh(&pfree_xmit_queue->lock);
@@ -1415,7 +1400,7 @@ s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitfram
{
if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) {
RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
- ("rtw_xmitframe_enqueue: drop xmit pkt for classifier fail\n"));
+ ("%s: drop xmit pkt for classifier fail\n", __func__));
/* pxmitframe->pkt = NULL; */
return _FAIL;
}
@@ -1505,26 +1490,26 @@ struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *
case 2:
ptxservq = &psta->sta_xmitpriv.bk_q;
*(ac) = 3;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BK\n"));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s : BK\n", __func__));
break;
case 4:
case 5:
ptxservq = &psta->sta_xmitpriv.vi_q;
*(ac) = 1;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VI\n"));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s : VI\n", __func__));
break;
case 6:
case 7:
ptxservq = &psta->sta_xmitpriv.vo_q;
*(ac) = 0;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VO\n"));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s : VO\n", __func__));
break;
case 0:
case 3:
default:
ptxservq = &psta->sta_xmitpriv.be_q;
*(ac) = 2;
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BE\n"));
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s : BE\n", __func__));
break;
}
@@ -1552,10 +1537,10 @@ s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe)
else
psta = rtw_get_stainfo(pstapriv, pattrib->ra);
- if (psta == NULL) {
+ if (!psta) {
res = _FAIL;
- DBG_88E("rtw_xmit_classifier: psta == NULL\n");
- RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmit_classifier: psta == NULL\n"));
+ DBG_88E("%s: psta == NULL\n", __func__);
+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: psta == NULL\n", __func__));
goto exit;
}
@@ -1660,8 +1645,8 @@ s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt)
s32 res;
pxmitframe = rtw_alloc_xmitframe(pxmitpriv);
- if (pxmitframe == NULL) {
- RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: no more pxmitframe\n"));
+ if (!pxmitframe) {
+ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("%s: no more pxmitframe\n", __func__));
DBG_88E("DBG_TX_DROP_FRAME %s no more pxmitframe\n", __func__);
return -1;
}
@@ -1669,7 +1654,7 @@ s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt)
res = update_attrib(padapter, *ppkt, &pxmitframe->attrib);
if (res == _FAIL) {
- RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: update attrib fail\n"));
+ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("%s: update attrib fail\n", __func__));
rtw_free_xmitframe(pxmitpriv, pxmitframe);
return -1;
}
@@ -1713,7 +1698,7 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra
else
psta = rtw_get_stainfo(pstapriv, pattrib->ra);
- if (psta == NULL)
+ if (!psta)
return ret;
if (pattrib->triggered == 1) {
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
index 9b7ba9bffb0d..8d242adae4b3 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
@@ -36,7 +36,7 @@ static u8 _is_fw_read_cmd_down(struct adapter *adapt, u8 msgbox_num)
do {
valid = usb_read8(adapt, REG_HMETFR) & BIT(msgbox_num);
- if (0 == valid)
+ if (valid == 0)
read_down = true;
} while ((!read_down) && (retry_cnts--));
@@ -67,7 +67,8 @@ static s32 FillH2CCmd_88E(struct adapter *adapt, u8 ElementID, u32 CmdLen, u8 *p
if (!adapt->bFWReady) {
- DBG_88E("FillH2CCmd_88E(): return H2C cmd because fw is not ready\n");
+ DBG_88E("%s(): return H2C cmd because fw is not ready\n",
+ __func__);
return ret;
}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c b/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
index d04b7fbb71e1..ff227c8b98ca 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
@@ -182,7 +182,7 @@ void rtw_hal_dm_init(struct adapter *Adapter)
/* Compare RSSI for deciding antenna */
void rtw_hal_antdiv_rssi_compared(struct adapter *Adapter, struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src)
{
- if (0 != Adapter->HalData->AntDivCfg) {
+ if (Adapter->HalData->AntDivCfg != 0) {
/* select optimum_antenna for before linked =>For antenna diversity */
if (dst->Rssi >= src->Rssi) {/* keep org parameter */
src->Rssi = dst->Rssi;
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
index 3673f573ac3d..54ede4baa0c9 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
@@ -221,13 +221,13 @@ s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy)
} else {
for (i = 0; i < (txpktbuf_bndy - 1); i++) {
status = _LLTWrite(padapter, i, i + 1);
- if (_SUCCESS != status)
+ if (status != _SUCCESS)
return status;
}
/* end of list */
status = _LLTWrite(padapter, (txpktbuf_bndy - 1), 0xFF);
- if (_SUCCESS != status)
+ if (status != _SUCCESS)
return status;
/* Make the other pages as ring buffer */
@@ -235,13 +235,13 @@ s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy)
/* Otherwise used as local loopback buffer. */
for (i = txpktbuf_bndy; i < Last_Entry_Of_TxPktBuf; i++) {
status = _LLTWrite(padapter, i, (i + 1));
- if (_SUCCESS != status)
+ if (status != _SUCCESS)
return status;
}
/* Let last entry point to the start entry of ring buffer */
status = _LLTWrite(padapter, Last_Entry_Of_TxPktBuf, txpktbuf_bndy);
- if (_SUCCESS != status) {
+ if (status != _SUCCESS) {
return status;
}
}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
index a9912b60eb59..4f0f512f303c 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
@@ -552,7 +552,7 @@ s32 rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmitp
pbuf = round_up(pbuf_tail, 8);
pfirstframe->agg_num++;
- if (MAX_TX_AGG_PACKET_NUMBER == pfirstframe->agg_num)
+ if (pfirstframe->agg_num == MAX_TX_AGG_PACKET_NUMBER)
break;
if (pbuf < bulkptr) {
diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c
index 17967c944946..c3bb183aba38 100644
--- a/drivers/staging/rtl8188eu/hal/usb_halinit.c
+++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c
@@ -1516,8 +1516,8 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val)
case HW_VAR_CAM_WRITE:
{
u32 cmd;
-
u32 *cam_val = (u32 *)val;
+
usb_write32(Adapter, WCAMI, cam_val[0]);
cmd = CAM_POLLINIG | CAM_WRITE | cam_val[1];
diff --git a/drivers/staging/rtl8188eu/include/rtw_security.h b/drivers/staging/rtl8188eu/include/rtw_security.h
index a0c6cf706218..b1883ca852af 100644
--- a/drivers/staging/rtl8188eu/include/rtw_security.h
+++ b/drivers/staging/rtl8188eu/include/rtw_security.h
@@ -308,6 +308,6 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe);
void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe);
u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe);
u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe);
-void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe);
+int rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe);
#endif /* __RTL871X_SECURITY_H_ */
diff --git a/drivers/staging/rtl8188eu/include/xmit_osdep.h b/drivers/staging/rtl8188eu/include/xmit_osdep.h
index 959ef4b3066c..00ebad88f0d1 100644
--- a/drivers/staging/rtl8188eu/include/xmit_osdep.h
+++ b/drivers/staging/rtl8188eu/include/xmit_osdep.h
@@ -18,15 +18,6 @@
#include <osdep_service.h>
#include <drv_types.h>
-struct pkt_file {
- struct sk_buff *pkt;
- size_t pkt_len; /* the remainder length of the open_file */
- unsigned char *cur_buffer;
- u8 *buf_start;
- u8 *cur_addr;
- size_t buf_len;
-};
-
#define NR_XMITFRAME 256
struct xmit_priv;
@@ -43,10 +34,6 @@ int rtw_os_xmit_resource_alloc(struct adapter *padapter,
struct xmit_buf *pxmitbuf, u32 alloc_sz);
void rtw_os_xmit_resource_free(struct xmit_buf *pxmitbuf);
-uint rtw_remainder_len(struct pkt_file *pfile);
-void _rtw_open_pktfile(struct sk_buff *pkt, struct pkt_file *pfile);
-uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen);
-
void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt);
void rtw_os_xmit_complete(struct adapter *padapter,
struct xmit_frame *pxframe);
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
index 32c7225a831e..127ecf896fc9 100644
--- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c
+++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
@@ -333,7 +333,7 @@ static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj,
struct net_device *pmondev;
int status = _FAIL;
- padapter = (struct adapter *)vzalloc(sizeof(*padapter));
+ padapter = vzalloc(sizeof(*padapter));
if (padapter == NULL)
goto exit;
padapter->dvobj = dvobj;
diff --git a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
index 8bf8248e4ac7..8ac9567c954d 100644
--- a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
@@ -22,43 +22,6 @@
#include <xmit_osdep.h>
#include <osdep_intf.h>
-uint rtw_remainder_len(struct pkt_file *pfile)
-{
- return pfile->buf_len - ((size_t)(pfile->cur_addr) -
- (size_t)(pfile->buf_start));
-}
-
-void _rtw_open_pktfile(struct sk_buff *pktptr, struct pkt_file *pfile)
-{
-
- pfile->pkt = pktptr;
- pfile->cur_addr = pktptr->data;
- pfile->buf_start = pktptr->data;
- pfile->pkt_len = pktptr->len;
- pfile->buf_len = pktptr->len;
-
- pfile->cur_buffer = pfile->buf_start;
-
-}
-
-uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen)
-{
- uint len = 0;
-
-
- len = rtw_remainder_len(pfile);
- len = min(rlen, len);
-
- if (rmem)
- skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len);
-
- pfile->cur_addr += len;
- pfile->pkt_len -= len;
-
-
- return len;
-}
-
int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz)
{
int i;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
index f802f60281f8..843e874b8a06 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
@@ -36,7 +36,6 @@ static int _rtl92e_wx_get_freq(struct net_device *dev,
return rtllib_wx_get_freq(priv->rtllib, a, wrqu, b);
}
-
static int _rtl92e_wx_get_mode(struct net_device *dev,
struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
@@ -149,7 +148,6 @@ static int _rtl92e_wx_set_rawtx(struct net_device *dev,
mutex_unlock(&priv->wx_mutex);
return ret;
-
}
static int _rtl92e_wx_force_reset(struct net_device *dev,
@@ -165,7 +163,6 @@ static int _rtl92e_wx_force_reset(struct net_device *dev,
priv->force_reset = *extra;
mutex_unlock(&priv->wx_mutex);
return 0;
-
}
static int _rtl92e_wx_adapter_power_status(struct net_device *dev,
@@ -174,7 +171,7 @@ static int _rtl92e_wx_adapter_power_status(struct net_device *dev,
{
struct r8192_priv *priv = rtllib_priv(dev);
struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *)
- (&(priv->rtllib->PowerSaveControl));
+ (&priv->rtllib->PowerSaveControl);
struct rtllib_device *ieee = priv->rtllib;
mutex_lock(&priv->wx_mutex);
@@ -205,7 +202,7 @@ static int _rtl92e_wx_set_lps_awake_interval(struct net_device *dev,
{
struct r8192_priv *priv = rtllib_priv(dev);
struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *)
- (&(priv->rtllib->PowerSaveControl));
+ (&priv->rtllib->PowerSaveControl);
mutex_lock(&priv->wx_mutex);
@@ -231,7 +228,6 @@ static int _rtl92e_wx_set_force_lps(struct net_device *dev,
priv->force_lps = *extra;
mutex_unlock(&priv->wx_mutex);
return 0;
-
}
static int _rtl92e_wx_set_debug(struct net_device *dev,
@@ -247,7 +243,7 @@ static int _rtl92e_wx_set_debug(struct net_device *dev,
netdev_info(dev, "=====>%s(), *extra:%x, debugflag:%x\n", __func__,
*extra, rt_global_debug_component);
if (c > 0)
- rt_global_debug_component |= (1<<c);
+ rt_global_debug_component |= (1 << c);
else
rt_global_debug_component &= BIT31;
return 0;
@@ -356,7 +352,7 @@ static int _rtl92e_wx_get_range(struct net_device *dev,
range->min_pmp = 0;
range->max_pmp = 5000000;
range->min_pmt = 0;
- range->max_pmt = 65535*1000;
+ range->max_pmt = 65535 * 1000;
range->pmp_flags = IW_POWER_PERIOD;
range->pmt_flags = IW_POWER_TIMEOUT;
range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
@@ -364,7 +360,7 @@ static int _rtl92e_wx_get_range(struct net_device *dev,
range->we_version_source = 18;
for (i = 0, val = 0; i < 14; i++) {
- if ((priv->rtllib->active_channel_map)[i+1]) {
+ if ((priv->rtllib->active_channel_map)[i + 1]) {
range->freq[val].i = i + 1;
range->freq[val].m = rtllib_wlan_frequencies[i] *
100000;
@@ -377,8 +373,8 @@ static int _rtl92e_wx_get_range(struct net_device *dev,
}
range->num_frequency = val;
range->num_channels = val;
- range->enc_capa = IW_ENC_CAPA_WPA|IW_ENC_CAPA_WPA2|
- IW_ENC_CAPA_CIPHER_TKIP|IW_ENC_CAPA_CIPHER_CCMP;
+ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE;
/* Event capability (kernel + driver) */
@@ -475,12 +471,10 @@ static int _rtl92e_wx_set_scan(struct net_device *dev,
return ret;
}
-
static int _rtl92e_wx_get_scan(struct net_device *dev,
struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
{
-
int ret;
struct r8192_priv *priv = rtllib_priv(dev);
@@ -490,7 +484,6 @@ static int _rtl92e_wx_get_scan(struct net_device *dev,
if (priv->bHwRadioOff)
return 0;
-
mutex_lock(&priv->wx_mutex);
ret = rtllib_wx_get_scan(priv->rtllib, a, wrqu, b);
@@ -552,7 +545,6 @@ static int _rtl92e_wx_set_nick(struct net_device *dev,
memcpy(priv->nick, extra, wrqu->data.length);
mutex_unlock(&priv->wx_mutex);
return 0;
-
}
static int _rtl92e_wx_get_nick(struct net_device *dev,
@@ -596,7 +588,6 @@ static int _rtl92e_wx_get_name(struct net_device *dev,
return rtllib_wx_get_name(priv->rtllib, info, wrqu, extra);
}
-
static int _rtl92e_wx_set_frag(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
@@ -619,7 +610,6 @@ static int _rtl92e_wx_set_frag(struct net_device *dev,
return 0;
}
-
static int _rtl92e_wx_get_frag(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
@@ -633,7 +623,6 @@ static int _rtl92e_wx_get_frag(struct net_device *dev,
return 0;
}
-
static int _rtl92e_wx_set_wap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *awrq, char *extra)
@@ -651,10 +640,8 @@ static int _rtl92e_wx_set_wap(struct net_device *dev,
mutex_unlock(&priv->wx_mutex);
return ret;
-
}
-
static int _rtl92e_wx_get_wap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
@@ -664,7 +651,6 @@ static int _rtl92e_wx_get_wap(struct net_device *dev,
return rtllib_wx_get_wap(priv->rtllib, info, wrqu, extra);
}
-
static int _rtl92e_wx_get_enc(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *key)
@@ -707,7 +693,6 @@ static int _rtl92e_wx_set_enc(struct net_device *dev,
ret = rtllib_wx_set_encode(priv->rtllib, info, wrqu, key);
mutex_unlock(&priv->wx_mutex);
-
if (wrqu->encoding.flags & IW_ENCODE_DISABLED) {
ieee->pairwise_key_type = ieee->group_key_type = KEY_TYPE_NA;
rtl92e_cam_reset(dev);
@@ -716,9 +701,8 @@ static int _rtl92e_wx_set_enc(struct net_device *dev,
goto end_hw_sec;
}
if (wrqu->encoding.length != 0) {
-
for (i = 0; i < 4; i++) {
- hwkey[i] |= key[4*i+0]&mask;
+ hwkey[i] |= key[4 * i + 0] & mask;
if (i == 1 && (4 * i + 1) == wrqu->encoding.length)
mask = 0x00;
if (i == 3 && (4 * i + 1) == wrqu->encoding.length)
@@ -786,8 +770,6 @@ static int _rtl92e_wx_set_scan_type(struct net_device *dev,
return 1;
}
-
-
#define R8192_MAX_RETRY 255
static int _rtl92e_wx_set_retry(struct net_device *dev,
struct iw_request_info *info,
@@ -833,7 +815,6 @@ static int _rtl92e_wx_get_retry(struct net_device *dev,
{
struct r8192_priv *priv = rtllib_priv(dev);
-
wrqu->retry.disabled = 0; /* can't be disabled */
if ((wrqu->retry.flags & IW_RETRY_TYPE) ==
@@ -862,12 +843,10 @@ static int _rtl92e_wx_get_sens(struct net_device *dev,
return 0;
}
-
static int _rtl92e_wx_set_sens(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
-
struct r8192_priv *priv = rtllib_priv(dev);
short err = 0;
@@ -963,15 +942,12 @@ static int _rtl92e_wx_set_encode_ext(struct net_device *dev,
rtl92e_set_swcam(dev, 4, idx, alg,
(u8 *)ieee->ap_mac_addr, 0, key, 0);
}
-
-
}
end_hw_sec:
priv->rtllib->wx_set_enc = 0;
mutex_unlock(&priv->wx_mutex);
return ret;
-
}
static int _rtl92e_wx_set_auth(struct net_device *dev,
@@ -986,7 +962,7 @@ static int _rtl92e_wx_set_auth(struct net_device *dev,
return 0;
mutex_lock(&priv->wx_mutex);
- ret = rtllib_wx_set_auth(priv->rtllib, info, &(data->param), extra);
+ ret = rtllib_wx_set_auth(priv->rtllib, info, &data->param, extra);
mutex_unlock(&priv->wx_mutex);
return ret;
}
@@ -995,7 +971,6 @@ static int _rtl92e_wx_set_mlme(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
-
int ret = 0;
struct r8192_priv *priv = rtllib_priv(dev);
@@ -1089,7 +1064,6 @@ static int _rtl92e_wx_set_promisc_mode(struct net_device *dev,
return 0;
}
-
static int _rtl92e_wx_get_promisc_mode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
@@ -1109,7 +1083,6 @@ static int _rtl92e_wx_get_promisc_mode(struct net_device *dev,
return 0;
}
-
#define IW_IOCTL(x) ((x) - SIOCSIWCOMMIT)
static iw_handler r8192_wx_handlers[] = {
[IW_IOCTL(SIOCGIWNAME)] = _rtl92e_wx_get_name,
@@ -1166,15 +1139,15 @@ static const struct iw_priv_args r8192_private_args[] = {
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "forcereset"
}, {
SIOCIWFIRSTPRIV + 0x6,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED|1, IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE,
"set_power"
}, {
SIOCIWFIRSTPRIV + 0xa,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED|1, IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE,
"lps_interv"
}, {
SIOCIWFIRSTPRIV + 0xb,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED|1, IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE,
"lps_force"
}, {
SIOCIWFIRSTPRIV + 0x16,
diff --git a/drivers/staging/rtl8192e/rtl819x_BAProc.c b/drivers/staging/rtl8192e/rtl819x_BAProc.c
index eb6d841f7c45..c466a5e7e3bd 100644
--- a/drivers/staging/rtl8192e/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192e/rtl819x_BAProc.c
@@ -76,7 +76,7 @@ static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *Dst,
u16 StatusCode, u8 type)
{
struct sk_buff *skb = NULL;
- struct rtllib_hdr_3addr *BAReq = NULL;
+ struct rtllib_hdr_3addr *BAReq = NULL;
u8 *tag = NULL;
u16 len = ieee->tx_headroom + 9;
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
index 30f72d220af1..fa580ce1cf43 100644
--- a/drivers/staging/rtl8192e/rtllib_rx.c
+++ b/drivers/staging/rtl8192e/rtllib_rx.c
@@ -2644,8 +2644,8 @@ static inline void rtllib_process_probe_response(
(network->ssid_len ? 1 : 0))) {
update_network(ieee, &ieee->current_network, network);
if ((ieee->current_network.mode == IEEE_N_24G ||
- ieee->current_network.mode == IEEE_G)
- && ieee->current_network.berp_info_valid) {
+ ieee->current_network.mode == IEEE_G) &&
+ ieee->current_network.berp_info_valid) {
if (ieee->current_network.erp_value & ERP_UseProtection)
ieee->current_network.buseprotection = true;
else
diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c
index 03fbff067fa4..74d4d2df3eb3 100644
--- a/drivers/staging/rtl8192e/rtllib_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_wx.c
@@ -371,8 +371,7 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee,
struct lib80211_crypt_data *new_crypt;
/* take WEP into use */
- new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
- GFP_KERNEL);
+ new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
if (new_crypt == NULL)
return -ENOMEM;
new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c
index e6648f7723ce..a4b40422e5bd 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c
@@ -73,7 +73,7 @@ static void *ieee80211_ccmp_init(int key_idx)
priv->tfm = (void *)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tfm)) {
- printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate crypto API aes\n");
+ pr_debug("ieee80211_crypt_ccmp: could not allocate crypto API aes\n");
priv->tfm = NULL;
goto fail;
}
@@ -276,22 +276,22 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
keyidx = pos[3];
if (!(keyidx & (1 << 5))) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "CCMP: received packet without ExtIV flag from %pM\n",
- hdr->addr2);
+ netdev_dbg(skb->dev, "CCMP: received packet without ExtIV flag from %pM\n",
+ hdr->addr2);
}
key->dot11RSNAStatsCCMPFormatErrors++;
return -2;
}
keyidx >>= 6;
if (key->key_idx != keyidx) {
- printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame keyidx=%d priv=%p\n",
- key->key_idx, keyidx, priv);
+ netdev_dbg(skb->dev, "CCMP: RX tkey->key_idx=%d frame keyidx=%d priv=%p\n",
+ key->key_idx, keyidx, priv);
return -6;
}
if (!key->key_set) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "CCMP: received packet from %pM with keyid=%d that does not have a configured key\n",
- hdr->addr2, keyidx);
+ netdev_dbg(skb->dev, "CCMP: received packet from %pM with keyid=%d that does not have a configured key\n",
+ hdr->addr2, keyidx);
}
return -3;
}
@@ -306,8 +306,8 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "CCMP: replay detected: STA=%pM previous PN %pm received PN %pm\n",
- hdr->addr2, key->rx_pn, pn);
+ netdev_dbg(skb->dev, "CCMP: replay detected: STA=%pM previous PN %pm received PN %pm\n",
+ hdr->addr2, key->rx_pn, pn);
}
key->dot11RSNAStatsCCMPReplays++;
return -4;
@@ -341,8 +341,8 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "CCMP: decrypt failed: STA=%pM\n",
- hdr->addr2);
+ netdev_dbg(skb->dev, "CCMP: decrypt failed: STA=%pM\n",
+ hdr->addr2);
}
key->dot11RSNAStatsCCMPDecryptErrors++;
return -5;
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
index 21b55fd5b717..86c73570e88a 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
@@ -195,7 +195,9 @@ static struct sk_buff *ieee80211_DELBA(
u16 len = 6 + ieee->tx_headroom;
if (net_ratelimit())
- IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), ReasonCode(%d) sentd to:%pM\n", __func__, ReasonCode, dst);
+ IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA,
+ "========>%s(), ReasonCode(%d) sentd to:%pM\n",
+ __func__, ReasonCode, dst);
memset(&DelbaParamSet, 0, 2);
@@ -233,7 +235,8 @@ static struct sk_buff *ieee80211_DELBA(
IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
if (net_ratelimit())
- IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "<=====%s()\n", __func__);
+ IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA,
+ "<=====%s()\n", __func__);
return skb;
}
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index 3c300f7b6a62..d607c59761cf 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -1706,6 +1706,8 @@ static short rtl8192_usb_initendpoints(struct net_device *dev)
priv->rx_urb[16] = usb_alloc_urb(0, GFP_KERNEL);
priv->oldaddr = kmalloc(16, GFP_KERNEL);
+ if (!priv->oldaddr)
+ return -ENOMEM;
oldaddr = priv->oldaddr;
align = ((long)oldaddr) & 3;
if (align) {
diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h
index ae79047ac6dc..ede99e96984f 100644
--- a/drivers/staging/rtl8712/drv_types.h
+++ b/drivers/staging/rtl8712/drv_types.h
@@ -161,7 +161,7 @@ struct _adapter {
u8 EepromAddressSize;
u8 hw_init_completed;
struct task_struct *cmdThread;
- pid_t evtThread;
+ pid_t evtThread;
struct task_struct *xmitThread;
pid_t recvThread;
uint (*dvobj_init)(struct _adapter *adapter);
diff --git a/drivers/staging/rtl8712/ieee80211.c b/drivers/staging/rtl8712/ieee80211.c
index 987270395635..7a4c00e49a88 100644
--- a/drivers/staging/rtl8712/ieee80211.c
+++ b/drivers/staging/rtl8712/ieee80211.c
@@ -107,7 +107,7 @@ u8 *r8712_set_ie(u8 *pbuf, sint index, uint len, u8 *source, uint *frlen)
* index: the information element id index, limit is the limit for search
* ---------------------------------------------------------------------------
*/
-u8 *r8712_get_ie(u8 *pbuf, sint index, sint *len, sint limit)
+u8 *r8712_get_ie(u8 *pbuf, sint index, uint *len, sint limit)
{
sint tmp, i;
u8 *p;
@@ -166,7 +166,8 @@ static uint r8712_get_rateset_len(u8 *rateset)
int r8712_generate_ie(struct registry_priv *pregistrypriv)
{
- int sz = 0, rate_len;
+ int rate_len;
+ uint sz = 0;
struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network;
u8 *ie = pdev_network->IEs;
u16 beaconPeriod = (u16)pdev_network->Configuration.BeaconPeriod;
@@ -211,9 +212,9 @@ int r8712_generate_ie(struct registry_priv *pregistrypriv)
return sz;
}
-unsigned char *r8712_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit)
+unsigned char *r8712_get_wpa_ie(unsigned char *pie, uint *wpa_ie_len, int limit)
{
- int len;
+ u32 len;
u16 val16;
unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01};
u8 *pbuf = pie;
@@ -245,7 +246,7 @@ check_next_ie:
return NULL;
}
-unsigned char *r8712_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit)
+unsigned char *r8712_get_wpa2_ie(unsigned char *pie, uint *rsn_ie_len, int limit)
{
return r8712_get_ie(pie, _WPA2_IE_ID_, rsn_ie_len, limit);
}
diff --git a/drivers/staging/rtl8712/ieee80211.h b/drivers/staging/rtl8712/ieee80211.h
index 68fd65e80906..d605dfd02200 100644
--- a/drivers/staging/rtl8712/ieee80211.h
+++ b/drivers/staging/rtl8712/ieee80211.h
@@ -738,9 +738,9 @@ static inline int ieee80211_get_hdrlen(u16 fc)
struct registry_priv;
u8 *r8712_set_ie(u8 *pbuf, sint index, uint len, u8 *source, uint *frlen);
-u8 *r8712_get_ie(u8 *pbuf, sint index, sint *len, sint limit);
-unsigned char *r8712_get_wpa_ie(unsigned char *pie, int *rsn_ie_len, int limit);
-unsigned char *r8712_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len,
+u8 *r8712_get_ie(u8 *pbuf, sint index, uint *len, sint limit);
+unsigned char *r8712_get_wpa_ie(unsigned char *pie, uint *rsn_ie_len, int limit);
+unsigned char *r8712_get_wpa2_ie(unsigned char *pie, uint *rsn_ie_len,
int limit);
int r8712_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
int *pairwise_cipher);
diff --git a/drivers/staging/rtl8712/mlme_linux.c b/drivers/staging/rtl8712/mlme_linux.c
index 3c7c4a4faeb2..baaa52f04560 100644
--- a/drivers/staging/rtl8712/mlme_linux.c
+++ b/drivers/staging/rtl8712/mlme_linux.c
@@ -36,7 +36,7 @@ static void sitesurvey_ctrl_handler(struct timer_list *t)
{
struct _adapter *adapter =
from_timer(adapter, t,
- mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer);
+ mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer);
_r8712_sitesurvey_ctrl_handler(adapter);
mod_timer(&adapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer,
diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c
index e7df5d7986fc..ff4e451c10f9 100644
--- a/drivers/staging/rtl8712/os_intfs.c
+++ b/drivers/staging/rtl8712/os_intfs.c
@@ -230,7 +230,7 @@ struct net_device *r8712_init_netdev(void)
static u32 start_drv_threads(struct _adapter *padapter)
{
padapter->cmdThread = kthread_run(r8712_cmd_thread, padapter, "%s",
- padapter->pnetdev->name);
+ padapter->pnetdev->name);
if (IS_ERR(padapter->cmdThread))
return _FAIL;
return _SUCCESS;
@@ -347,7 +347,6 @@ u8 r8712_free_drv_sw(struct _adapter *padapter)
return _SUCCESS;
}
-
static void enable_video_mode(struct _adapter *padapter, int cbw40_value)
{
/* bit 8:
diff --git a/drivers/staging/rtl8712/recv_linux.c b/drivers/staging/rtl8712/recv_linux.c
index 986a55bb9877..8cf4286f6318 100644
--- a/drivers/staging/rtl8712/recv_linux.c
+++ b/drivers/staging/rtl8712/recv_linux.c
@@ -111,8 +111,8 @@ void r8712_recv_indicatepkt(struct _adapter *padapter,
_pkt *skb;
struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
- precvpriv = &(padapter->recvpriv);
- pfree_recv_queue = &(precvpriv->free_recv_queue);
+ precvpriv = &padapter->recvpriv;
+ pfree_recv_queue = &precvpriv->free_recv_queue;
skb = precv_frame->u.hdr.pkt;
if (!skb)
goto _recv_indicatepkt_drop;
diff --git a/drivers/staging/rtl8712/rtl8712_bitdef.h b/drivers/staging/rtl8712/rtl8712_bitdef.h
index bff57a8eef3c..dee35fe2587a 100644
--- a/drivers/staging/rtl8712/rtl8712_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_bitdef.h
@@ -18,7 +18,6 @@
*
******************************************************************************/
-
#ifndef __RTL8712_BITDEF_H__
#define __RTL8712_BITDEF_H__
diff --git a/drivers/staging/rtl8712/rtl8712_cmd.c b/drivers/staging/rtl8712/rtl8712_cmd.c
index 9c8e0c50a804..b1dfe9f46619 100644
--- a/drivers/staging/rtl8712/rtl8712_cmd.c
+++ b/drivers/staging/rtl8712/rtl8712_cmd.c
@@ -320,7 +320,7 @@ int r8712_cmd_thread(void *context)
struct tx_desc *pdesc;
void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd);
struct _adapter *padapter = context;
- struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
struct completion *cmd_queue_comp =
&pcmdpriv->cmd_queue_comp;
struct mutex *pwctrl_lock = &padapter->pwrctrlpriv.mutex_lock;
@@ -334,7 +334,7 @@ int r8712_cmd_thread(void *context)
if (r8712_register_cmd_alive(padapter) != _SUCCESS)
continue;
_next:
- pcmd = r8712_dequeue_cmd(&(pcmdpriv->cmd_queue));
+ pcmd = r8712_dequeue_cmd(&pcmdpriv->cmd_queue);
if (!(pcmd)) {
r8712_unregister_cmd_alive(padapter);
continue;
@@ -419,7 +419,7 @@ _next:
}
/* free all cmd_obj resources */
do {
- pcmd = r8712_dequeue_cmd(&(pcmdpriv->cmd_queue));
+ pcmd = r8712_dequeue_cmd(&pcmdpriv->cmd_queue);
if (!pcmd)
break;
r8712_free_cmd_obj(pcmd);
@@ -433,7 +433,7 @@ void r8712_event_handle(struct _adapter *padapter, __le32 *peventbuf)
u8 evt_code, evt_seq;
u16 evt_sz;
void (*event_callback)(struct _adapter *dev, u8 *pbuf);
- struct evt_priv *pevt_priv = &(padapter->evtpriv);
+ struct evt_priv *pevt_priv = &padapter->evtpriv;
if (!peventbuf)
goto _abort_event_;
diff --git a/drivers/staging/rtl8712/rtl8712_cmd.h b/drivers/staging/rtl8712/rtl8712_cmd.h
index 67e9e910aef9..9181bb6b04c3 100644
--- a/drivers/staging/rtl8712/rtl8712_cmd.h
+++ b/drivers/staging/rtl8712/rtl8712_cmd.h
@@ -145,8 +145,8 @@ enum rtl8712_h2c_cmd {
#define _SetBBReg_CMD_ _Write_BBREG_CMD_
#define _GetRFReg_CMD_ _Read_RFREG_CMD_
#define _SetRFReg_CMD_ _Write_RFREG_CMD_
-#define _DRV_INT_CMD_ (MAX_H2CCMD+1)
-#define _SetRFIntFs_CMD_ (MAX_H2CCMD+2)
+#define _DRV_INT_CMD_ (MAX_H2CCMD + 1)
+#define _SetRFIntFs_CMD_ (MAX_H2CCMD + 2)
#ifdef _RTL8712_CMD_C_
static struct _cmd_callback cmd_callback[] = {
diff --git a/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h
index b7dda903001f..4b8985d50098 100644
--- a/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h
@@ -63,7 +63,7 @@
#define _IMEM_CHK_RPT BIT(1)
#define _IMEM_CODE_DONE BIT(0)
-#define _TXDMA_INIT_VALUE (_IMEM_CHK_RPT|_EMEM_CHK_RPT)
+#define _TXDMA_INIT_VALUE (_IMEM_CHK_RPT | _EMEM_CHK_RPT)
/*RCR*/
#define _ENMBID BIT(27)
diff --git a/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h b/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h
index 9374f1c48853..8df42a70399f 100644
--- a/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h
@@ -20,7 +20,6 @@
#ifndef __RTL8712_CMDCTRL_REGDEF_H__
#define __RTL8712_CMDCTRL_REGDEF_H__
-
#define CR (RTL8712_CMDCTRL_ + 0x0000)
#define TXPAUSE (RTL8712_CMDCTRL_ + 0x0002)
#define TCR (RTL8712_CMDCTRL_ + 0x0004)
@@ -29,6 +28,5 @@
#define SYSF_CFG (RTL8712_CMDCTRL_ + 0x000D)
#define MBIDCTRL (RTL8712_CMDCTRL_ + 0x000E)
-
#endif /* __RTL8712_CMDCTRL_REGDEF_H__ */
diff --git a/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h
index 8bd483795ca4..4b3436795cb1 100644
--- a/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h
@@ -51,5 +51,4 @@
/*FDLOCKFLAG1*/
#define _LOCKFLAG1_MSK 0x03
-
#endif /* __RTL8712_DEBUGCTRL_BITDEF_H__ */
diff --git a/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h b/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h
index 43630bb068f5..d7c964d436a1 100644
--- a/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h
@@ -41,7 +41,5 @@
#define TRXPKTBUF_DBG_CTRL (RTL8712_DEBUGCTRL_ + 0x38)
#define DPLL_MON (RTL8712_DEBUGCTRL_ + 0x3A)
-
-
#endif /* __RTL8712_DEBUGCTRL_REGDEF_H__ */
diff --git a/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h
index c564dc862d9d..bd8240476d71 100644
--- a/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h
@@ -140,6 +140,5 @@
/*TXFF_PG_NUM*/
#define _TXFF_PG_NUM_MSK 0x0FFF
-
#endif /* __RTL8712_FIFOCTRL_BITDEF_H__ */
diff --git a/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h b/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h
index 29b89c45c70c..6d527380fd29 100644
--- a/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h
@@ -71,6 +71,4 @@
#define TXQ_PGADD (RTL8712_FIFOCTRL_ + 0xB3)
#define TXFF_PG_NUM (RTL8712_FIFOCTRL_ + 0xB4)
-
-
#endif /* __RTL8712_FIFOCTRL_REGDEF_H__ */
diff --git a/drivers/staging/rtl8712/rtl8712_gp_bitdef.h b/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
index 44c906097530..66c35c990983 100644
--- a/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
@@ -70,7 +70,7 @@
#define GPIOSEL_PHYDBG 1 /* PHYDBG*/
#define GPIOSEL_BT 2 /* BT_coex*/
#define GPIOSEL_WLANDBG 3 /* WLANDBG*/
-#define GPIOSEL_GPIO_MASK (~(BIT(0)|BIT(1)))
+#define GPIOSEL_GPIO_MASK (~(BIT(0) | BIT(1)))
/* HW Radio OFF switch (GPIO BIT) */
#define HAL_8192S_HW_GPIO_OFF_BIT BIT(3)
#define HAL_8192S_HW_GPIO_OFF_MASK 0xF7
diff --git a/drivers/staging/rtl8712/rtl8712_gp_regdef.h b/drivers/staging/rtl8712/rtl8712_gp_regdef.h
index 8fc68f6a2c79..a0379360d0a3 100644
--- a/drivers/staging/rtl8712/rtl8712_gp_regdef.h
+++ b/drivers/staging/rtl8712/rtl8712_gp_regdef.h
@@ -37,6 +37,5 @@
#define PHY_REG_RPT (RTL8712_GP_ + 0x13)
#define PHY_REG_DATA (RTL8712_GP_ + 0x14)
-
#endif /*__RTL8712_GP_REGDEF_H__ */
diff --git a/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h b/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h
index 49598c314f09..2a561d2862e0 100644
--- a/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h
@@ -53,6 +53,5 @@
#define _VODOK BIT(1)
#define _RXOK BIT(0)
-
#endif /*__RTL8712_INTERRUPT_BITDEF_H__*/
diff --git a/drivers/staging/rtl8712/rtl8712_led.c b/drivers/staging/rtl8712/rtl8712_led.c
index 455fba721135..e9077347837e 100644
--- a/drivers/staging/rtl8712/rtl8712_led.c
+++ b/drivers/staging/rtl8712/rtl8712_led.c
@@ -181,11 +181,11 @@ static void SwLedOff(struct _adapter *padapter, struct LED_871x *pLed)
*/
void r8712_InitSwLeds(struct _adapter *padapter)
{
- struct led_priv *pledpriv = &(padapter->ledpriv);
+ struct led_priv *pledpriv = &padapter->ledpriv;
pledpriv->LedControlHandler = LedControl871x;
- InitLed871x(padapter, &(pledpriv->SwLed0), LED_PIN_LED0);
- InitLed871x(padapter, &(pledpriv->SwLed1), LED_PIN_LED1);
+ InitLed871x(padapter, &pledpriv->SwLed0, LED_PIN_LED0);
+ InitLed871x(padapter, &pledpriv->SwLed1, LED_PIN_LED1);
}
/* Description:
@@ -193,10 +193,10 @@ void r8712_InitSwLeds(struct _adapter *padapter)
*/
void r8712_DeInitSwLeds(struct _adapter *padapter)
{
- struct led_priv *ledpriv = &(padapter->ledpriv);
+ struct led_priv *ledpriv = &padapter->ledpriv;
- DeInitLed871x(&(ledpriv->SwLed0));
- DeInitLed871x(&(ledpriv->SwLed1));
+ DeInitLed871x(&ledpriv->SwLed0);
+ DeInitLed871x(&ledpriv->SwLed1);
}
/* Description:
@@ -206,7 +206,7 @@ void r8712_DeInitSwLeds(struct _adapter *padapter)
static void SwLedBlink(struct LED_871x *pLed)
{
struct _adapter *padapter = pLed->padapter;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
u8 bStopBlinking = false;
/* Change LED according to BlinkingLedState specified. */
@@ -281,14 +281,14 @@ static void SwLedBlink(struct LED_871x *pLed)
static void SwLedBlink1(struct LED_871x *pLed)
{
struct _adapter *padapter = pLed->padapter;
- struct led_priv *ledpriv = &(padapter->ledpriv);
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
- struct eeprom_priv *peeprompriv = &(padapter->eeprompriv);
- struct LED_871x *pLed1 = &(ledpriv->SwLed1);
+ struct led_priv *ledpriv = &padapter->ledpriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct eeprom_priv *peeprompriv = &padapter->eeprompriv;
+ struct LED_871x *pLed1 = &ledpriv->SwLed1;
u8 bStopBlinking = false;
if (peeprompriv->CustomerID == RT_CID_819x_CAMEO)
- pLed = &(ledpriv->SwLed1);
+ pLed = &ledpriv->SwLed1;
/* Change LED according to BlinkingLedState specified. */
if (pLed->BlinkingLedState == LED_STATE_ON)
SwLedOn(padapter, pLed);
@@ -499,7 +499,7 @@ static void SwLedBlink2(struct LED_871x *pLed)
static void SwLedBlink3(struct LED_871x *pLed)
{
struct _adapter *padapter = pLed->padapter;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
u8 bStopBlinking = false;
/* Change LED according to BlinkingLedState specified. */
@@ -593,8 +593,8 @@ static void SwLedBlink3(struct LED_871x *pLed)
static void SwLedBlink4(struct LED_871x *pLed)
{
struct _adapter *padapter = pLed->padapter;
- struct led_priv *ledpriv = &(padapter->ledpriv);
- struct LED_871x *pLed1 = &(ledpriv->SwLed1);
+ struct led_priv *ledpriv = &padapter->ledpriv;
+ struct LED_871x *pLed1 = &ledpriv->SwLed1;
u8 bStopBlinking = false;
/* Change LED according to BlinkingLedState specified. */
@@ -844,7 +844,7 @@ static void BlinkWorkItemCallback(struct work_struct *work)
{
struct LED_871x *pLed = container_of(work, struct LED_871x,
BlinkWorkItem);
- struct led_priv *ledpriv = &(pLed->padapter->ledpriv);
+ struct led_priv *ledpriv = &pLed->padapter->ledpriv;
switch (ledpriv->LedStrategy) {
case SW_LED_MODE0:
@@ -886,13 +886,13 @@ static void BlinkWorkItemCallback(struct work_struct *work)
static void SwLedControlMode1(struct _adapter *padapter,
enum LED_CTL_MODE LedAction)
{
- struct led_priv *ledpriv = &(padapter->ledpriv);
- struct LED_871x *pLed = &(ledpriv->SwLed0);
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
- struct sitesurvey_ctrl *psitesurveyctrl = &(pmlmepriv->sitesurveyctrl);
+ struct led_priv *ledpriv = &padapter->ledpriv;
+ struct LED_871x *pLed = &ledpriv->SwLed0;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct sitesurvey_ctrl *psitesurveyctrl = &pmlmepriv->sitesurveyctrl;
if (padapter->eeprompriv.CustomerID == RT_CID_819x_CAMEO)
- pLed = &(ledpriv->SwLed1);
+ pLed = &ledpriv->SwLed1;
switch (LedAction) {
case LED_CTL_START_TO_LINK:
case LED_CTL_NO_LINK:
@@ -1106,9 +1106,9 @@ static void SwLedControlMode1(struct _adapter *padapter,
static void SwLedControlMode2(struct _adapter *padapter,
enum LED_CTL_MODE LedAction)
{
- struct led_priv *ledpriv = &(padapter->ledpriv);
+ struct led_priv *ledpriv = &padapter->ledpriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- struct LED_871x *pLed = &(ledpriv->SwLed0);
+ struct LED_871x *pLed = &ledpriv->SwLed0;
switch (LedAction) {
case LED_CTL_SITE_SURVEY:
@@ -1239,9 +1239,9 @@ static void SwLedControlMode2(struct _adapter *padapter,
static void SwLedControlMode3(struct _adapter *padapter,
enum LED_CTL_MODE LedAction)
{
- struct led_priv *ledpriv = &(padapter->ledpriv);
+ struct led_priv *ledpriv = &padapter->ledpriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- struct LED_871x *pLed = &(ledpriv->SwLed0);
+ struct LED_871x *pLed = &ledpriv->SwLed0;
switch (LedAction) {
case LED_CTL_SITE_SURVEY:
@@ -1383,10 +1383,10 @@ static void SwLedControlMode3(struct _adapter *padapter,
static void SwLedControlMode4(struct _adapter *padapter,
enum LED_CTL_MODE LedAction)
{
- struct led_priv *ledpriv = &(padapter->ledpriv);
+ struct led_priv *ledpriv = &padapter->ledpriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- struct LED_871x *pLed = &(ledpriv->SwLed0);
- struct LED_871x *pLed1 = &(ledpriv->SwLed1);
+ struct LED_871x *pLed = &ledpriv->SwLed0;
+ struct LED_871x *pLed1 = &ledpriv->SwLed1;
switch (LedAction) {
case LED_CTL_START_TO_LINK:
@@ -1650,12 +1650,12 @@ static void SwLedControlMode4(struct _adapter *padapter,
static void SwLedControlMode5(struct _adapter *padapter,
enum LED_CTL_MODE LedAction)
{
- struct led_priv *ledpriv = &(padapter->ledpriv);
+ struct led_priv *ledpriv = &padapter->ledpriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- struct LED_871x *pLed = &(ledpriv->SwLed0);
+ struct LED_871x *pLed = &ledpriv->SwLed0;
if (padapter->eeprompriv.CustomerID == RT_CID_819x_CAMEO)
- pLed = &(ledpriv->SwLed1);
+ pLed = &ledpriv->SwLed1;
switch (LedAction) {
case LED_CTL_POWER_ON:
@@ -1723,9 +1723,9 @@ static void SwLedControlMode5(struct _adapter *padapter,
static void SwLedControlMode6(struct _adapter *padapter,
enum LED_CTL_MODE LedAction)
{
- struct led_priv *ledpriv = &(padapter->ledpriv);
+ struct led_priv *ledpriv = &padapter->ledpriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- struct LED_871x *pLed = &(ledpriv->SwLed0);
+ struct LED_871x *pLed = &ledpriv->SwLed0;
switch (LedAction) {
case LED_CTL_POWER_ON:
@@ -1737,7 +1737,7 @@ static void SwLedControlMode6(struct _adapter *padapter,
pLed->CurrLedState = LED_STATE_ON;
pLed->BlinkingLedState = LED_STATE_ON;
pLed->bLedBlinkInProgress = false;
- mod_timer(&(pLed->BlinkTimer), jiffies + msecs_to_jiffies(0));
+ mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(0));
break;
case LED_CTL_TX:
case LED_CTL_RX:
@@ -1807,7 +1807,7 @@ static void SwLedControlMode6(struct _adapter *padapter,
*/
void LedControl871x(struct _adapter *padapter, enum LED_CTL_MODE LedAction)
{
- struct led_priv *ledpriv = &(padapter->ledpriv);
+ struct led_priv *ledpriv = &padapter->ledpriv;
if (!ledpriv->bRegUseLed)
return;
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c
index 78245080e328..ac547ddd72d1 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.c
+++ b/drivers/staging/rtl8712/rtl871x_mlme.c
@@ -1725,7 +1725,8 @@ unsigned int r8712_restructure_ht_ie(struct _adapter *padapter, u8 *in_ie,
static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len)
{
u8 *p, max_ampdu_sz;
- int i, len;
+ int i;
+ uint len;
struct sta_info *bmc_sta, *psta;
struct ieee80211_ht_cap *pht_capie;
struct recv_reorder_ctrl *preorder_ctrl;
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c
index eda2aee02ff8..a8ae14ce6613 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.c
+++ b/drivers/staging/rtl8712/rtl871x_xmit.c
@@ -717,7 +717,7 @@ void r8712_update_protection(struct _adapter *padapter, u8 *ie, uint ie_len)
{
uint protection;
u8 *perp;
- sint erp_len;
+ uint erp_len;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct registry_priv *pregistrypriv = &padapter->registrypriv;
diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c
index af0a9e0a00df..9e132f943687 100644
--- a/drivers/staging/rtl8723bs/core/rtw_cmd.c
+++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c
@@ -1742,7 +1742,7 @@ exit:
return res;
}
-u32 g_wait_hiq_empty = 0;
+u32 g_wait_hiq_empty;
static void rtw_chk_hi_queue_hdl(struct adapter *padapter)
{
diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
index 9167900b5f7d..74750dbce379 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
@@ -1380,8 +1380,8 @@ int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8 *category, u8 *act
fc = le16_to_cpu(((struct ieee80211_hdr_3addr *)frame)->frame_control);
- if ((fc & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE))
- != (RTW_IEEE80211_FTYPE_MGMT|RTW_IEEE80211_STYPE_ACTION)
+ if ((fc & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE))
+ != (IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_ACTION)
) {
return false;
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c
index fe739eb2cf7d..c13e514a655a 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c
@@ -14,6 +14,7 @@
******************************************************************************/
#define _RTW_MLME_C_
+#include <linux/etherdevice.h>
#include <drv_types.h>
#include <rtw_debug.h>
#include <linux/jiffies.h>
@@ -2109,7 +2110,7 @@ int rtw_select_roaming_candidate(struct mlme_priv *mlme)
mlme->roam_network = candidate;
if (!memcmp(candidate->network.MacAddress, mlme->roam_tgt_addr, ETH_ALEN))
- memset(mlme->roam_tgt_addr, 0, ETH_ALEN);
+ eth_zero_addr(mlme->roam_tgt_addr);
}
ret = _SUCCESS;
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
index 7d7756e40bcb..589fab24bb25 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
@@ -1219,7 +1219,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
}
- if (pkt_len < IEEE80211_3ADDR_LEN + ie_offset) {
+ if (pkt_len < sizeof(struct ieee80211_hdr_3addr) + ie_offset) {
DBG_871X("handle_assoc(reassoc =%d) - too short payload (len =%lu)"
"\n", reassoc, (unsigned long)pkt_len);
return _FAIL;
@@ -1236,8 +1236,8 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
/* listen_interval = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN+2)); */
listen_interval = RTW_GET_LE16(pframe + WLAN_HDR_A3_LEN+2);
- left = pkt_len - (IEEE80211_3ADDR_LEN + ie_offset);
- pos = pframe + (IEEE80211_3ADDR_LEN + ie_offset);
+ left = pkt_len - (sizeof(struct ieee80211_hdr_3addr) + ie_offset);
+ pos = pframe + (sizeof(struct ieee80211_hdr_3addr) + ie_offset);
DBG_871X("%s\n", __func__);
@@ -4263,7 +4263,7 @@ unsigned int send_beacon(struct adapter *padapter)
issue_beacon(padapter, 100);
issue++;
do {
- yield();
+ cond_resched();
rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok));
poll++;
} while ((poll%10) != 0 && false == bxmitok && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
index 4a6af72013fa..85f7769ecc2d 100644
--- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
+++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
@@ -701,7 +701,7 @@ void LPS_Leave_check(
bReady = false;
start_time = jiffies;
- yield();
+ cond_resched();
while (1) {
down(&pwrpriv->lock);
diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c
index 9c7c3be0553a..86f995b8a88b 100644
--- a/drivers/staging/rtl8723bs/core/rtw_recv.c
+++ b/drivers/staging/rtl8723bs/core/rtw_recv.c
@@ -1785,7 +1785,7 @@ static union recv_frame *recvframe_defrag(struct adapter *adapter,
pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len;
plist = get_next(plist);
- };
+ }
/* free the defrag_q queue and return the prframe */
rtw_free_recvframe_queue(defrag_q, pfree_recv_queue);
diff --git a/drivers/staging/rtl8723bs/hal/hal_com.c b/drivers/staging/rtl8723bs/hal/hal_com.c
index dec887a5b338..1cef1d77977c 100644
--- a/drivers/staging/rtl8723bs/hal/hal_com.c
+++ b/drivers/staging/rtl8723bs/hal/hal_com.c
@@ -1680,18 +1680,18 @@ void rtw_store_phy_info(struct adapter *padapter, union recv_frame *prframe)
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
- PODM_PHY_INFO_T pPhyInfo = (PODM_PHY_INFO_T)(&pattrib->phy_info);
+ struct odm_phy_info *pPhyInfo = (PODM_PHY_INFO_T)(&pattrib->phy_info);
struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info;
psample_pkt_rssi->data_rate = pattrib->data_rate;
isCCKrate = pattrib->data_rate <= DESC_RATE11M;
- psample_pkt_rssi->pwdball = pPhyInfo->RxPWDBAll;
- psample_pkt_rssi->pwr_all = pPhyInfo->RecvSignalPower;
+ psample_pkt_rssi->pwdball = pPhyInfo->rx_pwd_ba11;
+ psample_pkt_rssi->pwr_all = pPhyInfo->recv_signal_power;
for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) {
- psample_pkt_rssi->mimo_singal_strength[rf_path] = pPhyInfo->RxMIMOSignalStrength[rf_path];
- psample_pkt_rssi->mimo_singal_quality[rf_path] = pPhyInfo->RxMIMOSignalQuality[rf_path];
+ psample_pkt_rssi->mimo_singal_strength[rf_path] = pPhyInfo->rx_mimo_signal_strength[rf_path];
+ psample_pkt_rssi->mimo_singal_quality[rf_path] = pPhyInfo->rx_mimo_signal_quality[rf_path];
if (!isCCKrate) {
psample_pkt_rssi->ofdm_pwr[rf_path] = pPhyInfo->RxPwr[rf_path];
psample_pkt_rssi->ofdm_snr[rf_path] = pPhyInfo->RxSNR[rf_path];
diff --git a/drivers/staging/rtl8723bs/hal/odm.h b/drivers/staging/rtl8723bs/hal/odm.h
index 87a76bafecb3..1037b88e8f08 100644
--- a/drivers/staging/rtl8723bs/hal/odm.h
+++ b/drivers/staging/rtl8723bs/hal/odm.h
@@ -17,7 +17,6 @@
#ifndef __HALDMOUTSRC_H__
#define __HALDMOUTSRC_H__
-
#include "odm_EdcaTurboCheck.h"
#include "odm_DIG.h"
#include "odm_PathDiv.h"
@@ -32,7 +31,6 @@
#define TRAFFIC_HIGH 1
#define NONE 0
-
/* 3 Tx Power Tracking */
/* 3 ============================================================ */
#define DPK_DELTA_MAPPING_NUM 13
@@ -81,7 +79,6 @@
#define AUX_ANT 2 /* AntB or Ant Aux */
#define MAX_ANT 3 /* 3 for AP using */
-
/* Antenna Diversity Type */
#define SW_ANTDIV 0
#define HW_ANTDIV 1
@@ -200,7 +197,6 @@ typedef struct _ODM_RATE_ADAPTIVE {
} ODM_RATE_ADAPTIVE, *PODM_RATE_ADAPTIVE;
-
#define IQK_MAC_REG_NUM 4
#define IQK_ADDA_REG_NUM 16
#define IQK_BB_REG_NUM_MAX 10
@@ -229,49 +225,49 @@ typedef struct _ODM_RATE_ADAPTIVE {
#define MAX_PATH_NUM_8814A 4
#define MAX_PATH_NUM_8822B 2
-
#define IQK_THRESHOLD 8
#define DPK_THRESHOLD 4
-typedef struct _ODM_Phy_Status_Info_ {
- /* */
- /* Be care, if you want to add any element please insert between */
- /* RxPWDBAll & SignalStrength. */
- /* */
- u8 RxPWDBAll;
-
- u8 SignalQuality; /* in 0-100 index. */
- s8 RxMIMOSignalQuality[4]; /* per-path's EVM */
- u8 RxMIMOEVMdbm[4]; /* per-path's EVM dbm */
+struct odm_phy_info {
+ /*
+ * Be care, if you want to add any element, please insert it between
+ * rx_pwd_ball and signal_strength.
+ */
+ u8 rx_pwd_ba11;
- u8 RxMIMOSignalStrength[4];/* in 0~100 index */
+ u8 signal_quality; /* in 0-100 index. */
+ s8 rx_mimo_signal_quality[4]; /* per-path's EVM */
+ u8 rx_mimo_evm_dbm[4]; /* per-path's EVM dbm */
- u16 Cfo_short[4]; /* per-path's Cfo_short */
- u16 Cfo_tail[4]; /* per-path's Cfo_tail */
+ u8 rx_mimo_signal_strength[4]; /* in 0~100 index */
- s8 RxPower; /* in dBm Translate from PWdB */
- s8 RecvSignalPower; /* Real power in dBm for this packet, no beautification and aggregation. Keep this raw info to be used for the other procedures. */
- u8 BTRxRSSIPercentage;
- u8 SignalStrength; /* in 0-100 index. */
+ u16 cfo_short[4]; /* per-path's Cfo_short */
+ u16 cfo_tail[4]; /* per-path's Cfo_tail */
- s8 RxPwr[4]; /* per-path's pwdb */
+ s8 rx_power; /* in dBm Translate from PWdB */
- u8 RxSNR[4]; /* per-path's SNR */
- u8 BandWidth;
- u8 btCoexPwrAdjust;
-} ODM_PHY_INFO_T, *PODM_PHY_INFO_T;
+ /*
+ * Real power in dBm for this packet, no beautification and
+ * aggregation. Keep this raw info to be used for the other procedures.
+ */
+ s8 recv_signal_power;
+ u8 bt_rx_rssi_percentage;
+ u8 signal_strength; /* in 0-100 index. */
+ s8 rx_pwr[4]; /* per-path's pwdb */
-typedef struct _ODM_Per_Pkt_Info_ {
- /* u8 Rate; */
- u8 DataRate;
- u8 StationID;
- bool bPacketMatchBSSID;
- bool bPacketToSelf;
- bool bPacketBeacon;
- bool bToSelf;
-} ODM_PACKET_INFO_T, *PODM_PACKET_INFO_T;
+ u8 rx_snr[4]; /* per-path's SNR */
+ u8 band_width;
+ u8 bt_coex_pwr_adjust;
+};
+struct odm_packet_info {
+ u8 data_rate;
+ u8 station_id;
+ bool bssid_match;
+ bool to_self;
+ bool is_beacon;
+};
typedef struct _ODM_Phy_Dbg_Info_ {
/* ODM Write, debug info */
@@ -285,12 +281,10 @@ typedef struct _ODM_Phy_Dbg_Info_ {
} ODM_PHY_DBG_INFO_T;
-
typedef struct _ODM_Mac_Status_Info_ {
u8 test;
} ODM_MAC_INFO;
-
typedef enum tag_Dynamic_ODM_Support_Ability_Type {
/* BB Team */
ODM_DIG = 0x00000001,
@@ -369,7 +363,6 @@ typedef enum _ODM_Common_Info_Definition {
ODM_CMNINFO_SMART_CONCURRENT,
/* HOOK BEFORE REG INIT----------- */
-
/* Dynamic value: */
/* POINTER REFERENCE----------- */
ODM_CMNINFO_MAC_PHY_MODE, /* ODM_MAC_PHY_MODE_E */
@@ -427,8 +420,6 @@ typedef enum _ODM_Common_Info_Definition {
ODM_CMNINFO_MAC_STATUS,
ODM_CMNINFO_MAX,
-
-
} ODM_CMNINFO_E;
/* 2011/10/20 MH Define ODM support ability. ODM_CMNINFO_ABILITY */
@@ -509,7 +500,6 @@ typedef enum tag_ODM_RF_Path_Bit_Definition {
ODM_RF_RX_D = BIT7,
} ODM_RF_PATH_E;
-
typedef enum tag_ODM_RF_Type_Definition {
ODM_1T1R = 0,
ODM_1T2R = 1,
@@ -521,7 +511,6 @@ typedef enum tag_ODM_RF_Type_Definition {
ODM_4T4R = 7,
} ODM_RF_TYPE_E;
-
/* */
/* ODM Dynamic common info value definition */
/* */
@@ -538,7 +527,6 @@ typedef enum tag_ODM_MAC_PHY_Mode_Definition {
ODM_DMDP = 2,
} ODM_MAC_PHY_MODE_E;
-
typedef enum tag_BT_Coexist_Definition {
ODM_BT_BUSY = 1,
ODM_BT_ON = 2,
@@ -607,7 +595,6 @@ typedef enum tag_Bandwidth_Definition {
ODM_BW10M = 4,
} ODM_BW_E;
-
/* ODM_CMNINFO_BOARD_TYPE */
/* For non-AC-series IC , ODM_BOARD_5G_EXT_PA and ODM_BOARD_5G_EXT_LNA are ignored */
/* For AC-series IC, external PA & LNA can be indivisuallly added on 2.4G and/or 5G */
@@ -661,7 +648,6 @@ typedef enum tag_CCA_Path {
ODM_CCA_1R_B = 2,
} ODM_CCA_PATH_E;
-
typedef struct _ODM_RA_Info_ {
u8 RateID;
u32 RateMask;
@@ -700,7 +686,6 @@ typedef struct _IQK_MATRIX_REGS_SETTING {
bool bBWIqkResultSaved[3];
} IQK_MATRIX_REGS_SETTING, *PIQK_MATRIX_REGS_SETTING;
-
/* Remove PATHDIV_PARA struct to odm_PathDiv.h */
typedef struct ODM_RF_Calibration_Structure {
@@ -736,7 +721,6 @@ typedef struct ODM_RF_Calibration_Structure {
u8 bRfPiEnable;
u32 TXPowerTrackingCallbackCnt; /* cosa add for debug */
-
/* Tx power Tracking ------------------------- */
u8 bCCKinCH14;
u8 CCK_index;
@@ -791,7 +775,6 @@ typedef struct ODM_RF_Calibration_Structure {
u32 TxIQC_8723B[2][3][2]; /* { {S1: 0xc94, 0xc80, 0xc4c} , {S0: 0xc9c, 0xc88, 0xc4c}} */
u32 RxIQC_8723B[2][2][2]; /* { {S1: 0xc14, 0xca0} , {S0: 0xc14, 0xca0}} */
-
/* for APK */
u32 APKoutput[2][2]; /* path A/B; output1_1a/output1_2a */
u8 bAPKdone;
@@ -839,7 +822,6 @@ typedef struct _FAST_ANTENNA_TRAINNING_ {
u32 OFDM_counter_main;
u32 OFDM_counter_aux;
-
u32 CCK_CtrlFrame_Cnt_main;
u32 CCK_CtrlFrame_Cnt_aux;
u32 OFDM_CtrlFrame_Cnt_main;
@@ -875,13 +857,11 @@ typedef struct _ODM_PATH_DIVERSITY_ {
u32 PathB_Cnt[ODM_ASSOCIATE_ENTRY_NUM];
} PATHDIV_T, *pPATHDIV_T;
-
typedef enum _BASEBAND_CONFIG_PHY_REG_PG_VALUE_TYPE{
PHY_REG_PG_RELATIVE_VALUE = 0,
PHY_REG_PG_EXACT_VALUE = 1
} PHY_REG_PG_TYPE;
-
/* */
/* Antenna detection information from single tone mechanism, added by Roger, 2012.11.27. */
/* */
@@ -933,7 +913,6 @@ typedef struct DM_Out_Source_Dynamic_Mechanism_Structure {
/* bool bSlaveOfDMSP; */
/* REMOVED COMMON INFO---------- */
-
/* 1 COMMON INFORMATION */
/* */
@@ -1105,7 +1084,6 @@ typedef struct DM_Out_Source_Dynamic_Mechanism_Structure {
u8 Adaptivity_IGI_upper;
u8 NHM_cnt_0;
-
ODM_NOISE_MONITOR noise_level;/* ODM_MAX_CHANNEL_NUM]; */
/* */
/* 2 Define STA info. */
@@ -1367,7 +1345,6 @@ typedef enum tag_SW_Antenna_Switch_Definition {
Antenna_MAX = 3,
} DM_SWAS_E;
-
/* Maximal number of antenna detection mechanism needs to perform, added by Roger, 2011.12.28. */
#define MAX_ANTENNA_DETECTION_CNT 10
@@ -1400,7 +1377,6 @@ extern u32 TxScalingTable_Jaguar[TXSCALE_TABLE_SIZE];
void ODM_SetAntenna(PDM_ODM_T pDM_Odm, u8 Antenna);
-
/* Remove BB power saving by Yuchen */
#define dm_CheckTXPowerTracking ODM_TXPowerTrackingCheck
@@ -1417,7 +1393,7 @@ bool ODM_RAStateCheck(
void ODM_SwAntDivChkPerPktRssi(
PDM_ODM_T pDM_Odm,
u8 StationID,
- PODM_PHY_INFO_T pPhyInfo
+ struct odm_phy_info *pPhyInfo
);
u32 ODM_Get_Rate_Bitmap(
diff --git a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c
index 71853e6f7106..178aaab3f76c 100644
--- a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c
+++ b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c
@@ -316,14 +316,14 @@ void ODM_CfoTracking(void *pDM_VOID)
void ODM_ParsingCFO(void *pDM_VOID, void *pPktinfo_VOID, s8 *pcfotail)
{
PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
- PODM_PACKET_INFO_T pPktinfo = (PODM_PACKET_INFO_T)pPktinfo_VOID;
+ struct odm_packet_info *pPktinfo = (struct odm_packet_info *)pPktinfo_VOID;
PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack;
u8 i;
if (!(pDM_Odm->SupportAbility & ODM_BB_CFO_TRACKING))
return;
- if (pPktinfo->StationID != 0) {
+ if (pPktinfo->station_id != 0) {
/* 3 Update CFO report for path-A & path-B */
/* Only paht-A and path-B have CFO tail and short CFO */
for (i = ODM_RF_PATH_A; i <= ODM_RF_PATH_B; i++)
diff --git a/drivers/staging/rtl8723bs/hal/odm_HWConfig.c b/drivers/staging/rtl8723bs/hal/odm_HWConfig.c
index 8dd6da8a4e26..9e161f080c57 100644
--- a/drivers/staging/rtl8723bs/hal/odm_HWConfig.c
+++ b/drivers/staging/rtl8723bs/hal/odm_HWConfig.c
@@ -91,9 +91,9 @@ static u8 odm_EVMdbToPercentage(s8 Value)
static void odm_RxPhyStatus92CSeries_Parsing(
PDM_ODM_T pDM_Odm,
- PODM_PHY_INFO_T pPhyInfo,
+ struct odm_phy_info *pPhyInfo,
u8 *pPhyStatus,
- PODM_PACKET_INFO_T pPktinfo
+ struct odm_packet_info *pPktinfo
)
{
u8 i, Max_spatial_stream;
@@ -106,9 +106,9 @@ static void odm_RxPhyStatus92CSeries_Parsing(
u8 LNA_idx, VGA_idx;
PPHY_STATUS_RPT_8192CD_T pPhyStaRpt = (PPHY_STATUS_RPT_8192CD_T)pPhyStatus;
- isCCKrate = pPktinfo->DataRate <= DESC_RATE11M;
- pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = -1;
- pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1;
+ isCCKrate = pPktinfo->data_rate <= DESC_RATE11M;
+ pPhyInfo->rx_mimo_signal_quality[ODM_RF_PATH_A] = -1;
+ pPhyInfo->rx_mimo_signal_quality[ODM_RF_PATH_B] = -1;
if (isCCKrate) {
@@ -137,9 +137,9 @@ static void odm_RxPhyStatus92CSeries_Parsing(
if (PWDB_ALL > 100)
PWDB_ALL = 100;
- pPhyInfo->RxPWDBAll = PWDB_ALL;
- pPhyInfo->BTRxRSSIPercentage = PWDB_ALL;
- pPhyInfo->RecvSignalPower = rx_pwr_all;
+ pPhyInfo->rx_pwd_ba11 = PWDB_ALL;
+ pPhyInfo->bt_rx_rssi_percentage = PWDB_ALL;
+ pPhyInfo->recv_signal_power = rx_pwr_all;
/* */
/* (3) Get Signal Quality (EVM) */
/* */
@@ -147,7 +147,7 @@ static void odm_RxPhyStatus92CSeries_Parsing(
{
u8 SQ, SQ_rpt;
- if (pPhyInfo->RxPWDBAll > 40 && !pDM_Odm->bInHctTest)
+ if (pPhyInfo->rx_pwd_ba11 > 40 && !pDM_Odm->bInHctTest)
SQ = 100;
else {
SQ_rpt = pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all;
@@ -162,9 +162,9 @@ static void odm_RxPhyStatus92CSeries_Parsing(
}
/* DbgPrint("cck SQ = %d\n", SQ); */
- pPhyInfo->SignalQuality = SQ;
- pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = SQ;
- pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1;
+ pPhyInfo->signal_quality = SQ;
+ pPhyInfo->rx_mimo_signal_quality[ODM_RF_PATH_A] = SQ;
+ pPhyInfo->rx_mimo_signal_quality[ODM_RF_PATH_B] = -1;
}
} else { /* is OFDM rate */
pDM_Odm->PhyDbgInfo.NumQryPhyStatusOFDM++;
@@ -183,17 +183,17 @@ static void odm_RxPhyStatus92CSeries_Parsing(
rx_pwr[i] = ((pPhyStaRpt->path_agc[i].gain&0x3F)*2) - 110;
- pPhyInfo->RxPwr[i] = rx_pwr[i];
+ pPhyInfo->rx_pwr[i] = rx_pwr[i];
/* Translate DBM to percentage. */
RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]);
total_rssi += RSSI;
/* RT_DISP(FRX, RX_PHY_SS, ("RF-%d RXPWR =%x RSSI =%d\n", i, rx_pwr[i], RSSI)); */
- pPhyInfo->RxMIMOSignalStrength[i] = (u8) RSSI;
+ pPhyInfo->rx_mimo_signal_strength[i] = (u8) RSSI;
/* Get Rx snr value in DB */
- pPhyInfo->RxSNR[i] = pDM_Odm->PhyDbgInfo.RxSNRdB[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2);
+ pPhyInfo->rx_snr[i] = pDM_Odm->PhyDbgInfo.RxSNRdB[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2);
}
@@ -205,17 +205,17 @@ static void odm_RxPhyStatus92CSeries_Parsing(
PWDB_ALL_BT = PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all);
/* RT_DISP(FRX, RX_PHY_SS, ("PWDB_ALL =%d\n", PWDB_ALL)); */
- pPhyInfo->RxPWDBAll = PWDB_ALL;
- /* ODM_RT_TRACE(pDM_Odm, ODM_COMP_RSSI_MONITOR, ODM_DBG_LOUD, ("ODM OFDM RSSI =%d\n", pPhyInfo->RxPWDBAll)); */
- pPhyInfo->BTRxRSSIPercentage = PWDB_ALL_BT;
- pPhyInfo->RxPower = rx_pwr_all;
- pPhyInfo->RecvSignalPower = rx_pwr_all;
+ pPhyInfo->rx_pwd_ba11 = PWDB_ALL;
+ /* ODM_RT_TRACE(pDM_Odm, ODM_COMP_RSSI_MONITOR, ODM_DBG_LOUD, ("ODM OFDM RSSI =%d\n", pPhyInfo->rx_pwd_ba11)); */
+ pPhyInfo->bt_rx_rssi_percentage = PWDB_ALL_BT;
+ pPhyInfo->rx_power = rx_pwr_all;
+ pPhyInfo->recv_signal_power = rx_pwr_all;
{/* pMgntInfo->CustomerID != RT_CID_819x_Lenovo */
/* */
/* (3)EVM of HT rate */
/* */
- if (pPktinfo->DataRate >= DESC_RATEMCS8 && pPktinfo->DataRate <= DESC_RATEMCS15)
+ if (pPktinfo->data_rate >= DESC_RATEMCS8 && pPktinfo->data_rate <= DESC_RATEMCS15)
Max_spatial_stream = 2; /* both spatial stream make sense */
else
Max_spatial_stream = 1; /* only spatial stream 1 makes sense */
@@ -232,9 +232,9 @@ static void odm_RxPhyStatus92CSeries_Parsing(
/* if (pPktinfo->bPacketMatchBSSID) */
{
if (i == ODM_RF_PATH_A) /* Fill value in RFD, Get the first spatial stream only */
- pPhyInfo->SignalQuality = (u8)(EVM & 0xff);
+ pPhyInfo->signal_quality = (u8)(EVM & 0xff);
- pPhyInfo->RxMIMOSignalQuality[i] = (u8)(EVM & 0xff);
+ pPhyInfo->rx_mimo_signal_quality[i] = (u8)(EVM & 0xff);
}
}
}
@@ -249,25 +249,25 @@ static void odm_RxPhyStatus92CSeries_Parsing(
#ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING
pPhyInfo->SignalStrength = (u8)PWDB_ALL;
#else
- pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(pDM_Odm, PWDB_ALL));/* PWDB_ALL; */
+ pPhyInfo->signal_strength = (u8)(odm_SignalScaleMapping(pDM_Odm, PWDB_ALL));/* PWDB_ALL; */
#endif
} else {
if (rf_rx_num != 0) {
#ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING
total_rssi /= rf_rx_num;
- pPhyInfo->SignalStrength = (u8)total_rssi;
+ pPhyInfo->signal_strength = (u8)total_rssi;
#else
- pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(pDM_Odm, total_rssi /= rf_rx_num));
+ pPhyInfo->signal_strength = (u8)(odm_SignalScaleMapping(pDM_Odm, total_rssi /= rf_rx_num));
#endif
}
}
- /* DbgPrint("isCCKrate = %d, pPhyInfo->RxPWDBAll = %d, pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a = 0x%x\n", */
- /* isCCKrate, pPhyInfo->RxPWDBAll, pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a); */
+ /* DbgPrint("isCCKrate = %d, pPhyInfo->rx_pwd_ba11 = %d, pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a = 0x%x\n", */
+ /* isCCKrate, pPhyInfo->rx_pwd_ba11, pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a); */
}
static void odm_Process_RSSIForDM(
- PDM_ODM_T pDM_Odm, PODM_PHY_INFO_T pPhyInfo, PODM_PACKET_INFO_T pPktinfo
+ PDM_ODM_T pDM_Odm, struct odm_phy_info *pPhyInfo, struct odm_packet_info *pPktinfo
)
{
@@ -279,22 +279,22 @@ static void odm_Process_RSSIForDM(
PSTA_INFO_T pEntry;
- if (pPktinfo->StationID == 0xFF)
+ if (pPktinfo->station_id == 0xFF)
return;
- pEntry = pDM_Odm->pODM_StaInfo[pPktinfo->StationID];
+ pEntry = pDM_Odm->pODM_StaInfo[pPktinfo->station_id];
if (!IS_STA_VALID(pEntry))
return;
- if ((!pPktinfo->bPacketMatchBSSID))
+ if ((!pPktinfo->bssid_match))
return;
- if (pPktinfo->bPacketBeacon)
+ if (pPktinfo->is_beacon)
pDM_Odm->PhyDbgInfo.NumQryBeaconPkt++;
- isCCKrate = ((pPktinfo->DataRate <= DESC_RATE11M)) ? true : false;
- pDM_Odm->RxRate = pPktinfo->DataRate;
+ isCCKrate = ((pPktinfo->data_rate <= DESC_RATE11M)) ? true : false;
+ pDM_Odm->RxRate = pPktinfo->data_rate;
/* Statistic for antenna/path diversity------------------ */
if (pDM_Odm->SupportAbility & ODM_BB_ANT_DIV) {
@@ -307,28 +307,28 @@ static void odm_Process_RSSIForDM(
UndecoratedSmoothedOFDM = pEntry->rssi_stat.UndecoratedSmoothedOFDM;
UndecoratedSmoothedPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB;
- if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) {
+ if (pPktinfo->to_self || pPktinfo->is_beacon) {
if (!isCCKrate) { /* ofdm rate */
- if (pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B] == 0) {
- RSSI_Ave = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A];
- pDM_Odm->RSSI_A = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A];
+ if (pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_B] == 0) {
+ RSSI_Ave = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_A];
+ pDM_Odm->RSSI_A = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_A];
pDM_Odm->RSSI_B = 0;
} else {
- /* DbgPrint("pRfd->Status.RxMIMOSignalStrength[0] = %d, pRfd->Status.RxMIMOSignalStrength[1] = %d\n", */
- /* pRfd->Status.RxMIMOSignalStrength[0], pRfd->Status.RxMIMOSignalStrength[1]); */
- pDM_Odm->RSSI_A = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A];
- pDM_Odm->RSSI_B = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B];
+ /* DbgPrint("pRfd->Status.rx_mimo_signal_strength[0] = %d, pRfd->Status.rx_mimo_signal_strength[1] = %d\n", */
+ /* pRfd->Status.rx_mimo_signal_strength[0], pRfd->Status.rx_mimo_signal_strength[1]); */
+ pDM_Odm->RSSI_A = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_A];
+ pDM_Odm->RSSI_B = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_B];
if (
- pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A] >
- pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]
+ pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_A] >
+ pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_B]
) {
- RSSI_max = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A];
- RSSI_min = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B];
+ RSSI_max = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_A];
+ RSSI_min = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_B];
} else {
- RSSI_max = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B];
- RSSI_min = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A];
+ RSSI_max = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_B];
+ RSSI_min = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_A];
}
if ((RSSI_max-RSSI_min) < 3)
@@ -343,9 +343,9 @@ static void odm_Process_RSSIForDM(
/* 1 Process OFDM RSSI */
if (UndecoratedSmoothedOFDM <= 0) /* initialize */
- UndecoratedSmoothedOFDM = pPhyInfo->RxPWDBAll;
+ UndecoratedSmoothedOFDM = pPhyInfo->rx_pwd_ba11;
else {
- if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedOFDM) {
+ if (pPhyInfo->rx_pwd_ba11 > (u32)UndecoratedSmoothedOFDM) {
UndecoratedSmoothedOFDM =
((UndecoratedSmoothedOFDM*(Rx_Smooth_Factor-1)) +
RSSI_Ave)/Rx_Smooth_Factor;
@@ -360,23 +360,23 @@ static void odm_Process_RSSIForDM(
pEntry->rssi_stat.PacketMap = (pEntry->rssi_stat.PacketMap<<1) | BIT0;
} else {
- RSSI_Ave = pPhyInfo->RxPWDBAll;
- pDM_Odm->RSSI_A = (u8) pPhyInfo->RxPWDBAll;
+ RSSI_Ave = pPhyInfo->rx_pwd_ba11;
+ pDM_Odm->RSSI_A = (u8) pPhyInfo->rx_pwd_ba11;
pDM_Odm->RSSI_B = 0;
/* 1 Process CCK RSSI */
if (UndecoratedSmoothedCCK <= 0) /* initialize */
- UndecoratedSmoothedCCK = pPhyInfo->RxPWDBAll;
+ UndecoratedSmoothedCCK = pPhyInfo->rx_pwd_ba11;
else {
- if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedCCK) {
+ if (pPhyInfo->rx_pwd_ba11 > (u32)UndecoratedSmoothedCCK) {
UndecoratedSmoothedCCK =
((UndecoratedSmoothedCCK*(Rx_Smooth_Factor-1)) +
- pPhyInfo->RxPWDBAll)/Rx_Smooth_Factor;
+ pPhyInfo->rx_pwd_ba11)/Rx_Smooth_Factor;
UndecoratedSmoothedCCK = UndecoratedSmoothedCCK + 1;
} else {
UndecoratedSmoothedCCK =
((UndecoratedSmoothedCCK*(Rx_Smooth_Factor-1)) +
- pPhyInfo->RxPWDBAll)/Rx_Smooth_Factor;
+ pPhyInfo->rx_pwd_ba11)/Rx_Smooth_Factor;
}
}
pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap<<1;
@@ -422,9 +422,9 @@ static void odm_Process_RSSIForDM(
/* */
static void ODM_PhyStatusQuery_92CSeries(
PDM_ODM_T pDM_Odm,
- PODM_PHY_INFO_T pPhyInfo,
+ struct odm_phy_info *pPhyInfo,
u8 *pPhyStatus,
- PODM_PACKET_INFO_T pPktinfo
+ struct odm_packet_info *pPktinfo
)
{
@@ -436,9 +436,9 @@ static void ODM_PhyStatusQuery_92CSeries(
void ODM_PhyStatusQuery(
PDM_ODM_T pDM_Odm,
- PODM_PHY_INFO_T pPhyInfo,
+ struct odm_phy_info *pPhyInfo,
u8 *pPhyStatus,
- PODM_PACKET_INFO_T pPktinfo
+ struct odm_packet_info *pPktinfo
)
{
diff --git a/drivers/staging/rtl8723bs/hal/odm_HWConfig.h b/drivers/staging/rtl8723bs/hal/odm_HWConfig.h
index f029922d12f0..fdb4f8579ff9 100644
--- a/drivers/staging/rtl8723bs/hal/odm_HWConfig.h
+++ b/drivers/staging/rtl8723bs/hal/odm_HWConfig.h
@@ -131,9 +131,9 @@ typedef struct _Phy_Status_Rpt_8812 {
void ODM_PhyStatusQuery(
PDM_ODM_T pDM_Odm,
- PODM_PHY_INFO_T pPhyInfo,
+ struct odm_phy_info *pPhyInfo,
u8 *pPhyStatus,
- PODM_PACKET_INFO_T pPktinfo
+ struct odm_packet_info *pPktinfo
);
HAL_STATUS ODM_ConfigRFWithTxPwrTrackHeaderFile(PDM_ODM_T pDM_Odm);
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
index d6cef9e8378d..0ce9b47d644d 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
@@ -433,13 +433,12 @@ s32 rtl8723b_FirmwareDownload(struct adapter *padapter, bool bUsedWoWLANFw)
goto exit;
}
- pFirmware->szFwBuffer = kzalloc(fw->size, GFP_KERNEL);
+ pFirmware->szFwBuffer = kmemdup(fw->data, fw->size, GFP_KERNEL);
if (!pFirmware->szFwBuffer) {
rtStatus = _FAIL;
goto exit;
}
- memcpy(pFirmware->szFwBuffer, fw->data, fw->size);
pFirmware->ulFwLength = fw->size;
release_firmware(fw);
if (pFirmware->ulFwLength > FW_8723B_SIZE) {
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c b/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c
index a71b552eca9a..f6aeb2630398 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c
@@ -163,7 +163,7 @@ static int phy_RF6052_Config_ParaFile(struct adapter *Adapter)
break;
}
- /*----Restore RFENV control type----*/;
+ /*----Restore RFENV control type----*/
switch (eRFPath) {
case RF_PATH_A:
case RF_PATH_C:
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c
index d9a4567ca721..5d5cd4d01156 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c
@@ -18,7 +18,6 @@
#include <rtw_debug.h>
#include <rtl8723b_hal.h>
-
static s32 initrecvbuf(struct recv_buf *precvbuf, struct adapter *padapter)
{
INIT_LIST_HEAD(&precvbuf->list);
@@ -29,9 +28,9 @@ static s32 initrecvbuf(struct recv_buf *precvbuf, struct adapter *padapter)
return _SUCCESS;
}
-static void update_recvframe_attrib(
- struct adapter *padapter, union recv_frame *precvframe, struct recv_stat *prxstat
-)
+static void update_recvframe_attrib(struct adapter *padapter,
+ union recv_frame *precvframe,
+ struct recv_stat *prxstat)
{
struct rx_pkt_attrib *pattrib;
struct recv_stat report;
@@ -48,7 +47,7 @@ static void update_recvframe_attrib(
memset(pattrib, 0, sizeof(struct rx_pkt_attrib));
/* update rx report to recv_frame attribute */
- pattrib->pkt_rpt_type = prxreport->c2h_ind?C2H_PACKET:NORMAL_RX;
+ pattrib->pkt_rpt_type = prxreport->c2h_ind ? C2H_PACKET : NORMAL_RX;
/* DBG_871X("%s: pkt_rpt_type =%d\n", __func__, pattrib->pkt_rpt_type); */
if (pattrib->pkt_rpt_type == NORMAL_RX) {
@@ -75,8 +74,9 @@ static void update_recvframe_attrib(
pattrib->mdata = (u8)prxreport->md;
pattrib->data_rate = (u8)prxreport->rx_rate;
- } else
+ } else {
pattrib->pkt_len = (u16)prxreport->pktlen;
+ }
}
/*
@@ -84,75 +84,92 @@ static void update_recvframe_attrib(
*Before calling this function,
*precvframe->u.hdr.rx_data should be ready!
*/
-static void update_recvframe_phyinfo(
- union recv_frame *precvframe, struct phy_stat *pphy_status
-)
+static void update_recvframe_phyinfo(union recv_frame *precvframe,
+ struct phy_stat *pphy_status)
{
struct adapter *padapter = precvframe->u.hdr.adapter;
struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
- struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
- PODM_PHY_INFO_T pPHYInfo = (PODM_PHY_INFO_T)(&pattrib->phy_info);
+ struct hal_com_data *p_hal_data = GET_HAL_DATA(padapter);
+ struct odm_phy_info *p_phy_info =
+ (struct odm_phy_info *)(&pattrib->phy_info);
u8 *wlanhdr;
- ODM_PACKET_INFO_T pkt_info;
+ u8 *my_bssid;
+ u8 *rx_bssid;
+ u8 *rx_ra;
+ u8 *my_hwaddr;
u8 *sa = NULL;
+
+ struct odm_packet_info pkt_info = {
+ .data_rate = 0x00,
+ .station_id = 0x00,
+ .bssid_match = false,
+ .to_self = false,
+ .is_beacon = false,
+ };
+
/* _irqL irqL; */
struct sta_priv *pstapriv;
struct sta_info *psta;
- pkt_info.bPacketMatchBSSID = false;
- pkt_info.bPacketToSelf = false;
- pkt_info.bPacketBeacon = false;
-
-
wlanhdr = get_recvframe_data(precvframe);
+ my_bssid = get_bssid(&padapter->mlmepriv);
+ rx_bssid = get_hdr_bssid(wlanhdr);
+ pkt_info.bssid_match = ((!IsFrameTypeCtrl(wlanhdr)) &&
+ !pattrib->icv_err && !pattrib->crc_err &&
+ !ether_addr_equal(rx_bssid, my_bssid));
- pkt_info.bPacketMatchBSSID = ((!IsFrameTypeCtrl(wlanhdr)) &&
- !pattrib->icv_err && !pattrib->crc_err &&
- !memcmp(get_hdr_bssid(wlanhdr), get_bssid(&padapter->mlmepriv), ETH_ALEN));
+ rx_ra = get_ra(wlanhdr);
+ my_hwaddr = myid(&padapter->eeprompriv);
+ pkt_info.to_self = pkt_info.bssid_match &&
+ !ether_addr_equal(rx_ra, my_hwaddr);
- pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID && (!memcmp(get_ra(wlanhdr), myid(&padapter->eeprompriv), ETH_ALEN));
- pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID && (GetFrameSubType(wlanhdr) == WIFI_BEACON);
+ pkt_info.is_beacon = pkt_info.bssid_match &&
+ (GetFrameSubType(wlanhdr) == WIFI_BEACON);
sa = get_ta(wlanhdr);
- pkt_info.StationID = 0xFF;
+ pkt_info.station_id = 0xFF;
pstapriv = &padapter->stapriv;
psta = rtw_get_stainfo(pstapriv, sa);
if (psta) {
- pkt_info.StationID = psta->mac_id;
- /* DBG_8192C("%s ==> StationID(%d)\n", __func__, pkt_info.StationID); */
+ pkt_info.station_id = psta->mac_id;
+ /* DBG_8192C("%s ==> StationID(%d)\n",
+ * __func__, pkt_info.station_id); */
}
- pkt_info.DataRate = pattrib->data_rate;
+ pkt_info.data_rate = pattrib->data_rate;
/* rtl8723b_query_rx_phy_status(precvframe, pphy_status); */
- /* spin_lock_bh(&pHalData->odm_stainfo_lock); */
- ODM_PhyStatusQuery(&pHalData->odmpriv, pPHYInfo, (u8 *)pphy_status, &(pkt_info));
+ /* spin_lock_bh(&p_hal_data->odm_stainfo_lock); */
+ ODM_PhyStatusQuery(&p_hal_data->odmpriv, p_phy_info,
+ (u8 *)pphy_status, &(pkt_info));
if (psta)
psta->rssi = pattrib->phy_info.RecvSignalPower;
- /* spin_unlock_bh(&pHalData->odm_stainfo_lock); */
+ /* spin_unlock_bh(&p_hal_data->odm_stainfo_lock); */
precvframe->u.hdr.psta = NULL;
if (
- pkt_info.bPacketMatchBSSID &&
+ pkt_info.bssid_match &&
(check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true)
) {
if (psta) {
precvframe->u.hdr.psta = psta;
rtl8723b_process_phy_info(padapter, precvframe);
}
- } else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) {
- if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == true)
+ } else if (pkt_info.to_self || pkt_info.is_beacon) {
+ u32 adhoc_state = WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE;
+ if (check_fwstate(&padapter->mlmepriv, adhoc_state))
if (psta)
precvframe->u.hdr.psta = psta;
rtl8723b_process_phy_info(padapter, precvframe);
}
}
-static void rtl8723bs_c2h_packet_handler(struct adapter *padapter, u8 *pbuf, u16 length)
+static void rtl8723bs_c2h_packet_handler(struct adapter *padapter,
+ u8 *pbuf, u16 length)
{
- u8 *tmpBuf = NULL;
+ u8 *tmp = NULL;
u8 res = false;
if (length == 0)
@@ -160,85 +177,127 @@ static void rtl8723bs_c2h_packet_handler(struct adapter *padapter, u8 *pbuf, u16
/* DBG_871X("+%s() length =%d\n", __func__, length); */
- tmpBuf = rtw_zmalloc(length);
- if (tmpBuf == NULL)
+ tmp = rtw_zmalloc(length);
+ if (tmp == NULL)
return;
- memcpy(tmpBuf, pbuf, length);
+ memcpy(tmp, pbuf, length);
- res = rtw_c2h_packet_wk_cmd(padapter, tmpBuf, length);
+ res = rtw_c2h_packet_wk_cmd(padapter, tmp, length);
if (res == false)
- kfree(tmpBuf);
+ kfree(tmp);
/* DBG_871X("-%s res(%d)\n", __func__, res); */
return;
}
+static inline union recv_frame *try_alloc_recvframe(struct recv_priv *precvpriv,
+ struct recv_buf *precvbuf)
+{
+ union recv_frame *precvframe;
+
+ precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue);
+ if (!precvframe) {
+ DBG_8192C("%s: no enough recv frame!\n", __func__);
+ rtw_enqueue_recvbuf_to_head(precvbuf,
+ &precvpriv->recv_buf_pending_queue);
+
+ /* The case of can't allocte recvframe should be temporary, */
+ /* schedule again and hope recvframe is available next time. */
+ tasklet_schedule(&precvpriv->recv_tasklet);
+ }
+
+ return precvframe;
+}
+
+static inline bool rx_crc_err(struct recv_priv *precvpriv,
+ struct hal_com_data *p_hal_data,
+ struct rx_pkt_attrib *pattrib,
+ union recv_frame *precvframe)
+{
+ /* fix Hardware RX data error, drop whole recv_buffer */
+ if ((!(p_hal_data->ReceiveConfig & RCR_ACRC32)) && pattrib->crc_err) {
+ DBG_8192C("%s()-%d: RX Warning! rx CRC ERROR !!\n",
+ __func__, __LINE__);
+ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
+ return true;
+ }
+
+ return false;
+}
+
+static inline bool pkt_exceeds_tail(struct recv_priv *precvpriv,
+ u8 *end, u8 *tail,
+ union recv_frame *precvframe)
+{
+ if (end > tail) {
+ DBG_8192C("%s()-%d: : next pkt len(%p,%d) exceed ptail(%p)!\n",
+ __func__, __LINE__, ptr, pkt_offset, precvbuf->ptail);
+ rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
+ return true;
+ }
+
+ return false;
+}
+
static void rtl8723bs_recv_tasklet(void *priv)
{
struct adapter *padapter;
- struct hal_com_data *pHalData;
+ struct hal_com_data *p_hal_data;
struct recv_priv *precvpriv;
struct recv_buf *precvbuf;
union recv_frame *precvframe;
struct rx_pkt_attrib *pattrib;
+ struct __queue *recv_buf_queue;
u8 *ptr;
u32 pkt_offset, skb_len, alloc_sz;
_pkt *pkt_copy = NULL;
u8 shift_sz = 0, rx_report_sz = 0;
-
padapter = priv;
- pHalData = GET_HAL_DATA(padapter);
+ p_hal_data = GET_HAL_DATA(padapter);
precvpriv = &padapter->recvpriv;
+ recv_buf_queue = &precvpriv->recv_buf_pending_queue;
do {
- precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue);
- if (NULL == precvbuf)
+ precvbuf = rtw_dequeue_recvbuf(recv_buf_queue);
+ if (!precvbuf)
break;
ptr = precvbuf->pdata;
while (ptr < precvbuf->ptail) {
- precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue);
- if (precvframe == NULL) {
- DBG_8192C("%s: no enough recv frame!\n", __func__);
- rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue);
-
- /* The case of can't allocte recvframe should be temporary, */
- /* schedule again and hope recvframe is available next time. */
- tasklet_schedule(&precvpriv->recv_tasklet);
+ precvframe = try_alloc_recvframe(precvpriv, precvbuf);
+ if(!precvframe)
return;
- }
/* rx desc parsing */
- update_recvframe_attrib(padapter, precvframe, (struct recv_stat *)ptr);
+ update_recvframe_attrib(padapter, precvframe,
+ (struct recv_stat *)ptr);
pattrib = &precvframe->u.hdr.attrib;
- /* fix Hardware RX data error, drop whole recv_buffer */
- if ((!(pHalData->ReceiveConfig & RCR_ACRC32)) && pattrib->crc_err) {
- DBG_8192C("%s()-%d: RX Warning! rx CRC ERROR !!\n", __func__, __LINE__);
- rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
+ if(rx_crc_err(precvpriv, p_hal_data,
+ pattrib, precvframe))
break;
- }
rx_report_sz = RXDESC_SIZE + pattrib->drvinfo_sz;
- pkt_offset = rx_report_sz + pattrib->shift_sz + pattrib->pkt_len;
+ pkt_offset = rx_report_sz +
+ pattrib->shift_sz +
+ pattrib->pkt_len;
- if ((ptr + pkt_offset) > precvbuf->ptail) {
- DBG_8192C("%s()-%d: : next pkt len(%p,%d) exceed ptail(%p)!\n", __func__, __LINE__, ptr, pkt_offset, precvbuf->ptail);
- rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
+ if(pkt_exceeds_tail(precvpriv, ptr + pkt_offset,
+ precvbuf->ptail, precvframe))
break;
- }
if ((pattrib->crc_err) || (pattrib->icv_err)) {
- {
- DBG_8192C("%s: crc_err =%d icv_err =%d, skip!\n", __func__, pattrib->crc_err, pattrib->icv_err);
- }
- rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
+ DBG_8192C("%s: crc_err =%d icv_err =%d, skip!\n",
+ __func__, pattrib->crc_err,
+ pattrib->icv_err);
+ rtw_free_recvframe(precvframe,
+ &precvpriv->free_recv_queue);
} else {
/* Modified by Albert 20101213 */
/* For 8 bytes IP header alignment. */
@@ -289,7 +348,7 @@ static void rtl8723bs_recv_tasklet(void *priv)
skb_reset_tail_pointer(pkt_clone);
precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail
= pkt_clone->data;
- precvframe->u.hdr.rx_end = pkt_clone->data + skb_len;
+ precvframe->u.hdr.rx_end = pkt_clone->data + skb_len;
} else {
DBG_8192C("%s: rtw_skb_clone fail\n", __func__);
rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
@@ -300,14 +359,14 @@ static void rtl8723bs_recv_tasklet(void *priv)
recvframe_put(precvframe, skb_len);
/* recvframe_pull(precvframe, drvinfo_sz + RXDESC_SIZE); */
- if (pHalData->ReceiveConfig & RCR_APPFCS)
+ if (p_hal_data->ReceiveConfig & RCR_APPFCS)
recvframe_pull_tail(precvframe, IEEE80211_FCS_LEN);
/* move to drv info position */
ptr += RXDESC_SIZE;
/* update drv info */
- if (pHalData->ReceiveConfig & RCR_APP_BA_SSN) {
+ if (p_hal_data->ReceiveConfig & RCR_APP_BA_SSN) {
/* rtl8723s_update_bassn(padapter, pdrvinfo); */
ptr += 4;
}
@@ -337,7 +396,6 @@ static void rtl8723bs_recv_tasklet(void *priv)
rtl8723bs_c2h_packet_handler(padapter, precvframe->u.hdr.rx_data, pattrib->pkt_len);
rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
-
}
}
@@ -350,7 +408,6 @@ static void rtl8723bs_recv_tasklet(void *priv)
rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue);
} while (1);
-
}
/*
@@ -366,7 +423,6 @@ s32 rtl8723bs_init_recv_priv(struct adapter *padapter)
struct recv_priv *precvpriv;
struct recv_buf *precvbuf;
-
res = _SUCCESS;
precvpriv = &padapter->recvpriv;
@@ -463,7 +519,6 @@ void rtl8723bs_free_recv_priv(struct adapter *padapter)
struct recv_priv *precvpriv;
struct recv_buf *precvbuf;
-
precvpriv = &padapter->recvpriv;
/* 3 1. kill tasklet */
diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h
index 32129ac8e169..16b81b1a3f33 100644
--- a/drivers/staging/rtl8723bs/include/drv_types.h
+++ b/drivers/staging/rtl8723bs/include/drv_types.h
@@ -692,9 +692,9 @@ int rtw_suspend_wow(struct adapter *padapter);
int rtw_resume_process_wow(struct adapter *padapter);
#endif
-__inline static u8 *myid(struct eeprom_priv *peepriv)
+static inline u8 *myid(struct eeprom_priv *peepriv)
{
- return (peepriv->mac_addr);
+ return peepriv->mac_addr;
}
/* HCI Related header file */
diff --git a/drivers/staging/rtl8723bs/include/ieee80211.h b/drivers/staging/rtl8723bs/include/ieee80211.h
index 73ce63770c3c..c8e5251c2760 100644
--- a/drivers/staging/rtl8723bs/include/ieee80211.h
+++ b/drivers/staging/rtl8723bs/include/ieee80211.h
@@ -84,10 +84,6 @@ enum {
#define IEEE_PARAM_IEEE_802_1X 6
#define IEEE_PARAM_WPAX_SELECT 7
-#define AUTH_ALG_OPEN_SYSTEM 0x1
-#define AUTH_ALG_SHARED_KEY 0x2
-#define AUTH_ALG_LEAP 0x00000004
-
#define IEEE_MLME_STA_DEAUTH 1
#define IEEE_MLME_STA_DISASSOC 2
@@ -276,20 +272,6 @@ struct sta_data{
u64 tx_drops;
};
-#define IEEE80211_DATA_LEN 2304
-/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
- 6.2.1.1.2.
-
- The figure in section 7.1.2 suggests a body size of up to 2312
- bytes is allowed, which is a bit confusing, I suspect this
- represents the 2304 bytes of real data, plus a possible 8 bytes of
- WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
-
-
-#define IEEE80211_HLEN 30
-#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
-
-
/* this is stolen from ipw2200 driver */
#define IEEE_IBSS_MAC_HASH_SIZE 31
@@ -317,75 +299,11 @@ enum eap_type {
EAPOL_ENCAP_ASF_ALERT
};
-#define IEEE80211_3ADDR_LEN 24
-#define IEEE80211_4ADDR_LEN 30
#define IEEE80211_FCS_LEN 4
#define MIN_FRAG_THRESHOLD 256U
#define MAX_FRAG_THRESHOLD 2346U
-/* Frame control field constants */
-#define RTW_IEEE80211_FCTL_VERS 0x0003
-#define RTW_IEEE80211_FCTL_FTYPE 0x000c
-#define RTW_IEEE80211_FCTL_STYPE 0x00f0
-#define RTW_IEEE80211_FCTL_TODS 0x0100
-#define RTW_IEEE80211_FCTL_FROMDS 0x0200
-#define RTW_IEEE80211_FCTL_MOREFRAGS 0x0400
-#define RTW_IEEE80211_FCTL_RETRY 0x0800
-#define RTW_IEEE80211_FCTL_PM 0x1000
-#define RTW_IEEE80211_FCTL_MOREDATA 0x2000
-#define RTW_IEEE80211_FCTL_PROTECTED 0x4000
-#define RTW_IEEE80211_FCTL_ORDER 0x8000
-#define RTW_IEEE80211_FCTL_CTL_EXT 0x0f00
-
-#define RTW_IEEE80211_FTYPE_MGMT 0x0000
-#define RTW_IEEE80211_FTYPE_CTL 0x0004
-#define RTW_IEEE80211_FTYPE_DATA 0x0008
-#define RTW_IEEE80211_FTYPE_EXT 0x000c
-
-/* management */
-#define RTW_IEEE80211_STYPE_ASSOC_REQ 0x0000
-#define RTW_IEEE80211_STYPE_ASSOC_RESP 0x0010
-#define RTW_IEEE80211_STYPE_REASSOC_REQ 0x0020
-#define RTW_IEEE80211_STYPE_REASSOC_RESP 0x0030
-#define RTW_IEEE80211_STYPE_PROBE_REQ 0x0040
-#define RTW_IEEE80211_STYPE_PROBE_RESP 0x0050
-#define RTW_IEEE80211_STYPE_BEACON 0x0080
-#define RTW_IEEE80211_STYPE_ATIM 0x0090
-#define RTW_IEEE80211_STYPE_DISASSOC 0x00A0
-#define RTW_IEEE80211_STYPE_AUTH 0x00B0
-#define RTW_IEEE80211_STYPE_DEAUTH 0x00C0
-#define RTW_IEEE80211_STYPE_ACTION 0x00D0
-
-/* control */
-#define RTW_IEEE80211_STYPE_CTL_EXT 0x0060
-#define RTW_IEEE80211_STYPE_BACK_REQ 0x0080
-#define RTW_IEEE80211_STYPE_BACK 0x0090
-#define RTW_IEEE80211_STYPE_PSPOLL 0x00A0
-#define RTW_IEEE80211_STYPE_RTS 0x00B0
-#define RTW_IEEE80211_STYPE_CTS 0x00C0
-#define RTW_IEEE80211_STYPE_ACK 0x00D0
-#define RTW_IEEE80211_STYPE_CFEND 0x00E0
-#define RTW_IEEE80211_STYPE_CFENDACK 0x00F0
-
-/* data */
-#define RTW_IEEE80211_STYPE_DATA 0x0000
-#define RTW_IEEE80211_STYPE_DATA_CFACK 0x0010
-#define RTW_IEEE80211_STYPE_DATA_CFPOLL 0x0020
-#define RTW_IEEE80211_STYPE_DATA_CFACKPOLL 0x0030
-#define RTW_IEEE80211_STYPE_NULLFUNC 0x0040
-#define RTW_IEEE80211_STYPE_CFACK 0x0050
-#define RTW_IEEE80211_STYPE_CFPOLL 0x0060
-#define RTW_IEEE80211_STYPE_CFACKPOLL 0x0070
-#define RTW_IEEE80211_STYPE_QOS_DATA 0x0080
-#define RTW_IEEE80211_STYPE_QOS_DATA_CFACK 0x0090
-#define RTW_IEEE80211_STYPE_QOS_DATA_CFPOLL 0x00A0
-#define RTW_IEEE80211_STYPE_QOS_DATA_CFACKPOLL 0x00B0
-#define RTW_IEEE80211_STYPE_QOS_NULLFUNC 0x00C0
-#define RTW_IEEE80211_STYPE_QOS_CFACK 0x00D0
-#define RTW_IEEE80211_STYPE_QOS_CFPOLL 0x00E0
-#define RTW_IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0
-
/* sequence control field */
#define RTW_IEEE80211_SCTL_FRAG 0x000F
#define RTW_IEEE80211_SCTL_SEQ 0xFFF0
@@ -426,8 +344,8 @@ struct ieee80211_snap_hdr {
#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
-#define WLAN_FC_GET_TYPE(fc) ((fc) & RTW_IEEE80211_FCTL_FTYPE)
-#define WLAN_FC_GET_STYPE(fc) ((fc) & RTW_IEEE80211_FCTL_STYPE)
+#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
+#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
#define WLAN_QC_GET_TID(qc) ((qc) & 0x0f)
@@ -435,91 +353,23 @@ struct ieee80211_snap_hdr {
#define WLAN_GET_SEQ_SEQ(seq) ((seq) & RTW_IEEE80211_SCTL_SEQ)
/* Authentication algorithms */
-#define WLAN_AUTH_OPEN 0
-#define WLAN_AUTH_SHARED_KEY 1
-
-#define WLAN_AUTH_CHALLENGE_LEN 128
-
#define WLAN_CAPABILITY_BSS (1<<0)
-#define WLAN_CAPABILITY_IBSS (1<<1)
-#define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
-#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
-#define WLAN_CAPABILITY_PRIVACY (1<<4)
-#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
-#define WLAN_CAPABILITY_PBCC (1<<6)
-#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
#define WLAN_CAPABILITY_SHORT_SLOT (1<<10)
-/* Status codes */
-#define WLAN_STATUS_SUCCESS 0
-#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
-#define WLAN_STATUS_CAPS_UNSUPPORTED 10
-#define WLAN_STATUS_REASSOC_NO_ASSOC 11
-#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
-#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
-#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
-#define WLAN_STATUS_CHALLENGE_FAIL 15
-#define WLAN_STATUS_AUTH_TIMEOUT 16
-#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
-#define WLAN_STATUS_ASSOC_DENIED_RATES 18
/* 802.11b */
#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
-#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
-#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
/* Reason codes */
-#define WLAN_REASON_UNSPECIFIED 1
-#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
-#define WLAN_REASON_DEAUTH_LEAVING 3
-#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
-#define WLAN_REASON_DISASSOC_AP_BUSY 5
-#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
-#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
-#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
-#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
#define WLAN_REASON_ACTIVE_ROAM 65533
#define WLAN_REASON_JOIN_WRONG_CHANNEL 65534
#define WLAN_REASON_EXPIRATION_CHK 65535
-/* Information Element IDs */
-#define WLAN_EID_SSID 0
-#define WLAN_EID_SUPP_RATES 1
-#define WLAN_EID_FH_PARAMS 2
-#define WLAN_EID_DS_PARAMS 3
-#define WLAN_EID_CF_PARAMS 4
-#define WLAN_EID_TIM 5
-#define WLAN_EID_IBSS_PARAMS 6
-#define WLAN_EID_CHALLENGE 16
-/* EIDs defined by IEEE 802.11h - START */
-#define WLAN_EID_PWR_CONSTRAINT 32
-#define WLAN_EID_PWR_CAPABILITY 33
-#define WLAN_EID_TPC_REQUEST 34
-#define WLAN_EID_TPC_REPORT 35
-#define WLAN_EID_SUPPORTED_CHANNELS 36
-#define WLAN_EID_CHANNEL_SWITCH 37
-#define WLAN_EID_MEASURE_REQUEST 38
-#define WLAN_EID_MEASURE_REPORT 39
-#define WLAN_EID_QUITE 40
-#define WLAN_EID_IBSS_DFS 41
/* EIDs defined by IEEE 802.11h - END */
-#define WLAN_EID_ERP_INFO 42
#define WLAN_EID_HT_CAP 45
-#define WLAN_EID_RSN 48
-#define WLAN_EID_EXT_SUPP_RATES 50
-#define WLAN_EID_MOBILITY_DOMAIN 54
-#define WLAN_EID_FAST_BSS_TRANSITION 55
-#define WLAN_EID_TIMEOUT_INTERVAL 56
-#define WLAN_EID_RIC_DATA 57
-#define WLAN_EID_HT_OPERATION 61
-#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
#define WLAN_EID_20_40_BSS_COEXISTENCE 72
#define WLAN_EID_20_40_BSS_INTOLERANT 73
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
-#define WLAN_EID_MMIE 76
-#define WLAN_EID_VENDOR_SPECIFIC 221
#define WLAN_EID_GENERIC (WLAN_EID_VENDOR_SPECIFIC)
-#define WLAN_EID_VHT_CAPABILITY 191
-#define WLAN_EID_VHT_OPERATION 192
#define WLAN_EID_VHT_OP_MODE_NOTIFY 199
#define IEEE80211_MGMT_HDR_LEN 24
diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme.h b/drivers/staging/rtl8723bs/include/rtw_mlme.h
index 00b3d92c9f51..2e4f12b54929 100644
--- a/drivers/staging/rtl8723bs/include/rtw_mlme.h
+++ b/drivers/staging/rtl8723bs/include/rtw_mlme.h
@@ -299,7 +299,7 @@ struct wifidirect_info{
struct tdls_ss_record{ /* signal strength record */
u8 macaddr[ETH_ALEN];
- u8 RxPWDBAll;
+ u8 rx_pwd_ba11;
u8 is_tdls_sta; /* true: direct link sta, false: else */
};
diff --git a/drivers/staging/rtl8723bs/include/rtw_recv.h b/drivers/staging/rtl8723bs/include/rtw_recv.h
index 71039ca79e4b..d4986f5685c5 100644
--- a/drivers/staging/rtl8723bs/include/rtw_recv.h
+++ b/drivers/staging/rtl8723bs/include/rtw_recv.h
@@ -99,20 +99,20 @@ struct signal_stat {
};
struct phy_info {
- u8 RxPWDBAll;
+ u8 rx_pwd_ba11;
u8 SignalQuality; /* in 0-100 index. */
- s8 RxMIMOSignalQuality[4]; /* per-path's EVM */
+ s8 rx_mimo_signal_quality[4]; /* per-path's EVM */
u8 RxMIMOEVMdbm[4]; /* per-path's EVM dbm */
- u8 RxMIMOSignalStrength[4];/* in 0~100 index */
+ u8 rx_mimo_signal_strength[4];/* in 0~100 index */
u16 Cfo_short[4]; /* per-path's Cfo_short */
u16 Cfo_tail[4]; /* per-path's Cfo_tail */
s8 RxPower; /* in dBm Translate from PWdB */
s8 RecvSignalPower;/* Real power in dBm for this packet, no beautification and aggregation. Keep this raw info to be used for the other procedures. */
- u8 BTRxRSSIPercentage;
+ u8 bt_rx_rssi_percentage;
u8 SignalStrength; /* in 0-100 index. */
s8 RxPwr[4]; /* per-path's pwdb */
@@ -187,7 +187,7 @@ struct rx_pkt_attrib {
u8 signal_qual;
s8 rx_mimo_signal_qual[2];
u8 signal_strength;
- u32 RxPWDBAll;
+ u32 rx_pwd_ba11;
s32 RecvSignalPower;
*/
struct phy_info phy_info;
diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
index 51d48de24a24..46bc2e512557 100644
--- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
+++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
@@ -14,6 +14,7 @@
******************************************************************************/
#define _IOCTL_CFG80211_C_
+#include <linux/etherdevice.h>
#include <drv_types.h>
#include <rtw_debug.h>
#include <linux/jiffies.h>
@@ -2391,7 +2392,7 @@ static int cfg80211_rtw_del_pmksa(struct wiphy *wiphy,
{
if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, (u8 *)pmksa->bssid, ETH_ALEN))
{ /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */
- memset(psecuritypriv->PMKIDList[index].Bssid, 0x00, ETH_ALEN);
+ eth_zero_addr(psecuritypriv->PMKIDList[index].Bssid);
memset(psecuritypriv->PMKIDList[index].PMKID, 0x00, WLAN_PMKID_LEN);
psecuritypriv->PMKIDList[index].bUsed = false;
bMatched = true;
@@ -2516,7 +2517,7 @@ static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struct net_de
dot11_hdr = (struct ieee80211_hdr *)skb->data;
frame_control = le16_to_cpu(dot11_hdr->frame_control);
/* Check if the QoS bit is set */
- if ((frame_control & RTW_IEEE80211_FCTL_FTYPE) == RTW_IEEE80211_FTYPE_DATA) {
+ if ((frame_control & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
/* Check if this ia a Wireless Distribution System (WDS) frame
* which has 4 MAC addresses
*/
@@ -2544,8 +2545,8 @@ static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struct net_de
return ret;
}
- else if ((frame_control & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE))
- == (RTW_IEEE80211_FTYPE_MGMT|RTW_IEEE80211_STYPE_ACTION)
+ else if ((frame_control & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE))
+ == (IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_ACTION)
)
{
/* only for action frames */
@@ -2606,7 +2607,7 @@ static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struct net_de
}
else
{
- DBG_8192C("frame_control = 0x%x\n", frame_control & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE));
+ DBG_8192C("frame_control = 0x%x\n", frame_control & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE));
}
@@ -3255,7 +3256,7 @@ static int cfg80211_rtw_sched_scan_start(struct wiphy *wiphy,
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
- u8 ret;
+ int ret;
if (padapter->bup == false) {
DBG_871X("%s: net device is down.\n", __func__);
diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
index cc18d0ad7d7b..b26533983864 100644
--- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c
@@ -14,6 +14,7 @@
******************************************************************************/
#define _IOCTL_LINUX_C_
+#include <linux/etherdevice.h>
#include <drv_types.h>
#include <rtw_debug.h>
#include <rtw_mp.h>
@@ -124,7 +125,7 @@ void rtw_indicate_wx_disassoc_event(struct adapter *padapter)
memset(&wrqu, 0, sizeof(union iwreq_data));
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+ eth_zero_addr(wrqu.ap_addr.sa_data);
}
/*
@@ -475,26 +476,26 @@ static int wpa_set_auth_algs(struct net_device *dev, u32 value)
struct adapter *padapter = (struct adapter *) rtw_netdev_priv(dev);
int ret = 0;
- if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) {
- DBG_871X("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY and AUTH_ALG_OPEN_SYSTEM [value:0x%x]\n", value);
+ if ((value & WLAN_AUTH_SHARED_KEY) && (value & WLAN_AUTH_OPEN)) {
+ DBG_871X("wpa_set_auth_algs, WLAN_AUTH_SHARED_KEY and WLAN_AUTH_OPEN [value:0x%x]\n", value);
padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch;
padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
- } else if (value & AUTH_ALG_SHARED_KEY) {
- DBG_871X("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY [value:0x%x]\n", value);
+ } else if (value & WLAN_AUTH_SHARED_KEY) {
+ DBG_871X("wpa_set_auth_algs, WLAN_AUTH_SHARED_KEY [value:0x%x]\n", value);
padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared;
padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared;
- } else if (value & AUTH_ALG_OPEN_SYSTEM) {
- DBG_871X("wpa_set_auth_algs, AUTH_ALG_OPEN_SYSTEM\n");
+ } else if (value & WLAN_AUTH_OPEN) {
+ DBG_871X("wpa_set_auth_algs, WLAN_AUTH_OPEN\n");
/* padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; */
if (padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK) {
padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
}
- } else if (value & AUTH_ALG_LEAP) {
- DBG_871X("wpa_set_auth_algs, AUTH_ALG_LEAP\n");
+ } else if (value & WLAN_AUTH_LEAP) {
+ DBG_871X("wpa_set_auth_algs, WLAN_AUTH_LEAP\n");
} else {
DBG_871X("wpa_set_auth_algs, error!\n");
ret = -EINVAL;
@@ -1080,7 +1081,7 @@ static int rtw_wx_set_pmkid(struct net_device *dev,
for (j = 0 ; j<NUM_PMKID_CACHE; j++) {
if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) {
/* BSSID is matched, the same AP => Remove this PMKID information and reset it. */
- memset(psecuritypriv->PMKIDList[ j ].Bssid, 0x00, ETH_ALEN);
+ eth_zero_addr(psecuritypriv->PMKIDList[j].Bssid);
psecuritypriv->PMKIDList[ j ].bUsed = false;
break;
}
@@ -1294,7 +1295,7 @@ static int rtw_wx_get_wap(struct net_device *dev,
wrqu->ap_addr.sa_family = ARPHRD_ETHER;
- memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
+ eth_zero_addr(wrqu->ap_addr.sa_data);
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_wap\n"));
@@ -1303,7 +1304,7 @@ static int rtw_wx_get_wap(struct net_device *dev,
((check_fwstate(pmlmepriv, WIFI_AP_STATE)) == true)) {
memcpy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress, ETH_ALEN);
} else {
- memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
+ eth_zero_addr(wrqu->ap_addr.sa_data);
}
return 0;
@@ -2130,75 +2131,65 @@ static int rtw_wx_set_gen_ie(struct net_device *dev,
}
static int rtw_wx_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
{
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
struct iw_param *param = (struct iw_param*)&(wrqu->param);
int ret = 0;
switch (param->flags & IW_AUTH_INDEX) {
-
case IW_AUTH_WPA_VERSION:
break;
case IW_AUTH_CIPHER_PAIRWISE:
-
break;
case IW_AUTH_CIPHER_GROUP:
-
break;
case IW_AUTH_KEY_MGMT:
/*
* ??? does not use these parameters
*/
break;
-
case IW_AUTH_TKIP_COUNTERMEASURES:
- {
- if (param->value) {
- /* wpa_supplicant is enabling the tkip countermeasure. */
+ /* wpa_supplicant is setting the tkip countermeasure. */
+ if (param->value) /* enabling */
padapter->securitypriv.btkip_countermeasure = true;
- } else {
- /* wpa_supplicant is disabling the tkip countermeasure. */
+ else /* disabling */
padapter->securitypriv.btkip_countermeasure = false;
- }
break;
- }
case IW_AUTH_DROP_UNENCRYPTED:
- {
- /* HACK:
- *
- * wpa_supplicant calls set_wpa_enabled when the driver
- * is loaded and unloaded, regardless of if WPA is being
- * used. No other calls are made which can be used to
- * determine if encryption will be used or not prior to
- * association being expected. If encryption is not being
- * used, drop_unencrypted is set to false, else true -- we
- * can use this to determine if the CAP_PRIVACY_ON bit should
- * be set.
- */
-
- if (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption1Enabled) {
- break;/* it means init value, or using wep, ndisencryptstatus = Ndis802_11Encryption1Enabled, */
- /* then it needn't reset it; */
- }
-
- if (param->value) {
- padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
- padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
- padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
- padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
- padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeOpen;
- }
+ /* HACK:
+ *
+ * wpa_supplicant calls set_wpa_enabled when the driver
+ * is loaded and unloaded, regardless of if WPA is being
+ * used. No other calls are made which can be used to
+ * determine if encryption will be used or not prior to
+ * association being expected. If encryption is not being
+ * used, drop_unencrypted is set to false, else true -- we
+ * can use this to determine if the CAP_PRIVACY_ON bit should
+ * be set.
+ */
+ /*
+ * This means init value, or using wep, ndisencryptstatus =
+ * Ndis802_11Encryption1Enabled, then it needn't reset it;
+ */
+ if (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption1Enabled)
break;
+
+ if (param->value) {
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+ padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeOpen;
}
+ break;
case IW_AUTH_80211_AUTH_ALG:
-
/*
* It's the starting point of a link layer connection using wpa_supplicant
- */
+ */
if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
LeaveAllPowerSaveMode(padapter);
rtw_disassoc_cmd(padapter, 500, false);
@@ -2207,11 +2198,8 @@ static int rtw_wx_set_auth(struct net_device *dev,
rtw_free_assoc_resources(padapter, 1);
}
-
ret = wpa_set_auth_algs(dev, (u32)param->value);
-
break;
-
case IW_AUTH_WPA_ENABLED:
break;
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
@@ -2221,6 +2209,7 @@ static int rtw_wx_set_auth(struct net_device *dev,
default:
return -EOPNOTSUPP;
}
+
return ret;
}
diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c
index e804b430931c..b43e24c3a23a 100644
--- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c
@@ -43,6 +43,7 @@ void rtw_os_recv_resource_free(struct recv_priv *precvpriv)
{
sint i;
union recv_frame *precvframe;
+
precvframe = (union recv_frame*) precvpriv->precv_frame_buf;
for (i = 0; i < NR_RECVFRAME; i++)
@@ -181,11 +182,11 @@ void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt
pkt->dev = padapter->pnetdev;
#ifdef CONFIG_TCP_CSUM_OFFLOAD_RX
- if ((pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1)) {
+ if ((pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1))
pkt->ip_summed = CHECKSUM_UNNECESSARY;
- } else {
+ else
pkt->ip_summed = CHECKSUM_NONE;
- }
+
#else /* !CONFIG_TCP_CSUM_OFFLOAD_RX */
pkt->ip_summed = CHECKSUM_NONE;
#endif /* CONFIG_TCP_CSUM_OFFLOAD_RX */
diff --git a/drivers/staging/rtl8723bs/os_dep/rtw_proc.c b/drivers/staging/rtl8723bs/os_dep/rtw_proc.c
index 9a885e626d1c..49c8684dc25b 100644
--- a/drivers/staging/rtl8723bs/os_dep/rtw_proc.c
+++ b/drivers/staging/rtl8723bs/os_dep/rtw_proc.c
@@ -19,7 +19,7 @@
#ifdef PROC_DEBUG
-static struct proc_dir_entry *rtw_proc = NULL;
+static struct proc_dir_entry *rtw_proc;
#define RTW_PROC_NAME "rtl8723bs"
@@ -142,7 +142,7 @@ int rtw_drv_proc_init(void)
goto exit;
}
- for (i = 0;i<drv_proc_hdls_num;i++) {
+ for (i = 0; i < drv_proc_hdls_num; i++) {
entry = rtw_proc_create_entry(drv_proc_hdls[i].name, rtw_proc, &rtw_drv_proc_fops, (void *)i);
if (!entry) {
rtw_warn_on(1);
@@ -163,7 +163,7 @@ void rtw_drv_proc_deinit(void)
if (rtw_proc == NULL)
return;
- for (i = 0;i<drv_proc_hdls_num;i++)
+ for (i = 0; i < drv_proc_hdls_num; i++)
remove_proc_entry(drv_proc_hdls[i].name, rtw_proc);
remove_proc_entry(RTW_PROC_NAME, get_proc_net);
@@ -341,7 +341,7 @@ static int proc_get_cam_cache(struct seq_file *m, void *v)
/* "MK", "GK", "MFB", "valid" */
);
- for (i = 0;i<32;i++) {
+ for (i = 0; i < 32; i++) {
if (dvobj->cam_cache[i].ctrl != 0)
DBG_871X_SEL_NL(m, "%2u 0x%04x "MAC_FMT" "KEY_FMT" %3u %-7s"
/* %2u %2u 0x%02x %5u" */
@@ -663,7 +663,7 @@ static struct proc_dir_entry *rtw_odm_proc_init(struct net_device *dev)
adapter->dir_odm = dir_odm;
- for (i = 0;i<odm_proc_hdls_num;i++) {
+ for (i = 0; i < odm_proc_hdls_num; i++) {
entry = rtw_proc_create_entry(odm_proc_hdls[i].name, dir_odm, &rtw_odm_proc_fops, (void *)i);
if (!entry) {
rtw_warn_on(1);
@@ -687,7 +687,7 @@ static void rtw_odm_proc_deinit(struct adapter *adapter)
return;
}
- for (i = 0;i<odm_proc_hdls_num;i++)
+ for (i = 0; i < odm_proc_hdls_num; i++)
remove_proc_entry(odm_proc_hdls[i].name, dir_odm);
remove_proc_entry("odm", adapter->dir_dev);
@@ -721,7 +721,7 @@ struct proc_dir_entry *rtw_adapter_proc_init(struct net_device *dev)
adapter->dir_dev = dir_dev;
- for (i = 0;i<adapter_proc_hdls_num;i++) {
+ for (i = 0; i < adapter_proc_hdls_num; i++) {
entry = rtw_proc_create_entry(adapter_proc_hdls[i].name, dir_dev, &rtw_adapter_proc_fops, (void *)i);
if (!entry) {
rtw_warn_on(1);
@@ -749,7 +749,7 @@ void rtw_adapter_proc_deinit(struct net_device *dev)
return;
}
- for (i = 0;i<adapter_proc_hdls_num;i++)
+ for (i = 0; i < adapter_proc_hdls_num; i++)
remove_proc_entry(adapter_proc_hdls[i].name, dir_dev);
rtw_odm_proc_deinit(adapter);
@@ -773,7 +773,7 @@ void rtw_adapter_proc_replace(struct net_device *dev)
return;
}
- for (i = 0;i<adapter_proc_hdls_num;i++)
+ for (i = 0; i < adapter_proc_hdls_num; i++)
remove_proc_entry(adapter_proc_hdls[i].name, dir_dev);
rtw_odm_proc_deinit(adapter);
diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
index 943324877707..99c407ba0874 100644
--- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
+++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c
@@ -337,7 +337,7 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct
struct adapter *padapter = NULL;
PSDIO_DATA psdio = &dvobj->intf_data;
- padapter = (struct adapter *)vzalloc(sizeof(*padapter));
+ padapter = vzalloc(sizeof(*padapter));
if (padapter == NULL) {
goto exit;
}
diff --git a/drivers/staging/rtl8723bs/os_dep/xmit_linux.c b/drivers/staging/rtl8723bs/os_dep/xmit_linux.c
index f29e110f9bdb..21e1b811f997 100644
--- a/drivers/staging/rtl8723bs/os_dep/xmit_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/xmit_linux.c
@@ -64,9 +64,7 @@ int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitb
if (alloc_sz > 0) {
pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz);
if (pxmitbuf->pallocated_buf == NULL)
- {
return _FAIL;
- }
pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
}
@@ -90,10 +88,8 @@ void rtw_os_pkt_complete(struct adapter *padapter, _pkt *pkt)
queue = skb_get_queue_mapping(pkt);
if (padapter->registrypriv.wifi_spec) {
if (__netif_subqueue_stopped(padapter->pnetdev, queue) &&
- (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD))
- {
+ (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD))
netif_wake_subqueue(padapter->pnetdev, queue);
- }
} else {
if (__netif_subqueue_stopped(padapter->pnetdev, queue))
netif_wake_subqueue(padapter->pnetdev, queue);
@@ -177,18 +173,15 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb)
for (i = 0; i < chk_alive_num; i++) {
psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
- if (!(psta->state & _FW_LINKED))
- {
+ if (!(psta->state & _FW_LINKED)) {
DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_fw_linked);
continue;
}
/* avoid come from STA1 and send back STA1 */
- if (!memcmp(psta->hwaddr, &skb->data[6], 6)
- || !memcmp(psta->hwaddr, null_addr, 6)
- || !memcmp(psta->hwaddr, bc_addr, 6)
- )
- {
+ if (!memcmp(psta->hwaddr, &skb->data[6], 6) ||
+ !memcmp(psta->hwaddr, null_addr, 6) ||
+ !memcmp(psta->hwaddr, bc_addr, 6)) {
DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_self);
continue;
}
@@ -248,14 +241,11 @@ int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev)
|| is_broadcast_mac_addr(pkt->data)
#endif
)
- && (padapter->registrypriv.wifi_spec == 0)
- )
- {
+ && padapter->registrypriv.wifi_spec == 0) {
if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4)) {
res = rtw_mlcst2unicst(padapter, pkt);
- if (res == true) {
+ if (res == true)
goto exit;
- }
} else {
/* DBG_871X("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt); */
/* DBG_871X("!m2u); */
diff --git a/drivers/staging/rtlwifi/base.c b/drivers/staging/rtlwifi/base.c
index c947def37d31..eea00035a735 100644
--- a/drivers/staging/rtlwifi/base.c
+++ b/drivers/staging/rtlwifi/base.c
@@ -710,20 +710,20 @@ u8 rtl_mrate_idx_to_arfr_id(
ret = RATEID_IDX_BGN_40M_1SS;
else
ret = RATEID_IDX_BGN_40M_2SS;
- ; break;
+ break;
case RATR_INX_WIRELESS_N:
case RATR_INX_WIRELESS_NG:
if (rtlphy->rf_type == RF_1T1R)
ret = RATEID_IDX_GN_N1SS;
else
ret = RATEID_IDX_GN_N2SS;
- ; break;
+ break;
case RATR_INX_WIRELESS_NB:
if (rtlphy->rf_type == RF_1T1R)
ret = RATEID_IDX_BGN_20M_1SS_BN;
else
ret = RATEID_IDX_BGN_20M_2SS_BN;
- ; break;
+ break;
case RATR_INX_WIRELESS_GB:
ret = RATEID_IDX_BG;
break;
diff --git a/drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.c b/drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.c
index ffff5b062672..5b826403ed66 100644
--- a/drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.c
+++ b/drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.c
@@ -2885,12 +2885,8 @@ static void halbtc8822b2ant_action_a2dp(struct btc_coexist *btcoexist)
NORMAL_EXEC, 5);
} else {
- if (wifi_turbo)
- halbtc8822b2ant_coex_table_with_type(
- btcoexist, NORMAL_EXEC, 10);
- else
- halbtc8822b2ant_coex_table_with_type(
- btcoexist, NORMAL_EXEC, 10);
+ halbtc8822b2ant_coex_table_with_type(btcoexist,
+ NORMAL_EXEC, 10);
halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true,
109);
diff --git a/drivers/staging/rtlwifi/phydm/phydm_features.h b/drivers/staging/rtlwifi/phydm/phydm_features.h
index 37f6f0cd7235..a12361c6a1a0 100644
--- a/drivers/staging/rtlwifi/phydm/phydm_features.h
+++ b/drivers/staging/rtlwifi/phydm/phydm_features.h
@@ -24,7 +24,7 @@
*****************************************************************************/
#ifndef __PHYDM_FEATURES_H__
-#define __PHYDM_FEATURES
+#define __PHYDM_FEATURES_H__
/*phydm debyg report & tools*/
diff --git a/drivers/staging/rtlwifi/phydm/phydm_kfree.h b/drivers/staging/rtlwifi/phydm/phydm_kfree.h
index 1ee60059afc1..fa1627e3662d 100644
--- a/drivers/staging/rtlwifi/phydm/phydm_kfree.h
+++ b/drivers/staging/rtlwifi/phydm/phydm_kfree.h
@@ -24,7 +24,7 @@
*****************************************************************************/
#ifndef __PHYDMKFREE_H__
-#define __PHYDKFREE_H__
+#define __PHYDMKFREE_H__
#define KFREE_VERSION "1.0"
diff --git a/drivers/staging/rtlwifi/phydm/phydm_rainfo.c b/drivers/staging/rtlwifi/phydm/phydm_rainfo.c
index 8c08c76d4eda..e10a91aeebee 100644
--- a/drivers/staging/rtlwifi/phydm/phydm_rainfo.c
+++ b/drivers/staging/rtlwifi/phydm/phydm_rainfo.c
@@ -142,7 +142,6 @@ void odm_c2h_ra_para_report_handler(void *dm_void, u8 *cmd_buf, u8 cmd_len)
"SGI_support =", cmd_buf[7]);
ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n",
"Rate_ID =", cmd_buf[8]);
- ;
}
ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE,
"-------------------------------\n");
diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.c b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.c
index d320311213cc..e2c72af16150 100644
--- a/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.c
+++ b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.c
@@ -1311,7 +1311,7 @@ static void _phy_iq_calibrate_8822b(struct phy_dm_struct *dm, bool reset)
iqk_info->kcount = 0;
ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, "[IQK]delay 50ms!!!\n");
ODM_delay_ms(50);
- };
+ }
_iqk_backup_iqk_8822b(dm, 1);
_iqk_fill_iqk_report_8822b(dm, 0);
diff --git a/drivers/staging/rtlwifi/rtl8822be/phy.c b/drivers/staging/rtlwifi/rtl8822be/phy.c
index ef37ae98c803..6697aee9317f 100644
--- a/drivers/staging/rtlwifi/rtl8822be/phy.c
+++ b/drivers/staging/rtlwifi/rtl8822be/phy.c
@@ -1251,7 +1251,7 @@ static void _rtl8822be_get_rate_values_of_tx_power_by_rate(
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"Invalid reg_addr 0x%x in %s()\n", reg_addr, __func__);
break;
- };
+ }
}
void rtl8822be_store_tx_power_by_rate(struct ieee80211_hw *hw, u32 band,
diff --git a/drivers/staging/rtlwifi/wifi.h b/drivers/staging/rtlwifi/wifi.h
index ca0243fa2e66..a23bb1719e35 100644
--- a/drivers/staging/rtlwifi/wifi.h
+++ b/drivers/staging/rtlwifi/wifi.h
@@ -2379,16 +2379,17 @@ struct rtl_hal_usbint_cfg {
u32 rx_max_size;
/* op - rx */
- void (*usb_rx_hdl)(struct ieee80211_hw *, struct sk_buff *);
- void (*usb_rx_segregate_hdl)(struct ieee80211_hw *, struct sk_buff *,
- struct sk_buff_head *);
+ void (*usb_rx_hdl)(struct ieee80211_hw *hw, struct sk_buff *skb);
+ void (*usb_rx_segregate_hdl)(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct sk_buff_head *skbh);
/* tx */
- void (*usb_tx_cleanup)(struct ieee80211_hw *, struct sk_buff *);
- int (*usb_tx_post_hdl)(struct ieee80211_hw *, struct urb *,
- struct sk_buff *);
- struct sk_buff *(*usb_tx_aggregate_hdl)(struct ieee80211_hw *,
- struct sk_buff_head *);
+ void (*usb_tx_cleanup)(struct ieee80211_hw *hw, struct sk_buff *skb);
+ int (*usb_tx_post_hdl)(struct ieee80211_hw *hw, struct urb *urb,
+ struct sk_buff *skb);
+ struct sk_buff *(*usb_tx_aggregate_hdl)(struct ieee80211_hw *hw,
+ struct sk_buff_head *skbh);
/* endpoint mapping */
int (*usb_endpoint_mapping)(struct ieee80211_hw *hw);
@@ -2693,12 +2694,12 @@ struct rtl_btc_ops {
};
struct rtl_halmac_ops {
- int (*halmac_init_adapter)(struct rtl_priv *);
- int (*halmac_deinit_adapter)(struct rtl_priv *);
- int (*halmac_init_hal)(struct rtl_priv *);
- int (*halmac_deinit_hal)(struct rtl_priv *);
- int (*halmac_poweron)(struct rtl_priv *);
- int (*halmac_poweroff)(struct rtl_priv *);
+ int (*halmac_init_adapter)(struct rtl_priv *rtlpriv);
+ int (*halmac_deinit_adapter)(struct rtl_priv *rtlpriv);
+ int (*halmac_init_hal)(struct rtl_priv *rtlpriv);
+ int (*halmac_deinit_hal)(struct rtl_priv *rtlpriv);
+ int (*halmac_poweron)(struct rtl_priv *rtlpriv);
+ int (*halmac_poweroff)(struct rtl_priv *rtlpriv);
int (*halmac_phy_power_switch)(struct rtl_priv *rtlpriv, u8 enable);
int (*halmac_set_mac_address)(struct rtl_priv *rtlpriv, u8 hwport,
diff --git a/drivers/staging/sm750fb/ddk750_chip.c b/drivers/staging/sm750fb/ddk750_chip.c
index 313b99104398..4c1f00f551da 100644
--- a/drivers/staging/sm750fb/ddk750_chip.c
+++ b/drivers/staging/sm750fb/ddk750_chip.c
@@ -8,9 +8,9 @@
#define MHz(x) ((x) * 1000000)
-static logical_chip_type_t chip;
+static enum logical_chip_type chip;
-logical_chip_type_t sm750_get_chip_type(void)
+enum logical_chip_type sm750_get_chip_type(void)
{
return chip;
}
diff --git a/drivers/staging/sm750fb/ddk750_chip.h b/drivers/staging/sm750fb/ddk750_chip.h
index aee82fcaf669..c72aac21b675 100644
--- a/drivers/staging/sm750fb/ddk750_chip.h
+++ b/drivers/staging/sm750fb/ddk750_chip.h
@@ -24,25 +24,23 @@ static inline void poke32(u32 addr, u32 data)
}
/* This is all the chips recognized by this library */
-typedef enum _logical_chip_type_t {
+enum logical_chip_type {
SM_UNKNOWN,
SM718,
SM750,
SM750LE,
-}
-logical_chip_type_t;
+};
-typedef enum _clock_type_t {
+enum clock_type {
MXCLK_PLL,
PRIMARY_PLL,
SECONDARY_PLL,
VGA0_PLL,
VGA1_PLL,
-}
-clock_type_t;
+};
struct pll_value {
- clock_type_t clockType;
+ enum clock_type clockType;
unsigned long inputFreq; /* Input clock frequency to the PLL */
/* Use this when clockType = PANEL_PLL */
@@ -94,7 +92,7 @@ struct initchip_param {
/* More initialization parameter can be added if needed */
};
-logical_chip_type_t sm750_get_chip_type(void);
+enum logical_chip_type sm750_get_chip_type(void);
void sm750_set_chip_type(unsigned short devId, u8 revId);
unsigned int sm750_calc_pll_value(unsigned int request, struct pll_value *pll);
unsigned int sm750_format_pll_reg(struct pll_value *pPLL);
diff --git a/drivers/staging/sm750fb/ddk750_display.c b/drivers/staging/sm750fb/ddk750_display.c
index c6fd90191530..1273e7d18925 100644
--- a/drivers/staging/sm750fb/ddk750_display.c
+++ b/drivers/staging/sm750fb/ddk750_display.c
@@ -111,7 +111,7 @@ static void swPanelPowerSequence(int disp, int delay)
primary_wait_vertical_sync(delay);
}
-void ddk750_setLogicalDispOut(disp_output_t output)
+void ddk750_setLogicalDispOut(enum disp_output output)
{
unsigned int reg;
diff --git a/drivers/staging/sm750fb/ddk750_display.h b/drivers/staging/sm750fb/ddk750_display.h
index 523bbf33521c..7fd101d98199 100644
--- a/drivers/staging/sm750fb/ddk750_display.h
+++ b/drivers/staging/sm750fb/ddk750_display.h
@@ -89,7 +89,7 @@
* LCD1 means panel path TFT1 & panel path DVI (so enable DAC)
* CRT means crt path DSUB
*/
-typedef enum _disp_output_t {
+enum disp_output {
do_LCD1_PRI = PNL_2_PRI | PRI_TP_ON | PNL_SEQ_ON | DAC_ON,
do_LCD1_SEC = PNL_2_SEC | SEC_TP_ON | PNL_SEQ_ON | DAC_ON,
do_LCD2_PRI = CRT_2_PRI | PRI_TP_ON | DUAL_TFT_ON,
@@ -100,9 +100,8 @@ typedef enum _disp_output_t {
*/
do_CRT_PRI = CRT_2_PRI | PRI_TP_ON | DPMS_ON | DAC_ON,
do_CRT_SEC = CRT_2_SEC | SEC_TP_ON | DPMS_ON | DAC_ON,
-}
-disp_output_t;
+};
-void ddk750_setLogicalDispOut(disp_output_t output);
+void ddk750_setLogicalDispOut(enum disp_output output);
#endif
diff --git a/drivers/staging/sm750fb/ddk750_mode.c b/drivers/staging/sm750fb/ddk750_mode.c
index 2cdd87b78e58..7e22d093b091 100644
--- a/drivers/staging/sm750fb/ddk750_mode.c
+++ b/drivers/staging/sm750fb/ddk750_mode.c
@@ -206,7 +206,7 @@ static int programModeRegisters(struct mode_parameter *pModeParam,
return ret;
}
-int ddk750_setModeTiming(struct mode_parameter *parm, clock_type_t clock)
+int ddk750_setModeTiming(struct mode_parameter *parm, enum clock_type clock)
{
struct pll_value pll;
unsigned int uiActualPixelClk;
diff --git a/drivers/staging/sm750fb/ddk750_mode.h b/drivers/staging/sm750fb/ddk750_mode.h
index 259a9d6a4eb2..2df78a0937b2 100644
--- a/drivers/staging/sm750fb/ddk750_mode.h
+++ b/drivers/staging/sm750fb/ddk750_mode.h
@@ -33,5 +33,5 @@ struct mode_parameter {
enum spolarity clock_phase_polarity;
};
-int ddk750_setModeTiming(struct mode_parameter *parm, clock_type_t clock);
+int ddk750_setModeTiming(struct mode_parameter *parm, enum clock_type clock);
#endif
diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c
index a8c79864ee4b..edeae9d06883 100644
--- a/drivers/staging/sm750fb/sm750_hw.c
+++ b/drivers/staging/sm750fb/sm750_hw.c
@@ -185,7 +185,7 @@ int hw_sm750_output_setMode(struct lynxfb_output *output,
struct fb_fix_screeninfo *fix)
{
int ret;
- disp_output_t disp_set;
+ enum disp_output disp_set;
int channel;
ret = 0;
@@ -254,7 +254,7 @@ int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc,
int ret, fmt;
u32 reg;
struct mode_parameter modparm;
- clock_type_t clock;
+ enum clock_type clock;
struct sm750_dev *sm750_dev;
struct lynxfb_par *par;
diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c
index cf1259059776..af30b7099bed 100644
--- a/drivers/staging/speakup/main.c
+++ b/drivers/staging/speakup/main.c
@@ -417,7 +417,7 @@ static void announce_edge(struct vc_data *vc, int msg_id)
bleep(spk_y);
if ((spk_bleeps & 2) && (msg_id < edge_quiet))
synth_printf("%s\n",
- spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
+ spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
}
static void speak_char(u16 ch)
@@ -449,8 +449,9 @@ static void speak_char(u16 ch)
if (*cp == '^') {
cp++;
synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp);
- } else
+ } else {
synth_printf(" %s ", cp);
+ }
}
}
@@ -561,7 +562,7 @@ static u_long get_word(struct vc_data *vc)
get_char(vc, (u_short *)&tmp_pos + 1, &temp) > SPACE) {
tmp_pos += 2;
tmpx++;
- } else
+ } else {
while (tmpx > 0) {
ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
if ((ch == SPACE || ch == 0 ||
@@ -571,6 +572,7 @@ static u_long get_word(struct vc_data *vc)
tmp_pos -= 2;
tmpx--;
}
+ }
attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
buf[cnt++] = attr_ch;
while (tmpx < vc->vc_cols - 1) {
diff --git a/drivers/staging/speakup/speakup_decpc.c b/drivers/staging/speakup/speakup_decpc.c
index 303f393d3f2f..6649309e0342 100644
--- a/drivers/staging/speakup/speakup_decpc.c
+++ b/drivers/staging/speakup/speakup_decpc.c
@@ -349,7 +349,7 @@ static int testkernel(void)
return 0;
else if (dt_stat == 0x0dec)
pr_warn("dec_pc at 0x%x, software not loaded\n",
- speakup_info.port_tts);
+ speakup_info.port_tts);
status = -3;
oops: synth_release_region(speakup_info.port_tts, SYNTH_IO_EXTENT);
speakup_info.port_tts = 0;
@@ -412,11 +412,11 @@ static void do_catch_up(struct spk_synth *synth)
if (!in_escape)
dt_sendchar(PROCSPEECH);
spin_lock_irqsave(&speakup_info.spinlock,
- flags);
+ flags);
jiffy_delta_val = jiffy_delta->u.n.value;
delay_time_val = delay_time->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock,
- flags);
+ flags);
schedule_timeout(msecs_to_jiffies
(delay_time_val));
jiff_max = jiffies + jiffy_delta_val;
diff --git a/drivers/staging/speakup/speakup_dectlk.c b/drivers/staging/speakup/speakup_dectlk.c
index 2ea22a2eb5f9..a144f28ee1a8 100644
--- a/drivers/staging/speakup/speakup_dectlk.c
+++ b/drivers/staging/speakup/speakup_dectlk.c
@@ -262,11 +262,11 @@ static void do_catch_up(struct spk_synth *synth)
if (!in_escape)
synth->io_ops->synth_out(synth, PROCSPEECH);
spin_lock_irqsave(&speakup_info.spinlock,
- flags);
+ flags);
jiffy_delta_val = jiffy_delta->u.n.value;
delay_time_val = delay_time->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock,
- flags);
+ flags);
schedule_timeout(msecs_to_jiffies
(delay_time_val));
jiff_max = jiffies + jiffy_delta_val;
diff --git a/drivers/staging/speakup/speakup_dtlk.c b/drivers/staging/speakup/speakup_dtlk.c
index f8cb83c9b82e..dbebed0eeeec 100644
--- a/drivers/staging/speakup/speakup_dtlk.c
+++ b/drivers/staging/speakup/speakup_dtlk.c
@@ -266,7 +266,7 @@ static char synth_read_tts(void)
outb_p(ch, speakup_info.port_tts);
while (synth_readable())
cpu_relax();
- return (char) ch;
+ return (char)ch;
}
/* interrogate the DoubleTalk PC and return its settings */
@@ -287,7 +287,7 @@ static struct synth_settings *synth_interrogate(struct spk_synth *synth)
}
t = buf;
/* serial number is little endian */
- status.serial_number = t[0] + t[1]*256;
+ status.serial_number = t[0] + t[1] * 256;
t += 2;
for (i = 0; *t != '\r'; t++) {
status.rom_version[i] = *t;
@@ -323,29 +323,29 @@ static int synth_probe(struct spk_synth *synth)
if (port_forced) {
speakup_info.port_tts = port_forced;
pr_info("probe forced to %x by kernel command line\n",
- speakup_info.port_tts);
+ speakup_info.port_tts);
if ((port_forced & 0xf) != 0xf)
pr_info("warning: port base should probably end with f\n");
- if (synth_request_region(speakup_info.port_tts-1,
- SYNTH_IO_EXTENT)) {
+ if (synth_request_region(speakup_info.port_tts - 1,
+ SYNTH_IO_EXTENT)) {
pr_warn("sorry, port already reserved\n");
return -EBUSY;
}
- port_val = inw(speakup_info.port_tts-1);
- synth_lpc = speakup_info.port_tts-1;
+ port_val = inw(speakup_info.port_tts - 1);
+ synth_lpc = speakup_info.port_tts - 1;
} else {
for (i = 0; synth_portlist[i]; i++) {
if (synth_request_region(synth_portlist[i],
- SYNTH_IO_EXTENT))
+ SYNTH_IO_EXTENT))
continue;
port_val = inw(synth_portlist[i]) & 0xfbff;
if (port_val == 0x107f) {
synth_lpc = synth_portlist[i];
- speakup_info.port_tts = synth_lpc+1;
+ speakup_info.port_tts = synth_lpc + 1;
break;
}
synth_release_region(synth_portlist[i],
- SYNTH_IO_EXTENT);
+ SYNTH_IO_EXTENT);
}
}
port_val &= 0xfbff;
@@ -359,7 +359,7 @@ static int synth_probe(struct spk_synth *synth)
cpu_relax(); /* wait until it's ready */
sp = synth_interrogate(synth);
pr_info("%s: %03x-%03x, ROM ver %s, s/n %u, driver: %s\n",
- synth->long_name, synth_lpc, synth_lpc+SYNTH_IO_EXTENT - 1,
+ synth->long_name, synth_lpc, synth_lpc + SYNTH_IO_EXTENT - 1,
sp->rom_version, sp->serial_number, synth->version);
synth->alive = 1;
return 0;
@@ -369,7 +369,8 @@ static void dtlk_release(void)
{
spk_stop_serial_interrupt();
if (speakup_info.port_tts)
- synth_release_region(speakup_info.port_tts-1, SYNTH_IO_EXTENT);
+ synth_release_region(speakup_info.port_tts - 1,
+ SYNTH_IO_EXTENT);
speakup_info.port_tts = 0;
}
diff --git a/drivers/staging/speakup/speakup_dummy.c b/drivers/staging/speakup/speakup_dummy.c
index a30d60450bd5..aa0c900f79f2 100644
--- a/drivers/staging/speakup/speakup_dummy.c
+++ b/drivers/staging/speakup/speakup_dummy.c
@@ -94,7 +94,7 @@ static struct spk_synth synth_dummy = {
.probe = spk_ttyio_synth_probe,
.release = spk_ttyio_release,
.synth_immediate = spk_ttyio_synth_immediate,
- .catch_up = spk_do_catch_up,
+ .catch_up = spk_do_catch_up_unicode,
.flush = spk_synth_flush,
.is_alive = spk_synth_is_alive_restart,
.synth_adjust = NULL,
diff --git a/drivers/staging/speakup/speakup_keypc.c b/drivers/staging/speakup/speakup_keypc.c
index de76183932e1..3901734982a4 100644
--- a/drivers/staging/speakup/speakup_keypc.c
+++ b/drivers/staging/speakup/speakup_keypc.c
@@ -260,7 +260,7 @@ static int synth_probe(struct spk_synth *synth)
if (port_forced) {
synth_port = port_forced;
pr_info("probe forced to %x by kernel command line\n",
- synth_port);
+ synth_port);
if (synth_request_region(synth_port-1, SYNTH_IO_EXTENT)) {
pr_warn("sorry, port already reserved\n");
return -EBUSY;
@@ -269,7 +269,7 @@ static int synth_probe(struct spk_synth *synth)
} else {
for (i = 0; synth_portlist[i]; i++) {
if (synth_request_region(synth_portlist[i],
- SYNTH_IO_EXTENT)) {
+ SYNTH_IO_EXTENT)) {
pr_warn
("request_region: failed with 0x%x, %d\n",
synth_portlist[i], SYNTH_IO_EXTENT);
diff --git a/drivers/staging/speakup/spk_priv.h b/drivers/staging/speakup/spk_priv.h
index 00430437eb4c..7b3a16e1fa23 100644
--- a/drivers/staging/speakup/spk_priv.h
+++ b/drivers/staging/speakup/spk_priv.h
@@ -57,6 +57,7 @@ int spk_ttyio_synth_probe(struct spk_synth *synth);
const char *spk_serial_synth_immediate(struct spk_synth *synth, const char *buff);
const char *spk_ttyio_synth_immediate(struct spk_synth *synth, const char *buff);
void spk_do_catch_up(struct spk_synth *synth);
+void spk_do_catch_up_unicode(struct spk_synth *synth);
void spk_synth_flush(struct spk_synth *synth);
unsigned char spk_synth_get_index(struct spk_synth *synth);
int spk_synth_is_alive_nop(struct spk_synth *synth);
diff --git a/drivers/staging/speakup/spk_ttyio.c b/drivers/staging/speakup/spk_ttyio.c
index 5aa3ffa3772d..eac63aab8162 100644
--- a/drivers/staging/speakup/spk_ttyio.c
+++ b/drivers/staging/speakup/spk_ttyio.c
@@ -71,7 +71,7 @@ static void spk_ttyio_ldisc_close(struct tty_struct *tty)
}
static int spk_ttyio_receive_buf2(struct tty_struct *tty,
- const unsigned char *cp, char *fp, int count)
+ const unsigned char *cp, char *fp, int count)
{
struct spk_ldisc_data *ldisc_data = tty->disc_data;
@@ -110,6 +110,7 @@ static struct tty_ldisc_ops spk_ttyio_ldisc_ops = {
};
static int spk_ttyio_out(struct spk_synth *in_synth, const char ch);
+static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch);
static void spk_ttyio_send_xchar(char ch);
static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear);
static unsigned char spk_ttyio_in(void);
@@ -118,6 +119,7 @@ static void spk_ttyio_flush_buffer(void);
struct spk_io_ops spk_ttyio_ops = {
.synth_out = spk_ttyio_out,
+ .synth_out_unicode = spk_ttyio_out_unicode,
.send_xchar = spk_ttyio_send_xchar,
.tiocmset = spk_ttyio_tiocmset,
.synth_in = spk_ttyio_in,
@@ -221,6 +223,23 @@ static int spk_ttyio_out(struct spk_synth *in_synth, const char ch)
return 0;
}
+static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch)
+{
+ int ret;
+
+ if (ch < 0x80)
+ ret = spk_ttyio_out(in_synth, ch);
+ else if (ch < 0x800) {
+ ret = spk_ttyio_out(in_synth, 0xc0 | (ch >> 6));
+ ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f));
+ } else {
+ ret = spk_ttyio_out(in_synth, 0xe0 | (ch >> 12));
+ ret &= spk_ttyio_out(in_synth, 0x80 | ((ch >> 6) & 0x3f));
+ ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f));
+ }
+ return ret;
+}
+
static int check_tty(struct tty_struct *tty)
{
if (!tty) {
diff --git a/drivers/staging/speakup/spk_types.h b/drivers/staging/speakup/spk_types.h
index c50de6035a9a..4203bed90b4f 100644
--- a/drivers/staging/speakup/spk_types.h
+++ b/drivers/staging/speakup/spk_types.h
@@ -151,6 +151,7 @@ struct spk_synth;
struct spk_io_ops {
int (*synth_out)(struct spk_synth *synth, const char ch);
+ int (*synth_out_unicode)(struct spk_synth *synth, u16 ch);
void (*send_xchar)(char ch);
void (*tiocmset)(unsigned int set, unsigned int clear);
unsigned char (*synth_in)(void);
diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c
index c06e6a810999..7deeb7061018 100644
--- a/drivers/staging/speakup/synth.c
+++ b/drivers/staging/speakup/synth.c
@@ -52,9 +52,9 @@ static int do_synth_init(struct spk_synth *in_synth);
* For devices that have a "full" notification mechanism, the driver can
* adapt the loop the way they prefer.
*/
-void spk_do_catch_up(struct spk_synth *synth)
+static void _spk_do_catch_up(struct spk_synth *synth, int unicode)
{
- u_char ch;
+ u16 ch;
unsigned long flags;
unsigned long jiff_max;
struct var_t *delay_time;
@@ -63,6 +63,7 @@ void spk_do_catch_up(struct spk_synth *synth)
int jiffy_delta_val;
int delay_time_val;
int full_time_val;
+ int ret;
jiffy_delta = spk_get_var(JIFFY);
full_time = spk_get_var(FULL);
@@ -81,7 +82,8 @@ void spk_do_catch_up(struct spk_synth *synth)
synth->flush(synth);
continue;
}
- synth_buffer_skip_nonlatin1();
+ if (!unicode)
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
@@ -92,7 +94,11 @@ void spk_do_catch_up(struct spk_synth *synth)
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
if (ch == '\n')
ch = synth->procspeech;
- if (!synth->io_ops->synth_out(synth, ch)) {
+ if (unicode)
+ ret = synth->io_ops->synth_out_unicode(synth, ch);
+ else
+ ret = synth->io_ops->synth_out(synth, ch);
+ if (!ret) {
schedule_timeout(msecs_to_jiffies(full_time_val));
continue;
}
@@ -117,8 +123,19 @@ void spk_do_catch_up(struct spk_synth *synth)
}
synth->io_ops->synth_out(synth, synth->procspeech);
}
+
+void spk_do_catch_up(struct spk_synth *synth)
+{
+ _spk_do_catch_up(synth, 0);
+}
EXPORT_SYMBOL_GPL(spk_do_catch_up);
+void spk_do_catch_up_unicode(struct spk_synth *synth)
+{
+ _spk_do_catch_up(synth, 1);
+}
+EXPORT_SYMBOL_GPL(spk_do_catch_up_unicode);
+
void spk_synth_flush(struct spk_synth *synth)
{
synth->io_ops->flush_buffer();
diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c
index 9bd4412356c9..076d97eaff6f 100644
--- a/drivers/staging/typec/tcpci.c
+++ b/drivers/staging/typec/tcpci.c
@@ -21,7 +21,6 @@
struct tcpci {
struct device *dev;
- struct i2c_client *client;
struct tcpm_port *port;
@@ -30,6 +29,12 @@ struct tcpci {
bool controls_vbus;
struct tcpc_dev tcpc;
+ struct tcpci_data *data;
+};
+
+struct tcpci_chip {
+ struct tcpci *tcpci;
+ struct tcpci_data data;
};
static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
@@ -37,8 +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
return container_of(tcpc, struct tcpci, tcpc);
}
-static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
- u16 *val)
+static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val)
{
return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));
}
@@ -98,9 +102,17 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
enum typec_cc_status cc)
{
+ int ret;
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
unsigned int reg = TCPC_ROLE_CTRL_DRP;
+ /* Handle vendor drp toggling */
+ if (tcpci->data->start_drp_toggling) {
+ ret = tcpci->data->start_drp_toggling(tcpci, tcpci->data, cc);
+ if (ret < 0)
+ return ret;
+ }
+
switch (cc) {
default:
case TYPEC_CC_RP_DEF:
@@ -117,7 +129,17 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
break;
}
- return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
+ if (cc == TYPEC_CC_RD)
+ reg |= (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
+ (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT);
+ else
+ reg |= (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) |
+ (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT);
+ ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
+ if (ret < 0)
+ return ret;
+ return regmap_write(tcpci->regmap, TCPC_COMMAND,
+ TCPC_CMD_LOOK4CONNECTION);
}
static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
@@ -178,6 +200,13 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
int ret;
+ /* Handle vendor set vconn */
+ if (tcpci->data->set_vconn) {
+ ret = tcpci->data->set_vconn(tcpci, tcpci->data, enable);
+ if (ret < 0)
+ return ret;
+ }
+
ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
if (ret < 0)
@@ -323,6 +352,13 @@ static int tcpci_init(struct tcpc_dev *tcpc)
if (time_after(jiffies, timeout))
return -ETIMEDOUT;
+ /* Handle vendor init */
+ if (tcpci->data->init) {
+ ret = tcpci->data->init(tcpci, tcpci->data);
+ if (ret < 0)
+ return ret;
+ }
+
/* Clear all events */
ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
if (ret < 0)
@@ -344,9 +380,8 @@ static int tcpci_init(struct tcpc_dev *tcpc)
return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
}
-static irqreturn_t tcpci_irq(int irq, void *dev_id)
+irqreturn_t tcpci_irq(struct tcpci *tcpci)
{
- struct tcpci *tcpci = dev_id;
u16 status;
tcpci_read16(tcpci, TCPC_ALERT, &status);
@@ -412,6 +447,14 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_GPL(tcpci_irq);
+
+static irqreturn_t _tcpci_irq(int irq, void *dev_id)
+{
+ struct tcpci_chip *chip = dev_id;
+
+ return tcpci_irq(chip->tcpci);
+}
static const struct regmap_config tcpci_regmap_config = {
.reg_bits = 8,
@@ -435,22 +478,18 @@ static int tcpci_parse_config(struct tcpci *tcpci)
return 0;
}
-static int tcpci_probe(struct i2c_client *client,
- const struct i2c_device_id *i2c_id)
+struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
{
struct tcpci *tcpci;
int err;
- tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
+ tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
if (!tcpci)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
- tcpci->client = client;
- tcpci->dev = &client->dev;
- i2c_set_clientdata(client, tcpci);
- tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
- if (IS_ERR(tcpci->regmap))
- return PTR_ERR(tcpci->regmap);
+ tcpci->dev = dev;
+ tcpci->data = data;
+ tcpci->regmap = data->regmap;
tcpci->tcpc.init = tcpci_init;
tcpci->tcpc.get_vbus = tcpci_get_vbus;
@@ -467,27 +506,63 @@ static int tcpci_probe(struct i2c_client *client,
err = tcpci_parse_config(tcpci);
if (err < 0)
- return err;
+ return ERR_PTR(err);
- /* Disable chip interrupts */
- tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
+ tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
+ if (PTR_ERR_OR_ZERO(tcpci->port))
+ return ERR_CAST(tcpci->port);
- err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
- tcpci_irq,
+ return tcpci;
+}
+EXPORT_SYMBOL_GPL(tcpci_register_port);
+
+void tcpci_unregister_port(struct tcpci *tcpci)
+{
+ tcpm_unregister_port(tcpci->port);
+}
+EXPORT_SYMBOL_GPL(tcpci_unregister_port);
+
+static int tcpci_probe(struct i2c_client *client,
+ const struct i2c_device_id *i2c_id)
+{
+ struct tcpci_chip *chip;
+ int err;
+ u16 val = 0;
+
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->data.regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
+ if (IS_ERR(chip->data.regmap))
+ return PTR_ERR(chip->data.regmap);
+
+ /* Disable chip interrupts before requesting irq */
+ err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val,
+ sizeof(u16));
+ if (err < 0)
+ return err;
+
+ err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+ _tcpci_irq,
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
- dev_name(tcpci->dev), tcpci);
+ dev_name(&client->dev), chip);
if (err < 0)
return err;
- tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
- return PTR_ERR_OR_ZERO(tcpci->port);
+ chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
+ if (PTR_ERR_OR_ZERO(chip->tcpci))
+ return PTR_ERR(chip->tcpci);
+
+ i2c_set_clientdata(client, chip);
+ return 0;
}
static int tcpci_remove(struct i2c_client *client)
{
- struct tcpci *tcpci = i2c_get_clientdata(client);
+ struct tcpci_chip *chip = i2c_get_clientdata(client);
- tcpm_unregister_port(tcpci->port);
+ tcpci_unregister_port(chip->tcpci);
return 0;
}
diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h
index fdfb06cc3b86..34c865f0dcf6 100644
--- a/drivers/staging/typec/tcpci.h
+++ b/drivers/staging/typec/tcpci.h
@@ -121,4 +121,18 @@
#define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG 0x76
#define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG 0x78
+struct tcpci;
+struct tcpci_data {
+ struct regmap *regmap;
+ int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
+ int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
+ bool enable);
+ int (*start_drp_toggling)(struct tcpci *tcpci, struct tcpci_data *data,
+ enum typec_cc_status cc);
+};
+
+struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data);
+void tcpci_unregister_port(struct tcpci *tcpci);
+irqreturn_t tcpci_irq(struct tcpci *tcpci);
+
#endif /* __LINUX_USB_TCPCI_H */
diff --git a/drivers/staging/unisys/visorinput/Kconfig b/drivers/staging/unisys/visorinput/Kconfig
index 655cd62433de..a3817e0f7e5c 100644
--- a/drivers/staging/unisys/visorinput/Kconfig
+++ b/drivers/staging/unisys/visorinput/Kconfig
@@ -4,7 +4,7 @@
config UNISYS_VISORINPUT
tristate "Unisys visorinput driver"
- depends on UNISYSSPAR && UNISYS_VISORBUS && FB && INPUT
+ depends on UNISYSSPAR && UNISYS_VISORBUS && INPUT
---help---
The Unisys s-Par visorinput driver provides a virtualized system
console (keyboard and mouse) that is accessible through the
diff --git a/drivers/staging/unisys/visorinput/Makefile b/drivers/staging/unisys/visorinput/Makefile
index beedca7f0e09..6e4bfa059a1f 100644
--- a/drivers/staging/unisys/visorinput/Makefile
+++ b/drivers/staging/unisys/visorinput/Makefile
@@ -4,4 +4,3 @@
obj-$(CONFIG_UNISYS_VISORINPUT) += visorinput.o
-ccflags-y += -Idrivers/staging/unisys/include
diff --git a/drivers/staging/unisys/visorinput/ultrainputreport.h b/drivers/staging/unisys/visorinput/ultrainputreport.h
deleted file mode 100644
index 67dac430ce0c..000000000000
--- a/drivers/staging/unisys/visorinput/ultrainputreport.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2010 - 2015 UNISYS CORPORATION
- * All rights reserved.
- */
-
-#ifndef __SPAR_ULTRAINPUTREPORT_H__
-#define __SPAR_ULTRAINPUTREPORT_H__
-
-#include <linux/types.h>
-
-/* These defines identify mouse and keyboard activity which is specified by the
- * firmware to the host using the cmsimpleinput protocol. @ingroup coretypes
- */
- /* only motion; arg1=x, arg2=y */
-#define INPUTACTION_XY_MOTION 1
-/* arg1: 1=left,2=center,3=right */
-#define INPUTACTION_MOUSE_BUTTON_DOWN 2
-/* arg1: 1=left,2=center,3=right */
-#define INPUTACTION_MOUSE_BUTTON_UP 3
-/* arg1: 1=left,2=center,3=right */
-#define INPUTACTION_MOUSE_BUTTON_CLICK 4
-/* arg1: 1=left,2=center 3=right */
-#define INPUTACTION_MOUSE_BUTTON_DCLICK 5
-/* arg1: wheel rotation away from user */
-#define INPUTACTION_WHEEL_ROTATE_AWAY 6
-/* arg1: wheel rotation toward user */
-#define INPUTACTION_WHEEL_ROTATE_TOWARD 7
-/* arg1: scancode, as follows: If arg1 <= 0xff, it's a 1-byte scancode and arg1
- * is that scancode. If arg1 > 0xff, it's a 2-byte scanecode, with the 1st
- * byte in the low 8 bits, and the 2nd byte in the high 8 bits.
- * E.g., the right ALT key would appear as x'38e0'.
- */
-#define INPUTACTION_KEY_DOWN 64
-/* arg1: scancode (in same format as inputaction_keyDown) */
-#define INPUTACTION_KEY_UP 65
-/* arg1: scancode (in same format as inputaction_keyDown); MUST refer to one of
- * the locking keys, like capslock, numlock, or scrolllock.
- * arg2: 1 iff locking key should be in the LOCKED position (e.g., light is ON)
- */
-#define INPUTACTION_SET_LOCKING_KEY_STATE 66
-/* arg1: scancode (in same format as inputaction_keyDown */
-#define INPUTACTION_KEY_DOWN_UP 67
-
-struct visor_inputactivity {
- u16 action;
- u16 arg1;
- u16 arg2;
- u16 arg3;
-} __packed;
-
-struct visor_inputreport {
- u64 seq_no;
- struct visor_inputactivity activity;
-} __packed;
-
-#endif
diff --git a/drivers/staging/unisys/visorinput/visorinput.c b/drivers/staging/unisys/visorinput/visorinput.c
index d8048e48658f..9693fb559052 100644
--- a/drivers/staging/unisys/visorinput/visorinput.c
+++ b/drivers/staging/unisys/visorinput/visorinput.c
@@ -18,7 +18,36 @@
#include <linux/uuid.h>
#include <linux/visorbus.h>
-#include "ultrainputreport.h"
+/* These defines identify mouse and keyboard activity which is specified by the
+ * firmware to the host using the cmsimpleinput protocol. @ingroup coretypes
+ */
+/* only motion; arg1=x, arg2=y */
+#define INPUTACTION_XY_MOTION 1
+
+/* arg1: 1=left,2=center,3=right */
+#define INPUTACTION_MOUSE_BUTTON_DOWN 2
+#define INPUTACTION_MOUSE_BUTTON_UP 3
+#define INPUTACTION_MOUSE_BUTTON_CLICK 4
+#define INPUTACTION_MOUSE_BUTTON_DCLICK 5
+
+/* arg1: wheel rotation away from/toward user */
+#define INPUTACTION_WHEEL_ROTATE_AWAY 6
+#define INPUTACTION_WHEEL_ROTATE_TOWARD 7
+
+/* arg1: scancode, as follows: If arg1 <= 0xff, it's a 1-byte scancode and arg1
+ * is that scancode. If arg1 > 0xff, it's a 2-byte scanecode, with the 1st
+ * byte in the low 8 bits, and the 2nd byte in the high 8 bits.
+ * E.g., the right ALT key would appear as x'38e0'.
+ */
+#define INPUTACTION_KEY_DOWN 64
+#define INPUTACTION_KEY_UP 65
+#define INPUTACTION_KEY_DOWN_UP 67
+
+/* arg1: scancode (in same format as inputaction_keyDown); MUST refer to one of
+ * the locking keys, like capslock, numlock, or scrolllock.
+ * arg2: 1 iff locking key should be in the LOCKED position (e.g., light is ON)
+ */
+#define INPUTACTION_SET_LOCKING_KEY_STATE 66
/* Keyboard channel {c73416d0-b0b8-44af-b304-9d2ae99f1b3d} */
#define VISOR_KEYBOARD_CHANNEL_GUID \
@@ -32,19 +61,45 @@
0x81, 0xc3, 0x61, 0xab, 0xcd, 0xbd, 0xbd, 0x87)
#define VISOR_MOUSE_CHANNEL_GUID_STR "addf07d4-94a9-46e2-81c3-61abcdbdbd87"
-#define PIXELS_ACROSS_DEFAULT 800
-#define PIXELS_DOWN_DEFAULT 600
+#define PIXELS_ACROSS_DEFAULT 1024
+#define PIXELS_DOWN_DEFAULT 768
#define KEYCODE_TABLE_BYTES 256
-enum visorinput_device_type {
+struct visor_inputactivity {
+ u16 action;
+ u16 arg1;
+ u16 arg2;
+ u16 arg3;
+} __packed;
+
+struct visor_inputreport {
+ u64 seq_no;
+ struct visor_inputactivity activity;
+} __packed;
+
+/* header of keyboard/mouse channels */
+struct visor_input_channel_data {
+ u32 n_input_reports;
+ union {
+ struct {
+ u16 x_res;
+ u16 y_res;
+ } mouse;
+ struct {
+ u32 flags;
+ } keyboard;
+ };
+} __packed;
+
+enum visorinput_dev_type {
visorinput_keyboard,
visorinput_mouse,
};
/*
- * This is the private data that we store for each device.
- * A pointer to this struct is maintained via
- * dev_get_drvdata() / dev_set_drvdata() for each struct device.
+ * This is the private data that we store for each device. A pointer to this
+ * struct is maintained via dev_get_drvdata() / dev_set_drvdata() for each
+ * struct device.
*/
struct visorinput_devdata {
struct visor_device *dev;
@@ -215,10 +270,9 @@ static int visorinput_open(struct input_dev *visorinput_dev)
dev_dbg(&visorinput_dev->dev, "%s opened\n", __func__);
/*
- * If we're not paused, really enable interrupts.
- * Regardless of whether we are paused, set a flag indicating
- * interrupts should be enabled so when we resume, interrupts
- * will really be enabled.
+ * If we're not paused, really enable interrupts. Regardless of whether
+ * we are paused, set a flag indicating interrupts should be enabled so
+ * when we resume, interrupts will really be enabled.
*/
mutex_lock(&devdata->lock_visor_dev);
devdata->interrupts_enabled = true;
@@ -244,10 +298,9 @@ static void visorinput_close(struct input_dev *visorinput_dev)
dev_dbg(&visorinput_dev->dev, "%s closed\n", __func__);
/*
- * If we're not paused, really disable interrupts.
- * Regardless of whether we are paused, set a flag indicating
- * interrupts should be disabled so when we resume we will
- * not re-enable them.
+ * If we're not paused, really disable interrupts. Regardless of
+ * whether we are paused, set a flag indicating interrupts should be
+ * disabled so when we resume we will not re-enable them.
*/
mutex_lock(&devdata->lock_visor_dev);
devdata->interrupts_enabled = false;
@@ -260,9 +313,9 @@ out_unlock:
}
/*
- * setup_client_keyboard() initializes and returns a Linux input node that
- * we can use to deliver keyboard inputs to Linux. We of course do this when
- * we see keyboard inputs coming in on a keyboard channel.
+ * setup_client_keyboard() initializes and returns a Linux input node that we
+ * can use to deliver keyboard inputs to Linux. We of course do this when we
+ * see keyboard inputs coming in on a keyboard channel.
*/
static struct input_dev *setup_client_keyboard(void *devdata,
unsigned char *keycode_table)
@@ -306,10 +359,9 @@ static struct input_dev *setup_client_keyboard(void *devdata,
return visorinput_dev;
}
-static struct input_dev *setup_client_mouse(void *devdata)
+static struct input_dev *setup_client_mouse(void *devdata, unsigned int xres,
+ unsigned int yres)
{
- int xres, yres;
- struct fb_info *fb0;
struct input_dev *visorinput_dev = input_allocate_device();
if (!visorinput_dev)
@@ -327,14 +379,10 @@ static struct input_dev *setup_client_mouse(void *devdata)
set_bit(BTN_RIGHT, visorinput_dev->keybit);
set_bit(BTN_MIDDLE, visorinput_dev->keybit);
- if (registered_fb[0]) {
- fb0 = registered_fb[0];
- xres = fb0->var.xres_virtual;
- yres = fb0->var.yres_virtual;
- } else {
+ if (xres == 0)
xres = PIXELS_ACROSS_DEFAULT;
+ if (yres == 0)
yres = PIXELS_DOWN_DEFAULT;
- }
input_set_abs_params(visorinput_dev, ABS_X, 0, xres, 0, 0);
input_set_abs_params(visorinput_dev, ABS_Y, 0, yres, 0, 0);
@@ -347,14 +395,15 @@ static struct input_dev *setup_client_mouse(void *devdata)
return visorinput_dev;
}
-static struct visorinput_devdata *devdata_create(
- struct visor_device *dev,
- enum visorinput_device_type devtype)
+static struct visorinput_devdata *devdata_create(struct visor_device *dev,
+ enum visorinput_dev_type dtype)
{
struct visorinput_devdata *devdata = NULL;
unsigned int extra_bytes = 0;
+ unsigned int size, xres, yres, err;
+ struct visor_input_channel_data data;
- if (devtype == visorinput_keyboard)
+ if (dtype == visorinput_keyboard)
/* allocate room for devdata->keycode_table, filled in below */
extra_bytes = KEYCODE_TABLE_BYTES * 2;
devdata = kzalloc(sizeof(*devdata) + extra_bytes, GFP_KERNEL);
@@ -373,11 +422,11 @@ static struct visorinput_devdata *devdata_create(
devdata->paused = true;
/*
- * This is an input device in a client guest partition,
- * so we need to create whatever input nodes are necessary to
- * deliver our inputs to the guest OS.
+ * This is an input device in a client guest partition, so we need to
+ * create whatever input nodes are necessary to deliver our inputs to
+ * the guest OS.
*/
- switch (devtype) {
+ switch (dtype) {
case visorinput_keyboard:
devdata->keycode_table_bytes = extra_bytes;
memcpy(devdata->keycode_table, visorkbd_keycode,
@@ -390,7 +439,15 @@ static struct visorinput_devdata *devdata_create(
goto cleanups_register;
break;
case visorinput_mouse:
- devdata->visorinput_dev = setup_client_mouse(devdata);
+ size = sizeof(struct visor_input_channel_data);
+ err = visorbus_read_channel(dev, sizeof(struct channel_header),
+ &data, size);
+ if (err)
+ goto cleanups_register;
+ xres = data.mouse.x_res;
+ yres = data.mouse.y_res;
+ devdata->visorinput_dev = setup_client_mouse(devdata, xres,
+ yres);
if (!devdata->visorinput_dev)
goto cleanups_register;
break;
@@ -404,10 +461,9 @@ static struct visorinput_devdata *devdata_create(
/*
* Device struct is completely set up now, with the exception of
- * visorinput_dev being registered.
- * We need to unlock before we register the device, because this
- * can cause an on-stack call of visorinput_open(), which would
- * deadlock if we had the lock.
+ * visorinput_dev being registered. We need to unlock before we
+ * register the device, because this can cause an on-stack call of
+ * visorinput_open(), which would deadlock if we had the lock.
*/
if (input_register_device(devdata->visorinput_dev)) {
input_free_device(devdata->visorinput_dev);
@@ -416,9 +472,9 @@ static struct visorinput_devdata *devdata_create(
mutex_lock(&devdata->lock_visor_dev);
/*
- * Establish calls to visorinput_channel_interrupt() if that is
- * the desired state that we've kept track of in interrupts_enabled
- * while the device was being created.
+ * Establish calls to visorinput_channel_interrupt() if that is the
+ * desired state that we've kept track of in interrupts_enabled while
+ * the device was being created.
*/
devdata->paused = false;
if (devdata->interrupts_enabled)
@@ -437,17 +493,17 @@ err_kfree_devdata:
static int visorinput_probe(struct visor_device *dev)
{
const guid_t *guid;
- enum visorinput_device_type devtype;
+ enum visorinput_dev_type dtype;
guid = visorchannel_get_guid(dev->visorchannel);
if (guid_equal(guid, &visor_mouse_channel_guid))
- devtype = visorinput_mouse;
+ dtype = visorinput_mouse;
else if (guid_equal(guid, &visor_keyboard_channel_guid))
- devtype = visorinput_keyboard;
+ dtype = visorinput_keyboard;
else
return -ENODEV;
visorbus_disable_channel_interrupts(dev);
- if (!devdata_create(dev, devtype))
+ if (!devdata_create(dev, dtype))
return -ENOMEM;
return 0;
}
@@ -469,8 +525,8 @@ static void visorinput_remove(struct visor_device *dev)
visorbus_disable_channel_interrupts(dev);
/*
- * due to above, at this time no thread of execution will be
- * in visorinput_channel_interrupt()
+ * due to above, at this time no thread of execution will be in
+ * visorinput_channel_interrupt()
*/
dev_set_drvdata(&dev->device, NULL);
@@ -513,9 +569,8 @@ static void handle_locking_key(struct input_dev *visorinput_dev, int keycode,
}
/*
- * <scancode> is either a 1-byte scancode, or an extended 16-bit scancode
- * with 0xE0 in the low byte and the extended scancode value in the next
- * higher byte.
+ * <scancode> is either a 1-byte scancode, or an extended 16-bit scancode with
+ * 0xE0 in the low byte and the extended scancode value in the next higher byte.
*/
static int scancode_to_keycode(int scancode)
{
@@ -656,8 +711,8 @@ static int visorinput_pause(struct visor_device *dev,
visorbus_disable_channel_interrupts(dev);
/*
- * due to above, at this time no thread of execution will be
- * in visorinput_channel_interrupt()
+ * due to above, at this time no thread of execution will be in
+ * visorinput_channel_interrupt()
*/
devdata->paused = true;
complete_func(dev, 0);
@@ -687,9 +742,9 @@ static int visorinput_resume(struct visor_device *dev,
complete_func(dev, 0);
/*
- * Re-establish calls to visorinput_channel_interrupt() if that is
- * the desired state that we've kept track of in interrupts_enabled
- * while the device was paused.
+ * Re-establish calls to visorinput_channel_interrupt() if that is the
+ * desired state that we've kept track of in interrupts_enabled while
+ * the device was paused.
*/
if (devdata->interrupts_enabled)
visorbus_enable_channel_interrupts(dev);
diff --git a/drivers/staging/vc04_services/Makefile b/drivers/staging/vc04_services/Makefile
index 1ecb261e04ae..fb26b826e640 100644
--- a/drivers/staging/vc04_services/Makefile
+++ b/drivers/staging/vc04_services/Makefile
@@ -4,7 +4,6 @@ obj-$(CONFIG_BCM2835_VCHIQ) += vchiq.o
vchiq-objs := \
interface/vchiq_arm/vchiq_core.o \
interface/vchiq_arm/vchiq_arm.o \
- interface/vchiq_arm/vchiq_kern_lib.o \
interface/vchiq_arm/vchiq_2835_arm.o \
interface/vchiq_arm/vchiq_debugfs.o \
interface/vchiq_arm/vchiq_shim.o \
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
index 5f7551fbf5cf..8359cf881bef 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
@@ -209,6 +209,7 @@ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
*/
if (alsa_stream->running) {
int err;
+
err = bcm2835_audio_stop(alsa_stream);
alsa_stream->running = 0;
if (err)
@@ -278,7 +279,8 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
/* notify the vchiq that it should enter spdif passthrough mode by
* setting channels=0 (see
- * https://github.com/raspberrypi/linux/issues/528) */
+ * https://github.com/raspberrypi/linux/issues/528)
+ */
if (chip->spdif_status & IEC958_AES0_NONAUDIO)
channels = 0;
else
@@ -412,7 +414,7 @@ static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
- cmd, arg, arg ? *(unsigned *) arg : 0, ret);
+ cmd, arg, arg ? *(unsigned int *)arg : 0, ret);
return ret;
}
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
index 045d577fe4f8..0ed21dd08170 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
@@ -25,6 +25,10 @@ MODULE_PARM_DESC(enable_compat_alsa,
static void snd_devm_unregister_child(struct device *dev, void *res)
{
struct device *childdev = *(struct device **)res;
+ struct bcm2835_chip *chip = dev_get_drvdata(childdev);
+ struct snd_card *card = chip->card;
+
+ snd_card_free(card);
device_unregister(childdev);
}
@@ -50,6 +54,13 @@ static int snd_devm_add_child(struct device *dev, struct device *child)
return 0;
}
+static void snd_bcm2835_release(struct device *dev)
+{
+ struct bcm2835_chip *chip = dev_get_drvdata(dev);
+
+ kfree(chip);
+}
+
static struct device *
snd_create_device(struct device *parent,
struct device_driver *driver,
@@ -65,6 +76,7 @@ snd_create_device(struct device *parent,
device_initialize(device);
device->parent = parent;
device->driver = driver;
+ device->release = snd_bcm2835_release;
dev_set_name(device, "%s", name);
@@ -75,18 +87,19 @@ snd_create_device(struct device *parent,
return device;
}
-static int snd_bcm2835_free(struct bcm2835_chip *chip)
-{
- kfree(chip);
- return 0;
-}
-
/* component-destructor
* (see "Management of Cards and Components")
*/
static int snd_bcm2835_dev_free(struct snd_device *device)
{
- return snd_bcm2835_free(device->device_data);
+ struct bcm2835_chip *chip = device->device_data;
+ struct snd_card *card = chip->card;
+
+ /* TODO: free pcm, ctl */
+
+ snd_device_free(card, chip);
+
+ return 0;
}
/* chip-specific constructor
@@ -111,7 +124,7 @@ static int snd_bcm2835_create(struct snd_card *card,
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
if (err) {
- snd_bcm2835_free(chip);
+ kfree(chip);
return err;
}
@@ -119,31 +132,14 @@ static int snd_bcm2835_create(struct snd_card *card,
return 0;
}
-static void snd_devm_card_free(struct device *dev, void *res)
+static struct snd_card *snd_bcm2835_card_new(struct device *dev)
{
- struct snd_card *snd_card = *(struct snd_card **)res;
-
- snd_card_free(snd_card);
-}
-
-static struct snd_card *snd_devm_card_new(struct device *dev)
-{
- struct snd_card **dr;
struct snd_card *card;
int ret;
- dr = devres_alloc(snd_devm_card_free, sizeof(*dr), GFP_KERNEL);
- if (!dr)
- return ERR_PTR(-ENOMEM);
-
ret = snd_card_new(dev, -1, NULL, THIS_MODULE, 0, &card);
- if (ret) {
- devres_free(dr);
+ if (ret)
return ERR_PTR(ret);
- }
-
- *dr = card;
- devres_add(dev, dr);
return card;
}
@@ -260,7 +256,7 @@ static int snd_add_child_device(struct device *device,
return PTR_ERR(child);
}
- card = snd_devm_card_new(child);
+ card = snd_bcm2835_card_new(child);
if (IS_ERR(card)) {
dev_err(child, "Failed to create card");
return PTR_ERR(card);
@@ -302,7 +298,7 @@ static int snd_add_child_device(struct device *device,
return err;
}
- dev_set_drvdata(child, card);
+ dev_set_drvdata(child, chip);
dev_info(child, "card created with %d channels\n", numchans);
return 0;
diff --git a/drivers/staging/vc04_services/bcm2835-camera/controls.c b/drivers/staging/vc04_services/bcm2835-camera/controls.c
index 0736214e1422..cff7b1e07153 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
@@ -1270,6 +1270,7 @@ int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev,
* mismatches.
*/
int i;
+
mask = 1 << V4L2_SCENE_MODE_NONE;
for (i = 0;
i < ARRAY_SIZE(scene_configs);
diff --git a/drivers/staging/vc04_services/interface/vchi/TODO b/drivers/staging/vc04_services/interface/vchi/TODO
index df93154b1aa6..86708c7c8ec3 100644
--- a/drivers/staging/vc04_services/interface/vchi/TODO
+++ b/drivers/staging/vc04_services/interface/vchi/TODO
@@ -1,9 +1,4 @@
-1) Write a DT binding doc and get the corresponding DT node merged to
- bcm2835.
-
-This will let the driver probe when enabled.
-
-2) Import drivers using VCHI.
+1) Import drivers using VCHI.
VCHI is just a tool to let drivers talk to the firmware. Here are
some of the ones we want:
@@ -14,11 +9,6 @@ some of the ones we want:
requests to the firmware, which are transmitted across VCHIQ. vcdbg
is really useful for debugging firmware interactions.
- - bcm2835-camera (https://github.com/raspberrypi/linux/tree/rpi-4.4.y/drivers/media/platform/bcm2835)
-
- This driver will let us get images from the camera using the MMAL
- protocol over VCHI.
-
- VCSM (https://github.com/raspberrypi/linux/tree/rpi-4.4.y/drivers/char/broadcom/vc_sm)
This driver is used for talking about regions of VC memory across
@@ -26,10 +16,41 @@ some of the ones we want:
to manage these buffers as dmabufs so that we can zero-copy import
camera images into vc4 for rendering/display.
-3) Garbage-collect unused code
+2) Garbage-collect unused code
One of the reasons this driver wasn't upstreamed previously was that
there's a lot code that got built that's probably unnecessary these
days. Once we have the set of VCHI-using drivers we want in tree, we
should be able to do a sweep of the code to see what's left that's
unused.
+
+3) Make driver more portable
+
+Building this driver with arm/multi_v7_defconfig or arm64/defconfig
+leads to data corruption during the following command:
+
+ vchiq_test -f 1
+
+This should be fixed.
+
+4) Fix kernel module support
+
+Even the VPU firmware doesn't support a VCHI re-connect, the driver
+should properly handle a module unload. This also includes that all
+resouces must be freed (kthreads, debugfs entries, ...) and global
+variables avoided.
+
+5) Fix stack hog
+
+Running make checkstack shows that vchiq_dump_service_use_state() has
+an extensive stack usage. Maybe other functions are also affected.
+
+6) Cleanup logging mechanism
+
+The driver should probably be using the standard kernel logging mechanisms
+such as dev_info, dev_dbg, and friends.
+
+7) Documentation
+
+A short top-down description of this driver's architecture (function of
+kthreads, userspace, limitations) could be very helpful for reviewers.
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
index b59ef14890aa..afdd3e944f3f 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
@@ -77,7 +77,17 @@ struct vchiq_pagelist_info {
};
static void __iomem *g_regs;
-static unsigned int g_cache_line_size = sizeof(CACHE_LINE_SIZE);
+/* This value is the size of the L2 cache lines as understood by the
+ * VPU firmware, which determines the required alignment of the
+ * offsets/sizes in pagelists.
+ *
+ * Modern VPU firmware looks for a DT "cache-line-size" property in
+ * the VCHIQ node and will overwrite it with the actual L2 cache size,
+ * which the kernel must then respect. That property was rejected
+ * upstream, so we have to use the VPU firmware's compatibility value
+ * of 32.
+ */
+static unsigned int g_cache_line_size = 32;
static unsigned int g_fragments_size;
static char *g_fragments_base;
static char *g_free_fragments;
@@ -117,14 +127,6 @@ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
if (err < 0)
return err;
- err = of_property_read_u32(dev->of_node, "cache-line-size",
- &g_cache_line_size);
-
- if (err) {
- dev_err(dev, "Missing cache-line-size property\n");
- return -ENODEV;
- }
-
g_fragments_size = 2 * g_cache_line_size;
/* Allocate space for the channels in coherent memory */
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
index c2c440009cac..24d456b0a6f0 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -193,6 +193,355 @@ static const char *const ioctl_names[] = {
vchiq_static_assert(ARRAY_SIZE(ioctl_names) ==
(VCHIQ_IOC_MAX + 1));
+static VCHIQ_STATUS_T
+vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
+ unsigned int size, VCHIQ_BULK_DIR_T dir);
+
+#define VCHIQ_INIT_RETRIES 10
+VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instance_out)
+{
+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
+ VCHIQ_STATE_T *state;
+ VCHIQ_INSTANCE_T instance = NULL;
+ int i;
+
+ vchiq_log_trace(vchiq_core_log_level, "%s called", __func__);
+
+ /* VideoCore may not be ready due to boot up timing.
+ * It may never be ready if kernel and firmware are mismatched,so don't
+ * block forever.
+ */
+ for (i = 0; i < VCHIQ_INIT_RETRIES; i++) {
+ state = vchiq_get_state();
+ if (state)
+ break;
+ udelay(500);
+ }
+ if (i == VCHIQ_INIT_RETRIES) {
+ vchiq_log_error(vchiq_core_log_level,
+ "%s: videocore not initialized\n", __func__);
+ goto failed;
+ } else if (i > 0) {
+ vchiq_log_warning(vchiq_core_log_level,
+ "%s: videocore initialized after %d retries\n",
+ __func__, i);
+ }
+
+ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+ if (!instance) {
+ vchiq_log_error(vchiq_core_log_level,
+ "%s: error allocating vchiq instance\n", __func__);
+ goto failed;
+ }
+
+ instance->connected = 0;
+ instance->state = state;
+ mutex_init(&instance->bulk_waiter_list_mutex);
+ INIT_LIST_HEAD(&instance->bulk_waiter_list);
+
+ *instance_out = instance;
+
+ status = VCHIQ_SUCCESS;
+
+failed:
+ vchiq_log_trace(vchiq_core_log_level,
+ "%s(%p): returning %d", __func__, instance, status);
+
+ return status;
+}
+EXPORT_SYMBOL(vchiq_initialise);
+
+VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance)
+{
+ VCHIQ_STATUS_T status;
+ VCHIQ_STATE_T *state = instance->state;
+
+ vchiq_log_trace(vchiq_core_log_level,
+ "%s(%p) called", __func__, instance);
+
+ if (mutex_lock_killable(&state->mutex) != 0)
+ return VCHIQ_RETRY;
+
+ /* Remove all services */
+ status = vchiq_shutdown_internal(state, instance);
+
+ mutex_unlock(&state->mutex);
+
+ vchiq_log_trace(vchiq_core_log_level,
+ "%s(%p): returning %d", __func__, instance, status);
+
+ if (status == VCHIQ_SUCCESS) {
+ struct list_head *pos, *next;
+
+ list_for_each_safe(pos, next,
+ &instance->bulk_waiter_list) {
+ struct bulk_waiter_node *waiter;
+
+ waiter = list_entry(pos,
+ struct bulk_waiter_node,
+ list);
+ list_del(pos);
+ vchiq_log_info(vchiq_arm_log_level,
+ "bulk_waiter - cleaned up %pK for pid %d",
+ waiter, waiter->pid);
+ kfree(waiter);
+ }
+ kfree(instance);
+ }
+
+ return status;
+}
+EXPORT_SYMBOL(vchiq_shutdown);
+
+static int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
+{
+ return instance->connected;
+}
+
+VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
+{
+ VCHIQ_STATUS_T status;
+ VCHIQ_STATE_T *state = instance->state;
+
+ vchiq_log_trace(vchiq_core_log_level,
+ "%s(%p) called", __func__, instance);
+
+ if (mutex_lock_killable(&state->mutex) != 0) {
+ vchiq_log_trace(vchiq_core_log_level,
+ "%s: call to mutex_lock failed", __func__);
+ status = VCHIQ_RETRY;
+ goto failed;
+ }
+ status = vchiq_connect_internal(state, instance);
+
+ if (status == VCHIQ_SUCCESS)
+ instance->connected = 1;
+
+ mutex_unlock(&state->mutex);
+
+failed:
+ vchiq_log_trace(vchiq_core_log_level,
+ "%s(%p): returning %d", __func__, instance, status);
+
+ return status;
+}
+EXPORT_SYMBOL(vchiq_connect);
+
+VCHIQ_STATUS_T vchiq_add_service(
+ VCHIQ_INSTANCE_T instance,
+ const VCHIQ_SERVICE_PARAMS_T *params,
+ VCHIQ_SERVICE_HANDLE_T *phandle)
+{
+ VCHIQ_STATUS_T status;
+ VCHIQ_STATE_T *state = instance->state;
+ VCHIQ_SERVICE_T *service = NULL;
+ int srvstate;
+
+ vchiq_log_trace(vchiq_core_log_level,
+ "%s(%p) called", __func__, instance);
+
+ *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
+
+ srvstate = vchiq_is_connected(instance)
+ ? VCHIQ_SRVSTATE_LISTENING
+ : VCHIQ_SRVSTATE_HIDDEN;
+
+ service = vchiq_add_service_internal(
+ state,
+ params,
+ srvstate,
+ instance,
+ NULL);
+
+ if (service) {
+ *phandle = service->handle;
+ status = VCHIQ_SUCCESS;
+ } else
+ status = VCHIQ_ERROR;
+
+ vchiq_log_trace(vchiq_core_log_level,
+ "%s(%p): returning %d", __func__, instance, status);
+
+ return status;
+}
+EXPORT_SYMBOL(vchiq_add_service);
+
+VCHIQ_STATUS_T vchiq_open_service(
+ VCHIQ_INSTANCE_T instance,
+ const VCHIQ_SERVICE_PARAMS_T *params,
+ VCHIQ_SERVICE_HANDLE_T *phandle)
+{
+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
+ VCHIQ_STATE_T *state = instance->state;
+ VCHIQ_SERVICE_T *service = NULL;
+
+ vchiq_log_trace(vchiq_core_log_level,
+ "%s(%p) called", __func__, instance);
+
+ *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
+
+ if (!vchiq_is_connected(instance))
+ goto failed;
+
+ service = vchiq_add_service_internal(state,
+ params,
+ VCHIQ_SRVSTATE_OPENING,
+ instance,
+ NULL);
+
+ if (service) {
+ *phandle = service->handle;
+ status = vchiq_open_service_internal(service, current->pid);
+ if (status != VCHIQ_SUCCESS) {
+ vchiq_remove_service(service->handle);
+ *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
+ }
+ }
+
+failed:
+ vchiq_log_trace(vchiq_core_log_level,
+ "%s(%p): returning %d", __func__, instance, status);
+
+ return status;
+}
+EXPORT_SYMBOL(vchiq_open_service);
+
+VCHIQ_STATUS_T
+vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data,
+ unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
+{
+ VCHIQ_STATUS_T status;
+
+ switch (mode) {
+ case VCHIQ_BULK_MODE_NOCALLBACK:
+ case VCHIQ_BULK_MODE_CALLBACK:
+ status = vchiq_bulk_transfer(handle,
+ VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
+ mode, VCHIQ_BULK_TRANSMIT);
+ break;
+ case VCHIQ_BULK_MODE_BLOCKING:
+ status = vchiq_blocking_bulk_transfer(handle,
+ (void *)data, size, VCHIQ_BULK_TRANSMIT);
+ break;
+ default:
+ return VCHIQ_ERROR;
+ }
+
+ return status;
+}
+EXPORT_SYMBOL(vchiq_bulk_transmit);
+
+VCHIQ_STATUS_T
+vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
+ unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
+{
+ VCHIQ_STATUS_T status;
+
+ switch (mode) {
+ case VCHIQ_BULK_MODE_NOCALLBACK:
+ case VCHIQ_BULK_MODE_CALLBACK:
+ status = vchiq_bulk_transfer(handle,
+ VCHI_MEM_HANDLE_INVALID, data, size, userdata,
+ mode, VCHIQ_BULK_RECEIVE);
+ break;
+ case VCHIQ_BULK_MODE_BLOCKING:
+ status = vchiq_blocking_bulk_transfer(handle,
+ (void *)data, size, VCHIQ_BULK_RECEIVE);
+ break;
+ default:
+ return VCHIQ_ERROR;
+ }
+
+ return status;
+}
+EXPORT_SYMBOL(vchiq_bulk_receive);
+
+static VCHIQ_STATUS_T
+vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
+ unsigned int size, VCHIQ_BULK_DIR_T dir)
+{
+ VCHIQ_INSTANCE_T instance;
+ VCHIQ_SERVICE_T *service;
+ VCHIQ_STATUS_T status;
+ struct bulk_waiter_node *waiter = NULL;
+ struct list_head *pos;
+
+ service = find_service_by_handle(handle);
+ if (!service)
+ return VCHIQ_ERROR;
+
+ instance = service->instance;
+
+ unlock_service(service);
+
+ mutex_lock(&instance->bulk_waiter_list_mutex);
+ list_for_each(pos, &instance->bulk_waiter_list) {
+ if (list_entry(pos, struct bulk_waiter_node,
+ list)->pid == current->pid) {
+ waiter = list_entry(pos,
+ struct bulk_waiter_node,
+ list);
+ list_del(pos);
+ break;
+ }
+ }
+ mutex_unlock(&instance->bulk_waiter_list_mutex);
+
+ if (waiter) {
+ VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
+
+ if (bulk) {
+ /* This thread has an outstanding bulk transfer. */
+ if ((bulk->data != data) ||
+ (bulk->size != size)) {
+ /* This is not a retry of the previous one.
+ * Cancel the signal when the transfer
+ * completes.
+ */
+ spin_lock(&bulk_waiter_spinlock);
+ bulk->userdata = NULL;
+ spin_unlock(&bulk_waiter_spinlock);
+ }
+ }
+ }
+
+ if (!waiter) {
+ waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL);
+ if (!waiter) {
+ vchiq_log_error(vchiq_core_log_level,
+ "%s - out of memory", __func__);
+ return VCHIQ_ERROR;
+ }
+ }
+
+ status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID,
+ data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING,
+ dir);
+ if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
+ !waiter->bulk_waiter.bulk) {
+ VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
+
+ if (bulk) {
+ /* Cancel the signal when the transfer
+ * completes.
+ */
+ spin_lock(&bulk_waiter_spinlock);
+ bulk->userdata = NULL;
+ spin_unlock(&bulk_waiter_spinlock);
+ }
+ kfree(waiter);
+ } else {
+ waiter->pid = current->pid;
+ mutex_lock(&instance->bulk_waiter_list_mutex);
+ list_add(&waiter->list, &instance->bulk_waiter_list);
+ mutex_unlock(&instance->bulk_waiter_list_mutex);
+ vchiq_log_info(vchiq_arm_log_level,
+ "saved bulk_waiter %pK for pid %d",
+ waiter, current->pid);
+ }
+
+ return status;
+}
/****************************************************************************
*
* add_completion
@@ -3225,7 +3574,8 @@ static int vchiq_probe(struct platform_device *pdev)
struct rpi_firmware *fw;
int err;
- fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
+ fw_node = of_find_compatible_node(NULL, NULL,
+ "raspberrypi,bcm2835-firmware");
if (!fw_node) {
dev_err(&pdev->dev, "Missing firmware node\n");
return -ENOENT;
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_build_info.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_build_info.h
deleted file mode 100644
index df645813bdae..000000000000
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_build_info.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Copyright (c) 2010-2012 Broadcom. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-const char *vchiq_get_build_hostname(void);
-const char *vchiq_get_build_version(void);
-const char *vchiq_get_build_time(void);
-const char *vchiq_get_build_date(void);
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h
index 0e270852900d..e4109a83e628 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h
@@ -149,16 +149,6 @@ vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
size_t size);
extern void vchiq_release_message(VCHIQ_SERVICE_HANDLE_T service,
VCHIQ_HEADER_T *header);
-extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service,
- const void *data, unsigned int size, void *userdata);
-extern VCHIQ_STATUS_T vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T service,
- void *data, unsigned int size, void *userdata);
-extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit_handle(
- VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle,
- const void *offset, unsigned int size, void *userdata);
-extern VCHIQ_STATUS_T vchiq_queue_bulk_receive_handle(
- VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle,
- void *offset, unsigned int size, void *userdata);
extern VCHIQ_STATUS_T vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service,
const void *data, unsigned int size, void *userdata,
VCHIQ_BULK_MODE_T mode);
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
deleted file mode 100644
index 43c89a08bda9..000000000000
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
+++ /dev/null
@@ -1,431 +0,0 @@
-/**
- * Copyright (c) 2010-2012 Broadcom. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-
-#include "vchiq_core.h"
-#include "vchiq_arm.h"
-#include "vchiq_killable.h"
-
-/* ---- Public Variables ------------------------------------------------- */
-
-/* ---- Private Constants and Types -------------------------------------- */
-
-struct bulk_waiter_node {
- struct bulk_waiter bulk_waiter;
- int pid;
- struct list_head list;
-};
-
-struct vchiq_instance_struct {
- VCHIQ_STATE_T *state;
-
- int connected;
-
- struct list_head bulk_waiter_list;
- struct mutex bulk_waiter_list_mutex;
-};
-
-static VCHIQ_STATUS_T
-vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
- unsigned int size, VCHIQ_BULK_DIR_T dir);
-
-#define VCHIQ_INIT_RETRIES 10
-VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instance_out)
-{
- VCHIQ_STATUS_T status = VCHIQ_ERROR;
- VCHIQ_STATE_T *state;
- VCHIQ_INSTANCE_T instance = NULL;
- int i;
-
- vchiq_log_trace(vchiq_core_log_level, "%s called", __func__);
-
- /* VideoCore may not be ready due to boot up timing.
- * It may never be ready if kernel and firmware are mismatched,so don't
- * block forever.
- */
- for (i = 0; i < VCHIQ_INIT_RETRIES; i++) {
- state = vchiq_get_state();
- if (state)
- break;
- udelay(500);
- }
- if (i == VCHIQ_INIT_RETRIES) {
- vchiq_log_error(vchiq_core_log_level,
- "%s: videocore not initialized\n", __func__);
- goto failed;
- } else if (i > 0) {
- vchiq_log_warning(vchiq_core_log_level,
- "%s: videocore initialized after %d retries\n",
- __func__, i);
- }
-
- instance = kzalloc(sizeof(*instance), GFP_KERNEL);
- if (!instance) {
- vchiq_log_error(vchiq_core_log_level,
- "%s: error allocating vchiq instance\n", __func__);
- goto failed;
- }
-
- instance->connected = 0;
- instance->state = state;
- mutex_init(&instance->bulk_waiter_list_mutex);
- INIT_LIST_HEAD(&instance->bulk_waiter_list);
-
- *instance_out = instance;
-
- status = VCHIQ_SUCCESS;
-
-failed:
- vchiq_log_trace(vchiq_core_log_level,
- "%s(%p): returning %d", __func__, instance, status);
-
- return status;
-}
-EXPORT_SYMBOL(vchiq_initialise);
-
-VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance)
-{
- VCHIQ_STATUS_T status;
- VCHIQ_STATE_T *state = instance->state;
-
- vchiq_log_trace(vchiq_core_log_level,
- "%s(%p) called", __func__, instance);
-
- if (mutex_lock_killable(&state->mutex) != 0)
- return VCHIQ_RETRY;
-
- /* Remove all services */
- status = vchiq_shutdown_internal(state, instance);
-
- mutex_unlock(&state->mutex);
-
- vchiq_log_trace(vchiq_core_log_level,
- "%s(%p): returning %d", __func__, instance, status);
-
- if (status == VCHIQ_SUCCESS) {
- struct list_head *pos, *next;
-
- list_for_each_safe(pos, next,
- &instance->bulk_waiter_list) {
- struct bulk_waiter_node *waiter;
-
- waiter = list_entry(pos,
- struct bulk_waiter_node,
- list);
- list_del(pos);
- vchiq_log_info(vchiq_arm_log_level,
- "bulk_waiter - cleaned up %pK for pid %d",
- waiter, waiter->pid);
- kfree(waiter);
- }
- kfree(instance);
- }
-
- return status;
-}
-EXPORT_SYMBOL(vchiq_shutdown);
-
-static int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
-{
- return instance->connected;
-}
-
-VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
-{
- VCHIQ_STATUS_T status;
- VCHIQ_STATE_T *state = instance->state;
-
- vchiq_log_trace(vchiq_core_log_level,
- "%s(%p) called", __func__, instance);
-
- if (mutex_lock_killable(&state->mutex) != 0) {
- vchiq_log_trace(vchiq_core_log_level,
- "%s: call to mutex_lock failed", __func__);
- status = VCHIQ_RETRY;
- goto failed;
- }
- status = vchiq_connect_internal(state, instance);
-
- if (status == VCHIQ_SUCCESS)
- instance->connected = 1;
-
- mutex_unlock(&state->mutex);
-
-failed:
- vchiq_log_trace(vchiq_core_log_level,
- "%s(%p): returning %d", __func__, instance, status);
-
- return status;
-}
-EXPORT_SYMBOL(vchiq_connect);
-
-VCHIQ_STATUS_T vchiq_add_service(
- VCHIQ_INSTANCE_T instance,
- const VCHIQ_SERVICE_PARAMS_T *params,
- VCHIQ_SERVICE_HANDLE_T *phandle)
-{
- VCHIQ_STATUS_T status;
- VCHIQ_STATE_T *state = instance->state;
- VCHIQ_SERVICE_T *service = NULL;
- int srvstate;
-
- vchiq_log_trace(vchiq_core_log_level,
- "%s(%p) called", __func__, instance);
-
- *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
-
- srvstate = vchiq_is_connected(instance)
- ? VCHIQ_SRVSTATE_LISTENING
- : VCHIQ_SRVSTATE_HIDDEN;
-
- service = vchiq_add_service_internal(
- state,
- params,
- srvstate,
- instance,
- NULL);
-
- if (service) {
- *phandle = service->handle;
- status = VCHIQ_SUCCESS;
- } else
- status = VCHIQ_ERROR;
-
- vchiq_log_trace(vchiq_core_log_level,
- "%s(%p): returning %d", __func__, instance, status);
-
- return status;
-}
-EXPORT_SYMBOL(vchiq_add_service);
-
-VCHIQ_STATUS_T vchiq_open_service(
- VCHIQ_INSTANCE_T instance,
- const VCHIQ_SERVICE_PARAMS_T *params,
- VCHIQ_SERVICE_HANDLE_T *phandle)
-{
- VCHIQ_STATUS_T status = VCHIQ_ERROR;
- VCHIQ_STATE_T *state = instance->state;
- VCHIQ_SERVICE_T *service = NULL;
-
- vchiq_log_trace(vchiq_core_log_level,
- "%s(%p) called", __func__, instance);
-
- *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
-
- if (!vchiq_is_connected(instance))
- goto failed;
-
- service = vchiq_add_service_internal(state,
- params,
- VCHIQ_SRVSTATE_OPENING,
- instance,
- NULL);
-
- if (service) {
- *phandle = service->handle;
- status = vchiq_open_service_internal(service, current->pid);
- if (status != VCHIQ_SUCCESS) {
- vchiq_remove_service(service->handle);
- *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
- }
- }
-
-failed:
- vchiq_log_trace(vchiq_core_log_level,
- "%s(%p): returning %d", __func__, instance, status);
-
- return status;
-}
-EXPORT_SYMBOL(vchiq_open_service);
-
-VCHIQ_STATUS_T
-vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
- const void *data, unsigned int size, void *userdata)
-{
- return vchiq_bulk_transfer(handle,
- VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
- VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
-}
-EXPORT_SYMBOL(vchiq_queue_bulk_transmit);
-
-VCHIQ_STATUS_T
-vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
- unsigned int size, void *userdata)
-{
- return vchiq_bulk_transfer(handle,
- VCHI_MEM_HANDLE_INVALID, data, size, userdata,
- VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
-}
-EXPORT_SYMBOL(vchiq_queue_bulk_receive);
-
-VCHIQ_STATUS_T
-vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data,
- unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
-{
- VCHIQ_STATUS_T status;
-
- switch (mode) {
- case VCHIQ_BULK_MODE_NOCALLBACK:
- case VCHIQ_BULK_MODE_CALLBACK:
- status = vchiq_bulk_transfer(handle,
- VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
- mode, VCHIQ_BULK_TRANSMIT);
- break;
- case VCHIQ_BULK_MODE_BLOCKING:
- status = vchiq_blocking_bulk_transfer(handle,
- (void *)data, size, VCHIQ_BULK_TRANSMIT);
- break;
- default:
- return VCHIQ_ERROR;
- }
-
- return status;
-}
-EXPORT_SYMBOL(vchiq_bulk_transmit);
-
-VCHIQ_STATUS_T
-vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
- unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
-{
- VCHIQ_STATUS_T status;
-
- switch (mode) {
- case VCHIQ_BULK_MODE_NOCALLBACK:
- case VCHIQ_BULK_MODE_CALLBACK:
- status = vchiq_bulk_transfer(handle,
- VCHI_MEM_HANDLE_INVALID, data, size, userdata,
- mode, VCHIQ_BULK_RECEIVE);
- break;
- case VCHIQ_BULK_MODE_BLOCKING:
- status = vchiq_blocking_bulk_transfer(handle,
- (void *)data, size, VCHIQ_BULK_RECEIVE);
- break;
- default:
- return VCHIQ_ERROR;
- }
-
- return status;
-}
-EXPORT_SYMBOL(vchiq_bulk_receive);
-
-static VCHIQ_STATUS_T
-vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
- unsigned int size, VCHIQ_BULK_DIR_T dir)
-{
- VCHIQ_INSTANCE_T instance;
- VCHIQ_SERVICE_T *service;
- VCHIQ_STATUS_T status;
- struct bulk_waiter_node *waiter = NULL;
- struct list_head *pos;
-
- service = find_service_by_handle(handle);
- if (!service)
- return VCHIQ_ERROR;
-
- instance = service->instance;
-
- unlock_service(service);
-
- mutex_lock(&instance->bulk_waiter_list_mutex);
- list_for_each(pos, &instance->bulk_waiter_list) {
- if (list_entry(pos, struct bulk_waiter_node,
- list)->pid == current->pid) {
- waiter = list_entry(pos,
- struct bulk_waiter_node,
- list);
- list_del(pos);
- break;
- }
- }
- mutex_unlock(&instance->bulk_waiter_list_mutex);
-
- if (waiter) {
- VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
-
- if (bulk) {
- /* This thread has an outstanding bulk transfer. */
- if ((bulk->data != data) ||
- (bulk->size != size)) {
- /* This is not a retry of the previous one.
- * Cancel the signal when the transfer
- * completes.
- */
- spin_lock(&bulk_waiter_spinlock);
- bulk->userdata = NULL;
- spin_unlock(&bulk_waiter_spinlock);
- }
- }
- }
-
- if (!waiter) {
- waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL);
- if (!waiter) {
- vchiq_log_error(vchiq_core_log_level,
- "%s - out of memory", __func__);
- return VCHIQ_ERROR;
- }
- }
-
- status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID,
- data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING,
- dir);
- if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
- !waiter->bulk_waiter.bulk) {
- VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
-
- if (bulk) {
- /* Cancel the signal when the transfer
- * completes.
- */
- spin_lock(&bulk_waiter_spinlock);
- bulk->userdata = NULL;
- spin_unlock(&bulk_waiter_spinlock);
- }
- kfree(waiter);
- } else {
- waiter->pid = current->pid;
- mutex_lock(&instance->bulk_waiter_list_mutex);
- list_add(&waiter->list, &instance->bulk_waiter_list);
- mutex_unlock(&instance->bulk_waiter_list_mutex);
- vchiq_log_info(vchiq_arm_log_level,
- "saved bulk_waiter %pK for pid %d",
- waiter, current->pid);
- }
-
- return status;
-}
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_memdrv.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
deleted file mode 100644
index c233b866725b..000000000000
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_memdrv.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Copyright (c) 2010-2012 Broadcom. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef VCHIQ_MEMDRV_H
-#define VCHIQ_MEMDRV_H
-
-/* ---- Include Files ----------------------------------------------------- */
-
-#include <linux/kernel.h>
-#include "vchiq_if.h"
-
-/* ---- Constants and Types ---------------------------------------------- */
-
-/* ---- Variable Externs ------------------------------------------------- */
-
-/* ---- Function Prototypes ---------------------------------------------- */
-
-VCHIQ_STATUS_T vchiq_memdrv_initialise(void);
-
-VCHIQ_STATUS_T vchiq_userdrv_create_instance(
- const VCHIQ_PLATFORM_DATA_T * platform_data);
-
-VCHIQ_STATUS_T vchiq_userdrv_suspend(
- const VCHIQ_PLATFORM_DATA_T * platform_data);
-
-VCHIQ_STATUS_T vchiq_userdrv_resume(
- const VCHIQ_PLATFORM_DATA_T * platform_data);
-
-#endif
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_pagelist.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
index 926c247fd9d3..bec411061554 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
@@ -34,7 +34,6 @@
#ifndef VCHIQ_PAGELIST_H
#define VCHIQ_PAGELIST_H
-#define CACHE_LINE_SIZE 32
#define PAGELIST_WRITE 0
#define PAGELIST_READ 1
#define PAGELIST_READ_WITH_FRAGMENTS 2
@@ -49,9 +48,4 @@ typedef struct pagelist_struct {
*/
} PAGELIST_T;
-typedef struct fragments_struct {
- char headbuf[CACHE_LINE_SIZE];
- char tailbuf[CACHE_LINE_SIZE];
-} FRAGMENTS_T;
-
#endif /* VCHIQ_PAGELIST_H */
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_version.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_version.c
deleted file mode 100644
index 994b81798134..000000000000
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_version.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Copyright (c) 2010-2012 Broadcom. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "vchiq_build_info.h"
-#include <linux/broadcom/vc_debug_sym.h>
-
-VC_DEBUG_DECLARE_STRING_VAR(vchiq_build_hostname, "dc4-arm-01");
-VC_DEBUG_DECLARE_STRING_VAR(vchiq_build_version, "9245b4c35b99b3870e1f7dc598c5692b3c66a6f0 (tainted)");
-VC_DEBUG_DECLARE_STRING_VAR(vchiq_build_time, __TIME__);
-VC_DEBUG_DECLARE_STRING_VAR(vchiq_build_date, __DATE__);
-
-const char *vchiq_get_build_hostname(void)
-{
- return vchiq_build_hostname;
-}
-
-const char *vchiq_get_build_version(void)
-{
- return vchiq_build_version;
-}
-
-const char *vchiq_get_build_date(void)
-{
- return vchiq_build_date;
-}
-
-const char *vchiq_get_build_time(void)
-{
- return vchiq_build_time;
-}
diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c
index 3242dee8246f..6a33aaa1a49f 100644
--- a/drivers/staging/vme/devices/vme_user.c
+++ b/drivers/staging/vme/devices/vme_user.c
@@ -558,7 +558,7 @@ static int vme_user_probe(struct vme_dev *vdev)
vme_user_cdev->owner = THIS_MODULE;
err = cdev_add(vme_user_cdev, MKDEV(VME_MAJOR, 0), VME_DEVS);
if (err)
- goto err_char;
+ goto err_class;
/* Request slave resources and allocate buffers (128kB wide) */
for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) {
@@ -618,7 +618,7 @@ static int vme_user_probe(struct vme_dev *vdev)
if (IS_ERR(vme_user_sysfs_class)) {
dev_err(&vdev->dev, "Error creating vme_user class.\n");
err = PTR_ERR(vme_user_sysfs_class);
- goto err_class;
+ goto err_master;
}
/* Add sysfs Entries */
diff --git a/drivers/staging/vt6655/baseband.h b/drivers/staging/vt6655/baseband.h
index b8ee33dcb352..30d9e9d20a39 100644
--- a/drivers/staging/vt6655/baseband.h
+++ b/drivers/staging/vt6655/baseband.h
@@ -46,13 +46,10 @@
#define TOP_RATE_2M 0x00200000
#define TOP_RATE_1M 0x00100000
-unsigned int
-BBuGetFrameTime(
- unsigned char byPreambleType,
- unsigned char byPktType,
- unsigned int cbFrameLength,
- unsigned short wRate
-);
+unsigned int BBuGetFrameTime(unsigned char byPreambleType,
+ unsigned char byPktType,
+ unsigned int cbFrameLength,
+ unsigned short wRate);
void vnt_get_phy_field(struct vnt_private *priv, u32 frame_length,
u16 tx_rate, u8 pkt_type, struct vnt_phy_field *phy);
diff --git a/drivers/staging/vt6655/card.h b/drivers/staging/vt6655/card.h
index 487039a64587..5884fd56153e 100644
--- a/drivers/staging/vt6655/card.h
+++ b/drivers/staging/vt6655/card.h
@@ -39,19 +39,6 @@
#define CB_MAX_CHANNEL_5G 42
#define CB_MAX_CHANNEL (CB_MAX_CHANNEL_24G + CB_MAX_CHANNEL_5G)
-typedef enum _CARD_PKT_TYPE {
- PKT_TYPE_802_11_BCN,
- PKT_TYPE_802_11_MNG,
- PKT_TYPE_802_11_DATA,
- PKT_TYPE_802_11_ALL
-} CARD_PKT_TYPE, *PCARD_PKT_TYPE;
-
-typedef enum _CARD_STATUS_TYPE {
- CARD_STATUS_MEDIA_CONNECT,
- CARD_STATUS_MEDIA_DISCONNECT,
- CARD_STATUS_PMKID
-} CARD_STATUS_TYPE, *PCARD_STATUS_TYPE;
-
struct vnt_private;
void CARDvSetRSPINF(struct vnt_private *priv, u8 bb_type);
diff --git a/drivers/staging/vt6655/device_cfg.h b/drivers/staging/vt6655/device_cfg.h
index 73f904b51b96..6b41c74f7c2a 100644
--- a/drivers/staging/vt6655/device_cfg.h
+++ b/drivers/staging/vt6655/device_cfg.h
@@ -16,13 +16,6 @@
#include <linux/types.h>
-typedef
-struct _version {
- unsigned char major;
- unsigned char minor;
- unsigned char build;
-} version_t, *pversion_t;
-
#define VID_TABLE_SIZE 64
#define MCAST_TABLE_SIZE 64
#define MCAM_SIZE 32
@@ -52,8 +45,4 @@ struct _version {
#define PKT_BUF_SZ 2390
-typedef enum _chip_type {
- VT3253 = 1
-} CHIP_TYPE, *PCHIP_TYPE;
-
#endif
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index 0dc902022a91..fbc4bc68144c 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -543,7 +543,7 @@ static void device_init_rd0_ring(struct vnt_private *priv)
if (!device_alloc_rx_buf(priv, desc))
dev_err(&priv->pcid->dev, "can not alloc rx bufs\n");
- desc->next = &(priv->aRD0Ring[(i + 1) % priv->opts.rx_descs0]);
+ desc->next = &priv->aRD0Ring[(i + 1) % priv->opts.rx_descs0];
desc->next_desc = cpu_to_le32(curr + sizeof(struct vnt_rx_desc));
}
@@ -567,7 +567,7 @@ static void device_init_rd1_ring(struct vnt_private *priv)
if (!device_alloc_rx_buf(priv, desc))
dev_err(&priv->pcid->dev, "can not alloc rx bufs\n");
- desc->next = &(priv->aRD1Ring[(i+1) % priv->opts.rx_descs1]);
+ desc->next = &priv->aRD1Ring[(i+1) % priv->opts.rx_descs1];
desc->next_desc = cpu_to_le32(curr + sizeof(struct vnt_rx_desc));
}
@@ -581,7 +581,7 @@ static void device_free_rd0_ring(struct vnt_private *priv)
int i;
for (i = 0; i < priv->opts.rx_descs0; i++) {
- struct vnt_rx_desc *desc = &(priv->aRD0Ring[i]);
+ struct vnt_rx_desc *desc = &priv->aRD0Ring[i];
struct vnt_rd_info *rd_info = desc->rd_info;
dma_unmap_single(&priv->pcid->dev, rd_info->skb_dma,
diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c
index 9aa4d5262aaa..9c4a5325afc7 100644
--- a/drivers/staging/vt6655/rxtx.c
+++ b/drivers/staging/vt6655/rxtx.c
@@ -320,7 +320,6 @@ s_uGetDataDuration(
uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
else
uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
-
}
if (bNeedAck) {
@@ -490,11 +489,9 @@ s_uFillDataHead(
bool is_pspoll
)
{
-
if (!pTxDataHead)
return 0;
-
if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
if (byFBOption == AUTO_FB_NONE) {
struct vnt_tx_datahead_g *buf = pTxDataHead;
@@ -618,7 +615,6 @@ s_uFillDataHead(
return 0;
}
-
static
void
s_vFillRTSHead(
@@ -966,7 +962,7 @@ s_vGenerateTxParameter(
return;
if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
- if (pvRTS != NULL) { /* RTS_need */
+ if (pvRTS) { /* RTS_need */
/* Fill RsvTime */
struct vnt_rrv_time_rts *buf = pvRrvTime;
@@ -988,7 +984,7 @@ s_vGenerateTxParameter(
s_vFillCTSHead(pDevice, uDMAIdx, byPktType, pvCTS, cbFrameSize, bNeedACK, bDisCRC, wCurrentRate, byFBOption);
}
} else if (byPktType == PK_TYPE_11A) {
- if (pvRTS != NULL) {/* RTS_need, non PCF mode */
+ if (pvRTS) {/* RTS_need, non PCF mode */
struct vnt_rrv_time_ab *buf = pvRrvTime;
buf->rts_rrv_time = s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate);
@@ -1002,7 +998,7 @@ s_vGenerateTxParameter(
buf->rrv_time = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11A, cbFrameSize, wCurrentRate, bNeedACK);
}
} else if (byPktType == PK_TYPE_11B) {
- if (pvRTS != NULL) {/* RTS_need, non PCF mode */
+ if (pvRTS) {/* RTS_need, non PCF mode */
struct vnt_rrv_time_ab *buf = pvRrvTime;
buf->rts_rrv_time = s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate);
@@ -1080,7 +1076,6 @@ s_cbFillTxBufHead(struct vnt_private *pDevice, unsigned char byPktType,
else if (fifo_ctl & FIFOCTL_AUTO_FB_1)
byFBOption = AUTO_FB_1;
-
/* Set RrvTime/RTS/CTS Buffer */
wTxBufSize = sizeof(struct vnt_tx_fifo_head);
if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {/* 802.11g packet */
@@ -1389,7 +1384,6 @@ int vnt_generate_fifo_header(struct vnt_private *priv, u32 dma_idx,
else if (priv->byAutoFBCtrl == AUTO_FB_1)
tx_buffer_head->fifo_ctl |=
cpu_to_le16(FIFOCTL_AUTO_FB_1);
-
}
tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_NONFRAG);
diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c
index 273176386a51..5bbc56f8779e 100644
--- a/drivers/staging/vt6656/usbpipe.c
+++ b/drivers/staging/vt6656/usbpipe.c
@@ -194,9 +194,6 @@ static void vnt_submit_rx_urb_complete(struct urb *urb)
if (vnt_rx_data(priv, rcb, urb->actual_length)) {
rcb->skb = dev_alloc_skb(priv->rx_buf_sz);
if (!rcb->skb) {
- dev_dbg(&priv->usb->dev,
- "Failed to re-alloc rx skb\n");
-
rcb->in_use = false;
return;
}
diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c
index e98fc8e93011..db66b1cc80b3 100644
--- a/drivers/staging/wilc1000/coreconfigurator.c
+++ b/drivers/staging/wilc1000/coreconfigurator.c
@@ -148,19 +148,19 @@ static inline u8 get_from_ds(u8 *header)
return ((header[1] & 0x02) >> 1);
}
-static inline void get_address1(u8 *pu8msa, u8 *addr)
+static inline void get_address1(u8 *msa, u8 *addr)
{
- memcpy(addr, pu8msa + 4, 6);
+ memcpy(addr, msa + 4, 6);
}
-static inline void get_address2(u8 *pu8msa, u8 *addr)
+static inline void get_address2(u8 *msa, u8 *addr)
{
- memcpy(addr, pu8msa + 10, 6);
+ memcpy(addr, msa + 10, 6);
}
-static inline void get_address3(u8 *pu8msa, u8 *addr)
+static inline void get_address3(u8 *msa, u8 *addr)
{
- memcpy(addr, pu8msa + 16, 6);
+ memcpy(addr, msa + 16, 6);
}
static inline void get_BSSID(u8 *data, u8 *bssid)
@@ -238,30 +238,30 @@ static inline u16 get_asoc_id(u8 *data)
return asoc_id;
}
-static u8 *get_tim_elm(u8 *pu8msa, u16 rx_len, u16 tag_param_offset)
+static u8 *get_tim_elm(u8 *msa, u16 rx_len, u16 tag_param_offset)
{
u16 index;
index = tag_param_offset;
while (index < (rx_len - FCS_LEN)) {
- if (pu8msa[index] == ITIM)
- return &pu8msa[index];
- index += (IE_HDR_LEN + pu8msa[index + 1]);
+ if (msa[index] == ITIM)
+ return &msa[index];
+ index += (IE_HDR_LEN + msa[index + 1]);
}
return NULL;
}
-static u8 get_current_channel_802_11n(u8 *pu8msa, u16 rx_len)
+static u8 get_current_channel_802_11n(u8 *msa, u16 rx_len)
{
u16 index;
index = TAG_PARAM_OFFSET;
while (index < (rx_len - FCS_LEN)) {
- if (pu8msa[index] == IDSPARMS)
- return pu8msa[index + 2];
- index += pu8msa[index + 1] + IE_HDR_LEN;
+ if (msa[index] == IDSPARMS)
+ return msa[index + 2];
+ index += msa[index + 1] + IE_HDR_LEN;
}
return 0;
@@ -320,8 +320,8 @@ s32 wilc_parse_network_info(u8 *msg_buffer,
get_ssid(msa, network_info->ssid, &network_info->ssid_len);
get_BSSID(msa, network_info->bssid);
- network_info->ch = get_current_channel_802_11n(msa,
- rx_len + FCS_LEN);
+ network_info->ch = get_current_channel_802_11n(msa, rx_len
+ + FCS_LEN);
index = MAC_HDR_LEN + TIME_STAMP_LEN;
diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c
index 358354b3a2b4..6b5300ca44a6 100644
--- a/drivers/staging/wilc1000/host_interface.c
+++ b/drivers/staging/wilc1000/host_interface.c
@@ -254,20 +254,13 @@ static u32 inactive_time;
static u8 del_beacon;
static u32 clients_count;
-static u8 *join_req;
-static u8 *info_element;
-static u8 mode_11i;
-static u8 auth_type;
-static u32 join_req_size;
-static u32 info_element_size;
-static struct wilc_vif *join_req_vif;
#define REAL_JOIN_REQ 0
#define FLUSHED_JOIN_REQ 1
#define FLUSHED_BYTE_POS 79
-static void *host_int_ParseJoinBssParam(struct network_info *ptstrNetworkInfo);
+static void *host_int_parse_join_bss_param(struct network_info *info);
static int host_int_get_ipaddress(struct wilc_vif *vif, u8 *ip_addr, u8 idx);
-static s32 Handle_ScanDone(struct wilc_vif *vif, enum scan_event enuEvent);
+static s32 handle_scan_done(struct wilc_vif *vif, enum scan_event evt);
static void host_if_work(struct work_struct *work);
/*!
@@ -469,8 +462,7 @@ static void handle_get_mac_address(struct wilc_vif *vif,
complete(&hif_wait_response);
}
-static void handle_cfg_param(struct wilc_vif *vif,
- struct cfg_param_attr *cfg_param_attr)
+static void handle_cfg_param(struct wilc_vif *vif, struct cfg_param_attr *param)
{
int ret = 0;
struct wid wid_list[32];
@@ -479,12 +471,12 @@ static void handle_cfg_param(struct wilc_vif *vif,
mutex_lock(&hif_drv->cfg_values_lock);
- if (cfg_param_attr->flag & BSS_TYPE) {
- u8 bss_type = cfg_param_attr->bss_type;
+ if (param->flag & BSS_TYPE) {
+ u8 bss_type = param->bss_type;
if (bss_type < 6) {
wid_list[i].id = WID_BSS_TYPE;
- wid_list[i].val = (s8 *)&bss_type;
+ wid_list[i].val = (s8 *)&param->bss_type;
wid_list[i].type = WID_CHAR;
wid_list[i].size = sizeof(char);
hif_drv->cfg_values.bss_type = bss_type;
@@ -494,228 +486,244 @@ static void handle_cfg_param(struct wilc_vif *vif,
}
i++;
}
- if (cfg_param_attr->flag & AUTH_TYPE) {
- if (cfg_param_attr->auth_type == 1 ||
- cfg_param_attr->auth_type == 2 ||
- cfg_param_attr->auth_type == 5) {
+ if (param->flag & AUTH_TYPE) {
+ u8 auth_type = param->auth_type;
+
+ if (auth_type == 1 || auth_type == 2 || auth_type == 5) {
wid_list[i].id = WID_AUTH_TYPE;
- wid_list[i].val = (s8 *)&cfg_param_attr->auth_type;
+ wid_list[i].val = (s8 *)&param->auth_type;
wid_list[i].type = WID_CHAR;
wid_list[i].size = sizeof(char);
- hif_drv->cfg_values.auth_type = (u8)cfg_param_attr->auth_type;
+ hif_drv->cfg_values.auth_type = auth_type;
} else {
netdev_err(vif->ndev, "Impossible value\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & AUTHEN_TIMEOUT) {
- if (cfg_param_attr->auth_timeout > 0 &&
- cfg_param_attr->auth_timeout < 65536) {
+ if (param->flag & AUTHEN_TIMEOUT) {
+ if (param->auth_timeout > 0) {
wid_list[i].id = WID_AUTH_TIMEOUT;
- wid_list[i].val = (s8 *)&cfg_param_attr->auth_timeout;
+ wid_list[i].val = (s8 *)&param->auth_timeout;
wid_list[i].type = WID_SHORT;
wid_list[i].size = sizeof(u16);
- hif_drv->cfg_values.auth_timeout = cfg_param_attr->auth_timeout;
+ hif_drv->cfg_values.auth_timeout = param->auth_timeout;
} else {
netdev_err(vif->ndev, "Range(1 ~ 65535) over\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & POWER_MANAGEMENT) {
- if (cfg_param_attr->power_mgmt_mode < 5) {
+ if (param->flag & POWER_MANAGEMENT) {
+ u8 pm_mode = param->power_mgmt_mode;
+
+ if (pm_mode < 5) {
wid_list[i].id = WID_POWER_MANAGEMENT;
- wid_list[i].val = (s8 *)&cfg_param_attr->power_mgmt_mode;
+ wid_list[i].val = (s8 *)&param->power_mgmt_mode;
wid_list[i].type = WID_CHAR;
wid_list[i].size = sizeof(char);
- hif_drv->cfg_values.power_mgmt_mode = (u8)cfg_param_attr->power_mgmt_mode;
+ hif_drv->cfg_values.power_mgmt_mode = pm_mode;
} else {
netdev_err(vif->ndev, "Invalid power mode\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & RETRY_SHORT) {
- if (cfg_param_attr->short_retry_limit > 0 &&
- cfg_param_attr->short_retry_limit < 256) {
+ if (param->flag & RETRY_SHORT) {
+ u16 retry_limit = param->short_retry_limit;
+
+ if (retry_limit > 0 && retry_limit < 256) {
wid_list[i].id = WID_SHORT_RETRY_LIMIT;
- wid_list[i].val = (s8 *)&cfg_param_attr->short_retry_limit;
+ wid_list[i].val = (s8 *)&param->short_retry_limit;
wid_list[i].type = WID_SHORT;
wid_list[i].size = sizeof(u16);
- hif_drv->cfg_values.short_retry_limit = cfg_param_attr->short_retry_limit;
+ hif_drv->cfg_values.short_retry_limit = retry_limit;
} else {
netdev_err(vif->ndev, "Range(1~256) over\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & RETRY_LONG) {
- if (cfg_param_attr->long_retry_limit > 0 &&
- cfg_param_attr->long_retry_limit < 256) {
+ if (param->flag & RETRY_LONG) {
+ u16 limit = param->long_retry_limit;
+
+ if (limit > 0 && limit < 256) {
wid_list[i].id = WID_LONG_RETRY_LIMIT;
- wid_list[i].val = (s8 *)&cfg_param_attr->long_retry_limit;
+ wid_list[i].val = (s8 *)&param->long_retry_limit;
wid_list[i].type = WID_SHORT;
wid_list[i].size = sizeof(u16);
- hif_drv->cfg_values.long_retry_limit = cfg_param_attr->long_retry_limit;
+ hif_drv->cfg_values.long_retry_limit = limit;
} else {
netdev_err(vif->ndev, "Range(1~256) over\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & FRAG_THRESHOLD) {
- if (cfg_param_attr->frag_threshold > 255 &&
- cfg_param_attr->frag_threshold < 7937) {
+ if (param->flag & FRAG_THRESHOLD) {
+ u16 frag_th = param->frag_threshold;
+
+ if (frag_th > 255 && frag_th < 7937) {
wid_list[i].id = WID_FRAG_THRESHOLD;
- wid_list[i].val = (s8 *)&cfg_param_attr->frag_threshold;
+ wid_list[i].val = (s8 *)&param->frag_threshold;
wid_list[i].type = WID_SHORT;
wid_list[i].size = sizeof(u16);
- hif_drv->cfg_values.frag_threshold = cfg_param_attr->frag_threshold;
+ hif_drv->cfg_values.frag_threshold = frag_th;
} else {
netdev_err(vif->ndev, "Threshold Range fail\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & RTS_THRESHOLD) {
- if (cfg_param_attr->rts_threshold > 255 &&
- cfg_param_attr->rts_threshold < 65536) {
+ if (param->flag & RTS_THRESHOLD) {
+ u16 rts_th = param->rts_threshold;
+
+ if (rts_th > 255) {
wid_list[i].id = WID_RTS_THRESHOLD;
- wid_list[i].val = (s8 *)&cfg_param_attr->rts_threshold;
+ wid_list[i].val = (s8 *)&param->rts_threshold;
wid_list[i].type = WID_SHORT;
wid_list[i].size = sizeof(u16);
- hif_drv->cfg_values.rts_threshold = cfg_param_attr->rts_threshold;
+ hif_drv->cfg_values.rts_threshold = rts_th;
} else {
netdev_err(vif->ndev, "Threshold Range fail\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & PREAMBLE) {
- if (cfg_param_attr->preamble_type < 3) {
+ if (param->flag & PREAMBLE) {
+ u16 preamble_type = param->preamble_type;
+
+ if (param->preamble_type < 3) {
wid_list[i].id = WID_PREAMBLE;
- wid_list[i].val = (s8 *)&cfg_param_attr->preamble_type;
+ wid_list[i].val = (s8 *)&param->preamble_type;
wid_list[i].type = WID_CHAR;
wid_list[i].size = sizeof(char);
- hif_drv->cfg_values.preamble_type = cfg_param_attr->preamble_type;
+ hif_drv->cfg_values.preamble_type = preamble_type;
} else {
netdev_err(vif->ndev, "Preamle Range(0~2) over\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & SHORT_SLOT_ALLOWED) {
- if (cfg_param_attr->short_slot_allowed < 2) {
+ if (param->flag & SHORT_SLOT_ALLOWED) {
+ u8 slot_allowed = param->short_slot_allowed;
+
+ if (slot_allowed < 2) {
wid_list[i].id = WID_SHORT_SLOT_ALLOWED;
- wid_list[i].val = (s8 *)&cfg_param_attr->short_slot_allowed;
+ wid_list[i].val = (s8 *)&param->short_slot_allowed;
wid_list[i].type = WID_CHAR;
wid_list[i].size = sizeof(char);
- hif_drv->cfg_values.short_slot_allowed = (u8)cfg_param_attr->short_slot_allowed;
+ hif_drv->cfg_values.short_slot_allowed = slot_allowed;
} else {
netdev_err(vif->ndev, "Short slot(2) over\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & TXOP_PROT_DISABLE) {
- if (cfg_param_attr->txop_prot_disabled < 2) {
+ if (param->flag & TXOP_PROT_DISABLE) {
+ u8 prot_disabled = param->txop_prot_disabled;
+
+ if (param->txop_prot_disabled < 2) {
wid_list[i].id = WID_11N_TXOP_PROT_DISABLE;
- wid_list[i].val = (s8 *)&cfg_param_attr->txop_prot_disabled;
+ wid_list[i].val = (s8 *)&param->txop_prot_disabled;
wid_list[i].type = WID_CHAR;
wid_list[i].size = sizeof(char);
- hif_drv->cfg_values.txop_prot_disabled = (u8)cfg_param_attr->txop_prot_disabled;
+ hif_drv->cfg_values.txop_prot_disabled = prot_disabled;
} else {
netdev_err(vif->ndev, "TXOP prot disable\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & BEACON_INTERVAL) {
- if (cfg_param_attr->beacon_interval > 0 &&
- cfg_param_attr->beacon_interval < 65536) {
+ if (param->flag & BEACON_INTERVAL) {
+ u16 beacon_interval = param->beacon_interval;
+
+ if (beacon_interval > 0) {
wid_list[i].id = WID_BEACON_INTERVAL;
- wid_list[i].val = (s8 *)&cfg_param_attr->beacon_interval;
+ wid_list[i].val = (s8 *)&param->beacon_interval;
wid_list[i].type = WID_SHORT;
wid_list[i].size = sizeof(u16);
- hif_drv->cfg_values.beacon_interval = cfg_param_attr->beacon_interval;
+ hif_drv->cfg_values.beacon_interval = beacon_interval;
} else {
netdev_err(vif->ndev, "Beacon interval(1~65535)fail\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & DTIM_PERIOD) {
- if (cfg_param_attr->dtim_period > 0 &&
- cfg_param_attr->dtim_period < 256) {
+ if (param->flag & DTIM_PERIOD) {
+ if (param->dtim_period > 0 && param->dtim_period < 256) {
wid_list[i].id = WID_DTIM_PERIOD;
- wid_list[i].val = (s8 *)&cfg_param_attr->dtim_period;
+ wid_list[i].val = (s8 *)&param->dtim_period;
wid_list[i].type = WID_CHAR;
wid_list[i].size = sizeof(char);
- hif_drv->cfg_values.dtim_period = cfg_param_attr->dtim_period;
+ hif_drv->cfg_values.dtim_period = param->dtim_period;
} else {
netdev_err(vif->ndev, "DTIM range(1~255) fail\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & SITE_SURVEY) {
- if (cfg_param_attr->site_survey_enabled < 3) {
+ if (param->flag & SITE_SURVEY) {
+ enum SITESURVEY enabled = param->site_survey_enabled;
+
+ if (enabled < 3) {
wid_list[i].id = WID_SITE_SURVEY;
- wid_list[i].val = (s8 *)&cfg_param_attr->site_survey_enabled;
+ wid_list[i].val = (s8 *)&param->site_survey_enabled;
wid_list[i].type = WID_CHAR;
wid_list[i].size = sizeof(char);
- hif_drv->cfg_values.site_survey_enabled = (u8)cfg_param_attr->site_survey_enabled;
+ hif_drv->cfg_values.site_survey_enabled = enabled;
} else {
netdev_err(vif->ndev, "Site survey disable\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & SITE_SURVEY_SCAN_TIME) {
- if (cfg_param_attr->site_survey_scan_time > 0 &&
- cfg_param_attr->site_survey_scan_time < 65536) {
+ if (param->flag & SITE_SURVEY_SCAN_TIME) {
+ u16 scan_time = param->site_survey_scan_time;
+
+ if (scan_time > 0) {
wid_list[i].id = WID_SITE_SURVEY_SCAN_TIME;
- wid_list[i].val = (s8 *)&cfg_param_attr->site_survey_scan_time;
+ wid_list[i].val = (s8 *)&param->site_survey_scan_time;
wid_list[i].type = WID_SHORT;
wid_list[i].size = sizeof(u16);
- hif_drv->cfg_values.site_survey_scan_time = cfg_param_attr->site_survey_scan_time;
+ hif_drv->cfg_values.site_survey_scan_time = scan_time;
} else {
netdev_err(vif->ndev, "Site scan time(1~65535) over\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & ACTIVE_SCANTIME) {
- if (cfg_param_attr->active_scan_time > 0 &&
- cfg_param_attr->active_scan_time < 65536) {
+ if (param->flag & ACTIVE_SCANTIME) {
+ u16 active_scan_time = param->active_scan_time;
+
+ if (active_scan_time > 0) {
wid_list[i].id = WID_ACTIVE_SCAN_TIME;
- wid_list[i].val = (s8 *)&cfg_param_attr->active_scan_time;
+ wid_list[i].val = (s8 *)&param->active_scan_time;
wid_list[i].type = WID_SHORT;
wid_list[i].size = sizeof(u16);
- hif_drv->cfg_values.active_scan_time = cfg_param_attr->active_scan_time;
+ hif_drv->cfg_values.active_scan_time = active_scan_time;
} else {
netdev_err(vif->ndev, "Active time(1~65535) over\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & PASSIVE_SCANTIME) {
- if (cfg_param_attr->passive_scan_time > 0 &&
- cfg_param_attr->passive_scan_time < 65536) {
+ if (param->flag & PASSIVE_SCANTIME) {
+ u16 time = param->passive_scan_time;
+
+ if (time > 0) {
wid_list[i].id = WID_PASSIVE_SCAN_TIME;
- wid_list[i].val = (s8 *)&cfg_param_attr->passive_scan_time;
+ wid_list[i].val = (s8 *)&param->passive_scan_time;
wid_list[i].type = WID_SHORT;
wid_list[i].size = sizeof(u16);
- hif_drv->cfg_values.passive_scan_time = cfg_param_attr->passive_scan_time;
+ hif_drv->cfg_values.passive_scan_time = time;
} else {
netdev_err(vif->ndev, "Passive time(1~65535) over\n");
goto unlock;
}
i++;
}
- if (cfg_param_attr->flag & CURRENT_TX_RATE) {
- enum CURRENT_TXRATE curr_tx_rate = cfg_param_attr->curr_tx_rate;
+ if (param->flag & CURRENT_TX_RATE) {
+ enum CURRENT_TXRATE curr_tx_rate = param->curr_tx_rate;
if (curr_tx_rate == AUTORATE || curr_tx_rate == MBPS_1 ||
curr_tx_rate == MBPS_2 || curr_tx_rate == MBPS_5_5 ||
@@ -754,8 +762,9 @@ static s32 handle_scan(struct wilc_vif *vif, struct scan_attr *scan_info)
u32 i;
u8 *buffer;
u8 valuesize = 0;
- u8 *pu8HdnNtwrksWidVal = NULL;
+ u8 *hdn_ntwk_wid_val = NULL;
struct host_if_drv *hif_drv = vif->hif_drv;
+ struct hidden_network *hidden_net = &scan_info->hidden_network;
hif_drv->usr_scan_req.scan_result = scan_info->result;
hif_drv->usr_scan_req.arg = scan_info->arg;
@@ -764,13 +773,13 @@ static s32 handle_scan(struct wilc_vif *vif, struct scan_attr *scan_info)
hif_drv->hif_state < HOST_IF_CONNECTED) {
netdev_err(vif->ndev, "Already scan\n");
result = -EBUSY;
- goto ERRORHANDLER;
+ goto error;
}
if (wilc_optaining_ip || wilc_connecting) {
netdev_err(vif->ndev, "Don't do obss scan\n");
result = -EBUSY;
- goto ERRORHANDLER;
+ goto error;
}
hif_drv->usr_scan_req.rcvd_ch_cnt = 0;
@@ -778,19 +787,20 @@ static s32 handle_scan(struct wilc_vif *vif, struct scan_attr *scan_info)
wid_list[index].id = (u16)WID_SSID_PROBE_REQ;
wid_list[index].type = WID_STR;
- for (i = 0; i < scan_info->hidden_network.n_ssids; i++)
- valuesize += ((scan_info->hidden_network.net_info[i].ssid_len) + 1);
- pu8HdnNtwrksWidVal = kmalloc(valuesize + 1, GFP_KERNEL);
- wid_list[index].val = pu8HdnNtwrksWidVal;
+ for (i = 0; i < hidden_net->n_ssids; i++)
+ valuesize += ((hidden_net->net_info[i].ssid_len) + 1);
+ hdn_ntwk_wid_val = kmalloc(valuesize + 1, GFP_KERNEL);
+ wid_list[index].val = hdn_ntwk_wid_val;
if (wid_list[index].val) {
buffer = wid_list[index].val;
- *buffer++ = scan_info->hidden_network.n_ssids;
+ *buffer++ = hidden_net->n_ssids;
- for (i = 0; i < scan_info->hidden_network.n_ssids; i++) {
- *buffer++ = scan_info->hidden_network.net_info[i].ssid_len;
- memcpy(buffer, scan_info->hidden_network.net_info[i].ssid, scan_info->hidden_network.net_info[i].ssid_len);
- buffer += scan_info->hidden_network.net_info[i].ssid_len;
+ for (i = 0; i < hidden_net->n_ssids; i++) {
+ *buffer++ = hidden_net->net_info[i].ssid_len;
+ memcpy(buffer, hidden_net->net_info[i].ssid,
+ hidden_net->net_info[i].ssid_len);
+ buffer += hidden_net->net_info[i].ssid_len;
}
wid_list[index].size = (s32)(valuesize + 1);
@@ -818,7 +828,7 @@ static s32 handle_scan(struct wilc_vif *vif, struct scan_attr *scan_info)
for (i = 0; i < scan_info->ch_list_len; i++) {
if (scan_info->ch_freq_list[i] > 0)
- scan_info->ch_freq_list[i] = scan_info->ch_freq_list[i] - 1;
+ scan_info->ch_freq_list[i] -= 1;
}
}
@@ -844,10 +854,10 @@ static s32 handle_scan(struct wilc_vif *vif, struct scan_attr *scan_info)
if (result)
netdev_err(vif->ndev, "Failed to send scan parameters\n");
-ERRORHANDLER:
+error:
if (result) {
del_timer(&hif_drv->scan_timer);
- Handle_ScanDone(vif, SCAN_EVENT_ABORTED);
+ handle_scan_done(vif, SCAN_EVENT_ABORTED);
}
kfree(scan_info->ch_freq_list);
@@ -858,24 +868,24 @@ ERRORHANDLER:
kfree(scan_info->hidden_network.net_info);
scan_info->hidden_network.net_info = NULL;
- kfree(pu8HdnNtwrksWidVal);
+ kfree(hdn_ntwk_wid_val);
return result;
}
-static s32 Handle_ScanDone(struct wilc_vif *vif,
- enum scan_event enuEvent)
+static s32 handle_scan_done(struct wilc_vif *vif, enum scan_event evt)
{
s32 result = 0;
- u8 u8abort_running_scan;
+ u8 abort_running_scan;
struct wid wid;
struct host_if_drv *hif_drv = vif->hif_drv;
+ struct user_scan_req *scan_req;
- if (enuEvent == SCAN_EVENT_ABORTED) {
- u8abort_running_scan = 1;
+ if (evt == SCAN_EVENT_ABORTED) {
+ abort_running_scan = 1;
wid.id = (u16)WID_ABORT_RUNNING_SCAN;
wid.type = WID_CHAR;
- wid.val = (s8 *)&u8abort_running_scan;
+ wid.val = (s8 *)&abort_running_scan;
wid.size = sizeof(char);
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
@@ -892,285 +902,280 @@ static s32 Handle_ScanDone(struct wilc_vif *vif,
return result;
}
- if (hif_drv->usr_scan_req.scan_result) {
- hif_drv->usr_scan_req.scan_result(enuEvent, NULL,
- hif_drv->usr_scan_req.arg, NULL);
- hif_drv->usr_scan_req.scan_result = NULL;
+ scan_req = &hif_drv->usr_scan_req;
+ if (scan_req->scan_result) {
+ scan_req->scan_result(evt, NULL, scan_req->arg, NULL);
+ scan_req->scan_result = NULL;
}
return result;
}
u8 wilc_connected_ssid[6] = {0};
-static s32 Handle_Connect(struct wilc_vif *vif,
- struct connect_attr *pstrHostIFconnectAttr)
+static s32 handle_connect(struct wilc_vif *vif,
+ struct connect_attr *conn_attr)
{
s32 result = 0;
- struct wid strWIDList[8];
- u32 u32WidsCount = 0, dummyval = 0;
- u8 *pu8CurrByte = NULL;
- struct join_bss_param *ptstrJoinBssParam;
+ struct wid wid_list[8];
+ u32 wid_cnt = 0, dummyval = 0;
+ u8 *cur_byte = NULL;
+ struct join_bss_param *bss_param;
struct host_if_drv *hif_drv = vif->hif_drv;
- if (memcmp(pstrHostIFconnectAttr->bssid, wilc_connected_ssid, ETH_ALEN) == 0) {
+ if (memcmp(conn_attr->bssid, wilc_connected_ssid, ETH_ALEN) == 0) {
result = 0;
netdev_err(vif->ndev, "Discard connect request\n");
return result;
}
- ptstrJoinBssParam = pstrHostIFconnectAttr->params;
- if (!ptstrJoinBssParam) {
+ bss_param = conn_attr->params;
+ if (!bss_param) {
netdev_err(vif->ndev, "Required BSSID not found\n");
result = -ENOENT;
- goto ERRORHANDLER;
+ goto error;
}
- if (pstrHostIFconnectAttr->bssid) {
- hif_drv->usr_conn_req.bssid = kmalloc(6, GFP_KERNEL);
- memcpy(hif_drv->usr_conn_req.bssid, pstrHostIFconnectAttr->bssid, 6);
+ if (conn_attr->bssid) {
+ hif_drv->usr_conn_req.bssid = kmemdup(conn_attr->bssid, 6,
+ GFP_KERNEL);
+ if (!hif_drv->usr_conn_req.bssid) {
+ result = -ENOMEM;
+ goto error;
+ }
}
- hif_drv->usr_conn_req.ssid_len = pstrHostIFconnectAttr->ssid_len;
- if (pstrHostIFconnectAttr->ssid) {
- hif_drv->usr_conn_req.ssid = kmalloc(pstrHostIFconnectAttr->ssid_len + 1, GFP_KERNEL);
+ hif_drv->usr_conn_req.ssid_len = conn_attr->ssid_len;
+ if (conn_attr->ssid) {
+ hif_drv->usr_conn_req.ssid = kmalloc(conn_attr->ssid_len + 1,
+ GFP_KERNEL);
+ if (!hif_drv->usr_conn_req.ssid) {
+ result = -ENOMEM;
+ goto error;
+ }
memcpy(hif_drv->usr_conn_req.ssid,
- pstrHostIFconnectAttr->ssid,
- pstrHostIFconnectAttr->ssid_len);
- hif_drv->usr_conn_req.ssid[pstrHostIFconnectAttr->ssid_len] = '\0';
- }
-
- hif_drv->usr_conn_req.ies_len = pstrHostIFconnectAttr->ies_len;
- if (pstrHostIFconnectAttr->ies) {
- hif_drv->usr_conn_req.ies = kmalloc(pstrHostIFconnectAttr->ies_len, GFP_KERNEL);
- memcpy(hif_drv->usr_conn_req.ies,
- pstrHostIFconnectAttr->ies,
- pstrHostIFconnectAttr->ies_len);
- }
-
- hif_drv->usr_conn_req.security = pstrHostIFconnectAttr->security;
- hif_drv->usr_conn_req.auth_type = pstrHostIFconnectAttr->auth_type;
- hif_drv->usr_conn_req.conn_result = pstrHostIFconnectAttr->result;
- hif_drv->usr_conn_req.arg = pstrHostIFconnectAttr->arg;
-
- strWIDList[u32WidsCount].id = WID_SUCCESS_FRAME_COUNT;
- strWIDList[u32WidsCount].type = WID_INT;
- strWIDList[u32WidsCount].size = sizeof(u32);
- strWIDList[u32WidsCount].val = (s8 *)(&(dummyval));
- u32WidsCount++;
-
- strWIDList[u32WidsCount].id = WID_RECEIVED_FRAGMENT_COUNT;
- strWIDList[u32WidsCount].type = WID_INT;
- strWIDList[u32WidsCount].size = sizeof(u32);
- strWIDList[u32WidsCount].val = (s8 *)(&(dummyval));
- u32WidsCount++;
-
- strWIDList[u32WidsCount].id = WID_FAILED_COUNT;
- strWIDList[u32WidsCount].type = WID_INT;
- strWIDList[u32WidsCount].size = sizeof(u32);
- strWIDList[u32WidsCount].val = (s8 *)(&(dummyval));
- u32WidsCount++;
+ conn_attr->ssid,
+ conn_attr->ssid_len);
+ hif_drv->usr_conn_req.ssid[conn_attr->ssid_len] = '\0';
+ }
- {
- strWIDList[u32WidsCount].id = WID_INFO_ELEMENT_ASSOCIATE;
- strWIDList[u32WidsCount].type = WID_BIN_DATA;
- strWIDList[u32WidsCount].val = hif_drv->usr_conn_req.ies;
- strWIDList[u32WidsCount].size = hif_drv->usr_conn_req.ies_len;
- u32WidsCount++;
-
- if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) {
- info_element_size = hif_drv->usr_conn_req.ies_len;
- info_element = kmalloc(info_element_size, GFP_KERNEL);
- memcpy(info_element, hif_drv->usr_conn_req.ies,
- info_element_size);
+ hif_drv->usr_conn_req.ies_len = conn_attr->ies_len;
+ if (conn_attr->ies) {
+ hif_drv->usr_conn_req.ies = kmemdup(conn_attr->ies,
+ conn_attr->ies_len,
+ GFP_KERNEL);
+ if (!hif_drv->usr_conn_req.ies) {
+ result = -ENOMEM;
+ goto error;
}
}
- strWIDList[u32WidsCount].id = (u16)WID_11I_MODE;
- strWIDList[u32WidsCount].type = WID_CHAR;
- strWIDList[u32WidsCount].size = sizeof(char);
- strWIDList[u32WidsCount].val = (s8 *)&hif_drv->usr_conn_req.security;
- u32WidsCount++;
-
- if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7))
- mode_11i = hif_drv->usr_conn_req.security;
- strWIDList[u32WidsCount].id = (u16)WID_AUTH_TYPE;
- strWIDList[u32WidsCount].type = WID_CHAR;
- strWIDList[u32WidsCount].size = sizeof(char);
- strWIDList[u32WidsCount].val = (s8 *)&hif_drv->usr_conn_req.auth_type;
- u32WidsCount++;
-
- if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7))
- auth_type = (u8)hif_drv->usr_conn_req.auth_type;
-
- strWIDList[u32WidsCount].id = (u16)WID_JOIN_REQ_EXTENDED;
- strWIDList[u32WidsCount].type = WID_STR;
- strWIDList[u32WidsCount].size = 112;
- strWIDList[u32WidsCount].val = kmalloc(strWIDList[u32WidsCount].size, GFP_KERNEL);
-
- if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) {
- join_req_size = strWIDList[u32WidsCount].size;
- join_req = kmalloc(join_req_size, GFP_KERNEL);
- }
- if (!strWIDList[u32WidsCount].val) {
+ hif_drv->usr_conn_req.security = conn_attr->security;
+ hif_drv->usr_conn_req.auth_type = conn_attr->auth_type;
+ hif_drv->usr_conn_req.conn_result = conn_attr->result;
+ hif_drv->usr_conn_req.arg = conn_attr->arg;
+
+ wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)(&(dummyval));
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)(&(dummyval));
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_FAILED_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)(&(dummyval));
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE;
+ wid_list[wid_cnt].type = WID_BIN_DATA;
+ wid_list[wid_cnt].val = hif_drv->usr_conn_req.ies;
+ wid_list[wid_cnt].size = hif_drv->usr_conn_req.ies_len;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = (u16)WID_11I_MODE;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ wid_list[wid_cnt].val = (s8 *)&hif_drv->usr_conn_req.security;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = (u16)WID_AUTH_TYPE;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ wid_list[wid_cnt].val = (s8 *)&hif_drv->usr_conn_req.auth_type;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = (u16)WID_JOIN_REQ_EXTENDED;
+ wid_list[wid_cnt].type = WID_STR;
+ wid_list[wid_cnt].size = 112;
+ wid_list[wid_cnt].val = kmalloc(wid_list[wid_cnt].size, GFP_KERNEL);
+
+ if (!wid_list[wid_cnt].val) {
result = -EFAULT;
- goto ERRORHANDLER;
+ goto error;
}
- pu8CurrByte = strWIDList[u32WidsCount].val;
+ cur_byte = wid_list[wid_cnt].val;
- if (pstrHostIFconnectAttr->ssid) {
- memcpy(pu8CurrByte, pstrHostIFconnectAttr->ssid, pstrHostIFconnectAttr->ssid_len);
- pu8CurrByte[pstrHostIFconnectAttr->ssid_len] = '\0';
+ if (conn_attr->ssid) {
+ memcpy(cur_byte, conn_attr->ssid, conn_attr->ssid_len);
+ cur_byte[conn_attr->ssid_len] = '\0';
}
- pu8CurrByte += MAX_SSID_LEN;
- *(pu8CurrByte++) = INFRASTRUCTURE;
+ cur_byte += MAX_SSID_LEN;
+ *(cur_byte++) = INFRASTRUCTURE;
- if (pstrHostIFconnectAttr->ch >= 1 && pstrHostIFconnectAttr->ch <= 14) {
- *(pu8CurrByte++) = pstrHostIFconnectAttr->ch;
+ if (conn_attr->ch >= 1 && conn_attr->ch <= 14) {
+ *(cur_byte++) = conn_attr->ch;
} else {
netdev_err(vif->ndev, "Channel out of range\n");
- *(pu8CurrByte++) = 0xFF;
+ *(cur_byte++) = 0xFF;
}
- *(pu8CurrByte++) = (ptstrJoinBssParam->cap_info) & 0xFF;
- *(pu8CurrByte++) = ((ptstrJoinBssParam->cap_info) >> 8) & 0xFF;
+ *(cur_byte++) = (bss_param->cap_info) & 0xFF;
+ *(cur_byte++) = ((bss_param->cap_info) >> 8) & 0xFF;
- if (pstrHostIFconnectAttr->bssid)
- memcpy(pu8CurrByte, pstrHostIFconnectAttr->bssid, 6);
- pu8CurrByte += 6;
+ if (conn_attr->bssid)
+ memcpy(cur_byte, conn_attr->bssid, 6);
+ cur_byte += 6;
- if (pstrHostIFconnectAttr->bssid)
- memcpy(pu8CurrByte, pstrHostIFconnectAttr->bssid, 6);
- pu8CurrByte += 6;
+ if (conn_attr->bssid)
+ memcpy(cur_byte, conn_attr->bssid, 6);
+ cur_byte += 6;
- *(pu8CurrByte++) = (ptstrJoinBssParam->beacon_period) & 0xFF;
- *(pu8CurrByte++) = ((ptstrJoinBssParam->beacon_period) >> 8) & 0xFF;
- *(pu8CurrByte++) = ptstrJoinBssParam->dtim_period;
+ *(cur_byte++) = (bss_param->beacon_period) & 0xFF;
+ *(cur_byte++) = ((bss_param->beacon_period) >> 8) & 0xFF;
+ *(cur_byte++) = bss_param->dtim_period;
- memcpy(pu8CurrByte, ptstrJoinBssParam->supp_rates, MAX_RATES_SUPPORTED + 1);
- pu8CurrByte += (MAX_RATES_SUPPORTED + 1);
+ memcpy(cur_byte, bss_param->supp_rates, MAX_RATES_SUPPORTED + 1);
+ cur_byte += (MAX_RATES_SUPPORTED + 1);
- *(pu8CurrByte++) = ptstrJoinBssParam->wmm_cap;
- *(pu8CurrByte++) = ptstrJoinBssParam->uapsd_cap;
+ *(cur_byte++) = bss_param->wmm_cap;
+ *(cur_byte++) = bss_param->uapsd_cap;
- *(pu8CurrByte++) = ptstrJoinBssParam->ht_capable;
- hif_drv->usr_conn_req.ht_capable = ptstrJoinBssParam->ht_capable;
+ *(cur_byte++) = bss_param->ht_capable;
+ hif_drv->usr_conn_req.ht_capable = bss_param->ht_capable;
- *(pu8CurrByte++) = ptstrJoinBssParam->rsn_found;
- *(pu8CurrByte++) = ptstrJoinBssParam->rsn_grp_policy;
- *(pu8CurrByte++) = ptstrJoinBssParam->mode_802_11i;
+ *(cur_byte++) = bss_param->rsn_found;
+ *(cur_byte++) = bss_param->rsn_grp_policy;
+ *(cur_byte++) = bss_param->mode_802_11i;
- memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_pcip_policy, sizeof(ptstrJoinBssParam->rsn_pcip_policy));
- pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_pcip_policy);
+ memcpy(cur_byte, bss_param->rsn_pcip_policy,
+ sizeof(bss_param->rsn_pcip_policy));
+ cur_byte += sizeof(bss_param->rsn_pcip_policy);
- memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_auth_policy, sizeof(ptstrJoinBssParam->rsn_auth_policy));
- pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_auth_policy);
+ memcpy(cur_byte, bss_param->rsn_auth_policy,
+ sizeof(bss_param->rsn_auth_policy));
+ cur_byte += sizeof(bss_param->rsn_auth_policy);
- memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_cap, sizeof(ptstrJoinBssParam->rsn_cap));
- pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_cap);
+ memcpy(cur_byte, bss_param->rsn_cap, sizeof(bss_param->rsn_cap));
+ cur_byte += sizeof(bss_param->rsn_cap);
- *(pu8CurrByte++) = REAL_JOIN_REQ;
- *(pu8CurrByte++) = ptstrJoinBssParam->noa_enabled;
+ *(cur_byte++) = REAL_JOIN_REQ;
+ *(cur_byte++) = bss_param->noa_enabled;
- if (ptstrJoinBssParam->noa_enabled) {
- *(pu8CurrByte++) = (ptstrJoinBssParam->tsf) & 0xFF;
- *(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 8) & 0xFF;
- *(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 16) & 0xFF;
- *(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 24) & 0xFF;
+ if (bss_param->noa_enabled) {
+ *(cur_byte++) = (bss_param->tsf) & 0xFF;
+ *(cur_byte++) = ((bss_param->tsf) >> 8) & 0xFF;
+ *(cur_byte++) = ((bss_param->tsf) >> 16) & 0xFF;
+ *(cur_byte++) = ((bss_param->tsf) >> 24) & 0xFF;
- *(pu8CurrByte++) = ptstrJoinBssParam->opp_enabled;
- *(pu8CurrByte++) = ptstrJoinBssParam->idx;
+ *(cur_byte++) = bss_param->opp_enabled;
+ *(cur_byte++) = bss_param->idx;
- if (ptstrJoinBssParam->opp_enabled)
- *(pu8CurrByte++) = ptstrJoinBssParam->ct_window;
+ if (bss_param->opp_enabled)
+ *(cur_byte++) = bss_param->ct_window;
- *(pu8CurrByte++) = ptstrJoinBssParam->cnt;
+ *(cur_byte++) = bss_param->cnt;
- memcpy(pu8CurrByte, ptstrJoinBssParam->duration, sizeof(ptstrJoinBssParam->duration));
- pu8CurrByte += sizeof(ptstrJoinBssParam->duration);
+ memcpy(cur_byte, bss_param->duration,
+ sizeof(bss_param->duration));
+ cur_byte += sizeof(bss_param->duration);
- memcpy(pu8CurrByte, ptstrJoinBssParam->interval, sizeof(ptstrJoinBssParam->interval));
- pu8CurrByte += sizeof(ptstrJoinBssParam->interval);
+ memcpy(cur_byte, bss_param->interval,
+ sizeof(bss_param->interval));
+ cur_byte += sizeof(bss_param->interval);
- memcpy(pu8CurrByte, ptstrJoinBssParam->start_time, sizeof(ptstrJoinBssParam->start_time));
- pu8CurrByte += sizeof(ptstrJoinBssParam->start_time);
+ memcpy(cur_byte, bss_param->start_time,
+ sizeof(bss_param->start_time));
+ cur_byte += sizeof(bss_param->start_time);
}
- pu8CurrByte = strWIDList[u32WidsCount].val;
- u32WidsCount++;
+ cur_byte = wid_list[wid_cnt].val;
+ wid_cnt++;
- if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) {
- memcpy(join_req, pu8CurrByte, join_req_size);
- join_req_vif = vif;
- }
-
- if (pstrHostIFconnectAttr->bssid)
+ if (conn_attr->bssid)
memcpy(wilc_connected_ssid,
- pstrHostIFconnectAttr->bssid, ETH_ALEN);
+ conn_attr->bssid, ETH_ALEN);
- result = wilc_send_config_pkt(vif, SET_CFG, strWIDList,
- u32WidsCount,
+ result = wilc_send_config_pkt(vif, SET_CFG, wid_list,
+ wid_cnt,
wilc_get_vif_idx(vif));
if (result) {
netdev_err(vif->ndev, "failed to send config packet\n");
result = -EFAULT;
- goto ERRORHANDLER;
+ goto error;
} else {
hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;
}
-ERRORHANDLER:
+error:
if (result) {
- struct connect_info strConnectInfo;
+ struct connect_info conn_info;
del_timer(&hif_drv->connect_timer);
- memset(&strConnectInfo, 0, sizeof(struct connect_info));
+ memset(&conn_info, 0, sizeof(struct connect_info));
- if (pstrHostIFconnectAttr->result) {
- if (pstrHostIFconnectAttr->bssid)
- memcpy(strConnectInfo.bssid, pstrHostIFconnectAttr->bssid, 6);
+ if (conn_attr->result) {
+ if (conn_attr->bssid)
+ memcpy(conn_info.bssid, conn_attr->bssid, 6);
- if (pstrHostIFconnectAttr->ies) {
- strConnectInfo.req_ies_len = pstrHostIFconnectAttr->ies_len;
- strConnectInfo.req_ies = kmalloc(pstrHostIFconnectAttr->ies_len, GFP_KERNEL);
- memcpy(strConnectInfo.req_ies,
- pstrHostIFconnectAttr->ies,
- pstrHostIFconnectAttr->ies_len);
+ if (conn_attr->ies) {
+ conn_info.req_ies_len = conn_attr->ies_len;
+ conn_info.req_ies = kmalloc(conn_attr->ies_len,
+ GFP_KERNEL);
+ memcpy(conn_info.req_ies,
+ conn_attr->ies,
+ conn_attr->ies_len);
}
- pstrHostIFconnectAttr->result(CONN_DISCONN_EVENT_CONN_RESP,
- &strConnectInfo,
+ conn_attr->result(CONN_DISCONN_EVENT_CONN_RESP,
+ &conn_info,
MAC_DISCONNECTED,
NULL,
- pstrHostIFconnectAttr->arg);
+ conn_attr->arg);
hif_drv->hif_state = HOST_IF_IDLE;
- kfree(strConnectInfo.req_ies);
- strConnectInfo.req_ies = NULL;
+ kfree(conn_info.req_ies);
+ conn_info.req_ies = NULL;
} else {
netdev_err(vif->ndev, "Connect callback is NULL\n");
}
}
- kfree(pstrHostIFconnectAttr->bssid);
- pstrHostIFconnectAttr->bssid = NULL;
+ kfree(conn_attr->bssid);
+ conn_attr->bssid = NULL;
- kfree(pstrHostIFconnectAttr->ssid);
- pstrHostIFconnectAttr->ssid = NULL;
+ kfree(conn_attr->ssid);
+ conn_attr->ssid = NULL;
- kfree(pstrHostIFconnectAttr->ies);
- pstrHostIFconnectAttr->ies = NULL;
+ kfree(conn_attr->ies);
+ conn_attr->ies = NULL;
- kfree(pu8CurrByte);
+ kfree(cur_byte);
return result;
}
-static s32 Handle_ConnectTimeout(struct wilc_vif *vif)
+static s32 handle_connect_timeout(struct wilc_vif *vif)
{
s32 result = 0;
- struct connect_info strConnectInfo;
+ struct connect_info info;
struct wid wid;
- u16 u16DummyReasonCode = 0;
+ u16 dummy_reason_code = 0;
struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv) {
@@ -1182,37 +1187,37 @@ static s32 Handle_ConnectTimeout(struct wilc_vif *vif)
scan_while_connected = false;
- memset(&strConnectInfo, 0, sizeof(struct connect_info));
+ memset(&info, 0, sizeof(struct connect_info));
if (hif_drv->usr_conn_req.conn_result) {
if (hif_drv->usr_conn_req.bssid) {
- memcpy(strConnectInfo.bssid,
+ memcpy(info.bssid,
hif_drv->usr_conn_req.bssid, 6);
}
if (hif_drv->usr_conn_req.ies) {
- strConnectInfo.req_ies_len = hif_drv->usr_conn_req.ies_len;
- strConnectInfo.req_ies = kmalloc(hif_drv->usr_conn_req.ies_len, GFP_KERNEL);
- memcpy(strConnectInfo.req_ies,
+ info.req_ies_len = hif_drv->usr_conn_req.ies_len;
+ info.req_ies = kmalloc(hif_drv->usr_conn_req.ies_len, GFP_KERNEL);
+ memcpy(info.req_ies,
hif_drv->usr_conn_req.ies,
hif_drv->usr_conn_req.ies_len);
}
hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_CONN_RESP,
- &strConnectInfo,
+ &info,
MAC_DISCONNECTED,
NULL,
hif_drv->usr_conn_req.arg);
- kfree(strConnectInfo.req_ies);
- strConnectInfo.req_ies = NULL;
+ kfree(info.req_ies);
+ info.req_ies = NULL;
} else {
netdev_err(vif->ndev, "Connect callback is NULL\n");
}
wid.id = (u16)WID_DISCONNECT;
wid.type = WID_CHAR;
- wid.val = (s8 *)&u16DummyReasonCode;
+ wid.val = (s8 *)&dummy_reason_code;
wid.size = sizeof(char);
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
@@ -1231,382 +1236,380 @@ static s32 Handle_ConnectTimeout(struct wilc_vif *vif)
eth_zero_addr(wilc_connected_ssid);
- if (join_req && join_req_vif == vif) {
- kfree(join_req);
- join_req = NULL;
- }
-
- if (info_element && join_req_vif == vif) {
- kfree(info_element);
- info_element = NULL;
- }
-
return result;
}
-static s32 Handle_RcvdNtwrkInfo(struct wilc_vif *vif,
- struct rcvd_net_info *pstrRcvdNetworkInfo)
+static s32 handle_rcvd_ntwrk_info(struct wilc_vif *vif,
+ struct rcvd_net_info *rcvd_info)
{
u32 i;
- bool bNewNtwrkFound;
+ bool found;
s32 result = 0;
- struct network_info *pstrNetworkInfo = NULL;
- void *pJoinParams = NULL;
+ struct network_info *info = NULL;
+ void *params = NULL;
struct host_if_drv *hif_drv = vif->hif_drv;
+ struct user_scan_req *scan_req = &hif_drv->usr_scan_req;
- bNewNtwrkFound = true;
+ found = true;
- if (hif_drv->usr_scan_req.scan_result) {
- wilc_parse_network_info(pstrRcvdNetworkInfo->buffer, &pstrNetworkInfo);
- if (!pstrNetworkInfo ||
- !hif_drv->usr_scan_req.scan_result) {
- netdev_err(vif->ndev, "driver is null\n");
- result = -EINVAL;
- goto done;
- }
+ if (!scan_req->scan_result)
+ goto done;
- for (i = 0; i < hif_drv->usr_scan_req.rcvd_ch_cnt; i++) {
- if (memcmp(hif_drv->usr_scan_req.net_info[i].bssid,
- pstrNetworkInfo->bssid, 6) == 0) {
- if (pstrNetworkInfo->rssi <= hif_drv->usr_scan_req.net_info[i].rssi) {
- goto done;
- } else {
- hif_drv->usr_scan_req.net_info[i].rssi = pstrNetworkInfo->rssi;
- bNewNtwrkFound = false;
- break;
- }
+ wilc_parse_network_info(rcvd_info->buffer, &info);
+ if (!info || !scan_req->scan_result) {
+ netdev_err(vif->ndev, "driver is null\n");
+ result = -EINVAL;
+ goto done;
+ }
+
+ for (i = 0; i < scan_req->rcvd_ch_cnt; i++) {
+ if (memcmp(scan_req->net_info[i].bssid, info->bssid, 6) == 0) {
+ if (info->rssi <= scan_req->net_info[i].rssi) {
+ goto done;
+ } else {
+ scan_req->net_info[i].rssi = info->rssi;
+ found = false;
+ break;
}
}
+ }
- if (bNewNtwrkFound) {
- if (hif_drv->usr_scan_req.rcvd_ch_cnt < MAX_NUM_SCANNED_NETWORKS) {
- hif_drv->usr_scan_req.net_info[hif_drv->usr_scan_req.rcvd_ch_cnt].rssi = pstrNetworkInfo->rssi;
+ if (found) {
+ if (scan_req->rcvd_ch_cnt < MAX_NUM_SCANNED_NETWORKS) {
+ scan_req->net_info[scan_req->rcvd_ch_cnt].rssi = info->rssi;
- memcpy(hif_drv->usr_scan_req.net_info[hif_drv->usr_scan_req.rcvd_ch_cnt].bssid,
- pstrNetworkInfo->bssid, 6);
+ memcpy(scan_req->net_info[scan_req->rcvd_ch_cnt].bssid,
+ info->bssid, 6);
- hif_drv->usr_scan_req.rcvd_ch_cnt++;
+ scan_req->rcvd_ch_cnt++;
- pstrNetworkInfo->new_network = true;
- pJoinParams = host_int_ParseJoinBssParam(pstrNetworkInfo);
+ info->new_network = true;
+ params = host_int_parse_join_bss_param(info);
- hif_drv->usr_scan_req.scan_result(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo,
- hif_drv->usr_scan_req.arg,
- pJoinParams);
- }
- } else {
- pstrNetworkInfo->new_network = false;
- hif_drv->usr_scan_req.scan_result(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo,
- hif_drv->usr_scan_req.arg, NULL);
+ scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, info,
+ scan_req->arg, params);
}
+ } else {
+ info->new_network = false;
+ scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, info,
+ scan_req->arg, NULL);
}
done:
- kfree(pstrRcvdNetworkInfo->buffer);
- pstrRcvdNetworkInfo->buffer = NULL;
+ kfree(rcvd_info->buffer);
+ rcvd_info->buffer = NULL;
- if (pstrNetworkInfo) {
- kfree(pstrNetworkInfo->ies);
- kfree(pstrNetworkInfo);
+ if (info) {
+ kfree(info->ies);
+ kfree(info);
}
return result;
}
static s32 host_int_get_assoc_res_info(struct wilc_vif *vif,
- u8 *pu8AssocRespInfo,
- u32 u32MaxAssocRespInfoLen,
- u32 *pu32RcvdAssocRespInfoLen);
+ u8 *assoc_resp_info,
+ u32 max_assoc_resp_info_len,
+ u32 *rcvd_assoc_resp_info_len);
-static s32 Handle_RcvdGnrlAsyncInfo(struct wilc_vif *vif,
- struct rcvd_async_info *pstrRcvdGnrlAsyncInfo)
+static inline void host_int_free_user_conn_req(struct host_if_drv *hif_drv)
{
- s32 result = 0;
- u8 u8MsgType = 0;
- u8 u8MsgID = 0;
- u16 u16MsgLen = 0;
- u16 u16WidID = (u16)WID_NIL;
- u8 u8WidLen = 0;
- u8 u8MacStatus;
- u8 u8MacStatusReasonCode;
- u8 u8MacStatusAdditionalInfo;
- struct connect_info strConnectInfo;
- struct disconnect_info strDisconnectNotifInfo;
- s32 s32Err = 0;
+ hif_drv->usr_conn_req.ssid_len = 0;
+ kfree(hif_drv->usr_conn_req.ssid);
+ hif_drv->usr_conn_req.ssid = NULL;
+ kfree(hif_drv->usr_conn_req.bssid);
+ hif_drv->usr_conn_req.bssid = NULL;
+ hif_drv->usr_conn_req.ies_len = 0;
+ kfree(hif_drv->usr_conn_req.ies);
+ hif_drv->usr_conn_req.ies = NULL;
+}
+
+static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,
+ u8 mac_status)
+{
+ struct connect_resp_info *connect_resp_info = NULL;
+ struct connect_info conn_info;
struct host_if_drv *hif_drv = vif->hif_drv;
- if (!hif_drv) {
- netdev_err(vif->ndev, "Driver handler is NULL\n");
- return -ENODEV;
- }
+ memset(&conn_info, 0, sizeof(struct connect_info));
- if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP ||
- hif_drv->hif_state == HOST_IF_CONNECTED ||
- hif_drv->usr_scan_req.scan_result) {
- if (!pstrRcvdGnrlAsyncInfo->buffer ||
- !hif_drv->usr_conn_req.conn_result) {
- netdev_err(vif->ndev, "driver is null\n");
- return -EINVAL;
- }
+ if (mac_status == MAC_CONNECTED) {
+ u32 rcvd_assoc_resp_info_len;
- u8MsgType = pstrRcvdGnrlAsyncInfo->buffer[0];
+ memset(rcv_assoc_resp, 0, MAX_ASSOC_RESP_FRAME_SIZE);
- if ('I' != u8MsgType) {
- netdev_err(vif->ndev, "Received Message incorrect.\n");
- return -EFAULT;
- }
+ host_int_get_assoc_res_info(vif, rcv_assoc_resp,
+ MAX_ASSOC_RESP_FRAME_SIZE,
+ &rcvd_assoc_resp_info_len);
- u8MsgID = pstrRcvdGnrlAsyncInfo->buffer[1];
- u16MsgLen = MAKE_WORD16(pstrRcvdGnrlAsyncInfo->buffer[2], pstrRcvdGnrlAsyncInfo->buffer[3]);
- u16WidID = MAKE_WORD16(pstrRcvdGnrlAsyncInfo->buffer[4], pstrRcvdGnrlAsyncInfo->buffer[5]);
- u8WidLen = pstrRcvdGnrlAsyncInfo->buffer[6];
- u8MacStatus = pstrRcvdGnrlAsyncInfo->buffer[7];
- u8MacStatusReasonCode = pstrRcvdGnrlAsyncInfo->buffer[8];
- u8MacStatusAdditionalInfo = pstrRcvdGnrlAsyncInfo->buffer[9];
- if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
- u32 u32RcvdAssocRespInfoLen = 0;
- struct connect_resp_info *pstrConnectRespInfo = NULL;
-
- memset(&strConnectInfo, 0, sizeof(struct connect_info));
-
- if (u8MacStatus == MAC_CONNECTED) {
- memset(rcv_assoc_resp, 0, MAX_ASSOC_RESP_FRAME_SIZE);
-
- host_int_get_assoc_res_info(vif,
- rcv_assoc_resp,
- MAX_ASSOC_RESP_FRAME_SIZE,
- &u32RcvdAssocRespInfoLen);
-
- if (u32RcvdAssocRespInfoLen != 0) {
- s32Err = wilc_parse_assoc_resp_info(rcv_assoc_resp, u32RcvdAssocRespInfoLen,
- &pstrConnectRespInfo);
- if (s32Err) {
- netdev_err(vif->ndev, "wilc_parse_assoc_resp_info() returned error %d\n", s32Err);
- } else {
- strConnectInfo.status = pstrConnectRespInfo->status;
-
- if (strConnectInfo.status == SUCCESSFUL_STATUSCODE && pstrConnectRespInfo->ies) {
- strConnectInfo.resp_ies_len = pstrConnectRespInfo->ies_len;
- strConnectInfo.resp_ies = kmalloc(pstrConnectRespInfo->ies_len, GFP_KERNEL);
- memcpy(strConnectInfo.resp_ies, pstrConnectRespInfo->ies,
- pstrConnectRespInfo->ies_len);
- }
-
- if (pstrConnectRespInfo) {
- kfree(pstrConnectRespInfo->ies);
- kfree(pstrConnectRespInfo);
- }
- }
+ if (rcvd_assoc_resp_info_len != 0) {
+ s32 err = 0;
+
+ err = wilc_parse_assoc_resp_info(rcv_assoc_resp, rcvd_assoc_resp_info_len,
+ &connect_resp_info);
+ if (err) {
+ netdev_err(vif->ndev,
+ "wilc_parse_assoc_resp_info() returned error %d\n",
+ err);
+ } else {
+ conn_info.status = connect_resp_info->status;
+
+ if (conn_info.status == SUCCESSFUL_STATUSCODE &&
+ connect_resp_info->ies) {
+ conn_info.resp_ies = kmemdup(connect_resp_info->ies,
+ connect_resp_info->ies_len,
+ GFP_KERNEL);
+ if (conn_info.resp_ies)
+ conn_info.resp_ies_len = connect_resp_info->ies_len;
}
- }
- if (u8MacStatus == MAC_CONNECTED &&
- strConnectInfo.status != SUCCESSFUL_STATUSCODE) {
- netdev_err(vif->ndev, "Received MAC status is MAC_CONNECTED while the received status code in Asoc Resp is not SUCCESSFUL_STATUSCODE\n");
- eth_zero_addr(wilc_connected_ssid);
- } else if (u8MacStatus == MAC_DISCONNECTED) {
- netdev_err(vif->ndev, "Received MAC status is MAC_DISCONNECTED\n");
- eth_zero_addr(wilc_connected_ssid);
+ kfree(connect_resp_info->ies);
+ kfree(connect_resp_info);
}
+ }
+ }
- if (hif_drv->usr_conn_req.bssid) {
- memcpy(strConnectInfo.bssid, hif_drv->usr_conn_req.bssid, 6);
+ if (mac_status == MAC_CONNECTED &&
+ conn_info.status != SUCCESSFUL_STATUSCODE) {
+ netdev_err(vif->ndev,
+ "Received MAC status is MAC_CONNECTED while the received status code in Asoc Resp is not SUCCESSFUL_STATUSCODE\n");
+ eth_zero_addr(wilc_connected_ssid);
+ } else if (mac_status == MAC_DISCONNECTED) {
+ netdev_err(vif->ndev, "Received MAC status is MAC_DISCONNECTED\n");
+ eth_zero_addr(wilc_connected_ssid);
+ }
- if (u8MacStatus == MAC_CONNECTED &&
- strConnectInfo.status == SUCCESSFUL_STATUSCODE) {
- memcpy(hif_drv->assoc_bssid,
- hif_drv->usr_conn_req.bssid, ETH_ALEN);
- }
- }
+ if (hif_drv->usr_conn_req.bssid) {
+ memcpy(conn_info.bssid, hif_drv->usr_conn_req.bssid, 6);
- if (hif_drv->usr_conn_req.ies) {
- strConnectInfo.req_ies_len = hif_drv->usr_conn_req.ies_len;
- strConnectInfo.req_ies = kmalloc(hif_drv->usr_conn_req.ies_len, GFP_KERNEL);
- memcpy(strConnectInfo.req_ies,
- hif_drv->usr_conn_req.ies,
- hif_drv->usr_conn_req.ies_len);
- }
+ if (mac_status == MAC_CONNECTED &&
+ conn_info.status == SUCCESSFUL_STATUSCODE) {
+ memcpy(hif_drv->assoc_bssid,
+ hif_drv->usr_conn_req.bssid, ETH_ALEN);
+ }
+ }
- del_timer(&hif_drv->connect_timer);
- hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_CONN_RESP,
- &strConnectInfo,
- u8MacStatus,
- NULL,
- hif_drv->usr_conn_req.arg);
+ if (hif_drv->usr_conn_req.ies) {
+ conn_info.req_ies = kmemdup(conn_info.req_ies,
+ hif_drv->usr_conn_req.ies_len,
+ GFP_KERNEL);
+ if (conn_info.req_ies)
+ conn_info.req_ies_len = hif_drv->usr_conn_req.ies_len;
+ }
- if (u8MacStatus == MAC_CONNECTED &&
- strConnectInfo.status == SUCCESSFUL_STATUSCODE) {
- wilc_set_power_mgmt(vif, 0, 0);
+ del_timer(&hif_drv->connect_timer);
+ hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_CONN_RESP,
+ &conn_info, mac_status, NULL,
+ hif_drv->usr_conn_req.arg);
- hif_drv->hif_state = HOST_IF_CONNECTED;
+ if (mac_status == MAC_CONNECTED &&
+ conn_info.status == SUCCESSFUL_STATUSCODE) {
+ wilc_set_power_mgmt(vif, 0, 0);
- wilc_optaining_ip = true;
- mod_timer(&wilc_during_ip_timer,
- jiffies + msecs_to_jiffies(10000));
- } else {
- hif_drv->hif_state = HOST_IF_IDLE;
- scan_while_connected = false;
- }
+ hif_drv->hif_state = HOST_IF_CONNECTED;
- kfree(strConnectInfo.resp_ies);
- strConnectInfo.resp_ies = NULL;
-
- kfree(strConnectInfo.req_ies);
- strConnectInfo.req_ies = NULL;
- hif_drv->usr_conn_req.ssid_len = 0;
- kfree(hif_drv->usr_conn_req.ssid);
- hif_drv->usr_conn_req.ssid = NULL;
- kfree(hif_drv->usr_conn_req.bssid);
- hif_drv->usr_conn_req.bssid = NULL;
- hif_drv->usr_conn_req.ies_len = 0;
- kfree(hif_drv->usr_conn_req.ies);
- hif_drv->usr_conn_req.ies = NULL;
- } else if ((u8MacStatus == MAC_DISCONNECTED) &&
- (hif_drv->hif_state == HOST_IF_CONNECTED)) {
- memset(&strDisconnectNotifInfo, 0, sizeof(struct disconnect_info));
+ wilc_optaining_ip = true;
+ mod_timer(&wilc_during_ip_timer,
+ jiffies + msecs_to_jiffies(10000));
+ } else {
+ hif_drv->hif_state = HOST_IF_IDLE;
+ scan_while_connected = false;
+ }
- if (hif_drv->usr_scan_req.scan_result) {
- del_timer(&hif_drv->scan_timer);
- Handle_ScanDone(vif, SCAN_EVENT_ABORTED);
- }
+ kfree(conn_info.resp_ies);
+ conn_info.resp_ies = NULL;
- strDisconnectNotifInfo.reason = 0;
- strDisconnectNotifInfo.ie = NULL;
- strDisconnectNotifInfo.ie_len = 0;
+ kfree(conn_info.req_ies);
+ conn_info.req_ies = NULL;
+ host_int_free_user_conn_req(hif_drv);
+}
- if (hif_drv->usr_conn_req.conn_result) {
- wilc_optaining_ip = false;
- wilc_set_power_mgmt(vif, 0, 0);
+static inline void host_int_handle_disconnect(struct wilc_vif *vif)
+{
+ struct disconnect_info disconn_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
- hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,
- NULL,
- 0,
- &strDisconnectNotifInfo,
- hif_drv->usr_conn_req.arg);
- } else {
- netdev_err(vif->ndev, "Connect result NULL\n");
- }
+ memset(&disconn_info, 0, sizeof(struct disconnect_info));
- eth_zero_addr(hif_drv->assoc_bssid);
+ if (hif_drv->usr_scan_req.scan_result) {
+ del_timer(&hif_drv->scan_timer);
+ handle_scan_done(vif, SCAN_EVENT_ABORTED);
+ }
- hif_drv->usr_conn_req.ssid_len = 0;
- kfree(hif_drv->usr_conn_req.ssid);
- hif_drv->usr_conn_req.ssid = NULL;
- kfree(hif_drv->usr_conn_req.bssid);
- hif_drv->usr_conn_req.bssid = NULL;
- hif_drv->usr_conn_req.ies_len = 0;
- kfree(hif_drv->usr_conn_req.ies);
- hif_drv->usr_conn_req.ies = NULL;
+ disconn_info.reason = 0;
+ disconn_info.ie = NULL;
+ disconn_info.ie_len = 0;
- if (join_req && join_req_vif == vif) {
- kfree(join_req);
- join_req = NULL;
- }
+ if (hif_drv->usr_conn_req.conn_result) {
+ wilc_optaining_ip = false;
+ wilc_set_power_mgmt(vif, 0, 0);
- if (info_element && join_req_vif == vif) {
- kfree(info_element);
- info_element = NULL;
- }
+ hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,
+ NULL, 0, &disconn_info,
+ hif_drv->usr_conn_req.arg);
+ } else {
+ netdev_err(vif->ndev, "Connect result NULL\n");
+ }
- hif_drv->hif_state = HOST_IF_IDLE;
- scan_while_connected = false;
+ eth_zero_addr(hif_drv->assoc_bssid);
+
+ host_int_free_user_conn_req(hif_drv);
+ hif_drv->hif_state = HOST_IF_IDLE;
+ scan_while_connected = false;
+}
+
+static s32 handle_rcvd_gnrl_async_info(struct wilc_vif *vif,
+ struct rcvd_async_info *rcvd_info)
+{
+ s32 result = 0;
+ u8 msg_type = 0;
+ u8 msg_id = 0;
+ u16 msg_len = 0;
+ u16 wid_id = (u16)WID_NIL;
+ u8 wid_len = 0;
+ u8 mac_status;
+ u8 mac_status_reason_code;
+ u8 mac_status_additional_info;
+ struct host_if_drv *hif_drv = vif->hif_drv;
+
+ if (!rcvd_info->buffer) {
+ netdev_err(vif->ndev, "Received buffer is NULL\n");
+ return -EINVAL;
+ }
+
+ if (!hif_drv) {
+ netdev_err(vif->ndev, "Driver handler is NULL\n");
+ kfree(rcvd_info->buffer);
+ rcvd_info->buffer = NULL;
+ return -ENODEV;
+ }
+
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP ||
+ hif_drv->hif_state == HOST_IF_CONNECTED ||
+ hif_drv->usr_scan_req.scan_result) {
+ if (!hif_drv->usr_conn_req.conn_result) {
+ netdev_err(vif->ndev, "driver is null\n");
+ kfree(rcvd_info->buffer);
+ rcvd_info->buffer = NULL;
+ return -EINVAL;
+ }
+
+ msg_type = rcvd_info->buffer[0];
+
+ if ('I' != msg_type) {
+ netdev_err(vif->ndev, "Received Message incorrect.\n");
+ kfree(rcvd_info->buffer);
+ rcvd_info->buffer = NULL;
+ return -EFAULT;
+ }
- } else if ((u8MacStatus == MAC_DISCONNECTED) &&
+ msg_id = rcvd_info->buffer[1];
+ msg_len = MAKE_WORD16(rcvd_info->buffer[2], rcvd_info->buffer[3]);
+ wid_id = MAKE_WORD16(rcvd_info->buffer[4], rcvd_info->buffer[5]);
+ wid_len = rcvd_info->buffer[6];
+ mac_status = rcvd_info->buffer[7];
+ mac_status_reason_code = rcvd_info->buffer[8];
+ mac_status_additional_info = rcvd_info->buffer[9];
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
+ host_int_parse_assoc_resp_info(vif, mac_status);
+ } else if ((mac_status == MAC_DISCONNECTED) &&
+ (hif_drv->hif_state == HOST_IF_CONNECTED)) {
+ host_int_handle_disconnect(vif);
+ } else if ((mac_status == MAC_DISCONNECTED) &&
(hif_drv->usr_scan_req.scan_result)) {
del_timer(&hif_drv->scan_timer);
if (hif_drv->usr_scan_req.scan_result)
- Handle_ScanDone(vif, SCAN_EVENT_ABORTED);
+ handle_scan_done(vif, SCAN_EVENT_ABORTED);
}
}
- kfree(pstrRcvdGnrlAsyncInfo->buffer);
- pstrRcvdGnrlAsyncInfo->buffer = NULL;
+ kfree(rcvd_info->buffer);
+ rcvd_info->buffer = NULL;
return result;
}
-static int Handle_Key(struct wilc_vif *vif,
- struct key_attr *pstrHostIFkeyAttr)
+static int handle_key(struct wilc_vif *vif, struct key_attr *hif_key)
{
s32 result = 0;
struct wid wid;
- struct wid strWIDList[5];
+ struct wid wid_list[5];
u8 i;
- u8 *pu8keybuf;
+ u8 *key_buf;
s8 s8idxarray[1];
s8 ret = 0;
struct host_if_drv *hif_drv = vif->hif_drv;
- switch (pstrHostIFkeyAttr->type) {
+ switch (hif_key->type) {
case WEP:
- if (pstrHostIFkeyAttr->action & ADDKEY_AP) {
- strWIDList[0].id = (u16)WID_11I_MODE;
- strWIDList[0].type = WID_CHAR;
- strWIDList[0].size = sizeof(char);
- strWIDList[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wep.mode;
+ if (hif_key->action & ADDKEY_AP) {
+ wid_list[0].id = (u16)WID_11I_MODE;
+ wid_list[0].type = WID_CHAR;
+ wid_list[0].size = sizeof(char);
+ wid_list[0].val = (s8 *)&hif_key->attr.wep.mode;
- strWIDList[1].id = WID_AUTH_TYPE;
- strWIDList[1].type = WID_CHAR;
- strWIDList[1].size = sizeof(char);
- strWIDList[1].val = (s8 *)&pstrHostIFkeyAttr->attr.wep.auth_type;
+ wid_list[1].id = WID_AUTH_TYPE;
+ wid_list[1].type = WID_CHAR;
+ wid_list[1].size = sizeof(char);
+ wid_list[1].val = (s8 *)&hif_key->attr.wep.auth_type;
- pu8keybuf = kmalloc(pstrHostIFkeyAttr->attr.wep.key_len + 2,
- GFP_KERNEL);
- if (!pu8keybuf)
+ key_buf = kmalloc(hif_key->attr.wep.key_len + 2,
+ GFP_KERNEL);
+ if (!key_buf)
return -ENOMEM;
- pu8keybuf[0] = pstrHostIFkeyAttr->attr.wep.index;
- pu8keybuf[1] = pstrHostIFkeyAttr->attr.wep.key_len;
+ key_buf[0] = hif_key->attr.wep.index;
+ key_buf[1] = hif_key->attr.wep.key_len;
- memcpy(&pu8keybuf[2], pstrHostIFkeyAttr->attr.wep.key,
- pstrHostIFkeyAttr->attr.wep.key_len);
+ memcpy(&key_buf[2], hif_key->attr.wep.key,
+ hif_key->attr.wep.key_len);
- kfree(pstrHostIFkeyAttr->attr.wep.key);
+ kfree(hif_key->attr.wep.key);
- strWIDList[2].id = (u16)WID_WEP_KEY_VALUE;
- strWIDList[2].type = WID_STR;
- strWIDList[2].size = pstrHostIFkeyAttr->attr.wep.key_len + 2;
- strWIDList[2].val = (s8 *)pu8keybuf;
+ wid_list[2].id = (u16)WID_WEP_KEY_VALUE;
+ wid_list[2].type = WID_STR;
+ wid_list[2].size = hif_key->attr.wep.key_len + 2;
+ wid_list[2].val = (s8 *)key_buf;
result = wilc_send_config_pkt(vif, SET_CFG,
- strWIDList, 3,
+ wid_list, 3,
wilc_get_vif_idx(vif));
- kfree(pu8keybuf);
- } else if (pstrHostIFkeyAttr->action & ADDKEY) {
- pu8keybuf = kmalloc(pstrHostIFkeyAttr->attr.wep.key_len + 2, GFP_KERNEL);
- if (!pu8keybuf)
+ kfree(key_buf);
+ } else if (hif_key->action & ADDKEY) {
+ key_buf = kmalloc(hif_key->attr.wep.key_len + 2, GFP_KERNEL);
+ if (!key_buf)
return -ENOMEM;
- pu8keybuf[0] = pstrHostIFkeyAttr->attr.wep.index;
- memcpy(pu8keybuf + 1, &pstrHostIFkeyAttr->attr.wep.key_len, 1);
- memcpy(pu8keybuf + 2, pstrHostIFkeyAttr->attr.wep.key,
- pstrHostIFkeyAttr->attr.wep.key_len);
- kfree(pstrHostIFkeyAttr->attr.wep.key);
+ key_buf[0] = hif_key->attr.wep.index;
+ memcpy(key_buf + 1, &hif_key->attr.wep.key_len, 1);
+ memcpy(key_buf + 2, hif_key->attr.wep.key,
+ hif_key->attr.wep.key_len);
+ kfree(hif_key->attr.wep.key);
wid.id = (u16)WID_ADD_WEP_KEY;
wid.type = WID_STR;
- wid.val = (s8 *)pu8keybuf;
- wid.size = pstrHostIFkeyAttr->attr.wep.key_len + 2;
+ wid.val = (s8 *)key_buf;
+ wid.size = hif_key->attr.wep.key_len + 2;
result = wilc_send_config_pkt(vif, SET_CFG,
&wid, 1,
wilc_get_vif_idx(vif));
- kfree(pu8keybuf);
- } else if (pstrHostIFkeyAttr->action & REMOVEKEY) {
+ kfree(key_buf);
+ } else if (hif_key->action & REMOVEKEY) {
wid.id = (u16)WID_REMOVE_WEP_KEY;
wid.type = WID_STR;
- s8idxarray[0] = (s8)pstrHostIFkeyAttr->attr.wep.index;
+ s8idxarray[0] = (s8)hif_key->attr.wep.index;
wid.val = s8idxarray;
wid.size = 1;
result = wilc_send_config_pkt(vif, SET_CFG,
&wid, 1,
wilc_get_vif_idx(vif));
- } else if (pstrHostIFkeyAttr->action & DEFAULTKEY) {
+ } else if (hif_key->action & DEFAULTKEY) {
wid.id = (u16)WID_KEY_ID;
wid.type = WID_CHAR;
- wid.val = (s8 *)&pstrHostIFkeyAttr->attr.wep.index;
+ wid.val = (s8 *)&hif_key->attr.wep.index;
wid.size = sizeof(char);
result = wilc_send_config_pkt(vif, SET_CFG,
@@ -1617,157 +1620,157 @@ static int Handle_Key(struct wilc_vif *vif,
break;
case WPA_RX_GTK:
- if (pstrHostIFkeyAttr->action & ADDKEY_AP) {
- pu8keybuf = kzalloc(RX_MIC_KEY_MSG_LEN, GFP_KERNEL);
- if (!pu8keybuf) {
+ if (hif_key->action & ADDKEY_AP) {
+ key_buf = kzalloc(RX_MIC_KEY_MSG_LEN, GFP_KERNEL);
+ if (!key_buf) {
ret = -ENOMEM;
- goto _WPARxGtk_end_case_;
+ goto out_wpa_rx_gtk;
}
- if (pstrHostIFkeyAttr->attr.wpa.seq)
- memcpy(pu8keybuf + 6, pstrHostIFkeyAttr->attr.wpa.seq, 8);
+ if (hif_key->attr.wpa.seq)
+ memcpy(key_buf + 6, hif_key->attr.wpa.seq, 8);
- memcpy(pu8keybuf + 14, &pstrHostIFkeyAttr->attr.wpa.index, 1);
- memcpy(pu8keybuf + 15, &pstrHostIFkeyAttr->attr.wpa.key_len, 1);
- memcpy(pu8keybuf + 16, pstrHostIFkeyAttr->attr.wpa.key,
- pstrHostIFkeyAttr->attr.wpa.key_len);
+ memcpy(key_buf + 14, &hif_key->attr.wpa.index, 1);
+ memcpy(key_buf + 15, &hif_key->attr.wpa.key_len, 1);
+ memcpy(key_buf + 16, hif_key->attr.wpa.key,
+ hif_key->attr.wpa.key_len);
- strWIDList[0].id = (u16)WID_11I_MODE;
- strWIDList[0].type = WID_CHAR;
- strWIDList[0].size = sizeof(char);
- strWIDList[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wpa.mode;
+ wid_list[0].id = (u16)WID_11I_MODE;
+ wid_list[0].type = WID_CHAR;
+ wid_list[0].size = sizeof(char);
+ wid_list[0].val = (s8 *)&hif_key->attr.wpa.mode;
- strWIDList[1].id = (u16)WID_ADD_RX_GTK;
- strWIDList[1].type = WID_STR;
- strWIDList[1].val = (s8 *)pu8keybuf;
- strWIDList[1].size = RX_MIC_KEY_MSG_LEN;
+ wid_list[1].id = (u16)WID_ADD_RX_GTK;
+ wid_list[1].type = WID_STR;
+ wid_list[1].val = (s8 *)key_buf;
+ wid_list[1].size = RX_MIC_KEY_MSG_LEN;
result = wilc_send_config_pkt(vif, SET_CFG,
- strWIDList, 2,
+ wid_list, 2,
wilc_get_vif_idx(vif));
- kfree(pu8keybuf);
+ kfree(key_buf);
complete(&hif_drv->comp_test_key_block);
- } else if (pstrHostIFkeyAttr->action & ADDKEY) {
- pu8keybuf = kzalloc(RX_MIC_KEY_MSG_LEN, GFP_KERNEL);
- if (!pu8keybuf) {
+ } else if (hif_key->action & ADDKEY) {
+ key_buf = kzalloc(RX_MIC_KEY_MSG_LEN, GFP_KERNEL);
+ if (!key_buf) {
ret = -ENOMEM;
- goto _WPARxGtk_end_case_;
+ goto out_wpa_rx_gtk;
}
if (hif_drv->hif_state == HOST_IF_CONNECTED)
- memcpy(pu8keybuf, hif_drv->assoc_bssid, ETH_ALEN);
+ memcpy(key_buf, hif_drv->assoc_bssid, ETH_ALEN);
else
netdev_err(vif->ndev, "Couldn't handle\n");
- memcpy(pu8keybuf + 6, pstrHostIFkeyAttr->attr.wpa.seq, 8);
- memcpy(pu8keybuf + 14, &pstrHostIFkeyAttr->attr.wpa.index, 1);
- memcpy(pu8keybuf + 15, &pstrHostIFkeyAttr->attr.wpa.key_len, 1);
- memcpy(pu8keybuf + 16, pstrHostIFkeyAttr->attr.wpa.key,
- pstrHostIFkeyAttr->attr.wpa.key_len);
+ memcpy(key_buf + 6, hif_key->attr.wpa.seq, 8);
+ memcpy(key_buf + 14, &hif_key->attr.wpa.index, 1);
+ memcpy(key_buf + 15, &hif_key->attr.wpa.key_len, 1);
+ memcpy(key_buf + 16, hif_key->attr.wpa.key,
+ hif_key->attr.wpa.key_len);
wid.id = (u16)WID_ADD_RX_GTK;
wid.type = WID_STR;
- wid.val = (s8 *)pu8keybuf;
+ wid.val = (s8 *)key_buf;
wid.size = RX_MIC_KEY_MSG_LEN;
result = wilc_send_config_pkt(vif, SET_CFG,
&wid, 1,
wilc_get_vif_idx(vif));
- kfree(pu8keybuf);
+ kfree(key_buf);
complete(&hif_drv->comp_test_key_block);
}
-_WPARxGtk_end_case_:
- kfree(pstrHostIFkeyAttr->attr.wpa.key);
- kfree(pstrHostIFkeyAttr->attr.wpa.seq);
+out_wpa_rx_gtk:
+ kfree(hif_key->attr.wpa.key);
+ kfree(hif_key->attr.wpa.seq);
if (ret)
return ret;
break;
case WPA_PTK:
- if (pstrHostIFkeyAttr->action & ADDKEY_AP) {
- pu8keybuf = kmalloc(PTK_KEY_MSG_LEN + 1, GFP_KERNEL);
- if (!pu8keybuf) {
+ if (hif_key->action & ADDKEY_AP) {
+ key_buf = kmalloc(PTK_KEY_MSG_LEN + 1, GFP_KERNEL);
+ if (!key_buf) {
ret = -ENOMEM;
- goto _WPAPtk_end_case_;
+ goto out_wpa_ptk;
}
- memcpy(pu8keybuf, pstrHostIFkeyAttr->attr.wpa.mac_addr, 6);
- memcpy(pu8keybuf + 6, &pstrHostIFkeyAttr->attr.wpa.index, 1);
- memcpy(pu8keybuf + 7, &pstrHostIFkeyAttr->attr.wpa.key_len, 1);
- memcpy(pu8keybuf + 8, pstrHostIFkeyAttr->attr.wpa.key,
- pstrHostIFkeyAttr->attr.wpa.key_len);
+ memcpy(key_buf, hif_key->attr.wpa.mac_addr, 6);
+ memcpy(key_buf + 6, &hif_key->attr.wpa.index, 1);
+ memcpy(key_buf + 7, &hif_key->attr.wpa.key_len, 1);
+ memcpy(key_buf + 8, hif_key->attr.wpa.key,
+ hif_key->attr.wpa.key_len);
- strWIDList[0].id = (u16)WID_11I_MODE;
- strWIDList[0].type = WID_CHAR;
- strWIDList[0].size = sizeof(char);
- strWIDList[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wpa.mode;
+ wid_list[0].id = (u16)WID_11I_MODE;
+ wid_list[0].type = WID_CHAR;
+ wid_list[0].size = sizeof(char);
+ wid_list[0].val = (s8 *)&hif_key->attr.wpa.mode;
- strWIDList[1].id = (u16)WID_ADD_PTK;
- strWIDList[1].type = WID_STR;
- strWIDList[1].val = (s8 *)pu8keybuf;
- strWIDList[1].size = PTK_KEY_MSG_LEN + 1;
+ wid_list[1].id = (u16)WID_ADD_PTK;
+ wid_list[1].type = WID_STR;
+ wid_list[1].val = (s8 *)key_buf;
+ wid_list[1].size = PTK_KEY_MSG_LEN + 1;
result = wilc_send_config_pkt(vif, SET_CFG,
- strWIDList, 2,
+ wid_list, 2,
wilc_get_vif_idx(vif));
- kfree(pu8keybuf);
+ kfree(key_buf);
complete(&hif_drv->comp_test_key_block);
- } else if (pstrHostIFkeyAttr->action & ADDKEY) {
- pu8keybuf = kmalloc(PTK_KEY_MSG_LEN, GFP_KERNEL);
- if (!pu8keybuf) {
+ } else if (hif_key->action & ADDKEY) {
+ key_buf = kmalloc(PTK_KEY_MSG_LEN, GFP_KERNEL);
+ if (!key_buf) {
netdev_err(vif->ndev, "No buffer send PTK\n");
ret = -ENOMEM;
- goto _WPAPtk_end_case_;
+ goto out_wpa_ptk;
}
- memcpy(pu8keybuf, pstrHostIFkeyAttr->attr.wpa.mac_addr, 6);
- memcpy(pu8keybuf + 6, &pstrHostIFkeyAttr->attr.wpa.key_len, 1);
- memcpy(pu8keybuf + 7, pstrHostIFkeyAttr->attr.wpa.key,
- pstrHostIFkeyAttr->attr.wpa.key_len);
+ memcpy(key_buf, hif_key->attr.wpa.mac_addr, 6);
+ memcpy(key_buf + 6, &hif_key->attr.wpa.key_len, 1);
+ memcpy(key_buf + 7, hif_key->attr.wpa.key,
+ hif_key->attr.wpa.key_len);
wid.id = (u16)WID_ADD_PTK;
wid.type = WID_STR;
- wid.val = (s8 *)pu8keybuf;
+ wid.val = (s8 *)key_buf;
wid.size = PTK_KEY_MSG_LEN;
result = wilc_send_config_pkt(vif, SET_CFG,
&wid, 1,
wilc_get_vif_idx(vif));
- kfree(pu8keybuf);
+ kfree(key_buf);
complete(&hif_drv->comp_test_key_block);
}
-_WPAPtk_end_case_:
- kfree(pstrHostIFkeyAttr->attr.wpa.key);
+out_wpa_ptk:
+ kfree(hif_key->attr.wpa.key);
if (ret)
return ret;
break;
case PMKSA:
- pu8keybuf = kmalloc((pstrHostIFkeyAttr->attr.pmkid.numpmkid * PMKSA_KEY_LEN) + 1, GFP_KERNEL);
- if (!pu8keybuf)
+ key_buf = kmalloc((hif_key->attr.pmkid.numpmkid * PMKSA_KEY_LEN) + 1, GFP_KERNEL);
+ if (!key_buf)
return -ENOMEM;
- pu8keybuf[0] = pstrHostIFkeyAttr->attr.pmkid.numpmkid;
+ key_buf[0] = hif_key->attr.pmkid.numpmkid;
- for (i = 0; i < pstrHostIFkeyAttr->attr.pmkid.numpmkid; i++) {
- memcpy(pu8keybuf + ((PMKSA_KEY_LEN * i) + 1), pstrHostIFkeyAttr->attr.pmkid.pmkidlist[i].bssid, ETH_ALEN);
- memcpy(pu8keybuf + ((PMKSA_KEY_LEN * i) + ETH_ALEN + 1), pstrHostIFkeyAttr->attr.pmkid.pmkidlist[i].pmkid, PMKID_LEN);
+ for (i = 0; i < hif_key->attr.pmkid.numpmkid; i++) {
+ memcpy(key_buf + ((PMKSA_KEY_LEN * i) + 1), hif_key->attr.pmkid.pmkidlist[i].bssid, ETH_ALEN);
+ memcpy(key_buf + ((PMKSA_KEY_LEN * i) + ETH_ALEN + 1), hif_key->attr.pmkid.pmkidlist[i].pmkid, PMKID_LEN);
}
wid.id = (u16)WID_PMKID_INFO;
wid.type = WID_STR;
- wid.val = (s8 *)pu8keybuf;
- wid.size = (pstrHostIFkeyAttr->attr.pmkid.numpmkid * PMKSA_KEY_LEN) + 1;
+ wid.val = (s8 *)key_buf;
+ wid.size = (hif_key->attr.pmkid.numpmkid * PMKSA_KEY_LEN) + 1;
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
wilc_get_vif_idx(vif));
- kfree(pu8keybuf);
+ kfree(key_buf);
break;
}
@@ -1777,17 +1780,19 @@ _WPAPtk_end_case_:
return result;
}
-static void Handle_Disconnect(struct wilc_vif *vif)
+static void handle_disconnect(struct wilc_vif *vif)
{
struct wid wid;
struct host_if_drv *hif_drv = vif->hif_drv;
-
+ struct disconnect_info disconn_info;
+ struct user_scan_req *scan_req;
+ struct user_conn_req *conn_req;
s32 result = 0;
- u16 u16DummyReasonCode = 0;
+ u16 dummy_reason_code = 0;
wid.id = (u16)WID_DISCONNECT;
wid.type = WID_CHAR;
- wid.val = (s8 *)&u16DummyReasonCode;
+ wid.val = (s8 *)&dummy_reason_code;
wid.size = sizeof(char);
wilc_optaining_ip = false;
@@ -1800,62 +1805,50 @@ static void Handle_Disconnect(struct wilc_vif *vif)
if (result) {
netdev_err(vif->ndev, "Failed to send dissconect\n");
- } else {
- struct disconnect_info strDisconnectNotifInfo;
-
- memset(&strDisconnectNotifInfo, 0, sizeof(struct disconnect_info));
+ goto out;
+ }
- strDisconnectNotifInfo.reason = 0;
- strDisconnectNotifInfo.ie = NULL;
- strDisconnectNotifInfo.ie_len = 0;
+ memset(&disconn_info, 0, sizeof(struct disconnect_info));
- if (hif_drv->usr_scan_req.scan_result) {
- del_timer(&hif_drv->scan_timer);
- hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED,
- NULL,
- hif_drv->usr_scan_req.arg,
- NULL);
- hif_drv->usr_scan_req.scan_result = NULL;
- }
+ disconn_info.reason = 0;
+ disconn_info.ie = NULL;
+ disconn_info.ie_len = 0;
+ scan_req = &hif_drv->usr_scan_req;
+ conn_req = &hif_drv->usr_conn_req;
- if (hif_drv->usr_conn_req.conn_result) {
- if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
- del_timer(&hif_drv->connect_timer);
+ if (scan_req->scan_result) {
+ del_timer(&hif_drv->scan_timer);
+ scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg,
+ NULL);
+ scan_req->scan_result = NULL;
+ }
- hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,
- NULL,
- 0,
- &strDisconnectNotifInfo,
- hif_drv->usr_conn_req.arg);
- } else {
- netdev_err(vif->ndev, "conn_result = NULL\n");
- }
+ if (conn_req->conn_result) {
+ if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
+ del_timer(&hif_drv->connect_timer);
- scan_while_connected = false;
+ conn_req->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, NULL,
+ 0, &disconn_info, conn_req->arg);
+ } else {
+ netdev_err(vif->ndev, "conn_result = NULL\n");
+ }
- hif_drv->hif_state = HOST_IF_IDLE;
+ scan_while_connected = false;
- eth_zero_addr(hif_drv->assoc_bssid);
+ hif_drv->hif_state = HOST_IF_IDLE;
- hif_drv->usr_conn_req.ssid_len = 0;
- kfree(hif_drv->usr_conn_req.ssid);
- hif_drv->usr_conn_req.ssid = NULL;
- kfree(hif_drv->usr_conn_req.bssid);
- hif_drv->usr_conn_req.bssid = NULL;
- hif_drv->usr_conn_req.ies_len = 0;
- kfree(hif_drv->usr_conn_req.ies);
- hif_drv->usr_conn_req.ies = NULL;
+ eth_zero_addr(hif_drv->assoc_bssid);
- if (join_req && join_req_vif == vif) {
- kfree(join_req);
- join_req = NULL;
- }
+ conn_req->ssid_len = 0;
+ kfree(conn_req->ssid);
+ conn_req->ssid = NULL;
+ kfree(conn_req->bssid);
+ conn_req->bssid = NULL;
+ conn_req->ies_len = 0;
+ kfree(conn_req->ies);
+ conn_req->ies = NULL;
- if (info_element && join_req_vif == vif) {
- kfree(info_element);
- info_element = NULL;
- }
- }
+out:
complete(&hif_drv->comp_test_disconn_block);
}
@@ -1869,7 +1862,7 @@ void wilc_resolve_disconnect_aberration(struct wilc_vif *vif)
wilc_disconnect(vif, 1);
}
-static void Handle_GetRssi(struct wilc_vif *vif)
+static void handle_get_rssi(struct wilc_vif *vif)
{
s32 result = 0;
struct wid wid;
@@ -1889,65 +1882,64 @@ static void Handle_GetRssi(struct wilc_vif *vif)
complete(&vif->hif_drv->comp_get_rssi);
}
-static s32 Handle_GetStatistics(struct wilc_vif *vif,
- struct rf_info *pstrStatistics)
+static s32 handle_get_statistics(struct wilc_vif *vif,
+ struct rf_info *stats)
{
- struct wid strWIDList[5];
- u32 u32WidsCount = 0, result = 0;
-
- strWIDList[u32WidsCount].id = WID_LINKSPEED;
- strWIDList[u32WidsCount].type = WID_CHAR;
- strWIDList[u32WidsCount].size = sizeof(char);
- strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->link_speed;
- u32WidsCount++;
-
- strWIDList[u32WidsCount].id = WID_RSSI;
- strWIDList[u32WidsCount].type = WID_CHAR;
- strWIDList[u32WidsCount].size = sizeof(char);
- strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->rssi;
- u32WidsCount++;
-
- strWIDList[u32WidsCount].id = WID_SUCCESS_FRAME_COUNT;
- strWIDList[u32WidsCount].type = WID_INT;
- strWIDList[u32WidsCount].size = sizeof(u32);
- strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->tx_cnt;
- u32WidsCount++;
-
- strWIDList[u32WidsCount].id = WID_RECEIVED_FRAGMENT_COUNT;
- strWIDList[u32WidsCount].type = WID_INT;
- strWIDList[u32WidsCount].size = sizeof(u32);
- strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->rx_cnt;
- u32WidsCount++;
-
- strWIDList[u32WidsCount].id = WID_FAILED_COUNT;
- strWIDList[u32WidsCount].type = WID_INT;
- strWIDList[u32WidsCount].size = sizeof(u32);
- strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->tx_fail_cnt;
- u32WidsCount++;
-
- result = wilc_send_config_pkt(vif, GET_CFG, strWIDList,
- u32WidsCount,
+ struct wid wid_list[5];
+ u32 wid_cnt = 0, result = 0;
+
+ wid_list[wid_cnt].id = WID_LINKSPEED;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ wid_list[wid_cnt].val = (s8 *)&stats->link_speed;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_RSSI;
+ wid_list[wid_cnt].type = WID_CHAR;
+ wid_list[wid_cnt].size = sizeof(char);
+ wid_list[wid_cnt].val = (s8 *)&stats->rssi;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)&stats->tx_cnt;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)&stats->rx_cnt;
+ wid_cnt++;
+
+ wid_list[wid_cnt].id = WID_FAILED_COUNT;
+ wid_list[wid_cnt].type = WID_INT;
+ wid_list[wid_cnt].size = sizeof(u32);
+ wid_list[wid_cnt].val = (s8 *)&stats->tx_fail_cnt;
+ wid_cnt++;
+
+ result = wilc_send_config_pkt(vif, GET_CFG, wid_list,
+ wid_cnt,
wilc_get_vif_idx(vif));
if (result)
netdev_err(vif->ndev, "Failed to send scan parameters\n");
- if (pstrStatistics->link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH &&
- pstrStatistics->link_speed != DEFAULT_LINK_SPEED)
+ if (stats->link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH &&
+ stats->link_speed != DEFAULT_LINK_SPEED)
wilc_enable_tcp_ack_filter(true);
- else if (pstrStatistics->link_speed != DEFAULT_LINK_SPEED)
+ else if (stats->link_speed != DEFAULT_LINK_SPEED)
wilc_enable_tcp_ack_filter(false);
- if (pstrStatistics != &vif->wilc->dummy_statistics)
+ if (stats != &vif->wilc->dummy_statistics)
complete(&hif_wait_response);
return 0;
}
-static s32 Handle_Get_InActiveTime(struct wilc_vif *vif,
- struct sta_inactive_t *strHostIfStaInactiveT)
+static s32 handle_get_inactive_time(struct wilc_vif *vif,
+ struct sta_inactive_t *hif_sta_inactive)
{
s32 result = 0;
- u8 *stamac;
struct wid wid;
struct host_if_drv *hif_drv = vif->hif_drv;
@@ -1958,11 +1950,11 @@ static s32 Handle_Get_InActiveTime(struct wilc_vif *vif,
if (!wid.val)
return -ENOMEM;
- stamac = wid.val;
- ether_addr_copy(stamac, strHostIfStaInactiveT->mac);
+ ether_addr_copy(wid.val, hif_sta_inactive->mac);
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
wilc_get_vif_idx(vif));
+ kfree(wid.val);
if (result) {
netdev_err(vif->ndev, "Failed to SET inactive time\n");
@@ -1987,64 +1979,63 @@ static s32 Handle_Get_InActiveTime(struct wilc_vif *vif,
return result;
}
-static void Handle_AddBeacon(struct wilc_vif *vif,
- struct beacon_attr *pstrSetBeaconParam)
+static void handle_add_beacon(struct wilc_vif *vif, struct beacon_attr *param)
{
s32 result = 0;
struct wid wid;
- u8 *pu8CurrByte;
+ u8 *cur_byte;
wid.id = (u16)WID_ADD_BEACON;
wid.type = WID_BIN;
- wid.size = pstrSetBeaconParam->head_len + pstrSetBeaconParam->tail_len + 16;
+ wid.size = param->head_len + param->tail_len + 16;
wid.val = kmalloc(wid.size, GFP_KERNEL);
if (!wid.val)
- goto ERRORHANDLER;
+ goto error;
- pu8CurrByte = wid.val;
- *pu8CurrByte++ = (pstrSetBeaconParam->interval & 0xFF);
- *pu8CurrByte++ = ((pstrSetBeaconParam->interval >> 8) & 0xFF);
- *pu8CurrByte++ = ((pstrSetBeaconParam->interval >> 16) & 0xFF);
- *pu8CurrByte++ = ((pstrSetBeaconParam->interval >> 24) & 0xFF);
+ cur_byte = wid.val;
+ *cur_byte++ = (param->interval & 0xFF);
+ *cur_byte++ = ((param->interval >> 8) & 0xFF);
+ *cur_byte++ = ((param->interval >> 16) & 0xFF);
+ *cur_byte++ = ((param->interval >> 24) & 0xFF);
- *pu8CurrByte++ = (pstrSetBeaconParam->dtim_period & 0xFF);
- *pu8CurrByte++ = ((pstrSetBeaconParam->dtim_period >> 8) & 0xFF);
- *pu8CurrByte++ = ((pstrSetBeaconParam->dtim_period >> 16) & 0xFF);
- *pu8CurrByte++ = ((pstrSetBeaconParam->dtim_period >> 24) & 0xFF);
+ *cur_byte++ = (param->dtim_period & 0xFF);
+ *cur_byte++ = ((param->dtim_period >> 8) & 0xFF);
+ *cur_byte++ = ((param->dtim_period >> 16) & 0xFF);
+ *cur_byte++ = ((param->dtim_period >> 24) & 0xFF);
- *pu8CurrByte++ = (pstrSetBeaconParam->head_len & 0xFF);
- *pu8CurrByte++ = ((pstrSetBeaconParam->head_len >> 8) & 0xFF);
- *pu8CurrByte++ = ((pstrSetBeaconParam->head_len >> 16) & 0xFF);
- *pu8CurrByte++ = ((pstrSetBeaconParam->head_len >> 24) & 0xFF);
+ *cur_byte++ = (param->head_len & 0xFF);
+ *cur_byte++ = ((param->head_len >> 8) & 0xFF);
+ *cur_byte++ = ((param->head_len >> 16) & 0xFF);
+ *cur_byte++ = ((param->head_len >> 24) & 0xFF);
- memcpy(pu8CurrByte, pstrSetBeaconParam->head, pstrSetBeaconParam->head_len);
- pu8CurrByte += pstrSetBeaconParam->head_len;
+ memcpy(cur_byte, param->head, param->head_len);
+ cur_byte += param->head_len;
- *pu8CurrByte++ = (pstrSetBeaconParam->tail_len & 0xFF);
- *pu8CurrByte++ = ((pstrSetBeaconParam->tail_len >> 8) & 0xFF);
- *pu8CurrByte++ = ((pstrSetBeaconParam->tail_len >> 16) & 0xFF);
- *pu8CurrByte++ = ((pstrSetBeaconParam->tail_len >> 24) & 0xFF);
+ *cur_byte++ = (param->tail_len & 0xFF);
+ *cur_byte++ = ((param->tail_len >> 8) & 0xFF);
+ *cur_byte++ = ((param->tail_len >> 16) & 0xFF);
+ *cur_byte++ = ((param->tail_len >> 24) & 0xFF);
- if (pstrSetBeaconParam->tail)
- memcpy(pu8CurrByte, pstrSetBeaconParam->tail, pstrSetBeaconParam->tail_len);
- pu8CurrByte += pstrSetBeaconParam->tail_len;
+ if (param->tail)
+ memcpy(cur_byte, param->tail, param->tail_len);
+ cur_byte += param->tail_len;
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
wilc_get_vif_idx(vif));
if (result)
netdev_err(vif->ndev, "Failed to send add beacon\n");
-ERRORHANDLER:
+error:
kfree(wid.val);
- kfree(pstrSetBeaconParam->head);
- kfree(pstrSetBeaconParam->tail);
+ kfree(param->head);
+ kfree(param->tail);
}
-static void Handle_DelBeacon(struct wilc_vif *vif)
+static void handle_del_beacon(struct wilc_vif *vif)
{
s32 result = 0;
struct wid wid;
- u8 *pu8CurrByte;
+ u8 *cur_byte;
wid.id = (u16)WID_DEL_BEACON;
wid.type = WID_CHAR;
@@ -2054,7 +2045,7 @@ static void Handle_DelBeacon(struct wilc_vif *vif)
if (!wid.val)
return;
- pu8CurrByte = wid.val;
+ cur_byte = wid.val;
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
wilc_get_vif_idx(vif));
@@ -2062,95 +2053,92 @@ static void Handle_DelBeacon(struct wilc_vif *vif)
netdev_err(vif->ndev, "Failed to send delete beacon\n");
}
-static u32 WILC_HostIf_PackStaParam(u8 *pu8Buffer,
- struct add_sta_param *pstrStationParam)
+static u32 wilc_hif_pack_sta_param(u8 *buff, struct add_sta_param *param)
{
- u8 *pu8CurrByte;
+ u8 *cur_byte;
- pu8CurrByte = pu8Buffer;
+ cur_byte = buff;
- memcpy(pu8CurrByte, pstrStationParam->bssid, ETH_ALEN);
- pu8CurrByte += ETH_ALEN;
+ memcpy(cur_byte, param->bssid, ETH_ALEN);
+ cur_byte += ETH_ALEN;
- *pu8CurrByte++ = pstrStationParam->aid & 0xFF;
- *pu8CurrByte++ = (pstrStationParam->aid >> 8) & 0xFF;
+ *cur_byte++ = param->aid & 0xFF;
+ *cur_byte++ = (param->aid >> 8) & 0xFF;
- *pu8CurrByte++ = pstrStationParam->rates_len;
- if (pstrStationParam->rates_len > 0)
- memcpy(pu8CurrByte, pstrStationParam->rates,
- pstrStationParam->rates_len);
- pu8CurrByte += pstrStationParam->rates_len;
+ *cur_byte++ = param->rates_len;
+ if (param->rates_len > 0)
+ memcpy(cur_byte, param->rates, param->rates_len);
+ cur_byte += param->rates_len;
- *pu8CurrByte++ = pstrStationParam->ht_supported;
- memcpy(pu8CurrByte, &pstrStationParam->ht_capa,
- sizeof(struct ieee80211_ht_cap));
- pu8CurrByte += sizeof(struct ieee80211_ht_cap);
+ *cur_byte++ = param->ht_supported;
+ memcpy(cur_byte, &param->ht_capa, sizeof(struct ieee80211_ht_cap));
+ cur_byte += sizeof(struct ieee80211_ht_cap);
- *pu8CurrByte++ = pstrStationParam->flags_mask & 0xFF;
- *pu8CurrByte++ = (pstrStationParam->flags_mask >> 8) & 0xFF;
+ *cur_byte++ = param->flags_mask & 0xFF;
+ *cur_byte++ = (param->flags_mask >> 8) & 0xFF;
- *pu8CurrByte++ = pstrStationParam->flags_set & 0xFF;
- *pu8CurrByte++ = (pstrStationParam->flags_set >> 8) & 0xFF;
+ *cur_byte++ = param->flags_set & 0xFF;
+ *cur_byte++ = (param->flags_set >> 8) & 0xFF;
- return pu8CurrByte - pu8Buffer;
+ return cur_byte - buff;
}
-static void Handle_AddStation(struct wilc_vif *vif,
- struct add_sta_param *pstrStationParam)
+static void handle_add_station(struct wilc_vif *vif,
+ struct add_sta_param *param)
{
s32 result = 0;
struct wid wid;
- u8 *pu8CurrByte;
+ u8 *cur_byte;
wid.id = (u16)WID_ADD_STA;
wid.type = WID_BIN;
- wid.size = WILC_ADD_STA_LENGTH + pstrStationParam->rates_len;
+ wid.size = WILC_ADD_STA_LENGTH + param->rates_len;
wid.val = kmalloc(wid.size, GFP_KERNEL);
if (!wid.val)
- goto ERRORHANDLER;
+ goto error;
- pu8CurrByte = wid.val;
- pu8CurrByte += WILC_HostIf_PackStaParam(pu8CurrByte, pstrStationParam);
+ cur_byte = wid.val;
+ cur_byte += wilc_hif_pack_sta_param(cur_byte, param);
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
wilc_get_vif_idx(vif));
if (result != 0)
netdev_err(vif->ndev, "Failed to send add station\n");
-ERRORHANDLER:
- kfree(pstrStationParam->rates);
+error:
+ kfree(param->rates);
kfree(wid.val);
}
-static void Handle_DelAllSta(struct wilc_vif *vif,
- struct del_all_sta *pstrDelAllStaParam)
+static void handle_del_all_sta(struct wilc_vif *vif,
+ struct del_all_sta *param)
{
s32 result = 0;
struct wid wid;
- u8 *pu8CurrByte;
+ u8 *curr_byte;
u8 i;
- u8 au8Zero_Buff[6] = {0};
+ u8 zero_buff[6] = {0};
wid.id = (u16)WID_DEL_ALL_STA;
wid.type = WID_STR;
- wid.size = (pstrDelAllStaParam->assoc_sta * ETH_ALEN) + 1;
+ wid.size = (param->assoc_sta * ETH_ALEN) + 1;
- wid.val = kmalloc((pstrDelAllStaParam->assoc_sta * ETH_ALEN) + 1, GFP_KERNEL);
+ wid.val = kmalloc((param->assoc_sta * ETH_ALEN) + 1, GFP_KERNEL);
if (!wid.val)
- goto ERRORHANDLER;
+ goto error;
- pu8CurrByte = wid.val;
+ curr_byte = wid.val;
- *(pu8CurrByte++) = pstrDelAllStaParam->assoc_sta;
+ *(curr_byte++) = param->assoc_sta;
for (i = 0; i < MAX_NUM_STA; i++) {
- if (memcmp(pstrDelAllStaParam->del_all_sta[i], au8Zero_Buff, ETH_ALEN))
- memcpy(pu8CurrByte, pstrDelAllStaParam->del_all_sta[i], ETH_ALEN);
+ if (memcmp(param->del_all_sta[i], zero_buff, ETH_ALEN))
+ memcpy(curr_byte, param->del_all_sta[i], ETH_ALEN);
else
continue;
- pu8CurrByte += ETH_ALEN;
+ curr_byte += ETH_ALEN;
}
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
@@ -2158,18 +2146,17 @@ static void Handle_DelAllSta(struct wilc_vif *vif,
if (result)
netdev_err(vif->ndev, "Failed to send add station\n");
-ERRORHANDLER:
+error:
kfree(wid.val);
complete(&hif_wait_response);
}
-static void Handle_DelStation(struct wilc_vif *vif,
- struct del_sta *pstrDelStaParam)
+static void handle_del_station(struct wilc_vif *vif, struct del_sta *param)
{
s32 result = 0;
struct wid wid;
- u8 *pu8CurrByte;
+ u8 *cur_byte;
wid.id = (u16)WID_REMOVE_STA;
wid.type = WID_BIN;
@@ -2177,107 +2164,108 @@ static void Handle_DelStation(struct wilc_vif *vif,
wid.val = kmalloc(wid.size, GFP_KERNEL);
if (!wid.val)
- goto ERRORHANDLER;
+ goto error;
- pu8CurrByte = wid.val;
+ cur_byte = wid.val;
- ether_addr_copy(pu8CurrByte, pstrDelStaParam->mac_addr);
+ ether_addr_copy(cur_byte, param->mac_addr);
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
wilc_get_vif_idx(vif));
if (result)
netdev_err(vif->ndev, "Failed to send add station\n");
-ERRORHANDLER:
+error:
kfree(wid.val);
}
-static void Handle_EditStation(struct wilc_vif *vif,
- struct add_sta_param *pstrStationParam)
+static void handle_edit_station(struct wilc_vif *vif,
+ struct add_sta_param *param)
{
s32 result = 0;
struct wid wid;
- u8 *pu8CurrByte;
+ u8 *cur_byte;
wid.id = (u16)WID_EDIT_STA;
wid.type = WID_BIN;
- wid.size = WILC_ADD_STA_LENGTH + pstrStationParam->rates_len;
+ wid.size = WILC_ADD_STA_LENGTH + param->rates_len;
wid.val = kmalloc(wid.size, GFP_KERNEL);
if (!wid.val)
- goto ERRORHANDLER;
+ goto error;
- pu8CurrByte = wid.val;
- pu8CurrByte += WILC_HostIf_PackStaParam(pu8CurrByte, pstrStationParam);
+ cur_byte = wid.val;
+ cur_byte += wilc_hif_pack_sta_param(cur_byte, param);
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
wilc_get_vif_idx(vif));
if (result)
netdev_err(vif->ndev, "Failed to send edit station\n");
-ERRORHANDLER:
- kfree(pstrStationParam->rates);
+error:
+ kfree(param->rates);
kfree(wid.val);
}
-static int Handle_RemainOnChan(struct wilc_vif *vif,
- struct remain_ch *pstrHostIfRemainOnChan)
+static int handle_remain_on_chan(struct wilc_vif *vif,
+ struct remain_ch *hif_remain_ch)
{
s32 result = 0;
- u8 u8remain_on_chan_flag;
+ u8 remain_on_chan_flag;
struct wid wid;
struct host_if_drv *hif_drv = vif->hif_drv;
if (!hif_drv->remain_on_ch_pending) {
- hif_drv->remain_on_ch.arg = pstrHostIfRemainOnChan->arg;
- hif_drv->remain_on_ch.expired = pstrHostIfRemainOnChan->expired;
- hif_drv->remain_on_ch.ready = pstrHostIfRemainOnChan->ready;
- hif_drv->remain_on_ch.ch = pstrHostIfRemainOnChan->ch;
- hif_drv->remain_on_ch.id = pstrHostIfRemainOnChan->id;
+ hif_drv->remain_on_ch.arg = hif_remain_ch->arg;
+ hif_drv->remain_on_ch.expired = hif_remain_ch->expired;
+ hif_drv->remain_on_ch.ready = hif_remain_ch->ready;
+ hif_drv->remain_on_ch.ch = hif_remain_ch->ch;
+ hif_drv->remain_on_ch.id = hif_remain_ch->id;
} else {
- pstrHostIfRemainOnChan->ch = hif_drv->remain_on_ch.ch;
+ hif_remain_ch->ch = hif_drv->remain_on_ch.ch;
}
if (hif_drv->usr_scan_req.scan_result) {
hif_drv->remain_on_ch_pending = 1;
result = -EBUSY;
- goto ERRORHANDLER;
+ goto error;
}
if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
result = -EBUSY;
- goto ERRORHANDLER;
+ goto error;
}
if (wilc_optaining_ip || wilc_connecting) {
result = -EBUSY;
- goto ERRORHANDLER;
+ goto error;
}
- u8remain_on_chan_flag = true;
+ remain_on_chan_flag = true;
wid.id = (u16)WID_REMAIN_ON_CHAN;
wid.type = WID_STR;
wid.size = 2;
wid.val = kmalloc(wid.size, GFP_KERNEL);
if (!wid.val) {
result = -ENOMEM;
- goto ERRORHANDLER;
+ goto error;
}
- wid.val[0] = u8remain_on_chan_flag;
- wid.val[1] = (s8)pstrHostIfRemainOnChan->ch;
+ wid.val[0] = remain_on_chan_flag;
+ wid.val[1] = (s8)hif_remain_ch->ch;
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
wilc_get_vif_idx(vif));
+ kfree(wid.val);
if (result != 0)
netdev_err(vif->ndev, "Failed to set remain on channel\n");
-ERRORHANDLER:
+error:
{
P2P_LISTEN_STATE = 1;
hif_drv->remain_on_ch_timer_vif = vif;
mod_timer(&hif_drv->remain_on_ch_timer,
jiffies +
- msecs_to_jiffies(pstrHostIfRemainOnChan->duration));
+ msecs_to_jiffies(hif_remain_ch->duration));
if (hif_drv->remain_on_ch.ready)
hif_drv->remain_on_ch.ready(hif_drv->remain_on_ch.arg);
@@ -2289,12 +2277,12 @@ ERRORHANDLER:
return result;
}
-static int Handle_RegisterFrame(struct wilc_vif *vif,
- struct reg_frame *pstrHostIfRegisterFrame)
+static int handle_register_frame(struct wilc_vif *vif,
+ struct reg_frame *hif_reg_frame)
{
s32 result = 0;
struct wid wid;
- u8 *pu8CurrByte;
+ u8 *cur_byte;
wid.id = (u16)WID_REGISTER_FRAME;
wid.type = WID_STR;
@@ -2302,16 +2290,17 @@ static int Handle_RegisterFrame(struct wilc_vif *vif,
if (!wid.val)
return -ENOMEM;
- pu8CurrByte = wid.val;
+ cur_byte = wid.val;
- *pu8CurrByte++ = pstrHostIfRegisterFrame->reg;
- *pu8CurrByte++ = pstrHostIfRegisterFrame->reg_id;
- memcpy(pu8CurrByte, &pstrHostIfRegisterFrame->frame_type, sizeof(u16));
+ *cur_byte++ = hif_reg_frame->reg;
+ *cur_byte++ = hif_reg_frame->reg_id;
+ memcpy(cur_byte, &hif_reg_frame->frame_type, sizeof(u16));
wid.size = sizeof(u16) + 2;
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
wilc_get_vif_idx(vif));
+ kfree(wid.val);
if (result) {
netdev_err(vif->ndev, "Failed to frame register\n");
result = -EINVAL;
@@ -2320,16 +2309,16 @@ static int Handle_RegisterFrame(struct wilc_vif *vif,
return result;
}
-static u32 Handle_ListenStateExpired(struct wilc_vif *vif,
- struct remain_ch *pstrHostIfRemainOnChan)
+static u32 handle_listen_state_expired(struct wilc_vif *vif,
+ struct remain_ch *hif_remain_ch)
{
- u8 u8remain_on_chan_flag;
+ u8 remain_on_chan_flag;
struct wid wid;
s32 result = 0;
struct host_if_drv *hif_drv = vif->hif_drv;
if (P2P_LISTEN_STATE) {
- u8remain_on_chan_flag = false;
+ remain_on_chan_flag = false;
wid.id = (u16)WID_REMAIN_ON_CHAN;
wid.type = WID_STR;
wid.size = 2;
@@ -2338,11 +2327,12 @@ static u32 Handle_ListenStateExpired(struct wilc_vif *vif,
if (!wid.val)
return -ENOMEM;
- wid.val[0] = u8remain_on_chan_flag;
+ wid.val[0] = remain_on_chan_flag;
wid.val[1] = FALSE_FRMWR_CHANNEL;
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
wilc_get_vif_idx(vif));
+ kfree(wid.val);
if (result != 0) {
netdev_err(vif->ndev, "Failed to set remain channel\n");
goto _done_;
@@ -2350,7 +2340,7 @@ static u32 Handle_ListenStateExpired(struct wilc_vif *vif,
if (hif_drv->remain_on_ch.expired) {
hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg,
- pstrHostIfRemainOnChan->id);
+ hif_remain_ch->id);
}
P2P_LISTEN_STATE = 0;
} else {
@@ -2362,7 +2352,7 @@ _done_:
return result;
}
-static void ListenTimerCB(struct timer_list *t)
+static void listen_timer_cb(struct timer_list *t)
{
struct host_if_drv *hif_drv = from_timer(hif_drv, t,
remain_on_ch_timer);
@@ -2382,21 +2372,21 @@ static void ListenTimerCB(struct timer_list *t)
netdev_err(vif->ndev, "wilc_mq_send fail\n");
}
-static void Handle_PowerManagement(struct wilc_vif *vif,
- struct power_mgmt_param *strPowerMgmtParam)
+static void handle_power_management(struct wilc_vif *vif,
+ struct power_mgmt_param *pm_param)
{
s32 result = 0;
struct wid wid;
- s8 s8PowerMode;
+ s8 power_mode;
wid.id = (u16)WID_POWER_MANAGEMENT;
- if (strPowerMgmtParam->enabled)
- s8PowerMode = MIN_FAST_PS;
+ if (pm_param->enabled)
+ power_mode = MIN_FAST_PS;
else
- s8PowerMode = NO_POWERSAVE;
+ power_mode = NO_POWERSAVE;
- wid.val = &s8PowerMode;
+ wid.val = &power_mode;
wid.size = sizeof(char);
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
@@ -2405,41 +2395,41 @@ static void Handle_PowerManagement(struct wilc_vif *vif,
netdev_err(vif->ndev, "Failed to send power management\n");
}
-static void Handle_SetMulticastFilter(struct wilc_vif *vif,
- struct set_multicast *strHostIfSetMulti)
+static void handle_set_mcast_filter(struct wilc_vif *vif,
+ struct set_multicast *hif_set_mc)
{
s32 result = 0;
struct wid wid;
- u8 *pu8CurrByte;
+ u8 *cur_byte;
wid.id = (u16)WID_SETUP_MULTICAST_FILTER;
wid.type = WID_BIN;
- wid.size = sizeof(struct set_multicast) + (strHostIfSetMulti->cnt * ETH_ALEN);
+ wid.size = sizeof(struct set_multicast) + (hif_set_mc->cnt * ETH_ALEN);
wid.val = kmalloc(wid.size, GFP_KERNEL);
if (!wid.val)
- goto ERRORHANDLER;
+ goto error;
- pu8CurrByte = wid.val;
- *pu8CurrByte++ = (strHostIfSetMulti->enabled & 0xFF);
- *pu8CurrByte++ = 0;
- *pu8CurrByte++ = 0;
- *pu8CurrByte++ = 0;
+ cur_byte = wid.val;
+ *cur_byte++ = (hif_set_mc->enabled & 0xFF);
+ *cur_byte++ = 0;
+ *cur_byte++ = 0;
+ *cur_byte++ = 0;
- *pu8CurrByte++ = (strHostIfSetMulti->cnt & 0xFF);
- *pu8CurrByte++ = ((strHostIfSetMulti->cnt >> 8) & 0xFF);
- *pu8CurrByte++ = ((strHostIfSetMulti->cnt >> 16) & 0xFF);
- *pu8CurrByte++ = ((strHostIfSetMulti->cnt >> 24) & 0xFF);
+ *cur_byte++ = (hif_set_mc->cnt & 0xFF);
+ *cur_byte++ = ((hif_set_mc->cnt >> 8) & 0xFF);
+ *cur_byte++ = ((hif_set_mc->cnt >> 16) & 0xFF);
+ *cur_byte++ = ((hif_set_mc->cnt >> 24) & 0xFF);
- if ((strHostIfSetMulti->cnt) > 0)
- memcpy(pu8CurrByte, wilc_multicast_mac_addr_list,
- ((strHostIfSetMulti->cnt) * ETH_ALEN));
+ if (hif_set_mc->cnt > 0)
+ memcpy(cur_byte, wilc_multicast_mac_addr_list,
+ ((hif_set_mc->cnt) * ETH_ALEN));
result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1,
wilc_get_vif_idx(vif));
if (result)
netdev_err(vif->ndev, "Failed to send setup multicast\n");
-ERRORHANDLER:
+error:
kfree(wid.val);
}
@@ -2498,20 +2488,20 @@ static void host_if_work(struct work_struct *work)
break;
case HOST_IF_MSG_CONNECT:
- Handle_Connect(msg->vif, &msg->body.con_info);
+ handle_connect(msg->vif, &msg->body.con_info);
break;
case HOST_IF_MSG_RCVD_NTWRK_INFO:
- Handle_RcvdNtwrkInfo(msg->vif, &msg->body.net_info);
+ handle_rcvd_ntwrk_info(msg->vif, &msg->body.net_info);
break;
case HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO:
- Handle_RcvdGnrlAsyncInfo(msg->vif,
- &msg->body.async_info);
+ handle_rcvd_gnrl_async_info(msg->vif,
+ &msg->body.async_info);
break;
case HOST_IF_MSG_KEY:
- Handle_Key(msg->vif, &msg->body.key_info);
+ handle_key(msg->vif, &msg->body.key_info);
break;
case HOST_IF_MSG_CFG_PARAMS:
@@ -2523,7 +2513,7 @@ static void host_if_work(struct work_struct *work)
break;
case HOST_IF_MSG_DISCONNECT:
- Handle_Disconnect(msg->vif);
+ handle_disconnect(msg->vif);
break;
case HOST_IF_MSG_RCVD_SCAN_COMPLETE:
@@ -2532,58 +2522,58 @@ static void host_if_work(struct work_struct *work)
if (!wilc_wlan_get_num_conn_ifcs(wilc))
wilc_chip_sleep_manually(wilc);
- Handle_ScanDone(msg->vif, SCAN_EVENT_DONE);
+ handle_scan_done(msg->vif, SCAN_EVENT_DONE);
if (msg->vif->hif_drv->remain_on_ch_pending)
- Handle_RemainOnChan(msg->vif,
- &msg->body.remain_on_ch);
+ handle_remain_on_chan(msg->vif,
+ &msg->body.remain_on_ch);
break;
case HOST_IF_MSG_GET_RSSI:
- Handle_GetRssi(msg->vif);
+ handle_get_rssi(msg->vif);
break;
case HOST_IF_MSG_GET_STATISTICS:
- Handle_GetStatistics(msg->vif,
- (struct rf_info *)msg->body.data);
+ handle_get_statistics(msg->vif,
+ (struct rf_info *)msg->body.data);
break;
case HOST_IF_MSG_ADD_BEACON:
- Handle_AddBeacon(msg->vif, &msg->body.beacon_info);
+ handle_add_beacon(msg->vif, &msg->body.beacon_info);
break;
case HOST_IF_MSG_DEL_BEACON:
- Handle_DelBeacon(msg->vif);
+ handle_del_beacon(msg->vif);
break;
case HOST_IF_MSG_ADD_STATION:
- Handle_AddStation(msg->vif, &msg->body.add_sta_info);
+ handle_add_station(msg->vif, &msg->body.add_sta_info);
break;
case HOST_IF_MSG_DEL_STATION:
- Handle_DelStation(msg->vif, &msg->body.del_sta_info);
+ handle_del_station(msg->vif, &msg->body.del_sta_info);
break;
case HOST_IF_MSG_EDIT_STATION:
- Handle_EditStation(msg->vif, &msg->body.edit_sta_info);
+ handle_edit_station(msg->vif, &msg->body.edit_sta_info);
break;
case HOST_IF_MSG_GET_INACTIVETIME:
- Handle_Get_InActiveTime(msg->vif, &msg->body.mac_info);
+ handle_get_inactive_time(msg->vif, &msg->body.mac_info);
break;
case HOST_IF_MSG_SCAN_TIMER_FIRED:
- Handle_ScanDone(msg->vif, SCAN_EVENT_ABORTED);
+ handle_scan_done(msg->vif, SCAN_EVENT_ABORTED);
break;
case HOST_IF_MSG_CONNECT_TIMER_FIRED:
- Handle_ConnectTimeout(msg->vif);
+ handle_connect_timeout(msg->vif);
break;
case HOST_IF_MSG_POWER_MGMT:
- Handle_PowerManagement(msg->vif,
- &msg->body.pwr_mgmt_info);
+ handle_power_management(msg->vif,
+ &msg->body.pwr_mgmt_info);
break;
case HOST_IF_MSG_SET_WFIDRV_HANDLER:
@@ -2610,23 +2600,23 @@ static void host_if_work(struct work_struct *work)
break;
case HOST_IF_MSG_REMAIN_ON_CHAN:
- Handle_RemainOnChan(msg->vif, &msg->body.remain_on_ch);
+ handle_remain_on_chan(msg->vif, &msg->body.remain_on_ch);
break;
case HOST_IF_MSG_REGISTER_FRAME:
- Handle_RegisterFrame(msg->vif, &msg->body.reg_frame);
+ handle_register_frame(msg->vif, &msg->body.reg_frame);
break;
case HOST_IF_MSG_LISTEN_TIMER_FIRED:
- Handle_ListenStateExpired(msg->vif, &msg->body.remain_on_ch);
+ handle_listen_state_expired(msg->vif, &msg->body.remain_on_ch);
break;
case HOST_IF_MSG_SET_MULTICAST_FILTER:
- Handle_SetMulticastFilter(msg->vif, &msg->body.multicast_info);
+ handle_set_mcast_filter(msg->vif, &msg->body.multicast_info);
break;
case HOST_IF_MSG_DEL_ALL_STA:
- Handle_DelAllSta(msg->vif, &msg->body.del_all_sta_info);
+ handle_del_all_sta(msg->vif, &msg->body.del_all_sta_info);
break;
case HOST_IF_MSG_SET_TX_POWER:
@@ -2647,7 +2637,7 @@ free_msg:
complete(&hif_thread_comp);
}
-static void TimerCB_Scan(struct timer_list *t)
+static void timer_scan_cb(struct timer_list *t)
{
struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer);
struct wilc_vif *vif = hif_drv->scan_timer_vif;
@@ -2660,7 +2650,7 @@ static void TimerCB_Scan(struct timer_list *t)
wilc_enqueue_cmd(&msg);
}
-static void TimerCB_Connect(struct timer_list *t)
+static void timer_connect_cb(struct timer_list *t)
{
struct host_if_drv *hif_drv = from_timer(hif_drv, t,
connect_timer);
@@ -2674,13 +2664,13 @@ static void TimerCB_Connect(struct timer_list *t)
wilc_enqueue_cmd(&msg);
}
-s32 wilc_remove_key(struct host_if_drv *hif_drv, const u8 *pu8StaAddress)
+s32 wilc_remove_key(struct host_if_drv *hif_drv, const u8 *sta_addr)
{
struct wid wid;
wid.id = (u16)WID_REMOVE_KEY;
wid.type = WID_STR;
- wid.val = (s8 *)pu8StaAddress;
+ wid.val = (s8 *)sta_addr;
wid.size = 6;
return 0;
@@ -2747,7 +2737,7 @@ int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index)
int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
u8 index)
{
- int result = 0;
+ int result;
struct host_if_msg msg;
struct host_if_drv *hif_drv = vif->hif_drv;
@@ -2770,17 +2760,20 @@ int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
msg.body.key_info.attr.wep.index = index;
result = wilc_enqueue_cmd(&msg);
- if (result)
+ if (result) {
netdev_err(vif->ndev, "STA - WEP Key\n");
- wait_for_completion(&hif_drv->comp_test_key_block);
+ kfree(msg.body.key_info.attr.wep.key);
+ return result;
+ }
- return result;
+ wait_for_completion(&hif_drv->comp_test_key_block);
+ return 0;
}
int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
u8 index, u8 mode, enum AUTHTYPE auth_type)
{
- int result = 0;
+ int result;
struct host_if_msg msg;
struct host_if_drv *hif_drv = vif->hif_drv;
@@ -2805,20 +2798,21 @@ int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
msg.body.key_info.attr.wep.auth_type = auth_type;
result = wilc_enqueue_cmd(&msg);
-
- if (result)
+ if (result) {
netdev_err(vif->ndev, "AP - WEP Key\n");
- else
- wait_for_completion(&hif_drv->comp_test_key_block);
+ kfree(msg.body.key_info.attr.wep.key);
+ return result;
+ }
- return result;
+ wait_for_completion(&hif_drv->comp_test_key_block);
+ return 0;
}
int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
u8 mode, u8 cipher_mode, u8 index)
{
- int result = 0;
+ int result;
struct host_if_msg msg;
struct host_if_drv *hif_drv = vif->hif_drv;
u8 key_len = ptk_key_len;
@@ -2850,10 +2844,12 @@ int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
return -ENOMEM;
if (rx_mic)
- memcpy(msg.body.key_info.attr.wpa.key + 16, rx_mic, RX_MIC_KEY_LEN);
+ memcpy(msg.body.key_info.attr.wpa.key + 16, rx_mic,
+ RX_MIC_KEY_LEN);
if (tx_mic)
- memcpy(msg.body.key_info.attr.wpa.key + 24, tx_mic, TX_MIC_KEY_LEN);
+ memcpy(msg.body.key_info.attr.wpa.key + 24, tx_mic,
+ TX_MIC_KEY_LEN);
msg.body.key_info.attr.wpa.key_len = key_len;
msg.body.key_info.attr.wpa.mac_addr = mac_addr;
@@ -2861,13 +2857,14 @@ int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
msg.vif = vif;
result = wilc_enqueue_cmd(&msg);
-
- if (result)
+ if (result) {
netdev_err(vif->ndev, "PTK Key\n");
- else
- wait_for_completion(&hif_drv->comp_test_key_block);
+ kfree(msg.body.key_info.attr.wpa.key);
+ return result;
+ }
- return result;
+ wait_for_completion(&hif_drv->comp_test_key_block);
+ return 0;
}
int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
@@ -2875,7 +2872,7 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
const u8 *rx_mic, const u8 *tx_mic, u8 mode,
u8 cipher_mode)
{
- int result = 0;
+ int result;
struct host_if_msg msg;
struct host_if_drv *hif_drv = vif->hif_drv;
u8 key_len = gtk_key_len;
@@ -2914,8 +2911,10 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
msg.body.key_info.attr.wpa.key = kmemdup(rx_gtk,
key_len,
GFP_KERNEL);
- if (!msg.body.key_info.attr.wpa.key)
+ if (!msg.body.key_info.attr.wpa.key) {
+ kfree(msg.body.key_info.attr.wpa.seq);
return -ENOMEM;
+ }
if (rx_mic)
memcpy(msg.body.key_info.attr.wpa.key + 16, rx_mic,
@@ -2930,12 +2929,15 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
msg.body.key_info.attr.wpa.seq_len = key_rsc_len;
result = wilc_enqueue_cmd(&msg);
- if (result)
+ if (result) {
netdev_err(vif->ndev, "RX GTK\n");
- else
- wait_for_completion(&hif_drv->comp_test_key_block);
+ kfree(msg.body.key_info.attr.wpa.seq);
+ kfree(msg.body.key_info.attr.wpa.key);
+ return result;
+ }
- return result;
+ wait_for_completion(&hif_drv->comp_test_key_block);
+ return 0;
}
int wilc_set_pmkid_info(struct wilc_vif *vif,
@@ -3080,27 +3082,27 @@ int wilc_disconnect(struct wilc_vif *vif, u16 reason_code)
}
static s32 host_int_get_assoc_res_info(struct wilc_vif *vif,
- u8 *pu8AssocRespInfo,
- u32 u32MaxAssocRespInfoLen,
- u32 *pu32RcvdAssocRespInfoLen)
+ u8 *assoc_resp_info,
+ u32 max_assoc_resp_info_len,
+ u32 *rcvd_assoc_resp_info_len)
{
s32 result = 0;
struct wid wid;
wid.id = (u16)WID_ASSOC_RES_INFO;
wid.type = WID_STR;
- wid.val = pu8AssocRespInfo;
- wid.size = u32MaxAssocRespInfoLen;
+ wid.val = assoc_resp_info;
+ wid.size = max_assoc_resp_info_len;
result = wilc_send_config_pkt(vif, GET_CFG, &wid, 1,
wilc_get_vif_idx(vif));
if (result) {
- *pu32RcvdAssocRespInfoLen = 0;
+ *rcvd_assoc_resp_info_len = 0;
netdev_err(vif->ndev, "Failed to send association response\n");
return -EINVAL;
}
- *pu32RcvdAssocRespInfoLen = wid.size;
+ *rcvd_assoc_resp_info_len = wid.size;
return result;
}
@@ -3165,7 +3167,7 @@ int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode)
}
s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac,
- u32 *pu32InactiveTime)
+ u32 *out_val)
{
s32 result = 0;
struct host_if_msg msg;
@@ -3188,7 +3190,7 @@ s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac,
else
wait_for_completion(&hif_drv->comp_inactive_time);
- *pu32InactiveTime = inactive_time;
+ *out_val = inactive_time;
return result;
}
@@ -3316,7 +3318,7 @@ int wilc_hif_set_cfg(struct wilc_vif *vif,
return wilc_enqueue_cmd(&msg);
}
-static void GetPeriodicRSSI(struct timer_list *unused)
+static void get_periodic_rssi(struct timer_list *unused)
{
struct wilc_vif *vif = periodic_rssi_vif;
@@ -3381,13 +3383,13 @@ int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
}
periodic_rssi_vif = vif;
- timer_setup(&periodic_rssi, GetPeriodicRSSI, 0);
+ timer_setup(&periodic_rssi, get_periodic_rssi, 0);
mod_timer(&periodic_rssi, jiffies + msecs_to_jiffies(5000));
}
- timer_setup(&hif_drv->scan_timer, TimerCB_Scan, 0);
- timer_setup(&hif_drv->connect_timer, TimerCB_Connect, 0);
- timer_setup(&hif_drv->remain_on_ch_timer, ListenTimerCB, 0);
+ timer_setup(&hif_drv->scan_timer, timer_scan_cb, 0);
+ timer_setup(&hif_drv->connect_timer, timer_connect_cb, 0);
+ timer_setup(&hif_drv->remain_on_ch_timer, listen_timer_cb, 0);
mutex_init(&hif_drv->cfg_values_lock);
mutex_lock(&hif_drv->cfg_values_lock);
@@ -3434,7 +3436,8 @@ int wilc_deinit(struct wilc_vif *vif)
if (hif_drv->usr_scan_req.scan_result) {
hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL,
- hif_drv->usr_scan_req.arg, NULL);
+ hif_drv->usr_scan_req.arg,
+ NULL);
hif_drv->usr_scan_req.scan_result = NULL;
}
@@ -3473,7 +3476,10 @@ void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length)
struct host_if_drv *hif_drv = NULL;
struct wilc_vif *vif;
- id = ((buffer[length - 4]) | (buffer[length - 3] << 8) | (buffer[length - 2] << 16) | (buffer[length - 1] << 24));
+ id = buffer[length - 4];
+ id |= (buffer[length - 3] << 8);
+ id |= (buffer[length - 2] << 16);
+ id |= (buffer[length - 1] << 24);
vif = wilc_get_vif_from_idx(wilc, id);
if (!vif)
return;
@@ -3490,12 +3496,15 @@ void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length)
msg.vif = vif;
msg.body.net_info.len = length;
- msg.body.net_info.buffer = kmalloc(length, GFP_KERNEL);
- memcpy(msg.body.net_info.buffer, buffer, length);
+ msg.body.net_info.buffer = kmemdup(buffer, length, GFP_KERNEL);
+ if (!msg.body.net_info.buffer)
+ return;
result = wilc_enqueue_cmd(&msg);
- if (result)
+ if (result) {
netdev_err(vif->ndev, "message parameters (%d)\n", result);
+ kfree(msg.body.net_info.buffer);
+ }
}
void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length)
@@ -3508,7 +3517,10 @@ void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length)
mutex_lock(&hif_deinit_lock);
- id = ((buffer[length - 4]) | (buffer[length - 3] << 8) | (buffer[length - 2] << 16) | (buffer[length - 1] << 24));
+ id = buffer[length - 4];
+ id |= (buffer[length - 3] << 8);
+ id |= (buffer[length - 2] << 16);
+ id |= (buffer[length - 1] << 24);
vif = wilc_get_vif_from_idx(wilc, id);
if (!vif) {
mutex_unlock(&hif_deinit_lock);
@@ -3534,12 +3546,17 @@ void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length)
msg.vif = vif;
msg.body.async_info.len = length;
- msg.body.async_info.buffer = kmalloc(length, GFP_KERNEL);
- memcpy(msg.body.async_info.buffer, buffer, length);
+ msg.body.async_info.buffer = kmemdup(buffer, length, GFP_KERNEL);
+ if (!msg.body.async_info.buffer) {
+ mutex_unlock(&hif_deinit_lock);
+ return;
+ }
result = wilc_enqueue_cmd(&msg);
- if (result)
+ if (result) {
netdev_err(vif->ndev, "synchronous info (%d)\n", result);
+ kfree(msg.body.async_info.buffer);
+ }
mutex_unlock(&hif_deinit_lock);
}
@@ -3552,7 +3569,10 @@ void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length)
struct host_if_drv *hif_drv = NULL;
struct wilc_vif *vif;
- id = ((buffer[length - 4]) | (buffer[length - 3] << 8) | (buffer[length - 2] << 16) | (buffer[length - 1] << 24));
+ id = buffer[length - 4];
+ id |= buffer[length - 3] << 8;
+ id |= buffer[length - 2] << 16;
+ id |= buffer[length - 1] << 24;
vif = wilc_get_vif_from_idx(wilc, id);
if (!vif)
return;
@@ -3673,7 +3693,7 @@ int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
beacon_info->head = kmemdup(head, head_len, GFP_KERNEL);
if (!beacon_info->head) {
result = -ENOMEM;
- goto ERRORHANDLER;
+ goto error;
}
beacon_info->tail_len = tail_len;
@@ -3681,7 +3701,7 @@ int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
beacon_info->tail = kmemdup(tail, tail_len, GFP_KERNEL);
if (!beacon_info->tail) {
result = -ENOMEM;
- goto ERRORHANDLER;
+ goto error;
}
} else {
beacon_info->tail = NULL;
@@ -3691,7 +3711,7 @@ int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
if (result)
netdev_err(vif->ndev, "wilc mq send fail\n");
-ERRORHANDLER:
+error:
if (result) {
kfree(beacon_info->head);
@@ -3737,8 +3757,10 @@ int wilc_add_station(struct wilc_vif *vif, struct add_sta_param *sta_param)
}
result = wilc_enqueue_cmd(&msg);
- if (result)
+ if (result) {
netdev_err(vif->ndev, "wilc_mq_send fail\n");
+ kfree(add_sta_info->rates);
+ }
return result;
}
@@ -3780,7 +3802,8 @@ int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN])
for (i = 0; i < MAX_NUM_STA; i++) {
if (memcmp(mac_addr[i], zero_addr, ETH_ALEN)) {
- memcpy(del_all_sta_info->del_all_sta[i], mac_addr[i], ETH_ALEN);
+ memcpy(del_all_sta_info->del_all_sta[i], mac_addr[i],
+ ETH_ALEN);
assoc_sta++;
}
}
@@ -3820,8 +3843,10 @@ int wilc_edit_station(struct wilc_vif *vif,
}
result = wilc_enqueue_cmd(&msg);
- if (result)
+ if (result) {
netdev_err(vif->ndev, "wilc_mq_send fail\n");
+ kfree(add_sta_info->rates);
+ }
return result;
}
@@ -3870,152 +3895,152 @@ int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled,
return result;
}
-static void *host_int_ParseJoinBssParam(struct network_info *ptstrNetworkInfo)
+static void *host_int_parse_join_bss_param(struct network_info *info)
{
- struct join_bss_param *pNewJoinBssParam = NULL;
- u8 *pu8IEs;
- u16 u16IEsLen;
+ struct join_bss_param *param = NULL;
+ u8 *ies;
+ u16 ies_len;
u16 index = 0;
- u8 suppRatesNo = 0;
- u8 extSuppRatesNo;
- u16 jumpOffset;
- u8 pcipherCount;
- u8 authCount;
- u8 pcipherTotalCount = 0;
- u8 authTotalCount = 0;
+ u8 rates_no = 0;
+ u8 ext_rates_no;
+ u16 offset;
+ u8 pcipher_cnt;
+ u8 auth_cnt;
+ u8 pcipher_total_cnt = 0;
+ u8 auth_total_cnt = 0;
u8 i, j;
- pu8IEs = ptstrNetworkInfo->ies;
- u16IEsLen = ptstrNetworkInfo->ies_len;
-
- pNewJoinBssParam = kzalloc(sizeof(*pNewJoinBssParam), GFP_KERNEL);
- if (pNewJoinBssParam) {
- pNewJoinBssParam->dtim_period = ptstrNetworkInfo->dtim_period;
- pNewJoinBssParam->beacon_period = ptstrNetworkInfo->beacon_period;
- pNewJoinBssParam->cap_info = ptstrNetworkInfo->cap_info;
- memcpy(pNewJoinBssParam->bssid, ptstrNetworkInfo->bssid, 6);
- memcpy((u8 *)pNewJoinBssParam->ssid, ptstrNetworkInfo->ssid,
- ptstrNetworkInfo->ssid_len + 1);
- pNewJoinBssParam->ssid_len = ptstrNetworkInfo->ssid_len;
- memset(pNewJoinBssParam->rsn_pcip_policy, 0xFF, 3);
- memset(pNewJoinBssParam->rsn_auth_policy, 0xFF, 3);
-
- while (index < u16IEsLen) {
- if (pu8IEs[index] == SUPP_RATES_IE) {
- suppRatesNo = pu8IEs[index + 1];
- pNewJoinBssParam->supp_rates[0] = suppRatesNo;
- index += 2;
-
- for (i = 0; i < suppRatesNo; i++)
- pNewJoinBssParam->supp_rates[i + 1] = pu8IEs[index + i];
-
- index += suppRatesNo;
- } else if (pu8IEs[index] == EXT_SUPP_RATES_IE) {
- extSuppRatesNo = pu8IEs[index + 1];
- if (extSuppRatesNo > (MAX_RATES_SUPPORTED - suppRatesNo))
- pNewJoinBssParam->supp_rates[0] = MAX_RATES_SUPPORTED;
- else
- pNewJoinBssParam->supp_rates[0] += extSuppRatesNo;
- index += 2;
- for (i = 0; i < (pNewJoinBssParam->supp_rates[0] - suppRatesNo); i++)
- pNewJoinBssParam->supp_rates[suppRatesNo + i + 1] = pu8IEs[index + i];
-
- index += extSuppRatesNo;
- } else if (pu8IEs[index] == HT_CAPABILITY_IE) {
- pNewJoinBssParam->ht_capable = true;
- index += pu8IEs[index + 1] + 2;
- } else if ((pu8IEs[index] == WMM_IE) &&
- (pu8IEs[index + 2] == 0x00) && (pu8IEs[index + 3] == 0x50) &&
- (pu8IEs[index + 4] == 0xF2) &&
- (pu8IEs[index + 5] == 0x02) &&
- ((pu8IEs[index + 6] == 0x00) || (pu8IEs[index + 6] == 0x01)) &&
- (pu8IEs[index + 7] == 0x01)) {
- pNewJoinBssParam->wmm_cap = true;
-
- if (pu8IEs[index + 8] & BIT(7))
- pNewJoinBssParam->uapsd_cap = true;
- index += pu8IEs[index + 1] + 2;
- } else if ((pu8IEs[index] == P2P_IE) &&
- (pu8IEs[index + 2] == 0x50) && (pu8IEs[index + 3] == 0x6f) &&
- (pu8IEs[index + 4] == 0x9a) &&
- (pu8IEs[index + 5] == 0x09) && (pu8IEs[index + 6] == 0x0c)) {
- u16 u16P2P_count;
-
- pNewJoinBssParam->tsf = ptstrNetworkInfo->tsf_lo;
- pNewJoinBssParam->noa_enabled = 1;
- pNewJoinBssParam->idx = pu8IEs[index + 9];
-
- if (pu8IEs[index + 10] & BIT(7)) {
- pNewJoinBssParam->opp_enabled = 1;
- pNewJoinBssParam->ct_window = pu8IEs[index + 10];
- } else {
- pNewJoinBssParam->opp_enabled = 0;
- }
+ ies = info->ies;
+ ies_len = info->ies_len;
- pNewJoinBssParam->cnt = pu8IEs[index + 11];
- u16P2P_count = index + 12;
+ param = kzalloc(sizeof(*param), GFP_KERNEL);
+ if (!param)
+ return NULL;
- memcpy(pNewJoinBssParam->duration, pu8IEs + u16P2P_count, 4);
- u16P2P_count += 4;
+ param->dtim_period = info->dtim_period;
+ param->beacon_period = info->beacon_period;
+ param->cap_info = info->cap_info;
+ memcpy(param->bssid, info->bssid, 6);
+ memcpy((u8 *)param->ssid, info->ssid, info->ssid_len + 1);
+ param->ssid_len = info->ssid_len;
+ memset(param->rsn_pcip_policy, 0xFF, 3);
+ memset(param->rsn_auth_policy, 0xFF, 3);
+
+ while (index < ies_len) {
+ if (ies[index] == SUPP_RATES_IE) {
+ rates_no = ies[index + 1];
+ param->supp_rates[0] = rates_no;
+ index += 2;
+
+ for (i = 0; i < rates_no; i++)
+ param->supp_rates[i + 1] = ies[index + i];
+
+ index += rates_no;
+ } else if (ies[index] == EXT_SUPP_RATES_IE) {
+ ext_rates_no = ies[index + 1];
+ if (ext_rates_no > (MAX_RATES_SUPPORTED - rates_no))
+ param->supp_rates[0] = MAX_RATES_SUPPORTED;
+ else
+ param->supp_rates[0] += ext_rates_no;
+ index += 2;
+ for (i = 0; i < (param->supp_rates[0] - rates_no); i++)
+ param->supp_rates[rates_no + i + 1] = ies[index + i];
+
+ index += ext_rates_no;
+ } else if (ies[index] == HT_CAPABILITY_IE) {
+ param->ht_capable = true;
+ index += ies[index + 1] + 2;
+ } else if ((ies[index] == WMM_IE) &&
+ (ies[index + 2] == 0x00) && (ies[index + 3] == 0x50) &&
+ (ies[index + 4] == 0xF2) &&
+ (ies[index + 5] == 0x02) &&
+ ((ies[index + 6] == 0x00) || (ies[index + 6] == 0x01)) &&
+ (ies[index + 7] == 0x01)) {
+ param->wmm_cap = true;
+
+ if (ies[index + 8] & BIT(7))
+ param->uapsd_cap = true;
+ index += ies[index + 1] + 2;
+ } else if ((ies[index] == P2P_IE) &&
+ (ies[index + 2] == 0x50) && (ies[index + 3] == 0x6f) &&
+ (ies[index + 4] == 0x9a) &&
+ (ies[index + 5] == 0x09) && (ies[index + 6] == 0x0c)) {
+ u16 p2p_cnt;
+
+ param->tsf = info->tsf_lo;
+ param->noa_enabled = 1;
+ param->idx = ies[index + 9];
+
+ if (ies[index + 10] & BIT(7)) {
+ param->opp_enabled = 1;
+ param->ct_window = ies[index + 10];
+ } else {
+ param->opp_enabled = 0;
+ }
- memcpy(pNewJoinBssParam->interval, pu8IEs + u16P2P_count, 4);
- u16P2P_count += 4;
+ param->cnt = ies[index + 11];
+ p2p_cnt = index + 12;
- memcpy(pNewJoinBssParam->start_time, pu8IEs + u16P2P_count, 4);
+ memcpy(param->duration, ies + p2p_cnt, 4);
+ p2p_cnt += 4;
- index += pu8IEs[index + 1] + 2;
- } else if ((pu8IEs[index] == RSN_IE) ||
- ((pu8IEs[index] == WPA_IE) && (pu8IEs[index + 2] == 0x00) &&
- (pu8IEs[index + 3] == 0x50) && (pu8IEs[index + 4] == 0xF2) &&
- (pu8IEs[index + 5] == 0x01))) {
- u16 rsnIndex = index;
+ memcpy(param->interval, ies + p2p_cnt, 4);
+ p2p_cnt += 4;
- if (pu8IEs[rsnIndex] == RSN_IE) {
- pNewJoinBssParam->mode_802_11i = 2;
- } else {
- if (pNewJoinBssParam->mode_802_11i == 0)
- pNewJoinBssParam->mode_802_11i = 1;
- rsnIndex += 4;
- }
+ memcpy(param->start_time, ies + p2p_cnt, 4);
- rsnIndex += 7;
- pNewJoinBssParam->rsn_grp_policy = pu8IEs[rsnIndex];
- rsnIndex++;
- jumpOffset = pu8IEs[rsnIndex] * 4;
- pcipherCount = (pu8IEs[rsnIndex] > 3) ? 3 : pu8IEs[rsnIndex];
- rsnIndex += 2;
+ index += ies[index + 1] + 2;
+ } else if ((ies[index] == RSN_IE) ||
+ ((ies[index] == WPA_IE) && (ies[index + 2] == 0x00) &&
+ (ies[index + 3] == 0x50) && (ies[index + 4] == 0xF2) &&
+ (ies[index + 5] == 0x01))) {
+ u16 rsn_idx = index;
- for (i = pcipherTotalCount, j = 0; i < pcipherCount + pcipherTotalCount && i < 3; i++, j++)
- pNewJoinBssParam->rsn_pcip_policy[i] = pu8IEs[rsnIndex + ((j + 1) * 4) - 1];
+ if (ies[rsn_idx] == RSN_IE) {
+ param->mode_802_11i = 2;
+ } else {
+ if (param->mode_802_11i == 0)
+ param->mode_802_11i = 1;
+ rsn_idx += 4;
+ }
- pcipherTotalCount += pcipherCount;
- rsnIndex += jumpOffset;
+ rsn_idx += 7;
+ param->rsn_grp_policy = ies[rsn_idx];
+ rsn_idx++;
+ offset = ies[rsn_idx] * 4;
+ pcipher_cnt = (ies[rsn_idx] > 3) ? 3 : ies[rsn_idx];
+ rsn_idx += 2;
- jumpOffset = pu8IEs[rsnIndex] * 4;
+ for (i = pcipher_total_cnt, j = 0; i < pcipher_cnt + pcipher_total_cnt && i < 3; i++, j++)
+ param->rsn_pcip_policy[i] = ies[rsn_idx + ((j + 1) * 4) - 1];
- authCount = (pu8IEs[rsnIndex] > 3) ? 3 : pu8IEs[rsnIndex];
- rsnIndex += 2;
+ pcipher_total_cnt += pcipher_cnt;
+ rsn_idx += offset;
- for (i = authTotalCount, j = 0; i < authTotalCount + authCount; i++, j++)
- pNewJoinBssParam->rsn_auth_policy[i] = pu8IEs[rsnIndex + ((j + 1) * 4) - 1];
+ offset = ies[rsn_idx] * 4;
- authTotalCount += authCount;
- rsnIndex += jumpOffset;
+ auth_cnt = (ies[rsn_idx] > 3) ? 3 : ies[rsn_idx];
+ rsn_idx += 2;
- if (pu8IEs[index] == RSN_IE) {
- pNewJoinBssParam->rsn_cap[0] = pu8IEs[rsnIndex];
- pNewJoinBssParam->rsn_cap[1] = pu8IEs[rsnIndex + 1];
- rsnIndex += 2;
- }
- pNewJoinBssParam->rsn_found = true;
- index += pu8IEs[index + 1] + 2;
- } else {
- index += pu8IEs[index + 1] + 2;
+ for (i = auth_total_cnt, j = 0; i < auth_total_cnt + auth_cnt; i++, j++)
+ param->rsn_auth_policy[i] = ies[rsn_idx + ((j + 1) * 4) - 1];
+
+ auth_total_cnt += auth_cnt;
+ rsn_idx += offset;
+
+ if (ies[index] == RSN_IE) {
+ param->rsn_cap[0] = ies[rsn_idx];
+ param->rsn_cap[1] = ies[rsn_idx + 1];
+ rsn_idx += 2;
}
+ param->rsn_found = true;
+ index += ies[index + 1] + 2;
+ } else {
+ index += ies[index + 1] + 2;
}
}
- return (void *)pNewJoinBssParam;
+ return (void *)param;
}
int wilc_setup_ipaddress(struct wilc_vif *vif, u8 *ip_addr, u8 idx)
diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h
index aa914d69ab0d..4b60b1822e91 100644
--- a/drivers/staging/wilc1000/host_interface.h
+++ b/drivers/staging/wilc1000/host_interface.h
@@ -304,7 +304,7 @@ struct add_sta_param {
};
struct wilc_vif;
-s32 wilc_remove_key(struct host_if_drv *hWFIDrv, const u8 *pu8StaAddress);
+s32 wilc_remove_key(struct host_if_drv *hif_drv, const u8 *sta_addr);
int wilc_remove_wep_key(struct wilc_vif *vif, u8 index);
int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index);
int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
diff --git a/drivers/staging/wilc1000/linux_mon.c b/drivers/staging/wilc1000/linux_mon.c
index 91d49c4738dc..169213f24faf 100644
--- a/drivers/staging/wilc1000/linux_mon.c
+++ b/drivers/staging/wilc1000/linux_mon.c
@@ -40,9 +40,6 @@ static u8 broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive*/
-#define IS_MANAGMEMENT 0x100
-#define IS_MANAGMEMENT_CALLBACK 0x080
-#define IS_MGMT_STATUS_SUCCES 0x040
#define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff)
void WILC_WFI_monitor_rx(u8 *buff, u32 size)
@@ -150,7 +147,7 @@ static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len)
if (!mgmt_tx)
return -ENOMEM;
- mgmt_tx->buff = kmalloc(len, GFP_ATOMIC);
+ mgmt_tx->buff = kmemdup(buf, len, GFP_ATOMIC);
if (!mgmt_tx->buff) {
kfree(mgmt_tx);
return -ENOMEM;
@@ -158,7 +155,6 @@ static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len)
mgmt_tx->size = len;
- memcpy(mgmt_tx->buff, buf, len);
wilc_wlan_txq_add_mgmt_pkt(dev, mgmt_tx, mgmt_tx->buff, mgmt_tx->size,
mgmt_tx_complete);
@@ -256,7 +252,7 @@ static const struct net_device_ops wilc_wfi_netdev_ops = {
* @brief WILC_WFI_init_mon_interface
* @details
* @param[in]
- * @return int : Return 0 on Success
+ * @return Pointer to net_device
* @author mdaftedar
* @date 12 JUL 2012
* @version 1.0
@@ -264,7 +260,6 @@ static const struct net_device_ops wilc_wfi_netdev_ops = {
struct net_device *WILC_WFI_init_mon_interface(const char *name,
struct net_device *real_dev)
{
- u32 ret = 0;
struct WILC_WFI_mon_priv *priv;
/*If monitor interface is already initialized, return it*/
@@ -279,8 +274,7 @@ struct net_device *WILC_WFI_init_mon_interface(const char *name,
wilc_wfi_mon->name[IFNAMSIZ - 1] = 0;
wilc_wfi_mon->netdev_ops = &wilc_wfi_netdev_ops;
- ret = register_netdevice(wilc_wfi_mon);
- if (ret) {
+ if (register_netdevice(wilc_wfi_mon)) {
netdev_err(real_dev, "register_netdevice failed\n");
return NULL;
}
diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c
index d9725efe0537..38a83bd31671 100644
--- a/drivers/staging/wilc1000/linux_wlan.c
+++ b/drivers/staging/wilc1000/linux_wlan.c
@@ -628,8 +628,7 @@ void wilc1000_wlan_deinit(struct net_device *dev)
wl->hif_func->disable_interrupt(wl);
mutex_unlock(&wl->hif_cs);
}
- if (&wl->txq_event)
- complete(&wl->txq_event);
+ complete(&wl->txq_event);
wlan_deinitialize_threads(dev);
deinit_irq(dev);
@@ -677,11 +676,9 @@ static int wlan_deinit_locks(struct net_device *dev)
vif = netdev_priv(dev);
wilc = vif->wilc;
- if (&wilc->hif_cs)
- mutex_destroy(&wilc->hif_cs);
-
- if (&wilc->rxq_cs)
- mutex_destroy(&wilc->rxq_cs);
+ mutex_destroy(&wilc->hif_cs);
+ mutex_destroy(&wilc->rxq_cs);
+ mutex_destroy(&wilc->txq_add_to_head_cs);
return 0;
}
@@ -716,8 +713,7 @@ static void wlan_deinitialize_threads(struct net_device *dev)
wl->close = 1;
- if (&wl->txq_event)
- complete(&wl->txq_event);
+ complete(&wl->txq_event);
if (wl->txq_thread) {
kthread_stop(wl->txq_thread);
@@ -866,10 +862,10 @@ static int wilc_mac_open(struct net_device *ndev)
break;
}
}
- wilc_get_mac_address(vif, mac_add);
- netdev_dbg(ndev, "Mac address: %pM\n", mac_add);
- memcpy(wl->vif[i]->src_addr, mac_add, ETH_ALEN);
+ wilc_get_mac_address(vif, mac_add);
+ netdev_dbg(ndev, "Mac address: %pM\n", mac_add);
+ memcpy(wl->vif[i]->src_addr, mac_add, ETH_ALEN);
memcpy(ndev->dev_addr, wl->vif[i]->src_addr, ETH_ALEN);
if (!is_valid_ether_addr(ndev->dev_addr)) {
@@ -1154,7 +1150,7 @@ void wilc_frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset)
}
}
-void WILC_WFI_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
+void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
{
int i = 0;
struct wilc_vif *vif;
diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c
index bb65b374c1ce..a08899941491 100644
--- a/drivers/staging/wilc1000/wilc_sdio.c
+++ b/drivers/staging/wilc1000/wilc_sdio.c
@@ -405,7 +405,7 @@ static int sdio_write_reg(struct wilc *wilc, u32 addr, u32 data)
cmd.increment = 1;
cmd.count = 4;
cmd.buffer = (u8 *)&data;
- cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */
+ cmd.block_size = g_sdio.block_size;
ret = wilc_sdio_cmd53(wilc, &cmd);
if (ret) {
dev_err(&func->dev,
@@ -489,7 +489,7 @@ static int sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
cmd.count = nleft;
cmd.buffer = buf;
- cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */
+ cmd.block_size = block_size;
if (addr > 0) {
if (!sdio_set_func0_csa_address(wilc, addr))
@@ -543,7 +543,7 @@ static int sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data)
cmd.count = 4;
cmd.buffer = (u8 *)data;
- cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */
+ cmd.block_size = g_sdio.block_size;
ret = wilc_sdio_cmd53(wilc, &cmd);
if (ret) {
dev_err(&func->dev,
@@ -629,7 +629,7 @@ static int sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
cmd.count = nleft;
cmd.buffer = buf;
- cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */
+ cmd.block_size = block_size;
if (addr > 0) {
if (!sdio_set_func0_csa_address(wilc, addr))
@@ -871,6 +871,7 @@ static int sdio_clear_int_ext(struct wilc *wilc, u32 val)
{
struct sdio_func *func = dev_to_sdio_func(wilc->dev);
int ret;
+ int vmm_ctl;
if (g_sdio.has_thrpt_enh3) {
u32 reg;
@@ -909,84 +910,82 @@ static int sdio_clear_int_ext(struct wilc *wilc, u32 val)
goto _fail_;
}
}
- } else {
- if (g_sdio.irq_gpio) {
- /* see below. has_thrpt_enh2 uses register 0xf8 to clear interrupts. */
- /* Cannot clear multiple interrupts. Must clear each interrupt individually */
- u32 flags;
-
- flags = val & (BIT(MAX_NUM_INT) - 1);
- if (flags) {
- int i;
-
- ret = 1;
- for (i = 0; i < g_sdio.nint; i++) {
- if (flags & 1) {
- struct sdio_cmd52 cmd;
-
- cmd.read_write = 1;
- cmd.function = 0;
- cmd.raw = 0;
- cmd.address = 0xf8;
- cmd.data = BIT(i);
-
- ret = wilc_sdio_cmd52(wilc, &cmd);
- if (ret) {
- dev_err(&func->dev,
- "Failed cmd52, set 0xf8 data (%d) ...\n",
- __LINE__);
- goto _fail_;
- }
+ return 1;
+ }
+ if (g_sdio.irq_gpio) {
+ /* has_thrpt_enh2 uses register 0xf8 to clear interrupts. */
+ /*
+ * Cannot clear multiple interrupts.
+ * Must clear each interrupt individually.
+ */
+ u32 flags;
+
+ flags = val & (BIT(MAX_NUM_INT) - 1);
+ if (flags) {
+ int i;
+
+ ret = 1;
+ for (i = 0; i < g_sdio.nint; i++) {
+ if (flags & 1) {
+ struct sdio_cmd52 cmd;
+
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = 0xf8;
+ cmd.data = BIT(i);
+
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd52, set 0xf8 data (%d) ...\n",
+ __LINE__);
+ goto _fail_;
}
- if (!ret)
- break;
- flags >>= 1;
}
if (!ret)
- goto _fail_;
- for (i = g_sdio.nint; i < MAX_NUM_INT; i++) {
- if (flags & 1)
- dev_err(&func->dev,
- "Unexpected interrupt cleared %d...\n",
- i);
- flags >>= 1;
- }
+ break;
+ flags >>= 1;
}
- }
-
- {
- u32 vmm_ctl;
-
- vmm_ctl = 0;
- /* select VMM table 0 */
- if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0)
- vmm_ctl |= BIT(0);
- /* select VMM table 1 */
- if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1)
- vmm_ctl |= BIT(1);
- /* enable VMM */
- if ((val & EN_VMM) == EN_VMM)
- vmm_ctl |= BIT(2);
-
- if (vmm_ctl) {
- struct sdio_cmd52 cmd;
-
- cmd.read_write = 1;
- cmd.function = 0;
- cmd.raw = 0;
- cmd.address = 0xf6;
- cmd.data = vmm_ctl;
- ret = wilc_sdio_cmd52(wilc, &cmd);
- if (ret) {
+ if (!ret)
+ goto _fail_;
+ for (i = g_sdio.nint; i < MAX_NUM_INT; i++) {
+ if (flags & 1)
dev_err(&func->dev,
- "Failed cmd52, set 0xf6 data (%d) ...\n",
- __LINE__);
- goto _fail_;
- }
+ "Unexpected interrupt cleared %d...\n",
+ i);
+ flags >>= 1;
}
}
}
+ vmm_ctl = 0;
+ /* select VMM table 0 */
+ if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0)
+ vmm_ctl |= BIT(0);
+ /* select VMM table 1 */
+ if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1)
+ vmm_ctl |= BIT(1);
+ /* enable VMM */
+ if ((val & EN_VMM) == EN_VMM)
+ vmm_ctl |= BIT(2);
+
+ if (vmm_ctl) {
+ struct sdio_cmd52 cmd;
+
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = 0xf6;
+ cmd.data = vmm_ctl;
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd52, set 0xf6 data (%d) ...\n",
+ __LINE__);
+ goto _fail_;
+ }
+ }
return 1;
_fail_:
return 0;
diff --git a/drivers/staging/wilc1000/wilc_spi.c b/drivers/staging/wilc1000/wilc_spi.c
index 8f71a6022721..6b392c946a6f 100644
--- a/drivers/staging/wilc1000/wilc_spi.c
+++ b/drivers/staging/wilc1000/wilc_spi.c
@@ -287,17 +287,19 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
u8 rsp;
int len = 0;
int result = N_OK;
+ int retry;
+ u8 crc[2];
wb[0] = cmd;
switch (cmd) {
- case CMD_SINGLE_READ: /* single word (4 bytes) read */
+ case CMD_SINGLE_READ: /* single word (4 bytes) read */
wb[1] = (u8)(adr >> 16);
wb[2] = (u8)(adr >> 8);
wb[3] = (u8)adr;
len = 5;
break;
- case CMD_INTERNAL_READ: /* internal register read */
+ case CMD_INTERNAL_READ: /* internal register read */
wb[1] = (u8)(adr >> 8);
if (clockless == 1)
wb[1] |= BIT(7);
@@ -306,29 +308,29 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
len = 5;
break;
- case CMD_TERMINATE: /* termination */
+ case CMD_TERMINATE:
wb[1] = 0x00;
wb[2] = 0x00;
wb[3] = 0x00;
len = 5;
break;
- case CMD_REPEAT: /* repeat */
+ case CMD_REPEAT:
wb[1] = 0x00;
wb[2] = 0x00;
wb[3] = 0x00;
len = 5;
break;
- case CMD_RESET: /* reset */
+ case CMD_RESET:
wb[1] = 0xff;
wb[2] = 0xff;
wb[3] = 0xff;
len = 5;
break;
- case CMD_DMA_WRITE: /* dma write */
- case CMD_DMA_READ: /* dma read */
+ case CMD_DMA_WRITE: /* dma write */
+ case CMD_DMA_READ: /* dma read */
wb[1] = (u8)(adr >> 16);
wb[2] = (u8)(adr >> 8);
wb[3] = (u8)adr;
@@ -337,8 +339,8 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
len = 7;
break;
- case CMD_DMA_EXT_WRITE: /* dma extended write */
- case CMD_DMA_EXT_READ: /* dma extended read */
+ case CMD_DMA_EXT_WRITE: /* dma extended write */
+ case CMD_DMA_EXT_READ: /* dma extended read */
wb[1] = (u8)(adr >> 16);
wb[2] = (u8)(adr >> 8);
wb[3] = (u8)adr;
@@ -348,7 +350,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
len = 8;
break;
- case CMD_INTERNAL_WRITE: /* internal register write */
+ case CMD_INTERNAL_WRITE: /* internal register write */
wb[1] = (u8)(adr >> 8);
if (clockless == 1)
wb[1] |= BIT(7);
@@ -360,7 +362,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
len = 8;
break;
- case CMD_SINGLE_WRITE: /* single word write */
+ case CMD_SINGLE_WRITE: /* single word write */
wb[1] = (u8)(adr >> 16);
wb[2] = (u8)(adr >> 8);
wb[3] = (u8)(adr);
@@ -395,13 +397,12 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
cmd == CMD_REPEAT) {
len2 = len + (NUM_SKIP_BYTES + NUM_RSP_BYTES + NUM_DUMMY_BYTES);
} else if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) {
- if (!g_spi.crc_off) {
- len2 = len + (NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES
- + NUM_CRC_BYTES + NUM_DUMMY_BYTES);
- } else {
- len2 = len + (NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES
- + NUM_DUMMY_BYTES);
- }
+ int tmp = NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES
+ + NUM_DUMMY_BYTES;
+ if (!g_spi.crc_off)
+ len2 = len + tmp + NUM_CRC_BYTES;
+ else
+ len2 = len + tmp;
} else {
len2 = len + (NUM_RSP_BYTES + NUM_DUMMY_BYTES);
}
@@ -422,19 +423,13 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
return N_FAIL;
}
- /**
+ /*
* Command/Control response
- **/
- if (cmd == CMD_RESET ||
- cmd == CMD_TERMINATE ||
- cmd == CMD_REPEAT) {
- rix++; /* skip 1 byte */
- }
+ */
+ if (cmd == CMD_RESET || cmd == CMD_TERMINATE || cmd == CMD_REPEAT)
+ rix++; /* skip 1 byte */
- /* do { */
rsp = rb[rix++];
- /* if(rsp == cmd) break; */
- /* } while(&rptr[1] <= &rb[len2]); */
if (rsp != cmd) {
dev_err(&spi->dev,
@@ -443,9 +438,9 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
return N_FAIL;
}
- /**
+ /*
* State response
- **/
+ */
rsp = rb[rix++];
if (rsp != 0x00) {
dev_err(&spi->dev, "Failed cmd state response state (%02x)\n",
@@ -455,15 +450,15 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ ||
cmd == CMD_DMA_READ || cmd == CMD_DMA_EXT_READ) {
- int retry;
- /* u16 crc1, crc2; */
- u8 crc[2];
- /**
+ /*
* Data Respnose header
- **/
+ */
retry = 100;
do {
- /* ensure there is room in buffer later to read data and crc */
+ /*
+ * ensure there is room in buffer later
+ * to read data and crc
+ */
if (rix < len2) {
rsp = rb[rix++];
} else {
@@ -479,129 +474,134 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
"Error, data read response (%02x)\n", rsp);
return N_RESET;
}
+ }
- if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) {
- /**
- * Read bytes
- **/
- if ((rix + 3) < len2) {
- b[0] = rb[rix++];
- b[1] = rb[rix++];
- b[2] = rb[rix++];
- b[3] = rb[rix++];
+ if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) {
+ /*
+ * Read bytes
+ */
+ if ((rix + 3) < len2) {
+ b[0] = rb[rix++];
+ b[1] = rb[rix++];
+ b[2] = rb[rix++];
+ b[3] = rb[rix++];
+ } else {
+ dev_err(&spi->dev,
+ "buffer overrun when reading data.\n");
+ return N_FAIL;
+ }
+
+ if (!g_spi.crc_off) {
+ /*
+ * Read Crc
+ */
+ if ((rix + 1) < len2) {
+ crc[0] = rb[rix++];
+ crc[1] = rb[rix++];
} else {
dev_err(&spi->dev,
- "buffer overrun when reading data.\n");
+ "buffer overrun when reading crc.\n");
return N_FAIL;
}
+ }
+ } else if ((cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) {
+ int ix;
- if (!g_spi.crc_off) {
- /**
- * Read Crc
- **/
- if ((rix + 1) < len2) {
- crc[0] = rb[rix++];
- crc[1] = rb[rix++];
- } else {
- dev_err(&spi->dev, "buffer overrun when reading crc.\n");
- return N_FAIL;
- }
- }
- } else if ((cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) {
- int ix;
-
- /* some data may be read in response to dummy bytes. */
- for (ix = 0; (rix < len2) && (ix < sz); )
- b[ix++] = rb[rix++];
-
- sz -= ix;
+ /* some data may be read in response to dummy bytes. */
+ for (ix = 0; (rix < len2) && (ix < sz); )
+ b[ix++] = rb[rix++];
- if (sz > 0) {
- int nbytes;
+ sz -= ix;
- if (sz <= (DATA_PKT_SZ - ix))
- nbytes = sz;
- else
- nbytes = DATA_PKT_SZ - ix;
+ if (sz > 0) {
+ int nbytes;
- /**
- * Read bytes
- **/
- if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
- dev_err(&spi->dev, "Failed data block read, bus error...\n");
- result = N_FAIL;
- goto _error_;
- }
+ if (sz <= (DATA_PKT_SZ - ix))
+ nbytes = sz;
+ else
+ nbytes = DATA_PKT_SZ - ix;
- /**
- * Read Crc
- **/
- if (!g_spi.crc_off) {
- if (wilc_spi_rx(wilc, crc, 2)) {
- dev_err(&spi->dev, "Failed data block crc read, bus error...\n");
- result = N_FAIL;
- goto _error_;
- }
- }
+ /*
+ * Read bytes
+ */
+ if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
+ dev_err(&spi->dev,
+ "Failed block read, bus err\n");
+ result = N_FAIL;
+ goto _error_;
+ }
- ix += nbytes;
- sz -= nbytes;
+ /*
+ * Read Crc
+ */
+ if (!g_spi.crc_off && wilc_spi_rx(wilc, crc, 2)) {
+ dev_err(&spi->dev,
+ "Failed block crc read, bus err\n");
+ result = N_FAIL;
+ goto _error_;
}
- /* if any data in left unread, then read the rest using normal DMA code.*/
- while (sz > 0) {
- int nbytes;
-
- if (sz <= DATA_PKT_SZ)
- nbytes = sz;
- else
- nbytes = DATA_PKT_SZ;
-
- /**
- * read data response only on the next DMA cycles not
- * the first DMA since data response header is already
- * handled above for the first DMA.
- **/
- /**
- * Data Respnose header
- **/
- retry = 10;
- do {
- if (wilc_spi_rx(wilc, &rsp, 1)) {
- dev_err(&spi->dev, "Failed data response read, bus error...\n");
- result = N_FAIL;
- break;
- }
- if (((rsp >> 4) & 0xf) == 0xf)
- break;
- } while (retry--);
-
- if (result == N_FAIL)
- break;
+ ix += nbytes;
+ sz -= nbytes;
+ }
+
+ /*
+ * if any data in left unread,
+ * then read the rest using normal DMA code.
+ */
+ while (sz > 0) {
+ int nbytes;
- /**
- * Read bytes
- **/
- if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
- dev_err(&spi->dev, "Failed data block read, bus error...\n");
+ if (sz <= DATA_PKT_SZ)
+ nbytes = sz;
+ else
+ nbytes = DATA_PKT_SZ;
+
+ /*
+ * read data response only on the next DMA cycles not
+ * the first DMA since data response header is already
+ * handled above for the first DMA.
+ */
+ /*
+ * Data Respnose header
+ */
+ retry = 10;
+ do {
+ if (wilc_spi_rx(wilc, &rsp, 1)) {
+ dev_err(&spi->dev,
+ "Failed resp read, bus err\n");
result = N_FAIL;
break;
}
+ if (((rsp >> 4) & 0xf) == 0xf)
+ break;
+ } while (retry--);
- /**
- * Read Crc
- **/
- if (!g_spi.crc_off) {
- if (wilc_spi_rx(wilc, crc, 2)) {
- dev_err(&spi->dev, "Failed data block crc read, bus error...\n");
- result = N_FAIL;
- break;
- }
- }
+ if (result == N_FAIL)
+ break;
- ix += nbytes;
- sz -= nbytes;
+ /*
+ * Read bytes
+ */
+ if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
+ dev_err(&spi->dev,
+ "Failed block read, bus err\n");
+ result = N_FAIL;
+ break;
}
+
+ /*
+ * Read Crc
+ */
+ if (!g_spi.crc_off && wilc_spi_rx(wilc, crc, 2)) {
+ dev_err(&spi->dev,
+ "Failed block crc read, bus err\n");
+ result = N_FAIL;
+ break;
+ }
+
+ ix += nbytes;
+ sz -= nbytes;
}
}
_error_:
@@ -614,11 +614,10 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
int ix, nbytes;
int result = 1;
u8 cmd, order, crc[2] = {0};
- /* u8 rsp; */
- /**
- * Data
- **/
+ /*
+ * Data
+ */
ix = 0;
do {
if (sz <= DATA_PKT_SZ)
@@ -626,9 +625,9 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
else
nbytes = DATA_PKT_SZ;
- /**
- * Write command
- **/
+ /*
+ * Write command
+ */
cmd = 0xf0;
if (ix == 0) {
if (sz <= DATA_PKT_SZ)
@@ -650,9 +649,9 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
break;
}
- /**
- * Write data
- **/
+ /*
+ * Write data
+ */
if (wilc_spi_tx(wilc, &b[ix], nbytes)) {
dev_err(&spi->dev,
"Failed data block write, bus error...\n");
@@ -660,9 +659,9 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
break;
}
- /**
- * Write Crc
- **/
+ /*
+ * Write Crc
+ */
if (!g_spi.crc_off) {
if (wilc_spi_tx(wilc, crc, 2)) {
dev_err(&spi->dev, "Failed data block crc write, bus error...\n");
@@ -671,9 +670,9 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
}
}
- /**
- * No need to wait for response
- **/
+ /*
+ * No need to wait for response
+ */
ix += nbytes;
sz -= nbytes;
} while (sz);
@@ -733,7 +732,7 @@ static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data)
data = cpu_to_le32(data);
if (addr < 0x30) {
- /* Clockless register*/
+ /* Clockless register */
cmd = CMD_INTERNAL_WRITE;
clockless = 1;
}
@@ -751,9 +750,9 @@ static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
int result;
u8 cmd = CMD_DMA_EXT_WRITE;
- /**
- * has to be greated than 4
- **/
+ /*
+ * has to be greated than 4
+ */
if (size <= 4)
return 0;
@@ -764,9 +763,9 @@ static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
return 0;
}
- /**
- * Data
- **/
+ /*
+ * Data
+ */
result = spi_data_write(wilc, buf, size);
if (result != N_OK)
dev_err(&spi->dev, "Failed block data write...\n");
@@ -783,7 +782,7 @@ static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data)
if (addr < 0x30) {
/* dev_err(&spi->dev, "***** read addr %d\n\n", addr); */
- /* Clockless register*/
+ /* Clockless register */
cmd = CMD_INTERNAL_READ;
clockless = 1;
}
@@ -825,9 +824,9 @@ static int wilc_spi_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
static int _wilc_spi_deinit(struct wilc *wilc)
{
- /**
- * TODO:
- **/
+ /*
+ * TODO:
+ */
return 1;
}
@@ -836,7 +835,6 @@ static int wilc_spi_init(struct wilc *wilc, bool resume)
struct spi_device *spi = to_spi_device(wilc->dev);
u32 reg;
u32 chipid;
-
static int isinit;
if (isinit) {
@@ -849,45 +847,53 @@ static int wilc_spi_init(struct wilc *wilc, bool resume)
memset(&g_spi, 0, sizeof(struct wilc_spi));
- /**
- * configure protocol
- **/
+ /*
+ * configure protocol
+ */
g_spi.crc_off = 0;
- /* TODO: We can remove the CRC trials if there is a definite way to reset */
+ /*
+ * TODO: We can remove the CRC trials if there is a definite
+ * way to reset
+ */
/* the SPI to it's initial value. */
if (!spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, &reg)) {
- /* Read failed. Try with CRC off. This might happen when module
+ /*
+ * Read failed. Try with CRC off. This might happen when module
* is removed but chip isn't reset
*/
g_spi.crc_off = 1;
- dev_err(&spi->dev, "Failed internal read protocol with CRC on, retrying with CRC off...\n");
+ dev_err(&spi->dev,
+ "Failed read with CRC on, retrying with CRC off\n");
if (!spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, &reg)) {
- /* Reaad failed with both CRC on and off, something went bad */
- dev_err(&spi->dev,
- "Failed internal read protocol...\n");
+ /*
+ * Read failed with both CRC on and off,
+ * something went bad
+ */
+ dev_err(&spi->dev, "Failed internal read protocol\n");
return 0;
}
}
- if (g_spi.crc_off == 0) {
- reg &= ~0xc; /* disable crc checking */
+ if (g_spi.crc_off == 0) {
+ reg &= ~0xc; /* disable crc checking */
reg &= ~0x70;
reg |= (0x5 << 4);
if (!spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg)) {
- dev_err(&spi->dev, "[wilc spi %d]: Failed internal write protocol reg...\n", __LINE__);
+ dev_err(&spi->dev,
+ "[wilc spi %d]: Failed internal write reg\n",
+ __LINE__);
return 0;
}
g_spi.crc_off = 1;
}
- /**
- * make sure can read back chip id correctly
- **/
+ /*
+ * make sure can read back chip id correctly
+ */
if (!wilc_spi_read_reg(wilc, 0x1000, &chipid)) {
dev_err(&spi->dev, "Fail cmd read chip id...\n");
return 0;
}
- /* dev_err(&spi->dev, "chipid (%08x)\n", chipid); */
g_spi.has_thrpt_enh = 1;
@@ -933,45 +939,46 @@ static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status)
int happened, j;
u32 unknown_mask;
u32 irq_flags;
+ int k = IRG_FLAGS_OFFSET + 5;
if (g_spi.has_thrpt_enh) {
ret = spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE,
int_status);
- } else {
- ret = wilc_spi_read_reg(wilc, WILC_VMM_TO_HOST_SIZE,
- &byte_cnt);
- if (!ret) {
- dev_err(&spi->dev,
- "Failed read WILC_VMM_TO_HOST_SIZE ...\n");
- goto _fail_;
- }
- tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK;
+ return ret;
+ }
+ ret = wilc_spi_read_reg(wilc, WILC_VMM_TO_HOST_SIZE, &byte_cnt);
+ if (!ret) {
+ dev_err(&spi->dev,
+ "Failed read WILC_VMM_TO_HOST_SIZE ...\n");
+ goto _fail_;
+ }
+ tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK;
- j = 0;
- do {
- happened = 0;
+ j = 0;
+ do {
+ happened = 0;
- wilc_spi_read_reg(wilc, 0x1a90, &irq_flags);
- tmp |= ((irq_flags >> 27) << IRG_FLAGS_OFFSET);
+ wilc_spi_read_reg(wilc, 0x1a90, &irq_flags);
+ tmp |= ((irq_flags >> 27) << IRG_FLAGS_OFFSET);
- if (g_spi.nint > 5) {
- wilc_spi_read_reg(wilc, 0x1a94,
- &irq_flags);
- tmp |= (((irq_flags >> 0) & 0x7) << (IRG_FLAGS_OFFSET + 5));
- }
+ if (g_spi.nint > 5) {
+ wilc_spi_read_reg(wilc, 0x1a94, &irq_flags);
+ tmp |= (((irq_flags >> 0) & 0x7) << k);
+ }
- unknown_mask = ~((1ul << g_spi.nint) - 1);
+ unknown_mask = ~((1ul << g_spi.nint) - 1);
- if ((tmp >> IRG_FLAGS_OFFSET) & unknown_mask) {
- dev_err(&spi->dev, "Unexpected interrupt (2): j=%d, tmp=%x, mask=%x\n", j, tmp, unknown_mask);
- happened = 1;
- }
+ if ((tmp >> IRG_FLAGS_OFFSET) & unknown_mask) {
+ dev_err(&spi->dev,
+ "Unexpected interrupt(2):j=%d,tmp=%x,mask=%x\n",
+ j, tmp, unknown_mask);
+ happened = 1;
+ }
- j++;
- } while (happened);
+ j++;
+ } while (happened);
- *int_status = tmp;
- }
+ *int_status = tmp;
_fail_:
return ret;
@@ -981,71 +988,69 @@ static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val)
{
struct spi_device *spi = to_spi_device(wilc->dev);
int ret;
+ u32 flags;
+ u32 tbl_ctl;
if (g_spi.has_thrpt_enh) {
ret = spi_internal_write(wilc, 0xe844 - WILC_SPI_REG_BASE,
val);
- } else {
- u32 flags;
-
- flags = val & (BIT(MAX_NUM_INT) - 1);
- if (flags) {
- int i;
-
- ret = 1;
- for (i = 0; i < g_spi.nint; i++) {
- /* No matter what you write 1 or 0, it will clear interrupt. */
- if (flags & 1)
- ret = wilc_spi_write_reg(wilc, 0x10c8 + i * 4, 1);
- if (!ret)
- break;
- flags >>= 1;
- }
- if (!ret) {
+ return ret;
+ }
+
+ flags = val & (BIT(MAX_NUM_INT) - 1);
+ if (flags) {
+ int i;
+
+ ret = 1;
+ for (i = 0; i < g_spi.nint; i++) {
+ /*
+ * No matter what you write 1 or 0,
+ * it will clear interrupt.
+ */
+ if (flags & 1)
+ ret = wilc_spi_write_reg(wilc,
+ 0x10c8 + i * 4, 1);
+ if (!ret)
+ break;
+ flags >>= 1;
+ }
+ if (!ret) {
+ dev_err(&spi->dev,
+ "Failed wilc_spi_write_reg, set reg %x ...\n",
+ 0x10c8 + i * 4);
+ goto _fail_;
+ }
+ for (i = g_spi.nint; i < MAX_NUM_INT; i++) {
+ if (flags & 1)
dev_err(&spi->dev,
- "Failed wilc_spi_write_reg, set reg %x ...\n",
- 0x10c8 + i * 4);
- goto _fail_;
- }
- for (i = g_spi.nint; i < MAX_NUM_INT; i++) {
- if (flags & 1)
- dev_err(&spi->dev,
- "Unexpected interrupt cleared %d...\n",
- i);
- flags >>= 1;
- }
+ "Unexpected interrupt cleared %d...\n",
+ i);
+ flags >>= 1;
}
+ }
- {
- u32 tbl_ctl;
-
- tbl_ctl = 0;
- /* select VMM table 0 */
- if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0)
- tbl_ctl |= BIT(0);
- /* select VMM table 1 */
- if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1)
- tbl_ctl |= BIT(1);
+ tbl_ctl = 0;
+ /* select VMM table 0 */
+ if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0)
+ tbl_ctl |= BIT(0);
+ /* select VMM table 1 */
+ if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1)
+ tbl_ctl |= BIT(1);
- ret = wilc_spi_write_reg(wilc, WILC_VMM_TBL_CTL,
- tbl_ctl);
- if (!ret) {
- dev_err(&spi->dev,
- "fail write reg vmm_tbl_ctl...\n");
- goto _fail_;
- }
+ ret = wilc_spi_write_reg(wilc, WILC_VMM_TBL_CTL, tbl_ctl);
+ if (!ret) {
+ dev_err(&spi->dev, "fail write reg vmm_tbl_ctl...\n");
+ goto _fail_;
+ }
- if ((val & EN_VMM) == EN_VMM) {
- /**
- * enable vmm transfer.
- **/
- ret = wilc_spi_write_reg(wilc,
- WILC_VMM_CORE_CTL, 1);
- if (!ret) {
- dev_err(&spi->dev, "fail write reg vmm_core_ctl...\n");
- goto _fail_;
- }
- }
+ if ((val & EN_VMM) == EN_VMM) {
+ /*
+ * enable vmm transfer.
+ */
+ ret = wilc_spi_write_reg(wilc, WILC_VMM_CORE_CTL, 1);
+ if (!ret) {
+ dev_err(&spi->dev, "fail write reg vmm_core_ctl...\n");
+ goto _fail_;
}
}
_fail_:
@@ -1065,9 +1070,9 @@ static int wilc_spi_sync_ext(struct wilc *wilc, int nint)
g_spi.nint = nint;
- /**
- * interrupt pin mux select
- **/
+ /*
+ * interrupt pin mux select
+ */
ret = wilc_spi_read_reg(wilc, WILC_PIN_MUX_0, &reg);
if (!ret) {
dev_err(&spi->dev, "Failed read reg (%08x)...\n",
@@ -1082,9 +1087,9 @@ static int wilc_spi_sync_ext(struct wilc *wilc, int nint)
return 0;
}
- /**
- * interrupt enable
- **/
+ /*
+ * interrupt enable
+ */
ret = wilc_spi_read_reg(wilc, WILC_INTR_ENABLE, &reg);
if (!ret) {
dev_err(&spi->dev, "Failed read reg (%08x)...\n",
diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
index 621810d70450..730d64f2f46a 100644
--- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
+++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c
@@ -85,9 +85,6 @@ static const struct wiphy_wowlan_support wowlan_support = {
#define TCP_ACK_FILTER_LINK_SPEED_THRESH 54
#define DEFAULT_LINK_SPEED 72
-#define IS_MANAGMEMENT 0x100
-#define IS_MANAGMEMENT_CALLBACK 0x080
-#define IS_MGMT_STATUS_SUCCES 0x040
#define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff)
static struct network_info last_scanned_shadow[MAX_NUM_SCANNED_NETWORKS_SHADOW];
@@ -297,8 +294,7 @@ static void clear_duringIP(struct timer_list *unused)
wilc_optaining_ip = false;
}
-static int is_network_in_shadow(struct network_info *pstrNetworkInfo,
- void *user_void)
+static int is_network_in_shadow(struct network_info *nw_info, void *user_void)
{
int state = -1;
int i;
@@ -309,7 +305,7 @@ static int is_network_in_shadow(struct network_info *pstrNetworkInfo,
} else {
for (i = 0; i < last_scanned_cnt; i++) {
if (memcmp(last_scanned_shadow[i].bssid,
- pstrNetworkInfo->bssid, 6) == 0) {
+ nw_info->bssid, 6) == 0) {
state = i;
break;
}
@@ -318,10 +314,10 @@ static int is_network_in_shadow(struct network_info *pstrNetworkInfo,
return state;
}
-static void add_network_to_shadow(struct network_info *pstrNetworkInfo,
- void *user_void, void *pJoinParams)
+static void add_network_to_shadow(struct network_info *nw_info,
+ void *user_void, void *join_params)
{
- int ap_found = is_network_in_shadow(pstrNetworkInfo, user_void);
+ int ap_found = is_network_in_shadow(nw_info, user_void);
u32 ap_index = 0;
u8 rssi_index = 0;
@@ -335,42 +331,41 @@ static void add_network_to_shadow(struct network_info *pstrNetworkInfo,
ap_index = ap_found;
}
rssi_index = last_scanned_shadow[ap_index].rssi_history.index;
- last_scanned_shadow[ap_index].rssi_history.samples[rssi_index++] = pstrNetworkInfo->rssi;
+ last_scanned_shadow[ap_index].rssi_history.samples[rssi_index++] = nw_info->rssi;
if (rssi_index == NUM_RSSI) {
rssi_index = 0;
last_scanned_shadow[ap_index].rssi_history.full = true;
}
last_scanned_shadow[ap_index].rssi_history.index = rssi_index;
- last_scanned_shadow[ap_index].rssi = pstrNetworkInfo->rssi;
- last_scanned_shadow[ap_index].cap_info = pstrNetworkInfo->cap_info;
- last_scanned_shadow[ap_index].ssid_len = pstrNetworkInfo->ssid_len;
+ last_scanned_shadow[ap_index].rssi = nw_info->rssi;
+ last_scanned_shadow[ap_index].cap_info = nw_info->cap_info;
+ last_scanned_shadow[ap_index].ssid_len = nw_info->ssid_len;
memcpy(last_scanned_shadow[ap_index].ssid,
- pstrNetworkInfo->ssid, pstrNetworkInfo->ssid_len);
+ nw_info->ssid, nw_info->ssid_len);
memcpy(last_scanned_shadow[ap_index].bssid,
- pstrNetworkInfo->bssid, ETH_ALEN);
- last_scanned_shadow[ap_index].beacon_period = pstrNetworkInfo->beacon_period;
- last_scanned_shadow[ap_index].dtim_period = pstrNetworkInfo->dtim_period;
- last_scanned_shadow[ap_index].ch = pstrNetworkInfo->ch;
- last_scanned_shadow[ap_index].ies_len = pstrNetworkInfo->ies_len;
- last_scanned_shadow[ap_index].tsf_hi = pstrNetworkInfo->tsf_hi;
+ nw_info->bssid, ETH_ALEN);
+ last_scanned_shadow[ap_index].beacon_period = nw_info->beacon_period;
+ last_scanned_shadow[ap_index].dtim_period = nw_info->dtim_period;
+ last_scanned_shadow[ap_index].ch = nw_info->ch;
+ last_scanned_shadow[ap_index].ies_len = nw_info->ies_len;
+ last_scanned_shadow[ap_index].tsf_hi = nw_info->tsf_hi;
if (ap_found != -1)
kfree(last_scanned_shadow[ap_index].ies);
- last_scanned_shadow[ap_index].ies = kmalloc(pstrNetworkInfo->ies_len,
+ last_scanned_shadow[ap_index].ies = kmalloc(nw_info->ies_len,
GFP_KERNEL);
memcpy(last_scanned_shadow[ap_index].ies,
- pstrNetworkInfo->ies, pstrNetworkInfo->ies_len);
+ nw_info->ies, nw_info->ies_len);
last_scanned_shadow[ap_index].time_scan = jiffies;
last_scanned_shadow[ap_index].time_scan_cached = jiffies;
last_scanned_shadow[ap_index].found = 1;
if (ap_found != -1)
kfree(last_scanned_shadow[ap_index].join_params);
- last_scanned_shadow[ap_index].join_params = pJoinParams;
+ last_scanned_shadow[ap_index].join_params = join_params;
}
-static void CfgScanResult(enum scan_event scan_event,
- struct network_info *network_info,
- void *user_void,
- void *join_params)
+static void cfg_scan_result(enum scan_event scan_event,
+ struct network_info *network_info,
+ void *user_void, void *join_params)
{
struct wilc_priv *priv;
struct wiphy *wiphy;
@@ -379,91 +374,97 @@ static void CfgScanResult(enum scan_event scan_event,
struct cfg80211_bss *bss = NULL;
priv = user_void;
- if (priv->cfg_scanning) {
- if (scan_event == SCAN_EVENT_NETWORK_FOUND) {
- wiphy = priv->dev->ieee80211_ptr->wiphy;
+ if (!priv->cfg_scanning)
+ return;
+
+ if (scan_event == SCAN_EVENT_NETWORK_FOUND) {
+ wiphy = priv->dev->ieee80211_ptr->wiphy;
+
+ if (!wiphy || !network_info)
+ return;
+
+ if (wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
+ (((s32)network_info->rssi * 100) < 0 ||
+ ((s32)network_info->rssi * 100) > 100))
+ return;
+
+ s32Freq = ieee80211_channel_to_frequency((s32)network_info->ch,
+ NL80211_BAND_2GHZ);
+ channel = ieee80211_get_channel(wiphy, s32Freq);
+
+ if (!channel)
+ return;
- if (!wiphy)
+ if (network_info->new_network) {
+ if (priv->rcvd_ch_cnt >= MAX_NUM_SCANNED_NETWORKS)
return;
- if (wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
- (((s32)network_info->rssi * 100) < 0 ||
- ((s32)network_info->rssi * 100) > 100))
+ priv->rcvd_ch_cnt++;
+
+ add_network_to_shadow(network_info, priv, join_params);
+
+ if (memcmp("DIRECT-", network_info->ssid, 7))
return;
- if (network_info) {
- s32Freq = ieee80211_channel_to_frequency((s32)network_info->ch, NL80211_BAND_2GHZ);
- channel = ieee80211_get_channel(wiphy, s32Freq);
-
- if (!channel)
- return;
-
- if (network_info->new_network) {
- if (priv->rcvd_ch_cnt < MAX_NUM_SCANNED_NETWORKS) {
- priv->rcvd_ch_cnt++;
-
- add_network_to_shadow(network_info, priv, join_params);
-
- if (!(memcmp("DIRECT-", network_info->ssid, 7))) {
- bss = cfg80211_inform_bss(wiphy,
- channel,
- CFG80211_BSS_FTYPE_UNKNOWN,
- network_info->bssid,
- network_info->tsf_hi,
- network_info->cap_info,
- network_info->beacon_period,
- (const u8 *)network_info->ies,
- (size_t)network_info->ies_len,
- (s32)network_info->rssi * 100,
- GFP_KERNEL);
- cfg80211_put_bss(wiphy, bss);
- }
- }
- } else {
- u32 i;
+ bss = cfg80211_inform_bss(wiphy,
+ channel,
+ CFG80211_BSS_FTYPE_UNKNOWN,
+ network_info->bssid,
+ network_info->tsf_hi,
+ network_info->cap_info,
+ network_info->beacon_period,
+ (const u8 *)network_info->ies,
+ (size_t)network_info->ies_len,
+ (s32)network_info->rssi * 100,
+ GFP_KERNEL);
+ cfg80211_put_bss(wiphy, bss);
+ } else {
+ u32 i;
- for (i = 0; i < priv->rcvd_ch_cnt; i++) {
- if (memcmp(last_scanned_shadow[i].bssid, network_info->bssid, 6) == 0) {
- last_scanned_shadow[i].rssi = network_info->rssi;
- last_scanned_shadow[i].time_scan = jiffies;
- break;
- }
- }
- }
+ for (i = 0; i < priv->rcvd_ch_cnt; i++) {
+ if (memcmp(last_scanned_shadow[i].bssid,
+ network_info->bssid, 6) == 0)
+ break;
}
- } else if (scan_event == SCAN_EVENT_DONE) {
- refresh_scan(priv, false);
- mutex_lock(&priv->scan_req_lock);
+ if (i >= priv->rcvd_ch_cnt)
+ return;
- if (priv->scan_req) {
- struct cfg80211_scan_info info = {
- .aborted = false,
- };
+ last_scanned_shadow[i].rssi = network_info->rssi;
+ last_scanned_shadow[i].time_scan = jiffies;
+ }
+ } else if (scan_event == SCAN_EVENT_DONE) {
+ refresh_scan(priv, false);
- cfg80211_scan_done(priv->scan_req, &info);
- priv->rcvd_ch_cnt = 0;
- priv->cfg_scanning = false;
- priv->scan_req = NULL;
- }
- mutex_unlock(&priv->scan_req_lock);
- } else if (scan_event == SCAN_EVENT_ABORTED) {
- mutex_lock(&priv->scan_req_lock);
+ mutex_lock(&priv->scan_req_lock);
- if (priv->scan_req) {
- struct cfg80211_scan_info info = {
- .aborted = false,
- };
+ if (priv->scan_req) {
+ struct cfg80211_scan_info info = {
+ .aborted = false,
+ };
- update_scan_time();
- refresh_scan(priv, false);
+ cfg80211_scan_done(priv->scan_req, &info);
+ priv->rcvd_ch_cnt = 0;
+ priv->cfg_scanning = false;
+ priv->scan_req = NULL;
+ }
+ mutex_unlock(&priv->scan_req_lock);
+ } else if (scan_event == SCAN_EVENT_ABORTED) {
+ mutex_lock(&priv->scan_req_lock);
- cfg80211_scan_done(priv->scan_req, &info);
- priv->cfg_scanning = false;
- priv->scan_req = NULL;
- }
- mutex_unlock(&priv->scan_req_lock);
+ if (priv->scan_req) {
+ struct cfg80211_scan_info info = {
+ .aborted = false,
+ };
+
+ update_scan_time();
+ refresh_scan(priv, false);
+
+ cfg80211_scan_done(priv->scan_req, &info);
+ priv->cfg_scanning = false;
+ priv->scan_req = NULL;
}
+ mutex_unlock(&priv->scan_req_lock);
}
}
@@ -586,8 +587,8 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
struct wilc_priv *priv;
u32 i;
s32 ret = 0;
- u8 au8ScanChanList[MAX_NUM_SCANNED_NETWORKS];
- struct hidden_network strHiddenNetwork;
+ u8 scan_ch_list[MAX_NUM_SCANNED_NETWORKS];
+ struct hidden_network hidden_ntwk;
struct wilc_vif *vif;
priv = wiphy_priv(wiphy);
@@ -602,38 +603,38 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
priv->cfg_scanning = true;
if (request->n_channels <= MAX_NUM_SCANNED_NETWORKS) {
for (i = 0; i < request->n_channels; i++)
- au8ScanChanList[i] = (u8)ieee80211_frequency_to_channel(request->channels[i]->center_freq);
+ scan_ch_list[i] = (u8)ieee80211_frequency_to_channel(request->channels[i]->center_freq);
if (request->n_ssids >= 1) {
- strHiddenNetwork.net_info =
+ hidden_ntwk.net_info =
kmalloc_array(request->n_ssids,
sizeof(struct hidden_network),
GFP_KERNEL);
- if (!strHiddenNetwork.net_info)
+ if (!hidden_ntwk.net_info)
return -ENOMEM;
- strHiddenNetwork.n_ssids = request->n_ssids;
+ hidden_ntwk.n_ssids = request->n_ssids;
for (i = 0; i < request->n_ssids; i++) {
if (request->ssids[i].ssid_len != 0) {
- strHiddenNetwork.net_info[i].ssid = kmalloc(request->ssids[i].ssid_len, GFP_KERNEL);
- memcpy(strHiddenNetwork.net_info[i].ssid, request->ssids[i].ssid, request->ssids[i].ssid_len);
- strHiddenNetwork.net_info[i].ssid_len = request->ssids[i].ssid_len;
+ hidden_ntwk.net_info[i].ssid = kmalloc(request->ssids[i].ssid_len, GFP_KERNEL);
+ memcpy(hidden_ntwk.net_info[i].ssid, request->ssids[i].ssid, request->ssids[i].ssid_len);
+ hidden_ntwk.net_info[i].ssid_len = request->ssids[i].ssid_len;
} else {
- strHiddenNetwork.n_ssids -= 1;
+ hidden_ntwk.n_ssids -= 1;
}
}
ret = wilc_scan(vif, USER_SCAN, ACTIVE_SCAN,
- au8ScanChanList,
+ scan_ch_list,
request->n_channels,
(const u8 *)request->ie,
- request->ie_len, CfgScanResult,
- (void *)priv, &strHiddenNetwork);
+ request->ie_len, cfg_scan_result,
+ (void *)priv, &hidden_ntwk);
} else {
ret = wilc_scan(vif, USER_SCAN, ACTIVE_SCAN,
- au8ScanChanList,
+ scan_ch_list,
request->n_channels,
(const u8 *)request->ie,
- request->ie_len, CfgScanResult,
+ request->ie_len, cfg_scan_result,
(void *)priv, NULL);
}
} else {
@@ -657,7 +658,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
struct wilc_priv *priv;
struct host_if_drv *wfi_drv;
- struct network_info *pstrNetworkInfo = NULL;
+ struct network_info *nw_info = NULL;
struct wilc_vif *vif;
wilc_connecting = 1;
@@ -692,7 +693,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
}
if (sel_bssi_idx < last_scanned_cnt) {
- pstrNetworkInfo = &last_scanned_shadow[sel_bssi_idx];
+ nw_info = &last_scanned_shadow[sel_bssi_idx];
} else {
ret = -ENOENT;
wilc_connecting = 0;
@@ -775,29 +776,23 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
}
if (sme->crypto.n_akm_suites) {
- switch (sme->crypto.akm_suites[0]) {
- case WLAN_AKM_SUITE_8021X:
+ if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_8021X)
auth_type = IEEE8021;
- break;
-
- default:
- break;
- }
}
- curr_channel = pstrNetworkInfo->ch;
+ curr_channel = nw_info->ch;
if (!wfi_drv->p2p_connect)
- wlan_channel = pstrNetworkInfo->ch;
+ wlan_channel = nw_info->ch;
- wilc_wlan_set_bssid(dev, pstrNetworkInfo->bssid, STATION_MODE);
+ wilc_wlan_set_bssid(dev, nw_info->bssid, STATION_MODE);
- ret = wilc_set_join_req(vif, pstrNetworkInfo->bssid, sme->ssid,
+ ret = wilc_set_join_req(vif, nw_info->bssid, sme->ssid,
sme->ssid_len, sme->ie, sme->ie_len,
cfg_connect_result, (void *)priv,
u8security, auth_type,
- pstrNetworkInfo->ch,
- pstrNetworkInfo->join_params);
+ nw_info->ch,
+ nw_info->join_params);
if (ret != 0) {
netdev_err(dev, "wilc_set_join_req(): Error\n");
ret = -ENOENT;
@@ -959,18 +954,14 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
}
kfree(priv->wilc_ptk[key_index]->key);
-
priv->wilc_ptk[key_index]->key = kmalloc(params->key_len, GFP_KERNEL);
+ memcpy(priv->wilc_ptk[key_index]->key, params->key, params->key_len);
kfree(priv->wilc_ptk[key_index]->seq);
-
- if (params->seq_len > 0)
+ if (params->seq_len > 0) {
priv->wilc_ptk[key_index]->seq = kmalloc(params->seq_len, GFP_KERNEL);
-
- memcpy(priv->wilc_ptk[key_index]->key, params->key, params->key_len);
-
- if (params->seq_len > 0)
memcpy(priv->wilc_ptk[key_index]->seq, params->seq, params->seq_len);
+ }
priv->wilc_ptk[key_index]->cipher = params->cipher;
priv->wilc_ptk[key_index]->key_len = params->key_len;
@@ -1127,8 +1118,8 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev,
}
static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
- bool pairwise,
- const u8 *mac_addr, void *cookie, void (*callback)(void *cookie, struct key_params *))
+ bool pairwise, const u8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie, struct key_params *))
{
struct wilc_priv *priv;
struct key_params key_params;
@@ -1154,8 +1145,8 @@ static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
return 0;
}
-static int set_default_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
- bool unicast, bool multicast)
+static int set_default_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, bool unicast, bool multicast)
{
struct wilc_priv *priv;
struct wilc_vif *vif;
@@ -1346,10 +1337,33 @@ static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
return 0;
}
+static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u8 ch_list_attr_idx,
+ u8 op_ch_attr_idx)
+{
+ int i = 0;
+ int j = 0;
+
+ if (ch_list_attr_idx) {
+ u8 limit = ch_list_attr_idx + 3 + buf[ch_list_attr_idx + 1];
+
+ for (i = ch_list_attr_idx + 3; i < limit; i++) {
+ if (buf[i] == 0x51) {
+ for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++)
+ buf[j] = wlan_channel;
+ break;
+ }
+ }
+ }
+
+ if (op_ch_attr_idx) {
+ buf[op_ch_attr_idx + 6] = 0x51;
+ buf[op_ch_attr_idx + 7] = wlan_channel;
+ }
+}
+
static void wilc_wfi_cfg_parse_rx_action(u8 *buf, u32 len)
{
u32 index = 0;
- u32 i = 0, j = 0;
u8 op_channel_attr_index = 0;
u8 channel_list_attr_index = 0;
@@ -1364,28 +1378,15 @@ static void wilc_wfi_cfg_parse_rx_action(u8 *buf, u32 len)
op_channel_attr_index = index;
index += buf[index + 1] + 3;
}
- if (wlan_channel != INVALID_CHANNEL) {
- if (channel_list_attr_index) {
- for (i = channel_list_attr_index + 3; i < ((channel_list_attr_index + 3) + buf[channel_list_attr_index + 1]); i++) {
- if (buf[i] == 0x51) {
- for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++)
- buf[j] = wlan_channel;
- break;
- }
- }
- }
-
- if (op_channel_attr_index) {
- buf[op_channel_attr_index + 6] = 0x51;
- buf[op_channel_attr_index + 7] = wlan_channel;
- }
- }
+ if (wlan_channel != INVALID_CHANNEL)
+ wilc_wfi_cfg_parse_ch_attr(buf, channel_list_attr_index,
+ op_channel_attr_index);
}
-static void wilc_wfi_cfg_parse_tx_action(u8 *buf, u32 len, bool oper_ch, u8 iftype)
+static void wilc_wfi_cfg_parse_tx_action(u8 *buf, u32 len, bool oper_ch,
+ u8 iftype)
{
u32 index = 0;
- u32 i = 0, j = 0;
u8 op_channel_attr_index = 0;
u8 channel_list_attr_index = 0;
@@ -1403,22 +1404,9 @@ static void wilc_wfi_cfg_parse_tx_action(u8 *buf, u32 len, bool oper_ch, u8 ifty
op_channel_attr_index = index;
index += buf[index + 1] + 3;
}
- if (wlan_channel != INVALID_CHANNEL && oper_ch) {
- if (channel_list_attr_index) {
- for (i = channel_list_attr_index + 3; i < ((channel_list_attr_index + 3) + buf[channel_list_attr_index + 1]); i++) {
- if (buf[i] == 0x51) {
- for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++)
- buf[j] = wlan_channel;
- break;
- }
- }
- }
-
- if (op_channel_attr_index) {
- buf[op_channel_attr_index + 6] = 0x51;
- buf[op_channel_attr_index + 7] = wlan_channel;
- }
- }
+ if (wlan_channel != INVALID_CHANNEL && oper_ch)
+ wilc_wfi_cfg_parse_ch_attr(buf, channel_list_attr_index,
+ op_channel_attr_index);
}
void WILC_WFI_p2p_rx(struct net_device *dev, u8 *buff, u32 size)
@@ -1717,9 +1705,13 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy,
wfi_drv->p2p_timeout = jiffies;
if (!priv->p2p_listen_state) {
+ struct wilc_wfi_p2p_listen_params *params;
+
+ params = &priv->remain_on_ch_params;
+
cfg80211_remain_on_channel_expired(priv->wdev,
- priv->remain_on_ch_params.listen_cookie,
- priv->remain_on_ch_params.listen_ch,
+ params->listen_cookie,
+ params->listen_ch,
GFP_KERNEL);
}
@@ -1813,7 +1805,8 @@ static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
}
static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
- enum nl80211_iftype type, struct vif_params *params)
+ enum nl80211_iftype type,
+ struct vif_params *params)
{
struct wilc_priv *priv;
struct wilc_vif *vif;
@@ -1837,7 +1830,8 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
vif->iftype = STATION_MODE;
wilc_set_operation_mode(vif, STATION_MODE);
- memset(priv->assoc_stainfo.sta_associated_bss, 0, MAX_NUM_STA * ETH_ALEN);
+ memset(priv->assoc_stainfo.sta_associated_bss, 0,
+ MAX_NUM_STA * ETH_ALEN);
wilc_enable_ps = true;
wilc_set_power_mgmt(vif, 1, 0);
@@ -2310,6 +2304,7 @@ int wilc_deinit_host_int(struct net_device *net)
op_ifcs--;
+ mutex_destroy(&priv->scan_req_lock);
ret = wilc_deinit(vif);
clear_shadow_scan();
diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h
index 3337fb26c8e2..d62c4f1cddc6 100644
--- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h
+++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h
@@ -230,7 +230,7 @@ void wilc_netdev_cleanup(struct wilc *wilc);
int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type,
int gpio, const struct wilc_hif_func *ops);
void wilc1000_wlan_deinit(struct net_device *dev);
-void WILC_WFI_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size);
+void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size);
int wilc_wlan_get_firmware(struct net_device *dev);
int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode);
diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c
index acaeafc2c350..bcbb92323a0a 100644
--- a/drivers/staging/wilc1000/wilc_wlan.c
+++ b/drivers/staging/wilc1000/wilc_wlan.c
@@ -173,11 +173,13 @@ static inline int update_tcp_session(u32 index, u32 ack)
static inline int add_tcp_pending_ack(u32 ack, u32 session_index,
struct txq_entry_t *txqe)
{
- if (pending_base + pending_acks < MAX_PENDING_ACKS) {
- pending_acks_info[pending_base + pending_acks].ack_num = ack;
- pending_acks_info[pending_base + pending_acks].txqe = txqe;
- pending_acks_info[pending_base + pending_acks].session_index = session_index;
- txqe->tcp_pending_ack_idx = pending_base + pending_acks;
+ u32 i = pending_base + pending_acks;
+
+ if (i < MAX_PENDING_ACKS) {
+ pending_acks_info[i].ack_num = ack;
+ pending_acks_info[i].txqe = txqe;
+ pending_acks_info[i].session_index = session_index;
+ txqe->tcp_pending_ack_idx = i;
pending_acks++;
}
return 0;
@@ -230,8 +232,10 @@ static inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe)
(u32)tcp_hdr_ptr[11];
for (i = 0; i < tcp_session; i++) {
+ u32 j = ack_session_info[i].seq_num;
+
if (i < 2 * MAX_TCP_SESSION &&
- ack_session_info[i].seq_num == seq_no) {
+ j == seq_no) {
update_tcp_session(i, ack_no);
break;
}
@@ -258,10 +262,20 @@ static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev)
spin_lock_irqsave(&wilc->txq_spinlock, wilc->txq_spinlock_flags);
for (i = pending_base; i < (pending_base + pending_acks); i++) {
- if (i >= MAX_PENDING_ACKS ||
- pending_acks_info[i].session_index >= 2 * MAX_TCP_SESSION)
+ u32 session_index;
+ u32 bigger_ack_num;
+
+ if (i >= MAX_PENDING_ACKS)
break;
- if (pending_acks_info[i].ack_num < ack_session_info[pending_acks_info[i].session_index].bigger_ack_num) {
+
+ session_index = pending_acks_info[i].session_index;
+
+ if (session_index >= 2 * MAX_TCP_SESSION)
+ break;
+
+ bigger_ack_num = ack_session_info[session_index].bigger_ack_num;
+
+ if (pending_acks_info[i].ack_num < bigger_ack_num) {
struct txq_entry_t *tqe;
tqe = pending_acks_info[i].txqe;
@@ -562,197 +576,196 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count)
u32 vmm_table[WILC_VMM_TBL_SIZE];
struct wilc_vif *vif;
struct wilc *wilc;
+ const struct wilc_hif_func *func;
vif = netdev_priv(dev);
wilc = vif->wilc;
txb = wilc->tx_buffer;
wilc->txq_exit = 0;
+
+ if (wilc->quit)
+ goto out;
+
+ mutex_lock(&wilc->txq_add_to_head_cs);
+ wilc_wlan_txq_filter_dup_tcp_ack(dev);
+ tqe = wilc_wlan_txq_get_first(wilc);
+ i = 0;
+ sum = 0;
do {
- if (wilc->quit)
- break;
+ if (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) {
+ if (tqe->type == WILC_CFG_PKT)
+ vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;
- mutex_lock(&wilc->txq_add_to_head_cs);
- wilc_wlan_txq_filter_dup_tcp_ack(dev);
- tqe = wilc_wlan_txq_get_first(wilc);
- i = 0;
- sum = 0;
- do {
- if (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) {
- if (tqe->type == WILC_CFG_PKT)
- vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET;
+ else if (tqe->type == WILC_NET_PKT)
+ vmm_sz = ETH_ETHERNET_HDR_OFFSET;
+
+ else
+ vmm_sz = HOST_HDR_OFFSET;
+
+ vmm_sz += tqe->buffer_size;
+
+ if (vmm_sz & 0x3)
+ vmm_sz = (vmm_sz + 4) & ~0x3;
- else if (tqe->type == WILC_NET_PKT)
- vmm_sz = ETH_ETHERNET_HDR_OFFSET;
+ if ((sum + vmm_sz) > LINUX_TX_SIZE)
+ break;
- else
- vmm_sz = HOST_HDR_OFFSET;
+ vmm_table[i] = vmm_sz / 4;
+ if (tqe->type == WILC_CFG_PKT)
+ vmm_table[i] |= BIT(10);
+ vmm_table[i] = cpu_to_le32(vmm_table[i]);
- vmm_sz += tqe->buffer_size;
+ i++;
+ sum += vmm_sz;
+ tqe = wilc_wlan_txq_get_next(wilc, tqe);
+ } else {
+ break;
+ }
+ } while (1);
+
+ if (i == 0)
+ goto out;
+ vmm_table[i] = 0x0;
+
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
+ counter = 0;
+ func = wilc->hif_func;
+ do {
+ ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, &reg);
+ if (!ret)
+ break;
- if (vmm_sz & 0x3)
- vmm_sz = (vmm_sz + 4) & ~0x3;
+ if ((reg & 0x1) == 0)
+ break;
- if ((sum + vmm_sz) > LINUX_TX_SIZE)
- break;
+ counter++;
+ if (counter > 200) {
+ counter = 0;
+ ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0);
+ break;
+ }
+ } while (!wilc->quit);
- vmm_table[i] = vmm_sz / 4;
- if (tqe->type == WILC_CFG_PKT)
- vmm_table[i] |= BIT(10);
- vmm_table[i] = cpu_to_le32(vmm_table[i]);
+ if (!ret)
+ goto out_release_bus;
- i++;
- sum += vmm_sz;
- tqe = wilc_wlan_txq_get_next(wilc, tqe);
- } else {
- break;
- }
- } while (1);
+ timeout = 200;
+ do {
+ ret = func->hif_block_tx(wilc,
+ WILC_VMM_TBL_RX_SHADOW_BASE,
+ (u8 *)vmm_table,
+ ((i + 1) * 4));
+ if (!ret)
+ break;
- if (i == 0)
+ ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2);
+ if (!ret)
break;
- vmm_table[i] = 0x0;
- acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
- counter = 0;
do {
- ret = wilc->hif_func->hif_read_reg(wilc,
- WILC_HOST_TX_CTRL,
- &reg);
+ ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
if (!ret)
break;
-
- if ((reg & 0x1) == 0)
- break;
-
- counter++;
- if (counter > 200) {
- counter = 0;
- ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0);
+ if ((reg >> 2) & 0x1) {
+ entries = ((reg >> 3) & 0x3f);
break;
}
- } while (!wilc->quit);
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+ } while (--timeout);
+ if (timeout <= 0) {
+ ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0);
+ break;
+ }
if (!ret)
- goto _end_;
+ break;
- timeout = 200;
- do {
- ret = wilc->hif_func->hif_block_tx(wilc, WILC_VMM_TBL_RX_SHADOW_BASE, (u8 *)vmm_table, ((i + 1) * 4));
+ if (entries == 0) {
+ ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, &reg);
if (!ret)
break;
-
- ret = wilc->hif_func->hif_write_reg(wilc,
- WILC_HOST_VMM_CTL,
- 0x2);
+ reg &= ~BIT(0);
+ ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg);
if (!ret)
break;
+ break;
+ }
+ break;
+ } while (1);
- do {
- ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
- if (!ret)
- break;
- if ((reg >> 2) & 0x1) {
- entries = ((reg >> 3) & 0x3f);
- break;
- }
- release_bus(wilc, RELEASE_ALLOW_SLEEP);
- } while (--timeout);
- if (timeout <= 0) {
- ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0);
- break;
- }
+ if (!ret)
+ goto out_release_bus;
- if (!ret)
- break;
+ if (entries == 0) {
+ ret = WILC_TX_ERR_NO_BUF;
+ goto out_release_bus;
+ }
- if (entries == 0) {
- ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, &reg);
- if (!ret)
- break;
- reg &= ~BIT(0);
- ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg);
- if (!ret)
- break;
- break;
- }
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
+
+ offset = 0;
+ i = 0;
+ do {
+ u32 header, buffer_offset;
+ char *bssid;
+
+ tqe = wilc_wlan_txq_remove_from_head(dev);
+ if (!tqe)
break;
- } while (1);
- if (!ret)
- goto _end_;
+ if (vmm_table[i] == 0)
+ break;
- if (entries == 0) {
- ret = WILC_TX_ERR_NO_BUF;
- goto _end_;
- }
+ vmm_table[i] = cpu_to_le32(vmm_table[i]);
+ vmm_sz = (vmm_table[i] & 0x3ff);
+ vmm_sz *= 4;
+ header = (tqe->type << 31) |
+ (tqe->buffer_size << 15) |
+ vmm_sz;
+ if (tqe->type == WILC_MGMT_PKT)
+ header |= BIT(30);
+ else
+ header &= ~BIT(30);
- release_bus(wilc, RELEASE_ALLOW_SLEEP);
+ header = cpu_to_le32(header);
+ memcpy(&txb[offset], &header, 4);
+ if (tqe->type == WILC_CFG_PKT) {
+ buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
+ } else if (tqe->type == WILC_NET_PKT) {
+ bssid = ((struct tx_complete_data *)(tqe->priv))->bssid;
- offset = 0;
- i = 0;
- do {
- tqe = wilc_wlan_txq_remove_from_head(dev);
- if (tqe && vmm_table[i] != 0) {
- u32 header, buffer_offset;
-
- vmm_table[i] = cpu_to_le32(vmm_table[i]);
- vmm_sz = (vmm_table[i] & 0x3ff);
- vmm_sz *= 4;
- header = (tqe->type << 31) |
- (tqe->buffer_size << 15) |
- vmm_sz;
- if (tqe->type == WILC_MGMT_PKT)
- header |= BIT(30);
- else
- header &= ~BIT(30);
-
- header = cpu_to_le32(header);
- memcpy(&txb[offset], &header, 4);
- if (tqe->type == WILC_CFG_PKT) {
- buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET;
- } else if (tqe->type == WILC_NET_PKT) {
- char *bssid = ((struct tx_complete_data *)(tqe->priv))->bssid;
-
- buffer_offset = ETH_ETHERNET_HDR_OFFSET;
- memcpy(&txb[offset + 8], bssid, 6);
- } else {
- buffer_offset = HOST_HDR_OFFSET;
- }
+ buffer_offset = ETH_ETHERNET_HDR_OFFSET;
+ memcpy(&txb[offset + 8], bssid, 6);
+ } else {
+ buffer_offset = HOST_HDR_OFFSET;
+ }
- memcpy(&txb[offset + buffer_offset],
- tqe->buffer, tqe->buffer_size);
- offset += vmm_sz;
- i++;
- tqe->status = 1;
- if (tqe->tx_complete_func)
- tqe->tx_complete_func(tqe->priv,
- tqe->status);
- if (tqe->tcp_pending_ack_idx != NOT_TCP_ACK &&
- tqe->tcp_pending_ack_idx < MAX_PENDING_ACKS)
- pending_acks_info[tqe->tcp_pending_ack_idx].txqe = NULL;
- kfree(tqe);
- } else {
- break;
- }
- } while (--entries);
+ memcpy(&txb[offset + buffer_offset],
+ tqe->buffer, tqe->buffer_size);
+ offset += vmm_sz;
+ i++;
+ tqe->status = 1;
+ if (tqe->tx_complete_func)
+ tqe->tx_complete_func(tqe->priv, tqe->status);
+ if (tqe->tcp_pending_ack_idx != NOT_TCP_ACK &&
+ tqe->tcp_pending_ack_idx < MAX_PENDING_ACKS)
+ pending_acks_info[tqe->tcp_pending_ack_idx].txqe = NULL;
+ kfree(tqe);
+ } while (--entries);
- acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
+ acquire_bus(wilc, ACQUIRE_AND_WAKEUP);
- ret = wilc->hif_func->hif_clear_int_ext(wilc, ENABLE_TX_VMM);
- if (!ret)
- goto _end_;
+ ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM);
+ if (!ret)
+ goto out_release_bus;
- ret = wilc->hif_func->hif_block_tx_ext(wilc, 0, txb, offset);
- if (!ret)
- goto _end_;
+ ret = func->hif_block_tx_ext(wilc, 0, txb, offset);
-_end_:
+out_release_bus:
+ release_bus(wilc, RELEASE_ALLOW_SLEEP);
- release_bus(wilc, RELEASE_ALLOW_SLEEP);
- if (ret != 1)
- break;
- } while (0);
+out:
mutex_unlock(&wilc->txq_add_to_head_cs);
wilc->txq_exit = 1;
@@ -760,9 +773,70 @@ _end_:
return ret;
}
+static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size)
+{
+ int offset = 0;
+ u32 header;
+ u32 pkt_len, pkt_offset, tp_len;
+ int is_cfg_packet;
+ u8 *buff_ptr;
+
+ do {
+ buff_ptr = buffer + offset;
+ memcpy(&header, buff_ptr, 4);
+ header = cpu_to_le32(header);
+
+ is_cfg_packet = (header >> 31) & 0x1;
+ pkt_offset = (header >> 22) & 0x1ff;
+ tp_len = (header >> 11) & 0x7ff;
+ pkt_len = header & 0x7ff;
+
+ if (pkt_len == 0 || tp_len == 0)
+ break;
+
+ if (pkt_offset & IS_MANAGMEMENT) {
+ pkt_offset &= ~(IS_MANAGMEMENT |
+ IS_MANAGMEMENT_CALLBACK |
+ IS_MGMT_STATUS_SUCCES);
+ buff_ptr += HOST_HDR_OFFSET;
+ wilc_wfi_mgmt_rx(wilc, buff_ptr, pkt_len);
+ } else {
+ if (!is_cfg_packet) {
+ if (pkt_len > 0) {
+ wilc_frmw_to_linux(wilc, buff_ptr,
+ pkt_len,
+ pkt_offset);
+ }
+ } else {
+ struct wilc_cfg_rsp rsp;
+
+ buff_ptr += pkt_offset;
+
+ wilc_wlan_cfg_indicate_rx(wilc, buff_ptr,
+ pkt_len,
+ &rsp);
+ if (rsp.type == WILC_CFG_RSP) {
+ if (wilc->cfg_seq_no == rsp.seq_no)
+ complete(&wilc->cfg_event);
+ } else if (rsp.type == WILC_CFG_RSP_STATUS) {
+ wilc_mac_indicate(wilc,
+ WILC_MAC_INDICATE_STATUS);
+
+ } else if (rsp.type == WILC_CFG_RSP_SCAN) {
+ wilc_mac_indicate(wilc,
+ WILC_MAC_INDICATE_SCAN);
+ }
+ }
+ }
+ offset += tp_len;
+ if (offset >= size)
+ break;
+ } while (1);
+}
+
static void wilc_wlan_handle_rxq(struct wilc *wilc)
{
- int offset = 0, size;
+ int size;
u8 *buffer;
struct rxq_entry_t *rqe;
@@ -779,61 +853,8 @@ static void wilc_wlan_handle_rxq(struct wilc *wilc)
buffer = rqe->buffer;
size = rqe->buffer_size;
- offset = 0;
-
- do {
- u32 header;
- u32 pkt_len, pkt_offset, tp_len;
- int is_cfg_packet;
+ wilc_wlan_handle_rx_buff(wilc, buffer, size);
- memcpy(&header, &buffer[offset], 4);
- header = cpu_to_le32(header);
-
- is_cfg_packet = (header >> 31) & 0x1;
- pkt_offset = (header >> 22) & 0x1ff;
- tp_len = (header >> 11) & 0x7ff;
- pkt_len = header & 0x7ff;
-
- if (pkt_len == 0 || tp_len == 0)
- break;
-
- #define IS_MANAGMEMENT 0x100
- #define IS_MANAGMEMENT_CALLBACK 0x080
- #define IS_MGMT_STATUS_SUCCES 0x040
-
- if (pkt_offset & IS_MANAGMEMENT) {
- pkt_offset &= ~(IS_MANAGMEMENT |
- IS_MANAGMEMENT_CALLBACK |
- IS_MGMT_STATUS_SUCCES);
-
- WILC_WFI_mgmt_rx(wilc, &buffer[offset + HOST_HDR_OFFSET], pkt_len);
- } else {
- if (!is_cfg_packet) {
- if (pkt_len > 0) {
- wilc_frmw_to_linux(wilc,
- &buffer[offset],
- pkt_len,
- pkt_offset);
- }
- } else {
- struct wilc_cfg_rsp rsp;
-
- wilc_wlan_cfg_indicate_rx(wilc, &buffer[pkt_offset + offset], pkt_len, &rsp);
- if (rsp.type == WILC_CFG_RSP) {
- if (wilc->cfg_seq_no == rsp.seq_no)
- complete(&wilc->cfg_event);
- } else if (rsp.type == WILC_CFG_RSP_STATUS) {
- wilc_mac_indicate(wilc, WILC_MAC_INDICATE_STATUS);
-
- } else if (rsp.type == WILC_CFG_RSP_SCAN) {
- wilc_mac_indicate(wilc, WILC_MAC_INDICATE_SCAN);
- }
- }
- }
- offset += tp_len;
- if (offset >= size)
- break;
- } while (1);
kfree(rqe);
} while (1);
@@ -1216,27 +1237,28 @@ int wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer,
offset += ret_size;
wilc->cfg_frame_offset = offset;
- if (commit) {
- netdev_dbg(vif->ndev,
- "[WILC]PACKET Commit with sequence number %d\n",
- wilc->cfg_seq_no);
- netdev_dbg(vif->ndev, "Processing cfg_set()\n");
- wilc->cfg_frame_in_use = 1;
+ if (!commit)
+ return ret_size;
- if (wilc_wlan_cfg_commit(vif, WILC_CFG_SET, drv_handler))
- ret_size = 0;
+ netdev_dbg(vif->ndev,
+ "[WILC]PACKET Commit with sequence number %d\n",
+ wilc->cfg_seq_no);
+ netdev_dbg(vif->ndev, "Processing cfg_set()\n");
+ wilc->cfg_frame_in_use = 1;
- if (!wait_for_completion_timeout(&wilc->cfg_event,
- msecs_to_jiffies(CFG_PKTS_TIMEOUT))) {
- netdev_dbg(vif->ndev, "Set Timed Out\n");
- ret_size = 0;
- }
+ if (wilc_wlan_cfg_commit(vif, WILC_CFG_SET, drv_handler))
+ ret_size = 0;
- wilc->cfg_frame_in_use = 0;
- wilc->cfg_frame_offset = 0;
- wilc->cfg_seq_no += 1;
+ if (!wait_for_completion_timeout(&wilc->cfg_event,
+ msecs_to_jiffies(CFG_PKTS_TIMEOUT))) {
+ netdev_dbg(vif->ndev, "Set Timed Out\n");
+ ret_size = 0;
}
+ wilc->cfg_frame_in_use = 0;
+ wilc->cfg_frame_offset = 0;
+ wilc->cfg_seq_no += 1;
+
return ret_size;
}
@@ -1258,21 +1280,22 @@ int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit,
offset += ret_size;
wilc->cfg_frame_offset = offset;
- if (commit) {
- wilc->cfg_frame_in_use = 1;
+ if (!commit)
+ return ret_size;
- if (wilc_wlan_cfg_commit(vif, WILC_CFG_QUERY, drv_handler))
- ret_size = 0;
+ wilc->cfg_frame_in_use = 1;
- if (!wait_for_completion_timeout(&wilc->cfg_event,
- msecs_to_jiffies(CFG_PKTS_TIMEOUT))) {
- netdev_dbg(vif->ndev, "Get Timed Out\n");
- ret_size = 0;
- }
- wilc->cfg_frame_in_use = 0;
- wilc->cfg_frame_offset = 0;
- wilc->cfg_seq_no += 1;
+ if (wilc_wlan_cfg_commit(vif, WILC_CFG_QUERY, drv_handler))
+ ret_size = 0;
+
+ if (!wait_for_completion_timeout(&wilc->cfg_event,
+ msecs_to_jiffies(CFG_PKTS_TIMEOUT))) {
+ netdev_dbg(vif->ndev, "Get Timed Out\n");
+ ret_size = 0;
}
+ wilc->cfg_frame_in_use = 0;
+ wilc->cfg_frame_offset = 0;
+ wilc->cfg_seq_no += 1;
return ret_size;
}
diff --git a/drivers/staging/wilc1000/wilc_wlan.h b/drivers/staging/wilc1000/wilc_wlan.h
index da7173105497..fa157a67b045 100644
--- a/drivers/staging/wilc1000/wilc_wlan.h
+++ b/drivers/staging/wilc1000/wilc_wlan.h
@@ -195,6 +195,11 @@
#define ENABLE_TX_VMM (SEL_VMM_TBL0 | EN_VMM)
/*time for expiring the completion of cfg packets*/
#define CFG_PKTS_TIMEOUT 2000
+
+#define IS_MANAGMEMENT 0x100
+#define IS_MANAGMEMENT_CALLBACK 0x080
+#define IS_MGMT_STATUS_SUCCES 0x040
+
/********************************************
*
* Debug Type
diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.c b/drivers/staging/wilc1000/wilc_wlan_cfg.c
index aeb5417f3587..2b44f4cc56b7 100644
--- a/drivers/staging/wilc1000/wilc_wlan_cfg.c
+++ b/drivers/staging/wilc1000/wilc_wlan_cfg.c
@@ -221,7 +221,8 @@ static int wilc_wlan_cfg_set_word(u8 *frame, u32 offset, u16 id, u32 val32)
return 8;
}
-static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str, u32 size)
+static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str,
+ u32 size)
{
u8 *buf;
@@ -483,20 +484,21 @@ int wilc_wlan_cfg_get_wid_value(u16 wid, u8 *buffer, u32 buffer_size)
} while (1);
} else if (type == CFG_STR_CMD) {
do {
- if (g_cfg_str[i].id == WID_NIL)
+ u32 id = g_cfg_str[i].id;
+
+ if (id == WID_NIL)
break;
- if (g_cfg_str[i].id == wid) {
+ if (id == wid) {
u32 size = g_cfg_str[i].str[0] |
(g_cfg_str[i].str[1] << 8);
if (buffer_size >= size) {
- if (g_cfg_str[i].id == WID_SITE_SURVEY_RESULTS) {
+ if (id == WID_SITE_SURVEY_RESULTS) {
static int toggle;
i += toggle;
toggle ^= 1;
-
}
memcpy(buffer, &g_cfg_str[i].str[2],
size);
@@ -523,9 +525,12 @@ int wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
frame += 4;
size -= 4;
- /**
- * The valid types of response messages are 'R' (Response), 'I' (Information), and 'N' (Network Information)
- **/
+ /*
+ * The valid types of response messages are
+ * 'R' (Response),
+ * 'I' (Information), and
+ * 'N' (Network Information)
+ */
switch (msg_type) {
case 'R':
diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c
index 78934e435fcf..d7de9e9c47a2 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.c
+++ b/drivers/staging/wlan-ng/prism2mgmt.c
@@ -563,7 +563,7 @@ int prism2mgmt_start(struct wlandevice *wlandev, void *msgp)
/*** STATION ***/
/* Set the REQUIRED config items */
/* SSID */
- pstr = (struct p80211pstrd *)&(msg->ssid.data);
+ pstr = (struct p80211pstrd *)&msg->ssid.data;
prism2mgmt_pstr2bytestr(p2bytestr, pstr);
result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID,
bytebuf, HFA384x_RID_CNFOWNSSID_LEN);
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index 10107de0119a..eca0b50f0df6 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -544,41 +544,42 @@ static u8 XGIfb_search_refresh_rate(struct xgifb_video_info *xgifb_info,
yres = XGIbios_mode[xgifb_info->mode_idx].yres;
xgifb_info->rate_idx = 0;
- while ((XGIfb_vrate[i].idx != 0) && (XGIfb_vrate[i].xres <= xres)) {
- if ((XGIfb_vrate[i].xres == xres) &&
- (XGIfb_vrate[i].yres == yres)) {
- if (XGIfb_vrate[i].refresh == rate) {
+
+ while (XGIfb_vrate[i].idx != 0 && XGIfb_vrate[i].xres <= xres) {
+ /* Skip values with xres or yres less than specified */
+ if ((XGIfb_vrate[i].yres != yres) ||
+ (XGIfb_vrate[i].xres != xres)) {
+ i++;
+ continue;
+ }
+ if (XGIfb_vrate[i].refresh == rate) {
+ xgifb_info->rate_idx = XGIfb_vrate[i].idx;
+ break;
+ } else if (XGIfb_vrate[i].refresh > rate) {
+ if (XGIfb_vrate[i].refresh - rate <= 3) {
+ pr_debug("Adjusting rate from %d up to %d\n",
+ rate, XGIfb_vrate[i].refresh);
xgifb_info->rate_idx = XGIfb_vrate[i].idx;
- break;
- } else if (XGIfb_vrate[i].refresh > rate) {
- if ((XGIfb_vrate[i].refresh - rate) <= 3) {
- pr_debug("Adjusting rate from %d up to %d\n",
- rate, XGIfb_vrate[i].refresh);
- xgifb_info->rate_idx =
- XGIfb_vrate[i].idx;
- xgifb_info->refresh_rate =
- XGIfb_vrate[i].refresh;
- } else if (((rate - XGIfb_vrate[i - 1].refresh)
- <= 2) && (XGIfb_vrate[i].idx
- != 1)) {
- pr_debug("Adjusting rate from %d down to %d\n",
- rate,
- XGIfb_vrate[i - 1].refresh);
- xgifb_info->rate_idx =
- XGIfb_vrate[i - 1].idx;
- xgifb_info->refresh_rate =
- XGIfb_vrate[i - 1].refresh;
- }
- break;
- } else if ((rate - XGIfb_vrate[i].refresh) <= 2) {
+ xgifb_info->refresh_rate =
+ XGIfb_vrate[i].refresh;
+ } else if ((XGIfb_vrate[i].idx != 1) &&
+ (rate - XGIfb_vrate[i - 1].refresh <= 2)) {
pr_debug("Adjusting rate from %d down to %d\n",
- rate, XGIfb_vrate[i].refresh);
- xgifb_info->rate_idx = XGIfb_vrate[i].idx;
- break;
+ rate, XGIfb_vrate[i - 1].refresh);
+ xgifb_info->rate_idx = XGIfb_vrate[i - 1].idx;
+ xgifb_info->refresh_rate =
+ XGIfb_vrate[i - 1].refresh;
}
+ break;
+ } else if (rate - XGIfb_vrate[i].refresh <= 2) {
+ pr_debug("Adjusting rate from %d down to %d\n",
+ rate, XGIfb_vrate[i].refresh);
+ xgifb_info->rate_idx = XGIfb_vrate[i].idx;
+ break;
}
i++;
}
+
if (xgifb_info->rate_idx > 0)
return xgifb_info->rate_idx;
pr_info("Unsupported rate %d for %dx%d\n",
diff --git a/drivers/thunderbolt/dma_port.c b/drivers/thunderbolt/dma_port.c
index af6dde347bee..f2701194f810 100644
--- a/drivers/thunderbolt/dma_port.c
+++ b/drivers/thunderbolt/dma_port.c
@@ -170,24 +170,22 @@ static int dma_port_write(struct tb_ctl *ctl, const void *buffer, u64 route,
static int dma_find_port(struct tb_switch *sw)
{
- int port, ret;
- u32 type;
+ static const int ports[] = { 3, 5, 7 };
+ int i;
/*
- * The DMA (NHI) port is either 3 or 5 depending on the
- * controller. Try both starting from 5 which is more common.
+ * The DMA (NHI) port is either 3, 5 or 7 depending on the
+ * controller. Try all of them.
*/
- port = 5;
- ret = dma_port_read(sw->tb->ctl, &type, tb_route(sw), port, 2, 1,
- DMA_PORT_TIMEOUT);
- if (!ret && (type & 0xffffff) == TB_TYPE_NHI)
- return port;
-
- port = 3;
- ret = dma_port_read(sw->tb->ctl, &type, tb_route(sw), port, 2, 1,
- DMA_PORT_TIMEOUT);
- if (!ret && (type & 0xffffff) == TB_TYPE_NHI)
- return port;
+ for (i = 0; i < ARRAY_SIZE(ports); i++) {
+ u32 type;
+ int ret;
+
+ ret = dma_port_read(sw->tb->ctl, &type, tb_route(sw), ports[i],
+ 2, 1, DMA_PORT_TIMEOUT);
+ if (!ret && (type & 0xffffff) == TB_TYPE_NHI)
+ return ports[i];
+ }
return -ENODEV;
}
diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c
index 9b90115319ce..6281266b8ec0 100644
--- a/drivers/thunderbolt/domain.c
+++ b/drivers/thunderbolt/domain.c
@@ -117,23 +117,151 @@ static const char * const tb_security_names[] = {
[TB_SECURITY_USER] = "user",
[TB_SECURITY_SECURE] = "secure",
[TB_SECURITY_DPONLY] = "dponly",
+ [TB_SECURITY_USBONLY] = "usbonly",
};
+static ssize_t boot_acl_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct tb *tb = container_of(dev, struct tb, dev);
+ uuid_t *uuids;
+ ssize_t ret;
+ int i;
+
+ uuids = kcalloc(tb->nboot_acl, sizeof(uuid_t), GFP_KERNEL);
+ if (!uuids)
+ return -ENOMEM;
+
+ if (mutex_lock_interruptible(&tb->lock)) {
+ ret = -ERESTARTSYS;
+ goto out;
+ }
+ ret = tb->cm_ops->get_boot_acl(tb, uuids, tb->nboot_acl);
+ if (ret) {
+ mutex_unlock(&tb->lock);
+ goto out;
+ }
+ mutex_unlock(&tb->lock);
+
+ for (ret = 0, i = 0; i < tb->nboot_acl; i++) {
+ if (!uuid_is_null(&uuids[i]))
+ ret += snprintf(buf + ret, PAGE_SIZE - ret, "%pUb",
+ &uuids[i]);
+
+ ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s",
+ i < tb->nboot_acl - 1 ? "," : "\n");
+ }
+
+out:
+ kfree(uuids);
+ return ret;
+}
+
+static ssize_t boot_acl_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tb *tb = container_of(dev, struct tb, dev);
+ char *str, *s, *uuid_str;
+ ssize_t ret = 0;
+ uuid_t *acl;
+ int i = 0;
+
+ /*
+ * Make sure the value is not bigger than tb->nboot_acl * UUID
+ * length + commas and optional "\n". Also the smallest allowable
+ * string is tb->nboot_acl * ",".
+ */
+ if (count > (UUID_STRING_LEN + 1) * tb->nboot_acl + 1)
+ return -EINVAL;
+ if (count < tb->nboot_acl - 1)
+ return -EINVAL;
+
+ str = kstrdup(buf, GFP_KERNEL);
+ if (!str)
+ return -ENOMEM;
+
+ acl = kcalloc(tb->nboot_acl, sizeof(uuid_t), GFP_KERNEL);
+ if (!acl) {
+ ret = -ENOMEM;
+ goto err_free_str;
+ }
+
+ uuid_str = strim(str);
+ while ((s = strsep(&uuid_str, ",")) != NULL && i < tb->nboot_acl) {
+ size_t len = strlen(s);
+
+ if (len) {
+ if (len != UUID_STRING_LEN) {
+ ret = -EINVAL;
+ goto err_free_acl;
+ }
+ ret = uuid_parse(s, &acl[i]);
+ if (ret)
+ goto err_free_acl;
+ }
+
+ i++;
+ }
+
+ if (s || i < tb->nboot_acl) {
+ ret = -EINVAL;
+ goto err_free_acl;
+ }
+
+ if (mutex_lock_interruptible(&tb->lock)) {
+ ret = -ERESTARTSYS;
+ goto err_free_acl;
+ }
+ ret = tb->cm_ops->set_boot_acl(tb, acl, tb->nboot_acl);
+ mutex_unlock(&tb->lock);
+
+err_free_acl:
+ kfree(acl);
+err_free_str:
+ kfree(str);
+
+ return ret ?: count;
+}
+static DEVICE_ATTR_RW(boot_acl);
+
static ssize_t security_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct tb *tb = container_of(dev, struct tb, dev);
+ const char *name = "unknown";
- return sprintf(buf, "%s\n", tb_security_names[tb->security_level]);
+ if (tb->security_level < ARRAY_SIZE(tb_security_names))
+ name = tb_security_names[tb->security_level];
+
+ return sprintf(buf, "%s\n", name);
}
static DEVICE_ATTR_RO(security);
static struct attribute *domain_attrs[] = {
+ &dev_attr_boot_acl.attr,
&dev_attr_security.attr,
NULL,
};
+static umode_t domain_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct tb *tb = container_of(dev, struct tb, dev);
+
+ if (attr == &dev_attr_boot_acl.attr) {
+ if (tb->nboot_acl &&
+ tb->cm_ops->get_boot_acl &&
+ tb->cm_ops->set_boot_acl)
+ return attr->mode;
+ return 0;
+ }
+
+ return attr->mode;
+}
+
static struct attribute_group domain_attr_group = {
+ .is_visible = domain_attr_is_visible,
.attrs = domain_attrs,
};
diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c
index ab02d13f40b7..2d2ceda9aa26 100644
--- a/drivers/thunderbolt/icm.c
+++ b/drivers/thunderbolt/icm.c
@@ -41,7 +41,8 @@
#define PHY_PORT_CS1_LINK_STATE_MASK GENMASK(29, 26)
#define PHY_PORT_CS1_LINK_STATE_SHIFT 26
-#define ICM_TIMEOUT 5000 /* ms */
+#define ICM_TIMEOUT 5000 /* ms */
+#define ICM_APPROVE_TIMEOUT 10000 /* ms */
#define ICM_MAX_LINK 4
#define ICM_MAX_DEPTH 6
@@ -55,9 +56,11 @@
* @vnd_cap: Vendor defined capability where PCIe2CIO mailbox resides
* (only set when @upstream_port is not %NULL)
* @safe_mode: ICM is in safe mode
+ * @max_boot_acl: Maximum number of preboot ACL entries (%0 if not supported)
* @is_supported: Checks if we can support ICM on this controller
* @get_mode: Read and return the ICM firmware mode (optional)
* @get_route: Find a route string for given switch
+ * @driver_ready: Send driver ready message to ICM
* @device_connected: Handle device connected ICM message
* @device_disconnected: Handle device disconnected ICM message
* @xdomain_connected - Handle XDomain connected ICM message
@@ -67,11 +70,15 @@ struct icm {
struct mutex request_lock;
struct delayed_work rescan_work;
struct pci_dev *upstream_port;
+ size_t max_boot_acl;
int vnd_cap;
bool safe_mode;
bool (*is_supported)(struct tb *tb);
int (*get_mode)(struct tb *tb);
int (*get_route)(struct tb *tb, u8 link, u8 depth, u64 *route);
+ int (*driver_ready)(struct tb *tb,
+ enum tb_security_level *security_level,
+ size_t *nboot_acl);
void (*device_connected)(struct tb *tb,
const struct icm_pkg_header *hdr);
void (*device_disconnected)(struct tb *tb,
@@ -111,6 +118,12 @@ static inline u64 get_route(u32 route_hi, u32 route_lo)
return (u64)route_hi << 32 | route_lo;
}
+static inline u64 get_parent_route(u64 route)
+{
+ int depth = tb_route_length(route);
+ return depth ? route & ~(0xffULL << (depth - 1) * TB_ROUTE_SHIFT) : 0;
+}
+
static bool icm_match(const struct tb_cfg_request *req,
const struct ctl_pkg *pkg)
{
@@ -245,6 +258,28 @@ err_free:
return ret;
}
+static int
+icm_fr_driver_ready(struct tb *tb, enum tb_security_level *security_level,
+ size_t *nboot_acl)
+{
+ struct icm_fr_pkg_driver_ready_response reply;
+ struct icm_pkg_driver_ready request = {
+ .hdr.code = ICM_DRIVER_READY,
+ };
+ int ret;
+
+ memset(&reply, 0, sizeof(reply));
+ ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
+ 1, ICM_TIMEOUT);
+ if (ret)
+ return ret;
+
+ if (security_level)
+ *security_level = reply.security_level & ICM_FR_SLEVEL_MASK;
+
+ return 0;
+}
+
static int icm_fr_approve_switch(struct tb *tb, struct tb_switch *sw)
{
struct icm_fr_pkg_approve_device request;
@@ -260,7 +295,7 @@ static int icm_fr_approve_switch(struct tb *tb, struct tb_switch *sw)
memset(&reply, 0, sizeof(reply));
/* Use larger timeout as establishing tunnels can take some time */
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
- 1, 10000);
+ 1, ICM_APPROVE_TIMEOUT);
if (ret)
return ret;
@@ -374,6 +409,59 @@ static int icm_fr_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd)
return 0;
}
+static void add_switch(struct tb_switch *parent_sw, u64 route,
+ const uuid_t *uuid, u8 connection_id, u8 connection_key,
+ u8 link, u8 depth, enum tb_security_level security_level,
+ bool authorized, bool boot)
+{
+ struct tb_switch *sw;
+
+ sw = tb_switch_alloc(parent_sw->tb, &parent_sw->dev, route);
+ if (!sw)
+ return;
+
+ sw->uuid = kmemdup(uuid, sizeof(*uuid), GFP_KERNEL);
+ sw->connection_id = connection_id;
+ sw->connection_key = connection_key;
+ sw->link = link;
+ sw->depth = depth;
+ sw->authorized = authorized;
+ sw->security_level = security_level;
+ sw->boot = boot;
+
+ /* Link the two switches now */
+ tb_port_at(route, parent_sw)->remote = tb_upstream_port(sw);
+ tb_upstream_port(sw)->remote = tb_port_at(route, parent_sw);
+
+ if (tb_switch_add(sw)) {
+ tb_port_at(tb_route(sw), parent_sw)->remote = NULL;
+ tb_switch_put(sw);
+ return;
+ }
+}
+
+static void update_switch(struct tb_switch *parent_sw, struct tb_switch *sw,
+ u64 route, u8 connection_id, u8 connection_key,
+ u8 link, u8 depth, bool boot)
+{
+ /* Disconnect from parent */
+ tb_port_at(tb_route(sw), parent_sw)->remote = NULL;
+ /* Re-connect via updated port*/
+ tb_port_at(route, parent_sw)->remote = tb_upstream_port(sw);
+
+ /* Update with the new addressing information */
+ sw->config.route_hi = upper_32_bits(route);
+ sw->config.route_lo = lower_32_bits(route);
+ sw->connection_id = connection_id;
+ sw->connection_key = connection_key;
+ sw->link = link;
+ sw->depth = depth;
+ sw->boot = boot;
+
+ /* This switch still exists */
+ sw->is_unplugged = false;
+}
+
static void remove_switch(struct tb_switch *sw)
{
struct tb_switch *parent_sw;
@@ -383,15 +471,52 @@ static void remove_switch(struct tb_switch *sw)
tb_switch_remove(sw);
}
+static void add_xdomain(struct tb_switch *sw, u64 route,
+ const uuid_t *local_uuid, const uuid_t *remote_uuid,
+ u8 link, u8 depth)
+{
+ struct tb_xdomain *xd;
+
+ xd = tb_xdomain_alloc(sw->tb, &sw->dev, route, local_uuid, remote_uuid);
+ if (!xd)
+ return;
+
+ xd->link = link;
+ xd->depth = depth;
+
+ tb_port_at(route, sw)->xdomain = xd;
+
+ tb_xdomain_add(xd);
+}
+
+static void update_xdomain(struct tb_xdomain *xd, u64 route, u8 link)
+{
+ xd->link = link;
+ xd->route = route;
+ xd->is_unplugged = false;
+}
+
+static void remove_xdomain(struct tb_xdomain *xd)
+{
+ struct tb_switch *sw;
+
+ sw = tb_to_switch(xd->dev.parent);
+ tb_port_at(xd->route, sw)->xdomain = NULL;
+ tb_xdomain_remove(xd);
+}
+
static void
icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
{
const struct icm_fr_event_device_connected *pkg =
(const struct icm_fr_event_device_connected *)hdr;
+ enum tb_security_level security_level;
struct tb_switch *sw, *parent_sw;
struct icm *icm = tb_priv(tb);
bool authorized = false;
+ struct tb_xdomain *xd;
u8 link, depth;
+ bool boot;
u64 route;
int ret;
@@ -399,6 +524,15 @@ icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
depth = (pkg->link_info & ICM_LINK_INFO_DEPTH_MASK) >>
ICM_LINK_INFO_DEPTH_SHIFT;
authorized = pkg->link_info & ICM_LINK_INFO_APPROVED;
+ security_level = (pkg->hdr.flags & ICM_FLAGS_SLEVEL_MASK) >>
+ ICM_FLAGS_SLEVEL_SHIFT;
+ boot = pkg->link_info & ICM_LINK_INFO_BOOT;
+
+ if (pkg->link_info & ICM_LINK_INFO_REJECTED) {
+ tb_info(tb, "switch at %u.%u was rejected by ICM firmware because topology limit exceeded\n",
+ link, depth);
+ return;
+ }
ret = icm->get_route(tb, link, depth, &route);
if (ret) {
@@ -425,16 +559,8 @@ icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
*/
if (sw->depth == depth && sw_phy_port == phy_port &&
!!sw->authorized == authorized) {
- tb_port_at(tb_route(sw), parent_sw)->remote = NULL;
- tb_port_at(route, parent_sw)->remote =
- tb_upstream_port(sw);
- sw->config.route_hi = upper_32_bits(route);
- sw->config.route_lo = lower_32_bits(route);
- sw->connection_id = pkg->connection_id;
- sw->connection_key = pkg->connection_key;
- sw->link = link;
- sw->depth = depth;
- sw->is_unplugged = false;
+ update_switch(parent_sw, sw, route, pkg->connection_id,
+ pkg->connection_key, link, depth, boot);
tb_switch_put(sw);
return;
}
@@ -467,6 +593,13 @@ icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
tb_switch_put(sw);
}
+ /* Remove existing XDomain connection if found */
+ xd = tb_xdomain_find_by_link_depth(tb, link, depth);
+ if (xd) {
+ remove_xdomain(xd);
+ tb_xdomain_put(xd);
+ }
+
parent_sw = tb_switch_find_by_link_depth(tb, link, depth - 1);
if (!parent_sw) {
tb_err(tb, "failed to find parent switch for %u.%u\n",
@@ -474,30 +607,10 @@ icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
return;
}
- sw = tb_switch_alloc(tb, &parent_sw->dev, route);
- if (!sw) {
- tb_switch_put(parent_sw);
- return;
- }
-
- sw->uuid = kmemdup(&pkg->ep_uuid, sizeof(pkg->ep_uuid), GFP_KERNEL);
- sw->connection_id = pkg->connection_id;
- sw->connection_key = pkg->connection_key;
- sw->link = link;
- sw->depth = depth;
- sw->authorized = authorized;
- sw->security_level = (pkg->hdr.flags & ICM_FLAGS_SLEVEL_MASK) >>
- ICM_FLAGS_SLEVEL_SHIFT;
-
- /* Link the two switches now */
- tb_port_at(route, parent_sw)->remote = tb_upstream_port(sw);
- tb_upstream_port(sw)->remote = tb_port_at(route, parent_sw);
+ add_switch(parent_sw, route, &pkg->ep_uuid, pkg->connection_id,
+ pkg->connection_key, link, depth, security_level,
+ authorized, boot);
- ret = tb_switch_add(sw);
- if (ret) {
- tb_port_at(tb_route(sw), parent_sw)->remote = NULL;
- tb_switch_put(sw);
- }
tb_switch_put(parent_sw);
}
@@ -529,15 +642,6 @@ icm_fr_device_disconnected(struct tb *tb, const struct icm_pkg_header *hdr)
tb_switch_put(sw);
}
-static void remove_xdomain(struct tb_xdomain *xd)
-{
- struct tb_switch *sw;
-
- sw = tb_to_switch(xd->dev.parent);
- tb_port_at(xd->route, sw)->xdomain = NULL;
- tb_xdomain_remove(xd);
-}
-
static void
icm_fr_xdomain_connected(struct tb *tb, const struct icm_pkg_header *hdr)
{
@@ -577,9 +681,7 @@ icm_fr_xdomain_connected(struct tb *tb, const struct icm_pkg_header *hdr)
phy_port = phy_port_from_route(route, depth);
if (xd->depth == depth && xd_phy_port == phy_port) {
- xd->link = link;
- xd->route = route;
- xd->is_unplugged = false;
+ update_xdomain(xd, route, link);
tb_xdomain_put(xd);
return;
}
@@ -629,19 +731,8 @@ icm_fr_xdomain_connected(struct tb *tb, const struct icm_pkg_header *hdr)
return;
}
- xd = tb_xdomain_alloc(sw->tb, &sw->dev, route,
- &pkg->local_uuid, &pkg->remote_uuid);
- if (!xd) {
- tb_switch_put(sw);
- return;
- }
-
- xd->link = link;
- xd->depth = depth;
-
- tb_port_at(route, sw)->xdomain = xd;
-
- tb_xdomain_add(xd);
+ add_xdomain(sw, route, &pkg->local_uuid, &pkg->remote_uuid, link,
+ depth);
tb_switch_put(sw);
}
@@ -664,6 +755,351 @@ icm_fr_xdomain_disconnected(struct tb *tb, const struct icm_pkg_header *hdr)
}
}
+static int
+icm_tr_driver_ready(struct tb *tb, enum tb_security_level *security_level,
+ size_t *nboot_acl)
+{
+ struct icm_tr_pkg_driver_ready_response reply;
+ struct icm_pkg_driver_ready request = {
+ .hdr.code = ICM_DRIVER_READY,
+ };
+ int ret;
+
+ memset(&reply, 0, sizeof(reply));
+ ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
+ 1, 20000);
+ if (ret)
+ return ret;
+
+ if (security_level)
+ *security_level = reply.info & ICM_TR_INFO_SLEVEL_MASK;
+ if (nboot_acl)
+ *nboot_acl = (reply.info & ICM_TR_INFO_BOOT_ACL_MASK) >>
+ ICM_TR_INFO_BOOT_ACL_SHIFT;
+ return 0;
+}
+
+static int icm_tr_approve_switch(struct tb *tb, struct tb_switch *sw)
+{
+ struct icm_tr_pkg_approve_device request;
+ struct icm_tr_pkg_approve_device reply;
+ int ret;
+
+ memset(&request, 0, sizeof(request));
+ memcpy(&request.ep_uuid, sw->uuid, sizeof(request.ep_uuid));
+ request.hdr.code = ICM_APPROVE_DEVICE;
+ request.route_lo = sw->config.route_lo;
+ request.route_hi = sw->config.route_hi;
+ request.connection_id = sw->connection_id;
+
+ memset(&reply, 0, sizeof(reply));
+ ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
+ 1, ICM_APPROVE_TIMEOUT);
+ if (ret)
+ return ret;
+
+ if (reply.hdr.flags & ICM_FLAGS_ERROR) {
+ tb_warn(tb, "PCIe tunnel creation failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int icm_tr_add_switch_key(struct tb *tb, struct tb_switch *sw)
+{
+ struct icm_tr_pkg_add_device_key_response reply;
+ struct icm_tr_pkg_add_device_key request;
+ int ret;
+
+ memset(&request, 0, sizeof(request));
+ memcpy(&request.ep_uuid, sw->uuid, sizeof(request.ep_uuid));
+ request.hdr.code = ICM_ADD_DEVICE_KEY;
+ request.route_lo = sw->config.route_lo;
+ request.route_hi = sw->config.route_hi;
+ request.connection_id = sw->connection_id;
+ memcpy(request.key, sw->key, TB_SWITCH_KEY_SIZE);
+
+ memset(&reply, 0, sizeof(reply));
+ ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
+ 1, ICM_TIMEOUT);
+ if (ret)
+ return ret;
+
+ if (reply.hdr.flags & ICM_FLAGS_ERROR) {
+ tb_warn(tb, "Adding key to switch failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int icm_tr_challenge_switch_key(struct tb *tb, struct tb_switch *sw,
+ const u8 *challenge, u8 *response)
+{
+ struct icm_tr_pkg_challenge_device_response reply;
+ struct icm_tr_pkg_challenge_device request;
+ int ret;
+
+ memset(&request, 0, sizeof(request));
+ memcpy(&request.ep_uuid, sw->uuid, sizeof(request.ep_uuid));
+ request.hdr.code = ICM_CHALLENGE_DEVICE;
+ request.route_lo = sw->config.route_lo;
+ request.route_hi = sw->config.route_hi;
+ request.connection_id = sw->connection_id;
+ memcpy(request.challenge, challenge, TB_SWITCH_KEY_SIZE);
+
+ memset(&reply, 0, sizeof(reply));
+ ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
+ 1, ICM_TIMEOUT);
+ if (ret)
+ return ret;
+
+ if (reply.hdr.flags & ICM_FLAGS_ERROR)
+ return -EKEYREJECTED;
+ if (reply.hdr.flags & ICM_FLAGS_NO_KEY)
+ return -ENOKEY;
+
+ memcpy(response, reply.response, TB_SWITCH_KEY_SIZE);
+
+ return 0;
+}
+
+static int icm_tr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd)
+{
+ struct icm_tr_pkg_approve_xdomain_response reply;
+ struct icm_tr_pkg_approve_xdomain request;
+ int ret;
+
+ memset(&request, 0, sizeof(request));
+ request.hdr.code = ICM_APPROVE_XDOMAIN;
+ request.route_hi = upper_32_bits(xd->route);
+ request.route_lo = lower_32_bits(xd->route);
+ request.transmit_path = xd->transmit_path;
+ request.transmit_ring = xd->transmit_ring;
+ request.receive_path = xd->receive_path;
+ request.receive_ring = xd->receive_ring;
+ memcpy(&request.remote_uuid, xd->remote_uuid, sizeof(*xd->remote_uuid));
+
+ memset(&reply, 0, sizeof(reply));
+ ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
+ 1, ICM_TIMEOUT);
+ if (ret)
+ return ret;
+
+ if (reply.hdr.flags & ICM_FLAGS_ERROR)
+ return -EIO;
+
+ return 0;
+}
+
+static int icm_tr_xdomain_tear_down(struct tb *tb, struct tb_xdomain *xd,
+ int stage)
+{
+ struct icm_tr_pkg_disconnect_xdomain_response reply;
+ struct icm_tr_pkg_disconnect_xdomain request;
+ int ret;
+
+ memset(&request, 0, sizeof(request));
+ request.hdr.code = ICM_DISCONNECT_XDOMAIN;
+ request.stage = stage;
+ request.route_hi = upper_32_bits(xd->route);
+ request.route_lo = lower_32_bits(xd->route);
+ memcpy(&request.remote_uuid, xd->remote_uuid, sizeof(*xd->remote_uuid));
+
+ memset(&reply, 0, sizeof(reply));
+ ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
+ 1, ICM_TIMEOUT);
+ if (ret)
+ return ret;
+
+ if (reply.hdr.flags & ICM_FLAGS_ERROR)
+ return -EIO;
+
+ return 0;
+}
+
+static int icm_tr_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd)
+{
+ int ret;
+
+ ret = icm_tr_xdomain_tear_down(tb, xd, 1);
+ if (ret)
+ return ret;
+
+ usleep_range(10, 50);
+ return icm_tr_xdomain_tear_down(tb, xd, 2);
+}
+
+static void
+icm_tr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr)
+{
+ const struct icm_tr_event_device_connected *pkg =
+ (const struct icm_tr_event_device_connected *)hdr;
+ enum tb_security_level security_level;
+ struct tb_switch *sw, *parent_sw;
+ struct tb_xdomain *xd;
+ bool authorized, boot;
+ u64 route;
+
+ /*
+ * Currently we don't use the QoS information coming with the
+ * device connected message so simply just ignore that extra
+ * packet for now.
+ */
+ if (pkg->hdr.packet_id)
+ return;
+
+ /*
+ * After NVM upgrade adding root switch device fails because we
+ * initiated reset. During that time ICM might still send device
+ * connected message which we ignore here.
+ */
+ if (!tb->root_switch)
+ return;
+
+ route = get_route(pkg->route_hi, pkg->route_lo);
+ authorized = pkg->link_info & ICM_LINK_INFO_APPROVED;
+ security_level = (pkg->hdr.flags & ICM_FLAGS_SLEVEL_MASK) >>
+ ICM_FLAGS_SLEVEL_SHIFT;
+ boot = pkg->link_info & ICM_LINK_INFO_BOOT;
+
+ if (pkg->link_info & ICM_LINK_INFO_REJECTED) {
+ tb_info(tb, "switch at %llx was rejected by ICM firmware because topology limit exceeded\n",
+ route);
+ return;
+ }
+
+ sw = tb_switch_find_by_uuid(tb, &pkg->ep_uuid);
+ if (sw) {
+ /* Update the switch if it is still in the same place */
+ if (tb_route(sw) == route && !!sw->authorized == authorized) {
+ parent_sw = tb_to_switch(sw->dev.parent);
+ update_switch(parent_sw, sw, route, pkg->connection_id,
+ 0, 0, 0, boot);
+ tb_switch_put(sw);
+ return;
+ }
+
+ remove_switch(sw);
+ tb_switch_put(sw);
+ }
+
+ /* Another switch with the same address */
+ sw = tb_switch_find_by_route(tb, route);
+ if (sw) {
+ remove_switch(sw);
+ tb_switch_put(sw);
+ }
+
+ /* XDomain connection with the same address */
+ xd = tb_xdomain_find_by_route(tb, route);
+ if (xd) {
+ remove_xdomain(xd);
+ tb_xdomain_put(xd);
+ }
+
+ parent_sw = tb_switch_find_by_route(tb, get_parent_route(route));
+ if (!parent_sw) {
+ tb_err(tb, "failed to find parent switch for %llx\n", route);
+ return;
+ }
+
+ add_switch(parent_sw, route, &pkg->ep_uuid, pkg->connection_id,
+ 0, 0, 0, security_level, authorized, boot);
+
+ tb_switch_put(parent_sw);
+}
+
+static void
+icm_tr_device_disconnected(struct tb *tb, const struct icm_pkg_header *hdr)
+{
+ const struct icm_tr_event_device_disconnected *pkg =
+ (const struct icm_tr_event_device_disconnected *)hdr;
+ struct tb_switch *sw;
+ u64 route;
+
+ route = get_route(pkg->route_hi, pkg->route_lo);
+
+ sw = tb_switch_find_by_route(tb, route);
+ if (!sw) {
+ tb_warn(tb, "no switch exists at %llx, ignoring\n", route);
+ return;
+ }
+
+ remove_switch(sw);
+ tb_switch_put(sw);
+}
+
+static void
+icm_tr_xdomain_connected(struct tb *tb, const struct icm_pkg_header *hdr)
+{
+ const struct icm_tr_event_xdomain_connected *pkg =
+ (const struct icm_tr_event_xdomain_connected *)hdr;
+ struct tb_xdomain *xd;
+ struct tb_switch *sw;
+ u64 route;
+
+ if (!tb->root_switch)
+ return;
+
+ route = get_route(pkg->local_route_hi, pkg->local_route_lo);
+
+ xd = tb_xdomain_find_by_uuid(tb, &pkg->remote_uuid);
+ if (xd) {
+ if (xd->route == route) {
+ update_xdomain(xd, route, 0);
+ tb_xdomain_put(xd);
+ return;
+ }
+
+ remove_xdomain(xd);
+ tb_xdomain_put(xd);
+ }
+
+ /* An existing xdomain with the same address */
+ xd = tb_xdomain_find_by_route(tb, route);
+ if (xd) {
+ remove_xdomain(xd);
+ tb_xdomain_put(xd);
+ }
+
+ /*
+ * If the user disconnected a switch during suspend and
+ * connected another host to the same port, remove the switch
+ * first.
+ */
+ sw = get_switch_at_route(tb->root_switch, route);
+ if (sw)
+ remove_switch(sw);
+
+ sw = tb_switch_find_by_route(tb, get_parent_route(route));
+ if (!sw) {
+ tb_warn(tb, "no switch exists at %llx, ignoring\n", route);
+ return;
+ }
+
+ add_xdomain(sw, route, &pkg->local_uuid, &pkg->remote_uuid, 0, 0);
+ tb_switch_put(sw);
+}
+
+static void
+icm_tr_xdomain_disconnected(struct tb *tb, const struct icm_pkg_header *hdr)
+{
+ const struct icm_tr_event_xdomain_disconnected *pkg =
+ (const struct icm_tr_event_xdomain_disconnected *)hdr;
+ struct tb_xdomain *xd;
+ u64 route;
+
+ route = get_route(pkg->route_hi, pkg->route_lo);
+
+ xd = tb_xdomain_find_by_route(tb, route);
+ if (xd) {
+ remove_xdomain(xd);
+ tb_xdomain_put(xd);
+ }
+}
+
static struct pci_dev *get_upstream_port(struct pci_dev *pdev)
{
struct pci_dev *parent;
@@ -728,14 +1164,14 @@ static bool icm_ar_is_supported(struct tb *tb)
static int icm_ar_get_mode(struct tb *tb)
{
struct tb_nhi *nhi = tb->nhi;
- int retries = 5;
+ int retries = 60;
u32 val;
do {
val = ioread32(nhi->iobase + REG_FW_STS);
if (val & REG_FW_STS_NVM_AUTH_DONE)
break;
- msleep(30);
+ msleep(50);
} while (--retries);
if (!retries) {
@@ -746,6 +1182,30 @@ static int icm_ar_get_mode(struct tb *tb)
return nhi_mailbox_mode(nhi);
}
+static int
+icm_ar_driver_ready(struct tb *tb, enum tb_security_level *security_level,
+ size_t *nboot_acl)
+{
+ struct icm_ar_pkg_driver_ready_response reply;
+ struct icm_pkg_driver_ready request = {
+ .hdr.code = ICM_DRIVER_READY,
+ };
+ int ret;
+
+ memset(&reply, 0, sizeof(reply));
+ ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
+ 1, ICM_TIMEOUT);
+ if (ret)
+ return ret;
+
+ if (security_level)
+ *security_level = reply.info & ICM_AR_INFO_SLEVEL_MASK;
+ if (nboot_acl && (reply.info & ICM_AR_INFO_BOOT_ACL_SUPPORTED))
+ *nboot_acl = (reply.info & ICM_AR_INFO_BOOT_ACL_MASK) >>
+ ICM_AR_INFO_BOOT_ACL_SHIFT;
+ return 0;
+}
+
static int icm_ar_get_route(struct tb *tb, u8 link, u8 depth, u64 *route)
{
struct icm_ar_pkg_get_route_response reply;
@@ -768,6 +1228,87 @@ static int icm_ar_get_route(struct tb *tb, u8 link, u8 depth, u64 *route)
return 0;
}
+static int icm_ar_get_boot_acl(struct tb *tb, uuid_t *uuids, size_t nuuids)
+{
+ struct icm_ar_pkg_preboot_acl_response reply;
+ struct icm_ar_pkg_preboot_acl request = {
+ .hdr = { .code = ICM_PREBOOT_ACL },
+ };
+ int ret, i;
+
+ memset(&reply, 0, sizeof(reply));
+ ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
+ 1, ICM_TIMEOUT);
+ if (ret)
+ return ret;
+
+ if (reply.hdr.flags & ICM_FLAGS_ERROR)
+ return -EIO;
+
+ for (i = 0; i < nuuids; i++) {
+ u32 *uuid = (u32 *)&uuids[i];
+
+ uuid[0] = reply.acl[i].uuid_lo;
+ uuid[1] = reply.acl[i].uuid_hi;
+
+ if (uuid[0] == 0xffffffff && uuid[1] == 0xffffffff) {
+ /* Map empty entries to null UUID */
+ uuid[0] = 0;
+ uuid[1] = 0;
+ } else {
+ /* Upper two DWs are always one's */
+ uuid[2] = 0xffffffff;
+ uuid[3] = 0xffffffff;
+ }
+ }
+
+ return ret;
+}
+
+static int icm_ar_set_boot_acl(struct tb *tb, const uuid_t *uuids,
+ size_t nuuids)
+{
+ struct icm_ar_pkg_preboot_acl_response reply;
+ struct icm_ar_pkg_preboot_acl request = {
+ .hdr = {
+ .code = ICM_PREBOOT_ACL,
+ .flags = ICM_FLAGS_WRITE,
+ },
+ };
+ int ret, i;
+
+ for (i = 0; i < nuuids; i++) {
+ const u32 *uuid = (const u32 *)&uuids[i];
+
+ if (uuid_is_null(&uuids[i])) {
+ /*
+ * Map null UUID to the empty (all one) entries
+ * for ICM.
+ */
+ request.acl[i].uuid_lo = 0xffffffff;
+ request.acl[i].uuid_hi = 0xffffffff;
+ } else {
+ /* Two high DWs need to be set to all one */
+ if (uuid[2] != 0xffffffff || uuid[3] != 0xffffffff)
+ return -EINVAL;
+
+ request.acl[i].uuid_lo = uuid[0];
+ request.acl[i].uuid_hi = uuid[1];
+ }
+ }
+
+ memset(&reply, 0, sizeof(reply));
+ ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
+ 1, ICM_TIMEOUT);
+ if (ret)
+ return ret;
+
+ if (reply.hdr.flags & ICM_FLAGS_ERROR)
+ return -EIO;
+
+ return 0;
+}
+
static void icm_handle_notification(struct work_struct *work)
{
struct icm_notification *n = container_of(work, typeof(*n), work);
@@ -814,23 +1355,18 @@ static void icm_handle_event(struct tb *tb, enum tb_cfg_pkg_type type,
}
static int
-__icm_driver_ready(struct tb *tb, enum tb_security_level *security_level)
+__icm_driver_ready(struct tb *tb, enum tb_security_level *security_level,
+ size_t *nboot_acl)
{
- struct icm_pkg_driver_ready_response reply;
- struct icm_pkg_driver_ready request = {
- .hdr.code = ICM_DRIVER_READY,
- };
- unsigned int retries = 10;
+ struct icm *icm = tb_priv(tb);
+ unsigned int retries = 50;
int ret;
- memset(&reply, 0, sizeof(reply));
- ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
- 1, ICM_TIMEOUT);
- if (ret)
+ ret = icm->driver_ready(tb, security_level, nboot_acl);
+ if (ret) {
+ tb_err(tb, "failed to send driver ready to ICM\n");
return ret;
-
- if (security_level)
- *security_level = reply.security_level & 0xf;
+ }
/*
* Hold on here until the switch config space is accessible so
@@ -848,6 +1384,7 @@ __icm_driver_ready(struct tb *tb, enum tb_security_level *security_level)
msleep(50);
} while (--retries);
+ tb_err(tb, "failed to read root switch config space, giving up\n");
return -ETIMEDOUT;
}
@@ -915,6 +1452,9 @@ static int icm_firmware_reset(struct tb *tb, struct tb_nhi *nhi)
struct icm *icm = tb_priv(tb);
u32 val;
+ if (!icm->upstream_port)
+ return -ENODEV;
+
/* Put ARC to wait for CIO reset event to happen */
val = ioread32(nhi->iobase + REG_FW_STS);
val |= REG_FW_STS_CIO_RESET_REQ;
@@ -1054,6 +1594,9 @@ static int icm_firmware_init(struct tb *tb)
break;
default:
+ if (ret < 0)
+ return ret;
+
tb_err(tb, "ICM firmware is in wrong mode: %u\n", ret);
return -ENODEV;
}
@@ -1089,7 +1632,18 @@ static int icm_driver_ready(struct tb *tb)
return 0;
}
- return __icm_driver_ready(tb, &tb->security_level);
+ ret = __icm_driver_ready(tb, &tb->security_level, &tb->nboot_acl);
+ if (ret)
+ return ret;
+
+ /*
+ * Make sure the number of supported preboot ACL matches what we
+ * expect or disable the whole feature.
+ */
+ if (tb->nboot_acl > icm->max_boot_acl)
+ tb->nboot_acl = 0;
+
+ return 0;
}
static int icm_suspend(struct tb *tb)
@@ -1185,7 +1739,7 @@ static void icm_complete(struct tb *tb)
* Now all existing children should be resumed, start events
* from ICM to get updated status.
*/
- __icm_driver_ready(tb, NULL);
+ __icm_driver_ready(tb, NULL, NULL);
/*
* We do not get notifications of devices that have been
@@ -1238,7 +1792,7 @@ static int icm_disconnect_pcie_paths(struct tb *tb)
return nhi_mailbox_cmd(tb->nhi, NHI_MAILBOX_DISCONNECT_PCIE_PATHS, 0);
}
-/* Falcon Ridge and Alpine Ridge */
+/* Falcon Ridge */
static const struct tb_cm_ops icm_fr_ops = {
.driver_ready = icm_driver_ready,
.start = icm_start,
@@ -1254,6 +1808,42 @@ static const struct tb_cm_ops icm_fr_ops = {
.disconnect_xdomain_paths = icm_fr_disconnect_xdomain_paths,
};
+/* Alpine Ridge */
+static const struct tb_cm_ops icm_ar_ops = {
+ .driver_ready = icm_driver_ready,
+ .start = icm_start,
+ .stop = icm_stop,
+ .suspend = icm_suspend,
+ .complete = icm_complete,
+ .handle_event = icm_handle_event,
+ .get_boot_acl = icm_ar_get_boot_acl,
+ .set_boot_acl = icm_ar_set_boot_acl,
+ .approve_switch = icm_fr_approve_switch,
+ .add_switch_key = icm_fr_add_switch_key,
+ .challenge_switch_key = icm_fr_challenge_switch_key,
+ .disconnect_pcie_paths = icm_disconnect_pcie_paths,
+ .approve_xdomain_paths = icm_fr_approve_xdomain_paths,
+ .disconnect_xdomain_paths = icm_fr_disconnect_xdomain_paths,
+};
+
+/* Titan Ridge */
+static const struct tb_cm_ops icm_tr_ops = {
+ .driver_ready = icm_driver_ready,
+ .start = icm_start,
+ .stop = icm_stop,
+ .suspend = icm_suspend,
+ .complete = icm_complete,
+ .handle_event = icm_handle_event,
+ .get_boot_acl = icm_ar_get_boot_acl,
+ .set_boot_acl = icm_ar_set_boot_acl,
+ .approve_switch = icm_tr_approve_switch,
+ .add_switch_key = icm_tr_add_switch_key,
+ .challenge_switch_key = icm_tr_challenge_switch_key,
+ .disconnect_pcie_paths = icm_disconnect_pcie_paths,
+ .approve_xdomain_paths = icm_tr_approve_xdomain_paths,
+ .disconnect_xdomain_paths = icm_tr_disconnect_xdomain_paths,
+};
+
struct tb *icm_probe(struct tb_nhi *nhi)
{
struct icm *icm;
@@ -1272,6 +1862,7 @@ struct tb *icm_probe(struct tb_nhi *nhi)
case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_NHI:
icm->is_supported = icm_fr_is_supported;
icm->get_route = icm_fr_get_route;
+ icm->driver_ready = icm_fr_driver_ready;
icm->device_connected = icm_fr_device_connected;
icm->device_disconnected = icm_fr_device_disconnected;
icm->xdomain_connected = icm_fr_xdomain_connected;
@@ -1284,14 +1875,29 @@ struct tb *icm_probe(struct tb_nhi *nhi)
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_LP_NHI:
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_NHI:
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_NHI:
+ icm->max_boot_acl = ICM_AR_PREBOOT_ACL_ENTRIES;
icm->is_supported = icm_ar_is_supported;
icm->get_mode = icm_ar_get_mode;
icm->get_route = icm_ar_get_route;
+ icm->driver_ready = icm_ar_driver_ready;
icm->device_connected = icm_fr_device_connected;
icm->device_disconnected = icm_fr_device_disconnected;
icm->xdomain_connected = icm_fr_xdomain_connected;
icm->xdomain_disconnected = icm_fr_xdomain_disconnected;
- tb->cm_ops = &icm_fr_ops;
+ tb->cm_ops = &icm_ar_ops;
+ break;
+
+ case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_NHI:
+ case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_NHI:
+ icm->max_boot_acl = ICM_AR_PREBOOT_ACL_ENTRIES;
+ icm->is_supported = icm_ar_is_supported;
+ icm->get_mode = icm_ar_get_mode;
+ icm->driver_ready = icm_tr_driver_ready;
+ icm->device_connected = icm_tr_device_connected;
+ icm->device_disconnected = icm_tr_device_disconnected;
+ icm->xdomain_connected = icm_tr_xdomain_connected;
+ icm->xdomain_disconnected = icm_tr_xdomain_disconnected;
+ tb->cm_ops = &icm_tr_ops;
break;
}
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index f45bcbc63738..f5a33e88e676 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -1036,7 +1036,7 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
*/
tb_domain_put(tb);
nhi_shutdown(nhi);
- return -EIO;
+ return res;
}
pci_set_drvdata(pdev, tb);
@@ -1064,6 +1064,7 @@ static const struct dev_pm_ops nhi_pm_ops = {
* we just disable hotplug, the
* pci-tunnels stay alive.
*/
+ .thaw_noirq = nhi_resume_noirq,
.restore_noirq = nhi_resume_noirq,
.suspend = nhi_suspend,
.freeze = nhi_suspend,
@@ -1110,6 +1111,8 @@ static struct pci_device_id nhi_ids[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_NHI) },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_NHI) },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_USBONLY_NHI) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_NHI) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_NHI) },
{ 0,}
};
diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h
index 4476ab4cfd0c..1696a4560948 100644
--- a/drivers/thunderbolt/nhi.h
+++ b/drivers/thunderbolt/nhi.h
@@ -45,5 +45,10 @@ enum nhi_fw_mode nhi_mailbox_mode(struct tb_nhi *nhi);
#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_LP_USBONLY_NHI 0x15dc
#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_USBONLY_NHI 0x15dd
#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_USBONLY_NHI 0x15de
+#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_BRIDGE 0x15e7
+#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_NHI 0x15e8
+#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_BRIDGE 0x15ea
+#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_NHI 0x15eb
+#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_BRIDGE 0x15ef
#endif
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index da54ace4dd2f..25758671ddf4 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -716,6 +716,13 @@ static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val)
if (sw->authorized)
goto unlock;
+ /*
+ * Make sure there is no PCIe rescan ongoing when a new PCIe
+ * tunnel is created. Otherwise the PCIe rescan code might find
+ * the new tunnel too early.
+ */
+ pci_lock_rescan_remove();
+
switch (val) {
/* Approve switch */
case 1:
@@ -735,6 +742,8 @@ static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val)
break;
}
+ pci_unlock_rescan_remove();
+
if (!ret) {
sw->authorized = val;
/* Notify status change to the userspace */
@@ -766,6 +775,15 @@ static ssize_t authorized_store(struct device *dev,
}
static DEVICE_ATTR_RW(authorized);
+static ssize_t boot_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct tb_switch *sw = tb_to_switch(dev);
+
+ return sprintf(buf, "%u\n", sw->boot);
+}
+static DEVICE_ATTR_RO(boot);
+
static ssize_t device_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -942,6 +960,7 @@ static DEVICE_ATTR_RO(unique_id);
static struct attribute *switch_attrs[] = {
&dev_attr_authorized.attr,
+ &dev_attr_boot.attr,
&dev_attr_device.attr,
&dev_attr_device_name.attr,
&dev_attr_key.attr,
@@ -970,6 +989,10 @@ static umode_t switch_attr_is_visible(struct kobject *kobj,
if (sw->dma_port)
return attr->mode;
return 0;
+ } else if (attr == &dev_attr_boot.attr) {
+ if (tb_route(sw))
+ return attr->mode;
+ return 0;
}
return sw->safe_mode ? 0 : attr->mode;
@@ -1028,6 +1051,9 @@ static int tb_switch_get_generation(struct tb_switch *sw)
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_BRIDGE:
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_BRIDGE:
case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_BRIDGE:
+ case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_BRIDGE:
+ case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_BRIDGE:
+ case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_BRIDGE:
return 3;
default:
@@ -1470,6 +1496,7 @@ struct tb_sw_lookup {
u8 link;
u8 depth;
const uuid_t *uuid;
+ u64 route;
};
static int tb_switch_match(struct device *dev, void *data)
@@ -1485,6 +1512,11 @@ static int tb_switch_match(struct device *dev, void *data)
if (lookup->uuid)
return !memcmp(sw->uuid, lookup->uuid, sizeof(*lookup->uuid));
+ if (lookup->route) {
+ return sw->config.route_lo == lower_32_bits(lookup->route) &&
+ sw->config.route_hi == upper_32_bits(lookup->route);
+ }
+
/* Root switch is matched only by depth */
if (!lookup->depth)
return !sw->depth;
@@ -1519,7 +1551,7 @@ struct tb_switch *tb_switch_find_by_link_depth(struct tb *tb, u8 link, u8 depth)
}
/**
- * tb_switch_find_by_link_depth() - Find switch by UUID
+ * tb_switch_find_by_uuid() - Find switch by UUID
* @tb: Domain the switch belongs
* @uuid: UUID to look for
*
@@ -1542,6 +1574,33 @@ struct tb_switch *tb_switch_find_by_uuid(struct tb *tb, const uuid_t *uuid)
return NULL;
}
+/**
+ * tb_switch_find_by_route() - Find switch by route string
+ * @tb: Domain the switch belongs
+ * @route: Route string to look for
+ *
+ * Returned switch has reference count increased so the caller needs to
+ * call tb_switch_put() when done with the switch.
+ */
+struct tb_switch *tb_switch_find_by_route(struct tb *tb, u64 route)
+{
+ struct tb_sw_lookup lookup;
+ struct device *dev;
+
+ if (!route)
+ return tb_switch_get(tb->root_switch);
+
+ memset(&lookup, 0, sizeof(lookup));
+ lookup.tb = tb;
+ lookup.route = route;
+
+ dev = bus_find_device(&tb_bus_type, NULL, &lookup, tb_switch_match);
+ if (dev)
+ return tb_to_switch(dev);
+
+ return NULL;
+}
+
void tb_switch_exit(void)
{
ida_destroy(&nvm_ida);
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 895c57a0a090..9d9f0ca16bfb 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -66,6 +66,7 @@ struct tb_switch_nvm {
* @nvm: Pointer to the NVM if the switch has one (%NULL otherwise)
* @no_nvm_upgrade: Prevent NVM upgrade of this switch
* @safe_mode: The switch is in safe-mode
+ * @boot: Whether the switch was already authorized on boot or not
* @authorized: Whether the switch is authorized by user or policy
* @work: Work used to automatically authorize a switch
* @security_level: Switch supported security level
@@ -99,6 +100,7 @@ struct tb_switch {
struct tb_switch_nvm *nvm;
bool no_nvm_upgrade;
bool safe_mode;
+ bool boot;
unsigned int authorized;
struct work_struct work;
enum tb_security_level security_level;
@@ -198,6 +200,8 @@ struct tb_path {
* @suspend: Connection manager specific suspend
* @complete: Connection manager specific complete
* @handle_event: Handle thunderbolt event
+ * @get_boot_acl: Get boot ACL list
+ * @set_boot_acl: Set boot ACL list
* @approve_switch: Approve switch
* @add_switch_key: Add key to switch
* @challenge_switch_key: Challenge switch using key
@@ -215,6 +219,8 @@ struct tb_cm_ops {
void (*complete)(struct tb *tb);
void (*handle_event)(struct tb *tb, enum tb_cfg_pkg_type,
const void *buf, size_t size);
+ int (*get_boot_acl)(struct tb *tb, uuid_t *uuids, size_t nuuids);
+ int (*set_boot_acl)(struct tb *tb, const uuid_t *uuids, size_t nuuids);
int (*approve_switch)(struct tb *tb, struct tb_switch *sw);
int (*add_switch_key)(struct tb *tb, struct tb_switch *sw);
int (*challenge_switch_key)(struct tb *tb, struct tb_switch *sw,
@@ -386,6 +392,14 @@ struct tb_switch *get_switch_at_route(struct tb_switch *sw, u64 route);
struct tb_switch *tb_switch_find_by_link_depth(struct tb *tb, u8 link,
u8 depth);
struct tb_switch *tb_switch_find_by_uuid(struct tb *tb, const uuid_t *uuid);
+struct tb_switch *tb_switch_find_by_route(struct tb *tb, u64 route);
+
+static inline struct tb_switch *tb_switch_get(struct tb_switch *sw)
+{
+ if (sw)
+ get_device(&sw->dev);
+ return sw;
+}
static inline void tb_switch_put(struct tb_switch *sw)
{
diff --git a/drivers/thunderbolt/tb_msgs.h b/drivers/thunderbolt/tb_msgs.h
index b0a092baa605..bc13f8d6b804 100644
--- a/drivers/thunderbolt/tb_msgs.h
+++ b/drivers/thunderbolt/tb_msgs.h
@@ -102,6 +102,8 @@ enum icm_pkg_code {
ICM_ADD_DEVICE_KEY = 0x6,
ICM_GET_ROUTE = 0xa,
ICM_APPROVE_XDOMAIN = 0x10,
+ ICM_DISCONNECT_XDOMAIN = 0x11,
+ ICM_PREBOOT_ACL = 0x18,
};
enum icm_event_code {
@@ -122,18 +124,23 @@ struct icm_pkg_header {
#define ICM_FLAGS_NO_KEY BIT(1)
#define ICM_FLAGS_SLEVEL_SHIFT 3
#define ICM_FLAGS_SLEVEL_MASK GENMASK(4, 3)
+#define ICM_FLAGS_WRITE BIT(7)
struct icm_pkg_driver_ready {
struct icm_pkg_header hdr;
};
-struct icm_pkg_driver_ready_response {
+/* Falcon Ridge only messages */
+
+struct icm_fr_pkg_driver_ready_response {
struct icm_pkg_header hdr;
u8 romver;
u8 ramver;
u16 security_level;
};
+#define ICM_FR_SLEVEL_MASK 0xf
+
/* Falcon Ridge & Alpine Ridge common messages */
struct icm_fr_pkg_get_topology {
@@ -176,6 +183,8 @@ struct icm_fr_event_device_connected {
#define ICM_LINK_INFO_DEPTH_SHIFT 4
#define ICM_LINK_INFO_DEPTH_MASK GENMASK(7, 4)
#define ICM_LINK_INFO_APPROVED BIT(8)
+#define ICM_LINK_INFO_REJECTED BIT(9)
+#define ICM_LINK_INFO_BOOT BIT(10)
struct icm_fr_pkg_approve_device {
struct icm_pkg_header hdr;
@@ -270,6 +279,18 @@ struct icm_fr_pkg_approve_xdomain_response {
/* Alpine Ridge only messages */
+struct icm_ar_pkg_driver_ready_response {
+ struct icm_pkg_header hdr;
+ u8 romver;
+ u8 ramver;
+ u16 info;
+};
+
+#define ICM_AR_INFO_SLEVEL_MASK GENMASK(3, 0)
+#define ICM_AR_INFO_BOOT_ACL_SHIFT 7
+#define ICM_AR_INFO_BOOT_ACL_MASK GENMASK(11, 7)
+#define ICM_AR_INFO_BOOT_ACL_SUPPORTED BIT(13)
+
struct icm_ar_pkg_get_route {
struct icm_pkg_header hdr;
u16 reserved;
@@ -284,6 +305,163 @@ struct icm_ar_pkg_get_route_response {
u32 route_lo;
};
+struct icm_ar_boot_acl_entry {
+ u32 uuid_lo;
+ u32 uuid_hi;
+};
+
+#define ICM_AR_PREBOOT_ACL_ENTRIES 16
+
+struct icm_ar_pkg_preboot_acl {
+ struct icm_pkg_header hdr;
+ struct icm_ar_boot_acl_entry acl[ICM_AR_PREBOOT_ACL_ENTRIES];
+};
+
+struct icm_ar_pkg_preboot_acl_response {
+ struct icm_pkg_header hdr;
+ struct icm_ar_boot_acl_entry acl[ICM_AR_PREBOOT_ACL_ENTRIES];
+};
+
+/* Titan Ridge messages */
+
+struct icm_tr_pkg_driver_ready_response {
+ struct icm_pkg_header hdr;
+ u16 reserved1;
+ u16 info;
+ u32 nvm_version;
+ u16 device_id;
+ u16 reserved2;
+};
+
+#define ICM_TR_INFO_SLEVEL_MASK GENMASK(2, 0)
+#define ICM_TR_INFO_BOOT_ACL_SHIFT 7
+#define ICM_TR_INFO_BOOT_ACL_MASK GENMASK(12, 7)
+
+struct icm_tr_event_device_connected {
+ struct icm_pkg_header hdr;
+ uuid_t ep_uuid;
+ u32 route_hi;
+ u32 route_lo;
+ u8 connection_id;
+ u8 reserved;
+ u16 link_info;
+ u32 ep_name[55];
+};
+
+struct icm_tr_event_device_disconnected {
+ struct icm_pkg_header hdr;
+ u32 route_hi;
+ u32 route_lo;
+};
+
+struct icm_tr_event_xdomain_connected {
+ struct icm_pkg_header hdr;
+ u16 reserved;
+ u16 link_info;
+ uuid_t remote_uuid;
+ uuid_t local_uuid;
+ u32 local_route_hi;
+ u32 local_route_lo;
+ u32 remote_route_hi;
+ u32 remote_route_lo;
+};
+
+struct icm_tr_event_xdomain_disconnected {
+ struct icm_pkg_header hdr;
+ u32 route_hi;
+ u32 route_lo;
+ uuid_t remote_uuid;
+};
+
+struct icm_tr_pkg_approve_device {
+ struct icm_pkg_header hdr;
+ uuid_t ep_uuid;
+ u32 route_hi;
+ u32 route_lo;
+ u8 connection_id;
+ u8 reserved1[3];
+};
+
+struct icm_tr_pkg_add_device_key {
+ struct icm_pkg_header hdr;
+ uuid_t ep_uuid;
+ u32 route_hi;
+ u32 route_lo;
+ u8 connection_id;
+ u8 reserved[3];
+ u32 key[8];
+};
+
+struct icm_tr_pkg_challenge_device {
+ struct icm_pkg_header hdr;
+ uuid_t ep_uuid;
+ u32 route_hi;
+ u32 route_lo;
+ u8 connection_id;
+ u8 reserved[3];
+ u32 challenge[8];
+};
+
+struct icm_tr_pkg_approve_xdomain {
+ struct icm_pkg_header hdr;
+ u32 route_hi;
+ u32 route_lo;
+ uuid_t remote_uuid;
+ u16 transmit_path;
+ u16 transmit_ring;
+ u16 receive_path;
+ u16 receive_ring;
+};
+
+struct icm_tr_pkg_disconnect_xdomain {
+ struct icm_pkg_header hdr;
+ u8 stage;
+ u8 reserved[3];
+ u32 route_hi;
+ u32 route_lo;
+ uuid_t remote_uuid;
+};
+
+struct icm_tr_pkg_challenge_device_response {
+ struct icm_pkg_header hdr;
+ uuid_t ep_uuid;
+ u32 route_hi;
+ u32 route_lo;
+ u8 connection_id;
+ u8 reserved[3];
+ u32 challenge[8];
+ u32 response[8];
+};
+
+struct icm_tr_pkg_add_device_key_response {
+ struct icm_pkg_header hdr;
+ uuid_t ep_uuid;
+ u32 route_hi;
+ u32 route_lo;
+ u8 connection_id;
+ u8 reserved[3];
+};
+
+struct icm_tr_pkg_approve_xdomain_response {
+ struct icm_pkg_header hdr;
+ u32 route_hi;
+ u32 route_lo;
+ uuid_t remote_uuid;
+ u16 transmit_path;
+ u16 transmit_ring;
+ u16 receive_path;
+ u16 receive_ring;
+};
+
+struct icm_tr_pkg_disconnect_xdomain_response {
+ struct icm_pkg_header hdr;
+ u8 stage;
+ u8 reserved[3];
+ u32 route_hi;
+ u32 route_lo;
+ uuid_t remote_uuid;
+};
+
/* XDomain messages */
struct tb_xdomain_header {
diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c
index f25d88d4552b..8abb4e843085 100644
--- a/drivers/thunderbolt/xdomain.c
+++ b/drivers/thunderbolt/xdomain.c
@@ -1255,6 +1255,7 @@ struct tb_xdomain_lookup {
const uuid_t *uuid;
u8 link;
u8 depth;
+ u64 route;
};
static struct tb_xdomain *switch_find_xdomain(struct tb_switch *sw,
@@ -1275,9 +1276,13 @@ static struct tb_xdomain *switch_find_xdomain(struct tb_switch *sw,
if (lookup->uuid) {
if (uuid_equal(xd->remote_uuid, lookup->uuid))
return xd;
- } else if (lookup->link == xd->link &&
+ } else if (lookup->link &&
+ lookup->link == xd->link &&
lookup->depth == xd->depth) {
return xd;
+ } else if (lookup->route &&
+ lookup->route == xd->route) {
+ return xd;
}
} else if (port->remote) {
xd = switch_find_xdomain(port->remote->sw, lookup);
@@ -1313,12 +1318,7 @@ struct tb_xdomain *tb_xdomain_find_by_uuid(struct tb *tb, const uuid_t *uuid)
lookup.uuid = uuid;
xd = switch_find_xdomain(tb->root_switch, &lookup);
- if (xd) {
- get_device(&xd->dev);
- return xd;
- }
-
- return NULL;
+ return tb_xdomain_get(xd);
}
EXPORT_SYMBOL_GPL(tb_xdomain_find_by_uuid);
@@ -1349,13 +1349,36 @@ struct tb_xdomain *tb_xdomain_find_by_link_depth(struct tb *tb, u8 link,
lookup.depth = depth;
xd = switch_find_xdomain(tb->root_switch, &lookup);
- if (xd) {
- get_device(&xd->dev);
- return xd;
- }
+ return tb_xdomain_get(xd);
+}
- return NULL;
+/**
+ * tb_xdomain_find_by_route() - Find an XDomain by route string
+ * @tb: Domain where the XDomain belongs to
+ * @route: XDomain route string
+ *
+ * Finds XDomain by walking through the Thunderbolt topology below @tb.
+ * The returned XDomain will have its reference count increased so the
+ * caller needs to call tb_xdomain_put() when it is done with the
+ * object.
+ *
+ * This will find all XDomains including the ones that are not yet added
+ * to the bus (handshake is still in progress).
+ *
+ * The caller needs to hold @tb->lock.
+ */
+struct tb_xdomain *tb_xdomain_find_by_route(struct tb *tb, u64 route)
+{
+ struct tb_xdomain_lookup lookup;
+ struct tb_xdomain *xd;
+
+ memset(&lookup, 0, sizeof(lookup));
+ lookup.route = route;
+
+ xd = switch_find_xdomain(tb->root_switch, &lookup);
+ return tb_xdomain_get(xd);
}
+EXPORT_SYMBOL_GPL(tb_xdomain_find_by_route);
bool tb_xdomain_handle_request(struct tb *tb, enum tb_cfg_pkg_type type,
const void *buf, size_t size)
diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig
index 3bade5ad3d71..4293c172e120 100644
--- a/drivers/tty/hvc/Kconfig
+++ b/drivers/tty/hvc/Kconfig
@@ -88,6 +88,16 @@ config HVC_DCC
driver. This console is used through a JTAG only on ARM. If you don't have
a JTAG then you probably don't want this option.
+config HVC_RISCV_SBI
+ bool "RISC-V SBI console support"
+ depends on RISCV
+ select HVC_DRIVER
+ help
+ This enables support for console output via RISC-V SBI calls, which
+ is normally used only during boot to output printk.
+
+ If you don't know what do to here, say Y.
+
config HVCS
tristate "IBM Hypervisor Virtual Console Server support"
depends on PPC_PSERIES && HVC_CONSOLE
diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile
index 7da1934d34e8..98880e357941 100644
--- a/drivers/tty/hvc/Makefile
+++ b/drivers/tty/hvc/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_HVC_IRQ) += hvc_irq.o
obj-$(CONFIG_HVC_XEN) += hvc_xen.o
obj-$(CONFIG_HVC_IUCV) += hvc_iucv.o
obj-$(CONFIG_HVC_UDBG) += hvc_udbg.o
+obj-$(CONFIG_HVC_RISCV_SBI) += hvc_riscv_sbi.o
obj-$(CONFIG_HVCS) += hvcs.o
diff --git a/drivers/tty/hvc/hvc_riscv_sbi.c b/drivers/tty/hvc/hvc_riscv_sbi.c
new file mode 100644
index 000000000000..75155bde2b88
--- /dev/null
+++ b/drivers/tty/hvc/hvc_riscv_sbi.c
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2008 David Gibson, IBM Corporation
+ * Copyright (C) 2012 Regents of the University of California
+ * Copyright (C) 2017 SiFive
+ */
+
+#include <linux/console.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+
+#include <asm/sbi.h>
+
+#include "hvc_console.h"
+
+static int hvc_sbi_tty_put(uint32_t vtermno, const char *buf, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ sbi_console_putchar(buf[i]);
+
+ return i;
+}
+
+static int hvc_sbi_tty_get(uint32_t vtermno, char *buf, int count)
+{
+ int i, c;
+
+ for (i = 0; i < count; i++) {
+ c = sbi_console_getchar();
+ if (c < 0)
+ break;
+ buf[i] = c;
+ }
+
+ return i;
+}
+
+static const struct hv_ops hvc_sbi_ops = {
+ .get_chars = hvc_sbi_tty_get,
+ .put_chars = hvc_sbi_tty_put,
+};
+
+static int __init hvc_sbi_init(void)
+{
+ return PTR_ERR_OR_ZERO(hvc_alloc(0, 0, &hvc_sbi_ops, 16));
+}
+device_initcall(hvc_sbi_init);
+
+static int __init hvc_sbi_console_init(void)
+{
+ hvc_instantiate(0, 0, &hvc_sbi_ops);
+ add_preferred_console("hvc", 0, NULL);
+
+ return 0;
+}
+console_initcall(hvc_sbi_console_init);
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index f439c72b9e3c..df93b727e984 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -350,7 +350,7 @@ static struct bus_type serdev_bus_type = {
};
/**
- * serdev_controller_alloc() - Allocate a new serdev device
+ * serdev_device_alloc() - Allocate a new serdev device
* @ctrl: associated controller
*
* Caller is responsible for either calling serdev_device_add() to add the
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index cd1b94a0f451..6fcdb90f616a 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -9,6 +9,7 @@
* LCR is written whilst busy. If it is, then a busy detect interrupt is
* raised, the LCR needs to be rewritten and the uart status register read.
*/
+#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -119,10 +120,27 @@ static void dw8250_check_lcr(struct uart_port *p, int value)
*/
}
+/* Returns once the transmitter is empty or we run out of retries */
+static void dw8250_tx_wait_empty(struct uart_port *p, int tries)
+{
+ unsigned int lsr;
+
+ while (tries--) {
+ lsr = readb (p->membase + (UART_LSR << p->regshift));
+ if (lsr & UART_LSR_TEMT)
+ break;
+ udelay (10);
+ }
+}
+
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
+ /* Allow the TX to drain before we reconfigure */
+ if (offset == UART_LCR)
+ dw8250_tx_wait_empty(p, 1000);
+
writeb(value, p->membase + (offset << p->regshift));
if (offset == UART_LCR && !d->uart_16550_compatible)
@@ -339,17 +357,11 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
p->serial_in = dw8250_serial_in32be;
p->serial_out = dw8250_serial_out32be;
}
- } else if (has_acpi_companion(p->dev)) {
- const struct acpi_device_id *id;
-
- id = acpi_match_device(p->dev->driver->acpi_match_table,
- p->dev);
- if (id && !strcmp(id->id, "APMC0D08")) {
- p->iotype = UPIO_MEM32;
- p->regshift = 2;
- p->serial_in = dw8250_serial_in32;
- data->uart_16550_compatible = true;
- }
+ } else if (acpi_dev_present("APMC0D08", NULL, -1)) {
+ p->iotype = UPIO_MEM32;
+ p->regshift = 2;
+ p->serial_in = dw8250_serial_in32;
+ data->uart_16550_compatible = true;
}
/* Platforms with iDMA */
diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c
index 308977807994..127017cc41d9 100644
--- a/drivers/tty/serial/8250/8250_men_mcb.c
+++ b/drivers/tty/serial/8250/8250_men_mcb.c
@@ -1,12 +1,19 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <linux/mcb.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <uapi/linux/serial_core.h>
+#define MEN_UART_ID_Z025 0x19
+#define MEN_UART_ID_Z057 0x39
+#define MEN_UART_ID_Z125 0x7d
+
+#define MEN_UART_MEM_SIZE 0x10
+
struct serial_8250_men_mcb_data {
struct uart_8250_port uart;
int line;
@@ -18,7 +25,7 @@ struct serial_8250_men_mcb_data {
* parameter in order to really set the correct baudrate, and
* do so if possible without user interaction
*/
-static u32 men_z125_lookup_uartclk(struct mcb_device *mdev)
+static u32 men_lookup_uartclk(struct mcb_device *mdev)
{
/* use default value if board is not available below */
u32 clkval = 1041666;
@@ -28,10 +35,12 @@ static u32 men_z125_lookup_uartclk(struct mcb_device *mdev)
mdev->bus->name);
if (strncmp(mdev->bus->name, "F075", 4) == 0)
clkval = 1041666;
- else if (strncmp(mdev->bus->name, "F216", 4) == 0)
+ else if (strncmp(mdev->bus->name, "F216", 4) == 0)
clkval = 1843200;
else if (strncmp(mdev->bus->name, "G215", 4) == 0)
clkval = 1843200;
+ else if (strncmp(mdev->bus->name, "F210", 4) == 0)
+ clkval = 115200;
else
dev_info(&mdev->dev,
"board not detected, using default uartclk\n");
@@ -41,62 +50,108 @@ static u32 men_z125_lookup_uartclk(struct mcb_device *mdev)
return clkval;
}
+static unsigned int get_num_ports(struct mcb_device *mdev,
+ void __iomem *membase)
+{
+ switch (mdev->id) {
+ case MEN_UART_ID_Z125:
+ return 1U;
+ case MEN_UART_ID_Z025:
+ return readb(membase) >> 4;
+ case MEN_UART_ID_Z057:
+ return 4U;
+ default:
+ dev_err(&mdev->dev, "no supported device!\n");
+ return -ENODEV;
+ }
+}
+
static int serial_8250_men_mcb_probe(struct mcb_device *mdev,
const struct mcb_device_id *id)
{
struct serial_8250_men_mcb_data *data;
struct resource *mem;
-
- data = devm_kzalloc(&mdev->dev,
- sizeof(struct serial_8250_men_mcb_data),
- GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- mcb_set_drvdata(mdev, data);
- data->uart.port.dev = mdev->dma_dev;
- spin_lock_init(&data->uart.port.lock);
-
- data->uart.port.type = PORT_16550;
- data->uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
- data->uart.port.iotype = UPIO_MEM;
- data->uart.port.uartclk = men_z125_lookup_uartclk(mdev);
- data->uart.port.regshift = 0;
- data->uart.port.fifosize = 60;
+ unsigned int num_ports;
+ unsigned int i;
+ void __iomem *membase;
mem = mcb_get_resource(mdev, IORESOURCE_MEM);
if (mem == NULL)
return -ENXIO;
+ membase = devm_ioremap_resource(&mdev->dev, mem);
+ if (IS_ERR(membase))
+ return PTR_ERR_OR_ZERO(membase);
- data->uart.port.irq = mcb_get_irq(mdev);
+ num_ports = get_num_ports(mdev, membase);
- data->uart.port.membase = devm_ioremap_resource(&mdev->dev, mem);
- if (IS_ERR(data->uart.port.membase))
- return PTR_ERR_OR_ZERO(data->uart.port.membase);
+ dev_dbg(&mdev->dev, "found a 16z%03u with %u ports\n",
+ mdev->id, num_ports);
- data->uart.port.mapbase = (unsigned long) mem->start;
- data->uart.port.iobase = data->uart.port.mapbase;
+ if (num_ports == 0 || num_ports > 4) {
+ dev_err(&mdev->dev, "unexpected number of ports: %u\n",
+ num_ports);
+ return -ENODEV;
+ }
- /* ok, register the port */
- data->line = serial8250_register_8250_port(&data->uart);
- if (data->line < 0)
- return data->line;
+ data = devm_kcalloc(&mdev->dev, num_ports,
+ sizeof(struct serial_8250_men_mcb_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
- dev_info(&mdev->dev, "found 16Z125 UART: ttyS%d\n", data->line);
+ mcb_set_drvdata(mdev, data);
+
+ for (i = 0; i < num_ports; i++) {
+ data[i].uart.port.dev = mdev->dma_dev;
+ spin_lock_init(&data[i].uart.port.lock);
+
+ data[i].uart.port.type = PORT_16550;
+ data[i].uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ
+ | UPF_FIXED_TYPE;
+ data[i].uart.port.iotype = UPIO_MEM;
+ data[i].uart.port.uartclk = men_lookup_uartclk(mdev);
+ data[i].uart.port.regshift = 0;
+ data[i].uart.port.irq = mcb_get_irq(mdev);
+ data[i].uart.port.membase = membase;
+ data[i].uart.port.fifosize = 60;
+ data[i].uart.port.mapbase = (unsigned long) mem->start
+ + i * MEN_UART_MEM_SIZE;
+ data[i].uart.port.iobase = data[i].uart.port.mapbase;
+
+ /* ok, register the port */
+ data[i].line = serial8250_register_8250_port(&data[i].uart);
+ if (data[i].line < 0) {
+ dev_err(&mdev->dev, "unable to register UART port\n");
+ return data[i].line;
+ }
+ dev_info(&mdev->dev, "found MCB UART: ttyS%d\n", data[i].line);
+ }
return 0;
}
static void serial_8250_men_mcb_remove(struct mcb_device *mdev)
{
+ unsigned int num_ports, i;
struct serial_8250_men_mcb_data *data = mcb_get_drvdata(mdev);
- if (data)
- serial8250_unregister_port(data->line);
+ if (!data)
+ return;
+
+ num_ports = get_num_ports(mdev, data[0].uart.port.membase);
+ if (num_ports < 0 || num_ports > 4) {
+ dev_err(&mdev->dev, "error retrieving number of ports!\n");
+ return;
+ }
+
+ for (i = 0; i < num_ports; i++)
+ serial8250_unregister_port(data[i].line);
}
static const struct mcb_device_id serial_8250_men_mcb_ids[] = {
- { .device = 0x7d },
+ { .device = MEN_UART_ID_Z025 },
+ { .device = MEN_UART_ID_Z057 },
+ { .device = MEN_UART_ID_Z125 },
{ }
};
MODULE_DEVICE_TABLE(mcb, serial_8250_men_mcb_ids);
@@ -113,6 +168,8 @@ static struct mcb_driver mcb_driver = {
module_mcb_driver(mcb_driver);
MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("MEN 16z125 8250 UART driver");
+MODULE_DESCRIPTION("MEN 8250 UART driver");
MODULE_AUTHOR("Michael Moese <michael.moese@men.de");
MODULE_ALIAS("mcb:16z125");
+MODULE_ALIAS("mcb:16z025");
+MODULE_ALIAS("mcb:16z057");
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 160b8906d9b9..9835b1c1cbe1 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -316,6 +316,7 @@ static const struct of_device_id of_platform_serial_table[] = {
{ .compatible = "mrvl,mmp-uart",
.data = (void *)PORT_XSCALE, },
{ .compatible = "ti,da830-uart", .data = (void *)PORT_DA830, },
+ { .compatible = "nuvoton,npcm750-uart", .data = (void *)PORT_NPCM, },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, of_platform_serial_table);
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 57f6eba47f44..624b501fd253 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -114,6 +114,7 @@ struct omap8250_priv {
struct uart_8250_dma omap8250_dma;
spinlock_t rx_dma_lock;
bool rx_dma_broken;
+ bool throttled;
};
#ifdef CONFIG_SERIAL_8250_DMA
@@ -692,6 +693,7 @@ static void omap_8250_shutdown(struct uart_port *port)
static void omap_8250_throttle(struct uart_port *port)
{
+ struct omap8250_priv *priv = port->private_data;
struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
@@ -700,6 +702,7 @@ static void omap_8250_throttle(struct uart_port *port)
spin_lock_irqsave(&port->lock, flags);
up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
serial_out(up, UART_IER, up->ier);
+ priv->throttled = true;
spin_unlock_irqrestore(&port->lock, flags);
pm_runtime_mark_last_busy(port->dev);
@@ -738,12 +741,16 @@ static int omap_8250_rs485_config(struct uart_port *port,
static void omap_8250_unthrottle(struct uart_port *port)
{
+ struct omap8250_priv *priv = port->private_data;
struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
pm_runtime_get_sync(port->dev);
spin_lock_irqsave(&port->lock, flags);
+ priv->throttled = false;
+ if (up->dma)
+ up->dma->rx_dma(up);
up->ier |= UART_IER_RLSI | UART_IER_RDI;
serial_out(up, UART_IER, up->ier);
spin_unlock_irqrestore(&port->lock, flags);
@@ -788,6 +795,7 @@ unlock:
static void __dma_rx_complete(void *param)
{
struct uart_8250_port *p = param;
+ struct omap8250_priv *priv = p->port.private_data;
struct uart_8250_dma *dma = p->dma;
struct dma_tx_state state;
unsigned long flags;
@@ -805,7 +813,8 @@ static void __dma_rx_complete(void *param)
return;
}
__dma_rx_do_complete(p);
- omap_8250_rx_dma(p);
+ if (!priv->throttled)
+ omap_8250_rx_dma(p);
spin_unlock_irqrestore(&p->port.lock, flags);
}
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index a93f77ab3da0..3296a05cda2d 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1685,9 +1685,6 @@ pci_wch_ch38x_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
#define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e
-#define PCI_VENDOR_ID_SUNIX 0x1fd4
-#define PCI_DEVICE_ID_SUNIX_1999 0x1999
-
#define PCIE_VENDOR_ID_WCH 0x1c00
#define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250
#define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 1328c7e70108..95833cbc4338 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -47,6 +47,10 @@
#define UART_EXAR_SLEEP 0x8b /* Sleep mode */
#define UART_EXAR_DVID 0x8d /* Device identification */
+/* Nuvoton NPCM timeout register */
+#define UART_NPCM_TOR 7
+#define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */
+
/*
* Debugging.
*/
@@ -293,6 +297,15 @@ static const struct serial8250_config uart_config[] = {
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
.flags = UART_CAP_FIFO,
},
+ [PORT_NPCM] = {
+ .name = "Nuvoton 16550",
+ .fifo_size = 16,
+ .tx_loadsz = 16,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+ .rxtrig_bytes = {1, 4, 8, 14},
+ .flags = UART_CAP_FIFO,
+ },
};
/* Uart divisor latch read */
@@ -1854,7 +1867,8 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
status = serial_port_in(port, UART_LSR);
- if (status & (UART_LSR_DR | UART_LSR_BI)) {
+ if (status & (UART_LSR_DR | UART_LSR_BI) &&
+ iir & UART_IIR_RDI) {
if (!up->dma || handle_rx_dma(up, iir))
status = serial8250_rx_chars(up, status);
}
@@ -2140,6 +2154,15 @@ int serial8250_do_startup(struct uart_port *port)
UART_DA830_PWREMU_MGMT_FREE);
}
+ if (port->type == PORT_NPCM) {
+ /*
+ * Nuvoton calls the scratch register 'UART_TOR' (timeout
+ * register). Enable it, and set TIOC (timeout interrupt
+ * comparator) to be 0x20 for correct operation.
+ */
+ serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20);
+ }
+
#ifdef CONFIG_SERIAL_8250_RSA
/*
* If this is an RSA port, see if we can kick it up to the
@@ -2462,6 +2485,15 @@ static unsigned int xr17v35x_get_divisor(struct uart_8250_port *up,
return quot_16 >> 4;
}
+/* Nuvoton NPCM UARTs have a custom divisor calculation */
+static unsigned int npcm_get_divisor(struct uart_8250_port *up,
+ unsigned int baud)
+{
+ struct uart_port *port = &up->port;
+
+ return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2;
+}
+
static unsigned int serial8250_get_divisor(struct uart_8250_port *up,
unsigned int baud,
unsigned int *frac)
@@ -2482,6 +2514,8 @@ static unsigned int serial8250_get_divisor(struct uart_8250_port *up,
quot = 0x8002;
else if (up->port.type == PORT_XR17V35X)
quot = xr17v35x_get_divisor(up, baud, frac);
+ else if (up->port.type == PORT_NPCM)
+ quot = npcm_get_divisor(up, baud);
else
quot = uart_get_divisor(port, baud);
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 16b1496e6105..f005eaf8bc57 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -157,11 +157,12 @@ config SERIAL_8250_CS
If unsure, say N.
config SERIAL_8250_MEN_MCB
- tristate "MEN Z125 UART device support"
+ tristate "MEN MCB UART device support"
depends on MCB && SERIAL_8250
help
This enables support for FPGA based UARTs found on many MEN
- boards. This driver enables support for the Z125 UARTs.
+ boards. This driver enables support for the 16z025, 16z057
+ and 16z125 UARTs.
To compile this driver as a module, chose M here: the
module will be called 8250_men_mcb.
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 736720a8d84f..0f058df0b070 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -989,6 +989,21 @@ config SERIAL_MSM_CONSOLE
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
+config SERIAL_QCOM_GENI
+ tristate "QCOM on-chip GENI based serial port support"
+ depends on ARCH_QCOM || COMPILE_TEST
+ depends on QCOM_GENI_SE
+ select SERIAL_CORE
+
+config SERIAL_QCOM_GENI_CONSOLE
+ bool "QCOM GENI Serial Console support"
+ depends on SERIAL_QCOM_GENI=y
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
+ help
+ Serial console driver for Qualcomm Technologies Inc's GENI based
+ QUP hardware.
+
config SERIAL_VT8500
bool "VIA VT8500 on-chip serial port support"
depends on ARCH_VT8500
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index b30ee2e5d518..daac675612df 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
+obj-$(CONFIG_SERIAL_QCOM_GENI) += qcom_geni_serial.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index b88b05f8e81e..0e487ce091ac 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -109,6 +109,20 @@ static unsigned int altera_uart_get_mctrl(struct uart_port *port)
return sigs;
}
+static void altera_uart_update_ctrl_reg(struct altera_uart *pp)
+{
+ unsigned short imr = pp->imr;
+
+ /*
+ * If the device doesn't have an irq, ensure that the irq bits are
+ * masked out to keep the irq line inactive.
+ */
+ if (!pp->port.irq)
+ imr &= ALTERA_UART_CONTROL_TRBK_MSK | ALTERA_UART_CONTROL_RTS_MSK;
+
+ altera_uart_writel(&pp->port, imr, ALTERA_UART_CONTROL_REG);
+}
+
static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
@@ -118,7 +132,7 @@ static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs)
pp->imr |= ALTERA_UART_CONTROL_RTS_MSK;
else
pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK;
- altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+ altera_uart_update_ctrl_reg(pp);
}
static void altera_uart_start_tx(struct uart_port *port)
@@ -126,7 +140,7 @@ static void altera_uart_start_tx(struct uart_port *port)
struct altera_uart *pp = container_of(port, struct altera_uart, port);
pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK;
- altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+ altera_uart_update_ctrl_reg(pp);
}
static void altera_uart_stop_tx(struct uart_port *port)
@@ -134,7 +148,7 @@ static void altera_uart_stop_tx(struct uart_port *port)
struct altera_uart *pp = container_of(port, struct altera_uart, port);
pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
- altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+ altera_uart_update_ctrl_reg(pp);
}
static void altera_uart_stop_rx(struct uart_port *port)
@@ -142,7 +156,7 @@ static void altera_uart_stop_rx(struct uart_port *port)
struct altera_uart *pp = container_of(port, struct altera_uart, port);
pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK;
- altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+ altera_uart_update_ctrl_reg(pp);
}
static void altera_uart_break_ctl(struct uart_port *port, int break_state)
@@ -155,7 +169,7 @@ static void altera_uart_break_ctl(struct uart_port *port, int break_state)
pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK;
else
pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK;
- altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+ altera_uart_update_ctrl_reg(pp);
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -262,7 +276,7 @@ static void altera_uart_tx_chars(struct altera_uart *pp)
if (xmit->head == xmit->tail) {
pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
- altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG);
+ altera_uart_update_ctrl_reg(pp);
}
}
@@ -307,27 +321,27 @@ static int altera_uart_startup(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
- int ret;
if (!port->irq) {
timer_setup(&pp->tmr, altera_uart_timer, 0);
mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port));
- return 0;
- }
-
- ret = request_irq(port->irq, altera_uart_interrupt, 0,
- DRV_NAME, port);
- if (ret) {
- pr_err(DRV_NAME ": unable to attach Altera UART %d "
- "interrupt vector=%d\n", port->line, port->irq);
- return ret;
+ } else {
+ int ret;
+
+ ret = request_irq(port->irq, altera_uart_interrupt, 0,
+ DRV_NAME, port);
+ if (ret) {
+ pr_err(DRV_NAME ": unable to attach Altera UART %d "
+ "interrupt vector=%d\n", port->line, port->irq);
+ return ret;
+ }
}
spin_lock_irqsave(&port->lock, flags);
/* Enable RX interrupts now */
pp->imr = ALTERA_UART_CONTROL_RRDY_MSK;
- writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
+ altera_uart_update_ctrl_reg(pp);
spin_unlock_irqrestore(&port->lock, flags);
@@ -343,7 +357,7 @@ static void altera_uart_shutdown(struct uart_port *port)
/* Disable all interrupts now */
pp->imr = 0;
- writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
+ altera_uart_update_ctrl_reg(pp);
spin_unlock_irqrestore(&port->lock, flags);
@@ -432,7 +446,7 @@ static void altera_uart_console_putc(struct uart_port *port, int c)
ALTERA_UART_STATUS_TRDY_MSK))
cpu_relax();
- writel(c, port->membase + ALTERA_UART_TXDATA_REG);
+ altera_uart_writel(port, c, ALTERA_UART_TXDATA_REG);
}
static void altera_uart_console_write(struct console *co, const char *s,
@@ -502,13 +516,13 @@ static int __init altera_uart_earlycon_setup(struct earlycon_device *dev,
return -ENODEV;
/* Enable RX interrupts now */
- writel(ALTERA_UART_CONTROL_RRDY_MSK,
- port->membase + ALTERA_UART_CONTROL_REG);
+ altera_uart_writel(port, ALTERA_UART_CONTROL_RRDY_MSK,
+ ALTERA_UART_CONTROL_REG);
if (dev->baud) {
unsigned int baudclk = port->uartclk / dev->baud;
- writel(baudclk, port->membase + ALTERA_UART_DIVISOR_REG);
+ altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG);
}
dev->con->write = altera_uart_earlycon_write;
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 2599f9ecccfe..d904a3a345e7 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -593,6 +593,11 @@ static int arc_serial_probe(struct platform_device *pdev)
if (dev_id < 0)
dev_id = 0;
+ if (dev_id >= ARRAY_SIZE(arc_uart_ports)) {
+ dev_err(&pdev->dev, "serial%d out of range\n", dev_id);
+ return -EINVAL;
+ }
+
uart = &arc_uart_ports[dev_id];
port = &uart->port;
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 8cf112f2efc3..51e47a63d61a 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -2145,6 +2145,10 @@ static int lpuart_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
return ret;
}
+ if (ret >= ARRAY_SIZE(lpuart_ports)) {
+ dev_err(&pdev->dev, "serial%d out of range\n", ret);
+ return -EINVAL;
+ }
sport->port.line = ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index a33c685af990..91f3a1a5cb7f 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -71,12 +71,12 @@
#define UCR1_IDEN (1<<12) /* Idle condition interrupt */
#define UCR1_ICD_REG(x) (((x) & 3) << 10) /* idle condition detect */
#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */
-#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */
+#define UCR1_RXDMAEN (1<<8) /* Recv ready DMA enable */
#define UCR1_IREN (1<<7) /* Infrared interface enable */
#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */
#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */
#define UCR1_SNDBRK (1<<4) /* Send break */
-#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */
+#define UCR1_TXDMAEN (1<<3) /* Transmitter ready DMA enable */
#define IMX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, i.mx1 only */
#define UCR1_ATDMAEN (1<<2) /* Aging DMA Timer Enable */
#define UCR1_DOZE (1<<1) /* Doze */
@@ -204,8 +204,14 @@ struct imx_port {
struct mctrl_gpios *gpios;
+ /* shadow registers */
+ unsigned int ucr1;
+ unsigned int ucr2;
+ unsigned int ucr3;
+ unsigned int ucr4;
+ unsigned int ufcr;
+
/* DMA fields */
- unsigned int dma_is_inited:1;
unsigned int dma_is_enabled:1;
unsigned int dma_is_rxing:1;
unsigned int dma_is_txing:1;
@@ -274,27 +280,81 @@ static const struct of_device_id imx_uart_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, imx_uart_dt_ids);
-static inline unsigned uts_reg(struct imx_port *sport)
+static void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset)
+{
+ switch (offset) {
+ case UCR1:
+ sport->ucr1 = val;
+ break;
+ case UCR2:
+ sport->ucr2 = val;
+ break;
+ case UCR3:
+ sport->ucr3 = val;
+ break;
+ case UCR4:
+ sport->ucr4 = val;
+ break;
+ case UFCR:
+ sport->ufcr = val;
+ break;
+ default:
+ break;
+ }
+ writel(val, sport->port.membase + offset);
+}
+
+static u32 imx_uart_readl(struct imx_port *sport, u32 offset)
+{
+ switch (offset) {
+ case UCR1:
+ return sport->ucr1;
+ break;
+ case UCR2:
+ /*
+ * UCR2_SRST is the only bit in the cached registers that might
+ * differ from the value that was last written. As it only
+ * clears after being set, reread conditionally.
+ */
+ if (sport->ucr2 & UCR2_SRST)
+ sport->ucr2 = readl(sport->port.membase + offset);
+ return sport->ucr2;
+ break;
+ case UCR3:
+ return sport->ucr3;
+ break;
+ case UCR4:
+ return sport->ucr4;
+ break;
+ case UFCR:
+ return sport->ufcr;
+ break;
+ default:
+ return readl(sport->port.membase + offset);
+ }
+}
+
+static inline unsigned imx_uart_uts_reg(struct imx_port *sport)
{
return sport->devdata->uts_reg;
}
-static inline int is_imx1_uart(struct imx_port *sport)
+static inline int imx_uart_is_imx1(struct imx_port *sport)
{
return sport->devdata->devtype == IMX1_UART;
}
-static inline int is_imx21_uart(struct imx_port *sport)
+static inline int imx_uart_is_imx21(struct imx_port *sport)
{
return sport->devdata->devtype == IMX21_UART;
}
-static inline int is_imx53_uart(struct imx_port *sport)
+static inline int imx_uart_is_imx53(struct imx_port *sport)
{
return sport->devdata->devtype == IMX53_UART;
}
-static inline int is_imx6q_uart(struct imx_port *sport)
+static inline int imx_uart_is_imx6q(struct imx_port *sport)
{
return sport->devdata->devtype == IMX6Q_UART;
}
@@ -302,26 +362,26 @@ static inline int is_imx6q_uart(struct imx_port *sport)
* Save and restore functions for UCR1, UCR2 and UCR3 registers
*/
#if defined(CONFIG_SERIAL_IMX_CONSOLE)
-static void imx_port_ucrs_save(struct uart_port *port,
+static void imx_uart_ucrs_save(struct imx_port *sport,
struct imx_port_ucrs *ucr)
{
/* save control registers */
- ucr->ucr1 = readl(port->membase + UCR1);
- ucr->ucr2 = readl(port->membase + UCR2);
- ucr->ucr3 = readl(port->membase + UCR3);
+ ucr->ucr1 = imx_uart_readl(sport, UCR1);
+ ucr->ucr2 = imx_uart_readl(sport, UCR2);
+ ucr->ucr3 = imx_uart_readl(sport, UCR3);
}
-static void imx_port_ucrs_restore(struct uart_port *port,
+static void imx_uart_ucrs_restore(struct imx_port *sport,
struct imx_port_ucrs *ucr)
{
/* restore control registers */
- writel(ucr->ucr1, port->membase + UCR1);
- writel(ucr->ucr2, port->membase + UCR2);
- writel(ucr->ucr3, port->membase + UCR3);
+ imx_uart_writel(sport, ucr->ucr1, UCR1);
+ imx_uart_writel(sport, ucr->ucr2, UCR2);
+ imx_uart_writel(sport, ucr->ucr3, UCR3);
}
#endif
-static void imx_port_rts_active(struct imx_port *sport, unsigned long *ucr2)
+static void imx_uart_rts_active(struct imx_port *sport, u32 *ucr2)
{
*ucr2 &= ~(UCR2_CTSC | UCR2_CTS);
@@ -329,7 +389,7 @@ static void imx_port_rts_active(struct imx_port *sport, unsigned long *ucr2)
mctrl_gpio_set(sport->gpios, sport->port.mctrl);
}
-static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2)
+static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2)
{
*ucr2 &= ~UCR2_CTSC;
*ucr2 |= UCR2_CTS;
@@ -338,75 +398,91 @@ static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2)
mctrl_gpio_set(sport->gpios, sport->port.mctrl);
}
-static void imx_port_rts_auto(struct imx_port *sport, unsigned long *ucr2)
+static void imx_uart_rts_auto(struct imx_port *sport, u32 *ucr2)
{
*ucr2 |= UCR2_CTSC;
}
-/*
- * interrupts disabled on entry
- */
-static void imx_stop_tx(struct uart_port *port)
+/* called with port.lock taken and irqs off */
+static void imx_uart_start_rx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
- unsigned long temp;
+ unsigned int ucr1, ucr2;
+
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr2 = imx_uart_readl(sport, UCR2);
+
+ ucr2 |= UCR2_RXEN;
+
+ if (sport->dma_is_enabled) {
+ ucr1 |= UCR1_RXDMAEN | UCR1_ATDMAEN;
+ } else {
+ ucr1 |= UCR1_RRDYEN;
+ ucr2 |= UCR2_ATEN;
+ }
+
+ /* Write UCR2 first as it includes RXEN */
+ imx_uart_writel(sport, ucr2, UCR2);
+ imx_uart_writel(sport, ucr1, UCR1);
+}
+
+/* called with port.lock taken and irqs off */
+static void imx_uart_stop_tx(struct uart_port *port)
+{
+ struct imx_port *sport = (struct imx_port *)port;
+ u32 ucr1;
/*
* We are maybe in the SMP context, so if the DMA TX thread is running
* on other cpu, we have to wait for it to finish.
*/
- if (sport->dma_is_enabled && sport->dma_is_txing)
+ if (sport->dma_is_txing)
return;
- temp = readl(port->membase + UCR1);
- writel(temp & ~UCR1_TXMPTYEN, port->membase + UCR1);
+ ucr1 = imx_uart_readl(sport, UCR1);
+ imx_uart_writel(sport, ucr1 & ~UCR1_TXMPTYEN, UCR1);
/* in rs485 mode disable transmitter if shifter is empty */
if (port->rs485.flags & SER_RS485_ENABLED &&
- readl(port->membase + USR2) & USR2_TXDC) {
- temp = readl(port->membase + UCR2);
+ imx_uart_readl(sport, USR2) & USR2_TXDC) {
+ u32 ucr2 = imx_uart_readl(sport, UCR2), ucr4;
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
- imx_port_rts_active(sport, &temp);
+ imx_uart_rts_active(sport, &ucr2);
else
- imx_port_rts_inactive(sport, &temp);
- temp |= UCR2_RXEN;
- writel(temp, port->membase + UCR2);
+ imx_uart_rts_inactive(sport, &ucr2);
+ imx_uart_writel(sport, ucr2, UCR2);
+
+ imx_uart_start_rx(port);
- temp = readl(port->membase + UCR4);
- temp &= ~UCR4_TCEN;
- writel(temp, port->membase + UCR4);
+ ucr4 = imx_uart_readl(sport, UCR4);
+ ucr4 &= ~UCR4_TCEN;
+ imx_uart_writel(sport, ucr4, UCR4);
}
}
-/*
- * interrupts disabled on entry
- */
-static void imx_stop_rx(struct uart_port *port)
+/* called with port.lock taken and irqs off */
+static void imx_uart_stop_rx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
- unsigned long temp;
+ u32 ucr1, ucr2;
- if (sport->dma_is_enabled && sport->dma_is_rxing) {
- if (sport->port.suspended) {
- dmaengine_terminate_all(sport->dma_chan_rx);
- sport->dma_is_rxing = 0;
- } else {
- return;
- }
- }
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr2 = imx_uart_readl(sport, UCR2);
- temp = readl(sport->port.membase + UCR2);
- writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
+ if (sport->dma_is_enabled) {
+ ucr1 &= ~(UCR1_RXDMAEN | UCR1_ATDMAEN);
+ } else {
+ ucr1 &= ~UCR1_RRDYEN;
+ ucr2 &= ~UCR2_ATEN;
+ }
+ imx_uart_writel(sport, ucr1, UCR1);
- /* disable the `Receiver Ready Interrrupt` */
- temp = readl(sport->port.membase + UCR1);
- writel(temp & ~UCR1_RRDYEN, sport->port.membase + UCR1);
+ ucr2 &= ~UCR2_RXEN;
+ imx_uart_writel(sport, ucr2, UCR2);
}
-/*
- * Set the modem control timer to fire immediately.
- */
-static void imx_enable_ms(struct uart_port *port)
+/* called with port.lock taken and irqs off */
+static void imx_uart_enable_ms(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
@@ -415,49 +491,50 @@ static void imx_enable_ms(struct uart_port *port)
mctrl_gpio_enable_ms(sport->gpios);
}
-static void imx_dma_tx(struct imx_port *sport);
-static inline void imx_transmit_buffer(struct imx_port *sport)
+static void imx_uart_dma_tx(struct imx_port *sport);
+
+/* called with port.lock taken and irqs off */
+static inline void imx_uart_transmit_buffer(struct imx_port *sport)
{
struct circ_buf *xmit = &sport->port.state->xmit;
- unsigned long temp;
if (sport->port.x_char) {
/* Send next char */
- writel(sport->port.x_char, sport->port.membase + URTX0);
+ imx_uart_writel(sport, sport->port.x_char, URTX0);
sport->port.icount.tx++;
sport->port.x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
- imx_stop_tx(&sport->port);
+ imx_uart_stop_tx(&sport->port);
return;
}
if (sport->dma_is_enabled) {
+ u32 ucr1;
/*
* We've just sent a X-char Ensure the TX DMA is enabled
* and the TX IRQ is disabled.
**/
- temp = readl(sport->port.membase + UCR1);
- temp &= ~UCR1_TXMPTYEN;
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr1 &= ~UCR1_TXMPTYEN;
if (sport->dma_is_txing) {
- temp |= UCR1_TDMAEN;
- writel(temp, sport->port.membase + UCR1);
+ ucr1 |= UCR1_TXDMAEN;
+ imx_uart_writel(sport, ucr1, UCR1);
} else {
- writel(temp, sport->port.membase + UCR1);
- imx_dma_tx(sport);
+ imx_uart_writel(sport, ucr1, UCR1);
+ imx_uart_dma_tx(sport);
}
- }
- if (sport->dma_is_txing)
return;
+ }
while (!uart_circ_empty(xmit) &&
- !(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) {
+ !(imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL)) {
/* send xmit->buf[xmit->tail]
* out the port here */
- writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
+ imx_uart_writel(sport, xmit->buf[xmit->tail], URTX0);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
sport->port.icount.tx++;
}
@@ -466,24 +543,24 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
uart_write_wakeup(&sport->port);
if (uart_circ_empty(xmit))
- imx_stop_tx(&sport->port);
+ imx_uart_stop_tx(&sport->port);
}
-static void dma_tx_callback(void *data)
+static void imx_uart_dma_tx_callback(void *data)
{
struct imx_port *sport = data;
struct scatterlist *sgl = &sport->tx_sgl[0];
struct circ_buf *xmit = &sport->port.state->xmit;
unsigned long flags;
- unsigned long temp;
+ u32 ucr1;
spin_lock_irqsave(&sport->port.lock, flags);
dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
- temp = readl(sport->port.membase + UCR1);
- temp &= ~UCR1_TDMAEN;
- writel(temp, sport->port.membase + UCR1);
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr1 &= ~UCR1_TXDMAEN;
+ imx_uart_writel(sport, ucr1, UCR1);
/* update the stat */
xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1);
@@ -497,24 +574,34 @@ static void dma_tx_callback(void *data)
uart_write_wakeup(&sport->port);
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
- imx_dma_tx(sport);
+ imx_uart_dma_tx(sport);
+ else if (sport->port.rs485.flags & SER_RS485_ENABLED) {
+ u32 ucr4 = imx_uart_readl(sport, UCR4);
+ ucr4 |= UCR4_TCEN;
+ imx_uart_writel(sport, ucr4, UCR4);
+ }
spin_unlock_irqrestore(&sport->port.lock, flags);
}
-static void imx_dma_tx(struct imx_port *sport)
+/* called with port.lock taken and irqs off */
+static void imx_uart_dma_tx(struct imx_port *sport)
{
struct circ_buf *xmit = &sport->port.state->xmit;
struct scatterlist *sgl = sport->tx_sgl;
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = sport->dma_chan_tx;
struct device *dev = sport->port.dev;
- unsigned long temp;
+ u32 ucr1, ucr4;
int ret;
if (sport->dma_is_txing)
return;
+ ucr4 = imx_uart_readl(sport, UCR4);
+ ucr4 &= ~UCR4_TCEN;
+ imx_uart_writel(sport, ucr4, UCR4);
+
sport->tx_bytes = uart_circ_chars_pending(xmit);
if (xmit->tail < xmit->head) {
@@ -541,15 +628,15 @@ static void imx_dma_tx(struct imx_port *sport)
dev_err(dev, "We cannot prepare for the TX slave dma!\n");
return;
}
- desc->callback = dma_tx_callback;
+ desc->callback = imx_uart_dma_tx_callback;
desc->callback_param = sport;
dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
uart_circ_chars_pending(xmit));
- temp = readl(sport->port.membase + UCR1);
- temp |= UCR1_TDMAEN;
- writel(temp, sport->port.membase + UCR1);
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr1 |= UCR1_TXDMAEN;
+ imx_uart_writel(sport, ucr1, UCR1);
/* fire it */
sport->dma_is_txing = 1;
@@ -558,99 +645,110 @@ static void imx_dma_tx(struct imx_port *sport)
return;
}
-/*
- * interrupts disabled on entry
- */
-static void imx_start_tx(struct uart_port *port)
+/* called with port.lock taken and irqs off */
+static void imx_uart_start_tx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
- unsigned long temp;
+ u32 ucr1;
+
+ if (!sport->port.x_char && uart_circ_empty(&port->state->xmit))
+ return;
if (port->rs485.flags & SER_RS485_ENABLED) {
- temp = readl(port->membase + UCR2);
+ u32 ucr2;
+
+ ucr2 = imx_uart_readl(sport, UCR2);
if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
- imx_port_rts_active(sport, &temp);
+ imx_uart_rts_active(sport, &ucr2);
else
- imx_port_rts_inactive(sport, &temp);
+ imx_uart_rts_inactive(sport, &ucr2);
+ imx_uart_writel(sport, ucr2, UCR2);
+
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
- temp &= ~UCR2_RXEN;
- writel(temp, port->membase + UCR2);
+ imx_uart_stop_rx(port);
- /* enable transmitter and shifter empty irq */
- temp = readl(port->membase + UCR4);
- temp |= UCR4_TCEN;
- writel(temp, port->membase + UCR4);
+ /*
+ * Enable transmitter and shifter empty irq only if DMA is off.
+ * In the DMA case this is done in the tx-callback.
+ */
+ if (!sport->dma_is_enabled) {
+ u32 ucr4 = imx_uart_readl(sport, UCR4);
+ ucr4 |= UCR4_TCEN;
+ imx_uart_writel(sport, ucr4, UCR4);
+ }
}
if (!sport->dma_is_enabled) {
- temp = readl(sport->port.membase + UCR1);
- writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
+ ucr1 = imx_uart_readl(sport, UCR1);
+ imx_uart_writel(sport, ucr1 | UCR1_TXMPTYEN, UCR1);
}
if (sport->dma_is_enabled) {
if (sport->port.x_char) {
/* We have X-char to send, so enable TX IRQ and
* disable TX DMA to let TX interrupt to send X-char */
- temp = readl(sport->port.membase + UCR1);
- temp &= ~UCR1_TDMAEN;
- temp |= UCR1_TXMPTYEN;
- writel(temp, sport->port.membase + UCR1);
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr1 &= ~UCR1_TXDMAEN;
+ ucr1 |= UCR1_TXMPTYEN;
+ imx_uart_writel(sport, ucr1, UCR1);
return;
}
if (!uart_circ_empty(&port->state->xmit) &&
!uart_tx_stopped(port))
- imx_dma_tx(sport);
+ imx_uart_dma_tx(sport);
return;
}
}
-static irqreturn_t imx_rtsint(int irq, void *dev_id)
+static irqreturn_t imx_uart_rtsint(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
- unsigned int val;
+ u32 usr1;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
- writel(USR1_RTSD, sport->port.membase + USR1);
- val = readl(sport->port.membase + USR1) & USR1_RTSS;
- uart_handle_cts_change(&sport->port, !!val);
+ imx_uart_writel(sport, USR1_RTSD, USR1);
+ usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS;
+ uart_handle_cts_change(&sport->port, !!usr1);
wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
spin_unlock_irqrestore(&sport->port.lock, flags);
return IRQ_HANDLED;
}
-static irqreturn_t imx_txint(int irq, void *dev_id)
+static irqreturn_t imx_uart_txint(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
- imx_transmit_buffer(sport);
+ imx_uart_transmit_buffer(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
return IRQ_HANDLED;
}
-static irqreturn_t imx_rxint(int irq, void *dev_id)
+static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
unsigned int rx, flg, ignored = 0;
struct tty_port *port = &sport->port.state->port;
- unsigned long flags, temp;
+ unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
- while (readl(sport->port.membase + USR2) & USR2_RDR) {
+ while (imx_uart_readl(sport, USR2) & USR2_RDR) {
+ u32 usr2;
+
flg = TTY_NORMAL;
sport->port.icount.rx++;
- rx = readl(sport->port.membase + URXD0);
+ rx = imx_uart_readl(sport, URXD0);
- temp = readl(sport->port.membase + USR2);
- if (temp & USR2_BRCD) {
- writel(USR2_BRCD, sport->port.membase + USR2);
+ usr2 = imx_uart_readl(sport, USR2);
+ if (usr2 & USR2_BRCD) {
+ imx_uart_writel(sport, USR2_BRCD, USR2);
if (uart_handle_break(&sport->port))
continue;
}
@@ -703,16 +801,16 @@ out:
return IRQ_HANDLED;
}
-static void clear_rx_errors(struct imx_port *sport);
+static void imx_uart_clear_rx_errors(struct imx_port *sport);
/*
* We have a modem side uart, so the meanings of RTS and CTS are inverted.
*/
-static unsigned int imx_get_hwmctrl(struct imx_port *sport)
+static unsigned int imx_uart_get_hwmctrl(struct imx_port *sport)
{
unsigned int tmp = TIOCM_DSR;
- unsigned usr1 = readl(sport->port.membase + USR1);
- unsigned usr2 = readl(sport->port.membase + USR2);
+ unsigned usr1 = imx_uart_readl(sport, USR1);
+ unsigned usr2 = imx_uart_readl(sport, USR2);
if (usr1 & USR1_RTSS)
tmp |= TIOCM_CTS;
@@ -722,7 +820,7 @@ static unsigned int imx_get_hwmctrl(struct imx_port *sport)
tmp |= TIOCM_CAR;
if (sport->dte_mode)
- if (!(readl(sport->port.membase + USR2) & USR2_RIIN))
+ if (!(imx_uart_readl(sport, USR2) & USR2_RIIN))
tmp |= TIOCM_RI;
return tmp;
@@ -731,11 +829,11 @@ static unsigned int imx_get_hwmctrl(struct imx_port *sport)
/*
* Handle any change of modem status signal since we were last called.
*/
-static void imx_mctrl_check(struct imx_port *sport)
+static void imx_uart_mctrl_check(struct imx_port *sport)
{
unsigned int status, changed;
- status = imx_get_hwmctrl(sport);
+ status = imx_uart_get_hwmctrl(sport);
changed = status ^ sport->old_status;
if (changed == 0)
@@ -755,55 +853,79 @@ static void imx_mctrl_check(struct imx_port *sport)
wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
}
-static irqreturn_t imx_int(int irq, void *dev_id)
+static irqreturn_t imx_uart_int(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
- unsigned int sts;
- unsigned int sts2;
+ unsigned int usr1, usr2, ucr1, ucr2, ucr3, ucr4;
irqreturn_t ret = IRQ_NONE;
- sts = readl(sport->port.membase + USR1);
- sts2 = readl(sport->port.membase + USR2);
+ usr1 = imx_uart_readl(sport, USR1);
+ usr2 = imx_uart_readl(sport, USR2);
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr2 = imx_uart_readl(sport, UCR2);
+ ucr3 = imx_uart_readl(sport, UCR3);
+ ucr4 = imx_uart_readl(sport, UCR4);
- if (!sport->dma_is_enabled && (sts & (USR1_RRDY | USR1_AGTIM))) {
- imx_rxint(irq, dev_id);
+ /*
+ * Even if a condition is true that can trigger an irq only handle it if
+ * the respective irq source is enabled. This prevents some undesired
+ * actions, for example if a character that sits in the RX FIFO and that
+ * should be fetched via DMA is tried to be fetched using PIO. Or the
+ * receiver is currently off and so reading from URXD0 results in an
+ * exception. So just mask the (raw) status bits for disabled irqs.
+ */
+ if ((ucr1 & UCR1_RRDYEN) == 0)
+ usr1 &= ~USR1_RRDY;
+ if ((ucr2 & UCR2_ATEN) == 0)
+ usr1 &= ~USR1_AGTIM;
+ if ((ucr1 & UCR1_TXMPTYEN) == 0)
+ usr1 &= ~USR1_TRDY;
+ if ((ucr4 & UCR4_TCEN) == 0)
+ usr2 &= ~USR2_TXDC;
+ if ((ucr3 & UCR3_DTRDEN) == 0)
+ usr1 &= ~USR1_DTRD;
+ if ((ucr1 & UCR1_RTSDEN) == 0)
+ usr1 &= ~USR1_RTSD;
+ if ((ucr3 & UCR3_AWAKEN) == 0)
+ usr1 &= ~USR1_AWAKE;
+ if ((ucr4 & UCR4_OREN) == 0)
+ usr2 &= ~USR2_ORE;
+
+ if (usr1 & (USR1_RRDY | USR1_AGTIM)) {
+ imx_uart_rxint(irq, dev_id);
ret = IRQ_HANDLED;
}
- if ((sts & USR1_TRDY &&
- readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) ||
- (sts2 & USR2_TXDC &&
- readl(sport->port.membase + UCR4) & UCR4_TCEN)) {
- imx_txint(irq, dev_id);
+ if ((usr1 & USR1_TRDY) || (usr2 & USR2_TXDC)) {
+ imx_uart_txint(irq, dev_id);
ret = IRQ_HANDLED;
}
- if (sts & USR1_DTRD) {
+ if (usr1 & USR1_DTRD) {
unsigned long flags;
- if (sts & USR1_DTRD)
- writel(USR1_DTRD, sport->port.membase + USR1);
+ imx_uart_writel(sport, USR1_DTRD, USR1);
spin_lock_irqsave(&sport->port.lock, flags);
- imx_mctrl_check(sport);
+ imx_uart_mctrl_check(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
ret = IRQ_HANDLED;
}
- if (sts & USR1_RTSD) {
- imx_rtsint(irq, dev_id);
+ if (usr1 & USR1_RTSD) {
+ imx_uart_rtsint(irq, dev_id);
ret = IRQ_HANDLED;
}
- if (sts & USR1_AWAKE) {
- writel(USR1_AWAKE, sport->port.membase + USR1);
+ if (usr1 & USR1_AWAKE) {
+ imx_uart_writel(sport, USR1_AWAKE, USR1);
ret = IRQ_HANDLED;
}
- if (sts2 & USR2_ORE) {
+ if (usr2 & USR2_ORE) {
sport->port.icount.overrun++;
- writel(USR2_ORE, sport->port.membase + USR2);
+ imx_uart_writel(sport, USR2_ORE, USR2);
ret = IRQ_HANDLED;
}
@@ -813,52 +935,56 @@ static irqreturn_t imx_int(int irq, void *dev_id)
/*
* Return TIOCSER_TEMT when transmitter is not busy.
*/
-static unsigned int imx_tx_empty(struct uart_port *port)
+static unsigned int imx_uart_tx_empty(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned int ret;
- ret = (readl(sport->port.membase + USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0;
+ ret = (imx_uart_readl(sport, USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0;
/* If the TX DMA is working, return 0. */
- if (sport->dma_is_enabled && sport->dma_is_txing)
+ if (sport->dma_is_txing)
ret = 0;
return ret;
}
-static unsigned int imx_get_mctrl(struct uart_port *port)
+/* called with port.lock taken and irqs off */
+static unsigned int imx_uart_get_mctrl(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
- unsigned int ret = imx_get_hwmctrl(sport);
+ unsigned int ret = imx_uart_get_hwmctrl(sport);
mctrl_gpio_get(sport->gpios, &ret);
return ret;
}
-static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+/* called with port.lock taken and irqs off */
+static void imx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct imx_port *sport = (struct imx_port *)port;
- unsigned long temp;
+ u32 ucr3, uts;
if (!(port->rs485.flags & SER_RS485_ENABLED)) {
- temp = readl(sport->port.membase + UCR2);
- temp &= ~(UCR2_CTS | UCR2_CTSC);
+ u32 ucr2;
+
+ ucr2 = imx_uart_readl(sport, UCR2);
+ ucr2 &= ~(UCR2_CTS | UCR2_CTSC);
if (mctrl & TIOCM_RTS)
- temp |= UCR2_CTS | UCR2_CTSC;
- writel(temp, sport->port.membase + UCR2);
+ ucr2 |= UCR2_CTS | UCR2_CTSC;
+ imx_uart_writel(sport, ucr2, UCR2);
}
- temp = readl(sport->port.membase + UCR3) & ~UCR3_DSR;
+ ucr3 = imx_uart_readl(sport, UCR3) & ~UCR3_DSR;
if (!(mctrl & TIOCM_DTR))
- temp |= UCR3_DSR;
- writel(temp, sport->port.membase + UCR3);
+ ucr3 |= UCR3_DSR;
+ imx_uart_writel(sport, ucr3, UCR3);
- temp = readl(sport->port.membase + uts_reg(sport)) & ~UTS_LOOP;
+ uts = imx_uart_readl(sport, imx_uart_uts_reg(sport)) & ~UTS_LOOP;
if (mctrl & TIOCM_LOOP)
- temp |= UTS_LOOP;
- writel(temp, sport->port.membase + uts_reg(sport));
+ uts |= UTS_LOOP;
+ imx_uart_writel(sport, uts, imx_uart_uts_reg(sport));
mctrl_gpio_set(sport->gpios, mctrl);
}
@@ -866,19 +992,20 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
/*
* Interrupts always disabled.
*/
-static void imx_break_ctl(struct uart_port *port, int break_state)
+static void imx_uart_break_ctl(struct uart_port *port, int break_state)
{
struct imx_port *sport = (struct imx_port *)port;
- unsigned long flags, temp;
+ unsigned long flags;
+ u32 ucr1;
spin_lock_irqsave(&sport->port.lock, flags);
- temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK;
+ ucr1 = imx_uart_readl(sport, UCR1) & ~UCR1_SNDBRK;
if (break_state != 0)
- temp |= UCR1_SNDBRK;
+ ucr1 |= UCR1_SNDBRK;
- writel(temp, sport->port.membase + UCR1);
+ imx_uart_writel(sport, ucr1, UCR1);
spin_unlock_irqrestore(&sport->port.lock, flags);
}
@@ -887,14 +1014,14 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
* This is our per-port timeout handler, for checking the
* modem status signals.
*/
-static void imx_timeout(struct timer_list *t)
+static void imx_uart_timeout(struct timer_list *t)
{
struct imx_port *sport = from_timer(sport, t, timer);
unsigned long flags;
if (sport->port.state) {
spin_lock_irqsave(&sport->port.lock, flags);
- imx_mctrl_check(sport);
+ imx_uart_mctrl_check(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
@@ -911,7 +1038,7 @@ static void imx_timeout(struct timer_list *t)
* Condition [2] is triggered when a character has been sitting in the FIFO
* for at least 8 byte durations.
*/
-static void dma_rx_callback(void *data)
+static void imx_uart_dma_rx_callback(void *data)
{
struct imx_port *sport = data;
struct dma_chan *chan = sport->dma_chan_rx;
@@ -927,8 +1054,7 @@ static void dma_rx_callback(void *data)
status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state);
if (status == DMA_ERROR) {
- dev_err(sport->port.dev, "DMA transaction error.\n");
- clear_rx_errors(sport);
+ imx_uart_clear_rx_errors(sport);
return;
}
@@ -988,7 +1114,7 @@ static void dma_rx_callback(void *data)
/* RX DMA buffer periods */
#define RX_DMA_PERIODS 4
-static int start_rx_dma(struct imx_port *sport)
+static int imx_uart_start_rx_dma(struct imx_port *sport)
{
struct scatterlist *sgl = &sport->rx_sgl;
struct dma_chan *chan = sport->dma_chan_rx;
@@ -1016,7 +1142,7 @@ static int start_rx_dma(struct imx_port *sport)
dev_err(dev, "We cannot prepare for the RX slave dma!\n");
return -EINVAL;
}
- desc->callback = dma_rx_callback;
+ desc->callback = imx_uart_dma_rx_callback;
desc->callback_param = sport;
dev_dbg(dev, "RX: prepare for the DMA.\n");
@@ -1026,27 +1152,35 @@ static int start_rx_dma(struct imx_port *sport)
return 0;
}
-static void clear_rx_errors(struct imx_port *sport)
+static void imx_uart_clear_rx_errors(struct imx_port *sport)
{
- unsigned int status_usr1, status_usr2;
+ struct tty_port *port = &sport->port.state->port;
+ u32 usr1, usr2;
- status_usr1 = readl(sport->port.membase + USR1);
- status_usr2 = readl(sport->port.membase + USR2);
+ usr1 = imx_uart_readl(sport, USR1);
+ usr2 = imx_uart_readl(sport, USR2);
- if (status_usr2 & USR2_BRCD) {
+ if (usr2 & USR2_BRCD) {
sport->port.icount.brk++;
- writel(USR2_BRCD, sport->port.membase + USR2);
- } else if (status_usr1 & USR1_FRAMERR) {
- sport->port.icount.frame++;
- writel(USR1_FRAMERR, sport->port.membase + USR1);
- } else if (status_usr1 & USR1_PARITYERR) {
- sport->port.icount.parity++;
- writel(USR1_PARITYERR, sport->port.membase + USR1);
+ imx_uart_writel(sport, USR2_BRCD, USR2);
+ uart_handle_break(&sport->port);
+ if (tty_insert_flip_char(port, 0, TTY_BREAK) == 0)
+ sport->port.icount.buf_overrun++;
+ tty_flip_buffer_push(port);
+ } else {
+ dev_err(sport->port.dev, "DMA transaction error.\n");
+ if (usr1 & USR1_FRAMERR) {
+ sport->port.icount.frame++;
+ imx_uart_writel(sport, USR1_FRAMERR, USR1);
+ } else if (usr1 & USR1_PARITYERR) {
+ sport->port.icount.parity++;
+ imx_uart_writel(sport, USR1_PARITYERR, USR1);
+ }
}
- if (status_usr2 & USR2_ORE) {
+ if (usr2 & USR2_ORE) {
sport->port.icount.overrun++;
- writel(USR2_ORE, sport->port.membase + USR2);
+ imx_uart_writel(sport, USR2_ORE, USR2);
}
}
@@ -1056,15 +1190,15 @@ static void clear_rx_errors(struct imx_port *sport)
#define TXTL_DMA 8 /* DMA burst setting */
#define RXTL_DMA 9 /* DMA burst setting */
-static void imx_setup_ufcr(struct imx_port *sport,
- unsigned char txwl, unsigned char rxwl)
+static void imx_uart_setup_ufcr(struct imx_port *sport,
+ unsigned char txwl, unsigned char rxwl)
{
unsigned int val;
/* set receiver / transmitter trigger level */
- val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
+ val = imx_uart_readl(sport, UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
val |= txwl << UFCR_TXTL_SHF | rxwl;
- writel(val, sport->port.membase + UFCR);
+ imx_uart_writel(sport, val, UFCR);
}
static void imx_uart_dma_exit(struct imx_port *sport)
@@ -1083,8 +1217,6 @@ static void imx_uart_dma_exit(struct imx_port *sport)
dma_release_channel(sport->dma_chan_tx);
sport->dma_chan_tx = NULL;
}
-
- sport->dma_is_inited = 0;
}
static int imx_uart_dma_init(struct imx_port *sport)
@@ -1137,43 +1269,41 @@ static int imx_uart_dma_init(struct imx_port *sport)
goto err;
}
- sport->dma_is_inited = 1;
-
return 0;
err:
imx_uart_dma_exit(sport);
return ret;
}
-static void imx_enable_dma(struct imx_port *sport)
+static void imx_uart_enable_dma(struct imx_port *sport)
{
- unsigned long temp;
+ u32 ucr1;
- /* set UCR1 */
- temp = readl(sport->port.membase + UCR1);
- temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN;
- writel(temp, sport->port.membase + UCR1);
+ imx_uart_setup_ufcr(sport, TXTL_DMA, RXTL_DMA);
- imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA);
+ /* set UCR1 */
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr1 |= UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN;
+ imx_uart_writel(sport, ucr1, UCR1);
sport->dma_is_enabled = 1;
}
-static void imx_disable_dma(struct imx_port *sport)
+static void imx_uart_disable_dma(struct imx_port *sport)
{
- unsigned long temp;
+ u32 ucr1, ucr2;
/* clear UCR1 */
- temp = readl(sport->port.membase + UCR1);
- temp &= ~(UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN);
- writel(temp, sport->port.membase + UCR1);
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr1 &= ~(UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN);
+ imx_uart_writel(sport, ucr1, UCR1);
/* clear UCR2 */
- temp = readl(sport->port.membase + UCR2);
- temp &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN);
- writel(temp, sport->port.membase + UCR2);
+ ucr2 = imx_uart_readl(sport, UCR2);
+ ucr2 &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN);
+ imx_uart_writel(sport, ucr2, UCR2);
- imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
sport->dma_is_enabled = 0;
}
@@ -1181,11 +1311,13 @@ static void imx_disable_dma(struct imx_port *sport)
/* half the RX buffer size */
#define CTSTL 16
-static int imx_startup(struct uart_port *port)
+static int imx_uart_startup(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
int retval, i;
- unsigned long flags, temp;
+ unsigned long flags;
+ int dma_is_inited = 0;
+ u32 ucr1, ucr2, ucr4;
retval = clk_prepare_enable(sport->clk_per);
if (retval)
@@ -1196,104 +1328,106 @@ static int imx_startup(struct uart_port *port)
return retval;
}
- imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
/* disable the DREN bit (Data Ready interrupt enable) before
* requesting IRQs
*/
- temp = readl(sport->port.membase + UCR4);
+ ucr4 = imx_uart_readl(sport, UCR4);
/* set the trigger level for CTS */
- temp &= ~(UCR4_CTSTL_MASK << UCR4_CTSTL_SHF);
- temp |= CTSTL << UCR4_CTSTL_SHF;
+ ucr4 &= ~(UCR4_CTSTL_MASK << UCR4_CTSTL_SHF);
+ ucr4 |= CTSTL << UCR4_CTSTL_SHF;
- writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
+ imx_uart_writel(sport, ucr4 & ~UCR4_DREN, UCR4);
/* Can we enable the DMA support? */
- if (!uart_console(port) && !sport->dma_is_inited)
- imx_uart_dma_init(sport);
+ if (!uart_console(port) && imx_uart_dma_init(sport) == 0)
+ dma_is_inited = 1;
spin_lock_irqsave(&sport->port.lock, flags);
/* Reset fifo's and state machines */
i = 100;
- temp = readl(sport->port.membase + UCR2);
- temp &= ~UCR2_SRST;
- writel(temp, sport->port.membase + UCR2);
+ ucr2 = imx_uart_readl(sport, UCR2);
+ ucr2 &= ~UCR2_SRST;
+ imx_uart_writel(sport, ucr2, UCR2);
- while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
+ while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0))
udelay(1);
/*
* Finally, clear and enable interrupts
*/
- writel(USR1_RTSD | USR1_DTRD, sport->port.membase + USR1);
- writel(USR2_ORE, sport->port.membase + USR2);
-
- if (sport->dma_is_inited && !sport->dma_is_enabled)
- imx_enable_dma(sport);
+ imx_uart_writel(sport, USR1_RTSD | USR1_DTRD, USR1);
+ imx_uart_writel(sport, USR2_ORE, USR2);
- temp = readl(sport->port.membase + UCR1) & ~UCR1_RRDYEN;
- if (!sport->dma_is_enabled)
- temp |= UCR1_RRDYEN;
- temp |= UCR1_UARTEN;
+ ucr1 = imx_uart_readl(sport, UCR1) & ~UCR1_RRDYEN;
+ ucr1 |= UCR1_UARTEN;
if (sport->have_rtscts)
- temp |= UCR1_RTSDEN;
+ ucr1 |= UCR1_RTSDEN;
- writel(temp, sport->port.membase + UCR1);
+ imx_uart_writel(sport, ucr1, UCR1);
- temp = readl(sport->port.membase + UCR4) & ~UCR4_OREN;
+ ucr4 = imx_uart_readl(sport, UCR4) & ~UCR4_OREN;
if (!sport->dma_is_enabled)
- temp |= UCR4_OREN;
- writel(temp, sport->port.membase + UCR4);
+ ucr4 |= UCR4_OREN;
+ imx_uart_writel(sport, ucr4, UCR4);
- temp = readl(sport->port.membase + UCR2) & ~UCR2_ATEN;
- temp |= (UCR2_RXEN | UCR2_TXEN);
+ ucr2 = imx_uart_readl(sport, UCR2) & ~UCR2_ATEN;
+ ucr2 |= (UCR2_RXEN | UCR2_TXEN);
if (!sport->have_rtscts)
- temp |= UCR2_IRTS;
+ ucr2 |= UCR2_IRTS;
/*
* make sure the edge sensitive RTS-irq is disabled,
* we're using RTSD instead.
*/
- if (!is_imx1_uart(sport))
- temp &= ~UCR2_RTSEN;
- writel(temp, sport->port.membase + UCR2);
+ if (!imx_uart_is_imx1(sport))
+ ucr2 &= ~UCR2_RTSEN;
+ imx_uart_writel(sport, ucr2, UCR2);
+
+ if (!imx_uart_is_imx1(sport)) {
+ u32 ucr3;
- if (!is_imx1_uart(sport)) {
- temp = readl(sport->port.membase + UCR3);
+ ucr3 = imx_uart_readl(sport, UCR3);
- temp |= UCR3_DTRDEN | UCR3_RI | UCR3_DCD;
+ ucr3 |= UCR3_DTRDEN | UCR3_RI | UCR3_DCD;
if (sport->dte_mode)
/* disable broken interrupts */
- temp &= ~(UCR3_RI | UCR3_DCD);
+ ucr3 &= ~(UCR3_RI | UCR3_DCD);
- writel(temp, sport->port.membase + UCR3);
+ imx_uart_writel(sport, ucr3, UCR3);
}
/*
* Enable modem status interrupts
*/
- imx_enable_ms(&sport->port);
+ imx_uart_enable_ms(&sport->port);
- /*
- * Start RX DMA immediately instead of waiting for RX FIFO interrupts.
- * In our iMX53 the average delay for the first reception dropped from
- * approximately 35000 microseconds to 1000 microseconds.
- */
- if (sport->dma_is_enabled)
- start_rx_dma(sport);
+ if (dma_is_inited) {
+ imx_uart_enable_dma(sport);
+ imx_uart_start_rx_dma(sport);
+ } else {
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr1 |= UCR1_RRDYEN;
+ imx_uart_writel(sport, ucr1, UCR1);
+
+ ucr2 = imx_uart_readl(sport, UCR2);
+ ucr2 |= UCR2_ATEN;
+ imx_uart_writel(sport, ucr2, UCR2);
+ }
spin_unlock_irqrestore(&sport->port.lock, flags);
return 0;
}
-static void imx_shutdown(struct uart_port *port)
+static void imx_uart_shutdown(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
- unsigned long temp;
unsigned long flags;
+ u32 ucr1, ucr2;
if (sport->dma_is_enabled) {
sport->dma_is_rxing = 0;
@@ -1302,9 +1436,9 @@ static void imx_shutdown(struct uart_port *port)
dmaengine_terminate_sync(sport->dma_chan_rx);
spin_lock_irqsave(&sport->port.lock, flags);
- imx_stop_tx(port);
- imx_stop_rx(port);
- imx_disable_dma(sport);
+ imx_uart_stop_tx(port);
+ imx_uart_stop_rx(port);
+ imx_uart_disable_dma(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
imx_uart_dma_exit(sport);
}
@@ -1312,9 +1446,9 @@ static void imx_shutdown(struct uart_port *port)
mctrl_gpio_disable_ms(sport->gpios);
spin_lock_irqsave(&sport->port.lock, flags);
- temp = readl(sport->port.membase + UCR2);
- temp &= ~(UCR2_TXEN);
- writel(temp, sport->port.membase + UCR2);
+ ucr2 = imx_uart_readl(sport, UCR2);
+ ucr2 &= ~(UCR2_TXEN | UCR2_ATEN);
+ imx_uart_writel(sport, ucr2, UCR2);
spin_unlock_irqrestore(&sport->port.lock, flags);
/*
@@ -1327,21 +1461,22 @@ static void imx_shutdown(struct uart_port *port)
*/
spin_lock_irqsave(&sport->port.lock, flags);
- temp = readl(sport->port.membase + UCR1);
- temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN | UCR1_RXDMAEN | UCR1_ATDMAEN);
- writel(temp, sport->port.membase + UCR1);
+ imx_uart_writel(sport, ucr1, UCR1);
spin_unlock_irqrestore(&sport->port.lock, flags);
clk_disable_unprepare(sport->clk_per);
clk_disable_unprepare(sport->clk_ipg);
}
-static void imx_flush_buffer(struct uart_port *port)
+/* called with port.lock taken and irqs off */
+static void imx_uart_flush_buffer(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
struct scatterlist *sgl = &sport->tx_sgl[0];
- unsigned long temp;
+ u32 ucr2;
int i = 100, ubir, ubmr, uts;
if (!sport->dma_chan_tx)
@@ -1350,11 +1485,13 @@ static void imx_flush_buffer(struct uart_port *port)
sport->tx_bytes = 0;
dmaengine_terminate_all(sport->dma_chan_tx);
if (sport->dma_is_txing) {
+ u32 ucr1;
+
dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents,
DMA_TO_DEVICE);
- temp = readl(sport->port.membase + UCR1);
- temp &= ~UCR1_TDMAEN;
- writel(temp, sport->port.membase + UCR1);
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr1 &= ~UCR1_TXDMAEN;
+ imx_uart_writel(sport, ucr1, UCR1);
sport->dma_is_txing = 0;
}
@@ -1369,33 +1506,33 @@ static void imx_flush_buffer(struct uart_port *port)
* UTXD. UBRC is read only, so only save/restore the other three
* registers.
*/
- ubir = readl(sport->port.membase + UBIR);
- ubmr = readl(sport->port.membase + UBMR);
- uts = readl(sport->port.membase + IMX21_UTS);
+ ubir = imx_uart_readl(sport, UBIR);
+ ubmr = imx_uart_readl(sport, UBMR);
+ uts = imx_uart_readl(sport, IMX21_UTS);
- temp = readl(sport->port.membase + UCR2);
- temp &= ~UCR2_SRST;
- writel(temp, sport->port.membase + UCR2);
+ ucr2 = imx_uart_readl(sport, UCR2);
+ ucr2 &= ~UCR2_SRST;
+ imx_uart_writel(sport, ucr2, UCR2);
- while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
+ while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0))
udelay(1);
/* Restore the registers */
- writel(ubir, sport->port.membase + UBIR);
- writel(ubmr, sport->port.membase + UBMR);
- writel(uts, sport->port.membase + IMX21_UTS);
+ imx_uart_writel(sport, ubir, UBIR);
+ imx_uart_writel(sport, ubmr, UBMR);
+ imx_uart_writel(sport, uts, IMX21_UTS);
}
static void
-imx_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long flags;
- unsigned long ucr2, old_ucr1, old_ucr2;
+ u32 ucr2, old_ucr1, old_ucr2, ufcr;
unsigned int baud, quot;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
- unsigned long div, ufcr;
+ unsigned long div;
unsigned long num, denom;
uint64_t tdiv64;
@@ -1426,11 +1563,11 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
*/
if (port->rs485.flags &
SER_RS485_RTS_AFTER_SEND)
- imx_port_rts_active(sport, &ucr2);
+ imx_uart_rts_active(sport, &ucr2);
else
- imx_port_rts_inactive(sport, &ucr2);
+ imx_uart_rts_inactive(sport, &ucr2);
} else {
- imx_port_rts_auto(sport, &ucr2);
+ imx_uart_rts_auto(sport, &ucr2);
}
} else {
termios->c_cflag &= ~CRTSCTS;
@@ -1438,9 +1575,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
} else if (port->rs485.flags & SER_RS485_ENABLED) {
/* disable transmitter */
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
- imx_port_rts_active(sport, &ucr2);
+ imx_uart_rts_active(sport, &ucr2);
else
- imx_port_rts_inactive(sport, &ucr2);
+ imx_uart_rts_inactive(sport, &ucr2);
}
@@ -1495,17 +1632,18 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
/*
* disable interrupts and drain transmitter
*/
- old_ucr1 = readl(sport->port.membase + UCR1);
- writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
- sport->port.membase + UCR1);
-
- while (!(readl(sport->port.membase + USR2) & USR2_TXDC))
+ old_ucr1 = imx_uart_readl(sport, UCR1);
+ imx_uart_writel(sport,
+ old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
+ UCR1);
+ old_ucr2 = imx_uart_readl(sport, UCR2);
+ imx_uart_writel(sport, old_ucr2 & ~UCR2_ATEN, UCR2);
+
+ while (!(imx_uart_readl(sport, USR2) & USR2_TXDC))
barrier();
/* then, disable everything */
- old_ucr2 = readl(sport->port.membase + UCR2);
- writel(old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN),
- sport->port.membase + UCR2);
+ imx_uart_writel(sport, old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN | UCR2_ATEN), UCR2);
old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN);
/* custom-baudrate handling */
@@ -1531,29 +1669,29 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
num -= 1;
denom -= 1;
- ufcr = readl(sport->port.membase + UFCR);
+ ufcr = imx_uart_readl(sport, UFCR);
ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
- writel(ufcr, sport->port.membase + UFCR);
+ imx_uart_writel(sport, ufcr, UFCR);
- writel(num, sport->port.membase + UBIR);
- writel(denom, sport->port.membase + UBMR);
+ imx_uart_writel(sport, num, UBIR);
+ imx_uart_writel(sport, denom, UBMR);
- if (!is_imx1_uart(sport))
- writel(sport->port.uartclk / div / 1000,
- sport->port.membase + IMX21_ONEMS);
+ if (!imx_uart_is_imx1(sport))
+ imx_uart_writel(sport, sport->port.uartclk / div / 1000,
+ IMX21_ONEMS);
- writel(old_ucr1, sport->port.membase + UCR1);
+ imx_uart_writel(sport, old_ucr1, UCR1);
/* set the parity, stop bits and data size */
- writel(ucr2 | old_ucr2, sport->port.membase + UCR2);
+ imx_uart_writel(sport, ucr2 | old_ucr2, UCR2);
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
- imx_enable_ms(&sport->port);
+ imx_uart_enable_ms(&sport->port);
spin_unlock_irqrestore(&sport->port.lock, flags);
}
-static const char *imx_type(struct uart_port *port)
+static const char *imx_uart_type(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
@@ -1563,7 +1701,7 @@ static const char *imx_type(struct uart_port *port)
/*
* Configure/autoconfigure the port.
*/
-static void imx_config_port(struct uart_port *port, int flags)
+static void imx_uart_config_port(struct uart_port *port, int flags)
{
struct imx_port *sport = (struct imx_port *)port;
@@ -1577,7 +1715,7 @@ static void imx_config_port(struct uart_port *port, int flags)
* even then only between PORT_IMX and PORT_UNKNOWN
*/
static int
-imx_verify_port(struct uart_port *port, struct serial_struct *ser)
+imx_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
{
struct imx_port *sport = (struct imx_port *)port;
int ret = 0;
@@ -1601,11 +1739,11 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
#if defined(CONFIG_CONSOLE_POLL)
-static int imx_poll_init(struct uart_port *port)
+static int imx_uart_poll_init(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long flags;
- unsigned long temp;
+ u32 ucr1, ucr2;
int retval;
retval = clk_prepare_enable(sport->clk_ipg);
@@ -1615,58 +1753,76 @@ static int imx_poll_init(struct uart_port *port)
if (retval)
clk_disable_unprepare(sport->clk_ipg);
- imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
spin_lock_irqsave(&sport->port.lock, flags);
- temp = readl(sport->port.membase + UCR1);
- if (is_imx1_uart(sport))
- temp |= IMX1_UCR1_UARTCLKEN;
- temp |= UCR1_UARTEN | UCR1_RRDYEN;
- temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN);
- writel(temp, sport->port.membase + UCR1);
+ /*
+ * Be careful about the order of enabling bits here. First enable the
+ * receiver (UARTEN + RXEN) and only then the corresponding irqs.
+ * This prevents that a character that already sits in the RX fifo is
+ * triggering an irq but the try to fetch it from there results in an
+ * exception because UARTEN or RXEN is still off.
+ */
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr2 = imx_uart_readl(sport, UCR2);
- temp = readl(sport->port.membase + UCR2);
- temp |= UCR2_RXEN;
- writel(temp, sport->port.membase + UCR2);
+ if (imx_uart_is_imx1(sport))
+ ucr1 |= IMX1_UCR1_UARTCLKEN;
+
+ ucr1 |= UCR1_UARTEN;
+ ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN | UCR1_RRDYEN);
+
+ ucr2 |= UCR2_RXEN;
+ ucr2 &= ~UCR2_ATEN;
+
+ imx_uart_writel(sport, ucr1, UCR1);
+ imx_uart_writel(sport, ucr2, UCR2);
+
+ /* now enable irqs */
+ imx_uart_writel(sport, ucr1 | UCR1_RRDYEN, UCR1);
+ imx_uart_writel(sport, ucr2 | UCR2_ATEN, UCR2);
spin_unlock_irqrestore(&sport->port.lock, flags);
return 0;
}
-static int imx_poll_get_char(struct uart_port *port)
+static int imx_uart_poll_get_char(struct uart_port *port)
{
- if (!(readl_relaxed(port->membase + USR2) & USR2_RDR))
+ struct imx_port *sport = (struct imx_port *)port;
+ if (!(imx_uart_readl(sport, USR2) & USR2_RDR))
return NO_POLL_CHAR;
- return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA;
+ return imx_uart_readl(sport, URXD0) & URXD_RX_DATA;
}
-static void imx_poll_put_char(struct uart_port *port, unsigned char c)
+static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c)
{
+ struct imx_port *sport = (struct imx_port *)port;
unsigned int status;
/* drain */
do {
- status = readl_relaxed(port->membase + USR1);
+ status = imx_uart_readl(sport, USR1);
} while (~status & USR1_TRDY);
/* write */
- writel_relaxed(c, port->membase + URTX0);
+ imx_uart_writel(sport, c, URTX0);
/* flush */
do {
- status = readl_relaxed(port->membase + USR2);
+ status = imx_uart_readl(sport, USR2);
} while (~status & USR2_TXDC);
}
#endif
-static int imx_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485conf)
+/* called with port.lock taken and irqs off or from .probe without locking */
+static int imx_uart_rs485_config(struct uart_port *port,
+ struct serial_rs485 *rs485conf)
{
struct imx_port *sport = (struct imx_port *)port;
- unsigned long temp;
+ u32 ucr2;
/* unimplemented */
rs485conf->delay_rts_before_send = 0;
@@ -1678,70 +1834,67 @@ static int imx_rs485_config(struct uart_port *port,
if (rs485conf->flags & SER_RS485_ENABLED) {
/* disable transmitter */
- temp = readl(sport->port.membase + UCR2);
+ ucr2 = imx_uart_readl(sport, UCR2);
if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
- imx_port_rts_active(sport, &temp);
+ imx_uart_rts_active(sport, &ucr2);
else
- imx_port_rts_inactive(sport, &temp);
- writel(temp, sport->port.membase + UCR2);
+ imx_uart_rts_inactive(sport, &ucr2);
+ imx_uart_writel(sport, ucr2, UCR2);
}
/* Make sure Rx is enabled in case Tx is active with Rx disabled */
if (!(rs485conf->flags & SER_RS485_ENABLED) ||
- rs485conf->flags & SER_RS485_RX_DURING_TX) {
- temp = readl(sport->port.membase + UCR2);
- temp |= UCR2_RXEN;
- writel(temp, sport->port.membase + UCR2);
- }
+ rs485conf->flags & SER_RS485_RX_DURING_TX)
+ imx_uart_start_rx(port);
port->rs485 = *rs485conf;
return 0;
}
-static const struct uart_ops imx_pops = {
- .tx_empty = imx_tx_empty,
- .set_mctrl = imx_set_mctrl,
- .get_mctrl = imx_get_mctrl,
- .stop_tx = imx_stop_tx,
- .start_tx = imx_start_tx,
- .stop_rx = imx_stop_rx,
- .enable_ms = imx_enable_ms,
- .break_ctl = imx_break_ctl,
- .startup = imx_startup,
- .shutdown = imx_shutdown,
- .flush_buffer = imx_flush_buffer,
- .set_termios = imx_set_termios,
- .type = imx_type,
- .config_port = imx_config_port,
- .verify_port = imx_verify_port,
+static const struct uart_ops imx_uart_pops = {
+ .tx_empty = imx_uart_tx_empty,
+ .set_mctrl = imx_uart_set_mctrl,
+ .get_mctrl = imx_uart_get_mctrl,
+ .stop_tx = imx_uart_stop_tx,
+ .start_tx = imx_uart_start_tx,
+ .stop_rx = imx_uart_stop_rx,
+ .enable_ms = imx_uart_enable_ms,
+ .break_ctl = imx_uart_break_ctl,
+ .startup = imx_uart_startup,
+ .shutdown = imx_uart_shutdown,
+ .flush_buffer = imx_uart_flush_buffer,
+ .set_termios = imx_uart_set_termios,
+ .type = imx_uart_type,
+ .config_port = imx_uart_config_port,
+ .verify_port = imx_uart_verify_port,
#if defined(CONFIG_CONSOLE_POLL)
- .poll_init = imx_poll_init,
- .poll_get_char = imx_poll_get_char,
- .poll_put_char = imx_poll_put_char,
+ .poll_init = imx_uart_poll_init,
+ .poll_get_char = imx_uart_poll_get_char,
+ .poll_put_char = imx_uart_poll_put_char,
#endif
};
-static struct imx_port *imx_ports[UART_NR];
+static struct imx_port *imx_uart_ports[UART_NR];
#ifdef CONFIG_SERIAL_IMX_CONSOLE
-static void imx_console_putchar(struct uart_port *port, int ch)
+static void imx_uart_console_putchar(struct uart_port *port, int ch)
{
struct imx_port *sport = (struct imx_port *)port;
- while (readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)
+ while (imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL)
barrier();
- writel(ch, sport->port.membase + URTX0);
+ imx_uart_writel(sport, ch, URTX0);
}
/*
* Interrupts are disabled on entering
*/
static void
-imx_console_write(struct console *co, const char *s, unsigned int count)
+imx_uart_console_write(struct console *co, const char *s, unsigned int count)
{
- struct imx_port *sport = imx_ports[co->index];
+ struct imx_port *sport = imx_uart_ports[co->index];
struct imx_port_ucrs old_ucr;
unsigned int ucr1;
unsigned long flags = 0;
@@ -1767,27 +1920,27 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
/*
* First, save UCR1/2/3 and then disable interrupts
*/
- imx_port_ucrs_save(&sport->port, &old_ucr);
+ imx_uart_ucrs_save(sport, &old_ucr);
ucr1 = old_ucr.ucr1;
- if (is_imx1_uart(sport))
+ if (imx_uart_is_imx1(sport))
ucr1 |= IMX1_UCR1_UARTCLKEN;
ucr1 |= UCR1_UARTEN;
ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN);
- writel(ucr1, sport->port.membase + UCR1);
+ imx_uart_writel(sport, ucr1, UCR1);
- writel(old_ucr.ucr2 | UCR2_TXEN, sport->port.membase + UCR2);
+ imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2);
- uart_console_write(&sport->port, s, count, imx_console_putchar);
+ uart_console_write(&sport->port, s, count, imx_uart_console_putchar);
/*
* Finally, wait for transmitter to become empty
* and restore UCR1/2/3
*/
- while (!(readl(sport->port.membase + USR2) & USR2_TXDC));
+ while (!(imx_uart_readl(sport, USR2) & USR2_TXDC));
- imx_port_ucrs_restore(&sport->port, &old_ucr);
+ imx_uart_ucrs_restore(sport, &old_ucr);
if (locked)
spin_unlock_irqrestore(&sport->port.lock, flags);
@@ -1801,17 +1954,17 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
* try to determine the current setup.
*/
static void __init
-imx_console_get_options(struct imx_port *sport, int *baud,
- int *parity, int *bits)
+imx_uart_console_get_options(struct imx_port *sport, int *baud,
+ int *parity, int *bits)
{
- if (readl(sport->port.membase + UCR1) & UCR1_UARTEN) {
+ if (imx_uart_readl(sport, UCR1) & UCR1_UARTEN) {
/* ok, the port was enabled */
unsigned int ucr2, ubir, ubmr, uartclk;
unsigned int baud_raw;
unsigned int ucfr_rfdiv;
- ucr2 = readl(sport->port.membase + UCR2);
+ ucr2 = imx_uart_readl(sport, UCR2);
*parity = 'n';
if (ucr2 & UCR2_PREN) {
@@ -1826,10 +1979,10 @@ imx_console_get_options(struct imx_port *sport, int *baud,
else
*bits = 7;
- ubir = readl(sport->port.membase + UBIR) & 0xffff;
- ubmr = readl(sport->port.membase + UBMR) & 0xffff;
+ ubir = imx_uart_readl(sport, UBIR) & 0xffff;
+ ubmr = imx_uart_readl(sport, UBMR) & 0xffff;
- ucfr_rfdiv = (readl(sport->port.membase + UFCR) & UFCR_RFDIV) >> 7;
+ ucfr_rfdiv = (imx_uart_readl(sport, UFCR) & UFCR_RFDIV) >> 7;
if (ucfr_rfdiv == 6)
ucfr_rfdiv = 7;
else
@@ -1860,7 +2013,7 @@ imx_console_get_options(struct imx_port *sport, int *baud,
}
static int __init
-imx_console_setup(struct console *co, char *options)
+imx_uart_console_setup(struct console *co, char *options)
{
struct imx_port *sport;
int baud = 9600;
@@ -1874,9 +2027,9 @@ imx_console_setup(struct console *co, char *options)
* if so, search for the first available port that does have
* console support.
*/
- if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports))
+ if (co->index == -1 || co->index >= ARRAY_SIZE(imx_uart_ports))
co->index = 0;
- sport = imx_ports[co->index];
+ sport = imx_uart_ports[co->index];
if (sport == NULL)
return -ENODEV;
@@ -1888,9 +2041,9 @@ imx_console_setup(struct console *co, char *options)
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
- imx_console_get_options(sport, &baud, &parity, &bits);
+ imx_uart_console_get_options(sport, &baud, &parity, &bits);
- imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
@@ -1908,34 +2061,36 @@ error_console:
return retval;
}
-static struct uart_driver imx_reg;
-static struct console imx_console = {
+static struct uart_driver imx_uart_uart_driver;
+static struct console imx_uart_console = {
.name = DEV_NAME,
- .write = imx_console_write,
+ .write = imx_uart_console_write,
.device = uart_console_device,
- .setup = imx_console_setup,
+ .setup = imx_uart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
- .data = &imx_reg,
+ .data = &imx_uart_uart_driver,
};
-#define IMX_CONSOLE &imx_console
+#define IMX_CONSOLE &imx_uart_console
#ifdef CONFIG_OF
-static void imx_console_early_putchar(struct uart_port *port, int ch)
+static void imx_uart_console_early_putchar(struct uart_port *port, int ch)
{
- while (readl_relaxed(port->membase + IMX21_UTS) & UTS_TXFULL)
+ struct imx_port *sport = (struct imx_port *)port;
+
+ while (imx_uart_readl(sport, IMX21_UTS) & UTS_TXFULL)
cpu_relax();
- writel_relaxed(ch, port->membase + URTX0);
+ imx_uart_writel(sport, ch, URTX0);
}
-static void imx_console_early_write(struct console *con, const char *s,
- unsigned count)
+static void imx_uart_console_early_write(struct console *con, const char *s,
+ unsigned count)
{
struct earlycon_device *dev = con->data;
- uart_console_write(&dev->port, s, count, imx_console_early_putchar);
+ uart_console_write(&dev->port, s, count, imx_uart_console_early_putchar);
}
static int __init
@@ -1944,7 +2099,7 @@ imx_console_early_setup(struct earlycon_device *dev, const char *opt)
if (!dev->port.membase)
return -ENODEV;
- dev->con->write = imx_console_early_write;
+ dev->con->write = imx_uart_console_early_write;
return 0;
}
@@ -1956,13 +2111,13 @@ OF_EARLYCON_DECLARE(ec_imx21, "fsl,imx21-uart", imx_console_early_setup);
#define IMX_CONSOLE NULL
#endif
-static struct uart_driver imx_reg = {
+static struct uart_driver imx_uart_uart_driver = {
.owner = THIS_MODULE,
.driver_name = DRIVER_NAME,
.dev_name = DEV_NAME,
.major = SERIAL_IMX_MAJOR,
.minor = MINOR_START,
- .nr = ARRAY_SIZE(imx_ports),
+ .nr = ARRAY_SIZE(imx_uart_ports),
.cons = IMX_CONSOLE,
};
@@ -1971,8 +2126,8 @@ static struct uart_driver imx_reg = {
* This function returns 1 iff pdev isn't a device instatiated by dt, 0 iff it
* could successfully get all information from dt or a negative errno.
*/
-static int serial_imx_probe_dt(struct imx_port *sport,
- struct platform_device *pdev)
+static int imx_uart_probe_dt(struct imx_port *sport,
+ struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
int ret;
@@ -2002,15 +2157,15 @@ static int serial_imx_probe_dt(struct imx_port *sport,
return 0;
}
#else
-static inline int serial_imx_probe_dt(struct imx_port *sport,
- struct platform_device *pdev)
+static inline int imx_uart_probe_dt(struct imx_port *sport,
+ struct platform_device *pdev)
{
return 1;
}
#endif
-static void serial_imx_probe_pdata(struct imx_port *sport,
- struct platform_device *pdev)
+static void imx_uart_probe_pdata(struct imx_port *sport,
+ struct platform_device *pdev)
{
struct imxuart_platform_data *pdata = dev_get_platdata(&pdev->dev);
@@ -2024,11 +2179,12 @@ static void serial_imx_probe_pdata(struct imx_port *sport,
sport->have_rtscts = 1;
}
-static int serial_imx_probe(struct platform_device *pdev)
+static int imx_uart_probe(struct platform_device *pdev)
{
struct imx_port *sport;
void __iomem *base;
- int ret = 0, reg;
+ int ret = 0;
+ u32 ucr1;
struct resource *res;
int txirq, rxirq, rtsirq;
@@ -2036,12 +2192,18 @@ static int serial_imx_probe(struct platform_device *pdev)
if (!sport)
return -ENOMEM;
- ret = serial_imx_probe_dt(sport, pdev);
+ ret = imx_uart_probe_dt(sport, pdev);
if (ret > 0)
- serial_imx_probe_pdata(sport, pdev);
+ imx_uart_probe_pdata(sport, pdev);
else if (ret < 0)
return ret;
+ if (sport->port.line >= ARRAY_SIZE(imx_uart_ports)) {
+ dev_err(&pdev->dev, "serial%d out of range\n",
+ sport->port.line);
+ return -EINVAL;
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
@@ -2058,10 +2220,10 @@ static int serial_imx_probe(struct platform_device *pdev)
sport->port.iotype = UPIO_MEM;
sport->port.irq = rxirq;
sport->port.fifosize = 32;
- sport->port.ops = &imx_pops;
- sport->port.rs485_config = imx_rs485_config;
+ sport->port.ops = &imx_uart_pops;
+ sport->port.rs485_config = imx_uart_rs485_config;
sport->port.flags = UPF_BOOT_AUTOCONF;
- timer_setup(&sport->timer, imx_timeout, 0);
+ timer_setup(&sport->timer, imx_uart_timeout, 0);
sport->gpios = mctrl_gpio_init(&sport->port, 0);
if (IS_ERR(sport->gpios))
@@ -2090,49 +2252,56 @@ static int serial_imx_probe(struct platform_device *pdev)
return ret;
}
+ /* initialize shadow register values */
+ sport->ucr1 = readl(sport->port.membase + UCR1);
+ sport->ucr2 = readl(sport->port.membase + UCR2);
+ sport->ucr3 = readl(sport->port.membase + UCR3);
+ sport->ucr4 = readl(sport->port.membase + UCR4);
+ sport->ufcr = readl(sport->port.membase + UFCR);
+
uart_get_rs485_mode(&pdev->dev, &sport->port.rs485);
if (sport->port.rs485.flags & SER_RS485_ENABLED &&
(!sport->have_rtscts && !sport->have_rtsgpio))
dev_err(&pdev->dev, "no RTS control, disabling rs485\n");
- imx_rs485_config(&sport->port, &sport->port.rs485);
+ imx_uart_rs485_config(&sport->port, &sport->port.rs485);
/* Disable interrupts before requesting them */
- reg = readl_relaxed(sport->port.membase + UCR1);
- reg &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN |
+ ucr1 = imx_uart_readl(sport, UCR1);
+ ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN |
UCR1_TXMPTYEN | UCR1_RTSDEN);
- writel_relaxed(reg, sport->port.membase + UCR1);
+ imx_uart_writel(sport, ucr1, UCR1);
- if (!is_imx1_uart(sport) && sport->dte_mode) {
+ if (!imx_uart_is_imx1(sport) && sport->dte_mode) {
/*
* The DCEDTE bit changes the direction of DSR, DCD, DTR and RI
* and influences if UCR3_RI and UCR3_DCD changes the level of RI
* and DCD (when they are outputs) or enables the respective
* irqs. So set this bit early, i.e. before requesting irqs.
*/
- reg = readl(sport->port.membase + UFCR);
- if (!(reg & UFCR_DCEDTE))
- writel(reg | UFCR_DCEDTE, sport->port.membase + UFCR);
+ u32 ufcr = imx_uart_readl(sport, UFCR);
+ if (!(ufcr & UFCR_DCEDTE))
+ imx_uart_writel(sport, ufcr | UFCR_DCEDTE, UFCR);
/*
* Disable UCR3_RI and UCR3_DCD irqs. They are also not
* enabled later because they cannot be cleared
* (confirmed on i.MX25) which makes them unusable.
*/
- writel(IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP | UCR3_DSR,
- sport->port.membase + UCR3);
+ imx_uart_writel(sport,
+ IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP | UCR3_DSR,
+ UCR3);
} else {
- unsigned long ucr3 = UCR3_DSR;
-
- reg = readl(sport->port.membase + UFCR);
- if (reg & UFCR_DCEDTE)
- writel(reg & ~UFCR_DCEDTE, sport->port.membase + UFCR);
+ u32 ucr3 = UCR3_DSR;
+ u32 ufcr = imx_uart_readl(sport, UFCR);
+ if (ufcr & UFCR_DCEDTE)
+ imx_uart_writel(sport, ufcr & ~UFCR_DCEDTE, UFCR);
- if (!is_imx1_uart(sport))
+ if (!imx_uart_is_imx1(sport))
ucr3 |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP;
- writel(ucr3, sport->port.membase + UCR3);
+ imx_uart_writel(sport, ucr3, UCR3);
}
clk_disable_unprepare(sport->clk_ipg);
@@ -2142,7 +2311,7 @@ static int serial_imx_probe(struct platform_device *pdev)
* chips only have one interrupt.
*/
if (txirq > 0) {
- ret = devm_request_irq(&pdev->dev, rxirq, imx_rxint, 0,
+ ret = devm_request_irq(&pdev->dev, rxirq, imx_uart_rxint, 0,
dev_name(&pdev->dev), sport);
if (ret) {
dev_err(&pdev->dev, "failed to request rx irq: %d\n",
@@ -2150,7 +2319,7 @@ static int serial_imx_probe(struct platform_device *pdev)
return ret;
}
- ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0,
+ ret = devm_request_irq(&pdev->dev, txirq, imx_uart_txint, 0,
dev_name(&pdev->dev), sport);
if (ret) {
dev_err(&pdev->dev, "failed to request tx irq: %d\n",
@@ -2158,7 +2327,7 @@ static int serial_imx_probe(struct platform_device *pdev)
return ret;
}
} else {
- ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0,
+ ret = devm_request_irq(&pdev->dev, rxirq, imx_uart_int, 0,
dev_name(&pdev->dev), sport);
if (ret) {
dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
@@ -2166,90 +2335,90 @@ static int serial_imx_probe(struct platform_device *pdev)
}
}
- imx_ports[sport->port.line] = sport;
+ imx_uart_ports[sport->port.line] = sport;
platform_set_drvdata(pdev, sport);
- return uart_add_one_port(&imx_reg, &sport->port);
+ return uart_add_one_port(&imx_uart_uart_driver, &sport->port);
}
-static int serial_imx_remove(struct platform_device *pdev)
+static int imx_uart_remove(struct platform_device *pdev)
{
struct imx_port *sport = platform_get_drvdata(pdev);
- return uart_remove_one_port(&imx_reg, &sport->port);
+ return uart_remove_one_port(&imx_uart_uart_driver, &sport->port);
}
-static void serial_imx_restore_context(struct imx_port *sport)
+static void imx_uart_restore_context(struct imx_port *sport)
{
if (!sport->context_saved)
return;
- writel(sport->saved_reg[4], sport->port.membase + UFCR);
- writel(sport->saved_reg[5], sport->port.membase + UESC);
- writel(sport->saved_reg[6], sport->port.membase + UTIM);
- writel(sport->saved_reg[7], sport->port.membase + UBIR);
- writel(sport->saved_reg[8], sport->port.membase + UBMR);
- writel(sport->saved_reg[9], sport->port.membase + IMX21_UTS);
- writel(sport->saved_reg[0], sport->port.membase + UCR1);
- writel(sport->saved_reg[1] | UCR2_SRST, sport->port.membase + UCR2);
- writel(sport->saved_reg[2], sport->port.membase + UCR3);
- writel(sport->saved_reg[3], sport->port.membase + UCR4);
+ imx_uart_writel(sport, sport->saved_reg[4], UFCR);
+ imx_uart_writel(sport, sport->saved_reg[5], UESC);
+ imx_uart_writel(sport, sport->saved_reg[6], UTIM);
+ imx_uart_writel(sport, sport->saved_reg[7], UBIR);
+ imx_uart_writel(sport, sport->saved_reg[8], UBMR);
+ imx_uart_writel(sport, sport->saved_reg[9], IMX21_UTS);
+ imx_uart_writel(sport, sport->saved_reg[0], UCR1);
+ imx_uart_writel(sport, sport->saved_reg[1] | UCR2_SRST, UCR2);
+ imx_uart_writel(sport, sport->saved_reg[2], UCR3);
+ imx_uart_writel(sport, sport->saved_reg[3], UCR4);
sport->context_saved = false;
}
-static void serial_imx_save_context(struct imx_port *sport)
+static void imx_uart_save_context(struct imx_port *sport)
{
/* Save necessary regs */
- sport->saved_reg[0] = readl(sport->port.membase + UCR1);
- sport->saved_reg[1] = readl(sport->port.membase + UCR2);
- sport->saved_reg[2] = readl(sport->port.membase + UCR3);
- sport->saved_reg[3] = readl(sport->port.membase + UCR4);
- sport->saved_reg[4] = readl(sport->port.membase + UFCR);
- sport->saved_reg[5] = readl(sport->port.membase + UESC);
- sport->saved_reg[6] = readl(sport->port.membase + UTIM);
- sport->saved_reg[7] = readl(sport->port.membase + UBIR);
- sport->saved_reg[8] = readl(sport->port.membase + UBMR);
- sport->saved_reg[9] = readl(sport->port.membase + IMX21_UTS);
+ sport->saved_reg[0] = imx_uart_readl(sport, UCR1);
+ sport->saved_reg[1] = imx_uart_readl(sport, UCR2);
+ sport->saved_reg[2] = imx_uart_readl(sport, UCR3);
+ sport->saved_reg[3] = imx_uart_readl(sport, UCR4);
+ sport->saved_reg[4] = imx_uart_readl(sport, UFCR);
+ sport->saved_reg[5] = imx_uart_readl(sport, UESC);
+ sport->saved_reg[6] = imx_uart_readl(sport, UTIM);
+ sport->saved_reg[7] = imx_uart_readl(sport, UBIR);
+ sport->saved_reg[8] = imx_uart_readl(sport, UBMR);
+ sport->saved_reg[9] = imx_uart_readl(sport, IMX21_UTS);
sport->context_saved = true;
}
-static void serial_imx_enable_wakeup(struct imx_port *sport, bool on)
+static void imx_uart_enable_wakeup(struct imx_port *sport, bool on)
{
- unsigned int val;
+ u32 ucr3;
- val = readl(sport->port.membase + UCR3);
+ ucr3 = imx_uart_readl(sport, UCR3);
if (on) {
- writel(USR1_AWAKE, sport->port.membase + USR1);
- val |= UCR3_AWAKEN;
+ imx_uart_writel(sport, USR1_AWAKE, USR1);
+ ucr3 |= UCR3_AWAKEN;
+ } else {
+ ucr3 &= ~UCR3_AWAKEN;
}
- else
- val &= ~UCR3_AWAKEN;
- writel(val, sport->port.membase + UCR3);
+ imx_uart_writel(sport, ucr3, UCR3);
if (sport->have_rtscts) {
- val = readl(sport->port.membase + UCR1);
+ u32 ucr1 = imx_uart_readl(sport, UCR1);
if (on)
- val |= UCR1_RTSDEN;
+ ucr1 |= UCR1_RTSDEN;
else
- val &= ~UCR1_RTSDEN;
- writel(val, sport->port.membase + UCR1);
+ ucr1 &= ~UCR1_RTSDEN;
+ imx_uart_writel(sport, ucr1, UCR1);
}
}
-static int imx_serial_port_suspend_noirq(struct device *dev)
+static int imx_uart_suspend_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
- serial_imx_save_context(sport);
+ imx_uart_save_context(sport);
clk_disable(sport->clk_ipg);
return 0;
}
-static int imx_serial_port_resume_noirq(struct device *dev)
+static int imx_uart_resume_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
@@ -2259,18 +2428,18 @@ static int imx_serial_port_resume_noirq(struct device *dev)
if (ret)
return ret;
- serial_imx_restore_context(sport);
+ imx_uart_restore_context(sport);
return 0;
}
-static int imx_serial_port_suspend(struct device *dev)
+static int imx_uart_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
int ret;
- uart_suspend_port(&imx_reg, &sport->port);
+ uart_suspend_port(&imx_uart_uart_driver, &sport->port);
disable_irq(sport->port.irq);
ret = clk_prepare_enable(sport->clk_ipg);
@@ -2278,20 +2447,20 @@ static int imx_serial_port_suspend(struct device *dev)
return ret;
/* enable wakeup from i.MX UART */
- serial_imx_enable_wakeup(sport, true);
+ imx_uart_enable_wakeup(sport, true);
return 0;
}
-static int imx_serial_port_resume(struct device *dev)
+static int imx_uart_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
/* disable wakeup from i.MX UART */
- serial_imx_enable_wakeup(sport, false);
+ imx_uart_enable_wakeup(sport, false);
- uart_resume_port(&imx_reg, &sport->port);
+ uart_resume_port(&imx_uart_uart_driver, &sport->port);
enable_irq(sport->port.irq);
clk_disable_unprepare(sport->clk_ipg);
@@ -2299,74 +2468,74 @@ static int imx_serial_port_resume(struct device *dev)
return 0;
}
-static int imx_serial_port_freeze(struct device *dev)
+static int imx_uart_freeze(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
- uart_suspend_port(&imx_reg, &sport->port);
+ uart_suspend_port(&imx_uart_uart_driver, &sport->port);
return clk_prepare_enable(sport->clk_ipg);
}
-static int imx_serial_port_thaw(struct device *dev)
+static int imx_uart_thaw(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
- uart_resume_port(&imx_reg, &sport->port);
+ uart_resume_port(&imx_uart_uart_driver, &sport->port);
clk_disable_unprepare(sport->clk_ipg);
return 0;
}
-static const struct dev_pm_ops imx_serial_port_pm_ops = {
- .suspend_noirq = imx_serial_port_suspend_noirq,
- .resume_noirq = imx_serial_port_resume_noirq,
- .freeze_noirq = imx_serial_port_suspend_noirq,
- .restore_noirq = imx_serial_port_resume_noirq,
- .suspend = imx_serial_port_suspend,
- .resume = imx_serial_port_resume,
- .freeze = imx_serial_port_freeze,
- .thaw = imx_serial_port_thaw,
- .restore = imx_serial_port_thaw,
+static const struct dev_pm_ops imx_uart_pm_ops = {
+ .suspend_noirq = imx_uart_suspend_noirq,
+ .resume_noirq = imx_uart_resume_noirq,
+ .freeze_noirq = imx_uart_suspend_noirq,
+ .restore_noirq = imx_uart_resume_noirq,
+ .suspend = imx_uart_suspend,
+ .resume = imx_uart_resume,
+ .freeze = imx_uart_freeze,
+ .thaw = imx_uart_thaw,
+ .restore = imx_uart_thaw,
};
-static struct platform_driver serial_imx_driver = {
- .probe = serial_imx_probe,
- .remove = serial_imx_remove,
+static struct platform_driver imx_uart_platform_driver = {
+ .probe = imx_uart_probe,
+ .remove = imx_uart_remove,
- .id_table = imx_uart_devtype,
- .driver = {
- .name = "imx-uart",
+ .id_table = imx_uart_devtype,
+ .driver = {
+ .name = "imx-uart",
.of_match_table = imx_uart_dt_ids,
- .pm = &imx_serial_port_pm_ops,
+ .pm = &imx_uart_pm_ops,
},
};
-static int __init imx_serial_init(void)
+static int __init imx_uart_init(void)
{
- int ret = uart_register_driver(&imx_reg);
+ int ret = uart_register_driver(&imx_uart_uart_driver);
if (ret)
return ret;
- ret = platform_driver_register(&serial_imx_driver);
+ ret = platform_driver_register(&imx_uart_platform_driver);
if (ret != 0)
- uart_unregister_driver(&imx_reg);
+ uart_unregister_driver(&imx_uart_uart_driver);
return ret;
}
-static void __exit imx_serial_exit(void)
+static void __exit imx_uart_exit(void)
{
- platform_driver_unregister(&serial_imx_driver);
- uart_unregister_driver(&imx_reg);
+ platform_driver_unregister(&imx_uart_platform_driver);
+ uart_unregister_driver(&imx_uart_uart_driver);
}
-module_init(imx_serial_init);
-module_exit(imx_serial_exit);
+module_init(imx_uart_init);
+module_exit(imx_uart_exit);
MODULE_AUTHOR("Sascha Hauer");
MODULE_DESCRIPTION("IMX generic serial port driver");
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 39f635812077..efe55a1a0615 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1318,7 +1318,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
/* Setup GPIO cotroller */
s->gpio.owner = THIS_MODULE;
s->gpio.parent = dev;
- s->gpio.label = dev_name(dev);
+ s->gpio.label = devtype->name;
s->gpio.direction_input = max310x_gpio_direction_input;
s->gpio.get = max310x_gpio_get;
s->gpio.direction_output= max310x_gpio_direction_output;
diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index a100e98259d7..750e5645dc85 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -65,7 +65,7 @@
#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\
+#define STAT_BRK_ERR (STAT_BRK_DET | STAT_FRM_ERR \
| STAT_PAR_ERR | STAT_OVR_ERR)
#define UART_BRDV 0x10
@@ -618,7 +618,7 @@ 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);
+ (val & STAT_TX_RDY(port)), 1, 10000);
}
static void mvebu_uart_console_putchar(struct uart_port *port, int ch)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 079dc47aa142..76aa289652f7 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -1663,6 +1663,10 @@ static int mxs_auart_probe(struct platform_device *pdev)
s->port.line = pdev->id < 0 ? 0 : pdev->id;
else if (ret < 0)
return ret;
+ if (s->port.line >= ARRAY_SIZE(auart_port)) {
+ dev_err(&pdev->dev, "serial%d out of range\n", s->port.line);
+ return -EINVAL;
+ }
if (of_id) {
pdev->id_entry = of_id->data;
@@ -1674,8 +1678,10 @@ static int mxs_auart_probe(struct platform_device *pdev)
return ret;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r)
- return -ENXIO;
+ if (!r) {
+ ret = -ENXIO;
+ goto out_disable_clks;
+ }
s->port.mapbase = r->start;
s->port.membase = ioremap(r->start, resource_size(r));
@@ -1690,21 +1696,23 @@ static int mxs_auart_probe(struct platform_device *pdev)
s->mctrl_prev = 0;
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
+ if (irq < 0) {
+ ret = irq;
+ goto out_disable_clks;
+ }
s->port.irq = irq;
ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
dev_name(&pdev->dev), s);
if (ret)
- return ret;
+ goto out_disable_clks;
platform_set_drvdata(pdev, s);
ret = mxs_auart_init_gpios(s, &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize GPIOs.\n");
- return ret;
+ goto out_disable_clks;
}
/*
@@ -1712,7 +1720,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
*/
ret = mxs_auart_request_gpio_irq(s);
if (ret)
- return ret;
+ goto out_disable_clks;
auart_port[s->port.line] = s;
@@ -1720,7 +1728,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
ret = uart_add_one_port(&auart_driver, &s->port);
if (ret)
- goto out_disable_clks_free_qpio_irq;
+ goto out_free_qpio_irq;
/* ASM9260 don't have version reg */
if (is_asm9260_auart(s)) {
@@ -1734,13 +1742,15 @@ static int mxs_auart_probe(struct platform_device *pdev)
return 0;
-out_disable_clks_free_qpio_irq:
- if (s->clk)
- clk_disable_unprepare(s->clk_ahb);
- if (s->clk_ahb)
- clk_disable_unprepare(s->clk_ahb);
+out_free_qpio_irq:
mxs_auart_free_gpio_irq(s);
auart_port[pdev->id] = NULL;
+
+out_disable_clks:
+ if (is_asm9260_auart(s)) {
+ clk_disable_unprepare(s->clk);
+ clk_disable_unprepare(s->clk_ahb);
+ }
return ret;
}
@@ -1751,6 +1761,10 @@ static int mxs_auart_remove(struct platform_device *pdev)
uart_remove_one_port(&auart_driver, &s->port);
auart_port[pdev->id] = NULL;
mxs_auart_free_gpio_irq(s);
+ if (is_asm9260_auart(s)) {
+ clk_disable_unprepare(s->clk);
+ clk_disable_unprepare(s->clk_ahb);
+ }
return 0;
}
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index baf552944d56..eda3c7710d6a 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -885,6 +885,10 @@ static int serial_pxa_probe(struct platform_device *dev)
sport->port.line = dev->id;
else if (ret < 0)
goto err_clk;
+ if (sport->port.line >= ARRAY_SIZE(serial_pxa_ports)) {
+ dev_err(&dev->dev, "serial%d out of range\n", sport->port.line);
+ return -EINVAL;
+ }
snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1);
sport->port.membase = ioremap(mmres->start, resource_size(mmres));
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
new file mode 100644
index 000000000000..65ff669373d4
--- /dev/null
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -0,0 +1,1158 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/qcom-geni-se.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+/* UART specific GENI registers */
+#define SE_UART_TX_TRANS_CFG 0x25c
+#define SE_UART_TX_WORD_LEN 0x268
+#define SE_UART_TX_STOP_BIT_LEN 0x26c
+#define SE_UART_TX_TRANS_LEN 0x270
+#define SE_UART_RX_TRANS_CFG 0x280
+#define SE_UART_RX_WORD_LEN 0x28c
+#define SE_UART_RX_STALE_CNT 0x294
+#define SE_UART_TX_PARITY_CFG 0x2a4
+#define SE_UART_RX_PARITY_CFG 0x2a8
+
+/* SE_UART_TRANS_CFG */
+#define UART_TX_PAR_EN BIT(0)
+#define UART_CTS_MASK BIT(1)
+
+/* SE_UART_TX_WORD_LEN */
+#define TX_WORD_LEN_MSK GENMASK(9, 0)
+
+/* SE_UART_TX_STOP_BIT_LEN */
+#define TX_STOP_BIT_LEN_MSK GENMASK(23, 0)
+#define TX_STOP_BIT_LEN_1 0
+#define TX_STOP_BIT_LEN_1_5 1
+#define TX_STOP_BIT_LEN_2 2
+
+/* SE_UART_TX_TRANS_LEN */
+#define TX_TRANS_LEN_MSK GENMASK(23, 0)
+
+/* SE_UART_RX_TRANS_CFG */
+#define UART_RX_INS_STATUS_BIT BIT(2)
+#define UART_RX_PAR_EN BIT(3)
+
+/* SE_UART_RX_WORD_LEN */
+#define RX_WORD_LEN_MASK GENMASK(9, 0)
+
+/* SE_UART_RX_STALE_CNT */
+#define RX_STALE_CNT GENMASK(23, 0)
+
+/* SE_UART_TX_PARITY_CFG/RX_PARITY_CFG */
+#define PAR_CALC_EN BIT(0)
+#define PAR_MODE_MSK GENMASK(2, 1)
+#define PAR_MODE_SHFT 1
+#define PAR_EVEN 0x00
+#define PAR_ODD 0x01
+#define PAR_SPACE 0x10
+#define PAR_MARK 0x11
+
+/* UART M_CMD OP codes */
+#define UART_START_TX 0x1
+#define UART_START_BREAK 0x4
+#define UART_STOP_BREAK 0x5
+/* UART S_CMD OP codes */
+#define UART_START_READ 0x1
+#define UART_PARAM 0x1
+
+#define UART_OVERSAMPLING 32
+#define STALE_TIMEOUT 16
+#define DEFAULT_BITS_PER_CHAR 10
+#define GENI_UART_CONS_PORTS 1
+#define DEF_FIFO_DEPTH_WORDS 16
+#define DEF_TX_WM 2
+#define DEF_FIFO_WIDTH_BITS 32
+#define UART_CONSOLE_RX_WM 2
+
+#ifdef CONFIG_CONSOLE_POLL
+#define RX_BYTES_PW 1
+#else
+#define RX_BYTES_PW 4
+#endif
+
+struct qcom_geni_serial_port {
+ struct uart_port uport;
+ struct geni_se se;
+ char name[20];
+ u32 tx_fifo_depth;
+ u32 tx_fifo_width;
+ u32 rx_fifo_depth;
+ u32 tx_wm;
+ u32 rx_wm;
+ u32 rx_rfr;
+ enum geni_se_xfer_mode xfer_mode;
+ bool setup;
+ int (*handle_rx)(struct uart_port *uport, u32 bytes, bool drop);
+ unsigned int xmit_size;
+ unsigned int baud;
+ unsigned int tx_bytes_pw;
+ unsigned int rx_bytes_pw;
+ bool brk;
+};
+
+static const struct uart_ops qcom_geni_serial_pops;
+static struct uart_driver qcom_geni_console_driver;
+static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop);
+static unsigned int qcom_geni_serial_tx_empty(struct uart_port *port);
+static void qcom_geni_serial_stop_rx(struct uart_port *uport);
+
+static const unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
+ 32000000, 48000000, 64000000, 80000000,
+ 96000000, 100000000};
+
+#define to_dev_port(ptr, member) \
+ container_of(ptr, struct qcom_geni_serial_port, member)
+
+static struct qcom_geni_serial_port qcom_geni_console_port;
+
+static int qcom_geni_serial_request_port(struct uart_port *uport)
+{
+ struct platform_device *pdev = to_platform_device(uport->dev);
+ struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ uport->membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(uport->membase))
+ return PTR_ERR(uport->membase);
+ port->se.base = uport->membase;
+ return 0;
+}
+
+static void qcom_geni_serial_config_port(struct uart_port *uport, int cfg_flags)
+{
+ if (cfg_flags & UART_CONFIG_TYPE) {
+ uport->type = PORT_MSM;
+ qcom_geni_serial_request_port(uport);
+ }
+}
+
+static unsigned int qcom_geni_cons_get_mctrl(struct uart_port *uport)
+{
+ return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS;
+}
+
+static void qcom_geni_cons_set_mctrl(struct uart_port *uport,
+ unsigned int mctrl)
+{
+}
+
+static const char *qcom_geni_serial_get_type(struct uart_port *uport)
+{
+ return "MSM";
+}
+
+static struct qcom_geni_serial_port *get_port_from_line(int line)
+{
+ if (line < 0 || line >= GENI_UART_CONS_PORTS)
+ return ERR_PTR(-ENXIO);
+ return &qcom_geni_console_port;
+}
+
+static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
+ int offset, int field, bool set)
+{
+ u32 reg;
+ struct qcom_geni_serial_port *port;
+ unsigned int baud;
+ unsigned int fifo_bits;
+ unsigned long timeout_us = 20000;
+
+ /* Ensure polling is not re-ordered before the prior writes/reads */
+ mb();
+
+ if (uport->private_data) {
+ port = to_dev_port(uport, uport);
+ baud = port->baud;
+ if (!baud)
+ baud = 115200;
+ fifo_bits = port->tx_fifo_depth * port->tx_fifo_width;
+ /*
+ * Total polling iterations based on FIFO worth of bytes to be
+ * sent at current baud. Add a little fluff to the wait.
+ */
+ timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500;
+ }
+
+ return !readl_poll_timeout_atomic(uport->membase + offset, reg,
+ (bool)(reg & field) == set, 10, timeout_us);
+}
+
+static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size)
+{
+ u32 m_cmd;
+
+ writel_relaxed(xmit_size, uport->membase + SE_UART_TX_TRANS_LEN);
+ m_cmd = UART_START_TX << M_OPCODE_SHFT;
+ writel(m_cmd, uport->membase + SE_GENI_M_CMD0);
+}
+
+static void qcom_geni_serial_poll_tx_done(struct uart_port *uport)
+{
+ int done;
+ u32 irq_clear = M_CMD_DONE_EN;
+
+ done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_DONE_EN, true);
+ if (!done) {
+ writel_relaxed(M_GENI_CMD_ABORT, uport->membase +
+ SE_GENI_M_CMD_CTRL_REG);
+ irq_clear |= M_CMD_ABORT_EN;
+ qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_ABORT_EN, true);
+ }
+ writel_relaxed(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR);
+}
+
+static void qcom_geni_serial_abort_rx(struct uart_port *uport)
+{
+ u32 irq_clear = S_CMD_DONE_EN | S_CMD_ABORT_EN;
+
+ writel(S_GENI_CMD_ABORT, uport->membase + SE_GENI_S_CMD_CTRL_REG);
+ qcom_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG,
+ S_GENI_CMD_ABORT, false);
+ writel_relaxed(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR);
+ writel_relaxed(FORCE_DEFAULT, uport->membase + GENI_FORCE_DEFAULT_REG);
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int qcom_geni_serial_get_char(struct uart_port *uport)
+{
+ u32 rx_fifo;
+ u32 status;
+
+ status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS);
+ writel_relaxed(status, uport->membase + SE_GENI_M_IRQ_CLEAR);
+
+ status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS);
+ writel_relaxed(status, uport->membase + SE_GENI_S_IRQ_CLEAR);
+
+ /*
+ * Ensure the writes to clear interrupts is not re-ordered after
+ * reading the data.
+ */
+ mb();
+
+ status = readl_relaxed(uport->membase + SE_GENI_RX_FIFO_STATUS);
+ if (!(status & RX_FIFO_WC_MSK))
+ return NO_POLL_CHAR;
+
+ rx_fifo = readl(uport->membase + SE_GENI_RX_FIFOn);
+ return rx_fifo & 0xff;
+}
+
+static void qcom_geni_serial_poll_put_char(struct uart_port *uport,
+ unsigned char c)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+
+ writel_relaxed(port->tx_wm, uport->membase + SE_GENI_TX_WATERMARK_REG);
+ qcom_geni_serial_setup_tx(uport, 1);
+ WARN_ON(!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_TX_FIFO_WATERMARK_EN, true));
+ writel_relaxed(c, uport->membase + SE_GENI_TX_FIFOn);
+ writel_relaxed(M_TX_FIFO_WATERMARK_EN, uport->membase +
+ SE_GENI_M_IRQ_CLEAR);
+ qcom_geni_serial_poll_tx_done(uport);
+}
+#endif
+
+#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
+static void qcom_geni_serial_wr_char(struct uart_port *uport, int ch)
+{
+ writel_relaxed(ch, uport->membase + SE_GENI_TX_FIFOn);
+}
+
+static void
+__qcom_geni_serial_console_write(struct uart_port *uport, const char *s,
+ unsigned int count)
+{
+ int i;
+ u32 bytes_to_send = count;
+
+ for (i = 0; i < count; i++) {
+ if (s[i] == '\n')
+ bytes_to_send++;
+ }
+
+ writel_relaxed(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG);
+ qcom_geni_serial_setup_tx(uport, bytes_to_send);
+ for (i = 0; i < count; ) {
+ size_t chars_to_write = 0;
+ size_t avail = DEF_FIFO_DEPTH_WORDS - DEF_TX_WM;
+
+ /*
+ * If the WM bit never set, then the Tx state machine is not
+ * in a valid state, so break, cancel/abort any existing
+ * command. Unfortunately the current data being written is
+ * lost.
+ */
+ if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_TX_FIFO_WATERMARK_EN, true))
+ break;
+ chars_to_write = min_t(size_t, (size_t)(count - i), avail / 2);
+ uart_console_write(uport, s + i, chars_to_write,
+ qcom_geni_serial_wr_char);
+ writel_relaxed(M_TX_FIFO_WATERMARK_EN, uport->membase +
+ SE_GENI_M_IRQ_CLEAR);
+ i += chars_to_write;
+ }
+ qcom_geni_serial_poll_tx_done(uport);
+}
+
+static void qcom_geni_serial_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_port *uport;
+ struct qcom_geni_serial_port *port;
+ bool locked = true;
+ unsigned long flags;
+
+ WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS);
+
+ port = get_port_from_line(co->index);
+ if (IS_ERR(port))
+ return;
+
+ uport = &port->uport;
+ if (oops_in_progress)
+ locked = spin_trylock_irqsave(&uport->lock, flags);
+ else
+ spin_lock_irqsave(&uport->lock, flags);
+
+ /* Cancel the current write to log the fault */
+ if (!locked) {
+ geni_se_cancel_m_cmd(&port->se);
+ if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_CANCEL_EN, true)) {
+ geni_se_abort_m_cmd(&port->se);
+ qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_ABORT_EN, true);
+ writel_relaxed(M_CMD_ABORT_EN, uport->membase +
+ SE_GENI_M_IRQ_CLEAR);
+ }
+ writel_relaxed(M_CMD_CANCEL_EN, uport->membase +
+ SE_GENI_M_IRQ_CLEAR);
+ }
+
+ __qcom_geni_serial_console_write(uport, s, count);
+ if (locked)
+ spin_unlock_irqrestore(&uport->lock, flags);
+}
+
+static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
+{
+ u32 i;
+ unsigned char buf[sizeof(u32)];
+ struct tty_port *tport;
+ struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+
+ tport = &uport->state->port;
+ for (i = 0; i < bytes; ) {
+ int c;
+ int chunk = min_t(int, bytes - i, port->rx_bytes_pw);
+
+ ioread32_rep(uport->membase + SE_GENI_RX_FIFOn, buf, 1);
+ i += chunk;
+ if (drop)
+ continue;
+
+ for (c = 0; c < chunk; c++) {
+ int sysrq;
+
+ uport->icount.rx++;
+ if (port->brk && buf[c] == 0) {
+ port->brk = false;
+ if (uart_handle_break(uport))
+ continue;
+ }
+
+ sysrq = uart_handle_sysrq_char(uport, buf[c]);
+ if (!sysrq)
+ tty_insert_flip_char(tport, buf[c], TTY_NORMAL);
+ }
+ }
+ if (!drop)
+ tty_flip_buffer_push(tport);
+ return 0;
+}
+#else
+static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
+{
+ return -EPERM;
+}
+
+#endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */
+
+static void qcom_geni_serial_start_tx(struct uart_port *uport)
+{
+ u32 irq_en;
+ struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ u32 status;
+
+ if (port->xfer_mode == GENI_SE_FIFO) {
+ status = readl_relaxed(uport->membase + SE_GENI_STATUS);
+ if (status & M_GENI_CMD_ACTIVE)
+ return;
+
+ if (!qcom_geni_serial_tx_empty(uport))
+ return;
+
+ /*
+ * Ensure writing to IRQ_EN & watermark registers are not
+ * re-ordered before checking the status of the Serial
+ * Engine and TX FIFO
+ */
+ mb();
+
+ irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
+ irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN;
+
+ writel_relaxed(port->tx_wm, uport->membase +
+ SE_GENI_TX_WATERMARK_REG);
+ writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
+ }
+}
+
+static void qcom_geni_serial_stop_tx(struct uart_port *uport)
+{
+ u32 irq_en;
+ u32 status;
+ struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+
+ irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
+ irq_en &= ~M_CMD_DONE_EN;
+ if (port->xfer_mode == GENI_SE_FIFO) {
+ irq_en &= ~M_TX_FIFO_WATERMARK_EN;
+ writel_relaxed(0, uport->membase +
+ SE_GENI_TX_WATERMARK_REG);
+ }
+ port->xmit_size = 0;
+ writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
+ status = readl_relaxed(uport->membase + SE_GENI_STATUS);
+ /* Possible stop tx is called multiple times. */
+ if (!(status & M_GENI_CMD_ACTIVE))
+ return;
+
+ /*
+ * Ensure cancel command write is not re-ordered before checking
+ * the status of the Primary Sequencer.
+ */
+ mb();
+
+ geni_se_cancel_m_cmd(&port->se);
+ if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_CANCEL_EN, true)) {
+ geni_se_abort_m_cmd(&port->se);
+ qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_ABORT_EN, true);
+ writel_relaxed(M_CMD_ABORT_EN, uport->membase +
+ SE_GENI_M_IRQ_CLEAR);
+ }
+ writel_relaxed(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
+}
+
+static void qcom_geni_serial_start_rx(struct uart_port *uport)
+{
+ u32 irq_en;
+ u32 status;
+ struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+
+ status = readl_relaxed(uport->membase + SE_GENI_STATUS);
+ if (status & S_GENI_CMD_ACTIVE)
+ qcom_geni_serial_stop_rx(uport);
+
+ /*
+ * Ensure setup command write is not re-ordered before checking
+ * the status of the Secondary Sequencer.
+ */
+ mb();
+
+ geni_se_setup_s_cmd(&port->se, UART_START_READ, 0);
+
+ if (port->xfer_mode == GENI_SE_FIFO) {
+ irq_en = readl_relaxed(uport->membase + SE_GENI_S_IRQ_EN);
+ irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN;
+ writel_relaxed(irq_en, uport->membase + SE_GENI_S_IRQ_EN);
+
+ irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
+ irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
+ writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
+ }
+}
+
+static void qcom_geni_serial_stop_rx(struct uart_port *uport)
+{
+ u32 irq_en;
+ u32 status;
+ struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ u32 irq_clear = S_CMD_DONE_EN;
+
+ if (port->xfer_mode == GENI_SE_FIFO) {
+ irq_en = readl_relaxed(uport->membase + SE_GENI_S_IRQ_EN);
+ irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN);
+ writel_relaxed(irq_en, uport->membase + SE_GENI_S_IRQ_EN);
+
+ irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
+ irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
+ writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
+ }
+
+ status = readl_relaxed(uport->membase + SE_GENI_STATUS);
+ /* Possible stop rx is called multiple times. */
+ if (!(status & S_GENI_CMD_ACTIVE))
+ return;
+
+ /*
+ * Ensure cancel command write is not re-ordered before checking
+ * the status of the Secondary Sequencer.
+ */
+ mb();
+
+ geni_se_cancel_s_cmd(&port->se);
+ qcom_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG,
+ S_GENI_CMD_CANCEL, false);
+ status = readl_relaxed(uport->membase + SE_GENI_STATUS);
+ writel_relaxed(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR);
+ if (status & S_GENI_CMD_ACTIVE)
+ qcom_geni_serial_abort_rx(uport);
+}
+
+static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop)
+{
+ u32 status;
+ u32 word_cnt;
+ u32 last_word_byte_cnt;
+ u32 last_word_partial;
+ u32 total_bytes;
+ struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+
+ status = readl_relaxed(uport->membase + SE_GENI_RX_FIFO_STATUS);
+ word_cnt = status & RX_FIFO_WC_MSK;
+ last_word_partial = status & RX_LAST;
+ last_word_byte_cnt = (status & RX_LAST_BYTE_VALID_MSK) >>
+ RX_LAST_BYTE_VALID_SHFT;
+
+ if (!word_cnt)
+ return;
+ total_bytes = port->rx_bytes_pw * (word_cnt - 1);
+ if (last_word_partial && last_word_byte_cnt)
+ total_bytes += last_word_byte_cnt;
+ else
+ total_bytes += port->rx_bytes_pw;
+ port->handle_rx(uport, total_bytes, drop);
+}
+
+static void qcom_geni_serial_handle_tx(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ struct circ_buf *xmit = &uport->state->xmit;
+ size_t avail;
+ size_t remaining;
+ int i;
+ u32 status;
+ unsigned int chunk;
+ int tail;
+
+ chunk = uart_circ_chars_pending(xmit);
+ status = readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS);
+ /* Both FIFO and framework buffer are drained */
+ if (chunk == port->xmit_size && !status) {
+ port->xmit_size = 0;
+ uart_circ_clear(xmit);
+ qcom_geni_serial_stop_tx(uport);
+ goto out_write_wakeup;
+ }
+ chunk -= port->xmit_size;
+
+ avail = (port->tx_fifo_depth - port->tx_wm) * port->tx_bytes_pw;
+ tail = (xmit->tail + port->xmit_size) & (UART_XMIT_SIZE - 1);
+ if (chunk > (UART_XMIT_SIZE - tail))
+ chunk = UART_XMIT_SIZE - tail;
+ if (chunk > avail)
+ chunk = avail;
+
+ if (!chunk)
+ goto out_write_wakeup;
+
+ qcom_geni_serial_setup_tx(uport, chunk);
+
+ remaining = chunk;
+ for (i = 0; i < chunk; ) {
+ unsigned int tx_bytes;
+ unsigned int buf = 0;
+ int c;
+
+ tx_bytes = min_t(size_t, remaining, (size_t)port->tx_bytes_pw);
+ for (c = 0; c < tx_bytes ; c++)
+ buf |= (xmit->buf[tail + c] << (c * BITS_PER_BYTE));
+
+ writel_relaxed(buf, uport->membase + SE_GENI_TX_FIFOn);
+
+ i += tx_bytes;
+ tail = (tail + tx_bytes) & (UART_XMIT_SIZE - 1);
+ uport->icount.tx += tx_bytes;
+ remaining -= tx_bytes;
+ }
+ qcom_geni_serial_poll_tx_done(uport);
+ port->xmit_size += chunk;
+out_write_wakeup:
+ uart_write_wakeup(uport);
+}
+
+static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
+{
+ unsigned int m_irq_status;
+ unsigned int s_irq_status;
+ struct uart_port *uport = dev;
+ unsigned long flags;
+ unsigned int m_irq_en;
+ bool drop_rx = false;
+ struct tty_port *tport = &uport->state->port;
+ struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+
+ if (uport->suspended)
+ return IRQ_HANDLED;
+
+ spin_lock_irqsave(&uport->lock, flags);
+ m_irq_status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS);
+ s_irq_status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS);
+ m_irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
+ writel_relaxed(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR);
+ writel_relaxed(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR);
+
+ if (WARN_ON(m_irq_status & M_ILLEGAL_CMD_EN))
+ goto out_unlock;
+
+ if (s_irq_status & S_RX_FIFO_WR_ERR_EN) {
+ uport->icount.overrun++;
+ tty_insert_flip_char(tport, 0, TTY_OVERRUN);
+ }
+
+ if (m_irq_status & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN) &&
+ m_irq_en & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
+ qcom_geni_serial_handle_tx(uport);
+
+ if (s_irq_status & S_GP_IRQ_0_EN || s_irq_status & S_GP_IRQ_1_EN) {
+ if (s_irq_status & S_GP_IRQ_0_EN)
+ uport->icount.parity++;
+ drop_rx = true;
+ } else if (s_irq_status & S_GP_IRQ_2_EN ||
+ s_irq_status & S_GP_IRQ_3_EN) {
+ uport->icount.brk++;
+ port->brk = true;
+ }
+
+ if (s_irq_status & S_RX_FIFO_WATERMARK_EN ||
+ s_irq_status & S_RX_FIFO_LAST_EN)
+ qcom_geni_serial_handle_rx(uport, drop_rx);
+
+out_unlock:
+ spin_unlock_irqrestore(&uport->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static int get_tx_fifo_size(struct qcom_geni_serial_port *port)
+{
+ struct uart_port *uport;
+
+ if (!port)
+ return -ENODEV;
+
+ uport = &port->uport;
+ port->tx_fifo_depth = geni_se_get_tx_fifo_depth(&port->se);
+ port->tx_fifo_width = geni_se_get_tx_fifo_width(&port->se);
+ port->rx_fifo_depth = geni_se_get_rx_fifo_depth(&port->se);
+ uport->fifosize =
+ (port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE;
+ return 0;
+}
+
+static void set_rfr_wm(struct qcom_geni_serial_port *port)
+{
+ /*
+ * Set RFR (Flow off) to FIFO_DEPTH - 2.
+ * RX WM level at 10% RX_FIFO_DEPTH.
+ * TX WM level at 10% TX_FIFO_DEPTH.
+ */
+ port->rx_rfr = port->rx_fifo_depth - 2;
+ port->rx_wm = UART_CONSOLE_RX_WM;
+ port->tx_wm = DEF_TX_WM;
+}
+
+static void qcom_geni_serial_shutdown(struct uart_port *uport)
+{
+ unsigned long flags;
+
+ /* Stop the console before stopping the current tx */
+ console_stop(uport->cons);
+
+ disable_irq(uport->irq);
+ free_irq(uport->irq, uport);
+ spin_lock_irqsave(&uport->lock, flags);
+ qcom_geni_serial_stop_tx(uport);
+ qcom_geni_serial_stop_rx(uport);
+ spin_unlock_irqrestore(&uport->lock, flags);
+}
+
+static int qcom_geni_serial_port_setup(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
+
+ set_rfr_wm(port);
+ writel_relaxed(rxstale, uport->membase + SE_UART_RX_STALE_CNT);
+ /*
+ * Make an unconditional cancel on the main sequencer to reset
+ * it else we could end up in data loss scenarios.
+ */
+ port->xfer_mode = GENI_SE_FIFO;
+ qcom_geni_serial_poll_tx_done(uport);
+ geni_se_config_packing(&port->se, BITS_PER_BYTE, port->tx_bytes_pw,
+ false, true, false);
+ geni_se_config_packing(&port->se, BITS_PER_BYTE, port->rx_bytes_pw,
+ false, false, true);
+ geni_se_init(&port->se, port->rx_wm, port->rx_rfr);
+ geni_se_select_mode(&port->se, port->xfer_mode);
+ port->setup = true;
+ return 0;
+}
+
+static int qcom_geni_serial_startup(struct uart_port *uport)
+{
+ int ret;
+ u32 proto;
+ struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+
+ scnprintf(port->name, sizeof(port->name),
+ "qcom_serial_geni%d", uport->line);
+
+ proto = geni_se_read_proto(&port->se);
+ if (proto != GENI_SE_UART) {
+ dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto);
+ return -ENXIO;
+ }
+
+ get_tx_fifo_size(port);
+ if (!port->setup) {
+ ret = qcom_geni_serial_port_setup(uport);
+ if (ret)
+ return ret;
+ }
+
+ ret = request_irq(uport->irq, qcom_geni_serial_isr, IRQF_TRIGGER_HIGH,
+ port->name, uport);
+ if (ret)
+ dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret);
+ return ret;
+}
+
+static unsigned long get_clk_cfg(unsigned long clk_freq)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(root_freq); i++) {
+ if (!(root_freq[i] % clk_freq))
+ return root_freq[i];
+ }
+ return 0;
+}
+
+static unsigned long get_clk_div_rate(unsigned int baud, unsigned int *clk_div)
+{
+ unsigned long ser_clk;
+ unsigned long desired_clk;
+
+ desired_clk = baud * UART_OVERSAMPLING;
+ ser_clk = get_clk_cfg(desired_clk);
+ if (!ser_clk) {
+ pr_err("%s: Can't find matching DFS entry for baud %d\n",
+ __func__, baud);
+ return ser_clk;
+ }
+
+ *clk_div = ser_clk / desired_clk;
+ return ser_clk;
+}
+
+static void qcom_geni_serial_set_termios(struct uart_port *uport,
+ struct ktermios *termios, struct ktermios *old)
+{
+ unsigned int baud;
+ unsigned int bits_per_char;
+ unsigned int tx_trans_cfg;
+ unsigned int tx_parity_cfg;
+ unsigned int rx_trans_cfg;
+ unsigned int rx_parity_cfg;
+ unsigned int stop_bit_len;
+ unsigned int clk_div;
+ unsigned long ser_clk_cfg;
+ struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ unsigned long clk_rate;
+
+ qcom_geni_serial_stop_rx(uport);
+ /* baud rate */
+ baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
+ port->baud = baud;
+ clk_rate = get_clk_div_rate(baud, &clk_div);
+ if (!clk_rate)
+ goto out_restart_rx;
+
+ uport->uartclk = clk_rate;
+ clk_set_rate(port->se.clk, clk_rate);
+ ser_clk_cfg = SER_CLK_EN;
+ ser_clk_cfg |= clk_div << CLK_DIV_SHFT;
+
+ /* parity */
+ tx_trans_cfg = readl_relaxed(uport->membase + SE_UART_TX_TRANS_CFG);
+ tx_parity_cfg = readl_relaxed(uport->membase + SE_UART_TX_PARITY_CFG);
+ rx_trans_cfg = readl_relaxed(uport->membase + SE_UART_RX_TRANS_CFG);
+ rx_parity_cfg = readl_relaxed(uport->membase + SE_UART_RX_PARITY_CFG);
+ if (termios->c_cflag & PARENB) {
+ tx_trans_cfg |= UART_TX_PAR_EN;
+ rx_trans_cfg |= UART_RX_PAR_EN;
+ tx_parity_cfg |= PAR_CALC_EN;
+ rx_parity_cfg |= PAR_CALC_EN;
+ if (termios->c_cflag & PARODD) {
+ tx_parity_cfg |= PAR_ODD;
+ rx_parity_cfg |= PAR_ODD;
+ } else if (termios->c_cflag & CMSPAR) {
+ tx_parity_cfg |= PAR_SPACE;
+ rx_parity_cfg |= PAR_SPACE;
+ } else {
+ tx_parity_cfg |= PAR_EVEN;
+ rx_parity_cfg |= PAR_EVEN;
+ }
+ } else {
+ tx_trans_cfg &= ~UART_TX_PAR_EN;
+ rx_trans_cfg &= ~UART_RX_PAR_EN;
+ tx_parity_cfg &= ~PAR_CALC_EN;
+ rx_parity_cfg &= ~PAR_CALC_EN;
+ }
+
+ /* bits per char */
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ bits_per_char = 5;
+ break;
+ case CS6:
+ bits_per_char = 6;
+ break;
+ case CS7:
+ bits_per_char = 7;
+ break;
+ case CS8:
+ default:
+ bits_per_char = 8;
+ break;
+ }
+
+ /* stop bits */
+ if (termios->c_cflag & CSTOPB)
+ stop_bit_len = TX_STOP_BIT_LEN_2;
+ else
+ stop_bit_len = TX_STOP_BIT_LEN_1;
+
+ /* flow control, clear the CTS_MASK bit if using flow control. */
+ if (termios->c_cflag & CRTSCTS)
+ tx_trans_cfg &= ~UART_CTS_MASK;
+ else
+ tx_trans_cfg |= UART_CTS_MASK;
+
+ if (baud)
+ uart_update_timeout(uport, termios->c_cflag, baud);
+
+ writel_relaxed(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG);
+ writel_relaxed(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG);
+ writel_relaxed(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG);
+ writel_relaxed(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG);
+ writel_relaxed(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN);
+ writel_relaxed(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN);
+ writel_relaxed(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN);
+ writel_relaxed(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG);
+ writel_relaxed(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG);
+out_restart_rx:
+ qcom_geni_serial_start_rx(uport);
+}
+
+static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport)
+{
+ return !readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS);
+}
+
+#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
+static int __init qcom_geni_console_setup(struct console *co, char *options)
+{
+ struct uart_port *uport;
+ struct qcom_geni_serial_port *port;
+ int baud;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index >= GENI_UART_CONS_PORTS || co->index < 0)
+ return -ENXIO;
+
+ port = get_port_from_line(co->index);
+ if (IS_ERR(port)) {
+ pr_err("Invalid line %d(%d)\n", co->index, (int)PTR_ERR(port));
+ return PTR_ERR(port);
+ }
+
+ uport = &port->uport;
+
+ if (unlikely(!uport->membase))
+ return -ENXIO;
+
+ if (geni_se_resources_on(&port->se)) {
+ dev_err(port->se.dev, "Error turning on resources\n");
+ return -ENXIO;
+ }
+
+ if (unlikely(geni_se_read_proto(&port->se) != GENI_SE_UART)) {
+ geni_se_resources_off(&port->se);
+ return -ENXIO;
+ }
+
+ if (!port->setup) {
+ port->tx_bytes_pw = 1;
+ port->rx_bytes_pw = RX_BYTES_PW;
+ qcom_geni_serial_stop_rx(uport);
+ qcom_geni_serial_port_setup(uport);
+ }
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(uport, co, baud, parity, bits, flow);
+}
+
+static int __init console_register(struct uart_driver *drv)
+{
+ return uart_register_driver(drv);
+}
+
+static void console_unregister(struct uart_driver *drv)
+{
+ uart_unregister_driver(drv);
+}
+
+static struct console cons_ops = {
+ .name = "ttyMSM",
+ .write = qcom_geni_serial_console_write,
+ .device = uart_console_device,
+ .setup = qcom_geni_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &qcom_geni_console_driver,
+};
+
+static struct uart_driver qcom_geni_console_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "qcom_geni_console",
+ .dev_name = "ttyMSM",
+ .nr = GENI_UART_CONS_PORTS,
+ .cons = &cons_ops,
+};
+#else
+static int console_register(struct uart_driver *drv)
+{
+ return 0;
+}
+
+static void console_unregister(struct uart_driver *drv)
+{
+}
+#endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */
+
+static void qcom_geni_serial_cons_pm(struct uart_port *uport,
+ unsigned int new_state, unsigned int old_state)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+
+ if (unlikely(!uart_console(uport)))
+ return;
+
+ if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF)
+ geni_se_resources_on(&port->se);
+ else if (new_state == UART_PM_STATE_OFF &&
+ old_state == UART_PM_STATE_ON)
+ geni_se_resources_off(&port->se);
+}
+
+static const struct uart_ops qcom_geni_console_pops = {
+ .tx_empty = qcom_geni_serial_tx_empty,
+ .stop_tx = qcom_geni_serial_stop_tx,
+ .start_tx = qcom_geni_serial_start_tx,
+ .stop_rx = qcom_geni_serial_stop_rx,
+ .set_termios = qcom_geni_serial_set_termios,
+ .startup = qcom_geni_serial_startup,
+ .request_port = qcom_geni_serial_request_port,
+ .config_port = qcom_geni_serial_config_port,
+ .shutdown = qcom_geni_serial_shutdown,
+ .type = qcom_geni_serial_get_type,
+ .set_mctrl = qcom_geni_cons_set_mctrl,
+ .get_mctrl = qcom_geni_cons_get_mctrl,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = qcom_geni_serial_get_char,
+ .poll_put_char = qcom_geni_serial_poll_put_char,
+#endif
+ .pm = qcom_geni_serial_cons_pm,
+};
+
+static int qcom_geni_serial_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ int line = -1;
+ struct qcom_geni_serial_port *port;
+ struct uart_port *uport;
+ struct resource *res;
+
+ if (pdev->dev.of_node)
+ line = of_alias_get_id(pdev->dev.of_node, "serial");
+ else
+ line = pdev->id;
+
+ if (line < 0 || line >= GENI_UART_CONS_PORTS)
+ return -ENXIO;
+ port = get_port_from_line(line);
+ if (IS_ERR(port)) {
+ ret = PTR_ERR(port);
+ dev_err(&pdev->dev, "Invalid line %d(%d)\n", line, ret);
+ return ret;
+ }
+
+ uport = &port->uport;
+ /* Don't allow 2 drivers to access the same port */
+ if (uport->private_data)
+ return -ENODEV;
+
+ uport->dev = &pdev->dev;
+ port->se.dev = &pdev->dev;
+ port->se.wrapper = dev_get_drvdata(pdev->dev.parent);
+ port->se.clk = devm_clk_get(&pdev->dev, "se");
+ if (IS_ERR(port->se.clk)) {
+ ret = PTR_ERR(port->se.clk);
+ dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret);
+ return ret;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+ uport->mapbase = res->start;
+
+ port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
+ port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
+ port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
+
+ uport->irq = platform_get_irq(pdev, 0);
+ if (uport->irq < 0) {
+ dev_err(&pdev->dev, "Failed to get IRQ %d\n", uport->irq);
+ return uport->irq;
+ }
+
+ uport->private_data = &qcom_geni_console_driver;
+ platform_set_drvdata(pdev, port);
+ port->handle_rx = handle_rx_console;
+ port->setup = false;
+ return uart_add_one_port(&qcom_geni_console_driver, uport);
+}
+
+static int qcom_geni_serial_remove(struct platform_device *pdev)
+{
+ struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
+ struct uart_driver *drv = port->uport.private_data;
+
+ uart_remove_one_port(drv, &port->uport);
+ return 0;
+}
+
+static int __maybe_unused qcom_geni_serial_sys_suspend_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
+ struct uart_port *uport = &port->uport;
+
+ uart_suspend_port(uport->private_data, uport);
+ return 0;
+}
+
+static int __maybe_unused qcom_geni_serial_sys_resume_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
+ struct uart_port *uport = &port->uport;
+
+ if (console_suspend_enabled && uport->suspended) {
+ uart_resume_port(uport->private_data, uport);
+ disable_irq(uport->irq);
+ }
+ return 0;
+}
+
+static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend_noirq,
+ qcom_geni_serial_sys_resume_noirq)
+};
+
+static const struct of_device_id qcom_geni_serial_match_table[] = {
+ { .compatible = "qcom,geni-debug-uart", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table);
+
+static struct platform_driver qcom_geni_serial_platform_driver = {
+ .remove = qcom_geni_serial_remove,
+ .probe = qcom_geni_serial_probe,
+ .driver = {
+ .name = "qcom_geni_serial",
+ .of_match_table = qcom_geni_serial_match_table,
+ .pm = &qcom_geni_serial_pm_ops,
+ },
+};
+
+static int __init qcom_geni_serial_init(void)
+{
+ int ret;
+
+ qcom_geni_console_port.uport.iotype = UPIO_MEM;
+ qcom_geni_console_port.uport.ops = &qcom_geni_console_pops;
+ qcom_geni_console_port.uport.flags = UPF_BOOT_AUTOCONF;
+ qcom_geni_console_port.uport.line = 0;
+
+ ret = console_register(&qcom_geni_console_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&qcom_geni_serial_platform_driver);
+ if (ret)
+ console_unregister(&qcom_geni_console_driver);
+ return ret;
+}
+module_init(qcom_geni_serial_init);
+
+static void __exit qcom_geni_serial_exit(void)
+{
+ platform_driver_unregister(&qcom_geni_serial_platform_driver);
+ console_unregister(&qcom_geni_console_driver);
+}
+module_exit(qcom_geni_serial_exit);
+
+MODULE_DESCRIPTION("Serial driver for GENI based QUP cores");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index f9fecc5ed0ce..3f2f8c118ce0 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -1818,6 +1818,10 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
dbg("s3c24xx_serial_probe(%p) %d\n", pdev, index);
+ if (index >= ARRAY_SIZE(s3c24xx_serial_ports)) {
+ dev_err(&pdev->dev, "serial%d out of range\n", index);
+ return -EINVAL;
+ }
ourport = &s3c24xx_serial_ports[index];
ourport->drv_data = s3c24xx_get_driver_data(pdev);
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 35b9201db3b4..0466f9f08a91 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1786,6 +1786,8 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
seq_printf(m, " brk:%d", uport->icount.brk);
if (uport->icount.overrun)
seq_printf(m, " oe:%d", uport->icount.overrun);
+ if (uport->icount.buf_overrun)
+ seq_printf(m, " bo:%d", uport->icount.buf_overrun);
#define INFOBIT(bit, str) \
if (uport->mctrl & (bit)) \
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 44adf9db38f8..fdbbff547106 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -33,6 +33,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
+#include <linux/ktime.h>
#include <linux/major.h>
#include <linux/module.h>
#include <linux/mm.h>
@@ -143,8 +144,8 @@ struct sci_port {
void *rx_buf[2];
size_t buf_len_rx;
struct work_struct work_tx;
- struct timer_list rx_timer;
- unsigned int rx_timeout;
+ struct hrtimer rx_timer;
+ unsigned int rx_timeout; /* microseconds */
#endif
unsigned int rx_frame;
int rx_trigger;
@@ -1231,6 +1232,15 @@ static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
}
}
+static void start_hrtimer_us(struct hrtimer *hrt, unsigned long usec)
+{
+ long sec = usec / 1000000;
+ long nsec = (usec % 1000000) * 1000;
+ ktime_t t = ktime_set(sec, nsec);
+
+ hrtimer_start(hrt, t, HRTIMER_MODE_REL);
+}
+
static void sci_dma_rx_complete(void *arg)
{
struct sci_port *s = arg;
@@ -1249,7 +1259,7 @@ static void sci_dma_rx_complete(void *arg)
if (active >= 0)
count = sci_dma_rx_push(s, s->rx_buf[active], s->buf_len_rx);
- mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
+ start_hrtimer_us(&s->rx_timer, s->rx_timeout);
if (count)
tty_flip_buffer_push(&port->state->port);
@@ -1393,9 +1403,9 @@ static void work_fn_tx(struct work_struct *work)
dma_async_issue_pending(chan);
}
-static void rx_timer_fn(struct timer_list *t)
+static enum hrtimer_restart rx_timer_fn(struct hrtimer *t)
{
- struct sci_port *s = from_timer(s, t, rx_timer);
+ struct sci_port *s = container_of(t, struct sci_port, rx_timer);
struct dma_chan *chan = s->chan_rx;
struct uart_port *port = &s->port;
struct dma_tx_state state;
@@ -1412,7 +1422,7 @@ static void rx_timer_fn(struct timer_list *t)
active = sci_dma_rx_find_active(s);
if (active < 0) {
spin_unlock_irqrestore(&port->lock, flags);
- return;
+ return HRTIMER_NORESTART;
}
status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state);
@@ -1422,7 +1432,7 @@ static void rx_timer_fn(struct timer_list *t)
s->active_rx, active);
/* Let packet complete handler take care of the packet */
- return;
+ return HRTIMER_NORESTART;
}
dmaengine_pause(chan);
@@ -1437,7 +1447,7 @@ static void rx_timer_fn(struct timer_list *t)
if (status == DMA_COMPLETE) {
spin_unlock_irqrestore(&port->lock, flags);
dev_dbg(port->dev, "Transaction complete after DMA engine was stopped");
- return;
+ return HRTIMER_NORESTART;
}
/* Handle incomplete DMA receive */
@@ -1462,6 +1472,8 @@ static void rx_timer_fn(struct timer_list *t)
serial_port_out(port, SCSCR, scr | SCSCR_RIE);
spin_unlock_irqrestore(&port->lock, flags);
+
+ return HRTIMER_NORESTART;
}
static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
@@ -1573,7 +1585,8 @@ static void sci_request_dma(struct uart_port *port)
dma += s->buf_len_rx;
}
- timer_setup(&s->rx_timer, rx_timer_fn, 0);
+ hrtimer_init(&s->rx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ s->rx_timer.function = rx_timer_fn;
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
sci_submit_rx(s);
@@ -1632,9 +1645,9 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
/* Clear current interrupt */
serial_port_out(port, SCxSR,
ssr & ~(SCIF_DR | SCxSR_RDxF(port)));
- dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n",
+ dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u us\n",
jiffies, s->rx_timeout);
- mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
+ start_hrtimer_us(&s->rx_timer, s->rx_timeout);
return IRQ_HANDLED;
}
@@ -1645,7 +1658,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
scif_set_rtrg(port, s->rx_trigger);
mod_timer(&s->rx_fifo_timer, jiffies + DIV_ROUND_UP(
- s->rx_frame * s->rx_fifo_timeout, 1000));
+ s->rx_frame * HZ * s->rx_fifo_timeout, 1000000));
}
/* I think sci_receive_chars has to be called irrespective
@@ -2081,7 +2094,7 @@ static void sci_shutdown(struct uart_port *port)
if (s->chan_rx) {
dev_dbg(port->dev, "%s(%d) deleting rx_timer\n", __func__,
port->line);
- del_timer_sync(&s->rx_timer);
+ hrtimer_cancel(&s->rx_timer);
}
#endif
@@ -2482,11 +2495,11 @@ done:
if (termios->c_cflag & PARENB)
bits++;
- s->rx_frame = (100 * bits * HZ) / (baud / 10);
+ s->rx_frame = (10000 * bits) / (baud / 100);
#ifdef CONFIG_SERIAL_SH_SCI_DMA
- s->rx_timeout = DIV_ROUND_UP(s->buf_len_rx * 2 * s->rx_frame, 1000);
- if (s->rx_timeout < msecs_to_jiffies(20))
- s->rx_timeout = msecs_to_jiffies(20);
+ s->rx_timeout = s->buf_len_rx * 2 * s->rx_frame;
+ if (s->rx_timeout < 20)
+ s->rx_timeout = 20;
#endif
if ((termios->c_cflag & CREAD) != 0)
@@ -3098,6 +3111,10 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
dev_err(&pdev->dev, "failed to get alias id (%d)\n", id);
return NULL;
}
+ if (id >= ARRAY_SIZE(sci_ports)) {
+ dev_err(&pdev->dev, "serial%d out of range\n", id);
+ return NULL;
+ }
sp = &sci_ports[id];
*dev_id = id;
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index 9925b00a9777..38622f2a30a9 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -1283,6 +1283,11 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
goto err;
}
sirfport->port.line = of_alias_get_id(np, "serial");
+ if (sirfport->port.line >= ARRAY_SIZE(sirf_ports)) {
+ dev_err(&pdev->dev, "serial%d out of range\n",
+ sirfport->port.line);
+ return -EINVAL;
+ }
sirf_ports[sirfport->port.line] = sirfport;
sirfport->port.iotype = UPIO_MEM;
sirfport->port.flags = UPF_BOOT_AUTOCONF;
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index c763253514e9..5f9f01fac6dd 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -782,7 +782,9 @@ static struct asc_port *asc_of_get_asc_port(struct platform_device *pdev)
if (!np)
return NULL;
- id = of_alias_get_id(np, ASC_SERIAL_NAME);
+ id = of_alias_get_id(np, "serial");
+ if (id < 0)
+ id = of_alias_get_id(np, ASC_SERIAL_NAME);
if (id < 0)
id = 0;
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 0fa735b60f2d..e8d7a7bb4339 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -62,6 +62,113 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
writel_relaxed(val, port->membase + reg);
}
+static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
+ u32 delay_DDE, u32 baud)
+{
+ u32 rs485_deat_dedt;
+ u32 rs485_deat_dedt_max = (USART_CR1_DEAT_MASK >> USART_CR1_DEAT_SHIFT);
+ bool over8;
+
+ *cr3 |= USART_CR3_DEM;
+ over8 = *cr1 & USART_CR1_OVER8;
+
+ if (over8)
+ rs485_deat_dedt = delay_ADE * baud * 8;
+ else
+ rs485_deat_dedt = delay_ADE * baud * 16;
+
+ rs485_deat_dedt = DIV_ROUND_CLOSEST(rs485_deat_dedt, 1000);
+ rs485_deat_dedt = rs485_deat_dedt > rs485_deat_dedt_max ?
+ rs485_deat_dedt_max : rs485_deat_dedt;
+ rs485_deat_dedt = (rs485_deat_dedt << USART_CR1_DEAT_SHIFT) &
+ USART_CR1_DEAT_MASK;
+ *cr1 |= rs485_deat_dedt;
+
+ if (over8)
+ rs485_deat_dedt = delay_DDE * baud * 8;
+ else
+ rs485_deat_dedt = delay_DDE * baud * 16;
+
+ rs485_deat_dedt = DIV_ROUND_CLOSEST(rs485_deat_dedt, 1000);
+ rs485_deat_dedt = rs485_deat_dedt > rs485_deat_dedt_max ?
+ rs485_deat_dedt_max : rs485_deat_dedt;
+ rs485_deat_dedt = (rs485_deat_dedt << USART_CR1_DEDT_SHIFT) &
+ USART_CR1_DEDT_MASK;
+ *cr1 |= rs485_deat_dedt;
+}
+
+static int stm32_config_rs485(struct uart_port *port,
+ struct serial_rs485 *rs485conf)
+{
+ struct stm32_port *stm32_port = to_stm32_port(port);
+ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
+ struct stm32_usart_config *cfg = &stm32_port->info->cfg;
+ u32 usartdiv, baud, cr1, cr3;
+ bool over8;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
+
+ port->rs485 = *rs485conf;
+
+ rs485conf->flags |= SER_RS485_RX_DURING_TX;
+
+ if (rs485conf->flags & SER_RS485_ENABLED) {
+ cr1 = readl_relaxed(port->membase + ofs->cr1);
+ cr3 = readl_relaxed(port->membase + ofs->cr3);
+ usartdiv = readl_relaxed(port->membase + ofs->brr);
+ usartdiv = usartdiv & GENMASK(15, 0);
+ over8 = cr1 & USART_CR1_OVER8;
+
+ if (over8)
+ usartdiv = usartdiv | (usartdiv & GENMASK(4, 0))
+ << USART_BRR_04_R_SHIFT;
+
+ baud = DIV_ROUND_CLOSEST(port->uartclk, usartdiv);
+ stm32_config_reg_rs485(&cr1, &cr3,
+ rs485conf->delay_rts_before_send,
+ rs485conf->delay_rts_after_send, baud);
+
+ if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
+ cr3 &= ~USART_CR3_DEP;
+ rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND;
+ } else {
+ cr3 |= USART_CR3_DEP;
+ rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
+ }
+
+ writel_relaxed(cr3, port->membase + ofs->cr3);
+ writel_relaxed(cr1, port->membase + ofs->cr1);
+ } else {
+ stm32_clr_bits(port, ofs->cr3, USART_CR3_DEM | USART_CR3_DEP);
+ stm32_clr_bits(port, ofs->cr1,
+ USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
+ }
+
+ stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return 0;
+}
+
+static int stm32_init_rs485(struct uart_port *port,
+ struct platform_device *pdev)
+{
+ struct serial_rs485 *rs485conf = &port->rs485;
+
+ rs485conf->flags = 0;
+ rs485conf->delay_rts_before_send = 0;
+ rs485conf->delay_rts_after_send = 0;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ uart_get_rs485_mode(&pdev->dev, rs485conf);
+
+ return 0;
+}
+
static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res,
bool threaded)
{
@@ -498,6 +605,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
+ struct serial_rs485 *rs485conf = &port->rs485;
unsigned int baud;
u32 usartdiv, mantissa, fraction, oversampling;
tcflag_t cflag = termios->c_cflag;
@@ -515,7 +623,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
writel_relaxed(0, port->membase + ofs->cr1);
cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
- cr1 |= BIT(cfg->uart_enable_bit);
+
if (stm32_port->fifoen)
cr1 |= USART_CR1_FIFOEN;
cr2 = 0;
@@ -553,9 +661,11 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
*/
if (usartdiv < 16) {
oversampling = 8;
+ cr1 |= USART_CR1_OVER8;
stm32_set_bits(port, ofs->cr1, USART_CR1_OVER8);
} else {
oversampling = 16;
+ cr1 &= ~USART_CR1_OVER8;
stm32_clr_bits(port, ofs->cr1, USART_CR1_OVER8);
}
@@ -592,10 +702,28 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
if (stm32_port->rx_ch)
cr3 |= USART_CR3_DMAR;
+ if (rs485conf->flags & SER_RS485_ENABLED) {
+ stm32_config_reg_rs485(&cr1, &cr3,
+ rs485conf->delay_rts_before_send,
+ rs485conf->delay_rts_after_send, baud);
+ if (rs485conf->flags & SER_RS485_RTS_ON_SEND) {
+ cr3 &= ~USART_CR3_DEP;
+ rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND;
+ } else {
+ cr3 |= USART_CR3_DEP;
+ rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
+ }
+
+ } else {
+ cr3 &= ~(USART_CR3_DEM | USART_CR3_DEP);
+ cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
+ }
+
writel_relaxed(cr3, port->membase + ofs->cr3);
writel_relaxed(cr2, port->membase + ofs->cr2);
writel_relaxed(cr1, port->membase + ofs->cr1);
+ stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -681,6 +809,10 @@ static int stm32_init_port(struct stm32_port *stm32port,
port->ops = &stm32_uart_ops;
port->dev = &pdev->dev;
port->irq = platform_get_irq(pdev, 0);
+ port->rs485_config = stm32_config_rs485;
+
+ stm32_init_rs485(port, pdev);
+
stm32port->wakeirq = platform_get_irq(pdev, 1);
stm32port->fifoen = stm32port->info->cfg.has_fifo;
diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h
index 2294d0f05872..6f294e280ea3 100644
--- a/drivers/tty/serial/stm32-usart.h
+++ b/drivers/tty/serial/stm32-usart.h
@@ -135,6 +135,7 @@ struct stm32_usart_info stm32h7_info = {
#define USART_BRR_DIV_F_MASK GENMASK(3, 0)
#define USART_BRR_DIV_M_MASK GENMASK(15, 4)
#define USART_BRR_DIV_M_SHIFT 4
+#define USART_BRR_04_R_SHIFT 1
/* USART_CR1 */
#define USART_CR1_SBK BIT(0)
@@ -162,6 +163,8 @@ struct stm32_usart_info stm32h7_info = {
#define USART_CR1_M1 BIT(28) /* F7 */
#define USART_CR1_IE_MASK (GENMASK(8, 4) | BIT(14) | BIT(26) | BIT(27))
#define USART_CR1_FIFOEN BIT(29) /* H7 */
+#define USART_CR1_DEAT_SHIFT 21
+#define USART_CR1_DEDT_SHIFT 16
/* USART_CR2 */
#define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index b9b2bc76bcac..abcb4d09a2d8 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -1110,7 +1110,7 @@ static struct uart_port *cdns_uart_get_port(int id)
struct uart_port *port;
/* Try the given port id if failed use default method */
- if (cdns_uart_port[id].mapbase != 0) {
+ if (id < CDNS_UART_NR_PORTS && cdns_uart_port[id].mapbase != 0) {
/* Find the next unused port */
for (id = 0; id < CDNS_UART_NR_PORTS; id++)
if (cdns_uart_port[id].mapbase == 0)
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index b4e57c5a8bba..f97251f39c26 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1354,6 +1354,11 @@ static void csi_m(struct vc_data *vc)
case 3:
vc->vc_italic = 1;
break;
+ case 21:
+ /*
+ * No console drivers support double underline, so
+ * convert it to a single underline.
+ */
case 4:
vc->vc_underline = 1;
break;
@@ -1389,7 +1394,6 @@ static void csi_m(struct vc_data *vc)
vc->vc_disp_ctrl = 1;
vc->vc_toggle_meta = 1;
break;
- case 21:
case 22:
vc->vc_intensity = 1;
break;
diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c
index 8ca549032c27..f695a7e8c314 100644
--- a/drivers/uio/uio_hv_generic.c
+++ b/drivers/uio/uio_hv_generic.c
@@ -121,6 +121,94 @@ static void hv_uio_rescind(struct vmbus_channel *channel)
uio_event_notify(&pdata->info);
}
+/*
+ * Handle fault when looking for sub channel ring buffer
+ * Subchannel ring buffer is same as resource 0 which is main ring buffer
+ * This is derived from uio_vma_fault
+ */
+static int hv_uio_vma_fault(struct vm_fault *vmf)
+{
+ struct vm_area_struct *vma = vmf->vma;
+ void *ring_buffer = vma->vm_private_data;
+ struct page *page;
+ void *addr;
+
+ addr = ring_buffer + (vmf->pgoff << PAGE_SHIFT);
+ page = virt_to_page(addr);
+ get_page(page);
+ vmf->page = page;
+ return 0;
+}
+
+static const struct vm_operations_struct hv_uio_vm_ops = {
+ .fault = hv_uio_vma_fault,
+};
+
+/* Sysfs API to allow mmap of the ring buffers */
+static int hv_uio_ring_mmap(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ struct vm_area_struct *vma)
+{
+ struct vmbus_channel *channel
+ = container_of(kobj, struct vmbus_channel, kobj);
+ unsigned long requested_pages, actual_pages;
+
+ if (vma->vm_end < vma->vm_start)
+ return -EINVAL;
+
+ /* only allow 0 for now */
+ if (vma->vm_pgoff > 0)
+ return -EINVAL;
+
+ requested_pages = vma_pages(vma);
+ actual_pages = 2 * HV_RING_SIZE;
+ if (requested_pages > actual_pages)
+ return -EINVAL;
+
+ vma->vm_private_data = channel->ringbuffer_pages;
+ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vma->vm_ops = &hv_uio_vm_ops;
+ return 0;
+}
+
+static struct bin_attribute ring_buffer_bin_attr __ro_after_init = {
+ .attr = {
+ .name = "ring",
+ .mode = 0600,
+ /* size is set at init time */
+ },
+ .mmap = hv_uio_ring_mmap,
+};
+
+/* Callback from VMBUS subystem when new channel created. */
+static void
+hv_uio_new_channel(struct vmbus_channel *new_sc)
+{
+ struct hv_device *hv_dev = new_sc->primary_channel->device_obj;
+ struct device *device = &hv_dev->device;
+ struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev);
+ const size_t ring_bytes = HV_RING_SIZE * PAGE_SIZE;
+ int ret;
+
+ /* Create host communication ring */
+ ret = vmbus_open(new_sc, ring_bytes, ring_bytes, NULL, 0,
+ hv_uio_channel_cb, pdata);
+ if (ret) {
+ dev_err(device, "vmbus_open subchannel failed: %d\n", ret);
+ return;
+ }
+
+ /* Disable interrupts on sub channel */
+ new_sc->inbound.ring_buffer->interrupt_mask = 1;
+ set_channel_read_mode(new_sc, HV_CALL_ISR);
+
+ ret = sysfs_create_bin_file(&new_sc->kobj, &ring_buffer_bin_attr);
+ if (ret) {
+ dev_err(device, "sysfs create ring bin file failed; %d\n", ret);
+ vmbus_close(new_sc);
+ }
+}
+
static void
hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata)
{
@@ -236,6 +324,7 @@ hv_uio_probe(struct hv_device *dev,
}
vmbus_set_chn_rescind_callback(dev->channel, hv_uio_rescind);
+ vmbus_set_sc_create_callback(dev->channel, hv_uio_new_channel);
hv_set_drvdata(dev, pdata);
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 148f3ee70286..75f7fb151f71 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -171,6 +171,8 @@ source "drivers/usb/gadget/Kconfig"
source "drivers/usb/typec/Kconfig"
+source "drivers/usb/roles/Kconfig"
+
config USB_LED_TRIG
bool "USB LED Triggers"
depends on LEDS_CLASS && LEDS_TRIGGERS
@@ -203,4 +205,7 @@ config USB_ULPI_BUS
To compile this driver as a module, choose M here: the module will
be called ulpi.
+config USB_ROLE_SWITCH
+ tristate
+
endif # USB_SUPPORT
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 060643a1b5c8..7d1b8c82b208 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -65,3 +65,5 @@ obj-$(CONFIG_USB_COMMON) += common/
obj-$(CONFIG_USBIP_CORE) += usbip/
obj-$(CONFIG_TYPEC) += typec/
+
+obj-$(CONFIG_USB_ROLE_SWITCH) += roles/
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 3b45c25f296e..e431c5aafe35 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -20,7 +20,6 @@
struct ci_hdrc_imx_platform_flag {
unsigned int flags;
- bool runtime_pm;
};
static const struct ci_hdrc_imx_platform_flag imx23_usb_data = {
@@ -29,7 +28,7 @@ static const struct ci_hdrc_imx_platform_flag imx23_usb_data = {
};
static const struct ci_hdrc_imx_platform_flag imx27_usb_data = {
- CI_HDRC_DISABLE_STREAMING,
+ .flags = CI_HDRC_DISABLE_STREAMING,
};
static const struct ci_hdrc_imx_platform_flag imx28_usb_data = {
@@ -84,6 +83,7 @@ struct ci_hdrc_imx_data {
struct clk *clk;
struct imx_usbmisc_data *usbmisc_data;
bool supports_runtime_pm;
+ bool override_phy_control;
bool in_lpm;
/* SoC before i.mx6 (except imx23/imx28) needs three clks */
bool need_three_clks;
@@ -255,6 +255,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
int ret;
const struct of_device_id *of_id;
const struct ci_hdrc_imx_platform_flag *imx_platform_flag;
+ struct device_node *np = pdev->dev.of_node;
of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
if (!of_id)
@@ -289,6 +290,14 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
}
pdata.usb_phy = data->phy;
+
+ if (of_device_is_compatible(np, "fsl,imx53-usb") && pdata.usb_phy &&
+ of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) {
+ pdata.flags |= CI_HDRC_OVERRIDE_PHY_CONTROL;
+ data->override_phy_control = true;
+ usb_phy_init(pdata.usb_phy);
+ }
+
pdata.flags |= imx_platform_flag->flags;
if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
data->supports_runtime_pm = true;
@@ -342,6 +351,8 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
pm_runtime_put_noidle(&pdev->dev);
}
ci_hdrc_remove_device(data->ci_pdev);
+ if (data->override_phy_control)
+ usb_phy_shutdown(data->phy);
imx_disable_unprepare_clks(&pdev->dev);
return 0;
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index c9e1a165ed82..ce648cb3ed94 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -45,18 +45,7 @@ static int ci_device_show(struct seq_file *s, void *data)
return 0;
}
-
-static int ci_device_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ci_device_show, inode->i_private);
-}
-
-static const struct file_operations ci_device_fops = {
- .open = ci_device_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(ci_device);
/**
* ci_port_test_show: reads port test mode
@@ -156,18 +145,7 @@ static int ci_qheads_show(struct seq_file *s, void *data)
return 0;
}
-
-static int ci_qheads_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ci_qheads_show, inode->i_private);
-}
-
-static const struct file_operations ci_qheads_fops = {
- .open = ci_qheads_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(ci_qheads);
/**
* ci_requests_show: DMA contents of all requests currently queued (all endpts)
@@ -204,18 +182,7 @@ static int ci_requests_show(struct seq_file *s, void *data)
return 0;
}
-
-static int ci_requests_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ci_requests_show, inode->i_private);
-}
-
-static const struct file_operations ci_requests_fops = {
- .open = ci_requests_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(ci_requests);
static int ci_otg_show(struct seq_file *s, void *unused)
{
@@ -278,18 +245,7 @@ static int ci_otg_show(struct seq_file *s, void *unused)
return 0;
}
-
-static int ci_otg_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ci_otg_show, inode->i_private);
-}
-
-static const struct file_operations ci_otg_fops = {
- .open = ci_otg_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(ci_otg);
static int ci_role_show(struct seq_file *s, void *data)
{
@@ -376,18 +332,7 @@ static int ci_registers_show(struct seq_file *s, void *unused)
return 0;
}
-
-static int ci_registers_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ci_registers_show, inode->i_private);
-}
-
-static const struct file_operations ci_registers_fops = {
- .open = ci_registers_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(ci_registers);
/**
* dbg_create_files: initializes the attribute interface
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index 19d60ed7e41f..af45aa3222b5 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -124,10 +124,8 @@ static int host_start(struct ci_hdrc *ci)
hcd->power_budget = ci->platdata->power_budget;
hcd->tpl_support = ci->platdata->tpl_support;
- if (ci->phy)
- hcd->phy = ci->phy;
- else
- hcd->usb_phy = ci->usb_phy;
+ if (ci->phy || ci->usb_phy)
+ hcd->skip_phy_initialization = 1;
ehci = hcd_to_ehci(hcd);
ehci->caps = ci->hw_bank.cap;
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index 8cdf0af156c6..34ad5bf8acd8 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -148,14 +148,21 @@ static int usbmisc_imx25_post(struct imx_usbmisc_data *data)
if (data->index > 2)
return -EINVAL;
- if (data->evdo) {
- spin_lock_irqsave(&usbmisc->lock, flags);
- reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
- val = readl(reg);
- writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
- spin_unlock_irqrestore(&usbmisc->lock, flags);
- usleep_range(5000, 10000); /* needed to stabilize voltage */
- }
+ if (data->index)
+ return 0;
+
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
+ val = readl(reg);
+
+ if (data->evdo)
+ val |= MX25_BM_EXTERNAL_VBUS_DIVIDER;
+ else
+ val &= ~MX25_BM_EXTERNAL_VBUS_DIVIDER;
+
+ writel(val, reg);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+ usleep_range(5000, 10000); /* needed to stabilize voltage */
return 0;
}
@@ -308,13 +315,12 @@ static int usbmisc_imx6q_set_wakeup
val = readl(usbmisc->base + data->index * 4);
if (enabled) {
val |= wakeup_setting;
- writel(val, usbmisc->base + data->index * 4);
} else {
if (val & MX6_BM_WAKEUP_INTR)
pr_debug("wakeup int at ci_hdrc.%d\n", data->index);
val &= ~wakeup_setting;
- writel(val, usbmisc->base + data->index * 4);
}
+ writel(val, usbmisc->base + data->index * 4);
spin_unlock_irqrestore(&usbmisc->lock, flags);
return ret;
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index 0a7c45e85481..fb4d5ef4165c 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -9,3 +9,4 @@ usb-common-$(CONFIG_USB_LED_TRIG) += led.o
obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o
obj-$(CONFIG_USB_ULPI_BUS) += ulpi.o
+obj-$(CONFIG_USB_ROLE_SWITCH) += roles.o
diff --git a/drivers/usb/common/roles.c b/drivers/usb/common/roles.c
new file mode 100644
index 000000000000..15cc76e22123
--- /dev/null
+++ b/drivers/usb/common/roles.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * USB Role Switch Support
+ *
+ * Copyright (C) 2018 Intel Corporation
+ * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+ * Hans de Goede <hdegoede@redhat.com>
+ */
+
+#include <linux/usb/role.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+static struct class *role_class;
+
+struct usb_role_switch {
+ struct device dev;
+ struct mutex lock; /* device lock*/
+ enum usb_role role;
+
+ /* From descriptor */
+ struct device *usb2_port;
+ struct device *usb3_port;
+ struct device *udc;
+ usb_role_switch_set_t set;
+ usb_role_switch_get_t get;
+ bool allow_userspace_control;
+};
+
+#define to_role_switch(d) container_of(d, struct usb_role_switch, dev)
+
+/**
+ * usb_role_switch_set_role - Set USB role for a switch
+ * @sw: USB role switch
+ * @role: USB role to be switched to
+ *
+ * Set USB role @role for @sw.
+ */
+int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role)
+{
+ int ret;
+
+ if (IS_ERR_OR_NULL(sw))
+ return 0;
+
+ mutex_lock(&sw->lock);
+
+ ret = sw->set(sw->dev.parent, role);
+ if (!ret)
+ sw->role = role;
+
+ mutex_unlock(&sw->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_role_switch_set_role);
+
+/**
+ * usb_role_switch_get_role - Get the USB role for a switch
+ * @sw: USB role switch
+ *
+ * Depending on the role-switch-driver this function returns either a cached
+ * value of the last set role, or reads back the actual value from the hardware.
+ */
+enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw)
+{
+ enum usb_role role;
+
+ if (IS_ERR_OR_NULL(sw))
+ return USB_ROLE_NONE;
+
+ mutex_lock(&sw->lock);
+
+ if (sw->get)
+ role = sw->get(sw->dev.parent);
+ else
+ role = sw->role;
+
+ mutex_unlock(&sw->lock);
+
+ return role;
+}
+EXPORT_SYMBOL_GPL(usb_role_switch_get_role);
+
+static int __switch_match(struct device *dev, const void *name)
+{
+ return !strcmp((const char *)name, dev_name(dev));
+}
+
+static void *usb_role_switch_match(struct device_connection *con, int ep,
+ void *data)
+{
+ struct device *dev;
+
+ dev = class_find_device(role_class, NULL, con->endpoint[ep],
+ __switch_match);
+
+ return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER);
+}
+
+/**
+ * usb_role_switch_get - Find USB role switch linked with the caller
+ * @dev: The caller device
+ *
+ * Finds and returns role switch linked with @dev. The reference count for the
+ * found switch is incremented.
+ */
+struct usb_role_switch *usb_role_switch_get(struct device *dev)
+{
+ return device_connection_find_match(dev, "usb-role-switch", NULL,
+ usb_role_switch_match);
+}
+EXPORT_SYMBOL_GPL(usb_role_switch_get);
+
+/**
+ * usb_role_switch_put - Release handle to a switch
+ * @sw: USB Role Switch
+ *
+ * Decrement reference count for @sw.
+ */
+void usb_role_switch_put(struct usb_role_switch *sw)
+{
+ if (!IS_ERR_OR_NULL(sw))
+ put_device(&sw->dev);
+}
+EXPORT_SYMBOL_GPL(usb_role_switch_put);
+
+static umode_t
+usb_role_switch_is_visible(struct kobject *kobj, struct attribute *attr, int n)
+{
+ struct device *dev = container_of(kobj, typeof(*dev), kobj);
+ struct usb_role_switch *sw = to_role_switch(dev);
+
+ if (sw->allow_userspace_control)
+ return attr->mode;
+
+ return 0;
+}
+
+static const char * const usb_roles[] = {
+ [USB_ROLE_NONE] = "none",
+ [USB_ROLE_HOST] = "host",
+ [USB_ROLE_DEVICE] = "device",
+};
+
+static ssize_t
+role_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct usb_role_switch *sw = to_role_switch(dev);
+ enum usb_role role = usb_role_switch_get_role(sw);
+
+ return sprintf(buf, "%s\n", usb_roles[role]);
+}
+
+static ssize_t role_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct usb_role_switch *sw = to_role_switch(dev);
+ int ret;
+
+ ret = sysfs_match_string(usb_roles, buf);
+ if (ret < 0) {
+ bool res;
+
+ /* Extra check if the user wants to disable the switch */
+ ret = kstrtobool(buf, &res);
+ if (ret || res)
+ return -EINVAL;
+ }
+
+ ret = usb_role_switch_set_role(sw, ret);
+ if (ret)
+ return ret;
+
+ return size;
+}
+static DEVICE_ATTR_RW(role);
+
+static struct attribute *usb_role_switch_attrs[] = {
+ &dev_attr_role.attr,
+ NULL,
+};
+
+static const struct attribute_group usb_role_switch_group = {
+ .is_visible = usb_role_switch_is_visible,
+ .attrs = usb_role_switch_attrs,
+};
+
+static const struct attribute_group *usb_role_switch_groups[] = {
+ &usb_role_switch_group,
+ NULL,
+};
+
+static int
+usb_role_switch_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ int ret;
+
+ ret = add_uevent_var(env, "USB_ROLE_SWITCH=%s", dev_name(dev));
+ if (ret)
+ dev_err(dev, "failed to add uevent USB_ROLE_SWITCH\n");
+
+ return ret;
+}
+
+static void usb_role_switch_release(struct device *dev)
+{
+ struct usb_role_switch *sw = to_role_switch(dev);
+
+ kfree(sw);
+}
+
+static const struct device_type usb_role_dev_type = {
+ .name = "usb_role_switch",
+ .groups = usb_role_switch_groups,
+ .uevent = usb_role_switch_uevent,
+ .release = usb_role_switch_release,
+};
+
+/**
+ * usb_role_switch_register - Register USB Role Switch
+ * @parent: Parent device for the switch
+ * @desc: Description of the switch
+ *
+ * USB Role Switch is a device capable or choosing the role for USB connector.
+ * On platforms where the USB controller is dual-role capable, the controller
+ * driver will need to register the switch. On platforms where the USB host and
+ * USB device controllers behind the connector are separate, there will be a
+ * mux, and the driver for that mux will need to register the switch.
+ *
+ * Returns handle to a new role switch or ERR_PTR. The content of @desc is
+ * copied.
+ */
+struct usb_role_switch *
+usb_role_switch_register(struct device *parent,
+ const struct usb_role_switch_desc *desc)
+{
+ struct usb_role_switch *sw;
+ int ret;
+
+ if (!desc || !desc->set)
+ return ERR_PTR(-EINVAL);
+
+ sw = kzalloc(sizeof(*sw), GFP_KERNEL);
+ if (!sw)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&sw->lock);
+
+ sw->allow_userspace_control = desc->allow_userspace_control;
+ sw->usb2_port = desc->usb2_port;
+ sw->usb3_port = desc->usb3_port;
+ sw->udc = desc->udc;
+ sw->set = desc->set;
+ sw->get = desc->get;
+
+ sw->dev.parent = parent;
+ sw->dev.class = role_class;
+ sw->dev.type = &usb_role_dev_type;
+ dev_set_name(&sw->dev, "%s-role-switch", dev_name(parent));
+
+ ret = device_register(&sw->dev);
+ if (ret) {
+ put_device(&sw->dev);
+ return ERR_PTR(ret);
+ }
+
+ /* TODO: Symlinks for the host port and the device controller. */
+
+ return sw;
+}
+EXPORT_SYMBOL_GPL(usb_role_switch_register);
+
+/**
+ * usb_role_switch_unregister - Unregsiter USB Role Switch
+ * @sw: USB Role Switch
+ *
+ * Unregister switch that was registered with usb_role_switch_register().
+ */
+void usb_role_switch_unregister(struct usb_role_switch *sw)
+{
+ if (!IS_ERR_OR_NULL(sw))
+ device_unregister(&sw->dev);
+}
+EXPORT_SYMBOL_GPL(usb_role_switch_unregister);
+
+static int __init usb_roles_init(void)
+{
+ role_class = class_create(THIS_MODULE, "usb_role");
+ return PTR_ERR_OR_ZERO(role_class);
+}
+subsys_initcall(usb_roles_init);
+
+static void __exit usb_roles_exit(void)
+{
+ class_destroy(role_class);
+}
+module_exit(usb_roles_exit);
+
+MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("USB Role Class");
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index 92c9cefb4317..18e874b0441e 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -6,7 +6,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 += phy.o port.o
usbcore-$(CONFIG_OF) += of.o
usbcore-$(CONFIG_USB_PCI) += hcd-pci.o
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 83c14dda6300..bc8242bc4564 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -210,8 +210,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
if (!udev->parent)
rc = hcd_bus_suspend(udev, msg);
- /* Non-root devices don't need to do anything for FREEZE or PRETHAW */
- else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+ /*
+ * Non-root USB2 devices don't need to do anything for FREEZE
+ * or PRETHAW. USB3 devices don't support global suspend and
+ * needs to be selectively suspended.
+ */
+ else if ((msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+ && (udev->speed < USB_SPEED_SUPER))
rc = 0;
else
rc = usb_port_suspend(udev, msg);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index fc32391a34d5..777036ae6367 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -37,6 +37,7 @@
#include <linux/usb/otg.h>
#include "usb.h"
+#include "phy.h"
/*-------------------------------------------------------------------------*/
@@ -2260,6 +2261,9 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
usb_set_device_state(rhdev, USB_STATE_SUSPENDED);
hcd->state = HC_STATE_SUSPENDED;
+ if (!PMSG_IS_AUTO(msg))
+ usb_phy_roothub_power_off(hcd->phy_roothub);
+
/* Did we race with a root-hub wakeup event? */
if (rhdev->do_remote_wakeup) {
char buffer[6];
@@ -2296,6 +2300,13 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
dev_dbg(&rhdev->dev, "skipped %s of dead bus\n", "resume");
return 0;
}
+
+ if (!PMSG_IS_AUTO(msg)) {
+ status = usb_phy_roothub_power_on(hcd->phy_roothub);
+ if (status)
+ return status;
+ }
+
if (!hcd->driver->bus_resume)
return -ENOENT;
if (HCD_RH_RUNNING(hcd))
@@ -2333,6 +2344,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
}
} else {
hcd->state = old_state;
+ usb_phy_roothub_power_off(hcd->phy_roothub);
dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
"resume", status);
if (status != -ESHUTDOWN)
@@ -2727,7 +2739,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
int retval;
struct usb_device *rhdev;
- if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->usb_phy) {
+ if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->skip_phy_initialization) {
struct usb_phy *phy = usb_get_phy_dev(hcd->self.sysdev, 0);
if (IS_ERR(phy)) {
@@ -2745,28 +2757,16 @@ int usb_add_hcd(struct usb_hcd *hcd,
}
}
- if (IS_ENABLED(CONFIG_GENERIC_PHY) && !hcd->phy) {
- struct phy *phy = phy_get(hcd->self.sysdev, "usb");
-
- if (IS_ERR(phy)) {
- retval = PTR_ERR(phy);
- if (retval == -EPROBE_DEFER)
- goto err_phy;
- } else {
- retval = phy_init(phy);
- if (retval) {
- phy_put(phy);
- goto err_phy;
- }
- retval = phy_power_on(phy);
- if (retval) {
- phy_exit(phy);
- phy_put(phy);
- goto err_phy;
- }
- hcd->phy = phy;
- hcd->remove_phy = 1;
+ if (!hcd->skip_phy_initialization && usb_hcd_is_primary_hcd(hcd)) {
+ hcd->phy_roothub = usb_phy_roothub_init(hcd->self.sysdev);
+ if (IS_ERR(hcd->phy_roothub)) {
+ retval = PTR_ERR(hcd->phy_roothub);
+ goto err_phy_roothub_init;
}
+
+ retval = usb_phy_roothub_power_on(hcd->phy_roothub);
+ if (retval)
+ goto err_usb_phy_roothub_power_on;
}
dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
@@ -2933,13 +2933,10 @@ err_allocate_root_hub:
err_register_bus:
hcd_buffer_destroy(hcd);
err_create_buf:
- if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->remove_phy && hcd->phy) {
- phy_power_off(hcd->phy);
- phy_exit(hcd->phy);
- phy_put(hcd->phy);
- hcd->phy = NULL;
- }
-err_phy:
+ usb_phy_roothub_power_off(hcd->phy_roothub);
+err_usb_phy_roothub_power_on:
+ usb_phy_roothub_exit(hcd->phy_roothub);
+err_phy_roothub_init:
if (hcd->remove_phy && hcd->usb_phy) {
usb_phy_shutdown(hcd->usb_phy);
usb_put_phy(hcd->usb_phy);
@@ -3017,12 +3014,9 @@ void usb_remove_hcd(struct usb_hcd *hcd)
usb_deregister_bus(&hcd->self);
hcd_buffer_destroy(hcd);
- if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->remove_phy && hcd->phy) {
- phy_power_off(hcd->phy);
- phy_exit(hcd->phy);
- phy_put(hcd->phy);
- hcd->phy = NULL;
- }
+ usb_phy_roothub_power_off(hcd->phy_roothub);
+ usb_phy_roothub_exit(hcd->phy_roothub);
+
if (hcd->remove_phy && hcd->usb_phy) {
usb_phy_shutdown(hcd->usb_phy);
usb_put_phy(hcd->usb_phy);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index c5c1f6cf3228..f6ea16e9f6bb 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2192,9 +2192,13 @@ static void show_string(struct usb_device *udev, char *id, char *string)
static void announce_device(struct usb_device *udev)
{
- dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",
+ u16 bcdDevice = le16_to_cpu(udev->descriptor.bcdDevice);
+
+ dev_info(&udev->dev,
+ "New USB device found, idVendor=%04x, idProduct=%04x, bcdDevice=%2x.%02x\n",
le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
+ le16_to_cpu(udev->descriptor.idProduct),
+ bcdDevice >> 8, bcdDevice & 0xff);
dev_info(&udev->dev,
"New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
udev->descriptor.iManufacturer,
@@ -3655,7 +3659,7 @@ static int hub_reset_resume(struct usb_interface *intf)
*/
void usb_root_hub_lost_power(struct usb_device *rhdev)
{
- dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
+ dev_notice(&rhdev->dev, "root hub lost power or was reset\n");
rhdev->reset_resume = 1;
}
EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
@@ -5104,8 +5108,10 @@ static void port_event(struct usb_hub *hub, int port1)
if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
u16 status = 0, unused;
+ port_dev->over_current_count++;
- dev_dbg(&port_dev->dev, "over-current change\n");
+ dev_dbg(&port_dev->dev, "over-current change #%u\n",
+ port_dev->over_current_count);
usb_clear_port_feature(hdev, port1,
USB_PORT_FEAT_C_OVER_CURRENT);
msleep(100); /* Cool down */
@@ -5505,21 +5511,15 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
if (udev->usb2_hw_lpm_enabled == 1)
usb_set_usb2_hardware_lpm(udev, 0);
- /* Disable LPM and LTM while we reset the device and reinstall the alt
- * settings. Device-initiated LPM settings, and system exit latency
- * settings are cleared when the device is reset, so we have to set
- * them up again.
+ /* Disable LPM while we reset the device and reinstall the alt settings.
+ * Device-initiated LPM, and system exit latency settings are cleared
+ * when the device is reset, so we have to set them up again.
*/
ret = usb_unlocked_disable_lpm(udev);
if (ret) {
dev_err(&udev->dev, "%s Failed to disable LPM\n", __func__);
goto re_enumerate_no_bos;
}
- ret = usb_disable_ltm(udev);
- if (ret) {
- dev_err(&udev->dev, "%s Failed to disable LTM\n", __func__);
- goto re_enumerate_no_bos;
- }
bos = udev->bos;
udev->bos = NULL;
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index 2a700ccc868c..4dc769ee9c74 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -96,6 +96,7 @@ struct usb_port {
enum usb_port_connect_type connect_type;
usb_port_location_t location;
struct mutex status_lock;
+ u32 over_current_count;
u8 portnum;
unsigned int is_superspeed:1;
unsigned int usb3_lpm_u1_permit:1;
diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c
new file mode 100644
index 000000000000..09b7c43c0ea4
--- /dev/null
+++ b/drivers/usb/core/phy.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * A wrapper for multiple PHYs which passes all phy_* function calls to
+ * multiple (actual) PHY devices. This is comes handy when initializing
+ * all PHYs on a HCD and to keep them all in the same state.
+ *
+ * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ */
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/phy/phy.h>
+#include <linux/of.h>
+
+#include "phy.h"
+
+struct usb_phy_roothub {
+ struct phy *phy;
+ struct list_head list;
+};
+
+static struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev)
+{
+ struct usb_phy_roothub *roothub_entry;
+
+ roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL);
+ if (!roothub_entry)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&roothub_entry->list);
+
+ return roothub_entry;
+}
+
+static int usb_phy_roothub_add_phy(struct device *dev, int index,
+ struct list_head *list)
+{
+ struct usb_phy_roothub *roothub_entry;
+ struct phy *phy = devm_of_phy_get_by_index(dev, dev->of_node, index);
+
+ if (IS_ERR_OR_NULL(phy)) {
+ if (!phy || PTR_ERR(phy) == -ENODEV)
+ return 0;
+ else
+ return PTR_ERR(phy);
+ }
+
+ roothub_entry = usb_phy_roothub_alloc(dev);
+ if (IS_ERR(roothub_entry))
+ return PTR_ERR(roothub_entry);
+
+ roothub_entry->phy = phy;
+
+ list_add_tail(&roothub_entry->list, list);
+
+ return 0;
+}
+
+struct usb_phy_roothub *usb_phy_roothub_init(struct device *dev)
+{
+ struct usb_phy_roothub *phy_roothub;
+ struct usb_phy_roothub *roothub_entry;
+ struct list_head *head;
+ int i, num_phys, err;
+
+ num_phys = of_count_phandle_with_args(dev->of_node, "phys",
+ "#phy-cells");
+ if (num_phys <= 0)
+ return NULL;
+
+ phy_roothub = usb_phy_roothub_alloc(dev);
+ if (IS_ERR(phy_roothub))
+ return phy_roothub;
+
+ for (i = 0; i < num_phys; i++) {
+ err = usb_phy_roothub_add_phy(dev, i, &phy_roothub->list);
+ if (err)
+ goto err_out;
+ }
+
+ head = &phy_roothub->list;
+
+ list_for_each_entry(roothub_entry, head, list) {
+ err = phy_init(roothub_entry->phy);
+ if (err)
+ goto err_exit_phys;
+ }
+
+ return phy_roothub;
+
+err_exit_phys:
+ list_for_each_entry_continue_reverse(roothub_entry, head, list)
+ phy_exit(roothub_entry->phy);
+
+err_out:
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_init);
+
+int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub)
+{
+ struct usb_phy_roothub *roothub_entry;
+ struct list_head *head;
+ int err, ret = 0;
+
+ if (!phy_roothub)
+ return 0;
+
+ head = &phy_roothub->list;
+
+ list_for_each_entry(roothub_entry, head, list) {
+ err = phy_exit(roothub_entry->phy);
+ if (err)
+ ret = ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_exit);
+
+int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub)
+{
+ struct usb_phy_roothub *roothub_entry;
+ struct list_head *head;
+ int err;
+
+ if (!phy_roothub)
+ return 0;
+
+ head = &phy_roothub->list;
+
+ list_for_each_entry(roothub_entry, head, list) {
+ err = phy_power_on(roothub_entry->phy);
+ if (err)
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ list_for_each_entry_continue_reverse(roothub_entry, head, list)
+ phy_power_off(roothub_entry->phy);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_power_on);
+
+void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub)
+{
+ struct usb_phy_roothub *roothub_entry;
+
+ if (!phy_roothub)
+ return;
+
+ list_for_each_entry_reverse(roothub_entry, &phy_roothub->list, list)
+ phy_power_off(roothub_entry->phy);
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off);
diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h
new file mode 100644
index 000000000000..6fde59bfbff8
--- /dev/null
+++ b/drivers/usb/core/phy.h
@@ -0,0 +1,7 @@
+struct usb_phy_roothub;
+
+struct usb_phy_roothub *usb_phy_roothub_init(struct device *dev);
+int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub);
+
+int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub);
+void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub);
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index 1a01e9ad3804..6979bde87d31 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -41,6 +41,15 @@ static ssize_t connect_type_show(struct device *dev,
}
static DEVICE_ATTR_RO(connect_type);
+static ssize_t over_current_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_port *port_dev = to_usb_port(dev);
+
+ return sprintf(buf, "%u\n", port_dev->over_current_count);
+}
+static DEVICE_ATTR_RO(over_current_count);
+
static ssize_t usb3_lpm_permit_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -109,6 +118,7 @@ static DEVICE_ATTR_RW(usb3_lpm_permit);
static struct attribute *port_dev_attrs[] = {
&dev_attr_connect_type.attr,
+ &dev_attr_over_current_count.attr,
NULL,
};
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 54b019e267c5..920f48a49a87 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -6,11 +6,157 @@
* Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
*/
+#include <linux/moduleparam.h>
#include <linux/usb.h>
#include <linux/usb/quirks.h>
#include <linux/usb/hcd.h>
#include "usb.h"
+struct quirk_entry {
+ u16 vid;
+ u16 pid;
+ u32 flags;
+};
+
+static DEFINE_MUTEX(quirk_mutex);
+
+static struct quirk_entry *quirk_list;
+static unsigned int quirk_count;
+
+static char quirks_param[128];
+
+static int quirks_param_set(const char *val, const struct kernel_param *kp)
+{
+ char *p, *field;
+ u16 vid, pid;
+ u32 flags;
+ size_t i;
+ int err;
+
+ err = param_set_copystring(val, kp);
+ if (err)
+ return err;
+
+ mutex_lock(&quirk_mutex);
+
+ if (!*val) {
+ quirk_count = 0;
+ kfree(quirk_list);
+ quirk_list = NULL;
+ goto unlock;
+ }
+
+ for (quirk_count = 1, i = 0; val[i]; i++)
+ if (val[i] == ',')
+ quirk_count++;
+
+ if (quirk_list) {
+ kfree(quirk_list);
+ quirk_list = NULL;
+ }
+
+ quirk_list = kcalloc(quirk_count, sizeof(struct quirk_entry),
+ GFP_KERNEL);
+ if (!quirk_list) {
+ mutex_unlock(&quirk_mutex);
+ return -ENOMEM;
+ }
+
+ for (i = 0, p = (char *)val; p && *p;) {
+ /* Each entry consists of VID:PID:flags */
+ field = strsep(&p, ":");
+ if (!field)
+ break;
+
+ if (kstrtou16(field, 16, &vid))
+ break;
+
+ field = strsep(&p, ":");
+ if (!field)
+ break;
+
+ if (kstrtou16(field, 16, &pid))
+ break;
+
+ field = strsep(&p, ",");
+ if (!field || !*field)
+ break;
+
+ /* Collect the flags */
+ for (flags = 0; *field; field++) {
+ switch (*field) {
+ case 'a':
+ flags |= USB_QUIRK_STRING_FETCH_255;
+ break;
+ case 'b':
+ flags |= USB_QUIRK_RESET_RESUME;
+ break;
+ case 'c':
+ flags |= USB_QUIRK_NO_SET_INTF;
+ break;
+ case 'd':
+ flags |= USB_QUIRK_CONFIG_INTF_STRINGS;
+ break;
+ case 'e':
+ flags |= USB_QUIRK_RESET;
+ break;
+ case 'f':
+ flags |= USB_QUIRK_HONOR_BNUMINTERFACES;
+ break;
+ case 'g':
+ flags |= USB_QUIRK_DELAY_INIT;
+ break;
+ case 'h':
+ flags |= USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL;
+ break;
+ case 'i':
+ flags |= USB_QUIRK_DEVICE_QUALIFIER;
+ break;
+ case 'j':
+ flags |= USB_QUIRK_IGNORE_REMOTE_WAKEUP;
+ break;
+ case 'k':
+ flags |= USB_QUIRK_NO_LPM;
+ break;
+ case 'l':
+ flags |= USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL;
+ break;
+ case 'm':
+ flags |= USB_QUIRK_DISCONNECT_SUSPEND;
+ break;
+ case 'n':
+ flags |= USB_QUIRK_DELAY_CTRL_MSG;
+ break;
+ /* Ignore unrecognized flag characters */
+ }
+ }
+
+ quirk_list[i++] = (struct quirk_entry)
+ { .vid = vid, .pid = pid, .flags = flags };
+ }
+
+ if (i < quirk_count)
+ quirk_count = i;
+
+unlock:
+ mutex_unlock(&quirk_mutex);
+
+ return 0;
+}
+
+static const struct kernel_param_ops quirks_param_ops = {
+ .set = quirks_param_set,
+ .get = param_get_string,
+};
+
+static struct kparam_string quirks_param_string = {
+ .maxlen = sizeof(quirks_param),
+ .string = quirks_param,
+};
+
+module_param_cb(quirks, &quirks_param_ops, &quirks_param_string, 0644);
+MODULE_PARM_DESC(quirks, "Add/modify USB quirks by specifying quirks=vendorID:productID:quirks");
+
/* Lists of quirky USB devices, split in device quirks and interface quirks.
* Device quirks are applied at the very beginning of the enumeration process,
* right after reading the device descriptor. They can thus only match on device
@@ -321,8 +467,8 @@ static int usb_amd_resume_quirk(struct usb_device *udev)
return 0;
}
-static u32 __usb_detect_quirks(struct usb_device *udev,
- const struct usb_device_id *id)
+static u32 usb_detect_static_quirks(struct usb_device *udev,
+ const struct usb_device_id *id)
{
u32 quirks = 0;
@@ -340,21 +486,43 @@ static u32 __usb_detect_quirks(struct usb_device *udev,
return quirks;
}
+static u32 usb_detect_dynamic_quirks(struct usb_device *udev)
+{
+ u16 vid = le16_to_cpu(udev->descriptor.idVendor);
+ u16 pid = le16_to_cpu(udev->descriptor.idProduct);
+ int i, flags = 0;
+
+ mutex_lock(&quirk_mutex);
+
+ for (i = 0; i < quirk_count; i++) {
+ if (vid == quirk_list[i].vid && pid == quirk_list[i].pid) {
+ flags = quirk_list[i].flags;
+ break;
+ }
+ }
+
+ mutex_unlock(&quirk_mutex);
+
+ return flags;
+}
+
/*
* Detect any quirks the device has, and do any housekeeping for it if needed.
*/
void usb_detect_quirks(struct usb_device *udev)
{
- udev->quirks = __usb_detect_quirks(udev, usb_quirk_list);
+ udev->quirks = usb_detect_static_quirks(udev, usb_quirk_list);
/*
* Pixart-based mice would trigger remote wakeup issue on AMD
* Yangtze chipset, so set them as RESET_RESUME flag.
*/
if (usb_amd_resume_quirk(udev))
- udev->quirks |= __usb_detect_quirks(udev,
+ udev->quirks |= usb_detect_static_quirks(udev,
usb_amd_resume_quirk_list);
+ udev->quirks ^= usb_detect_dynamic_quirks(udev);
+
if (udev->quirks)
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
udev->quirks);
@@ -373,7 +541,7 @@ void usb_detect_interface_quirks(struct usb_device *udev)
{
u32 quirks;
- quirks = __usb_detect_quirks(udev, usb_interface_quirk_list);
+ quirks = usb_detect_static_quirks(udev, usb_interface_quirk_list);
if (quirks == 0)
return;
@@ -381,3 +549,11 @@ void usb_detect_interface_quirks(struct usb_device *udev)
quirks);
udev->quirks |= quirks;
}
+
+void usb_release_quirk_list(void)
+{
+ mutex_lock(&quirk_mutex);
+ kfree(quirk_list);
+ quirk_list = NULL;
+ mutex_unlock(&quirk_mutex);
+}
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 796c9b149728..f51750bcd152 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -433,6 +433,14 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
max *= mult;
}
+ if (dev->speed == USB_SPEED_SUPER_PLUS &&
+ USB_SS_SSP_ISOC_COMP(ep->ss_ep_comp.bmAttributes)) {
+ struct usb_ssp_isoc_ep_comp_descriptor *isoc_ep_comp;
+
+ isoc_ep_comp = &ep->ssp_isoc_ep_comp;
+ max = le32_to_cpu(isoc_ep_comp->dwBytesPerInterval);
+ }
+
/* "high bandwidth" mode, 1-3 packets/uframe? */
if (dev->speed == USB_SPEED_HIGH)
max *= usb_endpoint_maxp_mult(&ep->desc);
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index 84da17460568..e221861b3187 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -90,8 +90,8 @@ static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle,
acpi_status status;
/*
- * According to ACPI Spec 9.13. PLD indicates whether usb port is
- * user visible and _UPC indicates whether it is connectable. If
+ * According to 9.14 in ACPI Spec 6.2. _PLD indicates whether usb port
+ * is user visible and _UPC indicates whether it is connectable. If
* the port was visible and connectable, it could be freely connected
* and disconnected with USB devices. If no visible and connectable,
* a usb device is directly hard-wired to the port. If no visible and
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 2f5fbc56a9dd..0adb6345ff2e 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1259,6 +1259,7 @@ static void __exit usb_exit(void)
if (usb_disabled())
return;
+ usb_release_quirk_list();
usb_deregister_device_driver(&usb_generic_driver);
usb_major_cleanup();
usb_deregister(&usbfs_driver);
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 149cc7480971..546a2219454b 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -36,6 +36,7 @@ extern void usb_deauthorize_interface(struct usb_interface *);
extern void usb_authorize_interface(struct usb_interface *);
extern void usb_detect_quirks(struct usb_device *udev);
extern void usb_detect_interface_quirks(struct usb_device *udev);
+extern void usb_release_quirk_list(void);
extern int usb_remove_device(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev,
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index 82a7d98c3436..18a0a1771289 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -64,10 +64,11 @@
*
* @hsotg: Programming view of the DWC_otg controller
*/
-static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
+int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
{
struct dwc2_gregs_backup *gr;
- int i;
+
+ dev_dbg(hsotg->dev, "%s\n", __func__);
/* Backup global regs */
gr = &hsotg->gr_backup;
@@ -78,10 +79,11 @@ static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
gr->gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
gr->grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ);
gr->gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
- gr->hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ);
gr->gdfifocfg = dwc2_readl(hsotg->regs + GDFIFOCFG);
- for (i = 0; i < MAX_EPS_CHANNELS; i++)
- gr->dtxfsiz[i] = dwc2_readl(hsotg->regs + DPTXFSIZN(i));
+ gr->pcgcctl1 = dwc2_readl(hsotg->regs + PCGCCTL1);
+ gr->glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
+ gr->gi2cctl = dwc2_readl(hsotg->regs + GI2CCTL);
+ gr->pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
gr->valid = true;
return 0;
@@ -94,10 +96,9 @@ static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
*
* @hsotg: Programming view of the DWC_otg controller
*/
-static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
+int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
{
struct dwc2_gregs_backup *gr;
- int i;
dev_dbg(hsotg->dev, "%s\n", __func__);
@@ -117,26 +118,27 @@ static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
dwc2_writel(gr->gahbcfg, hsotg->regs + GAHBCFG);
dwc2_writel(gr->grxfsiz, hsotg->regs + GRXFSIZ);
dwc2_writel(gr->gnptxfsiz, hsotg->regs + GNPTXFSIZ);
- dwc2_writel(gr->hptxfsiz, hsotg->regs + HPTXFSIZ);
dwc2_writel(gr->gdfifocfg, hsotg->regs + GDFIFOCFG);
- for (i = 0; i < MAX_EPS_CHANNELS; i++)
- dwc2_writel(gr->dtxfsiz[i], hsotg->regs + DPTXFSIZN(i));
+ dwc2_writel(gr->pcgcctl1, hsotg->regs + PCGCCTL1);
+ dwc2_writel(gr->glpmcfg, hsotg->regs + GLPMCFG);
+ dwc2_writel(gr->pcgcctl, hsotg->regs + PCGCTL);
+ dwc2_writel(gr->gi2cctl, hsotg->regs + GI2CCTL);
return 0;
}
/**
- * dwc2_exit_hibernation() - Exit controller from Partial Power Down.
+ * dwc2_exit_partial_power_down() - Exit controller from Partial Power Down.
*
* @hsotg: Programming view of the DWC_otg controller
* @restore: Controller registers need to be restored
*/
-int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore)
+int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore)
{
u32 pcgcctl;
int ret = 0;
- if (!hsotg->params.hibernation)
+ if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL)
return -ENOTSUPP;
pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
@@ -167,7 +169,7 @@ int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore)
return ret;
}
} else {
- ret = dwc2_restore_device_registers(hsotg);
+ ret = dwc2_restore_device_registers(hsotg, 0);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore device registers\n",
__func__);
@@ -180,16 +182,16 @@ int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore)
}
/**
- * dwc2_enter_hibernation() - Put controller in Partial Power Down.
+ * dwc2_enter_partial_power_down() - Put controller in Partial Power Down.
*
* @hsotg: Programming view of the DWC_otg controller
*/
-int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg)
+int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg)
{
u32 pcgcctl;
int ret = 0;
- if (!hsotg->params.hibernation)
+ if (!hsotg->params.power_down)
return -ENOTSUPP;
/* Backup all registers */
@@ -218,7 +220,7 @@ int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg)
/*
* Clear any pending interrupts since dwc2 will not be able to
- * clear them after entering hibernation.
+ * clear them after entering partial_power_down.
*/
dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
@@ -240,6 +242,142 @@ int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg)
}
/**
+ * dwc2_restore_essential_regs() - Restore essiential regs of core.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ * @rmode: Restore mode, enabled in case of remote-wakeup.
+ * @is_host: Host or device mode.
+ */
+static void dwc2_restore_essential_regs(struct dwc2_hsotg *hsotg, int rmode,
+ int is_host)
+{
+ u32 pcgcctl;
+ struct dwc2_gregs_backup *gr;
+ struct dwc2_dregs_backup *dr;
+ struct dwc2_hregs_backup *hr;
+
+ gr = &hsotg->gr_backup;
+ dr = &hsotg->dr_backup;
+ hr = &hsotg->hr_backup;
+
+ dev_dbg(hsotg->dev, "%s: restoring essential regs\n", __func__);
+
+ /* Load restore values for [31:14] bits */
+ pcgcctl = (gr->pcgcctl & 0xffffc000);
+ /* If High Speed */
+ if (is_host) {
+ if (!(pcgcctl & PCGCTL_P2HD_PRT_SPD_MASK))
+ pcgcctl |= BIT(17);
+ } else {
+ if (!(pcgcctl & PCGCTL_P2HD_DEV_ENUM_SPD_MASK))
+ pcgcctl |= BIT(17);
+ }
+ dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+
+ /* Umnask global Interrupt in GAHBCFG and restore it */
+ dwc2_writel(gr->gahbcfg | GAHBCFG_GLBL_INTR_EN, hsotg->regs + GAHBCFG);
+
+ /* Clear all pending interupts */
+ dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+
+ /* Unmask restore done interrupt */
+ dwc2_writel(GINTSTS_RESTOREDONE, hsotg->regs + GINTMSK);
+
+ /* Restore GUSBCFG and HCFG/DCFG */
+ dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG);
+
+ if (is_host) {
+ dwc2_writel(hr->hcfg, hsotg->regs + HCFG);
+ if (rmode)
+ pcgcctl |= PCGCTL_RESTOREMODE;
+ dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+ udelay(10);
+
+ pcgcctl |= PCGCTL_ESS_REG_RESTORED;
+ dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+ udelay(10);
+ } else {
+ dwc2_writel(dr->dcfg, hsotg->regs + DCFG);
+ if (!rmode)
+ pcgcctl |= PCGCTL_RESTOREMODE | PCGCTL_RSTPDWNMODULE;
+ dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+ udelay(10);
+
+ pcgcctl |= PCGCTL_ESS_REG_RESTORED;
+ dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+ udelay(10);
+ }
+}
+
+/**
+ * dwc2_hib_restore_common() - Common part of restore routine.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup.
+ * @is_host: Host or device mode.
+ */
+void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup,
+ int is_host)
+{
+ u32 gpwrdn;
+
+ /* Switch-on voltage to the core */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn &= ~GPWRDN_PWRDNSWTCH;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Reset core */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn &= ~GPWRDN_PWRDNRSTN;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Enable restore from PMU */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn |= GPWRDN_RESTORE;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Disable Power Down Clamp */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn &= ~GPWRDN_PWRDNCLMP;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(50);
+
+ if (!is_host && rem_wakeup)
+ udelay(70);
+
+ /* Deassert reset core */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn |= GPWRDN_PWRDNRSTN;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Disable PMU interrupt */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn &= ~GPWRDN_PMUINTSEL;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Set Restore Essential Regs bit in PCGCCTL register */
+ dwc2_restore_essential_regs(hsotg, rem_wakeup, is_host);
+
+ /*
+ * Wait For Restore_done Interrupt. This mechanism of polling the
+ * interrupt is introduced to avoid any possible race conditions
+ */
+ if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, GINTSTS_RESTOREDONE,
+ 20000)) {
+ dev_dbg(hsotg->dev,
+ "%s: Restore Done wan't generated here\n",
+ __func__);
+ } else {
+ dev_dbg(hsotg->dev, "restore done generated here\n");
+ }
+}
+
+/**
* dwc2_wait_for_mode() - Waits for the controller mode.
* @hsotg: Programming view of the DWC_otg controller.
* @host_mode: If true, waits for host mode, otherwise device mode.
@@ -311,13 +449,50 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)
}
/*
+ * dwc2_enter_hibernation() - Common function to enter hibernation.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ * @is_host: True if core is in host mode.
+ *
+ * Return: 0 if successful, negative error code otherwise
+ */
+int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host)
+{
+ if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_HIBERNATION)
+ return -ENOTSUPP;
+
+ if (is_host)
+ return dwc2_host_enter_hibernation(hsotg);
+ else
+ return dwc2_gadget_enter_hibernation(hsotg);
+}
+
+/*
+ * dwc2_exit_hibernation() - Common function to exit from hibernation.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ * @rem_wakeup: Remote-wakeup, enabled in case of remote-wakeup.
+ * @reset: Enabled in case of restore with reset.
+ * @is_host: True if core is in host mode.
+ *
+ * Return: 0 if successful, negative error code otherwise
+ */
+int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
+ int reset, int is_host)
+{
+ if (is_host)
+ return dwc2_host_exit_hibernation(hsotg, rem_wakeup, reset);
+ else
+ return dwc2_gadget_exit_hibernation(hsotg, rem_wakeup, reset);
+}
+
+/*
* Do core a soft reset of the core. Be careful with this because it
* resets all the internal state machines of the core.
*/
int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
{
u32 greset;
- int count = 0;
bool wait_for_host_mode = false;
dev_vdbg(hsotg->dev, "%s()\n", __func__);
@@ -346,29 +521,19 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
greset = dwc2_readl(hsotg->regs + GRSTCTL);
greset |= GRSTCTL_CSFTRST;
dwc2_writel(greset, hsotg->regs + GRSTCTL);
- do {
- udelay(1);
- greset = dwc2_readl(hsotg->regs + GRSTCTL);
- if (++count > 50) {
- dev_warn(hsotg->dev,
- "%s() HANG! Soft Reset GRSTCTL=%0x\n",
- __func__, greset);
- return -EBUSY;
- }
- } while (greset & GRSTCTL_CSFTRST);
+
+ if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 50)) {
+ dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n",
+ __func__);
+ return -EBUSY;
+ }
/* Wait for AHB master IDLE state */
- count = 0;
- do {
- udelay(1);
- greset = dwc2_readl(hsotg->regs + GRSTCTL);
- if (++count > 50) {
- dev_warn(hsotg->dev,
- "%s() HANG! AHB Idle GRSTCTL=%0x\n",
- __func__, greset);
- return -EBUSY;
- }
- } while (!(greset & GRSTCTL_AHBIDLE));
+ if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 50)) {
+ dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n",
+ __func__);
+ return -EBUSY;
+ }
if (wait_for_host_mode && !skip_wait)
dwc2_wait_for_mode(hsotg, true);
@@ -376,14 +541,14 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
return 0;
}
-/*
- * Force the mode of the controller.
+/**
+ * dwc2_force_mode() - Force the mode of the controller.
*
* Forcing the mode is needed for two cases:
*
* 1) If the dr_mode is set to either HOST or PERIPHERAL we force the
* controller to stay in a particular mode regardless of ID pin
- * changes. We do this usually after a core reset.
+ * changes. We do this once during probe.
*
* 2) During probe we want to read reset values of the hw
* configuration registers that are only available in either host or
@@ -400,7 +565,7 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
* the filter is configured and enabled. We poll the current mode of
* the controller to account for this delay.
*/
-static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
+void dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
{
u32 gusbcfg;
u32 set;
@@ -412,17 +577,17 @@ static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
* Force mode has no effect if the hardware is not OTG.
*/
if (!dwc2_hw_is_otg(hsotg))
- return false;
+ return;
/*
* If dr_mode is either peripheral or host only, there is no
* need to ever force the mode to the opposite mode.
*/
if (WARN_ON(host && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL))
- return false;
+ return;
if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST))
- return false;
+ return;
gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
@@ -434,7 +599,7 @@ static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
dwc2_wait_for_mode(hsotg, host);
- return true;
+ return;
}
/**
@@ -446,10 +611,15 @@ static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
* the force mode. We only need to call this once during probe if
* dr_mode == OTG.
*/
-void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
+static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
{
u32 gusbcfg;
+ if (!dwc2_hw_is_otg(hsotg))
+ return;
+
+ dev_dbg(hsotg->dev, "Clearing force mode bits\n");
+
gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
@@ -464,16 +634,13 @@ void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
*/
void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
{
- bool ret;
-
switch (hsotg->dr_mode) {
case USB_DR_MODE_HOST:
- ret = dwc2_force_mode(hsotg, true);
/*
* NOTE: This is required for some rockchip soc based
* platforms on their host-only dwc2.
*/
- if (!ret)
+ if (!dwc2_hw_is_otg(hsotg))
msleep(50);
break;
@@ -491,22 +658,17 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
}
/*
- * Do core a soft reset of the core. Be careful with this because it
- * resets all the internal state machines of the core.
- *
- * Additionally this will apply force mode as per the hsotg->dr_mode
- * parameter.
+ * dwc2_enable_acg - enable active clock gating feature
*/
-int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg)
+void dwc2_enable_acg(struct dwc2_hsotg *hsotg)
{
- int retval;
+ if (hsotg->params.acg_enable) {
+ u32 pcgcctl1 = dwc2_readl(hsotg->regs + PCGCCTL1);
- retval = dwc2_core_reset(hsotg, false);
- if (retval)
- return retval;
-
- dwc2_force_dr_mode(hsotg);
- return 0;
+ dev_dbg(hsotg->dev, "Enabling Active Clock Gating\n");
+ pcgcctl1 |= PCGCCTL1_GATEEN;
+ dwc2_writel(pcgcctl1, hsotg->regs + PCGCCTL1);
+ }
}
/**
@@ -683,25 +845,21 @@ void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg)
void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
{
u32 greset;
- int count = 0;
dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num);
+ /* Wait for AHB master IDLE state */
+ if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000))
+ dev_warn(hsotg->dev, "%s: HANG! AHB Idle GRSCTL\n",
+ __func__);
+
greset = GRSTCTL_TXFFLSH;
greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK;
dwc2_writel(greset, hsotg->regs + GRSTCTL);
- do {
- greset = dwc2_readl(hsotg->regs + GRSTCTL);
- if (++count > 10000) {
- dev_warn(hsotg->dev,
- "%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
- __func__, greset,
- dwc2_readl(hsotg->regs + GNPTXSTS));
- break;
- }
- udelay(1);
- } while (greset & GRSTCTL_TXFFLSH);
+ if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 10000))
+ dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_TXFFLSH\n",
+ __func__);
/* Wait for at least 3 PHY Clocks */
udelay(1);
@@ -715,43 +873,26 @@ void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg)
{
u32 greset;
- int count = 0;
dev_vdbg(hsotg->dev, "%s()\n", __func__);
+ /* Wait for AHB master IDLE state */
+ if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000))
+ dev_warn(hsotg->dev, "%s: HANG! AHB Idle GRSCTL\n",
+ __func__);
+
greset = GRSTCTL_RXFFLSH;
dwc2_writel(greset, hsotg->regs + GRSTCTL);
- do {
- greset = dwc2_readl(hsotg->regs + GRSTCTL);
- if (++count > 10000) {
- dev_warn(hsotg->dev, "%s() HANG! GRSTCTL=%0x\n",
- __func__, greset);
- break;
- }
- udelay(1);
- } while (greset & GRSTCTL_RXFFLSH);
+ /* Wait for RxFIFO flush done */
+ if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_RXFFLSH, 10000))
+ dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_RXFFLSH\n",
+ __func__);
/* Wait for at least 3 PHY Clocks */
udelay(1);
}
-/*
- * Forces either host or device mode if the controller is not
- * currently in that mode.
- *
- * Returns true if the mode was forced.
- */
-bool dwc2_force_mode_if_needed(struct dwc2_hsotg *hsotg, bool host)
-{
- if (host && dwc2_is_host_mode(hsotg))
- return false;
- else if (!host && dwc2_is_device_mode(hsotg))
- return false;
-
- return dwc2_force_mode(hsotg, host);
-}
-
bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
{
if (dwc2_readl(hsotg->regs + GSNPSID) == 0xffffffff)
@@ -825,6 +966,52 @@ bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg)
(op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE);
}
+/**
+ * dwc2_hsotg_wait_bit_set - Waits for bit to be set.
+ * @hsotg: Programming view of DWC_otg controller.
+ * @offset: Register's offset where bit/bits must be set.
+ * @mask: Mask of the bit/bits which must be set.
+ * @timeout: Timeout to wait.
+ *
+ * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout.
+ */
+int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
+ u32 timeout)
+{
+ u32 i;
+
+ for (i = 0; i < timeout; i++) {
+ if (dwc2_readl(hsotg->regs + offset) & mask)
+ return 0;
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+/**
+ * dwc2_hsotg_wait_bit_clear - Waits for bit to be clear.
+ * @hsotg: Programming view of DWC_otg controller.
+ * @offset: Register's offset where bit/bits must be set.
+ * @mask: Mask of the bit/bits which must be set.
+ * @timeout: Timeout to wait.
+ *
+ * Return: 0 if bit/bits are set or -ETIMEDOUT in case of timeout.
+ */
+int dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
+ u32 timeout)
+{
+ u32 i;
+
+ for (i = 0; i < timeout; i++) {
+ if (!(dwc2_readl(hsotg->regs + offset) & mask))
+ return 0;
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
MODULE_DESCRIPTION("DESIGNWARE HS OTG Core");
MODULE_AUTHOR("Synopsys, Inc.");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index cd77af3b1565..d83be5651f87 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -217,7 +217,7 @@ struct dwc2_hsotg_ep {
unsigned char dir_in;
unsigned char index;
unsigned char mc;
- unsigned char interval;
+ u16 interval;
unsigned int halted:1;
unsigned int periodic:1;
@@ -408,7 +408,7 @@ enum dwc2_ep0_state {
* @ahbcfg: This field allows the default value of the GAHBCFG
* register to be overridden
* -1 - GAHBCFG value will be set to 0x06
- * (INCR4, default)
+ * (INCR, default)
* all others - GAHBCFG value will be overridden with
* this value
* Not all bits can be controlled like this, the
@@ -421,12 +421,26 @@ enum dwc2_ep0_state {
* case.
* 0 - No (default)
* 1 - Yes
- * @hibernation: Specifies whether the controller support hibernation.
- * If hibernation is enabled, the controller will enter
- * hibernation in both peripheral and host mode when
+ * @power_down: Specifies whether the controller support power_down.
+ * If power_down is enabled, the controller will enter
+ * power_down in both peripheral and host mode when
* needed.
* 0 - No (default)
+ * 1 - Partial power down
+ * 2 - Hibernation
+ * @lpm: Enable LPM support.
+ * 0 - No
* 1 - Yes
+ * @lpm_clock_gating: Enable core PHY clock gating.
+ * 0 - No
+ * 1 - Yes
+ * @besl: Enable LPM Errata support.
+ * 0 - No
+ * 1 - Yes
+ * @hird_threshold_en: HIRD or HIRD Threshold enable.
+ * 0 - No
+ * 1 - Yes
+ * @hird_threshold: Value of BESL or HIRD Threshold.
* @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO
* register.
* 0 - Deactivate the transceiver (default)
@@ -479,12 +493,23 @@ struct dwc2_core_params {
bool enable_dynamic_fifo;
bool en_multiple_tx_fifo;
bool i2c_enable;
+ bool acg_enable;
bool ulpi_fs_ls;
bool ts_dline;
bool reload_ctl;
bool uframe_sched;
bool external_id_pin_ctl;
- bool hibernation;
+
+ int power_down;
+#define DWC2_POWER_DOWN_PARAM_NONE 0
+#define DWC2_POWER_DOWN_PARAM_PARTIAL 1
+#define DWC2_POWER_DOWN_PARAM_HIBERNATION 2
+
+ bool lpm;
+ bool lpm_clock_gating;
+ bool besl;
+ bool hird_threshold_en;
+ u8 hird_threshold;
bool activate_stm_fs_transceiver;
u16 max_packet_count;
u32 max_transfer_size;
@@ -560,6 +585,7 @@ struct dwc2_core_params {
* 2 - FS pins shared with UTMI+ pins
* 3 - FS pins shared with ULPI pins
* @total_fifo_size: Total internal RAM for FIFOs (bytes)
+ * @hibernation Is hibernation enabled?
* @utmi_phy_data_width UTMI+ PHY data width
* 0 - 8 bits
* 1 - 16 bits
@@ -587,12 +613,15 @@ struct dwc2_hw_params {
unsigned hs_phy_type:2;
unsigned fs_phy_type:2;
unsigned i2c_enable:1;
+ unsigned acg_enable:1;
unsigned num_dev_ep:4;
unsigned num_dev_in_eps : 4;
unsigned num_dev_perio_in_ep:4;
unsigned total_fifo_size:16;
unsigned power_optimized:1;
+ unsigned hibernation:1;
unsigned utmi_phy_data_width:2;
+ unsigned lpm_mode:1;
u32 snpsid;
u32 dev_ep_dirs;
u32 g_tx_fifo_size[MAX_EPS_CHANNELS];
@@ -611,9 +640,8 @@ struct dwc2_hw_params {
* @grxfsiz: Backup of GRXFSIZ register
* @gnptxfsiz: Backup of GNPTXFSIZ register
* @gi2cctl: Backup of GI2CCTL register
- * @hptxfsiz: Backup of HPTXFSIZ register
+ * @glpmcfg: Backup of GLPMCFG register
* @gdfifocfg: Backup of GDFIFOCFG register
- * @dtxfsiz: Backup of DTXFSIZ registers for each endpoint
* @gpwrdn: Backup of GPWRDN register
*/
struct dwc2_gregs_backup {
@@ -624,10 +652,10 @@ struct dwc2_gregs_backup {
u32 grxfsiz;
u32 gnptxfsiz;
u32 gi2cctl;
- u32 hptxfsiz;
+ u32 glpmcfg;
u32 pcgcctl;
+ u32 pcgcctl1;
u32 gdfifocfg;
- u32 dtxfsiz[MAX_EPS_CHANNELS];
u32 gpwrdn;
bool valid;
};
@@ -646,6 +674,7 @@ struct dwc2_gregs_backup {
* @doepctl: Backup of DOEPCTL register
* @doeptsiz: Backup of DOEPTSIZ register
* @doepdma: Backup of DOEPDMA register
+ * @dtxfsiz: Backup of DTXFSIZ registers for each endpoint
*/
struct dwc2_dregs_backup {
u32 dcfg;
@@ -659,6 +688,7 @@ struct dwc2_dregs_backup {
u32 doepctl[MAX_EPS_CHANNELS];
u32 doeptsiz[MAX_EPS_CHANNELS];
u32 doepdma[MAX_EPS_CHANNELS];
+ u32 dtxfsiz[MAX_EPS_CHANNELS];
bool valid;
};
@@ -670,6 +700,7 @@ struct dwc2_dregs_backup {
* @hcintmsk: Backup of HCINTMSK register
* @hptr0: Backup of HPTR0 register
* @hfir: Backup of HFIR register
+ * @hptxfsiz: Backup of HPTXFSIZ register
*/
struct dwc2_hregs_backup {
u32 hcfg;
@@ -677,6 +708,7 @@ struct dwc2_hregs_backup {
u32 hcintmsk[MAX_EPS_CHANNELS];
u32 hprt0;
u32 hfir;
+ u32 hptxfsiz;
bool valid;
};
@@ -780,12 +812,14 @@ struct dwc2_hregs_backup {
* @hcd_enabled Host mode sub-driver initialization indicator.
* @gadget_enabled Peripheral mode sub-driver initialization indicator.
* @ll_hw_enabled Status of low-level hardware resources.
+ * @hibernated: True if core is hibernated
* @phy: The otg phy transceiver structure for phy control.
* @uphy: The otg phy transceiver structure for old USB phy
* control.
* @plat: The platform specific configuration data. This can be
* removed once all SoCs support usb transceiver.
* @supplies: Definition of USB power supplies
+ * @vbus_supply: Regulator supplying vbus.
* @phyif: PHY interface width
* @lock: Spinlock that protects all the driver data structures
* @priv: Stores a pointer to the struct usb_hcd
@@ -897,6 +931,8 @@ struct dwc2_hregs_backup {
* @ctrl_req: Request for EP0 control packets.
* @ep0_state: EP0 control transfers state
* @test_mode: USB test mode requested by the host
+ * @remote_wakeup_allowed: True if device is allowed to wake-up host by
+ * remote-wakeup signalling
* @setup_desc_dma: EP0 setup stage desc chain DMA address
* @setup_desc: EP0 setup stage desc chain pointer
* @ctrl_in_desc_dma: EP0 IN data phase desc chain DMA address
@@ -917,11 +953,13 @@ struct dwc2_hsotg {
unsigned int hcd_enabled:1;
unsigned int gadget_enabled:1;
unsigned int ll_hw_enabled:1;
+ unsigned int hibernated:1;
struct phy *phy;
struct usb_phy *uphy;
struct dwc2_hsotg_plat *plat;
struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES];
+ struct regulator *vbus_supply;
u32 phyif;
spinlock_t lock;
@@ -947,6 +985,7 @@ struct dwc2_hsotg {
/* DWC OTG HW Release versions */
#define DWC2_CORE_REV_2_71a 0x4f54271a
+#define DWC2_CORE_REV_2_80a 0x4f54280a
#define DWC2_CORE_REV_2_90a 0x4f54290a
#define DWC2_CORE_REV_2_91a 0x4f54291a
#define DWC2_CORE_REV_2_92a 0x4f54292a
@@ -956,6 +995,11 @@ struct dwc2_hsotg {
#define DWC2_FS_IOT_REV_1_00a 0x5531100a
#define DWC2_HS_IOT_REV_1_00a 0x5532100a
+ /* DWC OTG HW Core ID */
+#define DWC2_OTG_ID 0x4f540000
+#define DWC2_FS_IOT_ID 0x55310000
+#define DWC2_HS_IOT_ID 0x55320000
+
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
union dwc2_hcd_internal_flags {
u32 d32;
@@ -1016,24 +1060,6 @@ struct dwc2_hsotg {
struct kmem_cache *desc_gen_cache;
struct kmem_cache *desc_hsisoc_cache;
-#ifdef DEBUG
- u32 frrem_samples;
- u64 frrem_accum;
-
- u32 hfnum_7_samples_a;
- u64 hfnum_7_frrem_accum_a;
- u32 hfnum_0_samples_a;
- u64 hfnum_0_frrem_accum_a;
- u32 hfnum_other_samples_a;
- u64 hfnum_other_frrem_accum_a;
-
- u32 hfnum_7_samples_b;
- u64 hfnum_7_frrem_accum_b;
- u32 hfnum_0_samples_b;
- u64 hfnum_0_frrem_accum_b;
- u32 hfnum_other_samples_b;
- u64 hfnum_other_frrem_accum_b;
-#endif
#endif /* CONFIG_USB_DWC2_HOST || CONFIG_USB_DWC2_DUAL_ROLE */
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \
@@ -1062,6 +1088,7 @@ struct dwc2_hsotg {
struct usb_gadget gadget;
unsigned int enabled:1;
unsigned int connected:1;
+ unsigned int remote_wakeup_allowed:1;
struct dwc2_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
struct dwc2_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
@@ -1106,12 +1133,13 @@ static inline bool dwc2_is_hs_iot(struct dwc2_hsotg *hsotg)
* and the DWC_otg controller
*/
int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait);
-int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg);
-int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg);
-int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore);
+int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg);
+int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore);
+int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host);
+int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
+ int reset, int is_host);
-bool dwc2_force_mode_if_needed(struct dwc2_hsotg *hsotg, bool host);
-void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg);
+void dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host);
void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg);
bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg);
@@ -1128,6 +1156,13 @@ void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg);
void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd);
void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd);
+void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup,
+ int is_host);
+int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg);
+int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg);
+
+void dwc2_enable_acg(struct dwc2_hsotg *hsotg);
+
/* This function should be called on every hardware interrupt. */
irqreturn_t dwc2_handle_common_intr(int irq, void *dev);
@@ -1137,6 +1172,11 @@ extern const struct of_device_id dwc2_of_match_table[];
int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg);
int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg);
+/* Common polling functions */
+int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hs_otg, u32 reg, u32 bit,
+ u32 timeout);
+int dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hs_otg, u32 reg, u32 bit,
+ u32 timeout);
/* Parameters */
int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
int dwc2_init_params(struct dwc2_hsotg *hsotg);
@@ -1180,7 +1220,7 @@ void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg);
int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg);
int dwc2_hsotg_suspend(struct dwc2_hsotg *dwc2);
int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2);
-int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq);
+int dwc2_gadget_init(struct dwc2_hsotg *hsotg);
void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
bool reset);
void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg);
@@ -1188,10 +1228,14 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2);
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);
+int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup);
+int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg);
+int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
+ int rem_wakeup, int reset);
int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg);
int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);
int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
+void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg);
#else
static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2)
{ return 0; }
@@ -1199,7 +1243,7 @@ static inline int dwc2_hsotg_suspend(struct dwc2_hsotg *dwc2)
{ return 0; }
static inline int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2)
{ return 0; }
-static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
+static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
bool reset) {}
@@ -1211,7 +1255,13 @@ static inline int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
#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)
+static inline int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg,
+ int remote_wakeup)
+{ return 0; }
+static inline int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg)
+{ return 0; }
+static inline int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
+ int rem_wakeup, int reset)
{ return 0; }
static inline int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg)
{ return 0; }
@@ -1219,6 +1269,7 @@ static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg)
{ return 0; }
+static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {}
#endif
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
@@ -1227,8 +1278,12 @@ int dwc2_hcd_get_future_frame_number(struct dwc2_hsotg *hsotg, int us);
void dwc2_hcd_connect(struct dwc2_hsotg *hsotg);
void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force);
void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
+int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup);
int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg);
int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
+int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg);
+int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
+ int rem_wakeup, int reset);
#else
static inline int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
{ return 0; }
@@ -1239,12 +1294,19 @@ 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_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
+{ return 0; }
static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
{ 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; }
+static inline int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
+{ return 0; }
+static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
+ int rem_wakeup, int reset)
+{ return 0; }
#endif
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index ab3fa1630853..2982a155734d 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -321,10 +321,10 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
if (dwc2_is_device_mode(hsotg)) {
if (hsotg->lx_state == DWC2_L2) {
- ret = dwc2_exit_hibernation(hsotg, true);
+ ret = dwc2_exit_partial_power_down(hsotg, true);
if (ret && (ret != -ENOTSUPP))
dev_err(hsotg->dev,
- "exit hibernation failed\n");
+ "exit power_down failed\n");
}
/*
@@ -335,6 +335,57 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
}
}
+/**
+ * dwc2_wakeup_from_lpm_l1 - Exit the device from LPM L1 state
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ */
+static void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg)
+{
+ u32 glpmcfg;
+ u32 i = 0;
+
+ if (hsotg->lx_state != DWC2_L1) {
+ dev_err(hsotg->dev, "Core isn't in DWC2_L1 state\n");
+ return;
+ }
+
+ glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
+ if (dwc2_is_device_mode(hsotg)) {
+ dev_dbg(hsotg->dev, "Exit from L1 state\n");
+ glpmcfg &= ~GLPMCFG_ENBLSLPM;
+ glpmcfg &= ~GLPMCFG_HIRD_THRES_EN;
+ dwc2_writel(glpmcfg, hsotg->regs + GLPMCFG);
+
+ do {
+ glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
+
+ if (!(glpmcfg & (GLPMCFG_COREL1RES_MASK |
+ GLPMCFG_L1RESUMEOK | GLPMCFG_SLPSTS)))
+ break;
+
+ udelay(1);
+ } while (++i < 200);
+
+ if (i == 200) {
+ dev_err(hsotg->dev, "Failed to exit L1 sleep state in 200us.\n");
+ return;
+ }
+ dwc2_gadget_init_lpm(hsotg);
+ } else {
+ /* TODO */
+ dev_err(hsotg->dev, "Host side LPM is not supported.\n");
+ return;
+ }
+
+ /* Change to L0 state */
+ hsotg->lx_state = DWC2_L0;
+
+ /* Inform gadget to exit from L1 */
+ call_gadget(hsotg, resume);
+}
+
/*
* This interrupt indicates that the DWC_otg controller has detected a
* resume or remote wakeup sequence. If the DWC_otg controller is in
@@ -352,6 +403,11 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
+ if (hsotg->lx_state == DWC2_L1) {
+ dwc2_wakeup_from_lpm_l1(hsotg);
+ return;
+ }
+
if (dwc2_is_device_mode(hsotg)) {
dev_dbg(hsotg->dev, "DSTS=0x%0x\n",
dwc2_readl(hsotg->regs + DSTS));
@@ -361,16 +417,16 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
/* Clear Remote Wakeup Signaling */
dctl &= ~DCTL_RMTWKUPSIG;
dwc2_writel(dctl, hsotg->regs + DCTL);
- ret = dwc2_exit_hibernation(hsotg, true);
+ ret = dwc2_exit_partial_power_down(hsotg, true);
if (ret && (ret != -ENOTSUPP))
- dev_err(hsotg->dev, "exit hibernation failed\n");
+ dev_err(hsotg->dev, "exit power_down failed\n");
call_gadget(hsotg, resume);
}
/* Change to L0 state */
hsotg->lx_state = DWC2_L0;
} else {
- if (hsotg->params.hibernation)
+ if (hsotg->params.power_down)
return;
if (hsotg->lx_state != DWC2_L1) {
@@ -428,32 +484,44 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
* state is active
*/
dsts = dwc2_readl(hsotg->regs + DSTS);
- dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dsts);
+ dev_dbg(hsotg->dev, "%s: DSTS=0x%0x\n", __func__, dsts);
dev_dbg(hsotg->dev,
- "DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
+ "DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d HWCFG4.Hibernation=%d\n",
!!(dsts & DSTS_SUSPSTS),
- hsotg->hw_params.power_optimized);
- if ((dsts & DSTS_SUSPSTS) && hsotg->hw_params.power_optimized) {
- /* Ignore suspend request before enumeration */
- if (!dwc2_is_device_connected(hsotg)) {
- dev_dbg(hsotg->dev,
- "ignore suspend request before enumeration\n");
- return;
+ hsotg->hw_params.power_optimized,
+ hsotg->hw_params.hibernation);
+
+ /* Ignore suspend request before enumeration */
+ if (!dwc2_is_device_connected(hsotg)) {
+ dev_dbg(hsotg->dev,
+ "ignore suspend request before enumeration\n");
+ return;
+ }
+ if (dsts & DSTS_SUSPSTS) {
+ if (hsotg->hw_params.power_optimized) {
+ ret = dwc2_enter_partial_power_down(hsotg);
+ if (ret) {
+ if (ret != -ENOTSUPP)
+ dev_err(hsotg->dev,
+ "%s: enter partial_power_down failed\n",
+ __func__);
+ goto skip_power_saving;
+ }
+
+ udelay(100);
+
+ /* Ask phy to be suspended */
+ if (!IS_ERR_OR_NULL(hsotg->uphy))
+ usb_phy_set_suspend(hsotg->uphy, true);
}
- ret = dwc2_enter_hibernation(hsotg);
- if (ret) {
- if (ret != -ENOTSUPP)
+ if (hsotg->hw_params.hibernation) {
+ ret = dwc2_enter_hibernation(hsotg, 0);
+ if (ret && ret != -ENOTSUPP)
dev_err(hsotg->dev,
- "enter hibernation failed\n");
- goto skip_power_saving;
+ "%s: enter hibernation failed\n",
+ __func__);
}
-
- udelay(100);
-
- /* Ask phy to be suspended */
- if (!IS_ERR_OR_NULL(hsotg->uphy))
- usb_phy_set_suspend(hsotg->uphy, true);
skip_power_saving:
/*
* Change to L2 (suspend) state before releasing
@@ -479,10 +547,75 @@ skip_power_saving:
}
}
+/**
+ * dwc2_handle_lpm_intr - GINTSTS_LPMTRANRCVD Interrupt handler
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ */
+static void dwc2_handle_lpm_intr(struct dwc2_hsotg *hsotg)
+{
+ u32 glpmcfg;
+ u32 pcgcctl;
+ u32 hird;
+ u32 hird_thres;
+ u32 hird_thres_en;
+ u32 enslpm;
+
+ /* Clear interrupt */
+ dwc2_writel(GINTSTS_LPMTRANRCVD, hsotg->regs + GINTSTS);
+
+ glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
+
+ if (!(glpmcfg & GLPMCFG_LPMCAP)) {
+ dev_err(hsotg->dev, "Unexpected LPM interrupt\n");
+ return;
+ }
+
+ hird = (glpmcfg & GLPMCFG_HIRD_MASK) >> GLPMCFG_HIRD_SHIFT;
+ hird_thres = (glpmcfg & GLPMCFG_HIRD_THRES_MASK &
+ ~GLPMCFG_HIRD_THRES_EN) >> GLPMCFG_HIRD_THRES_SHIFT;
+ hird_thres_en = glpmcfg & GLPMCFG_HIRD_THRES_EN;
+ enslpm = glpmcfg & GLPMCFG_ENBLSLPM;
+
+ if (dwc2_is_device_mode(hsotg)) {
+ dev_dbg(hsotg->dev, "HIRD_THRES_EN = %d\n", hird_thres_en);
+
+ if (hird_thres_en && hird >= hird_thres) {
+ dev_dbg(hsotg->dev, "L1 with utmi_l1_suspend_n\n");
+ } else if (enslpm) {
+ dev_dbg(hsotg->dev, "L1 with utmi_sleep_n\n");
+ } else {
+ dev_dbg(hsotg->dev, "Entering Sleep with L1 Gating\n");
+
+ pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
+ pcgcctl |= PCGCTL_ENBL_SLEEP_GATING;
+ dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+ }
+ /**
+ * Examine prt_sleep_sts after TL1TokenTetry period max (10 us)
+ */
+ udelay(10);
+
+ glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
+
+ if (glpmcfg & GLPMCFG_SLPSTS) {
+ /* Save the current state */
+ hsotg->lx_state = DWC2_L1;
+ dev_dbg(hsotg->dev,
+ "Core is in L1 sleep glpmcfg=%08x\n", glpmcfg);
+
+ /* Inform gadget that we are in L1 state */
+ call_gadget(hsotg, suspend);
+ }
+ }
+}
+
#define GINTMSK_COMMON (GINTSTS_WKUPINT | GINTSTS_SESSREQINT | \
GINTSTS_CONIDSTSCHNG | GINTSTS_OTGINT | \
GINTSTS_MODEMIS | GINTSTS_DISCONNINT | \
- GINTSTS_USBSUSP | GINTSTS_PRTINT)
+ GINTSTS_USBSUSP | GINTSTS_PRTINT | \
+ GINTSTS_LPMTRANRCVD)
/*
* This function returns the Core Interrupt register
@@ -510,6 +643,116 @@ static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
}
/*
+ * GPWRDN interrupt handler.
+ *
+ * The GPWRDN interrupts are those that occur in both Host and
+ * Device mode while core is in hibernated state.
+ */
+static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
+{
+ u32 gpwrdn;
+ int linestate;
+
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ /* clear all interrupt */
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ linestate = (gpwrdn & GPWRDN_LINESTATE_MASK) >> GPWRDN_LINESTATE_SHIFT;
+ dev_dbg(hsotg->dev,
+ "%s: dwc2_handle_gpwrdwn_intr called gpwrdn= %08x\n", __func__,
+ gpwrdn);
+
+ if ((gpwrdn & GPWRDN_DISCONN_DET) &&
+ (gpwrdn & GPWRDN_DISCONN_DET_MSK) && !linestate) {
+ u32 gpwrdn_tmp;
+
+ dev_dbg(hsotg->dev, "%s: GPWRDN_DISCONN_DET\n", __func__);
+
+ /* Switch-on voltage to the core */
+ gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH;
+ dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Reset core */
+ gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN;
+ dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Disable Power Down Clamp */
+ gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP;
+ dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Deassert reset core */
+ gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn_tmp |= GPWRDN_PWRDNRSTN;
+ dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Disable PMU interrupt */
+ gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn_tmp &= ~GPWRDN_PMUINTSEL;
+ dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
+
+ /* De-assert Wakeup Logic */
+ gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn_tmp &= ~GPWRDN_PMUACTV;
+ dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
+
+ hsotg->hibernated = 0;
+
+ if (gpwrdn & GPWRDN_IDSTS) {
+ hsotg->op_state = OTG_STATE_B_PERIPHERAL;
+ dwc2_core_init(hsotg, false);
+ dwc2_enable_global_interrupts(hsotg);
+ dwc2_hsotg_core_init_disconnected(hsotg, false);
+ dwc2_hsotg_core_connect(hsotg);
+ } else {
+ hsotg->op_state = OTG_STATE_A_HOST;
+
+ /* Initialize the Core for Host mode */
+ dwc2_core_init(hsotg, false);
+ dwc2_enable_global_interrupts(hsotg);
+ dwc2_hcd_start(hsotg);
+ }
+ }
+
+ if ((gpwrdn & GPWRDN_LNSTSCHG) &&
+ (gpwrdn & GPWRDN_LNSTSCHG_MSK) && linestate) {
+ dev_dbg(hsotg->dev, "%s: GPWRDN_LNSTSCHG\n", __func__);
+ if (hsotg->hw_params.hibernation &&
+ hsotg->hibernated) {
+ if (gpwrdn & GPWRDN_IDSTS) {
+ dwc2_exit_hibernation(hsotg, 0, 0, 0);
+ call_gadget(hsotg, resume);
+ } else {
+ dwc2_exit_hibernation(hsotg, 1, 0, 1);
+ }
+ }
+ }
+ if ((gpwrdn & GPWRDN_RST_DET) && (gpwrdn & GPWRDN_RST_DET_MSK)) {
+ dev_dbg(hsotg->dev, "%s: GPWRDN_RST_DET\n", __func__);
+ if (!linestate && (gpwrdn & GPWRDN_BSESSVLD))
+ dwc2_exit_hibernation(hsotg, 0, 1, 0);
+ }
+ if ((gpwrdn & GPWRDN_STS_CHGINT) &&
+ (gpwrdn & GPWRDN_STS_CHGINT_MSK) && linestate) {
+ dev_dbg(hsotg->dev, "%s: GPWRDN_STS_CHGINT\n", __func__);
+ if (hsotg->hw_params.hibernation &&
+ hsotg->hibernated) {
+ if (gpwrdn & GPWRDN_IDSTS) {
+ dwc2_exit_hibernation(hsotg, 0, 0, 0);
+ call_gadget(hsotg, resume);
+ } else {
+ dwc2_exit_hibernation(hsotg, 1, 0, 1);
+ }
+ }
+ }
+}
+
+/*
* Common interrupt handler
*
* The common interrupts are those that occur in both Host and Device mode.
@@ -539,6 +782,13 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
if (gintsts & ~GINTSTS_PRTINT)
retval = IRQ_HANDLED;
+ /* In case of hibernated state gintsts must not work */
+ if (hsotg->hibernated) {
+ dwc2_handle_gpwrdn_intr(hsotg);
+ retval = IRQ_HANDLED;
+ goto out;
+ }
+
if (gintsts & GINTSTS_MODEMIS)
dwc2_handle_mode_mismatch_intr(hsotg);
if (gintsts & GINTSTS_OTGINT)
@@ -553,6 +803,8 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
dwc2_handle_wakeup_detected_intr(hsotg);
if (gintsts & GINTSTS_USBSUSP)
dwc2_handle_usb_suspend_intr(hsotg);
+ if (gintsts & GINTSTS_LPMTRANRCVD)
+ dwc2_handle_lpm_intr(hsotg);
if (gintsts & GINTSTS_PRTINT) {
/*
diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c
index f4650a88be78..58c691f882a8 100644
--- a/drivers/usb/dwc2/debugfs.c
+++ b/drivers/usb/dwc2/debugfs.c
@@ -170,19 +170,7 @@ static int state_show(struct seq_file *seq, void *v)
return 0;
}
-
-static int state_open(struct inode *inode, struct file *file)
-{
- return single_open(file, state_show, inode->i_private);
-}
-
-static const struct file_operations state_fops = {
- .owner = THIS_MODULE,
- .open = state_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(state);
/**
* fifo_show - debugfs: show the fifo information
@@ -219,19 +207,7 @@ static int fifo_show(struct seq_file *seq, void *v)
return 0;
}
-
-static int fifo_open(struct inode *inode, struct file *file)
-{
- return single_open(file, fifo_show, inode->i_private);
-}
-
-static const struct file_operations fifo_fops = {
- .owner = THIS_MODULE,
- .open = fifo_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(fifo);
static const char *decode_direction(int is_in)
{
@@ -303,19 +279,7 @@ static int ep_show(struct seq_file *seq, void *v)
return 0;
}
-
-static int ep_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ep_show, inode->i_private);
-}
-
-static const struct file_operations ep_fops = {
- .owner = THIS_MODULE,
- .open = ep_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(ep);
/**
* dwc2_hsotg_create_debug - create debugfs directory and files
@@ -754,7 +718,12 @@ static int params_show(struct seq_file *seq, void *v)
print_param_hex(seq, p, ahbcfg);
print_param(seq, p, uframe_sched);
print_param(seq, p, external_id_pin_ctl);
- print_param(seq, p, hibernation);
+ print_param(seq, p, power_down);
+ print_param(seq, p, lpm);
+ print_param(seq, p, lpm_clock_gating);
+ print_param(seq, p, besl);
+ print_param(seq, p, hird_threshold_en);
+ print_param(seq, p, hird_threshold);
print_param(seq, p, host_dma);
print_param(seq, p, g_dma);
print_param(seq, p, g_dma_desc);
@@ -770,19 +739,7 @@ static int params_show(struct seq_file *seq, void *v)
return 0;
}
-
-static int params_open(struct inode *inode, struct file *file)
-{
- return single_open(file, params_show, inode->i_private);
-}
-
-static const struct file_operations params_fops = {
- .owner = THIS_MODULE,
- .open = params_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(params);
static int hw_params_show(struct seq_file *seq, void *v)
{
@@ -817,19 +774,7 @@ static int hw_params_show(struct seq_file *seq, void *v)
return 0;
}
-
-static int hw_params_open(struct inode *inode, struct file *file)
-{
- return single_open(file, hw_params_show, inode->i_private);
-}
-
-static const struct file_operations hw_params_fops = {
- .owner = THIS_MODULE,
- .open = hw_params_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(hw_params);
static int dr_mode_show(struct seq_file *seq, void *v)
{
@@ -840,19 +785,7 @@ static int dr_mode_show(struct seq_file *seq, void *v)
seq_printf(seq, "%s\n", dr_mode);
return 0;
}
-
-static int dr_mode_open(struct inode *inode, struct file *file)
-{
- return single_open(file, dr_mode_show, inode->i_private);
-}
-
-static const struct file_operations dr_mode_fops = {
- .owner = THIS_MODULE,
- .open = dr_mode_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(dr_mode);
int dwc2_debugfs_init(struct dwc2_hsotg *hsotg)
{
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 5bcad1d869b5..6c32bf26e48e 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -47,12 +47,12 @@ static inline struct dwc2_hsotg *to_hsotg(struct usb_gadget *gadget)
return container_of(gadget, struct dwc2_hsotg, gadget);
}
-static inline void __orr32(void __iomem *ptr, u32 val)
+static inline void dwc2_set_bit(void __iomem *ptr, u32 val)
{
dwc2_writel(dwc2_readl(ptr) | val, ptr);
}
-static inline void __bic32(void __iomem *ptr, u32 val)
+static inline void dwc2_clear_bit(void __iomem *ptr, u32 val)
{
dwc2_writel(dwc2_readl(ptr) & ~val, ptr);
}
@@ -116,10 +116,10 @@ static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep)
{
hs_ep->target_frame += hs_ep->interval;
if (hs_ep->target_frame > DSTS_SOFFN_LIMIT) {
- hs_ep->frame_overrun = 1;
+ hs_ep->frame_overrun = true;
hs_ep->target_frame &= DSTS_SOFFN_LIMIT;
} else {
- hs_ep->frame_overrun = 0;
+ hs_ep->frame_overrun = false;
}
}
@@ -252,6 +252,7 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
unsigned int ep;
unsigned int addr;
int timeout;
+
u32 val;
u32 *txfsz = hsotg->params.g_tx_fifo_size;
@@ -1296,8 +1297,8 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
req->zero, req->short_not_ok);
/* Prevent new request submission when controller is suspended */
- if (hs->lx_state == DWC2_L2) {
- dev_dbg(hs->dev, "%s: don't submit request while suspended\n",
+ if (hs->lx_state != DWC2_L0) {
+ dev_dbg(hs->dev, "%s: submit request only in active state\n",
__func__);
return -EAGAIN;
}
@@ -1639,6 +1640,10 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
switch (recip) {
case USB_RECIP_DEVICE:
switch (wValue) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ hsotg->remote_wakeup_allowed = 1;
+ break;
+
case USB_DEVICE_TEST_MODE:
if ((wIndex & 0xff) != 0)
return -EINVAL;
@@ -2495,30 +2500,13 @@ bad_mps:
*/
static void dwc2_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx)
{
- int timeout;
- int val;
-
dwc2_writel(GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH,
hsotg->regs + GRSTCTL);
/* wait until the fifo is flushed */
- timeout = 100;
-
- while (1) {
- val = dwc2_readl(hsotg->regs + GRSTCTL);
-
- if ((val & (GRSTCTL_TXFFLSH)) == 0)
- break;
-
- if (--timeout == 0) {
- dev_err(hsotg->dev,
- "%s: timeout flushing fifo (GRSTCTL=%08x)\n",
- __func__, val);
- break;
- }
-
- udelay(1);
- }
+ if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 100))
+ dev_warn(hsotg->dev, "%s: timeout flushing fifo GRSTCTL_TXFFLSH\n",
+ __func__);
}
/**
@@ -3253,7 +3241,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
dwc2_hsotg_init_fifo(hsotg);
if (!is_usb_reset)
- __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);
+ dwc2_set_bit(hsotg->regs + DCTL, DCTL_SFTDISCON);
dcfg |= DCFG_EPMISCNT(1);
@@ -3282,7 +3270,8 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF |
GINTSTS_USBRST | GINTSTS_RESETDET |
GINTSTS_ENUMDONE | GINTSTS_OTGINT |
- GINTSTS_USBSUSP | GINTSTS_WKUPINT;
+ GINTSTS_USBSUSP | GINTSTS_WKUPINT |
+ GINTSTS_LPMTRANRCVD;
if (!using_desc_dma(hsotg))
intmsk |= GINTSTS_INCOMPL_SOIN | GINTSTS_INCOMPL_SOOUT;
@@ -3294,12 +3283,12 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
if (using_dma(hsotg)) {
dwc2_writel(GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN |
- (GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT),
+ hsotg->params.ahbcfg,
hsotg->regs + GAHBCFG);
/* Set DDMA mode support in the core if needed */
if (using_desc_dma(hsotg))
- __orr32(hsotg->regs + DCFG, DCFG_DESCDMA_EN);
+ dwc2_set_bit(hsotg->regs + DCFG, DCFG_DESCDMA_EN);
} else {
dwc2_writel(((hsotg->dedicated_fifos) ?
@@ -3332,7 +3321,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
/* Enable BNA interrupt for DDMA */
if (using_desc_dma(hsotg))
- __orr32(hsotg->regs + DOEPMSK, DOEPMSK_BNAMSK);
+ dwc2_set_bit(hsotg->regs + DOEPMSK, DOEPMSK_BNAMSK);
dwc2_writel(0, hsotg->regs + DAINTMSK);
@@ -3356,9 +3345,9 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
dwc2_hsotg_ctrl_epint(hsotg, 0, 1, 1);
if (!is_usb_reset) {
- __orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
+ dwc2_set_bit(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
udelay(10); /* see openiboot */
- __bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
+ dwc2_clear_bit(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
}
dev_dbg(hsotg->dev, "DCTL=0x%08x\n", dwc2_readl(hsotg->regs + DCTL));
@@ -3385,7 +3374,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
val = DCTL_CGOUTNAK | DCTL_CGNPINNAK;
if (!is_usb_reset)
val |= DCTL_SFTDISCON;
- __orr32(hsotg->regs + DCTL, val);
+ dwc2_set_bit(hsotg->regs + DCTL, val);
+
+ /* configure the core to support LPM */
+ dwc2_gadget_init_lpm(hsotg);
/* must be at-least 3ms to allow bus to see disconnect */
mdelay(3);
@@ -3402,13 +3394,13 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg)
{
/* set the soft-disconnect bit */
- __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);
+ dwc2_set_bit(hsotg->regs + DCTL, DCTL_SFTDISCON);
}
void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg)
{
/* remove the soft-disconnect and let's go */
- __bic32(hsotg->regs + DCTL, DCTL_SFTDISCON);
+ dwc2_clear_bit(hsotg->regs + DCTL, DCTL_SFTDISCON);
}
/**
@@ -3428,14 +3420,21 @@ static void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg)
{
struct dwc2_hsotg_ep *hs_ep;
u32 epctrl;
+ u32 daintmsk;
u32 idx;
dev_dbg(hsotg->dev, "Incomplete isoc in interrupt received:\n");
+ daintmsk = dwc2_readl(hsotg->regs + DAINTMSK);
+
for (idx = 1; idx <= hsotg->num_of_eps; idx++) {
hs_ep = hsotg->eps_in[idx];
+ /* Proceed only unmasked ISOC EPs */
+ if (!hs_ep->isochronous || (BIT(idx) & ~daintmsk))
+ continue;
+
epctrl = dwc2_readl(hsotg->regs + DIEPCTL(idx));
- if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous &&
+ if ((epctrl & DXEPCTL_EPENA) &&
dwc2_gadget_target_frame_elapsed(hs_ep)) {
epctrl |= DXEPCTL_SNAK;
epctrl |= DXEPCTL_EPDIS;
@@ -3464,16 +3463,24 @@ static void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg)
{
u32 gintsts;
u32 gintmsk;
+ u32 daintmsk;
u32 epctrl;
struct dwc2_hsotg_ep *hs_ep;
int idx;
dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__);
+ daintmsk = dwc2_readl(hsotg->regs + DAINTMSK);
+ daintmsk >>= DAINT_OUTEP_SHIFT;
+
for (idx = 1; idx <= hsotg->num_of_eps; idx++) {
hs_ep = hsotg->eps_out[idx];
+ /* Proceed only unmasked ISOC EPs */
+ if (!hs_ep->isochronous || (BIT(idx) & ~daintmsk))
+ continue;
+
epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx));
- if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous &&
+ if ((epctrl & DXEPCTL_EPENA) &&
dwc2_gadget_target_frame_elapsed(hs_ep)) {
/* Unmask GOUTNAKEFF interrupt */
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
@@ -3481,8 +3488,10 @@ static void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg)
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
gintsts = dwc2_readl(hsotg->regs + GINTSTS);
- if (!(gintsts & GINTSTS_GOUTNAKEFF))
- __orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK);
+ if (!(gintsts & GINTSTS_GOUTNAKEFF)) {
+ dwc2_set_bit(hsotg->regs + DCTL, DCTL_SGOUTNAK);
+ break;
+ }
}
}
@@ -3522,7 +3531,7 @@ irq_retry:
/* This event must be used only if controller is suspended */
if (hsotg->lx_state == DWC2_L2) {
- dwc2_exit_hibernation(hsotg, true);
+ dwc2_exit_partial_power_down(hsotg, true);
hsotg->lx_state = DWC2_L0;
}
}
@@ -3541,7 +3550,7 @@ irq_retry:
dwc2_hsotg_disconnect(hsotg);
/* Reset device address to zero */
- __bic32(hsotg->regs + DCFG, DCFG_DEVADDR_MASK);
+ dwc2_clear_bit(hsotg->regs + DCFG, DCFG_DEVADDR_MASK);
if (usb_status & GOTGCTL_BSESVLD && connected)
dwc2_hsotg_core_init_disconnected(hsotg, true);
@@ -3627,8 +3636,11 @@ irq_retry:
u8 idx;
u32 epctrl;
u32 gintmsk;
+ u32 daintmsk;
struct dwc2_hsotg_ep *hs_ep;
+ daintmsk = dwc2_readl(hsotg->regs + DAINTMSK);
+ daintmsk >>= DAINT_OUTEP_SHIFT;
/* Mask this interrupt */
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk &= ~GINTSTS_GOUTNAKEFF;
@@ -3637,9 +3649,13 @@ irq_retry:
dev_dbg(hsotg->dev, "GOUTNakEff triggered\n");
for (idx = 1; idx <= hsotg->num_of_eps; idx++) {
hs_ep = hsotg->eps_out[idx];
+ /* Proceed only unmasked ISOC EPs */
+ if (!hs_ep->isochronous || (BIT(idx) & ~daintmsk))
+ continue;
+
epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx));
- if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous) {
+ if (epctrl & DXEPCTL_EPENA) {
epctrl |= DXEPCTL_SNAK;
epctrl |= DXEPCTL_EPDIS;
dwc2_writel(epctrl, hsotg->regs + DOEPCTL(idx));
@@ -3652,7 +3668,7 @@ irq_retry:
if (gintsts & GINTSTS_GINNAKEFF) {
dev_info(hsotg->dev, "GINNakEff triggered\n");
- __orr32(hsotg->regs + DCTL, DCTL_CGNPINNAK);
+ dwc2_set_bit(hsotg->regs + DCTL, DCTL_CGNPINNAK);
dwc2_hsotg_dump(hsotg);
}
@@ -3676,20 +3692,6 @@ irq_retry:
return IRQ_HANDLED;
}
-static int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hs_otg, u32 reg,
- u32 bit, u32 timeout)
-{
- u32 i;
-
- for (i = 0; i < timeout; i++) {
- if (dwc2_readl(hs_otg->regs + reg) & bit)
- return 0;
- udelay(1);
- }
-
- return -ETIMEDOUT;
-}
-
static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
struct dwc2_hsotg_ep *hs_ep)
{
@@ -3706,7 +3708,7 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
if (hs_ep->dir_in) {
if (hsotg->dedicated_fifos || hs_ep->periodic) {
- __orr32(hsotg->regs + epctrl_reg, DXEPCTL_SNAK);
+ dwc2_set_bit(hsotg->regs + epctrl_reg, DXEPCTL_SNAK);
/* Wait for Nak effect */
if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg,
DXEPINT_INEPNAKEFF, 100))
@@ -3714,7 +3716,7 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
"%s: timeout DIEPINT.NAKEFF\n",
__func__);
} else {
- __orr32(hsotg->regs + DCTL, DCTL_SGNPINNAK);
+ dwc2_set_bit(hsotg->regs + DCTL, DCTL_SGNPINNAK);
/* Wait for Nak effect */
if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
GINTSTS_GINNAKEFF, 100))
@@ -3724,7 +3726,7 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
}
} else {
if (!(dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_GOUTNAKEFF))
- __orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK);
+ dwc2_set_bit(hsotg->regs + DCTL, DCTL_SGOUTNAK);
/* Wait for global nak to take effect */
if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
@@ -3734,7 +3736,7 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
}
/* Disable ep */
- __orr32(hsotg->regs + epctrl_reg, DXEPCTL_EPDIS | DXEPCTL_SNAK);
+ dwc2_set_bit(hsotg->regs + epctrl_reg, DXEPCTL_EPDIS | DXEPCTL_SNAK);
/* Wait for ep to be disabled */
if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, DXEPINT_EPDISBLD, 100))
@@ -3742,7 +3744,7 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
"%s: timeout DOEPCTL.EPDisable\n", __func__);
/* Clear EPDISBLD interrupt */
- __orr32(hsotg->regs + epint_reg, DXEPINT_EPDISBLD);
+ dwc2_set_bit(hsotg->regs + epint_reg, DXEPINT_EPDISBLD);
if (hs_ep->dir_in) {
unsigned short fifo_index;
@@ -3757,11 +3759,11 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
/* Clear Global In NP NAK in Shared FIFO for non periodic ep */
if (!hsotg->dedicated_fifos && !hs_ep->periodic)
- __orr32(hsotg->regs + DCTL, DCTL_CGNPINNAK);
+ dwc2_set_bit(hsotg->regs + DCTL, DCTL_CGNPINNAK);
} else {
/* Remove global NAKs */
- __orr32(hsotg->regs + DCTL, DCTL_CGOUTNAK);
+ dwc2_set_bit(hsotg->regs + DCTL, DCTL_CGOUTNAK);
}
}
@@ -4183,7 +4185,7 @@ static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg)
dwc2_writel(0, hsotg->regs + DAINTMSK);
/* Be in disconnected state until gadget is registered */
- __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);
+ dwc2_set_bit(hsotg->regs + DCTL, DCTL_SFTDISCON);
/* setup fifos */
@@ -4205,7 +4207,7 @@ static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg)
dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
if (using_dma(hsotg))
- __orr32(hsotg->regs + GAHBCFG, GAHBCFG_DMA_EN);
+ dwc2_set_bit(hsotg->regs + GAHBCFG, GAHBCFG_DMA_EN);
}
/**
@@ -4352,6 +4354,8 @@ static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on)
if (is_on) {
hsotg->enabled = 1;
dwc2_hsotg_core_init_disconnected(hsotg, false);
+ /* Enable ACG feature in device mode,if supported */
+ dwc2_enable_acg(hsotg);
dwc2_hsotg_core_connect(hsotg);
} else {
dwc2_hsotg_core_disconnect(hsotg);
@@ -4374,18 +4378,21 @@ static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active)
spin_lock_irqsave(&hsotg->lock, flags);
/*
- * If controller is hibernated, it must exit from hibernation
+ * If controller is hibernated, it must exit from power_down
* before being initialized / de-initialized
*/
if (hsotg->lx_state == DWC2_L2)
- dwc2_exit_hibernation(hsotg, false);
+ dwc2_exit_partial_power_down(hsotg, false);
if (is_active) {
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
dwc2_hsotg_core_init_disconnected(hsotg, false);
- if (hsotg->enabled)
+ if (hsotg->enabled) {
+ /* Enable ACG feature in device mode,if supported */
+ dwc2_enable_acg(hsotg);
dwc2_hsotg_core_connect(hsotg);
+ }
} else {
dwc2_hsotg_core_disconnect(hsotg);
dwc2_hsotg_disconnect(hsotg);
@@ -4606,9 +4613,8 @@ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg)
/**
* dwc2_gadget_init - init function for gadget
* @dwc2: The data structure for the DWC2 driver.
- * @irq: The IRQ number for the controller.
*/
-int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
+int dwc2_gadget_init(struct dwc2_hsotg *hsotg)
{
struct device *dev = hsotg->dev;
int epnum;
@@ -4622,6 +4628,11 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
hsotg->gadget.max_speed = USB_SPEED_HIGH;
hsotg->gadget.ops = &dwc2_hsotg_gadget_ops;
hsotg->gadget.name = dev_name(dev);
+ hsotg->remote_wakeup_allowed = 0;
+
+ if (hsotg->params.lpm)
+ hsotg->gadget.lpm_capable = true;
+
if (hsotg->dr_mode == USB_DR_MODE_OTG)
hsotg->gadget.is_otg = 1;
else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
@@ -4649,8 +4660,8 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
return ret;
}
- ret = devm_request_irq(hsotg->dev, irq, dwc2_hsotg_irq, IRQF_SHARED,
- dev_name(hsotg->dev), hsotg);
+ ret = devm_request_irq(hsotg->dev, hsotg->irq, dwc2_hsotg_irq,
+ IRQF_SHARED, dev_name(hsotg->dev), hsotg);
if (ret < 0) {
dev_err(dev, "cannot claim IRQ for gadget\n");
return ret;
@@ -4751,8 +4762,11 @@ int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg)
spin_lock_irqsave(&hsotg->lock, flags);
dwc2_hsotg_core_init_disconnected(hsotg, false);
- if (hsotg->enabled)
+ if (hsotg->enabled) {
+ /* Enable ACG feature in device mode,if supported */
+ dwc2_enable_acg(hsotg);
dwc2_hsotg_core_connect(hsotg);
+ }
spin_unlock_irqrestore(&hsotg->lock, flags);
}
@@ -4806,6 +4820,7 @@ int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
dr->doeptsiz[i] = dwc2_readl(hsotg->regs + DOEPTSIZ(i));
dr->doepdma[i] = dwc2_readl(hsotg->regs + DOEPDMA(i));
+ dr->dtxfsiz[i] = dwc2_readl(hsotg->regs + DPTXFSIZN(i));
}
dr->valid = true;
return 0;
@@ -4817,11 +4832,13 @@ int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
* if controller power were disabled.
*
* @hsotg: Programming view of the DWC_otg controller
+ * @remote_wakeup: Indicates whether resume is initiated by Device or Host.
+ *
+ * Return: 0 if successful, negative error code otherwise
*/
-int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
+int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup)
{
struct dwc2_dregs_backup *dr;
- u32 dctl;
int i;
dev_dbg(hsotg->dev, "%s\n", __func__);
@@ -4835,28 +4852,240 @@ int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
}
dr->valid = false;
- dwc2_writel(dr->dcfg, hsotg->regs + DCFG);
- dwc2_writel(dr->dctl, hsotg->regs + DCTL);
+ if (!remote_wakeup)
+ 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));
-
+ dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i));
+ /** WA for enabled EPx's IN in DDMA mode. On entering to
+ * hibernation wrong value read and saved from DIEPDMAx,
+ * as result BNA interrupt asserted on hibernation exit
+ * by restoring from saved area.
+ */
+ if (hsotg->params.g_dma_desc &&
+ (dr->diepctl[i] & DXEPCTL_EPENA))
+ dr->diepdma[i] = hsotg->eps_in[i]->desc_list_dma;
+ dwc2_writel(dr->dtxfsiz[i], hsotg->regs + DPTXFSIZN(i));
+ dwc2_writel(dr->diepctl[i], hsotg->regs + DIEPCTL(i));
/* Restore OUT EPs */
- dwc2_writel(dr->doepctl[i], hsotg->regs + DOEPCTL(i));
dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i));
+ /* WA for enabled EPx's OUT in DDMA mode. On entering to
+ * hibernation wrong value read and saved from DOEPDMAx,
+ * as result BNA interrupt asserted on hibernation exit
+ * by restoring from saved area.
+ */
+ if (hsotg->params.g_dma_desc &&
+ (dr->doepctl[i] & DXEPCTL_EPENA))
+ dr->doepdma[i] = hsotg->eps_out[i]->desc_list_dma;
dwc2_writel(dr->doepdma[i], hsotg->regs + DOEPDMA(i));
+ dwc2_writel(dr->doepctl[i], hsotg->regs + DOEPCTL(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;
}
+
+/**
+ * dwc2_gadget_init_lpm - Configure the core to support LPM in device mode
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ */
+void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg)
+{
+ u32 val;
+
+ if (!hsotg->params.lpm)
+ return;
+
+ val = GLPMCFG_LPMCAP | GLPMCFG_APPL1RES;
+ val |= hsotg->params.hird_threshold_en ? GLPMCFG_HIRD_THRES_EN : 0;
+ val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0;
+ val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT;
+ val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0;
+ dwc2_writel(val, hsotg->regs + GLPMCFG);
+ dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg->regs
+ + GLPMCFG));
+}
+
+/**
+ * dwc2_gadget_enter_hibernation() - Put controller in Hibernation.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ *
+ * Return non-zero if failed to enter to hibernation.
+ */
+int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg)
+{
+ u32 gpwrdn;
+ int ret = 0;
+
+ /* Change to L2(suspend) state */
+ hsotg->lx_state = DWC2_L2;
+ dev_dbg(hsotg->dev, "Start of hibernation completed\n");
+ ret = dwc2_backup_global_registers(hsotg);
+ if (ret) {
+ dev_err(hsotg->dev, "%s: failed to backup global registers\n",
+ __func__);
+ return ret;
+ }
+ ret = dwc2_backup_device_registers(hsotg);
+ if (ret) {
+ dev_err(hsotg->dev, "%s: failed to backup device registers\n",
+ __func__);
+ return ret;
+ }
+
+ gpwrdn = GPWRDN_PWRDNRSTN;
+ gpwrdn |= GPWRDN_PMUACTV;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Set flag to indicate that we are in hibernation */
+ hsotg->hibernated = 1;
+
+ /* Enable interrupts from wake up logic */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn |= GPWRDN_PMUINTSEL;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Unmask device mode interrupts in GPWRDN */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn |= GPWRDN_RST_DET_MSK;
+ gpwrdn |= GPWRDN_LNSTSCHG_MSK;
+ gpwrdn |= GPWRDN_STS_CHGINT_MSK;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Enable Power Down Clamp */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn |= GPWRDN_PWRDNCLMP;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Switch off VDD */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn |= GPWRDN_PWRDNSWTCH;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Save gpwrdn register for further usage if stschng interrupt */
+ hsotg->gr_backup.gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ dev_dbg(hsotg->dev, "Hibernation completed\n");
+
+ return ret;
+}
+
+/**
+ * dwc2_gadget_exit_hibernation()
+ * This function is for exiting from Device mode hibernation by host initiated
+ * resume/reset and device initiated remote-wakeup.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ * @rem_wakeup: indicates whether resume is initiated by Device or Host.
+ * @param reset: indicates whether resume is initiated by Reset.
+ *
+ * Return non-zero if failed to exit from hibernation.
+ */
+int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
+ int rem_wakeup, int reset)
+{
+ u32 pcgcctl;
+ u32 gpwrdn;
+ u32 dctl;
+ int ret = 0;
+ struct dwc2_gregs_backup *gr;
+ struct dwc2_dregs_backup *dr;
+
+ gr = &hsotg->gr_backup;
+ dr = &hsotg->dr_backup;
+
+ if (!hsotg->hibernated) {
+ dev_dbg(hsotg->dev, "Already exited from Hibernation\n");
+ return 1;
+ }
+ dev_dbg(hsotg->dev,
+ "%s: called with rem_wakeup = %d reset = %d\n",
+ __func__, rem_wakeup, reset);
+
+ dwc2_hib_restore_common(hsotg, rem_wakeup, 0);
+
+ if (!reset) {
+ /* Clear all pending interupts */
+ dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+ }
+
+ /* De-assert Restore */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn &= ~GPWRDN_RESTORE;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ if (!rem_wakeup) {
+ pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
+ pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
+ dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+ }
+
+ /* Restore GUSBCFG, DCFG and DCTL */
+ dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG);
+ dwc2_writel(dr->dcfg, hsotg->regs + DCFG);
+ dwc2_writel(dr->dctl, hsotg->regs + DCTL);
+
+ /* De-assert Wakeup Logic */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn &= ~GPWRDN_PMUACTV;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+
+ if (rem_wakeup) {
+ udelay(10);
+ /* Start Remote Wakeup Signaling */
+ dwc2_writel(dr->dctl | DCTL_RMTWKUPSIG, hsotg->regs + DCTL);
+ } else {
+ udelay(50);
+ /* Set Device programming done bit */
+ dctl = dwc2_readl(hsotg->regs + DCTL);
+ dctl |= DCTL_PWRONPRGDONE;
+ dwc2_writel(dctl, hsotg->regs + DCTL);
+ }
+ /* Wait for interrupts which must be cleared */
+ mdelay(2);
+ /* Clear all pending interupts */
+ dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+
+ /* Restore global registers */
+ ret = dwc2_restore_global_registers(hsotg);
+ if (ret) {
+ dev_err(hsotg->dev, "%s: failed to restore registers\n",
+ __func__);
+ return ret;
+ }
+
+ /* Restore device registers */
+ ret = dwc2_restore_device_registers(hsotg, rem_wakeup);
+ if (ret) {
+ dev_err(hsotg->dev, "%s: failed to restore device registers\n",
+ __func__);
+ return ret;
+ }
+
+ if (rem_wakeup) {
+ mdelay(10);
+ dctl = dwc2_readl(hsotg->regs + DCTL);
+ dctl &= ~DCTL_RMTWKUPSIG;
+ dwc2_writel(dctl, hsotg->regs + DCTL);
+ }
+
+ hsotg->hibernated = 0;
+ hsotg->lx_state = DWC2_L0;
+ dev_dbg(hsotg->dev, "Hibernation recovery completes here\n");
+
+ return ret;
+}
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index a5d72fcd1603..190f95964000 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -91,6 +91,9 @@ static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg)
intmsk |= GINTSTS_WKUPINT | GINTSTS_USBSUSP |
GINTSTS_SESSREQINT;
+ if (dwc2_is_device_mode(hsotg) && hsotg->params.lpm)
+ intmsk |= GINTSTS_LPMTRANRCVD;
+
dwc2_writel(intmsk, hsotg->regs + GINTMSK);
}
@@ -138,7 +141,7 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
/* Reset after a PHY select */
- retval = dwc2_core_reset_and_force_dr_mode(hsotg);
+ retval = dwc2_core_reset(hsotg, false);
if (retval) {
dev_err(hsotg->dev,
@@ -236,7 +239,7 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
/* Reset after setting the PHY parameters */
- retval = dwc2_core_reset_and_force_dr_mode(hsotg);
+ retval = dwc2_core_reset(hsotg, false);
if (retval) {
dev_err(hsotg->dev,
"%s: Reset failed, aborting", __func__);
@@ -308,22 +311,10 @@ static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
break;
}
- dev_dbg(hsotg->dev, "host_dma:%d dma_desc_enable:%d\n",
- hsotg->params.host_dma,
- hsotg->params.dma_desc_enable);
-
- if (hsotg->params.host_dma) {
- if (hsotg->params.dma_desc_enable)
- 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->params.dma_desc_enable = false;
- }
-
if (hsotg->params.host_dma)
ahbcfg |= GAHBCFG_DMA_EN;
+ else
+ hsotg->params.dma_desc_enable = false;
dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
@@ -365,6 +356,23 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
}
+static int dwc2_vbus_supply_init(struct dwc2_hsotg *hsotg)
+{
+ hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus");
+ if (IS_ERR(hsotg->vbus_supply))
+ return 0;
+
+ return regulator_enable(hsotg->vbus_supply);
+}
+
+static int dwc2_vbus_supply_exit(struct dwc2_hsotg *hsotg)
+{
+ if (hsotg->vbus_supply)
+ return regulator_disable(hsotg->vbus_supply);
+
+ return 0;
+}
+
/**
* dwc2_enable_host_interrupts() - Enables the Host mode interrupts
*
@@ -989,6 +997,24 @@ void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
if (dbg_hc(chan))
dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ /*
+ * In buffer DMA or external DMA mode channel can't be halted
+ * for non-split periodic channels. At the end of the next
+ * uframe/frame (in the worst case), the core generates a channel
+ * halted and disables the channel automatically.
+ */
+ if ((hsotg->params.g_dma && !hsotg->params.g_dma_desc) ||
+ hsotg->hw_params.arch == GHWCFG2_EXT_DMA_ARCH) {
+ if (!chan->do_split &&
+ (chan->ep_type == USB_ENDPOINT_XFER_ISOC ||
+ chan->ep_type == USB_ENDPOINT_XFER_INT)) {
+ dev_err(hsotg->dev, "%s() Channel can't be halted\n",
+ __func__);
+ return;
+ }
+ }
+
if (halt_status == DWC2_HC_XFER_NO_HALT_STATUS)
dev_err(hsotg->dev, "!!! halt_status = %d !!!\n", halt_status);
@@ -2232,7 +2258,7 @@ static int dwc2_hcd_endpoint_reset(struct dwc2_hsotg *hsotg,
* @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)
+int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
{
u32 usbcfg, otgctl;
int retval;
@@ -2261,7 +2287,7 @@ static int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
* needed to in order to properly detect various parameters).
*/
if (!initial_setup) {
- retval = dwc2_core_reset_and_force_dr_mode(hsotg);
+ retval = dwc2_core_reset(hsotg, false);
if (retval) {
dev_err(hsotg->dev, "%s(): Reset failed, aborting\n",
__func__);
@@ -2322,10 +2348,22 @@ static int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
*/
static void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
{
- u32 hcfg, hfir, otgctl;
+ u32 hcfg, hfir, otgctl, usbcfg;
dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
+ /* Set HS/FS Timeout Calibration to 7 (max available value).
+ * The number of PHY clocks that the application programs in
+ * this field is added to the high/full speed interpacket timeout
+ * duration in the core to account for any additional delays
+ * introduced by the PHY. This can be required, because the delay
+ * introduced by the PHY in generating the linestate condition
+ * can vary from one PHY to another.
+ */
+ usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+ usbcfg |= GUSBCFG_TOUTCAL(7);
+ dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+
/* Restart the Phy Clock */
dwc2_writel(0, hsotg->regs + PCGCTL);
@@ -2403,27 +2441,24 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
/* 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);
+
+ if (dwc2_hsotg_wait_bit_clear(hsotg, HCCHAR(i),
+ HCCHAR_CHENA, 1000)) {
+ dev_warn(hsotg->dev, "Unable to clear enable on channel %d\n",
+ i);
+ }
}
}
+ /* Enable ACG feature in host mode, if supported */
+ dwc2_enable_acg(hsotg);
+
/* 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) {
@@ -3257,6 +3292,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
/* B-Device connector (Device Mode) */
if (gotgctl & GOTGCTL_CONID_B) {
+ dwc2_vbus_supply_exit(hsotg);
/* Wait for switch to device mode */
dev_dbg(hsotg->dev, "connId B\n");
if (hsotg->bus_suspended) {
@@ -3290,6 +3326,8 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
spin_lock_irqsave(&hsotg->lock, flags);
dwc2_hsotg_core_init_disconnected(hsotg, false);
spin_unlock_irqrestore(&hsotg->lock, flags);
+ /* Enable ACG feature in device mode,if supported */
+ dwc2_enable_acg(hsotg);
dwc2_hsotg_core_connect(hsotg);
} else {
host:
@@ -3377,10 +3415,10 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
hsotg->bus_suspended = true;
/*
- * If hibernation is supported, Phy clock will be suspended
+ * If power_down is supported, Phy clock will be suspended
* after registers are backuped.
*/
- if (!hsotg->params.hibernation) {
+ if (!hsotg->params.power_down) {
/* Suspend the Phy Clock */
pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
pcgctl |= PCGCTL_STOPPCLK;
@@ -3412,10 +3450,10 @@ static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
spin_lock_irqsave(&hsotg->lock, flags);
/*
- * If hibernation is supported, Phy clock is already resumed
+ * If power_down is supported, Phy clock is already resumed
* after registers restore.
*/
- if (!hsotg->params.hibernation) {
+ if (!hsotg->params.power_down) {
pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
pcgctl &= ~PCGCTL_STOPPCLK;
dwc2_writel(pcgctl, hsotg->regs + PCGCTL);
@@ -3486,8 +3524,12 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
dev_dbg(hsotg->dev,
"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
- if (hsotg->bus_suspended)
- dwc2_port_resume(hsotg);
+ if (hsotg->bus_suspended) {
+ if (hsotg->hibernated)
+ dwc2_exit_hibernation(hsotg, 0, 0, 1);
+ else
+ dwc2_port_resume(hsotg);
+ }
break;
case USB_PORT_FEAT_POWER:
@@ -3695,7 +3737,10 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
"SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
if (windex != hsotg->otg_port)
goto error;
- dwc2_port_suspend(hsotg, windex);
+ if (hsotg->params.power_down == 2)
+ dwc2_enter_hibernation(hsotg, 1);
+ else
+ dwc2_port_suspend(hsotg, windex);
break;
case USB_PORT_FEAT_POWER:
@@ -3707,6 +3752,9 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
break;
case USB_PORT_FEAT_RESET:
+ if (hsotg->params.power_down == 2 &&
+ hsotg->hibernated)
+ dwc2_exit_hibernation(hsotg, 0, 1, 1);
hprt0 = dwc2_read_hprt0(hsotg);
dev_dbg(hsotg->dev,
"SetPortFeature - USB_PORT_FEAT_RESET\n");
@@ -4002,7 +4050,6 @@ void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg)
(p_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
dev_dbg(hsotg->dev, " P Tx FIFO Space Avail: %d\n",
(p_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT);
- dwc2_hcd_dump_frrem(hsotg);
dwc2_dump_global_registers(hsotg);
dwc2_dump_host_registers(hsotg);
dev_dbg(hsotg->dev,
@@ -4011,75 +4058,6 @@ void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg)
#endif
}
-/*
- * NOTE: This function will be removed once the peripheral controller code
- * is integrated and the driver is stable
- */
-void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg)
-{
-#ifdef DWC2_DUMP_FRREM
- dev_dbg(hsotg->dev, "Frame remaining at SOF:\n");
- dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
- hsotg->frrem_samples, hsotg->frrem_accum,
- hsotg->frrem_samples > 0 ?
- hsotg->frrem_accum / hsotg->frrem_samples : 0);
- dev_dbg(hsotg->dev, "\n");
- dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 7):\n");
- dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
- hsotg->hfnum_7_samples,
- hsotg->hfnum_7_frrem_accum,
- hsotg->hfnum_7_samples > 0 ?
- hsotg->hfnum_7_frrem_accum / hsotg->hfnum_7_samples : 0);
- dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 0):\n");
- dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
- hsotg->hfnum_0_samples,
- hsotg->hfnum_0_frrem_accum,
- hsotg->hfnum_0_samples > 0 ?
- hsotg->hfnum_0_frrem_accum / hsotg->hfnum_0_samples : 0);
- dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 1-6):\n");
- dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
- hsotg->hfnum_other_samples,
- hsotg->hfnum_other_frrem_accum,
- hsotg->hfnum_other_samples > 0 ?
- hsotg->hfnum_other_frrem_accum / hsotg->hfnum_other_samples :
- 0);
- dev_dbg(hsotg->dev, "\n");
- dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 7):\n");
- dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
- hsotg->hfnum_7_samples_a, hsotg->hfnum_7_frrem_accum_a,
- hsotg->hfnum_7_samples_a > 0 ?
- hsotg->hfnum_7_frrem_accum_a / hsotg->hfnum_7_samples_a : 0);
- dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 0):\n");
- dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
- hsotg->hfnum_0_samples_a, hsotg->hfnum_0_frrem_accum_a,
- hsotg->hfnum_0_samples_a > 0 ?
- hsotg->hfnum_0_frrem_accum_a / hsotg->hfnum_0_samples_a : 0);
- dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 1-6):\n");
- dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
- hsotg->hfnum_other_samples_a, hsotg->hfnum_other_frrem_accum_a,
- hsotg->hfnum_other_samples_a > 0 ?
- hsotg->hfnum_other_frrem_accum_a / hsotg->hfnum_other_samples_a
- : 0);
- dev_dbg(hsotg->dev, "\n");
- dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 7):\n");
- dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
- hsotg->hfnum_7_samples_b, hsotg->hfnum_7_frrem_accum_b,
- hsotg->hfnum_7_samples_b > 0 ?
- hsotg->hfnum_7_frrem_accum_b / hsotg->hfnum_7_samples_b : 0);
- dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 0):\n");
- dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
- hsotg->hfnum_0_samples_b, hsotg->hfnum_0_frrem_accum_b,
- (hsotg->hfnum_0_samples_b > 0) ?
- hsotg->hfnum_0_frrem_accum_b / hsotg->hfnum_0_samples_b : 0);
- dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 1-6):\n");
- dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
- hsotg->hfnum_other_samples_b, hsotg->hfnum_other_frrem_accum_b,
- (hsotg->hfnum_other_samples_b > 0) ?
- hsotg->hfnum_other_frrem_accum_b / hsotg->hfnum_other_samples_b
- : 0);
-#endif
-}
-
struct wrapper_priv_data {
struct dwc2_hsotg *hsotg;
};
@@ -4363,6 +4341,9 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
}
spin_unlock_irqrestore(&hsotg->lock, flags);
+
+ dwc2_vbus_supply_init(hsotg);
+
return 0;
}
@@ -4390,6 +4371,8 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
spin_unlock_irqrestore(&hsotg->lock, flags);
+ dwc2_vbus_supply_exit(hsotg);
+
usleep_range(1000, 3000);
}
@@ -4414,7 +4397,7 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
if (hsotg->op_state == OTG_STATE_B_PERIPHERAL)
goto unlock;
- if (!hsotg->params.hibernation)
+ if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL)
goto skip_power_saving;
/*
@@ -4426,14 +4409,15 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
hprt0 |= HPRT0_SUSP;
hprt0 &= ~HPRT0_PWR;
dwc2_writel(hprt0, hsotg->regs + HPRT0);
+ dwc2_vbus_supply_exit(hsotg);
}
- /* Enter hibernation */
- ret = dwc2_enter_hibernation(hsotg);
+ /* Enter partial_power_down */
+ ret = dwc2_enter_partial_power_down(hsotg);
if (ret) {
if (ret != -ENOTSUPP)
dev_err(hsotg->dev,
- "enter hibernation failed\n");
+ "enter partial_power_down failed\n");
goto skip_power_saving;
}
@@ -4444,7 +4428,7 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
spin_lock_irqsave(&hsotg->lock, flags);
}
- /* After entering hibernation, hardware is no more accessible */
+ /* After entering partial_power_down, hardware is no more accessible */
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
skip_power_saving:
@@ -4469,7 +4453,7 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
if (hsotg->lx_state != DWC2_L2)
goto unlock;
- if (!hsotg->params.hibernation) {
+ if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL) {
hsotg->lx_state = DWC2_L0;
goto unlock;
}
@@ -4491,10 +4475,10 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
spin_lock_irqsave(&hsotg->lock, flags);
}
- /* Exit hibernation */
- ret = dwc2_exit_hibernation(hsotg, true);
+ /* Exit partial_power_down */
+ ret = dwc2_exit_partial_power_down(hsotg, true);
if (ret && (ret != -ENOTSUPP))
- dev_err(hsotg->dev, "exit hibernation failed\n");
+ dev_err(hsotg->dev, "exit partial_power_down failed\n");
hsotg->lx_state = DWC2_L0;
@@ -4506,6 +4490,8 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
spin_unlock_irqrestore(&hsotg->lock, flags);
dwc2_port_resume(hsotg);
} else {
+ dwc2_vbus_supply_init(hsotg);
+
/* Wait for controller to correctly update D+/D- level */
usleep_range(3000, 5000);
@@ -5368,6 +5354,7 @@ int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
hr->hprt0 = dwc2_read_hprt0(hsotg);
hr->hfir = dwc2_readl(hsotg->regs + HFIR);
+ hr->hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ);
hr->valid = true;
return 0;
@@ -5404,7 +5391,231 @@ int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
dwc2_writel(hr->hprt0, hsotg->regs + HPRT0);
dwc2_writel(hr->hfir, hsotg->regs + HFIR);
+ dwc2_writel(hr->hptxfsiz, hsotg->regs + HPTXFSIZ);
hsotg->frame_number = 0;
return 0;
}
+
+/**
+ * dwc2_host_enter_hibernation() - Put controller in Hibernation.
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
+{
+ unsigned long flags;
+ int ret = 0;
+ u32 hprt0;
+ u32 pcgcctl;
+ u32 gusbcfg;
+ u32 gpwrdn;
+
+ dev_dbg(hsotg->dev, "Preparing host for hibernation\n");
+ ret = dwc2_backup_global_registers(hsotg);
+ if (ret) {
+ dev_err(hsotg->dev, "%s: failed to backup global registers\n",
+ __func__);
+ return ret;
+ }
+ ret = dwc2_backup_host_registers(hsotg);
+ if (ret) {
+ dev_err(hsotg->dev, "%s: failed to backup host registers\n",
+ __func__);
+ return ret;
+ }
+
+ /* Enter USB Suspend Mode */
+ hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+ hprt0 |= HPRT0_SUSP;
+ hprt0 &= ~HPRT0_ENA;
+ dwc2_writel(hprt0, hsotg->regs + HPRT0);
+
+ /* Wait for the HPRT0.PrtSusp register field to be set */
+ if (dwc2_hsotg_wait_bit_set(hsotg, HPRT0, HPRT0_SUSP, 300))
+ dev_warn(hsotg->dev, "Suspend wasn't generated\n");
+
+ /*
+ * We need to disable interrupts to prevent servicing of any IRQ
+ * during going to hibernation
+ */
+ spin_lock_irqsave(&hsotg->lock, flags);
+ hsotg->lx_state = DWC2_L2;
+
+ gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+ if (gusbcfg & GUSBCFG_ULPI_UTMI_SEL) {
+ /* ULPI interface */
+ /* Suspend the Phy Clock */
+ pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
+ pcgcctl |= PCGCTL_STOPPCLK;
+ dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+ udelay(10);
+
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn |= GPWRDN_PMUACTV;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+ } else {
+ /* UTMI+ Interface */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn |= GPWRDN_PMUACTV;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
+ pcgcctl |= PCGCTL_STOPPCLK;
+ dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+ udelay(10);
+ }
+
+ /* Enable interrupts from wake up logic */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn |= GPWRDN_PMUINTSEL;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Unmask host mode interrupts in GPWRDN */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn |= GPWRDN_DISCONN_DET_MSK;
+ gpwrdn |= GPWRDN_LNSTSCHG_MSK;
+ gpwrdn |= GPWRDN_STS_CHGINT_MSK;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Enable Power Down Clamp */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn |= GPWRDN_PWRDNCLMP;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Switch off VDD */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn |= GPWRDN_PWRDNSWTCH;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+
+ hsotg->hibernated = 1;
+ hsotg->bus_suspended = 1;
+ dev_dbg(hsotg->dev, "Host hibernation completed\n");
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ return ret;
+}
+
+/*
+ * dwc2_host_exit_hibernation()
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ * @rem_wakeup: indicates whether resume is initiated by Device or Host.
+ * @param reset: indicates whether resume is initiated by Reset.
+ *
+ * Return: non-zero if failed to enter to hibernation.
+ *
+ * This function is for exiting from Host mode hibernation by
+ * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
+ */
+int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
+ int reset)
+{
+ u32 gpwrdn;
+ u32 hprt0;
+ int ret = 0;
+ struct dwc2_gregs_backup *gr;
+ struct dwc2_hregs_backup *hr;
+
+ gr = &hsotg->gr_backup;
+ hr = &hsotg->hr_backup;
+
+ dev_dbg(hsotg->dev,
+ "%s: called with rem_wakeup = %d reset = %d\n",
+ __func__, rem_wakeup, reset);
+
+ dwc2_hib_restore_common(hsotg, rem_wakeup, 1);
+ hsotg->hibernated = 0;
+
+ /*
+ * This step is not described in functional spec but if not wait for
+ * this delay, mismatch interrupts occurred because just after restore
+ * core is in Device mode(gintsts.curmode == 0)
+ */
+ mdelay(100);
+
+ /* Clear all pending interupts */
+ dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+
+ /* De-assert Restore */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn &= ~GPWRDN_RESTORE;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ /* Restore GUSBCFG, HCFG */
+ dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG);
+ dwc2_writel(hr->hcfg, hsotg->regs + HCFG);
+
+ /* De-assert Wakeup Logic */
+ gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+ gpwrdn &= ~GPWRDN_PMUACTV;
+ dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+ udelay(10);
+
+ hprt0 = hr->hprt0;
+ hprt0 |= HPRT0_PWR;
+ hprt0 &= ~HPRT0_ENA;
+ hprt0 &= ~HPRT0_SUSP;
+ dwc2_writel(hprt0, hsotg->regs + HPRT0);
+
+ hprt0 = hr->hprt0;
+ hprt0 |= HPRT0_PWR;
+ hprt0 &= ~HPRT0_ENA;
+ hprt0 &= ~HPRT0_SUSP;
+
+ if (reset) {
+ hprt0 |= HPRT0_RST;
+ dwc2_writel(hprt0, hsotg->regs + HPRT0);
+
+ /* Wait for Resume time and then program HPRT again */
+ mdelay(60);
+ hprt0 &= ~HPRT0_RST;
+ dwc2_writel(hprt0, hsotg->regs + HPRT0);
+ } else {
+ hprt0 |= HPRT0_RES;
+ dwc2_writel(hprt0, hsotg->regs + HPRT0);
+
+ /* Wait for Resume time and then program HPRT again */
+ mdelay(100);
+ hprt0 &= ~HPRT0_RES;
+ dwc2_writel(hprt0, hsotg->regs + HPRT0);
+ }
+ /* Clear all interrupt status */
+ hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+ hprt0 |= HPRT0_CONNDET;
+ hprt0 |= HPRT0_ENACHG;
+ hprt0 &= ~HPRT0_ENA;
+ dwc2_writel(hprt0, hsotg->regs + HPRT0);
+
+ hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+
+ /* Clear all pending interupts */
+ dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+
+ /* Restore global registers */
+ ret = dwc2_restore_global_registers(hsotg);
+ if (ret) {
+ dev_err(hsotg->dev, "%s: failed to restore registers\n",
+ __func__);
+ return ret;
+ }
+
+ /* Restore host registers */
+ ret = dwc2_restore_host_registers(hsotg);
+ if (ret) {
+ dev_err(hsotg->dev, "%s: failed to restore host registers\n",
+ __func__);
+ return ret;
+ }
+
+ hsotg->hibernated = 0;
+ hsotg->bus_suspended = 0;
+ hsotg->lx_state = DWC2_L0;
+ dev_dbg(hsotg->dev, "Host hibernation restore complete\n");
+ return ret;
+}
diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h
index ad60e46e66e1..96a9da5fb202 100644
--- a/drivers/usb/dwc2/hcd.h
+++ b/drivers/usb/dwc2/hcd.h
@@ -783,19 +783,6 @@ int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg);
*/
void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg);
-/**
- * dwc2_hcd_dump_frrem() - Dumps the average frame remaining at SOF
- *
- * @hsotg: The DWC2 HCD
- *
- * This can be used to determine average interrupt latency. Frame remaining is
- * also shown for start transfer and two additional sample points.
- *
- * NOTE: This function will be removed once the peripheral controller code
- * is integrated and the driver is stable
- */
-void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg);
-
/* URB interface */
/* Transfer flags */
@@ -813,47 +800,4 @@ int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context);
void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
int status);
-#ifdef DEBUG
-/*
- * Macro to sample the remaining PHY clocks left in the current frame. This
- * may be used during debugging to determine the average time it takes to
- * execute sections of code. There are two possible sample points, "a" and
- * "b", so the _letter_ argument must be one of these values.
- *
- * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
- * example, "cat /sys/devices/lm0/hcd_frrem".
- */
-#define dwc2_sample_frrem(_hcd_, _qh_, _letter_) \
-do { \
- struct hfnum_data _hfnum_; \
- struct dwc2_qtd *_qtd_; \
- \
- _qtd_ = list_entry((_qh_)->qtd_list.next, struct dwc2_qtd, \
- qtd_list_entry); \
- if (usb_pipeint(_qtd_->urb->pipe) && \
- (_qh_)->start_active_frame != 0 && !_qtd_->complete_split) { \
- _hfnum_.d32 = dwc2_readl((_hcd_)->regs + HFNUM); \
- switch (_hfnum_.b.frnum & 0x7) { \
- case 7: \
- (_hcd_)->hfnum_7_samples_##_letter_++; \
- (_hcd_)->hfnum_7_frrem_accum_##_letter_ += \
- _hfnum_.b.frrem; \
- break; \
- case 0: \
- (_hcd_)->hfnum_0_samples_##_letter_++; \
- (_hcd_)->hfnum_0_frrem_accum_##_letter_ += \
- _hfnum_.b.frrem; \
- break; \
- default: \
- (_hcd_)->hfnum_other_samples_##_letter_++; \
- (_hcd_)->hfnum_other_frrem_accum_##_letter_ += \
- _hfnum_.b.frrem; \
- break; \
- } \
- } \
-} while (0)
-#else
-#define dwc2_sample_frrem(_hcd_, _qh_, _letter_) do {} while (0)
-#endif
-
#endif /* __DWC2_HCD_H__ */
diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h
index 2c906d8ee465..38391e48351f 100644
--- a/drivers/usb/dwc2/hw.h
+++ b/drivers/usb/dwc2/hw.h
@@ -231,6 +231,7 @@
#define GUID HSOTG_REG(0x003c)
#define GSNPSID HSOTG_REG(0x0040)
#define GHWCFG1 HSOTG_REG(0x0044)
+#define GSNPSID_ID_MASK GENMASK(31, 16)
#define GHWCFG2 HSOTG_REG(0x0048)
#define GHWCFG2_OTG_ENABLE_IC_USB BIT(31)
@@ -309,6 +310,7 @@
#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14)
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14
+#define GHWCFG4_ACG_SUPPORTED BIT(12)
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2
@@ -320,28 +322,30 @@
#define GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT 0
#define GLPMCFG HSOTG_REG(0x0054)
-#define GLPMCFG_INV_SEL_HSIC BIT(31)
-#define GLPMCFG_HSIC_CONNECT BIT(30)
-#define GLPMCFG_RETRY_COUNT_STS_MASK (0x7 << 25)
-#define GLPMCFG_RETRY_COUNT_STS_SHIFT 25
-#define GLPMCFG_SEND_LPM BIT(24)
-#define GLPMCFG_RETRY_COUNT_MASK (0x7 << 21)
-#define GLPMCFG_RETRY_COUNT_SHIFT 21
-#define GLPMCFG_LPM_CHAN_INDEX_MASK (0xf << 17)
-#define GLPMCFG_LPM_CHAN_INDEX_SHIFT 17
-#define GLPMCFG_SLEEP_STATE_RESUMEOK BIT(16)
-#define GLPMCFG_PRT_SLEEP_STS BIT(15)
-#define GLPMCFG_LPM_RESP_MASK (0x3 << 13)
-#define GLPMCFG_LPM_RESP_SHIFT 13
+#define GLPMCFG_INVSELHSIC BIT(31)
+#define GLPMCFG_HSICCON BIT(30)
+#define GLPMCFG_RSTRSLPSTS BIT(29)
+#define GLPMCFG_ENBESL BIT(28)
+#define GLPMCFG_LPM_RETRYCNT_STS_MASK (0x7 << 25)
+#define GLPMCFG_LPM_RETRYCNT_STS_SHIFT 25
+#define GLPMCFG_SNDLPM BIT(24)
+#define GLPMCFG_RETRY_CNT_MASK (0x7 << 21)
+#define GLPMCFG_RETRY_CNT_SHIFT 21
+#define GLPMCFG_LPM_CHNL_INDX_MASK (0xf << 17)
+#define GLPMCFG_LPM_CHNL_INDX_SHIFT 17
+#define GLPMCFG_L1RESUMEOK BIT(16)
+#define GLPMCFG_SLPSTS BIT(15)
+#define GLPMCFG_COREL1RES_MASK (0x3 << 13)
+#define GLPMCFG_COREL1RES_SHIFT 13
#define GLPMCFG_HIRD_THRES_MASK (0x1f << 8)
#define GLPMCFG_HIRD_THRES_SHIFT 8
-#define GLPMCFG_HIRD_THRES_EN (0x10 << 8)
-#define GLPMCFG_EN_UTMI_SLEEP BIT(7)
-#define GLPMCFG_REM_WKUP_EN BIT(6)
+#define GLPMCFG_HIRD_THRES_EN (0x10 << 8)
+#define GLPMCFG_ENBLSLPM BIT(7)
+#define GLPMCFG_BREMOTEWAKE BIT(6)
#define GLPMCFG_HIRD_MASK (0xf << 2)
#define GLPMCFG_HIRD_SHIFT 2
-#define GLPMCFG_APPL_RESP BIT(1)
-#define GLPMCFG_LPM_CAP_EN BIT(0)
+#define GLPMCFG_APPL1RES BIT(1)
+#define GLPMCFG_LPMCAP BIT(0)
#define GPWRDN HSOTG_REG(0x0058)
#define GPWRDN_MULT_VAL_ID_BC_MASK (0x1f << 24)
@@ -644,6 +648,10 @@
#define PCGCTL_GATEHCLK BIT(1)
#define PCGCTL_STOPPCLK BIT(0)
+#define PCGCCTL1 HSOTG_REG(0xe04)
+#define PCGCCTL1_TIMER (0x3 << 1)
+#define PCGCCTL1_GATEEN BIT(0)
+
#define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000))
/* Host Mode Registers */
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index c4a47496d2fb..f03e41879224 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -252,6 +252,20 @@ static void dwc2_set_param_tx_fifo_sizes(struct dwc2_hsotg *hsotg)
p->g_tx_fifo_size[i] = depth_average;
}
+static void dwc2_set_param_power_down(struct dwc2_hsotg *hsotg)
+{
+ int val;
+
+ if (hsotg->hw_params.hibernation)
+ val = 2;
+ else if (hsotg->hw_params.power_optimized)
+ val = 1;
+ else
+ val = 0;
+
+ hsotg->params.power_down = val;
+}
+
/**
* dwc2_set_default_params() - Set all core parameters to their
* auto-detected default values.
@@ -266,21 +280,27 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg)
dwc2_set_param_phy_type(hsotg);
dwc2_set_param_speed(hsotg);
dwc2_set_param_phy_utmi_width(hsotg);
+ dwc2_set_param_power_down(hsotg);
p->phy_ulpi_ddr = false;
p->phy_ulpi_ext_vbus = false;
p->enable_dynamic_fifo = hw->enable_dynamic_fifo;
p->en_multiple_tx_fifo = hw->en_multiple_tx_fifo;
p->i2c_enable = hw->i2c_enable;
+ p->acg_enable = hw->acg_enable;
p->ulpi_fs_ls = false;
p->ts_dline = false;
p->reload_ctl = (hw->snpsid >= DWC2_CORE_REV_2_92a);
p->uframe_sched = true;
p->external_id_pin_ctl = false;
- p->hibernation = false;
+ p->lpm = true;
+ p->lpm_clock_gating = true;
+ p->besl = true;
+ p->hird_threshold_en = true;
+ p->hird_threshold = 4;
p->max_packet_count = hw->max_packet_count;
p->max_transfer_size = hw->max_transfer_size;
- p->ahbcfg = GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT;
+ p->ahbcfg = GAHBCFG_HBSTLEN_INCR << GAHBCFG_HBSTLEN_SHIFT;
if ((hsotg->dr_mode == USB_DR_MODE_HOST) ||
(hsotg->dr_mode == USB_DR_MODE_OTG)) {
@@ -463,6 +483,38 @@ static void dwc2_check_param_phy_utmi_width(struct dwc2_hsotg *hsotg)
dwc2_set_param_phy_utmi_width(hsotg);
}
+static void dwc2_check_param_power_down(struct dwc2_hsotg *hsotg)
+{
+ int param = hsotg->params.power_down;
+
+ switch (param) {
+ case DWC2_POWER_DOWN_PARAM_NONE:
+ break;
+ case DWC2_POWER_DOWN_PARAM_PARTIAL:
+ if (hsotg->hw_params.power_optimized)
+ break;
+ dev_dbg(hsotg->dev,
+ "Partial power down isn't supported by HW\n");
+ param = DWC2_POWER_DOWN_PARAM_NONE;
+ break;
+ case DWC2_POWER_DOWN_PARAM_HIBERNATION:
+ if (hsotg->hw_params.hibernation)
+ break;
+ dev_dbg(hsotg->dev,
+ "Hibernation isn't supported by HW\n");
+ param = DWC2_POWER_DOWN_PARAM_NONE;
+ break;
+ default:
+ dev_err(hsotg->dev,
+ "%s: Invalid parameter power_down=%d\n",
+ __func__, param);
+ param = DWC2_POWER_DOWN_PARAM_NONE;
+ break;
+ }
+
+ hsotg->params.power_down = param;
+}
+
static void dwc2_check_param_tx_fifo_sizes(struct dwc2_hsotg *hsotg)
{
int fifo_count;
@@ -523,10 +575,19 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg)
dwc2_check_param_phy_type(hsotg);
dwc2_check_param_speed(hsotg);
dwc2_check_param_phy_utmi_width(hsotg);
+ dwc2_check_param_power_down(hsotg);
CHECK_BOOL(enable_dynamic_fifo, hw->enable_dynamic_fifo);
CHECK_BOOL(en_multiple_tx_fifo, hw->en_multiple_tx_fifo);
CHECK_BOOL(i2c_enable, hw->i2c_enable);
+ CHECK_BOOL(acg_enable, hw->acg_enable);
CHECK_BOOL(reload_ctl, (hsotg->hw_params.snpsid > DWC2_CORE_REV_2_92a));
+ CHECK_BOOL(lpm, (hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_80a));
+ CHECK_BOOL(lpm, hw->lpm_mode);
+ CHECK_BOOL(lpm_clock_gating, hsotg->params.lpm);
+ CHECK_BOOL(besl, hsotg->params.lpm);
+ CHECK_BOOL(besl, (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a));
+ CHECK_BOOL(hird_threshold_en, hsotg->params.lpm);
+ CHECK_RANGE(hird_threshold, 0, hsotg->params.besl ? 12 : 7, 0);
CHECK_RANGE(max_packet_count,
15, hw->max_packet_count,
hw->max_packet_count);
@@ -579,19 +640,15 @@ static void dwc2_get_host_hwparams(struct dwc2_hsotg *hsotg)
struct dwc2_hw_params *hw = &hsotg->hw_params;
u32 gnptxfsiz;
u32 hptxfsiz;
- bool forced;
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
return;
- forced = dwc2_force_mode_if_needed(hsotg, true);
+ dwc2_force_mode(hsotg, true);
gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ);
- if (forced)
- dwc2_clear_force_mode(hsotg);
-
hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
FIFOSIZE_DEPTH_SHIFT;
hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >>
@@ -606,14 +663,13 @@ static void dwc2_get_host_hwparams(struct dwc2_hsotg *hsotg)
static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg)
{
struct dwc2_hw_params *hw = &hsotg->hw_params;
- bool forced;
u32 gnptxfsiz;
int fifo, fifo_count;
if (hsotg->dr_mode == USB_DR_MODE_HOST)
return;
- forced = dwc2_force_mode_if_needed(hsotg, false);
+ dwc2_force_mode(hsotg, false);
gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
@@ -625,9 +681,6 @@ static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg)
FIFOSIZE_DEPTH_MASK) >> FIFOSIZE_DEPTH_SHIFT;
}
- if (forced)
- dwc2_clear_force_mode(hsotg);
-
hw->dev_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
FIFOSIZE_DEPTH_SHIFT;
}
@@ -646,14 +699,13 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
/*
* Attempt to ensure this device is really a DWC_otg Controller.
* Read and verify the GSNPSID register contents. The value should be
- * 0x45f42xxx or 0x45f43xxx, which corresponds to either "OT2" or "OT3",
- * as in "OTG version 2.xx" or "OTG version 3.xx".
+ * 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx
*/
+
hw->snpsid = dwc2_readl(hsotg->regs + GSNPSID);
- if ((hw->snpsid & 0xfffff000) != 0x4f542000 &&
- (hw->snpsid & 0xfffff000) != 0x4f543000 &&
- (hw->snpsid & 0xffff0000) != 0x55310000 &&
- (hw->snpsid & 0xffff0000) != 0x55320000) {
+ if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID &&
+ (hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID &&
+ (hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) {
dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n",
hw->snpsid);
return -ENODEV;
@@ -706,6 +758,7 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
hw->i2c_enable = !!(hwcfg3 & GHWCFG3_I2C);
hw->total_fifo_size = (hwcfg3 & GHWCFG3_DFIFO_DEPTH_MASK) >>
GHWCFG3_DFIFO_DEPTH_SHIFT;
+ hw->lpm_mode = !!(hwcfg3 & GHWCFG3_OTG_LPM_EN);
/* hwcfg4 */
hw->en_multiple_tx_fifo = !!(hwcfg4 & GHWCFG4_DED_FIFO_EN);
@@ -715,8 +768,10 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
GHWCFG4_NUM_IN_EPS_SHIFT;
hw->dma_desc_enable = !!(hwcfg4 & GHWCFG4_DESC_DMA);
hw->power_optimized = !!(hwcfg4 & GHWCFG4_POWER_OPTIMIZ);
+ hw->hibernation = !!(hwcfg4 & GHWCFG4_HIBER);
hw->utmi_phy_data_width = (hwcfg4 & GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK) >>
GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT;
+ hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED);
/* fifo sizes */
hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>
diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c
index 3ecc951a1aea..7f21747007f1 100644
--- a/drivers/usb/dwc2/pci.c
+++ b/drivers/usb/dwc2/pci.c
@@ -83,7 +83,6 @@ static void dwc2_pci_remove(struct pci_dev *pci)
platform_device_unregister(glue->dwc2);
usb_phy_generic_unregister(glue->phy);
- kfree(glue);
pci_set_drvdata(pci, NULL);
}
@@ -105,10 +104,17 @@ static int dwc2_pci_probe(struct pci_dev *pci,
pci_set_master(pci);
+ phy = usb_phy_generic_register();
+ if (IS_ERR(phy)) {
+ dev_err(dev, "error registering generic PHY (%ld)\n",
+ PTR_ERR(phy));
+ return PTR_ERR(phy);
+ }
+
dwc2 = platform_device_alloc("dwc2", PLATFORM_DEVID_AUTO);
if (!dwc2) {
dev_err(dev, "couldn't allocate dwc2 device\n");
- return -ENOMEM;
+ goto err;
}
memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
@@ -125,32 +131,25 @@ static int dwc2_pci_probe(struct pci_dev *pci,
ret = platform_device_add_resources(dwc2, res, ARRAY_SIZE(res));
if (ret) {
dev_err(dev, "couldn't add resources to dwc2 device\n");
- return ret;
+ goto err;
}
dwc2->dev.parent = dev;
- phy = usb_phy_generic_register();
- if (IS_ERR(phy)) {
- dev_err(dev, "error registering generic PHY (%ld)\n",
- PTR_ERR(phy));
- return PTR_ERR(phy);
- }
-
ret = dwc2_pci_quirks(pci, dwc2);
if (ret)
goto err;
+ glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
+ if (!glue)
+ goto err;
+
ret = platform_device_add(dwc2);
if (ret) {
dev_err(dev, "failed to register dwc2 device\n");
goto err;
}
- glue = kzalloc(sizeof(*glue), GFP_KERNEL);
- if (!glue)
- return -ENOMEM;
-
glue->phy = phy;
glue->dwc2 = dwc2;
pci_set_drvdata(pci, glue);
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 4703478f702f..4c0819554bcd 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -382,8 +382,10 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (!dev->dev.dma_mask)
dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
retval = dma_set_coherent_mask(&dev->dev, DMA_BIT_MASK(32));
- if (retval)
+ if (retval) {
+ dev_err(&dev->dev, "can't set coherent DMA mask: %d\n", retval);
return retval;
+ }
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
hsotg->regs = devm_ioremap_resource(&dev->dev, res);
@@ -425,13 +427,20 @@ static int dwc2_driver_probe(struct platform_device *dev)
* Reset before dwc2_get_hwparams() then it could get power-on real
* reset value form registers.
*/
- dwc2_core_reset_and_force_dr_mode(hsotg);
+ retval = dwc2_core_reset(hsotg, false);
+ if (retval)
+ goto error;
/* Detect config values from hardware */
retval = dwc2_get_hwparams(hsotg);
if (retval)
goto error;
+ /*
+ * For OTG cores, set the force mode bits to reflect the value
+ * of dr_mode. Force mode bits should not be touched at any
+ * other time after this.
+ */
dwc2_force_dr_mode(hsotg);
retval = dwc2_init_params(hsotg);
@@ -439,7 +448,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
goto error;
if (hsotg->dr_mode != USB_DR_MODE_HOST) {
- retval = dwc2_gadget_init(hsotg, hsotg->irq);
+ retval = dwc2_gadget_init(hsotg);
if (retval)
goto error;
hsotg->gadget_enabled = 1;
@@ -456,6 +465,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
}
platform_set_drvdata(dev, hsotg);
+ hsotg->hibernated = 0;
dwc2_debugfs_init(hsotg);
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 7ac725038f8d..025bc68094fc 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -6,7 +6,7 @@ obj-$(CONFIG_USB_DWC3) += dwc3.o
dwc3-y := core.o
-ifneq ($(CONFIG_FTRACE),)
+ifneq ($(CONFIG_TRACING),)
dwc3-y += trace.o
endif
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index e94bf91cc58a..a15648d25e30 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -89,10 +89,7 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
return 0;
}
-static void dwc3_event_buffers_cleanup(struct dwc3 *dwc);
-static int dwc3_event_buffers_setup(struct dwc3 *dwc);
-
-static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
+void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
{
u32 reg;
@@ -110,13 +107,19 @@ static void __dwc3_set_mode(struct work_struct *work)
unsigned long flags;
int ret;
+ if (dwc->dr_mode != USB_DR_MODE_OTG)
+ return;
+
+ if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG)
+ dwc3_otg_update(dwc, 0);
+
if (!dwc->desired_dr_role)
return;
if (dwc->desired_dr_role == dwc->current_dr_role)
return;
- if (dwc->dr_mode != USB_DR_MODE_OTG)
+ if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev)
return;
switch (dwc->current_dr_role) {
@@ -127,6 +130,13 @@ static void __dwc3_set_mode(struct work_struct *work)
dwc3_gadget_exit(dwc);
dwc3_event_buffers_cleanup(dwc);
break;
+ case DWC3_GCTL_PRTCAP_OTG:
+ dwc3_otg_exit(dwc);
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc->desired_otg_role = DWC3_OTG_ROLE_IDLE;
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ dwc3_otg_update(dwc, 1);
+ break;
default:
break;
}
@@ -162,9 +172,14 @@ static void __dwc3_set_mode(struct work_struct *work)
if (ret)
dev_err(dwc->dev, "failed to initialize peripheral\n");
break;
+ case DWC3_GCTL_PRTCAP_OTG:
+ dwc3_otg_init(dwc);
+ dwc3_otg_update(dwc, 0);
+ break;
default:
break;
}
+
}
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
@@ -229,7 +244,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
do {
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (!(reg & DWC3_DCTL_CSFTRST))
- return 0;
+ goto done;
udelay(1);
} while (--retries);
@@ -238,6 +253,17 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
phy_exit(dwc->usb2_generic_phy);
return -ETIMEDOUT;
+
+done:
+ /*
+ * For DWC_usb31 controller, once DWC3_DCTL_CSFTRST bit is cleared,
+ * we must wait at least 50ms before accessing the PHY domain
+ * (synchronization delay). DWC_usb31 programming guide section 1.3.2.
+ */
+ if (dwc3_is_usb31(dwc))
+ msleep(50);
+
+ return 0;
}
/*
@@ -348,7 +374,7 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
*
* Returns 0 on success otherwise negative errno.
*/
-static int dwc3_event_buffers_setup(struct dwc3 *dwc)
+int dwc3_event_buffers_setup(struct dwc3 *dwc)
{
struct dwc3_event_buffer *evt;
@@ -365,7 +391,7 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc)
return 0;
}
-static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
+void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
{
struct dwc3_event_buffer *evt;
@@ -846,6 +872,43 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
}
+ /*
+ * Must config both number of packets and max burst settings to enable
+ * RX and/or TX threshold.
+ */
+ if (dwc3_is_usb31(dwc) && dwc->dr_mode == USB_DR_MODE_HOST) {
+ u8 rx_thr_num = dwc->rx_thr_num_pkt_prd;
+ u8 rx_maxburst = dwc->rx_max_burst_prd;
+ u8 tx_thr_num = dwc->tx_thr_num_pkt_prd;
+ u8 tx_maxburst = dwc->tx_max_burst_prd;
+
+ if (rx_thr_num && rx_maxburst) {
+ reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
+ reg |= DWC31_RXTHRNUMPKTSEL_PRD;
+
+ reg &= ~DWC31_RXTHRNUMPKT_PRD(~0);
+ reg |= DWC31_RXTHRNUMPKT_PRD(rx_thr_num);
+
+ reg &= ~DWC31_MAXRXBURSTSIZE_PRD(~0);
+ reg |= DWC31_MAXRXBURSTSIZE_PRD(rx_maxburst);
+
+ dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
+ }
+
+ if (tx_thr_num && tx_maxburst) {
+ reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG);
+ reg |= DWC31_TXTHRNUMPKTSEL_PRD;
+
+ reg &= ~DWC31_TXTHRNUMPKT_PRD(~0);
+ reg |= DWC31_TXTHRNUMPKT_PRD(tx_thr_num);
+
+ reg &= ~DWC31_MAXTXBURSTSIZE_PRD(~0);
+ reg |= DWC31_MAXTXBURSTSIZE_PRD(tx_maxburst);
+
+ dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg);
+ }
+ }
+
return 0;
err4:
@@ -1016,6 +1079,10 @@ static void dwc3_get_properties(struct dwc3 *dwc)
u8 lpm_nyet_threshold;
u8 tx_de_emphasis;
u8 hird_threshold;
+ u8 rx_thr_num_pkt_prd;
+ u8 rx_max_burst_prd;
+ u8 tx_thr_num_pkt_prd;
+ u8 tx_max_burst_prd;
/* default to highest possible threshold */
lpm_nyet_threshold = 0xff;
@@ -1050,6 +1117,14 @@ static void dwc3_get_properties(struct dwc3 *dwc)
&hird_threshold);
dwc->usb3_lpm_capable = device_property_read_bool(dev,
"snps,usb3_lpm_capable");
+ device_property_read_u8(dev, "snps,rx-thr-num-pkt-prd",
+ &rx_thr_num_pkt_prd);
+ device_property_read_u8(dev, "snps,rx-max-burst-prd",
+ &rx_max_burst_prd);
+ device_property_read_u8(dev, "snps,tx-thr-num-pkt-prd",
+ &tx_thr_num_pkt_prd);
+ device_property_read_u8(dev, "snps,tx-max-burst-prd",
+ &tx_max_burst_prd);
dwc->disable_scramble_quirk = device_property_read_bool(dev,
"snps,disable_scramble_quirk");
@@ -1100,6 +1175,12 @@ static void dwc3_get_properties(struct dwc3 *dwc)
dwc->hird_threshold = hird_threshold
| (dwc->is_utmi_l1_suspend << 4);
+ dwc->rx_thr_num_pkt_prd = rx_thr_num_pkt_prd;
+ dwc->rx_max_burst_prd = rx_max_burst_prd;
+
+ dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd;
+ dwc->tx_max_burst_prd = tx_max_burst_prd;
+
dwc->imod_interval = 0;
}
@@ -1326,6 +1407,20 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
if (!PMSG_IS_AUTO(msg))
dwc3_core_exit(dwc);
break;
+ case DWC3_GCTL_PRTCAP_OTG:
+ /* do nothing during runtime_suspend */
+ if (PMSG_IS_AUTO(msg))
+ break;
+
+ if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_gadget_suspend(dwc);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ }
+
+ dwc3_otg_exit(dwc);
+ dwc3_core_exit(dwc);
+ break;
default:
/* do nothing */
break;
@@ -1345,6 +1440,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
if (ret)
return ret;
+ dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_resume(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1355,7 +1451,29 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
ret = dwc3_core_init(dwc);
if (ret)
return ret;
+ dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
+ }
+ break;
+ case DWC3_GCTL_PRTCAP_OTG:
+ /* nothing to do on runtime_resume */
+ if (PMSG_IS_AUTO(msg))
+ break;
+
+ ret = dwc3_core_init(dwc);
+ if (ret)
+ return ret;
+
+ dwc3_set_prtcap(dwc, dwc->current_dr_role);
+
+ dwc3_otg_init(dwc);
+ if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) {
+ dwc3_otg_host_init(dwc);
+ } else if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_gadget_resume(dwc);
+ spin_unlock_irqrestore(&dwc->lock, flags);
}
+
break;
default:
/* do nothing */
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 860d2bc184d1..4f3b43809917 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -58,6 +58,11 @@
#define DWC3_DEVICE_EVENT_CMD_CMPL 10
#define DWC3_DEVICE_EVENT_OVERFLOW 11
+/* Controller's role while using the OTG block */
+#define DWC3_OTG_ROLE_IDLE 0
+#define DWC3_OTG_ROLE_HOST 1
+#define DWC3_OTG_ROLE_DEVICE 2
+
#define DWC3_GEVNTCOUNT_MASK 0xfffc
#define DWC3_GEVNTCOUNT_EHB BIT(31)
#define DWC3_GSNPSID_MASK 0xffff0000
@@ -100,6 +105,11 @@
#define DWC3_GHWPARAMS7 0xc15c
#define DWC3_GDBGFIFOSPACE 0xc160
#define DWC3_GDBGLTSSM 0xc164
+#define DWC3_GDBGBMU 0xc16c
+#define DWC3_GDBGLSPMUX 0xc170
+#define DWC3_GDBGLSP 0xc174
+#define DWC3_GDBGEPINFO0 0xc178
+#define DWC3_GDBGEPINFO1 0xc17c
#define DWC3_GPRTBIMAP_HS0 0xc180
#define DWC3_GPRTBIMAP_HS1 0xc184
#define DWC3_GPRTBIMAP_FS0 0xc188
@@ -173,6 +183,26 @@
#define DWC3_GRXTHRCFG_RXPKTCNT(n) (((n) & 0xf) << 24)
#define DWC3_GRXTHRCFG_PKTCNTSEL BIT(29)
+/* Global RX Threshold Configuration Register for DWC_usb31 only */
+#define DWC31_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 16)
+#define DWC31_GRXTHRCFG_RXPKTCNT(n) (((n) & 0x1f) << 21)
+#define DWC31_GRXTHRCFG_PKTCNTSEL BIT(26)
+#define DWC31_RXTHRNUMPKTSEL_HS_PRD BIT(15)
+#define DWC31_RXTHRNUMPKT_HS_PRD(n) (((n) & 0x3) << 13)
+#define DWC31_RXTHRNUMPKTSEL_PRD BIT(10)
+#define DWC31_RXTHRNUMPKT_PRD(n) (((n) & 0x1f) << 5)
+#define DWC31_MAXRXBURSTSIZE_PRD(n) ((n) & 0x1f)
+
+/* Global TX Threshold Configuration Register for DWC_usb31 only */
+#define DWC31_GTXTHRCFG_MAXTXBURSTSIZE(n) (((n) & 0x1f) << 16)
+#define DWC31_GTXTHRCFG_TXPKTCNT(n) (((n) & 0x1f) << 21)
+#define DWC31_GTXTHRCFG_PKTCNTSEL BIT(26)
+#define DWC31_TXTHRNUMPKTSEL_HS_PRD BIT(15)
+#define DWC31_TXTHRNUMPKT_HS_PRD(n) (((n) & 0x3) << 13)
+#define DWC31_TXTHRNUMPKTSEL_PRD BIT(10)
+#define DWC31_TXTHRNUMPKT_PRD(n) (((n) & 0x1f) << 5)
+#define DWC31_MAXTXBURSTSIZE_PRD(n) ((n) & 0x1f)
+
/* Global Configuration Register */
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
#define DWC3_GCTL_U2RSTECN BIT(16)
@@ -201,6 +231,15 @@
#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28)
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
+/* Global Status Register */
+#define DWC3_GSTS_OTG_IP BIT(10)
+#define DWC3_GSTS_BC_IP BIT(9)
+#define DWC3_GSTS_ADP_IP BIT(8)
+#define DWC3_GSTS_HOST_IP BIT(7)
+#define DWC3_GSTS_DEVICE_IP BIT(6)
+#define DWC3_GSTS_CSR_TIMEOUT BIT(5)
+#define DWC3_GSTS_BUS_ERR_ADDR_VLD BIT(4)
+
/* Global USB2 PHY Configuration Register */
#define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31)
#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS BIT(30)
@@ -241,6 +280,8 @@
#define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1)
/* Global TX Fifo Size Register */
+#define DWC31_GTXFIFOSIZ_TXFRAMNUM BIT(15) /* DWC_usb31 only */
+#define DWC31_GTXFIFOSIZ_TXFDEF(n) ((n) & 0x7fff) /* DWC_usb31 only */
#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
@@ -286,6 +327,11 @@
#define DWC3_MAX_HIBER_SCRATCHBUFS 15
/* Global HWPARAMS6 Register */
+#define DWC3_GHWPARAMS6_BCSUPPORT BIT(14)
+#define DWC3_GHWPARAMS6_OTG3SUPPORT BIT(13)
+#define DWC3_GHWPARAMS6_ADPSUPPORT BIT(12)
+#define DWC3_GHWPARAMS6_HNPSUPPORT BIT(11)
+#define DWC3_GHWPARAMS6_SRPSUPPORT BIT(10)
#define DWC3_GHWPARAMS6_EN_FPGA BIT(7)
/* Global HWPARAMS7 Register */
@@ -467,6 +513,74 @@
#define DWC3_DEV_IMOD_INTERVAL_SHIFT 0
#define DWC3_DEV_IMOD_INTERVAL_MASK (0xffff << 0)
+/* OTG Configuration Register */
+#define DWC3_OCFG_DISPWRCUTTOFF BIT(5)
+#define DWC3_OCFG_HIBDISMASK BIT(4)
+#define DWC3_OCFG_SFTRSTMASK BIT(3)
+#define DWC3_OCFG_OTGVERSION BIT(2)
+#define DWC3_OCFG_HNPCAP BIT(1)
+#define DWC3_OCFG_SRPCAP BIT(0)
+
+/* OTG CTL Register */
+#define DWC3_OCTL_OTG3GOERR BIT(7)
+#define DWC3_OCTL_PERIMODE BIT(6)
+#define DWC3_OCTL_PRTPWRCTL BIT(5)
+#define DWC3_OCTL_HNPREQ BIT(4)
+#define DWC3_OCTL_SESREQ BIT(3)
+#define DWC3_OCTL_TERMSELIDPULSE BIT(2)
+#define DWC3_OCTL_DEVSETHNPEN BIT(1)
+#define DWC3_OCTL_HSTSETHNPEN BIT(0)
+
+/* OTG Event Register */
+#define DWC3_OEVT_DEVICEMODE BIT(31)
+#define DWC3_OEVT_XHCIRUNSTPSET BIT(27)
+#define DWC3_OEVT_DEVRUNSTPSET BIT(26)
+#define DWC3_OEVT_HIBENTRY BIT(25)
+#define DWC3_OEVT_CONIDSTSCHNG BIT(24)
+#define DWC3_OEVT_HRRCONFNOTIF BIT(23)
+#define DWC3_OEVT_HRRINITNOTIF BIT(22)
+#define DWC3_OEVT_ADEVIDLE BIT(21)
+#define DWC3_OEVT_ADEVBHOSTEND BIT(20)
+#define DWC3_OEVT_ADEVHOST BIT(19)
+#define DWC3_OEVT_ADEVHNPCHNG BIT(18)
+#define DWC3_OEVT_ADEVSRPDET BIT(17)
+#define DWC3_OEVT_ADEVSESSENDDET BIT(16)
+#define DWC3_OEVT_BDEVBHOSTEND BIT(11)
+#define DWC3_OEVT_BDEVHNPCHNG BIT(10)
+#define DWC3_OEVT_BDEVSESSVLDDET BIT(9)
+#define DWC3_OEVT_BDEVVBUSCHNG BIT(8)
+#define DWC3_OEVT_BSESSVLD BIT(3)
+#define DWC3_OEVT_HSTNEGSTS BIT(2)
+#define DWC3_OEVT_SESREQSTS BIT(1)
+#define DWC3_OEVT_ERROR BIT(0)
+
+/* OTG Event Enable Register */
+#define DWC3_OEVTEN_XHCIRUNSTPSETEN BIT(27)
+#define DWC3_OEVTEN_DEVRUNSTPSETEN BIT(26)
+#define DWC3_OEVTEN_HIBENTRYEN BIT(25)
+#define DWC3_OEVTEN_CONIDSTSCHNGEN BIT(24)
+#define DWC3_OEVTEN_HRRCONFNOTIFEN BIT(23)
+#define DWC3_OEVTEN_HRRINITNOTIFEN BIT(22)
+#define DWC3_OEVTEN_ADEVIDLEEN BIT(21)
+#define DWC3_OEVTEN_ADEVBHOSTENDEN BIT(20)
+#define DWC3_OEVTEN_ADEVHOSTEN BIT(19)
+#define DWC3_OEVTEN_ADEVHNPCHNGEN BIT(18)
+#define DWC3_OEVTEN_ADEVSRPDETEN BIT(17)
+#define DWC3_OEVTEN_ADEVSESSENDDETEN BIT(16)
+#define DWC3_OEVTEN_BDEVBHOSTENDEN BIT(11)
+#define DWC3_OEVTEN_BDEVHNPCHNGEN BIT(10)
+#define DWC3_OEVTEN_BDEVSESSVLDDETEN BIT(9)
+#define DWC3_OEVTEN_BDEVVBUSCHNGEN BIT(8)
+
+/* OTG Status Register */
+#define DWC3_OSTS_DEVRUNSTP BIT(13)
+#define DWC3_OSTS_XHCIRUNSTP BIT(12)
+#define DWC3_OSTS_PERIPHERALSTATE BIT(4)
+#define DWC3_OSTS_XHCIPRTPOWER BIT(3)
+#define DWC3_OSTS_BSESVLD BIT(2)
+#define DWC3_OSTS_VBUSVLD BIT(1)
+#define DWC3_OSTS_CONIDSTS BIT(0)
+
/* Structures */
struct dwc3_trb;
@@ -781,6 +895,10 @@ struct dwc3_scratchpad_array {
* @regs_size: address space size
* @fladj: frame length adjustment
* @irq_gadget: peripheral controller's IRQ number
+ * @otg_irq: IRQ number for OTG IRQs
+ * @current_otg_role: current role of operation while using the OTG block
+ * @desired_otg_role: desired role of operation while using the OTG block
+ * @otg_restart_host: flag that OTG controller needs to restart host
* @nr_scratch: number of scratch buffers
* @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes)
@@ -816,6 +934,10 @@ struct dwc3_scratchpad_array {
* @test_mode_nr: test feature selector
* @lpm_nyet_threshold: LPM NYET response threshold
* @hird_threshold: HIRD threshold
+ * @rx_thr_num_pkt_prd: periodic ESS receive packet count
+ * @rx_max_burst_prd: max periodic ESS receive burst size
+ * @tx_thr_num_pkt_prd: periodic ESS transmit packet count
+ * @tx_max_burst_prd: max periodic ESS transmit burst size
* @hsphy_interface: "utmi" or "ulpi"
* @connected: true when we're connected to a host, false otherwise
* @delayed_status: true when gadget driver asks for delayed status
@@ -914,6 +1036,10 @@ struct dwc3 {
u32 fladj;
u32 irq_gadget;
+ u32 otg_irq;
+ u32 current_otg_role;
+ u32 desired_otg_role;
+ bool otg_restart_host;
u32 nr_scratch;
u32 u1u2;
u32 maximum_speed;
@@ -979,6 +1105,10 @@ struct dwc3 {
u8 test_mode_nr;
u8 lpm_nyet_threshold;
u8 hird_threshold;
+ u8 rx_thr_num_pkt_prd;
+ u8 rx_max_burst_prd;
+ u8 tx_thr_num_pkt_prd;
+ u8 tx_max_burst_prd;
const char *hsphy_interface;
@@ -1175,6 +1305,7 @@ struct dwc3_gadget_ep_cmd_params {
#define DWC3_HAS_OTG BIT(3)
/* prototypes */
+void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
@@ -1192,6 +1323,9 @@ static inline bool dwc3_is_usb31(struct dwc3 *dwc)
bool dwc3_has_imod(struct dwc3 *dwc);
+int dwc3_event_buffers_setup(struct dwc3 *dwc);
+void dwc3_event_buffers_cleanup(struct dwc3 *dwc);
+
#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
int dwc3_host_init(struct dwc3 *dwc);
void dwc3_host_exit(struct dwc3 *dwc);
@@ -1235,11 +1369,23 @@ static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
#if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
int dwc3_drd_init(struct dwc3 *dwc);
void dwc3_drd_exit(struct dwc3 *dwc);
+void dwc3_otg_init(struct dwc3 *dwc);
+void dwc3_otg_exit(struct dwc3 *dwc);
+void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus);
+void dwc3_otg_host_init(struct dwc3 *dwc);
#else
static inline int dwc3_drd_init(struct dwc3 *dwc)
{ return 0; }
static inline void dwc3_drd_exit(struct dwc3 *dwc)
{ }
+static inline void dwc3_otg_init(struct dwc3 *dwc)
+{ }
+static inline void dwc3_otg_exit(struct dwc3 *dwc)
+{ }
+static inline void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
+{ }
+static inline void dwc3_otg_host_init(struct dwc3 *dwc)
+{ }
#endif
/* power management interface */
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index 00e65530c81e..2f07be1e1f31 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -81,6 +81,11 @@ static const struct debugfs_reg32 dwc3_regs[] = {
dump_register(GHWPARAMS7),
dump_register(GDBGFIFOSPACE),
dump_register(GDBGLTSSM),
+ dump_register(GDBGBMU),
+ dump_register(GDBGLSPMUX),
+ dump_register(GDBGLSP),
+ dump_register(GDBGEPINFO0),
+ dump_register(GDBGEPINFO1),
dump_register(GPRTBIMAP_HS0),
dump_register(GPRTBIMAP_HS1),
dump_register(GPRTBIMAP_FS0),
@@ -487,8 +492,8 @@ static const struct file_operations dwc3_link_state_fops = {
};
struct dwc3_ep_file_map {
- char name[25];
- int (*show)(struct seq_file *s, void *unused);
+ const char name[25];
+ const struct file_operations *const fops;
};
static int dwc3_tx_fifo_queue_show(struct seq_file *s, void *unused)
@@ -596,7 +601,7 @@ static int dwc3_event_queue_show(struct seq_file *s, void *unused)
return 0;
}
-static int dwc3_ep_transfer_type_show(struct seq_file *s, void *unused)
+static int dwc3_transfer_type_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
@@ -632,7 +637,7 @@ out:
return 0;
}
-static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused)
+static int dwc3_trb_ring_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
@@ -670,58 +675,39 @@ out:
return 0;
}
-static struct dwc3_ep_file_map map[] = {
- { "tx_fifo_queue", dwc3_tx_fifo_queue_show, },
- { "rx_fifo_queue", dwc3_rx_fifo_queue_show, },
- { "tx_request_queue", dwc3_tx_request_queue_show, },
- { "rx_request_queue", dwc3_rx_request_queue_show, },
- { "rx_info_queue", dwc3_rx_info_queue_show, },
- { "descriptor_fetch_queue", dwc3_descriptor_fetch_queue_show, },
- { "event_queue", dwc3_event_queue_show, },
- { "transfer_type", dwc3_ep_transfer_type_show, },
- { "trb_ring", dwc3_ep_trb_ring_show, },
+DEFINE_SHOW_ATTRIBUTE(dwc3_tx_fifo_queue);
+DEFINE_SHOW_ATTRIBUTE(dwc3_rx_fifo_queue);
+DEFINE_SHOW_ATTRIBUTE(dwc3_tx_request_queue);
+DEFINE_SHOW_ATTRIBUTE(dwc3_rx_request_queue);
+DEFINE_SHOW_ATTRIBUTE(dwc3_rx_info_queue);
+DEFINE_SHOW_ATTRIBUTE(dwc3_descriptor_fetch_queue);
+DEFINE_SHOW_ATTRIBUTE(dwc3_event_queue);
+DEFINE_SHOW_ATTRIBUTE(dwc3_transfer_type);
+DEFINE_SHOW_ATTRIBUTE(dwc3_trb_ring);
+
+static const struct dwc3_ep_file_map dwc3_ep_file_map[] = {
+ { "tx_fifo_queue", &dwc3_tx_fifo_queue_fops, },
+ { "rx_fifo_queue", &dwc3_rx_fifo_queue_fops, },
+ { "tx_request_queue", &dwc3_tx_request_queue_fops, },
+ { "rx_request_queue", &dwc3_rx_request_queue_fops, },
+ { "rx_info_queue", &dwc3_rx_info_queue_fops, },
+ { "descriptor_fetch_queue", &dwc3_descriptor_fetch_queue_fops, },
+ { "event_queue", &dwc3_event_queue_fops, },
+ { "transfer_type", &dwc3_transfer_type_fops, },
+ { "trb_ring", &dwc3_trb_ring_fops, },
};
-static int dwc3_endpoint_open(struct inode *inode, struct file *file)
-{
- const char *file_name = file_dentry(file)->d_iname;
- struct dwc3_ep_file_map *f_map;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(map); i++) {
- f_map = &map[i];
-
- if (strcmp(f_map->name, file_name) == 0)
- break;
- }
-
- return single_open(file, f_map->show, inode->i_private);
-}
-
-static const struct file_operations dwc3_endpoint_fops = {
- .open = dwc3_endpoint_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void dwc3_debugfs_create_endpoint_file(struct dwc3_ep *dep,
- struct dentry *parent, int type)
-{
- struct dentry *file;
- struct dwc3_ep_file_map *ep_file = &map[type];
-
- file = debugfs_create_file(ep_file->name, S_IRUGO, parent, dep,
- &dwc3_endpoint_fops);
-}
-
static void dwc3_debugfs_create_endpoint_files(struct dwc3_ep *dep,
struct dentry *parent)
{
int i;
- for (i = 0; i < ARRAY_SIZE(map); i++)
- dwc3_debugfs_create_endpoint_file(dep, parent, i);
+ for (i = 0; i < ARRAY_SIZE(dwc3_ep_file_map); i++) {
+ const struct file_operations *fops = dwc3_ep_file_map[i].fops;
+ const char *name = dwc3_ep_file_map[i].name;
+
+ debugfs_create_file(name, S_IRUGO, parent, dep, fops);
+ }
}
static void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep,
diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
index cc8ab9a8e9d2..1d8c557e97e0 100644
--- a/drivers/usb/dwc3/drd.c
+++ b/drivers/usb/dwc3/drd.c
@@ -8,22 +8,423 @@
*/
#include <linux/extcon.h>
+#include <linux/platform_device.h>
#include "debug.h"
#include "core.h"
#include "gadget.h"
-static void dwc3_drd_update(struct dwc3 *dwc)
+static void dwc3_otg_disable_events(struct dwc3 *dwc, u32 disable_mask)
+{
+ u32 reg = dwc3_readl(dwc->regs, DWC3_OEVTEN);
+
+ reg &= ~(disable_mask);
+ dwc3_writel(dwc->regs, DWC3_OEVTEN, reg);
+}
+
+static void dwc3_otg_enable_events(struct dwc3 *dwc, u32 enable_mask)
+{
+ u32 reg = dwc3_readl(dwc->regs, DWC3_OEVTEN);
+
+ reg |= (enable_mask);
+ dwc3_writel(dwc->regs, DWC3_OEVTEN, reg);
+}
+
+static void dwc3_otg_clear_events(struct dwc3 *dwc)
+{
+ u32 reg = dwc3_readl(dwc->regs, DWC3_OEVT);
+
+ dwc3_writel(dwc->regs, DWC3_OEVTEN, reg);
+}
+
+#define DWC3_OTG_ALL_EVENTS (DWC3_OEVTEN_XHCIRUNSTPSETEN | \
+ DWC3_OEVTEN_DEVRUNSTPSETEN | DWC3_OEVTEN_HIBENTRYEN | \
+ DWC3_OEVTEN_CONIDSTSCHNGEN | DWC3_OEVTEN_HRRCONFNOTIFEN | \
+ DWC3_OEVTEN_HRRINITNOTIFEN | DWC3_OEVTEN_ADEVIDLEEN | \
+ DWC3_OEVTEN_ADEVBHOSTENDEN | DWC3_OEVTEN_ADEVHOSTEN | \
+ DWC3_OEVTEN_ADEVHNPCHNGEN | DWC3_OEVTEN_ADEVSRPDETEN | \
+ DWC3_OEVTEN_ADEVSESSENDDETEN | DWC3_OEVTEN_BDEVBHOSTENDEN | \
+ DWC3_OEVTEN_BDEVHNPCHNGEN | DWC3_OEVTEN_BDEVSESSVLDDETEN | \
+ DWC3_OEVTEN_BDEVVBUSCHNGEN)
+
+static irqreturn_t dwc3_otg_thread_irq(int irq, void *_dwc)
{
+ struct dwc3 *dwc = _dwc;
+
+ spin_lock(&dwc->lock);
+ if (dwc->otg_restart_host) {
+ dwc3_otg_host_init(dwc);
+ dwc->otg_restart_host = 0;
+ }
+
+ spin_unlock(&dwc->lock);
+
+ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dwc3_otg_irq(int irq, void *_dwc)
+{
+ u32 reg;
+ struct dwc3 *dwc = _dwc;
+ irqreturn_t ret = IRQ_NONE;
+
+ reg = dwc3_readl(dwc->regs, DWC3_OEVT);
+ if (reg) {
+ /* ignore non OTG events, we can't disable them in OEVTEN */
+ if (!(reg & DWC3_OTG_ALL_EVENTS)) {
+ dwc3_writel(dwc->regs, DWC3_OEVT, reg);
+ return IRQ_NONE;
+ }
+
+ if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST &&
+ !(reg & DWC3_OEVT_DEVICEMODE))
+ dwc->otg_restart_host = 1;
+ dwc3_writel(dwc->regs, DWC3_OEVT, reg);
+ ret = IRQ_WAKE_THREAD;
+ }
+
+ return ret;
+}
+
+static void dwc3_otgregs_init(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ /*
+ * Prevent host/device reset from resetting OTG core.
+ * If we don't do this then xhci_reset (USBCMD.HCRST) will reset
+ * the signal outputs sent to the PHY, the OTG FSM logic of the
+ * core and also the resets to the VBUS filters inside the core.
+ */
+ reg = dwc3_readl(dwc->regs, DWC3_OCFG);
+ reg |= DWC3_OCFG_SFTRSTMASK;
+ dwc3_writel(dwc->regs, DWC3_OCFG, reg);
+
+ /* Disable hibernation for simplicity */
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+ reg &= ~DWC3_GCTL_GBLHIBERNATIONEN;
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+ /*
+ * Initialize OTG registers as per
+ * Figure 11-4 OTG Driver Overall Programming Flow
+ */
+ /* OCFG.SRPCap = 0, OCFG.HNPCap = 0 */
+ reg = dwc3_readl(dwc->regs, DWC3_OCFG);
+ reg &= ~(DWC3_OCFG_SRPCAP | DWC3_OCFG_HNPCAP);
+ dwc3_writel(dwc->regs, DWC3_OCFG, reg);
+ /* OEVT = FFFF */
+ dwc3_otg_clear_events(dwc);
+ /* OEVTEN = 0 */
+ dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS);
+ /* OEVTEN.ConIDStsChngEn = 1. Instead we enable all events */
+ dwc3_otg_enable_events(dwc, DWC3_OTG_ALL_EVENTS);
+ /*
+ * OCTL.PeriMode = 1, OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0,
+ * OCTL.HNPReq = 0
+ */
+ reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+ reg |= DWC3_OCTL_PERIMODE;
+ reg &= ~(DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN |
+ DWC3_OCTL_HNPREQ);
+ dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+}
+
+static int dwc3_otg_get_irq(struct dwc3 *dwc)
+{
+ struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
+ int irq;
+
+ irq = platform_get_irq_byname(dwc3_pdev, "otg");
+ if (irq > 0)
+ goto out;
+
+ if (irq == -EPROBE_DEFER)
+ goto out;
+
+ irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3");
+ if (irq > 0)
+ goto out;
+
+ if (irq == -EPROBE_DEFER)
+ goto out;
+
+ irq = platform_get_irq(dwc3_pdev, 0);
+ if (irq > 0)
+ goto out;
+
+ if (irq != -EPROBE_DEFER)
+ dev_err(dwc->dev, "missing OTG IRQ\n");
+
+ if (!irq)
+ irq = -EINVAL;
+
+out:
+ return irq;
+}
+
+void dwc3_otg_init(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ /*
+ * As per Figure 11-4 OTG Driver Overall Programming Flow,
+ * block "Initialize GCTL for OTG operation".
+ */
+ /* GCTL.PrtCapDir=2'b11 */
+ dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
+ /* GUSB2PHYCFG0.SusPHY=0 */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+ /* Initialize OTG registers */
+ dwc3_otgregs_init(dwc);
+}
+
+void dwc3_otg_exit(struct dwc3 *dwc)
+{
+ /* disable all OTG IRQs */
+ dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS);
+ /* clear all events */
+ dwc3_otg_clear_events(dwc);
+}
+
+/* should be called before Host controller driver is started */
+void dwc3_otg_host_init(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ /* As per Figure 11-10 A-Device Flow Diagram */
+ /* OCFG.HNPCap = 0, OCFG.SRPCap = 0. Already 0 */
+
+ /*
+ * OCTL.PeriMode=0, OCTL.TermSelDLPulse = 0,
+ * OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0
+ */
+ reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+ reg &= ~(DWC3_OCTL_PERIMODE | DWC3_OCTL_TERMSELIDPULSE |
+ DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN);
+ dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+
+ /*
+ * OCFG.DisPrtPwrCutoff = 0/1
+ */
+ reg = dwc3_readl(dwc->regs, DWC3_OCFG);
+ reg &= ~DWC3_OCFG_DISPWRCUTTOFF;
+ dwc3_writel(dwc->regs, DWC3_OCFG, reg);
+
+ /*
+ * OCFG.SRPCap = 1, OCFG.HNPCap = GHWPARAMS6.HNP_CAP
+ * We don't want SRP/HNP for simple dual-role so leave
+ * these disabled.
+ */
+
+ /*
+ * OEVTEN.OTGADevHostEvntEn = 1
+ * OEVTEN.OTGADevSessEndDetEvntEn = 1
+ * We don't want HNP/role-swap so leave these disabled.
+ */
+
+ /* GUSB2PHYCFG.ULPIAutoRes = 1/0, GUSB2PHYCFG.SusPHY = 1 */
+ if (!dwc->dis_u2_susphy_quirk) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+ }
+
+ /* Set Port Power to enable VBUS: OCTL.PrtPwrCtl = 1 */
+ reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+ reg |= DWC3_OCTL_PRTPWRCTL;
+ dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+}
+
+/* should be called after Host controller driver is stopped */
+static void dwc3_otg_host_exit(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ /*
+ * Exit from A-device flow as per
+ * Figure 11-4 OTG Driver Overall Programming Flow
+ */
+
+ /*
+ * OEVTEN.OTGADevBHostEndEvntEn=0, OEVTEN.OTGADevHNPChngEvntEn=0
+ * OEVTEN.OTGADevSessEndDetEvntEn=0,
+ * OEVTEN.OTGADevHostEvntEn = 0
+ * But we don't disable any OTG events
+ */
+
+ /* OCTL.HstSetHNPEn = 0, OCTL.PrtPwrCtl=0 */
+ reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+ reg &= ~(DWC3_OCTL_HSTSETHNPEN | DWC3_OCTL_PRTPWRCTL);
+ dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+}
+
+/* should be called before the gadget controller driver is started */
+static void dwc3_otg_device_init(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ /* As per Figure 11-20 B-Device Flow Diagram */
+
+ /*
+ * OCFG.HNPCap = GHWPARAMS6.HNP_CAP, OCFG.SRPCap = 1
+ * but we keep them 0 for simple dual-role operation.
+ */
+ reg = dwc3_readl(dwc->regs, DWC3_OCFG);
+ /* OCFG.OTGSftRstMsk = 0/1 */
+ reg |= DWC3_OCFG_SFTRSTMASK;
+ dwc3_writel(dwc->regs, DWC3_OCFG, reg);
+ /*
+ * OCTL.PeriMode = 1
+ * OCTL.TermSelDLPulse = 0/1, OCTL.HNPReq = 0
+ * OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0
+ */
+ reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+ reg |= DWC3_OCTL_PERIMODE;
+ reg &= ~(DWC3_OCTL_TERMSELIDPULSE | DWC3_OCTL_HNPREQ |
+ DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN);
+ dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+ /* OEVTEN.OTGBDevSesVldDetEvntEn = 1 */
+ dwc3_otg_enable_events(dwc, DWC3_OEVTEN_BDEVSESSVLDDETEN);
+ /* GUSB2PHYCFG.ULPIAutoRes = 0, GUSB2PHYCFG0.SusPHY = 1 */
+ if (!dwc->dis_u2_susphy_quirk) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+ }
+ /* GCTL.GblHibernationEn = 0. Already 0. */
+}
+
+/* should be called after the gadget controller driver is stopped */
+static void dwc3_otg_device_exit(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ /*
+ * Exit from B-device flow as per
+ * Figure 11-4 OTG Driver Overall Programming Flow
+ */
+
+ /*
+ * OEVTEN.OTGBDevHNPChngEvntEn = 0
+ * OEVTEN.OTGBDevVBusChngEvntEn = 0
+ * OEVTEN.OTGBDevBHostEndEvntEn = 0
+ */
+ dwc3_otg_disable_events(dwc, DWC3_OEVTEN_BDEVHNPCHNGEN |
+ DWC3_OEVTEN_BDEVVBUSCHNGEN |
+ DWC3_OEVTEN_BDEVBHOSTENDEN);
+
+ /* OCTL.DevSetHNPEn = 0, OCTL.HNPReq = 0, OCTL.PeriMode=1 */
+ reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+ reg &= ~(DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HNPREQ);
+ reg |= DWC3_OCTL_PERIMODE;
+ dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+}
+
+void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
+{
+ int ret;
+ u32 reg;
int id;
+ unsigned long flags;
- id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
- if (id < 0)
- id = 0;
+ if (dwc->dr_mode != USB_DR_MODE_OTG)
+ return;
- dwc3_set_mode(dwc, id ?
- DWC3_GCTL_PRTCAP_HOST :
- DWC3_GCTL_PRTCAP_DEVICE);
+ /* don't do anything if debug user changed role to not OTG */
+ if (dwc->current_dr_role != DWC3_GCTL_PRTCAP_OTG)
+ return;
+
+ if (!ignore_idstatus) {
+ reg = dwc3_readl(dwc->regs, DWC3_OSTS);
+ id = !!(reg & DWC3_OSTS_CONIDSTS);
+
+ dwc->desired_otg_role = id ? DWC3_OTG_ROLE_DEVICE :
+ DWC3_OTG_ROLE_HOST;
+ }
+
+ if (dwc->desired_otg_role == dwc->current_otg_role)
+ return;
+
+ switch (dwc->current_otg_role) {
+ case DWC3_OTG_ROLE_HOST:
+ dwc3_host_exit(dwc);
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_otg_host_exit(dwc);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ break;
+ case DWC3_OTG_ROLE_DEVICE:
+ dwc3_gadget_exit(dwc);
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_event_buffers_cleanup(dwc);
+ dwc3_otg_device_exit(dwc);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ break;
+ default:
+ break;
+ }
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ dwc->current_otg_role = dwc->desired_otg_role;
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ switch (dwc->desired_otg_role) {
+ case DWC3_OTG_ROLE_HOST:
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_otgregs_init(dwc);
+ dwc3_otg_host_init(dwc);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ ret = dwc3_host_init(dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to initialize host\n");
+ } else {
+ if (dwc->usb2_phy)
+ otg_set_vbus(dwc->usb2_phy->otg, true);
+ if (dwc->usb2_generic_phy)
+ phy_set_mode(dwc->usb2_generic_phy,
+ PHY_MODE_USB_HOST);
+ }
+ break;
+ case DWC3_OTG_ROLE_DEVICE:
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_otgregs_init(dwc);
+ dwc3_otg_device_init(dwc);
+ dwc3_event_buffers_setup(dwc);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ if (dwc->usb2_phy)
+ otg_set_vbus(dwc->usb2_phy->otg, false);
+ if (dwc->usb2_generic_phy)
+ phy_set_mode(dwc->usb2_generic_phy,
+ PHY_MODE_USB_DEVICE);
+ ret = dwc3_gadget_init(dwc);
+ if (ret)
+ dev_err(dwc->dev, "failed to initialize peripheral\n");
+ break;
+ default:
+ break;
+ }
+}
+
+static void dwc3_drd_update(struct dwc3 *dwc)
+{
+ int id;
+
+ if (dwc->edev) {
+ id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
+ if (id < 0)
+ id = 0;
+ dwc3_set_mode(dwc, id ?
+ DWC3_GCTL_PRTCAP_HOST :
+ DWC3_GCTL_PRTCAP_DEVICE);
+ }
}
static int dwc3_drd_notifier(struct notifier_block *nb,
@@ -40,11 +441,11 @@ static int dwc3_drd_notifier(struct notifier_block *nb,
int dwc3_drd_init(struct dwc3 *dwc)
{
- int ret;
+ int ret, irq;
- if (dwc->dev->of_node) {
- if (of_property_read_bool(dwc->dev->of_node, "extcon"))
- dwc->edev = extcon_get_edev_by_phandle(dwc->dev, 0);
+ if (dwc->dev->of_node &&
+ of_property_read_bool(dwc->dev->of_node, "extcon")) {
+ dwc->edev = extcon_get_edev_by_phandle(dwc->dev, 0);
if (IS_ERR(dwc->edev))
return PTR_ERR(dwc->edev);
@@ -56,19 +457,71 @@ int dwc3_drd_init(struct dwc3 *dwc)
dev_err(dwc->dev, "couldn't register cable notifier\n");
return ret;
}
- }
- dwc3_drd_update(dwc);
+ dwc3_drd_update(dwc);
+ } else {
+ dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
+ dwc->current_dr_role = DWC3_GCTL_PRTCAP_OTG;
+
+ /* use OTG block to get ID event */
+ irq = dwc3_otg_get_irq(dwc);
+ if (irq < 0)
+ return irq;
+
+ dwc->otg_irq = irq;
+
+ /* disable all OTG IRQs */
+ dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS);
+ /* clear all events */
+ dwc3_otg_clear_events(dwc);
+
+ ret = request_threaded_irq(dwc->otg_irq, dwc3_otg_irq,
+ dwc3_otg_thread_irq,
+ IRQF_SHARED, "dwc3-otg", dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+ dwc->otg_irq, ret);
+ ret = -ENODEV;
+ return ret;
+ }
+
+ dwc3_otg_init(dwc);
+ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+ }
return 0;
}
void dwc3_drd_exit(struct dwc3 *dwc)
{
- extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
- &dwc->edev_nb);
+ unsigned long flags;
+
+ if (dwc->edev)
+ extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
+ &dwc->edev_nb);
+
+ cancel_work_sync(&dwc->drd_work);
+
+ /* debug user might have changed role, clean based on current role */
+ switch (dwc->current_dr_role) {
+ case DWC3_GCTL_PRTCAP_HOST:
+ dwc3_host_exit(dwc);
+ break;
+ case DWC3_GCTL_PRTCAP_DEVICE:
+ dwc3_gadget_exit(dwc);
+ dwc3_event_buffers_cleanup(dwc);
+ break;
+ case DWC3_GCTL_PRTCAP_OTG:
+ dwc3_otg_exit(dwc);
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc->desired_otg_role = DWC3_OTG_ROLE_IDLE;
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ dwc3_otg_update(dwc, 1);
+ break;
+ default:
+ break;
+ }
- dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
- flush_work(&dwc->drd_work);
- dwc3_gadget_exit(dwc);
+ if (!dwc->edev)
+ free_irq(dwc->otg_irq, dwc);
}
diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c
index e54c3622eb28..cb2ee96fd3e8 100644
--- a/drivers/usb/dwc3/dwc3-of-simple.c
+++ b/drivers/usb/dwc3/dwc3-of-simple.c
@@ -27,6 +27,7 @@ struct dwc3_of_simple {
struct clk **clks;
int num_clocks;
struct reset_control *resets;
+ bool pulse_resets;
};
static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
@@ -83,6 +84,7 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
int ret;
int i;
+ bool shared_resets = false;
simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL);
if (!simple)
@@ -91,16 +93,28 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, simple);
simple->dev = dev;
- simple->resets = of_reset_control_array_get_optional_exclusive(np);
+ if (of_device_is_compatible(np, "amlogic,meson-axg-dwc3") ||
+ of_device_is_compatible(np, "amlogic,meson-gxl-dwc3")) {
+ shared_resets = true;
+ simple->pulse_resets = true;
+ }
+
+ simple->resets = of_reset_control_array_get(np, shared_resets, true);
if (IS_ERR(simple->resets)) {
ret = PTR_ERR(simple->resets);
dev_err(dev, "failed to get device resets, err=%d\n", ret);
return ret;
}
- ret = reset_control_deassert(simple->resets);
- if (ret)
- goto err_resetc_put;
+ if (simple->pulse_resets) {
+ ret = reset_control_reset(simple->resets);
+ if (ret)
+ goto err_resetc_put;
+ } else {
+ ret = reset_control_deassert(simple->resets);
+ if (ret)
+ goto err_resetc_put;
+ }
ret = dwc3_of_simple_clk_init(simple, of_count_phandle_with_args(np,
"clocks", "#clock-cells"));
@@ -124,7 +138,8 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
return 0;
err_resetc_assert:
- reset_control_assert(simple->resets);
+ if (!simple->pulse_resets)
+ reset_control_assert(simple->resets);
err_resetc_put:
reset_control_put(simple->resets);
@@ -145,7 +160,9 @@ static int dwc3_of_simple_remove(struct platform_device *pdev)
}
simple->num_clocks = 0;
- reset_control_assert(simple->resets);
+ if (!simple->pulse_resets)
+ reset_control_assert(simple->resets);
+
reset_control_put(simple->resets);
pm_runtime_put_sync(dev);
@@ -196,6 +213,8 @@ static const struct of_device_id of_dwc3_simple_match[] = {
{ .compatible = "xlnx,zynqmp-dwc3" },
{ .compatible = "cavium,octeon-7130-usb-uctl" },
{ .compatible = "sprd,sc9860-dwc3" },
+ { .compatible = "amlogic,meson-axg-dwc3" },
+ { .compatible = "amlogic,meson-gxl-dwc3" },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_dwc3_simple_match);
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 3ba11136ebf0..c961a94d136b 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -222,7 +222,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,
ret = platform_device_add_resources(dwc->dwc3, res, ARRAY_SIZE(res));
if (ret) {
dev_err(dev, "couldn't add resources to dwc3 device\n");
- return ret;
+ goto err;
}
dwc->pci = pci;
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 18be31d5743a..5a991bca8ed7 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -814,7 +814,7 @@ out:
static void dwc3_ep0_complete_data(struct dwc3 *dwc,
const struct dwc3_event_depevt *event)
{
- struct dwc3_request *r = NULL;
+ struct dwc3_request *r;
struct usb_request *ur;
struct dwc3_trb *trb;
struct dwc3_ep *ep0;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 2bda4eb1e9ac..8796a5ee9bb9 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -166,18 +166,8 @@ static void dwc3_ep_inc_deq(struct dwc3_ep *dep)
dwc3_ep_inc_trb(&dep->trb_dequeue);
}
-/**
- * dwc3_gadget_giveback - call struct usb_request's ->complete callback
- * @dep: The endpoint to whom the request belongs to
- * @req: The request we're giving back
- * @status: completion code for the request
- *
- * Must be called with controller's lock held and interrupts disabled. This
- * function will unmap @req and call its ->complete() callback to notify upper
- * layers that it has completed.
- */
-void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
- int status)
+void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep,
+ struct dwc3_request *req, int status)
{
struct dwc3 *dwc = dep->dwc;
@@ -190,18 +180,35 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
if (req->trb)
usb_gadget_unmap_request_by_dev(dwc->sysdev,
- &req->request, req->direction);
+ &req->request, req->direction);
req->trb = NULL;
-
trace_dwc3_gadget_giveback(req);
+ if (dep->number > 1)
+ pm_runtime_put(dwc->dev);
+}
+
+/**
+ * dwc3_gadget_giveback - call struct usb_request's ->complete callback
+ * @dep: The endpoint to whom the request belongs to
+ * @req: The request we're giving back
+ * @status: completion code for the request
+ *
+ * Must be called with controller's lock held and interrupts disabled. This
+ * function will unmap @req and call its ->complete() callback to notify upper
+ * layers that it has completed.
+ */
+void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+ int status)
+{
+ struct dwc3 *dwc = dep->dwc;
+
+ dwc3_gadget_del_and_unmap_request(dep, req, status);
+
spin_unlock(&dwc->lock);
usb_gadget_giveback_request(&dep->endpoint, &req->request);
spin_lock(&dwc->lock);
-
- if (dep->number > 1)
- pm_runtime_put(dwc->dev);
}
/**
@@ -1227,7 +1234,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep)
if (req->trb)
memset(req->trb, 0, sizeof(struct dwc3_trb));
dep->queued_requests--;
- dwc3_gadget_giveback(dep, req, ret);
+ dwc3_gadget_del_and_unmap_request(dep, req, ret);
return ret;
}
@@ -1858,7 +1865,11 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
* bursts of data without going through any sort of endpoint throttling.
*/
reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
- reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL;
+ if (dwc3_is_usb31(dwc))
+ reg &= ~DWC31_GRXTHRCFG_PKTCNTSEL;
+ else
+ reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL;
+
dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
dwc3_gadget_setup_nump(dwc);
@@ -1950,6 +1961,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
int epnum;
+ u32 tmo_eps = 0;
spin_lock_irqsave(&dwc->lock, flags);
@@ -1960,6 +1972,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
struct dwc3_ep *dep = dwc->eps[epnum];
+ int ret;
if (!dep)
continue;
@@ -1967,9 +1980,24 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
continue;
- wait_event_lock_irq(dep->wait_end_transfer,
- !(dep->flags & DWC3_EP_END_TRANSFER_PENDING),
- dwc->lock);
+ ret = wait_event_interruptible_lock_irq_timeout(dep->wait_end_transfer,
+ !(dep->flags & DWC3_EP_END_TRANSFER_PENDING),
+ dwc->lock, msecs_to_jiffies(5));
+
+ if (ret <= 0) {
+ /* Timed out or interrupted! There's nothing much
+ * we can do so we just log here and print which
+ * endpoints timed out at the end.
+ */
+ tmo_eps |= 1 << epnum;
+ dep->flags &= DWC3_EP_END_TRANSFER_PENDING;
+ }
+ }
+
+ if (tmo_eps) {
+ dev_err(dwc->dev,
+ "end transfer timed out on endpoints 0x%x [bitmap]\n",
+ tmo_eps);
}
out:
@@ -2023,7 +2051,10 @@ static void dwc3_gadget_set_speed(struct usb_gadget *g,
reg |= DWC3_DCFG_SUPERSPEED;
break;
case USB_SPEED_SUPER_PLUS:
- reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+ if (dwc3_is_usb31(dwc))
+ reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+ else
+ reg |= DWC3_DCFG_SUPERSPEED;
break;
default:
dev_err(dwc->dev, "invalid speed (%d)\n", speed);
@@ -2101,7 +2132,10 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total)
mdwidth /= 8;
size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(num));
- size = DWC3_GTXFIFOSIZ_TXFDEF(size);
+ if (dwc3_is_usb31(dwc))
+ size = DWC31_GTXFIFOSIZ_TXFDEF(size);
+ else
+ size = DWC3_GTXFIFOSIZ_TXFDEF(size);
/* FIFO Depth is in MDWDITH bytes. Multiply */
size *= mdwidth;
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 77c7ecca816a..63a7cb87514a 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1422,11 +1422,12 @@ static int count_ext_compat(struct usb_configuration *c)
return res;
}
-static void fill_ext_compat(struct usb_configuration *c, u8 *buf)
+static int fill_ext_compat(struct usb_configuration *c, u8 *buf)
{
int i, count;
count = 16;
+ buf += 16;
for (i = 0; i < c->next_interface_id; ++i) {
struct usb_function *f;
int j;
@@ -1449,10 +1450,12 @@ static void fill_ext_compat(struct usb_configuration *c, u8 *buf)
buf += 23;
}
count += 24;
- if (count >= 4096)
- return;
+ if (count + 24 >= USB_COMP_EP0_OS_DESC_BUFSIZ)
+ return count;
}
}
+
+ return count;
}
static int count_ext_prop(struct usb_configuration *c, int interface)
@@ -1497,25 +1500,21 @@ static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf)
struct usb_os_desc *d;
struct usb_os_desc_ext_prop *ext_prop;
int j, count, n, ret;
- u8 *start = buf;
f = c->interface[interface];
+ count = 10; /* header length */
+ buf += 10;
for (j = 0; j < f->os_desc_n; ++j) {
if (interface != f->os_desc_table[j].if_id)
continue;
d = f->os_desc_table[j].os_desc;
if (d)
list_for_each_entry(ext_prop, &d->ext_prop, entry) {
- /* 4kB minus header length */
- n = buf - start;
- if (n >= 4086)
- return 0;
-
- count = ext_prop->data_len +
+ n = ext_prop->data_len +
ext_prop->name_len + 14;
- if (count > 4086 - n)
- return -EINVAL;
- usb_ext_prop_put_size(buf, count);
+ if (count + n >= USB_COMP_EP0_OS_DESC_BUFSIZ)
+ return count;
+ usb_ext_prop_put_size(buf, n);
usb_ext_prop_put_type(buf, ext_prop->type);
ret = usb_ext_prop_put_name(buf, ext_prop->name,
ext_prop->name_len);
@@ -1541,11 +1540,12 @@ static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf)
default:
return -EINVAL;
}
- buf += count;
+ buf += n;
+ count += n;
}
}
- return 0;
+ return count;
}
/*
@@ -1827,6 +1827,7 @@ unknown:
req->complete = composite_setup_complete;
buf = req->buf;
os_desc_cfg = cdev->os_desc_config;
+ w_length = min_t(u16, w_length, USB_COMP_EP0_OS_DESC_BUFSIZ);
memset(buf, 0, w_length);
buf[5] = 0x01;
switch (ctrl->bRequestType & USB_RECIP_MASK) {
@@ -1834,24 +1835,16 @@ unknown:
if (w_index != 0x4 || (w_value >> 8))
break;
buf[6] = w_index;
- if (w_length == 0x10) {
- /* Number of ext compat interfaces */
- count = count_ext_compat(os_desc_cfg);
- buf[8] = count;
- count *= 24; /* 24 B/ext compat desc */
- count += 16; /* header */
- put_unaligned_le32(count, buf);
- value = w_length;
- } else {
- /* "extended compatibility ID"s */
- count = count_ext_compat(os_desc_cfg);
- buf[8] = count;
- count *= 24; /* 24 B/ext compat desc */
- count += 16; /* header */
- put_unaligned_le32(count, buf);
- buf += 16;
- fill_ext_compat(os_desc_cfg, buf);
- value = w_length;
+ /* Number of ext compat interfaces */
+ count = count_ext_compat(os_desc_cfg);
+ buf[8] = count;
+ count *= 24; /* 24 B/ext compat desc */
+ count += 16; /* header */
+ put_unaligned_le32(count, buf);
+ value = w_length;
+ if (w_length > 0x10) {
+ value = fill_ext_compat(os_desc_cfg, buf);
+ value = min_t(u16, w_length, value);
}
break;
case USB_RECIP_INTERFACE:
@@ -1859,47 +1852,23 @@ unknown:
break;
interface = w_value & 0xFF;
buf[6] = w_index;
- if (w_length == 0x0A) {
- count = count_ext_prop(os_desc_cfg,
- interface);
- put_unaligned_le16(count, buf + 8);
- count = len_ext_prop(os_desc_cfg,
- interface);
- put_unaligned_le32(count, buf);
-
- value = w_length;
- } else {
- count = count_ext_prop(os_desc_cfg,
- interface);
- put_unaligned_le16(count, buf + 8);
- count = len_ext_prop(os_desc_cfg,
- interface);
- put_unaligned_le32(count, buf);
- buf += 10;
+ count = count_ext_prop(os_desc_cfg,
+ interface);
+ put_unaligned_le16(count, buf + 8);
+ count = len_ext_prop(os_desc_cfg,
+ interface);
+ put_unaligned_le32(count, buf);
+ value = w_length;
+ if (w_length > 0x0A) {
value = fill_ext_prop(os_desc_cfg,
interface, buf);
- if (value < 0)
- return value;
-
- value = w_length;
+ if (value >= 0)
+ value = min_t(u16, w_length, value);
}
break;
}
- if (value >= 0) {
- req->length = value;
- req->context = cdev;
- req->zero = value < w_length;
- value = composite_ep0_queue(cdev, req,
- GFP_ATOMIC);
- if (value < 0) {
- DBG(cdev, "ep_queue --> %d\n", value);
- req->status = 0;
- composite_setup_complete(gadget->ep0,
- req);
- }
- }
- return value;
+ goto check_value;
}
VDBG(cdev,
@@ -1973,6 +1942,7 @@ try_fun_setup:
goto done;
}
+check_value:
/* respond with data transfer before status phase? */
if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
req->length = value;
@@ -2156,8 +2126,8 @@ int composite_os_desc_req_prepare(struct usb_composite_dev *cdev,
goto end;
}
- /* OS feature descriptor length <= 4kB */
- cdev->os_desc_req->buf = kmalloc(4096, GFP_KERNEL);
+ cdev->os_desc_req->buf = kmalloc(USB_COMP_EP0_OS_DESC_BUFSIZ,
+ GFP_KERNEL);
if (!cdev->os_desc_req->buf) {
ret = -ENOMEM;
usb_ep_free_request(ep0, cdev->os_desc_req);
@@ -2172,6 +2142,7 @@ end:
void composite_dev_cleanup(struct usb_composite_dev *cdev)
{
struct usb_gadget_string_container *uc, *tmp;
+ struct usb_ep *ep, *tmp_ep;
list_for_each_entry_safe(uc, tmp, &cdev->gstrings, list) {
list_del(&uc->list);
@@ -2193,6 +2164,21 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)
}
cdev->next_string_id = 0;
device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
+
+ /*
+ * Some UDC backends have a dynamic EP allocation scheme.
+ *
+ * In that case, the dispose() callback is used to notify the
+ * backend that the EPs are no longer in use.
+ *
+ * Note: The UDC backend can remove the EP from the ep_list as
+ * a result, so we need to use the _safe list iterator.
+ */
+ list_for_each_entry_safe(ep, tmp_ep,
+ &cdev->gadget->ep_list, ep_list) {
+ if (ep->ops->dispose)
+ ep->ops->dispose(ep);
+ }
}
static int composite_bind(struct usb_gadget *gadget,
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index d2428a9e8900..0294e4f18873 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -758,9 +758,13 @@ static void ffs_user_copy_worker(struct work_struct *work)
bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD;
if (io_data->read && ret > 0) {
+ mm_segment_t oldfs = get_fs();
+
+ set_fs(USER_DS);
use_mm(io_data->mm);
ret = ffs_copy_to_iter(io_data->buf, ret, &io_data->data);
unuse_mm(io_data->mm);
+ set_fs(oldfs);
}
io_data->kiocb->ki_complete(io_data->kiocb, ret, ret);
@@ -3238,7 +3242,7 @@ static int ffs_func_setup(struct usb_function *f,
__ffs_event_add(ffs, FUNCTIONFS_SETUP);
spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
- return 0;
+ return USB_GADGET_DELAYED_STATUS;
}
static bool ffs_func_req_match(struct usb_function *f,
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index 4eb96b91cc40..e8f35db42394 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -404,7 +404,8 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (err) {
ERROR(midi, "%s: couldn't enqueue request: %d\n",
midi->out_ep->name, err);
- free_ep_req(midi->out_ep, req);
+ if (req->buf != NULL)
+ free_ep_req(midi->out_ep, req);
return err;
}
}
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c
index da81cf16b850..d78dbb73bde8 100644
--- a/drivers/usb/gadget/function/f_tcm.c
+++ b/drivers/usb/gadget/function/f_tcm.c
@@ -1094,7 +1094,7 @@ static int usbg_submit_command(struct f_uas *fu,
struct command_iu *cmd_iu = cmdbuf;
struct usbg_cmd *cmd;
struct usbg_tpg *tpg = fu->tpg;
- struct tcm_usbg_nexus *tv_nexus = tpg->tpg_nexus;
+ struct tcm_usbg_nexus *tv_nexus;
u32 cmd_len;
u16 scsi_tag;
diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c
index ef3d25259b0e..fd5595ac5bf7 100644
--- a/drivers/usb/gadget/legacy/mass_storage.c
+++ b/drivers/usb/gadget/legacy/mass_storage.c
@@ -225,7 +225,7 @@ static int msg_unbind(struct usb_composite_dev *cdev)
static struct usb_composite_driver msg_driver = {
.name = "g_mass_storage",
.dev = &msg_device_desc,
- .max_speed = USB_SPEED_SUPER,
+ .max_speed = USB_SPEED_SUPER_PLUS,
.needs_serial = 1,
.strings = dev_strings,
.bind = msg_bind,
diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h
index c3fbef2bb5db..09f90447fed5 100644
--- a/drivers/usb/gadget/u_f.h
+++ b/drivers/usb/gadget/u_f.h
@@ -61,7 +61,9 @@ struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len);
/* Frees a usb_request previously allocated by alloc_ep_req() */
static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req)
{
+ WARN_ON(req->buf == NULL);
kfree(req->buf);
+ req->buf = NULL;
usb_ep_free_request(ep, req);
}
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 075eaaa8a408..27c16399c7e8 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -23,7 +23,8 @@
#include <linux/usb/atmel_usba_udc.h>
#include <linux/delay.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
+#include <linux/irq.h>
+#include <linux/gpio/consumer.h>
#include "atmel_usba_udc.h"
#define USBA_VBUS_IRQFLAGS (IRQF_ONESHOT \
@@ -415,8 +416,8 @@ static inline void usba_int_enb_set(struct usba_udc *udc, u32 val)
static int vbus_is_present(struct usba_udc *udc)
{
- if (gpio_is_valid(udc->vbus_pin))
- return gpio_get_value(udc->vbus_pin) ^ udc->vbus_pin_inverted;
+ if (udc->vbus_pin)
+ return gpiod_get_value(udc->vbus_pin) ^ udc->vbus_pin_inverted;
/* No Vbus detection: Assume always present */
return 1;
@@ -1975,8 +1976,8 @@ static int atmel_usba_start(struct usb_gadget *gadget,
mutex_lock(&udc->vbus_mutex);
- if (gpio_is_valid(udc->vbus_pin))
- enable_irq(gpio_to_irq(udc->vbus_pin));
+ if (udc->vbus_pin)
+ enable_irq(gpiod_to_irq(udc->vbus_pin));
/* If Vbus is present, enable the controller and wait for reset */
udc->vbus_prev = vbus_is_present(udc);
@@ -1990,8 +1991,8 @@ static int atmel_usba_start(struct usb_gadget *gadget,
return 0;
err:
- if (gpio_is_valid(udc->vbus_pin))
- disable_irq(gpio_to_irq(udc->vbus_pin));
+ if (udc->vbus_pin)
+ disable_irq(gpiod_to_irq(udc->vbus_pin));
mutex_unlock(&udc->vbus_mutex);
@@ -2006,8 +2007,8 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
{
struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
- if (gpio_is_valid(udc->vbus_pin))
- disable_irq(gpio_to_irq(udc->vbus_pin));
+ if (udc->vbus_pin)
+ disable_irq(gpiod_to_irq(udc->vbus_pin));
if (fifo_mode == 0)
udc->configured_ep = 1;
@@ -2019,7 +2020,6 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
return 0;
}
-#ifdef CONFIG_OF
static void at91sam9rl_toggle_bias(struct usba_udc *udc, int is_on)
{
regmap_update_bits(udc->pmc, AT91_CKGR_UCKR, AT91_PMC_BIASEN,
@@ -2055,7 +2055,6 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
{
u32 val;
const char *name;
- enum of_gpio_flags flags;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
struct device_node *pp;
@@ -2075,9 +2074,9 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
udc->num_ep = 0;
- udc->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
- &flags);
- udc->vbus_pin_inverted = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+ udc->vbus_pin = devm_gpiod_get_optional(&pdev->dev, "atmel,vbus",
+ GPIOD_IN);
+ udc->vbus_pin_inverted = gpiod_is_active_low(udc->vbus_pin);
if (fifo_mode == 0) {
pp = NULL;
@@ -2204,75 +2203,10 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
err:
return ERR_PTR(ret);
}
-#else
-static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
- struct usba_udc *udc)
-{
- return ERR_PTR(-ENOSYS);
-}
-#endif
-
-static struct usba_ep * usba_udc_pdata(struct platform_device *pdev,
- struct usba_udc *udc)
-{
- struct usba_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct usba_ep *eps;
- int i;
-
- if (!pdata)
- return ERR_PTR(-ENXIO);
-
- eps = devm_kzalloc(&pdev->dev, sizeof(struct usba_ep) * pdata->num_ep,
- GFP_KERNEL);
- if (!eps)
- return ERR_PTR(-ENOMEM);
-
- udc->gadget.ep0 = &eps[0].ep;
-
- udc->vbus_pin = pdata->vbus_pin;
- udc->vbus_pin_inverted = pdata->vbus_pin_inverted;
- udc->num_ep = pdata->num_ep;
-
- INIT_LIST_HEAD(&eps[0].ep.ep_list);
-
- for (i = 0; i < pdata->num_ep; i++) {
- struct usba_ep *ep = &eps[i];
-
- ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
- ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
- ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
- ep->ep.ops = &usba_ep_ops;
- ep->ep.name = pdata->ep[i].name;
- ep->fifo_size = pdata->ep[i].fifo_size;
- usb_ep_set_maxpacket_limit(&ep->ep, ep->fifo_size);
- ep->udc = udc;
- INIT_LIST_HEAD(&ep->queue);
- ep->nr_banks = pdata->ep[i].nr_banks;
- ep->index = pdata->ep[i].index;
- ep->can_dma = pdata->ep[i].can_dma;
- ep->can_isoc = pdata->ep[i].can_isoc;
-
- if (i == 0) {
- ep->ep.caps.type_control = true;
- } else {
- ep->ep.caps.type_iso = ep->can_isoc;
- ep->ep.caps.type_bulk = true;
- ep->ep.caps.type_int = true;
- }
-
- ep->ep.caps.dir_in = true;
- ep->ep.caps.dir_out = true;
-
- if (i)
- list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
- }
-
- return eps;
-}
static int usba_udc_probe(struct platform_device *pdev)
{
- struct resource *regs, *fifo;
+ struct resource *res;
struct clk *pclk, *hclk;
struct usba_udc *udc;
int irq, ret, i;
@@ -2284,10 +2218,18 @@ static int usba_udc_probe(struct platform_device *pdev)
udc->gadget = usba_gadget_template;
INIT_LIST_HEAD(&udc->gadget.ep_list);
- regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
- fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
- if (!regs || !fifo)
- return -ENXIO;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
+ udc->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(udc->regs))
+ return PTR_ERR(udc->regs);
+ dev_info(&pdev->dev, "MMIO registers at %pR mapped at %p\n",
+ res, udc->regs);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
+ udc->fifo = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(udc->fifo))
+ return PTR_ERR(udc->fifo);
+ dev_info(&pdev->dev, "FIFO at %pR mapped at %p\n", res, udc->fifo);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -2305,23 +2247,6 @@ static int usba_udc_probe(struct platform_device *pdev)
udc->pdev = pdev;
udc->pclk = pclk;
udc->hclk = hclk;
- udc->vbus_pin = -ENODEV;
-
- ret = -ENOMEM;
- udc->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
- if (!udc->regs) {
- dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
- return ret;
- }
- dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
- (unsigned long)regs->start, udc->regs);
- udc->fifo = devm_ioremap(&pdev->dev, fifo->start, resource_size(fifo));
- if (!udc->fifo) {
- dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
- return ret;
- }
- dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
- (unsigned long)fifo->start, udc->fifo);
platform_set_drvdata(pdev, udc);
@@ -2335,10 +2260,7 @@ static int usba_udc_probe(struct platform_device *pdev)
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
clk_disable_unprepare(pclk);
- if (pdev->dev.of_node)
- udc->usba_ep = atmel_udc_of_init(pdev, udc);
- else
- udc->usba_ep = usba_udc_pdata(pdev, udc);
+ udc->usba_ep = atmel_udc_of_init(pdev, udc);
toggle_bias(udc, 0);
@@ -2354,24 +2276,18 @@ static int usba_udc_probe(struct platform_device *pdev)
}
udc->irq = irq;
- if (gpio_is_valid(udc->vbus_pin)) {
- if (!devm_gpio_request(&pdev->dev, udc->vbus_pin, "atmel_usba_udc")) {
- irq_set_status_flags(gpio_to_irq(udc->vbus_pin),
- IRQ_NOAUTOEN);
- ret = devm_request_threaded_irq(&pdev->dev,
- gpio_to_irq(udc->vbus_pin), NULL,
+ if (udc->vbus_pin) {
+ irq_set_status_flags(gpiod_to_irq(udc->vbus_pin), IRQ_NOAUTOEN);
+ ret = devm_request_threaded_irq(&pdev->dev,
+ gpiod_to_irq(udc->vbus_pin), NULL,
usba_vbus_irq_thread, USBA_VBUS_IRQFLAGS,
"atmel_usba_udc", udc);
if (ret) {
- udc->vbus_pin = -ENODEV;
+ udc->vbus_pin = NULL;
dev_warn(&udc->pdev->dev,
"failed to request vbus irq; "
"assuming always on\n");
}
- } else {
- /* gpio_request fail so use -EINVAL for gpio_is_valid */
- udc->vbus_pin = -EINVAL;
- }
}
ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
@@ -2423,9 +2339,9 @@ static int usba_udc_suspend(struct device *dev)
* Device may wake up. We stay clocked if we failed
* to request vbus irq, assuming always on.
*/
- if (gpio_is_valid(udc->vbus_pin)) {
+ if (udc->vbus_pin) {
usba_stop(udc);
- enable_irq_wake(gpio_to_irq(udc->vbus_pin));
+ enable_irq_wake(gpiod_to_irq(udc->vbus_pin));
}
out:
@@ -2441,8 +2357,8 @@ static int usba_udc_resume(struct device *dev)
if (!udc->driver)
return 0;
- if (device_may_wakeup(dev) && gpio_is_valid(udc->vbus_pin))
- disable_irq_wake(gpio_to_irq(udc->vbus_pin));
+ if (device_may_wakeup(dev) && udc->vbus_pin)
+ disable_irq_wake(gpiod_to_irq(udc->vbus_pin));
/* If Vbus is present, enable the controller and wait for reset */
mutex_lock(&udc->vbus_mutex);
@@ -2462,7 +2378,7 @@ static struct platform_driver udc_driver = {
.driver = {
.name = "atmel_usba_udc",
.pm = &usba_udc_pm_ops,
- .of_match_table = of_match_ptr(atmel_udc_dt_ids),
+ .of_match_table = atmel_udc_dt_ids,
},
};
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.h b/drivers/usb/gadget/udc/atmel_usba_udc.h
index 860a00a6fdd0..969ce8f3c3e2 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.h
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.h
@@ -7,6 +7,8 @@
#ifndef __LINUX_USB_GADGET_USBA_UDC_H__
#define __LINUX_USB_GADGET_USBA_UDC_H__
+#include <linux/gpio/consumer.h>
+
/* USB register offsets */
#define USBA_CTRL 0x0000
#define USBA_FNUM 0x0004
@@ -323,7 +325,7 @@ struct usba_udc {
struct platform_device *pdev;
const struct usba_udc_errata *errata;
int irq;
- int vbus_pin;
+ struct gpio_desc *vbus_pin;
int vbus_pin_inverted;
int num_ep;
int configured_ep;
diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c
index 465ccd1104de..3a8df8601074 100644
--- a/drivers/usb/gadget/udc/bcm63xx_udc.c
+++ b/drivers/usb/gadget/udc/bcm63xx_udc.c
@@ -2158,6 +2158,7 @@ static int bcm63xx_usbd_dbg_show(struct seq_file *s, void *p)
return 0;
}
+DEFINE_SHOW_ATTRIBUTE(bcm63xx_usbd_dbg);
/*
* bcm63xx_iudma_dbg_show - Show IUDMA status and descriptors.
@@ -2238,33 +2239,7 @@ static int bcm63xx_iudma_dbg_show(struct seq_file *s, void *p)
return 0;
}
-
-static int bcm63xx_usbd_dbg_open(struct inode *inode, struct file *file)
-{
- return single_open(file, bcm63xx_usbd_dbg_show, inode->i_private);
-}
-
-static int bcm63xx_iudma_dbg_open(struct inode *inode, struct file *file)
-{
- return single_open(file, bcm63xx_iudma_dbg_show, inode->i_private);
-}
-
-static const struct file_operations usbd_dbg_fops = {
- .owner = THIS_MODULE,
- .open = bcm63xx_usbd_dbg_open,
- .llseek = seq_lseek,
- .read = seq_read,
- .release = single_release,
-};
-
-static const struct file_operations iudma_dbg_fops = {
- .owner = THIS_MODULE,
- .open = bcm63xx_iudma_dbg_open,
- .llseek = seq_lseek,
- .read = seq_read,
- .release = single_release,
-};
-
+DEFINE_SHOW_ATTRIBUTE(bcm63xx_iudma_dbg);
/**
* bcm63xx_udc_init_debugfs - Create debugfs entries.
@@ -2282,11 +2257,11 @@ static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc)
goto err_root;
usbd = debugfs_create_file("usbd", 0400, root, udc,
- &usbd_dbg_fops);
+ &bcm63xx_usbd_dbg_fops);
if (!usbd)
goto err_usbd;
iudma = debugfs_create_file("iudma", 0400, root, udc,
- &iudma_dbg_fops);
+ &bcm63xx_iudma_dbg_fops);
if (!iudma)
goto err_iudma;
diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c
index f40d4c13cfa4..03149b9d7ea7 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_ep.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c
@@ -151,7 +151,7 @@ static int ep_bd_list_alloc(struct bdc_ep *ep)
if (!bd_table)
goto fail;
- bd_table->start_bd = dma_pool_alloc(bdc->bd_table_pool,
+ bd_table->start_bd = dma_pool_zalloc(bdc->bd_table_pool,
GFP_ATOMIC,
&dma);
if (!bd_table->start_bd) {
@@ -167,7 +167,6 @@ static int ep_bd_list_alloc(struct bdc_ep *ep)
(unsigned long long)bd_table->dma, prev_table);
ep->bd_list.bd_table_array[index] = bd_table;
- memset(bd_table->start_bd, 0, bd_p_tab * sizeof(struct bdc_bd));
if (prev_table)
chain_table(prev_table, bd_table, bd_p_tab);
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 1f8b19d9cf97..842814bc0e4f 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -238,6 +238,9 @@ EXPORT_SYMBOL_GPL(usb_ep_free_request);
* arranges to poll once per interval, and the gadget driver usually will
* have queued some data to transfer at that time.
*
+ * Note that @req's ->complete() callback must never be called from
+ * within usb_ep_queue() as that can create deadlock situations.
+ *
* Returns zero, or a negative error code. Endpoints that are not enabled
* report errors; errors will also be
* reported when the usb peripheral is disconnected.
@@ -1482,7 +1485,7 @@ ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \
- return snprintf(buf, PAGE_SIZE, "%s\n", \
+ return scnprintf(buf, PAGE_SIZE, "%s\n", \
usb_speed_string(udc->gadget->param)); \
} \
static DEVICE_ATTR_RO(name)
@@ -1497,7 +1500,7 @@ ssize_t name##_show(struct device *dev, \
struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \
struct usb_gadget *gadget = udc->gadget; \
\
- return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name); \
+ return scnprintf(buf, PAGE_SIZE, "%d\n", gadget->name); \
} \
static DEVICE_ATTR_RO(name)
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index e744d4b7bfed..baf72f95f0f1 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -2366,7 +2366,7 @@ static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb)
{
int ep = usb_pipeendpoint(urb->pipe);
- return snprintf(buf, size,
+ return scnprintf(buf, size,
"urb/%p %s ep%d%s%s len %d/%d\n",
urb,
({ char *s;
diff --git a/drivers/usb/gadget/udc/goku_udc.h b/drivers/usb/gadget/udc/goku_udc.h
index 26601bf4e7a9..70023d401079 100644
--- a/drivers/usb/gadget/udc/goku_udc.h
+++ b/drivers/usb/gadget/udc/goku_udc.h
@@ -25,7 +25,7 @@ struct goku_udc_regs {
# define INT_EP1DATASET 0x00040
# define INT_EP2DATASET 0x00080
# define INT_EP3DATASET 0x00100
-#define INT_EPnNAK(n) (0x00100 < (n)) /* 0 < n < 4 */
+#define INT_EPnNAK(n) (0x00100 << (n)) /* 0 < n < 4 */
# define INT_EP1NAK 0x00200
# define INT_EP2NAK 0x00400
# define INT_EP3NAK 0x00800
diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c
index b3fb1bbdb854..ca83c15d8ea4 100644
--- a/drivers/usb/gadget/udc/gr_udc.c
+++ b/drivers/usb/gadget/udc/gr_udc.c
@@ -179,8 +179,7 @@ static void gr_seq_ep_show(struct seq_file *seq, struct gr_ep *ep)
seq_puts(seq, "\n");
}
-
-static int gr_seq_show(struct seq_file *seq, void *v)
+static int gr_dfs_show(struct seq_file *seq, void *v)
{
struct gr_udc *dev = seq->private;
u32 control = gr_read32(&dev->regs->control);
@@ -203,19 +202,7 @@ static int gr_seq_show(struct seq_file *seq, void *v)
return 0;
}
-
-static int gr_dfs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, gr_seq_show, inode->i_private);
-}
-
-static const struct file_operations gr_dfs_fops = {
- .owner = THIS_MODULE,
- .open = gr_dfs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(gr_dfs);
static void gr_dfs_create(struct gr_udc *dev)
{
diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c
index 0e3f5faa000e..d4be53559f2e 100644
--- a/drivers/usb/gadget/udc/pxa25x_udc.c
+++ b/drivers/usb/gadget/udc/pxa25x_udc.c
@@ -1233,8 +1233,7 @@ static const struct usb_gadget_ops pxa25x_udc_ops = {
#ifdef CONFIG_USB_GADGET_DEBUG_FS
-static int
-udc_seq_show(struct seq_file *m, void *_d)
+static int udc_debug_show(struct seq_file *m, void *_d)
{
struct pxa25x_udc *dev = m->private;
unsigned long flags;
@@ -1335,25 +1334,12 @@ done:
local_irq_restore(flags);
return 0;
}
-
-static int
-udc_debugfs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, udc_seq_show, inode->i_private);
-}
-
-static const struct file_operations debug_fops = {
- .open = udc_debugfs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
+DEFINE_SHOW_ATTRIBUTE(udc_debug);
#define create_debug_files(dev) \
do { \
dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \
- S_IRUGO, NULL, dev, &debug_fops); \
+ S_IRUGO, NULL, dev, &udc_debug_fops); \
} while (0)
#define remove_debug_files(dev) debugfs_remove(dev->debugfs_udc)
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c
index fadcf2653c3d..a58242e901df 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.c
+++ b/drivers/usb/gadget/udc/pxa27x_udc.c
@@ -131,6 +131,7 @@ static int state_dbg_show(struct seq_file *s, void *p)
return 0;
}
+DEFINE_SHOW_ATTRIBUTE(state_dbg);
static int queues_dbg_show(struct seq_file *s, void *p)
{
@@ -163,6 +164,7 @@ static int queues_dbg_show(struct seq_file *s, void *p)
return 0;
}
+DEFINE_SHOW_ATTRIBUTE(queues_dbg);
static int eps_dbg_show(struct seq_file *s, void *p)
{
@@ -199,45 +201,7 @@ static int eps_dbg_show(struct seq_file *s, void *p)
return 0;
}
-
-static int eps_dbg_open(struct inode *inode, struct file *file)
-{
- return single_open(file, eps_dbg_show, inode->i_private);
-}
-
-static int queues_dbg_open(struct inode *inode, struct file *file)
-{
- return single_open(file, queues_dbg_show, inode->i_private);
-}
-
-static int state_dbg_open(struct inode *inode, struct file *file)
-{
- return single_open(file, state_dbg_show, inode->i_private);
-}
-
-static const struct file_operations state_dbg_fops = {
- .owner = THIS_MODULE,
- .open = state_dbg_open,
- .llseek = seq_lseek,
- .read = seq_read,
- .release = single_release,
-};
-
-static const struct file_operations queues_dbg_fops = {
- .owner = THIS_MODULE,
- .open = queues_dbg_open,
- .llseek = seq_lseek,
- .read = seq_read,
- .release = single_release,
-};
-
-static const struct file_operations eps_dbg_fops = {
- .owner = THIS_MODULE,
- .open = eps_dbg_open,
- .llseek = seq_lseek,
- .read = seq_read,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(eps_dbg);
static void pxa_init_debugfs(struct pxa_udc *udc)
{
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index b85822f0c874..5d958da8e1bc 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -293,19 +293,6 @@ config USB_CNS3XXX_EHCI
It is needed for high-speed (480Mbit/sec) USB 2.0 device
support.
-config USB_EHCI_ATH79
- bool "EHCI support for AR7XXX/AR9XXX SoCs (DEPRECATED)"
- depends on (SOC_AR71XX || SOC_AR724X || SOC_AR913X || SOC_AR933X)
- select USB_EHCI_ROOT_HUB_TT
- select USB_EHCI_HCD_PLATFORM
- default y
- ---help---
- This option is deprecated now and the driver was removed, use
- USB_EHCI_HCD_PLATFORM instead.
-
- Enables support for the built-in EHCI controller present
- on the Atheros AR7XXX/AR9XXX SoCs.
-
config USB_EHCI_HCD_PLATFORM
tristate "Generic EHCI driver for a platform device"
default n
@@ -490,18 +477,6 @@ config USB_OHCI_HCD_DAVINCI
controller. This driver cannot currently be a loadable
module because it lacks a proper PHY abstraction.
-config USB_OHCI_ATH79
- bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs (DEPRECATED)"
- depends on (SOC_AR71XX || SOC_AR724X)
- select USB_OHCI_HCD_PLATFORM
- default y
- help
- This option is deprecated now and the driver was removed, use
- USB_OHCI_HCD_PLATFORM instead.
-
- Enables support for the built-in OHCI controller present on the
- Atheros AR71XX/AR7240 SoCs.
-
config USB_OHCI_HCD_PPC_OF_BE
bool "OHCI support for OF platform bus (big endian)"
depends on PPC
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 4ede4ce12366..8a8cffe0b445 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -11,7 +11,7 @@ fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o
-xhci-hcd-y := xhci.o xhci-mem.o
+xhci-hcd-y := xhci.o xhci-mem.o xhci-ext-caps.o
xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
xhci-hcd-y += xhci-trace.o
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index c5094cb88cd5..0a9fd2022acf 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -155,6 +155,8 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev)
retval = -ENODEV;
goto err2;
}
+
+ hcd->skip_phy_initialization = 1;
}
#endif
return retval;
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 21307d862af6..4c6c08b675b5 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -73,10 +73,9 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
if (!qh)
goto done;
qh->hw = (struct ehci_qh_hw *)
- dma_pool_alloc(ehci->qh_pool, flags, &dma);
+ dma_pool_zalloc(ehci->qh_pool, flags, &dma);
if (!qh->hw)
goto fail;
- memset(qh->hw, 0, sizeof *qh->hw);
qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list);
INIT_LIST_HEAD (&qh->qtd_list);
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index b065a960adc2..4c306fb6b069 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -27,7 +27,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/usb.h>
@@ -44,8 +43,6 @@
struct ehci_platform_priv {
struct clk *clks[EHCI_MAX_CLKS];
struct reset_control *rsts;
- struct phy **phys;
- int num_phys;
bool reset_on_resume;
};
@@ -80,7 +77,7 @@ static int ehci_platform_power_on(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
- int clk, ret, phy_num;
+ int clk, ret;
for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
ret = clk_prepare_enable(priv->clks[clk]);
@@ -88,24 +85,8 @@ static int ehci_platform_power_on(struct platform_device *dev)
goto err_disable_clks;
}
- for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
- ret = phy_init(priv->phys[phy_num]);
- if (ret)
- goto err_exit_phy;
- ret = phy_power_on(priv->phys[phy_num]);
- if (ret) {
- phy_exit(priv->phys[phy_num]);
- goto err_exit_phy;
- }
- }
-
return 0;
-err_exit_phy:
- while (--phy_num >= 0) {
- phy_power_off(priv->phys[phy_num]);
- phy_exit(priv->phys[phy_num]);
- }
err_disable_clks:
while (--clk >= 0)
clk_disable_unprepare(priv->clks[clk]);
@@ -117,12 +98,7 @@ static void ehci_platform_power_off(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
- int clk, phy_num;
-
- for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
- phy_power_off(priv->phys[phy_num]);
- phy_exit(priv->phys[phy_num]);
- }
+ int clk;
for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
if (priv->clks[clk])
@@ -149,7 +125,7 @@ static int ehci_platform_probe(struct platform_device *dev)
struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
struct ehci_platform_priv *priv;
struct ehci_hcd *ehci;
- int err, irq, phy_num, clk = 0;
+ int err, irq, clk = 0;
if (usb_disabled())
return -ENODEV;
@@ -202,29 +178,6 @@ static int ehci_platform_probe(struct platform_device *dev)
"has-transaction-translator"))
hcd->has_tt = 1;
- priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
- "phys", "#phy-cells");
-
- if (priv->num_phys > 0) {
- priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
- sizeof(struct phy *), GFP_KERNEL);
- if (!priv->phys)
- return -ENOMEM;
- } else
- priv->num_phys = 0;
-
- for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
- priv->phys[phy_num] = devm_of_phy_get_by_index(
- &dev->dev, dev->dev.of_node, phy_num);
- if (IS_ERR(priv->phys[phy_num])) {
- err = PTR_ERR(priv->phys[phy_num]);
- goto err_put_hcd;
- } else if (!hcd->phy) {
- /* Avoiding phy_get() in usb_add_hcd() */
- hcd->phy = priv->phys[phy_num];
- }
- }
-
for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
if (IS_ERR(priv->clks[clk])) {
@@ -306,7 +259,7 @@ err_reset:
err_put_clks:
while (--clk >= 0)
clk_put(priv->clks[clk]);
-err_put_hcd:
+
if (pdata == &ehci_platform_defaults)
dev->dev.platform_data = NULL;
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index e56db44708bc..28e2a338b481 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1287,7 +1287,7 @@ itd_urb_transaction(
} else {
alloc_itd:
spin_unlock_irqrestore(&ehci->lock, flags);
- itd = dma_pool_alloc(ehci->itd_pool, mem_flags,
+ itd = dma_pool_zalloc(ehci->itd_pool, mem_flags,
&itd_dma);
spin_lock_irqsave(&ehci->lock, flags);
if (!itd) {
@@ -1297,7 +1297,6 @@ itd_urb_transaction(
}
}
- memset(itd, 0, sizeof(*itd));
itd->itd_dma = itd_dma;
itd->frame = NO_FRAME;
list_add(&itd->itd_list, &sched->td_list);
@@ -2081,7 +2080,7 @@ sitd_urb_transaction(
} else {
alloc_sitd:
spin_unlock_irqrestore(&ehci->lock, flags);
- sitd = dma_pool_alloc(ehci->sitd_pool, mem_flags,
+ sitd = dma_pool_zalloc(ehci->sitd_pool, mem_flags,
&sitd_dma);
spin_lock_irqsave(&ehci->lock, flags);
if (!sitd) {
@@ -2091,7 +2090,6 @@ sitd_urb_transaction(
}
}
- memset(sitd, 0, sizeof(*sitd));
sitd->sitd_dma = sitd_dma;
sitd->frame = NO_FRAME;
list_add(&sitd->sitd_list, &iso_sched->td_list);
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index c809f7d2f08f..a6f4389f7e88 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -461,6 +461,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
goto cleanup_clk_en;
}
hcd->usb_phy = u_phy;
+ hcd->skip_phy_initialization = 1;
tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node,
"nvidia,needs-double-reset");
diff --git a/drivers/usb/host/fhci-dbg.c b/drivers/usb/host/fhci-dbg.c
index fafa91189e45..ebf9bb219f75 100644
--- a/drivers/usb/host/fhci-dbg.c
+++ b/drivers/usb/host/fhci-dbg.c
@@ -55,6 +55,7 @@ static int fhci_dfs_regs_show(struct seq_file *s, void *v)
return 0;
}
+DEFINE_SHOW_ATTRIBUTE(fhci_dfs_regs);
static int fhci_dfs_irq_stat_show(struct seq_file *s, void *v)
{
@@ -75,30 +76,7 @@ static int fhci_dfs_irq_stat_show(struct seq_file *s, void *v)
return 0;
}
-
-static int fhci_dfs_regs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, fhci_dfs_regs_show, inode->i_private);
-}
-
-static int fhci_dfs_irq_stat_open(struct inode *inode, struct file *file)
-{
- return single_open(file, fhci_dfs_irq_stat_show, inode->i_private);
-}
-
-static const struct file_operations fhci_dfs_regs_fops = {
- .open = fhci_dfs_regs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations fhci_dfs_irq_stat_fops = {
- .open = fhci_dfs_irq_stat_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(fhci_dfs_irq_stat);
void fhci_dfs_create(struct fhci_hcd *fhci)
{
diff --git a/drivers/usb/host/imx21-dbg.c b/drivers/usb/host/imx21-dbg.c
index b964f9a51d87..a213ed6f07b5 100644
--- a/drivers/usb/host/imx21-dbg.c
+++ b/drivers/usb/host/imx21-dbg.c
@@ -245,6 +245,7 @@ static int debug_status_show(struct seq_file *s, void *v)
return 0;
}
+DEFINE_SHOW_ATTRIBUTE(debug_status);
static int debug_dmem_show(struct seq_file *s, void *v)
{
@@ -266,6 +267,7 @@ static int debug_dmem_show(struct seq_file *s, void *v)
return 0;
}
+DEFINE_SHOW_ATTRIBUTE(debug_dmem);
static int debug_etd_show(struct seq_file *s, void *v)
{
@@ -334,6 +336,7 @@ static int debug_etd_show(struct seq_file *s, void *v)
return 0;
}
+DEFINE_SHOW_ATTRIBUTE(debug_etd);
static void debug_statistics_show_one(struct seq_file *s,
const char *name, struct debug_stats *stats)
@@ -368,6 +371,7 @@ static int debug_statistics_show(struct seq_file *s, void *v)
return 0;
}
+DEFINE_SHOW_ATTRIBUTE(debug_statistics);
static void debug_isoc_show_one(struct seq_file *s,
const char *name, int index, struct debug_isoc_trace *trace)
@@ -409,66 +413,7 @@ static int debug_isoc_show(struct seq_file *s, void *v)
return 0;
}
-
-static int debug_status_open(struct inode *inode, struct file *file)
-{
- return single_open(file, debug_status_show, inode->i_private);
-}
-
-static int debug_dmem_open(struct inode *inode, struct file *file)
-{
- return single_open(file, debug_dmem_show, inode->i_private);
-}
-
-static int debug_etd_open(struct inode *inode, struct file *file)
-{
- return single_open(file, debug_etd_show, inode->i_private);
-}
-
-static int debug_statistics_open(struct inode *inode, struct file *file)
-{
- return single_open(file, debug_statistics_show, inode->i_private);
-}
-
-static int debug_isoc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, debug_isoc_show, inode->i_private);
-}
-
-static const struct file_operations debug_status_fops = {
- .open = debug_status_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations debug_dmem_fops = {
- .open = debug_dmem_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations debug_etd_fops = {
- .open = debug_etd_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations debug_statistics_fops = {
- .open = debug_statistics_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations debug_isoc_fops = {
- .open = debug_isoc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(debug_isoc);
static void create_debug_files(struct imx21 *imx21)
{
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 5f9234b9cf7b..4602ed801f0a 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1168,7 +1168,7 @@ static void dump_int(struct seq_file *s, char *label, u32 mask)
mask & HCINT_SF ? " sof" : "", mask & HCINT_SO ? " so" : "");
}
-static int isp116x_show_dbg(struct seq_file *s, void *unused)
+static int isp116x_debug_show(struct seq_file *s, void *unused)
{
struct isp116x *isp116x = s->private;
@@ -1196,18 +1196,7 @@ static int isp116x_show_dbg(struct seq_file *s, void *unused)
return 0;
}
-
-static int isp116x_open_seq(struct inode *inode, struct file *file)
-{
- return single_open(file, isp116x_show_dbg, inode->i_private);
-}
-
-static const struct file_operations isp116x_debug_fops = {
- .open = isp116x_open_seq,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(isp116x_debug);
static int create_debug_file(struct isp116x *isp116x)
{
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 0201c49bc4fc..d8d35d456456 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -230,6 +230,7 @@ static int ohci_omap_reset(struct usb_hcd *hcd)
} else {
return -EPROBE_DEFER;
}
+ hcd->skip_phy_initialization = 1;
ohci->start_hnp = start_hnp;
}
#endif
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index 1e6c954f4b3f..65a1c3fdc88c 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -21,7 +21,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
-#include <linux/phy/phy.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
@@ -38,8 +38,6 @@
struct ohci_platform_priv {
struct clk *clks[OHCI_MAX_CLKS];
struct reset_control *resets;
- struct phy **phys;
- int num_phys;
};
static const char hcd_name[] = "ohci-platform";
@@ -48,7 +46,7 @@ static int ohci_platform_power_on(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
- int clk, ret, phy_num;
+ int clk, ret;
for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) {
ret = clk_prepare_enable(priv->clks[clk]);
@@ -56,24 +54,8 @@ static int ohci_platform_power_on(struct platform_device *dev)
goto err_disable_clks;
}
- for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
- ret = phy_init(priv->phys[phy_num]);
- if (ret)
- goto err_exit_phy;
- ret = phy_power_on(priv->phys[phy_num]);
- if (ret) {
- phy_exit(priv->phys[phy_num]);
- goto err_exit_phy;
- }
- }
-
return 0;
-err_exit_phy:
- while (--phy_num >= 0) {
- phy_power_off(priv->phys[phy_num]);
- phy_exit(priv->phys[phy_num]);
- }
err_disable_clks:
while (--clk >= 0)
clk_disable_unprepare(priv->clks[clk]);
@@ -85,12 +67,7 @@ static void ohci_platform_power_off(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
- int clk, phy_num;
-
- for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
- phy_power_off(priv->phys[phy_num]);
- phy_exit(priv->phys[phy_num]);
- }
+ int clk;
for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
if (priv->clks[clk])
@@ -117,7 +94,7 @@ static int ohci_platform_probe(struct platform_device *dev)
struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
struct ohci_platform_priv *priv;
struct ohci_hcd *ohci;
- int err, irq, phy_num, clk = 0;
+ int err, irq, clk = 0;
if (usb_disabled())
return -ENODEV;
@@ -169,29 +146,6 @@ static int ohci_platform_probe(struct platform_device *dev)
of_property_read_u32(dev->dev.of_node, "num-ports",
&ohci->num_ports);
- priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
- "phys", "#phy-cells");
-
- if (priv->num_phys > 0) {
- priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
- sizeof(struct phy *), GFP_KERNEL);
- if (!priv->phys)
- return -ENOMEM;
- } else
- priv->num_phys = 0;
-
- for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
- priv->phys[phy_num] = devm_of_phy_get_by_index(
- &dev->dev, dev->dev.of_node, phy_num);
- if (IS_ERR(priv->phys[phy_num])) {
- err = PTR_ERR(priv->phys[phy_num]);
- goto err_put_hcd;
- } else if (!hcd->phy) {
- /* Avoiding phy_get() in usb_add_hcd() */
- hcd->phy = priv->phys[phy_num];
- }
- }
-
for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {
priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
if (IS_ERR(priv->clks[clk])) {
@@ -277,7 +231,7 @@ err_reset:
err_put_clks:
while (--clk >= 0)
clk_put(priv->clks[clk]);
-err_put_hcd:
+
if (pdata == &ohci_platform_defaults)
dev->dev.platform_data = NULL;
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index fa88a903fa2e..5b061e599948 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1381,7 +1381,7 @@ static void dump_irq(struct seq_file *s, char *label, u8 mask)
(mask & SL11H_INTMASK_DP) ? " dp" : "");
}
-static int sl811h_show(struct seq_file *s, void *unused)
+static int sl811h_debug_show(struct seq_file *s, void *unused)
{
struct sl811 *sl811 = s->private;
struct sl811h_ep *ep;
@@ -1491,25 +1491,14 @@ static int sl811h_show(struct seq_file *s, void *unused)
return 0;
}
-
-static int sl811h_open(struct inode *inode, struct file *file)
-{
- return single_open(file, sl811h_show, inode->i_private);
-}
-
-static const struct file_operations debug_ops = {
- .open = sl811h_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(sl811h_debug);
/* expect just one sl811 per system */
static void create_debug_file(struct sl811 *sl811)
{
sl811->debug_file = debugfs_create_file("sl811h", S_IRUGO,
usb_debug_root, sl811,
- &debug_ops);
+ &sl811h_debug_fops);
}
static void remove_debug_file(struct sl811 *sl811)
diff --git a/drivers/usb/host/whci/debug.c b/drivers/usb/host/whci/debug.c
index f154e5791bfd..8ddfe3f1f693 100644
--- a/drivers/usb/host/whci/debug.c
+++ b/drivers/usb/host/whci/debug.c
@@ -72,7 +72,7 @@ static void qset_print(struct seq_file *s, struct whc_qset *qset)
}
}
-static int di_print(struct seq_file *s, void *p)
+static int di_show(struct seq_file *s, void *p)
{
struct whc *whc = s->private;
int d;
@@ -91,8 +91,9 @@ static int di_print(struct seq_file *s, void *p)
}
return 0;
}
+DEFINE_SHOW_ATTRIBUTE(di);
-static int asl_print(struct seq_file *s, void *p)
+static int asl_show(struct seq_file *s, void *p)
{
struct whc *whc = s->private;
struct whc_qset *qset;
@@ -103,8 +104,9 @@ static int asl_print(struct seq_file *s, void *p)
return 0;
}
+DEFINE_SHOW_ATTRIBUTE(asl);
-static int pzl_print(struct seq_file *s, void *p)
+static int pzl_show(struct seq_file *s, void *p)
{
struct whc *whc = s->private;
struct whc_qset *qset;
@@ -118,45 +120,7 @@ static int pzl_print(struct seq_file *s, void *p)
}
return 0;
}
-
-static int di_open(struct inode *inode, struct file *file)
-{
- return single_open(file, di_print, inode->i_private);
-}
-
-static int asl_open(struct inode *inode, struct file *file)
-{
- return single_open(file, asl_print, inode->i_private);
-}
-
-static int pzl_open(struct inode *inode, struct file *file)
-{
- return single_open(file, pzl_print, inode->i_private);
-}
-
-static const struct file_operations di_fops = {
- .open = di_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static const struct file_operations asl_fops = {
- .open = asl_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static const struct file_operations pzl_fops = {
- .open = pzl_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
+DEFINE_SHOW_ATTRIBUTE(pzl);
void whc_dbg_init(struct whc *whc)
{
diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c
index 75f0b92694ba..48779c44c361 100644
--- a/drivers/usb/host/xhci-dbgtty.c
+++ b/drivers/usb/host/xhci-dbgtty.c
@@ -447,9 +447,10 @@ int xhci_dbc_tty_register_device(struct xhci_hcd *xhci)
xhci_dbc_tty_init_port(xhci, port);
tty_dev = tty_port_register_device(&port->port,
dbc_tty_driver, 0, NULL);
- ret = IS_ERR_OR_NULL(tty_dev);
- if (ret)
+ if (IS_ERR(tty_dev)) {
+ ret = PTR_ERR(tty_dev);
goto register_fail;
+ }
ret = kfifo_alloc(&port->write_fifo, DBC_WRITE_BUF_SIZE, GFP_KERNEL);
if (ret)
diff --git a/drivers/usb/host/xhci-ext-caps.c b/drivers/usb/host/xhci-ext-caps.c
new file mode 100644
index 000000000000..399113f9fc5c
--- /dev/null
+++ b/drivers/usb/host/xhci-ext-caps.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * XHCI extended capability handling
+ *
+ * Copyright (c) 2017 Hans de Goede <hdegoede@redhat.com>
+ */
+
+#include <linux/platform_device.h>
+#include "xhci.h"
+
+#define USB_SW_DRV_NAME "intel_xhci_usb_sw"
+#define USB_SW_RESOURCE_SIZE 0x400
+
+static void xhci_intel_unregister_pdev(void *arg)
+{
+ platform_device_unregister(arg);
+}
+
+static int xhci_create_intel_xhci_sw_pdev(struct xhci_hcd *xhci, u32 cap_offset)
+{
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+ struct device *dev = hcd->self.controller;
+ struct platform_device *pdev;
+ struct resource res = { 0, };
+ int ret;
+
+ pdev = platform_device_alloc(USB_SW_DRV_NAME, PLATFORM_DEVID_NONE);
+ if (!pdev) {
+ xhci_err(xhci, "couldn't allocate %s platform device\n",
+ USB_SW_DRV_NAME);
+ return -ENOMEM;
+ }
+
+ res.start = hcd->rsrc_start + cap_offset;
+ res.end = res.start + USB_SW_RESOURCE_SIZE - 1;
+ res.name = USB_SW_DRV_NAME;
+ res.flags = IORESOURCE_MEM;
+
+ ret = platform_device_add_resources(pdev, &res, 1);
+ if (ret) {
+ dev_err(dev, "couldn't add resources to intel_xhci_usb_sw pdev\n");
+ platform_device_put(pdev);
+ return ret;
+ }
+
+ pdev->dev.parent = dev;
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ dev_err(dev, "couldn't register intel_xhci_usb_sw pdev\n");
+ platform_device_put(pdev);
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(dev, xhci_intel_unregister_pdev, pdev);
+ if (ret) {
+ dev_err(dev, "couldn't add unregister action for intel_xhci_usb_sw pdev\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int xhci_ext_cap_init(struct xhci_hcd *xhci)
+{
+ void __iomem *base = &xhci->cap_regs->hc_capbase;
+ u32 offset, val;
+ int ret;
+
+ offset = xhci_find_next_ext_cap(base, 0, 0);
+
+ while (offset) {
+ val = readl(base + offset);
+
+ switch (XHCI_EXT_CAPS_ID(val)) {
+ case XHCI_EXT_CAPS_VENDOR_INTEL:
+ if (xhci->quirks & XHCI_INTEL_USB_ROLE_SW) {
+ ret = xhci_create_intel_xhci_sw_pdev(xhci,
+ offset);
+ if (ret)
+ return ret;
+ }
+ break;
+ }
+ offset = xhci_find_next_ext_cap(base, offset, 0);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xhci_ext_cap_init);
diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
index bf7316e130d3..268328c20681 100644
--- a/drivers/usb/host/xhci-ext-caps.h
+++ b/drivers/usb/host/xhci-ext-caps.h
@@ -39,6 +39,8 @@
#define XHCI_EXT_CAPS_ROUTE 5
/* IDs 6-9 reserved */
#define XHCI_EXT_CAPS_DEBUG 10
+/* Vendor caps */
+#define XHCI_EXT_CAPS_VENDOR_INTEL 192
/* USB Legacy Support Capability - section 7.1.1 */
#define XHCI_HC_BIOS_OWNED (1 << 16)
#define XHCI_HC_OS_OWNED (1 << 24)
@@ -84,7 +86,8 @@
* @base PCI MMIO registers base address.
* @start address at which to start looking, (0 or HCC_PARAMS to start at
* beginning of list)
- * @id Extended capability ID to search for.
+ * @id Extended capability ID to search for, or 0 for the next
+ * capability
*
* Returns the offset of the next matching extended capability structure.
* Some capabilities can occur several times, e.g., the XHCI_EXT_CAPS_PROTOCOL,
@@ -110,7 +113,7 @@ static inline int xhci_find_next_ext_cap(void __iomem *base, u32 start, int id)
val = readl(base + offset);
if (val == ~0)
return 0;
- if (XHCI_EXT_CAPS_ID(val) == id && offset != start)
+ if (offset != start && (id == 0 || XHCI_EXT_CAPS_ID(val) == id))
return offset;
next = XHCI_EXT_CAPS_NEXT(val);
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 332420d10be9..e5ace8995b3b 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -913,6 +913,8 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
if (dev->out_ctx)
xhci_free_container_ctx(xhci, dev->out_ctx);
+ if (dev->udev && dev->udev->slot_id)
+ dev->udev->slot_id = 0;
kfree(xhci->devs[slot_id]);
xhci->devs[slot_id] = NULL;
}
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index b0ab4d5e2751..7334da9e9779 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -14,7 +14,6 @@
#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/pm_runtime.h>
#include <linux/regmap.h>
@@ -352,62 +351,6 @@ static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = {
static struct hc_driver __read_mostly xhci_mtk_hc_driver;
-static int xhci_mtk_phy_init(struct xhci_hcd_mtk *mtk)
-{
- int i;
- int ret;
-
- for (i = 0; i < mtk->num_phys; i++) {
- ret = phy_init(mtk->phys[i]);
- if (ret)
- goto exit_phy;
- }
- return 0;
-
-exit_phy:
- for (; i > 0; i--)
- phy_exit(mtk->phys[i - 1]);
-
- return ret;
-}
-
-static int xhci_mtk_phy_exit(struct xhci_hcd_mtk *mtk)
-{
- int i;
-
- for (i = 0; i < mtk->num_phys; i++)
- phy_exit(mtk->phys[i]);
-
- return 0;
-}
-
-static int xhci_mtk_phy_power_on(struct xhci_hcd_mtk *mtk)
-{
- int i;
- int ret;
-
- for (i = 0; i < mtk->num_phys; i++) {
- ret = phy_power_on(mtk->phys[i]);
- if (ret)
- goto power_off_phy;
- }
- return 0;
-
-power_off_phy:
- for (; i > 0; i--)
- phy_power_off(mtk->phys[i - 1]);
-
- return ret;
-}
-
-static void xhci_mtk_phy_power_off(struct xhci_hcd_mtk *mtk)
-{
- unsigned int i;
-
- for (i = 0; i < mtk->num_phys; i++)
- phy_power_off(mtk->phys[i]);
-}
-
static int xhci_mtk_ldos_enable(struct xhci_hcd_mtk *mtk)
{
int ret;
@@ -488,8 +431,6 @@ static int xhci_mtk_probe(struct platform_device *pdev)
struct xhci_hcd *xhci;
struct resource *res;
struct usb_hcd *hcd;
- struct phy *phy;
- int phy_num;
int ret = -ENODEV;
int irq;
@@ -529,16 +470,6 @@ static int xhci_mtk_probe(struct platform_device *pdev)
return ret;
}
- mtk->num_phys = of_count_phandle_with_args(node,
- "phys", "#phy-cells");
- if (mtk->num_phys > 0) {
- mtk->phys = devm_kcalloc(dev, mtk->num_phys,
- sizeof(*mtk->phys), GFP_KERNEL);
- if (!mtk->phys)
- return -ENOMEM;
- } else {
- mtk->num_phys = 0;
- }
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
device_enable_async_suspend(dev);
@@ -596,23 +527,6 @@ static int xhci_mtk_probe(struct platform_device *pdev)
mtk->has_ippc = false;
}
- for (phy_num = 0; phy_num < mtk->num_phys; phy_num++) {
- phy = devm_of_phy_get_by_index(dev, node, phy_num);
- if (IS_ERR(phy)) {
- ret = PTR_ERR(phy);
- goto put_usb2_hcd;
- }
- mtk->phys[phy_num] = phy;
- }
-
- ret = xhci_mtk_phy_init(mtk);
- if (ret)
- goto put_usb2_hcd;
-
- ret = xhci_mtk_phy_power_on(mtk);
- if (ret)
- goto exit_phys;
-
device_init_wakeup(dev, true);
xhci = hcd_to_xhci(hcd);
@@ -630,7 +544,7 @@ static int xhci_mtk_probe(struct platform_device *pdev)
dev_name(dev), hcd);
if (!xhci->shared_hcd) {
ret = -ENOMEM;
- goto power_off_phys;
+ goto disable_device_wakeup;
}
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
@@ -653,13 +567,9 @@ put_usb3_hcd:
xhci_mtk_sch_exit(mtk);
usb_put_hcd(xhci->shared_hcd);
-power_off_phys:
- xhci_mtk_phy_power_off(mtk);
+disable_device_wakeup:
device_init_wakeup(dev, false);
-exit_phys:
- xhci_mtk_phy_exit(mtk);
-
put_usb2_hcd:
usb_put_hcd(hcd);
@@ -682,8 +592,6 @@ static int xhci_mtk_remove(struct platform_device *dev)
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
usb_remove_hcd(xhci->shared_hcd);
- xhci_mtk_phy_power_off(mtk);
- xhci_mtk_phy_exit(mtk);
device_init_wakeup(&dev->dev, false);
usb_remove_hcd(hcd);
@@ -718,7 +626,6 @@ static int __maybe_unused xhci_mtk_suspend(struct device *dev)
del_timer_sync(&xhci->shared_hcd->rh_timer);
xhci_mtk_host_disable(mtk);
- xhci_mtk_phy_power_off(mtk);
xhci_mtk_clks_disable(mtk);
usb_wakeup_set(mtk, true);
return 0;
@@ -732,7 +639,6 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev)
usb_wakeup_set(mtk, false);
xhci_mtk_clks_enable(mtk);
- xhci_mtk_phy_power_on(mtk);
xhci_mtk_host_enable(mtk);
xhci_dbg(xhci, "%s: restart port polling\n", __func__);
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index d9f831b67e57..f17b7eab66cf 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -178,6 +178,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
xhci->quirks |= XHCI_SSIC_PORT_UNUSED;
+ xhci->quirks |= XHCI_INTEL_USB_ROLE_SW;
}
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
(pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
@@ -311,6 +312,10 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
goto dealloc_usb2_hcd;
}
+ retval = xhci_ext_cap_init(xhci);
+ if (retval)
+ goto put_usb3_hcd;
+
retval = usb_add_hcd(xhci->shared_hcd, dev->irq,
IRQF_SHARED);
if (retval)
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 6652e2d5bd2e..df327dcc2bac 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -284,6 +284,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
ret = usb_phy_init(hcd->usb_phy);
if (ret)
goto put_usb3_hcd;
+ hcd->skip_phy_initialization = 1;
}
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index daa94c3aed80..91a1a824673d 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1436,7 +1436,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
case TRB_STOP_RING:
WARN_ON(slot_id != TRB_TO_SLOT_ID(
le32_to_cpu(cmd_trb->generic.field[3])));
- xhci_handle_cmd_stop_ep(xhci, slot_id, cmd_trb, event);
+ if (!cmd->completion)
+ xhci_handle_cmd_stop_ep(xhci, slot_id, cmd_trb, event);
break;
case TRB_SET_DEQ:
WARN_ON(slot_id != TRB_TO_SLOT_ID(
@@ -1815,8 +1816,7 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci,
static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
- unsigned int stream_id,
- struct xhci_td *td, union xhci_trb *ep_trb,
+ unsigned int stream_id, struct xhci_td *td,
enum xhci_ep_reset_type reset_type)
{
struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
@@ -1829,9 +1829,10 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
xhci_queue_reset_ep(xhci, command, slot_id, ep_index, reset_type);
- if (reset_type == EP_HARD_RESET)
+ if (reset_type == EP_HARD_RESET) {
+ ep->ep_state |= EP_HARD_CLEAR_TOGGLE;
xhci_cleanup_stalled_ring(xhci, ep_index, stream_id, td);
-
+ }
xhci_ring_cmd_db(xhci);
}
@@ -1922,7 +1923,7 @@ static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td,
}
static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
- union xhci_trb *ep_trb, struct xhci_transfer_event *event,
+ struct xhci_transfer_event *event,
struct xhci_virt_ep *ep, int *status)
{
struct xhci_virt_device *xdev;
@@ -1957,8 +1958,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
* The class driver clears the device side halt later.
*/
xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index,
- ep_ring->stream_id, td, ep_trb,
- EP_HARD_RESET);
+ ep_ring->stream_id, td, EP_HARD_RESET);
} else {
/* Update ring dequeue pointer */
while (ep_ring->dequeue != td->last_trb)
@@ -2083,7 +2083,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
td->urb->actual_length = requested;
finish_td:
- return finish_td(xhci, td, ep_trb, event, ep, status);
+ return finish_td(xhci, td, event, ep, status);
}
/*
@@ -2170,7 +2170,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
td->urb->actual_length += frame->actual_length;
- return finish_td(xhci, td, ep_trb, event, ep, status);
+ return finish_td(xhci, td, event, ep, status);
}
static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
@@ -2260,7 +2260,7 @@ finish_td:
remaining);
td->urb->actual_length = 0;
}
- return finish_td(xhci, td, ep_trb, event, ep, status);
+ return finish_td(xhci, td, event, ep, status);
}
/*
@@ -2318,7 +2318,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
case COMP_INVALID_STREAM_TYPE_ERROR:
case COMP_INVALID_STREAM_ID_ERROR:
xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, 0,
- NULL, NULL, EP_SOFT_RESET);
+ NULL, EP_SOFT_RESET);
goto cleanup;
case COMP_RING_UNDERRUN:
case COMP_RING_OVERRUN:
@@ -2584,8 +2584,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
xhci_cleanup_halted_endpoint(xhci, slot_id,
ep_index,
ep_ring->stream_id,
- td, ep_trb,
- EP_HARD_RESET);
+ td, EP_HARD_RESET);
goto cleanup;
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 5d37700ae4b0..9b27798ecce5 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1290,7 +1290,8 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
unsigned long flags;
int ret = 0;
- unsigned int slot_id, ep_index, ep_state;
+ unsigned int slot_id, ep_index;
+ unsigned int *ep_state;
struct urb_priv *urb_priv;
int num_tds;
@@ -1300,6 +1301,7 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
slot_id = urb->dev->slot_id;
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
+ ep_state = &xhci->devs[slot_id]->eps[ep_index].ep_state;
if (!HCD_HW_ACCESSIBLE(hcd)) {
if (!in_interrupt())
@@ -1351,6 +1353,17 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
ret = -ESHUTDOWN;
goto free_priv;
}
+ if (*ep_state & (EP_GETTING_STREAMS | EP_GETTING_NO_STREAMS)) {
+ xhci_warn(xhci, "WARN: Can't enqueue URB, ep in streams transition state %x\n",
+ *ep_state);
+ ret = -EINVAL;
+ goto free_priv;
+ }
+ if (*ep_state & EP_SOFT_CLEAR_TOGGLE) {
+ xhci_warn(xhci, "Can't enqueue URB while manually clearing toggle\n");
+ ret = -EINVAL;
+ goto free_priv;
+ }
switch (usb_endpoint_type(&urb->ep->desc)) {
@@ -1359,23 +1372,13 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
slot_id, ep_index);
break;
case USB_ENDPOINT_XFER_BULK:
- ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state;
- if (ep_state & (EP_GETTING_STREAMS | EP_GETTING_NO_STREAMS)) {
- xhci_warn(xhci, "WARN: Can't enqueue URB, ep in streams transition state %x\n",
- ep_state);
- ret = -EINVAL;
- break;
- }
ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
break;
-
-
case USB_ENDPOINT_XFER_INT:
ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
break;
-
case USB_ENDPOINT_XFER_ISOC:
ret = xhci_queue_isoc_tx_prepare(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
@@ -2874,33 +2877,103 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index,
}
}
-/* Called when clearing halted device. The core should have sent the control
- * message to clear the device halt condition. The host side of the halt should
- * already be cleared with a reset endpoint command issued when the STALL tx
- * event was received.
+/*
+ * Called after usb core issues a clear halt control message.
+ * The host side of the halt should already be cleared by a reset endpoint
+ * command issued when the STALL event was received.
*
- * Context: in_interrupt
+ * The reset endpoint command may only be issued to endpoints in the halted
+ * state. For software that wishes to reset the data toggle or sequence number
+ * of an endpoint that isn't in the halted state this function will issue a
+ * configure endpoint command with the Drop and Add bits set for the target
+ * endpoint. Refer to the additional note in xhci spcification section 4.6.8.
*/
static void xhci_endpoint_reset(struct usb_hcd *hcd,
- struct usb_host_endpoint *ep)
+ struct usb_host_endpoint *host_ep)
{
struct xhci_hcd *xhci;
+ struct usb_device *udev;
+ struct xhci_virt_device *vdev;
+ struct xhci_virt_ep *ep;
+ struct xhci_input_control_ctx *ctrl_ctx;
+ struct xhci_command *stop_cmd, *cfg_cmd;
+ unsigned int ep_index;
+ unsigned long flags;
+ u32 ep_flag;
xhci = hcd_to_xhci(hcd);
+ if (!host_ep->hcpriv)
+ return;
+ udev = (struct usb_device *) host_ep->hcpriv;
+ vdev = xhci->devs[udev->slot_id];
+ ep_index = xhci_get_endpoint_index(&host_ep->desc);
+ ep = &vdev->eps[ep_index];
+
+ /* Bail out if toggle is already being cleared by a endpoint reset */
+ if (ep->ep_state & EP_HARD_CLEAR_TOGGLE) {
+ ep->ep_state &= ~EP_HARD_CLEAR_TOGGLE;
+ return;
+ }
+ /* Only interrupt and bulk ep's use data toggle, USB2 spec 5.5.4-> */
+ if (usb_endpoint_xfer_control(&host_ep->desc) ||
+ usb_endpoint_xfer_isoc(&host_ep->desc))
+ return;
+
+ ep_flag = xhci_get_endpoint_flag(&host_ep->desc);
+
+ if (ep_flag == SLOT_FLAG || ep_flag == EP0_FLAG)
+ return;
+
+ stop_cmd = xhci_alloc_command(xhci, true, GFP_NOWAIT);
+ if (!stop_cmd)
+ return;
+
+ cfg_cmd = xhci_alloc_command_with_ctx(xhci, true, GFP_NOWAIT);
+ if (!cfg_cmd)
+ goto cleanup;
+
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ /* block queuing new trbs and ringing ep doorbell */
+ ep->ep_state |= EP_SOFT_CLEAR_TOGGLE;
/*
- * We might need to implement the config ep cmd in xhci 4.8.1 note:
- * The Reset Endpoint Command may only be issued to endpoints in the
- * Halted state. If software wishes reset the Data Toggle or Sequence
- * Number of an endpoint that isn't in the Halted state, then software
- * may issue a Configure Endpoint Command with the Drop and Add bits set
- * for the target endpoint. that is in the Stopped state.
+ * Make sure endpoint ring is empty before resetting the toggle/seq.
+ * Driver is required to synchronously cancel all transfer request.
+ * Stop the endpoint to force xHC to update the output context
*/
- /* For now just print debug to follow the situation */
- xhci_dbg(xhci, "Endpoint 0x%x ep reset callback called\n",
- ep->desc.bEndpointAddress);
+ if (!list_empty(&ep->ring->td_list)) {
+ dev_err(&udev->dev, "EP not empty, refuse reset\n");
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ goto cleanup;
+ }
+ xhci_queue_stop_endpoint(xhci, stop_cmd, udev->slot_id, ep_index, 0);
+ xhci_ring_cmd_db(xhci);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
+ wait_for_completion(stop_cmd->completion);
+
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ /* config ep command clears toggle if add and drop ep flags are set */
+ ctrl_ctx = xhci_get_input_control_ctx(cfg_cmd->in_ctx);
+ xhci_setup_input_ctx_for_config_ep(xhci, cfg_cmd->in_ctx, vdev->out_ctx,
+ ctrl_ctx, ep_flag, ep_flag);
+ xhci_endpoint_copy(xhci, cfg_cmd->in_ctx, vdev->out_ctx, ep_index);
+
+ xhci_queue_configure_endpoint(xhci, cfg_cmd, cfg_cmd->in_ctx->dma,
+ udev->slot_id, false);
+ xhci_ring_cmd_db(xhci);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
+ wait_for_completion(cfg_cmd->completion);
+
+ ep->ep_state &= ~EP_SOFT_CLEAR_TOGGLE;
+ xhci_free_command(xhci, cfg_cmd);
+cleanup:
+ xhci_free_command(xhci, stop_cmd);
}
static int xhci_check_streams_endpoint(struct xhci_hcd *xhci,
@@ -4768,6 +4841,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
* quirks
*/
struct device *dev = hcd->self.sysdev;
+ unsigned int minor_rev;
int retval;
/* Accept arbitrarily long scatter-gather lists */
@@ -4795,12 +4869,19 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
*/
hcd->has_tt = 1;
} else {
- /* Some 3.1 hosts return sbrn 0x30, can't rely on sbrn alone */
- if (xhci->sbrn == 0x31 || xhci->usb3_rhub.min_rev >= 1) {
- xhci_info(xhci, "Host supports USB 3.1 Enhanced SuperSpeed\n");
+ /*
+ * Some 3.1 hosts return sbrn 0x30, use xhci supported protocol
+ * minor revision instead of sbrn
+ */
+ minor_rev = xhci->usb3_rhub.min_rev;
+ if (minor_rev) {
hcd->speed = HCD_USB31;
hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
}
+ xhci_info(xhci, "Host supports USB 3.%x %s SuperSpeed\n",
+ minor_rev,
+ minor_rev ? "Enhanced" : "");
+
/* 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 866e141d4972..05c909b04f14 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -922,6 +922,8 @@ struct xhci_virt_ep {
#define EP_HAS_STREAMS (1 << 4)
/* Transitioning the endpoint to not using streams, don't enqueue URBs */
#define EP_GETTING_NO_STREAMS (1 << 5)
+#define EP_HARD_CLEAR_TOGGLE (1 << 6)
+#define EP_SOFT_CLEAR_TOGGLE (1 << 7)
/* ---- Related to URB cancellation ---- */
struct list_head cancelled_td_list;
/* Watchdog timer for stop endpoint command to cancel URBs */
@@ -1827,6 +1829,7 @@ struct xhci_hcd {
#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28)
#define XHCI_HW_LPM_DISABLE (1 << 29)
#define XHCI_SUSPEND_DELAY (1 << 30)
+#define XHCI_INTEL_USB_ROLE_SW (1 << 31)
unsigned int num_active_eps;
unsigned int limit_active_eps;
@@ -2022,6 +2025,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
void xhci_init_driver(struct hc_driver *drv,
const struct xhci_driver_overrides *over);
int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id);
+int xhci_ext_cap_init(struct xhci_hcd *xhci);
int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup);
int xhci_resume(struct xhci_hcd *xhci, bool hibernated);
diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c
index bac4ef5d9512..1714b2258b54 100644
--- a/drivers/usb/isp1760/isp1760-udc.c
+++ b/drivers/usb/isp1760/isp1760-udc.c
@@ -1441,7 +1441,6 @@ int isp1760_udc_register(struct isp1760_device *isp, int irq,
unsigned long irqflags)
{
struct isp1760_udc *udc = &isp->udc;
- const char *devname;
int ret;
udc->irq = -1;
@@ -1455,13 +1454,10 @@ int isp1760_udc_register(struct isp1760_device *isp, int irq,
if (ret < 0)
return ret;
- devname = dev_name(isp->dev);
- udc->irqname = kmalloc(strlen(devname) + 7, GFP_KERNEL);
+ udc->irqname = kasprintf(GFP_KERNEL, "%s (udc)", dev_name(isp->dev));
if (!udc->irqname)
return -ENOMEM;
- sprintf(udc->irqname, "%s (udc)", devname);
-
ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | irqflags,
udc->irqname, udc);
if (ret < 0)
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index 4b8712733fc7..b3160afe0458 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -54,7 +54,7 @@ MODULE_DEVICE_TABLE(usb, device_table);
/* we can have up to this number of device plugged in at once */
#define MAX_DEVICES 16
-#define COMMAND_TIMEOUT (2*HZ) /* 60 second timeout for a command */
+#define COMMAND_TIMEOUT (2*HZ)
/*
* The locking scheme is a vanilla 3-lock:
@@ -132,6 +132,8 @@ static void adu_abort_transfers(struct adu_device *dev)
spin_lock_irqsave(&dev->buflock, flags);
if (!dev->out_urb_finished) {
spin_unlock_irqrestore(&dev->buflock, flags);
+ wait_event_timeout(dev->write_wait, dev->out_urb_finished,
+ COMMAND_TIMEOUT);
usb_kill_urb(dev->interrupt_out_urb);
} else
spin_unlock_irqrestore(&dev->buflock, flags);
diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c
index 716cb515523e..cf5828ce927a 100644
--- a/drivers/usb/misc/chaoskey.c
+++ b/drivers/usb/misc/chaoskey.c
@@ -168,14 +168,10 @@ 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);
+ dev->name = kasprintf(GFP_KERNEL, "%s-%s", udev->product,
+ udev->serial);
if (dev->name == NULL)
goto out;
-
- strcpy(dev->name, udev->product);
- strcat(dev->name, "-");
- strcat(dev->name, udev->serial);
}
dev->interface = interface;
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 73f7bde78e11..a0d6e0af957c 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -1217,7 +1217,7 @@ font_op_error:
/* Interface routine */
static int
sisusbcon_font_set(struct vc_data *c, struct console_font *font,
- unsigned flags)
+ unsigned int flags)
{
struct sisusb_usb_data *sisusb;
unsigned charcount = font->charcount;
@@ -1338,29 +1338,65 @@ static void sisusbdummycon_init(struct vc_data *vc, int init)
vc_resize(vc, 80, 25);
}
-static int sisusbdummycon_dummy(void)
+static void sisusbdummycon_deinit(struct vc_data *vc) { }
+static void sisusbdummycon_clear(struct vc_data *vc, int sy, int sx,
+ int height, int width) { }
+static void sisusbdummycon_putc(struct vc_data *vc, int c, int ypos,
+ int xpos) { }
+static void sisusbdummycon_putcs(struct vc_data *vc, const unsigned short *s,
+ int count, int ypos, int xpos) { }
+static void sisusbdummycon_cursor(struct vc_data *vc, int mode) { }
+
+static bool sisusbdummycon_scroll(struct vc_data *vc, unsigned int top,
+ unsigned int bottom, enum con_scroll dir,
+ unsigned int lines)
{
- return 0;
+ return false;
}
-#define SISUSBCONDUMMY (void *)sisusbdummycon_dummy
+static int sisusbdummycon_switch(struct vc_data *vc)
+{
+ return 0;
+}
+
+static int sisusbdummycon_blank(struct vc_data *vc, int blank, int mode_switch)
+{
+ return 0;
+}
+
+static int sisusbdummycon_font_set(struct vc_data *vc,
+ struct console_font *font,
+ unsigned int flags)
+{
+ return 0;
+}
+
+static int sisusbdummycon_font_default(struct vc_data *vc,
+ struct console_font *font, char *name)
+{
+ return 0;
+}
+
+static int sisusbdummycon_font_copy(struct vc_data *vc, int con)
+{
+ return 0;
+}
static const struct consw sisusb_dummy_con = {
.owner = THIS_MODULE,
.con_startup = sisusbdummycon_startup,
.con_init = sisusbdummycon_init,
- .con_deinit = SISUSBCONDUMMY,
- .con_clear = SISUSBCONDUMMY,
- .con_putc = SISUSBCONDUMMY,
- .con_putcs = SISUSBCONDUMMY,
- .con_cursor = SISUSBCONDUMMY,
- .con_scroll = SISUSBCONDUMMY,
- .con_switch = SISUSBCONDUMMY,
- .con_blank = SISUSBCONDUMMY,
- .con_font_set = SISUSBCONDUMMY,
- .con_font_get = SISUSBCONDUMMY,
- .con_font_default = SISUSBCONDUMMY,
- .con_font_copy = SISUSBCONDUMMY,
+ .con_deinit = sisusbdummycon_deinit,
+ .con_clear = sisusbdummycon_clear,
+ .con_putc = sisusbdummycon_putc,
+ .con_putcs = sisusbdummycon_putcs,
+ .con_cursor = sisusbdummycon_cursor,
+ .con_scroll = sisusbdummycon_scroll,
+ .con_switch = sisusbdummycon_switch,
+ .con_blank = sisusbdummycon_blank,
+ .con_font_set = sisusbdummycon_font_set,
+ .con_font_default = sisusbdummycon_font_default,
+ .con_font_copy = sisusbdummycon_font_copy,
};
int
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 90028ef541e3..9e1142b8b91b 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -2028,11 +2028,14 @@ test_queue(struct usbtest_dev *dev, struct usbtest_param_32 *param,
unsigned i;
unsigned long packets = 0;
int status = 0;
- struct urb *urbs[param->sglen];
+ struct urb *urbs[MAX_SGLEN];
if (!param->sglen || param->iterations > UINT_MAX / param->sglen)
return -EINVAL;
+ if (param->sglen > MAX_SGLEN)
+ return -EINVAL;
+
memset(&context, 0, sizeof(context));
context.count = param->iterations * param->sglen;
context.dev = dev;
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 263c97fec708..de9a502491c2 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -769,10 +769,15 @@ static void uss720_disconnect(struct usb_interface *intf)
/* table of cables that work through this driver */
static const struct usb_device_id uss720_table[] = {
{ USB_DEVICE(0x047e, 0x1001) },
+ { USB_DEVICE(0x04b8, 0x0002) },
+ { USB_DEVICE(0x04b8, 0x0003) },
+ { USB_DEVICE(0x050d, 0x0002) },
+ { USB_DEVICE(0x050d, 0x1202) },
{ USB_DEVICE(0x0557, 0x2001) },
+ { USB_DEVICE(0x05ab, 0x0002) },
+ { USB_DEVICE(0x06c6, 0x0100) },
{ USB_DEVICE(0x0729, 0x1284) },
{ USB_DEVICE(0x1293, 0x0002) },
- { USB_DEVICE(0x050d, 0x0002) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c
index 7dac456f7ebc..e2050cac3eae 100644
--- a/drivers/usb/musb/musb_debugfs.c
+++ b/drivers/usb/musb/musb_debugfs.c
@@ -110,11 +110,7 @@ static int musb_regdump_show(struct seq_file *s, void *unused)
pm_runtime_put_autosuspend(musb->controller);
return 0;
}
-
-static int musb_regdump_open(struct inode *inode, struct file *file)
-{
- return single_open(file, musb_regdump_show, inode->i_private);
-}
+DEFINE_SHOW_ATTRIBUTE(musb_regdump);
static int musb_test_mode_show(struct seq_file *s, void *unused)
{
@@ -159,13 +155,6 @@ static int musb_test_mode_show(struct seq_file *s, void *unused)
return 0;
}
-static const struct file_operations musb_regdump_fops = {
- .open = musb_regdump_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
static int musb_test_mode_open(struct inode *inode, struct file *file)
{
return single_open(file, musb_test_mode_show, inode->i_private);
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 18da4873e52e..91a5027b5c1f 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -89,15 +89,19 @@ static int service_tx_status_request(
}
is_in = epnum & USB_DIR_IN;
- if (is_in) {
- epnum &= 0x0f;
+ epnum &= 0x0f;
+ if (epnum >= MUSB_C_NUM_EPS) {
+ handled = -EINVAL;
+ break;
+ }
+
+ if (is_in)
ep = &musb->endpoints[epnum].ep_in;
- } else {
+ else
ep = &musb->endpoints[epnum].ep_out;
- }
regs = musb->endpoints[epnum].regs;
- if (epnum >= MUSB_C_NUM_EPS || !ep->desc) {
+ if (!ep->desc) {
handled = -EINVAL;
break;
}
diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c
index 87295313a10c..66143ab8c043 100644
--- a/drivers/usb/phy/phy-ab8500-usb.c
+++ b/drivers/usb/phy/phy-ab8500-usb.c
@@ -29,17 +29,12 @@
/* Bank AB8500_USB */
#define AB8500_USB_LINE_STAT_REG 0x80
#define AB8505_USB_LINE_STAT_REG 0x94
-#define AB8540_USB_LINK_STAT_REG 0x94
-#define AB9540_USB_LINK_STAT_REG 0x94
-#define AB8540_USB_OTG_CTL_REG 0x87
#define AB8500_USB_PHY_CTRL_REG 0x8A
-#define AB8540_VBUS_CTRL_REG 0x82
/* Bank AB8500_DEVELOPMENT */
#define AB8500_BANK12_ACCESS 0x00
/* Bank AB8500_DEBUG */
-#define AB8540_DEBUG 0x32
#define AB8500_USB_PHY_TUNE1 0x05
#define AB8500_USB_PHY_TUNE2 0x06
#define AB8500_USB_PHY_TUNE3 0x07
@@ -53,10 +48,6 @@
#define AB8500_BIT_WD_CTRL_ENABLE (1 << 0)
#define AB8500_BIT_WD_CTRL_KICK (1 << 1)
#define AB8500_BIT_SOURCE2_VBUSDET (1 << 7)
-#define AB8540_BIT_OTG_CTL_VBUS_VALID_ENA (1 << 0)
-#define AB8540_BIT_OTG_CTL_ID_HOST_ENA (1 << 1)
-#define AB8540_BIT_OTG_CTL_ID_DEV_ENA (1 << 5)
-#define AB8540_BIT_VBUS_CTRL_CHARG_DET_ENA (1 << 0)
#define AB8500_WD_KICK_DELAY_US 100 /* usec */
#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */
@@ -113,68 +104,6 @@ enum ab8505_usb_link_status {
USB_LINK_MOTOROLA_FACTORY_CBL_PHY_EN_8505,
};
-enum ab8540_usb_link_status {
- USB_LINK_NOT_CONFIGURED_8540 = 0,
- USB_LINK_STD_HOST_NC_8540,
- USB_LINK_STD_HOST_C_NS_8540,
- USB_LINK_STD_HOST_C_S_8540,
- USB_LINK_CDP_8540,
- USB_LINK_RESERVED0_8540,
- USB_LINK_RESERVED1_8540,
- USB_LINK_DEDICATED_CHG_8540,
- USB_LINK_ACA_RID_A_8540,
- USB_LINK_ACA_RID_B_8540,
- USB_LINK_ACA_RID_C_NM_8540,
- USB_LINK_RESERVED2_8540,
- USB_LINK_RESERVED3_8540,
- USB_LINK_HM_IDGND_8540,
- USB_LINK_CHARGERPORT_NOT_OK_8540,
- USB_LINK_CHARGER_DM_HIGH_8540,
- USB_LINK_PHYEN_NO_VBUS_NO_IDGND_8540,
- USB_LINK_STD_UPSTREAM_NO_IDGNG_VBUS_8540,
- USB_LINK_STD_UPSTREAM_8540,
- USB_LINK_CHARGER_SE1_8540,
- USB_LINK_CARKIT_CHGR_1_8540,
- USB_LINK_CARKIT_CHGR_2_8540,
- USB_LINK_ACA_DOCK_CHGR_8540,
- USB_LINK_SAMSUNG_BOOT_CBL_PHY_EN_8540,
- USB_LINK_SAMSUNG_BOOT_CBL_PHY_DISB_8540,
- USB_LINK_SAMSUNG_UART_CBL_PHY_EN_8540,
- USB_LINK_SAMSUNG_UART_CBL_PHY_DISB_8540,
- USB_LINK_MOTOROLA_FACTORY_CBL_PHY_EN_8540
-};
-
-enum ab9540_usb_link_status {
- USB_LINK_NOT_CONFIGURED_9540 = 0,
- USB_LINK_STD_HOST_NC_9540,
- USB_LINK_STD_HOST_C_NS_9540,
- USB_LINK_STD_HOST_C_S_9540,
- USB_LINK_CDP_9540,
- USB_LINK_RESERVED0_9540,
- USB_LINK_RESERVED1_9540,
- USB_LINK_DEDICATED_CHG_9540,
- USB_LINK_ACA_RID_A_9540,
- USB_LINK_ACA_RID_B_9540,
- USB_LINK_ACA_RID_C_NM_9540,
- USB_LINK_RESERVED2_9540,
- USB_LINK_RESERVED3_9540,
- USB_LINK_HM_IDGND_9540,
- USB_LINK_CHARGERPORT_NOT_OK_9540,
- USB_LINK_CHARGER_DM_HIGH_9540,
- USB_LINK_PHYEN_NO_VBUS_NO_IDGND_9540,
- USB_LINK_STD_UPSTREAM_NO_IDGNG_VBUS_9540,
- USB_LINK_STD_UPSTREAM_9540,
- USB_LINK_CHARGER_SE1_9540,
- USB_LINK_CARKIT_CHGR_1_9540,
- USB_LINK_CARKIT_CHGR_2_9540,
- USB_LINK_ACA_DOCK_CHGR_9540,
- USB_LINK_SAMSUNG_BOOT_CBL_PHY_EN_9540,
- USB_LINK_SAMSUNG_BOOT_CBL_PHY_DISB_9540,
- USB_LINK_SAMSUNG_UART_CBL_PHY_EN_9540,
- USB_LINK_SAMSUNG_UART_CBL_PHY_DISB_9540,
- USB_LINK_MOTOROLA_FACTORY_CBL_PHY_EN_9540
-};
-
enum ab8500_usb_mode {
USB_IDLE = 0,
USB_PERIPHERAL,
@@ -192,10 +121,6 @@ enum ab8500_usb_mode {
#define AB8500_USB_FLAG_USE_AB_IDDET (1 << 3)
/* Enable setting regulators voltage */
#define AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE (1 << 4)
-/* Enable the check_vbus_status workaround */
-#define AB8500_USB_FLAG_USE_CHECK_VBUS_STATUS (1 << 5)
-/* Enable the vbus host workaround */
-#define AB8500_USB_FLAG_USE_VBUS_HOST_QUIRK (1 << 6)
struct ab8500_usb {
struct usb_phy phy;
@@ -203,7 +128,6 @@ struct ab8500_usb {
struct ab8500 *ab8500;
unsigned vbus_draw;
struct work_struct phy_dis_work;
- struct work_struct vbus_event_work;
enum ab8500_usb_mode mode;
struct clk *sysclk;
struct regulator *v_ape;
@@ -342,15 +266,6 @@ static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host)
abx500_mask_and_set_register_interruptible(ab->dev,
AB8500_USB, AB8500_USB_PHY_CTRL_REG,
bit, bit);
-
- if (ab->flags & AB8500_USB_FLAG_USE_VBUS_HOST_QUIRK) {
- if (sel_host)
- abx500_set_register_interruptible(ab->dev,
- AB8500_USB, AB8540_USB_OTG_CTL_REG,
- AB8540_BIT_OTG_CTL_VBUS_VALID_ENA |
- AB8540_BIT_OTG_CTL_ID_HOST_ENA |
- AB8540_BIT_OTG_CTL_ID_DEV_ENA);
- }
}
static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host)
@@ -395,263 +310,6 @@ static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host)
#define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_enable(ab, false)
#define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_disable(ab, false)
-static int ab9540_usb_link_status_update(struct ab8500_usb *ab,
- enum ab9540_usb_link_status lsts)
-{
- enum ux500_musb_vbus_id_status event = 0;
-
- dev_dbg(ab->dev, "ab9540_usb_link_status_update %d\n", lsts);
-
- if (ab->previous_link_status_state == USB_LINK_HM_IDGND_9540 &&
- (lsts == USB_LINK_STD_HOST_C_NS_9540 ||
- lsts == USB_LINK_STD_HOST_NC_9540))
- return 0;
-
- if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_9540 &&
- (lsts == USB_LINK_STD_HOST_NC_9540))
- return 0;
-
- ab->previous_link_status_state = lsts;
-
- switch (lsts) {
- case USB_LINK_ACA_RID_B_9540:
- event = UX500_MUSB_RIDB;
- case USB_LINK_NOT_CONFIGURED_9540:
- case USB_LINK_RESERVED0_9540:
- case USB_LINK_RESERVED1_9540:
- case USB_LINK_RESERVED2_9540:
- case USB_LINK_RESERVED3_9540:
- if (ab->mode == USB_PERIPHERAL)
- atomic_notifier_call_chain(&ab->phy.notifier,
- UX500_MUSB_CLEAN, &ab->vbus_draw);
- ab->mode = USB_IDLE;
- ab->phy.otg->default_a = false;
- ab->vbus_draw = 0;
- if (event != UX500_MUSB_RIDB)
- event = UX500_MUSB_NONE;
- /* Fallback to default B_IDLE as nothing is connected. */
- ab->phy.otg->state = OTG_STATE_B_IDLE;
- usb_phy_set_event(&ab->phy, USB_EVENT_NONE);
- break;
-
- case USB_LINK_ACA_RID_C_NM_9540:
- event = UX500_MUSB_RIDC;
- case USB_LINK_STD_HOST_NC_9540:
- case USB_LINK_STD_HOST_C_NS_9540:
- case USB_LINK_STD_HOST_C_S_9540:
- case USB_LINK_CDP_9540:
- if (ab->mode == USB_HOST) {
- ab->mode = USB_PERIPHERAL;
- ab8500_usb_host_phy_dis(ab);
- ab8500_usb_peri_phy_en(ab);
- atomic_notifier_call_chain(&ab->phy.notifier,
- UX500_MUSB_PREPARE, &ab->vbus_draw);
- usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED);
- }
- if (ab->mode == USB_IDLE) {
- ab->mode = USB_PERIPHERAL;
- ab8500_usb_peri_phy_en(ab);
- atomic_notifier_call_chain(&ab->phy.notifier,
- UX500_MUSB_PREPARE, &ab->vbus_draw);
- usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED);
- }
- if (event != UX500_MUSB_RIDC)
- event = UX500_MUSB_VBUS;
- break;
-
- case USB_LINK_ACA_RID_A_9540:
- event = UX500_MUSB_RIDA;
- case USB_LINK_HM_IDGND_9540:
- case USB_LINK_STD_UPSTREAM_9540:
- if (ab->mode == USB_PERIPHERAL) {
- ab->mode = USB_HOST;
- ab8500_usb_peri_phy_dis(ab);
- ab8500_usb_host_phy_en(ab);
- atomic_notifier_call_chain(&ab->phy.notifier,
- UX500_MUSB_PREPARE, &ab->vbus_draw);
- }
- if (ab->mode == USB_IDLE) {
- ab->mode = USB_HOST;
- ab8500_usb_host_phy_en(ab);
- atomic_notifier_call_chain(&ab->phy.notifier,
- UX500_MUSB_PREPARE, &ab->vbus_draw);
- }
- ab->phy.otg->default_a = true;
- if (event != UX500_MUSB_RIDA)
- event = UX500_MUSB_ID;
-
- atomic_notifier_call_chain(&ab->phy.notifier,
- event, &ab->vbus_draw);
- break;
-
- case USB_LINK_DEDICATED_CHG_9540:
- ab->mode = USB_DEDICATED_CHG;
- event = UX500_MUSB_CHARGER;
- atomic_notifier_call_chain(&ab->phy.notifier,
- event, &ab->vbus_draw);
- usb_phy_set_event(&ab->phy, USB_EVENT_CHARGER);
- break;
-
- case USB_LINK_PHYEN_NO_VBUS_NO_IDGND_9540:
- case USB_LINK_STD_UPSTREAM_NO_IDGNG_VBUS_9540:
- if (!(is_ab9540_2p0_or_earlier(ab->ab8500))) {
- event = UX500_MUSB_NONE;
- if (ab->mode == USB_HOST) {
- ab->phy.otg->default_a = false;
- ab->vbus_draw = 0;
- atomic_notifier_call_chain(&ab->phy.notifier,
- event, &ab->vbus_draw);
- ab8500_usb_host_phy_dis(ab);
- ab->mode = USB_IDLE;
- }
- if (ab->mode == USB_PERIPHERAL) {
- atomic_notifier_call_chain(&ab->phy.notifier,
- event, &ab->vbus_draw);
- ab8500_usb_peri_phy_dis(ab);
- atomic_notifier_call_chain(&ab->phy.notifier,
- UX500_MUSB_CLEAN,
- &ab->vbus_draw);
- ab->mode = USB_IDLE;
- ab->phy.otg->default_a = false;
- ab->vbus_draw = 0;
- usb_phy_set_event(&ab->phy, USB_EVENT_NONE);
- }
- }
- break;
-
- default:
- break;
- }
-
- return 0;
-}
-
-static int ab8540_usb_link_status_update(struct ab8500_usb *ab,
- enum ab8540_usb_link_status lsts)
-{
- enum ux500_musb_vbus_id_status event = 0;
-
- dev_dbg(ab->dev, "ab8540_usb_link_status_update %d\n", lsts);
-
- if (ab->enabled_charging_detection) {
- /* Disable USB Charger detection */
- abx500_mask_and_set_register_interruptible(ab->dev,
- AB8500_USB, AB8540_VBUS_CTRL_REG,
- AB8540_BIT_VBUS_CTRL_CHARG_DET_ENA, 0x00);
- ab->enabled_charging_detection = false;
- }
-
- /*
- * Spurious link_status interrupts are seen in case of a
- * disconnection of a device in IDGND and RIDA stage
- */
- if (ab->previous_link_status_state == USB_LINK_HM_IDGND_8540 &&
- (lsts == USB_LINK_STD_HOST_C_NS_8540 ||
- lsts == USB_LINK_STD_HOST_NC_8540))
- return 0;
-
- if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8540 &&
- (lsts == USB_LINK_STD_HOST_NC_8540))
- return 0;
-
- ab->previous_link_status_state = lsts;
-
- switch (lsts) {
- case USB_LINK_ACA_RID_B_8540:
- event = UX500_MUSB_RIDB;
- case USB_LINK_NOT_CONFIGURED_8540:
- case USB_LINK_RESERVED0_8540:
- case USB_LINK_RESERVED1_8540:
- case USB_LINK_RESERVED2_8540:
- case USB_LINK_RESERVED3_8540:
- ab->mode = USB_IDLE;
- ab->phy.otg->default_a = false;
- ab->vbus_draw = 0;
- if (event != UX500_MUSB_RIDB)
- event = UX500_MUSB_NONE;
- /*
- * Fallback to default B_IDLE as nothing
- * is connected
- */
- ab->phy.otg->state = OTG_STATE_B_IDLE;
- usb_phy_set_event(&ab->phy, USB_EVENT_NONE);
- break;
-
- case USB_LINK_ACA_RID_C_NM_8540:
- event = UX500_MUSB_RIDC;
- case USB_LINK_STD_HOST_NC_8540:
- case USB_LINK_STD_HOST_C_NS_8540:
- case USB_LINK_STD_HOST_C_S_8540:
- case USB_LINK_CDP_8540:
- if (ab->mode == USB_IDLE) {
- ab->mode = USB_PERIPHERAL;
- ab8500_usb_peri_phy_en(ab);
- atomic_notifier_call_chain(&ab->phy.notifier,
- UX500_MUSB_PREPARE, &ab->vbus_draw);
- usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED);
- }
- if (event != UX500_MUSB_RIDC)
- event = UX500_MUSB_VBUS;
- break;
-
- case USB_LINK_ACA_RID_A_8540:
- case USB_LINK_ACA_DOCK_CHGR_8540:
- event = UX500_MUSB_RIDA;
- case USB_LINK_HM_IDGND_8540:
- case USB_LINK_STD_UPSTREAM_8540:
- if (ab->mode == USB_IDLE) {
- ab->mode = USB_HOST;
- ab8500_usb_host_phy_en(ab);
- atomic_notifier_call_chain(&ab->phy.notifier,
- UX500_MUSB_PREPARE, &ab->vbus_draw);
- }
- ab->phy.otg->default_a = true;
- if (event != UX500_MUSB_RIDA)
- event = UX500_MUSB_ID;
- atomic_notifier_call_chain(&ab->phy.notifier,
- event, &ab->vbus_draw);
- break;
-
- case USB_LINK_DEDICATED_CHG_8540:
- ab->mode = USB_DEDICATED_CHG;
- event = UX500_MUSB_CHARGER;
- atomic_notifier_call_chain(&ab->phy.notifier,
- event, &ab->vbus_draw);
- usb_phy_set_event(&ab->phy, USB_EVENT_CHARGER);
- break;
-
- case USB_LINK_PHYEN_NO_VBUS_NO_IDGND_8540:
- case USB_LINK_STD_UPSTREAM_NO_IDGNG_VBUS_8540:
- event = UX500_MUSB_NONE;
- if (ab->mode == USB_HOST) {
- ab->phy.otg->default_a = false;
- ab->vbus_draw = 0;
- atomic_notifier_call_chain(&ab->phy.notifier,
- event, &ab->vbus_draw);
- ab8500_usb_host_phy_dis(ab);
- ab->mode = USB_IDLE;
- }
- if (ab->mode == USB_PERIPHERAL) {
- atomic_notifier_call_chain(&ab->phy.notifier,
- event, &ab->vbus_draw);
- ab8500_usb_peri_phy_dis(ab);
- atomic_notifier_call_chain(&ab->phy.notifier,
- UX500_MUSB_CLEAN, &ab->vbus_draw);
- ab->mode = USB_IDLE;
- ab->phy.otg->default_a = false;
- ab->vbus_draw = 0;
- usb_phy_set_event(&ab->phy, USB_EVENT_NONE);
- }
- break;
-
- default:
- event = UX500_MUSB_NONE;
- break;
- }
-
- return 0;
-}
-
static int ab8505_usb_link_status_update(struct ab8500_usb *ab,
enum ab8505_usb_link_status lsts)
{
@@ -858,20 +516,6 @@ static int abx500_usb_link_status_update(struct ab8500_usb *ab)
AB8500_USB, AB8505_USB_LINE_STAT_REG, &reg);
lsts = (reg >> 3) & 0x1F;
ret = ab8505_usb_link_status_update(ab, lsts);
- } else if (is_ab8540(ab->ab8500)) {
- enum ab8540_usb_link_status lsts;
-
- abx500_get_register_interruptible(ab->dev,
- AB8500_USB, AB8540_USB_LINK_STAT_REG, &reg);
- lsts = (reg >> 3) & 0xFF;
- ret = ab8540_usb_link_status_update(ab, lsts);
- } else if (is_ab9540(ab->ab8500)) {
- enum ab9540_usb_link_status lsts;
-
- abx500_get_register_interruptible(ab->dev,
- AB8500_USB, AB9540_USB_LINK_STAT_REG, &reg);
- lsts = (reg >> 3) & 0xFF;
- ret = ab9540_usb_link_status_update(ab, lsts);
}
return ret;
@@ -889,7 +533,7 @@ static int abx500_usb_link_status_update(struct ab8500_usb *ab)
static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data)
{
struct ab8500_usb *ab = (struct ab8500_usb *) data;
- enum usb_phy_events event = UX500_MUSB_NONE;
+ enum usb_phy_events event = USB_EVENT_NONE;
/* Link status will not be updated till phy is disabled. */
if (ab->mode == USB_HOST) {
@@ -946,69 +590,6 @@ static void ab8500_usb_phy_disable_work(struct work_struct *work)
ab8500_usb_peri_phy_dis(ab);
}
-/* Check if VBUS is set and linkstatus has not detected a cable. */
-static bool ab8500_usb_check_vbus_status(struct ab8500_usb *ab)
-{
- u8 isource2;
- u8 reg;
- enum ab8540_usb_link_status lsts;
-
- abx500_get_register_interruptible(ab->dev,
- AB8500_INTERRUPT, AB8500_IT_SOURCE2_REG,
- &isource2);
-
- /* If Vbus is below 3.6V abort */
- if (!(isource2 & AB8500_BIT_SOURCE2_VBUSDET))
- return false;
-
- abx500_get_register_interruptible(ab->dev,
- AB8500_USB, AB8540_USB_LINK_STAT_REG,
- &reg);
-
- lsts = (reg >> 3) & 0xFF;
-
- /* Check if linkstatus has detected a cable */
- if (lsts)
- return false;
-
- return true;
-}
-
-/* re-trigger charger detection again with watchdog re-kick. */
-static void ab8500_usb_vbus_turn_on_event_work(struct work_struct *work)
-{
- struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
- vbus_event_work);
-
- if (ab->mode != USB_IDLE)
- return;
-
- abx500_set_register_interruptible(ab->dev,
- AB8500_SYS_CTRL2_BLOCK, AB8500_MAIN_WD_CTRL_REG,
- AB8500_BIT_WD_CTRL_ENABLE);
-
- udelay(100);
-
- abx500_set_register_interruptible(ab->dev,
- AB8500_SYS_CTRL2_BLOCK, AB8500_MAIN_WD_CTRL_REG,
- AB8500_BIT_WD_CTRL_ENABLE | AB8500_BIT_WD_CTRL_KICK);
-
- udelay(100);
-
- /* Disable Main watchdog */
- abx500_set_register_interruptible(ab->dev,
- AB8500_SYS_CTRL2_BLOCK, AB8500_MAIN_WD_CTRL_REG,
- 0x0);
-
- /* Enable USB Charger detection */
- abx500_mask_and_set_register_interruptible(ab->dev,
- AB8500_USB, AB8540_VBUS_CTRL_REG,
- AB8540_BIT_VBUS_CTRL_CHARG_DET_ENA,
- AB8540_BIT_VBUS_CTRL_CHARG_DET_ENA);
-
- ab->enabled_charging_detection = true;
-}
-
static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend)
{
/* TODO */
@@ -1256,66 +837,6 @@ static void ab8500_usb_set_ab8505_tuning_values(struct ab8500_usb *ab)
err);
}
-static void ab8500_usb_set_ab8540_tuning_values(struct ab8500_usb *ab)
-{
- int err;
-
- err = abx500_set_register_interruptible(ab->dev,
- AB8540_DEBUG, AB8500_USB_PHY_TUNE1, 0xCC);
- if (err < 0)
- dev_err(ab->dev, "Failed to set PHY_TUNE1 register ret=%d\n",
- err);
-
- err = abx500_set_register_interruptible(ab->dev,
- AB8540_DEBUG, AB8500_USB_PHY_TUNE2, 0x60);
- if (err < 0)
- dev_err(ab->dev, "Failed to set PHY_TUNE2 register ret=%d\n",
- err);
-
- err = abx500_set_register_interruptible(ab->dev,
- AB8540_DEBUG, AB8500_USB_PHY_TUNE3, 0x90);
- if (err < 0)
- dev_err(ab->dev, "Failed to set PHY_TUNE3 register ret=%d\n",
- err);
-}
-
-static void ab8500_usb_set_ab9540_tuning_values(struct ab8500_usb *ab)
-{
- int err;
-
- /* Enable the PBT/Bank 0x12 access */
- err = abx500_set_register_interruptible(ab->dev,
- AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x01);
- if (err < 0)
- dev_err(ab->dev, "Failed to enable bank12 access err=%d\n",
- err);
-
- err = abx500_set_register_interruptible(ab->dev,
- AB8500_DEBUG, AB8500_USB_PHY_TUNE1, 0xC8);
- if (err < 0)
- dev_err(ab->dev, "Failed to set PHY_TUNE1 register err=%d\n",
- err);
-
- err = abx500_set_register_interruptible(ab->dev,
- AB8500_DEBUG, AB8500_USB_PHY_TUNE2, 0x60);
- if (err < 0)
- dev_err(ab->dev, "Failed to set PHY_TUNE2 register err=%d\n",
- err);
-
- err = abx500_set_register_interruptible(ab->dev,
- AB8500_DEBUG, AB8500_USB_PHY_TUNE3, 0x80);
- if (err < 0)
- dev_err(ab->dev, "Failed to set PHY_TUNE3 register err=%d\n",
- err);
-
- /* Switch to normal mode/disable Bank 0x12 access */
- err = abx500_set_register_interruptible(ab->dev,
- AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x00);
- if (err < 0)
- dev_err(ab->dev, "Failed to switch bank12 access err=%d\n",
- err);
-}
-
static int ab8500_usb_probe(struct platform_device *pdev)
{
struct ab8500_usb *ab;
@@ -1362,17 +883,6 @@ static int ab8500_usb_probe(struct platform_device *pdev)
AB8500_USB_FLAG_USE_ID_WAKEUP_IRQ |
AB8500_USB_FLAG_USE_VBUS_DET_IRQ |
AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE;
- } else if (is_ab8540(ab->ab8500)) {
- ab->flags |= AB8500_USB_FLAG_USE_LINK_STATUS_IRQ |
- AB8500_USB_FLAG_USE_CHECK_VBUS_STATUS |
- AB8500_USB_FLAG_USE_VBUS_HOST_QUIRK |
- AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE;
- } else if (is_ab9540(ab->ab8500)) {
- ab->flags |= AB8500_USB_FLAG_USE_LINK_STATUS_IRQ |
- AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE;
- if (is_ab9540_2p0_or_earlier(ab->ab8500))
- ab->flags |= AB8500_USB_FLAG_USE_ID_WAKEUP_IRQ |
- AB8500_USB_FLAG_USE_VBUS_DET_IRQ;
}
/* Disable regulator voltage setting for AB8500 <= v2.0 */
@@ -1384,8 +894,6 @@ static int ab8500_usb_probe(struct platform_device *pdev)
/* all: Disable phy when called from set_host and set_peripheral */
INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
- INIT_WORK(&ab->vbus_event_work, ab8500_usb_vbus_turn_on_event_work);
-
err = ab8500_usb_regulator_get(ab);
if (err)
return err;
@@ -1412,12 +920,6 @@ static int ab8500_usb_probe(struct platform_device *pdev)
else if (is_ab8505(ab->ab8500))
/* Phy tuning values for AB8505 */
ab8500_usb_set_ab8505_tuning_values(ab);
- else if (is_ab8540(ab->ab8500))
- /* Phy tuning values for AB8540 */
- ab8500_usb_set_ab8540_tuning_values(ab);
- else if (is_ab9540(ab->ab8500))
- /* Phy tuning values for AB9540 */
- ab8500_usb_set_ab9540_tuning_values(ab);
/* Needed to enable ID detection. */
ab8500_usb_wd_workaround(ab);
@@ -1428,11 +930,6 @@ static int ab8500_usb_probe(struct platform_device *pdev)
*/
ab8500_usb_restart_phy(ab);
- if (ab->flags & AB8500_USB_FLAG_USE_CHECK_VBUS_STATUS) {
- if (ab8500_usb_check_vbus_status(ab))
- schedule_work(&ab->vbus_event_work);
- }
-
abx500_usb_link_status_update(ab);
dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", rev);
@@ -1445,7 +942,6 @@ static int ab8500_usb_remove(struct platform_device *pdev)
struct ab8500_usb *ab = platform_get_drvdata(pdev);
cancel_work_sync(&ab->phy_dis_work);
- cancel_work_sync(&ab->vbus_event_work);
usb_remove_phy(&ab->phy);
@@ -1459,8 +955,6 @@ static int ab8500_usb_remove(struct platform_device *pdev)
static const struct platform_device_id ab8500_usb_devtype[] = {
{ .name = "ab8500-usb", },
- { .name = "ab8540-usb", },
- { .name = "ab9540-usb", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, ab8500_usb_devtype);
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index 74ba88297991..a53b89be5324 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -63,9 +63,9 @@ static void nop_reset(struct usb_phy_generic *nop)
if (!nop->gpiod_reset)
return;
- gpiod_set_value(nop->gpiod_reset, 1);
+ gpiod_set_value_cansleep(nop->gpiod_reset, 1);
usleep_range(10000, 20000);
- gpiod_set_value(nop->gpiod_reset, 0);
+ gpiod_set_value_cansleep(nop->gpiod_reset, 0);
}
/* interface to regulator framework */
@@ -159,7 +159,7 @@ void usb_gen_phy_shutdown(struct usb_phy *phy)
{
struct usb_phy_generic *nop = dev_get_drvdata(phy->dev);
- gpiod_set_value(nop->gpiod_reset, 1);
+ gpiod_set_value_cansleep(nop->gpiod_reset, 1);
if (!IS_ERR(nop->clk))
clk_disable_unprepare(nop->clk);
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index fbec863350f6..e5aa24c1e4fd 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -578,7 +578,7 @@ static enum usb_charger_type mxs_charger_primary_detection(struct mxs_phy *x)
* It must be called after DP is pulled up, which is used to
* differentiate DCP and CDP.
*/
-enum usb_charger_type mxs_charger_secondary_detection(struct mxs_phy *x)
+static enum usb_charger_type mxs_charger_secondary_detection(struct mxs_phy *x)
{
struct regmap *regmap = x->regmap_anatop;
int val;
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index f668bfb708d3..0e8d23e51732 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -16,7 +16,7 @@
#include <linux/export.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -305,14 +305,10 @@ static int utmip_pad_power_off(struct tegra_usb_phy *phy)
static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
{
- unsigned long timeout = 2000;
- do {
- if ((readl(reg) & mask) == result)
- return 0;
- udelay(1);
- timeout--;
- } while (timeout);
- return -1;
+ u32 tmp;
+
+ return readl_poll_timeout(reg, tmp, (tmp & mask) == result,
+ 2000, 6000);
}
static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
diff --git a/drivers/usb/roles/Kconfig b/drivers/usb/roles/Kconfig
new file mode 100644
index 000000000000..f5a5e6f79f1b
--- /dev/null
+++ b/drivers/usb/roles/Kconfig
@@ -0,0 +1,14 @@
+if USB_ROLE_SWITCH
+
+config USB_ROLES_INTEL_XHCI
+ tristate "Intel XHCI USB Role Switch"
+ depends on ACPI && X86
+ help
+ Driver for the internal USB role switch for switching the USB data
+ lines between the xHCI host controller and the dwc3 gadget controller
+ found on various Intel SoCs.
+
+ To compile the driver as a module, choose M here: the module will
+ be called intel-xhci-usb-role-switch.
+
+endif # USB_ROLE_SWITCH
diff --git a/drivers/usb/roles/Makefile b/drivers/usb/roles/Makefile
new file mode 100644
index 000000000000..e44b179ba275
--- /dev/null
+++ b/drivers/usb/roles/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_USB_ROLES_INTEL_XHCI) += intel-xhci-usb-role-switch.o
diff --git a/drivers/usb/roles/intel-xhci-usb-role-switch.c b/drivers/usb/roles/intel-xhci-usb-role-switch.c
new file mode 100644
index 000000000000..de72eedb762e
--- /dev/null
+++ b/drivers/usb/roles/intel-xhci-usb-role-switch.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Intel XHCI (Cherry Trail, Broxton and others) USB OTG role switch driver
+ *
+ * Copyright (c) 2016-2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Loosely based on android x86 kernel code which is:
+ *
+ * Copyright (C) 2014 Intel Corp.
+ *
+ * Author: Wu, Hao
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/usb/role.h>
+
+/* register definition */
+#define DUAL_ROLE_CFG0 0x68
+#define SW_VBUS_VALID BIT(24)
+#define SW_IDPIN_EN BIT(21)
+#define SW_IDPIN BIT(20)
+
+#define DUAL_ROLE_CFG1 0x6c
+#define HOST_MODE BIT(29)
+
+#define DUAL_ROLE_CFG1_POLL_TIMEOUT 1000
+
+#define DRV_NAME "intel_xhci_usb_sw"
+
+struct intel_xhci_usb_data {
+ struct usb_role_switch *role_sw;
+ void __iomem *base;
+};
+
+struct intel_xhci_acpi_match {
+ const char *hid;
+ int hrv;
+};
+
+/*
+ * ACPI IDs for PMICs which do not support separate data and power role
+ * detection (USB ACA detection for micro USB OTG), we allow userspace to
+ * change the role manually on these.
+ */
+static const struct intel_xhci_acpi_match allow_userspace_ctrl_ids[] = {
+ { "INT33F4", 3 }, /* X-Powers AXP288 PMIC */
+};
+
+static int intel_xhci_usb_set_role(struct device *dev, enum usb_role role)
+{
+ struct intel_xhci_usb_data *data = dev_get_drvdata(dev);
+ unsigned long timeout;
+ acpi_status status;
+ u32 glk, val;
+
+ /*
+ * On many CHT devices ACPI event (_AEI) handlers read / modify /
+ * write the cfg0 register, just like we do. Take the ACPI lock
+ * to avoid us racing with the AML code.
+ */
+ status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, &glk);
+ if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
+ dev_err(dev, "Error could not acquire lock\n");
+ return -EIO;
+ }
+
+ /* Set idpin value as requested */
+ val = readl(data->base + DUAL_ROLE_CFG0);
+ switch (role) {
+ case USB_ROLE_NONE:
+ val |= SW_IDPIN;
+ val &= ~SW_VBUS_VALID;
+ break;
+ case USB_ROLE_HOST:
+ val &= ~SW_IDPIN;
+ val &= ~SW_VBUS_VALID;
+ break;
+ case USB_ROLE_DEVICE:
+ val |= SW_IDPIN;
+ val |= SW_VBUS_VALID;
+ break;
+ }
+ val |= SW_IDPIN_EN;
+
+ writel(val, data->base + DUAL_ROLE_CFG0);
+
+ acpi_release_global_lock(glk);
+
+ /* In most case it takes about 600ms to finish mode switching */
+ timeout = jiffies + msecs_to_jiffies(DUAL_ROLE_CFG1_POLL_TIMEOUT);
+
+ /* Polling on CFG1 register to confirm mode switch.*/
+ do {
+ val = readl(data->base + DUAL_ROLE_CFG1);
+ if (!!(val & HOST_MODE) == (role == USB_ROLE_HOST))
+ return 0;
+
+ /* Interval for polling is set to about 5 - 10 ms */
+ usleep_range(5000, 10000);
+ } while (time_before(jiffies, timeout));
+
+ dev_warn(dev, "Timeout waiting for role-switch\n");
+ return -ETIMEDOUT;
+}
+
+static enum usb_role intel_xhci_usb_get_role(struct device *dev)
+{
+ struct intel_xhci_usb_data *data = dev_get_drvdata(dev);
+ enum usb_role role;
+ u32 val;
+
+ val = readl(data->base + DUAL_ROLE_CFG0);
+
+ if (!(val & SW_IDPIN))
+ role = USB_ROLE_HOST;
+ else if (val & SW_VBUS_VALID)
+ role = USB_ROLE_DEVICE;
+ else
+ role = USB_ROLE_NONE;
+
+ return role;
+}
+
+static struct usb_role_switch_desc sw_desc = {
+ .set = intel_xhci_usb_set_role,
+ .get = intel_xhci_usb_get_role,
+};
+
+static int intel_xhci_usb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct intel_xhci_usb_data *data;
+ struct resource *res;
+ int i;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
+ if (!data->base)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(allow_userspace_ctrl_ids); i++)
+ if (acpi_dev_present(allow_userspace_ctrl_ids[i].hid, "1",
+ allow_userspace_ctrl_ids[i].hrv))
+ sw_desc.allow_userspace_control = true;
+
+ platform_set_drvdata(pdev, data);
+
+ data->role_sw = usb_role_switch_register(dev, &sw_desc);
+ if (IS_ERR(data->role_sw))
+ return PTR_ERR(data->role_sw);
+
+ return 0;
+}
+
+static int intel_xhci_usb_remove(struct platform_device *pdev)
+{
+ struct intel_xhci_usb_data *data = platform_get_drvdata(pdev);
+
+ usb_role_switch_unregister(data->role_sw);
+ return 0;
+}
+
+static const struct platform_device_id intel_xhci_usb_table[] = {
+ { .name = DRV_NAME },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, intel_xhci_usb_table);
+
+static struct platform_driver intel_xhci_usb_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ },
+ .id_table = intel_xhci_usb_table,
+ .probe = intel_xhci_usb_probe,
+ .remove = intel_xhci_usb_remove,
+};
+
+module_platform_driver(intel_xhci_usb_driver);
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Intel XHCI USB role switch driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 06d502b3e913..de1e759dd512 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -155,6 +155,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x12B8, 0xEC62) }, /* Link G4+ ECU */
{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
{ USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */
+ { USB_DEVICE(0x155A, 0x1006) }, /* ELDAT Easywave RX09 */
{ USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */
{ USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */
{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index f58c4ff6b387..87202ad5a50d 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -769,6 +769,7 @@ static const struct usb_device_id id_table_combined[] = {
.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
{ USB_DEVICE(NOVITUS_VID, NOVITUS_BONO_E_PID) },
+ { USB_DEVICE(FTDI_VID, RTSYSTEMS_USB_VX8_PID) },
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) },
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) },
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) },
@@ -931,6 +932,7 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_FHE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
{ USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 8b4ecd2bd297..975d02666c5a 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -923,6 +923,9 @@
/*
* RT Systems programming cables for various ham radios
*/
+/* This device uses the VID of FTDI */
+#define RTSYSTEMS_USB_VX8_PID 0x9e50 /* USB-VX8 USB to 7 pin modular plug for Yaesu VX-8 radio */
+
#define RTSYSTEMS_VID 0x2100 /* Vendor ID */
#define RTSYSTEMS_USB_S03_PID 0x9001 /* RTS-03 USB to Serial Adapter */
#define RTSYSTEMS_USB_59_PID 0x9e50 /* USB-59 USB to 8 pin plug */
@@ -1442,6 +1445,12 @@
#define FTDI_CINTERION_MC55I_PID 0xA951
/*
+ * Product: FirmwareHubEmulator
+ * Manufacturer: Harman Becker Automotive Systems
+ */
+#define FTDI_FHE_PID 0xA9A0
+
+/*
* Product: Comet Caller ID decoder
* Manufacturer: Crucible Technologies
*/
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 2d8d9150da0c..c3f252283ab9 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -548,151 +548,15 @@ static void option_instat_callback(struct urb *urb);
#define WETELECOM_PRODUCT_6802 0x6802
#define WETELECOM_PRODUCT_WMD300 0x6803
-struct option_blacklist_info {
- /* bitmask of interface numbers blacklisted for send_setup */
- const unsigned long sendsetup;
- /* bitmask of interface numbers that are reserved */
- const unsigned long reserved;
-};
-
-static const struct option_blacklist_info four_g_w14_blacklist = {
- .sendsetup = BIT(0) | BIT(1),
-};
-
-static const struct option_blacklist_info four_g_w100_blacklist = {
- .sendsetup = BIT(1) | BIT(2),
- .reserved = BIT(3),
-};
-
-static const struct option_blacklist_info alcatel_x200_blacklist = {
- .sendsetup = BIT(0) | BIT(1),
- .reserved = BIT(4),
-};
-
-static const struct option_blacklist_info zte_0037_blacklist = {
- .sendsetup = BIT(0) | BIT(1),
-};
-
-static const struct option_blacklist_info zte_k3765_z_blacklist = {
- .sendsetup = BIT(0) | BIT(1) | BIT(2),
- .reserved = BIT(4),
-};
-
-static const struct option_blacklist_info zte_ad3812_z_blacklist = {
- .sendsetup = BIT(0) | BIT(1) | BIT(2),
-};
-
-static const struct option_blacklist_info zte_mc2718_z_blacklist = {
- .sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4),
-};
-
-static const struct option_blacklist_info zte_mc2716_z_blacklist = {
- .sendsetup = BIT(1) | BIT(2) | BIT(3),
-};
-
-static const struct option_blacklist_info zte_me3620_mbim_blacklist = {
- .reserved = BIT(2) | BIT(3) | BIT(4),
-};
-
-static const struct option_blacklist_info zte_me3620_xl_blacklist = {
- .reserved = BIT(3) | BIT(4) | BIT(5),
-};
-
-static const struct option_blacklist_info zte_zm8620_x_blacklist = {
- .reserved = BIT(3) | BIT(4) | BIT(5),
-};
-
-static const struct option_blacklist_info huawei_cdc12_blacklist = {
- .reserved = BIT(1) | BIT(2),
-};
-
-static const struct option_blacklist_info net_intf0_blacklist = {
- .reserved = BIT(0),
-};
-
-static const struct option_blacklist_info net_intf1_blacklist = {
- .reserved = BIT(1),
-};
-
-static const struct option_blacklist_info net_intf2_blacklist = {
- .reserved = BIT(2),
-};
-
-static const struct option_blacklist_info net_intf3_blacklist = {
- .reserved = BIT(3),
-};
-
-static const struct option_blacklist_info net_intf4_blacklist = {
- .reserved = BIT(4),
-};
-
-static const struct option_blacklist_info net_intf5_blacklist = {
- .reserved = BIT(5),
-};
-
-static const struct option_blacklist_info net_intf6_blacklist = {
- .reserved = BIT(6),
-};
-
-static const struct option_blacklist_info zte_mf626_blacklist = {
- .sendsetup = BIT(0) | BIT(1),
- .reserved = BIT(4),
-};
-
-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_me910_blacklist = {
- .sendsetup = BIT(0),
- .reserved = BIT(1) | BIT(3),
-};
-
-static const struct option_blacklist_info telit_me910_dual_modem_blacklist = {
- .sendsetup = BIT(0),
- .reserved = BIT(3),
-};
-
-static const struct option_blacklist_info telit_le910_blacklist = {
- .sendsetup = BIT(0),
- .reserved = BIT(1) | BIT(2),
-};
-static const struct option_blacklist_info telit_le920_blacklist = {
- .sendsetup = BIT(0),
- .reserved = BIT(1) | BIT(5),
-};
+/* Device flags */
-static const struct option_blacklist_info telit_le920a4_blacklist_1 = {
- .sendsetup = BIT(0),
- .reserved = BIT(1),
-};
+/* Interface does not support modem-control requests */
+#define NCTRL(ifnum) ((BIT(ifnum) & 0xff) << 8)
-static const struct option_blacklist_info telit_le922_blacklist_usbcfg0 = {
- .sendsetup = BIT(2),
- .reserved = BIT(0) | BIT(1) | BIT(3),
-};
+/* Interface is reserved */
+#define RSVD(ifnum) ((BIT(ifnum) & 0xff) << 0)
-static const struct option_blacklist_info telit_le922_blacklist_usbcfg3 = {
- .sendsetup = BIT(0),
- .reserved = BIT(1) | BIT(2) | BIT(3),
-};
-
-static const struct option_blacklist_info cinterion_rmnet2_blacklist = {
- .reserved = BIT(4) | BIT(5),
-};
-
-static const struct option_blacklist_info yuga_clm920_nc5_blacklist = {
- .reserved = BIT(1) | BIT(4),
-};
-
-static const struct option_blacklist_info quectel_ep06_blacklist = {
- .reserved = BIT(4) | BIT(5),
-};
static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
@@ -726,26 +590,26 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GKE) },
{ USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) },
{ USB_DEVICE(QUANTA_VENDOR_ID, 0xea42),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, USB_CLASS_COMM, 0x02, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c1f, USB_CLASS_COMM, 0x02, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t) &net_intf1_blacklist },
+ .driver_info = RSVD(1) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S6, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t) &net_intf1_blacklist },
+ .driver_info = RSVD(1) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1750, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t) &net_intf2_blacklist },
+ .driver_info = RSVD(2) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1441, USB_CLASS_COMM, 0x02, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1442, USB_CLASS_COMM, 0x02, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
+ .driver_info = RSVD(1) | RSVD(2) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
+ .driver_info = RSVD(1) | RSVD(2) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x14ac, 0xff, 0xff, 0xff), /* Huawei E1820 */
- .driver_info = (kernel_ulong_t) &net_intf1_blacklist },
+ .driver_info = RSVD(1) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
+ .driver_info = RSVD(1) | RSVD(2) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0xff, 0xff) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x01) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x02) },
@@ -1190,67 +1054,67 @@ static const struct usb_device_id option_ids[] = {
{ 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 },
+ .driver_info = RSVD(3) },
{ 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 */
/* Quectel products using Qualcomm vendor ID */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)},
{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
/* Yuga products use Qualcomm vendor ID */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, YUGA_PRODUCT_CLM920_NC5),
- .driver_info = (kernel_ulong_t)&yuga_clm920_nc5_blacklist },
+ .driver_info = RSVD(1) | RSVD(4) },
/* Quectel products using Quectel vendor ID */
{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC21),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC25),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06),
- .driver_info = (kernel_ulong_t)&quectel_ep06_blacklist },
+ .driver_info = RSVD(4) | RSVD(5) },
{ 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),
- .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ .driver_info = RSVD(0) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6004) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6005) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CGU_628A) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHE_628S),
- .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ .driver_info = RSVD(0) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_301),
- .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ .driver_info = RSVD(0) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_628),
- .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ .driver_info = RSVD(0) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_628S) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU_680) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU_685A) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_720S),
- .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ .driver_info = RSVD(0) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7002),
- .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ .driver_info = RSVD(0) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_629K),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7004),
- .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+ .driver_info = RSVD(3) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7005) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CGU_629),
- .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+ .driver_info = RSVD(5) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_629S),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_720I),
- .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ .driver_info = RSVD(0) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7212),
- .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ .driver_info = RSVD(0) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7213),
- .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ .driver_info = RSVD(0) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7251),
- .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+ .driver_info = RSVD(1) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7252),
- .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+ .driver_info = RSVD(1) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7253),
- .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+ .driver_info = RSVD(1) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) },
@@ -1258,38 +1122,38 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0),
- .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 },
+ .driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG1),
- .driver_info = (kernel_ulong_t)&telit_le910_blacklist },
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG2),
- .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 },
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG3),
- .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 },
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff),
- .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 },
+ .driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910),
- .driver_info = (kernel_ulong_t)&telit_me910_blacklist },
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM),
- .driver_info = (kernel_ulong_t)&telit_me910_dual_modem_blacklist },
+ .driver_info = NCTRL(0) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
- .driver_info = (kernel_ulong_t)&telit_le910_blacklist },
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4),
- .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 },
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),
- .driver_info = (kernel_ulong_t)&telit_le920_blacklist },
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(5) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1207) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1208),
- .driver_info = (kernel_ulong_t)&telit_le920a4_blacklist_1 },
+ .driver_info = NCTRL(0) | RSVD(1) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1211),
- .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 },
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1212),
- .driver_info = (kernel_ulong_t)&telit_le920a4_blacklist_1 },
+ .driver_info = NCTRL(0) | RSVD(1) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1213, 0xff) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1214),
- .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 },
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+ .driver_info = RSVD(1) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0003, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) },
@@ -1305,58 +1169,58 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0010, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0011, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+ .driver_info = RSVD(1) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0013, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0016, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+ .driver_info = RSVD(3) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+ .driver_info = RSVD(3) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0022, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0023, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0024, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+ .driver_info = RSVD(1) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0028, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0029, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0030, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff,
- 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_mf626_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff, 0xff, 0xff),
+ .driver_info = NCTRL(0) | NCTRL(1) | RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0032, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0033, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0034, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&zte_0037_blacklist },
+ .driver_info = NCTRL(0) | NCTRL(1) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0038, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0039, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0040, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0043, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0044, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0048, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+ .driver_info = RSVD(5) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0050, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0051, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0054, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+ .driver_info = RSVD(1) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0056, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0057, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0061, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0062, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0064, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0065, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0066, 0xff, 0xff, 0xff) },
@@ -1381,26 +1245,26 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0096, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0097, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0105, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0106, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0108, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+ .driver_info = RSVD(5) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0117, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0118, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+ .driver_info = RSVD(5) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0121, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+ .driver_info = RSVD(5) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0122, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0123, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0124, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+ .driver_info = RSVD(5) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0125, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+ .driver_info = RSVD(6) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0126, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+ .driver_info = RSVD(5) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0128, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0135, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0136, 0xff, 0xff, 0xff) },
@@ -1416,50 +1280,50 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0155, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+ .driver_info = RSVD(5) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+ .driver_info = RSVD(3) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0159, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0164, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0189, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0191, 0xff, 0xff, 0xff), /* ZTE EuFi890 */
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0196, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0197, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0199, 0xff, 0xff, 0xff), /* ZTE MF820S */
- .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+ .driver_info = RSVD(1) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0200, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0201, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0254, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0257, 0xff, 0xff, 0xff), /* ZTE MF821 */
- .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+ .driver_info = RSVD(3) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0265, 0xff, 0xff, 0xff), /* ONDA MT8205 */
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0284, 0xff, 0xff, 0xff), /* ZTE MF880 */
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0317, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0326, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0330, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0395, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0412, 0xff, 0xff, 0xff), /* Telewell TW-LTE 4G */
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0414, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0417, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1018, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1021, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+ .driver_info = RSVD(2) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) },
@@ -1576,23 +1440,23 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1170, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1244, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1245, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1246, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1247, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1248, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1249, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1250, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1251, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1252, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1253, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1254, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1255, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&zte_1255_blacklist },
+ .driver_info = RSVD(3) | RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1256, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1257, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1258, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1259, 0xff, 0xff, 0xff) },
@@ -1607,7 +1471,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1268, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1269, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+ .driver_info = RSVD(5) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1271, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1272, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 0xff, 0xff, 0xff) },
@@ -1643,17 +1507,17 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1303, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1333, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1401, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+ .driver_info = RSVD(2) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+ .driver_info = RSVD(2) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1424, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+ .driver_info = RSVD(2) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1425, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+ .driver_info = RSVD(2) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1426, 0xff, 0xff, 0xff), /* ZTE MF91 */
- .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+ .driver_info = RSVD(2) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1428, 0xff, 0xff, 0xff), /* Telewell TW-LTE 4G v2 */
- .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+ .driver_info = RSVD(2) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1533, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1534, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1535, 0xff, 0xff, 0xff) },
@@ -1671,8 +1535,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1596, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1598, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1600, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff,
- 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, 0xff, 0xff),
+ .driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) | RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */
@@ -1683,20 +1547,20 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0094, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0130, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+ .driver_info = RSVD(1) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0133, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+ .driver_info = RSVD(3) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0141, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+ .driver_info = RSVD(5) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0147, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0168, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0170, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0176, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+ .driver_info = RSVD(3) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+ .driver_info = RSVD(3) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff42, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff43, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff44, 0xff, 0xff, 0xff) },
@@ -1848,19 +1712,19 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&zte_mc2718_z_blacklist },
+ .driver_info = NCTRL(1) | NCTRL(2) | NCTRL(3) | NCTRL(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AD3812, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist },
+ .driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist },
+ .driver_info = NCTRL(1) | NCTRL(2) | NCTRL(3) },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_L),
- .driver_info = (kernel_ulong_t)&zte_me3620_xl_blacklist },
+ .driver_info = RSVD(3) | RSVD(4) | RSVD(5) },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_MBIM),
- .driver_info = (kernel_ulong_t)&zte_me3620_mbim_blacklist },
+ .driver_info = RSVD(2) | RSVD(3) | RSVD(4) },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ME3620_X),
- .driver_info = (kernel_ulong_t)&zte_me3620_xl_blacklist },
+ .driver_info = RSVD(3) | RSVD(4) | RSVD(5) },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_ZM8620_X),
- .driver_info = (kernel_ulong_t)&zte_zm8620_x_blacklist },
+ .driver_info = RSVD(3) | RSVD(4) | RSVD(5) },
{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) },
{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) },
{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) },
@@ -1880,37 +1744,34 @@ static const struct usb_device_id option_ids[] = {
{ 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 },
+ .driver_info = RSVD(5) | RSVD(6) },
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200),
- .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist
- },
+ .driver_info = NCTRL(0) | NCTRL(1) | RSVD(4) },
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D),
- .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+ .driver_info = RSVD(6) },
{ USB_DEVICE(ALCATEL_VENDOR_ID, 0x0052),
- .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+ .driver_info = RSVD(6) },
{ USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b6),
- .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+ .driver_info = RSVD(3) },
{ USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b7),
- .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+ .driver_info = RSVD(5) },
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L100V),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L800MA),
- .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+ .driver_info = RSVD(2) },
{ USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
{ USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
- .driver_info = (kernel_ulong_t)&four_g_w14_blacklist
- },
+ .driver_info = NCTRL(0) | NCTRL(1) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W100),
- .driver_info = (kernel_ulong_t)&four_g_w100_blacklist
- },
+ .driver_info = NCTRL(1) | NCTRL(2) | RSVD(3) },
{USB_DEVICE(LONGCHEER_VENDOR_ID, FUJISOFT_PRODUCT_FS040U),
- .driver_info = (kernel_ulong_t)&net_intf3_blacklist},
+ .driver_info = RSVD(3)},
{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) },
{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, 0x9801, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+ .driver_info = RSVD(3) },
{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, 0x9803, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) },
{ USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) },
@@ -1936,14 +1797,14 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX, 0xff) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8_2RMNET, 0xff),
- .driver_info = (kernel_ulong_t)&cinterion_rmnet2_blacklist },
+ .driver_info = RSVD(4) | RSVD(5) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8_AUDIO, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_2RMNET, 0xff) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_AUDIO, 0xff) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) },
@@ -1953,20 +1814,20 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, /* HC28 enumerates with Siemens or Cinterion VID depending on FW revision */
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD120),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD140),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) },
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD155),
- .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+ .driver_info = RSVD(6) },
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200),
- .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+ .driver_info = RSVD(6) },
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD160),
- .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+ .driver_info = RSVD(6) },
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD500),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/
{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) },
@@ -2043,9 +1904,9 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600E) },
{ USB_DEVICE_AND_INTERFACE_INFO(TPLINK_VENDOR_ID, TPLINK_PRODUCT_LTE, 0xff, 0x00, 0x00) }, /* TP-Link LTE Module */
{ USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180),
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE(TPLINK_VENDOR_ID, 0x9000), /* TP-Link MA260 */
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) },
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d01, 0xff) }, /* D-Link DWM-156 (variant) */
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d02, 0xff) },
@@ -2053,9 +1914,9 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d04, 0xff) }, /* D-Link DWM-158 */
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d0e, 0xff) }, /* D-Link DWM-157 C1 */
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e19, 0xff), /* D-Link DWM-221 B1 */
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e35, 0xff), /* D-Link DWM-222 */
- .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ .driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x7e11, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/A3 */
@@ -2114,11 +1975,10 @@ static int option_probe(struct usb_serial *serial,
{
struct usb_interface_descriptor *iface_desc =
&serial->interface->cur_altsetting->desc;
- struct usb_device_descriptor *dev_desc = &serial->dev->descriptor;
- const struct option_blacklist_info *blacklist;
+ unsigned long device_flags = id->driver_info;
/* Never bind to the CD-Rom emulation interface */
- if (iface_desc->bInterfaceClass == 0x08)
+ if (iface_desc->bInterfaceClass == USB_CLASS_MASS_STORAGE)
return -ENODEV;
/*
@@ -2126,21 +1986,11 @@ static int option_probe(struct usb_serial *serial,
* the same class/subclass/protocol as the serial interfaces. Look at
* the Windows driver .INF files for reserved interface numbers.
*/
- blacklist = (void *)id->driver_info;
- if (blacklist && test_bit(iface_desc->bInterfaceNumber,
- &blacklist->reserved))
- return -ENODEV;
- /*
- * Don't bind network interface on Samsung GT-B3730, it is handled by
- * a separate module.
- */
- if (dev_desc->idVendor == cpu_to_le16(SAMSUNG_VENDOR_ID) &&
- dev_desc->idProduct == cpu_to_le16(SAMSUNG_PRODUCT_GT_B3730) &&
- iface_desc->bInterfaceClass != USB_CLASS_CDC_DATA)
+ if (device_flags & RSVD(iface_desc->bInterfaceNumber))
return -ENODEV;
- /* Store the blacklist info so we can use it during attach. */
- usb_set_serial_data(serial, (void *)blacklist);
+ /* Store the device flags so we can use them during attach. */
+ usb_set_serial_data(serial, (void *)device_flags);
return 0;
}
@@ -2148,22 +1998,21 @@ static int option_probe(struct usb_serial *serial,
static int option_attach(struct usb_serial *serial)
{
struct usb_interface_descriptor *iface_desc;
- const struct option_blacklist_info *blacklist;
struct usb_wwan_intf_private *data;
+ unsigned long device_flags;
data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
if (!data)
return -ENOMEM;
- /* Retrieve blacklist info stored at probe. */
- blacklist = usb_get_serial_data(serial);
+ /* Retrieve device flags stored at probe. */
+ device_flags = (unsigned long)usb_get_serial_data(serial);
iface_desc = &serial->interface->cur_altsetting->desc;
- if (!blacklist || !test_bit(iface_desc->bInterfaceNumber,
- &blacklist->sendsetup)) {
+ if (!(device_flags & NCTRL(iface_desc->bInterfaceNumber)))
data->use_send_setup = 1;
- }
+
spin_lock_init(&data->susp_lock);
usb_set_serial_data(serial, data);
diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig
index bcb2744c5977..030f88cb0c3f 100644
--- a/drivers/usb/typec/Kconfig
+++ b/drivers/usb/typec/Kconfig
@@ -48,6 +48,7 @@ if TYPEC
config TYPEC_TCPM
tristate "USB Type-C Port Controller Manager"
depends on USB
+ select USB_ROLE_SWITCH
help
The Type-C Port Controller Manager provides a USB PD and USB Type-C
state machine for use with Type-C Port Controllers.
@@ -84,4 +85,6 @@ config TYPEC_TPS6598X
If you choose to build this driver as a dynamically linked module, the
module will be called tps6598x.ko.
+source "drivers/usb/typec/mux/Kconfig"
+
endif # TYPEC
diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile
index bb3138a6eaac..1f599a6c30cc 100644
--- a/drivers/usb/typec/Makefile
+++ b/drivers/usb/typec/Makefile
@@ -1,7 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_TYPEC) += typec.o
+typec-y := class.o mux.o
obj-$(CONFIG_TYPEC_TCPM) += tcpm.o
obj-y += fusb302/
obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o
obj-$(CONFIG_TYPEC_UCSI) += ucsi/
obj-$(CONFIG_TYPEC_TPS6598X) += tps6598x.o
+obj-$(CONFIG_TYPEC) += mux/
diff --git a/drivers/usb/typec/typec.c b/drivers/usb/typec/class.c
index 735726ced602..53df10df2f9d 100644
--- a/drivers/usb/typec/typec.c
+++ b/drivers/usb/typec/class.c
@@ -11,6 +11,7 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/usb/typec.h>
+#include <linux/usb/typec_mux.h>
struct typec_mode {
int index;
@@ -70,6 +71,10 @@ struct typec_port {
enum typec_port_type port_type;
struct mutex port_type_lock;
+ enum typec_orientation orientation;
+ struct typec_switch *sw;
+ struct typec_mux *mux;
+
const struct typec_capability *cap;
};
@@ -92,6 +97,7 @@ static const struct device_type typec_port_dev_type;
static DEFINE_IDA(typec_index_ida);
static struct class *typec_class;
+/* ------------------------------------------------------------------------- */
/* Common attributes */
static const char * const typec_accessory_modes[] = {
@@ -276,10 +282,10 @@ typec_altmode_roles_show(struct device *dev, struct device_attribute *attr,
ssize_t ret;
switch (mode->roles) {
- case TYPEC_PORT_DFP:
+ case TYPEC_PORT_SRC:
ret = sprintf(buf, "source\n");
break;
- case TYPEC_PORT_UFP:
+ case TYPEC_PORT_SNK:
ret = sprintf(buf, "sink\n");
break;
case TYPEC_PORT_DRP:
@@ -386,7 +392,7 @@ typec_register_altmode(struct device *parent,
alt = kzalloc(sizeof(*alt), GFP_KERNEL);
if (!alt)
- return NULL;
+ return ERR_PTR(-ENOMEM);
alt->svid = desc->svid;
alt->n_modes = desc->n_modes;
@@ -402,7 +408,7 @@ typec_register_altmode(struct device *parent,
dev_err(parent, "failed to register alternate mode (%d)\n",
ret);
put_device(&alt->dev);
- return NULL;
+ return ERR_PTR(ret);
}
return alt;
@@ -417,7 +423,7 @@ typec_register_altmode(struct device *parent,
*/
void typec_unregister_altmode(struct typec_altmode *alt)
{
- if (alt)
+ if (!IS_ERR_OR_NULL(alt))
device_unregister(&alt->dev);
}
EXPORT_SYMBOL_GPL(typec_unregister_altmode);
@@ -509,7 +515,7 @@ EXPORT_SYMBOL_GPL(typec_partner_register_altmode);
*
* Registers a device for USB Type-C Partner described in @desc.
*
- * Returns handle to the partner on success or NULL on failure.
+ * Returns handle to the partner on success or ERR_PTR on failure.
*/
struct typec_partner *typec_register_partner(struct typec_port *port,
struct typec_partner_desc *desc)
@@ -519,7 +525,7 @@ struct typec_partner *typec_register_partner(struct typec_port *port,
partner = kzalloc(sizeof(*partner), GFP_KERNEL);
if (!partner)
- return NULL;
+ return ERR_PTR(-ENOMEM);
partner->usb_pd = desc->usb_pd;
partner->accessory = desc->accessory;
@@ -542,7 +548,7 @@ struct typec_partner *typec_register_partner(struct typec_port *port,
if (ret) {
dev_err(&port->dev, "failed to register partner (%d)\n", ret);
put_device(&partner->dev);
- return NULL;
+ return ERR_PTR(ret);
}
return partner;
@@ -557,7 +563,7 @@ EXPORT_SYMBOL_GPL(typec_register_partner);
*/
void typec_unregister_partner(struct typec_partner *partner)
{
- if (partner)
+ if (!IS_ERR_OR_NULL(partner))
device_unregister(&partner->dev);
}
EXPORT_SYMBOL_GPL(typec_unregister_partner);
@@ -587,7 +593,7 @@ static const struct device_type typec_plug_dev_type = {
* the plug lists in response to Discover Modes command need to be listed in an
* array in @desc.
*
- * Returns handle to the alternate mode on success or NULL on failure.
+ * Returns handle to the alternate mode on success or ERR_PTR on failure.
*/
struct typec_altmode *
typec_plug_register_altmode(struct typec_plug *plug,
@@ -606,7 +612,7 @@ EXPORT_SYMBOL_GPL(typec_plug_register_altmode);
* Cable Plug represents a plug with electronics in it that can response to USB
* Power Delivery SOP Prime or SOP Double Prime packages.
*
- * Returns handle to the cable plug on success or NULL on failure.
+ * Returns handle to the cable plug on success or ERR_PTR on failure.
*/
struct typec_plug *typec_register_plug(struct typec_cable *cable,
struct typec_plug_desc *desc)
@@ -617,7 +623,7 @@ struct typec_plug *typec_register_plug(struct typec_cable *cable,
plug = kzalloc(sizeof(*plug), GFP_KERNEL);
if (!plug)
- return NULL;
+ return ERR_PTR(-ENOMEM);
sprintf(name, "plug%d", desc->index);
@@ -631,7 +637,7 @@ struct typec_plug *typec_register_plug(struct typec_cable *cable,
if (ret) {
dev_err(&cable->dev, "failed to register plug (%d)\n", ret);
put_device(&plug->dev);
- return NULL;
+ return ERR_PTR(ret);
}
return plug;
@@ -646,7 +652,7 @@ EXPORT_SYMBOL_GPL(typec_register_plug);
*/
void typec_unregister_plug(struct typec_plug *plug)
{
- if (plug)
+ if (!IS_ERR_OR_NULL(plug))
device_unregister(&plug->dev);
}
EXPORT_SYMBOL_GPL(typec_unregister_plug);
@@ -724,7 +730,7 @@ EXPORT_SYMBOL_GPL(typec_cable_set_identity);
* Registers a device for USB Type-C Cable described in @desc. The cable will be
* parent for the optional cable plug devises.
*
- * Returns handle to the cable on success or NULL on failure.
+ * Returns handle to the cable on success or ERR_PTR on failure.
*/
struct typec_cable *typec_register_cable(struct typec_port *port,
struct typec_cable_desc *desc)
@@ -734,7 +740,7 @@ struct typec_cable *typec_register_cable(struct typec_port *port,
cable = kzalloc(sizeof(*cable), GFP_KERNEL);
if (!cable)
- return NULL;
+ return ERR_PTR(-ENOMEM);
cable->type = desc->type;
cable->active = desc->active;
@@ -757,7 +763,7 @@ struct typec_cable *typec_register_cable(struct typec_port *port,
if (ret) {
dev_err(&port->dev, "failed to register cable (%d)\n", ret);
put_device(&cable->dev);
- return NULL;
+ return ERR_PTR(ret);
}
return cable;
@@ -772,7 +778,7 @@ EXPORT_SYMBOL_GPL(typec_register_cable);
*/
void typec_unregister_cable(struct typec_cable *cable)
{
- if (cable)
+ if (!IS_ERR_OR_NULL(cable))
device_unregister(&cable->dev);
}
EXPORT_SYMBOL_GPL(typec_unregister_cable);
@@ -791,14 +797,14 @@ static const char * const typec_data_roles[] = {
};
static const char * const typec_port_types[] = {
- [TYPEC_PORT_DFP] = "source",
- [TYPEC_PORT_UFP] = "sink",
+ [TYPEC_PORT_SRC] = "source",
+ [TYPEC_PORT_SNK] = "sink",
[TYPEC_PORT_DRP] = "dual",
};
static const char * const typec_port_types_drp[] = {
- [TYPEC_PORT_DFP] = "dual [source] sink",
- [TYPEC_PORT_UFP] = "dual source [sink]",
+ [TYPEC_PORT_SRC] = "dual [source] sink",
+ [TYPEC_PORT_SNK] = "dual source [sink]",
[TYPEC_PORT_DRP] = "[dual] source sink",
};
@@ -869,9 +875,7 @@ static ssize_t data_role_store(struct device *dev,
return ret;
mutex_lock(&port->port_type_lock);
- if (port->port_type != TYPEC_PORT_DRP) {
- dev_dbg(dev, "port type fixed at \"%s\"",
- typec_port_types[port->port_type]);
+ if (port->cap->data != TYPEC_PORT_DRD) {
ret = -EOPNOTSUPP;
goto unlock_and_ret;
}
@@ -891,7 +895,7 @@ static ssize_t data_role_show(struct device *dev,
{
struct typec_port *port = to_typec_port(dev);
- if (port->cap->type == TYPEC_PORT_DRP)
+ if (port->cap->data == TYPEC_PORT_DRD)
return sprintf(buf, "%s\n", port->data_role == TYPEC_HOST ?
"[host] device" : "host [device]");
@@ -1137,6 +1141,8 @@ static void typec_release(struct device *dev)
struct typec_port *port = to_typec_port(dev);
ida_simple_remove(&typec_index_ida, port->id);
+ typec_switch_put(port->sw);
+ typec_mux_put(port->mux);
kfree(port);
}
@@ -1246,6 +1252,47 @@ void typec_set_pwr_opmode(struct typec_port *port,
}
EXPORT_SYMBOL_GPL(typec_set_pwr_opmode);
+/* ------------------------------------------ */
+/* API for Multiplexer/DeMultiplexer Switches */
+
+/**
+ * typec_set_orientation - Set USB Type-C cable plug orientation
+ * @port: USB Type-C Port
+ * @orientation: USB Type-C cable plug orientation
+ *
+ * Set cable plug orientation for @port.
+ */
+int typec_set_orientation(struct typec_port *port,
+ enum typec_orientation orientation)
+{
+ int ret;
+
+ if (port->sw) {
+ ret = port->sw->set(port->sw, orientation);
+ if (ret)
+ return ret;
+ }
+
+ port->orientation = orientation;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(typec_set_orientation);
+
+/**
+ * typec_set_mode - Set mode of operation for USB Type-C connector
+ * @port: USB Type-C port for the connector
+ * @mode: Operation mode for the connector
+ *
+ * Set mode @mode for @port. This function will configure the muxes needed to
+ * enter @mode.
+ */
+int typec_set_mode(struct typec_port *port, int mode)
+{
+ return port->mux ? port->mux->set(port->mux, mode) : 0;
+}
+EXPORT_SYMBOL_GPL(typec_set_mode);
+
/* --------------------------------------- */
/**
@@ -1256,7 +1303,7 @@ EXPORT_SYMBOL_GPL(typec_set_pwr_opmode);
* This routine is used to register an alternate mode that @port is capable of
* supporting.
*
- * Returns handle to the alternate mode on success or NULL on failure.
+ * Returns handle to the alternate mode on success or ERR_PTR on failure.
*/
struct typec_altmode *
typec_port_register_altmode(struct typec_port *port,
@@ -1273,41 +1320,67 @@ EXPORT_SYMBOL_GPL(typec_port_register_altmode);
*
* Registers a device for USB Type-C Port described in @cap.
*
- * Returns handle to the port on success or NULL on failure.
+ * Returns handle to the port on success or ERR_PTR on failure.
*/
struct typec_port *typec_register_port(struct device *parent,
const struct typec_capability *cap)
{
struct typec_port *port;
- int role;
int ret;
int id;
port = kzalloc(sizeof(*port), GFP_KERNEL);
if (!port)
- return NULL;
+ return ERR_PTR(-ENOMEM);
id = ida_simple_get(&typec_index_ida, 0, 0, GFP_KERNEL);
if (id < 0) {
kfree(port);
- return NULL;
+ return ERR_PTR(id);
}
- if (cap->type == TYPEC_PORT_DFP)
- role = TYPEC_SOURCE;
- else if (cap->type == TYPEC_PORT_UFP)
- role = TYPEC_SINK;
- else
- role = cap->prefer_role;
+ port->sw = typec_switch_get(cap->fwnode ? &port->dev : parent);
+ if (IS_ERR(port->sw)) {
+ ret = PTR_ERR(port->sw);
+ goto err_switch;
+ }
- if (role == TYPEC_SOURCE) {
- port->data_role = TYPEC_HOST;
+ port->mux = typec_mux_get(cap->fwnode ? &port->dev : parent);
+ if (IS_ERR(port->mux)) {
+ ret = PTR_ERR(port->mux);
+ goto err_mux;
+ }
+
+ switch (cap->type) {
+ case TYPEC_PORT_SRC:
port->pwr_role = TYPEC_SOURCE;
port->vconn_role = TYPEC_SOURCE;
- } else {
- port->data_role = TYPEC_DEVICE;
+ break;
+ case TYPEC_PORT_SNK:
port->pwr_role = TYPEC_SINK;
port->vconn_role = TYPEC_SINK;
+ break;
+ case TYPEC_PORT_DRP:
+ if (cap->prefer_role != TYPEC_NO_PREFERRED_ROLE)
+ port->pwr_role = cap->prefer_role;
+ else
+ port->pwr_role = TYPEC_SINK;
+ break;
+ }
+
+ switch (cap->data) {
+ case TYPEC_PORT_DFP:
+ port->data_role = TYPEC_HOST;
+ break;
+ case TYPEC_PORT_UFP:
+ port->data_role = TYPEC_DEVICE;
+ break;
+ case TYPEC_PORT_DRD:
+ if (cap->prefer_role == TYPEC_SOURCE)
+ port->data_role = TYPEC_HOST;
+ else
+ port->data_role = TYPEC_DEVICE;
+ break;
}
port->id = id;
@@ -1326,10 +1399,19 @@ struct typec_port *typec_register_port(struct device *parent,
if (ret) {
dev_err(parent, "failed to register port (%d)\n", ret);
put_device(&port->dev);
- return NULL;
+ return ERR_PTR(ret);
}
return port;
+
+err_mux:
+ typec_switch_put(port->sw);
+
+err_switch:
+ ida_simple_remove(&typec_index_ida, port->id);
+ kfree(port);
+
+ return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(typec_register_port);
@@ -1341,7 +1423,7 @@ EXPORT_SYMBOL_GPL(typec_register_port);
*/
void typec_unregister_port(struct typec_port *port)
{
- if (port)
+ if (!IS_ERR_OR_NULL(port))
device_unregister(&port->dev);
}
EXPORT_SYMBOL_GPL(typec_unregister_port);
diff --git a/drivers/usb/typec/fusb302/fusb302.c b/drivers/usb/typec/fusb302/fusb302.c
index dcd8ef085b30..703617129067 100644
--- a/drivers/usb/typec/fusb302/fusb302.c
+++ b/drivers/usb/typec/fusb302/fusb302.c
@@ -199,7 +199,7 @@ static void fusb302_log(struct fusb302_chip *chip, const char *fmt, ...)
va_end(args);
}
-static int fusb302_seq_show(struct seq_file *s, void *v)
+static int fusb302_debug_show(struct seq_file *s, void *v)
{
struct fusb302_chip *chip = (struct fusb302_chip *)s->private;
int tail;
@@ -216,18 +216,7 @@ static int fusb302_seq_show(struct seq_file *s, void *v)
return 0;
}
-
-static int fusb302_debug_open(struct inode *inode, struct file *file)
-{
- return single_open(file, fusb302_seq_show, inode->i_private);
-}
-
-static const struct file_operations fusb302_debug_operations = {
- .open = fusb302_debug_open,
- .llseek = seq_lseek,
- .read = seq_read,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(fusb302_debug);
static struct dentry *rootdir;
@@ -242,7 +231,7 @@ static int fusb302_debugfs_init(struct fusb302_chip *chip)
chip->dentry = debugfs_create_file(dev_name(chip->dev),
S_IFREG | 0444, rootdir,
- chip, &fusb302_debug_operations);
+ chip, &fusb302_debug_fops);
return 0;
}
@@ -1230,6 +1219,7 @@ static const struct tcpc_config fusb302_tcpc_config = {
.max_snk_mw = 15000,
.operating_snk_mw = 2500,
.type = TYPEC_PORT_DRP,
+ .data = TYPEC_PORT_DRD,
.default_role = TYPEC_SINK,
.alt_modes = NULL,
};
@@ -1249,7 +1239,6 @@ static void init_tcpc_dev(struct tcpc_dev *fusb302_tcpc_dev)
fusb302_tcpc_dev->set_roles = tcpm_set_roles;
fusb302_tcpc_dev->start_drp_toggling = tcpm_start_drp_toggling;
fusb302_tcpc_dev->pd_transmit = tcpm_pd_transmit;
- fusb302_tcpc_dev->mux = NULL;
}
static const char * const cc_polarity_name[] = {
diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c
new file mode 100644
index 000000000000..f89093bd7185
--- /dev/null
+++ b/drivers/usb/typec/mux.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * USB Type-C Multiplexer/DeMultiplexer Switch support
+ *
+ * Copyright (C) 2018 Intel Corporation
+ * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+ * Hans de Goede <hdegoede@redhat.com>
+ */
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/usb/typec_mux.h>
+
+static DEFINE_MUTEX(switch_lock);
+static DEFINE_MUTEX(mux_lock);
+static LIST_HEAD(switch_list);
+static LIST_HEAD(mux_list);
+
+static void *typec_switch_match(struct device_connection *con, int ep,
+ void *data)
+{
+ struct typec_switch *sw;
+
+ list_for_each_entry(sw, &switch_list, entry)
+ if (!strcmp(con->endpoint[ep], dev_name(sw->dev)))
+ return sw;
+
+ /*
+ * We only get called if a connection was found, tell the caller to
+ * wait for the switch to show up.
+ */
+ return ERR_PTR(-EPROBE_DEFER);
+}
+
+/**
+ * typec_switch_get - Find USB Type-C orientation switch
+ * @dev: The caller device
+ *
+ * Finds a switch linked with @dev. Returns a reference to the switch on
+ * success, NULL if no matching connection was found, or
+ * ERR_PTR(-EPROBE_DEFER) when a connection was found but the switch
+ * has not been enumerated yet.
+ */
+struct typec_switch *typec_switch_get(struct device *dev)
+{
+ struct typec_switch *sw;
+
+ mutex_lock(&switch_lock);
+ sw = device_connection_find_match(dev, "typec-switch", NULL,
+ typec_switch_match);
+ if (!IS_ERR_OR_NULL(sw))
+ get_device(sw->dev);
+ mutex_unlock(&switch_lock);
+
+ return sw;
+}
+EXPORT_SYMBOL_GPL(typec_switch_get);
+
+/**
+ * typec_put_switch - Release USB Type-C orientation switch
+ * @sw: USB Type-C orientation switch
+ *
+ * Decrement reference count for @sw.
+ */
+void typec_switch_put(struct typec_switch *sw)
+{
+ if (!IS_ERR_OR_NULL(sw))
+ put_device(sw->dev);
+}
+EXPORT_SYMBOL_GPL(typec_switch_put);
+
+/**
+ * typec_switch_register - Register USB Type-C orientation switch
+ * @sw: USB Type-C orientation switch
+ *
+ * This function registers a switch that can be used for routing the correct
+ * data pairs depending on the cable plug orientation from the USB Type-C
+ * connector to the USB controllers. USB Type-C plugs can be inserted
+ * right-side-up or upside-down.
+ */
+int typec_switch_register(struct typec_switch *sw)
+{
+ mutex_lock(&switch_lock);
+ list_add_tail(&sw->entry, &switch_list);
+ mutex_unlock(&switch_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(typec_switch_register);
+
+/**
+ * typec_switch_unregister - Unregister USB Type-C orientation switch
+ * @sw: USB Type-C orientation switch
+ *
+ * Unregister switch that was registered with typec_switch_register().
+ */
+void typec_switch_unregister(struct typec_switch *sw)
+{
+ mutex_lock(&switch_lock);
+ list_del(&sw->entry);
+ mutex_unlock(&switch_lock);
+}
+EXPORT_SYMBOL_GPL(typec_switch_unregister);
+
+/* ------------------------------------------------------------------------- */
+
+static void *typec_mux_match(struct device_connection *con, int ep, void *data)
+{
+ struct typec_mux *mux;
+
+ list_for_each_entry(mux, &mux_list, entry)
+ if (!strcmp(con->endpoint[ep], dev_name(mux->dev)))
+ return mux;
+
+ /*
+ * We only get called if a connection was found, tell the caller to
+ * wait for the switch to show up.
+ */
+ return ERR_PTR(-EPROBE_DEFER);
+}
+
+/**
+ * typec_mux_get - Find USB Type-C Multiplexer
+ * @dev: The caller device
+ *
+ * Finds a mux linked to the caller. This function is primarily meant for the
+ * Type-C drivers. Returns a reference to the mux on success, NULL if no
+ * matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a connection
+ * was found but the mux has not been enumerated yet.
+ */
+struct typec_mux *typec_mux_get(struct device *dev)
+{
+ struct typec_mux *mux;
+
+ mutex_lock(&mux_lock);
+ mux = device_connection_find_match(dev, "typec-mux", NULL,
+ typec_mux_match);
+ if (!IS_ERR_OR_NULL(mux))
+ get_device(mux->dev);
+ mutex_unlock(&mux_lock);
+
+ return mux;
+}
+EXPORT_SYMBOL_GPL(typec_mux_get);
+
+/**
+ * typec_mux_put - Release handle to a Multiplexer
+ * @mux: USB Type-C Connector Multiplexer/DeMultiplexer
+ *
+ * Decrements reference count for @mux.
+ */
+void typec_mux_put(struct typec_mux *mux)
+{
+ if (!IS_ERR_OR_NULL(mux))
+ put_device(mux->dev);
+}
+EXPORT_SYMBOL_GPL(typec_mux_put);
+
+/**
+ * typec_mux_register - Register Multiplexer routing USB Type-C pins
+ * @mux: USB Type-C Connector Multiplexer/DeMultiplexer
+ *
+ * USB Type-C connectors can be used for alternate modes of operation besides
+ * USB when Accessory/Alternate Modes are supported. With some of those modes,
+ * the pins on the connector need to be reconfigured. This function registers
+ * multiplexer switches routing the pins on the connector.
+ */
+int typec_mux_register(struct typec_mux *mux)
+{
+ mutex_lock(&mux_lock);
+ list_add_tail(&mux->entry, &mux_list);
+ mutex_unlock(&mux_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(typec_mux_register);
+
+/**
+ * typec_mux_unregister - Unregister Multiplexer Switch
+ * @sw: USB Type-C Connector Multiplexer/DeMultiplexer
+ *
+ * Unregister mux that was registered with typec_mux_register().
+ */
+void typec_mux_unregister(struct typec_mux *mux)
+{
+ mutex_lock(&mux_lock);
+ list_del(&mux->entry);
+ mutex_unlock(&mux_lock);
+}
+EXPORT_SYMBOL_GPL(typec_mux_unregister);
diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig
new file mode 100644
index 000000000000..9a954d2b8d8f
--- /dev/null
+++ b/drivers/usb/typec/mux/Kconfig
@@ -0,0 +1,10 @@
+menu "USB Type-C Multiplexer/DeMultiplexer Switch support"
+
+config TYPEC_MUX_PI3USB30532
+ tristate "Pericom PI3USB30532 Type-C cross switch driver"
+ depends on I2C
+ help
+ Say Y or M if your system has a Pericom PI3USB30532 Type-C cross
+ switch / mux chip found on some devices with a Type-C port.
+
+endmenu
diff --git a/drivers/usb/typec/mux/Makefile b/drivers/usb/typec/mux/Makefile
new file mode 100644
index 000000000000..1332e469b8a0
--- /dev/null
+++ b/drivers/usb/typec/mux/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_TYPEC_MUX_PI3USB30532) += pi3usb30532.o
diff --git a/drivers/usb/typec/mux/pi3usb30532.c b/drivers/usb/typec/mux/pi3usb30532.c
new file mode 100644
index 000000000000..b0e88db60ecf
--- /dev/null
+++ b/drivers/usb/typec/mux/pi3usb30532.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Pericom PI3USB30532 Type-C cross switch / mux driver
+ *
+ * Copyright (c) 2017-2018 Hans de Goede <hdegoede@redhat.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/usb/tcpm.h>
+#include <linux/usb/typec_mux.h>
+
+#define PI3USB30532_CONF 0x00
+
+#define PI3USB30532_CONF_OPEN 0x00
+#define PI3USB30532_CONF_SWAP 0x01
+#define PI3USB30532_CONF_4LANE_DP 0x02
+#define PI3USB30532_CONF_USB3 0x04
+#define PI3USB30532_CONF_USB3_AND_2LANE_DP 0x06
+
+struct pi3usb30532 {
+ struct i2c_client *client;
+ struct mutex lock; /* protects the cached conf register */
+ struct typec_switch sw;
+ struct typec_mux mux;
+ u8 conf;
+};
+
+static int pi3usb30532_set_conf(struct pi3usb30532 *pi, u8 new_conf)
+{
+ int ret = 0;
+
+ if (pi->conf == new_conf)
+ return 0;
+
+ ret = i2c_smbus_write_byte_data(pi->client, PI3USB30532_CONF, new_conf);
+ if (ret) {
+ dev_err(&pi->client->dev, "Error writing conf: %d\n", ret);
+ return ret;
+ }
+
+ pi->conf = new_conf;
+ return 0;
+}
+
+static int pi3usb30532_sw_set(struct typec_switch *sw,
+ enum typec_orientation orientation)
+{
+ struct pi3usb30532 *pi = container_of(sw, struct pi3usb30532, sw);
+ u8 new_conf;
+ int ret;
+
+ mutex_lock(&pi->lock);
+ new_conf = pi->conf;
+
+ switch (orientation) {
+ case TYPEC_ORIENTATION_NONE:
+ new_conf = PI3USB30532_CONF_OPEN;
+ break;
+ case TYPEC_ORIENTATION_NORMAL:
+ new_conf &= ~PI3USB30532_CONF_SWAP;
+ break;
+ case TYPEC_ORIENTATION_REVERSE:
+ new_conf |= PI3USB30532_CONF_SWAP;
+ break;
+ }
+
+ ret = pi3usb30532_set_conf(pi, new_conf);
+ mutex_unlock(&pi->lock);
+
+ return ret;
+}
+
+static int pi3usb30532_mux_set(struct typec_mux *mux, int state)
+{
+ struct pi3usb30532 *pi = container_of(mux, struct pi3usb30532, mux);
+ u8 new_conf;
+ int ret;
+
+ mutex_lock(&pi->lock);
+ new_conf = pi->conf;
+
+ switch (state) {
+ case TYPEC_MUX_NONE:
+ new_conf = PI3USB30532_CONF_OPEN;
+ break;
+ case TYPEC_MUX_USB:
+ new_conf = (new_conf & PI3USB30532_CONF_SWAP) |
+ PI3USB30532_CONF_USB3;
+ break;
+ case TYPEC_MUX_DP:
+ new_conf = (new_conf & PI3USB30532_CONF_SWAP) |
+ PI3USB30532_CONF_4LANE_DP;
+ break;
+ case TYPEC_MUX_DOCK:
+ new_conf = (new_conf & PI3USB30532_CONF_SWAP) |
+ PI3USB30532_CONF_USB3_AND_2LANE_DP;
+ break;
+ }
+
+ ret = pi3usb30532_set_conf(pi, new_conf);
+ mutex_unlock(&pi->lock);
+
+ return ret;
+}
+
+static int pi3usb30532_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct pi3usb30532 *pi;
+ int ret;
+
+ pi = devm_kzalloc(dev, sizeof(*pi), GFP_KERNEL);
+ if (!pi)
+ return -ENOMEM;
+
+ pi->client = client;
+ pi->sw.dev = dev;
+ pi->sw.set = pi3usb30532_sw_set;
+ pi->mux.dev = dev;
+ pi->mux.set = pi3usb30532_mux_set;
+ mutex_init(&pi->lock);
+
+ ret = i2c_smbus_read_byte_data(client, PI3USB30532_CONF);
+ if (ret < 0) {
+ dev_err(dev, "Error reading config register %d\n", ret);
+ return ret;
+ }
+ pi->conf = ret;
+
+ ret = typec_switch_register(&pi->sw);
+ if (ret) {
+ dev_err(dev, "Error registering typec switch: %d\n", ret);
+ return ret;
+ }
+
+ ret = typec_mux_register(&pi->mux);
+ if (ret) {
+ typec_switch_unregister(&pi->sw);
+ dev_err(dev, "Error registering typec mux: %d\n", ret);
+ return ret;
+ }
+
+ i2c_set_clientdata(client, pi);
+ return 0;
+}
+
+static int pi3usb30532_remove(struct i2c_client *client)
+{
+ struct pi3usb30532 *pi = i2c_get_clientdata(client);
+
+ typec_mux_unregister(&pi->mux);
+ typec_switch_unregister(&pi->sw);
+ return 0;
+}
+
+static const struct i2c_device_id pi3usb30532_table[] = {
+ { "pi3usb30532" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pi3usb30532_table);
+
+static struct i2c_driver pi3usb30532_driver = {
+ .driver = {
+ .name = "pi3usb30532",
+ },
+ .probe_new = pi3usb30532_probe,
+ .remove = pi3usb30532_remove,
+ .id_table = pi3usb30532_table,
+};
+
+module_i2c_driver(pi3usb30532_driver);
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Pericom PI3USB30532 Type-C mux driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm.c
index 8b637a4b474b..677d12138dbd 100644
--- a/drivers/usb/typec/tcpm.c
+++ b/drivers/usb/typec/tcpm.c
@@ -20,6 +20,7 @@
#include <linux/usb/pd.h>
#include <linux/usb/pd_bdo.h>
#include <linux/usb/pd_vdo.h>
+#include <linux/usb/role.h>
#include <linux/usb/tcpm.h>
#include <linux/usb/typec.h>
#include <linux/workqueue.h>
@@ -176,6 +177,7 @@ struct tcpm_port {
struct typec_port *typec_port;
struct tcpc_dev *tcpc;
+ struct usb_role_switch *role_sw;
enum typec_role vconn_role;
enum typec_role pwr_role;
@@ -345,7 +347,7 @@ static enum tcpm_state tcpm_default_state(struct tcpm_port *port)
else if (port->tcpc->config->default_role == TYPEC_SINK)
return SNK_UNATTACHED;
/* Fall through to return SRC_UNATTACHED */
- } else if (port->port_type == TYPEC_PORT_UFP) {
+ } else if (port->port_type == TYPEC_PORT_SNK) {
return SNK_UNATTACHED;
}
return SRC_UNATTACHED;
@@ -503,7 +505,7 @@ static void tcpm_log_source_caps(struct tcpm_port *port)
}
}
-static int tcpm_seq_show(struct seq_file *s, void *v)
+static int tcpm_debug_show(struct seq_file *s, void *v)
{
struct tcpm_port *port = (struct tcpm_port *)s->private;
int tail;
@@ -520,18 +522,7 @@ static int tcpm_seq_show(struct seq_file *s, void *v)
return 0;
}
-
-static int tcpm_debug_open(struct inode *inode, struct file *file)
-{
- return single_open(file, tcpm_seq_show, inode->i_private);
-}
-
-static const struct file_operations tcpm_debug_operations = {
- .open = tcpm_debug_open,
- .llseek = seq_lseek,
- .read = seq_read,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(tcpm_debug);
static struct dentry *rootdir;
@@ -547,7 +538,7 @@ static int tcpm_debugfs_init(struct tcpm_port *port)
port->dentry = debugfs_create_file(dev_name(port->dev),
S_IFREG | 0444, rootdir,
- port, &tcpm_debug_operations);
+ port, &tcpm_debug_fops);
return 0;
}
@@ -615,18 +606,25 @@ void tcpm_pd_transmit_complete(struct tcpm_port *port,
EXPORT_SYMBOL_GPL(tcpm_pd_transmit_complete);
static int tcpm_mux_set(struct tcpm_port *port, enum tcpc_mux_mode mode,
- enum tcpc_usb_switch config)
+ enum usb_role usb_role,
+ enum typec_orientation orientation)
{
- int ret = 0;
+ int ret;
- tcpm_log(port, "Requesting mux mode %d, config %d, polarity %d",
- mode, config, port->polarity);
+ tcpm_log(port, "Requesting mux mode %d, usb-role %d, orientation %d",
+ mode, usb_role, orientation);
- if (port->tcpc->mux)
- ret = port->tcpc->mux->set(port->tcpc->mux, mode, config,
- port->polarity);
+ ret = typec_set_orientation(port->typec_port, orientation);
+ if (ret)
+ return ret;
- return ret;
+ if (port->role_sw) {
+ ret = usb_role_switch_set_role(port->role_sw, usb_role);
+ if (ret)
+ return ret;
+ }
+
+ return typec_set_mode(port->typec_port, mode);
}
static int tcpm_set_polarity(struct tcpm_port *port,
@@ -739,14 +737,21 @@ static int tcpm_set_attached_state(struct tcpm_port *port, bool attached)
static int tcpm_set_roles(struct tcpm_port *port, bool attached,
enum typec_role role, enum typec_data_role data)
{
+ enum typec_orientation orientation;
+ enum usb_role usb_role;
int ret;
+ if (port->polarity == TYPEC_POLARITY_CC1)
+ orientation = TYPEC_ORIENTATION_NORMAL;
+ else
+ orientation = TYPEC_ORIENTATION_REVERSE;
+
if (data == TYPEC_HOST)
- ret = tcpm_mux_set(port, TYPEC_MUX_USB,
- TCPC_USB_SWITCH_CONNECT);
+ usb_role = USB_ROLE_HOST;
else
- ret = tcpm_mux_set(port, TYPEC_MUX_NONE,
- TCPC_USB_SWITCH_DISCONNECT);
+ usb_role = USB_ROLE_DEVICE;
+
+ ret = tcpm_mux_set(port, TYPEC_MUX_USB, usb_role, orientation);
if (ret < 0)
return ret;
@@ -1041,7 +1046,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt,
break;
case CMDT_RSP_ACK:
/* silently drop message if we are not connected */
- if (!port->partner)
+ if (IS_ERR_OR_NULL(port->partner))
break;
switch (cmd) {
@@ -2039,7 +2044,8 @@ out_disable_vconn:
out_disable_pd:
port->tcpc->set_pd_rx(port->tcpc, false);
out_disable_mux:
- tcpm_mux_set(port, TYPEC_MUX_NONE, TCPC_USB_SWITCH_DISCONNECT);
+ tcpm_mux_set(port, TYPEC_MUX_NONE, USB_ROLE_NONE,
+ TYPEC_ORIENTATION_NONE);
return ret;
}
@@ -2083,6 +2089,8 @@ static void tcpm_reset_port(struct tcpm_port *port)
tcpm_init_vconn(port);
tcpm_set_current_limit(port, 0, 0);
tcpm_set_polarity(port, TYPEC_POLARITY_CC1);
+ tcpm_mux_set(port, TYPEC_MUX_NONE, USB_ROLE_NONE,
+ TYPEC_ORIENTATION_NONE);
tcpm_set_attached_state(port, false);
port->try_src_count = 0;
port->try_snk_count = 0;
@@ -2133,8 +2141,6 @@ static int tcpm_snk_attach(struct tcpm_port *port)
static void tcpm_snk_detach(struct tcpm_port *port)
{
tcpm_detach(port);
-
- /* XXX: (Dis)connect SuperSpeed mux? */
}
static int tcpm_acc_attach(struct tcpm_port *port)
@@ -2190,7 +2196,7 @@ static inline enum tcpm_state unattached_state(struct tcpm_port *port)
return SRC_UNATTACHED;
else
return SNK_UNATTACHED;
- } else if (port->port_type == TYPEC_PORT_DFP) {
+ } else if (port->port_type == TYPEC_PORT_SRC) {
return SRC_UNATTACHED;
}
@@ -3480,11 +3486,11 @@ static int tcpm_port_type_set(const struct typec_capability *cap,
if (!port->connected) {
tcpm_set_state(port, PORT_RESET, 0);
- } else if (type == TYPEC_PORT_UFP) {
+ } else if (type == TYPEC_PORT_SNK) {
if (!(port->pwr_role == TYPEC_SINK &&
port->data_role == TYPEC_DEVICE))
tcpm_set_state(port, PORT_RESET, 0);
- } else if (type == TYPEC_PORT_DFP) {
+ } else if (type == TYPEC_PORT_SRC) {
if (!(port->pwr_role == TYPEC_SOURCE &&
port->data_role == TYPEC_HOST))
tcpm_set_state(port, PORT_RESET, 0);
@@ -3652,6 +3658,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
port->typec_caps.prefer_role = tcpc->config->default_role;
port->typec_caps.type = tcpc->config->type;
+ port->typec_caps.data = tcpc->config->data;
port->typec_caps.revision = 0x0120; /* Type-C spec release 1.2 */
port->typec_caps.pd_revision = 0x0200; /* USB-PD spec release 2.0 */
port->typec_caps.dr_set = tcpm_dr_set;
@@ -3663,9 +3670,15 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
port->partner_desc.identity = &port->partner_ident;
port->port_type = tcpc->config->type;
+ port->role_sw = usb_role_switch_get(port->dev);
+ if (IS_ERR(port->role_sw)) {
+ err = PTR_ERR(port->role_sw);
+ goto out_destroy_wq;
+ }
+
port->typec_port = typec_register_port(port->dev, &port->typec_caps);
- if (!port->typec_port) {
- err = -ENOMEM;
+ if (IS_ERR(port->typec_port)) {
+ err = PTR_ERR(port->typec_port);
goto out_destroy_wq;
}
@@ -3674,15 +3687,17 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
i = 0;
while (paltmode->svid && i < ARRAY_SIZE(port->port_altmode)) {
- port->port_altmode[i] =
- typec_port_register_altmode(port->typec_port,
- paltmode);
- if (!port->port_altmode[i]) {
+ struct typec_altmode *alt;
+
+ alt = typec_port_register_altmode(port->typec_port,
+ paltmode);
+ if (IS_ERR(alt)) {
tcpm_log(port,
"%s: failed to register port alternate mode 0x%x",
dev_name(dev), paltmode->svid);
break;
}
+ port->port_altmode[i] = alt;
i++;
paltmode++;
}
@@ -3696,6 +3711,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
return port;
out_destroy_wq:
+ usb_role_switch_put(port->role_sw);
destroy_workqueue(port->wq);
return ERR_PTR(err);
}
diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tps6598x.c
index 2719f5d382f7..8b8406867c02 100644
--- a/drivers/usb/typec/tps6598x.c
+++ b/drivers/usb/typec/tps6598x.c
@@ -158,15 +158,15 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status)
desc.identity = &tps->partner_identity;
}
- tps->partner = typec_register_partner(tps->port, &desc);
- if (!tps->partner)
- return -ENODEV;
-
typec_set_pwr_opmode(tps->port, mode);
typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status));
typec_set_vconn_role(tps->port, TPS_STATUS_VCONN(status));
typec_set_data_role(tps->port, TPS_STATUS_DATAROLE(status));
+ tps->partner = typec_register_partner(tps->port, &desc);
+ if (IS_ERR(tps->partner))
+ return PTR_ERR(tps->partner);
+
if (desc.identity)
typec_partner_set_identity(tps->partner);
@@ -175,7 +175,8 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status)
static void tps6598x_disconnect(struct tps6598x *tps, u32 status)
{
- typec_unregister_partner(tps->partner);
+ if (!IS_ERR(tps->partner))
+ typec_unregister_partner(tps->partner);
tps->partner = NULL;
typec_set_pwr_opmode(tps->port, TYPEC_PWR_MODE_USB);
typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status));
@@ -392,34 +393,42 @@ static int tps6598x_probe(struct i2c_client *client)
if (ret < 0)
return ret;
+ tps->typec_cap.revision = USB_TYPEC_REV_1_2;
+ tps->typec_cap.pd_revision = 0x200;
+ tps->typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE;
+ tps->typec_cap.pr_set = tps6598x_pr_set;
+ tps->typec_cap.dr_set = tps6598x_dr_set;
+
switch (TPS_SYSCONF_PORTINFO(conf)) {
case TPS_PORTINFO_SINK_ACCESSORY:
case TPS_PORTINFO_SINK:
- tps->typec_cap.type = TYPEC_PORT_UFP;
+ tps->typec_cap.type = TYPEC_PORT_SNK;
+ tps->typec_cap.data = TYPEC_PORT_UFP;
break;
case TPS_PORTINFO_DRP_UFP_DRD:
case TPS_PORTINFO_DRP_DFP_DRD:
- tps->typec_cap.dr_set = tps6598x_dr_set;
- /* fall through */
+ tps->typec_cap.type = TYPEC_PORT_DRP;
+ tps->typec_cap.data = TYPEC_PORT_DRD;
+ break;
case TPS_PORTINFO_DRP_UFP:
+ tps->typec_cap.type = TYPEC_PORT_DRP;
+ tps->typec_cap.data = TYPEC_PORT_UFP;
+ break;
case TPS_PORTINFO_DRP_DFP:
- tps->typec_cap.pr_set = tps6598x_pr_set;
tps->typec_cap.type = TYPEC_PORT_DRP;
+ tps->typec_cap.data = TYPEC_PORT_DFP;
break;
case TPS_PORTINFO_SOURCE:
- tps->typec_cap.type = TYPEC_PORT_DFP;
+ tps->typec_cap.type = TYPEC_PORT_SRC;
+ tps->typec_cap.data = TYPEC_PORT_DFP;
break;
default:
return -ENODEV;
}
- tps->typec_cap.revision = USB_TYPEC_REV_1_2;
- tps->typec_cap.pd_revision = 0x200;
- tps->typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE;
-
tps->port = typec_register_port(&client->dev, &tps->typec_cap);
- if (!tps->port)
- return -ENODEV;
+ if (IS_ERR(tps->port))
+ return PTR_ERR(tps->port);
if (status & TPS_STATUS_PLUG_PRESENT) {
ret = tps6598x_connect(tps, status);
diff --git a/drivers/usb/typec/typec_wcove.c b/drivers/usb/typec/typec_wcove.c
index 2e990e0d917d..19cca7f1b2c5 100644
--- a/drivers/usb/typec/typec_wcove.c
+++ b/drivers/usb/typec/typec_wcove.c
@@ -572,6 +572,7 @@ static struct tcpc_config wcove_typec_config = {
.operating_snk_mw = 15000,
.type = TYPEC_PORT_DRP,
+ .data = TYPEC_PORT_DRD,
.default_role = TYPEC_SINK,
};
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 79046fe66426..bf0977fbd100 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -260,38 +260,45 @@ static void ucsi_pwr_opmode_change(struct ucsi_connector *con)
static int ucsi_register_partner(struct ucsi_connector *con)
{
- struct typec_partner_desc partner;
+ struct typec_partner_desc desc;
+ struct typec_partner *partner;
if (con->partner)
return 0;
- memset(&partner, 0, sizeof(partner));
+ memset(&desc, 0, sizeof(desc));
switch (con->status.partner_type) {
case UCSI_CONSTAT_PARTNER_TYPE_DEBUG:
- partner.accessory = TYPEC_ACCESSORY_DEBUG;
+ desc.accessory = TYPEC_ACCESSORY_DEBUG;
break;
case UCSI_CONSTAT_PARTNER_TYPE_AUDIO:
- partner.accessory = TYPEC_ACCESSORY_AUDIO;
+ desc.accessory = TYPEC_ACCESSORY_AUDIO;
break;
default:
break;
}
- partner.usb_pd = con->status.pwr_op_mode == UCSI_CONSTAT_PWR_OPMODE_PD;
+ desc.usb_pd = con->status.pwr_op_mode == UCSI_CONSTAT_PWR_OPMODE_PD;
- con->partner = typec_register_partner(con->port, &partner);
- if (!con->partner) {
- dev_err(con->ucsi->dev, "con%d: failed to register partner\n",
- con->num);
- return -ENODEV;
+ partner = typec_register_partner(con->port, &desc);
+ if (IS_ERR(partner)) {
+ dev_err(con->ucsi->dev,
+ "con%d: failed to register partner (%ld)\n", con->num,
+ PTR_ERR(partner));
+ return PTR_ERR(partner);
}
+ con->partner = partner;
+
return 0;
}
static void ucsi_unregister_partner(struct ucsi_connector *con)
{
+ if (!con->partner)
+ return;
+
typec_unregister_partner(con->partner);
con->partner = NULL;
}
@@ -585,11 +592,18 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
return ret;
if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DRP)
- cap->type = TYPEC_PORT_DRP;
+ cap->data = TYPEC_PORT_DRD;
else if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DFP)
- cap->type = TYPEC_PORT_DFP;
+ cap->data = TYPEC_PORT_DFP;
else if (con->cap.op_mode & UCSI_CONCAP_OPMODE_UFP)
- cap->type = TYPEC_PORT_UFP;
+ cap->data = TYPEC_PORT_UFP;
+
+ if (con->cap.provider && con->cap.consumer)
+ cap->type = TYPEC_PORT_DRP;
+ else if (con->cap.provider)
+ cap->type = TYPEC_PORT_SRC;
+ else if (con->cap.consumer)
+ cap->type = TYPEC_PORT_SNK;
cap->revision = ucsi->cap.typec_version;
cap->pd_revision = ucsi->cap.pd_version;
@@ -606,8 +620,8 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
/* Register the connector */
con->port = typec_register_port(ucsi->dev, cap);
- if (!con->port)
- return -ENODEV;
+ if (IS_ERR(con->port))
+ return PTR_ERR(con->port);
/* Get the status */
UCSI_CMD_GET_CONNECTOR_STATUS(ctrl, con->num);
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 26ca0ec01fd5..c3ddd0f1f449 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -640,4 +640,4 @@ static struct usb_driver skel_driver = {
module_usb_driver(skel_driver);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/usbip/Kconfig b/drivers/usb/usbip/Kconfig
index eeefa29f8aa2..a20b65cb6678 100644
--- a/drivers/usb/usbip/Kconfig
+++ b/drivers/usb/usbip/Kconfig
@@ -27,7 +27,7 @@ config USBIP_VHCI_HCD
config USBIP_VHCI_HC_PORTS
int "Number of ports per USB/IP virtual host controller"
- range 1 31
+ range 1 15
default 8
depends on USBIP_VHCI_HCD
---help---
diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c
index 4c00be2d1993..aff50eb09ca9 100644
--- a/drivers/usb/wusbcore/crypto.c
+++ b/drivers/usb/wusbcore/crypto.c
@@ -202,7 +202,7 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
struct scatterlist sg[4], sg_dst;
void *dst_buf;
size_t dst_size;
- u8 iv[crypto_skcipher_ivsize(tfm_cbc)];
+ u8 *iv;
size_t zero_padding;
/*
@@ -224,7 +224,9 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
if (!dst_buf)
goto error_dst_buf;
- memset(iv, 0, sizeof(iv));
+ iv = kzalloc(crypto_skcipher_ivsize(tfm_cbc), GFP_KERNEL);
+ if (!iv)
+ goto error_iv;
/* Setup B0 */
scratch->b0.flags = 0x59; /* Format B0 */
@@ -276,6 +278,8 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
bytewise_xor(mic, &scratch->ax, iv, 8);
result = 8;
error_cbc_crypt:
+ kfree(iv);
+error_iv:
kfree(dst_buf);
error_dst_buf:
return result;
diff --git a/drivers/usb/wusbcore/wa-nep.c b/drivers/usb/wusbcore/wa-nep.c
index 9fdcb6b84abf..5f0656db5482 100644
--- a/drivers/usb/wusbcore/wa-nep.c
+++ b/drivers/usb/wusbcore/wa-nep.c
@@ -93,7 +93,6 @@ static void wa_notif_dispatch(struct work_struct *ws)
goto out; /* screw it */
#endif
atomic_dec(&wa->notifs_queued); /* Throttling ctl */
- dev = &wa->usb_iface->dev;
size = nw->size;
itr = nw->data;
diff --git a/drivers/uwb/uwb-debug.c b/drivers/uwb/uwb-debug.c
index 991374b13571..f1622bae13be 100644
--- a/drivers/uwb/uwb-debug.c
+++ b/drivers/uwb/uwb-debug.c
@@ -206,7 +206,7 @@ static const struct file_operations command_fops = {
.owner = THIS_MODULE,
};
-static int reservations_print(struct seq_file *s, void *p)
+static int reservations_show(struct seq_file *s, void *p)
{
struct uwb_rc *rc = s->private;
struct uwb_rsv *rsv;
@@ -240,21 +240,9 @@ static int reservations_print(struct seq_file *s, void *p)
return 0;
}
+DEFINE_SHOW_ATTRIBUTE(reservations);
-static int reservations_open(struct inode *inode, struct file *file)
-{
- return single_open(file, reservations_print, inode->i_private);
-}
-
-static const struct file_operations reservations_fops = {
- .open = reservations_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static int drp_avail_print(struct seq_file *s, void *p)
+static int drp_avail_show(struct seq_file *s, void *p)
{
struct uwb_rc *rc = s->private;
@@ -264,19 +252,7 @@ static int drp_avail_print(struct seq_file *s, void *p)
return 0;
}
-
-static int drp_avail_open(struct inode *inode, struct file *file)
-{
- return single_open(file, drp_avail_print, inode->i_private);
-}
-
-static const struct file_operations drp_avail_fops = {
- .open = drp_avail_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
+DEFINE_SHOW_ATTRIBUTE(drp_avail);
static void uwb_dbg_channel_changed(struct uwb_pal *pal, int channel)
{
diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c
index b90ef96e43d6..f2eafe2ed980 100644
--- a/drivers/video/console/dummycon.c
+++ b/drivers/video/console/dummycon.c
@@ -41,12 +41,47 @@ static void dummycon_init(struct vc_data *vc, int init)
vc_resize(vc, DUMMY_COLUMNS, DUMMY_ROWS);
}
-static int dummycon_dummy(void)
+static void dummycon_deinit(struct vc_data *vc) { }
+static void dummycon_clear(struct vc_data *vc, int sy, int sx, int height,
+ int width) { }
+static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
+static void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
+ int count, int ypos, int xpos) { }
+static void dummycon_cursor(struct vc_data *vc, int mode) { }
+
+static bool dummycon_scroll(struct vc_data *vc, unsigned int top,
+ unsigned int bottom, enum con_scroll dir,
+ unsigned int lines)
+{
+ return false;
+}
+
+static int dummycon_switch(struct vc_data *vc)
{
- return 0;
+ return 0;
}
-#define DUMMY (void *)dummycon_dummy
+static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch)
+{
+ return 0;
+}
+
+static int dummycon_font_set(struct vc_data *vc, struct console_font *font,
+ unsigned int flags)
+{
+ return 0;
+}
+
+static int dummycon_font_default(struct vc_data *vc,
+ struct console_font *font, char *name)
+{
+ return 0;
+}
+
+static int dummycon_font_copy(struct vc_data *vc, int con)
+{
+ return 0;
+}
/*
* The console `switch' structure for the dummy console
@@ -55,19 +90,19 @@ static int dummycon_dummy(void)
*/
const struct consw dummy_con = {
- .owner = THIS_MODULE,
- .con_startup = dummycon_startup,
- .con_init = dummycon_init,
- .con_deinit = DUMMY,
- .con_clear = DUMMY,
- .con_putc = DUMMY,
- .con_putcs = DUMMY,
- .con_cursor = DUMMY,
- .con_scroll = DUMMY,
- .con_switch = DUMMY,
- .con_blank = DUMMY,
- .con_font_set = DUMMY,
- .con_font_default = DUMMY,
- .con_font_copy = DUMMY,
+ .owner = THIS_MODULE,
+ .con_startup = dummycon_startup,
+ .con_init = dummycon_init,
+ .con_deinit = dummycon_deinit,
+ .con_clear = dummycon_clear,
+ .con_putc = dummycon_putc,
+ .con_putcs = dummycon_putcs,
+ .con_cursor = dummycon_cursor,
+ .con_scroll = dummycon_scroll,
+ .con_switch = dummycon_switch,
+ .con_blank = dummycon_blank,
+ .con_font_set = dummycon_font_set,
+ .con_font_default = dummycon_font_default,
+ .con_font_copy = dummycon_font_copy,
};
EXPORT_SYMBOL_GPL(dummy_con);
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index 42d02a206059..7f2526b43b33 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -673,12 +673,12 @@ static bool newport_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
return true;
}
-static int newport_dummy(struct vc_data *c)
+static int newport_set_origin(struct vc_data *vc)
{
return 0;
}
-#define DUMMY (void *) newport_dummy
+static void newport_save_screen(struct vc_data *vc) { }
const struct consw newport_con = {
.owner = THIS_MODULE,
@@ -694,8 +694,8 @@ const struct consw newport_con = {
.con_blank = newport_blank,
.con_font_set = newport_font_set,
.con_font_default = newport_font_default,
- .con_set_origin = DUMMY,
- .con_save_screen = DUMMY
+ .con_set_origin = newport_set_origin,
+ .con_save_screen = newport_save_screen
};
static int newport_probe(struct gio_device *dev,
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index a17ba1465815..f09e17b60e45 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -1272,7 +1272,8 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
return 0;
}
-static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags)
+static int vgacon_font_set(struct vc_data *c, struct console_font *font,
+ unsigned int flags)
{
unsigned charcount = font->charcount;
int rc;
@@ -1407,21 +1408,20 @@ static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
* The console `switch' structure for the VGA based console
*/
-static int vgacon_dummy(struct vc_data *c)
-{
- return 0;
-}
-
-#define DUMMY (void *) vgacon_dummy
+static void vgacon_clear(struct vc_data *vc, int sy, int sx, int height,
+ int width) { }
+static void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
+static void vgacon_putcs(struct vc_data *vc, const unsigned short *s,
+ int count, int ypos, int xpos) { }
const struct consw vga_con = {
.owner = THIS_MODULE,
.con_startup = vgacon_startup,
.con_init = vgacon_init,
.con_deinit = vgacon_deinit,
- .con_clear = DUMMY,
- .con_putc = DUMMY,
- .con_putcs = DUMMY,
+ .con_clear = vgacon_clear,
+ .con_putc = vgacon_putc,
+ .con_putcs = vgacon_putcs,
.con_cursor = vgacon_cursor,
.con_scroll = vgacon_scroll,
.con_switch = vgacon_switch,
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 5baf7bc054e1..3e330e0f56ed 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -2595,7 +2595,8 @@ static int fbcon_copy_font(struct vc_data *vc, int con)
* is ever implemented.
*/
-static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags)
+static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
+ unsigned int flags)
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
unsigned charcount = font->charcount;
diff --git a/drivers/video/fbdev/stifb.c b/drivers/video/fbdev/stifb.c
index 6ded5c198998..3c2e4cabc08f 100644
--- a/drivers/video/fbdev/stifb.c
+++ b/drivers/video/fbdev/stifb.c
@@ -527,7 +527,7 @@ rattlerSetupPlanes(struct stifb_info *fb)
fb->id = saved_id;
for (y = 0; y < fb->info.var.yres; ++y)
- memset(fb->info.screen_base + y * fb->info.fix.line_length,
+ fb_memset(fb->info.screen_base + y * fb->info.fix.line_length,
0xff, fb->info.var.xres * fb->info.var.bits_per_pixel/8);
CRX24_SET_OVLY_MASK(fb);
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 0c2a5a8327bd..80a778b02f28 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -706,6 +706,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
dev_err(&sl->dev,
"Device registration [%s] failed. err=%d\n",
dev_name(&sl->dev), err);
+ put_device(&sl->dev);
return err;
}
w1_family_notify(BUS_NOTIFY_ADD_DEVICE, sl);
diff --git a/fs/Makefile b/fs/Makefile
index add789ea270a..c9375fd2c8c4 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -11,7 +11,7 @@ obj-y := open.o read_write.o file_table.o super.o \
ioctl.o readdir.o select.o dcache.o inode.o \
attr.o bad_inode.o file.o filesystems.o namespace.o \
seq_file.o xattr.o libfs.o fs-writeback.o \
- pnode.o splice.o sync.o utimes.o \
+ pnode.o splice.o sync.o utimes.o d_path.o \
stack.o fs_struct.o statfs.o fs_pin.o nsfs.o
ifeq ($(CONFIG_BLOCK),y)
diff --git a/fs/aio.c b/fs/aio.c
index 6bcd3fb5265a..88d7927ffbc6 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -115,8 +115,7 @@ struct kioctx {
struct page **ring_pages;
long nr_pages;
- struct rcu_head free_rcu;
- struct work_struct free_work; /* see free_ioctx() */
+ struct rcu_work free_rwork; /* see free_ioctx() */
/*
* signals when all in-flight requests are done
@@ -592,13 +591,12 @@ static int kiocb_cancel(struct aio_kiocb *kiocb)
/*
* free_ioctx() should be RCU delayed to synchronize against the RCU
* protected lookup_ioctx() and also needs process context to call
- * aio_free_ring(), so the double bouncing through kioctx->free_rcu and
- * ->free_work.
+ * aio_free_ring(). Use rcu_work.
*/
static void free_ioctx(struct work_struct *work)
{
- struct kioctx *ctx = container_of(work, struct kioctx, free_work);
-
+ struct kioctx *ctx = container_of(to_rcu_work(work), struct kioctx,
+ free_rwork);
pr_debug("freeing %p\n", ctx);
aio_free_ring(ctx);
@@ -608,14 +606,6 @@ static void free_ioctx(struct work_struct *work)
kmem_cache_free(kioctx_cachep, ctx);
}
-static void free_ioctx_rcufn(struct rcu_head *head)
-{
- struct kioctx *ctx = container_of(head, struct kioctx, free_rcu);
-
- INIT_WORK(&ctx->free_work, free_ioctx);
- schedule_work(&ctx->free_work);
-}
-
static void free_ioctx_reqs(struct percpu_ref *ref)
{
struct kioctx *ctx = container_of(ref, struct kioctx, reqs);
@@ -625,7 +615,8 @@ static void free_ioctx_reqs(struct percpu_ref *ref)
complete(&ctx->rq_wait->comp);
/* Synchronize against RCU protected table->table[] dereferences */
- call_rcu(&ctx->free_rcu, free_ioctx_rcufn);
+ INIT_RCU_WORK(&ctx->free_rwork, free_ioctx);
+ queue_rcu_work(system_wq, &ctx->free_rwork);
}
/*
diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig
index 273351ee4c46..167e5dc7eadd 100644
--- a/fs/btrfs/Kconfig
+++ b/fs/btrfs/Kconfig
@@ -1,7 +1,6 @@
config BTRFS_FS
tristate "Btrfs filesystem support"
- select CRYPTO
- select CRYPTO_CRC32C
+ select LIBCRC32C
select ZLIB_INFLATE
select ZLIB_DEFLATE
select LZO_COMPRESS
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
index 0c4373628eb4..ca693dd554e9 100644
--- a/fs/btrfs/Makefile
+++ b/fs/btrfs/Makefile
@@ -10,7 +10,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
export.o tree-log.o free-space-cache.o zlib.o lzo.o zstd.o \
compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
- uuid-tree.o props.o hash.o free-space-tree.o tree-checker.o
+ uuid-tree.o props.o free-space-tree.o tree-checker.o
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index 1ba49ebe67da..0066d95b133f 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -46,12 +46,12 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
BUG();
}
- size = __btrfs_getxattr(inode, name, "", 0);
+ size = btrfs_getxattr(inode, name, "", 0);
if (size > 0) {
value = kzalloc(size, GFP_KERNEL);
if (!value)
return ERR_PTR(-ENOMEM);
- size = __btrfs_getxattr(inode, name, value, size);
+ size = btrfs_getxattr(inode, name, value, size);
}
if (size > 0) {
acl = posix_acl_from_xattr(&init_user_ns, value, size);
@@ -65,9 +65,6 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
return acl;
}
-/*
- * Needs to be called with fs_mutex held
- */
static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
struct inode *inode, struct posix_acl *acl, int type)
{
@@ -101,7 +98,7 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
goto out;
}
- ret = __btrfs_setxattr(trans, inode, name, value, size, 0);
+ ret = btrfs_setxattr(trans, inode, name, value, size, 0);
out:
kfree(value);
@@ -127,11 +124,6 @@ int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
return ret;
}
-/*
- * btrfs_init_acl is already generally called under fs_mutex, so the locking
- * stuff has been fixed to work with that. If the locking stuff changes, we
- * need to re-evaluate the acl locking stuff.
- */
int btrfs_init_acl(struct btrfs_trans_handle *trans,
struct inode *inode, struct inode *dir)
{
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 26484648d090..571024bc632e 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -170,7 +170,7 @@ int __init btrfs_prelim_ref_init(void)
return 0;
}
-void btrfs_prelim_ref_exit(void)
+void __cold btrfs_prelim_ref_exit(void)
{
kmem_cache_destroy(btrfs_prelim_ref_cache);
}
@@ -738,7 +738,8 @@ static int add_missing_keys(struct btrfs_fs_info *fs_info,
BUG_ON(ref->key_for_search.type);
BUG_ON(!ref->wanted_disk_byte);
- eb = read_tree_block(fs_info, ref->wanted_disk_byte, 0);
+ eb = read_tree_block(fs_info, ref->wanted_disk_byte, 0,
+ ref->level - 1, NULL);
if (IS_ERR(eb)) {
free_pref(ref);
return PTR_ERR(eb);
@@ -773,15 +774,12 @@ static int add_delayed_refs(const struct btrfs_fs_info *fs_info,
struct btrfs_delayed_extent_op *extent_op = head->extent_op;
struct btrfs_key key;
struct btrfs_key tmp_op_key;
- struct btrfs_key *op_key = NULL;
struct rb_node *n;
int count;
int ret = 0;
- if (extent_op && extent_op->update_key) {
+ if (extent_op && extent_op->update_key)
btrfs_disk_key_to_cpu(&tmp_op_key, &extent_op->key);
- op_key = &tmp_op_key;
- }
spin_lock(&head->lock);
for (n = rb_first(&head->ref_tree); n; n = rb_next(n)) {
@@ -1291,7 +1289,8 @@ again:
ref->level == 0) {
struct extent_buffer *eb;
- eb = read_tree_block(fs_info, ref->parent, 0);
+ eb = read_tree_block(fs_info, ref->parent, 0,
+ ref->level, NULL);
if (IS_ERR(eb)) {
ret = PTR_ERR(eb);
goto out;
diff --git a/fs/btrfs/backref.h b/fs/btrfs/backref.h
index 0c2fab8514ff..0a30028d5196 100644
--- a/fs/btrfs/backref.h
+++ b/fs/btrfs/backref.h
@@ -73,7 +73,7 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr);
int __init btrfs_prelim_ref_init(void);
-void btrfs_prelim_ref_exit(void);
+void __cold btrfs_prelim_ref_exit(void);
struct prelim_ref {
struct rb_node rbnode;
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index 63f0ccc92a71..ca15be569d69 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -195,7 +195,6 @@ struct btrfs_inode {
/* Hook into fs_info->delayed_iputs */
struct list_head delayed_iput;
- long delayed_iput_count;
/*
* To avoid races between lockless (i_mutex not held) direct IO writes
@@ -365,6 +364,4 @@ static inline void btrfs_print_data_csum_error(struct btrfs_inode *inode,
logical_start, csum, csum_expected, mirror_num);
}
-bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end);
-
#endif
diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c
index 7d51b5a5b505..3baebbc021c5 100644
--- a/fs/btrfs/check-integrity.c
+++ b/fs/btrfs/check-integrity.c
@@ -96,9 +96,9 @@
#include <linux/blkdev.h>
#include <linux/mm.h>
#include <linux/string.h>
+#include <linux/crc32c.h>
#include "ctree.h"
#include "disk-io.h"
-#include "hash.h"
#include "transaction.h"
#include "extent_io.h"
#include "volumes.h"
@@ -1736,7 +1736,7 @@ static int btrfsic_test_for_metadata(struct btrfsic_state *state,
size_t sublen = i ? PAGE_SIZE :
(PAGE_SIZE - BTRFS_CSUM_SIZE);
- crc = btrfs_crc32c(crc, data, sublen);
+ crc = crc32c(crc, data, sublen);
}
btrfs_csum_final(crc, csum);
if (memcmp(csum, h->csum, state->csum_size))
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index 07d049c0c20f..562c3e633403 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -1133,7 +1133,7 @@ int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page,
return ret;
}
-void btrfs_exit_compress(void)
+void __cold btrfs_exit_compress(void)
{
free_workspaces();
}
diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h
index 677fa4aa0bd7..ce796557a918 100644
--- a/fs/btrfs/compression.h
+++ b/fs/btrfs/compression.h
@@ -76,7 +76,7 @@ struct compressed_bio {
};
void __init btrfs_init_compress(void);
-void btrfs_exit_compress(void);
+void __cold btrfs_exit_compress(void);
int btrfs_compress_pages(unsigned int type_level, struct address_space *mapping,
u64 start, struct page **pages,
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index b88a79e69ddf..a2c9d21176e2 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -41,8 +41,6 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
struct extent_buffer *src_buf);
static void del_ptr(struct btrfs_root *root, struct btrfs_path *path,
int level, int slot);
-static int tree_mod_log_free_eb(struct btrfs_fs_info *fs_info,
- struct extent_buffer *eb);
struct btrfs_path *btrfs_alloc_path(void)
{
@@ -301,11 +299,6 @@ enum mod_log_op {
MOD_LOG_ROOT_REPLACE,
};
-struct tree_mod_move {
- int dst_slot;
- int nr_items;
-};
-
struct tree_mod_root {
u64 logical;
u8 level;
@@ -328,32 +321,15 @@ struct tree_mod_elem {
u64 blockptr;
/* this is used for op == MOD_LOG_MOVE_KEYS */
- struct tree_mod_move move;
+ struct {
+ int dst_slot;
+ int nr_items;
+ } move;
/* this is used for op == MOD_LOG_ROOT_REPLACE */
struct tree_mod_root old_root;
};
-static inline void tree_mod_log_read_lock(struct btrfs_fs_info *fs_info)
-{
- read_lock(&fs_info->tree_mod_log_lock);
-}
-
-static inline void tree_mod_log_read_unlock(struct btrfs_fs_info *fs_info)
-{
- read_unlock(&fs_info->tree_mod_log_lock);
-}
-
-static inline void tree_mod_log_write_lock(struct btrfs_fs_info *fs_info)
-{
- write_lock(&fs_info->tree_mod_log_lock);
-}
-
-static inline void tree_mod_log_write_unlock(struct btrfs_fs_info *fs_info)
-{
- write_unlock(&fs_info->tree_mod_log_lock);
-}
-
/*
* Pull a new tree mod seq number for our operation.
*/
@@ -373,14 +349,14 @@ static inline u64 btrfs_inc_tree_mod_seq(struct btrfs_fs_info *fs_info)
u64 btrfs_get_tree_mod_seq(struct btrfs_fs_info *fs_info,
struct seq_list *elem)
{
- tree_mod_log_write_lock(fs_info);
+ write_lock(&fs_info->tree_mod_log_lock);
spin_lock(&fs_info->tree_mod_seq_lock);
if (!elem->seq) {
elem->seq = btrfs_inc_tree_mod_seq(fs_info);
list_add_tail(&elem->list, &fs_info->tree_mod_seq_list);
}
spin_unlock(&fs_info->tree_mod_seq_lock);
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&fs_info->tree_mod_log_lock);
return elem->seq;
}
@@ -422,7 +398,7 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info,
* anything that's lower than the lowest existing (read: blocked)
* sequence number can be removed from the tree.
*/
- tree_mod_log_write_lock(fs_info);
+ write_lock(&fs_info->tree_mod_log_lock);
tm_root = &fs_info->tree_mod_log;
for (node = rb_first(tm_root); node; node = next) {
next = rb_next(node);
@@ -432,7 +408,7 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info,
rb_erase(node, tm_root);
kfree(tm);
}
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&fs_info->tree_mod_log_lock);
}
/*
@@ -443,7 +419,7 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info,
* for root replace operations, or the logical address of the affected
* block for all other operations.
*
- * Note: must be called with write lock (tree_mod_log_write_lock).
+ * Note: must be called with write lock for fs_info::tree_mod_log_lock.
*/
static noinline int
__tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
@@ -481,7 +457,7 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
* Determines if logging can be omitted. Returns 1 if it can. Otherwise, it
* returns zero with the tree_mod_log_lock acquired. The caller must hold
* this until all tree mod log insertions are recorded in the rb tree and then
- * call tree_mod_log_write_unlock() to release.
+ * write unlock fs_info::tree_mod_log_lock.
*/
static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info,
struct extent_buffer *eb) {
@@ -491,9 +467,9 @@ static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info,
if (eb && btrfs_header_level(eb) == 0)
return 1;
- tree_mod_log_write_lock(fs_info);
+ write_lock(&fs_info->tree_mod_log_lock);
if (list_empty(&(fs_info)->tree_mod_seq_list)) {
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&fs_info->tree_mod_log_lock);
return 1;
}
@@ -536,38 +512,34 @@ alloc_tree_mod_elem(struct extent_buffer *eb, int slot,
return tm;
}
-static noinline int
-tree_mod_log_insert_key(struct btrfs_fs_info *fs_info,
- struct extent_buffer *eb, int slot,
- enum mod_log_op op, gfp_t flags)
+static noinline int tree_mod_log_insert_key(struct extent_buffer *eb, int slot,
+ enum mod_log_op op, gfp_t flags)
{
struct tree_mod_elem *tm;
int ret;
- if (!tree_mod_need_log(fs_info, eb))
+ if (!tree_mod_need_log(eb->fs_info, eb))
return 0;
tm = alloc_tree_mod_elem(eb, slot, op, flags);
if (!tm)
return -ENOMEM;
- if (tree_mod_dont_log(fs_info, eb)) {
+ if (tree_mod_dont_log(eb->fs_info, eb)) {
kfree(tm);
return 0;
}
- ret = __tree_mod_log_insert(fs_info, tm);
- tree_mod_log_write_unlock(fs_info);
+ ret = __tree_mod_log_insert(eb->fs_info, tm);
+ write_unlock(&eb->fs_info->tree_mod_log_lock);
if (ret)
kfree(tm);
return ret;
}
-static noinline int
-tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
- struct extent_buffer *eb, int dst_slot, int src_slot,
- int nr_items)
+static noinline int tree_mod_log_insert_move(struct extent_buffer *eb,
+ int dst_slot, int src_slot, int nr_items)
{
struct tree_mod_elem *tm = NULL;
struct tree_mod_elem **tm_list = NULL;
@@ -575,7 +547,7 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
int i;
int locked = 0;
- if (!tree_mod_need_log(fs_info, eb))
+ if (!tree_mod_need_log(eb->fs_info, eb))
return 0;
tm_list = kcalloc(nr_items, sizeof(struct tree_mod_elem *), GFP_NOFS);
@@ -603,7 +575,7 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
}
}
- if (tree_mod_dont_log(fs_info, eb))
+ if (tree_mod_dont_log(eb->fs_info, eb))
goto free_tms;
locked = 1;
@@ -613,26 +585,26 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
* buffer, i.e. dst_slot < src_slot.
*/
for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) {
- ret = __tree_mod_log_insert(fs_info, tm_list[i]);
+ ret = __tree_mod_log_insert(eb->fs_info, tm_list[i]);
if (ret)
goto free_tms;
}
- ret = __tree_mod_log_insert(fs_info, tm);
+ ret = __tree_mod_log_insert(eb->fs_info, tm);
if (ret)
goto free_tms;
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&eb->fs_info->tree_mod_log_lock);
kfree(tm_list);
return 0;
free_tms:
for (i = 0; i < nr_items; i++) {
if (tm_list[i] && !RB_EMPTY_NODE(&tm_list[i]->node))
- rb_erase(&tm_list[i]->node, &fs_info->tree_mod_log);
+ rb_erase(&tm_list[i]->node, &eb->fs_info->tree_mod_log);
kfree(tm_list[i]);
}
if (locked)
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&eb->fs_info->tree_mod_log_lock);
kfree(tm_list);
kfree(tm);
@@ -660,12 +632,10 @@ __tree_mod_log_free_eb(struct btrfs_fs_info *fs_info,
return 0;
}
-static noinline int
-tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
- struct extent_buffer *old_root,
- struct extent_buffer *new_root,
- int log_removal)
+static noinline int tree_mod_log_insert_root(struct extent_buffer *old_root,
+ struct extent_buffer *new_root, int log_removal)
{
+ struct btrfs_fs_info *fs_info = old_root->fs_info;
struct tree_mod_elem *tm = NULL;
struct tree_mod_elem **tm_list = NULL;
int nritems = 0;
@@ -713,7 +683,7 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
if (!ret)
ret = __tree_mod_log_insert(fs_info, tm);
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&fs_info->tree_mod_log_lock);
if (ret)
goto free_tms;
kfree(tm_list);
@@ -740,7 +710,7 @@ __tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq,
struct tree_mod_elem *cur = NULL;
struct tree_mod_elem *found = NULL;
- tree_mod_log_read_lock(fs_info);
+ read_lock(&fs_info->tree_mod_log_lock);
tm_root = &fs_info->tree_mod_log;
node = tm_root->rb_node;
while (node) {
@@ -768,7 +738,7 @@ __tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq,
break;
}
}
- tree_mod_log_read_unlock(fs_info);
+ read_unlock(&fs_info->tree_mod_log_lock);
return found;
}
@@ -849,7 +819,7 @@ tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
goto free_tms;
}
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&fs_info->tree_mod_log_lock);
kfree(tm_list);
return 0;
@@ -861,36 +831,13 @@ free_tms:
kfree(tm_list[i]);
}
if (locked)
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&fs_info->tree_mod_log_lock);
kfree(tm_list);
return ret;
}
-static inline void
-tree_mod_log_eb_move(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
- int dst_offset, int src_offset, int nr_items)
-{
- int ret;
- ret = tree_mod_log_insert_move(fs_info, dst, dst_offset, src_offset,
- nr_items);
- BUG_ON(ret < 0);
-}
-
-static noinline void
-tree_mod_log_set_node_key(struct btrfs_fs_info *fs_info,
- struct extent_buffer *eb, int slot, int atomic)
-{
- int ret;
-
- ret = tree_mod_log_insert_key(fs_info, eb, slot,
- MOD_LOG_KEY_REPLACE,
- atomic ? GFP_ATOMIC : GFP_NOFS);
- BUG_ON(ret < 0);
-}
-
-static noinline int
-tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb)
+static noinline int tree_mod_log_free_eb(struct extent_buffer *eb)
{
struct tree_mod_elem **tm_list = NULL;
int nritems = 0;
@@ -900,7 +847,7 @@ tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb)
if (btrfs_header_level(eb) == 0)
return 0;
- if (!tree_mod_need_log(fs_info, NULL))
+ if (!tree_mod_need_log(eb->fs_info, NULL))
return 0;
nritems = btrfs_header_nritems(eb);
@@ -917,11 +864,11 @@ tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb)
}
}
- if (tree_mod_dont_log(fs_info, eb))
+ if (tree_mod_dont_log(eb->fs_info, eb))
goto free_tms;
- ret = __tree_mod_log_free_eb(fs_info, tm_list, nritems);
- tree_mod_log_write_unlock(fs_info);
+ ret = __tree_mod_log_free_eb(eb->fs_info, tm_list, nritems);
+ write_unlock(&eb->fs_info->tree_mod_log_lock);
if (ret)
goto free_tms;
kfree(tm_list);
@@ -936,17 +883,6 @@ free_tms:
return ret;
}
-static noinline void
-tree_mod_log_set_root_pointer(struct btrfs_root *root,
- struct extent_buffer *new_root_node,
- int log_removal)
-{
- int ret;
- ret = tree_mod_log_insert_root(root->fs_info, root->node,
- new_root_node, log_removal);
- BUG_ON(ret < 0);
-}
-
/*
* check if the tree block can be shared by multiple trees
*/
@@ -1173,7 +1109,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
parent_start = buf->start;
extent_buffer_get(cow);
- tree_mod_log_set_root_pointer(root, cow, 1);
+ ret = tree_mod_log_insert_root(root->node, cow, 1);
+ BUG_ON(ret < 0);
rcu_assign_pointer(root->node, cow);
btrfs_free_tree_block(trans, root, buf, parent_start,
@@ -1182,7 +1119,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
add_root_to_dirty_list(root);
} else {
WARN_ON(trans->transid != btrfs_header_generation(parent));
- tree_mod_log_insert_key(fs_info, parent, parent_slot,
+ tree_mod_log_insert_key(parent, parent_slot,
MOD_LOG_KEY_REPLACE, GFP_NOFS);
btrfs_set_node_blockptr(parent, parent_slot,
cow->start);
@@ -1190,7 +1127,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
trans->transid);
btrfs_mark_buffer_dirty(parent);
if (last_ref) {
- ret = tree_mod_log_free_eb(fs_info, buf);
+ ret = tree_mod_log_free_eb(buf);
if (ret) {
btrfs_abort_transaction(trans, ret);
return ret;
@@ -1211,9 +1148,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
* returns the logical address of the oldest predecessor of the given root.
* entries older than time_seq are ignored.
*/
-static struct tree_mod_elem *
-__tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info,
- struct extent_buffer *eb_root, u64 time_seq)
+static struct tree_mod_elem *__tree_mod_log_oldest_root(
+ struct extent_buffer *eb_root, u64 time_seq)
{
struct tree_mod_elem *tm;
struct tree_mod_elem *found = NULL;
@@ -1230,7 +1166,7 @@ __tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info,
* first operation that's logged for this root.
*/
while (1) {
- tm = tree_mod_log_search_oldest(fs_info, root_logical,
+ tm = tree_mod_log_search_oldest(eb_root->fs_info, root_logical,
time_seq);
if (!looped && !tm)
return NULL;
@@ -1279,7 +1215,7 @@ __tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
unsigned long p_size = sizeof(struct btrfs_key_ptr);
n = btrfs_header_nritems(eb);
- tree_mod_log_read_lock(fs_info);
+ read_lock(&fs_info->tree_mod_log_lock);
while (tm && tm->seq >= time_seq) {
/*
* all the operations are recorded with the operator used for
@@ -1334,7 +1270,7 @@ __tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
if (tm->logical != first_tm->logical)
break;
}
- tree_mod_log_read_unlock(fs_info);
+ read_unlock(&fs_info->tree_mod_log_lock);
btrfs_set_header_nritems(eb, n);
}
@@ -1418,9 +1354,10 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
struct tree_mod_root *old_root = NULL;
u64 old_generation = 0;
u64 logical;
+ int level;
eb_root = btrfs_read_lock_root_node(root);
- tm = __tree_mod_log_oldest_root(fs_info, eb_root, time_seq);
+ tm = __tree_mod_log_oldest_root(eb_root, time_seq);
if (!tm)
return eb_root;
@@ -1428,15 +1365,17 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
old_root = &tm->old_root;
old_generation = tm->generation;
logical = old_root->logical;
+ level = old_root->level;
} else {
logical = eb_root->start;
+ level = btrfs_header_level(eb_root);
}
tm = tree_mod_log_search(fs_info, logical, time_seq);
if (old_root && tm && tm->op != MOD_LOG_KEY_REMOVE_WHILE_FREEING) {
btrfs_tree_read_unlock(eb_root);
free_extent_buffer(eb_root);
- old = read_tree_block(fs_info, logical, 0);
+ old = read_tree_block(fs_info, logical, 0, level, NULL);
if (WARN_ON(IS_ERR(old) || !extent_buffer_uptodate(old))) {
if (!IS_ERR(old))
free_extent_buffer(old);
@@ -1484,7 +1423,7 @@ int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq)
int level;
struct extent_buffer *eb_root = btrfs_root_node(root);
- tm = __tree_mod_log_oldest_root(root->fs_info, eb_root, time_seq);
+ tm = __tree_mod_log_oldest_root(eb_root, time_seq);
if (tm && tm->op == MOD_LOG_ROOT_REPLACE) {
level = tm->old_root.level;
} else {
@@ -1502,8 +1441,8 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
if (btrfs_is_testing(root->fs_info))
return 0;
- /* ensure we can see the force_cow */
- smp_rmb();
+ /* Ensure we can see the FORCE_COW bit */
+ smp_mb__before_atomic();
/*
* We do not need to cow a block if
@@ -1656,6 +1595,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
btrfs_set_lock_blocking(parent);
for (i = start_slot; i <= end_slot; i++) {
+ struct btrfs_key first_key;
int close = 1;
btrfs_node_key(parent, &disk_key, i);
@@ -1665,6 +1605,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
progress_passed = 1;
blocknr = btrfs_node_blockptr(parent, i);
gen = btrfs_node_ptr_generation(parent, i);
+ btrfs_node_key_to_cpu(parent, &first_key, i);
if (last_block == 0)
last_block = blocknr;
@@ -1688,7 +1629,9 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
uptodate = 0;
if (!cur || !uptodate) {
if (!cur) {
- cur = read_tree_block(fs_info, blocknr, gen);
+ cur = read_tree_block(fs_info, blocknr, gen,
+ parent_level - 1,
+ &first_key);
if (IS_ERR(cur)) {
return PTR_ERR(cur);
} else if (!extent_buffer_uptodate(cur)) {
@@ -1696,7 +1639,8 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
return -EIO;
}
} else if (!uptodate) {
- err = btrfs_read_buffer(cur, gen);
+ err = btrfs_read_buffer(cur, gen,
+ parent_level - 1,&first_key);
if (err) {
free_extent_buffer(cur);
return err;
@@ -1849,14 +1793,17 @@ read_node_slot(struct btrfs_fs_info *fs_info, struct extent_buffer *parent,
{
int level = btrfs_header_level(parent);
struct extent_buffer *eb;
+ struct btrfs_key first_key;
if (slot < 0 || slot >= btrfs_header_nritems(parent))
return ERR_PTR(-ENOENT);
BUG_ON(level == 0);
+ btrfs_node_key_to_cpu(parent, &first_key, slot);
eb = read_tree_block(fs_info, btrfs_node_blockptr(parent, slot),
- btrfs_node_ptr_generation(parent, slot));
+ btrfs_node_ptr_generation(parent, slot),
+ level - 1, &first_key);
if (!IS_ERR(eb) && !extent_buffer_uptodate(eb)) {
free_extent_buffer(eb);
eb = ERR_PTR(-EIO);
@@ -1928,7 +1875,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
goto enospc;
}
- tree_mod_log_set_root_pointer(root, child, 1);
+ ret = tree_mod_log_insert_root(root->node, child, 1);
+ BUG_ON(ret < 0);
rcu_assign_pointer(root->node, child);
add_root_to_dirty_list(root);
@@ -2007,8 +1955,9 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
} else {
struct btrfs_disk_key right_key;
btrfs_node_key(right, &right_key, 0);
- tree_mod_log_set_node_key(fs_info, parent,
- pslot + 1, 0);
+ ret = tree_mod_log_insert_key(parent, pslot + 1,
+ MOD_LOG_KEY_REPLACE, GFP_NOFS);
+ BUG_ON(ret < 0);
btrfs_set_node_key(parent, &right_key, pslot + 1);
btrfs_mark_buffer_dirty(parent);
}
@@ -2052,7 +2001,9 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
/* update the parent key to reflect our changes */
struct btrfs_disk_key mid_key;
btrfs_node_key(mid, &mid_key, 0);
- tree_mod_log_set_node_key(fs_info, parent, pslot, 0);
+ ret = tree_mod_log_insert_key(parent, pslot,
+ MOD_LOG_KEY_REPLACE, GFP_NOFS);
+ BUG_ON(ret < 0);
btrfs_set_node_key(parent, &mid_key, pslot);
btrfs_mark_buffer_dirty(parent);
}
@@ -2153,7 +2104,9 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
struct btrfs_disk_key disk_key;
orig_slot += left_nr;
btrfs_node_key(mid, &disk_key, 0);
- tree_mod_log_set_node_key(fs_info, parent, pslot, 0);
+ ret = tree_mod_log_insert_key(parent, pslot,
+ MOD_LOG_KEY_REPLACE, GFP_NOFS);
+ BUG_ON(ret < 0);
btrfs_set_node_key(parent, &disk_key, pslot);
btrfs_mark_buffer_dirty(parent);
if (btrfs_header_nritems(left) > orig_slot) {
@@ -2207,8 +2160,9 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
struct btrfs_disk_key disk_key;
btrfs_node_key(right, &disk_key, 0);
- tree_mod_log_set_node_key(fs_info, parent,
- pslot + 1, 0);
+ ret = tree_mod_log_insert_key(parent, pslot + 1,
+ MOD_LOG_KEY_REPLACE, GFP_NOFS);
+ BUG_ON(ret < 0);
btrfs_set_node_key(parent, &disk_key, pslot + 1);
btrfs_mark_buffer_dirty(parent);
@@ -2445,10 +2399,14 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
u64 gen;
struct extent_buffer *b = *eb_ret;
struct extent_buffer *tmp;
+ struct btrfs_key first_key;
int ret;
+ int parent_level;
blocknr = btrfs_node_blockptr(b, slot);
gen = btrfs_node_ptr_generation(b, slot);
+ parent_level = btrfs_header_level(b);
+ btrfs_node_key_to_cpu(b, &first_key, slot);
tmp = find_extent_buffer(fs_info, blocknr);
if (tmp) {
@@ -2467,7 +2425,7 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
btrfs_set_path_blocking(p);
/* now we're allowed to do a blocking uptodate check */
- ret = btrfs_read_buffer(tmp, gen);
+ ret = btrfs_read_buffer(tmp, gen, parent_level - 1, &first_key);
if (!ret) {
*eb_ret = tmp;
return 0;
@@ -2494,7 +2452,8 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
btrfs_release_path(p);
ret = -EAGAIN;
- tmp = read_tree_block(fs_info, blocknr, 0);
+ tmp = read_tree_block(fs_info, blocknr, 0, parent_level - 1,
+ &first_key);
if (!IS_ERR(tmp)) {
/*
* If the read above didn't mark this buffer up to date,
@@ -3161,13 +3120,17 @@ static void fixup_low_keys(struct btrfs_fs_info *fs_info,
{
int i;
struct extent_buffer *t;
+ int ret;
for (i = level; i < BTRFS_MAX_LEVEL; i++) {
int tslot = path->slots[i];
+
if (!path->nodes[i])
break;
t = path->nodes[i];
- tree_mod_log_set_node_key(fs_info, t, tslot, 1);
+ ret = tree_mod_log_insert_key(t, tslot, MOD_LOG_KEY_REPLACE,
+ GFP_ATOMIC);
+ BUG_ON(ret < 0);
btrfs_set_node_key(t, key, tslot);
btrfs_mark_buffer_dirty(path->nodes[i]);
if (tslot != 0)
@@ -3264,8 +3227,8 @@ static int push_node_left(struct btrfs_trans_handle *trans,
if (push_items < src_nritems) {
/*
- * don't call tree_mod_log_eb_move here, key removal was already
- * fully logged by tree_mod_log_eb_copy above.
+ * Don't call tree_mod_log_insert_move here, key removal was
+ * already fully logged by tree_mod_log_eb_copy above.
*/
memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0),
btrfs_node_key_ptr_offset(push_items),
@@ -3320,7 +3283,8 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
if (max_push < push_items)
push_items = max_push;
- tree_mod_log_eb_move(fs_info, dst, push_items, 0, dst_nritems);
+ ret = tree_mod_log_insert_move(dst, push_items, 0, dst_nritems);
+ BUG_ON(ret < 0);
memmove_extent_buffer(dst, btrfs_node_key_ptr_offset(push_items),
btrfs_node_key_ptr_offset(0),
(dst_nritems) *
@@ -3363,6 +3327,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
struct extent_buffer *c;
struct extent_buffer *old;
struct btrfs_disk_key lower_key;
+ int ret;
BUG_ON(path->nodes[level]);
BUG_ON(path->nodes[level-1] != root->node);
@@ -3401,7 +3366,8 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(c);
old = root->node;
- tree_mod_log_set_root_pointer(root, c, 0);
+ ret = tree_mod_log_insert_root(root->node, c, 0);
+ BUG_ON(ret < 0);
rcu_assign_pointer(root->node, c);
/* the super has an extra ref to root->node */
@@ -3438,17 +3404,19 @@ static void insert_ptr(struct btrfs_trans_handle *trans,
BUG_ON(slot > nritems);
BUG_ON(nritems == BTRFS_NODEPTRS_PER_BLOCK(fs_info));
if (slot != nritems) {
- if (level)
- tree_mod_log_eb_move(fs_info, lower, slot + 1,
- slot, nritems - slot);
+ if (level) {
+ ret = tree_mod_log_insert_move(lower, slot + 1, slot,
+ nritems - slot);
+ BUG_ON(ret < 0);
+ }
memmove_extent_buffer(lower,
btrfs_node_key_ptr_offset(slot + 1),
btrfs_node_key_ptr_offset(slot),
(nritems - slot) * sizeof(struct btrfs_key_ptr));
}
if (level) {
- ret = tree_mod_log_insert_key(fs_info, lower, slot,
- MOD_LOG_KEY_ADD, GFP_NOFS);
+ ret = tree_mod_log_insert_key(lower, slot, MOD_LOG_KEY_ADD,
+ GFP_NOFS);
BUG_ON(ret < 0);
}
btrfs_set_node_key(lower, key, slot);
@@ -4911,17 +4879,19 @@ static void del_ptr(struct btrfs_root *root, struct btrfs_path *path,
nritems = btrfs_header_nritems(parent);
if (slot != nritems - 1) {
- if (level)
- tree_mod_log_eb_move(fs_info, parent, slot,
- slot + 1, nritems - slot - 1);
+ if (level) {
+ ret = tree_mod_log_insert_move(parent, slot, slot + 1,
+ nritems - slot - 1);
+ BUG_ON(ret < 0);
+ }
memmove_extent_buffer(parent,
btrfs_node_key_ptr_offset(slot),
btrfs_node_key_ptr_offset(slot + 1),
sizeof(struct btrfs_key_ptr) *
(nritems - slot - 1));
} else if (level) {
- ret = tree_mod_log_insert_key(fs_info, parent, slot,
- MOD_LOG_KEY_REMOVE, GFP_NOFS);
+ ret = tree_mod_log_insert_key(parent, slot, MOD_LOG_KEY_REMOVE,
+ GFP_NOFS);
BUG_ON(ret < 0);
}
@@ -5145,9 +5115,6 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
* into min_key, so you can call btrfs_search_slot with cow=1 on the
* key and get a writable path.
*
- * This does lock as it descends, and path->keep_locks should be set
- * to 1 by the caller.
- *
* This honors path->lowest_level to prevent descent past a given level
* of the tree.
*
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index da308774b8a4..0eb55825862a 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -40,6 +40,7 @@
#include <linux/sizes.h>
#include <linux/dynamic_debug.h>
#include <linux/refcount.h>
+#include <linux/crc32c.h>
#include "extent_io.h"
#include "extent_map.h"
#include "async-thread.h"
@@ -65,6 +66,8 @@ struct btrfs_ordered_sum;
#define BTRFS_MAX_LEVEL 8
+#define BTRFS_OLDEST_GENERATION 0ULL
+
#define BTRFS_COMPAT_EXTENT_TREE_V0
/*
@@ -86,9 +89,9 @@ struct btrfs_ordered_sum;
*/
#define BTRFS_LINK_MAX 65535U
+/* four bytes for CRC32 */
static const int btrfs_csum_sizes[] = { 4 };
-/* four bytes for CRC32 */
#define BTRFS_EMPTY_DIR_SIZE 0
/* ioprio of readahead is set to idle */
@@ -98,6 +101,7 @@ static const int btrfs_csum_sizes[] = { 4 };
#define BTRFS_MAX_EXTENT_SIZE SZ_128M
+
/*
* Count how many BTRFS_MAX_EXTENT_SIZE cover the @size
*/
@@ -381,8 +385,9 @@ struct btrfs_dev_replace {
/* For raid type sysfs entries */
struct raid_kobject {
- int raid_type;
+ u64 flags;
struct kobject kobj;
+ struct list_head list;
};
struct btrfs_space_info {
@@ -707,7 +712,6 @@ struct btrfs_delayed_root;
#define BTRFS_FS_LOG_RECOVERING 4
#define BTRFS_FS_OPEN 5
#define BTRFS_FS_QUOTA_ENABLED 6
-#define BTRFS_FS_QUOTA_ENABLING 7
#define BTRFS_FS_UPDATE_UUID_TREE_GEN 9
#define BTRFS_FS_CREATING_FREE_SPACE_TREE 10
#define BTRFS_FS_BTREE_ERR 11
@@ -788,7 +792,7 @@ struct btrfs_fs_info {
unsigned long pending_changes;
unsigned long compress_type:4;
unsigned int compress_level;
- int commit_interval;
+ u32 commit_interval;
/*
* It is a suggestive number, the read side is safe even it gets a
* wrong number because we will write out the data into a regular
@@ -877,7 +881,6 @@ struct btrfs_fs_info {
struct rb_root tree_mod_log;
atomic_t async_delalloc_pages;
- atomic_t open_ioctl_trans;
/*
* this is used to protect the following list -- ordered_roots.
@@ -935,9 +938,11 @@ struct btrfs_fs_info {
struct btrfs_workqueue *extent_workers;
struct task_struct *transaction_kthread;
struct task_struct *cleaner_kthread;
- int thread_pool_size;
+ u32 thread_pool_size;
struct kobject *space_info_kobj;
+ struct list_head pending_raid_kobjs;
+ spinlock_t pending_raid_kobjs_lock; /* uncontended */
u64 total_pinned;
@@ -952,9 +957,9 @@ struct btrfs_fs_info {
struct btrfs_fs_devices *fs_devices;
/*
- * the space_info list is almost entirely read only. It only changes
- * when we add a new raid type to the FS, and that happens
- * very rarely. RCU is used to protect it.
+ * The space_info list is effectively read only after initial
+ * setup. It is populated at mount time and cleaned up after
+ * all block groups are removed. RCU is used to protect it.
*/
struct list_head space_info;
@@ -993,8 +998,8 @@ struct btrfs_fs_info {
struct btrfs_balance_control *balance_ctl;
wait_queue_head_t balance_wait_q;
- unsigned data_chunk_allocations;
- unsigned metadata_ratio;
+ u32 data_chunk_allocations;
+ u32 metadata_ratio;
void *bdev_holder;
@@ -1260,12 +1265,13 @@ struct btrfs_root {
struct btrfs_subvolume_writers *subv_writers;
atomic_t will_be_snapshotted;
- /* For qgroup metadata space reserve */
- atomic64_t qgroup_meta_rsv;
+ /* For qgroup metadata reserved space */
+ spinlock_t qgroup_meta_rsv_lock;
+ u64 qgroup_meta_rsv_pertrans;
+ u64 qgroup_meta_rsv_prealloc;
};
struct btrfs_file_private {
- struct btrfs_trans_handle *trans;
void *filldir_buf;
};
@@ -2554,6 +2560,20 @@ BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_right,
((unsigned long)(BTRFS_LEAF_DATA_OFFSET + \
btrfs_item_offset_nr(leaf, slot)))
+static inline u64 btrfs_name_hash(const char *name, int len)
+{
+ return crc32c((u32)~1, name, len);
+}
+
+/*
+ * Figure the key offset of an extended inode ref
+ */
+static inline u64 btrfs_extref_hash(u64 parent_objectid, const char *name,
+ int len)
+{
+ return (u64) crc32c(parent_objectid, name, len);
+}
+
static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info)
{
return ((space_info->flags & BTRFS_BLOCK_GROUP_METADATA) &&
@@ -2608,7 +2628,7 @@ void btrfs_dec_nocow_writers(struct btrfs_fs_info *fs_info, u64 bytenr);
void btrfs_wait_nocow_writers(struct btrfs_block_group_cache *bg);
void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, unsigned long count);
+ unsigned long count);
int btrfs_async_run_delayed_refs(struct btrfs_fs_info *fs_info,
unsigned long count, u64 transid, int wait);
int btrfs_lookup_data_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len);
@@ -2628,7 +2648,6 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(
u64 bytenr);
void btrfs_get_block_group(struct btrfs_block_group_cache *cache);
void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
-int get_block_group_index(struct btrfs_block_group_cache *cache);
struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 parent, u64 root_objectid,
@@ -2668,15 +2687,13 @@ int btrfs_free_reserved_extent(struct btrfs_fs_info *fs_info,
int btrfs_free_and_pin_reserved_extent(struct btrfs_fs_info *fs_info,
u64 start, u64 len);
void btrfs_prepare_extent_commit(struct btrfs_fs_info *fs_info);
-int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info);
+int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans);
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 bytenr, u64 num_bytes, u64 parent,
u64 root_objectid, u64 owner, u64 offset);
-int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info);
+int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans);
int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
int btrfs_setup_space_cache(struct btrfs_trans_handle *trans,
@@ -2688,6 +2705,7 @@ int btrfs_can_relocate(struct btrfs_fs_info *fs_info, u64 bytenr);
int btrfs_make_block_group(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 bytes_used,
u64 type, u64 chunk_offset, u64 size);
+void btrfs_add_raid_kobjects(struct btrfs_fs_info *fs_info);
struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(
struct btrfs_fs_info *fs_info,
const u64 chunk_offset);
@@ -2697,8 +2715,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info);
void btrfs_get_block_group_trimming(struct btrfs_block_group_cache *cache);
void btrfs_put_block_group_trimming(struct btrfs_block_group_cache *cache);
-void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info);
+void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans);
u64 btrfs_data_alloc_profile(struct btrfs_fs_info *fs_info);
u64 btrfs_metadata_alloc_profile(struct btrfs_fs_info *fs_info);
u64 btrfs_system_alloc_profile(struct btrfs_fs_info *fs_info);
@@ -2730,11 +2747,10 @@ int btrfs_check_data_free_space(struct inode *inode,
void btrfs_free_reserved_data_space(struct inode *inode,
struct extent_changeset *reserved, u64 start, u64 len);
void btrfs_delalloc_release_space(struct inode *inode,
- struct extent_changeset *reserved, u64 start, u64 len);
+ struct extent_changeset *reserved,
+ u64 start, u64 len, bool qgroup_free);
void btrfs_free_reserved_data_space_noquota(struct inode *inode, u64 start,
u64 len);
-void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info);
void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans);
int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
struct btrfs_inode *inode);
@@ -2745,10 +2761,12 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
u64 *qgroup_reserved, bool use_global_rsv);
void btrfs_subvolume_release_metadata(struct btrfs_fs_info *fs_info,
struct btrfs_block_rsv *rsv);
-void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes);
+void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes,
+ bool qgroup_free);
int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes);
-void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes);
+void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes,
+ bool qgroup_free);
int btrfs_delalloc_reserve_space(struct inode *inode,
struct extent_changeset **reserved, u64 start, u64 len);
void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type);
@@ -2792,7 +2810,6 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range);
int btrfs_init_space_info(struct btrfs_fs_info *fs_info);
int btrfs_delayed_refs_qgroup_accounting(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
-int __get_raid_index(u64 flags);
int btrfs_start_write_no_snapshotting(struct btrfs_root *root);
void btrfs_end_write_no_snapshotting(struct btrfs_root *root);
void btrfs_wait_for_snapshot_creation(struct btrfs_root *root);
@@ -3195,8 +3212,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb);
void btrfs_destroy_inode(struct inode *inode);
int btrfs_drop_inode(struct inode *inode);
int __init btrfs_init_cachep(void);
-void btrfs_destroy_cachep(void);
-long btrfs_ioctl_trans_end(struct file *file);
+void __cold btrfs_destroy_cachep(void);
struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
struct btrfs_root *root, int *was_new);
struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
@@ -3246,7 +3262,7 @@ ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
/* file.c */
int __init btrfs_auto_defrag_init(void);
-void btrfs_auto_defrag_exit(void);
+void __cold btrfs_auto_defrag_exit(void);
int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
struct btrfs_inode *inode);
int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info);
@@ -3281,25 +3297,23 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
/* sysfs.c */
int __init btrfs_init_sysfs(void);
-void btrfs_exit_sysfs(void);
+void __cold btrfs_exit_sysfs(void);
int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info);
void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info);
-/* xattr.c */
-ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
-
/* super.c */
int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
unsigned long new_flags);
int btrfs_sync_fs(struct super_block *sb, int wait);
-static inline __printf(2, 3)
+static inline __printf(2, 3) __cold
void btrfs_no_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
{
}
#ifdef CONFIG_PRINTK
__printf(2, 3)
+__cold
void btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...);
#else
#define btrfs_printk(fs_info, fmt, args...) \
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index 0530f6f2e4ba..86ec2edc05e8 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -23,6 +23,7 @@
#include "disk-io.h"
#include "transaction.h"
#include "ctree.h"
+#include "qgroup.h"
#define BTRFS_DELAYED_WRITEBACK 512
#define BTRFS_DELAYED_BACKGROUND 128
@@ -42,7 +43,7 @@ int __init btrfs_delayed_inode_init(void)
return 0;
}
-void btrfs_delayed_inode_exit(void)
+void __cold btrfs_delayed_inode_exit(void)
{
kmem_cache_destroy(delayed_node_cache);
}
@@ -552,11 +553,12 @@ static struct btrfs_delayed_item *__btrfs_next_delayed_item(
}
static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info,
+ struct btrfs_root *root,
struct btrfs_delayed_item *item)
{
struct btrfs_block_rsv *src_rsv;
struct btrfs_block_rsv *dst_rsv;
+ struct btrfs_fs_info *fs_info = root->fs_info;
u64 num_bytes;
int ret;
@@ -578,15 +580,17 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,
return ret;
}
-static void btrfs_delayed_item_release_metadata(struct btrfs_fs_info *fs_info,
+static void btrfs_delayed_item_release_metadata(struct btrfs_root *root,
struct btrfs_delayed_item *item)
{
struct btrfs_block_rsv *rsv;
+ struct btrfs_fs_info *fs_info = root->fs_info;
if (!item->bytes_reserved)
return;
rsv = &fs_info->delayed_block_rsv;
+ btrfs_qgroup_convert_reserved_meta(root, item->bytes_reserved);
trace_btrfs_space_reservation(fs_info, "delayed_item",
item->key.objectid, item->bytes_reserved,
0);
@@ -611,6 +615,9 @@ static int btrfs_delayed_inode_reserve_metadata(
num_bytes = btrfs_calc_trans_metadata_size(fs_info, 1);
+ ret = btrfs_qgroup_reserve_meta_prealloc(root, num_bytes, true);
+ if (ret < 0)
+ return ret;
/*
* btrfs_dirty_inode will update the inode under btrfs_join_transaction
* which doesn't reserve space for speed. This is a problem since we
@@ -630,8 +637,10 @@ static int btrfs_delayed_inode_reserve_metadata(
* EAGAIN to make us stop the transaction we have, so return
* ENOSPC instead so that btrfs_dirty_inode knows what to do.
*/
- if (ret == -EAGAIN)
+ if (ret == -EAGAIN) {
ret = -ENOSPC;
+ btrfs_qgroup_free_meta_prealloc(root, num_bytes);
+ }
if (!ret) {
node->bytes_reserved = num_bytes;
trace_btrfs_space_reservation(fs_info,
@@ -653,7 +662,8 @@ static int btrfs_delayed_inode_reserve_metadata(
}
static void btrfs_delayed_inode_release_metadata(struct btrfs_fs_info *fs_info,
- struct btrfs_delayed_node *node)
+ struct btrfs_delayed_node *node,
+ bool qgroup_free)
{
struct btrfs_block_rsv *rsv;
@@ -665,6 +675,12 @@ static void btrfs_delayed_inode_release_metadata(struct btrfs_fs_info *fs_info,
node->inode_id, node->bytes_reserved, 0);
btrfs_block_rsv_release(fs_info, rsv,
node->bytes_reserved);
+ if (qgroup_free)
+ btrfs_qgroup_free_meta_prealloc(node->root,
+ node->bytes_reserved);
+ else
+ btrfs_qgroup_convert_reserved_meta(node->root,
+ node->bytes_reserved);
node->bytes_reserved = 0;
}
@@ -766,7 +782,7 @@ static int btrfs_batch_insert_items(struct btrfs_root *root,
curr->data_len);
slot++;
- btrfs_delayed_item_release_metadata(fs_info, curr);
+ btrfs_delayed_item_release_metadata(root, curr);
list_del(&curr->tree_list);
btrfs_release_delayed_item(curr);
@@ -788,7 +804,6 @@ static int btrfs_insert_delayed_item(struct btrfs_trans_handle *trans,
struct btrfs_path *path,
struct btrfs_delayed_item *delayed_item)
{
- struct btrfs_fs_info *fs_info = root->fs_info;
struct extent_buffer *leaf;
char *ptr;
int ret;
@@ -806,7 +821,7 @@ static int btrfs_insert_delayed_item(struct btrfs_trans_handle *trans,
delayed_item->data_len);
btrfs_mark_buffer_dirty(leaf);
- btrfs_delayed_item_release_metadata(fs_info, delayed_item);
+ btrfs_delayed_item_release_metadata(root, delayed_item);
return 0;
}
@@ -858,7 +873,6 @@ static int btrfs_batch_delete_items(struct btrfs_trans_handle *trans,
struct btrfs_path *path,
struct btrfs_delayed_item *item)
{
- struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_delayed_item *curr, *next;
struct extent_buffer *leaf;
struct btrfs_key key;
@@ -908,7 +922,7 @@ static int btrfs_batch_delete_items(struct btrfs_trans_handle *trans,
goto out;
list_for_each_entry_safe(curr, next, &head, tree_list) {
- btrfs_delayed_item_release_metadata(fs_info, curr);
+ btrfs_delayed_item_release_metadata(root, curr);
list_del(&curr->tree_list);
btrfs_release_delayed_item(curr);
}
@@ -1051,7 +1065,7 @@ out:
no_iref:
btrfs_release_path(path);
err_out:
- btrfs_delayed_inode_release_metadata(fs_info, node);
+ btrfs_delayed_inode_release_metadata(fs_info, node, (ret < 0));
btrfs_release_delayed_inode(node);
return ret;
@@ -1115,9 +1129,9 @@ __btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
* Returns < 0 on error and returns with an aborted transaction with any
* outstanding delayed items cleaned up.
*/
-static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, int nr)
+static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans, int nr)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_delayed_root *delayed_root;
struct btrfs_delayed_node *curr_node, *prev_node;
struct btrfs_path *path;
@@ -1162,16 +1176,14 @@ static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
return ret;
}
-int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info)
+int btrfs_run_delayed_items(struct btrfs_trans_handle *trans)
{
- return __btrfs_run_delayed_items(trans, fs_info, -1);
+ return __btrfs_run_delayed_items(trans, -1);
}
-int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, int nr)
+int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans, int nr)
{
- return __btrfs_run_delayed_items(trans, fs_info, nr);
+ return __btrfs_run_delayed_items(trans, nr);
}
int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
@@ -1443,7 +1455,7 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
btrfs_set_stack_dir_type(dir_item, type);
memcpy((char *)(dir_item + 1), name, name_len);
- ret = btrfs_delayed_item_reserve_metadata(trans, fs_info, delayed_item);
+ ret = btrfs_delayed_item_reserve_metadata(trans, dir->root, delayed_item);
/*
* we have reserved enough space when we start a new transaction,
* so reserving metadata failure is impossible
@@ -1480,7 +1492,7 @@ static int btrfs_delete_delayed_insertion_item(struct btrfs_fs_info *fs_info,
return 1;
}
- btrfs_delayed_item_release_metadata(fs_info, item);
+ btrfs_delayed_item_release_metadata(node->root, item);
btrfs_release_delayed_item(item);
mutex_unlock(&node->mutex);
return 0;
@@ -1515,7 +1527,7 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
item->key = item_key;
- ret = btrfs_delayed_item_reserve_metadata(trans, fs_info, item);
+ ret = btrfs_delayed_item_reserve_metadata(trans, dir->root, item);
/*
* we have reserved enough space when we start a new transaction,
* so reserving metadata failure is impossible.
@@ -1880,7 +1892,7 @@ static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node)
mutex_lock(&delayed_node->mutex);
curr_item = __btrfs_first_delayed_insertion_item(delayed_node);
while (curr_item) {
- btrfs_delayed_item_release_metadata(fs_info, curr_item);
+ btrfs_delayed_item_release_metadata(root, curr_item);
prev_item = curr_item;
curr_item = __btrfs_next_delayed_item(prev_item);
btrfs_release_delayed_item(prev_item);
@@ -1888,7 +1900,7 @@ static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node)
curr_item = __btrfs_first_delayed_deletion_item(delayed_node);
while (curr_item) {
- btrfs_delayed_item_release_metadata(fs_info, curr_item);
+ btrfs_delayed_item_release_metadata(root, curr_item);
prev_item = curr_item;
curr_item = __btrfs_next_delayed_item(prev_item);
btrfs_release_delayed_item(prev_item);
@@ -1898,7 +1910,7 @@ static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node)
btrfs_release_delayed_iref(delayed_node);
if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
- btrfs_delayed_inode_release_metadata(fs_info, delayed_node);
+ btrfs_delayed_inode_release_metadata(fs_info, delayed_node, false);
btrfs_release_delayed_inode(delayed_node);
}
mutex_unlock(&delayed_node->mutex);
diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h
index c4189d495934..100a91e26b55 100644
--- a/fs/btrfs/delayed-inode.h
+++ b/fs/btrfs/delayed-inode.h
@@ -111,10 +111,8 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
int btrfs_inode_delayed_dir_index_count(struct btrfs_inode *inode);
-int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info);
-int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, int nr);
+int btrfs_run_delayed_items(struct btrfs_trans_handle *trans);
+int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans, int nr);
void btrfs_balance_delayed_items(struct btrfs_fs_info *fs_info);
@@ -151,7 +149,7 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
/* for init */
int __init btrfs_delayed_inode_init(void);
-void btrfs_delayed_inode_exit(void);
+void __cold btrfs_delayed_inode_exit(void);
/* for debugging */
void btrfs_assert_delayed_root_empty(struct btrfs_fs_info *fs_info);
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c
index 7ab5e0128f0c..2677257c149d 100644
--- a/fs/btrfs/delayed-ref.c
+++ b/fs/btrfs/delayed-ref.c
@@ -216,7 +216,7 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
struct btrfs_delayed_ref_root *delayed_refs;
delayed_refs = &trans->transaction->delayed_refs;
- assert_spin_locked(&delayed_refs->lock);
+ lockdep_assert_held(&delayed_refs->lock);
if (mutex_trylock(&head->mutex))
return 0;
@@ -239,7 +239,7 @@ static inline void drop_delayed_ref(struct btrfs_trans_handle *trans,
struct btrfs_delayed_ref_head *head,
struct btrfs_delayed_ref_node *ref)
{
- assert_spin_locked(&head->lock);
+ lockdep_assert_held(&head->lock);
rb_erase(&ref->ref_node, &head->ref_tree);
RB_CLEAR_NODE(&ref->ref_node);
if (!list_empty(&ref->add_list))
@@ -307,7 +307,7 @@ void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans,
struct rb_node *node;
u64 seq = 0;
- assert_spin_locked(&head->lock);
+ lockdep_assert_held(&head->lock);
if (RB_EMPTY_ROOT(&head->ref_tree))
return;
@@ -930,7 +930,7 @@ btrfs_find_delayed_ref_head(struct btrfs_delayed_ref_root *delayed_refs, u64 byt
return find_ref_head(&delayed_refs->href_root, bytenr, 0);
}
-void btrfs_delayed_ref_exit(void)
+void __cold btrfs_delayed_ref_exit(void)
{
kmem_cache_destroy(btrfs_delayed_ref_head_cachep);
kmem_cache_destroy(btrfs_delayed_tree_ref_cachep);
diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h
index c4f625e5a691..9e3e5aff0937 100644
--- a/fs/btrfs/delayed-ref.h
+++ b/fs/btrfs/delayed-ref.h
@@ -204,7 +204,7 @@ extern struct kmem_cache *btrfs_delayed_data_ref_cachep;
extern struct kmem_cache *btrfs_delayed_extent_op_cachep;
int __init btrfs_delayed_ref_init(void);
-void btrfs_delayed_ref_exit(void);
+void __cold btrfs_delayed_ref_exit(void);
static inline struct btrfs_delayed_extent_op *
btrfs_alloc_delayed_extent_op(void)
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index 7efbc4d1128b..0d203633bb96 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -44,7 +44,6 @@ static void btrfs_dev_replace_update_device_in_mapping_tree(
struct btrfs_fs_info *fs_info,
struct btrfs_device *srcdev,
struct btrfs_device *tgtdev);
-static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info);
static int btrfs_dev_replace_kthread(void *data);
static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info);
@@ -174,8 +173,14 @@ no_valid_dev_replace_entry_found:
}
set_bit(BTRFS_DEV_STATE_REPLACE_TGT,
&dev_replace->tgtdev->dev_state);
- btrfs_init_dev_replace_tgtdev_for_resume(fs_info,
- dev_replace->tgtdev);
+
+ WARN_ON(fs_info->fs_devices->rw_devices == 0);
+ dev_replace->tgtdev->io_width = fs_info->sectorsize;
+ dev_replace->tgtdev->io_align = fs_info->sectorsize;
+ dev_replace->tgtdev->sector_size = fs_info->sectorsize;
+ dev_replace->tgtdev->fs_info = fs_info;
+ set_bit(BTRFS_DEV_STATE_IN_FS_METADATA,
+ &dev_replace->tgtdev->dev_state);
}
break;
}
@@ -200,13 +205,13 @@ int btrfs_run_dev_replace(struct btrfs_trans_handle *trans,
struct btrfs_dev_replace_item *ptr;
struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
- btrfs_dev_replace_lock(dev_replace, 0);
+ btrfs_dev_replace_read_lock(dev_replace);
if (!dev_replace->is_valid ||
!dev_replace->item_needs_writeback) {
- btrfs_dev_replace_unlock(dev_replace, 0);
+ btrfs_dev_replace_read_unlock(dev_replace);
return 0;
}
- btrfs_dev_replace_unlock(dev_replace, 0);
+ btrfs_dev_replace_read_unlock(dev_replace);
key.objectid = 0;
key.type = BTRFS_DEV_REPLACE_KEY;
@@ -264,7 +269,7 @@ int btrfs_run_dev_replace(struct btrfs_trans_handle *trans,
ptr = btrfs_item_ptr(eb, path->slots[0],
struct btrfs_dev_replace_item);
- btrfs_dev_replace_lock(dev_replace, 1);
+ btrfs_dev_replace_write_lock(dev_replace);
if (dev_replace->srcdev)
btrfs_set_dev_replace_src_devid(eb, ptr,
dev_replace->srcdev->devid);
@@ -287,7 +292,7 @@ int btrfs_run_dev_replace(struct btrfs_trans_handle *trans,
btrfs_set_dev_replace_cursor_right(eb, ptr,
dev_replace->cursor_right);
dev_replace->item_needs_writeback = 0;
- btrfs_dev_replace_unlock(dev_replace, 1);
+ btrfs_dev_replace_write_unlock(dev_replace);
btrfs_mark_buffer_dirty(eb);
@@ -307,7 +312,7 @@ void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info)
static char* btrfs_dev_name(struct btrfs_device *device)
{
- if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state))
+ if (!device || test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state))
return "<missing disk>";
else
return rcu_str_deref(device->name);
@@ -352,7 +357,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
return PTR_ERR(trans);
}
- btrfs_dev_replace_lock(dev_replace, 1);
+ btrfs_dev_replace_write_lock(dev_replace);
switch (dev_replace->replace_state) {
case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
@@ -390,7 +395,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
dev_replace->item_needs_writeback = 1;
atomic64_set(&dev_replace->num_write_errors, 0);
atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0);
- btrfs_dev_replace_unlock(dev_replace, 1);
+ btrfs_dev_replace_write_unlock(dev_replace);
ret = btrfs_sysfs_add_device_link(tgt_device->fs_devices, tgt_device);
if (ret)
@@ -402,7 +407,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
trans = btrfs_start_transaction(root, 0);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
- btrfs_dev_replace_lock(dev_replace, 1);
+ btrfs_dev_replace_write_lock(dev_replace);
goto leave;
}
@@ -426,7 +431,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
leave:
dev_replace->srcdev = NULL;
dev_replace->tgtdev = NULL;
- btrfs_dev_replace_unlock(dev_replace, 1);
+ btrfs_dev_replace_write_unlock(dev_replace);
btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
return ret;
}
@@ -493,18 +498,18 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
/* don't allow cancel or unmount to disturb the finishing procedure */
mutex_lock(&dev_replace->lock_finishing_cancel_unmount);
- btrfs_dev_replace_lock(dev_replace, 0);
+ btrfs_dev_replace_read_lock(dev_replace);
/* was the operation canceled, or is it finished? */
if (dev_replace->replace_state !=
BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED) {
- btrfs_dev_replace_unlock(dev_replace, 0);
+ btrfs_dev_replace_read_unlock(dev_replace);
mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
return 0;
}
tgt_device = dev_replace->tgtdev;
src_device = dev_replace->srcdev;
- btrfs_dev_replace_unlock(dev_replace, 0);
+ btrfs_dev_replace_read_unlock(dev_replace);
/*
* flush all outstanding I/O and inode extent mappings before the
@@ -529,7 +534,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
/* keep away write_all_supers() during the finishing procedure */
mutex_lock(&fs_info->fs_devices->device_list_mutex);
mutex_lock(&fs_info->chunk_mutex);
- btrfs_dev_replace_lock(dev_replace, 1);
+ btrfs_dev_replace_write_lock(dev_replace);
dev_replace->replace_state =
scrub_ret ? BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED
: BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED;
@@ -549,7 +554,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
btrfs_dev_name(src_device),
src_device->devid,
rcu_str_deref(tgt_device->name), scrub_ret);
- btrfs_dev_replace_unlock(dev_replace, 1);
+ btrfs_dev_replace_write_unlock(dev_replace);
mutex_unlock(&fs_info->chunk_mutex);
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
mutex_unlock(&uuid_mutex);
@@ -586,7 +591,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list);
fs_info->fs_devices->rw_devices++;
- btrfs_dev_replace_unlock(dev_replace, 1);
+ btrfs_dev_replace_write_unlock(dev_replace);
btrfs_rm_dev_replace_blocked(fs_info);
@@ -679,7 +684,7 @@ void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
{
struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
- btrfs_dev_replace_lock(dev_replace, 0);
+ btrfs_dev_replace_read_lock(dev_replace);
/* even if !dev_replace_is_valid, the values are good enough for
* the replace_status ioctl */
args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
@@ -691,41 +696,36 @@ void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
args->status.num_uncorrectable_read_errors =
atomic64_read(&dev_replace->num_uncorrectable_read_errors);
args->status.progress_1000 = btrfs_dev_replace_progress(fs_info);
- btrfs_dev_replace_unlock(dev_replace, 0);
+ btrfs_dev_replace_read_unlock(dev_replace);
}
-int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info,
- struct btrfs_ioctl_dev_replace_args *args)
-{
- args->result = __btrfs_dev_replace_cancel(fs_info);
- return 0;
-}
-
-static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
+int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
{
struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
struct btrfs_device *tgt_device = NULL;
+ struct btrfs_device *src_device = NULL;
struct btrfs_trans_handle *trans;
struct btrfs_root *root = fs_info->tree_root;
- u64 result;
+ int result;
int ret;
if (sb_rdonly(fs_info->sb))
return -EROFS;
mutex_lock(&dev_replace->lock_finishing_cancel_unmount);
- btrfs_dev_replace_lock(dev_replace, 1);
+ btrfs_dev_replace_write_lock(dev_replace);
switch (dev_replace->replace_state) {
case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED;
- btrfs_dev_replace_unlock(dev_replace, 1);
+ btrfs_dev_replace_write_unlock(dev_replace);
goto leave;
case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
tgt_device = dev_replace->tgtdev;
+ src_device = dev_replace->srcdev;
dev_replace->tgtdev = NULL;
dev_replace->srcdev = NULL;
break;
@@ -733,7 +733,7 @@ static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED;
dev_replace->time_stopped = get_seconds();
dev_replace->item_needs_writeback = 1;
- btrfs_dev_replace_unlock(dev_replace, 1);
+ btrfs_dev_replace_write_unlock(dev_replace);
btrfs_scrub_cancel(fs_info);
trans = btrfs_start_transaction(root, 0);
@@ -743,6 +743,12 @@ static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
}
ret = btrfs_commit_transaction(trans);
WARN_ON(ret);
+
+ btrfs_info_in_rcu(fs_info,
+ "dev_replace from %s (devid %llu) to %s canceled",
+ btrfs_dev_name(src_device), src_device->devid,
+ btrfs_dev_name(tgt_device));
+
if (tgt_device)
btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
@@ -756,7 +762,7 @@ void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info)
struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
mutex_lock(&dev_replace->lock_finishing_cancel_unmount);
- btrfs_dev_replace_lock(dev_replace, 1);
+ btrfs_dev_replace_write_lock(dev_replace);
switch (dev_replace->replace_state) {
case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
@@ -772,7 +778,7 @@ void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info)
break;
}
- btrfs_dev_replace_unlock(dev_replace, 1);
+ btrfs_dev_replace_write_unlock(dev_replace);
mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
}
@@ -782,12 +788,12 @@ int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info)
struct task_struct *task;
struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
- btrfs_dev_replace_lock(dev_replace, 1);
+ btrfs_dev_replace_write_lock(dev_replace);
switch (dev_replace->replace_state) {
case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
- btrfs_dev_replace_unlock(dev_replace, 1);
+ btrfs_dev_replace_write_unlock(dev_replace);
return 0;
case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
break;
@@ -801,10 +807,10 @@ int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info)
"cannot continue dev_replace, tgtdev is missing");
btrfs_info(fs_info,
"you may cancel the operation after 'mount -o degraded'");
- btrfs_dev_replace_unlock(dev_replace, 1);
+ btrfs_dev_replace_write_unlock(dev_replace);
return 0;
}
- btrfs_dev_replace_unlock(dev_replace, 1);
+ btrfs_dev_replace_write_unlock(dev_replace);
WARN_ON(test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags));
task = kthread_run(btrfs_dev_replace_kthread, fs_info, "btrfs-devrepl");
@@ -873,37 +879,37 @@ int btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace)
return 1;
}
-void btrfs_dev_replace_lock(struct btrfs_dev_replace *dev_replace, int rw)
+void btrfs_dev_replace_read_lock(struct btrfs_dev_replace *dev_replace)
{
- if (rw == 1) {
- /* write */
-again:
- wait_event(dev_replace->read_lock_wq,
- atomic_read(&dev_replace->blocking_readers) == 0);
- write_lock(&dev_replace->lock);
- if (atomic_read(&dev_replace->blocking_readers)) {
- write_unlock(&dev_replace->lock);
- goto again;
- }
- } else {
- read_lock(&dev_replace->lock);
- atomic_inc(&dev_replace->read_locks);
- }
+ read_lock(&dev_replace->lock);
+ atomic_inc(&dev_replace->read_locks);
+}
+
+void btrfs_dev_replace_read_unlock(struct btrfs_dev_replace *dev_replace)
+{
+ ASSERT(atomic_read(&dev_replace->read_locks) > 0);
+ atomic_dec(&dev_replace->read_locks);
+ read_unlock(&dev_replace->lock);
}
-void btrfs_dev_replace_unlock(struct btrfs_dev_replace *dev_replace, int rw)
+void btrfs_dev_replace_write_lock(struct btrfs_dev_replace *dev_replace)
{
- if (rw == 1) {
- /* write */
- ASSERT(atomic_read(&dev_replace->blocking_readers) == 0);
+again:
+ wait_event(dev_replace->read_lock_wq,
+ atomic_read(&dev_replace->blocking_readers) == 0);
+ write_lock(&dev_replace->lock);
+ if (atomic_read(&dev_replace->blocking_readers)) {
write_unlock(&dev_replace->lock);
- } else {
- ASSERT(atomic_read(&dev_replace->read_locks) > 0);
- atomic_dec(&dev_replace->read_locks);
- read_unlock(&dev_replace->lock);
+ goto again;
}
}
+void btrfs_dev_replace_write_unlock(struct btrfs_dev_replace *dev_replace)
+{
+ ASSERT(atomic_read(&dev_replace->blocking_readers) == 0);
+ write_unlock(&dev_replace->lock);
+}
+
/* inc blocking cnt and release read lock */
void btrfs_dev_replace_set_lock_blocking(
struct btrfs_dev_replace *dev_replace)
diff --git a/fs/btrfs/dev-replace.h b/fs/btrfs/dev-replace.h
index f94a76844ae7..8566a02ef222 100644
--- a/fs/btrfs/dev-replace.h
+++ b/fs/btrfs/dev-replace.h
@@ -32,13 +32,14 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
int read_src);
void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
struct btrfs_ioctl_dev_replace_args *args);
-int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info,
- struct btrfs_ioctl_dev_replace_args *args);
+int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info);
void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info);
int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info);
int btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace);
-void btrfs_dev_replace_lock(struct btrfs_dev_replace *dev_replace, int rw);
-void btrfs_dev_replace_unlock(struct btrfs_dev_replace *dev_replace, int rw);
+void btrfs_dev_replace_read_lock(struct btrfs_dev_replace *dev_replace);
+void btrfs_dev_replace_read_unlock(struct btrfs_dev_replace *dev_replace);
+void btrfs_dev_replace_write_lock(struct btrfs_dev_replace *dev_replace);
+void btrfs_dev_replace_write_unlock(struct btrfs_dev_replace *dev_replace);
void btrfs_dev_replace_set_lock_blocking(struct btrfs_dev_replace *dev_replace);
void btrfs_dev_replace_clear_lock_blocking(
struct btrfs_dev_replace *dev_replace);
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c
index cbe421605cd5..29e967b2c667 100644
--- a/fs/btrfs/dir-item.c
+++ b/fs/btrfs/dir-item.c
@@ -18,7 +18,6 @@
#include "ctree.h"
#include "disk-io.h"
-#include "hash.h"
#include "transaction.h"
/*
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 21f34ad0d411..07b5e6f7df67 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -31,10 +31,10 @@
#include <linux/uuid.h>
#include <linux/semaphore.h>
#include <linux/error-injection.h>
+#include <linux/crc32c.h>
#include <asm/unaligned.h>
#include "ctree.h"
#include "disk-io.h"
-#include "hash.h"
#include "transaction.h"
#include "btrfs_inode.h"
#include "volumes.h"
@@ -110,7 +110,7 @@ int __init btrfs_end_io_wq_init(void)
return 0;
}
-void btrfs_end_io_wq_exit(void)
+void __cold btrfs_end_io_wq_exit(void)
{
kmem_cache_destroy(btrfs_end_io_wq_cache);
}
@@ -124,8 +124,8 @@ struct async_submit_bio {
void *private_data;
struct btrfs_fs_info *fs_info;
struct bio *bio;
- extent_submit_bio_hook_t *submit_bio_start;
- extent_submit_bio_hook_t *submit_bio_done;
+ extent_submit_bio_start_t *submit_bio_start;
+ extent_submit_bio_done_t *submit_bio_done;
int mirror_num;
unsigned long bio_flags;
/*
@@ -270,7 +270,7 @@ out:
u32 btrfs_csum_data(const char *data, u32 seed, size_t len)
{
- return btrfs_crc32c(seed, data, len);
+ return crc32c(seed, data, len);
}
void btrfs_csum_final(u32 crc, u8 *result)
@@ -403,8 +403,7 @@ static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
if (csum_type == BTRFS_CSUM_TYPE_CRC32) {
u32 crc = ~(u32)0;
- const int csum_size = sizeof(crc);
- char result[csum_size];
+ char result[sizeof(crc)];
/*
* The super_block structure does not span the whole
@@ -415,7 +414,7 @@ static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
btrfs_csum_final(crc, result);
- if (memcmp(raw_disk_sb, result, csum_size))
+ if (memcmp(raw_disk_sb, result, sizeof(result)))
ret = 1;
}
@@ -428,13 +427,59 @@ static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
return ret;
}
+static int verify_level_key(struct btrfs_fs_info *fs_info,
+ struct extent_buffer *eb, int level,
+ struct btrfs_key *first_key)
+{
+ int found_level;
+ struct btrfs_key found_key;
+ int ret;
+
+ found_level = btrfs_header_level(eb);
+ if (found_level != level) {
+#ifdef CONFIG_BTRFS_DEBUG
+ WARN_ON(1);
+ btrfs_err(fs_info,
+"tree level mismatch detected, bytenr=%llu level expected=%u has=%u",
+ eb->start, level, found_level);
+#endif
+ return -EIO;
+ }
+
+ if (!first_key)
+ return 0;
+
+ if (found_level)
+ btrfs_node_key_to_cpu(eb, &found_key, 0);
+ else
+ btrfs_item_key_to_cpu(eb, &found_key, 0);
+ ret = btrfs_comp_cpu_keys(first_key, &found_key);
+
+#ifdef CONFIG_BTRFS_DEBUG
+ if (ret) {
+ WARN_ON(1);
+ btrfs_err(fs_info,
+"tree first key mismatch detected, bytenr=%llu key expected=(%llu, %u, %llu) has=(%llu, %u, %llu)",
+ eb->start, first_key->objectid, first_key->type,
+ first_key->offset, found_key.objectid,
+ found_key.type, found_key.offset);
+ }
+#endif
+ return ret;
+}
+
/*
* helper to read a given tree block, doing retries as required when
* the checksums don't match and we have alternate mirrors to try.
+ *
+ * @parent_transid: expected transid, skip check if 0
+ * @level: expected level, mandatory check
+ * @first_key: expected key of first slot, skip check if NULL
*/
static int btree_read_extent_buffer_pages(struct btrfs_fs_info *fs_info,
struct extent_buffer *eb,
- u64 parent_transid)
+ u64 parent_transid, int level,
+ struct btrfs_key *first_key)
{
struct extent_io_tree *io_tree;
int failed = 0;
@@ -449,11 +494,14 @@ static int btree_read_extent_buffer_pages(struct btrfs_fs_info *fs_info,
ret = read_extent_buffer_pages(io_tree, eb, WAIT_COMPLETE,
mirror_num);
if (!ret) {
- if (!verify_parent_transid(io_tree, eb,
+ if (verify_parent_transid(io_tree, eb,
parent_transid, 0))
- break;
- else
ret = -EIO;
+ else if (verify_level_key(fs_info, eb, level,
+ first_key))
+ ret = -EUCLEAN;
+ else
+ break;
}
/*
@@ -461,7 +509,8 @@ static int btree_read_extent_buffer_pages(struct btrfs_fs_info *fs_info,
* there is no reason to read the other copies, they won't be
* any less wrong.
*/
- if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags))
+ if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags) ||
+ ret == -EUCLEAN)
break;
num_copies = btrfs_num_copies(fs_info,
@@ -602,12 +651,12 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
* that we don't try and read the other copies of this block, just
* return -EIO.
*/
- if (found_level == 0 && btrfs_check_leaf_full(root, eb)) {
+ if (found_level == 0 && btrfs_check_leaf_full(fs_info, eb)) {
set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
ret = -EIO;
}
- if (found_level > 0 && btrfs_check_node(root, eb))
+ if (found_level > 0 && btrfs_check_node(fs_info, eb))
ret = -EIO;
if (!ret)
@@ -710,14 +759,6 @@ blk_status_t btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio,
return 0;
}
-unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info)
-{
- unsigned long limit = min_t(unsigned long,
- info->thread_pool_size,
- info->fs_devices->open_devices);
- return 256 * limit;
-}
-
static void run_one_async_start(struct btrfs_work *work)
{
struct async_submit_bio *async;
@@ -725,7 +766,6 @@ static void run_one_async_start(struct btrfs_work *work)
async = container_of(work, struct async_submit_bio, work);
ret = async->submit_bio_start(async->private_data, async->bio,
- async->mirror_num, async->bio_flags,
async->bio_offset);
if (ret)
async->status = ret;
@@ -744,8 +784,7 @@ static void run_one_async_done(struct btrfs_work *work)
return;
}
- async->submit_bio_done(async->private_data, async->bio, async->mirror_num,
- async->bio_flags, async->bio_offset);
+ async->submit_bio_done(async->private_data, async->bio, async->mirror_num);
}
static void run_one_async_free(struct btrfs_work *work)
@@ -759,8 +798,8 @@ static void run_one_async_free(struct btrfs_work *work)
blk_status_t btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
int mirror_num, unsigned long bio_flags,
u64 bio_offset, void *private_data,
- extent_submit_bio_hook_t *submit_bio_start,
- extent_submit_bio_hook_t *submit_bio_done)
+ extent_submit_bio_start_t *submit_bio_start,
+ extent_submit_bio_done_t *submit_bio_done)
{
struct async_submit_bio *async;
@@ -807,8 +846,7 @@ static blk_status_t btree_csum_one_bio(struct bio *bio)
return errno_to_blk_status(ret);
}
-static blk_status_t __btree_submit_bio_start(void *private_data, struct bio *bio,
- int mirror_num, unsigned long bio_flags,
+static blk_status_t btree_submit_bio_start(void *private_data, struct bio *bio,
u64 bio_offset)
{
/*
@@ -818,9 +856,8 @@ static blk_status_t __btree_submit_bio_start(void *private_data, struct bio *bio
return btree_csum_one_bio(bio);
}
-static blk_status_t __btree_submit_bio_done(void *private_data, struct bio *bio,
- int mirror_num, unsigned long bio_flags,
- u64 bio_offset)
+static blk_status_t btree_submit_bio_done(void *private_data, struct bio *bio,
+ int mirror_num)
{
struct inode *inode = private_data;
blk_status_t ret;
@@ -879,8 +916,8 @@ static blk_status_t btree_submit_bio_hook(void *private_data, struct bio *bio,
*/
ret = btrfs_wq_submit_bio(fs_info, bio, mirror_num, 0,
bio_offset, private_data,
- __btree_submit_bio_start,
- __btree_submit_bio_done);
+ btree_submit_bio_start,
+ btree_submit_bio_done);
}
if (ret)
@@ -1062,8 +1099,17 @@ void btrfs_wait_tree_block_writeback(struct extent_buffer *buf)
buf->start, buf->start + buf->len - 1);
}
+/*
+ * Read tree block at logical address @bytenr and do variant basic but critical
+ * verification.
+ *
+ * @parent_transid: expected transid of this tree block, skip check if 0
+ * @level: expected level, mandatory check
+ * @first_key: expected key in slot 0, skip check if NULL
+ */
struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
- u64 parent_transid)
+ u64 parent_transid, int level,
+ struct btrfs_key *first_key)
{
struct extent_buffer *buf = NULL;
int ret;
@@ -1072,7 +1118,8 @@ struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
if (IS_ERR(buf))
return buf;
- ret = btree_read_extent_buffer_pages(fs_info, buf, parent_transid);
+ ret = btree_read_extent_buffer_pages(fs_info, buf, parent_transid,
+ level, first_key);
if (ret) {
free_extent_buffer(buf);
return ERR_PTR(ret);
@@ -1108,7 +1155,7 @@ static struct btrfs_subvolume_writers *btrfs_alloc_subvolume_writers(void)
if (!writers)
return ERR_PTR(-ENOMEM);
- ret = percpu_counter_init(&writers->counter, 0, GFP_KERNEL);
+ ret = percpu_counter_init(&writers->counter, 0, GFP_NOFS);
if (ret < 0) {
kfree(writers);
return ERR_PTR(ret);
@@ -1160,6 +1207,7 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
spin_lock_init(&root->accounting_lock);
spin_lock_init(&root->log_extents_lock[0]);
spin_lock_init(&root->log_extents_lock[1]);
+ spin_lock_init(&root->qgroup_meta_rsv_lock);
mutex_init(&root->objectid_mutex);
mutex_init(&root->log_mutex);
mutex_init(&root->ordered_extent_mutex);
@@ -1176,7 +1224,6 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
atomic_set(&root->orphan_inodes, 0);
refcount_set(&root->refs, 1);
atomic_set(&root->will_be_snapshotted, 0);
- atomic64_set(&root->qgroup_meta_rsv, 0);
root->log_transid = 0;
root->log_transid_committed = -1;
root->last_log_commit = 0;
@@ -1401,6 +1448,7 @@ static struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
struct btrfs_path *path;
u64 generation;
int ret;
+ int level;
path = btrfs_alloc_path();
if (!path)
@@ -1423,9 +1471,10 @@ static struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
}
generation = btrfs_root_generation(&root->root_item);
+ level = btrfs_root_level(&root->root_item);
root->node = read_tree_block(fs_info,
btrfs_root_bytenr(&root->root_item),
- generation);
+ generation, level, NULL);
if (IS_ERR(root->node)) {
ret = PTR_ERR(root->node);
goto find_fail;
@@ -1808,12 +1857,10 @@ sleep:
if (unlikely(test_bit(BTRFS_FS_STATE_ERROR,
&fs_info->fs_state)))
btrfs_cleanup_transaction(fs_info);
- set_current_state(TASK_INTERRUPTIBLE);
if (!kthread_should_stop() &&
(!btrfs_transaction_blocked(fs_info) ||
cannot_commit))
- schedule_timeout(delay);
- __set_current_state(TASK_RUNNING);
+ schedule_timeout_interruptible(delay);
} while (!kthread_should_stop());
return 0;
}
@@ -2183,7 +2230,7 @@ static void btrfs_init_qgroup(struct btrfs_fs_info *fs_info)
static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info,
struct btrfs_fs_devices *fs_devices)
{
- int max_active = fs_info->thread_pool_size;
+ u32 max_active = fs_info->thread_pool_size;
unsigned int flags = WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_UNBOUND;
fs_info->workers =
@@ -2276,6 +2323,7 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
struct btrfs_root *log_tree_root;
struct btrfs_super_block *disk_super = fs_info->super_copy;
u64 bytenr = btrfs_super_log_root(disk_super);
+ int level = btrfs_super_log_root_level(disk_super);
if (fs_devices->rw_devices == 0) {
btrfs_warn(fs_info, "log replay required on RO media");
@@ -2289,7 +2337,8 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
__setup_root(log_tree_root, fs_info, BTRFS_TREE_LOG_OBJECTID);
log_tree_root->node = read_tree_block(fs_info, bytenr,
- fs_info->generation + 1);
+ fs_info->generation + 1,
+ level, NULL);
if (IS_ERR(log_tree_root->node)) {
btrfs_warn(fs_info, "failed to read log tree");
ret = PTR_ERR(log_tree_root->node);
@@ -2334,23 +2383,29 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info)
location.offset = 0;
root = btrfs_read_tree_root(tree_root, &location);
- if (IS_ERR(root))
- return PTR_ERR(root);
+ if (IS_ERR(root)) {
+ ret = PTR_ERR(root);
+ goto out;
+ }
set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state);
fs_info->extent_root = root;
location.objectid = BTRFS_DEV_TREE_OBJECTID;
root = btrfs_read_tree_root(tree_root, &location);
- if (IS_ERR(root))
- return PTR_ERR(root);
+ if (IS_ERR(root)) {
+ ret = PTR_ERR(root);
+ goto out;
+ }
set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state);
fs_info->dev_root = root;
btrfs_init_devices_late(fs_info);
location.objectid = BTRFS_CSUM_TREE_OBJECTID;
root = btrfs_read_tree_root(tree_root, &location);
- if (IS_ERR(root))
- return PTR_ERR(root);
+ if (IS_ERR(root)) {
+ ret = PTR_ERR(root);
+ goto out;
+ }
set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state);
fs_info->csum_root = root;
@@ -2367,7 +2422,7 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info)
if (IS_ERR(root)) {
ret = PTR_ERR(root);
if (ret != -ENOENT)
- return ret;
+ goto out;
} else {
set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state);
fs_info->uuid_root = root;
@@ -2376,13 +2431,19 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info)
if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
location.objectid = BTRFS_FREE_SPACE_TREE_OBJECTID;
root = btrfs_read_tree_root(tree_root, &location);
- if (IS_ERR(root))
- return PTR_ERR(root);
+ if (IS_ERR(root)) {
+ ret = PTR_ERR(root);
+ goto out;
+ }
set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state);
fs_info->free_space_root = root;
}
return 0;
+out:
+ btrfs_warn(fs_info, "failed to read root (objectid=%llu): %d",
+ location.objectid, ret);
+ return ret;
}
int open_ctree(struct super_block *sb,
@@ -2404,8 +2465,8 @@ int open_ctree(struct super_block *sb,
int err = -EINVAL;
int num_backups_tried = 0;
int backup_index = 0;
- int max_active;
int clear_free_space_tree = 0;
+ int level;
tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info, GFP_KERNEL);
chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info, GFP_KERNEL);
@@ -2447,6 +2508,8 @@ int open_ctree(struct super_block *sb,
INIT_LIST_HEAD(&fs_info->delayed_iputs);
INIT_LIST_HEAD(&fs_info->delalloc_roots);
INIT_LIST_HEAD(&fs_info->caching_block_groups);
+ INIT_LIST_HEAD(&fs_info->pending_raid_kobjs);
+ spin_lock_init(&fs_info->pending_raid_kobjs_lock);
spin_lock_init(&fs_info->delalloc_root_lock);
spin_lock_init(&fs_info->trans_lock);
spin_lock_init(&fs_info->fs_roots_radix_lock);
@@ -2713,8 +2776,6 @@ int open_ctree(struct super_block *sb,
goto fail_alloc;
}
- max_active = fs_info->thread_pool_size;
-
ret = btrfs_init_workqueues(fs_info, fs_devices);
if (ret) {
err = ret;
@@ -2741,12 +2802,13 @@ int open_ctree(struct super_block *sb,
}
generation = btrfs_super_chunk_root_generation(disk_super);
+ level = btrfs_super_chunk_root_level(disk_super);
__setup_root(chunk_root, fs_info, BTRFS_CHUNK_TREE_OBJECTID);
chunk_root->node = read_tree_block(fs_info,
btrfs_super_chunk_root(disk_super),
- generation);
+ generation, level, NULL);
if (IS_ERR(chunk_root->node) ||
!extent_buffer_uptodate(chunk_root->node)) {
btrfs_err(fs_info, "failed to read chunk root");
@@ -2768,10 +2830,10 @@ int open_ctree(struct super_block *sb,
}
/*
- * keep the device that is marked to be the target device for the
- * dev_replace procedure
+ * Keep the devid that is marked to be the target device for the
+ * device replace procedure
*/
- btrfs_close_extra_devices(fs_devices, 0);
+ btrfs_free_extra_devids(fs_devices, 0);
if (!fs_devices->latest_bdev) {
btrfs_err(fs_info, "failed to read devices");
@@ -2780,10 +2842,11 @@ int open_ctree(struct super_block *sb,
retry_root_backup:
generation = btrfs_super_generation(disk_super);
+ level = btrfs_super_root_level(disk_super);
tree_root->node = read_tree_block(fs_info,
btrfs_super_root(disk_super),
- generation);
+ generation, level, NULL);
if (IS_ERR(tree_root->node) ||
!extent_buffer_uptodate(tree_root->node)) {
btrfs_warn(fs_info, "failed to read tree root");
@@ -2834,7 +2897,7 @@ retry_root_backup:
goto fail_block_groups;
}
- btrfs_close_extra_devices(fs_devices, 1);
+ btrfs_free_extra_devids(fs_devices, 1);
ret = btrfs_sysfs_add_fsid(fs_devices, NULL);
if (ret) {
@@ -2953,6 +3016,7 @@ retry_root_backup:
fs_info->fs_root = btrfs_read_fs_root_no_name(fs_info, &location);
if (IS_ERR(fs_info->fs_root)) {
err = PTR_ERR(fs_info->fs_root);
+ btrfs_warn(fs_info, "failed to read fs tree: %d", err);
goto fail_qgroup;
}
@@ -3290,6 +3354,7 @@ static int wait_dev_supers(struct btrfs_device *device, int max_mirrors)
struct buffer_head *bh;
int i;
int errors = 0;
+ bool primary_failed = false;
u64 bytenr;
if (max_mirrors == 0)
@@ -3306,11 +3371,16 @@ static int wait_dev_supers(struct btrfs_device *device, int max_mirrors)
BTRFS_SUPER_INFO_SIZE);
if (!bh) {
errors++;
+ if (i == 0)
+ primary_failed = true;
continue;
}
wait_on_buffer(bh);
- if (!buffer_uptodate(bh))
+ if (!buffer_uptodate(bh)) {
errors++;
+ if (i == 0)
+ primary_failed = true;
+ }
/* drop our reference */
brelse(bh);
@@ -3319,6 +3389,13 @@ static int wait_dev_supers(struct btrfs_device *device, int max_mirrors)
brelse(bh);
}
+ /* log error, force error return */
+ if (primary_failed) {
+ btrfs_err(device->fs_info, "error writing primary super block to device %llu",
+ device->devid);
+ return -1;
+ }
+
return errors < i ? 0 : -1;
}
@@ -3851,7 +3928,7 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
* So here we should only check item pointers, not item data.
*/
if (btrfs_header_level(buf) == 0 &&
- btrfs_check_leaf_relaxed(root, buf)) {
+ btrfs_check_leaf_relaxed(fs_info, buf)) {
btrfs_print_leaf(buf);
ASSERT(0);
}
@@ -3890,12 +3967,14 @@ void btrfs_btree_balance_dirty_nodelay(struct btrfs_fs_info *fs_info)
__btrfs_btree_balance_dirty(fs_info, 0);
}
-int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
+int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid, int level,
+ struct btrfs_key *first_key)
{
struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
struct btrfs_fs_info *fs_info = root->fs_info;
- return btree_read_extent_buffer_pages(fs_info, buf, parent_transid);
+ return btree_read_extent_buffer_pages(fs_info, buf, parent_transid,
+ level, first_key);
}
static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info)
@@ -4314,11 +4393,6 @@ void btrfs_cleanup_dirty_bgs(struct btrfs_transaction *cur_trans,
cache = list_first_entry(&cur_trans->dirty_bgs,
struct btrfs_block_group_cache,
dirty_list);
- if (!cache) {
- btrfs_err(fs_info, "orphan block group dirty_bgs list");
- spin_unlock(&cur_trans->dirty_bgs_lock);
- return;
- }
if (!list_empty(&cache->io_list)) {
spin_unlock(&cur_trans->dirty_bgs_lock);
@@ -4338,14 +4412,14 @@ void btrfs_cleanup_dirty_bgs(struct btrfs_transaction *cur_trans,
}
spin_unlock(&cur_trans->dirty_bgs_lock);
+ /*
+ * Refer to the definition of io_bgs member for details why it's safe
+ * to use it without any locking
+ */
while (!list_empty(&cur_trans->io_bgs)) {
cache = list_first_entry(&cur_trans->io_bgs,
struct btrfs_block_group_cache,
io_list);
- if (!cache) {
- btrfs_err(fs_info, "orphan block group on io_bgs list");
- return;
- }
list_del_init(&cache->io_list);
spin_lock(&cache->lock);
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index 301151a50ac1..453ea9f5d4e9 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -52,8 +52,9 @@ static inline u64 btrfs_sb_offset(int mirror)
struct btrfs_device;
struct btrfs_fs_devices;
-struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info,
- u64 bytenr, u64 parent_transid);
+struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
+ u64 parent_transid, int level,
+ struct btrfs_key *first_key);
void readahead_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr);
int reada_tree_block_flagged(struct btrfs_fs_info *fs_info, u64 bytenr,
int mirror_num, struct extent_buffer **eb);
@@ -123,7 +124,8 @@ static inline void btrfs_put_fs_root(struct btrfs_root *root)
void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
int atomic);
-int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid);
+int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid, int level,
+ struct btrfs_key *first_key);
u32 btrfs_csum_data(const char *data, u32 seed, size_t len);
void btrfs_csum_final(u32 crc, u8 *result);
blk_status_t btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio,
@@ -131,9 +133,8 @@ blk_status_t btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio,
blk_status_t btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
int mirror_num, unsigned long bio_flags,
u64 bio_offset, void *private_data,
- extent_submit_bio_hook_t *submit_bio_start,
- extent_submit_bio_hook_t *submit_bio_done);
-unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info);
+ extent_submit_bio_start_t *submit_bio_start,
+ extent_submit_bio_done_t *submit_bio_done);
int btrfs_write_tree_block(struct extent_buffer *buf);
void btrfs_wait_tree_block_writeback(struct extent_buffer *buf);
int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
@@ -154,7 +155,7 @@ struct extent_map *btree_get_extent(struct btrfs_inode *inode,
int create);
int btrfs_get_num_tolerated_disk_barrier_failures(u64 flags);
int __init btrfs_end_io_wq_init(void);
-void btrfs_end_io_wq_exit(void);
+void __cold btrfs_end_io_wq_exit(void);
#ifdef CONFIG_DEBUG_LOCK_ALLOC
void btrfs_init_lockdep(void);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index e0460d7b5622..e08d0d45af4f 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -27,7 +27,7 @@
#include <linux/ratelimit.h>
#include <linux/percpu_counter.h>
#include <linux/lockdep.h>
-#include "hash.h"
+#include <linux/crc32c.h>
#include "tree-log.h"
#include "disk-io.h"
#include "print-tree.h"
@@ -535,13 +535,11 @@ static noinline void caching_thread(struct btrfs_work *work)
struct btrfs_block_group_cache *block_group;
struct btrfs_fs_info *fs_info;
struct btrfs_caching_control *caching_ctl;
- struct btrfs_root *extent_root;
int ret;
caching_ctl = container_of(work, struct btrfs_caching_control, work);
block_group = caching_ctl->block_group;
fs_info = block_group->fs_info;
- extent_root = fs_info->extent_root;
mutex_lock(&caching_ctl->mutex);
down_read(&fs_info->commit_root_sem);
@@ -1203,11 +1201,11 @@ static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset)
__le64 lenum;
lenum = cpu_to_le64(root_objectid);
- high_crc = btrfs_crc32c(high_crc, &lenum, sizeof(lenum));
+ high_crc = crc32c(high_crc, &lenum, sizeof(lenum));
lenum = cpu_to_le64(owner);
- low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum));
+ low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
lenum = cpu_to_le64(offset);
- low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum));
+ low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
return ((u64)high_crc << 31) ^ (u64)low_crc;
}
@@ -2652,9 +2650,9 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans,
* Returns -ENOMEM or -EIO on failure and will abort the transaction.
*/
static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info,
unsigned long nr)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_delayed_ref_root *delayed_refs;
struct btrfs_delayed_ref_node *ref;
struct btrfs_delayed_ref_head *locked_ref = NULL;
@@ -2994,7 +2992,7 @@ static void delayed_ref_async_start(struct btrfs_work *work)
if (trans->transid > async->transid)
goto end;
- ret = btrfs_run_delayed_refs(trans, fs_info, async->count);
+ ret = btrfs_run_delayed_refs(trans, async->count);
if (ret)
async->error = ret;
end:
@@ -3053,8 +3051,9 @@ int btrfs_async_run_delayed_refs(struct btrfs_fs_info *fs_info,
* Returns <0 on error and aborts the transaction
*/
int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info, unsigned long count)
+ unsigned long count)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct rb_node *node;
struct btrfs_delayed_ref_root *delayed_refs;
struct btrfs_delayed_ref_head *head;
@@ -3078,7 +3077,7 @@ again:
delayed_refs->run_delayed_start = find_middle(&delayed_refs->root);
#endif
trans->can_flush_pending_bgs = false;
- ret = __btrfs_run_delayed_refs(trans, fs_info, count);
+ ret = __btrfs_run_delayed_refs(trans, count);
if (ret < 0) {
btrfs_abort_transaction(trans, ret);
return ret;
@@ -3086,7 +3085,7 @@ again:
if (run_all) {
if (!list_empty(&trans->new_bgs))
- btrfs_create_pending_block_groups(trans, fs_info);
+ btrfs_create_pending_block_groups(trans);
spin_lock(&delayed_refs->lock);
node = rb_first(&delayed_refs->href_root);
@@ -3660,9 +3659,9 @@ int btrfs_setup_space_cache(struct btrfs_trans_handle *trans,
* the commit latency by getting rid of the easy block groups while
* we're still allowing others to join the commit.
*/
-int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info)
+int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_block_group_cache *cache;
struct btrfs_transaction *cur_trans = trans->transaction;
int ret = 0;
@@ -3686,7 +3685,7 @@ again:
* make sure all the block groups on our dirty list actually
* exist
*/
- btrfs_create_pending_block_groups(trans, fs_info);
+ btrfs_create_pending_block_groups(trans);
if (!path) {
path = btrfs_alloc_path();
@@ -3741,8 +3740,9 @@ again:
should_put = 0;
/*
- * the cache_write_mutex is protecting
- * the io_list
+ * The cache_write_mutex is protecting the
+ * io_list, also refer to the definition of
+ * btrfs_transaction::io_bgs for more details
*/
list_add_tail(&cache->io_list, io);
} else {
@@ -3800,7 +3800,7 @@ again:
* go through delayed refs for all the stuff we've just kicked off
* and then loop back (just once)
*/
- ret = btrfs_run_delayed_refs(trans, fs_info, 0);
+ ret = btrfs_run_delayed_refs(trans, 0);
if (!ret && loops == 0) {
loops++;
spin_lock(&cur_trans->dirty_bgs_lock);
@@ -3882,7 +3882,7 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
cache_save_setup(cache, trans, path);
if (!ret)
- ret = btrfs_run_delayed_refs(trans, fs_info,
+ ret = btrfs_run_delayed_refs(trans,
(unsigned long) -1);
if (!ret && cache->disk_cache_state == BTRFS_DC_SETUP) {
@@ -3934,6 +3934,10 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
}
spin_unlock(&cur_trans->dirty_bgs_lock);
+ /*
+ * Refer to the definition of io_bgs member for details why it's safe
+ * to use it without any locking
+ */
while (!list_empty(io)) {
cache = list_first_entry(io, struct btrfs_block_group_cache,
io_list);
@@ -4332,8 +4336,7 @@ again:
/* commit the current transaction and try again */
commit_trans:
- if (need_commit &&
- !atomic_read(&fs_info->open_ioctl_trans)) {
+ if (need_commit) {
need_commit--;
if (need_commit > 0) {
@@ -4541,7 +4544,7 @@ void check_system_chunk(struct btrfs_trans_handle *trans,
* Needed because we can end up allocating a system chunk and for an
* atomic and race free space reservation in the chunk block reserve.
*/
- ASSERT(mutex_is_locked(&fs_info->chunk_mutex));
+ lockdep_assert_held(&fs_info->chunk_mutex);
info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
spin_lock(&info->lock);
@@ -4602,11 +4605,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
return -ENOSPC;
space_info = __find_space_info(fs_info, flags);
- if (!space_info) {
- ret = create_space_info(fs_info, flags, &space_info);
- if (ret)
- return ret;
- }
+ ASSERT(space_info);
again:
spin_lock(&space_info->lock);
@@ -4705,7 +4704,7 @@ out:
*/
if (trans->can_flush_pending_bgs &&
trans->chunk_bytes_reserved >= (u64)SZ_2M) {
- btrfs_create_pending_block_groups(trans, fs_info);
+ btrfs_create_pending_block_groups(trans);
btrfs_trans_release_chunk_metadata(trans);
}
return ret;
@@ -4826,7 +4825,6 @@ static void shrink_delalloc(struct btrfs_fs_info *fs_info, u64 to_reclaim,
long time_left;
unsigned long nr_pages;
int loops;
- enum btrfs_reserve_flush_enum flush;
/* Calc the number of the pages we need flush for space reservation */
items = calc_reclaim_items_nr(fs_info, to_reclaim);
@@ -4867,10 +4865,6 @@ static void shrink_delalloc(struct btrfs_fs_info *fs_info, u64 to_reclaim,
atomic_read(&fs_info->async_delalloc_pages) <=
(int)max_reclaim);
skip_async:
- if (!trans)
- flush = BTRFS_RESERVE_FLUSH_ALL;
- else
- flush = BTRFS_RESERVE_NO_FLUSH;
spin_lock(&space_info->lock);
if (list_empty(&space_info->tickets) &&
list_empty(&space_info->priority_tickets)) {
@@ -4993,7 +4987,7 @@ static void flush_space(struct btrfs_fs_info *fs_info,
ret = PTR_ERR(trans);
break;
}
- ret = btrfs_run_delayed_items_nr(trans, fs_info, nr);
+ ret = btrfs_run_delayed_items_nr(trans, nr);
btrfs_end_transaction(trans);
break;
case FLUSH_DELALLOC:
@@ -5388,10 +5382,15 @@ static int reserve_metadata_bytes(struct btrfs_root *root,
!block_rsv_use_bytes(global_rsv, orig_bytes))
ret = 0;
}
- if (ret == -ENOSPC)
+ if (ret == -ENOSPC) {
trace_btrfs_space_reservation(fs_info, "space_info:enospc",
block_rsv->space_info->flags,
orig_bytes, 1);
+
+ if (btrfs_test_opt(fs_info, ENOSPC_DEBUG))
+ dump_space_info(fs_info, block_rsv->space_info,
+ orig_bytes, 0);
+ }
return ret;
}
@@ -5760,6 +5759,9 @@ static int btrfs_inode_rsv_refill(struct btrfs_inode *inode,
if (num_bytes == 0)
return 0;
+ ret = btrfs_qgroup_reserve_meta_prealloc(root, num_bytes, true);
+ if (ret)
+ return ret;
ret = reserve_metadata_bytes(root, block_rsv, num_bytes, flush);
if (!ret) {
block_rsv_add_bytes(block_rsv, num_bytes, 0);
@@ -5772,11 +5774,15 @@ static int btrfs_inode_rsv_refill(struct btrfs_inode *inode,
/**
* btrfs_inode_rsv_release - release any excessive reservation.
* @inode - the inode we need to release from.
+ * @qgroup_free - free or convert qgroup meta.
+ * Unlike normal operation, qgroup meta reservation needs to know if we are
+ * freeing qgroup reservation or just converting it into per-trans. Normally
+ * @qgroup_free is true for error handling, and false for normal release.
*
* This is the same as btrfs_block_rsv_release, except that it handles the
* tracepoint for the reservation.
*/
-static void btrfs_inode_rsv_release(struct btrfs_inode *inode)
+static void btrfs_inode_rsv_release(struct btrfs_inode *inode, bool qgroup_free)
{
struct btrfs_fs_info *fs_info = inode->root->fs_info;
struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
@@ -5792,6 +5798,10 @@ static void btrfs_inode_rsv_release(struct btrfs_inode *inode)
if (released > 0)
trace_btrfs_space_reservation(fs_info, "delalloc",
btrfs_ino(inode), released, 0);
+ if (qgroup_free)
+ btrfs_qgroup_free_meta_prealloc(inode->root, released);
+ else
+ btrfs_qgroup_convert_reserved_meta(inode->root, released);
}
void btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
@@ -5892,24 +5902,6 @@ static void release_global_block_rsv(struct btrfs_fs_info *fs_info)
WARN_ON(fs_info->delayed_block_rsv.reserved > 0);
}
-void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info)
-{
- if (!trans->block_rsv) {
- ASSERT(!trans->bytes_reserved);
- return;
- }
-
- if (!trans->bytes_reserved)
- return;
-
- ASSERT(trans->block_rsv == &fs_info->trans_block_rsv);
- trace_btrfs_space_reservation(fs_info, "transaction",
- trans->transid, trans->bytes_reserved, 0);
- btrfs_block_rsv_release(fs_info, trans->block_rsv,
- trans->bytes_reserved);
- trans->bytes_reserved = 0;
-}
/*
* To be called after all the new block groups attached to the transaction
@@ -5951,7 +5943,7 @@ int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
*/
u64 num_bytes = btrfs_calc_trans_metadata_size(fs_info, 1);
- trace_btrfs_space_reservation(fs_info, "orphan", btrfs_ino(inode),
+ trace_btrfs_space_reservation(fs_info, "orphan", btrfs_ino(inode),
num_bytes, 1);
return btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes, 1);
}
@@ -5995,7 +5987,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
/* One for parent inode, two for dir entries */
num_bytes = 3 * fs_info->nodesize;
- ret = btrfs_qgroup_reserve_meta(root, num_bytes, true);
+ ret = btrfs_qgroup_reserve_meta_prealloc(root, num_bytes, true);
if (ret)
return ret;
} else {
@@ -6014,7 +6006,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes, 1);
if (ret && *qgroup_reserved)
- btrfs_qgroup_free_meta(root, *qgroup_reserved);
+ btrfs_qgroup_free_meta_prealloc(root, *qgroup_reserved);
return ret;
}
@@ -6051,7 +6043,6 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info,
int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
{
struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb);
- struct btrfs_root *root = inode->root;
unsigned nr_extents;
enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL;
int ret = 0;
@@ -6068,13 +6059,13 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
if (btrfs_is_free_space_inode(inode)) {
flush = BTRFS_RESERVE_NO_FLUSH;
delalloc_lock = false;
- } else if (current->journal_info) {
- flush = BTRFS_RESERVE_FLUSH_LIMIT;
- }
+ } else {
+ if (current->journal_info)
+ flush = BTRFS_RESERVE_FLUSH_LIMIT;
- if (flush != BTRFS_RESERVE_NO_FLUSH &&
- btrfs_transaction_in_commit(fs_info))
- schedule_timeout(1);
+ if (btrfs_transaction_in_commit(fs_info))
+ schedule_timeout(1);
+ }
if (delalloc_lock)
mutex_lock(&inode->delalloc_mutex);
@@ -6089,19 +6080,9 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes)
btrfs_calculate_inode_block_rsv_size(fs_info, inode);
spin_unlock(&inode->lock);
- if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
- ret = btrfs_qgroup_reserve_meta(root,
- nr_extents * fs_info->nodesize, true);
- if (ret)
- goto out_fail;
- }
-
ret = btrfs_inode_rsv_refill(inode, flush);
- if (unlikely(ret)) {
- btrfs_qgroup_free_meta(root,
- nr_extents * fs_info->nodesize);
+ if (unlikely(ret))
goto out_fail;
- }
if (delalloc_lock)
mutex_unlock(&inode->delalloc_mutex);
@@ -6115,7 +6096,7 @@ out_fail:
btrfs_calculate_inode_block_rsv_size(fs_info, inode);
spin_unlock(&inode->lock);
- btrfs_inode_rsv_release(inode);
+ btrfs_inode_rsv_release(inode, true);
if (delalloc_lock)
mutex_unlock(&inode->delalloc_mutex);
return ret;
@@ -6125,12 +6106,14 @@ out_fail:
* btrfs_delalloc_release_metadata - release a metadata reservation for an inode
* @inode: the inode to release the reservation for.
* @num_bytes: the number of bytes we are releasing.
+ * @qgroup_free: free qgroup reservation or convert it to per-trans reservation
*
* This will release the metadata reservation for an inode. This can be called
* once we complete IO for a given set of bytes to release their metadata
* reservations, or on error for the same reason.
*/
-void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes)
+void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes,
+ bool qgroup_free)
{
struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb);
@@ -6143,13 +6126,14 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes)
if (btrfs_is_testing(fs_info))
return;
- btrfs_inode_rsv_release(inode);
+ btrfs_inode_rsv_release(inode, qgroup_free);
}
/**
* btrfs_delalloc_release_extents - release our outstanding_extents
* @inode: the inode to balance the reservation for.
* @num_bytes: the number of bytes we originally reserved with
+ * @qgroup_free: do we need to free qgroup meta reservation or convert them.
*
* When we reserve space we increase outstanding_extents for the extents we may
* add. Once we've set the range as delalloc or created our ordered extents we
@@ -6157,7 +6141,8 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes)
* temporarily tracked outstanding_extents. This _must_ be used in conjunction
* with btrfs_delalloc_reserve_metadata.
*/
-void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes)
+void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes,
+ bool qgroup_free)
{
struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb);
unsigned num_extents;
@@ -6171,7 +6156,7 @@ void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes)
if (btrfs_is_testing(fs_info))
return;
- btrfs_inode_rsv_release(inode);
+ btrfs_inode_rsv_release(inode, qgroup_free);
}
/**
@@ -6227,9 +6212,9 @@ int btrfs_delalloc_reserve_space(struct inode *inode,
*/
void btrfs_delalloc_release_space(struct inode *inode,
struct extent_changeset *reserved,
- u64 start, u64 len)
+ u64 start, u64 len, bool qgroup_free)
{
- btrfs_delalloc_release_metadata(BTRFS_I(inode), len);
+ btrfs_delalloc_release_metadata(BTRFS_I(inode), len, qgroup_free);
btrfs_free_reserved_data_space(inode, reserved, start, len);
}
@@ -6783,9 +6768,9 @@ static int unpin_extent_range(struct btrfs_fs_info *fs_info,
return 0;
}
-int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info)
+int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_block_group_cache *block_group, *tmp;
struct list_head *deleted_bgs;
struct extent_io_tree *unpin;
@@ -7351,29 +7336,6 @@ wait_block_group_cache_done(struct btrfs_block_group_cache *cache)
return ret;
}
-int __get_raid_index(u64 flags)
-{
- if (flags & BTRFS_BLOCK_GROUP_RAID10)
- return BTRFS_RAID_RAID10;
- else if (flags & BTRFS_BLOCK_GROUP_RAID1)
- return BTRFS_RAID_RAID1;
- else if (flags & BTRFS_BLOCK_GROUP_DUP)
- return BTRFS_RAID_DUP;
- else if (flags & BTRFS_BLOCK_GROUP_RAID0)
- return BTRFS_RAID_RAID0;
- else if (flags & BTRFS_BLOCK_GROUP_RAID5)
- return BTRFS_RAID_RAID5;
- else if (flags & BTRFS_BLOCK_GROUP_RAID6)
- return BTRFS_RAID_RAID6;
-
- return BTRFS_RAID_SINGLE; /* BTRFS_BLOCK_GROUP_SINGLE */
-}
-
-int get_block_group_index(struct btrfs_block_group_cache *cache)
-{
- return __get_raid_index(cache->flags);
-}
-
static const char *btrfs_raid_type_names[BTRFS_NR_RAID_TYPES] = {
[BTRFS_RAID_RAID10] = "raid10",
[BTRFS_RAID_RAID1] = "raid1",
@@ -7488,7 +7450,7 @@ static noinline int find_free_extent(struct btrfs_fs_info *fs_info,
u64 empty_cluster = 0;
struct btrfs_space_info *space_info;
int loop = 0;
- int index = __get_raid_index(flags);
+ int index = btrfs_bg_flags_to_raid_index(flags);
bool failed_cluster_refill = false;
bool failed_alloc = false;
bool use_cluster = true;
@@ -7574,7 +7536,8 @@ static noinline int find_free_extent(struct btrfs_fs_info *fs_info,
btrfs_put_block_group(block_group);
up_read(&space_info->groups_sem);
} else {
- index = get_block_group_index(block_group);
+ index = btrfs_bg_flags_to_raid_index(
+ block_group->flags);
btrfs_lock_block_group(block_group, delalloc);
goto have_block_group;
}
@@ -7584,7 +7547,7 @@ static noinline int find_free_extent(struct btrfs_fs_info *fs_info,
}
search:
have_caching_bg = false;
- if (index == 0 || index == __get_raid_index(flags))
+ if (index == 0 || index == btrfs_bg_flags_to_raid_index(flags))
full_search = true;
down_read(&space_info->groups_sem);
list_for_each_entry(block_group, &space_info->block_groups[index],
@@ -7842,7 +7805,8 @@ checks:
loop:
failed_cluster_refill = false;
failed_alloc = false;
- BUG_ON(index != get_block_group_index(block_group));
+ BUG_ON(btrfs_bg_flags_to_raid_index(block_group->flags) !=
+ index);
btrfs_release_block_group(block_group, delalloc);
cond_resched();
}
@@ -7996,6 +7960,51 @@ again:
up_read(&info->groups_sem);
}
+/*
+ * btrfs_reserve_extent - entry point to the extent allocator. Tries to find a
+ * hole that is at least as big as @num_bytes.
+ *
+ * @root - The root that will contain this extent
+ *
+ * @ram_bytes - The amount of space in ram that @num_bytes take. This
+ * is used for accounting purposes. This value differs
+ * from @num_bytes only in the case of compressed extents.
+ *
+ * @num_bytes - Number of bytes to allocate on-disk.
+ *
+ * @min_alloc_size - Indicates the minimum amount of space that the
+ * allocator should try to satisfy. In some cases
+ * @num_bytes may be larger than what is required and if
+ * the filesystem is fragmented then allocation fails.
+ * However, the presence of @min_alloc_size gives a
+ * chance to try and satisfy the smaller allocation.
+ *
+ * @empty_size - A hint that you plan on doing more COW. This is the
+ * size in bytes the allocator should try to find free
+ * next to the block it returns. This is just a hint and
+ * may be ignored by the allocator.
+ *
+ * @hint_byte - Hint to the allocator to start searching above the byte
+ * address passed. It might be ignored.
+ *
+ * @ins - This key is modified to record the found hole. It will
+ * have the following values:
+ * ins->objectid == start position
+ * ins->flags = BTRFS_EXTENT_ITEM_KEY
+ * ins->offset == the size of the hole.
+ *
+ * @is_data - Boolean flag indicating whether an extent is
+ * allocated for data (true) or metadata (false)
+ *
+ * @delalloc - Boolean flag indicating whether this allocation is for
+ * delalloc or not. If 'true' data_rwsem of block groups
+ * is going to be acquired.
+ *
+ *
+ * Returns 0 when an allocation succeeded or < 0 when an error occurred. In
+ * case -ENOSPC is returned then @ins->offset will contain the size of the
+ * largest available hole the allocator managed to find.
+ */
int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes,
u64 num_bytes, u64 min_alloc_size,
u64 empty_size, u64 hint_byte,
@@ -8699,6 +8708,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
u64 parent;
u32 blocksize;
struct btrfs_key key;
+ struct btrfs_key first_key;
struct extent_buffer *next;
int level = wc->level;
int reada = 0;
@@ -8719,6 +8729,8 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
}
bytenr = btrfs_node_blockptr(path->nodes[level], path->slots[level]);
+ btrfs_node_key_to_cpu(path->nodes[level], &first_key,
+ path->slots[level]);
blocksize = fs_info->nodesize;
next = find_extent_buffer(fs_info, bytenr);
@@ -8783,7 +8795,8 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
if (!next) {
if (reada && level == 1)
reada_walk_down(trans, root, wc, path);
- next = read_tree_block(fs_info, bytenr, generation);
+ next = read_tree_block(fs_info, bytenr, generation, level - 1,
+ &first_key);
if (IS_ERR(next)) {
return PTR_ERR(next);
} else if (!extent_buffer_uptodate(next)) {
@@ -9648,7 +9661,7 @@ int btrfs_can_relocate(struct btrfs_fs_info *fs_info, u64 bytenr)
*/
target = get_restripe_target(fs_info, block_group->flags);
if (target) {
- index = __get_raid_index(extended_to_chunk(target));
+ index = btrfs_bg_flags_to_raid_index(extended_to_chunk(target));
} else {
/*
* this is just a balance, so if we were marked as full
@@ -9662,7 +9675,7 @@ int btrfs_can_relocate(struct btrfs_fs_info *fs_info, u64 bytenr)
goto out;
}
- index = get_block_group_index(block_group);
+ index = btrfs_bg_flags_to_raid_index(block_group->flags);
}
if (index == BTRFS_RAID_RAID10) {
@@ -9911,10 +9924,40 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
return 0;
}
+/* link_block_group will queue up kobjects to add when we're reclaim-safe */
+void btrfs_add_raid_kobjects(struct btrfs_fs_info *fs_info)
+{
+ struct btrfs_space_info *space_info;
+ struct raid_kobject *rkobj;
+ LIST_HEAD(list);
+ int index;
+ int ret = 0;
+
+ spin_lock(&fs_info->pending_raid_kobjs_lock);
+ list_splice_init(&fs_info->pending_raid_kobjs, &list);
+ spin_unlock(&fs_info->pending_raid_kobjs_lock);
+
+ list_for_each_entry(rkobj, &list, list) {
+ space_info = __find_space_info(fs_info, rkobj->flags);
+ index = btrfs_bg_flags_to_raid_index(rkobj->flags);
+
+ ret = kobject_add(&rkobj->kobj, &space_info->kobj,
+ "%s", get_raid_name(index));
+ if (ret) {
+ kobject_put(&rkobj->kobj);
+ break;
+ }
+ }
+ if (ret)
+ btrfs_warn(fs_info,
+ "failed to add kobject for block cache, ignoring");
+}
+
static void link_block_group(struct btrfs_block_group_cache *cache)
{
struct btrfs_space_info *space_info = cache->space_info;
- int index = get_block_group_index(cache);
+ struct btrfs_fs_info *fs_info = cache->fs_info;
+ int index = btrfs_bg_flags_to_raid_index(cache->flags);
bool first = false;
down_write(&space_info->groups_sem);
@@ -9924,27 +9967,20 @@ static void link_block_group(struct btrfs_block_group_cache *cache)
up_write(&space_info->groups_sem);
if (first) {
- struct raid_kobject *rkobj;
- int ret;
-
- rkobj = kzalloc(sizeof(*rkobj), GFP_NOFS);
- if (!rkobj)
- goto out_err;
- rkobj->raid_type = index;
- kobject_init(&rkobj->kobj, &btrfs_raid_ktype);
- ret = kobject_add(&rkobj->kobj, &space_info->kobj,
- "%s", get_raid_name(index));
- if (ret) {
- kobject_put(&rkobj->kobj);
- goto out_err;
+ struct raid_kobject *rkobj = kzalloc(sizeof(*rkobj), GFP_NOFS);
+ if (!rkobj) {
+ btrfs_warn(cache->fs_info,
+ "couldn't alloc memory for raid level kobject");
+ return;
}
+ rkobj->flags = cache->flags;
+ kobject_init(&rkobj->kobj, &btrfs_raid_ktype);
+
+ spin_lock(&fs_info->pending_raid_kobjs_lock);
+ list_add_tail(&rkobj->list, &fs_info->pending_raid_kobjs);
+ spin_unlock(&fs_info->pending_raid_kobjs_lock);
space_info->block_group_kobjs[index] = &rkobj->kobj;
}
-
- return;
-out_err:
- btrfs_warn(cache->fs_info,
- "failed to add kobject for block cache, ignoring");
}
static struct btrfs_block_group_cache *
@@ -10160,6 +10196,7 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
inc_block_group_ro(cache, 1);
}
+ btrfs_add_raid_kobjects(info);
init_global_block_rsv(info);
ret = 0;
error:
@@ -10167,9 +10204,9 @@ error:
return ret;
}
-void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info)
+void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_block_group_cache *block_group, *tmp;
struct btrfs_root *extent_root = fs_info->extent_root;
struct btrfs_block_group_item item;
@@ -10254,15 +10291,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
* with its ->space_info set.
*/
cache->space_info = __find_space_info(fs_info, cache->flags);
- if (!cache->space_info) {
- ret = create_space_info(fs_info, cache->flags,
- &cache->space_info);
- if (ret) {
- btrfs_remove_free_space_cache(cache);
- btrfs_put_block_group(cache);
- return ret;
- }
- }
+ ASSERT(cache->space_info);
ret = btrfs_add_block_group_cache(fs_info, cache);
if (ret) {
@@ -10334,7 +10363,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
block_group->key.offset);
memcpy(&key, &block_group->key, sizeof(key));
- index = get_block_group_index(block_group);
+ index = btrfs_bg_flags_to_raid_index(block_group->flags);
if (block_group->flags & (BTRFS_BLOCK_GROUP_DUP |
BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_RAID10))
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index dfeb74a0be77..47a8fe9d22e8 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -76,8 +76,8 @@ void btrfs_leak_debug_check(void)
while (!list_empty(&buffers)) {
eb = list_entry(buffers.next, struct extent_buffer, leak_list);
- pr_err("BTRFS: buffer leak start %llu len %lu refs %d\n",
- eb->start, eb->len, atomic_read(&eb->refs));
+ pr_err("BTRFS: buffer leak start %llu len %lu refs %d bflags %lu\n",
+ eb->start, eb->len, atomic_read(&eb->refs), eb->bflags);
list_del(&eb->leak_list);
kmem_cache_free(extent_buffer_cache, eb);
}
@@ -119,23 +119,22 @@ struct extent_page_data {
unsigned int sync_io:1;
};
-static void add_extent_changeset(struct extent_state *state, unsigned bits,
+static int add_extent_changeset(struct extent_state *state, unsigned bits,
struct extent_changeset *changeset,
int set)
{
int ret;
if (!changeset)
- return;
+ return 0;
if (set && (state->state & bits) == bits)
- return;
+ return 0;
if (!set && (state->state & bits) == 0)
- return;
+ return 0;
changeset->bytes_changed += state->end - state->start + 1;
ret = ulist_add(&changeset->range_changed, state->start, state->end,
GFP_ATOMIC);
- /* ENOMEM */
- BUG_ON(ret < 0);
+ return ret;
}
static void flush_write_bio(struct extent_page_data *epd);
@@ -187,7 +186,7 @@ free_state_cache:
return -ENOMEM;
}
-void extent_io_exit(void)
+void __cold extent_io_exit(void)
{
btrfs_leak_debug_check();
@@ -527,6 +526,7 @@ static struct extent_state *clear_state_bit(struct extent_io_tree *tree,
{
struct extent_state *next;
unsigned bits_to_clear = *bits & ~EXTENT_CTLBITS;
+ int ret;
if ((bits_to_clear & EXTENT_DIRTY) && (state->state & EXTENT_DIRTY)) {
u64 range = state->end - state->start + 1;
@@ -534,7 +534,8 @@ static struct extent_state *clear_state_bit(struct extent_io_tree *tree,
tree->dirty_bytes -= range;
}
clear_state_cb(tree, state, bits);
- add_extent_changeset(state, bits_to_clear, changeset, 0);
+ ret = add_extent_changeset(state, bits_to_clear, changeset, 0);
+ BUG_ON(ret < 0);
state->state &= ~bits_to_clear;
if (wake)
wake_up(&state->wq);
@@ -805,13 +806,15 @@ static void set_state_bits(struct extent_io_tree *tree,
unsigned *bits, struct extent_changeset *changeset)
{
unsigned bits_to_set = *bits & ~EXTENT_CTLBITS;
+ int ret;
set_state_cb(tree, state, bits);
if ((bits_to_set & EXTENT_DIRTY) && !(state->state & EXTENT_DIRTY)) {
u64 range = state->end - state->start + 1;
tree->dirty_bytes += range;
}
- add_extent_changeset(state, bits_to_set, changeset, 1);
+ ret = add_extent_changeset(state, bits_to_set, changeset, 1);
+ BUG_ON(ret < 0);
state->state |= bits_to_set;
}
@@ -2744,20 +2747,21 @@ static int __must_check submit_one_bio(struct bio *bio, int mirror_num,
return blk_status_to_errno(ret);
}
-static int merge_bio(struct extent_io_tree *tree, struct page *page,
- unsigned long offset, size_t size, struct bio *bio,
- unsigned long bio_flags)
-{
- int ret = 0;
- if (tree->ops)
- ret = tree->ops->merge_bio_hook(page, offset, size, bio,
- bio_flags);
- return ret;
-
-}
-
/*
* @opf: bio REQ_OP_* and REQ_* flags as one value
+ * @tree: tree so we can call our merge_bio hook
+ * @wbc: optional writeback control for io accounting
+ * @page: page to add to the bio
+ * @pg_offset: offset of the new bio or to check whether we are adding
+ * a contiguous page to the previous one
+ * @size: portion of page that we want to write
+ * @offset: starting offset in the page
+ * @bdev: attach newly created bios to this bdev
+ * @bio_ret: must be valid pointer, newly allocated bio will be stored there
+ * @end_io_func: end_io callback for new bio
+ * @mirror_num: desired mirror to read/write
+ * @prev_bio_flags: flags of previous bio to see if we can merge the current one
+ * @bio_flags: flags of the current bio to see if we can merge them
*/
static int submit_extent_page(unsigned int opf, struct extent_io_tree *tree,
struct writeback_control *wbc,
@@ -2773,21 +2777,27 @@ static int submit_extent_page(unsigned int opf, struct extent_io_tree *tree,
{
int ret = 0;
struct bio *bio;
- int contig = 0;
- int old_compressed = prev_bio_flags & EXTENT_BIO_COMPRESSED;
size_t page_size = min_t(size_t, size, PAGE_SIZE);
sector_t sector = offset >> 9;
- if (bio_ret && *bio_ret) {
+ ASSERT(bio_ret);
+
+ if (*bio_ret) {
+ bool contig;
+ bool can_merge = true;
+
bio = *bio_ret;
- if (old_compressed)
+ if (prev_bio_flags & EXTENT_BIO_COMPRESSED)
contig = bio->bi_iter.bi_sector == sector;
else
contig = bio_end_sector(bio) == sector;
- if (prev_bio_flags != bio_flags || !contig ||
+ if (tree->ops && tree->ops->merge_bio_hook(page, offset,
+ page_size, bio, bio_flags))
+ can_merge = false;
+
+ if (prev_bio_flags != bio_flags || !contig || !can_merge ||
force_bio_submit ||
- merge_bio(tree, page, pg_offset, page_size, bio, bio_flags) ||
bio_add_page(bio, page, page_size, pg_offset) < page_size) {
ret = submit_one_bio(bio, mirror_num, prev_bio_flags);
if (ret < 0) {
@@ -2813,10 +2823,7 @@ static int submit_extent_page(unsigned int opf, struct extent_io_tree *tree,
wbc_account_io(wbc, page, page_size);
}
- if (bio_ret)
- *bio_ret = bio;
- else
- ret = submit_one_bio(bio, mirror_num, bio_flags);
+ *bio_ret = bio;
return ret;
}
@@ -2886,8 +2893,7 @@ static int __do_readpage(struct extent_io_tree *tree,
{
struct inode *inode = page->mapping->host;
u64 start = page_offset(page);
- u64 page_end = start + PAGE_SIZE - 1;
- u64 end;
+ const u64 end = start + PAGE_SIZE - 1;
u64 cur = start;
u64 extent_offset;
u64 last_byte = i_size_read(inode);
@@ -2905,7 +2911,6 @@ static int __do_readpage(struct extent_io_tree *tree,
set_page_extent_mapped(page);
- end = page_end;
if (!PageUptodate(page)) {
if (cleancache_get_page(page) == 0) {
BUG_ON(blocksize != PAGE_SIZE);
@@ -5230,11 +5235,6 @@ void set_extent_buffer_uptodate(struct extent_buffer *eb)
}
}
-int extent_buffer_uptodate(struct extent_buffer *eb)
-{
- return test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
-}
-
int read_extent_buffer_pages(struct extent_io_tree *tree,
struct extent_buffer *eb, int wait, int mirror_num)
{
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index a7a850abd600..b77d84909863 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -83,8 +83,8 @@ static inline int le_test_bit(int nr, const u8 *addr)
return 1U & (addr[BIT_BYTE(nr)] >> (nr & (BITS_PER_BYTE-1)));
}
-extern void le_bitmap_set(u8 *map, unsigned int start, int len);
-extern void le_bitmap_clear(u8 *map, unsigned int start, int len);
+void le_bitmap_set(u8 *map, unsigned int start, int len);
+void le_bitmap_clear(u8 *map, unsigned int start, int len);
struct extent_state;
struct btrfs_root;
@@ -95,6 +95,13 @@ struct io_failure_record;
typedef blk_status_t (extent_submit_bio_hook_t)(void *private_data, struct bio *bio,
int mirror_num, unsigned long bio_flags,
u64 bio_offset);
+
+typedef blk_status_t (extent_submit_bio_start_t)(void *private_data,
+ struct bio *bio, u64 bio_offset);
+
+typedef blk_status_t (extent_submit_bio_done_t)(void *private_data,
+ struct bio *bio, int mirror_num);
+
struct extent_io_ops {
/*
* The following callbacks must be allways defined, the function
@@ -286,7 +293,7 @@ int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end);
int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
get_extent_t *get_extent, int mirror_num);
int __init extent_io_init(void);
-void extent_io_exit(void);
+void __cold extent_io_exit(void);
u64 count_range_bits(struct extent_io_tree *tree,
u64 *start, u64 search_end,
@@ -455,6 +462,11 @@ static inline void extent_buffer_get(struct extent_buffer *eb)
atomic_inc(&eb->refs);
}
+static inline int extent_buffer_uptodate(struct extent_buffer *eb)
+{
+ return test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
+}
+
int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv,
unsigned long start, unsigned long len);
void read_extent_buffer(const struct extent_buffer *eb, void *dst,
@@ -489,7 +501,6 @@ void clear_extent_buffer_dirty(struct extent_buffer *eb);
int set_extent_buffer_dirty(struct extent_buffer *eb);
void set_extent_buffer_uptodate(struct extent_buffer *eb);
void clear_extent_buffer_uptodate(struct extent_buffer *eb);
-int extent_buffer_uptodate(struct extent_buffer *eb);
int extent_buffer_under_io(struct extent_buffer *eb);
int map_private_extent_buffer(const struct extent_buffer *eb,
unsigned long offset, unsigned long min_len,
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index d3bd02105d1c..53a0633c6ef7 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -2,7 +2,6 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/hardirq.h>
#include "ctree.h"
#include "extent_map.h"
#include "compression.h"
@@ -20,7 +19,7 @@ int __init extent_map_init(void)
return 0;
}
-void extent_map_exit(void)
+void __cold extent_map_exit(void)
{
kmem_cache_destroy(extent_map_cache);
}
@@ -552,6 +551,9 @@ int btrfs_add_extent_mapping(struct extent_map_tree *em_tree,
ret = 0;
existing = search_extent_mapping(em_tree, start, len);
+
+ trace_btrfs_handle_em_exist(existing, em, start, len);
+
/*
* existing will always be non-NULL, since there must be
* extent causing the -EEXIST.
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
index b29f77bc0732..f6f8ba114977 100644
--- a/fs/btrfs/extent_map.h
+++ b/fs/btrfs/extent_map.h
@@ -86,7 +86,7 @@ void replace_extent_mapping(struct extent_map_tree *tree,
struct extent_map *alloc_extent_map(void);
void free_extent_map(struct extent_map *em);
int __init extent_map_init(void);
-void extent_map_exit(void);
+void __cold extent_map_exit(void);
int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, u64 gen);
void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em);
struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 41ab9073d1d4..f247300170e5 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1691,7 +1691,7 @@ again:
force_page_uptodate);
if (ret) {
btrfs_delalloc_release_extents(BTRFS_I(inode),
- reserve_bytes);
+ reserve_bytes, true);
break;
}
@@ -1703,7 +1703,7 @@ again:
if (extents_locked == -EAGAIN)
goto again;
btrfs_delalloc_release_extents(BTRFS_I(inode),
- reserve_bytes);
+ reserve_bytes, true);
ret = extents_locked;
break;
}
@@ -1738,7 +1738,7 @@ again:
fs_info->sb->s_blocksize_bits;
if (only_release_metadata) {
btrfs_delalloc_release_metadata(BTRFS_I(inode),
- release_bytes);
+ release_bytes, true);
} else {
u64 __pos;
@@ -1747,7 +1747,7 @@ again:
(dirty_pages << PAGE_SHIFT);
btrfs_delalloc_release_space(inode,
data_reserved, __pos,
- release_bytes);
+ release_bytes, true);
}
}
@@ -1760,7 +1760,8 @@ again:
if (extents_locked)
unlock_extent_cached(&BTRFS_I(inode)->io_tree,
lockstart, lockend, &cached_state);
- btrfs_delalloc_release_extents(BTRFS_I(inode), reserve_bytes);
+ btrfs_delalloc_release_extents(BTRFS_I(inode), reserve_bytes,
+ (ret != 0));
if (ret) {
btrfs_drop_pages(pages, num_pages);
break;
@@ -1800,11 +1801,11 @@ again:
if (only_release_metadata) {
btrfs_end_write_no_snapshotting(root);
btrfs_delalloc_release_metadata(BTRFS_I(inode),
- release_bytes);
+ release_bytes, true);
} else {
btrfs_delalloc_release_space(inode, data_reserved,
round_down(pos, fs_info->sectorsize),
- release_bytes);
+ release_bytes, true);
}
}
@@ -1997,8 +1998,6 @@ int btrfs_release_file(struct inode *inode, struct file *filp)
{
struct btrfs_file_private *private = filp->private_data;
- if (private && private->trans)
- btrfs_ioctl_trans_end(filp);
if (private && private->filldir_buf)
kfree(private->filldir_buf);
kfree(private);
@@ -2190,12 +2189,6 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
}
/*
- * ok we haven't committed the transaction yet, lets do a commit
- */
- if (file->private_data)
- btrfs_ioctl_trans_end(file);
-
- /*
* We use start here because we will need to wait on the IO to complete
* in btrfs_sync_log, which could require joining a transaction (for
* example checking cross references in the nocow path). If we use join
@@ -2214,7 +2207,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
}
trans->sync = true;
- ret = btrfs_log_dentry_safe(trans, root, dentry, start, end, &ctx);
+ ret = btrfs_log_dentry_safe(trans, dentry, start, end, &ctx);
if (ret < 0) {
/* Fallthrough and commit/free transaction. */
ret = 1;
@@ -2482,7 +2475,8 @@ static int btrfs_punch_hole_lock_range(struct inode *inode,
if ((!ordered ||
(ordered->file_offset + ordered->len <= lockstart ||
ordered->file_offset > lockend)) &&
- !btrfs_page_exists_in_range(inode, lockstart, lockend)) {
+ !filemap_range_has_page(inode->i_mapping,
+ lockstart, lockend)) {
if (ordered)
btrfs_put_ordered_extent(ordered);
break;
@@ -3378,7 +3372,7 @@ const struct file_operations btrfs_file_operations = {
.dedupe_file_range = btrfs_dedupe_file_range,
};
-void btrfs_auto_defrag_exit(void)
+void __cold btrfs_auto_defrag_exit(void)
{
kmem_cache_destroy(btrfs_inode_defrag_cachep);
}
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index a9f22ac50d6a..d0dde9e6afd7 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -3547,7 +3547,7 @@ int btrfs_write_out_ino_cache(struct btrfs_root *root,
if (ret) {
if (release_metadata)
btrfs_delalloc_release_metadata(BTRFS_I(inode),
- inode->i_size);
+ inode->i_size, true);
#ifdef DEBUG
btrfs_err(fs_info,
"failed to write free ino cache for root %llu",
diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
index fe5e0324dca9..af36a6a971fe 100644
--- a/fs/btrfs/free-space-tree.c
+++ b/fs/btrfs/free-space-tree.c
@@ -1071,7 +1071,7 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
- path->reada = 1;
+ path->reada = READA_FORWARD;
path2 = btrfs_alloc_path();
if (!path2) {
@@ -1573,7 +1573,7 @@ int load_free_space_tree(struct btrfs_caching_control *caching_ctl)
*/
path->skip_locking = 1;
path->search_commit_root = 1;
- path->reada = 1;
+ path->reada = READA_FORWARD;
info = search_free_space_info(NULL, fs_info, block_group, path, 0);
if (IS_ERR(info)) {
diff --git a/fs/btrfs/hash.c b/fs/btrfs/hash.c
deleted file mode 100644
index baacc1866861..000000000000
--- a/fs/btrfs/hash.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2014 Filipe David Borba Manana <fdmanana@gmail.com>
- *
- * 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 <crypto/hash.h>
-#include <linux/err.h>
-#include "hash.h"
-
-static struct crypto_shash *tfm;
-
-int __init btrfs_hash_init(void)
-{
- tfm = crypto_alloc_shash("crc32c", 0, 0);
-
- return PTR_ERR_OR_ZERO(tfm);
-}
-
-const char* btrfs_crc32c_impl(void)
-{
- return crypto_tfm_alg_driver_name(crypto_shash_tfm(tfm));
-}
-
-void btrfs_hash_exit(void)
-{
- crypto_free_shash(tfm);
-}
-
-u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length)
-{
- SHASH_DESC_ON_STACK(shash, tfm);
- u32 *ctx = (u32 *)shash_desc_ctx(shash);
- u32 retval;
- int err;
-
- shash->tfm = tfm;
- shash->flags = 0;
- *ctx = crc;
-
- err = crypto_shash_update(shash, address, length);
- BUG_ON(err);
-
- retval = *ctx;
- barrier_data(ctx);
- return retval;
-}
diff --git a/fs/btrfs/hash.h b/fs/btrfs/hash.h
deleted file mode 100644
index c3a2ec554361..000000000000
--- a/fs/btrfs/hash.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2007 Oracle. 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 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.
- *
- * 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 021110-1307, USA.
- */
-
-#ifndef __HASH__
-#define __HASH__
-
-int __init btrfs_hash_init(void);
-
-void btrfs_hash_exit(void);
-const char* btrfs_crc32c_impl(void);
-
-u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length);
-
-static inline u64 btrfs_name_hash(const char *name, int len)
-{
- return btrfs_crc32c((u32)~1, name, len);
-}
-
-/*
- * Figure the key offset of an extended inode ref
- */
-static inline u64 btrfs_extref_hash(u64 parent_objectid, const char *name,
- int len)
-{
- return (u64) btrfs_crc32c(parent_objectid, name, len);
-}
-
-#endif
diff --git a/fs/btrfs/inode-item.c b/fs/btrfs/inode-item.c
index 65e1a76bf755..1d5631ef2738 100644
--- a/fs/btrfs/inode-item.c
+++ b/fs/btrfs/inode-item.c
@@ -18,7 +18,6 @@
#include "ctree.h"
#include "disk-io.h"
-#include "hash.h"
#include "transaction.h"
#include "print-tree.h"
diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c
index 022b19336fee..9409dcc7020d 100644
--- a/fs/btrfs/inode-map.c
+++ b/fs/btrfs/inode-map.c
@@ -500,12 +500,12 @@ again:
ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, prealloc,
prealloc, prealloc, &alloc_hint);
if (ret) {
- btrfs_delalloc_release_extents(BTRFS_I(inode), prealloc);
+ btrfs_delalloc_release_extents(BTRFS_I(inode), prealloc, true);
goto out_put;
}
ret = btrfs_write_out_ino_cache(root, trans, path, inode);
- btrfs_delalloc_release_extents(BTRFS_I(inode), prealloc);
+ btrfs_delalloc_release_extents(BTRFS_I(inode), prealloc, false);
out_put:
iput(inode);
out_release:
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index f53470112670..1f091c2358a4 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -58,7 +58,6 @@
#include "free-space-cache.h"
#include "inode-map.h"
#include "backref.h"
-#include "hash.h"
#include "props.h"
#include "qgroup.h"
#include "dedupe.h"
@@ -102,7 +101,7 @@ static const unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = {
};
static int btrfs_setsize(struct inode *inode, struct iattr *attr);
-static int btrfs_truncate(struct inode *inode);
+static int btrfs_truncate(struct inode *inode, bool skip_writeback);
static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent);
static noinline int cow_file_range(struct inode *inode,
struct page *locked_page,
@@ -277,12 +276,12 @@ fail:
* does the checks required to make sure the data is small enough
* to fit as an inline extent.
*/
-static noinline int cow_file_range_inline(struct btrfs_root *root,
- struct inode *inode, u64 start,
+static noinline int cow_file_range_inline(struct inode *inode, u64 start,
u64 end, size_t compressed_size,
int compress_type,
struct page **compressed_pages)
{
+ struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_trans_handle *trans;
u64 isize = i_size_read(inode);
@@ -458,7 +457,6 @@ static noinline void compress_file_range(struct inode *inode,
int *num_added)
{
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
- struct btrfs_root *root = BTRFS_I(inode)->root;
u64 blocksize = fs_info->sectorsize;
u64 actual_end;
u64 isize = i_size_read(inode);
@@ -580,11 +578,11 @@ cont:
/* we didn't compress the entire range, try
* to make an uncompressed inline extent.
*/
- ret = cow_file_range_inline(root, inode, start, end,
- 0, BTRFS_COMPRESS_NONE, NULL);
+ ret = cow_file_range_inline(inode, start, end, 0,
+ BTRFS_COMPRESS_NONE, NULL);
} else {
/* try making a compressed inline extent */
- ret = cow_file_range_inline(root, inode, start, end,
+ ret = cow_file_range_inline(inode, start, end,
total_compressed,
compress_type, pages);
}
@@ -961,7 +959,6 @@ static noinline int cow_file_range(struct inode *inode,
u64 alloc_hint = 0;
u64 num_bytes;
unsigned long ram_size;
- u64 disk_num_bytes;
u64 cur_alloc_size = 0;
u64 blocksize = fs_info->sectorsize;
struct btrfs_key ins;
@@ -979,14 +976,14 @@ static noinline int cow_file_range(struct inode *inode,
num_bytes = ALIGN(end - start + 1, blocksize);
num_bytes = max(blocksize, num_bytes);
- disk_num_bytes = num_bytes;
+ ASSERT(num_bytes <= btrfs_super_total_bytes(fs_info->super_copy));
inode_should_defrag(BTRFS_I(inode), start, end, num_bytes, SZ_64K);
if (start == 0) {
/* lets try to make an inline extent */
- ret = cow_file_range_inline(root, inode, start, end, 0,
- BTRFS_COMPRESS_NONE, NULL);
+ ret = cow_file_range_inline(inode, start, end, 0,
+ BTRFS_COMPRESS_NONE, NULL);
if (ret == 0) {
/*
* We use DO_ACCOUNTING here because we need the
@@ -1010,15 +1007,12 @@ static noinline int cow_file_range(struct inode *inode,
}
}
- BUG_ON(disk_num_bytes >
- btrfs_super_total_bytes(fs_info->super_copy));
-
alloc_hint = get_extent_allocation_hint(inode, start, num_bytes);
btrfs_drop_extent_cache(BTRFS_I(inode), start,
start + num_bytes - 1, 0);
- while (disk_num_bytes > 0) {
- cur_alloc_size = disk_num_bytes;
+ while (num_bytes > 0) {
+ cur_alloc_size = num_bytes;
ret = btrfs_reserve_extent(root, cur_alloc_size, cur_alloc_size,
fs_info->sectorsize, 0, alloc_hint,
&ins, 1, 1);
@@ -1082,11 +1076,10 @@ static noinline int cow_file_range(struct inode *inode,
delalloc_end, locked_page,
EXTENT_LOCKED | EXTENT_DELALLOC,
page_ops);
- if (disk_num_bytes < cur_alloc_size)
- disk_num_bytes = 0;
+ if (num_bytes < cur_alloc_size)
+ num_bytes = 0;
else
- disk_num_bytes -= cur_alloc_size;
- num_bytes -= cur_alloc_size;
+ num_bytes -= cur_alloc_size;
alloc_hint = ins.objectid + ins.offset;
start += cur_alloc_size;
extent_reserved = false;
@@ -1262,6 +1255,8 @@ static noinline int csum_exist_in_range(struct btrfs_fs_info *fs_info,
list_del(&sums->list);
kfree(sums);
}
+ if (ret < 0)
+ return ret;
return 1;
}
@@ -1394,10 +1389,23 @@ next_slot:
goto out_check;
if (btrfs_extent_readonly(fs_info, disk_bytenr))
goto out_check;
- if (btrfs_cross_ref_exist(root, ino,
- found_key.offset -
- extent_offset, disk_bytenr))
+ ret = btrfs_cross_ref_exist(root, ino,
+ found_key.offset -
+ extent_offset, disk_bytenr);
+ if (ret) {
+ /*
+ * ret could be -EIO if the above fails to read
+ * metadata.
+ */
+ if (ret < 0) {
+ if (cow_start != (u64)-1)
+ cur_offset = cow_start;
+ goto error;
+ }
+
+ WARN_ON_ONCE(nolock);
goto out_check;
+ }
disk_bytenr += extent_offset;
disk_bytenr += cur_offset - found_key.offset;
num_bytes = min(end + 1, extent_end) - cur_offset;
@@ -1415,10 +1423,22 @@ next_slot:
* this ensure that csum for a given extent are
* either valid or do not exist.
*/
- if (csum_exist_in_range(fs_info, disk_bytenr,
- num_bytes)) {
+ ret = csum_exist_in_range(fs_info, disk_bytenr,
+ num_bytes);
+ if (ret) {
if (!nolock)
btrfs_end_write_no_snapshotting(root);
+
+ /*
+ * ret could be -EIO if the above fails to read
+ * metadata.
+ */
+ if (ret < 0) {
+ if (cow_start != (u64)-1)
+ cur_offset = cow_start;
+ goto error;
+ }
+ WARN_ON_ONCE(nolock);
goto out_check;
}
if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr)) {
@@ -1847,7 +1867,7 @@ static void btrfs_clear_bit_hook(void *private_data,
*/
if (*bits & EXTENT_CLEAR_META_RESV &&
root != fs_info->tree_root)
- btrfs_delalloc_release_metadata(inode, len);
+ btrfs_delalloc_release_metadata(inode, len, false);
/* For sanity tests. */
if (btrfs_is_testing(fs_info))
@@ -1921,8 +1941,7 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
* At IO completion time the cums attached on the ordered extent record
* are inserted into the btree
*/
-static blk_status_t __btrfs_submit_bio_start(void *private_data, struct bio *bio,
- int mirror_num, unsigned long bio_flags,
+static blk_status_t btrfs_submit_bio_start(void *private_data, struct bio *bio,
u64 bio_offset)
{
struct inode *inode = private_data;
@@ -1941,9 +1960,8 @@ static blk_status_t __btrfs_submit_bio_start(void *private_data, struct bio *bio
* At IO completion time the cums attached on the ordered extent record
* are inserted into the btree
*/
-static blk_status_t __btrfs_submit_bio_done(void *private_data, struct bio *bio,
- int mirror_num, unsigned long bio_flags,
- u64 bio_offset)
+static blk_status_t btrfs_submit_bio_done(void *private_data, struct bio *bio,
+ int mirror_num)
{
struct inode *inode = private_data;
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
@@ -2015,8 +2033,8 @@ static blk_status_t btrfs_submit_bio_hook(void *private_data, struct bio *bio,
/* we're doing a write, do the async checksumming */
ret = btrfs_wq_submit_bio(fs_info, bio, mirror_num, bio_flags,
bio_offset, inode,
- __btrfs_submit_bio_start,
- __btrfs_submit_bio_done);
+ btrfs_submit_bio_start,
+ btrfs_submit_bio_done);
goto out;
} else if (!skip_sum) {
ret = btrfs_csum_one_bio(inode, bio, 0, 0);
@@ -2134,7 +2152,7 @@ again:
ClearPageChecked(page);
set_page_dirty(page);
- btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE);
+ btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, false);
out:
unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start, page_end,
&cached_state);
@@ -2754,12 +2772,10 @@ static void relink_file_extents(struct new_sa_defrag_extent *new)
struct sa_defrag_extent_backref *backref;
struct sa_defrag_extent_backref *prev = NULL;
struct inode *inode;
- struct btrfs_root *root;
struct rb_node *node;
int ret;
inode = new->inode;
- root = BTRFS_I(inode)->root;
path = btrfs_alloc_path();
if (!path)
@@ -3247,6 +3263,16 @@ static int btrfs_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
start, (size_t)(end - start + 1));
}
+/*
+ * btrfs_add_delayed_iput - perform a delayed iput on @inode
+ *
+ * @inode: The inode we want to perform iput on
+ *
+ * This function uses the generic vfs_inode::i_count to track whether we should
+ * just decrement it (in case it's > 1) or if this is the last iput then link
+ * the inode to the delayed iput machinery. Delayed iputs are processed at
+ * transaction commit time/superblock commit/cleaner kthread.
+ */
void btrfs_add_delayed_iput(struct inode *inode)
{
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
@@ -3256,12 +3282,8 @@ void btrfs_add_delayed_iput(struct inode *inode)
return;
spin_lock(&fs_info->delayed_iput_lock);
- if (binode->delayed_iput_count == 0) {
- ASSERT(list_empty(&binode->delayed_iput));
- list_add_tail(&binode->delayed_iput, &fs_info->delayed_iputs);
- } else {
- binode->delayed_iput_count++;
- }
+ ASSERT(list_empty(&binode->delayed_iput));
+ list_add_tail(&binode->delayed_iput, &fs_info->delayed_iputs);
spin_unlock(&fs_info->delayed_iput_lock);
}
@@ -3274,13 +3296,7 @@ void btrfs_run_delayed_iputs(struct btrfs_fs_info *fs_info)
inode = list_first_entry(&fs_info->delayed_iputs,
struct btrfs_inode, delayed_iput);
- if (inode->delayed_iput_count) {
- inode->delayed_iput_count--;
- list_move_tail(&inode->delayed_iput,
- &fs_info->delayed_iputs);
- } else {
- list_del_init(&inode->delayed_iput);
- }
+ list_del_init(&inode->delayed_iput);
spin_unlock(&fs_info->delayed_iput_lock);
iput(&inode->vfs_inode);
spin_lock(&fs_info->delayed_iput_lock);
@@ -3350,7 +3366,7 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans,
struct btrfs_root *root = inode->root;
struct btrfs_block_rsv *block_rsv = NULL;
int reserve = 0;
- int insert = 0;
+ bool insert = false;
int ret;
if (!root->orphan_block_rsv) {
@@ -3360,7 +3376,16 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans,
return -ENOMEM;
}
+ if (!test_and_set_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
+ &inode->runtime_flags))
+ insert = true;
+
+ if (!test_and_set_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
+ &inode->runtime_flags))
+ reserve = 1;
+
spin_lock(&root->orphan_lock);
+ /* If someone has created ->orphan_block_rsv, be happy to use it. */
if (!root->orphan_block_rsv) {
root->orphan_block_rsv = block_rsv;
} else if (block_rsv) {
@@ -3368,26 +3393,8 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans,
block_rsv = NULL;
}
- if (!test_and_set_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
- &inode->runtime_flags)) {
-#if 0
- /*
- * For proper ENOSPC handling, we should do orphan
- * cleanup when mounting. But this introduces backward
- * compatibility issue.
- */
- if (!xchg(&root->orphan_item_inserted, 1))
- insert = 2;
- else
- insert = 1;
-#endif
- insert = 1;
+ if (insert)
atomic_inc(&root->orphan_inodes);
- }
-
- if (!test_and_set_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
- &inode->runtime_flags))
- reserve = 1;
spin_unlock(&root->orphan_lock);
/* grab metadata reservation from transaction handle */
@@ -3411,7 +3418,7 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans,
}
/* insert an orphan item to track this unlinked/truncated file */
- if (insert >= 1) {
+ if (insert) {
ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
if (ret) {
if (reserve) {
@@ -3435,15 +3442,6 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans,
ret = 0;
}
- /* insert an orphan item to track subvolume contains orphan files */
- if (insert >= 2) {
- ret = btrfs_insert_orphan_item(trans, fs_info->tree_root,
- root->root_key.objectid);
- if (ret && ret != -EEXIST) {
- btrfs_abort_transaction(trans, ret);
- return ret;
- }
- }
return 0;
}
@@ -3644,7 +3642,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
goto out;
}
- ret = btrfs_truncate(inode);
+ ret = btrfs_truncate(inode, false);
if (ret)
btrfs_orphan_del(NULL, BTRFS_I(inode));
} else {
@@ -4711,7 +4709,6 @@ delete:
if (updates) {
trans->delayed_ref_updates = 0;
ret = btrfs_run_delayed_refs(trans,
- fs_info,
updates * 2);
if (ret && !err)
err = ret;
@@ -4751,8 +4748,7 @@ error:
unsigned long updates = trans->delayed_ref_updates;
if (updates) {
trans->delayed_ref_updates = 0;
- ret = btrfs_run_delayed_refs(trans, fs_info,
- updates * 2);
+ ret = btrfs_run_delayed_refs(trans, updates * 2);
if (ret && !err)
err = ret;
}
@@ -4806,8 +4802,8 @@ again:
page = find_or_create_page(mapping, index, mask);
if (!page) {
btrfs_delalloc_release_space(inode, data_reserved,
- block_start, blocksize);
- btrfs_delalloc_release_extents(BTRFS_I(inode), blocksize);
+ block_start, blocksize, true);
+ btrfs_delalloc_release_extents(BTRFS_I(inode), blocksize, true);
ret = -ENOMEM;
goto out;
}
@@ -4874,8 +4870,8 @@ again:
out_unlock:
if (ret)
btrfs_delalloc_release_space(inode, data_reserved, block_start,
- blocksize);
- btrfs_delalloc_release_extents(BTRFS_I(inode), blocksize);
+ blocksize, true);
+ btrfs_delalloc_release_extents(BTRFS_I(inode), blocksize, (ret != 0));
unlock_page(page);
put_page(page);
out:
@@ -5130,7 +5126,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
inode_dio_wait(inode);
btrfs_inode_resume_unlocked_dio(BTRFS_I(inode));
- ret = btrfs_truncate(inode);
+ ret = btrfs_truncate(inode, newsize == oldsize);
if (ret && inode->i_nlink) {
int err;
@@ -5466,7 +5462,8 @@ no_delete:
/*
* this returns the key found in the dir entry in the location pointer.
- * If no dir entries were found, location->objectid is 0.
+ * If no dir entries were found, returns -ENOENT.
+ * If found a corrupted location in dir entry, returns -EUCLEAN.
*/
static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
struct btrfs_key *location)
@@ -5484,27 +5481,27 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
di = btrfs_lookup_dir_item(NULL, root, path, btrfs_ino(BTRFS_I(dir)),
name, namelen, 0);
- if (IS_ERR(di))
+ if (!di) {
+ ret = -ENOENT;
+ goto out;
+ }
+ if (IS_ERR(di)) {
ret = PTR_ERR(di);
-
- if (IS_ERR_OR_NULL(di))
- goto out_err;
+ goto out;
+ }
btrfs_dir_item_key_to_cpu(path->nodes[0], di, location);
if (location->type != BTRFS_INODE_ITEM_KEY &&
location->type != BTRFS_ROOT_ITEM_KEY) {
+ ret = -EUCLEAN;
btrfs_warn(root->fs_info,
"%s gets something invalid in DIR_ITEM (name %s, directory ino %llu, location(%llu %u %llu))",
__func__, name, btrfs_ino(BTRFS_I(dir)),
location->objectid, location->type, location->offset);
- goto out_err;
}
out:
btrfs_free_path(path);
return ret;
-out_err:
- location->objectid = 0;
- goto out;
}
/*
@@ -5807,9 +5804,6 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
if (ret < 0)
return ERR_PTR(ret);
- if (location.objectid == 0)
- return ERR_PTR(-ENOENT);
-
if (location.type == BTRFS_INODE_ITEM_KEY) {
inode = btrfs_iget(dir->i_sb, &location, root, NULL);
return inode;
@@ -7443,76 +7437,6 @@ out:
return ret;
}
-bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end)
-{
- struct radix_tree_root *root = &inode->i_mapping->page_tree;
- bool found = false;
- void **pagep = NULL;
- struct page *page = NULL;
- unsigned long start_idx;
- unsigned long end_idx;
-
- start_idx = start >> PAGE_SHIFT;
-
- /*
- * end is the last byte in the last page. end == start is legal
- */
- end_idx = end >> PAGE_SHIFT;
-
- rcu_read_lock();
-
- /* Most of the code in this while loop is lifted from
- * find_get_page. It's been modified to begin searching from a
- * page and return just the first page found in that range. If the
- * found idx is less than or equal to the end idx then we know that
- * a page exists. If no pages are found or if those pages are
- * outside of the range then we're fine (yay!) */
- while (page == NULL &&
- radix_tree_gang_lookup_slot(root, &pagep, NULL, start_idx, 1)) {
- page = radix_tree_deref_slot(pagep);
- if (unlikely(!page))
- break;
-
- if (radix_tree_exception(page)) {
- if (radix_tree_deref_retry(page)) {
- page = NULL;
- continue;
- }
- /*
- * Otherwise, shmem/tmpfs must be storing a swap entry
- * here as an exceptional entry: so return it without
- * attempting to raise page count.
- */
- page = NULL;
- break; /* TODO: Is this relevant for this use case? */
- }
-
- if (!page_cache_get_speculative(page)) {
- page = NULL;
- continue;
- }
-
- /*
- * Has the page moved?
- * This is part of the lockless pagecache protocol. See
- * include/linux/pagemap.h for details.
- */
- if (unlikely(page != *pagep)) {
- put_page(page);
- page = NULL;
- }
- }
-
- if (page) {
- if (page->index <= end_idx)
- found = true;
- put_page(page);
- }
-
- rcu_read_unlock();
- return found;
-}
-
static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
struct extent_state **cached_state, int writing)
{
@@ -7538,8 +7462,8 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
* get stale data.
*/
if (!ordered &&
- (!writing ||
- !btrfs_page_exists_in_range(inode, lockstart, lockend)))
+ (!writing || !filemap_range_has_page(inode->i_mapping,
+ lockstart, lockend)))
break;
unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
@@ -8270,9 +8194,8 @@ static void btrfs_endio_direct_write(struct bio *bio)
bio_put(bio);
}
-static blk_status_t __btrfs_submit_bio_start_direct_io(void *private_data,
- struct bio *bio, int mirror_num,
- unsigned long bio_flags, u64 offset)
+static blk_status_t btrfs_submit_bio_start_direct_io(void *private_data,
+ struct bio *bio, u64 offset)
{
struct inode *inode = private_data;
blk_status_t ret;
@@ -8298,13 +8221,13 @@ static void btrfs_end_dio_bio(struct bio *bio)
err = dip->subio_endio(dip->inode, btrfs_io_bio(bio), err);
if (err) {
- dip->errors = 1;
-
/*
- * before atomic variable goto zero, we must make sure
- * dip->errors is perceived to be set.
+ * We want to perceive the errors flag being set before
+ * decrementing the reference count. We don't need a barrier
+ * since atomic operations with a return value are fully
+ * ordered as per atomic_t.txt
*/
- smp_mb__before_atomic();
+ dip->errors = 1;
}
/* if there are more bios still pending for this dio, just exit */
@@ -8352,9 +8275,8 @@ static inline blk_status_t btrfs_lookup_and_bind_dio_csum(struct inode *inode,
return 0;
}
-static inline blk_status_t
-__btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, u64 file_offset,
- int async_submit)
+static inline blk_status_t btrfs_submit_dio_bio(struct bio *bio,
+ struct inode *inode, u64 file_offset, int async_submit)
{
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
struct btrfs_dio_private *dip = bio->bi_private;
@@ -8377,8 +8299,8 @@ __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, u64 file_offset,
if (write && async_submit) {
ret = btrfs_wq_submit_bio(fs_info, bio, 0, 0,
file_offset, inode,
- __btrfs_submit_bio_start_direct_io,
- __btrfs_submit_bio_done);
+ btrfs_submit_bio_start_direct_io,
+ btrfs_submit_bio_done);
goto err;
} else if (write) {
/*
@@ -8464,7 +8386,7 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip)
*/
atomic_inc(&dip->pending_bios);
- status = __btrfs_submit_dio_bio(bio, inode, file_offset,
+ status = btrfs_submit_dio_bio(bio, inode, file_offset,
async_submit);
if (status) {
bio_put(bio);
@@ -8484,7 +8406,7 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip)
} while (submit_len > 0);
submit:
- status = __btrfs_submit_dio_bio(bio, inode, file_offset, async_submit);
+ status = btrfs_submit_dio_bio(bio, inode, file_offset, async_submit);
if (!status)
return 0;
@@ -8492,10 +8414,11 @@ submit:
out_err:
dip->errors = 1;
/*
- * before atomic variable goto zero, we must
- * make sure dip->errors is perceived to be set.
+ * Before atomic variable goto zero, we must make sure dip->errors is
+ * perceived to be set. This ordering is ensured by the fact that an
+ * atomic operations with a return value are fully ordered as per
+ * atomic_t.txt
*/
- smp_mb__before_atomic();
if (atomic_dec_and_test(&dip->pending_bios))
bio_io_error(dip->orig_bio);
@@ -8713,7 +8636,7 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
if (ret < 0 && ret != -EIOCBQUEUED) {
if (dio_data.reserve)
btrfs_delalloc_release_space(inode, data_reserved,
- offset, dio_data.reserve);
+ offset, dio_data.reserve, true);
/*
* On error we might have left some ordered extents
* without submitting corresponding bios for them, so
@@ -8729,8 +8652,8 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
false);
} else if (ret >= 0 && (size_t)ret < count)
btrfs_delalloc_release_space(inode, data_reserved,
- offset, count - (size_t)ret);
- btrfs_delalloc_release_extents(BTRFS_I(inode), count);
+ offset, count - (size_t)ret, true);
+ btrfs_delalloc_release_extents(BTRFS_I(inode), count, false);
}
out:
if (wakeup)
@@ -9045,7 +8968,8 @@ again:
if (reserved_space < PAGE_SIZE) {
end = page_start + reserved_space - 1;
btrfs_delalloc_release_space(inode, data_reserved,
- page_start, PAGE_SIZE - reserved_space);
+ page_start, PAGE_SIZE - reserved_space,
+ true);
}
}
@@ -9095,23 +9019,23 @@ again:
out_unlock:
if (!ret) {
- btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE);
+ btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, true);
sb_end_pagefault(inode->i_sb);
extent_changeset_free(data_reserved);
return VM_FAULT_LOCKED;
}
unlock_page(page);
out:
- btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE);
+ btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, (ret != 0));
btrfs_delalloc_release_space(inode, data_reserved, page_start,
- reserved_space);
+ reserved_space, (ret != 0));
out_noreserve:
sb_end_pagefault(inode->i_sb);
extent_changeset_free(data_reserved);
return ret;
}
-static int btrfs_truncate(struct inode *inode)
+static int btrfs_truncate(struct inode *inode, bool skip_writeback)
{
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -9122,10 +9046,12 @@ static int btrfs_truncate(struct inode *inode)
u64 mask = fs_info->sectorsize - 1;
u64 min_size = btrfs_calc_trunc_metadata_size(fs_info, 1);
- ret = btrfs_wait_ordered_range(inode, inode->i_size & (~mask),
- (u64)-1);
- if (ret)
- return ret;
+ if (!skip_writeback) {
+ ret = btrfs_wait_ordered_range(inode, inode->i_size & (~mask),
+ (u64)-1);
+ if (ret)
+ return ret;
+ }
/*
* Yes ladies and gentlemen, this is indeed ugly. The fact is we have
@@ -9335,7 +9261,6 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
ei->dir_index = 0;
ei->last_unlink_trans = 0;
ei->last_log_commit = 0;
- ei->delayed_iput_count = 0;
spin_lock_init(&ei->lock);
ei->outstanding_extents = 0;
@@ -9455,7 +9380,7 @@ static void init_once(void *foo)
inode_init_once(&ei->vfs_inode);
}
-void btrfs_destroy_cachep(void)
+void __cold btrfs_destroy_cachep(void)
{
/*
* Make sure all delayed rcu free inodes are flushed before we
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 3278ae592a2c..b2db3988813f 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -106,7 +106,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
int no_time_update);
/* Mask out flags that are inappropriate for the given type of inode. */
-static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags)
+static unsigned int btrfs_mask_flags(umode_t mode, unsigned int flags)
{
if (S_ISDIR(mode))
return flags;
@@ -1197,7 +1197,7 @@ again:
spin_unlock(&BTRFS_I(inode)->lock);
btrfs_delalloc_release_space(inode, data_reserved,
start_index << PAGE_SHIFT,
- (page_cnt - i_done) << PAGE_SHIFT);
+ (page_cnt - i_done) << PAGE_SHIFT, true);
}
@@ -1215,7 +1215,8 @@ again:
unlock_page(pages[i]);
put_page(pages[i]);
}
- btrfs_delalloc_release_extents(BTRFS_I(inode), page_cnt << PAGE_SHIFT);
+ btrfs_delalloc_release_extents(BTRFS_I(inode), page_cnt << PAGE_SHIFT,
+ false);
extent_changeset_free(data_reserved);
return i_done;
out:
@@ -1225,8 +1226,9 @@ out:
}
btrfs_delalloc_release_space(inode, data_reserved,
start_index << PAGE_SHIFT,
- page_cnt << PAGE_SHIFT);
- btrfs_delalloc_release_extents(BTRFS_I(inode), page_cnt << PAGE_SHIFT);
+ page_cnt << PAGE_SHIFT, true);
+ btrfs_delalloc_release_extents(BTRFS_I(inode), page_cnt << PAGE_SHIFT,
+ true);
extent_changeset_free(data_reserved);
return ret;
@@ -2600,7 +2602,7 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
range->len = (u64)-1;
}
ret = btrfs_defrag_file(file_inode(file), file,
- range, 0, 0);
+ range, BTRFS_OLDEST_GENERATION, 0);
if (ret > 0)
ret = 0;
kfree(range);
@@ -3936,73 +3938,6 @@ int btrfs_clone_file_range(struct file *src_file, loff_t off,
return btrfs_clone_files(dst_file, src_file, off, len, destoff);
}
-/*
- * there are many ways the trans_start and trans_end ioctls can lead
- * to deadlocks. They should only be used by applications that
- * basically own the machine, and have a very in depth understanding
- * of all the possible deadlocks and enospc problems.
- */
-static long btrfs_ioctl_trans_start(struct file *file)
-{
- struct inode *inode = file_inode(file);
- struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
- struct btrfs_root *root = BTRFS_I(inode)->root;
- struct btrfs_trans_handle *trans;
- struct btrfs_file_private *private;
- int ret;
- static bool warned = false;
-
- ret = -EPERM;
- if (!capable(CAP_SYS_ADMIN))
- goto out;
-
- if (!warned) {
- btrfs_warn(fs_info,
- "Userspace transaction mechanism is considered "
- "deprecated and slated to be removed in 4.17. "
- "If you have a valid use case please "
- "speak up on the mailing list");
- WARN_ON(1);
- warned = true;
- }
-
- ret = -EINPROGRESS;
- private = file->private_data;
- if (private && private->trans)
- goto out;
- if (!private) {
- private = kzalloc(sizeof(struct btrfs_file_private),
- GFP_KERNEL);
- if (!private)
- return -ENOMEM;
- file->private_data = private;
- }
-
- ret = -EROFS;
- if (btrfs_root_readonly(root))
- goto out;
-
- ret = mnt_want_write_file(file);
- if (ret)
- goto out;
-
- atomic_inc(&fs_info->open_ioctl_trans);
-
- ret = -ENOMEM;
- trans = btrfs_start_ioctl_transaction(root);
- if (IS_ERR(trans))
- goto out_drop;
-
- private->trans = trans;
- return 0;
-
-out_drop:
- atomic_dec(&fs_info->open_ioctl_trans);
- mnt_drop_write_file(file);
-out:
- return ret;
-}
-
static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
{
struct inode *inode = file_inode(file);
@@ -4244,30 +4179,6 @@ out:
return ret;
}
-/*
- * there are many ways the trans_start and trans_end ioctls can lead
- * to deadlocks. They should only be used by applications that
- * basically own the machine, and have a very in depth understanding
- * of all the possible deadlocks and enospc problems.
- */
-long btrfs_ioctl_trans_end(struct file *file)
-{
- struct inode *inode = file_inode(file);
- struct btrfs_root *root = BTRFS_I(inode)->root;
- struct btrfs_file_private *private = file->private_data;
-
- if (!private || !private->trans)
- return -EINVAL;
-
- btrfs_end_transaction(private->trans);
- private->trans = NULL;
-
- atomic_dec(&root->fs_info->open_ioctl_trans);
-
- mnt_drop_write_file(file);
- return 0;
-}
-
static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
void __user *argp)
{
@@ -4429,7 +4340,8 @@ static long btrfs_ioctl_dev_replace(struct btrfs_fs_info *fs_info,
ret = 0;
break;
case BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL:
- ret = btrfs_dev_replace_cancel(fs_info, p);
+ p->result = btrfs_dev_replace_cancel(fs_info);
+ ret = 0;
break;
default:
ret = -EINVAL;
@@ -5138,10 +5050,17 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
received_uuid_changed = memcmp(root_item->received_uuid, sa->uuid,
BTRFS_UUID_SIZE);
if (received_uuid_changed &&
- !btrfs_is_empty_uuid(root_item->received_uuid))
- btrfs_uuid_tree_rem(trans, fs_info, root_item->received_uuid,
- BTRFS_UUID_KEY_RECEIVED_SUBVOL,
- root->root_key.objectid);
+ !btrfs_is_empty_uuid(root_item->received_uuid)) {
+ ret = btrfs_uuid_tree_rem(trans, fs_info,
+ root_item->received_uuid,
+ BTRFS_UUID_KEY_RECEIVED_SUBVOL,
+ root->root_key.objectid);
+ if (ret && ret != -ENOENT) {
+ btrfs_abort_transaction(trans, ret);
+ btrfs_end_transaction(trans);
+ goto out;
+ }
+ }
memcpy(root_item->received_uuid, sa->uuid, BTRFS_UUID_SIZE);
btrfs_set_root_stransid(root_item, sa->stransid);
btrfs_set_root_rtransid(root_item, sa->rtransid);
@@ -5574,10 +5493,6 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_dev_info(fs_info, argp);
case BTRFS_IOC_BALANCE:
return btrfs_ioctl_balance(file, NULL);
- case BTRFS_IOC_TRANS_START:
- return btrfs_ioctl_trans_start(file);
- case BTRFS_IOC_TRANS_END:
- return btrfs_ioctl_trans_end(file);
case BTRFS_IOC_TREE_SEARCH:
return btrfs_ioctl_tree_search(file, argp);
case BTRFS_IOC_TREE_SEARCH_V2:
diff --git a/fs/btrfs/locking.c b/fs/btrfs/locking.c
index d13128c70ddd..621083f8932c 100644
--- a/fs/btrfs/locking.c
+++ b/fs/btrfs/locking.c
@@ -290,7 +290,7 @@ void btrfs_tree_unlock(struct extent_buffer *eb)
/*
* Make sure counter is updated before we wake up waiters.
*/
- smp_mb();
+ smp_mb__after_atomic();
if (waitqueue_active(&eb->write_lock_wq))
wake_up(&eb->write_lock_wq);
} else {
diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c
index 6c7f18cd3b61..1c7f7f70caf4 100644
--- a/fs/btrfs/lzo.c
+++ b/fs/btrfs/lzo.c
@@ -382,14 +382,12 @@ static int lzo_decompress(struct list_head *ws, unsigned char *data_in,
struct workspace *workspace = list_entry(ws, struct workspace, list);
size_t in_len;
size_t out_len;
- size_t tot_len;
int ret = 0;
char *kaddr;
unsigned long bytes;
BUG_ON(srclen < LZO_LEN);
- tot_len = read_compress_length(data_in);
data_in += LZO_LEN;
in_len = read_compress_length(data_in);
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index 5b311aeddcc8..661cc3db0c7c 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -610,7 +610,7 @@ void btrfs_remove_ordered_extent(struct inode *inode,
btrfs_mod_outstanding_extents(btrfs_inode, -1);
spin_unlock(&btrfs_inode->lock);
if (root != fs_info->tree_root)
- btrfs_delalloc_release_metadata(btrfs_inode, entry->len);
+ btrfs_delalloc_release_metadata(btrfs_inode, entry->len, false);
tree = &btrfs_inode->ordered_tree;
spin_lock_irq(&tree->lock);
@@ -1154,7 +1154,7 @@ int __init ordered_data_init(void)
return 0;
}
-void ordered_data_exit(void)
+void __cold ordered_data_exit(void)
{
kmem_cache_destroy(btrfs_ordered_extent_cache);
}
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
index 56c4c0ee6381..4a1672a13ba6 100644
--- a/fs/btrfs/ordered-data.h
+++ b/fs/btrfs/ordered-data.h
@@ -151,7 +151,9 @@ static inline int btrfs_ordered_sum_size(struct btrfs_fs_info *fs_info,
unsigned long bytes)
{
int num_sectors = (int)DIV_ROUND_UP(bytes, fs_info->sectorsize);
- return sizeof(struct btrfs_ordered_sum) + num_sectors * sizeof(u32);
+ int csum_size = btrfs_super_csum_size(fs_info->super_copy);
+
+ return sizeof(struct btrfs_ordered_sum) + num_sectors * csum_size;
}
static inline void
@@ -215,5 +217,5 @@ void btrfs_wait_logged_extents(struct btrfs_trans_handle *trans,
struct btrfs_root *log, u64 transid);
void btrfs_free_logged_extents(struct btrfs_root *log, u64 transid);
int __init ordered_data_init(void);
-void ordered_data_exit(void);
+void __cold ordered_data_exit(void);
#endif
diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c
index 569205e651c7..4a8770485f77 100644
--- a/fs/btrfs/print-tree.c
+++ b/fs/btrfs/print-tree.c
@@ -365,9 +365,13 @@ void btrfs_print_tree(struct extent_buffer *c)
btrfs_node_blockptr(c, i));
}
for (i = 0; i < nr; i++) {
- struct extent_buffer *next = read_tree_block(fs_info,
- btrfs_node_blockptr(c, i),
- btrfs_node_ptr_generation(c, i));
+ struct btrfs_key first_key;
+ struct extent_buffer *next;
+
+ btrfs_node_key_to_cpu(c, &first_key, i);
+ next = read_tree_block(fs_info, btrfs_node_blockptr(c, i),
+ btrfs_node_ptr_generation(c, i),
+ level - 1, &first_key);
if (IS_ERR(next)) {
continue;
} else if (!extent_buffer_uptodate(next)) {
diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c
index b30a056963ab..5859f7d3cf3e 100644
--- a/fs/btrfs/props.c
+++ b/fs/btrfs/props.c
@@ -19,8 +19,8 @@
#include <linux/hashtable.h>
#include "props.h"
#include "btrfs_inode.h"
-#include "hash.h"
#include "transaction.h"
+#include "ctree.h"
#include "xattr.h"
#include "compression.h"
@@ -116,7 +116,7 @@ static int __btrfs_set_prop(struct btrfs_trans_handle *trans,
return -EINVAL;
if (value_len == 0) {
- ret = __btrfs_setxattr(trans, inode, handler->xattr_name,
+ ret = btrfs_setxattr(trans, inode, handler->xattr_name,
NULL, 0, flags);
if (ret)
return ret;
@@ -130,13 +130,13 @@ static int __btrfs_set_prop(struct btrfs_trans_handle *trans,
ret = handler->validate(value, value_len);
if (ret)
return ret;
- ret = __btrfs_setxattr(trans, inode, handler->xattr_name,
+ ret = btrfs_setxattr(trans, inode, handler->xattr_name,
value, value_len, flags);
if (ret)
return ret;
ret = handler->apply(inode, value, value_len);
if (ret) {
- __btrfs_setxattr(trans, inode, handler->xattr_name,
+ btrfs_setxattr(trans, inode, handler->xattr_name,
NULL, 0, flags);
return ret;
}
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index aa259d6986e1..f583f13ff26e 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -47,6 +47,82 @@
* - check all ioctl parameters
*/
+/*
+ * Helpers to access qgroup reservation
+ *
+ * Callers should ensure the lock context and type are valid
+ */
+
+static u64 qgroup_rsv_total(const struct btrfs_qgroup *qgroup)
+{
+ u64 ret = 0;
+ int i;
+
+ for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++)
+ ret += qgroup->rsv.values[i];
+
+ return ret;
+}
+
+#ifdef CONFIG_BTRFS_DEBUG
+static const char *qgroup_rsv_type_str(enum btrfs_qgroup_rsv_type type)
+{
+ if (type == BTRFS_QGROUP_RSV_DATA)
+ return "data";
+ if (type == BTRFS_QGROUP_RSV_META_PERTRANS)
+ return "meta_pertrans";
+ if (type == BTRFS_QGROUP_RSV_META_PREALLOC)
+ return "meta_prealloc";
+ return NULL;
+}
+#endif
+
+static void qgroup_rsv_add(struct btrfs_fs_info *fs_info,
+ struct btrfs_qgroup *qgroup, u64 num_bytes,
+ enum btrfs_qgroup_rsv_type type)
+{
+ trace_qgroup_update_reserve(fs_info, qgroup, num_bytes, type);
+ qgroup->rsv.values[type] += num_bytes;
+}
+
+static void qgroup_rsv_release(struct btrfs_fs_info *fs_info,
+ struct btrfs_qgroup *qgroup, u64 num_bytes,
+ enum btrfs_qgroup_rsv_type type)
+{
+ trace_qgroup_update_reserve(fs_info, qgroup, -(s64)num_bytes, type);
+ if (qgroup->rsv.values[type] >= num_bytes) {
+ qgroup->rsv.values[type] -= num_bytes;
+ return;
+ }
+#ifdef CONFIG_BTRFS_DEBUG
+ WARN_RATELIMIT(1,
+ "qgroup %llu %s reserved space underflow, have %llu to free %llu",
+ qgroup->qgroupid, qgroup_rsv_type_str(type),
+ qgroup->rsv.values[type], num_bytes);
+#endif
+ qgroup->rsv.values[type] = 0;
+}
+
+static void qgroup_rsv_add_by_qgroup(struct btrfs_fs_info *fs_info,
+ struct btrfs_qgroup *dest,
+ struct btrfs_qgroup *src)
+{
+ int i;
+
+ for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++)
+ qgroup_rsv_add(fs_info, dest, src->rsv.values[i], i);
+}
+
+static void qgroup_rsv_release_by_qgroup(struct btrfs_fs_info *fs_info,
+ struct btrfs_qgroup *dest,
+ struct btrfs_qgroup *src)
+{
+ int i;
+
+ for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++)
+ qgroup_rsv_release(fs_info, dest, src->rsv.values[i], i);
+}
+
static void btrfs_qgroup_update_old_refcnt(struct btrfs_qgroup *qg, u64 seq,
int mod)
{
@@ -826,10 +902,8 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans,
int slot;
mutex_lock(&fs_info->qgroup_ioctl_lock);
- if (fs_info->quota_root) {
- set_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags);
+ if (fs_info->quota_root)
goto out;
- }
fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL);
if (!fs_info->qgroup_ulist) {
@@ -923,8 +997,15 @@ out_add_root:
}
spin_lock(&fs_info->qgroup_lock);
fs_info->quota_root = quota_root;
- set_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags);
+ set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
spin_unlock(&fs_info->qgroup_lock);
+ ret = qgroup_rescan_init(fs_info, 0, 1);
+ if (!ret) {
+ qgroup_rescan_zero_tracking(fs_info);
+ btrfs_queue_work(fs_info->qgroup_rescan_workers,
+ &fs_info->qgroup_rescan_work);
+ }
+
out_free_path:
btrfs_free_path(path);
out_free_root:
@@ -991,33 +1072,29 @@ static void qgroup_dirty(struct btrfs_fs_info *fs_info,
list_add(&qgroup->dirty, &fs_info->dirty_qgroups);
}
-static void report_reserved_underflow(struct btrfs_fs_info *fs_info,
- struct btrfs_qgroup *qgroup,
- u64 num_bytes)
-{
-#ifdef CONFIG_BTRFS_DEBUG
- WARN_ON(qgroup->reserved < num_bytes);
- btrfs_debug(fs_info,
- "qgroup %llu reserved space underflow, have: %llu, to free: %llu",
- qgroup->qgroupid, qgroup->reserved, num_bytes);
-#endif
- qgroup->reserved = 0;
-}
/*
- * The easy accounting, if we are adding/removing the only ref for an extent
- * then this qgroup and all of the parent qgroups get their reference and
- * exclusive counts adjusted.
+ * The easy accounting, we're updating qgroup relationship whose child qgroup
+ * only has exclusive extents.
+ *
+ * In this case, all exclsuive extents will also be exlusive for parent, so
+ * excl/rfer just get added/removed.
+ *
+ * So is qgroup reservation space, which should also be added/removed to
+ * parent.
+ * Or when child tries to release reservation space, parent will underflow its
+ * reservation (for relationship adding case).
*
* Caller should hold fs_info->qgroup_lock.
*/
static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
struct ulist *tmp, u64 ref_root,
- u64 num_bytes, int sign)
+ struct btrfs_qgroup *src, int sign)
{
struct btrfs_qgroup *qgroup;
struct btrfs_qgroup_list *glist;
struct ulist_node *unode;
struct ulist_iterator uiter;
+ u64 num_bytes = src->excl;
int ret = 0;
qgroup = find_qgroup_rb(fs_info, ref_root);
@@ -1030,13 +1107,11 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
WARN_ON(sign < 0 && qgroup->excl < num_bytes);
qgroup->excl += sign * num_bytes;
qgroup->excl_cmpr += sign * num_bytes;
- if (sign > 0) {
- trace_qgroup_update_reserve(fs_info, qgroup, -(s64)num_bytes);
- if (qgroup->reserved < num_bytes)
- report_reserved_underflow(fs_info, qgroup, num_bytes);
- else
- qgroup->reserved -= num_bytes;
- }
+
+ if (sign > 0)
+ qgroup_rsv_add_by_qgroup(fs_info, qgroup, src);
+ else
+ qgroup_rsv_release_by_qgroup(fs_info, qgroup, src);
qgroup_dirty(fs_info, qgroup);
@@ -1056,15 +1131,10 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
qgroup->rfer_cmpr += sign * num_bytes;
WARN_ON(sign < 0 && qgroup->excl < num_bytes);
qgroup->excl += sign * num_bytes;
- if (sign > 0) {
- trace_qgroup_update_reserve(fs_info, qgroup,
- -(s64)num_bytes);
- if (qgroup->reserved < num_bytes)
- report_reserved_underflow(fs_info, qgroup,
- num_bytes);
- else
- qgroup->reserved -= num_bytes;
- }
+ if (sign > 0)
+ qgroup_rsv_add_by_qgroup(fs_info, qgroup, src);
+ else
+ qgroup_rsv_release_by_qgroup(fs_info, qgroup, src);
qgroup->excl_cmpr += sign * num_bytes;
qgroup_dirty(fs_info, qgroup);
@@ -1107,7 +1177,7 @@ static int quick_update_accounting(struct btrfs_fs_info *fs_info,
if (qgroup->excl == qgroup->rfer) {
ret = 0;
err = __qgroup_excl_accounting(fs_info, tmp, dst,
- qgroup->excl, sign);
+ qgroup, sign);
if (err < 0) {
ret = err;
goto out;
@@ -1414,7 +1484,7 @@ int btrfs_qgroup_trace_extent_nolock(struct btrfs_fs_info *fs_info,
struct btrfs_qgroup_extent_record *entry;
u64 bytenr = record->bytenr;
- assert_spin_locked(&delayed_refs->lock);
+ lockdep_assert_held(&delayed_refs->lock);
trace_btrfs_qgroup_trace_extent(fs_info, record);
while (*p) {
@@ -1614,7 +1684,7 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans,
return 0;
if (!extent_buffer_uptodate(root_eb)) {
- ret = btrfs_read_buffer(root_eb, root_gen);
+ ret = btrfs_read_buffer(root_eb, root_gen, root_level, NULL);
if (ret)
goto out;
}
@@ -1645,6 +1715,7 @@ walk_down:
level = root_level;
while (level >= 0) {
if (path->nodes[level] == NULL) {
+ struct btrfs_key first_key;
int parent_slot;
u64 child_gen;
u64 child_bytenr;
@@ -1657,8 +1728,10 @@ walk_down:
parent_slot = path->slots[level + 1];
child_bytenr = btrfs_node_blockptr(eb, parent_slot);
child_gen = btrfs_node_ptr_generation(eb, parent_slot);
+ btrfs_node_key_to_cpu(eb, &first_key, parent_slot);
- eb = read_tree_block(fs_info, child_bytenr, child_gen);
+ eb = read_tree_block(fs_info, child_bytenr, child_gen,
+ level, &first_key);
if (IS_ERR(eb)) {
ret = PTR_ERR(eb);
goto out;
@@ -2009,9 +2082,9 @@ out_free:
return ret;
}
-int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info)
+int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_qgroup_extent_record *record;
struct btrfs_delayed_ref_root *delayed_refs;
struct ulist *new_roots = NULL;
@@ -2080,17 +2153,9 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans,
{
struct btrfs_root *quota_root = fs_info->quota_root;
int ret = 0;
- int start_rescan_worker = 0;
if (!quota_root)
- goto out;
-
- if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) &&
- test_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags))
- start_rescan_worker = 1;
-
- if (test_and_clear_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags))
- set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
+ return ret;
spin_lock(&fs_info->qgroup_lock);
while (!list_empty(&fs_info->dirty_qgroups)) {
@@ -2119,18 +2184,6 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans,
if (ret)
fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
- if (!ret && start_rescan_worker) {
- ret = qgroup_rescan_init(fs_info, 0, 1);
- if (!ret) {
- qgroup_rescan_zero_tracking(fs_info);
- btrfs_queue_work(fs_info->qgroup_rescan_workers,
- &fs_info->qgroup_rescan_work);
- }
- ret = 0;
- }
-
-out:
-
return ret;
}
@@ -2338,24 +2391,24 @@ out:
static bool qgroup_check_limits(const struct btrfs_qgroup *qg, u64 num_bytes)
{
if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) &&
- qg->reserved + (s64)qg->rfer + num_bytes > qg->max_rfer)
+ qgroup_rsv_total(qg) + (s64)qg->rfer + num_bytes > qg->max_rfer)
return false;
if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) &&
- qg->reserved + (s64)qg->excl + num_bytes > qg->max_excl)
+ qgroup_rsv_total(qg) + (s64)qg->excl + num_bytes > qg->max_excl)
return false;
return true;
}
-static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce)
+static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce,
+ enum btrfs_qgroup_rsv_type type)
{
struct btrfs_root *quota_root;
struct btrfs_qgroup *qgroup;
struct btrfs_fs_info *fs_info = root->fs_info;
u64 ref_root = root->root_key.objectid;
int ret = 0;
- int retried = 0;
struct ulist_node *unode;
struct ulist_iterator uiter;
@@ -2369,7 +2422,6 @@ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce)
capable(CAP_SYS_RESOURCE))
enforce = false;
-retry:
spin_lock(&fs_info->qgroup_lock);
quota_root = fs_info->quota_root;
if (!quota_root)
@@ -2385,7 +2437,7 @@ retry:
*/
ulist_reinit(fs_info->qgroup_ulist);
ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid,
- (uintptr_t)qgroup, GFP_ATOMIC);
+ qgroup_to_aux(qgroup), GFP_ATOMIC);
if (ret < 0)
goto out;
ULIST_ITER_INIT(&uiter);
@@ -2396,27 +2448,6 @@ retry:
qg = unode_aux_to_qgroup(unode);
if (enforce && !qgroup_check_limits(qg, num_bytes)) {
- /*
- * Commit the tree and retry, since we may have
- * deletions which would free up space.
- */
- if (!retried && qg->reserved > 0) {
- struct btrfs_trans_handle *trans;
-
- spin_unlock(&fs_info->qgroup_lock);
- ret = btrfs_start_delalloc_inodes(root, 0);
- if (ret)
- return ret;
- btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
- trans = btrfs_join_transaction(root);
- if (IS_ERR(trans))
- return PTR_ERR(trans);
- ret = btrfs_commit_transaction(trans);
- if (ret)
- return ret;
- retried++;
- goto retry;
- }
ret = -EDQUOT;
goto out;
}
@@ -2424,7 +2455,7 @@ retry:
list_for_each_entry(glist, &qg->groups, next_group) {
ret = ulist_add(fs_info->qgroup_ulist,
glist->group->qgroupid,
- (uintptr_t)glist->group, GFP_ATOMIC);
+ qgroup_to_aux(glist->group), GFP_ATOMIC);
if (ret < 0)
goto out;
}
@@ -2439,8 +2470,8 @@ retry:
qg = unode_aux_to_qgroup(unode);
- trace_qgroup_update_reserve(fs_info, qg, num_bytes);
- qg->reserved += num_bytes;
+ trace_qgroup_update_reserve(fs_info, qg, num_bytes, type);
+ qgroup_rsv_add(fs_info, qg, num_bytes, type);
}
out:
@@ -2448,8 +2479,18 @@ out:
return ret;
}
+/*
+ * Free @num_bytes of reserved space with @type for qgroup. (Normally level 0
+ * qgroup).
+ *
+ * Will handle all higher level qgroup too.
+ *
+ * NOTE: If @num_bytes is (u64)-1, this means to free all bytes of this qgroup.
+ * This special case is only used for META_PERTRANS type.
+ */
void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
- u64 ref_root, u64 num_bytes)
+ u64 ref_root, u64 num_bytes,
+ enum btrfs_qgroup_rsv_type type)
{
struct btrfs_root *quota_root;
struct btrfs_qgroup *qgroup;
@@ -2463,6 +2504,10 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
if (num_bytes == 0)
return;
+ if (num_bytes == (u64)-1 && type != BTRFS_QGROUP_RSV_META_PERTRANS) {
+ WARN(1, "%s: Invalid type to free", __func__);
+ return;
+ }
spin_lock(&fs_info->qgroup_lock);
quota_root = fs_info->quota_root;
@@ -2473,9 +2518,16 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
if (!qgroup)
goto out;
+ if (num_bytes == (u64)-1)
+ /*
+ * We're freeing all pertrans rsv, get reserved value from
+ * level 0 qgroup as real num_bytes to free.
+ */
+ num_bytes = qgroup->rsv.values[type];
+
ulist_reinit(fs_info->qgroup_ulist);
ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid,
- (uintptr_t)qgroup, GFP_ATOMIC);
+ qgroup_to_aux(qgroup), GFP_ATOMIC);
if (ret < 0)
goto out;
ULIST_ITER_INIT(&uiter);
@@ -2485,16 +2537,13 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
qg = unode_aux_to_qgroup(unode);
- trace_qgroup_update_reserve(fs_info, qg, -(s64)num_bytes);
- if (qg->reserved < num_bytes)
- report_reserved_underflow(fs_info, qg, num_bytes);
- else
- qg->reserved -= num_bytes;
+ trace_qgroup_update_reserve(fs_info, qg, -(s64)num_bytes, type);
+ qgroup_rsv_release(fs_info, qg, num_bytes, type);
list_for_each_entry(glist, &qg->groups, next_group) {
ret = ulist_add(fs_info->qgroup_ulist,
glist->group->qgroupid,
- (uintptr_t)glist->group, GFP_ATOMIC);
+ qgroup_to_aux(glist->group), GFP_ATOMIC);
if (ret < 0)
goto out;
}
@@ -2877,7 +2926,7 @@ int btrfs_qgroup_reserve_data(struct inode *inode,
to_reserve, QGROUP_RESERVE);
if (ret < 0)
goto cleanup;
- ret = qgroup_reserve(root, to_reserve, true);
+ ret = qgroup_reserve(root, to_reserve, true, BTRFS_QGROUP_RSV_DATA);
if (ret < 0)
goto cleanup;
@@ -2940,7 +2989,8 @@ static int qgroup_free_reserved_data(struct inode *inode,
goto out;
freed += changeset.bytes_changed;
}
- btrfs_qgroup_free_refroot(root->fs_info, root->objectid, freed);
+ btrfs_qgroup_free_refroot(root->fs_info, root->objectid, freed,
+ BTRFS_QGROUP_RSV_DATA);
ret = freed;
out:
extent_changeset_release(&changeset);
@@ -2972,7 +3022,7 @@ static int __btrfs_qgroup_release_data(struct inode *inode,
if (free)
btrfs_qgroup_free_refroot(BTRFS_I(inode)->root->fs_info,
BTRFS_I(inode)->root->objectid,
- changeset.bytes_changed);
+ changeset.bytes_changed, BTRFS_QGROUP_RSV_DATA);
ret = changeset.bytes_changed;
out:
extent_changeset_release(&changeset);
@@ -3017,8 +3067,48 @@ int btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len)
return __btrfs_qgroup_release_data(inode, NULL, start, len, 0);
}
-int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
- bool enforce)
+static void add_root_meta_rsv(struct btrfs_root *root, int num_bytes,
+ enum btrfs_qgroup_rsv_type type)
+{
+ if (type != BTRFS_QGROUP_RSV_META_PREALLOC &&
+ type != BTRFS_QGROUP_RSV_META_PERTRANS)
+ return;
+ if (num_bytes == 0)
+ return;
+
+ spin_lock(&root->qgroup_meta_rsv_lock);
+ if (type == BTRFS_QGROUP_RSV_META_PREALLOC)
+ root->qgroup_meta_rsv_prealloc += num_bytes;
+ else
+ root->qgroup_meta_rsv_pertrans += num_bytes;
+ spin_unlock(&root->qgroup_meta_rsv_lock);
+}
+
+static int sub_root_meta_rsv(struct btrfs_root *root, int num_bytes,
+ enum btrfs_qgroup_rsv_type type)
+{
+ if (type != BTRFS_QGROUP_RSV_META_PREALLOC &&
+ type != BTRFS_QGROUP_RSV_META_PERTRANS)
+ return 0;
+ if (num_bytes == 0)
+ return 0;
+
+ spin_lock(&root->qgroup_meta_rsv_lock);
+ if (type == BTRFS_QGROUP_RSV_META_PREALLOC) {
+ num_bytes = min_t(u64, root->qgroup_meta_rsv_prealloc,
+ num_bytes);
+ root->qgroup_meta_rsv_prealloc -= num_bytes;
+ } else {
+ num_bytes = min_t(u64, root->qgroup_meta_rsv_pertrans,
+ num_bytes);
+ root->qgroup_meta_rsv_pertrans -= num_bytes;
+ }
+ spin_unlock(&root->qgroup_meta_rsv_lock);
+ return num_bytes;
+}
+
+int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
+ enum btrfs_qgroup_rsv_type type, bool enforce)
{
struct btrfs_fs_info *fs_info = root->fs_info;
int ret;
@@ -3028,31 +3118,39 @@ int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
return 0;
BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize));
- trace_qgroup_meta_reserve(root, (s64)num_bytes);
- ret = qgroup_reserve(root, num_bytes, enforce);
+ trace_qgroup_meta_reserve(root, type, (s64)num_bytes);
+ ret = qgroup_reserve(root, num_bytes, enforce, type);
if (ret < 0)
return ret;
- atomic64_add(num_bytes, &root->qgroup_meta_rsv);
+ /*
+ * Record what we have reserved into root.
+ *
+ * To avoid quota disabled->enabled underflow.
+ * In that case, we may try to free space we haven't reserved
+ * (since quota was disabled), so record what we reserved into root.
+ * And ensure later release won't underflow this number.
+ */
+ add_root_meta_rsv(root, num_bytes, type);
return ret;
}
-void btrfs_qgroup_free_meta_all(struct btrfs_root *root)
+void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root)
{
struct btrfs_fs_info *fs_info = root->fs_info;
- u64 reserved;
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
!is_fstree(root->objectid))
return;
- reserved = atomic64_xchg(&root->qgroup_meta_rsv, 0);
- if (reserved == 0)
- return;
- trace_qgroup_meta_reserve(root, -(s64)reserved);
- btrfs_qgroup_free_refroot(fs_info, root->objectid, reserved);
+ /* TODO: Update trace point to handle such free */
+ trace_qgroup_meta_free_all_pertrans(root);
+ /* Special value -1 means to free all reserved space */
+ btrfs_qgroup_free_refroot(fs_info, root->objectid, (u64)-1,
+ BTRFS_QGROUP_RSV_META_PERTRANS);
}
-void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes)
+void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes,
+ enum btrfs_qgroup_rsv_type type)
{
struct btrfs_fs_info *fs_info = root->fs_info;
@@ -3060,11 +3158,75 @@ void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes)
!is_fstree(root->objectid))
return;
+ /*
+ * reservation for META_PREALLOC can happen before quota is enabled,
+ * which can lead to underflow.
+ * Here ensure we will only free what we really have reserved.
+ */
+ num_bytes = sub_root_meta_rsv(root, num_bytes, type);
BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize));
- WARN_ON(atomic64_read(&root->qgroup_meta_rsv) < num_bytes);
- atomic64_sub(num_bytes, &root->qgroup_meta_rsv);
- trace_qgroup_meta_reserve(root, -(s64)num_bytes);
- btrfs_qgroup_free_refroot(fs_info, root->objectid, num_bytes);
+ trace_qgroup_meta_reserve(root, type, -(s64)num_bytes);
+ btrfs_qgroup_free_refroot(fs_info, root->objectid, num_bytes, type);
+}
+
+static void qgroup_convert_meta(struct btrfs_fs_info *fs_info, u64 ref_root,
+ int num_bytes)
+{
+ struct btrfs_root *quota_root = fs_info->quota_root;
+ struct btrfs_qgroup *qgroup;
+ struct ulist_node *unode;
+ struct ulist_iterator uiter;
+ int ret = 0;
+
+ if (num_bytes == 0)
+ return;
+ if (!quota_root)
+ return;
+
+ spin_lock(&fs_info->qgroup_lock);
+ qgroup = find_qgroup_rb(fs_info, ref_root);
+ if (!qgroup)
+ goto out;
+ ulist_reinit(fs_info->qgroup_ulist);
+ ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid,
+ qgroup_to_aux(qgroup), GFP_ATOMIC);
+ if (ret < 0)
+ goto out;
+ ULIST_ITER_INIT(&uiter);
+ while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) {
+ struct btrfs_qgroup *qg;
+ struct btrfs_qgroup_list *glist;
+
+ qg = unode_aux_to_qgroup(unode);
+
+ qgroup_rsv_release(fs_info, qg, num_bytes,
+ BTRFS_QGROUP_RSV_META_PREALLOC);
+ qgroup_rsv_add(fs_info, qg, num_bytes,
+ BTRFS_QGROUP_RSV_META_PERTRANS);
+ list_for_each_entry(glist, &qg->groups, next_group) {
+ ret = ulist_add(fs_info->qgroup_ulist,
+ glist->group->qgroupid,
+ qgroup_to_aux(glist->group), GFP_ATOMIC);
+ if (ret < 0)
+ goto out;
+ }
+ }
+out:
+ spin_unlock(&fs_info->qgroup_lock);
+}
+
+void btrfs_qgroup_convert_reserved_meta(struct btrfs_root *root, int num_bytes)
+{
+ struct btrfs_fs_info *fs_info = root->fs_info;
+
+ if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) ||
+ !is_fstree(root->objectid))
+ return;
+ /* Same as btrfs_qgroup_free_meta_prealloc() */
+ num_bytes = sub_root_meta_rsv(root, num_bytes,
+ BTRFS_QGROUP_RSV_META_PREALLOC);
+ trace_qgroup_meta_convert(root, num_bytes);
+ qgroup_convert_meta(fs_info, root->objectid, num_bytes);
}
/*
@@ -3092,7 +3254,7 @@ void btrfs_qgroup_check_reserved_leak(struct inode *inode)
}
btrfs_qgroup_free_refroot(BTRFS_I(inode)->root->fs_info,
BTRFS_I(inode)->root->objectid,
- changeset.bytes_changed);
+ changeset.bytes_changed, BTRFS_QGROUP_RSV_DATA);
}
extent_changeset_release(&changeset);
diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h
index d9984e87cddf..e63e2d497a8e 100644
--- a/fs/btrfs/qgroup.h
+++ b/fs/btrfs/qgroup.h
@@ -62,6 +62,48 @@ struct btrfs_qgroup_extent_record {
};
/*
+ * Qgroup reservation types:
+ *
+ * DATA:
+ * space reserved for data
+ *
+ * META_PERTRANS:
+ * Space reserved for metadata (per-transaction)
+ * Due to the fact that qgroup data is only updated at transaction commit
+ * time, reserved space for metadata must be kept until transaction
+ * commits.
+ * Any metadata reserved that are used in btrfs_start_transaction() should
+ * be of this type.
+ *
+ * META_PREALLOC:
+ * There are cases where metadata space is reserved before starting
+ * transaction, and then btrfs_join_transaction() to get a trans handle.
+ * Any metadata reserved for such usage should be of this type.
+ * And after join_transaction() part (or all) of such reservation should
+ * be converted into META_PERTRANS.
+ */
+enum btrfs_qgroup_rsv_type {
+ BTRFS_QGROUP_RSV_DATA = 0,
+ BTRFS_QGROUP_RSV_META_PERTRANS,
+ BTRFS_QGROUP_RSV_META_PREALLOC,
+ BTRFS_QGROUP_RSV_LAST,
+};
+
+/*
+ * Represents how many bytes we have reserved for this qgroup.
+ *
+ * Each type should have different reservation behavior.
+ * E.g, data follows its io_tree flag modification, while
+ * *currently* meta is just reserve-and-clear during transcation.
+ *
+ * TODO: Add new type for reservation which can survive transaction commit.
+ * Currect metadata reservation behavior is not suitable for such case.
+ */
+struct btrfs_qgroup_rsv {
+ u64 values[BTRFS_QGROUP_RSV_LAST];
+};
+
+/*
* one struct for each qgroup, organized in fs_info->qgroup_tree.
*/
struct btrfs_qgroup {
@@ -87,7 +129,7 @@ struct btrfs_qgroup {
/*
* reservation tracking
*/
- u64 reserved;
+ struct btrfs_qgroup_rsv rsv;
/*
* lists
@@ -220,20 +262,21 @@ btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info,
u64 bytenr, u64 num_bytes,
struct ulist *old_roots, struct ulist *new_roots);
-int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info);
+int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans);
int btrfs_run_qgroups(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 srcid, u64 objectid,
struct btrfs_qgroup_inherit *inherit);
void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
- u64 ref_root, u64 num_bytes);
+ u64 ref_root, u64 num_bytes,
+ enum btrfs_qgroup_rsv_type type);
static inline void btrfs_qgroup_free_delayed_ref(struct btrfs_fs_info *fs_info,
u64 ref_root, u64 num_bytes)
{
trace_btrfs_qgroup_free_delayed_ref(fs_info, ref_root, num_bytes);
- btrfs_qgroup_free_refroot(fs_info, ref_root, num_bytes);
+ btrfs_qgroup_free_refroot(fs_info, ref_root, num_bytes,
+ BTRFS_QGROUP_RSV_DATA);
}
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
@@ -248,9 +291,54 @@ int btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len);
int btrfs_qgroup_free_data(struct inode *inode,
struct extent_changeset *reserved, u64 start, u64 len);
-int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
- bool enforce);
-void btrfs_qgroup_free_meta_all(struct btrfs_root *root);
-void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes);
+int __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes,
+ enum btrfs_qgroup_rsv_type type, bool enforce);
+/* Reserve metadata space for pertrans and prealloc type */
+static inline int btrfs_qgroup_reserve_meta_pertrans(struct btrfs_root *root,
+ int num_bytes, bool enforce)
+{
+ return __btrfs_qgroup_reserve_meta(root, num_bytes,
+ BTRFS_QGROUP_RSV_META_PERTRANS, enforce);
+}
+static inline int btrfs_qgroup_reserve_meta_prealloc(struct btrfs_root *root,
+ int num_bytes, bool enforce)
+{
+ return __btrfs_qgroup_reserve_meta(root, num_bytes,
+ BTRFS_QGROUP_RSV_META_PREALLOC, enforce);
+}
+
+void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes,
+ enum btrfs_qgroup_rsv_type type);
+
+/* Free per-transaction meta reservation for error handling */
+static inline void btrfs_qgroup_free_meta_pertrans(struct btrfs_root *root,
+ int num_bytes)
+{
+ __btrfs_qgroup_free_meta(root, num_bytes,
+ BTRFS_QGROUP_RSV_META_PERTRANS);
+}
+
+/* Pre-allocated meta reservation can be freed at need */
+static inline void btrfs_qgroup_free_meta_prealloc(struct btrfs_root *root,
+ int num_bytes)
+{
+ __btrfs_qgroup_free_meta(root, num_bytes,
+ BTRFS_QGROUP_RSV_META_PREALLOC);
+}
+
+/*
+ * Per-transaction meta reservation should be all freed at transaction commit
+ * time
+ */
+void btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root);
+
+/*
+ * Convert @num_bytes of META_PREALLOCATED reservation to META_PERTRANS.
+ *
+ * This is called when preallocated meta reservation needs to be used.
+ * Normally after btrfs_join_transaction() call.
+ */
+void btrfs_qgroup_convert_reserved_meta(struct btrfs_root *root, int num_bytes);
+
void btrfs_qgroup_check_reserved_leak(struct inode *inode);
#endif /* __BTRFS_QGROUP__ */
diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
index fcfc20de2df3..c3a2bc8af675 100644
--- a/fs/btrfs/raid56.c
+++ b/fs/btrfs/raid56.c
@@ -1987,7 +1987,13 @@ cleanup:
kfree(pointers);
cleanup_io:
- if (rbio->operation == BTRFS_RBIO_READ_REBUILD) {
+ /*
+ * Similar to READ_REBUILD, REBUILD_MISSING at this point also has a
+ * valid rbio which is consistent with ondisk content, thus such a
+ * valid rbio can be cached to avoid further disk reads.
+ */
+ if (rbio->operation == BTRFS_RBIO_READ_REBUILD ||
+ rbio->operation == BTRFS_RBIO_REBUILD_MISSING) {
/*
* - In case of two failures, where rbio->failb != -1:
*
@@ -2009,8 +2015,6 @@ cleanup_io:
clear_bit(RBIO_CACHE_READY_BIT, &rbio->flags);
rbio_orig_end_io(rbio, err);
- } else if (rbio->operation == BTRFS_RBIO_REBUILD_MISSING) {
- rbio_orig_end_io(rbio, err);
} else if (err == BLK_STS_OK) {
rbio->faila = -1;
rbio->failb = -1;
@@ -2768,24 +2772,8 @@ raid56_alloc_missing_rbio(struct btrfs_fs_info *fs_info, struct bio *bio,
return rbio;
}
-static void missing_raid56_work(struct btrfs_work *work)
-{
- struct btrfs_raid_bio *rbio;
-
- rbio = container_of(work, struct btrfs_raid_bio, work);
- __raid56_parity_recover(rbio);
-}
-
-static void async_missing_raid56(struct btrfs_raid_bio *rbio)
-{
- btrfs_init_work(&rbio->work, btrfs_rmw_helper,
- missing_raid56_work, NULL, NULL);
-
- btrfs_queue_work(rbio->fs_info->rmw_workers, &rbio->work);
-}
-
void raid56_submit_missing_rbio(struct btrfs_raid_bio *rbio)
{
if (!lock_stripe_add(rbio))
- async_missing_raid56(rbio);
+ async_read_rebuild(rbio);
}
diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c
index ab852b8e3e37..a52dd12af648 100644
--- a/fs/btrfs/reada.c
+++ b/fs/btrfs/reada.c
@@ -395,20 +395,20 @@ static struct reada_extent *reada_find_extent(struct btrfs_fs_info *fs_info,
goto error;
/* insert extent in reada_tree + all per-device trees, all or nothing */
- btrfs_dev_replace_lock(&fs_info->dev_replace, 0);
+ btrfs_dev_replace_read_lock(&fs_info->dev_replace);
spin_lock(&fs_info->reada_lock);
ret = radix_tree_insert(&fs_info->reada_tree, index, re);
if (ret == -EEXIST) {
re_exist = radix_tree_lookup(&fs_info->reada_tree, index);
re_exist->refcnt++;
spin_unlock(&fs_info->reada_lock);
- btrfs_dev_replace_unlock(&fs_info->dev_replace, 0);
+ btrfs_dev_replace_read_unlock(&fs_info->dev_replace);
radix_tree_preload_end();
goto error;
}
if (ret) {
spin_unlock(&fs_info->reada_lock);
- btrfs_dev_replace_unlock(&fs_info->dev_replace, 0);
+ btrfs_dev_replace_read_unlock(&fs_info->dev_replace);
radix_tree_preload_end();
goto error;
}
@@ -451,13 +451,13 @@ static struct reada_extent *reada_find_extent(struct btrfs_fs_info *fs_info,
}
radix_tree_delete(&fs_info->reada_tree, index);
spin_unlock(&fs_info->reada_lock);
- btrfs_dev_replace_unlock(&fs_info->dev_replace, 0);
+ btrfs_dev_replace_read_unlock(&fs_info->dev_replace);
goto error;
}
have_zone = 1;
}
spin_unlock(&fs_info->reada_lock);
- btrfs_dev_replace_unlock(&fs_info->dev_replace, 0);
+ btrfs_dev_replace_read_unlock(&fs_info->dev_replace);
if (!have_zone)
goto error;
diff --git a/fs/btrfs/ref-verify.c b/fs/btrfs/ref-verify.c
index 171f3cce30e6..35fab67dcbe8 100644
--- a/fs/btrfs/ref-verify.c
+++ b/fs/btrfs/ref-verify.c
@@ -579,11 +579,16 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
while (level >= 0) {
if (level) {
+ struct btrfs_key first_key;
+
block_bytenr = btrfs_node_blockptr(path->nodes[level],
path->slots[level]);
gen = btrfs_node_ptr_generation(path->nodes[level],
path->slots[level]);
- eb = read_tree_block(fs_info, block_bytenr, gen);
+ btrfs_node_key_to_cpu(path->nodes[level], &first_key,
+ path->slots[level]);
+ eb = read_tree_block(fs_info, block_bytenr, gen,
+ level - 1, &first_key);
if (IS_ERR(eb))
return PTR_ERR(eb);
if (!extent_buffer_uptodate(eb)) {
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index cd2298d185dd..4874c09f6d3c 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -1839,6 +1839,8 @@ again:
parent = eb;
while (1) {
+ struct btrfs_key first_key;
+
level = btrfs_header_level(parent);
BUG_ON(level < lowest_level);
@@ -1852,6 +1854,7 @@ again:
old_bytenr = btrfs_node_blockptr(parent, slot);
blocksize = fs_info->nodesize;
old_ptr_gen = btrfs_node_ptr_generation(parent, slot);
+ btrfs_node_key_to_cpu(parent, &key, slot);
if (level <= max_level) {
eb = path->nodes[level];
@@ -1876,7 +1879,8 @@ again:
break;
}
- eb = read_tree_block(fs_info, old_bytenr, old_ptr_gen);
+ eb = read_tree_block(fs_info, old_bytenr, old_ptr_gen,
+ level - 1, &first_key);
if (IS_ERR(eb)) {
ret = PTR_ERR(eb);
break;
@@ -2036,6 +2040,8 @@ int walk_down_reloc_tree(struct btrfs_root *root, struct btrfs_path *path,
last_snapshot = btrfs_root_last_snapshot(&root->root_item);
for (i = *level; i > 0; i--) {
+ struct btrfs_key first_key;
+
eb = path->nodes[i];
nritems = btrfs_header_nritems(eb);
while (path->slots[i] < nritems) {
@@ -2056,7 +2062,9 @@ int walk_down_reloc_tree(struct btrfs_root *root, struct btrfs_path *path,
}
bytenr = btrfs_node_blockptr(eb, path->slots[i]);
- eb = read_tree_block(fs_info, bytenr, ptr_gen);
+ btrfs_node_key_to_cpu(eb, &first_key, path->slots[i]);
+ eb = read_tree_block(fs_info, bytenr, ptr_gen, i - 1,
+ &first_key);
if (IS_ERR(eb)) {
return PTR_ERR(eb);
} else if (!extent_buffer_uptodate(eb)) {
@@ -2714,6 +2722,8 @@ static int do_relocation(struct btrfs_trans_handle *trans,
path->lowest_level = node->level + 1;
rc->backref_cache.path[node->level] = node;
list_for_each_entry(edge, &node->upper, list[LOWER]) {
+ struct btrfs_key first_key;
+
cond_resched();
upper = edge->node[UPPER];
@@ -2779,7 +2789,9 @@ static int do_relocation(struct btrfs_trans_handle *trans,
blocksize = root->fs_info->nodesize;
generation = btrfs_node_ptr_generation(upper->eb, slot);
- eb = read_tree_block(fs_info, bytenr, generation);
+ btrfs_node_key_to_cpu(upper->eb, &first_key, slot);
+ eb = read_tree_block(fs_info, bytenr, generation,
+ upper->level - 1, &first_key);
if (IS_ERR(eb)) {
err = PTR_ERR(eb);
goto next;
@@ -2944,7 +2956,8 @@ static int get_tree_block_key(struct btrfs_fs_info *fs_info,
struct extent_buffer *eb;
BUG_ON(block->key_ready);
- eb = read_tree_block(fs_info, block->bytenr, block->key.offset);
+ eb = read_tree_block(fs_info, block->bytenr, block->key.offset,
+ block->level, NULL);
if (IS_ERR(eb)) {
return PTR_ERR(eb);
} else if (!extent_buffer_uptodate(eb)) {
@@ -3226,7 +3239,7 @@ static int relocate_file_extent_cluster(struct inode *inode,
mask);
if (!page) {
btrfs_delalloc_release_metadata(BTRFS_I(inode),
- PAGE_SIZE);
+ PAGE_SIZE, true);
ret = -ENOMEM;
goto out;
}
@@ -3245,9 +3258,9 @@ static int relocate_file_extent_cluster(struct inode *inode,
unlock_page(page);
put_page(page);
btrfs_delalloc_release_metadata(BTRFS_I(inode),
- PAGE_SIZE);
+ PAGE_SIZE, true);
btrfs_delalloc_release_extents(BTRFS_I(inode),
- PAGE_SIZE);
+ PAGE_SIZE, true);
ret = -EIO;
goto out;
}
@@ -3274,9 +3287,9 @@ static int relocate_file_extent_cluster(struct inode *inode,
unlock_page(page);
put_page(page);
btrfs_delalloc_release_metadata(BTRFS_I(inode),
- PAGE_SIZE);
+ PAGE_SIZE, true);
btrfs_delalloc_release_extents(BTRFS_I(inode),
- PAGE_SIZE);
+ PAGE_SIZE, true);
clear_extent_bits(&BTRFS_I(inode)->io_tree,
page_start, page_end,
@@ -3292,7 +3305,8 @@ static int relocate_file_extent_cluster(struct inode *inode,
put_page(page);
index++;
- btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE);
+ btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE,
+ false);
balance_dirty_pages_ratelimited(inode->i_mapping);
btrfs_throttle(fs_info);
}
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index ec56f33feea9..1a2066ac6fe7 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -371,7 +371,7 @@ static struct full_stripe_lock *insert_full_stripe_lock(
struct full_stripe_lock *entry;
struct full_stripe_lock *ret;
- WARN_ON(!mutex_is_locked(&locks_root->lock));
+ lockdep_assert_held(&locks_root->lock);
p = &locks_root->root.rb_node;
while (*p) {
@@ -413,7 +413,7 @@ static struct full_stripe_lock *search_full_stripe_lock(
struct rb_node *node;
struct full_stripe_lock *entry;
- WARN_ON(!mutex_is_locked(&locks_root->lock));
+ lockdep_assert_held(&locks_root->lock);
node = locks_root->root.rb_node;
while (node) {
@@ -1111,7 +1111,6 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
struct scrub_ctx *sctx = sblock_to_check->sctx;
struct btrfs_device *dev;
struct btrfs_fs_info *fs_info;
- u64 length;
u64 logical;
unsigned int failed_mirror_index;
unsigned int is_metadata;
@@ -1139,7 +1138,6 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
spin_unlock(&sctx->stat_lock);
return 0;
}
- length = sblock_to_check->page_count * PAGE_SIZE;
logical = sblock_to_check->pagev[0]->logical;
BUG_ON(sblock_to_check->pagev[0]->mirror_num < 1);
failed_mirror_index = sblock_to_check->pagev[0]->mirror_num - 1;
@@ -1412,8 +1410,17 @@ nodatasum_case:
if (!page_bad->io_error && !sctx->is_dev_replace)
continue;
- /* try to find no-io-error page in mirrors */
- if (page_bad->io_error) {
+ if (scrub_is_page_on_raid56(sblock_bad->pagev[0])) {
+ /*
+ * In case of dev replace, if raid56 rebuild process
+ * didn't work out correct data, then copy the content
+ * in sblock_bad to make sure target device is identical
+ * to source device, instead of writing garbage data in
+ * sblock_for_recheck array to target device.
+ */
+ sblock_other = NULL;
+ } else if (page_bad->io_error) {
+ /* try to find no-io-error page in mirrors */
for (mirror_index = 0;
mirror_index < BTRFS_MAX_MIRRORS &&
sblocks_for_recheck[mirror_index].page_count > 0;
@@ -1718,6 +1725,45 @@ static int scrub_submit_raid56_bio_wait(struct btrfs_fs_info *fs_info,
return blk_status_to_errno(bio->bi_status);
}
+static void scrub_recheck_block_on_raid56(struct btrfs_fs_info *fs_info,
+ struct scrub_block *sblock)
+{
+ struct scrub_page *first_page = sblock->pagev[0];
+ struct bio *bio;
+ int page_num;
+
+ /* All pages in sblock belong to the same stripe on the same device. */
+ ASSERT(first_page->dev);
+ if (!first_page->dev->bdev)
+ goto out;
+
+ bio = btrfs_io_bio_alloc(BIO_MAX_PAGES);
+ bio_set_dev(bio, first_page->dev->bdev);
+
+ for (page_num = 0; page_num < sblock->page_count; page_num++) {
+ struct scrub_page *page = sblock->pagev[page_num];
+
+ WARN_ON(!page->page);
+ bio_add_page(bio, page->page, PAGE_SIZE, 0);
+ }
+
+ if (scrub_submit_raid56_bio_wait(fs_info, bio, first_page)) {
+ bio_put(bio);
+ goto out;
+ }
+
+ bio_put(bio);
+
+ scrub_recheck_block_checksum(sblock);
+
+ return;
+out:
+ for (page_num = 0; page_num < sblock->page_count; page_num++)
+ sblock->pagev[page_num]->io_error = 1;
+
+ sblock->no_io_error_seen = 0;
+}
+
/*
* this function will check the on disk data for checksum errors, header
* errors and read I/O errors. If any I/O errors happen, the exact pages
@@ -1733,6 +1779,10 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
sblock->no_io_error_seen = 1;
+ /* short cut for raid56 */
+ if (!retry_failed_mirror && scrub_is_page_on_raid56(sblock->pagev[0]))
+ return scrub_recheck_block_on_raid56(fs_info, sblock);
+
for (page_num = 0; page_num < sblock->page_count; page_num++) {
struct bio *bio;
struct scrub_page *page = sblock->pagev[page_num];
@@ -1748,19 +1798,12 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
bio_set_dev(bio, page->dev->bdev);
bio_add_page(bio, page->page, PAGE_SIZE, 0);
- if (!retry_failed_mirror && scrub_is_page_on_raid56(page)) {
- if (scrub_submit_raid56_bio_wait(fs_info, bio, page)) {
- page->io_error = 1;
- sblock->no_io_error_seen = 0;
- }
- } else {
- bio->bi_iter.bi_sector = page->physical >> 9;
- bio_set_op_attrs(bio, REQ_OP_READ, 0);
+ bio->bi_iter.bi_sector = page->physical >> 9;
+ bio->bi_opf = REQ_OP_READ;
- if (btrfsic_submit_bio_wait(bio)) {
- page->io_error = 1;
- sblock->no_io_error_seen = 0;
- }
+ if (btrfsic_submit_bio_wait(bio)) {
+ page->io_error = 1;
+ sblock->no_io_error_seen = 0;
}
bio_put(bio);
@@ -2728,7 +2771,8 @@ static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u8 *csum)
}
/* scrub extent tries to collect up to 64 kB for each bio */
-static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len,
+static int scrub_extent(struct scrub_ctx *sctx, struct map_lookup *map,
+ u64 logical, u64 len,
u64 physical, struct btrfs_device *dev, u64 flags,
u64 gen, int mirror_num, u64 physical_for_dev_replace)
{
@@ -2737,13 +2781,19 @@ static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len,
u32 blocksize;
if (flags & BTRFS_EXTENT_FLAG_DATA) {
- blocksize = sctx->fs_info->sectorsize;
+ if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
+ blocksize = map->stripe_len;
+ else
+ blocksize = sctx->fs_info->sectorsize;
spin_lock(&sctx->stat_lock);
sctx->stat.data_extents_scrubbed++;
sctx->stat.data_bytes_scrubbed += len;
spin_unlock(&sctx->stat_lock);
} else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
- blocksize = sctx->fs_info->nodesize;
+ if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
+ blocksize = map->stripe_len;
+ else
+ blocksize = sctx->fs_info->nodesize;
spin_lock(&sctx->stat_lock);
sctx->stat.tree_extents_scrubbed++;
sctx->stat.tree_bytes_scrubbed += len;
@@ -2883,9 +2933,9 @@ static int scrub_extent_for_parity(struct scrub_parity *sparity,
}
if (flags & BTRFS_EXTENT_FLAG_DATA) {
- blocksize = sctx->fs_info->sectorsize;
+ blocksize = sparity->stripe_len;
} else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
- blocksize = sctx->fs_info->nodesize;
+ blocksize = sparity->stripe_len;
} else {
blocksize = sctx->fs_info->sectorsize;
WARN_ON(1);
@@ -3595,7 +3645,7 @@ again:
if (ret)
goto out;
- ret = scrub_extent(sctx, extent_logical, extent_len,
+ ret = scrub_extent(sctx, map, extent_logical, extent_len,
extent_physical, extent_dev, flags,
generation, extent_mirror_num,
extent_logical - logical + physical);
@@ -3885,11 +3935,11 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
break;
}
- btrfs_dev_replace_lock(&fs_info->dev_replace, 1);
+ btrfs_dev_replace_write_lock(&fs_info->dev_replace);
dev_replace->cursor_right = found_key.offset + length;
dev_replace->cursor_left = found_key.offset;
dev_replace->item_needs_writeback = 1;
- btrfs_dev_replace_unlock(&fs_info->dev_replace, 1);
+ btrfs_dev_replace_write_unlock(&fs_info->dev_replace);
ret = scrub_chunk(sctx, scrub_dev, chunk_offset, length,
found_key.offset, cache, is_dev_replace);
@@ -3925,10 +3975,10 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
scrub_pause_off(fs_info);
- btrfs_dev_replace_lock(&fs_info->dev_replace, 1);
+ btrfs_dev_replace_write_lock(&fs_info->dev_replace);
dev_replace->cursor_left = dev_replace->cursor_right;
dev_replace->item_needs_writeback = 1;
- btrfs_dev_replace_unlock(&fs_info->dev_replace, 1);
+ btrfs_dev_replace_write_unlock(&fs_info->dev_replace);
if (ro_set)
btrfs_dec_block_group_ro(cache);
@@ -4144,16 +4194,16 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
return -EIO;
}
- btrfs_dev_replace_lock(&fs_info->dev_replace, 0);
+ btrfs_dev_replace_read_lock(&fs_info->dev_replace);
if (dev->scrub_ctx ||
(!is_dev_replace &&
btrfs_dev_replace_is_ongoing(&fs_info->dev_replace))) {
- btrfs_dev_replace_unlock(&fs_info->dev_replace, 0);
+ btrfs_dev_replace_read_unlock(&fs_info->dev_replace);
mutex_unlock(&fs_info->scrub_lock);
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
return -EINPROGRESS;
}
- btrfs_dev_replace_unlock(&fs_info->dev_replace, 0);
+ btrfs_dev_replace_read_unlock(&fs_info->dev_replace);
ret = scrub_workers_get(fs_info, is_dev_replace);
if (ret) {
@@ -4480,7 +4530,8 @@ static int check_extent_to_block(struct btrfs_inode *inode, u64 start, u64 len,
* move on to the next inode.
*/
if (em->block_start > logical ||
- em->block_start + em->block_len < logical + len) {
+ em->block_start + em->block_len < logical + len ||
+ test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
free_extent_map(em);
ret = 1;
goto out_unlock;
@@ -4620,7 +4671,6 @@ static int write_page_nocow(struct scrub_ctx *sctx,
{
struct bio *bio;
struct btrfs_device *dev;
- int ret;
dev = sctx->wr_tgtdev;
if (!dev)
@@ -4635,17 +4685,15 @@ static int write_page_nocow(struct scrub_ctx *sctx,
bio->bi_iter.bi_sector = physical_for_dev_replace >> 9;
bio_set_dev(bio, dev->bdev);
bio->bi_opf = REQ_OP_WRITE | REQ_SYNC;
- ret = bio_add_page(bio, page, PAGE_SIZE, 0);
- if (ret != PAGE_SIZE) {
-leave_with_eio:
+ /* bio_add_page won't fail on a freshly allocated bio */
+ bio_add_page(bio, page, PAGE_SIZE, 0);
+
+ if (btrfsic_submit_bio_wait(bio)) {
bio_put(bio);
btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS);
return -EIO;
}
- if (btrfsic_submit_bio_wait(bio))
- goto leave_with_eio;
-
bio_put(bio);
return 0;
}
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 484e2af793de..1f5748c7d1c7 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -27,10 +27,10 @@
#include <linux/vmalloc.h>
#include <linux/string.h>
#include <linux/compat.h>
+#include <linux/crc32c.h>
#include "send.h"
#include "backref.h"
-#include "hash.h"
#include "locking.h"
#include "disk-io.h"
#include "btrfs_inode.h"
@@ -112,6 +112,7 @@ struct send_ctx {
u64 cur_inode_mode;
u64 cur_inode_rdev;
u64 cur_inode_last_extent;
+ u64 cur_inode_next_write_offset;
u64 send_progress;
@@ -270,6 +271,7 @@ struct name_cache_entry {
char name[];
};
+__cold
static void inconsistent_snapshot_error(struct send_ctx *sctx,
enum btrfs_compare_tree_result result,
const char *what)
@@ -611,9 +613,9 @@ static int tlv_put_btrfs_timespec(struct send_ctx *sctx, u16 attr,
}
-#define TLV_PUT(sctx, attrtype, attrlen, data) \
+#define TLV_PUT(sctx, attrtype, data, attrlen) \
do { \
- ret = tlv_put(sctx, attrtype, attrlen, data); \
+ ret = tlv_put(sctx, attrtype, data, attrlen); \
if (ret < 0) \
goto tlv_put_failure; \
} while (0)
@@ -695,7 +697,7 @@ static int send_cmd(struct send_ctx *sctx)
hdr->len = cpu_to_le32(sctx->send_size - sizeof(*hdr));
hdr->crc = 0;
- crc = btrfs_crc32c(0, (unsigned char *)sctx->send_buf, sctx->send_size);
+ crc = crc32c(0, (unsigned char *)sctx->send_buf, sctx->send_size);
hdr->crc = cpu_to_le32(crc);
ret = write_buf(sctx->send_filp, sctx->send_buf, sctx->send_size,
@@ -5029,6 +5031,7 @@ static int send_hole(struct send_ctx *sctx, u64 end)
break;
offset += len;
}
+ sctx->cur_inode_next_write_offset = offset;
tlv_put_failure:
fs_path_free(p);
return ret;
@@ -5264,6 +5267,7 @@ static int send_write_or_clone(struct send_ctx *sctx,
} else {
ret = send_extent_data(sctx, offset, len);
}
+ sctx->cur_inode_next_write_offset = offset + len;
out:
return ret;
}
@@ -5788,6 +5792,7 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
u64 right_gid;
int need_chmod = 0;
int need_chown = 0;
+ int need_truncate = 1;
int pending_move = 0;
int refs_processed = 0;
@@ -5825,9 +5830,13 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
need_chown = 1;
if (!S_ISLNK(sctx->cur_inode_mode))
need_chmod = 1;
+ if (sctx->cur_inode_next_write_offset == sctx->cur_inode_size)
+ need_truncate = 0;
} else {
+ u64 old_size;
+
ret = get_inode_info(sctx->parent_root, sctx->cur_ino,
- NULL, NULL, &right_mode, &right_uid,
+ &old_size, NULL, &right_mode, &right_uid,
&right_gid, NULL);
if (ret < 0)
goto out;
@@ -5836,6 +5845,10 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
need_chown = 1;
if (!S_ISLNK(sctx->cur_inode_mode) && left_mode != right_mode)
need_chmod = 1;
+ if ((old_size == sctx->cur_inode_size) ||
+ (sctx->cur_inode_size > old_size &&
+ sctx->cur_inode_next_write_offset == sctx->cur_inode_size))
+ need_truncate = 0;
}
if (S_ISREG(sctx->cur_inode_mode)) {
@@ -5854,10 +5867,13 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
goto out;
}
}
- ret = send_truncate(sctx, sctx->cur_ino, sctx->cur_inode_gen,
- sctx->cur_inode_size);
- if (ret < 0)
- goto out;
+ if (need_truncate) {
+ ret = send_truncate(sctx, sctx->cur_ino,
+ sctx->cur_inode_gen,
+ sctx->cur_inode_size);
+ if (ret < 0)
+ goto out;
+ }
}
if (need_chown) {
@@ -5911,6 +5927,7 @@ static int changed_inode(struct send_ctx *sctx,
sctx->cur_ino = key->objectid;
sctx->cur_inode_new_gen = 0;
sctx->cur_inode_last_extent = (u64)-1;
+ sctx->cur_inode_next_write_offset = 0;
/*
* Set send_progress to current inode. This will tell all get_cur_xxx
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 4b817947e00f..170baef49fae 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -41,6 +41,7 @@
#include <linux/slab.h>
#include <linux/cleancache.h>
#include <linux/ratelimit.h>
+#include <linux/crc32c.h>
#include <linux/btrfs.h>
#include "delayed-inode.h"
#include "ctree.h"
@@ -48,7 +49,6 @@
#include "transaction.h"
#include "btrfs_inode.h"
#include "print-tree.h"
-#include "hash.h"
#include "props.h"
#include "xattr.h"
#include "volumes.h"
@@ -308,21 +308,50 @@ static void btrfs_put_super(struct super_block *sb)
}
enum {
- Opt_degraded, Opt_subvol, Opt_subvolid, Opt_device, Opt_nodatasum,
- Opt_nodatacow, Opt_max_inline, Opt_alloc_start, Opt_nobarrier, Opt_ssd,
- Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl, Opt_compress,
- Opt_compress_type, Opt_compress_force, Opt_compress_force_type,
- Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard,
- Opt_space_cache, Opt_space_cache_version, Opt_clear_cache,
- Opt_user_subvol_rm_allowed, Opt_enospc_debug, Opt_subvolrootid,
- Opt_defrag, Opt_inode_cache, Opt_no_space_cache, Opt_recovery,
- Opt_skip_balance, Opt_check_integrity,
+ Opt_acl, Opt_noacl,
+ Opt_clear_cache,
+ Opt_commit_interval,
+ Opt_compress,
+ Opt_compress_force,
+ Opt_compress_force_type,
+ Opt_compress_type,
+ Opt_degraded,
+ Opt_device,
+ Opt_fatal_errors,
+ Opt_flushoncommit, Opt_noflushoncommit,
+ Opt_inode_cache, Opt_noinode_cache,
+ Opt_max_inline,
+ Opt_barrier, Opt_nobarrier,
+ Opt_datacow, Opt_nodatacow,
+ Opt_datasum, Opt_nodatasum,
+ Opt_defrag, Opt_nodefrag,
+ Opt_discard, Opt_nodiscard,
+ Opt_nologreplay,
+ Opt_norecovery,
+ Opt_ratio,
+ Opt_rescan_uuid_tree,
+ Opt_skip_balance,
+ Opt_space_cache, Opt_no_space_cache,
+ Opt_space_cache_version,
+ Opt_ssd, Opt_nossd,
+ Opt_ssd_spread, Opt_nossd_spread,
+ Opt_subvol,
+ Opt_subvolid,
+ Opt_thread_pool,
+ Opt_treelog, Opt_notreelog,
+ Opt_usebackuproot,
+ Opt_user_subvol_rm_allowed,
+
+ /* Deprecated options */
+ Opt_alloc_start,
+ Opt_recovery,
+ Opt_subvolrootid,
+
+ /* Debugging options */
+ Opt_check_integrity,
Opt_check_integrity_including_extent_data,
- Opt_check_integrity_print_mask, Opt_fatal_errors, Opt_rescan_uuid_tree,
- Opt_commit_interval, Opt_barrier, Opt_nodefrag, Opt_nodiscard,
- Opt_noenospc_debug, Opt_noflushoncommit, Opt_acl, Opt_datacow,
- Opt_datasum, Opt_treelog, Opt_noinode_cache, Opt_usebackuproot,
- Opt_nologreplay, Opt_norecovery,
+ Opt_check_integrity_print_mask,
+ Opt_enospc_debug, Opt_noenospc_debug,
#ifdef CONFIG_BTRFS_DEBUG
Opt_fragment_data, Opt_fragment_metadata, Opt_fragment_all,
#endif
@@ -333,58 +362,63 @@ enum {
};
static const match_table_t tokens = {
- {Opt_degraded, "degraded"},
- {Opt_subvol, "subvol=%s"},
- {Opt_subvolid, "subvolid=%s"},
- {Opt_device, "device=%s"},
- {Opt_nodatasum, "nodatasum"},
- {Opt_datasum, "datasum"},
- {Opt_nodatacow, "nodatacow"},
- {Opt_datacow, "datacow"},
- {Opt_nobarrier, "nobarrier"},
- {Opt_barrier, "barrier"},
- {Opt_max_inline, "max_inline=%s"},
- {Opt_alloc_start, "alloc_start=%s"},
- {Opt_thread_pool, "thread_pool=%d"},
+ {Opt_acl, "acl"},
+ {Opt_noacl, "noacl"},
+ {Opt_clear_cache, "clear_cache"},
+ {Opt_commit_interval, "commit=%u"},
{Opt_compress, "compress"},
{Opt_compress_type, "compress=%s"},
{Opt_compress_force, "compress-force"},
{Opt_compress_force_type, "compress-force=%s"},
- {Opt_ssd, "ssd"},
- {Opt_ssd_spread, "ssd_spread"},
- {Opt_nossd, "nossd"},
- {Opt_acl, "acl"},
- {Opt_noacl, "noacl"},
- {Opt_notreelog, "notreelog"},
- {Opt_treelog, "treelog"},
- {Opt_nologreplay, "nologreplay"},
- {Opt_norecovery, "norecovery"},
+ {Opt_degraded, "degraded"},
+ {Opt_device, "device=%s"},
+ {Opt_fatal_errors, "fatal_errors=%s"},
{Opt_flushoncommit, "flushoncommit"},
{Opt_noflushoncommit, "noflushoncommit"},
- {Opt_ratio, "metadata_ratio=%d"},
+ {Opt_inode_cache, "inode_cache"},
+ {Opt_noinode_cache, "noinode_cache"},
+ {Opt_max_inline, "max_inline=%s"},
+ {Opt_barrier, "barrier"},
+ {Opt_nobarrier, "nobarrier"},
+ {Opt_datacow, "datacow"},
+ {Opt_nodatacow, "nodatacow"},
+ {Opt_datasum, "datasum"},
+ {Opt_nodatasum, "nodatasum"},
+ {Opt_defrag, "autodefrag"},
+ {Opt_nodefrag, "noautodefrag"},
{Opt_discard, "discard"},
{Opt_nodiscard, "nodiscard"},
+ {Opt_nologreplay, "nologreplay"},
+ {Opt_norecovery, "norecovery"},
+ {Opt_ratio, "metadata_ratio=%u"},
+ {Opt_rescan_uuid_tree, "rescan_uuid_tree"},
+ {Opt_skip_balance, "skip_balance"},
{Opt_space_cache, "space_cache"},
+ {Opt_no_space_cache, "nospace_cache"},
{Opt_space_cache_version, "space_cache=%s"},
- {Opt_clear_cache, "clear_cache"},
+ {Opt_ssd, "ssd"},
+ {Opt_nossd, "nossd"},
+ {Opt_ssd_spread, "ssd_spread"},
+ {Opt_nossd_spread, "nossd_spread"},
+ {Opt_subvol, "subvol=%s"},
+ {Opt_subvolid, "subvolid=%s"},
+ {Opt_thread_pool, "thread_pool=%u"},
+ {Opt_treelog, "treelog"},
+ {Opt_notreelog, "notreelog"},
+ {Opt_usebackuproot, "usebackuproot"},
{Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"},
- {Opt_enospc_debug, "enospc_debug"},
- {Opt_noenospc_debug, "noenospc_debug"},
+
+ /* Deprecated options */
+ {Opt_alloc_start, "alloc_start=%s"},
+ {Opt_recovery, "recovery"},
{Opt_subvolrootid, "subvolrootid=%d"},
- {Opt_defrag, "autodefrag"},
- {Opt_nodefrag, "noautodefrag"},
- {Opt_inode_cache, "inode_cache"},
- {Opt_noinode_cache, "noinode_cache"},
- {Opt_no_space_cache, "nospace_cache"},
- {Opt_recovery, "recovery"}, /* deprecated */
- {Opt_usebackuproot, "usebackuproot"},
- {Opt_skip_balance, "skip_balance"},
+
+ /* Debugging options */
{Opt_check_integrity, "check_int"},
{Opt_check_integrity_including_extent_data, "check_int_data"},
- {Opt_check_integrity_print_mask, "check_int_print_mask=%d"},
- {Opt_rescan_uuid_tree, "rescan_uuid_tree"},
- {Opt_fatal_errors, "fatal_errors=%s"},
- {Opt_commit_interval, "commit=%d"},
+ {Opt_check_integrity_print_mask, "check_int_print_mask=%u"},
+ {Opt_enospc_debug, "enospc_debug"},
+ {Opt_noenospc_debug, "noenospc_debug"},
#ifdef CONFIG_BTRFS_DEBUG
{Opt_fragment_data, "fragment=data"},
{Opt_fragment_metadata, "fragment=metadata"},
@@ -579,6 +613,8 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
btrfs_set_opt(info->mount_opt, NOSSD);
btrfs_clear_and_info(info, SSD,
"not using ssd optimizations");
+ /* Fallthrough */
+ case Opt_nossd_spread:
btrfs_clear_and_info(info, SSD_SPREAD,
"not using spread ssd allocation scheme");
break;
@@ -594,12 +630,11 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
ret = match_int(&args[0], &intarg);
if (ret) {
goto out;
- } else if (intarg > 0) {
- info->thread_pool_size = intarg;
- } else {
+ } else if (intarg == 0) {
ret = -EINVAL;
goto out;
}
+ info->thread_pool_size = intarg;
break;
case Opt_max_inline:
num = match_strdup(&args[0]);
@@ -658,16 +693,11 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
break;
case Opt_ratio:
ret = match_int(&args[0], &intarg);
- if (ret) {
+ if (ret)
goto out;
- } else if (intarg >= 0) {
- info->metadata_ratio = intarg;
- btrfs_info(info, "metadata ratio %d",
- info->metadata_ratio);
- } else {
- ret = -EINVAL;
- goto out;
- }
+ info->metadata_ratio = intarg;
+ btrfs_info(info, "metadata ratio %u",
+ info->metadata_ratio);
break;
case Opt_discard:
btrfs_set_and_info(info, DISCARD,
@@ -762,17 +792,11 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
break;
case Opt_check_integrity_print_mask:
ret = match_int(&args[0], &intarg);
- if (ret) {
+ if (ret)
goto out;
- } else if (intarg >= 0) {
- info->check_integrity_print_mask = intarg;
- btrfs_info(info,
- "check_integrity_print_mask 0x%x",
- info->check_integrity_print_mask);
- } else {
- ret = -EINVAL;
- goto out;
- }
+ info->check_integrity_print_mask = intarg;
+ btrfs_info(info, "check_integrity_print_mask 0x%x",
+ info->check_integrity_print_mask);
break;
#else
case Opt_check_integrity_including_extent_data:
@@ -798,24 +822,18 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
case Opt_commit_interval:
intarg = 0;
ret = match_int(&args[0], &intarg);
- if (ret < 0) {
- btrfs_err(info, "invalid commit interval");
- ret = -EINVAL;
+ if (ret)
goto out;
- }
- if (intarg > 0) {
- if (intarg > 300) {
- btrfs_warn(info,
- "excessive commit interval %d",
- intarg);
- }
- info->commit_interval = intarg;
- } else {
+ if (intarg == 0) {
btrfs_info(info,
- "using default commit interval %ds",
+ "using default commit interval %us",
BTRFS_DEFAULT_COMMIT_INTERVAL);
- info->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
+ intarg = BTRFS_DEFAULT_COMMIT_INTERVAL;
+ } else if (intarg > 300) {
+ btrfs_warn(info, "excessive commit interval %d",
+ intarg);
}
+ info->commit_interval = intarg;
break;
#ifdef CONFIG_BTRFS_DEBUG
case Opt_fragment_all:
@@ -932,8 +950,8 @@ static int btrfs_parse_subvol_options(const char *options, fmode_t flags,
{
substring_t args[MAX_OPT_ARGS];
char *opts, *orig, *p;
- char *num = NULL;
int error = 0;
+ u64 subvolid;
if (!options)
return 0;
@@ -963,18 +981,15 @@ static int btrfs_parse_subvol_options(const char *options, fmode_t flags,
}
break;
case Opt_subvolid:
- num = match_strdup(&args[0]);
- if (num) {
- *subvol_objectid = memparse(num, NULL);
- kfree(num);
- /* we want the original fs_tree */
- if (!*subvol_objectid)
- *subvol_objectid =
- BTRFS_FS_TREE_OBJECTID;
- } else {
- error = -EINVAL;
+ error = match_u64(&args[0], &subvolid);
+ if (error)
goto out;
- }
+
+ /* we want the original fs_tree */
+ if (subvolid == 0)
+ subvolid = BTRFS_FS_TREE_OBJECTID;
+
+ *subvol_objectid = subvolid;
break;
case Opt_subvolrootid:
pr_warn("BTRFS: 'subvolrootid' mount option is deprecated and has no effect\n");
@@ -1284,7 +1299,7 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
seq_printf(seq, ",max_inline=%llu", info->max_inline);
if (info->thread_pool_size != min_t(unsigned long,
num_online_cpus() + 2, 8))
- seq_printf(seq, ",thread_pool=%d", info->thread_pool_size);
+ seq_printf(seq, ",thread_pool=%u", info->thread_pool_size);
if (btrfs_test_opt(info, COMPRESS)) {
compress_type = btrfs_compress_type2str(info->compress_type);
if (btrfs_test_opt(info, FORCE_COMPRESS))
@@ -1340,12 +1355,11 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
info->check_integrity_print_mask);
#endif
if (info->metadata_ratio)
- seq_printf(seq, ",metadata_ratio=%d",
- info->metadata_ratio);
+ seq_printf(seq, ",metadata_ratio=%u", info->metadata_ratio);
if (btrfs_test_opt(info, PANIC_ON_FATAL_ERROR))
seq_puts(seq, ",fatal_errors=panic");
if (info->commit_interval != BTRFS_DEFAULT_COMMIT_INTERVAL)
- seq_printf(seq, ",commit=%d", info->commit_interval);
+ seq_printf(seq, ",commit=%u", info->commit_interval);
#ifdef CONFIG_BTRFS_DEBUG
if (btrfs_test_opt(info, FRAGMENT_DATA))
seq_puts(seq, ",fragment=data");
@@ -1690,7 +1704,7 @@ out:
}
static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info,
- int new_pool_size, int old_pool_size)
+ u32 new_pool_size, u32 old_pool_size)
{
if (new_pool_size == old_pool_size)
return;
@@ -1758,8 +1772,8 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
unsigned long old_opts = fs_info->mount_opt;
unsigned long old_compress_type = fs_info->compress_type;
u64 old_max_inline = fs_info->max_inline;
- int old_thread_pool_size = fs_info->thread_pool_size;
- unsigned int old_metadata_ratio = fs_info->metadata_ratio;
+ u32 old_thread_pool_size = fs_info->thread_pool_size;
+ u32 old_metadata_ratio = fs_info->metadata_ratio;
int ret;
sync_filesystem(sb);
@@ -2290,11 +2304,18 @@ static int btrfs_show_devname(struct seq_file *m, struct dentry *root)
struct list_head *head;
struct rcu_string *name;
- mutex_lock(&fs_info->fs_devices->device_list_mutex);
+ /*
+ * Lightweight locking of the devices. We should not need
+ * device_list_mutex here as we only read the device data and the list
+ * is protected by RCU. Even if a device is deleted during the list
+ * traversals, we'll get valid data, the freeing callback will wait at
+ * least until until the rcu_read_unlock.
+ */
+ rcu_read_lock();
cur_devices = fs_info->fs_devices;
while (cur_devices) {
head = &cur_devices->devices;
- list_for_each_entry(dev, head, dev_list) {
+ list_for_each_entry_rcu(dev, head, dev_list) {
if (test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state))
continue;
if (!dev->name)
@@ -2306,14 +2327,12 @@ static int btrfs_show_devname(struct seq_file *m, struct dentry *root)
}
if (first_dev) {
- rcu_read_lock();
name = rcu_dereference(first_dev->name);
seq_escape(m, name->str, " \t\n\\");
- rcu_read_unlock();
} else {
WARN_ON(1);
}
- mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+ rcu_read_unlock();
return 0;
}
@@ -2355,7 +2374,7 @@ static int __init btrfs_interface_init(void)
return misc_register(&btrfs_misc);
}
-static void btrfs_interface_exit(void)
+static __cold void btrfs_interface_exit(void)
{
misc_deregister(&btrfs_misc);
}
@@ -2376,22 +2395,18 @@ static void __init btrfs_print_mod_info(void)
", ref-verify=on"
#endif
"\n",
- btrfs_crc32c_impl());
+ crc32c_impl());
}
static int __init init_btrfs_fs(void)
{
int err;
- err = btrfs_hash_init();
- if (err)
- return err;
-
btrfs_props_init();
err = btrfs_init_sysfs();
if (err)
- goto free_hash;
+ return err;
btrfs_init_compress();
@@ -2472,8 +2487,7 @@ free_cachep:
free_compress:
btrfs_exit_compress();
btrfs_exit_sysfs();
-free_hash:
- btrfs_hash_exit();
+
return err;
}
@@ -2493,7 +2507,6 @@ static void __exit exit_btrfs_fs(void)
btrfs_exit_sysfs();
btrfs_cleanup_fs_uuids();
btrfs_exit_compress();
- btrfs_hash_exit();
}
late_initcall(init_btrfs_fs);
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
index a8bafed931f4..ca067471cd46 100644
--- a/fs/btrfs/sysfs.c
+++ b/fs/btrfs/sysfs.c
@@ -272,7 +272,7 @@ static ssize_t raid_bytes_show(struct kobject *kobj,
{
struct btrfs_space_info *sinfo = to_space_info(kobj->parent);
struct btrfs_block_group_cache *block_group;
- int index = to_raid_kobj(kobj)->raid_type;
+ int index = btrfs_bg_flags_to_raid_index(to_raid_kobj(kobj)->flags);
u64 val = 0;
down_read(&sinfo->groups_sem);
@@ -923,7 +923,7 @@ out1:
return ret;
}
-void btrfs_exit_sysfs(void)
+void __cold btrfs_exit_sysfs(void)
{
sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
kset_unregister(btrfs_kset);
diff --git a/fs/btrfs/tests/btrfs-tests.c b/fs/btrfs/tests/btrfs-tests.c
index 9786d8cd0aa6..e74278170806 100644
--- a/fs/btrfs/tests/btrfs-tests.c
+++ b/fs/btrfs/tests/btrfs-tests.c
@@ -278,8 +278,7 @@ int btrfs_run_sanity_tests(void)
}
}
ret = btrfs_test_extent_map();
- if (ret)
- goto out;
+
out:
btrfs_destroy_test_fs();
return ret;
diff --git a/fs/btrfs/tests/extent-map-tests.c b/fs/btrfs/tests/extent-map-tests.c
index 70c993f01670..c23bd00bdd92 100644
--- a/fs/btrfs/tests/extent-map-tests.c
+++ b/fs/btrfs/tests/extent-map-tests.c
@@ -343,7 +343,7 @@ static void test_case_4(struct extent_map_tree *em_tree)
__test_case_4(em_tree, SZ_4K);
}
-int btrfs_test_extent_map()
+int btrfs_test_extent_map(void)
{
struct extent_map_tree *em_tree;
diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c
index 90204b166643..160eb2fba726 100644
--- a/fs/btrfs/tests/qgroup-tests.c
+++ b/fs/btrfs/tests/qgroup-tests.c
@@ -63,7 +63,7 @@ static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr,
btrfs_set_extent_generation(leaf, item, 1);
btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK);
block_info = (struct btrfs_tree_block_info *)(item + 1);
- btrfs_set_tree_block_level(leaf, block_info, 1);
+ btrfs_set_tree_block_level(leaf, block_info, 0);
iref = (struct btrfs_extent_inline_ref *)(block_info + 1);
if (parent > 0) {
btrfs_set_extent_inline_ref_type(leaf, iref,
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 04f07144b45c..5c4cf0f9146b 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -37,22 +37,16 @@
static const unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = {
[TRANS_STATE_RUNNING] = 0U,
- [TRANS_STATE_BLOCKED] = (__TRANS_USERSPACE |
- __TRANS_START),
- [TRANS_STATE_COMMIT_START] = (__TRANS_USERSPACE |
- __TRANS_START |
- __TRANS_ATTACH),
- [TRANS_STATE_COMMIT_DOING] = (__TRANS_USERSPACE |
- __TRANS_START |
+ [TRANS_STATE_BLOCKED] = __TRANS_START,
+ [TRANS_STATE_COMMIT_START] = (__TRANS_START | __TRANS_ATTACH),
+ [TRANS_STATE_COMMIT_DOING] = (__TRANS_START |
__TRANS_ATTACH |
__TRANS_JOIN),
- [TRANS_STATE_UNBLOCKED] = (__TRANS_USERSPACE |
- __TRANS_START |
+ [TRANS_STATE_UNBLOCKED] = (__TRANS_START |
__TRANS_ATTACH |
__TRANS_JOIN |
__TRANS_JOIN_NOLOCK),
- [TRANS_STATE_COMPLETED] = (__TRANS_USERSPACE |
- __TRANS_START |
+ [TRANS_STATE_COMPLETED] = (__TRANS_START |
__TRANS_ATTACH |
__TRANS_JOIN |
__TRANS_JOIN_NOLOCK),
@@ -126,9 +120,9 @@ static void clear_btree_io_tree(struct extent_io_tree *tree)
spin_unlock(&tree->lock);
}
-static noinline void switch_commit_roots(struct btrfs_transaction *trans,
- struct btrfs_fs_info *fs_info)
+static noinline void switch_commit_roots(struct btrfs_transaction *trans)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_root *root, *tmp;
down_write(&fs_info->commit_root_sem);
@@ -319,7 +313,7 @@ static int record_root_in_trans(struct btrfs_trans_handle *trans,
if ((test_bit(BTRFS_ROOT_REF_COWS, &root->state) &&
root->last_trans < trans->transid) || force) {
WARN_ON(root == fs_info->extent_root);
- WARN_ON(root->commit_root != root->node);
+ WARN_ON(!force && root->commit_root != root->node);
/*
* see below for IN_TRANS_SETUP usage rules
@@ -449,11 +443,7 @@ static int may_wait_transaction(struct btrfs_fs_info *fs_info, int type)
if (test_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags))
return 0;
- if (type == TRANS_USERSPACE)
- return 1;
-
- if (type == TRANS_START &&
- !atomic_read(&fs_info->open_ioctl_trans))
+ if (type == TRANS_START)
return 1;
return 0;
@@ -508,8 +498,8 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
*/
if (num_items && root != fs_info->chunk_root) {
qgroup_reserved = num_items * fs_info->nodesize;
- ret = btrfs_qgroup_reserve_meta(root, qgroup_reserved,
- enforce_qgroups);
+ ret = btrfs_qgroup_reserve_meta_pertrans(root, qgroup_reserved,
+ enforce_qgroups);
if (ret)
return ERR_PTR(ret);
@@ -593,7 +583,7 @@ again:
got_it:
btrfs_record_root_in_trans(h, root);
- if (!current->journal_info && type != TRANS_USERSPACE)
+ if (!current->journal_info)
current->journal_info = h;
return h;
@@ -606,7 +596,7 @@ alloc_fail:
btrfs_block_rsv_release(fs_info, &fs_info->trans_block_rsv,
num_bytes);
reserve_fail:
- btrfs_qgroup_free_meta(root, qgroup_reserved);
+ btrfs_qgroup_free_meta_pertrans(root, qgroup_reserved);
return ERR_PTR(ret);
}
@@ -658,14 +648,6 @@ struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv(
return trans;
}
-struct btrfs_trans_handle *btrfs_start_transaction_lflush(
- struct btrfs_root *root,
- unsigned int num_items)
-{
- return start_transaction(root, num_items, TRANS_START,
- BTRFS_RESERVE_FLUSH_LIMIT, true);
-}
-
struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root)
{
return start_transaction(root, 0, TRANS_JOIN, BTRFS_RESERVE_NO_FLUSH,
@@ -678,12 +660,6 @@ struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root
BTRFS_RESERVE_NO_FLUSH, true);
}
-struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root)
-{
- return start_transaction(root, 0, TRANS_USERSPACE,
- BTRFS_RESERVE_NO_FLUSH, true);
-}
-
/*
* btrfs_attach_transaction() - catch the running transaction
*
@@ -789,8 +765,7 @@ out:
void btrfs_throttle(struct btrfs_fs_info *fs_info)
{
- if (!atomic_read(&fs_info->open_ioctl_trans))
- wait_current_trans(fs_info);
+ wait_current_trans(fs_info);
}
static int should_end_transaction(struct btrfs_trans_handle *trans)
@@ -806,7 +781,6 @@ static int should_end_transaction(struct btrfs_trans_handle *trans)
int btrfs_should_end_transaction(struct btrfs_trans_handle *trans)
{
struct btrfs_transaction *cur_trans = trans->transaction;
- struct btrfs_fs_info *fs_info = trans->fs_info;
int updates;
int err;
@@ -818,7 +792,7 @@ int btrfs_should_end_transaction(struct btrfs_trans_handle *trans)
updates = trans->delayed_ref_updates;
trans->delayed_ref_updates = 0;
if (updates) {
- err = btrfs_run_delayed_refs(trans, fs_info, updates * 2);
+ err = btrfs_run_delayed_refs(trans, updates * 2);
if (err) /* Error code will also eval true */
return err;
}
@@ -826,6 +800,27 @@ int btrfs_should_end_transaction(struct btrfs_trans_handle *trans)
return should_end_transaction(trans);
}
+static void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans)
+
+{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
+
+ if (!trans->block_rsv) {
+ ASSERT(!trans->bytes_reserved);
+ return;
+ }
+
+ if (!trans->bytes_reserved)
+ return;
+
+ ASSERT(trans->block_rsv == &fs_info->trans_block_rsv);
+ trace_btrfs_space_reservation(fs_info, "transaction",
+ trans->transid, trans->bytes_reserved, 0);
+ btrfs_block_rsv_release(fs_info, trans->block_rsv,
+ trans->bytes_reserved);
+ trans->bytes_reserved = 0;
+}
+
static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
int throttle)
{
@@ -843,11 +838,11 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
return 0;
}
- btrfs_trans_release_metadata(trans, info);
+ btrfs_trans_release_metadata(trans);
trans->block_rsv = NULL;
if (!list_empty(&trans->new_bgs))
- btrfs_create_pending_block_groups(trans, info);
+ btrfs_create_pending_block_groups(trans);
trans->delayed_ref_updates = 0;
if (!trans->sync) {
@@ -864,16 +859,15 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
must_run_delayed_refs = 2;
}
- btrfs_trans_release_metadata(trans, info);
+ btrfs_trans_release_metadata(trans);
trans->block_rsv = NULL;
if (!list_empty(&trans->new_bgs))
- btrfs_create_pending_block_groups(trans, info);
+ btrfs_create_pending_block_groups(trans);
btrfs_trans_release_chunk_metadata(trans);
- if (lock && !atomic_read(&info->open_ioctl_trans) &&
- should_end_transaction(trans) &&
+ if (lock && should_end_transaction(trans) &&
READ_ONCE(cur_trans->state) == TRANS_STATE_RUNNING) {
spin_lock(&info->trans_lock);
if (cur_trans->state == TRANS_STATE_RUNNING)
@@ -1072,40 +1066,33 @@ int btrfs_wait_tree_log_extents(struct btrfs_root *log_root, int mark)
}
/*
- * when btree blocks are allocated, they have some corresponding bits set for
- * them in one of two extent_io trees. This is used to make sure all of
- * those extents are on disk for transaction or log commit
+ * When btree blocks are allocated the corresponding extents are marked dirty.
+ * This function ensures such extents are persisted on disk for transaction or
+ * log commit.
+ *
+ * @trans: transaction whose dirty pages we'd like to write
*/
-static int btrfs_write_and_wait_marked_extents(struct btrfs_fs_info *fs_info,
- struct extent_io_tree *dirty_pages, int mark)
+static int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans)
{
int ret;
int ret2;
+ struct extent_io_tree *dirty_pages = &trans->transaction->dirty_pages;
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct blk_plug plug;
blk_start_plug(&plug);
- ret = btrfs_write_marked_extents(fs_info, dirty_pages, mark);
+ ret = btrfs_write_marked_extents(fs_info, dirty_pages, EXTENT_DIRTY);
blk_finish_plug(&plug);
ret2 = btrfs_wait_extents(fs_info, dirty_pages);
+ clear_btree_io_tree(&trans->transaction->dirty_pages);
+
if (ret)
return ret;
- if (ret2)
+ else if (ret2)
return ret2;
- return 0;
-}
-
-static int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info)
-{
- int ret;
-
- ret = btrfs_write_and_wait_marked_extents(fs_info,
- &trans->transaction->dirty_pages,
- EXTENT_DIRTY);
- clear_btree_io_tree(&trans->transaction->dirty_pages);
-
- return ret;
+ else
+ return 0;
}
/*
@@ -1155,9 +1142,9 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
* failures will cause the file system to go offline. We still need
* to clean up the delayed refs.
*/
-static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info)
+static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct list_head *dirty_bgs = &trans->transaction->dirty_bgs;
struct list_head *io_bgs = &trans->transaction->io_bgs;
struct list_head *next;
@@ -1173,7 +1160,7 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
if (ret)
return ret;
- ret = btrfs_run_delayed_refs(trans, fs_info, (unsigned long)-1);
+ ret = btrfs_run_delayed_refs(trans, (unsigned long)-1);
if (ret)
return ret;
@@ -1192,7 +1179,7 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
return ret;
/* run_qgroups might have added some more refs */
- ret = btrfs_run_delayed_refs(trans, fs_info, (unsigned long)-1);
+ ret = btrfs_run_delayed_refs(trans, (unsigned long)-1);
if (ret)
return ret;
again:
@@ -1209,7 +1196,7 @@ again:
ret = update_cowonly_root(trans, root);
if (ret)
return ret;
- ret = btrfs_run_delayed_refs(trans, fs_info, (unsigned long)-1);
+ ret = btrfs_run_delayed_refs(trans, (unsigned long)-1);
if (ret)
return ret;
}
@@ -1218,7 +1205,7 @@ again:
ret = btrfs_write_dirty_block_groups(trans, fs_info);
if (ret)
return ret;
- ret = btrfs_run_delayed_refs(trans, fs_info, (unsigned long)-1);
+ ret = btrfs_run_delayed_refs(trans, (unsigned long)-1);
if (ret)
return ret;
}
@@ -1251,9 +1238,9 @@ void btrfs_add_dead_root(struct btrfs_root *root)
/*
* update all the cowonly tree roots on disk
*/
-static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info)
+static noinline int commit_fs_roots(struct btrfs_trans_handle *trans)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_root *gang[8];
int i;
int ret;
@@ -1297,7 +1284,7 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
spin_lock(&fs_info->fs_roots_radix_lock);
if (err)
break;
- btrfs_qgroup_free_meta_all(root);
+ btrfs_qgroup_free_meta_all_pertrans(root);
}
}
spin_unlock(&fs_info->fs_roots_radix_lock);
@@ -1366,15 +1353,23 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans,
return 0;
/*
+ * Ensure dirty @src will be commited. Or, after comming
+ * commit_fs_roots() and switch_commit_roots(), any dirty but not
+ * recorded root will never be updated again, causing an outdated root
+ * item.
+ */
+ record_root_in_trans(trans, src, 1);
+
+ /*
* We are going to commit transaction, see btrfs_commit_transaction()
* comment for reason locking tree_log_mutex
*/
mutex_lock(&fs_info->tree_log_mutex);
- ret = commit_fs_roots(trans, fs_info);
+ ret = commit_fs_roots(trans);
if (ret)
goto out;
- ret = btrfs_qgroup_account_extents(trans, fs_info);
+ ret = btrfs_qgroup_account_extents(trans);
if (ret < 0)
goto out;
@@ -1397,11 +1392,11 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans,
* like chunk and root tree, as they won't affect qgroup.
* And we don't write super to avoid half committed status.
*/
- ret = commit_cowonly_roots(trans, fs_info);
+ ret = commit_cowonly_roots(trans);
if (ret)
goto out;
- switch_commit_roots(trans->transaction, fs_info);
- ret = btrfs_write_and_wait_transaction(trans, fs_info);
+ switch_commit_roots(trans->transaction);
+ ret = btrfs_write_and_wait_transaction(trans);
if (ret)
btrfs_handle_fs_error(fs_info, ret,
"Error while writing out transaction for qgroup");
@@ -1430,9 +1425,10 @@ out:
* the creation of the pending snapshots, just return 0.
*/
static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info,
struct btrfs_pending_snapshot *pending)
{
+
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_key key;
struct btrfs_root_item *new_root_item;
struct btrfs_root *tree_root = fs_info->tree_root;
@@ -1524,7 +1520,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
* otherwise we corrupt the FS during
* snapshot
*/
- ret = btrfs_run_delayed_items(trans, fs_info);
+ ret = btrfs_run_delayed_items(trans);
if (ret) { /* Transaction aborted */
btrfs_abort_transaction(trans, ret);
goto fail;
@@ -1620,7 +1616,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
goto fail;
}
- ret = btrfs_run_delayed_refs(trans, fs_info, (unsigned long)-1);
+ ret = btrfs_run_delayed_refs(trans, (unsigned long)-1);
if (ret) {
btrfs_abort_transaction(trans, ret);
goto fail;
@@ -1674,7 +1670,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
}
}
- ret = btrfs_run_delayed_refs(trans, fs_info, (unsigned long)-1);
+ ret = btrfs_run_delayed_refs(trans, (unsigned long)-1);
if (ret) {
btrfs_abort_transaction(trans, ret);
goto fail;
@@ -1699,8 +1695,7 @@ no_free_objectid:
/*
* create all the snapshots we've scheduled for creation
*/
-static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans,
- struct btrfs_fs_info *fs_info)
+static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans)
{
struct btrfs_pending_snapshot *pending, *next;
struct list_head *head = &trans->transaction->pending_snapshots;
@@ -1708,7 +1703,7 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans,
list_for_each_entry_safe(pending, next, head, list) {
list_del(&pending->list);
- ret = create_pending_snapshot(trans, fs_info, pending);
+ ret = create_pending_snapshot(trans, pending);
if (ret)
break;
}
@@ -1861,10 +1856,9 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
}
-static void cleanup_transaction(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, int err)
+static void cleanup_transaction(struct btrfs_trans_handle *trans, int err)
{
- struct btrfs_fs_info *fs_info = root->fs_info;
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_transaction *cur_trans = trans->transaction;
DEFINE_WAIT(wait);
@@ -1904,7 +1898,7 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans,
btrfs_put_transaction(cur_trans);
btrfs_put_transaction(cur_trans);
- trace_btrfs_transaction_commit(root);
+ trace_btrfs_transaction_commit(trans->root);
if (current->journal_info == trans)
current->journal_info = NULL;
@@ -1959,13 +1953,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
/* make a pass through all the delayed refs we have so far
* any runnings procs may add more while we are here
*/
- ret = btrfs_run_delayed_refs(trans, fs_info, 0);
+ ret = btrfs_run_delayed_refs(trans, 0);
if (ret) {
btrfs_end_transaction(trans);
return ret;
}
- btrfs_trans_release_metadata(trans, fs_info);
+ btrfs_trans_release_metadata(trans);
trans->block_rsv = NULL;
cur_trans = trans->transaction;
@@ -1978,9 +1972,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
smp_wmb();
if (!list_empty(&trans->new_bgs))
- btrfs_create_pending_block_groups(trans, fs_info);
+ btrfs_create_pending_block_groups(trans);
- ret = btrfs_run_delayed_refs(trans, fs_info, 0);
+ ret = btrfs_run_delayed_refs(trans, 0);
if (ret) {
btrfs_end_transaction(trans);
return ret;
@@ -2008,12 +2002,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
run_it = 1;
mutex_unlock(&fs_info->ro_block_group_mutex);
- if (run_it)
- ret = btrfs_start_dirty_block_groups(trans, fs_info);
- }
- if (ret) {
- btrfs_end_transaction(trans);
- return ret;
+ if (run_it) {
+ ret = btrfs_start_dirty_block_groups(trans);
+ if (ret) {
+ btrfs_end_transaction(trans);
+ return ret;
+ }
+ }
}
spin_lock(&fs_info->trans_lock);
@@ -2061,7 +2056,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
if (ret)
goto cleanup_transaction;
- ret = btrfs_run_delayed_items(trans, fs_info);
+ ret = btrfs_run_delayed_items(trans);
if (ret)
goto cleanup_transaction;
@@ -2069,7 +2064,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
extwriter_counter_read(cur_trans) == 0);
/* some pending stuffs might be added after the previous flush. */
- ret = btrfs_run_delayed_items(trans, fs_info);
+ ret = btrfs_run_delayed_items(trans);
if (ret)
goto cleanup_transaction;
@@ -2106,7 +2101,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
* deal with them in create_pending_snapshot(), which is the
* core function of the snapshot creation.
*/
- ret = create_pending_snapshots(trans, fs_info);
+ ret = create_pending_snapshots(trans);
if (ret) {
mutex_unlock(&fs_info->reloc_mutex);
goto scrub_continue;
@@ -2122,13 +2117,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
* because all the tree which are snapshoted will be forced to COW
* the nodes and leaves.
*/
- ret = btrfs_run_delayed_items(trans, fs_info);
+ ret = btrfs_run_delayed_items(trans);
if (ret) {
mutex_unlock(&fs_info->reloc_mutex);
goto scrub_continue;
}
- ret = btrfs_run_delayed_refs(trans, fs_info, (unsigned long)-1);
+ ret = btrfs_run_delayed_refs(trans, (unsigned long)-1);
if (ret) {
mutex_unlock(&fs_info->reloc_mutex);
goto scrub_continue;
@@ -2157,7 +2152,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
*/
mutex_lock(&fs_info->tree_log_mutex);
- ret = commit_fs_roots(trans, fs_info);
+ ret = commit_fs_roots(trans);
if (ret) {
mutex_unlock(&fs_info->tree_log_mutex);
mutex_unlock(&fs_info->reloc_mutex);
@@ -2179,7 +2174,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
* commit_fs_roots() can call btrfs_save_ino_cache(), which generates
* new delayed refs. Must handle them or qgroup can be wrong.
*/
- ret = btrfs_run_delayed_refs(trans, fs_info, (unsigned long)-1);
+ ret = btrfs_run_delayed_refs(trans, (unsigned long)-1);
if (ret) {
mutex_unlock(&fs_info->tree_log_mutex);
mutex_unlock(&fs_info->reloc_mutex);
@@ -2190,14 +2185,14 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
* Since fs roots are all committed, we can get a quite accurate
* new_roots. So let's do quota accounting.
*/
- ret = btrfs_qgroup_account_extents(trans, fs_info);
+ ret = btrfs_qgroup_account_extents(trans);
if (ret < 0) {
mutex_unlock(&fs_info->tree_log_mutex);
mutex_unlock(&fs_info->reloc_mutex);
goto scrub_continue;
}
- ret = commit_cowonly_roots(trans, fs_info);
+ ret = commit_cowonly_roots(trans);
if (ret) {
mutex_unlock(&fs_info->tree_log_mutex);
mutex_unlock(&fs_info->reloc_mutex);
@@ -2229,7 +2224,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
list_add_tail(&fs_info->chunk_root->dirty_list,
&cur_trans->switch_commits);
- switch_commit_roots(cur_trans, fs_info);
+ switch_commit_roots(cur_trans);
ASSERT(list_empty(&cur_trans->dirty_bgs));
ASSERT(list_empty(&cur_trans->io_bgs));
@@ -2241,7 +2236,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
sizeof(*fs_info->super_copy));
btrfs_update_commit_device_size(fs_info);
- btrfs_update_commit_device_bytes_used(fs_info, cur_trans);
+ btrfs_update_commit_device_bytes_used(cur_trans);
clear_bit(BTRFS_FS_LOG1_ERR, &fs_info->flags);
clear_bit(BTRFS_FS_LOG2_ERR, &fs_info->flags);
@@ -2256,7 +2251,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
wake_up(&fs_info->transaction_wait);
- ret = btrfs_write_and_wait_transaction(trans, fs_info);
+ ret = btrfs_write_and_wait_transaction(trans);
if (ret) {
btrfs_handle_fs_error(fs_info, ret,
"Error while writing out transaction");
@@ -2273,7 +2268,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
if (ret)
goto scrub_continue;
- btrfs_finish_extent_commit(trans, fs_info);
+ btrfs_finish_extent_commit(trans);
if (test_bit(BTRFS_TRANS_HAVE_FREE_BGS, &cur_trans->flags))
btrfs_clear_space_info_full(fs_info);
@@ -2319,13 +2314,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
scrub_continue:
btrfs_scrub_continue(fs_info);
cleanup_transaction:
- btrfs_trans_release_metadata(trans, fs_info);
+ btrfs_trans_release_metadata(trans);
btrfs_trans_release_chunk_metadata(trans);
trans->block_rsv = NULL;
btrfs_warn(fs_info, "Skipping commit of aborted transaction.");
if (current->journal_info == trans)
current->journal_info = NULL;
- cleanup_transaction(trans, trans->root, ret);
+ cleanup_transaction(trans, ret);
return ret;
}
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index 6beee072b1bd..b6c94ce33503 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -69,6 +69,22 @@ struct btrfs_transaction {
struct list_head pending_chunks;
struct list_head switch_commits;
struct list_head dirty_bgs;
+
+ /*
+ * There is no explicit lock which protects io_bgs, rather its
+ * consistency is implied by the fact that all the sites which modify
+ * it do so under some form of transaction critical section, namely:
+ *
+ * - btrfs_start_dirty_block_groups - This function can only ever be
+ * run by one of the transaction committers. Refer to
+ * BTRFS_TRANS_DIRTY_BG_RUN usage in btrfs_commit_transaction
+ *
+ * - btrfs_write_dirty_blockgroups - this is called by
+ * commit_cowonly_roots from transaction critical section
+ * (TRANS_STATE_COMMIT_DOING)
+ *
+ * - btrfs_cleanup_dirty_bgs - called on transaction abort
+ */
struct list_head io_bgs;
struct list_head dropped_roots;
@@ -89,21 +105,18 @@ struct btrfs_transaction {
#define __TRANS_FREEZABLE (1U << 0)
-#define __TRANS_USERSPACE (1U << 8)
#define __TRANS_START (1U << 9)
#define __TRANS_ATTACH (1U << 10)
#define __TRANS_JOIN (1U << 11)
#define __TRANS_JOIN_NOLOCK (1U << 12)
#define __TRANS_DUMMY (1U << 13)
-#define TRANS_USERSPACE (__TRANS_USERSPACE | __TRANS_FREEZABLE)
#define TRANS_START (__TRANS_START | __TRANS_FREEZABLE)
#define TRANS_ATTACH (__TRANS_ATTACH)
#define TRANS_JOIN (__TRANS_JOIN | __TRANS_FREEZABLE)
#define TRANS_JOIN_NOLOCK (__TRANS_JOIN_NOLOCK)
-#define TRANS_EXTWRITERS (__TRANS_USERSPACE | __TRANS_START | \
- __TRANS_ATTACH)
+#define TRANS_EXTWRITERS (__TRANS_START | __TRANS_ATTACH)
#define BTRFS_SEND_TRANS_STUB ((void *)1)
@@ -186,15 +199,11 @@ struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv(
struct btrfs_root *root,
unsigned int num_items,
int min_factor);
-struct btrfs_trans_handle *btrfs_start_transaction_lflush(
- struct btrfs_root *root,
- unsigned int num_items);
struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root);
struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root);
struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root);
struct btrfs_trans_handle *btrfs_attach_transaction_barrier(
struct btrfs_root *root);
-struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root);
int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid);
void btrfs_add_dead_root(struct btrfs_root *root);
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index c3c8d48f6618..8871286c1a91 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -30,7 +30,6 @@
#include "tree-checker.h"
#include "disk-io.h"
#include "compression.h"
-#include "hash.h"
/*
* Error message should follow the following format:
@@ -53,7 +52,8 @@
* Allows callers to customize the output.
*/
__printf(4, 5)
-static void generic_err(const struct btrfs_root *root,
+__cold
+static void generic_err(const struct btrfs_fs_info *fs_info,
const struct extent_buffer *eb, int slot,
const char *fmt, ...)
{
@@ -65,10 +65,10 @@ static void generic_err(const struct btrfs_root *root,
vaf.fmt = fmt;
vaf.va = &args;
- btrfs_crit(root->fs_info,
+ btrfs_crit(fs_info,
"corrupt %s: root=%llu block=%llu slot=%d, %pV",
btrfs_header_level(eb) == 0 ? "leaf" : "node",
- root->objectid, btrfs_header_bytenr(eb), slot, &vaf);
+ btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, &vaf);
va_end(args);
}
@@ -77,7 +77,8 @@ static void generic_err(const struct btrfs_root *root,
* offset has its own meaning.
*/
__printf(4, 5)
-static void file_extent_err(const struct btrfs_root *root,
+__cold
+static void file_extent_err(const struct btrfs_fs_info *fs_info,
const struct extent_buffer *eb, int slot,
const char *fmt, ...)
{
@@ -91,10 +92,11 @@ static void file_extent_err(const struct btrfs_root *root,
vaf.fmt = fmt;
vaf.va = &args;
- btrfs_crit(root->fs_info,
+ btrfs_crit(fs_info,
"corrupt %s: root=%llu block=%llu slot=%d ino=%llu file_offset=%llu, %pV",
- btrfs_header_level(eb) == 0 ? "leaf" : "node", root->objectid,
- btrfs_header_bytenr(eb), slot, key.objectid, key.offset, &vaf);
+ btrfs_header_level(eb) == 0 ? "leaf" : "node",
+ btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
+ key.objectid, key.offset, &vaf);
va_end(args);
}
@@ -102,26 +104,26 @@ static void file_extent_err(const struct btrfs_root *root,
* Return 0 if the btrfs_file_extent_##name is aligned to @alignment
* Else return 1
*/
-#define CHECK_FE_ALIGNED(root, leaf, slot, fi, name, alignment) \
+#define CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, name, alignment) \
({ \
if (!IS_ALIGNED(btrfs_file_extent_##name((leaf), (fi)), (alignment))) \
- file_extent_err((root), (leaf), (slot), \
+ file_extent_err((fs_info), (leaf), (slot), \
"invalid %s for file extent, have %llu, should be aligned to %u", \
(#name), btrfs_file_extent_##name((leaf), (fi)), \
(alignment)); \
(!IS_ALIGNED(btrfs_file_extent_##name((leaf), (fi)), (alignment))); \
})
-static int check_extent_data_item(struct btrfs_root *root,
+static int check_extent_data_item(struct btrfs_fs_info *fs_info,
struct extent_buffer *leaf,
struct btrfs_key *key, int slot)
{
struct btrfs_file_extent_item *fi;
- u32 sectorsize = root->fs_info->sectorsize;
+ u32 sectorsize = fs_info->sectorsize;
u32 item_size = btrfs_item_size_nr(leaf, slot);
if (!IS_ALIGNED(key->offset, sectorsize)) {
- file_extent_err(root, leaf, slot,
+ file_extent_err(fs_info, leaf, slot,
"unaligned file_offset for file extent, have %llu should be aligned to %u",
key->offset, sectorsize);
return -EUCLEAN;
@@ -130,7 +132,7 @@ static int check_extent_data_item(struct btrfs_root *root,
fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) {
- file_extent_err(root, leaf, slot,
+ file_extent_err(fs_info, leaf, slot,
"invalid type for file extent, have %u expect range [0, %u]",
btrfs_file_extent_type(leaf, fi),
BTRFS_FILE_EXTENT_TYPES);
@@ -142,14 +144,14 @@ static int check_extent_data_item(struct btrfs_root *root,
* and must be caught in open_ctree().
*/
if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) {
- file_extent_err(root, leaf, slot,
+ file_extent_err(fs_info, leaf, slot,
"invalid compression for file extent, have %u expect range [0, %u]",
btrfs_file_extent_compression(leaf, fi),
BTRFS_COMPRESS_TYPES);
return -EUCLEAN;
}
if (btrfs_file_extent_encryption(leaf, fi)) {
- file_extent_err(root, leaf, slot,
+ file_extent_err(fs_info, leaf, slot,
"invalid encryption for file extent, have %u expect 0",
btrfs_file_extent_encryption(leaf, fi));
return -EUCLEAN;
@@ -157,7 +159,7 @@ static int check_extent_data_item(struct btrfs_root *root,
if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
/* Inline extent must have 0 as key offset */
if (key->offset) {
- file_extent_err(root, leaf, slot,
+ file_extent_err(fs_info, leaf, slot,
"invalid file_offset for inline file extent, have %llu expect 0",
key->offset);
return -EUCLEAN;
@@ -171,7 +173,7 @@ static int check_extent_data_item(struct btrfs_root *root,
/* Uncompressed inline extent size must match item size */
if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START +
btrfs_file_extent_ram_bytes(leaf, fi)) {
- file_extent_err(root, leaf, slot,
+ file_extent_err(fs_info, leaf, slot,
"invalid ram_bytes for uncompressed inline extent, have %u expect %llu",
item_size, BTRFS_FILE_EXTENT_INLINE_DATA_START +
btrfs_file_extent_ram_bytes(leaf, fi));
@@ -182,40 +184,41 @@ static int check_extent_data_item(struct btrfs_root *root,
/* Regular or preallocated extent has fixed item size */
if (item_size != sizeof(*fi)) {
- file_extent_err(root, leaf, slot,
+ file_extent_err(fs_info, leaf, slot,
"invalid item size for reg/prealloc file extent, have %u expect %zu",
item_size, sizeof(*fi));
return -EUCLEAN;
}
- if (CHECK_FE_ALIGNED(root, leaf, slot, fi, ram_bytes, sectorsize) ||
- CHECK_FE_ALIGNED(root, leaf, slot, fi, disk_bytenr, sectorsize) ||
- CHECK_FE_ALIGNED(root, leaf, slot, fi, disk_num_bytes, sectorsize) ||
- CHECK_FE_ALIGNED(root, leaf, slot, fi, offset, sectorsize) ||
- CHECK_FE_ALIGNED(root, leaf, slot, fi, num_bytes, sectorsize))
+ if (CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, ram_bytes, sectorsize) ||
+ CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, disk_bytenr, sectorsize) ||
+ CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, disk_num_bytes, sectorsize) ||
+ CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, offset, sectorsize) ||
+ CHECK_FE_ALIGNED(fs_info, leaf, slot, fi, num_bytes, sectorsize))
return -EUCLEAN;
return 0;
}
-static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf,
- struct btrfs_key *key, int slot)
+static int check_csum_item(struct btrfs_fs_info *fs_info,
+ struct extent_buffer *leaf, struct btrfs_key *key,
+ int slot)
{
- u32 sectorsize = root->fs_info->sectorsize;
- u32 csumsize = btrfs_super_csum_size(root->fs_info->super_copy);
+ u32 sectorsize = fs_info->sectorsize;
+ u32 csumsize = btrfs_super_csum_size(fs_info->super_copy);
if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) {
- generic_err(root, leaf, slot,
+ generic_err(fs_info, leaf, slot,
"invalid key objectid for csum item, have %llu expect %llu",
key->objectid, BTRFS_EXTENT_CSUM_OBJECTID);
return -EUCLEAN;
}
if (!IS_ALIGNED(key->offset, sectorsize)) {
- generic_err(root, leaf, slot,
+ generic_err(fs_info, leaf, slot,
"unaligned key offset for csum item, have %llu should be aligned to %u",
key->offset, sectorsize);
return -EUCLEAN;
}
if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) {
- generic_err(root, leaf, slot,
+ generic_err(fs_info, leaf, slot,
"unaligned item size for csum item, have %u should be aligned to %u",
btrfs_item_size_nr(leaf, slot), csumsize);
return -EUCLEAN;
@@ -228,7 +231,8 @@ static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf,
* which represents inode number
*/
__printf(4, 5)
-static void dir_item_err(const struct btrfs_root *root,
+__cold
+static void dir_item_err(const struct btrfs_fs_info *fs_info,
const struct extent_buffer *eb, int slot,
const char *fmt, ...)
{
@@ -242,14 +246,15 @@ static void dir_item_err(const struct btrfs_root *root,
vaf.fmt = fmt;
vaf.va = &args;
- btrfs_crit(root->fs_info,
+ btrfs_crit(fs_info,
"corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
- btrfs_header_level(eb) == 0 ? "leaf" : "node", root->objectid,
- btrfs_header_bytenr(eb), slot, key.objectid, &vaf);
+ btrfs_header_level(eb) == 0 ? "leaf" : "node",
+ btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
+ key.objectid, &vaf);
va_end(args);
}
-static int check_dir_item(struct btrfs_root *root,
+static int check_dir_item(struct btrfs_fs_info *fs_info,
struct extent_buffer *leaf,
struct btrfs_key *key, int slot)
{
@@ -268,7 +273,7 @@ static int check_dir_item(struct btrfs_root *root,
/* header itself should not cross item boundary */
if (cur + sizeof(*di) > item_size) {
- dir_item_err(root, leaf, slot,
+ dir_item_err(fs_info, leaf, slot,
"dir item header crosses item boundary, have %zu boundary %u",
cur + sizeof(*di), item_size);
return -EUCLEAN;
@@ -277,7 +282,7 @@ static int check_dir_item(struct btrfs_root *root,
/* dir type check */
dir_type = btrfs_dir_type(leaf, di);
if (dir_type >= BTRFS_FT_MAX) {
- dir_item_err(root, leaf, slot,
+ dir_item_err(fs_info, leaf, slot,
"invalid dir item type, have %u expect [0, %u)",
dir_type, BTRFS_FT_MAX);
return -EUCLEAN;
@@ -285,14 +290,14 @@ static int check_dir_item(struct btrfs_root *root,
if (key->type == BTRFS_XATTR_ITEM_KEY &&
dir_type != BTRFS_FT_XATTR) {
- dir_item_err(root, leaf, slot,
+ dir_item_err(fs_info, leaf, slot,
"invalid dir item type for XATTR key, have %u expect %u",
dir_type, BTRFS_FT_XATTR);
return -EUCLEAN;
}
if (dir_type == BTRFS_FT_XATTR &&
key->type != BTRFS_XATTR_ITEM_KEY) {
- dir_item_err(root, leaf, slot,
+ dir_item_err(fs_info, leaf, slot,
"xattr dir type found for non-XATTR key");
return -EUCLEAN;
}
@@ -305,21 +310,21 @@ static int check_dir_item(struct btrfs_root *root,
name_len = btrfs_dir_name_len(leaf, di);
data_len = btrfs_dir_data_len(leaf, di);
if (name_len > max_name_len) {
- dir_item_err(root, leaf, slot,
+ dir_item_err(fs_info, leaf, slot,
"dir item name len too long, have %u max %u",
name_len, max_name_len);
return -EUCLEAN;
}
- if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root->fs_info)) {
- dir_item_err(root, leaf, slot,
+ if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(fs_info)) {
+ dir_item_err(fs_info, leaf, slot,
"dir item name and data len too long, have %u max %u",
name_len + data_len,
- BTRFS_MAX_XATTR_SIZE(root->fs_info));
+ BTRFS_MAX_XATTR_SIZE(fs_info));
return -EUCLEAN;
}
if (data_len && dir_type != BTRFS_FT_XATTR) {
- dir_item_err(root, leaf, slot,
+ dir_item_err(fs_info, leaf, slot,
"dir item with invalid data len, have %u expect 0",
data_len);
return -EUCLEAN;
@@ -329,7 +334,7 @@ static int check_dir_item(struct btrfs_root *root,
/* header and name/data should not cross item boundary */
if (cur + total_size > item_size) {
- dir_item_err(root, leaf, slot,
+ dir_item_err(fs_info, leaf, slot,
"dir item data crosses item boundary, have %u boundary %u",
cur + total_size, item_size);
return -EUCLEAN;
@@ -347,7 +352,7 @@ static int check_dir_item(struct btrfs_root *root,
(unsigned long)(di + 1), name_len);
name_hash = btrfs_name_hash(namebuf, name_len);
if (key->offset != name_hash) {
- dir_item_err(root, leaf, slot,
+ dir_item_err(fs_info, leaf, slot,
"name hash mismatch with key, have 0x%016x expect 0x%016llx",
name_hash, key->offset);
return -EUCLEAN;
@@ -362,7 +367,7 @@ static int check_dir_item(struct btrfs_root *root,
/*
* Common point to switch the item-specific validation.
*/
-static int check_leaf_item(struct btrfs_root *root,
+static int check_leaf_item(struct btrfs_fs_info *fs_info,
struct extent_buffer *leaf,
struct btrfs_key *key, int slot)
{
@@ -370,24 +375,23 @@ static int check_leaf_item(struct btrfs_root *root,
switch (key->type) {
case BTRFS_EXTENT_DATA_KEY:
- ret = check_extent_data_item(root, leaf, key, slot);
+ ret = check_extent_data_item(fs_info, leaf, key, slot);
break;
case BTRFS_EXTENT_CSUM_KEY:
- ret = check_csum_item(root, leaf, key, slot);
+ ret = check_csum_item(fs_info, leaf, key, slot);
break;
case BTRFS_DIR_ITEM_KEY:
case BTRFS_DIR_INDEX_KEY:
case BTRFS_XATTR_ITEM_KEY:
- ret = check_dir_item(root, leaf, key, slot);
+ ret = check_dir_item(fs_info, leaf, key, slot);
break;
}
return ret;
}
-static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
+static int check_leaf(struct btrfs_fs_info *fs_info, struct extent_buffer *leaf,
bool check_item_data)
{
- struct btrfs_fs_info *fs_info = root->fs_info;
/* No valid key type is 0, so all key should be larger than this key */
struct btrfs_key prev_key = {0, 0, 0};
struct btrfs_key key;
@@ -420,7 +424,7 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
eb = btrfs_root_node(check_root);
/* if leaf is the root, then it's fine */
if (leaf != eb) {
- generic_err(check_root, leaf, 0,
+ generic_err(fs_info, leaf, 0,
"invalid nritems, have %u should not be 0 for non-root leaf",
nritems);
free_extent_buffer(eb);
@@ -453,7 +457,7 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
/* Make sure the keys are in the right order */
if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) {
- generic_err(root, leaf, slot,
+ generic_err(fs_info, leaf, slot,
"bad key order, prev (%llu %u %llu) current (%llu %u %llu)",
prev_key.objectid, prev_key.type,
prev_key.offset, key.objectid, key.type,
@@ -472,7 +476,7 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
item_end_expected = btrfs_item_offset_nr(leaf,
slot - 1);
if (btrfs_item_end_nr(leaf, slot) != item_end_expected) {
- generic_err(root, leaf, slot,
+ generic_err(fs_info, leaf, slot,
"unexpected item end, have %u expect %u",
btrfs_item_end_nr(leaf, slot),
item_end_expected);
@@ -486,7 +490,7 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
*/
if (btrfs_item_end_nr(leaf, slot) >
BTRFS_LEAF_DATA_SIZE(fs_info)) {
- generic_err(root, leaf, slot,
+ generic_err(fs_info, leaf, slot,
"slot end outside of leaf, have %u expect range [0, %u]",
btrfs_item_end_nr(leaf, slot),
BTRFS_LEAF_DATA_SIZE(fs_info));
@@ -496,7 +500,7 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
/* Also check if the item pointer overlaps with btrfs item. */
if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) >
btrfs_item_ptr_offset(leaf, slot)) {
- generic_err(root, leaf, slot,
+ generic_err(fs_info, leaf, slot,
"slot overlaps with its data, item end %lu data start %lu",
btrfs_item_nr_offset(slot) +
sizeof(struct btrfs_item),
@@ -509,7 +513,7 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
* Check if the item size and content meet other
* criteria
*/
- ret = check_leaf_item(root, leaf, &key, slot);
+ ret = check_leaf_item(fs_info, leaf, &key, slot);
if (ret < 0)
return ret;
}
@@ -522,18 +526,19 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
return 0;
}
-int btrfs_check_leaf_full(struct btrfs_root *root, struct extent_buffer *leaf)
+int btrfs_check_leaf_full(struct btrfs_fs_info *fs_info,
+ struct extent_buffer *leaf)
{
- return check_leaf(root, leaf, true);
+ return check_leaf(fs_info, leaf, true);
}
-int btrfs_check_leaf_relaxed(struct btrfs_root *root,
+int btrfs_check_leaf_relaxed(struct btrfs_fs_info *fs_info,
struct extent_buffer *leaf)
{
- return check_leaf(root, leaf, false);
+ return check_leaf(fs_info, leaf, false);
}
-int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
+int btrfs_check_node(struct btrfs_fs_info *fs_info, struct extent_buffer *node)
{
unsigned long nr = btrfs_header_nritems(node);
struct btrfs_key key, next_key;
@@ -541,12 +546,12 @@ int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
u64 bytenr;
int ret = 0;
- if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root->fs_info)) {
- btrfs_crit(root->fs_info,
+ if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(fs_info)) {
+ btrfs_crit(fs_info,
"corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%u]",
- root->objectid, node->start,
+ btrfs_header_owner(node), node->start,
nr == 0 ? "small" : "large", nr,
- BTRFS_NODEPTRS_PER_BLOCK(root->fs_info));
+ BTRFS_NODEPTRS_PER_BLOCK(fs_info));
return -EUCLEAN;
}
@@ -556,21 +561,21 @@ int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
btrfs_node_key_to_cpu(node, &next_key, slot + 1);
if (!bytenr) {
- generic_err(root, node, slot,
+ generic_err(fs_info, node, slot,
"invalid NULL node pointer");
ret = -EUCLEAN;
goto out;
}
- if (!IS_ALIGNED(bytenr, root->fs_info->sectorsize)) {
- generic_err(root, node, slot,
+ if (!IS_ALIGNED(bytenr, fs_info->sectorsize)) {
+ generic_err(fs_info, node, slot,
"unaligned pointer, have %llu should be aligned to %u",
- bytenr, root->fs_info->sectorsize);
+ bytenr, fs_info->sectorsize);
ret = -EUCLEAN;
goto out;
}
if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
- generic_err(root, node, slot,
+ generic_err(fs_info, node, slot,
"bad key order, current (%llu %u %llu) next (%llu %u %llu)",
key.objectid, key.type, key.offset,
next_key.objectid, next_key.type,
diff --git a/fs/btrfs/tree-checker.h b/fs/btrfs/tree-checker.h
index 3d53e8d6fda0..aba542755710 100644
--- a/fs/btrfs/tree-checker.h
+++ b/fs/btrfs/tree-checker.h
@@ -25,14 +25,15 @@
* Will check not only the item pointers, but also every possible member
* in item data.
*/
-int btrfs_check_leaf_full(struct btrfs_root *root, struct extent_buffer *leaf);
+int btrfs_check_leaf_full(struct btrfs_fs_info *fs_info,
+ struct extent_buffer *leaf);
/*
* Less strict leaf checker.
* Will only check item pointers, not reading item data.
*/
-int btrfs_check_leaf_relaxed(struct btrfs_root *root,
+int btrfs_check_leaf_relaxed(struct btrfs_fs_info *fs_info,
struct extent_buffer *leaf);
-int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node);
+int btrfs_check_node(struct btrfs_fs_info *fs_info, struct extent_buffer *node);
#endif
diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c
index cb65089127cc..c09dbe4bd6e7 100644
--- a/fs/btrfs/tree-defrag.c
+++ b/fs/btrfs/tree-defrag.c
@@ -39,7 +39,6 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
int level;
int next_key_ret = 0;
u64 last_ret = 0;
- u64 min_trans = 0;
if (root->fs_info->extent_root == root) {
/*
@@ -81,7 +80,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
path->keep_locks = 1;
- ret = btrfs_search_forward(root, &key, path, min_trans);
+ ret = btrfs_search_forward(root, &key, path, BTRFS_OLDEST_GENERATION);
if (ret < 0)
goto out;
if (ret > 0) {
@@ -130,7 +129,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
*/
path->slots[1] = btrfs_header_nritems(path->nodes[1]);
next_key_ret = btrfs_find_next_key(root, path, &key, 1,
- min_trans);
+ BTRFS_OLDEST_GENERATION);
if (next_key_ret == 0) {
memcpy(&root->defrag_progress, &key, sizeof(key));
ret = -EAGAIN;
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 434457794c27..c91babc6aa4b 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -21,12 +21,12 @@
#include <linux/blkdev.h>
#include <linux/list_sort.h>
#include <linux/iversion.h>
+#include "ctree.h"
#include "tree-log.h"
#include "disk-io.h"
#include "locking.h"
#include "print-tree.h"
#include "backref.h"
-#include "hash.h"
#include "compression.h"
#include "qgroup.h"
#include "inode-map.h"
@@ -286,7 +286,7 @@ struct walk_control {
* inside it
*/
int (*process_func)(struct btrfs_root *log, struct extent_buffer *eb,
- struct walk_control *wc, u64 gen);
+ struct walk_control *wc, u64 gen, int level);
};
/*
@@ -294,7 +294,7 @@ struct walk_control {
*/
static int process_one_buffer(struct btrfs_root *log,
struct extent_buffer *eb,
- struct walk_control *wc, u64 gen)
+ struct walk_control *wc, u64 gen, int level)
{
struct btrfs_fs_info *fs_info = log->fs_info;
int ret = 0;
@@ -304,7 +304,7 @@ static int process_one_buffer(struct btrfs_root *log,
* pin down any logged extents, so we have to read the block.
*/
if (btrfs_fs_incompat(fs_info, MIXED_GROUPS)) {
- ret = btrfs_read_buffer(eb, gen);
+ ret = btrfs_read_buffer(eb, gen, level, NULL);
if (ret)
return ret;
}
@@ -853,7 +853,6 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
struct btrfs_inode *dir,
struct btrfs_dir_item *di)
{
- struct btrfs_fs_info *fs_info = root->fs_info;
struct inode *inode;
char *name;
int name_len;
@@ -887,7 +886,7 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
if (ret)
goto out;
else
- ret = btrfs_run_delayed_items(trans, fs_info);
+ ret = btrfs_run_delayed_items(trans);
out:
kfree(name);
iput(inode);
@@ -1007,7 +1006,6 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
u64 ref_index, char *name, int namelen,
int *search_done)
{
- struct btrfs_fs_info *fs_info = root->fs_info;
int ret;
char *victim_name;
int victim_name_len;
@@ -1065,7 +1063,7 @@ again:
kfree(victim_name);
if (ret)
return ret;
- ret = btrfs_run_delayed_items(trans, fs_info);
+ ret = btrfs_run_delayed_items(trans);
if (ret)
return ret;
*search_done = 1;
@@ -1136,8 +1134,7 @@ again:
victim_name_len);
if (!ret)
ret = btrfs_run_delayed_items(
- trans,
- fs_info);
+ trans);
}
iput(victim_parent);
kfree(victim_name);
@@ -2098,7 +2095,6 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
struct inode *dir,
struct btrfs_key *dir_key)
{
- struct btrfs_fs_info *fs_info = root->fs_info;
int ret;
struct extent_buffer *eb;
int slot;
@@ -2162,7 +2158,7 @@ again:
ret = btrfs_unlink_inode(trans, root, BTRFS_I(dir),
BTRFS_I(inode), name, name_len);
if (!ret)
- ret = btrfs_run_delayed_items(trans, fs_info);
+ ret = btrfs_run_delayed_items(trans);
kfree(name);
iput(inode);
if (ret)
@@ -2410,17 +2406,16 @@ out:
* back refs).
*/
static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
- struct walk_control *wc, u64 gen)
+ struct walk_control *wc, u64 gen, int level)
{
int nritems;
struct btrfs_path *path;
struct btrfs_root *root = wc->replay_dest;
struct btrfs_key key;
- int level;
int i;
int ret;
- ret = btrfs_read_buffer(eb, gen);
+ ret = btrfs_read_buffer(eb, gen, level, NULL);
if (ret)
return ret;
@@ -2537,6 +2532,8 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
WARN_ON(*level >= BTRFS_MAX_LEVEL);
while (*level > 0) {
+ struct btrfs_key first_key;
+
WARN_ON(*level < 0);
WARN_ON(*level >= BTRFS_MAX_LEVEL);
cur = path->nodes[*level];
@@ -2549,6 +2546,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
bytenr = btrfs_node_blockptr(cur, path->slots[*level]);
ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]);
+ btrfs_node_key_to_cpu(cur, &first_key, path->slots[*level]);
blocksize = fs_info->nodesize;
parent = path->nodes[*level];
@@ -2559,7 +2557,8 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
return PTR_ERR(next);
if (*level == 1) {
- ret = wc->process_func(root, next, wc, ptr_gen);
+ ret = wc->process_func(root, next, wc, ptr_gen,
+ *level - 1);
if (ret) {
free_extent_buffer(next);
return ret;
@@ -2567,7 +2566,8 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
path->slots[*level]++;
if (wc->free) {
- ret = btrfs_read_buffer(next, ptr_gen);
+ ret = btrfs_read_buffer(next, ptr_gen,
+ *level - 1, &first_key);
if (ret) {
free_extent_buffer(next);
return ret;
@@ -2597,7 +2597,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
free_extent_buffer(next);
continue;
}
- ret = btrfs_read_buffer(next, ptr_gen);
+ ret = btrfs_read_buffer(next, ptr_gen, *level - 1, &first_key);
if (ret) {
free_extent_buffer(next);
return ret;
@@ -2647,7 +2647,8 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
root_owner = btrfs_header_owner(parent);
ret = wc->process_func(root, path->nodes[*level], wc,
- btrfs_header_generation(path->nodes[*level]));
+ btrfs_header_generation(path->nodes[*level]),
+ *level);
if (ret)
return ret;
@@ -2729,7 +2730,8 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
/* was the root node processed? if not, catch it here */
if (path->nodes[orig_level]) {
ret = wc->process_func(log, path->nodes[orig_level], wc,
- btrfs_header_generation(path->nodes[orig_level]));
+ btrfs_header_generation(path->nodes[orig_level]),
+ orig_level);
if (ret)
goto out;
if (wc->free) {
@@ -3972,6 +3974,7 @@ fill_holes:
ASSERT(ret == 0);
src = src_path->nodes[0];
i = 0;
+ need_find_last_extent = true;
}
btrfs_item_key_to_cpu(src, &key, i);
@@ -4006,6 +4009,36 @@ fill_holes:
break;
*last_extent = extent_end;
}
+
+ /*
+ * Check if there is a hole between the last extent found in our leaf
+ * and the first extent in the next leaf. If there is one, we need to
+ * log an explicit hole so that at replay time we can punch the hole.
+ */
+ if (ret == 0 &&
+ key.objectid == btrfs_ino(inode) &&
+ key.type == BTRFS_EXTENT_DATA_KEY &&
+ i == btrfs_header_nritems(src_path->nodes[0])) {
+ ret = btrfs_next_leaf(inode->root, src_path);
+ need_find_last_extent = true;
+ if (ret > 0) {
+ ret = 0;
+ } else if (ret == 0) {
+ btrfs_item_key_to_cpu(src_path->nodes[0], &key,
+ src_path->slots[0]);
+ if (key.objectid == btrfs_ino(inode) &&
+ key.type == BTRFS_EXTENT_DATA_KEY &&
+ *last_extent < key.offset) {
+ const u64 len = key.offset - *last_extent;
+
+ ret = btrfs_insert_file_extent(trans, log,
+ btrfs_ino(inode),
+ *last_extent, 0,
+ 0, len, 0, len,
+ 0, 0, 0);
+ }
+ }
+ }
/*
* Need to let the callers know we dropped the path so they should
* re-search.
@@ -5517,7 +5550,6 @@ out:
* the last committed transaction
*/
static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
struct btrfs_inode *inode,
struct dentry *parent,
const loff_t start,
@@ -5525,6 +5557,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
int inode_only,
struct btrfs_log_ctx *ctx)
{
+ struct btrfs_root *root = inode->root;
struct btrfs_fs_info *fs_info = root->fs_info;
struct super_block *sb;
struct dentry *old_parent = NULL;
@@ -5550,7 +5583,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
goto end_no_trans;
}
- if (root != inode->root || btrfs_root_refs(&root->root_item) == 0) {
+ if (btrfs_root_refs(&root->root_item) == 0) {
ret = 1;
goto end_no_trans;
}
@@ -5682,7 +5715,7 @@ end_no_trans:
* data on disk.
*/
int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, struct dentry *dentry,
+ struct dentry *dentry,
const loff_t start,
const loff_t end,
struct btrfs_log_ctx *ctx)
@@ -5690,8 +5723,8 @@ int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
struct dentry *parent = dget_parent(dentry);
int ret;
- ret = btrfs_log_inode_parent(trans, root, BTRFS_I(d_inode(dentry)),
- parent, start, end, LOG_INODE_ALL, ctx);
+ ret = btrfs_log_inode_parent(trans, BTRFS_I(d_inode(dentry)), parent,
+ start, end, LOG_INODE_ALL, ctx);
dput(parent);
return ret;
@@ -5953,7 +5986,6 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans,
struct dentry *parent)
{
struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb);
- struct btrfs_root *root = inode->root;
/*
* this will force the logging code to walk the dentry chain
@@ -5970,7 +6002,7 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans,
(!old_dir || old_dir->logged_trans <= fs_info->last_trans_committed))
return 0;
- return btrfs_log_inode_parent(trans, root, inode, parent, 0,
- LLONG_MAX, LOG_INODE_EXISTS, NULL);
+ return btrfs_log_inode_parent(trans, inode, parent, 0, LLONG_MAX,
+ LOG_INODE_EXISTS, NULL);
}
diff --git a/fs/btrfs/tree-log.h b/fs/btrfs/tree-log.h
index 483027f9a7f4..88abc43312a1 100644
--- a/fs/btrfs/tree-log.h
+++ b/fs/btrfs/tree-log.h
@@ -65,7 +65,7 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
int btrfs_recover_log_trees(struct btrfs_root *tree_root);
int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, struct dentry *dentry,
+ struct dentry *dentry,
const loff_t start,
const loff_t end,
struct btrfs_log_ctx *ctx);
diff --git a/fs/btrfs/uuid-tree.c b/fs/btrfs/uuid-tree.c
index 726f928238d0..9916f03430bc 100644
--- a/fs/btrfs/uuid-tree.c
+++ b/fs/btrfs/uuid-tree.c
@@ -282,7 +282,7 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info,
key.offset = 0;
again_search_slot:
- ret = btrfs_search_forward(root, &key, path, 0);
+ ret = btrfs_search_forward(root, &key, path, BTRFS_OLDEST_GENERATION);
if (ret) {
if (ret > 0)
ret = 0;
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index b2d05c6b1c56..93f8f17cacca 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -27,6 +27,7 @@
#include <linux/raid/pq.h>
#include <linux/semaphore.h>
#include <linux/uuid.h>
+#include <linux/list_sort.h>
#include <asm/div64.h>
#include "ctree.h"
#include "extent_map.h"
@@ -278,7 +279,7 @@ static void btrfs_kobject_uevent(struct block_device *bdev,
&disk_to_dev(bdev->bd_disk)->kobj);
}
-void btrfs_cleanup_fs_uuids(void)
+void __exit btrfs_cleanup_fs_uuids(void)
{
struct btrfs_fs_devices *fs_devices;
@@ -708,7 +709,7 @@ static int btrfs_open_one_device(struct btrfs_fs_devices *fs_devices,
if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state) &&
device->devid != BTRFS_DEV_REPLACE_DEVID) {
fs_devices->rw_devices++;
- list_add(&device->dev_alloc_list, &fs_devices->alloc_list);
+ list_add_tail(&device->dev_alloc_list, &fs_devices->alloc_list);
}
brelse(bh);
@@ -895,7 +896,11 @@ error:
return ERR_PTR(-ENOMEM);
}
-void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices, int step)
+/*
+ * After we have read the system tree and know devids belonging to
+ * this filesystem, remove the device which does not belong there.
+ */
+void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices, int step)
{
struct btrfs_device *device, *next;
struct btrfs_device *latest_dev = NULL;
@@ -1103,6 +1108,20 @@ out:
return ret;
}
+static int devid_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+ struct btrfs_device *dev1, *dev2;
+
+ dev1 = list_entry(a, struct btrfs_device, dev_list);
+ dev2 = list_entry(b, struct btrfs_device, dev_list);
+
+ if (dev1->devid < dev2->devid)
+ return -1;
+ else if (dev1->devid > dev2->devid)
+ return 1;
+ return 0;
+}
+
int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
fmode_t flags, void *holder)
{
@@ -1113,6 +1132,7 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
fs_devices->opened++;
ret = 0;
} else {
+ list_sort(NULL, &fs_devices->devices, devid_cmp);
ret = __btrfs_open_devices(fs_devices, flags, holder);
}
mutex_unlock(&uuid_mutex);
@@ -1916,12 +1936,12 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
mutex_lock(&uuid_mutex);
num_devices = fs_info->fs_devices->num_devices;
- btrfs_dev_replace_lock(&fs_info->dev_replace, 0);
+ btrfs_dev_replace_read_lock(&fs_info->dev_replace);
if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) {
WARN_ON(num_devices < 1);
num_devices--;
}
- btrfs_dev_replace_unlock(&fs_info->dev_replace, 0);
+ btrfs_dev_replace_read_unlock(&fs_info->dev_replace);
ret = btrfs_check_raid_min_devices(fs_info, num_devices - 1);
if (ret)
@@ -2047,7 +2067,7 @@ void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_fs_info *fs_info,
{
struct btrfs_fs_devices *fs_devices;
- WARN_ON(!mutex_is_locked(&fs_info->fs_devices->device_list_mutex));
+ lockdep_assert_held(&fs_info->fs_devices->device_list_mutex);
/*
* in case of fs with no seed, srcdev->fs_devices will point
@@ -2237,7 +2257,7 @@ static int btrfs_prepare_sprout(struct btrfs_fs_info *fs_info)
struct btrfs_device *device;
u64 super_flags;
- BUG_ON(!mutex_is_locked(&uuid_mutex));
+ lockdep_assert_held(&uuid_mutex);
if (!fs_devices->seeding)
return -EINVAL;
@@ -2642,7 +2662,6 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
device->total_bytes = btrfs_device_get_total_bytes(srcdev);
device->disk_total_bytes = btrfs_device_get_disk_total_bytes(srcdev);
device->bytes_used = btrfs_device_get_bytes_used(srcdev);
- ASSERT(list_empty(&srcdev->resized_list));
device->commit_total_bytes = srcdev->commit_total_bytes;
device->commit_bytes_used = device->bytes_used;
device->fs_info = fs_info;
@@ -2666,19 +2685,6 @@ error:
return ret;
}
-void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info,
- struct btrfs_device *tgtdev)
-{
- u32 sectorsize = fs_info->sectorsize;
-
- WARN_ON(fs_info->fs_devices->rw_devices == 0);
- tgtdev->io_width = sectorsize;
- tgtdev->io_align = sectorsize;
- tgtdev->sector_size = sectorsize;
- tgtdev->fs_info = fs_info;
- set_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &tgtdev->dev_state);
-}
-
static noinline int btrfs_update_device(struct btrfs_trans_handle *trans,
struct btrfs_device *device)
{
@@ -2984,7 +2990,7 @@ static int btrfs_relocate_chunk(struct btrfs_fs_info *fs_info, u64 chunk_offset)
* we release the path used to search the chunk/dev tree and before
* the current task acquires this mutex and calls us.
*/
- ASSERT(mutex_is_locked(&fs_info->delete_unused_bgs_mutex));
+ lockdep_assert_held(&fs_info->delete_unused_bgs_mutex);
ret = btrfs_can_relocate(fs_info, chunk_offset);
if (ret)
@@ -2997,6 +3003,16 @@ static int btrfs_relocate_chunk(struct btrfs_fs_info *fs_info, u64 chunk_offset)
if (ret)
return ret;
+ /*
+ * We add the kobjects here (and after forcing data chunk creation)
+ * since relocation is the only place we'll create chunks of a new
+ * type at runtime. The only place where we'll remove the last
+ * chunk of a type is the call immediately below this one. Even
+ * so, we're protected against races with the cleaner thread since
+ * we're covered by the delete_unused_bgs_mutex.
+ */
+ btrfs_add_raid_kobjects(fs_info);
+
trans = btrfs_start_trans_remove_block_group(root->fs_info,
chunk_offset);
if (IS_ERR(trans)) {
@@ -3124,6 +3140,8 @@ static int btrfs_may_alloc_data_chunk(struct btrfs_fs_info *fs_info,
if (ret < 0)
return ret;
+ btrfs_add_raid_kobjects(fs_info);
+
return 1;
}
}
@@ -3892,12 +3910,12 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
}
num_devices = fs_info->fs_devices->num_devices;
- btrfs_dev_replace_lock(&fs_info->dev_replace, 0);
+ btrfs_dev_replace_read_lock(&fs_info->dev_replace);
if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) {
BUG_ON(num_devices < 1);
num_devices--;
}
- btrfs_dev_replace_unlock(&fs_info->dev_replace, 0);
+ btrfs_dev_replace_read_unlock(&fs_info->dev_replace);
allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE | BTRFS_BLOCK_GROUP_DUP;
if (num_devices > 1)
allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1);
@@ -4202,7 +4220,8 @@ static int btrfs_uuid_scan_kthread(void *data)
key.offset = 0;
while (1) {
- ret = btrfs_search_forward(root, &key, path, 0);
+ ret = btrfs_search_forward(root, &key, path,
+ BTRFS_OLDEST_GENERATION);
if (ret) {
if (ret > 0)
ret = 0;
@@ -4672,7 +4691,7 @@ static void check_raid56_incompat_flag(struct btrfs_fs_info *info, u64 type)
btrfs_set_fs_incompat(info, RAID56);
}
-#define BTRFS_MAX_DEVS(r) ((BTRFS_MAX_ITEM_SIZE(r->fs_info) \
+#define BTRFS_MAX_DEVS(info) ((BTRFS_MAX_ITEM_SIZE(info) \
- sizeof(struct btrfs_chunk)) \
/ sizeof(struct btrfs_stripe) + 1)
@@ -4713,10 +4732,13 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
BUG_ON(!alloc_profile_is_valid(type, 0));
- if (list_empty(&fs_devices->alloc_list))
+ if (list_empty(&fs_devices->alloc_list)) {
+ if (btrfs_test_opt(info, ENOSPC_DEBUG))
+ btrfs_debug(info, "%s: no writable device", __func__);
return -ENOSPC;
+ }
- index = __get_raid_index(type);
+ index = btrfs_bg_flags_to_raid_index(type);
sub_stripes = btrfs_raid_array[index].sub_stripes;
dev_stripes = btrfs_raid_array[index].dev_stripes;
@@ -4729,7 +4751,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
max_stripe_size = SZ_1G;
max_chunk_size = 10 * max_stripe_size;
if (!devs_max)
- devs_max = BTRFS_MAX_DEVS(info->chunk_root);
+ devs_max = BTRFS_MAX_DEVS(info);
} else if (type & BTRFS_BLOCK_GROUP_METADATA) {
/* for larger filesystems, use larger metadata chunks */
if (fs_devices->total_rw_bytes > 50ULL * SZ_1G)
@@ -4738,7 +4760,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
max_stripe_size = SZ_256M;
max_chunk_size = max_stripe_size;
if (!devs_max)
- devs_max = BTRFS_MAX_DEVS(info->chunk_root);
+ devs_max = BTRFS_MAX_DEVS(info);
} else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
max_stripe_size = SZ_32M;
max_chunk_size = 2 * max_stripe_size;
@@ -4797,8 +4819,14 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
if (ret == 0)
max_avail = max_stripe_size * dev_stripes;
- if (max_avail < BTRFS_STRIPE_LEN * dev_stripes)
+ if (max_avail < BTRFS_STRIPE_LEN * dev_stripes) {
+ if (btrfs_test_opt(info, ENOSPC_DEBUG))
+ btrfs_debug(info,
+ "%s: devid %llu has no free space, have=%llu want=%u",
+ __func__, device->devid, max_avail,
+ BTRFS_STRIPE_LEN * dev_stripes);
continue;
+ }
if (ndevs == fs_devices->rw_devices) {
WARN(1, "%s: found more than %llu devices\n",
@@ -4821,8 +4849,13 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
/* round down to number of usable stripes */
ndevs = round_down(ndevs, devs_increment);
- if (ndevs < devs_increment * sub_stripes || ndevs < devs_min) {
+ if (ndevs < devs_min) {
ret = -ENOSPC;
+ if (btrfs_test_opt(info, ENOSPC_DEBUG)) {
+ btrfs_debug(info,
+ "%s: not enough devices with free space: have=%d minimum required=%d",
+ __func__, ndevs, devs_min);
+ }
goto error;
}
@@ -4856,18 +4889,17 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
* and compare that answer with the max chunk size
*/
if (stripe_size * data_stripes > max_chunk_size) {
- u64 mask = (1ULL << 24) - 1;
-
stripe_size = div_u64(max_chunk_size, data_stripes);
/* bump the answer up to a 16MB boundary */
- stripe_size = (stripe_size + mask) & ~mask;
+ stripe_size = round_up(stripe_size, SZ_16M);
- /* but don't go higher than the limits we found
- * while searching for free extents
+ /*
+ * But don't go higher than the limits we found while searching
+ * for free extents
*/
- if (stripe_size > devices_info[ndevs-1].max_avail)
- stripe_size = devices_info[ndevs-1].max_avail;
+ stripe_size = min(devices_info[ndevs - 1].max_avail,
+ stripe_size);
}
/* align to BTRFS_STRIPE_LEN */
@@ -5068,7 +5100,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
{
u64 chunk_offset;
- ASSERT(mutex_is_locked(&fs_info->chunk_mutex));
+ lockdep_assert_held(&fs_info->chunk_mutex);
chunk_offset = find_next_chunk(fs_info);
return __btrfs_alloc_chunk(trans, chunk_offset, type);
}
@@ -5209,11 +5241,11 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
ret = 1;
free_extent_map(em);
- btrfs_dev_replace_lock(&fs_info->dev_replace, 0);
+ btrfs_dev_replace_read_lock(&fs_info->dev_replace);
if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace) &&
fs_info->dev_replace.tgtdev)
ret++;
- btrfs_dev_replace_unlock(&fs_info->dev_replace, 0);
+ btrfs_dev_replace_read_unlock(&fs_info->dev_replace);
return ret;
}
@@ -5254,13 +5286,25 @@ int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
}
static int find_live_mirror(struct btrfs_fs_info *fs_info,
- struct map_lookup *map, int first, int num,
- int optimal, int dev_replace_is_ongoing)
+ struct map_lookup *map, int first,
+ int dev_replace_is_ongoing)
{
int i;
+ int num_stripes;
+ int preferred_mirror;
int tolerance;
struct btrfs_device *srcdev;
+ ASSERT((map->type &
+ (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10)));
+
+ if (map->type & BTRFS_BLOCK_GROUP_RAID10)
+ num_stripes = map->sub_stripes;
+ else
+ num_stripes = map->num_stripes;
+
+ preferred_mirror = first + current->pid % num_stripes;
+
if (dev_replace_is_ongoing &&
fs_info->dev_replace.cont_reading_from_srcdev_mode ==
BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_AVOID)
@@ -5274,10 +5318,10 @@ static int find_live_mirror(struct btrfs_fs_info *fs_info,
* mirror is available
*/
for (tolerance = 0; tolerance < 2; tolerance++) {
- if (map->stripes[optimal].dev->bdev &&
- (tolerance || map->stripes[optimal].dev != srcdev))
- return optimal;
- for (i = first; i < first + num; i++) {
+ if (map->stripes[preferred_mirror].dev->bdev &&
+ (tolerance || map->stripes[preferred_mirror].dev != srcdev))
+ return preferred_mirror;
+ for (i = first; i < first + num_stripes; i++) {
if (map->stripes[i].dev->bdev &&
(tolerance || map->stripes[i].dev != srcdev))
return i;
@@ -5287,7 +5331,7 @@ static int find_live_mirror(struct btrfs_fs_info *fs_info,
/* we couldn't find one that doesn't fail. Just return something
* and the io error handling code will clean up eventually
*/
- return optimal;
+ return preferred_mirror;
}
static inline int parity_smaller(u64 a, u64 b)
@@ -5779,10 +5823,10 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
if (!bbio_ret)
goto out;
- btrfs_dev_replace_lock(dev_replace, 0);
+ btrfs_dev_replace_read_lock(dev_replace);
dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(dev_replace);
if (!dev_replace_is_ongoing)
- btrfs_dev_replace_unlock(dev_replace, 0);
+ btrfs_dev_replace_read_unlock(dev_replace);
else
btrfs_dev_replace_set_lock_blocking(dev_replace);
@@ -5814,8 +5858,6 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
stripe_index = mirror_num - 1;
else {
stripe_index = find_live_mirror(fs_info, map, 0,
- map->num_stripes,
- current->pid % map->num_stripes,
dev_replace_is_ongoing);
mirror_num = stripe_index + 1;
}
@@ -5843,8 +5885,6 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
int old_stripe_index = stripe_index;
stripe_index = find_live_mirror(fs_info, map,
stripe_index,
- map->sub_stripes, stripe_index +
- current->pid % map->sub_stripes,
dev_replace_is_ongoing);
mirror_num = stripe_index - old_stripe_index + 1;
}
@@ -5984,7 +6024,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info,
out:
if (dev_replace_is_ongoing) {
btrfs_dev_replace_clear_lock_blocking(dev_replace);
- btrfs_dev_replace_unlock(dev_replace, 0);
+ btrfs_dev_replace_read_unlock(dev_replace);
}
free_extent_map(em);
return ret;
@@ -6618,7 +6658,7 @@ static struct btrfs_fs_devices *open_seed_devices(struct btrfs_fs_info *fs_info,
struct btrfs_fs_devices *fs_devices;
int ret;
- BUG_ON(!mutex_is_locked(&uuid_mutex));
+ lockdep_assert_held(&uuid_mutex);
ASSERT(fsid);
fs_devices = fs_info->fs_devices->seed;
@@ -7358,20 +7398,20 @@ void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info)
}
/* Must be invoked during the transaction commit */
-void btrfs_update_commit_device_bytes_used(struct btrfs_fs_info *fs_info,
- struct btrfs_transaction *transaction)
+void btrfs_update_commit_device_bytes_used(struct btrfs_transaction *trans)
{
+ struct btrfs_fs_info *fs_info = trans->fs_info;
struct extent_map *em;
struct map_lookup *map;
struct btrfs_device *dev;
int i;
- if (list_empty(&transaction->pending_chunks))
+ if (list_empty(&trans->pending_chunks))
return;
/* In order to kick the device replace finish process */
mutex_lock(&fs_info->chunk_mutex);
- list_for_each_entry(em, &transaction->pending_chunks, list) {
+ list_for_each_entry(em, &trans->pending_chunks, list) {
map = em->map_lookup;
for (i = 0; i < map->num_stripes; i++) {
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 28c28eeadff3..d1fcaea9fef5 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -422,7 +422,7 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
struct btrfs_fs_devices **fs_devices_ret);
int btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
-void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices, int step);
+void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices, int step);
void btrfs_assign_next_active_device(struct btrfs_fs_info *fs_info,
struct btrfs_device *device, struct btrfs_device *this_dev);
int btrfs_find_device_missing_or_by_path(struct btrfs_fs_info *fs_info,
@@ -436,7 +436,7 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
const u8 *uuid);
int btrfs_rm_device(struct btrfs_fs_info *fs_info,
const char *device_path, u64 devid);
-void btrfs_cleanup_fs_uuids(void);
+void __exit btrfs_cleanup_fs_uuids(void);
int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len);
int btrfs_grow_device(struct btrfs_trans_handle *trans,
struct btrfs_device *device, u64 new_size);
@@ -476,8 +476,6 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_fs_info *fs_info,
struct btrfs_device *srcdev);
void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
struct btrfs_device *tgtdev);
-void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info,
- struct btrfs_device *tgtdev);
void btrfs_scratch_superblocks(struct block_device *bdev, const char *device_path);
int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info,
u64 logical, u64 len);
@@ -546,9 +544,30 @@ static inline void btrfs_dev_stat_reset(struct btrfs_device *dev,
btrfs_dev_stat_set(dev, index, 0);
}
+/*
+ * Convert block group flags (BTRFS_BLOCK_GROUP_*) to btrfs_raid_types, which
+ * can be used as index to access btrfs_raid_array[].
+ */
+static inline enum btrfs_raid_types btrfs_bg_flags_to_raid_index(u64 flags)
+{
+ if (flags & BTRFS_BLOCK_GROUP_RAID10)
+ return BTRFS_RAID_RAID10;
+ else if (flags & BTRFS_BLOCK_GROUP_RAID1)
+ return BTRFS_RAID_RAID1;
+ else if (flags & BTRFS_BLOCK_GROUP_DUP)
+ return BTRFS_RAID_DUP;
+ else if (flags & BTRFS_BLOCK_GROUP_RAID0)
+ return BTRFS_RAID_RAID0;
+ else if (flags & BTRFS_BLOCK_GROUP_RAID5)
+ return BTRFS_RAID_RAID5;
+ else if (flags & BTRFS_BLOCK_GROUP_RAID6)
+ return BTRFS_RAID_RAID6;
+
+ return BTRFS_RAID_SINGLE; /* BTRFS_BLOCK_GROUP_SINGLE */
+}
+
void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info);
-void btrfs_update_commit_device_bytes_used(struct btrfs_fs_info *fs_info,
- struct btrfs_transaction *transaction);
+void btrfs_update_commit_device_bytes_used(struct btrfs_transaction *trans);
struct list_head *btrfs_get_fs_uuids(void);
void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info);
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index de7d072c78ef..e1e8177deb5e 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -33,7 +33,7 @@
#include "locking.h"
-ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
+int btrfs_getxattr(struct inode *inode, const char *name,
void *buffer, size_t size)
{
struct btrfs_dir_item *di;
@@ -233,7 +233,7 @@ out:
/*
* @value: "" makes the attribute to empty, NULL removes it
*/
-int __btrfs_setxattr(struct btrfs_trans_handle *trans,
+int btrfs_setxattr(struct btrfs_trans_handle *trans,
struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
@@ -374,7 +374,7 @@ static int btrfs_xattr_handler_get(const struct xattr_handler *handler,
const char *name, void *buffer, size_t size)
{
name = xattr_full_name(handler, name);
- return __btrfs_getxattr(inode, name, buffer, size);
+ return btrfs_getxattr(inode, name, buffer, size);
}
static int btrfs_xattr_handler_set(const struct xattr_handler *handler,
@@ -383,7 +383,7 @@ static int btrfs_xattr_handler_set(const struct xattr_handler *handler,
size_t size, int flags)
{
name = xattr_full_name(handler, name);
- return __btrfs_setxattr(NULL, inode, name, buffer, size, flags);
+ return btrfs_setxattr(NULL, inode, name, buffer, size, flags);
}
static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler,
@@ -448,8 +448,8 @@ static int btrfs_initxattrs(struct inode *inode,
}
strcpy(name, XATTR_SECURITY_PREFIX);
strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
- err = __btrfs_setxattr(trans, inode, name,
- xattr->value, xattr->value_len, 0);
+ err = btrfs_setxattr(trans, inode, name, xattr->value,
+ xattr->value_len, 0);
kfree(name);
if (err < 0)
break;
diff --git a/fs/btrfs/xattr.h b/fs/btrfs/xattr.h
index 15fc4743dc70..e215a3212a2a 100644
--- a/fs/btrfs/xattr.h
+++ b/fs/btrfs/xattr.h
@@ -23,13 +23,14 @@
extern const struct xattr_handler *btrfs_xattr_handlers[];
-extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
+int btrfs_getxattr(struct inode *inode, const char *name,
void *buffer, size_t size);
-extern int __btrfs_setxattr(struct btrfs_trans_handle *trans,
+int btrfs_setxattr(struct btrfs_trans_handle *trans,
struct inode *inode, const char *name,
const void *value, size_t size, int flags);
+ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
-extern int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
+int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
struct inode *inode, struct inode *dir,
const struct qstr *qstr);
diff --git a/fs/char_dev.c b/fs/char_dev.c
index a65e4a56318c..a279c58fe360 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -67,18 +67,18 @@ static int find_dynamic_major(void)
int i;
struct char_device_struct *cd;
- for (i = ARRAY_SIZE(chrdevs)-1; i > CHRDEV_MAJOR_DYN_END; i--) {
+ for (i = ARRAY_SIZE(chrdevs)-1; i >= CHRDEV_MAJOR_DYN_END; i--) {
if (chrdevs[i] == NULL)
return i;
}
for (i = CHRDEV_MAJOR_DYN_EXT_START;
- i > CHRDEV_MAJOR_DYN_EXT_END; i--) {
+ i >= CHRDEV_MAJOR_DYN_EXT_END; i--) {
for (cd = chrdevs[major_to_index(i)]; cd; cd = cd->next)
if (cd->major == i)
break;
- if (cd == NULL || cd->major != i)
+ if (cd == NULL)
return i;
}
@@ -121,8 +121,8 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
}
if (major >= CHRDEV_MAJOR_MAX) {
- pr_err("CHRDEV \"%s\" major requested (%d) is greater than the maximum (%d)\n",
- name, major, CHRDEV_MAJOR_MAX);
+ pr_err("CHRDEV \"%s\" major requested (%u) is greater than the maximum (%u)\n",
+ name, major, CHRDEV_MAJOR_MAX-1);
ret = -EINVAL;
goto out;
}
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index 687da62daf4e..741749a98614 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -187,13 +187,13 @@ config CIFS_NFSD_EXPORT
Allows NFS server to export a CIFS mounted share (nfsd over cifs)
config CIFS_SMB311
- bool "SMB3.1.1 network file system support (Experimental)"
+ bool "SMB3.1.1 network file system support"
depends on CIFS
+ select CRYPTO_SHA512
help
- This enables experimental support for the newest, SMB3.1.1, dialect.
- This dialect includes improved security negotiation features.
- If unsure, say N
+ This enables support for the newest, and most secure dialect, SMB3.11.
+ If unsure, say Y
config CIFS_SMB_DIRECT
bool "SMB Direct support (Experimental)"
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index f2b0a7f124da..a6ef088e057b 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -36,37 +36,6 @@
#include <crypto/skcipher.h>
#include <crypto/aead.h>
-static int
-cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
-{
- int rc;
- unsigned int size;
-
- if (server->secmech.sdescmd5 != NULL)
- return 0; /* already allocated */
-
- server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
- if (IS_ERR(server->secmech.md5)) {
- cifs_dbg(VFS, "could not allocate crypto md5\n");
- rc = PTR_ERR(server->secmech.md5);
- server->secmech.md5 = NULL;
- return rc;
- }
-
- size = sizeof(struct shash_desc) +
- crypto_shash_descsize(server->secmech.md5);
- server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
- if (!server->secmech.sdescmd5) {
- crypto_free_shash(server->secmech.md5);
- server->secmech.md5 = NULL;
- return -ENOMEM;
- }
- server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
- server->secmech.sdescmd5->shash.flags = 0x0;
-
- return 0;
-}
-
int __cifs_calc_signature(struct smb_rqst *rqst,
struct TCP_Server_Info *server, char *signature,
struct shash_desc *shash)
@@ -132,13 +101,10 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
if (!rqst->rq_iov || !signature || !server)
return -EINVAL;
- if (!server->secmech.sdescmd5) {
- rc = cifs_crypto_shash_md5_allocate(server);
- if (rc) {
- cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
- return -1;
- }
- }
+ rc = cifs_alloc_hash("md5", &server->secmech.md5,
+ &server->secmech.sdescmd5);
+ if (rc)
+ return -1;
rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
if (rc) {
@@ -663,37 +629,6 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
return rc;
}
-static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
-{
- int rc;
- unsigned int size;
-
- /* check if already allocated */
- if (server->secmech.sdeschmacmd5)
- return 0;
-
- server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
- if (IS_ERR(server->secmech.hmacmd5)) {
- cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
- rc = PTR_ERR(server->secmech.hmacmd5);
- server->secmech.hmacmd5 = NULL;
- return rc;
- }
-
- size = sizeof(struct shash_desc) +
- crypto_shash_descsize(server->secmech.hmacmd5);
- server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
- if (!server->secmech.sdeschmacmd5) {
- crypto_free_shash(server->secmech.hmacmd5);
- server->secmech.hmacmd5 = NULL;
- return -ENOMEM;
- }
- server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
- server->secmech.sdeschmacmd5->shash.flags = 0x0;
-
- return 0;
-}
-
int
setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
{
@@ -757,9 +692,10 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
mutex_lock(&ses->server->srv_mutex);
- rc = crypto_hmacmd5_alloc(ses->server);
+ rc = cifs_alloc_hash("hmac(md5)",
+ &ses->server->secmech.hmacmd5,
+ &ses->server->secmech.sdeschmacmd5);
if (rc) {
- cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc);
goto unlock;
}
@@ -893,6 +829,11 @@ cifs_crypto_secmech_release(struct TCP_Server_Info *server)
server->secmech.md5 = NULL;
}
+ if (server->secmech.sha512) {
+ crypto_free_shash(server->secmech.sha512);
+ server->secmech.sha512 = NULL;
+ }
+
if (server->secmech.hmacmd5) {
crypto_free_shash(server->secmech.hmacmd5);
server->secmech.hmacmd5 = NULL;
@@ -916,4 +857,6 @@ cifs_crypto_secmech_release(struct TCP_Server_Info *server)
server->secmech.sdeschmacmd5 = NULL;
kfree(server->secmech.sdescmd5);
server->secmech.sdescmd5 = NULL;
+ kfree(server->secmech.sdescsha512);
+ server->secmech.sdescsha512 = NULL;
}
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 32cdea67bbfd..f715609b13f3 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1486,6 +1486,7 @@ MODULE_SOFTDEP("pre: nls");
MODULE_SOFTDEP("pre: aes");
MODULE_SOFTDEP("pre: cmac");
MODULE_SOFTDEP("pre: sha256");
+MODULE_SOFTDEP("pre: sha512");
MODULE_SOFTDEP("pre: aead2");
MODULE_SOFTDEP("pre: ccm");
module_init(init_cifs)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 48f7c197cd2d..2282562e78a1 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -130,10 +130,12 @@ struct cifs_secmech {
struct crypto_shash *md5; /* md5 hash function */
struct crypto_shash *hmacsha256; /* hmac-sha256 hash function */
struct crypto_shash *cmacaes; /* block-cipher based MAC function */
+ struct crypto_shash *sha512; /* sha512 hash function */
struct sdesc *sdeschmacmd5; /* ctxt to generate ntlmv2 hash, CR1 */
struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
struct sdesc *sdeschmacsha256; /* ctxt to generate smb2 signature */
struct sdesc *sdesccmacaes; /* ctxt to generate smb3 signature */
+ struct sdesc *sdescsha512; /* ctxt to generate smb3.11 signing key */
struct crypto_aead *ccmaesencrypt; /* smb3 encryption aead */
struct crypto_aead *ccmaesdecrypt; /* smb3 decryption aead */
};
@@ -466,6 +468,7 @@ struct smb_version_values {
__u32 exclusive_lock_type;
__u32 shared_lock_type;
__u32 unlock_lock_type;
+ size_t header_preamble_size;
size_t header_size;
size_t max_header_size;
size_t read_rsp_size;
@@ -673,7 +676,8 @@ struct TCP_Server_Info {
unsigned int max_read;
unsigned int max_write;
#ifdef CONFIG_CIFS_SMB311
- __u8 preauth_sha_hash[64]; /* save initital negprot hash */
+ /* save initital negprot hash */
+ __u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
#endif /* 3.1.1 */
struct delayed_work reconnect; /* reconnect workqueue job */
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
@@ -862,7 +866,7 @@ struct cifs_ses {
__u8 smb3encryptionkey[SMB3_SIGN_KEY_SIZE];
__u8 smb3decryptionkey[SMB3_SIGN_KEY_SIZE];
#ifdef CONFIG_CIFS_SMB311
- __u8 preauth_sha_hash[64];
+ __u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
#endif /* 3.1.1 */
};
@@ -1466,6 +1470,7 @@ struct dfs_info3_param {
#define CIFS_FATTR_NEED_REVAL 0x4
#define CIFS_FATTR_INO_COLLISION 0x8
#define CIFS_FATTR_UNKNOWN_NLINK 0x10
+#define CIFS_FATTR_FAKE_ROOT_INO 0x20
struct cifs_fattr {
u32 cf_flags;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 93d565186698..365a414a75e9 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -542,4 +542,9 @@ enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
struct cifs_aio_ctx *cifs_aio_ctx_alloc(void);
void cifs_aio_ctx_release(struct kref *refcount);
int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw);
+
+int cifs_alloc_hash(const char *name, struct crypto_shash **shash,
+ struct sdesc **sdesc);
+void cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc);
+
#endif /* _CIFSPROTO_H */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 9ceebf30eb22..59c09a596c0a 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1454,7 +1454,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
unsigned int data_offset, data_len;
struct cifs_readdata *rdata = mid->callback_data;
char *buf = server->smallbuf;
- unsigned int buflen = get_rfc1002_length(buf) + 4;
+ unsigned int buflen = get_rfc1002_length(buf) +
+ server->vals->header_preamble_size;
bool use_rdma_mr = false;
cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
@@ -1504,7 +1505,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
return cifs_readv_discard(server, mid);
}
- data_offset = server->ops->read_data_offset(buf) + 4;
+ data_offset = server->ops->read_data_offset(buf) +
+ server->vals->header_preamble_size;
if (data_offset < server->total_read) {
/*
* win2k8 sometimes sends an offset of 0 when the read
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index a726f524fb84..4e0808f40195 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -775,7 +775,8 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
unsigned int pdu_length = get_rfc1002_length(buf);
/* make sure this will fit in a large buffer */
- if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) - 4) {
+ if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
+ server->vals->header_preamble_size) {
cifs_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
cifs_reconnect(server);
wake_up(&server->response_q);
@@ -791,7 +792,9 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
/* now read the rest */
length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
- pdu_length - HEADER_SIZE(server) + 1 + 4);
+ pdu_length - HEADER_SIZE(server) + 1
+ + server->vals->header_preamble_size);
+
if (length < 0)
return length;
server->total_read += length;
@@ -884,7 +887,8 @@ cifs_demultiplex_thread(void *p)
continue;
/* make sure we have enough to get to the MID */
- if (pdu_length < HEADER_SIZE(server) - 1 - 4) {
+ if (pdu_length < HEADER_SIZE(server) - 1 -
+ server->vals->header_preamble_size) {
cifs_dbg(VFS, "SMB response too short (%u bytes)\n",
pdu_length);
cifs_reconnect(server);
@@ -893,8 +897,10 @@ cifs_demultiplex_thread(void *p)
}
/* read down to the MID */
- length = cifs_read_from_socket(server, buf + 4,
- HEADER_SIZE(server) - 1 - 4);
+ length = cifs_read_from_socket(server,
+ buf + server->vals->header_preamble_size,
+ HEADER_SIZE(server) - 1
+ - server->vals->header_preamble_size);
if (length < 0)
continue;
server->total_read += length;
@@ -4306,7 +4312,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
server->sec_mode, server->capabilities, server->timeAdj);
if (ses->auth_key.response) {
- cifs_dbg(VFS, "Free previous auth_key.response = %p\n",
+ cifs_dbg(FYI, "Free previous auth_key.response = %p\n",
ses->auth_key.response);
kfree(ses->auth_key.response);
ses->auth_key.response = NULL;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 8f9a8cc7cc62..f856df4adae3 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -707,6 +707,18 @@ cgfi_exit:
return rc;
}
+/* Simple function to return a 64 bit hash of string. Rarely called */
+static __u64 simple_hashstr(const char *str)
+{
+ const __u64 hash_mult = 1125899906842597L; /* a big enough prime */
+ __u64 hash = 0;
+
+ while (*str)
+ hash = (hash + (__u64) *str++) * hash_mult;
+
+ return hash;
+}
+
int
cifs_get_inode_info(struct inode **inode, const char *full_path,
FILE_ALL_INFO *data, struct super_block *sb, int xid,
@@ -816,6 +828,14 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
tmprc);
fattr.cf_uniqueid = iunique(sb, ROOT_I);
cifs_autodisable_serverino(cifs_sb);
+ } else if ((fattr.cf_uniqueid == 0) &&
+ strlen(full_path) == 0) {
+ /* some servers ret bad root ino ie 0 */
+ cifs_dbg(FYI, "Invalid (0) inodenum\n");
+ fattr.cf_flags |=
+ CIFS_FATTR_FAKE_ROOT_INO;
+ fattr.cf_uniqueid =
+ simple_hashstr(tcon->treeName);
}
}
} else
@@ -832,6 +852,16 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
&fattr.cf_uniqueid, data);
if (tmprc)
fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
+ else if ((fattr.cf_uniqueid == 0) &&
+ strlen(full_path) == 0) {
+ /*
+ * Reuse existing root inode num since
+ * inum zero for root causes ls of . and .. to
+ * not be returned
+ */
+ cifs_dbg(FYI, "Srv ret 0 inode num for root\n");
+ fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
+ }
} else
fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
}
@@ -893,6 +923,9 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
}
cgii_exit:
+ if ((*inode) && ((*inode)->i_ino == 0))
+ cifs_dbg(FYI, "inode number of zero returned\n");
+
kfree(buf);
cifs_put_tlink(tlink);
return rc;
@@ -1066,10 +1099,7 @@ iget_no_retry:
out:
kfree(path);
- /* can not call macro free_xid here since in a void func
- * TODO: This is no longer true
- */
- _free_xid(xid);
+ free_xid(xid);
return inode;
}
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 60b5a11ee11b..889a840172eb 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -50,25 +50,12 @@ static int
symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
{
int rc;
- unsigned int size;
- struct crypto_shash *md5;
- struct sdesc *sdescmd5;
-
- md5 = crypto_alloc_shash("md5", 0, 0);
- if (IS_ERR(md5)) {
- rc = PTR_ERR(md5);
- cifs_dbg(VFS, "%s: Crypto md5 allocation error %d\n",
- __func__, rc);
- return rc;
- }
- size = sizeof(struct shash_desc) + crypto_shash_descsize(md5);
- sdescmd5 = kmalloc(size, GFP_KERNEL);
- if (!sdescmd5) {
- rc = -ENOMEM;
+ struct crypto_shash *md5 = NULL;
+ struct sdesc *sdescmd5 = NULL;
+
+ rc = cifs_alloc_hash("md5", &md5, &sdescmd5);
+ if (rc)
goto symlink_hash_err;
- }
- sdescmd5->shash.tfm = md5;
- sdescmd5->shash.flags = 0x0;
rc = crypto_shash_init(&sdescmd5->shash);
if (rc) {
@@ -85,9 +72,7 @@ symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
symlink_hash_err:
- crypto_free_shash(md5);
- kfree(sdescmd5);
-
+ cifs_free_hash(&md5, &sdescmd5);
return rc;
}
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index a0dbced4a45c..460084a8eac5 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -848,3 +848,57 @@ setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw)
iov_iter_bvec(&ctx->iter, ITER_BVEC | rw, ctx->bv, npages, ctx->len);
return 0;
}
+
+/**
+ * cifs_alloc_hash - allocate hash and hash context together
+ *
+ * The caller has to make sure @sdesc is initialized to either NULL or
+ * a valid context. Both can be freed via cifs_free_hash().
+ */
+int
+cifs_alloc_hash(const char *name,
+ struct crypto_shash **shash, struct sdesc **sdesc)
+{
+ int rc = 0;
+ size_t size;
+
+ if (*sdesc != NULL)
+ return 0;
+
+ *shash = crypto_alloc_shash(name, 0, 0);
+ if (IS_ERR(*shash)) {
+ cifs_dbg(VFS, "could not allocate crypto %s\n", name);
+ rc = PTR_ERR(*shash);
+ *shash = NULL;
+ *sdesc = NULL;
+ return rc;
+ }
+
+ size = sizeof(struct shash_desc) + crypto_shash_descsize(*shash);
+ *sdesc = kmalloc(size, GFP_KERNEL);
+ if (*sdesc == NULL) {
+ cifs_dbg(VFS, "no memory left to allocate crypto %s\n", name);
+ crypto_free_shash(*shash);
+ *shash = NULL;
+ return -ENOMEM;
+ }
+
+ (*sdesc)->shash.tfm = *shash;
+ (*sdesc)->shash.flags = 0x0;
+ return 0;
+}
+
+/**
+ * cifs_free_hash - free hash and hash context together
+ *
+ * Freeing a NULL hash or context is safe.
+ */
+void
+cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc)
+{
+ kfree(*sdesc);
+ *sdesc = NULL;
+ if (*shash)
+ crypto_free_shash(*shash);
+ *shash = NULL;
+}
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 3d495e440c87..aff8ce8ba34d 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -1122,6 +1122,7 @@ struct smb_version_values smb1_values = {
.exclusive_lock_type = 0,
.shared_lock_type = LOCKING_ANDX_SHARED_LOCK,
.unlock_lock_type = 0,
+ .header_preamble_size = 4,
.header_size = sizeof(struct smb_hdr),
.max_header_size = MAX_CIFS_HDR_SIZE,
.read_rsp_size = sizeof(READ_RSP),
diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c
index 62c88dfed57b..3bfc9c990724 100644
--- a/fs/cifs/smb2maperror.c
+++ b/fs/cifs/smb2maperror.c
@@ -745,7 +745,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
"STATUS_NOLOGON_SERVER_TRUST_ACCOUNT"},
{STATUS_DOMAIN_TRUST_INCONSISTENT, -EIO,
"STATUS_DOMAIN_TRUST_INCONSISTENT"},
- {STATUS_FS_DRIVER_REQUIRED, -EIO, "STATUS_FS_DRIVER_REQUIRED"},
+ {STATUS_FS_DRIVER_REQUIRED, -EOPNOTSUPP, "STATUS_FS_DRIVER_REQUIRED"},
{STATUS_IMAGE_ALREADY_LOADED_AS_DLL, -EIO,
"STATUS_IMAGE_ALREADY_LOADED_AS_DLL"},
{STATUS_NETWORK_OPEN_RESTRICTION, -EIO,
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 76d03abaa38c..5406e95f5d92 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -150,7 +150,8 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
}
return 1;
}
- if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE - 4) {
+ if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE -
+ srvr->vals->header_preamble_size) {
cifs_dbg(VFS, "SMB length greater than maximum, mid=%llu\n",
mid);
return 1;
@@ -189,26 +190,26 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
}
}
- if (4 + len != length) {
- cifs_dbg(VFS, "Total length %u RFC1002 length %u mismatch mid %llu\n",
- length, 4 + len, mid);
+ if (srvr->vals->header_preamble_size + len != length) {
+ cifs_dbg(VFS, "Total length %u RFC1002 length %zu mismatch mid %llu\n",
+ length, srvr->vals->header_preamble_size + len, mid);
return 1;
}
clc_len = smb2_calc_size(hdr);
- if (4 + len != clc_len) {
- cifs_dbg(FYI, "Calculated size %u length %u mismatch mid %llu\n",
- clc_len, 4 + len, mid);
+ if (srvr->vals->header_preamble_size + len != clc_len) {
+ cifs_dbg(FYI, "Calculated size %u length %zu mismatch mid %llu\n",
+ clc_len, srvr->vals->header_preamble_size + len, mid);
/* create failed on symlink */
if (command == SMB2_CREATE_HE &&
shdr->Status == STATUS_STOPPED_ON_SYMLINK)
return 0;
/* Windows 7 server returns 24 bytes more */
- if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
+ if (clc_len + 24 - srvr->vals->header_preamble_size == len && command == SMB2_OPLOCK_BREAK_HE)
return 0;
/* server can return one byte more due to implied bcc[0] */
- if (clc_len == 4 + len + 1)
+ if (clc_len == srvr->vals->header_preamble_size + len + 1)
return 0;
/*
@@ -218,10 +219,10 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
* Log the server error (once), but allow it and continue
* since the frame is parseable.
*/
- if (clc_len < 4 /* RFC1001 header size */ + len) {
+ if (clc_len < srvr->vals->header_preamble_size /* RFC1001 header size */ + len) {
printk_once(KERN_WARNING
- "SMB2 server sent bad RFC1001 len %d not %d\n",
- len, clc_len - 4);
+ "SMB2 server sent bad RFC1001 len %d not %zu\n",
+ len, clc_len - srvr->vals->header_preamble_size);
return 0;
}
@@ -706,3 +707,67 @@ smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server)
return 0;
}
+
+#ifdef CONFIG_CIFS_SMB311
+/**
+ * smb311_update_preauth_hash - update @ses hash with the packet data in @iov
+ *
+ * Assumes @iov does not contain the rfc1002 length and iov[0] has the
+ * SMB2 header.
+ */
+int
+smb311_update_preauth_hash(struct cifs_ses *ses, struct kvec *iov, int nvec)
+{
+ int i, rc;
+ struct sdesc *d;
+ struct smb2_sync_hdr *hdr;
+
+ if (ses->server->tcpStatus == CifsGood) {
+ /* skip non smb311 connections */
+ if (ses->server->dialect != SMB311_PROT_ID)
+ return 0;
+
+ /* skip last sess setup response */
+ hdr = (struct smb2_sync_hdr *)iov[0].iov_base;
+ if (hdr->Flags & SMB2_FLAGS_SIGNED)
+ return 0;
+ }
+
+ rc = smb311_crypto_shash_allocate(ses->server);
+ if (rc)
+ return rc;
+
+ d = ses->server->secmech.sdescsha512;
+ rc = crypto_shash_init(&d->shash);
+ if (rc) {
+ cifs_dbg(VFS, "%s: could not init sha512 shash\n", __func__);
+ return rc;
+ }
+
+ rc = crypto_shash_update(&d->shash, ses->preauth_sha_hash,
+ SMB2_PREAUTH_HASH_SIZE);
+ if (rc) {
+ cifs_dbg(VFS, "%s: could not update sha512 shash\n", __func__);
+ return rc;
+ }
+
+ for (i = 0; i < nvec; i++) {
+ rc = crypto_shash_update(&d->shash,
+ iov[i].iov_base, iov[i].iov_len);
+ if (rc) {
+ cifs_dbg(VFS, "%s: could not update sha512 shash\n",
+ __func__);
+ return rc;
+ }
+ }
+
+ rc = crypto_shash_final(&d->shash, ses->preauth_sha_hash);
+ if (rc) {
+ cifs_dbg(VFS, "%s: could not finalize sha512 shash\n",
+ __func__);
+ return rc;
+ }
+
+ return 0;
+}
+#endif
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index eb68e2fcc500..968b1d43a1ea 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -1412,7 +1412,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
} while (rc == -EAGAIN);
if (rc) {
- if (rc != -ENOENT)
+ if ((rc != -ENOENT) && (rc != -EOPNOTSUPP))
cifs_dbg(VFS, "ioctl error in smb2_get_dfs_refer rc=%d\n", rc);
goto out;
}
@@ -1457,6 +1457,8 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
unsigned int sub_offset;
unsigned int print_len;
unsigned int print_offset;
+ struct cifs_ses *ses = tcon->ses;
+ struct TCP_Server_Info *server = ses->server;
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
@@ -1479,7 +1481,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
}
if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) ||
- get_rfc1002_length(err_buf) + 4 < SMB2_SYMLINK_STRUCT_SIZE) {
+ get_rfc1002_length(err_buf) + server->vals->header_preamble_size < SMB2_SYMLINK_STRUCT_SIZE) {
kfree(utf16_path);
return -ENOENT;
}
@@ -1492,13 +1494,13 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
print_len = le16_to_cpu(symlink->PrintNameLength);
print_offset = le16_to_cpu(symlink->PrintNameOffset);
- if (get_rfc1002_length(err_buf) + 4 <
+ if (get_rfc1002_length(err_buf) + server->vals->header_preamble_size <
SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {
kfree(utf16_path);
return -ENOENT;
}
- if (get_rfc1002_length(err_buf) + 4 <
+ if (get_rfc1002_length(err_buf) + server->vals->header_preamble_size <
SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) {
kfree(utf16_path);
return -ENOENT;
@@ -2050,7 +2052,8 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile)
}
static void
-fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq)
+fill_transform_hdr(struct TCP_Server_Info *server,
+ struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq)
{
struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)old_rq->rq_iov[1].iov_base;
@@ -2062,10 +2065,19 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq)
tr_hdr->Flags = cpu_to_le16(0x01);
get_random_bytes(&tr_hdr->Nonce, SMB3_AES128CMM_NONCE);
memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8);
- inc_rfc1001_len(tr_hdr, sizeof(struct smb2_transform_hdr) - 4);
+ inc_rfc1001_len(tr_hdr, sizeof(struct smb2_transform_hdr) - server->vals->header_preamble_size);
inc_rfc1001_len(tr_hdr, orig_len);
}
+/* We can not use the normal sg_set_buf() as we will sometimes pass a
+ * stack object as buf.
+ */
+static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf,
+ unsigned int buflen)
+{
+ sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf));
+}
+
static struct scatterlist *
init_sg(struct smb_rqst *rqst, u8 *sign)
{
@@ -2080,16 +2092,16 @@ init_sg(struct smb_rqst *rqst, u8 *sign)
return NULL;
sg_init_table(sg, sg_len);
- sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len);
+ smb2_sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len);
for (i = 1; i < rqst->rq_nvec; i++)
- sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base,
+ smb2_sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base,
rqst->rq_iov[i].iov_len);
for (j = 0; i < sg_len - 1; i++, j++) {
unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz
: rqst->rq_tailsz;
sg_set_page(&sg[i], rqst->rq_pages[j], len, 0);
}
- sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE);
+ smb2_sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE);
return sg;
}
@@ -2125,7 +2137,7 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
{
struct smb2_transform_hdr *tr_hdr =
(struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base;
- unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
+ unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20 - server->vals->header_preamble_size;
int rc = 0;
struct scatterlist *sg;
u8 sign[SMB2_SIGNATURE_SIZE] = {};
@@ -2253,7 +2265,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
goto err_free_iov;
/* fill the 1st iov with a transform header */
- fill_transform_hdr(tr_hdr, old_rq);
+ fill_transform_hdr(server, tr_hdr, old_rq);
new_rq->rq_iov[0].iov_base = tr_hdr;
new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr);
@@ -2335,10 +2347,10 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
if (rc)
return rc;
- memmove(buf + 4, iov[1].iov_base, buf_data_size);
+ memmove(buf + server->vals->header_preamble_size, iov[1].iov_base, buf_data_size);
hdr = (struct smb2_hdr *)buf;
hdr->smb2_buf_length = cpu_to_be32(buf_data_size + page_data_size);
- server->total_read = buf_data_size + page_data_size + 4;
+ server->total_read = buf_data_size + page_data_size + server->vals->header_preamble_size;
return rc;
}
@@ -2442,7 +2454,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
return 0;
}
- data_offset = server->ops->read_data_offset(buf) + 4;
+ data_offset = server->ops->read_data_offset(buf) + server->vals->header_preamble_size;
#ifdef CONFIG_CIFS_SMB_DIRECT
use_rdma_mr = rdata->mr;
#endif
@@ -2538,11 +2550,12 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
unsigned int npages;
struct page **pages;
unsigned int len;
- unsigned int buflen = get_rfc1002_length(buf) + 4;
+ unsigned int buflen = get_rfc1002_length(buf) + server->vals->header_preamble_size;
int rc;
int i = 0;
- len = min_t(unsigned int, buflen, server->vals->read_rsp_size - 4 +
+ len = min_t(unsigned int, buflen, server->vals->read_rsp_size -
+ server->vals->header_preamble_size +
sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
rc = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, len);
@@ -2550,8 +2563,9 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
return rc;
server->total_read += rc;
- len = le32_to_cpu(tr_hdr->OriginalMessageSize) + 4 -
- server->vals->read_rsp_size;
+ len = le32_to_cpu(tr_hdr->OriginalMessageSize) +
+ server->vals->header_preamble_size -
+ server->vals->read_rsp_size;
npages = DIV_ROUND_UP(len, PAGE_SIZE);
pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
@@ -2577,7 +2591,8 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
if (rc)
goto free_pages;
- rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size - 4,
+ rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size -
+ server->vals->header_preamble_size,
pages, npages, len);
if (rc)
goto free_pages;
@@ -2614,7 +2629,7 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
struct mid_q_entry *mid_entry;
/* switch to large buffer if too big for a small one */
- if (pdu_length + 4 > MAX_CIFS_SMALL_BUFFER_SIZE) {
+ if (pdu_length + server->vals->header_preamble_size > MAX_CIFS_SMALL_BUFFER_SIZE) {
server->large_buf = true;
memcpy(server->bigbuf, buf, server->total_read);
buf = server->bigbuf;
@@ -2622,12 +2637,13 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
/* now read the rest */
length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
- pdu_length - HEADER_SIZE(server) + 1 + 4);
+ pdu_length - HEADER_SIZE(server) + 1 +
+ server->vals->header_preamble_size);
if (length < 0)
return length;
server->total_read += length;
- buf_size = pdu_length + 4 - sizeof(struct smb2_transform_hdr);
+ buf_size = pdu_length + server->vals->header_preamble_size - sizeof(struct smb2_transform_hdr);
length = decrypt_raw_data(server, buf, buf_size, NULL, 0, 0);
if (length)
return length;
@@ -2656,7 +2672,7 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
unsigned int orig_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
- if (pdu_length + 4 < sizeof(struct smb2_transform_hdr) +
+ if (pdu_length + server->vals->header_preamble_size < sizeof(struct smb2_transform_hdr) +
sizeof(struct smb2_sync_hdr)) {
cifs_dbg(VFS, "Transform message is too small (%u)\n",
pdu_length);
@@ -2665,14 +2681,14 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
return -ECONNABORTED;
}
- if (pdu_length + 4 < orig_len + sizeof(struct smb2_transform_hdr)) {
+ if (pdu_length + server->vals->header_preamble_size < orig_len + sizeof(struct smb2_transform_hdr)) {
cifs_dbg(VFS, "Transform message is broken\n");
cifs_reconnect(server);
wake_up(&server->response_q);
return -ECONNABORTED;
}
- if (pdu_length + 4 > CIFSMaxBufSize + MAX_HEADER_SIZE(server))
+ if (pdu_length + server->vals->header_preamble_size > CIFSMaxBufSize + MAX_HEADER_SIZE(server))
return receive_encrypted_read(server, mid);
return receive_encrypted_standard(server, mid);
@@ -2683,7 +2699,8 @@ smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
- return handle_read_data(server, mid, buf, get_rfc1002_length(buf) + 4,
+ return handle_read_data(server, mid, buf, get_rfc1002_length(buf) +
+ server->vals->header_preamble_size,
NULL, 0, 0);
}
@@ -3088,6 +3105,7 @@ struct smb_version_values smb20_values = {
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
.header_size = sizeof(struct smb2_hdr),
+ .header_preamble_size = 4,
.max_header_size = MAX_SMB2_HDR_SIZE,
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
.lock_cmd = SMB2_LOCK,
@@ -3108,6 +3126,7 @@ struct smb_version_values smb21_values = {
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
.header_size = sizeof(struct smb2_hdr),
+ .header_preamble_size = 4,
.max_header_size = MAX_SMB2_HDR_SIZE,
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
.lock_cmd = SMB2_LOCK,
@@ -3128,6 +3147,7 @@ struct smb_version_values smb3any_values = {
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
.header_size = sizeof(struct smb2_hdr),
+ .header_preamble_size = 4,
.max_header_size = MAX_SMB2_HDR_SIZE,
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
.lock_cmd = SMB2_LOCK,
@@ -3148,6 +3168,7 @@ struct smb_version_values smbdefault_values = {
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
.header_size = sizeof(struct smb2_hdr),
+ .header_preamble_size = 4,
.max_header_size = MAX_SMB2_HDR_SIZE,
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
.lock_cmd = SMB2_LOCK,
@@ -3168,6 +3189,7 @@ struct smb_version_values smb30_values = {
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
.header_size = sizeof(struct smb2_hdr),
+ .header_preamble_size = 4,
.max_header_size = MAX_SMB2_HDR_SIZE,
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
.lock_cmd = SMB2_LOCK,
@@ -3188,6 +3210,7 @@ struct smb_version_values smb302_values = {
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
.header_size = sizeof(struct smb2_hdr),
+ .header_preamble_size = 4,
.max_header_size = MAX_SMB2_HDR_SIZE,
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
.lock_cmd = SMB2_LOCK,
@@ -3209,6 +3232,7 @@ struct smb_version_values smb311_values = {
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
.header_size = sizeof(struct smb2_hdr),
+ .header_preamble_size = 4,
.max_header_size = MAX_SMB2_HDR_SIZE,
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
.lock_cmd = SMB2_LOCK,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 63778ac22fd9..f7741cee2a4c 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -453,6 +453,10 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
return rc;
req->sync_hdr.SessionId = 0;
+#ifdef CONFIG_CIFS_SMB311
+ memset(server->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE);
+ memset(ses->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE);
+#endif
if (strcmp(ses->server->vals->version_string,
SMB3ANY_VERSION_STRING) == 0) {
@@ -564,6 +568,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
/* BB: add check that dialect was valid given dialect(s) we asked for */
+#ifdef CONFIG_CIFS_SMB311
+ /*
+ * Keep a copy of the hash after negprot. This hash will be
+ * the starting hash value for all sessions made from this
+ * server.
+ */
+ memcpy(server->preauth_sha_hash, ses->preauth_sha_hash,
+ SMB2_PREAUTH_HASH_SIZE);
+#endif
/* SMB2 only has an extended negflavor */
server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
/* set it to the maximum buffer size value we can send with 1 credit */
@@ -571,8 +584,10 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
SMB2_MAX_BUFFER_SIZE);
server->max_read = le32_to_cpu(rsp->MaxReadSize);
server->max_write = le32_to_cpu(rsp->MaxWriteSize);
- /* BB Do we need to validate the SecurityMode? */
server->sec_mode = le16_to_cpu(rsp->SecurityMode);
+ if ((server->sec_mode & SMB2_SEC_MODE_FLAGS_ALL) != server->sec_mode)
+ cifs_dbg(FYI, "Server returned unexpected security mode 0x%x\n",
+ server->sec_mode);
server->capabilities = le32_to_cpu(rsp->Capabilities);
/* Internal types */
server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES;
@@ -621,6 +636,10 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
return 0;
#endif
+ /* In SMB3.11 preauth integrity supersedes validate negotiate */
+ if (tcon->ses->server->dialect == SMB311_PROT_ID)
+ return 0;
+
/*
* validation ioctl must be signed, so no point sending this if we
* can not sign it (ie are not known user). Even if signing is not
@@ -1148,6 +1167,14 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
sess_data->buf0_type = CIFS_NO_BUFFER;
sess_data->nls_cp = (struct nls_table *) nls_cp;
+#ifdef CONFIG_CIFS_SMB311
+ /*
+ * Initialize the session hash with the server one.
+ */
+ memcpy(ses->preauth_sha_hash, ses->server->preauth_sha_hash,
+ SMB2_PREAUTH_HASH_SIZE);
+#endif
+
while (sess_data->func)
sess_data->func(sess_data);
@@ -1280,6 +1307,11 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
iov[1].iov_base = unc_path;
iov[1].iov_len = unc_path_len;
+ /* 3.11 tcon req must be signed if not encrypted. See MS-SMB2 3.2.4.1.1 */
+ if ((ses->server->dialect == SMB311_PROT_ID) &&
+ !encryption_required(tcon))
+ req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED;
+
rc = smb2_send_recv(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov);
cifs_small_buf_release(req);
rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base;
@@ -1441,7 +1473,7 @@ parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp,
unsigned int remaining;
char *name;
- data_offset = (char *)rsp + 4 + le32_to_cpu(rsp->CreateContextsOffset);
+ data_offset = (char *)rsp + server->vals->header_preamble_size + le32_to_cpu(rsp->CreateContextsOffset);
remaining = le32_to_cpu(rsp->CreateContextsLength);
cc = (struct create_context *)data_offset;
while (remaining >= sizeof(struct create_context)) {
@@ -1738,8 +1770,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
rc = alloc_path_with_tree_prefix(&copy_path, &copy_size,
&name_len,
tcon->treeName, path);
- if (rc)
+ if (rc) {
+ cifs_small_buf_release(req);
return rc;
+ }
req->NameLength = cpu_to_le16(name_len * 2);
uni_path_len = copy_size;
path = copy_path;
@@ -1750,8 +1784,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
if (uni_path_len % 8 != 0) {
copy_size = roundup(uni_path_len, 8);
copy_path = kzalloc(copy_size, GFP_KERNEL);
- if (!copy_path)
+ if (!copy_path) {
+ cifs_small_buf_release(req);
return -ENOMEM;
+ }
memcpy((char *)copy_path, (const char *)path,
uni_path_len);
uni_path_len = copy_size;
@@ -3418,6 +3454,7 @@ static int
build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
int outbuf_len, u64 persistent_fid, u64 volatile_fid)
{
+ struct TCP_Server_Info *server = tcon->ses->server;
int rc;
struct smb2_query_info_req *req;
unsigned int total_len;
@@ -3440,7 +3477,7 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
req->InputBufferOffset =
cpu_to_le16(sizeof(struct smb2_query_info_req) - 1);
req->OutputBufferLength = cpu_to_le32(
- outbuf_len + sizeof(struct smb2_query_info_rsp) - 1 - 4);
+ outbuf_len + sizeof(struct smb2_query_info_rsp) - 1 - server->vals->header_preamble_size);
iov->iov_base = (char *)req;
iov->iov_len = total_len;
@@ -3457,6 +3494,7 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
int resp_buftype;
struct cifs_ses *ses = tcon->ses;
+ struct TCP_Server_Info *server = ses->server;
struct smb2_fs_full_size_info *info = NULL;
int flags = 0;
@@ -3477,7 +3515,7 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
}
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
- info = (struct smb2_fs_full_size_info *)(4 /* RFC1001 len */ +
+ info = (struct smb2_fs_full_size_info *)(server->vals->header_preamble_size +
le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr);
rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset),
le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr,
@@ -3500,6 +3538,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
int resp_buftype, max_len, min_len;
struct cifs_ses *ses = tcon->ses;
+ struct TCP_Server_Info *server = ses->server;
unsigned int rsp_len, offset;
int flags = 0;
@@ -3540,15 +3579,15 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
goto qfsattr_exit;
if (level == FS_ATTRIBUTE_INFORMATION)
- memcpy(&tcon->fsAttrInfo, 4 /* RFC1001 len */ + offset
+ memcpy(&tcon->fsAttrInfo, server->vals->header_preamble_size + offset
+ (char *)&rsp->hdr, min_t(unsigned int,
rsp_len, max_len));
else if (level == FS_DEVICE_INFORMATION)
- memcpy(&tcon->fsDevInfo, 4 /* RFC1001 len */ + offset
+ memcpy(&tcon->fsDevInfo, server->vals->header_preamble_size + offset
+ (char *)&rsp->hdr, sizeof(FILE_SYSTEM_DEVICE_INFO));
else if (level == FS_SECTOR_SIZE_INFORMATION) {
struct smb3_fs_ss_info *ss_info = (struct smb3_fs_ss_info *)
- (4 /* RFC1001 len */ + offset + (char *)&rsp->hdr);
+ (server->vals->header_preamble_size + offset + (char *)&rsp->hdr);
tcon->ss_flags = le32_to_cpu(ss_info->Flags);
tcon->perf_sector_size =
le32_to_cpu(ss_info->PhysicalBytesPerSectorForPerf);
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 2a2b34ccaf49..253e2c7c952f 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -249,6 +249,8 @@ struct smb2_negotiate_req {
/* SecurityMode flags */
#define SMB2_NEGOTIATE_SIGNING_ENABLED 0x0001
#define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x0002
+#define SMB2_SEC_MODE_FLAGS_ALL 0x0003
+
/* Capabilities flags */
#define SMB2_GLOBAL_CAP_DFS 0x00000001
#define SMB2_GLOBAL_CAP_LEASING 0x00000002 /* Resp only New to SMB2.1 */
@@ -264,6 +266,7 @@ struct smb2_negotiate_req {
#define SMB311_SALT_SIZE 32
/* Hash Algorithm Types */
#define SMB2_PREAUTH_INTEGRITY_SHA512 cpu_to_le16(0x0001)
+#define SMB2_PREAUTH_HASH_SIZE 64
struct smb2_preauth_neg_context {
__le16 ContextType; /* 1 */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 05287b01f596..cbcce3f7e86f 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -202,4 +202,9 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *);
extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
enum securityEnum);
+#ifdef CONFIG_CIFS_SMB311
+extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server);
+extern int smb311_update_preauth_hash(struct cifs_ses *ses,
+ struct kvec *iov, int nvec);
+#endif
#endif /* _SMB2PROTO_H */
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 99493946e2f9..bf49cb73b9e6 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -43,77 +43,62 @@
static int
smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
{
- int rc;
- unsigned int size;
+ return cifs_alloc_hash("hmac(sha256)",
+ &server->secmech.hmacsha256,
+ &server->secmech.sdeschmacsha256);
+}
- if (server->secmech.sdeschmacsha256 != NULL)
- return 0; /* already allocated */
+static int
+smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
+{
+ struct cifs_secmech *p = &server->secmech;
+ int rc;
- server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
- if (IS_ERR(server->secmech.hmacsha256)) {
- cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
- rc = PTR_ERR(server->secmech.hmacsha256);
- server->secmech.hmacsha256 = NULL;
- return rc;
- }
+ rc = cifs_alloc_hash("hmac(sha256)",
+ &p->hmacsha256,
+ &p->sdeschmacsha256);
+ if (rc)
+ goto err;
- size = sizeof(struct shash_desc) +
- crypto_shash_descsize(server->secmech.hmacsha256);
- server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
- if (!server->secmech.sdeschmacsha256) {
- crypto_free_shash(server->secmech.hmacsha256);
- server->secmech.hmacsha256 = NULL;
- return -ENOMEM;
- }
- server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
- server->secmech.sdeschmacsha256->shash.flags = 0x0;
+ rc = cifs_alloc_hash("cmac(aes)", &p->cmacaes, &p->sdesccmacaes);
+ if (rc)
+ goto err;
return 0;
+err:
+ cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256);
+ return rc;
}
-static int
-smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
+#ifdef CONFIG_CIFS_SMB311
+int
+smb311_crypto_shash_allocate(struct TCP_Server_Info *server)
{
- unsigned int size;
- int rc;
-
- if (server->secmech.sdesccmacaes != NULL)
- return 0; /* already allocated */
+ struct cifs_secmech *p = &server->secmech;
+ int rc = 0;
- rc = smb2_crypto_shash_allocate(server);
+ rc = cifs_alloc_hash("hmac(sha256)",
+ &p->hmacsha256,
+ &p->sdeschmacsha256);
if (rc)
return rc;
- server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
- if (IS_ERR(server->secmech.cmacaes)) {
- cifs_dbg(VFS, "could not allocate crypto cmac-aes");
- kfree(server->secmech.sdeschmacsha256);
- server->secmech.sdeschmacsha256 = NULL;
- crypto_free_shash(server->secmech.hmacsha256);
- server->secmech.hmacsha256 = NULL;
- rc = PTR_ERR(server->secmech.cmacaes);
- server->secmech.cmacaes = NULL;
- return rc;
- }
+ rc = cifs_alloc_hash("cmac(aes)", &p->cmacaes, &p->sdesccmacaes);
+ if (rc)
+ goto err;
- size = sizeof(struct shash_desc) +
- crypto_shash_descsize(server->secmech.cmacaes);
- server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
- if (!server->secmech.sdesccmacaes) {
- cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
- kfree(server->secmech.sdeschmacsha256);
- server->secmech.sdeschmacsha256 = NULL;
- crypto_free_shash(server->secmech.hmacsha256);
- crypto_free_shash(server->secmech.cmacaes);
- server->secmech.hmacsha256 = NULL;
- server->secmech.cmacaes = NULL;
- return -ENOMEM;
- }
- server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
- server->secmech.sdesccmacaes->shash.flags = 0x0;
+ rc = cifs_alloc_hash("sha512", &p->sha512, &p->sdescsha512);
+ if (rc)
+ goto err;
return 0;
+
+err:
+ cifs_free_hash(&p->cmacaes, &p->sdesccmacaes);
+ cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256);
+ return rc;
}
+#endif
static struct cifs_ses *
smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
@@ -457,7 +442,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
return rc;
}
-
+
rc = __cifs_calc_signature(rqst, server, sigptr,
&server->secmech.sdesccmacaes->shash);
diff --git a/fs/cifs/smbdirect.c b/fs/cifs/smbdirect.c
index 91710eb571fb..5008af546dd1 100644
--- a/fs/cifs/smbdirect.c
+++ b/fs/cifs/smbdirect.c
@@ -862,6 +862,8 @@ static int smbd_post_send_negotiate_req(struct smbd_connection *info)
ib_dma_unmap_single(info->id->device, request->sge[0].addr,
request->sge[0].length, DMA_TO_DEVICE);
+ smbd_disconnect_rdma_connection(info);
+
dma_mapping_failed:
mempool_free(request, info->request_mempool);
return rc;
@@ -1025,7 +1027,7 @@ static int smbd_post_send(struct smbd_connection *info,
for (i = 0; i < request->num_sge; i++) {
log_rdma_send(INFO,
- "rdma_request sge[%d] addr=%llu legnth=%u\n",
+ "rdma_request sge[%d] addr=%llu length=%u\n",
i, request->sge[0].addr, request->sge[0].length);
ib_dma_sync_single_for_device(
info->id->device,
@@ -1061,6 +1063,7 @@ static int smbd_post_send(struct smbd_connection *info,
if (atomic_dec_and_test(&info->send_pending))
wake_up(&info->wait_send_pending);
}
+ smbd_disconnect_rdma_connection(info);
} else
/* Reset timer for idle connection after packet is sent */
mod_delayed_work(info->workqueue, &info->idle_timer_work,
@@ -1202,7 +1205,7 @@ static int smbd_post_recv(
if (rc) {
ib_dma_unmap_single(info->id->device, response->sge.addr,
response->sge.length, DMA_FROM_DEVICE);
-
+ smbd_disconnect_rdma_connection(info);
log_rdma_recv(ERR, "ib_post_recv failed rc=%d\n", rc);
}
@@ -1498,8 +1501,8 @@ int smbd_reconnect(struct TCP_Server_Info *server)
log_rdma_event(INFO, "reconnecting rdma session\n");
if (!server->smbd_conn) {
- log_rdma_event(ERR, "rdma session already destroyed\n");
- return -EINVAL;
+ log_rdma_event(INFO, "rdma session already destroyed\n");
+ goto create_conn;
}
/*
@@ -1512,15 +1515,19 @@ int smbd_reconnect(struct TCP_Server_Info *server)
}
/* wait until the transport is destroyed */
- wait_event(server->smbd_conn->wait_destroy,
- server->smbd_conn->transport_status == SMBD_DESTROYED);
+ if (!wait_event_timeout(server->smbd_conn->wait_destroy,
+ server->smbd_conn->transport_status == SMBD_DESTROYED, 5*HZ))
+ return -EAGAIN;
destroy_workqueue(server->smbd_conn->workqueue);
kfree(server->smbd_conn);
+create_conn:
log_rdma_event(INFO, "creating rdma session\n");
server->smbd_conn = smbd_get_connection(
server, (struct sockaddr *) &server->dstaddr);
+ log_rdma_event(INFO, "created rdma session info=%p\n",
+ server->smbd_conn);
return server->smbd_conn ? 0 : -ENOENT;
}
@@ -2295,7 +2302,7 @@ static void smbd_mr_recovery_work(struct work_struct *work)
rc = ib_dereg_mr(smbdirect_mr->mr);
if (rc) {
log_rdma_mr(ERR,
- "ib_dereg_mr faield rc=%x\n",
+ "ib_dereg_mr failed rc=%x\n",
rc);
smbd_disconnect_rdma_connection(info);
}
@@ -2542,6 +2549,8 @@ dma_map_error:
if (atomic_dec_and_test(&info->mr_used_count))
wake_up(&info->wait_for_mr_cleanup);
+ smbd_disconnect_rdma_connection(info);
+
return NULL;
}
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
index c12bffefa3c9..a0b80ac651a6 100644
--- a/fs/cifs/smbencrypt.c
+++ b/fs/cifs/smbencrypt.c
@@ -121,25 +121,12 @@ int
mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len)
{
int rc;
- unsigned int size;
- struct crypto_shash *md4;
- struct sdesc *sdescmd4;
-
- md4 = crypto_alloc_shash("md4", 0, 0);
- if (IS_ERR(md4)) {
- rc = PTR_ERR(md4);
- cifs_dbg(VFS, "%s: Crypto md4 allocation error %d\n",
- __func__, rc);
- return rc;
- }
- size = sizeof(struct shash_desc) + crypto_shash_descsize(md4);
- sdescmd4 = kmalloc(size, GFP_KERNEL);
- if (!sdescmd4) {
- rc = -ENOMEM;
+ struct crypto_shash *md4 = NULL;
+ struct sdesc *sdescmd4 = NULL;
+
+ rc = cifs_alloc_hash("md4", &md4, &sdescmd4);
+ if (rc)
goto mdfour_err;
- }
- sdescmd4->shash.tfm = md4;
- sdescmd4->shash.flags = 0x0;
rc = crypto_shash_init(&sdescmd4->shash);
if (rc) {
@@ -156,9 +143,7 @@ mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len)
cifs_dbg(VFS, "%s: Could not generate md4 hash\n", __func__);
mdfour_err:
- crypto_free_shash(md4);
- kfree(sdescmd4);
-
+ cifs_free_hash(&md4, &sdescmd4);
return rc;
}
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 9779b3292d8e..279718dcb2ed 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -37,6 +37,7 @@
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
+#include "smb2proto.h"
#include "smbdirect.h"
/* Max number of iovectors we can use off the stack when sending requests. */
@@ -751,6 +752,12 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
if (rc < 0)
goto out;
+#ifdef CONFIG_CIFS_SMB311
+ if (ses->status == CifsNew)
+ smb311_update_preauth_hash(ses, rqst->rq_iov+1,
+ rqst->rq_nvec-1);
+#endif
+
if (timeout == CIFS_ASYNC_OP)
goto out;
@@ -783,12 +790,23 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
buf = (char *)midQ->resp_buf;
resp_iov->iov_base = buf;
- resp_iov->iov_len = get_rfc1002_length(buf) + 4;
+ resp_iov->iov_len = get_rfc1002_length(buf) +
+ ses->server->vals->header_preamble_size;
if (midQ->large_buf)
*resp_buf_type = CIFS_LARGE_BUFFER;
else
*resp_buf_type = CIFS_SMALL_BUFFER;
+#ifdef CONFIG_CIFS_SMB311
+ if (ses->status == CifsNew) {
+ struct kvec iov = {
+ .iov_base = buf + 4,
+ .iov_len = get_rfc1002_length(buf)
+ };
+ smb311_update_preauth_hash(ses, &iov, 1);
+ }
+#endif
+
credits = ses->server->ops->get_credits(midQ);
rc = ses->server->ops->check_receive(midQ, ses->server,
diff --git a/fs/d_path.c b/fs/d_path.c
new file mode 100644
index 000000000000..e8fce6b1174f
--- /dev/null
+++ b/fs/d_path.c
@@ -0,0 +1,470 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/syscalls.h>
+#include <linux/export.h>
+#include <linux/uaccess.h>
+#include <linux/fs_struct.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/prefetch.h>
+#include "mount.h"
+
+static int prepend(char **buffer, int *buflen, const char *str, int namelen)
+{
+ *buflen -= namelen;
+ if (*buflen < 0)
+ return -ENAMETOOLONG;
+ *buffer -= namelen;
+ memcpy(*buffer, str, namelen);
+ return 0;
+}
+
+/**
+ * prepend_name - prepend a pathname in front of current buffer pointer
+ * @buffer: buffer pointer
+ * @buflen: allocated length of the buffer
+ * @name: name string and length qstr structure
+ *
+ * With RCU path tracing, it may race with d_move(). Use READ_ONCE() to
+ * make sure that either the old or the new name pointer and length are
+ * fetched. However, there may be mismatch between length and pointer.
+ * The length cannot be trusted, we need to copy it byte-by-byte until
+ * the length is reached or a null byte is found. It also prepends "/" at
+ * the beginning of the name. The sequence number check at the caller will
+ * retry it again when a d_move() does happen. So any garbage in the buffer
+ * due to mismatched pointer and length will be discarded.
+ *
+ * Load acquire is needed to make sure that we see that terminating NUL.
+ */
+static int prepend_name(char **buffer, int *buflen, const struct qstr *name)
+{
+ const char *dname = smp_load_acquire(&name->name); /* ^^^ */
+ u32 dlen = READ_ONCE(name->len);
+ char *p;
+
+ *buflen -= dlen + 1;
+ if (*buflen < 0)
+ return -ENAMETOOLONG;
+ p = *buffer -= dlen + 1;
+ *p++ = '/';
+ while (dlen--) {
+ char c = *dname++;
+ if (!c)
+ break;
+ *p++ = c;
+ }
+ return 0;
+}
+
+/**
+ * prepend_path - Prepend path string to a buffer
+ * @path: the dentry/vfsmount to report
+ * @root: root vfsmnt/dentry
+ * @buffer: pointer to the end of the buffer
+ * @buflen: pointer to buffer length
+ *
+ * The function will first try to write out the pathname without taking any
+ * lock other than the RCU read lock to make sure that dentries won't go away.
+ * It only checks the sequence number of the global rename_lock as any change
+ * in the dentry's d_seq will be preceded by changes in the rename_lock
+ * sequence number. If the sequence number had been changed, it will restart
+ * the whole pathname back-tracing sequence again by taking the rename_lock.
+ * In this case, there is no need to take the RCU read lock as the recursive
+ * parent pointer references will keep the dentry chain alive as long as no
+ * rename operation is performed.
+ */
+static int prepend_path(const struct path *path,
+ const struct path *root,
+ char **buffer, int *buflen)
+{
+ struct dentry *dentry;
+ struct vfsmount *vfsmnt;
+ struct mount *mnt;
+ int error = 0;
+ unsigned seq, m_seq = 0;
+ char *bptr;
+ int blen;
+
+ rcu_read_lock();
+restart_mnt:
+ read_seqbegin_or_lock(&mount_lock, &m_seq);
+ seq = 0;
+ rcu_read_lock();
+restart:
+ bptr = *buffer;
+ blen = *buflen;
+ error = 0;
+ dentry = path->dentry;
+ vfsmnt = path->mnt;
+ mnt = real_mount(vfsmnt);
+ read_seqbegin_or_lock(&rename_lock, &seq);
+ while (dentry != root->dentry || vfsmnt != root->mnt) {
+ struct dentry * parent;
+
+ if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
+ struct mount *parent = READ_ONCE(mnt->mnt_parent);
+ /* Escaped? */
+ if (dentry != vfsmnt->mnt_root) {
+ bptr = *buffer;
+ blen = *buflen;
+ error = 3;
+ break;
+ }
+ /* Global root? */
+ if (mnt != parent) {
+ dentry = READ_ONCE(mnt->mnt_mountpoint);
+ mnt = parent;
+ vfsmnt = &mnt->mnt;
+ continue;
+ }
+ if (!error)
+ error = is_mounted(vfsmnt) ? 1 : 2;
+ break;
+ }
+ parent = dentry->d_parent;
+ prefetch(parent);
+ error = prepend_name(&bptr, &blen, &dentry->d_name);
+ if (error)
+ break;
+
+ dentry = parent;
+ }
+ if (!(seq & 1))
+ rcu_read_unlock();
+ if (need_seqretry(&rename_lock, seq)) {
+ seq = 1;
+ goto restart;
+ }
+ done_seqretry(&rename_lock, seq);
+
+ if (!(m_seq & 1))
+ rcu_read_unlock();
+ if (need_seqretry(&mount_lock, m_seq)) {
+ m_seq = 1;
+ goto restart_mnt;
+ }
+ done_seqretry(&mount_lock, m_seq);
+
+ if (error >= 0 && bptr == *buffer) {
+ if (--blen < 0)
+ error = -ENAMETOOLONG;
+ else
+ *--bptr = '/';
+ }
+ *buffer = bptr;
+ *buflen = blen;
+ return error;
+}
+
+/**
+ * __d_path - return the path of a dentry
+ * @path: the dentry/vfsmount to report
+ * @root: root vfsmnt/dentry
+ * @buf: buffer to return value in
+ * @buflen: buffer length
+ *
+ * Convert a dentry into an ASCII path name.
+ *
+ * Returns a pointer into the buffer or an error code if the
+ * path was too long.
+ *
+ * "buflen" should be positive.
+ *
+ * If the path is not reachable from the supplied root, return %NULL.
+ */
+char *__d_path(const struct path *path,
+ const struct path *root,
+ char *buf, int buflen)
+{
+ char *res = buf + buflen;
+ int error;
+
+ prepend(&res, &buflen, "\0", 1);
+ error = prepend_path(path, root, &res, &buflen);
+
+ if (error < 0)
+ return ERR_PTR(error);
+ if (error > 0)
+ return NULL;
+ return res;
+}
+
+char *d_absolute_path(const struct path *path,
+ char *buf, int buflen)
+{
+ struct path root = {};
+ char *res = buf + buflen;
+ int error;
+
+ prepend(&res, &buflen, "\0", 1);
+ error = prepend_path(path, &root, &res, &buflen);
+
+ if (error > 1)
+ error = -EINVAL;
+ if (error < 0)
+ return ERR_PTR(error);
+ return res;
+}
+
+/*
+ * same as __d_path but appends "(deleted)" for unlinked files.
+ */
+static int path_with_deleted(const struct path *path,
+ const struct path *root,
+ char **buf, int *buflen)
+{
+ prepend(buf, buflen, "\0", 1);
+ if (d_unlinked(path->dentry)) {
+ int error = prepend(buf, buflen, " (deleted)", 10);
+ if (error)
+ return error;
+ }
+
+ return prepend_path(path, root, buf, buflen);
+}
+
+static int prepend_unreachable(char **buffer, int *buflen)
+{
+ return prepend(buffer, buflen, "(unreachable)", 13);
+}
+
+static void get_fs_root_rcu(struct fs_struct *fs, struct path *root)
+{
+ unsigned seq;
+
+ do {
+ seq = read_seqcount_begin(&fs->seq);
+ *root = fs->root;
+ } while (read_seqcount_retry(&fs->seq, seq));
+}
+
+/**
+ * d_path - return the path of a dentry
+ * @path: path to report
+ * @buf: buffer to return value in
+ * @buflen: buffer length
+ *
+ * Convert a dentry into an ASCII path name. If the entry has been deleted
+ * the string " (deleted)" is appended. Note that this is ambiguous.
+ *
+ * Returns a pointer into the buffer or an error code if the path was
+ * too long. Note: Callers should use the returned pointer, not the passed
+ * in buffer, to use the name! The implementation often starts at an offset
+ * into the buffer, and may leave 0 bytes at the start.
+ *
+ * "buflen" should be positive.
+ */
+char *d_path(const struct path *path, char *buf, int buflen)
+{
+ char *res = buf + buflen;
+ struct path root;
+ int error;
+
+ /*
+ * We have various synthetic filesystems that never get mounted. On
+ * these filesystems dentries are never used for lookup purposes, and
+ * thus don't need to be hashed. They also don't need a name until a
+ * user wants to identify the object in /proc/pid/fd/. The little hack
+ * below allows us to generate a name for these objects on demand:
+ *
+ * Some pseudo inodes are mountable. When they are mounted
+ * path->dentry == path->mnt->mnt_root. In that case don't call d_dname
+ * and instead have d_path return the mounted path.
+ */
+ if (path->dentry->d_op && path->dentry->d_op->d_dname &&
+ (!IS_ROOT(path->dentry) || path->dentry != path->mnt->mnt_root))
+ return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
+
+ rcu_read_lock();
+ get_fs_root_rcu(current->fs, &root);
+ error = path_with_deleted(path, &root, &res, &buflen);
+ rcu_read_unlock();
+
+ if (error < 0)
+ res = ERR_PTR(error);
+ return res;
+}
+EXPORT_SYMBOL(d_path);
+
+/*
+ * Helper function for dentry_operations.d_dname() members
+ */
+char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen,
+ const char *fmt, ...)
+{
+ va_list args;
+ char temp[64];
+ int sz;
+
+ va_start(args, fmt);
+ sz = vsnprintf(temp, sizeof(temp), fmt, args) + 1;
+ va_end(args);
+
+ if (sz > sizeof(temp) || sz > buflen)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ buffer += buflen - sz;
+ return memcpy(buffer, temp, sz);
+}
+
+char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
+{
+ char *end = buffer + buflen;
+ /* these dentries are never renamed, so d_lock is not needed */
+ if (prepend(&end, &buflen, " (deleted)", 11) ||
+ prepend(&end, &buflen, dentry->d_name.name, dentry->d_name.len) ||
+ prepend(&end, &buflen, "/", 1))
+ end = ERR_PTR(-ENAMETOOLONG);
+ return end;
+}
+EXPORT_SYMBOL(simple_dname);
+
+/*
+ * Write full pathname from the root of the filesystem into the buffer.
+ */
+static char *__dentry_path(struct dentry *d, char *buf, int buflen)
+{
+ struct dentry *dentry;
+ char *end, *retval;
+ int len, seq = 0;
+ int error = 0;
+
+ if (buflen < 2)
+ goto Elong;
+
+ rcu_read_lock();
+restart:
+ dentry = d;
+ end = buf + buflen;
+ len = buflen;
+ prepend(&end, &len, "\0", 1);
+ /* Get '/' right */
+ retval = end-1;
+ *retval = '/';
+ read_seqbegin_or_lock(&rename_lock, &seq);
+ while (!IS_ROOT(dentry)) {
+ struct dentry *parent = dentry->d_parent;
+
+ prefetch(parent);
+ error = prepend_name(&end, &len, &dentry->d_name);
+ if (error)
+ break;
+
+ retval = end;
+ dentry = parent;
+ }
+ if (!(seq & 1))
+ rcu_read_unlock();
+ if (need_seqretry(&rename_lock, seq)) {
+ seq = 1;
+ goto restart;
+ }
+ done_seqretry(&rename_lock, seq);
+ if (error)
+ goto Elong;
+ return retval;
+Elong:
+ return ERR_PTR(-ENAMETOOLONG);
+}
+
+char *dentry_path_raw(struct dentry *dentry, char *buf, int buflen)
+{
+ return __dentry_path(dentry, buf, buflen);
+}
+EXPORT_SYMBOL(dentry_path_raw);
+
+char *dentry_path(struct dentry *dentry, char *buf, int buflen)
+{
+ char *p = NULL;
+ char *retval;
+
+ if (d_unlinked(dentry)) {
+ p = buf + buflen;
+ if (prepend(&p, &buflen, "//deleted", 10) != 0)
+ goto Elong;
+ buflen++;
+ }
+ retval = __dentry_path(dentry, buf, buflen);
+ if (!IS_ERR(retval) && p)
+ *p = '/'; /* restore '/' overriden with '\0' */
+ return retval;
+Elong:
+ return ERR_PTR(-ENAMETOOLONG);
+}
+
+static void get_fs_root_and_pwd_rcu(struct fs_struct *fs, struct path *root,
+ struct path *pwd)
+{
+ unsigned seq;
+
+ do {
+ seq = read_seqcount_begin(&fs->seq);
+ *root = fs->root;
+ *pwd = fs->pwd;
+ } while (read_seqcount_retry(&fs->seq, seq));
+}
+
+/*
+ * NOTE! The user-level library version returns a
+ * character pointer. The kernel system call just
+ * returns the length of the buffer filled (which
+ * includes the ending '\0' character), or a negative
+ * error value. So libc would do something like
+ *
+ * char *getcwd(char * buf, size_t size)
+ * {
+ * int retval;
+ *
+ * retval = sys_getcwd(buf, size);
+ * if (retval >= 0)
+ * return buf;
+ * errno = -retval;
+ * return NULL;
+ * }
+ */
+SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
+{
+ int error;
+ struct path pwd, root;
+ char *page = __getname();
+
+ if (!page)
+ return -ENOMEM;
+
+ rcu_read_lock();
+ get_fs_root_and_pwd_rcu(current->fs, &root, &pwd);
+
+ error = -ENOENT;
+ if (!d_unlinked(pwd.dentry)) {
+ unsigned long len;
+ char *cwd = page + PATH_MAX;
+ int buflen = PATH_MAX;
+
+ prepend(&cwd, &buflen, "\0", 1);
+ error = prepend_path(&pwd, &root, &cwd, &buflen);
+ rcu_read_unlock();
+
+ if (error < 0)
+ goto out;
+
+ /* Unreachable from current root */
+ if (error > 0) {
+ error = prepend_unreachable(&cwd, &buflen);
+ if (error)
+ goto out;
+ }
+
+ error = -ERANGE;
+ len = PATH_MAX + page - cwd;
+ if (len <= size) {
+ error = len;
+ if (copy_to_user(buf, cwd, len))
+ error = -EFAULT;
+ }
+ } else {
+ rcu_read_unlock();
+ }
+
+out:
+ __putname(page);
+ return error;
+}
diff --git a/fs/dcache.c b/fs/dcache.c
index 8945e6cabd93..593079176123 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -14,7 +14,7 @@
* the dcache entry is deleted or garbage collected.
*/
-#include <linux/syscalls.h>
+#include <linux/ratelimit.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/fs.h>
@@ -24,18 +24,11 @@
#include <linux/hash.h>
#include <linux/cache.h>
#include <linux/export.h>
-#include <linux/mount.h>
-#include <linux/file.h>
-#include <linux/uaccess.h>
#include <linux/security.h>
#include <linux/seqlock.h>
-#include <linux/swap.h>
#include <linux/bootmem.h>
-#include <linux/fs_struct.h>
#include <linux/bit_spinlock.h>
#include <linux/rculist_bl.h>
-#include <linux/prefetch.h>
-#include <linux/ratelimit.h>
#include <linux/list_lru.h>
#include "internal.h"
#include "mount.h"
@@ -74,9 +67,7 @@
* dentry->d_lock
*
* If no ancestor relationship:
- * if (dentry1 < dentry2)
- * dentry1->d_lock
- * dentry2->d_lock
+ * arbitrary, since it's serialized on rename_lock
*/
int sysctl_vfs_cache_pressure __read_mostly = 100;
EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
@@ -440,17 +431,6 @@ static void d_lru_shrink_move(struct list_lru_one *lru, struct dentry *dentry,
list_lru_isolate_move(lru, &dentry->d_lru, list);
}
-/*
- * dentry_lru_(add|del)_list) must be called with d_lock held.
- */
-static void dentry_lru_add(struct dentry *dentry)
-{
- if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST)))
- d_lru_add(dentry);
- else if (unlikely(!(dentry->d_flags & DCACHE_REFERENCED)))
- dentry->d_flags |= DCACHE_REFERENCED;
-}
-
/**
* d_drop - drop a dentry
* @dentry: dentry to drop
@@ -470,30 +450,29 @@ static void dentry_lru_add(struct dentry *dentry)
*/
static void ___d_drop(struct dentry *dentry)
{
- if (!d_unhashed(dentry)) {
- struct hlist_bl_head *b;
- /*
- * Hashed dentries are normally on the dentry hashtable,
- * with the exception of those newly allocated by
- * d_obtain_root, which are always IS_ROOT:
- */
- if (unlikely(IS_ROOT(dentry)))
- b = &dentry->d_sb->s_roots;
- else
- b = d_hash(dentry->d_name.hash);
+ struct hlist_bl_head *b;
+ /*
+ * Hashed dentries are normally on the dentry hashtable,
+ * with the exception of those newly allocated by
+ * d_obtain_root, which are always IS_ROOT:
+ */
+ if (unlikely(IS_ROOT(dentry)))
+ b = &dentry->d_sb->s_roots;
+ else
+ b = d_hash(dentry->d_name.hash);
- hlist_bl_lock(b);
- __hlist_bl_del(&dentry->d_hash);
- hlist_bl_unlock(b);
- /* After this call, in-progress rcu-walk path lookup will fail. */
- write_seqcount_invalidate(&dentry->d_seq);
- }
+ hlist_bl_lock(b);
+ __hlist_bl_del(&dentry->d_hash);
+ hlist_bl_unlock(b);
}
void __d_drop(struct dentry *dentry)
{
- ___d_drop(dentry);
- dentry->d_hash.pprev = NULL;
+ if (!d_unhashed(dentry)) {
+ ___d_drop(dentry);
+ dentry->d_hash.pprev = NULL;
+ write_seqcount_invalidate(&dentry->d_seq);
+ }
}
EXPORT_SYMBOL(__d_drop);
@@ -589,10 +568,71 @@ static void __dentry_kill(struct dentry *dentry)
dentry_free(dentry);
}
+static struct dentry *__lock_parent(struct dentry *dentry)
+{
+ struct dentry *parent;
+ rcu_read_lock();
+ spin_unlock(&dentry->d_lock);
+again:
+ parent = READ_ONCE(dentry->d_parent);
+ spin_lock(&parent->d_lock);
+ /*
+ * We can't blindly lock dentry until we are sure
+ * that we won't violate the locking order.
+ * Any changes of dentry->d_parent must have
+ * been done with parent->d_lock held, so
+ * spin_lock() above is enough of a barrier
+ * for checking if it's still our child.
+ */
+ if (unlikely(parent != dentry->d_parent)) {
+ spin_unlock(&parent->d_lock);
+ goto again;
+ }
+ rcu_read_unlock();
+ if (parent != dentry)
+ spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+ else
+ parent = NULL;
+ return parent;
+}
+
+static inline struct dentry *lock_parent(struct dentry *dentry)
+{
+ struct dentry *parent = dentry->d_parent;
+ if (IS_ROOT(dentry))
+ return NULL;
+ if (likely(spin_trylock(&parent->d_lock)))
+ return parent;
+ return __lock_parent(dentry);
+}
+
+static inline bool retain_dentry(struct dentry *dentry)
+{
+ WARN_ON(d_in_lookup(dentry));
+
+ /* Unreachable? Get rid of it */
+ if (unlikely(d_unhashed(dentry)))
+ return false;
+
+ if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED))
+ return false;
+
+ if (unlikely(dentry->d_flags & DCACHE_OP_DELETE)) {
+ if (dentry->d_op->d_delete(dentry))
+ return false;
+ }
+ /* retain; LRU fodder */
+ dentry->d_lockref.count--;
+ if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST)))
+ d_lru_add(dentry);
+ else if (unlikely(!(dentry->d_flags & DCACHE_REFERENCED)))
+ dentry->d_flags |= DCACHE_REFERENCED;
+ return true;
+}
+
/*
* Finish off a dentry we've decided to kill.
* dentry->d_lock must be held, returns with it unlocked.
- * If ref is non-zero, then decrement the refcount too.
* Returns dentry requiring refcount drop, or NULL if we're done.
*/
static struct dentry *dentry_kill(struct dentry *dentry)
@@ -602,62 +642,43 @@ static struct dentry *dentry_kill(struct dentry *dentry)
struct dentry *parent = NULL;
if (inode && unlikely(!spin_trylock(&inode->i_lock)))
- goto failed;
+ goto slow_positive;
if (!IS_ROOT(dentry)) {
parent = dentry->d_parent;
if (unlikely(!spin_trylock(&parent->d_lock))) {
- if (inode)
- spin_unlock(&inode->i_lock);
- goto failed;
+ parent = __lock_parent(dentry);
+ if (likely(inode || !dentry->d_inode))
+ goto got_locks;
+ /* negative that became positive */
+ if (parent)
+ spin_unlock(&parent->d_lock);
+ inode = dentry->d_inode;
+ goto slow_positive;
}
}
-
__dentry_kill(dentry);
return parent;
-failed:
+slow_positive:
spin_unlock(&dentry->d_lock);
- return dentry; /* try again with same dentry */
-}
-
-static inline struct dentry *lock_parent(struct dentry *dentry)
-{
- struct dentry *parent = dentry->d_parent;
- if (IS_ROOT(dentry))
- return NULL;
- if (unlikely(dentry->d_lockref.count < 0))
- return NULL;
- if (likely(spin_trylock(&parent->d_lock)))
+ spin_lock(&inode->i_lock);
+ spin_lock(&dentry->d_lock);
+ parent = lock_parent(dentry);
+got_locks:
+ if (unlikely(dentry->d_lockref.count != 1)) {
+ dentry->d_lockref.count--;
+ } else if (likely(!retain_dentry(dentry))) {
+ __dentry_kill(dentry);
return parent;
- rcu_read_lock();
- spin_unlock(&dentry->d_lock);
-again:
- parent = READ_ONCE(dentry->d_parent);
- spin_lock(&parent->d_lock);
- /*
- * We can't blindly lock dentry until we are sure
- * that we won't violate the locking order.
- * Any changes of dentry->d_parent must have
- * been done with parent->d_lock held, so
- * spin_lock() above is enough of a barrier
- * for checking if it's still our child.
- */
- if (unlikely(parent != dentry->d_parent)) {
- spin_unlock(&parent->d_lock);
- goto again;
}
- if (parent != dentry) {
- spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
- if (unlikely(dentry->d_lockref.count < 0)) {
- spin_unlock(&parent->d_lock);
- parent = NULL;
- }
- } else {
- parent = NULL;
- }
- rcu_read_unlock();
- return parent;
+ /* we are keeping it, after all */
+ if (inode)
+ spin_unlock(&inode->i_lock);
+ if (parent)
+ spin_unlock(&parent->d_lock);
+ spin_unlock(&dentry->d_lock);
+ return NULL;
}
/*
@@ -807,27 +828,11 @@ repeat:
/* Slow case: now with the dentry lock held */
rcu_read_unlock();
- WARN_ON(d_in_lookup(dentry));
-
- /* Unreachable? Get rid of it */
- if (unlikely(d_unhashed(dentry)))
- goto kill_it;
-
- if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED))
- goto kill_it;
-
- if (unlikely(dentry->d_flags & DCACHE_OP_DELETE)) {
- if (dentry->d_op->d_delete(dentry))
- goto kill_it;
+ if (likely(retain_dentry(dentry))) {
+ spin_unlock(&dentry->d_lock);
+ return;
}
- dentry_lru_add(dentry);
-
- dentry->d_lockref.count--;
- spin_unlock(&dentry->d_lock);
- return;
-
-kill_it:
dentry = dentry_kill(dentry);
if (dentry) {
cond_resched();
@@ -976,56 +981,83 @@ restart:
}
EXPORT_SYMBOL(d_prune_aliases);
-static void shrink_dentry_list(struct list_head *list)
+/*
+ * Lock a dentry from shrink list.
+ * Called under rcu_read_lock() and dentry->d_lock; the former
+ * guarantees that nothing we access will be freed under us.
+ * Note that dentry is *not* protected from concurrent dentry_kill(),
+ * d_delete(), etc.
+ *
+ * Return false if dentry has been disrupted or grabbed, leaving
+ * the caller to kick it off-list. Otherwise, return true and have
+ * that dentry's inode and parent both locked.
+ */
+static bool shrink_lock_dentry(struct dentry *dentry)
{
- struct dentry *dentry, *parent;
+ struct inode *inode;
+ struct dentry *parent;
- while (!list_empty(list)) {
- struct inode *inode;
- dentry = list_entry(list->prev, struct dentry, d_lru);
+ if (dentry->d_lockref.count)
+ return false;
+
+ inode = dentry->d_inode;
+ if (inode && unlikely(!spin_trylock(&inode->i_lock))) {
+ spin_unlock(&dentry->d_lock);
+ spin_lock(&inode->i_lock);
spin_lock(&dentry->d_lock);
- parent = lock_parent(dentry);
+ if (unlikely(dentry->d_lockref.count))
+ goto out;
+ /* changed inode means that somebody had grabbed it */
+ if (unlikely(inode != dentry->d_inode))
+ goto out;
+ }
- /*
- * The dispose list is isolated and dentries are not accounted
- * to the LRU here, so we can simply remove it from the list
- * here regardless of whether it is referenced or not.
- */
- d_shrink_del(dentry);
+ parent = dentry->d_parent;
+ if (IS_ROOT(dentry) || likely(spin_trylock(&parent->d_lock)))
+ return true;
- /*
- * We found an inuse dentry which was not removed from
- * the LRU because of laziness during lookup. Do not free it.
- */
- if (dentry->d_lockref.count > 0) {
- spin_unlock(&dentry->d_lock);
- if (parent)
- spin_unlock(&parent->d_lock);
- continue;
- }
+ spin_unlock(&dentry->d_lock);
+ spin_lock(&parent->d_lock);
+ if (unlikely(parent != dentry->d_parent)) {
+ spin_unlock(&parent->d_lock);
+ spin_lock(&dentry->d_lock);
+ goto out;
+ }
+ spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+ if (likely(!dentry->d_lockref.count))
+ return true;
+ spin_unlock(&parent->d_lock);
+out:
+ if (inode)
+ spin_unlock(&inode->i_lock);
+ return false;
+}
+static void shrink_dentry_list(struct list_head *list)
+{
+ while (!list_empty(list)) {
+ struct dentry *dentry, *parent;
- if (unlikely(dentry->d_flags & DCACHE_DENTRY_KILLED)) {
- bool can_free = dentry->d_flags & DCACHE_MAY_FREE;
+ dentry = list_entry(list->prev, struct dentry, d_lru);
+ spin_lock(&dentry->d_lock);
+ rcu_read_lock();
+ if (!shrink_lock_dentry(dentry)) {
+ bool can_free = false;
+ rcu_read_unlock();
+ d_shrink_del(dentry);
+ if (dentry->d_lockref.count < 0)
+ can_free = dentry->d_flags & DCACHE_MAY_FREE;
spin_unlock(&dentry->d_lock);
- if (parent)
- spin_unlock(&parent->d_lock);
if (can_free)
dentry_free(dentry);
continue;
}
-
- inode = dentry->d_inode;
- if (inode && unlikely(!spin_trylock(&inode->i_lock))) {
- d_shrink_add(dentry, list);
- spin_unlock(&dentry->d_lock);
- if (parent)
- spin_unlock(&parent->d_lock);
- continue;
- }
-
+ rcu_read_unlock();
+ d_shrink_del(dentry);
+ parent = dentry->d_parent;
__dentry_kill(dentry);
-
+ if (parent == dentry)
+ continue;
/*
* We need to prune ancestors too. This is necessary to prevent
* quadratic behavior of shrink_dcache_parent(), but is also
@@ -1033,26 +1065,8 @@ static void shrink_dentry_list(struct list_head *list)
* fragmentation.
*/
dentry = parent;
- while (dentry && !lockref_put_or_lock(&dentry->d_lockref)) {
- parent = lock_parent(dentry);
- if (dentry->d_lockref.count != 1) {
- dentry->d_lockref.count--;
- spin_unlock(&dentry->d_lock);
- if (parent)
- spin_unlock(&parent->d_lock);
- break;
- }
- inode = dentry->d_inode; /* can't be NULL */
- if (unlikely(!spin_trylock(&inode->i_lock))) {
- spin_unlock(&dentry->d_lock);
- if (parent)
- spin_unlock(&parent->d_lock);
- cpu_relax();
- continue;
- }
- __dentry_kill(dentry);
- dentry = parent;
- }
+ while (dentry && !lockref_put_or_lock(&dentry->d_lockref))
+ dentry = dentry_kill(dentry);
}
}
@@ -2379,32 +2393,22 @@ EXPORT_SYMBOL(d_hash_and_lookup);
void d_delete(struct dentry * dentry)
{
- struct inode *inode;
- int isdir = 0;
+ struct inode *inode = dentry->d_inode;
+ int isdir = d_is_dir(dentry);
+
+ spin_lock(&inode->i_lock);
+ spin_lock(&dentry->d_lock);
/*
* Are we the only user?
*/
-again:
- spin_lock(&dentry->d_lock);
- inode = dentry->d_inode;
- isdir = S_ISDIR(inode->i_mode);
if (dentry->d_lockref.count == 1) {
- if (!spin_trylock(&inode->i_lock)) {
- spin_unlock(&dentry->d_lock);
- cpu_relax();
- goto again;
- }
dentry->d_flags &= ~DCACHE_CANT_MOUNT;
dentry_unlink_inode(dentry);
- fsnotify_nameremove(dentry, isdir);
- return;
- }
-
- if (!d_unhashed(dentry))
+ } else {
__d_drop(dentry);
-
- spin_unlock(&dentry->d_lock);
-
+ spin_unlock(&dentry->d_lock);
+ spin_unlock(&inode->i_lock);
+ }
fsnotify_nameremove(dentry, isdir);
}
EXPORT_SYMBOL(d_delete);
@@ -2769,57 +2773,6 @@ static void copy_name(struct dentry *dentry, struct dentry *target)
kfree_rcu(old_name, u.head);
}
-static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target)
-{
- /*
- * XXXX: do we really need to take target->d_lock?
- */
- if (IS_ROOT(dentry) || dentry->d_parent == target->d_parent)
- spin_lock(&target->d_parent->d_lock);
- else {
- if (d_ancestor(dentry->d_parent, target->d_parent)) {
- spin_lock(&dentry->d_parent->d_lock);
- spin_lock_nested(&target->d_parent->d_lock,
- DENTRY_D_LOCK_NESTED);
- } else {
- spin_lock(&target->d_parent->d_lock);
- spin_lock_nested(&dentry->d_parent->d_lock,
- DENTRY_D_LOCK_NESTED);
- }
- }
- if (target < dentry) {
- spin_lock_nested(&target->d_lock, 2);
- spin_lock_nested(&dentry->d_lock, 3);
- } else {
- spin_lock_nested(&dentry->d_lock, 2);
- spin_lock_nested(&target->d_lock, 3);
- }
-}
-
-static void dentry_unlock_for_move(struct dentry *dentry, struct dentry *target)
-{
- if (target->d_parent != dentry->d_parent)
- spin_unlock(&dentry->d_parent->d_lock);
- if (target->d_parent != target)
- spin_unlock(&target->d_parent->d_lock);
- spin_unlock(&target->d_lock);
- spin_unlock(&dentry->d_lock);
-}
-
-/*
- * When switching names, the actual string doesn't strictly have to
- * be preserved in the target - because we're dropping the target
- * anyway. As such, we can just do a simple memcpy() to copy over
- * the new name before we switch, unless we are going to rehash
- * it. Note that if we *do* unhash the target, we are not allowed
- * to rehash it without giving it a new name/hash key - whether
- * we swap or overwrite the names here, resulting name won't match
- * the reality in filesystem; it's only there for d_path() purposes.
- * Note that all of this is happening under rename_lock, so the
- * any hash lookup seeing it in the middle of manipulations will
- * be discarded anyway. So we do not care what happens to the hash
- * key in that case.
- */
/*
* __d_move - move a dentry
* @dentry: entry to move
@@ -2834,15 +2787,34 @@ static void dentry_unlock_for_move(struct dentry *dentry, struct dentry *target)
static void __d_move(struct dentry *dentry, struct dentry *target,
bool exchange)
{
+ struct dentry *old_parent, *p;
struct inode *dir = NULL;
unsigned n;
- if (!dentry->d_inode)
- printk(KERN_WARNING "VFS: moving negative dcache entry\n");
- BUG_ON(d_ancestor(dentry, target));
+ WARN_ON(!dentry->d_inode);
+ if (WARN_ON(dentry == target))
+ return;
+
BUG_ON(d_ancestor(target, dentry));
+ old_parent = dentry->d_parent;
+ p = d_ancestor(old_parent, target);
+ if (IS_ROOT(dentry)) {
+ BUG_ON(p);
+ spin_lock(&target->d_parent->d_lock);
+ } else if (!p) {
+ /* target is not a descendent of dentry->d_parent */
+ spin_lock(&target->d_parent->d_lock);
+ spin_lock_nested(&old_parent->d_lock, DENTRY_D_LOCK_NESTED);
+ } else {
+ BUG_ON(p == dentry);
+ spin_lock(&old_parent->d_lock);
+ if (p != target)
+ spin_lock_nested(&target->d_parent->d_lock,
+ DENTRY_D_LOCK_NESTED);
+ }
+ spin_lock_nested(&dentry->d_lock, 2);
+ spin_lock_nested(&target->d_lock, 3);
- dentry_lock_for_move(dentry, target);
if (unlikely(d_in_lookup(target))) {
dir = target->d_parent->d_inode;
n = start_dir_add(dir);
@@ -2853,47 +2825,44 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
write_seqcount_begin_nested(&target->d_seq, DENTRY_D_LOCK_NESTED);
/* unhash both */
- /* ___d_drop does write_seqcount_barrier, but they're OK to nest. */
- ___d_drop(dentry);
- ___d_drop(target);
+ if (!d_unhashed(dentry))
+ ___d_drop(dentry);
+ if (!d_unhashed(target))
+ ___d_drop(target);
- /* Switch the names.. */
- if (exchange)
- swap_names(dentry, target);
- else
+ /* ... and switch them in the tree */
+ dentry->d_parent = target->d_parent;
+ if (!exchange) {
copy_name(dentry, target);
-
- /* rehash in new place(s) */
- __d_rehash(dentry);
- if (exchange)
- __d_rehash(target);
- else
target->d_hash.pprev = NULL;
-
- /* ... and switch them in the tree */
- if (IS_ROOT(dentry)) {
- /* splicing a tree */
- dentry->d_flags |= DCACHE_RCUACCESS;
- dentry->d_parent = target->d_parent;
- target->d_parent = target;
- list_del_init(&target->d_child);
- list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
+ dentry->d_parent->d_lockref.count++;
+ if (dentry == old_parent)
+ dentry->d_flags |= DCACHE_RCUACCESS;
+ else
+ WARN_ON(!--old_parent->d_lockref.count);
} else {
- /* swapping two dentries */
- swap(dentry->d_parent, target->d_parent);
+ target->d_parent = old_parent;
+ swap_names(dentry, target);
list_move(&target->d_child, &target->d_parent->d_subdirs);
- list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
- if (exchange)
- fsnotify_update_flags(target);
- fsnotify_update_flags(dentry);
+ __d_rehash(target);
+ fsnotify_update_flags(target);
}
+ list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
+ __d_rehash(dentry);
+ fsnotify_update_flags(dentry);
write_seqcount_end(&target->d_seq);
write_seqcount_end(&dentry->d_seq);
if (dir)
end_dir_add(dir, n);
- dentry_unlock_for_move(dentry, target);
+
+ if (dentry->d_parent != old_parent)
+ spin_unlock(&dentry->d_parent->d_lock);
+ if (dentry != old_parent)
+ spin_unlock(&old_parent->d_lock);
+ spin_unlock(&target->d_lock);
+ spin_unlock(&dentry->d_lock);
}
/*
@@ -3041,12 +3010,14 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
inode->i_sb->s_type->name,
inode->i_sb->s_id);
} else if (!IS_ROOT(new)) {
+ struct dentry *old_parent = dget(new->d_parent);
int err = __d_unalias(inode, dentry, new);
write_sequnlock(&rename_lock);
if (err) {
dput(new);
new = ERR_PTR(err);
}
+ dput(old_parent);
} else {
__d_move(new, dentry, false);
write_sequnlock(&rename_lock);
@@ -3061,467 +3032,6 @@ out:
}
EXPORT_SYMBOL(d_splice_alias);
-static int prepend(char **buffer, int *buflen, const char *str, int namelen)
-{
- *buflen -= namelen;
- if (*buflen < 0)
- return -ENAMETOOLONG;
- *buffer -= namelen;
- memcpy(*buffer, str, namelen);
- return 0;
-}
-
-/**
- * prepend_name - prepend a pathname in front of current buffer pointer
- * @buffer: buffer pointer
- * @buflen: allocated length of the buffer
- * @name: name string and length qstr structure
- *
- * With RCU path tracing, it may race with d_move(). Use READ_ONCE() to
- * make sure that either the old or the new name pointer and length are
- * fetched. However, there may be mismatch between length and pointer.
- * The length cannot be trusted, we need to copy it byte-by-byte until
- * the length is reached or a null byte is found. It also prepends "/" at
- * the beginning of the name. The sequence number check at the caller will
- * retry it again when a d_move() does happen. So any garbage in the buffer
- * due to mismatched pointer and length will be discarded.
- *
- * Load acquire is needed to make sure that we see that terminating NUL.
- */
-static int prepend_name(char **buffer, int *buflen, const struct qstr *name)
-{
- const char *dname = smp_load_acquire(&name->name); /* ^^^ */
- u32 dlen = READ_ONCE(name->len);
- char *p;
-
- *buflen -= dlen + 1;
- if (*buflen < 0)
- return -ENAMETOOLONG;
- p = *buffer -= dlen + 1;
- *p++ = '/';
- while (dlen--) {
- char c = *dname++;
- if (!c)
- break;
- *p++ = c;
- }
- return 0;
-}
-
-/**
- * prepend_path - Prepend path string to a buffer
- * @path: the dentry/vfsmount to report
- * @root: root vfsmnt/dentry
- * @buffer: pointer to the end of the buffer
- * @buflen: pointer to buffer length
- *
- * The function will first try to write out the pathname without taking any
- * lock other than the RCU read lock to make sure that dentries won't go away.
- * It only checks the sequence number of the global rename_lock as any change
- * in the dentry's d_seq will be preceded by changes in the rename_lock
- * sequence number. If the sequence number had been changed, it will restart
- * the whole pathname back-tracing sequence again by taking the rename_lock.
- * In this case, there is no need to take the RCU read lock as the recursive
- * parent pointer references will keep the dentry chain alive as long as no
- * rename operation is performed.
- */
-static int prepend_path(const struct path *path,
- const struct path *root,
- char **buffer, int *buflen)
-{
- struct dentry *dentry;
- struct vfsmount *vfsmnt;
- struct mount *mnt;
- int error = 0;
- unsigned seq, m_seq = 0;
- char *bptr;
- int blen;
-
- rcu_read_lock();
-restart_mnt:
- read_seqbegin_or_lock(&mount_lock, &m_seq);
- seq = 0;
- rcu_read_lock();
-restart:
- bptr = *buffer;
- blen = *buflen;
- error = 0;
- dentry = path->dentry;
- vfsmnt = path->mnt;
- mnt = real_mount(vfsmnt);
- read_seqbegin_or_lock(&rename_lock, &seq);
- while (dentry != root->dentry || vfsmnt != root->mnt) {
- struct dentry * parent;
-
- if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
- struct mount *parent = READ_ONCE(mnt->mnt_parent);
- /* Escaped? */
- if (dentry != vfsmnt->mnt_root) {
- bptr = *buffer;
- blen = *buflen;
- error = 3;
- break;
- }
- /* Global root? */
- if (mnt != parent) {
- dentry = READ_ONCE(mnt->mnt_mountpoint);
- mnt = parent;
- vfsmnt = &mnt->mnt;
- continue;
- }
- if (!error)
- error = is_mounted(vfsmnt) ? 1 : 2;
- break;
- }
- parent = dentry->d_parent;
- prefetch(parent);
- error = prepend_name(&bptr, &blen, &dentry->d_name);
- if (error)
- break;
-
- dentry = parent;
- }
- if (!(seq & 1))
- rcu_read_unlock();
- if (need_seqretry(&rename_lock, seq)) {
- seq = 1;
- goto restart;
- }
- done_seqretry(&rename_lock, seq);
-
- if (!(m_seq & 1))
- rcu_read_unlock();
- if (need_seqretry(&mount_lock, m_seq)) {
- m_seq = 1;
- goto restart_mnt;
- }
- done_seqretry(&mount_lock, m_seq);
-
- if (error >= 0 && bptr == *buffer) {
- if (--blen < 0)
- error = -ENAMETOOLONG;
- else
- *--bptr = '/';
- }
- *buffer = bptr;
- *buflen = blen;
- return error;
-}
-
-/**
- * __d_path - return the path of a dentry
- * @path: the dentry/vfsmount to report
- * @root: root vfsmnt/dentry
- * @buf: buffer to return value in
- * @buflen: buffer length
- *
- * Convert a dentry into an ASCII path name.
- *
- * Returns a pointer into the buffer or an error code if the
- * path was too long.
- *
- * "buflen" should be positive.
- *
- * If the path is not reachable from the supplied root, return %NULL.
- */
-char *__d_path(const struct path *path,
- const struct path *root,
- char *buf, int buflen)
-{
- char *res = buf + buflen;
- int error;
-
- prepend(&res, &buflen, "\0", 1);
- error = prepend_path(path, root, &res, &buflen);
-
- if (error < 0)
- return ERR_PTR(error);
- if (error > 0)
- return NULL;
- return res;
-}
-
-char *d_absolute_path(const struct path *path,
- char *buf, int buflen)
-{
- struct path root = {};
- char *res = buf + buflen;
- int error;
-
- prepend(&res, &buflen, "\0", 1);
- error = prepend_path(path, &root, &res, &buflen);
-
- if (error > 1)
- error = -EINVAL;
- if (error < 0)
- return ERR_PTR(error);
- return res;
-}
-
-/*
- * same as __d_path but appends "(deleted)" for unlinked files.
- */
-static int path_with_deleted(const struct path *path,
- const struct path *root,
- char **buf, int *buflen)
-{
- prepend(buf, buflen, "\0", 1);
- if (d_unlinked(path->dentry)) {
- int error = prepend(buf, buflen, " (deleted)", 10);
- if (error)
- return error;
- }
-
- return prepend_path(path, root, buf, buflen);
-}
-
-static int prepend_unreachable(char **buffer, int *buflen)
-{
- return prepend(buffer, buflen, "(unreachable)", 13);
-}
-
-static void get_fs_root_rcu(struct fs_struct *fs, struct path *root)
-{
- unsigned seq;
-
- do {
- seq = read_seqcount_begin(&fs->seq);
- *root = fs->root;
- } while (read_seqcount_retry(&fs->seq, seq));
-}
-
-/**
- * d_path - return the path of a dentry
- * @path: path to report
- * @buf: buffer to return value in
- * @buflen: buffer length
- *
- * Convert a dentry into an ASCII path name. If the entry has been deleted
- * the string " (deleted)" is appended. Note that this is ambiguous.
- *
- * Returns a pointer into the buffer or an error code if the path was
- * too long. Note: Callers should use the returned pointer, not the passed
- * in buffer, to use the name! The implementation often starts at an offset
- * into the buffer, and may leave 0 bytes at the start.
- *
- * "buflen" should be positive.
- */
-char *d_path(const struct path *path, char *buf, int buflen)
-{
- char *res = buf + buflen;
- struct path root;
- int error;
-
- /*
- * We have various synthetic filesystems that never get mounted. On
- * these filesystems dentries are never used for lookup purposes, and
- * thus don't need to be hashed. They also don't need a name until a
- * user wants to identify the object in /proc/pid/fd/. The little hack
- * below allows us to generate a name for these objects on demand:
- *
- * Some pseudo inodes are mountable. When they are mounted
- * path->dentry == path->mnt->mnt_root. In that case don't call d_dname
- * and instead have d_path return the mounted path.
- */
- if (path->dentry->d_op && path->dentry->d_op->d_dname &&
- (!IS_ROOT(path->dentry) || path->dentry != path->mnt->mnt_root))
- return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
-
- rcu_read_lock();
- get_fs_root_rcu(current->fs, &root);
- error = path_with_deleted(path, &root, &res, &buflen);
- rcu_read_unlock();
-
- if (error < 0)
- res = ERR_PTR(error);
- return res;
-}
-EXPORT_SYMBOL(d_path);
-
-/*
- * Helper function for dentry_operations.d_dname() members
- */
-char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen,
- const char *fmt, ...)
-{
- va_list args;
- char temp[64];
- int sz;
-
- va_start(args, fmt);
- sz = vsnprintf(temp, sizeof(temp), fmt, args) + 1;
- va_end(args);
-
- if (sz > sizeof(temp) || sz > buflen)
- return ERR_PTR(-ENAMETOOLONG);
-
- buffer += buflen - sz;
- return memcpy(buffer, temp, sz);
-}
-
-char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
-{
- char *end = buffer + buflen;
- /* these dentries are never renamed, so d_lock is not needed */
- if (prepend(&end, &buflen, " (deleted)", 11) ||
- prepend(&end, &buflen, dentry->d_name.name, dentry->d_name.len) ||
- prepend(&end, &buflen, "/", 1))
- end = ERR_PTR(-ENAMETOOLONG);
- return end;
-}
-EXPORT_SYMBOL(simple_dname);
-
-/*
- * Write full pathname from the root of the filesystem into the buffer.
- */
-static char *__dentry_path(struct dentry *d, char *buf, int buflen)
-{
- struct dentry *dentry;
- char *end, *retval;
- int len, seq = 0;
- int error = 0;
-
- if (buflen < 2)
- goto Elong;
-
- rcu_read_lock();
-restart:
- dentry = d;
- end = buf + buflen;
- len = buflen;
- prepend(&end, &len, "\0", 1);
- /* Get '/' right */
- retval = end-1;
- *retval = '/';
- read_seqbegin_or_lock(&rename_lock, &seq);
- while (!IS_ROOT(dentry)) {
- struct dentry *parent = dentry->d_parent;
-
- prefetch(parent);
- error = prepend_name(&end, &len, &dentry->d_name);
- if (error)
- break;
-
- retval = end;
- dentry = parent;
- }
- if (!(seq & 1))
- rcu_read_unlock();
- if (need_seqretry(&rename_lock, seq)) {
- seq = 1;
- goto restart;
- }
- done_seqretry(&rename_lock, seq);
- if (error)
- goto Elong;
- return retval;
-Elong:
- return ERR_PTR(-ENAMETOOLONG);
-}
-
-char *dentry_path_raw(struct dentry *dentry, char *buf, int buflen)
-{
- return __dentry_path(dentry, buf, buflen);
-}
-EXPORT_SYMBOL(dentry_path_raw);
-
-char *dentry_path(struct dentry *dentry, char *buf, int buflen)
-{
- char *p = NULL;
- char *retval;
-
- if (d_unlinked(dentry)) {
- p = buf + buflen;
- if (prepend(&p, &buflen, "//deleted", 10) != 0)
- goto Elong;
- buflen++;
- }
- retval = __dentry_path(dentry, buf, buflen);
- if (!IS_ERR(retval) && p)
- *p = '/'; /* restore '/' overriden with '\0' */
- return retval;
-Elong:
- return ERR_PTR(-ENAMETOOLONG);
-}
-
-static void get_fs_root_and_pwd_rcu(struct fs_struct *fs, struct path *root,
- struct path *pwd)
-{
- unsigned seq;
-
- do {
- seq = read_seqcount_begin(&fs->seq);
- *root = fs->root;
- *pwd = fs->pwd;
- } while (read_seqcount_retry(&fs->seq, seq));
-}
-
-/*
- * NOTE! The user-level library version returns a
- * character pointer. The kernel system call just
- * returns the length of the buffer filled (which
- * includes the ending '\0' character), or a negative
- * error value. So libc would do something like
- *
- * char *getcwd(char * buf, size_t size)
- * {
- * int retval;
- *
- * retval = sys_getcwd(buf, size);
- * if (retval >= 0)
- * return buf;
- * errno = -retval;
- * return NULL;
- * }
- */
-SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
-{
- int error;
- struct path pwd, root;
- char *page = __getname();
-
- if (!page)
- return -ENOMEM;
-
- rcu_read_lock();
- get_fs_root_and_pwd_rcu(current->fs, &root, &pwd);
-
- error = -ENOENT;
- if (!d_unlinked(pwd.dentry)) {
- unsigned long len;
- char *cwd = page + PATH_MAX;
- int buflen = PATH_MAX;
-
- prepend(&cwd, &buflen, "\0", 1);
- error = prepend_path(&pwd, &root, &cwd, &buflen);
- rcu_read_unlock();
-
- if (error < 0)
- goto out;
-
- /* Unreachable from current root */
- if (error > 0) {
- error = prepend_unreachable(&cwd, &buflen);
- if (error)
- goto out;
- }
-
- error = -ERANGE;
- len = PATH_MAX + page - cwd;
- if (len <= size) {
- error = len;
- if (copy_to_user(buf, cwd, len))
- error = -EFAULT;
- }
- } else {
- rcu_read_unlock();
- }
-
-out:
- __putname(page);
- return error;
-}
-
/*
* Test whether new_dentry is a subdirectory of old_dentry.
*
@@ -3585,6 +3095,8 @@ void d_genocide(struct dentry *parent)
d_walk(parent, parent, d_genocide_kill, NULL);
}
+EXPORT_SYMBOL(d_genocide);
+
void d_tmpfile(struct dentry *dentry, struct inode *inode)
{
inode_dec_link_count(inode);
@@ -3664,8 +3176,6 @@ static void __init dcache_init(void)
struct kmem_cache *names_cachep __read_mostly;
EXPORT_SYMBOL(names_cachep);
-EXPORT_SYMBOL(d_genocide);
-
void __init vfs_caches_init_early(void)
{
int i;
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 63a998c3f252..13b01351dd1c 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -270,10 +270,7 @@ struct dentry *debugfs_lookup(const char *name, struct dentry *parent)
if (!parent)
parent = debugfs_mount->mnt_root;
- inode_lock(d_inode(parent));
- dentry = lookup_one_len(name, parent, strlen(name));
- inode_unlock(d_inode(parent));
-
+ dentry = lookup_one_len_unlocked(name, parent, strlen(name));
if (IS_ERR(dentry))
return NULL;
if (!d_really_is_positive(dentry)) {
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index e31d6ed3ec32..e072e955ce33 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -138,10 +138,6 @@ static int devpts_ptmx_path(struct path *path)
struct super_block *sb;
int err;
- /* Has the devpts filesystem already been found? */
- if (path->mnt->mnt_sb->s_magic == DEVPTS_SUPER_MAGIC)
- return 0;
-
/* Is a devpts filesystem at "pts" in the same directory? */
err = path_pts(path);
if (err)
@@ -156,25 +152,53 @@ static int devpts_ptmx_path(struct path *path)
return 0;
}
+/*
+ * Try to find a suitable devpts filesystem. We support the following
+ * scenarios:
+ * - The ptmx device node is located in the same directory as the devpts
+ * mount where the pts device nodes are located.
+ * This is e.g. the case when calling open on the /dev/pts/ptmx device
+ * node when the devpts filesystem is mounted at /dev/pts.
+ * - The ptmx device node is located outside the devpts filesystem mount
+ * where the pts device nodes are located. For example, the ptmx device
+ * is a symlink, separate device node, or bind-mount.
+ * A supported scenario is bind-mounting /dev/pts/ptmx to /dev/ptmx and
+ * then calling open on /dev/ptmx. In this case a suitable pts
+ * subdirectory can be found in the common parent directory /dev of the
+ * devpts mount and the ptmx bind-mount, after resolving the /dev/ptmx
+ * bind-mount.
+ * If no suitable pts subdirectory can be found this function will fail.
+ * This is e.g. the case when bind-mounting /dev/pts/ptmx to /ptmx.
+ */
struct vfsmount *devpts_mntget(struct file *filp, struct pts_fs_info *fsi)
{
struct path path;
- int err;
+ int err = 0;
path = filp->f_path;
path_get(&path);
- err = devpts_ptmx_path(&path);
+ /* Walk upward while the start point is a bind mount of
+ * a single file.
+ */
+ while (path.mnt->mnt_root == path.dentry)
+ if (follow_up(&path) == 0)
+ break;
+
+ /* devpts_ptmx_path() finds a devpts fs or returns an error. */
+ if ((path.mnt->mnt_sb->s_magic != DEVPTS_SUPER_MAGIC) ||
+ (DEVPTS_SB(path.mnt->mnt_sb) != fsi))
+ err = devpts_ptmx_path(&path);
dput(path.dentry);
- if (err) {
- mntput(path.mnt);
- return ERR_PTR(err);
- }
- if (DEVPTS_SB(path.mnt->mnt_sb) != fsi) {
- mntput(path.mnt);
- return ERR_PTR(-ENODEV);
+ if (!err) {
+ if (DEVPTS_SB(path.mnt->mnt_sb) == fsi)
+ return path.mnt;
+
+ err = -ENODEV;
}
- return path.mnt;
+
+ mntput(path.mnt);
+ return ERR_PTR(err);
}
struct pts_fs_info *devpts_acquire(struct file *filp)
@@ -182,15 +206,19 @@ struct pts_fs_info *devpts_acquire(struct file *filp)
struct pts_fs_info *result;
struct path path;
struct super_block *sb;
- int err;
path = filp->f_path;
path_get(&path);
- err = devpts_ptmx_path(&path);
- if (err) {
- result = ERR_PTR(err);
- goto out;
+ /* Has the devpts filesystem already been found? */
+ if (path.mnt->mnt_sb->s_magic != DEVPTS_SUPER_MAGIC) {
+ int err;
+
+ err = devpts_ptmx_path(&path);
+ if (err) {
+ result = ERR_PTR(err);
+ goto out;
+ }
}
/*
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index f9b3e0a83526..a33d8fb1bf2a 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -243,8 +243,6 @@ static int ext4_init_block_bitmap(struct super_block *sb,
*/
ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group),
sb->s_blocksize * 8, bh->b_data);
- ext4_block_bitmap_csum_set(sb, block_group, gdp, bh);
- ext4_group_desc_csum_set(sb, block_group, gdp);
return 0;
}
@@ -340,20 +338,25 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb,
/* check whether block bitmap block number is set */
blk = ext4_block_bitmap(sb, desc);
offset = blk - group_first_block;
- if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
+ if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize ||
+ !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
/* bad block bitmap */
return blk;
/* check whether the inode bitmap block number is set */
blk = ext4_inode_bitmap(sb, desc);
offset = blk - group_first_block;
- if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
+ if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize ||
+ !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
/* bad block bitmap */
return blk;
/* check whether the inode table block number is set */
blk = ext4_inode_table(sb, desc);
offset = blk - group_first_block;
+ if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize ||
+ EXT4_B2C(sbi, offset + sbi->s_itb_per_group) >= sb->s_blocksize)
+ return blk;
next_zero_bit = ext4_find_next_zero_bit(bh->b_data,
EXT4_B2C(sbi, offset + sbi->s_itb_per_group),
EXT4_B2C(sbi, offset));
@@ -419,6 +422,7 @@ struct buffer_head *
ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
{
struct ext4_group_desc *desc;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
struct buffer_head *bh;
ext4_fsblk_t bitmap_blk;
int err;
@@ -427,6 +431,12 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
if (!desc)
return ERR_PTR(-EFSCORRUPTED);
bitmap_blk = ext4_block_bitmap(sb, desc);
+ if ((bitmap_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
+ (bitmap_blk >= ext4_blocks_count(sbi->s_es))) {
+ ext4_error(sb, "Invalid block bitmap block %llu in "
+ "block_group %u", bitmap_blk, block_group);
+ return ERR_PTR(-EFSCORRUPTED);
+ }
bh = sb_getblk(sb, bitmap_blk);
if (unlikely(!bh)) {
ext4_error(sb, "Cannot get buffer for block bitmap - "
@@ -448,6 +458,7 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
err = ext4_init_block_bitmap(sb, bh, block_group, desc);
set_bitmap_uptodate(bh);
set_buffer_uptodate(bh);
+ set_buffer_verified(bh);
ext4_unlock_group(sb, block_group);
unlock_buffer(bh);
if (err) {
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index da87cf757f7d..e2902d394f1b 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -365,13 +365,15 @@ static loff_t ext4_dir_llseek(struct file *file, loff_t offset, int whence)
{
struct inode *inode = file->f_mapping->host;
int dx_dir = is_dx_dir(inode);
- loff_t htree_max = ext4_get_htree_eof(file);
+ loff_t ret, htree_max = ext4_get_htree_eof(file);
if (likely(dx_dir))
- return generic_file_llseek_size(file, offset, whence,
+ ret = generic_file_llseek_size(file, offset, whence,
htree_max, htree_max);
else
- return ext4_llseek(file, offset, whence);
+ ret = ext4_llseek(file, offset, whence);
+ file->f_version = inode_peek_iversion(inode) - 1;
+ return ret;
}
/*
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 3241475a1733..a42e71203e53 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1522,8 +1522,6 @@ enum {
EXT4_STATE_EXT_MIGRATE, /* Inode is migrating */
EXT4_STATE_DIO_UNWRITTEN, /* need convert on dio done*/
EXT4_STATE_NEWENTRY, /* File just added to dir */
- EXT4_STATE_DIOREAD_LOCK, /* Disable support for dio read
- nolocking */
EXT4_STATE_MAY_INLINE_DATA, /* may have in-inode data */
EXT4_STATE_EXT_PRECACHED, /* extents have been precached */
EXT4_STATE_LUSTRE_EA_INODE, /* Lustre-style ea_inode */
@@ -3181,21 +3179,6 @@ static inline void set_bitmap_uptodate(struct buffer_head *bh)
set_bit(BH_BITMAP_UPTODATE, &(bh)->b_state);
}
-/*
- * Disable DIO read nolock optimization, so new dioreaders will be forced
- * to grab i_mutex
- */
-static inline void ext4_inode_block_unlocked_dio(struct inode *inode)
-{
- ext4_set_inode_state(inode, EXT4_STATE_DIOREAD_LOCK);
- smp_mb();
-}
-static inline void ext4_inode_resume_unlocked_dio(struct inode *inode)
-{
- smp_mb();
- ext4_clear_inode_state(inode, EXT4_STATE_DIOREAD_LOCK);
-}
-
#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
/* For ioend & aio unwritten conversion wait queues */
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index 2d593201cf7a..7c70b08d104c 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -166,13 +166,6 @@ int __ext4_journal_get_write_access(const char *where, unsigned int line,
might_sleep();
if (ext4_handle_valid(handle)) {
- struct super_block *sb;
-
- sb = handle->h_transaction->t_journal->j_private;
- if (unlikely(ext4_forced_shutdown(EXT4_SB(sb)))) {
- jbd2_journal_abort_handle(handle);
- return -EIO;
- }
err = jbd2_journal_get_write_access(handle, bh);
if (err)
ext4_journal_abort_handle(where, line, __func__, bh,
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 054416e9d827..0a7315961bac 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4796,7 +4796,6 @@ static long ext4_zero_range(struct file *file, loff_t offset,
flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
/* Wait all existing dio workers, newcomers will block on i_mutex */
- ext4_inode_block_unlocked_dio(inode);
inode_dio_wait(inode);
/* Preallocate the range including the unaligned edges */
@@ -4807,7 +4806,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
round_down(offset, 1 << blkbits)) >> blkbits,
new_size, flags);
if (ret)
- goto out_dio;
+ goto out_mutex;
}
@@ -4824,7 +4823,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
ret = ext4_update_disksize_before_punch(inode, offset, len);
if (ret) {
up_write(&EXT4_I(inode)->i_mmap_sem);
- goto out_dio;
+ goto out_mutex;
}
/* Now release the pages and zero block aligned part of pages */
truncate_pagecache_range(inode, start, end - 1);
@@ -4834,10 +4833,10 @@ static long ext4_zero_range(struct file *file, loff_t offset,
flags);
up_write(&EXT4_I(inode)->i_mmap_sem);
if (ret)
- goto out_dio;
+ goto out_mutex;
}
if (!partial_begin && !partial_end)
- goto out_dio;
+ goto out_mutex;
/*
* In worst case we have to writeout two nonadjacent unwritten
@@ -4850,7 +4849,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
ext4_std_error(inode->i_sb, ret);
- goto out_dio;
+ goto out_mutex;
}
inode->i_mtime = inode->i_ctime = current_time(inode);
@@ -4875,8 +4874,6 @@ static long ext4_zero_range(struct file *file, loff_t offset,
ext4_handle_sync(handle);
ext4_journal_stop(handle);
-out_dio:
- ext4_inode_resume_unlocked_dio(inode);
out_mutex:
inode_unlock(inode);
return ret;
@@ -4964,11 +4961,9 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
}
/* Wait all existing dio workers, newcomers will block on i_mutex */
- ext4_inode_block_unlocked_dio(inode);
inode_dio_wait(inode);
ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, flags);
- ext4_inode_resume_unlocked_dio(inode);
if (ret)
goto out;
@@ -5485,7 +5480,6 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
}
/* Wait for existing dio to complete */
- ext4_inode_block_unlocked_dio(inode);
inode_dio_wait(inode);
/*
@@ -5562,7 +5556,6 @@ out_stop:
ext4_journal_stop(handle);
out_mmap:
up_write(&EXT4_I(inode)->i_mmap_sem);
- ext4_inode_resume_unlocked_dio(inode);
out_mutex:
inode_unlock(inode);
return ret;
@@ -5635,7 +5628,6 @@ int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
}
/* Wait for existing dio to complete */
- ext4_inode_block_unlocked_dio(inode);
inode_dio_wait(inode);
/*
@@ -5737,7 +5729,6 @@ out_stop:
ext4_journal_stop(handle);
out_mmap:
up_write(&EXT4_I(inode)->i_mmap_sem);
- ext4_inode_resume_unlocked_dio(inode);
out_mutex:
inode_unlock(inode);
return ret;
@@ -5751,7 +5742,7 @@ out_mutex:
* @lblk1: Start block for first inode
* @lblk2: Start block for second inode
* @count: Number of blocks to swap
- * @mark_unwritten: Mark second inode's extents as unwritten after swap
+ * @unwritten: Mark second inode's extents as unwritten after swap
* @erp: Pointer to save error value
*
* This helper routine does exactly what is promise "swap extents". All other
@@ -5765,7 +5756,7 @@ out_mutex:
*/
int
ext4_swap_extents(handle_t *handle, struct inode *inode1,
- struct inode *inode2, ext4_lblk_t lblk1, ext4_lblk_t lblk2,
+ struct inode *inode2, ext4_lblk_t lblk1, ext4_lblk_t lblk2,
ext4_lblk_t count, int unwritten, int *erp)
{
struct ext4_ext_path *path1 = NULL;
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 7830d28df331..df92e3ec9913 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -66,44 +66,6 @@ void ext4_mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
}
-/* Initializes an uninitialized inode bitmap */
-static int ext4_init_inode_bitmap(struct super_block *sb,
- struct buffer_head *bh,
- ext4_group_t block_group,
- struct ext4_group_desc *gdp)
-{
- struct ext4_group_info *grp;
- struct ext4_sb_info *sbi = EXT4_SB(sb);
- J_ASSERT_BH(bh, buffer_locked(bh));
-
- /* If checksum is bad mark all blocks and inodes use to prevent
- * allocation, essentially implementing a per-group read-only flag. */
- if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
- grp = ext4_get_group_info(sb, block_group);
- if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
- percpu_counter_sub(&sbi->s_freeclusters_counter,
- grp->bb_free);
- set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
- if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
- int count;
- count = ext4_free_inodes_count(sb, gdp);
- percpu_counter_sub(&sbi->s_freeinodes_counter,
- count);
- }
- set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
- return -EFSBADCRC;
- }
-
- memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
- ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8,
- bh->b_data);
- ext4_inode_bitmap_csum_set(sb, block_group, gdp, bh,
- EXT4_INODES_PER_GROUP(sb) / 8);
- ext4_group_desc_csum_set(sb, block_group, gdp);
-
- return 0;
-}
-
void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate)
{
if (uptodate) {
@@ -160,6 +122,7 @@ static struct buffer_head *
ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
{
struct ext4_group_desc *desc;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
struct buffer_head *bh = NULL;
ext4_fsblk_t bitmap_blk;
int err;
@@ -169,6 +132,12 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
return ERR_PTR(-EFSCORRUPTED);
bitmap_blk = ext4_inode_bitmap(sb, desc);
+ if ((bitmap_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
+ (bitmap_blk >= ext4_blocks_count(sbi->s_es))) {
+ ext4_error(sb, "Invalid inode bitmap blk %llu in "
+ "block_group %u", bitmap_blk, block_group);
+ return ERR_PTR(-EFSCORRUPTED);
+ }
bh = sb_getblk(sb, bitmap_blk);
if (unlikely(!bh)) {
ext4_error(sb, "Cannot read inode bitmap - "
@@ -187,17 +156,14 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
ext4_lock_group(sb, block_group);
if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
- err = ext4_init_inode_bitmap(sb, bh, block_group, desc);
+ memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
+ ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb),
+ sb->s_blocksize * 8, bh->b_data);
set_bitmap_uptodate(bh);
set_buffer_uptodate(bh);
set_buffer_verified(bh);
ext4_unlock_group(sb, block_group);
unlock_buffer(bh);
- if (err) {
- ext4_error(sb, "Failed to init inode bitmap for group "
- "%u: %d", block_group, err);
- goto out;
- }
return bh;
}
ext4_unlock_group(sb, block_group);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c94780075b04..18aa2ef963ad 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2694,15 +2694,6 @@ out:
return err;
}
-static int __writepage(struct page *page, struct writeback_control *wbc,
- void *data)
-{
- struct address_space *mapping = data;
- int ret = ext4_writepage(page, wbc);
- mapping_set_error(mapping, ret);
- return ret;
-}
-
static int ext4_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
@@ -2740,11 +2731,7 @@ static int ext4_writepages(struct address_space *mapping,
goto out_writepages;
if (ext4_should_journal_data(inode)) {
- struct blk_plug plug;
-
- blk_start_plug(&plug);
- ret = write_cache_pages(mapping, wbc, __writepage, mapping);
- blk_finish_plug(&plug);
+ ret = generic_writepages(mapping, wbc);
goto out_writepages;
}
@@ -3524,7 +3511,7 @@ retry:
iomap->flags |= IOMAP_F_DIRTY;
iomap->bdev = inode->i_sb->s_bdev;
iomap->dax_dev = sbi->s_daxdev;
- iomap->offset = first_block << blkbits;
+ iomap->offset = (u64)first_block << blkbits;
iomap->length = (u64)map.m_len << blkbits;
if (ret == 0) {
@@ -3669,7 +3656,7 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter)
int orphan = 0;
handle_t *handle;
- if (final_size > inode->i_size) {
+ if (final_size > inode->i_size || final_size > ei->i_disksize) {
/* Credits for sb + inode write */
handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
if (IS_ERR(handle)) {
@@ -3682,7 +3669,7 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter)
goto out;
}
orphan = 1;
- ei->i_disksize = inode->i_size;
+ ext4_update_i_disksize(inode, inode->i_size);
ext4_journal_stop(handle);
}
@@ -3789,9 +3776,10 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter)
ext4_orphan_del(handle, inode);
if (ret > 0) {
loff_t end = offset + ret;
- if (end > inode->i_size) {
- ei->i_disksize = end;
- i_size_write(inode, end);
+ if (end > inode->i_size || end > ei->i_disksize) {
+ ext4_update_i_disksize(inode, end);
+ if (end > inode->i_size)
+ i_size_write(inode, end);
/*
* We're going to return a positive `ret'
* here due to non-zero-length I/O, so there's
@@ -4251,7 +4239,6 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
}
/* Wait all existing dio workers, newcomers will block on i_mutex */
- ext4_inode_block_unlocked_dio(inode);
inode_dio_wait(inode);
/*
@@ -4324,7 +4311,6 @@ out_stop:
ext4_journal_stop(handle);
out_dio:
up_write(&EXT4_I(inode)->i_mmap_sem);
- ext4_inode_resume_unlocked_dio(inode);
out_mutex:
inode_unlock(inode);
return ret;
@@ -4746,6 +4732,12 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
goto bad_inode;
raw_inode = ext4_raw_inode(&iloc);
+ if ((ino == EXT4_ROOT_INO) && (raw_inode->i_links_count == 0)) {
+ EXT4_ERROR_INODE(inode, "root inode unallocated");
+ ret = -EFSCORRUPTED;
+ goto bad_inode;
+ }
+
if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
@@ -5506,9 +5498,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
*/
if (orphan) {
if (!ext4_should_journal_data(inode)) {
- ext4_inode_block_unlocked_dio(inode);
inode_dio_wait(inode);
- ext4_inode_resume_unlocked_dio(inode);
} else
ext4_wait_for_tail_page_commit(inode);
}
@@ -5999,7 +5989,6 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
return -EROFS;
/* Wait for all existing dio workers */
- ext4_inode_block_unlocked_dio(inode);
inode_dio_wait(inode);
/*
@@ -6015,7 +6004,6 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
err = filemap_write_and_wait(inode->i_mapping);
if (err < 0) {
up_write(&EXT4_I(inode)->i_mmap_sem);
- ext4_inode_resume_unlocked_dio(inode);
return err;
}
}
@@ -6038,7 +6026,6 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
if (err < 0) {
jbd2_journal_unlock_updates(journal);
percpu_up_write(&sbi->s_journal_flag_rwsem);
- ext4_inode_resume_unlocked_dio(inode);
return err;
}
ext4_clear_inode_flag(inode, EXT4_INODE_JOURNAL_DATA);
@@ -6050,7 +6037,6 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
if (val)
up_write(&EXT4_I(inode)->i_mmap_sem);
- ext4_inode_resume_unlocked_dio(inode);
/* Finally we can mark the inode as dirty. */
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 7e99ad02f1ba..a7074115d6f6 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -124,8 +124,6 @@ static long swap_inode_boot_loader(struct super_block *sb,
truncate_inode_pages(&inode_bl->i_data, 0);
/* Wait for all existing dio workers */
- ext4_inode_block_unlocked_dio(inode);
- ext4_inode_block_unlocked_dio(inode_bl);
inode_dio_wait(inode);
inode_dio_wait(inode_bl);
@@ -186,8 +184,6 @@ static long swap_inode_boot_loader(struct super_block *sb,
ext4_double_up_write_data_sem(inode, inode_bl);
journal_err_out:
- ext4_inode_resume_unlocked_dio(inode);
- ext4_inode_resume_unlocked_dio(inode_bl);
unlock_two_nondirectories(inode, inode_bl);
iput(inode_bl);
return err;
@@ -481,6 +477,7 @@ static int ext4_shutdown(struct super_block *sb, unsigned long arg)
return 0;
ext4_msg(sb, KERN_ALERT, "shut down requested (%d)", flags);
+ trace_ext4_shutdown(sb, flags);
switch (flags) {
case EXT4_GOING_FLAGS_DEFAULT:
@@ -492,15 +489,13 @@ static int ext4_shutdown(struct super_block *sb, unsigned long arg)
set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags);
if (sbi->s_journal && !is_journal_aborted(sbi->s_journal)) {
(void) ext4_force_commit(sb);
- jbd2_journal_abort(sbi->s_journal, 0);
+ jbd2_journal_abort(sbi->s_journal, -ESHUTDOWN);
}
break;
case EXT4_GOING_FLAGS_NOLOGFLUSH:
set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags);
- if (sbi->s_journal && !is_journal_aborted(sbi->s_journal)) {
- msleep(100);
- jbd2_journal_abort(sbi->s_journal, 0);
- }
+ if (sbi->s_journal && !is_journal_aborted(sbi->s_journal))
+ jbd2_journal_abort(sbi->s_journal, -ESHUTDOWN);
break;
default:
return -EINVAL;
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index b96e4bd3b3ec..8e17efdcbf11 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -601,8 +601,6 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk,
lock_two_nondirectories(orig_inode, donor_inode);
/* Wait for all existing dio workers */
- ext4_inode_block_unlocked_dio(orig_inode);
- ext4_inode_block_unlocked_dio(donor_inode);
inode_dio_wait(orig_inode);
inode_dio_wait(donor_inode);
@@ -693,8 +691,6 @@ out:
ext4_ext_drop_refs(path);
kfree(path);
ext4_double_up_write_data_sem(orig_inode, donor_inode);
- ext4_inode_resume_unlocked_dio(orig_inode);
- ext4_inode_resume_unlocked_dio(donor_inode);
unlock_two_nondirectories(orig_inode, donor_inode);
return ret;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 39bf464c35f1..185f7e61f4cf 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -101,15 +101,13 @@ static struct inode *ext4_get_journal_inode(struct super_block *sb,
* i_data_sem (rw)
*
* truncate:
- * sb_start_write -> i_mutex -> EXT4_STATE_DIOREAD_LOCK (w) -> i_mmap_sem (w) ->
- * i_mmap_rwsem (w) -> page lock
- * sb_start_write -> i_mutex -> EXT4_STATE_DIOREAD_LOCK (w) -> i_mmap_sem (w) ->
- * transaction start -> i_data_sem (rw)
+ * sb_start_write -> i_mutex -> i_mmap_sem (w) -> i_mmap_rwsem (w) -> page lock
+ * sb_start_write -> i_mutex -> i_mmap_sem (w) -> transaction start ->
+ * i_data_sem (rw)
*
* direct IO:
- * sb_start_write -> i_mutex -> EXT4_STATE_DIOREAD_LOCK (r) -> mmap_sem
- * sb_start_write -> i_mutex -> EXT4_STATE_DIOREAD_LOCK (r) ->
- * transaction start -> i_data_sem (rw)
+ * sb_start_write -> i_mutex -> mmap_sem
+ * sb_start_write -> i_mutex -> transaction start -> i_data_sem (rw)
*
* writepages:
* transaction start -> page lock(s) -> i_data_sem (rw)
@@ -448,6 +446,7 @@ void __ext4_error(struct super_block *sb, const char *function,
if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
return;
+ trace_ext4_error(sb, function, line);
if (ext4_error_ratelimit(sb)) {
va_start(args, fmt);
vaf.fmt = fmt;
@@ -472,6 +471,7 @@ void __ext4_error_inode(struct inode *inode, const char *function,
if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
return;
+ trace_ext4_error(inode->i_sb, function, line);
es->s_last_error_ino = cpu_to_le32(inode->i_ino);
es->s_last_error_block = cpu_to_le64(block);
if (ext4_error_ratelimit(inode->i_sb)) {
@@ -507,6 +507,7 @@ void __ext4_error_file(struct file *file, const char *function,
if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
return;
+ trace_ext4_error(inode->i_sb, function, line);
es = EXT4_SB(inode->i_sb)->s_es;
es->s_last_error_ino = cpu_to_le32(inode->i_ino);
if (ext4_error_ratelimit(inode->i_sb)) {
@@ -719,6 +720,7 @@ __acquires(bitlock)
if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
return;
+ trace_ext4_error(sb, function, line);
es->s_last_error_ino = cpu_to_le32(ino);
es->s_last_error_block = cpu_to_le64(block);
__save_error_info(sb, function, line);
@@ -2019,7 +2021,7 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
{
struct ext4_sb_info *sbi = EXT4_SB(sb);
struct ext4_super_block *es = sbi->s_es;
- int def_errors, def_mount_opt = nodefs ? 0 : sbi->s_def_mount_opt;
+ int def_errors, def_mount_opt = sbi->s_def_mount_opt;
const struct mount_opts *m;
char sep = nodefs ? '\n' : ',';
@@ -2034,7 +2036,7 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
if (((m->flags & (MOPT_SET|MOPT_CLEAR)) == 0) ||
(m->flags & MOPT_CLEAR_ERR))
continue;
- if (!(m->mount_opt & (sbi->s_mount_opt ^ def_mount_opt)))
+ if (!nodefs && !(m->mount_opt & (sbi->s_mount_opt ^ def_mount_opt)))
continue; /* skip if same as the default */
if ((want_set &&
(sbi->s_mount_opt & m->mount_opt) != m->mount_opt) ||
@@ -2068,7 +2070,8 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
SEQ_OPTS_PUTS("i_version");
if (nodefs || sbi->s_stripe)
SEQ_OPTS_PRINT("stripe=%lu", sbi->s_stripe);
- if (EXT4_MOUNT_DATA_FLAGS & (sbi->s_mount_opt ^ def_mount_opt)) {
+ if (nodefs || EXT4_MOUNT_DATA_FLAGS &
+ (sbi->s_mount_opt ^ def_mount_opt)) {
if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
SEQ_OPTS_PUTS("data=journal");
else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
@@ -2081,7 +2084,7 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
SEQ_OPTS_PRINT("inode_readahead_blks=%u",
sbi->s_inode_readahead_blks);
- if (nodefs || (test_opt(sb, INIT_INODE_TABLE) &&
+ if (test_opt(sb, INIT_INODE_TABLE) && (nodefs ||
(sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT)))
SEQ_OPTS_PRINT("init_itable=%u", sbi->s_li_wait_mult);
if (nodefs || sbi->s_max_dir_size_kb)
@@ -2333,6 +2336,8 @@ static int ext4_check_descriptors(struct super_block *sb,
ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
"Block bitmap for group %u overlaps "
"superblock", i);
+ if (!sb_rdonly(sb))
+ return 0;
}
if (block_bitmap < first_block || block_bitmap > last_block) {
ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
@@ -2345,6 +2350,8 @@ static int ext4_check_descriptors(struct super_block *sb,
ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
"Inode bitmap for group %u overlaps "
"superblock", i);
+ if (!sb_rdonly(sb))
+ return 0;
}
if (inode_bitmap < first_block || inode_bitmap > last_block) {
ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
@@ -2357,6 +2364,8 @@ static int ext4_check_descriptors(struct super_block *sb,
ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
"Inode table for group %u overlaps "
"superblock", i);
+ if (!sb_rdonly(sb))
+ return 0;
}
if (inode_table < first_block ||
inode_table + sbi->s_itb_per_group - 1 > last_block) {
@@ -3490,15 +3499,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
}
/* Load the checksum driver */
- if (ext4_has_feature_metadata_csum(sb) ||
- ext4_has_feature_ea_inode(sb)) {
- sbi->s_chksum_driver = crypto_alloc_shash("crc32c", 0, 0);
- if (IS_ERR(sbi->s_chksum_driver)) {
- ext4_msg(sb, KERN_ERR, "Cannot load crc32c driver.");
- ret = PTR_ERR(sbi->s_chksum_driver);
- sbi->s_chksum_driver = NULL;
- goto failed_mount;
- }
+ sbi->s_chksum_driver = crypto_alloc_shash("crc32c", 0, 0);
+ if (IS_ERR(sbi->s_chksum_driver)) {
+ ext4_msg(sb, KERN_ERR, "Cannot load crc32c driver.");
+ ret = PTR_ERR(sbi->s_chksum_driver);
+ sbi->s_chksum_driver = NULL;
+ goto failed_mount;
}
/* Check superblock checksum */
@@ -3660,6 +3666,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
ext4_msg(sb, KERN_INFO, "mounting ext2 file system "
"using the ext4 subsystem");
else {
+ /*
+ * If we're probing be silent, if this looks like
+ * it's actually an ext[34] filesystem.
+ */
+ if (silent && ext4_feature_set_ok(sb, sb_rdonly(sb)))
+ goto failed_mount;
ext4_msg(sb, KERN_ERR, "couldn't mount as ext2 due "
"to feature incompatibilities");
goto failed_mount;
@@ -3671,6 +3683,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
ext4_msg(sb, KERN_INFO, "mounting ext3 file system "
"using the ext4 subsystem");
else {
+ /*
+ * If we're probing be silent, if this looks like
+ * it's actually an ext4 filesystem.
+ */
+ if (silent && ext4_feature_set_ok(sb, sb_rdonly(sb)))
+ goto failed_mount;
ext4_msg(sb, KERN_ERR, "couldn't mount as ext3 due "
"to feature incompatibilities");
goto failed_mount;
@@ -4094,10 +4112,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
* cope, else JOURNAL_DATA
*/
if (jbd2_journal_check_available_features
- (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE))
+ (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)) {
set_opt(sb, ORDERED_DATA);
- else
+ sbi->s_def_mount_opt |= EXT4_MOUNT_ORDERED_DATA;
+ } else {
set_opt(sb, JOURNAL_DATA);
+ sbi->s_def_mount_opt |= EXT4_MOUNT_JOURNAL_DATA;
+ }
break;
case EXT4_MOUNT_ORDERED_DATA:
diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c
index 1205261f130c..9ebd26c957c2 100644
--- a/fs/ext4/sysfs.c
+++ b/fs/ext4/sysfs.c
@@ -49,8 +49,7 @@ struct ext4_attr {
} u;
};
-static ssize_t session_write_kbytes_show(struct ext4_attr *a,
- struct ext4_sb_info *sbi, char *buf)
+static ssize_t session_write_kbytes_show(struct ext4_sb_info *sbi, char *buf)
{
struct super_block *sb = sbi->s_buddy_cache->i_sb;
@@ -61,8 +60,7 @@ static ssize_t session_write_kbytes_show(struct ext4_attr *a,
sbi->s_sectors_written_start) >> 1);
}
-static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a,
- struct ext4_sb_info *sbi, char *buf)
+static ssize_t lifetime_write_kbytes_show(struct ext4_sb_info *sbi, char *buf)
{
struct super_block *sb = sbi->s_buddy_cache->i_sb;
@@ -74,8 +72,7 @@ static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a,
EXT4_SB(sb)->s_sectors_written_start) >> 1)));
}
-static ssize_t inode_readahead_blks_store(struct ext4_attr *a,
- struct ext4_sb_info *sbi,
+static ssize_t inode_readahead_blks_store(struct ext4_sb_info *sbi,
const char *buf, size_t count)
{
unsigned long t;
@@ -92,8 +89,7 @@ static ssize_t inode_readahead_blks_store(struct ext4_attr *a,
return count;
}
-static ssize_t reserved_clusters_store(struct ext4_attr *a,
- struct ext4_sb_info *sbi,
+static ssize_t reserved_clusters_store(struct ext4_sb_info *sbi,
const char *buf, size_t count)
{
unsigned long long val;
@@ -109,8 +105,7 @@ static ssize_t reserved_clusters_store(struct ext4_attr *a,
return count;
}
-static ssize_t trigger_test_error(struct ext4_attr *a,
- struct ext4_sb_info *sbi,
+static ssize_t trigger_test_error(struct ext4_sb_info *sbi,
const char *buf, size_t count)
{
int len = count;
@@ -268,9 +263,9 @@ static ssize_t ext4_attr_show(struct kobject *kobj,
(s64) EXT4_C2B(sbi,
percpu_counter_sum(&sbi->s_dirtyclusters_counter)));
case attr_session_write_kbytes:
- return session_write_kbytes_show(a, sbi, buf);
+ return session_write_kbytes_show(sbi, buf);
case attr_lifetime_write_kbytes:
- return lifetime_write_kbytes_show(a, sbi, buf);
+ return lifetime_write_kbytes_show(sbi, buf);
case attr_reserved_clusters:
return snprintf(buf, PAGE_SIZE, "%llu\n",
(unsigned long long)
@@ -306,7 +301,7 @@ static ssize_t ext4_attr_store(struct kobject *kobj,
switch (a->attr_id) {
case attr_reserved_clusters:
- return reserved_clusters_store(a, sbi, buf, len);
+ return reserved_clusters_store(sbi, buf, len);
case attr_pointer_ui:
if (!ptr)
return 0;
@@ -316,9 +311,9 @@ static ssize_t ext4_attr_store(struct kobject *kobj,
*((unsigned int *) ptr) = t;
return len;
case attr_inode_readahead:
- return inode_readahead_blks_store(a, sbi, buf, len);
+ return inode_readahead_blks_store(sbi, buf, len);
case attr_trigger_test_error:
- return trigger_test_error(a, sbi, buf, len);
+ return trigger_test_error(sbi, buf, len);
}
return 0;
}
@@ -330,13 +325,6 @@ static void ext4_sb_release(struct kobject *kobj)
complete(&sbi->s_kobj_unregister);
}
-static void ext4_kset_release(struct kobject *kobj)
-{
- struct kset *kset = container_of(kobj, struct kset, kobj);
-
- kfree(kset);
-}
-
static const struct sysfs_ops ext4_attr_ops = {
.show = ext4_attr_show,
.store = ext4_attr_store,
@@ -348,19 +336,14 @@ static struct kobj_type ext4_sb_ktype = {
.release = ext4_sb_release,
};
-static struct kobj_type ext4_ktype = {
- .sysfs_ops = &ext4_attr_ops,
- .release = ext4_kset_release,
-};
-
-static struct kset *ext4_kset;
-
static struct kobj_type ext4_feat_ktype = {
.default_attrs = ext4_feat_attrs,
.sysfs_ops = &ext4_attr_ops,
.release = (void (*)(struct kobject *))kfree,
};
+static struct kobject *ext4_root;
+
static struct kobject *ext4_feat;
#define PROC_FILE_SHOW_DEFN(name) \
@@ -398,9 +381,8 @@ int ext4_register_sysfs(struct super_block *sb)
const struct ext4_proc_files *p;
int err;
- sbi->s_kobj.kset = ext4_kset;
init_completion(&sbi->s_kobj_unregister);
- err = kobject_init_and_add(&sbi->s_kobj, &ext4_sb_ktype, NULL,
+ err = kobject_init_and_add(&sbi->s_kobj, &ext4_sb_ktype, ext4_root,
"%s", sb->s_id);
if (err) {
kobject_put(&sbi->s_kobj);
@@ -436,26 +418,18 @@ int __init ext4_init_sysfs(void)
{
int ret;
- ext4_kset = kzalloc(sizeof(*ext4_kset), GFP_KERNEL);
- if (!ext4_kset)
+ ext4_root = kobject_create_and_add("ext4", fs_kobj);
+ if (!ext4_root)
return -ENOMEM;
- kobject_set_name(&ext4_kset->kobj, "ext4");
- ext4_kset->kobj.parent = fs_kobj;
- ext4_kset->kobj.ktype = &ext4_ktype;
- ret = kset_register(ext4_kset);
- if (ret)
- goto kset_err;
-
ext4_feat = kzalloc(sizeof(*ext4_feat), GFP_KERNEL);
if (!ext4_feat) {
ret = -ENOMEM;
- goto kset_err;
+ goto root_err;
}
- ext4_feat->kset = ext4_kset;
ret = kobject_init_and_add(ext4_feat, &ext4_feat_ktype,
- NULL, "features");
+ ext4_root, "features");
if (ret)
goto feat_err;
@@ -464,17 +438,19 @@ int __init ext4_init_sysfs(void)
feat_err:
kobject_put(ext4_feat);
-kset_err:
- kset_unregister(ext4_kset);
- ext4_kset = NULL;
+ ext4_feat = NULL;
+root_err:
+ kobject_put(ext4_root);
+ ext4_root = NULL;
return ret;
}
void ext4_exit_sysfs(void)
{
kobject_put(ext4_feat);
- kset_unregister(ext4_kset);
- ext4_kset = NULL;
+ ext4_feat = NULL;
+ kobject_put(ext4_root);
+ ext4_root = NULL;
remove_proc_entry(proc_dirname, NULL);
ext4_proc_root = NULL;
}
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 63656dbafdc4..499cb4b1fbd2 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -195,10 +195,13 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end,
/* Check the values */
while (!IS_LAST_ENTRY(entry)) {
- if (entry->e_value_size != 0 &&
- entry->e_value_inum == 0) {
+ u32 size = le32_to_cpu(entry->e_value_size);
+
+ if (size > EXT4_XATTR_SIZE_MAX)
+ return -EFSCORRUPTED;
+
+ if (size != 0 && entry->e_value_inum == 0) {
u16 offs = le16_to_cpu(entry->e_value_offs);
- u32 size = le32_to_cpu(entry->e_value_size);
void *value;
/*
@@ -222,25 +225,36 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end,
}
static inline int
-ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh)
+__ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh,
+ const char *function, unsigned int line)
{
- int error;
+ int error = -EFSCORRUPTED;
if (buffer_verified(bh))
return 0;
if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
BHDR(bh)->h_blocks != cpu_to_le32(1))
- return -EFSCORRUPTED;
+ goto errout;
+ error = -EFSBADCRC;
if (!ext4_xattr_block_csum_verify(inode, bh))
- return -EFSBADCRC;
+ goto errout;
error = ext4_xattr_check_entries(BFIRST(bh), bh->b_data + bh->b_size,
bh->b_data);
- if (!error)
+errout:
+ if (error)
+ __ext4_error_inode(inode, function, line, 0,
+ "corrupted xattr block %llu",
+ (unsigned long long) bh->b_blocknr);
+ else
set_buffer_verified(bh);
return error;
}
+#define ext4_xattr_check_block(inode, bh) \
+ __ext4_xattr_check_block((inode), (bh), __func__, __LINE__)
+
+
static int
__xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header,
void *end, const char *function, unsigned int line)
@@ -262,18 +276,22 @@ errout:
__xattr_check_inode((inode), (header), (end), __func__, __LINE__)
static int
-ext4_xattr_find_entry(struct ext4_xattr_entry **pentry, int name_index,
- const char *name, int sorted)
+xattr_find_entry(struct inode *inode, struct ext4_xattr_entry **pentry,
+ void *end, int name_index, const char *name, int sorted)
{
- struct ext4_xattr_entry *entry;
+ struct ext4_xattr_entry *entry, *next;
size_t name_len;
int cmp = 1;
if (name == NULL)
return -EINVAL;
name_len = strlen(name);
- entry = *pentry;
- for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
+ for (entry = *pentry; !IS_LAST_ENTRY(entry); entry = next) {
+ next = EXT4_XATTR_NEXT(entry);
+ if ((void *) next >= end) {
+ EXT4_ERROR_INODE(inode, "corrupted xattr entries");
+ return -EFSCORRUPTED;
+ }
cmp = name_index - entry->e_name_index;
if (!cmp)
cmp = name_len - entry->e_name_len;
@@ -495,6 +513,7 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
struct buffer_head *bh = NULL;
struct ext4_xattr_entry *entry;
size_t size;
+ void *end;
int error;
struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode);
@@ -511,20 +530,20 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
goto cleanup;
ea_bdebug(bh, "b_count=%d, refcount=%d",
atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
- if (ext4_xattr_check_block(inode, bh)) {
- EXT4_ERROR_INODE(inode, "bad block %llu",
- EXT4_I(inode)->i_file_acl);
- error = -EFSCORRUPTED;
+ error = ext4_xattr_check_block(inode, bh);
+ if (error)
goto cleanup;
- }
ext4_xattr_block_cache_insert(ea_block_cache, bh);
entry = BFIRST(bh);
- error = ext4_xattr_find_entry(&entry, name_index, name, 1);
+ end = bh->b_data + bh->b_size;
+ error = xattr_find_entry(inode, &entry, end, name_index, name, 1);
if (error)
goto cleanup;
size = le32_to_cpu(entry->e_value_size);
+ error = -ERANGE;
+ if (unlikely(size > EXT4_XATTR_SIZE_MAX))
+ goto cleanup;
if (buffer) {
- error = -ERANGE;
if (size > buffer_size)
goto cleanup;
if (entry->e_value_inum) {
@@ -533,8 +552,12 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
if (error)
goto cleanup;
} else {
- memcpy(buffer, bh->b_data +
- le16_to_cpu(entry->e_value_offs), size);
+ u16 offset = le16_to_cpu(entry->e_value_offs);
+ void *p = bh->b_data + offset;
+
+ if (unlikely(p + size > end))
+ goto cleanup;
+ memcpy(buffer, p, size);
}
}
error = size;
@@ -568,12 +591,14 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
if (error)
goto cleanup;
entry = IFIRST(header);
- error = ext4_xattr_find_entry(&entry, name_index, name, 0);
+ error = xattr_find_entry(inode, &entry, end, name_index, name, 0);
if (error)
goto cleanup;
size = le32_to_cpu(entry->e_value_size);
+ error = -ERANGE;
+ if (unlikely(size > EXT4_XATTR_SIZE_MAX))
+ goto cleanup;
if (buffer) {
- error = -ERANGE;
if (size > buffer_size)
goto cleanup;
if (entry->e_value_inum) {
@@ -582,8 +607,12 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
if (error)
goto cleanup;
} else {
- memcpy(buffer, (void *)IFIRST(header) +
- le16_to_cpu(entry->e_value_offs), size);
+ u16 offset = le16_to_cpu(entry->e_value_offs);
+ void *p = (void *)IFIRST(header) + offset;
+
+ if (unlikely(p + size > end))
+ goto cleanup;
+ memcpy(buffer, p, size);
}
}
error = size;
@@ -676,12 +705,9 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
goto cleanup;
ea_bdebug(bh, "b_count=%d, refcount=%d",
atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
- if (ext4_xattr_check_block(inode, bh)) {
- EXT4_ERROR_INODE(inode, "bad block %llu",
- EXT4_I(inode)->i_file_acl);
- error = -EFSCORRUPTED;
+ error = ext4_xattr_check_block(inode, bh);
+ if (error)
goto cleanup;
- }
ext4_xattr_block_cache_insert(EA_BLOCK_CACHE(inode), bh);
error = ext4_xattr_list_entries(dentry, BFIRST(bh), buffer, buffer_size);
@@ -808,10 +834,9 @@ int ext4_get_inode_usage(struct inode *inode, qsize_t *usage)
goto out;
}
- if (ext4_xattr_check_block(inode, bh)) {
- ret = -EFSCORRUPTED;
+ ret = ext4_xattr_check_block(inode, bh);
+ if (ret)
goto out;
- }
for (entry = BFIRST(bh); !IS_LAST_ENTRY(entry);
entry = EXT4_XATTR_NEXT(entry))
@@ -1793,19 +1818,16 @@ ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i,
ea_bdebug(bs->bh, "b_count=%d, refcount=%d",
atomic_read(&(bs->bh->b_count)),
le32_to_cpu(BHDR(bs->bh)->h_refcount));
- if (ext4_xattr_check_block(inode, bs->bh)) {
- EXT4_ERROR_INODE(inode, "bad block %llu",
- EXT4_I(inode)->i_file_acl);
- error = -EFSCORRUPTED;
+ error = ext4_xattr_check_block(inode, bs->bh);
+ if (error)
goto cleanup;
- }
/* Find the named attribute. */
bs->s.base = BHDR(bs->bh);
bs->s.first = BFIRST(bs->bh);
bs->s.end = bs->bh->b_data + bs->bh->b_size;
bs->s.here = bs->s.first;
- error = ext4_xattr_find_entry(&bs->s.here, i->name_index,
- i->name, 1);
+ error = xattr_find_entry(inode, &bs->s.here, bs->s.end,
+ i->name_index, i->name, 1);
if (error && error != -ENODATA)
goto cleanup;
bs->s.not_found = error;
@@ -2164,8 +2186,8 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
if (error)
return error;
/* Find the named attribute. */
- error = ext4_xattr_find_entry(&is->s.here, i->name_index,
- i->name, 0);
+ error = xattr_find_entry(inode, &is->s.here, is->s.end,
+ i->name_index, i->name, 0);
if (error && error != -ENODATA)
return error;
is->s.not_found = error;
@@ -2721,13 +2743,9 @@ retry:
error = -EIO;
if (!bh)
goto cleanup;
- if (ext4_xattr_check_block(inode, bh)) {
- EXT4_ERROR_INODE(inode, "bad block %llu",
- EXT4_I(inode)->i_file_acl);
- error = -EFSCORRUPTED;
- brelse(bh);
+ error = ext4_xattr_check_block(inode, bh);
+ if (error)
goto cleanup;
- }
base = BHDR(bh);
end = bh->b_data + bh->b_size;
min_offs = end - base;
@@ -2884,11 +2902,8 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
goto cleanup;
}
error = ext4_xattr_check_block(inode, bh);
- if (error) {
- EXT4_ERROR_INODE(inode, "bad block %llu (error %d)",
- EXT4_I(inode)->i_file_acl, error);
+ if (error)
goto cleanup;
- }
if (ext4_has_feature_ea_inode(inode->i_sb)) {
for (entry = BFIRST(bh); !IS_LAST_ENTRY(entry);
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
index dd54c4f995c8..f39cad2abe2a 100644
--- a/fs/ext4/xattr.h
+++ b/fs/ext4/xattr.h
@@ -71,6 +71,17 @@ struct ext4_xattr_entry {
#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
/*
+ * XATTR_SIZE_MAX is currently 64k, but for the purposes of checking
+ * for file system consistency errors, we use a somewhat bigger value.
+ * This allows XATTR_SIZE_MAX to grow in the future, but by using this
+ * instead of INT_MAX for certain consistency checks, we don't need to
+ * worry about arithmetic overflows. (Actually XATTR_SIZE_MAX is
+ * defined in include/uapi/linux/limits.h, so changing it is going
+ * not going to be trivial....)
+ */
+#define EXT4_XATTR_SIZE_MAX (1 << 24)
+
+/*
* The minimum size of EA value when you start storing it in an external inode
* size of block - size of header - size of 1 entry - 4 null bytes
*/
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 2f725b4a386b..f58716567972 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -940,13 +940,13 @@ failed:
}
/**
- * gfs2_set_page_dirty - Page dirtying function
+ * jdata_set_page_dirty - Page dirtying function
* @page: The page to dirty
*
* Returns: 1 if it dirtyed the page, or 0 otherwise
*/
-static int gfs2_set_page_dirty(struct page *page)
+static int jdata_set_page_dirty(struct page *page)
{
SetPageChecked(page);
return __set_page_dirty_buffers(page);
@@ -1214,7 +1214,7 @@ static const struct address_space_operations gfs2_ordered_aops = {
.readpages = gfs2_readpages,
.write_begin = gfs2_write_begin,
.write_end = gfs2_write_end,
- .set_page_dirty = gfs2_set_page_dirty,
+ .set_page_dirty = __set_page_dirty_buffers,
.bmap = gfs2_bmap,
.invalidatepage = gfs2_invalidatepage,
.releasepage = gfs2_releasepage,
@@ -1231,7 +1231,7 @@ static const struct address_space_operations gfs2_jdata_aops = {
.readpages = gfs2_readpages,
.write_begin = gfs2_write_begin,
.write_end = gfs2_write_end,
- .set_page_dirty = gfs2_set_page_dirty,
+ .set_page_dirty = jdata_set_page_dirty,
.bmap = gfs2_bmap,
.invalidatepage = gfs2_invalidatepage,
.releasepage = gfs2_releasepage,
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 51f940e76c5e..685c305cbeb6 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -491,14 +491,12 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
- struct super_block *sb = sdp->sd_vfs;
struct buffer_head *dibh = mp->mp_bh[0];
u64 bn;
unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0;
unsigned dblks = 0;
unsigned ptrs_per_blk;
const unsigned end_of_metadata = mp->mp_fheight - 1;
- int ret;
enum alloc_state state;
__be64 *ptr;
__be64 zero_bn = 0;
@@ -607,15 +605,6 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
iomap->flags |= IOMAP_F_NEW;
while (n-- > 0)
*ptr++ = cpu_to_be64(bn++);
- if (flags & IOMAP_ZERO) {
- ret = sb_issue_zeroout(sb, iomap->addr >> inode->i_blkbits,
- dblks, GFP_NOFS);
- if (ret) {
- fs_err(sdp,
- "Failed to zero data buffers\n");
- flags &= ~IOMAP_ZERO;
- }
- }
break;
}
} while (iomap->addr == IOMAP_NULL_ADDR);
@@ -812,15 +801,22 @@ do_alloc:
}
/**
- * gfs2_block_map - Map a block from an inode to a disk block
+ * gfs2_block_map - Map one or more blocks of an inode to a disk block
* @inode: The inode
* @lblock: The logical block number
* @bh_map: The bh to be mapped
* @create: True if its ok to alloc blocks to satify the request
*
- * Sets buffer_mapped() if successful, sets buffer_boundary() if a
- * read of metadata will be required before the next block can be
- * mapped. Sets buffer_new() if new blocks were allocated.
+ * The size of the requested mapping is defined in bh_map->b_size.
+ *
+ * Clears buffer_mapped(bh_map) and leaves bh_map->b_size unchanged
+ * when @lblock is not mapped. Sets buffer_mapped(bh_map) and
+ * bh_map->b_size to indicate the size of the mapping when @lblock and
+ * successive blocks are mapped, up to the requested size.
+ *
+ * Sets buffer_boundary() if a read of metadata will be required
+ * before the next block can be mapped. Sets buffer_new() if new
+ * blocks were allocated.
*
* Returns: errno
*/
@@ -839,8 +835,6 @@ int gfs2_block_map(struct inode *inode, sector_t lblock,
if (create)
flags |= IOMAP_WRITE;
- if (buffer_zeronew(bh_map))
- flags |= IOMAP_ZERO;
ret = gfs2_iomap_begin(inode, (loff_t)lblock << inode->i_blkbits,
bh_map->b_size, flags, &iomap);
if (ret) {
@@ -1344,6 +1338,7 @@ static inline bool walk_done(struct gfs2_sbd *sdp,
static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ u64 maxsize = sdp->sd_heightsize[ip->i_height];
struct metapath mp = {};
struct buffer_head *dibh, *bh;
struct gfs2_holder rd_gh;
@@ -1359,6 +1354,14 @@ static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length)
u64 prev_bnr = 0;
__be64 *start, *end;
+ if (offset >= maxsize) {
+ /*
+ * The starting point lies beyond the allocated meta-data;
+ * there are no blocks do deallocate.
+ */
+ return 0;
+ }
+
/*
* The start position of the hole is defined by lblock, start_list, and
* start_aligned. The end position of the hole is defined by lend,
@@ -1372,7 +1375,6 @@ static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length)
*/
if (length) {
- u64 maxsize = sdp->sd_heightsize[ip->i_height];
u64 end_offset = offset + length;
u64 lend;
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 7c21aea0266b..d9fb0ad6cc30 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -1940,7 +1940,6 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
{
struct buffer_head *bh;
struct gfs2_dirent *dent;
- int error;
dent = gfs2_dirent_search(&dip->i_inode, filename, gfs2_dirent_find, &bh);
if (!dent) {
@@ -1953,18 +1952,10 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
gfs2_trans_add_meta(dip->i_gl, bh);
gfs2_inum_out(nip, dent);
dent->de_type = cpu_to_be16(new_type);
-
- if (dip->i_diskflags & GFS2_DIF_EXHASH) {
- brelse(bh);
- error = gfs2_meta_inode_buffer(dip, &bh);
- if (error)
- return error;
- gfs2_trans_add_meta(dip->i_gl, bh);
- }
+ brelse(bh);
dip->i_inode.i_mtime = dip->i_inode.i_ctime = current_time(&dip->i_inode);
- gfs2_dinode_out(dip, bh->b_data);
- brelse(bh);
+ mark_inode_dirty_sync(&dip->i_inode);
return 0;
}
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index 4f88e201b3f0..4b71f021a9e2 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -729,11 +729,12 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
int mode)
{
+ struct super_block *sb = inode->i_sb;
struct gfs2_inode *ip = GFS2_I(inode);
+ loff_t end = offset + len;
struct buffer_head *dibh;
+ struct iomap iomap;
int error;
- unsigned int nr_blks;
- sector_t lblock = offset >> inode->i_blkbits;
error = gfs2_meta_inode_buffer(ip, &dibh);
if (unlikely(error))
@@ -747,21 +748,19 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
goto out;
}
- while (len) {
- struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
- bh_map.b_size = len;
- set_buffer_zeronew(&bh_map);
-
- error = gfs2_block_map(inode, lblock, &bh_map, 1);
- if (unlikely(error))
+ while (offset < end) {
+ error = gfs2_iomap_begin(inode, offset, end - offset,
+ IOMAP_WRITE, &iomap);
+ if (error)
goto out;
- len -= bh_map.b_size;
- nr_blks = bh_map.b_size >> inode->i_blkbits;
- lblock += nr_blks;
- if (!buffer_new(&bh_map))
+ offset = iomap.offset + iomap.length;
+ if (iomap.type != IOMAP_HOLE)
continue;
- if (unlikely(!buffer_zeronew(&bh_map))) {
- error = -EIO;
+ error = sb_issue_zeroout(sb, iomap.addr >> inode->i_blkbits,
+ iomap.length >> inode->i_blkbits,
+ GFP_NOFS);
+ if (error) {
+ fs_err(GFS2_SB(inode), "Failed to zero data buffers\n");
goto out;
}
}
@@ -809,7 +808,7 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_alloc_parms ap = { .aflags = 0, };
unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
- loff_t bytes, max_bytes, max_blks = UINT_MAX;
+ loff_t bytes, max_bytes, max_blks;
int error;
const loff_t pos = offset;
const loff_t count = len;
@@ -861,7 +860,8 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t
return error;
/* ap.allowed tells us how many blocks quota will allow
* us to write. Check if this reduces max_blks */
- if (ap.allowed && ap.allowed < max_blks)
+ max_blks = UINT_MAX;
+ if (ap.allowed)
max_blks = ap.allowed;
error = gfs2_inplace_reserve(ip, &ap);
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index e0557b8a590a..1b6b1e3f5caf 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -130,15 +130,12 @@ static inline bool gfs2_rbm_eq(const struct gfs2_rbm *rbm1,
enum gfs2_state_bits {
BH_Pinned = BH_PrivateStart,
BH_Escaped = BH_PrivateStart + 1,
- BH_Zeronew = BH_PrivateStart + 2,
};
BUFFER_FNS(Pinned, pinned)
TAS_BUFFER_FNS(Pinned, pinned)
BUFFER_FNS(Escaped, escaped)
TAS_BUFFER_FNS(Escaped, escaped)
-BUFFER_FNS(Zeronew, zeronew)
-TAS_BUFFER_FNS(Zeronew, zeronew)
struct gfs2_bufdata {
struct buffer_head *bd_bh;
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 59e0560180ec..8700eb815638 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -1326,19 +1326,11 @@ static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
static int update_moved_ino(struct gfs2_inode *ip, struct gfs2_inode *ndip,
int dir_rename)
{
- int error;
- struct buffer_head *dibh;
-
if (dir_rename)
return gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR);
- error = gfs2_meta_inode_buffer(ip, &dibh);
- if (error)
- return error;
ip->i_inode.i_ctime = current_time(&ip->i_inode);
- gfs2_trans_add_meta(ip->i_gl, dibh);
- gfs2_dinode_out(ip, dibh->b_data);
- brelse(dibh);
+ mark_inode_dirty_sync(&ip->i_inode);
return 0;
}
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index cf6b46247df4..0248835625f1 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -73,7 +73,7 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
*
*/
-void gfs2_remove_from_ail(struct gfs2_bufdata *bd)
+static void gfs2_remove_from_ail(struct gfs2_bufdata *bd)
{
bd->bd_tr = NULL;
list_del_init(&bd->bd_ail_st_list);
diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h
index 93b52ac1ca1f..1862e310a067 100644
--- a/fs/gfs2/log.h
+++ b/fs/gfs2/log.h
@@ -70,7 +70,6 @@ extern void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
u32 type);
extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
-extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
extern void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc);
extern void gfs2_log_shutdown(struct gfs2_sbd *sdp);
diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h
index 5e47c935a515..836f29480be6 100644
--- a/fs/gfs2/quota.h
+++ b/fs/gfs2/quota.h
@@ -45,6 +45,8 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip,
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
int ret;
+
+ ap->allowed = UINT_MAX; /* Assume we are permitted a whole lot */
if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
return 0;
ret = gfs2_quota_lock(ip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE);
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
index b6b258998bcd..d8b622c375ab 100644
--- a/fs/gfs2/recovery.c
+++ b/fs/gfs2/recovery.c
@@ -15,6 +15,7 @@
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <linux/crc32c.h>
+#include <linux/ktime.h>
#include "gfs2.h"
#include "incore.h"
@@ -409,12 +410,13 @@ void gfs2_recover_func(struct work_struct *work)
struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
struct gfs2_log_header_host head;
struct gfs2_holder j_gh, ji_gh, thaw_gh;
- unsigned long t;
+ ktime_t t_start, t_jlck, t_jhd, t_tlck, t_rep;
int ro = 0;
unsigned int pass;
int error;
int jlocked = 0;
+ t_start = ktime_get();
if (sdp->sd_args.ar_spectator ||
(jd->jd_jid != sdp->sd_lockstruct.ls_jid)) {
fs_info(sdp, "jid=%u: Trying to acquire journal lock...\n",
@@ -446,6 +448,7 @@ void gfs2_recover_func(struct work_struct *work)
fs_info(sdp, "jid=%u, already locked for use\n", jd->jd_jid);
}
+ t_jlck = ktime_get();
fs_info(sdp, "jid=%u: Looking at journal...\n", jd->jd_jid);
error = gfs2_jdesc_check(jd);
@@ -455,13 +458,12 @@ void gfs2_recover_func(struct work_struct *work)
error = gfs2_find_jhead(jd, &head);
if (error)
goto fail_gunlock_ji;
+ t_jhd = ktime_get();
if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
fs_info(sdp, "jid=%u: Acquiring the transaction lock...\n",
jd->jd_jid);
- t = jiffies;
-
/* Acquire a shared hold on the freeze lock */
error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED,
@@ -495,6 +497,7 @@ void gfs2_recover_func(struct work_struct *work)
goto fail_gunlock_thaw;
}
+ t_tlck = ktime_get();
fs_info(sdp, "jid=%u: Replaying journal...\n", jd->jd_jid);
for (pass = 0; pass < 2; pass++) {
@@ -509,9 +512,14 @@ void gfs2_recover_func(struct work_struct *work)
clean_journal(jd, &head);
gfs2_glock_dq_uninit(&thaw_gh);
- t = DIV_ROUND_UP(jiffies - t, HZ);
- fs_info(sdp, "jid=%u: Journal replayed in %lus\n",
- jd->jd_jid, t);
+ t_rep = ktime_get();
+ fs_info(sdp, "jid=%u: Journal replayed in %lldms [jlck:%lldms, "
+ "jhead:%lldms, tlck:%lldms, replay:%lldms]\n",
+ jd->jd_jid, ktime_ms_delta(t_rep, t_start),
+ ktime_ms_delta(t_jlck, t_start),
+ ktime_ms_delta(t_jhd, t_jlck),
+ ktime_ms_delta(t_tlck, t_jhd),
+ ktime_ms_delta(t_rep, t_tlck));
}
gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_SUCCESS);
diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h
index b9318b49ff8f..cb10b95efe0f 100644
--- a/fs/gfs2/trace_gfs2.h
+++ b/fs/gfs2/trace_gfs2.h
@@ -515,6 +515,7 @@ TRACE_EVENT(gfs2_iomap_end,
__field( u64, inum )
__field( loff_t, offset )
__field( ssize_t, length )
+ __field( sector_t, pblock )
__field( u16, flags )
__field( u16, type )
__field( int, ret )
@@ -525,16 +526,20 @@ TRACE_EVENT(gfs2_iomap_end,
__entry->inum = ip->i_no_addr;
__entry->offset = iomap->offset;
__entry->length = iomap->length;
+ __entry->pblock = iomap->addr == IOMAP_NULL_ADDR ? 0 :
+ (iomap->addr >> ip->i_inode.i_blkbits);
__entry->flags = iomap->flags;
__entry->type = iomap->type;
__entry->ret = ret;
),
- TP_printk("%u,%u bmap %llu iomap end %llu/%lu ty:%d flags:%08x rc:%d",
+ TP_printk("%u,%u bmap %llu iomap end %llu/%lu to %llu ty:%d flags:%08x rc:%d",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->inum,
(unsigned long long)__entry->offset,
- (unsigned long)__entry->length, (u16)__entry->type,
+ (unsigned long)__entry->length,
+ (long long)__entry->pblock,
+ (u16)__entry->type,
(u16)__entry->flags, __entry->ret)
);
diff --git a/fs/inode.c b/fs/inode.c
index ef362364d396..b153aeaa61ea 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -346,9 +346,8 @@ void inc_nlink(struct inode *inode)
}
EXPORT_SYMBOL(inc_nlink);
-void address_space_init_once(struct address_space *mapping)
+static void __address_space_init_once(struct address_space *mapping)
{
- memset(mapping, 0, sizeof(*mapping));
INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC | __GFP_ACCOUNT);
spin_lock_init(&mapping->tree_lock);
init_rwsem(&mapping->i_mmap_rwsem);
@@ -356,6 +355,12 @@ void address_space_init_once(struct address_space *mapping)
spin_lock_init(&mapping->private_lock);
mapping->i_mmap = RB_ROOT_CACHED;
}
+
+void address_space_init_once(struct address_space *mapping)
+{
+ memset(mapping, 0, sizeof(*mapping));
+ __address_space_init_once(mapping);
+}
EXPORT_SYMBOL(address_space_init_once);
/*
@@ -371,7 +376,7 @@ void inode_init_once(struct inode *inode)
INIT_LIST_HEAD(&inode->i_io_list);
INIT_LIST_HEAD(&inode->i_wb_list);
INIT_LIST_HEAD(&inode->i_lru);
- address_space_init_once(&inode->i_data);
+ __address_space_init_once(&inode->i_data);
i_size_ordered_init(inode);
}
EXPORT_SYMBOL(inode_init_once);
@@ -1533,7 +1538,6 @@ retry:
if (atomic_dec_and_lock(&inode->i_count, &inode->i_lock)) {
if (inode->i_nlink && (inode->i_state & I_DIRTY_TIME)) {
atomic_inc(&inode->i_count);
- inode->i_state &= ~I_DIRTY_TIME;
spin_unlock(&inode->i_lock);
trace_writeback_lazytime_iput(inode);
mark_inode_dirty_sync(inode);
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 3fbf48ec2188..dfb057900e79 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -974,7 +974,7 @@ out:
}
/*
- * This is a variaon of __jbd2_update_log_tail which checks for validity of
+ * This is a variation of __jbd2_update_log_tail which checks for validity of
* provided log tail and locks j_checkpoint_mutex. So it is safe against races
* with other threads updating log tail.
*/
@@ -1417,6 +1417,9 @@ int jbd2_journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid,
journal_superblock_t *sb = journal->j_superblock;
int ret;
+ if (is_journal_aborted(journal))
+ return -EIO;
+
BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex));
jbd_debug(1, "JBD2: updating superblock (start %lu, seq %u)\n",
tail_block, tail_tid);
@@ -1483,12 +1486,15 @@ static void jbd2_mark_journal_empty(journal_t *journal, int write_op)
void jbd2_journal_update_sb_errno(journal_t *journal)
{
journal_superblock_t *sb = journal->j_superblock;
+ int errcode;
read_lock(&journal->j_state_lock);
- jbd_debug(1, "JBD2: updating superblock error (errno %d)\n",
- journal->j_errno);
- sb->s_errno = cpu_to_be32(journal->j_errno);
+ errcode = journal->j_errno;
read_unlock(&journal->j_state_lock);
+ if (errcode == -ESHUTDOWN)
+ errcode = 0;
+ jbd_debug(1, "JBD2: updating superblock error (errno %d)\n", errcode);
+ sb->s_errno = cpu_to_be32(errcode);
jbd2_write_superblock(journal, REQ_SYNC | REQ_FUA);
}
@@ -2105,12 +2111,22 @@ void __jbd2_journal_abort_hard(journal_t *journal)
* but don't do any other IO. */
static void __journal_abort_soft (journal_t *journal, int errno)
{
- if (journal->j_flags & JBD2_ABORT)
- return;
+ int old_errno;
- if (!journal->j_errno)
+ write_lock(&journal->j_state_lock);
+ old_errno = journal->j_errno;
+ if (!journal->j_errno || errno == -ESHUTDOWN)
journal->j_errno = errno;
+ if (journal->j_flags & JBD2_ABORT) {
+ write_unlock(&journal->j_state_lock);
+ if (!old_errno && old_errno != -ESHUTDOWN &&
+ errno == -ESHUTDOWN)
+ jbd2_journal_update_sb_errno(journal);
+ return;
+ }
+ write_unlock(&journal->j_state_lock);
+
__jbd2_journal_abort_hard(journal);
if (errno) {
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
index f99910b69c78..a4967b27ffb6 100644
--- a/fs/jbd2/recovery.c
+++ b/fs/jbd2/recovery.c
@@ -600,8 +600,8 @@ static int do_one_pass(journal_t *journal,
success = -EFSBADCRC;
printk(KERN_ERR "JBD2: Invalid "
"checksum recovering "
- "block %llu in log\n",
- blocknr);
+ "data block %llu in "
+ "log\n", blocknr);
block_error = 1;
goto skip_write;
}
diff --git a/fs/namei.c b/fs/namei.c
index 5c2b953c352d..a09419379f5d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1474,43 +1474,36 @@ static struct dentry *lookup_dcache(const struct qstr *name,
}
/*
- * Call i_op->lookup on the dentry. The dentry must be negative and
- * unhashed.
- *
- * dir->d_inode->i_mutex must be held
+ * Parent directory has inode locked exclusive. This is one
+ * and only case when ->lookup() gets called on non in-lookup
+ * dentries - as the matter of fact, this only gets called
+ * when directory is guaranteed to have no in-lookup children
+ * at all.
*/
-static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry,
- unsigned int flags)
-{
- struct dentry *old;
-
- /* Don't create child dentry for a dead directory. */
- if (unlikely(IS_DEADDIR(dir))) {
- dput(dentry);
- return ERR_PTR(-ENOENT);
- }
-
- old = dir->i_op->lookup(dir, dentry, flags);
- if (unlikely(old)) {
- dput(dentry);
- dentry = old;
- }
- return dentry;
-}
-
static struct dentry *__lookup_hash(const struct qstr *name,
struct dentry *base, unsigned int flags)
{
struct dentry *dentry = lookup_dcache(name, base, flags);
+ struct dentry *old;
+ struct inode *dir = base->d_inode;
if (dentry)
return dentry;
+ /* Don't create child dentry for a dead directory. */
+ if (unlikely(IS_DEADDIR(dir)))
+ return ERR_PTR(-ENOENT);
+
dentry = d_alloc(base, name);
if (unlikely(!dentry))
return ERR_PTR(-ENOMEM);
- return lookup_real(base->d_inode, dentry, flags);
+ old = dir->i_op->lookup(dir, dentry, flags);
+ if (unlikely(old)) {
+ dput(dentry);
+ dentry = old;
+ }
+ return dentry;
}
static int lookup_fast(struct nameidata *nd,
diff --git a/fs/sync.c b/fs/sync.c
index 9908a114d506..b54e0541ad89 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -192,12 +192,8 @@ int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync)
if (!file->f_op->fsync)
return -EINVAL;
- if (!datasync && (inode->i_state & I_DIRTY_TIME)) {
- spin_lock(&inode->i_lock);
- inode->i_state &= ~I_DIRTY_TIME;
- spin_unlock(&inode->i_lock);
+ if (!datasync && (inode->i_state & I_DIRTY_TIME))
mark_inode_dirty_sync(inode);
- }
return file->f_op->fsync(file, start, end, datasync);
}
EXPORT_SYMBOL(vfs_fsync_range);
diff --git a/fs/xfs/kmem.c b/fs/xfs/kmem.c
index 393b6849aeb3..7bace03dc9dc 100644
--- a/fs/xfs/kmem.c
+++ b/fs/xfs/kmem.c
@@ -46,13 +46,13 @@ kmem_alloc(size_t size, xfs_km_flags_t flags)
}
void *
-kmem_zalloc_large(size_t size, xfs_km_flags_t flags)
+kmem_alloc_large(size_t size, xfs_km_flags_t flags)
{
unsigned nofs_flag = 0;
void *ptr;
gfp_t lflags;
- ptr = kmem_zalloc(size, flags | KM_MAYFAIL);
+ ptr = kmem_alloc(size, flags | KM_MAYFAIL);
if (ptr)
return ptr;
@@ -67,7 +67,7 @@ kmem_zalloc_large(size_t size, xfs_km_flags_t flags)
nofs_flag = memalloc_nofs_save();
lflags = kmem_flags_convert(flags);
- ptr = __vmalloc(size, lflags | __GFP_ZERO, PAGE_KERNEL);
+ ptr = __vmalloc(size, lflags, PAGE_KERNEL);
if (flags & KM_NOFS)
memalloc_nofs_restore(nofs_flag);
diff --git a/fs/xfs/kmem.h b/fs/xfs/kmem.h
index 4b87472f35bc..6023b594ead7 100644
--- a/fs/xfs/kmem.h
+++ b/fs/xfs/kmem.h
@@ -71,7 +71,7 @@ kmem_flags_convert(xfs_km_flags_t flags)
}
extern void *kmem_alloc(size_t, xfs_km_flags_t);
-extern void *kmem_zalloc_large(size_t size, xfs_km_flags_t);
+extern void *kmem_alloc_large(size_t size, xfs_km_flags_t);
extern void *kmem_realloc(const void *, size_t, xfs_km_flags_t);
static inline void kmem_free(const void *ptr)
{
@@ -85,6 +85,12 @@ kmem_zalloc(size_t size, xfs_km_flags_t flags)
return kmem_alloc(size, flags | KM_ZERO);
}
+static inline void *
+kmem_zalloc_large(size_t size, xfs_km_flags_t flags)
+{
+ return kmem_alloc_large(size, flags | KM_ZERO);
+}
+
/*
* Zone interfaces
*/
diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c
index 2291f4224e24..03885a968de8 100644
--- a/fs/xfs/libxfs/xfs_ag_resv.c
+++ b/fs/xfs/libxfs/xfs_ag_resv.c
@@ -95,13 +95,13 @@ xfs_ag_resv_critical(
switch (type) {
case XFS_AG_RESV_METADATA:
- avail = pag->pagf_freeblks - pag->pag_agfl_resv.ar_reserved;
+ avail = pag->pagf_freeblks - pag->pag_rmapbt_resv.ar_reserved;
orig = pag->pag_meta_resv.ar_asked;
break;
- case XFS_AG_RESV_AGFL:
+ case XFS_AG_RESV_RMAPBT:
avail = pag->pagf_freeblks + pag->pagf_flcount -
pag->pag_meta_resv.ar_reserved;
- orig = pag->pag_agfl_resv.ar_asked;
+ orig = pag->pag_rmapbt_resv.ar_asked;
break;
default:
ASSERT(0);
@@ -126,10 +126,10 @@ xfs_ag_resv_needed(
{
xfs_extlen_t len;
- len = pag->pag_meta_resv.ar_reserved + pag->pag_agfl_resv.ar_reserved;
+ len = pag->pag_meta_resv.ar_reserved + pag->pag_rmapbt_resv.ar_reserved;
switch (type) {
case XFS_AG_RESV_METADATA:
- case XFS_AG_RESV_AGFL:
+ case XFS_AG_RESV_RMAPBT:
len -= xfs_perag_resv(pag, type)->ar_reserved;
break;
case XFS_AG_RESV_NONE:
@@ -160,10 +160,11 @@ __xfs_ag_resv_free(
if (pag->pag_agno == 0)
pag->pag_mount->m_ag_max_usable += resv->ar_asked;
/*
- * AGFL blocks are always considered "free", so whatever
- * was reserved at mount time must be given back at umount.
+ * RMAPBT blocks come from the AGFL and AGFL blocks are always
+ * considered "free", so whatever was reserved at mount time must be
+ * given back at umount.
*/
- if (type == XFS_AG_RESV_AGFL)
+ if (type == XFS_AG_RESV_RMAPBT)
oldresv = resv->ar_orig_reserved;
else
oldresv = resv->ar_reserved;
@@ -185,7 +186,7 @@ xfs_ag_resv_free(
int error;
int err2;
- error = __xfs_ag_resv_free(pag, XFS_AG_RESV_AGFL);
+ error = __xfs_ag_resv_free(pag, XFS_AG_RESV_RMAPBT);
err2 = __xfs_ag_resv_free(pag, XFS_AG_RESV_METADATA);
if (err2 && !error)
error = err2;
@@ -284,15 +285,15 @@ xfs_ag_resv_init(
}
}
- /* Create the AGFL metadata reservation */
- if (pag->pag_agfl_resv.ar_asked == 0) {
+ /* Create the RMAPBT metadata reservation */
+ if (pag->pag_rmapbt_resv.ar_asked == 0) {
ask = used = 0;
error = xfs_rmapbt_calc_reserves(mp, agno, &ask, &used);
if (error)
goto out;
- error = __xfs_ag_resv_init(pag, XFS_AG_RESV_AGFL, ask, used);
+ error = __xfs_ag_resv_init(pag, XFS_AG_RESV_RMAPBT, ask, used);
if (error)
goto out;
}
@@ -304,7 +305,7 @@ xfs_ag_resv_init(
return error;
ASSERT(xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved +
- xfs_perag_resv(pag, XFS_AG_RESV_AGFL)->ar_reserved <=
+ xfs_perag_resv(pag, XFS_AG_RESV_RMAPBT)->ar_reserved <=
pag->pagf_freeblks + pag->pagf_flcount);
#endif
out:
@@ -325,8 +326,10 @@ xfs_ag_resv_alloc_extent(
trace_xfs_ag_resv_alloc_extent(pag, type, args->len);
switch (type) {
- case XFS_AG_RESV_METADATA:
case XFS_AG_RESV_AGFL:
+ return;
+ case XFS_AG_RESV_METADATA:
+ case XFS_AG_RESV_RMAPBT:
resv = xfs_perag_resv(pag, type);
break;
default:
@@ -341,7 +344,7 @@ xfs_ag_resv_alloc_extent(
len = min_t(xfs_extlen_t, args->len, resv->ar_reserved);
resv->ar_reserved -= len;
- if (type == XFS_AG_RESV_AGFL)
+ if (type == XFS_AG_RESV_RMAPBT)
return;
/* Allocations of reserved blocks only need on-disk sb updates... */
xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_RES_FDBLOCKS, -(int64_t)len);
@@ -365,8 +368,10 @@ xfs_ag_resv_free_extent(
trace_xfs_ag_resv_free_extent(pag, type, len);
switch (type) {
- case XFS_AG_RESV_METADATA:
case XFS_AG_RESV_AGFL:
+ return;
+ case XFS_AG_RESV_METADATA:
+ case XFS_AG_RESV_RMAPBT:
resv = xfs_perag_resv(pag, type);
break;
default:
@@ -379,7 +384,7 @@ xfs_ag_resv_free_extent(
leftover = min_t(xfs_extlen_t, len, resv->ar_asked - resv->ar_reserved);
resv->ar_reserved += leftover;
- if (type == XFS_AG_RESV_AGFL)
+ if (type == XFS_AG_RESV_RMAPBT)
return;
/* Freeing into the reserved pool only requires on-disk update... */
xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FDBLOCKS, len);
diff --git a/fs/xfs/libxfs/xfs_ag_resv.h b/fs/xfs/libxfs/xfs_ag_resv.h
index 8d6c687deef3..938f2f96c5e8 100644
--- a/fs/xfs/libxfs/xfs_ag_resv.h
+++ b/fs/xfs/libxfs/xfs_ag_resv.h
@@ -32,4 +32,35 @@ void xfs_ag_resv_alloc_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type,
void xfs_ag_resv_free_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type,
struct xfs_trans *tp, xfs_extlen_t len);
+/*
+ * RMAPBT reservation accounting wrappers. Since rmapbt blocks are sourced from
+ * the AGFL, they are allocated one at a time and the reservation updates don't
+ * require a transaction.
+ */
+static inline void
+xfs_ag_resv_rmapbt_alloc(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno)
+{
+ struct xfs_alloc_arg args = {0};
+ struct xfs_perag *pag;
+
+ args.len = 1;
+ pag = xfs_perag_get(mp, agno);
+ xfs_ag_resv_alloc_extent(pag, XFS_AG_RESV_RMAPBT, &args);
+ xfs_perag_put(pag);
+}
+
+static inline void
+xfs_ag_resv_rmapbt_free(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno)
+{
+ struct xfs_perag *pag;
+
+ pag = xfs_perag_get(mp, agno);
+ xfs_ag_resv_free_extent(pag, XFS_AG_RESV_RMAPBT, NULL, 1);
+ xfs_perag_put(pag);
+}
+
#endif /* __XFS_AG_RESV_H__ */
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index c02781a4c091..39387bdd225d 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -53,6 +53,23 @@ STATIC int xfs_alloc_ag_vextent_size(xfs_alloc_arg_t *);
STATIC int xfs_alloc_ag_vextent_small(xfs_alloc_arg_t *,
xfs_btree_cur_t *, xfs_agblock_t *, xfs_extlen_t *, int *);
+/*
+ * Size of the AGFL. For CRC-enabled filesystes we steal a couple of slots in
+ * the beginning of the block for a proper header with the location information
+ * and CRC.
+ */
+unsigned int
+xfs_agfl_size(
+ struct xfs_mount *mp)
+{
+ unsigned int size = mp->m_sb.sb_sectsize;
+
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ size -= sizeof(struct xfs_agfl);
+
+ return size / sizeof(xfs_agblock_t);
+}
+
unsigned int
xfs_refc_block(
struct xfs_mount *mp)
@@ -550,7 +567,7 @@ xfs_agfl_verify(
if (bp->b_pag && be32_to_cpu(agfl->agfl_seqno) != bp->b_pag->pag_agno)
return __this_address;
- for (i = 0; i < XFS_AGFL_SIZE(mp); i++) {
+ for (i = 0; i < xfs_agfl_size(mp); i++) {
if (be32_to_cpu(agfl->agfl_bno[i]) != NULLAGBLOCK &&
be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks)
return __this_address;
@@ -1564,7 +1581,6 @@ xfs_alloc_ag_vextent_small(
int *stat) /* status: 0-freelist, 1-normal/none */
{
struct xfs_owner_info oinfo;
- struct xfs_perag *pag;
int error;
xfs_agblock_t fbno;
xfs_extlen_t flen;
@@ -1616,18 +1632,13 @@ xfs_alloc_ag_vextent_small(
/*
* If we're feeding an AGFL block to something that
* doesn't live in the free space, we need to clear
- * out the OWN_AG rmap and add the block back to
- * the AGFL per-AG reservation.
+ * out the OWN_AG rmap.
*/
xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_AG);
error = xfs_rmap_free(args->tp, args->agbp, args->agno,
fbno, 1, &oinfo);
if (error)
goto error0;
- pag = xfs_perag_get(args->mp, args->agno);
- xfs_ag_resv_free_extent(pag, XFS_AG_RESV_AGFL,
- args->tp, 1);
- xfs_perag_put(pag);
*stat = 0;
return 0;
@@ -1911,14 +1922,12 @@ xfs_free_ag_extent(
XFS_STATS_INC(mp, xs_freex);
XFS_STATS_ADD(mp, xs_freeb, len);
- trace_xfs_free_extent(mp, agno, bno, len, type == XFS_AG_RESV_AGFL,
- haveleft, haveright);
+ trace_xfs_free_extent(mp, agno, bno, len, type, haveleft, haveright);
return 0;
error0:
- trace_xfs_free_extent(mp, agno, bno, len, type == XFS_AG_RESV_AGFL,
- -1, -1);
+ trace_xfs_free_extent(mp, agno, bno, len, type, -1, -1);
if (bno_cur)
xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR);
if (cnt_cur)
@@ -2054,6 +2063,93 @@ xfs_alloc_space_available(
}
/*
+ * Check the agfl fields of the agf for inconsistency or corruption. The purpose
+ * is to detect an agfl header padding mismatch between current and early v5
+ * kernels. This problem manifests as a 1-slot size difference between the
+ * on-disk flcount and the active [first, last] range of a wrapped agfl. This
+ * may also catch variants of agfl count corruption unrelated to padding. Either
+ * way, we'll reset the agfl and warn the user.
+ *
+ * Return true if a reset is required before the agfl can be used, false
+ * otherwise.
+ */
+static bool
+xfs_agfl_needs_reset(
+ struct xfs_mount *mp,
+ struct xfs_agf *agf)
+{
+ uint32_t f = be32_to_cpu(agf->agf_flfirst);
+ uint32_t l = be32_to_cpu(agf->agf_fllast);
+ uint32_t c = be32_to_cpu(agf->agf_flcount);
+ int agfl_size = xfs_agfl_size(mp);
+ int active;
+
+ /* no agfl header on v4 supers */
+ if (!xfs_sb_version_hascrc(&mp->m_sb))
+ return false;
+
+ /*
+ * The agf read verifier catches severe corruption of these fields.
+ * Repeat some sanity checks to cover a packed -> unpacked mismatch if
+ * the verifier allows it.
+ */
+ if (f >= agfl_size || l >= agfl_size)
+ return true;
+ if (c > agfl_size)
+ return true;
+
+ /*
+ * Check consistency between the on-disk count and the active range. An
+ * agfl padding mismatch manifests as an inconsistent flcount.
+ */
+ if (c && l >= f)
+ active = l - f + 1;
+ else if (c)
+ active = agfl_size - f + l + 1;
+ else
+ active = 0;
+
+ return active != c;
+}
+
+/*
+ * Reset the agfl to an empty state. Ignore/drop any existing blocks since the
+ * agfl content cannot be trusted. Warn the user that a repair is required to
+ * recover leaked blocks.
+ *
+ * The purpose of this mechanism is to handle filesystems affected by the agfl
+ * header padding mismatch problem. A reset keeps the filesystem online with a
+ * relatively minor free space accounting inconsistency rather than suffer the
+ * inevitable crash from use of an invalid agfl block.
+ */
+static void
+xfs_agfl_reset(
+ struct xfs_trans *tp,
+ struct xfs_buf *agbp,
+ struct xfs_perag *pag)
+{
+ struct xfs_mount *mp = tp->t_mountp;
+ struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
+
+ ASSERT(pag->pagf_agflreset);
+ trace_xfs_agfl_reset(mp, agf, 0, _RET_IP_);
+
+ xfs_warn(mp,
+ "WARNING: Reset corrupted AGFL on AG %u. %d blocks leaked. "
+ "Please unmount and run xfs_repair.",
+ pag->pag_agno, pag->pagf_flcount);
+
+ agf->agf_flfirst = 0;
+ agf->agf_fllast = cpu_to_be32(xfs_agfl_size(mp) - 1);
+ agf->agf_flcount = 0;
+ xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLLAST |
+ XFS_AGF_FLCOUNT);
+
+ pag->pagf_flcount = 0;
+ pag->pagf_agflreset = false;
+}
+
+/*
* Decide whether to use this allocation group for this allocation.
* If so, fix up the btree freelist's size.
*/
@@ -2114,6 +2210,10 @@ xfs_alloc_fix_freelist(
}
}
+ /* reset a padding mismatched agfl before final free space check */
+ if (pag->pagf_agflreset)
+ xfs_agfl_reset(tp, agbp, pag);
+
/* If there isn't enough total space or single-extent, reject it. */
need = xfs_alloc_min_freelist(mp, pag);
if (!xfs_alloc_space_available(args, need, flags))
@@ -2266,10 +2366,11 @@ xfs_alloc_get_freelist(
bno = be32_to_cpu(agfl_bno[be32_to_cpu(agf->agf_flfirst)]);
be32_add_cpu(&agf->agf_flfirst, 1);
xfs_trans_brelse(tp, agflbp);
- if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp))
+ if (be32_to_cpu(agf->agf_flfirst) == xfs_agfl_size(mp))
agf->agf_flfirst = 0;
pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno));
+ ASSERT(!pag->pagf_agflreset);
be32_add_cpu(&agf->agf_flcount, -1);
xfs_trans_agflist_delta(tp, -1);
pag->pagf_flcount--;
@@ -2377,10 +2478,11 @@ xfs_alloc_put_freelist(
be32_to_cpu(agf->agf_seqno), &agflbp)))
return error;
be32_add_cpu(&agf->agf_fllast, 1);
- if (be32_to_cpu(agf->agf_fllast) == XFS_AGFL_SIZE(mp))
+ if (be32_to_cpu(agf->agf_fllast) == xfs_agfl_size(mp))
agf->agf_fllast = 0;
pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno));
+ ASSERT(!pag->pagf_agflreset);
be32_add_cpu(&agf->agf_flcount, 1);
xfs_trans_agflist_delta(tp, 1);
pag->pagf_flcount++;
@@ -2395,7 +2497,7 @@ xfs_alloc_put_freelist(
xfs_alloc_log_agf(tp, agbp, logflags);
- ASSERT(be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp));
+ ASSERT(be32_to_cpu(agf->agf_flcount) <= xfs_agfl_size(mp));
agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp);
blockp = &agfl_bno[be32_to_cpu(agf->agf_fllast)];
@@ -2428,9 +2530,9 @@ xfs_agf_verify(
if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&
be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) &&
- be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) &&
- be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) &&
- be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
+ be32_to_cpu(agf->agf_flfirst) < xfs_agfl_size(mp) &&
+ be32_to_cpu(agf->agf_fllast) < xfs_agfl_size(mp) &&
+ be32_to_cpu(agf->agf_flcount) <= xfs_agfl_size(mp)))
return __this_address;
if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) < 1 ||
@@ -2588,6 +2690,7 @@ xfs_alloc_read_agf(
pag->pagb_count = 0;
pag->pagb_tree = RB_ROOT;
pag->pagf_init = 1;
+ pag->pagf_agflreset = xfs_agfl_needs_reset(mp, agf);
}
#ifdef DEBUG
else if (!XFS_FORCED_SHUTDOWN(mp)) {
diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h
index 65a0cafe06e4..a311a2414a6b 100644
--- a/fs/xfs/libxfs/xfs_alloc.h
+++ b/fs/xfs/libxfs/xfs_alloc.h
@@ -26,6 +26,8 @@ struct xfs_trans;
extern struct workqueue_struct *xfs_alloc_wq;
+unsigned int xfs_agfl_size(struct xfs_mount *mp);
+
/*
* Freespace allocation types. Argument to xfs_alloc_[v]extent.
*/
diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
index 6840b588187e..b451649ba176 100644
--- a/fs/xfs/libxfs/xfs_alloc_btree.c
+++ b/fs/xfs/libxfs/xfs_alloc_btree.c
@@ -74,18 +74,13 @@ xfs_allocbt_alloc_block(
int error;
xfs_agblock_t bno;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-
/* Allocate the new block from the freelist. If we can't, give up. */
error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp,
&bno, 1);
- if (error) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+ if (error)
return error;
- }
if (bno == NULLAGBLOCK) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
}
@@ -95,7 +90,6 @@ xfs_allocbt_alloc_block(
xfs_trans_agbtree_delta(cur->bc_tp, 1);
new->s = cpu_to_be32(bno);
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 1;
return 0;
}
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index daae00ed30c5..3b03d886df66 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -1244,8 +1244,9 @@ xfs_iread_extents(
xfs_warn(ip->i_mount,
"corrupt dinode %Lu, (btree extents).",
(unsigned long long) ip->i_ino);
- XFS_CORRUPTION_ERROR(__func__,
- XFS_ERRLEVEL_LOW, ip->i_mount, block);
+ xfs_inode_verifier_error(ip, -EFSCORRUPTED,
+ __func__, block, sizeof(*block),
+ __this_address);
error = -EFSCORRUPTED;
goto out_brelse;
}
@@ -1261,11 +1262,15 @@ xfs_iread_extents(
*/
frp = XFS_BMBT_REC_ADDR(mp, block, 1);
for (j = 0; j < num_recs; j++, frp++, i++) {
+ xfs_failaddr_t fa;
+
xfs_bmbt_disk_get_all(frp, &new);
- if (!xfs_bmbt_validate_extent(mp, whichfork, &new)) {
- XFS_ERROR_REPORT("xfs_bmap_read_extents(2)",
- XFS_ERRLEVEL_LOW, mp);
+ fa = xfs_bmap_validate_extent(ip, whichfork, &new);
+ if (fa) {
error = -EFSCORRUPTED;
+ xfs_inode_verifier_error(ip, error,
+ "xfs_iread_extents(2)",
+ frp, sizeof(*frp), fa);
goto out_brelse;
}
xfs_iext_insert(ip, &icur, &new, state);
@@ -6154,3 +6159,39 @@ xfs_bmap_finish_one(
return error;
}
+
+/* Check that an inode's extent does not have invalid flags or bad ranges. */
+xfs_failaddr_t
+xfs_bmap_validate_extent(
+ struct xfs_inode *ip,
+ int whichfork,
+ struct xfs_bmbt_irec *irec)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ xfs_fsblock_t endfsb;
+ bool isrt;
+
+ isrt = XFS_IS_REALTIME_INODE(ip);
+ endfsb = irec->br_startblock + irec->br_blockcount - 1;
+ if (isrt) {
+ if (!xfs_verify_rtbno(mp, irec->br_startblock))
+ return __this_address;
+ if (!xfs_verify_rtbno(mp, endfsb))
+ return __this_address;
+ } else {
+ if (!xfs_verify_fsbno(mp, irec->br_startblock))
+ return __this_address;
+ if (!xfs_verify_fsbno(mp, endfsb))
+ return __this_address;
+ if (XFS_FSB_TO_AGNO(mp, irec->br_startblock) !=
+ XFS_FSB_TO_AGNO(mp, endfsb))
+ return __this_address;
+ }
+ if (irec->br_state != XFS_EXT_NORM) {
+ if (whichfork != XFS_DATA_FORK)
+ return __this_address;
+ if (!xfs_sb_version_hasextflgbit(&mp->m_sb))
+ return __this_address;
+ }
+ return NULL;
+}
diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
index e36d75799cd5..f3be6416260b 100644
--- a/fs/xfs/libxfs/xfs_bmap.h
+++ b/fs/xfs/libxfs/xfs_bmap.h
@@ -274,4 +274,7 @@ static inline int xfs_bmap_fork_to_state(int whichfork)
}
}
+xfs_failaddr_t xfs_bmap_validate_extent(struct xfs_inode *ip, int whichfork,
+ struct xfs_bmbt_irec *irec);
+
#endif /* __XFS_BMAP_H__ */
diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c
index 9faf479aba49..d89d06bea6e3 100644
--- a/fs/xfs/libxfs/xfs_bmap_btree.c
+++ b/fs/xfs/libxfs/xfs_bmap_btree.c
@@ -272,10 +272,10 @@ xfs_bmbt_alloc_block(
cur->bc_private.b.dfops->dop_low = true;
}
if (WARN_ON_ONCE(args.fsbno == NULLFSBLOCK)) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
}
+
ASSERT(args.len == 1);
cur->bc_private.b.firstblock = args.fsbno;
cur->bc_private.b.allocated++;
@@ -286,12 +286,10 @@ xfs_bmbt_alloc_block(
new->l = cpu_to_be64(args.fsbno);
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 1;
return 0;
error0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
}
diff --git a/fs/xfs/libxfs/xfs_bmap_btree.h b/fs/xfs/libxfs/xfs_bmap_btree.h
index 135b8c56d23e..e4505746ccaa 100644
--- a/fs/xfs/libxfs/xfs_bmap_btree.h
+++ b/fs/xfs/libxfs/xfs_bmap_btree.h
@@ -118,18 +118,4 @@ extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip,
extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *,
struct xfs_trans *, struct xfs_inode *, int);
-/*
- * Check that the extent does not contain an invalid unwritten extent flag.
- */
-static inline bool xfs_bmbt_validate_extent(struct xfs_mount *mp, int whichfork,
- struct xfs_bmbt_irec *irec)
-{
- if (irec->br_state == XFS_EXT_NORM)
- return true;
- if (whichfork == XFS_DATA_FORK &&
- xfs_sb_version_hasextflgbit(&mp->m_sb))
- return true;
- return false;
-}
-
#endif /* __XFS_BMAP_BTREE_H__ */
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
index 79ee4a1951d1..edc0193358a5 100644
--- a/fs/xfs/libxfs/xfs_btree.c
+++ b/fs/xfs/libxfs/xfs_btree.c
@@ -1438,8 +1438,6 @@ xfs_btree_log_keys(
int first,
int last)
{
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
- XFS_BTREE_TRACE_ARGBII(cur, bp, first, last);
if (bp) {
xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF);
@@ -1450,8 +1448,6 @@ xfs_btree_log_keys(
xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip,
xfs_ilog_fbroot(cur->bc_private.b.whichfork));
}
-
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
}
/*
@@ -1464,15 +1460,12 @@ xfs_btree_log_recs(
int first,
int last)
{
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
- XFS_BTREE_TRACE_ARGBII(cur, bp, first, last);
xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF);
xfs_trans_log_buf(cur->bc_tp, bp,
xfs_btree_rec_offset(cur, first),
xfs_btree_rec_offset(cur, last + 1) - 1);
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
}
/*
@@ -1485,8 +1478,6 @@ xfs_btree_log_ptrs(
int first, /* index of first pointer to log */
int last) /* index of last pointer to log */
{
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
- XFS_BTREE_TRACE_ARGBII(cur, bp, first, last);
if (bp) {
struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
@@ -1501,7 +1492,6 @@ xfs_btree_log_ptrs(
xfs_ilog_fbroot(cur->bc_private.b.whichfork));
}
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
}
/*
@@ -1543,9 +1533,6 @@ xfs_btree_log_block(
XFS_BTREE_LBLOCK_CRC_LEN
};
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
- XFS_BTREE_TRACE_ARGBI(cur, bp, fields);
-
if (bp) {
int nbits;
@@ -1573,8 +1560,6 @@ xfs_btree_log_block(
xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip,
xfs_ilog_fbroot(cur->bc_private.b.whichfork));
}
-
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
}
/*
@@ -1593,9 +1578,6 @@ xfs_btree_increment(
int error; /* error return value */
int lev;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
- XFS_BTREE_TRACE_ARGI(cur, level);
-
ASSERT(level < cur->bc_nlevels);
/* Read-ahead to the right at this level. */
@@ -1671,17 +1653,14 @@ xfs_btree_increment(
cur->bc_ptrs[lev] = 1;
}
out1:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 1;
return 0;
out0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
error0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
}
@@ -1701,9 +1680,6 @@ xfs_btree_decrement(
int lev;
union xfs_btree_ptr ptr;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
- XFS_BTREE_TRACE_ARGI(cur, level);
-
ASSERT(level < cur->bc_nlevels);
/* Read-ahead to the left at this level. */
@@ -1769,17 +1745,14 @@ xfs_btree_decrement(
cur->bc_ptrs[lev] = xfs_btree_get_numrecs(block);
}
out1:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 1;
return 0;
out0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
error0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
}
@@ -1881,9 +1854,6 @@ xfs_btree_lookup(
union xfs_btree_ptr *pp; /* ptr to btree block */
union xfs_btree_ptr ptr; /* ptr to btree block */
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
- XFS_BTREE_TRACE_ARGI(cur, dir);
-
XFS_BTREE_STATS_INC(cur, lookup);
/* No such thing as a zero-level tree. */
@@ -1929,7 +1899,6 @@ xfs_btree_lookup(
ASSERT(level == 0 && cur->bc_nlevels == 1);
cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
}
@@ -2004,7 +1973,6 @@ xfs_btree_lookup(
if (error)
goto error0;
XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1);
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 1;
return 0;
}
@@ -2019,11 +1987,9 @@ xfs_btree_lookup(
*stat = 1;
else
*stat = 0;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
return 0;
error0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
}
@@ -2169,10 +2135,8 @@ __xfs_btree_updkeys(
trace_xfs_btree_updkeys(cur, level, bp);
#ifdef DEBUG
error = xfs_btree_check_block(cur, block, level, bp);
- if (error) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+ if (error)
return error;
- }
#endif
ptr = cur->bc_ptrs[level];
nlkey = xfs_btree_key_addr(cur, ptr, block);
@@ -2224,9 +2188,6 @@ xfs_btree_update_keys(
if (cur->bc_flags & XFS_BTREE_OVERLAPPING)
return __xfs_btree_updkeys(cur, level, block, bp, false);
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
- XFS_BTREE_TRACE_ARGIK(cur, level, keyp);
-
/*
* Go up the tree from this level toward the root.
* At each level, update the key value to the value input.
@@ -2241,10 +2202,8 @@ xfs_btree_update_keys(
block = xfs_btree_get_block(cur, level, &bp);
#ifdef DEBUG
error = xfs_btree_check_block(cur, block, level, bp);
- if (error) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+ if (error)
return error;
- }
#endif
ptr = cur->bc_ptrs[level];
kp = xfs_btree_key_addr(cur, ptr, block);
@@ -2252,7 +2211,6 @@ xfs_btree_update_keys(
xfs_btree_log_keys(cur, bp, ptr, ptr);
}
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
return 0;
}
@@ -2272,9 +2230,6 @@ xfs_btree_update(
int ptr;
union xfs_btree_rec *rp;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
- XFS_BTREE_TRACE_ARGR(cur, rec);
-
/* Pick up the current block. */
block = xfs_btree_get_block(cur, 0, &bp);
@@ -2307,11 +2262,9 @@ xfs_btree_update(
goto error0;
}
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
return 0;
error0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
}
@@ -2339,9 +2292,6 @@ xfs_btree_lshift(
int error; /* error return value */
int i;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
- XFS_BTREE_TRACE_ARGI(cur, level);
-
if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
level == cur->bc_nlevels - 1)
goto out0;
@@ -2500,21 +2450,17 @@ xfs_btree_lshift(
/* Slide the cursor value left one. */
cur->bc_ptrs[level]--;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 1;
return 0;
out0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
error0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
error1:
- XFS_BTREE_TRACE_CURSOR(tcur, XBT_ERROR);
xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);
return error;
}
@@ -2541,9 +2487,6 @@ xfs_btree_rshift(
int error; /* error return value */
int i; /* loop counter */
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
- XFS_BTREE_TRACE_ARGI(cur, level);
-
if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
(level == cur->bc_nlevels - 1))
goto out0;
@@ -2676,21 +2619,17 @@ xfs_btree_rshift(
xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 1;
return 0;
out0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
error0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
error1:
- XFS_BTREE_TRACE_CURSOR(tcur, XBT_ERROR);
xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);
return error;
}
@@ -2726,9 +2665,6 @@ __xfs_btree_split(
int i;
#endif
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
- XFS_BTREE_TRACE_ARGIPK(cur, level, *ptrp, key);
-
XFS_BTREE_STATS_INC(cur, split);
/* Set up left block (current one). */
@@ -2878,16 +2814,13 @@ __xfs_btree_split(
(*curp)->bc_ptrs[level + 1]++;
}
*ptrp = rptr;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 1;
return 0;
out0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
error0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
}
@@ -2994,7 +2927,6 @@ xfs_btree_new_iroot(
int i; /* loop counter */
#endif
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
XFS_BTREE_STATS_INC(cur, newroot);
ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
@@ -3008,10 +2940,9 @@ xfs_btree_new_iroot(
error = cur->bc_ops->alloc_block(cur, pp, &nptr, stat);
if (error)
goto error0;
- if (*stat == 0) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
+ if (*stat == 0)
return 0;
- }
+
XFS_BTREE_STATS_INC(cur, alloc);
/* Copy the root into a real block. */
@@ -3074,10 +3005,8 @@ xfs_btree_new_iroot(
*logflags |=
XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_private.b.whichfork);
*stat = 1;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
return 0;
error0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
}
@@ -3102,7 +3031,6 @@ xfs_btree_new_root(
union xfs_btree_ptr rptr;
union xfs_btree_ptr lptr;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
XFS_BTREE_STATS_INC(cur, newroot);
/* initialise our start point from the cursor */
@@ -3202,14 +3130,11 @@ xfs_btree_new_root(
xfs_btree_setbuf(cur, cur->bc_nlevels, nbp);
cur->bc_ptrs[cur->bc_nlevels] = nptr;
cur->bc_nlevels++;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 1;
return 0;
error0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
out0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
}
@@ -3230,7 +3155,7 @@ xfs_btree_make_block_unfull(
if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
level == cur->bc_nlevels - 1) {
- struct xfs_inode *ip = cur->bc_private.b.ip;
+ struct xfs_inode *ip = cur->bc_private.b.ip;
if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) {
/* A root block that can be made bigger. */
@@ -3309,9 +3234,6 @@ xfs_btree_insrec(
#endif
xfs_daddr_t old_bn;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
- XFS_BTREE_TRACE_ARGIPR(cur, level, *ptrp, &rec);
-
ncur = NULL;
lkey = &nkey;
@@ -3324,14 +3246,12 @@ xfs_btree_insrec(
error = xfs_btree_new_root(cur, stat);
xfs_btree_set_ptr_null(cur, ptrp);
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
return error;
}
/* If we're off the left edge, return failure. */
ptr = cur->bc_ptrs[level];
if (ptr == 0) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
}
@@ -3489,12 +3409,10 @@ xfs_btree_insrec(
*curp = ncur;
}
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 1;
return 0;
error0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
}
@@ -3572,11 +3490,9 @@ xfs_btree_insert(
}
} while (!xfs_btree_ptr_is_null(cur, &nptr));
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = i;
return 0;
error0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
}
@@ -3611,8 +3527,6 @@ xfs_btree_kill_iroot(
int i;
#endif
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-
ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
ASSERT(cur->bc_nlevels > 1);
@@ -3670,19 +3584,15 @@ xfs_btree_kill_iroot(
#ifdef DEBUG
for (i = 0; i < numrecs; i++) {
error = xfs_btree_check_ptr(cur, cpp, i, level - 1);
- if (error) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+ if (error)
return error;
- }
}
#endif
xfs_btree_copy_ptrs(cur, pp, cpp, numrecs);
error = xfs_btree_free_block(cur, cbp);
- if (error) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+ if (error)
return error;
- }
cur->bc_bufs[level - 1] = NULL;
be16_add_cpu(&block->bb_level, -1);
@@ -3690,7 +3600,6 @@ xfs_btree_kill_iroot(
XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_private.b.whichfork));
cur->bc_nlevels--;
out0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
return 0;
}
@@ -3706,7 +3615,6 @@ xfs_btree_kill_root(
{
int error;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
XFS_BTREE_STATS_INC(cur, killroot);
/*
@@ -3716,16 +3624,13 @@ xfs_btree_kill_root(
cur->bc_ops->set_root(cur, newroot, -1);
error = xfs_btree_free_block(cur, bp);
- if (error) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+ if (error)
return error;
- }
cur->bc_bufs[level] = NULL;
cur->bc_ra[level] = 0;
cur->bc_nlevels--;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
return 0;
}
@@ -3744,7 +3649,6 @@ xfs_btree_dec_cursor(
return error;
}
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 1;
return 0;
}
@@ -3780,15 +3684,11 @@ xfs_btree_delrec(
struct xfs_btree_cur *tcur; /* temporary btree cursor */
int numrecs; /* temporary numrec count */
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
- XFS_BTREE_TRACE_ARGI(cur, level);
-
tcur = NULL;
/* Get the index of the entry being deleted, check for nothing there. */
ptr = cur->bc_ptrs[level];
if (ptr == 0) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
}
@@ -3805,7 +3705,6 @@ xfs_btree_delrec(
/* Fail if we're off the end of the block. */
if (ptr > numrecs) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
}
@@ -4080,7 +3979,7 @@ xfs_btree_delrec(
tcur = NULL;
if (level == 0)
cur->bc_ptrs[0]++;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
+
*stat = 1;
return 0;
}
@@ -4250,13 +4149,11 @@ xfs_btree_delrec(
* call updkeys directly.
*/
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
/* Return value means the next level up has something to do. */
*stat = 2;
return 0;
error0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
if (tcur)
xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);
return error;
@@ -4277,8 +4174,6 @@ xfs_btree_delete(
int i;
bool joined = false;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-
/*
* Go up the tree, starting at leaf level.
*
@@ -4314,11 +4209,9 @@ xfs_btree_delete(
}
}
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = i;
return 0;
error0:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
}
diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
index 50440b5618e8..58e30c0975c3 100644
--- a/fs/xfs/libxfs/xfs_btree.h
+++ b/fs/xfs/libxfs/xfs_btree.h
@@ -473,25 +473,6 @@ static inline int xfs_btree_get_level(struct xfs_btree_block *block)
#define XFS_FILBLKS_MIN(a,b) min_t(xfs_filblks_t, (a), (b))
#define XFS_FILBLKS_MAX(a,b) max_t(xfs_filblks_t, (a), (b))
-/*
- * Trace hooks. Currently not implemented as they need to be ported
- * over to the generic tracing functionality, which is some effort.
- *
- * i,j = integer (32 bit)
- * b = btree block buffer (xfs_buf_t)
- * p = btree ptr
- * r = btree record
- * k = btree key
- */
-#define XFS_BTREE_TRACE_ARGBI(c, b, i)
-#define XFS_BTREE_TRACE_ARGBII(c, b, i, j)
-#define XFS_BTREE_TRACE_ARGI(c, i)
-#define XFS_BTREE_TRACE_ARGIPK(c, i, p, s)
-#define XFS_BTREE_TRACE_ARGIPR(c, i, p, r)
-#define XFS_BTREE_TRACE_ARGIK(c, i, k)
-#define XFS_BTREE_TRACE_ARGR(c, r)
-#define XFS_BTREE_TRACE_CURSOR(c, t)
-
xfs_failaddr_t xfs_btree_sblock_v5hdr_verify(struct xfs_buf *bp);
xfs_failaddr_t xfs_btree_sblock_verify(struct xfs_buf *bp,
unsigned int max_recs);
diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
index 388d67c5c903..989e95a53db2 100644
--- a/fs/xfs/libxfs/xfs_dir2.h
+++ b/fs/xfs/libxfs/xfs_dir2.h
@@ -173,7 +173,7 @@ extern void xfs_dir2_data_log_unused(struct xfs_da_args *args,
extern void xfs_dir2_data_make_free(struct xfs_da_args *args,
struct xfs_buf *bp, xfs_dir2_data_aoff_t offset,
xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp);
-extern void xfs_dir2_data_use_free(struct xfs_da_args *args,
+extern int xfs_dir2_data_use_free(struct xfs_da_args *args,
struct xfs_buf *bp, struct xfs_dir2_data_unused *dup,
xfs_dir2_data_aoff_t offset, xfs_dir2_data_aoff_t len,
int *needlogp, int *needscanp);
diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 2da86a394bcf..875893ded514 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -451,15 +451,19 @@ xfs_dir2_block_addname(
* No stale entries, will use enddup space to hold new leaf.
*/
if (!btp->stale) {
+ xfs_dir2_data_aoff_t aoff;
+
/*
* Mark the space needed for the new leaf entry, now in use.
*/
- xfs_dir2_data_use_free(args, bp, enddup,
- (xfs_dir2_data_aoff_t)
- ((char *)enddup - (char *)hdr + be16_to_cpu(enddup->length) -
- sizeof(*blp)),
- (xfs_dir2_data_aoff_t)sizeof(*blp),
- &needlog, &needscan);
+ aoff = (xfs_dir2_data_aoff_t)((char *)enddup - (char *)hdr +
+ be16_to_cpu(enddup->length) - sizeof(*blp));
+ error = xfs_dir2_data_use_free(args, bp, enddup, aoff,
+ (xfs_dir2_data_aoff_t)sizeof(*blp), &needlog,
+ &needscan);
+ if (error)
+ return error;
+
/*
* Update the tail (entry count).
*/
@@ -541,9 +545,11 @@ xfs_dir2_block_addname(
/*
* Mark space for the data entry used.
*/
- xfs_dir2_data_use_free(args, bp, dup,
- (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
- (xfs_dir2_data_aoff_t)len, &needlog, &needscan);
+ error = xfs_dir2_data_use_free(args, bp, dup,
+ (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
+ (xfs_dir2_data_aoff_t)len, &needlog, &needscan);
+ if (error)
+ return error;
/*
* Create the new data entry.
*/
@@ -997,8 +1003,10 @@ xfs_dir2_leaf_to_block(
/*
* Use up the space at the end of the block (blp/btp).
*/
- xfs_dir2_data_use_free(args, dbp, dup, args->geo->blksize - size, size,
- &needlog, &needscan);
+ error = xfs_dir2_data_use_free(args, dbp, dup,
+ args->geo->blksize - size, size, &needlog, &needscan);
+ if (error)
+ return error;
/*
* Initialize the block tail.
*/
@@ -1110,18 +1118,14 @@ xfs_dir2_sf_to_block(
* Add block 0 to the inode.
*/
error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno);
- if (error) {
- kmem_free(sfp);
- return error;
- }
+ if (error)
+ goto out_free;
/*
* Initialize the data block, then convert it to block format.
*/
error = xfs_dir3_data_init(args, blkno, &bp);
- if (error) {
- kmem_free(sfp);
- return error;
- }
+ if (error)
+ goto out_free;
xfs_dir3_block_init(mp, tp, bp, dp);
hdr = bp->b_addr;
@@ -1136,8 +1140,10 @@ xfs_dir2_sf_to_block(
*/
dup = dp->d_ops->data_unused_p(hdr);
needlog = needscan = 0;
- xfs_dir2_data_use_free(args, bp, dup, args->geo->blksize - i,
- i, &needlog, &needscan);
+ error = xfs_dir2_data_use_free(args, bp, dup, args->geo->blksize - i,
+ i, &needlog, &needscan);
+ if (error)
+ goto out_free;
ASSERT(needscan == 0);
/*
* Fill in the tail.
@@ -1150,9 +1156,11 @@ xfs_dir2_sf_to_block(
/*
* Remove the freespace, we'll manage it.
*/
- xfs_dir2_data_use_free(args, bp, dup,
- (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
- be16_to_cpu(dup->length), &needlog, &needscan);
+ error = xfs_dir2_data_use_free(args, bp, dup,
+ (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
+ be16_to_cpu(dup->length), &needlog, &needscan);
+ if (error)
+ goto out_free;
/*
* Create entry for .
*/
@@ -1256,4 +1264,7 @@ xfs_dir2_sf_to_block(
xfs_dir2_block_log_tail(tp, bp);
xfs_dir3_data_check(dp, bp);
return 0;
+out_free:
+ kmem_free(sfp);
+ return error;
}
diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c
index 920279485275..cb67ec730b9b 100644
--- a/fs/xfs/libxfs/xfs_dir2_data.c
+++ b/fs/xfs/libxfs/xfs_dir2_data.c
@@ -932,10 +932,51 @@ xfs_dir2_data_make_free(
*needscanp = needscan;
}
+/* Check our free data for obvious signs of corruption. */
+static inline xfs_failaddr_t
+xfs_dir2_data_check_free(
+ struct xfs_dir2_data_hdr *hdr,
+ struct xfs_dir2_data_unused *dup,
+ xfs_dir2_data_aoff_t offset,
+ xfs_dir2_data_aoff_t len)
+{
+ if (hdr->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC) &&
+ hdr->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC) &&
+ hdr->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) &&
+ hdr->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
+ return __this_address;
+ if (be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG)
+ return __this_address;
+ if (offset < (char *)dup - (char *)hdr)
+ return __this_address;
+ if (offset + len > (char *)dup + be16_to_cpu(dup->length) - (char *)hdr)
+ return __this_address;
+ if ((char *)dup - (char *)hdr !=
+ be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)))
+ return __this_address;
+ return NULL;
+}
+
+/* Sanity-check a new bestfree entry. */
+static inline xfs_failaddr_t
+xfs_dir2_data_check_new_free(
+ struct xfs_dir2_data_hdr *hdr,
+ struct xfs_dir2_data_free *dfp,
+ struct xfs_dir2_data_unused *newdup)
+{
+ if (dfp == NULL)
+ return __this_address;
+ if (dfp->length != newdup->length)
+ return __this_address;
+ if (be16_to_cpu(dfp->offset) != (char *)newdup - (char *)hdr)
+ return __this_address;
+ return NULL;
+}
+
/*
* Take a byte range out of an existing unused space and make it un-free.
*/
-void
+int
xfs_dir2_data_use_free(
struct xfs_da_args *args,
struct xfs_buf *bp,
@@ -947,23 +988,19 @@ xfs_dir2_data_use_free(
{
xfs_dir2_data_hdr_t *hdr; /* data block header */
xfs_dir2_data_free_t *dfp; /* bestfree pointer */
+ xfs_dir2_data_unused_t *newdup; /* new unused entry */
+ xfs_dir2_data_unused_t *newdup2; /* another new unused entry */
+ struct xfs_dir2_data_free *bf;
+ xfs_failaddr_t fa;
int matchback; /* matches end of freespace */
int matchfront; /* matches start of freespace */
int needscan; /* need to regen bestfree */
- xfs_dir2_data_unused_t *newdup; /* new unused entry */
- xfs_dir2_data_unused_t *newdup2; /* another new unused entry */
int oldlen; /* old unused entry's length */
- struct xfs_dir2_data_free *bf;
hdr = bp->b_addr;
- ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
- hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
- hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
- hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
- ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG);
- ASSERT(offset >= (char *)dup - (char *)hdr);
- ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)hdr);
- ASSERT((char *)dup - (char *)hdr == be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
+ fa = xfs_dir2_data_check_free(hdr, dup, offset, len);
+ if (fa)
+ goto corrupt;
/*
* Look up the entry in the bestfree table.
*/
@@ -1008,9 +1045,9 @@ xfs_dir2_data_use_free(
xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup,
needlogp);
- ASSERT(dfp != NULL);
- ASSERT(dfp->length == newdup->length);
- ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
+ fa = xfs_dir2_data_check_new_free(hdr, dfp, newdup);
+ if (fa)
+ goto corrupt;
/*
* If we got inserted at the last slot,
* that means we don't know if there was a better
@@ -1036,9 +1073,9 @@ xfs_dir2_data_use_free(
xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup,
needlogp);
- ASSERT(dfp != NULL);
- ASSERT(dfp->length == newdup->length);
- ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
+ fa = xfs_dir2_data_check_new_free(hdr, dfp, newdup);
+ if (fa)
+ goto corrupt;
/*
* If we got inserted at the last slot,
* that means we don't know if there was a better
@@ -1084,6 +1121,11 @@ xfs_dir2_data_use_free(
}
}
*needscanp = needscan;
+ return 0;
+corrupt:
+ xfs_corruption_error(__func__, XFS_ERRLEVEL_LOW, args->dp->i_mount,
+ hdr, __FILE__, __LINE__, fa);
+ return -EFSCORRUPTED;
}
/* Find the end of the entry data in a data/block format dir block. */
diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
index d7e630f41f9c..50fc9c0c5e2b 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -877,9 +877,13 @@ xfs_dir2_leaf_addname(
/*
* Mark the initial part of our freespace in use for the new entry.
*/
- xfs_dir2_data_use_free(args, dbp, dup,
- (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length,
- &needlog, &needscan);
+ error = xfs_dir2_data_use_free(args, dbp, dup,
+ (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
+ length, &needlog, &needscan);
+ if (error) {
+ xfs_trans_brelse(tp, lbp);
+ return error;
+ }
/*
* Initialize our new entry (at last).
*/
@@ -1415,7 +1419,8 @@ xfs_dir2_leaf_removename(
oldbest = be16_to_cpu(bf[0].length);
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
bestsp = xfs_dir2_leaf_bests_p(ltp);
- ASSERT(be16_to_cpu(bestsp[db]) == oldbest);
+ if (be16_to_cpu(bestsp[db]) != oldbest)
+ return -EFSCORRUPTED;
/*
* Mark the former data entry unused.
*/
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index 239d97a64296..9df096cc3c37 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -387,8 +387,9 @@ xfs_dir2_leaf_to_node(
dp->d_ops->free_hdr_from_disk(&freehdr, free);
leaf = lbp->b_addr;
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
- ASSERT(be32_to_cpu(ltp->bestcount) <=
- (uint)dp->i_d.di_size / args->geo->blksize);
+ if (be32_to_cpu(ltp->bestcount) >
+ (uint)dp->i_d.di_size / args->geo->blksize)
+ return -EFSCORRUPTED;
/*
* Copy freespace entries from the leaf block to the new block.
@@ -1728,6 +1729,7 @@ xfs_dir2_node_addname_int(
__be16 *bests;
struct xfs_dir3_icfree_hdr freehdr;
struct xfs_dir2_data_free *bf;
+ xfs_dir2_data_aoff_t aoff;
dp = args->dp;
mp = dp->i_mount;
@@ -2022,9 +2024,13 @@ xfs_dir2_node_addname_int(
/*
* Mark the first part of the unused space, inuse for us.
*/
- xfs_dir2_data_use_free(args, dbp, dup,
- (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length,
- &needlog, &needscan);
+ aoff = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr);
+ error = xfs_dir2_data_use_free(args, dbp, dup, aoff, length,
+ &needlog, &needscan);
+ if (error) {
+ xfs_trans_brelse(tp, dbp);
+ return error;
+ }
/*
* Fill in the new entry and log it.
*/
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 1acb584fc5f7..42956d8d95ed 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -803,24 +803,13 @@ typedef struct xfs_agi {
&(XFS_BUF_TO_AGFL(bp)->agfl_bno[0]) : \
(__be32 *)(bp)->b_addr)
-/*
- * Size of the AGFL. For CRC-enabled filesystes we steal a couple of
- * slots in the beginning of the block for a proper header with the
- * location information and CRC.
- */
-#define XFS_AGFL_SIZE(mp) \
- (((mp)->m_sb.sb_sectsize - \
- (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \
- sizeof(struct xfs_agfl) : 0)) / \
- sizeof(xfs_agblock_t))
-
typedef struct xfs_agfl {
__be32 agfl_magicnum;
__be32 agfl_seqno;
uuid_t agfl_uuid;
__be64 agfl_lsn;
__be32 agfl_crc;
- __be32 agfl_bno[]; /* actually XFS_AGFL_SIZE(mp) */
+ __be32 agfl_bno[]; /* actually xfs_agfl_size(mp) */
} __attribute__((packed)) xfs_agfl_t;
#define XFS_AGFL_CRC_OFF offsetof(struct xfs_agfl, agfl_crc)
diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
index af197a5f3a82..a2dd7f4a2719 100644
--- a/fs/xfs/libxfs/xfs_ialloc_btree.c
+++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
@@ -93,8 +93,6 @@ __xfs_inobt_alloc_block(
int error; /* error return value */
xfs_agblock_t sbno = be32_to_cpu(start->s);
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-
memset(&args, 0, sizeof(args));
args.tp = cur->bc_tp;
args.mp = cur->bc_mp;
@@ -107,17 +105,14 @@ __xfs_inobt_alloc_block(
args.resv = resv;
error = xfs_alloc_vextent(&args);
- if (error) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+ if (error)
return error;
- }
+
if (args.fsbno == NULLFSBLOCK) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
}
ASSERT(args.len == 1);
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
new->s = cpu_to_be32(XFS_FSB_TO_AGBNO(args.mp, args.fsbno));
*stat = 1;
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index 4fe17b368316..ef68b1de006a 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -93,20 +93,26 @@ xfs_inode_buf_verify(
bool readahead)
{
struct xfs_mount *mp = bp->b_target->bt_mount;
+ xfs_agnumber_t agno;
int i;
int ni;
/*
* Validate the magic number and version of every inode in the buffer
*/
+ agno = xfs_daddr_to_agno(mp, XFS_BUF_ADDR(bp));
ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock;
for (i = 0; i < ni; i++) {
int di_ok;
xfs_dinode_t *dip;
+ xfs_agino_t unlinked_ino;
dip = xfs_buf_offset(bp, (i << mp->m_sb.sb_inodelog));
+ unlinked_ino = be32_to_cpu(dip->di_next_unlinked);
di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) &&
- xfs_dinode_good_version(mp, dip->di_version);
+ xfs_dinode_good_version(mp, dip->di_version) &&
+ (unlinked_ino == NULLAGINO ||
+ xfs_verify_agino(mp, agno, unlinked_ino));
if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
XFS_ERRTAG_ITOBP_INOTOBP))) {
if (readahead) {
@@ -115,16 +121,18 @@ xfs_inode_buf_verify(
return;
}
- xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
#ifdef DEBUG
xfs_alert(mp,
"bad inode magic/vsn daddr %lld #%d (magic=%x)",
(unsigned long long)bp->b_bn, i,
be16_to_cpu(dip->di_magic));
#endif
+ xfs_buf_verifier_error(bp, -EFSCORRUPTED,
+ __func__, dip, sizeof(*dip),
+ NULL);
+ return;
}
}
- xfs_inobp_check(mp, bp);
}
@@ -564,10 +572,7 @@ xfs_iread(
/* initialise the on-disk inode core */
memset(&ip->i_d, 0, sizeof(ip->i_d));
VFS_I(ip)->i_generation = prandom_u32();
- if (xfs_sb_version_hascrc(&mp->m_sb))
- ip->i_d.di_version = 3;
- else
- ip->i_d.di_version = 2;
+ ip->i_d.di_version = 3;
return 0;
}
@@ -649,3 +654,108 @@ xfs_iread(
xfs_trans_brelse(tp, bp);
return error;
}
+
+/*
+ * Validate di_extsize hint.
+ *
+ * The rules are documented at xfs_ioctl_setattr_check_extsize().
+ * These functions must be kept in sync with each other.
+ */
+xfs_failaddr_t
+xfs_inode_validate_extsize(
+ struct xfs_mount *mp,
+ uint32_t extsize,
+ uint16_t mode,
+ uint16_t flags)
+{
+ bool rt_flag;
+ bool hint_flag;
+ bool inherit_flag;
+ uint32_t extsize_bytes;
+ uint32_t blocksize_bytes;
+
+ rt_flag = (flags & XFS_DIFLAG_REALTIME);
+ hint_flag = (flags & XFS_DIFLAG_EXTSIZE);
+ inherit_flag = (flags & XFS_DIFLAG_EXTSZINHERIT);
+ extsize_bytes = XFS_FSB_TO_B(mp, extsize);
+
+ if (rt_flag)
+ blocksize_bytes = mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog;
+ else
+ blocksize_bytes = mp->m_sb.sb_blocksize;
+
+ if ((hint_flag || inherit_flag) && !(S_ISDIR(mode) || S_ISREG(mode)))
+ return __this_address;
+
+ if (hint_flag && !S_ISREG(mode))
+ return __this_address;
+
+ if (inherit_flag && !S_ISDIR(mode))
+ return __this_address;
+
+ if ((hint_flag || inherit_flag) && extsize == 0)
+ return __this_address;
+
+ if (!(hint_flag || inherit_flag) && extsize != 0)
+ return __this_address;
+
+ if (extsize_bytes % blocksize_bytes)
+ return __this_address;
+
+ if (extsize > MAXEXTLEN)
+ return __this_address;
+
+ if (!rt_flag && extsize > mp->m_sb.sb_agblocks / 2)
+ return __this_address;
+
+ return NULL;
+}
+
+/*
+ * Validate di_cowextsize hint.
+ *
+ * The rules are documented at xfs_ioctl_setattr_check_cowextsize().
+ * These functions must be kept in sync with each other.
+ */
+xfs_failaddr_t
+xfs_inode_validate_cowextsize(
+ struct xfs_mount *mp,
+ uint32_t cowextsize,
+ uint16_t mode,
+ uint16_t flags,
+ uint64_t flags2)
+{
+ bool rt_flag;
+ bool hint_flag;
+ uint32_t cowextsize_bytes;
+
+ rt_flag = (flags & XFS_DIFLAG_REALTIME);
+ hint_flag = (flags2 & XFS_DIFLAG2_COWEXTSIZE);
+ cowextsize_bytes = XFS_FSB_TO_B(mp, cowextsize);
+
+ if (hint_flag && !xfs_sb_version_hasreflink(&mp->m_sb))
+ return __this_address;
+
+ if (hint_flag && !(S_ISDIR(mode) || S_ISREG(mode)))
+ return __this_address;
+
+ if (hint_flag && cowextsize == 0)
+ return __this_address;
+
+ if (!hint_flag && cowextsize != 0)
+ return __this_address;
+
+ if (hint_flag && rt_flag)
+ return __this_address;
+
+ if (cowextsize_bytes % mp->m_sb.sb_blocksize)
+ return __this_address;
+
+ if (cowextsize > MAXEXTLEN)
+ return __this_address;
+
+ if (cowextsize > mp->m_sb.sb_agblocks / 2)
+ return __this_address;
+
+ return NULL;
+}
diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
index 8a5e1da52d74..d9a376a78ee2 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.h
+++ b/fs/xfs/libxfs/xfs_inode_buf.h
@@ -84,5 +84,10 @@ void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *);
xfs_failaddr_t xfs_dinode_verify(struct xfs_mount *mp, xfs_ino_t ino,
struct xfs_dinode *dip);
+xfs_failaddr_t xfs_inode_validate_extsize(struct xfs_mount *mp,
+ uint32_t extsize, uint16_t mode, uint16_t flags);
+xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
+ uint32_t cowextsize, uint16_t mode, uint16_t flags,
+ uint64_t flags2);
#endif /* __XFS_INODE_BUF_H__ */
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 866d2861c625..701c42a28d05 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -195,8 +195,9 @@ xfs_iformat_local(
"corrupt inode %Lu (bad size %d for local fork, size = %d).",
(unsigned long long) ip->i_ino, size,
XFS_DFORK_SIZE(dip, ip->i_mount, whichfork));
- XFS_CORRUPTION_ERROR("xfs_iformat_local", XFS_ERRLEVEL_LOW,
- ip->i_mount, dip);
+ xfs_inode_verifier_error(ip, -EFSCORRUPTED,
+ "xfs_iformat_local", dip, sizeof(*dip),
+ __this_address);
return -EFSCORRUPTED;
}
@@ -231,8 +232,9 @@ xfs_iformat_extents(
if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, mp, whichfork))) {
xfs_warn(ip->i_mount, "corrupt inode %Lu ((a)extents = %d).",
(unsigned long long) ip->i_ino, nex);
- XFS_CORRUPTION_ERROR("xfs_iformat_extents(1)", XFS_ERRLEVEL_LOW,
- mp, dip);
+ xfs_inode_verifier_error(ip, -EFSCORRUPTED,
+ "xfs_iformat_extents(1)", dip, sizeof(*dip),
+ __this_address);
return -EFSCORRUPTED;
}
@@ -245,10 +247,14 @@ xfs_iformat_extents(
xfs_iext_first(ifp, &icur);
for (i = 0; i < nex; i++, dp++) {
+ xfs_failaddr_t fa;
+
xfs_bmbt_disk_get_all(dp, &new);
- if (!xfs_bmbt_validate_extent(mp, whichfork, &new)) {
- XFS_ERROR_REPORT("xfs_iformat_extents(2)",
- XFS_ERRLEVEL_LOW, mp);
+ fa = xfs_bmap_validate_extent(ip, whichfork, &new);
+ if (fa) {
+ xfs_inode_verifier_error(ip, -EFSCORRUPTED,
+ "xfs_iformat_extents(2)",
+ dp, sizeof(*dp), fa);
return -EFSCORRUPTED;
}
@@ -305,8 +311,9 @@ xfs_iformat_btree(
level == 0 || level > XFS_BTREE_MAXLEVELS) {
xfs_warn(mp, "corrupt inode %Lu (btree).",
(unsigned long long) ip->i_ino);
- XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW,
- mp, dip);
+ xfs_inode_verifier_error(ip, -EFSCORRUPTED,
+ "xfs_iformat_btree", dfp, size,
+ __this_address);
return -EFSCORRUPTED;
}
@@ -595,7 +602,7 @@ xfs_iextents_copy(
for_each_xfs_iext(ifp, &icur, &rec) {
if (isnullstartblock(rec.br_startblock))
continue;
- ASSERT(xfs_bmbt_validate_extent(ip->i_mount, whichfork, &rec));
+ ASSERT(xfs_bmap_validate_extent(ip, whichfork, &rec) == NULL);
xfs_bmbt_disk_set_all(dp, &rec);
trace_xfs_write_extent(ip, &icur, state, _RET_IP_);
copied += sizeof(struct xfs_bmbt_rec);
diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
index 8479769e470d..265fdcefcbae 100644
--- a/fs/xfs/libxfs/xfs_refcount_btree.c
+++ b/fs/xfs/libxfs/xfs_refcount_btree.c
@@ -79,8 +79,6 @@ xfs_refcountbt_alloc_block(
struct xfs_alloc_arg args; /* block allocation args */
int error; /* error return value */
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-
memset(&args, 0, sizeof(args));
args.tp = cur->bc_tp;
args.mp = cur->bc_mp;
@@ -98,7 +96,6 @@ xfs_refcountbt_alloc_block(
trace_xfs_refcountbt_alloc_block(cur->bc_mp, cur->bc_private.a.agno,
args.agbno, 1);
if (args.fsbno == NULLFSBLOCK) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
}
@@ -109,12 +106,10 @@ xfs_refcountbt_alloc_block(
be32_add_cpu(&agf->agf_refcount_blocks, 1);
xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS);
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 1;
return 0;
out_error:
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
return error;
}
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
index e829c3e489ea..8b0d0de1cd11 100644
--- a/fs/xfs/libxfs/xfs_rmap_btree.c
+++ b/fs/xfs/libxfs/xfs_rmap_btree.c
@@ -104,20 +104,15 @@ xfs_rmapbt_alloc_block(
int error;
xfs_agblock_t bno;
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-
/* Allocate the new block from the freelist. If we can't, give up. */
error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp,
&bno, 1);
- if (error) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+ if (error)
return error;
- }
trace_xfs_rmapbt_alloc_block(cur->bc_mp, cur->bc_private.a.agno,
bno, 1);
if (bno == NULLAGBLOCK) {
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
*stat = 0;
return 0;
}
@@ -130,7 +125,8 @@ xfs_rmapbt_alloc_block(
be32_add_cpu(&agf->agf_rmap_blocks, 1);
xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS);
- XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
+ xfs_ag_resv_rmapbt_alloc(cur->bc_mp, cur->bc_private.a.agno);
+
*stat = 1;
return 0;
}
@@ -158,6 +154,8 @@ xfs_rmapbt_free_block(
XFS_EXTENT_BUSY_SKIP_DISCARD);
xfs_trans_agbtree_delta(cur->bc_tp, -1);
+ xfs_ag_resv_rmapbt_free(cur->bc_mp, cur->bc_private.a.agno);
+
return 0;
}
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index a55f7a45fa78..53433cc024fd 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -731,7 +731,6 @@ xfs_sb_mount_common(
struct xfs_sb *sbp)
{
mp->m_agfrotor = mp->m_agirotor = 0;
- spin_lock_init(&mp->m_agirotor_lock);
mp->m_maxagi = mp->m_sb.sb_agcount;
mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG;
mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;
diff --git a/fs/xfs/scrub/agheader.c b/fs/xfs/scrub/agheader.c
index 05c66e05ae20..018aabbd9394 100644
--- a/fs/xfs/scrub/agheader.c
+++ b/fs/xfs/scrub/agheader.c
@@ -80,7 +80,7 @@ xfs_scrub_walk_agfl(
}
/* first to the end */
- for (i = flfirst; i < XFS_AGFL_SIZE(mp); i++) {
+ for (i = flfirst; i < xfs_agfl_size(mp); i++) {
error = fn(sc, be32_to_cpu(agfl_bno[i]), priv);
if (error)
return error;
@@ -664,7 +664,7 @@ xfs_scrub_agf(
if (agfl_last > agfl_first)
fl_count = agfl_last - agfl_first + 1;
else
- fl_count = XFS_AGFL_SIZE(mp) - agfl_first + agfl_last + 1;
+ fl_count = xfs_agfl_size(mp) - agfl_first + agfl_last + 1;
if (agfl_count != 0 && fl_count != agfl_count)
xfs_scrub_block_set_corrupt(sc, sc->sa.agf_bp);
@@ -791,7 +791,7 @@ xfs_scrub_agfl(
/* Allocate buffer to ensure uniqueness of AGFL entries. */
agf = XFS_BUF_TO_AGF(sc->sa.agf_bp);
agflcount = be32_to_cpu(agf->agf_flcount);
- if (agflcount > XFS_AGFL_SIZE(sc->mp)) {
+ if (agflcount > xfs_agfl_size(sc->mp)) {
xfs_scrub_block_set_corrupt(sc, sc->sa.agf_bp);
goto out;
}
diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c
index 4ed80474f545..127575f0abfb 100644
--- a/fs/xfs/scrub/attr.c
+++ b/fs/xfs/scrub/attr.c
@@ -98,7 +98,7 @@ xfs_scrub_xattr_listent(
if (flags & XFS_ATTR_INCOMPLETE) {
/* Incomplete attr key, just mark the inode for preening. */
- xfs_scrub_ino_set_preen(sx->sc, context->dp->i_ino, NULL);
+ xfs_scrub_ino_set_preen(sx->sc, context->dp->i_ino);
return;
}
diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
index d00282130492..639d14b51e90 100644
--- a/fs/xfs/scrub/bmap.c
+++ b/fs/xfs/scrub/bmap.c
@@ -37,6 +37,7 @@
#include "xfs_bmap_util.h"
#include "xfs_bmap_btree.h"
#include "xfs_rmap.h"
+#include "xfs_rmap_btree.h"
#include "xfs_refcount.h"
#include "scrub/xfs_scrub.h"
#include "scrub/scrub.h"
@@ -423,6 +424,169 @@ xfs_scrub_bmap_btree(
return error;
}
+struct xfs_scrub_bmap_check_rmap_info {
+ struct xfs_scrub_context *sc;
+ int whichfork;
+ struct xfs_iext_cursor icur;
+};
+
+/* Can we find bmaps that fit this rmap? */
+STATIC int
+xfs_scrub_bmap_check_rmap(
+ struct xfs_btree_cur *cur,
+ struct xfs_rmap_irec *rec,
+ void *priv)
+{
+ struct xfs_bmbt_irec irec;
+ struct xfs_scrub_bmap_check_rmap_info *sbcri = priv;
+ struct xfs_ifork *ifp;
+ struct xfs_scrub_context *sc = sbcri->sc;
+ bool have_map;
+
+ /* Is this even the right fork? */
+ if (rec->rm_owner != sc->ip->i_ino)
+ return 0;
+ if ((sbcri->whichfork == XFS_ATTR_FORK) ^
+ !!(rec->rm_flags & XFS_RMAP_ATTR_FORK))
+ return 0;
+ if (rec->rm_flags & XFS_RMAP_BMBT_BLOCK)
+ return 0;
+
+ /* Now look up the bmbt record. */
+ ifp = XFS_IFORK_PTR(sc->ip, sbcri->whichfork);
+ if (!ifp) {
+ xfs_scrub_fblock_set_corrupt(sc, sbcri->whichfork,
+ rec->rm_offset);
+ goto out;
+ }
+ have_map = xfs_iext_lookup_extent(sc->ip, ifp, rec->rm_offset,
+ &sbcri->icur, &irec);
+ if (!have_map)
+ xfs_scrub_fblock_set_corrupt(sc, sbcri->whichfork,
+ rec->rm_offset);
+ /*
+ * bmap extent record lengths are constrained to 2^21 blocks in length
+ * because of space constraints in the on-disk metadata structure.
+ * However, rmap extent record lengths are constrained only by AG
+ * length, so we have to loop through the bmbt to make sure that the
+ * entire rmap is covered by bmbt records.
+ */
+ while (have_map) {
+ if (irec.br_startoff != rec->rm_offset)
+ xfs_scrub_fblock_set_corrupt(sc, sbcri->whichfork,
+ rec->rm_offset);
+ if (irec.br_startblock != XFS_AGB_TO_FSB(sc->mp,
+ cur->bc_private.a.agno, rec->rm_startblock))
+ xfs_scrub_fblock_set_corrupt(sc, sbcri->whichfork,
+ rec->rm_offset);
+ if (irec.br_blockcount > rec->rm_blockcount)
+ xfs_scrub_fblock_set_corrupt(sc, sbcri->whichfork,
+ rec->rm_offset);
+ if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
+ break;
+ rec->rm_startblock += irec.br_blockcount;
+ rec->rm_offset += irec.br_blockcount;
+ rec->rm_blockcount -= irec.br_blockcount;
+ if (rec->rm_blockcount == 0)
+ break;
+ have_map = xfs_iext_next_extent(ifp, &sbcri->icur, &irec);
+ if (!have_map)
+ xfs_scrub_fblock_set_corrupt(sc, sbcri->whichfork,
+ rec->rm_offset);
+ }
+
+out:
+ if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
+ return XFS_BTREE_QUERY_RANGE_ABORT;
+ return 0;
+}
+
+/* Make sure each rmap has a corresponding bmbt entry. */
+STATIC int
+xfs_scrub_bmap_check_ag_rmaps(
+ struct xfs_scrub_context *sc,
+ int whichfork,
+ xfs_agnumber_t agno)
+{
+ struct xfs_scrub_bmap_check_rmap_info sbcri;
+ struct xfs_btree_cur *cur;
+ struct xfs_buf *agf;
+ int error;
+
+ error = xfs_alloc_read_agf(sc->mp, sc->tp, agno, 0, &agf);
+ if (error)
+ return error;
+
+ cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno);
+ if (!cur) {
+ error = -ENOMEM;
+ goto out_agf;
+ }
+
+ sbcri.sc = sc;
+ sbcri.whichfork = whichfork;
+ error = xfs_rmap_query_all(cur, xfs_scrub_bmap_check_rmap, &sbcri);
+ if (error == XFS_BTREE_QUERY_RANGE_ABORT)
+ error = 0;
+
+ xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+out_agf:
+ xfs_trans_brelse(sc->tp, agf);
+ return error;
+}
+
+/* Make sure each rmap has a corresponding bmbt entry. */
+STATIC int
+xfs_scrub_bmap_check_rmaps(
+ struct xfs_scrub_context *sc,
+ int whichfork)
+{
+ loff_t size;
+ xfs_agnumber_t agno;
+ int error;
+
+ if (!xfs_sb_version_hasrmapbt(&sc->mp->m_sb) ||
+ whichfork == XFS_COW_FORK ||
+ (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
+ return 0;
+
+ /* Don't support realtime rmap checks yet. */
+ if (XFS_IS_REALTIME_INODE(sc->ip) && whichfork == XFS_DATA_FORK)
+ return 0;
+
+ /*
+ * Only do this for complex maps that are in btree format, or for
+ * situations where we would seem to have a size but zero extents.
+ * The inode repair code can zap broken iforks, which means we have
+ * to flag this bmap as corrupt if there are rmaps that need to be
+ * reattached.
+ */
+ switch (whichfork) {
+ case XFS_DATA_FORK:
+ size = i_size_read(VFS_I(sc->ip));
+ break;
+ case XFS_ATTR_FORK:
+ size = XFS_IFORK_Q(sc->ip);
+ break;
+ default:
+ size = 0;
+ break;
+ }
+ if (XFS_IFORK_FORMAT(sc->ip, whichfork) != XFS_DINODE_FMT_BTREE &&
+ (size == 0 || XFS_IFORK_NEXTENTS(sc->ip, whichfork) > 0))
+ return 0;
+
+ for (agno = 0; agno < sc->mp->m_sb.sb_agcount; agno++) {
+ error = xfs_scrub_bmap_check_ag_rmaps(sc, whichfork, agno);
+ if (error)
+ return error;
+ if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
+ break;
+ }
+
+ return 0;
+}
+
/*
* Scrub an inode fork's block mappings.
*
@@ -457,16 +621,16 @@ xfs_scrub_bmap(
goto out;
/* No CoW forks on non-reflink inodes/filesystems. */
if (!xfs_is_reflink_inode(ip)) {
- xfs_scrub_ino_set_corrupt(sc, sc->ip->i_ino, NULL);
+ xfs_scrub_ino_set_corrupt(sc, sc->ip->i_ino);
goto out;
}
break;
case XFS_ATTR_FORK:
if (!ifp)
- goto out;
+ goto out_check_rmap;
if (!xfs_sb_version_hasattr(&mp->m_sb) &&
!xfs_sb_version_hasattr2(&mp->m_sb))
- xfs_scrub_ino_set_corrupt(sc, sc->ip->i_ino, NULL);
+ xfs_scrub_ino_set_corrupt(sc, sc->ip->i_ino);
break;
default:
ASSERT(whichfork == XFS_DATA_FORK);
@@ -534,6 +698,10 @@ xfs_scrub_bmap(
goto out;
}
+out_check_rmap:
+ error = xfs_scrub_bmap_check_rmaps(sc, whichfork);
+ if (!xfs_scrub_fblock_xref_process_error(sc, whichfork, 0, &error))
+ goto out;
out:
return error;
}
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index 8033ab9d8f47..8ed91d5c868d 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -213,12 +213,10 @@ xfs_scrub_block_set_preen(
void
xfs_scrub_ino_set_preen(
struct xfs_scrub_context *sc,
- xfs_ino_t ino,
- struct xfs_buf *bp)
+ xfs_ino_t ino)
{
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_PREEN;
- trace_xfs_scrub_ino_preen(sc, ino, bp ? bp->b_bn : 0,
- __return_address);
+ trace_xfs_scrub_ino_preen(sc, ino, __return_address);
}
/* Record a corrupt block. */
@@ -249,22 +247,20 @@ xfs_scrub_block_xref_set_corrupt(
void
xfs_scrub_ino_set_corrupt(
struct xfs_scrub_context *sc,
- xfs_ino_t ino,
- struct xfs_buf *bp)
+ xfs_ino_t ino)
{
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
- trace_xfs_scrub_ino_error(sc, ino, bp ? bp->b_bn : 0, __return_address);
+ trace_xfs_scrub_ino_error(sc, ino, __return_address);
}
/* Record a corruption while cross-referencing with an inode. */
void
xfs_scrub_ino_xref_set_corrupt(
struct xfs_scrub_context *sc,
- xfs_ino_t ino,
- struct xfs_buf *bp)
+ xfs_ino_t ino)
{
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_XCORRUPT;
- trace_xfs_scrub_ino_error(sc, ino, bp ? bp->b_bn : 0, __return_address);
+ trace_xfs_scrub_ino_error(sc, ino, __return_address);
}
/* Record corruption in a block indexed by a file fork. */
@@ -296,12 +292,10 @@ xfs_scrub_fblock_xref_set_corrupt(
void
xfs_scrub_ino_set_warning(
struct xfs_scrub_context *sc,
- xfs_ino_t ino,
- struct xfs_buf *bp)
+ xfs_ino_t ino)
{
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_WARNING;
- trace_xfs_scrub_ino_warning(sc, ino, bp ? bp->b_bn : 0,
- __return_address);
+ trace_xfs_scrub_ino_warning(sc, ino, __return_address);
}
/* Warn about a block indexed by a file fork that needs review. */
@@ -619,7 +613,7 @@ xfs_scrub_checkpoint_log(
{
int error;
- error = _xfs_log_force(mp, XFS_LOG_SYNC, NULL);
+ error = xfs_log_force(mp, XFS_LOG_SYNC);
if (error)
return error;
xfs_ail_push_all_sync(mp->m_ail);
diff --git a/fs/xfs/scrub/common.h b/fs/xfs/scrub/common.h
index ddb65d22c76a..deaf60400981 100644
--- a/fs/xfs/scrub/common.h
+++ b/fs/xfs/scrub/common.h
@@ -63,25 +63,22 @@ bool xfs_scrub_fblock_xref_process_error(struct xfs_scrub_context *sc,
void xfs_scrub_block_set_preen(struct xfs_scrub_context *sc,
struct xfs_buf *bp);
-void xfs_scrub_ino_set_preen(struct xfs_scrub_context *sc, xfs_ino_t ino,
- struct xfs_buf *bp);
+void xfs_scrub_ino_set_preen(struct xfs_scrub_context *sc, xfs_ino_t ino);
void xfs_scrub_block_set_corrupt(struct xfs_scrub_context *sc,
struct xfs_buf *bp);
-void xfs_scrub_ino_set_corrupt(struct xfs_scrub_context *sc, xfs_ino_t ino,
- struct xfs_buf *bp);
+void xfs_scrub_ino_set_corrupt(struct xfs_scrub_context *sc, xfs_ino_t ino);
void xfs_scrub_fblock_set_corrupt(struct xfs_scrub_context *sc, int whichfork,
xfs_fileoff_t offset);
void xfs_scrub_block_xref_set_corrupt(struct xfs_scrub_context *sc,
struct xfs_buf *bp);
-void xfs_scrub_ino_xref_set_corrupt(struct xfs_scrub_context *sc, xfs_ino_t ino,
- struct xfs_buf *bp);
+void xfs_scrub_ino_xref_set_corrupt(struct xfs_scrub_context *sc,
+ xfs_ino_t ino);
void xfs_scrub_fblock_xref_set_corrupt(struct xfs_scrub_context *sc,
int whichfork, xfs_fileoff_t offset);
-void xfs_scrub_ino_set_warning(struct xfs_scrub_context *sc, xfs_ino_t ino,
- struct xfs_buf *bp);
+void xfs_scrub_ino_set_warning(struct xfs_scrub_context *sc, xfs_ino_t ino);
void xfs_scrub_fblock_set_warning(struct xfs_scrub_context *sc, int whichfork,
xfs_fileoff_t offset);
diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c
index 50b6a26b0299..38f29806eb54 100644
--- a/fs/xfs/scrub/dir.c
+++ b/fs/xfs/scrub/dir.c
@@ -781,7 +781,7 @@ xfs_scrub_directory(
/* Plausible size? */
if (sc->ip->i_d.di_size < xfs_dir2_sf_hdr_size(0)) {
- xfs_scrub_ino_set_corrupt(sc, sc->ip->i_ino, NULL);
+ xfs_scrub_ino_set_corrupt(sc, sc->ip->i_ino);
goto out;
}
diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
index 63ab3f98430d..106ca4bd753f 100644
--- a/fs/xfs/scrub/ialloc.c
+++ b/fs/xfs/scrub/ialloc.c
@@ -259,7 +259,8 @@ xfs_scrub_iallocbt_check_freemask(
error = xfs_imap_to_bp(mp, bs->cur->bc_tp, &imap,
&dip, &bp, 0, 0);
- if (!xfs_scrub_btree_process_error(bs->sc, bs->cur, 0, &error))
+ if (!xfs_scrub_btree_xref_process_error(bs->sc, bs->cur, 0,
+ &error))
continue;
/* Which inodes are free? */
@@ -433,7 +434,7 @@ xfs_scrub_iallocbt_xref_rmap_inodes(
if (!xfs_scrub_should_check_xref(sc, &error, &sc->sa.rmap_cur))
return;
if (blocks != inode_blocks)
- xfs_scrub_btree_set_corrupt(sc, sc->sa.ino_cur, 0);
+ xfs_scrub_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0);
}
/* Scrub the inode btrees for some AG. */
diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
index 21297bef8df1..df14930e4fc5 100644
--- a/fs/xfs/scrub/inode.c
+++ b/fs/xfs/scrub/inode.c
@@ -89,67 +89,21 @@ out:
/* Inode core */
-/*
- * Validate di_extsize hint.
- *
- * The rules are documented at xfs_ioctl_setattr_check_extsize().
- * These functions must be kept in sync with each other.
- */
+/* Validate di_extsize hint. */
STATIC void
xfs_scrub_inode_extsize(
struct xfs_scrub_context *sc,
- struct xfs_buf *bp,
struct xfs_dinode *dip,
xfs_ino_t ino,
uint16_t mode,
uint16_t flags)
{
- struct xfs_mount *mp = sc->mp;
- bool rt_flag;
- bool hint_flag;
- bool inherit_flag;
- uint32_t extsize;
- uint32_t extsize_bytes;
- uint32_t blocksize_bytes;
-
- rt_flag = (flags & XFS_DIFLAG_REALTIME);
- hint_flag = (flags & XFS_DIFLAG_EXTSIZE);
- inherit_flag = (flags & XFS_DIFLAG_EXTSZINHERIT);
- extsize = be32_to_cpu(dip->di_extsize);
- extsize_bytes = XFS_FSB_TO_B(sc->mp, extsize);
-
- if (rt_flag)
- blocksize_bytes = mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog;
- else
- blocksize_bytes = mp->m_sb.sb_blocksize;
-
- if ((hint_flag || inherit_flag) && !(S_ISDIR(mode) || S_ISREG(mode)))
- goto bad;
-
- if (hint_flag && !S_ISREG(mode))
- goto bad;
-
- if (inherit_flag && !S_ISDIR(mode))
- goto bad;
-
- if ((hint_flag || inherit_flag) && extsize == 0)
- goto bad;
-
- if (!(hint_flag || inherit_flag) && extsize != 0)
- goto bad;
-
- if (extsize_bytes % blocksize_bytes)
- goto bad;
-
- if (extsize > MAXEXTLEN)
- goto bad;
+ xfs_failaddr_t fa;
- if (!rt_flag && extsize > mp->m_sb.sb_agblocks / 2)
- goto bad;
-
- return;
-bad:
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ fa = xfs_inode_validate_extsize(sc->mp, be32_to_cpu(dip->di_extsize),
+ mode, flags);
+ if (fa)
+ xfs_scrub_ino_set_corrupt(sc, ino);
}
/*
@@ -161,58 +115,25 @@ bad:
STATIC void
xfs_scrub_inode_cowextsize(
struct xfs_scrub_context *sc,
- struct xfs_buf *bp,
struct xfs_dinode *dip,
xfs_ino_t ino,
uint16_t mode,
uint16_t flags,
uint64_t flags2)
{
- struct xfs_mount *mp = sc->mp;
- bool rt_flag;
- bool hint_flag;
- uint32_t extsize;
- uint32_t extsize_bytes;
-
- rt_flag = (flags & XFS_DIFLAG_REALTIME);
- hint_flag = (flags2 & XFS_DIFLAG2_COWEXTSIZE);
- extsize = be32_to_cpu(dip->di_cowextsize);
- extsize_bytes = XFS_FSB_TO_B(sc->mp, extsize);
-
- if (hint_flag && !xfs_sb_version_hasreflink(&mp->m_sb))
- goto bad;
-
- if (hint_flag && !(S_ISDIR(mode) || S_ISREG(mode)))
- goto bad;
-
- if (hint_flag && extsize == 0)
- goto bad;
-
- if (!hint_flag && extsize != 0)
- goto bad;
-
- if (hint_flag && rt_flag)
- goto bad;
-
- if (extsize_bytes % mp->m_sb.sb_blocksize)
- goto bad;
-
- if (extsize > MAXEXTLEN)
- goto bad;
-
- if (extsize > mp->m_sb.sb_agblocks / 2)
- goto bad;
+ xfs_failaddr_t fa;
- return;
-bad:
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ fa = xfs_inode_validate_cowextsize(sc->mp,
+ be32_to_cpu(dip->di_cowextsize), mode, flags,
+ flags2);
+ if (fa)
+ xfs_scrub_ino_set_corrupt(sc, ino);
}
/* Make sure the di_flags make sense for the inode. */
STATIC void
xfs_scrub_inode_flags(
struct xfs_scrub_context *sc,
- struct xfs_buf *bp,
struct xfs_dinode *dip,
xfs_ino_t ino,
uint16_t mode,
@@ -251,14 +172,13 @@ xfs_scrub_inode_flags(
return;
bad:
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
}
/* Make sure the di_flags2 make sense for the inode. */
STATIC void
xfs_scrub_inode_flags2(
struct xfs_scrub_context *sc,
- struct xfs_buf *bp,
struct xfs_dinode *dip,
xfs_ino_t ino,
uint16_t mode,
@@ -295,14 +215,13 @@ xfs_scrub_inode_flags2(
return;
bad:
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
}
/* Scrub all the ondisk inode fields. */
STATIC void
xfs_scrub_dinode(
struct xfs_scrub_context *sc,
- struct xfs_buf *bp,
struct xfs_dinode *dip,
xfs_ino_t ino)
{
@@ -333,7 +252,7 @@ xfs_scrub_dinode(
/* mode is recognized */
break;
default:
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
break;
}
@@ -344,22 +263,22 @@ xfs_scrub_dinode(
* We autoconvert v1 inodes into v2 inodes on writeout,
* so just mark this inode for preening.
*/
- xfs_scrub_ino_set_preen(sc, ino, bp);
+ xfs_scrub_ino_set_preen(sc, ino);
break;
case 2:
case 3:
if (dip->di_onlink != 0)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
if (dip->di_mode == 0 && sc->ip)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
if (dip->di_projid_hi != 0 &&
!xfs_sb_version_hasprojid32bit(&mp->m_sb))
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
break;
default:
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
return;
}
@@ -369,40 +288,40 @@ xfs_scrub_dinode(
*/
if (dip->di_uid == cpu_to_be32(-1U) ||
dip->di_gid == cpu_to_be32(-1U))
- xfs_scrub_ino_set_warning(sc, ino, bp);
+ xfs_scrub_ino_set_warning(sc, ino);
/* di_format */
switch (dip->di_format) {
case XFS_DINODE_FMT_DEV:
if (!S_ISCHR(mode) && !S_ISBLK(mode) &&
!S_ISFIFO(mode) && !S_ISSOCK(mode))
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
break;
case XFS_DINODE_FMT_LOCAL:
if (!S_ISDIR(mode) && !S_ISLNK(mode))
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
break;
case XFS_DINODE_FMT_EXTENTS:
if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode))
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
break;
case XFS_DINODE_FMT_BTREE:
if (!S_ISREG(mode) && !S_ISDIR(mode))
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
break;
case XFS_DINODE_FMT_UUID:
default:
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
break;
}
/* di_[amc]time.nsec */
if (be32_to_cpu(dip->di_atime.t_nsec) >= NSEC_PER_SEC)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
if (be32_to_cpu(dip->di_mtime.t_nsec) >= NSEC_PER_SEC)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
if (be32_to_cpu(dip->di_ctime.t_nsec) >= NSEC_PER_SEC)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
/*
* di_size. xfs_dinode_verify checks for things that screw up
@@ -411,19 +330,19 @@ xfs_scrub_dinode(
*/
isize = be64_to_cpu(dip->di_size);
if (isize & (1ULL << 63))
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
/* Devices, fifos, and sockets must have zero size */
if (!S_ISDIR(mode) && !S_ISREG(mode) && !S_ISLNK(mode) && isize != 0)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
/* Directories can't be larger than the data section size (32G) */
if (S_ISDIR(mode) && (isize == 0 || isize >= XFS_DIR2_SPACE_SIZE))
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
/* Symlinks can't be larger than SYMLINK_MAXLEN */
if (S_ISLNK(mode) && (isize == 0 || isize >= XFS_SYMLINK_MAXLEN))
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
/*
* Warn if the running kernel can't handle the kinds of offsets
@@ -432,7 +351,7 @@ xfs_scrub_dinode(
* overly large offsets, flag the inode for admin review.
*/
if (isize >= mp->m_super->s_maxbytes)
- xfs_scrub_ino_set_warning(sc, ino, bp);
+ xfs_scrub_ino_set_warning(sc, ino);
/* di_nblocks */
if (flags2 & XFS_DIFLAG2_REFLINK) {
@@ -447,15 +366,15 @@ xfs_scrub_dinode(
*/
if (be64_to_cpu(dip->di_nblocks) >=
mp->m_sb.sb_dblocks + mp->m_sb.sb_rblocks)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
} else {
if (be64_to_cpu(dip->di_nblocks) >= mp->m_sb.sb_dblocks)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
}
- xfs_scrub_inode_flags(sc, bp, dip, ino, mode, flags);
+ xfs_scrub_inode_flags(sc, dip, ino, mode, flags);
- xfs_scrub_inode_extsize(sc, bp, dip, ino, mode, flags);
+ xfs_scrub_inode_extsize(sc, dip, ino, mode, flags);
/* di_nextents */
nextents = be32_to_cpu(dip->di_nextents);
@@ -463,31 +382,31 @@ xfs_scrub_dinode(
switch (dip->di_format) {
case XFS_DINODE_FMT_EXTENTS:
if (nextents > fork_recs)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
break;
case XFS_DINODE_FMT_BTREE:
if (nextents <= fork_recs)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
break;
default:
if (nextents != 0)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
break;
}
/* di_forkoff */
if (XFS_DFORK_APTR(dip) >= (char *)dip + mp->m_sb.sb_inodesize)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
if (dip->di_anextents != 0 && dip->di_forkoff == 0)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
if (dip->di_forkoff == 0 && dip->di_aformat != XFS_DINODE_FMT_EXTENTS)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
/* di_aformat */
if (dip->di_aformat != XFS_DINODE_FMT_LOCAL &&
dip->di_aformat != XFS_DINODE_FMT_EXTENTS &&
dip->di_aformat != XFS_DINODE_FMT_BTREE)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
/* di_anextents */
nextents = be16_to_cpu(dip->di_anextents);
@@ -495,92 +414,26 @@ xfs_scrub_dinode(
switch (dip->di_aformat) {
case XFS_DINODE_FMT_EXTENTS:
if (nextents > fork_recs)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
break;
case XFS_DINODE_FMT_BTREE:
if (nextents <= fork_recs)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
break;
default:
if (nextents != 0)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
}
if (dip->di_version >= 3) {
if (be32_to_cpu(dip->di_crtime.t_nsec) >= NSEC_PER_SEC)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
- xfs_scrub_inode_flags2(sc, bp, dip, ino, mode, flags, flags2);
- xfs_scrub_inode_cowextsize(sc, bp, dip, ino, mode, flags,
+ xfs_scrub_ino_set_corrupt(sc, ino);
+ xfs_scrub_inode_flags2(sc, dip, ino, mode, flags, flags2);
+ xfs_scrub_inode_cowextsize(sc, dip, ino, mode, flags,
flags2);
}
}
-/* Map and read a raw inode. */
-STATIC int
-xfs_scrub_inode_map_raw(
- struct xfs_scrub_context *sc,
- xfs_ino_t ino,
- struct xfs_buf **bpp,
- struct xfs_dinode **dipp)
-{
- struct xfs_imap imap;
- struct xfs_mount *mp = sc->mp;
- struct xfs_buf *bp = NULL;
- struct xfs_dinode *dip;
- int error;
-
- error = xfs_imap(mp, sc->tp, ino, &imap, XFS_IGET_UNTRUSTED);
- if (error == -EINVAL) {
- /*
- * Inode could have gotten deleted out from under us;
- * just forget about it.
- */
- error = -ENOENT;
- goto out;
- }
- if (!xfs_scrub_process_error(sc, XFS_INO_TO_AGNO(mp, ino),
- XFS_INO_TO_AGBNO(mp, ino), &error))
- goto out;
-
- error = xfs_trans_read_buf(mp, sc->tp, mp->m_ddev_targp,
- imap.im_blkno, imap.im_len, XBF_UNMAPPED, &bp,
- NULL);
- if (!xfs_scrub_process_error(sc, XFS_INO_TO_AGNO(mp, ino),
- XFS_INO_TO_AGBNO(mp, ino), &error))
- goto out;
-
- /*
- * Is this really an inode? We disabled verifiers in the above
- * xfs_trans_read_buf call because the inode buffer verifier
- * fails on /any/ inode record in the inode cluster with a bad
- * magic or version number, not just the one that we're
- * checking. Therefore, grab the buffer unconditionally, attach
- * the inode verifiers by hand, and run the inode verifier only
- * on the one inode we want.
- */
- bp->b_ops = &xfs_inode_buf_ops;
- dip = xfs_buf_offset(bp, imap.im_boffset);
- if (xfs_dinode_verify(mp, ino, dip) != NULL ||
- !xfs_dinode_good_version(mp, dip->di_version)) {
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
- goto out_buf;
- }
-
- /* ...and is it the one we asked for? */
- if (be32_to_cpu(dip->di_gen) != sc->sm->sm_gen) {
- error = -ENOENT;
- goto out_buf;
- }
-
- *dipp = dip;
- *bpp = bp;
-out:
- return error;
-out_buf:
- xfs_trans_brelse(sc->tp, bp);
- return error;
-}
-
/*
* Make sure the finobt doesn't think this inode is free.
* We don't have to check the inobt ourselves because we got the inode via
@@ -645,18 +498,18 @@ xfs_scrub_inode_xref_bmap(
if (!xfs_scrub_should_check_xref(sc, &error, NULL))
return;
if (nextents < be32_to_cpu(dip->di_nextents))
- xfs_scrub_ino_xref_set_corrupt(sc, sc->ip->i_ino, NULL);
+ xfs_scrub_ino_xref_set_corrupt(sc, sc->ip->i_ino);
error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_ATTR_FORK,
&nextents, &acount);
if (!xfs_scrub_should_check_xref(sc, &error, NULL))
return;
if (nextents != be16_to_cpu(dip->di_anextents))
- xfs_scrub_ino_xref_set_corrupt(sc, sc->ip->i_ino, NULL);
+ xfs_scrub_ino_xref_set_corrupt(sc, sc->ip->i_ino);
/* Check nblocks against the inode. */
if (count + acount != be64_to_cpu(dip->di_nblocks))
- xfs_scrub_ino_xref_set_corrupt(sc, sc->ip->i_ino, NULL);
+ xfs_scrub_ino_xref_set_corrupt(sc, sc->ip->i_ino);
}
/* Cross-reference with the other btrees. */
@@ -700,8 +553,7 @@ xfs_scrub_inode_xref(
static void
xfs_scrub_inode_check_reflink_iflag(
struct xfs_scrub_context *sc,
- xfs_ino_t ino,
- struct xfs_buf *bp)
+ xfs_ino_t ino)
{
struct xfs_mount *mp = sc->mp;
bool has_shared;
@@ -716,9 +568,9 @@ xfs_scrub_inode_check_reflink_iflag(
XFS_INO_TO_AGBNO(mp, ino), &error))
return;
if (xfs_is_reflink_inode(sc->ip) && !has_shared)
- xfs_scrub_ino_set_preen(sc, ino, bp);
+ xfs_scrub_ino_set_preen(sc, ino);
else if (!xfs_is_reflink_inode(sc->ip) && has_shared)
- xfs_scrub_ino_set_corrupt(sc, ino, bp);
+ xfs_scrub_ino_set_corrupt(sc, ino);
}
/* Scrub an inode. */
@@ -727,43 +579,33 @@ xfs_scrub_inode(
struct xfs_scrub_context *sc)
{
struct xfs_dinode di;
- struct xfs_buf *bp = NULL;
- struct xfs_dinode *dip;
- xfs_ino_t ino;
int error = 0;
- /* Did we get the in-core inode, or are we doing this manually? */
- if (sc->ip) {
- ino = sc->ip->i_ino;
- xfs_inode_to_disk(sc->ip, &di, 0);
- dip = &di;
- } else {
- /* Map & read inode. */
- ino = sc->sm->sm_ino;
- error = xfs_scrub_inode_map_raw(sc, ino, &bp, &dip);
- if (error || !bp)
- goto out;
+ /*
+ * If sc->ip is NULL, that means that the setup function called
+ * xfs_iget to look up the inode. xfs_iget returned a EFSCORRUPTED
+ * and a NULL inode, so flag the corruption error and return.
+ */
+ if (!sc->ip) {
+ xfs_scrub_ino_set_corrupt(sc, sc->sm->sm_ino);
+ return 0;
}
- xfs_scrub_dinode(sc, bp, dip, ino);
+ /* Scrub the inode core. */
+ xfs_inode_to_disk(sc->ip, &di, 0);
+ xfs_scrub_dinode(sc, &di, sc->ip->i_ino);
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
goto out;
- /* Now let's do the things that require a live inode. */
- if (!sc->ip)
- goto out;
-
/*
* Look for discrepancies between file's data blocks and the reflink
* iflag. We already checked the iflag against the file mode when
* we scrubbed the dinode.
*/
if (S_ISREG(VFS_I(sc->ip)->i_mode))
- xfs_scrub_inode_check_reflink_iflag(sc, ino, bp);
+ xfs_scrub_inode_check_reflink_iflag(sc, sc->ip->i_ino);
- xfs_scrub_inode_xref(sc, ino, dip);
+ xfs_scrub_inode_xref(sc, sc->ip->i_ino, &di);
out:
- if (bp)
- xfs_trans_brelse(sc->tp, bp);
return error;
}
diff --git a/fs/xfs/scrub/parent.c b/fs/xfs/scrub/parent.c
index 0d3851410c74..1fb88c18d455 100644
--- a/fs/xfs/scrub/parent.c
+++ b/fs/xfs/scrub/parent.c
@@ -167,8 +167,18 @@ xfs_scrub_parent_validate(
* if the parent pointer erroneously points to a file, we
* can't use DONTCACHE here because DONTCACHE inodes can trigger
* immediate inactive cleanup of the inode.
+ *
+ * If _iget returns -EINVAL then the parent inode number is garbage
+ * and the directory is corrupt. If the _iget returns -EFSCORRUPTED
+ * or -EFSBADCRC then the parent is corrupt which is a cross
+ * referencing error. Any other error is an operational error.
*/
- error = xfs_iget(mp, sc->tp, dnum, 0, 0, &dp);
+ error = xfs_iget(mp, sc->tp, dnum, XFS_IGET_UNTRUSTED, 0, &dp);
+ if (error == -EINVAL) {
+ error = -EFSCORRUPTED;
+ xfs_scrub_fblock_process_error(sc, XFS_DATA_FORK, 0, &error);
+ goto out;
+ }
if (!xfs_scrub_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
goto out;
if (dp == sc->ip || !S_ISDIR(VFS_I(dp)->i_mode)) {
diff --git a/fs/xfs/scrub/quota.c b/fs/xfs/scrub/quota.c
index 51daa4ae2627..6ba465e6c885 100644
--- a/fs/xfs/scrub/quota.c
+++ b/fs/xfs/scrub/quota.c
@@ -219,7 +219,7 @@ xfs_scrub_quota(
/* Look for problem extents. */
xfs_ilock(ip, XFS_ILOCK_EXCL);
if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) {
- xfs_scrub_ino_set_corrupt(sc, sc->ip->i_ino, NULL);
+ xfs_scrub_ino_set_corrupt(sc, sc->ip->i_ino);
goto out_unlock_inode;
}
max_dqid_off = ((xfs_dqid_t)-1) / qi->qi_dqperchunk;
diff --git a/fs/xfs/scrub/rtbitmap.c b/fs/xfs/scrub/rtbitmap.c
index 26390991369a..39c41dfe08ee 100644
--- a/fs/xfs/scrub/rtbitmap.c
+++ b/fs/xfs/scrub/rtbitmap.c
@@ -116,8 +116,7 @@ xfs_scrub_xref_is_used_rt_space(
if (!xfs_scrub_should_check_xref(sc, &error, NULL))
goto out_unlock;
if (is_free)
- xfs_scrub_ino_xref_set_corrupt(sc, sc->mp->m_rbmip->i_ino,
- NULL);
+ xfs_scrub_ino_xref_set_corrupt(sc, sc->mp->m_rbmip->i_ino);
out_unlock:
xfs_iunlock(sc->mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
}
diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
index 4dc896852bf0..5d2b1c241be5 100644
--- a/fs/xfs/scrub/trace.h
+++ b/fs/xfs/scrub/trace.h
@@ -174,53 +174,32 @@ DEFINE_SCRUB_BLOCK_ERROR_EVENT(xfs_scrub_block_error);
DEFINE_SCRUB_BLOCK_ERROR_EVENT(xfs_scrub_block_preen);
DECLARE_EVENT_CLASS(xfs_scrub_ino_error_class,
- TP_PROTO(struct xfs_scrub_context *sc, xfs_ino_t ino, xfs_daddr_t daddr,
- void *ret_ip),
- TP_ARGS(sc, ino, daddr, ret_ip),
+ TP_PROTO(struct xfs_scrub_context *sc, xfs_ino_t ino, void *ret_ip),
+ TP_ARGS(sc, ino, ret_ip),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_ino_t, ino)
__field(unsigned int, type)
- __field(xfs_agnumber_t, agno)
- __field(xfs_agblock_t, bno)
__field(void *, ret_ip)
),
TP_fast_assign(
- xfs_fsblock_t fsbno;
- xfs_agnumber_t agno;
- xfs_agblock_t bno;
-
- if (daddr) {
- fsbno = XFS_DADDR_TO_FSB(sc->mp, daddr);
- agno = XFS_FSB_TO_AGNO(sc->mp, fsbno);
- bno = XFS_FSB_TO_AGBNO(sc->mp, fsbno);
- } else {
- agno = XFS_INO_TO_AGNO(sc->mp, ino);
- bno = XFS_AGINO_TO_AGBNO(sc->mp,
- XFS_INO_TO_AGINO(sc->mp, ino));
- }
-
__entry->dev = sc->mp->m_super->s_dev;
__entry->ino = ino;
__entry->type = sc->sm->sm_type;
- __entry->agno = agno;
- __entry->bno = bno;
__entry->ret_ip = ret_ip;
),
- TP_printk("dev %d:%d ino 0x%llx type %u agno %u agbno %u ret_ip %pS",
+ TP_printk("dev %d:%d ino 0x%llx type %u ret_ip %pS",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
__entry->type,
- __entry->agno,
- __entry->bno,
__entry->ret_ip)
)
#define DEFINE_SCRUB_INO_ERROR_EVENT(name) \
DEFINE_EVENT(xfs_scrub_ino_error_class, name, \
TP_PROTO(struct xfs_scrub_context *sc, xfs_ino_t ino, \
- xfs_daddr_t daddr, void *ret_ip), \
- TP_ARGS(sc, ino, daddr, ret_ip))
+ void *ret_ip), \
+ TP_ARGS(sc, ino, ret_ip))
DEFINE_SCRUB_INO_ERROR_EVENT(xfs_scrub_ino_error);
DEFINE_SCRUB_INO_ERROR_EVENT(xfs_scrub_ino_preen);
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 9c6a830da0ee..19eadc807056 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -209,7 +209,8 @@ xfs_setfilesize_trans_alloc(
struct xfs_trans *tp;
int error;
- error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp);
+ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0,
+ XFS_TRANS_NOFS, &tp);
if (error)
return error;
@@ -1330,21 +1331,20 @@ xfs_get_blocks(
end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size);
offset_fsb = XFS_B_TO_FSBT(mp, offset);
- error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb,
- &imap, &nimaps, XFS_BMAPI_ENTIRE);
+ error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap,
+ &nimaps, 0);
if (error)
goto out_unlock;
-
- if (nimaps) {
- trace_xfs_get_blocks_found(ip, offset, size,
- imap.br_state == XFS_EXT_UNWRITTEN ?
- XFS_IO_UNWRITTEN : XFS_IO_OVERWRITE, &imap);
- xfs_iunlock(ip, lockmode);
- } else {
+ if (!nimaps) {
trace_xfs_get_blocks_notfound(ip, offset, size);
goto out_unlock;
}
+ trace_xfs_get_blocks_found(ip, offset, size,
+ imap.br_state == XFS_EXT_UNWRITTEN ?
+ XFS_IO_UNWRITTEN : XFS_IO_OVERWRITE, &imap);
+ xfs_iunlock(ip, lockmode);
+
/* trim mapping down to size requested */
xfs_map_trim_size(inode, iblock, bh_result, &imap, offset, size);
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index c83f549dc17b..05dee8fdd895 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -1208,18 +1208,15 @@ xfs_free_file_space(
/*
* Now that we've unmap all full blocks we'll have to zero out any
- * partial block at the beginning and/or end. xfs_zero_range is
- * smart enough to skip any holes, including those we just created,
- * but we must take care not to zero beyond EOF and enlarge i_size.
+ * partial block at the beginning and/or end. iomap_zero_range is smart
+ * enough to skip any holes, including those we just created, but we
+ * must take care not to zero beyond EOF and enlarge i_size.
*/
-
if (offset >= XFS_ISIZE(ip))
return 0;
-
if (offset + len > XFS_ISIZE(ip))
len = XFS_ISIZE(ip) - offset;
-
- return xfs_zero_range(ip, offset, len, NULL);
+ return iomap_zero_range(VFS_I(ip), offset, len, NULL, &xfs_iomap_ops);
}
/*
@@ -1899,17 +1896,28 @@ xfs_swap_extents(
* performed with log redo items!
*/
if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {
+ int w = XFS_DATA_FORK;
+ uint32_t ipnext = XFS_IFORK_NEXTENTS(ip, w);
+ uint32_t tipnext = XFS_IFORK_NEXTENTS(tip, w);
+
+ /*
+ * Conceptually this shouldn't affect the shape of either bmbt,
+ * but since we atomically move extents one by one, we reserve
+ * enough space to rebuild both trees.
+ */
+ resblks = XFS_SWAP_RMAP_SPACE_RES(mp, ipnext, w);
+ resblks += XFS_SWAP_RMAP_SPACE_RES(mp, tipnext, w);
+
/*
- * Conceptually this shouldn't affect the shape of either
- * bmbt, but since we atomically move extents one by one,
- * we reserve enough space to rebuild both trees.
+ * Handle the corner case where either inode might straddle the
+ * btree format boundary. If so, the inode could bounce between
+ * btree <-> extent format on unmap -> remap cycles, freeing and
+ * allocating a bmapbt block each time.
*/
- resblks = XFS_SWAP_RMAP_SPACE_RES(mp,
- XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK),
- XFS_DATA_FORK) +
- XFS_SWAP_RMAP_SPACE_RES(mp,
- XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK),
- XFS_DATA_FORK);
+ if (ipnext == (XFS_IFORK_MAXEXT(ip, w) + 1))
+ resblks += XFS_IFORK_MAXEXT(ip, w);
+ if (tipnext == (XFS_IFORK_MAXEXT(tip, w) + 1))
+ resblks += XFS_IFORK_MAXEXT(tip, w);
}
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp);
if (error)
@@ -2003,11 +2011,11 @@ xfs_swap_extents(
ip->i_cowfp = tip->i_cowfp;
tip->i_cowfp = cowfp;
- if (ip->i_cowfp && ip->i_cnextents)
+ if (ip->i_cowfp && ip->i_cowfp->if_bytes)
xfs_inode_set_cowblocks_tag(ip);
else
xfs_inode_clear_cowblocks_tag(ip);
- if (tip->i_cowfp && tip->i_cnextents)
+ if (tip->i_cowfp && tip->i_cowfp->if_bytes)
xfs_inode_set_cowblocks_tag(tip);
else
xfs_inode_clear_cowblocks_tag(tip);
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index d1da2ee9e6db..ac669a10c62f 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -1708,7 +1708,7 @@ xfs_buftarg_isolate(
* zero. If the value is already zero, we need to reclaim the
* buffer, otherwise it gets another trip through the LRU.
*/
- if (!atomic_add_unless(&bp->b_lru_ref, -1, 0)) {
+ if (atomic_add_unless(&bp->b_lru_ref, -1, 0)) {
spin_unlock(&bp->b_lock);
return LRU_ROTATE;
}
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 270ddb4d2313..82ad270e390e 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -460,7 +460,7 @@ xfs_buf_item_unpin(
list_del_init(&bp->b_li_list);
bp->b_iodone = NULL;
} else {
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
xfs_trans_ail_delete(ailp, lip, SHUTDOWN_LOG_IO_ERROR);
xfs_buf_item_relse(bp);
ASSERT(bp->b_log_item == NULL);
@@ -1057,12 +1057,12 @@ xfs_buf_do_callbacks_fail(
lip = list_first_entry(&bp->b_li_list, struct xfs_log_item,
li_bio_list);
ailp = lip->li_ailp;
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
list_for_each_entry(lip, &bp->b_li_list, li_bio_list) {
if (lip->li_ops->iop_error)
lip->li_ops->iop_error(lip, bp);
}
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
}
static bool
@@ -1226,7 +1226,7 @@ xfs_buf_iodone(
*
* Either way, AIL is useless if we're forcing a shutdown.
*/
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
xfs_trans_ail_delete(ailp, lip, SHUTDOWN_CORRUPT_INCORE);
xfs_buf_item_free(BUF_ITEM(lip));
}
@@ -1246,7 +1246,7 @@ xfs_buf_resubmit_failed_buffers(
/*
* Clear XFS_LI_FAILED flag from all items before resubmit
*
- * XFS_LI_FAILED set/clear is protected by xa_lock, caller this
+ * XFS_LI_FAILED set/clear is protected by ail_lock, caller this
* function already have it acquired
*/
list_for_each_entry(lip, &bp->b_li_list, li_bio_list)
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 43572f8a1b8e..a7daef9e16bf 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -394,8 +394,6 @@ xfs_qm_dqalloc(
error1:
xfs_defer_cancel(&dfops);
error0:
- xfs_iunlock(quotip, XFS_ILOCK_EXCL);
-
return error;
}
@@ -920,7 +918,7 @@ xfs_qm_dqflush_done(
(lip->li_flags & XFS_LI_FAILED))) {
/* xfs_trans_ail_delete() drops the AIL lock. */
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
if (lip->li_lsn == qip->qli_flush_lsn) {
xfs_trans_ail_delete(ailp, lip, SHUTDOWN_CORRUPT_INCORE);
} else {
@@ -930,7 +928,7 @@ xfs_qm_dqflush_done(
*/
if (lip->li_flags & XFS_LI_FAILED)
xfs_clear_li_failed(lip);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
}
}
diff --git a/fs/xfs/xfs_dquot_item.c b/fs/xfs/xfs_dquot_item.c
index 96eaa6933709..4b331e354da7 100644
--- a/fs/xfs/xfs_dquot_item.c
+++ b/fs/xfs/xfs_dquot_item.c
@@ -157,8 +157,9 @@ xfs_dquot_item_error(
STATIC uint
xfs_qm_dquot_logitem_push(
struct xfs_log_item *lip,
- struct list_head *buffer_list) __releases(&lip->li_ailp->xa_lock)
- __acquires(&lip->li_ailp->xa_lock)
+ struct list_head *buffer_list)
+ __releases(&lip->li_ailp->ail_lock)
+ __acquires(&lip->li_ailp->ail_lock)
{
struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot;
struct xfs_buf *bp = lip->li_buf;
@@ -205,7 +206,7 @@ xfs_qm_dquot_logitem_push(
goto out_unlock;
}
- spin_unlock(&lip->li_ailp->xa_lock);
+ spin_unlock(&lip->li_ailp->ail_lock);
error = xfs_qm_dqflush(dqp, &bp);
if (error) {
@@ -217,7 +218,7 @@ xfs_qm_dquot_logitem_push(
xfs_buf_relse(bp);
}
- spin_lock(&lip->li_ailp->xa_lock);
+ spin_lock(&lip->li_ailp->ail_lock);
out_unlock:
xfs_dqunlock(dqp);
return rval;
@@ -400,7 +401,7 @@ xfs_qm_qoffend_logitem_committed(
* Delete the qoff-start logitem from the AIL.
* xfs_trans_ail_delete() drops the AIL lock.
*/
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
xfs_trans_ail_delete(ailp, &qfs->qql_item, SHUTDOWN_LOG_IO_ERROR);
kmem_free(qfs->qql_item.li_lv_shadow);
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index ccf520f0b00d..a63f5083f497 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -347,27 +347,32 @@ xfs_corruption_error(
* values, and omit the stack trace unless the error level is tuned high.
*/
void
-xfs_verifier_error(
+xfs_buf_verifier_error(
struct xfs_buf *bp,
int error,
+ const char *name,
+ void *buf,
+ size_t bufsz,
xfs_failaddr_t failaddr)
{
struct xfs_mount *mp = bp->b_target->bt_mount;
xfs_failaddr_t fa;
+ int sz;
fa = failaddr ? failaddr : __return_address;
__xfs_buf_ioerror(bp, error, fa);
- xfs_alert(mp, "Metadata %s detected at %pS, %s block 0x%llx",
+ xfs_alert(mp, "Metadata %s detected at %pS, %s block 0x%llx %s",
bp->b_error == -EFSBADCRC ? "CRC error" : "corruption",
- fa, bp->b_ops->name, bp->b_bn);
+ fa, bp->b_ops->name, bp->b_bn, name);
xfs_alert(mp, "Unmount and run xfs_repair");
if (xfs_error_level >= XFS_ERRLEVEL_LOW) {
+ sz = min_t(size_t, XFS_CORRUPTION_DUMP_LEN, bufsz);
xfs_alert(mp, "First %d bytes of corrupted metadata buffer:",
- XFS_CORRUPTION_DUMP_LEN);
- xfs_hex_dump(xfs_buf_offset(bp, 0), XFS_CORRUPTION_DUMP_LEN);
+ sz);
+ xfs_hex_dump(buf, sz);
}
if (xfs_error_level >= XFS_ERRLEVEL_HIGH)
@@ -375,6 +380,20 @@ xfs_verifier_error(
}
/*
+ * Warnings specifically for verifier errors. Differentiate CRC vs. invalid
+ * values, and omit the stack trace unless the error level is tuned high.
+ */
+void
+xfs_verifier_error(
+ struct xfs_buf *bp,
+ int error,
+ xfs_failaddr_t failaddr)
+{
+ return xfs_buf_verifier_error(bp, error, "", xfs_buf_offset(bp, 0),
+ XFS_CORRUPTION_DUMP_LEN, failaddr);
+}
+
+/*
* Warnings for inode corruption problems. Don't bother with the stack
* trace unless the error level is turned up high.
*/
diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h
index 7e728c5a46b8..ce391349e78b 100644
--- a/fs/xfs/xfs_error.h
+++ b/fs/xfs/xfs_error.h
@@ -26,6 +26,9 @@ extern void xfs_error_report(const char *tag, int level, struct xfs_mount *mp,
extern void xfs_corruption_error(const char *tag, int level,
struct xfs_mount *mp, void *p, const char *filename,
int linenum, xfs_failaddr_t failaddr);
+extern void xfs_buf_verifier_error(struct xfs_buf *bp, int error,
+ const char *name, void *buf, size_t bufsz,
+ xfs_failaddr_t failaddr);
extern void xfs_verifier_error(struct xfs_buf *bp, int error,
xfs_failaddr_t failaddr);
extern void xfs_inode_verifier_error(struct xfs_inode *ip, int error,
diff --git a/fs/xfs/xfs_export.c b/fs/xfs/xfs_export.c
index fe1bfee35898..761f3189eff2 100644
--- a/fs/xfs/xfs_export.c
+++ b/fs/xfs/xfs_export.c
@@ -237,7 +237,7 @@ xfs_fs_nfs_commit_metadata(
if (!lsn)
return 0;
- return _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, NULL);
+ return xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, NULL);
}
const struct export_operations xfs_export_operations = {
diff --git a/fs/xfs/xfs_extent_busy.c b/fs/xfs/xfs_extent_busy.c
index 77760dbf0242..13e3d1a69e76 100644
--- a/fs/xfs/xfs_extent_busy.c
+++ b/fs/xfs/xfs_extent_busy.c
@@ -611,10 +611,9 @@ xfs_extent_busy_flush(
unsigned busy_gen)
{
DEFINE_WAIT (wait);
- int log_flushed = 0, error;
+ int error;
- trace_xfs_log_force(mp, 0, _THIS_IP_);
- error = _xfs_log_force(mp, XFS_LOG_SYNC, &log_flushed);
+ error = xfs_log_force(mp, XFS_LOG_SYNC);
if (error)
return;
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 9ea08326f876..299aee4b7b0b 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -48,20 +48,6 @@
static const struct vm_operations_struct xfs_file_vm_ops;
-/*
- * Clear the specified ranges to zero through either the pagecache or DAX.
- * Holes and unwritten extents will be left as-is as they already are zeroed.
- */
-int
-xfs_zero_range(
- struct xfs_inode *ip,
- xfs_off_t pos,
- xfs_off_t count,
- bool *did_zero)
-{
- return iomap_zero_range(VFS_I(ip), pos, count, did_zero, &xfs_iomap_ops);
-}
-
int
xfs_update_prealloc_flags(
struct xfs_inode *ip,
@@ -122,7 +108,7 @@ xfs_dir_fsync(
if (!lsn)
return 0;
- return _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, NULL);
+ return xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, NULL);
}
STATIC int
@@ -182,7 +168,7 @@ xfs_file_fsync(
}
if (lsn) {
- error = _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, &log_flushed);
+ error = xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, &log_flushed);
ip->i_itemp->ili_fsync_fields = 0;
}
xfs_iunlock(ip, XFS_ILOCK_SHARED);
@@ -301,31 +287,6 @@ xfs_file_read_iter(
}
/*
- * Zero any on disk space between the current EOF and the new, larger EOF.
- *
- * This handles the normal case of zeroing the remainder of the last block in
- * the file and the unusual case of zeroing blocks out beyond the size of the
- * file. This second case only happens with fixed size extents and when the
- * system crashes before the inode size was updated but after blocks were
- * allocated.
- *
- * Expects the iolock to be held exclusive, and will take the ilock internally.
- */
-int /* error (positive) */
-xfs_zero_eof(
- struct xfs_inode *ip,
- xfs_off_t offset, /* starting I/O offset */
- xfs_fsize_t isize, /* current inode size */
- bool *did_zeroing)
-{
- ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
- ASSERT(offset > isize);
-
- trace_xfs_zero_eof(ip, isize, offset - isize);
- return xfs_zero_range(ip, isize, offset - isize, did_zeroing);
-}
-
-/*
* Common pre-write limit and setup checks.
*
* Called with the iolocked held either shared and exclusive according to
@@ -344,6 +305,7 @@ xfs_file_aio_write_checks(
ssize_t error = 0;
size_t count = iov_iter_count(from);
bool drained_dio = false;
+ loff_t isize;
restart:
error = generic_write_checks(iocb, from);
@@ -380,7 +342,8 @@ restart:
* and hence be able to correctly determine if we need to run zeroing.
*/
spin_lock(&ip->i_flags_lock);
- if (iocb->ki_pos > i_size_read(inode)) {
+ isize = i_size_read(inode);
+ if (iocb->ki_pos > isize) {
spin_unlock(&ip->i_flags_lock);
if (!drained_dio) {
if (*iolock == XFS_IOLOCK_SHARED) {
@@ -401,7 +364,10 @@ restart:
drained_dio = true;
goto restart;
}
- error = xfs_zero_eof(ip, iocb->ki_pos, i_size_read(inode), NULL);
+
+ trace_xfs_zero_eof(ip, isize, iocb->ki_pos - isize);
+ error = iomap_zero_range(inode, isize, iocb->ki_pos - isize,
+ NULL, &xfs_iomap_ops);
if (error)
return error;
} else
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 8b4545623e25..523792768080 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -217,7 +217,7 @@ xfs_growfs_data_private(
}
agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, bp);
- for (bucket = 0; bucket < XFS_AGFL_SIZE(mp); bucket++)
+ for (bucket = 0; bucket < xfs_agfl_size(mp); bucket++)
agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK);
error = xfs_bwrite(bp);
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index d53a316162d6..9a18f69f6e96 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -483,7 +483,28 @@ xfs_iget_cache_miss(
trace_xfs_iget_miss(ip);
- if ((VFS_I(ip)->i_mode == 0) && !(flags & XFS_IGET_CREATE)) {
+
+ /*
+ * If we are allocating a new inode, then check what was returned is
+ * actually a free, empty inode. If we are not allocating an inode,
+ * the check we didn't find a free inode.
+ */
+ if (flags & XFS_IGET_CREATE) {
+ if (VFS_I(ip)->i_mode != 0) {
+ xfs_warn(mp,
+"Corruption detected! Free inode 0x%llx not marked free on disk",
+ ino);
+ error = -EFSCORRUPTED;
+ goto out_destroy;
+ }
+ if (ip->i_d.di_nblocks != 0) {
+ xfs_warn(mp,
+"Corruption detected! Free inode 0x%llx has blocks allocated!",
+ ino);
+ error = -EFSCORRUPTED;
+ goto out_destroy;
+ }
+ } else if (VFS_I(ip)->i_mode == 0) {
error = -ENOENT;
goto out_destroy;
}
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 604ee384a00a..3e3aab3888fa 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1872,6 +1872,7 @@ xfs_inactive(
xfs_inode_t *ip)
{
struct xfs_mount *mp;
+ struct xfs_ifork *cow_ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
int error;
int truncate = 0;
@@ -1892,6 +1893,10 @@ xfs_inactive(
if (mp->m_flags & XFS_MOUNT_RDONLY)
return;
+ /* Try to clean out the cow blocks if there are any. */
+ if (xfs_is_reflink_inode(ip) && cow_ifp->if_bytes > 0)
+ xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF, true);
+
if (VFS_I(ip)->i_nlink != 0) {
/*
* force is true because we are evicting an inode from the
@@ -2470,6 +2475,10 @@ xfs_ifree(
ip->i_d.di_forkoff = 0; /* mark the attr fork not in use */
ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
+
+ /* Don't attempt to replay owner changes for a deleted inode */
+ ip->i_itemp->ili_fields &= ~(XFS_ILOG_AOWNER|XFS_ILOG_DOWNER);
+
/*
* Bump the generation count so no one will be confused
* by reincarnations of this inode.
@@ -2497,7 +2506,7 @@ xfs_iunpin(
trace_xfs_inode_unpin_nowait(ip, _RET_IP_);
/* Give the log a push to start the unpinning I/O */
- xfs_log_force_lsn(ip->i_mount, ip->i_itemp->ili_last_lsn, 0);
+ xfs_log_force_lsn(ip->i_mount, ip->i_itemp->ili_last_lsn, 0, NULL);
}
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 3e8dc990d41c..132d8aa2afc4 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -443,10 +443,6 @@ enum xfs_prealloc_flags {
int xfs_update_prealloc_flags(struct xfs_inode *ip,
enum xfs_prealloc_flags flags);
-int xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset,
- xfs_fsize_t isize, bool *did_zeroing);
-int xfs_zero_range(struct xfs_inode *ip, xfs_off_t pos, xfs_off_t count,
- bool *did_zero);
/* from xfs_iops.c */
extern void xfs_setup_inode(struct xfs_inode *ip);
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index d5037f060d6f..34b91b789702 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -502,8 +502,8 @@ STATIC uint
xfs_inode_item_push(
struct xfs_log_item *lip,
struct list_head *buffer_list)
- __releases(&lip->li_ailp->xa_lock)
- __acquires(&lip->li_ailp->xa_lock)
+ __releases(&lip->li_ailp->ail_lock)
+ __acquires(&lip->li_ailp->ail_lock)
{
struct xfs_inode_log_item *iip = INODE_ITEM(lip);
struct xfs_inode *ip = iip->ili_inode;
@@ -562,7 +562,7 @@ xfs_inode_item_push(
ASSERT(iip->ili_fields != 0 || XFS_FORCED_SHUTDOWN(ip->i_mount));
ASSERT(iip->ili_logged == 0 || XFS_FORCED_SHUTDOWN(ip->i_mount));
- spin_unlock(&lip->li_ailp->xa_lock);
+ spin_unlock(&lip->li_ailp->ail_lock);
error = xfs_iflush(ip, &bp);
if (!error) {
@@ -571,7 +571,7 @@ xfs_inode_item_push(
xfs_buf_relse(bp);
}
- spin_lock(&lip->li_ailp->xa_lock);
+ spin_lock(&lip->li_ailp->ail_lock);
out_unlock:
xfs_iunlock(ip, XFS_ILOCK_SHARED);
return rval;
@@ -579,9 +579,6 @@ out_unlock:
/*
* Unlock the inode associated with the inode log item.
- * Clear the fields of the inode and inode log item that
- * are specific to the current transaction. If the
- * hold flags is set, do not unlock the inode.
*/
STATIC void
xfs_inode_item_unlock(
@@ -637,10 +634,6 @@ xfs_inode_item_committed(
return lsn;
}
-/*
- * XXX rcc - this one really has to do something. Probably needs
- * to stamp in a new field in the incore inode.
- */
STATIC void
xfs_inode_item_committing(
struct xfs_log_item *lip,
@@ -759,7 +752,7 @@ xfs_iflush_done(
bool mlip_changed = false;
/* this is an opencoded batch version of xfs_trans_ail_delete */
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
list_for_each_entry(blip, &tmp, li_bio_list) {
if (INODE_ITEM(blip)->ili_logged &&
blip->li_lsn == INODE_ITEM(blip)->ili_flush_lsn)
@@ -770,15 +763,15 @@ xfs_iflush_done(
}
if (mlip_changed) {
- if (!XFS_FORCED_SHUTDOWN(ailp->xa_mount))
- xlog_assign_tail_lsn_locked(ailp->xa_mount);
- if (list_empty(&ailp->xa_ail))
- wake_up_all(&ailp->xa_empty);
+ if (!XFS_FORCED_SHUTDOWN(ailp->ail_mount))
+ xlog_assign_tail_lsn_locked(ailp->ail_mount);
+ if (list_empty(&ailp->ail_head))
+ wake_up_all(&ailp->ail_empty);
}
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
if (mlip_changed)
- xfs_log_space_wake(ailp->xa_mount);
+ xfs_log_space_wake(ailp->ail_mount);
}
/*
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 56475fcd76f2..e0307fbff911 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -46,6 +46,7 @@
#include <linux/security.h>
#include <linux/iomap.h>
#include <linux/slab.h>
+#include <linux/iversion.h>
/*
* Directories have different lock order w.r.t. mmap_sem compared to regular
@@ -874,7 +875,9 @@ xfs_setattr_size(
* truncate.
*/
if (newsize > oldsize) {
- error = xfs_zero_eof(ip, newsize, oldsize, &did_zeroing);
+ trace_xfs_zero_eof(ip, oldsize, newsize - oldsize);
+ error = iomap_zero_range(inode, oldsize, newsize - oldsize,
+ &did_zeroing, &xfs_iomap_ops);
} else {
error = iomap_truncate_page(inode, newsize, &did_zeroing,
&xfs_iomap_ops);
@@ -1052,11 +1055,21 @@ xfs_vn_update_time(
{
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
+ int log_flags = XFS_ILOG_TIMESTAMP;
struct xfs_trans *tp;
int error;
trace_xfs_update_time(ip);
+ if (inode->i_sb->s_flags & SB_LAZYTIME) {
+ if (!((flags & S_VERSION) &&
+ inode_maybe_inc_iversion(inode, false)))
+ return generic_update_time(inode, now, flags);
+
+ /* Capture the iversion update that just occurred */
+ log_flags |= XFS_ILOG_CORE;
+ }
+
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp);
if (error)
return error;
@@ -1070,7 +1083,7 @@ xfs_vn_update_time(
inode->i_atime = *now;
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
- xfs_trans_log_inode(tp, ip, XFS_ILOG_TIMESTAMP);
+ xfs_trans_log_inode(tp, ip, log_flags);
return xfs_trans_commit(tp);
}
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 3e5ba1ecc080..b9c9c848146b 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -869,7 +869,7 @@ xfs_log_unmount_write(xfs_mount_t *mp)
return 0;
}
- error = _xfs_log_force(mp, XFS_LOG_SYNC, NULL);
+ error = xfs_log_force(mp, XFS_LOG_SYNC);
ASSERT(error || !(XLOG_FORCED_SHUTDOWN(log)));
#ifdef DEBUG
@@ -1149,7 +1149,7 @@ xlog_assign_tail_lsn_locked(
struct xfs_log_item *lip;
xfs_lsn_t tail_lsn;
- assert_spin_locked(&mp->m_ail->xa_lock);
+ assert_spin_locked(&mp->m_ail->ail_lock);
/*
* To make sure we always have a valid LSN for the log tail we keep
@@ -1172,9 +1172,9 @@ xlog_assign_tail_lsn(
{
xfs_lsn_t tail_lsn;
- spin_lock(&mp->m_ail->xa_lock);
+ spin_lock(&mp->m_ail->ail_lock);
tail_lsn = xlog_assign_tail_lsn_locked(mp);
- spin_unlock(&mp->m_ail->xa_lock);
+ spin_unlock(&mp->m_ail->ail_lock);
return tail_lsn;
}
@@ -3304,269 +3304,215 @@ xlog_state_switch_iclogs(
* not in the active nor dirty state.
*/
int
-_xfs_log_force(
+xfs_log_force(
struct xfs_mount *mp,
- uint flags,
- int *log_flushed)
+ uint flags)
{
struct xlog *log = mp->m_log;
struct xlog_in_core *iclog;
xfs_lsn_t lsn;
XFS_STATS_INC(mp, xs_log_force);
+ trace_xfs_log_force(mp, 0, _RET_IP_);
xlog_cil_force(log);
spin_lock(&log->l_icloglock);
-
iclog = log->l_iclog;
- if (iclog->ic_state & XLOG_STATE_IOERROR) {
- spin_unlock(&log->l_icloglock);
- return -EIO;
- }
+ if (iclog->ic_state & XLOG_STATE_IOERROR)
+ goto out_error;
- /* If the head iclog is not active nor dirty, we just attach
- * ourselves to the head and go to sleep.
- */
- if (iclog->ic_state == XLOG_STATE_ACTIVE ||
- iclog->ic_state == XLOG_STATE_DIRTY) {
+ if (iclog->ic_state == XLOG_STATE_DIRTY ||
+ (iclog->ic_state == XLOG_STATE_ACTIVE &&
+ atomic_read(&iclog->ic_refcnt) == 0 && iclog->ic_offset == 0)) {
/*
- * If the head is dirty or (active and empty), then
- * we need to look at the previous iclog. If the previous
- * iclog is active or dirty we are done. There is nothing
- * to sync out. Otherwise, we attach ourselves to the
+ * If the head is dirty or (active and empty), then we need to
+ * look at the previous iclog.
+ *
+ * If the previous iclog is active or dirty we are done. There
+ * is nothing to sync out. Otherwise, we attach ourselves to the
* previous iclog and go to sleep.
*/
- if (iclog->ic_state == XLOG_STATE_DIRTY ||
- (atomic_read(&iclog->ic_refcnt) == 0
- && iclog->ic_offset == 0)) {
- iclog = iclog->ic_prev;
- if (iclog->ic_state == XLOG_STATE_ACTIVE ||
- iclog->ic_state == XLOG_STATE_DIRTY)
- goto no_sleep;
- else
- goto maybe_sleep;
- } else {
- if (atomic_read(&iclog->ic_refcnt) == 0) {
- /* We are the only one with access to this
- * iclog. Flush it out now. There should
- * be a roundoff of zero to show that someone
- * has already taken care of the roundoff from
- * the previous sync.
- */
- atomic_inc(&iclog->ic_refcnt);
- lsn = be64_to_cpu(iclog->ic_header.h_lsn);
- xlog_state_switch_iclogs(log, iclog, 0);
- spin_unlock(&log->l_icloglock);
+ iclog = iclog->ic_prev;
+ if (iclog->ic_state == XLOG_STATE_ACTIVE ||
+ iclog->ic_state == XLOG_STATE_DIRTY)
+ goto out_unlock;
+ } else if (iclog->ic_state == XLOG_STATE_ACTIVE) {
+ if (atomic_read(&iclog->ic_refcnt) == 0) {
+ /*
+ * We are the only one with access to this iclog.
+ *
+ * Flush it out now. There should be a roundoff of zero
+ * to show that someone has already taken care of the
+ * roundoff from the previous sync.
+ */
+ atomic_inc(&iclog->ic_refcnt);
+ lsn = be64_to_cpu(iclog->ic_header.h_lsn);
+ xlog_state_switch_iclogs(log, iclog, 0);
+ spin_unlock(&log->l_icloglock);
- if (xlog_state_release_iclog(log, iclog))
- return -EIO;
-
- if (log_flushed)
- *log_flushed = 1;
- spin_lock(&log->l_icloglock);
- if (be64_to_cpu(iclog->ic_header.h_lsn) == lsn &&
- iclog->ic_state != XLOG_STATE_DIRTY)
- goto maybe_sleep;
- else
- goto no_sleep;
- } else {
- /* Someone else is writing to this iclog.
- * Use its call to flush out the data. However,
- * the other thread may not force out this LR,
- * so we mark it WANT_SYNC.
- */
- xlog_state_switch_iclogs(log, iclog, 0);
- goto maybe_sleep;
- }
- }
- }
+ if (xlog_state_release_iclog(log, iclog))
+ return -EIO;
- /* By the time we come around again, the iclog could've been filled
- * which would give it another lsn. If we have a new lsn, just
- * return because the relevant data has been flushed.
- */
-maybe_sleep:
- if (flags & XFS_LOG_SYNC) {
- /*
- * We must check if we're shutting down here, before
- * we wait, while we're holding the l_icloglock.
- * Then we check again after waking up, in case our
- * sleep was disturbed by a bad news.
- */
- if (iclog->ic_state & XLOG_STATE_IOERROR) {
- spin_unlock(&log->l_icloglock);
- return -EIO;
+ spin_lock(&log->l_icloglock);
+ if (be64_to_cpu(iclog->ic_header.h_lsn) != lsn ||
+ iclog->ic_state == XLOG_STATE_DIRTY)
+ goto out_unlock;
+ } else {
+ /*
+ * Someone else is writing to this iclog.
+ *
+ * Use its call to flush out the data. However, the
+ * other thread may not force out this LR, so we mark
+ * it WANT_SYNC.
+ */
+ xlog_state_switch_iclogs(log, iclog, 0);
}
- XFS_STATS_INC(mp, xs_log_force_sleep);
- xlog_wait(&iclog->ic_force_wait, &log->l_icloglock);
+ } else {
/*
- * No need to grab the log lock here since we're
- * only deciding whether or not to return EIO
- * and the memory read should be atomic.
+ * If the head iclog is not active nor dirty, we just attach
+ * ourselves to the head and go to sleep if necessary.
*/
- if (iclog->ic_state & XLOG_STATE_IOERROR)
- return -EIO;
- } else {
-
-no_sleep:
- spin_unlock(&log->l_icloglock);
+ ;
}
+
+ if (!(flags & XFS_LOG_SYNC))
+ goto out_unlock;
+
+ if (iclog->ic_state & XLOG_STATE_IOERROR)
+ goto out_error;
+ XFS_STATS_INC(mp, xs_log_force_sleep);
+ xlog_wait(&iclog->ic_force_wait, &log->l_icloglock);
+ if (iclog->ic_state & XLOG_STATE_IOERROR)
+ return -EIO;
return 0;
-}
-/*
- * Wrapper for _xfs_log_force(), to be used when caller doesn't care
- * about errors or whether the log was flushed or not. This is the normal
- * interface to use when trying to unpin items or move the log forward.
- */
-void
-xfs_log_force(
- xfs_mount_t *mp,
- uint flags)
-{
- trace_xfs_log_force(mp, 0, _RET_IP_);
- _xfs_log_force(mp, flags, NULL);
+out_unlock:
+ spin_unlock(&log->l_icloglock);
+ return 0;
+out_error:
+ spin_unlock(&log->l_icloglock);
+ return -EIO;
}
-/*
- * Force the in-core log to disk for a specific LSN.
- *
- * Find in-core log with lsn.
- * If it is in the DIRTY state, just return.
- * If it is in the ACTIVE state, move the in-core log into the WANT_SYNC
- * state and go to sleep or return.
- * If it is in any other state, go to sleep or return.
- *
- * Synchronous forces are implemented with a signal variable. All callers
- * to force a given lsn to disk will wait on a the sv attached to the
- * specific in-core log. When given in-core log finally completes its
- * write to disk, that thread will wake up all threads waiting on the
- * sv.
- */
-int
-_xfs_log_force_lsn(
+static int
+__xfs_log_force_lsn(
struct xfs_mount *mp,
xfs_lsn_t lsn,
uint flags,
- int *log_flushed)
+ int *log_flushed,
+ bool already_slept)
{
struct xlog *log = mp->m_log;
struct xlog_in_core *iclog;
- int already_slept = 0;
- ASSERT(lsn != 0);
-
- XFS_STATS_INC(mp, xs_log_force);
-
- lsn = xlog_cil_force_lsn(log, lsn);
- if (lsn == NULLCOMMITLSN)
- return 0;
-
-try_again:
spin_lock(&log->l_icloglock);
iclog = log->l_iclog;
- if (iclog->ic_state & XLOG_STATE_IOERROR) {
- spin_unlock(&log->l_icloglock);
- return -EIO;
- }
+ if (iclog->ic_state & XLOG_STATE_IOERROR)
+ goto out_error;
- do {
- if (be64_to_cpu(iclog->ic_header.h_lsn) != lsn) {
- iclog = iclog->ic_next;
- continue;
- }
+ while (be64_to_cpu(iclog->ic_header.h_lsn) != lsn) {
+ iclog = iclog->ic_next;
+ if (iclog == log->l_iclog)
+ goto out_unlock;
+ }
- if (iclog->ic_state == XLOG_STATE_DIRTY) {
- spin_unlock(&log->l_icloglock);
- return 0;
- }
+ if (iclog->ic_state == XLOG_STATE_DIRTY)
+ goto out_unlock;
- if (iclog->ic_state == XLOG_STATE_ACTIVE) {
- /*
- * We sleep here if we haven't already slept (e.g.
- * this is the first time we've looked at the correct
- * iclog buf) and the buffer before us is going to
- * be sync'ed. The reason for this is that if we
- * are doing sync transactions here, by waiting for
- * the previous I/O to complete, we can allow a few
- * more transactions into this iclog before we close
- * it down.
- *
- * Otherwise, we mark the buffer WANT_SYNC, and bump
- * up the refcnt so we can release the log (which
- * drops the ref count). The state switch keeps new
- * transaction commits from using this buffer. When
- * the current commits finish writing into the buffer,
- * the refcount will drop to zero and the buffer will
- * go out then.
- */
- if (!already_slept &&
- (iclog->ic_prev->ic_state &
- (XLOG_STATE_WANT_SYNC | XLOG_STATE_SYNCING))) {
- ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR));
+ if (iclog->ic_state == XLOG_STATE_ACTIVE) {
+ /*
+ * We sleep here if we haven't already slept (e.g. this is the
+ * first time we've looked at the correct iclog buf) and the
+ * buffer before us is going to be sync'ed. The reason for this
+ * is that if we are doing sync transactions here, by waiting
+ * for the previous I/O to complete, we can allow a few more
+ * transactions into this iclog before we close it down.
+ *
+ * Otherwise, we mark the buffer WANT_SYNC, and bump up the
+ * refcnt so we can release the log (which drops the ref count).
+ * The state switch keeps new transaction commits from using
+ * this buffer. When the current commits finish writing into
+ * the buffer, the refcount will drop to zero and the buffer
+ * will go out then.
+ */
+ if (!already_slept &&
+ (iclog->ic_prev->ic_state &
+ (XLOG_STATE_WANT_SYNC | XLOG_STATE_SYNCING))) {
+ ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR));
- XFS_STATS_INC(mp, xs_log_force_sleep);
+ XFS_STATS_INC(mp, xs_log_force_sleep);
- xlog_wait(&iclog->ic_prev->ic_write_wait,
- &log->l_icloglock);
- already_slept = 1;
- goto try_again;
- }
- atomic_inc(&iclog->ic_refcnt);
- xlog_state_switch_iclogs(log, iclog, 0);
- spin_unlock(&log->l_icloglock);
- if (xlog_state_release_iclog(log, iclog))
- return -EIO;
- if (log_flushed)
- *log_flushed = 1;
- spin_lock(&log->l_icloglock);
+ xlog_wait(&iclog->ic_prev->ic_write_wait,
+ &log->l_icloglock);
+ return -EAGAIN;
}
+ atomic_inc(&iclog->ic_refcnt);
+ xlog_state_switch_iclogs(log, iclog, 0);
+ spin_unlock(&log->l_icloglock);
+ if (xlog_state_release_iclog(log, iclog))
+ return -EIO;
+ if (log_flushed)
+ *log_flushed = 1;
+ spin_lock(&log->l_icloglock);
+ }
- if ((flags & XFS_LOG_SYNC) && /* sleep */
- !(iclog->ic_state &
- (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY))) {
- /*
- * Don't wait on completion if we know that we've
- * gotten a log write error.
- */
- if (iclog->ic_state & XLOG_STATE_IOERROR) {
- spin_unlock(&log->l_icloglock);
- return -EIO;
- }
- XFS_STATS_INC(mp, xs_log_force_sleep);
- xlog_wait(&iclog->ic_force_wait, &log->l_icloglock);
- /*
- * No need to grab the log lock here since we're
- * only deciding whether or not to return EIO
- * and the memory read should be atomic.
- */
- if (iclog->ic_state & XLOG_STATE_IOERROR)
- return -EIO;
- } else { /* just return */
- spin_unlock(&log->l_icloglock);
- }
+ if (!(flags & XFS_LOG_SYNC) ||
+ (iclog->ic_state & (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY)))
+ goto out_unlock;
- return 0;
- } while (iclog != log->l_iclog);
+ if (iclog->ic_state & XLOG_STATE_IOERROR)
+ goto out_error;
+
+ XFS_STATS_INC(mp, xs_log_force_sleep);
+ xlog_wait(&iclog->ic_force_wait, &log->l_icloglock);
+ if (iclog->ic_state & XLOG_STATE_IOERROR)
+ return -EIO;
+ return 0;
+out_unlock:
spin_unlock(&log->l_icloglock);
return 0;
+out_error:
+ spin_unlock(&log->l_icloglock);
+ return -EIO;
}
/*
- * Wrapper for _xfs_log_force_lsn(), to be used when caller doesn't care
- * about errors or whether the log was flushed or not. This is the normal
- * interface to use when trying to unpin items or move the log forward.
+ * Force the in-core log to disk for a specific LSN.
+ *
+ * Find in-core log with lsn.
+ * If it is in the DIRTY state, just return.
+ * If it is in the ACTIVE state, move the in-core log into the WANT_SYNC
+ * state and go to sleep or return.
+ * If it is in any other state, go to sleep or return.
+ *
+ * Synchronous forces are implemented with a wait queue. All callers trying
+ * to force a given lsn to disk must wait on the queue attached to the
+ * specific in-core log. When given in-core log finally completes its write
+ * to disk, that thread will wake up all threads waiting on the queue.
*/
-void
+int
xfs_log_force_lsn(
- xfs_mount_t *mp,
- xfs_lsn_t lsn,
- uint flags)
+ struct xfs_mount *mp,
+ xfs_lsn_t lsn,
+ uint flags,
+ int *log_flushed)
{
+ int ret;
+ ASSERT(lsn != 0);
+
+ XFS_STATS_INC(mp, xs_log_force);
trace_xfs_log_force(mp, lsn, _RET_IP_);
- _xfs_log_force_lsn(mp, lsn, flags, NULL);
+
+ lsn = xlog_cil_force_lsn(mp->m_log, lsn);
+ if (lsn == NULLCOMMITLSN)
+ return 0;
+
+ ret = __xfs_log_force_lsn(mp, lsn, flags, log_flushed, false);
+ if (ret == -EAGAIN)
+ ret = __xfs_log_force_lsn(mp, lsn, flags, log_flushed, true);
+ return ret;
}
/*
@@ -4035,7 +3981,7 @@ xfs_log_force_umount(
* to guarantee this.
*/
if (!logerror)
- _xfs_log_force(mp, XFS_LOG_SYNC, NULL);
+ xfs_log_force(mp, XFS_LOG_SYNC);
/*
* mark the filesystem and the as in a shutdown state and wake
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h
index bf212772595c..7e2d62922a16 100644
--- a/fs/xfs/xfs_log.h
+++ b/fs/xfs/xfs_log.h
@@ -129,18 +129,9 @@ xfs_lsn_t xfs_log_done(struct xfs_mount *mp,
struct xlog_ticket *ticket,
struct xlog_in_core **iclog,
bool regrant);
-int _xfs_log_force(struct xfs_mount *mp,
- uint flags,
- int *log_forced);
-void xfs_log_force(struct xfs_mount *mp,
- uint flags);
-int _xfs_log_force_lsn(struct xfs_mount *mp,
- xfs_lsn_t lsn,
- uint flags,
- int *log_forced);
-void xfs_log_force_lsn(struct xfs_mount *mp,
- xfs_lsn_t lsn,
- uint flags);
+int xfs_log_force(struct xfs_mount *mp, uint flags);
+int xfs_log_force_lsn(struct xfs_mount *mp, xfs_lsn_t lsn, uint flags,
+ int *log_forced);
int xfs_log_mount(struct xfs_mount *mp,
struct xfs_buftarg *log_target,
xfs_daddr_t start_block,
diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c
index 43aa42a3a5d3..cb376ac8a595 100644
--- a/fs/xfs/xfs_log_cil.c
+++ b/fs/xfs/xfs_log_cil.c
@@ -202,7 +202,7 @@ xlog_cil_alloc_shadow_bufs(
*/
kmem_free(lip->li_lv_shadow);
- lv = kmem_alloc(buf_size, KM_SLEEP|KM_NOFS);
+ lv = kmem_alloc_large(buf_size, KM_SLEEP | KM_NOFS);
memset(lv, 0, xlog_cil_iovec_space(niovecs));
lv->lv_item = lip;
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 00240c9ee72e..2b2383f1895e 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -3173,13 +3173,6 @@ xlog_recover_inode_pass2(
/* recover the log dinode inode into the on disk inode */
xfs_log_dinode_to_disk(ldip, dip);
- /* the rest is in on-disk format */
- if (item->ri_buf[1].i_len > isize) {
- memcpy((char *)dip + isize,
- item->ri_buf[1].i_addr + isize,
- item->ri_buf[1].i_len - isize);
- }
-
fields = in_f->ilf_fields;
if (fields & XFS_ILOG_DEV)
xfs_dinode_put_rdev(dip, in_f->ilf_u.ilfu_rdev);
@@ -3252,7 +3245,9 @@ xlog_recover_inode_pass2(
}
out_owner_change:
- if (in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER))
+ /* Recover the swapext owner change unless inode has been deleted */
+ if ((in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER)) &&
+ (dip->di_mode != 0))
error = xfs_recover_inode_owner_change(mp, dip, in_f,
buffer_list);
/* re-generate the checksum. */
@@ -3434,7 +3429,7 @@ xlog_recover_efi_pass2(
}
atomic_set(&efip->efi_next_extent, efi_formatp->efi_nextents);
- spin_lock(&log->l_ailp->xa_lock);
+ spin_lock(&log->l_ailp->ail_lock);
/*
* The EFI has two references. One for the EFD and one for EFI to ensure
* it makes it into the AIL. Insert the EFI into the AIL directly and
@@ -3477,7 +3472,7 @@ xlog_recover_efd_pass2(
* Search for the EFI with the id in the EFD format structure in the
* AIL.
*/
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
while (lip != NULL) {
if (lip->li_type == XFS_LI_EFI) {
@@ -3487,9 +3482,9 @@ xlog_recover_efd_pass2(
* Drop the EFD reference to the EFI. This
* removes the EFI from the AIL and frees it.
*/
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
xfs_efi_release(efip);
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
break;
}
}
@@ -3497,7 +3492,7 @@ xlog_recover_efd_pass2(
}
xfs_trans_ail_cursor_done(&cur);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
return 0;
}
@@ -3530,7 +3525,7 @@ xlog_recover_rui_pass2(
}
atomic_set(&ruip->rui_next_extent, rui_formatp->rui_nextents);
- spin_lock(&log->l_ailp->xa_lock);
+ spin_lock(&log->l_ailp->ail_lock);
/*
* The RUI has two references. One for the RUD and one for RUI to ensure
* it makes it into the AIL. Insert the RUI into the AIL directly and
@@ -3570,7 +3565,7 @@ xlog_recover_rud_pass2(
* Search for the RUI with the id in the RUD format structure in the
* AIL.
*/
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
while (lip != NULL) {
if (lip->li_type == XFS_LI_RUI) {
@@ -3580,9 +3575,9 @@ xlog_recover_rud_pass2(
* Drop the RUD reference to the RUI. This
* removes the RUI from the AIL and frees it.
*/
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
xfs_rui_release(ruip);
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
break;
}
}
@@ -3590,7 +3585,7 @@ xlog_recover_rud_pass2(
}
xfs_trans_ail_cursor_done(&cur);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
return 0;
}
@@ -3646,7 +3641,7 @@ xlog_recover_cui_pass2(
}
atomic_set(&cuip->cui_next_extent, cui_formatp->cui_nextents);
- spin_lock(&log->l_ailp->xa_lock);
+ spin_lock(&log->l_ailp->ail_lock);
/*
* The CUI has two references. One for the CUD and one for CUI to ensure
* it makes it into the AIL. Insert the CUI into the AIL directly and
@@ -3687,7 +3682,7 @@ xlog_recover_cud_pass2(
* Search for the CUI with the id in the CUD format structure in the
* AIL.
*/
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
while (lip != NULL) {
if (lip->li_type == XFS_LI_CUI) {
@@ -3697,9 +3692,9 @@ xlog_recover_cud_pass2(
* Drop the CUD reference to the CUI. This
* removes the CUI from the AIL and frees it.
*/
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
xfs_cui_release(cuip);
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
break;
}
}
@@ -3707,7 +3702,7 @@ xlog_recover_cud_pass2(
}
xfs_trans_ail_cursor_done(&cur);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
return 0;
}
@@ -3765,7 +3760,7 @@ xlog_recover_bui_pass2(
}
atomic_set(&buip->bui_next_extent, bui_formatp->bui_nextents);
- spin_lock(&log->l_ailp->xa_lock);
+ spin_lock(&log->l_ailp->ail_lock);
/*
* The RUI has two references. One for the RUD and one for RUI to ensure
* it makes it into the AIL. Insert the RUI into the AIL directly and
@@ -3806,7 +3801,7 @@ xlog_recover_bud_pass2(
* Search for the BUI with the id in the BUD format structure in the
* AIL.
*/
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
while (lip != NULL) {
if (lip->li_type == XFS_LI_BUI) {
@@ -3816,9 +3811,9 @@ xlog_recover_bud_pass2(
* Drop the BUD reference to the BUI. This
* removes the BUI from the AIL and frees it.
*/
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
xfs_bui_release(buip);
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
break;
}
}
@@ -3826,7 +3821,7 @@ xlog_recover_bud_pass2(
}
xfs_trans_ail_cursor_done(&cur);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
return 0;
}
@@ -4659,9 +4654,9 @@ xlog_recover_process_efi(
if (test_bit(XFS_EFI_RECOVERED, &efip->efi_flags))
return 0;
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
error = xfs_efi_recover(mp, efip);
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
return error;
}
@@ -4677,9 +4672,9 @@ xlog_recover_cancel_efi(
efip = container_of(lip, struct xfs_efi_log_item, efi_item);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
xfs_efi_release(efip);
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
}
/* Recover the RUI if necessary. */
@@ -4699,9 +4694,9 @@ xlog_recover_process_rui(
if (test_bit(XFS_RUI_RECOVERED, &ruip->rui_flags))
return 0;
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
error = xfs_rui_recover(mp, ruip);
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
return error;
}
@@ -4717,9 +4712,9 @@ xlog_recover_cancel_rui(
ruip = container_of(lip, struct xfs_rui_log_item, rui_item);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
xfs_rui_release(ruip);
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
}
/* Recover the CUI if necessary. */
@@ -4740,9 +4735,9 @@ xlog_recover_process_cui(
if (test_bit(XFS_CUI_RECOVERED, &cuip->cui_flags))
return 0;
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
error = xfs_cui_recover(mp, cuip, dfops);
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
return error;
}
@@ -4758,9 +4753,9 @@ xlog_recover_cancel_cui(
cuip = container_of(lip, struct xfs_cui_log_item, cui_item);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
xfs_cui_release(cuip);
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
}
/* Recover the BUI if necessary. */
@@ -4781,9 +4776,9 @@ xlog_recover_process_bui(
if (test_bit(XFS_BUI_RECOVERED, &buip->bui_flags))
return 0;
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
error = xfs_bui_recover(mp, buip, dfops);
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
return error;
}
@@ -4799,9 +4794,9 @@ xlog_recover_cancel_bui(
buip = container_of(lip, struct xfs_bui_log_item, bui_item);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
xfs_bui_release(buip);
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
}
/* Is this log item a deferred action intent? */
@@ -4889,7 +4884,7 @@ xlog_recover_process_intents(
#endif
ailp = log->l_ailp;
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
#if defined(DEBUG) || defined(XFS_WARN)
last_lsn = xlog_assign_lsn(log->l_curr_cycle, log->l_curr_block);
@@ -4943,7 +4938,7 @@ xlog_recover_process_intents(
}
out:
xfs_trans_ail_cursor_done(&cur);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
if (error)
xfs_defer_cancel(&dfops);
else
@@ -4966,7 +4961,7 @@ xlog_recover_cancel_intents(
struct xfs_ail *ailp;
ailp = log->l_ailp;
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
while (lip != NULL) {
/*
@@ -5000,7 +4995,7 @@ xlog_recover_cancel_intents(
}
xfs_trans_ail_cursor_done(&cur);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
return error;
}
@@ -5127,16 +5122,9 @@ xlog_recover_process_iunlinks(
xfs_agino_t agino;
int bucket;
int error;
- uint mp_dmevmask;
mp = log->l_mp;
- /*
- * Prevent any DMAPI event from being sent while in this function.
- */
- mp_dmevmask = mp->m_dmevmask;
- mp->m_dmevmask = 0;
-
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
/*
* Find the agi for this ag.
@@ -5172,8 +5160,6 @@ xlog_recover_process_iunlinks(
}
xfs_buf_rele(agibp);
}
-
- mp->m_dmevmask = mp_dmevmask;
}
STATIC int
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 98fd41cbb9e1..a901b86772f8 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -803,8 +803,6 @@ xfs_mountfs(
get_unaligned_be16(&sbp->sb_uuid.b[4]);
mp->m_fixedfsid[1] = get_unaligned_be32(&sbp->sb_uuid.b[0]);
- mp->m_dmevmask = 0; /* not persistent; set after each mount */
-
error = xfs_da_mount(mp);
if (error) {
xfs_warn(mp, "Failed dir/attr init: %d", error);
@@ -819,8 +817,6 @@ xfs_mountfs(
/*
* Allocate and initialize the per-ag data.
*/
- spin_lock_init(&mp->m_perag_lock);
- INIT_RADIX_TREE(&mp->m_perag_tree, GFP_ATOMIC);
error = xfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi);
if (error) {
xfs_warn(mp, "Failed per-ag init: %d", error);
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index e0792d036be2..10b90bbc5162 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -138,7 +138,6 @@ typedef struct xfs_mount {
spinlock_t m_perag_lock; /* lock for m_perag_tree */
struct mutex m_growlock; /* growfs mutex */
int m_fixedfsid[2]; /* unchanged for life of FS */
- uint m_dmevmask; /* DMI events for this FS */
uint64_t m_flags; /* global mount flags */
bool m_inotbt_nores; /* no per-AG finobt resv. */
int m_ialloc_inos; /* inodes in inode allocation */
@@ -326,8 +325,9 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d)
/* per-AG block reservation data structures*/
enum xfs_ag_resv_type {
XFS_AG_RESV_NONE = 0,
- XFS_AG_RESV_METADATA,
XFS_AG_RESV_AGFL,
+ XFS_AG_RESV_METADATA,
+ XFS_AG_RESV_RMAPBT,
};
struct xfs_ag_resv {
@@ -353,6 +353,7 @@ typedef struct xfs_perag {
char pagi_inodeok; /* The agi is ok for inodes */
uint8_t pagf_levels[XFS_BTNUM_AGF];
/* # of levels in bno & cnt btree */
+ bool pagf_agflreset; /* agfl requires reset before use */
uint32_t pagf_flcount; /* count of blocks in freelist */
xfs_extlen_t pagf_freeblks; /* total free blocks */
xfs_extlen_t pagf_longest; /* longest free space */
@@ -391,8 +392,8 @@ typedef struct xfs_perag {
/* Blocks reserved for all kinds of metadata. */
struct xfs_ag_resv pag_meta_resv;
- /* Blocks reserved for just AGFL-based metadata. */
- struct xfs_ag_resv pag_agfl_resv;
+ /* Blocks reserved for the reverse mapping btree. */
+ struct xfs_ag_resv pag_rmapbt_resv;
/* reference count */
uint8_t pagf_refcount_level;
@@ -406,8 +407,8 @@ xfs_perag_resv(
switch (type) {
case XFS_AG_RESV_METADATA:
return &pag->pag_meta_resv;
- case XFS_AG_RESV_AGFL:
- return &pag->pag_agfl_resv;
+ case XFS_AG_RESV_RMAPBT:
+ return &pag->pag_rmapbt_resv;
default:
return NULL;
}
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 270246943a06..cdbd342a5249 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -394,7 +394,7 @@ xfs_reflink_allocate_cow(
retry:
ASSERT(xfs_is_reflink_inode(ip));
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
/*
* Even if the extent is not shared we might have a preallocation for
@@ -668,7 +668,7 @@ xfs_reflink_cancel_cow_range(
/* Start a rolling transaction to remove the mappings */
error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_write,
- 0, 0, 0, &tp);
+ 0, 0, XFS_TRANS_NOFS, &tp);
if (error)
goto out;
@@ -741,7 +741,7 @@ xfs_reflink_end_cow(
(unsigned int)(end_fsb - offset_fsb),
XFS_DATA_FORK);
error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_write,
- resblks, 0, XFS_TRANS_RESERVE, &tp);
+ resblks, 0, XFS_TRANS_RESERVE | XFS_TRANS_NOFS, &tp);
if (error)
goto out;
@@ -762,10 +762,8 @@ xfs_reflink_end_cow(
xfs_trim_extent(&del, offset_fsb, end_fsb - offset_fsb);
/* Extent delete may have bumped ext forward */
- if (!del.br_blockcount) {
- xfs_iext_prev(ifp, &icur);
- goto next_extent;
- }
+ if (!del.br_blockcount)
+ goto prev_extent;
ASSERT(!isnullstartblock(got.br_startblock));
@@ -774,10 +772,8 @@ xfs_reflink_end_cow(
* speculatively preallocated CoW extents that have been
* allocated but have not yet been involved in a write.
*/
- if (got.br_state == XFS_EXT_UNWRITTEN) {
- xfs_iext_prev(ifp, &icur);
- goto next_extent;
- }
+ if (got.br_state == XFS_EXT_UNWRITTEN)
+ goto prev_extent;
/* Unmap the old blocks in the data fork. */
xfs_defer_init(&dfops, &firstfsb);
@@ -816,9 +812,12 @@ xfs_reflink_end_cow(
error = xfs_defer_finish(&tp, &dfops);
if (error)
goto out_defer;
-next_extent:
if (!xfs_iext_get_extent(ifp, &icur, &got))
break;
+ continue;
+prev_extent:
+ if (!xfs_iext_prev_extent(ifp, &icur, &got))
+ break;
}
error = xfs_trans_commit(tp);
@@ -1061,7 +1060,7 @@ xfs_reflink_ag_has_free_space(
return 0;
pag = xfs_perag_get(mp, agno);
- if (xfs_ag_resv_critical(pag, XFS_AG_RESV_AGFL) ||
+ if (xfs_ag_resv_critical(pag, XFS_AG_RESV_RMAPBT) ||
xfs_ag_resv_critical(pag, XFS_AG_RESV_METADATA))
error = -ENOSPC;
xfs_perag_put(pag);
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 93588ea3d3d2..612c1d5348b3 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -972,7 +972,6 @@ xfs_fs_destroy_inode(
struct inode *inode)
{
struct xfs_inode *ip = XFS_I(inode);
- int error;
trace_xfs_destroy_inode(ip);
@@ -980,14 +979,6 @@ xfs_fs_destroy_inode(
XFS_STATS_INC(ip->i_mount, vn_rele);
XFS_STATS_INC(ip->i_mount, vn_remove);
- if (xfs_is_reflink_inode(ip)) {
- error = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF, true);
- if (error && !XFS_FORCED_SHUTDOWN(ip->i_mount))
- xfs_warn(ip->i_mount,
-"Error %d while evicting CoW blocks for inode %llu.",
- error, ip->i_ino);
- }
-
xfs_inactive(ip);
ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0);
@@ -1009,6 +1000,28 @@ xfs_fs_destroy_inode(
xfs_inode_set_reclaim_tag(ip);
}
+static void
+xfs_fs_dirty_inode(
+ struct inode *inode,
+ int flag)
+{
+ struct xfs_inode *ip = XFS_I(inode);
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_trans *tp;
+
+ if (!(inode->i_sb->s_flags & SB_LAZYTIME))
+ return;
+ if (flag != I_DIRTY_SYNC || !(inode->i_state & I_DIRTY_TIME))
+ return;
+
+ if (xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp))
+ return;
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_TIMESTAMP);
+ xfs_trans_commit(tp);
+}
+
/*
* Slab object creation initialisation for the XFS inode.
* This covers only the idempotent fields in the XFS inode;
@@ -1566,29 +1579,48 @@ xfs_destroy_percpu_counters(
percpu_counter_destroy(&mp->m_fdblocks);
}
-STATIC int
-xfs_fs_fill_super(
- struct super_block *sb,
- void *data,
- int silent)
+static struct xfs_mount *
+xfs_mount_alloc(
+ struct super_block *sb)
{
- struct inode *root;
- struct xfs_mount *mp = NULL;
- int flags = 0, error = -ENOMEM;
+ struct xfs_mount *mp;
mp = kzalloc(sizeof(struct xfs_mount), GFP_KERNEL);
if (!mp)
- goto out;
+ return NULL;
+ mp->m_super = sb;
spin_lock_init(&mp->m_sb_lock);
+ spin_lock_init(&mp->m_agirotor_lock);
+ INIT_RADIX_TREE(&mp->m_perag_tree, GFP_ATOMIC);
+ spin_lock_init(&mp->m_perag_lock);
mutex_init(&mp->m_growlock);
atomic_set(&mp->m_active_trans, 0);
INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker);
INIT_DELAYED_WORK(&mp->m_eofblocks_work, xfs_eofblocks_worker);
INIT_DELAYED_WORK(&mp->m_cowblocks_work, xfs_cowblocks_worker);
mp->m_kobj.kobject.kset = xfs_kset;
+ return mp;
+}
- mp->m_super = sb;
+
+STATIC int
+xfs_fs_fill_super(
+ struct super_block *sb,
+ void *data,
+ int silent)
+{
+ struct inode *root;
+ struct xfs_mount *mp = NULL;
+ int flags = 0, error = -ENOMEM;
+
+ /*
+ * allocate mp and do all low-level struct initializations before we
+ * attach it to the super
+ */
+ mp = xfs_mount_alloc(sb);
+ if (!mp)
+ goto out;
sb->s_fs_info = mp;
error = xfs_parseargs(mp, (char *)data);
@@ -1789,6 +1821,7 @@ xfs_fs_free_cached_objects(
static const struct super_operations xfs_super_operations = {
.alloc_inode = xfs_fs_alloc_inode,
.destroy_inode = xfs_fs_destroy_inode,
+ .dirty_inode = xfs_fs_dirty_inode,
.drop_inode = xfs_fs_drop_inode,
.put_super = xfs_fs_put_super,
.sync_fs = xfs_fs_sync_fs,
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 945de08af7ba..a982c0b623d0 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -1477,7 +1477,7 @@ TRACE_EVENT(xfs_extent_busy_trim,
__entry->tlen)
);
-TRACE_EVENT(xfs_agf,
+DECLARE_EVENT_CLASS(xfs_agf_class,
TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags,
unsigned long caller_ip),
TP_ARGS(mp, agf, flags, caller_ip),
@@ -1533,6 +1533,13 @@ TRACE_EVENT(xfs_agf,
__entry->longest,
(void *)__entry->caller_ip)
);
+#define DEFINE_AGF_EVENT(name) \
+DEFINE_EVENT(xfs_agf_class, name, \
+ TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags, \
+ unsigned long caller_ip), \
+ TP_ARGS(mp, agf, flags, caller_ip))
+DEFINE_AGF_EVENT(xfs_agf);
+DEFINE_AGF_EVENT(xfs_agfl_reset);
TRACE_EVENT(xfs_free_extent,
TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno,
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 86f92df32c42..d6d8f9d129a7 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -119,8 +119,11 @@ xfs_trans_dup(
/* We gave our writer reference to the new transaction */
tp->t_flags |= XFS_TRANS_NO_WRITECOUNT;
ntp->t_ticket = xfs_log_ticket_get(tp->t_ticket);
+
+ ASSERT(tp->t_blk_res >= tp->t_blk_res_used);
ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used;
tp->t_blk_res = tp->t_blk_res_used;
+
ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used;
tp->t_rtx_res = tp->t_rtx_res_used;
ntp->t_pflags = tp->t_pflags;
@@ -344,13 +347,14 @@ xfs_trans_mod_sb(
break;
case XFS_TRANS_SB_FDBLOCKS:
/*
- * Track the number of blocks allocated in the
- * transaction. Make sure it does not exceed the
- * number reserved.
+ * Track the number of blocks allocated in the transaction.
+ * Make sure it does not exceed the number reserved. If so,
+ * shutdown as this can lead to accounting inconsistency.
*/
if (delta < 0) {
tp->t_blk_res_used += (uint)-delta;
- ASSERT(tp->t_blk_res_used <= tp->t_blk_res);
+ if (tp->t_blk_res_used > tp->t_blk_res)
+ xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
}
tp->t_fdblocks_delta += delta;
if (xfs_sb_version_haslazysbcount(&mp->m_sb))
@@ -803,8 +807,8 @@ xfs_log_item_batch_insert(
{
int i;
- spin_lock(&ailp->xa_lock);
- /* xfs_trans_ail_update_bulk drops ailp->xa_lock */
+ spin_lock(&ailp->ail_lock);
+ /* xfs_trans_ail_update_bulk drops ailp->ail_lock */
xfs_trans_ail_update_bulk(ailp, cur, log_items, nr_items, commit_lsn);
for (i = 0; i < nr_items; i++) {
@@ -847,9 +851,9 @@ xfs_trans_committed_bulk(
struct xfs_ail_cursor cur;
int i = 0;
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
xfs_trans_ail_cursor_last(ailp, &cur, commit_lsn);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
/* unpin all the log items */
for (lv = log_vector; lv; lv = lv->lv_next ) {
@@ -869,7 +873,7 @@ xfs_trans_committed_bulk(
* object into the AIL as we are in a shutdown situation.
*/
if (aborted) {
- ASSERT(XFS_FORCED_SHUTDOWN(ailp->xa_mount));
+ ASSERT(XFS_FORCED_SHUTDOWN(ailp->ail_mount));
lip->li_ops->iop_unpin(lip, 1);
continue;
}
@@ -883,11 +887,11 @@ xfs_trans_committed_bulk(
* not affect the AIL cursor the bulk insert path is
* using.
*/
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0)
xfs_trans_ail_update(ailp, lip, item_lsn);
else
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
lip->li_ops->iop_unpin(lip, 0);
continue;
}
@@ -905,9 +909,9 @@ xfs_trans_committed_bulk(
if (i)
xfs_log_item_batch_insert(ailp, &cur, log_items, i, commit_lsn);
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
xfs_trans_ail_cursor_done(&cur);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
}
/*
@@ -966,7 +970,7 @@ __xfs_trans_commit(
* log out now and wait for it.
*/
if (sync) {
- error = _xfs_log_force_lsn(mp, commit_lsn, XFS_LOG_SYNC, NULL);
+ error = xfs_log_force_lsn(mp, commit_lsn, XFS_LOG_SYNC, NULL);
XFS_STATS_INC(mp, xs_trans_sync);
} else {
XFS_STATS_INC(mp, xs_trans_async);
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index cef89f7127d3..d4a2445215e6 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -40,7 +40,7 @@ xfs_ail_check(
{
xfs_log_item_t *prev_lip;
- if (list_empty(&ailp->xa_ail))
+ if (list_empty(&ailp->ail_head))
return;
/*
@@ -48,11 +48,11 @@ xfs_ail_check(
*/
ASSERT((lip->li_flags & XFS_LI_IN_AIL) != 0);
prev_lip = list_entry(lip->li_ail.prev, xfs_log_item_t, li_ail);
- if (&prev_lip->li_ail != &ailp->xa_ail)
+ if (&prev_lip->li_ail != &ailp->ail_head)
ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0);
prev_lip = list_entry(lip->li_ail.next, xfs_log_item_t, li_ail);
- if (&prev_lip->li_ail != &ailp->xa_ail)
+ if (&prev_lip->li_ail != &ailp->ail_head)
ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) >= 0);
@@ -69,10 +69,10 @@ static xfs_log_item_t *
xfs_ail_max(
struct xfs_ail *ailp)
{
- if (list_empty(&ailp->xa_ail))
+ if (list_empty(&ailp->ail_head))
return NULL;
- return list_entry(ailp->xa_ail.prev, xfs_log_item_t, li_ail);
+ return list_entry(ailp->ail_head.prev, xfs_log_item_t, li_ail);
}
/*
@@ -84,7 +84,7 @@ xfs_ail_next(
struct xfs_ail *ailp,
xfs_log_item_t *lip)
{
- if (lip->li_ail.next == &ailp->xa_ail)
+ if (lip->li_ail.next == &ailp->ail_head)
return NULL;
return list_first_entry(&lip->li_ail, xfs_log_item_t, li_ail);
@@ -105,11 +105,11 @@ xfs_ail_min_lsn(
xfs_lsn_t lsn = 0;
xfs_log_item_t *lip;
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
lip = xfs_ail_min(ailp);
if (lip)
lsn = lip->li_lsn;
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
return lsn;
}
@@ -124,11 +124,11 @@ xfs_ail_max_lsn(
xfs_lsn_t lsn = 0;
xfs_log_item_t *lip;
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
lip = xfs_ail_max(ailp);
if (lip)
lsn = lip->li_lsn;
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
return lsn;
}
@@ -146,7 +146,7 @@ xfs_trans_ail_cursor_init(
struct xfs_ail_cursor *cur)
{
cur->item = NULL;
- list_add_tail(&cur->list, &ailp->xa_cursors);
+ list_add_tail(&cur->list, &ailp->ail_cursors);
}
/*
@@ -194,7 +194,7 @@ xfs_trans_ail_cursor_clear(
{
struct xfs_ail_cursor *cur;
- list_for_each_entry(cur, &ailp->xa_cursors, list) {
+ list_for_each_entry(cur, &ailp->ail_cursors, list) {
if (cur->item == lip)
cur->item = (struct xfs_log_item *)
((uintptr_t)cur->item | 1);
@@ -222,7 +222,7 @@ xfs_trans_ail_cursor_first(
goto out;
}
- list_for_each_entry(lip, &ailp->xa_ail, li_ail) {
+ list_for_each_entry(lip, &ailp->ail_head, li_ail) {
if (XFS_LSN_CMP(lip->li_lsn, lsn) >= 0)
goto out;
}
@@ -241,7 +241,7 @@ __xfs_trans_ail_cursor_last(
{
xfs_log_item_t *lip;
- list_for_each_entry_reverse(lip, &ailp->xa_ail, li_ail) {
+ list_for_each_entry_reverse(lip, &ailp->ail_head, li_ail) {
if (XFS_LSN_CMP(lip->li_lsn, lsn) <= 0)
return lip;
}
@@ -310,7 +310,7 @@ xfs_ail_splice(
if (lip)
list_splice(list, &lip->li_ail);
else
- list_splice(list, &ailp->xa_ail);
+ list_splice(list, &ailp->ail_head);
}
/*
@@ -335,17 +335,17 @@ xfsaild_push_item(
* If log item pinning is enabled, skip the push and track the item as
* pinned. This can help induce head-behind-tail conditions.
*/
- if (XFS_TEST_ERROR(false, ailp->xa_mount, XFS_ERRTAG_LOG_ITEM_PIN))
+ if (XFS_TEST_ERROR(false, ailp->ail_mount, XFS_ERRTAG_LOG_ITEM_PIN))
return XFS_ITEM_PINNED;
- return lip->li_ops->iop_push(lip, &ailp->xa_buf_list);
+ return lip->li_ops->iop_push(lip, &ailp->ail_buf_list);
}
static long
xfsaild_push(
struct xfs_ail *ailp)
{
- xfs_mount_t *mp = ailp->xa_mount;
+ xfs_mount_t *mp = ailp->ail_mount;
struct xfs_ail_cursor cur;
xfs_log_item_t *lip;
xfs_lsn_t lsn;
@@ -360,30 +360,30 @@ xfsaild_push(
* buffers the last time we ran, force the log first and wait for it
* before pushing again.
*/
- if (ailp->xa_log_flush && ailp->xa_last_pushed_lsn == 0 &&
- (!list_empty_careful(&ailp->xa_buf_list) ||
+ if (ailp->ail_log_flush && ailp->ail_last_pushed_lsn == 0 &&
+ (!list_empty_careful(&ailp->ail_buf_list) ||
xfs_ail_min_lsn(ailp))) {
- ailp->xa_log_flush = 0;
+ ailp->ail_log_flush = 0;
XFS_STATS_INC(mp, xs_push_ail_flush);
xfs_log_force(mp, XFS_LOG_SYNC);
}
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
- /* barrier matches the xa_target update in xfs_ail_push() */
+ /* barrier matches the ail_target update in xfs_ail_push() */
smp_rmb();
- target = ailp->xa_target;
- ailp->xa_target_prev = target;
+ target = ailp->ail_target;
+ ailp->ail_target_prev = target;
- lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->xa_last_pushed_lsn);
+ lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->ail_last_pushed_lsn);
if (!lip) {
/*
* If the AIL is empty or our push has reached the end we are
* done now.
*/
xfs_trans_ail_cursor_done(&cur);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
goto out_done;
}
@@ -404,7 +404,7 @@ xfsaild_push(
XFS_STATS_INC(mp, xs_push_ail_success);
trace_xfs_ail_push(lip);
- ailp->xa_last_pushed_lsn = lsn;
+ ailp->ail_last_pushed_lsn = lsn;
break;
case XFS_ITEM_FLUSHING:
@@ -423,7 +423,7 @@ xfsaild_push(
trace_xfs_ail_flushing(lip);
flushing++;
- ailp->xa_last_pushed_lsn = lsn;
+ ailp->ail_last_pushed_lsn = lsn;
break;
case XFS_ITEM_PINNED:
@@ -431,7 +431,7 @@ xfsaild_push(
trace_xfs_ail_pinned(lip);
stuck++;
- ailp->xa_log_flush++;
+ ailp->ail_log_flush++;
break;
case XFS_ITEM_LOCKED:
XFS_STATS_INC(mp, xs_push_ail_locked);
@@ -468,10 +468,10 @@ xfsaild_push(
lsn = lip->li_lsn;
}
xfs_trans_ail_cursor_done(&cur);
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
- if (xfs_buf_delwri_submit_nowait(&ailp->xa_buf_list))
- ailp->xa_log_flush++;
+ if (xfs_buf_delwri_submit_nowait(&ailp->ail_buf_list))
+ ailp->ail_log_flush++;
if (!count || XFS_LSN_CMP(lsn, target) >= 0) {
out_done:
@@ -481,7 +481,7 @@ out_done:
* AIL before we start the next scan from the start of the AIL.
*/
tout = 50;
- ailp->xa_last_pushed_lsn = 0;
+ ailp->ail_last_pushed_lsn = 0;
} else if (((stuck + flushing) * 100) / count > 90) {
/*
* Either there is a lot of contention on the AIL or we are
@@ -494,7 +494,7 @@ out_done:
* the restart to issue a log force to unpin the stuck items.
*/
tout = 20;
- ailp->xa_last_pushed_lsn = 0;
+ ailp->ail_last_pushed_lsn = 0;
} else {
/*
* Assume we have more work to do in a short while.
@@ -536,26 +536,26 @@ xfsaild(
break;
}
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
/*
* Idle if the AIL is empty and we are not racing with a target
* update. We check the AIL after we set the task to a sleep
- * state to guarantee that we either catch an xa_target update
+ * state to guarantee that we either catch an ail_target update
* or that a wake_up resets the state to TASK_RUNNING.
* Otherwise, we run the risk of sleeping indefinitely.
*
- * The barrier matches the xa_target update in xfs_ail_push().
+ * The barrier matches the ail_target update in xfs_ail_push().
*/
smp_rmb();
if (!xfs_ail_min(ailp) &&
- ailp->xa_target == ailp->xa_target_prev) {
- spin_unlock(&ailp->xa_lock);
+ ailp->ail_target == ailp->ail_target_prev) {
+ spin_unlock(&ailp->ail_lock);
freezable_schedule();
tout = 0;
continue;
}
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
if (tout)
freezable_schedule_timeout(msecs_to_jiffies(tout));
@@ -592,8 +592,8 @@ xfs_ail_push(
xfs_log_item_t *lip;
lip = xfs_ail_min(ailp);
- if (!lip || XFS_FORCED_SHUTDOWN(ailp->xa_mount) ||
- XFS_LSN_CMP(threshold_lsn, ailp->xa_target) <= 0)
+ if (!lip || XFS_FORCED_SHUTDOWN(ailp->ail_mount) ||
+ XFS_LSN_CMP(threshold_lsn, ailp->ail_target) <= 0)
return;
/*
@@ -601,10 +601,10 @@ xfs_ail_push(
* the XFS_AIL_PUSHING_BIT.
*/
smp_wmb();
- xfs_trans_ail_copy_lsn(ailp, &ailp->xa_target, &threshold_lsn);
+ xfs_trans_ail_copy_lsn(ailp, &ailp->ail_target, &threshold_lsn);
smp_wmb();
- wake_up_process(ailp->xa_task);
+ wake_up_process(ailp->ail_task);
}
/*
@@ -630,18 +630,18 @@ xfs_ail_push_all_sync(
struct xfs_log_item *lip;
DEFINE_WAIT(wait);
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
while ((lip = xfs_ail_max(ailp)) != NULL) {
- prepare_to_wait(&ailp->xa_empty, &wait, TASK_UNINTERRUPTIBLE);
- ailp->xa_target = lip->li_lsn;
- wake_up_process(ailp->xa_task);
- spin_unlock(&ailp->xa_lock);
+ prepare_to_wait(&ailp->ail_empty, &wait, TASK_UNINTERRUPTIBLE);
+ ailp->ail_target = lip->li_lsn;
+ wake_up_process(ailp->ail_task);
+ spin_unlock(&ailp->ail_lock);
schedule();
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
}
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
- finish_wait(&ailp->xa_empty, &wait);
+ finish_wait(&ailp->ail_empty, &wait);
}
/*
@@ -672,7 +672,7 @@ xfs_trans_ail_update_bulk(
struct xfs_ail_cursor *cur,
struct xfs_log_item **log_items,
int nr_items,
- xfs_lsn_t lsn) __releases(ailp->xa_lock)
+ xfs_lsn_t lsn) __releases(ailp->ail_lock)
{
xfs_log_item_t *mlip;
int mlip_changed = 0;
@@ -705,13 +705,13 @@ xfs_trans_ail_update_bulk(
xfs_ail_splice(ailp, cur, &tmp, lsn);
if (mlip_changed) {
- if (!XFS_FORCED_SHUTDOWN(ailp->xa_mount))
- xlog_assign_tail_lsn_locked(ailp->xa_mount);
- spin_unlock(&ailp->xa_lock);
+ if (!XFS_FORCED_SHUTDOWN(ailp->ail_mount))
+ xlog_assign_tail_lsn_locked(ailp->ail_mount);
+ spin_unlock(&ailp->ail_lock);
- xfs_log_space_wake(ailp->xa_mount);
+ xfs_log_space_wake(ailp->ail_mount);
} else {
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
}
}
@@ -756,13 +756,13 @@ void
xfs_trans_ail_delete(
struct xfs_ail *ailp,
struct xfs_log_item *lip,
- int shutdown_type) __releases(ailp->xa_lock)
+ int shutdown_type) __releases(ailp->ail_lock)
{
- struct xfs_mount *mp = ailp->xa_mount;
+ struct xfs_mount *mp = ailp->ail_mount;
bool mlip_changed;
if (!(lip->li_flags & XFS_LI_IN_AIL)) {
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
if (!XFS_FORCED_SHUTDOWN(mp)) {
xfs_alert_tag(mp, XFS_PTAG_AILDELETE,
"%s: attempting to delete a log item that is not in the AIL",
@@ -776,13 +776,13 @@ xfs_trans_ail_delete(
if (mlip_changed) {
if (!XFS_FORCED_SHUTDOWN(mp))
xlog_assign_tail_lsn_locked(mp);
- if (list_empty(&ailp->xa_ail))
- wake_up_all(&ailp->xa_empty);
+ if (list_empty(&ailp->ail_head))
+ wake_up_all(&ailp->ail_empty);
}
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
if (mlip_changed)
- xfs_log_space_wake(ailp->xa_mount);
+ xfs_log_space_wake(ailp->ail_mount);
}
int
@@ -795,16 +795,16 @@ xfs_trans_ail_init(
if (!ailp)
return -ENOMEM;
- ailp->xa_mount = mp;
- INIT_LIST_HEAD(&ailp->xa_ail);
- INIT_LIST_HEAD(&ailp->xa_cursors);
- spin_lock_init(&ailp->xa_lock);
- INIT_LIST_HEAD(&ailp->xa_buf_list);
- init_waitqueue_head(&ailp->xa_empty);
+ ailp->ail_mount = mp;
+ INIT_LIST_HEAD(&ailp->ail_head);
+ INIT_LIST_HEAD(&ailp->ail_cursors);
+ spin_lock_init(&ailp->ail_lock);
+ INIT_LIST_HEAD(&ailp->ail_buf_list);
+ init_waitqueue_head(&ailp->ail_empty);
- ailp->xa_task = kthread_run(xfsaild, ailp, "xfsaild/%s",
- ailp->xa_mount->m_fsname);
- if (IS_ERR(ailp->xa_task))
+ ailp->ail_task = kthread_run(xfsaild, ailp, "xfsaild/%s",
+ ailp->ail_mount->m_fsname);
+ if (IS_ERR(ailp->ail_task))
goto out_free_ailp;
mp->m_ail = ailp;
@@ -821,6 +821,6 @@ xfs_trans_ail_destroy(
{
struct xfs_ail *ailp = mp->m_ail;
- kthread_stop(ailp->xa_task);
+ kthread_stop(ailp->ail_task);
kmem_free(ailp);
}
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
index 653ce379d36b..a5d9dfc45d98 100644
--- a/fs/xfs/xfs_trans_buf.c
+++ b/fs/xfs/xfs_trans_buf.c
@@ -431,8 +431,8 @@ xfs_trans_brelse(
* If the fs has shutdown and we dropped the last reference, it may fall
* on us to release a (possibly dirty) bli if it never made it to the
* AIL (e.g., the aborted unpin already happened and didn't release it
- * due to our reference). Since we're already shutdown and need xa_lock,
- * just force remove from the AIL and release the bli here.
+ * due to our reference). Since we're already shutdown and need
+ * ail_lock, just force remove from the AIL and release the bli here.
*/
if (XFS_FORCED_SHUTDOWN(tp->t_mountp) && freed) {
xfs_trans_ail_remove(&bip->bli_item, SHUTDOWN_LOG_IO_ERROR);
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c
index 4a89da4b6fe7..07cea592dc01 100644
--- a/fs/xfs/xfs_trans_inode.c
+++ b/fs/xfs/xfs_trans_inode.c
@@ -98,10 +98,24 @@ xfs_trans_log_inode(
xfs_inode_t *ip,
uint flags)
{
+ struct inode *inode = VFS_I(ip);
+
ASSERT(ip->i_itemp != NULL);
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
/*
+ * Don't bother with i_lock for the I_DIRTY_TIME check here, as races
+ * don't matter - we either will need an extra transaction in 24 hours
+ * to log the timestamps, or will clear already cleared fields in the
+ * worst case.
+ */
+ if (inode->i_state & (I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED)) {
+ spin_lock(&inode->i_lock);
+ inode->i_state &= ~(I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED);
+ spin_unlock(&inode->i_lock);
+ }
+
+ /*
* Record the specific change for fdatasync optimisation. This
* allows fdatasync to skip log forces for inodes that are only
* timestamp dirty. We do this before the change count so that
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
index b317a3644c00..be24b0c8a332 100644
--- a/fs/xfs/xfs_trans_priv.h
+++ b/fs/xfs/xfs_trans_priv.h
@@ -65,17 +65,17 @@ struct xfs_ail_cursor {
* Eventually we need to drive the locking in here as well.
*/
struct xfs_ail {
- struct xfs_mount *xa_mount;
- struct task_struct *xa_task;
- struct list_head xa_ail;
- xfs_lsn_t xa_target;
- xfs_lsn_t xa_target_prev;
- struct list_head xa_cursors;
- spinlock_t xa_lock;
- xfs_lsn_t xa_last_pushed_lsn;
- int xa_log_flush;
- struct list_head xa_buf_list;
- wait_queue_head_t xa_empty;
+ struct xfs_mount *ail_mount;
+ struct task_struct *ail_task;
+ struct list_head ail_head;
+ xfs_lsn_t ail_target;
+ xfs_lsn_t ail_target_prev;
+ struct list_head ail_cursors;
+ spinlock_t ail_lock;
+ xfs_lsn_t ail_last_pushed_lsn;
+ int ail_log_flush;
+ struct list_head ail_buf_list;
+ wait_queue_head_t ail_empty;
};
/*
@@ -84,7 +84,7 @@ struct xfs_ail {
void xfs_trans_ail_update_bulk(struct xfs_ail *ailp,
struct xfs_ail_cursor *cur,
struct xfs_log_item **log_items, int nr_items,
- xfs_lsn_t lsn) __releases(ailp->xa_lock);
+ xfs_lsn_t lsn) __releases(ailp->ail_lock);
/*
* Return a pointer to the first item in the AIL. If the AIL is empty, then
* return NULL.
@@ -93,7 +93,7 @@ static inline struct xfs_log_item *
xfs_ail_min(
struct xfs_ail *ailp)
{
- return list_first_entry_or_null(&ailp->xa_ail, struct xfs_log_item,
+ return list_first_entry_or_null(&ailp->ail_head, struct xfs_log_item,
li_ail);
}
@@ -101,14 +101,14 @@ static inline void
xfs_trans_ail_update(
struct xfs_ail *ailp,
struct xfs_log_item *lip,
- xfs_lsn_t lsn) __releases(ailp->xa_lock)
+ xfs_lsn_t lsn) __releases(ailp->ail_lock)
{
xfs_trans_ail_update_bulk(ailp, NULL, &lip, 1, lsn);
}
bool xfs_ail_delete_one(struct xfs_ail *ailp, struct xfs_log_item *lip);
void xfs_trans_ail_delete(struct xfs_ail *ailp, struct xfs_log_item *lip,
- int shutdown_type) __releases(ailp->xa_lock);
+ int shutdown_type) __releases(ailp->ail_lock);
static inline void
xfs_trans_ail_remove(
@@ -117,12 +117,12 @@ xfs_trans_ail_remove(
{
struct xfs_ail *ailp = lip->li_ailp;
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
/* xfs_trans_ail_delete() drops the AIL lock */
if (lip->li_flags & XFS_LI_IN_AIL)
xfs_trans_ail_delete(ailp, lip, shutdown_type);
else
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
}
void xfs_ail_push(struct xfs_ail *, xfs_lsn_t);
@@ -149,9 +149,9 @@ xfs_trans_ail_copy_lsn(
xfs_lsn_t *src)
{
ASSERT(sizeof(xfs_lsn_t) == 8); /* don't lock if it shrinks */
- spin_lock(&ailp->xa_lock);
+ spin_lock(&ailp->ail_lock);
*dst = *src;
- spin_unlock(&ailp->xa_lock);
+ spin_unlock(&ailp->ail_lock);
}
#else
static inline void
@@ -172,7 +172,7 @@ xfs_clear_li_failed(
struct xfs_buf *bp = lip->li_buf;
ASSERT(lip->li_flags & XFS_LI_IN_AIL);
- lockdep_assert_held(&lip->li_ailp->xa_lock);
+ lockdep_assert_held(&lip->li_ailp->ail_lock);
if (lip->li_flags & XFS_LI_FAILED) {
lip->li_flags &= ~XFS_LI_FAILED;
@@ -186,7 +186,7 @@ xfs_set_li_failed(
struct xfs_log_item *lip,
struct xfs_buf *bp)
{
- lockdep_assert_held(&lip->li_ailp->xa_lock);
+ lockdep_assert_held(&lip->li_ailp->ail_lock);
if (!(lip->li_flags & XFS_LI_FAILED)) {
xfs_buf_hold(bp);
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 8add3493a202..278841c75b97 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -599,7 +599,6 @@
IRQCHIP_OF_MATCH_TABLE() \
ACPI_PROBE_TABLE(irqchip) \
ACPI_PROBE_TABLE(timer) \
- ACPI_PROBE_TABLE(iort) \
EARLYCON_TABLE()
#define INIT_TEXT \
diff --git a/include/crypto/ablk_helper.h b/include/crypto/ablk_helper.h
deleted file mode 100644
index 4e655c2a4e15..000000000000
--- a/include/crypto/ablk_helper.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Shared async block cipher helpers
- */
-
-#ifndef _CRYPTO_ABLK_HELPER_H
-#define _CRYPTO_ABLK_HELPER_H
-
-#include <linux/crypto.h>
-#include <linux/kernel.h>
-#include <crypto/cryptd.h>
-
-struct async_helper_ctx {
- struct cryptd_ablkcipher *cryptd_tfm;
-};
-
-extern int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
- unsigned int key_len);
-
-extern int __ablk_encrypt(struct ablkcipher_request *req);
-
-extern int ablk_encrypt(struct ablkcipher_request *req);
-
-extern int ablk_decrypt(struct ablkcipher_request *req);
-
-extern void ablk_exit(struct crypto_tfm *tfm);
-
-extern int ablk_init_common(struct crypto_tfm *tfm, const char *drv_name);
-
-extern int ablk_init(struct crypto_tfm *tfm);
-
-#endif /* _CRYPTO_ABLK_HELPER_H */
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index e3cebf640c00..1aba888241dd 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -30,7 +30,6 @@ struct crypto_type {
int (*init_tfm)(struct crypto_tfm *tfm);
void (*show)(struct seq_file *m, struct crypto_alg *alg);
int (*report)(struct sk_buff *skb, struct crypto_alg *alg);
- struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask);
void (*free)(struct crypto_instance *inst);
unsigned int type;
diff --git a/include/crypto/engine.h b/include/crypto/engine.h
index dd04c1699b51..1cbec29af3d6 100644
--- a/include/crypto/engine.h
+++ b/include/crypto/engine.h
@@ -17,7 +17,10 @@
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <crypto/algapi.h>
+#include <crypto/aead.h>
+#include <crypto/akcipher.h>
#include <crypto/hash.h>
+#include <crypto/skcipher.h>
#define ENGINE_NAME_LEN 30
/*
@@ -37,12 +40,6 @@
* @unprepare_crypt_hardware: there are currently no more requests on the
* queue so the subsystem notifies the driver that it may relax the
* hardware by issuing this call
- * @prepare_cipher_request: do some prepare if need before handle the current request
- * @unprepare_cipher_request: undo any work done by prepare_cipher_request()
- * @cipher_one_request: do encryption for current request
- * @prepare_hash_request: do some prepare if need before handle the current request
- * @unprepare_hash_request: undo any work done by prepare_hash_request()
- * @hash_one_request: do hash for current request
* @kworker: kthread worker struct for request pump
* @pump_requests: work struct for scheduling work to the request pump
* @priv_data: the engine private data
@@ -65,19 +62,6 @@ struct crypto_engine {
int (*prepare_crypt_hardware)(struct crypto_engine *engine);
int (*unprepare_crypt_hardware)(struct crypto_engine *engine);
- int (*prepare_cipher_request)(struct crypto_engine *engine,
- struct ablkcipher_request *req);
- int (*unprepare_cipher_request)(struct crypto_engine *engine,
- struct ablkcipher_request *req);
- int (*prepare_hash_request)(struct crypto_engine *engine,
- struct ahash_request *req);
- int (*unprepare_hash_request)(struct crypto_engine *engine,
- struct ahash_request *req);
- int (*cipher_one_request)(struct crypto_engine *engine,
- struct ablkcipher_request *req);
- int (*hash_one_request)(struct crypto_engine *engine,
- struct ahash_request *req);
-
struct kthread_worker *kworker;
struct kthread_work pump_requests;
@@ -85,19 +69,45 @@ struct crypto_engine {
struct crypto_async_request *cur_req;
};
-int crypto_transfer_cipher_request(struct crypto_engine *engine,
- struct ablkcipher_request *req,
- bool need_pump);
-int crypto_transfer_cipher_request_to_engine(struct crypto_engine *engine,
- struct ablkcipher_request *req);
-int crypto_transfer_hash_request(struct crypto_engine *engine,
- struct ahash_request *req, bool need_pump);
+/*
+ * struct crypto_engine_op - crypto hardware engine operations
+ * @prepare__request: do some prepare if need before handle the current request
+ * @unprepare_request: undo any work done by prepare_request()
+ * @do_one_request: do encryption for current request
+ */
+struct crypto_engine_op {
+ int (*prepare_request)(struct crypto_engine *engine,
+ void *areq);
+ int (*unprepare_request)(struct crypto_engine *engine,
+ void *areq);
+ int (*do_one_request)(struct crypto_engine *engine,
+ void *areq);
+};
+
+struct crypto_engine_ctx {
+ struct crypto_engine_op op;
+};
+
+int crypto_transfer_ablkcipher_request_to_engine(struct crypto_engine *engine,
+ struct ablkcipher_request *req);
+int crypto_transfer_aead_request_to_engine(struct crypto_engine *engine,
+ struct aead_request *req);
+int crypto_transfer_akcipher_request_to_engine(struct crypto_engine *engine,
+ struct akcipher_request *req);
int crypto_transfer_hash_request_to_engine(struct crypto_engine *engine,
- struct ahash_request *req);
-void crypto_finalize_cipher_request(struct crypto_engine *engine,
- struct ablkcipher_request *req, int err);
+ struct ahash_request *req);
+int crypto_transfer_skcipher_request_to_engine(struct crypto_engine *engine,
+ struct skcipher_request *req);
+void crypto_finalize_ablkcipher_request(struct crypto_engine *engine,
+ struct ablkcipher_request *req, int err);
+void crypto_finalize_aead_request(struct crypto_engine *engine,
+ struct aead_request *req, int err);
+void crypto_finalize_akcipher_request(struct crypto_engine *engine,
+ struct akcipher_request *req, int err);
void crypto_finalize_hash_request(struct crypto_engine *engine,
struct ahash_request *req, int err);
+void crypto_finalize_skcipher_request(struct crypto_engine *engine,
+ struct skcipher_request *req, int err);
int crypto_engine_start(struct crypto_engine *engine);
int crypto_engine_stop(struct crypto_engine *engine);
struct crypto_engine *crypto_engine_alloc_init(struct device *dev, bool rt);
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index 2d1849dffb80..76e432cab75d 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -74,7 +74,8 @@ struct ahash_request {
* @init: **[mandatory]** Initialize the transformation context. Intended only to initialize the
* state of the HASH transformation at the beginning. This shall fill in
* the internal structures used during the entire duration of the whole
- * transformation. No data processing happens at this point.
+ * transformation. No data processing happens at this point. Driver code
+ * implementation must not use req->result.
* @update: **[mandatory]** Push a chunk of data into the driver for transformation. This
* function actually pushes blocks of data from upper layers into the
* driver, which then passes those to the hardware as seen fit. This
@@ -83,7 +84,8 @@ struct ahash_request {
* transformation. This function shall not modify the transformation
* context, as this function may be called in parallel with the same
* transformation object. Data processing can happen synchronously
- * [SHASH] or asynchronously [AHASH] at this point.
+ * [SHASH] or asynchronously [AHASH] at this point. Driver must not use
+ * req->result.
* @final: **[mandatory]** Retrieve result from the driver. This function finalizes the
* transformation and retrieves the resulting hash from the driver and
* pushes it back to upper layers. No data processing happens at this
@@ -120,11 +122,12 @@ struct ahash_request {
* you want to save partial result of the transformation after
* processing certain amount of data and reload this partial result
* multiple times later on for multiple re-use. No data processing
- * happens at this point.
+ * happens at this point. Driver must not use req->result.
* @import: Import partial state of the transformation. This function loads the
* entire state of the ongoing transformation from a provided block of
* data so the transformation can continue from this point onward. No
- * data processing happens at this point.
+ * data processing happens at this point. Driver must not use
+ * req->result.
* @halg: see struct hash_alg_common
*/
struct ahash_alg {
diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h
index 27040a46d50a..a0b0ad9d585e 100644
--- a/include/crypto/internal/hash.h
+++ b/include/crypto/internal/hash.h
@@ -126,11 +126,6 @@ int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc);
int shash_ahash_finup(struct ahash_request *req, struct shash_desc *desc);
int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc);
-int ahash_mcryptd_update(struct ahash_request *desc);
-int ahash_mcryptd_final(struct ahash_request *desc);
-int ahash_mcryptd_finup(struct ahash_request *desc);
-int ahash_mcryptd_digest(struct ahash_request *desc);
-
int crypto_init_shash_ops_async(struct crypto_tfm *tfm);
static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm)
diff --git a/include/crypto/internal/simd.h b/include/crypto/internal/simd.h
index 32ceb6929885..f18344518e32 100644
--- a/include/crypto/internal/simd.h
+++ b/include/crypto/internal/simd.h
@@ -7,6 +7,7 @@
#define _CRYPTO_INTERNAL_SIMD_H
struct simd_skcipher_alg;
+struct skcipher_alg;
struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname,
const char *drvname,
@@ -15,4 +16,10 @@ struct simd_skcipher_alg *simd_skcipher_create(const char *algname,
const char *basename);
void simd_skcipher_free(struct simd_skcipher_alg *alg);
+int simd_register_skciphers_compat(struct skcipher_alg *algs, int count,
+ struct simd_skcipher_alg **simd_algs);
+
+void simd_unregister_skciphers(struct skcipher_alg *algs, int count,
+ struct simd_skcipher_alg **simd_algs);
+
#endif /* _CRYPTO_INTERNAL_SIMD_H */
diff --git a/include/crypto/lrw.h b/include/crypto/lrw.h
deleted file mode 100644
index a9d44c06d081..000000000000
--- a/include/crypto/lrw.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _CRYPTO_LRW_H
-#define _CRYPTO_LRW_H
-
-#include <crypto/b128ops.h>
-
-struct scatterlist;
-struct gf128mul_64k;
-struct blkcipher_desc;
-
-#define LRW_BLOCK_SIZE 16
-
-struct lrw_table_ctx {
- /* optimizes multiplying a random (non incrementing, as at the
- * start of a new sector) value with key2, we could also have
- * used 4k optimization tables or no optimization at all. In the
- * latter case we would have to store key2 here */
- struct gf128mul_64k *table;
- /* stores:
- * key2*{ 0,0,...0,0,0,0,1 }, key2*{ 0,0,...0,0,0,1,1 },
- * key2*{ 0,0,...0,0,1,1,1 }, key2*{ 0,0,...0,1,1,1,1 }
- * key2*{ 0,0,...1,1,1,1,1 }, etc
- * needed for optimized multiplication of incrementing values
- * with key2 */
- be128 mulinc[128];
-};
-
-int lrw_init_table(struct lrw_table_ctx *ctx, const u8 *tweak);
-void lrw_free_table(struct lrw_table_ctx *ctx);
-
-struct lrw_crypt_req {
- be128 *tbuf;
- unsigned int tbuflen;
-
- struct lrw_table_ctx *table_ctx;
- void *crypt_ctx;
- void (*crypt_fn)(void *ctx, u8 *blks, unsigned int nbytes);
-};
-
-int lrw_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes,
- struct lrw_crypt_req *req);
-
-#endif /* _CRYPTO_LRW_H */
diff --git a/include/crypto/sm4.h b/include/crypto/sm4.h
new file mode 100644
index 000000000000..b64e64d20b28
--- /dev/null
+++ b/include/crypto/sm4.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Common values for the SM4 algorithm
+ * Copyright (C) 2018 ARM Limited or its affiliates.
+ */
+
+#ifndef _CRYPTO_SM4_H
+#define _CRYPTO_SM4_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+
+#define SM4_KEY_SIZE 16
+#define SM4_BLOCK_SIZE 16
+#define SM4_RKEY_WORDS 32
+
+struct crypto_sm4_ctx {
+ u32 rkey_enc[SM4_RKEY_WORDS];
+ u32 rkey_dec[SM4_RKEY_WORDS];
+};
+
+int crypto_sm4_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+ unsigned int key_len);
+int crypto_sm4_expand_key(struct crypto_sm4_ctx *ctx, const u8 *in_key,
+ unsigned int key_len);
+
+#endif
diff --git a/include/crypto/speck.h b/include/crypto/speck.h
new file mode 100644
index 000000000000..73cfc952d405
--- /dev/null
+++ b/include/crypto/speck.h
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Common values for the Speck algorithm
+ */
+
+#ifndef _CRYPTO_SPECK_H
+#define _CRYPTO_SPECK_H
+
+#include <linux/types.h>
+
+/* Speck128 */
+
+#define SPECK128_BLOCK_SIZE 16
+
+#define SPECK128_128_KEY_SIZE 16
+#define SPECK128_128_NROUNDS 32
+
+#define SPECK128_192_KEY_SIZE 24
+#define SPECK128_192_NROUNDS 33
+
+#define SPECK128_256_KEY_SIZE 32
+#define SPECK128_256_NROUNDS 34
+
+struct speck128_tfm_ctx {
+ u64 round_keys[SPECK128_256_NROUNDS];
+ int nrounds;
+};
+
+void crypto_speck128_encrypt(const struct speck128_tfm_ctx *ctx,
+ u8 *out, const u8 *in);
+
+void crypto_speck128_decrypt(const struct speck128_tfm_ctx *ctx,
+ u8 *out, const u8 *in);
+
+int crypto_speck128_setkey(struct speck128_tfm_ctx *ctx, const u8 *key,
+ unsigned int keysize);
+
+/* Speck64 */
+
+#define SPECK64_BLOCK_SIZE 8
+
+#define SPECK64_96_KEY_SIZE 12
+#define SPECK64_96_NROUNDS 26
+
+#define SPECK64_128_KEY_SIZE 16
+#define SPECK64_128_NROUNDS 27
+
+struct speck64_tfm_ctx {
+ u32 round_keys[SPECK64_128_NROUNDS];
+ int nrounds;
+};
+
+void crypto_speck64_encrypt(const struct speck64_tfm_ctx *ctx,
+ u8 *out, const u8 *in);
+
+void crypto_speck64_decrypt(const struct speck64_tfm_ctx *ctx,
+ u8 *out, const u8 *in);
+
+int crypto_speck64_setkey(struct speck64_tfm_ctx *ctx, const u8 *key,
+ unsigned int keysize);
+
+#endif /* _CRYPTO_SPECK_H */
diff --git a/include/crypto/xts.h b/include/crypto/xts.h
index 322aab6e78a7..34d94c95445a 100644
--- a/include/crypto/xts.h
+++ b/include/crypto/xts.h
@@ -6,27 +6,10 @@
#include <crypto/internal/skcipher.h>
#include <linux/fips.h>
-struct scatterlist;
-struct blkcipher_desc;
-
#define XTS_BLOCK_SIZE 16
-struct xts_crypt_req {
- le128 *tbuf;
- unsigned int tbuflen;
-
- void *tweak_ctx;
- void (*tweak_fn)(void *ctx, u8* dst, const u8* src);
- void *crypt_ctx;
- void (*crypt_fn)(void *ctx, u8 *blks, unsigned int nbytes);
-};
-
#define XTS_TWEAK_CAST(x) ((void (*)(void *, u8*, const u8*))(x))
-int xts_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes,
- struct xts_crypt_req *req);
-
static inline int xts_check_key(struct crypto_tfm *tfm,
const u8 *key, unsigned int keylen)
{
diff --git a/include/dt-bindings/media/tda1997x.h b/include/dt-bindings/media/tda1997x.h
new file mode 100644
index 000000000000..bd9fbd718ec9
--- /dev/null
+++ b/include/dt-bindings/media/tda1997x.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2017 Gateworks Corporation
+ */
+#ifndef _DT_BINDINGS_MEDIA_TDA1997X_H
+#define _DT_BINDINGS_MEDIA_TDA1997X_H
+
+/* TDA19973 36bit Video Port control registers */
+#define TDA1997X_VP36_35_32 0
+#define TDA1997X_VP36_31_28 1
+#define TDA1997X_VP36_27_24 2
+#define TDA1997X_VP36_23_20 3
+#define TDA1997X_VP36_19_16 4
+#define TDA1997X_VP36_15_12 5
+#define TDA1997X_VP36_11_08 6
+#define TDA1997X_VP36_07_04 7
+#define TDA1997X_VP36_03_00 8
+
+/* TDA19971 24bit Video Port control registers */
+#define TDA1997X_VP24_V23_20 0
+#define TDA1997X_VP24_V19_16 1
+#define TDA1997X_VP24_V15_12 3
+#define TDA1997X_VP24_V11_08 4
+#define TDA1997X_VP24_V07_04 6
+#define TDA1997X_VP24_V03_00 7
+
+/* Pin groups */
+#define TDA1997X_VP_OUT_EN 0x80 /* enable output group */
+#define TDA1997X_VP_HIZ 0x40 /* hi-Z output group when not used */
+#define TDA1997X_VP_SWP 0x10 /* pin-swap output group */
+#define TDA1997X_R_CR_CBCR_3_0 (0 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ)
+#define TDA1997X_R_CR_CBCR_7_4 (1 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ)
+#define TDA1997X_R_CR_CBCR_11_8 (2 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ)
+#define TDA1997X_B_CB_3_0 (3 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ)
+#define TDA1997X_B_CB_7_4 (4 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ)
+#define TDA1997X_B_CB_11_8 (5 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ)
+#define TDA1997X_G_Y_3_0 (6 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ)
+#define TDA1997X_G_Y_7_4 (7 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ)
+#define TDA1997X_G_Y_11_8 (8 | TDA1997X_VP_OUT_EN | TDA1997X_VP_HIZ)
+/* pinswapped groups */
+#define TDA1997X_R_CR_CBCR_3_0_S (TDA1997X_R_CR_CBCR_3_0 | TDA1997X_VP_SWAP)
+#define TDA1997X_R_CR_CBCR_7_4_S (TDA1997X_R_CR_CBCR_7_4 | TDA1997X_VP_SWAP)
+#define TDA1997X_R_CR_CBCR_11_8_S (TDA1997X_R_CR_CBCR_11_8 | TDA1997X_VP_SWAP)
+#define TDA1997X_B_CB_3_0_S (TDA1997X_B_CB_3_0 | TDA1997X_VP_SWAP)
+#define TDA1997X_B_CB_7_4_S (TDA1997X_B_CB_7_4 | TDA1997X_VP_SWAP)
+#define TDA1997X_B_CB_11_8_S (TDA1997X_B_CB_11_8 | TDA1997X_VP_SWAP)
+#define TDA1997X_G_Y_3_0_S (TDA1997X_G_Y_3_0 | TDA1997X_VP_SWAP)
+#define TDA1997X_G_Y_7_4_S (TDA1997X_G_Y_7_4 | TDA1997X_VP_SWAP)
+#define TDA1997X_G_Y_11_8_S (TDA1997X_G_Y_11_8 | TDA1997X_VP_SWAP)
+
+/* Audio bus DAI format */
+#define TDA1997X_I2S16 1 /* I2S 16bit */
+#define TDA1997X_I2S32 2 /* I2S 32bit */
+#define TDA1997X_SPDIF 3 /* SPDIF */
+#define TDA1997X_OBA 4 /* One Bit Audio */
+#define TDA1997X_DST 5 /* Direct Stream Transfer */
+#define TDA1997X_I2S16_HBR 6 /* HBR straight in I2S 16bit mode */
+#define TDA1997X_I2S16_HBR_DEMUX 7 /* HBR demux in I2S 16bit mode */
+#define TDA1997X_I2S32_HBR_DEMUX 8 /* HBR demux in I2S 32bit mode */
+#define TDA1997X_SPDIF_HBR_DEMUX 9 /* HBR demux in SPDIF mode */
+
+/* Audio bus channel layout */
+#define TDA1997X_LAYOUT0 0 /* 2-channel */
+#define TDA1997X_LAYOUT1 1 /* 8-channel */
+
+/* Audio bus clock */
+#define TDA1997X_ACLK_16FS 0
+#define TDA1997X_ACLK_32FS 1
+#define TDA1997X_ACLK_64FS 2
+#define TDA1997X_ACLK_128FS 3
+#define TDA1997X_ACLK_256FS 4
+#define TDA1997X_ACLK_512FS 5
+
+#endif /* _DT_BINDINGS_MEDIA_TDA1997X_H */
diff --git a/include/linux/byteorder/generic.h b/include/linux/byteorder/generic.h
index 451aaa0786ae..4b13e0a3e15b 100644
--- a/include/linux/byteorder/generic.h
+++ b/include/linux/byteorder/generic.h
@@ -156,6 +156,23 @@ static inline void le64_add_cpu(__le64 *var, u64 val)
*var = cpu_to_le64(le64_to_cpu(*var) + val);
}
+/* XXX: this stuff can be optimized */
+static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
+{
+ while (words--) {
+ __le32_to_cpus(buf);
+ buf++;
+ }
+}
+
+static inline void cpu_to_le32_array(u32 *buf, unsigned int words)
+{
+ while (words--) {
+ __cpu_to_le32s(buf);
+ buf++;
+ }
+}
+
static inline void be16_add_cpu(__be16 *var, u16 val)
{
*var = cpu_to_be16(be16_to_cpu(*var) + val);
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index f8e76d01a5ad..dc5b70449dc6 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -151,8 +151,8 @@ struct cgroup_subsys_state {
atomic_t online_cnt;
/* percpu_ref killing and RCU release */
- struct rcu_head rcu_head;
struct work_struct destroy_work;
+ struct rcu_work destroy_rwork;
/*
* PI: the parent css. Placed here for cache proximity to following
diff --git a/include/linux/console.h b/include/linux/console.h
index b8920a031a3e..dfd6b0e97855 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -46,46 +46,52 @@ enum con_scroll {
struct consw {
struct module *owner;
const char *(*con_startup)(void);
- void (*con_init)(struct vc_data *, int);
- void (*con_deinit)(struct vc_data *);
- void (*con_clear)(struct vc_data *, int, int, int, int);
- void (*con_putc)(struct vc_data *, int, int, int);
- void (*con_putcs)(struct vc_data *, const unsigned short *, int, int, int);
- void (*con_cursor)(struct vc_data *, int);
- bool (*con_scroll)(struct vc_data *, unsigned int top,
+ void (*con_init)(struct vc_data *vc, int init);
+ void (*con_deinit)(struct vc_data *vc);
+ void (*con_clear)(struct vc_data *vc, int sy, int sx, int height,
+ int width);
+ void (*con_putc)(struct vc_data *vc, int c, int ypos, int xpos);
+ void (*con_putcs)(struct vc_data *vc, const unsigned short *s,
+ int count, int ypos, int xpos);
+ void (*con_cursor)(struct vc_data *vc, int mode);
+ bool (*con_scroll)(struct vc_data *vc, unsigned int top,
unsigned int bottom, enum con_scroll dir,
unsigned int lines);
- int (*con_switch)(struct vc_data *);
- int (*con_blank)(struct vc_data *, int, int);
- int (*con_font_set)(struct vc_data *, struct console_font *, unsigned);
- int (*con_font_get)(struct vc_data *, struct console_font *);
- int (*con_font_default)(struct vc_data *, struct console_font *, char *);
- int (*con_font_copy)(struct vc_data *, int);
- int (*con_resize)(struct vc_data *, unsigned int, unsigned int,
- unsigned int);
- void (*con_set_palette)(struct vc_data *,
+ int (*con_switch)(struct vc_data *vc);
+ int (*con_blank)(struct vc_data *vc, int blank, int mode_switch);
+ int (*con_font_set)(struct vc_data *vc, struct console_font *font,
+ unsigned int flags);
+ int (*con_font_get)(struct vc_data *vc, struct console_font *font);
+ int (*con_font_default)(struct vc_data *vc,
+ struct console_font *font, char *name);
+ int (*con_font_copy)(struct vc_data *vc, int con);
+ int (*con_resize)(struct vc_data *vc, unsigned int width,
+ unsigned int height, unsigned int user);
+ void (*con_set_palette)(struct vc_data *vc,
const unsigned char *table);
- void (*con_scrolldelta)(struct vc_data *, int lines);
- int (*con_set_origin)(struct vc_data *);
- void (*con_save_screen)(struct vc_data *);
- u8 (*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8, u8);
- void (*con_invert_region)(struct vc_data *, u16 *, int);
- u16 *(*con_screen_pos)(struct vc_data *, int);
- unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, int *);
+ void (*con_scrolldelta)(struct vc_data *vc, int lines);
+ int (*con_set_origin)(struct vc_data *vc);
+ void (*con_save_screen)(struct vc_data *vc);
+ u8 (*con_build_attr)(struct vc_data *vc, u8 color, u8 intensity,
+ u8 blink, u8 underline, u8 reverse, u8 italic);
+ void (*con_invert_region)(struct vc_data *vc, u16 *p, int count);
+ u16 *(*con_screen_pos)(struct vc_data *vc, int offset);
+ unsigned long (*con_getxy)(struct vc_data *vc, unsigned long position,
+ int *px, int *py);
/*
* Flush the video console driver's scrollback buffer
*/
- void (*con_flush_scrollback)(struct vc_data *);
+ void (*con_flush_scrollback)(struct vc_data *vc);
/*
* Prepare the console for the debugger. This includes, but is not
* limited to, unblanking the console, loading an appropriate
* palette, and allowing debugger generated output.
*/
- int (*con_debug_enter)(struct vc_data *);
+ int (*con_debug_enter)(struct vc_data *vc);
/*
* Restore the console to its pre-debug state as closely as possible.
*/
- int (*con_debug_leave)(struct vc_data *);
+ int (*con_debug_leave)(struct vc_data *vc);
};
extern const struct consw *conswitchp;
diff --git a/include/linux/crc32c.h b/include/linux/crc32c.h
index 357ae4611a45..bd21af828ff6 100644
--- a/include/linux/crc32c.h
+++ b/include/linux/crc32c.h
@@ -5,6 +5,7 @@
#include <linux/types.h>
extern u32 crc32c(u32 crc, const void *address, unsigned int length);
+extern const char *crc32c_impl(void);
/* This macro exists for backwards-compatibility. */
#define crc32c_le crc32c
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 7e6e84cf6383..6eb06101089f 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -435,6 +435,14 @@ struct compress_alg {
* @cra_exit: Deinitialize the cryptographic transformation object. This is a
* counterpart to @cra_init, used to remove various changes set in
* @cra_init.
+ * @cra_u.ablkcipher: Union member which contains an asynchronous block cipher
+ * definition. See @struct @ablkcipher_alg.
+ * @cra_u.blkcipher: Union member which contains a synchronous block cipher
+ * definition See @struct @blkcipher_alg.
+ * @cra_u.cipher: Union member which contains a single-block symmetric cipher
+ * definition. See @struct @cipher_alg.
+ * @cra_u.compress: Union member which contains a (de)compression algorithm.
+ * See @struct @compress_alg.
* @cra_module: Owner of this transformation implementation. Set to THIS_MODULE
* @cra_list: internally used
* @cra_users: internally used
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 82a99d366aec..94acbde17bb1 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -56,9 +56,7 @@ struct qstr {
#define QSTR_INIT(n,l) { { { .len = l } }, .name = n }
-extern const char empty_string[];
extern const struct qstr empty_name;
-extern const char slash_string[];
extern const struct qstr slash_name;
struct dentry_stat_t {
@@ -361,7 +359,7 @@ static inline void dont_mount(struct dentry *dentry)
extern void __d_lookup_done(struct dentry *);
-static inline int d_in_lookup(struct dentry *dentry)
+static inline int d_in_lookup(const struct dentry *dentry)
{
return dentry->d_flags & DCACHE_PAR_LOOKUP;
}
@@ -489,7 +487,7 @@ static inline bool d_really_is_positive(const struct dentry *dentry)
return dentry->d_inode != NULL;
}
-static inline int simple_positive(struct dentry *dentry)
+static inline int simple_positive(const struct dentry *dentry)
{
return d_really_is_positive(dentry) && !d_unhashed(dentry);
}
diff --git a/include/linux/device.h b/include/linux/device.h
index abf952c82c6d..0059b99e1f25 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -256,6 +256,7 @@ enum probe_type {
* automatically.
* @pm: Power management operations of the device which matched
* this driver.
+ * @coredump: Called through sysfs to initiate a device coredump.
* @p: Driver core's private data, no one other than the driver
* core can touch this.
*
@@ -730,6 +731,28 @@ struct device_dma_parameters {
};
/**
+ * struct device_connection - Device Connection Descriptor
+ * @endpoint: The names of the two devices connected together
+ * @id: Unique identifier for the connection
+ * @list: List head, private, for internal use only
+ */
+struct device_connection {
+ const char *endpoint[2];
+ const char *id;
+ struct list_head list;
+};
+
+void *device_connection_find_match(struct device *dev, const char *con_id,
+ void *data,
+ void *(*match)(struct device_connection *con,
+ int ep, void *data));
+
+struct device *device_connection_find(struct device *dev, const char *con_id);
+
+void device_connection_add(struct device_connection *con);
+void device_connection_remove(struct device_connection *con);
+
+/**
* enum device_link_state - Device link states.
* @DL_STATE_NONE: The presence of the drivers is not being tracked.
* @DL_STATE_DORMANT: None of the supplier/consumer drivers is present.
diff --git a/include/linux/extcon.h b/include/linux/extcon.h
index 6d94e82c8ad9..7f033b1ea568 100644
--- a/include/linux/extcon.h
+++ b/include/linux/extcon.h
@@ -230,6 +230,7 @@ extern void devm_extcon_unregister_notifier_all(struct device *dev,
* Following APIs get the extcon_dev from devicetree or by through extcon name.
*/
extern struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name);
+extern struct extcon_dev *extcon_find_edev_by_node(struct device_node *node);
extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
int index);
@@ -283,6 +284,11 @@ static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
return ERR_PTR(-ENODEV);
}
+static inline struct extcon_dev *extcon_find_edev_by_node(struct device_node *node)
+{
+ return ERR_PTR(-ENODEV);
+}
+
static inline struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
int index)
{
diff --git a/include/linux/extcon/extcon-gpio.h b/include/linux/extcon/extcon-gpio.h
deleted file mode 100644
index 7cacafb78b09..000000000000
--- a/include/linux/extcon/extcon-gpio.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Single-state GPIO extcon driver based on extcon class
- *
- * Copyright (C) 2012 Samsung Electronics
- * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * based on switch class driver
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 __EXTCON_GPIO_H__
-#define __EXTCON_GPIO_H__ __FILE__
-
-#include <linux/extcon.h>
-
-/**
- * struct gpio_extcon_pdata - A simple GPIO-controlled extcon device.
- * @extcon_id: The unique id of specific external connector.
- * @gpio: Corresponding GPIO.
- * @gpio_active_low: Boolean describing whether gpio active state is 1 or 0
- * If true, low state of gpio means active.
- * If false, high state of gpio means active.
- * @debounce: Debounce time for GPIO IRQ in ms.
- * @irq_flags: IRQ Flags (e.g., IRQF_TRIGGER_LOW).
- * @check_on_resume: Boolean describing whether to check the state of gpio
- * while resuming from sleep.
- */
-struct gpio_extcon_pdata {
- unsigned int extcon_id;
- unsigned gpio;
- bool gpio_active_low;
- unsigned long debounce;
- unsigned long irq_flags;
-
- bool check_on_resume;
-};
-
-#endif /* __EXTCON_GPIO_H__ */
diff --git a/include/linux/firmware.h b/include/linux/firmware.h
index d4508080348d..41050417cafb 100644
--- a/include/linux/firmware.h
+++ b/include/linux/firmware.h
@@ -85,4 +85,7 @@ static inline int request_firmware_into_buf(const struct firmware **firmware_p,
}
#endif
+
+int firmware_request_cache(struct device *device, const char *name);
+
#endif
diff --git a/drivers/staging/fsl-mc/include/mc.h b/include/linux/fsl/mc.h
index 765ba41f5987..f27cb14088a4 100644
--- a/drivers/staging/fsl-mc/include/mc.h
+++ b/include/linux/fsl/mc.h
@@ -209,7 +209,7 @@ struct mc_cmd_header {
__le16 cmd_id;
};
-struct mc_command {
+struct fsl_mc_command {
u64 header;
u64 params[MC_CMD_NUM_OF_PARAMS];
};
@@ -256,7 +256,7 @@ static inline u64 mc_encode_cmd_header(u16 cmd_id,
return header;
}
-static inline u16 mc_cmd_hdr_read_token(struct mc_command *cmd)
+static inline u16 mc_cmd_hdr_read_token(struct fsl_mc_command *cmd)
{
struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header;
u16 token = le16_to_cpu(hdr->token);
@@ -273,7 +273,7 @@ struct mc_rsp_api_ver {
__le16 minor_ver;
};
-static inline u32 mc_cmd_read_object_id(struct mc_command *cmd)
+static inline u32 mc_cmd_read_object_id(struct fsl_mc_command *cmd)
{
struct mc_rsp_create *rsp_params;
@@ -281,7 +281,7 @@ static inline u32 mc_cmd_read_object_id(struct mc_command *cmd)
return le32_to_cpu(rsp_params->object_id);
}
-static inline void mc_cmd_read_api_version(struct mc_command *cmd,
+static inline void mc_cmd_read_api_version(struct fsl_mc_command *cmd,
u16 *major_ver,
u16 *minor_ver)
{
@@ -342,7 +342,7 @@ struct fsl_mc_io {
};
};
-int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd);
+int mc_send_command(struct fsl_mc_io *mc_io, struct fsl_mc_command *cmd);
#ifdef CONFIG_FSL_MC_BUS
#define dev_is_fsl_mc(_dev) ((_dev)->bus == &fsl_mc_bus_type)
@@ -451,4 +451,112 @@ static inline bool is_fsl_mc_bus_dprtc(const struct fsl_mc_device *mc_dev)
return mc_dev->dev.type == &fsl_mc_bus_dprtc_type;
}
+/*
+ * Data Path Buffer Pool (DPBP) API
+ * Contains initialization APIs and runtime control APIs for DPBP
+ */
+
+int dpbp_open(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ int dpbp_id,
+ u16 *token);
+
+int dpbp_close(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
+int dpbp_enable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
+int dpbp_disable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
+int dpbp_reset(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
+/**
+ * struct dpbp_attr - Structure representing DPBP attributes
+ * @id: DPBP object ID
+ * @bpid: Hardware buffer pool ID; should be used as an argument in
+ * acquire/release operations on buffers
+ */
+struct dpbp_attr {
+ int id;
+ u16 bpid;
+};
+
+int dpbp_get_attributes(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ struct dpbp_attr *attr);
+
+/* Data Path Concentrator (DPCON) API
+ * Contains initialization APIs and runtime control APIs for DPCON
+ */
+
+/**
+ * Use it to disable notifications; see dpcon_set_notification()
+ */
+#define DPCON_INVALID_DPIO_ID (int)(-1)
+
+int dpcon_open(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ int dpcon_id,
+ u16 *token);
+
+int dpcon_close(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
+int dpcon_enable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
+int dpcon_disable(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
+int dpcon_reset(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token);
+
+/**
+ * struct dpcon_attr - Structure representing DPCON attributes
+ * @id: DPCON object ID
+ * @qbman_ch_id: Channel ID to be used by dequeue operation
+ * @num_priorities: Number of priorities for the DPCON channel (1-8)
+ */
+struct dpcon_attr {
+ int id;
+ u16 qbman_ch_id;
+ u8 num_priorities;
+};
+
+int dpcon_get_attributes(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ struct dpcon_attr *attr);
+
+/**
+ * struct dpcon_notification_cfg - Structure representing notification params
+ * @dpio_id: DPIO object ID; must be configured with a notification channel;
+ * to disable notifications set it to 'DPCON_INVALID_DPIO_ID';
+ * @priority: Priority selection within the DPIO channel; valid values
+ * are 0-7, depending on the number of priorities in that channel
+ * @user_ctx: User context value provided with each CDAN message
+ */
+struct dpcon_notification_cfg {
+ int dpio_id;
+ u8 priority;
+ u64 user_ctx;
+};
+
+int dpcon_set_notification(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 token,
+ struct dpcon_notification_cfg *cfg);
+
#endif /* _FSL_MC_H_ */
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index c7902ca7c9f4..78f456fcd242 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -161,11 +161,9 @@ struct hrtimer_clock_base {
enum hrtimer_base_type {
HRTIMER_BASE_MONOTONIC,
HRTIMER_BASE_REALTIME,
- HRTIMER_BASE_BOOTTIME,
HRTIMER_BASE_TAI,
HRTIMER_BASE_MONOTONIC_SOFT,
HRTIMER_BASE_REALTIME_SOFT,
- HRTIMER_BASE_BOOTTIME_SOFT,
HRTIMER_BASE_TAI_SOFT,
HRTIMER_MAX_CLOCK_BASES,
};
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 93bd6fcd6e62..2048f3c3b68a 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -844,7 +844,7 @@ struct vmbus_channel {
/*
* NUMA distribution policy:
- * We support teo policies:
+ * We support two policies:
* 1) Balanced: Here all performance critical channels are
* distributed evenly amongst all the NUMA nodes.
* This policy will be the default policy.
diff --git a/include/linux/ipc.h b/include/linux/ipc.h
index 821b2f260992..6cc2df7f7ac9 100644
--- a/include/linux/ipc.h
+++ b/include/linux/ipc.h
@@ -8,8 +8,6 @@
#include <uapi/linux/ipc.h>
#include <linux/refcount.h>
-#define IPCMNI 32768 /* <= MAX_INT limit for ipc arrays (including sysctl changes) */
-
/* used by in-kernel data structures */
struct kern_ipc_perm {
spinlock_t lock;
diff --git a/include/linux/irq.h b/include/linux/irq.h
index a0231e96a578..65916a305f3d 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -10,18 +10,13 @@
* Thanks. --rmk
*/
-#include <linux/smp.h>
-#include <linux/linkage.h>
#include <linux/cache.h>
#include <linux/spinlock.h>
#include <linux/cpumask.h>
-#include <linux/gfp.h>
#include <linux/irqhandler.h>
#include <linux/irqreturn.h>
#include <linux/irqnr.h>
-#include <linux/errno.h>
#include <linux/topology.h>
-#include <linux/wait.h>
#include <linux/io.h>
#include <linux/slab.h>
@@ -1170,4 +1165,22 @@ int __ipi_send_mask(struct irq_desc *desc, const struct cpumask *dest);
int ipi_send_single(unsigned int virq, unsigned int cpu);
int ipi_send_mask(unsigned int virq, const struct cpumask *dest);
+#ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER
+/*
+ * Registers a generic IRQ handling function as the top-level IRQ handler in
+ * the system, which is generally the first C code called from an assembly
+ * architecture-specific interrupt handler.
+ *
+ * Returns 0 on success, or -EBUSY if an IRQ handler has already been
+ * registered.
+ */
+int __init set_handle_irq(void (*handle_irq)(struct pt_regs *));
+
+/*
+ * Allows interrupt handlers to find the irqchip that's been registered as the
+ * top-level IRQ handler.
+ */
+extern void (*handle_arch_irq)(struct pt_regs *) __ro_after_init;
+#endif
+
#endif /* _LINUX_IRQ_H */
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index b26eccc78fb1..f5af3b594e6e 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -106,6 +106,7 @@
#define GICR_PIDR2 GICD_PIDR2
#define GICR_CTLR_ENABLE_LPIS (1UL << 0)
+#define GICR_CTLR_RWP (1UL << 3)
#define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff)
@@ -312,7 +313,8 @@
#define GITS_TYPER_DEVBITS_SHIFT 13
#define GITS_TYPER_DEVBITS(r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
#define GITS_TYPER_PTA (1UL << 19)
-#define GITS_TYPER_HWCOLLCNT_SHIFT 24
+#define GITS_TYPER_HCC_SHIFT 24
+#define GITS_TYPER_HCC(r) (((r) >> GITS_TYPER_HCC_SHIFT) & 0xff)
#define GITS_TYPER_VMOVP (1ULL << 37)
#define GITS_IIDR_REV_SHIFT 12
diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h
index dcde9471897d..cc8fa109cfa3 100644
--- a/include/linux/kconfig.h
+++ b/include/linux/kconfig.h
@@ -70,7 +70,4 @@
*/
#define IS_ENABLED(option) __or(IS_BUILTIN(option), IS_MODULE(option))
-/* Make sure we always have all types and struct attributes defined. */
-#include <linux/compiler_types.h>
-
#endif /* __LINUX_KCONFIG_H */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 293fa0677fba..3cbf3cfff4f0 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -480,6 +480,15 @@ extern int func_ptr_is_kernel_text(void *ptr);
unsigned long int_sqrt(unsigned long);
+#if BITS_PER_LONG < 64
+u32 int_sqrt64(u64 x);
+#else
+static inline u32 int_sqrt64(u64 x)
+{
+ return (u32)int_sqrt(x);
+}
+#endif
+
extern void bust_spinlocks(int yes);
extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in progress */
extern int panic_timeout;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index ed9826b21c5e..1795fecdea17 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -617,6 +617,7 @@ struct ata_host {
void *private_data;
struct ata_port_operations *ops;
unsigned long flags;
+ struct kref kref;
struct mutex eh_mutex;
struct task_struct *eh_owner;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 7161d8e7ee79..bde167fa2c51 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1575,28 +1575,28 @@ union security_list_options {
int (*msg_msg_alloc_security)(struct msg_msg *msg);
void (*msg_msg_free_security)(struct msg_msg *msg);
- int (*msg_queue_alloc_security)(struct msg_queue *msq);
- void (*msg_queue_free_security)(struct msg_queue *msq);
- int (*msg_queue_associate)(struct msg_queue *msq, int msqflg);
- int (*msg_queue_msgctl)(struct msg_queue *msq, int cmd);
- int (*msg_queue_msgsnd)(struct msg_queue *msq, struct msg_msg *msg,
+ int (*msg_queue_alloc_security)(struct kern_ipc_perm *msq);
+ void (*msg_queue_free_security)(struct kern_ipc_perm *msq);
+ int (*msg_queue_associate)(struct kern_ipc_perm *msq, int msqflg);
+ int (*msg_queue_msgctl)(struct kern_ipc_perm *msq, int cmd);
+ int (*msg_queue_msgsnd)(struct kern_ipc_perm *msq, struct msg_msg *msg,
int msqflg);
- int (*msg_queue_msgrcv)(struct msg_queue *msq, struct msg_msg *msg,
+ int (*msg_queue_msgrcv)(struct kern_ipc_perm *msq, struct msg_msg *msg,
struct task_struct *target, long type,
int mode);
- int (*shm_alloc_security)(struct shmid_kernel *shp);
- void (*shm_free_security)(struct shmid_kernel *shp);
- int (*shm_associate)(struct shmid_kernel *shp, int shmflg);
- int (*shm_shmctl)(struct shmid_kernel *shp, int cmd);
- int (*shm_shmat)(struct shmid_kernel *shp, char __user *shmaddr,
+ int (*shm_alloc_security)(struct kern_ipc_perm *shp);
+ void (*shm_free_security)(struct kern_ipc_perm *shp);
+ int (*shm_associate)(struct kern_ipc_perm *shp, int shmflg);
+ int (*shm_shmctl)(struct kern_ipc_perm *shp, int cmd);
+ int (*shm_shmat)(struct kern_ipc_perm *shp, char __user *shmaddr,
int shmflg);
- int (*sem_alloc_security)(struct sem_array *sma);
- void (*sem_free_security)(struct sem_array *sma);
- int (*sem_associate)(struct sem_array *sma, int semflg);
- int (*sem_semctl)(struct sem_array *sma, int cmd);
- int (*sem_semop)(struct sem_array *sma, struct sembuf *sops,
+ int (*sem_alloc_security)(struct kern_ipc_perm *sma);
+ void (*sem_free_security)(struct kern_ipc_perm *sma);
+ int (*sem_associate)(struct kern_ipc_perm *sma, int semflg);
+ int (*sem_semctl)(struct kern_ipc_perm *sma, int cmd);
+ int (*sem_semop)(struct kern_ipc_perm *sma, struct sembuf *sops,
unsigned nsops, int alter);
int (*netlink_send)(struct sock *sk, struct sk_buff *skb);
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
index 080798f17ece..82bf7747b312 100644
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -266,6 +266,8 @@ enum axp20x_variants {
#define AXP288_RT_BATT_V_H 0xa0
#define AXP288_RT_BATT_V_L 0xa1
+#define AXP813_ADC_RATE 0x85
+
/* Fuel Gauge */
#define AXP288_FG_RDC1_REG 0xba
#define AXP288_FG_RDC0_REG 0xbb
diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
index c8e0164c5423..e06f5f79eaef 100644
--- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
+++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
@@ -243,6 +243,8 @@
#define IMX6Q_GPR4_IPU_RD_CACHE_CTL BIT(0)
#define IMX6Q_GPR5_L2_CLK_STOP BIT(8)
+#define IMX6Q_GPR5_SATA_SW_PD BIT(10)
+#define IMX6Q_GPR5_SATA_SW_RST BIT(11)
#define IMX6Q_GPR6_IPU1_ID00_WR_QOS_MASK (0xf << 0)
#define IMX6Q_GPR6_IPU1_ID01_WR_QOS_MASK (0xf << 4)
diff --git a/include/linux/msg.h b/include/linux/msg.h
index 0a7eefeee0d1..9a972a296b95 100644
--- a/include/linux/msg.h
+++ b/include/linux/msg.h
@@ -3,7 +3,6 @@
#define _LINUX_MSG_H
#include <linux/list.h>
-#include <linux/time64.h>
#include <uapi/linux/msg.h>
/* one msg_msg structure for each message */
@@ -16,21 +15,4 @@ struct msg_msg {
/* the actual message follows immediately */
};
-/* one msq_queue structure for each present queue on the system */
-struct msg_queue {
- struct kern_ipc_perm q_perm;
- time64_t q_stime; /* last msgsnd time */
- time64_t q_rtime; /* last msgrcv time */
- time64_t q_ctime; /* last change time */
- unsigned long q_cbytes; /* current number of bytes on queue */
- unsigned long q_qnum; /* number of messages in queue */
- unsigned long q_qbytes; /* max number of bytes on queue */
- pid_t q_lspid; /* pid of last msgsnd */
- pid_t q_lrpid; /* last receive pid */
-
- struct list_head q_messages;
- struct list_head q_receivers;
- struct list_head q_senders;
-} __randomize_layout;
-
#endif /* _LINUX_MSG_H */
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index 497706f5adca..f89598bc4e1c 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -22,6 +22,31 @@ typedef int (*nvmem_reg_read_t)(void *priv, unsigned int offset,
typedef int (*nvmem_reg_write_t)(void *priv, unsigned int offset,
void *val, size_t bytes);
+/**
+ * struct nvmem_config - NVMEM device configuration
+ *
+ * @dev: Parent device.
+ * @name: Optional name.
+ * @id: Optional device ID used in full name. Ignored if name is NULL.
+ * @owner: Pointer to exporter module. Used for refcounting.
+ * @cells: Optional array of pre-defined NVMEM cells.
+ * @ncells: Number of elements in cells.
+ * @read_only: Device is read-only.
+ * @root_only: Device is accessibly to root only.
+ * @reg_read: Callback to read data.
+ * @reg_write: Callback to write data.
+ * @size: Device size.
+ * @word_size: Minimum read/write access granularity.
+ * @stride: Minimum read/write access stride.
+ * @priv: User context passed to read/write callbacks.
+ *
+ * Note: A default "nvmem<id>" name will be assigned to the device if
+ * no name is specified in its configuration. In such case "<id>" is
+ * generated with ida_simple_get() and provided id field is ignored.
+ *
+ * Note: Specifying name and setting id to -1 implies a unique device
+ * whose name is provided as-is (kept unaltered).
+ */
struct nvmem_config {
struct device *dev;
const char *name;
@@ -47,6 +72,11 @@ struct nvmem_config {
struct nvmem_device *nvmem_register(const struct nvmem_config *cfg);
int nvmem_unregister(struct nvmem_device *nvmem);
+struct nvmem_device *devm_nvmem_register(struct device *dev,
+ const struct nvmem_config *cfg);
+
+int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem);
+
#else
static inline struct nvmem_device *nvmem_register(const struct nvmem_config *c)
@@ -59,5 +89,17 @@ static inline int nvmem_unregister(struct nvmem_device *nvmem)
return -ENOSYS;
}
+static inline struct nvmem_device *
+devm_nvmem_register(struct device *dev, const struct nvmem_config *c)
+{
+ return nvmem_register(c);
+}
+
+static inline int
+devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem)
+{
+ return nvmem_unregister(nvmem);
+}
+
#endif /* CONFIG_NVMEM */
#endif /* ifndef _LINUX_NVMEM_PROVIDER_H */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index a637a7d8ce5b..2d61d9bde83d 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1562,6 +1562,8 @@
#define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227
#define PCI_DEVICE_ID_SERVERWORKS_HT1100LD 0x0408
+#define PCI_VENDOR_ID_ALTERA 0x1172
+
#define PCI_VENDOR_ID_SBE 0x1176
#define PCI_DEVICE_ID_SBE_WANXL100 0x0301
#define PCI_DEVICE_ID_SBE_WANXL200 0x0302
@@ -2557,6 +2559,9 @@
#define PCI_DEVICE_ID_TEHUTI_3010 0x3010
#define PCI_DEVICE_ID_TEHUTI_3014 0x3014
+#define PCI_VENDOR_ID_SUNIX 0x1fd4
+#define PCI_DEVICE_ID_SUNIX_1999 0x1999
+
#define PCI_VENDOR_ID_HINT 0x3388
#define PCI_DEVICE_ID_HINT_VXPROII_IDE 0x8013
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 4f8423a948d5..c9d14eeee7f5 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -25,7 +25,15 @@ struct phy;
enum phy_mode {
PHY_MODE_INVALID,
PHY_MODE_USB_HOST,
+ PHY_MODE_USB_HOST_LS,
+ PHY_MODE_USB_HOST_FS,
+ PHY_MODE_USB_HOST_HS,
+ PHY_MODE_USB_HOST_SS,
PHY_MODE_USB_DEVICE,
+ PHY_MODE_USB_DEVICE_LS,
+ PHY_MODE_USB_DEVICE_FS,
+ PHY_MODE_USB_DEVICE_HS,
+ PHY_MODE_USB_DEVICE_SS,
PHY_MODE_USB_OTG,
PHY_MODE_SGMII,
PHY_MODE_10GKR,
@@ -61,6 +69,7 @@ struct phy_ops {
*/
struct phy_attrs {
u32 bus_width;
+ enum phy_mode mode;
};
/**
@@ -72,7 +81,8 @@ struct phy_attrs {
* @mutex: mutex to protect phy_ops
* @init_count: used to protect when the PHY is used by multiple consumers
* @power_count: used to protect when the PHY is used by multiple consumers
- * @phy_attrs: used to specify PHY specific attributes
+ * @attrs: used to specify PHY specific attributes
+ * @pwr: power regulator associated with the phy
*/
struct phy {
struct device dev;
@@ -88,9 +98,10 @@ struct phy {
/**
* struct phy_provider - represents the phy provider
* @dev: phy provider device
+ * @children: can be used to override the default (dev->of_node) child node
* @owner: the module owner having of_xlate
- * @of_xlate: function pointer to obtain phy instance from phy pointer
* @list: to maintain a linked list of PHY providers
+ * @of_xlate: function pointer to obtain phy instance from phy pointer
*/
struct phy_provider {
struct device *dev;
@@ -101,6 +112,13 @@ struct phy_provider {
struct of_phandle_args *args);
};
+/**
+ * struct phy_lookup - PHY association in list of phys managed by the phy driver
+ * @node: list node
+ * @dev_id: the device of the association
+ * @con_id: connection ID string on device
+ * @phy: the phy of the association
+ */
struct phy_lookup {
struct list_head node;
const char *dev_id;
@@ -144,6 +162,10 @@ int phy_exit(struct phy *phy);
int phy_power_on(struct phy *phy);
int phy_power_off(struct phy *phy);
int phy_set_mode(struct phy *phy, enum phy_mode mode);
+static inline enum phy_mode phy_get_mode(struct phy *phy)
+{
+ return phy->attrs.mode;
+}
int phy_reset(struct phy *phy);
int phy_calibrate(struct phy *phy);
static inline int phy_get_bus_width(struct phy *phy)
@@ -260,6 +282,11 @@ static inline int phy_set_mode(struct phy *phy, enum phy_mode mode)
return -ENOSYS;
}
+static inline enum phy_mode phy_get_mode(struct phy *phy)
+{
+ return PHY_MODE_INVALID;
+}
+
static inline int phy_reset(struct phy *phy)
{
if (!phy)
diff --git a/include/linux/random.h b/include/linux/random.h
index 4024f7d9c77d..2ddf13b4281e 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -85,10 +85,8 @@ static inline unsigned long get_random_canary(void)
static inline int get_random_bytes_wait(void *buf, int nbytes)
{
int ret = wait_for_random_bytes();
- if (unlikely(ret))
- return ret;
get_random_bytes(buf, nbytes);
- return 0;
+ return ret;
}
#define declare_get_random_var_wait(var) \
diff --git a/include/linux/security.h b/include/linux/security.h
index 73f1ef625d40..128e1e4a5346 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -36,7 +36,6 @@ struct linux_binprm;
struct cred;
struct rlimit;
struct siginfo;
-struct sem_array;
struct sembuf;
struct kern_ipc_perm;
struct audit_context;
@@ -50,9 +49,7 @@ struct qstr;
struct iattr;
struct fown_struct;
struct file_operations;
-struct shmid_kernel;
struct msg_msg;
-struct msg_queue;
struct xattr;
struct xfrm_sec_ctx;
struct mm_struct;
@@ -355,24 +352,24 @@ int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag);
void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid);
int security_msg_msg_alloc(struct msg_msg *msg);
void security_msg_msg_free(struct msg_msg *msg);
-int security_msg_queue_alloc(struct msg_queue *msq);
-void security_msg_queue_free(struct msg_queue *msq);
-int security_msg_queue_associate(struct msg_queue *msq, int msqflg);
-int security_msg_queue_msgctl(struct msg_queue *msq, int cmd);
-int security_msg_queue_msgsnd(struct msg_queue *msq,
+int security_msg_queue_alloc(struct kern_ipc_perm *msq);
+void security_msg_queue_free(struct kern_ipc_perm *msq);
+int security_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg);
+int security_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd);
+int security_msg_queue_msgsnd(struct kern_ipc_perm *msq,
struct msg_msg *msg, int msqflg);
-int security_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
+int security_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg,
struct task_struct *target, long type, int mode);
-int security_shm_alloc(struct shmid_kernel *shp);
-void security_shm_free(struct shmid_kernel *shp);
-int security_shm_associate(struct shmid_kernel *shp, int shmflg);
-int security_shm_shmctl(struct shmid_kernel *shp, int cmd);
-int security_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, int shmflg);
-int security_sem_alloc(struct sem_array *sma);
-void security_sem_free(struct sem_array *sma);
-int security_sem_associate(struct sem_array *sma, int semflg);
-int security_sem_semctl(struct sem_array *sma, int cmd);
-int security_sem_semop(struct sem_array *sma, struct sembuf *sops,
+int security_shm_alloc(struct kern_ipc_perm *shp);
+void security_shm_free(struct kern_ipc_perm *shp);
+int security_shm_associate(struct kern_ipc_perm *shp, int shmflg);
+int security_shm_shmctl(struct kern_ipc_perm *shp, int cmd);
+int security_shm_shmat(struct kern_ipc_perm *shp, char __user *shmaddr, int shmflg);
+int security_sem_alloc(struct kern_ipc_perm *sma);
+void security_sem_free(struct kern_ipc_perm *sma);
+int security_sem_associate(struct kern_ipc_perm *sma, int semflg);
+int security_sem_semctl(struct kern_ipc_perm *sma, int cmd);
+int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops,
unsigned nsops, int alter);
void security_d_instantiate(struct dentry *dentry, struct inode *inode);
int security_getprocattr(struct task_struct *p, char *name, char **value);
@@ -1045,32 +1042,32 @@ static inline int security_msg_msg_alloc(struct msg_msg *msg)
static inline void security_msg_msg_free(struct msg_msg *msg)
{ }
-static inline int security_msg_queue_alloc(struct msg_queue *msq)
+static inline int security_msg_queue_alloc(struct kern_ipc_perm *msq)
{
return 0;
}
-static inline void security_msg_queue_free(struct msg_queue *msq)
+static inline void security_msg_queue_free(struct kern_ipc_perm *msq)
{ }
-static inline int security_msg_queue_associate(struct msg_queue *msq,
+static inline int security_msg_queue_associate(struct kern_ipc_perm *msq,
int msqflg)
{
return 0;
}
-static inline int security_msg_queue_msgctl(struct msg_queue *msq, int cmd)
+static inline int security_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
{
return 0;
}
-static inline int security_msg_queue_msgsnd(struct msg_queue *msq,
+static inline int security_msg_queue_msgsnd(struct kern_ipc_perm *msq,
struct msg_msg *msg, int msqflg)
{
return 0;
}
-static inline int security_msg_queue_msgrcv(struct msg_queue *msq,
+static inline int security_msg_queue_msgrcv(struct kern_ipc_perm *msq,
struct msg_msg *msg,
struct task_struct *target,
long type, int mode)
@@ -1078,50 +1075,50 @@ static inline int security_msg_queue_msgrcv(struct msg_queue *msq,
return 0;
}
-static inline int security_shm_alloc(struct shmid_kernel *shp)
+static inline int security_shm_alloc(struct kern_ipc_perm *shp)
{
return 0;
}
-static inline void security_shm_free(struct shmid_kernel *shp)
+static inline void security_shm_free(struct kern_ipc_perm *shp)
{ }
-static inline int security_shm_associate(struct shmid_kernel *shp,
+static inline int security_shm_associate(struct kern_ipc_perm *shp,
int shmflg)
{
return 0;
}
-static inline int security_shm_shmctl(struct shmid_kernel *shp, int cmd)
+static inline int security_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
{
return 0;
}
-static inline int security_shm_shmat(struct shmid_kernel *shp,
+static inline int security_shm_shmat(struct kern_ipc_perm *shp,
char __user *shmaddr, int shmflg)
{
return 0;
}
-static inline int security_sem_alloc(struct sem_array *sma)
+static inline int security_sem_alloc(struct kern_ipc_perm *sma)
{
return 0;
}
-static inline void security_sem_free(struct sem_array *sma)
+static inline void security_sem_free(struct kern_ipc_perm *sma)
{ }
-static inline int security_sem_associate(struct sem_array *sma, int semflg)
+static inline int security_sem_associate(struct kern_ipc_perm *sma, int semflg)
{
return 0;
}
-static inline int security_sem_semctl(struct sem_array *sma, int cmd)
+static inline int security_sem_semctl(struct kern_ipc_perm *sma, int cmd)
{
return 0;
}
-static inline int security_sem_semop(struct sem_array *sma,
+static inline int security_sem_semop(struct kern_ipc_perm *sma,
struct sembuf *sops, unsigned nsops,
int alter)
{
diff --git a/include/linux/sem.h b/include/linux/sem.h
index 9badd322dcee..5608a500c43e 100644
--- a/include/linux/sem.h
+++ b/include/linux/sem.h
@@ -2,48 +2,10 @@
#ifndef _LINUX_SEM_H
#define _LINUX_SEM_H
-#include <linux/atomic.h>
-#include <linux/rcupdate.h>
-#include <linux/cache.h>
-#include <linux/time64.h>
#include <uapi/linux/sem.h>
struct task_struct;
-
-/* One semaphore structure for each semaphore in the system. */
-struct sem {
- int semval; /* current value */
- /*
- * PID of the process that last modified the semaphore. For
- * Linux, specifically these are:
- * - semop
- * - semctl, via SETVAL and SETALL.
- * - at task exit when performing undo adjustments (see exit_sem).
- */
- int sempid;
- spinlock_t lock; /* spinlock for fine-grained semtimedop */
- struct list_head pending_alter; /* pending single-sop operations */
- /* that alter the semaphore */
- struct list_head pending_const; /* pending single-sop operations */
- /* that do not alter the semaphore*/
- time_t sem_otime; /* candidate for sem_otime */
-} ____cacheline_aligned_in_smp;
-
-/* One sem_array data structure for each set of semaphores in the system. */
-struct sem_array {
- struct kern_ipc_perm sem_perm; /* permissions .. see ipc.h */
- time64_t sem_ctime; /* create/last semctl() time */
- struct list_head pending_alter; /* pending operations */
- /* that alter the array */
- struct list_head pending_const; /* pending complex operations */
- /* that do not alter semvals */
- struct list_head list_id; /* undo requests on this array */
- int sem_nsems; /* no. of semaphores in array */
- int complex_count; /* pending complex operations */
- unsigned int use_global_lock;/* >0: global lock required */
-
- struct sem sems[];
-} __randomize_layout;
+struct sem_undo_list;
#ifdef CONFIG_SYSVIPC
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index b32df49a3bd5..1d356105f25a 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -379,7 +379,7 @@ extern int of_setup_earlycon(const struct earlycon_id *match,
extern bool earlycon_acpi_spcr_enable __initdata;
int setup_earlycon(char *buf);
#else
-static const bool earlycon_acpi_spcr_enable;
+static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED;
static inline int setup_earlycon(char *buf) { return 0; }
#endif
diff --git a/include/linux/shm.h b/include/linux/shm.h
index 2bbafacfbfc9..d8e69aed3d32 100644
--- a/include/linux/shm.h
+++ b/include/linux/shm.h
@@ -7,27 +7,7 @@
#include <uapi/linux/shm.h>
#include <asm/shmparam.h>
-struct shmid_kernel /* private to the kernel */
-{
- struct kern_ipc_perm shm_perm;
- struct file *shm_file;
- unsigned long shm_nattch;
- unsigned long shm_segsz;
- time64_t shm_atim;
- time64_t shm_dtim;
- time64_t shm_ctim;
- pid_t shm_cprid;
- pid_t shm_lprid;
- struct user_struct *mlock_user;
-
- /* The task created the shm object. NULL if the task is dead. */
- struct task_struct *shm_creator;
- struct list_head shm_clist; /* list by creator */
-} __randomize_layout;
-
-/* shm_mode upper byte flags */
-#define SHM_DEST 01000 /* segment will be destroyed on last detach */
-#define SHM_LOCKED 02000 /* segment will not be swapped */
+struct file;
#ifdef CONFIG_SYSVIPC
struct sysv_shm {
diff --git a/include/linux/sizes.h b/include/linux/sizes.h
index ce3e8150c174..fbde0bc7e882 100644
--- a/include/linux/sizes.h
+++ b/include/linux/sizes.h
@@ -8,6 +8,8 @@
#ifndef __LINUX_SIZES_H__
#define __LINUX_SIZES_H__
+#include <linux/const.h>
+
#define SZ_1 0x00000001
#define SZ_2 0x00000002
#define SZ_4 0x00000004
@@ -44,4 +46,6 @@
#define SZ_1G 0x40000000
#define SZ_2G 0x80000000
+#define SZ_4G _AC(0x100000000, ULL)
+
#endif /* __LINUX_SIZES_H__ */
diff --git a/include/linux/stm.h b/include/linux/stm.h
index 210ff2292361..c6f577ab6f21 100644
--- a/include/linux/stm.h
+++ b/include/linux/stm.h
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* System Trace Module (STM) infrastructure apis
* Copyright (C) 2014 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.
*/
#ifndef _STM_H_
diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h
index 7b69853188b1..a3ed26082bc1 100644
--- a/include/linux/thunderbolt.h
+++ b/include/linux/thunderbolt.h
@@ -45,12 +45,16 @@ enum tb_cfg_pkg_type {
* @TB_SECURITY_USER: User approval required at minimum
* @TB_SECURITY_SECURE: One time saved key required at minimum
* @TB_SECURITY_DPONLY: Only tunnel Display port (and USB)
+ * @TB_SECURITY_USBONLY: Only tunnel USB controller of the connected
+ * Thunderbolt dock (and Display Port). All PCIe
+ * links downstream of the dock are removed.
*/
enum tb_security_level {
TB_SECURITY_NONE,
TB_SECURITY_USER,
TB_SECURITY_SECURE,
TB_SECURITY_DPONLY,
+ TB_SECURITY_USBONLY,
};
/**
@@ -65,6 +69,7 @@ enum tb_security_level {
* @cm_ops: Connection manager specific operations vector
* @index: Linux assigned domain number
* @security_level: Current security level
+ * @nboot_acl: Number of boot ACLs the domain supports
* @privdata: Private connection manager specific data
*/
struct tb {
@@ -77,6 +82,7 @@ struct tb {
const struct tb_cm_ops *cm_ops;
int index;
enum tb_security_level security_level;
+ size_t nboot_acl;
unsigned long privdata[0];
};
@@ -237,6 +243,7 @@ int tb_xdomain_enable_paths(struct tb_xdomain *xd, u16 transmit_path,
u16 receive_ring);
int tb_xdomain_disable_paths(struct tb_xdomain *xd);
struct tb_xdomain *tb_xdomain_find_by_uuid(struct tb *tb, const uuid_t *uuid);
+struct tb_xdomain *tb_xdomain_find_by_route(struct tb *tb, u64 route);
static inline struct tb_xdomain *
tb_xdomain_find_by_uuid_locked(struct tb *tb, const uuid_t *uuid)
@@ -250,6 +257,18 @@ tb_xdomain_find_by_uuid_locked(struct tb *tb, const uuid_t *uuid)
return xd;
}
+static inline struct tb_xdomain *
+tb_xdomain_find_by_route_locked(struct tb *tb, u64 route)
+{
+ struct tb_xdomain *xd;
+
+ mutex_lock(&tb->lock);
+ xd = tb_xdomain_find_by_route(tb, route);
+ mutex_unlock(&tb->lock);
+
+ return xd;
+}
+
static inline struct tb_xdomain *tb_xdomain_get(struct tb_xdomain *xd)
{
if (xd)
diff --git a/include/linux/time32.h b/include/linux/time32.h
index 65b1de25198d..d2bcd4377b56 100644
--- a/include/linux/time32.h
+++ b/include/linux/time32.h
@@ -217,5 +217,6 @@ static inline s64 timeval_to_ns(const struct timeval *tv)
* Returns the timeval representation of the nsec parameter.
*/
extern struct timeval ns_to_timeval(const s64 nsec);
+extern struct __kernel_old_timeval ns_to_kernel_old_timeval(s64 nsec);
#endif
diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h
index d315c3d6725c..4b3dca173e89 100644
--- a/include/linux/timekeeper_internal.h
+++ b/include/linux/timekeeper_internal.h
@@ -52,6 +52,7 @@ struct tk_read_base {
* @offs_real: Offset clock monotonic -> clock realtime
* @offs_boot: Offset clock monotonic -> clock boottime
* @offs_tai: Offset clock monotonic -> clock tai
+ * @time_suspended: Accumulated suspend time
* @tai_offset: The current UTC to TAI offset in seconds
* @clock_was_set_seq: The sequence number of clock was set events
* @cs_was_changed_seq: The sequence number of clocksource change events
@@ -94,6 +95,7 @@ struct timekeeper {
ktime_t offs_real;
ktime_t offs_boot;
ktime_t offs_tai;
+ ktime_t time_suspended;
s32 tai_offset;
unsigned int clock_was_set_seq;
u8 cs_was_changed_seq;
@@ -117,6 +119,8 @@ struct timekeeper {
s64 ntp_error;
u32 ntp_error_shift;
u32 ntp_err_mult;
+ /* Flag used to avoid updating NTP twice with same second */
+ u32 skip_second_overflow;
#ifdef CONFIG_DEBUG_TIMEKEEPING
long last_warning;
/*
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h
index b17bcce58bc4..82c219dfd3bb 100644
--- a/include/linux/timekeeping.h
+++ b/include/linux/timekeeping.h
@@ -32,20 +32,25 @@ extern void getrawmonotonic64(struct timespec64 *ts);
extern void ktime_get_ts64(struct timespec64 *ts);
extern time64_t ktime_get_seconds(void);
extern time64_t ktime_get_real_seconds(void);
+extern void ktime_get_active_ts64(struct timespec64 *ts);
extern int __getnstimeofday64(struct timespec64 *tv);
extern void getnstimeofday64(struct timespec64 *tv);
extern void getboottime64(struct timespec64 *ts);
-#define ktime_get_real_ts64(ts) getnstimeofday64(ts)
+#define ktime_get_real_ts64(ts) getnstimeofday64(ts)
+
+/* Clock BOOTTIME compatibility wrappers */
+static inline void get_monotonic_boottime64(struct timespec64 *ts)
+{
+ ktime_get_ts64(ts);
+}
/*
* ktime_t based interfaces
*/
-
enum tk_offsets {
TK_OFFS_REAL,
- TK_OFFS_BOOT,
TK_OFFS_TAI,
TK_OFFS_MAX,
};
@@ -56,6 +61,10 @@ extern ktime_t ktime_mono_to_any(ktime_t tmono, enum tk_offsets offs);
extern ktime_t ktime_get_raw(void);
extern u32 ktime_get_resolution_ns(void);
+/* Clock BOOTTIME compatibility wrappers */
+static inline ktime_t ktime_get_boottime(void) { return ktime_get(); }
+static inline u64 ktime_get_boot_ns(void) { return ktime_get(); }
+
/**
* ktime_get_real - get the real (wall-) time in ktime_t format
*/
@@ -65,17 +74,6 @@ static inline ktime_t ktime_get_real(void)
}
/**
- * ktime_get_boottime - Returns monotonic time since boot in ktime_t format
- *
- * This is similar to CLOCK_MONTONIC/ktime_get, but also includes the
- * time spent in suspend.
- */
-static inline ktime_t ktime_get_boottime(void)
-{
- return ktime_get_with_offset(TK_OFFS_BOOT);
-}
-
-/**
* ktime_get_clocktai - Returns the TAI time of day in ktime_t format
*/
static inline ktime_t ktime_get_clocktai(void)
@@ -101,11 +99,6 @@ static inline u64 ktime_get_real_ns(void)
return ktime_to_ns(ktime_get_real());
}
-static inline u64 ktime_get_boot_ns(void)
-{
- return ktime_to_ns(ktime_get_boottime());
-}
-
static inline u64 ktime_get_tai_ns(void)
{
return ktime_to_ns(ktime_get_clocktai());
@@ -118,17 +111,11 @@ static inline u64 ktime_get_raw_ns(void)
extern u64 ktime_get_mono_fast_ns(void);
extern u64 ktime_get_raw_fast_ns(void);
-extern u64 ktime_get_boot_fast_ns(void);
extern u64 ktime_get_real_fast_ns(void);
/*
* timespec64 interfaces utilizing the ktime based ones
*/
-static inline void get_monotonic_boottime64(struct timespec64 *ts)
-{
- *ts = ktime_to_timespec64(ktime_get_boottime());
-}
-
static inline void timekeeping_clocktai64(struct timespec64 *ts)
{
*ts = ktime_to_timespec64(ktime_get_clocktai());
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index cef0e44601f8..4b6b9283fa7b 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -54,6 +54,9 @@
/* big enough to hold our biggest descriptor */
#define USB_COMP_EP0_BUFSIZ 1024
+/* OS feature descriptor length <= 4kB */
+#define USB_COMP_EP0_OS_DESC_BUFSIZ 4096
+
#define USB_MS_TO_HS_INTERVAL(x) (ilog2((x * 1000 / 125)) + 1)
struct usb_configuration;
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 66a5cff7ee14..e3424234b23a 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -129,6 +129,7 @@ struct usb_ep_ops {
int (*enable) (struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc);
int (*disable) (struct usb_ep *ep);
+ void (*dispose) (struct usb_ep *ep);
struct usb_request *(*alloc_request) (struct usb_ep *ep,
gfp_t gfp_flags);
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 176900528822..aef50cb2ed1b 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -103,7 +103,7 @@ struct usb_hcd {
* other external phys should be software-transparent
*/
struct usb_phy *usb_phy;
- struct phy *phy;
+ struct usb_phy_roothub *phy_roothub;
/* Flags that need to be manipulated atomically because they can
* change while the host controller is running. Always use
@@ -151,6 +151,12 @@ struct usb_hcd {
unsigned msix_enabled:1; /* driver has MSI-X enabled? */
unsigned msi_enabled:1; /* driver has MSI enabled? */
unsigned remove_phy:1; /* auto-remove USB phy */
+ /*
+ * do not manage the PHY state in the HCD core, instead let the driver
+ * handle this (for example if the PHY can only be turned on after a
+ * specific event)
+ */
+ unsigned skip_phy_initialization:1;
/* The next flag is a stopgap, to be removed when all the HCDs
* support the new root-hub polling mechanism. */
diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h
index b3d41d7409b3..ff359bdfdc7b 100644
--- a/include/linux/usb/pd.h
+++ b/include/linux/usb/pd.h
@@ -35,6 +35,13 @@ enum pd_ctrl_msg_type {
PD_CTRL_WAIT = 12,
PD_CTRL_SOFT_RESET = 13,
/* 14-15 Reserved */
+ PD_CTRL_NOT_SUPP = 16,
+ PD_CTRL_GET_SOURCE_CAP_EXT = 17,
+ PD_CTRL_GET_STATUS = 18,
+ PD_CTRL_FR_SWAP = 19,
+ PD_CTRL_GET_PPS_STATUS = 20,
+ PD_CTRL_GET_COUNTRY_CODES = 21,
+ /* 22-31 Reserved */
};
enum pd_data_msg_type {
@@ -43,13 +50,39 @@ enum pd_data_msg_type {
PD_DATA_REQUEST = 2,
PD_DATA_BIST = 3,
PD_DATA_SINK_CAP = 4,
- /* 5-14 Reserved */
+ PD_DATA_BATT_STATUS = 5,
+ PD_DATA_ALERT = 6,
+ PD_DATA_GET_COUNTRY_INFO = 7,
+ /* 8-14 Reserved */
PD_DATA_VENDOR_DEF = 15,
+ /* 16-31 Reserved */
+};
+
+enum pd_ext_msg_type {
+ /* 0 Reserved */
+ PD_EXT_SOURCE_CAP_EXT = 1,
+ PD_EXT_STATUS = 2,
+ PD_EXT_GET_BATT_CAP = 3,
+ PD_EXT_GET_BATT_STATUS = 4,
+ PD_EXT_BATT_CAP = 5,
+ PD_EXT_GET_MANUFACTURER_INFO = 6,
+ PD_EXT_MANUFACTURER_INFO = 7,
+ PD_EXT_SECURITY_REQUEST = 8,
+ PD_EXT_SECURITY_RESPONSE = 9,
+ PD_EXT_FW_UPDATE_REQUEST = 10,
+ PD_EXT_FW_UPDATE_RESPONSE = 11,
+ PD_EXT_PPS_STATUS = 12,
+ PD_EXT_COUNTRY_INFO = 13,
+ PD_EXT_COUNTRY_CODES = 14,
+ /* 15-31 Reserved */
};
#define PD_REV10 0x0
#define PD_REV20 0x1
+#define PD_REV30 0x2
+#define PD_MAX_REV PD_REV30
+#define PD_HEADER_EXT_HDR BIT(15)
#define PD_HEADER_CNT_SHIFT 12
#define PD_HEADER_CNT_MASK 0x7
#define PD_HEADER_ID_SHIFT 9
@@ -59,18 +92,19 @@ enum pd_data_msg_type {
#define PD_HEADER_REV_MASK 0x3
#define PD_HEADER_DATA_ROLE BIT(5)
#define PD_HEADER_TYPE_SHIFT 0
-#define PD_HEADER_TYPE_MASK 0xf
+#define PD_HEADER_TYPE_MASK 0x1f
-#define PD_HEADER(type, pwr, data, id, cnt) \
+#define PD_HEADER(type, pwr, data, rev, id, cnt, ext_hdr) \
((((type) & PD_HEADER_TYPE_MASK) << PD_HEADER_TYPE_SHIFT) | \
((pwr) == TYPEC_SOURCE ? PD_HEADER_PWR_ROLE : 0) | \
((data) == TYPEC_HOST ? PD_HEADER_DATA_ROLE : 0) | \
- (PD_REV20 << PD_HEADER_REV_SHIFT) | \
+ (rev << PD_HEADER_REV_SHIFT) | \
(((id) & PD_HEADER_ID_MASK) << PD_HEADER_ID_SHIFT) | \
- (((cnt) & PD_HEADER_CNT_MASK) << PD_HEADER_CNT_SHIFT))
+ (((cnt) & PD_HEADER_CNT_MASK) << PD_HEADER_CNT_SHIFT) | \
+ ((ext_hdr) ? PD_HEADER_EXT_HDR : 0))
#define PD_HEADER_LE(type, pwr, data, id, cnt) \
- cpu_to_le16(PD_HEADER((type), (pwr), (data), (id), (cnt)))
+ cpu_to_le16(PD_HEADER((type), (pwr), (data), PD_REV20, (id), (cnt), (0)))
static inline unsigned int pd_header_cnt(u16 header)
{
@@ -102,16 +136,75 @@ static inline unsigned int pd_header_msgid_le(__le16 header)
return pd_header_msgid(le16_to_cpu(header));
}
+static inline unsigned int pd_header_rev(u16 header)
+{
+ return (header >> PD_HEADER_REV_SHIFT) & PD_HEADER_REV_MASK;
+}
+
+static inline unsigned int pd_header_rev_le(__le16 header)
+{
+ return pd_header_rev(le16_to_cpu(header));
+}
+
+#define PD_EXT_HDR_CHUNKED BIT(15)
+#define PD_EXT_HDR_CHUNK_NUM_SHIFT 11
+#define PD_EXT_HDR_CHUNK_NUM_MASK 0xf
+#define PD_EXT_HDR_REQ_CHUNK BIT(10)
+#define PD_EXT_HDR_DATA_SIZE_SHIFT 0
+#define PD_EXT_HDR_DATA_SIZE_MASK 0x1ff
+
+#define PD_EXT_HDR(data_size, req_chunk, chunk_num, chunked) \
+ ((((data_size) & PD_EXT_HDR_DATA_SIZE_MASK) << PD_EXT_HDR_DATA_SIZE_SHIFT) | \
+ ((req_chunk) ? PD_EXT_HDR_REQ_CHUNK : 0) | \
+ (((chunk_num) & PD_EXT_HDR_CHUNK_NUM_MASK) << PD_EXT_HDR_CHUNK_NUM_SHIFT) | \
+ ((chunked) ? PD_EXT_HDR_CHUNKED : 0))
+
+#define PD_EXT_HDR_LE(data_size, req_chunk, chunk_num, chunked) \
+ cpu_to_le16(PD_EXT_HDR((data_size), (req_chunk), (chunk_num), (chunked)))
+
+static inline unsigned int pd_ext_header_chunk_num(u16 ext_header)
+{
+ return (ext_header >> PD_EXT_HDR_CHUNK_NUM_SHIFT) &
+ PD_EXT_HDR_CHUNK_NUM_MASK;
+}
+
+static inline unsigned int pd_ext_header_data_size(u16 ext_header)
+{
+ return (ext_header >> PD_EXT_HDR_DATA_SIZE_SHIFT) &
+ PD_EXT_HDR_DATA_SIZE_MASK;
+}
+
+static inline unsigned int pd_ext_header_data_size_le(__le16 ext_header)
+{
+ return pd_ext_header_data_size(le16_to_cpu(ext_header));
+}
+
#define PD_MAX_PAYLOAD 7
+#define PD_EXT_MAX_CHUNK_DATA 26
/**
- * struct pd_message - PD message as seen on wire
- * @header: PD message header
- * @payload: PD message payload
- */
+ * struct pd_chunked_ext_message_data - PD chunked extended message data as
+ * seen on wire
+ * @header: PD extended message header
+ * @data: PD extended message data
+ */
+struct pd_chunked_ext_message_data {
+ __le16 header;
+ u8 data[PD_EXT_MAX_CHUNK_DATA];
+} __packed;
+
+/**
+ * struct pd_message - PD message as seen on wire
+ * @header: PD message header
+ * @payload: PD message payload
+ * @ext_msg: PD message chunked extended message data
+ */
struct pd_message {
__le16 header;
- __le32 payload[PD_MAX_PAYLOAD];
+ union {
+ __le32 payload[PD_MAX_PAYLOAD];
+ struct pd_chunked_ext_message_data ext_msg;
+ };
} __packed;
/* PDO: Power Data Object */
@@ -121,6 +214,7 @@ enum pd_pdo_type {
PDO_TYPE_FIXED = 0,
PDO_TYPE_BATT = 1,
PDO_TYPE_VAR = 2,
+ PDO_TYPE_APDO = 3,
};
#define PDO_TYPE_SHIFT 30
@@ -174,6 +268,34 @@ enum pd_pdo_type {
(PDO_TYPE(PDO_TYPE_VAR) | PDO_VAR_MIN_VOLT(min_mv) | \
PDO_VAR_MAX_VOLT(max_mv) | PDO_VAR_MAX_CURR(max_ma))
+enum pd_apdo_type {
+ APDO_TYPE_PPS = 0,
+};
+
+#define PDO_APDO_TYPE_SHIFT 28 /* Only valid value currently is 0x0 - PPS */
+#define PDO_APDO_TYPE_MASK 0x3
+
+#define PDO_APDO_TYPE(t) ((t) << PDO_APDO_TYPE_SHIFT)
+
+#define PDO_PPS_APDO_MAX_VOLT_SHIFT 17 /* 100mV units */
+#define PDO_PPS_APDO_MIN_VOLT_SHIFT 8 /* 100mV units */
+#define PDO_PPS_APDO_MAX_CURR_SHIFT 0 /* 50mA units */
+
+#define PDO_PPS_APDO_VOLT_MASK 0xff
+#define PDO_PPS_APDO_CURR_MASK 0x7f
+
+#define PDO_PPS_APDO_MIN_VOLT(mv) \
+ ((((mv) / 100) & PDO_PPS_APDO_VOLT_MASK) << PDO_PPS_APDO_MIN_VOLT_SHIFT)
+#define PDO_PPS_APDO_MAX_VOLT(mv) \
+ ((((mv) / 100) & PDO_PPS_APDO_VOLT_MASK) << PDO_PPS_APDO_MAX_VOLT_SHIFT)
+#define PDO_PPS_APDO_MAX_CURR(ma) \
+ ((((ma) / 50) & PDO_PPS_APDO_CURR_MASK) << PDO_PPS_APDO_MAX_CURR_SHIFT)
+
+#define PDO_PPS_APDO(min_mv, max_mv, max_ma) \
+ (PDO_TYPE(PDO_TYPE_APDO) | PDO_APDO_TYPE(APDO_TYPE_PPS) | \
+ PDO_PPS_APDO_MIN_VOLT(min_mv) | PDO_PPS_APDO_MAX_VOLT(max_mv) | \
+ PDO_PPS_APDO_MAX_CURR(max_ma))
+
static inline enum pd_pdo_type pdo_type(u32 pdo)
{
return (pdo >> PDO_TYPE_SHIFT) & PDO_TYPE_MASK;
@@ -204,6 +326,29 @@ static inline unsigned int pdo_max_power(u32 pdo)
return ((pdo >> PDO_BATT_MAX_PWR_SHIFT) & PDO_PWR_MASK) * 250;
}
+static inline enum pd_apdo_type pdo_apdo_type(u32 pdo)
+{
+ return (pdo >> PDO_APDO_TYPE_SHIFT) & PDO_APDO_TYPE_MASK;
+}
+
+static inline unsigned int pdo_pps_apdo_min_voltage(u32 pdo)
+{
+ return ((pdo >> PDO_PPS_APDO_MIN_VOLT_SHIFT) &
+ PDO_PPS_APDO_VOLT_MASK) * 100;
+}
+
+static inline unsigned int pdo_pps_apdo_max_voltage(u32 pdo)
+{
+ return ((pdo >> PDO_PPS_APDO_MAX_VOLT_SHIFT) &
+ PDO_PPS_APDO_VOLT_MASK) * 100;
+}
+
+static inline unsigned int pdo_pps_apdo_max_current(u32 pdo)
+{
+ return ((pdo >> PDO_PPS_APDO_MAX_CURR_SHIFT) &
+ PDO_PPS_APDO_CURR_MASK) * 50;
+}
+
/* RDO: Request Data Object */
#define RDO_OBJ_POS_SHIFT 28
#define RDO_OBJ_POS_MASK 0x7
@@ -237,6 +382,24 @@ static inline unsigned int pdo_max_power(u32 pdo)
(RDO_OBJ(idx) | (flags) | \
RDO_BATT_OP_PWR(op_mw) | RDO_BATT_MAX_PWR(max_mw))
+#define RDO_PROG_VOLT_MASK 0x7ff
+#define RDO_PROG_CURR_MASK 0x7f
+
+#define RDO_PROG_VOLT_SHIFT 9
+#define RDO_PROG_CURR_SHIFT 0
+
+#define RDO_PROG_VOLT_MV_STEP 20
+#define RDO_PROG_CURR_MA_STEP 50
+
+#define PDO_PROG_OUT_VOLT(mv) \
+ ((((mv) / RDO_PROG_VOLT_MV_STEP) & RDO_PROG_VOLT_MASK) << RDO_PROG_VOLT_SHIFT)
+#define PDO_PROG_OP_CURR(ma) \
+ ((((ma) / RDO_PROG_CURR_MA_STEP) & RDO_PROG_CURR_MASK) << RDO_PROG_CURR_SHIFT)
+
+#define RDO_PROG(idx, out_mv, op_ma, flags) \
+ (RDO_OBJ(idx) | (flags) | \
+ PDO_PROG_OUT_VOLT(out_mv) | PDO_PROG_OP_CURR(op_ma))
+
static inline unsigned int rdo_index(u32 rdo)
{
return (rdo >> RDO_OBJ_POS_SHIFT) & RDO_OBJ_POS_MASK;
diff --git a/include/linux/usb/pd_ado.h b/include/linux/usb/pd_ado.h
new file mode 100644
index 000000000000..9aa1cf31c93c
--- /dev/null
+++ b/include/linux/usb/pd_ado.h
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ */
+
+#ifndef __LINUX_USB_PD_ADO_H
+#define __LINUX_USB_PD_ADO_H
+
+/* ADO : Alert Data Object */
+#define USB_PD_ADO_TYPE_SHIFT 24
+#define USB_PD_ADO_TYPE_MASK 0xff
+#define USB_PD_ADO_FIXED_BATT_SHIFT 20
+#define USB_PD_ADO_FIXED_BATT_MASK 0xf
+#define USB_PD_ADO_HOT_SWAP_BATT_SHIFT 16
+#define USB_PD_ADO_HOT_SWAP_BATT_MASK 0xf
+
+#define USB_PD_ADO_TYPE_BATT_STATUS_CHANGE BIT(1)
+#define USB_PD_ADO_TYPE_OCP BIT(2)
+#define USB_PD_ADO_TYPE_OTP BIT(3)
+#define USB_PD_ADO_TYPE_OP_COND_CHANGE BIT(4)
+#define USB_PD_ADO_TYPE_SRC_INPUT_CHANGE BIT(5)
+#define USB_PD_ADO_TYPE_OVP BIT(6)
+
+static inline unsigned int usb_pd_ado_type(u32 ado)
+{
+ return (ado >> USB_PD_ADO_TYPE_SHIFT) & USB_PD_ADO_TYPE_MASK;
+}
+
+static inline unsigned int usb_pd_ado_fixed_batt(u32 ado)
+{
+ return (ado >> USB_PD_ADO_FIXED_BATT_SHIFT) &
+ USB_PD_ADO_FIXED_BATT_MASK;
+}
+
+static inline unsigned int usb_pd_ado_hot_swap_batt(u32 ado)
+{
+ return (ado >> USB_PD_ADO_HOT_SWAP_BATT_SHIFT) &
+ USB_PD_ADO_HOT_SWAP_BATT_MASK;
+}
+#endif /* __LINUX_USB_PD_ADO_H */
diff --git a/include/linux/usb/pd_ext_sdb.h b/include/linux/usb/pd_ext_sdb.h
new file mode 100644
index 000000000000..0eb83ce19597
--- /dev/null
+++ b/include/linux/usb/pd_ext_sdb.h
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ */
+
+#ifndef __LINUX_USB_PD_EXT_SDB_H
+#define __LINUX_USB_PD_EXT_SDB_H
+
+/* SDB : Status Data Block */
+enum usb_pd_ext_sdb_fields {
+ USB_PD_EXT_SDB_INTERNAL_TEMP = 0,
+ USB_PD_EXT_SDB_PRESENT_INPUT,
+ USB_PD_EXT_SDB_PRESENT_BATT_INPUT,
+ USB_PD_EXT_SDB_EVENT_FLAGS,
+ USB_PD_EXT_SDB_TEMP_STATUS,
+ USB_PD_EXT_SDB_DATA_SIZE,
+};
+
+/* Event Flags */
+#define USB_PD_EXT_SDB_EVENT_OCP BIT(1)
+#define USB_PD_EXT_SDB_EVENT_OTP BIT(2)
+#define USB_PD_EXT_SDB_EVENT_OVP BIT(3)
+#define USB_PD_EXT_SDB_EVENT_CF_CV_MODE BIT(4)
+
+#define USB_PD_EXT_SDB_PPS_EVENTS (USB_PD_EXT_SDB_EVENT_OCP | \
+ USB_PD_EXT_SDB_EVENT_OTP | \
+ USB_PD_EXT_SDB_EVENT_OVP)
+
+#endif /* __LINUX_USB_PD_EXT_SDB_H */
diff --git a/include/linux/usb/role.h b/include/linux/usb/role.h
new file mode 100644
index 000000000000..edc51be4a77c
--- /dev/null
+++ b/include/linux/usb/role.h
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#ifndef __LINUX_USB_ROLE_H
+#define __LINUX_USB_ROLE_H
+
+#include <linux/device.h>
+
+struct usb_role_switch;
+
+enum usb_role {
+ USB_ROLE_NONE,
+ USB_ROLE_HOST,
+ USB_ROLE_DEVICE,
+};
+
+typedef int (*usb_role_switch_set_t)(struct device *dev, enum usb_role role);
+typedef enum usb_role (*usb_role_switch_get_t)(struct device *dev);
+
+/**
+ * struct usb_role_switch_desc - USB Role Switch Descriptor
+ * @usb2_port: Optional reference to the host controller port device (USB2)
+ * @usb3_port: Optional reference to the host controller port device (USB3)
+ * @udc: Optional reference to the peripheral controller device
+ * @set: Callback for setting the role
+ * @get: Callback for getting the role (optional)
+ * @allow_userspace_control: If true userspace may change the role through sysfs
+ *
+ * @usb2_port and @usb3_port will point to the USB host port and @udc to the USB
+ * device controller behind the USB connector with the role switch. If
+ * @usb2_port, @usb3_port and @udc are included in the description, the
+ * reference count for them should be incremented by the caller of
+ * usb_role_switch_register() before registering the switch.
+ */
+struct usb_role_switch_desc {
+ struct device *usb2_port;
+ struct device *usb3_port;
+ struct device *udc;
+ usb_role_switch_set_t set;
+ usb_role_switch_get_t get;
+ bool allow_userspace_control;
+};
+
+int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role);
+enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw);
+struct usb_role_switch *usb_role_switch_get(struct device *dev);
+void usb_role_switch_put(struct usb_role_switch *sw);
+
+struct usb_role_switch *
+usb_role_switch_register(struct device *parent,
+ const struct usb_role_switch_desc *desc);
+void usb_role_switch_unregister(struct usb_role_switch *sw);
+
+#endif /* __LINUX_USB_ROLE_H */
diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h
index ca1c0b57f03f..f0d839daeaea 100644
--- a/include/linux/usb/tcpm.h
+++ b/include/linux/usb/tcpm.h
@@ -91,17 +91,13 @@ struct tcpc_config {
unsigned int operating_snk_mw;
enum typec_port_type type;
+ enum typec_port_data data;
enum typec_role default_role;
bool try_role_hw; /* try.{src,snk} implemented in hardware */
const struct typec_altmode_desc *alt_modes;
};
-enum tcpc_usb_switch {
- TCPC_USB_SWITCH_CONNECT,
- TCPC_USB_SWITCH_DISCONNECT,
-};
-
/* Mux state attributes */
#define TCPC_MUX_USB_ENABLED BIT(0) /* USB enabled */
#define TCPC_MUX_DP_ENABLED BIT(1) /* DP enabled */
@@ -116,14 +112,6 @@ enum tcpc_mux_mode {
TCPC_MUX_DP_ENABLED,
};
-struct tcpc_mux_dev {
- int (*set)(struct tcpc_mux_dev *dev, enum tcpc_mux_mode mux_mode,
- enum tcpc_usb_switch usb_config,
- enum typec_cc_polarity polarity);
- bool dfp_only;
- void *priv_data;
-};
-
/**
* struct tcpc_dev - Port configuration and callback functions
* @config: Pointer to port configuration
@@ -175,7 +163,6 @@ struct tcpc_dev {
int (*try_role)(struct tcpc_dev *dev, int role);
int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type type,
const struct pd_message *msg);
- struct tcpc_mux_dev *mux;
};
struct tcpm_port;
diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h
index 0d44ce6af08f..672b39bb0adc 100644
--- a/include/linux/usb/typec.h
+++ b/include/linux/usb/typec.h
@@ -22,9 +22,15 @@ struct typec_port;
struct fwnode_handle;
enum typec_port_type {
+ TYPEC_PORT_SRC,
+ TYPEC_PORT_SNK,
+ TYPEC_PORT_DRP,
+};
+
+enum typec_port_data {
TYPEC_PORT_DFP,
TYPEC_PORT_UFP,
- TYPEC_PORT_DRP,
+ TYPEC_PORT_DRD,
};
enum typec_plug_type {
@@ -60,6 +66,12 @@ enum typec_accessory {
#define TYPEC_MAX_ACCESSORY 3
+enum typec_orientation {
+ TYPEC_ORIENTATION_NONE,
+ TYPEC_ORIENTATION_NORMAL,
+ TYPEC_ORIENTATION_REVERSE,
+};
+
/*
* struct usb_pd_identity - USB Power Delivery identity data
* @id_header: ID Header VDO
@@ -180,11 +192,14 @@ struct typec_partner_desc {
/*
* struct typec_capability - USB Type-C Port Capabilities
- * @role: DFP (Host-only), UFP (Device-only) or DRP (Dual Role)
+ * @type: Supported power role of the port
+ * @data: Supported data role of the port
* @revision: USB Type-C Specification release. Binary coded decimal
* @pd_revision: USB Power Delivery Specification revision if supported
- * @prefer_role: Initial role preference
+ * @prefer_role: Initial role preference (DRP ports).
* @accessory: Supported Accessory Modes
+ * @sw: Cable plug orientation switch
+ * @mux: Multiplexer switch for Alternate/Accessory Modes
* @fwnode: Optional fwnode of the port
* @try_role: Set data role preference for DRP port
* @dr_set: Set Data Role
@@ -197,11 +212,14 @@ struct typec_partner_desc {
*/
struct typec_capability {
enum typec_port_type type;
+ enum typec_port_data data;
u16 revision; /* 0120H = "1.2" */
u16 pd_revision; /* 0300H = "3.0" */
int prefer_role;
enum typec_accessory accessory[TYPEC_MAX_ACCESSORY];
+ struct typec_switch *sw;
+ struct typec_mux *mux;
struct fwnode_handle *fwnode;
int (*try_role)(const struct typec_capability *,
@@ -245,4 +263,8 @@ void typec_set_pwr_role(struct typec_port *port, enum typec_role role);
void typec_set_vconn_role(struct typec_port *port, enum typec_role role);
void typec_set_pwr_opmode(struct typec_port *port, enum typec_pwr_opmode mode);
+int typec_set_orientation(struct typec_port *port,
+ enum typec_orientation orientation);
+int typec_set_mode(struct typec_port *port, int mode);
+
#endif /* __LINUX_USB_TYPEC_H */
diff --git a/include/linux/usb/typec_mux.h b/include/linux/usb/typec_mux.h
new file mode 100644
index 000000000000..12c1b057834b
--- /dev/null
+++ b/include/linux/usb/typec_mux.h
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#ifndef __USB_TYPEC_MUX
+#define __USB_TYPEC_MUX
+
+#include <linux/list.h>
+#include <linux/usb/typec.h>
+
+struct device;
+
+/**
+ * struct typec_switch - USB Type-C cable orientation switch
+ * @dev: Switch device
+ * @entry: List entry
+ * @set: Callback to the driver for setting the orientation
+ *
+ * USB Type-C pin flipper switch routing the correct data pairs from the
+ * connector to the USB controller depending on the orientation of the cable
+ * plug.
+ */
+struct typec_switch {
+ struct device *dev;
+ struct list_head entry;
+
+ int (*set)(struct typec_switch *sw, enum typec_orientation orientation);
+};
+
+/**
+ * struct typec_switch - USB Type-C connector pin mux
+ * @dev: Mux device
+ * @entry: List entry
+ * @set: Callback to the driver for setting the state of the mux
+ *
+ * Pin Multiplexer/DeMultiplexer switch routing the USB Type-C connector pins to
+ * different components depending on the requested mode of operation. Used with
+ * Accessory/Alternate modes.
+ */
+struct typec_mux {
+ struct device *dev;
+ struct list_head entry;
+
+ int (*set)(struct typec_mux *mux, int state);
+};
+
+struct typec_switch *typec_switch_get(struct device *dev);
+void typec_switch_put(struct typec_switch *sw);
+int typec_switch_register(struct typec_switch *sw);
+void typec_switch_unregister(struct typec_switch *sw);
+
+struct typec_mux *typec_mux_get(struct device *dev);
+void typec_mux_put(struct typec_mux *mux);
+int typec_mux_register(struct typec_mux *mux);
+void typec_mux_unregister(struct typec_mux *mux);
+
+#endif /* __USB_TYPEC_MUX */
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 55a611486bac..d9f131ecf708 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -599,6 +599,120 @@ do { \
__ret; \
})
+/**
+ * wait_event_idle - wait for a condition without contributing to system load
+ * @wq_head: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ *
+ * The process is put to sleep (TASK_IDLE) until the
+ * @condition evaluates to true.
+ * The @condition is checked each time the waitqueue @wq_head is woken up.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ *
+ */
+#define wait_event_idle(wq_head, condition) \
+do { \
+ might_sleep(); \
+ if (!(condition)) \
+ ___wait_event(wq_head, condition, TASK_IDLE, 0, 0, schedule()); \
+} while (0)
+
+/**
+ * wait_event_idle_exclusive - wait for a condition with contributing to system load
+ * @wq_head: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ *
+ * The process is put to sleep (TASK_IDLE) until the
+ * @condition evaluates to true.
+ * The @condition is checked each time the waitqueue @wq_head is woken up.
+ *
+ * The process is put on the wait queue with an WQ_FLAG_EXCLUSIVE flag
+ * set thus if other processes wait on the same list, when this
+ * process is woken further processes are not considered.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ *
+ */
+#define wait_event_idle_exclusive(wq_head, condition) \
+do { \
+ might_sleep(); \
+ if (!(condition)) \
+ ___wait_event(wq_head, condition, TASK_IDLE, 1, 0, schedule()); \
+} while (0)
+
+#define __wait_event_idle_timeout(wq_head, condition, timeout) \
+ ___wait_event(wq_head, ___wait_cond_timeout(condition), \
+ TASK_IDLE, 0, timeout, \
+ __ret = schedule_timeout(__ret))
+
+/**
+ * wait_event_idle_timeout - sleep without load until a condition becomes true or a timeout elapses
+ * @wq_head: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ * @timeout: timeout, in jiffies
+ *
+ * The process is put to sleep (TASK_IDLE) until the
+ * @condition evaluates to true. The @condition is checked each time
+ * the waitqueue @wq_head is woken up.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ *
+ * Returns:
+ * 0 if the @condition evaluated to %false after the @timeout elapsed,
+ * 1 if the @condition evaluated to %true after the @timeout elapsed,
+ * or the remaining jiffies (at least 1) if the @condition evaluated
+ * to %true before the @timeout elapsed.
+ */
+#define wait_event_idle_timeout(wq_head, condition, timeout) \
+({ \
+ long __ret = timeout; \
+ might_sleep(); \
+ if (!___wait_cond_timeout(condition)) \
+ __ret = __wait_event_idle_timeout(wq_head, condition, timeout); \
+ __ret; \
+})
+
+#define __wait_event_idle_exclusive_timeout(wq_head, condition, timeout) \
+ ___wait_event(wq_head, ___wait_cond_timeout(condition), \
+ TASK_IDLE, 1, timeout, \
+ __ret = schedule_timeout(__ret))
+
+/**
+ * wait_event_idle_exclusive_timeout - sleep without load until a condition becomes true or a timeout elapses
+ * @wq_head: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ * @timeout: timeout, in jiffies
+ *
+ * The process is put to sleep (TASK_IDLE) until the
+ * @condition evaluates to true. The @condition is checked each time
+ * the waitqueue @wq_head is woken up.
+ *
+ * The process is put on the wait queue with an WQ_FLAG_EXCLUSIVE flag
+ * set thus if other processes wait on the same list, when this
+ * process is woken further processes are not considered.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ *
+ * Returns:
+ * 0 if the @condition evaluated to %false after the @timeout elapsed,
+ * 1 if the @condition evaluated to %true after the @timeout elapsed,
+ * or the remaining jiffies (at least 1) if the @condition evaluated
+ * to %true before the @timeout elapsed.
+ */
+#define wait_event_idle_exclusive_timeout(wq_head, condition, timeout) \
+({ \
+ long __ret = timeout; \
+ might_sleep(); \
+ if (!___wait_cond_timeout(condition)) \
+ __ret = __wait_event_idle_exclusive_timeout(wq_head, condition, timeout);\
+ __ret; \
+})
+
extern int do_wait_intr(wait_queue_head_t *, wait_queue_entry_t *);
extern int do_wait_intr_irq(wait_queue_head_t *, wait_queue_entry_t *);
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 0c3301421c57..39a0e215022a 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -13,6 +13,7 @@
#include <linux/threads.h>
#include <linux/atomic.h>
#include <linux/cpumask.h>
+#include <linux/rcupdate.h>
struct workqueue_struct;
@@ -120,6 +121,14 @@ struct delayed_work {
int cpu;
};
+struct rcu_work {
+ struct work_struct work;
+ struct rcu_head rcu;
+
+ /* target workqueue ->rcu uses to queue ->work */
+ struct workqueue_struct *wq;
+};
+
/**
* struct workqueue_attrs - A struct for workqueue attributes.
*
@@ -151,6 +160,11 @@ static inline struct delayed_work *to_delayed_work(struct work_struct *work)
return container_of(work, struct delayed_work, work);
}
+static inline struct rcu_work *to_rcu_work(struct work_struct *work)
+{
+ return container_of(work, struct rcu_work, work);
+}
+
struct execute_work {
struct work_struct work;
};
@@ -266,6 +280,12 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
#define INIT_DEFERRABLE_WORK_ONSTACK(_work, _func) \
__INIT_DELAYED_WORK_ONSTACK(_work, _func, TIMER_DEFERRABLE)
+#define INIT_RCU_WORK(_work, _func) \
+ INIT_WORK(&(_work)->work, (_func))
+
+#define INIT_RCU_WORK_ONSTACK(_work, _func) \
+ INIT_WORK_ONSTACK(&(_work)->work, (_func))
+
/**
* work_pending - Find out whether a work item is currently pending
* @work: The work item in question
@@ -447,6 +467,7 @@ extern bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
struct delayed_work *work, unsigned long delay);
extern bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq,
struct delayed_work *dwork, unsigned long delay);
+extern bool queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *rwork);
extern void flush_workqueue(struct workqueue_struct *wq);
extern void drain_workqueue(struct workqueue_struct *wq);
@@ -462,6 +483,8 @@ extern bool flush_delayed_work(struct delayed_work *dwork);
extern bool cancel_delayed_work(struct delayed_work *dwork);
extern bool cancel_delayed_work_sync(struct delayed_work *dwork);
+extern bool flush_rcu_work(struct rcu_work *rwork);
+
extern void workqueue_set_max_active(struct workqueue_struct *wq,
int max_active);
extern struct work_struct *current_work(void);
diff --git a/include/media/cec-notifier.h b/include/media/cec-notifier.h
index 57ec319a7f44..cf0add70b0e7 100644
--- a/include/media/cec-notifier.h
+++ b/include/media/cec-notifier.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cec-notifier.h - notify CEC drivers of physical address changes
*
* Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk>
* Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef LINUX_CEC_NOTIFIER_H
diff --git a/include/media/cec-pin.h b/include/media/cec-pin.h
index 83b3e17e0a07..ed16c6dde0ba 100644
--- a/include/media/cec-pin.h
+++ b/include/media/cec-pin.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cec-pin.h - low-level CEC pin control
*
* Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef LINUX_CEC_PIN_H
diff --git a/include/media/cec.h b/include/media/cec.h
index 7cdf71d7125a..580ab1042898 100644
--- a/include/media/cec.h
+++ b/include/media/cec.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* cec - HDMI Consumer Electronics Control support header
*
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _MEDIA_CEC_H
@@ -104,7 +92,7 @@ struct cec_fh {
wait_queue_head_t wait;
struct mutex lock;
struct list_head events[CEC_NUM_EVENTS]; /* queued events */
- u8 queued_events[CEC_NUM_EVENTS];
+ u16 queued_events[CEC_NUM_EVENTS];
unsigned int total_queued_events;
struct cec_event_entry core_events[CEC_NUM_CORE_EVENTS];
struct list_head msgs; /* queued messages */
@@ -129,6 +117,10 @@ struct cec_adap_ops {
void (*adap_status)(struct cec_adapter *adap, struct seq_file *file);
void (*adap_free)(struct cec_adapter *adap);
+ /* Error injection callbacks */
+ int (*error_inj_show)(struct cec_adapter *adap, struct seq_file *sf);
+ bool (*error_inj_parse_line)(struct cec_adapter *adap, char *line);
+
/* High-level CEC message callback */
int (*received)(struct cec_adapter *adap, struct cec_msg *msg);
};
@@ -201,6 +193,7 @@ struct cec_adapter {
struct dentry *cec_dir;
struct dentry *status_file;
+ struct dentry *error_inj_file;
u16 phys_addrs[15];
u32 sequence;
@@ -298,11 +291,12 @@ static inline void cec_received_msg(struct cec_adapter *adap,
*
* @adap: pointer to the cec adapter
* @is_high: when true the CEC pin is high, otherwise it is low
+ * @dropped_events: when true some events were dropped
* @ts: the timestamp for this event
*
*/
-void cec_queue_pin_cec_event(struct cec_adapter *adap,
- bool is_high, ktime_t ts);
+void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high,
+ bool dropped_events, ktime_t ts);
/**
* cec_queue_pin_hpd_event() - queue a pin event with a given timestamp.
diff --git a/include/media/drv-intf/renesas-ceu.h b/include/media/drv-intf/renesas-ceu.h
new file mode 100644
index 000000000000..52841d1b4763
--- /dev/null
+++ b/include/media/drv-intf/renesas-ceu.h
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * renesas-ceu.h - Renesas CEU driver interface
+ *
+ * Copyright 2017-2018 Jacopo Mondi <jacopo+renesas@jmondi.org>
+ */
+
+#ifndef __MEDIA_DRV_INTF_RENESAS_CEU_H__
+#define __MEDIA_DRV_INTF_RENESAS_CEU_H__
+
+#define CEU_MAX_SUBDEVS 2
+
+struct ceu_async_subdev {
+ unsigned long flags;
+ unsigned char bus_width;
+ unsigned char bus_shift;
+ unsigned int i2c_adapter_id;
+ unsigned int i2c_address;
+};
+
+struct ceu_platform_data {
+ unsigned int num_subdevs;
+ struct ceu_async_subdev subdevs[CEU_MAX_SUBDEVS];
+};
+
+#endif /* ___MEDIA_DRV_INTF_RENESAS_CEU_H__ */
diff --git a/include/media/dvbdev.h b/include/media/dvbdev.h
index 554db879527f..ee91516ad074 100644
--- a/include/media/dvbdev.h
+++ b/include/media/dvbdev.h
@@ -358,7 +358,61 @@ long dvb_generic_ioctl(struct file *file,
int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
int (*func)(struct file *file, unsigned int cmd, void *arg));
-/** generic DVB attach function. */
+#if IS_ENABLED(CONFIG_I2C)
+
+struct i2c_adapter;
+struct i2c_client;
+/**
+ * dvb_module_probe - helper routine to probe an I2C module
+ *
+ * @module_name:
+ * Name of the I2C module to be probed
+ * @name:
+ * Optional name for the I2C module. Used for debug purposes.
+ * If %NULL, defaults to @module_name.
+ * @adap:
+ * pointer to &struct i2c_adapter that describes the I2C adapter where
+ * the module will be bound.
+ * @addr:
+ * I2C address of the adapter, in 7-bit notation.
+ * @platform_data:
+ * Platform data to be passed to the I2C module probed.
+ *
+ * This function binds an I2C device into the DVB core. Should be used by
+ * all drivers that use I2C bus to control the hardware. A module bound
+ * with dvb_module_probe() should use dvb_module_release() to unbind.
+ *
+ * Return:
+ * On success, return an &struct i2c_client, pointing the the bound
+ * I2C device. %NULL otherwise.
+ *
+ * .. note::
+ *
+ * In the past, DVB modules (mainly, frontends) were bound via dvb_attach()
+ * macro, with does an ugly hack, using I2C low level functions. Such
+ * usage is deprecated and will be removed soon. Instead, use this routine.
+ */
+struct i2c_client *dvb_module_probe(const char *module_name,
+ const char *name,
+ struct i2c_adapter *adap,
+ unsigned char addr,
+ void *platform_data);
+
+/**
+ * dvb_module_release - releases an I2C device allocated with
+ * dvb_module_probe().
+ *
+ * @client: pointer to &struct i2c_client with the I2C client to be released.
+ * can be %NULL.
+ *
+ * This function should be used to free all resources reserved by
+ * dvb_module_probe() and unbinding the I2C hardware.
+ */
+void dvb_module_release(struct i2c_client *client);
+
+#endif /* CONFIG_I2C */
+
+/* Legacy generic DVB attach function. */
#ifdef CONFIG_MEDIA_ATTACH
/**
@@ -371,6 +425,13 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
* the @FUNCTION function there, with @ARGS.
* As it increments symbol usage cont, at unregister, dvb_detach()
* should be called.
+ *
+ * .. note::
+ *
+ * In the past, DVB modules (mainly, frontends) were bound via dvb_attach()
+ * macro, with does an ugly hack, using I2C low level functions. Such
+ * usage is deprecated and will be removed soon. Instead, you should use
+ * dvb_module_probe().
*/
#define dvb_attach(FUNCTION, ARGS...) ({ \
void *__r = NULL; \
@@ -402,6 +463,6 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
#define dvb_detach(FUNC) {}
-#endif
+#endif /* CONFIG_MEDIA_ATTACH */
#endif /* #ifndef _DVBDEV_H_ */
diff --git a/include/media/i2c/ad9389b.h b/include/media/i2c/ad9389b.h
index 5ba9af869b8b..30f9ea9a1273 100644
--- a/include/media/i2c/ad9389b.h
+++ b/include/media/i2c/ad9389b.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Analog Devices AD9389B/AD9889B video encoder driver header
*
* Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef AD9389B_H
diff --git a/include/media/i2c/adv7511.h b/include/media/i2c/adv7511.h
index 61c3d711cc69..1874c05f486f 100644
--- a/include/media/i2c/adv7511.h
+++ b/include/media/i2c/adv7511.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Analog Devices ADV7511 HDMI Transmitter Device Driver
*
* Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef ADV7511_H
diff --git a/include/media/i2c/adv7604.h b/include/media/i2c/adv7604.h
index 2e6857dee0cc..77a9799128b6 100644
--- a/include/media/i2c/adv7604.h
+++ b/include/media/i2c/adv7604.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* adv7604 - Analog Devices ADV7604 video decoder driver
*
* Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
*/
#ifndef _ADV7604_
diff --git a/include/media/i2c/adv7842.h b/include/media/i2c/adv7842.h
index 7f53ada9bdf1..05e01f0dd3c2 100644
--- a/include/media/i2c/adv7842.h
+++ b/include/media/i2c/adv7842.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* adv7842 - Analog Devices ADV7842 video decoder driver
*
* Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
*/
#ifndef _ADV7842_
diff --git a/include/media/i2c/mt9t112.h b/include/media/i2c/mt9t112.h
index a43c74ab05ec..cc80d5cc2104 100644
--- a/include/media/i2c/mt9t112.h
+++ b/include/media/i2c/mt9t112.h
@@ -1,28 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/* mt9t112 Camera
*
* Copyright (C) 2009 Renesas Solutions Corp.
* Kuninori Morimoto <morimoto.kuninori@renesas.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 __MT9T112_H__
#define __MT9T112_H__
-#define MT9T112_FLAG_PCLK_RISING_EDGE (1 << 0)
-#define MT9T112_FLAG_DATAWIDTH_8 (1 << 1) /* default width is 10 */
-
struct mt9t112_pll_divider {
u8 m, n;
u8 p1, p2, p3, p4, p5, p6, p7;
};
-/*
- * mt9t112 camera info
+/**
+ * mt9t112_platform_data - mt9t112 driver interface
+ * @flags: Sensor media bus configuration.
+ * @divider: Sensor PLL configuration
*/
-struct mt9t112_camera_info {
+struct mt9t112_platform_data {
+#define MT9T112_FLAG_PCLK_RISING_EDGE BIT(0)
u32 flags;
struct mt9t112_pll_divider divider;
};
diff --git a/include/media/i2c/ov772x.h b/include/media/i2c/ov772x.h
index 00dbb7c4feae..27d087baffc5 100644
--- a/include/media/i2c/ov772x.h
+++ b/include/media/i2c/ov772x.h
@@ -48,8 +48,10 @@ struct ov772x_edge_ctrl {
.threshold = (t & OV772X_EDGE_THRESHOLD_MASK), \
}
-/*
- * ov772x camera info
+/**
+ * ov772x_camera_info - ov772x driver interface structure
+ * @flags: Sensor configuration flags
+ * @edgectrl: Sensor edge control
*/
struct ov772x_camera_info {
unsigned long flags;
diff --git a/include/media/i2c/tc358743.h b/include/media/i2c/tc358743.h
index 4513f2f9cfbc..b343650c2948 100644
--- a/include/media/i2c/tc358743.h
+++ b/include/media/i2c/tc358743.h
@@ -1,22 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* tc358743 - Toshiba HDMI to CSI-2 bridge
*
- * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights
- * reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
+ * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*/
/*
diff --git a/include/media/i2c/tda1997x.h b/include/media/i2c/tda1997x.h
new file mode 100644
index 000000000000..c6c2a8ae413d
--- /dev/null
+++ b/include/media/i2c/tda1997x.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * tda1997x - NXP HDMI receiver
+ *
+ * Copyright 2017 Tim Harvey <tharvey@gateworks.com>
+ *
+ */
+
+#ifndef _TDA1997X_
+#define _TDA1997X_
+
+/* Platform Data */
+struct tda1997x_platform_data {
+ enum v4l2_mbus_type vidout_bus_type;
+ u32 vidout_bus_width;
+ u8 vidout_port_cfg[9];
+ /* pin polarity (1=invert) */
+ bool vidout_inv_de;
+ bool vidout_inv_hs;
+ bool vidout_inv_vs;
+ bool vidout_inv_pclk;
+ /* clock delays (0=-8, 1=-7 ... 15=+7 pixels) */
+ u8 vidout_delay_hs;
+ u8 vidout_delay_vs;
+ u8 vidout_delay_de;
+ u8 vidout_delay_pclk;
+ /* sync selections (controls how sync pins are derived) */
+ u8 vidout_sel_hs;
+ u8 vidout_sel_vs;
+ u8 vidout_sel_de;
+
+ /* Audio Port Output */
+ int audout_format;
+ u32 audout_mclk_fs; /* clock multiplier */
+ u32 audout_width; /* 13 or 32 bit */
+ u32 audout_layout; /* layout0=AP0 layout1=AP0,AP1,AP2,AP3 */
+ bool audout_layoutauto; /* audio layout dictated by pkt header */
+ bool audout_invert_clk; /* data valid on rising edge of BCLK */
+ bool audio_auto_mute; /* enable hardware audio auto-mute */
+};
+
+#endif
diff --git a/include/media/i2c/ths7303.h b/include/media/i2c/ths7303.h
index 834e2f95b630..95492d12786d 100644
--- a/include/media/i2c/ths7303.h
+++ b/include/media/i2c/ths7303.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 Texas Instruments Inc
*
@@ -7,15 +8,6 @@
* Hans Verkuil <hans.verkuil@cisco.com>
* Lad, Prabhakar <prabhakar.lad@ti.com>
* Martin Bugge <marbugge@cisco.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 version 2.
- *
- * 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 THS7353_H
diff --git a/include/media/i2c/tw9910.h b/include/media/i2c/tw9910.h
index 90bcf1fa5421..bec8f7bce745 100644
--- a/include/media/i2c/tw9910.h
+++ b/include/media/i2c/tw9910.h
@@ -18,6 +18,9 @@
#include <media/soc_camera.h>
+/**
+ * tw9910_mpout_pin - MPOUT (multi-purpose output) pin functions
+ */
enum tw9910_mpout_pin {
TW9910_MPO_VLOSS,
TW9910_MPO_HLOCK,
@@ -29,6 +32,12 @@ enum tw9910_mpout_pin {
TW9910_MPO_RTCO,
};
+/**
+ * tw9910_video_info - tw9910 driver interface structure
+ * @buswidth: Parallel data bus width (8 or 16).
+ * @mpout: Selected function of MPOUT (multi-purpose output) pin.
+ * See &enum tw9910_mpout_pin
+ */
struct tw9910_video_info {
unsigned long buswidth;
enum tw9910_mpout_pin mpout;
diff --git a/include/media/i2c/uda1342.h b/include/media/i2c/uda1342.h
index cd156403a368..cb412d4c1088 100644
--- a/include/media/i2c/uda1342.h
+++ b/include/media/i2c/uda1342.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* uda1342.h - definition for uda1342 inputs
*
* Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
*/
#ifndef _UDA1342_H_
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index aed4272d47f5..6742fd86ff65 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -23,13 +23,6 @@
#include <linux/timer.h>
#include <media/rc-map.h>
-extern int rc_core_debug;
-#define IR_dprintk(level, fmt, ...) \
-do { \
- if (rc_core_debug >= level) \
- printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \
-} while (0)
-
/**
* enum rc_driver_type - type of the RC driver.
*
@@ -341,7 +334,9 @@ void ir_raw_event_handle(struct rc_dev *dev);
int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse);
int ir_raw_event_store_with_filter(struct rc_dev *dev,
- struct ir_raw_event *ev);
+ struct ir_raw_event *ev);
+int ir_raw_event_store_with_timeout(struct rc_dev *dev,
+ struct ir_raw_event *ev);
void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
int ir_raw_encode_scancode(enum rc_proto protocol, u32 scancode,
struct ir_raw_event *events, unsigned int max);
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 7046734b3895..bfa3017cecba 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -36,6 +36,7 @@
#define RC_PROTO_BIT_SHARP BIT_ULL(RC_PROTO_SHARP)
#define RC_PROTO_BIT_XMP BIT_ULL(RC_PROTO_XMP)
#define RC_PROTO_BIT_CEC BIT_ULL(RC_PROTO_CEC)
+#define RC_PROTO_BIT_IMON BIT_ULL(RC_PROTO_IMON)
#define RC_PROTO_BIT_ALL \
(RC_PROTO_BIT_UNKNOWN | RC_PROTO_BIT_OTHER | \
@@ -49,7 +50,8 @@
RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \
RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | \
RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_SHARP | \
- RC_PROTO_BIT_XMP | RC_PROTO_BIT_CEC)
+ RC_PROTO_BIT_XMP | RC_PROTO_BIT_CEC | \
+ RC_PROTO_BIT_IMON)
/* All rc protocols for which we have decoders */
#define RC_PROTO_BIT_ALL_IR_DECODER \
(RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \
@@ -62,7 +64,7 @@
RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \
RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | \
RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_SHARP | \
- RC_PROTO_BIT_XMP)
+ RC_PROTO_BIT_XMP | RC_PROTO_BIT_IMON)
#define RC_PROTO_BIT_ALL_IR_ENCODER \
(RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \
@@ -75,7 +77,7 @@
RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \
RC_PROTO_BIT_RC6_6A_24 | \
RC_PROTO_BIT_RC6_6A_32 | RC_PROTO_BIT_RC6_MCE | \
- RC_PROTO_BIT_SHARP)
+ RC_PROTO_BIT_SHARP | RC_PROTO_BIT_IMON)
#define RC_SCANCODE_UNKNOWN(x) (x)
#define RC_SCANCODE_OTHER(x) (x)
@@ -211,6 +213,7 @@ struct rc_map *rc_map_get(const char *name);
#define RC_MAP_HISI_TV_DEMO "rc-hisi-tv-demo"
#define RC_MAP_IMON_MCE "rc-imon-mce"
#define RC_MAP_IMON_PAD "rc-imon-pad"
+#define RC_MAP_IMON_RSC "rc-imon-rsc"
#define RC_MAP_IODATA_BCTV7E "rc-iodata-bctv7e"
#define RC_MAP_IT913X_V1 "rc-it913x-v1"
#define RC_MAP_IT913X_V2 "rc-it913x-v2"
diff --git a/include/media/tpg/v4l2-tpg.h b/include/media/tpg/v4l2-tpg.h
index 823fadede7bf..eb191e85d363 100644
--- a/include/media/tpg/v4l2-tpg.h
+++ b/include/media/tpg/v4l2-tpg.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* v4l2-tpg.h - Test Pattern Generator
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _V4L2_TPG_H_
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index e0d95a7c5d48..54b689247937 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -316,21 +316,37 @@ void v4l_bound_align_image(unsigned int *width, unsigned int wmin,
unsigned int salign);
/**
- * v4l2_find_nearest_format - find the nearest format size among a discrete
- * set of resolutions.
+ * v4l2_find_nearest_size - Find the nearest size among a discrete
+ * set of resolutions contained in an array of a driver specific struct.
*
- * @sizes: array of &struct v4l2_frmsize_discrete image sizes.
- * @num_sizes: length of @sizes array.
+ * @array: a driver specific array of image sizes
+ * @width_field: the name of the width field in the driver specific struct
+ * @height_field: the name of the height field in the driver specific struct
* @width: desired width.
* @height: desired height.
*
* Finds the closest resolution to minimize the width and height differences
- * between what requested and the supported resolutions.
+ * between what requested and the supported resolutions. The size of the width
+ * and height fields in the driver specific must equal to that of u32, i.e. four
+ * bytes.
+ *
+ * Returns the best match or NULL if the length of the array is zero.
*/
-const struct v4l2_frmsize_discrete *
-v4l2_find_nearest_format(const struct v4l2_frmsize_discrete *sizes,
- const size_t num_sizes,
- s32 width, s32 height);
+#define v4l2_find_nearest_size(array, width_field, height_field, \
+ width, height) \
+ ({ \
+ BUILD_BUG_ON(sizeof((array)->width_field) != sizeof(u32) || \
+ sizeof((array)->height_field) != sizeof(u32)); \
+ (typeof(&(*(array))))__v4l2_find_nearest_size( \
+ (array), ARRAY_SIZE(array), sizeof(*(array)), \
+ offsetof(typeof(*(array)), width_field), \
+ offsetof(typeof(*(array)), height_field), \
+ width, height); \
+ })
+const void *
+__v4l2_find_nearest_size(const void *array, size_t array_size,
+ size_t entry_size, size_t width_offset,
+ size_t height_offset, s32 width, s32 height);
/**
* v4l2_get_timestamp - helper routine to get a timestamp to be used when
@@ -341,4 +357,30 @@ v4l2_find_nearest_format(const struct v4l2_frmsize_discrete *sizes,
*/
void v4l2_get_timestamp(struct timeval *tv);
+/**
+ * v4l2_g_parm_cap - helper routine for vidioc_g_parm to fill this in by
+ * calling the g_frame_interval op of the given subdev. It only works
+ * for V4L2_BUF_TYPE_VIDEO_CAPTURE(_MPLANE), hence the _cap in the
+ * function name.
+ *
+ * @vdev: the struct video_device pointer. Used to determine the device caps.
+ * @sd: the sub-device pointer.
+ * @a: the VIDIOC_G_PARM argument.
+ */
+int v4l2_g_parm_cap(struct video_device *vdev,
+ struct v4l2_subdev *sd, struct v4l2_streamparm *a);
+
+/**
+ * v4l2_s_parm_cap - helper routine for vidioc_s_parm to fill this in by
+ * calling the s_frame_interval op of the given subdev. It only works
+ * for V4L2_BUF_TYPE_VIDEO_CAPTURE(_MPLANE), hence the _cap in the
+ * function name.
+ *
+ * @vdev: the struct video_device pointer. Used to determine the device caps.
+ * @sd: the sub-device pointer.
+ * @a: the VIDIOC_S_PARM argument.
+ */
+int v4l2_s_parm_cap(struct video_device *vdev,
+ struct v4l2_subdev *sd, struct v4l2_streamparm *a);
+
#endif /* V4L2_COMMON_H_ */
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 05ebb9ef9e73..5b445b5654f7 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -761,8 +761,8 @@ void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed);
* An error is returned if one of the range arguments is invalid for this
* control type.
*
- * This function assumes that the control handler is not locked and will
- * take the lock itself.
+ * The caller is responsible for acquiring the control handler mutex on behalf
+ * of __v4l2_ctrl_modify_range().
*/
int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
s64 min, s64 max, u64 step, s64 def);
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 53f32022fabe..27634e8d2585 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -298,10 +298,10 @@ struct video_device
* media_entity_to_video_device - Returns a &struct video_device from
* the &struct media_entity embedded on it.
*
- * @entity: pointer to &struct media_entity
+ * @__entity: pointer to &struct media_entity
*/
-#define media_entity_to_video_device(entity) \
- container_of(entity, struct video_device, entity)
+#define media_entity_to_video_device(__entity) \
+ container_of(__entity, struct video_device, entity)
/**
* to_video_device - Returns a &struct video_device from the
diff --git a/include/media/v4l2-dv-timings.h b/include/media/v4l2-dv-timings.h
index ebf00e07a515..17cb27df1b81 100644
--- a/include/media/v4l2-dv-timings.h
+++ b/include/media/v4l2-dv-timings.h
@@ -1,21 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* v4l2-dv-timings - Internal header with dv-timings helper functions
*
* Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
*/
#ifndef __V4L2_DV_TIMINGS_H
@@ -225,5 +212,26 @@ static inline bool can_reduce_fps(struct v4l2_bt_timings *bt)
return false;
}
+/**
+ * struct v4l2_hdmi_rx_colorimetry - describes the HDMI colorimetry information
+ * @colorspace: enum v4l2_colorspace, the colorspace
+ * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
+ * @quantization: enum v4l2_quantization, colorspace quantization
+ * @xfer_func: enum v4l2_xfer_func, colorspace transfer function
+ */
+struct v4l2_hdmi_colorimetry {
+ enum v4l2_colorspace colorspace;
+ enum v4l2_ycbcr_encoding ycbcr_enc;
+ enum v4l2_quantization quantization;
+ enum v4l2_xfer_func xfer_func;
+};
+
+struct hdmi_avi_infoframe;
+struct hdmi_vendor_infoframe;
+
+struct v4l2_hdmi_colorimetry
+v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi,
+ const struct hdmi_vendor_infoframe *hdmi,
+ unsigned int height);
#endif
diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h
index 62633e7d2630..ea73fef8bdc0 100644
--- a/include/media/v4l2-fh.h
+++ b/include/media/v4l2-fh.h
@@ -22,6 +22,7 @@
#define V4L2_FH_H
#include <linux/fs.h>
+#include <linux/kconfig.h>
#include <linux/list.h>
#include <linux/videodev2.h>
diff --git a/include/media/v4l2-rect.h b/include/media/v4l2-rect.h
index d2125f0cc7cd..595c3ba05f23 100644
--- a/include/media/v4l2-rect.h
+++ b/include/media/v4l2-rect.h
@@ -1,20 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* v4l2-rect.h - v4l2_rect helper functions
*
* Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _V4L2_RECT_H_
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 980a86c08fce..9102d6ca566e 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -224,6 +224,9 @@ struct v4l2_subdev_core_ops {
* struct v4l2_subdev_tuner_ops - Callbacks used when v4l device was opened
* in radio mode.
*
+ * @standby: puts the tuner in standby mode. It will be woken up
+ * automatically the next time it is used.
+ *
* @s_radio: callback that switches the tuner to radio mode.
* drivers should explicitly call it when a tuner ops should
* operate on radio mode, before being able to handle it.
@@ -268,6 +271,7 @@ struct v4l2_subdev_core_ops {
* }
*/
struct v4l2_subdev_tuner_ops {
+ int (*standby)(struct v4l2_subdev *sd);
int (*s_radio)(struct v4l2_subdev *sd);
int (*s_frequency)(struct v4l2_subdev *sd, const struct v4l2_frequency *freq);
int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq);
@@ -393,10 +397,6 @@ struct v4l2_mbus_frame_desc {
*
* @g_pixelaspect: callback to return the pixelaspect ratio.
*
- * @g_parm: callback for VIDIOC_G_PARM() ioctl handler code.
- *
- * @s_parm: callback for VIDIOC_S_PARM() ioctl handler code.
- *
* @g_frame_interval: callback for VIDIOC_SUBDEV_G_FRAME_INTERVAL()
* ioctl handler code.
*
@@ -434,8 +434,6 @@ struct v4l2_subdev_video_ops {
int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
int (*s_stream)(struct v4l2_subdev *sd, int enable);
int (*g_pixelaspect)(struct v4l2_subdev *sd, struct v4l2_fract *aspect);
- int (*g_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
- int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
int (*g_frame_interval)(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *interval);
int (*s_frame_interval)(struct v4l2_subdev *sd,
@@ -867,6 +865,13 @@ struct v4l2_subdev {
struct v4l2_subdev_platform_data *pdata;
};
+
+/**
+ * media_entity_to_v4l2_subdev - Returns a &struct v4l2_subdev from
+ * the &struct media_entity embedded in it.
+ *
+ * @ent: pointer to &struct media_entity.
+ */
#define media_entity_to_v4l2_subdev(ent) \
({ \
typeof(ent) __me_sd_ent = (ent); \
@@ -876,14 +881,20 @@ struct v4l2_subdev {
NULL; \
})
+/**
+ * vdev_to_v4l2_subdev - Returns a &struct v4l2_subdev from
+ * the &struct video_device embedded on it.
+ *
+ * @vdev: pointer to &struct video_device
+ */
#define vdev_to_v4l2_subdev(vdev) \
((struct v4l2_subdev *)video_get_drvdata(vdev))
/**
* struct v4l2_subdev_fh - Used for storing subdev information per file handle
*
- * @vfh: pointer to struct v4l2_fh
- * @pad: pointer to v4l2_subdev_pad_config
+ * @vfh: pointer to &struct v4l2_fh
+ * @pad: pointer to &struct v4l2_subdev_pad_config
*/
struct v4l2_subdev_fh {
struct v4l2_fh vfh;
@@ -892,23 +903,70 @@ struct v4l2_subdev_fh {
#endif
};
+/**
+ * to_v4l2_subdev_fh - Returns a &struct v4l2_subdev_fh from
+ * the &struct v4l2_fh embedded on it.
+ *
+ * @fh: pointer to &struct v4l2_fh
+ */
#define to_v4l2_subdev_fh(fh) \
container_of(fh, struct v4l2_subdev_fh, vfh)
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-#define __V4L2_SUBDEV_MK_GET_TRY(rtype, fun_name, field_name) \
- static inline struct rtype * \
- fun_name(struct v4l2_subdev *sd, \
- struct v4l2_subdev_pad_config *cfg, \
- unsigned int pad) \
- { \
- BUG_ON(pad >= sd->entity.num_pads); \
- return &cfg[pad].field_name; \
- }
-
-__V4L2_SUBDEV_MK_GET_TRY(v4l2_mbus_framefmt, v4l2_subdev_get_try_format, try_fmt)
-__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, v4l2_subdev_get_try_crop, try_crop)
-__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, v4l2_subdev_get_try_compose, try_compose)
+
+/**
+ * v4l2_subdev_get_try_format - ancillary routine to call
+ * &struct v4l2_subdev_pad_config->try_fmt
+ *
+ * @sd: pointer to &struct v4l2_subdev
+ * @cfg: pointer to &struct v4l2_subdev_pad_config array.
+ * @pad: index of the pad in the @cfg array.
+ */
+static inline struct v4l2_mbus_framefmt
+*v4l2_subdev_get_try_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad)
+{
+ if (WARN_ON(pad >= sd->entity.num_pads))
+ pad = 0;
+ return &cfg[pad].try_fmt;
+}
+
+/**
+ * v4l2_subdev_get_try_crop - ancillary routine to call
+ * &struct v4l2_subdev_pad_config->try_crop
+ *
+ * @sd: pointer to &struct v4l2_subdev
+ * @cfg: pointer to &struct v4l2_subdev_pad_config array.
+ * @pad: index of the pad in the @cfg array.
+ */
+static inline struct v4l2_rect
+*v4l2_subdev_get_try_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad)
+{
+ if (WARN_ON(pad >= sd->entity.num_pads))
+ pad = 0;
+ return &cfg[pad].try_crop;
+}
+
+/**
+ * v4l2_subdev_get_try_crop - ancillary routine to call
+ * &struct v4l2_subdev_pad_config->try_compose
+ *
+ * @sd: pointer to &struct v4l2_subdev
+ * @cfg: pointer to &struct v4l2_subdev_pad_config array.
+ * @pad: index of the pad in the @cfg array.
+ */
+static inline struct v4l2_rect
+*v4l2_subdev_get_try_compose(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad)
+{
+ if (WARN_ON(pad >= sd->entity.num_pads))
+ pad = 0;
+ return &cfg[pad].try_compose;
+}
#endif
extern const struct v4l2_file_operations v4l2_subdev_fops;
@@ -1016,9 +1074,16 @@ void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg);
void v4l2_subdev_init(struct v4l2_subdev *sd,
const struct v4l2_subdev_ops *ops);
-/*
- * Call an ops of a v4l2_subdev, doing the right checks against
- * NULL pointers.
+/**
+ * v4l2_subdev_call - call an operation of a v4l2_subdev.
+ *
+ * @sd: pointer to the &struct v4l2_subdev
+ * @o: name of the element at &struct v4l2_subdev_ops that contains @f.
+ * Each element there groups a set of callbacks functions.
+ * @f: callback function that will be called if @cond matches.
+ * The callback functions are defined in groups, according to
+ * each element at &struct v4l2_subdev_ops.
+ * @args...: arguments for @f.
*
* Example: err = v4l2_subdev_call(sd, video, s_std, norm);
*/
@@ -1034,6 +1099,14 @@ void v4l2_subdev_init(struct v4l2_subdev *sd,
__result; \
})
+/**
+ * v4l2_subdev_has_op - Checks if a subdev defines a certain operation.
+ *
+ * @sd: pointer to the &struct v4l2_subdev
+ * @o: The group of callback functions in &struct v4l2_subdev_ops
+ * which @f is a part of.
+ * @f: callback function to be checked for its existence.
+ */
#define v4l2_subdev_has_op(sd, o, f) \
((sd)->ops->o && (sd)->ops->o->f)
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 5b6c541e4e1b..f6818f732f34 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -296,6 +296,9 @@ struct vb2_buffer {
/**
* struct vb2_ops - driver-specific callbacks.
*
+ * These operations are not called from interrupt context except where
+ * mentioned specifically.
+ *
* @queue_setup: called from VIDIOC_REQBUFS() and VIDIOC_CREATE_BUFS()
* handlers before memory allocation. It can be called
* twice: if the original number of requested buffers
@@ -358,12 +361,12 @@ struct vb2_buffer {
* driver can return an error if hardware fails, in that
* case all buffers that have been already given by
* the @buf_queue callback are to be returned by the driver
- * by calling vb2_buffer_done() with %VB2_BUF_STATE_QUEUED.
- * If you need a minimum number of buffers before you can
- * start streaming, then set
- * &vb2_queue->min_buffers_needed. If that is non-zero then
- * @start_streaming won't be called until at least that
- * many buffers have been queued up by userspace.
+ * by calling vb2_buffer_done() with %VB2_BUF_STATE_QUEUED
+ * or %VB2_BUF_STATE_REQUEUEING. If you need a minimum
+ * number of buffers before you can start streaming, then
+ * set &vb2_queue->min_buffers_needed. If that is non-zero
+ * then @start_streaming won't be called until at least
+ * that many buffers have been queued up by userspace.
* @stop_streaming: called when 'streaming' state must be disabled; driver
* should stop any DMA transactions or wait until they
* finish and give back all buffers it got from &buf_queue
@@ -601,10 +604,9 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no);
* @state: state of the buffer, as defined by &enum vb2_buffer_state.
* Either %VB2_BUF_STATE_DONE if the operation finished
* successfully, %VB2_BUF_STATE_ERROR if the operation finished
- * with an error or %VB2_BUF_STATE_QUEUED if the driver wants to
- * requeue buffers. If start_streaming fails then it should return
- * buffers with state %VB2_BUF_STATE_QUEUED to put them back into
- * the queue.
+ * with an error or any of %VB2_BUF_STATE_QUEUED or
+ * %VB2_BUF_STATE_REQUEUEING if the driver wants to
+ * requeue buffers (see below).
*
* This function should be called by the driver after a hardware operation on
* a buffer is finished and the buffer may be returned to userspace. The driver
@@ -613,9 +615,14 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no);
* to the driver by &vb2_ops->buf_queue can be passed to this function.
*
* While streaming a buffer can only be returned in state DONE or ERROR.
- * The start_streaming op can also return them in case the DMA engine cannot
- * be started for some reason. In that case the buffers should be returned with
- * state QUEUED.
+ * The &vb2_ops->start_streaming op can also return them in case the DMA engine
+ * cannot be started for some reason. In that case the buffers should be
+ * returned with state QUEUED or REQUEUEING to put them back into the queue.
+ *
+ * %VB2_BUF_STATE_REQUEUEING is like %VB2_BUF_STATE_QUEUED, but it also calls
+ * &vb2_ops->buf_queue to queue buffers back to the driver. Note that calling
+ * vb2_buffer_done(..., VB2_BUF_STATE_REQUEUEING) from interrupt context will
+ * result in &vb2_ops->buf_queue being called in interrupt context as well.
*/
void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state);
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 95ccc1eef558..b619a190ff12 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -895,7 +895,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
u16 conn_timeout);
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, u8 sec_level, u16 conn_timeout,
- u8 role);
+ u8 role, bdaddr_t *direct_rpa);
struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
u8 sec_level, u8 auth_type);
struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
diff --git a/include/net/devlink.h b/include/net/devlink.h
index e21d8cadd480..2e4f71e16e95 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -232,14 +232,6 @@ struct devlink_dpipe_headers {
};
/**
- * struct devlink_resource_ops - resource ops
- * @occ_get: get the occupied size
- */
-struct devlink_resource_ops {
- u64 (*occ_get)(struct devlink *devlink);
-};
-
-/**
* struct devlink_resource_size_params - resource's size parameters
* @size_min: minimum size which can be set
* @size_max: maximum size which can be set
@@ -265,6 +257,8 @@ devlink_resource_size_params_init(struct devlink_resource_size_params *size_para
size_params->unit = unit;
}
+typedef u64 devlink_resource_occ_get_t(void *priv);
+
/**
* struct devlink_resource - devlink resource
* @name: name of the resource
@@ -277,7 +271,6 @@ devlink_resource_size_params_init(struct devlink_resource_size_params *size_para
* @size_params: size parameters
* @list: parent list
* @resource_list: list of child resources
- * @resource_ops: resource ops
*/
struct devlink_resource {
const char *name;
@@ -289,7 +282,8 @@ struct devlink_resource {
struct devlink_resource_size_params size_params;
struct list_head list;
struct list_head resource_list;
- const struct devlink_resource_ops *resource_ops;
+ devlink_resource_occ_get_t *occ_get;
+ void *occ_get_priv;
};
#define DEVLINK_RESOURCE_ID_PARENT_TOP 0
@@ -409,8 +403,7 @@ int devlink_resource_register(struct devlink *devlink,
u64 resource_size,
u64 resource_id,
u64 parent_resource_id,
- const struct devlink_resource_size_params *size_params,
- const struct devlink_resource_ops *resource_ops);
+ const struct devlink_resource_size_params *size_params);
void devlink_resources_unregister(struct devlink *devlink,
struct devlink_resource *resource);
int devlink_resource_size_get(struct devlink *devlink,
@@ -419,6 +412,12 @@ int devlink_resource_size_get(struct devlink *devlink,
int devlink_dpipe_table_resource_set(struct devlink *devlink,
const char *table_name, u64 resource_id,
u64 resource_units);
+void devlink_resource_occ_get_register(struct devlink *devlink,
+ u64 resource_id,
+ devlink_resource_occ_get_t *occ_get,
+ void *occ_get_priv);
+void devlink_resource_occ_get_unregister(struct devlink *devlink,
+ u64 resource_id);
#else
@@ -562,8 +561,7 @@ devlink_resource_register(struct devlink *devlink,
u64 resource_size,
u64 resource_id,
u64 parent_resource_id,
- const struct devlink_resource_size_params *size_params,
- const struct devlink_resource_ops *resource_ops)
+ const struct devlink_resource_size_params *size_params)
{
return 0;
}
@@ -589,6 +587,20 @@ devlink_dpipe_table_resource_set(struct devlink *devlink,
return -EOPNOTSUPP;
}
+static inline void
+devlink_resource_occ_get_register(struct devlink *devlink,
+ u64 resource_id,
+ devlink_resource_occ_get_t *occ_get,
+ void *occ_get_priv)
+{
+}
+
+static inline void
+devlink_resource_occ_get_unregister(struct devlink *devlink,
+ u64 resource_id)
+{
+}
+
#endif
#endif /* _NET_DEVLINK_H_ */
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index 899495589a7e..c7be1ca8e562 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -43,6 +43,7 @@ struct inet_timewait_sock {
#define tw_family __tw_common.skc_family
#define tw_state __tw_common.skc_state
#define tw_reuse __tw_common.skc_reuse
+#define tw_reuseport __tw_common.skc_reuseport
#define tw_ipv6only __tw_common.skc_ipv6only
#define tw_bound_dev_if __tw_common.skc_bound_dev_if
#define tw_node __tw_common.skc_nulls_node
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 0084013d6bed..08b132381984 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -214,6 +214,9 @@ static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
#endif
}
+void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst,
+ const struct flowi6 *fl6);
+
static inline bool ipv6_unicast_destination(const struct sk_buff *skb)
{
struct rt6_info *rt = (struct rt6_info *) skb_dst(skb);
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 9b6e7f51b1d4..836f31af1369 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -965,7 +965,8 @@ int ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst,
struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 *fl6,
const struct in6_addr *final_dst);
struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
- const struct in6_addr *final_dst);
+ const struct in6_addr *final_dst,
+ bool connected);
struct dst_entry *ip6_blackhole_route(struct net *net,
struct dst_entry *orig_dst);
diff --git a/include/net/nexthop.h b/include/net/nexthop.h
index 36bb794f5cd6..902ff382a6dc 100644
--- a/include/net/nexthop.h
+++ b/include/net/nexthop.h
@@ -7,7 +7,7 @@
static inline int rtnh_ok(const struct rtnexthop *rtnh, int remaining)
{
- return remaining >= sizeof(*rtnh) &&
+ return remaining >= (int)sizeof(*rtnh) &&
rtnh->rtnh_len >= sizeof(*rtnh) &&
rtnh->rtnh_len <= remaining;
}
diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h
index c3ac5ec86519..965c650a5273 100644
--- a/include/trace/events/btrfs.h
+++ b/include/trace/events/btrfs.h
@@ -71,6 +71,12 @@ TRACE_DEFINE_ENUM(COMMIT_TRANS);
{ BTRFS_FILE_EXTENT_REG, "REG" }, \
{ BTRFS_FILE_EXTENT_PREALLOC, "PREALLOC"})
+#define show_qgroup_rsv_type(type) \
+ __print_symbolic(type, \
+ { BTRFS_QGROUP_RSV_DATA, "DATA" }, \
+ { BTRFS_QGROUP_RSV_META_PERTRANS, "META_PERTRANS" }, \
+ { BTRFS_QGROUP_RSV_META_PREALLOC, "META_PREALLOC" })
+
#define BTRFS_GROUP_FLAGS \
{ BTRFS_BLOCK_GROUP_DATA, "DATA"}, \
{ BTRFS_BLOCK_GROUP_SYSTEM, "SYSTEM"}, \
@@ -248,6 +254,41 @@ TRACE_EVENT_CONDITION(btrfs_get_extent,
__entry->refs, __entry->compress_type)
);
+TRACE_EVENT(btrfs_handle_em_exist,
+
+ TP_PROTO(const struct extent_map *existing, const struct extent_map *map, u64 start, u64 len),
+
+ TP_ARGS(existing, map, start, len),
+
+ TP_STRUCT__entry(
+ __field( u64, e_start )
+ __field( u64, e_len )
+ __field( u64, map_start )
+ __field( u64, map_len )
+ __field( u64, start )
+ __field( u64, len )
+ ),
+
+ TP_fast_assign(
+ __entry->e_start = existing->start;
+ __entry->e_len = existing->len;
+ __entry->map_start = map->start;
+ __entry->map_len = map->len;
+ __entry->start = start;
+ __entry->len = len;
+ ),
+
+ TP_printk("start=%llu len=%llu "
+ "existing(start=%llu len=%llu) "
+ "em(start=%llu len=%llu)",
+ (unsigned long long)__entry->start,
+ (unsigned long long)__entry->len,
+ (unsigned long long)__entry->e_start,
+ (unsigned long long)__entry->e_len,
+ (unsigned long long)__entry->map_start,
+ (unsigned long long)__entry->map_len)
+);
+
/* file extent item */
DECLARE_EVENT_CLASS(btrfs__file_extent_item_regular,
@@ -1598,28 +1639,52 @@ TRACE_EVENT(qgroup_update_counters,
TRACE_EVENT(qgroup_update_reserve,
TP_PROTO(struct btrfs_fs_info *fs_info, struct btrfs_qgroup *qgroup,
- s64 diff),
+ s64 diff, int type),
- TP_ARGS(fs_info, qgroup, diff),
+ TP_ARGS(fs_info, qgroup, diff, type),
TP_STRUCT__entry_btrfs(
__field( u64, qgid )
__field( u64, cur_reserved )
__field( s64, diff )
+ __field( int, type )
),
TP_fast_assign_btrfs(fs_info,
__entry->qgid = qgroup->qgroupid;
- __entry->cur_reserved = qgroup->reserved;
+ __entry->cur_reserved = qgroup->rsv.values[type];
__entry->diff = diff;
),
- TP_printk_btrfs("qgid=%llu cur_reserved=%llu diff=%lld",
- __entry->qgid, __entry->cur_reserved, __entry->diff)
+ TP_printk_btrfs("qgid=%llu type=%s cur_reserved=%llu diff=%lld",
+ __entry->qgid, show_qgroup_rsv_type(__entry->type),
+ __entry->cur_reserved, __entry->diff)
);
TRACE_EVENT(qgroup_meta_reserve,
+ TP_PROTO(struct btrfs_root *root, s64 diff, int type),
+
+ TP_ARGS(root, diff, type),
+
+ TP_STRUCT__entry_btrfs(
+ __field( u64, refroot )
+ __field( s64, diff )
+ __field( int, type )
+ ),
+
+ TP_fast_assign_btrfs(root->fs_info,
+ __entry->refroot = root->objectid;
+ __entry->diff = diff;
+ ),
+
+ TP_printk_btrfs("refroot=%llu(%s) type=%s diff=%lld",
+ show_root_type(__entry->refroot),
+ show_qgroup_rsv_type(__entry->type), __entry->diff)
+);
+
+TRACE_EVENT(qgroup_meta_convert,
+
TP_PROTO(struct btrfs_root *root, s64 diff),
TP_ARGS(root, diff),
@@ -1627,6 +1692,7 @@ TRACE_EVENT(qgroup_meta_reserve,
TP_STRUCT__entry_btrfs(
__field( u64, refroot )
__field( s64, diff )
+ __field( int, type )
),
TP_fast_assign_btrfs(root->fs_info,
@@ -1634,8 +1700,36 @@ TRACE_EVENT(qgroup_meta_reserve,
__entry->diff = diff;
),
- TP_printk_btrfs("refroot=%llu(%s) diff=%lld",
- show_root_type(__entry->refroot), __entry->diff)
+ TP_printk_btrfs("refroot=%llu(%s) type=%s->%s diff=%lld",
+ show_root_type(__entry->refroot),
+ show_qgroup_rsv_type(BTRFS_QGROUP_RSV_META_PREALLOC),
+ show_qgroup_rsv_type(BTRFS_QGROUP_RSV_META_PERTRANS),
+ __entry->diff)
+);
+
+TRACE_EVENT(qgroup_meta_free_all_pertrans,
+
+ TP_PROTO(struct btrfs_root *root),
+
+ TP_ARGS(root),
+
+ TP_STRUCT__entry_btrfs(
+ __field( u64, refroot )
+ __field( s64, diff )
+ __field( int, type )
+ ),
+
+ TP_fast_assign_btrfs(root->fs_info,
+ __entry->refroot = root->objectid;
+ spin_lock(&root->qgroup_meta_rsv_lock);
+ __entry->diff = -(s64)root->qgroup_meta_rsv_pertrans;
+ spin_unlock(&root->qgroup_meta_rsv_lock);
+ __entry->type = BTRFS_QGROUP_RSV_META_PERTRANS;
+ ),
+
+ TP_printk_btrfs("refroot=%llu(%s) type=%s diff=%lld",
+ show_root_type(__entry->refroot),
+ show_qgroup_rsv_type(__entry->type), __entry->diff)
);
DECLARE_EVENT_CLASS(btrfs__prelim_ref,
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
index 4d0e3af4e561..0e31eb136c57 100644
--- a/include/trace/events/ext4.h
+++ b/include/trace/events/ext4.h
@@ -2585,6 +2585,49 @@ DEFINE_GETFSMAP_EVENT(ext4_getfsmap_low_key);
DEFINE_GETFSMAP_EVENT(ext4_getfsmap_high_key);
DEFINE_GETFSMAP_EVENT(ext4_getfsmap_mapping);
+TRACE_EVENT(ext4_shutdown,
+ TP_PROTO(struct super_block *sb, unsigned long flags),
+
+ TP_ARGS(sb, flags),
+
+ TP_STRUCT__entry(
+ __field( dev_t, dev )
+ __field( unsigned, flags )
+ ),
+
+ TP_fast_assign(
+ __entry->dev = sb->s_dev;
+ __entry->flags = flags;
+ ),
+
+ TP_printk("dev %d,%d flags %u",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->flags)
+);
+
+TRACE_EVENT(ext4_error,
+ TP_PROTO(struct super_block *sb, const char *function,
+ unsigned int line),
+
+ TP_ARGS(sb, function, line),
+
+ TP_STRUCT__entry(
+ __field( dev_t, dev )
+ __field( const char *, function )
+ __field( unsigned, line )
+ ),
+
+ TP_fast_assign(
+ __entry->dev = sb->s_dev;
+ __entry->function = function;
+ __entry->line = line;
+ ),
+
+ TP_printk("dev %d,%d function %s line %u",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->function, __entry->line)
+);
+
#endif /* _TRACE_EXT4_H */
/* This part must be outside protection */
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index 73ae06b67051..6088bca89917 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -207,7 +207,8 @@ typedef struct siginfo {
#define __FPE_DECERR 11 /* packed decimal error */
#define __FPE_INVASC 12 /* invalid ASCII digit */
#define __FPE_INVDEC 13 /* invalid decimal digit */
-#define NSIGFPE 13
+#define FPE_FLTUNK 14 /* undiagnosed floating-point exception */
+#define NSIGFPE 14
/*
* SIGSEGV si_codes
diff --git a/include/uapi/linux/cec-funcs.h b/include/uapi/linux/cec-funcs.h
index 28e8a2a86e16..8997d5068c08 100644
--- a/include/uapi/linux/cec-funcs.h
+++ b/include/uapi/linux/cec-funcs.h
@@ -3,35 +3,6 @@
* cec - HDMI Consumer Electronics Control message functions
*
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * Alternatively you can redistribute this file under the terms of the
- * BSD license as stated below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. The names of its contributors may not be used to endorse or promote
- * products derived from this software without specific prior written
- * permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _CEC_UAPI_FUNCS_H
diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h
index b51fbe1941a7..20fe091b7e96 100644
--- a/include/uapi/linux/cec.h
+++ b/include/uapi/linux/cec.h
@@ -3,35 +3,6 @@
* cec - HDMI Consumer Electronics Control public header
*
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * Alternatively you can redistribute this file under the terms of the
- * BSD license as stated below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. The names of its contributors may not be used to endorse or promote
- * products derived from this software without specific prior written
- * permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef _CEC_UAPI_H
diff --git a/include/uapi/linux/irda.h b/include/uapi/linux/irda.h
deleted file mode 100644
index 2105c266aa6e..000000000000
--- a/include/uapi/linux/irda.h
+++ /dev/null
@@ -1,252 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
-/*********************************************************************
- *
- * Filename: irda.h
- * Version:
- * Description:
- * Status: Experimental.
- * Author: Dag Brattli <dagb@cs.uit.no>
- * Created at: Mon Mar 8 14:06:12 1999
- * Modified at: Sat Dec 25 16:06:42 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
- *
- * Copyright (c) 1999 Dag Brattli, 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.
- *
- * Neither Dag Brattli nor University of Tromsø admit liability nor
- * provide warranty for any of this software. This material is
- * provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#ifndef KERNEL_IRDA_H
-#define KERNEL_IRDA_H
-
-#include <linux/types.h>
-#include <linux/socket.h>
-
-/* Note that this file is shared with user space. */
-
-/* Hint bit positions for first hint byte */
-#define HINT_PNP 0x01
-#define HINT_PDA 0x02
-#define HINT_COMPUTER 0x04
-#define HINT_PRINTER 0x08
-#define HINT_MODEM 0x10
-#define HINT_FAX 0x20
-#define HINT_LAN 0x40
-#define HINT_EXTENSION 0x80
-
-/* Hint bit positions for second hint byte (first extension byte) */
-#define HINT_TELEPHONY 0x01
-#define HINT_FILE_SERVER 0x02
-#define HINT_COMM 0x04
-#define HINT_MESSAGE 0x08
-#define HINT_HTTP 0x10
-#define HINT_OBEX 0x20
-
-/* IrLMP character code values */
-#define CS_ASCII 0x00
-#define CS_ISO_8859_1 0x01
-#define CS_ISO_8859_2 0x02
-#define CS_ISO_8859_3 0x03
-#define CS_ISO_8859_4 0x04
-#define CS_ISO_8859_5 0x05
-#define CS_ISO_8859_6 0x06
-#define CS_ISO_8859_7 0x07
-#define CS_ISO_8859_8 0x08
-#define CS_ISO_8859_9 0x09
-#define CS_UNICODE 0xff
-
-/* These are the currently known dongles */
-typedef enum {
- IRDA_TEKRAM_DONGLE = 0,
- IRDA_ESI_DONGLE = 1,
- IRDA_ACTISYS_DONGLE = 2,
- IRDA_ACTISYS_PLUS_DONGLE = 3,
- IRDA_GIRBIL_DONGLE = 4,
- IRDA_LITELINK_DONGLE = 5,
- IRDA_AIRPORT_DONGLE = 6,
- IRDA_OLD_BELKIN_DONGLE = 7,
- IRDA_EP7211_IR = 8,
- IRDA_MCP2120_DONGLE = 9,
- IRDA_ACT200L_DONGLE = 10,
- IRDA_MA600_DONGLE = 11,
- IRDA_TOIM3232_DONGLE = 12,
- IRDA_EP7211_DONGLE = 13,
-} IRDA_DONGLE;
-
-/* Protocol types to be used for SOCK_DGRAM */
-enum {
- IRDAPROTO_UNITDATA = 0,
- IRDAPROTO_ULTRA = 1,
- IRDAPROTO_MAX
-};
-
-#define SOL_IRLMP 266 /* Same as SOL_IRDA for now */
-#define SOL_IRTTP 266 /* Same as SOL_IRDA for now */
-
-#define IRLMP_ENUMDEVICES 1 /* Return discovery log */
-#define IRLMP_IAS_SET 2 /* Set an attribute in local IAS */
-#define IRLMP_IAS_QUERY 3 /* Query remote IAS for attribute */
-#define IRLMP_HINTS_SET 4 /* Set hint bits advertised */
-#define IRLMP_QOS_SET 5
-#define IRLMP_QOS_GET 6
-#define IRLMP_MAX_SDU_SIZE 7
-#define IRLMP_IAS_GET 8 /* Get an attribute from local IAS */
-#define IRLMP_IAS_DEL 9 /* Remove attribute from local IAS */
-#define IRLMP_HINT_MASK_SET 10 /* Set discovery filter */
-#define IRLMP_WAITDEVICE 11 /* Wait for a new discovery */
-
-#define IRTTP_MAX_SDU_SIZE IRLMP_MAX_SDU_SIZE /* Compatibility */
-
-#define IAS_MAX_STRING 256 /* See IrLMP 1.1, 4.3.3.2 */
-#define IAS_MAX_OCTET_STRING 1024 /* See IrLMP 1.1, 4.3.3.2 */
-#define IAS_MAX_CLASSNAME 60 /* See IrLMP 1.1, 4.3.1 */
-#define IAS_MAX_ATTRIBNAME 60 /* See IrLMP 1.1, 4.3.3.1 */
-#define IAS_MAX_ATTRIBNUMBER 256 /* See IrLMP 1.1, 4.3.3.1 */
-/* For user space backward compatibility - may be fixed in kernel 2.5.X
- * Note : need 60+1 ('\0'), make it 64 for alignement - Jean II */
-#define IAS_EXPORT_CLASSNAME 64
-#define IAS_EXPORT_ATTRIBNAME 256
-
-/* Attribute type needed for struct irda_ias_set */
-#define IAS_MISSING 0
-#define IAS_INTEGER 1
-#define IAS_OCT_SEQ 2
-#define IAS_STRING 3
-
-#define LSAP_ANY 0xff
-
-struct sockaddr_irda {
- __kernel_sa_family_t sir_family; /* AF_IRDA */
- __u8 sir_lsap_sel; /* LSAP selector */
- __u32 sir_addr; /* Device address */
- char sir_name[25]; /* Usually <service>:IrDA:TinyTP */
-};
-
-struct irda_device_info {
- __u32 saddr; /* Address of local interface */
- __u32 daddr; /* Address of remote device */
- char info[22]; /* Description */
- __u8 charset; /* Charset used for description */
- __u8 hints[2]; /* Hint bits */
-};
-
-struct irda_device_list {
- __u32 len;
- struct irda_device_info dev[1];
-};
-
-struct irda_ias_set {
- char irda_class_name[IAS_EXPORT_CLASSNAME];
- char irda_attrib_name[IAS_EXPORT_ATTRIBNAME];
- unsigned int irda_attrib_type;
- union {
- unsigned int irda_attrib_int;
- struct {
- unsigned short len;
- __u8 octet_seq[IAS_MAX_OCTET_STRING];
- } irda_attrib_octet_seq;
- struct {
- __u8 len;
- __u8 charset;
- __u8 string[IAS_MAX_STRING];
- } irda_attrib_string;
- } attribute;
- __u32 daddr; /* Address of device (for some queries only) */
-};
-
-/* Some private IOCTL's (max 16) */
-#define SIOCSDONGLE (SIOCDEVPRIVATE + 0)
-#define SIOCGDONGLE (SIOCDEVPRIVATE + 1)
-#define SIOCSBANDWIDTH (SIOCDEVPRIVATE + 2)
-#define SIOCSMEDIABUSY (SIOCDEVPRIVATE + 3)
-#define SIOCGMEDIABUSY (SIOCDEVPRIVATE + 4)
-#define SIOCGRECEIVING (SIOCDEVPRIVATE + 5)
-#define SIOCSMODE (SIOCDEVPRIVATE + 6)
-#define SIOCGMODE (SIOCDEVPRIVATE + 7)
-#define SIOCSDTRRTS (SIOCDEVPRIVATE + 8)
-#define SIOCGQOS (SIOCDEVPRIVATE + 9)
-
-/* No reason to include <linux/if.h> just because of this one ;-) */
-#define IRNAMSIZ 16
-
-/* IrDA quality of service information (must not exceed 16 bytes) */
-struct if_irda_qos {
- unsigned long baudrate;
- unsigned short data_size;
- unsigned short window_size;
- unsigned short min_turn_time;
- unsigned short max_turn_time;
- unsigned char add_bofs;
- unsigned char link_disc;
-};
-
-/* For setting RTS and DTR lines of a dongle */
-struct if_irda_line {
- __u8 dtr;
- __u8 rts;
-};
-
-/* IrDA interface configuration (data part must not exceed 16 bytes) */
-struct if_irda_req {
- union {
- char ifrn_name[IRNAMSIZ]; /* if name, e.g. "irda0" */
- } ifr_ifrn;
-
- /* Data part */
- union {
- struct if_irda_line ifru_line;
- struct if_irda_qos ifru_qos;
- unsigned short ifru_flags;
- unsigned int ifru_receiving;
- unsigned int ifru_mode;
- unsigned int ifru_dongle;
- } ifr_ifru;
-};
-
-#define ifr_baudrate ifr_ifru.ifru_qos.baudrate
-#define ifr_receiving ifr_ifru.ifru_receiving
-#define ifr_dongle ifr_ifru.ifru_dongle
-#define ifr_mode ifr_ifru.ifru_mode
-#define ifr_dtr ifr_ifru.ifru_line.dtr
-#define ifr_rts ifr_ifru.ifru_line.rts
-
-
-/* IrDA netlink definitions */
-#define IRDA_NL_NAME "irda"
-#define IRDA_NL_VERSION 1
-
-enum irda_nl_commands {
- IRDA_NL_CMD_UNSPEC,
- IRDA_NL_CMD_SET_MODE,
- IRDA_NL_CMD_GET_MODE,
-
- __IRDA_NL_CMD_AFTER_LAST
-};
-#define IRDA_NL_CMD_MAX (__IRDA_NL_CMD_AFTER_LAST - 1)
-
-enum nl80211_attrs {
- IRDA_NL_ATTR_UNSPEC,
- IRDA_NL_ATTR_IFNAME,
- IRDA_NL_ATTR_MODE,
-
- __IRDA_NL_ATTR_AFTER_LAST
-};
-#define IRDA_NL_ATTR_MAX (__IRDA_NL_ATTR_AFTER_LAST - 1)
-
-/* IrDA modes */
-#define IRDA_MODE_PRIMARY 0x1
-#define IRDA_MODE_SECONDARY 0x2
-#define IRDA_MODE_MONITOR 0x4
-
-#endif /* KERNEL_IRDA_H */
-
-
-
-
diff --git a/include/uapi/linux/ixjuser.h b/include/uapi/linux/ixjuser.h
deleted file mode 100644
index ba245007cfe7..000000000000
--- a/include/uapi/linux/ixjuser.h
+++ /dev/null
@@ -1,721 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
-#ifndef __LINUX_IXJUSER_H
-#define __LINUX_IXJUSER_H
-
-/******************************************************************************
- *
- * ixjuser.h
- *
- * Device Driver for Quicknet Technologies, Inc.'s Telephony cards
- * including the Internet PhoneJACK, Internet PhoneJACK Lite,
- * Internet PhoneJACK PCI, Internet LineJACK, Internet PhoneCARD and
- * SmartCABLE
- *
- * (c) Copyright 1999-2001 Quicknet Technologies, 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.
- *
- * Author: Ed Okerson, <eokerson@quicknet.net>
- *
- * Contributors: Greg Herlein, <gherlein@quicknet.net>
- * David W. Erhart, <derhart@quicknet.net>
- * John Sellers, <jsellers@quicknet.net>
- * Mike Preston, <mpreston@quicknet.net>
- *
- * More information about the hardware related to this driver can be found
- * at our website: http://www.quicknet.net
- *
- * Fixes:
- *
- * IN NO EVENT SHALL QUICKNET TECHNOLOGIES, INC. BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
- * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF QUICKNET
- * TECHNOLOGIES, INC.HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * QUICKNET TECHNOLOGIES, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND QUICKNET TECHNOLOGIES, INC. HAS NO OBLIGATION
- * TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- *****************************************************************************/
-
-#include <linux/telephony.h>
-
-
-/******************************************************************************
-*
-* IOCTL's used for the Quicknet Telephony Cards
-*
-* If you use the IXJCTL_TESTRAM command, the card must be power cycled to
-* reset the SRAM values before further use.
-*
-******************************************************************************/
-
-#define IXJCTL_DSP_RESET _IO ('q', 0xC0)
-
-#define IXJCTL_RING PHONE_RING
-#define IXJCTL_HOOKSTATE PHONE_HOOKSTATE
-#define IXJCTL_MAXRINGS PHONE_MAXRINGS
-#define IXJCTL_RING_CADENCE PHONE_RING_CADENCE
-#define IXJCTL_RING_START PHONE_RING_START
-#define IXJCTL_RING_STOP PHONE_RING_STOP
-
-#define IXJCTL_CARDTYPE _IOR ('q', 0xC1, int)
-#define IXJCTL_SERIAL _IOR ('q', 0xC2, int)
-#define IXJCTL_DSP_TYPE _IOR ('q', 0xC3, int)
-#define IXJCTL_DSP_VERSION _IOR ('q', 0xC4, int)
-#define IXJCTL_VERSION _IOR ('q', 0xDA, char *)
-#define IXJCTL_DSP_IDLE _IO ('q', 0xC5)
-#define IXJCTL_TESTRAM _IO ('q', 0xC6)
-
-/******************************************************************************
-*
-* This group of IOCTLs deal with the record settings of the DSP
-*
-* The IXJCTL_REC_DEPTH command sets the internal buffer depth of the DSP.
-* Setting a lower depth reduces latency, but increases the demand of the
-* application to service the driver without frame loss. The DSP has 480
-* bytes of physical buffer memory for the record channel so the true
-* maximum limit is determined by how many frames will fit in the buffer.
-*
-* 1 uncompressed (480 byte) 16-bit linear frame.
-* 2 uncompressed (240 byte) 8-bit A-law/mu-law frames.
-* 15 TrueSpeech 8.5 frames.
-* 20 TrueSpeech 6.3,5.3,4.8 or 4.1 frames.
-*
-* The default in the driver is currently set to 2 frames.
-*
-* The IXJCTL_REC_VOLUME and IXJCTL_PLAY_VOLUME commands both use a Q8
-* number as a parameter, 0x100 scales the signal by 1.0, 0x200 scales the
-* signal by 2.0, 0x80 scales the signal by 0.5. No protection is given
-* against over-scaling, if the multiplication factor times the input
-* signal exceeds 16 bits, overflow distortion will occur. The default
-* setting is 0x100 (1.0).
-*
-* The IXJCTL_REC_LEVEL returns the average signal level (not r.m.s.) on
-* the most recently recorded frame as a 16 bit value.
-******************************************************************************/
-
-#define IXJCTL_REC_CODEC PHONE_REC_CODEC
-#define IXJCTL_REC_START PHONE_REC_START
-#define IXJCTL_REC_STOP PHONE_REC_STOP
-#define IXJCTL_REC_DEPTH PHONE_REC_DEPTH
-#define IXJCTL_FRAME PHONE_FRAME
-#define IXJCTL_REC_VOLUME PHONE_REC_VOLUME
-#define IXJCTL_REC_LEVEL PHONE_REC_LEVEL
-
-typedef enum {
- f300_640 = 4, f300_500, f1100, f350, f400, f480, f440, f620, f20_50,
- f133_200, f300, f300_420, f330, f300_425, f330_440, f340, f350_400,
- f350_440, f350_450, f360, f380_420, f392, f400_425, f400_440, f400_450,
- f420, f425, f425_450, f425_475, f435, f440_450, f440_480, f445, f450,
- f452, f475, f480_620, f494, f500, f520, f523, f525, f540_660, f587,
- f590, f600, f660, f700, f740, f750, f750_1450, f770, f800, f816, f850,
- f857_1645, f900, f900_1300, f935_1215, f941_1477, f942, f950, f950_1400,
- f975, f1000, f1020, f1050, f1100_1750, f1140, f1200, f1209, f1330, f1336,
- lf1366, f1380, f1400, f1477, f1600, f1633_1638, f1800, f1860
-} IXJ_FILTER_FREQ;
-
-typedef struct {
- unsigned int filter;
- IXJ_FILTER_FREQ freq;
- char enable;
-} IXJ_FILTER;
-
-typedef struct {
- char enable;
- char en_filter;
- unsigned int filter;
- unsigned int on1;
- unsigned int off1;
- unsigned int on2;
- unsigned int off2;
- unsigned int on3;
- unsigned int off3;
-} IXJ_FILTER_CADENCE;
-
-#define IXJCTL_SET_FILTER _IOW ('q', 0xC7, IXJ_FILTER *)
-#define IXJCTL_SET_FILTER_RAW _IOW ('q', 0xDD, IXJ_FILTER_RAW *)
-#define IXJCTL_GET_FILTER_HIST _IOW ('q', 0xC8, int)
-#define IXJCTL_FILTER_CADENCE _IOW ('q', 0xD6, IXJ_FILTER_CADENCE *)
-#define IXJCTL_PLAY_CID _IO ('q', 0xD7)
-/******************************************************************************
-*
-* This IOCTL allows you to reassign values in the tone index table. The
-* tone table has 32 entries (0 - 31), but the driver only allows entries
-* 13 - 27 to be modified, entry 0 is reserved for silence and 1 - 12 are
-* the standard DTMF digits and 28 - 31 are the DTMF tones for A, B, C & D.
-* The positions used internally for Call Progress Tones are as follows:
-* Dial Tone - 25
-* Ring Back - 26
-* Busy Signal - 27
-*
-* The freq values are calculated as:
-* freq = cos(2 * PI * frequency / 8000)
-*
-* The most commonly needed values are already calculated and listed in the
-* enum IXJ_TONE_FREQ. Each tone index can have two frequencies with
-* different gains, if you are only using a single frequency set the unused
-* one to 0.
-*
-* The gain values range from 0 to 15 indicating +6dB to -24dB in 2dB
-* increments.
-*
-******************************************************************************/
-
-typedef enum {
- hz20 = 0x7ffa,
- hz50 = 0x7fe5,
- hz133 = 0x7f4c,
- hz200 = 0x7e6b,
- hz261 = 0x7d50, /* .63 C1 */
- hz277 = 0x7cfa, /* .18 CS1 */
- hz293 = 0x7c9f, /* .66 D1 */
- hz300 = 0x7c75,
- hz311 = 0x7c32, /* .13 DS1 */
- hz329 = 0x7bbf, /* .63 E1 */
- hz330 = 0x7bb8,
- hz340 = 0x7b75,
- hz349 = 0x7b37, /* .23 F1 */
- hz350 = 0x7b30,
- hz360 = 0x7ae9,
- hz369 = 0x7aa8, /* .99 FS1 */
- hz380 = 0x7a56,
- hz392 = 0x79fa, /* .00 G1 */
- hz400 = 0x79bb,
- hz415 = 0x7941, /* .30 GS1 */
- hz420 = 0x7918,
- hz425 = 0x78ee,
- hz435 = 0x7899,
- hz440 = 0x786d, /* .00 A1 */
- hz445 = 0x7842,
- hz450 = 0x7815,
- hz452 = 0x7803,
- hz466 = 0x7784, /* .16 AS1 */
- hz475 = 0x7731,
- hz480 = 0x7701,
- hz493 = 0x7685, /* .88 B1 */
- hz494 = 0x767b,
- hz500 = 0x7640,
- hz520 = 0x7578,
- hz523 = 0x7559, /* .25 C2 */
- hz525 = 0x7544,
- hz540 = 0x74a7,
- hz554 = 0x7411, /* .37 CS2 */
- hz587 = 0x72a1, /* .33 D2 */
- hz590 = 0x727f,
- hz600 = 0x720b,
- hz620 = 0x711e,
- hz622 = 0x7106, /* .25 DS2 */
- hz659 = 0x6f3b, /* .26 E2 */
- hz660 = 0x6f2e,
- hz698 = 0x6d3d, /* .46 F2 */
- hz700 = 0x6d22,
- hz739 = 0x6b09, /* .99 FS2 */
- hz740 = 0x6afa,
- hz750 = 0x6a6c,
- hz770 = 0x694b,
- hz783 = 0x688b, /* .99 G2 */
- hz800 = 0x678d,
- hz816 = 0x6698,
- hz830 = 0x65bf, /* .61 GS2 */
- hz850 = 0x6484,
- hz857 = 0x6414,
- hz880 = 0x629f, /* .00 A2 */
- hz900 = 0x6154,
- hz932 = 0x5f35, /* .33 AS2 */
- hz935 = 0x5f01,
- hz941 = 0x5e9a,
- hz942 = 0x5e88,
- hz950 = 0x5dfd,
- hz975 = 0x5c44,
- hz1000 = 0x5a81,
- hz1020 = 0x5912,
- hz1050 = 0x56e2,
- hz1100 = 0x5320,
- hz1140 = 0x5007,
- hz1200 = 0x4b3b,
- hz1209 = 0x4a80,
- hz1215 = 0x4a02,
- hz1250 = 0x471c,
- hz1300 = 0x42e0,
- hz1330 = 0x4049,
- hz1336 = 0x3fc4,
- hz1366 = 0x3d22,
- hz1380 = 0x3be4,
- hz1400 = 0x3a1b,
- hz1450 = 0x3596,
- hz1477 = 0x331c,
- hz1500 = 0x30fb,
- hz1600 = 0x278d,
- hz1633 = 0x2462,
- hz1638 = 0x23e7,
- hz1645 = 0x233a,
- hz1750 = 0x18f8,
- hz1800 = 0x1405,
- hz1860 = 0xe0b,
- hz2100 = 0xf5f6,
- hz2130 = 0xf2f5,
- hz2450 = 0xd3b3,
- hz2750 = 0xb8e4
-} IXJ_FREQ;
-
-typedef enum {
- C1 = hz261,
- CS1 = hz277,
- D1 = hz293,
- DS1 = hz311,
- E1 = hz329,
- F1 = hz349,
- FS1 = hz369,
- G1 = hz392,
- GS1 = hz415,
- A1 = hz440,
- AS1 = hz466,
- B1 = hz493,
- C2 = hz523,
- CS2 = hz554,
- D2 = hz587,
- DS2 = hz622,
- E2 = hz659,
- F2 = hz698,
- FS2 = hz739,
- G2 = hz783,
- GS2 = hz830,
- A2 = hz880,
- AS2 = hz932,
-} IXJ_NOTE;
-
-typedef struct {
- int tone_index;
- int freq0;
- int gain0;
- int freq1;
- int gain1;
-} IXJ_TONE;
-
-#define IXJCTL_INIT_TONE _IOW ('q', 0xC9, IXJ_TONE *)
-
-/******************************************************************************
-*
-* The IXJCTL_TONE_CADENCE ioctl defines tone sequences used for various
-* Call Progress Tones (CPT). This is accomplished by setting up an array of
-* IXJ_CADENCE_ELEMENT structures that sequentially define the states of
-* the tone sequence. The tone_on_time and tone_off time are in
-* 250 microsecond intervals. A pointer to this array is passed to the
-* driver as the ce element of an IXJ_CADENCE structure. The elements_used
-* must be set to the number of IXJ_CADENCE_ELEMENTS in the array. The
-* termination variable defines what to do at the end of a cadence, the
-* options are to play the cadence once and stop, to repeat the last
-* element of the cadence indefinitely, or to repeat the entire cadence
-* indefinitely. The ce variable is a pointer to the array of IXJ_TONE
-* structures. If the freq0 variable is non-zero, the tone table contents
-* for the tone_index are updated to the frequencies and gains defined. It
-* should be noted that DTMF tones cannot be reassigned, so if DTMF tone
-* table indexes are used in a cadence the frequency and gain variables will
-* be ignored.
-*
-* If the array elements contain frequency parameters the driver will
-* initialize the needed tone table elements and begin playing the tone,
-* there is no preset limit on the number of elements in the cadence. If
-* there is more than one frequency used in the cadence, sequential elements
-* of different frequencies MUST use different tone table indexes. Only one
-* cadence can be played at a time. It is possible to build complex
-* cadences with multiple frequencies using 2 tone table indexes by
-* alternating between them.
-*
-******************************************************************************/
-
-typedef struct {
- int index;
- int tone_on_time;
- int tone_off_time;
- int freq0;
- int gain0;
- int freq1;
- int gain1;
-} IXJ_CADENCE_ELEMENT;
-
-typedef enum {
- PLAY_ONCE,
- REPEAT_LAST_ELEMENT,
- REPEAT_ALL
-} IXJ_CADENCE_TERM;
-
-typedef struct {
- int elements_used;
- IXJ_CADENCE_TERM termination;
- IXJ_CADENCE_ELEMENT __user *ce;
-} IXJ_CADENCE;
-
-#define IXJCTL_TONE_CADENCE _IOW ('q', 0xCA, IXJ_CADENCE *)
-/******************************************************************************
-*
-* This group of IOCTLs deal with the playback settings of the DSP
-*
-******************************************************************************/
-
-#define IXJCTL_PLAY_CODEC PHONE_PLAY_CODEC
-#define IXJCTL_PLAY_START PHONE_PLAY_START
-#define IXJCTL_PLAY_STOP PHONE_PLAY_STOP
-#define IXJCTL_PLAY_DEPTH PHONE_PLAY_DEPTH
-#define IXJCTL_PLAY_VOLUME PHONE_PLAY_VOLUME
-#define IXJCTL_PLAY_LEVEL PHONE_PLAY_LEVEL
-
-/******************************************************************************
-*
-* This group of IOCTLs deal with the Acoustic Echo Cancellation settings
-* of the DSP
-*
-* Issuing the IXJCTL_AEC_START command with a value of AEC_OFF has the
-* same effect as IXJCTL_AEC_STOP. This is to simplify slider bar
-* controls. IXJCTL_AEC_GET_LEVEL returns the current setting of the AEC.
-******************************************************************************/
-#define IXJCTL_AEC_START _IOW ('q', 0xCB, int)
-#define IXJCTL_AEC_STOP _IO ('q', 0xCC)
-#define IXJCTL_AEC_GET_LEVEL _IO ('q', 0xCD)
-
-#define AEC_OFF 0
-#define AEC_LOW 1
-#define AEC_MED 2
-#define AEC_HIGH 3
-#define AEC_AUTO 4
-#define AEC_AGC 5
-/******************************************************************************
-*
-* Call Progress Tones, DTMF, etc.
-* IXJCTL_DTMF_OOB determines if DTMF signaling is sent as Out-Of-Band
-* only. If you pass a 1, DTMF is suppressed from the audio stream.
-* Tone on and off times are in 250 microsecond intervals so
-* ioctl(ixj1, IXJCTL_SET_TONE_ON_TIME, 360);
-* will set the tone on time of board ixj1 to 360 * 250us = 90ms
-* the default values of tone on and off times is 840 or 210ms
-******************************************************************************/
-
-#define IXJCTL_DTMF_READY PHONE_DTMF_READY
-#define IXJCTL_GET_DTMF PHONE_GET_DTMF
-#define IXJCTL_GET_DTMF_ASCII PHONE_GET_DTMF_ASCII
-#define IXJCTL_DTMF_OOB PHONE_DTMF_OOB
-#define IXJCTL_EXCEPTION PHONE_EXCEPTION
-#define IXJCTL_PLAY_TONE PHONE_PLAY_TONE
-#define IXJCTL_SET_TONE_ON_TIME PHONE_SET_TONE_ON_TIME
-#define IXJCTL_SET_TONE_OFF_TIME PHONE_SET_TONE_OFF_TIME
-#define IXJCTL_GET_TONE_ON_TIME PHONE_GET_TONE_ON_TIME
-#define IXJCTL_GET_TONE_OFF_TIME PHONE_GET_TONE_OFF_TIME
-#define IXJCTL_GET_TONE_STATE PHONE_GET_TONE_STATE
-#define IXJCTL_BUSY PHONE_BUSY
-#define IXJCTL_RINGBACK PHONE_RINGBACK
-#define IXJCTL_DIALTONE PHONE_DIALTONE
-#define IXJCTL_CPT_STOP PHONE_CPT_STOP
-
-/******************************************************************************
-* LineJACK specific IOCTLs
-*
-* The lsb 4 bits of the LED argument represent the state of each of the 4
-* LED's on the LineJACK
-******************************************************************************/
-
-#define IXJCTL_SET_LED _IOW ('q', 0xCE, int)
-#define IXJCTL_MIXER _IOW ('q', 0xCF, int)
-
-/******************************************************************************
-*
-* The master volume controls use attenuation with 32 levels from 0 to -62dB
-* with steps of 2dB each, the defines should be OR'ed together then sent
-* as the parameter to the mixer command to change the mixer settings.
-*
-******************************************************************************/
-#define MIXER_MASTER_L 0x0000
-#define MIXER_MASTER_R 0x0100
-#define ATT00DB 0x00
-#define ATT02DB 0x01
-#define ATT04DB 0x02
-#define ATT06DB 0x03
-#define ATT08DB 0x04
-#define ATT10DB 0x05
-#define ATT12DB 0x06
-#define ATT14DB 0x07
-#define ATT16DB 0x08
-#define ATT18DB 0x09
-#define ATT20DB 0x0A
-#define ATT22DB 0x0B
-#define ATT24DB 0x0C
-#define ATT26DB 0x0D
-#define ATT28DB 0x0E
-#define ATT30DB 0x0F
-#define ATT32DB 0x10
-#define ATT34DB 0x11
-#define ATT36DB 0x12
-#define ATT38DB 0x13
-#define ATT40DB 0x14
-#define ATT42DB 0x15
-#define ATT44DB 0x16
-#define ATT46DB 0x17
-#define ATT48DB 0x18
-#define ATT50DB 0x19
-#define ATT52DB 0x1A
-#define ATT54DB 0x1B
-#define ATT56DB 0x1C
-#define ATT58DB 0x1D
-#define ATT60DB 0x1E
-#define ATT62DB 0x1F
-#define MASTER_MUTE 0x80
-
-/******************************************************************************
-*
-* The input volume controls use gain with 32 levels from +12dB to -50dB
-* with steps of 2dB each, the defines should be OR'ed together then sent
-* as the parameter to the mixer command to change the mixer settings.
-*
-******************************************************************************/
-#define MIXER_PORT_CD_L 0x0600
-#define MIXER_PORT_CD_R 0x0700
-#define MIXER_PORT_LINE_IN_L 0x0800
-#define MIXER_PORT_LINE_IN_R 0x0900
-#define MIXER_PORT_POTS_REC 0x0C00
-#define MIXER_PORT_MIC 0x0E00
-
-#define GAIN12DB 0x00
-#define GAIN10DB 0x01
-#define GAIN08DB 0x02
-#define GAIN06DB 0x03
-#define GAIN04DB 0x04
-#define GAIN02DB 0x05
-#define GAIN00DB 0x06
-#define GAIN_02DB 0x07
-#define GAIN_04DB 0x08
-#define GAIN_06DB 0x09
-#define GAIN_08DB 0x0A
-#define GAIN_10DB 0x0B
-#define GAIN_12DB 0x0C
-#define GAIN_14DB 0x0D
-#define GAIN_16DB 0x0E
-#define GAIN_18DB 0x0F
-#define GAIN_20DB 0x10
-#define GAIN_22DB 0x11
-#define GAIN_24DB 0x12
-#define GAIN_26DB 0x13
-#define GAIN_28DB 0x14
-#define GAIN_30DB 0x15
-#define GAIN_32DB 0x16
-#define GAIN_34DB 0x17
-#define GAIN_36DB 0x18
-#define GAIN_38DB 0x19
-#define GAIN_40DB 0x1A
-#define GAIN_42DB 0x1B
-#define GAIN_44DB 0x1C
-#define GAIN_46DB 0x1D
-#define GAIN_48DB 0x1E
-#define GAIN_50DB 0x1F
-#define INPUT_MUTE 0x80
-
-/******************************************************************************
-*
-* The POTS volume control use attenuation with 8 levels from 0dB to -28dB
-* with steps of 4dB each, the defines should be OR'ed together then sent
-* as the parameter to the mixer command to change the mixer settings.
-*
-******************************************************************************/
-#define MIXER_PORT_POTS_PLAY 0x0F00
-
-#define POTS_ATT_00DB 0x00
-#define POTS_ATT_04DB 0x01
-#define POTS_ATT_08DB 0x02
-#define POTS_ATT_12DB 0x03
-#define POTS_ATT_16DB 0x04
-#define POTS_ATT_20DB 0x05
-#define POTS_ATT_24DB 0x06
-#define POTS_ATT_28DB 0x07
-#define POTS_MUTE 0x80
-
-/******************************************************************************
-*
-* The DAA controls the interface to the PSTN port. The driver loads the
-* US coefficients by default, so if you live in a different country you
-* need to load the set for your countries phone system.
-*
-******************************************************************************/
-#define IXJCTL_DAA_COEFF_SET _IOW ('q', 0xD0, int)
-
-#define DAA_US 1 /*PITA 8kHz */
-#define DAA_UK 2 /*ISAR34 8kHz */
-#define DAA_FRANCE 3 /* */
-#define DAA_GERMANY 4
-#define DAA_AUSTRALIA 5
-#define DAA_JAPAN 6
-
-/******************************************************************************
-*
-* Use IXJCTL_PORT to set or query the port the card is set to. If the
-* argument is set to PORT_QUERY, the return value of the ioctl will
-* indicate which port is currently in use, otherwise it will change the
-* port.
-*
-******************************************************************************/
-#define IXJCTL_PORT _IOW ('q', 0xD1, int)
-
-#define PORT_QUERY 0
-#define PORT_POTS 1
-#define PORT_PSTN 2
-#define PORT_SPEAKER 3
-#define PORT_HANDSET 4
-
-#define IXJCTL_PSTN_SET_STATE PHONE_PSTN_SET_STATE
-#define IXJCTL_PSTN_GET_STATE PHONE_PSTN_GET_STATE
-
-#define PSTN_ON_HOOK 0
-#define PSTN_RINGING 1
-#define PSTN_OFF_HOOK 2
-#define PSTN_PULSE_DIAL 3
-
-/******************************************************************************
-*
-* The DAA Analog GAIN sets 2 parameters at one time, the receive gain (AGRR),
-* and the transmit gain (AGX). OR together the components and pass them
-* as the parameter to IXJCTL_DAA_AGAIN. The default setting is both at 0dB.
-*
-******************************************************************************/
-#define IXJCTL_DAA_AGAIN _IOW ('q', 0xD2, int)
-
-#define AGRR00DB 0x00 /* Analog gain in receive direction 0dB */
-#define AGRR3_5DB 0x10 /* Analog gain in receive direction 3.5dB */
-#define AGRR06DB 0x30 /* Analog gain in receive direction 6dB */
-
-#define AGX00DB 0x00 /* Analog gain in transmit direction 0dB */
-#define AGX_6DB 0x04 /* Analog gain in transmit direction -6dB */
-#define AGX3_5DB 0x08 /* Analog gain in transmit direction 3.5dB */
-#define AGX_2_5B 0x0C /* Analog gain in transmit direction -2.5dB */
-
-#define IXJCTL_PSTN_LINETEST _IO ('q', 0xD3)
-
-#define IXJCTL_CID _IOR ('q', 0xD4, PHONE_CID *)
-#define IXJCTL_VMWI _IOR ('q', 0xD8, int)
-#define IXJCTL_CIDCW _IOW ('q', 0xD9, PHONE_CID *)
-/******************************************************************************
-*
-* The wink duration is tunable with this ioctl. The default wink duration
-* is 320ms. You do not need to use this ioctl if you do not require a
-* different wink duration.
-*
-******************************************************************************/
-#define IXJCTL_WINK_DURATION PHONE_WINK_DURATION
-
-/******************************************************************************
-*
-* This ioctl will connect the POTS port to the PSTN port on the LineJACK
-* In order for this to work properly the port selection should be set to
-* the PSTN port with IXJCTL_PORT prior to calling this ioctl. This will
-* enable conference calls between PSTN callers and network callers.
-* Passing a 1 to this ioctl enables the POTS<->PSTN connection while
-* passing a 0 turns it back off.
-*
-******************************************************************************/
-#define IXJCTL_POTS_PSTN _IOW ('q', 0xD5, int)
-
-/******************************************************************************
-*
-* IOCTLs added by request.
-*
-* IXJCTL_HZ sets the value your Linux kernel uses for HZ as defined in
-* /usr/include/asm/param.h, this determines the fundamental
-* frequency of the clock ticks on your Linux system. The kernel
-* must be rebuilt if you change this value, also all modules you
-* use (except this one) must be recompiled. The default value
-* is 100, and you only need to use this IOCTL if you use some
-* other value.
-*
-*
-* IXJCTL_RATE sets the number of times per second that the driver polls
-* the DSP. This value cannot be larger than HZ. By
-* increasing both of these values, you may be able to reduce
-* latency because the max hang time that can exist between the
-* driver and the DSP will be reduced.
-*
-******************************************************************************/
-
-#define IXJCTL_HZ _IOW ('q', 0xE0, int)
-#define IXJCTL_RATE _IOW ('q', 0xE1, int)
-#define IXJCTL_FRAMES_READ _IOR ('q', 0xE2, unsigned long)
-#define IXJCTL_FRAMES_WRITTEN _IOR ('q', 0xE3, unsigned long)
-#define IXJCTL_READ_WAIT _IOR ('q', 0xE4, unsigned long)
-#define IXJCTL_WRITE_WAIT _IOR ('q', 0xE5, unsigned long)
-#define IXJCTL_DRYBUFFER_READ _IOR ('q', 0xE6, unsigned long)
-#define IXJCTL_DRYBUFFER_CLEAR _IO ('q', 0xE7)
-#define IXJCTL_DTMF_PRESCALE _IOW ('q', 0xE8, int)
-
-/******************************************************************************
-*
-* This ioctl allows the user application to control what events the driver
-* will send signals for, and what signals it will send for which event.
-* By default, if signaling is enabled, all events will send SIGIO when
-* they occur. To disable signals for an event set the signal to 0.
-*
-******************************************************************************/
-typedef enum {
- SIG_DTMF_READY,
- SIG_HOOKSTATE,
- SIG_FLASH,
- SIG_PSTN_RING,
- SIG_CALLER_ID,
- SIG_PSTN_WINK,
- SIG_F0, SIG_F1, SIG_F2, SIG_F3,
- SIG_FC0, SIG_FC1, SIG_FC2, SIG_FC3,
- SIG_READ_READY = 33,
- SIG_WRITE_READY = 34
-} IXJ_SIGEVENT;
-
-typedef struct {
- unsigned int event;
- int signal;
-} IXJ_SIGDEF;
-
-#define IXJCTL_SIGCTL _IOW ('q', 0xE9, IXJ_SIGDEF *)
-
-/******************************************************************************
-*
-* These ioctls allow the user application to change the gain in the
-* Smart Cable of the Internet Phone Card. Sending -1 as a value will cause
-* return value to be the current setting. Valid values to set are 0x00 - 0x1F
-*
-* 11111 = +12 dB
-* 10111 = 0 dB
-* 00000 = -34.5 dB
-*
-* IXJCTL_SC_RXG sets the Receive gain
-* IXJCTL_SC_TXG sets the Transmit gain
-*
-******************************************************************************/
-#define IXJCTL_SC_RXG _IOW ('q', 0xEA, int)
-#define IXJCTL_SC_TXG _IOW ('q', 0xEB, int)
-
-/******************************************************************************
-*
-* The intercom IOCTL's short the output from one card to the input of the
-* other and vice versa (actually done in the DSP read function). It is only
-* necessary to execute the IOCTL on one card, but it is necessary to have
-* both devices open to be able to detect hook switch changes. The record
-* codec and rate of each card must match the playback codec and rate of
-* the other card for this to work properly.
-*
-******************************************************************************/
-
-#define IXJCTL_INTERCOM_START _IOW ('q', 0xFD, int)
-#define IXJCTL_INTERCOM_STOP _IOW ('q', 0xFE, int)
-
-/******************************************************************************
- *
- * new structure for accessing raw filter information
- *
- ******************************************************************************/
-
-typedef struct {
- unsigned int filter;
- char enable;
- unsigned int coeff[19];
-} IXJ_FILTER_RAW;
-
-#endif
diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h
index f5bf06ecd87d..f189931042a7 100644
--- a/include/uapi/linux/lirc.h
+++ b/include/uapi/linux/lirc.h
@@ -185,6 +185,7 @@ struct lirc_scancode {
* @RC_PROTO_SHARP: Sharp protocol
* @RC_PROTO_XMP: XMP protocol
* @RC_PROTO_CEC: CEC protocol
+ * @RC_PROTO_IMON: iMon Pad protocol
*/
enum rc_proto {
RC_PROTO_UNKNOWN = 0,
@@ -210,6 +211,7 @@ enum rc_proto {
RC_PROTO_SHARP = 20,
RC_PROTO_XMP = 21,
RC_PROTO_CEC = 22,
+ RC_PROTO_IMON = 23,
};
#endif
diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
index b9b9446095e9..c7e9a5cba24e 100644
--- a/include/uapi/linux/media.h
+++ b/include/uapi/linux/media.h
@@ -15,10 +15,6 @@
* 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __LINUX_MEDIA_H
@@ -42,108 +38,66 @@ struct media_device_info {
__u32 reserved[31];
};
-#define MEDIA_ENT_ID_FLAG_NEXT (1 << 31)
-
-/*
- * Initial value to be used when a new entity is created
- * Drivers should change it to something useful
- */
-#define MEDIA_ENT_F_UNKNOWN 0x00000000
-
/*
* Base number ranges for entity functions
*
- * NOTE: those ranges and entity function number are phased just to
- * make it easier to maintain this file. Userspace should not rely on
- * the ranges to identify a group of function types, as newer
- * functions can be added with any name within the full u32 range.
- */
-#define MEDIA_ENT_F_BASE 0x00000000
-#define MEDIA_ENT_F_OLD_BASE 0x00010000
-#define MEDIA_ENT_F_OLD_SUBDEV_BASE 0x00020000
-
-/*
- * DVB entities
+ * NOTE: Userspace should not rely on these ranges to identify a group
+ * of function types, as newer functions can be added with any name within
+ * the full u32 range.
+ *
+ * Some older functions use the MEDIA_ENT_F_OLD_*_BASE range. Do not
+ * change this, this is for backwards compatibility. When adding new
+ * functions always use MEDIA_ENT_F_BASE.
*/
-#define MEDIA_ENT_F_DTV_DEMOD (MEDIA_ENT_F_BASE + 0x00001)
-#define MEDIA_ENT_F_TS_DEMUX (MEDIA_ENT_F_BASE + 0x00002)
-#define MEDIA_ENT_F_DTV_CA (MEDIA_ENT_F_BASE + 0x00003)
-#define MEDIA_ENT_F_DTV_NET_DECAP (MEDIA_ENT_F_BASE + 0x00004)
+#define MEDIA_ENT_F_BASE 0x00000000
+#define MEDIA_ENT_F_OLD_BASE 0x00010000
+#define MEDIA_ENT_F_OLD_SUBDEV_BASE 0x00020000
/*
- * I/O entities
+ * Initial value to be used when a new entity is created
+ * Drivers should change it to something useful.
*/
-#define MEDIA_ENT_F_IO_DTV (MEDIA_ENT_F_BASE + 0x01001)
-#define MEDIA_ENT_F_IO_VBI (MEDIA_ENT_F_BASE + 0x01002)
-#define MEDIA_ENT_F_IO_SWRADIO (MEDIA_ENT_F_BASE + 0x01003)
+#define MEDIA_ENT_F_UNKNOWN MEDIA_ENT_F_BASE
/*
- * Analog TV IF-PLL decoders
- *
- * It is a responsibility of the master/bridge drivers to create links
- * for MEDIA_ENT_F_IF_VID_DECODER and MEDIA_ENT_F_IF_AUD_DECODER.
+ * Subdevs are initialized with MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN in order
+ * to preserve backward compatibility. Drivers must change to the proper
+ * subdev type before registering the entity.
*/
-#define MEDIA_ENT_F_IF_VID_DECODER (MEDIA_ENT_F_BASE + 0x02001)
-#define MEDIA_ENT_F_IF_AUD_DECODER (MEDIA_ENT_F_BASE + 0x02002)
+#define MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN MEDIA_ENT_F_OLD_SUBDEV_BASE
/*
- * Audio Entity Functions
+ * DVB entity functions
*/
-#define MEDIA_ENT_F_AUDIO_CAPTURE (MEDIA_ENT_F_BASE + 0x03001)
-#define MEDIA_ENT_F_AUDIO_PLAYBACK (MEDIA_ENT_F_BASE + 0x03002)
-#define MEDIA_ENT_F_AUDIO_MIXER (MEDIA_ENT_F_BASE + 0x03003)
+#define MEDIA_ENT_F_DTV_DEMOD (MEDIA_ENT_F_BASE + 0x00001)
+#define MEDIA_ENT_F_TS_DEMUX (MEDIA_ENT_F_BASE + 0x00002)
+#define MEDIA_ENT_F_DTV_CA (MEDIA_ENT_F_BASE + 0x00003)
+#define MEDIA_ENT_F_DTV_NET_DECAP (MEDIA_ENT_F_BASE + 0x00004)
/*
- * Processing entities
+ * I/O entity functions
*/
-#define MEDIA_ENT_F_PROC_VIDEO_COMPOSER (MEDIA_ENT_F_BASE + 0x4001)
-#define MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER (MEDIA_ENT_F_BASE + 0x4002)
-#define MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV (MEDIA_ENT_F_BASE + 0x4003)
-#define MEDIA_ENT_F_PROC_VIDEO_LUT (MEDIA_ENT_F_BASE + 0x4004)
-#define MEDIA_ENT_F_PROC_VIDEO_SCALER (MEDIA_ENT_F_BASE + 0x4005)
-#define MEDIA_ENT_F_PROC_VIDEO_STATISTICS (MEDIA_ENT_F_BASE + 0x4006)
+#define MEDIA_ENT_F_IO_V4L (MEDIA_ENT_F_OLD_BASE + 1)
+#define MEDIA_ENT_F_IO_DTV (MEDIA_ENT_F_BASE + 0x01001)
+#define MEDIA_ENT_F_IO_VBI (MEDIA_ENT_F_BASE + 0x01002)
+#define MEDIA_ENT_F_IO_SWRADIO (MEDIA_ENT_F_BASE + 0x01003)
/*
- * Switch and bridge entitites
+ * Sensor functions
*/
-#define MEDIA_ENT_F_VID_MUX (MEDIA_ENT_F_BASE + 0x5001)
-#define MEDIA_ENT_F_VID_IF_BRIDGE (MEDIA_ENT_F_BASE + 0x5002)
+#define MEDIA_ENT_F_CAM_SENSOR (MEDIA_ENT_F_OLD_SUBDEV_BASE + 1)
+#define MEDIA_ENT_F_FLASH (MEDIA_ENT_F_OLD_SUBDEV_BASE + 2)
+#define MEDIA_ENT_F_LENS (MEDIA_ENT_F_OLD_SUBDEV_BASE + 3)
/*
- * Connectors
+ * Video decoder functions
*/
-/* It is a responsibility of the entity drivers to add connectors and links */
-#ifdef __KERNEL__
- /*
- * For now, it should not be used in userspace, as some
- * definitions may change
- */
-
-#define MEDIA_ENT_F_CONN_RF (MEDIA_ENT_F_BASE + 0x30001)
-#define MEDIA_ENT_F_CONN_SVIDEO (MEDIA_ENT_F_BASE + 0x30002)
-#define MEDIA_ENT_F_CONN_COMPOSITE (MEDIA_ENT_F_BASE + 0x30003)
-
-#endif
+#define MEDIA_ENT_F_ATV_DECODER (MEDIA_ENT_F_OLD_SUBDEV_BASE + 4)
+#define MEDIA_ENT_F_DTV_DECODER (MEDIA_ENT_F_BASE + 0x6001)
/*
- * Don't touch on those. The ranges MEDIA_ENT_F_OLD_BASE and
- * MEDIA_ENT_F_OLD_SUBDEV_BASE are kept to keep backward compatibility
- * with the legacy v1 API.The number range is out of range by purpose:
- * several previously reserved numbers got excluded from this range.
+ * Digital TV, analog TV, radio and/or software defined radio tuner functions.
*
- * Subdevs are initialized with MEDIA_ENT_T_V4L2_SUBDEV_UNKNOWN,
- * in order to preserve backward compatibility.
- * Drivers must change to the proper subdev type before
- * registering the entity.
- */
-
-#define MEDIA_ENT_F_IO_V4L (MEDIA_ENT_F_OLD_BASE + 1)
-
-#define MEDIA_ENT_F_CAM_SENSOR (MEDIA_ENT_F_OLD_SUBDEV_BASE + 1)
-#define MEDIA_ENT_F_FLASH (MEDIA_ENT_F_OLD_SUBDEV_BASE + 2)
-#define MEDIA_ENT_F_LENS (MEDIA_ENT_F_OLD_SUBDEV_BASE + 3)
-#define MEDIA_ENT_F_ATV_DECODER (MEDIA_ENT_F_OLD_SUBDEV_BASE + 4)
-/*
* It is a responsibility of the master/bridge drivers to add connectors
* and links for MEDIA_ENT_F_TUNER. Please notice that some old tuners
* may require the usage of separate I2C chips to decode analog TV signals,
@@ -151,49 +105,46 @@ struct media_device_info {
* On such cases, the IF-PLL staging is mapped via one or two entities:
* MEDIA_ENT_F_IF_VID_DECODER and/or MEDIA_ENT_F_IF_AUD_DECODER.
*/
-#define MEDIA_ENT_F_TUNER (MEDIA_ENT_F_OLD_SUBDEV_BASE + 5)
+#define MEDIA_ENT_F_TUNER (MEDIA_ENT_F_OLD_SUBDEV_BASE + 5)
-#define MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN MEDIA_ENT_F_OLD_SUBDEV_BASE
+/*
+ * Analog TV IF-PLL decoder functions
+ *
+ * It is a responsibility of the master/bridge drivers to create links
+ * for MEDIA_ENT_F_IF_VID_DECODER and MEDIA_ENT_F_IF_AUD_DECODER.
+ */
+#define MEDIA_ENT_F_IF_VID_DECODER (MEDIA_ENT_F_BASE + 0x02001)
+#define MEDIA_ENT_F_IF_AUD_DECODER (MEDIA_ENT_F_BASE + 0x02002)
-#if !defined(__KERNEL__) || defined(__NEED_MEDIA_LEGACY_API)
+/*
+ * Audio entity functions
+ */
+#define MEDIA_ENT_F_AUDIO_CAPTURE (MEDIA_ENT_F_BASE + 0x03001)
+#define MEDIA_ENT_F_AUDIO_PLAYBACK (MEDIA_ENT_F_BASE + 0x03002)
+#define MEDIA_ENT_F_AUDIO_MIXER (MEDIA_ENT_F_BASE + 0x03003)
/*
- * Legacy symbols used to avoid userspace compilation breakages
- *
- * Those symbols map the entity function into types and should be
- * used only on legacy programs for legacy hardware. Don't rely
- * on those for MEDIA_IOC_G_TOPOLOGY.
+ * Processing entity functions
*/
-#define MEDIA_ENT_TYPE_SHIFT 16
-#define MEDIA_ENT_TYPE_MASK 0x00ff0000
-#define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff
-
-/* End of the old subdev reserved numberspace */
-#define MEDIA_ENT_T_DEVNODE_UNKNOWN (MEDIA_ENT_T_DEVNODE | \
- MEDIA_ENT_SUBTYPE_MASK)
-
-#define MEDIA_ENT_T_DEVNODE MEDIA_ENT_F_OLD_BASE
-#define MEDIA_ENT_T_DEVNODE_V4L MEDIA_ENT_F_IO_V4L
-#define MEDIA_ENT_T_DEVNODE_FB (MEDIA_ENT_T_DEVNODE + 2)
-#define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENT_T_DEVNODE + 3)
-#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENT_T_DEVNODE + 4)
-
-#define MEDIA_ENT_T_UNKNOWN MEDIA_ENT_F_UNKNOWN
-#define MEDIA_ENT_T_V4L2_VIDEO MEDIA_ENT_F_IO_V4L
-#define MEDIA_ENT_T_V4L2_SUBDEV MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN
-#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR MEDIA_ENT_F_CAM_SENSOR
-#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH MEDIA_ENT_F_FLASH
-#define MEDIA_ENT_T_V4L2_SUBDEV_LENS MEDIA_ENT_F_LENS
-#define MEDIA_ENT_T_V4L2_SUBDEV_DECODER MEDIA_ENT_F_ATV_DECODER
-#define MEDIA_ENT_T_V4L2_SUBDEV_TUNER MEDIA_ENT_F_TUNER
+#define MEDIA_ENT_F_PROC_VIDEO_COMPOSER (MEDIA_ENT_F_BASE + 0x4001)
+#define MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER (MEDIA_ENT_F_BASE + 0x4002)
+#define MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV (MEDIA_ENT_F_BASE + 0x4003)
+#define MEDIA_ENT_F_PROC_VIDEO_LUT (MEDIA_ENT_F_BASE + 0x4004)
+#define MEDIA_ENT_F_PROC_VIDEO_SCALER (MEDIA_ENT_F_BASE + 0x4005)
+#define MEDIA_ENT_F_PROC_VIDEO_STATISTICS (MEDIA_ENT_F_BASE + 0x4006)
-/* Obsolete symbol for media_version, no longer used in the kernel */
-#define MEDIA_API_VERSION KERNEL_VERSION(0, 1, 0)
-#endif
+/*
+ * Switch and bridge entity functions
+ */
+#define MEDIA_ENT_F_VID_MUX (MEDIA_ENT_F_BASE + 0x5001)
+#define MEDIA_ENT_F_VID_IF_BRIDGE (MEDIA_ENT_F_BASE + 0x5002)
/* Entity flags */
-#define MEDIA_ENT_FL_DEFAULT (1 << 0)
-#define MEDIA_ENT_FL_CONNECTOR (1 << 1)
+#define MEDIA_ENT_FL_DEFAULT (1 << 0)
+#define MEDIA_ENT_FL_CONNECTOR (1 << 1)
+
+/* OR with the entity id value to find the next entity */
+#define MEDIA_ENT_ID_FLAG_NEXT (1 << 31)
struct media_entity_desc {
__u32 id;
@@ -214,7 +165,7 @@ struct media_entity_desc {
__u32 minor;
} dev;
-#if 1
+#if !defined(__KERNEL__)
/*
* TODO: this shouldn't have been added without
* actual drivers that use this. When the first real driver
@@ -225,24 +176,17 @@ struct media_entity_desc {
* contain the subdevice information. In addition, struct dev
* can only refer to a single device, and not to multiple (e.g.
* pcm and mixer devices).
- *
- * So for now mark this as a to do.
*/
struct {
__u32 card;
__u32 device;
__u32 subdevice;
} alsa;
-#endif
-#if 1
/*
* DEPRECATED: previous node specifications. Kept just to
- * avoid breaking compilation, but media_entity_desc.dev
- * should be used instead. In particular, alsa and dvb
- * fields below are wrong: for all devnodes, there should
- * be just major/minor inside the struct, as this is enough
- * to represent any devnode, no matter what type.
+ * avoid breaking compilation. Use media_entity_desc.dev
+ * instead.
*/
struct {
__u32 major;
@@ -261,9 +205,9 @@ struct media_entity_desc {
};
};
-#define MEDIA_PAD_FL_SINK (1 << 0)
-#define MEDIA_PAD_FL_SOURCE (1 << 1)
-#define MEDIA_PAD_FL_MUST_CONNECT (1 << 2)
+#define MEDIA_PAD_FL_SINK (1 << 0)
+#define MEDIA_PAD_FL_SOURCE (1 << 1)
+#define MEDIA_PAD_FL_MUST_CONNECT (1 << 2)
struct media_pad_desc {
__u32 entity; /* entity ID */
@@ -272,13 +216,13 @@ struct media_pad_desc {
__u32 reserved[2];
};
-#define MEDIA_LNK_FL_ENABLED (1 << 0)
-#define MEDIA_LNK_FL_IMMUTABLE (1 << 1)
-#define MEDIA_LNK_FL_DYNAMIC (1 << 2)
+#define MEDIA_LNK_FL_ENABLED (1 << 0)
+#define MEDIA_LNK_FL_IMMUTABLE (1 << 1)
+#define MEDIA_LNK_FL_DYNAMIC (1 << 2)
-#define MEDIA_LNK_FL_LINK_TYPE (0xf << 28)
-# define MEDIA_LNK_FL_DATA_LINK (0 << 28)
-# define MEDIA_LNK_FL_INTERFACE_LINK (1 << 28)
+#define MEDIA_LNK_FL_LINK_TYPE (0xf << 28)
+# define MEDIA_LNK_FL_DATA_LINK (0 << 28)
+# define MEDIA_LNK_FL_INTERFACE_LINK (1 << 28)
struct media_link_desc {
struct media_pad_desc source;
@@ -298,57 +242,47 @@ struct media_links_enum {
/* Interface type ranges */
-#define MEDIA_INTF_T_DVB_BASE 0x00000100
-#define MEDIA_INTF_T_V4L_BASE 0x00000200
-#define MEDIA_INTF_T_ALSA_BASE 0x00000300
+#define MEDIA_INTF_T_DVB_BASE 0x00000100
+#define MEDIA_INTF_T_V4L_BASE 0x00000200
/* Interface types */
-#define MEDIA_INTF_T_DVB_FE (MEDIA_INTF_T_DVB_BASE)
-#define MEDIA_INTF_T_DVB_DEMUX (MEDIA_INTF_T_DVB_BASE + 1)
-#define MEDIA_INTF_T_DVB_DVR (MEDIA_INTF_T_DVB_BASE + 2)
-#define MEDIA_INTF_T_DVB_CA (MEDIA_INTF_T_DVB_BASE + 3)
-#define MEDIA_INTF_T_DVB_NET (MEDIA_INTF_T_DVB_BASE + 4)
-
-#define MEDIA_INTF_T_V4L_VIDEO (MEDIA_INTF_T_V4L_BASE)
-#define MEDIA_INTF_T_V4L_VBI (MEDIA_INTF_T_V4L_BASE + 1)
-#define MEDIA_INTF_T_V4L_RADIO (MEDIA_INTF_T_V4L_BASE + 2)
-#define MEDIA_INTF_T_V4L_SUBDEV (MEDIA_INTF_T_V4L_BASE + 3)
-#define MEDIA_INTF_T_V4L_SWRADIO (MEDIA_INTF_T_V4L_BASE + 4)
-#define MEDIA_INTF_T_V4L_TOUCH (MEDIA_INTF_T_V4L_BASE + 5)
-
-#define MEDIA_INTF_T_ALSA_PCM_CAPTURE (MEDIA_INTF_T_ALSA_BASE)
-#define MEDIA_INTF_T_ALSA_PCM_PLAYBACK (MEDIA_INTF_T_ALSA_BASE + 1)
-#define MEDIA_INTF_T_ALSA_CONTROL (MEDIA_INTF_T_ALSA_BASE + 2)
-#define MEDIA_INTF_T_ALSA_COMPRESS (MEDIA_INTF_T_ALSA_BASE + 3)
-#define MEDIA_INTF_T_ALSA_RAWMIDI (MEDIA_INTF_T_ALSA_BASE + 4)
-#define MEDIA_INTF_T_ALSA_HWDEP (MEDIA_INTF_T_ALSA_BASE + 5)
-#define MEDIA_INTF_T_ALSA_SEQUENCER (MEDIA_INTF_T_ALSA_BASE + 6)
-#define MEDIA_INTF_T_ALSA_TIMER (MEDIA_INTF_T_ALSA_BASE + 7)
+#define MEDIA_INTF_T_DVB_FE (MEDIA_INTF_T_DVB_BASE)
+#define MEDIA_INTF_T_DVB_DEMUX (MEDIA_INTF_T_DVB_BASE + 1)
+#define MEDIA_INTF_T_DVB_DVR (MEDIA_INTF_T_DVB_BASE + 2)
+#define MEDIA_INTF_T_DVB_CA (MEDIA_INTF_T_DVB_BASE + 3)
+#define MEDIA_INTF_T_DVB_NET (MEDIA_INTF_T_DVB_BASE + 4)
+
+#define MEDIA_INTF_T_V4L_VIDEO (MEDIA_INTF_T_V4L_BASE)
+#define MEDIA_INTF_T_V4L_VBI (MEDIA_INTF_T_V4L_BASE + 1)
+#define MEDIA_INTF_T_V4L_RADIO (MEDIA_INTF_T_V4L_BASE + 2)
+#define MEDIA_INTF_T_V4L_SUBDEV (MEDIA_INTF_T_V4L_BASE + 3)
+#define MEDIA_INTF_T_V4L_SWRADIO (MEDIA_INTF_T_V4L_BASE + 4)
+#define MEDIA_INTF_T_V4L_TOUCH (MEDIA_INTF_T_V4L_BASE + 5)
+
+#if defined(__KERNEL__)
/*
- * MC next gen API definitions
+ * Connector functions
*
- * NOTE: The declarations below are close to the MC RFC for the Media
- * Controller, the next generation. Yet, there are a few adjustments
- * to do, as we want to be able to have a functional API before
- * the MC properties change. Those will be properly marked below.
- * Please also notice that I removed "num_pads", "num_links",
- * from the proposal, as a proper userspace application will likely
- * use lists for pads/links, just as we intend to do in Kernelspace.
- * The API definition should be freed from fields that are bound to
- * some specific data structure.
+ * For now these should not be used in userspace, as some definitions may
+ * change.
*
- * FIXME: Currently, I opted to name the new types as "media_v2", as this
- * won't cause any conflict with the Kernelspace namespace, nor with
- * the previous kAPI media_*_desc namespace. This can be changed
- * later, before the adding this API upstream.
+ * It is the responsibility of the entity drivers to add connectors and links.
*/
+#define MEDIA_ENT_F_CONN_RF (MEDIA_ENT_F_BASE + 0x30001)
+#define MEDIA_ENT_F_CONN_SVIDEO (MEDIA_ENT_F_BASE + 0x30002)
+#define MEDIA_ENT_F_CONN_COMPOSITE (MEDIA_ENT_F_BASE + 0x30003)
+#endif
+
+/*
+ * MC next gen API definitions
+ */
struct media_v2_entity {
__u32 id;
- char name[64]; /* FIXME: move to a property? (RFC says so) */
+ char name[64];
__u32 function; /* Main function of the entity */
__u32 reserved[6];
} __attribute__ ((packed));
@@ -408,10 +342,62 @@ struct media_v2_topology {
/* ioctls */
-#define MEDIA_IOC_DEVICE_INFO _IOWR('|', 0x00, struct media_device_info)
-#define MEDIA_IOC_ENUM_ENTITIES _IOWR('|', 0x01, struct media_entity_desc)
-#define MEDIA_IOC_ENUM_LINKS _IOWR('|', 0x02, struct media_links_enum)
-#define MEDIA_IOC_SETUP_LINK _IOWR('|', 0x03, struct media_link_desc)
-#define MEDIA_IOC_G_TOPOLOGY _IOWR('|', 0x04, struct media_v2_topology)
+#define MEDIA_IOC_DEVICE_INFO _IOWR('|', 0x00, struct media_device_info)
+#define MEDIA_IOC_ENUM_ENTITIES _IOWR('|', 0x01, struct media_entity_desc)
+#define MEDIA_IOC_ENUM_LINKS _IOWR('|', 0x02, struct media_links_enum)
+#define MEDIA_IOC_SETUP_LINK _IOWR('|', 0x03, struct media_link_desc)
+#define MEDIA_IOC_G_TOPOLOGY _IOWR('|', 0x04, struct media_v2_topology)
+
+#if !defined(__KERNEL__) || defined(__NEED_MEDIA_LEGACY_API)
+
+/*
+ * Legacy symbols used to avoid userspace compilation breakages.
+ * Do not use any of this in new applications!
+ *
+ * Those symbols map the entity function into types and should be
+ * used only on legacy programs for legacy hardware. Don't rely
+ * on those for MEDIA_IOC_G_TOPOLOGY.
+ */
+#define MEDIA_ENT_TYPE_SHIFT 16
+#define MEDIA_ENT_TYPE_MASK 0x00ff0000
+#define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff
+
+#define MEDIA_ENT_T_DEVNODE_UNKNOWN (MEDIA_ENT_F_OLD_BASE | \
+ MEDIA_ENT_SUBTYPE_MASK)
+
+#define MEDIA_ENT_T_DEVNODE MEDIA_ENT_F_OLD_BASE
+#define MEDIA_ENT_T_DEVNODE_V4L MEDIA_ENT_F_IO_V4L
+#define MEDIA_ENT_T_DEVNODE_FB (MEDIA_ENT_F_OLD_BASE + 2)
+#define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENT_F_OLD_BASE + 3)
+#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENT_F_OLD_BASE + 4)
+
+#define MEDIA_ENT_T_UNKNOWN MEDIA_ENT_F_UNKNOWN
+#define MEDIA_ENT_T_V4L2_VIDEO MEDIA_ENT_F_IO_V4L
+#define MEDIA_ENT_T_V4L2_SUBDEV MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN
+#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR MEDIA_ENT_F_CAM_SENSOR
+#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH MEDIA_ENT_F_FLASH
+#define MEDIA_ENT_T_V4L2_SUBDEV_LENS MEDIA_ENT_F_LENS
+#define MEDIA_ENT_T_V4L2_SUBDEV_DECODER MEDIA_ENT_F_ATV_DECODER
+#define MEDIA_ENT_T_V4L2_SUBDEV_TUNER MEDIA_ENT_F_TUNER
+
+/*
+ * There is still no ALSA support in the media controller. These
+ * defines should not have been added and we leave them here only
+ * in case some application tries to use these defines.
+ */
+#define MEDIA_INTF_T_ALSA_BASE 0x00000300
+#define MEDIA_INTF_T_ALSA_PCM_CAPTURE (MEDIA_INTF_T_ALSA_BASE)
+#define MEDIA_INTF_T_ALSA_PCM_PLAYBACK (MEDIA_INTF_T_ALSA_BASE + 1)
+#define MEDIA_INTF_T_ALSA_CONTROL (MEDIA_INTF_T_ALSA_BASE + 2)
+#define MEDIA_INTF_T_ALSA_COMPRESS (MEDIA_INTF_T_ALSA_BASE + 3)
+#define MEDIA_INTF_T_ALSA_RAWMIDI (MEDIA_INTF_T_ALSA_BASE + 4)
+#define MEDIA_INTF_T_ALSA_HWDEP (MEDIA_INTF_T_ALSA_BASE + 5)
+#define MEDIA_INTF_T_ALSA_SEQUENCER (MEDIA_INTF_T_ALSA_BASE + 6)
+#define MEDIA_INTF_T_ALSA_TIMER (MEDIA_INTF_T_ALSA_BASE + 7)
+
+/* Obsolete symbol for media_version, no longer used in the kernel */
+#define MEDIA_API_VERSION KERNEL_VERSION(0, 1, 0)
+
+#endif
#endif /* __LINUX_MEDIA_H */
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 1c8413f93e3d..dce5f9dae121 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -76,6 +76,9 @@
#define PORT_SUNZILOG 38
#define PORT_SUNSAB 39
+/* Nuvoton UART */
+#define PORT_NPCM 40
+
/* Intel EG20 */
#define PORT_PCH_8LINE 44
#define PORT_PCH_2LINE 45
diff --git a/include/uapi/linux/stm.h b/include/uapi/linux/stm.h
index dbffdc23d804..7bac318b4440 100644
--- a/include/uapi/linux/stm.h
+++ b/include/uapi/linux/stm.h
@@ -3,15 +3,6 @@
* System Trace Module (STM) userspace interfaces
* Copyright (c) 2014, 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.
- *
* STM class implements generic infrastructure for System Trace Module devices
* as defined in MIPI STPv2 specification.
*/
@@ -21,6 +12,10 @@
#include <linux/types.h>
+/* Maximum allowed master and channel values */
+#define STP_MASTER_MAX 0xffff
+#define STP_CHANNEL_MAX 0xffff
+
/**
* struct stp_policy_id - identification for the STP policy
* @size: size of the structure including real id[] length
diff --git a/include/uapi/linux/telephony.h b/include/uapi/linux/telephony.h
deleted file mode 100644
index d2c9f7105f4b..000000000000
--- a/include/uapi/linux/telephony.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
-/******************************************************************************
- *
- * telephony.h
- *
- * Basic Linux Telephony Interface
- *
- * (c) Copyright 1999-2001 Quicknet Technologies, 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.
- *
- * Authors: Ed Okerson, <eokerson@quicknet.net>
- * Greg Herlein, <gherlein@quicknet.net>
- *
- * Contributors: Alan Cox, <alan@lxorguk.ukuu.org.uk>
- * David W. Erhart, <derhart@quicknet.net>
- *
- * IN NO EVENT SHALL QUICKNET TECHNOLOGIES, INC. BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
- * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF QUICKNET
- * TECHNOLOGIES, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * QUICKNET TECHNOLOGIES, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND QUICKNET TECHNOLOGIES, INC. HAS NO OBLIGATION
- * TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- *****************************************************************************/
-
-#ifndef TELEPHONY_H
-#define TELEPHONY_H
-
-#define TELEPHONY_VERSION 3013
-
-#define PHONE_VENDOR_IXJ 1
-#define PHONE_VENDOR_QUICKNET PHONE_VENDOR_IXJ
-#define PHONE_VENDOR_VOICETRONIX 2
-#define PHONE_VENDOR_ACULAB 3
-#define PHONE_VENDOR_DIGI 4
-#define PHONE_VENDOR_FRANKLIN 5
-
-/******************************************************************************
- * Vendor Summary Information Area
- *
- * Quicknet Technologies, Inc. - makes low density analog telephony cards
- * with audio compression, POTS and PSTN interfaces (www.quicknet.net)
- *
- * (other vendors following this API shuld add a short description of
- * the telephony products they support under Linux)
- *
- *****************************************************************************/
-#define QTI_PHONEJACK 100
-#define QTI_LINEJACK 300
-#define QTI_PHONEJACK_LITE 400
-#define QTI_PHONEJACK_PCI 500
-#define QTI_PHONECARD 600
-
-/******************************************************************************
-*
-* The capabilities ioctls can inform you of the capabilities of each phone
-* device installed in your system. The PHONECTL_CAPABILITIES ioctl
-* returns an integer value indicating the number of capabilities the
-* device has. The PHONECTL_CAPABILITIES_LIST will fill an array of
-* capability structs with all of its capabilities. The
-* PHONECTL_CAPABILITIES_CHECK takes a single capability struct and returns
-* a TRUE if the device has that capability, otherwise it returns false.
-*
-******************************************************************************/
-typedef enum {
- vendor = 0,
- device,
- port,
- codec,
- dsp
-} phone_cap;
-
-struct phone_capability {
- char desc[80];
- phone_cap captype;
- int cap;
- int handle;
-};
-
-typedef enum {
- pots = 0,
- pstn,
- handset,
- speaker
-} phone_ports;
-
-#define PHONE_CAPABILITIES _IO ('q', 0x80)
-#define PHONE_CAPABILITIES_LIST _IOR ('q', 0x81, struct phone_capability *)
-#define PHONE_CAPABILITIES_CHECK _IOW ('q', 0x82, struct phone_capability *)
-
-typedef struct {
- char month[3];
- char day[3];
- char hour[3];
- char min[3];
- int numlen;
- char number[11];
- int namelen;
- char name[80];
-} PHONE_CID;
-
-#define PHONE_RING _IO ('q', 0x83)
-#define PHONE_HOOKSTATE _IO ('q', 0x84)
-#define PHONE_MAXRINGS _IOW ('q', 0x85, char)
-#define PHONE_RING_CADENCE _IOW ('q', 0x86, short)
-#define OLD_PHONE_RING_START _IO ('q', 0x87)
-#define PHONE_RING_START _IOW ('q', 0x87, PHONE_CID *)
-#define PHONE_RING_STOP _IO ('q', 0x88)
-
-#define USA_RING_CADENCE 0xC0C0
-
-#define PHONE_REC_CODEC _IOW ('q', 0x89, int)
-#define PHONE_REC_START _IO ('q', 0x8A)
-#define PHONE_REC_STOP _IO ('q', 0x8B)
-#define PHONE_REC_DEPTH _IOW ('q', 0x8C, int)
-#define PHONE_FRAME _IOW ('q', 0x8D, int)
-#define PHONE_REC_VOLUME _IOW ('q', 0x8E, int)
-#define PHONE_REC_VOLUME_LINEAR _IOW ('q', 0xDB, int)
-#define PHONE_REC_LEVEL _IO ('q', 0x8F)
-
-#define PHONE_PLAY_CODEC _IOW ('q', 0x90, int)
-#define PHONE_PLAY_START _IO ('q', 0x91)
-#define PHONE_PLAY_STOP _IO ('q', 0x92)
-#define PHONE_PLAY_DEPTH _IOW ('q', 0x93, int)
-#define PHONE_PLAY_VOLUME _IOW ('q', 0x94, int)
-#define PHONE_PLAY_VOLUME_LINEAR _IOW ('q', 0xDC, int)
-#define PHONE_PLAY_LEVEL _IO ('q', 0x95)
-#define PHONE_DTMF_READY _IOR ('q', 0x96, int)
-#define PHONE_GET_DTMF _IOR ('q', 0x97, int)
-#define PHONE_GET_DTMF_ASCII _IOR ('q', 0x98, int)
-#define PHONE_DTMF_OOB _IOW ('q', 0x99, int)
-#define PHONE_EXCEPTION _IOR ('q', 0x9A, int)
-#define PHONE_PLAY_TONE _IOW ('q', 0x9B, char)
-#define PHONE_SET_TONE_ON_TIME _IOW ('q', 0x9C, int)
-#define PHONE_SET_TONE_OFF_TIME _IOW ('q', 0x9D, int)
-#define PHONE_GET_TONE_ON_TIME _IO ('q', 0x9E)
-#define PHONE_GET_TONE_OFF_TIME _IO ('q', 0x9F)
-#define PHONE_GET_TONE_STATE _IO ('q', 0xA0)
-#define PHONE_BUSY _IO ('q', 0xA1)
-#define PHONE_RINGBACK _IO ('q', 0xA2)
-#define PHONE_DIALTONE _IO ('q', 0xA3)
-#define PHONE_CPT_STOP _IO ('q', 0xA4)
-
-#define PHONE_PSTN_SET_STATE _IOW ('q', 0xA4, int)
-#define PHONE_PSTN_GET_STATE _IO ('q', 0xA5)
-
-#define PSTN_ON_HOOK 0
-#define PSTN_RINGING 1
-#define PSTN_OFF_HOOK 2
-#define PSTN_PULSE_DIAL 3
-
-/******************************************************************************
-*
-* The wink duration is tunable with this ioctl. The default wink duration
-* is 320ms. You do not need to use this ioctl if you do not require a
-* different wink duration.
-*
-******************************************************************************/
-#define PHONE_WINK_DURATION _IOW ('q', 0xA6, int)
-#define PHONE_WINK _IOW ('q', 0xAA, int)
-
-/******************************************************************************
-*
-* Codec Definitions
-*
-******************************************************************************/
-typedef enum {
- G723_63 = 1,
- G723_53 = 2,
- TS85 = 3,
- TS48 = 4,
- TS41 = 5,
- G728 = 6,
- G729 = 7,
- ULAW = 8,
- ALAW = 9,
- LINEAR16 = 10,
- LINEAR8 = 11,
- WSS = 12,
- G729B = 13
-} phone_codec;
-
-struct phone_codec_data
-{
- phone_codec type;
- unsigned short buf_min, buf_opt, buf_max;
-};
-
-#define PHONE_QUERY_CODEC _IOWR ('q', 0xA7, struct phone_codec_data *)
-#define PHONE_PSTN_LINETEST _IO ('q', 0xA8)
-
-/******************************************************************************
-*
-* This controls the VAD/CNG functionality of G.723.1. The driver will
-* always pass full size frames, any unused bytes will be padded with zeros,
-* and frames passed to the driver should also be padded with zeros. The
-* frame type is encoded in the least significant two bits of the first
-* WORD of the frame as follows:
-*
-* bits 1-0 Frame Type Data Rate Significant Words
-* 00 0 G.723.1 6.3 12
-* 01 1 G.723.1 5.3 10
-* 10 2 VAD/CNG 2
-* 11 3 Repeat last CNG 2 bits
-*
-******************************************************************************/
-#define PHONE_VAD _IOW ('q', 0xA9, int)
-
-
-/******************************************************************************
-*
-* The exception structure allows us to multiplex multiple events onto the
-* select() exception set. If any of these flags are set select() will
-* return with a positive indication on the exception set. The dtmf_ready
-* bit indicates if there is data waiting in the DTMF buffer. The
-* hookstate bit is set if there is a change in hookstate status, it does not
-* indicate the current state of the hookswitch. The pstn_ring bit
-* indicates that the DAA on a LineJACK card has detected ring voltage on
-* the PSTN port. The caller_id bit indicates that caller_id data has been
-* received and is available. The pstn_wink bit indicates that the DAA on
-* the LineJACK has received a wink from the telco switch. The f0, f1, f2
-* and f3 bits indicate that the filter has been triggered by detecting the
-* frequency programmed into that filter.
-*
-* The remaining bits should be set to zero. They will become defined over time
-* for other interface cards and their needs.
-*
-******************************************************************************/
-struct phone_except
-{
- unsigned int dtmf_ready:1;
- unsigned int hookstate:1;
- unsigned int pstn_ring:1;
- unsigned int caller_id:1;
- unsigned int pstn_wink:1;
- unsigned int f0:1;
- unsigned int f1:1;
- unsigned int f2:1;
- unsigned int f3:1;
- unsigned int flash:1;
- unsigned int fc0:1;
- unsigned int fc1:1;
- unsigned int fc2:1;
- unsigned int fc3:1;
- unsigned int reserved:18;
-};
-
-union telephony_exception {
- struct phone_except bits;
- unsigned int bytes;
-};
-
-
-#endif /* TELEPHONY_H */
-
diff --git a/include/uapi/linux/time.h b/include/uapi/linux/time.h
index 53f8dd84beb5..16a296612ba4 100644
--- a/include/uapi/linux/time.h
+++ b/include/uapi/linux/time.h
@@ -43,6 +43,18 @@ struct itimerval {
};
/*
+ * legacy timeval structure, only embedded in structures that
+ * traditionally used 'timeval' to pass time intervals (not absolute
+ * times). Do not add new users. If user space fails to compile
+ * here, this is probably because it is not y2038 safe and needs to
+ * be changed to use another interface.
+ */
+struct __kernel_old_timeval {
+ __kernel_long_t tv_sec;
+ __kernel_long_t tv_usec;
+};
+
+/*
* The IDs of the various system clocks (for POSIX.1b interval timers):
*/
#define CLOCK_REALTIME 0
@@ -61,6 +73,7 @@ struct itimerval {
*/
#define CLOCK_SGI_CYCLE 10
#define CLOCK_TAI 11
+#define CLOCK_MONOTONIC_ACTIVE 12
#define MAX_CLOCKS 16
#define CLOCKS_MASK (CLOCK_REALTIME | CLOCK_MONOTONIC)
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index cbbb750d87d1..8d473c979b61 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -589,6 +589,98 @@ enum v4l2_vp8_golden_frame_sel {
#define V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP (V4L2_CID_MPEG_BASE+510)
#define V4L2_CID_MPEG_VIDEO_VPX_PROFILE (V4L2_CID_MPEG_BASE+511)
+/* CIDs for HEVC encoding. */
+
+#define V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP (V4L2_CID_MPEG_BASE + 600)
+#define V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP (V4L2_CID_MPEG_BASE + 601)
+#define V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP (V4L2_CID_MPEG_BASE + 602)
+#define V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP (V4L2_CID_MPEG_BASE + 603)
+#define V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP (V4L2_CID_MPEG_BASE + 604)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP (V4L2_CID_MPEG_BASE + 605)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE (V4L2_CID_MPEG_BASE + 606)
+enum v4l2_mpeg_video_hevc_hier_coding_type {
+ V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B = 0,
+ V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER (V4L2_CID_MPEG_BASE + 607)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP (V4L2_CID_MPEG_BASE + 608)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP (V4L2_CID_MPEG_BASE + 609)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP (V4L2_CID_MPEG_BASE + 610)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP (V4L2_CID_MPEG_BASE + 611)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP (V4L2_CID_MPEG_BASE + 612)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP (V4L2_CID_MPEG_BASE + 613)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP (V4L2_CID_MPEG_BASE + 614)
+#define V4L2_CID_MPEG_VIDEO_HEVC_PROFILE (V4L2_CID_MPEG_BASE + 615)
+enum v4l2_mpeg_video_hevc_profile {
+ V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN = 0,
+ V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE = 1,
+ V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10 = 2,
+};
+#define V4L2_CID_MPEG_VIDEO_HEVC_LEVEL (V4L2_CID_MPEG_BASE + 616)
+enum v4l2_mpeg_video_hevc_level {
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_1 = 0,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_2 = 1,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1 = 2,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_3 = 3,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1 = 4,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_4 = 5,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1 = 6,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_5 = 7,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1 = 8,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2 = 9,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_6 = 10,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1 = 11,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2 = 12,
+};
+#define V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION (V4L2_CID_MPEG_BASE + 617)
+#define V4L2_CID_MPEG_VIDEO_HEVC_TIER (V4L2_CID_MPEG_BASE + 618)
+enum v4l2_mpeg_video_hevc_tier {
+ V4L2_MPEG_VIDEO_HEVC_TIER_MAIN = 0,
+ V4L2_MPEG_VIDEO_HEVC_TIER_HIGH = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH (V4L2_CID_MPEG_BASE + 619)
+#define V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE (V4L2_CID_MPEG_BASE + 620)
+enum v4l2_cid_mpeg_video_hevc_loop_filter_mode {
+ V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED = 0,
+ V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED = 1,
+ V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY = 2,
+};
+#define V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2 (V4L2_CID_MPEG_BASE + 621)
+#define V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2 (V4L2_CID_MPEG_BASE + 622)
+#define V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE (V4L2_CID_MPEG_BASE + 623)
+enum v4l2_cid_mpeg_video_hevc_refresh_type {
+ V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE = 0,
+ V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA = 1,
+ V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR = 2,
+};
+#define V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD (V4L2_CID_MPEG_BASE + 624)
+#define V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU (V4L2_CID_MPEG_BASE + 625)
+#define V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED (V4L2_CID_MPEG_BASE + 626)
+#define V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT (V4L2_CID_MPEG_BASE + 627)
+#define V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB (V4L2_CID_MPEG_BASE + 628)
+#define V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID (V4L2_CID_MPEG_BASE + 629)
+#define V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING (V4L2_CID_MPEG_BASE + 630)
+#define V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1 (V4L2_CID_MPEG_BASE + 631)
+#define V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT (V4L2_CID_MPEG_BASE + 632)
+#define V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION (V4L2_CID_MPEG_BASE + 633)
+#define V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE (V4L2_CID_MPEG_BASE + 634)
+#define V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD (V4L2_CID_MPEG_BASE + 635)
+enum v4l2_cid_mpeg_video_hevc_size_of_length_field {
+ V4L2_MPEG_VIDEO_HEVC_SIZE_0 = 0,
+ V4L2_MPEG_VIDEO_HEVC_SIZE_1 = 1,
+ V4L2_MPEG_VIDEO_HEVC_SIZE_2 = 2,
+ V4L2_MPEG_VIDEO_HEVC_SIZE_4 = 3,
+};
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR (V4L2_CID_MPEG_BASE + 636)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR (V4L2_CID_MPEG_BASE + 637)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR (V4L2_CID_MPEG_BASE + 638)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR (V4L2_CID_MPEG_BASE + 639)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR (V4L2_CID_MPEG_BASE + 640)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR (V4L2_CID_MPEG_BASE + 641)
+#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR (V4L2_CID_MPEG_BASE + 642)
+#define V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES (V4L2_CID_MPEG_BASE + 643)
+#define V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR (V4L2_CID_MPEG_BASE + 644)
+
/* MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */
#define V4L2_CID_MPEG_CX2341X_BASE (V4L2_CTRL_CLASS_MPEG | 0x1000)
#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+0)
@@ -657,7 +749,6 @@ enum v4l2_mpeg_mfc51_video_force_frame_type {
#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC (V4L2_CID_MPEG_MFC51_BASE+53)
#define V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P (V4L2_CID_MPEG_MFC51_BASE+54)
-
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/include/uapi/linux/v4l2-mediabus.h b/include/uapi/linux/v4l2-mediabus.h
index 6e20de63ec59..123a231001a8 100644
--- a/include/uapi/linux/v4l2-mediabus.h
+++ b/include/uapi/linux/v4l2-mediabus.h
@@ -18,8 +18,8 @@
/**
* struct v4l2_mbus_framefmt - frame format on the media bus
- * @width: frame width
- * @height: frame height
+ * @width: image width
+ * @height: image height
* @code: data format code (from enum v4l2_mbus_pixelcode)
* @field: used interlacing type (from enum v4l2_field)
* @colorspace: colorspace of the data (from enum v4l2_colorspace)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 982718965180..600877be5c22 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -635,6 +635,7 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */
#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* VP8 */
#define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0') /* VP9 */
+#define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') /* HEVC aka H.265 */
/* Vendor-specific formats */
#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
diff --git a/ipc/msg.c b/ipc/msg.c
index 9de48065c1ac..114a21189613 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -43,6 +43,23 @@
#include <linux/uaccess.h>
#include "util.h"
+/* one msq_queue structure for each present queue on the system */
+struct msg_queue {
+ struct kern_ipc_perm q_perm;
+ time64_t q_stime; /* last msgsnd time */
+ time64_t q_rtime; /* last msgrcv time */
+ time64_t q_ctime; /* last change time */
+ unsigned long q_cbytes; /* current number of bytes on queue */
+ unsigned long q_qnum; /* number of messages in queue */
+ unsigned long q_qbytes; /* max number of bytes on queue */
+ struct pid *q_lspid; /* pid of last msgsnd */
+ struct pid *q_lrpid; /* last receive pid */
+
+ struct list_head q_messages;
+ struct list_head q_receivers;
+ struct list_head q_senders;
+} __randomize_layout;
+
/* one msg_receiver structure for each sleeping receiver */
struct msg_receiver {
struct list_head r_list;
@@ -101,7 +118,7 @@ static void msg_rcu_free(struct rcu_head *head)
struct kern_ipc_perm *p = container_of(head, struct kern_ipc_perm, rcu);
struct msg_queue *msq = container_of(p, struct msg_queue, q_perm);
- security_msg_queue_free(msq);
+ security_msg_queue_free(&msq->q_perm);
kvfree(msq);
}
@@ -127,7 +144,7 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
msq->q_perm.key = key;
msq->q_perm.security = NULL;
- retval = security_msg_queue_alloc(msq);
+ retval = security_msg_queue_alloc(&msq->q_perm);
if (retval) {
kvfree(msq);
return retval;
@@ -137,7 +154,7 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
msq->q_ctime = ktime_get_real_seconds();
msq->q_cbytes = msq->q_qnum = 0;
msq->q_qbytes = ns->msg_ctlmnb;
- msq->q_lspid = msq->q_lrpid = 0;
+ msq->q_lspid = msq->q_lrpid = NULL;
INIT_LIST_HEAD(&msq->q_messages);
INIT_LIST_HEAD(&msq->q_receivers);
INIT_LIST_HEAD(&msq->q_senders);
@@ -250,25 +267,17 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
free_msg(msg);
}
atomic_sub(msq->q_cbytes, &ns->msg_bytes);
+ ipc_update_pid(&msq->q_lspid, NULL);
+ ipc_update_pid(&msq->q_lrpid, NULL);
ipc_rcu_putref(&msq->q_perm, msg_rcu_free);
}
-/*
- * Called with msg_ids.rwsem and ipcp locked.
- */
-static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg)
-{
- struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
-
- return security_msg_queue_associate(msq, msgflg);
-}
-
long ksys_msgget(key_t key, int msgflg)
{
struct ipc_namespace *ns;
static const struct ipc_ops msg_ops = {
.getnew = newque,
- .associate = msg_security,
+ .associate = security_msg_queue_associate,
};
struct ipc_params msg_params;
@@ -385,7 +394,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
msq = container_of(ipcp, struct msg_queue, q_perm);
- err = security_msg_queue_msgctl(msq, cmd);
+ err = security_msg_queue_msgctl(&msq->q_perm, cmd);
if (err)
goto out_unlock1;
@@ -507,7 +516,7 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
if (ipcperms(ns, &msq->q_perm, S_IRUGO))
goto out_unlock;
- err = security_msg_queue_msgctl(msq, cmd);
+ err = security_msg_queue_msgctl(&msq->q_perm, cmd);
if (err)
goto out_unlock;
@@ -526,8 +535,8 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
p->msg_cbytes = msq->q_cbytes;
p->msg_qnum = msq->q_qnum;
p->msg_qbytes = msq->q_qbytes;
- p->msg_lspid = msq->q_lspid;
- p->msg_lrpid = msq->q_lrpid;
+ p->msg_lspid = pid_vnr(msq->q_lspid);
+ p->msg_lrpid = pid_vnr(msq->q_lrpid);
ipc_unlock_object(&msq->q_perm);
rcu_read_unlock();
@@ -733,7 +742,7 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg,
list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
if (testmsg(msg, msr->r_msgtype, msr->r_mode) &&
- !security_msg_queue_msgrcv(msq, msg, msr->r_tsk,
+ !security_msg_queue_msgrcv(&msq->q_perm, msg, msr->r_tsk,
msr->r_msgtype, msr->r_mode)) {
list_del(&msr->r_list);
@@ -741,7 +750,7 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg,
wake_q_add(wake_q, msr->r_tsk);
WRITE_ONCE(msr->r_msg, ERR_PTR(-E2BIG));
} else {
- msq->q_lrpid = task_pid_vnr(msr->r_tsk);
+ ipc_update_pid(&msq->q_lrpid, task_pid(msr->r_tsk));
msq->q_rtime = get_seconds();
wake_q_add(wake_q, msr->r_tsk);
@@ -799,7 +808,7 @@ static long do_msgsnd(int msqid, long mtype, void __user *mtext,
goto out_unlock0;
}
- err = security_msg_queue_msgsnd(msq, msg, msgflg);
+ err = security_msg_queue_msgsnd(&msq->q_perm, msg, msgflg);
if (err)
goto out_unlock0;
@@ -842,7 +851,7 @@ static long do_msgsnd(int msqid, long mtype, void __user *mtext,
}
- msq->q_lspid = task_tgid_vnr(current);
+ ipc_update_pid(&msq->q_lspid, task_tgid(current));
msq->q_stime = get_seconds();
if (!pipelined_send(msq, msg, &wake_q)) {
@@ -987,7 +996,7 @@ static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode)
list_for_each_entry(msg, &msq->q_messages, m_list) {
if (testmsg(msg, *msgtyp, mode) &&
- !security_msg_queue_msgrcv(msq, msg, current,
+ !security_msg_queue_msgrcv(&msq->q_perm, msg, current,
*msgtyp, mode)) {
if (mode == SEARCH_LESSEQUAL && msg->m_type != 1) {
*msgtyp = msg->m_type - 1;
@@ -1072,7 +1081,7 @@ static long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, in
list_del(&msg->m_list);
msq->q_qnum--;
msq->q_rtime = get_seconds();
- msq->q_lrpid = task_tgid_vnr(current);
+ ipc_update_pid(&msq->q_lrpid, task_tgid(current));
msq->q_cbytes -= msg->m_ts;
atomic_sub(msg->m_ts, &ns->msg_bytes);
atomic_dec(&ns->msg_hdrs);
@@ -1227,6 +1236,7 @@ void msg_exit_ns(struct ipc_namespace *ns)
#ifdef CONFIG_PROC_FS
static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
{
+ struct pid_namespace *pid_ns = ipc_seq_pid_ns(s);
struct user_namespace *user_ns = seq_user_ns(s);
struct kern_ipc_perm *ipcp = it;
struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
@@ -1238,8 +1248,8 @@ static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
msq->q_perm.mode,
msq->q_cbytes,
msq->q_qnum,
- msq->q_lspid,
- msq->q_lrpid,
+ pid_nr_ns(msq->q_lspid, pid_ns),
+ pid_nr_ns(msq->q_lrpid, pid_ns),
from_kuid_munged(user_ns, msq->q_perm.uid),
from_kgid_munged(user_ns, msq->q_perm.gid),
from_kuid_munged(user_ns, msq->q_perm.cuid),
diff --git a/ipc/sem.c b/ipc/sem.c
index 1cf56279a84c..2994da8ccc7f 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -88,13 +88,47 @@
#include <linux/uaccess.h>
#include "util.h"
+/* One semaphore structure for each semaphore in the system. */
+struct sem {
+ int semval; /* current value */
+ /*
+ * PID of the process that last modified the semaphore. For
+ * Linux, specifically these are:
+ * - semop
+ * - semctl, via SETVAL and SETALL.
+ * - at task exit when performing undo adjustments (see exit_sem).
+ */
+ struct pid *sempid;
+ spinlock_t lock; /* spinlock for fine-grained semtimedop */
+ struct list_head pending_alter; /* pending single-sop operations */
+ /* that alter the semaphore */
+ struct list_head pending_const; /* pending single-sop operations */
+ /* that do not alter the semaphore*/
+ time_t sem_otime; /* candidate for sem_otime */
+} ____cacheline_aligned_in_smp;
+
+/* One sem_array data structure for each set of semaphores in the system. */
+struct sem_array {
+ struct kern_ipc_perm sem_perm; /* permissions .. see ipc.h */
+ time64_t sem_ctime; /* create/last semctl() time */
+ struct list_head pending_alter; /* pending operations */
+ /* that alter the array */
+ struct list_head pending_const; /* pending complex operations */
+ /* that do not alter semvals */
+ struct list_head list_id; /* undo requests on this array */
+ int sem_nsems; /* no. of semaphores in array */
+ int complex_count; /* pending complex operations */
+ unsigned int use_global_lock;/* >0: global lock required */
+
+ struct sem sems[];
+} __randomize_layout;
/* One queue for each sleeping process in the system. */
struct sem_queue {
struct list_head list; /* queue of pending operations */
struct task_struct *sleeper; /* this process */
struct sem_undo *undo; /* undo structure */
- int pid; /* process id of requesting process */
+ struct pid *pid; /* process id of requesting process */
int status; /* completion status of operation */
struct sembuf *sops; /* array of pending operations */
struct sembuf *blocking; /* the operation that blocked */
@@ -265,7 +299,7 @@ static void sem_rcu_free(struct rcu_head *head)
struct kern_ipc_perm *p = container_of(head, struct kern_ipc_perm, rcu);
struct sem_array *sma = container_of(p, struct sem_array, sem_perm);
- security_sem_free(sma);
+ security_sem_free(&sma->sem_perm);
kvfree(sma);
}
@@ -495,7 +529,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
sma->sem_perm.key = key;
sma->sem_perm.security = NULL;
- retval = security_sem_alloc(sma);
+ retval = security_sem_alloc(&sma->sem_perm);
if (retval) {
kvfree(sma);
return retval;
@@ -533,17 +567,6 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
/*
* Called with sem_ids.rwsem and ipcp locked.
*/
-static inline int sem_security(struct kern_ipc_perm *ipcp, int semflg)
-{
- struct sem_array *sma;
-
- sma = container_of(ipcp, struct sem_array, sem_perm);
- return security_sem_associate(sma, semflg);
-}
-
-/*
- * Called with sem_ids.rwsem and ipcp locked.
- */
static inline int sem_more_checks(struct kern_ipc_perm *ipcp,
struct ipc_params *params)
{
@@ -561,7 +584,7 @@ long ksys_semget(key_t key, int nsems, int semflg)
struct ipc_namespace *ns;
static const struct ipc_ops sem_ops = {
.getnew = newary,
- .associate = sem_security,
+ .associate = security_sem_associate,
.more_checks = sem_more_checks,
};
struct ipc_params sem_params;
@@ -602,7 +625,8 @@ SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg)
*/
static int perform_atomic_semop_slow(struct sem_array *sma, struct sem_queue *q)
{
- int result, sem_op, nsops, pid;
+ int result, sem_op, nsops;
+ struct pid *pid;
struct sembuf *sop;
struct sem *curr;
struct sembuf *sops;
@@ -640,7 +664,7 @@ static int perform_atomic_semop_slow(struct sem_array *sma, struct sem_queue *q)
sop--;
pid = q->pid;
while (sop >= sops) {
- sma->sems[sop->sem_num].sempid = pid;
+ ipc_update_pid(&sma->sems[sop->sem_num].sempid, pid);
sop--;
}
@@ -727,7 +751,7 @@ static int perform_atomic_semop(struct sem_array *sma, struct sem_queue *q)
un->semadj[sop->sem_num] = undo;
}
curr->semval += sem_op;
- curr->sempid = q->pid;
+ ipc_update_pid(&curr->sempid, q->pid);
}
return 0;
@@ -1134,6 +1158,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
unlink_queue(sma, q);
wake_up_sem_queue_prepare(q, -EIDRM, &wake_q);
}
+ ipc_update_pid(&sem->sempid, NULL);
}
/* Remove the semaphore set from the IDR */
@@ -1214,7 +1239,7 @@ static int semctl_stat(struct ipc_namespace *ns, int semid,
if (ipcperms(ns, &sma->sem_perm, S_IRUGO))
goto out_unlock;
- err = security_sem_semctl(sma, cmd);
+ err = security_sem_semctl(&sma->sem_perm, cmd);
if (err)
goto out_unlock;
@@ -1305,7 +1330,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
return -EACCES;
}
- err = security_sem_semctl(sma, SETVAL);
+ err = security_sem_semctl(&sma->sem_perm, SETVAL);
if (err) {
rcu_read_unlock();
return -EACCES;
@@ -1326,7 +1351,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
un->semadj[semnum] = 0;
curr->semval = val;
- curr->sempid = task_tgid_vnr(current);
+ ipc_update_pid(&curr->sempid, task_tgid(current));
sma->sem_ctime = ktime_get_real_seconds();
/* maybe some queued-up processes were waiting for this */
do_smart_update(sma, NULL, 0, 0, &wake_q);
@@ -1359,7 +1384,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
if (ipcperms(ns, &sma->sem_perm, cmd == SETALL ? S_IWUGO : S_IRUGO))
goto out_rcu_wakeup;
- err = security_sem_semctl(sma, cmd);
+ err = security_sem_semctl(&sma->sem_perm, cmd);
if (err)
goto out_rcu_wakeup;
@@ -1447,7 +1472,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
for (i = 0; i < nsems; i++) {
sma->sems[i].semval = sem_io[i];
- sma->sems[i].sempid = task_tgid_vnr(current);
+ ipc_update_pid(&sma->sems[i].sempid, task_tgid(current));
}
ipc_assert_locked_object(&sma->sem_perm);
@@ -1479,7 +1504,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
err = curr->semval;
goto out_unlock;
case GETPID:
- err = curr->sempid;
+ err = pid_vnr(curr->sempid);
goto out_unlock;
case GETNCNT:
err = count_semcnt(sma, semnum, 0);
@@ -1550,7 +1575,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
sma = container_of(ipcp, struct sem_array, sem_perm);
- err = security_sem_semctl(sma, cmd);
+ err = security_sem_semctl(&sma->sem_perm, cmd);
if (err)
goto out_unlock1;
@@ -1977,7 +2002,7 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops,
goto out_free;
}
- error = security_sem_semop(sma, sops, nsops, alter);
+ error = security_sem_semop(&sma->sem_perm, sops, nsops, alter);
if (error) {
rcu_read_unlock();
goto out_free;
@@ -2008,7 +2033,7 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops,
queue.sops = sops;
queue.nsops = nsops;
queue.undo = un;
- queue.pid = task_tgid_vnr(current);
+ queue.pid = task_tgid(current);
queue.alter = alter;
queue.dupsop = dupsop;
@@ -2315,7 +2340,7 @@ void exit_sem(struct task_struct *tsk)
semaphore->semval = 0;
if (semaphore->semval > SEMVMX)
semaphore->semval = SEMVMX;
- semaphore->sempid = task_tgid_vnr(current);
+ ipc_update_pid(&semaphore->sempid, task_tgid(current));
}
}
/* maybe some queued-up processes were waiting for this */
diff --git a/ipc/shm.c b/ipc/shm.c
index c38c8425a89e..acefe44fefef 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -48,6 +48,28 @@
#include "util.h"
+struct shmid_kernel /* private to the kernel */
+{
+ struct kern_ipc_perm shm_perm;
+ struct file *shm_file;
+ unsigned long shm_nattch;
+ unsigned long shm_segsz;
+ time64_t shm_atim;
+ time64_t shm_dtim;
+ time64_t shm_ctim;
+ struct pid *shm_cprid;
+ struct pid *shm_lprid;
+ struct user_struct *mlock_user;
+
+ /* The task created the shm object. NULL if the task is dead. */
+ struct task_struct *shm_creator;
+ struct list_head shm_clist; /* list by creator */
+} __randomize_layout;
+
+/* shm_mode upper byte flags */
+#define SHM_DEST 01000 /* segment will be destroyed on last detach */
+#define SHM_LOCKED 02000 /* segment will not be swapped */
+
struct shm_file_data {
int id;
struct ipc_namespace *ns;
@@ -181,7 +203,7 @@ static void shm_rcu_free(struct rcu_head *head)
rcu);
struct shmid_kernel *shp = container_of(ptr, struct shmid_kernel,
shm_perm);
- security_shm_free(shp);
+ security_shm_free(&shp->shm_perm);
kvfree(shp);
}
@@ -204,7 +226,7 @@ static int __shm_open(struct vm_area_struct *vma)
return PTR_ERR(shp);
shp->shm_atim = ktime_get_real_seconds();
- shp->shm_lprid = task_tgid_vnr(current);
+ ipc_update_pid(&shp->shm_lprid, task_tgid(current));
shp->shm_nattch++;
shm_unlock(shp);
return 0;
@@ -245,6 +267,8 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
user_shm_unlock(i_size_read(file_inode(shm_file)),
shp->mlock_user);
fput(shm_file);
+ ipc_update_pid(&shp->shm_cprid, NULL);
+ ipc_update_pid(&shp->shm_lprid, NULL);
ipc_rcu_putref(&shp->shm_perm, shm_rcu_free);
}
@@ -289,7 +313,7 @@ static void shm_close(struct vm_area_struct *vma)
if (WARN_ON_ONCE(IS_ERR(shp)))
goto done; /* no-op */
- shp->shm_lprid = task_tgid_vnr(current);
+ ipc_update_pid(&shp->shm_lprid, task_tgid(current));
shp->shm_dtim = ktime_get_real_seconds();
shp->shm_nattch--;
if (shm_may_destroy(ns, shp))
@@ -566,7 +590,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
shp->mlock_user = NULL;
shp->shm_perm.security = NULL;
- error = security_shm_alloc(shp);
+ error = security_shm_alloc(&shp->shm_perm);
if (error) {
kvfree(shp);
return error;
@@ -604,8 +628,8 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
if (IS_ERR(file))
goto no_file;
- shp->shm_cprid = task_tgid_vnr(current);
- shp->shm_lprid = 0;
+ shp->shm_cprid = get_pid(task_tgid(current));
+ shp->shm_lprid = NULL;
shp->shm_atim = shp->shm_dtim = 0;
shp->shm_ctim = ktime_get_real_seconds();
shp->shm_segsz = size;
@@ -634,6 +658,8 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
return error;
no_id:
+ ipc_update_pid(&shp->shm_cprid, NULL);
+ ipc_update_pid(&shp->shm_lprid, NULL);
if (is_file_hugepages(file) && shp->mlock_user)
user_shm_unlock(size, shp->mlock_user);
fput(file);
@@ -645,17 +671,6 @@ no_file:
/*
* Called with shm_ids.rwsem and ipcp locked.
*/
-static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg)
-{
- struct shmid_kernel *shp;
-
- shp = container_of(ipcp, struct shmid_kernel, shm_perm);
- return security_shm_associate(shp, shmflg);
-}
-
-/*
- * Called with shm_ids.rwsem and ipcp locked.
- */
static inline int shm_more_checks(struct kern_ipc_perm *ipcp,
struct ipc_params *params)
{
@@ -673,7 +688,7 @@ long ksys_shmget(key_t key, size_t size, int shmflg)
struct ipc_namespace *ns;
static const struct ipc_ops shm_ops = {
.getnew = newseg,
- .associate = shm_security,
+ .associate = security_shm_associate,
.more_checks = shm_more_checks,
};
struct ipc_params shm_params;
@@ -852,7 +867,7 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
shp = container_of(ipcp, struct shmid_kernel, shm_perm);
- err = security_shm_shmctl(shp, cmd);
+ err = security_shm_shmctl(&shp->shm_perm, cmd);
if (err)
goto out_unlock1;
@@ -951,7 +966,7 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
if (ipcperms(ns, &shp->shm_perm, S_IRUGO))
goto out_unlock;
- err = security_shm_shmctl(shp, cmd);
+ err = security_shm_shmctl(&shp->shm_perm, cmd);
if (err)
goto out_unlock;
@@ -968,8 +983,8 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
tbuf->shm_atime = shp->shm_atim;
tbuf->shm_dtime = shp->shm_dtim;
tbuf->shm_ctime = shp->shm_ctim;
- tbuf->shm_cpid = shp->shm_cprid;
- tbuf->shm_lpid = shp->shm_lprid;
+ tbuf->shm_cpid = pid_vnr(shp->shm_cprid);
+ tbuf->shm_lpid = pid_vnr(shp->shm_lprid);
tbuf->shm_nattch = shp->shm_nattch;
ipc_unlock_object(&shp->shm_perm);
@@ -995,7 +1010,7 @@ static int shmctl_do_lock(struct ipc_namespace *ns, int shmid, int cmd)
}
audit_ipc_obj(&(shp->shm_perm));
- err = security_shm_shmctl(shp, cmd);
+ err = security_shm_shmctl(&shp->shm_perm, cmd);
if (err)
goto out_unlock1;
@@ -1375,7 +1390,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg,
if (ipcperms(ns, &shp->shm_perm, acc_mode))
goto out_unlock;
- err = security_shm_shmat(shp, shmaddr, shmflg);
+ err = security_shm_shmat(&shp->shm_perm, shmaddr, shmflg);
if (err)
goto out_unlock;
@@ -1618,6 +1633,7 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
#ifdef CONFIG_PROC_FS
static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
{
+ struct pid_namespace *pid_ns = ipc_seq_pid_ns(s);
struct user_namespace *user_ns = seq_user_ns(s);
struct kern_ipc_perm *ipcp = it;
struct shmid_kernel *shp;
@@ -1640,8 +1656,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
shp->shm_perm.id,
shp->shm_perm.mode,
shp->shm_segsz,
- shp->shm_cprid,
- shp->shm_lprid,
+ pid_nr_ns(shp->shm_cprid, pid_ns),
+ pid_nr_ns(shp->shm_lprid, pid_ns),
shp->shm_nattch,
from_kuid_munged(user_ns, shp->shm_perm.uid),
from_kgid_munged(user_ns, shp->shm_perm.gid),
diff --git a/ipc/util.c b/ipc/util.c
index 4ed5a17dd06f..3783b7991cc7 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -747,9 +747,16 @@ int ipc_parse_version(int *cmd)
#ifdef CONFIG_PROC_FS
struct ipc_proc_iter {
struct ipc_namespace *ns;
+ struct pid_namespace *pid_ns;
struct ipc_proc_iface *iface;
};
+struct pid_namespace *ipc_seq_pid_ns(struct seq_file *s)
+{
+ struct ipc_proc_iter *iter = s->private;
+ return iter->pid_ns;
+}
+
/*
* This routine locks the ipc structure found at least at position pos.
*/
@@ -872,6 +879,7 @@ static int sysvipc_proc_open(struct inode *inode, struct file *file)
iter->iface = PDE_DATA(inode);
iter->ns = get_ipc_ns(current->nsproxy->ipc_ns);
+ iter->pid_ns = get_pid_ns(task_active_pid_ns(current));
return 0;
}
@@ -881,6 +889,7 @@ static int sysvipc_proc_release(struct inode *inode, struct file *file)
struct seq_file *seq = file->private_data;
struct ipc_proc_iter *iter = seq->private;
put_ipc_ns(iter->ns);
+ put_pid_ns(iter->pid_ns);
return seq_release_private(inode, file);
}
diff --git a/ipc/util.h b/ipc/util.h
index 51853dc2f340..acc5159e96d0 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/ipc_namespace.h>
+#define IPCMNI 32768 /* <= MAX_INT limit for ipc arrays (including sysctl changes) */
#define SEQ_MULTIPLIER (IPCMNI)
int sem_init(void);
@@ -22,6 +23,7 @@ int msg_init(void);
void shm_init(void);
struct ipc_namespace;
+struct pid_namespace;
#ifdef CONFIG_POSIX_MQUEUE
extern void mq_clear_sbinfo(struct ipc_namespace *ns);
@@ -85,6 +87,7 @@ int ipc_init_ids(struct ipc_ids *);
#ifdef CONFIG_PROC_FS
void __init ipc_init_proc_interface(const char *path, const char *header,
int ids, int (*show)(struct seq_file *, void *));
+struct pid_namespace *ipc_seq_pid_ns(struct seq_file *);
#else
#define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
#endif
@@ -149,6 +152,15 @@ struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns,
struct ipc_ids *ids, int id, int cmd,
struct ipc64_perm *perm, int extra_perm);
+static inline void ipc_update_pid(struct pid **pos, struct pid *pid)
+{
+ struct pid *old = *pos;
+ if (old != pid) {
+ *pos = get_pid(pid);
+ put_pid(old);
+ }
+}
+
#ifndef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
/* On IA-64, we always use the "64-bit version" of the IPC structures. */
# define ipc_parse_version(cmd) IPC_64
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 4bfb2908ec15..a662bfcbea0e 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -4524,10 +4524,10 @@ static struct cftype cgroup_base_files[] = {
* and thus involve punting to css->destroy_work adding two additional
* steps to the already complex sequence.
*/
-static void css_free_work_fn(struct work_struct *work)
+static void css_free_rwork_fn(struct work_struct *work)
{
- struct cgroup_subsys_state *css =
- container_of(work, struct cgroup_subsys_state, destroy_work);
+ struct cgroup_subsys_state *css = container_of(to_rcu_work(work),
+ struct cgroup_subsys_state, destroy_rwork);
struct cgroup_subsys *ss = css->ss;
struct cgroup *cgrp = css->cgroup;
@@ -4573,15 +4573,6 @@ static void css_free_work_fn(struct work_struct *work)
}
}
-static void css_free_rcu_fn(struct rcu_head *rcu_head)
-{
- struct cgroup_subsys_state *css =
- container_of(rcu_head, struct cgroup_subsys_state, rcu_head);
-
- INIT_WORK(&css->destroy_work, css_free_work_fn);
- queue_work(cgroup_destroy_wq, &css->destroy_work);
-}
-
static void css_release_work_fn(struct work_struct *work)
{
struct cgroup_subsys_state *css =
@@ -4631,7 +4622,8 @@ static void css_release_work_fn(struct work_struct *work)
mutex_unlock(&cgroup_mutex);
- call_rcu(&css->rcu_head, css_free_rcu_fn);
+ INIT_RCU_WORK(&css->destroy_rwork, css_free_rwork_fn);
+ queue_rcu_work(cgroup_destroy_wq, &css->destroy_rwork);
}
static void css_release(struct percpu_ref *ref)
@@ -4765,7 +4757,8 @@ static struct cgroup_subsys_state *css_create(struct cgroup *cgrp,
err_list_del:
list_del_rcu(&css->sibling);
err_free_css:
- call_rcu(&css->rcu_head, css_free_rcu_fn);
+ INIT_RCU_WORK(&css->destroy_rwork, css_free_rwork_fn);
+ queue_rcu_work(cgroup_destroy_wq, &css->destroy_rwork);
return ERR_PTR(err);
}
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index 6fc87ccda1d7..c6766f326072 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -132,3 +132,9 @@ config GENERIC_IRQ_DEBUGFS
If you don't know what to do here, say N.
endmenu
+
+config GENERIC_IRQ_MULTI_HANDLER
+ depends on !MULTI_IRQ_HANDLER
+ bool
+ help
+ Allow to specify the low level IRQ handler at run time.
diff --git a/kernel/irq/autoprobe.c b/kernel/irq/autoprobe.c
index 8c82ea26e837..16cbf6beb276 100644
--- a/kernel/irq/autoprobe.c
+++ b/kernel/irq/autoprobe.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * linux/kernel/irq/autoprobe.c
- *
* Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
*
* This file contains the interrupt probing code and driver APIs.
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index c69357a43849..a2b3d9de999c 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -1,13 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * linux/kernel/irq/chip.c
- *
* Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
* Copyright (C) 2005-2006, Thomas Gleixner, Russell King
*
- * This file contains the core interrupt handling code, for irq-chip
- * based architectures.
- *
- * Detailed information is available in Documentation/core-api/genericirq.rst
+ * This file contains the core interrupt handling code, for irq-chip based
+ * architectures. Detailed information is available in
+ * Documentation/core-api/genericirq.rst
*/
#include <linux/irq.h>
diff --git a/kernel/irq/cpuhotplug.c b/kernel/irq/cpuhotplug.c
index 9eb09aef0313..5b1072e394b2 100644
--- a/kernel/irq/cpuhotplug.c
+++ b/kernel/irq/cpuhotplug.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Generic cpu hotunplug interrupt migration code copied from the
* arch/arm implementation
diff --git a/kernel/irq/debugfs.c b/kernel/irq/debugfs.c
index acfaaef8672a..4dadeb3d6666 100644
--- a/kernel/irq/debugfs.c
+++ b/kernel/irq/debugfs.c
@@ -1,8 +1,6 @@
-/*
- * Copyright 2017 Thomas Gleixner <tglx@linutronix.de>
- *
- * This file is licensed under the GPL V2.
- */
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2017 Thomas Gleixner <tglx@linutronix.de>
+
#include <linux/irqdomain.h>
#include <linux/irq.h>
#include <linux/uaccess.h>
diff --git a/kernel/irq/devres.c b/kernel/irq/devres.c
index 194c506d9d20..6a682c229e10 100644
--- a/kernel/irq/devres.c
+++ b/kernel/irq/devres.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/device.h>
diff --git a/kernel/irq/dummychip.c b/kernel/irq/dummychip.c
index 326a67f2410b..0b0cdf206dc4 100644
--- a/kernel/irq/dummychip.c
+++ b/kernel/irq/dummychip.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
* Copyright (C) 2005-2006, Thomas Gleixner, Russell King
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c
index 508c03dfef25..e2999a070a99 100644
--- a/kernel/irq/generic-chip.c
+++ b/kernel/irq/generic-chip.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Library implementing the most common irq chip callback functions
*
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 79f987b942b8..38554bc35375 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -1,12 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * linux/kernel/irq/handle.c
- *
* Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
* Copyright (C) 2005-2006, Thomas Gleixner, Russell King
*
- * This file contains the core interrupt handling code.
- *
- * Detailed information is available in Documentation/core-api/genericirq.rst
+ * This file contains the core interrupt handling code. Detailed
+ * information is available in Documentation/core-api/genericirq.rst
*
*/
@@ -20,6 +18,10 @@
#include "internals.h"
+#ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER
+void (*handle_arch_irq)(struct pt_regs *) __ro_after_init;
+#endif
+
/**
* handle_bad_irq - handle spurious and unhandled irqs
* @desc: description of the interrupt
@@ -207,3 +209,14 @@ irqreturn_t handle_irq_event(struct irq_desc *desc)
irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
return ret;
}
+
+#ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER
+int __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
+{
+ if (handle_arch_irq)
+ return -EBUSY;
+
+ handle_arch_irq = handle_irq;
+ return 0;
+}
+#endif
diff --git a/kernel/irq/ipi.c b/kernel/irq/ipi.c
index 259a22aa9934..8b778e37dc6d 100644
--- a/kernel/irq/ipi.c
+++ b/kernel/irq/ipi.c
@@ -1,6 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * linux/kernel/irq/ipi.c
- *
* Copyright (C) 2015 Imagination Technologies Ltd
* Author: Qais Yousef <qais.yousef@imgtec.com>
*
diff --git a/kernel/irq/irq_sim.c b/kernel/irq/irq_sim.c
index 24caabf1a0f7..fc4f361a86bb 100644
--- a/kernel/irq/irq_sim.c
+++ b/kernel/irq/irq_sim.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2017 Bartosz Golaszewski <brgl@bgdev.pl>
*
@@ -7,6 +8,7 @@
* option) any later version.
*/
+#include <linux/slab.h>
#include <linux/irq_sim.h>
#include <linux/irq.h>
@@ -49,7 +51,8 @@ static void irq_sim_handle_irq(struct irq_work *work)
* @sim: The interrupt simulator object to initialize.
* @num_irqs: Number of interrupts to allocate
*
- * Returns 0 on success and a negative error number on failure.
+ * On success: return the base of the allocated interrupt range.
+ * On failure: a negative errno.
*/
int irq_sim_init(struct irq_sim *sim, unsigned int num_irqs)
{
@@ -78,7 +81,7 @@ int irq_sim_init(struct irq_sim *sim, unsigned int num_irqs)
init_irq_work(&sim->work_ctx.work, irq_sim_handle_irq);
sim->irq_count = num_irqs;
- return 0;
+ return sim->irq_base;
}
EXPORT_SYMBOL_GPL(irq_sim_init);
@@ -110,7 +113,8 @@ static void devm_irq_sim_release(struct device *dev, void *res)
* @sim: The interrupt simulator object to initialize.
* @num_irqs: Number of interrupts to allocate
*
- * Returns 0 on success and a negative error number on failure.
+ * On success: return the base of the allocated interrupt range.
+ * On failure: a negative errno.
*/
int devm_irq_sim_init(struct device *dev, struct irq_sim *sim,
unsigned int num_irqs)
@@ -123,7 +127,7 @@ int devm_irq_sim_init(struct device *dev, struct irq_sim *sim,
return -ENOMEM;
rv = irq_sim_init(sim, num_irqs);
- if (rv) {
+ if (rv < 0) {
devres_free(dr);
return rv;
}
@@ -131,7 +135,7 @@ int devm_irq_sim_init(struct device *dev, struct irq_sim *sim,
dr->sim = sim;
devres_add(dev, dr);
- return 0;
+ return rv;
}
EXPORT_SYMBOL_GPL(devm_irq_sim_init);
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index 49b54e9979cc..afc7f902d74a 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -1,10 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
* Copyright (C) 2005-2006, Thomas Gleixner, Russell King
*
- * This file contains the interrupt descriptor management code
- *
- * Detailed information is available in Documentation/core-api/genericirq.rst
+ * This file contains the interrupt descriptor management code. Detailed
+ * information is available in Documentation/core-api/genericirq.rst
*
*/
#include <linux/irq.h>
@@ -210,6 +210,22 @@ static ssize_t type_show(struct kobject *kobj,
}
IRQ_ATTR_RO(type);
+static ssize_t wakeup_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct irq_desc *desc = container_of(kobj, struct irq_desc, kobj);
+ ssize_t ret = 0;
+
+ raw_spin_lock_irq(&desc->lock);
+ ret = sprintf(buf, "%s\n",
+ irqd_is_wakeup_set(&desc->irq_data) ? "enabled" : "disabled");
+ raw_spin_unlock_irq(&desc->lock);
+
+ return ret;
+
+}
+IRQ_ATTR_RO(wakeup);
+
static ssize_t name_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
@@ -253,6 +269,7 @@ static struct attribute *irq_attrs[] = {
&chip_name_attr.attr,
&hwirq_attr.attr,
&type_attr.attr,
+ &wakeup_attr.attr,
&name_attr.attr,
&actions_attr.attr,
NULL
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 82b8b18ee1eb..5d9fc01b60a6 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
#define pr_fmt(fmt) "irq: " fmt
#include <linux/acpi.h>
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 0f922729bab9..e3336d904f64 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1,6 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * linux/kernel/irq/manage.c
- *
* Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
* Copyright (C) 2005-2006 Thomas Gleixner
*
@@ -855,10 +854,14 @@ irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)
* This code is triggered unconditionally. Check the affinity
* mask pointer. For CPU_MASK_OFFSTACK=n this is optimized out.
*/
- if (cpumask_available(desc->irq_common_data.affinity))
- cpumask_copy(mask, desc->irq_common_data.affinity);
- else
+ if (cpumask_available(desc->irq_common_data.affinity)) {
+ const struct cpumask *m;
+
+ m = irq_data_get_effective_affinity_mask(&desc->irq_data);
+ cpumask_copy(mask, m);
+ } else {
valid = false;
+ }
raw_spin_unlock_irq(&desc->lock);
if (valid)
@@ -1519,9 +1522,9 @@ EXPORT_SYMBOL_GPL(setup_irq);
* Internal function to unregister an irqaction - used to free
* regular and special interrupts that are part of the architecture.
*/
-static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
+static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id)
{
- struct irq_desc *desc = irq_to_desc(irq);
+ unsigned irq = desc->irq_data.irq;
struct irqaction *action, **action_ptr;
unsigned long flags;
@@ -1651,7 +1654,7 @@ void remove_irq(unsigned int irq, struct irqaction *act)
struct irq_desc *desc = irq_to_desc(irq);
if (desc && !WARN_ON(irq_settings_is_per_cpu_devid(desc)))
- __free_irq(irq, act->dev_id);
+ __free_irq(desc, act->dev_id);
}
EXPORT_SYMBOL_GPL(remove_irq);
@@ -1685,7 +1688,7 @@ const void *free_irq(unsigned int irq, void *dev_id)
desc->affinity_notify = NULL;
#endif
- action = __free_irq(irq, dev_id);
+ action = __free_irq(desc, dev_id);
if (!action)
return NULL;
diff --git a/kernel/irq/matrix.c b/kernel/irq/matrix.c
index 4c5770407031..5092494bf261 100644
--- a/kernel/irq/matrix.c
+++ b/kernel/irq/matrix.c
@@ -1,8 +1,6 @@
-/*
- * Copyright (C) 2017 Thomas Gleixner <tglx@linutronix.de>
- *
- * SPDX-License-Identifier: GPL-2.0
- */
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2017 Thomas Gleixner <tglx@linutronix.de>
+
#include <linux/spinlock.h>
#include <linux/seq_file.h>
#include <linux/bitmap.h>
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 2f3c4f5382cc..2a8571f72b17 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -1,6 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * linux/kernel/irq/msi.c
- *
* Copyright (C) 2014 Intel Corp.
* Author: Jiang Liu <jiang.liu@linux.intel.com>
*
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
index 6bd9b58429cc..d6961d3c6f9e 100644
--- a/kernel/irq/pm.c
+++ b/kernel/irq/pm.c
@@ -1,6 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- * linux/kernel/irq/pm.c
- *
* Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
*
* This file contains power management functions related to interrupts.
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index e8f374971e37..7cb091d81d91 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * linux/kernel/irq/proc.c
- *
* Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
*
* This file contains the /proc/irq/ handling code.
diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c
index 1d08f45135c2..95414ad3506a 100644
--- a/kernel/irq/resend.c
+++ b/kernel/irq/resend.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * linux/kernel/irq/resend.c
- *
* Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
* Copyright (C) 2005-2006, Thomas Gleixner
*
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index 6cdecc6f4c53..d867d6ddafdd 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * linux/kernel/irq/spurious.c
- *
* Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
*
* This file contains spurious interrupt handling.
diff --git a/kernel/irq/timings.c b/kernel/irq/timings.c
index e0923fa4927a..1e4cb63a5c82 100644
--- a/kernel/irq/timings.c
+++ b/kernel/irq/timings.c
@@ -1,13 +1,6 @@
-/*
- * linux/kernel/irq/timings.c
- *
- * Copyright (C) 2016, Linaro Ltd - Daniel Lezcano <daniel.lezcano@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.
- *
- */
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2016, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org>
+
#include <linux/kernel.h>
#include <linux/percpu.h>
#include <linux/slab.h>
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index 93b57f026688..2a2ac53d8b8b 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -23,55 +23,39 @@
#include <linux/sched/signal.h>
#include <linux/idr.h>
-struct pid_cache {
- int nr_ids;
- char name[16];
- struct kmem_cache *cachep;
- struct list_head list;
-};
-
-static LIST_HEAD(pid_caches_lh);
static DEFINE_MUTEX(pid_caches_mutex);
static struct kmem_cache *pid_ns_cachep;
+/* MAX_PID_NS_LEVEL is needed for limiting size of 'struct pid' */
+#define MAX_PID_NS_LEVEL 32
+/* Write once array, filled from the beginning. */
+static struct kmem_cache *pid_cache[MAX_PID_NS_LEVEL];
/*
* creates the kmem cache to allocate pids from.
- * @nr_ids: the number of numerical ids this pid will have to carry
+ * @level: pid namespace level
*/
-static struct kmem_cache *create_pid_cachep(int nr_ids)
+static struct kmem_cache *create_pid_cachep(unsigned int level)
{
- struct pid_cache *pcache;
- struct kmem_cache *cachep;
-
+ /* Level 0 is init_pid_ns.pid_cachep */
+ struct kmem_cache **pkc = &pid_cache[level - 1];
+ struct kmem_cache *kc;
+ char name[4 + 10 + 1];
+ unsigned int len;
+
+ kc = READ_ONCE(*pkc);
+ if (kc)
+ return kc;
+
+ snprintf(name, sizeof(name), "pid_%u", level + 1);
+ len = sizeof(struct pid) + level * sizeof(struct upid);
mutex_lock(&pid_caches_mutex);
- list_for_each_entry(pcache, &pid_caches_lh, list)
- if (pcache->nr_ids == nr_ids)
- goto out;
-
- pcache = kmalloc(sizeof(struct pid_cache), GFP_KERNEL);
- if (pcache == NULL)
- goto err_alloc;
-
- snprintf(pcache->name, sizeof(pcache->name), "pid_%d", nr_ids);
- cachep = kmem_cache_create(pcache->name,
- sizeof(struct pid) + (nr_ids - 1) * sizeof(struct upid),
- 0, SLAB_HWCACHE_ALIGN, NULL);
- if (cachep == NULL)
- goto err_cachep;
-
- pcache->nr_ids = nr_ids;
- pcache->cachep = cachep;
- list_add(&pcache->list, &pid_caches_lh);
-out:
+ /* Name collision forces to do allocation under mutex. */
+ if (!*pkc)
+ *pkc = kmem_cache_create(name, len, 0, SLAB_HWCACHE_ALIGN, 0);
mutex_unlock(&pid_caches_mutex);
- return pcache->cachep;
-
-err_cachep:
- kfree(pcache);
-err_alloc:
- mutex_unlock(&pid_caches_mutex);
- return NULL;
+ /* current can fail, but someone else can succeed. */
+ return READ_ONCE(*pkc);
}
static void proc_cleanup_work(struct work_struct *work)
@@ -80,9 +64,6 @@ static void proc_cleanup_work(struct work_struct *work)
pid_ns_release_proc(ns);
}
-/* MAX_PID_NS_LEVEL is needed for limiting size of 'struct pid' */
-#define MAX_PID_NS_LEVEL 32
-
static struct ucounts *inc_pid_namespaces(struct user_namespace *ns)
{
return inc_ucount(ns, current_euid(), UCOUNT_PID_NAMESPACES);
@@ -119,7 +100,7 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns
idr_init(&ns->idr);
- ns->pid_cachep = create_pid_cachep(level + 1);
+ ns->pid_cachep = create_pid_cachep(level);
if (ns->pid_cachep == NULL)
goto out_free_idr;
diff --git a/kernel/signal.c b/kernel/signal.c
index f04466655238..47491aa3e790 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2844,10 +2844,6 @@ enum siginfo_layout siginfo_layout(int sig, int si_code)
if ((sig == SIGFPE) && (si_code == FPE_FIXME))
layout = SIL_FAULT;
#endif
-#ifdef BUS_FIXME
- if ((sig == SIGBUS) && (si_code == BUS_FIXME))
- layout = SIL_FAULT;
-#endif
}
return layout;
}
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 24d243ef8e71..177de3640c78 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -460,40 +460,46 @@ struct tasklet_head {
static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);
-void __tasklet_schedule(struct tasklet_struct *t)
+static void __tasklet_schedule_common(struct tasklet_struct *t,
+ struct tasklet_head __percpu *headp,
+ unsigned int softirq_nr)
{
+ struct tasklet_head *head;
unsigned long flags;
local_irq_save(flags);
+ head = this_cpu_ptr(headp);
t->next = NULL;
- *__this_cpu_read(tasklet_vec.tail) = t;
- __this_cpu_write(tasklet_vec.tail, &(t->next));
- raise_softirq_irqoff(TASKLET_SOFTIRQ);
+ *head->tail = t;
+ head->tail = &(t->next);
+ raise_softirq_irqoff(softirq_nr);
local_irq_restore(flags);
}
+
+void __tasklet_schedule(struct tasklet_struct *t)
+{
+ __tasklet_schedule_common(t, &tasklet_vec,
+ TASKLET_SOFTIRQ);
+}
EXPORT_SYMBOL(__tasklet_schedule);
void __tasklet_hi_schedule(struct tasklet_struct *t)
{
- unsigned long flags;
-
- local_irq_save(flags);
- t->next = NULL;
- *__this_cpu_read(tasklet_hi_vec.tail) = t;
- __this_cpu_write(tasklet_hi_vec.tail, &(t->next));
- raise_softirq_irqoff(HI_SOFTIRQ);
- local_irq_restore(flags);
+ __tasklet_schedule_common(t, &tasklet_hi_vec,
+ HI_SOFTIRQ);
}
EXPORT_SYMBOL(__tasklet_hi_schedule);
-static __latent_entropy void tasklet_action(struct softirq_action *a)
+static void tasklet_action_common(struct softirq_action *a,
+ struct tasklet_head *tl_head,
+ unsigned int softirq_nr)
{
struct tasklet_struct *list;
local_irq_disable();
- list = __this_cpu_read(tasklet_vec.head);
- __this_cpu_write(tasklet_vec.head, NULL);
- __this_cpu_write(tasklet_vec.tail, this_cpu_ptr(&tasklet_vec.head));
+ list = tl_head->head;
+ tl_head->head = NULL;
+ tl_head->tail = &tl_head->head;
local_irq_enable();
while (list) {
@@ -515,47 +521,21 @@ static __latent_entropy void tasklet_action(struct softirq_action *a)
local_irq_disable();
t->next = NULL;
- *__this_cpu_read(tasklet_vec.tail) = t;
- __this_cpu_write(tasklet_vec.tail, &(t->next));
- __raise_softirq_irqoff(TASKLET_SOFTIRQ);
+ *tl_head->tail = t;
+ tl_head->tail = &t->next;
+ __raise_softirq_irqoff(softirq_nr);
local_irq_enable();
}
}
-static __latent_entropy void tasklet_hi_action(struct softirq_action *a)
+static __latent_entropy void tasklet_action(struct softirq_action *a)
{
- struct tasklet_struct *list;
-
- local_irq_disable();
- list = __this_cpu_read(tasklet_hi_vec.head);
- __this_cpu_write(tasklet_hi_vec.head, NULL);
- __this_cpu_write(tasklet_hi_vec.tail, this_cpu_ptr(&tasklet_hi_vec.head));
- local_irq_enable();
-
- while (list) {
- struct tasklet_struct *t = list;
-
- list = list->next;
-
- if (tasklet_trylock(t)) {
- if (!atomic_read(&t->count)) {
- if (!test_and_clear_bit(TASKLET_STATE_SCHED,
- &t->state))
- BUG();
- t->func(t->data);
- tasklet_unlock(t);
- continue;
- }
- tasklet_unlock(t);
- }
+ tasklet_action_common(a, this_cpu_ptr(&tasklet_vec), TASKLET_SOFTIRQ);
+}
- local_irq_disable();
- t->next = NULL;
- *__this_cpu_read(tasklet_hi_vec.tail) = t;
- __this_cpu_write(tasklet_hi_vec.tail, &(t->next));
- __raise_softirq_irqoff(HI_SOFTIRQ);
- local_irq_enable();
- }
+static __latent_entropy void tasklet_hi_action(struct softirq_action *a)
+{
+ tasklet_action_common(a, this_cpu_ptr(&tasklet_hi_vec), HI_SOFTIRQ);
}
void tasklet_init(struct tasklet_struct *t,
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index f98f28c12020..bdf7090b106d 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -253,6 +253,10 @@ extern struct ctl_table random_table[];
extern struct ctl_table epoll_table[];
#endif
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+extern struct ctl_table firmware_config_table[];
+#endif
+
#ifdef HAVE_ARCH_PICK_MMAP_LAYOUT
int sysctl_legacy_va_layout;
#endif
@@ -748,6 +752,13 @@ static struct ctl_table kern_table[] = {
.mode = 0555,
.child = usermodehelper_table,
},
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+ {
+ .procname = "firmware_config",
+ .mode = 0555,
+ .child = firmware_config_table,
+ },
+#endif
{
.procname = "overflowuid",
.data = &overflowuid,
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index ec09ce9a6012..639321bf2e39 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -326,6 +326,17 @@ static int alarmtimer_resume(struct device *dev)
}
#endif
+static void
+__alarm_init(struct alarm *alarm, enum alarmtimer_type type,
+ enum alarmtimer_restart (*function)(struct alarm *, ktime_t))
+{
+ timerqueue_init(&alarm->node);
+ alarm->timer.function = alarmtimer_fired;
+ alarm->function = function;
+ alarm->type = type;
+ alarm->state = ALARMTIMER_STATE_INACTIVE;
+}
+
/**
* alarm_init - Initialize an alarm structure
* @alarm: ptr to alarm to be initialized
@@ -335,13 +346,9 @@ static int alarmtimer_resume(struct device *dev)
void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
enum alarmtimer_restart (*function)(struct alarm *, ktime_t))
{
- timerqueue_init(&alarm->node);
hrtimer_init(&alarm->timer, alarm_bases[type].base_clockid,
- HRTIMER_MODE_ABS);
- alarm->timer.function = alarmtimer_fired;
- alarm->function = function;
- alarm->type = type;
- alarm->state = ALARMTIMER_STATE_INACTIVE;
+ HRTIMER_MODE_ABS);
+ __alarm_init(alarm, type, function);
}
EXPORT_SYMBOL_GPL(alarm_init);
@@ -719,6 +726,8 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp,
__set_current_state(TASK_RUNNING);
+ destroy_hrtimer_on_stack(&alarm->timer);
+
if (!alarm->data)
return 0;
@@ -740,6 +749,15 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp,
return -ERESTART_RESTARTBLOCK;
}
+static void
+alarm_init_on_stack(struct alarm *alarm, enum alarmtimer_type type,
+ enum alarmtimer_restart (*function)(struct alarm *, ktime_t))
+{
+ hrtimer_init_on_stack(&alarm->timer, alarm_bases[type].base_clockid,
+ HRTIMER_MODE_ABS);
+ __alarm_init(alarm, type, function);
+}
+
/**
* alarm_timer_nsleep_restart - restartblock alarmtimer nsleep
* @restart: ptr to restart block
@@ -752,7 +770,7 @@ static long __sched alarm_timer_nsleep_restart(struct restart_block *restart)
ktime_t exp = restart->nanosleep.expires;
struct alarm alarm;
- alarm_init(&alarm, type, alarmtimer_nsleep_wakeup);
+ alarm_init_on_stack(&alarm, type, alarmtimer_nsleep_wakeup);
return alarmtimer_do_nsleep(&alarm, exp, type);
}
@@ -784,7 +802,7 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
if (!capable(CAP_WAKE_ALARM))
return -EPERM;
- alarm_init(&alarm, type, alarmtimer_nsleep_wakeup);
+ alarm_init_on_stack(&alarm, type, alarmtimer_nsleep_wakeup);
exp = timespec64_to_ktime(*tsreq);
/* Convert (if necessary) to absolute time */
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 65f9e3f24dde..0e974cface0b 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -594,6 +594,9 @@ static void __clocksource_select(bool skipcur)
if (!best)
return;
+ if (!strlen(override_name))
+ goto found;
+
/* Check for the override clocksource. */
list_for_each_entry(cs, &clocksource_list, list) {
if (skipcur && cs == curr_clocksource)
@@ -625,6 +628,7 @@ static void __clocksource_select(bool skipcur)
break;
}
+found:
if (curr_clocksource != best && !timekeeping_notify(best)) {
pr_info("Switched to clocksource %s\n", best->name);
curr_clocksource = best;
@@ -853,16 +857,16 @@ EXPORT_SYMBOL(clocksource_unregister);
#ifdef CONFIG_SYSFS
/**
- * sysfs_show_current_clocksources - sysfs interface for current clocksource
+ * current_clocksource_show - sysfs interface for current clocksource
* @dev: unused
* @attr: unused
* @buf: char buffer to be filled with clocksource list
*
* Provides sysfs interface for listing current clocksource.
*/
-static ssize_t
-sysfs_show_current_clocksources(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t current_clocksource_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
ssize_t count = 0;
@@ -891,7 +895,7 @@ ssize_t sysfs_get_uname(const char *buf, char *dst, size_t cnt)
}
/**
- * sysfs_override_clocksource - interface for manually overriding clocksource
+ * current_clocksource_store - interface for manually overriding clocksource
* @dev: unused
* @attr: unused
* @buf: name of override clocksource
@@ -900,9 +904,9 @@ ssize_t sysfs_get_uname(const char *buf, char *dst, size_t cnt)
* Takes input from sysfs interface for manually overriding the default
* clocksource selection.
*/
-static ssize_t sysfs_override_clocksource(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t current_clocksource_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
ssize_t ret;
@@ -916,9 +920,10 @@ static ssize_t sysfs_override_clocksource(struct device *dev,
return ret;
}
+static DEVICE_ATTR_RW(current_clocksource);
/**
- * sysfs_unbind_current_clocksource - interface for manually unbinding clocksource
+ * unbind_clocksource_store - interface for manually unbinding clocksource
* @dev: unused
* @attr: unused
* @buf: unused
@@ -926,7 +931,7 @@ static ssize_t sysfs_override_clocksource(struct device *dev,
*
* Takes input from sysfs interface for manually unbinding a clocksource.
*/
-static ssize_t sysfs_unbind_clocksource(struct device *dev,
+static ssize_t unbind_clocksource_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -950,19 +955,19 @@ static ssize_t sysfs_unbind_clocksource(struct device *dev,
return ret ? ret : count;
}
+static DEVICE_ATTR_WO(unbind_clocksource);
/**
- * sysfs_show_available_clocksources - sysfs interface for listing clocksource
+ * available_clocksource_show - sysfs interface for listing clocksource
* @dev: unused
* @attr: unused
* @buf: char buffer to be filled with clocksource list
*
* Provides sysfs interface for listing registered clocksources
*/
-static ssize_t
-sysfs_show_available_clocksources(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t available_clocksource_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct clocksource *src;
ssize_t count = 0;
@@ -986,17 +991,15 @@ sysfs_show_available_clocksources(struct device *dev,
return count;
}
+static DEVICE_ATTR_RO(available_clocksource);
-/*
- * Sysfs setup bits:
- */
-static DEVICE_ATTR(current_clocksource, 0644, sysfs_show_current_clocksources,
- sysfs_override_clocksource);
-
-static DEVICE_ATTR(unbind_clocksource, 0200, NULL, sysfs_unbind_clocksource);
-
-static DEVICE_ATTR(available_clocksource, 0444,
- sysfs_show_available_clocksources, NULL);
+static struct attribute *clocksource_attrs[] = {
+ &dev_attr_current_clocksource.attr,
+ &dev_attr_unbind_clocksource.attr,
+ &dev_attr_available_clocksource.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(clocksource);
static struct bus_type clocksource_subsys = {
.name = "clocksource",
@@ -1006,6 +1009,7 @@ static struct bus_type clocksource_subsys = {
static struct device device_clocksource = {
.id = 0,
.bus = &clocksource_subsys,
+ .groups = clocksource_groups,
};
static int __init init_clocksource_sysfs(void)
@@ -1014,17 +1018,7 @@ static int __init init_clocksource_sysfs(void)
if (!error)
error = device_register(&device_clocksource);
- if (!error)
- error = device_create_file(
- &device_clocksource,
- &dev_attr_current_clocksource);
- if (!error)
- error = device_create_file(&device_clocksource,
- &dev_attr_unbind_clocksource);
- if (!error)
- error = device_create_file(
- &device_clocksource,
- &dev_attr_available_clocksource);
+
return error;
}
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 23788100e214..9b082ce86325 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -91,11 +91,6 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
.get_time = &ktime_get_real,
},
{
- .index = HRTIMER_BASE_BOOTTIME,
- .clockid = CLOCK_BOOTTIME,
- .get_time = &ktime_get_boottime,
- },
- {
.index = HRTIMER_BASE_TAI,
.clockid = CLOCK_TAI,
.get_time = &ktime_get_clocktai,
@@ -111,11 +106,6 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
.get_time = &ktime_get_real,
},
{
- .index = HRTIMER_BASE_BOOTTIME_SOFT,
- .clockid = CLOCK_BOOTTIME,
- .get_time = &ktime_get_boottime,
- },
- {
.index = HRTIMER_BASE_TAI_SOFT,
.clockid = CLOCK_TAI,
.get_time = &ktime_get_clocktai,
@@ -129,7 +119,7 @@ static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = {
[CLOCK_REALTIME] = HRTIMER_BASE_REALTIME,
[CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC,
- [CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME,
+ [CLOCK_BOOTTIME] = HRTIMER_BASE_MONOTONIC,
[CLOCK_TAI] = HRTIMER_BASE_TAI,
};
@@ -565,14 +555,12 @@ __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base, unsigned int active_
static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
{
ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset;
- ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset;
ktime_t *offs_tai = &base->clock_base[HRTIMER_BASE_TAI].offset;
ktime_t now = ktime_get_update_offsets_now(&base->clock_was_set_seq,
- offs_real, offs_boot, offs_tai);
+ offs_real, offs_tai);
base->clock_base[HRTIMER_BASE_REALTIME_SOFT].offset = *offs_real;
- base->clock_base[HRTIMER_BASE_BOOTTIME_SOFT].offset = *offs_boot;
base->clock_base[HRTIMER_BASE_TAI_SOFT].offset = *offs_tai;
return now;
diff --git a/kernel/time/posix-stubs.c b/kernel/time/posix-stubs.c
index b258bee13b02..6259dbc0191a 100644
--- a/kernel/time/posix-stubs.c
+++ b/kernel/time/posix-stubs.c
@@ -73,6 +73,8 @@ int do_clock_gettime(clockid_t which_clock, struct timespec64 *tp)
case CLOCK_BOOTTIME:
get_monotonic_boottime64(tp);
break;
+ case CLOCK_MONOTONIC_ACTIVE:
+ ktime_get_active_ts64(tp);
default:
return -EINVAL;
}
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index 10b7186d0638..b6899b5060bd 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -252,15 +252,16 @@ static int posix_get_coarse_res(const clockid_t which_clock, struct timespec64 *
return 0;
}
-static int posix_get_boottime(const clockid_t which_clock, struct timespec64 *tp)
+static int posix_get_tai(clockid_t which_clock, struct timespec64 *tp)
{
- get_monotonic_boottime64(tp);
+ timekeeping_clocktai64(tp);
return 0;
}
-static int posix_get_tai(clockid_t which_clock, struct timespec64 *tp)
+static int posix_get_monotonic_active(clockid_t which_clock,
+ struct timespec64 *tp)
{
- timekeeping_clocktai64(tp);
+ ktime_get_active_ts64(tp);
return 0;
}
@@ -1316,19 +1317,9 @@ static const struct k_clock clock_tai = {
.timer_arm = common_hrtimer_arm,
};
-static const struct k_clock clock_boottime = {
+static const struct k_clock clock_monotonic_active = {
.clock_getres = posix_get_hrtimer_res,
- .clock_get = posix_get_boottime,
- .nsleep = common_nsleep,
- .timer_create = common_timer_create,
- .timer_set = common_timer_set,
- .timer_get = common_timer_get,
- .timer_del = common_timer_del,
- .timer_rearm = common_hrtimer_rearm,
- .timer_forward = common_hrtimer_forward,
- .timer_remaining = common_hrtimer_remaining,
- .timer_try_to_cancel = common_hrtimer_try_to_cancel,
- .timer_arm = common_hrtimer_arm,
+ .clock_get = posix_get_monotonic_active,
};
static const struct k_clock * const posix_clocks[] = {
@@ -1339,10 +1330,11 @@ static const struct k_clock * const posix_clocks[] = {
[CLOCK_MONOTONIC_RAW] = &clock_monotonic_raw,
[CLOCK_REALTIME_COARSE] = &clock_realtime_coarse,
[CLOCK_MONOTONIC_COARSE] = &clock_monotonic_coarse,
- [CLOCK_BOOTTIME] = &clock_boottime,
+ [CLOCK_BOOTTIME] = &clock_monotonic,
[CLOCK_REALTIME_ALARM] = &alarm_clock,
[CLOCK_BOOTTIME_ALARM] = &alarm_clock,
[CLOCK_TAI] = &clock_tai,
+ [CLOCK_MONOTONIC_ACTIVE] = &clock_monotonic_active,
};
static const struct k_clock *clockid_to_kclock(const clockid_t id)
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index 49edc1c4f3e6..099572ca4a8f 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -419,6 +419,19 @@ void tick_suspend_local(void)
clockevents_shutdown(td->evtdev);
}
+static void tick_forward_next_period(void)
+{
+ ktime_t delta, now = ktime_get();
+ u64 n;
+
+ delta = ktime_sub(now, tick_next_period);
+ n = ktime_divns(delta, tick_period);
+ tick_next_period += n * tick_period;
+ if (tick_next_period < now)
+ tick_next_period += tick_period;
+ tick_sched_forward_next_period();
+}
+
/**
* tick_resume_local - Resume the local tick device
*
@@ -431,6 +444,8 @@ void tick_resume_local(void)
struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
bool broadcast = tick_resume_check_broadcast();
+ tick_forward_next_period();
+
clockevents_tick_resume(td->evtdev);
if (!broadcast) {
if (td->mode == TICKDEV_MODE_PERIODIC)
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index e277284c2831..21efab7485ca 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -141,6 +141,12 @@ static inline void tick_check_oneshot_broadcast_this_cpu(void) { }
static inline bool tick_broadcast_oneshot_available(void) { return tick_oneshot_possible(); }
#endif /* !(BROADCAST && ONESHOT) */
+#if defined(CONFIG_NO_HZ_COMMON) || defined(CONFIG_HIGH_RES_TIMERS)
+extern void tick_sched_forward_next_period(void);
+#else
+static inline void tick_sched_forward_next_period(void) { }
+#endif
+
/* NO_HZ_FULL internal */
#ifdef CONFIG_NO_HZ_FULL
extern void tick_nohz_init(void);
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 5d4a0342f934..f3ab08caa2c3 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -52,6 +52,15 @@ struct tick_sched *tick_get_tick_sched(int cpu)
static ktime_t last_jiffies_update;
/*
+ * Called after resume. Make sure that jiffies are not fast forwarded due to
+ * clock monotonic being forwarded by the suspended time.
+ */
+void tick_sched_forward_next_period(void)
+{
+ last_jiffies_update = tick_next_period;
+}
+
+/*
* Must be called with interrupts disabled !
*/
static void tick_do_update_jiffies64(ktime_t now)
diff --git a/kernel/time/time.c b/kernel/time/time.c
index bd4e6c7dd689..3044d48ebe56 100644
--- a/kernel/time/time.c
+++ b/kernel/time/time.c
@@ -488,6 +488,18 @@ struct timeval ns_to_timeval(const s64 nsec)
}
EXPORT_SYMBOL(ns_to_timeval);
+struct __kernel_old_timeval ns_to_kernel_old_timeval(const s64 nsec)
+{
+ struct timespec64 ts = ns_to_timespec64(nsec);
+ struct __kernel_old_timeval tv;
+
+ tv.tv_sec = ts.tv_sec;
+ tv.tv_usec = (suseconds_t)ts.tv_nsec / 1000;
+
+ return tv;
+}
+EXPORT_SYMBOL(ns_to_kernel_old_timeval);
+
/**
* set_normalized_timespec - set timespec sec and nsec parts and normalize
*
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index cd03317e7b57..ca90219a1e73 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -138,7 +138,12 @@ static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec64 wtm)
static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta)
{
- tk->offs_boot = ktime_add(tk->offs_boot, delta);
+ /* Update both bases so mono and raw stay coupled. */
+ tk->tkr_mono.base += delta;
+ tk->tkr_raw.base += delta;
+
+ /* Accumulate time spent in suspend */
+ tk->time_suspended += delta;
}
/*
@@ -332,6 +337,7 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
tk->tkr_mono.mult = clock->mult;
tk->tkr_raw.mult = clock->mult;
tk->ntp_err_mult = 0;
+ tk->skip_second_overflow = 0;
}
/* Timekeeper helper functions. */
@@ -467,36 +473,6 @@ u64 ktime_get_raw_fast_ns(void)
}
EXPORT_SYMBOL_GPL(ktime_get_raw_fast_ns);
-/**
- * ktime_get_boot_fast_ns - NMI safe and fast access to boot clock.
- *
- * To keep it NMI safe since we're accessing from tracing, we're not using a
- * separate timekeeper with updates to monotonic clock and boot offset
- * protected with seqlocks. This has the following minor side effects:
- *
- * (1) Its possible that a timestamp be taken after the boot offset is updated
- * but before the timekeeper is updated. If this happens, the new boot offset
- * is added to the old timekeeping making the clock appear to update slightly
- * earlier:
- * CPU 0 CPU 1
- * timekeeping_inject_sleeptime64()
- * __timekeeping_inject_sleeptime(tk, delta);
- * timestamp();
- * timekeeping_update(tk, TK_CLEAR_NTP...);
- *
- * (2) On 32-bit systems, the 64-bit boot offset (tk->offs_boot) may be
- * partially updated. Since the tk->offs_boot update is a rare event, this
- * should be a rare occurrence which postprocessing should be able to handle.
- */
-u64 notrace ktime_get_boot_fast_ns(void)
-{
- struct timekeeper *tk = &tk_core.timekeeper;
-
- return (ktime_get_mono_fast_ns() + ktime_to_ns(tk->offs_boot));
-}
-EXPORT_SYMBOL_GPL(ktime_get_boot_fast_ns);
-
-
/*
* See comment for __ktime_get_fast_ns() vs. timestamp ordering
*/
@@ -788,7 +764,6 @@ EXPORT_SYMBOL_GPL(ktime_get_resolution_ns);
static ktime_t *offsets[TK_OFFS_MAX] = {
[TK_OFFS_REAL] = &tk_core.timekeeper.offs_real,
- [TK_OFFS_BOOT] = &tk_core.timekeeper.offs_boot,
[TK_OFFS_TAI] = &tk_core.timekeeper.offs_tai,
};
@@ -886,6 +861,39 @@ void ktime_get_ts64(struct timespec64 *ts)
EXPORT_SYMBOL_GPL(ktime_get_ts64);
/**
+ * ktime_get_active_ts64 - Get the active non-suspended monotonic clock
+ * @ts: pointer to timespec variable
+ *
+ * The function calculates the monotonic clock from the realtime clock and
+ * the wall_to_monotonic offset, subtracts the accumulated suspend time and
+ * stores the result in normalized timespec64 format in the variable
+ * pointed to by @ts.
+ */
+void ktime_get_active_ts64(struct timespec64 *ts)
+{
+ struct timekeeper *tk = &tk_core.timekeeper;
+ struct timespec64 tomono, tsusp;
+ u64 nsec, nssusp;
+ unsigned int seq;
+
+ WARN_ON(timekeeping_suspended);
+
+ do {
+ seq = read_seqcount_begin(&tk_core.seq);
+ ts->tv_sec = tk->xtime_sec;
+ nsec = timekeeping_get_ns(&tk->tkr_mono);
+ tomono = tk->wall_to_monotonic;
+ nssusp = tk->time_suspended;
+ } while (read_seqcount_retry(&tk_core.seq, seq));
+
+ ts->tv_sec += tomono.tv_sec;
+ ts->tv_nsec = 0;
+ timespec64_add_ns(ts, nsec + tomono.tv_nsec);
+ tsusp = ns_to_timespec64(nssusp);
+ *ts = timespec64_sub(*ts, tsusp);
+}
+
+/**
* ktime_get_seconds - Get the seconds portion of CLOCK_MONOTONIC
*
* Returns the seconds portion of CLOCK_MONOTONIC with a single non
@@ -1585,7 +1593,6 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
return;
}
tk_xtime_add(tk, delta);
- tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, *delta));
tk_update_sleep_time(tk, timespec64_to_ktime(*delta));
tk_debug_account_sleep_time(delta);
}
@@ -1799,20 +1806,19 @@ device_initcall(timekeeping_init_ops);
*/
static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk,
s64 offset,
- bool negative,
- int adj_scale)
+ s32 mult_adj)
{
s64 interval = tk->cycle_interval;
- s32 mult_adj = 1;
- if (negative) {
- mult_adj = -mult_adj;
+ if (mult_adj == 0) {
+ return;
+ } else if (mult_adj == -1) {
interval = -interval;
- offset = -offset;
+ offset = -offset;
+ } else if (mult_adj != 1) {
+ interval *= mult_adj;
+ offset *= mult_adj;
}
- mult_adj <<= adj_scale;
- interval <<= adj_scale;
- offset <<= adj_scale;
/*
* So the following can be confusing.
@@ -1860,8 +1866,6 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk,
* xtime_nsec_2 = xtime_nsec_1 - offset
* Which simplfies to:
* xtime_nsec -= offset
- *
- * XXX - TODO: Doc ntp_error calculation.
*/
if ((mult_adj > 0) && (tk->tkr_mono.mult + mult_adj < mult_adj)) {
/* NTP adjustment caused clocksource mult overflow */
@@ -1872,89 +1876,38 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk,
tk->tkr_mono.mult += mult_adj;
tk->xtime_interval += interval;
tk->tkr_mono.xtime_nsec -= offset;
- tk->ntp_error -= (interval - offset) << tk->ntp_error_shift;
}
/*
- * Calculate the multiplier adjustment needed to match the frequency
- * specified by NTP
+ * Adjust the timekeeper's multiplier to the correct frequency
+ * and also to reduce the accumulated error value.
*/
-static __always_inline void timekeeping_freqadjust(struct timekeeper *tk,
- s64 offset)
+static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
{
- s64 interval = tk->cycle_interval;
- s64 xinterval = tk->xtime_interval;
- u32 base = tk->tkr_mono.clock->mult;
- u32 max = tk->tkr_mono.clock->maxadj;
- u32 cur_adj = tk->tkr_mono.mult;
- s64 tick_error;
- bool negative;
- u32 adj_scale;
-
- /* Remove any current error adj from freq calculation */
- if (tk->ntp_err_mult)
- xinterval -= tk->cycle_interval;
-
- tk->ntp_tick = ntp_tick_length();
-
- /* Calculate current error per tick */
- tick_error = ntp_tick_length() >> tk->ntp_error_shift;
- tick_error -= (xinterval + tk->xtime_remainder);
-
- /* Don't worry about correcting it if its small */
- if (likely((tick_error >= 0) && (tick_error <= interval)))
- return;
-
- /* preserve the direction of correction */
- negative = (tick_error < 0);
+ u32 mult;
- /* If any adjustment would pass the max, just return */
- if (negative && (cur_adj - 1) <= (base - max))
- return;
- if (!negative && (cur_adj + 1) >= (base + max))
- return;
/*
- * Sort out the magnitude of the correction, but
- * avoid making so large a correction that we go
- * over the max adjustment.
+ * Determine the multiplier from the current NTP tick length.
+ * Avoid expensive division when the tick length doesn't change.
*/
- adj_scale = 0;
- tick_error = abs(tick_error);
- while (tick_error > interval) {
- u32 adj = 1 << (adj_scale + 1);
-
- /* Check if adjustment gets us within 1 unit from the max */
- if (negative && (cur_adj - adj) <= (base - max))
- break;
- if (!negative && (cur_adj + adj) >= (base + max))
- break;
-
- adj_scale++;
- tick_error >>= 1;
+ if (likely(tk->ntp_tick == ntp_tick_length())) {
+ mult = tk->tkr_mono.mult - tk->ntp_err_mult;
+ } else {
+ tk->ntp_tick = ntp_tick_length();
+ mult = div64_u64((tk->ntp_tick >> tk->ntp_error_shift) -
+ tk->xtime_remainder, tk->cycle_interval);
}
- /* scale the corrections */
- timekeeping_apply_adjustment(tk, offset, negative, adj_scale);
-}
+ /*
+ * If the clock is behind the NTP time, increase the multiplier by 1
+ * to catch up with it. If it's ahead and there was a remainder in the
+ * tick division, the clock will slow down. Otherwise it will stay
+ * ahead until the tick length changes to a non-divisible value.
+ */
+ tk->ntp_err_mult = tk->ntp_error > 0 ? 1 : 0;
+ mult += tk->ntp_err_mult;
-/*
- * Adjust the timekeeper's multiplier to the correct frequency
- * and also to reduce the accumulated error value.
- */
-static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
-{
- /* Correct for the current frequency error */
- timekeeping_freqadjust(tk, offset);
-
- /* Next make a small adjustment to fix any cumulative error */
- if (!tk->ntp_err_mult && (tk->ntp_error > 0)) {
- tk->ntp_err_mult = 1;
- timekeeping_apply_adjustment(tk, offset, 0, 0);
- } else if (tk->ntp_err_mult && (tk->ntp_error <= 0)) {
- /* Undo any existing error adjustment */
- timekeeping_apply_adjustment(tk, offset, 1, 0);
- tk->ntp_err_mult = 0;
- }
+ timekeeping_apply_adjustment(tk, offset, mult - tk->tkr_mono.mult);
if (unlikely(tk->tkr_mono.clock->maxadj &&
(abs(tk->tkr_mono.mult - tk->tkr_mono.clock->mult)
@@ -1971,18 +1924,15 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
* in the code above, its possible the required corrective factor to
* xtime_nsec could cause it to underflow.
*
- * Now, since we already accumulated the second, cannot simply roll
- * the accumulated second back, since the NTP subsystem has been
- * notified via second_overflow. So instead we push xtime_nsec forward
- * by the amount we underflowed, and add that amount into the error.
- *
- * We'll correct this error next time through this function, when
- * xtime_nsec is not as small.
+ * Now, since we have already accumulated the second and the NTP
+ * subsystem has been notified via second_overflow(), we need to skip
+ * the next update.
*/
if (unlikely((s64)tk->tkr_mono.xtime_nsec < 0)) {
- s64 neg = -(s64)tk->tkr_mono.xtime_nsec;
- tk->tkr_mono.xtime_nsec = 0;
- tk->ntp_error += neg << tk->ntp_error_shift;
+ tk->tkr_mono.xtime_nsec += (u64)NSEC_PER_SEC <<
+ tk->tkr_mono.shift;
+ tk->xtime_sec--;
+ tk->skip_second_overflow = 1;
}
}
@@ -2005,6 +1955,15 @@ static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk)
tk->tkr_mono.xtime_nsec -= nsecps;
tk->xtime_sec++;
+ /*
+ * Skip NTP update if this second was accumulated before,
+ * i.e. xtime_nsec underflowed in timekeeping_adjust()
+ */
+ if (unlikely(tk->skip_second_overflow)) {
+ tk->skip_second_overflow = 0;
+ continue;
+ }
+
/* Figure out if its a leap sec and apply if needed */
leap = second_overflow(tk->xtime_sec);
if (unlikely(leap)) {
@@ -2121,7 +2080,7 @@ void update_wall_time(void)
shift--;
}
- /* correct the clock when NTP error is too big */
+ /* Adjust the multiplier to correct NTP error */
timekeeping_adjust(tk, offset);
/*
@@ -2166,7 +2125,7 @@ out:
void getboottime64(struct timespec64 *ts)
{
struct timekeeper *tk = &tk_core.timekeeper;
- ktime_t t = ktime_sub(tk->offs_real, tk->offs_boot);
+ ktime_t t = ktime_sub(tk->offs_real, tk->time_suspended);
*ts = ktime_to_timespec64(t);
}
@@ -2236,7 +2195,6 @@ void do_timer(unsigned long ticks)
* ktime_get_update_offsets_now - hrtimer helper
* @cwsseq: pointer to check and store the clock was set sequence number
* @offs_real: pointer to storage for monotonic -> realtime offset
- * @offs_boot: pointer to storage for monotonic -> boottime offset
* @offs_tai: pointer to storage for monotonic -> clock tai offset
*
* Returns current monotonic time and updates the offsets if the
@@ -2246,7 +2204,7 @@ void do_timer(unsigned long ticks)
* Called from hrtimer_interrupt() or retrigger_next_event()
*/
ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, ktime_t *offs_real,
- ktime_t *offs_boot, ktime_t *offs_tai)
+ ktime_t *offs_tai)
{
struct timekeeper *tk = &tk_core.timekeeper;
unsigned int seq;
@@ -2263,7 +2221,6 @@ ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, ktime_t *offs_real,
if (*cwsseq != tk->clock_was_set_seq) {
*cwsseq = tk->clock_was_set_seq;
*offs_real = tk->offs_real;
- *offs_boot = tk->offs_boot;
*offs_tai = tk->offs_tai;
}
diff --git a/kernel/time/timekeeping.h b/kernel/time/timekeeping.h
index 7a9b4eb7a1d5..79b67f5e0343 100644
--- a/kernel/time/timekeeping.h
+++ b/kernel/time/timekeeping.h
@@ -6,7 +6,6 @@
*/
extern ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq,
ktime_t *offs_real,
- ktime_t *offs_boot,
ktime_t *offs_tai);
extern int timekeeping_valid_for_hres(void);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 20a2300ae4e8..300f4ea39646 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1164,7 +1164,7 @@ static struct {
{ trace_clock, "perf", 1 },
{ ktime_get_mono_fast_ns, "mono", 1 },
{ ktime_get_raw_fast_ns, "mono_raw", 1 },
- { ktime_get_boot_fast_ns, "boot", 1 },
+ { ktime_get_mono_fast_ns, "boot", 1 },
ARCH_TRACE_CLOCKS
};
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 254e636a3d6b..ca7959be8aaa 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -153,10 +153,9 @@ struct worker_pool {
unsigned long watchdog_ts; /* L: watchdog timestamp */
struct list_head worklist; /* L: list of pending works */
- int nr_workers; /* L: total number of workers */
- /* nr_idle includes the ones off idle_list for rebinding */
- int nr_idle; /* L: currently idle ones */
+ int nr_workers; /* L: total number of workers */
+ int nr_idle; /* L: currently idle workers */
struct list_head idle_list; /* X: list of idle workers */
struct timer_list idle_timer; /* L: worker idle timeout */
@@ -166,7 +165,6 @@ struct worker_pool {
DECLARE_HASHTABLE(busy_hash, BUSY_WORKER_HASH_ORDER);
/* L: hash of busy workers */
- /* see manage_workers() for details on the two manager mutexes */
struct worker *manager; /* L: purely informational */
struct mutex attach_mutex; /* attach/detach exclusion */
struct list_head workers; /* A: attached workers */
@@ -1604,6 +1602,40 @@ bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq,
}
EXPORT_SYMBOL_GPL(mod_delayed_work_on);
+static void rcu_work_rcufn(struct rcu_head *rcu)
+{
+ struct rcu_work *rwork = container_of(rcu, struct rcu_work, rcu);
+
+ /* read the comment in __queue_work() */
+ local_irq_disable();
+ __queue_work(WORK_CPU_UNBOUND, rwork->wq, &rwork->work);
+ local_irq_enable();
+}
+
+/**
+ * queue_rcu_work - queue work after a RCU grace period
+ * @wq: workqueue to use
+ * @rwork: work to queue
+ *
+ * Return: %false if @rwork was already pending, %true otherwise. Note
+ * that a full RCU grace period is guaranteed only after a %true return.
+ * While @rwork is guarnateed to be executed after a %false return, the
+ * execution may happen before a full RCU grace period has passed.
+ */
+bool queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *rwork)
+{
+ struct work_struct *work = &rwork->work;
+
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
+ rwork->wq = wq;
+ call_rcu(&rwork->rcu, rcu_work_rcufn);
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL(queue_rcu_work);
+
/**
* worker_enter_idle - enter idle state
* @worker: worker which is entering idle state
@@ -3001,6 +3033,26 @@ bool flush_delayed_work(struct delayed_work *dwork)
}
EXPORT_SYMBOL(flush_delayed_work);
+/**
+ * flush_rcu_work - wait for a rwork to finish executing the last queueing
+ * @rwork: the rcu work to flush
+ *
+ * Return:
+ * %true if flush_rcu_work() waited for the work to finish execution,
+ * %false if it was already idle.
+ */
+bool flush_rcu_work(struct rcu_work *rwork)
+{
+ if (test_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(&rwork->work))) {
+ rcu_barrier();
+ flush_work(&rwork->work);
+ return true;
+ } else {
+ return flush_work(&rwork->work);
+ }
+}
+EXPORT_SYMBOL(flush_rcu_work);
+
static bool __cancel_work(struct work_struct *work, bool is_dwork)
{
unsigned long flags;
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 00eeff94b357..51c6bf0d93c6 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -324,11 +324,11 @@ config DEBUG_SECTION_MISMATCH
the analysis would not catch the illegal reference.
This option tells gcc to inline less (but it does result in
a larger kernel).
- - Run the section mismatch analysis for each module/built-in.o file.
+ - Run the section mismatch analysis for each module/built-in.a file.
When we run the section mismatch analysis on vmlinux.o, we
lose valuable information about where the mismatch was
introduced.
- Running the analysis for each module/built-in.o file
+ Running the analysis for each module/built-in.a file
tells where the mismatch happens much closer to the
source. The drawback is that the same mismatch is
reported at least twice.
diff --git a/lib/devres.c b/lib/devres.c
index 5f2aedd58bc5..5bec1120b392 100644
--- a/lib/devres.c
+++ b/lib/devres.c
@@ -5,6 +5,12 @@
#include <linux/gfp.h>
#include <linux/export.h>
+enum devm_ioremap_type {
+ DEVM_IOREMAP = 0,
+ DEVM_IOREMAP_NC,
+ DEVM_IOREMAP_WC,
+};
+
void devm_ioremap_release(struct device *dev, void *res)
{
iounmap(*(void __iomem **)res);
@@ -15,24 +21,28 @@ static int devm_ioremap_match(struct device *dev, void *res, void *match_data)
return *(void **)res == match_data;
}
-/**
- * devm_ioremap - Managed ioremap()
- * @dev: Generic device to remap IO address for
- * @offset: Resource address to map
- * @size: Size of map
- *
- * Managed ioremap(). Map is automatically unmapped on driver detach.
- */
-void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
- resource_size_t size)
+static void __iomem *__devm_ioremap(struct device *dev, resource_size_t offset,
+ resource_size_t size,
+ enum devm_ioremap_type type)
{
- void __iomem **ptr, *addr;
+ void __iomem **ptr, *addr = NULL;
ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return NULL;
- addr = ioremap(offset, size);
+ switch (type) {
+ case DEVM_IOREMAP:
+ addr = ioremap(offset, size);
+ break;
+ case DEVM_IOREMAP_NC:
+ addr = ioremap_nocache(offset, size);
+ break;
+ case DEVM_IOREMAP_WC:
+ addr = ioremap_wc(offset, size);
+ break;
+ }
+
if (addr) {
*ptr = addr;
devres_add(dev, ptr);
@@ -41,6 +51,20 @@ void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
return addr;
}
+
+/**
+ * devm_ioremap - Managed ioremap()
+ * @dev: Generic device to remap IO address for
+ * @offset: Resource address to map
+ * @size: Size of map
+ *
+ * Managed ioremap(). Map is automatically unmapped on driver detach.
+ */
+void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
+ resource_size_t size)
+{
+ return __devm_ioremap(dev, offset, size, DEVM_IOREMAP);
+}
EXPORT_SYMBOL(devm_ioremap);
/**
@@ -55,20 +79,7 @@ EXPORT_SYMBOL(devm_ioremap);
void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset,
resource_size_t size)
{
- void __iomem **ptr, *addr;
-
- ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return NULL;
-
- addr = ioremap_nocache(offset, size);
- if (addr) {
- *ptr = addr;
- devres_add(dev, ptr);
- } else
- devres_free(ptr);
-
- return addr;
+ return __devm_ioremap(dev, offset, size, DEVM_IOREMAP_NC);
}
EXPORT_SYMBOL(devm_ioremap_nocache);
@@ -83,20 +94,7 @@ EXPORT_SYMBOL(devm_ioremap_nocache);
void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
resource_size_t size)
{
- void __iomem **ptr, *addr;
-
- ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return NULL;
-
- addr = ioremap_wc(offset, size);
- if (addr) {
- *ptr = addr;
- devres_add(dev, ptr);
- } else
- devres_free(ptr);
-
- return addr;
+ return __devm_ioremap(dev, offset, size, DEVM_IOREMAP_WC);
}
EXPORT_SYMBOL(devm_ioremap_wc);
diff --git a/lib/int_sqrt.c b/lib/int_sqrt.c
index e2d329099bf7..14436f4ca6bd 100644
--- a/lib/int_sqrt.c
+++ b/lib/int_sqrt.c
@@ -38,3 +38,33 @@ unsigned long int_sqrt(unsigned long x)
return y;
}
EXPORT_SYMBOL(int_sqrt);
+
+#if BITS_PER_LONG < 64
+/**
+ * int_sqrt64 - strongly typed int_sqrt function when minimum 64 bit input
+ * is expected.
+ * @x: 64bit integer of which to calculate the sqrt
+ */
+u32 int_sqrt64(u64 x)
+{
+ u64 b, m, y = 0;
+
+ if (x <= ULONG_MAX)
+ return int_sqrt((unsigned long) x);
+
+ m = 1ULL << (fls64(x) & ~1ULL);
+ while (m != 0) {
+ b = y + m;
+ y >>= 1;
+
+ if (x >= b) {
+ x -= b;
+ y += m;
+ }
+ m >>= 2;
+ }
+
+ return y;
+}
+EXPORT_SYMBOL(int_sqrt64);
+#endif
diff --git a/lib/kobject.c b/lib/kobject.c
index afd5a3fc6123..e1d1f290bf35 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -204,8 +204,9 @@ static int kobject_add_internal(struct kobject *kobj)
return -ENOENT;
if (!kobj->name || !kobj->name[0]) {
- WARN(1, "kobject: (%p): attempted to be registered with empty "
- "name!\n", kobj);
+ WARN(1,
+ "kobject: (%p): attempted to be registered with empty name!\n",
+ kobj);
return -EINVAL;
}
@@ -232,9 +233,8 @@ static int kobject_add_internal(struct kobject *kobj)
/* be noisy on error issues */
if (error == -EEXIST)
- WARN(1, "%s failed for %s with "
- "-EEXIST, don't try to register things with "
- "the same name in the same directory.\n",
+ WARN(1,
+ "%s failed for %s with -EEXIST, don't try to register things with the same name in the same directory.\n",
__func__, kobject_name(kobj));
else
WARN(1, "%s failed for %s (error: %d parent: %s)\n",
@@ -334,8 +334,8 @@ void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
}
if (kobj->state_initialized) {
/* do not error out as sometimes we can recover */
- printk(KERN_ERR "kobject (%p): tried to init an initialized "
- "object, something is seriously wrong.\n", kobj);
+ pr_err("kobject (%p): tried to init an initialized object, something is seriously wrong.\n",
+ kobj);
dump_stack();
}
@@ -344,7 +344,7 @@ void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
return;
error:
- printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
+ pr_err("kobject (%p): %s\n", kobj, err_str);
dump_stack();
}
EXPORT_SYMBOL(kobject_init);
@@ -357,7 +357,7 @@ static __printf(3, 0) int kobject_add_varg(struct kobject *kobj,
retval = kobject_set_name_vargs(kobj, fmt, vargs);
if (retval) {
- printk(KERN_ERR "kobject: can not set name properly!\n");
+ pr_err("kobject: can not set name properly!\n");
return retval;
}
kobj->parent = parent;
@@ -399,8 +399,7 @@ int kobject_add(struct kobject *kobj, struct kobject *parent,
return -EINVAL;
if (!kobj->state_initialized) {
- printk(KERN_ERR "kobject '%s' (%p): tried to add an "
- "uninitialized object, something is seriously wrong.\n",
+ pr_err("kobject '%s' (%p): tried to add an uninitialized object, something is seriously wrong.\n",
kobject_name(kobj), kobj);
dump_stack();
return -EINVAL;
@@ -590,9 +589,9 @@ struct kobject *kobject_get(struct kobject *kobj)
{
if (kobj) {
if (!kobj->state_initialized)
- WARN(1, KERN_WARNING "kobject: '%s' (%p): is not "
- "initialized, yet kobject_get() is being "
- "called.\n", kobject_name(kobj), kobj);
+ WARN(1, KERN_WARNING
+ "kobject: '%s' (%p): is not initialized, yet kobject_get() is being called.\n",
+ kobject_name(kobj), kobj);
kref_get(&kobj->kref);
}
return kobj;
@@ -622,8 +621,7 @@ static void kobject_cleanup(struct kobject *kobj)
kobject_name(kobj), kobj, __func__, kobj->parent);
if (t && !t->release)
- pr_debug("kobject: '%s' (%p): does not have a release() "
- "function, it is broken and must be fixed.\n",
+ pr_debug("kobject: '%s' (%p): does not have a release() function, it is broken and must be fixed.\n",
kobject_name(kobj), kobj);
/* send "remove" if the caller did not do it but sent "add" */
@@ -686,9 +684,9 @@ void kobject_put(struct kobject *kobj)
{
if (kobj) {
if (!kobj->state_initialized)
- WARN(1, KERN_WARNING "kobject: '%s' (%p): is not "
- "initialized, yet kobject_put() is being "
- "called.\n", kobject_name(kobj), kobj);
+ WARN(1, KERN_WARNING
+ "kobject: '%s' (%p): is not initialized, yet kobject_put() is being called.\n",
+ kobject_name(kobj), kobj);
kref_put(&kobj->kref, kobject_release);
}
}
@@ -752,8 +750,7 @@ struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
retval = kobject_add(kobj, parent, "%s", name);
if (retval) {
- printk(KERN_WARNING "%s: kobject_add error: %d\n",
- __func__, retval);
+ pr_warn("%s: kobject_add error: %d\n", __func__, retval);
kobject_put(kobj);
kobj = NULL;
}
diff --git a/lib/libcrc32c.c b/lib/libcrc32c.c
index 9f79547d1b97..f0a2934605bf 100644
--- a/lib/libcrc32c.c
+++ b/lib/libcrc32c.c
@@ -71,6 +71,12 @@ static void __exit libcrc32c_mod_fini(void)
crypto_free_shash(tfm);
}
+const char *crc32c_impl(void)
+{
+ return crypto_shash_driver_name(tfm);
+}
+EXPORT_SYMBOL(crc32c_impl);
+
module_init(libcrc32c_mod_init);
module_exit(libcrc32c_mod_fini);
diff --git a/lib/zstd/Makefile b/lib/zstd/Makefile
index dd0a359c135b..7920cbbfeae9 100644
--- a/lib/zstd/Makefile
+++ b/lib/zstd/Makefile
@@ -3,16 +3,7 @@ obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd_decompress.o
ccflags-y += -O3
-# Object files unique to zstd_compress and zstd_decompress
-zstd_compress-y := fse_compress.o huf_compress.o compress.o
-zstd_decompress-y := huf_decompress.o decompress.o
-
-# These object files are shared between the modules.
-# Always add them to zstd_compress.
-# Unless both zstd_compress and zstd_decompress are built in
-# then also add them to zstd_decompress.
-zstd_compress-y += entropy_common.o fse_decompress.o zstd_common.o
-
-ifneq ($(CONFIG_ZSTD_COMPRESS)$(CONFIG_ZSTD_DECOMPRESS),yy)
- zstd_decompress-y += entropy_common.o fse_decompress.o zstd_common.o
-endif
+zstd_compress-y := fse_compress.o huf_compress.o compress.o \
+ entropy_common.o fse_decompress.o zstd_common.o
+zstd_decompress-y := huf_decompress.o decompress.o \
+ entropy_common.o fse_decompress.o zstd_common.o
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index a9682534c377..45ff5dc124cc 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -749,18 +749,31 @@ static bool conn_use_rpa(struct hci_conn *conn)
}
static void hci_req_add_le_create_conn(struct hci_request *req,
- struct hci_conn *conn)
+ struct hci_conn *conn,
+ bdaddr_t *direct_rpa)
{
struct hci_cp_le_create_conn cp;
struct hci_dev *hdev = conn->hdev;
u8 own_addr_type;
- /* Update random address, but set require_privacy to false so
- * that we never connect with an non-resolvable address.
+ /* If direct address was provided we use it instead of current
+ * address.
*/
- if (hci_update_random_address(req, false, conn_use_rpa(conn),
- &own_addr_type))
- return;
+ if (direct_rpa) {
+ if (bacmp(&req->hdev->random_addr, direct_rpa))
+ hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
+ direct_rpa);
+
+ /* direct address is always RPA */
+ own_addr_type = ADDR_LE_DEV_RANDOM;
+ } else {
+ /* Update random address, but set require_privacy to false so
+ * that we never connect with an non-resolvable address.
+ */
+ if (hci_update_random_address(req, false, conn_use_rpa(conn),
+ &own_addr_type))
+ return;
+ }
memset(&cp, 0, sizeof(cp));
@@ -825,7 +838,7 @@ static void hci_req_directed_advertising(struct hci_request *req,
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, u8 sec_level, u16 conn_timeout,
- u8 role)
+ u8 role, bdaddr_t *direct_rpa)
{
struct hci_conn_params *params;
struct hci_conn *conn;
@@ -940,7 +953,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
hci_dev_set_flag(hdev, HCI_LE_SCAN_INTERRUPTED);
}
- hci_req_add_le_create_conn(&req, conn);
+ hci_req_add_le_create_conn(&req, conn, direct_rpa);
create_conn:
err = hci_req_run(&req, create_le_conn_complete);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index cd3bbb766c24..139707cd9d35 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -4648,7 +4648,8 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev,
/* This function requires the caller holds hdev->lock */
static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
bdaddr_t *addr,
- u8 addr_type, u8 adv_type)
+ u8 addr_type, u8 adv_type,
+ bdaddr_t *direct_rpa)
{
struct hci_conn *conn;
struct hci_conn_params *params;
@@ -4699,7 +4700,8 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
}
conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW,
- HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER);
+ HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER,
+ direct_rpa);
if (!IS_ERR(conn)) {
/* If HCI_AUTO_CONN_EXPLICIT is set, conn is already owned
* by higher layer that tried to connect, if no then
@@ -4808,8 +4810,13 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
bdaddr_type = irk->addr_type;
}
- /* Check if we have been requested to connect to this device */
- conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type);
+ /* Check if we have been requested to connect to this device.
+ *
+ * direct_addr is set only for directed advertising reports (it is NULL
+ * for advertising reports) and is already verified to be RPA above.
+ */
+ conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type,
+ direct_addr);
if (conn && type == LE_ADV_IND) {
/* Store report for later inclusion by
* mgmt_device_connected
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index fc6615d59165..9b7907ebfa01 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -7156,7 +7156,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
hcon = hci_connect_le(hdev, dst, dst_type,
chan->sec_level,
HCI_LE_CONN_TIMEOUT,
- HCI_ROLE_SLAVE);
+ HCI_ROLE_SLAVE, NULL);
else
hcon = hci_connect_le_scan(hdev, dst, dst_type,
chan->sec_level,
diff --git a/net/core/dev.c b/net/core/dev.c
index 9b04a9fd1dfd..969462ebb296 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1027,7 +1027,7 @@ bool dev_valid_name(const char *name)
{
if (*name == '\0')
return false;
- if (strlen(name) >= IFNAMSIZ)
+ if (strnlen(name, IFNAMSIZ) == IFNAMSIZ)
return false;
if (!strcmp(name, ".") || !strcmp(name, ".."))
return false;
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index c0548d268e1a..e3e6a3e2ca22 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -57,8 +57,8 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
return -EINVAL;
list_for_each_entry(ha, &list->list, list) {
- if (!memcmp(ha->addr, addr, addr_len) &&
- ha->type == addr_type) {
+ if (ha->type == addr_type &&
+ !memcmp(ha->addr, addr, addr_len)) {
if (global) {
/* check if addr is already used as global */
if (ha->global_use)
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 9236e421bd62..ad1317376798 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -2405,6 +2405,16 @@ devlink_resource_size_params_put(struct devlink_resource *resource,
return 0;
}
+static int devlink_resource_occ_put(struct devlink_resource *resource,
+ struct sk_buff *skb)
+{
+ if (!resource->occ_get)
+ return 0;
+ return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
+ resource->occ_get(resource->occ_get_priv),
+ DEVLINK_ATTR_PAD);
+}
+
static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
struct devlink_resource *resource)
{
@@ -2425,11 +2435,8 @@ static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
if (resource->size != resource->size_new)
nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
resource->size_new, DEVLINK_ATTR_PAD);
- if (resource->resource_ops && resource->resource_ops->occ_get)
- if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
- resource->resource_ops->occ_get(devlink),
- DEVLINK_ATTR_PAD))
- goto nla_put_failure;
+ if (devlink_resource_occ_put(resource, skb))
+ goto nla_put_failure;
if (devlink_resource_size_params_put(resource, skb))
goto nla_put_failure;
if (list_empty(&resource->resource_list))
@@ -3162,15 +3169,13 @@ EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
* @resource_id: resource's id
* @parent_reosurce_id: resource's parent id
* @size params: size parameters
- * @resource_ops: resource ops
*/
int devlink_resource_register(struct devlink *devlink,
const char *resource_name,
u64 resource_size,
u64 resource_id,
u64 parent_resource_id,
- const struct devlink_resource_size_params *size_params,
- const struct devlink_resource_ops *resource_ops)
+ const struct devlink_resource_size_params *size_params)
{
struct devlink_resource *resource;
struct list_head *resource_list;
@@ -3213,7 +3218,6 @@ int devlink_resource_register(struct devlink *devlink,
resource->size = resource_size;
resource->size_new = resource_size;
resource->id = resource_id;
- resource->resource_ops = resource_ops;
resource->size_valid = true;
memcpy(&resource->size_params, size_params,
sizeof(resource->size_params));
@@ -3315,6 +3319,58 @@ out:
}
EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
+/**
+ * devlink_resource_occ_get_register - register occupancy getter
+ *
+ * @devlink: devlink
+ * @resource_id: resource id
+ * @occ_get: occupancy getter callback
+ * @occ_get_priv: occupancy getter callback priv
+ */
+void devlink_resource_occ_get_register(struct devlink *devlink,
+ u64 resource_id,
+ devlink_resource_occ_get_t *occ_get,
+ void *occ_get_priv)
+{
+ struct devlink_resource *resource;
+
+ mutex_lock(&devlink->lock);
+ resource = devlink_resource_find(devlink, NULL, resource_id);
+ if (WARN_ON(!resource))
+ goto out;
+ WARN_ON(resource->occ_get);
+
+ resource->occ_get = occ_get;
+ resource->occ_get_priv = occ_get_priv;
+out:
+ mutex_unlock(&devlink->lock);
+}
+EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
+
+/**
+ * devlink_resource_occ_get_unregister - unregister occupancy getter
+ *
+ * @devlink: devlink
+ * @resource_id: resource id
+ */
+void devlink_resource_occ_get_unregister(struct devlink *devlink,
+ u64 resource_id)
+{
+ struct devlink_resource *resource;
+
+ mutex_lock(&devlink->lock);
+ resource = devlink_resource_find(devlink, NULL, resource_id);
+ if (WARN_ON(!resource))
+ goto out;
+ WARN_ON(!resource->occ_get);
+
+ resource->occ_get = NULL;
+ resource->occ_get_priv = NULL;
+out:
+ mutex_unlock(&devlink->lock);
+}
+EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
+
static int __init devlink_module_init(void)
{
return genl_register_family(&devlink_nl_family);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 1bca1e0fc8f7..345b51837ca8 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -857,6 +857,7 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
n->cloned = 1;
n->nohdr = 0;
+ n->peeked = 0;
n->destructor = NULL;
C(tail);
C(end);
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index e65fcb45c3f6..b08feb219b44 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -614,6 +614,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
ireq = inet_rsk(req);
sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr);
sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr);
+ ireq->ir_mark = inet_request_mark(sk, skb);
ireq->ireq_family = AF_INET;
ireq->ir_iif = sk->sk_bound_dev_if;
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 5df7857fc0f3..6344f1b18a6a 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -351,6 +351,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;
ireq->ireq_family = AF_INET6;
+ ireq->ir_mark = inet_request_mark(sk, skb);
if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 70de7895e5b8..053731473c99 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -126,6 +126,7 @@ static inline struct net_device *dsa_master_find_slave(struct net_device *dev,
struct dsa_port *cpu_dp = dev->dsa_ptr;
struct dsa_switch_tree *dst = cpu_dp->dst;
struct dsa_switch *ds;
+ struct dsa_port *slave_port;
if (device < 0 || device >= DSA_MAX_SWITCHES)
return NULL;
@@ -137,7 +138,12 @@ static inline struct net_device *dsa_master_find_slave(struct net_device *dev,
if (port < 0 || port >= ds->num_ports)
return NULL;
- return ds->ports[port].slave;
+ slave_port = &ds->ports[port];
+
+ if (unlikely(slave_port->type != DSA_PORT_TYPE_USER))
+ return NULL;
+
+ return slave_port->slave;
}
/* port.c */
diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
index 44f148a6bb57..1790b65944b3 100644
--- a/net/ieee802154/6lowpan/reassembly.c
+++ b/net/ieee802154/6lowpan/reassembly.c
@@ -411,7 +411,6 @@ err:
}
#ifdef CONFIG_SYSCTL
-static long zero;
static struct ctl_table lowpan_frags_ns_ctl_table[] = {
{
@@ -428,7 +427,6 @@ static struct ctl_table lowpan_frags_ns_ctl_table[] = {
.maxlen = sizeof(unsigned long),
.mode = 0644,
.proc_handler = proc_doulongvec_minmax,
- .extra1 = &zero,
.extra2 = &init_net.ieee802154_lowpan.frags.high_thresh
},
{
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index be4c595edccb..bf6c2d4d4fdc 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -437,7 +437,7 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
/*unsigned long now; */
struct net *net = dev_net(dev);
- rt = ip_route_output(net, sip, tip, 0, 0);
+ rt = ip_route_output(net, sip, tip, 0, l3mdev_master_ifindex_rcu(dev));
if (IS_ERR(rt))
return 1;
if (rt->dst.dev != dev) {
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index c3ea4906d237..88c5069b5d20 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -178,6 +178,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk,
tw->tw_dport = inet->inet_dport;
tw->tw_family = sk->sk_family;
tw->tw_reuse = sk->sk_reuse;
+ tw->tw_reuseport = sk->sk_reuseport;
tw->tw_hash = sk->sk_hash;
tw->tw_ipv6only = 0;
tw->tw_transparent = inet->transparent;
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 994fa70a910f..8e9528ebaa8e 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -667,7 +667,7 @@ struct sk_buff *ip_check_defrag(struct net *net, struct sk_buff *skb, u32 user)
EXPORT_SYMBOL(ip_check_defrag);
#ifdef CONFIG_SYSCTL
-static long zero;
+static int dist_min;
static struct ctl_table ip4_frags_ns_ctl_table[] = {
{
@@ -684,7 +684,6 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = {
.maxlen = sizeof(unsigned long),
.mode = 0644,
.proc_handler = proc_doulongvec_minmax,
- .extra1 = &zero,
.extra2 = &init_net.ipv4.frags.high_thresh
},
{
@@ -700,7 +699,7 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = {
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
- .extra1 = &zero
+ .extra1 = &dist_min,
},
{ }
};
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 94cacae76aca..4c11b810a447 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1090,7 +1090,8 @@ alloc_new_skb:
length -= copy;
}
- refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);
+ if (wmem_alloc_delta)
+ refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);
return 0;
error_efault:
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index de6d94482fe7..6b0e362cc99b 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -253,13 +253,14 @@ static struct net_device *__ip_tunnel_create(struct net *net,
struct net_device *dev;
char name[IFNAMSIZ];
- if (parms->name[0])
+ err = -E2BIG;
+ if (parms->name[0]) {
+ if (!dev_valid_name(parms->name))
+ goto failed;
strlcpy(name, parms->name, IFNAMSIZ);
- else {
- if (strlen(ops->kind) > (IFNAMSIZ - 3)) {
- err = -E2BIG;
+ } else {
+ if (strlen(ops->kind) > (IFNAMSIZ - 3))
goto failed;
- }
strlcpy(name, ops->kind, IFNAMSIZ);
strncat(name, "%d", 2);
}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 8322e479f299..59bc6ab1a4eb 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2297,13 +2297,14 @@ struct rtable *ip_route_output_key_hash(struct net *net, struct flowi4 *fl4,
const struct sk_buff *skb)
{
__u8 tos = RT_FL_TOS(fl4);
- struct fib_result res;
+ struct fib_result res = {
+ .type = RTN_UNSPEC,
+ .fi = NULL,
+ .table = NULL,
+ .tclassid = 0,
+ };
struct rtable *rth;
- res.tclassid = 0;
- res.fi = NULL;
- res.table = NULL;
-
fl4->flowi4_iif = LOOPBACK_IFINDEX;
fl4->flowi4_tos = tos & IPTOS_RT_MASK;
fl4->flowi4_scope = ((tos & RTO_ONLINK) ?
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 88bc2ef7c7a8..a02ad100f0d7 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -106,14 +106,7 @@ int ip6_datagram_dst_update(struct sock *sk, bool fix_sk_saddr)
}
}
- ip6_dst_store(sk, dst,
- ipv6_addr_equal(&fl6.daddr, &sk->sk_v6_daddr) ?
- &sk->sk_v6_daddr : NULL,
-#ifdef CONFIG_IPV6_SUBTREES
- ipv6_addr_equal(&fl6.saddr, &np->saddr) ?
- &np->saddr :
-#endif
- NULL);
+ ip6_sk_dst_store_flow(sk, dst, &fl6);
out:
fl6_sock_release(flowlabel);
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index f8a103bdbd60..69727bc168cb 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -335,11 +335,13 @@ static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net,
if (t || !create)
return t;
- if (parms->name[0])
+ if (parms->name[0]) {
+ if (!dev_valid_name(parms->name))
+ return NULL;
strlcpy(name, parms->name, IFNAMSIZ);
- else
+ } else {
strcpy(name, "ip6gre%d");
-
+ }
dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
ip6gre_tunnel_setup);
if (!dev)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index e6eaa4dd9f60..2e891d2c30ef 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -375,6 +375,11 @@ static int ip6_forward_proxy_check(struct sk_buff *skb)
static inline int ip6_forward_finish(struct net *net, struct sock *sk,
struct sk_buff *skb)
{
+ struct dst_entry *dst = skb_dst(skb);
+
+ __IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
+ __IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len);
+
return dst_output(net, sk, skb);
}
@@ -569,8 +574,6 @@ int ip6_forward(struct sk_buff *skb)
hdr->hop_limit--;
- __IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
- __IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len);
return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
net, NULL, skb, skb->dev, dst->dev,
ip6_forward_finish);
@@ -1105,23 +1108,32 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
* @sk: socket which provides the dst cache and route info
* @fl6: flow to lookup
* @final_dst: final destination address for ipsec lookup
+ * @connected: whether @sk is connected or not
*
* This function performs a route lookup on the given flow with the
* possibility of using the cached route in the socket if it is valid.
* It will take the socket dst lock when operating on the dst cache.
* As a result, this function can only be used in process context.
*
+ * In addition, for a connected socket, cache the dst in the socket
+ * if the current cache is not valid.
+ *
* It returns a valid dst pointer on success, or a pointer encoded
* error code.
*/
struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
- const struct in6_addr *final_dst)
+ const struct in6_addr *final_dst,
+ bool connected)
{
struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie);
dst = ip6_sk_dst_check(sk, dst, fl6);
- if (!dst)
- dst = ip6_dst_lookup_flow(sk, fl6, final_dst);
+ if (dst)
+ return dst;
+
+ dst = ip6_dst_lookup_flow(sk, fl6, final_dst);
+ if (connected && !IS_ERR(dst))
+ ip6_sk_dst_store_flow(sk, dst_clone(dst), fl6);
return dst;
}
@@ -1536,7 +1548,8 @@ alloc_new_skb:
length -= copy;
}
- refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);
+ if (wmem_alloc_delta)
+ refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);
return 0;
error_efault:
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index df4c29f7d59f..da66aaac51ce 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -297,13 +297,16 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
struct net_device *dev;
struct ip6_tnl *t;
char name[IFNAMSIZ];
- int err = -ENOMEM;
+ int err = -E2BIG;
- if (p->name[0])
+ if (p->name[0]) {
+ if (!dev_valid_name(p->name))
+ goto failed;
strlcpy(name, p->name, IFNAMSIZ);
- else
+ } else {
sprintf(name, "ip6tnl%%d");
-
+ }
+ err = -ENOMEM;
dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
ip6_tnl_dev_setup);
if (!dev)
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
index 6ebb2e8777f4..c214ffec02f0 100644
--- a/net/ipv6/ip6_vti.c
+++ b/net/ipv6/ip6_vti.c
@@ -212,10 +212,13 @@ static struct ip6_tnl *vti6_tnl_create(struct net *net, struct __ip6_tnl_parm *p
char name[IFNAMSIZ];
int err;
- if (p->name[0])
+ if (p->name[0]) {
+ if (!dev_valid_name(p->name))
+ goto failed;
strlcpy(name, p->name, IFNAMSIZ);
- else
+ } else {
sprintf(name, "ip6_vti%%d");
+ }
dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, vti6_dev_setup);
if (!dev)
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 3622aac343ae..5e0332014c17 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -55,7 +55,6 @@ static const char nf_frags_cache_name[] = "nf-frags";
static struct inet_frags nf_frags;
#ifdef CONFIG_SYSCTL
-static long zero;
static struct ctl_table nf_ct_frag6_sysctl_table[] = {
{
@@ -71,7 +70,6 @@ static struct ctl_table nf_ct_frag6_sysctl_table[] = {
.maxlen = sizeof(unsigned long),
.mode = 0644,
.proc_handler = proc_doulongvec_minmax,
- .extra1 = &zero,
.extra2 = &init_net.nf_frag.frags.high_thresh
},
{
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
index d12c55dad7d1..746eeae7f581 100644
--- a/net/ipv6/ping.c
+++ b/net/ipv6/ping.c
@@ -121,7 +121,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
ipc6.tclass = np->tclass;
fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
- dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr);
+ dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr, false);
if (IS_ERR(dst))
return PTR_ERR(dst);
rt = (struct rt6_info *) dst;
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 70e4a578b2fb..4979610287e2 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -548,7 +548,6 @@ static const struct inet6_protocol frag_protocol = {
};
#ifdef CONFIG_SYSCTL
-static int zero;
static struct ctl_table ip6_frags_ns_ctl_table[] = {
{
@@ -565,7 +564,6 @@ static struct ctl_table ip6_frags_ns_ctl_table[] = {
.maxlen = sizeof(unsigned long),
.mode = 0644,
.proc_handler = proc_doulongvec_minmax,
- .extra1 = &zero,
.extra2 = &init_net.ipv6.frags.high_thresh
},
{
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index f239f91d2efb..49b954d6d0fa 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2229,6 +2229,23 @@ void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
}
EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu);
+void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst,
+ const struct flowi6 *fl6)
+{
+#ifdef CONFIG_IPV6_SUBTREES
+ struct ipv6_pinfo *np = inet6_sk(sk);
+#endif
+
+ ip6_dst_store(sk, dst,
+ ipv6_addr_equal(&fl6->daddr, &sk->sk_v6_daddr) ?
+ &sk->sk_v6_daddr : NULL,
+#ifdef CONFIG_IPV6_SUBTREES
+ ipv6_addr_equal(&fl6->saddr, &np->saddr) ?
+ &np->saddr :
+#endif
+ NULL);
+}
+
/* Handle redirects */
struct ip6rd_flowi {
struct flowi6 fl6;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 1522bcfd253f..2afce37a7177 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -250,11 +250,13 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net,
if (!create)
goto failed;
- if (parms->name[0])
+ if (parms->name[0]) {
+ if (!dev_valid_name(parms->name))
+ goto failed;
strlcpy(name, parms->name, IFNAMSIZ);
- else
+ } else {
strcpy(name, "sit%d");
-
+ }
dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
ipip6_tunnel_setup);
if (!dev)
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 6861ed479469..4ec76a87aeb8 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1116,10 +1116,10 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
struct dst_entry *dst;
struct ipcm6_cookie ipc6;
int addr_len = msg->msg_namelen;
+ bool connected = false;
int ulen = len;
int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
int err;
- int connected = 0;
int is_udplite = IS_UDPLITE(sk);
int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
struct sockcm_cookie sockc;
@@ -1241,7 +1241,7 @@ do_udp_sendmsg:
fl6.fl6_dport = inet->inet_dport;
daddr = &sk->sk_v6_daddr;
fl6.flowlabel = np->flow_label;
- connected = 1;
+ connected = true;
}
if (!fl6.flowi6_oif)
@@ -1271,7 +1271,7 @@ do_udp_sendmsg:
}
if (!(opt->opt_nflen|opt->opt_flen))
opt = NULL;
- connected = 0;
+ connected = false;
}
if (!opt) {
opt = txopt_get(np);
@@ -1293,11 +1293,11 @@ do_udp_sendmsg:
final_p = fl6_update_dst(&fl6, opt, &final);
if (final_p)
- connected = 0;
+ connected = false;
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) {
fl6.flowi6_oif = np->mcast_oif;
- connected = 0;
+ connected = false;
} else if (!fl6.flowi6_oif)
fl6.flowi6_oif = np->ucast_oif;
@@ -1308,7 +1308,7 @@ do_udp_sendmsg:
fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
- dst = ip6_sk_dst_lookup_flow(sk, &fl6, final_p);
+ dst = ip6_sk_dst_lookup_flow(sk, &fl6, final_p, connected);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
dst = NULL;
@@ -1333,7 +1333,7 @@ back_from_confirm:
err = PTR_ERR(skb);
if (!IS_ERR_OR_NULL(skb))
err = udp_v6_send_skb(skb, &fl6);
- goto release_dst;
+ goto out;
}
lock_sock(sk);
@@ -1367,23 +1367,6 @@ do_append_data:
err = np->recverr ? net_xmit_errno(err) : 0;
release_sock(sk);
-release_dst:
- if (dst) {
- if (connected) {
- ip6_dst_store(sk, dst,
- ipv6_addr_equal(&fl6.daddr, &sk->sk_v6_daddr) ?
- &sk->sk_v6_daddr : NULL,
-#ifdef CONFIG_IPV6_SUBTREES
- ipv6_addr_equal(&fl6.saddr, &np->saddr) ?
- &np->saddr :
-#endif
- NULL);
- } else {
- dst_release(dst);
- }
- dst = NULL;
- }
-
out:
dst_release(dst);
fl6_sock_release(flowlabel);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index fa556fdef57d..55342c4d5cec 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1844,6 +1844,8 @@ static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
if (msg->msg_namelen) {
err = -EINVAL;
+ if (msg->msg_namelen < sizeof(struct sockaddr_nl))
+ goto out;
if (addr->nl_family != AF_NETLINK)
goto out;
dst_portid = addr->nl_pid;
diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c
index 21800e6f5019..0410d2277ca2 100644
--- a/net/rxrpc/input.c
+++ b/net/rxrpc/input.c
@@ -1200,6 +1200,12 @@ void rxrpc_data_ready(struct sock *udp_sk)
!rxrpc_validate_jumbo(skb))
goto bad_message;
break;
+
+ /* Packet types 9-11 should just be ignored. */
+ case RXRPC_PACKET_TYPE_PARAMS:
+ case RXRPC_PACKET_TYPE_10:
+ case RXRPC_PACKET_TYPE_11:
+ goto discard;
}
rcu_read_lock();
diff --git a/net/rxrpc/protocol.h b/net/rxrpc/protocol.h
index 4bddcf3face3..93da73bf7098 100644
--- a/net/rxrpc/protocol.h
+++ b/net/rxrpc/protocol.h
@@ -46,6 +46,9 @@ struct rxrpc_wire_header {
#define RXRPC_PACKET_TYPE_CHALLENGE 6 /* connection security challenge (SRVR->CLNT) */
#define RXRPC_PACKET_TYPE_RESPONSE 7 /* connection secutity response (CLNT->SRVR) */
#define RXRPC_PACKET_TYPE_DEBUG 8 /* debug info request */
+#define RXRPC_PACKET_TYPE_PARAMS 9 /* Parameter negotiation (unspec'd, ignore) */
+#define RXRPC_PACKET_TYPE_10 10 /* Ignored */
+#define RXRPC_PACKET_TYPE_11 11 /* Ignored */
#define RXRPC_PACKET_TYPE_VERSION 13 /* version string request */
#define RXRPC_N_PACKET_TYPES 14 /* number of packet types (incl type 0) */
@@ -78,6 +81,9 @@ struct rxrpc_wire_header {
(1 << RXRPC_PACKET_TYPE_CHALLENGE) | \
(1 << RXRPC_PACKET_TYPE_RESPONSE) | \
/*(1 << RXRPC_PACKET_TYPE_DEBUG) | */ \
+ (1 << RXRPC_PACKET_TYPE_PARAMS) | \
+ (1 << RXRPC_PACKET_TYPE_10) | \
+ (1 << RXRPC_PACKET_TYPE_11) | \
(1 << RXRPC_PACKET_TYPE_VERSION))
/*****************************************************************************/
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
index 9092531d45d8..18089c02e557 100644
--- a/net/sched/act_bpf.c
+++ b/net/sched/act_bpf.c
@@ -248,10 +248,14 @@ static int tcf_bpf_init_from_efd(struct nlattr **tb, struct tcf_bpf_cfg *cfg)
static void tcf_bpf_cfg_cleanup(const struct tcf_bpf_cfg *cfg)
{
- if (cfg->is_ebpf)
- bpf_prog_put(cfg->filter);
- else
- bpf_prog_destroy(cfg->filter);
+ struct bpf_prog *filter = cfg->filter;
+
+ if (filter) {
+ if (cfg->is_ebpf)
+ bpf_prog_put(filter);
+ else
+ bpf_prog_destroy(filter);
+ }
kfree(cfg->bpf_ops);
kfree(cfg->bpf_name);
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index ed8b6a24b9e9..bac47b5d18fd 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -489,6 +489,7 @@ static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key)
RCU_INIT_POINTER(*kp, key->next);
tcf_unbind_filter(tp, &key->res);
+ idr_remove(&ht->handle_idr, key->handle);
tcf_exts_get_net(&key->exts);
call_rcu(&key->rcu, u32_delete_key_freepf_rcu);
return 0;
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 0d873c58e516..f1fc48e9689c 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -728,8 +728,10 @@ static int sctp_v6_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr)
sctp_v6_map_v4(addr);
}
- if (addr->sa.sa_family == AF_INET)
+ if (addr->sa.sa_family == AF_INET) {
+ memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero));
return sizeof(struct sockaddr_in);
+ }
return sizeof(struct sockaddr_in6);
}
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 7a10ae3c3d82..eb712df7156e 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -357,11 +357,14 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
if (!opt->pf->af_supported(addr->sa.sa_family, opt))
return NULL;
- /* V4 mapped address are really of AF_INET family */
- if (addr->sa.sa_family == AF_INET6 &&
- ipv6_addr_v4mapped(&addr->v6.sin6_addr) &&
- !opt->pf->af_supported(AF_INET, opt))
- return NULL;
+ if (addr->sa.sa_family == AF_INET6) {
+ if (len < SIN6_LEN_RFC2133)
+ return NULL;
+ /* V4 mapped address are really of AF_INET family */
+ if (ipv6_addr_v4mapped(&addr->v6.sin6_addr) &&
+ !opt->pf->af_supported(AF_INET, opt))
+ return NULL;
+ }
/* If we get this far, af is valid. */
af = sctp_get_af_specific(addr->sa.sa_family);
diff --git a/net/tipc/diag.c b/net/tipc/diag.c
index 46d9cd62f781..aaabb0b776dd 100644
--- a/net/tipc/diag.c
+++ b/net/tipc/diag.c
@@ -59,7 +59,7 @@ static int __tipc_add_sock_diag(struct sk_buff *skb,
if (!nlh)
return -EMSGSIZE;
- err = tipc_sk_fill_sock_diag(skb, tsk, req->tidiag_states,
+ err = tipc_sk_fill_sock_diag(skb, cb, tsk, req->tidiag_states,
__tipc_diag_gen_cookie);
if (err)
return err;
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 3e5eba30865e..1fd1c8b5ce03 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -3257,8 +3257,8 @@ out:
}
EXPORT_SYMBOL(tipc_nl_sk_walk);
-int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct tipc_sock *tsk,
- u32 sk_filter_state,
+int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct netlink_callback *cb,
+ struct tipc_sock *tsk, u32 sk_filter_state,
u64 (*tipc_diag_gen_cookie)(struct sock *sk))
{
struct sock *sk = &tsk->sk;
@@ -3280,7 +3280,8 @@ int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct tipc_sock *tsk,
nla_put_u32(skb, TIPC_NLA_SOCK_TIPC_STATE, (u32)sk->sk_state) ||
nla_put_u32(skb, TIPC_NLA_SOCK_INO, sock_i_ino(sk)) ||
nla_put_u32(skb, TIPC_NLA_SOCK_UID,
- from_kuid_munged(sk_user_ns(sk), sock_i_uid(sk))) ||
+ from_kuid_munged(sk_user_ns(NETLINK_CB(cb->skb).sk),
+ sock_i_uid(sk))) ||
nla_put_u64_64bit(skb, TIPC_NLA_SOCK_COOKIE,
tipc_diag_gen_cookie(sk),
TIPC_NLA_SOCK_PAD))
diff --git a/net/tipc/socket.h b/net/tipc/socket.h
index aae3fd4cd06c..aff9b2ae5a1f 100644
--- a/net/tipc/socket.h
+++ b/net/tipc/socket.h
@@ -61,8 +61,8 @@ int tipc_sk_rht_init(struct net *net);
void tipc_sk_rht_destroy(struct net *net);
int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb);
int tipc_nl_publ_dump(struct sk_buff *skb, struct netlink_callback *cb);
-int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct tipc_sock *tsk,
- u32 sk_filter_state,
+int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct netlink_callback *cb,
+ struct tipc_sock *tsk, u32 sk_filter_state,
u64 (*tipc_diag_gen_cookie)(struct sock *sk));
int tipc_nl_sk_walk(struct sk_buff *skb, struct netlink_callback *cb,
int (*skb_handler)(struct sk_buff *skb,
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index 6925a989569b..b7d80bc5f4ab 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -145,6 +145,8 @@ struct tipc_subscription *tipc_sub_subscribe(struct net *net,
pr_warn("Subscription rejected, no memory\n");
return NULL;
}
+ INIT_LIST_HEAD(&sub->service_list);
+ INIT_LIST_HEAD(&sub->sub_list);
sub->net = net;
sub->conid = conid;
sub->inactive = false;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index aded82da1aea..68bb70a62afe 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -745,14 +745,6 @@ static struct proto unix_proto = {
.obj_size = sizeof(struct unix_sock),
};
-/*
- * AF_UNIX sockets do not interact with hardware, hence they
- * dont trigger interrupts - so it's safe for them to have
- * bh-unsafe locking for their sk_receive_queue.lock. Split off
- * this special lock-class by reinitializing the spinlock key:
- */
-static struct lock_class_key af_unix_sk_receive_queue_lock_key;
-
static struct sock *unix_create1(struct net *net, struct socket *sock, int kern)
{
struct sock *sk = NULL;
@@ -767,8 +759,6 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern)
goto out;
sock_init_data(sock, sk);
- lockdep_set_class(&sk->sk_receive_queue.lock,
- &af_unix_sk_receive_queue_lock_key);
sk->sk_allocation = GFP_KERNEL_ACCOUNT;
sk->sk_write_space = unix_write_space;
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 065324a8046f..cce31ee876b6 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -237,9 +237,7 @@ cc-ldoption = $(call try-run-cached,\
# ld-option
# Usage: LDFLAGS += $(call ld-option, -X)
-ld-option = $(call try-run-cached,\
- $(CC) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -x c /dev/null -c -o "$$TMPO"; \
- $(LD) $(LDFLAGS) $(1) "$$TMPO" -o "$$TMP",$(1),$(2))
+ld-option = $(call try-run-cached, $(LD) $(LDFLAGS) $(1) -v,$(1),$(2))
# ar-option
# Usage: KBUILD_ARFLAGS := $(call ar-option,D)
@@ -368,7 +366,7 @@ ksym_dep_filter = \
$(CPP) $(call flags_nodeps,a_flags) -D__KSYM_DEPS__ $< ;; \
boot*|build*|cpp_its_S|*cpp_lds_S|dtc|host*|vdso*) : ;; \
*) echo "Don't know how to preprocess $(1)" >&2; false ;; \
- esac | tr ";" "\n" | sed -rn 's/^.*=== __KSYM_(.*) ===.*$$/KSYM_\1/p'
+ esac | tr ";" "\n" | sed -n 's/^.*=== __KSYM_\(.*\) ===.*$$/_\1/p'
cmd_and_fixdep = \
$(echo-cmd) $(cmd_$(1)); \
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 4f2b25d43ec9..77cce68c4d63 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -73,11 +73,11 @@ endif
ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
lib-target := $(obj)/lib.a
-obj-y += $(obj)/lib-ksyms.o
+real-obj-y += $(obj)/lib-ksyms.o
endif
-ifneq ($(strip $(obj-y) $(need-builtin)),)
-builtin-target := $(obj)/built-in.o
+ifneq ($(strip $(real-obj-y) $(need-builtin)),)
+builtin-target := $(obj)/built-in.a
endif
modorder-target := $(obj)/modules.order
@@ -104,7 +104,7 @@ ifneq ($(KBUILD_ENABLE_EXTRA_GCC_CHECKS),)
cmd_checkdoc = $(srctree)/scripts/kernel-doc -none $< ;
endif
-# Do section mismatch analysis for each module/built-in.o
+# Do section mismatch analysis for each module/built-in.a
ifdef CONFIG_DEBUG_SECTION_MISMATCH
cmd_secanalysis = ; scripts/mod/modpost $@
endif
@@ -119,29 +119,17 @@ modkern_cflags = \
$(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL))
quiet_modtag := $(empty) $(empty)
-$(real-objs-m) : part-of-module := y
-$(real-objs-m:.o=.i) : part-of-module := y
-$(real-objs-m:.o=.s) : part-of-module := y
-$(real-objs-m:.o=.lst): part-of-module := y
+$(real-obj-m) : part-of-module := y
+$(real-obj-m:.o=.i) : part-of-module := y
+$(real-obj-m:.o=.s) : part-of-module := y
+$(real-obj-m:.o=.lst): part-of-module := y
-$(real-objs-m) : quiet_modtag := [M]
-$(real-objs-m:.o=.i) : quiet_modtag := [M]
-$(real-objs-m:.o=.s) : quiet_modtag := [M]
-$(real-objs-m:.o=.lst): quiet_modtag := [M]
+$(real-obj-m) : quiet_modtag := [M]
+$(real-obj-m:.o=.i) : quiet_modtag := [M]
+$(real-obj-m:.o=.s) : quiet_modtag := [M]
+$(real-obj-m:.o=.lst): quiet_modtag := [M]
-$(obj-m) : quiet_modtag := [M]
-
-# Default for not multi-part modules
-modname = $(basetarget)
-
-$(multi-objs-m) : modname = $(modname-multi)
-$(multi-objs-m:.o=.i) : modname = $(modname-multi)
-$(multi-objs-m:.o=.s) : modname = $(modname-multi)
-$(multi-objs-m:.o=.lst) : modname = $(modname-multi)
-$(multi-objs-y) : modname = $(modname-multi)
-$(multi-objs-y:.o=.i) : modname = $(modname-multi)
-$(multi-objs-y:.o=.s) : modname = $(modname-multi)
-$(multi-objs-y:.o=.lst) : modname = $(modname-multi)
+$(obj-m) : quiet_modtag := [M]
quiet_cmd_cc_s_c = CC $(quiet_modtag) $@
cmd_cc_s_c = $(CC) $(c_flags) $(DISABLE_LTO) -fverbose-asm -S -o $@ $<
@@ -314,7 +302,7 @@ endef
# List module undefined symbols (or empty line if not enabled)
ifdef CONFIG_TRIM_UNUSED_KSYMS
-cmd_undef_syms = $(NM) $@ | sed -n 's/^ \+U //p' | xargs echo
+cmd_undef_syms = $(NM) $@ | sed -n 's/^ *U //p' | xargs echo
else
cmd_undef_syms = echo
endif
@@ -345,8 +333,8 @@ $(obj)/%.lst: $(src)/%.c FORCE
modkern_aflags := $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL)
-$(real-objs-m) : modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE)
-$(real-objs-m:.o=.s): modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE)
+$(real-obj-m) : modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE)
+$(real-obj-m:.o=.s): modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE)
# .S file exports must have their C prototypes defined in asm/asm-prototypes.h
# or a file that it includes, in order to get versioned symbols. We build a
@@ -424,7 +412,7 @@ endif
$(obj)/%.o: $(src)/%.S $(objtool_dep) FORCE
$(call if_changed_rule,as_o_S)
-targets += $(real-objs-y) $(real-objs-m) $(lib-y)
+targets += $(filter-out $(subdir-obj-y), $(real-obj-y)) $(real-obj-m) $(lib-y)
targets += $(extra-y) $(MAKECMDGOALS) $(always)
# Linker scripts preprocessor (.lds.S -> .lds)
@@ -458,24 +446,16 @@ $(sort $(subdir-obj-y)): $(subdir-ym) ;
#
ifdef builtin-target
-ifdef CONFIG_THIN_ARCHIVES
- cmd_make_builtin = rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS)
- cmd_make_empty_builtin = rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS)
- quiet_cmd_link_o_target = AR $@
-else
- cmd_make_builtin = $(LD) $(ld_flags) -r -o
- cmd_make_empty_builtin = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS)
- quiet_cmd_link_o_target = LD $@
-endif
-
-# If the list of objects to link is empty, just create an empty built-in.o
-cmd_link_o_target = $(if $(strip $(obj-y)),\
- $(cmd_make_builtin) $@ $(filter $(obj-y), $^) \
- $(cmd_secanalysis),\
- $(cmd_make_empty_builtin) $@)
+# built-in.a archives are made with no symbol table or index which
+# makes them small and fast, but unable to be used by the linker.
+# scripts/link-vmlinux.sh builds an aggregate built-in.a with a symbol
+# table and index.
+quiet_cmd_ar_builtin = AR $@
+ cmd_ar_builtin = rm -f $@; \
+ $(AR) rcSTP$(KBUILD_ARFLAGS) $@ $(filter $(real-obj-y), $^)
-$(builtin-target): $(obj-y) FORCE
- $(call if_changed,link_o_target)
+$(builtin-target): $(real-obj-y) FORCE
+ $(call if_changed,ar_builtin)
targets += $(builtin-target)
endif # builtin-target
@@ -499,11 +479,8 @@ $(modorder-target): $(subdir-ym) FORCE
ifdef lib-target
quiet_cmd_link_l_target = AR $@
-ifdef CONFIG_THIN_ARCHIVES
- cmd_link_l_target = rm -f $@; $(AR) rcsTP$(KBUILD_ARFLAGS) $@ $(lib-y)
-else
- cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y)
-endif
+# lib target archives do get a symbol table and index
+cmd_link_l_target = rm -f $@; $(AR) rcsTP$(KBUILD_ARFLAGS) $@ $(lib-y)
$(lib-target): $(lib-y) FORCE
$(call if_changed,link_l_target)
@@ -549,22 +526,8 @@ $($(subst $(obj)/,,$(@:.o=-objs))) \
$($(subst $(obj)/,,$(@:.o=-y))) \
$($(subst $(obj)/,,$(@:.o=-m)))), $^)
-cmd_link_multi-link = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis)
-
-ifdef CONFIG_THIN_ARCHIVES
- quiet_cmd_link_multi-y = AR $@
- cmd_link_multi-y = rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS) $@ $(link_multi_deps)
-else
- quiet_cmd_link_multi-y = LD $@
- cmd_link_multi-y = $(cmd_link_multi-link)
-endif
-
quiet_cmd_link_multi-m = LD [M] $@
-cmd_link_multi-m = $(cmd_link_multi-link)
-
-$(multi-used-y): FORCE
- $(call if_changed,link_multi-y)
-$(call multi_depend, $(multi-used-y), .o, -objs -y)
+cmd_link_multi-m = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis)
$(multi-used-m): FORCE
$(call if_changed,link_multi-m)
@@ -572,7 +535,7 @@ $(multi-used-m): FORCE
$(cmd_undef_syms); } > $(MODVERDIR)/$(@F:.o=.mod)
$(call multi_depend, $(multi-used-m), .o, -objs -y -m)
-targets += $(multi-used-y) $(multi-used-m)
+targets += $(multi-used-m)
targets := $(filter-out $(PHONY), $(targets))
# Descending
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index a6f538b31ad6..e3215b7652ee 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -27,7 +27,7 @@ modorder := $(patsubst %/,%/modules.order, $(filter %/, $(obj-y)) $(obj-m:.o=.ko
# Handle objects in subdirs
# ---------------------------------------------------------------------------
-# o if we encounter foo/ in $(obj-y), replace it by foo/built-in.o
+# o if we encounter foo/ in $(obj-y), replace it by foo/built-in.a
# and add the directory to the list of dirs to descend into: $(subdir-y)
# o if we encounter foo/ in $(obj-m), remove it from $(obj-m)
# and add the directory to the list of dirs to descend into: $(subdir-m)
@@ -35,7 +35,7 @@ __subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y += $(__subdir-y)
__subdir-m := $(patsubst %/,%,$(filter %/, $(obj-m)))
subdir-m += $(__subdir-m)
-obj-y := $(patsubst %/, %/built-in.o, $(obj-y))
+obj-y := $(patsubst %/, %/built-in.a, $(obj-y))
obj-m := $(filter-out %/, $(obj-m))
# Subdirectories we need to descend into
@@ -47,18 +47,14 @@ multi-used-m := $(sort $(foreach m,$(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m
multi-used := $(multi-used-y) $(multi-used-m)
single-used-m := $(sort $(filter-out $(multi-used-m),$(obj-m)))
-# Build list of the parts of our composite objects, our composite
-# objects depend on those (obviously)
-multi-objs-y := $(foreach m, $(multi-used-y), $($(m:.o=-objs)) $($(m:.o=-y)))
-multi-objs-m := $(foreach m, $(multi-used-m), $($(m:.o=-objs)) $($(m:.o=-y)))
-
# $(subdir-obj-y) is the list of objects in $(obj-y) which uses dir/ to
# tell kbuild to descend
-subdir-obj-y := $(filter %/built-in.o, $(obj-y))
+subdir-obj-y := $(filter %/built-in.a, $(obj-y))
-# Replace multi-part objects by their individual parts, look at local dir only
-real-objs-y := $(foreach m, $(filter-out $(subdir-obj-y), $(obj-y)), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m)))
-real-objs-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m))),$($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m)),$(m)))
+# Replace multi-part objects by their individual parts,
+# including built-in.a from subdirectories
+real-obj-y := $(foreach m, $(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m)))
+real-obj-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m))),$($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m)),$(m)))
# DTB
# If CONFIG_OF_ALL_DTBS is enabled, all DT blobs are built
@@ -71,29 +67,29 @@ extra-y := $(addprefix $(obj)/,$(extra-y))
always := $(addprefix $(obj)/,$(always))
targets := $(addprefix $(obj)/,$(targets))
modorder := $(addprefix $(obj)/,$(modorder))
-obj-y := $(addprefix $(obj)/,$(obj-y))
obj-m := $(addprefix $(obj)/,$(obj-m))
lib-y := $(addprefix $(obj)/,$(lib-y))
subdir-obj-y := $(addprefix $(obj)/,$(subdir-obj-y))
-real-objs-y := $(addprefix $(obj)/,$(real-objs-y))
-real-objs-m := $(addprefix $(obj)/,$(real-objs-m))
+real-obj-y := $(addprefix $(obj)/,$(real-obj-y))
+real-obj-m := $(addprefix $(obj)/,$(real-obj-m))
single-used-m := $(addprefix $(obj)/,$(single-used-m))
-multi-used-y := $(addprefix $(obj)/,$(multi-used-y))
multi-used-m := $(addprefix $(obj)/,$(multi-used-m))
-multi-objs-y := $(addprefix $(obj)/,$(multi-objs-y))
-multi-objs-m := $(addprefix $(obj)/,$(multi-objs-m))
subdir-ym := $(addprefix $(obj)/,$(subdir-ym))
+# Finds the multi-part object the current object will be linked into.
+# If the object belongs to two or more multi-part objects, all of them are
+# concatenated with a colon separator.
+modname-multi = $(subst $(space),:,$(sort $(foreach m,$(multi-used),\
+ $(if $(filter $*.o, $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m))),$(m:.o=)))))
+
+modname = $(if $(modname-multi),$(modname-multi),$(basetarget))
+
# These flags are needed for modversions and compiling, so we define them here
# $(modname_flags) defines KBUILD_MODNAME as the name of the module it will
# end up in (or would, if it gets compiled in)
-# Note: Files that end up in two or more modules are compiled without the
-# KBUILD_MODNAME definition. The reason is that any made-up name would
-# differ in different configs.
name-fix = $(squote)$(quote)$(subst $(comma),_,$(subst -,_,$1))$(quote)$(squote)
basename_flags = -DKBUILD_BASENAME=$(call name-fix,$(basetarget))
-modname_flags = $(if $(filter 1,$(words $(modname))),\
- -DKBUILD_MODNAME=$(call name-fix,$(modname)))
+modname_flags = -DKBUILD_MODNAME=$(call name-fix,$(modname))
orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
$(ccflags-y) $(CFLAGS_$(basetarget).o)
@@ -156,6 +152,7 @@ __cpp_flags = $(call flags,_cpp_flags)
endif
c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \
+ -include $(srctree)/include/linux/compiler_types.h \
$(__c_flags) $(modkern_cflags) \
$(basename_flags) $(modname_flags)
@@ -173,10 +170,6 @@ dtc_cpp_flags = -Wp,-MD,$(depfile).pre.tmp -nostdinc \
$(addprefix -I,$(DTC_INCLUDE)) \
-undef -D__DTS__
-# Finds the multi-part object the current object will be linked into
-modname-multi = $(sort $(foreach m,$(multi-used),\
- $(if $(filter $(subst $(obj)/,,$*.o), $($(m:.o=-objs)) $($(m:.o=-y))),$(m:.o=))))
-
# Useful for describing the dependency of composite objects
# Usage:
# $(call multi_depend, multi_used_targets, suffix_to_remove, suffix_to_add)
@@ -329,7 +322,7 @@ dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
size_append = printf $(shell \
dec_size=0; \
for F in $1; do \
- fsize=$$(stat -c "%s" $$F); \
+ fsize=$$($(CONFIG_SHELL) $(srctree)/scripts/file-size.sh $$F); \
dec_size=$$(expr $$dec_size + $$fsize); \
done; \
printf "%08x\n" $$dec_size | \
diff --git a/scripts/adjust_autoksyms.sh b/scripts/adjust_autoksyms.sh
index d67830e6e360..016b3c48a4ec 100755
--- a/scripts/adjust_autoksyms.sh
+++ b/scripts/adjust_autoksyms.sh
@@ -48,9 +48,6 @@ case "${KCONFIG_CONFIG}" in
. "./${KCONFIG_CONFIG}"
esac
-# In case it doesn't exist yet...
-if [ -e "$cur_ksyms_file" ]; then touch "$cur_ksyms_file"; fi
-
# Generate a new ksym list file with symbols needed by the current
# set of modules.
cat > "$new_ksyms_file" << EOT
@@ -60,7 +57,9 @@ cat > "$new_ksyms_file" << EOT
EOT
[ "$(ls -A "$MODVERDIR")" ] &&
-sed -ns -e '3{s/ /\n/g;/^$/!p;}' "$MODVERDIR"/*.mod | sort -u |
+for mod in "$MODVERDIR"/*.mod; do
+ sed -n -e '3{s/ /\n/g;/^$/!p;}' "$mod"
+done | sort -u |
while read sym; do
if [ -n "$CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX" ]; then
sym="${sym#_}"
@@ -81,7 +80,7 @@ sort "$cur_ksyms_file" "$new_ksyms_file" | uniq -u |
sed -n 's/^#define __KSYM_\(.*\) 1/\1/p' | tr "A-Z_" "a-z/" |
while read sympath; do
if [ -z "$sympath" ]; then continue; fi
- depfile="include/config/ksym/${sympath}.h"
+ depfile="include/ksym/${sympath}.h"
mkdir -p "$(dirname "$depfile")"
touch "$depfile"
# Filesystems with coarse time precision may create timestamps
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index 449b68c4c90c..f387538c58bc 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -113,11 +113,11 @@ static void usage(void)
/*
* Print out a dependency path from a symbol name
*/
-static void print_config(const char *m, int slen)
+static void print_dep(const char *m, int slen, const char *dir)
{
int c, i;
- printf(" $(wildcard include/config/");
+ printf(" $(wildcard %s/", dir);
for (i = 0; i < slen; i++) {
c = m[i];
if (c == '_')
@@ -140,7 +140,7 @@ static void do_extra_deps(void)
fprintf(stderr, "fixdep: bad data on stdin\n");
exit(1);
}
- print_config(buf, len - 1);
+ print_dep(buf, len - 1, "include/ksym");
}
}
@@ -208,7 +208,7 @@ static void use_config(const char *m, int slen)
return;
define_config(m, slen, hash);
- print_config(m, slen);
+ print_dep(m, slen, "include/config");
}
/* test if s ends in sub */
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 949842e8c97e..764ffd1bb1c5 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2797,7 +2797,10 @@ sub process {
# Only applies when adding the entry originally, after that we do not have
# sufficient context to determine whether it is indeed long enough.
if ($realfile =~ /Kconfig/ &&
- $line =~ /^\+\s*config\s+/) {
+ # 'choice' is usually the last thing on the line (though
+ # Kconfig supports named choices), so use a word boundary
+ # (\b) rather than a whitespace character (\s)
+ $line =~ /^\+\s*(?:config|menuconfig|choice)\b/) {
my $length = 0;
my $cnt = $realcnt;
my $ln = $linenr + 1;
@@ -2812,9 +2815,13 @@ sub process {
next if ($f =~ /^-/);
last if (!$file && $f =~ /^\@\@/);
- if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate)\s*\"/) {
+ if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) {
$is_start = 1;
- } elsif ($lines[$ln - 1] =~ /^\+\s*(?:---)?help(?:---)?$/) {
+ } elsif ($lines[$ln - 1] =~ /^\+\s*(?:help|---help---)\s*$/) {
+ if ($lines[$ln - 1] =~ "---help---") {
+ WARN("CONFIG_DESCRIPTION",
+ "prefer 'help' over '---help---' for new help texts\n" . $herecurr);
+ }
$length = -1;
}
@@ -2822,7 +2829,13 @@ sub process {
$f =~ s/#.*//;
$f =~ s/^\s+//;
next if ($f =~ /^$/);
- if ($f =~ /^\s*config\s/) {
+
+ # This only checks context lines in the patch
+ # and so hopefully shouldn't trigger false
+ # positives, even though some of these are
+ # common words in help texts
+ if ($f =~ /^\s*(?:config|menuconfig|choice|endchoice|
+ if|endif|menu|endmenu|source)\b/x) {
$is_end = 1;
last;
}
diff --git a/scripts/clang-version.sh b/scripts/clang-version.sh
new file mode 100755
index 000000000000..9780efa56980
--- /dev/null
+++ b/scripts/clang-version.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# clang-version [-p] clang-command
+#
+# Prints the compiler version of `clang-command' in a canonical 4-digit form
+# such as `0500' for clang-5.0 etc.
+#
+# With the -p option, prints the patchlevel as well, for example `050001' for
+# clang-5.0.1 etc.
+#
+
+if [ "$1" = "-p" ] ; then
+ with_patchlevel=1;
+ shift;
+fi
+
+compiler="$*"
+
+if [ ${#compiler} -eq 0 ]; then
+ echo "Error: No compiler specified."
+ printf "Usage:\n\t$0 <clang-command>\n"
+ exit 1
+fi
+
+MAJOR=$(echo __clang_major__ | $compiler -E -x c - | tail -n 1)
+MINOR=$(echo __clang_minor__ | $compiler -E -x c - | tail -n 1)
+if [ "x$with_patchlevel" != "x" ] ; then
+ PATCHLEVEL=$(echo __clang_patchlevel__ | $compiler -E -x c - | tail -n 1)
+ printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL
+else
+ printf "%02d%02d\\n" $MAJOR $MINOR
+fi
diff --git a/scripts/file-size.sh b/scripts/file-size.sh
new file mode 100755
index 000000000000..7eb7423416b5
--- /dev/null
+++ b/scripts/file-size.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+set -- $(ls -dn "$1")
+printf '%s\n' "$5"
diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh
index 86a3c0e5cfbc..10e528b3a08f 100755
--- a/scripts/gen_initramfs_list.sh
+++ b/scripts/gen_initramfs_list.sh
@@ -194,7 +194,7 @@ input_file() {
source="$1"
if [ -f "$1" ]; then
${dep_list}header "$1"
- is_cpio="$(echo "$1" | sed 's/^.*\.cpio\(\..*\)\?/cpio/')"
+ is_cpio="$(echo "$1" | sed 's/^.*\.cpio\(\..*\)\{0,1\}/cpio/')"
if [ $2 -eq 0 -a ${is_cpio} = "cpio" ]; then
cpio_file=$1
echo "$1" | grep -q '^.*\.cpio\..*' && is_cpio_compressed="compressed"
diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh
index a18bca720995..593f8879c641 100755
--- a/scripts/headers_install.sh
+++ b/scripts/headers_install.sh
@@ -31,13 +31,13 @@ trap 'rm -f "$OUTDIR/$FILE" "$OUTDIR/$FILE.sed"' EXIT
for i in "$@"
do
FILE="$(basename "$i")"
- sed -r \
- -e 's/([ \t(])(__user|__force|__iomem)[ \t]/\1/g' \
- -e 's/__attribute_const__([ \t]|$)/\1/g' \
+ sed -E \
+ -e 's/([[:space:](])(__user|__force|__iomem)[[:space:]]/\1/g' \
+ -e 's/__attribute_const__([[:space:]]|$)/\1/g' \
-e 's@^#include <linux/compiler(|_types).h>@@' \
-e 's/(^|[^a-zA-Z0-9])__packed([^a-zA-Z0-9_]|$)/\1__attribute__((packed))\2/g' \
- -e 's/(^|[ \t(])(inline|asm|volatile)([ \t(]|$)/\1__\2__\3/g' \
- -e 's@#(ifndef|define|endif[ \t]*/[*])[ \t]*_UAPI@#\1 @' \
+ -e 's/(^|[[:space:](])(inline|asm|volatile)([[:space:](]|$)/\1__\2__\3/g' \
+ -e 's@#(ifndef|define|endif[[:space:]]*/[*])[[:space:]]*_UAPI@#\1 @' \
"$SRCDIR/$i" > "$OUTDIR/$FILE.sed" || exit 1
scripts/unifdef -U__KERNEL__ -D__EXPORTED_HEADERS__ "$OUTDIR/$FILE.sed" \
> "$OUTDIR/$FILE"
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 65792650c630..5abfbf1b8fe2 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -221,6 +221,7 @@ static int symbol_valid(struct sym_entry *s)
static char *special_prefixes[] = {
"__crc_", /* modversions */
+ "__efistub_", /* arm64 EFI stub namespace */
NULL };
static char *special_suffixes[] = {
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index cb3ec53a7c29..f9bdd02c06a2 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -3,7 +3,7 @@
# Kernel configuration targets
# These targets are used from top-level makefile
-PHONY += xconfig gconfig menuconfig config silentoldconfig update-po-config \
+PHONY += xconfig gconfig menuconfig config syncconfig update-po-config \
localmodconfig localyesconfig
ifdef KBUILD_KCONFIG
@@ -36,24 +36,22 @@ nconfig: $(obj)/nconf
# This has become an internal implementation detail and is now deprecated
# for external use.
-silentoldconfig: $(obj)/conf
+syncconfig: $(obj)/conf
$(Q)mkdir -p include/config include/generated
- $(Q)test -e include/generated/autoksyms.h || \
- touch include/generated/autoksyms.h
$< $(silent) --$@ $(Kconfig)
-localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
+localyesconfig localmodconfig: $(obj)/conf
$(Q)mkdir -p include/config include/generated
- $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config
+ $(Q)perl $(srctree)/$(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config
$(Q)if [ -f .config ]; then \
cmp -s .tmp.config .config || \
(mv -f .config .config.old.1; \
mv -f .tmp.config .config; \
- $(obj)/conf $(silent) --silentoldconfig $(Kconfig); \
+ $< $(silent) --oldconfig $(Kconfig); \
mv -f .config.old.1 .config.old) \
else \
mv -f .tmp.config .config; \
- $(obj)/conf $(silent) --silentoldconfig $(Kconfig); \
+ $< $(silent) --oldconfig $(Kconfig); \
fi
$(Q)rm -f .tmp.config
@@ -88,7 +86,7 @@ PHONY += $(simple-targets)
$(simple-targets): $(obj)/conf
$< $(silent) --$@ $(Kconfig)
-PHONY += oldnoconfig savedefconfig defconfig
+PHONY += oldnoconfig silentoldconfig savedefconfig defconfig
# oldnoconfig is an alias of olddefconfig, because people already are dependent
# on its behavior (sets new symbols to their default value but not 'n') with the
@@ -97,6 +95,13 @@ oldnoconfig: olddefconfig
@echo " WARNING: \"oldnoconfig\" target will be removed after Linux 4.19"
@echo " Please use \"olddefconfig\" instead, which is an alias."
+# We do not expect manual invokcation of "silentoldcofig" (or "syncconfig").
+silentoldconfig: syncconfig
+ @echo " WARNING: \"silentoldconfig\" has been renamed to \"syncconfig\""
+ @echo " and is now an internal implementation detail."
+ @echo " What you want is probably \"oldconfig\"."
+ @echo " \"silentoldconfig\" will be removed after Linux 4.19"
+
savedefconfig: $(obj)/conf
$< $(silent) --$@=defconfig $(Kconfig)
@@ -135,6 +140,14 @@ PHONY += tinyconfig
tinyconfig:
$(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config
+# CHECK: -o cache_dir=<path> working?
+PHONY += testconfig
+testconfig: $(obj)/conf
+ $(PYTHON3) -B -m pytest $(srctree)/$(src)/tests \
+ -o cache_dir=$(abspath $(obj)/tests/.cache) \
+ $(if $(findstring 1,$(KBUILD_VERBOSE)),--capture=no)
+clean-dirs += tests/.cache
+
# Help text used by make help
help:
@echo ' config - Update current config utilising a line-oriented program'
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 822dc51923d6..4e08121a35fb 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -23,7 +23,7 @@ static void check_conf(struct menu *menu);
enum input_mode {
oldaskconfig,
- silentoldconfig,
+ syncconfig,
oldconfig,
allnoconfig,
allyesconfig,
@@ -100,7 +100,7 @@ static int conf_askvalue(struct symbol *sym, const char *def)
switch (input_mode) {
case oldconfig:
- case silentoldconfig:
+ case syncconfig:
if (sym_has_value(sym)) {
printf("%s\n", def);
return 0;
@@ -293,7 +293,7 @@ static int conf_choice(struct menu *menu)
printf("[1-%d?]: ", cnt);
switch (input_mode) {
case oldconfig:
- case silentoldconfig:
+ case syncconfig:
if (!is_new) {
cnt = def;
printf("%d\n", cnt);
@@ -358,10 +358,11 @@ static void conf(struct menu *menu)
switch (prop->type) {
case P_MENU:
- if ((input_mode == silentoldconfig ||
- input_mode == listnewconfig ||
- input_mode == olddefconfig) &&
- rootEntry != menu) {
+ /*
+ * Except in oldaskconfig mode, we show only menus that
+ * contain new symbols.
+ */
+ if (input_mode != oldaskconfig && rootEntry != menu) {
check_conf(menu);
return;
}
@@ -424,7 +425,7 @@ static void check_conf(struct menu *menu)
if (sym->name && !sym_is_choice_value(sym)) {
printf("%s%s\n", CONFIG_, sym->name);
}
- } else if (input_mode != olddefconfig) {
+ } else {
if (!conf_cnt++)
printf(_("*\n* Restart config...\n*\n"));
rootEntry = menu_get_parent_menu(menu);
@@ -440,7 +441,7 @@ static void check_conf(struct menu *menu)
static struct option long_opts[] = {
{"oldaskconfig", no_argument, NULL, oldaskconfig},
{"oldconfig", no_argument, NULL, oldconfig},
- {"silentoldconfig", no_argument, NULL, silentoldconfig},
+ {"syncconfig", no_argument, NULL, syncconfig},
{"defconfig", optional_argument, NULL, defconfig},
{"savedefconfig", required_argument, NULL, savedefconfig},
{"allnoconfig", no_argument, NULL, allnoconfig},
@@ -467,8 +468,8 @@ static void conf_usage(const char *progname)
printf(" --listnewconfig List new options\n");
printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
printf(" --oldconfig Update a configuration using a provided .config as base\n");
- printf(" --silentoldconfig Similar to oldconfig but generates configuration in\n"
- " include/{generated/,config/} (oldconfig used to be more verbose)\n");
+ printf(" --syncconfig Similar to oldconfig but generates configuration in\n"
+ " include/{generated/,config/}\n");
printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
printf(" --oldnoconfig An alias of olddefconfig\n");
printf(" --defconfig <file> New config with default defined in <file>\n");
@@ -500,7 +501,7 @@ int main(int ac, char **av)
}
input_mode = (enum input_mode)opt;
switch (opt) {
- case silentoldconfig:
+ case syncconfig:
sync_kconfig = 1;
break;
case defconfig:
@@ -582,7 +583,7 @@ int main(int ac, char **av)
}
break;
case savedefconfig:
- case silentoldconfig:
+ case syncconfig:
case oldaskconfig:
case oldconfig:
case listnewconfig:
@@ -662,24 +663,24 @@ int main(int ac, char **av)
case oldaskconfig:
rootEntry = &rootmenu;
conf(&rootmenu);
- input_mode = silentoldconfig;
+ input_mode = oldconfig;
/* fall through */
case oldconfig:
case listnewconfig:
- case olddefconfig:
- case silentoldconfig:
+ case syncconfig:
/* Update until a loop caused no more changes */
do {
conf_cnt = 0;
check_conf(&rootmenu);
- } while (conf_cnt &&
- (input_mode != listnewconfig &&
- input_mode != olddefconfig));
+ } while (conf_cnt);
+ break;
+ case olddefconfig:
+ default:
break;
}
if (sync_kconfig) {
- /* silentoldconfig is used during the build so we shall update autoconf.
+ /* syncconfig is used during the build so we shall update autoconf.
* All other commands are only used to generate a config.
*/
if (conf_get_changed() && conf_write(NULL)) {
diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c
index d45381986ac7..e1a39e90841d 100644
--- a/scripts/kconfig/expr.c
+++ b/scripts/kconfig/expr.c
@@ -1137,49 +1137,9 @@ static int expr_compare_type(enum expr_type t1, enum expr_type t2)
return 0;
}
-static inline struct expr *
-expr_get_leftmost_symbol(const struct expr *e)
-{
-
- if (e == NULL)
- return NULL;
-
- while (e->type != E_SYMBOL)
- e = e->left.expr;
-
- return expr_copy(e);
-}
-
-/*
- * Given expression `e1' and `e2', returns the leaf of the longest
- * sub-expression of `e1' not containing 'e2.
- */
-struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
-{
- struct expr *ret;
-
- switch (e1->type) {
- case E_OR:
- return expr_alloc_and(
- expr_simplify_unmet_dep(e1->left.expr, e2),
- expr_simplify_unmet_dep(e1->right.expr, e2));
- case E_AND: {
- struct expr *e;
- e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
- e = expr_eliminate_dups(e);
- ret = (!expr_eq(e, e1)) ? e1 : NULL;
- expr_free(e);
- break;
- }
- default:
- ret = e1;
- break;
- }
-
- return expr_get_leftmost_symbol(ret);
-}
-
-static void __expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken, bool revdep)
+void expr_print(struct expr *e,
+ void (*fn)(void *, struct symbol *, const char *),
+ void *data, int prevtoken)
{
if (!e) {
fn(data, NULL, "y");
@@ -1234,14 +1194,9 @@ static void __expr_print(struct expr *e, void (*fn)(void *, struct symbol *, con
fn(data, e->right.sym, e->right.sym->name);
break;
case E_OR:
- if (revdep && e->left.expr->type != E_OR)
- fn(data, NULL, "\n - ");
- __expr_print(e->left.expr, fn, data, E_OR, revdep);
- if (revdep)
- fn(data, NULL, "\n - ");
- else
- fn(data, NULL, " || ");
- __expr_print(e->right.expr, fn, data, E_OR, revdep);
+ expr_print(e->left.expr, fn, data, E_OR);
+ fn(data, NULL, " || ");
+ expr_print(e->right.expr, fn, data, E_OR);
break;
case E_AND:
expr_print(e->left.expr, fn, data, E_AND);
@@ -1274,11 +1229,6 @@ static void __expr_print(struct expr *e, void (*fn)(void *, struct symbol *, con
fn(data, NULL, ")");
}
-void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
-{
- __expr_print(e, fn, data, prevtoken, false);
-}
-
static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
{
xfwrite(str, strlen(str), 1, data);
@@ -1329,7 +1279,27 @@ void expr_gstr_print(struct expr *e, struct gstr *gs)
* line with a minus. This makes expressions much easier to read.
* Suitable for reverse dependency expressions.
*/
-void expr_gstr_print_revdep(struct expr *e, struct gstr *gs)
+static void expr_print_revdep(struct expr *e,
+ void (*fn)(void *, struct symbol *, const char *),
+ void *data, tristate pr_type, const char **title)
+{
+ if (e->type == E_OR) {
+ expr_print_revdep(e->left.expr, fn, data, pr_type, title);
+ expr_print_revdep(e->right.expr, fn, data, pr_type, title);
+ } else if (expr_calc_value(e) == pr_type) {
+ if (*title) {
+ fn(data, NULL, *title);
+ *title = NULL;
+ }
+
+ fn(data, NULL, " - ");
+ expr_print(e, fn, data, E_NONE);
+ fn(data, NULL, "\n");
+ }
+}
+
+void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
+ tristate pr_type, const char *title)
{
- __expr_print(e, expr_print_gstr_helper, gs, E_NONE, true);
+ expr_print_revdep(e, expr_print_gstr_helper, gs, pr_type, &title);
}
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index c16e82e302a2..94a383b21df6 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -305,12 +305,12 @@ struct expr *expr_transform(struct expr *e);
int expr_contains_symbol(struct expr *dep, struct symbol *sym);
bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
-struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
void expr_fprint(struct expr *e, FILE *out);
struct gstr; /* forward */
void expr_gstr_print(struct expr *e, struct gstr *gs);
-void expr_gstr_print_revdep(struct expr *e, struct gstr *gs);
+void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
+ tristate pr_type, const char *title);
static inline int expr_is_yes(struct expr *e)
{
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 2d5ec2d0e952..f4394af6e4b8 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -68,6 +68,7 @@ struct kconf_id {
enum symbol_type stype;
};
+extern int yylineno;
void zconfdump(FILE *out);
void zconf_starthelp(void);
FILE *zconf_fopen(const char *name);
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 36cd3e1f1c28..5c5c1374b151 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -828,16 +828,16 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym,
get_symbol_props_str(r, sym, P_SELECT, _(" Selects: "));
if (sym->rev_dep.expr) {
- str_append(r, _(" Selected by: "));
- expr_gstr_print_revdep(sym->rev_dep.expr, r);
- str_append(r, "\n");
+ expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, " Selected by [y]:\n");
+ expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, " Selected by [m]:\n");
+ expr_gstr_print_revdep(sym->rev_dep.expr, r, no, " Selected by [n]:\n");
}
get_symbol_props_str(r, sym, P_IMPLY, _(" Implies: "));
if (sym->implied.expr) {
- str_append(r, _(" Implied by: "));
- expr_gstr_print_revdep(sym->implied.expr, r);
- str_append(r, "\n");
+ expr_gstr_print_revdep(sym->implied.expr, r, yes, " Implied by [y]:\n");
+ expr_gstr_print_revdep(sym->implied.expr, r, mod, " Implied by [m]:\n");
+ expr_gstr_print_revdep(sym->implied.expr, r, no, " Implied by [n]:\n");
}
str_append(r, "\n\n");
diff --git a/scripts/kconfig/nconf.h b/scripts/kconfig/nconf.h
index 0d5261705ef5..9f6f21d3b0d4 100644
--- a/scripts/kconfig/nconf.h
+++ b/scripts/kconfig/nconf.h
@@ -15,7 +15,7 @@
#include <string.h>
#include <unistd.h>
#include <locale.h>
-#include <curses.h>
+#include <ncurses.h>
#include <menu.h>
#include <panel.h>
#include <form.h>
@@ -24,8 +24,6 @@
#include <time.h>
#include <sys/time.h>
-#include "ncurses.h"
-
#define max(a, b) ({\
typeof(a) _a = a;\
typeof(b) _b = b;\
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 2220bc4b051b..f0b2e3b3102d 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -243,7 +243,7 @@ static void sym_calc_visibility(struct symbol *sym)
tri = yes;
if (sym->dir_dep.expr)
tri = expr_calc_value(sym->dir_dep.expr);
- if (tri == mod)
+ if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
tri = yes;
if (sym->dir_dep.tri != tri) {
sym->dir_dep.tri = tri;
@@ -333,6 +333,27 @@ static struct symbol *sym_calc_choice(struct symbol *sym)
return def_sym;
}
+static void sym_warn_unmet_dep(struct symbol *sym)
+{
+ struct gstr gs = str_new();
+
+ str_printf(&gs,
+ "\nWARNING: unmet direct dependencies detected for %s\n",
+ sym->name);
+ str_printf(&gs,
+ " Depends on [%c]: ",
+ sym->dir_dep.tri == mod ? 'm' : 'n');
+ expr_gstr_print(sym->dir_dep.expr, &gs);
+ str_printf(&gs, "\n");
+
+ expr_gstr_print_revdep(sym->rev_dep.expr, &gs, yes,
+ " Selected by [y]:\n");
+ expr_gstr_print_revdep(sym->rev_dep.expr, &gs, mod,
+ " Selected by [m]:\n");
+
+ fputs(str_get(&gs), stderr);
+}
+
void sym_calc_value(struct symbol *sym)
{
struct symbol_value newval, oldval;
@@ -403,9 +424,10 @@ void sym_calc_value(struct symbol *sym)
if (!sym_is_choice(sym)) {
prop = sym_get_default_prop(sym);
if (prop) {
- sym->flags |= SYMBOL_WRITE;
newval.tri = EXPR_AND(expr_calc_value(prop->expr),
prop->visible.tri);
+ if (newval.tri != no)
+ sym->flags |= SYMBOL_WRITE;
}
if (sym->implied.tri != no) {
sym->flags |= SYMBOL_WRITE;
@@ -413,18 +435,8 @@ void sym_calc_value(struct symbol *sym)
}
}
calc_newval:
- if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
- struct expr *e;
- e = expr_simplify_unmet_dep(sym->rev_dep.expr,
- sym->dir_dep.expr);
- fprintf(stderr, "warning: (");
- expr_fprint(e, stderr);
- fprintf(stderr, ") selects %s which has unmet direct dependencies (",
- sym->name);
- expr_fprint(sym->dir_dep.expr, stderr);
- fprintf(stderr, ")\n");
- expr_free(e);
- }
+ if (sym->dir_dep.tri < sym->rev_dep.tri)
+ sym_warn_unmet_dep(sym);
newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
}
if (newval.tri == mod &&
diff --git a/scripts/kconfig/tests/auto_submenu/Kconfig b/scripts/kconfig/tests/auto_submenu/Kconfig
new file mode 100644
index 000000000000..c17bf2caa7e6
--- /dev/null
+++ b/scripts/kconfig/tests/auto_submenu/Kconfig
@@ -0,0 +1,50 @@
+config A
+ bool "A"
+ default y
+
+config A0
+ bool "A0"
+ depends on A
+ default y
+ help
+ This depends on A, so should be a submenu of A.
+
+config A0_0
+ bool "A1_0"
+ depends on A0
+ help
+ Submenus are created recursively.
+ This should be a submenu of A0.
+
+config A1
+ bool "A1"
+ depends on A
+ default y
+ help
+ This should line up with A0.
+
+choice
+ prompt "choice"
+ depends on A1
+ help
+ Choice should become a submenu as well.
+
+config A1_0
+ bool "A1_0"
+
+config A1_1
+ bool "A1_1"
+
+endchoice
+
+config B
+ bool "B"
+ help
+ This is independent of A.
+
+config C
+ bool "C"
+ depends on A
+ help
+ This depends on A, but not a consecutive item, so can/should not
+ be a submenu.
diff --git a/scripts/kconfig/tests/auto_submenu/__init__.py b/scripts/kconfig/tests/auto_submenu/__init__.py
new file mode 100644
index 000000000000..32e79b85faeb
--- /dev/null
+++ b/scripts/kconfig/tests/auto_submenu/__init__.py
@@ -0,0 +1,12 @@
+"""
+Create submenu for symbols that depend on the preceding one.
+
+If a symbols has dependency on the preceding symbol, the menu entry
+should become the submenu of the preceding one, and displayed with
+deeper indentation.
+"""
+
+
+def test(conf):
+ assert conf.oldaskconfig() == 0
+ assert conf.stdout_contains('expected_stdout')
diff --git a/scripts/kconfig/tests/auto_submenu/expected_stdout b/scripts/kconfig/tests/auto_submenu/expected_stdout
new file mode 100644
index 000000000000..bf5236f39a56
--- /dev/null
+++ b/scripts/kconfig/tests/auto_submenu/expected_stdout
@@ -0,0 +1,10 @@
+A (A) [Y/n/?] (NEW)
+ A0 (A0) [Y/n/?] (NEW)
+ A1_0 (A0_0) [N/y/?] (NEW)
+ A1 (A1) [Y/n/?] (NEW)
+ choice
+ > 1. A1_0 (A1_0) (NEW)
+ 2. A1_1 (A1_1) (NEW)
+ choice[1-2?]:
+B (B) [N/y/?] (NEW)
+C (C) [N/y/?] (NEW)
diff --git a/scripts/kconfig/tests/choice/Kconfig b/scripts/kconfig/tests/choice/Kconfig
new file mode 100644
index 000000000000..cc60e9ce2c03
--- /dev/null
+++ b/scripts/kconfig/tests/choice/Kconfig
@@ -0,0 +1,54 @@
+config MODULES
+ bool "Enable loadable module support"
+ option modules
+ default y
+
+choice
+ prompt "boolean choice"
+ default BOOL_CHOICE1
+
+config BOOL_CHOICE0
+ bool "choice 0"
+
+config BOOL_CHOICE1
+ bool "choice 1"
+
+endchoice
+
+choice
+ prompt "optional boolean choice"
+ optional
+ default OPT_BOOL_CHOICE1
+
+config OPT_BOOL_CHOICE0
+ bool "choice 0"
+
+config OPT_BOOL_CHOICE1
+ bool "choice 1"
+
+endchoice
+
+choice
+ prompt "tristate choice"
+ default TRI_CHOICE1
+
+config TRI_CHOICE0
+ tristate "choice 0"
+
+config TRI_CHOICE1
+ tristate "choice 1"
+
+endchoice
+
+choice
+ prompt "optional tristate choice"
+ optional
+ default OPT_TRI_CHOICE1
+
+config OPT_TRI_CHOICE0
+ tristate "choice 0"
+
+config OPT_TRI_CHOICE1
+ tristate "choice 1"
+
+endchoice
diff --git a/scripts/kconfig/tests/choice/__init__.py b/scripts/kconfig/tests/choice/__init__.py
new file mode 100644
index 000000000000..9edcc5262134
--- /dev/null
+++ b/scripts/kconfig/tests/choice/__init__.py
@@ -0,0 +1,40 @@
+"""
+Basic choice tests.
+
+The handling of 'choice' is a bit complicated part in Kconfig.
+
+The behavior of 'y' choice is intuitive. If choice values are tristate,
+the choice can be 'm' where each value can be enabled independently.
+Also, if a choice is marked as 'optional', the whole choice can be
+invisible.
+"""
+
+
+def test_oldask0(conf):
+ assert conf.oldaskconfig() == 0
+ assert conf.stdout_contains('oldask0_expected_stdout')
+
+
+def test_oldask1(conf):
+ assert conf.oldaskconfig('oldask1_config') == 0
+ assert conf.stdout_contains('oldask1_expected_stdout')
+
+
+def test_allyes(conf):
+ assert conf.allyesconfig() == 0
+ assert conf.config_contains('allyes_expected_config')
+
+
+def test_allmod(conf):
+ assert conf.allmodconfig() == 0
+ assert conf.config_contains('allmod_expected_config')
+
+
+def test_allno(conf):
+ assert conf.allnoconfig() == 0
+ assert conf.config_contains('allno_expected_config')
+
+
+def test_alldef(conf):
+ assert conf.alldefconfig() == 0
+ assert conf.config_contains('alldef_expected_config')
diff --git a/scripts/kconfig/tests/choice/alldef_expected_config b/scripts/kconfig/tests/choice/alldef_expected_config
new file mode 100644
index 000000000000..7a754bf4be94
--- /dev/null
+++ b/scripts/kconfig/tests/choice/alldef_expected_config
@@ -0,0 +1,5 @@
+CONFIG_MODULES=y
+# CONFIG_BOOL_CHOICE0 is not set
+CONFIG_BOOL_CHOICE1=y
+# CONFIG_TRI_CHOICE0 is not set
+# CONFIG_TRI_CHOICE1 is not set
diff --git a/scripts/kconfig/tests/choice/allmod_expected_config b/scripts/kconfig/tests/choice/allmod_expected_config
new file mode 100644
index 000000000000..f1f5dcdb7923
--- /dev/null
+++ b/scripts/kconfig/tests/choice/allmod_expected_config
@@ -0,0 +1,9 @@
+CONFIG_MODULES=y
+# CONFIG_BOOL_CHOICE0 is not set
+CONFIG_BOOL_CHOICE1=y
+# CONFIG_OPT_BOOL_CHOICE0 is not set
+CONFIG_OPT_BOOL_CHOICE1=y
+CONFIG_TRI_CHOICE0=m
+CONFIG_TRI_CHOICE1=m
+CONFIG_OPT_TRI_CHOICE0=m
+CONFIG_OPT_TRI_CHOICE1=m
diff --git a/scripts/kconfig/tests/choice/allno_expected_config b/scripts/kconfig/tests/choice/allno_expected_config
new file mode 100644
index 000000000000..b88ee7a43136
--- /dev/null
+++ b/scripts/kconfig/tests/choice/allno_expected_config
@@ -0,0 +1,5 @@
+# CONFIG_MODULES is not set
+# CONFIG_BOOL_CHOICE0 is not set
+CONFIG_BOOL_CHOICE1=y
+# CONFIG_TRI_CHOICE0 is not set
+CONFIG_TRI_CHOICE1=y
diff --git a/scripts/kconfig/tests/choice/allyes_expected_config b/scripts/kconfig/tests/choice/allyes_expected_config
new file mode 100644
index 000000000000..e5a062a1157c
--- /dev/null
+++ b/scripts/kconfig/tests/choice/allyes_expected_config
@@ -0,0 +1,9 @@
+CONFIG_MODULES=y
+# CONFIG_BOOL_CHOICE0 is not set
+CONFIG_BOOL_CHOICE1=y
+# CONFIG_OPT_BOOL_CHOICE0 is not set
+CONFIG_OPT_BOOL_CHOICE1=y
+# CONFIG_TRI_CHOICE0 is not set
+CONFIG_TRI_CHOICE1=y
+# CONFIG_OPT_TRI_CHOICE0 is not set
+CONFIG_OPT_TRI_CHOICE1=y
diff --git a/scripts/kconfig/tests/choice/oldask0_expected_stdout b/scripts/kconfig/tests/choice/oldask0_expected_stdout
new file mode 100644
index 000000000000..b251bba9698b
--- /dev/null
+++ b/scripts/kconfig/tests/choice/oldask0_expected_stdout
@@ -0,0 +1,10 @@
+Enable loadable module support (MODULES) [Y/n/?] (NEW)
+boolean choice
+ 1. choice 0 (BOOL_CHOICE0) (NEW)
+> 2. choice 1 (BOOL_CHOICE1) (NEW)
+choice[1-2?]:
+optional boolean choice [N/y/?] (NEW)
+tristate choice [M/y/?] (NEW)
+ choice 0 (TRI_CHOICE0) [N/m/?] (NEW)
+ choice 1 (TRI_CHOICE1) [N/m/?] (NEW)
+optional tristate choice [N/m/y/?] (NEW)
diff --git a/scripts/kconfig/tests/choice/oldask1_config b/scripts/kconfig/tests/choice/oldask1_config
new file mode 100644
index 000000000000..b67bfe3c641f
--- /dev/null
+++ b/scripts/kconfig/tests/choice/oldask1_config
@@ -0,0 +1,2 @@
+# CONFIG_MODULES is not set
+CONFIG_OPT_BOOL_CHOICE0=y
diff --git a/scripts/kconfig/tests/choice/oldask1_expected_stdout b/scripts/kconfig/tests/choice/oldask1_expected_stdout
new file mode 100644
index 000000000000..c2125e9bf96a
--- /dev/null
+++ b/scripts/kconfig/tests/choice/oldask1_expected_stdout
@@ -0,0 +1,15 @@
+Enable loadable module support (MODULES) [N/y/?]
+boolean choice
+ 1. choice 0 (BOOL_CHOICE0) (NEW)
+> 2. choice 1 (BOOL_CHOICE1) (NEW)
+choice[1-2?]:
+optional boolean choice [Y/n/?] (NEW)
+optional boolean choice
+> 1. choice 0 (OPT_BOOL_CHOICE0)
+ 2. choice 1 (OPT_BOOL_CHOICE1) (NEW)
+choice[1-2?]:
+tristate choice
+ 1. choice 0 (TRI_CHOICE0) (NEW)
+> 2. choice 1 (TRI_CHOICE1) (NEW)
+choice[1-2?]:
+optional tristate choice [N/y/?]
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig b/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig
new file mode 100644
index 000000000000..11ac25c26040
--- /dev/null
+++ b/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig
@@ -0,0 +1,19 @@
+config MODULES
+ def_bool y
+ option modules
+
+config DEP
+ tristate
+ default m
+
+choice
+ prompt "Tristate Choice"
+
+config CHOICE0
+ tristate "Choice 0"
+
+config CHOICE1
+ tristate "Choice 1"
+ depends on DEP
+
+endchoice
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/__init__.py b/scripts/kconfig/tests/choice_value_with_m_dep/__init__.py
new file mode 100644
index 000000000000..f8d728c7b101
--- /dev/null
+++ b/scripts/kconfig/tests/choice_value_with_m_dep/__init__.py
@@ -0,0 +1,15 @@
+"""
+Hide tristate choice values with mod dependency in y choice.
+
+If tristate choice values depend on symbols set to 'm', they should be
+hidden when the choice containing them is changed from 'm' to 'y'
+(i.e. exclusive choice).
+
+Related Linux commit: fa64e5f6a35efd5e77d639125d973077ca506074
+"""
+
+
+def test(conf):
+ assert conf.oldaskconfig('config', 'y') == 0
+ assert conf.config_contains('expected_config')
+ assert conf.stdout_contains('expected_stdout')
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/config b/scripts/kconfig/tests/choice_value_with_m_dep/config
new file mode 100644
index 000000000000..3a126b7a2546
--- /dev/null
+++ b/scripts/kconfig/tests/choice_value_with_m_dep/config
@@ -0,0 +1,2 @@
+CONFIG_CHOICE0=m
+CONFIG_CHOICE1=m
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/expected_config b/scripts/kconfig/tests/choice_value_with_m_dep/expected_config
new file mode 100644
index 000000000000..4d07b449540e
--- /dev/null
+++ b/scripts/kconfig/tests/choice_value_with_m_dep/expected_config
@@ -0,0 +1,3 @@
+CONFIG_MODULES=y
+CONFIG_DEP=m
+CONFIG_CHOICE0=y
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/expected_stdout b/scripts/kconfig/tests/choice_value_with_m_dep/expected_stdout
new file mode 100644
index 000000000000..2b50ab65c86a
--- /dev/null
+++ b/scripts/kconfig/tests/choice_value_with_m_dep/expected_stdout
@@ -0,0 +1,4 @@
+Tristate Choice [M/y/?] y
+Tristate Choice
+> 1. Choice 0 (CHOICE0)
+choice[1]: 1
diff --git a/scripts/kconfig/tests/conftest.py b/scripts/kconfig/tests/conftest.py
new file mode 100644
index 000000000000..0345ef6e3273
--- /dev/null
+++ b/scripts/kconfig/tests/conftest.py
@@ -0,0 +1,291 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@socionext.com>
+#
+
+"""
+Kconfig unit testing framework.
+
+This provides fixture functions commonly used from test files.
+"""
+
+import os
+import pytest
+import shutil
+import subprocess
+import tempfile
+
+CONF_PATH = os.path.abspath(os.path.join('scripts', 'kconfig', 'conf'))
+
+
+class Conf:
+ """Kconfig runner and result checker.
+
+ This class provides methods to run text-based interface of Kconfig
+ (scripts/kconfig/conf) and retrieve the resulted configuration,
+ stdout, and stderr. It also provides methods to compare those
+ results with expectations.
+ """
+
+ def __init__(self, request):
+ """Create a new Conf instance.
+
+ request: object to introspect the requesting test module
+ """
+ # the directory of the test being run
+ self._test_dir = os.path.dirname(str(request.fspath))
+
+ # runners
+ def _run_conf(self, mode, dot_config=None, out_file='.config',
+ interactive=False, in_keys=None, extra_env={}):
+ """Run text-based Kconfig executable and save the result.
+
+ mode: input mode option (--oldaskconfig, --defconfig=<file> etc.)
+ dot_config: .config file to use for configuration base
+ out_file: file name to contain the output config data
+ interactive: flag to specify the interactive mode
+ in_keys: key inputs for interactive modes
+ extra_env: additional environments
+ returncode: exit status of the Kconfig executable
+ """
+ command = [CONF_PATH, mode, 'Kconfig']
+
+ # Override 'srctree' environment to make the test as the top directory
+ extra_env['srctree'] = self._test_dir
+
+ # Run Kconfig in a temporary directory.
+ # This directory is automatically removed when done.
+ with tempfile.TemporaryDirectory() as temp_dir:
+
+ # if .config is given, copy it to the working directory
+ if dot_config:
+ shutil.copyfile(os.path.join(self._test_dir, dot_config),
+ os.path.join(temp_dir, '.config'))
+
+ ps = subprocess.Popen(command,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ cwd=temp_dir,
+ env=dict(os.environ, **extra_env))
+
+ # If input key sequence is given, feed it to stdin.
+ if in_keys:
+ ps.stdin.write(in_keys.encode('utf-8'))
+
+ while ps.poll() is None:
+ # For interactive modes such as oldaskconfig, oldconfig,
+ # send 'Enter' key until the program finishes.
+ if interactive:
+ ps.stdin.write(b'\n')
+
+ self.retcode = ps.returncode
+ self.stdout = ps.stdout.read().decode()
+ self.stderr = ps.stderr.read().decode()
+
+ # Retrieve the resulted config data only when .config is supposed
+ # to exist. If the command fails, the .config does not exist.
+ # 'listnewconfig' does not produce .config in the first place.
+ if self.retcode == 0 and out_file:
+ with open(os.path.join(temp_dir, out_file)) as f:
+ self.config = f.read()
+ else:
+ self.config = None
+
+ # Logging:
+ # Pytest captures the following information by default. In failure
+ # of tests, the captured log will be displayed. This will be useful to
+ # figure out what has happened.
+
+ print("[command]\n{}\n".format(' '.join(command)))
+
+ print("[retcode]\n{}\n".format(self.retcode))
+
+ print("[stdout]")
+ print(self.stdout)
+
+ print("[stderr]")
+ print(self.stderr)
+
+ if self.config is not None:
+ print("[output for '{}']".format(out_file))
+ print(self.config)
+
+ return self.retcode
+
+ def oldaskconfig(self, dot_config=None, in_keys=None):
+ """Run oldaskconfig.
+
+ dot_config: .config file to use for configuration base (optional)
+ in_key: key inputs (optional)
+ returncode: exit status of the Kconfig executable
+ """
+ return self._run_conf('--oldaskconfig', dot_config=dot_config,
+ interactive=True, in_keys=in_keys)
+
+ def oldconfig(self, dot_config=None, in_keys=None):
+ """Run oldconfig.
+
+ dot_config: .config file to use for configuration base (optional)
+ in_key: key inputs (optional)
+ returncode: exit status of the Kconfig executable
+ """
+ return self._run_conf('--oldconfig', dot_config=dot_config,
+ interactive=True, in_keys=in_keys)
+
+ def olddefconfig(self, dot_config=None):
+ """Run olddefconfig.
+
+ dot_config: .config file to use for configuration base (optional)
+ returncode: exit status of the Kconfig executable
+ """
+ return self._run_conf('--olddefconfig', dot_config=dot_config)
+
+ def defconfig(self, defconfig):
+ """Run defconfig.
+
+ defconfig: defconfig file for input
+ returncode: exit status of the Kconfig executable
+ """
+ defconfig_path = os.path.join(self._test_dir, defconfig)
+ return self._run_conf('--defconfig={}'.format(defconfig_path))
+
+ def _allconfig(self, mode, all_config):
+ if all_config:
+ all_config_path = os.path.join(self._test_dir, all_config)
+ extra_env = {'KCONFIG_ALLCONFIG': all_config_path}
+ else:
+ extra_env = {}
+
+ return self._run_conf('--{}config'.format(mode), extra_env=extra_env)
+
+ def allyesconfig(self, all_config=None):
+ """Run allyesconfig.
+
+ all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
+ returncode: exit status of the Kconfig executable
+ """
+ return self._allconfig('allyes', all_config)
+
+ def allmodconfig(self, all_config=None):
+ """Run allmodconfig.
+
+ all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
+ returncode: exit status of the Kconfig executable
+ """
+ return self._allconfig('allmod', all_config)
+
+ def allnoconfig(self, all_config=None):
+ """Run allnoconfig.
+
+ all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
+ returncode: exit status of the Kconfig executable
+ """
+ return self._allconfig('allno', all_config)
+
+ def alldefconfig(self, all_config=None):
+ """Run alldefconfig.
+
+ all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
+ returncode: exit status of the Kconfig executable
+ """
+ return self._allconfig('alldef', all_config)
+
+ def randconfig(self, all_config=None):
+ """Run randconfig.
+
+ all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
+ returncode: exit status of the Kconfig executable
+ """
+ return self._allconfig('rand', all_config)
+
+ def savedefconfig(self, dot_config):
+ """Run savedefconfig.
+
+ dot_config: .config file for input
+ returncode: exit status of the Kconfig executable
+ """
+ return self._run_conf('--savedefconfig', out_file='defconfig')
+
+ def listnewconfig(self, dot_config=None):
+ """Run listnewconfig.
+
+ dot_config: .config file to use for configuration base (optional)
+ returncode: exit status of the Kconfig executable
+ """
+ return self._run_conf('--listnewconfig', dot_config=dot_config,
+ out_file=None)
+
+ # checkers
+ def _read_and_compare(self, compare, expected):
+ """Compare the result with expectation.
+
+ compare: function to compare the result with expectation
+ expected: file that contains the expected data
+ """
+ with open(os.path.join(self._test_dir, expected)) as f:
+ expected_data = f.read()
+ return compare(self, expected_data)
+
+ def _contains(self, attr, expected):
+ return self._read_and_compare(
+ lambda s, e: getattr(s, attr).find(e) >= 0,
+ expected)
+
+ def _matches(self, attr, expected):
+ return self._read_and_compare(lambda s, e: getattr(s, attr) == e,
+ expected)
+
+ def config_contains(self, expected):
+ """Check if resulted configuration contains expected data.
+
+ expected: file that contains the expected data
+ returncode: True if result contains the expected data, False otherwise
+ """
+ return self._contains('config', expected)
+
+ def config_matches(self, expected):
+ """Check if resulted configuration exactly matches expected data.
+
+ expected: file that contains the expected data
+ returncode: True if result matches the expected data, False otherwise
+ """
+ return self._matches('config', expected)
+
+ def stdout_contains(self, expected):
+ """Check if resulted stdout contains expected data.
+
+ expected: file that contains the expected data
+ returncode: True if result contains the expected data, False otherwise
+ """
+ return self._contains('stdout', expected)
+
+ def stdout_matches(self, expected):
+ """Check if resulted stdout exactly matches expected data.
+
+ expected: file that contains the expected data
+ returncode: True if result matches the expected data, False otherwise
+ """
+ return self._matches('stdout', expected)
+
+ def stderr_contains(self, expected):
+ """Check if resulted stderr contains expected data.
+
+ expected: file that contains the expected data
+ returncode: True if result contains the expected data, False otherwise
+ """
+ return self._contains('stderr', expected)
+
+ def stderr_matches(self, expected):
+ """Check if resulted stderr exactly matches expected data.
+
+ expected: file that contains the expected data
+ returncode: True if result matches the expected data, False otherwise
+ """
+ return self._matches('stderr', expected)
+
+
+@pytest.fixture(scope="module")
+def conf(request):
+ """Create a Conf instance and provide it to test functions."""
+ return Conf(request)
diff --git a/scripts/kconfig/tests/err_recursive_inc/Kconfig b/scripts/kconfig/tests/err_recursive_inc/Kconfig
new file mode 100644
index 000000000000..0e4c8750ab65
--- /dev/null
+++ b/scripts/kconfig/tests/err_recursive_inc/Kconfig
@@ -0,0 +1 @@
+source "Kconfig.inc1"
diff --git a/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc1 b/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc1
new file mode 100644
index 000000000000..00e408d653fc
--- /dev/null
+++ b/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc1
@@ -0,0 +1,4 @@
+
+
+
+source "Kconfig.inc2"
diff --git a/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc2 b/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc2
new file mode 100644
index 000000000000..349ea2db15dc
--- /dev/null
+++ b/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc2
@@ -0,0 +1,3 @@
+
+
+source "Kconfig.inc3"
diff --git a/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc3 b/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc3
new file mode 100644
index 000000000000..0e4c8750ab65
--- /dev/null
+++ b/scripts/kconfig/tests/err_recursive_inc/Kconfig.inc3
@@ -0,0 +1 @@
+source "Kconfig.inc1"
diff --git a/scripts/kconfig/tests/err_recursive_inc/__init__.py b/scripts/kconfig/tests/err_recursive_inc/__init__.py
new file mode 100644
index 000000000000..0e4c839c54aa
--- /dev/null
+++ b/scripts/kconfig/tests/err_recursive_inc/__init__.py
@@ -0,0 +1,10 @@
+"""
+Detect recursive inclusion error.
+
+If recursive inclusion is detected, it should fail with error messages.
+"""
+
+
+def test(conf):
+ assert conf.oldaskconfig() != 0
+ assert conf.stderr_contains('expected_stderr')
diff --git a/scripts/kconfig/tests/err_recursive_inc/expected_stderr b/scripts/kconfig/tests/err_recursive_inc/expected_stderr
new file mode 100644
index 000000000000..6b582eee2176
--- /dev/null
+++ b/scripts/kconfig/tests/err_recursive_inc/expected_stderr
@@ -0,0 +1,6 @@
+Recursive inclusion detected.
+Inclusion path:
+ current file : Kconfig.inc1
+ included from: Kconfig.inc3:1
+ included from: Kconfig.inc2:3
+ included from: Kconfig.inc1:4
diff --git a/scripts/kconfig/tests/inter_choice/Kconfig b/scripts/kconfig/tests/inter_choice/Kconfig
new file mode 100644
index 000000000000..e44449f075df
--- /dev/null
+++ b/scripts/kconfig/tests/inter_choice/Kconfig
@@ -0,0 +1,23 @@
+config MODULES
+ def_bool y
+ option modules
+
+choice
+ prompt "Choice"
+
+config CHOICE_VAL0
+ tristate "Choice 0"
+
+config CHOIVE_VAL1
+ tristate "Choice 1"
+
+endchoice
+
+choice
+ prompt "Another choice"
+ depends on CHOICE_VAL0
+
+config DUMMY
+ bool "dummy"
+
+endchoice
diff --git a/scripts/kconfig/tests/inter_choice/__init__.py b/scripts/kconfig/tests/inter_choice/__init__.py
new file mode 100644
index 000000000000..5c7fc365ed40
--- /dev/null
+++ b/scripts/kconfig/tests/inter_choice/__init__.py
@@ -0,0 +1,14 @@
+"""
+Do not affect user-assigned choice value by another choice.
+
+Handling of state flags for choices is complecated. In old days,
+the defconfig result of a choice could be affected by another choice
+if those choices interact by 'depends on', 'select', etc.
+
+Related Linux commit: fbe98bb9ed3dae23e320c6b113e35f129538d14a
+"""
+
+
+def test(conf):
+ assert conf.defconfig('defconfig') == 0
+ assert conf.config_contains('expected_config')
diff --git a/scripts/kconfig/tests/inter_choice/defconfig b/scripts/kconfig/tests/inter_choice/defconfig
new file mode 100644
index 000000000000..162c4148e2a5
--- /dev/null
+++ b/scripts/kconfig/tests/inter_choice/defconfig
@@ -0,0 +1 @@
+CONFIG_CHOICE_VAL0=y
diff --git a/scripts/kconfig/tests/inter_choice/expected_config b/scripts/kconfig/tests/inter_choice/expected_config
new file mode 100644
index 000000000000..5dceefb054e3
--- /dev/null
+++ b/scripts/kconfig/tests/inter_choice/expected_config
@@ -0,0 +1,4 @@
+CONFIG_MODULES=y
+CONFIG_CHOICE_VAL0=y
+# CONFIG_CHOIVE_VAL1 is not set
+CONFIG_DUMMY=y
diff --git a/scripts/kconfig/tests/new_choice_with_dep/Kconfig b/scripts/kconfig/tests/new_choice_with_dep/Kconfig
new file mode 100644
index 000000000000..53ef1b86e7bf
--- /dev/null
+++ b/scripts/kconfig/tests/new_choice_with_dep/Kconfig
@@ -0,0 +1,37 @@
+config A
+ bool "A"
+ help
+ This is a new symbol.
+
+choice
+ prompt "Choice ?"
+ depends on A
+ help
+ "depends on A" has been newly added.
+
+config CHOICE_B
+ bool "Choice B"
+
+config CHOICE_C
+ bool "Choice C"
+ help
+ This is a new symbol, so should be asked.
+
+endchoice
+
+choice
+ prompt "Choice2 ?"
+
+config CHOICE_D
+ bool "Choice D"
+
+config CHOICE_E
+ bool "Choice E"
+
+config CHOICE_F
+ bool "Choice F"
+ depends on A
+ help
+ This is a new symbol, so should be asked.
+
+endchoice
diff --git a/scripts/kconfig/tests/new_choice_with_dep/__init__.py b/scripts/kconfig/tests/new_choice_with_dep/__init__.py
new file mode 100644
index 000000000000..f0e0ead0f32f
--- /dev/null
+++ b/scripts/kconfig/tests/new_choice_with_dep/__init__.py
@@ -0,0 +1,14 @@
+"""
+Ask new choice values when they become visible.
+
+If new choice values are added with new dependency, and they become
+visible during user configuration, oldconfig should recognize them
+as (NEW), and ask the user for choice.
+
+Related Linux commit: 5d09598d488f081e3be23f885ed65cbbe2d073b5
+"""
+
+
+def test(conf):
+ assert conf.oldconfig('config', 'y') == 0
+ assert conf.stdout_contains('expected_stdout')
diff --git a/scripts/kconfig/tests/new_choice_with_dep/config b/scripts/kconfig/tests/new_choice_with_dep/config
new file mode 100644
index 000000000000..47ef95d567fd
--- /dev/null
+++ b/scripts/kconfig/tests/new_choice_with_dep/config
@@ -0,0 +1,3 @@
+CONFIG_CHOICE_B=y
+# CONFIG_CHOICE_D is not set
+CONFIG_CHOICE_E=y
diff --git a/scripts/kconfig/tests/new_choice_with_dep/expected_stdout b/scripts/kconfig/tests/new_choice_with_dep/expected_stdout
new file mode 100644
index 000000000000..74dc0bcb22bc
--- /dev/null
+++ b/scripts/kconfig/tests/new_choice_with_dep/expected_stdout
@@ -0,0 +1,10 @@
+A (A) [N/y/?] (NEW) y
+ Choice ?
+ > 1. Choice B (CHOICE_B)
+ 2. Choice C (CHOICE_C) (NEW)
+ choice[1-2?]:
+Choice2 ?
+ 1. Choice D (CHOICE_D)
+> 2. Choice E (CHOICE_E)
+ 3. Choice F (CHOICE_F) (NEW)
+choice[1-3?]:
diff --git a/scripts/kconfig/tests/no_write_if_dep_unmet/Kconfig b/scripts/kconfig/tests/no_write_if_dep_unmet/Kconfig
new file mode 100644
index 000000000000..c00b8fe54f45
--- /dev/null
+++ b/scripts/kconfig/tests/no_write_if_dep_unmet/Kconfig
@@ -0,0 +1,14 @@
+config A
+ bool "A"
+
+choice
+ prompt "Choice ?"
+ depends on A
+
+config CHOICE_B
+ bool "Choice B"
+
+config CHOICE_C
+ bool "Choice C"
+
+endchoice
diff --git a/scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py b/scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py
new file mode 100644
index 000000000000..207261b0fe00
--- /dev/null
+++ b/scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py
@@ -0,0 +1,19 @@
+"""
+Do not write choice values to .config if the dependency is unmet.
+
+"# CONFIG_... is not set" should not be written into the .config file
+for symbols with unmet dependency.
+
+This was not working correctly for choice values because choice needs
+a bit different symbol computation.
+
+This checks that no unneeded "# COFIG_... is not set" is contained in
+the .config file.
+
+Related Linux commit: cb67ab2cd2b8abd9650292c986c79901e3073a59
+"""
+
+
+def test(conf):
+ assert conf.oldaskconfig('config', 'n') == 0
+ assert conf.config_matches('expected_config')
diff --git a/scripts/kconfig/tests/no_write_if_dep_unmet/config b/scripts/kconfig/tests/no_write_if_dep_unmet/config
new file mode 100644
index 000000000000..abd280e2f616
--- /dev/null
+++ b/scripts/kconfig/tests/no_write_if_dep_unmet/config
@@ -0,0 +1 @@
+CONFIG_A=y
diff --git a/scripts/kconfig/tests/no_write_if_dep_unmet/expected_config b/scripts/kconfig/tests/no_write_if_dep_unmet/expected_config
new file mode 100644
index 000000000000..0d15e41da475
--- /dev/null
+++ b/scripts/kconfig/tests/no_write_if_dep_unmet/expected_config
@@ -0,0 +1,5 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux Kernel Configuration
+#
+# CONFIG_A is not set
diff --git a/scripts/kconfig/tests/pytest.ini b/scripts/kconfig/tests/pytest.ini
new file mode 100644
index 000000000000..85d7ce8e448b
--- /dev/null
+++ b/scripts/kconfig/tests/pytest.ini
@@ -0,0 +1,7 @@
+[pytest]
+addopts = --verbose
+
+# Pytest requires that test files have unique names, because pytest imports
+# them as top-level modules. It is silly to prefix or suffix a test file with
+# the directory name that contains it. Use __init__.py for all test files.
+python_files = __init__.py
diff --git a/scripts/kconfig/tests/rand_nested_choice/Kconfig b/scripts/kconfig/tests/rand_nested_choice/Kconfig
new file mode 100644
index 000000000000..c591d512929f
--- /dev/null
+++ b/scripts/kconfig/tests/rand_nested_choice/Kconfig
@@ -0,0 +1,33 @@
+choice
+ prompt "choice"
+
+config A
+ bool "A"
+
+config B
+ bool "B"
+
+if B
+choice
+ prompt "sub choice"
+
+config C
+ bool "C"
+
+config D
+ bool "D"
+
+if D
+choice
+ prompt "subsub choice"
+
+config E
+ bool "E"
+
+endchoice
+endif # D
+
+endchoice
+endif # B
+
+endchoice
diff --git a/scripts/kconfig/tests/rand_nested_choice/__init__.py b/scripts/kconfig/tests/rand_nested_choice/__init__.py
new file mode 100644
index 000000000000..e729a4e85218
--- /dev/null
+++ b/scripts/kconfig/tests/rand_nested_choice/__init__.py
@@ -0,0 +1,16 @@
+"""
+Set random values recursively in nested choices.
+
+Kconfig can create a choice-in-choice structure by using 'if' statement.
+randconfig should correctly set random choice values.
+
+Related Linux commit: 3b9a19e08960e5cdad5253998637653e592a3c29
+"""
+
+
+def test(conf):
+ for i in range(20):
+ assert conf.randconfig() == 0
+ assert (conf.config_contains('expected_stdout0') or
+ conf.config_contains('expected_stdout1') or
+ conf.config_contains('expected_stdout2'))
diff --git a/scripts/kconfig/tests/rand_nested_choice/expected_stdout0 b/scripts/kconfig/tests/rand_nested_choice/expected_stdout0
new file mode 100644
index 000000000000..05450f3d4eb5
--- /dev/null
+++ b/scripts/kconfig/tests/rand_nested_choice/expected_stdout0
@@ -0,0 +1,2 @@
+CONFIG_A=y
+# CONFIG_B is not set
diff --git a/scripts/kconfig/tests/rand_nested_choice/expected_stdout1 b/scripts/kconfig/tests/rand_nested_choice/expected_stdout1
new file mode 100644
index 000000000000..37ab29584157
--- /dev/null
+++ b/scripts/kconfig/tests/rand_nested_choice/expected_stdout1
@@ -0,0 +1,4 @@
+# CONFIG_A is not set
+CONFIG_B=y
+CONFIG_C=y
+# CONFIG_D is not set
diff --git a/scripts/kconfig/tests/rand_nested_choice/expected_stdout2 b/scripts/kconfig/tests/rand_nested_choice/expected_stdout2
new file mode 100644
index 000000000000..849ff47e9848
--- /dev/null
+++ b/scripts/kconfig/tests/rand_nested_choice/expected_stdout2
@@ -0,0 +1,5 @@
+# CONFIG_A is not set
+CONFIG_B=y
+# CONFIG_C is not set
+CONFIG_D=y
+CONFIG_E=y
diff --git a/scripts/kconfig/tests/warn_recursive_dep/Kconfig b/scripts/kconfig/tests/warn_recursive_dep/Kconfig
new file mode 100644
index 000000000000..a65bfcb7137e
--- /dev/null
+++ b/scripts/kconfig/tests/warn_recursive_dep/Kconfig
@@ -0,0 +1,62 @@
+# depends on itself
+
+config A
+ bool "A"
+ depends on A
+
+# select itself
+
+config B
+ bool
+ select B
+
+# depends on each other
+
+config C1
+ bool "C1"
+ depends on C2
+
+config C2
+ bool "C2"
+ depends on C1
+
+# depends on and select
+
+config D1
+ bool "D1"
+ depends on D2
+ select D2
+
+config D2
+ bool
+
+# depends on and imply
+# This is not recursive dependency
+
+config E1
+ bool "E1"
+ depends on E2
+ imply E2
+
+config E2
+ bool "E2"
+
+# property
+
+config F1
+ bool "F1"
+ default F2
+
+config F2
+ bool "F2"
+ depends on F1
+
+# menu
+
+menu "menu depending on its content"
+ depends on G
+
+config G
+ bool "G"
+
+endmenu
diff --git a/scripts/kconfig/tests/warn_recursive_dep/__init__.py b/scripts/kconfig/tests/warn_recursive_dep/__init__.py
new file mode 100644
index 000000000000..adb21951ba41
--- /dev/null
+++ b/scripts/kconfig/tests/warn_recursive_dep/__init__.py
@@ -0,0 +1,9 @@
+"""
+Warn recursive inclusion.
+
+Recursive dependency should be warned.
+"""
+
+def test(conf):
+ assert conf.oldaskconfig() == 0
+ assert conf.stderr_contains('expected_stderr')
diff --git a/scripts/kconfig/tests/warn_recursive_dep/expected_stderr b/scripts/kconfig/tests/warn_recursive_dep/expected_stderr
new file mode 100644
index 000000000000..3de807dd9cb2
--- /dev/null
+++ b/scripts/kconfig/tests/warn_recursive_dep/expected_stderr
@@ -0,0 +1,30 @@
+Kconfig:9:error: recursive dependency detected!
+Kconfig:9: symbol B is selected by B
+For a resolution refer to Documentation/kbuild/kconfig-language.txt
+subsection "Kconfig recursive dependency limitations"
+
+Kconfig:3:error: recursive dependency detected!
+Kconfig:3: symbol A depends on A
+For a resolution refer to Documentation/kbuild/kconfig-language.txt
+subsection "Kconfig recursive dependency limitations"
+
+Kconfig:15:error: recursive dependency detected!
+Kconfig:15: symbol C1 depends on C2
+Kconfig:19: symbol C2 depends on C1
+For a resolution refer to Documentation/kbuild/kconfig-language.txt
+subsection "Kconfig recursive dependency limitations"
+
+Kconfig:30:error: recursive dependency detected!
+Kconfig:30: symbol D2 is selected by D1
+Kconfig:25: symbol D1 depends on D2
+For a resolution refer to Documentation/kbuild/kconfig-language.txt
+subsection "Kconfig recursive dependency limitations"
+
+Kconfig:59:error: recursive dependency detected!
+Kconfig:59: symbol G depends on G
+For a resolution refer to Documentation/kbuild/kconfig-language.txt
+subsection "Kconfig recursive dependency limitations"
+
+Kconfig:50:error: recursive dependency detected!
+Kconfig:50: symbol F2 depends on F1
+Kconfig:48: symbol F1 default value contains F2
diff --git a/scripts/kconfig/zconf.l b/scripts/kconfig/zconf.l
index 88b650eb9cc9..045093d827e1 100644
--- a/scripts/kconfig/zconf.l
+++ b/scripts/kconfig/zconf.l
@@ -1,5 +1,5 @@
%option nostdinit noyywrap never-interactive full ecs
-%option 8bit nodefault perf-report perf-report
+%option 8bit nodefault yylineno
%option noinput
%x COMMAND HELP STRING PARAM
%{
@@ -83,7 +83,6 @@ n [A-Za-z0-9_-]
[ \t]*#.*\n |
[ \t]*\n {
- current_file->lineno++;
return T_EOL;
}
[ \t]*#.*
@@ -104,7 +103,7 @@ n [A-Za-z0-9_-]
const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
BEGIN(PARAM);
current_pos.file = current_file;
- current_pos.lineno = current_file->lineno;
+ current_pos.lineno = yylineno;
if (id && id->flags & TF_COMMAND) {
yylval.id = id;
return id->token;
@@ -116,7 +115,6 @@ n [A-Za-z0-9_-]
. warn_ignored_character(*yytext);
\n {
BEGIN(INITIAL);
- current_file->lineno++;
return T_EOL;
}
}
@@ -138,7 +136,7 @@ n [A-Za-z0-9_-]
new_string();
BEGIN(STRING);
}
- \n BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+ \n BEGIN(INITIAL); return T_EOL;
({n}|[/.])+ {
const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
if (id && id->flags & TF_PARAM) {
@@ -150,7 +148,7 @@ n [A-Za-z0-9_-]
return T_WORD;
}
#.* /* comment */
- \\\n current_file->lineno++;
+ \\\n ;
[[:blank:]]+
. warn_ignored_character(*yytext);
<<EOF>> {
@@ -187,7 +185,6 @@ n [A-Za-z0-9_-]
fprintf(stderr,
"%s:%d:warning: multi-line strings not supported\n",
zconf_curname(), zconf_lineno());
- current_file->lineno++;
BEGIN(INITIAL);
return T_EOL;
}
@@ -220,12 +217,10 @@ n [A-Za-z0-9_-]
}
}
[ \t]*\n/[^ \t\n] {
- current_file->lineno++;
zconf_endhelp();
return T_HELPTEXT;
}
[ \t]*\n {
- current_file->lineno++;
append_string("\n", 1);
}
[^ \t\n].* {
@@ -304,7 +299,7 @@ void zconf_initscan(const char *name)
memset(current_buf, 0, sizeof(*current_buf));
current_file = file_lookup(name);
- current_file->lineno = 1;
+ yylineno = 1;
}
void zconf_nextfile(const char *name)
@@ -325,24 +320,26 @@ void zconf_nextfile(const char *name)
buf->parent = current_buf;
current_buf = buf;
- for (iter = current_file->parent; iter; iter = iter->parent ) {
- if (!strcmp(current_file->name,iter->name) ) {
+ current_file->lineno = yylineno;
+ file->parent = current_file;
+
+ for (iter = current_file; iter; iter = iter->parent) {
+ if (!strcmp(iter->name, file->name)) {
fprintf(stderr,
- "%s:%d: recursive inclusion detected. "
- "Inclusion path:\n current file : '%s'\n",
- zconf_curname(), zconf_lineno(),
- zconf_curname());
- iter = current_file;
+ "Recursive inclusion detected.\n"
+ "Inclusion path:\n"
+ " current file : %s\n", file->name);
+ iter = file;
do {
iter = iter->parent;
- fprintf(stderr, " included from: '%s:%d'\n",
+ fprintf(stderr, " included from: %s:%d\n",
iter->name, iter->lineno - 1);
- } while (strcmp(iter->name, current_file->name));
+ } while (strcmp(iter->name, file->name));
exit(1);
}
}
- file->lineno = 1;
- file->parent = current_file;
+
+ yylineno = 1;
current_file = file;
}
@@ -351,6 +348,8 @@ static void zconf_endfile(void)
struct buffer *parent;
current_file = current_file->parent;
+ if (current_file)
+ yylineno = current_file->lineno;
parent = current_buf->parent;
if (parent) {
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index be56a1153014..9045823c7be7 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -4,7 +4,7 @@
# link vmlinux
#
# vmlinux is linked from the objects selected by $(KBUILD_VMLINUX_INIT) and
-# $(KBUILD_VMLINUX_MAIN) and $(KBUILD_VMLINUX_LIBS). Most are built-in.o files
+# $(KBUILD_VMLINUX_MAIN) and $(KBUILD_VMLINUX_LIBS). Most are built-in.a files
# from top-level directories in the kernel tree, others are specified in
# arch/$(ARCH)/Makefile. Ordering when linking is important, and
# $(KBUILD_VMLINUX_INIT) must be first. $(KBUILD_VMLINUX_LIBS) are archives
@@ -18,7 +18,7 @@
# | +--< init/version.o + more
# |
# +--< $(KBUILD_VMLINUX_MAIN)
-# | +--< drivers/built-in.o mm/built-in.o + more
+# | +--< drivers/built-in.a mm/built-in.a + more
# |
# +--< $(KBUILD_VMLINUX_LIBS)
# | +--< lib/lib.a + more
@@ -51,17 +51,15 @@ info()
#
# Traditional incremental style of link does not require this step
#
-# built-in.o output file
+# built-in.a output file
#
archive_builtin()
{
- if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then
- info AR built-in.o
- rm -f built-in.o;
- ${AR} rcsTP${KBUILD_ARFLAGS} built-in.o \
- ${KBUILD_VMLINUX_INIT} \
- ${KBUILD_VMLINUX_MAIN}
- fi
+ info AR built-in.a
+ rm -f built-in.a;
+ ${AR} rcsTP${KBUILD_ARFLAGS} built-in.a \
+ ${KBUILD_VMLINUX_INIT} \
+ ${KBUILD_VMLINUX_MAIN}
}
# Link of vmlinux.o used for section mismatch analysis
@@ -70,20 +68,13 @@ modpost_link()
{
local objects
- if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then
- objects="--whole-archive \
- built-in.o \
- --no-whole-archive \
- --start-group \
- ${KBUILD_VMLINUX_LIBS} \
- --end-group"
- else
- objects="${KBUILD_VMLINUX_INIT} \
- --start-group \
- ${KBUILD_VMLINUX_MAIN} \
- ${KBUILD_VMLINUX_LIBS} \
- --end-group"
- fi
+ objects="--whole-archive \
+ built-in.a \
+ --no-whole-archive \
+ --start-group \
+ ${KBUILD_VMLINUX_LIBS} \
+ --end-group"
+
${LD} ${LDFLAGS} -r -o ${1} ${objects}
}
@@ -96,46 +87,28 @@ vmlinux_link()
local objects
if [ "${SRCARCH}" != "um" ]; then
- if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then
- objects="--whole-archive \
- built-in.o \
- --no-whole-archive \
- --start-group \
- ${KBUILD_VMLINUX_LIBS} \
- --end-group \
- ${1}"
- else
- objects="${KBUILD_VMLINUX_INIT} \
- --start-group \
- ${KBUILD_VMLINUX_MAIN} \
- ${KBUILD_VMLINUX_LIBS} \
- --end-group \
- ${1}"
- fi
-
- ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \
+ objects="--whole-archive \
+ built-in.a \
+ --no-whole-archive \
+ --start-group \
+ ${KBUILD_VMLINUX_LIBS} \
+ --end-group \
+ ${1}"
+
+ ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \
-T ${lds} ${objects}
else
- if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then
- objects="-Wl,--whole-archive \
- built-in.o \
- -Wl,--no-whole-archive \
- -Wl,--start-group \
- ${KBUILD_VMLINUX_LIBS} \
- -Wl,--end-group \
- ${1}"
- else
- objects="${KBUILD_VMLINUX_INIT} \
- -Wl,--start-group \
- ${KBUILD_VMLINUX_MAIN} \
- ${KBUILD_VMLINUX_LIBS} \
- -Wl,--end-group \
- ${1}"
- fi
-
- ${CC} ${CFLAGS_vmlinux} -o ${2} \
- -Wl,-T,${lds} \
- ${objects} \
+ objects="-Wl,--whole-archive \
+ built-in.a \
+ -Wl,--no-whole-archive \
+ -Wl,--start-group \
+ ${KBUILD_VMLINUX_LIBS} \
+ -Wl,--end-group \
+ ${1}"
+
+ ${CC} ${CFLAGS_vmlinux} -o ${2} \
+ -Wl,-T,${lds} \
+ ${objects} \
-lutil -lrt -lpthread
rm -f linux
fi
@@ -191,7 +164,7 @@ cleanup()
rm -f .tmp_System.map
rm -f .tmp_kallsyms*
rm -f .tmp_vmlinux*
- rm -f built-in.o
+ rm -f built-in.a
rm -f System.map
rm -f vmlinux
rm -f vmlinux.o
@@ -296,8 +269,8 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then
kallsyms .tmp_vmlinux2 .tmp_kallsyms2.o
# step 3
- size1=$(stat -c "%s" .tmp_kallsyms1.o)
- size2=$(stat -c "%s" .tmp_kallsyms2.o)
+ size1=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" .tmp_kallsyms1.o)
+ size2=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" .tmp_kallsyms2.o)
if [ $size1 -ne $size2 ] || [ -n "${KALLSYMS_EXTRA_PASS}" ]; then
kallsymso=.tmp_kallsyms3.o
diff --git a/scripts/namespace.pl b/scripts/namespace.pl
index 729c547fc9e1..6135574a6f39 100755
--- a/scripts/namespace.pl
+++ b/scripts/namespace.pl
@@ -164,7 +164,7 @@ sub linux_objects
s:^\./::;
if (/.*\.o$/ &&
! (
- m:/built-in.o$:
+ m:/built-in.a$:
|| m:arch/x86/vdso/:
|| m:arch/x86/boot/:
|| m:arch/ia64/ia32/ia32.o$:
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
index c74ecc6504e8..191eb949d52c 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -368,6 +368,11 @@ if ($arch eq "x86_64") {
} elsif ($arch eq "microblaze") {
# Microblaze calls '_mcount' instead of plain 'mcount'.
$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
+} elsif ($arch eq "riscv") {
+ $function_regex = "^([0-9a-fA-F]+)\\s+<([^.0-9][0-9a-zA-Z_\\.]+)>:";
+ $mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL\\s_mcount\$";
+ $type = ".quad";
+ $alignment = 2;
} else {
die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
}
diff --git a/security/security.c b/security/security.c
index 1cd8526cb0b7..02d734e69955 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1163,84 +1163,84 @@ void security_msg_msg_free(struct msg_msg *msg)
call_void_hook(msg_msg_free_security, msg);
}
-int security_msg_queue_alloc(struct msg_queue *msq)
+int security_msg_queue_alloc(struct kern_ipc_perm *msq)
{
return call_int_hook(msg_queue_alloc_security, 0, msq);
}
-void security_msg_queue_free(struct msg_queue *msq)
+void security_msg_queue_free(struct kern_ipc_perm *msq)
{
call_void_hook(msg_queue_free_security, msq);
}
-int security_msg_queue_associate(struct msg_queue *msq, int msqflg)
+int security_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
{
return call_int_hook(msg_queue_associate, 0, msq, msqflg);
}
-int security_msg_queue_msgctl(struct msg_queue *msq, int cmd)
+int security_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
{
return call_int_hook(msg_queue_msgctl, 0, msq, cmd);
}
-int security_msg_queue_msgsnd(struct msg_queue *msq,
+int security_msg_queue_msgsnd(struct kern_ipc_perm *msq,
struct msg_msg *msg, int msqflg)
{
return call_int_hook(msg_queue_msgsnd, 0, msq, msg, msqflg);
}
-int security_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
+int security_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg,
struct task_struct *target, long type, int mode)
{
return call_int_hook(msg_queue_msgrcv, 0, msq, msg, target, type, mode);
}
-int security_shm_alloc(struct shmid_kernel *shp)
+int security_shm_alloc(struct kern_ipc_perm *shp)
{
return call_int_hook(shm_alloc_security, 0, shp);
}
-void security_shm_free(struct shmid_kernel *shp)
+void security_shm_free(struct kern_ipc_perm *shp)
{
call_void_hook(shm_free_security, shp);
}
-int security_shm_associate(struct shmid_kernel *shp, int shmflg)
+int security_shm_associate(struct kern_ipc_perm *shp, int shmflg)
{
return call_int_hook(shm_associate, 0, shp, shmflg);
}
-int security_shm_shmctl(struct shmid_kernel *shp, int cmd)
+int security_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
{
return call_int_hook(shm_shmctl, 0, shp, cmd);
}
-int security_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, int shmflg)
+int security_shm_shmat(struct kern_ipc_perm *shp, char __user *shmaddr, int shmflg)
{
return call_int_hook(shm_shmat, 0, shp, shmaddr, shmflg);
}
-int security_sem_alloc(struct sem_array *sma)
+int security_sem_alloc(struct kern_ipc_perm *sma)
{
return call_int_hook(sem_alloc_security, 0, sma);
}
-void security_sem_free(struct sem_array *sma)
+void security_sem_free(struct kern_ipc_perm *sma)
{
call_void_hook(sem_free_security, sma);
}
-int security_sem_associate(struct sem_array *sma, int semflg)
+int security_sem_associate(struct kern_ipc_perm *sma, int semflg)
{
return call_int_hook(sem_associate, 0, sma, semflg);
}
-int security_sem_semctl(struct sem_array *sma, int cmd)
+int security_sem_semctl(struct kern_ipc_perm *sma, int cmd)
{
return call_int_hook(sem_semctl, 0, sma, cmd);
}
-int security_sem_semop(struct sem_array *sma, struct sembuf *sops,
+int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops,
unsigned nsops, int alter)
{
return call_int_hook(sem_semop, 0, sma, sops, nsops, alter);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 8644d864e3c1..925e546b5a87 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5532,52 +5532,52 @@ static void selinux_msg_msg_free_security(struct msg_msg *msg)
}
/* message queue security operations */
-static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
+static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
{
struct ipc_security_struct *isec;
struct common_audit_data ad;
u32 sid = current_sid();
int rc;
- rc = ipc_alloc_security(&msq->q_perm, SECCLASS_MSGQ);
+ rc = ipc_alloc_security(msq, SECCLASS_MSGQ);
if (rc)
return rc;
- isec = msq->q_perm.security;
+ isec = msq->security;
ad.type = LSM_AUDIT_DATA_IPC;
- ad.u.ipc_id = msq->q_perm.key;
+ ad.u.ipc_id = msq->key;
rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
MSGQ__CREATE, &ad);
if (rc) {
- ipc_free_security(&msq->q_perm);
+ ipc_free_security(msq);
return rc;
}
return 0;
}
-static void selinux_msg_queue_free_security(struct msg_queue *msq)
+static void selinux_msg_queue_free_security(struct kern_ipc_perm *msq)
{
- ipc_free_security(&msq->q_perm);
+ ipc_free_security(msq);
}
-static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
+static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
{
struct ipc_security_struct *isec;
struct common_audit_data ad;
u32 sid = current_sid();
- isec = msq->q_perm.security;
+ isec = msq->security;
ad.type = LSM_AUDIT_DATA_IPC;
- ad.u.ipc_id = msq->q_perm.key;
+ ad.u.ipc_id = msq->key;
return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
MSGQ__ASSOCIATE, &ad);
}
-static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
+static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
{
int err;
int perms;
@@ -5602,11 +5602,11 @@ static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
return 0;
}
- err = ipc_has_perm(&msq->q_perm, perms);
+ err = ipc_has_perm(msq, perms);
return err;
}
-static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
+static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *msg, int msqflg)
{
struct ipc_security_struct *isec;
struct msg_security_struct *msec;
@@ -5614,7 +5614,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
u32 sid = current_sid();
int rc;
- isec = msq->q_perm.security;
+ isec = msq->security;
msec = msg->security;
/*
@@ -5632,7 +5632,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
}
ad.type = LSM_AUDIT_DATA_IPC;
- ad.u.ipc_id = msq->q_perm.key;
+ ad.u.ipc_id = msq->key;
/* Can this process write to the queue? */
rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
@@ -5649,7 +5649,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
return rc;
}
-static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
+static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg,
struct task_struct *target,
long type, int mode)
{
@@ -5659,11 +5659,11 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
u32 sid = task_sid(target);
int rc;
- isec = msq->q_perm.security;
+ isec = msq->security;
msec = msg->security;
ad.type = LSM_AUDIT_DATA_IPC;
- ad.u.ipc_id = msq->q_perm.key;
+ ad.u.ipc_id = msq->key;
rc = avc_has_perm(sid, isec->sid,
SECCLASS_MSGQ, MSGQ__READ, &ad);
@@ -5674,53 +5674,53 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
}
/* Shared Memory security operations */
-static int selinux_shm_alloc_security(struct shmid_kernel *shp)
+static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
{
struct ipc_security_struct *isec;
struct common_audit_data ad;
u32 sid = current_sid();
int rc;
- rc = ipc_alloc_security(&shp->shm_perm, SECCLASS_SHM);
+ rc = ipc_alloc_security(shp, SECCLASS_SHM);
if (rc)
return rc;
- isec = shp->shm_perm.security;
+ isec = shp->security;
ad.type = LSM_AUDIT_DATA_IPC;
- ad.u.ipc_id = shp->shm_perm.key;
+ ad.u.ipc_id = shp->key;
rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
SHM__CREATE, &ad);
if (rc) {
- ipc_free_security(&shp->shm_perm);
+ ipc_free_security(shp);
return rc;
}
return 0;
}
-static void selinux_shm_free_security(struct shmid_kernel *shp)
+static void selinux_shm_free_security(struct kern_ipc_perm *shp)
{
- ipc_free_security(&shp->shm_perm);
+ ipc_free_security(shp);
}
-static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
+static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
{
struct ipc_security_struct *isec;
struct common_audit_data ad;
u32 sid = current_sid();
- isec = shp->shm_perm.security;
+ isec = shp->security;
ad.type = LSM_AUDIT_DATA_IPC;
- ad.u.ipc_id = shp->shm_perm.key;
+ ad.u.ipc_id = shp->key;
return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
SHM__ASSOCIATE, &ad);
}
/* Note, at this point, shp is locked down */
-static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
+static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
{
int perms;
int err;
@@ -5749,11 +5749,11 @@ static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
return 0;
}
- err = ipc_has_perm(&shp->shm_perm, perms);
+ err = ipc_has_perm(shp, perms);
return err;
}
-static int selinux_shm_shmat(struct shmid_kernel *shp,
+static int selinux_shm_shmat(struct kern_ipc_perm *shp,
char __user *shmaddr, int shmflg)
{
u32 perms;
@@ -5763,57 +5763,57 @@ static int selinux_shm_shmat(struct shmid_kernel *shp,
else
perms = SHM__READ | SHM__WRITE;
- return ipc_has_perm(&shp->shm_perm, perms);
+ return ipc_has_perm(shp, perms);
}
/* Semaphore security operations */
-static int selinux_sem_alloc_security(struct sem_array *sma)
+static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
{
struct ipc_security_struct *isec;
struct common_audit_data ad;
u32 sid = current_sid();
int rc;
- rc = ipc_alloc_security(&sma->sem_perm, SECCLASS_SEM);
+ rc = ipc_alloc_security(sma, SECCLASS_SEM);
if (rc)
return rc;
- isec = sma->sem_perm.security;
+ isec = sma->security;
ad.type = LSM_AUDIT_DATA_IPC;
- ad.u.ipc_id = sma->sem_perm.key;
+ ad.u.ipc_id = sma->key;
rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
SEM__CREATE, &ad);
if (rc) {
- ipc_free_security(&sma->sem_perm);
+ ipc_free_security(sma);
return rc;
}
return 0;
}
-static void selinux_sem_free_security(struct sem_array *sma)
+static void selinux_sem_free_security(struct kern_ipc_perm *sma)
{
- ipc_free_security(&sma->sem_perm);
+ ipc_free_security(sma);
}
-static int selinux_sem_associate(struct sem_array *sma, int semflg)
+static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
{
struct ipc_security_struct *isec;
struct common_audit_data ad;
u32 sid = current_sid();
- isec = sma->sem_perm.security;
+ isec = sma->security;
ad.type = LSM_AUDIT_DATA_IPC;
- ad.u.ipc_id = sma->sem_perm.key;
+ ad.u.ipc_id = sma->key;
return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
SEM__ASSOCIATE, &ad);
}
/* Note, at this point, sma is locked down */
-static int selinux_sem_semctl(struct sem_array *sma, int cmd)
+static int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd)
{
int err;
u32 perms;
@@ -5851,11 +5851,11 @@ static int selinux_sem_semctl(struct sem_array *sma, int cmd)
return 0;
}
- err = ipc_has_perm(&sma->sem_perm, perms);
+ err = ipc_has_perm(sma, perms);
return err;
}
-static int selinux_sem_semop(struct sem_array *sma,
+static int selinux_sem_semop(struct kern_ipc_perm *sma,
struct sembuf *sops, unsigned nsops, int alter)
{
u32 perms;
@@ -5865,7 +5865,7 @@ static int selinux_sem_semop(struct sem_array *sma,
else
perms = SEM__READ;
- return ipc_has_perm(&sma->sem_perm, perms);
+ return ipc_has_perm(sma, perms);
}
static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 03fdecba93bb..0735b8db158b 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2945,25 +2945,24 @@ static void smack_msg_msg_free_security(struct msg_msg *msg)
}
/**
- * smack_of_shm - the smack pointer for the shm
- * @shp: the object
+ * smack_of_ipc - the smack pointer for the ipc
+ * @isp: the object
*
* Returns a pointer to the smack value
*/
-static struct smack_known *smack_of_shm(struct shmid_kernel *shp)
+static struct smack_known *smack_of_ipc(struct kern_ipc_perm *isp)
{
- return (struct smack_known *)shp->shm_perm.security;
+ return (struct smack_known *)isp->security;
}
/**
- * smack_shm_alloc_security - Set the security blob for shm
- * @shp: the object
+ * smack_ipc_alloc_security - Set the security blob for ipc
+ * @isp: the object
*
* Returns 0
*/
-static int smack_shm_alloc_security(struct shmid_kernel *shp)
+static int smack_ipc_alloc_security(struct kern_ipc_perm *isp)
{
- struct kern_ipc_perm *isp = &shp->shm_perm;
struct smack_known *skp = smk_of_current();
isp->security = skp;
@@ -2971,34 +2970,32 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp)
}
/**
- * smack_shm_free_security - Clear the security blob for shm
- * @shp: the object
+ * smack_ipc_free_security - Clear the security blob for ipc
+ * @isp: the object
*
* Clears the blob pointer
*/
-static void smack_shm_free_security(struct shmid_kernel *shp)
+static void smack_ipc_free_security(struct kern_ipc_perm *isp)
{
- struct kern_ipc_perm *isp = &shp->shm_perm;
-
isp->security = NULL;
}
/**
* smk_curacc_shm : check if current has access on shm
- * @shp : the object
+ * @isp : the object
* @access : access requested
*
* Returns 0 if current has the requested access, error code otherwise
*/
-static int smk_curacc_shm(struct shmid_kernel *shp, int access)
+static int smk_curacc_shm(struct kern_ipc_perm *isp, int access)
{
- struct smack_known *ssp = smack_of_shm(shp);
+ struct smack_known *ssp = smack_of_ipc(isp);
struct smk_audit_info ad;
int rc;
#ifdef CONFIG_AUDIT
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
- ad.a.u.ipc_id = shp->shm_perm.id;
+ ad.a.u.ipc_id = isp->id;
#endif
rc = smk_curacc(ssp, access, &ad);
rc = smk_bu_current("shm", ssp, access, rc);
@@ -3007,27 +3004,27 @@ static int smk_curacc_shm(struct shmid_kernel *shp, int access)
/**
* smack_shm_associate - Smack access check for shm
- * @shp: the object
+ * @isp: the object
* @shmflg: access requested
*
* Returns 0 if current has the requested access, error code otherwise
*/
-static int smack_shm_associate(struct shmid_kernel *shp, int shmflg)
+static int smack_shm_associate(struct kern_ipc_perm *isp, int shmflg)
{
int may;
may = smack_flags_to_may(shmflg);
- return smk_curacc_shm(shp, may);
+ return smk_curacc_shm(isp, may);
}
/**
* smack_shm_shmctl - Smack access check for shm
- * @shp: the object
+ * @isp: the object
* @cmd: what it wants to do
*
* Returns 0 if current has the requested access, error code otherwise
*/
-static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd)
+static int smack_shm_shmctl(struct kern_ipc_perm *isp, int cmd)
{
int may;
@@ -3051,81 +3048,42 @@ static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd)
default:
return -EINVAL;
}
- return smk_curacc_shm(shp, may);
+ return smk_curacc_shm(isp, may);
}
/**
* smack_shm_shmat - Smack access for shmat
- * @shp: the object
+ * @isp: the object
* @shmaddr: unused
* @shmflg: access requested
*
* Returns 0 if current has the requested access, error code otherwise
*/
-static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
+static int smack_shm_shmat(struct kern_ipc_perm *ipc, char __user *shmaddr,
int shmflg)
{
int may;
may = smack_flags_to_may(shmflg);
- return smk_curacc_shm(shp, may);
-}
-
-/**
- * smack_of_sem - the smack pointer for the sem
- * @sma: the object
- *
- * Returns a pointer to the smack value
- */
-static struct smack_known *smack_of_sem(struct sem_array *sma)
-{
- return (struct smack_known *)sma->sem_perm.security;
-}
-
-/**
- * smack_sem_alloc_security - Set the security blob for sem
- * @sma: the object
- *
- * Returns 0
- */
-static int smack_sem_alloc_security(struct sem_array *sma)
-{
- struct kern_ipc_perm *isp = &sma->sem_perm;
- struct smack_known *skp = smk_of_current();
-
- isp->security = skp;
- return 0;
-}
-
-/**
- * smack_sem_free_security - Clear the security blob for sem
- * @sma: the object
- *
- * Clears the blob pointer
- */
-static void smack_sem_free_security(struct sem_array *sma)
-{
- struct kern_ipc_perm *isp = &sma->sem_perm;
-
- isp->security = NULL;
+ return smk_curacc_shm(ipc, may);
}
/**
* smk_curacc_sem : check if current has access on sem
- * @sma : the object
+ * @isp : the object
* @access : access requested
*
* Returns 0 if current has the requested access, error code otherwise
*/
-static int smk_curacc_sem(struct sem_array *sma, int access)
+static int smk_curacc_sem(struct kern_ipc_perm *isp, int access)
{
- struct smack_known *ssp = smack_of_sem(sma);
+ struct smack_known *ssp = smack_of_ipc(isp);
struct smk_audit_info ad;
int rc;
#ifdef CONFIG_AUDIT
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
- ad.a.u.ipc_id = sma->sem_perm.id;
+ ad.a.u.ipc_id = isp->id;
#endif
rc = smk_curacc(ssp, access, &ad);
rc = smk_bu_current("sem", ssp, access, rc);
@@ -3134,27 +3092,27 @@ static int smk_curacc_sem(struct sem_array *sma, int access)
/**
* smack_sem_associate - Smack access check for sem
- * @sma: the object
+ * @isp: the object
* @semflg: access requested
*
* Returns 0 if current has the requested access, error code otherwise
*/
-static int smack_sem_associate(struct sem_array *sma, int semflg)
+static int smack_sem_associate(struct kern_ipc_perm *isp, int semflg)
{
int may;
may = smack_flags_to_may(semflg);
- return smk_curacc_sem(sma, may);
+ return smk_curacc_sem(isp, may);
}
/**
* smack_sem_shmctl - Smack access check for sem
- * @sma: the object
+ * @isp: the object
* @cmd: what it wants to do
*
* Returns 0 if current has the requested access, error code otherwise
*/
-static int smack_sem_semctl(struct sem_array *sma, int cmd)
+static int smack_sem_semctl(struct kern_ipc_perm *isp, int cmd)
{
int may;
@@ -3184,12 +3142,12 @@ static int smack_sem_semctl(struct sem_array *sma, int cmd)
return -EINVAL;
}
- return smk_curacc_sem(sma, may);
+ return smk_curacc_sem(isp, may);
}
/**
* smack_sem_semop - Smack checks of semaphore operations
- * @sma: the object
+ * @isp: the object
* @sops: unused
* @nsops: unused
* @alter: unused
@@ -3198,67 +3156,28 @@ static int smack_sem_semctl(struct sem_array *sma, int cmd)
*
* Returns 0 if access is allowed, error code otherwise
*/
-static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops,
+static int smack_sem_semop(struct kern_ipc_perm *isp, struct sembuf *sops,
unsigned nsops, int alter)
{
- return smk_curacc_sem(sma, MAY_READWRITE);
-}
-
-/**
- * smack_msg_alloc_security - Set the security blob for msg
- * @msq: the object
- *
- * Returns 0
- */
-static int smack_msg_queue_alloc_security(struct msg_queue *msq)
-{
- struct kern_ipc_perm *kisp = &msq->q_perm;
- struct smack_known *skp = smk_of_current();
-
- kisp->security = skp;
- return 0;
-}
-
-/**
- * smack_msg_free_security - Clear the security blob for msg
- * @msq: the object
- *
- * Clears the blob pointer
- */
-static void smack_msg_queue_free_security(struct msg_queue *msq)
-{
- struct kern_ipc_perm *kisp = &msq->q_perm;
-
- kisp->security = NULL;
-}
-
-/**
- * smack_of_msq - the smack pointer for the msq
- * @msq: the object
- *
- * Returns a pointer to the smack label entry
- */
-static struct smack_known *smack_of_msq(struct msg_queue *msq)
-{
- return (struct smack_known *)msq->q_perm.security;
+ return smk_curacc_sem(isp, MAY_READWRITE);
}
/**
* smk_curacc_msq : helper to check if current has access on msq
- * @msq : the msq
+ * @isp : the msq
* @access : access requested
*
* return 0 if current has access, error otherwise
*/
-static int smk_curacc_msq(struct msg_queue *msq, int access)
+static int smk_curacc_msq(struct kern_ipc_perm *isp, int access)
{
- struct smack_known *msp = smack_of_msq(msq);
+ struct smack_known *msp = smack_of_ipc(isp);
struct smk_audit_info ad;
int rc;
#ifdef CONFIG_AUDIT
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
- ad.a.u.ipc_id = msq->q_perm.id;
+ ad.a.u.ipc_id = isp->id;
#endif
rc = smk_curacc(msp, access, &ad);
rc = smk_bu_current("msq", msp, access, rc);
@@ -3267,27 +3186,27 @@ static int smk_curacc_msq(struct msg_queue *msq, int access)
/**
* smack_msg_queue_associate - Smack access check for msg_queue
- * @msq: the object
+ * @isp: the object
* @msqflg: access requested
*
* Returns 0 if current has the requested access, error code otherwise
*/
-static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg)
+static int smack_msg_queue_associate(struct kern_ipc_perm *isp, int msqflg)
{
int may;
may = smack_flags_to_may(msqflg);
- return smk_curacc_msq(msq, may);
+ return smk_curacc_msq(isp, may);
}
/**
* smack_msg_queue_msgctl - Smack access check for msg_queue
- * @msq: the object
+ * @isp: the object
* @cmd: what it wants to do
*
* Returns 0 if current has the requested access, error code otherwise
*/
-static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd)
+static int smack_msg_queue_msgctl(struct kern_ipc_perm *isp, int cmd)
{
int may;
@@ -3310,29 +3229,29 @@ static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd)
return -EINVAL;
}
- return smk_curacc_msq(msq, may);
+ return smk_curacc_msq(isp, may);
}
/**
* smack_msg_queue_msgsnd - Smack access check for msg_queue
- * @msq: the object
+ * @isp: the object
* @msg: unused
* @msqflg: access requested
*
* Returns 0 if current has the requested access, error code otherwise
*/
-static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
+static int smack_msg_queue_msgsnd(struct kern_ipc_perm *isp, struct msg_msg *msg,
int msqflg)
{
int may;
may = smack_flags_to_may(msqflg);
- return smk_curacc_msq(msq, may);
+ return smk_curacc_msq(isp, may);
}
/**
* smack_msg_queue_msgsnd - Smack access check for msg_queue
- * @msq: the object
+ * @isp: the object
* @msg: unused
* @target: unused
* @type: unused
@@ -3340,10 +3259,10 @@ static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
*
* Returns 0 if current has read and write access, error code otherwise
*/
-static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
+static int smack_msg_queue_msgrcv(struct kern_ipc_perm *isp, struct msg_msg *msg,
struct task_struct *target, long type, int mode)
{
- return smk_curacc_msq(msq, MAY_READWRITE);
+ return smk_curacc_msq(isp, MAY_READWRITE);
}
/**
@@ -4756,21 +4675,21 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(msg_msg_alloc_security, smack_msg_msg_alloc_security),
LSM_HOOK_INIT(msg_msg_free_security, smack_msg_msg_free_security),
- LSM_HOOK_INIT(msg_queue_alloc_security, smack_msg_queue_alloc_security),
- LSM_HOOK_INIT(msg_queue_free_security, smack_msg_queue_free_security),
+ LSM_HOOK_INIT(msg_queue_alloc_security, smack_ipc_alloc_security),
+ LSM_HOOK_INIT(msg_queue_free_security, smack_ipc_free_security),
LSM_HOOK_INIT(msg_queue_associate, smack_msg_queue_associate),
LSM_HOOK_INIT(msg_queue_msgctl, smack_msg_queue_msgctl),
LSM_HOOK_INIT(msg_queue_msgsnd, smack_msg_queue_msgsnd),
LSM_HOOK_INIT(msg_queue_msgrcv, smack_msg_queue_msgrcv),
- LSM_HOOK_INIT(shm_alloc_security, smack_shm_alloc_security),
- LSM_HOOK_INIT(shm_free_security, smack_shm_free_security),
+ LSM_HOOK_INIT(shm_alloc_security, smack_ipc_alloc_security),
+ LSM_HOOK_INIT(shm_free_security, smack_ipc_free_security),
LSM_HOOK_INIT(shm_associate, smack_shm_associate),
LSM_HOOK_INIT(shm_shmctl, smack_shm_shmctl),
LSM_HOOK_INIT(shm_shmat, smack_shm_shmat),
- LSM_HOOK_INIT(sem_alloc_security, smack_sem_alloc_security),
- LSM_HOOK_INIT(sem_free_security, smack_sem_free_security),
+ LSM_HOOK_INIT(sem_alloc_security, smack_ipc_alloc_security),
+ LSM_HOOK_INIT(sem_free_security, smack_ipc_free_security),
LSM_HOOK_INIT(sem_associate, smack_sem_associate),
LSM_HOOK_INIT(sem_semctl, smack_sem_semctl),
LSM_HOOK_INIT(sem_semop, smack_sem_semop),
diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c
index 457a1521f32f..d78aed86af09 100644
--- a/tools/hv/hv_fcopy_daemon.c
+++ b/tools/hv/hv_fcopy_daemon.c
@@ -21,15 +21,17 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <string.h>
#include <errno.h>
#include <linux/hyperv.h>
+#include <linux/limits.h>
#include <syslog.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <getopt.h>
static int target_fd;
-static char target_fname[W_MAX_PATH];
+static char target_fname[PATH_MAX];
static unsigned long long filesize;
static int hv_start_fcopy(struct hv_start_fcopy *smsg)
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 4c99c57736ce..dbf6e8bd98ba 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -634,64 +634,6 @@ static char *kvp_if_name_to_mac(char *if_name)
return mac_addr;
}
-
-/*
- * Retrieve the interface name given tha MAC address.
- */
-
-static char *kvp_mac_to_if_name(char *mac)
-{
- DIR *dir;
- struct dirent *entry;
- FILE *file;
- char *p, *x;
- char *if_name = NULL;
- char buf[256];
- char dev_id[PATH_MAX];
- unsigned int i;
-
- dir = opendir(KVP_NET_DIR);
- if (dir == NULL)
- return NULL;
-
- while ((entry = readdir(dir)) != NULL) {
- /*
- * Set the state for the next pass.
- */
- snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR,
- entry->d_name);
-
- file = fopen(dev_id, "r");
- if (file == NULL)
- continue;
-
- p = fgets(buf, sizeof(buf), file);
- if (p) {
- x = strchr(p, '\n');
- if (x)
- *x = '\0';
-
- for (i = 0; i < strlen(p); i++)
- p[i] = toupper(p[i]);
-
- if (!strcmp(p, mac)) {
- /*
- * Found the MAC match; return the interface
- * name. The caller will free the memory.
- */
- if_name = strdup(entry->d_name);
- fclose(file);
- break;
- }
- }
- fclose(file);
- }
-
- closedir(dir);
- return if_name;
-}
-
-
static void kvp_process_ipconfig_file(char *cmd,
char *config_buf, unsigned int len,
int element_size, int offset)
@@ -997,6 +939,70 @@ getaddr_done:
return error;
}
+/*
+ * Retrieve the IP given the MAC address.
+ */
+static int kvp_mac_to_ip(struct hv_kvp_ipaddr_value *kvp_ip_val)
+{
+ char *mac = (char *)kvp_ip_val->adapter_id;
+ DIR *dir;
+ struct dirent *entry;
+ FILE *file;
+ char *p, *x;
+ char *if_name = NULL;
+ char buf[256];
+ char dev_id[PATH_MAX];
+ unsigned int i;
+ int error = HV_E_FAIL;
+
+ dir = opendir(KVP_NET_DIR);
+ if (dir == NULL)
+ return HV_E_FAIL;
+
+ while ((entry = readdir(dir)) != NULL) {
+ /*
+ * Set the state for the next pass.
+ */
+ snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR,
+ entry->d_name);
+
+ file = fopen(dev_id, "r");
+ if (file == NULL)
+ continue;
+
+ p = fgets(buf, sizeof(buf), file);
+ fclose(file);
+ if (!p)
+ continue;
+
+ x = strchr(p, '\n');
+ if (x)
+ *x = '\0';
+
+ for (i = 0; i < strlen(p); i++)
+ p[i] = toupper(p[i]);
+
+ if (strcmp(p, mac))
+ continue;
+
+ /*
+ * Found the MAC match.
+ * A NIC (e.g. VF) matching the MAC, but without IP, is skipped.
+ */
+ if_name = entry->d_name;
+ if (!if_name)
+ continue;
+
+ error = kvp_get_ip_info(0, if_name, KVP_OP_GET_IP_INFO,
+ kvp_ip_val, MAX_IP_ADDR_SIZE * 2);
+
+ if (!error && strlen((char *)kvp_ip_val->ip_addr))
+ break;
+ }
+
+ closedir(dir);
+ return error;
+}
static int expand_ipv6(char *addr, int type)
{
@@ -1472,26 +1478,12 @@ int main(int argc, char *argv[])
switch (op) {
case KVP_OP_GET_IP_INFO:
kvp_ip_val = &hv_msg->body.kvp_ip_val;
- if_name =
- kvp_mac_to_if_name((char *)kvp_ip_val->adapter_id);
- if (if_name == NULL) {
- /*
- * We could not map the mac address to an
- * interface name; return error.
- */
- hv_msg->error = HV_E_FAIL;
- break;
- }
- error = kvp_get_ip_info(
- 0, if_name, KVP_OP_GET_IP_INFO,
- kvp_ip_val,
- (MAX_IP_ADDR_SIZE * 2));
+ error = kvp_mac_to_ip(kvp_ip_val);
if (error)
hv_msg->error = error;
- free(if_name);
break;
case KVP_OP_SET_IP_INFO:
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
index b2b4ebffab8c..34031a297f02 100644
--- a/tools/hv/hv_vss_daemon.c
+++ b/tools/hv/hv_vss_daemon.c
@@ -22,6 +22,7 @@
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
+#include <sys/sysmacros.h>
#include <fcntl.h>
#include <stdio.h>
#include <mntent.h>
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 7442dfb73b7f..dbda89c9d9b9 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -7,6 +7,7 @@ TARGETS += cpufreq
TARGETS += cpu-hotplug
TARGETS += efivarfs
TARGETS += exec
+TARGETS += filesystems
TARGETS += firmware
TARGETS += ftrace
TARGETS += futex
diff --git a/tools/testing/selftests/filesystems/.gitignore b/tools/testing/selftests/filesystems/.gitignore
index 31d6e426b6d4..8449cf6716ce 100644
--- a/tools/testing/selftests/filesystems/.gitignore
+++ b/tools/testing/selftests/filesystems/.gitignore
@@ -1 +1,2 @@
dnotify_test
+devpts_pts
diff --git a/tools/testing/selftests/filesystems/Makefile b/tools/testing/selftests/filesystems/Makefile
index 13a73bf725b5..4e6d09fb166f 100644
--- a/tools/testing/selftests/filesystems/Makefile
+++ b/tools/testing/selftests/filesystems/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-TEST_PROGS := dnotify_test
+TEST_PROGS := dnotify_test devpts_pts
all: $(TEST_PROGS)
include ../lib.mk
diff --git a/tools/testing/selftests/filesystems/devpts_pts.c b/tools/testing/selftests/filesystems/devpts_pts.c
new file mode 100644
index 000000000000..b9055e974289
--- /dev/null
+++ b/tools/testing/selftests/filesystems/devpts_pts.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/wait.h>
+
+static bool terminal_dup2(int duplicate, int original)
+{
+ int ret;
+
+ ret = dup2(duplicate, original);
+ if (ret < 0)
+ return false;
+
+ return true;
+}
+
+static int terminal_set_stdfds(int fd)
+{
+ int i;
+
+ if (fd < 0)
+ return 0;
+
+ for (i = 0; i < 3; i++)
+ if (!terminal_dup2(fd, (int[]){STDIN_FILENO, STDOUT_FILENO,
+ STDERR_FILENO}[i]))
+ return -1;
+
+ return 0;
+}
+
+static int login_pty(int fd)
+{
+ int ret;
+
+ setsid();
+
+ ret = ioctl(fd, TIOCSCTTY, NULL);
+ if (ret < 0)
+ return -1;
+
+ ret = terminal_set_stdfds(fd);
+ if (ret < 0)
+ return -1;
+
+ if (fd > STDERR_FILENO)
+ close(fd);
+
+ return 0;
+}
+
+static int wait_for_pid(pid_t pid)
+{
+ int status, ret;
+
+again:
+ ret = waitpid(pid, &status, 0);
+ if (ret == -1) {
+ if (errno == EINTR)
+ goto again;
+ return -1;
+ }
+ if (ret != pid)
+ goto again;
+
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ return -1;
+
+ return 0;
+}
+
+static int resolve_procfd_symlink(int fd, char *buf, size_t buflen)
+{
+ int ret;
+ char procfd[4096];
+
+ ret = snprintf(procfd, 4096, "/proc/self/fd/%d", fd);
+ if (ret < 0 || ret >= 4096)
+ return -1;
+
+ ret = readlink(procfd, buf, buflen);
+ if (ret < 0 || (size_t)ret >= buflen)
+ return -1;
+
+ buf[ret] = '\0';
+
+ return 0;
+}
+
+static int do_tiocgptpeer(char *ptmx, char *expected_procfd_contents)
+{
+ int ret;
+ int master = -1, slave = -1, fret = -1;
+
+ master = open(ptmx, O_RDWR | O_NOCTTY | O_CLOEXEC);
+ if (master < 0) {
+ fprintf(stderr, "Failed to open \"%s\": %s\n", ptmx,
+ strerror(errno));
+ return -1;
+ }
+
+ /*
+ * grantpt() makes assumptions about /dev/pts/ so ignore it. It's also
+ * not really needed.
+ */
+ ret = unlockpt(master);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to unlock terminal\n");
+ goto do_cleanup;
+ }
+
+#ifdef TIOCGPTPEER
+ slave = ioctl(master, TIOCGPTPEER, O_RDWR | O_NOCTTY | O_CLOEXEC);
+#endif
+ if (slave < 0) {
+ if (errno == EINVAL) {
+ fprintf(stderr, "TIOCGPTPEER is not supported. "
+ "Skipping test.\n");
+ fret = EXIT_SUCCESS;
+ }
+
+ fprintf(stderr, "Failed to perform TIOCGPTPEER ioctl\n");
+ goto do_cleanup;
+ }
+
+ pid_t pid = fork();
+ if (pid < 0)
+ goto do_cleanup;
+
+ if (pid == 0) {
+ char buf[4096];
+
+ ret = login_pty(slave);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to setup terminal\n");
+ _exit(EXIT_FAILURE);
+ }
+
+ ret = resolve_procfd_symlink(STDIN_FILENO, buf, sizeof(buf));
+ if (ret < 0) {
+ fprintf(stderr, "Failed to retrieve pathname of pts "
+ "slave file descriptor\n");
+ _exit(EXIT_FAILURE);
+ }
+
+ if (strncmp(expected_procfd_contents, buf,
+ strlen(expected_procfd_contents)) != 0) {
+ fprintf(stderr, "Received invalid contents for "
+ "\"/proc/<pid>/fd/%d\" symlink: %s\n",
+ STDIN_FILENO, buf);
+ _exit(-1);
+ }
+
+ fprintf(stderr, "Contents of \"/proc/<pid>/fd/%d\" "
+ "symlink are valid: %s\n", STDIN_FILENO, buf);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ ret = wait_for_pid(pid);
+ if (ret < 0)
+ goto do_cleanup;
+
+ fret = EXIT_SUCCESS;
+
+do_cleanup:
+ if (master >= 0)
+ close(master);
+ if (slave >= 0)
+ close(slave);
+
+ return fret;
+}
+
+static int verify_non_standard_devpts_mount(void)
+{
+ char *mntpoint;
+ int ret = -1;
+ char devpts[] = P_tmpdir "/devpts_fs_XXXXXX";
+ char ptmx[] = P_tmpdir "/devpts_fs_XXXXXX/ptmx";
+
+ ret = umount("/dev/pts");
+ if (ret < 0) {
+ fprintf(stderr, "Failed to unmount \"/dev/pts\": %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ (void)umount("/dev/ptmx");
+
+ mntpoint = mkdtemp(devpts);
+ if (!mntpoint) {
+ fprintf(stderr, "Failed to create temporary mountpoint: %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ ret = mount("devpts", mntpoint, "devpts", MS_NOSUID | MS_NOEXEC,
+ "newinstance,ptmxmode=0666,mode=0620,gid=5");
+ if (ret < 0) {
+ fprintf(stderr, "Failed to mount devpts fs to \"%s\" in new "
+ "mount namespace: %s\n", mntpoint,
+ strerror(errno));
+ unlink(mntpoint);
+ return -1;
+ }
+
+ ret = snprintf(ptmx, sizeof(ptmx), "%s/ptmx", devpts);
+ if (ret < 0 || (size_t)ret >= sizeof(ptmx)) {
+ unlink(mntpoint);
+ return -1;
+ }
+
+ ret = do_tiocgptpeer(ptmx, mntpoint);
+ unlink(mntpoint);
+ if (ret < 0)
+ return -1;
+
+ return 0;
+}
+
+static int verify_ptmx_bind_mount(void)
+{
+ int ret;
+
+ ret = mount("/dev/pts/ptmx", "/dev/ptmx", NULL, MS_BIND, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to bind mount \"/dev/pts/ptmx\" to "
+ "\"/dev/ptmx\" mount namespace\n");
+ return -1;
+ }
+
+ ret = do_tiocgptpeer("/dev/ptmx", "/dev/pts/");
+ if (ret < 0)
+ return -1;
+
+ return 0;
+}
+
+static int verify_invalid_ptmx_bind_mount(void)
+{
+ int ret;
+ char mntpoint_fd;
+ char ptmx[] = P_tmpdir "/devpts_ptmx_XXXXXX";
+
+ mntpoint_fd = mkstemp(ptmx);
+ if (mntpoint_fd < 0) {
+ fprintf(stderr, "Failed to create temporary directory: %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ ret = mount("/dev/pts/ptmx", ptmx, NULL, MS_BIND, NULL);
+ close(mntpoint_fd);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to bind mount \"/dev/pts/ptmx\" to "
+ "\"%s\" mount namespace\n", ptmx);
+ return -1;
+ }
+
+ ret = do_tiocgptpeer(ptmx, "/dev/pts/");
+ if (ret == 0)
+ return -1;
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ if (!isatty(STDIN_FILENO)) {
+ fprintf(stderr, "Standard input file desciptor is not attached "
+ "to a terminal. Skipping test\n");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = unshare(CLONE_NEWNS);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to unshare mount namespace\n");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = mount("", "/", NULL, MS_PRIVATE | MS_REC, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to make \"/\" MS_PRIVATE in new mount "
+ "namespace\n");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = verify_ptmx_bind_mount();
+ if (ret < 0)
+ exit(EXIT_FAILURE);
+
+ ret = verify_invalid_ptmx_bind_mount();
+ if (ret < 0)
+ exit(EXIT_FAILURE);
+
+ ret = verify_non_standard_devpts_mount();
+ if (ret < 0)
+ exit(EXIT_FAILURE);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tools/testing/selftests/firmware/Makefile b/tools/testing/selftests/firmware/Makefile
index 1894d625af2d..826f38d5dd19 100644
--- a/tools/testing/selftests/firmware/Makefile
+++ b/tools/testing/selftests/firmware/Makefile
@@ -3,7 +3,7 @@
# No binaries, but make sure arg-less "make" doesn't trigger "run_tests"
all:
-TEST_PROGS := fw_filesystem.sh fw_fallback.sh
+TEST_PROGS := fw_run_tests.sh
include ../lib.mk
diff --git a/tools/testing/selftests/firmware/config b/tools/testing/selftests/firmware/config
index c8137f70e291..bf634dda0720 100644
--- a/tools/testing/selftests/firmware/config
+++ b/tools/testing/selftests/firmware/config
@@ -1 +1,5 @@
CONFIG_TEST_FIRMWARE=y
+CONFIG_FW_LOADER=y
+CONFIG_FW_LOADER_USER_HELPER=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
diff --git a/tools/testing/selftests/firmware/fw_fallback.sh b/tools/testing/selftests/firmware/fw_fallback.sh
index 722cad91df74..8e2e34a2ca69 100755
--- a/tools/testing/selftests/firmware/fw_fallback.sh
+++ b/tools/testing/selftests/firmware/fw_fallback.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# This validates that the kernel will fall back to using the fallback mechanism
# to load firmware it can't find on disk itself. We must request a firmware
@@ -6,31 +6,17 @@
# won't find so that we can do the load ourself manually.
set -e
-modprobe test_firmware
+TEST_REQS_FW_SYSFS_FALLBACK="yes"
+TEST_REQS_FW_SET_CUSTOM_PATH="no"
+TEST_DIR=$(dirname $0)
+source $TEST_DIR/fw_lib.sh
-DIR=/sys/devices/virtual/misc/test_firmware
+check_mods
+check_setup
+verify_reqs
+setup_tmp_file
-# CONFIG_FW_LOADER_USER_HELPER has a sysfs class under /sys/class/firmware/
-# These days no one enables CONFIG_FW_LOADER_USER_HELPER so check for that
-# as an indicator for CONFIG_FW_LOADER_USER_HELPER.
-HAS_FW_LOADER_USER_HELPER=$(if [ -d /sys/class/firmware/ ]; then echo yes; else echo no; fi)
-
-if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
- OLD_TIMEOUT=$(cat /sys/class/firmware/timeout)
-else
- echo "usermode helper disabled so ignoring test"
- exit 0
-fi
-
-FWPATH=$(mktemp -d)
-FW="$FWPATH/test-firmware.bin"
-
-test_finish()
-{
- echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout
- rm -f "$FW"
- rmdir "$FWPATH"
-}
+trap "test_finish" EXIT
load_fw()
{
@@ -169,12 +155,6 @@ load_fw_fallback_with_child()
return $RET
}
-trap "test_finish" EXIT
-
-# This is an unlikely real-world firmware content. :)
-echo "ABCD0123" >"$FW"
-NAME=$(basename "$FW")
-
test_syfs_timeout()
{
DEVPATH="$DIR"/"nope-$NAME"/loading
@@ -258,8 +238,10 @@ run_sysfs_main_tests()
run_sysfs_custom_load_tests()
{
- if load_fw_custom "$NAME" "$FW" ; then
- if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ RANDOM_FILE_PATH=$(setup_random_file)
+ RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
+ if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then
+ if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
echo "$0: firmware was not loaded" >&2
exit 1
else
@@ -267,8 +249,10 @@ run_sysfs_custom_load_tests()
fi
fi
- if load_fw_custom "$NAME" "$FW" ; then
- if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ RANDOM_FILE_PATH=$(setup_random_file)
+ RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
+ if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then
+ if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
echo "$0: firmware was not loaded" >&2
exit 1
else
@@ -276,8 +260,12 @@ run_sysfs_custom_load_tests()
fi
fi
- if load_fw_custom_cancel "nope-$NAME" "$FW" ; then
- if diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ RANDOM_FILE_REAL="$RANDOM_FILE_PATH"
+ FAKE_RANDOM_FILE_PATH=$(setup_random_file_fake)
+ FAKE_RANDOM_FILE="$(basename $FAKE_RANDOM_FILE_PATH)"
+
+ if load_fw_custom_cancel "$FAKE_RANDOM_FILE" "$RANDOM_FILE_REAL" ; then
+ if diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then
echo "$0: firmware was expected to be cancelled" >&2
exit 1
else
@@ -286,7 +274,10 @@ run_sysfs_custom_load_tests()
fi
}
-run_sysfs_main_tests
+if [ "$HAS_FW_LOADER_USER_HELPER_FALLBACK" = "yes" ]; then
+ run_sysfs_main_tests
+fi
+
run_sysfs_custom_load_tests
exit 0
diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh
index f9508e1a4058..6452d2129cd9 100755
--- a/tools/testing/selftests/firmware/fw_filesystem.sh
+++ b/tools/testing/selftests/firmware/fw_filesystem.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# This validates that the kernel will load firmware out of its list of
# firmware locations on disk. Since the user helper does similar work,
@@ -6,52 +6,15 @@
# know so we can be sure we're not accidentally testing the user helper.
set -e
-DIR=/sys/devices/virtual/misc/test_firmware
+TEST_REQS_FW_SYSFS_FALLBACK="no"
+TEST_REQS_FW_SET_CUSTOM_PATH="yes"
TEST_DIR=$(dirname $0)
+source $TEST_DIR/fw_lib.sh
-test_modprobe()
-{
- if [ ! -d $DIR ]; then
- echo "$0: $DIR not present"
- echo "You must have the following enabled in your kernel:"
- cat $TEST_DIR/config
- exit 1
- fi
-}
-
-trap "test_modprobe" EXIT
-
-if [ ! -d $DIR ]; then
- modprobe test_firmware
-fi
-
-# CONFIG_FW_LOADER_USER_HELPER has a sysfs class under /sys/class/firmware/
-# These days most distros enable CONFIG_FW_LOADER_USER_HELPER but disable
-# CONFIG_FW_LOADER_USER_HELPER_FALLBACK. We use /sys/class/firmware/ as an
-# indicator for CONFIG_FW_LOADER_USER_HELPER.
-HAS_FW_LOADER_USER_HELPER=$(if [ -d /sys/class/firmware/ ]; then echo yes; else echo no; fi)
-
-if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
- OLD_TIMEOUT=$(cat /sys/class/firmware/timeout)
-fi
-
-OLD_FWPATH=$(cat /sys/module/firmware_class/parameters/path)
-
-FWPATH=$(mktemp -d)
-FW="$FWPATH/test-firmware.bin"
-
-test_finish()
-{
- if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
- echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout
- fi
- if [ "$OLD_FWPATH" = "" ]; then
- OLD_FWPATH=" "
- fi
- echo -n "$OLD_FWPATH" >/sys/module/firmware_class/parameters/path
- rm -f "$FW"
- rmdir "$FWPATH"
-}
+check_mods
+check_setup
+verify_reqs
+setup_tmp_file
trap "test_finish" EXIT
@@ -60,14 +23,6 @@ if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
echo 1 >/sys/class/firmware/timeout
fi
-# Set the kernel search path.
-echo -n "$FWPATH" >/sys/module/firmware_class/parameters/path
-
-# This is an unlikely real-world firmware content. :)
-echo "ABCD0123" >"$FW"
-
-NAME=$(basename "$FW")
-
if printf '\000' >"$DIR"/trigger_request 2> /dev/null; then
echo "$0: empty filename should not succeed" >&2
exit 1
@@ -275,10 +230,13 @@ test_wait_and_cancel_custom_load()
test_request_firmware_nowait_custom_nofile()
{
echo -n "Batched request_firmware_nowait(uevent=false) nofile try #$1: "
+ config_reset
config_unset_uevent
- config_set_name nope-test-firmware.bin
+ RANDOM_FILE_PATH=$(setup_random_file_fake)
+ RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
+ config_set_name $RANDOM_FILE
config_trigger_async &
- test_wait_and_cancel_custom_load nope-test-firmware.bin
+ test_wait_and_cancel_custom_load $RANDOM_FILE
wait
release_all_firmware
echo "OK"
@@ -316,7 +274,11 @@ test_request_firmware_nowait_uevent()
test_request_firmware_nowait_custom()
{
echo -n "Batched request_firmware_nowait(uevent=false) try #$1: "
+ config_reset
config_unset_uevent
+ RANDOM_FILE_PATH=$(setup_random_file)
+ RANDOM_FILE="$(basename $RANDOM_FILE_PATH)"
+ config_set_name $RANDOM_FILE
config_trigger_async
release_all_firmware
echo "OK"
diff --git a/tools/testing/selftests/firmware/fw_lib.sh b/tools/testing/selftests/firmware/fw_lib.sh
new file mode 100755
index 000000000000..9ea31b57d71a
--- /dev/null
+++ b/tools/testing/selftests/firmware/fw_lib.sh
@@ -0,0 +1,194 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+# Library of helpers for test scripts.
+set -e
+
+DIR=/sys/devices/virtual/misc/test_firmware
+
+PROC_CONFIG="/proc/config.gz"
+TEST_DIR=$(dirname $0)
+
+print_reqs_exit()
+{
+ echo "You must have the following enabled in your kernel:" >&2
+ cat $TEST_DIR/config >&2
+ exit 1
+}
+
+test_modprobe()
+{
+ if [ ! -d $DIR ]; then
+ print_reqs_exit
+ fi
+}
+
+check_mods()
+{
+ trap "test_modprobe" EXIT
+ if [ ! -d $DIR ]; then
+ modprobe test_firmware
+ fi
+ if [ ! -f $PROC_CONFIG ]; then
+ if modprobe configs 2>/dev/null; then
+ echo "Loaded configs module"
+ if [ ! -f $PROC_CONFIG ]; then
+ echo "You must have the following enabled in your kernel:" >&2
+ cat $TEST_DIR/config >&2
+ echo "Resorting to old heuristics" >&2
+ fi
+ else
+ echo "Failed to load configs module, using old heuristics" >&2
+ fi
+ fi
+}
+
+check_setup()
+{
+ HAS_FW_LOADER_USER_HELPER="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER=y)"
+ HAS_FW_LOADER_USER_HELPER_FALLBACK="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y)"
+ PROC_FW_IGNORE_SYSFS_FALLBACK="0"
+ PROC_FW_FORCE_SYSFS_FALLBACK="0"
+
+ if [ -z $PROC_SYS_DIR ]; then
+ PROC_SYS_DIR="/proc/sys/kernel"
+ fi
+
+ FW_PROC="${PROC_SYS_DIR}/firmware_config"
+ FW_FORCE_SYSFS_FALLBACK="$FW_PROC/force_sysfs_fallback"
+ FW_IGNORE_SYSFS_FALLBACK="$FW_PROC/ignore_sysfs_fallback"
+
+ if [ -f $FW_FORCE_SYSFS_FALLBACK ]; then
+ PROC_FW_FORCE_SYSFS_FALLBACK="$(cat $FW_FORCE_SYSFS_FALLBACK)"
+ fi
+
+ if [ -f $FW_IGNORE_SYSFS_FALLBACK ]; then
+ PROC_FW_IGNORE_SYSFS_FALLBACK="$(cat $FW_IGNORE_SYSFS_FALLBACK)"
+ fi
+
+ if [ "$PROC_FW_FORCE_SYSFS_FALLBACK" = "1" ]; then
+ HAS_FW_LOADER_USER_HELPER="yes"
+ HAS_FW_LOADER_USER_HELPER_FALLBACK="yes"
+ fi
+
+ if [ "$PROC_FW_IGNORE_SYSFS_FALLBACK" = "1" ]; then
+ HAS_FW_LOADER_USER_HELPER_FALLBACK="no"
+ HAS_FW_LOADER_USER_HELPER="no"
+ fi
+
+ if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
+ OLD_TIMEOUT="$(cat /sys/class/firmware/timeout)"
+ fi
+
+ OLD_FWPATH="$(cat /sys/module/firmware_class/parameters/path)"
+}
+
+verify_reqs()
+{
+ if [ "$TEST_REQS_FW_SYSFS_FALLBACK" = "yes" ]; then
+ if [ ! "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
+ echo "usermode helper disabled so ignoring test"
+ exit 0
+ fi
+ fi
+}
+
+setup_tmp_file()
+{
+ FWPATH=$(mktemp -d)
+ FW="$FWPATH/test-firmware.bin"
+ echo "ABCD0123" >"$FW"
+ NAME=$(basename "$FW")
+ if [ "$TEST_REQS_FW_SET_CUSTOM_PATH" = "yes" ]; then
+ echo -n "$FWPATH" >/sys/module/firmware_class/parameters/path
+ fi
+}
+
+__setup_random_file()
+{
+ RANDOM_FILE_PATH="$(mktemp -p $FWPATH)"
+ # mktemp says dry-run -n is unsafe, so...
+ if [[ "$1" = "fake" ]]; then
+ rm -rf $RANDOM_FILE_PATH
+ sync
+ else
+ echo "ABCD0123" >"$RANDOM_FILE_PATH"
+ fi
+ echo $RANDOM_FILE_PATH
+}
+
+setup_random_file()
+{
+ echo $(__setup_random_file)
+}
+
+setup_random_file_fake()
+{
+ echo $(__setup_random_file fake)
+}
+
+proc_set_force_sysfs_fallback()
+{
+ if [ -f $FW_FORCE_SYSFS_FALLBACK ]; then
+ echo -n $1 > $FW_FORCE_SYSFS_FALLBACK
+ check_setup
+ fi
+}
+
+proc_set_ignore_sysfs_fallback()
+{
+ if [ -f $FW_IGNORE_SYSFS_FALLBACK ]; then
+ echo -n $1 > $FW_IGNORE_SYSFS_FALLBACK
+ check_setup
+ fi
+}
+
+proc_restore_defaults()
+{
+ proc_set_force_sysfs_fallback 0
+ proc_set_ignore_sysfs_fallback 0
+}
+
+test_finish()
+{
+ if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then
+ echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout
+ fi
+ if [ "$OLD_FWPATH" = "" ]; then
+ OLD_FWPATH=" "
+ fi
+ if [ "$TEST_REQS_FW_SET_CUSTOM_PATH" = "yes" ]; then
+ echo -n "$OLD_FWPATH" >/sys/module/firmware_class/parameters/path
+ fi
+ if [ -f $FW ]; then
+ rm -f "$FW"
+ fi
+ if [ -d $FWPATH ]; then
+ rm -rf "$FWPATH"
+ fi
+ proc_restore_defaults
+}
+
+kconfig_has()
+{
+ if [ -f $PROC_CONFIG ]; then
+ if zgrep -q $1 $PROC_CONFIG 2>/dev/null; then
+ echo "yes"
+ else
+ echo "no"
+ fi
+ else
+ # We currently don't have easy heuristics to infer this
+ # so best we can do is just try to use the kernel assuming
+ # you had enabled it. This matches the old behaviour.
+ if [ "$1" = "CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y" ]; then
+ echo "yes"
+ elif [ "$1" = "CONFIG_FW_LOADER_USER_HELPER=y" ]; then
+ if [ -d /sys/class/firmware/ ]; then
+ echo yes
+ else
+ echo no
+ fi
+ fi
+ fi
+}
diff --git a/tools/testing/selftests/firmware/fw_run_tests.sh b/tools/testing/selftests/firmware/fw_run_tests.sh
new file mode 100755
index 000000000000..06d638e9dc62
--- /dev/null
+++ b/tools/testing/selftests/firmware/fw_run_tests.sh
@@ -0,0 +1,70 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+# This runs all known tests across all known possible configurations we could
+# emulate in one run.
+
+set -e
+
+TEST_DIR=$(dirname $0)
+source $TEST_DIR/fw_lib.sh
+
+export HAS_FW_LOADER_USER_HELPER=""
+export HAS_FW_LOADER_USER_HELPER_FALLBACK=""
+
+run_tests()
+{
+ proc_set_force_sysfs_fallback $1
+ proc_set_ignore_sysfs_fallback $2
+ $TEST_DIR/fw_filesystem.sh
+
+ proc_set_force_sysfs_fallback $1
+ proc_set_ignore_sysfs_fallback $2
+ $TEST_DIR/fw_fallback.sh
+}
+
+run_test_config_0001()
+{
+ echo "-----------------------------------------------------"
+ echo "Running kernel configuration test 1 -- rare"
+ echo "Emulates:"
+ echo "CONFIG_FW_LOADER=y"
+ echo "CONFIG_FW_LOADER_USER_HELPER=n"
+ echo "CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n"
+ run_tests 0 1
+}
+
+run_test_config_0002()
+{
+ echo "-----------------------------------------------------"
+ echo "Running kernel configuration test 2 -- distro"
+ echo "Emulates:"
+ echo "CONFIG_FW_LOADER=y"
+ echo "CONFIG_FW_LOADER_USER_HELPER=y"
+ echo "CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n"
+ proc_set_ignore_sysfs_fallback 0
+ run_tests 0 0
+}
+
+run_test_config_0003()
+{
+ echo "-----------------------------------------------------"
+ echo "Running kernel configuration test 3 -- android"
+ echo "Emulates:"
+ echo "CONFIG_FW_LOADER=y"
+ echo "CONFIG_FW_LOADER_USER_HELPER=y"
+ echo "CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y"
+ run_tests 1 0
+}
+
+check_mods
+check_setup
+
+if [ -f $FW_FORCE_SYSFS_FALLBACK ]; then
+ run_test_config_0001
+ run_test_config_0002
+ run_test_config_0003
+else
+ echo "Running basic kernel configuration, working with your config"
+ run_test
+fi
diff --git a/tools/usb/usbip/libsrc/usbip_common.c b/tools/usb/usbip/libsrc/usbip_common.c
index 001bb8e8f668..bb424638d75b 100644
--- a/tools/usb/usbip/libsrc/usbip_common.c
+++ b/tools/usb/usbip/libsrc/usbip_common.c
@@ -66,6 +66,29 @@ const char *usbip_speed_string(int num)
return "Unknown Speed";
}
+struct op_common_status_string {
+ int num;
+ char *desc;
+};
+
+static struct op_common_status_string op_common_status_strings[] = {
+ { ST_OK, "Request Completed Successfully" },
+ { ST_NA, "Request Failed" },
+ { ST_DEV_BUSY, "Device busy (exported)" },
+ { ST_DEV_ERR, "Device in error state" },
+ { ST_NODEV, "Device not found" },
+ { ST_ERROR, "Unexpected response" },
+ { 0, NULL}
+};
+
+const char *usbip_op_common_status_string(int status)
+{
+ for (int i = 0; op_common_status_strings[i].desc != NULL; i++)
+ if (op_common_status_strings[i].num == status)
+ return op_common_status_strings[i].desc;
+
+ return "Unknown Op Common Status";
+}
#define DBG_UDEV_INTEGER(name)\
dbg("%-20s = %x", to_string(name), (int) udev->name)
diff --git a/tools/usb/usbip/libsrc/usbip_common.h b/tools/usb/usbip/libsrc/usbip_common.h
index e45ec9d2fdbc..73a367a7fa10 100644
--- a/tools/usb/usbip/libsrc/usbip_common.h
+++ b/tools/usb/usbip/libsrc/usbip_common.h
@@ -43,6 +43,16 @@
#define SYSFS_PATH_MAX 256
#define SYSFS_BUS_ID_SIZE 32
+/* Defines for op_code status in server/client op_common PDUs */
+#define ST_OK 0x00
+#define ST_NA 0x01
+ /* Device requested for import is not available */
+#define ST_DEV_BUSY 0x02
+ /* Device requested for import is in error state */
+#define ST_DEV_ERR 0x03
+#define ST_NODEV 0x04
+#define ST_ERROR 0x05
+
extern int usbip_use_syslog;
extern int usbip_use_stderr;
extern int usbip_use_debug ;
@@ -130,6 +140,7 @@ int read_usb_interface(struct usbip_usb_device *udev, int i,
const char *usbip_speed_string(int num);
const char *usbip_status_string(int32_t status);
+const char *usbip_op_common_status_string(int status);
int usbip_names_init(char *);
void usbip_names_free(void);
diff --git a/tools/usb/usbip/libsrc/usbip_host_common.c b/tools/usb/usbip/libsrc/usbip_host_common.c
index 6ff7b601f854..dc93fadbee96 100644
--- a/tools/usb/usbip/libsrc/usbip_host_common.c
+++ b/tools/usb/usbip/libsrc/usbip_host_common.c
@@ -234,14 +234,17 @@ int usbip_export_device(struct usbip_exported_device *edev, int sockfd)
switch (edev->status) {
case SDEV_ST_ERROR:
dbg("status SDEV_ST_ERROR");
+ ret = ST_DEV_ERR;
break;
case SDEV_ST_USED:
dbg("status SDEV_ST_USED");
+ ret = ST_DEV_BUSY;
break;
default:
dbg("status unknown: 0x%x", edev->status);
+ ret = -1;
}
- return -1;
+ return ret;
}
/* only the first interface is true */
diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
index 7f07b2d50f59..ba88728483ff 100644
--- a/tools/usb/usbip/src/usbip_attach.c
+++ b/tools/usb/usbip/src/usbip_attach.c
@@ -135,6 +135,7 @@ static int query_import_device(int sockfd, char *busid)
struct op_import_request request;
struct op_import_reply reply;
uint16_t code = OP_REP_IMPORT;
+ int status;
memset(&request, 0, sizeof(request));
memset(&reply, 0, sizeof(reply));
@@ -157,9 +158,10 @@ static int query_import_device(int sockfd, char *busid)
}
/* receive a reply */
- rc = usbip_net_recv_op_common(sockfd, &code);
+ rc = usbip_net_recv_op_common(sockfd, &code, &status);
if (rc < 0) {
- err("recv op_common");
+ err("Attach Request for %s failed - %s\n",
+ busid, usbip_op_common_status_string(status));
return -1;
}
@@ -194,10 +196,8 @@ static int attach_device(char *host, char *busid)
}
rhport = query_import_device(sockfd, busid);
- if (rhport < 0) {
- err("query");
+ if (rhport < 0)
return -1;
- }
close(sockfd);
diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c
index d65a9f444174..8d4ccf4b9480 100644
--- a/tools/usb/usbip/src/usbip_list.c
+++ b/tools/usb/usbip/src/usbip_list.c
@@ -62,6 +62,7 @@ static int get_exported_devices(char *host, int sockfd)
struct usbip_usb_interface uintf;
unsigned int i;
int rc, j;
+ int status;
rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
if (rc < 0) {
@@ -69,9 +70,10 @@ static int get_exported_devices(char *host, int sockfd)
return -1;
}
- rc = usbip_net_recv_op_common(sockfd, &code);
+ rc = usbip_net_recv_op_common(sockfd, &code, &status);
if (rc < 0) {
- dbg("usbip_net_recv_op_common failed");
+ err("Exported Device List Request failed - %s\n",
+ usbip_op_common_status_string(status));
return -1;
}
diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c
index b4c37e76a6e0..8ffcd47d9638 100644
--- a/tools/usb/usbip/src/usbip_network.c
+++ b/tools/usb/usbip/src/usbip_network.c
@@ -163,7 +163,7 @@ int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status)
return 0;
}
-int usbip_net_recv_op_common(int sockfd, uint16_t *code)
+int usbip_net_recv_op_common(int sockfd, uint16_t *code, int *status)
{
struct op_common op_common;
int rc;
@@ -179,8 +179,8 @@ int usbip_net_recv_op_common(int sockfd, uint16_t *code)
PACK_OP_COMMON(0, &op_common);
if (op_common.version != USBIP_VERSION) {
- dbg("version mismatch: %d %d", op_common.version,
- USBIP_VERSION);
+ err("USBIP Kernel and tool version mismatch: %d %d:",
+ op_common.version, USBIP_VERSION);
goto err;
}
@@ -191,10 +191,14 @@ int usbip_net_recv_op_common(int sockfd, uint16_t *code)
if (op_common.code != *code) {
dbg("unexpected pdu %#0x for %#0x", op_common.code,
*code);
+ /* return error status */
+ *status = ST_ERROR;
goto err;
}
}
+ *status = op_common.status;
+
if (op_common.status != ST_OK) {
dbg("request failed at peer: %d", op_common.status);
goto err;
diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h
index 7032687621d3..555215eae43e 100644
--- a/tools/usb/usbip/src/usbip_network.h
+++ b/tools/usb/usbip/src/usbip_network.h
@@ -27,9 +27,7 @@ struct op_common {
#define OP_REPLY (0x00 << 8)
uint16_t code;
- /* add more error code */
-#define ST_OK 0x00
-#define ST_NA 0x01
+ /* status codes defined in usbip_common.h */
uint32_t status; /* op_code status (for reply) */
} __attribute__((packed));
@@ -176,7 +174,7 @@ void usbip_net_pack_usb_interface(int pack, struct usbip_usb_interface *uinf);
ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen);
ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen);
int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status);
-int usbip_net_recv_op_common(int sockfd, uint16_t *code);
+int usbip_net_recv_op_common(int sockfd, uint16_t *code, int *status);
int usbip_net_set_reuseaddr(int sockfd);
int usbip_net_set_nodelay(int sockfd);
int usbip_net_set_keepalive(int sockfd);
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
index c6dad2a13c80..32864c52942d 100644
--- a/tools/usb/usbip/src/usbipd.c
+++ b/tools/usb/usbip/src/usbipd.c
@@ -107,7 +107,7 @@ static int recv_request_import(int sockfd)
struct usbip_usb_device pdu_udev;
struct list_head *i;
int found = 0;
- int error = 0;
+ int status = ST_OK;
int rc;
memset(&req, 0, sizeof(req));
@@ -133,22 +133,21 @@ static int recv_request_import(int sockfd)
usbip_net_set_nodelay(sockfd);
/* export device needs a TCP/IP socket descriptor */
- rc = usbip_export_device(edev, sockfd);
- if (rc < 0)
- error = 1;
+ status = usbip_export_device(edev, sockfd);
+ if (status < 0)
+ status = ST_NA;
} else {
info("requested device not found: %s", req.busid);
- error = 1;
+ status = ST_NODEV;
}
- rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT,
- (!error ? ST_OK : ST_NA));
+ rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT, status);
if (rc < 0) {
dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
return -1;
}
- if (error) {
+ if (status) {
dbg("import request busid %s: failed", req.busid);
return -1;
}
@@ -176,10 +175,21 @@ static int send_reply_devlist(int connfd)
struct list_head *j;
int rc, i;
+ /*
+ * Exclude devices that are already exported to a client from
+ * the exportable device list to avoid:
+ * - import requests for devices that are exported only to
+ * fail the request.
+ * - revealing devices that are imported by a client to
+ * another client.
+ */
+
reply.ndev = 0;
/* number of exported devices */
list_for_each(j, &driver->edev_list) {
- reply.ndev += 1;
+ edev = list_entry(j, struct usbip_exported_device, node);
+ if (edev->status != SDEV_ST_USED)
+ reply.ndev += 1;
}
info("exportable devices: %d", reply.ndev);
@@ -198,6 +208,9 @@ static int send_reply_devlist(int connfd)
list_for_each(j, &driver->edev_list) {
edev = list_entry(j, struct usbip_exported_device, node);
+ if (edev->status == SDEV_ST_USED)
+ continue;
+
dump_usb_device(&edev->udev);
memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
usbip_net_pack_usb_device(1, &pdu_udev);
@@ -251,8 +264,9 @@ static int recv_pdu(int connfd)
{
uint16_t code = OP_UNSPEC;
int ret;
+ int status;
- ret = usbip_net_recv_op_common(connfd, &code);
+ ret = usbip_net_recv_op_common(connfd, &code, &status);
if (ret < 0) {
dbg("could not receive opcode: %#0x", code);
return -1;
diff --git a/usr/initramfs_data.S b/usr/initramfs_data.S
index 10d325e24566..b28da799f6a6 100644
--- a/usr/initramfs_data.S
+++ b/usr/initramfs_data.S
@@ -10,7 +10,7 @@
ld -m elf_i386 --format binary --oformat elf32-i386 -r \
-T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
- ld -m elf_i386 -r -o built-in.o initramfs_data.o
+ ld -m elf_i386 -r -o built-in.a initramfs_data.o
For including the .init.ramfs sections, see include/asm-generic/vmlinux.lds.